aboutsummaryrefslogtreecommitdiff
path: root/contrib/bearssl
diff options
context:
space:
mode:
Diffstat (limited to 'contrib/bearssl')
-rw-r--r--contrib/bearssl/Doxyfile2427
-rw-r--r--contrib/bearssl/LICENSE.txt21
-rw-r--r--contrib/bearssl/Makefile45
-rw-r--r--contrib/bearssl/README.txt136
-rw-r--r--contrib/bearssl/T0/BlobWriter.cs112
-rw-r--r--contrib/bearssl/T0/CPU.cs181
-rw-r--r--contrib/bearssl/T0/CodeElement.cs100
-rw-r--r--contrib/bearssl/T0/CodeElementJump.cs97
-rw-r--r--contrib/bearssl/T0/CodeElementUInt.cs55
-rw-r--r--contrib/bearssl/T0/CodeElementUIntExpr.cs66
-rw-r--r--contrib/bearssl/T0/CodeElementUIntInt.cs61
-rw-r--r--contrib/bearssl/T0/CodeElementUIntUInt.cs60
-rw-r--r--contrib/bearssl/T0/ConstData.cs198
-rw-r--r--contrib/bearssl/T0/Opcode.cs117
-rw-r--r--contrib/bearssl/T0/OpcodeCall.cs71
-rw-r--r--contrib/bearssl/T0/OpcodeConst.cs95
-rw-r--r--contrib/bearssl/T0/OpcodeGetLocal.cs57
-rw-r--r--contrib/bearssl/T0/OpcodeJump.cs64
-rw-r--r--contrib/bearssl/T0/OpcodeJumpIf.cs65
-rw-r--r--contrib/bearssl/T0/OpcodeJumpIfNot.cs65
-rw-r--r--contrib/bearssl/T0/OpcodeJumpUncond.cs61
-rw-r--r--contrib/bearssl/T0/OpcodePutLocal.cs57
-rw-r--r--contrib/bearssl/T0/OpcodeRet.cs50
-rw-r--r--contrib/bearssl/T0/SType.cs129
-rw-r--r--contrib/bearssl/T0/T0Comp.cs2123
-rw-r--r--contrib/bearssl/T0/TPointerBase.cs64
-rw-r--r--contrib/bearssl/T0/TPointerBlob.cs75
-rw-r--r--contrib/bearssl/T0/TPointerExpr.cs97
-rw-r--r--contrib/bearssl/T0/TPointerNull.cs44
-rw-r--r--contrib/bearssl/T0/TPointerXT.cs73
-rw-r--r--contrib/bearssl/T0/TValue.cs231
-rw-r--r--contrib/bearssl/T0/Word.cs172
-rw-r--r--contrib/bearssl/T0/WordBuilder.cs385
-rw-r--r--contrib/bearssl/T0/WordData.cs96
-rw-r--r--contrib/bearssl/T0/WordInterpreted.cs283
-rw-r--r--contrib/bearssl/T0/WordNative.cs59
-rw-r--r--contrib/bearssl/T0/kern.t0309
-rwxr-xr-xcontrib/bearssl/T0Comp.exebin0 -> 72704 bytes
-rw-r--r--contrib/bearssl/build/.do_not_remove0
-rw-r--r--contrib/bearssl/conf/Unix.mk69
-rw-r--r--contrib/bearssl/conf/Unix32.mk12
-rw-r--r--contrib/bearssl/conf/UnixClang.mk11
-rw-r--r--contrib/bearssl/conf/Win.mk70
-rw-r--r--contrib/bearssl/conf/samd20.mk20
-rw-r--r--contrib/bearssl/inc/bearssl.h170
-rw-r--r--contrib/bearssl/inc/bearssl_aead.h1059
-rw-r--r--contrib/bearssl/inc/bearssl_block.h2618
-rw-r--r--contrib/bearssl/inc/bearssl_ec.h967
-rw-r--r--contrib/bearssl/inc/bearssl_hash.h1346
-rw-r--r--contrib/bearssl/inc/bearssl_hmac.h241
-rw-r--r--contrib/bearssl/inc/bearssl_kdf.h284
-rw-r--r--contrib/bearssl/inc/bearssl_pem.h294
-rw-r--r--contrib/bearssl/inc/bearssl_prf.h150
-rw-r--r--contrib/bearssl/inc/bearssl_rand.h397
-rw-r--r--contrib/bearssl/inc/bearssl_rsa.h1655
-rw-r--r--contrib/bearssl/inc/bearssl_ssl.h4296
-rw-r--r--contrib/bearssl/inc/bearssl_x509.h1397
-rw-r--r--contrib/bearssl/mk/Defaults.mk41
-rw-r--r--contrib/bearssl/mk/NMake.mk38
-rw-r--r--contrib/bearssl/mk/Rules.mk1318
-rw-r--r--contrib/bearssl/mk/SingleUnix.mk38
-rw-r--r--contrib/bearssl/mk/mkT0.cmd32
-rwxr-xr-xcontrib/bearssl/mk/mkT0.sh11
-rwxr-xr-xcontrib/bearssl/mk/mkrules.sh570
-rw-r--r--contrib/bearssl/samples/README.txt36
-rw-r--r--contrib/bearssl/samples/cert-ee-ec+rsa.pem14
-rw-r--r--contrib/bearssl/samples/cert-ee-ec.pem10
-rw-r--r--contrib/bearssl/samples/cert-ee-rsa.pem17
-rw-r--r--contrib/bearssl/samples/cert-ica-ec.pem10
-rw-r--r--contrib/bearssl/samples/cert-ica-rsa.pem17
-rw-r--r--contrib/bearssl/samples/cert-root-ec.pem9
-rw-r--r--contrib/bearssl/samples/cert-root-rsa.pem16
-rw-r--r--contrib/bearssl/samples/chain-ec+rsa.h166
-rw-r--r--contrib/bearssl/samples/chain-ec.h117
-rw-r--r--contrib/bearssl/samples/chain-rsa.h183
-rw-r--r--contrib/bearssl/samples/client_basic.c380
-rw-r--r--contrib/bearssl/samples/custom_profile.c601
-rw-r--r--contrib/bearssl/samples/key-ec.h40
-rw-r--r--contrib/bearssl/samples/key-ee-ec.pem5
-rw-r--r--contrib/bearssl/samples/key-ee-rsa.pem23
-rw-r--r--contrib/bearssl/samples/key-ica-ec.pem5
-rw-r--r--contrib/bearssl/samples/key-ica-rsa.pem23
-rw-r--r--contrib/bearssl/samples/key-root-ec.pem5
-rw-r--r--contrib/bearssl/samples/key-root-rsa.pem23
-rw-r--r--contrib/bearssl/samples/key-rsa.h108
-rw-r--r--contrib/bearssl/samples/server_basic.c436
-rw-r--r--contrib/bearssl/src/aead/ccm.c346
-rw-r--r--contrib/bearssl/src/aead/eax.c525
-rw-r--r--contrib/bearssl/src/aead/gcm.c318
-rw-r--r--contrib/bearssl/src/codec/ccopy.c44
-rw-r--r--contrib/bearssl/src/codec/dec16be.c38
-rw-r--r--contrib/bearssl/src/codec/dec16le.c38
-rw-r--r--contrib/bearssl/src/codec/dec32be.c38
-rw-r--r--contrib/bearssl/src/codec/dec32le.c38
-rw-r--r--contrib/bearssl/src/codec/dec64be.c38
-rw-r--r--contrib/bearssl/src/codec/dec64le.c38
-rw-r--r--contrib/bearssl/src/codec/enc16be.c38
-rw-r--r--contrib/bearssl/src/codec/enc16le.c38
-rw-r--r--contrib/bearssl/src/codec/enc32be.c38
-rw-r--r--contrib/bearssl/src/codec/enc32le.c38
-rw-r--r--contrib/bearssl/src/codec/enc64be.c38
-rw-r--r--contrib/bearssl/src/codec/enc64le.c38
-rw-r--r--contrib/bearssl/src/codec/pemdec.c526
-rw-r--r--contrib/bearssl/src/codec/pemdec.t0314
-rw-r--r--contrib/bearssl/src/codec/pemenc.c173
-rw-r--r--contrib/bearssl/src/config.h229
-rw-r--r--contrib/bearssl/src/ec/ec_all_m15.c121
-rw-r--r--contrib/bearssl/src/ec/ec_all_m31.c171
-rw-r--r--contrib/bearssl/src/ec/ec_c25519_i15.c398
-rw-r--r--contrib/bearssl/src/ec/ec_c25519_i31.c390
-rw-r--r--contrib/bearssl/src/ec/ec_c25519_m15.c1478
-rw-r--r--contrib/bearssl/src/ec/ec_c25519_m31.c800
-rw-r--r--contrib/bearssl/src/ec/ec_c25519_m62.c605
-rw-r--r--contrib/bearssl/src/ec/ec_c25519_m64.c835
-rw-r--r--contrib/bearssl/src/ec/ec_curve25519.c46
-rw-r--r--contrib/bearssl/src/ec/ec_default.c36
-rw-r--r--contrib/bearssl/src/ec/ec_keygen.c86
-rw-r--r--contrib/bearssl/src/ec/ec_p256_m15.c2130
-rw-r--r--contrib/bearssl/src/ec/ec_p256_m31.c1475
-rw-r--r--contrib/bearssl/src/ec/ec_p256_m62.c1765
-rw-r--r--contrib/bearssl/src/ec/ec_p256_m64.c1730
-rw-r--r--contrib/bearssl/src/ec/ec_prime_i15.c820
-rw-r--r--contrib/bearssl/src/ec/ec_prime_i31.c819
-rw-r--r--contrib/bearssl/src/ec/ec_pubkey.c85
-rw-r--r--contrib/bearssl/src/ec/ec_secp256r1.c51
-rw-r--r--contrib/bearssl/src/ec/ec_secp384r1.c57
-rw-r--r--contrib/bearssl/src/ec/ec_secp521r1.c64
-rw-r--r--contrib/bearssl/src/ec/ecdsa_atr.c134
-rw-r--r--contrib/bearssl/src/ec/ecdsa_default_sign_asn1.c36
-rw-r--r--contrib/bearssl/src/ec/ecdsa_default_sign_raw.c36
-rw-r--r--contrib/bearssl/src/ec/ecdsa_default_vrfy_asn1.c36
-rw-r--r--contrib/bearssl/src/ec/ecdsa_default_vrfy_raw.c36
-rw-r--r--contrib/bearssl/src/ec/ecdsa_i15_bits.c47
-rw-r--r--contrib/bearssl/src/ec/ecdsa_i15_sign_asn1.c45
-rw-r--r--contrib/bearssl/src/ec/ecdsa_i15_sign_raw.c174
-rw-r--r--contrib/bearssl/src/ec/ecdsa_i15_vrfy_asn1.c48
-rw-r--r--contrib/bearssl/src/ec/ecdsa_i15_vrfy_raw.c166
-rw-r--r--contrib/bearssl/src/ec/ecdsa_i31_bits.c47
-rw-r--r--contrib/bearssl/src/ec/ecdsa_i31_sign_asn1.c45
-rw-r--r--contrib/bearssl/src/ec/ecdsa_i31_sign_raw.c173
-rw-r--r--contrib/bearssl/src/ec/ecdsa_i31_vrfy_asn1.c48
-rw-r--r--contrib/bearssl/src/ec/ecdsa_i31_vrfy_raw.c165
-rw-r--r--contrib/bearssl/src/ec/ecdsa_rta.c121
-rw-r--r--contrib/bearssl/src/hash/dig_oid.c84
-rw-r--r--contrib/bearssl/src/hash/dig_size.c50
-rw-r--r--contrib/bearssl/src/hash/ghash_ctmul.c345
-rw-r--r--contrib/bearssl/src/hash/ghash_ctmul32.c251
-rw-r--r--contrib/bearssl/src/hash/ghash_ctmul64.c154
-rw-r--r--contrib/bearssl/src/hash/ghash_pclmul.c389
-rw-r--r--contrib/bearssl/src/hash/ghash_pwr8.c411
-rw-r--r--contrib/bearssl/src/hash/md5.c208
-rw-r--r--contrib/bearssl/src/hash/md5sha1.c141
-rw-r--r--contrib/bearssl/src/hash/mgf1.c56
-rw-r--r--contrib/bearssl/src/hash/multihash.c166
-rw-r--r--contrib/bearssl/src/hash/sha1.c191
-rw-r--r--contrib/bearssl/src/hash/sha2big.c285
-rw-r--r--contrib/bearssl/src/hash/sha2small.c341
-rw-r--r--contrib/bearssl/src/inner.h2557
-rw-r--r--contrib/bearssl/src/int/i15_add.c46
-rw-r--r--contrib/bearssl/src/int/i15_bitlen.c44
-rw-r--r--contrib/bearssl/src/int/i15_decmod.c124
-rw-r--r--contrib/bearssl/src/int/i15_decode.c56
-rw-r--r--contrib/bearssl/src/int/i15_decred.c100
-rw-r--r--contrib/bearssl/src/int/i15_encode.c56
-rw-r--r--contrib/bearssl/src/int/i15_fmont.c59
-rw-r--r--contrib/bearssl/src/int/i15_iszero.c39
-rw-r--r--contrib/bearssl/src/int/i15_moddiv.c465
-rw-r--r--contrib/bearssl/src/int/i15_modpow.c50
-rw-r--r--contrib/bearssl/src/int/i15_modpow2.c160
-rw-r--r--contrib/bearssl/src/int/i15_montmul.c184
-rw-r--r--contrib/bearssl/src/int/i15_mulacc.c61
-rw-r--r--contrib/bearssl/src/int/i15_muladd.c173
-rw-r--r--contrib/bearssl/src/int/i15_ninv15.c38
-rw-r--r--contrib/bearssl/src/int/i15_reduce.c66
-rw-r--r--contrib/bearssl/src/int/i15_rshift.c47
-rw-r--r--contrib/bearssl/src/int/i15_sub.c46
-rw-r--r--contrib/bearssl/src/int/i15_tmont.c36
-rw-r--r--contrib/bearssl/src/int/i31_add.c46
-rw-r--r--contrib/bearssl/src/int/i31_bitlen.c44
-rw-r--r--contrib/bearssl/src/int/i31_decmod.c124
-rw-r--r--contrib/bearssl/src/int/i31_decode.c57
-rw-r--r--contrib/bearssl/src/int/i31_decred.c103
-rw-r--r--contrib/bearssl/src/int/i31_encode.c79
-rw-r--r--contrib/bearssl/src/int/i31_fmont.c60
-rw-r--r--contrib/bearssl/src/int/i31_iszero.c39
-rw-r--r--contrib/bearssl/src/int/i31_moddiv.c488
-rw-r--r--contrib/bearssl/src/int/i31_modpow.c65
-rw-r--r--contrib/bearssl/src/int/i31_modpow2.c160
-rw-r--r--contrib/bearssl/src/int/i31_montmul.c127
-rw-r--r--contrib/bearssl/src/int/i31_mulacc.c74
-rw-r--r--contrib/bearssl/src/int/i31_muladd.c157
-rw-r--r--contrib/bearssl/src/int/i31_ninv31.c39
-rw-r--r--contrib/bearssl/src/int/i31_reduce.c66
-rw-r--r--contrib/bearssl/src/int/i31_rshift.c47
-rw-r--r--contrib/bearssl/src/int/i31_sub.c46
-rw-r--r--contrib/bearssl/src/int/i31_tmont.c36
-rw-r--r--contrib/bearssl/src/int/i32_add.c51
-rw-r--r--contrib/bearssl/src/int/i32_bitlen.c44
-rw-r--r--contrib/bearssl/src/int/i32_decmod.c77
-rw-r--r--contrib/bearssl/src/int/i32_decode.c63
-rw-r--r--contrib/bearssl/src/int/i32_decred.c107
-rw-r--r--contrib/bearssl/src/int/i32_div32.c56
-rw-r--r--contrib/bearssl/src/int/i32_encode.c72
-rw-r--r--contrib/bearssl/src/int/i32_fmont.c60
-rw-r--r--contrib/bearssl/src/int/i32_iszero.c39
-rw-r--r--contrib/bearssl/src/int/i32_modpow.c65
-rw-r--r--contrib/bearssl/src/int/i32_montmul.c69
-rw-r--r--contrib/bearssl/src/int/i32_mulacc.c56
-rw-r--r--contrib/bearssl/src/int/i32_muladd.c138
-rw-r--r--contrib/bearssl/src/int/i32_ninv32.c39
-rw-r--r--contrib/bearssl/src/int/i32_reduce.c66
-rw-r--r--contrib/bearssl/src/int/i32_sub.c51
-rw-r--r--contrib/bearssl/src/int/i32_tmont.c36
-rw-r--r--contrib/bearssl/src/int/i62_modpow2.c493
-rw-r--r--contrib/bearssl/src/kdf/hkdf.c107
-rw-r--r--contrib/bearssl/src/kdf/shake.c590
-rw-r--r--contrib/bearssl/src/mac/hmac.c122
-rw-r--r--contrib/bearssl/src/mac/hmac_ct.c193
-rw-r--r--contrib/bearssl/src/rand/aesctr_drbg.c206
-rw-r--r--contrib/bearssl/src/rand/hmac_drbg.c157
-rw-r--r--contrib/bearssl/src/rand/sysrng.c170
-rw-r--r--contrib/bearssl/src/rsa/rsa_default_keygen.c38
-rw-r--r--contrib/bearssl/src/rsa/rsa_default_modulus.c36
-rw-r--r--contrib/bearssl/src/rsa/rsa_default_oaep_decrypt.c38
-rw-r--r--contrib/bearssl/src/rsa/rsa_default_oaep_encrypt.c38
-rw-r--r--contrib/bearssl/src/rsa/rsa_default_pkcs1_sign.c38
-rw-r--r--contrib/bearssl/src/rsa/rsa_default_pkcs1_vrfy.c38
-rw-r--r--contrib/bearssl/src/rsa/rsa_default_priv.c38
-rw-r--r--contrib/bearssl/src/rsa/rsa_default_privexp.c36
-rw-r--r--contrib/bearssl/src/rsa/rsa_default_pss_sign.c38
-rw-r--r--contrib/bearssl/src/rsa/rsa_default_pss_vrfy.c38
-rw-r--r--contrib/bearssl/src/rsa/rsa_default_pub.c38
-rw-r--r--contrib/bearssl/src/rsa/rsa_default_pubexp.c36
-rw-r--r--contrib/bearssl/src/rsa/rsa_i15_keygen.c583
-rw-r--r--contrib/bearssl/src/rsa/rsa_i15_modulus.c99
-rw-r--r--contrib/bearssl/src/rsa/rsa_i15_oaep_decrypt.c41
-rw-r--r--contrib/bearssl/src/rsa/rsa_i15_oaep_encrypt.c44
-rw-r--r--contrib/bearssl/src/rsa/rsa_i15_pkcs1_sign.c37
-rw-r--r--contrib/bearssl/src/rsa/rsa_i15_pkcs1_vrfy.c43
-rw-r--r--contrib/bearssl/src/rsa/rsa_i15_priv.c209
-rw-r--r--contrib/bearssl/src/rsa/rsa_i15_privexp.c320
-rw-r--r--contrib/bearssl/src/rsa/rsa_i15_pss_sign.c40
-rw-r--r--contrib/bearssl/src/rsa/rsa_i15_pss_vrfy.c44
-rw-r--r--contrib/bearssl/src/rsa/rsa_i15_pub.c113
-rw-r--r--contrib/bearssl/src/rsa/rsa_i15_pubexp.c152
-rw-r--r--contrib/bearssl/src/rsa/rsa_i31_keygen.c37
-rw-r--r--contrib/bearssl/src/rsa/rsa_i31_keygen_inner.c608
-rw-r--r--contrib/bearssl/src/rsa/rsa_i31_modulus.c99
-rw-r--r--contrib/bearssl/src/rsa/rsa_i31_oaep_decrypt.c41
-rw-r--r--contrib/bearssl/src/rsa/rsa_i31_oaep_encrypt.c44
-rw-r--r--contrib/bearssl/src/rsa/rsa_i31_pkcs1_sign.c37
-rw-r--r--contrib/bearssl/src/rsa/rsa_i31_pkcs1_vrfy.c43
-rw-r--r--contrib/bearssl/src/rsa/rsa_i31_priv.c203
-rw-r--r--contrib/bearssl/src/rsa/rsa_i31_privexp.c318
-rw-r--r--contrib/bearssl/src/rsa/rsa_i31_pss_sign.c40
-rw-r--r--contrib/bearssl/src/rsa/rsa_i31_pss_vrfy.c44
-rw-r--r--contrib/bearssl/src/rsa/rsa_i31_pub.c106
-rw-r--r--contrib/bearssl/src/rsa/rsa_i31_pubexp.c152
-rw-r--r--contrib/bearssl/src/rsa/rsa_i32_oaep_decrypt.c41
-rw-r--r--contrib/bearssl/src/rsa/rsa_i32_oaep_encrypt.c44
-rw-r--r--contrib/bearssl/src/rsa/rsa_i32_pkcs1_sign.c37
-rw-r--r--contrib/bearssl/src/rsa/rsa_i32_pkcs1_vrfy.c43
-rw-r--r--contrib/bearssl/src/rsa/rsa_i32_priv.c160
-rw-r--r--contrib/bearssl/src/rsa/rsa_i32_pss_sign.c40
-rw-r--r--contrib/bearssl/src/rsa/rsa_i32_pss_vrfy.c44
-rw-r--r--contrib/bearssl/src/rsa/rsa_i32_pub.c77
-rw-r--r--contrib/bearssl/src/rsa/rsa_i62_keygen.c57
-rw-r--r--contrib/bearssl/src/rsa/rsa_i62_oaep_decrypt.c61
-rw-r--r--contrib/bearssl/src/rsa/rsa_i62_oaep_encrypt.c64
-rw-r--r--contrib/bearssl/src/rsa/rsa_i62_pkcs1_sign.c57
-rw-r--r--contrib/bearssl/src/rsa/rsa_i62_pkcs1_vrfy.c63
-rw-r--r--contrib/bearssl/src/rsa/rsa_i62_priv.c223
-rw-r--r--contrib/bearssl/src/rsa/rsa_i62_pss_sign.c60
-rw-r--r--contrib/bearssl/src/rsa/rsa_i62_pss_vrfy.c64
-rw-r--r--contrib/bearssl/src/rsa/rsa_i62_pub.c125
-rw-r--r--contrib/bearssl/src/rsa/rsa_oaep_pad.c112
-rw-r--r--contrib/bearssl/src/rsa/rsa_oaep_unpad.c145
-rw-r--r--contrib/bearssl/src/rsa/rsa_pkcs1_sig_pad.c100
-rw-r--r--contrib/bearssl/src/rsa/rsa_pkcs1_sig_unpad.c121
-rw-r--r--contrib/bearssl/src/rsa/rsa_pss_sig_pad.c106
-rw-r--r--contrib/bearssl/src/rsa/rsa_pss_sig_unpad.c121
-rw-r--r--contrib/bearssl/src/rsa/rsa_ssl_decrypt.c52
-rw-r--r--contrib/bearssl/src/settings.c306
-rw-r--r--contrib/bearssl/src/ssl/prf.c73
-rw-r--r--contrib/bearssl/src/ssl/prf_md5sha1.c43
-rw-r--r--contrib/bearssl/src/ssl/prf_sha256.c36
-rw-r--r--contrib/bearssl/src/ssl/prf_sha384.c36
-rw-r--r--contrib/bearssl/src/ssl/ssl_ccert_single_ec.c156
-rw-r--r--contrib/bearssl/src/ssl/ssl_ccert_single_rsa.c149
-rw-r--r--contrib/bearssl/src/ssl/ssl_client.c78
-rw-r--r--contrib/bearssl/src/ssl/ssl_client_default_rsapub.c32
-rw-r--r--contrib/bearssl/src/ssl/ssl_client_full.c179
-rw-r--r--contrib/bearssl/src/ssl/ssl_engine.c1569
-rw-r--r--contrib/bearssl/src/ssl/ssl_engine_default_aescbc.c64
-rw-r--r--contrib/bearssl/src/ssl/ssl_engine_default_aesccm.c67
-rw-r--r--contrib/bearssl/src/ssl/ssl_engine_default_aesgcm.c89
-rw-r--r--contrib/bearssl/src/ssl/ssl_engine_default_chapol.c65
-rw-r--r--contrib/bearssl/src/ssl/ssl_engine_default_descbc.c37
-rw-r--r--contrib/bearssl/src/ssl/ssl_engine_default_ec.c36
-rw-r--r--contrib/bearssl/src/ssl/ssl_engine_default_ecdsa.c38
-rw-r--r--contrib/bearssl/src/ssl/ssl_engine_default_rsavrfy.c32
-rw-r--r--contrib/bearssl/src/ssl/ssl_hashes.c46
-rw-r--r--contrib/bearssl/src/ssl/ssl_hs_client.c1915
-rw-r--r--contrib/bearssl/src/ssl/ssl_hs_client.t01276
-rw-r--r--contrib/bearssl/src/ssl/ssl_hs_common.t01382
-rw-r--r--contrib/bearssl/src/ssl/ssl_hs_server.c2009
-rw-r--r--contrib/bearssl/src/ssl/ssl_hs_server.t01510
-rw-r--r--contrib/bearssl/src/ssl/ssl_io.c261
-rw-r--r--contrib/bearssl/src/ssl/ssl_keyexport.c83
-rw-r--r--contrib/bearssl/src/ssl/ssl_lru.c537
-rw-r--r--contrib/bearssl/src/ssl/ssl_rec_cbc.c440
-rw-r--r--contrib/bearssl/src/ssl/ssl_rec_ccm.c213
-rw-r--r--contrib/bearssl/src/ssl/ssl_rec_chapol.c177
-rw-r--r--contrib/bearssl/src/ssl/ssl_rec_gcm.c235
-rw-r--r--contrib/bearssl/src/ssl/ssl_scert_single_ec.c142
-rw-r--r--contrib/bearssl/src/ssl/ssl_scert_single_rsa.c162
-rw-r--r--contrib/bearssl/src/ssl/ssl_server.c52
-rw-r--r--contrib/bearssl/src/ssl/ssl_server_full_ec.c149
-rw-r--r--contrib/bearssl/src/ssl/ssl_server_full_rsa.c132
-rw-r--r--contrib/bearssl/src/ssl/ssl_server_mine2c.c71
-rw-r--r--contrib/bearssl/src/ssl/ssl_server_mine2g.c71
-rw-r--r--contrib/bearssl/src/ssl/ssl_server_minf2c.c71
-rw-r--r--contrib/bearssl/src/ssl/ssl_server_minf2g.c71
-rw-r--r--contrib/bearssl/src/ssl/ssl_server_minr2g.c70
-rw-r--r--contrib/bearssl/src/ssl/ssl_server_minu2g.c70
-rw-r--r--contrib/bearssl/src/ssl/ssl_server_minv2g.c70
-rw-r--r--contrib/bearssl/src/symcipher/aes_big_cbcdec.c69
-rw-r--r--contrib/bearssl/src/symcipher/aes_big_cbcenc.c67
-rw-r--r--contrib/bearssl/src/symcipher/aes_big_ctr.c84
-rw-r--r--contrib/bearssl/src/symcipher/aes_big_ctrcbc.c142
-rw-r--r--contrib/bearssl/src/symcipher/aes_big_dec.c254
-rw-r--r--contrib/bearssl/src/symcipher/aes_big_enc.c157
-rw-r--r--contrib/bearssl/src/symcipher/aes_common.c112
-rw-r--r--contrib/bearssl/src/symcipher/aes_ct.c328
-rw-r--r--contrib/bearssl/src/symcipher/aes_ct64.c398
-rw-r--r--contrib/bearssl/src/symcipher/aes_ct64_cbcdec.c104
-rw-r--r--contrib/bearssl/src/symcipher/aes_ct64_cbcenc.c81
-rw-r--r--contrib/bearssl/src/symcipher/aes_ct64_ctr.c114
-rw-r--r--contrib/bearssl/src/symcipher/aes_ct64_ctrcbc.c433
-rw-r--r--contrib/bearssl/src/symcipher/aes_ct64_dec.c159
-rw-r--r--contrib/bearssl/src/symcipher/aes_ct64_enc.c115
-rw-r--r--contrib/bearssl/src/symcipher/aes_ct_cbcdec.c111
-rw-r--r--contrib/bearssl/src/symcipher/aes_ct_cbcenc.c91
-rw-r--r--contrib/bearssl/src/symcipher/aes_ct_ctr.c116
-rw-r--r--contrib/bearssl/src/symcipher/aes_ct_ctrcbc.c422
-rw-r--r--contrib/bearssl/src/symcipher/aes_ct_dec.c170
-rw-r--r--contrib/bearssl/src/symcipher/aes_ct_enc.c112
-rw-r--r--contrib/bearssl/src/symcipher/aes_pwr8.c445
-rw-r--r--contrib/bearssl/src/symcipher/aes_pwr8_cbcdec.c670
-rw-r--r--contrib/bearssl/src/symcipher/aes_pwr8_cbcenc.c417
-rw-r--r--contrib/bearssl/src/symcipher/aes_pwr8_ctr.c717
-rw-r--r--contrib/bearssl/src/symcipher/aes_pwr8_ctrcbc.c946
-rw-r--r--contrib/bearssl/src/symcipher/aes_small_cbcdec.c69
-rw-r--r--contrib/bearssl/src/symcipher/aes_small_cbcenc.c67
-rw-r--r--contrib/bearssl/src/symcipher/aes_small_ctr.c84
-rw-r--r--contrib/bearssl/src/symcipher/aes_small_ctrcbc.c142
-rw-r--r--contrib/bearssl/src/symcipher/aes_small_dec.c176
-rw-r--r--contrib/bearssl/src/symcipher/aes_small_enc.c129
-rw-r--r--contrib/bearssl/src/symcipher/aes_x86ni.c240
-rw-r--r--contrib/bearssl/src/symcipher/aes_x86ni_cbcdec.c223
-rw-r--r--contrib/bearssl/src/symcipher/aes_x86ni_cbcenc.c122
-rw-r--r--contrib/bearssl/src/symcipher/aes_x86ni_ctr.c211
-rw-r--r--contrib/bearssl/src/symcipher/aes_x86ni_ctrcbc.c596
-rw-r--r--contrib/bearssl/src/symcipher/chacha20_ct.c106
-rw-r--r--contrib/bearssl/src/symcipher/chacha20_sse2.c237
-rw-r--r--contrib/bearssl/src/symcipher/des_ct.c411
-rw-r--r--contrib/bearssl/src/symcipher/des_ct_cbcdec.c87
-rw-r--r--contrib/bearssl/src/symcipher/des_ct_cbcenc.c69
-rw-r--r--contrib/bearssl/src/symcipher/des_support.c166
-rw-r--r--contrib/bearssl/src/symcipher/des_tab.c310
-rw-r--r--contrib/bearssl/src/symcipher/des_tab_cbcdec.c85
-rw-r--r--contrib/bearssl/src/symcipher/des_tab_cbcenc.c67
-rw-r--r--contrib/bearssl/src/symcipher/poly1305_ctmul.c260
-rw-r--r--contrib/bearssl/src/symcipher/poly1305_ctmul32.c297
-rw-r--r--contrib/bearssl/src/symcipher/poly1305_ctmulq.c475
-rw-r--r--contrib/bearssl/src/symcipher/poly1305_i15.c221
-rw-r--r--contrib/bearssl/src/x509/asn1.t0757
-rw-r--r--contrib/bearssl/src/x509/asn1enc.c93
-rw-r--r--contrib/bearssl/src/x509/encode_ec_pk8der.c110
-rw-r--r--contrib/bearssl/src/x509/encode_ec_rawder.c161
-rw-r--r--contrib/bearssl/src/x509/encode_rsa_pk8der.c97
-rw-r--r--contrib/bearssl/src/x509/encode_rsa_rawder.c96
-rw-r--r--contrib/bearssl/src/x509/skey_decoder.c650
-rw-r--r--contrib/bearssl/src/x509/skey_decoder.t0373
-rw-r--r--contrib/bearssl/src/x509/x509_decoder.c773
-rw-r--r--contrib/bearssl/src/x509/x509_decoder.t0321
-rw-r--r--contrib/bearssl/src/x509/x509_knownkey.c105
-rw-r--r--contrib/bearssl/src/x509/x509_minimal.c1713
-rw-r--r--contrib/bearssl/src/x509/x509_minimal.t01508
-rw-r--r--contrib/bearssl/src/x509/x509_minimal_full.c59
-rw-r--r--contrib/bearssl/test/test_crypto.c9475
-rw-r--r--contrib/bearssl/test/test_math.c482
-rw-r--r--contrib/bearssl/test/test_speed.c1772
-rw-r--r--contrib/bearssl/test/test_x509.c2058
-rw-r--r--contrib/bearssl/test/x509/alltests.txt722
-rw-r--r--contrib/bearssl/test/x509/dn-ee.der1
-rw-r--r--contrib/bearssl/test/x509/dn-ica1.der1
-rw-r--r--contrib/bearssl/test/x509/dn-ica2.der1
-rw-r--r--contrib/bearssl/test/x509/dn-root-new.der1
-rw-r--r--contrib/bearssl/test/x509/dn-root.der1
-rw-r--r--contrib/bearssl/test/x509/ee-badsig1.crtbin0 -> 870 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-badsig2.crtbin0 -> 870 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-cp1.crtbin0 -> 745 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-cp2.crtbin0 -> 702 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-cp3.crtbin0 -> 737 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-cp4.crtbin0 -> 748 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-dates.crtbin0 -> 872 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-md5.crtbin0 -> 870 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-names.crtbin0 -> 892 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-names2.crtbin0 -> 842 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-names3.crtbin0 -> 843 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-names4.crtbin0 -> 938 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-p256-sha1.crtbin0 -> 472 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-p256-sha224.crtbin0 -> 473 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-p256-sha256.crtbin0 -> 474 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-p256-sha384.crtbin0 -> 475 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-p256-sha512.crtbin0 -> 474 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-p256.crtbin0 -> 474 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-p384.crtbin0 -> 534 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-p521.crtbin0 -> 610 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-sha1.crtbin0 -> 870 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-sha224.crtbin0 -> 870 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-sha384.crtbin0 -> 870 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-sha512.crtbin0 -> 870 bytes
-rw-r--r--contrib/bearssl/test/x509/ee-trailing.crtbin0 -> 871 bytes
-rw-r--r--contrib/bearssl/test/x509/ee.crtbin0 -> 870 bytes
-rw-r--r--contrib/bearssl/test/x509/ica1-1016.crtbin0 -> 709 bytes
-rw-r--r--contrib/bearssl/test/x509/ica1-1017.crtbin0 -> 709 bytes
-rw-r--r--contrib/bearssl/test/x509/ica1-4096.crtbin0 -> 1098 bytes
-rw-r--r--contrib/bearssl/test/x509/ica1-p256.crtbin0 -> 446 bytes
-rw-r--r--contrib/bearssl/test/x509/ica1-p384.crtbin0 -> 507 bytes
-rw-r--r--contrib/bearssl/test/x509/ica1-p521.crtbin0 -> 581 bytes
-rw-r--r--contrib/bearssl/test/x509/ica1.crtbin0 -> 842 bytes
-rw-r--r--contrib/bearssl/test/x509/ica2-1016.crtbin0 -> 725 bytes
-rw-r--r--contrib/bearssl/test/x509/ica2-1017.crtbin0 -> 726 bytes
-rw-r--r--contrib/bearssl/test/x509/ica2-4096.crtbin0 -> 1111 bytes
-rw-r--r--contrib/bearssl/test/x509/ica2-notCA.crtbin0 -> 852 bytes
-rw-r--r--contrib/bearssl/test/x509/ica2-p256.crtbin0 -> 460 bytes
-rw-r--r--contrib/bearssl/test/x509/ica2-p384.crtbin0 -> 520 bytes
-rw-r--r--contrib/bearssl/test/x509/ica2-p521.crtbin0 -> 595 bytes
-rw-r--r--contrib/bearssl/test/x509/ica2.crtbin0 -> 855 bytes
-rw-r--r--contrib/bearssl/test/x509/junk.crtbin0 -> 800 bytes
-rw-r--r--contrib/bearssl/test/x509/names.crtbin0 -> 1366 bytes
-rw-r--r--contrib/bearssl/test/x509/root-p256.crtbin0 -> 413 bytes
-rw-r--r--contrib/bearssl/test/x509/root-p384.crtbin0 -> 475 bytes
-rw-r--r--contrib/bearssl/test/x509/root-p521.crtbin0 -> 549 bytes
-rw-r--r--contrib/bearssl/test/x509/root.crtbin0 -> 810 bytes
-rw-r--r--contrib/bearssl/tools/brssl.c122
-rw-r--r--contrib/bearssl/tools/brssl.h572
-rw-r--r--contrib/bearssl/tools/certs.c237
-rw-r--r--contrib/bearssl/tools/chain.c154
-rw-r--r--contrib/bearssl/tools/client.c1112
-rw-r--r--contrib/bearssl/tools/errors.c344
-rw-r--r--contrib/bearssl/tools/files.c329
-rw-r--r--contrib/bearssl/tools/impl.c48
-rw-r--r--contrib/bearssl/tools/keys.c234
-rw-r--r--contrib/bearssl/tools/names.c1056
-rw-r--r--contrib/bearssl/tools/server.c1235
-rw-r--r--contrib/bearssl/tools/skey.c784
-rw-r--r--contrib/bearssl/tools/sslio.c760
-rw-r--r--contrib/bearssl/tools/ta.c254
-rw-r--r--contrib/bearssl/tools/twrch.c1069
-rw-r--r--contrib/bearssl/tools/vector.c66
-rw-r--r--contrib/bearssl/tools/verify.c353
-rw-r--r--contrib/bearssl/tools/xmem.c132
465 files changed, 120601 insertions, 0 deletions
diff --git a/contrib/bearssl/Doxyfile b/contrib/bearssl/Doxyfile
new file mode 100644
index 000000000000..088682db878e
--- /dev/null
+++ b/contrib/bearssl/Doxyfile
@@ -0,0 +1,2427 @@
+# Doxyfile 1.8.11
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project.
+#
+# All text after a double hash (##) is considered a comment and is placed in
+# front of the TAG it is preceding.
+#
+# All text after a single hash (#) is considered a comment and will be ignored.
+# The format is:
+# TAG = value [value, ...]
+# For lists, items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (\" \").
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all text
+# before the first occurrence of this tag. Doxygen uses libiconv (or the iconv
+# built into libc) for the transcoding. See http://www.gnu.org/software/libiconv
+# for the list of possible encodings.
+# The default value is: UTF-8.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded by
+# double-quotes, unless you are using Doxywizard) that should identify the
+# project for which the documentation is generated. This name is used in the
+# title of most generated pages and in a few other places.
+# The default value is: My Project.
+
+PROJECT_NAME = "BearSSL"
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number. This
+# could be handy for archiving the generated documentation or if some version
+# control system is used.
+
+PROJECT_NUMBER =
+
+# Using the PROJECT_BRIEF tag one can provide an optional one line description
+# for a project that appears at the top of each page and should give viewer a
+# quick idea about the purpose of the project. Keep the description short.
+
+PROJECT_BRIEF =
+
+# With the PROJECT_LOGO tag one can specify a logo or an icon that is included
+# in the documentation. The maximum height of the logo should not exceed 55
+# pixels and the maximum width should not exceed 200 pixels. Doxygen will copy
+# the logo to the output directory.
+
+PROJECT_LOGO =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute) path
+# into which the generated documentation will be written. If a relative path is
+# entered, it will be relative to the location where doxygen was started. If
+# left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = apidoc
+
+# If the CREATE_SUBDIRS tag is set to YES then doxygen will create 4096 sub-
+# directories (in 2 levels) under the output directory of each output format and
+# will distribute the generated files over these directories. Enabling this
+# option can be useful when feeding doxygen a huge amount of source files, where
+# putting all generated files in the same directory would otherwise causes
+# performance problems for the file system.
+# The default value is: NO.
+
+CREATE_SUBDIRS = NO
+
+# If the ALLOW_UNICODE_NAMES tag is set to YES, doxygen will allow non-ASCII
+# characters to appear in the names of generated files. If set to NO, non-ASCII
+# characters will be escaped, for example _xE3_x81_x84 will be used for Unicode
+# U+3044.
+# The default value is: NO.
+
+ALLOW_UNICODE_NAMES = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# Possible values are: Afrikaans, Arabic, Armenian, Brazilian, Catalan, Chinese,
+# Chinese-Traditional, Croatian, Czech, Danish, Dutch, English (United States),
+# Esperanto, Farsi (Persian), Finnish, French, German, Greek, Hungarian,
+# Indonesian, Italian, Japanese, Japanese-en (Japanese with English messages),
+# Korean, Korean-en (Korean with English messages), Latvian, Lithuanian,
+# Macedonian, Norwegian, Persian (Farsi), Polish, Portuguese, Romanian, Russian,
+# Serbian, Serbian-Cyrillic, Slovak, Slovene, Spanish, Swedish, Turkish,
+# Ukrainian and Vietnamese.
+# The default value is: English.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES, doxygen will include brief member
+# descriptions after the members that are listed in the file and class
+# documentation (similar to Javadoc). Set to NO to disable this.
+# The default value is: YES.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES, doxygen will prepend the brief
+# description of a member or function before the detailed description
+#
+# Note: If both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+# The default value is: YES.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator that is
+# used to form the text in various listings. Each string in this list, if found
+# as the leading text of the brief description, will be stripped from the text
+# and the result, after processing the whole list, is used as the annotated
+# text. Otherwise, the brief description is used as-is. If left blank, the
+# following values are used ($name is automatically replaced with the name of
+# the entity):The $name class, The $name widget, The $name file, is, provides,
+# specifies, contains, represents, a, an and the.
+
+ABBREVIATE_BRIEF =
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# doxygen will generate a detailed section even if there is only a brief
+# description.
+# The default value is: NO.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+# The default value is: NO.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES, doxygen will prepend the full path
+# before files name in the file list and in the header files. If set to NO the
+# shortest path that makes the file name unique will be used
+# The default value is: YES.
+
+FULL_PATH_NAMES = NO
+
+# The STRIP_FROM_PATH tag can be used to strip a user-defined part of the path.
+# Stripping is only done if one of the specified strings matches the left-hand
+# part of the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the path to
+# strip.
+#
+# Note that you can specify absolute paths here, but also relative paths, which
+# will be relative from the directory where doxygen is started.
+# This tag requires that the tag FULL_PATH_NAMES is set to YES.
+
+STRIP_FROM_PATH =
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of the
+# path mentioned in the documentation of a class, which tells the reader which
+# header file to include in order to use a class. If left blank only the name of
+# the header file containing the class definition is used. Otherwise one should
+# specify the list of include paths that are normally passed to the compiler
+# using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter (but
+# less readable) file names. This can be useful is your file systems doesn't
+# support long names like on DOS, Mac, or CD-ROM.
+# The default value is: NO.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then doxygen will interpret the
+# first line (until the first dot) of a Javadoc-style comment as the brief
+# description. If set to NO, the Javadoc-style will behave just like regular Qt-
+# style comments (thus requiring an explicit @brief command for a brief
+# description.)
+# The default value is: NO.
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then doxygen will interpret the first
+# line (until the first dot) of a Qt-style comment as the brief description. If
+# set to NO, the Qt-style will behave just like regular Qt-style comments (thus
+# requiring an explicit \brief command for a brief description.)
+# The default value is: NO.
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make doxygen treat a
+# multi-line C++ special comment block (i.e. a block of //! or /// comments) as
+# a brief description. This used to be the default behavior. The new default is
+# to treat a multi-line C++ comment block as a detailed description. Set this
+# tag to YES if you prefer the old behavior instead.
+#
+# Note that setting this tag to YES also means that rational rose comments are
+# not recognized any more.
+# The default value is: NO.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES then an undocumented member inherits the
+# documentation from any documented member that it re-implements.
+# The default value is: YES.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES then doxygen will produce a new
+# page for each member. If set to NO, the documentation of a member will be part
+# of the file/class/namespace that contains it.
+# The default value is: NO.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab. Doxygen
+# uses this value to replace tabs by spaces in code fragments.
+# Minimum value: 1, maximum value: 16, default value: 4.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that act as commands in
+# the documentation. An alias has the form:
+# name=value
+# For example adding
+# "sideeffect=@par Side Effects:\n"
+# will allow you to put the command \sideeffect (or @sideeffect) in the
+# documentation, which will result in a user-defined paragraph with heading
+# "Side Effects:". You can put \n's in the value part of an alias to insert
+# newlines.
+
+ALIASES =
+
+# This tag can be used to specify a number of word-keyword mappings (TCL only).
+# A mapping has the form "name=value". For example adding "class=itcl::class"
+# will allow you to use the command class in the itcl::class meaning.
+
+TCL_SUBST =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C sources
+# only. Doxygen will then generate output that is more tailored for C. For
+# instance, some of the names that are used will be different. The list of all
+# members will be omitted, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_FOR_C = YES
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java or
+# Python sources only. Doxygen will then generate output that is more tailored
+# for that language. For instance, namespaces will be presented as packages,
+# qualified scopes will look different, etc.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources. Doxygen will then generate output that is tailored for Fortran.
+# The default value is: NO.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for VHDL.
+# The default value is: NO.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it
+# parses. With this tag you can assign which parser to use for a given
+# extension. Doxygen has a built-in mapping, but you can override or extend it
+# using this tag. The format is ext=language, where ext is a file extension, and
+# language is one of the parsers supported by doxygen: IDL, Java, Javascript,
+# C#, C, C++, D, PHP, Objective-C, Python, Fortran (fixed format Fortran:
+# FortranFixed, free formatted Fortran: FortranFree, unknown formatted Fortran:
+# Fortran. In the later case the parser tries to guess whether the code is fixed
+# or free formatted code, this is the default for Fortran type files), VHDL. For
+# instance to make doxygen treat .inc files as Fortran files (default is PHP),
+# and .f files as C (default is Fortran), use: inc=Fortran f=C.
+#
+# Note: For files without extension you can use no_extension as a placeholder.
+#
+# Note that for custom extensions you also need to set FILE_PATTERNS otherwise
+# the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If the MARKDOWN_SUPPORT tag is enabled then doxygen pre-processes all comments
+# according to the Markdown format, which allows for more readable
+# documentation. See http://daringfireball.net/projects/markdown/ for details.
+# The output of markdown processing is further processed by doxygen, so you can
+# mix doxygen, HTML, and XML commands with Markdown formatting. Disable only in
+# case of backward compatibilities issues.
+# The default value is: YES.
+
+MARKDOWN_SUPPORT = YES
+
+# When enabled doxygen tries to link words that correspond to documented
+# classes, or namespaces to their corresponding documentation. Such a link can
+# be prevented in individual cases by putting a % sign in front of the word or
+# globally by setting AUTOLINK_SUPPORT to NO.
+# The default value is: YES.
+
+AUTOLINK_SUPPORT = YES
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should set this
+# tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string);
+# versus func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+# The default value is: NO.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+# The default value is: NO.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip (see:
+# http://www.riverbankcomputing.co.uk/software/sip/intro) sources only. Doxygen
+# will parse them like normal C++ but will assume all classes use public instead
+# of private inheritance when no explicit protection keyword is present.
+# The default value is: NO.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate
+# getter and setter methods for a property. Setting this option to YES will make
+# doxygen to replace the get and set methods by a property in the documentation.
+# This will only work if the methods are indeed getting or setting a simple
+# type. If this is not the case, or you want to show the methods anyway, you
+# should set this option to NO.
+# The default value is: YES.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+# The default value is: NO.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# If one adds a struct or class to a group and this option is enabled, then also
+# any nested class or struct is added to the same group. By default this option
+# is disabled and one has to add nested compounds explicitly via \ingroup.
+# The default value is: NO.
+
+GROUP_NESTED_COMPOUNDS = NO
+
+# Set the SUBGROUPING tag to YES to allow class member groups of the same type
+# (for instance a group of public functions) to be put as a subgroup of that
+# type (e.g. under the Public Functions section). Set it to NO to prevent
+# subgrouping. Alternatively, this can be done per class using the
+# \nosubgrouping command.
+# The default value is: YES.
+
+SUBGROUPING = YES
+
+# When the INLINE_GROUPED_CLASSES tag is set to YES, classes, structs and unions
+# are shown inside the group in which they are included (e.g. using \ingroup)
+# instead of on a separate page (for HTML and Man pages) or section (for LaTeX
+# and RTF).
+#
+# Note that this feature does not work in combination with
+# SEPARATE_MEMBER_PAGES.
+# The default value is: NO.
+
+INLINE_GROUPED_CLASSES = NO
+
+# When the INLINE_SIMPLE_STRUCTS tag is set to YES, structs, classes, and unions
+# with only public data fields or simple typedef fields will be shown inline in
+# the documentation of the scope in which they are defined (i.e. file,
+# namespace, or group documentation), provided this scope is documented. If set
+# to NO, structs, classes, and unions are shown on a separate page (for HTML and
+# Man pages) or section (for LaTeX and RTF).
+# The default value is: NO.
+
+INLINE_SIMPLE_STRUCTS = NO
+
+# When TYPEDEF_HIDES_STRUCT tag is enabled, a typedef of a struct, union, or
+# enum is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically be
+# useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+# The default value is: NO.
+
+TYPEDEF_HIDES_STRUCT = YES
+
+# The size of the symbol lookup cache can be set using LOOKUP_CACHE_SIZE. This
+# cache is used to resolve symbols given their name and scope. Since this can be
+# an expensive process and often the same symbol appears multiple times in the
+# code, doxygen keeps a cache of pre-resolved symbols. If the cache is too small
+# doxygen will become slower. If the cache is too large, memory is wasted. The
+# cache size is given by this formula: 2^(16+LOOKUP_CACHE_SIZE). The valid range
+# is 0..9, the default is 0, corresponding to a cache size of 2^16=65536
+# symbols. At the end of a run doxygen will report the cache usage and suggest
+# the optimal cache size from a speed point of view.
+# Minimum value: 0, maximum value: 9, default value: 0.
+
+LOOKUP_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES, doxygen will assume all entities in
+# documentation are documented, even if no documentation was available. Private
+# class members and static file members will be hidden unless the
+# EXTRACT_PRIVATE respectively EXTRACT_STATIC tags are set to YES.
+# Note: This will also disable the warnings about undocumented members that are
+# normally produced when WARNINGS is set to YES.
+# The default value is: NO.
+
+EXTRACT_ALL = YES
+
+# If the EXTRACT_PRIVATE tag is set to YES, all private members of a class will
+# be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_PACKAGE tag is set to YES, all members with package or internal
+# scope will be included in the documentation.
+# The default value is: NO.
+
+EXTRACT_PACKAGE = NO
+
+# If the EXTRACT_STATIC tag is set to YES, all static members of a file will be
+# included in the documentation.
+# The default value is: NO.
+
+EXTRACT_STATIC = YES
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES, classes (and structs) defined
+# locally in source files will be included in the documentation. If set to NO,
+# only classes defined in header files are included. Does not have any effect
+# for Java sources.
+# The default value is: YES.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. If set to YES, local methods,
+# which are defined in the implementation section but not in the interface are
+# included in the documentation. If set to NO, only methods in the interface are
+# included.
+# The default value is: NO.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base name of
+# the file that contains the anonymous namespace. By default anonymous namespace
+# are hidden.
+# The default value is: NO.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, doxygen will hide all
+# undocumented members inside documented classes or files. If set to NO these
+# members will be included in the various overviews, but no documentation
+# section is generated. This option has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy. If set
+# to NO, these classes will be included in the various overviews. This option
+# has no effect if EXTRACT_ALL is enabled.
+# The default value is: NO.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, doxygen will hide all friend
+# (class|struct|union) declarations. If set to NO, these declarations will be
+# included in the documentation.
+# The default value is: NO.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, doxygen will hide any
+# documentation blocks found inside the body of a function. If set to NO, these
+# blocks will be appended to the function's detailed documentation block.
+# The default value is: NO.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation that is typed after a
+# \internal command is included. If the tag is set to NO then the documentation
+# will be excluded. Set it to YES to include the internal documentation.
+# The default value is: NO.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then doxygen will only generate file
+# names in lower-case letters. If set to YES, upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+# The default value is: system dependent.
+
+CASE_SENSE_NAMES = YES
+
+# If the HIDE_SCOPE_NAMES tag is set to NO then doxygen will show members with
+# their full class and namespace scopes in the documentation. If set to YES, the
+# scope will be hidden.
+# The default value is: NO.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the HIDE_COMPOUND_REFERENCE tag is set to NO (default) then doxygen will
+# append additional text to a page's title, such as Class Reference. If set to
+# YES the compound reference will be hidden.
+# The default value is: NO.
+
+HIDE_COMPOUND_REFERENCE= NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES then doxygen will put a list of
+# the files that are included by a file in the documentation of that file.
+# The default value is: YES.
+
+SHOW_INCLUDE_FILES = NO
+
+# If the SHOW_GROUPED_MEMB_INC tag is set to YES then Doxygen will add for each
+# grouped member an include statement to the documentation, telling the reader
+# which file to include in order to use the member.
+# The default value is: NO.
+
+SHOW_GROUPED_MEMB_INC = NO
+
+# If the FORCE_LOCAL_INCLUDES tag is set to YES then doxygen will list include
+# files with double quotes in the documentation rather than with sharp brackets.
+# The default value is: NO.
+
+FORCE_LOCAL_INCLUDES = NO
+
+# If the INLINE_INFO tag is set to YES then a tag [inline] is inserted in the
+# documentation for inline members.
+# The default value is: YES.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES then doxygen will sort the
+# (detailed) documentation of file and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order.
+# The default value is: YES.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the brief
+# descriptions of file, namespace and class members alphabetically by member
+# name. If set to NO, the members will appear in declaration order. Note that
+# this will also influence the order of the classes in the class list.
+# The default value is: NO.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen will sort the
+# (brief and detailed) documentation of class members so that constructors and
+# destructors are listed first. If set to NO the constructors will appear in the
+# respective orders defined by SORT_BRIEF_DOCS and SORT_MEMBER_DOCS.
+# Note: If SORT_BRIEF_DOCS is set to NO this option is ignored for sorting brief
+# member documentation.
+# Note: If SORT_MEMBER_DOCS is set to NO this option is ignored for sorting
+# detailed member documentation.
+# The default value is: NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the hierarchy
+# of group names into alphabetical order. If set to NO the group names will
+# appear in their defined order.
+# The default value is: NO.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be sorted by
+# fully-qualified names, including namespaces. If set to NO, the class list will
+# be sorted only by class name, not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the alphabetical
+# list.
+# The default value is: NO.
+
+SORT_BY_SCOPE_NAME = NO
+
+# If the STRICT_PROTO_MATCHING option is enabled and doxygen fails to do proper
+# type resolution of all parameters of a function it will reject a match between
+# the prototype and the implementation of a member function even if there is
+# only one candidate or it is obvious which candidate to choose by doing a
+# simple string match. By disabling STRICT_PROTO_MATCHING doxygen will still
+# accept a match between prototype and implementation in such cases.
+# The default value is: NO.
+
+STRICT_PROTO_MATCHING = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or disable (NO) the todo
+# list. This list is created by putting \todo commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or disable (NO) the test
+# list. This list is created by putting \test commands in the documentation.
+# The default value is: YES.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or disable (NO) the bug
+# list. This list is created by putting \bug commands in the documentation.
+# The default value is: YES.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or disable (NO)
+# the deprecated list. This list is created by putting \deprecated commands in
+# the documentation.
+# The default value is: YES.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional documentation
+# sections, marked by \if <section_label> ... \endif and \cond <section_label>
+# ... \endcond blocks.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines that the
+# initial value of a variable or macro / define can have for it to appear in the
+# documentation. If the initializer consists of more lines than specified here
+# it will be hidden. Use a value of 0 to hide initializers completely. The
+# appearance of the value of individual variables and macros / defines can be
+# controlled using \showinitializer or \hideinitializer command in the
+# documentation regardless of this setting.
+# Minimum value: 0, maximum value: 10000, default value: 30.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated at
+# the bottom of the documentation of classes and structs. If set to YES, the
+# list will mention the files that were used to generate the documentation.
+# The default value is: YES.
+
+SHOW_USED_FILES = YES
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page. This
+# will remove the Files entry from the Quick Index and from the Folder Tree View
+# (if specified).
+# The default value is: YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the Namespaces
+# page. This will remove the Namespaces entry from the Quick Index and from the
+# Folder Tree View (if specified).
+# The default value is: YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command command input-file, where command is the value of the
+# FILE_VERSION_FILTER tag, and input-file is the name of an input file provided
+# by doxygen. Whatever the program writes to standard output is used as the file
+# version. For an example see the documentation.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed
+# by doxygen. The layout file controls the global structure of the generated
+# output files in an output format independent way. To create the layout file
+# that represents doxygen's defaults, run doxygen with the -l option. You can
+# optionally specify a file name after the option, if omitted DoxygenLayout.xml
+# will be used as the name of the layout file.
+#
+# Note that if you run doxygen from a directory containing a file called
+# DoxygenLayout.xml, doxygen will parse it automatically even if the LAYOUT_FILE
+# tag is left empty.
+
+LAYOUT_FILE =
+
+# The CITE_BIB_FILES tag can be used to specify one or more bib files containing
+# the reference definitions. This must be a list of .bib files. The .bib
+# extension is automatically appended if omitted. This requires the bibtex tool
+# to be installed. See also http://en.wikipedia.org/wiki/BibTeX for more info.
+# For LaTeX the style of the bibliography can be controlled using
+# LATEX_BIB_STYLE. To use this feature you need bibtex and perl available in the
+# search path. See also \cite for info how to create references.
+
+CITE_BIB_FILES =
+
+#---------------------------------------------------------------------------
+# Configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated to
+# standard output by doxygen. If QUIET is set to YES this implies that the
+# messages are off.
+# The default value is: NO.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated to standard error (stderr) by doxygen. If WARNINGS is set to YES
+# this implies that the warnings are on.
+#
+# Tip: Turn warnings on while writing the documentation.
+# The default value is: YES.
+
+WARNINGS = YES
+
+# If the WARN_IF_UNDOCUMENTED tag is set to YES then doxygen will generate
+# warnings for undocumented members. If EXTRACT_ALL is set to YES then this flag
+# will automatically be disabled.
+# The default value is: YES.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If the WARN_IF_DOC_ERROR tag is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some parameters
+# in a documented function, or documenting parameters that don't exist or using
+# markup commands wrongly.
+# The default value is: YES.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be enabled to get warnings for functions that
+# are documented, but have no documentation for their parameters or return
+# value. If set to NO, doxygen will only warn about wrong or incomplete
+# parameter documentation, but not about the absence of documentation.
+# The default value is: NO.
+
+WARN_NO_PARAMDOC = NO
+
+# If the WARN_AS_ERROR tag is set to YES then doxygen will immediately stop when
+# a warning is encountered.
+# The default value is: NO.
+
+WARN_AS_ERROR = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that doxygen
+# can produce. The string should contain the $file, $line, and $text tags, which
+# will be replaced by the file and line number from which the warning originated
+# and the warning text. Optionally the format may contain $version, which will
+# be replaced by the version of the file (if it could be obtained via
+# FILE_VERSION_FILTER)
+# The default value is: $file:$line: $text.
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning and error
+# messages should be written. If left blank the output is written to standard
+# error (stderr).
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag is used to specify the files and/or directories that contain
+# documented source files. You may enter file names like myfile.cpp or
+# directories like /usr/src/myproject. Separate the files or directories with
+# spaces. See also FILE_PATTERNS and EXTENSION_MAPPING
+# Note: If this tag is empty the current directory is searched.
+
+INPUT = inc/bearssl.h inc/bearssl_aead.h inc/bearssl_block.h inc/bearssl_ec.h inc/bearssl_hash.h inc/bearssl_hmac.h inc/bearssl_kdf.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
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding. Doxygen uses
+# libiconv (or the iconv built into libc) for the transcoding. See the libiconv
+# documentation (see: http://www.gnu.org/software/libiconv) for the list of
+# possible encodings.
+# The default value is: UTF-8.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard patterns (like *.cpp and
+# *.h) to filter out the source-files in the directories.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# read by doxygen.
+#
+# If left blank the following patterns are tested:*.c, *.cc, *.cxx, *.cpp,
+# *.c++, *.java, *.ii, *.ixx, *.ipp, *.i++, *.inl, *.idl, *.ddl, *.odl, *.h,
+# *.hh, *.hxx, *.hpp, *.h++, *.cs, *.d, *.php, *.php4, *.php5, *.phtml, *.inc,
+# *.m, *.markdown, *.md, *.mm, *.dox, *.py, *.pyw, *.f90, *.f, *.for, *.tcl,
+# *.vhd, *.vhdl, *.ucf, *.qsf, *.as and *.js.
+
+FILE_PATTERNS =
+
+# The RECURSIVE tag can be used to specify whether or not subdirectories should
+# be searched for input files as well.
+# The default value is: NO.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should be
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+#
+# Note that relative paths are relative to the directory from which doxygen is
+# run.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used to select whether or not files or
+# directories that are symbolic links (a Unix file system feature) are excluded
+# from the input.
+# The default value is: NO.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories.
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+#
+# Note that the wildcards are matched against the file with absolute path, so to
+# exclude all test directories use the pattern */test/*
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or directories
+# that contain example code fragments that are included (see the \include
+# command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp and
+# *.h) to filter out the source-files in the directories. If left blank all
+# files are included.
+
+EXAMPLE_PATTERNS =
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude commands
+# irrespective of the value of the RECURSIVE tag.
+# The default value is: NO.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or directories
+# that contain images that are to be included in the documentation (see the
+# \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command:
+#
+# <filter> <input-file>
+#
+# where <filter> is the value of the INPUT_FILTER tag, and <input-file> is the
+# name of an input file. Doxygen will then use the output that the filter
+# program writes to standard output. If FILTER_PATTERNS is specified, this tag
+# will be ignored.
+#
+# Note that the filter must not add or remove lines; it is applied before the
+# code is scanned, but not when the output code is generated. If lines are added
+# or removed, the anchors will not be placed correctly.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form: pattern=filter
+# (like *.cpp=my_cpp_filter). See INPUT_FILTER for further information on how
+# filters are used. If the FILTER_PATTERNS tag is empty or if none of the
+# patterns match the file name, INPUT_FILTER is applied.
+#
+# Note that for custom extensions or not directly supported extensions you also
+# need to set EXTENSION_MAPPING for the extension otherwise the files are not
+# properly processed by doxygen.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will also be used to filter the input files that are used for
+# producing the source files to browse (i.e. when SOURCE_BROWSER is set to YES).
+# The default value is: NO.
+
+FILTER_SOURCE_FILES = NO
+
+# The FILTER_SOURCE_PATTERNS tag can be used to specify source filters per file
+# pattern. A pattern will override the setting for FILTER_PATTERN (if any) and
+# it is also possible to disable source filtering for a specific pattern using
+# *.ext= (so without naming a filter).
+# This tag requires that the tag FILTER_SOURCE_FILES is set to YES.
+
+FILTER_SOURCE_PATTERNS =
+
+# If the USE_MDFILE_AS_MAINPAGE tag refers to the name of a markdown file that
+# is part of the input, its contents will be placed on the main page
+# (index.html). This can be useful if you have a project on for instance GitHub
+# and want to reuse the introduction page also for the doxygen output.
+
+USE_MDFILE_AS_MAINPAGE =
+
+#---------------------------------------------------------------------------
+# Configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will be
+# generated. Documented entities will be cross-referenced with these sources.
+#
+# Note: To get rid of all source code in the generated output, make sure that
+# also VERBATIM_HEADERS is set to NO.
+# The default value is: NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body of functions,
+# classes and enums directly into the documentation.
+# The default value is: NO.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES will instruct doxygen to hide any
+# special comment blocks from generated source code fragments. Normal C, C++ and
+# Fortran comments will always remain visible.
+# The default value is: YES.
+
+STRIP_CODE_COMMENTS = NO
+
+# If the REFERENCED_BY_RELATION tag is set to YES then for each documented
+# function all documented functions referencing it will be listed.
+# The default value is: NO.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES then for each documented function
+# all documented entities called/used by that function will be listed.
+# The default value is: NO.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES and SOURCE_BROWSER tag is set
+# to YES then the hyperlinks from functions in REFERENCES_RELATION and
+# REFERENCED_BY_RELATION lists will link to the source code. Otherwise they will
+# link to the documentation.
+# The default value is: YES.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If SOURCE_TOOLTIPS is enabled (the default) then hovering a hyperlink in the
+# source code will show a tooltip with additional information such as prototype,
+# brief description and links to the definition and documentation. Since this
+# will make the HTML file larger and loading of large files a bit slower, you
+# can opt to disable this feature.
+# The default value is: YES.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+SOURCE_TOOLTIPS = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code will
+# point to the HTML generated by the htags(1) tool instead of doxygen built-in
+# source browser. The htags tool is part of GNU's global source tagging system
+# (see http://www.gnu.org/software/global/global.html). You will need version
+# 4.8.6 or higher.
+#
+# To use it do the following:
+# - Install the latest version of global
+# - Enable SOURCE_BROWSER and USE_HTAGS in the config file
+# - Make sure the INPUT points to the root of the source tree
+# - Run doxygen as normal
+#
+# Doxygen will invoke htags (and that will in turn invoke gtags), so these
+# tools must be available from the command line (i.e. in the search path).
+#
+# The result: instead of the source browser generated by doxygen, the links to
+# source code will now point to the output of htags.
+# The default value is: NO.
+# This tag requires that the tag SOURCE_BROWSER is set to YES.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set the YES then doxygen will generate a
+# verbatim copy of the header file for each class for which an include is
+# specified. Set to NO to disable this.
+# See also: Section \class.
+# The default value is: YES.
+
+VERBATIM_HEADERS = YES
+
+# If the CLANG_ASSISTED_PARSING tag is set to YES then doxygen will use the
+# clang parser (see: http://clang.llvm.org/) for more accurate parsing at the
+# cost of reduced performance. This can be particularly helpful with template
+# rich C++ code for which doxygen's built-in parser lacks the necessary type
+# information.
+# Note: The availability of this option depends on whether or not doxygen was
+# generated with the -Duse-libclang=ON option for CMake.
+# The default value is: NO.
+
+CLANG_ASSISTED_PARSING = NO
+
+# If clang assisted parsing is enabled you can provide the compiler with command
+# line options that you would normally use when invoking the compiler. Note that
+# the include paths will already be set by doxygen for the files and directories
+# specified with INPUT and INCLUDE_PATH.
+# This tag requires that the tag CLANG_ASSISTED_PARSING is set to YES.
+
+CLANG_OPTIONS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index of all
+# compounds will be generated. Enable this if the project contains a lot of
+# classes, structs, unions or interfaces.
+# The default value is: YES.
+
+ALPHABETICAL_INDEX = YES
+
+# The COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns in
+# which the alphabetical index list will be split.
+# Minimum value: 1, maximum value: 20, default value: 5.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all classes will
+# be put under the same header in the alphabetical index. The IGNORE_PREFIX tag
+# can be used to specify a prefix (or a list of prefixes) that should be ignored
+# while generating the index headers.
+# This tag requires that the tag ALPHABETICAL_INDEX is set to YES.
+
+IGNORE_PREFIX = br_ BR_
+
+#---------------------------------------------------------------------------
+# Configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES, doxygen will generate HTML output
+# The default value is: YES.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for each
+# generated HTML page (for example: .htm, .php, .asp).
+# The default value is: .html.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a user-defined HTML header file for
+# each generated HTML page. If the tag is left blank doxygen will generate a
+# standard header.
+#
+# To get valid HTML the header file that includes any scripts and style sheets
+# that doxygen needs, which is dependent on the configuration options used (e.g.
+# the setting GENERATE_TREEVIEW). It is highly recommended to start with a
+# default header using
+# doxygen -w html new_header.html new_footer.html new_stylesheet.css
+# YourConfigFile
+# and then modify the file new_header.html. See also section "Doxygen usage"
+# for information on how to generate the default header that doxygen normally
+# uses.
+# Note: The header is subject to change so you typically have to regenerate the
+# default header when upgrading to a newer version of doxygen. For a description
+# of the possible markers and block names see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a user-defined HTML footer for each
+# generated HTML page. If the tag is left blank doxygen will generate a standard
+# footer. See HTML_HEADER for more information on how to generate a default
+# footer and what special commands can be used inside the footer. See also
+# section "Doxygen usage" for information on how to generate the default footer
+# that doxygen normally uses.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading style
+# sheet that is used by each HTML page. It can be used to fine-tune the look of
+# the HTML output. If left blank doxygen will generate a default style sheet.
+# See also section "Doxygen usage" for information on how to generate the style
+# sheet that doxygen normally uses.
+# Note: It is recommended to use HTML_EXTRA_STYLESHEET instead of this tag, as
+# it is more robust and this tag (HTML_STYLESHEET) will in the future become
+# obsolete.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_STYLESHEET =
+
+# The HTML_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# cascading style sheets that are included after the standard style sheets
+# created by doxygen. Using this option one can overrule certain style aspects.
+# This is preferred over using HTML_STYLESHEET since it does not replace the
+# standard style sheet and is therefore more robust against future updates.
+# Doxygen will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list). For an example see the documentation.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_STYLESHEET =
+
+# The HTML_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the HTML output directory. Note
+# that these files will be copied to the base HTML output directory. Use the
+# $relpath^ marker in the HTML_HEADER and/or HTML_FOOTER files to load these
+# files. In the HTML_STYLESHEET file, use the file name only. Also note that the
+# files will be copied as-is; there are no commands or markers available.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_EXTRA_FILES =
+
+# The HTML_COLORSTYLE_HUE tag controls the color of the HTML output. Doxygen
+# will adjust the colors in the style sheet and background images according to
+# this color. Hue is specified as an angle on a colorwheel, see
+# http://en.wikipedia.org/wiki/Hue for more information. For instance the value
+# 0 represents red, 60 is yellow, 120 is green, 180 is cyan, 240 is blue, 300
+# purple, and 360 is red again.
+# Minimum value: 0, maximum value: 359, default value: 220.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_HUE = 45
+
+# The HTML_COLORSTYLE_SAT tag controls the purity (or saturation) of the colors
+# in the HTML output. For a value of 0 the output will use grayscales only. A
+# value of 255 will produce the most vivid colors.
+# Minimum value: 0, maximum value: 255, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_SAT = 150
+
+# The HTML_COLORSTYLE_GAMMA tag controls the gamma correction applied to the
+# luminance component of the colors in the HTML output. Values below 100
+# gradually make the output lighter, whereas values above 100 make the output
+# darker. The value divided by 100 is the actual gamma applied, so 80 represents
+# a gamma of 0.8, The value 220 represents a gamma of 2.2, and 100 does not
+# change the gamma.
+# Minimum value: 40, maximum value: 240, default value: 80.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_COLORSTYLE_GAMMA = 80
+
+# If the HTML_TIMESTAMP tag is set to YES then the footer of each generated HTML
+# page will contain the date and time when the page was generated. Setting this
+# to YES can help to show when doxygen was last run and thus if the
+# documentation is up to date.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_TIMESTAMP = NO
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# With HTML_INDEX_NUM_ENTRIES one can control the preferred number of entries
+# shown in the various tree structured indices initially; the user can expand
+# and collapse entries dynamically later on. Doxygen will expand the tree to
+# such a level that at most the specified number of entries are visible (unless
+# a fully collapsed tree already exceeds this amount). So setting the number of
+# entries 1 will produce a full collapsed tree by default. 0 is a special value
+# representing an infinite number of entries and will result in a full expanded
+# tree by default.
+# Minimum value: 0, maximum value: 9999, default value: 100.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+HTML_INDEX_NUM_ENTRIES = 100
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files will be
+# generated that can be used as input for Apple's Xcode 3 integrated development
+# environment (see: http://developer.apple.com/tools/xcode/), introduced with
+# OSX 10.5 (Leopard). To create a documentation set, doxygen will generate a
+# Makefile in the HTML output directory. Running make will produce the docset in
+# that directory and running make install will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find it at
+# startup. See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html
+# for more information.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_DOCSET = NO
+
+# This tag determines the name of the docset feed. A documentation feed provides
+# an umbrella under which multiple documentation sets from a single provider
+# (such as a company or product suite) can be grouped.
+# The default value is: Doxygen generated docs.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# This tag specifies a string that should uniquely identify the documentation
+# set bundle. This should be a reverse domain-name style string, e.g.
+# com.mycompany.MyDocSet. Doxygen will append .docset to the name.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# The DOCSET_PUBLISHER_ID tag specifies a string that should uniquely identify
+# the documentation publisher. This should be a reverse domain-name style
+# string, e.g. com.mycompany.MyDocSet.documentation.
+# The default value is: org.doxygen.Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_ID = org.doxygen.Publisher
+
+# The DOCSET_PUBLISHER_NAME tag identifies the documentation publisher.
+# The default value is: Publisher.
+# This tag requires that the tag GENERATE_DOCSET is set to YES.
+
+DOCSET_PUBLISHER_NAME = Publisher
+
+# If the GENERATE_HTMLHELP tag is set to YES then doxygen generates three
+# additional HTML index files: index.hhp, index.hhc, and index.hhk. The
+# index.hhp is a project file that can be read by Microsoft's HTML Help Workshop
+# (see: http://www.microsoft.com/en-us/download/details.aspx?id=21138) on
+# Windows.
+#
+# The HTML Help Workshop contains a compiler that can convert all HTML output
+# generated by doxygen into a single compiled HTML file (.chm). Compiled HTML
+# files are now used as the Windows 98 help format, and will replace the old
+# Windows help format (.hlp) on all Windows platforms in the future. Compressed
+# HTML files also contain an index, a table of contents, and you can search for
+# words in the documentation. The HTML workshop also contains a viewer for
+# compressed HTML files.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_HTMLHELP = NO
+
+# The CHM_FILE tag can be used to specify the file name of the resulting .chm
+# file. You can add a path in front of the file if the result should not be
+# written to the html output directory.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_FILE =
+
+# The HHC_LOCATION tag can be used to specify the location (absolute path
+# including file name) of the HTML help compiler (hhc.exe). If non-empty,
+# doxygen will try to run the HTML help compiler on the generated index.hhp.
+# The file has to be specified with full path.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+HHC_LOCATION =
+
+# The GENERATE_CHI flag controls if a separate .chi index file is generated
+# (YES) or that it should be included in the master .chm file (NO).
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+GENERATE_CHI = NO
+
+# The CHM_INDEX_ENCODING is used to encode HtmlHelp index (hhk), content (hhc)
+# and project file content.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+CHM_INDEX_ENCODING =
+
+# The BINARY_TOC flag controls whether a binary table of contents is generated
+# (YES) or a normal table of contents (NO) in the .chm file. Furthermore it
+# enables the Previous and Next buttons.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members to
+# the table of contents of the HTML help documentation and to the tree view.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTMLHELP is set to YES.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and
+# QHP_VIRTUAL_FOLDER are set, an additional index file will be generated that
+# can be used as input for Qt's qhelpgenerator to generate a Qt Compressed Help
+# (.qch) of the generated HTML documentation.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can be used to specify
+# the file name of the resulting .qch file. The path specified is relative to
+# the HTML output folder.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating Qt Help
+# Project output. For more information please see Qt Help Project / Namespace
+# (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#namespace).
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_NAMESPACE = org.doxygen.Project
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating Qt
+# Help Project output. For more information please see Qt Help Project / Virtual
+# Folders (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#virtual-
+# folders).
+# The default value is: doc.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If the QHP_CUST_FILTER_NAME tag is set, it specifies the name of a custom
+# filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILTER_ATTRS tag specifies the list of the attributes of the
+# custom filter to add. For more information please see Qt Help Project / Custom
+# Filters (see: http://qt-project.org/doc/qt-4.8/qthelpproject.html#custom-
+# filters).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this
+# project's filter section matches. Qt Help Project / Filter Attributes (see:
+# http://qt-project.org/doc/qt-4.8/qthelpproject.html#filter-attributes).
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHP_SECT_FILTER_ATTRS =
+
+# The QHG_LOCATION tag can be used to specify the location of Qt's
+# qhelpgenerator. If non-empty doxygen will try to run qhelpgenerator on the
+# generated .qhp file.
+# This tag requires that the tag GENERATE_QHP is set to YES.
+
+QHG_LOCATION =
+
+# If the GENERATE_ECLIPSEHELP tag is set to YES, additional index files will be
+# generated, together with the HTML files, they form an Eclipse help plugin. To
+# install this plugin and make it available under the help contents menu in
+# Eclipse, the contents of the directory containing the HTML and XML files needs
+# to be copied into the plugins directory of eclipse. The name of the directory
+# within the plugins directory should be the same as the ECLIPSE_DOC_ID value.
+# After copying Eclipse needs to be restarted before the help appears.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_ECLIPSEHELP = NO
+
+# A unique identifier for the Eclipse help plugin. When installing the plugin
+# the directory name containing the HTML and XML files should also have this
+# name. Each documentation set should have its own identifier.
+# The default value is: org.doxygen.Project.
+# This tag requires that the tag GENERATE_ECLIPSEHELP is set to YES.
+
+ECLIPSE_DOC_ID = org.doxygen.Project
+
+# If you want full control over the layout of the generated HTML pages it might
+# be necessary to disable the index and replace it with your own. The
+# DISABLE_INDEX tag can be used to turn on/off the condensed index (tabs) at top
+# of each HTML page. A value of NO enables the index and the value YES disables
+# it. Since the tabs in the index contain the same information as the navigation
+# tree, you can set this option to YES if you also set GENERATE_TREEVIEW to YES.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+DISABLE_INDEX = NO
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information. If the tag
+# value is set to YES, a side panel will be generated containing a tree-like
+# index structure (just like the one that is generated for HTML Help). For this
+# to work a browser that supports JavaScript, DHTML, CSS and frames is required
+# (i.e. any modern browser). Windows users are probably better off using the
+# HTML help feature. Via custom style sheets (see HTML_EXTRA_STYLESHEET) one can
+# further fine-tune the look of the index. As an example, the default style
+# sheet generated by doxygen has an example that shows how to put an image at
+# the root of the tree instead of the PROJECT_NAME. Since the tree basically has
+# the same information as the tab index, you could consider setting
+# DISABLE_INDEX to YES when enabling this option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+GENERATE_TREEVIEW = NO
+
+# The ENUM_VALUES_PER_LINE tag can be used to set the number of enum values that
+# doxygen will group on one line in the generated HTML documentation.
+#
+# Note that a value of 0 will completely suppress the enum values from appearing
+# in the overview section.
+# Minimum value: 0, maximum value: 20, default value: 4.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+ENUM_VALUES_PER_LINE = 4
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be used
+# to set the initial width (in pixels) of the frame in which the tree is shown.
+# Minimum value: 0, maximum value: 1500, default value: 250.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+TREEVIEW_WIDTH = 250
+
+# If the EXT_LINKS_IN_WINDOW option is set to YES, doxygen will open links to
+# external symbols imported via tag files in a separate window.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+EXT_LINKS_IN_WINDOW = NO
+
+# Use this tag to change the font size of LaTeX formulas included as images in
+# the HTML documentation. When you change the font size after a successful
+# doxygen run you need to manually remove any form_*.png images from the HTML
+# output directory to force them to be regenerated.
+# Minimum value: 8, maximum value: 50, default value: 10.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_FONTSIZE = 10
+
+# Use the FORMULA_TRANPARENT tag to determine whether or not the images
+# generated for formulas are transparent PNGs. Transparent PNGs are not
+# supported properly for IE 6.0, but are supported on all modern browsers.
+#
+# Note that when changing this option you need to delete any form_*.png files in
+# the HTML output directory before the changes have effect.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+FORMULA_TRANSPARENT = YES
+
+# Enable the USE_MATHJAX option to render LaTeX formulas using MathJax (see
+# http://www.mathjax.org) which uses client side Javascript for the rendering
+# instead of using pre-rendered bitmaps. Use this if you do not have LaTeX
+# installed or if you want to formulas look prettier in the HTML output. When
+# enabled you may also need to install MathJax separately and configure the path
+# to it using the MATHJAX_RELPATH option.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+USE_MATHJAX = NO
+
+# When MathJax is enabled you can set the default output format to be used for
+# the MathJax output. See the MathJax site (see:
+# http://docs.mathjax.org/en/latest/output.html) for more details.
+# Possible values are: HTML-CSS (which is slower, but has the best
+# compatibility), NativeMML (i.e. MathML) and SVG.
+# The default value is: HTML-CSS.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_FORMAT = HTML-CSS
+
+# When MathJax is enabled you need to specify the location relative to the HTML
+# output directory using the MATHJAX_RELPATH option. The destination directory
+# should contain the MathJax.js script. For instance, if the mathjax directory
+# is located at the same level as the HTML output directory, then
+# MATHJAX_RELPATH should be ../mathjax. The default value points to the MathJax
+# Content Delivery Network so you can quickly see the result without installing
+# MathJax. However, it is strongly recommended to install a local copy of
+# MathJax from http://www.mathjax.org before deployment.
+# The default value is: http://cdn.mathjax.org/mathjax/latest.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_RELPATH = http://cdn.mathjax.org/mathjax/latest
+
+# The MATHJAX_EXTENSIONS tag can be used to specify one or more MathJax
+# extension names that should be enabled during MathJax rendering. For example
+# MATHJAX_EXTENSIONS = TeX/AMSmath TeX/AMSsymbols
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_EXTENSIONS =
+
+# The MATHJAX_CODEFILE tag can be used to specify a file with javascript pieces
+# of code that will be used on startup of the MathJax code. See the MathJax site
+# (see: http://docs.mathjax.org/en/latest/output.html) for more details. For an
+# example see the documentation.
+# This tag requires that the tag USE_MATHJAX is set to YES.
+
+MATHJAX_CODEFILE =
+
+# When the SEARCHENGINE tag is enabled doxygen will generate a search box for
+# the HTML output. The underlying search engine uses javascript and DHTML and
+# should work on any modern browser. Note that when using HTML help
+# (GENERATE_HTMLHELP), Qt help (GENERATE_QHP), or docsets (GENERATE_DOCSET)
+# there is already a search function so this one should typically be disabled.
+# For large projects the javascript based search engine can be slow, then
+# enabling SERVER_BASED_SEARCH may provide a better solution. It is possible to
+# search using the keyboard; to jump to the search box use <access key> + S
+# (what the <access key> is depends on the OS and browser, but it is typically
+# <CTRL>, <ALT>/<option>, or both). Inside the search box use the <cursor down
+# key> to jump into the search results window, the results can be navigated
+# using the <cursor keys>. Press <Enter> to select an item or <escape> to cancel
+# the search. The filter options can be selected when the cursor is inside the
+# search box by pressing <Shift>+<cursor down>. Also here use the <cursor keys>
+# to select a filter and <Enter> or <escape> to activate or cancel the filter
+# option.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_HTML is set to YES.
+
+SEARCHENGINE = YES
+
+# When the SERVER_BASED_SEARCH tag is enabled the search engine will be
+# implemented using a web server instead of a web client using Javascript. There
+# are two flavors of web server based searching depending on the EXTERNAL_SEARCH
+# setting. When disabled, doxygen will generate a PHP script for searching and
+# an index file used by the script. When EXTERNAL_SEARCH is enabled the indexing
+# and searching needs to be provided by external tools. See the section
+# "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SERVER_BASED_SEARCH = NO
+
+# When EXTERNAL_SEARCH tag is enabled doxygen will no longer generate the PHP
+# script for searching. Instead the search results are written to an XML file
+# which needs to be processed by an external indexer. Doxygen will invoke an
+# external search engine pointed to by the SEARCHENGINE_URL option to obtain the
+# search results.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/).
+#
+# See the section "External Indexing and Searching" for details.
+# The default value is: NO.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH = NO
+
+# The SEARCHENGINE_URL should point to a search engine hosted by a web server
+# which will return the search results when EXTERNAL_SEARCH is enabled.
+#
+# Doxygen ships with an example indexer (doxyindexer) and search engine
+# (doxysearch.cgi) which are based on the open source search engine library
+# Xapian (see: http://xapian.org/). See the section "External Indexing and
+# Searching" for details.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHENGINE_URL =
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the unindexed
+# search data is written to a file for indexing by an external tool. With the
+# SEARCHDATA_FILE tag the name of this file can be specified.
+# The default file is: searchdata.xml.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+SEARCHDATA_FILE = searchdata.xml
+
+# When SERVER_BASED_SEARCH and EXTERNAL_SEARCH are both enabled the
+# EXTERNAL_SEARCH_ID tag can be used as an identifier for the project. This is
+# useful in combination with EXTRA_SEARCH_MAPPINGS to search through multiple
+# projects and redirect the results back to the right project.
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTERNAL_SEARCH_ID =
+
+# The EXTRA_SEARCH_MAPPINGS tag can be used to enable searching through doxygen
+# projects other than the one defined by this configuration file, but that are
+# all added to the same external search index. Each project needs to have a
+# unique id set via EXTERNAL_SEARCH_ID. The search mapping then maps the id of
+# to a relative location where the documentation can be found. The format is:
+# EXTRA_SEARCH_MAPPINGS = tagname1=loc1 tagname2=loc2 ...
+# This tag requires that the tag SEARCHENGINE is set to YES.
+
+EXTRA_SEARCH_MAPPINGS =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES, doxygen will generate LaTeX output.
+# The default value is: YES.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked.
+#
+# Note that when enabling USE_PDFLATEX this option is only used for generating
+# bitmaps for formulas in the HTML output, but not in the Makefile that is
+# written to the output directory.
+# The default file is: latex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to generate
+# index for LaTeX.
+# The default file is: makeindex.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES, doxygen generates more compact LaTeX
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used by the
+# printer.
+# Possible values are: a4 (210 x 297 mm), letter (8.5 x 11 inches), legal (8.5 x
+# 14 inches) and executive (7.25 x 10.5 inches).
+# The default value is: a4.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PAPER_TYPE = a4
+
+# The EXTRA_PACKAGES tag can be used to specify one or more LaTeX package names
+# that should be included in the LaTeX output. The package can be specified just
+# by its name or with the correct syntax as to be used with the LaTeX
+# \usepackage command. To get the times font for instance you can specify :
+# EXTRA_PACKAGES=times or EXTRA_PACKAGES={times}
+# To use the option intlimits with the amsmath package you can specify:
+# EXTRA_PACKAGES=[intlimits]{amsmath}
+# If left blank no extra packages will be included.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for the
+# generated LaTeX document. The header should contain everything until the first
+# chapter. If it is left blank doxygen will generate a standard header. See
+# section "Doxygen usage" for information on how to let doxygen write the
+# default header to a separate file.
+#
+# Note: Only use a user-defined header if you know what you are doing! The
+# following commands have a special meaning inside the header: $title,
+# $datetime, $date, $doxygenversion, $projectname, $projectnumber,
+# $projectbrief, $projectlogo. Doxygen will replace $title with the empty
+# string, for the replacement values of the other commands the user is referred
+# to HTML_HEADER.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HEADER =
+
+# The LATEX_FOOTER tag can be used to specify a personal LaTeX footer for the
+# generated LaTeX document. The footer should contain everything after the last
+# chapter. If it is left blank doxygen will generate a standard footer. See
+# LATEX_HEADER for more information on how to generate a default footer and what
+# special commands can be used inside the footer.
+#
+# Note: Only use a user-defined footer if you know what you are doing!
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_FOOTER =
+
+# The LATEX_EXTRA_STYLESHEET tag can be used to specify additional user-defined
+# LaTeX style sheets that are included after the standard style sheets created
+# by doxygen. Using this option one can overrule certain style aspects. Doxygen
+# will copy the style sheet files to the output directory.
+# Note: The order of the extra style sheet files is of importance (e.g. the last
+# style sheet in the list overrules the setting of the previous ones in the
+# list).
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_STYLESHEET =
+
+# The LATEX_EXTRA_FILES tag can be used to specify one or more extra images or
+# other source files which should be copied to the LATEX_OUTPUT output
+# directory. Note that the files will be copied as-is; there are no commands or
+# markers available.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_EXTRA_FILES =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated is
+# prepared for conversion to PDF (using ps2pdf or pdflatex). The PDF file will
+# contain links (just like the HTML output) instead of page references. This
+# makes the output suitable for online browsing using a PDF viewer.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, doxygen will use pdflatex to generate
+# the PDF file directly from the LaTeX files. Set this option to YES, to get a
+# higher quality PDF documentation.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \batchmode
+# command to the generated LaTeX files. This will instruct LaTeX to keep running
+# if errors occur, instead of asking the user for help. This option is also used
+# when generating formulas in HTML.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BATCHMODE = NO
+
+# If the LATEX_HIDE_INDICES tag is set to YES then doxygen will not include the
+# index chapters (such as File Index, Compound Index, etc.) in the output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_HIDE_INDICES = NO
+
+# If the LATEX_SOURCE_CODE tag is set to YES then doxygen will include source
+# code with syntax highlighting in the LaTeX output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_SOURCE_CODE = NO
+
+# The LATEX_BIB_STYLE tag can be used to specify the style to use for the
+# bibliography, e.g. plainnat, or ieeetr. See
+# http://en.wikipedia.org/wiki/BibTeX and \cite for more info.
+# The default value is: plain.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_BIB_STYLE = plain
+
+# If the LATEX_TIMESTAMP tag is set to YES then the footer of each generated
+# page will contain the date and time when the page was generated. Setting this
+# to NO can help when comparing the output of multiple runs.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_LATEX is set to YES.
+
+LATEX_TIMESTAMP = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES, doxygen will generate RTF output. The
+# RTF output is optimized for Word 97 and may not look too pretty with other RTF
+# readers/editors.
+# The default value is: NO.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: rtf.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES, doxygen generates more compact RTF
+# documents. This may be useful for small projects and may help to save some
+# trees in general.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated will
+# contain hyperlink fields. The RTF file will contain links (just like the HTML
+# output) instead of page references. This makes the output suitable for online
+# browsing using Word or some other Word compatible readers that support those
+# fields.
+#
+# Note: WordPad (write) and others do not support links.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's config
+# file, i.e. a series of assignments. You only have to provide replacements,
+# missing definitions are set to their default value.
+#
+# See also section "Doxygen usage" for information on how to generate the
+# default style sheet that doxygen normally uses.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an RTF document. Syntax is
+# similar to doxygen's config file. A template extensions file can be generated
+# using doxygen -e rtf extensionFile.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_EXTENSIONS_FILE =
+
+# If the RTF_SOURCE_CODE tag is set to YES then doxygen will include source code
+# with syntax highlighting in the RTF output.
+#
+# Note that which sources are shown also depends on other settings such as
+# SOURCE_BROWSER.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_RTF is set to YES.
+
+RTF_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES, doxygen will generate man pages for
+# classes and files.
+# The default value is: NO.
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it. A directory man3 will be created inside the directory specified by
+# MAN_OUTPUT.
+# The default directory is: man.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to the generated
+# man pages. In case the manual section does not start with a number, the number
+# 3 is prepended. The dot (.) at the beginning of the MAN_EXTENSION tag is
+# optional.
+# The default value is: .3.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_EXTENSION = .3
+
+# The MAN_SUBDIR tag determines the name of the directory created within
+# MAN_OUTPUT in which the man pages are placed. If defaults to man followed by
+# MAN_EXTENSION with the initial . removed.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_SUBDIR =
+
+# If the MAN_LINKS tag is set to YES and doxygen generates man output, then it
+# will generate one additional man file for each entity documented in the real
+# man page(s). These additional files only source the real man page, but without
+# them the man command would be unable to find the correct page.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_MAN is set to YES.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES, doxygen will generate an XML file that
+# captures the structure of the code including all documentation.
+# The default value is: NO.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put. If a
+# relative path is entered the value of OUTPUT_DIRECTORY will be put in front of
+# it.
+# The default directory is: xml.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_OUTPUT = xml
+
+# If the XML_PROGRAMLISTING tag is set to YES, doxygen will dump the program
+# listings (including syntax highlighting and cross-referencing information) to
+# the XML output. Note that enabling this will significantly increase the size
+# of the XML output.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_XML is set to YES.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to the DOCBOOK output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_DOCBOOK tag is set to YES, doxygen will generate Docbook files
+# that can be used to generate PDF.
+# The default value is: NO.
+
+GENERATE_DOCBOOK = NO
+
+# The DOCBOOK_OUTPUT tag is used to specify where the Docbook pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be put in
+# front of it.
+# The default directory is: docbook.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_OUTPUT = docbook
+
+# If the DOCBOOK_PROGRAMLISTING tag is set to YES, doxygen will include the
+# program listings (including syntax highlighting and cross-referencing
+# information) to the DOCBOOK output. Note that enabling this will significantly
+# increase the size of the DOCBOOK output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_DOCBOOK is set to YES.
+
+DOCBOOK_PROGRAMLISTING = NO
+
+#---------------------------------------------------------------------------
+# Configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES, doxygen will generate an
+# AutoGen Definitions (see http://autogen.sf.net) file that captures the
+# structure of the code including all documentation. Note that this feature is
+# still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# Configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES, doxygen will generate a Perl module
+# file that captures the structure of the code including all documentation.
+#
+# Note that this feature is still experimental and incomplete at the moment.
+# The default value is: NO.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES, doxygen will generate the necessary
+# Makefile rules, Perl scripts and LaTeX code to be able to generate PDF and DVI
+# output from the Perl module output.
+# The default value is: NO.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES, the Perl module output will be nicely
+# formatted so it can be parsed by a human reader. This is useful if you want to
+# understand what is going on. On the other hand, if this tag is set to NO, the
+# size of the Perl module output will be much smaller and Perl will parse it
+# just the same.
+# The default value is: YES.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file are
+# prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX. This is useful
+# so different doxyrules.make files included by the same Makefile don't
+# overwrite each other's variables.
+# This tag requires that the tag GENERATE_PERLMOD is set to YES.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES, doxygen will evaluate all
+# C-preprocessor directives found in the sources and include files.
+# The default value is: YES.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES, doxygen will expand all macro names
+# in the source code. If set to NO, only conditional compilation will be
+# performed. Macro expansion can be done in a controlled way by setting
+# EXPAND_ONLY_PREDEF to YES.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES then
+# the macro expansion is limited to the macros specified with the PREDEFINED and
+# EXPAND_AS_DEFINED tags.
+# The default value is: NO.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES, the include files in the
+# INCLUDE_PATH will be searched if a #include is found.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by the
+# preprocessor.
+# This tag requires that the tag SEARCH_INCLUDES is set to YES.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will be
+# used.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that are
+# defined before the preprocessor is started (similar to the -D option of e.g.
+# gcc). The argument of the tag is a list of macros of the form: name or
+# name=definition (no spaces). If the definition and the "=" are omitted, "=1"
+# is assumed. To prevent a macro definition from being undefined via #undef or
+# recursively expanded use the := operator instead of the = operator.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+PREDEFINED = BR_DOXYGEN_IGNORE
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then this
+# tag can be used to specify a list of macro names that should be expanded. The
+# macro definition that is found in the sources will be used. Use the PREDEFINED
+# tag if you want to use a different macro definition that overrules the
+# definition found in the source code.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES then doxygen's preprocessor will
+# remove all references to function-like macros that are alone on a line, have
+# an all uppercase name, and do not end with a semicolon. Such function macros
+# are typically used for boiler-plate code, and will confuse the parser if not
+# removed.
+# The default value is: YES.
+# This tag requires that the tag ENABLE_PREPROCESSING is set to YES.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration options related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES tag can be used to specify one or more tag files. For each tag
+# file the location of the external documentation should be added. The format of
+# a tag file without this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where loc1 and loc2 can be relative or absolute paths or URLs. See the
+# section "Linking to external documentation" for more information about the use
+# of tag files.
+# Note: Each tag file must have a unique name (where the name does NOT include
+# the path). If a tag file is not located in the directory in which doxygen is
+# run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create a
+# tag file that is based on the input files it reads. See section "Linking to
+# external documentation" for more information about the usage of tag files.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES, all external class will be listed in
+# the class index. If set to NO, only the inherited external classes will be
+# listed.
+# The default value is: NO.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES, all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will be
+# listed.
+# The default value is: YES.
+
+EXTERNAL_GROUPS = YES
+
+# If the EXTERNAL_PAGES tag is set to YES, all external pages will be listed in
+# the related pages index. If set to NO, only the current project's pages will
+# be listed.
+# The default value is: YES.
+
+EXTERNAL_PAGES = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of 'which perl').
+# The default file (with absolute path) is: /usr/bin/perl.
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES, doxygen will generate a class diagram
+# (in HTML and LaTeX) for classes with base or super classes. Setting the tag to
+# NO turns the diagrams off. Note that this option also works with HAVE_DOT
+# disabled, but it is recommended to install and use dot, since it yields more
+# powerful graphs.
+# The default value is: YES.
+
+CLASS_DIAGRAMS = NO
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see:
+# http://www.mcternan.me.uk/mscgen/)) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# You can include diagrams made with dia in doxygen documentation. Doxygen will
+# then run dia to produce the diagram and insert it in the documentation. The
+# DIA_PATH tag allows you to specify the directory where the dia binary resides.
+# If left empty dia is assumed to be found in the default search path.
+
+DIA_PATH =
+
+# If set to YES the inheritance and collaboration graphs will hide inheritance
+# and usage relations if the target is undocumented or is not a class.
+# The default value is: YES.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz (see:
+# http://www.graphviz.org/), a graph visualization toolkit from AT&T and Lucent
+# Bell Labs. The other options in this section have no effect if this option is
+# set to NO
+# The default value is: YES.
+
+HAVE_DOT = YES
+
+# The DOT_NUM_THREADS specifies the number of dot invocations doxygen is allowed
+# to run in parallel. When set to 0 doxygen will base this on the number of
+# processors available in the system. You can set it explicitly to a value
+# larger than 0 to get control over the balance between CPU load and processing
+# speed.
+# Minimum value: 0, maximum value: 32, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_NUM_THREADS = 0
+
+# When you want a differently looking font in the dot files that doxygen
+# generates you can specify the font name using DOT_FONTNAME. You need to make
+# sure dot is able to find the font, which can be done by putting it in a
+# standard location or by setting the DOTFONTPATH environment variable or by
+# setting DOT_FONTPATH to the directory containing the font.
+# The default value is: Helvetica.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTNAME = Helvetica
+
+# The DOT_FONTSIZE tag can be used to set the size (in points) of the font of
+# dot graphs.
+# Minimum value: 4, maximum value: 24, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the default font as specified with
+# DOT_FONTNAME. If you specify a different font using DOT_FONTNAME you can set
+# the path where dot can find it using this tag.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH tag is set to YES then doxygen will generate a graph for
+# each documented class showing the direct and indirect inheritance relations.
+# Setting this tag to YES will force the CLASS_DIAGRAMS tag to NO.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CLASS_GRAPH = NO
+
+# If the COLLABORATION_GRAPH tag is set to YES then doxygen will generate a
+# graph for each documented class showing the direct and indirect implementation
+# dependencies (inheritance, containment, and class references variables) of the
+# class with other documented classes.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+COLLABORATION_GRAPH = NO
+
+# If the GROUP_GRAPHS tag is set to YES then doxygen will generate a graph for
+# groups, showing the direct groups dependencies.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GROUP_GRAPHS = NO
+
+# If the UML_LOOK tag is set to YES, doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LOOK = NO
+
+# If the UML_LOOK tag is enabled, the fields and methods are shown inside the
+# class node. If there are many fields or methods and many nodes the graph may
+# become too big to be useful. The UML_LIMIT_NUM_FIELDS threshold limits the
+# number of items for each type to make the size more manageable. Set this to 0
+# for no limit. Note that the threshold may be exceeded by 50% before the limit
+# is enforced. So when you set the threshold to 10, up to 15 fields may appear,
+# but if the number exceeds 15, the total amount of fields shown is limited to
+# 10.
+# Minimum value: 0, maximum value: 100, default value: 10.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+UML_LIMIT_NUM_FIELDS = 10
+
+# If the TEMPLATE_RELATIONS tag is set to YES then the inheritance and
+# collaboration graphs will show the relations between templates and their
+# instances.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+TEMPLATE_RELATIONS = NO
+
+# If the INCLUDE_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are set to
+# YES then doxygen will generate a graph for each documented file showing the
+# direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDE_GRAPH = YES
+
+# If the INCLUDED_BY_GRAPH, ENABLE_PREPROCESSING and SEARCH_INCLUDES tags are
+# set to YES then doxygen will generate a graph for each documented file showing
+# the direct and indirect include dependencies of the file with other documented
+# files.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH tag is set to YES then doxygen will generate a call
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable call graphs for selected
+# functions only using the \callgraph command. Disabling a call graph can be
+# accomplished by means of the command \hidecallgraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH tag is set to YES then doxygen will generate a caller
+# dependency graph for every global function or class method.
+#
+# Note that enabling this option will significantly increase the time of a run.
+# So in most cases it will be better to enable caller graphs for selected
+# functions only using the \callergraph command. Disabling a caller graph can be
+# accomplished by means of the command \hidecallergraph.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY tag is set to YES then doxygen will graphical
+# hierarchy of all classes instead of a textual one.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH tag is set to YES then doxygen will show the
+# dependencies a directory has on other directories in a graphical way. The
+# dependency relations are determined by the #include relations between the
+# files in the directories.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. For an explanation of the image formats see the section
+# output formats in the documentation of the dot tool (Graphviz (see:
+# http://www.graphviz.org/)).
+# Note: If you choose svg you need to set HTML_FILE_EXTENSION to xhtml in order
+# to make the SVG files visible in IE 9+ (other browsers do not have this
+# requirement).
+# Possible values are: png, png:cairo, png:cairo:cairo, png:cairo:gd, png:gd,
+# png:gd:gd, jpg, jpg:cairo, jpg:cairo:gd, jpg:gd, jpg:gd:gd, gif, gif:cairo,
+# gif:cairo:gd, gif:gd, gif:gd:gd, svg, png:gd, png:gd:gd, png:cairo,
+# png:cairo:gd, png:cairo:cairo, png:cairo:gdiplus, png:gdiplus and
+# png:gdiplus:gdiplus.
+# The default value is: png.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_IMAGE_FORMAT = png
+
+# If DOT_IMAGE_FORMAT is set to svg, then this option can be set to YES to
+# enable generation of interactive SVG images that allow zooming and panning.
+#
+# Note that this requires a modern browser other than Internet Explorer. Tested
+# and working are Firefox, Chrome, Safari, and Opera.
+# Note: For IE 9+ you need to set HTML_FILE_EXTENSION to xhtml in order to make
+# the SVG files visible. Older versions of IE do not have SVG support.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+INTERACTIVE_SVG = NO
+
+# The DOT_PATH tag can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the \dotfile
+# command).
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOTFILE_DIRS =
+
+# The MSCFILE_DIRS tag can be used to specify one or more directories that
+# contain msc files that are included in the documentation (see the \mscfile
+# command).
+
+MSCFILE_DIRS =
+
+# The DIAFILE_DIRS tag can be used to specify one or more directories that
+# contain dia files that are included in the documentation (see the \diafile
+# command).
+
+DIAFILE_DIRS =
+
+# When using plantuml, the PLANTUML_JAR_PATH tag should be used to specify the
+# path where java can find the plantuml.jar file. If left blank, it is assumed
+# PlantUML is not used or called during a preprocessing step. Doxygen will
+# generate a warning when it encounters a \startuml command in this case and
+# will not generate output for the diagram.
+
+PLANTUML_JAR_PATH =
+
+# When using plantuml, the specified paths are searched for files specified by
+# the !include statement in a plantuml block.
+
+PLANTUML_INCLUDE_PATH =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of nodes
+# that will be shown in the graph. If the number of nodes in a graph becomes
+# larger than this value, doxygen will truncate the graph, which is visualized
+# by representing a node as a red box. Note that doxygen if the number of direct
+# children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note that
+# the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+# Minimum value: 0, maximum value: 10000, default value: 50.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the graphs
+# generated by dot. A depth value of 3 means that only nodes reachable from the
+# root by following a path via at most 3 edges will be shown. Nodes that lay
+# further from the root node will be omitted. Note that setting this option to 1
+# or 2 may greatly reduce the computation time needed for large code bases. Also
+# note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+# Minimum value: 0, maximum value: 1000, default value: 0.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not seem
+# to support this out of the box.
+#
+# Warning: Depending on the platform used, enabling this option may lead to
+# badly anti-aliased labels on the edges of a graph (i.e. they become hard to
+# read).
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES to allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10) support
+# this, this feature is disabled by default.
+# The default value is: NO.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES doxygen will generate a legend page
+# explaining the meaning of the various boxes and arrows in the dot generated
+# graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES, doxygen will remove the intermediate dot
+# files that are used to generate the various graphs.
+# The default value is: YES.
+# This tag requires that the tag HAVE_DOT is set to YES.
+
+DOT_CLEANUP = YES
diff --git a/contrib/bearssl/LICENSE.txt b/contrib/bearssl/LICENSE.txt
new file mode 100644
index 000000000000..088502032e43
--- /dev/null
+++ b/contrib/bearssl/LICENSE.txt
@@ -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.
diff --git a/contrib/bearssl/Makefile b/contrib/bearssl/Makefile
new file mode 100644
index 000000000000..f7f24fccd1c7
--- /dev/null
+++ b/contrib/bearssl/Makefile
@@ -0,0 +1,45 @@
+# Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+# ======================================================================
+
+# The lines below are a horrible hack that nonetheless works. On a
+# "make" utility compatible with Single Unix v4 (this includes GNU and
+# BSD make), the '\' at the end of a command line counts as an escape
+# for the newline character, so the next line is still a comment.
+# However, Microsoft's nmake.exe (that comes with Visual Studio) does
+# not interpret the final '\' that way in a comment. The end result is
+# that when using nmake.exe, this will include "mk/Win.mk", whereas
+# GNU/BSD make will include "mk/Unix.mk".
+
+# \
+!ifndef 0 # \
+!include mk/NMake.mk # \
+!else
+.POSIX:
+include mk/SingleUnix.mk
+# Extra hack for OpenBSD make.
+ifndef: all
+0: all
+endif: all
+# \
+!endif
diff --git a/contrib/bearssl/README.txt b/contrib/bearssl/README.txt
new file mode 100644
index 000000000000..0cb528874066
--- /dev/null
+++ b/contrib/bearssl/README.txt
@@ -0,0 +1,136 @@
+# Documentation
+
+The most up-to-date documentation is supposed to be available on the
+[BearSSL Web site](https://www.bearssl.org/).
+
+# Disclaimer
+
+BearSSL is considered beta-level software. Most planned functionalities
+are implemented; new evolution may still break both source and binary
+compatibility.
+
+Using BearSSL for production purposes would be a relatively bold but not
+utterly crazy move. BearSSL is free, open-source software, provided
+without any guarantee of fitness or reliability. That being said, it
+appears to behave properly, and only minor issues have been found (and
+fixed) so far. You are encourage to inspect its API and code 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
+
+Right now, BearSSL is a simple library, along with a few test and debug
+command-line tools. There is no installer yet. The library _can_ be
+compiled as a shared library on some systems, but since the binary API
+is not fully stabilised, this is not a very good idea to do that right
+now.
+
+To compile the code, just type `make`. This will try to use sane
+"default" values. On a Windows system with Visual Studio, run a console
+with the environment initialised for a specific version of the C compiler,
+and type `nmake`.
+
+To override the default settings, create a custom configuration file in
+the `conf` directory, and invoke `make` (or `nmake`) with an explicit
+`CONF=` parameter. For instance, to use the provided `samd20.mk`
+configuration file (that targets cross-compilation for an Atmel board
+that features a Cortex-M0+ CPU), type:
+
+ make CONF=samd20
+
+The `conf/samd20.mk` file includes the `Unix.mk` file and then overrides
+some of the parameters, including the destination directory. Any custom
+configuration can be made the same way.
+
+Some compile-time options can be set through macros, either on the
+compiler command-line, or in the `src/config.h` file. See the comments
+in that file. Some settings are autodetected but they can still be
+explicitly overridden.
+
+When compilation is done, the library (static and DLL, when appropriate)
+and the command-line tools can be found in the designated build
+directory (by default named `build`). The public headers (to be used
+by applications linked against BearSSL) are in the `inc/` directory.
+
+To run the tests:
+
+ - `testcrypto all` runs the cryptographic tests (test vectors on all
+ implemented cryptogaphic functions). It can be slow. You can also
+ run a selection of the tests by providing their names (run
+ `testcrypto` without any parameter to see the available names).
+
+ - `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. As for `testcrypto`, specific named benchmarks can
+ be executed.
+
+ - `testx509` runs X.509 validation tests. The test certificates are
+ all in `test/x509/`.
+
+The `brssl` command-line tool produced in the build directory 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).
+
+**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` and `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.
diff --git a/contrib/bearssl/T0/BlobWriter.cs b/contrib/bearssl/T0/BlobWriter.cs
new file mode 100644
index 000000000000..3bbc8e6ac29f
--- /dev/null
+++ b/contrib/bearssl/T0/BlobWriter.cs
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/T0/CPU.cs b/contrib/bearssl/T0/CPU.cs
new file mode 100644
index 000000000000..22f1a1793aad
--- /dev/null
+++ b/contrib/bearssl/T0/CPU.cs
@@ -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];
+ }
+ }
+}
diff --git a/contrib/bearssl/T0/CodeElement.cs b/contrib/bearssl/T0/CodeElement.cs
new file mode 100644
index 000000000000..471a61f903f2
--- /dev/null
+++ b/contrib/bearssl/T0/CodeElement.cs
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 GetLength(bool oneByteCode);
+
+ internal abstract int Encode(BlobWriter bw, bool oneByteCode);
+
+ internal static int EncodeOneByte(uint val, BlobWriter bw)
+ {
+ if (val > 255) {
+ throw new Exception(string.Format(
+ "Cannot encode '{0}' over one byte", val));
+ }
+ bw.Append((byte)val);
+ return 1;
+ }
+
+ 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;
+ }
+}
diff --git a/contrib/bearssl/T0/CodeElementJump.cs b/contrib/bearssl/T0/CodeElementJump.cs
new file mode 100644
index 000000000000..4dae0bc8c059
--- /dev/null
+++ b/contrib/bearssl/T0/CodeElementJump.cs
@@ -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 CodeElementJump : CodeElement {
+
+ uint jumpType;
+ CodeElement target;
+
+ internal CodeElementJump(uint jumpType)
+ {
+ this.jumpType = jumpType;
+ }
+
+ /* obsolete
+ 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 int GetLength(bool oneByteCode)
+ {
+ int len = oneByteCode ? 1 : 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, bool oneByteCode)
+ {
+ if (bw == null) {
+ return GetLength(oneByteCode);
+ }
+ int len;
+ if (oneByteCode) {
+ len = EncodeOneByte(jumpType, bw);
+ } else {
+ len = Encode7EUnsigned(jumpType, bw);
+ }
+ int joff = JumpOff;
+ if (joff == Int32.MinValue) {
+ throw new Exception("Unresolved addresses");
+ }
+ return len + Encode7ESigned(joff, bw);
+ }
+}
diff --git a/contrib/bearssl/T0/CodeElementUInt.cs b/contrib/bearssl/T0/CodeElementUInt.cs
new file mode 100644
index 000000000000..049cdad642e1
--- /dev/null
+++ b/contrib/bearssl/T0/CodeElementUInt.cs
@@ -0,0 +1,55 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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;
+ }
+
+ /* obsolete
+ internal override int Length {
+ get {
+ return Encode7EUnsigned(val, null);
+ }
+ }
+ */
+
+ internal override int GetLength(bool oneByteCode)
+ {
+ return oneByteCode ? 1 : Encode7EUnsigned(val, null);
+ }
+
+ internal override int Encode(BlobWriter bw, bool oneByteCode)
+ {
+ return oneByteCode
+ ? EncodeOneByte(val, bw)
+ : Encode7EUnsigned(val, bw);
+ }
+}
diff --git a/contrib/bearssl/T0/CodeElementUIntExpr.cs b/contrib/bearssl/T0/CodeElementUIntExpr.cs
new file mode 100644
index 000000000000..8dd55a54d953
--- /dev/null
+++ b/contrib/bearssl/T0/CodeElementUIntExpr.cs
@@ -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.
+ */
+
+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;
+ }
+
+ /* obsolete
+ internal override int Length {
+ get {
+ return Encode7EUnsigned(val, null)
+ + (cx.GetMaxBitLength(off) + 6) / 7;
+ }
+ }
+ */
+
+ internal override int GetLength(bool oneByteCode)
+ {
+ int len = oneByteCode ? 1 : Encode7EUnsigned(val, null);
+ return len + (cx.GetMaxBitLength(off) + 6) / 7;
+ }
+
+ internal override int Encode(BlobWriter bw, bool oneByteCode)
+ {
+ int len1 = oneByteCode
+ ? EncodeOneByte(val, bw)
+ : 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;
+ }
+}
diff --git a/contrib/bearssl/T0/CodeElementUIntInt.cs b/contrib/bearssl/T0/CodeElementUIntInt.cs
new file mode 100644
index 000000000000..0223e27719af
--- /dev/null
+++ b/contrib/bearssl/T0/CodeElementUIntInt.cs
@@ -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;
+
+class CodeElementUIntInt : CodeElement {
+
+ uint val1;
+ int val2;
+
+ internal CodeElementUIntInt(uint val1, int val2) : base()
+ {
+ this.val1 = val1;
+ this.val2 = val2;
+ }
+
+ /* obsolete
+ internal override int Length {
+ get {
+ return Encode7EUnsigned(val1, null)
+ + Encode7ESigned(val2, null);
+ }
+ }
+ */
+
+ internal override int GetLength(bool oneByteCode)
+ {
+ return (oneByteCode ? 1 : Encode7EUnsigned(val1, null))
+ + Encode7ESigned(val2, null);
+ }
+
+ internal override int Encode(BlobWriter bw, bool oneByteCode)
+ {
+ int len = oneByteCode
+ ? EncodeOneByte(val1, bw)
+ : Encode7EUnsigned(val1, bw);
+ len += Encode7ESigned(val2, bw);
+ return len;
+ }
+}
diff --git a/contrib/bearssl/T0/CodeElementUIntUInt.cs b/contrib/bearssl/T0/CodeElementUIntUInt.cs
new file mode 100644
index 000000000000..6f94de54f9d2
--- /dev/null
+++ b/contrib/bearssl/T0/CodeElementUIntUInt.cs
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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;
+ }
+
+ /* obsolete
+ internal override int Length {
+ get {
+ return Encode7EUnsigned(val1, null)
+ + Encode7EUnsigned(val2, null);
+ }
+ }
+ */
+
+ internal override int GetLength(bool oneByteCode)
+ {
+ return (oneByteCode ? 1 : Encode7EUnsigned(val1, null))
+ + Encode7EUnsigned(val2, null);
+ }
+
+ internal override int Encode(BlobWriter bw, bool oneByteCode)
+ {
+ int len = oneByteCode
+ ? EncodeOneByte(val1, bw)
+ : Encode7EUnsigned(val1, bw);
+ len += Encode7EUnsigned(val2, bw);
+ return len;
+ }
+}
diff --git a/contrib/bearssl/T0/ConstData.cs b/contrib/bearssl/T0/ConstData.cs
new file mode 100644
index 000000000000..6a06b64ed145
--- /dev/null
+++ b/contrib/bearssl/T0/ConstData.cs
@@ -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]);
+ }
+ }
+}
diff --git a/contrib/bearssl/T0/Opcode.cs b/contrib/bearssl/T0/Opcode.cs
new file mode 100644
index 000000000000..81d1e9d7d3d8
--- /dev/null
+++ b/contrib/bearssl/T0/Opcode.cs
@@ -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)
+ {
+ }
+}
diff --git a/contrib/bearssl/T0/OpcodeCall.cs b/contrib/bearssl/T0/OpcodeCall.cs
new file mode 100644
index 000000000000..098004225dce
--- /dev/null
+++ b/contrib/bearssl/T0/OpcodeCall.cs
@@ -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);
+ }
+}
diff --git a/contrib/bearssl/T0/OpcodeConst.cs b/contrib/bearssl/T0/OpcodeConst.cs
new file mode 100644
index 000000000000..ae75ae59d651
--- /dev/null
+++ b/contrib/bearssl/T0/OpcodeConst.cs
@@ -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();
+ }
+}
diff --git a/contrib/bearssl/T0/OpcodeGetLocal.cs b/contrib/bearssl/T0/OpcodeGetLocal.cs
new file mode 100644
index 000000000000..59d24fc5c361
--- /dev/null
+++ b/contrib/bearssl/T0/OpcodeGetLocal.cs
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/T0/OpcodeJump.cs b/contrib/bearssl/T0/OpcodeJump.cs
new file mode 100644
index 000000000000..4f3ec684d881
--- /dev/null
+++ b/contrib/bearssl/T0/OpcodeJump.cs
@@ -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]);
+ }
+}
diff --git a/contrib/bearssl/T0/OpcodeJumpIf.cs b/contrib/bearssl/T0/OpcodeJumpIf.cs
new file mode 100644
index 000000000000..d70243449202
--- /dev/null
+++ b/contrib/bearssl/T0/OpcodeJumpIf.cs
@@ -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;
+ }
+ }
+}
diff --git a/contrib/bearssl/T0/OpcodeJumpIfNot.cs b/contrib/bearssl/T0/OpcodeJumpIfNot.cs
new file mode 100644
index 000000000000..afbf19de5eb5
--- /dev/null
+++ b/contrib/bearssl/T0/OpcodeJumpIfNot.cs
@@ -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;
+ }
+ }
+}
diff --git a/contrib/bearssl/T0/OpcodeJumpUncond.cs b/contrib/bearssl/T0/OpcodeJumpUncond.cs
new file mode 100644
index 000000000000..e7d8a82bda3d
--- /dev/null
+++ b/contrib/bearssl/T0/OpcodeJumpUncond.cs
@@ -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;
+ }
+ }
+}
diff --git a/contrib/bearssl/T0/OpcodePutLocal.cs b/contrib/bearssl/T0/OpcodePutLocal.cs
new file mode 100644
index 000000000000..b148a65b9ca2
--- /dev/null
+++ b/contrib/bearssl/T0/OpcodePutLocal.cs
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/T0/OpcodeRet.cs b/contrib/bearssl/T0/OpcodeRet.cs
new file mode 100644
index 000000000000..187473b1d60e
--- /dev/null
+++ b/contrib/bearssl/T0/OpcodeRet.cs
@@ -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";
+ }
+}
diff --git a/contrib/bearssl/T0/SType.cs b/contrib/bearssl/T0/SType.cs
new file mode 100644
index 000000000000..80e9f0176e18
--- /dev/null
+++ b/contrib/bearssl/T0/SType.cs
@@ -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);
+ }
+}
diff --git a/contrib/bearssl/T0/T0Comp.cs b/contrib/bearssl/T0/T0Comp.cs
new file mode 100644
index 000000000000..7a397f7cbc48
--- /dev/null
+++ b/contrib/bearssl/T0/T0Comp.cs
@@ -0,0 +1,2123 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+using System;
+using System.Collections.Generic;
+using System.IO;
+using System.Reflection;
+using System.Text;
+
+/*
+ * This is the main compiler class.
+ */
+
+public class T0Comp {
+
+ /*
+ * Command-line entry point.
+ */
+ public static void Main(string[] args)
+ {
+ try {
+ List<string> r = new List<string>();
+ string outBase = null;
+ List<string> entryPoints = new List<string>();
+ string coreRun = null;
+ bool flow = true;
+ int dsLim = 32;
+ int rsLim = 32;
+ for (int i = 0; i < args.Length; i ++) {
+ string a = args[i];
+ if (!a.StartsWith("-")) {
+ r.Add(a);
+ continue;
+ }
+ if (a == "--") {
+ for (;;) {
+ if (++ i >= args.Length) {
+ break;
+ }
+ r.Add(args[i]);
+ }
+ break;
+ }
+ while (a.StartsWith("-")) {
+ a = a.Substring(1);
+ }
+ int j = a.IndexOf('=');
+ string pname;
+ string pval, pval2;
+ if (j < 0) {
+ pname = a.ToLowerInvariant();
+ pval = null;
+ pval2 = (i + 1) < args.Length
+ ? args[i + 1] : null;
+ } else {
+ pname = a.Substring(0, j).Trim()
+ .ToLowerInvariant();
+ pval = a.Substring(j + 1);
+ pval2 = null;
+ }
+ switch (pname) {
+ case "o":
+ case "out":
+ if (pval == null) {
+ if (pval2 == null) {
+ Usage();
+ }
+ i ++;
+ pval = pval2;
+ }
+ if (outBase != null) {
+ Usage();
+ }
+ outBase = pval;
+ break;
+ case "r":
+ case "run":
+ if (pval == null) {
+ if (pval2 == null) {
+ Usage();
+ }
+ i ++;
+ pval = pval2;
+ }
+ coreRun = pval;
+ break;
+ case "m":
+ case "main":
+ if (pval == null) {
+ if (pval2 == null) {
+ Usage();
+ }
+ i ++;
+ pval = pval2;
+ }
+ foreach (string ep in pval.Split(',')) {
+ string epz = ep.Trim();
+ if (epz.Length > 0) {
+ entryPoints.Add(epz);
+ }
+ }
+ break;
+ case "nf":
+ case "noflow":
+ flow = false;
+ break;
+ default:
+ Usage();
+ break;
+ }
+ }
+ if (r.Count == 0) {
+ Usage();
+ }
+ if (outBase == null) {
+ outBase = "t0out";
+ }
+ if (entryPoints.Count == 0) {
+ entryPoints.Add("main");
+ }
+ if (coreRun == null) {
+ coreRun = outBase;
+ }
+ T0Comp tc = new T0Comp();
+ tc.enableFlowAnalysis = flow;
+ tc.dsLimit = dsLim;
+ tc.rsLimit = rsLim;
+ using (TextReader tr = new StreamReader(
+ Assembly.GetExecutingAssembly()
+ .GetManifestResourceStream("t0-kernel")))
+ {
+ tc.ProcessInput(tr);
+ }
+ foreach (string a in r) {
+ Console.WriteLine("[{0}]", a);
+ using (TextReader tr = File.OpenText(a)) {
+ tc.ProcessInput(tr);
+ }
+ }
+ tc.Generate(outBase, coreRun, entryPoints.ToArray());
+ } catch (Exception e) {
+ Console.WriteLine(e.ToString());
+ Environment.Exit(1);
+ }
+ }
+
+ static void Usage()
+ {
+ Console.WriteLine(
+"usage: T0Comp.exe [ options... ] file...");
+ Console.WriteLine(
+"options:");
+ Console.WriteLine(
+" -o file use 'file' as base for output file name (default: 't0out')");
+ Console.WriteLine(
+" -r name use 'name' as base for run function (default: same as output)");
+ Console.WriteLine(
+" -m name[,name...]");
+ Console.WriteLine(
+" define entry point(s)");
+ Console.WriteLine(
+" -nf disable flow analysis");
+ Environment.Exit(1);
+ }
+
+ /*
+ * If 'delayedChar' is Int32.MinValue then there is no delayed
+ * character.
+ * If 'delayedChar' equals x >= 0 then there is one delayed
+ * character of value x.
+ * If 'delayedChar' equals y < 0 then there are two delayed
+ * characters, a newline (U+000A) followed by character of
+ * value -(y+1).
+ */
+ TextReader currentInput;
+ int delayedChar;
+
+ /*
+ * Common StringBuilder used to parse tokens; it is reused for
+ * each new token.
+ */
+ StringBuilder tokenBuilder;
+
+ /*
+ * There may be a delayed token in some cases.
+ */
+ String delayedToken;
+
+ /*
+ * Defined words are referenced by name in this map. Names are
+ * string-sensitive; for better reproducibility, the map is sorted
+ * (ordinal order).
+ */
+ IDictionary<string, Word> words;
+
+ /*
+ * Last defined word is also referenced in 'lastWord'. This is
+ * used by 'immediate'.
+ */
+ Word lastWord;
+
+ /*
+ * When compiling, this builder is used. A stack saves other
+ * builders in case of nested definition.
+ */
+ WordBuilder wordBuilder;
+ Stack<WordBuilder> savedWordBuilders;
+
+ /*
+ * C code defined for words is kept in this map, by word name.
+ */
+ IDictionary<string, string> allCCode;
+
+ /*
+ * 'compiling' is true when compiling tokens to a word, false
+ * when interpreting them.
+ */
+ bool compiling;
+
+ /*
+ * 'quitRunLoop' is set to true to trigger exit of the
+ * interpretation loop when the end of the current input file
+ * is reached.
+ */
+ bool quitRunLoop;
+
+ /*
+ * 'extraCode' is for C code that is to be added as preamble to
+ * the C output.
+ */
+ List<string> extraCode;
+
+ /*
+ * 'extraCodeDefer' is for C code that is to be added in the C
+ * output _after_ the data and code blocks.
+ */
+ List<string> extraCodeDefer;
+
+ /*
+ * 'dataBlock' is the data block in which constant data bytes
+ * are accumulated.
+ */
+ ConstData dataBlock;
+
+ /*
+ * Counter for blocks of constant data.
+ */
+ long currentBlobID;
+
+ /*
+ * Flow analysis enable flag.
+ */
+ bool enableFlowAnalysis;
+
+ /*
+ * Data stack size limit.
+ */
+ int dsLimit;
+
+ /*
+ * Return stack size limit.
+ */
+ int rsLimit;
+
+ T0Comp()
+ {
+ tokenBuilder = new StringBuilder();
+ words = new SortedDictionary<string, Word>(
+ StringComparer.Ordinal);
+ savedWordBuilders = new Stack<WordBuilder>();
+ allCCode = new SortedDictionary<string, string>(
+ StringComparer.Ordinal);
+ compiling = false;
+ extraCode = new List<string>();
+ extraCodeDefer = new List<string>();
+ enableFlowAnalysis = true;
+
+ /*
+ * Native words are predefined and implemented only with
+ * native code. Some may be part of the generated output,
+ * if C code is set for them.
+ */
+
+ /*
+ * add-cc:
+ * Parses next token as a word name, then a C code snippet.
+ * Sets the C code for that word.
+ */
+ AddNative("add-cc:", false, SType.BLANK, cpu => {
+ string tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing name)");
+ }
+ if (allCCode.ContainsKey(tt)) {
+ throw new Exception(
+ "C code already set for: " + tt);
+ }
+ allCCode[tt] = ParseCCode();
+ });
+
+ /*
+ * cc:
+ * Parses next token as a word name, then a C code snippet.
+ * A new word is defined, that throws an exception when
+ * invoked during compilation. The C code is set for that
+ * new word.
+ */
+ AddNative("cc:", false, SType.BLANK, cpu => {
+ string tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing name)");
+ }
+ Word w = AddNative(tt, false, cpu2 => {
+ throw new Exception(
+ "C-only word: " + tt);
+ });
+ if (allCCode.ContainsKey(tt)) {
+ throw new Exception(
+ "C code already set for: " + tt);
+ }
+ SType stackEffect;
+ allCCode[tt] = ParseCCode(out stackEffect);
+ w.StackEffect = stackEffect;
+ });
+
+ /*
+ * preamble
+ * Parses a C code snippet, then adds it to the generated
+ * output preamble.
+ */
+ AddNative("preamble", false, SType.BLANK, cpu => {
+ extraCode.Add(ParseCCode());
+ });
+
+ /*
+ * postamble
+ * Parses a C code snippet, then adds it to the generated
+ * output after the data and code blocks.
+ */
+ AddNative("postamble", false, SType.BLANK, cpu => {
+ extraCodeDefer.Add(ParseCCode());
+ });
+
+ /*
+ * make-CX
+ * Expects two integers and a string, and makes a
+ * constant that stands for the string as a C constant
+ * expression. The two integers are the expected range
+ * (min-max, inclusive).
+ */
+ AddNative("make-CX", false, new SType(3, 1), cpu => {
+ TValue c = cpu.Pop();
+ if (!(c.ptr is TPointerBlob)) {
+ throw new Exception(string.Format(
+ "'{0}' is not a string", c));
+ }
+ int max = cpu.Pop();
+ int min = cpu.Pop();
+ TValue tv = new TValue(0, new TPointerExpr(
+ c.ToString(), min, max));
+ cpu.Push(tv);
+ });
+
+ /*
+ * CX (immediate)
+ * Parses two integer constants, then a C code snippet.
+ * It then pushes on the stack, or compiles to the
+ * current word, a value consisting of the given C
+ * expression; the two integers indicate the expected
+ * range (min-max, inclusive) of the C expression when
+ * evaluated.
+ */
+ AddNative("CX", true, cpu => {
+ string tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing min value)");
+ }
+ int min = ParseInteger(tt);
+ tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing max value)");
+ }
+ int max = ParseInteger(tt);
+ if (max < min) {
+ throw new Exception("min/max in wrong order");
+ }
+ TValue tv = new TValue(0, new TPointerExpr(
+ ParseCCode().Trim(), min, max));
+ if (compiling) {
+ wordBuilder.Literal(tv);
+ } else {
+ cpu.Push(tv);
+ }
+ });
+
+ /*
+ * co
+ * Interrupt the current execution. This implements
+ * coroutines. It cannot be invoked during compilation.
+ */
+ AddNative("co", false, SType.BLANK, cpu => {
+ throw new Exception("No coroutine in compile mode");
+ });
+
+ /*
+ * :
+ * Parses next token as word name. It begins definition
+ * of that word, setting it as current target for
+ * word building. Any previously opened word is saved
+ * and will become available again as a target when that
+ * new word is finished building.
+ */
+ AddNative(":", false, cpu => {
+ string tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing name)");
+ }
+ if (compiling) {
+ savedWordBuilders.Push(wordBuilder);
+ } else {
+ compiling = true;
+ }
+ wordBuilder = new WordBuilder(this, tt);
+ tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (while compiling)");
+ }
+ if (tt == "(") {
+ SType stackEffect = ParseStackEffectNF();
+ if (!stackEffect.IsKnown) {
+ throw new Exception(
+ "Invalid stack effect syntax");
+ }
+ wordBuilder.StackEffect = stackEffect;
+ } else {
+ delayedToken = tt;
+ }
+ });
+
+ /*
+ * Pops a string as word name, and two integers as stack
+ * effect. It begins definition of that word, setting it
+ * as current target for word building. Any previously
+ * opened word is saved and will become available again as
+ * a target when that new word is finished building.
+ *
+ * Stack effect is the pair 'din dout'. If din is negative,
+ * then the stack effect is "unknown". If din is nonnegative
+ * but dout is negative, then the word is reputed never to
+ * return.
+ */
+ AddNative("define-word", false, cpu => {
+ int dout = cpu.Pop();
+ int din = cpu.Pop();
+ TValue s = cpu.Pop();
+ if (!(s.ptr is TPointerBlob)) {
+ throw new Exception(string.Format(
+ "Not a string: '{0}'", s));
+ }
+ string tt = s.ToString();
+ if (compiling) {
+ savedWordBuilders.Push(wordBuilder);
+ } else {
+ compiling = true;
+ }
+ wordBuilder = new WordBuilder(this, tt);
+ wordBuilder.StackEffect = new SType(din, dout);
+ });
+
+ /*
+ * ; (immediate)
+ * Ends current word. The current word is registered under
+ * its name, and the previously opened word (if any) becomes
+ * again the building target.
+ */
+ AddNative(";", true, cpu => {
+ if (!compiling) {
+ throw new Exception("Not compiling");
+ }
+ Word w = wordBuilder.Build();
+ string name = w.Name;
+ if (words.ContainsKey(name)) {
+ throw new Exception(
+ "Word already defined: " + name);
+ }
+ words[name] = w;
+ lastWord = w;
+ if (savedWordBuilders.Count > 0) {
+ wordBuilder = savedWordBuilders.Pop();
+ } else {
+ wordBuilder = null;
+ compiling = false;
+ }
+ });
+
+ /*
+ * immediate
+ * Sets the last defined word as immediate.
+ */
+ AddNative("immediate", false, cpu => {
+ if (lastWord == null) {
+ throw new Exception("No word defined yet");
+ }
+ lastWord.Immediate = true;
+ });
+
+ /*
+ * literal (immediate)
+ * Pops the current TOS value, and add in the current word
+ * the action of pushing that value. This cannot be used
+ * when no word is being built.
+ */
+ WordNative wliteral = AddNative("literal", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Literal(cpu.Pop());
+ });
+
+ /*
+ * compile
+ * Pops the current TOS value, which must be an XT (pointer
+ * to a word); the action of calling that word is compiled
+ * in the current word.
+ */
+ WordNative wcompile = AddNative("compile", false, cpu => {
+ CheckCompiling();
+ wordBuilder.Call(cpu.Pop().ToXT());
+ });
+
+ /*
+ * postpone (immediate)
+ * Parses the next token as a word name, and add to the
+ * current word the action of calling that word. This
+ * basically removes immediatety from the next word.
+ */
+ AddNative("postpone", true, cpu => {
+ CheckCompiling();
+ string tt = Next();
+ if (tt == null) {
+ throw new Exception(
+ "EOF reached (missing name)");
+ }
+ TValue v;
+ bool isVal = TryParseLiteral(tt, out v);
+ Word w = LookupNF(tt);
+ if (isVal && w != null) {
+ throw new Exception(String.Format(
+ "Ambiguous: both defined word and"
+ + " literal: {0}", tt));
+ }
+ if (isVal) {
+ wordBuilder.Literal(v);
+ wordBuilder.CallExt(wliteral);
+ } else if (w != null) {
+ if (w.Immediate) {
+ wordBuilder.CallExt(w);
+ } else {
+ wordBuilder.Literal(new TValue(0,
+ new TPointerXT(w)));
+ wordBuilder.CallExt(wcompile);
+ }
+ } else {
+ wordBuilder.Literal(new TValue(0,
+ new TPointerXT(tt)));
+ wordBuilder.CallExt(wcompile);
+ }
+ });
+
+ /*
+ * Interrupt compilation with an error.
+ */
+ AddNative("exitvm", false, cpu => {
+ throw new Exception();
+ });
+
+ /*
+ * Open a new data block. Its symbolic address is pushed
+ * on the stack.
+ */
+ AddNative("new-data-block", false, cpu => {
+ dataBlock = new ConstData(this);
+ cpu.Push(new TValue(0, new TPointerBlob(dataBlock)));
+ });
+
+ /*
+ * Define a new data word. The data address and name are
+ * popped from the stack.
+ */
+ AddNative("define-data-word", false, cpu => {
+ string name = cpu.Pop().ToString();
+ TValue va = cpu.Pop();
+ TPointerBlob tb = va.ptr as TPointerBlob;
+ if (tb == null) {
+ throw new Exception(
+ "Address is not a data area");
+ }
+ Word w = new WordData(this, name, tb.Blob, va.x);
+ if (words.ContainsKey(name)) {
+ throw new Exception(
+ "Word already defined: " + name);
+ }
+ words[name] = w;
+ lastWord = w;
+ });
+
+ /*
+ * Get an address pointing at the end of the current
+ * data block. This is the address of the next byte that
+ * will be added.
+ */
+ AddNative("current-data", false, cpu => {
+ if (dataBlock == null) {
+ throw new Exception(
+ "No current data block");
+ }
+ cpu.Push(new TValue(dataBlock.Length,
+ new TPointerBlob(dataBlock)));
+ });
+
+ /*
+ * Add a byte value to the data block.
+ */
+ AddNative("data-add8", false, cpu => {
+ if (dataBlock == null) {
+ throw new Exception(
+ "No current data block");
+ }
+ int v = cpu.Pop();
+ if (v < 0 || v > 0xFF) {
+ throw new Exception(
+ "Byte value out of range: " + v);
+ }
+ dataBlock.Add8((byte)v);
+ });
+
+ /*
+ * Set a byte value in the data block.
+ */
+ AddNative("data-set8", false, cpu => {
+ TValue va = cpu.Pop();
+ TPointerBlob tb = va.ptr as TPointerBlob;
+ if (tb == null) {
+ throw new Exception(
+ "Address is not a data area");
+ }
+ int v = cpu.Pop();
+ if (v < 0 || v > 0xFF) {
+ throw new Exception(
+ "Byte value out of range: " + v);
+ }
+ tb.Blob.Set8(va.x, (byte)v);
+ });
+
+ /*
+ * Get a byte value from a data block.
+ */
+ AddNative("data-get8", false, new SType(1, 1), cpu => {
+ TValue va = cpu.Pop();
+ TPointerBlob tb = va.ptr as TPointerBlob;
+ if (tb == null) {
+ throw new Exception(
+ "Address is not a data area");
+ }
+ int v = tb.Blob.Read8(va.x);
+ cpu.Push(v);
+ });
+
+ /*
+ *
+ */
+ AddNative("compile-local-read", false, cpu => {
+ CheckCompiling();
+ wordBuilder.GetLocal(cpu.Pop().ToString());
+ });
+ AddNative("compile-local-write", false, cpu => {
+ CheckCompiling();
+ wordBuilder.PutLocal(cpu.Pop().ToString());
+ });
+
+ AddNative("ahead", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Ahead();
+ });
+ AddNative("begin", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Begin();
+ });
+ AddNative("again", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Again();
+ });
+ AddNative("until", true, cpu => {
+ CheckCompiling();
+ wordBuilder.AgainIfNot();
+ });
+ AddNative("untilnot", true, cpu => {
+ CheckCompiling();
+ wordBuilder.AgainIf();
+ });
+ AddNative("if", true, cpu => {
+ CheckCompiling();
+ wordBuilder.AheadIfNot();
+ });
+ AddNative("ifnot", true, cpu => {
+ CheckCompiling();
+ wordBuilder.AheadIf();
+ });
+ AddNative("then", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Then();
+ });
+ AddNative("cs-pick", false, cpu => {
+ CheckCompiling();
+ wordBuilder.CSPick(cpu.Pop());
+ });
+ AddNative("cs-roll", false, cpu => {
+ CheckCompiling();
+ wordBuilder.CSRoll(cpu.Pop());
+ });
+ AddNative("next-word", false, cpu => {
+ string s = Next();
+ if (s == null) {
+ throw new Exception("No next word (EOF)");
+ }
+ cpu.Push(StringToBlob(s));
+ });
+ AddNative("parse", false, cpu => {
+ int d = cpu.Pop();
+ string s = ReadTerm(d);
+ cpu.Push(StringToBlob(s));
+ });
+ AddNative("char", false, cpu => {
+ int c = NextChar();
+ if (c < 0) {
+ throw new Exception("No next character (EOF)");
+ }
+ cpu.Push(c);
+ });
+ AddNative("'", false, cpu => {
+ string name = Next();
+ cpu.Push(new TValue(0, new TPointerXT(name)));
+ });
+
+ /*
+ * The "execute" word is valid in generated C code, but
+ * since it jumps to a runtime pointer, its actual stack
+ * effect cannot be computed in advance.
+ */
+ AddNative("execute", false, cpu => {
+ cpu.Pop().Execute(this, cpu);
+ });
+
+ AddNative("[", true, cpu => {
+ CheckCompiling();
+ compiling = false;
+ });
+ AddNative("]", false, cpu => {
+ compiling = true;
+ });
+ AddNative("(local)", false, cpu => {
+ CheckCompiling();
+ wordBuilder.DefLocal(cpu.Pop().ToString());
+ });
+ AddNative("ret", true, cpu => {
+ CheckCompiling();
+ wordBuilder.Ret();
+ });
+
+ AddNative("drop", false, new SType(1, 0), cpu => {
+ cpu.Pop();
+ });
+ AddNative("dup", false, new SType(1, 2), cpu => {
+ cpu.Push(cpu.Peek(0));
+ });
+ AddNative("swap", false, new SType(2, 2), cpu => {
+ cpu.Rot(1);
+ });
+ AddNative("over", false, new SType(2, 3), cpu => {
+ cpu.Push(cpu.Peek(1));
+ });
+ AddNative("rot", false, new SType(3, 3), cpu => {
+ cpu.Rot(2);
+ });
+ AddNative("-rot", false, new SType(3, 3), cpu => {
+ cpu.NRot(2);
+ });
+
+ /*
+ * "roll" and "pick" are special in that the stack slot
+ * they inspect might be known only at runtime, so an
+ * absolute stack effect cannot be attributed. Instead,
+ * we simply hope that the caller knows what it is doing,
+ * and we use a simple stack effect for just the count
+ * value and picked value.
+ */
+ AddNative("roll", false, new SType(1, 0), cpu => {
+ cpu.Rot(cpu.Pop());
+ });
+ AddNative("pick", false, new SType(1, 1), cpu => {
+ cpu.Push(cpu.Peek(cpu.Pop()));
+ });
+
+ AddNative("+", false, new SType(2, 1), cpu => {
+ TValue b = cpu.Pop();
+ TValue a = cpu.Pop();
+ if (b.ptr == null) {
+ a.x += (int)b;
+ cpu.Push(a);
+ } else if (a.ptr is TPointerBlob
+ && b.ptr is TPointerBlob)
+ {
+ cpu.Push(StringToBlob(
+ a.ToString() + b.ToString()));
+ } else {
+ throw new Exception(string.Format(
+ "Cannot add '{0}' to '{1}'", b, a));
+ }
+ });
+ AddNative("-", false, new SType(2, 1), cpu => {
+ /*
+ * We can subtract two pointers, provided that
+ * they point to the same blob. Otherwise,
+ * the subtraction second operand must be an
+ * integer.
+ */
+ TValue b = cpu.Pop();
+ TValue a = cpu.Pop();
+ TPointerBlob ap = a.ptr as TPointerBlob;
+ TPointerBlob bp = b.ptr as TPointerBlob;
+ if (ap != null && bp != null && ap.Blob == bp.Blob) {
+ cpu.Push(new TValue(a.x - b.x));
+ return;
+ }
+ int bx = b;
+ a.x -= bx;
+ cpu.Push(a);
+ });
+ AddNative("neg", false, new SType(1, 1), cpu => {
+ int ax = cpu.Pop();
+ cpu.Push(-ax);
+ });
+ AddNative("*", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax * bx);
+ });
+ AddNative("/", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax / bx);
+ });
+ AddNative("u/", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax / bx);
+ });
+ AddNative("%", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax % bx);
+ });
+ AddNative("u%", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax % bx);
+ });
+ AddNative("<", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax < bx);
+ });
+ AddNative("<=", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax <= bx);
+ });
+ AddNative(">", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax > bx);
+ });
+ AddNative(">=", false, new SType(2, 1), cpu => {
+ int bx = cpu.Pop();
+ int ax = cpu.Pop();
+ cpu.Push(ax >= bx);
+ });
+ AddNative("=", false, new SType(2, 1), cpu => {
+ TValue b = cpu.Pop();
+ TValue a = cpu.Pop();
+ cpu.Push(a.Equals(b));
+ });
+ AddNative("<>", false, new SType(2, 1), cpu => {
+ TValue b = cpu.Pop();
+ TValue a = cpu.Pop();
+ cpu.Push(!a.Equals(b));
+ });
+ AddNative("u<", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop().UInt;
+ uint ax = cpu.Pop().UInt;
+ cpu.Push(new TValue(ax < bx));
+ });
+ AddNative("u<=", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop().UInt;
+ uint ax = cpu.Pop().UInt;
+ cpu.Push(new TValue(ax <= bx));
+ });
+ AddNative("u>", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop().UInt;
+ uint ax = cpu.Pop().UInt;
+ cpu.Push(new TValue(ax > bx));
+ });
+ AddNative("u>=", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax >= bx);
+ });
+ AddNative("and", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax & bx);
+ });
+ AddNative("or", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax | bx);
+ });
+ AddNative("xor", false, new SType(2, 1), cpu => {
+ uint bx = cpu.Pop();
+ uint ax = cpu.Pop();
+ cpu.Push(ax ^ bx);
+ });
+ AddNative("not", false, new SType(1, 1), cpu => {
+ uint ax = cpu.Pop();
+ cpu.Push(~ax);
+ });
+ AddNative("<<", false, new SType(2, 1), cpu => {
+ int count = cpu.Pop();
+ if (count < 0 || count > 31) {
+ throw new Exception("Invalid shift count");
+ }
+ uint ax = cpu.Pop();
+ cpu.Push(ax << count);
+ });
+ AddNative(">>", false, new SType(2, 1), cpu => {
+ int count = cpu.Pop();
+ if (count < 0 || count > 31) {
+ throw new Exception("Invalid shift count");
+ }
+ int ax = cpu.Pop();
+ cpu.Push(ax >> count);
+ });
+ AddNative("u>>", false, new SType(2, 1), cpu => {
+ int count = cpu.Pop();
+ if (count < 0 || count > 31) {
+ throw new Exception("Invalid shift count");
+ }
+ uint ax = cpu.Pop();
+ cpu.Push(ax >> count);
+ });
+
+ AddNative(".", false, new SType(1, 0), cpu => {
+ Console.Write(" {0}", cpu.Pop().ToString());
+ });
+ AddNative(".s", false, SType.BLANK, cpu => {
+ int n = cpu.Depth;
+ for (int i = n - 1; i >= 0; i --) {
+ Console.Write(" {0}", cpu.Peek(i).ToString());
+ }
+ });
+ AddNative("putc", false, new SType(1, 0), cpu => {
+ Console.Write((char)cpu.Pop());
+ });
+ AddNative("puts", false, new SType(1, 0), cpu => {
+ Console.Write("{0}", cpu.Pop().ToString());
+ });
+ AddNative("cr", false, SType.BLANK, cpu => {
+ Console.WriteLine();
+ });
+ AddNative("eqstr", false, new SType(2, 1), cpu => {
+ string s2 = cpu.Pop().ToString();
+ string s1 = cpu.Pop().ToString();
+ cpu.Push(s1 == s2);
+ });
+ }
+
+ WordNative AddNative(string name, bool immediate,
+ WordNative.NativeRun code)
+ {
+ return AddNative(name, immediate, SType.UNKNOWN, code);
+ }
+
+ WordNative AddNative(string name, bool immediate, SType stackEffect,
+ WordNative.NativeRun code)
+ {
+ if (words.ContainsKey(name)) {
+ throw new Exception(
+ "Word already defined: " + name);
+ }
+ WordNative w = new WordNative(this, name, code);
+ w.Immediate = immediate;
+ w.StackEffect = stackEffect;
+ words[name] = w;
+ return w;
+ }
+
+ internal long NextBlobID()
+ {
+ return currentBlobID ++;
+ }
+
+ int NextChar()
+ {
+ int c = delayedChar;
+ if (c >= 0) {
+ delayedChar = Int32.MinValue;
+ } else if (c > Int32.MinValue) {
+ delayedChar = -(c + 1);
+ c = '\n';
+ } else {
+ c = currentInput.Read();
+ }
+ if (c == '\r') {
+ if (delayedChar >= 0) {
+ c = delayedChar;
+ delayedChar = Int32.MinValue;
+ } else {
+ c = currentInput.Read();
+ }
+ if (c != '\n') {
+ delayedChar = c;
+ c = '\n';
+ }
+ }
+ return c;
+ }
+
+ /*
+ * Un-read the character value 'c'. That value MUST be the one
+ * that was obtained from NextChar().
+ */
+ void Unread(int c)
+ {
+ if (c < 0) {
+ return;
+ }
+ if (delayedChar < 0) {
+ if (delayedChar != Int32.MinValue) {
+ throw new Exception(
+ "Already two delayed characters");
+ }
+ delayedChar = c;
+ } else if (c != '\n') {
+ throw new Exception("Cannot delay two characters");
+ } else {
+ delayedChar = -(delayedChar + 1);
+ }
+ }
+
+ string Next()
+ {
+ string r = delayedToken;
+ if (r != null) {
+ delayedToken = null;
+ return r;
+ }
+ tokenBuilder.Length = 0;
+ int c;
+ for (;;) {
+ c = NextChar();
+ if (c < 0) {
+ return null;
+ }
+ if (!IsWS(c)) {
+ break;
+ }
+ }
+ if (c == '"') {
+ return ParseString();
+ }
+ for (;;) {
+ tokenBuilder.Append((char)c);
+ c = NextChar();
+ if (c < 0 || IsWS(c)) {
+ Unread(c);
+ return tokenBuilder.ToString();
+ }
+ }
+ }
+
+ string ParseCCode()
+ {
+ SType stackEffect;
+ string r = ParseCCode(out stackEffect);
+ if (stackEffect.IsKnown) {
+ throw new Exception(
+ "Stack effect forbidden in this declaration");
+ }
+ return r;
+ }
+
+ string ParseCCode(out SType stackEffect)
+ {
+ string s = ParseCCodeNF(out stackEffect);
+ if (s == null) {
+ throw new Exception("Error while parsing C code");
+ }
+ return s;
+ }
+
+ string ParseCCodeNF(out SType stackEffect)
+ {
+ stackEffect = SType.UNKNOWN;
+ for (;;) {
+ int c = NextChar();
+ if (c < 0) {
+ return null;
+ }
+ if (!IsWS(c)) {
+ if (c == '(') {
+ if (stackEffect.IsKnown) {
+ Unread(c);
+ return null;
+ }
+ stackEffect = ParseStackEffectNF();
+ if (!stackEffect.IsKnown) {
+ return null;
+ }
+ continue;
+ } else if (c != '{') {
+ Unread(c);
+ return null;
+ }
+ break;
+ }
+ }
+ StringBuilder sb = new StringBuilder();
+ int count = 1;
+ for (;;) {
+ int c = NextChar();
+ if (c < 0) {
+ return null;
+ }
+ switch (c) {
+ case '{':
+ count ++;
+ break;
+ case '}':
+ if (-- count == 0) {
+ return sb.ToString();
+ }
+ break;
+ }
+ sb.Append((char)c);
+ }
+ }
+
+ /*
+ * Parse a stack effect declaration. This method assumes that the
+ * opening parenthesis has just been read. If the parsing fails,
+ * then this method returns SType.UNKNOWN.
+ */
+ SType ParseStackEffectNF()
+ {
+ bool seenSep = false;
+ bool seenBang = false;
+ int din = 0, dout = 0;
+ for (;;) {
+ string t = Next();
+ if (t == null) {
+ return SType.UNKNOWN;
+ }
+ if (t == "--") {
+ if (seenSep) {
+ return SType.UNKNOWN;
+ }
+ seenSep = true;
+ } else if (t == ")") {
+ if (seenSep) {
+ if (seenBang && dout == 1) {
+ dout = -1;
+ }
+ return new SType(din, dout);
+ } else {
+ return SType.UNKNOWN;
+ }
+ } else {
+ if (seenSep) {
+ if (dout == 0 && t == "!") {
+ seenBang = true;
+ }
+ dout ++;
+ } else {
+ din ++;
+ }
+ }
+ }
+ }
+
+ string ParseString()
+ {
+ StringBuilder sb = new StringBuilder();
+ sb.Append('"');
+ bool lcwb = false;
+ int hexNum = 0;
+ int acc = 0;
+ for (;;) {
+ int c = NextChar();
+ if (c < 0) {
+ throw new Exception(
+ "Unfinished literal string");
+ }
+ if (hexNum > 0) {
+ int d = HexVal(c);
+ if (d < 0) {
+ throw new Exception(String.Format(
+ "not an hex digit: U+{0:X4}",
+ c));
+ }
+ acc = (acc << 4) + d;
+ if (-- hexNum == 0) {
+ sb.Append((char)acc);
+ acc = 0;
+ }
+ } else if (lcwb) {
+ lcwb = false;
+ switch (c) {
+ case '\n': SkipNL(); break;
+ case 'x':
+ hexNum = 2;
+ break;
+ case 'u':
+ hexNum = 4;
+ break;
+ default:
+ sb.Append(SingleCharEscape(c));
+ break;
+ }
+ } else {
+ switch (c) {
+ case '"':
+ return sb.ToString();
+ case '\\':
+ lcwb = true;
+ break;
+ default:
+ sb.Append((char)c);
+ break;
+ }
+ }
+ }
+ }
+
+ static char SingleCharEscape(int c)
+ {
+ switch (c) {
+ case 'n': return '\n';
+ case 'r': return '\r';
+ case 't': return '\t';
+ case 's': return ' ';
+ default:
+ return (char)c;
+ }
+ }
+
+ /*
+ * A backslash+newline sequence occurred in a literal string; we
+ * check and consume the newline escape sequence (whitespace at
+ * start of next line, then a double-quote character).
+ */
+ void SkipNL()
+ {
+ for (;;) {
+ int c = NextChar();
+ if (c < 0) {
+ throw new Exception("EOF in literal string");
+ }
+ if (c == '\n') {
+ throw new Exception(
+ "Unescaped newline in literal string");
+ }
+ if (IsWS(c)) {
+ continue;
+ }
+ if (c == '"') {
+ return;
+ }
+ throw new Exception(
+ "Invalid newline escape in literal string");
+ }
+ }
+
+ static char DecodeCharConst(string t)
+ {
+ if (t.Length == 1 && t[0] != '\\') {
+ return t[0];
+ }
+ if (t.Length >= 2 && t[0] == '\\') {
+ switch (t[1]) {
+ case 'x':
+ if (t.Length == 4) {
+ int x = DecHex(t.Substring(2));
+ if (x >= 0) {
+ return (char)x;
+ }
+ }
+ break;
+ case 'u':
+ if (t.Length == 6) {
+ int x = DecHex(t.Substring(2));
+ if (x >= 0) {
+ return (char)x;
+ }
+ }
+ break;
+ default:
+ if (t.Length == 2) {
+ return SingleCharEscape(t[1]);
+ }
+ break;
+ }
+ }
+ throw new Exception("Invalid literal char: `" + t);
+ }
+
+ static int DecHex(string s)
+ {
+ int acc = 0;
+ foreach (char c in s) {
+ int d = HexVal(c);
+ if (d < 0) {
+ return -1;
+ }
+ acc = (acc << 4) + d;
+ }
+ return acc;
+ }
+
+ static int HexVal(int c)
+ {
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ } else if (c >= 'A' && c <= 'F') {
+ return c - ('A' - 10);
+ } else if (c >= 'a' && c <= 'f') {
+ return c - ('a' - 10);
+ } else {
+ return -1;
+ }
+ }
+
+ string ReadTerm(int ct)
+ {
+ StringBuilder sb = new StringBuilder();
+ for (;;) {
+ int c = NextChar();
+ if (c < 0) {
+ throw new Exception(String.Format(
+ "EOF reached before U+{0:X4}", ct));
+ }
+ if (c == ct) {
+ return sb.ToString();
+ }
+ sb.Append((char)c);
+ }
+ }
+
+ static bool IsWS(int c)
+ {
+ return c <= 32;
+ }
+
+ void ProcessInput(TextReader tr)
+ {
+ this.currentInput = tr;
+ delayedChar = -1;
+ Word w = new WordNative(this, "toplevel",
+ xcpu => { CompileStep(xcpu); });
+ CPU cpu = new CPU();
+ Opcode[] code = new Opcode[] {
+ new OpcodeCall(w),
+ new OpcodeJumpUncond(-2)
+ };
+ quitRunLoop = false;
+ cpu.Enter(code, 0);
+ for (;;) {
+ if (quitRunLoop) {
+ break;
+ }
+ Opcode op = cpu.ipBuf[cpu.ipOff ++];
+ op.Run(cpu);
+ }
+ }
+
+ void CompileStep(CPU cpu)
+ {
+ string tt = Next();
+ if (tt == null) {
+ if (compiling) {
+ throw new Exception("EOF while compiling");
+ }
+ quitRunLoop = true;
+ return;
+ }
+ TValue v;
+ bool isVal = TryParseLiteral(tt, out v);
+ Word w = LookupNF(tt);
+ if (isVal && w != null) {
+ throw new Exception(String.Format(
+ "Ambiguous: both defined word and literal: {0}",
+ tt));
+ }
+ if (compiling) {
+ if (isVal) {
+ wordBuilder.Literal(v);
+ } else if (w != null) {
+ if (w.Immediate) {
+ w.Run(cpu);
+ } else {
+ wordBuilder.CallExt(w);
+ }
+ } else {
+ wordBuilder.Call(tt);
+ }
+ } else {
+ if (isVal) {
+ cpu.Push(v);
+ } else if (w != null) {
+ w.Run(cpu);
+ } else {
+ throw new Exception(String.Format(
+ "Unknown word: '{0}'", tt));
+ }
+ }
+ }
+
+ string GetCCode(string name)
+ {
+ string ccode;
+ allCCode.TryGetValue(name, out ccode);
+ return ccode;
+ }
+
+ void Generate(string outBase, string coreRun,
+ params string[] entryPoints)
+ {
+ /*
+ * Gather all words that are part of the generated
+ * code. This is done by exploring references
+ * transitively. All such words are thus implicitly
+ * resolved.
+ */
+ IDictionary<string, Word> wordSet =
+ new SortedDictionary<string, Word>(
+ StringComparer.Ordinal);
+ Queue<Word> tx = new Queue<Word>();
+ foreach (string ep in entryPoints) {
+ if (wordSet.ContainsKey(ep)) {
+ continue;
+ }
+ Word w = Lookup(ep);
+ wordSet[w.Name] = w;
+ tx.Enqueue(w);
+ }
+ while (tx.Count > 0) {
+ Word w = tx.Dequeue();
+ foreach (Word w2 in w.GetReferences()) {
+ if (wordSet.ContainsKey(w2.Name)) {
+ continue;
+ }
+ wordSet[w2.Name] = w2;
+ tx.Enqueue(w2);
+ }
+ }
+
+ /*
+ * Do flow analysis.
+ */
+ if (enableFlowAnalysis) {
+ foreach (string ep in entryPoints) {
+ Word w = wordSet[ep];
+ w.AnalyseFlow();
+ Console.WriteLine("{0}: ds={1} rs={2}",
+ ep, w.MaxDataStack, w.MaxReturnStack);
+ if (w.MaxDataStack > dsLimit) {
+ throw new Exception("'" + ep
+ + "' exceeds data stack limit");
+ }
+ if (w.MaxReturnStack > rsLimit) {
+ throw new Exception("'" + ep
+ + "' exceeds return stack"
+ + " limit");
+ }
+ }
+ }
+
+ /*
+ * Gather referenced data areas and compute their
+ * addresses in the generated data block. The address
+ * 0 in the data block is unaffected so that no
+ * valid runtime pointer is equal to null.
+ */
+ IDictionary<long, ConstData> blocks =
+ new SortedDictionary<long, ConstData>();
+ foreach (Word w in wordSet.Values) {
+ foreach (ConstData cd in w.GetDataBlocks()) {
+ blocks[cd.ID] = cd;
+ }
+ }
+ int dataLen = 1;
+ foreach (ConstData cd in blocks.Values) {
+ cd.Address = dataLen;
+ dataLen += cd.Length;
+ }
+
+ /*
+ * Generated code is a sequence of "slot numbers", each
+ * referencing either a piece of explicit C code, or an
+ * entry in the table of interpreted words.
+ *
+ * Opcodes other than "call" get the slots 0 to 6:
+ *
+ * 0 ret no argument
+ * 1 const signed value
+ * 2 get local local number
+ * 3 put local local number
+ * 4 jump signed offset
+ * 5 jump if signed offset
+ * 6 jump if not signed offset
+ *
+ * The argument, if any, is in "7E" format: the value is
+ * encoded in 7-bit chunk, with big-endian signed
+ * convention. Each 7-bit chunk is encoded over one byte;
+ * the upper bit is 1 for all chunks except the last one.
+ *
+ * Words with explicit C code get the slot numbers
+ * immediately after 6. Interpreted words come afterwards.
+ */
+ IDictionary<string, int> slots = new Dictionary<string, int>();
+ int curSlot = 7;
+
+ /*
+ * Get explicit C code for words which have such code.
+ * We use string equality on C code so that words with
+ * identical implementations get merged.
+ *
+ * We also check that words with no explicit C code are
+ * interpreted.
+ */
+ IDictionary<string, int> ccodeUni =
+ new Dictionary<string, int>();
+ IDictionary<int, string> ccodeNames =
+ new Dictionary<int, string>();
+ foreach (Word w in wordSet.Values) {
+ string ccode = GetCCode(w.Name);
+ if (ccode == null) {
+ if (w is WordNative) {
+ throw new Exception(String.Format(
+ "No C code for native '{0}'",
+ w.Name));
+ }
+ continue;
+ }
+ int sn;
+ if (ccodeUni.ContainsKey(ccode)) {
+ sn = ccodeUni[ccode];
+ ccodeNames[sn] += " " + EscapeCComment(w.Name);
+ } else {
+ sn = curSlot ++;
+ ccodeUni[ccode] = sn;
+ ccodeNames[sn] = EscapeCComment(w.Name);
+ }
+ slots[w.Name] = sn;
+ w.Slot = sn;
+ }
+
+ /*
+ * Assign slot values to all remaining words; we know they
+ * are all interpreted.
+ */
+ int slotInterpreted = curSlot;
+ foreach (Word w in wordSet.Values) {
+ if (GetCCode(w.Name) != null) {
+ continue;
+ }
+ int sn = curSlot ++;
+ slots[w.Name] = sn;
+ w.Slot = sn;
+ }
+ int numInterpreted = curSlot - slotInterpreted;
+
+ /*
+ * Verify that all entry points are interpreted words.
+ */
+ foreach (string ep in entryPoints) {
+ if (GetCCode(ep) != null) {
+ throw new Exception(
+ "Non-interpreted entry point");
+ }
+ }
+
+ /*
+ * Compute the code block. Each word (without any C code)
+ * yields some CodeElement instances.
+ */
+ List<CodeElement> gcodeList = new List<CodeElement>();
+ CodeElement[] interpretedEntry =
+ new CodeElement[numInterpreted];
+ foreach (Word w in wordSet.Values) {
+ if (GetCCode(w.Name) != null) {
+ continue;
+ }
+ int n = gcodeList.Count;
+ w.GenerateCodeElements(gcodeList);
+ interpretedEntry[w.Slot - slotInterpreted] =
+ gcodeList[n];
+ }
+ CodeElement[] gcode = gcodeList.ToArray();
+
+ /*
+ * If there are less than 256 words in total (C +
+ * interpreted) then we can use "one-byte code" which is
+ * more compact when the number of words is in the
+ * 128..255 range.
+ */
+ bool oneByteCode;
+ if (slotInterpreted + numInterpreted >= 256) {
+ Console.WriteLine("WARNING: more than 255 words");
+ oneByteCode = false;
+ } else {
+ oneByteCode = true;
+ }
+
+ /*
+ * Compute all addresses and offsets. This loops until
+ * the addresses stabilize.
+ */
+ int totalLen = -1;
+ int[] gcodeLen = new int[gcode.Length];
+ for (;;) {
+ for (int i = 0; i < gcode.Length; i ++) {
+ gcodeLen[i] = gcode[i].GetLength(oneByteCode);
+ }
+ int off = 0;
+ for (int i = 0; i < gcode.Length; i ++) {
+ gcode[i].Address = off;
+ gcode[i].LastLength = gcodeLen[i];
+ off += gcodeLen[i];
+ }
+ if (off == totalLen) {
+ break;
+ }
+ totalLen = off;
+ }
+
+ /*
+ * Produce output file.
+ */
+ using (TextWriter tw = File.CreateText(outBase + ".c")) {
+ tw.NewLine = "\n";
+
+ tw.WriteLine("{0}",
+@"/* Automatically generated code; do not modify directly. */
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+} t0_context;
+
+static uint32_t
+t0_parse7E_unsigned(const unsigned char **p)
+{
+ uint32_t x;
+
+ x = 0;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ return x;
+ }
+ }
+}
+
+static int32_t
+t0_parse7E_signed(const unsigned char **p)
+{
+ int neg;
+ uint32_t x;
+
+ neg = ((**p) >> 6) & 1;
+ x = (uint32_t)-neg;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ if (neg) {
+ return -(int32_t)~x - 1;
+ } else {
+ return (int32_t)x;
+ }
+ }
+ }
+}
+
+#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80)
+#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F)
+#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8)
+#define T0_INT1(x) T0_FBYTE(x, 0)
+#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+
+/* static const unsigned char t0_datablock[]; */
+");
+
+ /*
+ * Add declarations (not definitions) for the
+ * entry point initialisation functions, and the
+ * runner.
+ */
+ tw.WriteLine();
+ foreach (string ep in entryPoints) {
+ tw.WriteLine("void {0}_init_{1}(void *t0ctx);",
+ coreRun, ep);
+ }
+ tw.WriteLine();
+ tw.WriteLine("void {0}_run(void *t0ctx);", coreRun);
+
+ /*
+ * Add preamble elements here. They may be needed
+ * for evaluating constant expressions in the
+ * code block.
+ */
+ foreach (string pp in extraCode) {
+ tw.WriteLine();
+ tw.WriteLine("{0}", pp);
+ }
+
+ BlobWriter bw;
+ tw.WriteLine();
+ tw.Write("static const unsigned char"
+ + " t0_datablock[] = {");
+ bw = new BlobWriter(tw, 78, 1);
+ bw.Append((byte)0);
+ foreach (ConstData cd in blocks.Values) {
+ cd.Encode(bw);
+ }
+ tw.WriteLine();
+ tw.WriteLine("};");
+
+ tw.WriteLine();
+ tw.Write("static const unsigned char"
+ + " t0_codeblock[] = {");
+ bw = new BlobWriter(tw, 78, 1);
+ foreach (CodeElement ce in gcode) {
+ ce.Encode(bw, oneByteCode);
+ }
+ tw.WriteLine();
+ tw.WriteLine("};");
+
+ tw.WriteLine();
+ tw.Write("static const uint16_t t0_caddr[] = {");
+ for (int i = 0; i < interpretedEntry.Length; i ++) {
+ if (i != 0) {
+ tw.Write(',');
+ }
+ tw.WriteLine();
+ tw.Write("\t{0}", interpretedEntry[i].Address);
+ }
+ tw.WriteLine();
+ tw.WriteLine("};");
+
+ tw.WriteLine();
+ tw.WriteLine("#define T0_INTERPRETED {0}",
+ slotInterpreted);
+ tw.WriteLine();
+ tw.WriteLine("{0}",
+@"#define T0_ENTER(ip, rp, slot) do { \
+ const unsigned char *t0_newip; \
+ uint32_t t0_lnum; \
+ t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \
+ t0_lnum = t0_parse7E_unsigned(&t0_newip); \
+ (rp) += t0_lnum; \
+ *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \
+ (ip) = t0_newip; \
+ } while (0)");
+ tw.WriteLine();
+ tw.WriteLine("{0}",
+@"#define T0_DEFENTRY(name, slot) \
+void \
+name(void *ctx) \
+{ \
+ t0_context *t0ctx = ctx; \
+ t0ctx->ip = &t0_codeblock[0]; \
+ T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
+}");
+
+ tw.WriteLine();
+ foreach (string ep in entryPoints) {
+ tw.WriteLine("T0_DEFENTRY({0}, {1})",
+ coreRun + "_init_" + ep,
+ wordSet[ep].Slot);
+ }
+ tw.WriteLine();
+ if (oneByteCode) {
+ tw.WriteLine("{0}",
+@"#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++)");
+ } else {
+ tw.WriteLine("{0}",
+@"#define T0_NEXT(t0ipp) t0_parse7E_unsigned(t0ipp)");
+ }
+ tw.WriteLine();
+ tw.WriteLine("void");
+ tw.WriteLine("{0}_run(void *t0ctx)", coreRun);
+ tw.WriteLine("{0}",
+@"{
+ uint32_t *dp, *rp;
+ const unsigned char *ip;
+
+#define T0_LOCAL(x) (*(rp - 2 - (x)))
+#define T0_POP() (*-- dp)
+#define T0_POPi() (*(int32_t *)(-- dp))
+#define T0_PEEK(x) (*(dp - 1 - (x)))
+#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x)))
+#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0)
+#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0)
+#define T0_RPOP() (*-- rp)
+#define T0_RPOPi() (*(int32_t *)(-- rp))
+#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0)
+#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0)
+#define T0_ROLL(x) do { \
+ size_t t0len = (size_t)(x); \
+ uint32_t t0tmp = *(dp - 1 - t0len); \
+ memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_SWAP() do { \
+ uint32_t t0tmp = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_ROT() do { \
+ uint32_t t0tmp = *(dp - 3); \
+ *(dp - 3) = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_NROT() do { \
+ uint32_t t0tmp = *(dp - 1); \
+ *(dp - 1) = *(dp - 2); \
+ *(dp - 2) = *(dp - 3); \
+ *(dp - 3) = t0tmp; \
+} while (0)
+#define T0_PICK(x) do { \
+ uint32_t t0depth = (x); \
+ T0_PUSH(T0_PEEK(t0depth)); \
+} while (0)
+#define T0_CO() do { \
+ goto t0_exit; \
+} while (0)
+#define T0_RET() goto t0_next
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ goto t0_next;
+ for (;;) {
+ uint32_t t0x;
+
+ t0_next:
+ t0x = T0_NEXT(&ip);
+ if (t0x < T0_INTERPRETED) {
+ switch (t0x) {
+ int32_t t0off;
+
+ case 0: /* ret */
+ t0x = T0_RPOP();
+ rp -= (t0x >> 16);
+ t0x &= 0xFFFF;
+ if (t0x == 0) {
+ ip = NULL;
+ goto t0_exit;
+ }
+ ip = &t0_codeblock[t0x];
+ break;
+ case 1: /* literal constant */
+ T0_PUSHi(t0_parse7E_signed(&ip));
+ break;
+ case 2: /* read local */
+ T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip)));
+ break;
+ case 3: /* write local */
+ T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP();
+ break;
+ case 4: /* jump */
+ t0off = t0_parse7E_signed(&ip);
+ ip += t0off;
+ break;
+ case 5: /* jump if */
+ t0off = t0_parse7E_signed(&ip);
+ if (T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 6: /* jump if not */
+ t0off = t0_parse7E_signed(&ip);
+ if (!T0_POP()) {
+ ip += t0off;
+ }
+ break;");
+
+ SortedDictionary<int, string> nccode =
+ new SortedDictionary<int, string>();
+ foreach (string k in ccodeUni.Keys) {
+ nccode[ccodeUni[k]] = k;
+ }
+ foreach (int sn in nccode.Keys) {
+ tw.WriteLine(
+@" case {0}: {{
+ /* {1} */
+{2}
+ }}
+ break;", sn, ccodeNames[sn], nccode[sn]);
+ }
+
+ tw.WriteLine(
+@" }
+
+ } else {
+ T0_ENTER(ip, rp, t0x);
+ }
+ }
+t0_exit:
+ ((t0_context *)t0ctx)->dp = dp;
+ ((t0_context *)t0ctx)->rp = rp;
+ ((t0_context *)t0ctx)->ip = ip;
+}");
+
+ /*
+ * Add the "postamblr" elements here. These are
+ * elements that may need access to the data
+ * block or code block, so they must occur after
+ * their definition.
+ */
+ foreach (string pp in extraCodeDefer) {
+ tw.WriteLine();
+ tw.WriteLine("{0}", pp);
+ }
+ }
+
+ int codeLen = 0;
+ foreach (CodeElement ce in gcode) {
+ codeLen += ce.GetLength(oneByteCode);
+ }
+ int dataBlockLen = 0;
+ foreach (ConstData cd in blocks.Values) {
+ dataBlockLen += cd.Length;
+ }
+
+ /*
+ * Write some statistics on produced code.
+ */
+ Console.WriteLine("code length: {0,6} byte(s)", codeLen);
+ Console.WriteLine("data length: {0,6} byte(s)", dataLen);
+ Console.WriteLine("total words: {0} (interpreted: {1})",
+ slotInterpreted + numInterpreted, numInterpreted);
+ }
+
+ internal Word Lookup(string name)
+ {
+ Word w = LookupNF(name);
+ if (w != null) {
+ return w;
+ }
+ throw new Exception(String.Format("No such word: '{0}'", name));
+ }
+
+ internal Word LookupNF(string name)
+ {
+ Word w;
+ words.TryGetValue(name, out w);
+ return w;
+ }
+
+ internal TValue StringToBlob(string s)
+ {
+ return new TValue(0, new TPointerBlob(this, s));
+ }
+
+ internal bool TryParseLiteral(string tt, out TValue tv)
+ {
+ tv = new TValue(0);
+ if (tt.StartsWith("\"")) {
+ tv = StringToBlob(tt.Substring(1));
+ return true;
+ }
+ if (tt.StartsWith("`")) {
+ tv = DecodeCharConst(tt.Substring(1));
+ return true;
+ }
+ bool neg = false;
+ if (tt.StartsWith("-")) {
+ neg = true;
+ tt = tt.Substring(1);
+ } else if (tt.StartsWith("+")) {
+ tt = tt.Substring(1);
+ }
+ uint radix = 10;
+ if (tt.StartsWith("0x") || tt.StartsWith("0X")) {
+ radix = 16;
+ tt = tt.Substring(2);
+ } else if (tt.StartsWith("0b") || tt.StartsWith("0B")) {
+ radix = 2;
+ tt = tt.Substring(2);
+ }
+ if (tt.Length == 0) {
+ return false;
+ }
+ uint acc = 0;
+ bool overflow = false;
+ uint maxV = uint.MaxValue / radix;
+ foreach (char c in tt) {
+ int d = HexVal(c);
+ if (d < 0 || d >= radix) {
+ return false;
+ }
+ if (acc > maxV) {
+ overflow = true;
+ }
+ acc *= radix;
+ if ((uint)d > uint.MaxValue - acc) {
+ overflow = true;
+ }
+ acc += (uint)d;
+ }
+ int x = (int)acc;
+ if (neg) {
+ if (acc > (uint)0x80000000) {
+ overflow = true;
+ }
+ x = -x;
+ }
+ if (overflow) {
+ throw new Exception(
+ "invalid literal integer (overflow)");
+ }
+ tv = x;
+ return true;
+ }
+
+ int ParseInteger(string tt)
+ {
+ TValue tv;
+ if (!TryParseLiteral(tt, out tv)) {
+ throw new Exception("not an integer: " + ToString());
+ }
+ return (int)tv;
+ }
+
+ void CheckCompiling()
+ {
+ if (!compiling) {
+ throw new Exception("Not in compilation mode");
+ }
+ }
+
+ static string EscapeCComment(string s)
+ {
+ StringBuilder sb = new StringBuilder();
+ foreach (char c in s) {
+ if (c >= 33 && c <= 126 && c != '%') {
+ sb.Append(c);
+ } else if (c < 0x100) {
+ sb.AppendFormat("%{0:X2}", (int)c);
+ } else if (c < 0x800) {
+ sb.AppendFormat("%{0:X2}%{0:X2}",
+ ((int)c >> 6) | 0xC0,
+ ((int)c & 0x3F) | 0x80);
+ } else {
+ sb.AppendFormat("%{0:X2}%{0:X2}%{0:X2}",
+ ((int)c >> 12) | 0xE0,
+ (((int)c >> 6) & 0x3F) | 0x80,
+ ((int)c & 0x3F) | 0x80);
+ }
+ }
+ return sb.ToString().Replace("*/", "%2A/");
+ }
+}
diff --git a/contrib/bearssl/T0/TPointerBase.cs b/contrib/bearssl/T0/TPointerBase.cs
new file mode 100644
index 000000000000..f996d8d878cf
--- /dev/null
+++ b/contrib/bearssl/T0/TPointerBase.cs
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/T0/TPointerBlob.cs b/contrib/bearssl/T0/TPointerBlob.cs
new file mode 100644
index 000000000000..d4aeff647c52
--- /dev/null
+++ b/contrib/bearssl/T0/TPointerBlob.cs
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/T0/TPointerExpr.cs b/contrib/bearssl/T0/TPointerExpr.cs
new file mode 100644
index 000000000000..314b27208971
--- /dev/null
+++ b/contrib/bearssl/T0/TPointerExpr.cs
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/T0/TPointerNull.cs b/contrib/bearssl/T0/TPointerNull.cs
new file mode 100644
index 000000000000..f8eb11e42f20
--- /dev/null
+++ b/contrib/bearssl/T0/TPointerNull.cs
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/T0/TPointerXT.cs b/contrib/bearssl/T0/TPointerXT.cs
new file mode 100644
index 000000000000..883f31296417
--- /dev/null
+++ b/contrib/bearssl/T0/TPointerXT.cs
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/T0/TValue.cs b/contrib/bearssl/T0/TValue.cs
new file mode 100644
index 000000000000..e4f225574c8e
--- /dev/null
+++ b/contrib/bearssl/T0/TValue.cs
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/T0/Word.cs b/contrib/bearssl/T0/Word.cs
new file mode 100644
index 000000000000..2dfb66ef0691
--- /dev/null
+++ b/contrib/bearssl/T0/Word.cs
@@ -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;
+ }
+ }
+}
diff --git a/contrib/bearssl/T0/WordBuilder.cs b/contrib/bearssl/T0/WordBuilder.cs
new file mode 100644
index 000000000000..c410930eab78
--- /dev/null
+++ b/contrib/bearssl/T0/WordBuilder.cs
@@ -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));
+ }
+}
diff --git a/contrib/bearssl/T0/WordData.cs b/contrib/bearssl/T0/WordData.cs
new file mode 100644
index 000000000000..2d74bd3effe3
--- /dev/null
+++ b/contrib/bearssl/T0/WordData.cs
@@ -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));
+ }
+}
diff --git a/contrib/bearssl/T0/WordInterpreted.cs b/contrib/bearssl/T0/WordInterpreted.cs
new file mode 100644
index 000000000000..882170b23930
--- /dev/null
+++ b/contrib/bearssl/T0/WordInterpreted.cs
@@ -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;
+ }
+ }
+}
diff --git a/contrib/bearssl/T0/WordNative.cs b/contrib/bearssl/T0/WordNative.cs
new file mode 100644
index 000000000000..786887253762
--- /dev/null
+++ b/contrib/bearssl/T0/WordNative.cs
@@ -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);
+ }
+}
diff --git a/contrib/bearssl/T0/kern.t0 b/contrib/bearssl/T0/kern.t0
new file mode 100644
index 000000000000..9fce4f84d301
--- /dev/null
+++ b/contrib/bearssl/T0/kern.t0
@@ -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));
+}
diff --git a/contrib/bearssl/T0Comp.exe b/contrib/bearssl/T0Comp.exe
new file mode 100755
index 000000000000..67eba109800e
--- /dev/null
+++ b/contrib/bearssl/T0Comp.exe
Binary files differ
diff --git a/contrib/bearssl/build/.do_not_remove b/contrib/bearssl/build/.do_not_remove
new file mode 100644
index 000000000000..e69de29bb2d1
--- /dev/null
+++ b/contrib/bearssl/build/.do_not_remove
diff --git a/contrib/bearssl/conf/Unix.mk b/contrib/bearssl/conf/Unix.mk
new file mode 100644
index 000000000000..02f2b2be8ee4
--- /dev/null
+++ b/contrib/bearssl/conf/Unix.mk
@@ -0,0 +1,69 @@
+# Configuration for a native build on a generic Unix-like system.
+
+# Build directory.
+BUILD = build
+
+# Extension for executable files.
+E =
+
+# Extension for object files.
+O = .o
+
+# Prefix for library file name.
+LP = lib
+
+# Extension for library file name.
+L = .a
+
+# Prefix for DLL file name.
+DP = lib
+
+# Extension for DLL file name.
+D = .so
+
+# Output file names can be overridden directly. By default, they are
+# assembled using the prefix/extension macros defined above.
+# BEARSSLLIB = libbearssl.a
+# BEARSSLDLL = libbearssl.so
+# BRSSL = brssl
+# TESTCRYPTO = testcrypto
+# TESTSPEED = testspeed
+# TESTX509 = testx509
+
+# File deletion tool.
+RM = rm -f
+
+# Directory creation tool.
+MKDIR = mkdir -p
+
+# C compiler and flags.
+CC = cc
+CFLAGS = -W -Wall -Os -fPIC
+CCOUT = -c -o
+
+# Static library building tool.
+AR = ar
+ARFLAGS = -rcs
+AROUT =
+
+# DLL building tool.
+LDDLL = cc
+LDDLLFLAGS = -shared
+LDDLLOUT = -o
+
+# Static linker.
+LD = cc
+LDFLAGS =
+LDOUT = -o
+
+# C# compiler; we assume usage of Mono.
+MKT0COMP = mk$PmkT0.sh
+RUNT0COMP = mono T0Comp.exe
+
+# Set the values to 'no' to disable building of the corresponding element
+# by default. Building can still be invoked with an explicit target call
+# (e.g. 'make dll' to force build the DLL).
+#STATICLIB = no
+#DLL = no
+#TOOLS = no
+#TESTS = no
diff --git a/contrib/bearssl/conf/Unix32.mk b/contrib/bearssl/conf/Unix32.mk
new file mode 100644
index 000000000000..0d3bed8808b5
--- /dev/null
+++ b/contrib/bearssl/conf/Unix32.mk
@@ -0,0 +1,12 @@
+# Example configuration file for compiling on a Unix-like system with
+# GCC, targeting a 32-bit output. Moreover, it enables the "LOMUL" setting
+# to make the code select the "small" integer implementations (i15, m15,
+# ctmul32...), which is not necessarily a good idea for performance, but
+# handy for tests.
+
+include conf/Unix.mk
+
+BUILD = build32
+CFLAGS = -W -Wall -Os -fPIC -m32 -DBR_LOMUL
+LDFLAGS = -m32
+LDDLLFLAGS = -shared -m32
diff --git a/contrib/bearssl/conf/UnixClang.mk b/contrib/bearssl/conf/UnixClang.mk
new file mode 100644
index 000000000000..3636cf896c78
--- /dev/null
+++ b/contrib/bearssl/conf/UnixClang.mk
@@ -0,0 +1,11 @@
+# Example configuration file for compiling on a Unix-like system with
+# clang as compiler instead of gcc.
+
+# We are on a Unix system so we assume a Single Unix compatible 'make'
+# utility, and Unix defaults.
+include conf/Unix.mk
+
+BUILD = bclang
+CC = clang
+LD = clang
+LDDLL = clang
diff --git a/contrib/bearssl/conf/Win.mk b/contrib/bearssl/conf/Win.mk
new file mode 100644
index 000000000000..2ed4bb6895aa
--- /dev/null
+++ b/contrib/bearssl/conf/Win.mk
@@ -0,0 +1,70 @@
+# Configuration for a native build on a Windows system with Visual Studio.
+
+# Build directory.
+BUILD = build
+
+# Extension for executable files.
+E = .exe
+
+# Extension for object files.
+O = .obj
+
+# Prefix for static library file name.
+LP =
+
+# Extension for static library file name. We add an 's' so that the
+# name is distinct from the 'import library' generated along with the DLL.
+L = s.lib
+
+# Prefix for DLL file name.
+DP =
+
+# Extension for DLL file name.
+D = .dll
+
+# Output file names can be overridden directly. By default, they are
+# assembled using the prefix/extension macros defined above.
+# BEARSSLLIB = bearssls.lib
+# BEARSSLDLL = bearssl.dll
+# BRSSL = brssl.exe
+# TESTCRYPTO = testcrypto.exe
+# TESTSPEED = testspeed.exe
+# TESTX509 = testx509.exe
+
+# File deletion tool.
+RM = del /Q
+
+# Directory creation tool.
+MKDIR = mkdir
+
+# C compiler and flags.
+CC = cl
+CFLAGS = -nologo -W2 -O2
+CCOUT = -c -Fo
+
+# Static library building tool.
+AR = lib
+ARFLAGS = -nologo
+AROUT = -out:
+
+# DLL building tool.
+LDDLL = cl
+LDDLLFLAGS = -nologo -LD -MT
+LDDLLOUT = -Fe
+
+# Static linker.
+LD = cl
+LDFLAGS = -nologo
+LDOUT = -Fe
+
+# C# compiler.
+MKT0COMP = mk$PmkT0.cmd
+RUNT0COMP = T0Comp.exe
+
+# Set the values to 'no' to disable building of the corresponding element
+# by default. Building can still be invoked with an explicit target call
+# (e.g. 'make dll' to force build the DLL).
+#STATICLIB = no
+#DLL = no
+#TOOLS = no
+#TESTS = no
diff --git a/contrib/bearssl/conf/samd20.mk b/contrib/bearssl/conf/samd20.mk
new file mode 100644
index 000000000000..5b3d5004c38a
--- /dev/null
+++ b/contrib/bearssl/conf/samd20.mk
@@ -0,0 +1,20 @@
+# Example configuration file for compiling for an Atmel SAM D20 Xplained
+# Pro evaluation kit, on a Unix-like system, with a GNU toolchain.
+
+# We are on a Unix system so we assume a Single Unix compatible 'make'
+# utility, and Unix defaults.
+include conf/Unix.mk
+
+# We override the build directory.
+BUILD = samd20
+
+# C compiler, linker, and static library builder.
+CC = arm-none-eabi-gcc
+CFLAGS = -W -Wall -Os -mthumb -ffunction-sections -fdata-sections -mcpu=cortex-m0plus -DBR_ARMEL_CORTEXM_GCC
+LD = arm-none-eabi-gcc
+AR = arm-none-eabi-ar
+
+# We compile only the static library.
+DLL = no
+TOOLS = no
+TESTS = no
diff --git a/contrib/bearssl/inc/bearssl.h b/contrib/bearssl/inc/bearssl.h
new file mode 100644
index 000000000000..4f4797cf7937
--- /dev/null
+++ b/contrib/bearssl/inc/bearssl.h
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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>
+
+/** \mainpage BearSSL API
+ *
+ * # API Layout
+ *
+ * The functions and structures defined by the BearSSL API are located
+ * in various header files:
+ *
+ * | Header file | Elements |
+ * | :-------------- | :------------------------------------------------ |
+ * | bearssl_hash.h | Hash functions |
+ * | bearssl_hmac.h | HMAC |
+ * | bearssl_kdf.h | Key Derivation Functions |
+ * | bearssl_rand.h | Pseudorandom byte generators |
+ * | bearssl_prf.h | PRF implementations (for SSL/TLS) |
+ * | bearssl_block.h | Symmetric encryption |
+ * | bearssl_aead.h | AEAD algorithms (combined encryption + MAC) |
+ * | bearssl_rsa.h | RSA encryption and signatures |
+ * | bearssl_ec.h | Elliptic curves support (including ECDSA) |
+ * | bearssl_ssl.h | SSL/TLS engine interface |
+ * | bearssl_x509.h | X.509 certificate decoding and validation |
+ * | bearssl_pem.h | Base64/PEM decoding support functions |
+ *
+ * Applications using BearSSL are supposed to simply include `bearssl.h`
+ * as follows:
+ *
+ * #include <bearssl.h>
+ *
+ * The `bearssl.h` file itself includes all the other header files. It is
+ * possible to include specific header files, but it has no practical
+ * advantage for the application. The API is separated into separate
+ * header files only for documentation convenience.
+ *
+ *
+ * # Conventions
+ *
+ * ## MUST and SHALL
+ *
+ * In all descriptions, the usual "MUST", "SHALL", "MAY",... terminology
+ * is used. Failure to meet requirements expressed with a "MUST" or
+ * "SHALL" implies undefined behaviour, which means that segmentation
+ * faults, buffer overflows, and other similar adverse events, may occur.
+ *
+ * In general, BearSSL is not very forgiving of programming errors, and
+ * does not include much failsafes or error reporting when the problem
+ * does not arise from external transient conditions, and can be fixed
+ * only in the application code. This is done so in order to make the
+ * total code footprint lighter.
+ *
+ *
+ * ## `NULL` values
+ *
+ * Function parameters with a pointer type shall not be `NULL` unless
+ * explicitly authorised by the documentation. As an exception, when
+ * the pointer aims at a sequence of bytes and is accompanied with
+ * a length parameter, and the length is zero (meaning that there is
+ * no byte at all to retrieve), then the pointer may be `NULL` even if
+ * not explicitly allowed.
+ *
+ *
+ * ## Memory Allocation
+ *
+ * BearSSL does not perform dynamic memory allocation. This implies that
+ * for any functionality that requires a non-transient state, the caller
+ * is responsible for allocating the relevant context structure. Such
+ * allocation can be done in any appropriate area, including static data
+ * segments, the heap, and the stack, provided that proper alignment is
+ * respected. The header files define these context structures
+ * (including size and contents), so the C compiler should handle
+ * alignment automatically.
+ *
+ * Since there is no dynamic resource allocation, there is also nothing to
+ * release. When the calling code is done with a BearSSL feature, it
+ * may simple release the context structures it allocated itself, with
+ * no "close function" to call. If the context structures were allocated
+ * on the stack (as local variables), then even that release operation is
+ * implicit.
+ *
+ *
+ * ## Structure Contents
+ *
+ * Except when explicitly indicated, structure contents are opaque: they
+ * are included in the header files so that calling code may know the
+ * structure sizes and alignment requirements, but callers SHALL NOT
+ * access individual fields directly. For fields that are supposed to
+ * be read from or written to, the API defines accessor functions (the
+ * simplest of these accessor functions are defined as `static inline`
+ * functions, and the C compiler will optimise them away).
+ *
+ *
+ * # API Usage
+ *
+ * BearSSL usage for running a SSL/TLS client or server is described
+ * on the [BearSSL Web site](https://www.bearssl.org/api1.html). The
+ * BearSSL source archive also comes with sample code.
+ */
+
+#include "bearssl_hash.h"
+#include "bearssl_hmac.h"
+#include "bearssl_kdf.h"
+#include "bearssl_rand.h"
+#include "bearssl_prf.h"
+#include "bearssl_block.h"
+#include "bearssl_aead.h"
+#include "bearssl_rsa.h"
+#include "bearssl_ec.h"
+#include "bearssl_ssl.h"
+#include "bearssl_x509.h"
+#include "bearssl_pem.h"
+
+/** \brief Type for a configuration option.
+ *
+ * A "configuration option" is a value that is selected when the BearSSL
+ * library itself is compiled. Most options are boolean; their value is
+ * then either 1 (option is enabled) or 0 (option is disabled). Some
+ * values have other integer values. Option names correspond to macro
+ * names. Some of the options can be explicitly set in the internal
+ * `"config.h"` file.
+ */
+typedef struct {
+ /** \brief Configurable option name. */
+ const char *name;
+ /** \brief Configurable option value. */
+ long value;
+} br_config_option;
+
+/** \brief Get configuration report.
+ *
+ * This function returns compiled configuration options, each as a
+ * 'long' value. Names match internal macro names, in particular those
+ * that can be set in the `"config.h"` inner file. For boolean options,
+ * the numerical value is 1 if enabled, 0 if disabled. For maximum
+ * key sizes, values are expressed in bits.
+ *
+ * The returned array is terminated by an entry whose `name` is `NULL`.
+ *
+ * \return the configuration report.
+ */
+const br_config_option *br_get_config(void);
+
+#endif
diff --git a/contrib/bearssl/inc/bearssl_aead.h b/contrib/bearssl/inc/bearssl_aead.h
new file mode 100644
index 000000000000..8e35a1fdeb43
--- /dev/null
+++ b/contrib/bearssl/inc/bearssl_aead.h
@@ -0,0 +1,1059 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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_AEAD_H__
+#define BR_BEARSSL_AEAD_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "bearssl_block.h"
+#include "bearssl_hash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_aead.h
+ *
+ * # Authenticated Encryption with Additional Data
+ *
+ * This file documents the API for AEAD encryption.
+ *
+ *
+ * ## Procedural API
+ *
+ * An AEAD algorithm processes messages and provides confidentiality
+ * (encryption) and checked integrity (MAC). It uses the following
+ * parameters:
+ *
+ * - A symmetric key. Exact size depends on the AEAD algorithm.
+ *
+ * - A nonce (IV). Size depends on the AEAD algorithm; for most
+ * algorithms, it is crucial for security that any given nonce
+ * value is never used twice for the same key and distinct
+ * messages.
+ *
+ * - Data to encrypt and protect.
+ *
+ * - Additional authenticated data, which is covered by the MAC but
+ * otherwise left untouched (i.e. not encrypted).
+ *
+ * The AEAD algorithm encrypts the data, and produces an authentication
+ * tag. It is assumed that the encrypted data, the tag, the additional
+ * authenticated data and the nonce are sent to the receiver; the
+ * additional data and the nonce may be implicit (e.g. using elements of
+ * the underlying transport protocol, such as record sequence numbers).
+ * The receiver will recompute the tag value and compare it with the one
+ * received; if they match, then the data is correct, and can be
+ * decrypted and used; otherwise, at least one of the elements was
+ * altered in transit, normally leading to wholesale rejection of the
+ * complete message.
+ *
+ * For each AEAD algorithm, identified by a symbolic name (hereafter
+ * denoted as "`xxx`"), the following functions are defined:
+ *
+ * - `br_xxx_init()`
+ *
+ * Initialise the AEAD algorithm, on a provided context structure.
+ * Exact parameters depend on the algorithm, and may include
+ * pointers to extra implementations and context structures. The
+ * secret key is provided at this point, either directly or
+ * indirectly.
+ *
+ * - `br_xxx_reset()`
+ *
+ * Start a new AEAD computation. The nonce value is provided as
+ * parameter to this function.
+ *
+ * - `br_xxx_aad_inject()`
+ *
+ * Inject some additional authenticated data. Additional data may
+ * be provided in several chunks of arbitrary length.
+ *
+ * - `br_xxx_flip()`
+ *
+ * This function MUST be called after injecting all additional
+ * authenticated data, and before beginning to encrypt the plaintext
+ * (or decrypt the ciphertext).
+ *
+ * - `br_xxx_run()`
+ *
+ * Process some plaintext (to encrypt) or ciphertext (to decrypt).
+ * Encryption/decryption is done in place. Data may be provided in
+ * several chunks of arbitrary length.
+ *
+ * - `br_xxx_get_tag()`
+ *
+ * Compute the authentication tag. All message data (encrypted or
+ * decrypted) must have been injected at that point. Also, this
+ * call may modify internal context elements, so it may be called
+ * only once for a given AEAD computation.
+ *
+ * - `br_xxx_check_tag()`
+ *
+ * An alternative to `br_xxx_get_tag()`, meant to be used by the
+ * receiver: the authentication tag is internally recomputed, and
+ * compared with the one provided as parameter.
+ *
+ * This API makes the following assumptions on the AEAD algorithm:
+ *
+ * - Encryption does not expand the size of the ciphertext; there is
+ * no padding. This is true of most modern AEAD modes such as GCM.
+ *
+ * - The additional authenticated data must be processed first,
+ * before the encrypted/decrypted data.
+ *
+ * - Nonce, plaintext and additional authenticated data all consist
+ * in an integral number of bytes. There is no provision to use
+ * elements whose length in bits is not a multiple of 8.
+ *
+ * Each AEAD algorithm has its own requirements and limits on the sizes
+ * of additional data and plaintext. This API does not provide any
+ * way to report invalid usage; it is up to the caller to ensure that
+ * the provided key, nonce, and data elements all fit the algorithm's
+ * requirements.
+ *
+ *
+ * ## 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:
+ *
+ * - `reset`
+ *
+ * Pointer to the reset function, that allows starting a new
+ * computation.
+ *
+ * - `aad_inject`
+ *
+ * Pointer to the additional authenticated data injection function.
+ *
+ * - `flip`
+ *
+ * Pointer to the function that transitions from additional data
+ * to main message data processing.
+ *
+ * - `get_tag`
+ *
+ * Pointer to the function that computes and returns the tag.
+ *
+ * - `check_tag`
+ *
+ * Pointer to the function that computes and verifies the tag against
+ * a received value.
+ *
+ * Note that there is no OOP method for context initialisation: the
+ * various AEAD algorithms have different requirements that would not
+ * map well to a single initialisation API.
+ *
+ * The OOP API is not provided for CCM, due to its specific requirements
+ * (length of plaintext must be known in advance).
+ */
+
+/**
+ * \brief Class type of an AEAD algorithm.
+ */
+typedef struct br_aead_class_ br_aead_class;
+struct br_aead_class_ {
+
+ /**
+ * \brief Size (in bytes) of authentication tags created by
+ * this AEAD algorithm.
+ */
+ size_t tag_size;
+
+ /**
+ * \brief Reset an AEAD context.
+ *
+ * This function resets an already initialised AEAD context for
+ * a new computation run. Implementations and keys are
+ * conserved. This function can be called at any time; it
+ * cancels any ongoing AEAD computation that uses the provided
+ * context structure.
+
+ * The provided IV is a _nonce_. Each AEAD algorithm has its
+ * own requirements on IV size and contents; for most of them,
+ * it is crucial to security that each nonce value is used
+ * only once for a given secret key.
+ *
+ * \param cc AEAD context structure.
+ * \param iv AEAD nonce to use.
+ * \param len AEAD nonce length (in bytes).
+ */
+ void (*reset)(const br_aead_class **cc, const void *iv, size_t len);
+
+ /**
+ * \brief Inject additional authenticated data.
+ *
+ * The provided data is injected into a running AEAD
+ * computation. Additional data must be injected _before_ the
+ * call to `flip()`. Additional data can be injected in several
+ * chunks of arbitrary length.
+ *
+ * \param cc AEAD context structure.
+ * \param data pointer to additional authenticated data.
+ * \param len length of additional authenticated data (in bytes).
+ */
+ void (*aad_inject)(const br_aead_class **cc,
+ const void *data, size_t len);
+
+ /**
+ * \brief Finish injection of additional authenticated data.
+ *
+ * This function MUST be called before beginning the actual
+ * encryption or decryption (with `run()`), even if no
+ * additional authenticated data was injected. No additional
+ * authenticated data may be injected after this function call.
+ *
+ * \param cc AEAD context structure.
+ */
+ void (*flip)(const br_aead_class **cc);
+
+ /**
+ * \brief Encrypt or decrypt some data.
+ *
+ * Data encryption or decryption can be done after `flip()` has
+ * been called on the context. If `encrypt` is non-zero, then
+ * the provided data shall be plaintext, and it is encrypted in
+ * place. Otherwise, the data shall be ciphertext, and it is
+ * decrypted in place.
+ *
+ * Data may be provided in several chunks of arbitrary length.
+ *
+ * \param cc AEAD context structure.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ */
+ void (*run)(const br_aead_class **cc, int encrypt,
+ void *data, size_t len);
+
+ /**
+ * \brief Compute authentication tag.
+ *
+ * Compute the AEAD authentication tag. The tag length depends
+ * on the AEAD algorithm; it is written in the provided `tag`
+ * buffer. This call terminates the AEAD run: no data may be
+ * processed with that AEAD context afterwards, until `reset()`
+ * is called to initiate a new AEAD run.
+ *
+ * The tag value must normally be sent along with the encrypted
+ * data. When decrypting, the tag value must be recomputed and
+ * compared with the received tag: if the two tag values differ,
+ * then either the tag or the encrypted data was altered in
+ * transit. As an alternative to this function, the
+ * `check_tag()` function may be used to compute and check the
+ * tag value.
+ *
+ * Tag length depends on the AEAD algorithm.
+ *
+ * \param cc AEAD context structure.
+ * \param tag destination buffer for the tag.
+ */
+ void (*get_tag)(const br_aead_class **cc, void *tag);
+
+ /**
+ * \brief Compute and check authentication tag.
+ *
+ * This function is an alternative to `get_tag()`, and is
+ * normally used on the receiving end (i.e. when decrypting
+ * messages). The tag value is recomputed and compared with the
+ * provided tag value. If they match, 1 is returned; on
+ * mismatch, 0 is returned. A returned value of 0 means that the
+ * data or the tag was altered in transit, normally leading to
+ * wholesale rejection of the complete message.
+ *
+ * Tag length depends on the AEAD algorithm.
+ *
+ * \param cc AEAD context structure.
+ * \param tag tag value to compare with.
+ * \return 1 on success (exact match of tag value), 0 otherwise.
+ */
+ uint32_t (*check_tag)(const br_aead_class **cc, const void *tag);
+
+ /**
+ * \brief Compute authentication tag (with truncation).
+ *
+ * This function is similar to `get_tag()`, except that the tag
+ * length is provided. Some AEAD algorithms allow several tag
+ * lengths, usually by truncating the normal tag. Shorter tags
+ * mechanically increase success probability of forgeries.
+ * The range of allowed tag lengths depends on the algorithm.
+ *
+ * \param cc AEAD context structure.
+ * \param tag destination buffer for the tag.
+ * \param len tag length (in bytes).
+ */
+ void (*get_tag_trunc)(const br_aead_class **cc, void *tag, size_t len);
+
+ /**
+ * \brief Compute and check authentication tag (with truncation).
+ *
+ * This function is similar to `check_tag()` except that it
+ * works over an explicit tag length. See `get_tag()` for a
+ * discussion of explicit tag lengths; the range of allowed tag
+ * lengths depends on the algorithm.
+ *
+ * \param cc AEAD context structure.
+ * \param tag tag value to compare with.
+ * \param len tag length (in bytes).
+ * \return 1 on success (exact match of tag value), 0 otherwise.
+ */
+ uint32_t (*check_tag_trunc)(const br_aead_class **cc,
+ const void *tag, size_t len);
+};
+
+/**
+ * \brief Context structure for GCM.
+ *
+ * GCM is an AEAD mode that combines a block cipher in CTR mode with a
+ * MAC based on GHASH, to provide authenticated encryption:
+ *
+ * - Any block cipher with 16-byte blocks can be used with GCM.
+ *
+ * - The nonce can have any length, from 0 up to 2^64-1 bits; however,
+ * 96-bit nonces (12 bytes) are recommended (nonces with a length
+ * distinct from 12 bytes are internally hashed, which risks reusing
+ * nonce value with a small but not always negligible probability).
+ *
+ * - Additional authenticated data may have length up to 2^64-1 bits.
+ *
+ * - Message length may range up to 2^39-256 bits at most.
+ *
+ * - The authentication tag has length 16 bytes.
+ *
+ * The GCM initialisation function receives as parameter an
+ * _initialised_ block cipher implementation context, with the secret
+ * key already set. A pointer to that context will be kept within the
+ * GCM context structure. It is up to the caller to allocate and
+ * initialise that block cipher context.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_aead_class *vtable;
+
+#ifndef BR_DOXYGEN_IGNORE
+ const br_block_ctr_class **bctx;
+ br_ghash gh;
+ unsigned char h[16];
+ unsigned char j0_1[12];
+ unsigned char buf[16];
+ unsigned char y[16];
+ uint32_t j0_2, jc;
+ uint64_t count_aad, count_ctr;
+#endif
+} br_gcm_context;
+
+/**
+ * \brief Initialize a GCM context.
+ *
+ * A block cipher implementation, with its initialised context structure,
+ * is provided. The block cipher MUST use 16-byte blocks in CTR mode,
+ * and its secret key MUST have been already set in the provided context.
+ * A GHASH implementation must also be provided. The parameters are linked
+ * in the GCM context.
+ *
+ * After this function has been called, the `br_gcm_reset()` function must
+ * be called, to provide the IV for GCM computation.
+ *
+ * \param ctx GCM context structure.
+ * \param bctx block cipher context (already initialised with secret key).
+ * \param gh GHASH implementation.
+ */
+void br_gcm_init(br_gcm_context *ctx,
+ const br_block_ctr_class **bctx, br_ghash gh);
+
+/**
+ * \brief Reset a GCM context.
+ *
+ * This function resets an already initialised GCM context for a new
+ * computation run. Implementations and keys are conserved. This function
+ * can be called at any time; it cancels any ongoing GCM computation that
+ * uses the provided context structure.
+ *
+ * The provided IV is a _nonce_. It is critical to GCM security that IV
+ * values are not repeated for the same encryption key. IV can have
+ * arbitrary length (up to 2^64-1 bits), but the "normal" length is
+ * 96 bits (12 bytes).
+ *
+ * \param ctx GCM context structure.
+ * \param iv GCM nonce to use.
+ * \param len GCM nonce length (in bytes).
+ */
+void br_gcm_reset(br_gcm_context *ctx, const void *iv, size_t len);
+
+/**
+ * \brief Inject additional authenticated data into GCM.
+ *
+ * The provided data is injected into a running GCM computation. Additional
+ * data must be injected _before_ the call to `br_gcm_flip()`.
+ * Additional data can be injected in several chunks of arbitrary length;
+ * the maximum total size of additional authenticated data is 2^64-1
+ * bits.
+ *
+ * \param ctx GCM context structure.
+ * \param data pointer to additional authenticated data.
+ * \param len length of additional authenticated data (in bytes).
+ */
+void br_gcm_aad_inject(br_gcm_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Finish injection of additional authenticated data into GCM.
+ *
+ * This function MUST be called before beginning the actual encryption
+ * or decryption (with `br_gcm_run()`), even if no additional authenticated
+ * data was injected. No additional authenticated data may be injected
+ * after this function call.
+ *
+ * \param ctx GCM context structure.
+ */
+void br_gcm_flip(br_gcm_context *ctx);
+
+/**
+ * \brief Encrypt or decrypt some data with GCM.
+ *
+ * Data encryption or decryption can be done after `br_gcm_flip()`
+ * has been called on the context. If `encrypt` is non-zero, then the
+ * provided data shall be plaintext, and it is encrypted in place.
+ * Otherwise, the data shall be ciphertext, and it is decrypted in place.
+ *
+ * Data may be provided in several chunks of arbitrary length. The maximum
+ * total length for data is 2^39-256 bits, i.e. about 65 gigabytes.
+ *
+ * \param ctx GCM context structure.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ */
+void br_gcm_run(br_gcm_context *ctx, int encrypt, void *data, size_t len);
+
+/**
+ * \brief Compute GCM authentication tag.
+ *
+ * Compute the GCM authentication tag. The tag is a 16-byte value which
+ * is written in the provided `tag` buffer. This call terminates the
+ * GCM run: no data may be processed with that GCM context afterwards,
+ * until `br_gcm_reset()` is called to initiate a new GCM run.
+ *
+ * The tag value must normally be sent along with the encrypted data.
+ * When decrypting, the tag value must be recomputed and compared with
+ * the received tag: if the two tag values differ, then either the tag
+ * or the encrypted data was altered in transit. As an alternative to
+ * this function, the `br_gcm_check_tag()` function can be used to
+ * compute and check the tag value.
+ *
+ * \param ctx GCM context structure.
+ * \param tag destination buffer for the tag (16 bytes).
+ */
+void br_gcm_get_tag(br_gcm_context *ctx, void *tag);
+
+/**
+ * \brief Compute and check GCM authentication tag.
+ *
+ * This function is an alternative to `br_gcm_get_tag()`, normally used
+ * on the receiving end (i.e. when decrypting value). The tag value is
+ * recomputed and compared with the provided tag value. If they match, 1
+ * is returned; on mismatch, 0 is returned. A returned value of 0 means
+ * that the data or the tag was altered in transit, normally leading to
+ * wholesale rejection of the complete message.
+ *
+ * \param ctx GCM context structure.
+ * \param tag tag value to compare with (16 bytes).
+ * \return 1 on success (exact match of tag value), 0 otherwise.
+ */
+uint32_t br_gcm_check_tag(br_gcm_context *ctx, const void *tag);
+
+/**
+ * \brief Compute GCM authentication tag (with truncation).
+ *
+ * This function is similar to `br_gcm_get_tag()`, except that it allows
+ * the tag to be truncated to a smaller length. The intended tag length
+ * is provided as `len` (in bytes); it MUST be no more than 16, but
+ * it may be smaller. Note that decreasing tag length mechanically makes
+ * forgeries easier; NIST SP 800-38D specifies that the tag length shall
+ * lie between 12 and 16 bytes (inclusive), but may be truncated down to
+ * 4 or 8 bytes, for specific applications that can tolerate it. It must
+ * also be noted that successful forgeries leak information on the
+ * authentication key, making subsequent forgeries easier. Therefore,
+ * tag truncation, and in particular truncation to sizes lower than 12
+ * bytes, shall be envisioned only with great care.
+ *
+ * The tag is written in the provided `tag` buffer. This call terminates
+ * the GCM run: no data may be processed with that GCM context
+ * afterwards, until `br_gcm_reset()` is called to initiate a new GCM
+ * run.
+ *
+ * The tag value must normally be sent along with the encrypted data.
+ * When decrypting, the tag value must be recomputed and compared with
+ * the received tag: if the two tag values differ, then either the tag
+ * or the encrypted data was altered in transit. As an alternative to
+ * this function, the `br_gcm_check_tag_trunc()` function can be used to
+ * compute and check the tag value.
+ *
+ * \param ctx GCM context structure.
+ * \param tag destination buffer for the tag.
+ * \param len tag length (16 bytes or less).
+ */
+void br_gcm_get_tag_trunc(br_gcm_context *ctx, void *tag, size_t len);
+
+/**
+ * \brief Compute and check GCM authentication tag (with truncation).
+ *
+ * This function is an alternative to `br_gcm_get_tag_trunc()`, normally used
+ * on the receiving end (i.e. when decrypting value). The tag value is
+ * recomputed and compared with the provided tag value. If they match, 1
+ * is returned; on mismatch, 0 is returned. A returned value of 0 means
+ * that the data or the tag was altered in transit, normally leading to
+ * wholesale rejection of the complete message.
+ *
+ * Tag length MUST be 16 bytes or less. The normal GCM tag length is 16
+ * bytes. See `br_check_tag_trunc()` for some discussion on the potential
+ * perils of truncating authentication tags.
+ *
+ * \param ctx GCM context structure.
+ * \param tag tag value to compare with.
+ * \param len tag length (in bytes).
+ * \return 1 on success (exact match of tag value), 0 otherwise.
+ */
+uint32_t br_gcm_check_tag_trunc(br_gcm_context *ctx,
+ const void *tag, size_t len);
+
+/**
+ * \brief Class instance for GCM.
+ */
+extern const br_aead_class br_gcm_vtable;
+
+/**
+ * \brief Context structure for EAX.
+ *
+ * EAX is an AEAD mode that combines a block cipher in CTR mode with
+ * CBC-MAC using the same block cipher and the same key, to provide
+ * authenticated encryption:
+ *
+ * - Any block cipher with 16-byte blocks can be used with EAX
+ * (technically, other block sizes are defined as well, but this
+ * is not implemented by these functions; shorter blocks also
+ * imply numerous security issues).
+ *
+ * - The nonce can have any length, as long as nonce values are
+ * not reused (thus, if nonces are randomly selected, the nonce
+ * size should be such that reuse probability is negligible).
+ *
+ * - Additional authenticated data length is unlimited.
+ *
+ * - Message length is unlimited.
+ *
+ * - The authentication tag has length 16 bytes.
+ *
+ * The EAX initialisation function receives as parameter an
+ * _initialised_ block cipher implementation context, with the secret
+ * key already set. A pointer to that context will be kept within the
+ * EAX context structure. It is up to the caller to allocate and
+ * initialise that block cipher context.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_aead_class *vtable;
+
+#ifndef BR_DOXYGEN_IGNORE
+ const br_block_ctrcbc_class **bctx;
+ unsigned char L2[16];
+ unsigned char L4[16];
+ unsigned char nonce[16];
+ unsigned char head[16];
+ unsigned char ctr[16];
+ unsigned char cbcmac[16];
+ unsigned char buf[16];
+ size_t ptr;
+#endif
+} br_eax_context;
+
+/**
+ * \brief EAX captured state.
+ *
+ * Some internal values computed by EAX may be captured at various
+ * points, and reused for another EAX run with the same secret key,
+ * for lower per-message overhead. Captured values do not depend on
+ * the nonce.
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char st[3][16];
+#endif
+} br_eax_state;
+
+/**
+ * \brief Initialize an EAX context.
+ *
+ * A block cipher implementation, with its initialised context
+ * structure, is provided. The block cipher MUST use 16-byte blocks in
+ * CTR + CBC-MAC mode, and its secret key MUST have been already set in
+ * the provided context. The parameters are linked in the EAX context.
+ *
+ * After this function has been called, the `br_eax_reset()` function must
+ * be called, to provide the nonce for EAX computation.
+ *
+ * \param ctx EAX context structure.
+ * \param bctx block cipher context (already initialised with secret key).
+ */
+void br_eax_init(br_eax_context *ctx, const br_block_ctrcbc_class **bctx);
+
+/**
+ * \brief Capture pre-AAD state.
+ *
+ * This function precomputes key-dependent data, and stores it in the
+ * provided `st` structure. This structure should then be used with
+ * `br_eax_reset_pre_aad()`, or updated with `br_eax_get_aad_mac()`
+ * and then used with `br_eax_reset_post_aad()`.
+ *
+ * The EAX context structure is unmodified by this call.
+ *
+ * \param ctx EAX context structure.
+ * \param st recipient for captured state.
+ */
+void br_eax_capture(const br_eax_context *ctx, br_eax_state *st);
+
+/**
+ * \brief Reset an EAX context.
+ *
+ * This function resets an already initialised EAX context for a new
+ * computation run. Implementations and keys are conserved. This function
+ * can be called at any time; it cancels any ongoing EAX computation that
+ * uses the provided context structure.
+ *
+ * It is critical to EAX security that nonce values are not repeated for
+ * the same encryption key. Nonces can have arbitrary length. If nonces
+ * are randomly generated, then a nonce length of at least 128 bits (16
+ * bytes) is recommended, to make nonce reuse probability sufficiently
+ * low.
+ *
+ * \param ctx EAX context structure.
+ * \param nonce EAX nonce to use.
+ * \param len EAX nonce length (in bytes).
+ */
+void br_eax_reset(br_eax_context *ctx, const void *nonce, size_t len);
+
+/**
+ * \brief Reset an EAX context with a pre-AAD captured state.
+ *
+ * This function is an alternative to `br_eax_reset()`, that reuses a
+ * previously captured state structure for lower per-message overhead.
+ * The state should have been populated with `br_eax_capture_state()`
+ * but not updated with `br_eax_get_aad_mac()`.
+ *
+ * After this function is called, additional authenticated data MUST
+ * be injected. At least one byte of additional authenticated data
+ * MUST be provided with `br_eax_aad_inject()`; computation result will
+ * be incorrect if `br_eax_flip()` is called right away.
+ *
+ * After injection of the AAD and call to `br_eax_flip()`, at least
+ * one message byte must be provided. Empty messages are not supported
+ * with this reset mode.
+ *
+ * \param ctx EAX context structure.
+ * \param st pre-AAD captured state.
+ * \param nonce EAX nonce to use.
+ * \param len EAX nonce length (in bytes).
+ */
+void br_eax_reset_pre_aad(br_eax_context *ctx, const br_eax_state *st,
+ const void *nonce, size_t len);
+
+/**
+ * \brief Reset an EAX context with a post-AAD captured state.
+ *
+ * This function is an alternative to `br_eax_reset()`, that reuses a
+ * previously captured state structure for lower per-message overhead.
+ * The state should have been populated with `br_eax_capture_state()`
+ * and then updated with `br_eax_get_aad_mac()`.
+ *
+ * After this function is called, message data MUST be injected. The
+ * `br_eax_flip()` function MUST NOT be called. At least one byte of
+ * message data MUST be provided with `br_eax_run()`; empty messages
+ * are not supported with this reset mode.
+ *
+ * \param ctx EAX context structure.
+ * \param st post-AAD captured state.
+ * \param nonce EAX nonce to use.
+ * \param len EAX nonce length (in bytes).
+ */
+void br_eax_reset_post_aad(br_eax_context *ctx, const br_eax_state *st,
+ const void *nonce, size_t len);
+
+/**
+ * \brief Inject additional authenticated data into EAX.
+ *
+ * The provided data is injected into a running EAX computation. Additional
+ * data must be injected _before_ the call to `br_eax_flip()`.
+ * Additional data can be injected in several chunks of arbitrary length;
+ * the total amount of additional authenticated data is unlimited.
+ *
+ * \param ctx EAX context structure.
+ * \param data pointer to additional authenticated data.
+ * \param len length of additional authenticated data (in bytes).
+ */
+void br_eax_aad_inject(br_eax_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Finish injection of additional authenticated data into EAX.
+ *
+ * This function MUST be called before beginning the actual encryption
+ * or decryption (with `br_eax_run()`), even if no additional authenticated
+ * data was injected. No additional authenticated data may be injected
+ * after this function call.
+ *
+ * \param ctx EAX context structure.
+ */
+void br_eax_flip(br_eax_context *ctx);
+
+/**
+ * \brief Obtain a copy of the MAC on additional authenticated data.
+ *
+ * This function may be called only after `br_eax_flip()`; it copies the
+ * AAD-specific MAC value into the provided state. The MAC value depends
+ * on the secret key and the additional data itself, but not on the
+ * nonce. The updated state `st` is meant to be used as parameter for a
+ * further `br_eax_reset_post_aad()` call.
+ *
+ * \param ctx EAX context structure.
+ * \param st captured state to update.
+ */
+static inline void
+br_eax_get_aad_mac(const br_eax_context *ctx, br_eax_state *st)
+{
+ memcpy(st->st[1], ctx->head, sizeof ctx->head);
+}
+
+/**
+ * \brief Encrypt or decrypt some data with EAX.
+ *
+ * Data encryption or decryption can be done after `br_eax_flip()`
+ * has been called on the context. If `encrypt` is non-zero, then the
+ * provided data shall be plaintext, and it is encrypted in place.
+ * Otherwise, the data shall be ciphertext, and it is decrypted in place.
+ *
+ * Data may be provided in several chunks of arbitrary length.
+ *
+ * \param ctx EAX context structure.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ */
+void br_eax_run(br_eax_context *ctx, int encrypt, void *data, size_t len);
+
+/**
+ * \brief Compute EAX authentication tag.
+ *
+ * Compute the EAX authentication tag. The tag is a 16-byte value which
+ * is written in the provided `tag` buffer. This call terminates the
+ * EAX run: no data may be processed with that EAX context afterwards,
+ * until `br_eax_reset()` is called to initiate a new EAX run.
+ *
+ * The tag value must normally be sent along with the encrypted data.
+ * When decrypting, the tag value must be recomputed and compared with
+ * the received tag: if the two tag values differ, then either the tag
+ * or the encrypted data was altered in transit. As an alternative to
+ * this function, the `br_eax_check_tag()` function can be used to
+ * compute and check the tag value.
+ *
+ * \param ctx EAX context structure.
+ * \param tag destination buffer for the tag (16 bytes).
+ */
+void br_eax_get_tag(br_eax_context *ctx, void *tag);
+
+/**
+ * \brief Compute and check EAX authentication tag.
+ *
+ * This function is an alternative to `br_eax_get_tag()`, normally used
+ * on the receiving end (i.e. when decrypting value). The tag value is
+ * recomputed and compared with the provided tag value. If they match, 1
+ * is returned; on mismatch, 0 is returned. A returned value of 0 means
+ * that the data or the tag was altered in transit, normally leading to
+ * wholesale rejection of the complete message.
+ *
+ * \param ctx EAX context structure.
+ * \param tag tag value to compare with (16 bytes).
+ * \return 1 on success (exact match of tag value), 0 otherwise.
+ */
+uint32_t br_eax_check_tag(br_eax_context *ctx, const void *tag);
+
+/**
+ * \brief Compute EAX authentication tag (with truncation).
+ *
+ * This function is similar to `br_eax_get_tag()`, except that it allows
+ * the tag to be truncated to a smaller length. The intended tag length
+ * is provided as `len` (in bytes); it MUST be no more than 16, but
+ * it may be smaller. Note that decreasing tag length mechanically makes
+ * forgeries easier; NIST SP 800-38D specifies that the tag length shall
+ * lie between 12 and 16 bytes (inclusive), but may be truncated down to
+ * 4 or 8 bytes, for specific applications that can tolerate it. It must
+ * also be noted that successful forgeries leak information on the
+ * authentication key, making subsequent forgeries easier. Therefore,
+ * tag truncation, and in particular truncation to sizes lower than 12
+ * bytes, shall be envisioned only with great care.
+ *
+ * The tag is written in the provided `tag` buffer. This call terminates
+ * the EAX run: no data may be processed with that EAX context
+ * afterwards, until `br_eax_reset()` is called to initiate a new EAX
+ * run.
+ *
+ * The tag value must normally be sent along with the encrypted data.
+ * When decrypting, the tag value must be recomputed and compared with
+ * the received tag: if the two tag values differ, then either the tag
+ * or the encrypted data was altered in transit. As an alternative to
+ * this function, the `br_eax_check_tag_trunc()` function can be used to
+ * compute and check the tag value.
+ *
+ * \param ctx EAX context structure.
+ * \param tag destination buffer for the tag.
+ * \param len tag length (16 bytes or less).
+ */
+void br_eax_get_tag_trunc(br_eax_context *ctx, void *tag, size_t len);
+
+/**
+ * \brief Compute and check EAX authentication tag (with truncation).
+ *
+ * This function is an alternative to `br_eax_get_tag_trunc()`, normally used
+ * on the receiving end (i.e. when decrypting value). The tag value is
+ * recomputed and compared with the provided tag value. If they match, 1
+ * is returned; on mismatch, 0 is returned. A returned value of 0 means
+ * that the data or the tag was altered in transit, normally leading to
+ * wholesale rejection of the complete message.
+ *
+ * Tag length MUST be 16 bytes or less. The normal EAX tag length is 16
+ * bytes. See `br_check_tag_trunc()` for some discussion on the potential
+ * perils of truncating authentication tags.
+ *
+ * \param ctx EAX context structure.
+ * \param tag tag value to compare with.
+ * \param len tag length (in bytes).
+ * \return 1 on success (exact match of tag value), 0 otherwise.
+ */
+uint32_t br_eax_check_tag_trunc(br_eax_context *ctx,
+ const void *tag, size_t len);
+
+/**
+ * \brief Class instance for EAX.
+ */
+extern const br_aead_class br_eax_vtable;
+
+/**
+ * \brief Context structure for CCM.
+ *
+ * CCM is an AEAD mode that combines a block cipher in CTR mode with
+ * CBC-MAC using the same block cipher and the same key, to provide
+ * authenticated encryption:
+ *
+ * - Any block cipher with 16-byte blocks can be used with CCM
+ * (technically, other block sizes are defined as well, but this
+ * is not implemented by these functions; shorter blocks also
+ * imply numerous security issues).
+ *
+ * - The authentication tag length, and plaintext length, MUST be
+ * known when starting processing data. Plaintext and ciphertext
+ * can still be provided by chunks, but the total size must match
+ * the value provided upon initialisation.
+ *
+ * - The nonce length is constrained between 7 and 13 bytes (inclusive).
+ * Furthermore, the plaintext length, when encoded, must fit over
+ * 15-nonceLen bytes; thus, if the nonce has length 13 bytes, then
+ * the plaintext length cannot exceed 65535 bytes.
+ *
+ * - Additional authenticated data length is practically unlimited
+ * (formal limit is at 2^64 bytes).
+ *
+ * - The authentication tag has length 4 to 16 bytes (even values only).
+ *
+ * The CCM initialisation function receives as parameter an
+ * _initialised_ block cipher implementation context, with the secret
+ * key already set. A pointer to that context will be kept within the
+ * CCM context structure. It is up to the caller to allocate and
+ * initialise that block cipher context.
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ const br_block_ctrcbc_class **bctx;
+ unsigned char ctr[16];
+ unsigned char cbcmac[16];
+ unsigned char tagmask[16];
+ unsigned char buf[16];
+ size_t ptr;
+ size_t tag_len;
+#endif
+} br_ccm_context;
+
+/**
+ * \brief Initialize a CCM context.
+ *
+ * A block cipher implementation, with its initialised context
+ * structure, is provided. The block cipher MUST use 16-byte blocks in
+ * CTR + CBC-MAC mode, and its secret key MUST have been already set in
+ * the provided context. The parameters are linked in the CCM context.
+ *
+ * After this function has been called, the `br_ccm_reset()` function must
+ * be called, to provide the nonce for CCM computation.
+ *
+ * \param ctx CCM context structure.
+ * \param bctx block cipher context (already initialised with secret key).
+ */
+void br_ccm_init(br_ccm_context *ctx, const br_block_ctrcbc_class **bctx);
+
+/**
+ * \brief Reset a CCM context.
+ *
+ * This function resets an already initialised CCM context for a new
+ * computation run. Implementations and keys are conserved. This function
+ * can be called at any time; it cancels any ongoing CCM computation that
+ * uses the provided context structure.
+ *
+ * The `aad_len` parameter contains the total length, in bytes, of the
+ * additional authenticated data. It may be zero. That length MUST be
+ * exact.
+ *
+ * The `data_len` parameter contains the total length, in bytes, of the
+ * data that will be injected (plaintext or ciphertext). That length MUST
+ * be exact. Moreover, that length MUST be less than 2^(8*(15-nonce_len)).
+ *
+ * The nonce length (`nonce_len`), in bytes, must be in the 7..13 range
+ * (inclusive).
+ *
+ * The tag length (`tag_len`), in bytes, must be in the 4..16 range, and
+ * be an even integer. Short tags mechanically allow for higher forgery
+ * probabilities; hence, tag sizes smaller than 12 bytes shall be used only
+ * with care.
+ *
+ * It is critical to CCM security that nonce values are not repeated for
+ * the same encryption key. Random generation of nonces is not generally
+ * recommended, due to the relatively small maximum nonce value.
+ *
+ * Returned value is 1 on success, 0 on error. An error is reported if
+ * the tag or nonce length is out of range, or if the
+ * plaintext/ciphertext length cannot be encoded with the specified
+ * nonce length.
+ *
+ * \param ctx CCM context structure.
+ * \param nonce CCM nonce to use.
+ * \param nonce_len CCM nonce length (in bytes, 7 to 13).
+ * \param aad_len additional authenticated data length (in bytes).
+ * \param data_len plaintext/ciphertext length (in bytes).
+ * \param tag_len tag length (in bytes).
+ * \return 1 on success, 0 on error.
+ */
+int br_ccm_reset(br_ccm_context *ctx, const void *nonce, size_t nonce_len,
+ uint64_t aad_len, uint64_t data_len, size_t tag_len);
+
+/**
+ * \brief Inject additional authenticated data into CCM.
+ *
+ * The provided data is injected into a running CCM computation. Additional
+ * data must be injected _before_ the call to `br_ccm_flip()`.
+ * Additional data can be injected in several chunks of arbitrary length,
+ * but the total amount MUST exactly match the value which was provided
+ * to `br_ccm_reset()`.
+ *
+ * \param ctx CCM context structure.
+ * \param data pointer to additional authenticated data.
+ * \param len length of additional authenticated data (in bytes).
+ */
+void br_ccm_aad_inject(br_ccm_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Finish injection of additional authenticated data into CCM.
+ *
+ * This function MUST be called before beginning the actual encryption
+ * or decryption (with `br_ccm_run()`), even if no additional authenticated
+ * data was injected. No additional authenticated data may be injected
+ * after this function call.
+ *
+ * \param ctx CCM context structure.
+ */
+void br_ccm_flip(br_ccm_context *ctx);
+
+/**
+ * \brief Encrypt or decrypt some data with CCM.
+ *
+ * Data encryption or decryption can be done after `br_ccm_flip()`
+ * has been called on the context. If `encrypt` is non-zero, then the
+ * provided data shall be plaintext, and it is encrypted in place.
+ * Otherwise, the data shall be ciphertext, and it is decrypted in place.
+ *
+ * Data may be provided in several chunks of arbitrary length, provided
+ * that the total length exactly matches the length provided to the
+ * `br_ccm_reset()` call.
+ *
+ * \param ctx CCM context structure.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ */
+void br_ccm_run(br_ccm_context *ctx, int encrypt, void *data, size_t len);
+
+/**
+ * \brief Compute CCM authentication tag.
+ *
+ * Compute the CCM authentication tag. This call terminates the CCM
+ * run: all data must have been injected with `br_ccm_run()` (in zero,
+ * one or more successive calls). After this function has been called,
+ * no more data can br processed; a `br_ccm_reset()` call is required
+ * to start a new message.
+ *
+ * The tag length was provided upon context initialisation (last call
+ * to `br_ccm_reset()`); it is returned by this function.
+ *
+ * The tag value must normally be sent along with the encrypted data.
+ * When decrypting, the tag value must be recomputed and compared with
+ * the received tag: if the two tag values differ, then either the tag
+ * or the encrypted data was altered in transit. As an alternative to
+ * this function, the `br_ccm_check_tag()` function can be used to
+ * compute and check the tag value.
+ *
+ * \param ctx CCM context structure.
+ * \param tag destination buffer for the tag (up to 16 bytes).
+ * \return the tag length (in bytes).
+ */
+size_t br_ccm_get_tag(br_ccm_context *ctx, void *tag);
+
+/**
+ * \brief Compute and check CCM authentication tag.
+ *
+ * This function is an alternative to `br_ccm_get_tag()`, normally used
+ * on the receiving end (i.e. when decrypting value). The tag value is
+ * recomputed and compared with the provided tag value. If they match, 1
+ * is returned; on mismatch, 0 is returned. A returned value of 0 means
+ * that the data or the tag was altered in transit, normally leading to
+ * wholesale rejection of the complete message.
+ *
+ * \param ctx CCM context structure.
+ * \param tag tag value to compare with (up to 16 bytes).
+ * \return 1 on success (exact match of tag value), 0 otherwise.
+ */
+uint32_t br_ccm_check_tag(br_ccm_context *ctx, const void *tag);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/bearssl/inc/bearssl_block.h b/contrib/bearssl/inc/bearssl_block.h
new file mode 100644
index 000000000000..683a4906d061
--- /dev/null
+++ b/contrib/bearssl/inc/bearssl_block.h
@@ -0,0 +1,2618 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_block.h
+ *
+ * # Block Ciphers and Symmetric Ciphers
+ *
+ * This file documents the API for block ciphers and other symmetric
+ * ciphers.
+ *
+ *
+ * ## Procedural API
+ *
+ * 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,
+ * initialised with the encryption key.
+ *
+ * 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.
+ *
+ * - `br_xxx_ctrcbc_keys`
+ *
+ * Context structure that contains the subkeys resulting from the
+ * key expansion. These subkeys are appropriate for doing combined
+ * CTR encryption/decryption and CBC-MAC, as used in the CCM and EAX
+ * authenticated encryption modes. The structure first field is
+ * called `vtable` and points to the appropriate OOP structure.
+ *
+ * - `br_xxx_ctrcbc_init(br_xxx_ctr_keys *ctx, const void *key, size_t len)`
+ *
+ * Perform key expansion: subkeys for combined CTR
+ * encryption/decryption and CBC-MAC 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_ctrcbc_encrypt(const br_xxx_ctrcbc_keys *ctx, void *ctr, void *cbcmac, void *data, size_t len)`
+ *
+ * Perform CTR encryption of some data, and CBC-MAC. Processing is
+ * done "in place" (the output data replaces the input data). This
+ * function applies CTR encryption on the data, using a full
+ * block-size counter (i.e. for 128-bit blocks, the counter is
+ * incremented as a 128-bit value). The 'ctr' array contains the
+ * initial value for the counter (used in the first block) and it is
+ * updated with the new value after data processing. The 'cbcmac'
+ * value shall point to a block-sized value which is used as IV for
+ * CBC-MAC, computed over the encrypted data (output of CTR
+ * encryption); the resulting CBC-MAC is written over 'cbcmac' on
+ * output.
+ *
+ * The data length MUST be a multiple of the block size.
+ *
+ * - `br_xxx_ctrcbc_decrypt(const br_xxx_ctrcbc_keys *ctx, void *ctr, void *cbcmac, void *data, size_t len)`
+ *
+ * Perform CTR decryption of some data, and CBC-MAC. Processing is
+ * done "in place" (the output data replaces the input data). This
+ * function applies CTR decryption on the data, using a full
+ * block-size counter (i.e. for 128-bit blocks, the counter is
+ * incremented as a 128-bit value). The 'ctr' array contains the
+ * initial value for the counter (used in the first block) and it is
+ * updated with the new value after data processing. The 'cbcmac'
+ * value shall point to a block-sized value which is used as IV for
+ * CBC-MAC, computed over the encrypted data (input of CTR
+ * encryption); the resulting CBC-MAC is written over 'cbcmac' on
+ * output.
+ *
+ * The data length MUST be a multiple of the block size.
+ *
+ * - `br_xxx_ctrcbc_ctr(const br_xxx_ctrcbc_keys *ctx, void *ctr, void *data, size_t len)`
+ *
+ * Perform CTR encryption or decryption of the provided data. The
+ * data is processed "in place" (the output data replaces the input
+ * data). A full block-sized counter is applied (i.e. for 128-bit
+ * blocks, the counter is incremented as a 128-bit value). The 'ctr'
+ * array contains the initial value for the counter (used in the
+ * first block), and it is updated with the new value after data
+ * processing.
+ *
+ * The data length MUST be a multiple of the block size.
+ *
+ * - `br_xxx_ctrcbc_mac(const br_xxx_ctrcbc_keys *ctx, void *cbcmac, const void *data, size_t len)`
+ *
+ * Compute CBC-MAC over the provided data. The IV for CBC-MAC is
+ * provided as 'cbcmac'; the output is written over the same array.
+ * The data itself is untouched. The data length MUST be 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`
+ *
+ * The size (in bytes) of the context structure for subkeys.
+ *
+ * - `block_size`
+ *
+ * The cipher block size (in bytes).
+ *
+ * - `log_block_size`
+ *
+ * The base-2 logarithm of cipher block size (e.g. 4 for blocks
+ * of 16 bytes).
+ *
+ * - `init`
+ *
+ * Pointer to the key expansion function.
+ *
+ * - `run`
+ *
+ * Pointer to the encryption/decryption function.
+ *
+ * For combined CTR/CBC-MAC encryption, the `vtable` has a slightly
+ * different structure:
+ *
+ * - `context_size`
+ *
+ * The size (in bytes) of the context structure for subkeys.
+ *
+ * - `block_size`
+ *
+ * The cipher block size (in bytes).
+ *
+ * - `log_block_size`
+ *
+ * The base-2 logarithm of cipher block size (e.g. 4 for blocks
+ * of 16 bytes).
+ *
+ * - `init`
+ *
+ * Pointer to the key expansion function.
+ *
+ * - `encrypt`
+ *
+ * Pointer to the CTR encryption + CBC-MAC function.
+ *
+ * - `decrypt`
+ *
+ * Pointer to the CTR decryption + CBC-MAC function.
+ *
+ * - `ctr`
+ *
+ * Pointer to the CTR encryption/decryption function.
+ *
+ * - `mac`
+ *
+ * Pointer to the CBC-MAC function.
+ *
+ * For block cipher "`xxx`", static, constant instances of these
+ * structures are defined, under the names:
+ *
+ * - `br_xxx_cbcenc_vtable`
+ * - `br_xxx_cbcdec_vtable`
+ * - `br_xxx_ctr_vtable`
+ * - `br_xxx_ctrcbc_vtable`
+ *
+ *
+ * ## Implemented Block Ciphers
+ *
+ * Provided implementations are:
+ *
+ * | Name | Function | Block Size (bytes) | Key lengths (bytes) |
+ * | :-------- | :------- | :----------------: | :-----------------: |
+ * | aes_big | AES | 16 | 16, 24 and 32 |
+ * | aes_small | AES | 16 | 16, 24 and 32 |
+ * | aes_ct | AES | 16 | 16, 24 and 32 |
+ * | aes_ct64 | AES | 16 | 16, 24 and 32 |
+ * | aes_x86ni | AES | 16 | 16, 24 and 32 |
+ * | aes_pwr8 | AES | 16 | 16, 24 and 32 |
+ * | des_ct | DES/3DES | 8 | 8, 16 and 24 |
+ * | des_tab | DES/3DES | 8 | 8, 16 and 24 |
+ *
+ * **Note:** DES/3DES nominally uses keys of 64, 128 and 192 bits (i.e. 8,
+ * 16 and 24 bytes), but some of the bits are ignored by the algorithm, so
+ * the _effective_ key lengths, from a security point of view, are 56,
+ * 112 and 168 bits, respectively.
+ *
+ * `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. On 32-bit machines,
+ * `aes_ct64` is not faster than `aes_ct`, often a bit slower, and has
+ * a larger footprint; however, on 64-bit architectures, `aes_ct64`
+ * is typically twice faster than `aes_ct` for modes that allow parallel
+ * operations (i.e. CTR, and CBC decryption, but not CBC encryption).
+ *
+ * `aes_x86ni` exists only on x86 architectures (32-bit and 64-bit). It
+ * uses the AES-NI opcodes when available.
+ *
+ * `aes_pwr8` exists only on PowerPC / POWER architectures (32-bit and
+ * 64-bit, both little-endian and big-endian). It uses the AES opcodes
+ * present in POWER8 and later.
+ *
+ * `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`.
+ *
+ * ## ChaCha20 and Poly1305
+ *
+ * ChaCha20 is a stream cipher. Poly1305 is a MAC algorithm. They
+ * are described in [RFC 7539](https://tools.ietf.org/html/rfc7539).
+ *
+ * Two function pointer types are defined:
+ *
+ * - `br_chacha20_run` describes a function that implements ChaCha20
+ * only.
+ *
+ * - `br_poly1305_run` describes an implementation of Poly1305,
+ * in the AEAD combination with ChaCha20 specified in RFC 7539
+ * (the ChaCha20 implementation is provided as a function pointer).
+ *
+ * `chacha20_ct` is a straightforward implementation of ChaCha20 in
+ * plain C; it is constant-time, small, and reasonably fast.
+ *
+ * `chacha20_sse2` leverages SSE2 opcodes (on x86 architectures that
+ * support these opcodes). It is faster than `chacha20_ct`.
+ *
+ * `poly1305_ctmul` is an implementation of the ChaCha20+Poly1305 AEAD
+ * construction, where the Poly1305 part is performed with mixed 32-bit
+ * multiplications (operands are 32-bit, result is 64-bit).
+ *
+ * `poly1305_ctmul32` implements ChaCha20+Poly1305 using pure 32-bit
+ * multiplications (32-bit operands, 32-bit result). It is slower than
+ * `poly1305_ctmul`, except on some specific architectures such as
+ * the ARM Cortex M0+.
+ *
+ * `poly1305_ctmulq` implements ChaCha20+Poly1305 with mixed 64-bit
+ * multiplications (operands are 64-bit, result is 128-bit) on 64-bit
+ * platforms that support such operations.
+ *
+ * `poly1305_i15` implements ChaCha20+Poly1305 with the generic "i15"
+ * big integer implementation. It is meant mostly for testing purposes,
+ * although it can help with saving a few hundred bytes of code footprint
+ * on systems where code size is scarce.
+ */
+
+/**
+ * \brief Class type for CBC encryption implementations.
+ *
+ * A `br_block_cbcenc_class` instance points to the functions implementing
+ * a specific block cipher, when used in CBC mode for encrypting data.
+ */
+typedef struct br_block_cbcenc_class_ br_block_cbcenc_class;
+struct br_block_cbcenc_class_ {
+ /**
+ * \brief Size (in bytes) of the context structure appropriate
+ * for containing subkeys.
+ */
+ size_t context_size;
+
+ /**
+ * \brief Size of individual blocks (in bytes).
+ */
+ unsigned block_size;
+
+ /**
+ * \brief Base-2 logarithm of the size of individual blocks,
+ * expressed in bytes.
+ */
+ unsigned log_block_size;
+
+ /**
+ * \brief Initialisation function.
+ *
+ * This function sets the `vtable` field in the context structure.
+ * The key length MUST be one of the key lengths supported by
+ * the implementation.
+ *
+ * \param ctx context structure to initialise.
+ * \param key secret key.
+ * \param key_len key length (in bytes).
+ */
+ void (*init)(const br_block_cbcenc_class **ctx,
+ const void *key, size_t key_len);
+
+ /**
+ * \brief Run the CBC encryption.
+ *
+ * The `iv` parameter points to the IV for this run; it is
+ * updated with a copy of the last encrypted block. The data
+ * is encrypted "in place"; its length (`len`) MUST be a
+ * multiple of the block size.
+ *
+ * \param ctx context structure (already initialised).
+ * \param iv IV for CBC encryption (updated).
+ * \param data data to encrypt.
+ * \param len data length (in bytes, multiple of block size).
+ */
+ void (*run)(const br_block_cbcenc_class *const *ctx,
+ void *iv, void *data, size_t len);
+};
+
+/**
+ * \brief Class type for CBC decryption implementations.
+ *
+ * A `br_block_cbcdec_class` instance points to the functions implementing
+ * a specific block cipher, when used in CBC mode for decrypting data.
+ */
+typedef struct br_block_cbcdec_class_ br_block_cbcdec_class;
+struct br_block_cbcdec_class_ {
+ /**
+ * \brief Size (in bytes) of the context structure appropriate
+ * for containing subkeys.
+ */
+ size_t context_size;
+
+ /**
+ * \brief Size of individual blocks (in bytes).
+ */
+ unsigned block_size;
+
+ /**
+ * \brief Base-2 logarithm of the size of individual blocks,
+ * expressed in bytes.
+ */
+ unsigned log_block_size;
+
+ /**
+ * \brief Initialisation function.
+ *
+ * This function sets the `vtable` field in the context structure.
+ * The key length MUST be one of the key lengths supported by
+ * the implementation.
+ *
+ * \param ctx context structure to initialise.
+ * \param key secret key.
+ * \param key_len key length (in bytes).
+ */
+ void (*init)(const br_block_cbcdec_class **ctx,
+ const void *key, size_t key_len);
+
+ /**
+ * \brief Run the CBC decryption.
+ *
+ * The `iv` parameter points to the IV for this run; it is
+ * updated with a copy of the last encrypted block. The data
+ * is decrypted "in place"; its length (`len`) MUST be a
+ * multiple of the block size.
+ *
+ * \param ctx context structure (already initialised).
+ * \param iv IV for CBC decryption (updated).
+ * \param data data to decrypt.
+ * \param len data length (in bytes, multiple of block size).
+ */
+ void (*run)(const br_block_cbcdec_class *const *ctx,
+ void *iv, void *data, size_t len);
+};
+
+/**
+ * \brief Class type for CTR encryption/decryption implementations.
+ *
+ * A `br_block_ctr_class` instance points to the functions implementing
+ * a specific block cipher, when used in CTR mode for encrypting or
+ * decrypting data.
+ */
+typedef struct br_block_ctr_class_ br_block_ctr_class;
+struct br_block_ctr_class_ {
+ /**
+ * \brief Size (in bytes) of the context structure appropriate
+ * for containing subkeys.
+ */
+ size_t context_size;
+
+ /**
+ * \brief Size of individual blocks (in bytes).
+ */
+ unsigned block_size;
+
+ /**
+ * \brief Base-2 logarithm of the size of individual blocks,
+ * expressed in bytes.
+ */
+ unsigned log_block_size;
+
+ /**
+ * \brief Initialisation function.
+ *
+ * This function sets the `vtable` field in the context structure.
+ * The key length MUST be one of the key lengths supported by
+ * the implementation.
+ *
+ * \param ctx context structure to initialise.
+ * \param key secret key.
+ * \param key_len key length (in bytes).
+ */
+ void (*init)(const br_block_ctr_class **ctx,
+ const void *key, size_t key_len);
+
+ /**
+ * \brief Run the CTR encryption or decryption.
+ *
+ * The `iv` parameter points to the IV for this run; its
+ * length is exactly 4 bytes less than the block size (e.g.
+ * 12 bytes for AES/CTR). The IV is combined with a 32-bit
+ * block counter to produce the block value which is processed
+ * with the block cipher.
+ *
+ * The data to encrypt or decrypt is updated "in place". Its
+ * length (`len` bytes) is not required to be a multiple of
+ * the block size; if the final block is partial, then the
+ * corresponding key stream bits are dropped.
+ *
+ * The resulting counter value is returned.
+ *
+ * \param ctx context structure (already initialised).
+ * \param iv IV for CTR encryption/decryption.
+ * \param cc initial value for the block counter.
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ * \return the new block counter value.
+ */
+ uint32_t (*run)(const br_block_ctr_class *const *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len);
+};
+
+/**
+ * \brief Class type for combined CTR and CBC-MAC implementations.
+ *
+ * A `br_block_ctrcbc_class` instance points to the functions implementing
+ * a specific block cipher, when used in CTR mode for encrypting or
+ * decrypting data, along with CBC-MAC.
+ */
+typedef struct br_block_ctrcbc_class_ br_block_ctrcbc_class;
+struct br_block_ctrcbc_class_ {
+ /**
+ * \brief Size (in bytes) of the context structure appropriate
+ * for containing subkeys.
+ */
+ size_t context_size;
+
+ /**
+ * \brief Size of individual blocks (in bytes).
+ */
+ unsigned block_size;
+
+ /**
+ * \brief Base-2 logarithm of the size of individual blocks,
+ * expressed in bytes.
+ */
+ unsigned log_block_size;
+
+ /**
+ * \brief Initialisation function.
+ *
+ * This function sets the `vtable` field in the context structure.
+ * The key length MUST be one of the key lengths supported by
+ * the implementation.
+ *
+ * \param ctx context structure to initialise.
+ * \param key secret key.
+ * \param key_len key length (in bytes).
+ */
+ void (*init)(const br_block_ctrcbc_class **ctx,
+ const void *key, size_t key_len);
+
+ /**
+ * \brief Run the CTR encryption + CBC-MAC.
+ *
+ * The `ctr` parameter points to the counter; its length shall
+ * be equal to the block size. It is updated by this function
+ * as encryption proceeds.
+ *
+ * The `cbcmac` parameter points to the IV for CBC-MAC. The MAC
+ * is computed over the encrypted data (output of CTR
+ * encryption). Its length shall be equal to the block size. The
+ * computed CBC-MAC value is written over the `cbcmac` array.
+ *
+ * The data to encrypt is updated "in place". Its length (`len`
+ * bytes) MUST be a multiple of the block size.
+ *
+ * \param ctx context structure (already initialised).
+ * \param ctr counter for CTR encryption (initial and final).
+ * \param cbcmac IV and output buffer for CBC-MAC.
+ * \param data data to encrypt.
+ * \param len data length (in bytes).
+ */
+ void (*encrypt)(const br_block_ctrcbc_class *const *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+ /**
+ * \brief Run the CTR decryption + CBC-MAC.
+ *
+ * The `ctr` parameter points to the counter; its length shall
+ * be equal to the block size. It is updated by this function
+ * as decryption proceeds.
+ *
+ * The `cbcmac` parameter points to the IV for CBC-MAC. The MAC
+ * is computed over the encrypted data (i.e. before CTR
+ * decryption). Its length shall be equal to the block size. The
+ * computed CBC-MAC value is written over the `cbcmac` array.
+ *
+ * The data to decrypt is updated "in place". Its length (`len`
+ * bytes) MUST be a multiple of the block size.
+ *
+ * \param ctx context structure (already initialised).
+ * \param ctr counter for CTR encryption (initial and final).
+ * \param cbcmac IV and output buffer for CBC-MAC.
+ * \param data data to decrypt.
+ * \param len data length (in bytes).
+ */
+ void (*decrypt)(const br_block_ctrcbc_class *const *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+ /**
+ * \brief Run the CTR encryption/decryption only.
+ *
+ * The `ctr` parameter points to the counter; its length shall
+ * be equal to the block size. It is updated by this function
+ * as decryption proceeds.
+ *
+ * The data to decrypt is updated "in place". Its length (`len`
+ * bytes) MUST be a multiple of the block size.
+ *
+ * \param ctx context structure (already initialised).
+ * \param ctr counter for CTR encryption (initial and final).
+ * \param data data to decrypt.
+ * \param len data length (in bytes).
+ */
+ void (*ctr)(const br_block_ctrcbc_class *const *ctx,
+ void *ctr, void *data, size_t len);
+
+ /**
+ * \brief Run the CBC-MAC only.
+ *
+ * The `cbcmac` parameter points to the IV for CBC-MAC. The MAC
+ * is computed over the encrypted data (i.e. before CTR
+ * decryption). Its length shall be equal to the block size. The
+ * computed CBC-MAC value is written over the `cbcmac` array.
+ *
+ * The data is unmodified. Its length (`len` bytes) MUST be a
+ * multiple of the block size.
+ *
+ * \param ctx context structure (already initialised).
+ * \param cbcmac IV and output buffer for CBC-MAC.
+ * \param data data to decrypt.
+ * \param len data length (in bytes).
+ */
+ void (*mac)(const br_block_ctrcbc_class *const *ctx,
+ void *cbcmac, const 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.
+ */
+
+/** \brief AES block size (16 bytes). */
+#define br_aes_big_BLOCK_SIZE 16
+
+/**
+ * \brief Context for AES subkeys (`aes_big` implementation, CBC encryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcenc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_big_cbcenc_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_big` implementation, CBC decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcdec_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_big_cbcdec_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_big` implementation, CTR encryption
+ * and decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctr_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_big_ctr_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_big` implementation, CTR encryption
+ * and decryption + CBC-MAC).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctrcbc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_big_ctrcbc_keys;
+
+/**
+ * \brief Class instance for AES CBC encryption (`aes_big` implementation).
+ */
+extern const br_block_cbcenc_class br_aes_big_cbcenc_vtable;
+
+/**
+ * \brief Class instance for AES CBC decryption (`aes_big` implementation).
+ */
+extern const br_block_cbcdec_class br_aes_big_cbcdec_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption and decryption
+ * (`aes_big` implementation).
+ */
+extern const br_block_ctr_class br_aes_big_ctr_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption/decryption + CBC-MAC
+ * (`aes_big` implementation).
+ */
+extern const br_block_ctrcbc_class br_aes_big_ctrcbc_vtable;
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC encryption
+ * (`aes_big` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_big_cbcenc_init(br_aes_big_cbcenc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC decryption
+ * (`aes_big` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_big_cbcdec_init(br_aes_big_cbcdec_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR encryption
+ * and decryption (`aes_big` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_big_ctr_init(br_aes_big_ctr_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC
+ * (`aes_big` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_big_ctrcbc_init(br_aes_big_ctrcbc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief CBC encryption with AES (`aes_big` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_big_cbcenc_run(const br_aes_big_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CBC decryption with AES (`aes_big` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_big_cbcdec_run(const br_aes_big_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CTR encryption and decryption with AES (`aes_big` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (constant, 12 bytes).
+ * \param cc initial block counter value.
+ * \param data data to encrypt or decrypt (updated).
+ * \param len data length (in bytes).
+ * \return new block counter value.
+ */
+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);
+
+/**
+ * \brief CTR encryption + CBC-MAC with AES (`aes_big` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_big_ctrcbc_encrypt(const br_aes_big_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR decryption + CBC-MAC with AES (`aes_big` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_big_ctrcbc_decrypt(const br_aes_big_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR encryption/decryption with AES (`aes_big` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param data data to MAC (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_big_ctrcbc_ctr(const br_aes_big_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len);
+
+/**
+ * \brief CBC-MAC with AES (`aes_big` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to MAC (unmodified).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_big_ctrcbc_mac(const br_aes_big_ctrcbc_keys *ctx,
+ void *cbcmac, const 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.
+ */
+
+/** \brief AES block size (16 bytes). */
+#define br_aes_small_BLOCK_SIZE 16
+
+/**
+ * \brief Context for AES subkeys (`aes_small` implementation, CBC encryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcenc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_small_cbcenc_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_small` implementation, CBC decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcdec_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_small_cbcdec_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_small` implementation, CTR encryption
+ * and decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctr_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_small_ctr_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_small` implementation, CTR encryption
+ * and decryption + CBC-MAC).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctrcbc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_small_ctrcbc_keys;
+
+/**
+ * \brief Class instance for AES CBC encryption (`aes_small` implementation).
+ */
+extern const br_block_cbcenc_class br_aes_small_cbcenc_vtable;
+
+/**
+ * \brief Class instance for AES CBC decryption (`aes_small` implementation).
+ */
+extern const br_block_cbcdec_class br_aes_small_cbcdec_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption and decryption
+ * (`aes_small` implementation).
+ */
+extern const br_block_ctr_class br_aes_small_ctr_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption/decryption + CBC-MAC
+ * (`aes_small` implementation).
+ */
+extern const br_block_ctrcbc_class br_aes_small_ctrcbc_vtable;
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC encryption
+ * (`aes_small` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_small_cbcenc_init(br_aes_small_cbcenc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC decryption
+ * (`aes_small` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_small_cbcdec_init(br_aes_small_cbcdec_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR encryption
+ * and decryption (`aes_small` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_small_ctr_init(br_aes_small_ctr_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC
+ * (`aes_small` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_small_ctrcbc_init(br_aes_small_ctrcbc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief CBC encryption with AES (`aes_small` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_small_cbcenc_run(const br_aes_small_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CBC decryption with AES (`aes_small` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_small_cbcdec_run(const br_aes_small_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CTR encryption and decryption with AES (`aes_small` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (constant, 12 bytes).
+ * \param cc initial block counter value.
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes).
+ * \return new block counter value.
+ */
+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);
+
+/**
+ * \brief CTR encryption + CBC-MAC with AES (`aes_small` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_small_ctrcbc_encrypt(const br_aes_small_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR decryption + CBC-MAC with AES (`aes_small` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_small_ctrcbc_decrypt(const br_aes_small_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR encryption/decryption with AES (`aes_small` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param data data to MAC (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_small_ctrcbc_ctr(const br_aes_small_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len);
+
+/**
+ * \brief CBC-MAC with AES (`aes_small` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to MAC (unmodified).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_small_ctrcbc_mac(const br_aes_small_ctrcbc_keys *ctx,
+ void *cbcmac, const 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.
+ */
+
+/** \brief AES block size (16 bytes). */
+#define br_aes_ct_BLOCK_SIZE 16
+
+/**
+ * \brief Context for AES subkeys (`aes_ct` implementation, CBC encryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcenc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_ct_cbcenc_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_ct` implementation, CBC decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcdec_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_ct_cbcdec_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_ct` implementation, CTR encryption
+ * and decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctr_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_ct_ctr_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_ct` implementation, CTR encryption
+ * and decryption + CBC-MAC).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctrcbc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[60];
+ unsigned num_rounds;
+#endif
+} br_aes_ct_ctrcbc_keys;
+
+/**
+ * \brief Class instance for AES CBC encryption (`aes_ct` implementation).
+ */
+extern const br_block_cbcenc_class br_aes_ct_cbcenc_vtable;
+
+/**
+ * \brief Class instance for AES CBC decryption (`aes_ct` implementation).
+ */
+extern const br_block_cbcdec_class br_aes_ct_cbcdec_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption and decryption
+ * (`aes_ct` implementation).
+ */
+extern const br_block_ctr_class br_aes_ct_ctr_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption/decryption + CBC-MAC
+ * (`aes_ct` implementation).
+ */
+extern const br_block_ctrcbc_class br_aes_ct_ctrcbc_vtable;
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC encryption
+ * (`aes_ct` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_ct_cbcenc_init(br_aes_ct_cbcenc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC decryption
+ * (`aes_ct` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_ct_cbcdec_init(br_aes_ct_cbcdec_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR encryption
+ * and decryption (`aes_ct` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_ct_ctr_init(br_aes_ct_ctr_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC
+ * (`aes_ct` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_ct_ctrcbc_init(br_aes_ct_ctrcbc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief CBC encryption with AES (`aes_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_ct_cbcenc_run(const br_aes_ct_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CBC decryption with AES (`aes_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_ct_cbcdec_run(const br_aes_ct_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CTR encryption and decryption with AES (`aes_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (constant, 12 bytes).
+ * \param cc initial block counter value.
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes).
+ * \return new block counter value.
+ */
+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);
+
+/**
+ * \brief CTR encryption + CBC-MAC with AES (`aes_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_ct_ctrcbc_encrypt(const br_aes_ct_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR decryption + CBC-MAC with AES (`aes_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_ct_ctrcbc_decrypt(const br_aes_ct_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR encryption/decryption with AES (`aes_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param data data to MAC (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_ct_ctrcbc_ctr(const br_aes_ct_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len);
+
+/**
+ * \brief CBC-MAC with AES (`aes_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to MAC (unmodified).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_ct_ctrcbc_mac(const br_aes_ct_ctrcbc_keys *ctx,
+ void *cbcmac, const 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.)
+ */
+
+/** \brief AES block size (16 bytes). */
+#define br_aes_ct64_BLOCK_SIZE 16
+
+/**
+ * \brief Context for AES subkeys (`aes_ct64` implementation, CBC encryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcenc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint64_t skey[30];
+ unsigned num_rounds;
+#endif
+} br_aes_ct64_cbcenc_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_ct64` implementation, CBC decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcdec_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint64_t skey[30];
+ unsigned num_rounds;
+#endif
+} br_aes_ct64_cbcdec_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_ct64` implementation, CTR encryption
+ * and decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctr_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint64_t skey[30];
+ unsigned num_rounds;
+#endif
+} br_aes_ct64_ctr_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_ct64` implementation, CTR encryption
+ * and decryption + CBC-MAC).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctrcbc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint64_t skey[30];
+ unsigned num_rounds;
+#endif
+} br_aes_ct64_ctrcbc_keys;
+
+/**
+ * \brief Class instance for AES CBC encryption (`aes_ct64` implementation).
+ */
+extern const br_block_cbcenc_class br_aes_ct64_cbcenc_vtable;
+
+/**
+ * \brief Class instance for AES CBC decryption (`aes_ct64` implementation).
+ */
+extern const br_block_cbcdec_class br_aes_ct64_cbcdec_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption and decryption
+ * (`aes_ct64` implementation).
+ */
+extern const br_block_ctr_class br_aes_ct64_ctr_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption/decryption + CBC-MAC
+ * (`aes_ct64` implementation).
+ */
+extern const br_block_ctrcbc_class br_aes_ct64_ctrcbc_vtable;
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC encryption
+ * (`aes_ct64` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_ct64_cbcenc_init(br_aes_ct64_cbcenc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC decryption
+ * (`aes_ct64` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_ct64_cbcdec_init(br_aes_ct64_cbcdec_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR encryption
+ * and decryption (`aes_ct64` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_ct64_ctr_init(br_aes_ct64_ctr_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC
+ * (`aes_ct64` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_ct64_ctrcbc_init(br_aes_ct64_ctrcbc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief CBC encryption with AES (`aes_ct64` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_ct64_cbcenc_run(const br_aes_ct64_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CBC decryption with AES (`aes_ct64` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_ct64_cbcdec_run(const br_aes_ct64_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CTR encryption and decryption with AES (`aes_ct64` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (constant, 12 bytes).
+ * \param cc initial block counter value.
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes).
+ * \return new block counter value.
+ */
+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);
+
+/**
+ * \brief CTR encryption + CBC-MAC with AES (`aes_ct64` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_ct64_ctrcbc_encrypt(const br_aes_ct64_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR decryption + CBC-MAC with AES (`aes_ct64` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_ct64_ctrcbc_decrypt(const br_aes_ct64_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR encryption/decryption with AES (`aes_ct64` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param data data to MAC (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_ct64_ctrcbc_ctr(const br_aes_ct64_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len);
+
+/**
+ * \brief CBC-MAC with AES (`aes_ct64` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to MAC (unmodified).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_ct64_ctrcbc_mac(const br_aes_ct64_ctrcbc_keys *ctx,
+ void *cbcmac, const void *data, size_t len);
+
+/*
+ * AES implementation using AES-NI opcodes (x86 platform).
+ */
+
+/** \brief AES block size (16 bytes). */
+#define br_aes_x86ni_BLOCK_SIZE 16
+
+/**
+ * \brief Context for AES subkeys (`aes_x86ni` implementation, CBC encryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcenc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ unsigned char skni[16 * 15];
+ } skey;
+ unsigned num_rounds;
+#endif
+} br_aes_x86ni_cbcenc_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_x86ni` implementation, CBC decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcdec_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ unsigned char skni[16 * 15];
+ } skey;
+ unsigned num_rounds;
+#endif
+} br_aes_x86ni_cbcdec_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_x86ni` implementation, CTR encryption
+ * and decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctr_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ unsigned char skni[16 * 15];
+ } skey;
+ unsigned num_rounds;
+#endif
+} br_aes_x86ni_ctr_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_x86ni` implementation, CTR encryption
+ * and decryption + CBC-MAC).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctrcbc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ unsigned char skni[16 * 15];
+ } skey;
+ unsigned num_rounds;
+#endif
+} br_aes_x86ni_ctrcbc_keys;
+
+/**
+ * \brief Class instance for AES CBC encryption (`aes_x86ni` implementation).
+ *
+ * Since this implementation might be omitted from the library, or the
+ * AES opcode unavailable on the current CPU, a pointer to this class
+ * instance should be obtained through `br_aes_x86ni_cbcenc_get_vtable()`.
+ */
+extern const br_block_cbcenc_class br_aes_x86ni_cbcenc_vtable;
+
+/**
+ * \brief Class instance for AES CBC decryption (`aes_x86ni` implementation).
+ *
+ * Since this implementation might be omitted from the library, or the
+ * AES opcode unavailable on the current CPU, a pointer to this class
+ * instance should be obtained through `br_aes_x86ni_cbcdec_get_vtable()`.
+ */
+extern const br_block_cbcdec_class br_aes_x86ni_cbcdec_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption and decryption
+ * (`aes_x86ni` implementation).
+ *
+ * Since this implementation might be omitted from the library, or the
+ * AES opcode unavailable on the current CPU, a pointer to this class
+ * instance should be obtained through `br_aes_x86ni_ctr_get_vtable()`.
+ */
+extern const br_block_ctr_class br_aes_x86ni_ctr_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption/decryption + CBC-MAC
+ * (`aes_x86ni` implementation).
+ *
+ * Since this implementation might be omitted from the library, or the
+ * AES opcode unavailable on the current CPU, a pointer to this class
+ * instance should be obtained through `br_aes_x86ni_ctrcbc_get_vtable()`.
+ */
+extern const br_block_ctrcbc_class br_aes_x86ni_ctrcbc_vtable;
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC encryption
+ * (`aes_x86ni` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_x86ni_cbcenc_init(br_aes_x86ni_cbcenc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC decryption
+ * (`aes_x86ni` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_x86ni_cbcdec_init(br_aes_x86ni_cbcdec_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR encryption
+ * and decryption (`aes_x86ni` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_x86ni_ctr_init(br_aes_x86ni_ctr_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC
+ * (`aes_x86ni` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_x86ni_ctrcbc_init(br_aes_x86ni_ctrcbc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief CBC encryption with AES (`aes_x86ni` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_x86ni_cbcenc_run(const br_aes_x86ni_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CBC decryption with AES (`aes_x86ni` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_x86ni_cbcdec_run(const br_aes_x86ni_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CTR encryption and decryption with AES (`aes_x86ni` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (constant, 12 bytes).
+ * \param cc initial block counter value.
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes).
+ * \return new block counter value.
+ */
+uint32_t br_aes_x86ni_ctr_run(const br_aes_x86ni_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/**
+ * \brief CTR encryption + CBC-MAC with AES (`aes_x86ni` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_x86ni_ctrcbc_encrypt(const br_aes_x86ni_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR decryption + CBC-MAC with AES (`aes_x86ni` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_x86ni_ctrcbc_decrypt(const br_aes_x86ni_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR encryption/decryption with AES (`aes_x86ni` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param data data to MAC (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_x86ni_ctrcbc_ctr(const br_aes_x86ni_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len);
+
+/**
+ * \brief CBC-MAC with AES (`aes_x86ni` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to MAC (unmodified).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_x86ni_ctrcbc_mac(const br_aes_x86ni_ctrcbc_keys *ctx,
+ void *cbcmac, const void *data, size_t len);
+
+/**
+ * \brief Obtain the `aes_x86ni` AES-CBC (encryption) implementation, if
+ * available.
+ *
+ * This function returns a pointer to `br_aes_x86ni_cbcenc_vtable`, if
+ * that implementation was compiled in the library _and_ the x86 AES
+ * opcodes are available on the currently running CPU. If either of
+ * these conditions is not met, then this function returns `NULL`.
+ *
+ * \return the `aes_x86ni` AES-CBC (encryption) implementation, or `NULL`.
+ */
+const br_block_cbcenc_class *br_aes_x86ni_cbcenc_get_vtable(void);
+
+/**
+ * \brief Obtain the `aes_x86ni` AES-CBC (decryption) implementation, if
+ * available.
+ *
+ * This function returns a pointer to `br_aes_x86ni_cbcdec_vtable`, if
+ * that implementation was compiled in the library _and_ the x86 AES
+ * opcodes are available on the currently running CPU. If either of
+ * these conditions is not met, then this function returns `NULL`.
+ *
+ * \return the `aes_x86ni` AES-CBC (decryption) implementation, or `NULL`.
+ */
+const br_block_cbcdec_class *br_aes_x86ni_cbcdec_get_vtable(void);
+
+/**
+ * \brief Obtain the `aes_x86ni` AES-CTR implementation, if available.
+ *
+ * This function returns a pointer to `br_aes_x86ni_ctr_vtable`, if
+ * that implementation was compiled in the library _and_ the x86 AES
+ * opcodes are available on the currently running CPU. If either of
+ * these conditions is not met, then this function returns `NULL`.
+ *
+ * \return the `aes_x86ni` AES-CTR implementation, or `NULL`.
+ */
+const br_block_ctr_class *br_aes_x86ni_ctr_get_vtable(void);
+
+/**
+ * \brief Obtain the `aes_x86ni` AES-CTR + CBC-MAC implementation, if
+ * available.
+ *
+ * This function returns a pointer to `br_aes_x86ni_ctrcbc_vtable`, if
+ * that implementation was compiled in the library _and_ the x86 AES
+ * opcodes are available on the currently running CPU. If either of
+ * these conditions is not met, then this function returns `NULL`.
+ *
+ * \return the `aes_x86ni` AES-CTR implementation, or `NULL`.
+ */
+const br_block_ctrcbc_class *br_aes_x86ni_ctrcbc_get_vtable(void);
+
+/*
+ * AES implementation using POWER8 opcodes.
+ */
+
+/** \brief AES block size (16 bytes). */
+#define br_aes_pwr8_BLOCK_SIZE 16
+
+/**
+ * \brief Context for AES subkeys (`aes_pwr8` implementation, CBC encryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcenc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ unsigned char skni[16 * 15];
+ } skey;
+ unsigned num_rounds;
+#endif
+} br_aes_pwr8_cbcenc_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_pwr8` implementation, CBC decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcdec_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ unsigned char skni[16 * 15];
+ } skey;
+ unsigned num_rounds;
+#endif
+} br_aes_pwr8_cbcdec_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_pwr8` implementation, CTR encryption
+ * and decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctr_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ unsigned char skni[16 * 15];
+ } skey;
+ unsigned num_rounds;
+#endif
+} br_aes_pwr8_ctr_keys;
+
+/**
+ * \brief Context for AES subkeys (`aes_pwr8` implementation, CTR encryption
+ * and decryption + CBC-MAC).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_ctrcbc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ unsigned char skni[16 * 15];
+ } skey;
+ unsigned num_rounds;
+#endif
+} br_aes_pwr8_ctrcbc_keys;
+
+/**
+ * \brief Class instance for AES CBC encryption (`aes_pwr8` implementation).
+ *
+ * Since this implementation might be omitted from the library, or the
+ * AES opcode unavailable on the current CPU, a pointer to this class
+ * instance should be obtained through `br_aes_pwr8_cbcenc_get_vtable()`.
+ */
+extern const br_block_cbcenc_class br_aes_pwr8_cbcenc_vtable;
+
+/**
+ * \brief Class instance for AES CBC decryption (`aes_pwr8` implementation).
+ *
+ * Since this implementation might be omitted from the library, or the
+ * AES opcode unavailable on the current CPU, a pointer to this class
+ * instance should be obtained through `br_aes_pwr8_cbcdec_get_vtable()`.
+ */
+extern const br_block_cbcdec_class br_aes_pwr8_cbcdec_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption and decryption
+ * (`aes_pwr8` implementation).
+ *
+ * Since this implementation might be omitted from the library, or the
+ * AES opcode unavailable on the current CPU, a pointer to this class
+ * instance should be obtained through `br_aes_pwr8_ctr_get_vtable()`.
+ */
+extern const br_block_ctr_class br_aes_pwr8_ctr_vtable;
+
+/**
+ * \brief Class instance for AES CTR encryption/decryption + CBC-MAC
+ * (`aes_pwr8` implementation).
+ *
+ * Since this implementation might be omitted from the library, or the
+ * AES opcode unavailable on the current CPU, a pointer to this class
+ * instance should be obtained through `br_aes_pwr8_ctrcbc_get_vtable()`.
+ */
+extern const br_block_ctrcbc_class br_aes_pwr8_ctrcbc_vtable;
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC encryption
+ * (`aes_pwr8` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_pwr8_cbcenc_init(br_aes_pwr8_cbcenc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CBC decryption
+ * (`aes_pwr8` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_pwr8_cbcdec_init(br_aes_pwr8_cbcdec_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR encryption
+ * and decryption (`aes_pwr8` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_pwr8_ctr_init(br_aes_pwr8_ctr_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for AES CTR + CBC-MAC
+ * (`aes_pwr8` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_aes_pwr8_ctrcbc_init(br_aes_pwr8_ctrcbc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief CBC encryption with AES (`aes_pwr8` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_pwr8_cbcenc_run(const br_aes_pwr8_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CBC decryption with AES (`aes_pwr8` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 16).
+ */
+void br_aes_pwr8_cbcdec_run(const br_aes_pwr8_cbcdec_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CTR encryption and decryption with AES (`aes_pwr8` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (constant, 12 bytes).
+ * \param cc initial block counter value.
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes).
+ * \return new block counter value.
+ */
+uint32_t br_aes_pwr8_ctr_run(const br_aes_pwr8_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/**
+ * \brief CTR encryption + CBC-MAC with AES (`aes_pwr8` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_pwr8_ctrcbc_encrypt(const br_aes_pwr8_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR decryption + CBC-MAC with AES (`aes_pwr8` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_pwr8_ctrcbc_decrypt(const br_aes_pwr8_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len);
+
+/**
+ * \brief CTR encryption/decryption with AES (`aes_pwr8` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param ctr counter for CTR (16 bytes, updated).
+ * \param data data to MAC (updated).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_pwr8_ctrcbc_ctr(const br_aes_pwr8_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len);
+
+/**
+ * \brief CBC-MAC with AES (`aes_pwr8` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param cbcmac IV for CBC-MAC (updated).
+ * \param data data to MAC (unmodified).
+ * \param len data length (in bytes, MUST be a multiple of 16).
+ */
+void br_aes_pwr8_ctrcbc_mac(const br_aes_pwr8_ctrcbc_keys *ctx,
+ void *cbcmac, const void *data, size_t len);
+
+/**
+ * \brief Obtain the `aes_pwr8` AES-CBC (encryption) implementation, if
+ * available.
+ *
+ * This function returns a pointer to `br_aes_pwr8_cbcenc_vtable`, if
+ * that implementation was compiled in the library _and_ the POWER8
+ * crypto opcodes are available on the currently running CPU. If either
+ * of these conditions is not met, then this function returns `NULL`.
+ *
+ * \return the `aes_pwr8` AES-CBC (encryption) implementation, or `NULL`.
+ */
+const br_block_cbcenc_class *br_aes_pwr8_cbcenc_get_vtable(void);
+
+/**
+ * \brief Obtain the `aes_pwr8` AES-CBC (decryption) implementation, if
+ * available.
+ *
+ * This function returns a pointer to `br_aes_pwr8_cbcdec_vtable`, if
+ * that implementation was compiled in the library _and_ the POWER8
+ * crypto opcodes are available on the currently running CPU. If either
+ * of these conditions is not met, then this function returns `NULL`.
+ *
+ * \return the `aes_pwr8` AES-CBC (decryption) implementation, or `NULL`.
+ */
+const br_block_cbcdec_class *br_aes_pwr8_cbcdec_get_vtable(void);
+
+/**
+ * \brief Obtain the `aes_pwr8` AES-CTR implementation, if available.
+ *
+ * This function returns a pointer to `br_aes_pwr8_ctr_vtable`, if that
+ * implementation was compiled in the library _and_ the POWER8 crypto
+ * opcodes are available on the currently running CPU. If either of
+ * these conditions is not met, then this function returns `NULL`.
+ *
+ * \return the `aes_pwr8` AES-CTR implementation, or `NULL`.
+ */
+const br_block_ctr_class *br_aes_pwr8_ctr_get_vtable(void);
+
+/**
+ * \brief Obtain the `aes_pwr8` AES-CTR + CBC-MAC implementation, if
+ * available.
+ *
+ * This function returns a pointer to `br_aes_pwr8_ctrcbc_vtable`, if
+ * that implementation was compiled in the library _and_ the POWER8 AES
+ * opcodes are available on the currently running CPU. If either of
+ * these conditions is not met, then this function returns `NULL`.
+ *
+ * \return the `aes_pwr8` AES-CTR implementation, or `NULL`.
+ */
+const br_block_ctrcbc_class *br_aes_pwr8_ctrcbc_get_vtable(void);
+
+/**
+ * \brief Aggregate structure large enough to be used as context for
+ * subkeys (CBC encryption) for all AES implementations.
+ */
+typedef union {
+ const br_block_cbcenc_class *vtable;
+ br_aes_big_cbcenc_keys c_big;
+ br_aes_small_cbcenc_keys c_small;
+ br_aes_ct_cbcenc_keys c_ct;
+ br_aes_ct64_cbcenc_keys c_ct64;
+ br_aes_x86ni_cbcenc_keys c_x86ni;
+ br_aes_pwr8_cbcenc_keys c_pwr8;
+} br_aes_gen_cbcenc_keys;
+
+/**
+ * \brief Aggregate structure large enough to be used as context for
+ * subkeys (CBC decryption) for all AES implementations.
+ */
+typedef union {
+ const br_block_cbcdec_class *vtable;
+ br_aes_big_cbcdec_keys c_big;
+ br_aes_small_cbcdec_keys c_small;
+ br_aes_ct_cbcdec_keys c_ct;
+ br_aes_ct64_cbcdec_keys c_ct64;
+ br_aes_x86ni_cbcdec_keys c_x86ni;
+ br_aes_pwr8_cbcdec_keys c_pwr8;
+} br_aes_gen_cbcdec_keys;
+
+/**
+ * \brief Aggregate structure large enough to be used as context for
+ * subkeys (CTR encryption and decryption) for all AES implementations.
+ */
+typedef union {
+ const br_block_ctr_class *vtable;
+ br_aes_big_ctr_keys c_big;
+ br_aes_small_ctr_keys c_small;
+ br_aes_ct_ctr_keys c_ct;
+ br_aes_ct64_ctr_keys c_ct64;
+ br_aes_x86ni_ctr_keys c_x86ni;
+ br_aes_pwr8_ctr_keys c_pwr8;
+} br_aes_gen_ctr_keys;
+
+/**
+ * \brief Aggregate structure large enough to be used as context for
+ * subkeys (CTR encryption/decryption + CBC-MAC) for all AES implementations.
+ */
+typedef union {
+ const br_block_ctrcbc_class *vtable;
+ br_aes_big_ctrcbc_keys c_big;
+ br_aes_small_ctrcbc_keys c_small;
+ br_aes_ct_ctrcbc_keys c_ct;
+ br_aes_ct64_ctrcbc_keys c_ct64;
+ br_aes_x86ni_ctrcbc_keys c_x86ni;
+ br_aes_pwr8_ctrcbc_keys c_pwr8;
+} br_aes_gen_ctrcbc_keys;
+
+/*
+ * Traditional, table-based implementation for DES/3DES. Since tables are
+ * used, cache-timing attacks are conceptually possible.
+ */
+
+/** \brief DES/3DES block size (8 bytes). */
+#define br_des_tab_BLOCK_SIZE 8
+
+/**
+ * \brief Context for DES subkeys (`des_tab` implementation, CBC encryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcenc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[96];
+ unsigned num_rounds;
+#endif
+} br_des_tab_cbcenc_keys;
+
+/**
+ * \brief Context for DES subkeys (`des_tab` implementation, CBC decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcdec_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[96];
+ unsigned num_rounds;
+#endif
+} br_des_tab_cbcdec_keys;
+
+/**
+ * \brief Class instance for DES CBC encryption (`des_tab` implementation).
+ */
+extern const br_block_cbcenc_class br_des_tab_cbcenc_vtable;
+
+/**
+ * \brief Class instance for DES CBC decryption (`des_tab` implementation).
+ */
+extern const br_block_cbcdec_class br_des_tab_cbcdec_vtable;
+
+/**
+ * \brief Context initialisation (key schedule) for DES CBC encryption
+ * (`des_tab` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_des_tab_cbcenc_init(br_des_tab_cbcenc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for DES CBC decryption
+ * (`des_tab` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_des_tab_cbcdec_init(br_des_tab_cbcdec_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief CBC encryption with DES (`des_tab` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 8).
+ */
+void br_des_tab_cbcenc_run(const br_des_tab_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CBC decryption with DES (`des_tab` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 8).
+ */
+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.
+ */
+
+/** \brief DES/3DES block size (8 bytes). */
+#define br_des_ct_BLOCK_SIZE 8
+
+/**
+ * \brief Context for DES subkeys (`des_ct` implementation, CBC encryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcenc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[96];
+ unsigned num_rounds;
+#endif
+} br_des_ct_cbcenc_keys;
+
+/**
+ * \brief Context for DES subkeys (`des_ct` implementation, CBC decryption).
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /** \brief Pointer to vtable for this context. */
+ const br_block_cbcdec_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint32_t skey[96];
+ unsigned num_rounds;
+#endif
+} br_des_ct_cbcdec_keys;
+
+/**
+ * \brief Class instance for DES CBC encryption (`des_ct` implementation).
+ */
+extern const br_block_cbcenc_class br_des_ct_cbcenc_vtable;
+
+/**
+ * \brief Class instance for DES CBC decryption (`des_ct` implementation).
+ */
+extern const br_block_cbcdec_class br_des_ct_cbcdec_vtable;
+
+/**
+ * \brief Context initialisation (key schedule) for DES CBC encryption
+ * (`des_ct` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_des_ct_cbcenc_init(br_des_ct_cbcenc_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief Context initialisation (key schedule) for DES CBC decryption
+ * (`des_ct` implementation).
+ *
+ * \param ctx context to initialise.
+ * \param key secret key.
+ * \param len secret key length (in bytes).
+ */
+void br_des_ct_cbcdec_init(br_des_ct_cbcdec_keys *ctx,
+ const void *key, size_t len);
+
+/**
+ * \brief CBC encryption with DES (`des_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to encrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 8).
+ */
+void br_des_ct_cbcenc_run(const br_des_ct_cbcenc_keys *ctx, void *iv,
+ void *data, size_t len);
+
+/**
+ * \brief CBC decryption with DES (`des_ct` implementation).
+ *
+ * \param ctx context (already initialised).
+ * \param iv IV (updated).
+ * \param data data to decrypt (updated).
+ * \param len data length (in bytes, MUST be multiple of 8).
+ */
+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.
+ */
+
+/**
+ * \brief Aggregate structure large enough to be used as context for
+ * subkeys (CBC encryption) for all DES 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;
+
+/**
+ * \brief Aggregate structure large enough to be used as context for
+ * subkeys (CBC decryption) for all DES implementations.
+ */
+typedef union {
+ const br_block_cbcdec_class *vtable;
+ br_des_tab_cbcdec_keys c_tab;
+ br_des_ct_cbcdec_keys c_ct;
+} br_des_gen_cbcdec_keys;
+
+/**
+ * \brief Type for a ChaCha20 implementation.
+ *
+ * An implementation follows the description in RFC 7539:
+ *
+ * - Key is 256 bits (`key` points to exactly 32 bytes).
+ *
+ * - IV is 96 bits (`iv` points to exactly 12 bytes).
+ *
+ * - Block counter is over 32 bits and starts at value `cc`; the
+ * resulting value is returned.
+ *
+ * Data (pointed to by `data`, of length `len`) is encrypted/decrypted
+ * in place. If `len` is not a multiple of 64, then the excess bytes from
+ * the last block processing are dropped (therefore, "chunked" processing
+ * works only as long as each non-final chunk has a length multiple of 64).
+ *
+ * \param key secret key (32 bytes).
+ * \param iv IV (12 bytes).
+ * \param cc initial counter value.
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ */
+typedef uint32_t (*br_chacha20_run)(const void *key,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/**
+ * \brief ChaCha20 implementation (straightforward C code, constant-time).
+ *
+ * \see br_chacha20_run
+ *
+ * \param key secret key (32 bytes).
+ * \param iv IV (12 bytes).
+ * \param cc initial counter value.
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ */
+uint32_t br_chacha20_ct_run(const void *key,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/**
+ * \brief ChaCha20 implementation (SSE2 code, constant-time).
+ *
+ * This implementation is available only on x86 platforms, depending on
+ * compiler support. Moreover, in 32-bit mode, it might not actually run,
+ * if the underlying hardware does not implement the SSE2 opcode (in
+ * 64-bit mode, SSE2 is part of the ABI, so if the code could be compiled
+ * at all, then it can run). Use `br_chacha20_sse2_get()` to safely obtain
+ * a pointer to that function.
+ *
+ * \see br_chacha20_run
+ *
+ * \param key secret key (32 bytes).
+ * \param iv IV (12 bytes).
+ * \param cc initial counter value.
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ */
+uint32_t br_chacha20_sse2_run(const void *key,
+ const void *iv, uint32_t cc, void *data, size_t len);
+
+/**
+ * \brief Obtain the `sse2` ChaCha20 implementation, if available.
+ *
+ * This function returns a pointer to `br_chacha20_sse2_run`, if
+ * that implementation was compiled in the library _and_ the SSE2
+ * opcodes are available on the currently running CPU. If either of
+ * these conditions is not met, then this function returns `0`.
+ *
+ * \return the `sse2` ChaCha20 implementation, or `0`.
+ */
+br_chacha20_run br_chacha20_sse2_get(void);
+
+/**
+ * \brief Type for a ChaCha20+Poly1305 AEAD implementation.
+ *
+ * The provided data is encrypted or decrypted with ChaCha20. The
+ * authentication tag is computed on the concatenation of the
+ * additional data and the ciphertext, with the padding and lengths
+ * as described in RFC 7539 (section 2.8).
+ *
+ * After decryption, the caller is responsible for checking that the
+ * computed tag matches the expected value.
+ *
+ * \param key secret key (32 bytes).
+ * \param iv nonce (12 bytes).
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ * \param aad additional authenticated data.
+ * \param aad_len length of additional authenticated data (in bytes).
+ * \param tag output buffer for the authentication tag.
+ * \param ichacha implementation of ChaCha20.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ */
+typedef void (*br_poly1305_run)(const void *key, const void *iv,
+ void *data, size_t len, const void *aad, size_t aad_len,
+ void *tag, br_chacha20_run ichacha, int encrypt);
+
+/**
+ * \brief ChaCha20+Poly1305 AEAD implementation (mixed 32-bit multiplications).
+ *
+ * \see br_poly1305_run
+ *
+ * \param key secret key (32 bytes).
+ * \param iv nonce (12 bytes).
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ * \param aad additional authenticated data.
+ * \param aad_len length of additional authenticated data (in bytes).
+ * \param tag output buffer for the authentication tag.
+ * \param ichacha implementation of ChaCha20.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ */
+void br_poly1305_ctmul_run(const void *key, const void *iv,
+ void *data, size_t len, const void *aad, size_t aad_len,
+ void *tag, br_chacha20_run ichacha, int encrypt);
+
+/**
+ * \brief ChaCha20+Poly1305 AEAD implementation (pure 32-bit multiplications).
+ *
+ * \see br_poly1305_run
+ *
+ * \param key secret key (32 bytes).
+ * \param iv nonce (12 bytes).
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ * \param aad additional authenticated data.
+ * \param aad_len length of additional authenticated data (in bytes).
+ * \param tag output buffer for the authentication tag.
+ * \param ichacha implementation of ChaCha20.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ */
+void br_poly1305_ctmul32_run(const void *key, const void *iv,
+ void *data, size_t len, const void *aad, size_t aad_len,
+ void *tag, br_chacha20_run ichacha, int encrypt);
+
+/**
+ * \brief ChaCha20+Poly1305 AEAD implementation (i15).
+ *
+ * This implementation relies on the generic big integer code "i15"
+ * (which uses pure 32-bit multiplications). As such, it may save a
+ * little code footprint in a context where "i15" is already included
+ * (e.g. for elliptic curves or for RSA); however, it is also
+ * substantially slower than the ctmul and ctmul32 implementations.
+ *
+ * \see br_poly1305_run
+ *
+ * \param key secret key (32 bytes).
+ * \param iv nonce (12 bytes).
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ * \param aad additional authenticated data.
+ * \param aad_len length of additional authenticated data (in bytes).
+ * \param tag output buffer for the authentication tag.
+ * \param ichacha implementation of ChaCha20.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ */
+void br_poly1305_i15_run(const void *key, const void *iv,
+ void *data, size_t len, const void *aad, size_t aad_len,
+ void *tag, br_chacha20_run ichacha, int encrypt);
+
+/**
+ * \brief ChaCha20+Poly1305 AEAD implementation (ctmulq).
+ *
+ * This implementation uses 64-bit multiplications (result over 128 bits).
+ * It is available only on platforms that offer such a primitive (in
+ * practice, 64-bit architectures). Use `br_poly1305_ctmulq_get()` to
+ * dynamically obtain a pointer to that function, or 0 if not supported.
+ *
+ * \see br_poly1305_run
+ *
+ * \param key secret key (32 bytes).
+ * \param iv nonce (12 bytes).
+ * \param data data to encrypt or decrypt.
+ * \param len data length (in bytes).
+ * \param aad additional authenticated data.
+ * \param aad_len length of additional authenticated data (in bytes).
+ * \param tag output buffer for the authentication tag.
+ * \param ichacha implementation of ChaCha20.
+ * \param encrypt non-zero for encryption, zero for decryption.
+ */
+void br_poly1305_ctmulq_run(const void *key, const void *iv,
+ void *data, size_t len, const void *aad, size_t aad_len,
+ void *tag, br_chacha20_run ichacha, int encrypt);
+
+/**
+ * \brief Get the ChaCha20+Poly1305 "ctmulq" implementation, if available.
+ *
+ * This function returns a pointer to the `br_poly1305_ctmulq_run()`
+ * function if supported on the current platform; otherwise, it returns 0.
+ *
+ * \return the ctmulq ChaCha20+Poly1305 implementation, or 0.
+ */
+br_poly1305_run br_poly1305_ctmulq_get(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/bearssl/inc/bearssl_ec.h b/contrib/bearssl/inc/bearssl_ec.h
new file mode 100644
index 000000000000..f954309eb6c1
--- /dev/null
+++ b/contrib/bearssl/inc/bearssl_ec.h
@@ -0,0 +1,967 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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>
+
+#include "bearssl_rand.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_ec.h
+ *
+ * # Elliptic Curves
+ *
+ * This file documents the EC implementations provided with BearSSL, and
+ * ECDSA.
+ *
+ * ## Elliptic Curve API
+ *
+ * Only "named curves" are supported. Each EC implementation supports
+ * one or several named curves, identified by symbolic identifiers.
+ * These identifiers are small integers, that correspond to the values
+ * registered by the
+ * [IANA](http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-8).
+ *
+ * Since all currently defined elliptic curve identifiers are in the 0..31
+ * range, it is convenient to encode support of some curves in a 32-bit
+ * word, such that bit x corresponds to curve of identifier x.
+ *
+ * An EC implementation is incarnated by a `br_ec_impl` instance, that
+ * offers the following fields:
+ *
+ * - `supported_curves`
+ *
+ * A 32-bit word that documents the identifiers of the curves supported
+ * by this implementation.
+ *
+ * - `generator()`
+ *
+ * Callback method that returns a pointer to the conventional generator
+ * point for that curve.
+ *
+ * - `order()`
+ *
+ * Callback method that returns a pointer to the subgroup order for
+ * that curve. That value uses unsigned big-endian encoding.
+ *
+ * - `xoff()`
+ *
+ * Callback method that returns the offset and length of the X
+ * coordinate in an encoded point.
+ *
+ * - `mul()`
+ *
+ * Multiply a curve point with an integer.
+ *
+ * - `mulgen()`
+ *
+ * Multiply the curve generator with an integer. This may be faster
+ * than the generic `mul()`.
+ *
+ * - `muladd()`
+ *
+ * Multiply two curve points by two integers, and return the sum of
+ * the two products.
+ *
+ * All curve points are represented in uncompressed format. The `mul()`
+ * and `muladd()` methods take care to validate that the provided points
+ * are really part of the relevant curve subgroup.
+ *
+ * For all point multiplication functions, the following holds:
+ *
+ * - Functions validate that the provided points are valid members
+ * of the relevant curve subgroup. An error is reported if that is
+ * not the case.
+ *
+ * - Processing is constant-time, even if the point operands are not
+ * valid. This holds for both the source and resulting points, and
+ * the multipliers (integers). Only the byte length of the provided
+ * multiplier arrays (not their actual value length in bits) may
+ * leak through timing-based side channels.
+ *
+ * - The multipliers (integers) MUST be lower than the subgroup order.
+ * If this property is not met, then the result is indeterminate,
+ * but an error value is not ncessearily returned.
+ *
+ *
+ * ## ECDSA
+ *
+ * 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
+ * }
+ *
+ * In general, in all of X.509 and SSL/TLS, the "asn1" format is used.
+ * BearSSL offers ECDSA implementations for both formats; conversion
+ * functions between the two formats are also provided. Conversion of a
+ * "raw" format signature into "asn1" may enlarge a signature by no more
+ * than 9 bytes for all supported curves; conversely, conversion of an
+ * "asn1" signature to "raw" may expand the signature but the "raw"
+ * length will never be more than twice the length of the "asn1" length
+ * (and usually it will be shorter).
+ *
+ * Note that for a given signature, the "raw" format is not fully
+ * deterministic, in that it does not enforce a minimal common length.
+ */
+
+/*
+ * 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
+ */
+
+/** \brief Identifier for named curve sect163k1. */
+#define BR_EC_sect163k1 1
+
+/** \brief Identifier for named curve sect163r1. */
+#define BR_EC_sect163r1 2
+
+/** \brief Identifier for named curve sect163r2. */
+#define BR_EC_sect163r2 3
+
+/** \brief Identifier for named curve sect193r1. */
+#define BR_EC_sect193r1 4
+
+/** \brief Identifier for named curve sect193r2. */
+#define BR_EC_sect193r2 5
+
+/** \brief Identifier for named curve sect233k1. */
+#define BR_EC_sect233k1 6
+
+/** \brief Identifier for named curve sect233r1. */
+#define BR_EC_sect233r1 7
+
+/** \brief Identifier for named curve sect239k1. */
+#define BR_EC_sect239k1 8
+
+/** \brief Identifier for named curve sect283k1. */
+#define BR_EC_sect283k1 9
+
+/** \brief Identifier for named curve sect283r1. */
+#define BR_EC_sect283r1 10
+
+/** \brief Identifier for named curve sect409k1. */
+#define BR_EC_sect409k1 11
+
+/** \brief Identifier for named curve sect409r1. */
+#define BR_EC_sect409r1 12
+
+/** \brief Identifier for named curve sect571k1. */
+#define BR_EC_sect571k1 13
+
+/** \brief Identifier for named curve sect571r1. */
+#define BR_EC_sect571r1 14
+
+/** \brief Identifier for named curve secp160k1. */
+#define BR_EC_secp160k1 15
+
+/** \brief Identifier for named curve secp160r1. */
+#define BR_EC_secp160r1 16
+
+/** \brief Identifier for named curve secp160r2. */
+#define BR_EC_secp160r2 17
+
+/** \brief Identifier for named curve secp192k1. */
+#define BR_EC_secp192k1 18
+
+/** \brief Identifier for named curve secp192r1. */
+#define BR_EC_secp192r1 19
+
+/** \brief Identifier for named curve secp224k1. */
+#define BR_EC_secp224k1 20
+
+/** \brief Identifier for named curve secp224r1. */
+#define BR_EC_secp224r1 21
+
+/** \brief Identifier for named curve secp256k1. */
+#define BR_EC_secp256k1 22
+
+/** \brief Identifier for named curve secp256r1. */
+#define BR_EC_secp256r1 23
+
+/** \brief Identifier for named curve secp384r1. */
+#define BR_EC_secp384r1 24
+
+/** \brief Identifier for named curve secp521r1. */
+#define BR_EC_secp521r1 25
+
+/** \brief Identifier for named curve brainpoolP256r1. */
+#define BR_EC_brainpoolP256r1 26
+
+/** \brief Identifier for named curve brainpoolP384r1. */
+#define BR_EC_brainpoolP384r1 27
+
+/** \brief Identifier for named curve brainpoolP512r1. */
+#define BR_EC_brainpoolP512r1 28
+
+/** \brief Identifier for named curve Curve25519. */
+#define BR_EC_curve25519 29
+
+/** \brief Identifier for named curve Curve448. */
+#define BR_EC_curve448 30
+
+/**
+ * \brief Structure for an EC public key.
+ */
+typedef struct {
+ /** \brief Identifier for the curve used by this key. */
+ int curve;
+ /** \brief Public curve point (uncompressed format). */
+ unsigned char *q;
+ /** \brief Length of public curve point (in bytes). */
+ size_t qlen;
+} br_ec_public_key;
+
+/**
+ * \brief Structure for an EC private key.
+ *
+ * The private key is an integer modulo the curve subgroup order. The
+ * encoding below tolerates extra leading zeros. In general, it is
+ * recommended that the private key has the same length as the curve
+ * subgroup order.
+ */
+typedef struct {
+ /** \brief Identifier for the curve used by this key. */
+ int curve;
+ /** \brief Private key (integer, unsigned big-endian encoding). */
+ unsigned char *x;
+ /** \brief Private key length (in bytes). */
+ size_t xlen;
+} br_ec_private_key;
+
+/**
+ * \brief Type for an EC implementation.
+ */
+typedef struct {
+ /**
+ * \brief Supported curves.
+ *
+ * This word is a bitfield: bit `x` is set if the curve of ID `x`
+ * is supported. E.g. an implementation supporting both NIST P-256
+ * (secp256r1, ID 23) and NIST P-384 (secp384r1, ID 24) will have
+ * value `0x01800000` in this field.
+ */
+ uint32_t supported_curves;
+
+ /**
+ * \brief Get the conventional generator.
+ *
+ * This function returns the conventional generator (encoded
+ * curve point) for the specified curve. This function MUST NOT
+ * be called if the curve is not supported.
+ *
+ * \param curve curve identifier.
+ * \param len receiver for the encoded generator length (in bytes).
+ * \return the encoded generator.
+ */
+ const unsigned char *(*generator)(int curve, size_t *len);
+
+ /**
+ * \brief Get the subgroup order.
+ *
+ * This function returns the order of the subgroup generated by
+ * the conventional generator, for the specified curve. Unsigned
+ * big-endian encoding is used. This function MUST NOT be called
+ * if the curve is not supported.
+ *
+ * \param curve curve identifier.
+ * \param len receiver for the encoded order length (in bytes).
+ * \return the encoded order.
+ */
+ const unsigned char *(*order)(int curve, size_t *len);
+
+ /**
+ * \brief Get the offset and length for the X coordinate.
+ *
+ * This function returns the offset and length (in bytes) of
+ * the X coordinate in an encoded non-zero point.
+ *
+ * \param curve curve identifier.
+ * \param len receiver for the X coordinate length (in bytes).
+ * \return the offset for the X coordinate (in bytes).
+ */
+ size_t (*xoff)(int curve, size_t *len);
+
+ /**
+ * \brief Multiply a curve point by an integer.
+ *
+ * The source point is provided in array `G` (of size `Glen` bytes);
+ * the multiplication result is written over it. The multiplier
+ * `x` (of size `xlen` bytes) uses unsigned big-endian encoding.
+ *
+ * Rules:
+ *
+ * - The specified curve MUST be supported.
+ *
+ * - The source point must be a valid point on the relevant curve
+ * subgroup (and not the "point at infinity" either). If this is
+ * not the case, then this function returns an error (0).
+ *
+ * - The multiplier integer MUST be non-zero and less than the
+ * curve subgroup order. If this property does not hold, then
+ * the result is indeterminate and an error code is not
+ * guaranteed.
+ *
+ * Returned value is 1 on success, 0 on error. On error, the
+ * contents of `G` are indeterminate.
+ *
+ * \param G point to multiply.
+ * \param Glen length of the encoded point (in bytes).
+ * \param x multiplier (unsigned big-endian).
+ * \param xlen multiplier length (in bytes).
+ * \param curve curve identifier.
+ * \return 1 on success, 0 on error.
+ */
+ uint32_t (*mul)(unsigned char *G, size_t Glen,
+ const unsigned char *x, size_t xlen, int curve);
+
+ /**
+ * \brief Multiply the generator by an integer.
+ *
+ * The multiplier MUST be non-zero and less than the curve
+ * subgroup order. Results are indeterminate if this property
+ * does not hold.
+ *
+ * \param R output buffer for the point.
+ * \param x multiplier (unsigned big-endian).
+ * \param xlen multiplier length (in bytes).
+ * \param curve curve identifier.
+ * \return encoded result point length (in bytes).
+ */
+ size_t (*mulgen)(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve);
+
+ /**
+ * \brief Multiply two points by two integers and add the
+ * results.
+ *
+ * The point `x*A + y*B` is computed and written back in the `A`
+ * array.
+ *
+ * Rules:
+ *
+ * - The specified curve MUST be supported.
+ *
+ * - The source points (`A` and `B`) must be valid points on
+ * the relevant curve subgroup (and not the "point at
+ * infinity" either). If this is not the case, then this
+ * function returns an error (0).
+ *
+ * - If the `B` pointer is `NULL`, then the conventional
+ * subgroup generator is used. With some implementations,
+ * this may be faster than providing a pointer to the
+ * generator.
+ *
+ * - The multiplier integers (`x` and `y`) MUST be non-zero
+ * and less than the curve subgroup order. If either integer
+ * is zero, then an error is reported, but if one of them is
+ * not lower than the subgroup order, then the result is
+ * indeterminate and an error code is not guaranteed.
+ *
+ * - If the final result is the point at infinity, then an
+ * error is returned.
+ *
+ * Returned value is 1 on success, 0 on error. On error, the
+ * contents of `A` are indeterminate.
+ *
+ * \param A first point to multiply.
+ * \param B second point to multiply (`NULL` for the generator).
+ * \param len common length of the encoded points (in bytes).
+ * \param x multiplier for `A` (unsigned big-endian).
+ * \param xlen length of multiplier for `A` (in bytes).
+ * \param y multiplier for `A` (unsigned big-endian).
+ * \param ylen length of multiplier for `A` (in bytes).
+ * \param curve curve identifier.
+ * \return 1 on success, 0 on error.
+ */
+ 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;
+
+/**
+ * \brief EC implementation "i31".
+ *
+ * This implementation internally uses generic code for modular integers,
+ * with a representation as sequences of 31-bit words. 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;
+
+/**
+ * \brief EC implementation "i15".
+ *
+ * This implementation internally uses generic code for modular integers,
+ * with a representation as sequences of 15-bit words. It supports secp256r1,
+ * secp384r1 and secp521r1 (aka NIST curves P-256, P-384 and P-521).
+ */
+extern const br_ec_impl br_ec_prime_i15;
+
+/**
+ * \brief EC implementation "m15" for P-256.
+ *
+ * This implementation uses specialised code for curve secp256r1 (also
+ * known as NIST P-256), with optional Karatsuba decomposition, and fast
+ * modular reduction thanks to the field modulus special format. Only
+ * 32-bit multiplications are used (with 32-bit results, not 64-bit).
+ */
+extern const br_ec_impl br_ec_p256_m15;
+
+/**
+ * \brief EC implementation "m31" for P-256.
+ *
+ * This implementation uses specialised code for curve secp256r1 (also
+ * known as NIST P-256), relying on multiplications of 31-bit values
+ * (MUL31).
+ */
+extern const br_ec_impl br_ec_p256_m31;
+
+/**
+ * \brief EC implementation "m62" (specialised code) for P-256.
+ *
+ * This implementation uses custom code relying on multiplication of
+ * integers up to 64 bits, with a 128-bit result. This implementation is
+ * defined only on platforms that offer the 64x64->128 multiplication
+ * support; use `br_ec_p256_m62_get()` to dynamically obtain a pointer
+ * to that implementation.
+ */
+extern const br_ec_impl br_ec_p256_m62;
+
+/**
+ * \brief Get the "m62" implementation of P-256, if available.
+ *
+ * \return the implementation, or 0.
+ */
+const br_ec_impl *br_ec_p256_m62_get(void);
+
+/**
+ * \brief EC implementation "m64" (specialised code) for P-256.
+ *
+ * This implementation uses custom code relying on multiplication of
+ * integers up to 64 bits, with a 128-bit result. This implementation is
+ * defined only on platforms that offer the 64x64->128 multiplication
+ * support; use `br_ec_p256_m64_get()` to dynamically obtain a pointer
+ * to that implementation.
+ */
+extern const br_ec_impl br_ec_p256_m64;
+
+/**
+ * \brief Get the "m64" implementation of P-256, if available.
+ *
+ * \return the implementation, or 0.
+ */
+const br_ec_impl *br_ec_p256_m64_get(void);
+
+/**
+ * \brief EC implementation "i15" (generic code) for Curve25519.
+ *
+ * This implementation uses the generic code for modular integers (with
+ * 15-bit words) to support Curve25519. Due to the specificities of the
+ * curve definition, the following applies:
+ *
+ * - `muladd()` is not implemented (the function returns 0 systematically).
+ * - `order()` returns 2^255-1, since the point multiplication algorithm
+ * accepts any 32-bit integer as input (it clears the top bit and low
+ * three bits systematically).
+ */
+extern const br_ec_impl br_ec_c25519_i15;
+
+/**
+ * \brief EC implementation "i31" (generic code) for Curve25519.
+ *
+ * This implementation uses the generic code for modular integers (with
+ * 31-bit words) to support Curve25519. Due to the specificities of the
+ * curve definition, the following applies:
+ *
+ * - `muladd()` is not implemented (the function returns 0 systematically).
+ * - `order()` returns 2^255-1, since the point multiplication algorithm
+ * accepts any 32-bit integer as input (it clears the top bit and low
+ * three bits systematically).
+ */
+extern const br_ec_impl br_ec_c25519_i31;
+
+/**
+ * \brief EC implementation "m15" (specialised code) for Curve25519.
+ *
+ * This implementation uses custom code relying on multiplication of
+ * integers up to 15 bits. Due to the specificities of the curve
+ * definition, the following applies:
+ *
+ * - `muladd()` is not implemented (the function returns 0 systematically).
+ * - `order()` returns 2^255-1, since the point multiplication algorithm
+ * accepts any 32-bit integer as input (it clears the top bit and low
+ * three bits systematically).
+ */
+extern const br_ec_impl br_ec_c25519_m15;
+
+/**
+ * \brief EC implementation "m31" (specialised code) for Curve25519.
+ *
+ * This implementation uses custom code relying on multiplication of
+ * integers up to 31 bits. Due to the specificities of the curve
+ * definition, the following applies:
+ *
+ * - `muladd()` is not implemented (the function returns 0 systematically).
+ * - `order()` returns 2^255-1, since the point multiplication algorithm
+ * accepts any 32-bit integer as input (it clears the top bit and low
+ * three bits systematically).
+ */
+extern const br_ec_impl br_ec_c25519_m31;
+
+/**
+ * \brief EC implementation "m62" (specialised code) for Curve25519.
+ *
+ * This implementation uses custom code relying on multiplication of
+ * integers up to 62 bits, with a 124-bit result. This implementation is
+ * defined only on platforms that offer the 64x64->128 multiplication
+ * support; use `br_ec_c25519_m62_get()` to dynamically obtain a pointer
+ * to that implementation. Due to the specificities of the curve
+ * definition, the following applies:
+ *
+ * - `muladd()` is not implemented (the function returns 0 systematically).
+ * - `order()` returns 2^255-1, since the point multiplication algorithm
+ * accepts any 32-bit integer as input (it clears the top bit and low
+ * three bits systematically).
+ */
+extern const br_ec_impl br_ec_c25519_m62;
+
+/**
+ * \brief Get the "m62" implementation of Curve25519, if available.
+ *
+ * \return the implementation, or 0.
+ */
+const br_ec_impl *br_ec_c25519_m62_get(void);
+
+/**
+ * \brief EC implementation "m64" (specialised code) for Curve25519.
+ *
+ * This implementation uses custom code relying on multiplication of
+ * integers up to 64 bits, with a 128-bit result. This implementation is
+ * defined only on platforms that offer the 64x64->128 multiplication
+ * support; use `br_ec_c25519_m64_get()` to dynamically obtain a pointer
+ * to that implementation. Due to the specificities of the curve
+ * definition, the following applies:
+ *
+ * - `muladd()` is not implemented (the function returns 0 systematically).
+ * - `order()` returns 2^255-1, since the point multiplication algorithm
+ * accepts any 32-bit integer as input (it clears the top bit and low
+ * three bits systematically).
+ */
+extern const br_ec_impl br_ec_c25519_m64;
+
+/**
+ * \brief Get the "m64" implementation of Curve25519, if available.
+ *
+ * \return the implementation, or 0.
+ */
+const br_ec_impl *br_ec_c25519_m64_get(void);
+
+/**
+ * \brief Aggregate EC implementation "m15".
+ *
+ * This implementation is a wrapper for:
+ *
+ * - `br_ec_c25519_m15` for Curve25519
+ * - `br_ec_p256_m15` for NIST P-256
+ * - `br_ec_prime_i15` for other curves (NIST P-384 and NIST-P512)
+ */
+extern const br_ec_impl br_ec_all_m15;
+
+/**
+ * \brief Aggregate EC implementation "m31".
+ *
+ * This implementation is a wrapper for:
+ *
+ * - `br_ec_c25519_m31` for Curve25519
+ * - `br_ec_p256_m31` for NIST P-256
+ * - `br_ec_prime_i31` for other curves (NIST P-384 and NIST-P512)
+ */
+extern const br_ec_impl br_ec_all_m31;
+
+/**
+ * \brief Get the "default" EC implementation for the current system.
+ *
+ * This returns a pointer to the preferred implementation on the
+ * current system.
+ *
+ * \return the default EC implementation.
+ */
+const br_ec_impl *br_ec_get_default(void);
+
+/**
+ * \brief 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).
+ *
+ * \param sig signature to convert.
+ * \param sig_len signature length (in bytes).
+ * \return the new signature length, or 0 on error.
+ */
+size_t br_ecdsa_raw_to_asn1(void *sig, size_t sig_len);
+
+/**
+ * \brief Convert a signature from "asn1" to "raw".
+ *
+ * Conversion is done "in place" and the new length is returned.
+ * Conversion may enlarge the signature, but the new signature length
+ * will be less than twice the source length at most. On error, 0 is
+ * returned (error conditions include an invalid ASN.1 structure or an
+ * oversized integer).
+ *
+ * \param sig signature to convert.
+ * \param sig_len signature length (in bytes).
+ * \return the new signature length, or 0 on error.
+ */
+size_t br_ecdsa_asn1_to_raw(void *sig, size_t sig_len);
+
+/**
+ * \brief 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. This function returns 0 if the specified curve is
+ * not supported by the provided EC implementation.
+ *
+ * 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 |
+ *
+ * \param impl EC implementation to use.
+ * \param hf hash function used to process the data.
+ * \param hash_value signed data (hashed).
+ * \param sk EC private key.
+ * \param sig destination buffer.
+ * \return the signature length (in bytes), or 0 on error.
+ */
+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);
+
+/**
+ * \brief Type for an ECDSA signature verification function.
+ *
+ * A pointer to the EC implementation is provided. The hashed value,
+ * computed over the purportedly signed data, is also provided with
+ * its length.
+ *
+ * The signature format is either "raw" or "asn1", depending on the
+ * implementation.
+ *
+ * Returned value is 1 on success (valid signature), 0 on error. This
+ * function returns 0 if the specified curve is not supported by the
+ * provided EC implementation.
+ *
+ * \param impl EC implementation to use.
+ * \param hash signed data (hashed).
+ * \param hash_len hash value length (in bytes).
+ * \param pk EC public key.
+ * \param sig signature.
+ * \param sig_len signature length (in bytes).
+ * \return 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);
+
+/**
+ * \brief ECDSA signature generator, "i31" implementation, "asn1" format.
+ *
+ * \see br_ecdsa_sign()
+ *
+ * \param impl EC implementation to use.
+ * \param hf hash function used to process the data.
+ * \param hash_value signed data (hashed).
+ * \param sk EC private key.
+ * \param sig destination buffer.
+ * \return the signature length (in bytes), or 0 on error.
+ */
+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);
+
+/**
+ * \brief ECDSA signature generator, "i31" implementation, "raw" format.
+ *
+ * \see br_ecdsa_sign()
+ *
+ * \param impl EC implementation to use.
+ * \param hf hash function used to process the data.
+ * \param hash_value signed data (hashed).
+ * \param sk EC private key.
+ * \param sig destination buffer.
+ * \return the signature length (in bytes), or 0 on error.
+ */
+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);
+
+/**
+ * \brief ECDSA signature verifier, "i31" implementation, "asn1" format.
+ *
+ * \see br_ecdsa_vrfy()
+ *
+ * \param impl EC implementation to use.
+ * \param hash signed data (hashed).
+ * \param hash_len hash value length (in bytes).
+ * \param pk EC public key.
+ * \param sig signature.
+ * \param sig_len signature length (in bytes).
+ * \return 1 on success, 0 on error.
+ */
+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);
+
+/**
+ * \brief ECDSA signature verifier, "i31" implementation, "raw" format.
+ *
+ * \see br_ecdsa_vrfy()
+ *
+ * \param impl EC implementation to use.
+ * \param hash signed data (hashed).
+ * \param hash_len hash value length (in bytes).
+ * \param pk EC public key.
+ * \param sig signature.
+ * \param sig_len signature length (in bytes).
+ * \return 1 on success, 0 on error.
+ */
+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);
+
+/**
+ * \brief ECDSA signature generator, "i15" implementation, "asn1" format.
+ *
+ * \see br_ecdsa_sign()
+ *
+ * \param impl EC implementation to use.
+ * \param hf hash function used to process the data.
+ * \param hash_value signed data (hashed).
+ * \param sk EC private key.
+ * \param sig destination buffer.
+ * \return the signature length (in bytes), or 0 on error.
+ */
+size_t br_ecdsa_i15_sign_asn1(const br_ec_impl *impl,
+ const br_hash_class *hf, const void *hash_value,
+ const br_ec_private_key *sk, void *sig);
+
+/**
+ * \brief ECDSA signature generator, "i15" implementation, "raw" format.
+ *
+ * \see br_ecdsa_sign()
+ *
+ * \param impl EC implementation to use.
+ * \param hf hash function used to process the data.
+ * \param hash_value signed data (hashed).
+ * \param sk EC private key.
+ * \param sig destination buffer.
+ * \return the signature length (in bytes), or 0 on error.
+ */
+size_t br_ecdsa_i15_sign_raw(const br_ec_impl *impl,
+ const br_hash_class *hf, const void *hash_value,
+ const br_ec_private_key *sk, void *sig);
+
+/**
+ * \brief ECDSA signature verifier, "i15" implementation, "asn1" format.
+ *
+ * \see br_ecdsa_vrfy()
+ *
+ * \param impl EC implementation to use.
+ * \param hash signed data (hashed).
+ * \param hash_len hash value length (in bytes).
+ * \param pk EC public key.
+ * \param sig signature.
+ * \param sig_len signature length (in bytes).
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_ecdsa_i15_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);
+
+/**
+ * \brief ECDSA signature verifier, "i15" implementation, "raw" format.
+ *
+ * \see br_ecdsa_vrfy()
+ *
+ * \param impl EC implementation to use.
+ * \param hash signed data (hashed).
+ * \param hash_len hash value length (in bytes).
+ * \param pk EC public key.
+ * \param sig signature.
+ * \param sig_len signature length (in bytes).
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_ecdsa_i15_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);
+
+/**
+ * \brief Get "default" ECDSA implementation (signer, asn1 format).
+ *
+ * This returns the preferred implementation of ECDSA signature generation
+ * ("asn1" output format) on the current system.
+ *
+ * \return the default implementation.
+ */
+br_ecdsa_sign br_ecdsa_sign_asn1_get_default(void);
+
+/**
+ * \brief Get "default" ECDSA implementation (signer, raw format).
+ *
+ * This returns the preferred implementation of ECDSA signature generation
+ * ("raw" output format) on the current system.
+ *
+ * \return the default implementation.
+ */
+br_ecdsa_sign br_ecdsa_sign_raw_get_default(void);
+
+/**
+ * \brief Get "default" ECDSA implementation (verifier, asn1 format).
+ *
+ * This returns the preferred implementation of ECDSA signature verification
+ * ("asn1" output format) on the current system.
+ *
+ * \return the default implementation.
+ */
+br_ecdsa_vrfy br_ecdsa_vrfy_asn1_get_default(void);
+
+/**
+ * \brief Get "default" ECDSA implementation (verifier, raw format).
+ *
+ * This returns the preferred implementation of ECDSA signature verification
+ * ("raw" output format) on the current system.
+ *
+ * \return the default implementation.
+ */
+br_ecdsa_vrfy br_ecdsa_vrfy_raw_get_default(void);
+
+/**
+ * \brief Maximum size for EC private key element buffer.
+ *
+ * This is the largest number of bytes that `br_ec_keygen()` may need or
+ * ever return.
+ */
+#define BR_EC_KBUF_PRIV_MAX_SIZE 72
+
+/**
+ * \brief Maximum size for EC public key element buffer.
+ *
+ * This is the largest number of bytes that `br_ec_compute_public()` may
+ * need or ever return.
+ */
+#define BR_EC_KBUF_PUB_MAX_SIZE 145
+
+/**
+ * \brief Generate a new EC private key.
+ *
+ * If the specified `curve` is not supported by the elliptic curve
+ * implementation (`impl`), then this function returns zero.
+ *
+ * The `sk` structure fields are set to the new private key data. In
+ * particular, `sk.x` is made to point to the provided key buffer (`kbuf`),
+ * in which the actual private key data is written. That buffer is assumed
+ * to be large enough. The `BR_EC_KBUF_PRIV_MAX_SIZE` defines the maximum
+ * size for all supported curves.
+ *
+ * The number of bytes used in `kbuf` is returned. If `kbuf` is `NULL`, then
+ * the private key is not actually generated, and `sk` may also be `NULL`;
+ * the minimum length for `kbuf` is still computed and returned.
+ *
+ * If `sk` is `NULL` but `kbuf` is not `NULL`, then the private key is
+ * still generated and stored in `kbuf`.
+ *
+ * \param rng_ctx source PRNG context (already initialized).
+ * \param impl the elliptic curve implementation.
+ * \param sk the private key structure to fill, or `NULL`.
+ * \param kbuf the key element buffer, or `NULL`.
+ * \param curve the curve identifier.
+ * \return the key data length (in bytes), or zero.
+ */
+size_t br_ec_keygen(const br_prng_class **rng_ctx,
+ const br_ec_impl *impl, br_ec_private_key *sk,
+ void *kbuf, int curve);
+
+/**
+ * \brief Compute EC public key from EC private key.
+ *
+ * This function uses the provided elliptic curve implementation (`impl`)
+ * to compute the public key corresponding to the private key held in `sk`.
+ * The public key point is written into `kbuf`, which is then linked from
+ * the `*pk` structure. The size of the public key point, i.e. the number
+ * of bytes used in `kbuf`, is returned.
+ *
+ * If `kbuf` is `NULL`, then the public key point is NOT computed, and
+ * the public key structure `*pk` is unmodified (`pk` may be `NULL` in
+ * that case). The size of the public key point is still returned.
+ *
+ * If `pk` is `NULL` but `kbuf` is not `NULL`, then the public key
+ * point is computed and stored in `kbuf`, and its size is returned.
+ *
+ * If the curve used by the private key is not supported by the curve
+ * implementation, then this function returns zero.
+ *
+ * The private key MUST be valid. An off-range private key value is not
+ * necessarily detected, and leads to unpredictable results.
+ *
+ * \param impl the elliptic curve implementation.
+ * \param pk the public key structure to fill (or `NULL`).
+ * \param kbuf the public key point buffer (or `NULL`).
+ * \param sk the source private key.
+ * \return the public key point length (in bytes), or zero.
+ */
+size_t br_ec_compute_pub(const br_ec_impl *impl, br_ec_public_key *pk,
+ void *kbuf, const br_ec_private_key *sk);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/bearssl/inc/bearssl_hash.h b/contrib/bearssl/inc/bearssl_hash.h
new file mode 100644
index 000000000000..3b15ba7ca487
--- /dev/null
+++ b/contrib/bearssl/inc/bearssl_hash.h
@@ -0,0 +1,1346 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_hash.h
+ *
+ * # Hash Functions
+ *
+ * This file documents the API for hash functions.
+ *
+ *
+ * ## Procedural API
+ *
+ * For each implemented hash function, of name "`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: for the "standard" hash functions defined in [the TLS
+ * standard](https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1),
+ * the symbolic identifiers match the constants used in TLS, i.e.
+ * 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)`
+ *
+ * Initialise the provided context. Previous contents of the structure
+ * are ignored. This calls resets the context to the start of a new
+ * hash computation; it also sets the first field of the context
+ * structure (called `vtable`) to a pointer to the statically
+ * allocated constant `br_xxx_vtable` structure.
+ *
+ * - `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 accommodate 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.
+ *
+ *
+ * ## Object-Oriented API
+ *
+ * For each hash function that follows the procedural API described
+ * above, an object-oriented API is also provided. In that API, function
+ * pointers from the vtable (`br_xxx_vtable`) are used. The vtable
+ * incarnates object-oriented programming. An introduction on the OOP
+ * concept used here can be read on the BearSSL Web site:<br />
+ * &nbsp;&nbsp;&nbsp;[https://www.bearssl.org/oop.html](https://www.bearssl.org/oop.html)
+ *
+ * The vtable offers functions called `init()`, `update()`, `out()`,
+ * `set()` and `set_state()`, which are in fact the functions from
+ * the procedural API. That vtable also contains two informative fields:
+ *
+ * - `context_size`
+ *
+ * The size of the context structure (`br_xxx_context`), in bytes.
+ * This can be used by generic implementations to perform dynamic
+ * context allocation.
+ *
+ * - `desc`
+ *
+ * A "descriptor" field that encodes some information on the hash
+ * function: symbolic identifier, output size, state size,
+ * internal block size, details on the padding.
+ *
+ * Users of this object-oriented API (in particular generic HMAC
+ * implementations) 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 16 and no more
+ * than 256.
+ *
+ *
+ * ## Implemented Hash Functions
+ *
+ * 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.)
+ *
+ *
+ * ## Multi-Hasher
+ *
+ * An aggregate hasher is provided, that can compute several standard
+ * hash functions in parallel. It uses `br_multihash_context` and a
+ * procedural API. It is configured with the implementations (the vtables)
+ * that it should use; it will then compute all these hash functions in
+ * parallel, on the same input. It is meant to be used in cases when the
+ * hash of an object will be used, but the exact hash function is not
+ * known yet (typically, streamed processing on X.509 certificates).
+ *
+ * Only the standard hash functions (MD5, SHA-1, SHA-224, SHA-256, SHA-384
+ * and SHA-512) are supported by the multi-hasher.
+ *
+ *
+ * ## GHASH
+ *
+ * GHASH is not a generic hash function; it is a _universal_ hash function,
+ * which, as the name does not say, means that it CANNOT be used in most
+ * places where a hash function is needed. GHASH is used within the GCM
+ * encryption mode, to provide the checked integrity functionality.
+ *
+ * A GHASH implementation is basically a function that uses the type defined
+ * in this file under the name `br_ghash`:
+ *
+ * typedef void (*br_ghash)(void *y, const void *h, const void *data, size_t len);
+ *
+ * The `y` pointer refers to a 16-byte value which is used as input, and
+ * receives the output of the GHASH invocation. `h` is a 16-byte secret
+ * value (that serves as key). `data` and `len` define the input data.
+ *
+ * Three GHASH implementations are provided, all constant-time, based on
+ * the use of integer multiplications with appropriate masking to cancel
+ * carry propagation.
+ */
+
+/**
+ * \brief Class type for hash function implementations.
+ *
+ * A `br_hash_class` instance references the methods implementing a hash
+ * function. Constant instances of this structure are defined for each
+ * implemented hash function. Such instances are also called "vtables".
+ *
+ * Vtables are used to support object-oriented programming, as
+ * described on [the BearSSL Web site](https://www.bearssl.org/oop.html).
+ */
+typedef struct br_hash_class_ br_hash_class;
+struct br_hash_class_ {
+ /**
+ * \brief Size (in bytes) of the context structure appropriate for
+ * computing this hash function.
+ */
+ size_t context_size;
+
+ /**
+ * \brief Descriptor word that contains information about the hash
+ * function.
+ *
+ * For each word `xxx` described below, use `BR_HASHDESC_xxx_OFF`
+ * and `BR_HASHDESC_xxx_MASK` to access the specific value, as
+ * follows:
+ *
+ * (hf->desc >> BR_HASHDESC_xxx_OFF) & BR_HASHDESC_xxx_MASK
+ *
+ * The defined elements are:
+ *
+ * - `ID`: the symbolic identifier for the function, as defined
+ * in [TLS](https://tools.ietf.org/html/rfc5246#section-7.4.1.4.1)
+ * (MD5 = 1, SHA-1 = 2,...).
+ *
+ * - `OUT`: hash output size, in bytes.
+ *
+ * - `STATE`: internal running state size, in bytes.
+ *
+ * - `LBLEN`: base-2 logarithm for the internal block size, as
+ * defined for HMAC processing (this is 6 for MD5, SHA-1, SHA-224
+ * and SHA-256, since these functions use 64-byte blocks; for
+ * SHA-384 and SHA-512, this is 7, corresponding to their
+ * 128-byte blocks).
+ *
+ * The descriptor may contain a few other flags.
+ */
+ uint32_t desc;
+
+ /**
+ * \brief Initialisation method.
+ *
+ * This method takes as parameter a pointer to a context area,
+ * that it initialises. The first field of the context is set
+ * to this vtable; other elements are initialised for a new hash
+ * computation.
+ *
+ * \param ctx pointer to (the first field of) the context.
+ */
+ void (*init)(const br_hash_class **ctx);
+
+ /**
+ * \brief Data injection method.
+ *
+ * The `len` bytes starting at address `data` are injected into
+ * the running hash computation incarnated by the specified
+ * context. The context is updated accordingly. It is allowed
+ * to have `len == 0`, in which case `data` is ignored (and could
+ * be `NULL`), and nothing happens.
+ * on the input data.
+ *
+ * \param ctx pointer to (the first field of) the context.
+ * \param data pointer to the first data byte to inject.
+ * \param len number of bytes to inject.
+ */
+ void (*update)(const br_hash_class **ctx, const void *data, size_t len);
+
+ /**
+ * \brief Produce hash output.
+ *
+ * The hash output corresponding to all data bytes injected in the
+ * context since the last `init()` call is computed, and written
+ * in the buffer pointed to by `dst`. The hash output size depends
+ * on the implemented hash function (e.g. 16 bytes for MD5).
+ * The context is _not_ modified by this call, so further bytes
+ * may be afterwards injected to continue the current computation.
+ *
+ * \param ctx pointer to (the first field of) the context.
+ * \param dst destination buffer for the hash output.
+ */
+ void (*out)(const br_hash_class *const *ctx, void *dst);
+
+ /**
+ * \brief Get running state.
+ *
+ * This method saves the current running state into the `dst`
+ * buffer. What constitutes the "running state" depends on the
+ * hash function; for Merkle-Damgård hash functions (like
+ * MD5 or SHA-1), this is the output obtained after processing
+ * each block. The number of bytes injected so far is returned.
+ * The context is not modified by this call.
+ *
+ * \param ctx pointer to (the first field of) the context.
+ * \param dst destination buffer for the state.
+ * \return the injected total byte length.
+ */
+ uint64_t (*state)(const br_hash_class *const *ctx, void *dst);
+
+ /**
+ * \brief Set running state.
+ *
+ * This methods replaces the running state for the function.
+ *
+ * \param ctx pointer to (the first field of) the context.
+ * \param stb source buffer for the state.
+ * \param count injected total byte length.
+ */
+ void (*set_state)(const br_hash_class **ctx,
+ const void *stb, uint64_t count);
+};
+
+#ifndef BR_DOXYGEN_IGNORE
+#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)
+#endif
+
+/*
+ * 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.
+ */
+
+/**
+ * \brief Symbolic identifier for MD5.
+ */
+#define br_md5_ID 1
+
+/**
+ * \brief MD5 output size (in bytes).
+ */
+#define br_md5_SIZE 16
+
+/**
+ * \brief Constant vtable for MD5.
+ */
+extern const br_hash_class br_md5_vtable;
+
+/**
+ * \brief MD5 context.
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /**
+ * \brief Pointer to vtable for this context.
+ */
+ const br_hash_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char buf[64];
+ uint64_t count;
+ uint32_t val[4];
+#endif
+} br_md5_context;
+
+/**
+ * \brief MD5 context initialisation.
+ *
+ * This function initialises or resets a context for a new MD5
+ * computation. It also sets the vtable pointer.
+ *
+ * \param ctx pointer to the context structure.
+ */
+void br_md5_init(br_md5_context *ctx);
+
+/**
+ * \brief Inject some data bytes in a running MD5 computation.
+ *
+ * The provided context is updated with some data bytes. If the number
+ * of bytes (`len`) is zero, then the data pointer (`data`) is ignored
+ * and may be `NULL`, and this function does nothing.
+ *
+ * \param ctx pointer to the context structure.
+ * \param data pointer to the injected data.
+ * \param len injected data length (in bytes).
+ */
+void br_md5_update(br_md5_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Compute MD5 output.
+ *
+ * The MD5 output for the concatenation of all bytes injected in the
+ * provided context since the last initialisation or reset call, is
+ * computed and written in the buffer pointed to by `out`. The context
+ * itself is not modified, so extra bytes may be injected afterwards
+ * to continue that computation.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the hash output.
+ */
+void br_md5_out(const br_md5_context *ctx, void *out);
+
+/**
+ * \brief Save MD5 running state.
+ *
+ * The running state for MD5 (output of the last internal block
+ * processing) is written in the buffer pointed to by `out`. The
+ * number of bytes injected since the last initialisation or reset
+ * call is returned. The context is not modified.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the running state.
+ * \return the injected total byte length.
+ */
+uint64_t br_md5_state(const br_md5_context *ctx, void *out);
+
+/**
+ * \brief Restore MD5 running state.
+ *
+ * The running state for MD5 is set to the provided values.
+ *
+ * \param ctx pointer to the context structure.
+ * \param stb source buffer for the running state.
+ * \param count the injected total byte length.
+ */
+void br_md5_set_state(br_md5_context *ctx, const void *stb, uint64_t count);
+
+/**
+ * \brief Symbolic identifier for SHA-1.
+ */
+#define br_sha1_ID 2
+
+/**
+ * \brief SHA-1 output size (in bytes).
+ */
+#define br_sha1_SIZE 20
+
+/**
+ * \brief Constant vtable for SHA-1.
+ */
+extern const br_hash_class br_sha1_vtable;
+
+/**
+ * \brief SHA-1 context.
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /**
+ * \brief Pointer to vtable for this context.
+ */
+ const br_hash_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char buf[64];
+ uint64_t count;
+ uint32_t val[5];
+#endif
+} br_sha1_context;
+
+/**
+ * \brief SHA-1 context initialisation.
+ *
+ * This function initialises or resets a context for a new SHA-1
+ * computation. It also sets the vtable pointer.
+ *
+ * \param ctx pointer to the context structure.
+ */
+void br_sha1_init(br_sha1_context *ctx);
+
+/**
+ * \brief Inject some data bytes in a running SHA-1 computation.
+ *
+ * The provided context is updated with some data bytes. If the number
+ * of bytes (`len`) is zero, then the data pointer (`data`) is ignored
+ * and may be `NULL`, and this function does nothing.
+ *
+ * \param ctx pointer to the context structure.
+ * \param data pointer to the injected data.
+ * \param len injected data length (in bytes).
+ */
+void br_sha1_update(br_sha1_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Compute SHA-1 output.
+ *
+ * The SHA-1 output for the concatenation of all bytes injected in the
+ * provided context since the last initialisation or reset call, is
+ * computed and written in the buffer pointed to by `out`. The context
+ * itself is not modified, so extra bytes may be injected afterwards
+ * to continue that computation.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the hash output.
+ */
+void br_sha1_out(const br_sha1_context *ctx, void *out);
+
+/**
+ * \brief Save SHA-1 running state.
+ *
+ * The running state for SHA-1 (output of the last internal block
+ * processing) is written in the buffer pointed to by `out`. The
+ * number of bytes injected since the last initialisation or reset
+ * call is returned. The context is not modified.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the running state.
+ * \return the injected total byte length.
+ */
+uint64_t br_sha1_state(const br_sha1_context *ctx, void *out);
+
+/**
+ * \brief Restore SHA-1 running state.
+ *
+ * The running state for SHA-1 is set to the provided values.
+ *
+ * \param ctx pointer to the context structure.
+ * \param stb source buffer for the running state.
+ * \param count the injected total byte length.
+ */
+void br_sha1_set_state(br_sha1_context *ctx, const void *stb, uint64_t count);
+
+/**
+ * \brief Symbolic identifier for SHA-224.
+ */
+#define br_sha224_ID 3
+
+/**
+ * \brief SHA-224 output size (in bytes).
+ */
+#define br_sha224_SIZE 28
+
+/**
+ * \brief Constant vtable for SHA-224.
+ */
+extern const br_hash_class br_sha224_vtable;
+
+/**
+ * \brief SHA-224 context.
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /**
+ * \brief Pointer to vtable for this context.
+ */
+ const br_hash_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char buf[64];
+ uint64_t count;
+ uint32_t val[8];
+#endif
+} br_sha224_context;
+
+/**
+ * \brief SHA-224 context initialisation.
+ *
+ * This function initialises or resets a context for a new SHA-224
+ * computation. It also sets the vtable pointer.
+ *
+ * \param ctx pointer to the context structure.
+ */
+void br_sha224_init(br_sha224_context *ctx);
+
+/**
+ * \brief Inject some data bytes in a running SHA-224 computation.
+ *
+ * The provided context is updated with some data bytes. If the number
+ * of bytes (`len`) is zero, then the data pointer (`data`) is ignored
+ * and may be `NULL`, and this function does nothing.
+ *
+ * \param ctx pointer to the context structure.
+ * \param data pointer to the injected data.
+ * \param len injected data length (in bytes).
+ */
+void br_sha224_update(br_sha224_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Compute SHA-224 output.
+ *
+ * The SHA-224 output for the concatenation of all bytes injected in the
+ * provided context since the last initialisation or reset call, is
+ * computed and written in the buffer pointed to by `out`. The context
+ * itself is not modified, so extra bytes may be injected afterwards
+ * to continue that computation.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the hash output.
+ */
+void br_sha224_out(const br_sha224_context *ctx, void *out);
+
+/**
+ * \brief Save SHA-224 running state.
+ *
+ * The running state for SHA-224 (output of the last internal block
+ * processing) is written in the buffer pointed to by `out`. The
+ * number of bytes injected since the last initialisation or reset
+ * call is returned. The context is not modified.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the running state.
+ * \return the injected total byte length.
+ */
+uint64_t br_sha224_state(const br_sha224_context *ctx, void *out);
+
+/**
+ * \brief Restore SHA-224 running state.
+ *
+ * The running state for SHA-224 is set to the provided values.
+ *
+ * \param ctx pointer to the context structure.
+ * \param stb source buffer for the running state.
+ * \param count the injected total byte length.
+ */
+void br_sha224_set_state(br_sha224_context *ctx,
+ const void *stb, uint64_t count);
+
+/**
+ * \brief Symbolic identifier for SHA-256.
+ */
+#define br_sha256_ID 4
+
+/**
+ * \brief SHA-256 output size (in bytes).
+ */
+#define br_sha256_SIZE 32
+
+/**
+ * \brief Constant vtable for SHA-256.
+ */
+extern const br_hash_class br_sha256_vtable;
+
+#ifdef BR_DOXYGEN_IGNORE
+/**
+ * \brief SHA-256 context.
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /**
+ * \brief Pointer to vtable for this context.
+ */
+ const br_hash_class *vtable;
+} br_sha256_context;
+#else
+typedef br_sha224_context br_sha256_context;
+#endif
+
+/**
+ * \brief SHA-256 context initialisation.
+ *
+ * This function initialises or resets a context for a new SHA-256
+ * computation. It also sets the vtable pointer.
+ *
+ * \param ctx pointer to the context structure.
+ */
+void br_sha256_init(br_sha256_context *ctx);
+
+#ifdef BR_DOXYGEN_IGNORE
+/**
+ * \brief Inject some data bytes in a running SHA-256 computation.
+ *
+ * The provided context is updated with some data bytes. If the number
+ * of bytes (`len`) is zero, then the data pointer (`data`) is ignored
+ * and may be `NULL`, and this function does nothing.
+ *
+ * \param ctx pointer to the context structure.
+ * \param data pointer to the injected data.
+ * \param len injected data length (in bytes).
+ */
+void br_sha256_update(br_sha256_context *ctx, const void *data, size_t len);
+#else
+#define br_sha256_update br_sha224_update
+#endif
+
+/**
+ * \brief Compute SHA-256 output.
+ *
+ * The SHA-256 output for the concatenation of all bytes injected in the
+ * provided context since the last initialisation or reset call, is
+ * computed and written in the buffer pointed to by `out`. The context
+ * itself is not modified, so extra bytes may be injected afterwards
+ * to continue that computation.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the hash output.
+ */
+void br_sha256_out(const br_sha256_context *ctx, void *out);
+
+#if BR_DOXYGEN_IGNORE
+/**
+ * \brief Save SHA-256 running state.
+ *
+ * The running state for SHA-256 (output of the last internal block
+ * processing) is written in the buffer pointed to by `out`. The
+ * number of bytes injected since the last initialisation or reset
+ * call is returned. The context is not modified.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the running state.
+ * \return the injected total byte length.
+ */
+uint64_t br_sha256_state(const br_sha256_context *ctx, void *out);
+#else
+#define br_sha256_state br_sha224_state
+#endif
+
+#if BR_DOXYGEN_IGNORE
+/**
+ * \brief Restore SHA-256 running state.
+ *
+ * The running state for SHA-256 is set to the provided values.
+ *
+ * \param ctx pointer to the context structure.
+ * \param stb source buffer for the running state.
+ * \param count the injected total byte length.
+ */
+void br_sha256_set_state(br_sha256_context *ctx,
+ const void *stb, uint64_t count);
+#else
+#define br_sha256_set_state br_sha224_set_state
+#endif
+
+/**
+ * \brief Symbolic identifier for SHA-384.
+ */
+#define br_sha384_ID 5
+
+/**
+ * \brief SHA-384 output size (in bytes).
+ */
+#define br_sha384_SIZE 48
+
+/**
+ * \brief Constant vtable for SHA-384.
+ */
+extern const br_hash_class br_sha384_vtable;
+
+/**
+ * \brief SHA-384 context.
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /**
+ * \brief Pointer to vtable for this context.
+ */
+ const br_hash_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char buf[128];
+ uint64_t count;
+ uint64_t val[8];
+#endif
+} br_sha384_context;
+
+/**
+ * \brief SHA-384 context initialisation.
+ *
+ * This function initialises or resets a context for a new SHA-384
+ * computation. It also sets the vtable pointer.
+ *
+ * \param ctx pointer to the context structure.
+ */
+void br_sha384_init(br_sha384_context *ctx);
+
+/**
+ * \brief Inject some data bytes in a running SHA-384 computation.
+ *
+ * The provided context is updated with some data bytes. If the number
+ * of bytes (`len`) is zero, then the data pointer (`data`) is ignored
+ * and may be `NULL`, and this function does nothing.
+ *
+ * \param ctx pointer to the context structure.
+ * \param data pointer to the injected data.
+ * \param len injected data length (in bytes).
+ */
+void br_sha384_update(br_sha384_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Compute SHA-384 output.
+ *
+ * The SHA-384 output for the concatenation of all bytes injected in the
+ * provided context since the last initialisation or reset call, is
+ * computed and written in the buffer pointed to by `out`. The context
+ * itself is not modified, so extra bytes may be injected afterwards
+ * to continue that computation.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the hash output.
+ */
+void br_sha384_out(const br_sha384_context *ctx, void *out);
+
+/**
+ * \brief Save SHA-384 running state.
+ *
+ * The running state for SHA-384 (output of the last internal block
+ * processing) is written in the buffer pointed to by `out`. The
+ * number of bytes injected since the last initialisation or reset
+ * call is returned. The context is not modified.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the running state.
+ * \return the injected total byte length.
+ */
+uint64_t br_sha384_state(const br_sha384_context *ctx, void *out);
+
+/**
+ * \brief Restore SHA-384 running state.
+ *
+ * The running state for SHA-384 is set to the provided values.
+ *
+ * \param ctx pointer to the context structure.
+ * \param stb source buffer for the running state.
+ * \param count the injected total byte length.
+ */
+void br_sha384_set_state(br_sha384_context *ctx,
+ const void *stb, uint64_t count);
+
+/**
+ * \brief Symbolic identifier for SHA-512.
+ */
+#define br_sha512_ID 6
+
+/**
+ * \brief SHA-512 output size (in bytes).
+ */
+#define br_sha512_SIZE 64
+
+/**
+ * \brief Constant vtable for SHA-512.
+ */
+extern const br_hash_class br_sha512_vtable;
+
+#ifdef BR_DOXYGEN_IGNORE
+/**
+ * \brief SHA-512 context.
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /**
+ * \brief Pointer to vtable for this context.
+ */
+ const br_hash_class *vtable;
+} br_sha512_context;
+#else
+typedef br_sha384_context br_sha512_context;
+#endif
+
+/**
+ * \brief SHA-512 context initialisation.
+ *
+ * This function initialises or resets a context for a new SHA-512
+ * computation. It also sets the vtable pointer.
+ *
+ * \param ctx pointer to the context structure.
+ */
+void br_sha512_init(br_sha512_context *ctx);
+
+#ifdef BR_DOXYGEN_IGNORE
+/**
+ * \brief Inject some data bytes in a running SHA-512 computation.
+ *
+ * The provided context is updated with some data bytes. If the number
+ * of bytes (`len`) is zero, then the data pointer (`data`) is ignored
+ * and may be `NULL`, and this function does nothing.
+ *
+ * \param ctx pointer to the context structure.
+ * \param data pointer to the injected data.
+ * \param len injected data length (in bytes).
+ */
+void br_sha512_update(br_sha512_context *ctx, const void *data, size_t len);
+#else
+#define br_sha512_update br_sha384_update
+#endif
+
+/**
+ * \brief Compute SHA-512 output.
+ *
+ * The SHA-512 output for the concatenation of all bytes injected in the
+ * provided context since the last initialisation or reset call, is
+ * computed and written in the buffer pointed to by `out`. The context
+ * itself is not modified, so extra bytes may be injected afterwards
+ * to continue that computation.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the hash output.
+ */
+void br_sha512_out(const br_sha512_context *ctx, void *out);
+
+#ifdef BR_DOXYGEN_IGNORE
+/**
+ * \brief Save SHA-512 running state.
+ *
+ * The running state for SHA-512 (output of the last internal block
+ * processing) is written in the buffer pointed to by `out`. The
+ * number of bytes injected since the last initialisation or reset
+ * call is returned. The context is not modified.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the running state.
+ * \return the injected total byte length.
+ */
+uint64_t br_sha512_state(const br_sha512_context *ctx, void *out);
+#else
+#define br_sha512_state br_sha384_state
+#endif
+
+#ifdef BR_DOXYGEN_IGNORE
+/**
+ * \brief Restore SHA-512 running state.
+ *
+ * The running state for SHA-512 is set to the provided values.
+ *
+ * \param ctx pointer to the context structure.
+ * \param stb source buffer for the running state.
+ * \param count the injected total byte length.
+ */
+void br_sha512_set_state(br_sha512_context *ctx,
+ const void *stb, uint64_t count);
+#else
+#define br_sha512_set_state br_sha384_set_state
+#endif
+
+/*
+ * "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.
+ */
+
+/**
+ * \brief Symbolic identifier for MD5+SHA-1.
+ *
+ * MD5+SHA-1 is the concatenation of MD5 and SHA-1, computed over the
+ * same input. It is not one of the functions identified in TLS, so
+ * we give it a symbolic identifier of value 0.
+ */
+#define br_md5sha1_ID 0
+
+/**
+ * \brief MD5+SHA-1 output size (in bytes).
+ */
+#define br_md5sha1_SIZE 36
+
+/**
+ * \brief Constant vtable for MD5+SHA-1.
+ */
+extern const br_hash_class br_md5sha1_vtable;
+
+/**
+ * \brief MD5+SHA-1 context.
+ *
+ * First field is a pointer to the vtable; it is set by the initialisation
+ * function. Other fields are not supposed to be accessed by user code.
+ */
+typedef struct {
+ /**
+ * \brief Pointer to vtable for this context.
+ */
+ const br_hash_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char buf[64];
+ uint64_t count;
+ uint32_t val_md5[4];
+ uint32_t val_sha1[5];
+#endif
+} br_md5sha1_context;
+
+/**
+ * \brief MD5+SHA-1 context initialisation.
+ *
+ * This function initialises or resets a context for a new SHA-512
+ * computation. It also sets the vtable pointer.
+ *
+ * \param ctx pointer to the context structure.
+ */
+void br_md5sha1_init(br_md5sha1_context *ctx);
+
+/**
+ * \brief Inject some data bytes in a running MD5+SHA-1 computation.
+ *
+ * The provided context is updated with some data bytes. If the number
+ * of bytes (`len`) is zero, then the data pointer (`data`) is ignored
+ * and may be `NULL`, and this function does nothing.
+ *
+ * \param ctx pointer to the context structure.
+ * \param data pointer to the injected data.
+ * \param len injected data length (in bytes).
+ */
+void br_md5sha1_update(br_md5sha1_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Compute MD5+SHA-1 output.
+ *
+ * The MD5+SHA-1 output for the concatenation of all bytes injected in the
+ * provided context since the last initialisation or reset call, is
+ * computed and written in the buffer pointed to by `out`. The context
+ * itself is not modified, so extra bytes may be injected afterwards
+ * to continue that computation.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the hash output.
+ */
+void br_md5sha1_out(const br_md5sha1_context *ctx, void *out);
+
+/**
+ * \brief Save MD5+SHA-1 running state.
+ *
+ * The running state for MD5+SHA-1 (output of the last internal block
+ * processing) is written in the buffer pointed to by `out`. The
+ * number of bytes injected since the last initialisation or reset
+ * call is returned. The context is not modified.
+ *
+ * \param ctx pointer to the context structure.
+ * \param out destination buffer for the running state.
+ * \return the injected total byte length.
+ */
+uint64_t br_md5sha1_state(const br_md5sha1_context *ctx, void *out);
+
+/**
+ * \brief Restore MD5+SHA-1 running state.
+ *
+ * The running state for MD5+SHA-1 is set to the provided values.
+ *
+ * \param ctx pointer to the context structure.
+ * \param stb source buffer for the running state.
+ * \param count the injected total byte length.
+ */
+void br_md5sha1_set_state(br_md5sha1_context *ctx,
+ const void *stb, uint64_t count);
+
+/**
+ * \brief Aggregate context for configurable hash function support.
+ *
+ * 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_md5sha1_context md5sha1;
+} 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.
+ */
+
+/**
+ * \brief Multi-hasher context structure.
+ *
+ * The multi-hasher runs up to six hash functions in the standard TLS list
+ * (MD5, SHA-1, SHA-224, SHA-256, SHA-384 and SHA-512) in parallel, over
+ * the same input.
+ *
+ * The multi-hasher does _not_ follow the OOP structure with a vtable.
+ * Instead, it is configured with the vtables of the hash functions it
+ * should run. Structure fields are not supposed to be accessed directly.
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char buf[128];
+ uint64_t count;
+ uint32_t val_32[25];
+ uint64_t val_64[16];
+ const br_hash_class *impl[6];
+#endif
+} br_multihash_context;
+
+/**
+ * \brief Clear a multi-hasher context.
+ *
+ * This should always be called once on a given context, _before_ setting
+ * the implementation pointers.
+ *
+ * \param ctx the multi-hasher context.
+ */
+void br_multihash_zero(br_multihash_context *ctx);
+
+/**
+ * \brief Set a hash function implementation.
+ *
+ * Implementations shall be set _after_ clearing the context (with
+ * `br_multihash_zero()`) but _before_ initialising the computation
+ * (with `br_multihash_init()`). The hash function implementation
+ * MUST be one of the standard hash functions (MD5, SHA-1, SHA-224,
+ * SHA-256, SHA-384 or SHA-512); it may also be `NULL` to remove
+ * an implementation from the multi-hasher.
+ *
+ * \param ctx the multi-hasher context.
+ * \param id the hash function symbolic identifier.
+ * \param impl the hash function vtable, or `NULL`.
+ */
+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;
+}
+
+/**
+ * \brief Get a hash function implementation.
+ *
+ * This function returns the currently configured vtable for a given
+ * hash function (by symbolic ID). If no such function was configured in
+ * the provided multi-hasher context, then this function returns `NULL`.
+ *
+ * \param ctx the multi-hasher context.
+ * \param id the hash function symbolic identifier.
+ * \return the hash function vtable, or `NULL`.
+ */
+static inline const br_hash_class *
+br_multihash_getimpl(const br_multihash_context *ctx, int id)
+{
+ return ctx->impl[id - 1];
+}
+
+/**
+ * \brief Reset a multi-hasher context.
+ *
+ * This function prepares the context for a new hashing computation,
+ * for all implementations configured at that point.
+ *
+ * \param ctx the multi-hasher context.
+ */
+void br_multihash_init(br_multihash_context *ctx);
+
+/**
+ * \brief Inject some data bytes in a running multi-hashing computation.
+ *
+ * The provided context is updated with some data bytes. If the number
+ * of bytes (`len`) is zero, then the data pointer (`data`) is ignored
+ * and may be `NULL`, and this function does nothing.
+ *
+ * \param ctx pointer to the context structure.
+ * \param data pointer to the injected data.
+ * \param len injected data length (in bytes).
+ */
+void br_multihash_update(br_multihash_context *ctx,
+ const void *data, size_t len);
+
+/**
+ * \brief Compute a hash output from a multi-hasher.
+ *
+ * The hash output for the concatenation of all bytes injected in the
+ * provided context since the last initialisation or reset call, is
+ * computed and written in the buffer pointed to by `dst`. The hash
+ * function to use is identified by `id` and must be one of the standard
+ * hash functions. If that hash function was indeed configured in the
+ * multi-hasher context, the corresponding hash value is written in
+ * `dst` and its length (in bytes) is returned. If the hash function
+ * was _not_ configured, then nothing is written in `dst` and 0 is
+ * returned.
+ *
+ * The context itself is not modified, so extra bytes may be injected
+ * afterwards to continue the hash computations.
+ *
+ * \param ctx pointer to the context structure.
+ * \param id the hash function symbolic identifier.
+ * \param dst destination buffer for the hash output.
+ * \return the hash output length (in bytes), or 0.
+ */
+size_t br_multihash_out(const br_multihash_context *ctx, int id, void *dst);
+
+/**
+ * \brief 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.
+ * The `y` array is updated.
+ *
+ * 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.
+ *
+ * \param y the array to update.
+ * \param h the GHASH key.
+ * \param data the input data (may be `NULL` if `len` is zero).
+ * \param len the input data length (in bytes).
+ */
+typedef void (*br_ghash)(void *y, const void *h, const void *data, size_t len);
+
+/**
+ * \brief GHASH implementation using multiplications (mixed 32-bit).
+ *
+ * This implementation uses multiplications of 32-bit values, with a
+ * 64-bit result. It is constant-time (if multiplications are
+ * constant-time).
+ *
+ * \param y the array to update.
+ * \param h the GHASH key.
+ * \param data the input data (may be `NULL` if `len` is zero).
+ * \param len the input data length (in bytes).
+ */
+void br_ghash_ctmul(void *y, const void *h, const void *data, size_t len);
+
+/**
+ * \brief GHASH implementation using multiplications (strict 32-bit).
+ *
+ * This implementation uses multiplications of 32-bit values, with a
+ * 32-bit result. It is usually somewhat slower than `br_ghash_ctmul()`,
+ * but it is expected to be faster on architectures for which the
+ * 32-bit multiplication opcode does not yield the upper 32 bits of the
+ * product. It is constant-time (if multiplications are constant-time).
+ *
+ * \param y the array to update.
+ * \param h the GHASH key.
+ * \param data the input data (may be `NULL` if `len` is zero).
+ * \param len the input data length (in bytes).
+ */
+void br_ghash_ctmul32(void *y, const void *h, const void *data, size_t len);
+
+/**
+ * \brief GHASH implementation using multiplications (64-bit).
+ *
+ * This implementation uses multiplications of 64-bit values, with a
+ * 64-bit result. It is constant-time (if multiplications are
+ * constant-time). It is substantially faster than `br_ghash_ctmul()`
+ * and `br_ghash_ctmul32()` on most 64-bit architectures.
+ *
+ * \param y the array to update.
+ * \param h the GHASH key.
+ * \param data the input data (may be `NULL` if `len` is zero).
+ * \param len the input data length (in bytes).
+ */
+void br_ghash_ctmul64(void *y, const void *h, const void *data, size_t len);
+
+/**
+ * \brief GHASH implementation using the `pclmulqdq` opcode (part of the
+ * AES-NI instructions).
+ *
+ * This implementation is available only on x86 platforms where the
+ * compiler supports the relevant intrinsic functions. Even if the
+ * compiler supports these functions, the local CPU might not support
+ * the `pclmulqdq` opcode, meaning that a call will fail with an
+ * illegal instruction exception. To safely obtain a pointer to this
+ * function when supported (or 0 otherwise), use `br_ghash_pclmul_get()`.
+ *
+ * \param y the array to update.
+ * \param h the GHASH key.
+ * \param data the input data (may be `NULL` if `len` is zero).
+ * \param len the input data length (in bytes).
+ */
+void br_ghash_pclmul(void *y, const void *h, const void *data, size_t len);
+
+/**
+ * \brief Obtain the `pclmul` GHASH implementation, if available.
+ *
+ * If the `pclmul` implementation was compiled in the library (depending
+ * on the compiler abilities) _and_ the local CPU appears to support the
+ * opcode, then this function will return a pointer to the
+ * `br_ghash_pclmul()` function. Otherwise, it will return `0`.
+ *
+ * \return the `pclmul` GHASH implementation, or `0`.
+ */
+br_ghash br_ghash_pclmul_get(void);
+
+/**
+ * \brief GHASH implementation using the POWER8 opcodes.
+ *
+ * This implementation is available only on POWER8 platforms (and later).
+ * To safely obtain a pointer to this function when supported (or 0
+ * otherwise), use `br_ghash_pwr8_get()`.
+ *
+ * \param y the array to update.
+ * \param h the GHASH key.
+ * \param data the input data (may be `NULL` if `len` is zero).
+ * \param len the input data length (in bytes).
+ */
+void br_ghash_pwr8(void *y, const void *h, const void *data, size_t len);
+
+/**
+ * \brief Obtain the `pwr8` GHASH implementation, if available.
+ *
+ * If the `pwr8` implementation was compiled in the library (depending
+ * on the compiler abilities) _and_ the local CPU appears to support the
+ * opcode, then this function will return a pointer to the
+ * `br_ghash_pwr8()` function. Otherwise, it will return `0`.
+ *
+ * \return the `pwr8` GHASH implementation, or `0`.
+ */
+br_ghash br_ghash_pwr8_get(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/bearssl/inc/bearssl_hmac.h b/contrib/bearssl/inc/bearssl_hmac.h
new file mode 100644
index 000000000000..4dc01ca31203
--- /dev/null
+++ b/contrib/bearssl/inc/bearssl_hmac.h
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_hmac.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.
+ */
+
+/**
+ * \brief HMAC key context.
+ *
+ * The HMAC key context is initialised with a hash function implementation
+ * and a secret key. Contents are opaque (callers should not access them
+ * directly). The caller is responsible for allocating the context where
+ * appropriate. Context initialisation and usage incurs no dynamic
+ * allocation, so there is no release function.
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ const br_hash_class *dig_vtable;
+ unsigned char ksi[64], kso[64];
+#endif
+} br_hmac_key_context;
+
+/**
+ * \brief HMAC key context initialisation.
+ *
+ * Initialise the key context with the provided key, using the hash function
+ * identified by `digest_vtable`. This supports arbitrary key lengths.
+ *
+ * \param kc HMAC key context to initialise.
+ * \param digest_vtable pointer to the hash function implementation vtable.
+ * \param key pointer to the HMAC secret key.
+ * \param key_len HMAC secret key length (in bytes).
+ */
+void br_hmac_key_init(br_hmac_key_context *kc,
+ const br_hash_class *digest_vtable, const void *key, size_t key_len);
+
+/*
+ * \brief Get the underlying hash function.
+ *
+ * This function returns a pointer to the implementation vtable of the
+ * hash function used for this HMAC key context.
+ *
+ * \param kc HMAC key context.
+ * \return the hash function implementation.
+ */
+static inline const br_hash_class *br_hmac_key_get_digest(
+ const br_hmac_key_context *kc)
+{
+ return kc->dig_vtable;
+}
+
+/**
+ * \brief HMAC computation context.
+ *
+ * The HMAC computation context maintains the state for a single HMAC
+ * computation. It is modified as input bytes are injected. The context
+ * is caller-allocated and has no release function since it does not
+ * dynamically allocate external resources. Its contents are opaque.
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ br_hash_compat_context dig;
+ unsigned char kso[64];
+ size_t out_len;
+#endif
+} br_hmac_context;
+
+/**
+ * \brief HMAC computation initialisation.
+ *
+ * Initialise 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. The
+ * "natural output length" is the output length of the underlying hash
+ * function.
+ *
+ * \param ctx HMAC context to initialise.
+ * \param kc HMAC key context (already initialised with the key).
+ * \param out_len HMAC output length (0 to select "natural length").
+ */
+void br_hmac_init(br_hmac_context *ctx,
+ const br_hmac_key_context *kc, size_t out_len);
+
+/**
+ * \brief Get the HMAC output size.
+ *
+ * The HMAC output size is the number of bytes that will actually be
+ * produced with `br_hmac_out()` with the provided context. This function
+ * MUST NOT be called on a non-initialised HMAC computation context.
+ * The returned value is the minimum of the HMAC natural length (output
+ * size of the underlying hash function) and the `out_len` parameter which
+ * was used with the last `br_hmac_init()` call on that context (if the
+ * initialisation `out_len` parameter was 0, then this function will
+ * return the HMAC natural length).
+ *
+ * \param ctx the (already initialised) HMAC computation context.
+ * \return the HMAC actual output size.
+ */
+static inline size_t
+br_hmac_size(br_hmac_context *ctx)
+{
+ return ctx->out_len;
+}
+
+/*
+ * \brief Get the underlying hash function.
+ *
+ * This function returns a pointer to the implementation vtable of the
+ * hash function used for this HMAC context.
+ *
+ * \param hc HMAC context.
+ * \return the hash function implementation.
+ */
+static inline const br_hash_class *br_hmac_get_digest(
+ const br_hmac_context *hc)
+{
+ return hc->dig.vtable;
+}
+
+/**
+ * \brief Inject some bytes in HMAC.
+ *
+ * The provided `len` bytes are injected as extra input in the HMAC
+ * computation incarnated by the `ctx` HMAC context. It is acceptable
+ * that `len` is zero, in which case `data` is ignored (and may be
+ * `NULL`) and this function does nothing.
+ */
+void br_hmac_update(br_hmac_context *ctx, const void *data, size_t len);
+
+/**
+ * \brief Compute the HMAC output.
+ *
+ * The destination buffer MUST be large enough to accommodate the result;
+ * its length is at most the "natural length" of HMAC (i.e. the output
+ * length of the underlying hash function). 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).
+ *
+ * \param ctx HMAC computation context.
+ * \param out destination buffer for the HMAC output.
+ * \return the produced value length (in bytes).
+ */
+size_t br_hmac_out(const br_hmac_context *ctx, void *out);
+
+/**
+ * \brief Constant-time HMAC computation.
+ *
+ * This function 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 byte contents 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<sup>30</sup>
+ * (i.e. about one gigabyte).
+ *
+ * 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.
+ *
+ * \param ctx the (already initialised) HMAC computation context.
+ * \param data the extra input bytes.
+ * \param len the extra input length (in bytes).
+ * \param min_len minimum extra input length (in bytes).
+ * \param max_len maximum extra input length (in bytes).
+ * \param out destination buffer for the HMAC output.
+ * \return the produced value 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);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/bearssl/inc/bearssl_kdf.h b/contrib/bearssl/inc/bearssl_kdf.h
new file mode 100644
index 000000000000..955b84367ee5
--- /dev/null
+++ b/contrib/bearssl/inc/bearssl_kdf.h
@@ -0,0 +1,284 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef BR_BEARSSL_KDF_H__
+#define BR_BEARSSL_KDF_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "bearssl_hash.h"
+#include "bearssl_hmac.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_kdf.h
+ *
+ * # Key Derivation Functions
+ *
+ * KDF are functions that takes a variable length input, and provide a
+ * variable length output, meant to be used to derive subkeys from a
+ * master key.
+ *
+ * ## HKDF
+ *
+ * HKDF is a KDF defined by [RFC 5869](https://tools.ietf.org/html/rfc5869).
+ * It is based on HMAC, itself using an underlying hash function. Any
+ * hash function can be used, as long as it is compatible with the rules
+ * for the HMAC implementation (i.e. output size is 64 bytes or less, hash
+ * internal state size is 64 bytes or less, and the internal block length is
+ * a power of 2 between 16 and 256 bytes). HKDF has two phases:
+ *
+ * - HKDF-Extract: the input data in ingested, along with a "salt" value.
+ *
+ * - HKDF-Expand: the output is produced, from the result of processing
+ * the input and salt, and using an extra non-secret parameter called
+ * "info".
+ *
+ * The "salt" and "info" strings are non-secret and can be empty. Their role
+ * is normally to bind the input and output, respectively, to conventional
+ * identifiers that qualifu them within the used protocol or application.
+ *
+ * The implementation defined in this file uses the following functions:
+ *
+ * - `br_hkdf_init()`: initialize an HKDF context, with a hash function,
+ * and the salt. This starts the HKDF-Extract process.
+ *
+ * - `br_hkdf_inject()`: inject more input bytes. This function may be
+ * called repeatedly if the input data is provided by chunks.
+ *
+ * - `br_hkdf_flip()`: end the HKDF-Extract process, and start the
+ * HKDF-Expand process.
+ *
+ * - `br_hkdf_produce()`: get the next bytes of output. This function
+ * may be called several times to obtain the full output by chunks.
+ * For correct HKDF processing, the same "info" string must be
+ * provided for each call.
+ *
+ * Note that the HKDF total output size (the number of bytes that
+ * HKDF-Expand is willing to produce) is limited: if the hash output size
+ * is _n_ bytes, then the maximum output size is _255*n_.
+ *
+ * ## SHAKE
+ *
+ * SHAKE is defined in
+ * [FIPS 202](https://csrc.nist.gov/publications/detail/fips/202/final)
+ * under two versions: SHAKE128 and SHAKE256, offering an alleged
+ * "security level" of 128 and 256 bits, respectively (SHAKE128 is
+ * about 20 to 25% faster than SHAKE256). SHAKE internally relies on
+ * the Keccak family of sponge functions, not on any externally provided
+ * hash function. Contrary to HKDF, SHAKE does not have a concept of
+ * either a "salt" or an "info" string. The API consists in four
+ * functions:
+ *
+ * - `br_shake_init()`: initialize a SHAKE context for a given
+ * security level.
+ *
+ * - `br_shake_inject()`: inject more input bytes. This function may be
+ * called repeatedly if the input data is provided by chunks.
+ *
+ * - `br_shake_flip()`: end the data injection process, and start the
+ * data production process.
+ *
+ * - `br_shake_produce()`: get the next bytes of output. This function
+ * may be called several times to obtain the full output by chunks.
+ */
+
+/**
+ * \brief HKDF context.
+ *
+ * The HKDF context is initialized with a hash function implementation
+ * and a salt value. Contents are opaque (callers should not access them
+ * directly). The caller is responsible for allocating the context where
+ * appropriate. Context initialisation and usage incurs no dynamic
+ * allocation, so there is no release function.
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ union {
+ br_hmac_context hmac_ctx;
+ br_hmac_key_context prk_ctx;
+ } u;
+ unsigned char buf[64];
+ size_t ptr;
+ size_t dig_len;
+ unsigned chunk_num;
+#endif
+} br_hkdf_context;
+
+/**
+ * \brief HKDF context initialization.
+ *
+ * The underlying hash function and salt value are provided. Arbitrary
+ * salt lengths can be used.
+ *
+ * HKDF makes a difference between a salt of length zero, and an
+ * absent salt (the latter being equivalent to a salt consisting of
+ * bytes of value zero, of the same length as the hash function output).
+ * If `salt_len` is zero, then this function assumes that the salt is
+ * present but of length zero. To specify an _absent_ salt, use
+ * `BR_HKDF_NO_SALT` as `salt` parameter (`salt_len` is then ignored).
+ *
+ * \param hc HKDF context to initialise.
+ * \param digest_vtable pointer to the hash function implementation vtable.
+ * \param salt HKDF-Extract salt.
+ * \param salt_len HKDF-Extract salt length (in bytes).
+ */
+void br_hkdf_init(br_hkdf_context *hc, const br_hash_class *digest_vtable,
+ const void *salt, size_t salt_len);
+
+/**
+ * \brief The special "absent salt" value for HKDF.
+ */
+#define BR_HKDF_NO_SALT (&br_hkdf_no_salt)
+
+#ifndef BR_DOXYGEN_IGNORE
+extern const unsigned char br_hkdf_no_salt;
+#endif
+
+/**
+ * \brief HKDF input injection (HKDF-Extract).
+ *
+ * This function injects some more input bytes ("key material") into
+ * HKDF. This function may be called several times, after `br_hkdf_init()`
+ * but before `br_hkdf_flip()`.
+ *
+ * \param hc HKDF context.
+ * \param ikm extra input bytes.
+ * \param ikm_len number of extra input bytes.
+ */
+void br_hkdf_inject(br_hkdf_context *hc, const void *ikm, size_t ikm_len);
+
+/**
+ * \brief HKDF switch to the HKDF-Expand phase.
+ *
+ * This call terminates the HKDF-Extract process (input injection), and
+ * starts the HKDF-Expand process (output production).
+ *
+ * \param hc HKDF context.
+ */
+void br_hkdf_flip(br_hkdf_context *hc);
+
+/**
+ * \brief HKDF output production (HKDF-Expand).
+ *
+ * Produce more output bytes from the current state. This function may be
+ * called several times, but only after `br_hkdf_flip()`.
+ *
+ * Returned value is the number of actually produced bytes. The total
+ * output length is limited to 255 times the output length of the
+ * underlying hash function.
+ *
+ * \param hc HKDF context.
+ * \param info application specific information string.
+ * \param info_len application specific information string length (in bytes).
+ * \param out destination buffer for the HKDF output.
+ * \param out_len the length of the requested output (in bytes).
+ * \return the produced output length (in bytes).
+ */
+size_t br_hkdf_produce(br_hkdf_context *hc,
+ const void *info, size_t info_len, void *out, size_t out_len);
+
+/**
+ * \brief SHAKE context.
+ *
+ * The HKDF context is initialized with a "security level". The internal
+ * notion is called "capacity"; the capacity is twice the security level
+ * (for instance, SHAKE128 has capacity 256).
+ *
+ * The caller is responsible for allocating the context where
+ * appropriate. Context initialisation and usage incurs no dynamic
+ * allocation, so there is no release function.
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char dbuf[200];
+ size_t dptr;
+ size_t rate;
+ uint64_t A[25];
+#endif
+} br_shake_context;
+
+/**
+ * \brief SHAKE context initialization.
+ *
+ * The context is initialized for the provided "security level".
+ * Internally, this sets the "capacity" to twice the security level;
+ * thus, for SHAKE128, the `security_level` parameter should be 128,
+ * which corresponds to a 256-bit capacity.
+ *
+ * Allowed security levels are all multiples of 32, from 32 to 768,
+ * inclusive. Larger security levels imply lower performance; levels
+ * beyond 256 bits don't make much sense. Standard levels are 128
+ * and 256 bits (for SHAKE128 and SHAKE256, respectively).
+ *
+ * \param sc SHAKE context to initialise.
+ * \param security_level security level (in bits).
+ */
+void br_shake_init(br_shake_context *sc, int security_level);
+
+/**
+ * \brief SHAKE input injection.
+ *
+ * This function injects some more input bytes ("key material") into
+ * SHAKE. This function may be called several times, after `br_shake_init()`
+ * but before `br_shake_flip()`.
+ *
+ * \param sc SHAKE context.
+ * \param data extra input bytes.
+ * \param len number of extra input bytes.
+ */
+void br_shake_inject(br_shake_context *sc, const void *data, size_t len);
+
+/**
+ * \brief SHAKE switch to production phase.
+ *
+ * This call terminates the input injection process, and starts the
+ * output production process.
+ *
+ * \param sc SHAKE context.
+ */
+void br_shake_flip(br_shake_context *hc);
+
+/**
+ * \brief SHAKE output production.
+ *
+ * Produce more output bytes from the current state. This function may be
+ * called several times, but only after `br_shake_flip()`.
+ *
+ * There is no practical limit to the number of bytes that may be produced.
+ *
+ * \param sc SHAKE context.
+ * \param out destination buffer for the SHAKE output.
+ * \param len the length of the requested output (in bytes).
+ */
+void br_shake_produce(br_shake_context *sc, void *out, size_t len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/bearssl/inc/bearssl_pem.h b/contrib/bearssl/inc/bearssl_pem.h
new file mode 100644
index 000000000000..8dba58272cbb
--- /dev/null
+++ b/contrib/bearssl/inc/bearssl_pem.h
@@ -0,0 +1,294 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_pem.h
+ *
+ * # PEM Support
+ *
+ * PEM is a traditional encoding layer use to store binary objects (in
+ * particular X.509 certificates, and private keys) in text files. While
+ * the acronym comes from an old, defunct standard ("Privacy Enhanced
+ * Mail"), the format has been reused, with some variations, by many
+ * systems, and is a _de facto_ standard, even though it is not, actually,
+ * specified in all clarity anywhere.
+ *
+ * ## Format Details
+ *
+ * BearSSL contains a generic, streamed PEM decoder, which handles the
+ * following format:
+ *
+ * - The input source (a sequence of bytes) is assumed to be the
+ * encoding of a text file in an ASCII-compatible charset. This
+ * includes ISO-8859-1, Windows-1252, and UTF-8 encodings. Each
+ * line ends on a newline character (U+000A LINE FEED). The
+ * U+000D CARRIAGE RETURN characters are ignored, so the code
+ * accepts both Windows-style and Unix-style line endings.
+ *
+ * - Each object begins with a banner that occurs at the start of
+ * a line; the first banner characters are "`-----BEGIN `" (five
+ * dashes, the word "BEGIN", and a space). The banner matching is
+ * not case-sensitive.
+ *
+ * - The _object name_ consists in the characters that follow the
+ * banner start sequence, up to the end of the line, but without
+ * trailing dashes (in "normal" PEM, there are five trailing
+ * dashes, but this implementation is not picky about these dashes).
+ * The BearSSL decoder normalises the name characters to uppercase
+ * (for ASCII letters only) and accepts names up to 127 characters.
+ *
+ * - The object ends with a banner that again occurs at the start of
+ * a line, and starts with "`-----END `" (again case-insensitive).
+ *
+ * - Between that start and end banner, only Base64 data shall occur.
+ * Base64 converts each sequence of three bytes into four
+ * characters; the four characters are ASCII letters, digits, "`+`"
+ * or "`-`" signs, and one or two "`=`" signs may occur in the last
+ * quartet. Whitespace is ignored (whitespace is any ASCII character
+ * of code 32 or less, so control characters are whitespace) and
+ * lines may have arbitrary length; the only restriction is that the
+ * four characters of a quartet must appear on the same line (no
+ * line break inside a quartet).
+ *
+ * - A single file may contain more than one PEM object. Bytes that
+ * occur between objects are ignored.
+ *
+ *
+ * ## PEM Decoder API
+ *
+ * The PEM decoder offers a state-machine API. The caller allocates a
+ * decoder context, then injects source bytes. Source bytes are pushed
+ * with `br_pem_decoder_push()`. The decoder stops accepting bytes when
+ * it reaches an "event", which is either the start of an object, the
+ * end of an object, or a decoding error within an object.
+ *
+ * The `br_pem_decoder_event()` function is used to obtain the current
+ * event; it also clears it, thus allowing the decoder to accept more
+ * bytes. When a object start event is raised, the decoder context
+ * offers the found object name (normalised to ASCII uppercase).
+ *
+ * When an object is reached, the caller must set an appropriate callback
+ * function, which will receive (by chunks) the decoded object data.
+ *
+ * Since the decoder context makes no dynamic allocation, it requires
+ * no explicit deallocation.
+ */
+
+/**
+ * \brief PEM decoder context.
+ *
+ * Contents are opaque (they should not be accessed directly).
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ /* 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;
+#endif
+} br_pem_decoder_context;
+
+/**
+ * \brief Initialise a PEM decoder structure.
+ *
+ * \param ctx decoder context to initialise.
+ */
+void br_pem_decoder_init(br_pem_decoder_context *ctx);
+
+/**
+ * \brief 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 raised. When an
+ * event is raised, it must be read (with `br_pem_decoder_event()`);
+ * until the event is read, this function will return 0.
+ *
+ * \param ctx decoder context.
+ * \param data new data bytes.
+ * \param len number of new data bytes.
+ * \return the number of bytes actually received (may be less than `len`).
+ */
+size_t br_pem_decoder_push(br_pem_decoder_context *ctx,
+ const void *data, size_t len);
+
+/**
+ * \brief Set the receiver for decoded data.
+ *
+ * When an object is entered, the provided function (with opaque context
+ * pointer) will be called repeatedly with successive chunks of decoded
+ * data for that object. If `dest` is set to 0, then decoded data is
+ * simply ignored. The receiver can be set at any time, but, in practice,
+ * it should be called immediately after receiving a "start of object"
+ * event.
+ *
+ * \param ctx decoder context.
+ * \param dest callback for receiving decoded data.
+ * \param dest_ctx opaque context pointer for the `dest` callback.
+ */
+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;
+}
+
+/**
+ * \brief Get the last event.
+ *
+ * If an event was raised, then this function returns the event value, and
+ * also clears it, thereby allowing the decoder to proceed. If no event
+ * was raised since the last call to `br_pem_decoder_event()`, then this
+ * function returns 0.
+ *
+ * \param ctx decoder context.
+ * \return the raised event, or 0.
+ */
+int br_pem_decoder_event(br_pem_decoder_context *ctx);
+
+/**
+ * \brief Event: start of object.
+ *
+ * This event is raised when the start of a new object has been detected.
+ * The object name (normalised to uppercase) can be accessed with
+ * `br_pem_decoder_name()`.
+ */
+#define BR_PEM_BEGIN_OBJ 1
+
+/**
+ * \brief Event: end of object.
+ *
+ * This event is raised when the end of the current object is reached
+ * (normally, i.e. with no decoding error).
+ */
+#define BR_PEM_END_OBJ 2
+
+/**
+ * \brief Event: decoding error.
+ *
+ * This event is raised when decoding fails within 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
+
+/**
+ * \brief Get the name of the encountered object.
+ *
+ * The encountered object name is defined only when the "start of object"
+ * event is raised. That name is normalised to uppercase (for ASCII letters
+ * only) and does not include trailing dashes.
+ *
+ * \param ctx decoder context.
+ * \return the current object name.
+ */
+static inline const char *
+br_pem_decoder_name(br_pem_decoder_context *ctx)
+{
+ return ctx->name;
+}
+
+/**
+ * \brief Encode an object in PEM.
+ *
+ * This function encodes the provided binary object (`data`, of length `len`
+ * bytes) into PEM. The `banner` text will be included in the header and
+ * footer (e.g. use `"CERTIFICATE"` to get a `"BEGIN CERTIFICATE"` header).
+ *
+ * The length (in characters) of the PEM output is returned; that length
+ * does NOT include the terminating zero, that this function nevertheless
+ * adds. If using the returned value for allocation purposes, the allocated
+ * buffer size MUST be at least one byte larger than the returned size.
+ *
+ * If `dest` is `NULL`, then the encoding does not happen; however, the
+ * length of the encoded object is still computed and returned.
+ *
+ * The `data` pointer may be `NULL` only if `len` is zero (when encoding
+ * an object of length zero, which is not very useful), or when `dest`
+ * is `NULL` (in that case, source data bytes are ignored).
+ *
+ * Some `flags` can be specified to alter the encoding behaviour:
+ *
+ * - If `BR_PEM_LINE64` is set, then line-breaking will occur after
+ * every 64 characters of output, instead of the default of 76.
+ *
+ * - If `BR_PEM_CRLF` is set, then end-of-line sequence will use
+ * CR+LF instead of a single LF.
+ *
+ * The `data` and `dest` buffers may overlap, in which case the source
+ * binary data is destroyed in the process. Note that the PEM-encoded output
+ * is always larger than the source binary.
+ *
+ * \param dest the destination buffer (or `NULL`).
+ * \param data the source buffer (can be `NULL` in some cases).
+ * \param len the source length (in bytes).
+ * \param banner the PEM banner expression.
+ * \param flags the behavioural flags.
+ * \return the PEM object length (in characters), EXCLUDING the final zero.
+ */
+size_t br_pem_encode(void *dest, const void *data, size_t len,
+ const char *banner, unsigned flags);
+
+/**
+ * \brief PEM encoding flag: split lines at 64 characters.
+ */
+#define BR_PEM_LINE64 0x0001
+
+/**
+ * \brief PEM encoding flag: use CR+LF line endings.
+ */
+#define BR_PEM_CRLF 0x0002
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/bearssl/inc/bearssl_prf.h b/contrib/bearssl/inc/bearssl_prf.h
new file mode 100644
index 000000000000..fdf608c85387
--- /dev/null
+++ b/contrib/bearssl/inc/bearssl_prf.h
@@ -0,0 +1,150 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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>
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_prf.h
+ *
+ * # The TLS PRF
+ *
+ * The "PRF" is the pseudorandom function used internally during the
+ * SSL/TLS handshake, notably to expand negotiated shared secrets into
+ * the symmetric encryption keys that will be used to process the
+ * application data.
+ *
+ * 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. Most standard cipher suites
+ * rely on the SHA-256 based PRF, but some use 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. The "seed" is provided as an
+ * arbitrary number of binary chunks, that gets internally concatenated.
+ */
+
+/**
+ * \brief Type for a seed chunk.
+ *
+ * Each chunk may have an arbitrary length, and may be empty (no byte at
+ * all). If the chunk length is zero, then the pointer to the chunk data
+ * may be `NULL`.
+ */
+typedef struct {
+ /**
+ * \brief Pointer to the chunk data.
+ */
+ const void *data;
+
+ /**
+ * \brief Chunk length (in bytes).
+ */
+ size_t len;
+} br_tls_prf_seed_chunk;
+
+/**
+ * \brief PRF implementation for TLS 1.0 and 1.1.
+ *
+ * This PRF is the one specified by TLS 1.0 and 1.1. It internally uses
+ * MD5 and SHA-1.
+ *
+ * \param dst destination buffer.
+ * \param len output length (in bytes).
+ * \param secret secret value (key) for this computation.
+ * \param secret_len length of "secret" (in bytes).
+ * \param label PRF label (zero-terminated ASCII string).
+ * \param seed_num number of seed chunks.
+ * \param seed seed chnks for this computation (usually non-secret).
+ */
+void br_tls10_prf(void *dst, size_t len,
+ const void *secret, size_t secret_len, const char *label,
+ size_t seed_num, const br_tls_prf_seed_chunk *seed);
+
+/**
+ * \brief PRF implementation for TLS 1.2, with SHA-256.
+ *
+ * This PRF is the one specified by TLS 1.2, when the underlying hash
+ * function is SHA-256.
+ *
+ * \param dst destination buffer.
+ * \param len output length (in bytes).
+ * \param secret secret value (key) for this computation.
+ * \param secret_len length of "secret" (in bytes).
+ * \param label PRF label (zero-terminated ASCII string).
+ * \param seed_num number of seed chunks.
+ * \param seed seed chnks for this computation (usually non-secret).
+ */
+void br_tls12_sha256_prf(void *dst, size_t len,
+ const void *secret, size_t secret_len, const char *label,
+ size_t seed_num, const br_tls_prf_seed_chunk *seed);
+
+/**
+ * \brief PRF implementation for TLS 1.2, with SHA-384.
+ *
+ * This PRF is the one specified by TLS 1.2, when the underlying hash
+ * function is SHA-384.
+ *
+ * \param dst destination buffer.
+ * \param len output length (in bytes).
+ * \param secret secret value (key) for this computation.
+ * \param secret_len length of "secret" (in bytes).
+ * \param label PRF label (zero-terminated ASCII string).
+ * \param seed_num number of seed chunks.
+ * \param seed seed chnks for this computation (usually non-secret).
+ */
+void br_tls12_sha384_prf(void *dst, size_t len,
+ const void *secret, size_t secret_len, const char *label,
+ size_t seed_num, const br_tls_prf_seed_chunk *seed);
+
+/**
+ * brief A convenient type name for a PRF implementation.
+ *
+ * \param dst destination buffer.
+ * \param len output length (in bytes).
+ * \param secret secret value (key) for this computation.
+ * \param secret_len length of "secret" (in bytes).
+ * \param label PRF label (zero-terminated ASCII string).
+ * \param seed_num number of seed chunks.
+ * \param seed seed chnks for this computation (usually non-secret).
+ */
+typedef void (*br_tls_prf_impl)(void *dst, size_t len,
+ const void *secret, size_t secret_len, const char *label,
+ size_t seed_num, const br_tls_prf_seed_chunk *seed);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/bearssl/inc/bearssl_rand.h b/contrib/bearssl/inc/bearssl_rand.h
new file mode 100644
index 000000000000..0a9f544fc4c5
--- /dev/null
+++ b/contrib/bearssl/inc/bearssl_rand.h
@@ -0,0 +1,397 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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>
+
+#include "bearssl_block.h"
+#include "bearssl_hash.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_rand.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).
+ *
+ *
+ * ## Procedural and OOP API
+ *
+ * For the PRNG of name "`xxx`", two API are provided. The _procedural_
+ * API defined a context structure `br_xxx_context` and three functions:
+ *
+ * - `br_xxx_init()`
+ *
+ * Initialise the context with an initial seed.
+ *
+ * - `br_xxx_generate()`
+ *
+ * Produce some pseudo-random bytes.
+ *
+ * - `br_xxx_update()`
+ *
+ * Inject some additional seed.
+ *
+ * The initialisation function sets the first context field (`vtable`)
+ * to a pointer to the vtable that supports the OOP API. The OOP API
+ * provides access to the same functions through function pointers,
+ * named `init()`, `generate()` and `update()`.
+ *
+ * Note that the context initialisation method may accept additional
+ * parameters, provided as a 'const void *' pointer at API level. These
+ * additional parameters depend on the implemented PRNG.
+ *
+ *
+ * ## HMAC_DRBG
+ *
+ * HMAC_DRBG is defined in [NIST SP 800-90A Revision
+ * 1](http://nvlpubs.nist.gov/nistpubs/SpecialPublications/NIST.SP.800-90Ar1.pdf).
+ * It uses HMAC repeatedly, over some configurable underlying hash
+ * function. In BearSSL, it is implemented under the "`hmac_drbg`" name.
+ * The "extra parameters" pointer for context initialisation should be
+ * set to a pointer to the vtable for the underlying hash function (e.g.
+ * pointer to `br_sha256_vtable` to use HMAC_DRBG with SHA-256).
+ *
+ * According to the NIST standard, each request shall produce up to
+ * 2<sup>19</sup> bits (i.e. 64 kB of data); moreover, the context shall
+ * be reseeded at least once every 2<sup>48</sup> requests. This
+ * implementation does not maintain the reseed counter (the threshold is
+ * too high to be reached in practice) and does not object to producing
+ * more than 64 kB in a single request; thus, the code cannot fail,
+ * which corresponds to the fact that the API has no room for error
+ * codes. However, this implies that requesting more than 64 kB in one
+ * `generate()` request, or making more than 2<sup>48</sup> requests
+ * without reseeding, is formally out of NIST specification. There is
+ * no currently known security penalty for exceeding the NIST limits,
+ * and, in any case, HMAC_DRBG usage in implementing SSL/TLS always
+ * stays much below these thresholds.
+ *
+ *
+ * ## AESCTR_DRBG
+ *
+ * AESCTR_DRBG is a custom PRNG based on AES-128 in CTR mode. This is
+ * meant to be used only in situations where you are desperate for
+ * speed, and have an hardware-optimized AES/CTR implementation. Whether
+ * this will yield perceptible improvements depends on what you use the
+ * pseudorandom bytes for, and how many you want; for instance, RSA key
+ * pair generation uses a substantial amount of randomness, and using
+ * AESCTR_DRBG instead of HMAC_DRBG yields a 15 to 20% increase in key
+ * generation speed on a recent x86 CPU (Intel Core i7-6567U at 3.30 GHz).
+ *
+ * Internally, it uses CTR mode with successive counter values, starting
+ * at zero (counter value expressed over 128 bits, big-endian convention).
+ * The counter is not allowed to reach 32768; thus, every 32768*16 bytes
+ * at most, the `update()` function is run (on an empty seed, if none is
+ * provided). The `update()` function computes the new AES-128 key by
+ * applying a custom hash function to the concatenation of a state-dependent
+ * word (encryption of an all-one block with the current key) and the new
+ * seed. The custom hash function uses Hirose's construction over AES-256;
+ * see the comments in `aesctr_drbg.c` for details.
+ *
+ * This DRBG does not follow an existing standard, and thus should be
+ * considered as inadequate for production use until it has been properly
+ * analysed.
+ */
+
+/**
+ * \brief Class type for PRNG implementations.
+ *
+ * A `br_prng_class` instance references the methods implementing a PRNG.
+ * Constant instances of this structure are defined for each implemented
+ * PRNG. Such instances are also called "vtables".
+ */
+typedef struct br_prng_class_ br_prng_class;
+struct br_prng_class_ {
+ /**
+ * \brief Size (in bytes) of the context structure appropriate for
+ * running this PRNG.
+ */
+ size_t context_size;
+
+ /**
+ * \brief Initialisation method.
+ *
+ * The context to initialise is provided as a pointer to its
+ * first field (the vtable pointer); this function sets that
+ * first field to a pointer to the vtable.
+ *
+ * The extra parameters depend on the implementation; each
+ * implementation defines what kind of extra parameters it
+ * expects (if any).
+ *
+ * Requirements on the initial seed depend on the implemented
+ * PRNG.
+ *
+ * \param ctx PRNG context to initialise.
+ * \param params extra parameters for the PRNG.
+ * \param seed initial seed.
+ * \param seed_len initial seed length (in bytes).
+ */
+ void (*init)(const br_prng_class **ctx, const void *params,
+ const void *seed, size_t seed_len);
+
+ /**
+ * \brief Random bytes generation.
+ *
+ * This method produces `len` pseudorandom bytes, in the `out`
+ * buffer. The context is updated accordingly.
+ *
+ * \param ctx PRNG context.
+ * \param out output buffer.
+ * \param len number of pseudorandom bytes to produce.
+ */
+ void (*generate)(const br_prng_class **ctx, void *out, size_t len);
+
+ /**
+ * \brief Inject additional seed bytes.
+ *
+ * The provided seed bytes are added into the PRNG internal
+ * entropy pool.
+ *
+ * \param ctx PRNG context.
+ * \param seed additional seed.
+ * \param seed_len additional seed length (in bytes).
+ */
+ void (*update)(const br_prng_class **ctx,
+ const void *seed, size_t seed_len);
+};
+
+/**
+ * \brief Context for HMAC_DRBG.
+ *
+ * The context contents are opaque, except the first field, which
+ * supports OOP.
+ */
+typedef struct {
+ /**
+ * \brief Pointer to the vtable.
+ *
+ * This field is set with the initialisation method/function.
+ */
+ const br_prng_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char K[64];
+ unsigned char V[64];
+ const br_hash_class *digest_class;
+#endif
+} br_hmac_drbg_context;
+
+/**
+ * \brief Statically allocated, constant vtable for HMAC_DRBG.
+ */
+extern const br_prng_class br_hmac_drbg_vtable;
+
+/**
+ * \brief HMAC_DRBG initialisation.
+ *
+ * The context to initialise is provided as a pointer to its first field
+ * (the vtable pointer); this function sets that first field to a
+ * pointer to the vtable.
+ *
+ * The `seed` value is what is called, in NIST terminology, the
+ * concatenation of the "seed", "nonce" and "personalization string", in
+ * that order.
+ *
+ * The `digest_class` parameter defines the underlying hash function.
+ * Formally, the NIST standard specifies that the hash function shall
+ * be only SHA-1 or one of the SHA-2 functions. This implementation also
+ * works with any other implemented hash function (such as MD5), but
+ * this is non-standard and therefore not recommended.
+ *
+ * \param ctx HMAC_DRBG context to initialise.
+ * \param digest_class vtable for the underlying hash function.
+ * \param seed initial seed.
+ * \param seed_len initial seed length (in bytes).
+ */
+void br_hmac_drbg_init(br_hmac_drbg_context *ctx,
+ const br_hash_class *digest_class, const void *seed, size_t seed_len);
+
+/**
+ * \brief Random bytes generation with HMAC_DRBG.
+ *
+ * This method produces `len` pseudorandom bytes, in the `out`
+ * buffer. The context is updated accordingly. Formally, requesting
+ * more than 65536 bytes in one request falls out of specification
+ * limits (but it won't fail).
+ *
+ * \param ctx HMAC_DRBG context.
+ * \param out output buffer.
+ * \param len number of pseudorandom bytes to produce.
+ */
+void br_hmac_drbg_generate(br_hmac_drbg_context *ctx, void *out, size_t len);
+
+/**
+ * \brief Inject additional seed bytes in HMAC_DRBG.
+ *
+ * The provided seed bytes are added into the HMAC_DRBG internal
+ * entropy pool. The process does not _replace_ existing entropy,
+ * thus pushing non-random bytes (i.e. bytes which are known to the
+ * attackers) does not degrade the overall quality of generated bytes.
+ *
+ * \param ctx HMAC_DRBG context.
+ * \param seed additional seed.
+ * \param seed_len additional seed length (in bytes).
+ */
+void br_hmac_drbg_update(br_hmac_drbg_context *ctx,
+ const void *seed, size_t seed_len);
+
+/**
+ * \brief Get the hash function implementation used by a given instance of
+ * HMAC_DRBG.
+ *
+ * This calls MUST NOT be performed on a context which was not
+ * previously initialised.
+ *
+ * \param ctx HMAC_DRBG context.
+ * \return the hash function vtable.
+ */
+static inline const br_hash_class *
+br_hmac_drbg_get_hash(const br_hmac_drbg_context *ctx)
+{
+ return ctx->digest_class;
+}
+
+/**
+ * \brief Type for a provider of entropy seeds.
+ *
+ * A "seeder" is a function that is able to obtain random values from
+ * some source and inject them as entropy seed in a PRNG. A seeder
+ * shall guarantee that the total entropy of the injected seed is large
+ * enough to seed a PRNG for purposes of cryptographic key generation
+ * (i.e. at least 128 bits).
+ *
+ * A seeder may report a failure to obtain adequate entropy. Seeders
+ * shall endeavour to fix themselves transient errors by trying again;
+ * thus, callers may consider reported errors as permanent.
+ *
+ * \param ctx PRNG context to seed.
+ * \return 1 on success, 0 on error.
+ */
+typedef int (*br_prng_seeder)(const br_prng_class **ctx);
+
+/**
+ * \brief Get a seeder backed by the operating system or hardware.
+ *
+ * Get a seeder that feeds on RNG facilities provided by the current
+ * operating system or hardware. If no such facility is known, then 0
+ * is returned.
+ *
+ * If `name` is not `NULL`, then `*name` is set to a symbolic string
+ * that identifies the seeder implementation. If no seeder is returned
+ * and `name` is not `NULL`, then `*name` is set to a pointer to the
+ * constant string `"none"`.
+ *
+ * \param name receiver for seeder name, or `NULL`.
+ * \return the system seeder, if available, or 0.
+ */
+br_prng_seeder br_prng_seeder_system(const char **name);
+
+/**
+ * \brief Context for AESCTR_DRBG.
+ *
+ * The context contents are opaque, except the first field, which
+ * supports OOP.
+ */
+typedef struct {
+ /**
+ * \brief Pointer to the vtable.
+ *
+ * This field is set with the initialisation method/function.
+ */
+ const br_prng_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ br_aes_gen_ctr_keys sk;
+ uint32_t cc;
+#endif
+} br_aesctr_drbg_context;
+
+/**
+ * \brief Statically allocated, constant vtable for AESCTR_DRBG.
+ */
+extern const br_prng_class br_aesctr_drbg_vtable;
+
+/**
+ * \brief AESCTR_DRBG initialisation.
+ *
+ * The context to initialise is provided as a pointer to its first field
+ * (the vtable pointer); this function sets that first field to a
+ * pointer to the vtable.
+ *
+ * The internal AES key is first set to the all-zero key; then, the
+ * `br_aesctr_drbg_update()` function is called with the provided `seed`.
+ * The call is performed even if the seed length (`seed_len`) is zero.
+ *
+ * The `aesctr` parameter defines the underlying AES/CTR implementation.
+ *
+ * \param ctx AESCTR_DRBG context to initialise.
+ * \param aesctr vtable for the AES/CTR implementation.
+ * \param seed initial seed (can be `NULL` if `seed_len` is zero).
+ * \param seed_len initial seed length (in bytes).
+ */
+void br_aesctr_drbg_init(br_aesctr_drbg_context *ctx,
+ const br_block_ctr_class *aesctr, const void *seed, size_t seed_len);
+
+/**
+ * \brief Random bytes generation with AESCTR_DRBG.
+ *
+ * This method produces `len` pseudorandom bytes, in the `out`
+ * buffer. The context is updated accordingly.
+ *
+ * \param ctx AESCTR_DRBG context.
+ * \param out output buffer.
+ * \param len number of pseudorandom bytes to produce.
+ */
+void br_aesctr_drbg_generate(br_aesctr_drbg_context *ctx,
+ void *out, size_t len);
+
+/**
+ * \brief Inject additional seed bytes in AESCTR_DRBG.
+ *
+ * The provided seed bytes are added into the AESCTR_DRBG internal
+ * entropy pool. The process does not _replace_ existing entropy,
+ * thus pushing non-random bytes (i.e. bytes which are known to the
+ * attackers) does not degrade the overall quality of generated bytes.
+ *
+ * \param ctx AESCTR_DRBG context.
+ * \param seed additional seed.
+ * \param seed_len additional seed length (in bytes).
+ */
+void br_aesctr_drbg_update(br_aesctr_drbg_context *ctx,
+ const void *seed, size_t seed_len);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/bearssl/inc/bearssl_rsa.h b/contrib/bearssl/inc/bearssl_rsa.h
new file mode 100644
index 000000000000..0a069fd3615d
--- /dev/null
+++ b/contrib/bearssl/inc/bearssl_rsa.h
@@ -0,0 +1,1655 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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>
+
+#include "bearssl_hash.h"
+#include "bearssl_rand.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_rsa.h
+ *
+ * # RSA
+ *
+ * This file documents the RSA implementations provided with BearSSL.
+ * Note that the SSL engine accesses these implementations through a
+ * configurable API, so it is possible to, for instance, run a SSL
+ * server which uses a RSA engine which is not based on this code.
+ *
+ * ## Key Elements
+ *
+ * RSA public and private keys consist in lists of big integers. All
+ * such integers are represented with big-endian unsigned notation:
+ * first byte is the most significant, and the value is positive (so
+ * there is no dedicated "sign bit"). Public and private key structures
+ * thus contain, for each such integer, a pointer to the first value byte
+ * (`unsigned char *`), and a length (`size_t`) which is the number of
+ * relevant bytes. As a general rule, minimal-length encoding is not
+ * enforced: values may have extra leading bytes of value 0.
+ *
+ * RSA public keys consist in two integers:
+ *
+ * - the modulus (`n`);
+ * - the public exponent (`e`).
+ *
+ * RSA private keys, as defined in
+ * [PKCS#1](https://tools.ietf.org/html/rfc3447), contain eight integers:
+ *
+ * - the modulus (`n`);
+ * - the public exponent (`e`);
+ * - the private exponent (`d`);
+ * - the first prime factor (`p`);
+ * - the second prime factor (`q`);
+ * - the first reduced exponent (`dp`, which is `d` modulo `p-1`);
+ * - the second reduced exponent (`dq`, which is `d` modulo `q-1`);
+ * - the CRT coefficient (`iq`, the inverse of `q` modulo `p`).
+ *
+ * However, the implementations defined in BearSSL use only five of
+ * these integers: `p`, `q`, `dp`, `dq` and `iq`.
+ *
+ * ## Security Features and Limitations
+ *
+ * The implementations contained in BearSSL have the following limitations
+ * and features:
+ *
+ * - They are constant-time. This means that the execution time and
+ * memory access pattern may depend on the _lengths_ of the private
+ * key components, but not on their value, nor on the value of
+ * the operand. Note that this property is not achieved through
+ * random masking, but "true" constant-time code.
+ *
+ * - They support only private keys with two prime factors. RSA private
+ * keys with three or more prime factors are nominally supported, but
+ * rarely used; they may offer faster operations, at the expense of
+ * more code and potentially a reduction in security if there are
+ * "too many" prime factors.
+ *
+ * - The public exponent may have arbitrary length. Of course, it is
+ * a good idea to keep public exponents small, so that public key
+ * operations are fast; but, contrary to some widely deployed
+ * implementations, BearSSL has no problem with public exponents
+ * longer than 32 bits.
+ *
+ * - The two prime factors of the modulus need not have the same length
+ * (but severely imbalanced factor lengths might reduce security).
+ * Similarly, there is no requirement that the first factor (`p`)
+ * be greater than the second factor (`q`).
+ *
+ * - Prime factors and modulus must be smaller than a compile-time limit.
+ * This is made necessary by the use of fixed-size stack buffers, and
+ * the limit has been adjusted to keep stack usage under 2 kB for the
+ * RSA operations. Currently, the maximum modulus size is 4096 bits,
+ * and the maximum prime factor size is 2080 bits.
+ *
+ * - The RSA functions themselves do not enforce lower size limits,
+ * except that which is absolutely necessary for the operation to
+ * mathematically make sense (e.g. a PKCS#1 v1.5 signature with
+ * SHA-1 requires a modulus of at least 361 bits). It is up to users
+ * of this code to enforce size limitations when appropriate (e.g.
+ * the X.509 validation engine, by default, rejects RSA keys of
+ * less than 1017 bits).
+ *
+ * - Within the size constraints expressed above, arbitrary bit lengths
+ * are supported. There is no requirement that prime factors or
+ * modulus have a size multiple of 8 or 16.
+ *
+ * - When verifying PKCS#1 v1.5 signatures, both variants of the hash
+ * function identifying header (with and without the ASN.1 NULL) are
+ * supported. When producing such signatures, the variant with the
+ * ASN.1 NULL is used.
+ *
+ * ## Implementations
+ *
+ * Three RSA implementations are included:
+ *
+ * - The **i32** implementation internally represents big integers
+ * as arrays of 32-bit integers. It is perfunctory and portable,
+ * but not very efficient.
+ *
+ * - The **i31** implementation uses 32-bit integers, each containing
+ * 31 bits worth of integer data. The i31 implementation is somewhat
+ * faster than the i32 implementation (the reduced integer size makes
+ * carry propagation easier) for a similar code footprint, but uses
+ * very slightly larger stack buffers (about 4% bigger).
+ *
+ * - The **i62** implementation is similar to the i31 implementation,
+ * except that it internally leverages the 64x64->128 multiplication
+ * opcode. This implementation is available only on architectures
+ * where such an opcode exists. It is much faster than i31.
+ *
+ * - The **i15** implementation uses 16-bit integers, each containing
+ * 15 bits worth of integer data. Multiplication results fit on
+ * 32 bits, so this won't use the "widening" multiplication routine
+ * on ARM Cortex M0/M0+, for much better performance and constant-time
+ * execution.
+ */
+
+/**
+ * \brief RSA public key.
+ *
+ * The structure references the modulus and the public exponent. Both
+ * integers use unsigned big-endian representation; extra leading bytes
+ * of value 0 are allowed.
+ */
+typedef struct {
+ /** \brief Modulus. */
+ unsigned char *n;
+ /** \brief Modulus length (in bytes). */
+ size_t nlen;
+ /** \brief Public exponent. */
+ unsigned char *e;
+ /** \brief Public exponent length (in bytes). */
+ size_t elen;
+} br_rsa_public_key;
+
+/**
+ * \brief RSA private key.
+ *
+ * The structure references the private factors, reduced private
+ * exponents, and CRT coefficient. It also contains the bit length of
+ * the modulus. The big integers use unsigned big-endian representation;
+ * extra leading bytes of value 0 are allowed. However, the modulus bit
+ * length (`n_bitlen`) MUST be exact.
+ */
+typedef struct {
+ /** \brief Modulus bit length (in bits, exact value). */
+ uint32_t n_bitlen;
+ /** \brief First prime factor. */
+ unsigned char *p;
+ /** \brief First prime factor length (in bytes). */
+ size_t plen;
+ /** \brief Second prime factor. */
+ unsigned char *q;
+ /** \brief Second prime factor length (in bytes). */
+ size_t qlen;
+ /** \brief First reduced private exponent. */
+ unsigned char *dp;
+ /** \brief First reduced private exponent length (in bytes). */
+ size_t dplen;
+ /** \brief Second reduced private exponent. */
+ unsigned char *dq;
+ /** \brief Second reduced private exponent length (in bytes). */
+ size_t dqlen;
+ /** \brief CRT coefficient. */
+ unsigned char *iq;
+ /** \brief CRT coefficient length (in bytes). */
+ size_t iqlen;
+} br_rsa_private_key;
+
+/**
+ * \brief Type for a RSA public key engine.
+ *
+ * The public key engine performs the modular exponentiation of the
+ * provided value with the public exponent. The value is modified in
+ * place.
+ *
+ * The value length (`xlen`) is verified to have _exactly_ the same
+ * length as the modulus (actual modulus length, without extra leading
+ * zeros in the modulus representation in memory). If the length does
+ * not match, then this function returns 0 and `x[]` is unmodified.
+ *
+ * It `xlen` is correct, then `x[]` is modified. Returned value is 1
+ * on success, 0 on error. Error conditions include an oversized `x[]`
+ * (the array has the same length as the modulus, but the numerical value
+ * is not lower than the modulus) and an invalid modulus (e.g. an even
+ * integer). If an error is reported, then the new contents of `x[]` are
+ * unspecified.
+ *
+ * \param x operand to exponentiate.
+ * \param xlen length of the operand (in bytes).
+ * \param pk RSA public key.
+ * \return 1 on success, 0 on error.
+ */
+typedef uint32_t (*br_rsa_public)(unsigned char *x, size_t xlen,
+ const br_rsa_public_key *pk);
+
+/**
+ * \brief Type for a RSA signature verification engine (PKCS#1 v1.5).
+ *
+ * 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
+ * also be `NULL`, in which case the raw hash value should be used
+ * with the PKCS#1 v1.5 "type 1" padding (as 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.
+ *
+ * \param x signature buffer.
+ * \param xlen signature length (in bytes).
+ * \param hash_oid encoded hash algorithm OID (or `NULL`).
+ * \param hash_len expected hash value length (in bytes).
+ * \param pk RSA public key.
+ * \param hash_out output buffer for the hash value.
+ * \return 1 on success, 0 on error.
+ */
+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);
+
+/**
+ * \brief Type for a RSA signature verification engine (PSS).
+ *
+ * Parameters are:
+ *
+ * - The signature itself. The provided array is NOT modified.
+ *
+ * - The hash function which was used to hash the message.
+ *
+ * - The hash function to use with MGF1 within the PSS padding. This
+ * is not necessarily the same hash function as the one which was
+ * used to hash the signed message.
+ *
+ * - The hashed message (as an array of bytes).
+ *
+ * - The PSS salt length (in bytes).
+ *
+ * - The public key.
+ *
+ * **Constraints:**
+ *
+ * - Hash message length MUST be no more than 64 bytes.
+ *
+ * Note that, contrary to PKCS#1 v1.5 signature, the hash value of the
+ * signed data cannot be extracted from the signature; it must be
+ * provided to the verification function.
+ *
+ * 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.
+ *
+ * \param x signature buffer.
+ * \param xlen signature length (in bytes).
+ * \param hf_data hash function applied on the message.
+ * \param hf_mgf1 hash function to use with MGF1.
+ * \param hash hash value of the signed message.
+ * \param salt_len PSS salt length (in bytes).
+ * \param pk RSA public key.
+ * \return 1 on success, 0 on error.
+ */
+typedef uint32_t (*br_rsa_pss_vrfy)(const unsigned char *x, size_t xlen,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const void *hash, size_t salt_len, const br_rsa_public_key *pk);
+
+/**
+ * \brief Type for a RSA encryption engine (OAEP).
+ *
+ * Parameters are:
+ *
+ * - A source of random bytes. The source must be already initialized.
+ *
+ * - A hash function, used internally with the mask generation function
+ * (MGF1).
+ *
+ * - A label. The `label` pointer may be `NULL` if `label_len` is zero
+ * (an empty label, which is the default in PKCS#1 v2.2).
+ *
+ * - The public key.
+ *
+ * - The destination buffer. Its maximum length (in bytes) is provided;
+ * if that length is lower than the public key length, then an error
+ * is reported.
+ *
+ * - The source message.
+ *
+ * The encrypted message output has exactly the same length as the modulus
+ * (mathematical length, in bytes, not counting extra leading zeros in the
+ * modulus representation in the public key).
+ *
+ * The source message (`src`, length `src_len`) may overlap with the
+ * destination buffer (`dst`, length `dst_max_len`).
+ *
+ * This function returns the actual encrypted message length, in bytes;
+ * on error, zero is returned. An error is reported if the output buffer
+ * is not large enough, or the public is invalid, or the public key
+ * modulus exceeds the maximum supported RSA size.
+ *
+ * \param rnd source of random bytes.
+ * \param dig hash function to use with MGF1.
+ * \param label label value (may be `NULL` if `label_len` is zero).
+ * \param label_len label length, in bytes.
+ * \param pk RSA public key.
+ * \param dst destination buffer.
+ * \param dst_max_len destination buffer length (maximum encrypted data size).
+ * \param src message to encrypt.
+ * \param src_len source message length (in bytes).
+ * \return encrypted message length (in bytes), or 0 on error.
+ */
+typedef size_t (*br_rsa_oaep_encrypt)(
+ const br_prng_class **rnd, const br_hash_class *dig,
+ const void *label, size_t label_len,
+ const br_rsa_public_key *pk,
+ void *dst, size_t dst_max_len,
+ const void *src, size_t src_len);
+
+/**
+ * \brief Type for a RSA 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.
+ *
+ * \param x operand to exponentiate.
+ * \param sk RSA private key.
+ * \return 1 on success, 0 on error.
+ */
+typedef uint32_t (*br_rsa_private)(unsigned char *x,
+ const br_rsa_private_key *sk);
+
+/**
+ * \brief Type for a RSA signature generation engine (PKCS#1 v1.5).
+ *
+ * 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
+ * also be `NULL`, in which case the raw hash value should be used
+ * with the PKCS#1 v1.5 "type 1" padding (as used in SSL/TLS up
+ * to TLS-1.1, with a 36-byte hash value).
+ *
+ * - The hash value computes over the data to sign (its length is
+ * expressed in bytes).
+ *
+ * - The RSA private key.
+ *
+ * - The output buffer, that receives the signature.
+ *
+ * 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.
+ *
+ * \param hash_oid encoded hash algorithm OID (or `NULL`).
+ * \param hash hash value.
+ * \param hash_len hash value length (in bytes).
+ * \param sk RSA private key.
+ * \param x output buffer for the signature value.
+ * \return 1 on success, 0 on error.
+ */
+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);
+
+/**
+ * \brief Type for a RSA signature generation engine (PSS).
+ *
+ * Parameters are:
+ *
+ * - An initialized PRNG for salt generation. If the salt length is
+ * zero (`salt_len` parameter), then the PRNG is optional (this is
+ * not the typical case, as the security proof of RSA/PSS is
+ * tighter when a non-empty salt is used).
+ *
+ * - The hash function which was used to hash the message.
+ *
+ * - The hash function to use with MGF1 within the PSS padding. This
+ * is not necessarily the same function as the one used to hash the
+ * message.
+ *
+ * - The hashed message.
+ *
+ * - The salt length, in bytes.
+ *
+ * - The RSA private key.
+ *
+ * - The output buffer, that receives the signature.
+ *
+ * Returned value is 1 on success, 0 on error. Error conditions include
+ * a too small modulus for the provided hash and salt lengths, 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.
+ *
+ * \param rng PRNG for salt generation (`NULL` if `salt_len` is zero).
+ * \param hf_data hash function used to hash the signed data.
+ * \param hf_mgf1 hash function to use with MGF1.
+ * \param hash hashed message.
+ * \param salt_len salt length (in bytes).
+ * \param sk RSA private key.
+ * \param x output buffer for the signature value.
+ * \return 1 on success, 0 on error.
+ */
+typedef uint32_t (*br_rsa_pss_sign)(const br_prng_class **rng,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const unsigned char *hash_value, size_t salt_len,
+ const br_rsa_private_key *sk, unsigned char *x);
+
+/**
+ * \brief Encoded OID for SHA-1 (in RSA PKCS#1 signatures).
+ */
+#define BR_HASH_OID_SHA1 \
+ ((const unsigned char *)"\x05\x2B\x0E\x03\x02\x1A")
+
+/**
+ * \brief Encoded OID for SHA-224 (in RSA PKCS#1 signatures).
+ */
+#define BR_HASH_OID_SHA224 \
+ ((const unsigned char *)"\x09\x60\x86\x48\x01\x65\x03\x04\x02\x04")
+
+/**
+ * \brief Encoded OID for SHA-256 (in RSA PKCS#1 signatures).
+ */
+#define BR_HASH_OID_SHA256 \
+ ((const unsigned char *)"\x09\x60\x86\x48\x01\x65\x03\x04\x02\x01")
+
+/**
+ * \brief Encoded OID for SHA-384 (in RSA PKCS#1 signatures).
+ */
+#define BR_HASH_OID_SHA384 \
+ ((const unsigned char *)"\x09\x60\x86\x48\x01\x65\x03\x04\x02\x02")
+
+/**
+ * \brief Encoded OID for SHA-512 (in RSA PKCS#1 signatures).
+ */
+#define BR_HASH_OID_SHA512 \
+ ((const unsigned char *)"\x09\x60\x86\x48\x01\x65\x03\x04\x02\x03")
+
+/**
+ * \brief Type for a RSA decryption engine (OAEP).
+ *
+ * Parameters are:
+ *
+ * - A hash function, used internally with the mask generation function
+ * (MGF1).
+ *
+ * - A label. The `label` pointer may be `NULL` if `label_len` is zero
+ * (an empty label, which is the default in PKCS#1 v2.2).
+ *
+ * - The private key.
+ *
+ * - The source and destination buffer. The buffer initially contains
+ * the encrypted message; the buffer contents are altered, and the
+ * decrypted message is written at the start of that buffer
+ * (decrypted message is always shorter than the encrypted message).
+ *
+ * If decryption fails in any way, then `*len` is unmodified, and the
+ * function returns 0. Otherwise, `*len` is set to the decrypted message
+ * length, and 1 is returned. The implementation is responsible for
+ * checking that the input message length matches the key modulus length,
+ * and that the padding is correct.
+ *
+ * Implementations MUST use constant-time check of the validity of the
+ * OAEP padding, at least until the leading byte and hash value have
+ * been checked. Whether overall decryption worked, and the length of
+ * the decrypted message, may leak.
+ *
+ * \param dig hash function to use with MGF1.
+ * \param label label value (may be `NULL` if `label_len` is zero).
+ * \param label_len label length, in bytes.
+ * \param sk RSA private key.
+ * \param data input/output buffer.
+ * \param len encrypted/decrypted message length.
+ * \return 1 on success, 0 on error.
+ */
+typedef uint32_t (*br_rsa_oaep_decrypt)(
+ const br_hash_class *dig, const void *label, size_t label_len,
+ const br_rsa_private_key *sk, void *data, size_t *len);
+
+/*
+ * RSA "i32" engine. Integers are internally represented as arrays of
+ * 32-bit integers, and the core multiplication primitive is the
+ * 32x32->64 multiplication.
+ */
+
+/**
+ * \brief RSA public key engine "i32".
+ *
+ * \see br_rsa_public
+ *
+ * \param x operand to exponentiate.
+ * \param xlen length of the operand (in bytes).
+ * \param pk RSA public key.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i32_public(unsigned char *x, size_t xlen,
+ const br_rsa_public_key *pk);
+
+/**
+ * \brief RSA signature verification engine "i32" (PKCS#1 v1.5 signatures).
+ *
+ * \see br_rsa_pkcs1_vrfy
+ *
+ * \param x signature buffer.
+ * \param xlen signature length (in bytes).
+ * \param hash_oid encoded hash algorithm OID (or `NULL`).
+ * \param hash_len expected hash value length (in bytes).
+ * \param pk RSA public key.
+ * \param hash_out output buffer for the hash value.
+ * \return 1 on success, 0 on error.
+ */
+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);
+
+/**
+ * \brief RSA signature verification engine "i32" (PSS signatures).
+ *
+ * \see br_rsa_pss_vrfy
+ *
+ * \param x signature buffer.
+ * \param xlen signature length (in bytes).
+ * \param hf_data hash function applied on the message.
+ * \param hf_mgf1 hash function to use with MGF1.
+ * \param hash hash value of the signed message.
+ * \param salt_len PSS salt length (in bytes).
+ * \param pk RSA public key.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i32_pss_vrfy(const unsigned char *x, size_t xlen,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const void *hash, size_t salt_len, const br_rsa_public_key *pk);
+
+/**
+ * \brief RSA private key engine "i32".
+ *
+ * \see br_rsa_private
+ *
+ * \param x operand to exponentiate.
+ * \param sk RSA private key.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i32_private(unsigned char *x,
+ const br_rsa_private_key *sk);
+
+/**
+ * \brief RSA signature generation engine "i32" (PKCS#1 v1.5 signatures).
+ *
+ * \see br_rsa_pkcs1_sign
+ *
+ * \param hash_oid encoded hash algorithm OID (or `NULL`).
+ * \param hash hash value.
+ * \param hash_len hash value length (in bytes).
+ * \param sk RSA private key.
+ * \param x output buffer for the hash value.
+ * \return 1 on success, 0 on error.
+ */
+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);
+
+/**
+ * \brief RSA signature generation engine "i32" (PSS signatures).
+ *
+ * \see br_rsa_pss_sign
+ *
+ * \param rng PRNG for salt generation (`NULL` if `salt_len` is zero).
+ * \param hf_data hash function used to hash the signed data.
+ * \param hf_mgf1 hash function to use with MGF1.
+ * \param hash hashed message.
+ * \param salt_len salt length (in bytes).
+ * \param sk RSA private key.
+ * \param x output buffer for the signature value.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i32_pss_sign(const br_prng_class **rng,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const unsigned char *hash_value, size_t salt_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.
+ */
+
+/**
+ * \brief RSA public key engine "i31".
+ *
+ * \see br_rsa_public
+ *
+ * \param x operand to exponentiate.
+ * \param xlen length of the operand (in bytes).
+ * \param pk RSA public key.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i31_public(unsigned char *x, size_t xlen,
+ const br_rsa_public_key *pk);
+
+/**
+ * \brief RSA signature verification engine "i31" (PKCS#1 v1.5 signatures).
+ *
+ * \see br_rsa_pkcs1_vrfy
+ *
+ * \param x signature buffer.
+ * \param xlen signature length (in bytes).
+ * \param hash_oid encoded hash algorithm OID (or `NULL`).
+ * \param hash_len expected hash value length (in bytes).
+ * \param pk RSA public key.
+ * \param hash_out output buffer for the hash value.
+ * \return 1 on success, 0 on error.
+ */
+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);
+
+/**
+ * \brief RSA signature verification engine "i31" (PSS signatures).
+ *
+ * \see br_rsa_pss_vrfy
+ *
+ * \param x signature buffer.
+ * \param xlen signature length (in bytes).
+ * \param hf_data hash function applied on the message.
+ * \param hf_mgf1 hash function to use with MGF1.
+ * \param hash hash value of the signed message.
+ * \param salt_len PSS salt length (in bytes).
+ * \param pk RSA public key.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i31_pss_vrfy(const unsigned char *x, size_t xlen,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const void *hash, size_t salt_len, const br_rsa_public_key *pk);
+
+/**
+ * \brief RSA private key engine "i31".
+ *
+ * \see br_rsa_private
+ *
+ * \param x operand to exponentiate.
+ * \param sk RSA private key.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i31_private(unsigned char *x,
+ const br_rsa_private_key *sk);
+
+/**
+ * \brief RSA signature generation engine "i31" (PKCS#1 v1.5 signatures).
+ *
+ * \see br_rsa_pkcs1_sign
+ *
+ * \param hash_oid encoded hash algorithm OID (or `NULL`).
+ * \param hash hash value.
+ * \param hash_len hash value length (in bytes).
+ * \param sk RSA private key.
+ * \param x output buffer for the hash value.
+ * \return 1 on success, 0 on error.
+ */
+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);
+
+/**
+ * \brief RSA signature generation engine "i31" (PSS signatures).
+ *
+ * \see br_rsa_pss_sign
+ *
+ * \param rng PRNG for salt generation (`NULL` if `salt_len` is zero).
+ * \param hf_data hash function used to hash the signed data.
+ * \param hf_mgf1 hash function to use with MGF1.
+ * \param hash hashed message.
+ * \param salt_len salt length (in bytes).
+ * \param sk RSA private key.
+ * \param x output buffer for the signature value.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i31_pss_sign(const br_prng_class **rng,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const unsigned char *hash_value, size_t salt_len,
+ const br_rsa_private_key *sk, unsigned char *x);
+
+/*
+ * RSA "i62" engine. Similar to i31, but internal multiplication use
+ * 64x64->128 multiplications. This is available only on architecture
+ * that offer such an opcode.
+ */
+
+/**
+ * \brief RSA public key engine "i62".
+ *
+ * This function is defined only on architecture that offer a 64x64->128
+ * opcode. Use `br_rsa_i62_public_get()` to dynamically obtain a pointer
+ * to that function.
+ *
+ * \see br_rsa_public
+ *
+ * \param x operand to exponentiate.
+ * \param xlen length of the operand (in bytes).
+ * \param pk RSA public key.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i62_public(unsigned char *x, size_t xlen,
+ const br_rsa_public_key *pk);
+
+/**
+ * \brief RSA signature verification engine "i62" (PKCS#1 v1.5 signatures).
+ *
+ * This function is defined only on architecture that offer a 64x64->128
+ * opcode. Use `br_rsa_i62_pkcs1_vrfy_get()` to dynamically obtain a pointer
+ * to that function.
+ *
+ * \see br_rsa_pkcs1_vrfy
+ *
+ * \param x signature buffer.
+ * \param xlen signature length (in bytes).
+ * \param hash_oid encoded hash algorithm OID (or `NULL`).
+ * \param hash_len expected hash value length (in bytes).
+ * \param pk RSA public key.
+ * \param hash_out output buffer for the hash value.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i62_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);
+
+/**
+ * \brief RSA signature verification engine "i62" (PSS signatures).
+ *
+ * This function is defined only on architecture that offer a 64x64->128
+ * opcode. Use `br_rsa_i62_pss_vrfy_get()` to dynamically obtain a pointer
+ * to that function.
+ *
+ * \see br_rsa_pss_vrfy
+ *
+ * \param x signature buffer.
+ * \param xlen signature length (in bytes).
+ * \param hf_data hash function applied on the message.
+ * \param hf_mgf1 hash function to use with MGF1.
+ * \param hash hash value of the signed message.
+ * \param salt_len PSS salt length (in bytes).
+ * \param pk RSA public key.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i62_pss_vrfy(const unsigned char *x, size_t xlen,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const void *hash, size_t salt_len, const br_rsa_public_key *pk);
+
+/**
+ * \brief RSA private key engine "i62".
+ *
+ * This function is defined only on architecture that offer a 64x64->128
+ * opcode. Use `br_rsa_i62_private_get()` to dynamically obtain a pointer
+ * to that function.
+ *
+ * \see br_rsa_private
+ *
+ * \param x operand to exponentiate.
+ * \param sk RSA private key.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i62_private(unsigned char *x,
+ const br_rsa_private_key *sk);
+
+/**
+ * \brief RSA signature generation engine "i62" (PKCS#1 v1.5 signatures).
+ *
+ * This function is defined only on architecture that offer a 64x64->128
+ * opcode. Use `br_rsa_i62_pkcs1_sign_get()` to dynamically obtain a pointer
+ * to that function.
+ *
+ * \see br_rsa_pkcs1_sign
+ *
+ * \param hash_oid encoded hash algorithm OID (or `NULL`).
+ * \param hash hash value.
+ * \param hash_len hash value length (in bytes).
+ * \param sk RSA private key.
+ * \param x output buffer for the hash value.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i62_pkcs1_sign(const unsigned char *hash_oid,
+ const unsigned char *hash, size_t hash_len,
+ const br_rsa_private_key *sk, unsigned char *x);
+
+/**
+ * \brief RSA signature generation engine "i62" (PSS signatures).
+ *
+ * This function is defined only on architecture that offer a 64x64->128
+ * opcode. Use `br_rsa_i62_pss_sign_get()` to dynamically obtain a pointer
+ * to that function.
+ *
+ * \see br_rsa_pss_sign
+ *
+ * \param rng PRNG for salt generation (`NULL` if `salt_len` is zero).
+ * \param hf_data hash function used to hash the signed data.
+ * \param hf_mgf1 hash function to use with MGF1.
+ * \param hash hashed message.
+ * \param salt_len salt length (in bytes).
+ * \param sk RSA private key.
+ * \param x output buffer for the signature value.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i62_pss_sign(const br_prng_class **rng,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const unsigned char *hash_value, size_t salt_len,
+ const br_rsa_private_key *sk, unsigned char *x);
+
+/**
+ * \brief Get the RSA "i62" implementation (public key operations),
+ * if available.
+ *
+ * \return the implementation, or 0.
+ */
+br_rsa_public br_rsa_i62_public_get(void);
+
+/**
+ * \brief Get the RSA "i62" implementation (PKCS#1 v1.5 signature verification),
+ * if available.
+ *
+ * \return the implementation, or 0.
+ */
+br_rsa_pkcs1_vrfy br_rsa_i62_pkcs1_vrfy_get(void);
+
+/**
+ * \brief Get the RSA "i62" implementation (PSS signature verification),
+ * if available.
+ *
+ * \return the implementation, or 0.
+ */
+br_rsa_pss_vrfy br_rsa_i62_pss_vrfy_get(void);
+
+/**
+ * \brief Get the RSA "i62" implementation (private key operations),
+ * if available.
+ *
+ * \return the implementation, or 0.
+ */
+br_rsa_private br_rsa_i62_private_get(void);
+
+/**
+ * \brief Get the RSA "i62" implementation (PKCS#1 v1.5 signature generation),
+ * if available.
+ *
+ * \return the implementation, or 0.
+ */
+br_rsa_pkcs1_sign br_rsa_i62_pkcs1_sign_get(void);
+
+/**
+ * \brief Get the RSA "i62" implementation (PSS signature generation),
+ * if available.
+ *
+ * \return the implementation, or 0.
+ */
+br_rsa_pss_sign br_rsa_i62_pss_sign_get(void);
+
+/**
+ * \brief Get the RSA "i62" implementation (OAEP encryption),
+ * if available.
+ *
+ * \return the implementation, or 0.
+ */
+br_rsa_oaep_encrypt br_rsa_i62_oaep_encrypt_get(void);
+
+/**
+ * \brief Get the RSA "i62" implementation (OAEP decryption),
+ * if available.
+ *
+ * \return the implementation, or 0.
+ */
+br_rsa_oaep_decrypt br_rsa_i62_oaep_decrypt_get(void);
+
+/*
+ * RSA "i15" engine. Integers are represented as 15-bit integers, so
+ * the code uses only 32-bit multiplication (no 64-bit result), which
+ * is vastly faster (and constant-time) on the ARM Cortex M0/M0+.
+ */
+
+/**
+ * \brief RSA public key engine "i15".
+ *
+ * \see br_rsa_public
+ *
+ * \param x operand to exponentiate.
+ * \param xlen length of the operand (in bytes).
+ * \param pk RSA public key.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i15_public(unsigned char *x, size_t xlen,
+ const br_rsa_public_key *pk);
+
+/**
+ * \brief RSA signature verification engine "i15" (PKCS#1 v1.5 signatures).
+ *
+ * \see br_rsa_pkcs1_vrfy
+ *
+ * \param x signature buffer.
+ * \param xlen signature length (in bytes).
+ * \param hash_oid encoded hash algorithm OID (or `NULL`).
+ * \param hash_len expected hash value length (in bytes).
+ * \param pk RSA public key.
+ * \param hash_out output buffer for the hash value.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i15_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);
+
+/**
+ * \brief RSA signature verification engine "i15" (PSS signatures).
+ *
+ * \see br_rsa_pss_vrfy
+ *
+ * \param x signature buffer.
+ * \param xlen signature length (in bytes).
+ * \param hf_data hash function applied on the message.
+ * \param hf_mgf1 hash function to use with MGF1.
+ * \param hash hash value of the signed message.
+ * \param salt_len PSS salt length (in bytes).
+ * \param pk RSA public key.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i15_pss_vrfy(const unsigned char *x, size_t xlen,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const void *hash, size_t salt_len, const br_rsa_public_key *pk);
+
+/**
+ * \brief RSA private key engine "i15".
+ *
+ * \see br_rsa_private
+ *
+ * \param x operand to exponentiate.
+ * \param sk RSA private key.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i15_private(unsigned char *x,
+ const br_rsa_private_key *sk);
+
+/**
+ * \brief RSA signature generation engine "i15" (PKCS#1 v1.5 signatures).
+ *
+ * \see br_rsa_pkcs1_sign
+ *
+ * \param hash_oid encoded hash algorithm OID (or `NULL`).
+ * \param hash hash value.
+ * \param hash_len hash value length (in bytes).
+ * \param sk RSA private key.
+ * \param x output buffer for the hash value.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i15_pkcs1_sign(const unsigned char *hash_oid,
+ const unsigned char *hash, size_t hash_len,
+ const br_rsa_private_key *sk, unsigned char *x);
+
+/**
+ * \brief RSA signature generation engine "i15" (PSS signatures).
+ *
+ * \see br_rsa_pss_sign
+ *
+ * \param rng PRNG for salt generation (`NULL` if `salt_len` is zero).
+ * \param hf_data hash function used to hash the signed data.
+ * \param hf_mgf1 hash function to use with MGF1.
+ * \param hash hashed message.
+ * \param salt_len salt length (in bytes).
+ * \param sk RSA private key.
+ * \param x output buffer for the signature value.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i15_pss_sign(const br_prng_class **rng,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const unsigned char *hash_value, size_t salt_len,
+ const br_rsa_private_key *sk, unsigned char *x);
+
+/**
+ * \brief Get "default" RSA implementation (public-key operations).
+ *
+ * This returns the preferred implementation of RSA (public-key operations)
+ * on the current system.
+ *
+ * \return the default implementation.
+ */
+br_rsa_public br_rsa_public_get_default(void);
+
+/**
+ * \brief Get "default" RSA implementation (private-key operations).
+ *
+ * This returns the preferred implementation of RSA (private-key operations)
+ * on the current system.
+ *
+ * \return the default implementation.
+ */
+br_rsa_private br_rsa_private_get_default(void);
+
+/**
+ * \brief Get "default" RSA implementation (PKCS#1 v1.5 signature verification).
+ *
+ * This returns the preferred implementation of RSA (signature verification)
+ * on the current system.
+ *
+ * \return the default implementation.
+ */
+br_rsa_pkcs1_vrfy br_rsa_pkcs1_vrfy_get_default(void);
+
+/**
+ * \brief Get "default" RSA implementation (PSS signature verification).
+ *
+ * This returns the preferred implementation of RSA (signature verification)
+ * on the current system.
+ *
+ * \return the default implementation.
+ */
+br_rsa_pss_vrfy br_rsa_pss_vrfy_get_default(void);
+
+/**
+ * \brief Get "default" RSA implementation (PKCS#1 v1.5 signature generation).
+ *
+ * This returns the preferred implementation of RSA (signature generation)
+ * on the current system.
+ *
+ * \return the default implementation.
+ */
+br_rsa_pkcs1_sign br_rsa_pkcs1_sign_get_default(void);
+
+/**
+ * \brief Get "default" RSA implementation (PSS signature generation).
+ *
+ * This returns the preferred implementation of RSA (signature generation)
+ * on the current system.
+ *
+ * \return the default implementation.
+ */
+br_rsa_pss_sign br_rsa_pss_sign_get_default(void);
+
+/**
+ * \brief Get "default" RSA implementation (OAEP encryption).
+ *
+ * This returns the preferred implementation of RSA (OAEP encryption)
+ * on the current system.
+ *
+ * \return the default implementation.
+ */
+br_rsa_oaep_encrypt br_rsa_oaep_encrypt_get_default(void);
+
+/**
+ * \brief Get "default" RSA implementation (OAEP decryption).
+ *
+ * This returns the preferred implementation of RSA (OAEP decryption)
+ * on the current system.
+ *
+ * \return the default implementation.
+ */
+br_rsa_oaep_decrypt br_rsa_oaep_decrypt_get_default(void);
+
+/**
+ * \brief RSA decryption helper, for SSL/TLS.
+ *
+ * This function performs the RSA decryption for a RSA-based key exchange
+ * in a SSL/TLS server. The provided RSA engine is used. The `data`
+ * parameter points to the value to decrypt, of length `len` bytes. On
+ * success, the 48-byte pre-master secret is copied into `data`, starting
+ * at the first byte of that buffer; on error, the contents of `data`
+ * become indeterminate.
+ *
+ * This function first checks that the provided value length (`len`) is
+ * not lower than 59 bytes, and matches the RSA modulus length; if neither
+ * of this property is met, then this function returns 0 and the buffer
+ * is unmodified.
+ *
+ * Otherwise, decryption and then padding verification are performed, both
+ * in constant-time. A decryption error, or a bad padding, or an
+ * incorrect decrypted value length are reported with a returned value of
+ * 0; on success, 1 is returned. The caller (SSL server engine) is supposed
+ * to proceed with a random pre-master secret in case of error.
+ *
+ * \param core RSA private key engine.
+ * \param sk RSA private key.
+ * \param data input/output buffer.
+ * \param len length (in bytes) of the data to decrypt.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_ssl_decrypt(br_rsa_private core, const br_rsa_private_key *sk,
+ unsigned char *data, size_t len);
+
+/**
+ * \brief RSA encryption (OAEP) with the "i15" engine.
+ *
+ * \see br_rsa_oaep_encrypt
+ *
+ * \param rnd source of random bytes.
+ * \param dig hash function to use with MGF1.
+ * \param label label value (may be `NULL` if `label_len` is zero).
+ * \param label_len label length, in bytes.
+ * \param pk RSA public key.
+ * \param dst destination buffer.
+ * \param dst_max_len destination buffer length (maximum encrypted data size).
+ * \param src message to encrypt.
+ * \param src_len source message length (in bytes).
+ * \return encrypted message length (in bytes), or 0 on error.
+ */
+size_t br_rsa_i15_oaep_encrypt(
+ const br_prng_class **rnd, const br_hash_class *dig,
+ const void *label, size_t label_len,
+ const br_rsa_public_key *pk,
+ void *dst, size_t dst_max_len,
+ const void *src, size_t src_len);
+
+/**
+ * \brief RSA decryption (OAEP) with the "i15" engine.
+ *
+ * \see br_rsa_oaep_decrypt
+ *
+ * \param dig hash function to use with MGF1.
+ * \param label label value (may be `NULL` if `label_len` is zero).
+ * \param label_len label length, in bytes.
+ * \param sk RSA private key.
+ * \param data input/output buffer.
+ * \param len encrypted/decrypted message length.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i15_oaep_decrypt(
+ const br_hash_class *dig, const void *label, size_t label_len,
+ const br_rsa_private_key *sk, void *data, size_t *len);
+
+/**
+ * \brief RSA encryption (OAEP) with the "i31" engine.
+ *
+ * \see br_rsa_oaep_encrypt
+ *
+ * \param rnd source of random bytes.
+ * \param dig hash function to use with MGF1.
+ * \param label label value (may be `NULL` if `label_len` is zero).
+ * \param label_len label length, in bytes.
+ * \param pk RSA public key.
+ * \param dst destination buffer.
+ * \param dst_max_len destination buffer length (maximum encrypted data size).
+ * \param src message to encrypt.
+ * \param src_len source message length (in bytes).
+ * \return encrypted message length (in bytes), or 0 on error.
+ */
+size_t br_rsa_i31_oaep_encrypt(
+ const br_prng_class **rnd, const br_hash_class *dig,
+ const void *label, size_t label_len,
+ const br_rsa_public_key *pk,
+ void *dst, size_t dst_max_len,
+ const void *src, size_t src_len);
+
+/**
+ * \brief RSA decryption (OAEP) with the "i31" engine.
+ *
+ * \see br_rsa_oaep_decrypt
+ *
+ * \param dig hash function to use with MGF1.
+ * \param label label value (may be `NULL` if `label_len` is zero).
+ * \param label_len label length, in bytes.
+ * \param sk RSA private key.
+ * \param data input/output buffer.
+ * \param len encrypted/decrypted message length.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i31_oaep_decrypt(
+ const br_hash_class *dig, const void *label, size_t label_len,
+ const br_rsa_private_key *sk, void *data, size_t *len);
+
+/**
+ * \brief RSA encryption (OAEP) with the "i32" engine.
+ *
+ * \see br_rsa_oaep_encrypt
+ *
+ * \param rnd source of random bytes.
+ * \param dig hash function to use with MGF1.
+ * \param label label value (may be `NULL` if `label_len` is zero).
+ * \param label_len label length, in bytes.
+ * \param pk RSA public key.
+ * \param dst destination buffer.
+ * \param dst_max_len destination buffer length (maximum encrypted data size).
+ * \param src message to encrypt.
+ * \param src_len source message length (in bytes).
+ * \return encrypted message length (in bytes), or 0 on error.
+ */
+size_t br_rsa_i32_oaep_encrypt(
+ const br_prng_class **rnd, const br_hash_class *dig,
+ const void *label, size_t label_len,
+ const br_rsa_public_key *pk,
+ void *dst, size_t dst_max_len,
+ const void *src, size_t src_len);
+
+/**
+ * \brief RSA decryption (OAEP) with the "i32" engine.
+ *
+ * \see br_rsa_oaep_decrypt
+ *
+ * \param dig hash function to use with MGF1.
+ * \param label label value (may be `NULL` if `label_len` is zero).
+ * \param label_len label length, in bytes.
+ * \param sk RSA private key.
+ * \param data input/output buffer.
+ * \param len encrypted/decrypted message length.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i32_oaep_decrypt(
+ const br_hash_class *dig, const void *label, size_t label_len,
+ const br_rsa_private_key *sk, void *data, size_t *len);
+
+/**
+ * \brief RSA encryption (OAEP) with the "i62" engine.
+ *
+ * This function is defined only on architecture that offer a 64x64->128
+ * opcode. Use `br_rsa_i62_oaep_encrypt_get()` to dynamically obtain a pointer
+ * to that function.
+ *
+ * \see br_rsa_oaep_encrypt
+ *
+ * \param rnd source of random bytes.
+ * \param dig hash function to use with MGF1.
+ * \param label label value (may be `NULL` if `label_len` is zero).
+ * \param label_len label length, in bytes.
+ * \param pk RSA public key.
+ * \param dst destination buffer.
+ * \param dst_max_len destination buffer length (maximum encrypted data size).
+ * \param src message to encrypt.
+ * \param src_len source message length (in bytes).
+ * \return encrypted message length (in bytes), or 0 on error.
+ */
+size_t br_rsa_i62_oaep_encrypt(
+ const br_prng_class **rnd, const br_hash_class *dig,
+ const void *label, size_t label_len,
+ const br_rsa_public_key *pk,
+ void *dst, size_t dst_max_len,
+ const void *src, size_t src_len);
+
+/**
+ * \brief RSA decryption (OAEP) with the "i62" engine.
+ *
+ * This function is defined only on architecture that offer a 64x64->128
+ * opcode. Use `br_rsa_i62_oaep_decrypt_get()` to dynamically obtain a pointer
+ * to that function.
+ *
+ * \see br_rsa_oaep_decrypt
+ *
+ * \param dig hash function to use with MGF1.
+ * \param label label value (may be `NULL` if `label_len` is zero).
+ * \param label_len label length, in bytes.
+ * \param sk RSA private key.
+ * \param data input/output buffer.
+ * \param len encrypted/decrypted message length.
+ * \return 1 on success, 0 on error.
+ */
+uint32_t br_rsa_i62_oaep_decrypt(
+ const br_hash_class *dig, const void *label, size_t label_len,
+ const br_rsa_private_key *sk, void *data, size_t *len);
+
+/**
+ * \brief Get buffer size to hold RSA private key elements.
+ *
+ * This macro returns the length (in bytes) of the buffer needed to
+ * receive the elements of a RSA private key, as generated by one of
+ * the `br_rsa_*_keygen()` functions. If the provided size is a constant
+ * expression, then the whole macro evaluates to a constant expression.
+ *
+ * \param size target key size (modulus size, in bits)
+ * \return the length of the private key buffer, in bytes.
+ */
+#define BR_RSA_KBUF_PRIV_SIZE(size) (5 * (((size) + 15) >> 4))
+
+/**
+ * \brief Get buffer size to hold RSA public key elements.
+ *
+ * This macro returns the length (in bytes) of the buffer needed to
+ * receive the elements of a RSA public key, as generated by one of
+ * the `br_rsa_*_keygen()` functions. If the provided size is a constant
+ * expression, then the whole macro evaluates to a constant expression.
+ *
+ * \param size target key size (modulus size, in bits)
+ * \return the length of the public key buffer, in bytes.
+ */
+#define BR_RSA_KBUF_PUB_SIZE(size) (4 + (((size) + 7) >> 3))
+
+/**
+ * \brief Type for RSA key pair generator implementation.
+ *
+ * This function generates a new RSA key pair whose modulus has bit
+ * length `size` bits. The private key elements are written in the
+ * `kbuf_priv` buffer, and pointer values and length fields to these
+ * elements are populated in the provided private key structure `sk`.
+ * Similarly, the public key elements are written in `kbuf_pub`, with
+ * pointers and lengths set in `pk`.
+ *
+ * If `pk` is `NULL`, then `kbuf_pub` may be `NULL`, and only the
+ * private key is set.
+ *
+ * If `pubexp` is not zero, then its value will be used as public
+ * exponent. Valid RSA public exponent values are odd integers
+ * greater than 1. If `pubexp` is zero, then the public exponent will
+ * have value 3.
+ *
+ * The provided PRNG (`rng_ctx`) must have already been initialized
+ * and seeded.
+ *
+ * Returned value is 1 on success, 0 on error. An error is reported
+ * if the requested range is outside of the supported key sizes, or
+ * if an invalid non-zero public exponent value is provided. Supported
+ * range starts at 512 bits, and up to an implementation-defined
+ * maximum (by default 4096 bits). Note that key sizes up to 768 bits
+ * have been broken in practice, and sizes lower than 2048 bits are
+ * usually considered to be weak and should not be used.
+ *
+ * \param rng_ctx source PRNG context (already initialized)
+ * \param sk RSA private key structure (destination)
+ * \param kbuf_priv buffer for private key elements
+ * \param pk RSA public key structure (destination), or `NULL`
+ * \param kbuf_pub buffer for public key elements, or `NULL`
+ * \param size target RSA modulus size (in bits)
+ * \param pubexp public exponent to use, or zero
+ * \return 1 on success, 0 on error (invalid parameters)
+ */
+typedef uint32_t (*br_rsa_keygen)(
+ const br_prng_class **rng_ctx,
+ br_rsa_private_key *sk, void *kbuf_priv,
+ br_rsa_public_key *pk, void *kbuf_pub,
+ unsigned size, uint32_t pubexp);
+
+/**
+ * \brief RSA key pair generation with the "i15" engine.
+ *
+ * \see br_rsa_keygen
+ *
+ * \param rng_ctx source PRNG context (already initialized)
+ * \param sk RSA private key structure (destination)
+ * \param kbuf_priv buffer for private key elements
+ * \param pk RSA public key structure (destination), or `NULL`
+ * \param kbuf_pub buffer for public key elements, or `NULL`
+ * \param size target RSA modulus size (in bits)
+ * \param pubexp public exponent to use, or zero
+ * \return 1 on success, 0 on error (invalid parameters)
+ */
+uint32_t br_rsa_i15_keygen(
+ const br_prng_class **rng_ctx,
+ br_rsa_private_key *sk, void *kbuf_priv,
+ br_rsa_public_key *pk, void *kbuf_pub,
+ unsigned size, uint32_t pubexp);
+
+/**
+ * \brief RSA key pair generation with the "i31" engine.
+ *
+ * \see br_rsa_keygen
+ *
+ * \param rng_ctx source PRNG context (already initialized)
+ * \param sk RSA private key structure (destination)
+ * \param kbuf_priv buffer for private key elements
+ * \param pk RSA public key structure (destination), or `NULL`
+ * \param kbuf_pub buffer for public key elements, or `NULL`
+ * \param size target RSA modulus size (in bits)
+ * \param pubexp public exponent to use, or zero
+ * \return 1 on success, 0 on error (invalid parameters)
+ */
+uint32_t br_rsa_i31_keygen(
+ const br_prng_class **rng_ctx,
+ br_rsa_private_key *sk, void *kbuf_priv,
+ br_rsa_public_key *pk, void *kbuf_pub,
+ unsigned size, uint32_t pubexp);
+
+/**
+ * \brief RSA key pair generation with the "i62" engine.
+ *
+ * This function is defined only on architecture that offer a 64x64->128
+ * opcode. Use `br_rsa_i62_keygen_get()` to dynamically obtain a pointer
+ * to that function.
+ *
+ * \see br_rsa_keygen
+ *
+ * \param rng_ctx source PRNG context (already initialized)
+ * \param sk RSA private key structure (destination)
+ * \param kbuf_priv buffer for private key elements
+ * \param pk RSA public key structure (destination), or `NULL`
+ * \param kbuf_pub buffer for public key elements, or `NULL`
+ * \param size target RSA modulus size (in bits)
+ * \param pubexp public exponent to use, or zero
+ * \return 1 on success, 0 on error (invalid parameters)
+ */
+uint32_t br_rsa_i62_keygen(
+ const br_prng_class **rng_ctx,
+ br_rsa_private_key *sk, void *kbuf_priv,
+ br_rsa_public_key *pk, void *kbuf_pub,
+ unsigned size, uint32_t pubexp);
+
+/**
+ * \brief Get the RSA "i62" implementation (key pair generation),
+ * if available.
+ *
+ * \return the implementation, or 0.
+ */
+br_rsa_keygen br_rsa_i62_keygen_get(void);
+
+/**
+ * \brief Get "default" RSA implementation (key pair generation).
+ *
+ * This returns the preferred implementation of RSA (key pair generation)
+ * on the current system.
+ *
+ * \return the default implementation.
+ */
+br_rsa_keygen br_rsa_keygen_get_default(void);
+
+/**
+ * \brief Type for a modulus computing function.
+ *
+ * Such a function computes the public modulus from the private key. The
+ * encoded modulus (unsigned big-endian) is written on `n`, and the size
+ * (in bytes) is returned. If `n` is `NULL`, then the size is returned but
+ * the modulus itself is not computed.
+ *
+ * If the key size exceeds an internal limit, 0 is returned.
+ *
+ * \param n destination buffer (or `NULL`).
+ * \param sk RSA private key.
+ * \return the modulus length (in bytes), or 0.
+ */
+typedef size_t (*br_rsa_compute_modulus)(void *n, const br_rsa_private_key *sk);
+
+/**
+ * \brief Recompute RSA modulus ("i15" engine).
+ *
+ * \see br_rsa_compute_modulus
+ *
+ * \param n destination buffer (or `NULL`).
+ * \param sk RSA private key.
+ * \return the modulus length (in bytes), or 0.
+ */
+size_t br_rsa_i15_compute_modulus(void *n, const br_rsa_private_key *sk);
+
+/**
+ * \brief Recompute RSA modulus ("i31" engine).
+ *
+ * \see br_rsa_compute_modulus
+ *
+ * \param n destination buffer (or `NULL`).
+ * \param sk RSA private key.
+ * \return the modulus length (in bytes), or 0.
+ */
+size_t br_rsa_i31_compute_modulus(void *n, const br_rsa_private_key *sk);
+
+/**
+ * \brief Get "default" RSA implementation (recompute modulus).
+ *
+ * This returns the preferred implementation of RSA (recompute modulus)
+ * on the current system.
+ *
+ * \return the default implementation.
+ */
+br_rsa_compute_modulus br_rsa_compute_modulus_get_default(void);
+
+/**
+ * \brief Type for a public exponent computing function.
+ *
+ * Such a function recomputes the public exponent from the private key.
+ * 0 is returned if any of the following occurs:
+ *
+ * - Either `p` or `q` is not equal to 3 modulo 4.
+ *
+ * - The public exponent does not fit on 32 bits.
+ *
+ * - An internal limit is exceeded.
+ *
+ * - The private key is invalid in some way.
+ *
+ * For all private keys produced by the key generator functions
+ * (`br_rsa_keygen` type), this function succeeds and returns the true
+ * public exponent. The public exponent is always an odd integer greater
+ * than 1.
+ *
+ * \return the public exponent, or 0.
+ */
+typedef uint32_t (*br_rsa_compute_pubexp)(const br_rsa_private_key *sk);
+
+/**
+ * \brief Recompute RSA public exponent ("i15" engine).
+ *
+ * \see br_rsa_compute_pubexp
+ *
+ * \return the public exponent, or 0.
+ */
+uint32_t br_rsa_i15_compute_pubexp(const br_rsa_private_key *sk);
+
+/**
+ * \brief Recompute RSA public exponent ("i31" engine).
+ *
+ * \see br_rsa_compute_pubexp
+ *
+ * \return the public exponent, or 0.
+ */
+uint32_t br_rsa_i31_compute_pubexp(const br_rsa_private_key *sk);
+
+/**
+ * \brief Get "default" RSA implementation (recompute public exponent).
+ *
+ * This returns the preferred implementation of RSA (recompute public
+ * exponent) on the current system.
+ *
+ * \return the default implementation.
+ */
+br_rsa_compute_pubexp br_rsa_compute_pubexp_get_default(void);
+
+/**
+ * \brief Type for a private exponent computing function.
+ *
+ * An RSA private key (`br_rsa_private_key`) contains two reduced
+ * private exponents, which are sufficient to perform private key
+ * operations. However, standard encoding formats for RSA private keys
+ * require also a copy of the complete private exponent (non-reduced),
+ * which this function recomputes.
+ *
+ * This function suceeds if all the following conditions hold:
+ *
+ * - Both private factors `p` and `q` are equal to 3 modulo 4.
+ *
+ * - The provided public exponent `pubexp` is correct, and, in particular,
+ * is odd, relatively prime to `p-1` and `q-1`, and greater than 1.
+ *
+ * - No internal storage limit is exceeded.
+ *
+ * For all private keys produced by the key generator functions
+ * (`br_rsa_keygen` type), this function succeeds. Note that the API
+ * restricts the public exponent to a maximum size of 32 bits.
+ *
+ * The encoded private exponent is written in `d` (unsigned big-endian
+ * convention), and the length (in bytes) is returned. If `d` is `NULL`,
+ * then the exponent is not written anywhere, but the length is still
+ * returned. On error, 0 is returned.
+ *
+ * Not all error conditions are detected when `d` is `NULL`; therefore, the
+ * returned value shall be checked also when actually producing the value.
+ *
+ * \param d destination buffer (or `NULL`).
+ * \param sk RSA private key.
+ * \param pubexp the public exponent.
+ * \return the private exponent length (in bytes), or 0.
+ */
+typedef size_t (*br_rsa_compute_privexp)(void *d,
+ const br_rsa_private_key *sk, uint32_t pubexp);
+
+/**
+ * \brief Recompute RSA private exponent ("i15" engine).
+ *
+ * \see br_rsa_compute_privexp
+ *
+ * \param d destination buffer (or `NULL`).
+ * \param sk RSA private key.
+ * \param pubexp the public exponent.
+ * \return the private exponent length (in bytes), or 0.
+ */
+size_t br_rsa_i15_compute_privexp(void *d,
+ const br_rsa_private_key *sk, uint32_t pubexp);
+
+/**
+ * \brief Recompute RSA private exponent ("i31" engine).
+ *
+ * \see br_rsa_compute_privexp
+ *
+ * \param d destination buffer (or `NULL`).
+ * \param sk RSA private key.
+ * \param pubexp the public exponent.
+ * \return the private exponent length (in bytes), or 0.
+ */
+size_t br_rsa_i31_compute_privexp(void *d,
+ const br_rsa_private_key *sk, uint32_t pubexp);
+
+/**
+ * \brief Get "default" RSA implementation (recompute private exponent).
+ *
+ * This returns the preferred implementation of RSA (recompute private
+ * exponent) on the current system.
+ *
+ * \return the default implementation.
+ */
+br_rsa_compute_privexp br_rsa_compute_privexp_get_default(void);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/bearssl/inc/bearssl_ssl.h b/contrib/bearssl/inc/bearssl_ssl.h
new file mode 100644
index 000000000000..8c8c86bdb50a
--- /dev/null
+++ b/contrib/bearssl/inc/bearssl_ssl.h
@@ -0,0 +1,4296 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef BR_BEARSSL_SSL_H__
+#define BR_BEARSSL_SSL_H__
+
+#include <stddef.h>
+#include <stdint.h>
+
+#include "bearssl_block.h"
+#include "bearssl_hash.h"
+#include "bearssl_hmac.h"
+#include "bearssl_prf.h"
+#include "bearssl_rand.h"
+#include "bearssl_x509.h"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_ssl.h
+ *
+ * # SSL
+ *
+ * For an overview of the SSL/TLS API, see [the BearSSL Web
+ * site](https://www.bearssl.org/api1.html).
+ *
+ * The `BR_TLS_*` constants correspond to the standard cipher suites and
+ * their values in the [IANA
+ * registry](http://www.iana.org/assignments/tls-parameters/tls-parameters.xhtml#tls-parameters-4).
+ *
+ * The `BR_ALERT_*` constants are for standard TLS alert messages. When
+ * a fatal alert message is sent of received, then the SSL engine context
+ * status is set to the sum of that alert value (an integer in the 0..255
+ * range) and a fixed offset (`BR_ERR_SEND_FATAL_ALERT` for a sent alert,
+ * `BR_ERR_RECV_FATAL_ALERT` for a received alert).
+ */
+
+/** \brief Optimal input buffer size. */
+#define BR_SSL_BUFSIZE_INPUT (16384 + 325)
+
+/** \brief Optimal output buffer size. */
+#define BR_SSL_BUFSIZE_OUTPUT (16384 + 85)
+
+/** \brief Optimal buffer size for monodirectional engine
+ (shared input/output buffer). */
+#define BR_SSL_BUFSIZE_MONO BR_SSL_BUFSIZE_INPUT
+
+/** \brief Optimal buffer size for bidirectional engine
+ (single buffer split into two separate input/output buffers). */
+#define BR_SSL_BUFSIZE_BIDI (BR_SSL_BUFSIZE_INPUT + BR_SSL_BUFSIZE_OUTPUT)
+
+/*
+ * Constants for known SSL/TLS protocol versions (SSL 3.0, TLS 1.0, TLS 1.1
+ * and TLS 1.2). Note that though there is a constant for SSL 3.0, that
+ * protocol version is not actually supported.
+ */
+
+/** \brief Protocol version: SSL 3.0 (unsupported). */
+#define BR_SSL30 0x0300
+/** \brief Protocol version: TLS 1.0. */
+#define BR_TLS10 0x0301
+/** \brief Protocol version: TLS 1.1. */
+#define BR_TLS11 0x0302
+/** \brief Protocol version: TLS 1.2. */
+#define BR_TLS12 0x0303
+
+/*
+ * Error constants. They are used to report the reason why a context has
+ * been marked as failed.
+ *
+ * Implementation note: SSL-level error codes should be in the 1..31
+ * range. The 32..63 range is for certificate decoding and validation
+ * errors. Received fatal alerts imply an error code in the 256..511 range.
+ */
+
+/** \brief SSL status: no error so far (0). */
+#define BR_ERR_OK 0
+
+/** \brief SSL status: caller-provided parameter is incorrect. */
+#define BR_ERR_BAD_PARAM 1
+
+/** \brief SSL status: operation requested by the caller cannot be applied
+ with the current context state (e.g. reading data while outgoing data
+ is waiting to be sent). */
+#define BR_ERR_BAD_STATE 2
+
+/** \brief SSL status: incoming protocol or record version is unsupported. */
+#define BR_ERR_UNSUPPORTED_VERSION 3
+
+/** \brief SSL status: incoming record version does not match the expected
+ version. */
+#define BR_ERR_BAD_VERSION 4
+
+/** \brief SSL status: incoming record length is invalid. */
+#define BR_ERR_BAD_LENGTH 5
+
+/** \brief SSL status: incoming record is too large to be processed, or
+ buffer is too small for the handshake message to send. */
+#define BR_ERR_TOO_LARGE 6
+
+/** \brief SSL status: decryption found an invalid padding, or the record
+ MAC is not correct. */
+#define BR_ERR_BAD_MAC 7
+
+/** \brief SSL status: no initial entropy was provided, and none can be
+ obtained from the OS. */
+#define BR_ERR_NO_RANDOM 8
+
+/** \brief SSL status: incoming record type is unknown. */
+#define BR_ERR_UNKNOWN_TYPE 9
+
+/** \brief SSL status: incoming record or message has wrong type with
+ regards to the current engine state. */
+#define BR_ERR_UNEXPECTED 10
+
+/** \brief SSL status: ChangeCipherSpec message from the peer has invalid
+ contents. */
+#define BR_ERR_BAD_CCS 12
+
+/** \brief SSL status: alert message from the peer has invalid contents
+ (odd length). */
+#define BR_ERR_BAD_ALERT 13
+
+/** \brief SSL status: incoming handshake message decoding failed. */
+#define BR_ERR_BAD_HANDSHAKE 14
+
+/** \brief SSL status: ServerHello contains a session ID which is larger
+ than 32 bytes. */
+#define BR_ERR_OVERSIZED_ID 15
+
+/** \brief SSL status: server wants to use a cipher suite that we did
+ not claim to support. This is also reported if we tried to advertise
+ a cipher suite that we do not support. */
+#define BR_ERR_BAD_CIPHER_SUITE 16
+
+/** \brief SSL status: server wants to use a compression that we did not
+ claim to support. */
+#define BR_ERR_BAD_COMPRESSION 17
+
+/** \brief SSL status: server's max fragment length does not match
+ client's. */
+#define BR_ERR_BAD_FRAGLEN 18
+
+/** \brief SSL status: secure renegotiation failed. */
+#define BR_ERR_BAD_SECRENEG 19
+
+/** \brief SSL status: server sent an extension type that we did not
+ announce, or used the same extension type several times in a single
+ ServerHello. */
+#define BR_ERR_EXTRA_EXTENSION 20
+
+/** \brief SSL status: invalid Server Name Indication contents (when
+ used by the server, this extension shall be empty). */
+#define BR_ERR_BAD_SNI 21
+
+/** \brief SSL status: invalid ServerHelloDone from the server (length
+ is not 0). */
+#define BR_ERR_BAD_HELLO_DONE 22
+
+/** \brief SSL status: internal limit exceeded (e.g. server's public key
+ is too large). */
+#define BR_ERR_LIMIT_EXCEEDED 23
+
+/** \brief SSL status: Finished message from peer does not match the
+ expected value. */
+#define BR_ERR_BAD_FINISHED 24
+
+/** \brief SSL status: session resumption attempt with distinct version
+ or cipher suite. */
+#define BR_ERR_RESUME_MISMATCH 25
+
+/** \brief SSL status: unsupported or invalid algorithm (ECDHE curve,
+ signature algorithm, hash function). */
+#define BR_ERR_INVALID_ALGORITHM 26
+
+/** \brief SSL status: invalid signature (on ServerKeyExchange from
+ server, or in CertificateVerify from client). */
+#define BR_ERR_BAD_SIGNATURE 27
+
+/** \brief SSL status: peer's public key does not have the proper type
+ or is not allowed for requested operation. */
+#define BR_ERR_WRONG_KEY_USAGE 28
+
+/** \brief SSL status: client did not send a certificate upon request,
+ or the client certificate could not be validated. */
+#define BR_ERR_NO_CLIENT_AUTH 29
+
+/** \brief SSL status: I/O error or premature close on underlying
+ transport stream. This error code is set only by the simplified
+ I/O API ("br_sslio_*"). */
+#define BR_ERR_IO 31
+
+/** \brief SSL status: base value for a received fatal alert.
+
+ When a fatal alert is received from the peer, the alert value
+ is added to this constant. */
+#define BR_ERR_RECV_FATAL_ALERT 256
+
+/** \brief SSL status: base value for a sent fatal alert.
+
+ When a fatal alert is sent to the peer, the alert value is added
+ to this constant. */
+#define BR_ERR_SEND_FATAL_ALERT 512
+
+/* ===================================================================== */
+
+/**
+ * \brief Decryption engine for SSL.
+ *
+ * When processing incoming records, the SSL engine will use a decryption
+ * engine that uses a specific context structure, and has a set of
+ * methods (a vtable) that follows this template.
+ *
+ * The decryption engine is responsible for applying decryption, verifying
+ * MAC, and keeping track of the record sequence number.
+ */
+typedef struct br_sslrec_in_class_ br_sslrec_in_class;
+struct br_sslrec_in_class_ {
+ /**
+ * \brief Context size (in bytes).
+ */
+ size_t context_size;
+
+ /**
+ * \brief Test validity of the incoming record length.
+ *
+ * This function returns 1 if the announced length for an
+ * incoming record is valid, 0 otherwise,
+ *
+ * \param ctx decryption engine context.
+ * \param record_len incoming record length.
+ * \return 1 of a valid length, 0 otherwise.
+ */
+ int (*check_length)(const br_sslrec_in_class *const *ctx,
+ size_t record_len);
+
+ /**
+ * \brief Decrypt the incoming record.
+ *
+ * This function may assume that the record length is valid
+ * (it has been previously tested with `check_length()`).
+ * Decryption is done in place; `*len` is updated with the
+ * cleartext length, and the address of the first plaintext
+ * byte is returned. If the record is correct but empty, then
+ * `*len` is set to 0 and a non-`NULL` pointer is returned.
+ *
+ * On decryption/MAC error, `NULL` is returned.
+ *
+ * \param ctx decryption engine context.
+ * \param record_type record type (23 for application data, etc).
+ * \param version record version.
+ * \param payload address of encrypted payload.
+ * \param len pointer to payload length (updated).
+ * \return pointer to plaintext, or `NULL` on error.
+ */
+ unsigned char *(*decrypt)(const br_sslrec_in_class **ctx,
+ int record_type, unsigned version,
+ void *payload, size_t *len);
+};
+
+/**
+ * \brief Encryption engine for SSL.
+ *
+ * When building outgoing records, the SSL engine will use an encryption
+ * engine that uses a specific context structure, and has a set of
+ * methods (a vtable) that follows this template.
+ *
+ * The encryption engine is responsible for applying encryption and MAC,
+ * and keeping track of the record sequence number.
+ */
+typedef struct br_sslrec_out_class_ br_sslrec_out_class;
+struct br_sslrec_out_class_ {
+ /**
+ * \brief Context size (in bytes).
+ */
+ size_t context_size;
+
+ /**
+ * \brief Compute maximum plaintext sizes and offsets.
+ *
+ * When this function is called, the `*start` and `*end`
+ * values contain offsets designating the free area in the
+ * outgoing buffer for plaintext data; that free area is
+ * preceded by a 5-byte space which will receive the record
+ * header.
+ *
+ * The `max_plaintext()` function is responsible for adjusting
+ * both `*start` and `*end` to make room for any record-specific
+ * header, MAC, padding, and possible split.
+ *
+ * \param ctx encryption engine context.
+ * \param start pointer to start of plaintext offset (updated).
+ * \param end pointer to start of plaintext offset (updated).
+ */
+ void (*max_plaintext)(const br_sslrec_out_class *const *ctx,
+ size_t *start, size_t *end);
+
+ /**
+ * \brief Perform record encryption.
+ *
+ * This function encrypts the record. The plaintext address and
+ * length are provided. Returned value is the start of the
+ * encrypted record (or sequence of records, if a split was
+ * performed), _including_ the 5-byte header, and `*len` is
+ * adjusted to the total size of the record(s), there again
+ * including the header(s).
+ *
+ * \param ctx decryption engine context.
+ * \param record_type record type (23 for application data, etc).
+ * \param version record version.
+ * \param plaintext address of plaintext.
+ * \param len pointer to plaintext length (updated).
+ * \return pointer to start of built record.
+ */
+ unsigned char *(*encrypt)(const br_sslrec_out_class **ctx,
+ int record_type, unsigned version,
+ void *plaintext, size_t *len);
+};
+
+/**
+ * \brief Context for a no-encryption engine.
+ *
+ * The no-encryption engine processes outgoing records during the initial
+ * handshake, before encryption is applied.
+ */
+typedef struct {
+ /** \brief No-encryption engine vtable. */
+ const br_sslrec_out_class *vtable;
+} br_sslrec_out_clear_context;
+
+/** \brief Static, constant vtable for the no-encryption engine. */
+extern const br_sslrec_out_class br_sslrec_out_clear_vtable;
+
+/* ===================================================================== */
+
+/**
+ * \brief Record decryption engine class, for CBC mode.
+ *
+ * This class type extends the decryption engine class with an
+ * initialisation method that receives the parameters needed
+ * for CBC processing: block cipher implementation, block cipher key,
+ * HMAC parameters (hash function, key, MAC length), and IV. If the
+ * IV is `NULL`, then a per-record IV will be used (TLS 1.1+).
+ */
+typedef struct br_sslrec_in_cbc_class_ br_sslrec_in_cbc_class;
+struct br_sslrec_in_cbc_class_ {
+ /**
+ * \brief Superclass, as first vtable field.
+ */
+ br_sslrec_in_class inner;
+
+ /**
+ * \brief Engine initialisation method.
+ *
+ * This method sets the vtable field in the context.
+ *
+ * \param ctx context to initialise.
+ * \param bc_impl block cipher implementation (CBC decryption).
+ * \param bc_key block cipher key.
+ * \param bc_key_len block cipher key length (in bytes).
+ * \param dig_impl hash function for HMAC.
+ * \param mac_key HMAC key.
+ * \param mac_key_len HMAC key length (in bytes).
+ * \param mac_out_len HMAC output length (in bytes).
+ * \param iv initial IV (or `NULL`).
+ */
+ void (*init)(const br_sslrec_in_cbc_class **ctx,
+ const br_block_cbcdec_class *bc_impl,
+ const void *bc_key, size_t bc_key_len,
+ const br_hash_class *dig_impl,
+ const void *mac_key, size_t mac_key_len, size_t mac_out_len,
+ const void *iv);
+};
+
+/**
+ * \brief Record encryption engine class, for CBC mode.
+ *
+ * This class type extends the encryption engine class with an
+ * initialisation method that receives the parameters needed
+ * for CBC processing: block cipher implementation, block cipher key,
+ * HMAC parameters (hash function, key, MAC length), and IV. If the
+ * IV is `NULL`, then a per-record IV will be used (TLS 1.1+).
+ */
+typedef struct br_sslrec_out_cbc_class_ br_sslrec_out_cbc_class;
+struct br_sslrec_out_cbc_class_ {
+ /**
+ * \brief Superclass, as first vtable field.
+ */
+ br_sslrec_out_class inner;
+
+ /**
+ * \brief Engine initialisation method.
+ *
+ * This method sets the vtable field in the context.
+ *
+ * \param ctx context to initialise.
+ * \param bc_impl block cipher implementation (CBC encryption).
+ * \param bc_key block cipher key.
+ * \param bc_key_len block cipher key length (in bytes).
+ * \param dig_impl hash function for HMAC.
+ * \param mac_key HMAC key.
+ * \param mac_key_len HMAC key length (in bytes).
+ * \param mac_out_len HMAC output length (in bytes).
+ * \param iv initial IV (or `NULL`).
+ */
+ void (*init)(const br_sslrec_out_cbc_class **ctx,
+ const br_block_cbcenc_class *bc_impl,
+ const void *bc_key, size_t bc_key_len,
+ const br_hash_class *dig_impl,
+ const void *mac_key, size_t mac_key_len, size_t mac_out_len,
+ const void *iv);
+};
+
+/**
+ * \brief Context structure for decrypting incoming records with
+ * CBC + HMAC.
+ *
+ * The first field points to the vtable. The other fields are opaque
+ * and shall not be accessed directly.
+ */
+typedef struct {
+ /** \brief Pointer to vtable. */
+ const br_sslrec_in_cbc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint64_t seq;
+ union {
+ const br_block_cbcdec_class *vtable;
+ br_aes_gen_cbcdec_keys aes;
+ br_des_gen_cbcdec_keys des;
+ } bc;
+ br_hmac_key_context mac;
+ size_t mac_len;
+ unsigned char iv[16];
+ int explicit_IV;
+#endif
+} br_sslrec_in_cbc_context;
+
+/**
+ * \brief Static, constant vtable for record decryption with CBC.
+ */
+extern const br_sslrec_in_cbc_class br_sslrec_in_cbc_vtable;
+
+/**
+ * \brief Context structure for encrypting outgoing records with
+ * CBC + HMAC.
+ *
+ * The first field points to the vtable. The other fields are opaque
+ * and shall not be accessed directly.
+ */
+typedef struct {
+ /** \brief Pointer to vtable. */
+ const br_sslrec_out_cbc_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint64_t seq;
+ union {
+ const br_block_cbcenc_class *vtable;
+ br_aes_gen_cbcenc_keys aes;
+ br_des_gen_cbcenc_keys des;
+ } bc;
+ br_hmac_key_context mac;
+ size_t mac_len;
+ unsigned char iv[16];
+ int explicit_IV;
+#endif
+} br_sslrec_out_cbc_context;
+
+/**
+ * \brief Static, constant vtable for record encryption with CBC.
+ */
+extern const br_sslrec_out_cbc_class br_sslrec_out_cbc_vtable;
+
+/* ===================================================================== */
+
+/**
+ * \brief Record decryption engine class, for GCM mode.
+ *
+ * This class type extends the decryption engine class with an
+ * initialisation method that receives the parameters needed
+ * for GCM processing: block cipher implementation, block cipher key,
+ * GHASH implementation, and 4-byte IV.
+ */
+typedef struct br_sslrec_in_gcm_class_ br_sslrec_in_gcm_class;
+struct br_sslrec_in_gcm_class_ {
+ /**
+ * \brief Superclass, as first vtable field.
+ */
+ br_sslrec_in_class inner;
+
+ /**
+ * \brief Engine initialisation method.
+ *
+ * This method sets the vtable field in the context.
+ *
+ * \param ctx context to initialise.
+ * \param bc_impl block cipher implementation (CTR).
+ * \param key block cipher key.
+ * \param key_len block cipher key length (in bytes).
+ * \param gh_impl GHASH implementation.
+ * \param iv static IV (4 bytes).
+ */
+ void (*init)(const br_sslrec_in_gcm_class **ctx,
+ const br_block_ctr_class *bc_impl,
+ const void *key, size_t key_len,
+ br_ghash gh_impl,
+ const void *iv);
+};
+
+/**
+ * \brief Record encryption engine class, for GCM mode.
+ *
+ * This class type extends the encryption engine class with an
+ * initialisation method that receives the parameters needed
+ * for GCM processing: block cipher implementation, block cipher key,
+ * GHASH implementation, and 4-byte IV.
+ */
+typedef struct br_sslrec_out_gcm_class_ br_sslrec_out_gcm_class;
+struct br_sslrec_out_gcm_class_ {
+ /**
+ * \brief Superclass, as first vtable field.
+ */
+ br_sslrec_out_class inner;
+
+ /**
+ * \brief Engine initialisation method.
+ *
+ * This method sets the vtable field in the context.
+ *
+ * \param ctx context to initialise.
+ * \param bc_impl block cipher implementation (CTR).
+ * \param key block cipher key.
+ * \param key_len block cipher key length (in bytes).
+ * \param gh_impl GHASH implementation.
+ * \param iv static IV (4 bytes).
+ */
+ void (*init)(const br_sslrec_out_gcm_class **ctx,
+ const br_block_ctr_class *bc_impl,
+ const void *key, size_t key_len,
+ br_ghash gh_impl,
+ const void *iv);
+};
+
+/**
+ * \brief Context structure for processing records with GCM.
+ *
+ * The same context structure is used for encrypting and decrypting.
+ *
+ * The first field points to the vtable. The other fields are opaque
+ * and shall not be accessed directly.
+ */
+typedef struct {
+ /** \brief Pointer to vtable. */
+ union {
+ const void *gen;
+ const br_sslrec_in_gcm_class *in;
+ const br_sslrec_out_gcm_class *out;
+ } vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint64_t seq;
+ union {
+ const br_block_ctr_class *vtable;
+ br_aes_gen_ctr_keys aes;
+ } bc;
+ br_ghash gh;
+ unsigned char iv[4];
+ unsigned char h[16];
+#endif
+} br_sslrec_gcm_context;
+
+/**
+ * \brief Static, constant vtable for record decryption with GCM.
+ */
+extern const br_sslrec_in_gcm_class br_sslrec_in_gcm_vtable;
+
+/**
+ * \brief Static, constant vtable for record encryption with GCM.
+ */
+extern const br_sslrec_out_gcm_class br_sslrec_out_gcm_vtable;
+
+/* ===================================================================== */
+
+/**
+ * \brief Record decryption engine class, for ChaCha20+Poly1305.
+ *
+ * This class type extends the decryption engine class with an
+ * initialisation method that receives the parameters needed
+ * for ChaCha20+Poly1305 processing: ChaCha20 implementation,
+ * Poly1305 implementation, key, and 12-byte IV.
+ */
+typedef struct br_sslrec_in_chapol_class_ br_sslrec_in_chapol_class;
+struct br_sslrec_in_chapol_class_ {
+ /**
+ * \brief Superclass, as first vtable field.
+ */
+ br_sslrec_in_class inner;
+
+ /**
+ * \brief Engine initialisation method.
+ *
+ * This method sets the vtable field in the context.
+ *
+ * \param ctx context to initialise.
+ * \param ichacha ChaCha20 implementation.
+ * \param ipoly Poly1305 implementation.
+ * \param key secret key (32 bytes).
+ * \param iv static IV (12 bytes).
+ */
+ void (*init)(const br_sslrec_in_chapol_class **ctx,
+ br_chacha20_run ichacha,
+ br_poly1305_run ipoly,
+ const void *key, const void *iv);
+};
+
+/**
+ * \brief Record encryption engine class, for ChaCha20+Poly1305.
+ *
+ * This class type extends the encryption engine class with an
+ * initialisation method that receives the parameters needed
+ * for ChaCha20+Poly1305 processing: ChaCha20 implementation,
+ * Poly1305 implementation, key, and 12-byte IV.
+ */
+typedef struct br_sslrec_out_chapol_class_ br_sslrec_out_chapol_class;
+struct br_sslrec_out_chapol_class_ {
+ /**
+ * \brief Superclass, as first vtable field.
+ */
+ br_sslrec_out_class inner;
+
+ /**
+ * \brief Engine initialisation method.
+ *
+ * This method sets the vtable field in the context.
+ *
+ * \param ctx context to initialise.
+ * \param ichacha ChaCha20 implementation.
+ * \param ipoly Poly1305 implementation.
+ * \param key secret key (32 bytes).
+ * \param iv static IV (12 bytes).
+ */
+ void (*init)(const br_sslrec_out_chapol_class **ctx,
+ br_chacha20_run ichacha,
+ br_poly1305_run ipoly,
+ const void *key, const void *iv);
+};
+
+/**
+ * \brief Context structure for processing records with ChaCha20+Poly1305.
+ *
+ * The same context structure is used for encrypting and decrypting.
+ *
+ * The first field points to the vtable. The other fields are opaque
+ * and shall not be accessed directly.
+ */
+typedef struct {
+ /** \brief Pointer to vtable. */
+ union {
+ const void *gen;
+ const br_sslrec_in_chapol_class *in;
+ const br_sslrec_out_chapol_class *out;
+ } vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint64_t seq;
+ unsigned char key[32];
+ unsigned char iv[12];
+ br_chacha20_run ichacha;
+ br_poly1305_run ipoly;
+#endif
+} br_sslrec_chapol_context;
+
+/**
+ * \brief Static, constant vtable for record decryption with ChaCha20+Poly1305.
+ */
+extern const br_sslrec_in_chapol_class br_sslrec_in_chapol_vtable;
+
+/**
+ * \brief Static, constant vtable for record encryption with ChaCha20+Poly1305.
+ */
+extern const br_sslrec_out_chapol_class br_sslrec_out_chapol_vtable;
+
+/* ===================================================================== */
+
+/**
+ * \brief Record decryption engine class, for CCM mode.
+ *
+ * This class type extends the decryption engine class with an
+ * initialisation method that receives the parameters needed
+ * for CCM processing: block cipher implementation, block cipher key,
+ * and 4-byte IV.
+ */
+typedef struct br_sslrec_in_ccm_class_ br_sslrec_in_ccm_class;
+struct br_sslrec_in_ccm_class_ {
+ /**
+ * \brief Superclass, as first vtable field.
+ */
+ br_sslrec_in_class inner;
+
+ /**
+ * \brief Engine initialisation method.
+ *
+ * This method sets the vtable field in the context.
+ *
+ * \param ctx context to initialise.
+ * \param bc_impl block cipher implementation (CTR+CBC).
+ * \param key block cipher key.
+ * \param key_len block cipher key length (in bytes).
+ * \param iv static IV (4 bytes).
+ * \param tag_len tag length (in bytes)
+ */
+ void (*init)(const br_sslrec_in_ccm_class **ctx,
+ const br_block_ctrcbc_class *bc_impl,
+ const void *key, size_t key_len,
+ const void *iv, size_t tag_len);
+};
+
+/**
+ * \brief Record encryption engine class, for CCM mode.
+ *
+ * This class type extends the encryption engine class with an
+ * initialisation method that receives the parameters needed
+ * for CCM processing: block cipher implementation, block cipher key,
+ * and 4-byte IV.
+ */
+typedef struct br_sslrec_out_ccm_class_ br_sslrec_out_ccm_class;
+struct br_sslrec_out_ccm_class_ {
+ /**
+ * \brief Superclass, as first vtable field.
+ */
+ br_sslrec_out_class inner;
+
+ /**
+ * \brief Engine initialisation method.
+ *
+ * This method sets the vtable field in the context.
+ *
+ * \param ctx context to initialise.
+ * \param bc_impl block cipher implementation (CTR+CBC).
+ * \param key block cipher key.
+ * \param key_len block cipher key length (in bytes).
+ * \param iv static IV (4 bytes).
+ * \param tag_len tag length (in bytes)
+ */
+ void (*init)(const br_sslrec_out_ccm_class **ctx,
+ const br_block_ctrcbc_class *bc_impl,
+ const void *key, size_t key_len,
+ const void *iv, size_t tag_len);
+};
+
+/**
+ * \brief Context structure for processing records with CCM.
+ *
+ * The same context structure is used for encrypting and decrypting.
+ *
+ * The first field points to the vtable. The other fields are opaque
+ * and shall not be accessed directly.
+ */
+typedef struct {
+ /** \brief Pointer to vtable. */
+ union {
+ const void *gen;
+ const br_sslrec_in_ccm_class *in;
+ const br_sslrec_out_ccm_class *out;
+ } vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ uint64_t seq;
+ union {
+ const br_block_ctrcbc_class *vtable;
+ br_aes_gen_ctrcbc_keys aes;
+ } bc;
+ unsigned char iv[4];
+ size_t tag_len;
+#endif
+} br_sslrec_ccm_context;
+
+/**
+ * \brief Static, constant vtable for record decryption with CCM.
+ */
+extern const br_sslrec_in_ccm_class br_sslrec_in_ccm_vtable;
+
+/**
+ * \brief Static, constant vtable for record encryption with CCM.
+ */
+extern const br_sslrec_out_ccm_class br_sslrec_out_ccm_vtable;
+
+/* ===================================================================== */
+
+/**
+ * \brief Type for session parameters, to be saved for session resumption.
+ */
+typedef struct {
+ /** \brief Session ID buffer. */
+ unsigned char session_id[32];
+ /** \brief Session ID length (in bytes, at most 32). */
+ unsigned char session_id_len;
+ /** \brief Protocol version. */
+ uint16_t version;
+ /** \brief Cipher suite. */
+ uint16_t cipher_suite;
+ /** \brief Master secret. */
+ unsigned char master_secret[48];
+} br_ssl_session_parameters;
+
+#ifndef BR_DOXYGEN_IGNORE
+/*
+ * Maximum number of cipher suites supported by a client or server.
+ */
+#define BR_MAX_CIPHER_SUITES 48
+#endif
+
+/**
+ * \brief Context structure for SSL engine.
+ *
+ * This strucuture is common to the client and server; both the client
+ * context (`br_ssl_client_context`) and the server context
+ * (`br_ssl_server_context`) include a `br_ssl_engine_context` as their
+ * first field.
+ *
+ * The engine context manages records, including alerts, closures, and
+ * transitions to new encryption/MAC algorithms. Processing of handshake
+ * records is delegated to externally provided code. This structure
+ * should not be used directly.
+ *
+ * Structure contents are opaque and shall not be accessed directly.
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ /*
+ * The error code. When non-zero, then the state is "failed" and
+ * no I/O may occur until reset.
+ */
+ int err;
+
+ /*
+ * Configured I/O buffers. They are either disjoint, or identical.
+ */
+ unsigned char *ibuf, *obuf;
+ size_t ibuf_len, obuf_len;
+
+ /*
+ * Maximum fragment length applies to outgoing records; incoming
+ * records can be processed as long as they fit in the input
+ * buffer. It is guaranteed that incoming records at least as big
+ * as max_frag_len can be processed.
+ */
+ uint16_t max_frag_len;
+ unsigned char log_max_frag_len;
+ unsigned char peer_log_max_frag_len;
+
+ /*
+ * Buffering management registers.
+ */
+ size_t ixa, ixb, ixc;
+ size_t oxa, oxb, oxc;
+ unsigned char iomode;
+ unsigned char incrypt;
+
+ /*
+ * Shutdown flag: when set to non-zero, incoming record bytes
+ * will not be accepted anymore. This is used after a close_notify
+ * has been received: afterwards, the engine no longer claims that
+ * it could receive bytes from the transport medium.
+ */
+ unsigned char shutdown_recv;
+
+ /*
+ * 'record_type_in' is set to the incoming record type when the
+ * record header has been received.
+ * 'record_type_out' is used to make the next outgoing record
+ * header when it is ready to go.
+ */
+ unsigned char record_type_in, record_type_out;
+
+ /*
+ * When a record is received, its version is extracted:
+ * -- if 'version_in' is 0, then it is set to the received version;
+ * -- otherwise, if the received version is not identical to
+ * the 'version_in' contents, then a failure is reported.
+ *
+ * This implements the SSL requirement that all records shall
+ * use the negotiated protocol version, once decided (in the
+ * ServerHello). It is up to the handshake handler to adjust this
+ * field when necessary.
+ */
+ uint16_t version_in;
+
+ /*
+ * 'version_out' is used when the next outgoing record is ready
+ * to go.
+ */
+ uint16_t version_out;
+
+ /*
+ * Record handler contexts.
+ */
+ union {
+ const br_sslrec_in_class *vtable;
+ br_sslrec_in_cbc_context cbc;
+ br_sslrec_gcm_context gcm;
+ br_sslrec_chapol_context chapol;
+ br_sslrec_ccm_context ccm;
+ } in;
+ union {
+ const br_sslrec_out_class *vtable;
+ br_sslrec_out_clear_context clear;
+ br_sslrec_out_cbc_context cbc;
+ br_sslrec_gcm_context gcm;
+ br_sslrec_chapol_context chapol;
+ br_sslrec_ccm_context ccm;
+ } out;
+
+ /*
+ * The "application data" flag. Value:
+ * 0 handshake is in process, no application data acceptable
+ * 1 application data can be sent and received
+ * 2 closing, no application data can be sent, but some
+ * can still be received (and discarded)
+ */
+ unsigned char application_data;
+
+ /*
+ * Context RNG.
+ *
+ * rng_init_done is initially 0. It is set to 1 when the
+ * basic structure of the RNG is set, and 2 when some
+ * entropy has been pushed in. The value 2 marks the RNG
+ * as "properly seeded".
+ *
+ * rng_os_rand_done is initially 0. It is set to 1 when
+ * some seeding from the OS or hardware has been attempted.
+ */
+ br_hmac_drbg_context rng;
+ int rng_init_done;
+ int rng_os_rand_done;
+
+ /*
+ * Supported minimum and maximum versions, and cipher suites.
+ */
+ uint16_t version_min;
+ uint16_t version_max;
+ uint16_t suites_buf[BR_MAX_CIPHER_SUITES];
+ unsigned char suites_num;
+
+ /*
+ * For clients, the server name to send as a SNI extension. For
+ * servers, the name received in the SNI extension (if any).
+ */
+ char server_name[256];
+
+ /*
+ * "Security parameters". These are filled by the handshake
+ * handler, and used when switching encryption state.
+ */
+ unsigned char client_random[32];
+ unsigned char server_random[32];
+ br_ssl_session_parameters session;
+
+ /*
+ * ECDHE elements: curve and point from the peer. The server also
+ * uses that buffer for the point to send to the client.
+ */
+ unsigned char ecdhe_curve;
+ unsigned char ecdhe_point[133];
+ unsigned char ecdhe_point_len;
+
+ /*
+ * Secure renegotiation (RFC 5746): 'reneg' can be:
+ * 0 first handshake (server support is not known)
+ * 1 peer does not support secure renegotiation
+ * 2 peer supports secure renegotiation
+ *
+ * The saved_finished buffer contains the client and the
+ * server "Finished" values from the last handshake, in
+ * that order (12 bytes each).
+ */
+ unsigned char reneg;
+ unsigned char saved_finished[24];
+
+ /*
+ * Behavioural flags.
+ */
+ uint32_t flags;
+
+ /*
+ * Context variables for the handshake processor. The 'pad' must
+ * be large enough to accommodate an RSA-encrypted pre-master
+ * secret, or an RSA signature; since we want to support up to
+ * RSA-4096, this means at least 512 bytes. (Other pad usages
+ * require its length to be at least 256.)
+ */
+ struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+ } cpu;
+ uint32_t dp_stack[32];
+ uint32_t rp_stack[32];
+ unsigned char pad[512];
+ unsigned char *hbuf_in, *hbuf_out, *saved_hbuf_out;
+ size_t hlen_in, hlen_out;
+ void (*hsrun)(void *ctx);
+
+ /*
+ * The 'action' value communicates OOB information between the
+ * engine and the handshake processor.
+ *
+ * From the engine:
+ * 0 invocation triggered by I/O
+ * 1 invocation triggered by explicit close
+ * 2 invocation triggered by explicit renegotiation
+ */
+ unsigned char action;
+
+ /*
+ * State for alert messages. Value is either 0, or the value of
+ * the alert level byte (level is either 1 for warning, or 2 for
+ * fatal; we convert all other values to 'fatal').
+ */
+ unsigned char alert;
+
+ /*
+ * Closure flags. This flag is set when a close_notify has been
+ * received from the peer.
+ */
+ unsigned char close_received;
+
+ /*
+ * Multi-hasher for the handshake messages. The handshake handler
+ * is responsible for resetting it when appropriate.
+ */
+ br_multihash_context mhash;
+
+ /*
+ * Pointer to the X.509 engine. The engine is supposed to be
+ * already initialized. It is used to validate the peer's
+ * certificate.
+ */
+ const br_x509_class **x509ctx;
+
+ /*
+ * Certificate chain to send. This is used by both client and
+ * server, when they send their respective Certificate messages.
+ * If chain_len is 0, then chain may be NULL.
+ */
+ const br_x509_certificate *chain;
+ size_t chain_len;
+ const unsigned char *cert_cur;
+ size_t cert_len;
+
+ /*
+ * List of supported protocol names (ALPN extension). If unset,
+ * (number of names is 0), then:
+ * - the client sends no ALPN extension;
+ * - the server ignores any incoming ALPN extension.
+ *
+ * Otherwise:
+ * - the client sends an ALPN extension with all the names;
+ * - the server selects the first protocol in its list that
+ * the client also supports, or fails (fatal alert 120)
+ * if the client sends an ALPN extension and there is no
+ * match.
+ *
+ * The 'selected_protocol' field contains 1+n if the matching
+ * name has index n in the list (the value is 0 if no match was
+ * performed, e.g. the peer did not send an ALPN extension).
+ */
+ const char **protocol_names;
+ uint16_t protocol_names_num;
+ uint16_t selected_protocol;
+
+ /*
+ * Pointers to implementations; left to NULL for unsupported
+ * functions. For the raw hash functions, implementations are
+ * referenced from the multihasher (mhash field).
+ */
+ br_tls_prf_impl prf10;
+ br_tls_prf_impl prf_sha256;
+ br_tls_prf_impl prf_sha384;
+ const br_block_cbcenc_class *iaes_cbcenc;
+ const br_block_cbcdec_class *iaes_cbcdec;
+ const br_block_ctr_class *iaes_ctr;
+ const br_block_ctrcbc_class *iaes_ctrcbc;
+ const br_block_cbcenc_class *ides_cbcenc;
+ const br_block_cbcdec_class *ides_cbcdec;
+ br_ghash ighash;
+ br_chacha20_run ichacha;
+ br_poly1305_run ipoly;
+ const br_sslrec_in_cbc_class *icbc_in;
+ const br_sslrec_out_cbc_class *icbc_out;
+ const br_sslrec_in_gcm_class *igcm_in;
+ const br_sslrec_out_gcm_class *igcm_out;
+ const br_sslrec_in_chapol_class *ichapol_in;
+ const br_sslrec_out_chapol_class *ichapol_out;
+ const br_sslrec_in_ccm_class *iccm_in;
+ const br_sslrec_out_ccm_class *iccm_out;
+ const br_ec_impl *iec;
+ br_rsa_pkcs1_vrfy irsavrfy;
+ br_ecdsa_vrfy iecdsa;
+#endif
+} br_ssl_engine_context;
+
+/**
+ * \brief Get currently defined engine behavioural flags.
+ *
+ * \param cc SSL engine context.
+ * \return the flags.
+ */
+static inline uint32_t
+br_ssl_engine_get_flags(br_ssl_engine_context *cc)
+{
+ return cc->flags;
+}
+
+/**
+ * \brief Set all engine behavioural flags.
+ *
+ * \param cc SSL engine context.
+ * \param flags new value for all flags.
+ */
+static inline void
+br_ssl_engine_set_all_flags(br_ssl_engine_context *cc, uint32_t flags)
+{
+ cc->flags = flags;
+}
+
+/**
+ * \brief Set some engine behavioural flags.
+ *
+ * The flags set in the `flags` parameter are set in the context; other
+ * flags are untouched.
+ *
+ * \param cc SSL engine context.
+ * \param flags additional set flags.
+ */
+static inline void
+br_ssl_engine_add_flags(br_ssl_engine_context *cc, uint32_t flags)
+{
+ cc->flags |= flags;
+}
+
+/**
+ * \brief Clear some engine behavioural flags.
+ *
+ * The flags set in the `flags` parameter are cleared from the context; other
+ * flags are untouched.
+ *
+ * \param cc SSL engine context.
+ * \param flags flags to remove.
+ */
+static inline void
+br_ssl_engine_remove_flags(br_ssl_engine_context *cc, uint32_t flags)
+{
+ cc->flags &= ~flags;
+}
+
+/**
+ * \brief Behavioural flag: enforce server preferences.
+ *
+ * If this flag is set, then the server will enforce its own cipher suite
+ * preference order; otherwise, it follows the client preferences.
+ */
+#define BR_OPT_ENFORCE_SERVER_PREFERENCES ((uint32_t)1 << 0)
+
+/**
+ * \brief Behavioural flag: disable renegotiation.
+ *
+ * If this flag is set, then renegotiations are rejected unconditionally:
+ * they won't be honoured if asked for programmatically, and requests from
+ * the peer are rejected.
+ */
+#define BR_OPT_NO_RENEGOTIATION ((uint32_t)1 << 1)
+
+/**
+ * \brief Behavioural flag: tolerate lack of client authentication.
+ *
+ * If this flag is set in a server and the server requests a client
+ * certificate, but the authentication fails (the client does not send
+ * a certificate, or the client's certificate chain cannot be validated),
+ * then the connection keeps on. Without this flag, a failed client
+ * authentication terminates the connection.
+ *
+ * Notes:
+ *
+ * - If the client's certificate can be validated and its public key is
+ * supported, then a wrong signature value terminates the connection
+ * regardless of that flag.
+ *
+ * - If using full-static ECDH, then a failure to validate the client's
+ * certificate prevents the handshake from succeeding.
+ */
+#define BR_OPT_TOLERATE_NO_CLIENT_AUTH ((uint32_t)1 << 2)
+
+/**
+ * \brief Behavioural flag: fail on application protocol mismatch.
+ *
+ * The ALPN extension ([RFC 7301](https://tools.ietf.org/html/rfc7301))
+ * allows the client to send a list of application protocol names, and
+ * the server to select one. A mismatch is one of the following occurrences:
+ *
+ * - On the client: the client sends a list of names, the server
+ * responds with a protocol name which is _not_ part of the list of
+ * names sent by the client.
+ *
+ * - On the server: the client sends a list of names, and the server
+ * is also configured with a list of names, but there is no common
+ * protocol name between the two lists.
+ *
+ * Normal behaviour in case of mismatch is to report no matching name
+ * (`br_ssl_engine_get_selected_protocol()` returns `NULL`) and carry on.
+ * If the flag is set, then a mismatch implies a protocol failure (if
+ * the mismatch is detected by the server, it will send a fatal alert).
+ *
+ * Note: even with this flag, `br_ssl_engine_get_selected_protocol()`
+ * may still return `NULL` if the client or the server does not send an
+ * ALPN extension at all.
+ */
+#define BR_OPT_FAIL_ON_ALPN_MISMATCH ((uint32_t)1 << 3)
+
+/**
+ * \brief Set the minimum and maximum supported protocol versions.
+ *
+ * The two provided versions MUST be supported by the implementation
+ * (i.e. TLS 1.0, 1.1 and 1.2), and `version_max` MUST NOT be lower
+ * than `version_min`.
+ *
+ * \param cc SSL engine context.
+ * \param version_min minimum supported TLS version.
+ * \param version_max maximum supported TLS version.
+ */
+static inline void
+br_ssl_engine_set_versions(br_ssl_engine_context *cc,
+ unsigned version_min, unsigned version_max)
+{
+ cc->version_min = version_min;
+ cc->version_max = version_max;
+}
+
+/**
+ * \brief Set the list of cipher suites advertised by this context.
+ *
+ * The provided array is copied into the context. It is the caller
+ * responsibility to ensure that all provided suites will be supported
+ * by the context. The engine context has enough room to receive _all_
+ * suites supported by the implementation. The provided array MUST NOT
+ * contain duplicates.
+ *
+ * If the engine is for a client, the "signaling" pseudo-cipher suite
+ * `TLS_FALLBACK_SCSV` can be added at the end of the list, if the
+ * calling application is performing a voluntary downgrade (voluntary
+ * downgrades are not recommended, but if such a downgrade is done, then
+ * adding the fallback pseudo-suite is a good idea).
+ *
+ * \param cc SSL engine context.
+ * \param suites cipher suites.
+ * \param suites_num number of cipher suites.
+ */
+void br_ssl_engine_set_suites(br_ssl_engine_context *cc,
+ const uint16_t *suites, size_t suites_num);
+
+/**
+ * \brief Set the X.509 engine.
+ *
+ * The caller shall ensure that the X.509 engine is properly initialised.
+ *
+ * \param cc SSL engine context.
+ * \param x509ctx X.509 certificate validation context.
+ */
+static inline void
+br_ssl_engine_set_x509(br_ssl_engine_context *cc, const br_x509_class **x509ctx)
+{
+ cc->x509ctx = x509ctx;
+}
+
+/**
+ * \brief Set the supported protocol names.
+ *
+ * Protocol names are part of the ALPN extension ([RFC
+ * 7301](https://tools.ietf.org/html/rfc7301)). Each protocol name is a
+ * character string, containing no more than 255 characters (256 with the
+ * terminating zero). When names are set, then:
+ *
+ * - The client will send an ALPN extension, containing the names. If
+ * the server responds with an ALPN extension, the client will verify
+ * that the response contains one of its name, and report that name
+ * through `br_ssl_engine_get_selected_protocol()`.
+ *
+ * - The server will parse incoming ALPN extension (from clients), and
+ * try to find a common protocol; if none is found, the connection
+ * is aborted with a fatal alert. On match, a response ALPN extension
+ * is sent, and name is reported through
+ * `br_ssl_engine_get_selected_protocol()`.
+ *
+ * The provided array is linked in, and must remain valid while the
+ * connection is live.
+ *
+ * Names MUST NOT be empty. Names MUST NOT be longer than 255 characters
+ * (excluding the terminating 0).
+ *
+ * \param ctx SSL engine context.
+ * \param names list of protocol names (zero-terminated).
+ * \param num number of protocol names (MUST be 1 or more).
+ */
+static inline void
+br_ssl_engine_set_protocol_names(br_ssl_engine_context *ctx,
+ const char **names, size_t num)
+{
+ ctx->protocol_names = names;
+ ctx->protocol_names_num = num;
+}
+
+/**
+ * \brief Get the selected protocol.
+ *
+ * If this context was initialised with a non-empty list of protocol
+ * names, and both client and server sent ALPN extensions during the
+ * handshake, and a common name was found, then that name is returned.
+ * Otherwise, `NULL` is returned.
+ *
+ * The returned pointer is one of the pointers provided to the context
+ * with `br_ssl_engine_set_protocol_names()`.
+ *
+ * \return the selected protocol, or `NULL`.
+ */
+static inline const char *
+br_ssl_engine_get_selected_protocol(br_ssl_engine_context *ctx)
+{
+ unsigned k;
+
+ k = ctx->selected_protocol;
+ return (k == 0 || k == 0xFFFF) ? NULL : ctx->protocol_names[k - 1];
+}
+
+/**
+ * \brief Set a hash function implementation (by ID).
+ *
+ * Hash functions set with this call will be used for SSL/TLS specific
+ * usages, not X.509 certificate validation. Only "standard" hash functions
+ * may be set (MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512). If `impl`
+ * is `NULL`, then the hash function support is removed, not added.
+ *
+ * \param ctx SSL engine context.
+ * \param id hash function identifier.
+ * \param impl hash function implementation (or `NULL`).
+ */
+static inline void
+br_ssl_engine_set_hash(br_ssl_engine_context *ctx,
+ int id, const br_hash_class *impl)
+{
+ br_multihash_setimpl(&ctx->mhash, id, impl);
+}
+
+/**
+ * \brief Get a hash function implementation (by ID).
+ *
+ * This function retrieves a hash function implementation which was
+ * set with `br_ssl_engine_set_hash()`.
+ *
+ * \param ctx SSL engine context.
+ * \param id hash function identifier.
+ * \return the hash function implementation (or `NULL`).
+ */
+static inline const br_hash_class *
+br_ssl_engine_get_hash(br_ssl_engine_context *ctx, int id)
+{
+ return br_multihash_getimpl(&ctx->mhash, id);
+}
+
+/**
+ * \brief Set the PRF implementation (for TLS 1.0 and 1.1).
+ *
+ * This function sets (or removes, if `impl` is `NULL`) the implementation
+ * for the PRF used in TLS 1.0 and 1.1.
+ *
+ * \param cc SSL engine context.
+ * \param impl PRF implementation (or `NULL`).
+ */
+static inline void
+br_ssl_engine_set_prf10(br_ssl_engine_context *cc, br_tls_prf_impl impl)
+{
+ cc->prf10 = impl;
+}
+
+/**
+ * \brief Set the PRF implementation with SHA-256 (for TLS 1.2).
+ *
+ * This function sets (or removes, if `impl` is `NULL`) the implementation
+ * for the SHA-256 variant of the PRF used in TLS 1.2.
+ *
+ * \param cc SSL engine context.
+ * \param impl PRF implementation (or `NULL`).
+ */
+static inline void
+br_ssl_engine_set_prf_sha256(br_ssl_engine_context *cc, br_tls_prf_impl impl)
+{
+ cc->prf_sha256 = impl;
+}
+
+/**
+ * \brief Set the PRF implementation with SHA-384 (for TLS 1.2).
+ *
+ * This function sets (or removes, if `impl` is `NULL`) the implementation
+ * for the SHA-384 variant of the PRF used in TLS 1.2.
+ *
+ * \param cc SSL engine context.
+ * \param impl PRF implementation (or `NULL`).
+ */
+static inline void
+br_ssl_engine_set_prf_sha384(br_ssl_engine_context *cc, br_tls_prf_impl impl)
+{
+ cc->prf_sha384 = impl;
+}
+
+/**
+ * \brief Set the AES/CBC implementations.
+ *
+ * \param cc SSL engine context.
+ * \param impl_enc AES/CBC encryption implementation (or `NULL`).
+ * \param impl_dec AES/CBC decryption implementation (or `NULL`).
+ */
+static inline void
+br_ssl_engine_set_aes_cbc(br_ssl_engine_context *cc,
+ const br_block_cbcenc_class *impl_enc,
+ const br_block_cbcdec_class *impl_dec)
+{
+ cc->iaes_cbcenc = impl_enc;
+ cc->iaes_cbcdec = impl_dec;
+}
+
+/**
+ * \brief Set the "default" AES/CBC implementations.
+ *
+ * This function configures in the engine the AES implementations that
+ * should provide best runtime performance on the local system, while
+ * still being safe (in particular, constant-time). It also sets the
+ * handlers for CBC records.
+ *
+ * \param cc SSL engine context.
+ */
+void br_ssl_engine_set_default_aes_cbc(br_ssl_engine_context *cc);
+
+/**
+ * \brief Set the AES/CTR implementation.
+ *
+ * \param cc SSL engine context.
+ * \param impl AES/CTR encryption/decryption implementation (or `NULL`).
+ */
+static inline void
+br_ssl_engine_set_aes_ctr(br_ssl_engine_context *cc,
+ const br_block_ctr_class *impl)
+{
+ cc->iaes_ctr = impl;
+}
+
+/**
+ * \brief Set the "default" implementations for AES/GCM (AES/CTR + GHASH).
+ *
+ * This function configures in the engine the AES/CTR and GHASH
+ * implementation that should provide best runtime performance on the local
+ * system, while still being safe (in particular, constant-time). It also
+ * sets the handlers for GCM records.
+ *
+ * \param cc SSL engine context.
+ */
+void br_ssl_engine_set_default_aes_gcm(br_ssl_engine_context *cc);
+
+/**
+ * \brief Set the DES/CBC implementations.
+ *
+ * \param cc SSL engine context.
+ * \param impl_enc DES/CBC encryption implementation (or `NULL`).
+ * \param impl_dec DES/CBC decryption implementation (or `NULL`).
+ */
+static inline void
+br_ssl_engine_set_des_cbc(br_ssl_engine_context *cc,
+ const br_block_cbcenc_class *impl_enc,
+ const br_block_cbcdec_class *impl_dec)
+{
+ cc->ides_cbcenc = impl_enc;
+ cc->ides_cbcdec = impl_dec;
+}
+
+/**
+ * \brief Set the "default" DES/CBC implementations.
+ *
+ * This function configures in the engine the DES implementations that
+ * should provide best runtime performance on the local system, while
+ * still being safe (in particular, constant-time). It also sets the
+ * handlers for CBC records.
+ *
+ * \param cc SSL engine context.
+ */
+void br_ssl_engine_set_default_des_cbc(br_ssl_engine_context *cc);
+
+/**
+ * \brief Set the GHASH implementation (used in GCM mode).
+ *
+ * \param cc SSL engine context.
+ * \param impl GHASH implementation (or `NULL`).
+ */
+static inline void
+br_ssl_engine_set_ghash(br_ssl_engine_context *cc, br_ghash impl)
+{
+ cc->ighash = impl;
+}
+
+/**
+ * \brief Set the ChaCha20 implementation.
+ *
+ * \param cc SSL engine context.
+ * \param ichacha ChaCha20 implementation (or `NULL`).
+ */
+static inline void
+br_ssl_engine_set_chacha20(br_ssl_engine_context *cc,
+ br_chacha20_run ichacha)
+{
+ cc->ichacha = ichacha;
+}
+
+/**
+ * \brief Set the Poly1305 implementation.
+ *
+ * \param cc SSL engine context.
+ * \param ipoly Poly1305 implementation (or `NULL`).
+ */
+static inline void
+br_ssl_engine_set_poly1305(br_ssl_engine_context *cc,
+ br_poly1305_run ipoly)
+{
+ cc->ipoly = ipoly;
+}
+
+/**
+ * \brief Set the "default" ChaCha20 and Poly1305 implementations.
+ *
+ * This function configures in the engine the ChaCha20 and Poly1305
+ * implementations that should provide best runtime performance on the
+ * local system, while still being safe (in particular, constant-time).
+ * It also sets the handlers for ChaCha20+Poly1305 records.
+ *
+ * \param cc SSL engine context.
+ */
+void br_ssl_engine_set_default_chapol(br_ssl_engine_context *cc);
+
+/**
+ * \brief Set the AES/CTR+CBC implementation.
+ *
+ * \param cc SSL engine context.
+ * \param impl AES/CTR+CBC encryption/decryption implementation (or `NULL`).
+ */
+static inline void
+br_ssl_engine_set_aes_ctrcbc(br_ssl_engine_context *cc,
+ const br_block_ctrcbc_class *impl)
+{
+ cc->iaes_ctrcbc = impl;
+}
+
+/**
+ * \brief Set the "default" implementations for AES/CCM.
+ *
+ * This function configures in the engine the AES/CTR+CBC
+ * implementation that should provide best runtime performance on the local
+ * system, while still being safe (in particular, constant-time). It also
+ * sets the handlers for CCM records.
+ *
+ * \param cc SSL engine context.
+ */
+void br_ssl_engine_set_default_aes_ccm(br_ssl_engine_context *cc);
+
+/**
+ * \brief Set the record encryption and decryption engines for CBC + HMAC.
+ *
+ * \param cc SSL engine context.
+ * \param impl_in record CBC decryption implementation (or `NULL`).
+ * \param impl_out record CBC encryption implementation (or `NULL`).
+ */
+static inline void
+br_ssl_engine_set_cbc(br_ssl_engine_context *cc,
+ const br_sslrec_in_cbc_class *impl_in,
+ const br_sslrec_out_cbc_class *impl_out)
+{
+ cc->icbc_in = impl_in;
+ cc->icbc_out = impl_out;
+}
+
+/**
+ * \brief Set the record encryption and decryption engines for GCM.
+ *
+ * \param cc SSL engine context.
+ * \param impl_in record GCM decryption implementation (or `NULL`).
+ * \param impl_out record GCM encryption implementation (or `NULL`).
+ */
+static inline void
+br_ssl_engine_set_gcm(br_ssl_engine_context *cc,
+ const br_sslrec_in_gcm_class *impl_in,
+ const br_sslrec_out_gcm_class *impl_out)
+{
+ cc->igcm_in = impl_in;
+ cc->igcm_out = impl_out;
+}
+
+/**
+ * \brief Set the record encryption and decryption engines for CCM.
+ *
+ * \param cc SSL engine context.
+ * \param impl_in record CCM decryption implementation (or `NULL`).
+ * \param impl_out record CCM encryption implementation (or `NULL`).
+ */
+static inline void
+br_ssl_engine_set_ccm(br_ssl_engine_context *cc,
+ const br_sslrec_in_ccm_class *impl_in,
+ const br_sslrec_out_ccm_class *impl_out)
+{
+ cc->iccm_in = impl_in;
+ cc->iccm_out = impl_out;
+}
+
+/**
+ * \brief Set the record encryption and decryption engines for
+ * ChaCha20+Poly1305.
+ *
+ * \param cc SSL engine context.
+ * \param impl_in record ChaCha20 decryption implementation (or `NULL`).
+ * \param impl_out record ChaCha20 encryption implementation (or `NULL`).
+ */
+static inline void
+br_ssl_engine_set_chapol(br_ssl_engine_context *cc,
+ const br_sslrec_in_chapol_class *impl_in,
+ const br_sslrec_out_chapol_class *impl_out)
+{
+ cc->ichapol_in = impl_in;
+ cc->ichapol_out = impl_out;
+}
+
+/**
+ * \brief Set the EC implementation.
+ *
+ * The elliptic curve implementation will be used for ECDH and ECDHE
+ * cipher suites, and for ECDSA support.
+ *
+ * \param cc SSL engine context.
+ * \param iec EC implementation (or `NULL`).
+ */
+static inline void
+br_ssl_engine_set_ec(br_ssl_engine_context *cc, const br_ec_impl *iec)
+{
+ cc->iec = iec;
+}
+
+/**
+ * \brief Set the "default" EC implementation.
+ *
+ * This function sets the elliptic curve implementation for ECDH and
+ * ECDHE cipher suites, and for ECDSA support. It selects the fastest
+ * implementation on the current system.
+ *
+ * \param cc SSL engine context.
+ */
+void br_ssl_engine_set_default_ec(br_ssl_engine_context *cc);
+
+/**
+ * \brief Get the EC implementation configured in the provided engine.
+ *
+ * \param cc SSL engine context.
+ * \return the EC implementation.
+ */
+static inline const br_ec_impl *
+br_ssl_engine_get_ec(br_ssl_engine_context *cc)
+{
+ return cc->iec;
+}
+
+/**
+ * \brief Set the RSA signature verification implementation.
+ *
+ * On the client, this is used to verify the server's signature on its
+ * ServerKeyExchange message (for ECDHE_RSA cipher suites). On the server,
+ * this is used to verify the client's CertificateVerify message (if a
+ * client certificate is requested, and that certificate contains a RSA key).
+ *
+ * \param cc SSL engine context.
+ * \param irsavrfy RSA signature verification implementation.
+ */
+static inline void
+br_ssl_engine_set_rsavrfy(br_ssl_engine_context *cc, br_rsa_pkcs1_vrfy irsavrfy)
+{
+ cc->irsavrfy = irsavrfy;
+}
+
+/**
+ * \brief Set the "default" RSA implementation (signature verification).
+ *
+ * This function sets the RSA implementation (signature verification)
+ * to the fastest implementation available on the current platform.
+ *
+ * \param cc SSL engine context.
+ */
+void br_ssl_engine_set_default_rsavrfy(br_ssl_engine_context *cc);
+
+/**
+ * \brief Get the RSA implementation (signature verification) configured
+ * in the provided engine.
+ *
+ * \param cc SSL engine context.
+ * \return the RSA signature verification implementation.
+ */
+static inline br_rsa_pkcs1_vrfy
+br_ssl_engine_get_rsavrfy(br_ssl_engine_context *cc)
+{
+ return cc->irsavrfy;
+}
+
+/*
+ * \brief Set the ECDSA implementation (signature verification).
+ *
+ * On the client, this is used to verify the server's signature on its
+ * ServerKeyExchange message (for ECDHE_ECDSA cipher suites). On the server,
+ * this is used to verify the client's CertificateVerify message (if a
+ * client certificate is requested, that certificate contains an EC key,
+ * and full-static ECDH is not used).
+ *
+ * The ECDSA implementation will use the EC core implementation configured
+ * in the engine context.
+ *
+ * \param cc client context.
+ * \param iecdsa ECDSA verification implementation.
+ */
+static inline void
+br_ssl_engine_set_ecdsa(br_ssl_engine_context *cc, br_ecdsa_vrfy iecdsa)
+{
+ cc->iecdsa = iecdsa;
+}
+
+/**
+ * \brief Set the "default" ECDSA implementation (signature verification).
+ *
+ * This function sets the ECDSA implementation (signature verification)
+ * to the fastest implementation available on the current platform. This
+ * call also sets the elliptic curve implementation itself, there again
+ * to the fastest EC implementation available.
+ *
+ * \param cc SSL engine context.
+ */
+void br_ssl_engine_set_default_ecdsa(br_ssl_engine_context *cc);
+
+/**
+ * \brief Get the ECDSA implementation (signature verification) configured
+ * in the provided engine.
+ *
+ * \param cc SSL engine context.
+ * \return the ECDSA signature verification implementation.
+ */
+static inline br_ecdsa_vrfy
+br_ssl_engine_get_ecdsa(br_ssl_engine_context *cc)
+{
+ return cc->iecdsa;
+}
+
+/**
+ * \brief Set the I/O buffer for the SSL engine.
+ *
+ * Once this call has been made, `br_ssl_client_reset()` or
+ * `br_ssl_server_reset()` MUST be called before using the context.
+ *
+ * The provided buffer will be used as long as the engine context is
+ * used. The caller is responsible for keeping it available.
+ *
+ * If `bidi` is 0, then the engine will operate in half-duplex mode
+ * (it won't be able to send data while there is unprocessed incoming
+ * data in the buffer, and it won't be able to receive data while there
+ * is unsent data in the buffer). The optimal buffer size in half-duplex
+ * mode is `BR_SSL_BUFSIZE_MONO`; if the buffer is larger, then extra
+ * bytes are ignored. If the buffer is smaller, then this limits the
+ * capacity of the engine to support all allowed record sizes.
+ *
+ * If `bidi` is 1, then the engine will split the buffer into two
+ * parts, for separate handling of outgoing and incoming data. This
+ * enables full-duplex processing, but requires more RAM. The optimal
+ * buffer size in full-duplex mode is `BR_SSL_BUFSIZE_BIDI`; if the
+ * buffer is larger, then extra bytes are ignored. If the buffer is
+ * smaller, then the split will favour the incoming part, so that
+ * interoperability is maximised.
+ *
+ * \param cc SSL engine context
+ * \param iobuf I/O buffer.
+ * \param iobuf_len I/O buffer length (in bytes).
+ * \param bidi non-zero for full-duplex mode.
+ */
+void br_ssl_engine_set_buffer(br_ssl_engine_context *cc,
+ void *iobuf, size_t iobuf_len, int bidi);
+
+/**
+ * \brief Set the I/O buffers for the SSL engine.
+ *
+ * Once this call has been made, `br_ssl_client_reset()` or
+ * `br_ssl_server_reset()` MUST be called before using the context.
+ *
+ * This function is similar to `br_ssl_engine_set_buffer()`, except
+ * that it enforces full-duplex mode, and the two I/O buffers are
+ * provided as separate chunks.
+ *
+ * The macros `BR_SSL_BUFSIZE_INPUT` and `BR_SSL_BUFSIZE_OUTPUT`
+ * evaluate to the optimal (maximum) sizes for the input and output
+ * buffer, respectively.
+ *
+ * \param cc SSL engine context
+ * \param ibuf input buffer.
+ * \param ibuf_len input buffer length (in bytes).
+ * \param obuf output buffer.
+ * \param obuf_len output buffer length (in bytes).
+ */
+void br_ssl_engine_set_buffers_bidi(br_ssl_engine_context *cc,
+ void *ibuf, size_t ibuf_len, void *obuf, size_t obuf_len);
+
+/**
+ * \brief Inject some "initial entropy" in the context.
+ *
+ * This entropy will be added to what can be obtained from the
+ * underlying operating system, if that OS is supported.
+ *
+ * This function may be called several times; all injected entropy chunks
+ * are cumulatively mixed.
+ *
+ * If entropy gathering from the OS is supported and compiled in, then this
+ * step is optional. Otherwise, it is mandatory to inject randomness, and
+ * the caller MUST take care to push (as one or several successive calls)
+ * enough entropy to achieve cryptographic resistance (at least 80 bits,
+ * preferably 128 or more). The engine will report an error if no entropy
+ * was provided and none can be obtained from the OS.
+ *
+ * Take care that this function cannot assess the cryptographic quality of
+ * the provided bytes.
+ *
+ * In all generality, "entropy" must here be considered to mean "that
+ * which the attacker cannot predict". If your OS/architecture does not
+ * have a suitable source of randomness, then you can make do with the
+ * combination of a large enough secret value (possibly a copy of an
+ * asymmetric private key that you also store on the system) AND a
+ * non-repeating value (e.g. current time, provided that the local clock
+ * cannot be reset or altered by the attacker).
+ *
+ * \param cc SSL engine context.
+ * \param data extra entropy to inject.
+ * \param len length of the extra data (in bytes).
+ */
+void br_ssl_engine_inject_entropy(br_ssl_engine_context *cc,
+ const void *data, size_t len);
+
+/**
+ * \brief Get the "server name" in this engine.
+ *
+ * For clients, this is the name provided with `br_ssl_client_reset()`;
+ * for servers, this is the name received from the client as part of the
+ * ClientHello message. If there is no such name (e.g. the client did
+ * not send an SNI extension) then the returned string is empty
+ * (returned pointer points to a byte of value 0).
+ *
+ * The returned pointer refers to a buffer inside the context, which may
+ * be overwritten as part of normal SSL activity (even within the same
+ * connection, if a renegotiation occurs).
+ *
+ * \param cc SSL engine context.
+ * \return the server name (possibly empty).
+ */
+static inline const char *
+br_ssl_engine_get_server_name(const br_ssl_engine_context *cc)
+{
+ return cc->server_name;
+}
+
+/**
+ * \brief Get the protocol version.
+ *
+ * This function returns the protocol version that is used by the
+ * engine. That value is set after sending (for a server) or receiving
+ * (for a client) the ServerHello message.
+ *
+ * \param cc SSL engine context.
+ * \return the protocol version.
+ */
+static inline unsigned
+br_ssl_engine_get_version(const br_ssl_engine_context *cc)
+{
+ return cc->session.version;
+}
+
+/**
+ * \brief Get a copy of the session parameters.
+ *
+ * The session parameters are filled during the handshake, so this
+ * function shall not be called before completion of the handshake.
+ * The initial handshake is completed when the context first allows
+ * application data to be injected.
+ *
+ * This function copies the current session parameters into the provided
+ * structure. Beware that the session parameters include the master
+ * secret, which is sensitive data, to handle with great care.
+ *
+ * \param cc SSL engine context.
+ * \param pp destination structure for the session parameters.
+ */
+static inline void
+br_ssl_engine_get_session_parameters(const br_ssl_engine_context *cc,
+ br_ssl_session_parameters *pp)
+{
+ memcpy(pp, &cc->session, sizeof *pp);
+}
+
+/**
+ * \brief Set the session parameters to the provided values.
+ *
+ * This function is meant to be used in the client, before doing a new
+ * handshake; a session resumption will be attempted with these
+ * parameters. In the server, this function has no effect.
+ *
+ * \param cc SSL engine context.
+ * \param pp source structure for the session parameters.
+ */
+static inline void
+br_ssl_engine_set_session_parameters(br_ssl_engine_context *cc,
+ const br_ssl_session_parameters *pp)
+{
+ memcpy(&cc->session, pp, sizeof *pp);
+}
+
+/**
+ * \brief Get identifier for the curve used for key exchange.
+ *
+ * If the cipher suite uses ECDHE, then this function returns the
+ * identifier for the curve used for transient parameters. This is
+ * defined during the course of the handshake, when the ServerKeyExchange
+ * is sent (on the server) or received (on the client). If the
+ * cipher suite does not use ECDHE (e.g. static ECDH, or RSA key
+ * exchange), then this value is indeterminate.
+ *
+ * @param cc SSL engine context.
+ * @return the ECDHE curve identifier.
+ */
+static inline int
+br_ssl_engine_get_ecdhe_curve(br_ssl_engine_context *cc)
+{
+ return cc->ecdhe_curve;
+}
+
+/**
+ * \brief Get the current engine state.
+ *
+ * An SSL engine (client or server) has, at any time, a state which is
+ * the combination of zero, one or more of these flags:
+ *
+ * - `BR_SSL_CLOSED`
+ *
+ * Engine is finished, no more I/O (until next reset).
+ *
+ * - `BR_SSL_SENDREC`
+ *
+ * Engine has some bytes to send to the peer.
+ *
+ * - `BR_SSL_RECVREC`
+ *
+ * Engine expects some bytes from the peer.
+ *
+ * - `BR_SSL_SENDAPP`
+ *
+ * Engine may receive application data to send (or flush).
+ *
+ * - `BR_SSL_RECVAPP`
+ *
+ * Engine has obtained some application data from the peer,
+ * that should be read by the caller.
+ *
+ * If no flag at all is set (state value is 0), then the engine is not
+ * fully initialised yet.
+ *
+ * The `BR_SSL_CLOSED` flag is exclusive; when it is set, no other flag
+ * is set. To distinguish between a normal closure and an error, use
+ * `br_ssl_engine_last_error()`.
+ *
+ * Generally speaking, `BR_SSL_SENDREC` and `BR_SSL_SENDAPP` are mutually
+ * exclusive: the input buffer, at any point, either accumulates
+ * plaintext data, or contains an assembled record that is being sent.
+ * Similarly, `BR_SSL_RECVREC` and `BR_SSL_RECVAPP` are mutually exclusive.
+ * This may change in a future library version.
+ *
+ * \param cc SSL engine context.
+ * \return the current engine state.
+ */
+unsigned br_ssl_engine_current_state(const br_ssl_engine_context *cc);
+
+/** \brief SSL engine state: closed or failed. */
+#define BR_SSL_CLOSED 0x0001
+/** \brief SSL engine state: record data is ready to be sent to the peer. */
+#define BR_SSL_SENDREC 0x0002
+/** \brief SSL engine state: engine may receive records from the peer. */
+#define BR_SSL_RECVREC 0x0004
+/** \brief SSL engine state: engine may accept application data to send. */
+#define BR_SSL_SENDAPP 0x0008
+/** \brief SSL engine state: engine has received application data. */
+#define BR_SSL_RECVAPP 0x0010
+
+/**
+ * \brief Get the engine error indicator.
+ *
+ * The error indicator is `BR_ERR_OK` (0) if no error was encountered
+ * since the last call to `br_ssl_client_reset()` or
+ * `br_ssl_server_reset()`. Other status values are "sticky": they
+ * remain set, and prevent all I/O activity, until cleared. Only the
+ * reset calls clear the error indicator.
+ *
+ * \param cc SSL engine context.
+ * \return 0, or a non-zero error code.
+ */
+static inline int
+br_ssl_engine_last_error(const br_ssl_engine_context *cc)
+{
+ return cc->err;
+}
+
+/*
+ * There are four I/O operations, each identified by a symbolic name:
+ *
+ * sendapp inject application data in the engine
+ * recvapp retrieving application data from the engine
+ * sendrec sending records on the transport medium
+ * recvrec receiving records from the transport medium
+ *
+ * Terminology works thus: in a layered model where the SSL engine sits
+ * between the application and the network, "send" designates operations
+ * where bytes flow from application to network, and "recv" for the
+ * reverse operation. Application data (the plaintext that is to be
+ * conveyed through SSL) is "app", while encrypted records are "rec".
+ * Note that from the SSL engine point of view, "sendapp" and "recvrec"
+ * designate bytes that enter the engine ("inject" operation), while
+ * "recvapp" and "sendrec" designate bytes that exit the engine
+ * ("extract" operation).
+ *
+ * For the operation 'xxx', two functions are defined:
+ *
+ * br_ssl_engine_xxx_buf
+ * Returns a pointer and length to the buffer to use for that
+ * operation. '*len' is set to the number of bytes that may be read
+ * from the buffer (extract operation) or written to the buffer
+ * (inject operation). If no byte may be exchanged for that operation
+ * at that point, then '*len' is set to zero, and NULL is returned.
+ * The engine state is unmodified by this call.
+ *
+ * br_ssl_engine_xxx_ack
+ * Informs the engine that 'len' bytes have been read from the buffer
+ * (extract operation) or written to the buffer (inject operation).
+ * The 'len' value MUST NOT be zero. The 'len' value MUST NOT exceed
+ * that which was obtained from a preceding br_ssl_engine_xxx_buf()
+ * call.
+ */
+
+/**
+ * \brief Get buffer for application data to send.
+ *
+ * If the engine is ready to accept application data to send to the
+ * peer, then this call returns a pointer to the buffer where such
+ * data shall be written, and its length is written in `*len`.
+ * Otherwise, `*len` is set to 0 and `NULL` is returned.
+ *
+ * \param cc SSL engine context.
+ * \param len receives the application data output buffer length, or 0.
+ * \return the application data output buffer, or `NULL`.
+ */
+unsigned char *br_ssl_engine_sendapp_buf(
+ const br_ssl_engine_context *cc, size_t *len);
+
+/**
+ * \brief Inform the engine of some new application data.
+ *
+ * After writing `len` bytes in the buffer returned by
+ * `br_ssl_engine_sendapp_buf()`, the application shall call this
+ * function to trigger any relevant processing. The `len` parameter
+ * MUST NOT be 0, and MUST NOT exceed the value obtained in the
+ * `br_ssl_engine_sendapp_buf()` call.
+ *
+ * \param cc SSL engine context.
+ * \param len number of bytes pushed (not zero).
+ */
+void br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len);
+
+/**
+ * \brief Get buffer for received application data.
+ *
+ * If the engine has received application data from the peer, hen this
+ * call returns a pointer to the buffer from where such data shall be
+ * read, and its length is written in `*len`. Otherwise, `*len` is set
+ * to 0 and `NULL` is returned.
+ *
+ * \param cc SSL engine context.
+ * \param len receives the application data input buffer length, or 0.
+ * \return the application data input buffer, or `NULL`.
+ */
+unsigned char *br_ssl_engine_recvapp_buf(
+ const br_ssl_engine_context *cc, size_t *len);
+
+/**
+ * \brief Acknowledge some received application data.
+ *
+ * After reading `len` bytes from the buffer returned by
+ * `br_ssl_engine_recvapp_buf()`, the application shall call this
+ * function to trigger any relevant processing. The `len` parameter
+ * MUST NOT be 0, and MUST NOT exceed the value obtained in the
+ * `br_ssl_engine_recvapp_buf()` call.
+ *
+ * \param cc SSL engine context.
+ * \param len number of bytes read (not zero).
+ */
+void br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len);
+
+/**
+ * \brief Get buffer for record data to send.
+ *
+ * If the engine has prepared some records to send to the peer, then this
+ * call returns a pointer to the buffer from where such data shall be
+ * read, and its length is written in `*len`. Otherwise, `*len` is set
+ * to 0 and `NULL` is returned.
+ *
+ * \param cc SSL engine context.
+ * \param len receives the record data output buffer length, or 0.
+ * \return the record data output buffer, or `NULL`.
+ */
+unsigned char *br_ssl_engine_sendrec_buf(
+ const br_ssl_engine_context *cc, size_t *len);
+
+/**
+ * \brief Acknowledge some sent record data.
+ *
+ * After reading `len` bytes from the buffer returned by
+ * `br_ssl_engine_sendrec_buf()`, the application shall call this
+ * function to trigger any relevant processing. The `len` parameter
+ * MUST NOT be 0, and MUST NOT exceed the value obtained in the
+ * `br_ssl_engine_sendrec_buf()` call.
+ *
+ * \param cc SSL engine context.
+ * \param len number of bytes read (not zero).
+ */
+void br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len);
+
+/**
+ * \brief Get buffer for incoming records.
+ *
+ * If the engine is ready to accept records from the peer, then this
+ * call returns a pointer to the buffer where such data shall be
+ * written, and its length is written in `*len`. Otherwise, `*len` is
+ * set to 0 and `NULL` is returned.
+ *
+ * \param cc SSL engine context.
+ * \param len receives the record data input buffer length, or 0.
+ * \return the record data input buffer, or `NULL`.
+ */
+unsigned char *br_ssl_engine_recvrec_buf(
+ const br_ssl_engine_context *cc, size_t *len);
+
+/**
+ * \brief Inform the engine of some new record data.
+ *
+ * After writing `len` bytes in the buffer returned by
+ * `br_ssl_engine_recvrec_buf()`, the application shall call this
+ * function to trigger any relevant processing. The `len` parameter
+ * MUST NOT be 0, and MUST NOT exceed the value obtained in the
+ * `br_ssl_engine_recvrec_buf()` call.
+ *
+ * \param cc SSL engine context.
+ * \param len number of bytes pushed (not zero).
+ */
+void br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len);
+
+/**
+ * \brief Flush buffered application data.
+ *
+ * If some application data has been buffered in the engine, then wrap
+ * it into a record and mark it for sending. If no application data has
+ * been buffered but the engine would be ready to accept some, AND the
+ * `force` parameter is non-zero, then an empty record is assembled and
+ * marked for sending. In all other cases, this function does nothing.
+ *
+ * Empty records are technically legal, but not all existing SSL/TLS
+ * implementations support them. Empty records can be useful as a
+ * transparent "keep-alive" mechanism to maintain some low-level
+ * network activity.
+ *
+ * \param cc SSL engine context.
+ * \param force non-zero to force sending an empty record.
+ */
+void br_ssl_engine_flush(br_ssl_engine_context *cc, int force);
+
+/**
+ * \brief Initiate a closure.
+ *
+ * If, at that point, the context is open and in ready state, then a
+ * `close_notify` alert is assembled and marked for sending; this
+ * triggers the closure protocol. Otherwise, no such alert is assembled.
+ *
+ * \param cc SSL engine context.
+ */
+void br_ssl_engine_close(br_ssl_engine_context *cc);
+
+/**
+ * \brief Initiate a renegotiation.
+ *
+ * If the engine is failed or closed, or if the peer is known not to
+ * support secure renegotiation (RFC 5746), or if renegotiations have
+ * been disabled with the `BR_OPT_NO_RENEGOTIATION` flag, or if there
+ * is buffered incoming application data, then this function returns 0
+ * and nothing else happens.
+ *
+ * Otherwise, this function returns 1, and a renegotiation attempt is
+ * triggered (if a handshake is already ongoing at that point, then
+ * no new handshake is triggered).
+ *
+ * \param cc SSL engine context.
+ * \return 1 on success, 0 on error.
+ */
+int br_ssl_engine_renegotiate(br_ssl_engine_context *cc);
+
+/**
+ * \brief Export key material from a connected SSL engine (RFC 5705).
+ *
+ * This calls compute a secret key of arbitrary length from the master
+ * secret of a connected SSL engine. If the provided context is not
+ * currently in "application data" state (initial handshake is not
+ * finished, another handshake is ongoing, or the connection failed or
+ * was closed), then this function returns 0. Otherwise, a secret key of
+ * length `len` bytes is computed and written in the buffer pointed to
+ * by `dst`, and 1 is returned.
+ *
+ * The computed key follows the specification described in RFC 5705.
+ * That RFC includes two key computations, with and without a "context
+ * value". If `context` is `NULL`, then the variant without context is
+ * used; otherwise, the `context_len` bytes located at the address
+ * pointed to by `context` are used in the computation. Note that it
+ * is possible to have a "with context" key with a context length of
+ * zero bytes, by setting `context` to a non-`NULL` value but
+ * `context_len` to 0.
+ *
+ * When context bytes are used, the context length MUST NOT exceed
+ * 65535 bytes.
+ *
+ * \param cc SSL engine context.
+ * \param dst destination buffer for exported key.
+ * \param len exported key length (in bytes).
+ * \param label disambiguation label.
+ * \param context context value (or `NULL`).
+ * \param context_len context length (in bytes).
+ * \return 1 on success, 0 on error.
+ */
+int br_ssl_key_export(br_ssl_engine_context *cc,
+ void *dst, size_t len, const char *label,
+ const void *context, size_t context_len);
+
+/*
+ * Pre-declaration for the SSL client context.
+ */
+typedef struct br_ssl_client_context_ br_ssl_client_context;
+
+/**
+ * \brief Type for the client certificate, if requested by the server.
+ */
+typedef struct {
+ /**
+ * \brief Authentication type.
+ *
+ * This is either `BR_AUTH_RSA` (RSA signature), `BR_AUTH_ECDSA`
+ * (ECDSA signature), or `BR_AUTH_ECDH` (static ECDH key exchange).
+ */
+ int auth_type;
+
+ /**
+ * \brief Hash function for computing the CertificateVerify.
+ *
+ * This is the symbolic identifier for the hash function that
+ * will be used to produce the hash of handshake messages, to
+ * be signed into the CertificateVerify. For full static ECDH
+ * (client and server certificates are both EC in the same
+ * curve, and static ECDH is used), this value is set to -1.
+ *
+ * Take care that with TLS 1.0 and 1.1, that value MUST match
+ * the protocol requirements: value must be 0 (MD5+SHA-1) for
+ * a RSA signature, or 2 (SHA-1) for an ECDSA signature. Only
+ * TLS 1.2 allows for other hash functions.
+ */
+ int hash_id;
+
+ /**
+ * \brief Certificate chain to send to the server.
+ *
+ * This is an array of `br_x509_certificate` objects, each
+ * normally containing a DER-encoded certificate. The client
+ * code does not try to decode these elements. If there is no
+ * chain to send to the server, then this pointer shall be
+ * set to `NULL`.
+ */
+ const br_x509_certificate *chain;
+
+ /**
+ * \brief Certificate chain length (number of certificates).
+ *
+ * If there is no chain to send to the server, then this value
+ * shall be set to 0.
+ */
+ size_t chain_len;
+
+} br_ssl_client_certificate;
+
+/*
+ * Note: the constants below for signatures match the TLS constants.
+ */
+
+/** \brief Client authentication type: static ECDH. */
+#define BR_AUTH_ECDH 0
+/** \brief Client authentication type: RSA signature. */
+#define BR_AUTH_RSA 1
+/** \brief Client authentication type: ECDSA signature. */
+#define BR_AUTH_ECDSA 3
+
+/**
+ * \brief Class type for a certificate handler (client side).
+ *
+ * A certificate handler selects a client certificate chain to send to
+ * the server, upon explicit request from that server. It receives
+ * the list of trust anchor DN from the server, and supported types
+ * of certificates and signatures, and returns the chain to use. It
+ * is also invoked to perform the corresponding private key operation
+ * (a signature, or an ECDH computation).
+ *
+ * The SSL client engine will first push the trust anchor DN with
+ * `start_name_list()`, `start_name()`, `append_name()`, `end_name()`
+ * and `end_name_list()`. Then it will call `choose()`, to select the
+ * actual chain (and signature/hash algorithms). Finally, it will call
+ * either `do_sign()` or `do_keyx()`, depending on the algorithm choices.
+ */
+typedef struct br_ssl_client_certificate_class_ br_ssl_client_certificate_class;
+struct br_ssl_client_certificate_class_ {
+ /**
+ * \brief Context size (in bytes).
+ */
+ size_t context_size;
+
+ /**
+ * \brief Begin reception of a list of trust anchor names. This
+ * is called while parsing the incoming CertificateRequest.
+ *
+ * \param pctx certificate handler context.
+ */
+ void (*start_name_list)(const br_ssl_client_certificate_class **pctx);
+
+ /**
+ * \brief Begin reception of a new trust anchor name.
+ *
+ * The total encoded name length is provided; it is less than
+ * 65535 bytes.
+ *
+ * \param pctx certificate handler context.
+ * \param len encoded name length (in bytes).
+ */
+ void (*start_name)(const br_ssl_client_certificate_class **pctx,
+ size_t len);
+
+ /**
+ * \brief Receive some more bytes for the current trust anchor name.
+ *
+ * The provided reference (`data`) points to a transient buffer
+ * they may be reused as soon as this function returns. The chunk
+ * length (`len`) is never zero.
+ *
+ * \param pctx certificate handler context.
+ * \param data anchor name chunk.
+ * \param len anchor name chunk length (in bytes).
+ */
+ void (*append_name)(const br_ssl_client_certificate_class **pctx,
+ const unsigned char *data, size_t len);
+
+ /**
+ * \brief End current trust anchor name.
+ *
+ * This function is called when all the encoded anchor name data
+ * has been provided.
+ *
+ * \param pctx certificate handler context.
+ */
+ void (*end_name)(const br_ssl_client_certificate_class **pctx);
+
+ /**
+ * \brief End list of trust anchor names.
+ *
+ * This function is called when all the anchor names in the
+ * CertificateRequest message have been obtained.
+ *
+ * \param pctx certificate handler context.
+ */
+ void (*end_name_list)(const br_ssl_client_certificate_class **pctx);
+
+ /**
+ * \brief Select client certificate and algorithms.
+ *
+ * This callback function shall fill the provided `choices`
+ * structure with the selected algorithms and certificate chain.
+ * The `hash_id`, `chain` and `chain_len` fields must be set. If
+ * the client cannot or does not wish to send a certificate,
+ * then it shall set `chain` to `NULL` and `chain_len` to 0.
+ *
+ * The `auth_types` parameter describes the authentication types,
+ * signature algorithms and hash functions that are supported by
+ * both the client context and the server, and compatible with
+ * the current protocol version. This is a bit field with the
+ * following contents:
+ *
+ * - If RSA signatures with hash function x are supported, then
+ * bit x is set.
+ *
+ * - If ECDSA signatures with hash function x are supported,
+ * then bit 8+x is set.
+ *
+ * - If static ECDH is supported, with a RSA-signed certificate,
+ * then bit 16 is set.
+ *
+ * - If static ECDH is supported, with an ECDSA-signed certificate,
+ * then bit 17 is set.
+ *
+ * Notes:
+ *
+ * - When using TLS 1.0 or 1.1, the hash function for RSA
+ * signatures is always the special MD5+SHA-1 (id 0), and the
+ * hash function for ECDSA signatures is always SHA-1 (id 2).
+ *
+ * - When using TLS 1.2, the list of hash functions is trimmed
+ * down to include only hash functions that the client context
+ * can support. The actual server list can be obtained with
+ * `br_ssl_client_get_server_hashes()`; that list may be used
+ * to select the certificate chain to send to the server.
+ *
+ * \param pctx certificate handler context.
+ * \param cc SSL client context.
+ * \param auth_types supported authentication types and algorithms.
+ * \param choices destination structure for the policy choices.
+ */
+ void (*choose)(const br_ssl_client_certificate_class **pctx,
+ const br_ssl_client_context *cc, uint32_t auth_types,
+ br_ssl_client_certificate *choices);
+
+ /**
+ * \brief Perform key exchange (client part).
+ *
+ * This callback is invoked in case of a full static ECDH key
+ * exchange:
+ *
+ * - the cipher suite uses `ECDH_RSA` or `ECDH_ECDSA`;
+ *
+ * - the server requests a client certificate;
+ *
+ * - the client has, and sends, a client certificate that
+ * uses an EC key in the same curve as the server's key,
+ * and chooses static ECDH (the `hash_id` field in the choice
+ * structure was set to -1).
+ *
+ * In that situation, this callback is invoked to compute the
+ * client-side ECDH: the provided `data` (of length `*len` bytes)
+ * is the server's public key point (as decoded from its
+ * certificate), and the client shall multiply that point with
+ * its own private key, and write back the X coordinate of the
+ * resulting point in the same buffer, starting at offset 0.
+ * The `*len` value shall be modified to designate the actual
+ * length of the X coordinate.
+ *
+ * The callback must uphold the following:
+ *
+ * - If the input array does not have the proper length for
+ * an encoded curve point, then an error (0) shall be reported.
+ *
+ * - If the input array has the proper length, then processing
+ * MUST be constant-time, even if the data is not a valid
+ * encoded point.
+ *
+ * - This callback MUST check that the input point is valid.
+ *
+ * Returned value is 1 on success, 0 on error.
+ *
+ * \param pctx certificate handler context.
+ * \param data server public key point.
+ * \param len public key point length / X coordinate length.
+ * \return 1 on success, 0 on error.
+ */
+ uint32_t (*do_keyx)(const br_ssl_client_certificate_class **pctx,
+ unsigned char *data, size_t *len);
+
+ /**
+ * \brief Perform a signature (client authentication).
+ *
+ * This callback is invoked when a client certificate was sent,
+ * and static ECDH is not used. It shall compute a signature,
+ * using the client's private key, over the provided hash value
+ * (which is the hash of all previous handshake messages).
+ *
+ * On input, the hash value to sign is in `data`, of size
+ * `hv_len`; the involved hash function is identified by
+ * `hash_id`. The signature shall be computed and written
+ * back into `data`; the total size of that buffer is `len`
+ * bytes.
+ *
+ * This callback shall verify that the signature length does not
+ * exceed `len` bytes, and abstain from writing the signature if
+ * it does not fit.
+ *
+ * For RSA signatures, the `hash_id` may be 0, in which case
+ * this is the special header-less signature specified in TLS 1.0
+ * and 1.1, with a 36-byte hash value. Otherwise, normal PKCS#1
+ * v1.5 signatures shall be computed.
+ *
+ * For ECDSA signatures, the signature value shall use the ASN.1
+ * based encoding.
+ *
+ * Returned value is the signature length (in bytes), or 0 on error.
+ *
+ * \param pctx certificate handler context.
+ * \param hash_id hash function identifier.
+ * \param hv_len hash value length (in bytes).
+ * \param data input/output buffer (hash value, then signature).
+ * \param len total buffer length (in bytes).
+ * \return signature length (in bytes) on success, or 0 on error.
+ */
+ size_t (*do_sign)(const br_ssl_client_certificate_class **pctx,
+ int hash_id, size_t hv_len, unsigned char *data, size_t len);
+};
+
+/**
+ * \brief A single-chain RSA client certificate handler.
+ *
+ * This handler uses a single certificate chain, with a RSA
+ * signature. The list of trust anchor DN is ignored.
+ *
+ * Apart from the first field (vtable pointer), its contents are
+ * opaque and shall not be accessed directly.
+ */
+typedef struct {
+ /** \brief Pointer to vtable. */
+ const br_ssl_client_certificate_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ const br_x509_certificate *chain;
+ size_t chain_len;
+ const br_rsa_private_key *sk;
+ br_rsa_pkcs1_sign irsasign;
+#endif
+} br_ssl_client_certificate_rsa_context;
+
+/**
+ * \brief A single-chain EC client certificate handler.
+ *
+ * This handler uses a single certificate chain, with a RSA
+ * signature. The list of trust anchor DN is ignored.
+ *
+ * This handler may support both static ECDH, and ECDSA signatures
+ * (either usage may be selectively disabled).
+ *
+ * Apart from the first field (vtable pointer), its contents are
+ * opaque and shall not be accessed directly.
+ */
+typedef struct {
+ /** \brief Pointer to vtable. */
+ const br_ssl_client_certificate_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ const br_x509_certificate *chain;
+ size_t chain_len;
+ const br_ec_private_key *sk;
+ unsigned allowed_usages;
+ unsigned issuer_key_type;
+ const br_multihash_context *mhash;
+ const br_ec_impl *iec;
+ br_ecdsa_sign iecdsa;
+#endif
+} br_ssl_client_certificate_ec_context;
+
+/**
+ * \brief Context structure for a SSL client.
+ *
+ * The first field (called `eng`) is the SSL engine; all functions that
+ * work on a `br_ssl_engine_context` structure shall take as parameter
+ * a pointer to that field. The other structure fields are opaque and
+ * must not be accessed directly.
+ */
+struct br_ssl_client_context_ {
+ /**
+ * \brief The encapsulated engine context.
+ */
+ br_ssl_engine_context eng;
+
+#ifndef BR_DOXYGEN_IGNORE
+ /*
+ * Minimum ClientHello length; padding with an extension (RFC
+ * 7685) is added if necessary to match at least that length.
+ * Such padding is nominally unnecessary, but it has been used
+ * to work around some server implementation bugs.
+ */
+ uint16_t min_clienthello_len;
+
+ /*
+ * Bit field for algoithms (hash + signature) supported by the
+ * server when requesting a client certificate.
+ */
+ uint32_t hashes;
+
+ /*
+ * Server's public key curve.
+ */
+ int server_curve;
+
+ /*
+ * Context for certificate handler.
+ */
+ const br_ssl_client_certificate_class **client_auth_vtable;
+
+ /*
+ * Client authentication type.
+ */
+ unsigned char auth_type;
+
+ /*
+ * Hash function to use for the client signature. This is 0xFF
+ * if static ECDH is used.
+ */
+ unsigned char hash_id;
+
+ /*
+ * For the core certificate handlers, thus avoiding (in most
+ * cases) the need for an externally provided policy context.
+ */
+ union {
+ const br_ssl_client_certificate_class *vtable;
+ br_ssl_client_certificate_rsa_context single_rsa;
+ br_ssl_client_certificate_ec_context single_ec;
+ } client_auth;
+
+ /*
+ * Implementations.
+ */
+ br_rsa_public irsapub;
+#endif
+};
+
+/**
+ * \brief Get the hash functions and signature algorithms supported by
+ * the server.
+ *
+ * This value is a bit field:
+ *
+ * - If RSA (PKCS#1 v1.5) is supported with hash function of ID `x`,
+ * then bit `x` is set (hash function ID is 0 for the special MD5+SHA-1,
+ * or 2 to 6 for the SHA family).
+ *
+ * - If ECDSA is supported with hash function of ID `x`, then bit `8+x`
+ * is set.
+ *
+ * - Newer algorithms are symbolic 16-bit identifiers that do not
+ * represent signature algorithm and hash function separately. If
+ * the TLS-level identifier is `0x0800+x` for a `x` in the 0..15
+ * range, then bit `16+x` is set.
+ *
+ * "New algorithms" are currently defined only in draft documents, so
+ * this support is subject to possible change. Right now (early 2017),
+ * this maps ed25519 (EdDSA on Curve25519) to bit 23, and ed448 (EdDSA
+ * on Curve448) to bit 24. If the identifiers on the wire change in
+ * future document, then the decoding mechanism in BearSSL will be
+ * amended to keep mapping ed25519 and ed448 on bits 23 and 24,
+ * respectively. Mapping of other new algorithms (e.g. RSA/PSS) is not
+ * guaranteed yet.
+ *
+ * \param cc client context.
+ * \return the server-supported hash functions and signature algorithms.
+ */
+static inline uint32_t
+br_ssl_client_get_server_hashes(const br_ssl_client_context *cc)
+{
+ return cc->hashes;
+}
+
+/**
+ * \brief Get the server key curve.
+ *
+ * This function returns the ID for the curve used by the server's public
+ * key. This is set when the server's certificate chain is processed;
+ * this value is 0 if the server's key is not an EC key.
+ *
+ * \return the server's public key curve ID, or 0.
+ */
+static inline int
+br_ssl_client_get_server_curve(const br_ssl_client_context *cc)
+{
+ return cc->server_curve;
+}
+
+/*
+ * Each br_ssl_client_init_xxx() function sets the list of supported
+ * cipher suites and used implementations, as specified by the profile
+ * name 'xxx'. Defined profile names are:
+ *
+ * full all supported versions and suites; constant-time implementations
+ * TODO: add other profiles
+ */
+
+/**
+ * \brief SSL client profile: full.
+ *
+ * This function initialises the provided SSL client context with
+ * all supported algorithms and cipher suites. It also initialises
+ * a companion X.509 validation engine with all supported algorithms,
+ * and the provided trust anchors; the X.509 engine will be used by
+ * the client context to validate the server's certificate.
+ *
+ * \param cc client context to initialise.
+ * \param xc X.509 validation context to initialise.
+ * \param trust_anchors trust anchors to use.
+ * \param trust_anchors_num number of trust anchors.
+ */
+void br_ssl_client_init_full(br_ssl_client_context *cc,
+ br_x509_minimal_context *xc,
+ const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num);
+
+/**
+ * \brief Clear the complete contents of a SSL client context.
+ *
+ * Everything is cleared, including the reference to the configured buffer,
+ * implementations, cipher suites and state. This is a preparatory step
+ * to assembling a custom profile.
+ *
+ * \param cc client context to clear.
+ */
+void br_ssl_client_zero(br_ssl_client_context *cc);
+
+/**
+ * \brief Set an externally provided client certificate handler context.
+ *
+ * The handler's methods are invoked when the server requests a client
+ * certificate.
+ *
+ * \param cc client context.
+ * \param pctx certificate handler context (pointer to its vtable field).
+ */
+static inline void
+br_ssl_client_set_client_certificate(br_ssl_client_context *cc,
+ const br_ssl_client_certificate_class **pctx)
+{
+ cc->client_auth_vtable = pctx;
+}
+
+/**
+ * \brief Set the RSA public-key operations implementation.
+ *
+ * This will be used to encrypt the pre-master secret with the server's
+ * RSA public key (RSA-encryption cipher suites only).
+ *
+ * \param cc client context.
+ * \param irsapub RSA public-key encryption implementation.
+ */
+static inline void
+br_ssl_client_set_rsapub(br_ssl_client_context *cc, br_rsa_public irsapub)
+{
+ cc->irsapub = irsapub;
+}
+
+/**
+ * \brief Set the "default" RSA implementation for public-key operations.
+ *
+ * This sets the RSA implementation in the client context (for encrypting
+ * the pre-master secret, in `TLS_RSA_*` cipher suites) to the fastest
+ * available on the current platform.
+ *
+ * \param cc client context.
+ */
+void br_ssl_client_set_default_rsapub(br_ssl_client_context *cc);
+
+/**
+ * \brief Set the minimum ClientHello length (RFC 7685 padding).
+ *
+ * If this value is set and the ClientHello would be shorter, then
+ * the Pad ClientHello extension will be added with enough padding bytes
+ * to reach the target size. Because of the extension header, the resulting
+ * size will sometimes be slightly more than `len` bytes if the target
+ * size cannot be exactly met.
+ *
+ * The target length relates to the _contents_ of the ClientHello, not
+ * counting its 4-byte header. For instance, if `len` is set to 512,
+ * then the padding will bring the ClientHello size to 516 bytes with its
+ * header, and 521 bytes when counting the 5-byte record header.
+ *
+ * \param cc client context.
+ * \param len minimum ClientHello length (in bytes).
+ */
+static inline void
+br_ssl_client_set_min_clienthello_len(br_ssl_client_context *cc, uint16_t len)
+{
+ cc->min_clienthello_len = len;
+}
+
+/**
+ * \brief Prepare or reset a client context for a new connection.
+ *
+ * The `server_name` parameter is used to fill the SNI extension; the
+ * X.509 "minimal" engine will also match that name against the server
+ * names included in the server's certificate. If the parameter is
+ * `NULL` then no SNI extension will be sent, and the X.509 "minimal"
+ * engine (if used for server certificate validation) will not check
+ * presence of any specific name in the received certificate.
+ *
+ * Therefore, setting the `server_name` to `NULL` shall be reserved
+ * to cases where alternate or additional methods are used to ascertain
+ * that the right server public key is used (e.g. a "known key" model).
+ *
+ * If `resume_session` is non-zero and the context was previously used
+ * then the session parameters may be reused (depending on whether the
+ * server previously sent a non-empty session ID, and accepts the session
+ * resumption). The session parameters for session resumption can also
+ * be set explicitly with `br_ssl_engine_set_session_parameters()`.
+ *
+ * On failure, the context is marked as failed, and this function
+ * returns 0. A possible failure condition is when no initial entropy
+ * was injected, and none could be obtained from the OS (either OS
+ * randomness gathering is not supported, or it failed).
+ *
+ * \param cc client context.
+ * \param server_name target server name, or `NULL`.
+ * \param resume_session non-zero to try session resumption.
+ * \return 0 on failure, 1 on success.
+ */
+int br_ssl_client_reset(br_ssl_client_context *cc,
+ const char *server_name, int resume_session);
+
+/**
+ * \brief Forget any session in the context.
+ *
+ * This means that the next handshake that uses this context will
+ * necessarily be a full handshake (this applies both to new connections
+ * and to renegotiations).
+ *
+ * \param cc client context.
+ */
+static inline void
+br_ssl_client_forget_session(br_ssl_client_context *cc)
+{
+ cc->eng.session.session_id_len = 0;
+}
+
+/**
+ * \brief Set client certificate chain and key (single RSA case).
+ *
+ * This function sets a client certificate chain, that the client will
+ * send to the server whenever a client certificate is requested. This
+ * certificate uses an RSA public key; the corresponding private key is
+ * invoked for authentication. Trust anchor names sent by the server are
+ * ignored.
+ *
+ * The provided chain and private key are linked in the client context;
+ * they must remain valid as long as they may be used, i.e. normally
+ * for the duration of the connection, since they might be invoked
+ * again upon renegotiations.
+ *
+ * \param cc SSL client context.
+ * \param chain client certificate chain (SSL order: EE comes first).
+ * \param chain_len client chain length (number of certificates).
+ * \param sk client private key.
+ * \param irsasign RSA signature implementation (PKCS#1 v1.5).
+ */
+void br_ssl_client_set_single_rsa(br_ssl_client_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk, br_rsa_pkcs1_sign irsasign);
+
+/*
+ * \brief Set the client certificate chain and key (single EC case).
+ *
+ * This function sets a client certificate chain, that the client will
+ * send to the server whenever a client certificate is requested. This
+ * certificate uses an EC public key; the corresponding private key is
+ * invoked for authentication. Trust anchor names sent by the server are
+ * ignored.
+ *
+ * The provided chain and private key are linked in the client context;
+ * they must remain valid as long as they may be used, i.e. normally
+ * for the duration of the connection, since they might be invoked
+ * again upon renegotiations.
+ *
+ * The `allowed_usages` is a combination of usages, namely
+ * `BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`. The `BR_KEYTYPE_KEYX`
+ * value allows full static ECDH, while the `BR_KEYTYPE_SIGN` value
+ * allows ECDSA signatures. If ECDSA signatures are used, then an ECDSA
+ * signature implementation must be provided; otherwise, the `iecdsa`
+ * parameter may be 0.
+ *
+ * The `cert_issuer_key_type` value is either `BR_KEYTYPE_RSA` or
+ * `BR_KEYTYPE_EC`; it is the type of the public key used the the CA
+ * that issued (signed) the client certificate. That value is used with
+ * full static ECDH: support of the certificate by the server depends
+ * on how the certificate was signed. (Note: when using TLS 1.2, this
+ * parameter is ignored; but its value matters for TLS 1.0 and 1.1.)
+ *
+ * \param cc server context.
+ * \param chain server certificate chain to send.
+ * \param chain_len chain length (number of certificates).
+ * \param sk server private key (EC).
+ * \param allowed_usages allowed private key usages.
+ * \param cert_issuer_key_type issuing CA's key type.
+ * \param iec EC core implementation.
+ * \param iecdsa ECDSA signature implementation ("asn1" format).
+ */
+void br_ssl_client_set_single_ec(br_ssl_client_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk, unsigned allowed_usages,
+ unsigned cert_issuer_key_type,
+ const br_ec_impl *iec, br_ecdsa_sign iecdsa);
+
+/**
+ * \brief Type for a "translated cipher suite", as an array of two
+ * 16-bit integers.
+ *
+ * The first element is the cipher suite identifier (as used on the wire).
+ * The second element is the concatenation of four 4-bit elements which
+ * characterise the cipher suite contents. In most to least significant
+ * order, these 4-bit elements are:
+ *
+ * - Bits 12 to 15: key exchange + server key type
+ *
+ * | val | symbolic constant | suite type | details |
+ * | :-- | :----------------------- | :---------- | :----------------------------------------------- |
+ * | 0 | `BR_SSLKEYX_RSA` | RSA | RSA key exchange, key is RSA (encryption) |
+ * | 1 | `BR_SSLKEYX_ECDHE_RSA` | ECDHE_RSA | ECDHE key exchange, key is RSA (signature) |
+ * | 2 | `BR_SSLKEYX_ECDHE_ECDSA` | ECDHE_ECDSA | ECDHE key exchange, key is EC (signature) |
+ * | 3 | `BR_SSLKEYX_ECDH_RSA` | ECDH_RSA | Key is EC (key exchange), cert signed with RSA |
+ * | 4 | `BR_SSLKEYX_ECDH_ECDSA` | ECDH_ECDSA | Key is EC (key exchange), cert signed with ECDSA |
+ *
+ * - Bits 8 to 11: symmetric encryption algorithm
+ *
+ * | val | symbolic constant | symmetric encryption | key strength (bits) |
+ * | :-- | :--------------------- | :------------------- | :------------------ |
+ * | 0 | `BR_SSLENC_3DES_CBC` | 3DES/CBC | 168 |
+ * | 1 | `BR_SSLENC_AES128_CBC` | AES-128/CBC | 128 |
+ * | 2 | `BR_SSLENC_AES256_CBC` | AES-256/CBC | 256 |
+ * | 3 | `BR_SSLENC_AES128_GCM` | AES-128/GCM | 128 |
+ * | 4 | `BR_SSLENC_AES256_GCM` | AES-256/GCM | 256 |
+ * | 5 | `BR_SSLENC_CHACHA20` | ChaCha20/Poly1305 | 256 |
+ *
+ * - Bits 4 to 7: MAC algorithm
+ *
+ * | val | symbolic constant | MAC type | details |
+ * | :-- | :----------------- | :----------- | :------------------------------------ |
+ * | 0 | `BR_SSLMAC_AEAD` | AEAD | No dedicated MAC (encryption is AEAD) |
+ * | 2 | `BR_SSLMAC_SHA1` | HMAC/SHA-1 | Value matches `br_sha1_ID` |
+ * | 4 | `BR_SSLMAC_SHA256` | HMAC/SHA-256 | Value matches `br_sha256_ID` |
+ * | 5 | `BR_SSLMAC_SHA384` | HMAC/SHA-384 | Value matches `br_sha384_ID` |
+ *
+ * - Bits 0 to 3: hash function for PRF when used with TLS-1.2
+ *
+ * | val | symbolic constant | hash function | details |
+ * | :-- | :----------------- | :------------ | :----------------------------------- |
+ * | 4 | `BR_SSLPRF_SHA256` | SHA-256 | Value matches `br_sha256_ID` |
+ * | 5 | `BR_SSLPRF_SHA384` | SHA-384 | Value matches `br_sha384_ID` |
+ *
+ * For instance, cipher suite `TLS_RSA_WITH_AES_128_GCM_SHA256` has
+ * standard identifier 0x009C, and is translated to 0x0304, for, in
+ * that order: RSA key exchange (0), AES-128/GCM (3), AEAD integrity (0),
+ * SHA-256 in the TLS PRF (4).
+ */
+typedef uint16_t br_suite_translated[2];
+
+#ifndef BR_DOXYGEN_IGNORE
+/*
+ * Constants are already documented in the br_suite_translated type.
+ */
+
+#define BR_SSLKEYX_RSA 0
+#define BR_SSLKEYX_ECDHE_RSA 1
+#define BR_SSLKEYX_ECDHE_ECDSA 2
+#define BR_SSLKEYX_ECDH_RSA 3
+#define BR_SSLKEYX_ECDH_ECDSA 4
+
+#define BR_SSLENC_3DES_CBC 0
+#define BR_SSLENC_AES128_CBC 1
+#define BR_SSLENC_AES256_CBC 2
+#define BR_SSLENC_AES128_GCM 3
+#define BR_SSLENC_AES256_GCM 4
+#define BR_SSLENC_CHACHA20 5
+
+#define BR_SSLMAC_AEAD 0
+#define BR_SSLMAC_SHA1 br_sha1_ID
+#define BR_SSLMAC_SHA256 br_sha256_ID
+#define BR_SSLMAC_SHA384 br_sha384_ID
+
+#define BR_SSLPRF_SHA256 br_sha256_ID
+#define BR_SSLPRF_SHA384 br_sha384_ID
+
+#endif
+
+/*
+ * Pre-declaration for the SSL server context.
+ */
+typedef struct br_ssl_server_context_ br_ssl_server_context;
+
+/**
+ * \brief Type for the server policy choices, taken after analysis of
+ * the client message (ClientHello).
+ */
+typedef struct {
+ /**
+ * \brief Cipher suite to use with that client.
+ */
+ uint16_t cipher_suite;
+
+ /**
+ * \brief Hash function or algorithm for signing the ServerKeyExchange.
+ *
+ * This parameter is ignored for `TLS_RSA_*` and `TLS_ECDH_*`
+ * cipher suites; it is used only for `TLS_ECDHE_*` suites, in
+ * which the server _signs_ the ephemeral EC Diffie-Hellman
+ * parameters sent to the client.
+ *
+ * This identifier must be one of the following values:
+ *
+ * - `0xFF00 + id`, where `id` is a hash function identifier
+ * (0 for MD5+SHA-1, or 2 to 6 for one of the SHA functions);
+ *
+ * - a full 16-bit identifier, lower than `0xFF00`.
+ *
+ * If the first option is used, then the SSL engine will
+ * compute the hash of the data that is to be signed, with the
+ * designated hash function. The `do_sign()` method will be
+ * invoked with that hash value provided in the the `data`
+ * buffer.
+ *
+ * If the second option is used, then the SSL engine will NOT
+ * compute a hash on the data; instead, it will provide the
+ * to-be-signed data itself in `data`, i.e. the concatenation of
+ * the client random, server random, and encoded ECDH
+ * parameters. Furthermore, with TLS-1.2 and later, the 16-bit
+ * identifier will be used "as is" in the protocol, in the
+ * SignatureAndHashAlgorithm; for instance, `0x0401` stands for
+ * RSA PKCS#1 v1.5 signature (the `01`) with SHA-256 as hash
+ * function (the `04`).
+ *
+ * Take care that with TLS 1.0 and 1.1, the hash function is
+ * constrainted by the protocol: RSA signature must use
+ * MD5+SHA-1 (so use `0xFF00`), while ECDSA must use SHA-1
+ * (`0xFF02`). Since TLS 1.0 and 1.1 don't include a
+ * SignatureAndHashAlgorithm field in their ServerKeyExchange
+ * messages, any value below `0xFF00` will be usable to send the
+ * raw ServerKeyExchange data to the `do_sign()` callback, but
+ * that callback must still follow the protocol requirements
+ * when generating the signature.
+ */
+ unsigned algo_id;
+
+ /**
+ * \brief Certificate chain to send to the client.
+ *
+ * This is an array of `br_x509_certificate` objects, each
+ * normally containing a DER-encoded certificate. The server
+ * code does not try to decode these elements.
+ */
+ const br_x509_certificate *chain;
+
+ /**
+ * \brief Certificate chain length (number of certificates).
+ */
+ size_t chain_len;
+
+} br_ssl_server_choices;
+
+/**
+ * \brief Class type for a policy handler (server side).
+ *
+ * A policy handler selects the policy parameters for a connection
+ * (cipher suite and other algorithms, and certificate chain to send to
+ * the client); it also performs the server-side computations involving
+ * its permanent private key.
+ *
+ * The SSL server engine will invoke first `choose()`, once the
+ * ClientHello message has been received, then either `do_keyx()`
+ * `do_sign()`, depending on the cipher suite.
+ */
+typedef struct br_ssl_server_policy_class_ br_ssl_server_policy_class;
+struct br_ssl_server_policy_class_ {
+ /**
+ * \brief Context size (in bytes).
+ */
+ size_t context_size;
+
+ /**
+ * \brief Select algorithms and certificates for this connection.
+ *
+ * This callback function shall fill the provided `choices`
+ * structure with the policy choices for this connection. This
+ * entails selecting the cipher suite, hash function for signing
+ * the ServerKeyExchange (applicable only to ECDHE cipher suites),
+ * and certificate chain to send.
+ *
+ * The callback receives a pointer to the server context that
+ * contains the relevant data. In particular, the functions
+ * `br_ssl_server_get_client_suites()`,
+ * `br_ssl_server_get_client_hashes()` and
+ * `br_ssl_server_get_client_curves()` can be used to obtain
+ * the cipher suites, hash functions and elliptic curves
+ * supported by both the client and server, respectively. The
+ * `br_ssl_engine_get_version()` and `br_ssl_engine_get_server_name()`
+ * functions yield the protocol version and requested server name
+ * (SNI), respectively.
+ *
+ * This function may modify its context structure (`pctx`) in
+ * arbitrary ways to keep track of its own choices.
+ *
+ * This function shall return 1 if appropriate policy choices
+ * could be made, or 0 if this connection cannot be pursued.
+ *
+ * \param pctx policy context.
+ * \param cc SSL server context.
+ * \param choices destination structure for the policy choices.
+ * \return 1 on success, 0 on error.
+ */
+ int (*choose)(const br_ssl_server_policy_class **pctx,
+ const br_ssl_server_context *cc,
+ br_ssl_server_choices *choices);
+
+ /**
+ * \brief Perform key exchange (server part).
+ *
+ * This callback is invoked to perform the server-side cryptographic
+ * operation for a key exchange that is not ECDHE. This callback
+ * uses the private key.
+ *
+ * **For RSA key exchange**, the provided `data` (of length `*len`
+ * bytes) shall be decrypted with the server's private key, and
+ * the 48-byte premaster secret copied back to the first 48 bytes
+ * of `data`.
+ *
+ * - The caller makes sure that `*len` is at least 59 bytes.
+ *
+ * - This callback MUST check that the provided length matches
+ * that of the key modulus; it shall report an error otherwise.
+ *
+ * - If the length matches that of the RSA key modulus, then
+ * processing MUST be constant-time, even if decryption fails,
+ * or the padding is incorrect, or the plaintext message length
+ * is not exactly 48 bytes.
+ *
+ * - This callback needs not check the two first bytes of the
+ * obtained pre-master secret (the caller will do that).
+ *
+ * - If an error is reported (0), then what the callback put
+ * in the first 48 bytes of `data` is unimportant (the caller
+ * will use random bytes instead).
+ *
+ * **For ECDH key exchange**, the provided `data` (of length `*len`
+ * bytes) is the elliptic curve point from the client. The
+ * callback shall multiply it with its private key, and store
+ * the resulting X coordinate in `data`, starting at offset 0,
+ * and set `*len` to the length of the X coordinate.
+ *
+ * - If the input array does not have the proper length for
+ * an encoded curve point, then an error (0) shall be reported.
+ *
+ * - If the input array has the proper length, then processing
+ * MUST be constant-time, even if the data is not a valid
+ * encoded point.
+ *
+ * - This callback MUST check that the input point is valid.
+ *
+ * Returned value is 1 on success, 0 on error.
+ *
+ * \param pctx policy context.
+ * \param data key exchange data from the client.
+ * \param len key exchange data length (in bytes).
+ * \return 1 on success, 0 on error.
+ */
+ uint32_t (*do_keyx)(const br_ssl_server_policy_class **pctx,
+ unsigned char *data, size_t *len);
+
+ /**
+ * \brief Perform a signature (for a ServerKeyExchange message).
+ *
+ * This callback function is invoked for ECDHE cipher suites. On
+ * input, the hash value or message to sign is in `data`, of
+ * size `hv_len`; the involved hash function or algorithm is
+ * identified by `algo_id`. The signature shall be computed and
+ * written back into `data`; the total size of that buffer is
+ * `len` bytes.
+ *
+ * This callback shall verify that the signature length does not
+ * exceed `len` bytes, and abstain from writing the signature if
+ * it does not fit.
+ *
+ * The `algo_id` value matches that which was written in the
+ * `choices` structures by the `choose()` callback. This will be
+ * one of the following:
+ *
+ * - `0xFF00 + id` for a hash function identifier `id`. In
+ * that case, the `data` buffer contains a hash value
+ * already computed over the data that is to be signed,
+ * of length `hv_len`. The `id` may be 0 to designate the
+ * special MD5+SHA-1 concatenation (old-style RSA signing).
+ *
+ * - Another value, lower than `0xFF00`. The `data` buffer
+ * then contains the raw, non-hashed data to be signed
+ * (concatenation of the client and server randoms and
+ * ECDH parameters). The callback is responsible to apply
+ * any relevant hashing as part of the signing process.
+ *
+ * Returned value is the signature length (in bytes), or 0 on error.
+ *
+ * \param pctx policy context.
+ * \param algo_id hash function / algorithm identifier.
+ * \param data input/output buffer (message/hash, then signature).
+ * \param hv_len hash value or message length (in bytes).
+ * \param len total buffer length (in bytes).
+ * \return signature length (in bytes) on success, or 0 on error.
+ */
+ size_t (*do_sign)(const br_ssl_server_policy_class **pctx,
+ unsigned algo_id,
+ unsigned char *data, size_t hv_len, size_t len);
+};
+
+/**
+ * \brief A single-chain RSA policy handler.
+ *
+ * This policy context uses a single certificate chain, and a RSA
+ * private key. The context can be restricted to only signatures or
+ * only key exchange.
+ *
+ * Apart from the first field (vtable pointer), its contents are
+ * opaque and shall not be accessed directly.
+ */
+typedef struct {
+ /** \brief Pointer to vtable. */
+ const br_ssl_server_policy_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ const br_x509_certificate *chain;
+ size_t chain_len;
+ const br_rsa_private_key *sk;
+ unsigned allowed_usages;
+ br_rsa_private irsacore;
+ br_rsa_pkcs1_sign irsasign;
+#endif
+} br_ssl_server_policy_rsa_context;
+
+/**
+ * \brief A single-chain EC policy handler.
+ *
+ * This policy context uses a single certificate chain, and an EC
+ * private key. The context can be restricted to only signatures or
+ * only key exchange.
+ *
+ * Due to how TLS is defined, this context must be made aware whether
+ * the server certificate was itself signed with RSA or ECDSA. The code
+ * does not try to decode the certificate to obtain that information.
+ *
+ * Apart from the first field (vtable pointer), its contents are
+ * opaque and shall not be accessed directly.
+ */
+typedef struct {
+ /** \brief Pointer to vtable. */
+ const br_ssl_server_policy_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ const br_x509_certificate *chain;
+ size_t chain_len;
+ const br_ec_private_key *sk;
+ unsigned allowed_usages;
+ unsigned cert_issuer_key_type;
+ const br_multihash_context *mhash;
+ const br_ec_impl *iec;
+ br_ecdsa_sign iecdsa;
+#endif
+} br_ssl_server_policy_ec_context;
+
+/**
+ * \brief Class type for a session parameter cache.
+ *
+ * Session parameters are saved in the cache with `save()`, and
+ * retrieved with `load()`. The cache implementation can apply any
+ * storage and eviction strategy that it sees fit. The SSL server
+ * context that performs the request is provided, so that its
+ * functionalities may be used by the implementation (e.g. hash
+ * functions or random number generation).
+ */
+typedef struct br_ssl_session_cache_class_ br_ssl_session_cache_class;
+struct br_ssl_session_cache_class_ {
+ /**
+ * \brief Context size (in bytes).
+ */
+ size_t context_size;
+
+ /**
+ * \brief Record a session.
+ *
+ * This callback should record the provided session parameters.
+ * The `params` structure is transient, so its contents shall
+ * be copied into the cache. The session ID has been randomly
+ * generated and always has length exactly 32 bytes.
+ *
+ * \param ctx session cache context.
+ * \param server_ctx SSL server context.
+ * \param params session parameters to save.
+ */
+ void (*save)(const br_ssl_session_cache_class **ctx,
+ br_ssl_server_context *server_ctx,
+ const br_ssl_session_parameters *params);
+
+ /**
+ * \brief Lookup a session in the cache.
+ *
+ * The session ID to lookup is in `params` and always has length
+ * exactly 32 bytes. If the session parameters are found in the
+ * cache, then the parameters shall be copied into the `params`
+ * structure. Returned value is 1 on successful lookup, 0
+ * otherwise.
+ *
+ * \param ctx session cache context.
+ * \param server_ctx SSL server context.
+ * \param params destination for session parameters.
+ * \return 1 if found, 0 otherwise.
+ */
+ int (*load)(const br_ssl_session_cache_class **ctx,
+ br_ssl_server_context *server_ctx,
+ br_ssl_session_parameters *params);
+};
+
+/**
+ * \brief Context for a basic cache system.
+ *
+ * The system stores session parameters in a buffer provided at
+ * initialisation time. Each entry uses exactly 100 bytes, and
+ * buffer sizes up to 4294967295 bytes are supported.
+ *
+ * Entries are evicted with a LRU (Least Recently Used) policy. A
+ * search tree is maintained to keep lookups fast even with large
+ * caches.
+ *
+ * Apart from the first field (vtable pointer), the structure
+ * contents are opaque and shall not be accessed directly.
+ */
+typedef struct {
+ /** \brief Pointer to vtable. */
+ const br_ssl_session_cache_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ unsigned char *store;
+ size_t store_len, store_ptr;
+ unsigned char index_key[32];
+ const br_hash_class *hash;
+ int init_done;
+ uint32_t head, tail, root;
+#endif
+} br_ssl_session_cache_lru;
+
+/**
+ * \brief Initialise a LRU session cache with the provided storage space.
+ *
+ * The provided storage space must remain valid as long as the cache
+ * is used. Arbitrary lengths are supported, up to 4294967295 bytes;
+ * each entry uses up exactly 100 bytes.
+ *
+ * \param cc session cache context.
+ * \param store storage space for cached entries.
+ * \param store_len storage space length (in bytes).
+ */
+void br_ssl_session_cache_lru_init(br_ssl_session_cache_lru *cc,
+ unsigned char *store, size_t store_len);
+
+/**
+ * \brief Forget an entry in an LRU session cache.
+ *
+ * The session cache context must have been initialised. The entry
+ * with the provided session ID (of exactly 32 bytes) is looked for
+ * in the cache; if located, it is disabled.
+ *
+ * \param cc session cache context.
+ * \param id session ID to forget.
+ */
+void br_ssl_session_cache_lru_forget(
+ br_ssl_session_cache_lru *cc, const unsigned char *id);
+
+/**
+ * \brief Context structure for a SSL server.
+ *
+ * The first field (called `eng`) is the SSL engine; all functions that
+ * work on a `br_ssl_engine_context` structure shall take as parameter
+ * a pointer to that field. The other structure fields are opaque and
+ * must not be accessed directly.
+ */
+struct br_ssl_server_context_ {
+ /**
+ * \brief The encapsulated engine context.
+ */
+ br_ssl_engine_context eng;
+
+#ifndef BR_DOXYGEN_IGNORE
+ /*
+ * Maximum version from the client.
+ */
+ uint16_t client_max_version;
+
+ /*
+ * Session cache.
+ */
+ const br_ssl_session_cache_class **cache_vtable;
+
+ /*
+ * Translated cipher suites supported by the client. The list
+ * is trimmed to include only the cipher suites that the
+ * server also supports; they are in the same order as in the
+ * client message.
+ */
+ br_suite_translated client_suites[BR_MAX_CIPHER_SUITES];
+ unsigned char client_suites_num;
+
+ /*
+ * Hash functions supported by the client, with ECDSA and RSA
+ * (bit mask). For hash function with id 'x', set bit index is
+ * x for RSA, x+8 for ECDSA. For newer algorithms, with ID
+ * 0x08**, bit 16+k is set for algorithm 0x0800+k.
+ */
+ uint32_t hashes;
+
+ /*
+ * Curves supported by the client (bit mask, for named curves).
+ */
+ uint32_t curves;
+
+ /*
+ * Context for chain handler.
+ */
+ const br_ssl_server_policy_class **policy_vtable;
+ uint16_t sign_hash_id;
+
+ /*
+ * For the core handlers, thus avoiding (in most cases) the
+ * need for an externally provided policy context.
+ */
+ union {
+ const br_ssl_server_policy_class *vtable;
+ br_ssl_server_policy_rsa_context single_rsa;
+ br_ssl_server_policy_ec_context single_ec;
+ } chain_handler;
+
+ /*
+ * Buffer for the ECDHE private key.
+ */
+ unsigned char ecdhe_key[70];
+ size_t ecdhe_key_len;
+
+ /*
+ * Trust anchor names for client authentication. "ta_names" and
+ * "tas" cannot be both non-NULL.
+ */
+ const br_x500_name *ta_names;
+ const br_x509_trust_anchor *tas;
+ size_t num_tas;
+ size_t cur_dn_index;
+ const unsigned char *cur_dn;
+ size_t cur_dn_len;
+
+ /*
+ * Buffer for the hash value computed over all handshake messages
+ * prior to CertificateVerify, and identifier for the hash function.
+ */
+ unsigned char hash_CV[64];
+ size_t hash_CV_len;
+ int hash_CV_id;
+
+ /*
+ * Server-specific implementations.
+ * (none for now)
+ */
+#endif
+};
+
+/*
+ * Each br_ssl_server_init_xxx() function sets the list of supported
+ * cipher suites and used implementations, as specified by the profile
+ * name 'xxx'. Defined profile names are:
+ *
+ * full_rsa all supported algorithm, server key type is RSA
+ * full_ec all supported algorithm, server key type is EC
+ * TODO: add other profiles
+ *
+ * Naming scheme for "minimal" profiles: min123
+ *
+ * -- character 1: key exchange
+ * r = RSA
+ * e = ECDHE_RSA
+ * f = ECDHE_ECDSA
+ * u = ECDH_RSA
+ * v = ECDH_ECDSA
+ * -- character 2: version / PRF
+ * 0 = TLS 1.0 / 1.1 with MD5+SHA-1
+ * 2 = TLS 1.2 with SHA-256
+ * 3 = TLS 1.2 with SHA-384
+ * -- character 3: encryption
+ * a = AES/CBC
+ * d = 3DES/CBC
+ * g = AES/GCM
+ * c = ChaCha20+Poly1305
+ */
+
+/**
+ * \brief SSL server profile: full_rsa.
+ *
+ * This function initialises the provided SSL server context with
+ * all supported algorithms and cipher suites that rely on a RSA
+ * key pair.
+ *
+ * \param cc server context to initialise.
+ * \param chain server certificate chain.
+ * \param chain_len certificate chain length (number of certificate).
+ * \param sk RSA private key.
+ */
+void br_ssl_server_init_full_rsa(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk);
+
+/**
+ * \brief SSL server profile: full_ec.
+ *
+ * This function initialises the provided SSL server context with
+ * all supported algorithms and cipher suites that rely on an EC
+ * key pair.
+ *
+ * The key type of the CA that issued the server's certificate must
+ * be provided, since it matters for ECDH cipher suites (ECDH_RSA
+ * suites require a RSA-powered CA). The key type is either
+ * `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`.
+ *
+ * \param cc server context to initialise.
+ * \param chain server certificate chain.
+ * \param chain_len chain length (number of certificates).
+ * \param cert_issuer_key_type certificate issuer's key type.
+ * \param sk EC private key.
+ */
+void br_ssl_server_init_full_ec(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ unsigned cert_issuer_key_type, const br_ec_private_key *sk);
+
+/**
+ * \brief SSL server profile: minr2g.
+ *
+ * This profile uses only TLS_RSA_WITH_AES_128_GCM_SHA256. Server key is
+ * RSA, and RSA key exchange is used (not forward secure, but uses little
+ * CPU in the client).
+ *
+ * \param cc server context to initialise.
+ * \param chain server certificate chain.
+ * \param chain_len certificate chain length (number of certificate).
+ * \param sk RSA private key.
+ */
+void br_ssl_server_init_minr2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk);
+
+/**
+ * \brief SSL server profile: mine2g.
+ *
+ * This profile uses only TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256. Server key
+ * is RSA, and ECDHE key exchange is used. This suite provides forward
+ * security, with a higher CPU expense on the client, and a somewhat
+ * larger code footprint (compared to "minr2g").
+ *
+ * \param cc server context to initialise.
+ * \param chain server certificate chain.
+ * \param chain_len certificate chain length (number of certificate).
+ * \param sk RSA private key.
+ */
+void br_ssl_server_init_mine2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk);
+
+/**
+ * \brief SSL server profile: minf2g.
+ *
+ * This profile uses only TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256.
+ * Server key is EC, and ECDHE key exchange is used. This suite provides
+ * forward security, with a higher CPU expense on the client and server
+ * (by a factor of about 3 to 4), and a somewhat larger code footprint
+ * (compared to "minu2g" and "minv2g").
+ *
+ * \param cc server context to initialise.
+ * \param chain server certificate chain.
+ * \param chain_len certificate chain length (number of certificate).
+ * \param sk EC private key.
+ */
+void br_ssl_server_init_minf2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk);
+
+/**
+ * \brief SSL server profile: minu2g.
+ *
+ * This profile uses only TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256.
+ * Server key is EC, and ECDH key exchange is used; the issuing CA used
+ * a RSA key.
+ *
+ * The "minu2g" and "minv2g" profiles do not provide forward secrecy,
+ * but are the lightest on the server (for CPU usage), and are rather
+ * inexpensive on the client as well.
+ *
+ * \param cc server context to initialise.
+ * \param chain server certificate chain.
+ * \param chain_len certificate chain length (number of certificate).
+ * \param sk EC private key.
+ */
+void br_ssl_server_init_minu2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk);
+
+/**
+ * \brief SSL server profile: minv2g.
+ *
+ * This profile uses only TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256.
+ * Server key is EC, and ECDH key exchange is used; the issuing CA used
+ * an EC key.
+ *
+ * The "minu2g" and "minv2g" profiles do not provide forward secrecy,
+ * but are the lightest on the server (for CPU usage), and are rather
+ * inexpensive on the client as well.
+ *
+ * \param cc server context to initialise.
+ * \param chain server certificate chain.
+ * \param chain_len certificate chain length (number of certificate).
+ * \param sk EC private key.
+ */
+void br_ssl_server_init_minv2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk);
+
+/**
+ * \brief SSL server profile: mine2c.
+ *
+ * This profile uses only TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256.
+ * Server key is RSA, and ECDHE key exchange is used. This suite
+ * provides forward security.
+ *
+ * \param cc server context to initialise.
+ * \param chain server certificate chain.
+ * \param chain_len certificate chain length (number of certificate).
+ * \param sk RSA private key.
+ */
+void br_ssl_server_init_mine2c(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk);
+
+/**
+ * \brief SSL server profile: minf2c.
+ *
+ * This profile uses only TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256.
+ * Server key is EC, and ECDHE key exchange is used. This suite provides
+ * forward security.
+ *
+ * \param cc server context to initialise.
+ * \param chain server certificate chain.
+ * \param chain_len certificate chain length (number of certificate).
+ * \param sk EC private key.
+ */
+void br_ssl_server_init_minf2c(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk);
+
+/**
+ * \brief Get the supported client suites.
+ *
+ * This function shall be called only after the ClientHello has been
+ * processed, typically from the policy engine. The returned array
+ * contains the cipher suites that are supported by both the client
+ * and the server; these suites are in client preference order, unless
+ * the `BR_OPT_ENFORCE_SERVER_PREFERENCES` flag was set, in which case
+ * they are in server preference order.
+ *
+ * The suites are _translated_, which means that each suite is given
+ * as two 16-bit integers: the standard suite identifier, and its
+ * translated version, broken down into its individual components,
+ * as explained with the `br_suite_translated` type.
+ *
+ * The returned array is allocated in the context and will be rewritten
+ * by each handshake.
+ *
+ * \param cc server context.
+ * \param num receives the array size (number of suites).
+ * \return the translated common cipher suites, in preference order.
+ */
+static inline const br_suite_translated *
+br_ssl_server_get_client_suites(const br_ssl_server_context *cc, size_t *num)
+{
+ *num = cc->client_suites_num;
+ return cc->client_suites;
+}
+
+/**
+ * \brief Get the hash functions and signature algorithms supported by
+ * the client.
+ *
+ * This value is a bit field:
+ *
+ * - If RSA (PKCS#1 v1.5) is supported with hash function of ID `x`,
+ * then bit `x` is set (hash function ID is 0 for the special MD5+SHA-1,
+ * or 2 to 6 for the SHA family).
+ *
+ * - If ECDSA is supported with hash function of ID `x`, then bit `8+x`
+ * is set.
+ *
+ * - Newer algorithms are symbolic 16-bit identifiers that do not
+ * represent signature algorithm and hash function separately. If
+ * the TLS-level identifier is `0x0800+x` for a `x` in the 0..15
+ * range, then bit `16+x` is set.
+ *
+ * "New algorithms" are currently defined only in draft documents, so
+ * this support is subject to possible change. Right now (early 2017),
+ * this maps ed25519 (EdDSA on Curve25519) to bit 23, and ed448 (EdDSA
+ * on Curve448) to bit 24. If the identifiers on the wire change in
+ * future document, then the decoding mechanism in BearSSL will be
+ * amended to keep mapping ed25519 and ed448 on bits 23 and 24,
+ * respectively. Mapping of other new algorithms (e.g. RSA/PSS) is not
+ * guaranteed yet.
+ *
+ * \param cc server context.
+ * \return the client-supported hash functions and signature algorithms.
+ */
+static inline uint32_t
+br_ssl_server_get_client_hashes(const br_ssl_server_context *cc)
+{
+ return cc->hashes;
+}
+
+/**
+ * \brief Get the elliptic curves supported by the client.
+ *
+ * This is a bit field (bit x is set if curve of ID x is supported).
+ *
+ * \param cc server context.
+ * \return the client-supported elliptic curves.
+ */
+static inline uint32_t
+br_ssl_server_get_client_curves(const br_ssl_server_context *cc)
+{
+ return cc->curves;
+}
+
+/**
+ * \brief Clear the complete contents of a SSL server context.
+ *
+ * Everything is cleared, including the reference to the configured buffer,
+ * implementations, cipher suites and state. This is a preparatory step
+ * to assembling a custom profile.
+ *
+ * \param cc server context to clear.
+ */
+void br_ssl_server_zero(br_ssl_server_context *cc);
+
+/**
+ * \brief Set an externally provided policy context.
+ *
+ * The policy context's methods are invoked to decide the cipher suite
+ * and certificate chain, and to perform operations involving the server's
+ * private key.
+ *
+ * \param cc server context.
+ * \param pctx policy context (pointer to its vtable field).
+ */
+static inline void
+br_ssl_server_set_policy(br_ssl_server_context *cc,
+ const br_ssl_server_policy_class **pctx)
+{
+ cc->policy_vtable = pctx;
+}
+
+/**
+ * \brief Set the server certificate chain and key (single RSA case).
+ *
+ * This function uses a policy context included in the server context.
+ * It configures use of a single server certificate chain with a RSA
+ * private key. The `allowed_usages` is a combination of usages, namely
+ * `BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`; this enables or disables
+ * the corresponding cipher suites (i.e. `TLS_RSA_*` use the RSA key for
+ * key exchange, while `TLS_ECDHE_RSA_*` use the RSA key for signatures).
+ *
+ * \param cc server context.
+ * \param chain server certificate chain to send to the client.
+ * \param chain_len chain length (number of certificates).
+ * \param sk server private key (RSA).
+ * \param allowed_usages allowed private key usages.
+ * \param irsacore RSA core implementation.
+ * \param irsasign RSA signature implementation (PKCS#1 v1.5).
+ */
+void br_ssl_server_set_single_rsa(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk, unsigned allowed_usages,
+ br_rsa_private irsacore, br_rsa_pkcs1_sign irsasign);
+
+/**
+ * \brief Set the server certificate chain and key (single EC case).
+ *
+ * This function uses a policy context included in the server context.
+ * It configures use of a single server certificate chain with an EC
+ * private key. The `allowed_usages` is a combination of usages, namely
+ * `BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`; this enables or disables
+ * the corresponding cipher suites (i.e. `TLS_ECDH_*` use the EC key for
+ * key exchange, while `TLS_ECDHE_ECDSA_*` use the EC key for signatures).
+ *
+ * In order to support `TLS_ECDH_*` cipher suites (non-ephemeral ECDH),
+ * the algorithm type of the key used by the issuing CA to sign the
+ * server's certificate must be provided, as `cert_issuer_key_type`
+ * parameter (this value is either `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`).
+ *
+ * \param cc server context.
+ * \param chain server certificate chain to send.
+ * \param chain_len chain length (number of certificates).
+ * \param sk server private key (EC).
+ * \param allowed_usages allowed private key usages.
+ * \param cert_issuer_key_type issuing CA's key type.
+ * \param iec EC core implementation.
+ * \param iecdsa ECDSA signature implementation ("asn1" format).
+ */
+void br_ssl_server_set_single_ec(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk, unsigned allowed_usages,
+ unsigned cert_issuer_key_type,
+ const br_ec_impl *iec, br_ecdsa_sign iecdsa);
+
+/**
+ * \brief Activate client certificate authentication.
+ *
+ * The trust anchor encoded X.500 names (DN) to send to the client are
+ * provided. A client certificate will be requested and validated through
+ * the X.509 validator configured in the SSL engine. If `num` is 0, then
+ * client certificate authentication is disabled.
+ *
+ * If the client does not send a certificate, or on validation failure,
+ * the handshake aborts. Unauthenticated clients can be tolerated by
+ * setting the `BR_OPT_TOLERATE_NO_CLIENT_AUTH` flag.
+ *
+ * The provided array is linked in, not copied, so that pointer must
+ * remain valid as long as anchor names may be used.
+ *
+ * \param cc server context.
+ * \param ta_names encoded trust anchor names.
+ * \param num number of encoded trust anchor names.
+ */
+static inline void
+br_ssl_server_set_trust_anchor_names(br_ssl_server_context *cc,
+ const br_x500_name *ta_names, size_t num)
+{
+ cc->ta_names = ta_names;
+ cc->tas = NULL;
+ cc->num_tas = num;
+}
+
+/**
+ * \brief Activate client certificate authentication.
+ *
+ * This is a variant for `br_ssl_server_set_trust_anchor_names()`: the
+ * trust anchor names are provided not as an array of stand-alone names
+ * (`br_x500_name` structures), but as an array of trust anchors
+ * (`br_x509_trust_anchor` structures). The server engine itself will
+ * only use the `dn` field of each trust anchor. This is meant to allow
+ * defining a single array of trust anchors, to be used here and in the
+ * X.509 validation engine itself.
+ *
+ * The provided array is linked in, not copied, so that pointer must
+ * remain valid as long as anchor names may be used.
+ *
+ * \param cc server context.
+ * \param tas trust anchors (only names are used).
+ * \param num number of trust anchors.
+ */
+static inline void
+br_ssl_server_set_trust_anchor_names_alt(br_ssl_server_context *cc,
+ const br_x509_trust_anchor *tas, size_t num)
+{
+ cc->ta_names = NULL;
+ cc->tas = tas;
+ cc->num_tas = num;
+}
+
+/**
+ * \brief Configure the cache for session parameters.
+ *
+ * The cache context is provided as a pointer to its first field (vtable
+ * pointer).
+ *
+ * \param cc server context.
+ * \param vtable session cache context.
+ */
+static inline void
+br_ssl_server_set_cache(br_ssl_server_context *cc,
+ const br_ssl_session_cache_class **vtable)
+{
+ cc->cache_vtable = vtable;
+}
+
+/**
+ * \brief Prepare or reset a server context for handling an incoming client.
+ *
+ * \param cc server context.
+ * \return 1 on success, 0 on error.
+ */
+int br_ssl_server_reset(br_ssl_server_context *cc);
+
+/* ===================================================================== */
+
+/*
+ * Context for the simplified I/O context. The transport medium is accessed
+ * through the low_read() and low_write() callback functions, each with
+ * its own opaque context pointer.
+ *
+ * low_read() read some bytes, at most 'len' bytes, into data[]. The
+ * returned value is the number of read bytes, or -1 on error.
+ * The 'len' parameter is guaranteed never to exceed 20000,
+ * so the length always fits in an 'int' on all platforms.
+ *
+ * low_write() write up to 'len' bytes, to be read from data[]. The
+ * returned value is the number of written bytes, or -1 on
+ * error. The 'len' parameter is guaranteed never to exceed
+ * 20000, so the length always fits in an 'int' on all
+ * parameters.
+ *
+ * A socket closure (if the transport medium is a socket) should be reported
+ * as an error (-1). The callbacks shall endeavour to block until at least
+ * one byte can be read or written; a callback returning 0 at times is
+ * acceptable, but this normally leads to the callback being immediately
+ * called again, so the callback should at least always try to block for
+ * some time if no I/O can take place.
+ *
+ * The SSL engine naturally applies some buffering, so the callbacks need
+ * not apply buffers of their own.
+ */
+/**
+ * \brief Context structure for the simplified SSL I/O wrapper.
+ *
+ * This structure is initialised with `br_sslio_init()`. Its contents
+ * are opaque and shall not be accessed directly.
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ br_ssl_engine_context *engine;
+ int (*low_read)(void *read_context,
+ unsigned char *data, size_t len);
+ void *read_context;
+ int (*low_write)(void *write_context,
+ const unsigned char *data, size_t len);
+ void *write_context;
+#endif
+} br_sslio_context;
+
+/**
+ * \brief Initialise a simplified I/O wrapper context.
+ *
+ * The simplified I/O wrapper offers a simpler read/write API for a SSL
+ * engine (client or server), using the provided callback functions for
+ * reading data from, or writing data to, the transport medium.
+ *
+ * The callback functions have the following semantics:
+ *
+ * - Each callback receives an opaque context value (of type `void *`)
+ * that the callback may use arbitrarily (or possibly ignore).
+ *
+ * - `low_read()` reads at least one byte, at most `len` bytes, from
+ * the transport medium. Read bytes shall be written in `data`.
+ *
+ * - `low_write()` writes at least one byte, at most `len` bytes, unto
+ * the transport medium. The bytes to write are read from `data`.
+ *
+ * - The `len` parameter is never zero, and is always lower than 20000.
+ *
+ * - The number of processed bytes (read or written) is returned. Since
+ * that number is less than 20000, it always fits on an `int`.
+ *
+ * - On error, the callbacks return -1. Reaching end-of-stream is an
+ * error. Errors are permanent: the SSL connection is terminated.
+ *
+ * - Callbacks SHOULD NOT return 0. This is tolerated, as long as
+ * callbacks endeavour to block for some non-negligible amount of
+ * time until at least one byte can be sent or received (if a
+ * callback returns 0, then the wrapper invokes it again
+ * immediately).
+ *
+ * - Callbacks MAY return as soon as at least one byte is processed;
+ * they MAY also insist on reading or writing _all_ requested bytes.
+ * Since SSL is a self-terminated protocol (each record has a length
+ * header), this does not change semantics.
+ *
+ * - Callbacks need not apply any buffering (for performance) since SSL
+ * itself uses buffers.
+ *
+ * \param ctx wrapper context to initialise.
+ * \param engine SSL engine to wrap.
+ * \param low_read callback for reading data from the transport.
+ * \param read_context context pointer for `low_read()`.
+ * \param low_write callback for writing data on the transport.
+ * \param write_context context pointer for `low_write()`.
+ */
+void br_sslio_init(br_sslio_context *ctx,
+ br_ssl_engine_context *engine,
+ int (*low_read)(void *read_context,
+ unsigned char *data, size_t len),
+ void *read_context,
+ int (*low_write)(void *write_context,
+ const unsigned char *data, size_t len),
+ void *write_context);
+
+/**
+ * \brief Read some application data from a SSL connection.
+ *
+ * If `len` is zero, then this function returns 0 immediately. In
+ * all other cases, it never returns 0.
+ *
+ * This call returns only when at least one byte has been obtained.
+ * Returned value is the number of bytes read, or -1 on error. The
+ * number of bytes always fits on an 'int' (data from a single SSL/TLS
+ * record is returned).
+ *
+ * On error or SSL closure, this function returns -1. The caller should
+ * inspect the error status on the SSL engine to distinguish between
+ * normal closure and error.
+ *
+ * \param cc SSL wrapper context.
+ * \param dst destination buffer for application data.
+ * \param len maximum number of bytes to obtain.
+ * \return number of bytes obtained, or -1 on error.
+ */
+int br_sslio_read(br_sslio_context *cc, void *dst, size_t len);
+
+/**
+ * \brief Read application data from a SSL connection.
+ *
+ * This calls returns only when _all_ requested `len` bytes are read,
+ * or an error is reached. Returned value is 0 on success, -1 on error.
+ * A normal (verified) SSL closure before that many bytes are obtained
+ * is reported as an error by this function.
+ *
+ * \param cc SSL wrapper context.
+ * \param dst destination buffer for application data.
+ * \param len number of bytes to obtain.
+ * \return 0 on success, or -1 on error.
+ */
+int br_sslio_read_all(br_sslio_context *cc, void *dst, size_t len);
+
+/**
+ * \brief Write some application data unto a SSL connection.
+ *
+ * If `len` is zero, then this function returns 0 immediately. In
+ * all other cases, it never returns 0.
+ *
+ * This call returns only when at least one byte has been written.
+ * Returned value is the number of bytes written, or -1 on error. The
+ * number of bytes always fits on an 'int' (less than 20000).
+ *
+ * On error or SSL closure, this function returns -1. The caller should
+ * inspect the error status on the SSL engine to distinguish between
+ * normal closure and error.
+ *
+ * **Important:** SSL is buffered; a "written" byte is a byte that was
+ * injected into the wrapped SSL engine, but this does not necessarily mean
+ * that it has been scheduled for sending. Use `br_sslio_flush()` to
+ * ensure that all pending data has been sent to the transport medium.
+ *
+ * \param cc SSL wrapper context.
+ * \param src source buffer for application data.
+ * \param len maximum number of bytes to write.
+ * \return number of bytes written, or -1 on error.
+ */
+int br_sslio_write(br_sslio_context *cc, const void *src, size_t len);
+
+/**
+ * \brief Write application data unto a SSL connection.
+ *
+ * This calls returns only when _all_ requested `len` bytes have been
+ * written, or an error is reached. Returned value is 0 on success, -1
+ * on error. A normal (verified) SSL closure before that many bytes are
+ * written is reported as an error by this function.
+ *
+ * **Important:** SSL is buffered; a "written" byte is a byte that was
+ * injected into the wrapped SSL engine, but this does not necessarily mean
+ * that it has been scheduled for sending. Use `br_sslio_flush()` to
+ * ensure that all pending data has been sent to the transport medium.
+ *
+ * \param cc SSL wrapper context.
+ * \param src source buffer for application data.
+ * \param len number of bytes to write.
+ * \return 0 on success, or -1 on error.
+ */
+int br_sslio_write_all(br_sslio_context *cc, const void *src, size_t len);
+
+/**
+ * \brief Flush pending data.
+ *
+ * This call makes sure that any buffered application data in the
+ * provided context (including the wrapped SSL engine) has been sent
+ * to the transport medium (i.e. accepted by the `low_write()` callback
+ * method). If there is no such pending data, then this function does
+ * nothing (and returns a success, i.e. 0).
+ *
+ * If the underlying transport medium has its own buffers, then it is
+ * up to the caller to ensure the corresponding flushing.
+ *
+ * Returned value is 0 on success, -1 on error.
+ *
+ * \param cc SSL wrapper context.
+ * \return 0 on success, or -1 on error.
+ */
+int br_sslio_flush(br_sslio_context *cc);
+
+/**
+ * \brief Close the SSL connection.
+ *
+ * This call runs the SSL closure protocol (sending a `close_notify`,
+ * receiving the response `close_notify`). When it returns, the SSL
+ * connection is finished. It is still up to the caller to manage the
+ * possible transport-level termination, if applicable (alternatively,
+ * the underlying transport stream may be reused for non-SSL messages).
+ *
+ * Returned value is 0 on success, -1 on error. A failure by the peer
+ * to process the complete closure protocol (i.e. sending back the
+ * `close_notify`) is an error.
+ *
+ * \param cc SSL wrapper context.
+ * \return 0 on success, or -1 on error.
+ */
+int br_sslio_close(br_sslio_context *cc);
+
+/* ===================================================================== */
+
+/*
+ * Symbolic constants for cipher suites.
+ */
+
+/* From RFC 5246 */
+#define BR_TLS_NULL_WITH_NULL_NULL 0x0000
+#define BR_TLS_RSA_WITH_NULL_MD5 0x0001
+#define BR_TLS_RSA_WITH_NULL_SHA 0x0002
+#define BR_TLS_RSA_WITH_NULL_SHA256 0x003B
+#define BR_TLS_RSA_WITH_RC4_128_MD5 0x0004
+#define BR_TLS_RSA_WITH_RC4_128_SHA 0x0005
+#define BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA 0x000A
+#define BR_TLS_RSA_WITH_AES_128_CBC_SHA 0x002F
+#define BR_TLS_RSA_WITH_AES_256_CBC_SHA 0x0035
+#define BR_TLS_RSA_WITH_AES_128_CBC_SHA256 0x003C
+#define BR_TLS_RSA_WITH_AES_256_CBC_SHA256 0x003D
+#define BR_TLS_DH_DSS_WITH_3DES_EDE_CBC_SHA 0x000D
+#define BR_TLS_DH_RSA_WITH_3DES_EDE_CBC_SHA 0x0010
+#define BR_TLS_DHE_DSS_WITH_3DES_EDE_CBC_SHA 0x0013
+#define BR_TLS_DHE_RSA_WITH_3DES_EDE_CBC_SHA 0x0016
+#define BR_TLS_DH_DSS_WITH_AES_128_CBC_SHA 0x0030
+#define BR_TLS_DH_RSA_WITH_AES_128_CBC_SHA 0x0031
+#define BR_TLS_DHE_DSS_WITH_AES_128_CBC_SHA 0x0032
+#define BR_TLS_DHE_RSA_WITH_AES_128_CBC_SHA 0x0033
+#define BR_TLS_DH_DSS_WITH_AES_256_CBC_SHA 0x0036
+#define BR_TLS_DH_RSA_WITH_AES_256_CBC_SHA 0x0037
+#define BR_TLS_DHE_DSS_WITH_AES_256_CBC_SHA 0x0038
+#define BR_TLS_DHE_RSA_WITH_AES_256_CBC_SHA 0x0039
+#define BR_TLS_DH_DSS_WITH_AES_128_CBC_SHA256 0x003E
+#define BR_TLS_DH_RSA_WITH_AES_128_CBC_SHA256 0x003F
+#define BR_TLS_DHE_DSS_WITH_AES_128_CBC_SHA256 0x0040
+#define BR_TLS_DHE_RSA_WITH_AES_128_CBC_SHA256 0x0067
+#define BR_TLS_DH_DSS_WITH_AES_256_CBC_SHA256 0x0068
+#define BR_TLS_DH_RSA_WITH_AES_256_CBC_SHA256 0x0069
+#define BR_TLS_DHE_DSS_WITH_AES_256_CBC_SHA256 0x006A
+#define BR_TLS_DHE_RSA_WITH_AES_256_CBC_SHA256 0x006B
+#define BR_TLS_DH_anon_WITH_RC4_128_MD5 0x0018
+#define BR_TLS_DH_anon_WITH_3DES_EDE_CBC_SHA 0x001B
+#define BR_TLS_DH_anon_WITH_AES_128_CBC_SHA 0x0034
+#define BR_TLS_DH_anon_WITH_AES_256_CBC_SHA 0x003A
+#define BR_TLS_DH_anon_WITH_AES_128_CBC_SHA256 0x006C
+#define BR_TLS_DH_anon_WITH_AES_256_CBC_SHA256 0x006D
+
+/* From RFC 4492 */
+#define BR_TLS_ECDH_ECDSA_WITH_NULL_SHA 0xC001
+#define BR_TLS_ECDH_ECDSA_WITH_RC4_128_SHA 0xC002
+#define BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC003
+#define BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA 0xC004
+#define BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA 0xC005
+#define BR_TLS_ECDHE_ECDSA_WITH_NULL_SHA 0xC006
+#define BR_TLS_ECDHE_ECDSA_WITH_RC4_128_SHA 0xC007
+#define BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA 0xC008
+#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA 0xC009
+#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA 0xC00A
+#define BR_TLS_ECDH_RSA_WITH_NULL_SHA 0xC00B
+#define BR_TLS_ECDH_RSA_WITH_RC4_128_SHA 0xC00C
+#define BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA 0xC00D
+#define BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA 0xC00E
+#define BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA 0xC00F
+#define BR_TLS_ECDHE_RSA_WITH_NULL_SHA 0xC010
+#define BR_TLS_ECDHE_RSA_WITH_RC4_128_SHA 0xC011
+#define BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA 0xC012
+#define BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA 0xC013
+#define BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA 0xC014
+#define BR_TLS_ECDH_anon_WITH_NULL_SHA 0xC015
+#define BR_TLS_ECDH_anon_WITH_RC4_128_SHA 0xC016
+#define BR_TLS_ECDH_anon_WITH_3DES_EDE_CBC_SHA 0xC017
+#define BR_TLS_ECDH_anon_WITH_AES_128_CBC_SHA 0xC018
+#define BR_TLS_ECDH_anon_WITH_AES_256_CBC_SHA 0xC019
+
+/* From RFC 5288 */
+#define BR_TLS_RSA_WITH_AES_128_GCM_SHA256 0x009C
+#define BR_TLS_RSA_WITH_AES_256_GCM_SHA384 0x009D
+#define BR_TLS_DHE_RSA_WITH_AES_128_GCM_SHA256 0x009E
+#define BR_TLS_DHE_RSA_WITH_AES_256_GCM_SHA384 0x009F
+#define BR_TLS_DH_RSA_WITH_AES_128_GCM_SHA256 0x00A0
+#define BR_TLS_DH_RSA_WITH_AES_256_GCM_SHA384 0x00A1
+#define BR_TLS_DHE_DSS_WITH_AES_128_GCM_SHA256 0x00A2
+#define BR_TLS_DHE_DSS_WITH_AES_256_GCM_SHA384 0x00A3
+#define BR_TLS_DH_DSS_WITH_AES_128_GCM_SHA256 0x00A4
+#define BR_TLS_DH_DSS_WITH_AES_256_GCM_SHA384 0x00A5
+#define BR_TLS_DH_anon_WITH_AES_128_GCM_SHA256 0x00A6
+#define BR_TLS_DH_anon_WITH_AES_256_GCM_SHA384 0x00A7
+
+/* From RFC 5289 */
+#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 0xC023
+#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 0xC024
+#define BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256 0xC025
+#define BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384 0xC026
+#define BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 0xC027
+#define BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384 0xC028
+#define BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256 0xC029
+#define BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384 0xC02A
+#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 0xC02B
+#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 0xC02C
+#define BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256 0xC02D
+#define BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384 0xC02E
+#define BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 0xC02F
+#define BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 0xC030
+#define BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256 0xC031
+#define BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384 0xC032
+
+/* From RFC 6655 and 7251 */
+#define BR_TLS_RSA_WITH_AES_128_CCM 0xC09C
+#define BR_TLS_RSA_WITH_AES_256_CCM 0xC09D
+#define BR_TLS_RSA_WITH_AES_128_CCM_8 0xC0A0
+#define BR_TLS_RSA_WITH_AES_256_CCM_8 0xC0A1
+#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM 0xC0AC
+#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM 0xC0AD
+#define BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8 0xC0AE
+#define BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8 0xC0AF
+
+/* From RFC 7905 */
+#define BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA8
+#define BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 0xCCA9
+#define BR_TLS_DHE_RSA_WITH_CHACHA20_POLY1305_SHA256 0xCCAA
+#define BR_TLS_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAB
+#define BR_TLS_ECDHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAC
+#define BR_TLS_DHE_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAD
+#define BR_TLS_RSA_PSK_WITH_CHACHA20_POLY1305_SHA256 0xCCAE
+
+/* From RFC 7507 */
+#define BR_TLS_FALLBACK_SCSV 0x5600
+
+/*
+ * Symbolic constants for alerts.
+ */
+#define BR_ALERT_CLOSE_NOTIFY 0
+#define BR_ALERT_UNEXPECTED_MESSAGE 10
+#define BR_ALERT_BAD_RECORD_MAC 20
+#define BR_ALERT_RECORD_OVERFLOW 22
+#define BR_ALERT_DECOMPRESSION_FAILURE 30
+#define BR_ALERT_HANDSHAKE_FAILURE 40
+#define BR_ALERT_BAD_CERTIFICATE 42
+#define BR_ALERT_UNSUPPORTED_CERTIFICATE 43
+#define BR_ALERT_CERTIFICATE_REVOKED 44
+#define BR_ALERT_CERTIFICATE_EXPIRED 45
+#define BR_ALERT_CERTIFICATE_UNKNOWN 46
+#define BR_ALERT_ILLEGAL_PARAMETER 47
+#define BR_ALERT_UNKNOWN_CA 48
+#define BR_ALERT_ACCESS_DENIED 49
+#define BR_ALERT_DECODE_ERROR 50
+#define BR_ALERT_DECRYPT_ERROR 51
+#define BR_ALERT_PROTOCOL_VERSION 70
+#define BR_ALERT_INSUFFICIENT_SECURITY 71
+#define BR_ALERT_INTERNAL_ERROR 80
+#define BR_ALERT_USER_CANCELED 90
+#define BR_ALERT_NO_RENEGOTIATION 100
+#define BR_ALERT_UNSUPPORTED_EXTENSION 110
+#define BR_ALERT_NO_APPLICATION_PROTOCOL 120
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/bearssl/inc/bearssl_x509.h b/contrib/bearssl/inc/bearssl_x509.h
new file mode 100644
index 000000000000..49d2fba0d5bc
--- /dev/null
+++ b/contrib/bearssl/inc/bearssl_x509.h
@@ -0,0 +1,1397 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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"
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/** \file bearssl_x509.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.
+ *
+ * **The "known key" engine** returns a public key which is already known
+ * from out-of-band information (e.g. the client _remembers_ the key from
+ * a previous connection, as in the usual SSH model). This is the simplest
+ * engine since it simply ignores the chain, thereby avoiding the need
+ * for any decoding logic.
+ *
+ * **The "minimal" engine** implements minimal X.509 decoding and chain
+ * validation:
+ *
+ * - The provided chain should validate "as is". There is no attempt
+ * at reordering, skipping or downloading extra certificates.
+ *
+ * - X.509 v1, v2 and v3 certificates are supported.
+ *
+ * - Trust anchors are a DN and a public key. Each anchor is either a
+ * "CA" anchor, or a non-CA.
+ *
+ * - If the end-entity certificate matches a non-CA anchor (subject DN
+ * is equal to the non-CA name, and public key is also identical to
+ * the anchor key), then this is a _direct trust_ case and the
+ * remaining certificates are ignored.
+ *
+ * - Unless direct trust is applied, the chain must be verifiable up to
+ * a certificate whose issuer DN matches the DN from a "CA" trust anchor,
+ * and whose signature is verifiable against that anchor's public key.
+ * Subsequent certificates in the chain are ignored.
+ *
+ * - The engine verifies subject/issuer DN matching, and enforces
+ * processing of Basic Constraints and Key Usage extensions. The
+ * Authority Key Identifier, Subject Key Identifier, Issuer Alt Name,
+ * Subject Directory Attribute, CRL Distribution Points, Freshest CRL,
+ * Authority Info Access and Subject Info Access extensions are
+ * ignored. The Subject Alt Name is decoded for the end-entity
+ * certificate under some conditions (see below). Other extensions
+ * are ignored if non-critical, or imply chain rejection if critical.
+ *
+ * - The Subject Alt Name extension is parsed for names of type `dNSName`
+ * when decoding the end-entity certificate, and only if there is a
+ * server name to match. If there is no SAN extension, then the
+ * Common Name from the subjectDN is used. That name matching is
+ * case-insensitive and honours a single starting wildcard (i.e. if
+ * the name in the certificate starts with "`*.`" then this matches
+ * any word as first element). Note: this name matching is performed
+ * also in the "direct trust" model.
+ *
+ * - DN matching is byte-to-byte equality (a future version might
+ * include some limited processing for case-insensitive matching and
+ * whitespace normalisation).
+ *
+ * - Successful validation produces a public key type but also a set
+ * of allowed usages (`BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`).
+ * The caller is responsible for checking that the key type and
+ * usages are compatible with the expected values (e.g. with the
+ * selected cipher suite, when the client validates the server's
+ * certificate).
+ *
+ * **Important caveats:**
+ *
+ * - The "minimal" engine does not check revocation status. The relevant
+ * extensions are ignored, and CRL or OCSP responses are not gathered
+ * or checked.
+ *
+ * - The "minimal" engine does not currently support Name Constraints
+ * (some basic functionality to handle sub-domains may be added in a
+ * later version).
+ *
+ * - The decoder is not "validating" in the sense that it won't reject
+ * some certificates with invalid field values when these fields are
+ * not actually processed.
+ */
+
+/*
+ * X.509 error codes are in the 32..63 range.
+ */
+
+/** \brief X.509 status: validation was successful; this is not actually
+ an error. */
+#define BR_ERR_X509_OK 32
+
+/** \brief X.509 status: invalid value in an ASN.1 structure. */
+#define BR_ERR_X509_INVALID_VALUE 33
+
+/** \brief X.509 status: truncated certificate. */
+#define BR_ERR_X509_TRUNCATED 34
+
+/** \brief X.509 status: empty certificate chain (no certificate at all). */
+#define BR_ERR_X509_EMPTY_CHAIN 35
+
+/** \brief X.509 status: decoding error: inner element extends beyond
+ outer element size. */
+#define BR_ERR_X509_INNER_TRUNC 36
+
+/** \brief X.509 status: decoding error: unsupported tag class (application
+ or private). */
+#define BR_ERR_X509_BAD_TAG_CLASS 37
+
+/** \brief X.509 status: decoding error: unsupported tag value. */
+#define BR_ERR_X509_BAD_TAG_VALUE 38
+
+/** \brief X.509 status: decoding error: indefinite length. */
+#define BR_ERR_X509_INDEFINITE_LENGTH 39
+
+/** \brief X.509 status: decoding error: extraneous element. */
+#define BR_ERR_X509_EXTRA_ELEMENT 40
+
+/** \brief X.509 status: decoding error: unexpected element. */
+#define BR_ERR_X509_UNEXPECTED 41
+
+/** \brief X.509 status: decoding error: expected constructed element, but
+ is primitive. */
+#define BR_ERR_X509_NOT_CONSTRUCTED 42
+
+/** \brief X.509 status: decoding error: expected primitive element, but
+ is constructed. */
+#define BR_ERR_X509_NOT_PRIMITIVE 43
+
+/** \brief X.509 status: decoding error: BIT STRING length is not multiple
+ of 8. */
+#define BR_ERR_X509_PARTIAL_BYTE 44
+
+/** \brief X.509 status: decoding error: BOOLEAN value has invalid length. */
+#define BR_ERR_X509_BAD_BOOLEAN 45
+
+/** \brief X.509 status: decoding error: value is off-limits. */
+#define BR_ERR_X509_OVERFLOW 46
+
+/** \brief X.509 status: invalid distinguished name. */
+#define BR_ERR_X509_BAD_DN 47
+
+/** \brief X.509 status: invalid date/time representation. */
+#define BR_ERR_X509_BAD_TIME 48
+
+/** \brief X.509 status: certificate contains unsupported features that
+ cannot be ignored. */
+#define BR_ERR_X509_UNSUPPORTED 49
+
+/** \brief X.509 status: key or signature size exceeds internal limits. */
+#define BR_ERR_X509_LIMIT_EXCEEDED 50
+
+/** \brief X.509 status: key type does not match that which was expected. */
+#define BR_ERR_X509_WRONG_KEY_TYPE 51
+
+/** \brief X.509 status: signature is invalid. */
+#define BR_ERR_X509_BAD_SIGNATURE 52
+
+/** \brief X.509 status: validation time is unknown. */
+#define BR_ERR_X509_TIME_UNKNOWN 53
+
+/** \brief X.509 status: certificate is expired or not yet valid. */
+#define BR_ERR_X509_EXPIRED 54
+
+/** \brief X.509 status: issuer/subject DN mismatch in the chain. */
+#define BR_ERR_X509_DN_MISMATCH 55
+
+/** \brief X.509 status: expected server name was not found in the chain. */
+#define BR_ERR_X509_BAD_SERVER_NAME 56
+
+/** \brief X.509 status: unknown critical extension in certificate. */
+#define BR_ERR_X509_CRITICAL_EXTENSION 57
+
+/** \brief X.509 status: not a CA, or path length constraint violation */
+#define BR_ERR_X509_NOT_CA 58
+
+/** \brief X.509 status: Key Usage extension prohibits intended usage. */
+#define BR_ERR_X509_FORBIDDEN_KEY_USAGE 59
+
+/** \brief X.509 status: public key found in certificate is too small. */
+#define BR_ERR_X509_WEAK_PUBLIC_KEY 60
+
+/** \brief X.509 status: chain could not be linked to a trust anchor. */
+#define BR_ERR_X509_NOT_TRUSTED 62
+
+/**
+ * \brief Aggregate structure for public keys.
+ */
+typedef struct {
+ /** \brief Key type: `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC` */
+ unsigned char key_type;
+ /** \brief Actual public key. */
+ union {
+ /** \brief RSA public key. */
+ br_rsa_public_key rsa;
+ /** \brief EC public key. */
+ br_ec_public_key ec;
+ } key;
+} br_x509_pkey;
+
+/**
+ * \brief Distinguished Name (X.500) structure.
+ *
+ * The DN is DER-encoded.
+ */
+typedef struct {
+ /** \brief Encoded DN data. */
+ unsigned char *data;
+ /** \brief Encoded DN length (in bytes). */
+ size_t len;
+} br_x500_name;
+
+/**
+ * \brief Trust anchor structure.
+ */
+typedef struct {
+ /** \brief Encoded DN (X.500 name). */
+ br_x500_name dn;
+ /** \brief Anchor flags (e.g. `BR_X509_TA_CA`). */
+ unsigned flags;
+ /** \brief Anchor public key. */
+ br_x509_pkey pkey;
+} br_x509_trust_anchor;
+
+/**
+ * \brief Trust anchor flag: CA.
+ *
+ * A "CA" anchor is deemed fit to verify signatures on certificates.
+ * A "non-CA" anchor is accepted only for direct trust (server's
+ * certificate name and key match the anchor).
+ */
+#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.
+ */
+/** \brief Key type: algorithm is RSA. */
+#define BR_KEYTYPE_RSA 1
+/** \brief Key type: algorithm is EC. */
+#define BR_KEYTYPE_EC 2
+
+/**
+ * \brief Key type: usage is "key exchange".
+ *
+ * This value is combined (with bitwise OR) with the algorithm
+ * (`BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`) when informing the X.509
+ * validation engine that it should find a public key of that type,
+ * fit for key exchanges (e.g. `TLS_RSA_*` and `TLS_ECDH_*` cipher
+ * suites).
+ */
+#define BR_KEYTYPE_KEYX 0x10
+
+/**
+ * \brief Key type: usage is "signature".
+ *
+ * This value is combined (with bitwise OR) with the algorithm
+ * (`BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`) when informing the X.509
+ * validation engine that it should find a public key of that type,
+ * fit for signatures (e.g. `TLS_ECDHE_*` cipher suites).
+ */
+#define BR_KEYTYPE_SIGN 0x20
+
+/*
+ * 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.
+ */
+
+/**
+ * \brief Class type for an X.509 engine.
+ *
+ * A certificate chain validation uses a caller-allocated context, which
+ * contains the running state for that validation. Methods are called
+ * in due order:
+ *
+ * - `start_chain()` is called at the start of the validation.
+ * - Certificates are processed one by one, in SSL order (end-entity
+ * comes first). For each certificate, the following methods are
+ * called:
+ *
+ * - `start_cert()` at the beginning of the certificate.
+ * - `append()` is called zero, one or more times, to provide
+ * the certificate (possibly in chunks).
+ * - `end_cert()` at the end of the certificate.
+ *
+ * - `end_chain()` is called when the last certificate in the chain
+ * was processed.
+ * - `get_pkey()` is called after chain processing, if the chain
+ * validation was successful.
+ *
+ * A context structure may be reused; the `start_chain()` method shall
+ * ensure (re)initialisation.
+ */
+typedef struct br_x509_class_ br_x509_class;
+struct br_x509_class_ {
+ /**
+ * \brief X.509 context size, in bytes.
+ */
+ size_t context_size;
+
+ /**
+ * \brief Start a new chain.
+ *
+ * This method shall set the vtable (first field) of the context
+ * structure.
+ *
+ * The `server_name`, if not `NULL`, will be considered as a
+ * fully qualified domain name, to be matched against the `dNSName`
+ * elements of the end-entity certificate's SAN extension (if there
+ * is no SAN, then the Common Name from the subjectDN will be used).
+ * If `server_name` is `NULL` then no such matching is performed.
+ *
+ * \param ctx validation context.
+ * \param server_name server name to match (or `NULL`).
+ */
+ void (*start_chain)(const br_x509_class **ctx,
+ const char *server_name);
+
+ /**
+ * \brief Start a new certificate.
+ *
+ * \param ctx validation context.
+ * \param length new certificate length (in bytes).
+ */
+ void (*start_cert)(const br_x509_class **ctx, uint32_t length);
+
+ /**
+ * \brief Receive some bytes for the current certificate.
+ *
+ * This function may be called several times in succession for
+ * a given certificate. The caller guarantees that for each
+ * call, `len` is not zero, and the sum of all chunk lengths
+ * for a certificate matches the total certificate length which
+ * was provided in the previous `start_cert()` call.
+ *
+ * If the new certificate is empty (no byte at all) then this
+ * function won't be called at all.
+ *
+ * \param ctx validation context.
+ * \param buf certificate data chunk.
+ * \param len certificate data chunk length (in bytes).
+ */
+ void (*append)(const br_x509_class **ctx,
+ const unsigned char *buf, size_t len);
+
+ /**
+ * \brief Finish the current certificate.
+ *
+ * This function is called when the end of the current certificate
+ * is reached.
+ *
+ * \param ctx validation context.
+ */
+ void (*end_cert)(const br_x509_class **ctx);
+
+ /**
+ * \brief Finish the chain.
+ *
+ * This function is called at the end of the chain. It shall
+ * return either 0 if the validation was successful, or a
+ * non-zero error code. The `BR_ERR_X509_*` constants are
+ * error codes, though other values may be possible.
+ *
+ * \param ctx validation context.
+ * \return 0 on success, or a non-zero error code.
+ */
+ unsigned (*end_chain)(const br_x509_class **ctx);
+
+ /**
+ * \brief Get the resulting end-entity public key.
+ *
+ * The decoded public key is returned. The returned pointer
+ * may be valid only as long as the context structure is
+ * unmodified, i.e. it may cease to be valid if the context
+ * is released or reused.
+ *
+ * This function _may_ return `NULL` if the validation failed.
+ * However, returning a public key does not mean that the
+ * validation was wholly successful; some engines may return
+ * a decoded public key even if the chain did not end on a
+ * trusted anchor.
+ *
+ * If validation succeeded and `usage` is not `NULL`, then
+ * `*usage` is filled with a combination of `BR_KEYTYPE_SIGN`
+ * and/or `BR_KEYTYPE_KEYX` that specifies the validated key
+ * usage types. It is the caller's responsibility to check
+ * that value against the intended use of the public key.
+ *
+ * \param ctx validation context.
+ * \return the end-entity public key, or `NULL`.
+ */
+ const br_x509_pkey *(*get_pkey)(
+ const br_x509_class *const *ctx, unsigned *usages);
+};
+
+/**
+ * \brief The "known key" X.509 engine structure.
+ *
+ * The structure contents are opaque (they shall not be accessed directly),
+ * except for the first field (the vtable).
+ *
+ * The "known key" engine returns an externally configured public key,
+ * and totally ignores the certificate contents.
+ */
+typedef struct {
+ /** \brief Reference to the context vtable. */
+ const br_x509_class *vtable;
+#ifndef BR_DOXYGEN_IGNORE
+ br_x509_pkey pkey;
+ unsigned usages;
+#endif
+} br_x509_knownkey_context;
+
+/**
+ * \brief Class instance for the "known key" X.509 engine.
+ */
+extern const br_x509_class br_x509_knownkey_vtable;
+
+/**
+ * \brief Initialize a "known key" X.509 engine with a known RSA public key.
+ *
+ * The `usages` parameter indicates the allowed key usages for that key
+ * (`BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`).
+ *
+ * The provided pointers are linked in, not copied, so they must remain
+ * valid while the public key may be in usage.
+ *
+ * \param ctx context to initialise.
+ * \param pk known public key.
+ * \param usages allowed key usages.
+ */
+void br_x509_knownkey_init_rsa(br_x509_knownkey_context *ctx,
+ const br_rsa_public_key *pk, unsigned usages);
+
+/**
+ * \brief Initialize a "known key" X.509 engine with a known EC public key.
+ *
+ * The `usages` parameter indicates the allowed key usages for that key
+ * (`BR_KEYTYPE_KEYX` and/or `BR_KEYTYPE_SIGN`).
+ *
+ * The provided pointers are linked in, not copied, so they must remain
+ * valid while the public key may be in usage.
+ *
+ * \param ctx context to initialise.
+ * \param pk known public key.
+ * \param usages allowed key usages.
+ */
+void br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx,
+ const br_ec_public_key *pk, unsigned usages);
+
+#ifndef BR_DOXYGEN_IGNORE
+/*
+ * 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 implementations (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. The X.509 "minimal" engine will tolerate
+ * public exponents of arbitrary size as long as the modulus and the
+ * exponent can fit together in the dedicated buffer.
+ *
+ * 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
+#endif
+
+/**
+ * \brief Type for receiving a name element.
+ *
+ * An array of such structures can be provided to the X.509 decoding
+ * engines. If the specified elements are found in the certificate
+ * subject DN or the SAN extension, then the name contents are copied
+ * as zero-terminated strings into the buffer.
+ *
+ * The decoder converts TeletexString and BMPString to UTF8String, and
+ * ensures that the resulting string is zero-terminated. If the string
+ * does not fit in the provided buffer, then the copy is aborted and an
+ * error is reported.
+ */
+typedef struct {
+ /**
+ * \brief Element OID.
+ *
+ * For X.500 name elements (to be extracted from the subject DN),
+ * this is the encoded OID for the requested name element; the
+ * first byte shall contain the length of the DER-encoded OID
+ * value, followed by the OID value (for instance, OID 2.5.4.3,
+ * for id-at-commonName, will be `03 55 04 03`). This is
+ * equivalent to full DER encoding with the length but without
+ * the tag.
+ *
+ * For SAN name elements, the first byte (`oid[0]`) has value 0,
+ * followed by another byte that matches the expected GeneralName
+ * tag. Allowed second byte values are then:
+ *
+ * - 1: `rfc822Name`
+ *
+ * - 2: `dNSName`
+ *
+ * - 6: `uniformResourceIdentifier`
+ *
+ * - 0: `otherName`
+ *
+ * If first and second byte are 0, then this is a SAN element of
+ * type `otherName`; the `oid[]` array should then contain, right
+ * after the two bytes of value 0, an encoded OID (with the same
+ * conventions as for X.500 name elements). If a match is found
+ * for that OID, then the corresponding name element will be
+ * extracted, as long as it is a supported string type.
+ */
+ const unsigned char *oid;
+
+ /**
+ * \brief Destination buffer.
+ */
+ char *buf;
+
+ /**
+ * \brief Length (in bytes) of the destination buffer.
+ *
+ * The buffer MUST NOT be smaller than 1 byte.
+ */
+ size_t len;
+
+ /**
+ * \brief Decoding status.
+ *
+ * Status is 0 if the name element was not found, 1 if it was
+ * found and decoded, or -1 on error. Error conditions include
+ * an unrecognised encoding, an invalid encoding, or a string
+ * too large for the destination buffer.
+ */
+ int status;
+
+} br_name_element;
+
+/**
+ * \brief The "minimal" X.509 engine structure.
+ *
+ * The structure contents are opaque (they shall not be accessed directly),
+ * except for the first field (the vtable).
+ *
+ * The "minimal" engine performs a rudimentary but serviceable X.509 path
+ * validation.
+ */
+typedef struct {
+ const br_x509_class *vtable;
+
+#ifndef BR_DOXYGEN_IGNORE
+ /* 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;
+
+ /* Validated key usages. */
+ unsigned char key_usages;
+
+ /* 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];
+
+ /*
+ * Name elements to gather.
+ */
+ br_name_element *name_elts;
+ size_t num_name_elts;
+
+ /*
+ * Public key cryptography implementations (signature verification).
+ */
+ br_rsa_pkcs1_vrfy irsa;
+ br_ecdsa_vrfy iecdsa;
+ const br_ec_impl *iec;
+#endif
+
+} br_x509_minimal_context;
+
+/**
+ * \brief Class instance for the "minimal" X.509 engine.
+ */
+extern const br_x509_class br_x509_minimal_vtable;
+
+/**
+ * \brief Initialise a "minimal" X.509 engine.
+ *
+ * The `dn_hash_impl` parameter shall be a hash function internally used
+ * to match X.500 names (subject/issuer DN, and anchor names). Any standard
+ * hash function may be used, but a collision-resistant hash function is
+ * advised.
+ *
+ * After initialization, some implementations for signature verification
+ * (hash functions and signature algorithms) MUST be added.
+ *
+ * \param ctx context to initialise.
+ * \param dn_hash_impl hash function for DN comparisons.
+ * \param trust_anchors trust anchors.
+ * \param trust_anchors_num number of trust anchors.
+ */
+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);
+
+/**
+ * \brief Set a supported hash function in an X.509 "minimal" engine.
+ *
+ * Hash functions are used with signature verification algorithms.
+ * Once initialised (with `br_x509_minimal_init()`), the context must
+ * be configured with the hash functions it shall support for that
+ * purpose. The hash function identifier MUST be one of the standard
+ * hash function identifiers (1 to 6, for MD5, SHA-1, SHA-224, SHA-256,
+ * SHA-384 and SHA-512).
+ *
+ * If `impl` is `NULL`, this _removes_ support for the designated
+ * hash function.
+ *
+ * \param ctx validation context.
+ * \param id hash function identifier (from 1 to 6).
+ * \param impl hash function implementation (or `NULL`).
+ */
+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);
+}
+
+/**
+ * \brief Set a RSA signature verification implementation in the X.509
+ * "minimal" engine.
+ *
+ * Once initialised (with `br_x509_minimal_init()`), the context must
+ * be configured with the signature verification implementations that
+ * it is supposed to support. If `irsa` is `0`, then the RSA support
+ * is disabled.
+ *
+ * \param ctx validation context.
+ * \param irsa RSA signature verification implementation (or `0`).
+ */
+static inline void
+br_x509_minimal_set_rsa(br_x509_minimal_context *ctx,
+ br_rsa_pkcs1_vrfy irsa)
+{
+ ctx->irsa = irsa;
+}
+
+/**
+ * \brief Set a ECDSA signature verification implementation in the X.509
+ * "minimal" engine.
+ *
+ * Once initialised (with `br_x509_minimal_init()`), the context must
+ * be configured with the signature verification implementations that
+ * it is supposed to support.
+ *
+ * If `iecdsa` is `0`, then this call disables ECDSA support; in that
+ * case, `iec` may be `NULL`. Otherwise, `iecdsa` MUST point to a function
+ * that verifies ECDSA signatures with format "asn1", and it will use
+ * `iec` as underlying elliptic curve support.
+ *
+ * \param ctx validation context.
+ * \param iec elliptic curve implementation (or `NULL`).
+ * \param iecdsa ECDSA implementation (or `0`).
+ */
+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;
+}
+
+/**
+ * \brief Initialise a "minimal" X.509 engine with default algorithms.
+ *
+ * This function performs the same job as `br_x509_minimal_init()`, but
+ * also sets implementations for RSA, ECDSA, and the standard hash
+ * functions.
+ *
+ * \param ctx context to initialise.
+ * \param trust_anchors trust anchors.
+ * \param trust_anchors_num number of trust anchors.
+ */
+void br_x509_minimal_init_full(br_x509_minimal_context *ctx,
+ const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num);
+
+/**
+ * \brief Set the validation time for the X.509 "minimal" engine.
+ *
+ * The validation time is set as two 32-bit integers, for days and
+ * seconds since a fixed epoch:
+ *
+ * - 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).
+ *
+ * The validation date and time is understood in the UTC time zone.
+ *
+ * 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,
+ * not setting the validation date and time implies a validation
+ * failure (except in case of direct trust of the EE key).
+ *
+ * \param ctx validation context.
+ * \param days days since January 1st, 0 AD (Gregorian calendar).
+ * \param seconds seconds since midnight (0 to 86400).
+ */
+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;
+}
+
+/**
+ * \brief Set the minimal acceptable length for RSA keys (X.509 "minimal"
+ * engine).
+ *
+ * The RSA key length is expressed in bytes. The default minimum key
+ * length is 128 bytes, corresponding to 1017 bits. RSA keys shorter
+ * than the configured length will be rejected, implying validation
+ * failure. This setting applies to keys extracted from certificates
+ * (both end-entity, and intermediate CA) but not to "CA" trust anchors.
+ *
+ * \param ctx validation context.
+ * \param byte_length minimum RSA key length, **in bytes** (not bits).
+ */
+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);
+}
+
+/**
+ * \brief Set the name elements to gather.
+ *
+ * The provided array is linked in the context. The elements are
+ * gathered from the EE certificate. If the same element type is
+ * requested several times, then the relevant structures will be filled
+ * in the order the matching values are encountered in the certificate.
+ *
+ * \param ctx validation context.
+ * \param elts array of name element structures to fill.
+ * \param num_elts number of name element structures to fill.
+ */
+static inline void
+br_x509_minimal_set_name_elements(br_x509_minimal_context *ctx,
+ br_name_element *elts, size_t num_elts)
+{
+ ctx->name_elts = elts;
+ ctx->num_name_elts = num_elts;
+}
+
+/**
+ * \brief X.509 decoder context.
+ *
+ * This structure is _not_ for X.509 validation, but for extracting
+ * names and public keys from encoded certificates. Intended usage is
+ * to use (self-signed) certificates as trust anchors.
+ *
+ * Contents are opaque and shall not be accessed directly.
+ */
+typedef struct {
+
+#ifndef BR_DOXYGEN_IGNORE
+ /* 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;
+#endif
+
+} br_x509_decoder_context;
+
+/**
+ * \brief Initialise an X.509 decoder context for processing a new
+ * certificate.
+ *
+ * The `append_dn()` callback (with opaque context `append_dn_ctx`)
+ * will be invoked to receive, chunk by chunk, the certificate's
+ * subject DN. If `append_dn` is `0` then the subject DN will be
+ * ignored.
+ *
+ * \param ctx X.509 decoder context to initialise.
+ * \param append_dn DN receiver callback (or `0`).
+ * \param append_dn_ctx context for the DN receiver callback.
+ */
+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);
+
+/**
+ * \brief Push some certificate bytes into a decoder context.
+ *
+ * If `len` is non-zero, then that many bytes are pushed, from address
+ * `data`, into the provided decoder context.
+ *
+ * \param ctx X.509 decoder context.
+ * \param data certificate data chunk.
+ * \param len certificate data chunk length (in bytes).
+ */
+void br_x509_decoder_push(br_x509_decoder_context *ctx,
+ const void *data, size_t len);
+
+/**
+ * \brief 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.
+ *
+ * \param ctx X.509 decoder context.
+ * \return the public key, or `NULL` on unfinished/error.
+ */
+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;
+ }
+}
+
+/**
+ * \brief Get decoder error status.
+ *
+ * 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.
+ *
+ * \param ctx X.509 decoder context.
+ * \return 0 on successful decoding, or a non-zero error code.
+ */
+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;
+}
+
+/**
+ * \brief 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. This flag should not be read before
+ * decoding completed successfully.
+ *
+ * \param ctx X.509 decoder context.
+ * \return the "isCA" flag.
+ */
+static inline int
+br_x509_decoder_isCA(br_x509_decoder_context *ctx)
+{
+ return ctx->isCA;
+}
+
+/**
+ * \brief Get the issuing CA key type (type of algorithm 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.
+ *
+ * \param ctx X.509 decoder context.
+ * \return the issuing CA key type.
+ */
+static inline int
+br_x509_decoder_get_signer_key_type(br_x509_decoder_context *ctx)
+{
+ return ctx->signer_key_type;
+}
+
+/**
+ * \brief Get the identifier for the hash function used to sign the decoded
+ * certificate.
+ *
+ * This is 0 if the hash function was not recognised.
+ *
+ * \param ctx X.509 decoder context.
+ * \return the signature hash function identifier.
+ */
+static inline int
+br_x509_decoder_get_signer_hash_id(br_x509_decoder_context *ctx)
+{
+ return ctx->signer_hash_id;
+}
+
+/**
+ * \brief Type for an X.509 certificate (DER-encoded).
+ */
+typedef struct {
+ /** \brief The DER-encoded certificate data. */
+ unsigned char *data;
+ /** \brief The DER-encoded certificate length (in bytes). */
+ size_t data_len;
+} br_x509_certificate;
+
+/**
+ * \brief Private key decoder context.
+ *
+ * The private key decoder recognises RSA and EC private keys, either in
+ * their raw, DER-encoded format, or wrapped in an unencrypted PKCS#8
+ * archive (again DER-encoded).
+ *
+ * Structure contents are opaque and shall not be accessed directly.
+ */
+typedef struct {
+#ifndef BR_DOXYGEN_IGNORE
+ /* 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];
+#endif
+} br_skey_decoder_context;
+
+/**
+ * \brief Initialise a private key decoder context.
+ *
+ * \param ctx key decoder context to initialise.
+ */
+void br_skey_decoder_init(br_skey_decoder_context *ctx);
+
+/**
+ * \brief Push some data bytes into a private key decoder context.
+ *
+ * If `len` is non-zero, then that many data bytes, starting at address
+ * `data`, are pushed into the decoder.
+ *
+ * \param ctx key decoder context.
+ * \param data private key data chunk.
+ * \param len private key data chunk length (in bytes).
+ */
+void br_skey_decoder_push(br_skey_decoder_context *ctx,
+ const void *data, size_t len);
+
+/**
+ * \brief Get the decoding status for a private key.
+ *
+ * Decoding status is 0 on success, or a non-zero error code. If the
+ * decoding is unfinished when this function is called, then the
+ * status code `BR_ERR_X509_TRUNCATED` is returned.
+ *
+ * \param ctx key decoder context.
+ * \return 0 on successful decoding, 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;
+}
+
+/**
+ * \brief Get the decoded private key type.
+ *
+ * Private key type is `BR_KEYTYPE_RSA` or `BR_KEYTYPE_EC`. If decoding is
+ * not finished or failed, then 0 is returned.
+ *
+ * \param ctx key decoder context.
+ * \return decoded private key type, or 0.
+ */
+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;
+ }
+}
+
+/**
+ * \brief 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.
+ *
+ * \param ctx key decoder context.
+ * \return decoded RSA private key, or `NULL`.
+ */
+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;
+ }
+}
+
+/**
+ * \brief 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.
+ *
+ * \param ctx key decoder context.
+ * \return decoded EC private key, or `NULL`.
+ */
+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;
+ }
+}
+
+/**
+ * \brief Encode an RSA private key (raw DER format).
+ *
+ * This function encodes the provided key into the "raw" format specified
+ * in PKCS#1 (RFC 8017, Appendix C, type `RSAPrivateKey`), with DER
+ * encoding rules.
+ *
+ * The key elements are:
+ *
+ * - `sk`: the private key (`p`, `q`, `dp`, `dq` and `iq`)
+ *
+ * - `pk`: the public key (`n` and `e`)
+ *
+ * - `d` (size: `dlen` bytes): the private exponent
+ *
+ * The public key elements, and the private exponent `d`, can be
+ * recomputed from the private key (see `br_rsa_compute_modulus()`,
+ * `br_rsa_compute_pubexp()` and `br_rsa_compute_privexp()`).
+ *
+ * If `dest` is not `NULL`, then the encoded key is written at that
+ * address, and the encoded length (in bytes) is returned. If `dest` is
+ * `NULL`, then nothing is written, but the encoded length is still
+ * computed and returned.
+ *
+ * \param dest the destination buffer (or `NULL`).
+ * \param sk the RSA private key.
+ * \param pk the RSA public key.
+ * \param d the RSA private exponent.
+ * \param dlen the RSA private exponent length (in bytes).
+ * \return the encoded key length (in bytes).
+ */
+size_t br_encode_rsa_raw_der(void *dest, const br_rsa_private_key *sk,
+ const br_rsa_public_key *pk, const void *d, size_t dlen);
+
+/**
+ * \brief Encode an RSA private key (PKCS#8 DER format).
+ *
+ * This function encodes the provided key into the PKCS#8 format
+ * (RFC 5958, type `OneAsymmetricKey`). It wraps around the "raw DER"
+ * format for the RSA key, as implemented by `br_encode_rsa_raw_der()`.
+ *
+ * The key elements are:
+ *
+ * - `sk`: the private key (`p`, `q`, `dp`, `dq` and `iq`)
+ *
+ * - `pk`: the public key (`n` and `e`)
+ *
+ * - `d` (size: `dlen` bytes): the private exponent
+ *
+ * The public key elements, and the private exponent `d`, can be
+ * recomputed from the private key (see `br_rsa_compute_modulus()`,
+ * `br_rsa_compute_pubexp()` and `br_rsa_compute_privexp()`).
+ *
+ * If `dest` is not `NULL`, then the encoded key is written at that
+ * address, and the encoded length (in bytes) is returned. If `dest` is
+ * `NULL`, then nothing is written, but the encoded length is still
+ * computed and returned.
+ *
+ * \param dest the destination buffer (or `NULL`).
+ * \param sk the RSA private key.
+ * \param pk the RSA public key.
+ * \param d the RSA private exponent.
+ * \param dlen the RSA private exponent length (in bytes).
+ * \return the encoded key length (in bytes).
+ */
+size_t br_encode_rsa_pkcs8_der(void *dest, const br_rsa_private_key *sk,
+ const br_rsa_public_key *pk, const void *d, size_t dlen);
+
+/**
+ * \brief Encode an EC private key (raw DER format).
+ *
+ * This function encodes the provided key into the "raw" format specified
+ * in RFC 5915 (type `ECPrivateKey`), with DER encoding rules.
+ *
+ * The private key is provided in `sk`, the public key being `pk`. If
+ * `pk` is `NULL`, then the encoded key will not include the public key
+ * in its `publicKey` field (which is nominally optional).
+ *
+ * If `dest` is not `NULL`, then the encoded key is written at that
+ * address, and the encoded length (in bytes) is returned. If `dest` is
+ * `NULL`, then nothing is written, but the encoded length is still
+ * computed and returned.
+ *
+ * If the key cannot be encoded (e.g. because there is no known OBJECT
+ * IDENTIFIER for the used curve), then 0 is returned.
+ *
+ * \param dest the destination buffer (or `NULL`).
+ * \param sk the EC private key.
+ * \param pk the EC public key (or `NULL`).
+ * \return the encoded key length (in bytes), or 0.
+ */
+size_t br_encode_ec_raw_der(void *dest,
+ const br_ec_private_key *sk, const br_ec_public_key *pk);
+
+/**
+ * \brief Encode an EC private key (PKCS#8 DER format).
+ *
+ * This function encodes the provided key into the PKCS#8 format
+ * (RFC 5958, type `OneAsymmetricKey`). The curve is identified
+ * by an OID provided as parameters to the `privateKeyAlgorithm`
+ * field. The private key value (contents of the `privateKey` field)
+ * contains the DER encoding of the `ECPrivateKey` type defined in
+ * RFC 5915, without the `parameters` field (since they would be
+ * redundant with the information in `privateKeyAlgorithm`).
+ *
+ * The private key is provided in `sk`, the public key being `pk`. If
+ * `pk` is not `NULL`, then the encoded public key is included in the
+ * `publicKey` field of the private key value (but not in the `publicKey`
+ * field of the PKCS#8 `OneAsymmetricKey` wrapper).
+ *
+ * If `dest` is not `NULL`, then the encoded key is written at that
+ * address, and the encoded length (in bytes) is returned. If `dest` is
+ * `NULL`, then nothing is written, but the encoded length is still
+ * computed and returned.
+ *
+ * If the key cannot be encoded (e.g. because there is no known OBJECT
+ * IDENTIFIER for the used curve), then 0 is returned.
+ *
+ * \param dest the destination buffer (or `NULL`).
+ * \param sk the EC private key.
+ * \param pk the EC public key (or `NULL`).
+ * \return the encoded key length (in bytes), or 0.
+ */
+size_t br_encode_ec_pkcs8_der(void *dest,
+ const br_ec_private_key *sk, const br_ec_public_key *pk);
+
+/**
+ * \brief PEM banner for RSA private key (raw).
+ */
+#define BR_ENCODE_PEM_RSA_RAW "RSA PRIVATE KEY"
+
+/**
+ * \brief PEM banner for EC private key (raw).
+ */
+#define BR_ENCODE_PEM_EC_RAW "EC PRIVATE KEY"
+
+/**
+ * \brief PEM banner for an RSA or EC private key in PKCS#8 format.
+ */
+#define BR_ENCODE_PEM_PKCS8 "PRIVATE KEY"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/contrib/bearssl/mk/Defaults.mk b/contrib/bearssl/mk/Defaults.mk
new file mode 100644
index 000000000000..4c66025d5876
--- /dev/null
+++ b/contrib/bearssl/mk/Defaults.mk
@@ -0,0 +1,41 @@
+# Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+# ======================================================================
+
+# This file sets variables with generic default values, which can be
+# overridden in the selected configuration file.
+
+BUILD = build
+OBJDIR = $(BUILD)$Pobj
+BEARSSLLIB = $(BUILD)$P$(LP)bearssl$L
+BEARSSLDLL = $(BUILD)$P$(DP)bearssl$D
+BRSSL = $(BUILD)$Pbrssl$E
+TESTCRYPTO = $(BUILD)$Ptestcrypto$E
+TESTSPEED = $(BUILD)$Ptestspeed$E
+TESTX509 = $(BUILD)$Ptestx509$E
+INCFLAGS = -Isrc -Iinc
+T0COMP = T0Comp.exe
+STATICLIB = lib
+DLL = dll
+TOOLS = tools
+TESTS = tests
diff --git a/contrib/bearssl/mk/NMake.mk b/contrib/bearssl/mk/NMake.mk
new file mode 100644
index 000000000000..7a53704dcdc3
--- /dev/null
+++ b/contrib/bearssl/mk/NMake.mk
@@ -0,0 +1,38 @@
+# Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+# ======================================================================
+
+# This file sets variables for use with NMake.exe, as distributed with
+# Visual Studio.
+
+# Load generic defaults.
+!include mk/Defaults.mk
+
+# Default configuration is 'Win' (native build with Visual Studio).
+CONF = Win
+
+# Path separator.
+P = ^\
+
+!include conf/$(CONF).mk
+!include mk/Rules.mk
diff --git a/contrib/bearssl/mk/Rules.mk b/contrib/bearssl/mk/Rules.mk
new file mode 100644
index 000000000000..7448bb48ea36
--- /dev/null
+++ b/contrib/bearssl/mk/Rules.mk
@@ -0,0 +1,1318 @@
+# Automatically generated rules. Use 'mkrules.sh' to modify/regenerate.
+
+OBJ = \
+ $(OBJDIR)$Psettings$O \
+ $(OBJDIR)$Pccm$O \
+ $(OBJDIR)$Peax$O \
+ $(OBJDIR)$Pgcm$O \
+ $(OBJDIR)$Pccopy$O \
+ $(OBJDIR)$Pdec16be$O \
+ $(OBJDIR)$Pdec16le$O \
+ $(OBJDIR)$Pdec32be$O \
+ $(OBJDIR)$Pdec32le$O \
+ $(OBJDIR)$Pdec64be$O \
+ $(OBJDIR)$Pdec64le$O \
+ $(OBJDIR)$Penc16be$O \
+ $(OBJDIR)$Penc16le$O \
+ $(OBJDIR)$Penc32be$O \
+ $(OBJDIR)$Penc32le$O \
+ $(OBJDIR)$Penc64be$O \
+ $(OBJDIR)$Penc64le$O \
+ $(OBJDIR)$Ppemdec$O \
+ $(OBJDIR)$Ppemenc$O \
+ $(OBJDIR)$Pec_all_m15$O \
+ $(OBJDIR)$Pec_all_m31$O \
+ $(OBJDIR)$Pec_c25519_i15$O \
+ $(OBJDIR)$Pec_c25519_i31$O \
+ $(OBJDIR)$Pec_c25519_m15$O \
+ $(OBJDIR)$Pec_c25519_m31$O \
+ $(OBJDIR)$Pec_c25519_m62$O \
+ $(OBJDIR)$Pec_c25519_m64$O \
+ $(OBJDIR)$Pec_curve25519$O \
+ $(OBJDIR)$Pec_default$O \
+ $(OBJDIR)$Pec_keygen$O \
+ $(OBJDIR)$Pec_p256_m15$O \
+ $(OBJDIR)$Pec_p256_m31$O \
+ $(OBJDIR)$Pec_p256_m62$O \
+ $(OBJDIR)$Pec_p256_m64$O \
+ $(OBJDIR)$Pec_prime_i15$O \
+ $(OBJDIR)$Pec_prime_i31$O \
+ $(OBJDIR)$Pec_pubkey$O \
+ $(OBJDIR)$Pec_secp256r1$O \
+ $(OBJDIR)$Pec_secp384r1$O \
+ $(OBJDIR)$Pec_secp521r1$O \
+ $(OBJDIR)$Pecdsa_atr$O \
+ $(OBJDIR)$Pecdsa_default_sign_asn1$O \
+ $(OBJDIR)$Pecdsa_default_sign_raw$O \
+ $(OBJDIR)$Pecdsa_default_vrfy_asn1$O \
+ $(OBJDIR)$Pecdsa_default_vrfy_raw$O \
+ $(OBJDIR)$Pecdsa_i15_bits$O \
+ $(OBJDIR)$Pecdsa_i15_sign_asn1$O \
+ $(OBJDIR)$Pecdsa_i15_sign_raw$O \
+ $(OBJDIR)$Pecdsa_i15_vrfy_asn1$O \
+ $(OBJDIR)$Pecdsa_i15_vrfy_raw$O \
+ $(OBJDIR)$Pecdsa_i31_bits$O \
+ $(OBJDIR)$Pecdsa_i31_sign_asn1$O \
+ $(OBJDIR)$Pecdsa_i31_sign_raw$O \
+ $(OBJDIR)$Pecdsa_i31_vrfy_asn1$O \
+ $(OBJDIR)$Pecdsa_i31_vrfy_raw$O \
+ $(OBJDIR)$Pecdsa_rta$O \
+ $(OBJDIR)$Pdig_oid$O \
+ $(OBJDIR)$Pdig_size$O \
+ $(OBJDIR)$Pghash_ctmul$O \
+ $(OBJDIR)$Pghash_ctmul32$O \
+ $(OBJDIR)$Pghash_ctmul64$O \
+ $(OBJDIR)$Pghash_pclmul$O \
+ $(OBJDIR)$Pghash_pwr8$O \
+ $(OBJDIR)$Pmd5$O \
+ $(OBJDIR)$Pmd5sha1$O \
+ $(OBJDIR)$Pmgf1$O \
+ $(OBJDIR)$Pmultihash$O \
+ $(OBJDIR)$Psha1$O \
+ $(OBJDIR)$Psha2big$O \
+ $(OBJDIR)$Psha2small$O \
+ $(OBJDIR)$Pi15_add$O \
+ $(OBJDIR)$Pi15_bitlen$O \
+ $(OBJDIR)$Pi15_decmod$O \
+ $(OBJDIR)$Pi15_decode$O \
+ $(OBJDIR)$Pi15_decred$O \
+ $(OBJDIR)$Pi15_encode$O \
+ $(OBJDIR)$Pi15_fmont$O \
+ $(OBJDIR)$Pi15_iszero$O \
+ $(OBJDIR)$Pi15_moddiv$O \
+ $(OBJDIR)$Pi15_modpow$O \
+ $(OBJDIR)$Pi15_modpow2$O \
+ $(OBJDIR)$Pi15_montmul$O \
+ $(OBJDIR)$Pi15_mulacc$O \
+ $(OBJDIR)$Pi15_muladd$O \
+ $(OBJDIR)$Pi15_ninv15$O \
+ $(OBJDIR)$Pi15_reduce$O \
+ $(OBJDIR)$Pi15_rshift$O \
+ $(OBJDIR)$Pi15_sub$O \
+ $(OBJDIR)$Pi15_tmont$O \
+ $(OBJDIR)$Pi31_add$O \
+ $(OBJDIR)$Pi31_bitlen$O \
+ $(OBJDIR)$Pi31_decmod$O \
+ $(OBJDIR)$Pi31_decode$O \
+ $(OBJDIR)$Pi31_decred$O \
+ $(OBJDIR)$Pi31_encode$O \
+ $(OBJDIR)$Pi31_fmont$O \
+ $(OBJDIR)$Pi31_iszero$O \
+ $(OBJDIR)$Pi31_moddiv$O \
+ $(OBJDIR)$Pi31_modpow$O \
+ $(OBJDIR)$Pi31_modpow2$O \
+ $(OBJDIR)$Pi31_montmul$O \
+ $(OBJDIR)$Pi31_mulacc$O \
+ $(OBJDIR)$Pi31_muladd$O \
+ $(OBJDIR)$Pi31_ninv31$O \
+ $(OBJDIR)$Pi31_reduce$O \
+ $(OBJDIR)$Pi31_rshift$O \
+ $(OBJDIR)$Pi31_sub$O \
+ $(OBJDIR)$Pi31_tmont$O \
+ $(OBJDIR)$Pi32_add$O \
+ $(OBJDIR)$Pi32_bitlen$O \
+ $(OBJDIR)$Pi32_decmod$O \
+ $(OBJDIR)$Pi32_decode$O \
+ $(OBJDIR)$Pi32_decred$O \
+ $(OBJDIR)$Pi32_div32$O \
+ $(OBJDIR)$Pi32_encode$O \
+ $(OBJDIR)$Pi32_fmont$O \
+ $(OBJDIR)$Pi32_iszero$O \
+ $(OBJDIR)$Pi32_modpow$O \
+ $(OBJDIR)$Pi32_montmul$O \
+ $(OBJDIR)$Pi32_mulacc$O \
+ $(OBJDIR)$Pi32_muladd$O \
+ $(OBJDIR)$Pi32_ninv32$O \
+ $(OBJDIR)$Pi32_reduce$O \
+ $(OBJDIR)$Pi32_sub$O \
+ $(OBJDIR)$Pi32_tmont$O \
+ $(OBJDIR)$Pi62_modpow2$O \
+ $(OBJDIR)$Phkdf$O \
+ $(OBJDIR)$Pshake$O \
+ $(OBJDIR)$Phmac$O \
+ $(OBJDIR)$Phmac_ct$O \
+ $(OBJDIR)$Paesctr_drbg$O \
+ $(OBJDIR)$Phmac_drbg$O \
+ $(OBJDIR)$Psysrng$O \
+ $(OBJDIR)$Prsa_default_keygen$O \
+ $(OBJDIR)$Prsa_default_modulus$O \
+ $(OBJDIR)$Prsa_default_oaep_decrypt$O \
+ $(OBJDIR)$Prsa_default_oaep_encrypt$O \
+ $(OBJDIR)$Prsa_default_pkcs1_sign$O \
+ $(OBJDIR)$Prsa_default_pkcs1_vrfy$O \
+ $(OBJDIR)$Prsa_default_priv$O \
+ $(OBJDIR)$Prsa_default_privexp$O \
+ $(OBJDIR)$Prsa_default_pss_sign$O \
+ $(OBJDIR)$Prsa_default_pss_vrfy$O \
+ $(OBJDIR)$Prsa_default_pub$O \
+ $(OBJDIR)$Prsa_default_pubexp$O \
+ $(OBJDIR)$Prsa_i15_keygen$O \
+ $(OBJDIR)$Prsa_i15_modulus$O \
+ $(OBJDIR)$Prsa_i15_oaep_decrypt$O \
+ $(OBJDIR)$Prsa_i15_oaep_encrypt$O \
+ $(OBJDIR)$Prsa_i15_pkcs1_sign$O \
+ $(OBJDIR)$Prsa_i15_pkcs1_vrfy$O \
+ $(OBJDIR)$Prsa_i15_priv$O \
+ $(OBJDIR)$Prsa_i15_privexp$O \
+ $(OBJDIR)$Prsa_i15_pss_sign$O \
+ $(OBJDIR)$Prsa_i15_pss_vrfy$O \
+ $(OBJDIR)$Prsa_i15_pub$O \
+ $(OBJDIR)$Prsa_i15_pubexp$O \
+ $(OBJDIR)$Prsa_i31_keygen$O \
+ $(OBJDIR)$Prsa_i31_keygen_inner$O \
+ $(OBJDIR)$Prsa_i31_modulus$O \
+ $(OBJDIR)$Prsa_i31_oaep_decrypt$O \
+ $(OBJDIR)$Prsa_i31_oaep_encrypt$O \
+ $(OBJDIR)$Prsa_i31_pkcs1_sign$O \
+ $(OBJDIR)$Prsa_i31_pkcs1_vrfy$O \
+ $(OBJDIR)$Prsa_i31_priv$O \
+ $(OBJDIR)$Prsa_i31_privexp$O \
+ $(OBJDIR)$Prsa_i31_pss_sign$O \
+ $(OBJDIR)$Prsa_i31_pss_vrfy$O \
+ $(OBJDIR)$Prsa_i31_pub$O \
+ $(OBJDIR)$Prsa_i31_pubexp$O \
+ $(OBJDIR)$Prsa_i32_oaep_decrypt$O \
+ $(OBJDIR)$Prsa_i32_oaep_encrypt$O \
+ $(OBJDIR)$Prsa_i32_pkcs1_sign$O \
+ $(OBJDIR)$Prsa_i32_pkcs1_vrfy$O \
+ $(OBJDIR)$Prsa_i32_priv$O \
+ $(OBJDIR)$Prsa_i32_pss_sign$O \
+ $(OBJDIR)$Prsa_i32_pss_vrfy$O \
+ $(OBJDIR)$Prsa_i32_pub$O \
+ $(OBJDIR)$Prsa_i62_keygen$O \
+ $(OBJDIR)$Prsa_i62_oaep_decrypt$O \
+ $(OBJDIR)$Prsa_i62_oaep_encrypt$O \
+ $(OBJDIR)$Prsa_i62_pkcs1_sign$O \
+ $(OBJDIR)$Prsa_i62_pkcs1_vrfy$O \
+ $(OBJDIR)$Prsa_i62_priv$O \
+ $(OBJDIR)$Prsa_i62_pss_sign$O \
+ $(OBJDIR)$Prsa_i62_pss_vrfy$O \
+ $(OBJDIR)$Prsa_i62_pub$O \
+ $(OBJDIR)$Prsa_oaep_pad$O \
+ $(OBJDIR)$Prsa_oaep_unpad$O \
+ $(OBJDIR)$Prsa_pkcs1_sig_pad$O \
+ $(OBJDIR)$Prsa_pkcs1_sig_unpad$O \
+ $(OBJDIR)$Prsa_pss_sig_pad$O \
+ $(OBJDIR)$Prsa_pss_sig_unpad$O \
+ $(OBJDIR)$Prsa_ssl_decrypt$O \
+ $(OBJDIR)$Pprf$O \
+ $(OBJDIR)$Pprf_md5sha1$O \
+ $(OBJDIR)$Pprf_sha256$O \
+ $(OBJDIR)$Pprf_sha384$O \
+ $(OBJDIR)$Pssl_ccert_single_ec$O \
+ $(OBJDIR)$Pssl_ccert_single_rsa$O \
+ $(OBJDIR)$Pssl_client$O \
+ $(OBJDIR)$Pssl_client_default_rsapub$O \
+ $(OBJDIR)$Pssl_client_full$O \
+ $(OBJDIR)$Pssl_engine$O \
+ $(OBJDIR)$Pssl_engine_default_aescbc$O \
+ $(OBJDIR)$Pssl_engine_default_aesccm$O \
+ $(OBJDIR)$Pssl_engine_default_aesgcm$O \
+ $(OBJDIR)$Pssl_engine_default_chapol$O \
+ $(OBJDIR)$Pssl_engine_default_descbc$O \
+ $(OBJDIR)$Pssl_engine_default_ec$O \
+ $(OBJDIR)$Pssl_engine_default_ecdsa$O \
+ $(OBJDIR)$Pssl_engine_default_rsavrfy$O \
+ $(OBJDIR)$Pssl_hashes$O \
+ $(OBJDIR)$Pssl_hs_client$O \
+ $(OBJDIR)$Pssl_hs_server$O \
+ $(OBJDIR)$Pssl_io$O \
+ $(OBJDIR)$Pssl_keyexport$O \
+ $(OBJDIR)$Pssl_lru$O \
+ $(OBJDIR)$Pssl_rec_cbc$O \
+ $(OBJDIR)$Pssl_rec_ccm$O \
+ $(OBJDIR)$Pssl_rec_chapol$O \
+ $(OBJDIR)$Pssl_rec_gcm$O \
+ $(OBJDIR)$Pssl_scert_single_ec$O \
+ $(OBJDIR)$Pssl_scert_single_rsa$O \
+ $(OBJDIR)$Pssl_server$O \
+ $(OBJDIR)$Pssl_server_full_ec$O \
+ $(OBJDIR)$Pssl_server_full_rsa$O \
+ $(OBJDIR)$Pssl_server_mine2c$O \
+ $(OBJDIR)$Pssl_server_mine2g$O \
+ $(OBJDIR)$Pssl_server_minf2c$O \
+ $(OBJDIR)$Pssl_server_minf2g$O \
+ $(OBJDIR)$Pssl_server_minr2g$O \
+ $(OBJDIR)$Pssl_server_minu2g$O \
+ $(OBJDIR)$Pssl_server_minv2g$O \
+ $(OBJDIR)$Paes_big_cbcdec$O \
+ $(OBJDIR)$Paes_big_cbcenc$O \
+ $(OBJDIR)$Paes_big_ctr$O \
+ $(OBJDIR)$Paes_big_ctrcbc$O \
+ $(OBJDIR)$Paes_big_dec$O \
+ $(OBJDIR)$Paes_big_enc$O \
+ $(OBJDIR)$Paes_common$O \
+ $(OBJDIR)$Paes_ct$O \
+ $(OBJDIR)$Paes_ct64$O \
+ $(OBJDIR)$Paes_ct64_cbcdec$O \
+ $(OBJDIR)$Paes_ct64_cbcenc$O \
+ $(OBJDIR)$Paes_ct64_ctr$O \
+ $(OBJDIR)$Paes_ct64_ctrcbc$O \
+ $(OBJDIR)$Paes_ct64_dec$O \
+ $(OBJDIR)$Paes_ct64_enc$O \
+ $(OBJDIR)$Paes_ct_cbcdec$O \
+ $(OBJDIR)$Paes_ct_cbcenc$O \
+ $(OBJDIR)$Paes_ct_ctr$O \
+ $(OBJDIR)$Paes_ct_ctrcbc$O \
+ $(OBJDIR)$Paes_ct_dec$O \
+ $(OBJDIR)$Paes_ct_enc$O \
+ $(OBJDIR)$Paes_pwr8$O \
+ $(OBJDIR)$Paes_pwr8_cbcdec$O \
+ $(OBJDIR)$Paes_pwr8_cbcenc$O \
+ $(OBJDIR)$Paes_pwr8_ctr$O \
+ $(OBJDIR)$Paes_pwr8_ctrcbc$O \
+ $(OBJDIR)$Paes_small_cbcdec$O \
+ $(OBJDIR)$Paes_small_cbcenc$O \
+ $(OBJDIR)$Paes_small_ctr$O \
+ $(OBJDIR)$Paes_small_ctrcbc$O \
+ $(OBJDIR)$Paes_small_dec$O \
+ $(OBJDIR)$Paes_small_enc$O \
+ $(OBJDIR)$Paes_x86ni$O \
+ $(OBJDIR)$Paes_x86ni_cbcdec$O \
+ $(OBJDIR)$Paes_x86ni_cbcenc$O \
+ $(OBJDIR)$Paes_x86ni_ctr$O \
+ $(OBJDIR)$Paes_x86ni_ctrcbc$O \
+ $(OBJDIR)$Pchacha20_ct$O \
+ $(OBJDIR)$Pchacha20_sse2$O \
+ $(OBJDIR)$Pdes_ct$O \
+ $(OBJDIR)$Pdes_ct_cbcdec$O \
+ $(OBJDIR)$Pdes_ct_cbcenc$O \
+ $(OBJDIR)$Pdes_support$O \
+ $(OBJDIR)$Pdes_tab$O \
+ $(OBJDIR)$Pdes_tab_cbcdec$O \
+ $(OBJDIR)$Pdes_tab_cbcenc$O \
+ $(OBJDIR)$Ppoly1305_ctmul$O \
+ $(OBJDIR)$Ppoly1305_ctmul32$O \
+ $(OBJDIR)$Ppoly1305_ctmulq$O \
+ $(OBJDIR)$Ppoly1305_i15$O \
+ $(OBJDIR)$Pasn1enc$O \
+ $(OBJDIR)$Pencode_ec_pk8der$O \
+ $(OBJDIR)$Pencode_ec_rawder$O \
+ $(OBJDIR)$Pencode_rsa_pk8der$O \
+ $(OBJDIR)$Pencode_rsa_rawder$O \
+ $(OBJDIR)$Pskey_decoder$O \
+ $(OBJDIR)$Px509_decoder$O \
+ $(OBJDIR)$Px509_knownkey$O \
+ $(OBJDIR)$Px509_minimal$O \
+ $(OBJDIR)$Px509_minimal_full$O
+OBJBRSSL = \
+ $(OBJDIR)$Pbrssl$O \
+ $(OBJDIR)$Pcerts$O \
+ $(OBJDIR)$Pchain$O \
+ $(OBJDIR)$Pclient$O \
+ $(OBJDIR)$Perrors$O \
+ $(OBJDIR)$Pfiles$O \
+ $(OBJDIR)$Pimpl$O \
+ $(OBJDIR)$Pkeys$O \
+ $(OBJDIR)$Pnames$O \
+ $(OBJDIR)$Pserver$O \
+ $(OBJDIR)$Pskey$O \
+ $(OBJDIR)$Psslio$O \
+ $(OBJDIR)$Pta$O \
+ $(OBJDIR)$Ptwrch$O \
+ $(OBJDIR)$Pvector$O \
+ $(OBJDIR)$Pverify$O \
+ $(OBJDIR)$Pxmem$O
+OBJTESTCRYPTO = \
+ $(OBJDIR)$Ptest_crypto$O
+OBJTESTSPEED = \
+ $(OBJDIR)$Ptest_speed$O
+OBJTESTX509 = \
+ $(OBJDIR)$Ptest_x509$O
+HEADERSPUB = inc$Pbearssl.h inc$Pbearssl_aead.h inc$Pbearssl_block.h inc$Pbearssl_ec.h inc$Pbearssl_hash.h inc$Pbearssl_hmac.h inc$Pbearssl_kdf.h inc$Pbearssl_pem.h inc$Pbearssl_prf.h inc$Pbearssl_rand.h inc$Pbearssl_rsa.h inc$Pbearssl_ssl.h inc$Pbearssl_x509.h
+HEADERSPRIV = $(HEADERSPUB) src$Pconfig.h src$Pinner.h
+HEADERSTOOLS = $(HEADERSPUB) tools$Pbrssl.h
+T0SRC = T0$PBlobWriter.cs T0$PCPU.cs T0$PCodeElement.cs T0$PCodeElementJump.cs T0$PCodeElementUInt.cs T0$PCodeElementUIntExpr.cs T0$PCodeElementUIntInt.cs T0$PCodeElementUIntUInt.cs T0$PConstData.cs T0$POpcode.cs T0$POpcodeCall.cs T0$POpcodeConst.cs T0$POpcodeGetLocal.cs T0$POpcodeJump.cs T0$POpcodeJumpIf.cs T0$POpcodeJumpIfNot.cs T0$POpcodeJumpUncond.cs T0$POpcodePutLocal.cs T0$POpcodeRet.cs T0$PSType.cs T0$PT0Comp.cs T0$PTPointerBase.cs T0$PTPointerBlob.cs T0$PTPointerExpr.cs T0$PTPointerNull.cs T0$PTPointerXT.cs T0$PTValue.cs T0$PWord.cs T0$PWordBuilder.cs T0$PWordData.cs T0$PWordInterpreted.cs T0$PWordNative.cs
+T0KERN =
+
+all: $(STATICLIB) $(DLL) $(TOOLS) $(TESTS)
+
+no:
+
+lib: $(BEARSSLLIB)
+
+dll: $(BEARSSLDLL)
+
+tools: $(BRSSL)
+
+tests: $(TESTCRYPTO) $(TESTSPEED) $(TESTX509)
+
+T0: kT0
+
+kT0: $(T0COMP) src$Pssl$Pssl_hs_common.t0 src$Pssl$Pssl_hs_client.t0 src$Pssl$Pssl_hs_server.t0 src$Px509$Pasn1.t0 src$Px509$Pskey_decoder.t0 src$Px509$Px509_decoder.t0 src$Px509$Px509_minimal.t0
+ $(RUNT0COMP) -o src$Pcodec$Ppemdec -r br_pem_decoder src$Pcodec$Ppemdec.t0
+ $(RUNT0COMP) -o src$Pssl$Pssl_hs_client -r br_ssl_hs_client src$Pssl$Pssl_hs_common.t0 src$Pssl$Pssl_hs_client.t0
+ $(RUNT0COMP) -o src$Pssl$Pssl_hs_server -r br_ssl_hs_server src$Pssl$Pssl_hs_common.t0 src$Pssl$Pssl_hs_server.t0
+ $(RUNT0COMP) -o src$Px509$Pskey_decoder -r br_skey_decoder src$Px509$Pasn1.t0 src$Px509$Pskey_decoder.t0
+ $(RUNT0COMP) -o src$Px509$Px509_decoder -r br_x509_decoder src$Px509$Pasn1.t0 src$Px509$Px509_decoder.t0
+ $(RUNT0COMP) -o src$Px509$Px509_minimal -r br_x509_minimal src$Px509$Pasn1.t0 src$Px509$Px509_minimal.t0
+
+$(T0COMP): $(T0SRC) $(T0KERN)
+ $(MKT0COMP)
+
+clean:
+ -$(RM) $(OBJDIR)$P*$O
+ -$(RM) $(BEARSSLLIB) $(BEARSSLDLL) $(BRSSL) $(TESTCRYPTO) $(TESTSPEED) $(TESTX509)
+
+$(OBJDIR):
+ -$(MKDIR) $(OBJDIR)
+
+$(BEARSSLLIB): $(OBJDIR) $(OBJ)
+ $(AR) $(ARFLAGS) $(AROUT)$(BEARSSLLIB) $(OBJ)
+
+$(BEARSSLDLL): $(OBJDIR) $(OBJ)
+ $(LDDLL) $(LDDLLFLAGS) $(LDDLLOUT)$(BEARSSLDLL) $(OBJ)
+
+$(BRSSL): $(BEARSSLLIB) $(OBJBRSSL)
+ $(LD) $(LDFLAGS) $(LDOUT)$(BRSSL) $(OBJBRSSL) $(BEARSSLLIB)
+
+$(TESTCRYPTO): $(BEARSSLLIB) $(OBJTESTCRYPTO)
+ $(LD) $(LDFLAGS) $(LDOUT)$(TESTCRYPTO) $(OBJTESTCRYPTO) $(BEARSSLLIB)
+
+$(TESTSPEED): $(BEARSSLLIB) $(OBJTESTSPEED)
+ $(LD) $(LDFLAGS) $(LDOUT)$(TESTSPEED) $(OBJTESTSPEED) $(BEARSSLLIB)
+
+$(TESTX509): $(BEARSSLLIB) $(OBJTESTX509)
+ $(LD) $(LDFLAGS) $(LDOUT)$(TESTX509) $(OBJTESTX509) $(BEARSSLLIB)
+
+$(OBJDIR)$Psettings$O: src$Psettings.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Psettings$O src$Psettings.c
+
+$(OBJDIR)$Pccm$O: src$Paead$Pccm.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pccm$O src$Paead$Pccm.c
+
+$(OBJDIR)$Peax$O: src$Paead$Peax.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Peax$O src$Paead$Peax.c
+
+$(OBJDIR)$Pgcm$O: src$Paead$Pgcm.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pgcm$O src$Paead$Pgcm.c
+
+$(OBJDIR)$Pccopy$O: src$Pcodec$Pccopy.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pccopy$O src$Pcodec$Pccopy.c
+
+$(OBJDIR)$Pdec16be$O: src$Pcodec$Pdec16be.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pdec16be$O src$Pcodec$Pdec16be.c
+
+$(OBJDIR)$Pdec16le$O: src$Pcodec$Pdec16le.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pdec16le$O src$Pcodec$Pdec16le.c
+
+$(OBJDIR)$Pdec32be$O: src$Pcodec$Pdec32be.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pdec32be$O src$Pcodec$Pdec32be.c
+
+$(OBJDIR)$Pdec32le$O: src$Pcodec$Pdec32le.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pdec32le$O src$Pcodec$Pdec32le.c
+
+$(OBJDIR)$Pdec64be$O: src$Pcodec$Pdec64be.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pdec64be$O src$Pcodec$Pdec64be.c
+
+$(OBJDIR)$Pdec64le$O: src$Pcodec$Pdec64le.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pdec64le$O src$Pcodec$Pdec64le.c
+
+$(OBJDIR)$Penc16be$O: src$Pcodec$Penc16be.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Penc16be$O src$Pcodec$Penc16be.c
+
+$(OBJDIR)$Penc16le$O: src$Pcodec$Penc16le.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Penc16le$O src$Pcodec$Penc16le.c
+
+$(OBJDIR)$Penc32be$O: src$Pcodec$Penc32be.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Penc32be$O src$Pcodec$Penc32be.c
+
+$(OBJDIR)$Penc32le$O: src$Pcodec$Penc32le.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Penc32le$O src$Pcodec$Penc32le.c
+
+$(OBJDIR)$Penc64be$O: src$Pcodec$Penc64be.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Penc64be$O src$Pcodec$Penc64be.c
+
+$(OBJDIR)$Penc64le$O: src$Pcodec$Penc64le.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Penc64le$O src$Pcodec$Penc64le.c
+
+$(OBJDIR)$Ppemdec$O: src$Pcodec$Ppemdec.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Ppemdec$O src$Pcodec$Ppemdec.c
+
+$(OBJDIR)$Ppemenc$O: src$Pcodec$Ppemenc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Ppemenc$O src$Pcodec$Ppemenc.c
+
+$(OBJDIR)$Pec_all_m15$O: src$Pec$Pec_all_m15.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_all_m15$O src$Pec$Pec_all_m15.c
+
+$(OBJDIR)$Pec_all_m31$O: src$Pec$Pec_all_m31.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_all_m31$O src$Pec$Pec_all_m31.c
+
+$(OBJDIR)$Pec_c25519_i15$O: src$Pec$Pec_c25519_i15.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_c25519_i15$O src$Pec$Pec_c25519_i15.c
+
+$(OBJDIR)$Pec_c25519_i31$O: src$Pec$Pec_c25519_i31.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_c25519_i31$O src$Pec$Pec_c25519_i31.c
+
+$(OBJDIR)$Pec_c25519_m15$O: src$Pec$Pec_c25519_m15.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_c25519_m15$O src$Pec$Pec_c25519_m15.c
+
+$(OBJDIR)$Pec_c25519_m31$O: src$Pec$Pec_c25519_m31.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_c25519_m31$O src$Pec$Pec_c25519_m31.c
+
+$(OBJDIR)$Pec_c25519_m62$O: src$Pec$Pec_c25519_m62.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_c25519_m62$O src$Pec$Pec_c25519_m62.c
+
+$(OBJDIR)$Pec_c25519_m64$O: src$Pec$Pec_c25519_m64.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_c25519_m64$O src$Pec$Pec_c25519_m64.c
+
+$(OBJDIR)$Pec_curve25519$O: src$Pec$Pec_curve25519.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_curve25519$O src$Pec$Pec_curve25519.c
+
+$(OBJDIR)$Pec_default$O: src$Pec$Pec_default.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_default$O src$Pec$Pec_default.c
+
+$(OBJDIR)$Pec_keygen$O: src$Pec$Pec_keygen.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_keygen$O src$Pec$Pec_keygen.c
+
+$(OBJDIR)$Pec_p256_m15$O: src$Pec$Pec_p256_m15.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_p256_m15$O src$Pec$Pec_p256_m15.c
+
+$(OBJDIR)$Pec_p256_m31$O: src$Pec$Pec_p256_m31.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_p256_m31$O src$Pec$Pec_p256_m31.c
+
+$(OBJDIR)$Pec_p256_m62$O: src$Pec$Pec_p256_m62.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_p256_m62$O src$Pec$Pec_p256_m62.c
+
+$(OBJDIR)$Pec_p256_m64$O: src$Pec$Pec_p256_m64.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_p256_m64$O src$Pec$Pec_p256_m64.c
+
+$(OBJDIR)$Pec_prime_i15$O: src$Pec$Pec_prime_i15.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_prime_i15$O src$Pec$Pec_prime_i15.c
+
+$(OBJDIR)$Pec_prime_i31$O: src$Pec$Pec_prime_i31.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_prime_i31$O src$Pec$Pec_prime_i31.c
+
+$(OBJDIR)$Pec_pubkey$O: src$Pec$Pec_pubkey.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_pubkey$O src$Pec$Pec_pubkey.c
+
+$(OBJDIR)$Pec_secp256r1$O: src$Pec$Pec_secp256r1.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_secp256r1$O src$Pec$Pec_secp256r1.c
+
+$(OBJDIR)$Pec_secp384r1$O: src$Pec$Pec_secp384r1.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_secp384r1$O src$Pec$Pec_secp384r1.c
+
+$(OBJDIR)$Pec_secp521r1$O: src$Pec$Pec_secp521r1.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pec_secp521r1$O src$Pec$Pec_secp521r1.c
+
+$(OBJDIR)$Pecdsa_atr$O: src$Pec$Pecdsa_atr.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pecdsa_atr$O src$Pec$Pecdsa_atr.c
+
+$(OBJDIR)$Pecdsa_default_sign_asn1$O: src$Pec$Pecdsa_default_sign_asn1.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pecdsa_default_sign_asn1$O src$Pec$Pecdsa_default_sign_asn1.c
+
+$(OBJDIR)$Pecdsa_default_sign_raw$O: src$Pec$Pecdsa_default_sign_raw.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pecdsa_default_sign_raw$O src$Pec$Pecdsa_default_sign_raw.c
+
+$(OBJDIR)$Pecdsa_default_vrfy_asn1$O: src$Pec$Pecdsa_default_vrfy_asn1.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pecdsa_default_vrfy_asn1$O src$Pec$Pecdsa_default_vrfy_asn1.c
+
+$(OBJDIR)$Pecdsa_default_vrfy_raw$O: src$Pec$Pecdsa_default_vrfy_raw.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pecdsa_default_vrfy_raw$O src$Pec$Pecdsa_default_vrfy_raw.c
+
+$(OBJDIR)$Pecdsa_i15_bits$O: src$Pec$Pecdsa_i15_bits.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pecdsa_i15_bits$O src$Pec$Pecdsa_i15_bits.c
+
+$(OBJDIR)$Pecdsa_i15_sign_asn1$O: src$Pec$Pecdsa_i15_sign_asn1.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pecdsa_i15_sign_asn1$O src$Pec$Pecdsa_i15_sign_asn1.c
+
+$(OBJDIR)$Pecdsa_i15_sign_raw$O: src$Pec$Pecdsa_i15_sign_raw.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pecdsa_i15_sign_raw$O src$Pec$Pecdsa_i15_sign_raw.c
+
+$(OBJDIR)$Pecdsa_i15_vrfy_asn1$O: src$Pec$Pecdsa_i15_vrfy_asn1.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pecdsa_i15_vrfy_asn1$O src$Pec$Pecdsa_i15_vrfy_asn1.c
+
+$(OBJDIR)$Pecdsa_i15_vrfy_raw$O: src$Pec$Pecdsa_i15_vrfy_raw.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pecdsa_i15_vrfy_raw$O src$Pec$Pecdsa_i15_vrfy_raw.c
+
+$(OBJDIR)$Pecdsa_i31_bits$O: src$Pec$Pecdsa_i31_bits.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pecdsa_i31_bits$O src$Pec$Pecdsa_i31_bits.c
+
+$(OBJDIR)$Pecdsa_i31_sign_asn1$O: src$Pec$Pecdsa_i31_sign_asn1.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pecdsa_i31_sign_asn1$O src$Pec$Pecdsa_i31_sign_asn1.c
+
+$(OBJDIR)$Pecdsa_i31_sign_raw$O: src$Pec$Pecdsa_i31_sign_raw.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pecdsa_i31_sign_raw$O src$Pec$Pecdsa_i31_sign_raw.c
+
+$(OBJDIR)$Pecdsa_i31_vrfy_asn1$O: src$Pec$Pecdsa_i31_vrfy_asn1.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pecdsa_i31_vrfy_asn1$O src$Pec$Pecdsa_i31_vrfy_asn1.c
+
+$(OBJDIR)$Pecdsa_i31_vrfy_raw$O: src$Pec$Pecdsa_i31_vrfy_raw.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pecdsa_i31_vrfy_raw$O src$Pec$Pecdsa_i31_vrfy_raw.c
+
+$(OBJDIR)$Pecdsa_rta$O: src$Pec$Pecdsa_rta.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pecdsa_rta$O src$Pec$Pecdsa_rta.c
+
+$(OBJDIR)$Pdig_oid$O: src$Phash$Pdig_oid.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pdig_oid$O src$Phash$Pdig_oid.c
+
+$(OBJDIR)$Pdig_size$O: src$Phash$Pdig_size.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pdig_size$O src$Phash$Pdig_size.c
+
+$(OBJDIR)$Pghash_ctmul$O: src$Phash$Pghash_ctmul.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pghash_ctmul$O src$Phash$Pghash_ctmul.c
+
+$(OBJDIR)$Pghash_ctmul32$O: src$Phash$Pghash_ctmul32.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pghash_ctmul32$O src$Phash$Pghash_ctmul32.c
+
+$(OBJDIR)$Pghash_ctmul64$O: src$Phash$Pghash_ctmul64.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pghash_ctmul64$O src$Phash$Pghash_ctmul64.c
+
+$(OBJDIR)$Pghash_pclmul$O: src$Phash$Pghash_pclmul.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pghash_pclmul$O src$Phash$Pghash_pclmul.c
+
+$(OBJDIR)$Pghash_pwr8$O: src$Phash$Pghash_pwr8.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pghash_pwr8$O src$Phash$Pghash_pwr8.c
+
+$(OBJDIR)$Pmd5$O: src$Phash$Pmd5.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pmd5$O src$Phash$Pmd5.c
+
+$(OBJDIR)$Pmd5sha1$O: src$Phash$Pmd5sha1.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pmd5sha1$O src$Phash$Pmd5sha1.c
+
+$(OBJDIR)$Pmgf1$O: src$Phash$Pmgf1.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pmgf1$O src$Phash$Pmgf1.c
+
+$(OBJDIR)$Pmultihash$O: src$Phash$Pmultihash.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pmultihash$O src$Phash$Pmultihash.c
+
+$(OBJDIR)$Psha1$O: src$Phash$Psha1.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Psha1$O src$Phash$Psha1.c
+
+$(OBJDIR)$Psha2big$O: src$Phash$Psha2big.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Psha2big$O src$Phash$Psha2big.c
+
+$(OBJDIR)$Psha2small$O: src$Phash$Psha2small.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Psha2small$O src$Phash$Psha2small.c
+
+$(OBJDIR)$Pi15_add$O: src$Pint$Pi15_add.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_add$O src$Pint$Pi15_add.c
+
+$(OBJDIR)$Pi15_bitlen$O: src$Pint$Pi15_bitlen.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_bitlen$O src$Pint$Pi15_bitlen.c
+
+$(OBJDIR)$Pi15_decmod$O: src$Pint$Pi15_decmod.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_decmod$O src$Pint$Pi15_decmod.c
+
+$(OBJDIR)$Pi15_decode$O: src$Pint$Pi15_decode.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_decode$O src$Pint$Pi15_decode.c
+
+$(OBJDIR)$Pi15_decred$O: src$Pint$Pi15_decred.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_decred$O src$Pint$Pi15_decred.c
+
+$(OBJDIR)$Pi15_encode$O: src$Pint$Pi15_encode.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_encode$O src$Pint$Pi15_encode.c
+
+$(OBJDIR)$Pi15_fmont$O: src$Pint$Pi15_fmont.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_fmont$O src$Pint$Pi15_fmont.c
+
+$(OBJDIR)$Pi15_iszero$O: src$Pint$Pi15_iszero.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_iszero$O src$Pint$Pi15_iszero.c
+
+$(OBJDIR)$Pi15_moddiv$O: src$Pint$Pi15_moddiv.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_moddiv$O src$Pint$Pi15_moddiv.c
+
+$(OBJDIR)$Pi15_modpow$O: src$Pint$Pi15_modpow.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_modpow$O src$Pint$Pi15_modpow.c
+
+$(OBJDIR)$Pi15_modpow2$O: src$Pint$Pi15_modpow2.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_modpow2$O src$Pint$Pi15_modpow2.c
+
+$(OBJDIR)$Pi15_montmul$O: src$Pint$Pi15_montmul.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_montmul$O src$Pint$Pi15_montmul.c
+
+$(OBJDIR)$Pi15_mulacc$O: src$Pint$Pi15_mulacc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_mulacc$O src$Pint$Pi15_mulacc.c
+
+$(OBJDIR)$Pi15_muladd$O: src$Pint$Pi15_muladd.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_muladd$O src$Pint$Pi15_muladd.c
+
+$(OBJDIR)$Pi15_ninv15$O: src$Pint$Pi15_ninv15.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_ninv15$O src$Pint$Pi15_ninv15.c
+
+$(OBJDIR)$Pi15_reduce$O: src$Pint$Pi15_reduce.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_reduce$O src$Pint$Pi15_reduce.c
+
+$(OBJDIR)$Pi15_rshift$O: src$Pint$Pi15_rshift.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_rshift$O src$Pint$Pi15_rshift.c
+
+$(OBJDIR)$Pi15_sub$O: src$Pint$Pi15_sub.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_sub$O src$Pint$Pi15_sub.c
+
+$(OBJDIR)$Pi15_tmont$O: src$Pint$Pi15_tmont.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi15_tmont$O src$Pint$Pi15_tmont.c
+
+$(OBJDIR)$Pi31_add$O: src$Pint$Pi31_add.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_add$O src$Pint$Pi31_add.c
+
+$(OBJDIR)$Pi31_bitlen$O: src$Pint$Pi31_bitlen.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_bitlen$O src$Pint$Pi31_bitlen.c
+
+$(OBJDIR)$Pi31_decmod$O: src$Pint$Pi31_decmod.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_decmod$O src$Pint$Pi31_decmod.c
+
+$(OBJDIR)$Pi31_decode$O: src$Pint$Pi31_decode.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_decode$O src$Pint$Pi31_decode.c
+
+$(OBJDIR)$Pi31_decred$O: src$Pint$Pi31_decred.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_decred$O src$Pint$Pi31_decred.c
+
+$(OBJDIR)$Pi31_encode$O: src$Pint$Pi31_encode.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_encode$O src$Pint$Pi31_encode.c
+
+$(OBJDIR)$Pi31_fmont$O: src$Pint$Pi31_fmont.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_fmont$O src$Pint$Pi31_fmont.c
+
+$(OBJDIR)$Pi31_iszero$O: src$Pint$Pi31_iszero.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_iszero$O src$Pint$Pi31_iszero.c
+
+$(OBJDIR)$Pi31_moddiv$O: src$Pint$Pi31_moddiv.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_moddiv$O src$Pint$Pi31_moddiv.c
+
+$(OBJDIR)$Pi31_modpow$O: src$Pint$Pi31_modpow.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_modpow$O src$Pint$Pi31_modpow.c
+
+$(OBJDIR)$Pi31_modpow2$O: src$Pint$Pi31_modpow2.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_modpow2$O src$Pint$Pi31_modpow2.c
+
+$(OBJDIR)$Pi31_montmul$O: src$Pint$Pi31_montmul.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_montmul$O src$Pint$Pi31_montmul.c
+
+$(OBJDIR)$Pi31_mulacc$O: src$Pint$Pi31_mulacc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_mulacc$O src$Pint$Pi31_mulacc.c
+
+$(OBJDIR)$Pi31_muladd$O: src$Pint$Pi31_muladd.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_muladd$O src$Pint$Pi31_muladd.c
+
+$(OBJDIR)$Pi31_ninv31$O: src$Pint$Pi31_ninv31.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_ninv31$O src$Pint$Pi31_ninv31.c
+
+$(OBJDIR)$Pi31_reduce$O: src$Pint$Pi31_reduce.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_reduce$O src$Pint$Pi31_reduce.c
+
+$(OBJDIR)$Pi31_rshift$O: src$Pint$Pi31_rshift.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_rshift$O src$Pint$Pi31_rshift.c
+
+$(OBJDIR)$Pi31_sub$O: src$Pint$Pi31_sub.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_sub$O src$Pint$Pi31_sub.c
+
+$(OBJDIR)$Pi31_tmont$O: src$Pint$Pi31_tmont.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi31_tmont$O src$Pint$Pi31_tmont.c
+
+$(OBJDIR)$Pi32_add$O: src$Pint$Pi32_add.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi32_add$O src$Pint$Pi32_add.c
+
+$(OBJDIR)$Pi32_bitlen$O: src$Pint$Pi32_bitlen.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi32_bitlen$O src$Pint$Pi32_bitlen.c
+
+$(OBJDIR)$Pi32_decmod$O: src$Pint$Pi32_decmod.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi32_decmod$O src$Pint$Pi32_decmod.c
+
+$(OBJDIR)$Pi32_decode$O: src$Pint$Pi32_decode.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi32_decode$O src$Pint$Pi32_decode.c
+
+$(OBJDIR)$Pi32_decred$O: src$Pint$Pi32_decred.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi32_decred$O src$Pint$Pi32_decred.c
+
+$(OBJDIR)$Pi32_div32$O: src$Pint$Pi32_div32.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi32_div32$O src$Pint$Pi32_div32.c
+
+$(OBJDIR)$Pi32_encode$O: src$Pint$Pi32_encode.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi32_encode$O src$Pint$Pi32_encode.c
+
+$(OBJDIR)$Pi32_fmont$O: src$Pint$Pi32_fmont.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi32_fmont$O src$Pint$Pi32_fmont.c
+
+$(OBJDIR)$Pi32_iszero$O: src$Pint$Pi32_iszero.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi32_iszero$O src$Pint$Pi32_iszero.c
+
+$(OBJDIR)$Pi32_modpow$O: src$Pint$Pi32_modpow.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi32_modpow$O src$Pint$Pi32_modpow.c
+
+$(OBJDIR)$Pi32_montmul$O: src$Pint$Pi32_montmul.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi32_montmul$O src$Pint$Pi32_montmul.c
+
+$(OBJDIR)$Pi32_mulacc$O: src$Pint$Pi32_mulacc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi32_mulacc$O src$Pint$Pi32_mulacc.c
+
+$(OBJDIR)$Pi32_muladd$O: src$Pint$Pi32_muladd.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi32_muladd$O src$Pint$Pi32_muladd.c
+
+$(OBJDIR)$Pi32_ninv32$O: src$Pint$Pi32_ninv32.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi32_ninv32$O src$Pint$Pi32_ninv32.c
+
+$(OBJDIR)$Pi32_reduce$O: src$Pint$Pi32_reduce.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi32_reduce$O src$Pint$Pi32_reduce.c
+
+$(OBJDIR)$Pi32_sub$O: src$Pint$Pi32_sub.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi32_sub$O src$Pint$Pi32_sub.c
+
+$(OBJDIR)$Pi32_tmont$O: src$Pint$Pi32_tmont.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi32_tmont$O src$Pint$Pi32_tmont.c
+
+$(OBJDIR)$Pi62_modpow2$O: src$Pint$Pi62_modpow2.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pi62_modpow2$O src$Pint$Pi62_modpow2.c
+
+$(OBJDIR)$Phkdf$O: src$Pkdf$Phkdf.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Phkdf$O src$Pkdf$Phkdf.c
+
+$(OBJDIR)$Pshake$O: src$Pkdf$Pshake.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pshake$O src$Pkdf$Pshake.c
+
+$(OBJDIR)$Phmac$O: src$Pmac$Phmac.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Phmac$O src$Pmac$Phmac.c
+
+$(OBJDIR)$Phmac_ct$O: src$Pmac$Phmac_ct.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Phmac_ct$O src$Pmac$Phmac_ct.c
+
+$(OBJDIR)$Paesctr_drbg$O: src$Prand$Paesctr_drbg.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paesctr_drbg$O src$Prand$Paesctr_drbg.c
+
+$(OBJDIR)$Phmac_drbg$O: src$Prand$Phmac_drbg.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Phmac_drbg$O src$Prand$Phmac_drbg.c
+
+$(OBJDIR)$Psysrng$O: src$Prand$Psysrng.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Psysrng$O src$Prand$Psysrng.c
+
+$(OBJDIR)$Prsa_default_keygen$O: src$Prsa$Prsa_default_keygen.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_default_keygen$O src$Prsa$Prsa_default_keygen.c
+
+$(OBJDIR)$Prsa_default_modulus$O: src$Prsa$Prsa_default_modulus.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_default_modulus$O src$Prsa$Prsa_default_modulus.c
+
+$(OBJDIR)$Prsa_default_oaep_decrypt$O: src$Prsa$Prsa_default_oaep_decrypt.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_default_oaep_decrypt$O src$Prsa$Prsa_default_oaep_decrypt.c
+
+$(OBJDIR)$Prsa_default_oaep_encrypt$O: src$Prsa$Prsa_default_oaep_encrypt.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_default_oaep_encrypt$O src$Prsa$Prsa_default_oaep_encrypt.c
+
+$(OBJDIR)$Prsa_default_pkcs1_sign$O: src$Prsa$Prsa_default_pkcs1_sign.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_default_pkcs1_sign$O src$Prsa$Prsa_default_pkcs1_sign.c
+
+$(OBJDIR)$Prsa_default_pkcs1_vrfy$O: src$Prsa$Prsa_default_pkcs1_vrfy.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_default_pkcs1_vrfy$O src$Prsa$Prsa_default_pkcs1_vrfy.c
+
+$(OBJDIR)$Prsa_default_priv$O: src$Prsa$Prsa_default_priv.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_default_priv$O src$Prsa$Prsa_default_priv.c
+
+$(OBJDIR)$Prsa_default_privexp$O: src$Prsa$Prsa_default_privexp.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_default_privexp$O src$Prsa$Prsa_default_privexp.c
+
+$(OBJDIR)$Prsa_default_pss_sign$O: src$Prsa$Prsa_default_pss_sign.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_default_pss_sign$O src$Prsa$Prsa_default_pss_sign.c
+
+$(OBJDIR)$Prsa_default_pss_vrfy$O: src$Prsa$Prsa_default_pss_vrfy.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_default_pss_vrfy$O src$Prsa$Prsa_default_pss_vrfy.c
+
+$(OBJDIR)$Prsa_default_pub$O: src$Prsa$Prsa_default_pub.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_default_pub$O src$Prsa$Prsa_default_pub.c
+
+$(OBJDIR)$Prsa_default_pubexp$O: src$Prsa$Prsa_default_pubexp.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_default_pubexp$O src$Prsa$Prsa_default_pubexp.c
+
+$(OBJDIR)$Prsa_i15_keygen$O: src$Prsa$Prsa_i15_keygen.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i15_keygen$O src$Prsa$Prsa_i15_keygen.c
+
+$(OBJDIR)$Prsa_i15_modulus$O: src$Prsa$Prsa_i15_modulus.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i15_modulus$O src$Prsa$Prsa_i15_modulus.c
+
+$(OBJDIR)$Prsa_i15_oaep_decrypt$O: src$Prsa$Prsa_i15_oaep_decrypt.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i15_oaep_decrypt$O src$Prsa$Prsa_i15_oaep_decrypt.c
+
+$(OBJDIR)$Prsa_i15_oaep_encrypt$O: src$Prsa$Prsa_i15_oaep_encrypt.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i15_oaep_encrypt$O src$Prsa$Prsa_i15_oaep_encrypt.c
+
+$(OBJDIR)$Prsa_i15_pkcs1_sign$O: src$Prsa$Prsa_i15_pkcs1_sign.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i15_pkcs1_sign$O src$Prsa$Prsa_i15_pkcs1_sign.c
+
+$(OBJDIR)$Prsa_i15_pkcs1_vrfy$O: src$Prsa$Prsa_i15_pkcs1_vrfy.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i15_pkcs1_vrfy$O src$Prsa$Prsa_i15_pkcs1_vrfy.c
+
+$(OBJDIR)$Prsa_i15_priv$O: src$Prsa$Prsa_i15_priv.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i15_priv$O src$Prsa$Prsa_i15_priv.c
+
+$(OBJDIR)$Prsa_i15_privexp$O: src$Prsa$Prsa_i15_privexp.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i15_privexp$O src$Prsa$Prsa_i15_privexp.c
+
+$(OBJDIR)$Prsa_i15_pss_sign$O: src$Prsa$Prsa_i15_pss_sign.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i15_pss_sign$O src$Prsa$Prsa_i15_pss_sign.c
+
+$(OBJDIR)$Prsa_i15_pss_vrfy$O: src$Prsa$Prsa_i15_pss_vrfy.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i15_pss_vrfy$O src$Prsa$Prsa_i15_pss_vrfy.c
+
+$(OBJDIR)$Prsa_i15_pub$O: src$Prsa$Prsa_i15_pub.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i15_pub$O src$Prsa$Prsa_i15_pub.c
+
+$(OBJDIR)$Prsa_i15_pubexp$O: src$Prsa$Prsa_i15_pubexp.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i15_pubexp$O src$Prsa$Prsa_i15_pubexp.c
+
+$(OBJDIR)$Prsa_i31_keygen$O: src$Prsa$Prsa_i31_keygen.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i31_keygen$O src$Prsa$Prsa_i31_keygen.c
+
+$(OBJDIR)$Prsa_i31_keygen_inner$O: src$Prsa$Prsa_i31_keygen_inner.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i31_keygen_inner$O src$Prsa$Prsa_i31_keygen_inner.c
+
+$(OBJDIR)$Prsa_i31_modulus$O: src$Prsa$Prsa_i31_modulus.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i31_modulus$O src$Prsa$Prsa_i31_modulus.c
+
+$(OBJDIR)$Prsa_i31_oaep_decrypt$O: src$Prsa$Prsa_i31_oaep_decrypt.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i31_oaep_decrypt$O src$Prsa$Prsa_i31_oaep_decrypt.c
+
+$(OBJDIR)$Prsa_i31_oaep_encrypt$O: src$Prsa$Prsa_i31_oaep_encrypt.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i31_oaep_encrypt$O src$Prsa$Prsa_i31_oaep_encrypt.c
+
+$(OBJDIR)$Prsa_i31_pkcs1_sign$O: src$Prsa$Prsa_i31_pkcs1_sign.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i31_pkcs1_sign$O src$Prsa$Prsa_i31_pkcs1_sign.c
+
+$(OBJDIR)$Prsa_i31_pkcs1_vrfy$O: src$Prsa$Prsa_i31_pkcs1_vrfy.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i31_pkcs1_vrfy$O src$Prsa$Prsa_i31_pkcs1_vrfy.c
+
+$(OBJDIR)$Prsa_i31_priv$O: src$Prsa$Prsa_i31_priv.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i31_priv$O src$Prsa$Prsa_i31_priv.c
+
+$(OBJDIR)$Prsa_i31_privexp$O: src$Prsa$Prsa_i31_privexp.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i31_privexp$O src$Prsa$Prsa_i31_privexp.c
+
+$(OBJDIR)$Prsa_i31_pss_sign$O: src$Prsa$Prsa_i31_pss_sign.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i31_pss_sign$O src$Prsa$Prsa_i31_pss_sign.c
+
+$(OBJDIR)$Prsa_i31_pss_vrfy$O: src$Prsa$Prsa_i31_pss_vrfy.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i31_pss_vrfy$O src$Prsa$Prsa_i31_pss_vrfy.c
+
+$(OBJDIR)$Prsa_i31_pub$O: src$Prsa$Prsa_i31_pub.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i31_pub$O src$Prsa$Prsa_i31_pub.c
+
+$(OBJDIR)$Prsa_i31_pubexp$O: src$Prsa$Prsa_i31_pubexp.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i31_pubexp$O src$Prsa$Prsa_i31_pubexp.c
+
+$(OBJDIR)$Prsa_i32_oaep_decrypt$O: src$Prsa$Prsa_i32_oaep_decrypt.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i32_oaep_decrypt$O src$Prsa$Prsa_i32_oaep_decrypt.c
+
+$(OBJDIR)$Prsa_i32_oaep_encrypt$O: src$Prsa$Prsa_i32_oaep_encrypt.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i32_oaep_encrypt$O src$Prsa$Prsa_i32_oaep_encrypt.c
+
+$(OBJDIR)$Prsa_i32_pkcs1_sign$O: src$Prsa$Prsa_i32_pkcs1_sign.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i32_pkcs1_sign$O src$Prsa$Prsa_i32_pkcs1_sign.c
+
+$(OBJDIR)$Prsa_i32_pkcs1_vrfy$O: src$Prsa$Prsa_i32_pkcs1_vrfy.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i32_pkcs1_vrfy$O src$Prsa$Prsa_i32_pkcs1_vrfy.c
+
+$(OBJDIR)$Prsa_i32_priv$O: src$Prsa$Prsa_i32_priv.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i32_priv$O src$Prsa$Prsa_i32_priv.c
+
+$(OBJDIR)$Prsa_i32_pss_sign$O: src$Prsa$Prsa_i32_pss_sign.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i32_pss_sign$O src$Prsa$Prsa_i32_pss_sign.c
+
+$(OBJDIR)$Prsa_i32_pss_vrfy$O: src$Prsa$Prsa_i32_pss_vrfy.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i32_pss_vrfy$O src$Prsa$Prsa_i32_pss_vrfy.c
+
+$(OBJDIR)$Prsa_i32_pub$O: src$Prsa$Prsa_i32_pub.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i32_pub$O src$Prsa$Prsa_i32_pub.c
+
+$(OBJDIR)$Prsa_i62_keygen$O: src$Prsa$Prsa_i62_keygen.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i62_keygen$O src$Prsa$Prsa_i62_keygen.c
+
+$(OBJDIR)$Prsa_i62_oaep_decrypt$O: src$Prsa$Prsa_i62_oaep_decrypt.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i62_oaep_decrypt$O src$Prsa$Prsa_i62_oaep_decrypt.c
+
+$(OBJDIR)$Prsa_i62_oaep_encrypt$O: src$Prsa$Prsa_i62_oaep_encrypt.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i62_oaep_encrypt$O src$Prsa$Prsa_i62_oaep_encrypt.c
+
+$(OBJDIR)$Prsa_i62_pkcs1_sign$O: src$Prsa$Prsa_i62_pkcs1_sign.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i62_pkcs1_sign$O src$Prsa$Prsa_i62_pkcs1_sign.c
+
+$(OBJDIR)$Prsa_i62_pkcs1_vrfy$O: src$Prsa$Prsa_i62_pkcs1_vrfy.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i62_pkcs1_vrfy$O src$Prsa$Prsa_i62_pkcs1_vrfy.c
+
+$(OBJDIR)$Prsa_i62_priv$O: src$Prsa$Prsa_i62_priv.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i62_priv$O src$Prsa$Prsa_i62_priv.c
+
+$(OBJDIR)$Prsa_i62_pss_sign$O: src$Prsa$Prsa_i62_pss_sign.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i62_pss_sign$O src$Prsa$Prsa_i62_pss_sign.c
+
+$(OBJDIR)$Prsa_i62_pss_vrfy$O: src$Prsa$Prsa_i62_pss_vrfy.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i62_pss_vrfy$O src$Prsa$Prsa_i62_pss_vrfy.c
+
+$(OBJDIR)$Prsa_i62_pub$O: src$Prsa$Prsa_i62_pub.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_i62_pub$O src$Prsa$Prsa_i62_pub.c
+
+$(OBJDIR)$Prsa_oaep_pad$O: src$Prsa$Prsa_oaep_pad.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_oaep_pad$O src$Prsa$Prsa_oaep_pad.c
+
+$(OBJDIR)$Prsa_oaep_unpad$O: src$Prsa$Prsa_oaep_unpad.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_oaep_unpad$O src$Prsa$Prsa_oaep_unpad.c
+
+$(OBJDIR)$Prsa_pkcs1_sig_pad$O: src$Prsa$Prsa_pkcs1_sig_pad.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_pkcs1_sig_pad$O src$Prsa$Prsa_pkcs1_sig_pad.c
+
+$(OBJDIR)$Prsa_pkcs1_sig_unpad$O: src$Prsa$Prsa_pkcs1_sig_unpad.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_pkcs1_sig_unpad$O src$Prsa$Prsa_pkcs1_sig_unpad.c
+
+$(OBJDIR)$Prsa_pss_sig_pad$O: src$Prsa$Prsa_pss_sig_pad.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_pss_sig_pad$O src$Prsa$Prsa_pss_sig_pad.c
+
+$(OBJDIR)$Prsa_pss_sig_unpad$O: src$Prsa$Prsa_pss_sig_unpad.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_pss_sig_unpad$O src$Prsa$Prsa_pss_sig_unpad.c
+
+$(OBJDIR)$Prsa_ssl_decrypt$O: src$Prsa$Prsa_ssl_decrypt.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Prsa_ssl_decrypt$O src$Prsa$Prsa_ssl_decrypt.c
+
+$(OBJDIR)$Pprf$O: src$Pssl$Pprf.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pprf$O src$Pssl$Pprf.c
+
+$(OBJDIR)$Pprf_md5sha1$O: src$Pssl$Pprf_md5sha1.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pprf_md5sha1$O src$Pssl$Pprf_md5sha1.c
+
+$(OBJDIR)$Pprf_sha256$O: src$Pssl$Pprf_sha256.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pprf_sha256$O src$Pssl$Pprf_sha256.c
+
+$(OBJDIR)$Pprf_sha384$O: src$Pssl$Pprf_sha384.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pprf_sha384$O src$Pssl$Pprf_sha384.c
+
+$(OBJDIR)$Pssl_ccert_single_ec$O: src$Pssl$Pssl_ccert_single_ec.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_ccert_single_ec$O src$Pssl$Pssl_ccert_single_ec.c
+
+$(OBJDIR)$Pssl_ccert_single_rsa$O: src$Pssl$Pssl_ccert_single_rsa.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_ccert_single_rsa$O src$Pssl$Pssl_ccert_single_rsa.c
+
+$(OBJDIR)$Pssl_client$O: src$Pssl$Pssl_client.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_client$O src$Pssl$Pssl_client.c
+
+$(OBJDIR)$Pssl_client_default_rsapub$O: src$Pssl$Pssl_client_default_rsapub.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_client_default_rsapub$O src$Pssl$Pssl_client_default_rsapub.c
+
+$(OBJDIR)$Pssl_client_full$O: src$Pssl$Pssl_client_full.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_client_full$O src$Pssl$Pssl_client_full.c
+
+$(OBJDIR)$Pssl_engine$O: src$Pssl$Pssl_engine.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_engine$O src$Pssl$Pssl_engine.c
+
+$(OBJDIR)$Pssl_engine_default_aescbc$O: src$Pssl$Pssl_engine_default_aescbc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_engine_default_aescbc$O src$Pssl$Pssl_engine_default_aescbc.c
+
+$(OBJDIR)$Pssl_engine_default_aesccm$O: src$Pssl$Pssl_engine_default_aesccm.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_engine_default_aesccm$O src$Pssl$Pssl_engine_default_aesccm.c
+
+$(OBJDIR)$Pssl_engine_default_aesgcm$O: src$Pssl$Pssl_engine_default_aesgcm.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_engine_default_aesgcm$O src$Pssl$Pssl_engine_default_aesgcm.c
+
+$(OBJDIR)$Pssl_engine_default_chapol$O: src$Pssl$Pssl_engine_default_chapol.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_engine_default_chapol$O src$Pssl$Pssl_engine_default_chapol.c
+
+$(OBJDIR)$Pssl_engine_default_descbc$O: src$Pssl$Pssl_engine_default_descbc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_engine_default_descbc$O src$Pssl$Pssl_engine_default_descbc.c
+
+$(OBJDIR)$Pssl_engine_default_ec$O: src$Pssl$Pssl_engine_default_ec.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_engine_default_ec$O src$Pssl$Pssl_engine_default_ec.c
+
+$(OBJDIR)$Pssl_engine_default_ecdsa$O: src$Pssl$Pssl_engine_default_ecdsa.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_engine_default_ecdsa$O src$Pssl$Pssl_engine_default_ecdsa.c
+
+$(OBJDIR)$Pssl_engine_default_rsavrfy$O: src$Pssl$Pssl_engine_default_rsavrfy.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_engine_default_rsavrfy$O src$Pssl$Pssl_engine_default_rsavrfy.c
+
+$(OBJDIR)$Pssl_hashes$O: src$Pssl$Pssl_hashes.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_hashes$O src$Pssl$Pssl_hashes.c
+
+$(OBJDIR)$Pssl_hs_client$O: src$Pssl$Pssl_hs_client.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_hs_client$O src$Pssl$Pssl_hs_client.c
+
+$(OBJDIR)$Pssl_hs_server$O: src$Pssl$Pssl_hs_server.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_hs_server$O src$Pssl$Pssl_hs_server.c
+
+$(OBJDIR)$Pssl_io$O: src$Pssl$Pssl_io.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_io$O src$Pssl$Pssl_io.c
+
+$(OBJDIR)$Pssl_keyexport$O: src$Pssl$Pssl_keyexport.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_keyexport$O src$Pssl$Pssl_keyexport.c
+
+$(OBJDIR)$Pssl_lru$O: src$Pssl$Pssl_lru.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_lru$O src$Pssl$Pssl_lru.c
+
+$(OBJDIR)$Pssl_rec_cbc$O: src$Pssl$Pssl_rec_cbc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_rec_cbc$O src$Pssl$Pssl_rec_cbc.c
+
+$(OBJDIR)$Pssl_rec_ccm$O: src$Pssl$Pssl_rec_ccm.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_rec_ccm$O src$Pssl$Pssl_rec_ccm.c
+
+$(OBJDIR)$Pssl_rec_chapol$O: src$Pssl$Pssl_rec_chapol.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_rec_chapol$O src$Pssl$Pssl_rec_chapol.c
+
+$(OBJDIR)$Pssl_rec_gcm$O: src$Pssl$Pssl_rec_gcm.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_rec_gcm$O src$Pssl$Pssl_rec_gcm.c
+
+$(OBJDIR)$Pssl_scert_single_ec$O: src$Pssl$Pssl_scert_single_ec.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_scert_single_ec$O src$Pssl$Pssl_scert_single_ec.c
+
+$(OBJDIR)$Pssl_scert_single_rsa$O: src$Pssl$Pssl_scert_single_rsa.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_scert_single_rsa$O src$Pssl$Pssl_scert_single_rsa.c
+
+$(OBJDIR)$Pssl_server$O: src$Pssl$Pssl_server.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_server$O src$Pssl$Pssl_server.c
+
+$(OBJDIR)$Pssl_server_full_ec$O: src$Pssl$Pssl_server_full_ec.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_server_full_ec$O src$Pssl$Pssl_server_full_ec.c
+
+$(OBJDIR)$Pssl_server_full_rsa$O: src$Pssl$Pssl_server_full_rsa.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_server_full_rsa$O src$Pssl$Pssl_server_full_rsa.c
+
+$(OBJDIR)$Pssl_server_mine2c$O: src$Pssl$Pssl_server_mine2c.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_server_mine2c$O src$Pssl$Pssl_server_mine2c.c
+
+$(OBJDIR)$Pssl_server_mine2g$O: src$Pssl$Pssl_server_mine2g.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_server_mine2g$O src$Pssl$Pssl_server_mine2g.c
+
+$(OBJDIR)$Pssl_server_minf2c$O: src$Pssl$Pssl_server_minf2c.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_server_minf2c$O src$Pssl$Pssl_server_minf2c.c
+
+$(OBJDIR)$Pssl_server_minf2g$O: src$Pssl$Pssl_server_minf2g.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_server_minf2g$O src$Pssl$Pssl_server_minf2g.c
+
+$(OBJDIR)$Pssl_server_minr2g$O: src$Pssl$Pssl_server_minr2g.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_server_minr2g$O src$Pssl$Pssl_server_minr2g.c
+
+$(OBJDIR)$Pssl_server_minu2g$O: src$Pssl$Pssl_server_minu2g.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_server_minu2g$O src$Pssl$Pssl_server_minu2g.c
+
+$(OBJDIR)$Pssl_server_minv2g$O: src$Pssl$Pssl_server_minv2g.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pssl_server_minv2g$O src$Pssl$Pssl_server_minv2g.c
+
+$(OBJDIR)$Paes_big_cbcdec$O: src$Psymcipher$Paes_big_cbcdec.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_big_cbcdec$O src$Psymcipher$Paes_big_cbcdec.c
+
+$(OBJDIR)$Paes_big_cbcenc$O: src$Psymcipher$Paes_big_cbcenc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_big_cbcenc$O src$Psymcipher$Paes_big_cbcenc.c
+
+$(OBJDIR)$Paes_big_ctr$O: src$Psymcipher$Paes_big_ctr.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_big_ctr$O src$Psymcipher$Paes_big_ctr.c
+
+$(OBJDIR)$Paes_big_ctrcbc$O: src$Psymcipher$Paes_big_ctrcbc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_big_ctrcbc$O src$Psymcipher$Paes_big_ctrcbc.c
+
+$(OBJDIR)$Paes_big_dec$O: src$Psymcipher$Paes_big_dec.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_big_dec$O src$Psymcipher$Paes_big_dec.c
+
+$(OBJDIR)$Paes_big_enc$O: src$Psymcipher$Paes_big_enc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_big_enc$O src$Psymcipher$Paes_big_enc.c
+
+$(OBJDIR)$Paes_common$O: src$Psymcipher$Paes_common.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_common$O src$Psymcipher$Paes_common.c
+
+$(OBJDIR)$Paes_ct$O: src$Psymcipher$Paes_ct.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_ct$O src$Psymcipher$Paes_ct.c
+
+$(OBJDIR)$Paes_ct64$O: src$Psymcipher$Paes_ct64.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_ct64$O src$Psymcipher$Paes_ct64.c
+
+$(OBJDIR)$Paes_ct64_cbcdec$O: src$Psymcipher$Paes_ct64_cbcdec.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_ct64_cbcdec$O src$Psymcipher$Paes_ct64_cbcdec.c
+
+$(OBJDIR)$Paes_ct64_cbcenc$O: src$Psymcipher$Paes_ct64_cbcenc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_ct64_cbcenc$O src$Psymcipher$Paes_ct64_cbcenc.c
+
+$(OBJDIR)$Paes_ct64_ctr$O: src$Psymcipher$Paes_ct64_ctr.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_ct64_ctr$O src$Psymcipher$Paes_ct64_ctr.c
+
+$(OBJDIR)$Paes_ct64_ctrcbc$O: src$Psymcipher$Paes_ct64_ctrcbc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_ct64_ctrcbc$O src$Psymcipher$Paes_ct64_ctrcbc.c
+
+$(OBJDIR)$Paes_ct64_dec$O: src$Psymcipher$Paes_ct64_dec.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_ct64_dec$O src$Psymcipher$Paes_ct64_dec.c
+
+$(OBJDIR)$Paes_ct64_enc$O: src$Psymcipher$Paes_ct64_enc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_ct64_enc$O src$Psymcipher$Paes_ct64_enc.c
+
+$(OBJDIR)$Paes_ct_cbcdec$O: src$Psymcipher$Paes_ct_cbcdec.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_ct_cbcdec$O src$Psymcipher$Paes_ct_cbcdec.c
+
+$(OBJDIR)$Paes_ct_cbcenc$O: src$Psymcipher$Paes_ct_cbcenc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_ct_cbcenc$O src$Psymcipher$Paes_ct_cbcenc.c
+
+$(OBJDIR)$Paes_ct_ctr$O: src$Psymcipher$Paes_ct_ctr.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_ct_ctr$O src$Psymcipher$Paes_ct_ctr.c
+
+$(OBJDIR)$Paes_ct_ctrcbc$O: src$Psymcipher$Paes_ct_ctrcbc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_ct_ctrcbc$O src$Psymcipher$Paes_ct_ctrcbc.c
+
+$(OBJDIR)$Paes_ct_dec$O: src$Psymcipher$Paes_ct_dec.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_ct_dec$O src$Psymcipher$Paes_ct_dec.c
+
+$(OBJDIR)$Paes_ct_enc$O: src$Psymcipher$Paes_ct_enc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_ct_enc$O src$Psymcipher$Paes_ct_enc.c
+
+$(OBJDIR)$Paes_pwr8$O: src$Psymcipher$Paes_pwr8.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_pwr8$O src$Psymcipher$Paes_pwr8.c
+
+$(OBJDIR)$Paes_pwr8_cbcdec$O: src$Psymcipher$Paes_pwr8_cbcdec.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_pwr8_cbcdec$O src$Psymcipher$Paes_pwr8_cbcdec.c
+
+$(OBJDIR)$Paes_pwr8_cbcenc$O: src$Psymcipher$Paes_pwr8_cbcenc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_pwr8_cbcenc$O src$Psymcipher$Paes_pwr8_cbcenc.c
+
+$(OBJDIR)$Paes_pwr8_ctr$O: src$Psymcipher$Paes_pwr8_ctr.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_pwr8_ctr$O src$Psymcipher$Paes_pwr8_ctr.c
+
+$(OBJDIR)$Paes_pwr8_ctrcbc$O: src$Psymcipher$Paes_pwr8_ctrcbc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_pwr8_ctrcbc$O src$Psymcipher$Paes_pwr8_ctrcbc.c
+
+$(OBJDIR)$Paes_small_cbcdec$O: src$Psymcipher$Paes_small_cbcdec.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_small_cbcdec$O src$Psymcipher$Paes_small_cbcdec.c
+
+$(OBJDIR)$Paes_small_cbcenc$O: src$Psymcipher$Paes_small_cbcenc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_small_cbcenc$O src$Psymcipher$Paes_small_cbcenc.c
+
+$(OBJDIR)$Paes_small_ctr$O: src$Psymcipher$Paes_small_ctr.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_small_ctr$O src$Psymcipher$Paes_small_ctr.c
+
+$(OBJDIR)$Paes_small_ctrcbc$O: src$Psymcipher$Paes_small_ctrcbc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_small_ctrcbc$O src$Psymcipher$Paes_small_ctrcbc.c
+
+$(OBJDIR)$Paes_small_dec$O: src$Psymcipher$Paes_small_dec.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_small_dec$O src$Psymcipher$Paes_small_dec.c
+
+$(OBJDIR)$Paes_small_enc$O: src$Psymcipher$Paes_small_enc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_small_enc$O src$Psymcipher$Paes_small_enc.c
+
+$(OBJDIR)$Paes_x86ni$O: src$Psymcipher$Paes_x86ni.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_x86ni$O src$Psymcipher$Paes_x86ni.c
+
+$(OBJDIR)$Paes_x86ni_cbcdec$O: src$Psymcipher$Paes_x86ni_cbcdec.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_x86ni_cbcdec$O src$Psymcipher$Paes_x86ni_cbcdec.c
+
+$(OBJDIR)$Paes_x86ni_cbcenc$O: src$Psymcipher$Paes_x86ni_cbcenc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_x86ni_cbcenc$O src$Psymcipher$Paes_x86ni_cbcenc.c
+
+$(OBJDIR)$Paes_x86ni_ctr$O: src$Psymcipher$Paes_x86ni_ctr.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_x86ni_ctr$O src$Psymcipher$Paes_x86ni_ctr.c
+
+$(OBJDIR)$Paes_x86ni_ctrcbc$O: src$Psymcipher$Paes_x86ni_ctrcbc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Paes_x86ni_ctrcbc$O src$Psymcipher$Paes_x86ni_ctrcbc.c
+
+$(OBJDIR)$Pchacha20_ct$O: src$Psymcipher$Pchacha20_ct.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pchacha20_ct$O src$Psymcipher$Pchacha20_ct.c
+
+$(OBJDIR)$Pchacha20_sse2$O: src$Psymcipher$Pchacha20_sse2.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pchacha20_sse2$O src$Psymcipher$Pchacha20_sse2.c
+
+$(OBJDIR)$Pdes_ct$O: src$Psymcipher$Pdes_ct.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pdes_ct$O src$Psymcipher$Pdes_ct.c
+
+$(OBJDIR)$Pdes_ct_cbcdec$O: src$Psymcipher$Pdes_ct_cbcdec.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pdes_ct_cbcdec$O src$Psymcipher$Pdes_ct_cbcdec.c
+
+$(OBJDIR)$Pdes_ct_cbcenc$O: src$Psymcipher$Pdes_ct_cbcenc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pdes_ct_cbcenc$O src$Psymcipher$Pdes_ct_cbcenc.c
+
+$(OBJDIR)$Pdes_support$O: src$Psymcipher$Pdes_support.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pdes_support$O src$Psymcipher$Pdes_support.c
+
+$(OBJDIR)$Pdes_tab$O: src$Psymcipher$Pdes_tab.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pdes_tab$O src$Psymcipher$Pdes_tab.c
+
+$(OBJDIR)$Pdes_tab_cbcdec$O: src$Psymcipher$Pdes_tab_cbcdec.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pdes_tab_cbcdec$O src$Psymcipher$Pdes_tab_cbcdec.c
+
+$(OBJDIR)$Pdes_tab_cbcenc$O: src$Psymcipher$Pdes_tab_cbcenc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pdes_tab_cbcenc$O src$Psymcipher$Pdes_tab_cbcenc.c
+
+$(OBJDIR)$Ppoly1305_ctmul$O: src$Psymcipher$Ppoly1305_ctmul.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Ppoly1305_ctmul$O src$Psymcipher$Ppoly1305_ctmul.c
+
+$(OBJDIR)$Ppoly1305_ctmul32$O: src$Psymcipher$Ppoly1305_ctmul32.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Ppoly1305_ctmul32$O src$Psymcipher$Ppoly1305_ctmul32.c
+
+$(OBJDIR)$Ppoly1305_ctmulq$O: src$Psymcipher$Ppoly1305_ctmulq.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Ppoly1305_ctmulq$O src$Psymcipher$Ppoly1305_ctmulq.c
+
+$(OBJDIR)$Ppoly1305_i15$O: src$Psymcipher$Ppoly1305_i15.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Ppoly1305_i15$O src$Psymcipher$Ppoly1305_i15.c
+
+$(OBJDIR)$Pasn1enc$O: src$Px509$Pasn1enc.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pasn1enc$O src$Px509$Pasn1enc.c
+
+$(OBJDIR)$Pencode_ec_pk8der$O: src$Px509$Pencode_ec_pk8der.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pencode_ec_pk8der$O src$Px509$Pencode_ec_pk8der.c
+
+$(OBJDIR)$Pencode_ec_rawder$O: src$Px509$Pencode_ec_rawder.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pencode_ec_rawder$O src$Px509$Pencode_ec_rawder.c
+
+$(OBJDIR)$Pencode_rsa_pk8der$O: src$Px509$Pencode_rsa_pk8der.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pencode_rsa_pk8der$O src$Px509$Pencode_rsa_pk8der.c
+
+$(OBJDIR)$Pencode_rsa_rawder$O: src$Px509$Pencode_rsa_rawder.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pencode_rsa_rawder$O src$Px509$Pencode_rsa_rawder.c
+
+$(OBJDIR)$Pskey_decoder$O: src$Px509$Pskey_decoder.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pskey_decoder$O src$Px509$Pskey_decoder.c
+
+$(OBJDIR)$Px509_decoder$O: src$Px509$Px509_decoder.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Px509_decoder$O src$Px509$Px509_decoder.c
+
+$(OBJDIR)$Px509_knownkey$O: src$Px509$Px509_knownkey.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Px509_knownkey$O src$Px509$Px509_knownkey.c
+
+$(OBJDIR)$Px509_minimal$O: src$Px509$Px509_minimal.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Px509_minimal$O src$Px509$Px509_minimal.c
+
+$(OBJDIR)$Px509_minimal_full$O: src$Px509$Px509_minimal_full.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Px509_minimal_full$O src$Px509$Px509_minimal_full.c
+
+$(OBJDIR)$Pbrssl$O: tools$Pbrssl.c $(HEADERSTOOLS)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pbrssl$O tools$Pbrssl.c
+
+$(OBJDIR)$Pcerts$O: tools$Pcerts.c $(HEADERSTOOLS)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pcerts$O tools$Pcerts.c
+
+$(OBJDIR)$Pchain$O: tools$Pchain.c $(HEADERSTOOLS)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pchain$O tools$Pchain.c
+
+$(OBJDIR)$Pclient$O: tools$Pclient.c $(HEADERSTOOLS)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pclient$O tools$Pclient.c
+
+$(OBJDIR)$Perrors$O: tools$Perrors.c $(HEADERSTOOLS)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Perrors$O tools$Perrors.c
+
+$(OBJDIR)$Pfiles$O: tools$Pfiles.c $(HEADERSTOOLS)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pfiles$O tools$Pfiles.c
+
+$(OBJDIR)$Pimpl$O: tools$Pimpl.c $(HEADERSTOOLS)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pimpl$O tools$Pimpl.c
+
+$(OBJDIR)$Pkeys$O: tools$Pkeys.c $(HEADERSTOOLS)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pkeys$O tools$Pkeys.c
+
+$(OBJDIR)$Pnames$O: tools$Pnames.c $(HEADERSTOOLS)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pnames$O tools$Pnames.c
+
+$(OBJDIR)$Pserver$O: tools$Pserver.c $(HEADERSTOOLS)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pserver$O tools$Pserver.c
+
+$(OBJDIR)$Pskey$O: tools$Pskey.c $(HEADERSTOOLS)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pskey$O tools$Pskey.c
+
+$(OBJDIR)$Psslio$O: tools$Psslio.c $(HEADERSTOOLS)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Psslio$O tools$Psslio.c
+
+$(OBJDIR)$Pta$O: tools$Pta.c $(HEADERSTOOLS)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pta$O tools$Pta.c
+
+$(OBJDIR)$Ptwrch$O: tools$Ptwrch.c $(HEADERSTOOLS)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Ptwrch$O tools$Ptwrch.c
+
+$(OBJDIR)$Pvector$O: tools$Pvector.c $(HEADERSTOOLS)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pvector$O tools$Pvector.c
+
+$(OBJDIR)$Pverify$O: tools$Pverify.c $(HEADERSTOOLS)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pverify$O tools$Pverify.c
+
+$(OBJDIR)$Pxmem$O: tools$Pxmem.c $(HEADERSTOOLS)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Pxmem$O tools$Pxmem.c
+
+$(OBJDIR)$Ptest_crypto$O: test$Ptest_crypto.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Ptest_crypto$O test$Ptest_crypto.c
+
+$(OBJDIR)$Ptest_speed$O: test$Ptest_speed.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$Ptest_speed$O test$Ptest_speed.c
+
+$(OBJDIR)$Ptest_x509$O: test$Ptest_x509.c $(HEADERSPRIV)
+ $(CC) $(CFLAGS) $(INCFLAGS) -DSRCDIRNAME=".." $(CCOUT)$(OBJDIR)$Ptest_x509$O test$Ptest_x509.c
diff --git a/contrib/bearssl/mk/SingleUnix.mk b/contrib/bearssl/mk/SingleUnix.mk
new file mode 100644
index 000000000000..e169617b5b8e
--- /dev/null
+++ b/contrib/bearssl/mk/SingleUnix.mk
@@ -0,0 +1,38 @@
+# Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+
+# ======================================================================
+
+# This file sets variables for use with a SingleUnix-compatible 'make'
+# utility.
+
+# Load generic default.
+include mk/Defaults.mk
+
+# Path separator.
+P = /
+
+# Default configuration is 'Unix' (native build on a Unix-like system).
+CONF = Unix
+
+include conf/$(CONF).mk
+include mk/Rules.mk
diff --git a/contrib/bearssl/mk/mkT0.cmd b/contrib/bearssl/mk/mkT0.cmd
new file mode 100644
index 000000000000..98955625b9e3
--- /dev/null
+++ b/contrib/bearssl/mk/mkT0.cmd
@@ -0,0 +1,32 @@
+@echo off
+
+rem =====================================================================
+rem This script uses the command-line C# compiler csc.exe, which is
+rem provided with the .NET framework. We need framework 3.5 or later
+rem (some of the code uses features not available in the language version
+rem implemented in the compiler provided with framework 2.0.50727).
+rem =====================================================================
+
+if exist "%SystemRoot%\Microsoft.NET\Framework\v3.5\csc.exe" (
+ set CSC="%SystemRoot%\Microsoft.NET\Framework\v3.5\csc.exe"
+ goto do_compile
+)
+if exist "%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\csc.exe" (
+ set CSC="%SystemRoot%\Microsoft.NET\Framework\v4.0.30319\csc.exe"
+ goto do_compile
+)
+if exist "%SystemRoot%\Microsoft.NET\Framework64\v3.5\csc.exe" (
+ set CSC="%SystemRoot%\Microsoft.NET\Framework64\v3.5\csc.exe"
+ goto do_compile
+)
+if exist "%SystemRoot%\Microsoft.NET\Framework64\v4.0.30319\csc.exe" (
+ set CSC="%SystemRoot%\Microsoft.NET\Framework64\v4.0.30319\csc.exe"
+ goto do_compile
+)
+
+echo C# compiler not found
+exit 1
+
+:do_compile
+%CSC% /nologo /out:T0Comp.exe /main:T0Comp /res:T0\kern.t0,t0-kernel T0\*.cs
+if %errorlevel% neq 0 exit /b %errorlevel%
diff --git a/contrib/bearssl/mk/mkT0.sh b/contrib/bearssl/mk/mkT0.sh
new file mode 100755
index 000000000000..61de5c6e63c5
--- /dev/null
+++ b/contrib/bearssl/mk/mkT0.sh
@@ -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
diff --git a/contrib/bearssl/mk/mkrules.sh b/contrib/bearssl/mk/mkrules.sh
new file mode 100755
index 000000000000..297a5d5bb73e
--- /dev/null
+++ b/contrib/bearssl/mk/mkrules.sh
@@ -0,0 +1,570 @@
+#! /bin/sh
+
+# ========================================================================
+#
+# Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+#
+# Permission is hereby granted, free of charge, to any person obtaining
+# a copy of this software and associated documentation files (the
+# "Software"), to deal in the Software without restriction, including
+# without limitation the rights to use, copy, modify, merge, publish,
+# distribute, sublicense, and/or sell copies of the Software, and to
+# permit persons to whom the Software is furnished to do so, subject to
+# the following conditions:
+#
+# The above copyright notice and this permission notice shall be
+# included in all copies or substantial portions of the Software.
+#
+# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+# EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+# MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+# NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+# BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+# ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+# CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+# SOFTWARE.
+#
+# ========================================================================
+#
+# This script is used to generate the 'Rules.mk' file from the list
+# of source file included below. If the list changes (e.g. to add a
+# new source file), then add it here and rerun this script.
+#
+# ========================================================================
+
+# Solaris compatibility: switch to a more POSIX-compliant /bin/sh.
+if [ -z "$BR_SCRIPT_LOOP" ] ; then
+ BR_SCRIPT_LOOP=yes
+ export BR_SCRIPT_LOOP
+ if [ -x /usr/xpg6/bin/sh ] ; then
+ exec /usr/xpg6/bin/sh "$0" "$@"
+ fi
+ if [ -x /usr/xpg4/bin/sh ] ; then
+ exec /usr/xpg4/bin/sh "$0" "$@"
+ fi
+fi
+
+# Exit on first error.
+set -e
+
+# Source files. Please keep in alphabetical order.
+coresrc=" \
+ src/settings.c \
+ src/aead/ccm.c \
+ src/aead/eax.c \
+ src/aead/gcm.c \
+ src/codec/ccopy.c \
+ src/codec/dec16be.c \
+ src/codec/dec16le.c \
+ src/codec/dec32be.c \
+ src/codec/dec32le.c \
+ src/codec/dec64be.c \
+ src/codec/dec64le.c \
+ src/codec/enc16be.c \
+ src/codec/enc16le.c \
+ src/codec/enc32be.c \
+ src/codec/enc32le.c \
+ src/codec/enc64be.c \
+ src/codec/enc64le.c \
+ src/codec/pemdec.c \
+ src/codec/pemenc.c \
+ src/ec/ec_all_m15.c \
+ src/ec/ec_all_m31.c \
+ src/ec/ec_c25519_i15.c \
+ src/ec/ec_c25519_i31.c \
+ src/ec/ec_c25519_m15.c \
+ src/ec/ec_c25519_m31.c \
+ src/ec/ec_c25519_m62.c \
+ src/ec/ec_c25519_m64.c \
+ src/ec/ec_curve25519.c \
+ src/ec/ec_default.c \
+ src/ec/ec_keygen.c \
+ src/ec/ec_p256_m15.c \
+ src/ec/ec_p256_m31.c \
+ src/ec/ec_p256_m62.c \
+ src/ec/ec_p256_m64.c \
+ src/ec/ec_prime_i15.c \
+ src/ec/ec_prime_i31.c \
+ src/ec/ec_pubkey.c \
+ src/ec/ec_secp256r1.c \
+ src/ec/ec_secp384r1.c \
+ src/ec/ec_secp521r1.c \
+ src/ec/ecdsa_atr.c \
+ src/ec/ecdsa_default_sign_asn1.c \
+ src/ec/ecdsa_default_sign_raw.c \
+ src/ec/ecdsa_default_vrfy_asn1.c \
+ src/ec/ecdsa_default_vrfy_raw.c \
+ src/ec/ecdsa_i15_bits.c \
+ src/ec/ecdsa_i15_sign_asn1.c \
+ src/ec/ecdsa_i15_sign_raw.c \
+ src/ec/ecdsa_i15_vrfy_asn1.c \
+ src/ec/ecdsa_i15_vrfy_raw.c \
+ src/ec/ecdsa_i31_bits.c \
+ src/ec/ecdsa_i31_sign_asn1.c \
+ src/ec/ecdsa_i31_sign_raw.c \
+ src/ec/ecdsa_i31_vrfy_asn1.c \
+ src/ec/ecdsa_i31_vrfy_raw.c \
+ src/ec/ecdsa_rta.c \
+ src/hash/dig_oid.c \
+ src/hash/dig_size.c \
+ src/hash/ghash_ctmul.c \
+ src/hash/ghash_ctmul32.c \
+ src/hash/ghash_ctmul64.c \
+ src/hash/ghash_pclmul.c \
+ src/hash/ghash_pwr8.c \
+ src/hash/md5.c \
+ src/hash/md5sha1.c \
+ src/hash/mgf1.c \
+ src/hash/multihash.c \
+ src/hash/sha1.c \
+ src/hash/sha2big.c \
+ src/hash/sha2small.c \
+ src/int/i15_add.c \
+ src/int/i15_bitlen.c \
+ src/int/i15_decmod.c \
+ src/int/i15_decode.c \
+ src/int/i15_decred.c \
+ src/int/i15_encode.c \
+ src/int/i15_fmont.c \
+ src/int/i15_iszero.c \
+ src/int/i15_moddiv.c \
+ src/int/i15_modpow.c \
+ src/int/i15_modpow2.c \
+ src/int/i15_montmul.c \
+ src/int/i15_mulacc.c \
+ src/int/i15_muladd.c \
+ src/int/i15_ninv15.c \
+ src/int/i15_reduce.c \
+ src/int/i15_rshift.c \
+ src/int/i15_sub.c \
+ src/int/i15_tmont.c \
+ src/int/i31_add.c \
+ src/int/i31_bitlen.c \
+ src/int/i31_decmod.c \
+ src/int/i31_decode.c \
+ src/int/i31_decred.c \
+ src/int/i31_encode.c \
+ src/int/i31_fmont.c \
+ src/int/i31_iszero.c \
+ src/int/i31_moddiv.c \
+ src/int/i31_modpow.c \
+ src/int/i31_modpow2.c \
+ src/int/i31_montmul.c \
+ src/int/i31_mulacc.c \
+ src/int/i31_muladd.c \
+ src/int/i31_ninv31.c \
+ src/int/i31_reduce.c \
+ src/int/i31_rshift.c \
+ src/int/i31_sub.c \
+ src/int/i31_tmont.c \
+ src/int/i32_add.c \
+ src/int/i32_bitlen.c \
+ src/int/i32_decmod.c \
+ src/int/i32_decode.c \
+ src/int/i32_decred.c \
+ src/int/i32_div32.c \
+ src/int/i32_encode.c \
+ src/int/i32_fmont.c \
+ src/int/i32_iszero.c \
+ src/int/i32_modpow.c \
+ src/int/i32_montmul.c \
+ src/int/i32_mulacc.c \
+ src/int/i32_muladd.c \
+ src/int/i32_ninv32.c \
+ src/int/i32_reduce.c \
+ src/int/i32_sub.c \
+ src/int/i32_tmont.c \
+ src/int/i62_modpow2.c \
+ src/kdf/hkdf.c \
+ src/kdf/shake.c \
+ src/mac/hmac.c \
+ src/mac/hmac_ct.c \
+ src/rand/aesctr_drbg.c \
+ src/rand/hmac_drbg.c \
+ src/rand/sysrng.c \
+ src/rsa/rsa_default_keygen.c \
+ src/rsa/rsa_default_modulus.c \
+ src/rsa/rsa_default_oaep_decrypt.c \
+ src/rsa/rsa_default_oaep_encrypt.c \
+ src/rsa/rsa_default_pkcs1_sign.c \
+ src/rsa/rsa_default_pkcs1_vrfy.c \
+ src/rsa/rsa_default_priv.c \
+ src/rsa/rsa_default_privexp.c \
+ src/rsa/rsa_default_pss_sign.c \
+ src/rsa/rsa_default_pss_vrfy.c \
+ src/rsa/rsa_default_pub.c \
+ src/rsa/rsa_default_pubexp.c \
+ src/rsa/rsa_i15_keygen.c \
+ src/rsa/rsa_i15_modulus.c \
+ src/rsa/rsa_i15_oaep_decrypt.c \
+ src/rsa/rsa_i15_oaep_encrypt.c \
+ src/rsa/rsa_i15_pkcs1_sign.c \
+ src/rsa/rsa_i15_pkcs1_vrfy.c \
+ src/rsa/rsa_i15_priv.c \
+ src/rsa/rsa_i15_privexp.c \
+ src/rsa/rsa_i15_pss_sign.c \
+ src/rsa/rsa_i15_pss_vrfy.c \
+ src/rsa/rsa_i15_pub.c \
+ src/rsa/rsa_i15_pubexp.c \
+ src/rsa/rsa_i31_keygen.c \
+ src/rsa/rsa_i31_keygen_inner.c \
+ src/rsa/rsa_i31_modulus.c \
+ src/rsa/rsa_i31_oaep_decrypt.c \
+ src/rsa/rsa_i31_oaep_encrypt.c \
+ src/rsa/rsa_i31_pkcs1_sign.c \
+ src/rsa/rsa_i31_pkcs1_vrfy.c \
+ src/rsa/rsa_i31_priv.c \
+ src/rsa/rsa_i31_privexp.c \
+ src/rsa/rsa_i31_pss_sign.c \
+ src/rsa/rsa_i31_pss_vrfy.c \
+ src/rsa/rsa_i31_pub.c \
+ src/rsa/rsa_i31_pubexp.c \
+ src/rsa/rsa_i32_oaep_decrypt.c \
+ src/rsa/rsa_i32_oaep_encrypt.c \
+ src/rsa/rsa_i32_pkcs1_sign.c \
+ src/rsa/rsa_i32_pkcs1_vrfy.c \
+ src/rsa/rsa_i32_priv.c \
+ src/rsa/rsa_i32_pss_sign.c \
+ src/rsa/rsa_i32_pss_vrfy.c \
+ src/rsa/rsa_i32_pub.c \
+ src/rsa/rsa_i62_keygen.c \
+ src/rsa/rsa_i62_oaep_decrypt.c \
+ src/rsa/rsa_i62_oaep_encrypt.c \
+ src/rsa/rsa_i62_pkcs1_sign.c \
+ src/rsa/rsa_i62_pkcs1_vrfy.c \
+ src/rsa/rsa_i62_priv.c \
+ src/rsa/rsa_i62_pss_sign.c \
+ src/rsa/rsa_i62_pss_vrfy.c \
+ src/rsa/rsa_i62_pub.c \
+ src/rsa/rsa_oaep_pad.c \
+ src/rsa/rsa_oaep_unpad.c \
+ src/rsa/rsa_pkcs1_sig_pad.c \
+ src/rsa/rsa_pkcs1_sig_unpad.c \
+ src/rsa/rsa_pss_sig_pad.c \
+ src/rsa/rsa_pss_sig_unpad.c \
+ src/rsa/rsa_ssl_decrypt.c \
+ src/ssl/prf.c \
+ src/ssl/prf_md5sha1.c \
+ src/ssl/prf_sha256.c \
+ src/ssl/prf_sha384.c \
+ src/ssl/ssl_ccert_single_ec.c \
+ src/ssl/ssl_ccert_single_rsa.c \
+ src/ssl/ssl_client.c \
+ src/ssl/ssl_client_default_rsapub.c \
+ src/ssl/ssl_client_full.c \
+ src/ssl/ssl_engine.c \
+ src/ssl/ssl_engine_default_aescbc.c \
+ src/ssl/ssl_engine_default_aesccm.c \
+ src/ssl/ssl_engine_default_aesgcm.c \
+ src/ssl/ssl_engine_default_chapol.c \
+ src/ssl/ssl_engine_default_descbc.c \
+ src/ssl/ssl_engine_default_ec.c \
+ src/ssl/ssl_engine_default_ecdsa.c \
+ src/ssl/ssl_engine_default_rsavrfy.c \
+ src/ssl/ssl_hashes.c \
+ src/ssl/ssl_hs_client.c \
+ src/ssl/ssl_hs_server.c \
+ src/ssl/ssl_io.c \
+ src/ssl/ssl_keyexport.c \
+ src/ssl/ssl_lru.c \
+ src/ssl/ssl_rec_cbc.c \
+ src/ssl/ssl_rec_ccm.c \
+ src/ssl/ssl_rec_chapol.c \
+ src/ssl/ssl_rec_gcm.c \
+ src/ssl/ssl_scert_single_ec.c \
+ src/ssl/ssl_scert_single_rsa.c \
+ src/ssl/ssl_server.c \
+ src/ssl/ssl_server_full_ec.c \
+ src/ssl/ssl_server_full_rsa.c \
+ src/ssl/ssl_server_mine2c.c \
+ src/ssl/ssl_server_mine2g.c \
+ src/ssl/ssl_server_minf2c.c \
+ src/ssl/ssl_server_minf2g.c \
+ src/ssl/ssl_server_minr2g.c \
+ src/ssl/ssl_server_minu2g.c \
+ src/ssl/ssl_server_minv2g.c \
+ src/symcipher/aes_big_cbcdec.c \
+ src/symcipher/aes_big_cbcenc.c \
+ src/symcipher/aes_big_ctr.c \
+ src/symcipher/aes_big_ctrcbc.c \
+ src/symcipher/aes_big_dec.c \
+ src/symcipher/aes_big_enc.c \
+ src/symcipher/aes_common.c \
+ src/symcipher/aes_ct.c \
+ src/symcipher/aes_ct64.c \
+ src/symcipher/aes_ct64_cbcdec.c \
+ src/symcipher/aes_ct64_cbcenc.c \
+ src/symcipher/aes_ct64_ctr.c \
+ src/symcipher/aes_ct64_ctrcbc.c \
+ src/symcipher/aes_ct64_dec.c \
+ src/symcipher/aes_ct64_enc.c \
+ src/symcipher/aes_ct_cbcdec.c \
+ src/symcipher/aes_ct_cbcenc.c \
+ src/symcipher/aes_ct_ctr.c \
+ src/symcipher/aes_ct_ctrcbc.c \
+ src/symcipher/aes_ct_dec.c \
+ src/symcipher/aes_ct_enc.c \
+ src/symcipher/aes_pwr8.c \
+ src/symcipher/aes_pwr8_cbcdec.c \
+ src/symcipher/aes_pwr8_cbcenc.c \
+ src/symcipher/aes_pwr8_ctr.c \
+ src/symcipher/aes_pwr8_ctrcbc.c \
+ src/symcipher/aes_small_cbcdec.c \
+ src/symcipher/aes_small_cbcenc.c \
+ src/symcipher/aes_small_ctr.c \
+ src/symcipher/aes_small_ctrcbc.c \
+ src/symcipher/aes_small_dec.c \
+ src/symcipher/aes_small_enc.c \
+ src/symcipher/aes_x86ni.c \
+ src/symcipher/aes_x86ni_cbcdec.c \
+ src/symcipher/aes_x86ni_cbcenc.c \
+ src/symcipher/aes_x86ni_ctr.c \
+ src/symcipher/aes_x86ni_ctrcbc.c \
+ src/symcipher/chacha20_ct.c \
+ src/symcipher/chacha20_sse2.c \
+ src/symcipher/des_ct.c \
+ src/symcipher/des_ct_cbcdec.c \
+ src/symcipher/des_ct_cbcenc.c \
+ src/symcipher/des_support.c \
+ src/symcipher/des_tab.c \
+ src/symcipher/des_tab_cbcdec.c \
+ src/symcipher/des_tab_cbcenc.c \
+ src/symcipher/poly1305_ctmul.c \
+ src/symcipher/poly1305_ctmul32.c \
+ src/symcipher/poly1305_ctmulq.c \
+ src/symcipher/poly1305_i15.c \
+ src/x509/asn1enc.c \
+ src/x509/encode_ec_pk8der.c \
+ src/x509/encode_ec_rawder.c \
+ src/x509/encode_rsa_pk8der.c \
+ src/x509/encode_rsa_rawder.c \
+ src/x509/skey_decoder.c \
+ src/x509/x509_decoder.c \
+ src/x509/x509_knownkey.c \
+ src/x509/x509_minimal.c \
+ src/x509/x509_minimal_full.c"
+
+# Source files for the 'brssl' command-line tool.
+toolssrc=" \
+ tools/brssl.c \
+ tools/certs.c \
+ tools/chain.c \
+ tools/client.c \
+ tools/errors.c \
+ tools/files.c \
+ tools/impl.c \
+ tools/keys.c \
+ tools/names.c \
+ tools/server.c \
+ tools/skey.c \
+ tools/sslio.c \
+ tools/ta.c \
+ tools/twrch.c \
+ tools/vector.c \
+ tools/verify.c \
+ tools/xmem.c"
+
+# Source files the the 'testcrypto' command-line tool.
+testcryptosrc=" \
+ test/test_crypto.c"
+
+# Source files the the 'testspeed' command-line tool.
+testspeedsrc=" \
+ test/test_speed.c"
+
+# Source files the the 'testx509' command-line tool.
+testx509src=" \
+ test/test_x509.c"
+
+# Public header files.
+headerspub=" \
+ inc/bearssl.h \
+ inc/bearssl_aead.h \
+ inc/bearssl_block.h \
+ inc/bearssl_ec.h \
+ inc/bearssl_hash.h \
+ inc/bearssl_hmac.h \
+ inc/bearssl_kdf.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"
+
+# Private header files.
+headerspriv=" \
+ src/config.h \
+ src/inner.h"
+
+# Header files for the 'brssl' command-line tool.
+headerstools=" \
+ tools/brssl.h"
+
+# T0 compiler source code.
+t0compsrc=" \
+ 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"
+
+t0compkern=" \
+ T0/kern.t0"
+
+# Function to turn slashes into $P (macro for path separator).
+escsep() {
+ printf '%s' "$1" | sed 's/\//$P/g'
+}
+
+# Create rules file.
+rm -f Rules.mk
+cat > Rules.mk <<EOF
+# Automatically generated rules. Use 'mkrules.sh' to modify/regenerate.
+EOF
+
+(printf "\nOBJ ="
+for f in $coresrc ; do
+ printf ' \\\n $(OBJDIR)$P%s' "$(basename "$f" .c)\$O"
+done
+printf "\nOBJBRSSL ="
+for f in $toolssrc ; do
+ printf ' \\\n $(OBJDIR)$P%s' "$(basename "$f" .c)\$O"
+done
+printf "\nOBJTESTCRYPTO ="
+for f in $testcryptosrc ; do
+ printf ' \\\n $(OBJDIR)$P%s' "$(basename "$f" .c)\$O"
+done
+printf "\nOBJTESTSPEED ="
+for f in $testspeedsrc ; do
+ printf ' \\\n $(OBJDIR)$P%s' "$(basename "$f" .c)\$O"
+done
+printf "\nOBJTESTX509 ="
+for f in $testx509src ; do
+ printf ' \\\n $(OBJDIR)$P%s' "$(basename "$f" .c)\$O"
+done
+printf "\nHEADERSPUB ="
+for f in $headerspub ; do
+ printf " %s" "$(escsep "$f")"
+done
+printf "\nHEADERSPRIV = %s" '$(HEADERSPUB)'
+for f in $headerspriv ; do
+ printf " %s" "$(escsep "$f")"
+done
+printf "\nHEADERSTOOLS = %s" '$(HEADERSPUB)'
+for f in $headerstools ; do
+ printf " %s" "$(escsep "$f")"
+done
+printf "\nT0SRC ="
+for f in $t0compsrc ; do
+ printf " %s" "$(escsep "$f")"
+done
+printf "\nT0KERN ="
+for f in $t0kernsrc ; do
+ printf " %s" "$(escsep "$f")"
+done
+printf "\n") >> Rules.mk
+
+cat >> Rules.mk <<EOF
+
+all: \$(STATICLIB) \$(DLL) \$(TOOLS) \$(TESTS)
+
+no:
+
+lib: \$(BEARSSLLIB)
+
+dll: \$(BEARSSLDLL)
+
+tools: \$(BRSSL)
+
+tests: \$(TESTCRYPTO) \$(TESTSPEED) \$(TESTX509)
+
+T0: kT0
+
+kT0: \$(T0COMP) src\$Pssl\$Pssl_hs_common.t0 src\$Pssl\$Pssl_hs_client.t0 src\$Pssl\$Pssl_hs_server.t0 src\$Px509\$Pasn1.t0 src\$Px509\$Pskey_decoder.t0 src\$Px509\$Px509_decoder.t0 src\$Px509\$Px509_minimal.t0
+ \$(RUNT0COMP) -o src\$Pcodec\$Ppemdec -r br_pem_decoder src\$Pcodec\$Ppemdec.t0
+ \$(RUNT0COMP) -o src\$Pssl\$Pssl_hs_client -r br_ssl_hs_client src\$Pssl\$Pssl_hs_common.t0 src\$Pssl\$Pssl_hs_client.t0
+ \$(RUNT0COMP) -o src\$Pssl\$Pssl_hs_server -r br_ssl_hs_server src\$Pssl\$Pssl_hs_common.t0 src\$Pssl\$Pssl_hs_server.t0
+ \$(RUNT0COMP) -o src\$Px509\$Pskey_decoder -r br_skey_decoder src\$Px509\$Pasn1.t0 src\$Px509\$Pskey_decoder.t0
+ \$(RUNT0COMP) -o src\$Px509\$Px509_decoder -r br_x509_decoder src\$Px509\$Pasn1.t0 src\$Px509\$Px509_decoder.t0
+ \$(RUNT0COMP) -o src\$Px509\$Px509_minimal -r br_x509_minimal src\$Px509\$Pasn1.t0 src\$Px509\$Px509_minimal.t0
+
+\$(T0COMP): \$(T0SRC) \$(T0KERN)
+ \$(MKT0COMP)
+
+clean:
+ -\$(RM) \$(OBJDIR)\$P*\$O
+ -\$(RM) \$(BEARSSLLIB) \$(BEARSSLDLL) \$(BRSSL) \$(TESTCRYPTO) \$(TESTSPEED) \$(TESTX509)
+
+\$(OBJDIR):
+ -\$(MKDIR) \$(OBJDIR)
+
+\$(BEARSSLLIB): \$(OBJDIR) \$(OBJ)
+ \$(AR) \$(ARFLAGS) \$(AROUT)\$(BEARSSLLIB) \$(OBJ)
+
+\$(BEARSSLDLL): \$(OBJDIR) \$(OBJ)
+ \$(LDDLL) \$(LDDLLFLAGS) \$(LDDLLOUT)\$(BEARSSLDLL) \$(OBJ)
+
+\$(BRSSL): \$(BEARSSLLIB) \$(OBJBRSSL)
+ \$(LD) \$(LDFLAGS) \$(LDOUT)\$(BRSSL) \$(OBJBRSSL) \$(BEARSSLLIB)
+
+\$(TESTCRYPTO): \$(BEARSSLLIB) \$(OBJTESTCRYPTO)
+ \$(LD) \$(LDFLAGS) \$(LDOUT)\$(TESTCRYPTO) \$(OBJTESTCRYPTO) \$(BEARSSLLIB)
+
+\$(TESTSPEED): \$(BEARSSLLIB) \$(OBJTESTSPEED)
+ \$(LD) \$(LDFLAGS) \$(LDOUT)\$(TESTSPEED) \$(OBJTESTSPEED) \$(BEARSSLLIB)
+
+\$(TESTX509): \$(BEARSSLLIB) \$(OBJTESTX509)
+ \$(LD) \$(LDFLAGS) \$(LDOUT)\$(TESTX509) \$(OBJTESTX509) \$(BEARSSLLIB)
+EOF
+
+(for f in $coresrc ; do
+ b="$(basename "$f" .c)\$O"
+ g="$(escsep "$f")"
+ printf '\n$(OBJDIR)$P%s: %s $(HEADERSPRIV)\n\t$(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$P%s %s\n' "$b" "$g" "$b" "$g"
+done
+
+for f in $toolssrc ; do
+ b="$(basename "$f" .c)\$O"
+ g="$(escsep "$f")"
+ printf '\n$(OBJDIR)$P%s: %s $(HEADERSTOOLS)\n\t$(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$P%s %s\n' "$b" "$g" "$b" "$g"
+done
+
+for f in $testcryptosrc $testspeedsrc ; do
+ b="$(basename "$f" .c)\$O"
+ g="$(escsep "$f")"
+ printf '\n$(OBJDIR)$P%s: %s $(HEADERSPRIV)\n\t$(CC) $(CFLAGS) $(INCFLAGS) $(CCOUT)$(OBJDIR)$P%s %s\n' "$b" "$g" "$b" "$g"
+done
+
+for f in $testx509src ; do
+ b="$(basename "$f" .c)\$O"
+ g="$(escsep "$f")"
+ printf '\n$(OBJDIR)$P%s: %s $(HEADERSPRIV)\n\t$(CC) $(CFLAGS) $(INCFLAGS) -DSRCDIRNAME=".." $(CCOUT)$(OBJDIR)$P%s %s\n' "$b" "$g" "$b" "$g"
+done) >> Rules.mk
diff --git a/contrib/bearssl/samples/README.txt b/contrib/bearssl/samples/README.txt
new file mode 100644
index 000000000000..77c93c79a867
--- /dev/null
+++ b/contrib/bearssl/samples/README.txt
@@ -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.
diff --git a/contrib/bearssl/samples/cert-ee-ec+rsa.pem b/contrib/bearssl/samples/cert-ee-ec+rsa.pem
new file mode 100644
index 000000000000..07f5457aa815
--- /dev/null
+++ b/contrib/bearssl/samples/cert-ee-ec+rsa.pem
@@ -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-----
diff --git a/contrib/bearssl/samples/cert-ee-ec.pem b/contrib/bearssl/samples/cert-ee-ec.pem
new file mode 100644
index 000000000000..ff8ddbc346d5
--- /dev/null
+++ b/contrib/bearssl/samples/cert-ee-ec.pem
@@ -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-----
diff --git a/contrib/bearssl/samples/cert-ee-rsa.pem b/contrib/bearssl/samples/cert-ee-rsa.pem
new file mode 100644
index 000000000000..ef33e4058377
--- /dev/null
+++ b/contrib/bearssl/samples/cert-ee-rsa.pem
@@ -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-----
diff --git a/contrib/bearssl/samples/cert-ica-ec.pem b/contrib/bearssl/samples/cert-ica-ec.pem
new file mode 100644
index 000000000000..204ab76c562b
--- /dev/null
+++ b/contrib/bearssl/samples/cert-ica-ec.pem
@@ -0,0 +1,10 @@
+-----BEGIN CERTIFICATE-----
+MIIBqTCCAU6gAwIBAgIUINPr4oz+2uajLF478mY6KzZ7sMowCgYIKoZIzj0EAwIwHDELMAkGA1UE
+BhMCQ0ExDTALBgNVBAMTBFJvb3QwHhcNMTAwMTAxMDAwMDAwWhcNMzcxMjMxMjM1OTU5WjAnMQsw
+CQYDVQQGEwJDQTEYMBYGA1UEAxMPSW50ZXJtZWRpYXRlIENBMFkwEwYHKoZIzj0CAQYIKoZIzj0D
+AQcDQgAEcC6SggEXbG2r4dFjCUhJ0qY1UtM8c7uyiDeYh/GN4Oxlmg4T9e2RYci2bTOEbq6OVYDN
+SZ4Hv9CunebQsycWoaNjMGEwHwYDVR0jBBgwFoAUlUG04meq8X+8j3nzaBRaa5IWokAwHQYDVR0O
+BBYEFPDQ8SL5ekgXBns9vbj1zVWcXD5wMA4GA1UdDwEB/wQEAwIAhjAPBgNVHRMBAf8EBTADAQH/
+MAoGCCqGSM49BAMCA0kAMEYCIQCF40ZomdYCellmHLdPNS0INjhhfgVI2GlDH+tW6a0GDgIhAIJw
+tGIDSUbIVFkF2XjbUxzgbmb1DxQ7yS04EnCRVvmp
+-----END CERTIFICATE-----
diff --git a/contrib/bearssl/samples/cert-ica-rsa.pem b/contrib/bearssl/samples/cert-ica-rsa.pem
new file mode 100644
index 000000000000..058ffab44594
--- /dev/null
+++ b/contrib/bearssl/samples/cert-ica-rsa.pem
@@ -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-----
diff --git a/contrib/bearssl/samples/cert-root-ec.pem b/contrib/bearssl/samples/cert-root-ec.pem
new file mode 100644
index 000000000000..1bfd5786d6c9
--- /dev/null
+++ b/contrib/bearssl/samples/cert-root-ec.pem
@@ -0,0 +1,9 @@
+-----BEGIN CERTIFICATE-----
+MIIBijCCATCgAwIBAgIBCTAKBggqhkjOPQQDAjAcMQswCQYDVQQGEwJDQTENMAsGA1UEAxMEUm9v
+dDAeFw0xMDAxMDEwMDAwMDBaFw0zNzEyMzEyMzU5NTlaMBwxCzAJBgNVBAYTAkNBMQ0wCwYDVQQD
+EwRSb290MFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEcXS6q7kwLoHV5Vf58yBoDJz5ZNu0IA1t
+6kDQSm5C/baaaCVE9t97xPze3Xu7xdt8dj9BZkBu26eHwuXYxfN/jaNjMGEwHwYDVR0jBBgwFoAU
+lUG04meq8X+8j3nzaBRaa5IWokAwHQYDVR0OBBYEFJVBtOJnqvF/vI9582gUWmuSFqJAMA4GA1Ud
+DwEB/wQEAwIAhjAPBgNVHRMBAf8EBTADAQH/MAoGCCqGSM49BAMCA0gAMEUCIQCz1GCIAoRtqU2h
+x62hec7E+/XxnUGDORWnkliiGrcmxQIgNPq9NHD7ts0xYjTwZsd0bN62+iY93lM4LHbkNV9q/gA=
+-----END CERTIFICATE-----
diff --git a/contrib/bearssl/samples/cert-root-rsa.pem b/contrib/bearssl/samples/cert-root-rsa.pem
new file mode 100644
index 000000000000..6b5ebd09f94c
--- /dev/null
+++ b/contrib/bearssl/samples/cert-root-rsa.pem
@@ -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-----
diff --git a/contrib/bearssl/samples/chain-ec+rsa.h b/contrib/bearssl/samples/chain-ec+rsa.h
new file mode 100644
index 000000000000..2a27ff5cfda9
--- /dev/null
+++ b/contrib/bearssl/samples/chain-ec+rsa.h
@@ -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
diff --git a/contrib/bearssl/samples/chain-ec.h b/contrib/bearssl/samples/chain-ec.h
new file mode 100644
index 000000000000..b4927a325d8e
--- /dev/null
+++ b/contrib/bearssl/samples/chain-ec.h
@@ -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
diff --git a/contrib/bearssl/samples/chain-rsa.h b/contrib/bearssl/samples/chain-rsa.h
new file mode 100644
index 000000000000..f8387891af80
--- /dev/null
+++ b/contrib/bearssl/samples/chain-rsa.h
@@ -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
diff --git a/contrib/bearssl/samples/client_basic.c b/contrib/bearssl/samples/client_basic.c
new file mode 100644
index 000000000000..31a88be4c128
--- /dev/null
+++ b/contrib/bearssl/samples/client_basic.c
@@ -0,0 +1,380 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 <signal.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 = "/";
+ }
+
+ /*
+ * Ignore SIGPIPE to avoid crashing in case of abrupt socket close.
+ */
+ signal(SIGPIPE, SIG_IGN);
+
+ /*
+ * 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;
+ }
+}
diff --git a/contrib/bearssl/samples/custom_profile.c b/contrib/bearssl/samples/custom_profile.c
new file mode 100644
index 000000000000..8133532974f1
--- /dev/null
+++ b/contrib/bearssl/samples/custom_profile.c
@@ -0,0 +1,601 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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_CHACHA20_POLY1305_SHA256,
+ BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ 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.
+ *
+ * Moreover, these hash functions are also used to compute
+ * hashes supporting signatures on the server side (for ECDHE_*
+ * cipher suites), and on the client side (for client
+ * certificates, except in the case of full static ECDH). In TLS
+ * 1.0 and 1.1, SHA-1 (and also MD5) will be used, but with TLS
+ * 1.2 these hash functions are negotiated between client and
+ * server; SHA-256 and/or SHA-384 should be sufficient in
+ * practice.
+ *
+ * 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 implementations.
+ *
+ * -- 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 ECDHE_RSA, ECDH_ECDSA or ECDH_RSA).
+ *
+ * Normally, you use the "default" implementations, obtained
+ * through relevant function calls. These functions return
+ * implementations that are deemed "best" for the current
+ * platform, where "best" means "fastest within constant-time
+ * implementations". Selecting the default implementation is a
+ * mixture of compile-time and runtime checks.
+ *
+ * Nevertheless, specific implementations may be selected
+ * explicitly, e.g. to use code which is slower but with a
+ * smaller footprint.
+ *
+ * The RSA code comes in three variants, called "i15", "i31" and
+ * "i32". The "i31" code is somewhat faster than the "i32" code.
+ * Usually, "i31" is faster than "i15", except on some specific
+ * architectures (ARM Cortex M0, M0+, M1 and M3) where the "i15"
+ * should be preferred (the "i15" code is constant-time, while
+ * the "i31" is not, and the "i15" code is faster anyway).
+ *
+ * ECDSA code also comes in "i15" and "i31" variants. As in the
+ * case of RSA, the "i31" code is faster, except on the small
+ * ARM Cortex M, where the "i15" code is faster and safer.
+ *
+ * There are no less than 10 elliptic curve implementations:
+ *
+ * - ec_c25519_i15, ec_c25519_i31, ec_c25519_m15 and ec_c25519_m31
+ * implement Curve25519.
+ *
+ * - ec_p256_m15 and ec_p256_m31 implement NIST curve P-256.
+ *
+ * - ec_prime_i15 and ec_prime_i31 implement NIST curves P-256,
+ * P-384 and P-521.
+ *
+ * - ec_all_m15 is an aggregate implementation that uses
+ * ec_c25519_m15, ec_p256_m15 and ec_prime_i15.
+ *
+ * - ec_all_m31 is an aggregate implementation that uses
+ * ec_c25519_m31, ec_p256_m31 and ec_prime_i31.
+ *
+ * For a given curve, "m15" is faster than "i15" (but possibly
+ * with a larger code footprint) and "m31" is faster than "i31"
+ * (there again with a larger code footprint). For best
+ * performance, use ec_all_m31, except on the small ARM Cortex M
+ * where ec_all_m15 should be used. Referencing the other
+ * implementations directly will result in smaller code, but
+ * support for fewer curves and possibly lower performance.
+ */
+ br_ssl_client_set_default_rsapub(cc);
+ br_ssl_engine_set_default_rsavrfy(&cc->eng);
+ br_ssl_engine_set_default_ecdsa(&cc->eng);
+ /* Alternate: set implementations explicitly.
+ 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_all_m31);
+ br_ssl_engine_set_ecdsa(&cc->eng, &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").
+ * -- Cipher suites in CHACHA20_POLY1305 need the ChaCha20+Poly1305
+ * record handler ("set_chapol").
+ */
+ 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_chapol(&cc->eng,
+ &br_sslrec_in_chapol_vtable,
+ &br_sslrec_out_chapol_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.
+ *
+ * aes_x86ni Very fast implementation that uses the AES-NI
+ * opcodes on recent x86 CPU. But it may not be
+ * compiled in the library if the compiler or
+ * architecture is not supported; and the CPU
+ * may also not support the opcodes. Selection
+ * functions are provided to test for availability
+ * of the code and the opcodes.
+ *
+ * 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 preferred. 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);
+ */
+}
diff --git a/contrib/bearssl/samples/key-ec.h b/contrib/bearssl/samples/key-ec.h
new file mode 100644
index 000000000000..c9d0fa4fb6e0
--- /dev/null
+++ b/contrib/bearssl/samples/key-ec.h
@@ -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
+};
diff --git a/contrib/bearssl/samples/key-ee-ec.pem b/contrib/bearssl/samples/key-ee-ec.pem
new file mode 100644
index 000000000000..2e6a1363fdad
--- /dev/null
+++ b/contrib/bearssl/samples/key-ee-ec.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIAORW0IGkHORG0jvCPu1rXVl+eb3IUdiSPo/l3twnYaloAoGCCqGSM49AwEHoUQDQgAE
+Xzidp/9Niq/2NDlGGvw63/Qjqqnq+8UI3gCOvnmlN1hMbd0ByqtH34m2xxcfOPwdIBTdRcDgj5NO
+OAv86ZmhSQ==
+-----END EC PRIVATE KEY-----
diff --git a/contrib/bearssl/samples/key-ee-rsa.pem b/contrib/bearssl/samples/key-ee-rsa.pem
new file mode 100644
index 000000000000..e8b22b40aaef
--- /dev/null
+++ b/contrib/bearssl/samples/key-ee-rsa.pem
@@ -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-----
diff --git a/contrib/bearssl/samples/key-ica-ec.pem b/contrib/bearssl/samples/key-ica-ec.pem
new file mode 100644
index 000000000000..74430980c428
--- /dev/null
+++ b/contrib/bearssl/samples/key-ica-ec.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIEJOkvo4MZ9N+wlTodEzmWor1RauybudPe92K15viDbzoAoGCCqGSM49AwEHoUQDQgAE
+cC6SggEXbG2r4dFjCUhJ0qY1UtM8c7uyiDeYh/GN4Oxlmg4T9e2RYci2bTOEbq6OVYDNSZ4Hv9Cu
+nebQsycWoQ==
+-----END EC PRIVATE KEY-----
diff --git a/contrib/bearssl/samples/key-ica-rsa.pem b/contrib/bearssl/samples/key-ica-rsa.pem
new file mode 100644
index 000000000000..2e38e3407066
--- /dev/null
+++ b/contrib/bearssl/samples/key-ica-rsa.pem
@@ -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-----
diff --git a/contrib/bearssl/samples/key-root-ec.pem b/contrib/bearssl/samples/key-root-ec.pem
new file mode 100644
index 000000000000..e76db90c56d4
--- /dev/null
+++ b/contrib/bearssl/samples/key-root-ec.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEINx41f6h/utlj52XNFbIGJdkF3qZy1/g9hH2/yV4t/tnoAoGCCqGSM49AwEHoUQDQgAE
+cXS6q7kwLoHV5Vf58yBoDJz5ZNu0IA1t6kDQSm5C/baaaCVE9t97xPze3Xu7xdt8dj9BZkBu26eH
+wuXYxfN/jQ==
+-----END EC PRIVATE KEY-----
diff --git a/contrib/bearssl/samples/key-root-rsa.pem b/contrib/bearssl/samples/key-root-rsa.pem
new file mode 100644
index 000000000000..82a2eb033ea8
--- /dev/null
+++ b/contrib/bearssl/samples/key-root-rsa.pem
@@ -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-----
diff --git a/contrib/bearssl/samples/key-rsa.h b/contrib/bearssl/samples/key-rsa.h
new file mode 100644
index 000000000000..8de538d93b24
--- /dev/null
+++ b/contrib/bearssl/samples/key-rsa.h
@@ -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
+};
diff --git a/contrib/bearssl/samples/server_basic.c b/contrib/bearssl/samples/server_basic.c
new file mode 100644
index 000000000000..e774c4d26a55
--- /dev/null
+++ b/contrib/bearssl/samples/server_basic.c
@@ -0,0 +1,436 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 <signal.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.
+ *
+ * Other macros, which can be defined (with a non-zero value):
+ *
+ * SERVER_PROFILE_MIN_FS
+ * Select a "minimal" profile with forward security (ECDHE cipher
+ * suite).
+ *
+ * SERVER_PROFILE_MIN_NOFS
+ * Select a "minimal" profile without forward security (RSA or ECDH
+ * cipher suite, but not ECDHE).
+ *
+ * SERVER_CHACHA20
+ * If SERVER_PROFILE_MIN_FS is selected, then this macro selects
+ * a cipher suite with ChaCha20+Poly1305; otherwise, AES/GCM is
+ * used. This macro has no effect otherwise, since there is no
+ * non-forward secure cipher suite that uses ChaCha20+Poly1305.
+ */
+
+#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_INET6,
+ &((struct sockaddr_in6 *)&sa)->sin6_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];
+
+ /*
+ * Ignore SIGPIPE to avoid crashing in case of abrupt socket close.
+ */
+ signal(SIGPIPE, SIG_IGN);
+
+ /*
+ * 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
+#if SERVER_CHACHA20
+ br_ssl_server_init_mine2c(&sc, CHAIN, CHAIN_LEN, &SKEY);
+#else
+ br_ssl_server_init_mine2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
+#endif
+#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
+#if SERVER_CHACHA20
+ br_ssl_server_init_minf2c(&sc, CHAIN, CHAIN_LEN, &SKEY);
+#else
+ br_ssl_server_init_minf2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
+#endif
+#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
+#if SERVER_CHACHA20
+ br_ssl_server_init_minf2c(&sc, CHAIN, CHAIN_LEN, &SKEY);
+#else
+ br_ssl_server_init_minf2g(&sc, CHAIN, CHAIN_LEN, &SKEY);
+#endif
+#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);
+ }
+}
diff --git a/contrib/bearssl/src/aead/ccm.c b/contrib/bearssl/src/aead/ccm.c
new file mode 100644
index 000000000000..68cc913ec058
--- /dev/null
+++ b/contrib/bearssl/src/aead/ccm.c
@@ -0,0 +1,346 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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"
+
+/*
+ * Implementation Notes
+ * ====================
+ *
+ * The combined CTR + CBC-MAC functions can only handle full blocks,
+ * so some buffering is necessary.
+ *
+ * - 'ptr' contains a value from 0 to 15, which is the number of bytes
+ * accumulated in buf[] that still needs to be processed with the
+ * current CBC-MAC computation.
+ *
+ * - When processing the message itself, CTR encryption/decryption is
+ * also done at the same time. The first 'ptr' bytes of buf[] then
+ * contains the plaintext bytes, while the last '16 - ptr' bytes of
+ * buf[] are the remnants of the stream block, to be used against
+ * the next input bytes, when available. When 'ptr' is 0, the
+ * contents of buf[] are to be ignored.
+ *
+ * - The current counter and running CBC-MAC values are kept in 'ctr'
+ * and 'cbcmac', respectively.
+ */
+
+/* see bearssl_block.h */
+void
+br_ccm_init(br_ccm_context *ctx, const br_block_ctrcbc_class **bctx)
+{
+ ctx->bctx = bctx;
+}
+
+/* see bearssl_block.h */
+int
+br_ccm_reset(br_ccm_context *ctx, const void *nonce, size_t nonce_len,
+ uint64_t aad_len, uint64_t data_len, size_t tag_len)
+{
+ unsigned char tmp[16];
+ unsigned u, q;
+
+ if (nonce_len < 7 || nonce_len > 13) {
+ return 0;
+ }
+ if (tag_len < 4 || tag_len > 16 || (tag_len & 1) != 0) {
+ return 0;
+ }
+ q = 15 - (unsigned)nonce_len;
+ ctx->tag_len = tag_len;
+
+ /*
+ * Block B0, to start CBC-MAC.
+ */
+ tmp[0] = (aad_len > 0 ? 0x40 : 0x00)
+ | (((unsigned)tag_len - 2) << 2)
+ | (q - 1);
+ memcpy(tmp + 1, nonce, nonce_len);
+ for (u = 0; u < q; u ++) {
+ tmp[15 - u] = (unsigned char)data_len;
+ data_len >>= 8;
+ }
+ if (data_len != 0) {
+ /*
+ * If the data length was not entirely consumed in the
+ * loop above, then it exceeds the maximum limit of
+ * q bytes (when encoded).
+ */
+ return 0;
+ }
+
+ /*
+ * Start CBC-MAC.
+ */
+ memset(ctx->cbcmac, 0, sizeof ctx->cbcmac);
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, tmp, sizeof tmp);
+
+ /*
+ * Assemble AAD length header.
+ */
+ if ((aad_len >> 32) != 0) {
+ ctx->buf[0] = 0xFF;
+ ctx->buf[1] = 0xFF;
+ br_enc64be(ctx->buf + 2, aad_len);
+ ctx->ptr = 10;
+ } else if (aad_len >= 0xFF00) {
+ ctx->buf[0] = 0xFF;
+ ctx->buf[1] = 0xFE;
+ br_enc32be(ctx->buf + 2, (uint32_t)aad_len);
+ ctx->ptr = 6;
+ } else if (aad_len > 0) {
+ br_enc16be(ctx->buf, (unsigned)aad_len);
+ ctx->ptr = 2;
+ } else {
+ ctx->ptr = 0;
+ }
+
+ /*
+ * Make initial counter value and compute tag mask.
+ */
+ ctx->ctr[0] = q - 1;
+ memcpy(ctx->ctr + 1, nonce, nonce_len);
+ memset(ctx->ctr + 1 + nonce_len, 0, q);
+ memset(ctx->tagmask, 0, sizeof ctx->tagmask);
+ (*ctx->bctx)->ctr(ctx->bctx, ctx->ctr,
+ ctx->tagmask, sizeof ctx->tagmask);
+
+ return 1;
+}
+
+/* see bearssl_block.h */
+void
+br_ccm_aad_inject(br_ccm_context *ctx, const void *data, size_t len)
+{
+ const unsigned char *dbuf;
+ size_t ptr;
+
+ dbuf = data;
+
+ /*
+ * Complete partial block, if needed.
+ */
+ ptr = ctx->ptr;
+ if (ptr != 0) {
+ size_t clen;
+
+ clen = (sizeof ctx->buf) - ptr;
+ if (clen > len) {
+ memcpy(ctx->buf + ptr, dbuf, len);
+ ctx->ptr = ptr + len;
+ return;
+ }
+ memcpy(ctx->buf + ptr, dbuf, clen);
+ dbuf += clen;
+ len -= clen;
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
+ ctx->buf, sizeof ctx->buf);
+ }
+
+ /*
+ * Process complete blocks.
+ */
+ ptr = len & 15;
+ len -= ptr;
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, dbuf, len);
+ dbuf += len;
+
+ /*
+ * Copy last partial block in the context buffer.
+ */
+ memcpy(ctx->buf, dbuf, ptr);
+ ctx->ptr = ptr;
+}
+
+/* see bearssl_block.h */
+void
+br_ccm_flip(br_ccm_context *ctx)
+{
+ size_t ptr;
+
+ /*
+ * Complete AAD partial block with zeros, if necessary.
+ */
+ ptr = ctx->ptr;
+ if (ptr != 0) {
+ memset(ctx->buf + ptr, 0, (sizeof ctx->buf) - ptr);
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
+ ctx->buf, sizeof ctx->buf);
+ ctx->ptr = 0;
+ }
+
+ /*
+ * Counter was already set by br_ccm_reset().
+ */
+}
+
+/* see bearssl_block.h */
+void
+br_ccm_run(br_ccm_context *ctx, int encrypt, void *data, size_t len)
+{
+ unsigned char *dbuf;
+ size_t ptr;
+
+ dbuf = data;
+
+ /*
+ * Complete a partial block, if any: ctx->buf[] contains
+ * ctx->ptr plaintext bytes (already reported), and the other
+ * bytes are CTR stream output.
+ */
+ ptr = ctx->ptr;
+ if (ptr != 0) {
+ size_t clen;
+ size_t u;
+
+ clen = (sizeof ctx->buf) - ptr;
+ if (clen > len) {
+ clen = len;
+ }
+ if (encrypt) {
+ for (u = 0; u < clen; u ++) {
+ unsigned w, x;
+
+ w = ctx->buf[ptr + u];
+ x = dbuf[u];
+ ctx->buf[ptr + u] = x;
+ dbuf[u] = w ^ x;
+ }
+ } else {
+ for (u = 0; u < clen; u ++) {
+ unsigned w;
+
+ w = ctx->buf[ptr + u] ^ dbuf[u];
+ dbuf[u] = w;
+ ctx->buf[ptr + u] = w;
+ }
+ }
+ dbuf += clen;
+ len -= clen;
+ ptr += clen;
+ if (ptr < sizeof ctx->buf) {
+ ctx->ptr = ptr;
+ return;
+ }
+ (*ctx->bctx)->mac(ctx->bctx,
+ ctx->cbcmac, ctx->buf, sizeof ctx->buf);
+ }
+
+ /*
+ * Process all complete blocks. Note that the ctrcbc API is for
+ * encrypt-then-MAC (CBC-MAC is computed over the encrypted
+ * blocks) while CCM uses MAC-and-encrypt (CBC-MAC is computed
+ * over the plaintext blocks). Therefore, we need to use the
+ * _decryption_ function for encryption, and the encryption
+ * function for decryption (this works because CTR encryption
+ * and decryption are identical, so the choice really is about
+ * computing the CBC-MAC before or after XORing with the CTR
+ * stream).
+ */
+ ptr = len & 15;
+ len -= ptr;
+ if (encrypt) {
+ (*ctx->bctx)->decrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
+ dbuf, len);
+ } else {
+ (*ctx->bctx)->encrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
+ dbuf, len);
+ }
+ dbuf += len;
+
+ /*
+ * If there is some remaining data, then we need to compute an
+ * extra block of CTR stream.
+ */
+ if (ptr != 0) {
+ size_t u;
+
+ memset(ctx->buf, 0, sizeof ctx->buf);
+ (*ctx->bctx)->ctr(ctx->bctx, ctx->ctr,
+ ctx->buf, sizeof ctx->buf);
+ if (encrypt) {
+ for (u = 0; u < ptr; u ++) {
+ unsigned w, x;
+
+ w = ctx->buf[u];
+ x = dbuf[u];
+ ctx->buf[u] = x;
+ dbuf[u] = w ^ x;
+ }
+ } else {
+ for (u = 0; u < ptr; u ++) {
+ unsigned w;
+
+ w = ctx->buf[u] ^ dbuf[u];
+ dbuf[u] = w;
+ ctx->buf[u] = w;
+ }
+ }
+ }
+ ctx->ptr = ptr;
+}
+
+/* see bearssl_block.h */
+size_t
+br_ccm_get_tag(br_ccm_context *ctx, void *tag)
+{
+ size_t ptr;
+ size_t u;
+
+ /*
+ * If there is some buffered data, then we need to pad it with
+ * zeros and finish up CBC-MAC.
+ */
+ ptr = ctx->ptr;
+ if (ptr != 0) {
+ memset(ctx->buf + ptr, 0, (sizeof ctx->buf) - ptr);
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
+ ctx->buf, sizeof ctx->buf);
+ }
+
+ /*
+ * XOR the tag mask into the CBC-MAC output.
+ */
+ for (u = 0; u < ctx->tag_len; u ++) {
+ ctx->cbcmac[u] ^= ctx->tagmask[u];
+ }
+ memcpy(tag, ctx->cbcmac, ctx->tag_len);
+ return ctx->tag_len;
+}
+
+/* see bearssl_block.h */
+uint32_t
+br_ccm_check_tag(br_ccm_context *ctx, const void *tag)
+{
+ unsigned char tmp[16];
+ size_t u, tag_len;
+ uint32_t z;
+
+ tag_len = br_ccm_get_tag(ctx, tmp);
+ z = 0;
+ for (u = 0; u < tag_len; u ++) {
+ z |= tmp[u] ^ ((const unsigned char *)tag)[u];
+ }
+ return EQ0(z);
+}
diff --git a/contrib/bearssl/src/aead/eax.c b/contrib/bearssl/src/aead/eax.c
new file mode 100644
index 000000000000..bcc704a7fcd7
--- /dev/null
+++ b/contrib/bearssl/src/aead/eax.c
@@ -0,0 +1,525 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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"
+
+/*
+ * Implementation Notes
+ * ====================
+ *
+ * The combined CTR + CBC-MAC functions can only handle full blocks,
+ * so some buffering is necessary. Moreover, EAX has a special padding
+ * rule for CBC-MAC, which implies that we cannot compute the MAC over
+ * the last received full block until we know whether we are at the
+ * end of the data or not.
+ *
+ * - 'ptr' contains a value from 1 to 16, which is the number of bytes
+ * accumulated in buf[] that still needs to be processed with the
+ * current OMAC computation. Beware that this can go to 16: a
+ * complete block cannot be processed until it is known whether it
+ * is the last block or not. However, it can never be 0, because
+ * OMAC^t works on an input that is at least one-block long.
+ *
+ * - When processing the message itself, CTR encryption/decryption is
+ * also done at the same time. The first 'ptr' bytes of buf[] then
+ * contains the encrypted bytes, while the last '16 - ptr' bytes of
+ * buf[] are the remnants of the stream block, to be used against
+ * the next input bytes, when available.
+ *
+ * - The current counter and running CBC-MAC values are kept in 'ctr'
+ * and 'cbcmac', respectively.
+ *
+ * - The derived keys for padding are kept in L2 and L4 (double and
+ * quadruple of Enc_K(0^n), in GF(2^128), respectively).
+ */
+
+/*
+ * Start an OMAC computation; the first block is the big-endian
+ * representation of the provided value ('val' must fit on one byte).
+ * We make it a delayed block because it may also be the last one,
+ */
+static void
+omac_start(br_eax_context *ctx, unsigned val)
+{
+ memset(ctx->cbcmac, 0, sizeof ctx->cbcmac);
+ memset(ctx->buf, 0, sizeof ctx->buf);
+ ctx->buf[15] = val;
+ ctx->ptr = 16;
+}
+
+/*
+ * Double a value in finite field GF(2^128), defined with modulus
+ * X^128+X^7+X^2+X+1.
+ */
+static void
+double_gf128(unsigned char *dst, const unsigned char *src)
+{
+ unsigned cc;
+ int i;
+
+ cc = 0x87 & -((unsigned)src[0] >> 7);
+ for (i = 15; i >= 0; i --) {
+ unsigned z;
+
+ z = (src[i] << 1) ^ cc;
+ cc = z >> 8;
+ dst[i] = (unsigned char)z;
+ }
+}
+
+/*
+ * Apply padding to the last block, currently in ctx->buf (with
+ * ctx->ptr bytes), and finalize OMAC computation.
+ */
+static void
+do_pad(br_eax_context *ctx)
+{
+ unsigned char *pad;
+ size_t ptr, u;
+
+ ptr = ctx->ptr;
+ if (ptr == 16) {
+ pad = ctx->L2;
+ } else {
+ ctx->buf[ptr ++] = 0x80;
+ memset(ctx->buf + ptr, 0x00, 16 - ptr);
+ pad = ctx->L4;
+ }
+ for (u = 0; u < sizeof ctx->buf; u ++) {
+ ctx->buf[u] ^= pad[u];
+ }
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, ctx->buf, sizeof ctx->buf);
+}
+
+/*
+ * Apply CBC-MAC on the provided data, with buffering management.
+ *
+ * Upon entry, two situations are acceptable:
+ *
+ * ctx->ptr == 0: there is no data to process in ctx->buf
+ * ctx->ptr == 16: there is a full block of unprocessed data in ctx->buf
+ *
+ * Upon exit, ctx->ptr may be zero only if it was already zero on entry,
+ * and len == 0. In all other situations, ctx->ptr will be non-zero on
+ * exit (and may have value 16).
+ */
+static void
+do_cbcmac_chunk(br_eax_context *ctx, const void *data, size_t len)
+{
+ size_t ptr;
+
+ if (len == 0) {
+ return;
+ }
+ ptr = len & (size_t)15;
+ if (ptr == 0) {
+ len -= 16;
+ ptr = 16;
+ } else {
+ len -= ptr;
+ }
+ if (ctx->ptr == 16) {
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
+ ctx->buf, sizeof ctx->buf);
+ }
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac, data, len);
+ memcpy(ctx->buf, (const unsigned char *)data + len, ptr);
+ ctx->ptr = ptr;
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_init(br_eax_context *ctx, const br_block_ctrcbc_class **bctx)
+{
+ unsigned char tmp[16], iv[16];
+
+ ctx->vtable = &br_eax_vtable;
+ ctx->bctx = bctx;
+
+ /*
+ * Encrypt a whole-zero block to compute L2 and L4.
+ */
+ memset(tmp, 0, sizeof tmp);
+ memset(iv, 0, sizeof iv);
+ (*bctx)->ctr(bctx, iv, tmp, sizeof tmp);
+ double_gf128(ctx->L2, tmp);
+ double_gf128(ctx->L4, ctx->L2);
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_capture(const br_eax_context *ctx, br_eax_state *st)
+{
+ /*
+ * We capture the three OMAC* states _after_ processing the
+ * initial block (assuming that nonce, message and AAD are
+ * all non-empty).
+ */
+ int i;
+
+ memset(st->st, 0, sizeof st->st);
+ for (i = 0; i < 3; i ++) {
+ unsigned char tmp[16];
+
+ memset(tmp, 0, sizeof tmp);
+ tmp[15] = (unsigned char)i;
+ (*ctx->bctx)->mac(ctx->bctx, st->st[i], tmp, sizeof tmp);
+ }
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_reset(br_eax_context *ctx, const void *nonce, size_t len)
+{
+ /*
+ * Process nonce with OMAC^0.
+ */
+ omac_start(ctx, 0);
+ do_cbcmac_chunk(ctx, nonce, len);
+ do_pad(ctx);
+ memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
+
+ /*
+ * Start OMAC^1 for the AAD ("header" in the EAX specification).
+ */
+ omac_start(ctx, 1);
+
+ /*
+ * We use ctx->head[0] as temporary flag to mark that we are
+ * using a "normal" reset().
+ */
+ ctx->head[0] = 0;
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_reset_pre_aad(br_eax_context *ctx, const br_eax_state *st,
+ const void *nonce, size_t len)
+{
+ if (len == 0) {
+ omac_start(ctx, 0);
+ } else {
+ memcpy(ctx->cbcmac, st->st[0], sizeof ctx->cbcmac);
+ ctx->ptr = 0;
+ do_cbcmac_chunk(ctx, nonce, len);
+ }
+ do_pad(ctx);
+ memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
+
+ memcpy(ctx->cbcmac, st->st[1], sizeof ctx->cbcmac);
+ ctx->ptr = 0;
+
+ memcpy(ctx->ctr, st->st[2], sizeof ctx->ctr);
+
+ /*
+ * We use ctx->head[0] as a flag to indicate that we use a
+ * a recorded state, with ctx->ctr containing the preprocessed
+ * first block for OMAC^2.
+ */
+ ctx->head[0] = 1;
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_reset_post_aad(br_eax_context *ctx, const br_eax_state *st,
+ const void *nonce, size_t len)
+{
+ if (len == 0) {
+ omac_start(ctx, 0);
+ } else {
+ memcpy(ctx->cbcmac, st->st[0], sizeof ctx->cbcmac);
+ ctx->ptr = 0;
+ do_cbcmac_chunk(ctx, nonce, len);
+ }
+ do_pad(ctx);
+ memcpy(ctx->nonce, ctx->cbcmac, sizeof ctx->cbcmac);
+ memcpy(ctx->ctr, ctx->nonce, sizeof ctx->nonce);
+
+ memcpy(ctx->head, st->st[1], sizeof ctx->head);
+
+ memcpy(ctx->cbcmac, st->st[2], sizeof ctx->cbcmac);
+ ctx->ptr = 0;
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_aad_inject(br_eax_context *ctx, const void *data, size_t len)
+{
+ size_t ptr;
+
+ ptr = ctx->ptr;
+
+ /*
+ * If there is a partial block, first complete it.
+ */
+ if (ptr < 16) {
+ size_t clen;
+
+ clen = 16 - ptr;
+ if (len <= clen) {
+ memcpy(ctx->buf + ptr, data, len);
+ ctx->ptr = ptr + len;
+ return;
+ }
+ memcpy(ctx->buf + ptr, data, clen);
+ data = (const unsigned char *)data + clen;
+ len -= clen;
+ }
+
+ /*
+ * We now have a full block in buf[], and this is not the last
+ * block.
+ */
+ do_cbcmac_chunk(ctx, data, len);
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_flip(br_eax_context *ctx)
+{
+ int from_capture;
+
+ /*
+ * ctx->head[0] may be non-zero if the context was reset with
+ * a pre-AAD captured state. In that case, ctx->ctr[] contains
+ * the state for OMAC^2 _after_ processing the first block.
+ */
+ from_capture = ctx->head[0];
+
+ /*
+ * Complete the OMAC computation on the AAD.
+ */
+ do_pad(ctx);
+ memcpy(ctx->head, ctx->cbcmac, sizeof ctx->cbcmac);
+
+ /*
+ * Start OMAC^2 for the encrypted data.
+ * If the context was initialized from a captured state, then
+ * the OMAC^2 value is in the ctr[] array.
+ */
+ if (from_capture) {
+ memcpy(ctx->cbcmac, ctx->ctr, sizeof ctx->cbcmac);
+ ctx->ptr = 0;
+ } else {
+ omac_start(ctx, 2);
+ }
+
+ /*
+ * Initial counter value for CTR is the processed nonce.
+ */
+ memcpy(ctx->ctr, ctx->nonce, sizeof ctx->nonce);
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_run(br_eax_context *ctx, int encrypt, void *data, size_t len)
+{
+ unsigned char *dbuf;
+ size_t ptr;
+
+ /*
+ * Ensure that there is actual data to process.
+ */
+ if (len == 0) {
+ return;
+ }
+
+ dbuf = data;
+ ptr = ctx->ptr;
+
+ /*
+ * We may have ptr == 0 here if we initialized from a captured
+ * state. In that case, there is no partially consumed block
+ * or unprocessed data.
+ */
+ if (ptr != 0 && ptr != 16) {
+ /*
+ * We have a partially consumed block.
+ */
+ size_t u, clen;
+
+ clen = 16 - ptr;
+ if (len <= clen) {
+ clen = len;
+ }
+ if (encrypt) {
+ for (u = 0; u < clen; u ++) {
+ ctx->buf[ptr + u] ^= dbuf[u];
+ }
+ memcpy(dbuf, ctx->buf + ptr, clen);
+ } else {
+ for (u = 0; u < clen; u ++) {
+ unsigned dx, sx;
+
+ sx = ctx->buf[ptr + u];
+ dx = dbuf[u];
+ ctx->buf[ptr + u] = dx;
+ dbuf[u] = sx ^ dx;
+ }
+ }
+
+ if (len <= clen) {
+ ctx->ptr = ptr + clen;
+ return;
+ }
+ dbuf += clen;
+ len -= clen;
+ }
+
+ /*
+ * We now have a complete encrypted block in buf[] that must still
+ * be processed with OMAC, and this is not the final buf.
+ * Exception: when ptr == 0, no block has been produced yet.
+ */
+ if (ptr != 0) {
+ (*ctx->bctx)->mac(ctx->bctx, ctx->cbcmac,
+ ctx->buf, sizeof ctx->buf);
+ }
+
+ /*
+ * Do CTR encryption or decryption and CBC-MAC for all full blocks
+ * except the last.
+ */
+ ptr = len & (size_t)15;
+ if (ptr == 0) {
+ len -= 16;
+ ptr = 16;
+ } else {
+ len -= ptr;
+ }
+ if (encrypt) {
+ (*ctx->bctx)->encrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
+ dbuf, len);
+ } else {
+ (*ctx->bctx)->decrypt(ctx->bctx, ctx->ctr, ctx->cbcmac,
+ dbuf, len);
+ }
+ dbuf += len;
+
+ /*
+ * Compute next block of CTR stream, and use it to finish
+ * encrypting or decrypting the data.
+ */
+ memset(ctx->buf, 0, sizeof ctx->buf);
+ (*ctx->bctx)->ctr(ctx->bctx, ctx->ctr, ctx->buf, sizeof ctx->buf);
+ if (encrypt) {
+ size_t u;
+
+ for (u = 0; u < ptr; u ++) {
+ ctx->buf[u] ^= dbuf[u];
+ }
+ memcpy(dbuf, ctx->buf, ptr);
+ } else {
+ size_t u;
+
+ for (u = 0; u < ptr; u ++) {
+ unsigned dx, sx;
+
+ sx = ctx->buf[u];
+ dx = dbuf[u];
+ ctx->buf[u] = dx;
+ dbuf[u] = sx ^ dx;
+ }
+ }
+ ctx->ptr = ptr;
+}
+
+/*
+ * Complete tag computation. The final tag is written in ctx->cbcmac.
+ */
+static void
+do_final(br_eax_context *ctx)
+{
+ size_t u;
+
+ do_pad(ctx);
+
+ /*
+ * Authentication tag is the XOR of the three OMAC outputs for
+ * the nonce, AAD and encrypted data.
+ */
+ for (u = 0; u < 16; u ++) {
+ ctx->cbcmac[u] ^= ctx->nonce[u] ^ ctx->head[u];
+ }
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_get_tag(br_eax_context *ctx, void *tag)
+{
+ do_final(ctx);
+ memcpy(tag, ctx->cbcmac, sizeof ctx->cbcmac);
+}
+
+/* see bearssl_aead.h */
+void
+br_eax_get_tag_trunc(br_eax_context *ctx, void *tag, size_t len)
+{
+ do_final(ctx);
+ memcpy(tag, ctx->cbcmac, len);
+}
+
+/* see bearssl_aead.h */
+uint32_t
+br_eax_check_tag_trunc(br_eax_context *ctx, const void *tag, size_t len)
+{
+ unsigned char tmp[16];
+ size_t u;
+ int x;
+
+ br_eax_get_tag(ctx, tmp);
+ x = 0;
+ for (u = 0; u < len; u ++) {
+ x |= tmp[u] ^ ((const unsigned char *)tag)[u];
+ }
+ return EQ0(x);
+}
+
+/* see bearssl_aead.h */
+uint32_t
+br_eax_check_tag(br_eax_context *ctx, const void *tag)
+{
+ return br_eax_check_tag_trunc(ctx, tag, 16);
+}
+
+/* see bearssl_aead.h */
+const br_aead_class br_eax_vtable = {
+ 16,
+ (void (*)(const br_aead_class **, const void *, size_t))
+ &br_eax_reset,
+ (void (*)(const br_aead_class **, const void *, size_t))
+ &br_eax_aad_inject,
+ (void (*)(const br_aead_class **))
+ &br_eax_flip,
+ (void (*)(const br_aead_class **, int, void *, size_t))
+ &br_eax_run,
+ (void (*)(const br_aead_class **, void *))
+ &br_eax_get_tag,
+ (uint32_t (*)(const br_aead_class **, const void *))
+ &br_eax_check_tag,
+ (void (*)(const br_aead_class **, void *, size_t))
+ &br_eax_get_tag_trunc,
+ (uint32_t (*)(const br_aead_class **, const void *, size_t))
+ &br_eax_check_tag_trunc
+};
diff --git a/contrib/bearssl/src/aead/gcm.c b/contrib/bearssl/src/aead/gcm.c
new file mode 100644
index 000000000000..ede5f0872dd9
--- /dev/null
+++ b/contrib/bearssl/src/aead/gcm.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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"
+
+/*
+ * Implementation Notes
+ * ====================
+ *
+ * Since CTR and GHASH implementations can handle only full blocks, a
+ * 16-byte buffer (buf[]) is maintained in the context:
+ *
+ * - When processing AAD, buf[] contains the 0-15 unprocessed bytes.
+ *
+ * - When doing CTR encryption / decryption, buf[] contains the AES output
+ * for the last partial block, to be used with the next few bytes of
+ * data, as well as the already encrypted bytes. For instance, if the
+ * processed data length so far is 21 bytes, then buf[0..4] contains
+ * the five last encrypted bytes, and buf[5..15] contains the next 11
+ * AES output bytes to be XORed with the next 11 bytes of input.
+ *
+ * The recorded AES output bytes are used to complete the block when
+ * the corresponding bytes are obtained. Note that buf[] always
+ * contains the _encrypted_ bytes, whether we apply encryption or
+ * decryption: these bytes are used as input to GHASH when the block
+ * is complete.
+ *
+ * In both cases, the low bits of the data length counters (count_aad,
+ * count_ctr) are used to work out the current situation.
+ */
+
+/* see bearssl_aead.h */
+void
+br_gcm_init(br_gcm_context *ctx, const br_block_ctr_class **bctx, br_ghash gh)
+{
+ unsigned char iv[12];
+
+ ctx->vtable = &br_gcm_vtable;
+ ctx->bctx = bctx;
+ ctx->gh = gh;
+
+ /*
+ * The GHASH key h[] is the raw encryption of the all-zero
+ * block. Since we only have a CTR implementation, we use it
+ * with an all-zero IV and a zero counter, to CTR-encrypt an
+ * all-zero block.
+ */
+ memset(ctx->h, 0, sizeof ctx->h);
+ memset(iv, 0, sizeof iv);
+ (*bctx)->run(bctx, iv, 0, ctx->h, sizeof ctx->h);
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_reset(br_gcm_context *ctx, const void *iv, size_t len)
+{
+ /*
+ * If the provided nonce is 12 bytes, then this is the initial
+ * IV for CTR mode; it will be used with a counter that starts
+ * at 2 (value 1 is for encrypting the GHASH output into the tag).
+ *
+ * If the provided nonce has any other length, then it is hashed
+ * (with GHASH) into a 16-byte value that will be the IV for CTR
+ * (both 12-byte IV and 32-bit counter).
+ */
+ if (len == 12) {
+ memcpy(ctx->j0_1, iv, 12);
+ ctx->j0_2 = 1;
+ } else {
+ unsigned char ty[16], tmp[16];
+
+ memset(ty, 0, sizeof ty);
+ ctx->gh(ty, ctx->h, iv, len);
+ memset(tmp, 0, 8);
+ br_enc64be(tmp + 8, (uint64_t)len << 3);
+ ctx->gh(ty, ctx->h, tmp, 16);
+ memcpy(ctx->j0_1, ty, 12);
+ ctx->j0_2 = br_dec32be(ty + 12);
+ }
+ ctx->jc = ctx->j0_2 + 1;
+ memset(ctx->y, 0, sizeof ctx->y);
+ ctx->count_aad = 0;
+ ctx->count_ctr = 0;
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_aad_inject(br_gcm_context *ctx, const void *data, size_t len)
+{
+ size_t ptr, dlen;
+
+ ptr = (size_t)ctx->count_aad & (size_t)15;
+ if (ptr != 0) {
+ /*
+ * If there is a partial block, then we first try to
+ * complete it.
+ */
+ size_t clen;
+
+ clen = 16 - ptr;
+ if (len < clen) {
+ memcpy(ctx->buf + ptr, data, len);
+ ctx->count_aad += (uint64_t)len;
+ return;
+ }
+ memcpy(ctx->buf + ptr, data, clen);
+ ctx->gh(ctx->y, ctx->h, ctx->buf, 16);
+ data = (const unsigned char *)data + clen;
+ len -= clen;
+ ctx->count_aad += (uint64_t)clen;
+ }
+
+ /*
+ * Now AAD is aligned on a 16-byte block (with regards to GHASH).
+ * We process all complete blocks, and save the last partial
+ * block.
+ */
+ dlen = len & ~(size_t)15;
+ ctx->gh(ctx->y, ctx->h, data, dlen);
+ memcpy(ctx->buf, (const unsigned char *)data + dlen, len - dlen);
+ ctx->count_aad += (uint64_t)len;
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_flip(br_gcm_context *ctx)
+{
+ /*
+ * We complete the GHASH computation if there is a partial block.
+ * The GHASH implementation automatically applies padding with
+ * zeros.
+ */
+ size_t ptr;
+
+ ptr = (size_t)ctx->count_aad & (size_t)15;
+ if (ptr != 0) {
+ ctx->gh(ctx->y, ctx->h, ctx->buf, ptr);
+ }
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_run(br_gcm_context *ctx, int encrypt, void *data, size_t len)
+{
+ unsigned char *buf;
+ size_t ptr, dlen;
+
+ buf = data;
+ ptr = (size_t)ctx->count_ctr & (size_t)15;
+ if (ptr != 0) {
+ /*
+ * If we have a partial block, then we try to complete it.
+ */
+ size_t u, clen;
+
+ clen = 16 - ptr;
+ if (len < clen) {
+ clen = len;
+ }
+ for (u = 0; u < clen; u ++) {
+ unsigned x, y;
+
+ x = buf[u];
+ y = x ^ ctx->buf[ptr + u];
+ ctx->buf[ptr + u] = encrypt ? y : x;
+ buf[u] = y;
+ }
+ ctx->count_ctr += (uint64_t)clen;
+ buf += clen;
+ len -= clen;
+ if (ptr + clen < 16) {
+ return;
+ }
+ ctx->gh(ctx->y, ctx->h, ctx->buf, 16);
+ }
+
+ /*
+ * Process full blocks.
+ */
+ dlen = len & ~(size_t)15;
+ if (!encrypt) {
+ ctx->gh(ctx->y, ctx->h, buf, dlen);
+ }
+ ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->jc, buf, dlen);
+ if (encrypt) {
+ ctx->gh(ctx->y, ctx->h, buf, dlen);
+ }
+ buf += dlen;
+ len -= dlen;
+ ctx->count_ctr += (uint64_t)dlen;
+
+ if (len > 0) {
+ /*
+ * There is a partial block.
+ */
+ size_t u;
+
+ memset(ctx->buf, 0, sizeof ctx->buf);
+ ctx->jc = (*ctx->bctx)->run(ctx->bctx, ctx->j0_1,
+ ctx->jc, ctx->buf, 16);
+ for (u = 0; u < len; u ++) {
+ unsigned x, y;
+
+ x = buf[u];
+ y = x ^ ctx->buf[u];
+ ctx->buf[u] = encrypt ? y : x;
+ buf[u] = y;
+ }
+ ctx->count_ctr += (uint64_t)len;
+ }
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_get_tag(br_gcm_context *ctx, void *tag)
+{
+ size_t ptr;
+ unsigned char tmp[16];
+
+ ptr = (size_t)ctx->count_ctr & (size_t)15;
+ if (ptr > 0) {
+ /*
+ * There is a partial block: encrypted/decrypted data has
+ * been produced, but the encrypted bytes must still be
+ * processed by GHASH.
+ */
+ ctx->gh(ctx->y, ctx->h, ctx->buf, ptr);
+ }
+
+ /*
+ * Final block for GHASH: the AAD and plaintext lengths (in bits).
+ */
+ br_enc64be(tmp, ctx->count_aad << 3);
+ br_enc64be(tmp + 8, ctx->count_ctr << 3);
+ ctx->gh(ctx->y, ctx->h, tmp, 16);
+
+ /*
+ * Tag is the GHASH output XORed with the encryption of the
+ * nonce with the initial counter value.
+ */
+ memcpy(tag, ctx->y, 16);
+ (*ctx->bctx)->run(ctx->bctx, ctx->j0_1, ctx->j0_2, tag, 16);
+}
+
+/* see bearssl_aead.h */
+void
+br_gcm_get_tag_trunc(br_gcm_context *ctx, void *tag, size_t len)
+{
+ unsigned char tmp[16];
+
+ br_gcm_get_tag(ctx, tmp);
+ memcpy(tag, tmp, len);
+}
+
+/* see bearssl_aead.h */
+uint32_t
+br_gcm_check_tag_trunc(br_gcm_context *ctx, const void *tag, size_t len)
+{
+ unsigned char tmp[16];
+ size_t u;
+ int x;
+
+ br_gcm_get_tag(ctx, tmp);
+ x = 0;
+ for (u = 0; u < len; u ++) {
+ x |= tmp[u] ^ ((const unsigned char *)tag)[u];
+ }
+ return EQ0(x);
+}
+
+/* see bearssl_aead.h */
+uint32_t
+br_gcm_check_tag(br_gcm_context *ctx, const void *tag)
+{
+ return br_gcm_check_tag_trunc(ctx, tag, 16);
+}
+
+/* see bearssl_aead.h */
+const br_aead_class br_gcm_vtable = {
+ 16,
+ (void (*)(const br_aead_class **, const void *, size_t))
+ &br_gcm_reset,
+ (void (*)(const br_aead_class **, const void *, size_t))
+ &br_gcm_aad_inject,
+ (void (*)(const br_aead_class **))
+ &br_gcm_flip,
+ (void (*)(const br_aead_class **, int, void *, size_t))
+ &br_gcm_run,
+ (void (*)(const br_aead_class **, void *))
+ &br_gcm_get_tag,
+ (uint32_t (*)(const br_aead_class **, const void *))
+ &br_gcm_check_tag,
+ (void (*)(const br_aead_class **, void *, size_t))
+ &br_gcm_get_tag_trunc,
+ (uint32_t (*)(const br_aead_class **, const void *, size_t))
+ &br_gcm_check_tag_trunc
+};
diff --git a/contrib/bearssl/src/codec/ccopy.c b/contrib/bearssl/src/codec/ccopy.c
new file mode 100644
index 000000000000..2beace723b03
--- /dev/null
+++ b/contrib/bearssl/src/codec/ccopy.c
@@ -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 ++;
+ }
+}
diff --git a/contrib/bearssl/src/codec/dec16be.c b/contrib/bearssl/src/codec/dec16be.c
new file mode 100644
index 000000000000..4f3f7f4a0c34
--- /dev/null
+++ b/contrib/bearssl/src/codec/dec16be.c
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/src/codec/dec16le.c b/contrib/bearssl/src/codec/dec16le.c
new file mode 100644
index 000000000000..84d85364a257
--- /dev/null
+++ b/contrib/bearssl/src/codec/dec16le.c
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/src/codec/dec32be.c b/contrib/bearssl/src/codec/dec32be.c
new file mode 100644
index 000000000000..5a8fc596c5a7
--- /dev/null
+++ b/contrib/bearssl/src/codec/dec32be.c
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/src/codec/dec32le.c b/contrib/bearssl/src/codec/dec32le.c
new file mode 100644
index 000000000000..ed36e7189bd7
--- /dev/null
+++ b/contrib/bearssl/src/codec/dec32le.c
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/src/codec/dec64be.c b/contrib/bearssl/src/codec/dec64be.c
new file mode 100644
index 000000000000..0c40a76d584b
--- /dev/null
+++ b/contrib/bearssl/src/codec/dec64be.c
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/src/codec/dec64le.c b/contrib/bearssl/src/codec/dec64le.c
new file mode 100644
index 000000000000..cbd02c2cc0b8
--- /dev/null
+++ b/contrib/bearssl/src/codec/dec64le.c
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/src/codec/enc16be.c b/contrib/bearssl/src/codec/enc16be.c
new file mode 100644
index 000000000000..6e06652193ff
--- /dev/null
+++ b/contrib/bearssl/src/codec/enc16be.c
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/src/codec/enc16le.c b/contrib/bearssl/src/codec/enc16le.c
new file mode 100644
index 000000000000..3e5049a039f8
--- /dev/null
+++ b/contrib/bearssl/src/codec/enc16le.c
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/src/codec/enc32be.c b/contrib/bearssl/src/codec/enc32be.c
new file mode 100644
index 000000000000..97298b5ee14a
--- /dev/null
+++ b/contrib/bearssl/src/codec/enc32be.c
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/src/codec/enc32le.c b/contrib/bearssl/src/codec/enc32le.c
new file mode 100644
index 000000000000..9e9c8562642f
--- /dev/null
+++ b/contrib/bearssl/src/codec/enc32le.c
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/src/codec/enc64be.c b/contrib/bearssl/src/codec/enc64be.c
new file mode 100644
index 000000000000..d548944c210a
--- /dev/null
+++ b/contrib/bearssl/src/codec/enc64be.c
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/src/codec/enc64le.c b/contrib/bearssl/src/codec/enc64le.c
new file mode 100644
index 000000000000..1f1d68ebb7e8
--- /dev/null
+++ b/contrib/bearssl/src/codec/enc64le.c
@@ -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;
+ }
+}
diff --git a/contrib/bearssl/src/codec/pemdec.c b/contrib/bearssl/src/codec/pemdec.c
new file mode 100644
index 000000000000..8e54e6d0d475
--- /dev/null
+++ b/contrib/bearssl/src/codec/pemdec.c
@@ -0,0 +1,526 @@
+/* Automatically generated code; do not modify directly. */
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+} t0_context;
+
+static uint32_t
+t0_parse7E_unsigned(const unsigned char **p)
+{
+ uint32_t x;
+
+ x = 0;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ return x;
+ }
+ }
+}
+
+static int32_t
+t0_parse7E_signed(const unsigned char **p)
+{
+ int neg;
+ uint32_t x;
+
+ neg = ((**p) >> 6) & 1;
+ x = (uint32_t)-neg;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ if (neg) {
+ return -(int32_t)~x - 1;
+ } else {
+ return (int32_t)x;
+ }
+ }
+ }
+}
+
+#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80)
+#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F)
+#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8)
+#define T0_INT1(x) T0_FBYTE(x, 0)
+#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+
+/* static const unsigned char t0_datablock[]; */
+
+
+void br_pem_decoder_init_main(void *t0ctx);
+
+void br_pem_decoder_run(void *t0ctx);
+
+
+
+#include "inner.h"
+
+#define CTX ((br_pem_decoder_context *)(void *)((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 unsigned char 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 unsigned char 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, 0x25, 0x01, 0x00, 0x18, 0x0D, 0x06, 0x03,
+ 0x13, 0x04, 0x3C, 0x01, 0x7F, 0x18, 0x0D, 0x06, 0x13, 0x13, 0x02, 0x00,
+ 0x05, 0x06, 0x2E, 0x01, 0x03, 0x2D, 0x04, 0x03, 0x01, 0x7F, 0x23, 0x01,
+ 0x00, 0x00, 0x04, 0x23, 0x01, 0x01, 0x18, 0x0D, 0x06, 0x09, 0x13, 0x01,
+ 0x00, 0x23, 0x01, 0x00, 0x00, 0x04, 0x14, 0x01, 0x02, 0x18, 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, 0x16, 0x14, 0x1D, 0x06, 0x05, 0x13, 0x2E, 0x01, 0x03, 0x00,
+ 0x03, 0x00, 0x29, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x04, 0x13, 0x01, 0x03,
+ 0x00, 0x16, 0x14, 0x1D, 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, 0x1C, 0x01, 0x01, 0x00, 0x16, 0x14,
+ 0x1D, 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, 0x1C, 0x02, 0x00, 0x01, 0x02,
+ 0x0F, 0x1C, 0x01, 0x01, 0x00, 0x16, 0x14, 0x1D, 0x06, 0x05, 0x13, 0x2E,
+ 0x01, 0x03, 0x00, 0x02, 0x00, 0x01, 0x06, 0x0A, 0x07, 0x03, 0x00, 0x02,
+ 0x00, 0x01, 0x10, 0x0F, 0x1C, 0x02, 0x00, 0x01, 0x08, 0x0F, 0x1C, 0x02,
+ 0x00, 0x1C, 0x01, 0x00, 0x00, 0x00, 0x28, 0x01, 0x01, 0x2D, 0x24, 0x06,
+ 0x02, 0x04, 0x7B, 0x04, 0x75, 0x00, 0x14, 0x12, 0x2A, 0x14, 0x05, 0x04,
+ 0x20, 0x01, 0x7F, 0x00, 0x2C, 0x2A, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x05,
+ 0x13, 0x20, 0x01, 0x00, 0x00, 0x0D, 0x05, 0x05, 0x13, 0x2E, 0x01, 0x00,
+ 0x00, 0x1E, 0x04, 0x5E, 0x00, 0x01, 0x01, 0x27, 0x06, 0x0B, 0x22, 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, 0x1B, 0x01, 0x80, 0x7A, 0x0B, 0x10, 0x06, 0x03,
+ 0x01, 0x20, 0x08, 0x00, 0x01, 0x14, 0x03, 0x00, 0x1B, 0x18, 0x05, 0x05,
+ 0x20, 0x2E, 0x01, 0x00, 0x00, 0x2C, 0x14, 0x01, 0x0A, 0x0D, 0x06, 0x06,
+ 0x20, 0x02, 0x00, 0x1B, 0x08, 0x00, 0x14, 0x01, 0x0D, 0x0D, 0x06, 0x03,
+ 0x13, 0x04, 0x03, 0x2A, 0x18, 0x1A, 0x1E, 0x1B, 0x1F, 0x1B, 0x04, 0x59,
+ 0x00, 0x19, 0x14, 0x1D, 0x05, 0x01, 0x00, 0x13, 0x11, 0x04, 0x76, 0x00,
+ 0x21, 0x1A, 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, 0x1F, 0x14, 0x22, 0x07, 0x17,
+ 0x01, 0x2D, 0x0C, 0x06, 0x08, 0x22, 0x07, 0x1E, 0x01, 0x00, 0x1B, 0x1A,
+ 0x00, 0x04, 0x69, 0x22, 0x1A, 0x00, 0x00, 0x14, 0x01, 0x0A, 0x0C, 0x1B,
+ 0x01, 0x20, 0x0B, 0x10, 0x00
+};
+
+static const uint16_t t0_caddr[] = {
+ 0,
+ 5,
+ 10,
+ 15,
+ 19,
+ 24,
+ 29,
+ 67,
+ 149,
+ 384,
+ 396,
+ 431,
+ 450,
+ 460,
+ 479,
+ 523,
+ 534,
+ 539,
+ 549,
+ 574,
+ 601
+};
+
+#define T0_INTERPRETED 29
+
+#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)
+
+#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++)
+
+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() goto t0_next
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ goto t0_next;
+ for (;;) {
+ uint32_t t0x;
+
+ t0_next:
+ t0x = T0_NEXT(&ip);
+ if (t0x < T0_INTERPRETED) {
+ switch (t0x) {
+ int32_t t0off;
+
+ case 0: /* ret */
+ t0x = T0_RPOP();
+ rp -= (t0x >> 16);
+ t0x &= 0xFFFF;
+ if (t0x == 0) {
+ ip = NULL;
+ goto t0_exit;
+ }
+ ip = &t0_codeblock[t0x];
+ break;
+ case 1: /* literal constant */
+ T0_PUSHi(t0_parse7E_signed(&ip));
+ break;
+ case 2: /* read local */
+ T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip)));
+ break;
+ case 3: /* write local */
+ T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP();
+ break;
+ case 4: /* jump */
+ t0off = t0_parse7E_signed(&ip);
+ ip += t0off;
+ break;
+ case 5: /* jump if */
+ t0off = t0_parse7E_signed(&ip);
+ if (T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 6: /* jump if not */
+ t0off = t0_parse7E_signed(&ip);
+ if (!T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 7: {
+ /* + */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a + b);
+
+ }
+ break;
+ case 8: {
+ /* - */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a - b);
+
+ }
+ break;
+ case 9: {
+ /* < */
+
+ 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) {
+ if (CTX->dest) {
+ CTX->dest(CTX->dest_ctx, CTX->buf, CTX->ptr);
+ }
+ CTX->ptr = 0;
+ }
+
+ }
+ break;
+ case 22: {
+ /* from-base64 */
+
+ uint32_t c = T0_POP();
+ uint32_t p, q, r, z;
+ p = c - 0x41;
+ q = c - 0x61;
+ r = c - 0x30;
+
+ z = ((p + 2) & -LT(p, 26))
+ | ((q + 28) & -LT(q, 26))
+ | ((r + 54) & -LT(r, 10))
+ | (64 & -EQ(c, 0x2B))
+ | (65 & -EQ(c, 0x2F))
+ | EQ(c, 0x3D);
+ T0_PUSHi((int32_t)z - 2);
+
+ }
+ break;
+ case 23: {
+ /* get8 */
+
+ size_t addr = T0_POP();
+ T0_PUSH(*((unsigned char *)CTX + addr));
+
+ }
+ break;
+ case 24: {
+ /* over */
+ T0_PUSH(T0_PEEK(1));
+ }
+ break;
+ case 25: {
+ /* read8-native */
+
+ if (CTX->hlen > 0) {
+ T0_PUSH(*CTX->hbuf ++);
+ CTX->hlen --;
+ } else {
+ T0_PUSHi(-1);
+ }
+
+ }
+ break;
+ case 26: {
+ /* set8 */
+
+ size_t addr = T0_POP();
+ unsigned x = T0_POP();
+ *((unsigned char *)CTX + addr) = x;
+
+ }
+ break;
+ case 27: {
+ /* swap */
+ T0_SWAP();
+ }
+ break;
+ case 28: {
+ /* 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;
+}
diff --git a/contrib/bearssl/src/codec/pemdec.t0 b/contrib/bearssl/src/codec/pemdec.t0
new file mode 100644
index 000000000000..2237abbfe00b
--- /dev/null
+++ b/contrib/bearssl/src/codec/pemdec.t0
@@ -0,0 +1,314 @@
+\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+\
+\ Permission is hereby granted, free of charge, to any person obtaining
+\ a copy of this software and associated documentation files (the
+\ "Software"), to deal in the Software without restriction, including
+\ without limitation the rights to use, copy, modify, merge, publish,
+\ distribute, sublicense, and/or sell copies of the Software, and to
+\ permit persons to whom the Software is furnished to do so, subject to
+\ the following conditions:
+\
+\ The above copyright notice and this permission notice shall be
+\ included in all copies or substantial portions of the Software.
+\
+\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+\ ACTION 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 *)(void *)((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
+ dup `\r = if drop else norm-upper over set8 then
+ 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.
+cc: from-base64 ( char -- x ) {
+ uint32_t c = T0_POP();
+ uint32_t p, q, r, z;
+ p = c - 0x41;
+ q = c - 0x61;
+ r = c - 0x30;
+
+ z = ((p + 2) & -LT(p, 26))
+ | ((q + 28) & -LT(q, 26))
+ | ((r + 54) & -LT(r, 10))
+ | (64 & -EQ(c, 0x2B))
+ | (65 & -EQ(c, 0x2F))
+ | EQ(c, 0x3D);
+ T0_PUSHi((int32_t)z - 2);
+}
+
+\ 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) {
+ if (CTX->dest) {
+ 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 ;
diff --git a/contrib/bearssl/src/codec/pemenc.c b/contrib/bearssl/src/codec/pemenc.c
new file mode 100644
index 000000000000..236601e60d45
--- /dev/null
+++ b/contrib/bearssl/src/codec/pemenc.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * Get the appropriate Base64 character for a numeric value in the
+ * 0..63 range. This is constant-time.
+ */
+static char
+b64char(uint32_t x)
+{
+ /*
+ * Values 0 to 25 map to 0x41..0x5A ('A' to 'Z')
+ * Values 26 to 51 map to 0x61..0x7A ('a' to 'z')
+ * Values 52 to 61 map to 0x30..0x39 ('0' to '9')
+ * Value 62 maps to 0x2B ('+')
+ * Value 63 maps to 0x2F ('/')
+ */
+ uint32_t a, b, c;
+
+ a = x - 26;
+ b = x - 52;
+ c = x - 62;
+
+ /*
+ * Looking at bits 8..15 of values a, b and c:
+ *
+ * x a b c
+ * ---------------------
+ * 0..25 FF FF FF
+ * 26..51 00 FF FF
+ * 52..61 00 00 FF
+ * 62..63 00 00 00
+ */
+ return (char)(((x + 0x41) & ((a & b & c) >> 8))
+ | ((x + (0x61 - 26)) & ((~a & b & c) >> 8))
+ | ((x - (52 - 0x30)) & ((~a & ~b & c) >> 8))
+ | ((0x2B + ((x & 1) << 2)) & (~(a | b | c) >> 8)));
+}
+
+/* see bearssl_pem.h */
+size_t
+br_pem_encode(void *dest, const void *data, size_t len,
+ const char *banner, unsigned flags)
+{
+ size_t dlen, banner_len, lines;
+ char *d;
+ unsigned char *buf;
+ size_t u;
+ int off, lim;
+
+ banner_len = strlen(banner);
+ /* FIXME: try to avoid divisions here, as they may pull
+ an extra libc function. */
+ if ((flags & BR_PEM_LINE64) != 0) {
+ lines = (len + 47) / 48;
+ } else {
+ lines = (len + 56) / 57;
+ }
+ dlen = (banner_len << 1) + 30 + (((len + 2) / 3) << 2)
+ + lines + 2;
+ if ((flags & BR_PEM_CRLF) != 0) {
+ dlen += lines + 2;
+ }
+
+ if (dest == NULL) {
+ return dlen;
+ }
+
+ d = dest;
+
+ /*
+ * We always move the source data to the end of output buffer;
+ * the encoding process never "catches up" except at the very
+ * end. This also handles all conditions of partial or total
+ * overlap.
+ */
+ buf = (unsigned char *)d + dlen - len;
+ memmove(buf, data, len);
+
+ memcpy(d, "-----BEGIN ", 11);
+ d += 11;
+ memcpy(d, banner, banner_len);
+ d += banner_len;
+ memcpy(d, "-----", 5);
+ d += 5;
+ if ((flags & BR_PEM_CRLF) != 0) {
+ *d ++ = 0x0D;
+ }
+ *d ++ = 0x0A;
+
+ off = 0;
+ lim = (flags & BR_PEM_LINE64) != 0 ? 16 : 19;
+ for (u = 0; (u + 2) < len; u += 3) {
+ uint32_t w;
+
+ w = ((uint32_t)buf[u] << 16)
+ | ((uint32_t)buf[u + 1] << 8)
+ | (uint32_t)buf[u + 2];
+ *d ++ = b64char(w >> 18);
+ *d ++ = b64char((w >> 12) & 0x3F);
+ *d ++ = b64char((w >> 6) & 0x3F);
+ *d ++ = b64char(w & 0x3F);
+ if (++ off == lim) {
+ off = 0;
+ if ((flags & BR_PEM_CRLF) != 0) {
+ *d ++ = 0x0D;
+ }
+ *d ++ = 0x0A;
+ }
+ }
+ if (u < len) {
+ uint32_t w;
+
+ w = (uint32_t)buf[u] << 16;
+ if (u + 1 < len) {
+ w |= (uint32_t)buf[u + 1] << 8;
+ }
+ *d ++ = b64char(w >> 18);
+ *d ++ = b64char((w >> 12) & 0x3F);
+ if (u + 1 < len) {
+ *d ++ = b64char((w >> 6) & 0x3F);
+ } else {
+ *d ++ = 0x3D;
+ }
+ *d ++ = 0x3D;
+ off ++;
+ }
+ if (off != 0) {
+ if ((flags & BR_PEM_CRLF) != 0) {
+ *d ++ = 0x0D;
+ }
+ *d ++ = 0x0A;
+ }
+
+ memcpy(d, "-----END ", 9);
+ d += 9;
+ memcpy(d, banner, banner_len);
+ d += banner_len;
+ memcpy(d, "-----", 5);
+ d += 5;
+ if ((flags & BR_PEM_CRLF) != 0) {
+ *d ++ = 0x0D;
+ }
+ *d ++ = 0x0A;
+
+ /* Final zero, not counted in returned length. */
+ *d ++ = 0x00;
+
+ return dlen;
+}
diff --git a/contrib/bearssl/src/config.h b/contrib/bearssl/src/config.h
new file mode 100644
index 000000000000..8ea4d8af8d61
--- /dev/null
+++ b/contrib/bearssl/src/config.h
@@ -0,0 +1,229 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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_LOMUL is enabled, then multiplications of 32-bit values whose
+ * result are truncated to the low 32 bits are assumed to be
+ * substantially more efficient than 32-bit multiplications that yield
+ * 64-bit results. This is typically the case on low-end ARM Cortex M
+ * systems (M0, M0+, M1, and arguably M3 and M4 as well).
+ *
+#define BR_LOMUL 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_SLOW_MUL15 is enabled, short multplications (on 15-bit words)
+ * are assumed to be substantially slow with regards to other integer
+ * operations, thus making it worth to make more integer operations if
+ * it allows using less multiplications.
+ *
+#define BR_SLOW_MUL15 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_CT_MUL15 is enabled, multiplications of 15-bit values (held
+ * in 32-bit words) use an alternate implementation which is slower and
+ * larger than the normal multiplication, but should ensure
+ * constant-time multiplications on most/all architectures where the
+ * basic multiplication is not constant-time.
+#define BR_CT_MUL15 1
+ */
+
+/*
+ * When BR_NO_ARITH_SHIFT is enabled, arithmetic right shifts (with sign
+ * extension) are performed with a sequence of operations which is bigger
+ * and slower than a simple right shift on a signed value. This avoids
+ * relying on an implementation-defined behaviour. However, most if not
+ * all C compilers use sign extension for right shifts on signed values,
+ * so this alternate macro is disabled by default.
+#define BR_NO_ARITH_SHIFT 1
+ */
+
+/*
+ * When BR_RDRAND is enabled, the SSL engine will use the RDRAND opcode
+ * to automatically obtain quality randomness for seeding its internal
+ * PRNG. Since that opcode is present only in recent x86 CPU, its
+ * support is dynamically tested; if the current CPU does not support
+ * it, then another random source will be used, such as /dev/urandom or
+ * CryptGenRandom().
+ *
+#define BR_RDRAND 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
+ */
+
+/*
+ * When BR_ARMEL_CORTEXM_GCC is enabled, some operations are replaced with
+ * inline assembly which is shorter and/or faster. This should be used
+ * only when all of the following are true:
+ * - target architecture is ARM in Thumb mode
+ * - target endianness is little-endian
+ * - compiler is GCC (or GCC-compatible for inline assembly syntax)
+ *
+ * This is meant for the low-end cores (Cortex M0, M0+, M1, M3).
+ * Note: if BR_LOMUL is not explicitly enabled or disabled, then
+ * enabling BR_ARMEL_CORTEXM_GCC also enables BR_LOMUL.
+ *
+#define BR_ARMEL_CORTEXM_GCC 1
+ */
+
+/*
+ * When BR_AES_X86NI is enabled, the AES implementation using the x86 "NI"
+ * instructions (dedicated AES opcodes) will be compiled. If this is not
+ * enabled explicitly, then that AES implementation will be compiled only
+ * if a compatible compiler is detected. If set explicitly to 0, the
+ * implementation will not be compiled at all.
+ *
+#define BR_AES_X86NI 1
+ */
+
+/*
+ * When BR_SSE2 is enabled, SSE2 intrinsics will be used for some
+ * algorithm implementations that use them (e.g. chacha20_sse2). If this
+ * is not enabled explicitly, then support for SSE2 intrinsics will be
+ * automatically detected. If set explicitly to 0, then SSE2 code will
+ * not be compiled at all.
+ *
+#define BR_SSE2 1
+ */
+
+/*
+ * When BR_POWER8 is enabled, the AES implementation using the POWER ISA
+ * 2.07 opcodes (available on POWER8 processors and later) is compiled.
+ * If this is not enabled explicitly, then that implementation will be
+ * compiled only if a compatible compiler is detected, _and_ the target
+ * architecture is POWER8 or later.
+ *
+#define BR_POWER8 1
+ */
+
+/*
+ * When BR_INT128 is enabled, then code using the 'unsigned __int64'
+ * and 'unsigned __int128' types will be used to leverage 64x64->128
+ * unsigned multiplications. This should work with GCC and compatible
+ * compilers on 64-bit architectures.
+ *
+#define BR_INT128 1
+ */
+
+/*
+ * When BR_UMUL128 is enabled, then code using the '_umul128()' and
+ * '_addcarry_u64()' intrinsics will be used to implement 64x64->128
+ * unsigned multiplications. This should work on Visual C on x64 systems.
+ *
+#define BR_UMUL128 1
+ */
+
+/*
+ * When BR_LE_UNALIGNED is enabled, then the current architecture is
+ * assumed to use little-endian encoding for integers, and to tolerate
+ * unaligned accesses with no or minimal time penalty.
+ *
+#define BR_LE_UNALIGNED 1
+ */
+
+/*
+ * When BR_BE_UNALIGNED is enabled, then the current architecture is
+ * assumed to use big-endian encoding for integers, and to tolerate
+ * unaligned accesses with no or minimal time penalty.
+ *
+#define BR_BE_UNALIGNED 1
+ */
+
+#endif
diff --git a/contrib/bearssl/src/ec/ec_all_m15.c b/contrib/bearssl/src/ec/ec_all_m15.c
new file mode 100644
index 000000000000..bb550e1851b1
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_all_m15.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 *
+api_generator(int curve, size_t *len)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+ return br_ec_p256_m15.generator(curve, len);
+ case BR_EC_curve25519:
+ return br_ec_c25519_m15.generator(curve, len);
+ default:
+ return br_ec_prime_i15.generator(curve, len);
+ }
+}
+
+static const unsigned char *
+api_order(int curve, size_t *len)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+ return br_ec_p256_m15.order(curve, len);
+ case BR_EC_curve25519:
+ return br_ec_c25519_m15.order(curve, len);
+ default:
+ return br_ec_prime_i15.order(curve, len);
+ }
+}
+
+static size_t
+api_xoff(int curve, size_t *len)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+ return br_ec_p256_m15.xoff(curve, len);
+ case BR_EC_curve25519:
+ return br_ec_c25519_m15.xoff(curve, len);
+ default:
+ return br_ec_prime_i15.xoff(curve, len);
+ }
+}
+
+static uint32_t
+api_mul(unsigned char *G, size_t Glen,
+ const unsigned char *kb, size_t kblen, int curve)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+ return br_ec_p256_m15.mul(G, Glen, kb, kblen, curve);
+ case BR_EC_curve25519:
+ return br_ec_c25519_m15.mul(G, Glen, kb, kblen, curve);
+ default:
+ return br_ec_prime_i15.mul(G, Glen, kb, kblen, curve);
+ }
+}
+
+static size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+ return br_ec_p256_m15.mulgen(R, x, xlen, curve);
+ case BR_EC_curve25519:
+ return br_ec_c25519_m15.mulgen(R, x, xlen, curve);
+ default:
+ return br_ec_prime_i15.mulgen(R, x, xlen, curve);
+ }
+}
+
+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)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+ return br_ec_p256_m15.muladd(A, B, len,
+ x, xlen, y, ylen, curve);
+ case BR_EC_curve25519:
+ return br_ec_c25519_m15.muladd(A, B, len,
+ x, xlen, y, ylen, curve);
+ default:
+ return br_ec_prime_i15.muladd(A, B, len,
+ x, xlen, y, ylen, curve);
+ }
+}
+
+/* see bearssl_ec.h */
+const br_ec_impl br_ec_all_m15 = {
+ (uint32_t)0x23800000,
+ &api_generator,
+ &api_order,
+ &api_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
diff --git a/contrib/bearssl/src/ec/ec_all_m31.c b/contrib/bearssl/src/ec/ec_all_m31.c
new file mode 100644
index 000000000000..8fd8c3c064ad
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_all_m31.c
@@ -0,0 +1,171 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 *
+api_generator(int curve, size_t *len)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+#if BR_INT128 || BR_UMUL128
+ return br_ec_p256_m64.generator(curve, len);
+#else
+ return br_ec_p256_m31.generator(curve, len);
+#endif
+ case BR_EC_curve25519:
+#if BR_INT128 || BR_UMUL128
+ return br_ec_c25519_m64.generator(curve, len);
+#else
+ return br_ec_c25519_m31.generator(curve, len);
+#endif
+ default:
+ return br_ec_prime_i31.generator(curve, len);
+ }
+}
+
+static const unsigned char *
+api_order(int curve, size_t *len)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+#if BR_INT128 || BR_UMUL128
+ return br_ec_p256_m64.order(curve, len);
+#else
+ return br_ec_p256_m31.order(curve, len);
+#endif
+ case BR_EC_curve25519:
+#if BR_INT128 || BR_UMUL128
+ return br_ec_c25519_m64.order(curve, len);
+#else
+ return br_ec_c25519_m31.order(curve, len);
+#endif
+ default:
+ return br_ec_prime_i31.order(curve, len);
+ }
+}
+
+static size_t
+api_xoff(int curve, size_t *len)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+#if BR_INT128 || BR_UMUL128
+ return br_ec_p256_m64.xoff(curve, len);
+#else
+ return br_ec_p256_m31.xoff(curve, len);
+#endif
+ case BR_EC_curve25519:
+#if BR_INT128 || BR_UMUL128
+ return br_ec_c25519_m64.xoff(curve, len);
+#else
+ return br_ec_c25519_m31.xoff(curve, len);
+#endif
+ default:
+ return br_ec_prime_i31.xoff(curve, len);
+ }
+}
+
+static uint32_t
+api_mul(unsigned char *G, size_t Glen,
+ const unsigned char *kb, size_t kblen, int curve)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+#if BR_INT128 || BR_UMUL128
+ return br_ec_p256_m64.mul(G, Glen, kb, kblen, curve);
+#else
+ return br_ec_p256_m31.mul(G, Glen, kb, kblen, curve);
+#endif
+ case BR_EC_curve25519:
+#if BR_INT128 || BR_UMUL128
+ return br_ec_c25519_m64.mul(G, Glen, kb, kblen, curve);
+#else
+ return br_ec_c25519_m31.mul(G, Glen, kb, kblen, curve);
+#endif
+ default:
+ return br_ec_prime_i31.mul(G, Glen, kb, kblen, curve);
+ }
+}
+
+static size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+#if BR_INT128 || BR_UMUL128
+ return br_ec_p256_m64.mulgen(R, x, xlen, curve);
+#else
+ return br_ec_p256_m31.mulgen(R, x, xlen, curve);
+#endif
+ case BR_EC_curve25519:
+#if BR_INT128 || BR_UMUL128
+ return br_ec_c25519_m64.mulgen(R, x, xlen, curve);
+#else
+ return br_ec_c25519_m31.mulgen(R, x, xlen, curve);
+#endif
+ default:
+ return br_ec_prime_i31.mulgen(R, x, xlen, curve);
+ }
+}
+
+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)
+{
+ switch (curve) {
+ case BR_EC_secp256r1:
+#if BR_INT128 || BR_UMUL128
+ return br_ec_p256_m64.muladd(A, B, len,
+ x, xlen, y, ylen, curve);
+#else
+ return br_ec_p256_m31.muladd(A, B, len,
+ x, xlen, y, ylen, curve);
+#endif
+ case BR_EC_curve25519:
+#if BR_INT128 || BR_UMUL128
+ return br_ec_c25519_m64.muladd(A, B, len,
+ x, xlen, y, ylen, curve);
+#else
+ return br_ec_c25519_m31.muladd(A, B, len,
+ x, xlen, y, ylen, curve);
+#endif
+ default:
+ return br_ec_prime_i31.muladd(A, B, len,
+ x, xlen, y, ylen, curve);
+ }
+}
+
+/* see bearssl_ec.h */
+const br_ec_impl br_ec_all_m31 = {
+ (uint32_t)0x23800000,
+ &api_generator,
+ &api_order,
+ &api_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
diff --git a/contrib/bearssl/src/ec/ec_c25519_i15.c b/contrib/bearssl/src/ec/ec_c25519_i15.c
new file mode 100644
index 000000000000..8fadcf48039b
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_c25519_i15.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 the field:
+ * - field modulus p = 2^255-19
+ * - R^2 mod p (R = 2^(15k) for the smallest k such that R >= p)
+ */
+
+static const uint16_t C255_P[] = {
+ 0x0110,
+ 0x7FED, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
+ 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
+ 0x7FFF
+};
+
+#define P0I 0x4A1B
+
+static const uint16_t C255_R2[] = {
+ 0x0110,
+ 0x0169, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000
+};
+
+/* obsolete
+#include <stdio.h>
+#include <stdlib.h>
+static void
+print_int_mont(const char *name, const uint16_t *x)
+{
+ uint16_t y[18];
+ unsigned char tmp[32];
+ size_t u;
+
+ printf("%s = ", name);
+ memcpy(y, x, sizeof y);
+ br_i15_from_monty(y, C255_P, P0I);
+ br_i15_encode(tmp, sizeof tmp, y);
+ for (u = 0; u < sizeof tmp; u ++) {
+ printf("%02X", tmp[u]);
+ }
+ printf("\n");
+}
+*/
+
+static const uint16_t C255_A24[] = {
+ 0x0110,
+ 0x45D3, 0x0046, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000
+};
+
+static const unsigned char GEN[] = {
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const unsigned char ORDER[] = {
+ 0x7F, 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
+};
+
+static const unsigned char *
+api_generator(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return GEN;
+}
+
+static const unsigned char *
+api_order(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return ORDER;
+}
+
+static size_t
+api_xoff(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return 0;
+}
+
+static void
+cswap(uint16_t *a, uint16_t *b, uint32_t ctl)
+{
+ int i;
+
+ ctl = -ctl;
+ for (i = 0; i < 18; i ++) {
+ uint32_t aw, bw, tw;
+
+ aw = a[i];
+ bw = b[i];
+ tw = ctl & (aw ^ bw);
+ a[i] = aw ^ tw;
+ b[i] = bw ^ tw;
+ }
+}
+
+static void
+c255_add(uint16_t *d, const uint16_t *a, const uint16_t *b)
+{
+ uint32_t ctl;
+ uint16_t t[18];
+
+ memcpy(t, a, sizeof t);
+ ctl = br_i15_add(t, b, 1);
+ ctl |= NOT(br_i15_sub(t, C255_P, 0));
+ br_i15_sub(t, C255_P, ctl);
+ memcpy(d, t, sizeof t);
+}
+
+static void
+c255_sub(uint16_t *d, const uint16_t *a, const uint16_t *b)
+{
+ uint16_t t[18];
+
+ memcpy(t, a, sizeof t);
+ br_i15_add(t, C255_P, br_i15_sub(t, b, 1));
+ memcpy(d, t, sizeof t);
+}
+
+static void
+c255_mul(uint16_t *d, const uint16_t *a, const uint16_t *b)
+{
+ uint16_t t[18];
+
+ br_i15_montymul(t, a, b, C255_P, P0I);
+ memcpy(d, t, sizeof t);
+}
+
+static void
+byteswap(unsigned char *G)
+{
+ int i;
+
+ for (i = 0; i < 16; i ++) {
+ unsigned char t;
+
+ t = G[i];
+ G[i] = G[31 - i];
+ G[31 - i] = t;
+ }
+}
+
+static uint32_t
+api_mul(unsigned char *G, size_t Glen,
+ const unsigned char *kb, size_t kblen, int curve)
+{
+#define ILEN (18 * sizeof(uint16_t))
+
+ /*
+ * The a[] and b[] arrays have an extra word to allow for
+ * decoding without using br_i15_decode_reduce().
+ */
+ uint16_t x1[18], x2[18], x3[18], z2[18], z3[18];
+ uint16_t a[19], aa[18], b[19], bb[18];
+ uint16_t c[18], d[18], e[18], da[18], cb[18];
+ unsigned char k[32];
+ uint32_t swap;
+ int i;
+
+ (void)curve;
+
+ /*
+ * Points are encoded over exactly 32 bytes. Multipliers must fit
+ * in 32 bytes as well.
+ * RFC 7748 mandates that the high bit of the last point byte must
+ * be ignored/cleared.
+ */
+ if (Glen != 32 || kblen > 32) {
+ return 0;
+ }
+ G[31] &= 0x7F;
+
+ /*
+ * Byteswap the point encoding, because it uses little-endian, and
+ * the generic decoding routine uses big-endian.
+ */
+ byteswap(G);
+
+ /*
+ * Decode the point ('u' coordinate). This should be reduced
+ * modulo p, but we prefer to avoid the dependency on
+ * br_i15_decode_reduce(). Instead, we use br_i15_decode_mod()
+ * with a synthetic modulus of value 2^255 (this must work
+ * since G was truncated to 255 bits), then use a conditional
+ * subtraction. We use br_i15_decode_mod() and not
+ * br_i15_decode(), because the ec_prime_i15 implementation uses
+ * the former but not the latter.
+ * br_i15_decode_reduce(a, G, 32, C255_P);
+ */
+ br_i15_zero(b, 0x111);
+ b[18] = 1;
+ br_i15_decode_mod(a, G, 32, b);
+ a[0] = 0x110;
+ br_i15_sub(a, C255_P, NOT(br_i15_sub(a, C255_P, 0)));
+
+ /*
+ * Initialise variables x1, x2, z2, x3 and z3. We set all of them
+ * into Montgomery representation.
+ */
+ br_i15_montymul(x1, a, C255_R2, C255_P, P0I);
+ memcpy(x3, x1, ILEN);
+ br_i15_zero(z2, C255_P[0]);
+ memcpy(x2, z2, ILEN);
+ x2[1] = 19;
+ memcpy(z3, x2, ILEN);
+
+ memset(k, 0, (sizeof k) - kblen);
+ memcpy(k + (sizeof k) - kblen, kb, kblen);
+ k[31] &= 0xF8;
+ k[0] &= 0x7F;
+ k[0] |= 0x40;
+
+ /* obsolete
+ print_int_mont("x1", x1);
+ */
+
+ swap = 0;
+ for (i = 254; i >= 0; i --) {
+ uint32_t kt;
+
+ kt = (k[31 - (i >> 3)] >> (i & 7)) & 1;
+ swap ^= kt;
+ cswap(x2, x3, swap);
+ cswap(z2, z3, swap);
+ swap = kt;
+
+ /* obsolete
+ print_int_mont("x2", x2);
+ print_int_mont("z2", z2);
+ print_int_mont("x3", x3);
+ print_int_mont("z3", z3);
+ */
+
+ c255_add(a, x2, z2);
+ c255_mul(aa, a, a);
+ c255_sub(b, x2, z2);
+ c255_mul(bb, b, b);
+ c255_sub(e, aa, bb);
+ c255_add(c, x3, z3);
+ c255_sub(d, x3, z3);
+ c255_mul(da, d, a);
+ c255_mul(cb, c, b);
+
+ /* obsolete
+ print_int_mont("a ", a);
+ print_int_mont("aa", aa);
+ print_int_mont("b ", b);
+ print_int_mont("bb", bb);
+ print_int_mont("e ", e);
+ print_int_mont("c ", c);
+ print_int_mont("d ", d);
+ print_int_mont("da", da);
+ print_int_mont("cb", cb);
+ */
+
+ c255_add(x3, da, cb);
+ c255_mul(x3, x3, x3);
+ c255_sub(z3, da, cb);
+ c255_mul(z3, z3, z3);
+ c255_mul(z3, z3, x1);
+ c255_mul(x2, aa, bb);
+ c255_mul(z2, C255_A24, e);
+ c255_add(z2, z2, aa);
+ c255_mul(z2, e, z2);
+
+ /* obsolete
+ print_int_mont("x2", x2);
+ print_int_mont("z2", z2);
+ print_int_mont("x3", x3);
+ print_int_mont("z3", z3);
+ */
+ }
+ cswap(x2, x3, swap);
+ cswap(z2, z3, swap);
+
+ /*
+ * Inverse z2 with a modular exponentiation. This is a simple
+ * square-and-multiply algorithm; we mutualise most non-squarings
+ * since the exponent contains almost only ones.
+ */
+ memcpy(a, z2, ILEN);
+ for (i = 0; i < 15; i ++) {
+ c255_mul(a, a, a);
+ c255_mul(a, a, z2);
+ }
+ memcpy(b, a, ILEN);
+ for (i = 0; i < 14; i ++) {
+ int j;
+
+ for (j = 0; j < 16; j ++) {
+ c255_mul(b, b, b);
+ }
+ c255_mul(b, b, a);
+ }
+ for (i = 14; i >= 0; i --) {
+ c255_mul(b, b, b);
+ if ((0xFFEB >> i) & 1) {
+ c255_mul(b, z2, b);
+ }
+ }
+ c255_mul(b, x2, b);
+
+ /*
+ * To avoid a dependency on br_i15_from_monty(), we use a
+ * Montgomery multiplication with 1.
+ * memcpy(x2, b, ILEN);
+ * br_i15_from_monty(x2, C255_P, P0I);
+ */
+ br_i15_zero(a, C255_P[0]);
+ a[1] = 1;
+ br_i15_montymul(x2, a, b, C255_P, P0I);
+
+ br_i15_encode(G, 32, x2);
+ byteswap(G);
+ return 1;
+
+#undef ILEN
+}
+
+static size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ const unsigned char *G;
+ size_t Glen;
+
+ G = api_generator(curve, &Glen);
+ memcpy(R, G, Glen);
+ api_mul(R, Glen, x, xlen, curve);
+ return Glen;
+}
+
+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)
+{
+ /*
+ * We don't implement this method, since it is used for ECDSA
+ * only, and there is no ECDSA over Curve25519 (which instead
+ * uses EdDSA).
+ */
+ (void)A;
+ (void)B;
+ (void)len;
+ (void)x;
+ (void)xlen;
+ (void)y;
+ (void)ylen;
+ (void)curve;
+ return 0;
+}
+
+/* see bearssl_ec.h */
+const br_ec_impl br_ec_c25519_i15 = {
+ (uint32_t)0x20000000,
+ &api_generator,
+ &api_order,
+ &api_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
diff --git a/contrib/bearssl/src/ec/ec_c25519_i31.c b/contrib/bearssl/src/ec/ec_c25519_i31.c
new file mode 100644
index 000000000000..f8ffc2c243af
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_c25519_i31.c
@@ -0,0 +1,390 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 the field:
+ * - field modulus p = 2^255-19
+ * - R^2 mod p (R = 2^(31k) for the smallest k such that R >= p)
+ */
+
+static const uint32_t C255_P[] = {
+ 0x00000107,
+ 0x7FFFFFED, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF,
+ 0x7FFFFFFF, 0x7FFFFFFF, 0x7FFFFFFF, 0x0000007F
+};
+
+#define P0I 0x286BCA1B
+
+static const uint32_t C255_R2[] = {
+ 0x00000107,
+ 0x00000000, 0x02D20000, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000
+};
+
+static const uint32_t C255_A24[] = {
+ 0x00000107,
+ 0x53000000, 0x0000468B, 0x00000000, 0x00000000, 0x00000000,
+ 0x00000000, 0x00000000, 0x00000000, 0x00000000
+};
+
+/* obsolete
+#include <stdio.h>
+#include <stdlib.h>
+static void
+print_int_mont(const char *name, const uint32_t *x)
+{
+ uint32_t y[10];
+ unsigned char tmp[32];
+ size_t u;
+
+ printf("%s = ", name);
+ memcpy(y, x, sizeof y);
+ br_i31_from_monty(y, C255_P, P0I);
+ br_i31_encode(tmp, sizeof tmp, y);
+ for (u = 0; u < sizeof tmp; u ++) {
+ printf("%02X", tmp[u]);
+ }
+ printf("\n");
+}
+*/
+
+static const unsigned char GEN[] = {
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const unsigned char ORDER[] = {
+ 0x7F, 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
+};
+
+static const unsigned char *
+api_generator(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return GEN;
+}
+
+static const unsigned char *
+api_order(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return ORDER;
+}
+
+static size_t
+api_xoff(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return 0;
+}
+
+static void
+cswap(uint32_t *a, uint32_t *b, uint32_t ctl)
+{
+ int i;
+
+ ctl = -ctl;
+ for (i = 0; i < 10; i ++) {
+ uint32_t aw, bw, tw;
+
+ aw = a[i];
+ bw = b[i];
+ tw = ctl & (aw ^ bw);
+ a[i] = aw ^ tw;
+ b[i] = bw ^ tw;
+ }
+}
+
+static void
+c255_add(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ uint32_t ctl;
+ uint32_t t[10];
+
+ memcpy(t, a, sizeof t);
+ ctl = br_i31_add(t, b, 1);
+ ctl |= NOT(br_i31_sub(t, C255_P, 0));
+ br_i31_sub(t, C255_P, ctl);
+ memcpy(d, t, sizeof t);
+}
+
+static void
+c255_sub(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ uint32_t t[10];
+
+ memcpy(t, a, sizeof t);
+ br_i31_add(t, C255_P, br_i31_sub(t, b, 1));
+ memcpy(d, t, sizeof t);
+}
+
+static void
+c255_mul(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ uint32_t t[10];
+
+ br_i31_montymul(t, a, b, C255_P, P0I);
+ memcpy(d, t, sizeof t);
+}
+
+static void
+byteswap(unsigned char *G)
+{
+ int i;
+
+ for (i = 0; i < 16; i ++) {
+ unsigned char t;
+
+ t = G[i];
+ G[i] = G[31 - i];
+ G[31 - i] = t;
+ }
+}
+
+static uint32_t
+api_mul(unsigned char *G, size_t Glen,
+ const unsigned char *kb, size_t kblen, int curve)
+{
+ uint32_t x1[10], x2[10], x3[10], z2[10], z3[10];
+ uint32_t a[10], aa[10], b[10], bb[10];
+ uint32_t c[10], d[10], e[10], da[10], cb[10];
+ unsigned char k[32];
+ uint32_t swap;
+ int i;
+
+ (void)curve;
+
+ /*
+ * Points are encoded over exactly 32 bytes. Multipliers must fit
+ * in 32 bytes as well.
+ * RFC 7748 mandates that the high bit of the last point byte must
+ * be ignored/cleared.
+ */
+ if (Glen != 32 || kblen > 32) {
+ return 0;
+ }
+ G[31] &= 0x7F;
+
+ /*
+ * Byteswap the point encoding, because it uses little-endian, and
+ * the generic decoding routine uses big-endian.
+ */
+ byteswap(G);
+
+ /*
+ * Decode the point ('u' coordinate). This should be reduced
+ * modulo p, but we prefer to avoid the dependency on
+ * br_i31_decode_reduce(). Instead, we use br_i31_decode_mod()
+ * with a synthetic modulus of value 2^255 (this must work
+ * since G was truncated to 255 bits), then use a conditional
+ * subtraction. We use br_i31_decode_mod() and not
+ * br_i31_decode(), because the ec_prime_i31 implementation uses
+ * the former but not the latter.
+ * br_i31_decode_reduce(a, G, 32, C255_P);
+ */
+ br_i31_zero(b, 0x108);
+ b[9] = 0x0080;
+ br_i31_decode_mod(a, G, 32, b);
+ a[0] = 0x107;
+ br_i31_sub(a, C255_P, NOT(br_i31_sub(a, C255_P, 0)));
+
+ /*
+ * Initialise variables x1, x2, z2, x3 and z3. We set all of them
+ * into Montgomery representation.
+ */
+ br_i31_montymul(x1, a, C255_R2, C255_P, P0I);
+ memcpy(x3, x1, sizeof x1);
+ br_i31_zero(z2, C255_P[0]);
+ memcpy(x2, z2, sizeof z2);
+ x2[1] = 0x13000000;
+ memcpy(z3, x2, sizeof x2);
+
+ /*
+ * kb[] is in big-endian notation, but possibly shorter than k[].
+ */
+ memset(k, 0, (sizeof k) - kblen);
+ memcpy(k + (sizeof k) - kblen, kb, kblen);
+ k[31] &= 0xF8;
+ k[0] &= 0x7F;
+ k[0] |= 0x40;
+
+ /* obsolete
+ print_int_mont("x1", x1);
+ */
+
+ swap = 0;
+ for (i = 254; i >= 0; i --) {
+ uint32_t kt;
+
+ kt = (k[31 - (i >> 3)] >> (i & 7)) & 1;
+ swap ^= kt;
+ cswap(x2, x3, swap);
+ cswap(z2, z3, swap);
+ swap = kt;
+
+ /* obsolete
+ print_int_mont("x2", x2);
+ print_int_mont("z2", z2);
+ print_int_mont("x3", x3);
+ print_int_mont("z3", z3);
+ */
+
+ c255_add(a, x2, z2);
+ c255_mul(aa, a, a);
+ c255_sub(b, x2, z2);
+ c255_mul(bb, b, b);
+ c255_sub(e, aa, bb);
+ c255_add(c, x3, z3);
+ c255_sub(d, x3, z3);
+ c255_mul(da, d, a);
+ c255_mul(cb, c, b);
+
+ /* obsolete
+ print_int_mont("a ", a);
+ print_int_mont("aa", aa);
+ print_int_mont("b ", b);
+ print_int_mont("bb", bb);
+ print_int_mont("e ", e);
+ print_int_mont("c ", c);
+ print_int_mont("d ", d);
+ print_int_mont("da", da);
+ print_int_mont("cb", cb);
+ */
+
+ c255_add(x3, da, cb);
+ c255_mul(x3, x3, x3);
+ c255_sub(z3, da, cb);
+ c255_mul(z3, z3, z3);
+ c255_mul(z3, z3, x1);
+ c255_mul(x2, aa, bb);
+ c255_mul(z2, C255_A24, e);
+ c255_add(z2, z2, aa);
+ c255_mul(z2, e, z2);
+
+ /* obsolete
+ print_int_mont("x2", x2);
+ print_int_mont("z2", z2);
+ print_int_mont("x3", x3);
+ print_int_mont("z3", z3);
+ */
+ }
+ cswap(x2, x3, swap);
+ cswap(z2, z3, swap);
+
+ /*
+ * Inverse z2 with a modular exponentiation. This is a simple
+ * square-and-multiply algorithm; we mutualise most non-squarings
+ * since the exponent contains almost only ones.
+ */
+ memcpy(a, z2, sizeof z2);
+ for (i = 0; i < 15; i ++) {
+ c255_mul(a, a, a);
+ c255_mul(a, a, z2);
+ }
+ memcpy(b, a, sizeof a);
+ for (i = 0; i < 14; i ++) {
+ int j;
+
+ for (j = 0; j < 16; j ++) {
+ c255_mul(b, b, b);
+ }
+ c255_mul(b, b, a);
+ }
+ for (i = 14; i >= 0; i --) {
+ c255_mul(b, b, b);
+ if ((0xFFEB >> i) & 1) {
+ c255_mul(b, z2, b);
+ }
+ }
+ c255_mul(b, x2, b);
+
+ /*
+ * To avoid a dependency on br_i31_from_monty(), we use
+ * a Montgomery multiplication with 1.
+ * memcpy(x2, b, sizeof b);
+ * br_i31_from_monty(x2, C255_P, P0I);
+ */
+ br_i31_zero(a, C255_P[0]);
+ a[1] = 1;
+ br_i31_montymul(x2, a, b, C255_P, P0I);
+
+ br_i31_encode(G, 32, x2);
+ byteswap(G);
+ return 1;
+}
+
+static size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ const unsigned char *G;
+ size_t Glen;
+
+ G = api_generator(curve, &Glen);
+ memcpy(R, G, Glen);
+ api_mul(R, Glen, x, xlen, curve);
+ return Glen;
+}
+
+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)
+{
+ /*
+ * We don't implement this method, since it is used for ECDSA
+ * only, and there is no ECDSA over Curve25519 (which instead
+ * uses EdDSA).
+ */
+ (void)A;
+ (void)B;
+ (void)len;
+ (void)x;
+ (void)xlen;
+ (void)y;
+ (void)ylen;
+ (void)curve;
+ return 0;
+}
+
+/* see bearssl_ec.h */
+const br_ec_impl br_ec_c25519_i31 = {
+ (uint32_t)0x20000000,
+ &api_generator,
+ &api_order,
+ &api_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
diff --git a/contrib/bearssl/src/ec/ec_c25519_m15.c b/contrib/bearssl/src/ec/ec_c25519_m15.c
new file mode 100644
index 000000000000..deff55b330b1
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_c25519_m15.c
@@ -0,0 +1,1478 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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"
+
+/* obsolete
+#include <stdio.h>
+#include <stdlib.h>
+static void
+print_int(const char *name, const uint32_t *x)
+{
+ size_t u;
+ unsigned char tmp[36];
+
+ printf("%s = ", name);
+ for (u = 0; u < 20; u ++) {
+ if (x[u] > 0x1FFF) {
+ printf("INVALID:");
+ for (u = 0; u < 20; u ++) {
+ printf(" %04X", x[u]);
+ }
+ printf("\n");
+ return;
+ }
+ }
+ memset(tmp, 0, sizeof tmp);
+ for (u = 0; u < 20; u ++) {
+ uint32_t w;
+ int j, k;
+
+ w = x[u];
+ j = 13 * (int)u;
+ k = j & 7;
+ if (k != 0) {
+ w <<= k;
+ j -= k;
+ }
+ k = j >> 3;
+ tmp[35 - k] |= (unsigned char)w;
+ tmp[34 - k] |= (unsigned char)(w >> 8);
+ tmp[33 - k] |= (unsigned char)(w >> 16);
+ tmp[32 - k] |= (unsigned char)(w >> 24);
+ }
+ for (u = 4; u < 36; u ++) {
+ printf("%02X", tmp[u]);
+ }
+ printf("\n");
+}
+*/
+
+/*
+ * If BR_NO_ARITH_SHIFT is undefined, or defined to 0, then we _assume_
+ * that right-shifting a signed negative integer copies the sign bit
+ * (arithmetic right-shift). This is "implementation-defined behaviour",
+ * i.e. it is not undefined, but it may differ between compilers. Each
+ * compiler is supposed to document its behaviour in that respect. GCC
+ * explicitly defines that an arithmetic right shift is used. We expect
+ * all other compilers to do the same, because underlying CPU offer an
+ * arithmetic right shift opcode that could not be used otherwise.
+ */
+#if BR_NO_ARITH_SHIFT
+#define ARSH(x, n) (((uint32_t)(x) >> (n)) \
+ | ((-((uint32_t)(x) >> 31)) << (32 - (n))))
+#else
+#define ARSH(x, n) ((*(int32_t *)&(x)) >> (n))
+#endif
+
+/*
+ * Convert an integer from unsigned little-endian encoding to a sequence of
+ * 13-bit words in little-endian order. The final "partial" word is
+ * returned.
+ */
+static uint32_t
+le8_to_le13(uint32_t *dst, const unsigned char *src, size_t len)
+{
+ uint32_t acc;
+ int acc_len;
+
+ acc = 0;
+ acc_len = 0;
+ while (len -- > 0) {
+ acc |= (uint32_t)(*src ++) << acc_len;
+ acc_len += 8;
+ if (acc_len >= 13) {
+ *dst ++ = acc & 0x1FFF;
+ acc >>= 13;
+ acc_len -= 13;
+ }
+ }
+ return acc;
+}
+
+/*
+ * Convert an integer (13-bit words, little-endian) to unsigned
+ * little-endian encoding. The total encoding length is provided; all
+ * the destination bytes will be filled.
+ */
+static void
+le13_to_le8(unsigned char *dst, size_t len, const uint32_t *src)
+{
+ uint32_t acc;
+ int acc_len;
+
+ acc = 0;
+ acc_len = 0;
+ while (len -- > 0) {
+ if (acc_len < 8) {
+ acc |= (*src ++) << acc_len;
+ acc_len += 13;
+ }
+ *dst ++ = (unsigned char)acc;
+ acc >>= 8;
+ acc_len -= 8;
+ }
+}
+
+/*
+ * Normalise an array of words to a strict 13 bits per word. Returned
+ * value is the resulting carry. The source (w) and destination (d)
+ * arrays may be identical, but shall not overlap partially.
+ */
+static inline uint32_t
+norm13(uint32_t *d, const uint32_t *w, size_t len)
+{
+ size_t u;
+ uint32_t cc;
+
+ cc = 0;
+ for (u = 0; u < len; u ++) {
+ int32_t z;
+
+ z = w[u] + cc;
+ d[u] = z & 0x1FFF;
+ cc = ARSH(z, 13);
+ }
+ return cc;
+}
+
+/*
+ * mul20() multiplies two 260-bit integers together. Each word must fit
+ * on 13 bits; source operands use 20 words, destination operand
+ * receives 40 words. All overlaps allowed.
+ *
+ * square20() computes the square of a 260-bit integer. Each word must
+ * fit on 13 bits; source operand uses 20 words, destination operand
+ * receives 40 words. All overlaps allowed.
+ */
+
+#if BR_SLOW_MUL15
+
+static void
+mul20(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ /*
+ * Two-level Karatsuba: turns a 20x20 multiplication into
+ * nine 5x5 multiplications. We use 13-bit words but do not
+ * propagate carries immediately, so words may expand:
+ *
+ * - First Karatsuba decomposition turns the 20x20 mul on
+ * 13-bit words into three 10x10 muls, two on 13-bit words
+ * and one on 14-bit words.
+ *
+ * - Second Karatsuba decomposition further splits these into:
+ *
+ * * four 5x5 muls on 13-bit words
+ * * four 5x5 muls on 14-bit words
+ * * one 5x5 mul on 15-bit words
+ *
+ * Highest word value is 8191, 16382 or 32764, for 13-bit, 14-bit
+ * or 15-bit words, respectively.
+ */
+ uint32_t u[45], v[45], w[90];
+ uint32_t cc;
+ int i;
+
+#define ZADD(dw, d_off, s1w, s1_off, s2w, s2_off) do { \
+ (dw)[5 * (d_off) + 0] = (s1w)[5 * (s1_off) + 0] \
+ + (s2w)[5 * (s2_off) + 0]; \
+ (dw)[5 * (d_off) + 1] = (s1w)[5 * (s1_off) + 1] \
+ + (s2w)[5 * (s2_off) + 1]; \
+ (dw)[5 * (d_off) + 2] = (s1w)[5 * (s1_off) + 2] \
+ + (s2w)[5 * (s2_off) + 2]; \
+ (dw)[5 * (d_off) + 3] = (s1w)[5 * (s1_off) + 3] \
+ + (s2w)[5 * (s2_off) + 3]; \
+ (dw)[5 * (d_off) + 4] = (s1w)[5 * (s1_off) + 4] \
+ + (s2w)[5 * (s2_off) + 4]; \
+ } while (0)
+
+#define ZADDT(dw, d_off, sw, s_off) do { \
+ (dw)[5 * (d_off) + 0] += (sw)[5 * (s_off) + 0]; \
+ (dw)[5 * (d_off) + 1] += (sw)[5 * (s_off) + 1]; \
+ (dw)[5 * (d_off) + 2] += (sw)[5 * (s_off) + 2]; \
+ (dw)[5 * (d_off) + 3] += (sw)[5 * (s_off) + 3]; \
+ (dw)[5 * (d_off) + 4] += (sw)[5 * (s_off) + 4]; \
+ } while (0)
+
+#define ZSUB2F(dw, d_off, s1w, s1_off, s2w, s2_off) do { \
+ (dw)[5 * (d_off) + 0] -= (s1w)[5 * (s1_off) + 0] \
+ + (s2w)[5 * (s2_off) + 0]; \
+ (dw)[5 * (d_off) + 1] -= (s1w)[5 * (s1_off) + 1] \
+ + (s2w)[5 * (s2_off) + 1]; \
+ (dw)[5 * (d_off) + 2] -= (s1w)[5 * (s1_off) + 2] \
+ + (s2w)[5 * (s2_off) + 2]; \
+ (dw)[5 * (d_off) + 3] -= (s1w)[5 * (s1_off) + 3] \
+ + (s2w)[5 * (s2_off) + 3]; \
+ (dw)[5 * (d_off) + 4] -= (s1w)[5 * (s1_off) + 4] \
+ + (s2w)[5 * (s2_off) + 4]; \
+ } while (0)
+
+#define CPR1(w, cprcc) do { \
+ uint32_t cprz = (w) + cprcc; \
+ (w) = cprz & 0x1FFF; \
+ cprcc = cprz >> 13; \
+ } while (0)
+
+#define CPR(dw, d_off) do { \
+ uint32_t cprcc; \
+ cprcc = 0; \
+ CPR1((dw)[(d_off) + 0], cprcc); \
+ CPR1((dw)[(d_off) + 1], cprcc); \
+ CPR1((dw)[(d_off) + 2], cprcc); \
+ CPR1((dw)[(d_off) + 3], cprcc); \
+ CPR1((dw)[(d_off) + 4], cprcc); \
+ CPR1((dw)[(d_off) + 5], cprcc); \
+ CPR1((dw)[(d_off) + 6], cprcc); \
+ CPR1((dw)[(d_off) + 7], cprcc); \
+ CPR1((dw)[(d_off) + 8], cprcc); \
+ (dw)[(d_off) + 9] = cprcc; \
+ } while (0)
+
+ memcpy(u, a, 20 * sizeof *a);
+ ZADD(u, 4, a, 0, a, 1);
+ ZADD(u, 5, a, 2, a, 3);
+ ZADD(u, 6, a, 0, a, 2);
+ ZADD(u, 7, a, 1, a, 3);
+ ZADD(u, 8, u, 6, u, 7);
+
+ memcpy(v, b, 20 * sizeof *b);
+ ZADD(v, 4, b, 0, b, 1);
+ ZADD(v, 5, b, 2, b, 3);
+ ZADD(v, 6, b, 0, b, 2);
+ ZADD(v, 7, b, 1, b, 3);
+ ZADD(v, 8, v, 6, v, 7);
+
+ /*
+ * Do the eight first 8x8 muls. Source words are at most 16382
+ * each, so we can add product results together "as is" in 32-bit
+ * words.
+ */
+ for (i = 0; i < 40; i += 5) {
+ w[(i << 1) + 0] = MUL15(u[i + 0], v[i + 0]);
+ w[(i << 1) + 1] = MUL15(u[i + 0], v[i + 1])
+ + MUL15(u[i + 1], v[i + 0]);
+ w[(i << 1) + 2] = MUL15(u[i + 0], v[i + 2])
+ + MUL15(u[i + 1], v[i + 1])
+ + MUL15(u[i + 2], v[i + 0]);
+ w[(i << 1) + 3] = MUL15(u[i + 0], v[i + 3])
+ + MUL15(u[i + 1], v[i + 2])
+ + MUL15(u[i + 2], v[i + 1])
+ + MUL15(u[i + 3], v[i + 0]);
+ w[(i << 1) + 4] = MUL15(u[i + 0], v[i + 4])
+ + MUL15(u[i + 1], v[i + 3])
+ + MUL15(u[i + 2], v[i + 2])
+ + MUL15(u[i + 3], v[i + 1])
+ + MUL15(u[i + 4], v[i + 0]);
+ w[(i << 1) + 5] = MUL15(u[i + 1], v[i + 4])
+ + MUL15(u[i + 2], v[i + 3])
+ + MUL15(u[i + 3], v[i + 2])
+ + MUL15(u[i + 4], v[i + 1]);
+ w[(i << 1) + 6] = MUL15(u[i + 2], v[i + 4])
+ + MUL15(u[i + 3], v[i + 3])
+ + MUL15(u[i + 4], v[i + 2]);
+ w[(i << 1) + 7] = MUL15(u[i + 3], v[i + 4])
+ + MUL15(u[i + 4], v[i + 3]);
+ w[(i << 1) + 8] = MUL15(u[i + 4], v[i + 4]);
+ w[(i << 1) + 9] = 0;
+ }
+
+ /*
+ * For the 9th multiplication, source words are up to 32764,
+ * so we must do some carry propagation. If we add up to
+ * 4 products and the carry is no more than 524224, then the
+ * result fits in 32 bits, and the next carry will be no more
+ * than 524224 (because 4*(32764^2)+524224 < 8192*524225).
+ *
+ * We thus just skip one of the products in the middle word,
+ * then do a carry propagation (this reduces words to 13 bits
+ * each, except possibly the last, which may use up to 17 bits
+ * or so), then add the missing product.
+ */
+ w[80 + 0] = MUL15(u[40 + 0], v[40 + 0]);
+ w[80 + 1] = MUL15(u[40 + 0], v[40 + 1])
+ + MUL15(u[40 + 1], v[40 + 0]);
+ w[80 + 2] = MUL15(u[40 + 0], v[40 + 2])
+ + MUL15(u[40 + 1], v[40 + 1])
+ + MUL15(u[40 + 2], v[40 + 0]);
+ w[80 + 3] = MUL15(u[40 + 0], v[40 + 3])
+ + MUL15(u[40 + 1], v[40 + 2])
+ + MUL15(u[40 + 2], v[40 + 1])
+ + MUL15(u[40 + 3], v[40 + 0]);
+ w[80 + 4] = MUL15(u[40 + 0], v[40 + 4])
+ + MUL15(u[40 + 1], v[40 + 3])
+ + MUL15(u[40 + 2], v[40 + 2])
+ + MUL15(u[40 + 3], v[40 + 1]);
+ /* + MUL15(u[40 + 4], v[40 + 0]) */
+ w[80 + 5] = MUL15(u[40 + 1], v[40 + 4])
+ + MUL15(u[40 + 2], v[40 + 3])
+ + MUL15(u[40 + 3], v[40 + 2])
+ + MUL15(u[40 + 4], v[40 + 1]);
+ w[80 + 6] = MUL15(u[40 + 2], v[40 + 4])
+ + MUL15(u[40 + 3], v[40 + 3])
+ + MUL15(u[40 + 4], v[40 + 2]);
+ w[80 + 7] = MUL15(u[40 + 3], v[40 + 4])
+ + MUL15(u[40 + 4], v[40 + 3]);
+ w[80 + 8] = MUL15(u[40 + 4], v[40 + 4]);
+
+ CPR(w, 80);
+
+ w[80 + 4] += MUL15(u[40 + 4], v[40 + 0]);
+
+ /*
+ * The products on 14-bit words in slots 6 and 7 yield values
+ * up to 5*(16382^2) each, and we need to subtract two such
+ * values from the higher word. We need the subtraction to fit
+ * in a _signed_ 32-bit integer, i.e. 31 bits + a sign bit.
+ * However, 10*(16382^2) does not fit. So we must perform a
+ * bit of reduction here.
+ */
+ CPR(w, 60);
+ CPR(w, 70);
+
+ /*
+ * Recompose results.
+ */
+
+ /* 0..1*0..1 into 0..3 */
+ ZSUB2F(w, 8, w, 0, w, 2);
+ ZSUB2F(w, 9, w, 1, w, 3);
+ ZADDT(w, 1, w, 8);
+ ZADDT(w, 2, w, 9);
+
+ /* 2..3*2..3 into 4..7 */
+ ZSUB2F(w, 10, w, 4, w, 6);
+ ZSUB2F(w, 11, w, 5, w, 7);
+ ZADDT(w, 5, w, 10);
+ ZADDT(w, 6, w, 11);
+
+ /* (0..1+2..3)*(0..1+2..3) into 12..15 */
+ ZSUB2F(w, 16, w, 12, w, 14);
+ ZSUB2F(w, 17, w, 13, w, 15);
+ ZADDT(w, 13, w, 16);
+ ZADDT(w, 14, w, 17);
+
+ /* first-level recomposition */
+ ZSUB2F(w, 12, w, 0, w, 4);
+ ZSUB2F(w, 13, w, 1, w, 5);
+ ZSUB2F(w, 14, w, 2, w, 6);
+ ZSUB2F(w, 15, w, 3, w, 7);
+ ZADDT(w, 2, w, 12);
+ ZADDT(w, 3, w, 13);
+ ZADDT(w, 4, w, 14);
+ ZADDT(w, 5, w, 15);
+
+ /*
+ * Perform carry propagation to bring all words down to 13 bits.
+ */
+ cc = norm13(d, w, 40);
+ d[39] += (cc << 13);
+
+#undef ZADD
+#undef ZADDT
+#undef ZSUB2F
+#undef CPR1
+#undef CPR
+}
+
+static inline void
+square20(uint32_t *d, const uint32_t *a)
+{
+ mul20(d, a, a);
+}
+
+#else
+
+static void
+mul20(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ uint32_t t[39];
+
+ t[ 0] = MUL15(a[ 0], b[ 0]);
+ t[ 1] = MUL15(a[ 0], b[ 1])
+ + MUL15(a[ 1], b[ 0]);
+ t[ 2] = MUL15(a[ 0], b[ 2])
+ + MUL15(a[ 1], b[ 1])
+ + MUL15(a[ 2], b[ 0]);
+ t[ 3] = MUL15(a[ 0], b[ 3])
+ + MUL15(a[ 1], b[ 2])
+ + MUL15(a[ 2], b[ 1])
+ + MUL15(a[ 3], b[ 0]);
+ t[ 4] = MUL15(a[ 0], b[ 4])
+ + MUL15(a[ 1], b[ 3])
+ + MUL15(a[ 2], b[ 2])
+ + MUL15(a[ 3], b[ 1])
+ + MUL15(a[ 4], b[ 0]);
+ t[ 5] = MUL15(a[ 0], b[ 5])
+ + MUL15(a[ 1], b[ 4])
+ + MUL15(a[ 2], b[ 3])
+ + MUL15(a[ 3], b[ 2])
+ + MUL15(a[ 4], b[ 1])
+ + MUL15(a[ 5], b[ 0]);
+ t[ 6] = MUL15(a[ 0], b[ 6])
+ + MUL15(a[ 1], b[ 5])
+ + MUL15(a[ 2], b[ 4])
+ + MUL15(a[ 3], b[ 3])
+ + MUL15(a[ 4], b[ 2])
+ + MUL15(a[ 5], b[ 1])
+ + MUL15(a[ 6], b[ 0]);
+ t[ 7] = MUL15(a[ 0], b[ 7])
+ + MUL15(a[ 1], b[ 6])
+ + MUL15(a[ 2], b[ 5])
+ + MUL15(a[ 3], b[ 4])
+ + MUL15(a[ 4], b[ 3])
+ + MUL15(a[ 5], b[ 2])
+ + MUL15(a[ 6], b[ 1])
+ + MUL15(a[ 7], b[ 0]);
+ t[ 8] = MUL15(a[ 0], b[ 8])
+ + MUL15(a[ 1], b[ 7])
+ + MUL15(a[ 2], b[ 6])
+ + MUL15(a[ 3], b[ 5])
+ + MUL15(a[ 4], b[ 4])
+ + MUL15(a[ 5], b[ 3])
+ + MUL15(a[ 6], b[ 2])
+ + MUL15(a[ 7], b[ 1])
+ + MUL15(a[ 8], b[ 0]);
+ t[ 9] = MUL15(a[ 0], b[ 9])
+ + MUL15(a[ 1], b[ 8])
+ + MUL15(a[ 2], b[ 7])
+ + MUL15(a[ 3], b[ 6])
+ + MUL15(a[ 4], b[ 5])
+ + MUL15(a[ 5], b[ 4])
+ + MUL15(a[ 6], b[ 3])
+ + MUL15(a[ 7], b[ 2])
+ + MUL15(a[ 8], b[ 1])
+ + MUL15(a[ 9], b[ 0]);
+ t[10] = MUL15(a[ 0], b[10])
+ + MUL15(a[ 1], b[ 9])
+ + MUL15(a[ 2], b[ 8])
+ + MUL15(a[ 3], b[ 7])
+ + MUL15(a[ 4], b[ 6])
+ + MUL15(a[ 5], b[ 5])
+ + MUL15(a[ 6], b[ 4])
+ + MUL15(a[ 7], b[ 3])
+ + MUL15(a[ 8], b[ 2])
+ + MUL15(a[ 9], b[ 1])
+ + MUL15(a[10], b[ 0]);
+ t[11] = MUL15(a[ 0], b[11])
+ + MUL15(a[ 1], b[10])
+ + MUL15(a[ 2], b[ 9])
+ + MUL15(a[ 3], b[ 8])
+ + MUL15(a[ 4], b[ 7])
+ + MUL15(a[ 5], b[ 6])
+ + MUL15(a[ 6], b[ 5])
+ + MUL15(a[ 7], b[ 4])
+ + MUL15(a[ 8], b[ 3])
+ + MUL15(a[ 9], b[ 2])
+ + MUL15(a[10], b[ 1])
+ + MUL15(a[11], b[ 0]);
+ t[12] = MUL15(a[ 0], b[12])
+ + MUL15(a[ 1], b[11])
+ + MUL15(a[ 2], b[10])
+ + MUL15(a[ 3], b[ 9])
+ + MUL15(a[ 4], b[ 8])
+ + MUL15(a[ 5], b[ 7])
+ + MUL15(a[ 6], b[ 6])
+ + MUL15(a[ 7], b[ 5])
+ + MUL15(a[ 8], b[ 4])
+ + MUL15(a[ 9], b[ 3])
+ + MUL15(a[10], b[ 2])
+ + MUL15(a[11], b[ 1])
+ + MUL15(a[12], b[ 0]);
+ t[13] = MUL15(a[ 0], b[13])
+ + MUL15(a[ 1], b[12])
+ + MUL15(a[ 2], b[11])
+ + MUL15(a[ 3], b[10])
+ + MUL15(a[ 4], b[ 9])
+ + MUL15(a[ 5], b[ 8])
+ + MUL15(a[ 6], b[ 7])
+ + MUL15(a[ 7], b[ 6])
+ + MUL15(a[ 8], b[ 5])
+ + MUL15(a[ 9], b[ 4])
+ + MUL15(a[10], b[ 3])
+ + MUL15(a[11], b[ 2])
+ + MUL15(a[12], b[ 1])
+ + MUL15(a[13], b[ 0]);
+ t[14] = MUL15(a[ 0], b[14])
+ + MUL15(a[ 1], b[13])
+ + MUL15(a[ 2], b[12])
+ + MUL15(a[ 3], b[11])
+ + MUL15(a[ 4], b[10])
+ + MUL15(a[ 5], b[ 9])
+ + MUL15(a[ 6], b[ 8])
+ + MUL15(a[ 7], b[ 7])
+ + MUL15(a[ 8], b[ 6])
+ + MUL15(a[ 9], b[ 5])
+ + MUL15(a[10], b[ 4])
+ + MUL15(a[11], b[ 3])
+ + MUL15(a[12], b[ 2])
+ + MUL15(a[13], b[ 1])
+ + MUL15(a[14], b[ 0]);
+ t[15] = MUL15(a[ 0], b[15])
+ + MUL15(a[ 1], b[14])
+ + MUL15(a[ 2], b[13])
+ + MUL15(a[ 3], b[12])
+ + MUL15(a[ 4], b[11])
+ + MUL15(a[ 5], b[10])
+ + MUL15(a[ 6], b[ 9])
+ + MUL15(a[ 7], b[ 8])
+ + MUL15(a[ 8], b[ 7])
+ + MUL15(a[ 9], b[ 6])
+ + MUL15(a[10], b[ 5])
+ + MUL15(a[11], b[ 4])
+ + MUL15(a[12], b[ 3])
+ + MUL15(a[13], b[ 2])
+ + MUL15(a[14], b[ 1])
+ + MUL15(a[15], b[ 0]);
+ t[16] = MUL15(a[ 0], b[16])
+ + MUL15(a[ 1], b[15])
+ + MUL15(a[ 2], b[14])
+ + MUL15(a[ 3], b[13])
+ + MUL15(a[ 4], b[12])
+ + MUL15(a[ 5], b[11])
+ + MUL15(a[ 6], b[10])
+ + MUL15(a[ 7], b[ 9])
+ + MUL15(a[ 8], b[ 8])
+ + MUL15(a[ 9], b[ 7])
+ + MUL15(a[10], b[ 6])
+ + MUL15(a[11], b[ 5])
+ + MUL15(a[12], b[ 4])
+ + MUL15(a[13], b[ 3])
+ + MUL15(a[14], b[ 2])
+ + MUL15(a[15], b[ 1])
+ + MUL15(a[16], b[ 0]);
+ t[17] = MUL15(a[ 0], b[17])
+ + MUL15(a[ 1], b[16])
+ + MUL15(a[ 2], b[15])
+ + MUL15(a[ 3], b[14])
+ + MUL15(a[ 4], b[13])
+ + MUL15(a[ 5], b[12])
+ + MUL15(a[ 6], b[11])
+ + MUL15(a[ 7], b[10])
+ + MUL15(a[ 8], b[ 9])
+ + MUL15(a[ 9], b[ 8])
+ + MUL15(a[10], b[ 7])
+ + MUL15(a[11], b[ 6])
+ + MUL15(a[12], b[ 5])
+ + MUL15(a[13], b[ 4])
+ + MUL15(a[14], b[ 3])
+ + MUL15(a[15], b[ 2])
+ + MUL15(a[16], b[ 1])
+ + MUL15(a[17], b[ 0]);
+ t[18] = MUL15(a[ 0], b[18])
+ + MUL15(a[ 1], b[17])
+ + MUL15(a[ 2], b[16])
+ + MUL15(a[ 3], b[15])
+ + MUL15(a[ 4], b[14])
+ + MUL15(a[ 5], b[13])
+ + MUL15(a[ 6], b[12])
+ + MUL15(a[ 7], b[11])
+ + MUL15(a[ 8], b[10])
+ + MUL15(a[ 9], b[ 9])
+ + MUL15(a[10], b[ 8])
+ + MUL15(a[11], b[ 7])
+ + MUL15(a[12], b[ 6])
+ + MUL15(a[13], b[ 5])
+ + MUL15(a[14], b[ 4])
+ + MUL15(a[15], b[ 3])
+ + MUL15(a[16], b[ 2])
+ + MUL15(a[17], b[ 1])
+ + MUL15(a[18], b[ 0]);
+ t[19] = MUL15(a[ 0], b[19])
+ + MUL15(a[ 1], b[18])
+ + MUL15(a[ 2], b[17])
+ + MUL15(a[ 3], b[16])
+ + MUL15(a[ 4], b[15])
+ + MUL15(a[ 5], b[14])
+ + MUL15(a[ 6], b[13])
+ + MUL15(a[ 7], b[12])
+ + MUL15(a[ 8], b[11])
+ + MUL15(a[ 9], b[10])
+ + MUL15(a[10], b[ 9])
+ + MUL15(a[11], b[ 8])
+ + MUL15(a[12], b[ 7])
+ + MUL15(a[13], b[ 6])
+ + MUL15(a[14], b[ 5])
+ + MUL15(a[15], b[ 4])
+ + MUL15(a[16], b[ 3])
+ + MUL15(a[17], b[ 2])
+ + MUL15(a[18], b[ 1])
+ + MUL15(a[19], b[ 0]);
+ t[20] = MUL15(a[ 1], b[19])
+ + MUL15(a[ 2], b[18])
+ + MUL15(a[ 3], b[17])
+ + MUL15(a[ 4], b[16])
+ + MUL15(a[ 5], b[15])
+ + MUL15(a[ 6], b[14])
+ + MUL15(a[ 7], b[13])
+ + MUL15(a[ 8], b[12])
+ + MUL15(a[ 9], b[11])
+ + MUL15(a[10], b[10])
+ + MUL15(a[11], b[ 9])
+ + MUL15(a[12], b[ 8])
+ + MUL15(a[13], b[ 7])
+ + MUL15(a[14], b[ 6])
+ + MUL15(a[15], b[ 5])
+ + MUL15(a[16], b[ 4])
+ + MUL15(a[17], b[ 3])
+ + MUL15(a[18], b[ 2])
+ + MUL15(a[19], b[ 1]);
+ t[21] = MUL15(a[ 2], b[19])
+ + MUL15(a[ 3], b[18])
+ + MUL15(a[ 4], b[17])
+ + MUL15(a[ 5], b[16])
+ + MUL15(a[ 6], b[15])
+ + MUL15(a[ 7], b[14])
+ + MUL15(a[ 8], b[13])
+ + MUL15(a[ 9], b[12])
+ + MUL15(a[10], b[11])
+ + MUL15(a[11], b[10])
+ + MUL15(a[12], b[ 9])
+ + MUL15(a[13], b[ 8])
+ + MUL15(a[14], b[ 7])
+ + MUL15(a[15], b[ 6])
+ + MUL15(a[16], b[ 5])
+ + MUL15(a[17], b[ 4])
+ + MUL15(a[18], b[ 3])
+ + MUL15(a[19], b[ 2]);
+ t[22] = MUL15(a[ 3], b[19])
+ + MUL15(a[ 4], b[18])
+ + MUL15(a[ 5], b[17])
+ + MUL15(a[ 6], b[16])
+ + MUL15(a[ 7], b[15])
+ + MUL15(a[ 8], b[14])
+ + MUL15(a[ 9], b[13])
+ + MUL15(a[10], b[12])
+ + MUL15(a[11], b[11])
+ + MUL15(a[12], b[10])
+ + MUL15(a[13], b[ 9])
+ + MUL15(a[14], b[ 8])
+ + MUL15(a[15], b[ 7])
+ + MUL15(a[16], b[ 6])
+ + MUL15(a[17], b[ 5])
+ + MUL15(a[18], b[ 4])
+ + MUL15(a[19], b[ 3]);
+ t[23] = MUL15(a[ 4], b[19])
+ + MUL15(a[ 5], b[18])
+ + MUL15(a[ 6], b[17])
+ + MUL15(a[ 7], b[16])
+ + MUL15(a[ 8], b[15])
+ + MUL15(a[ 9], b[14])
+ + MUL15(a[10], b[13])
+ + MUL15(a[11], b[12])
+ + MUL15(a[12], b[11])
+ + MUL15(a[13], b[10])
+ + MUL15(a[14], b[ 9])
+ + MUL15(a[15], b[ 8])
+ + MUL15(a[16], b[ 7])
+ + MUL15(a[17], b[ 6])
+ + MUL15(a[18], b[ 5])
+ + MUL15(a[19], b[ 4]);
+ t[24] = MUL15(a[ 5], b[19])
+ + MUL15(a[ 6], b[18])
+ + MUL15(a[ 7], b[17])
+ + MUL15(a[ 8], b[16])
+ + MUL15(a[ 9], b[15])
+ + MUL15(a[10], b[14])
+ + MUL15(a[11], b[13])
+ + MUL15(a[12], b[12])
+ + MUL15(a[13], b[11])
+ + MUL15(a[14], b[10])
+ + MUL15(a[15], b[ 9])
+ + MUL15(a[16], b[ 8])
+ + MUL15(a[17], b[ 7])
+ + MUL15(a[18], b[ 6])
+ + MUL15(a[19], b[ 5]);
+ t[25] = MUL15(a[ 6], b[19])
+ + MUL15(a[ 7], b[18])
+ + MUL15(a[ 8], b[17])
+ + MUL15(a[ 9], b[16])
+ + MUL15(a[10], b[15])
+ + MUL15(a[11], b[14])
+ + MUL15(a[12], b[13])
+ + MUL15(a[13], b[12])
+ + MUL15(a[14], b[11])
+ + MUL15(a[15], b[10])
+ + MUL15(a[16], b[ 9])
+ + MUL15(a[17], b[ 8])
+ + MUL15(a[18], b[ 7])
+ + MUL15(a[19], b[ 6]);
+ t[26] = MUL15(a[ 7], b[19])
+ + MUL15(a[ 8], b[18])
+ + MUL15(a[ 9], b[17])
+ + MUL15(a[10], b[16])
+ + MUL15(a[11], b[15])
+ + MUL15(a[12], b[14])
+ + MUL15(a[13], b[13])
+ + MUL15(a[14], b[12])
+ + MUL15(a[15], b[11])
+ + MUL15(a[16], b[10])
+ + MUL15(a[17], b[ 9])
+ + MUL15(a[18], b[ 8])
+ + MUL15(a[19], b[ 7]);
+ t[27] = MUL15(a[ 8], b[19])
+ + MUL15(a[ 9], b[18])
+ + MUL15(a[10], b[17])
+ + MUL15(a[11], b[16])
+ + MUL15(a[12], b[15])
+ + MUL15(a[13], b[14])
+ + MUL15(a[14], b[13])
+ + MUL15(a[15], b[12])
+ + MUL15(a[16], b[11])
+ + MUL15(a[17], b[10])
+ + MUL15(a[18], b[ 9])
+ + MUL15(a[19], b[ 8]);
+ t[28] = MUL15(a[ 9], b[19])
+ + MUL15(a[10], b[18])
+ + MUL15(a[11], b[17])
+ + MUL15(a[12], b[16])
+ + MUL15(a[13], b[15])
+ + MUL15(a[14], b[14])
+ + MUL15(a[15], b[13])
+ + MUL15(a[16], b[12])
+ + MUL15(a[17], b[11])
+ + MUL15(a[18], b[10])
+ + MUL15(a[19], b[ 9]);
+ t[29] = MUL15(a[10], b[19])
+ + MUL15(a[11], b[18])
+ + MUL15(a[12], b[17])
+ + MUL15(a[13], b[16])
+ + MUL15(a[14], b[15])
+ + MUL15(a[15], b[14])
+ + MUL15(a[16], b[13])
+ + MUL15(a[17], b[12])
+ + MUL15(a[18], b[11])
+ + MUL15(a[19], b[10]);
+ t[30] = MUL15(a[11], b[19])
+ + MUL15(a[12], b[18])
+ + MUL15(a[13], b[17])
+ + MUL15(a[14], b[16])
+ + MUL15(a[15], b[15])
+ + MUL15(a[16], b[14])
+ + MUL15(a[17], b[13])
+ + MUL15(a[18], b[12])
+ + MUL15(a[19], b[11]);
+ t[31] = MUL15(a[12], b[19])
+ + MUL15(a[13], b[18])
+ + MUL15(a[14], b[17])
+ + MUL15(a[15], b[16])
+ + MUL15(a[16], b[15])
+ + MUL15(a[17], b[14])
+ + MUL15(a[18], b[13])
+ + MUL15(a[19], b[12]);
+ t[32] = MUL15(a[13], b[19])
+ + MUL15(a[14], b[18])
+ + MUL15(a[15], b[17])
+ + MUL15(a[16], b[16])
+ + MUL15(a[17], b[15])
+ + MUL15(a[18], b[14])
+ + MUL15(a[19], b[13]);
+ t[33] = MUL15(a[14], b[19])
+ + MUL15(a[15], b[18])
+ + MUL15(a[16], b[17])
+ + MUL15(a[17], b[16])
+ + MUL15(a[18], b[15])
+ + MUL15(a[19], b[14]);
+ t[34] = MUL15(a[15], b[19])
+ + MUL15(a[16], b[18])
+ + MUL15(a[17], b[17])
+ + MUL15(a[18], b[16])
+ + MUL15(a[19], b[15]);
+ t[35] = MUL15(a[16], b[19])
+ + MUL15(a[17], b[18])
+ + MUL15(a[18], b[17])
+ + MUL15(a[19], b[16]);
+ t[36] = MUL15(a[17], b[19])
+ + MUL15(a[18], b[18])
+ + MUL15(a[19], b[17]);
+ t[37] = MUL15(a[18], b[19])
+ + MUL15(a[19], b[18]);
+ t[38] = MUL15(a[19], b[19]);
+
+ d[39] = norm13(d, t, 39);
+}
+
+static void
+square20(uint32_t *d, const uint32_t *a)
+{
+ uint32_t t[39];
+
+ t[ 0] = MUL15(a[ 0], a[ 0]);
+ t[ 1] = ((MUL15(a[ 0], a[ 1])) << 1);
+ t[ 2] = MUL15(a[ 1], a[ 1])
+ + ((MUL15(a[ 0], a[ 2])) << 1);
+ t[ 3] = ((MUL15(a[ 0], a[ 3])
+ + MUL15(a[ 1], a[ 2])) << 1);
+ t[ 4] = MUL15(a[ 2], a[ 2])
+ + ((MUL15(a[ 0], a[ 4])
+ + MUL15(a[ 1], a[ 3])) << 1);
+ t[ 5] = ((MUL15(a[ 0], a[ 5])
+ + MUL15(a[ 1], a[ 4])
+ + MUL15(a[ 2], a[ 3])) << 1);
+ t[ 6] = MUL15(a[ 3], a[ 3])
+ + ((MUL15(a[ 0], a[ 6])
+ + MUL15(a[ 1], a[ 5])
+ + MUL15(a[ 2], a[ 4])) << 1);
+ t[ 7] = ((MUL15(a[ 0], a[ 7])
+ + MUL15(a[ 1], a[ 6])
+ + MUL15(a[ 2], a[ 5])
+ + MUL15(a[ 3], a[ 4])) << 1);
+ t[ 8] = MUL15(a[ 4], a[ 4])
+ + ((MUL15(a[ 0], a[ 8])
+ + MUL15(a[ 1], a[ 7])
+ + MUL15(a[ 2], a[ 6])
+ + MUL15(a[ 3], a[ 5])) << 1);
+ t[ 9] = ((MUL15(a[ 0], a[ 9])
+ + MUL15(a[ 1], a[ 8])
+ + MUL15(a[ 2], a[ 7])
+ + MUL15(a[ 3], a[ 6])
+ + MUL15(a[ 4], a[ 5])) << 1);
+ t[10] = MUL15(a[ 5], a[ 5])
+ + ((MUL15(a[ 0], a[10])
+ + MUL15(a[ 1], a[ 9])
+ + MUL15(a[ 2], a[ 8])
+ + MUL15(a[ 3], a[ 7])
+ + MUL15(a[ 4], a[ 6])) << 1);
+ t[11] = ((MUL15(a[ 0], a[11])
+ + MUL15(a[ 1], a[10])
+ + MUL15(a[ 2], a[ 9])
+ + MUL15(a[ 3], a[ 8])
+ + MUL15(a[ 4], a[ 7])
+ + MUL15(a[ 5], a[ 6])) << 1);
+ t[12] = MUL15(a[ 6], a[ 6])
+ + ((MUL15(a[ 0], a[12])
+ + MUL15(a[ 1], a[11])
+ + MUL15(a[ 2], a[10])
+ + MUL15(a[ 3], a[ 9])
+ + MUL15(a[ 4], a[ 8])
+ + MUL15(a[ 5], a[ 7])) << 1);
+ t[13] = ((MUL15(a[ 0], a[13])
+ + MUL15(a[ 1], a[12])
+ + MUL15(a[ 2], a[11])
+ + MUL15(a[ 3], a[10])
+ + MUL15(a[ 4], a[ 9])
+ + MUL15(a[ 5], a[ 8])
+ + MUL15(a[ 6], a[ 7])) << 1);
+ t[14] = MUL15(a[ 7], a[ 7])
+ + ((MUL15(a[ 0], a[14])
+ + MUL15(a[ 1], a[13])
+ + MUL15(a[ 2], a[12])
+ + MUL15(a[ 3], a[11])
+ + MUL15(a[ 4], a[10])
+ + MUL15(a[ 5], a[ 9])
+ + MUL15(a[ 6], a[ 8])) << 1);
+ t[15] = ((MUL15(a[ 0], a[15])
+ + MUL15(a[ 1], a[14])
+ + MUL15(a[ 2], a[13])
+ + MUL15(a[ 3], a[12])
+ + MUL15(a[ 4], a[11])
+ + MUL15(a[ 5], a[10])
+ + MUL15(a[ 6], a[ 9])
+ + MUL15(a[ 7], a[ 8])) << 1);
+ t[16] = MUL15(a[ 8], a[ 8])
+ + ((MUL15(a[ 0], a[16])
+ + MUL15(a[ 1], a[15])
+ + MUL15(a[ 2], a[14])
+ + MUL15(a[ 3], a[13])
+ + MUL15(a[ 4], a[12])
+ + MUL15(a[ 5], a[11])
+ + MUL15(a[ 6], a[10])
+ + MUL15(a[ 7], a[ 9])) << 1);
+ t[17] = ((MUL15(a[ 0], a[17])
+ + MUL15(a[ 1], a[16])
+ + MUL15(a[ 2], a[15])
+ + MUL15(a[ 3], a[14])
+ + MUL15(a[ 4], a[13])
+ + MUL15(a[ 5], a[12])
+ + MUL15(a[ 6], a[11])
+ + MUL15(a[ 7], a[10])
+ + MUL15(a[ 8], a[ 9])) << 1);
+ t[18] = MUL15(a[ 9], a[ 9])
+ + ((MUL15(a[ 0], a[18])
+ + MUL15(a[ 1], a[17])
+ + MUL15(a[ 2], a[16])
+ + MUL15(a[ 3], a[15])
+ + MUL15(a[ 4], a[14])
+ + MUL15(a[ 5], a[13])
+ + MUL15(a[ 6], a[12])
+ + MUL15(a[ 7], a[11])
+ + MUL15(a[ 8], a[10])) << 1);
+ t[19] = ((MUL15(a[ 0], a[19])
+ + MUL15(a[ 1], a[18])
+ + MUL15(a[ 2], a[17])
+ + MUL15(a[ 3], a[16])
+ + MUL15(a[ 4], a[15])
+ + MUL15(a[ 5], a[14])
+ + MUL15(a[ 6], a[13])
+ + MUL15(a[ 7], a[12])
+ + MUL15(a[ 8], a[11])
+ + MUL15(a[ 9], a[10])) << 1);
+ t[20] = MUL15(a[10], a[10])
+ + ((MUL15(a[ 1], a[19])
+ + MUL15(a[ 2], a[18])
+ + MUL15(a[ 3], a[17])
+ + MUL15(a[ 4], a[16])
+ + MUL15(a[ 5], a[15])
+ + MUL15(a[ 6], a[14])
+ + MUL15(a[ 7], a[13])
+ + MUL15(a[ 8], a[12])
+ + MUL15(a[ 9], a[11])) << 1);
+ t[21] = ((MUL15(a[ 2], a[19])
+ + MUL15(a[ 3], a[18])
+ + MUL15(a[ 4], a[17])
+ + MUL15(a[ 5], a[16])
+ + MUL15(a[ 6], a[15])
+ + MUL15(a[ 7], a[14])
+ + MUL15(a[ 8], a[13])
+ + MUL15(a[ 9], a[12])
+ + MUL15(a[10], a[11])) << 1);
+ t[22] = MUL15(a[11], a[11])
+ + ((MUL15(a[ 3], a[19])
+ + MUL15(a[ 4], a[18])
+ + MUL15(a[ 5], a[17])
+ + MUL15(a[ 6], a[16])
+ + MUL15(a[ 7], a[15])
+ + MUL15(a[ 8], a[14])
+ + MUL15(a[ 9], a[13])
+ + MUL15(a[10], a[12])) << 1);
+ t[23] = ((MUL15(a[ 4], a[19])
+ + MUL15(a[ 5], a[18])
+ + MUL15(a[ 6], a[17])
+ + MUL15(a[ 7], a[16])
+ + MUL15(a[ 8], a[15])
+ + MUL15(a[ 9], a[14])
+ + MUL15(a[10], a[13])
+ + MUL15(a[11], a[12])) << 1);
+ t[24] = MUL15(a[12], a[12])
+ + ((MUL15(a[ 5], a[19])
+ + MUL15(a[ 6], a[18])
+ + MUL15(a[ 7], a[17])
+ + MUL15(a[ 8], a[16])
+ + MUL15(a[ 9], a[15])
+ + MUL15(a[10], a[14])
+ + MUL15(a[11], a[13])) << 1);
+ t[25] = ((MUL15(a[ 6], a[19])
+ + MUL15(a[ 7], a[18])
+ + MUL15(a[ 8], a[17])
+ + MUL15(a[ 9], a[16])
+ + MUL15(a[10], a[15])
+ + MUL15(a[11], a[14])
+ + MUL15(a[12], a[13])) << 1);
+ t[26] = MUL15(a[13], a[13])
+ + ((MUL15(a[ 7], a[19])
+ + MUL15(a[ 8], a[18])
+ + MUL15(a[ 9], a[17])
+ + MUL15(a[10], a[16])
+ + MUL15(a[11], a[15])
+ + MUL15(a[12], a[14])) << 1);
+ t[27] = ((MUL15(a[ 8], a[19])
+ + MUL15(a[ 9], a[18])
+ + MUL15(a[10], a[17])
+ + MUL15(a[11], a[16])
+ + MUL15(a[12], a[15])
+ + MUL15(a[13], a[14])) << 1);
+ t[28] = MUL15(a[14], a[14])
+ + ((MUL15(a[ 9], a[19])
+ + MUL15(a[10], a[18])
+ + MUL15(a[11], a[17])
+ + MUL15(a[12], a[16])
+ + MUL15(a[13], a[15])) << 1);
+ t[29] = ((MUL15(a[10], a[19])
+ + MUL15(a[11], a[18])
+ + MUL15(a[12], a[17])
+ + MUL15(a[13], a[16])
+ + MUL15(a[14], a[15])) << 1);
+ t[30] = MUL15(a[15], a[15])
+ + ((MUL15(a[11], a[19])
+ + MUL15(a[12], a[18])
+ + MUL15(a[13], a[17])
+ + MUL15(a[14], a[16])) << 1);
+ t[31] = ((MUL15(a[12], a[19])
+ + MUL15(a[13], a[18])
+ + MUL15(a[14], a[17])
+ + MUL15(a[15], a[16])) << 1);
+ t[32] = MUL15(a[16], a[16])
+ + ((MUL15(a[13], a[19])
+ + MUL15(a[14], a[18])
+ + MUL15(a[15], a[17])) << 1);
+ t[33] = ((MUL15(a[14], a[19])
+ + MUL15(a[15], a[18])
+ + MUL15(a[16], a[17])) << 1);
+ t[34] = MUL15(a[17], a[17])
+ + ((MUL15(a[15], a[19])
+ + MUL15(a[16], a[18])) << 1);
+ t[35] = ((MUL15(a[16], a[19])
+ + MUL15(a[17], a[18])) << 1);
+ t[36] = MUL15(a[18], a[18])
+ + ((MUL15(a[17], a[19])) << 1);
+ t[37] = ((MUL15(a[18], a[19])) << 1);
+ t[38] = MUL15(a[19], a[19]);
+
+ d[39] = norm13(d, t, 39);
+}
+
+#endif
+
+/*
+ * Perform a "final reduction" in field F255 (field for Curve25519)
+ * The source value must be less than twice the modulus. If the value
+ * is not lower than the modulus, then the modulus is subtracted and
+ * this function returns 1; otherwise, it leaves it untouched and it
+ * returns 0.
+ */
+static uint32_t
+reduce_final_f255(uint32_t *d)
+{
+ uint32_t t[20];
+ uint32_t cc;
+ int i;
+
+ memcpy(t, d, sizeof t);
+ cc = 19;
+ for (i = 0; i < 20; i ++) {
+ uint32_t w;
+
+ w = t[i] + cc;
+ cc = w >> 13;
+ t[i] = w & 0x1FFF;
+ }
+ cc = t[19] >> 8;
+ t[19] &= 0xFF;
+ CCOPY(cc, d, t, sizeof t);
+ return cc;
+}
+
+static void
+f255_mulgen(uint32_t *d, const uint32_t *a, const uint32_t *b, int square)
+{
+ uint32_t t[40], cc, w;
+
+ /*
+ * Compute raw multiplication. All result words fit in 13 bits
+ * each; upper word (t[39]) must fit on 5 bits, since the product
+ * of two 256-bit integers must fit on 512 bits.
+ */
+ if (square) {
+ square20(t, a);
+ } else {
+ mul20(t, a, b);
+ }
+
+ /*
+ * Modular reduction: each high word is added where necessary.
+ * Since the modulus is 2^255-19 and word 20 corresponds to
+ * offset 20*13 = 260, word 20+k must be added to word k with
+ * a factor of 19*2^5 = 608. The extra bits in word 19 are also
+ * added that way.
+ */
+ cc = MUL15(t[19] >> 8, 19);
+ t[19] &= 0xFF;
+
+#define MM1(x) do { \
+ w = t[x] + cc + MUL15(t[(x) + 20], 608); \
+ t[x] = w & 0x1FFF; \
+ cc = w >> 13; \
+ } while (0)
+
+ MM1( 0);
+ MM1( 1);
+ MM1( 2);
+ MM1( 3);
+ MM1( 4);
+ MM1( 5);
+ MM1( 6);
+ MM1( 7);
+ MM1( 8);
+ MM1( 9);
+ MM1(10);
+ MM1(11);
+ MM1(12);
+ MM1(13);
+ MM1(14);
+ MM1(15);
+ MM1(16);
+ MM1(17);
+ MM1(18);
+ MM1(19);
+
+#undef MM1
+
+ cc = MUL15(w >> 8, 19);
+ t[19] &= 0xFF;
+
+#define MM2(x) do { \
+ w = t[x] + cc; \
+ d[x] = w & 0x1FFF; \
+ cc = w >> 13; \
+ } while (0)
+
+ MM2( 0);
+ MM2( 1);
+ MM2( 2);
+ MM2( 3);
+ MM2( 4);
+ MM2( 5);
+ MM2( 6);
+ MM2( 7);
+ MM2( 8);
+ MM2( 9);
+ MM2(10);
+ MM2(11);
+ MM2(12);
+ MM2(13);
+ MM2(14);
+ MM2(15);
+ MM2(16);
+ MM2(17);
+ MM2(18);
+ MM2(19);
+
+#undef MM2
+}
+
+/*
+ * Perform a multiplication of two integers modulo 2^255-19.
+ * Operands are arrays of 20 words, each containing 13 bits of data, in
+ * little-endian order. Input value may be up to 2^256-1; on output, value
+ * fits on 256 bits and is lower than twice the modulus.
+ *
+ * f255_mul() is the general multiplication, f255_square() is specialised
+ * for squarings.
+ */
+#define f255_mul(d, a, b) f255_mulgen(d, a, b, 0)
+#define f255_square(d, a) f255_mulgen(d, a, a, 1)
+
+/*
+ * Add two values in F255. Partial reduction is performed (down to less
+ * than twice the modulus).
+ */
+static void
+f255_add(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ int i;
+ uint32_t cc, w;
+
+ cc = 0;
+ for (i = 0; i < 20; i ++) {
+ w = a[i] + b[i] + cc;
+ d[i] = w & 0x1FFF;
+ cc = w >> 13;
+ }
+ cc = MUL15(w >> 8, 19);
+ d[19] &= 0xFF;
+ for (i = 0; i < 20; i ++) {
+ w = d[i] + cc;
+ d[i] = w & 0x1FFF;
+ cc = w >> 13;
+ }
+}
+
+/*
+ * Subtract one value from another in F255. Partial reduction is
+ * performed (down to less than twice the modulus).
+ */
+static void
+f255_sub(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ /*
+ * We actually compute a - b + 2*p, so that the final value is
+ * necessarily positive.
+ */
+ int i;
+ uint32_t cc, w;
+
+ cc = (uint32_t)-38;
+ for (i = 0; i < 20; i ++) {
+ w = a[i] - b[i] + cc;
+ d[i] = w & 0x1FFF;
+ cc = ARSH(w, 13);
+ }
+ cc = MUL15((w + 0x200) >> 8, 19);
+ d[19] &= 0xFF;
+ for (i = 0; i < 20; i ++) {
+ w = d[i] + cc;
+ d[i] = w & 0x1FFF;
+ cc = w >> 13;
+ }
+}
+
+/*
+ * Multiply an integer by the 'A24' constant (121665). Partial reduction
+ * is performed (down to less than twice the modulus).
+ */
+static void
+f255_mul_a24(uint32_t *d, const uint32_t *a)
+{
+ int i;
+ uint32_t cc, w;
+
+ cc = 0;
+ for (i = 0; i < 20; i ++) {
+ w = MUL15(a[i], 121665) + cc;
+ d[i] = w & 0x1FFF;
+ cc = w >> 13;
+ }
+ cc = MUL15(w >> 8, 19);
+ d[19] &= 0xFF;
+ for (i = 0; i < 20; i ++) {
+ w = d[i] + cc;
+ d[i] = w & 0x1FFF;
+ cc = w >> 13;
+ }
+}
+
+static const unsigned char GEN[] = {
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const unsigned char ORDER[] = {
+ 0x7F, 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
+};
+
+static const unsigned char *
+api_generator(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return GEN;
+}
+
+static const unsigned char *
+api_order(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return ORDER;
+}
+
+static size_t
+api_xoff(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return 0;
+}
+
+static void
+cswap(uint32_t *a, uint32_t *b, uint32_t ctl)
+{
+ int i;
+
+ ctl = -ctl;
+ for (i = 0; i < 20; i ++) {
+ uint32_t aw, bw, tw;
+
+ aw = a[i];
+ bw = b[i];
+ tw = ctl & (aw ^ bw);
+ a[i] = aw ^ tw;
+ b[i] = bw ^ tw;
+ }
+}
+
+static uint32_t
+api_mul(unsigned char *G, size_t Glen,
+ const unsigned char *kb, size_t kblen, int curve)
+{
+ uint32_t x1[20], x2[20], x3[20], z2[20], z3[20];
+ uint32_t a[20], aa[20], b[20], bb[20];
+ uint32_t c[20], d[20], e[20], da[20], cb[20];
+ unsigned char k[32];
+ uint32_t swap;
+ int i;
+
+ (void)curve;
+
+ /*
+ * Points are encoded over exactly 32 bytes. Multipliers must fit
+ * in 32 bytes as well.
+ * RFC 7748 mandates that the high bit of the last point byte must
+ * be ignored/cleared.
+ */
+ if (Glen != 32 || kblen > 32) {
+ return 0;
+ }
+ G[31] &= 0x7F;
+
+ /*
+ * Initialise variables x1, x2, z2, x3 and z3. We set all of them
+ * into Montgomery representation.
+ */
+ x1[19] = le8_to_le13(x1, G, 32);
+ memcpy(x3, x1, sizeof x1);
+ memset(z2, 0, sizeof z2);
+ memset(x2, 0, sizeof x2);
+ x2[0] = 1;
+ memset(z3, 0, sizeof z3);
+ z3[0] = 1;
+
+ memset(k, 0, (sizeof k) - kblen);
+ memcpy(k + (sizeof k) - kblen, kb, kblen);
+ k[31] &= 0xF8;
+ k[0] &= 0x7F;
+ k[0] |= 0x40;
+
+ /* obsolete
+ print_int("x1", x1);
+ */
+
+ swap = 0;
+ for (i = 254; i >= 0; i --) {
+ uint32_t kt;
+
+ kt = (k[31 - (i >> 3)] >> (i & 7)) & 1;
+ swap ^= kt;
+ cswap(x2, x3, swap);
+ cswap(z2, z3, swap);
+ swap = kt;
+
+ /* obsolete
+ print_int("x2", x2);
+ print_int("z2", z2);
+ print_int("x3", x3);
+ print_int("z3", z3);
+ */
+
+ f255_add(a, x2, z2);
+ f255_square(aa, a);
+ f255_sub(b, x2, z2);
+ f255_square(bb, b);
+ f255_sub(e, aa, bb);
+ f255_add(c, x3, z3);
+ f255_sub(d, x3, z3);
+ f255_mul(da, d, a);
+ f255_mul(cb, c, b);
+
+ /* obsolete
+ print_int("a ", a);
+ print_int("aa", aa);
+ print_int("b ", b);
+ print_int("bb", bb);
+ print_int("e ", e);
+ print_int("c ", c);
+ print_int("d ", d);
+ print_int("da", da);
+ print_int("cb", cb);
+ */
+
+ f255_add(x3, da, cb);
+ f255_square(x3, x3);
+ f255_sub(z3, da, cb);
+ f255_square(z3, z3);
+ f255_mul(z3, z3, x1);
+ f255_mul(x2, aa, bb);
+ f255_mul_a24(z2, e);
+ f255_add(z2, z2, aa);
+ f255_mul(z2, e, z2);
+
+ /* obsolete
+ print_int("x2", x2);
+ print_int("z2", z2);
+ print_int("x3", x3);
+ print_int("z3", z3);
+ */
+ }
+ cswap(x2, x3, swap);
+ cswap(z2, z3, swap);
+
+ /*
+ * Inverse z2 with a modular exponentiation. This is a simple
+ * square-and-multiply algorithm; we mutualise most non-squarings
+ * since the exponent contains almost only ones.
+ */
+ memcpy(a, z2, sizeof z2);
+ for (i = 0; i < 15; i ++) {
+ f255_square(a, a);
+ f255_mul(a, a, z2);
+ }
+ memcpy(b, a, sizeof a);
+ for (i = 0; i < 14; i ++) {
+ int j;
+
+ for (j = 0; j < 16; j ++) {
+ f255_square(b, b);
+ }
+ f255_mul(b, b, a);
+ }
+ for (i = 14; i >= 0; i --) {
+ f255_square(b, b);
+ if ((0xFFEB >> i) & 1) {
+ f255_mul(b, z2, b);
+ }
+ }
+ f255_mul(x2, x2, b);
+ reduce_final_f255(x2);
+ le13_to_le8(G, 32, x2);
+ return 1;
+}
+
+static size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ const unsigned char *G;
+ size_t Glen;
+
+ G = api_generator(curve, &Glen);
+ memcpy(R, G, Glen);
+ api_mul(R, Glen, x, xlen, curve);
+ return Glen;
+}
+
+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)
+{
+ /*
+ * We don't implement this method, since it is used for ECDSA
+ * only, and there is no ECDSA over Curve25519 (which instead
+ * uses EdDSA).
+ */
+ (void)A;
+ (void)B;
+ (void)len;
+ (void)x;
+ (void)xlen;
+ (void)y;
+ (void)ylen;
+ (void)curve;
+ return 0;
+}
+
+/* see bearssl_ec.h */
+const br_ec_impl br_ec_c25519_m15 = {
+ (uint32_t)0x20000000,
+ &api_generator,
+ &api_order,
+ &api_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
diff --git a/contrib/bearssl/src/ec/ec_c25519_m31.c b/contrib/bearssl/src/ec/ec_c25519_m31.c
new file mode 100644
index 000000000000..1dd6d514f8ba
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_c25519_m31.c
@@ -0,0 +1,800 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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"
+
+/* obsolete
+#include <stdio.h>
+#include <stdlib.h>
+static void
+print_int(const char *name, const uint32_t *x)
+{
+ size_t u;
+ unsigned char tmp[40];
+
+ printf("%s = ", name);
+ for (u = 0; u < 9; u ++) {
+ if (x[u] > 0x3FFFFFFF) {
+ printf("INVALID:");
+ for (u = 0; u < 9; u ++) {
+ printf(" %08X", x[u]);
+ }
+ printf("\n");
+ return;
+ }
+ }
+ memset(tmp, 0, sizeof tmp);
+ for (u = 0; u < 9; u ++) {
+ uint64_t w;
+ int j, k;
+
+ w = x[u];
+ j = 30 * (int)u;
+ k = j & 7;
+ if (k != 0) {
+ w <<= k;
+ j -= k;
+ }
+ k = j >> 3;
+ for (j = 0; j < 8; j ++) {
+ tmp[39 - k - j] |= (unsigned char)w;
+ w >>= 8;
+ }
+ }
+ for (u = 8; u < 40; u ++) {
+ printf("%02X", tmp[u]);
+ }
+ printf("\n");
+}
+*/
+
+/*
+ * If BR_NO_ARITH_SHIFT is undefined, or defined to 0, then we _assume_
+ * that right-shifting a signed negative integer copies the sign bit
+ * (arithmetic right-shift). This is "implementation-defined behaviour",
+ * i.e. it is not undefined, but it may differ between compilers. Each
+ * compiler is supposed to document its behaviour in that respect. GCC
+ * explicitly defines that an arithmetic right shift is used. We expect
+ * all other compilers to do the same, because underlying CPU offer an
+ * arithmetic right shift opcode that could not be used otherwise.
+ */
+#if BR_NO_ARITH_SHIFT
+#define ARSH(x, n) (((uint32_t)(x) >> (n)) \
+ | ((-((uint32_t)(x) >> 31)) << (32 - (n))))
+#else
+#define ARSH(x, n) ((*(int32_t *)&(x)) >> (n))
+#endif
+
+/*
+ * Convert an integer from unsigned little-endian encoding to a sequence of
+ * 30-bit words in little-endian order. The final "partial" word is
+ * returned.
+ */
+static uint32_t
+le8_to_le30(uint32_t *dst, const unsigned char *src, size_t len)
+{
+ uint32_t acc;
+ int acc_len;
+
+ acc = 0;
+ acc_len = 0;
+ while (len -- > 0) {
+ uint32_t b;
+
+ b = *src ++;
+ if (acc_len < 22) {
+ acc |= b << acc_len;
+ acc_len += 8;
+ } else {
+ *dst ++ = (acc | (b << acc_len)) & 0x3FFFFFFF;
+ acc = b >> (30 - acc_len);
+ acc_len -= 22;
+ }
+ }
+ return acc;
+}
+
+/*
+ * Convert an integer (30-bit words, little-endian) to unsigned
+ * little-endian encoding. The total encoding length is provided; all
+ * the destination bytes will be filled.
+ */
+static void
+le30_to_le8(unsigned char *dst, size_t len, const uint32_t *src)
+{
+ uint32_t acc;
+ int acc_len;
+
+ acc = 0;
+ acc_len = 0;
+ while (len -- > 0) {
+ if (acc_len < 8) {
+ uint32_t w;
+
+ w = *src ++;
+ *dst ++ = (unsigned char)(acc | (w << acc_len));
+ acc = w >> (8 - acc_len);
+ acc_len += 22;
+ } else {
+ *dst ++ = (unsigned char)acc;
+ acc >>= 8;
+ acc_len -= 8;
+ }
+ }
+}
+
+/*
+ * Multiply two integers. Source integers are represented as arrays of
+ * nine 30-bit words, for values up to 2^270-1. Result is encoded over
+ * 18 words of 30 bits each.
+ */
+static void
+mul9(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ /*
+ * Maximum intermediate result is no more than
+ * 10376293531797946367, which fits in 64 bits. Reason:
+ *
+ * 10376293531797946367 = 9 * (2^30-1)^2 + 9663676406
+ * 10376293531797946367 < 9663676407 * 2^30
+ *
+ * Thus, adding together 9 products of 30-bit integers, with
+ * a carry of at most 9663676406, yields an integer that fits
+ * on 64 bits and generates a carry of at most 9663676406.
+ */
+ uint64_t t[17];
+ uint64_t cc;
+ int i;
+
+ t[ 0] = MUL31(a[0], b[0]);
+ t[ 1] = MUL31(a[0], b[1])
+ + MUL31(a[1], b[0]);
+ t[ 2] = MUL31(a[0], b[2])
+ + MUL31(a[1], b[1])
+ + MUL31(a[2], b[0]);
+ t[ 3] = MUL31(a[0], b[3])
+ + MUL31(a[1], b[2])
+ + MUL31(a[2], b[1])
+ + MUL31(a[3], b[0]);
+ t[ 4] = MUL31(a[0], b[4])
+ + MUL31(a[1], b[3])
+ + MUL31(a[2], b[2])
+ + MUL31(a[3], b[1])
+ + MUL31(a[4], b[0]);
+ t[ 5] = MUL31(a[0], b[5])
+ + MUL31(a[1], b[4])
+ + MUL31(a[2], b[3])
+ + MUL31(a[3], b[2])
+ + MUL31(a[4], b[1])
+ + MUL31(a[5], b[0]);
+ t[ 6] = MUL31(a[0], b[6])
+ + MUL31(a[1], b[5])
+ + MUL31(a[2], b[4])
+ + MUL31(a[3], b[3])
+ + MUL31(a[4], b[2])
+ + MUL31(a[5], b[1])
+ + MUL31(a[6], b[0]);
+ t[ 7] = MUL31(a[0], b[7])
+ + MUL31(a[1], b[6])
+ + MUL31(a[2], b[5])
+ + MUL31(a[3], b[4])
+ + MUL31(a[4], b[3])
+ + MUL31(a[5], b[2])
+ + MUL31(a[6], b[1])
+ + MUL31(a[7], b[0]);
+ t[ 8] = MUL31(a[0], b[8])
+ + MUL31(a[1], b[7])
+ + MUL31(a[2], b[6])
+ + MUL31(a[3], b[5])
+ + MUL31(a[4], b[4])
+ + MUL31(a[5], b[3])
+ + MUL31(a[6], b[2])
+ + MUL31(a[7], b[1])
+ + MUL31(a[8], b[0]);
+ t[ 9] = MUL31(a[1], b[8])
+ + MUL31(a[2], b[7])
+ + MUL31(a[3], b[6])
+ + MUL31(a[4], b[5])
+ + MUL31(a[5], b[4])
+ + MUL31(a[6], b[3])
+ + MUL31(a[7], b[2])
+ + MUL31(a[8], b[1]);
+ t[10] = MUL31(a[2], b[8])
+ + MUL31(a[3], b[7])
+ + MUL31(a[4], b[6])
+ + MUL31(a[5], b[5])
+ + MUL31(a[6], b[4])
+ + MUL31(a[7], b[3])
+ + MUL31(a[8], b[2]);
+ t[11] = MUL31(a[3], b[8])
+ + MUL31(a[4], b[7])
+ + MUL31(a[5], b[6])
+ + MUL31(a[6], b[5])
+ + MUL31(a[7], b[4])
+ + MUL31(a[8], b[3]);
+ t[12] = MUL31(a[4], b[8])
+ + MUL31(a[5], b[7])
+ + MUL31(a[6], b[6])
+ + MUL31(a[7], b[5])
+ + MUL31(a[8], b[4]);
+ t[13] = MUL31(a[5], b[8])
+ + MUL31(a[6], b[7])
+ + MUL31(a[7], b[6])
+ + MUL31(a[8], b[5]);
+ t[14] = MUL31(a[6], b[8])
+ + MUL31(a[7], b[7])
+ + MUL31(a[8], b[6]);
+ t[15] = MUL31(a[7], b[8])
+ + MUL31(a[8], b[7]);
+ t[16] = MUL31(a[8], b[8]);
+
+ /*
+ * Propagate carries.
+ */
+ cc = 0;
+ for (i = 0; i < 17; i ++) {
+ uint64_t w;
+
+ w = t[i] + cc;
+ d[i] = (uint32_t)w & 0x3FFFFFFF;
+ cc = w >> 30;
+ }
+ d[17] = (uint32_t)cc;
+}
+
+/*
+ * Square a 270-bit integer, represented as an array of nine 30-bit words.
+ * Result uses 18 words of 30 bits each.
+ */
+static void
+square9(uint32_t *d, const uint32_t *a)
+{
+ uint64_t t[17];
+ uint64_t cc;
+ int i;
+
+ t[ 0] = MUL31(a[0], a[0]);
+ t[ 1] = ((MUL31(a[0], a[1])) << 1);
+ t[ 2] = MUL31(a[1], a[1])
+ + ((MUL31(a[0], a[2])) << 1);
+ t[ 3] = ((MUL31(a[0], a[3])
+ + MUL31(a[1], a[2])) << 1);
+ t[ 4] = MUL31(a[2], a[2])
+ + ((MUL31(a[0], a[4])
+ + MUL31(a[1], a[3])) << 1);
+ t[ 5] = ((MUL31(a[0], a[5])
+ + MUL31(a[1], a[4])
+ + MUL31(a[2], a[3])) << 1);
+ t[ 6] = MUL31(a[3], a[3])
+ + ((MUL31(a[0], a[6])
+ + MUL31(a[1], a[5])
+ + MUL31(a[2], a[4])) << 1);
+ t[ 7] = ((MUL31(a[0], a[7])
+ + MUL31(a[1], a[6])
+ + MUL31(a[2], a[5])
+ + MUL31(a[3], a[4])) << 1);
+ t[ 8] = MUL31(a[4], a[4])
+ + ((MUL31(a[0], a[8])
+ + MUL31(a[1], a[7])
+ + MUL31(a[2], a[6])
+ + MUL31(a[3], a[5])) << 1);
+ t[ 9] = ((MUL31(a[1], a[8])
+ + MUL31(a[2], a[7])
+ + MUL31(a[3], a[6])
+ + MUL31(a[4], a[5])) << 1);
+ t[10] = MUL31(a[5], a[5])
+ + ((MUL31(a[2], a[8])
+ + MUL31(a[3], a[7])
+ + MUL31(a[4], a[6])) << 1);
+ t[11] = ((MUL31(a[3], a[8])
+ + MUL31(a[4], a[7])
+ + MUL31(a[5], a[6])) << 1);
+ t[12] = MUL31(a[6], a[6])
+ + ((MUL31(a[4], a[8])
+ + MUL31(a[5], a[7])) << 1);
+ t[13] = ((MUL31(a[5], a[8])
+ + MUL31(a[6], a[7])) << 1);
+ t[14] = MUL31(a[7], a[7])
+ + ((MUL31(a[6], a[8])) << 1);
+ t[15] = ((MUL31(a[7], a[8])) << 1);
+ t[16] = MUL31(a[8], a[8]);
+
+ /*
+ * Propagate carries.
+ */
+ cc = 0;
+ for (i = 0; i < 17; i ++) {
+ uint64_t w;
+
+ w = t[i] + cc;
+ d[i] = (uint32_t)w & 0x3FFFFFFF;
+ cc = w >> 30;
+ }
+ d[17] = (uint32_t)cc;
+}
+
+/*
+ * Perform a "final reduction" in field F255 (field for Curve25519)
+ * The source value must be less than twice the modulus. If the value
+ * is not lower than the modulus, then the modulus is subtracted and
+ * this function returns 1; otherwise, it leaves it untouched and it
+ * returns 0.
+ */
+static uint32_t
+reduce_final_f255(uint32_t *d)
+{
+ uint32_t t[9];
+ uint32_t cc;
+ int i;
+
+ memcpy(t, d, sizeof t);
+ cc = 19;
+ for (i = 0; i < 9; i ++) {
+ uint32_t w;
+
+ w = t[i] + cc;
+ cc = w >> 30;
+ t[i] = w & 0x3FFFFFFF;
+ }
+ cc = t[8] >> 15;
+ t[8] &= 0x7FFF;
+ CCOPY(cc, d, t, sizeof t);
+ return cc;
+}
+
+/*
+ * Perform a multiplication of two integers modulo 2^255-19.
+ * Operands are arrays of 9 words, each containing 30 bits of data, in
+ * little-endian order. Input value may be up to 2^256-1; on output, value
+ * fits on 256 bits and is lower than twice the modulus.
+ */
+static void
+f255_mul(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ uint32_t t[18], cc;
+ int i;
+
+ /*
+ * Compute raw multiplication. All result words fit in 30 bits
+ * each; upper word (t[17]) must fit on 2 bits, since the product
+ * of two 256-bit integers must fit on 512 bits.
+ */
+ mul9(t, a, b);
+
+ /*
+ * Modular reduction: each high word is added where necessary.
+ * Since the modulus is 2^255-19 and word 9 corresponds to
+ * offset 9*30 = 270, word 9+k must be added to word k with
+ * a factor of 19*2^15 = 622592. The extra bits in word 8 are also
+ * added that way.
+ *
+ * Keeping the carry on 32 bits helps with 32-bit architectures,
+ * and does not noticeably impact performance on 64-bit systems.
+ */
+ cc = MUL15(t[8] >> 15, 19); /* at most 19*(2^15-1) = 622573 */
+ t[8] &= 0x7FFF;
+ for (i = 0; i < 9; i ++) {
+ uint64_t w;
+
+ w = (uint64_t)t[i] + (uint64_t)cc + MUL31(t[i + 9], 622592);
+ t[i] = (uint32_t)w & 0x3FFFFFFF;
+ cc = (uint32_t)(w >> 30); /* at most 622592 */
+ }
+
+ /*
+ * Original product was up to (2^256-1)^2, i.e. a 512-bit integer.
+ * This was split into two parts (upper of 257 bits, lower of 255
+ * bits), and the upper was added to the lower with a factor 19,
+ * which means that the intermediate value is less than 77*2^255
+ * (19*2^257 + 2^255). Therefore, the extra bits "t[8] >> 15" are
+ * less than 77, and the initial carry cc is at most 76*19 = 1444.
+ */
+ cc = MUL15(t[8] >> 15, 19);
+ t[8] &= 0x7FFF;
+ for (i = 0; i < 9; i ++) {
+ uint32_t z;
+
+ z = t[i] + cc;
+ d[i] = z & 0x3FFFFFFF;
+ cc = z >> 30;
+ }
+
+ /*
+ * Final result is at most 2^255 + 1443. In particular, the last
+ * carry is necessarily 0, since t[8] was truncated to 15 bits.
+ */
+}
+
+/*
+ * Perform a squaring of an integer modulo 2^255-19.
+ * Operands are arrays of 9 words, each containing 30 bits of data, in
+ * little-endian order. Input value may be up to 2^256-1; on output, value
+ * fits on 256 bits and is lower than twice the modulus.
+ */
+static void
+f255_square(uint32_t *d, const uint32_t *a)
+{
+ uint32_t t[18], cc;
+ int i;
+
+ /*
+ * Compute raw squaring. All result words fit in 30 bits
+ * each; upper word (t[17]) must fit on 2 bits, since the square
+ * of a 256-bit integers must fit on 512 bits.
+ */
+ square9(t, a);
+
+ /*
+ * Modular reduction: each high word is added where necessary.
+ * See f255_mul() for details on the reduction and carry limits.
+ */
+ cc = MUL15(t[8] >> 15, 19);
+ t[8] &= 0x7FFF;
+ for (i = 0; i < 9; i ++) {
+ uint64_t w;
+
+ w = (uint64_t)t[i] + (uint64_t)cc + MUL31(t[i + 9], 622592);
+ t[i] = (uint32_t)w & 0x3FFFFFFF;
+ cc = (uint32_t)(w >> 30);
+ }
+ cc = MUL15(t[8] >> 15, 19);
+ t[8] &= 0x7FFF;
+ for (i = 0; i < 9; i ++) {
+ uint32_t z;
+
+ z = t[i] + cc;
+ d[i] = z & 0x3FFFFFFF;
+ cc = z >> 30;
+ }
+}
+
+/*
+ * Add two values in F255. Partial reduction is performed (down to less
+ * than twice the modulus).
+ */
+static void
+f255_add(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ /*
+ * Since operand words fit on 30 bits, we can use 32-bit
+ * variables throughout.
+ */
+ int i;
+ uint32_t cc, w;
+
+ cc = 0;
+ for (i = 0; i < 9; i ++) {
+ w = a[i] + b[i] + cc;
+ d[i] = w & 0x3FFFFFFF;
+ cc = w >> 30;
+ }
+ cc = MUL15(w >> 15, 19);
+ d[8] &= 0x7FFF;
+ for (i = 0; i < 9; i ++) {
+ w = d[i] + cc;
+ d[i] = w & 0x3FFFFFFF;
+ cc = w >> 30;
+ }
+}
+
+/*
+ * Subtract one value from another in F255. Partial reduction is
+ * performed (down to less than twice the modulus).
+ */
+static void
+f255_sub(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ /*
+ * We actually compute a - b + 2*p, so that the final value is
+ * necessarily positive.
+ */
+ int i;
+ uint32_t cc, w;
+
+ cc = (uint32_t)-38;
+ for (i = 0; i < 9; i ++) {
+ w = a[i] - b[i] + cc;
+ d[i] = w & 0x3FFFFFFF;
+ cc = ARSH(w, 30);
+ }
+ cc = MUL15((w + 0x10000) >> 15, 19);
+ d[8] &= 0x7FFF;
+ for (i = 0; i < 9; i ++) {
+ w = d[i] + cc;
+ d[i] = w & 0x3FFFFFFF;
+ cc = w >> 30;
+ }
+}
+
+/*
+ * Multiply an integer by the 'A24' constant (121665). Partial reduction
+ * is performed (down to less than twice the modulus).
+ */
+static void
+f255_mul_a24(uint32_t *d, const uint32_t *a)
+{
+ int i;
+ uint64_t w;
+ uint32_t cc;
+
+ /*
+ * a[] is over 256 bits, thus a[8] has length at most 16 bits.
+ * We single out the processing of the last word: intermediate
+ * value w is up to 121665*2^16, yielding a carry for the next
+ * loop of at most 19*(121665*2^16/2^15) = 4623289.
+ */
+ cc = 0;
+ for (i = 0; i < 8; i ++) {
+ w = MUL31(a[i], 121665) + (uint64_t)cc;
+ d[i] = (uint32_t)w & 0x3FFFFFFF;
+ cc = (uint32_t)(w >> 30);
+ }
+ w = MUL31(a[8], 121665) + (uint64_t)cc;
+ d[8] = (uint32_t)w & 0x7FFF;
+ cc = MUL15((uint32_t)(w >> 15), 19);
+
+ for (i = 0; i < 9; i ++) {
+ uint32_t z;
+
+ z = d[i] + cc;
+ d[i] = z & 0x3FFFFFFF;
+ cc = z >> 30;
+ }
+}
+
+static const unsigned char GEN[] = {
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const unsigned char ORDER[] = {
+ 0x7F, 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
+};
+
+static const unsigned char *
+api_generator(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return GEN;
+}
+
+static const unsigned char *
+api_order(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return ORDER;
+}
+
+static size_t
+api_xoff(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return 0;
+}
+
+static void
+cswap(uint32_t *a, uint32_t *b, uint32_t ctl)
+{
+ int i;
+
+ ctl = -ctl;
+ for (i = 0; i < 9; i ++) {
+ uint32_t aw, bw, tw;
+
+ aw = a[i];
+ bw = b[i];
+ tw = ctl & (aw ^ bw);
+ a[i] = aw ^ tw;
+ b[i] = bw ^ tw;
+ }
+}
+
+static uint32_t
+api_mul(unsigned char *G, size_t Glen,
+ const unsigned char *kb, size_t kblen, int curve)
+{
+ uint32_t x1[9], x2[9], x3[9], z2[9], z3[9];
+ uint32_t a[9], aa[9], b[9], bb[9];
+ uint32_t c[9], d[9], e[9], da[9], cb[9];
+ unsigned char k[32];
+ uint32_t swap;
+ int i;
+
+ (void)curve;
+
+ /*
+ * Points are encoded over exactly 32 bytes. Multipliers must fit
+ * in 32 bytes as well.
+ * RFC 7748 mandates that the high bit of the last point byte must
+ * be ignored/cleared.
+ */
+ if (Glen != 32 || kblen > 32) {
+ return 0;
+ }
+ G[31] &= 0x7F;
+
+ /*
+ * Initialise variables x1, x2, z2, x3 and z3. We set all of them
+ * into Montgomery representation.
+ */
+ x1[8] = le8_to_le30(x1, G, 32);
+ memcpy(x3, x1, sizeof x1);
+ memset(z2, 0, sizeof z2);
+ memset(x2, 0, sizeof x2);
+ x2[0] = 1;
+ memset(z3, 0, sizeof z3);
+ z3[0] = 1;
+
+ memset(k, 0, (sizeof k) - kblen);
+ memcpy(k + (sizeof k) - kblen, kb, kblen);
+ k[31] &= 0xF8;
+ k[0] &= 0x7F;
+ k[0] |= 0x40;
+
+ /* obsolete
+ print_int("x1", x1);
+ */
+
+ swap = 0;
+ for (i = 254; i >= 0; i --) {
+ uint32_t kt;
+
+ kt = (k[31 - (i >> 3)] >> (i & 7)) & 1;
+ swap ^= kt;
+ cswap(x2, x3, swap);
+ cswap(z2, z3, swap);
+ swap = kt;
+
+ /* obsolete
+ print_int("x2", x2);
+ print_int("z2", z2);
+ print_int("x3", x3);
+ print_int("z3", z3);
+ */
+
+ f255_add(a, x2, z2);
+ f255_square(aa, a);
+ f255_sub(b, x2, z2);
+ f255_square(bb, b);
+ f255_sub(e, aa, bb);
+ f255_add(c, x3, z3);
+ f255_sub(d, x3, z3);
+ f255_mul(da, d, a);
+ f255_mul(cb, c, b);
+
+ /* obsolete
+ print_int("a ", a);
+ print_int("aa", aa);
+ print_int("b ", b);
+ print_int("bb", bb);
+ print_int("e ", e);
+ print_int("c ", c);
+ print_int("d ", d);
+ print_int("da", da);
+ print_int("cb", cb);
+ */
+
+ f255_add(x3, da, cb);
+ f255_square(x3, x3);
+ f255_sub(z3, da, cb);
+ f255_square(z3, z3);
+ f255_mul(z3, z3, x1);
+ f255_mul(x2, aa, bb);
+ f255_mul_a24(z2, e);
+ f255_add(z2, z2, aa);
+ f255_mul(z2, e, z2);
+
+ /* obsolete
+ print_int("x2", x2);
+ print_int("z2", z2);
+ print_int("x3", x3);
+ print_int("z3", z3);
+ */
+ }
+ cswap(x2, x3, swap);
+ cswap(z2, z3, swap);
+
+ /*
+ * Inverse z2 with a modular exponentiation. This is a simple
+ * square-and-multiply algorithm; we mutualise most non-squarings
+ * since the exponent contains almost only ones.
+ */
+ memcpy(a, z2, sizeof z2);
+ for (i = 0; i < 15; i ++) {
+ f255_square(a, a);
+ f255_mul(a, a, z2);
+ }
+ memcpy(b, a, sizeof a);
+ for (i = 0; i < 14; i ++) {
+ int j;
+
+ for (j = 0; j < 16; j ++) {
+ f255_square(b, b);
+ }
+ f255_mul(b, b, a);
+ }
+ for (i = 14; i >= 0; i --) {
+ f255_square(b, b);
+ if ((0xFFEB >> i) & 1) {
+ f255_mul(b, z2, b);
+ }
+ }
+ f255_mul(x2, x2, b);
+ reduce_final_f255(x2);
+ le30_to_le8(G, 32, x2);
+ return 1;
+}
+
+static size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ const unsigned char *G;
+ size_t Glen;
+
+ G = api_generator(curve, &Glen);
+ memcpy(R, G, Glen);
+ api_mul(R, Glen, x, xlen, curve);
+ return Glen;
+}
+
+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)
+{
+ /*
+ * We don't implement this method, since it is used for ECDSA
+ * only, and there is no ECDSA over Curve25519 (which instead
+ * uses EdDSA).
+ */
+ (void)A;
+ (void)B;
+ (void)len;
+ (void)x;
+ (void)xlen;
+ (void)y;
+ (void)ylen;
+ (void)curve;
+ return 0;
+}
+
+/* see bearssl_ec.h */
+const br_ec_impl br_ec_c25519_m31 = {
+ (uint32_t)0x20000000,
+ &api_generator,
+ &api_order,
+ &api_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
diff --git a/contrib/bearssl/src/ec/ec_c25519_m62.c b/contrib/bearssl/src/ec/ec_c25519_m62.c
new file mode 100644
index 000000000000..6b058eb1bf97
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_c25519_m62.c
@@ -0,0 +1,605 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#if BR_INT128 || BR_UMUL128
+
+#if BR_UMUL128
+#include <intrin.h>
+#endif
+
+static const unsigned char GEN[] = {
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const unsigned char ORDER[] = {
+ 0x7F, 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
+};
+
+static const unsigned char *
+api_generator(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return GEN;
+}
+
+static const unsigned char *
+api_order(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return ORDER;
+}
+
+static size_t
+api_xoff(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return 0;
+}
+
+/*
+ * A field element is encoded as five 64-bit integers, in basis 2^51.
+ * Limbs may be occasionally larger than 2^51, to save on carry
+ * propagation costs.
+ */
+
+#define MASK51 (((uint64_t)1 << 51) - (uint64_t)1)
+
+/*
+ * Swap two field elements, conditionally on a flag.
+ */
+static inline void
+f255_cswap(uint64_t *a, uint64_t *b, uint32_t ctl)
+{
+ uint64_t m, w;
+
+ m = -(uint64_t)ctl;
+ w = m & (a[0] ^ b[0]); a[0] ^= w; b[0] ^= w;
+ w = m & (a[1] ^ b[1]); a[1] ^= w; b[1] ^= w;
+ w = m & (a[2] ^ b[2]); a[2] ^= w; b[2] ^= w;
+ w = m & (a[3] ^ b[3]); a[3] ^= w; b[3] ^= w;
+ w = m & (a[4] ^ b[4]); a[4] ^= w; b[4] ^= w;
+}
+
+/*
+ * Addition with no carry propagation. Limbs double in size.
+ */
+static inline void
+f255_add(uint64_t *d, const uint64_t *a, const uint64_t *b)
+{
+ d[0] = a[0] + b[0];
+ d[1] = a[1] + b[1];
+ d[2] = a[2] + b[2];
+ d[3] = a[3] + b[3];
+ d[4] = a[4] + b[4];
+}
+
+/*
+ * Subtraction.
+ * On input, limbs must fit on 60 bits each. On output, result is
+ * partially reduced, with max value 2^255+19456; moreover, all
+ * limbs will fit on 51 bits, except the low limb, which may have
+ * value up to 2^51+19455.
+ */
+static inline void
+f255_sub(uint64_t *d, const uint64_t *a, const uint64_t *b)
+{
+ uint64_t cc, w;
+
+ /*
+ * We compute d = (2^255-19)*1024 + a - b. Since the limbs
+ * fit on 60 bits, the maximum value of operands are slightly
+ * more than 2^264, but much less than 2^265-19456. This
+ * ensures that the result is positive.
+ */
+
+ /*
+ * Initial carry is 19456, since we add 2^265-19456. Each
+ * individual subtraction may yield a carry up to 513.
+ */
+ w = a[0] - b[0] - 19456;
+ d[0] = w & MASK51;
+ cc = -(w >> 51) & 0x3FF;
+ w = a[1] - b[1] - cc;
+ d[1] = w & MASK51;
+ cc = -(w >> 51) & 0x3FF;
+ w = a[2] - b[2] - cc;
+ d[2] = w & MASK51;
+ cc = -(w >> 51) & 0x3FF;
+ w = a[3] - b[3] - cc;
+ d[3] = w & MASK51;
+ cc = -(w >> 51) & 0x3FF;
+ d[4] = ((uint64_t)1 << 61) + a[4] - b[4] - cc;
+
+ /*
+ * Partial reduction. The intermediate result may be up to
+ * slightly above 2^265, but less than 2^265+2^255. When we
+ * truncate to 255 bits, the upper bits will be at most 1024.
+ */
+ d[0] += 19 * (d[4] >> 51);
+ d[4] &= MASK51;
+}
+
+/*
+ * UMUL51(hi, lo, x, y) computes:
+ *
+ * hi = floor((x * y) / (2^51))
+ * lo = x * y mod 2^51
+ *
+ * Note that lo < 2^51, but "hi" may be larger, if the input operands are
+ * larger.
+ */
+#if BR_INT128
+
+#define UMUL51(hi, lo, x, y) do { \
+ unsigned __int128 umul_tmp; \
+ umul_tmp = (unsigned __int128)(x) * (unsigned __int128)(y); \
+ (hi) = (uint64_t)(umul_tmp >> 51); \
+ (lo) = (uint64_t)umul_tmp & MASK51; \
+ } while (0)
+
+#elif BR_UMUL128
+
+#define UMUL51(hi, lo, x, y) do { \
+ uint64_t umul_hi, umul_lo; \
+ umul_lo = _umul128((x), (y), &umul_hi); \
+ (hi) = (umul_hi << 13) | (umul_lo >> 51); \
+ (lo) = umul_lo & MASK51; \
+ } while (0)
+
+#endif
+
+/*
+ * Multiplication.
+ * On input, limbs must fit on 54 bits each.
+ * On output, limb 0 is at most 2^51 + 155647, and other limbs fit
+ * on 51 bits each.
+ */
+static inline void
+f255_mul(uint64_t *d, uint64_t *a, uint64_t *b)
+{
+ uint64_t t[10], hi, lo, w, cc;
+
+ /*
+ * Perform cross products, accumulating values without carry
+ * propagation.
+ *
+ * Since input limbs fit on 54 bits each, each individual
+ * UMUL51 will produce a "hi" of less than 2^57. The maximum
+ * sum will be at most 5*(2^57-1) + 4*(2^51-1) (for t[5]),
+ * i.e. less than 324*2^51.
+ */
+
+ UMUL51(t[1], t[0], a[0], b[0]);
+
+ UMUL51(t[2], lo, a[1], b[0]); t[1] += lo;
+ UMUL51(hi, lo, a[0], b[1]); t[1] += lo; t[2] += hi;
+
+ UMUL51(t[3], lo, a[2], b[0]); t[2] += lo;
+ UMUL51(hi, lo, a[1], b[1]); t[2] += lo; t[3] += hi;
+ UMUL51(hi, lo, a[0], b[2]); t[2] += lo; t[3] += hi;
+
+ UMUL51(t[4], lo, a[3], b[0]); t[3] += lo;
+ UMUL51(hi, lo, a[2], b[1]); t[3] += lo; t[4] += hi;
+ UMUL51(hi, lo, a[1], b[2]); t[3] += lo; t[4] += hi;
+ UMUL51(hi, lo, a[0], b[3]); t[3] += lo; t[4] += hi;
+
+ UMUL51(t[5], lo, a[4], b[0]); t[4] += lo;
+ UMUL51(hi, lo, a[3], b[1]); t[4] += lo; t[5] += hi;
+ UMUL51(hi, lo, a[2], b[2]); t[4] += lo; t[5] += hi;
+ UMUL51(hi, lo, a[1], b[3]); t[4] += lo; t[5] += hi;
+ UMUL51(hi, lo, a[0], b[4]); t[4] += lo; t[5] += hi;
+
+ UMUL51(t[6], lo, a[4], b[1]); t[5] += lo;
+ UMUL51(hi, lo, a[3], b[2]); t[5] += lo; t[6] += hi;
+ UMUL51(hi, lo, a[2], b[3]); t[5] += lo; t[6] += hi;
+ UMUL51(hi, lo, a[1], b[4]); t[5] += lo; t[6] += hi;
+
+ UMUL51(t[7], lo, a[4], b[2]); t[6] += lo;
+ UMUL51(hi, lo, a[3], b[3]); t[6] += lo; t[7] += hi;
+ UMUL51(hi, lo, a[2], b[4]); t[6] += lo; t[7] += hi;
+
+ UMUL51(t[8], lo, a[4], b[3]); t[7] += lo;
+ UMUL51(hi, lo, a[3], b[4]); t[7] += lo; t[8] += hi;
+
+ UMUL51(t[9], lo, a[4], b[4]); t[8] += lo;
+
+ /*
+ * The upper words t[5]..t[9] are folded back into the lower
+ * words, using the rule that 2^255 = 19 in the field.
+ *
+ * Since each t[i] is less than 324*2^51, the additions below
+ * will yield less than 6480*2^51 in each limb; this fits in
+ * 64 bits (6480*2^51 < 8192*2^51 = 2^64), hence there is
+ * no overflow.
+ */
+ t[0] += 19 * t[5];
+ t[1] += 19 * t[6];
+ t[2] += 19 * t[7];
+ t[3] += 19 * t[8];
+ t[4] += 19 * t[9];
+
+ /*
+ * Propagate carries.
+ */
+ w = t[0];
+ d[0] = w & MASK51;
+ cc = w >> 51;
+ w = t[1] + cc;
+ d[1] = w & MASK51;
+ cc = w >> 51;
+ w = t[2] + cc;
+ d[2] = w & MASK51;
+ cc = w >> 51;
+ w = t[3] + cc;
+ d[3] = w & MASK51;
+ cc = w >> 51;
+ w = t[4] + cc;
+ d[4] = w & MASK51;
+ cc = w >> 51;
+
+ /*
+ * Since the limbs were 64-bit values, the top carry is at
+ * most 8192 (in practice, that cannot be reached). We simply
+ * performed a partial reduction.
+ */
+ d[0] += 19 * cc;
+}
+
+/*
+ * Multiplication by A24 = 121665.
+ * Input must have limbs of 60 bits at most.
+ */
+static inline void
+f255_mul_a24(uint64_t *d, const uint64_t *a)
+{
+ uint64_t t[5], cc, w;
+
+ /*
+ * 121665 = 15 * 8111. We first multiply by 15, with carry
+ * propagation and partial reduction.
+ */
+ w = a[0] * 15;
+ t[0] = w & MASK51;
+ cc = w >> 51;
+ w = a[1] * 15 + cc;
+ t[1] = w & MASK51;
+ cc = w >> 51;
+ w = a[2] * 15 + cc;
+ t[2] = w & MASK51;
+ cc = w >> 51;
+ w = a[3] * 15 + cc;
+ t[3] = w & MASK51;
+ cc = w >> 51;
+ w = a[4] * 15 + cc;
+ t[4] = w & MASK51;
+ t[0] += 19 * (w >> 51);
+
+ /*
+ * Then multiplication by 8111. At that point, we known that
+ * t[0] is less than 2^51 + 19*8192, and other limbs are less
+ * than 2^51; thus, there will be no overflow.
+ */
+ w = t[0] * 8111;
+ d[0] = w & MASK51;
+ cc = w >> 51;
+ w = t[1] * 8111 + cc;
+ d[1] = w & MASK51;
+ cc = w >> 51;
+ w = t[2] * 8111 + cc;
+ d[2] = w & MASK51;
+ cc = w >> 51;
+ w = t[3] * 8111 + cc;
+ d[3] = w & MASK51;
+ cc = w >> 51;
+ w = t[4] * 8111 + cc;
+ d[4] = w & MASK51;
+ d[0] += 19 * (w >> 51);
+}
+
+/*
+ * Finalize reduction.
+ * On input, limbs must fit on 51 bits, except possibly the low limb,
+ * which may be slightly above 2^51.
+ */
+static inline void
+f255_final_reduce(uint64_t *a)
+{
+ uint64_t t[5], cc, w;
+
+ /*
+ * We add 19. If the result (in t[]) is below 2^255, then a[]
+ * is already less than 2^255-19, thus already reduced.
+ * Otherwise, we subtract 2^255 from t[], in which case we
+ * have t = a - (2^255-19), and that's our result.
+ */
+ w = a[0] + 19;
+ t[0] = w & MASK51;
+ cc = w >> 51;
+ w = a[1] + cc;
+ t[1] = w & MASK51;
+ cc = w >> 51;
+ w = a[2] + cc;
+ t[2] = w & MASK51;
+ cc = w >> 51;
+ w = a[3] + cc;
+ t[3] = w & MASK51;
+ cc = w >> 51;
+ w = a[4] + cc;
+ t[4] = w & MASK51;
+ cc = w >> 51;
+
+ /*
+ * The bit 255 of t is in cc. If that bit is 0, when a[] must
+ * be unchanged; otherwise, it must be replaced with t[].
+ */
+ cc = -cc;
+ a[0] ^= cc & (a[0] ^ t[0]);
+ a[1] ^= cc & (a[1] ^ t[1]);
+ a[2] ^= cc & (a[2] ^ t[2]);
+ a[3] ^= cc & (a[3] ^ t[3]);
+ a[4] ^= cc & (a[4] ^ t[4]);
+}
+
+static uint32_t
+api_mul(unsigned char *G, size_t Glen,
+ const unsigned char *kb, size_t kblen, int curve)
+{
+ unsigned char k[32];
+ uint64_t x1[5], x2[5], z2[5], x3[5], z3[5];
+ uint32_t swap;
+ int i;
+
+ (void)curve;
+
+ /*
+ * Points are encoded over exactly 32 bytes. Multipliers must fit
+ * in 32 bytes as well.
+ */
+ if (Glen != 32 || kblen > 32) {
+ return 0;
+ }
+
+ /*
+ * RFC 7748 mandates that the high bit of the last point byte must
+ * be ignored/cleared; the "& MASK51" in the initialization for
+ * x1[4] clears that bit.
+ */
+ x1[0] = br_dec64le(&G[0]) & MASK51;
+ x1[1] = (br_dec64le(&G[6]) >> 3) & MASK51;
+ x1[2] = (br_dec64le(&G[12]) >> 6) & MASK51;
+ x1[3] = (br_dec64le(&G[19]) >> 1) & MASK51;
+ x1[4] = (br_dec64le(&G[24]) >> 12) & MASK51;
+
+ /*
+ * We can use memset() to clear values, because exact-width types
+ * like uint64_t are guaranteed to have no padding bits or
+ * trap representations.
+ */
+ memset(x2, 0, sizeof x2);
+ x2[0] = 1;
+ memset(z2, 0, sizeof z2);
+ memcpy(x3, x1, sizeof x1);
+ memcpy(z3, x2, sizeof x2);
+
+ /*
+ * The multiplier is provided in big-endian notation, and
+ * possibly shorter than 32 bytes.
+ */
+ memset(k, 0, (sizeof k) - kblen);
+ memcpy(k + (sizeof k) - kblen, kb, kblen);
+ k[31] &= 0xF8;
+ k[0] &= 0x7F;
+ k[0] |= 0x40;
+
+ swap = 0;
+
+ for (i = 254; i >= 0; i --) {
+ uint64_t a[5], aa[5], b[5], bb[5], e[5];
+ uint64_t c[5], d[5], da[5], cb[5];
+ uint32_t kt;
+
+ kt = (k[31 - (i >> 3)] >> (i & 7)) & 1;
+ swap ^= kt;
+ f255_cswap(x2, x3, swap);
+ f255_cswap(z2, z3, swap);
+ swap = kt;
+
+ /*
+ * At that point, limbs of x_2 and z_2 are assumed to fit
+ * on at most 52 bits each.
+ *
+ * Each f255_add() adds one bit to the maximum range of
+ * the values, but f255_sub() and f255_mul() bring back
+ * the limbs into 52 bits. All f255_add() outputs are
+ * used only as inputs for f255_mul(), which ensures
+ * that limbs remain in the proper range.
+ */
+
+ /* A = x_2 + z_2 -- limbs fit on 53 bits each */
+ f255_add(a, x2, z2);
+
+ /* AA = A^2 */
+ f255_mul(aa, a, a);
+
+ /* B = x_2 - z_2 */
+ f255_sub(b, x2, z2);
+
+ /* BB = B^2 */
+ f255_mul(bb, b, b);
+
+ /* E = AA - BB */
+ f255_sub(e, aa, bb);
+
+ /* C = x_3 + z_3 -- limbs fit on 53 bits each */
+ f255_add(c, x3, z3);
+
+ /* D = x_3 - z_3 */
+ f255_sub(d, x3, z3);
+
+ /* DA = D * A */
+ f255_mul(da, d, a);
+
+ /* CB = C * B */
+ f255_mul(cb, c, b);
+
+ /* x_3 = (DA + CB)^2 */
+ f255_add(x3, da, cb);
+ f255_mul(x3, x3, x3);
+
+ /* z_3 = x_1 * (DA - CB)^2 */
+ f255_sub(z3, da, cb);
+ f255_mul(z3, z3, z3);
+ f255_mul(z3, x1, z3);
+
+ /* x_2 = AA * BB */
+ f255_mul(x2, aa, bb);
+
+ /* z_2 = E * (AA + a24 * E) */
+ f255_mul_a24(z2, e);
+ f255_add(z2, aa, z2);
+ f255_mul(z2, e, z2);
+ }
+
+ f255_cswap(x2, x3, swap);
+ f255_cswap(z2, z3, swap);
+
+ /*
+ * Compute 1/z2 = z2^(p-2). Since p = 2^255-19, we can mutualize
+ * most non-squarings. We use x1 and x3, now useless, as temporaries.
+ */
+ memcpy(x1, z2, sizeof z2);
+ for (i = 0; i < 15; i ++) {
+ f255_mul(x1, x1, x1);
+ f255_mul(x1, x1, z2);
+ }
+ memcpy(x3, x1, sizeof x1);
+ for (i = 0; i < 14; i ++) {
+ int j;
+
+ for (j = 0; j < 16; j ++) {
+ f255_mul(x3, x3, x3);
+ }
+ f255_mul(x3, x3, x1);
+ }
+ for (i = 14; i >= 0; i --) {
+ f255_mul(x3, x3, x3);
+ if ((0xFFEB >> i) & 1) {
+ f255_mul(x3, z2, x3);
+ }
+ }
+
+ /*
+ * Compute x2/z2. We have 1/z2 in x3.
+ */
+ f255_mul(x2, x2, x3);
+ f255_final_reduce(x2);
+
+ /*
+ * Encode the final x2 value in little-endian. We first assemble
+ * the limbs into 64-bit values.
+ */
+ x2[0] |= x2[1] << 51;
+ x2[1] = (x2[1] >> 13) | (x2[2] << 38);
+ x2[2] = (x2[2] >> 26) | (x2[3] << 25);
+ x2[3] = (x2[3] >> 39) | (x2[4] << 12);
+ br_enc64le(G, x2[0]);
+ br_enc64le(G + 8, x2[1]);
+ br_enc64le(G + 16, x2[2]);
+ br_enc64le(G + 24, x2[3]);
+ return 1;
+}
+
+static size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ const unsigned char *G;
+ size_t Glen;
+
+ G = api_generator(curve, &Glen);
+ memcpy(R, G, Glen);
+ api_mul(R, Glen, x, xlen, curve);
+ return Glen;
+}
+
+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)
+{
+ /*
+ * We don't implement this method, since it is used for ECDSA
+ * only, and there is no ECDSA over Curve25519 (which instead
+ * uses EdDSA).
+ */
+ (void)A;
+ (void)B;
+ (void)len;
+ (void)x;
+ (void)xlen;
+ (void)y;
+ (void)ylen;
+ (void)curve;
+ return 0;
+}
+
+/* see bearssl_ec.h */
+const br_ec_impl br_ec_c25519_m62 = {
+ (uint32_t)0x20000000,
+ &api_generator,
+ &api_order,
+ &api_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
+
+/* see bearssl_ec.h */
+const br_ec_impl *
+br_ec_c25519_m62_get(void)
+{
+ return &br_ec_c25519_m62;
+}
+
+#else
+
+/* see bearssl_ec.h */
+const br_ec_impl *
+br_ec_c25519_m62_get(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/contrib/bearssl/src/ec/ec_c25519_m64.c b/contrib/bearssl/src/ec/ec_c25519_m64.c
new file mode 100644
index 000000000000..7e7f12f7e3ad
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_c25519_m64.c
@@ -0,0 +1,835 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#if BR_INT128 || BR_UMUL128
+
+#if BR_UMUL128
+#include <intrin.h>
+#endif
+
+static const unsigned char GEN[] = {
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const unsigned char ORDER[] = {
+ 0x7F, 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
+};
+
+static const unsigned char *
+api_generator(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return GEN;
+}
+
+static const unsigned char *
+api_order(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return ORDER;
+}
+
+static size_t
+api_xoff(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return 0;
+}
+
+/*
+ * A field element is encoded as four 64-bit integers, in basis 2^63.
+ * Operations return partially reduced values, which may range up to
+ * 2^255+37.
+ */
+
+#define MASK63 (((uint64_t)1 << 63) - (uint64_t)1)
+
+/*
+ * Swap two field elements, conditionally on a flag.
+ */
+static inline void
+f255_cswap(uint64_t *a, uint64_t *b, uint32_t ctl)
+{
+ uint64_t m, w;
+
+ m = -(uint64_t)ctl;
+ w = m & (a[0] ^ b[0]); a[0] ^= w; b[0] ^= w;
+ w = m & (a[1] ^ b[1]); a[1] ^= w; b[1] ^= w;
+ w = m & (a[2] ^ b[2]); a[2] ^= w; b[2] ^= w;
+ w = m & (a[3] ^ b[3]); a[3] ^= w; b[3] ^= w;
+}
+
+/*
+ * Addition in the field.
+ */
+static inline void
+f255_add(uint64_t *d, const uint64_t *a, const uint64_t *b)
+{
+#if BR_INT128
+
+ uint64_t t0, t1, t2, t3, cc;
+ unsigned __int128 z;
+
+ z = (unsigned __int128)a[0] + (unsigned __int128)b[0];
+ t0 = (uint64_t)z;
+ z = (unsigned __int128)a[1] + (unsigned __int128)b[1] + (z >> 64);
+ t1 = (uint64_t)z;
+ z = (unsigned __int128)a[2] + (unsigned __int128)b[2] + (z >> 64);
+ t2 = (uint64_t)z;
+ z = (unsigned __int128)a[3] + (unsigned __int128)b[3] + (z >> 64);
+ t3 = (uint64_t)z & MASK63;
+ cc = (uint64_t)(z >> 63);
+
+ /*
+ * Since operands are at most 2^255+37, the sum is at most
+ * 2^256+74; thus, the carry cc is equal to 0, 1 or 2.
+ *
+ * We use: 2^255 = 19 mod p.
+ * Since we add 0, 19 or 38 to a value that fits on 255 bits,
+ * the result is at most 2^255+37.
+ */
+ z = (unsigned __int128)t0 + (unsigned __int128)(19 * cc);
+ d[0] = (uint64_t)z;
+ z = (unsigned __int128)t1 + (z >> 64);
+ d[1] = (uint64_t)z;
+ z = (unsigned __int128)t2 + (z >> 64);
+ d[2] = (uint64_t)z;
+ d[3] = t3 + (uint64_t)(z >> 64);
+
+#elif BR_UMUL128
+
+ uint64_t t0, t1, t2, t3, cc;
+ unsigned char k;
+
+ k = _addcarry_u64(0, a[0], b[0], &t0);
+ k = _addcarry_u64(k, a[1], b[1], &t1);
+ k = _addcarry_u64(k, a[2], b[2], &t2);
+ k = _addcarry_u64(k, a[3], b[3], &t3);
+ cc = (k << 1) + (t3 >> 63);
+ t3 &= MASK63;
+
+ /*
+ * Since operands are at most 2^255+37, the sum is at most
+ * 2^256+74; thus, the carry cc is equal to 0, 1 or 2.
+ *
+ * We use: 2^255 = 19 mod p.
+ * Since we add 0, 19 or 38 to a value that fits on 255 bits,
+ * the result is at most 2^255+37.
+ */
+ k = _addcarry_u64(0, t0, 19 * cc, &d[0]);
+ k = _addcarry_u64(k, t1, 0, &d[1]);
+ k = _addcarry_u64(k, t2, 0, &d[2]);
+ (void)_addcarry_u64(k, t3, 0, &d[3]);
+
+#endif
+}
+
+/*
+ * Subtraction.
+ * On input, limbs must fit on 60 bits each. On output, result is
+ * partially reduced, with max value 2^255+19456; moreover, all
+ * limbs will fit on 51 bits, except the low limb, which may have
+ * value up to 2^51+19455.
+ */
+static inline void
+f255_sub(uint64_t *d, const uint64_t *a, const uint64_t *b)
+{
+#if BR_INT128
+
+ /*
+ * We compute t = 2^256 - 38 + a - b, which is necessarily
+ * positive but lower than 2^256 + 2^255, since a <= 2^255 + 37
+ * and b <= 2^255 + 37. We then subtract 0, p or 2*p, depending
+ * on the two upper bits of t (bits 255 and 256).
+ */
+
+ uint64_t t0, t1, t2, t3, t4, cc;
+ unsigned __int128 z;
+
+ z = (unsigned __int128)a[0] - (unsigned __int128)b[0] - 38;
+ t0 = (uint64_t)z;
+ cc = -(uint64_t)(z >> 64);
+ z = (unsigned __int128)a[1] - (unsigned __int128)b[1]
+ - (unsigned __int128)cc;
+ t1 = (uint64_t)z;
+ cc = -(uint64_t)(z >> 64);
+ z = (unsigned __int128)a[2] - (unsigned __int128)b[2]
+ - (unsigned __int128)cc;
+ t2 = (uint64_t)z;
+ cc = -(uint64_t)(z >> 64);
+ z = (unsigned __int128)a[3] - (unsigned __int128)b[3]
+ - (unsigned __int128)cc;
+ t3 = (uint64_t)z;
+ t4 = 1 + (uint64_t)(z >> 64);
+
+ /*
+ * We have a 257-bit result. The two top bits can be 00, 01 or 10,
+ * but not 11 (value t <= 2^256 - 38 + 2^255 + 37 = 2^256 + 2^255 - 1).
+ * Therefore, we can truncate to 255 bits, and add 0, 19 or 38.
+ * This guarantees that the result is at most 2^255+37.
+ */
+ cc = (38 & -t4) + (19 & -(t3 >> 63));
+ t3 &= MASK63;
+ z = (unsigned __int128)t0 + (unsigned __int128)cc;
+ d[0] = (uint64_t)z;
+ z = (unsigned __int128)t1 + (z >> 64);
+ d[1] = (uint64_t)z;
+ z = (unsigned __int128)t2 + (z >> 64);
+ d[2] = (uint64_t)z;
+ d[3] = t3 + (uint64_t)(z >> 64);
+
+#elif BR_UMUL128
+
+ /*
+ * We compute t = 2^256 - 38 + a - b, which is necessarily
+ * positive but lower than 2^256 + 2^255, since a <= 2^255 + 37
+ * and b <= 2^255 + 37. We then subtract 0, p or 2*p, depending
+ * on the two upper bits of t (bits 255 and 256).
+ */
+
+ uint64_t t0, t1, t2, t3, t4;
+ unsigned char k;
+
+ k = _subborrow_u64(0, a[0], b[0], &t0);
+ k = _subborrow_u64(k, a[1], b[1], &t1);
+ k = _subborrow_u64(k, a[2], b[2], &t2);
+ k = _subborrow_u64(k, a[3], b[3], &t3);
+ (void)_subborrow_u64(k, 1, 0, &t4);
+
+ k = _subborrow_u64(0, t0, 38, &t0);
+ k = _subborrow_u64(k, t1, 0, &t1);
+ k = _subborrow_u64(k, t2, 0, &t2);
+ k = _subborrow_u64(k, t3, 0, &t3);
+ (void)_subborrow_u64(k, t4, 0, &t4);
+
+ /*
+ * We have a 257-bit result. The two top bits can be 00, 01 or 10,
+ * but not 11 (value t <= 2^256 - 38 + 2^255 + 37 = 2^256 + 2^255 - 1).
+ * Therefore, we can truncate to 255 bits, and add 0, 19 or 38.
+ * This guarantees that the result is at most 2^255+37.
+ */
+ t4 = (38 & -t4) + (19 & -(t3 >> 63));
+ t3 &= MASK63;
+ k = _addcarry_u64(0, t0, t4, &d[0]);
+ k = _addcarry_u64(k, t1, 0, &d[1]);
+ k = _addcarry_u64(k, t2, 0, &d[2]);
+ (void)_addcarry_u64(k, t3, 0, &d[3]);
+
+#endif
+}
+
+/*
+ * Multiplication.
+ */
+static inline void
+f255_mul(uint64_t *d, uint64_t *a, uint64_t *b)
+{
+#if BR_INT128
+
+ unsigned __int128 z;
+ uint64_t t0, t1, t2, t3, t4, t5, t6, t7, th;
+
+ /*
+ * Compute the product a*b over plain integers.
+ */
+ z = (unsigned __int128)a[0] * (unsigned __int128)b[0];
+ t0 = (uint64_t)z;
+ z = (unsigned __int128)a[0] * (unsigned __int128)b[1] + (z >> 64);
+ t1 = (uint64_t)z;
+ z = (unsigned __int128)a[0] * (unsigned __int128)b[2] + (z >> 64);
+ t2 = (uint64_t)z;
+ z = (unsigned __int128)a[0] * (unsigned __int128)b[3] + (z >> 64);
+ t3 = (uint64_t)z;
+ t4 = (uint64_t)(z >> 64);
+
+ z = (unsigned __int128)a[1] * (unsigned __int128)b[0]
+ + (unsigned __int128)t1;
+ t1 = (uint64_t)z;
+ z = (unsigned __int128)a[1] * (unsigned __int128)b[1]
+ + (unsigned __int128)t2 + (z >> 64);
+ t2 = (uint64_t)z;
+ z = (unsigned __int128)a[1] * (unsigned __int128)b[2]
+ + (unsigned __int128)t3 + (z >> 64);
+ t3 = (uint64_t)z;
+ z = (unsigned __int128)a[1] * (unsigned __int128)b[3]
+ + (unsigned __int128)t4 + (z >> 64);
+ t4 = (uint64_t)z;
+ t5 = (uint64_t)(z >> 64);
+
+ z = (unsigned __int128)a[2] * (unsigned __int128)b[0]
+ + (unsigned __int128)t2;
+ t2 = (uint64_t)z;
+ z = (unsigned __int128)a[2] * (unsigned __int128)b[1]
+ + (unsigned __int128)t3 + (z >> 64);
+ t3 = (uint64_t)z;
+ z = (unsigned __int128)a[2] * (unsigned __int128)b[2]
+ + (unsigned __int128)t4 + (z >> 64);
+ t4 = (uint64_t)z;
+ z = (unsigned __int128)a[2] * (unsigned __int128)b[3]
+ + (unsigned __int128)t5 + (z >> 64);
+ t5 = (uint64_t)z;
+ t6 = (uint64_t)(z >> 64);
+
+ z = (unsigned __int128)a[3] * (unsigned __int128)b[0]
+ + (unsigned __int128)t3;
+ t3 = (uint64_t)z;
+ z = (unsigned __int128)a[3] * (unsigned __int128)b[1]
+ + (unsigned __int128)t4 + (z >> 64);
+ t4 = (uint64_t)z;
+ z = (unsigned __int128)a[3] * (unsigned __int128)b[2]
+ + (unsigned __int128)t5 + (z >> 64);
+ t5 = (uint64_t)z;
+ z = (unsigned __int128)a[3] * (unsigned __int128)b[3]
+ + (unsigned __int128)t6 + (z >> 64);
+ t6 = (uint64_t)z;
+ t7 = (uint64_t)(z >> 64);
+
+ /*
+ * Modulo p, we have:
+ *
+ * 2^255 = 19
+ * 2^510 = 19*19 = 361
+ *
+ * We split the intermediate t into three parts, in basis
+ * 2^255. The low one will be in t0..t3; the middle one in t4..t7.
+ * The upper one can only be a single bit (th), since the
+ * multiplication operands are at most 2^255+37 each.
+ */
+ th = t7 >> 62;
+ t7 = ((t7 << 1) | (t6 >> 63)) & MASK63;
+ t6 = (t6 << 1) | (t5 >> 63);
+ t5 = (t5 << 1) | (t4 >> 63);
+ t4 = (t4 << 1) | (t3 >> 63);
+ t3 &= MASK63;
+
+ /*
+ * Multiply the middle part (t4..t7) by 19. We truncate it to
+ * 255 bits; the extra bits will go along with th.
+ */
+ z = (unsigned __int128)t4 * 19;
+ t4 = (uint64_t)z;
+ z = (unsigned __int128)t5 * 19 + (z >> 64);
+ t5 = (uint64_t)z;
+ z = (unsigned __int128)t6 * 19 + (z >> 64);
+ t6 = (uint64_t)z;
+ z = (unsigned __int128)t7 * 19 + (z >> 64);
+ t7 = (uint64_t)z & MASK63;
+
+ th = (361 & -th) + (19 * (uint64_t)(z >> 63));
+
+ /*
+ * Add elements together.
+ * At this point:
+ * t0..t3 fits on 255 bits.
+ * t4..t7 fits on 255 bits.
+ * th <= 361 + 342 = 703.
+ */
+ z = (unsigned __int128)t0 + (unsigned __int128)t4
+ + (unsigned __int128)th;
+ t0 = (uint64_t)z;
+ z = (unsigned __int128)t1 + (unsigned __int128)t5 + (z >> 64);
+ t1 = (uint64_t)z;
+ z = (unsigned __int128)t2 + (unsigned __int128)t6 + (z >> 64);
+ t2 = (uint64_t)z;
+ z = (unsigned __int128)t3 + (unsigned __int128)t7 + (z >> 64);
+ t3 = (uint64_t)z & MASK63;
+ th = (uint64_t)(z >> 63);
+
+ /*
+ * Since the sum is at most 2^256 + 703, the two upper bits, in th,
+ * can only have value 0, 1 or 2. We just add th*19, which
+ * guarantees a result of at most 2^255+37.
+ */
+ z = (unsigned __int128)t0 + (19 * th);
+ d[0] = (uint64_t)z;
+ z = (unsigned __int128)t1 + (z >> 64);
+ d[1] = (uint64_t)z;
+ z = (unsigned __int128)t2 + (z >> 64);
+ d[2] = (uint64_t)z;
+ d[3] = t3 + (uint64_t)(z >> 64);
+
+#elif BR_UMUL128
+
+ uint64_t t0, t1, t2, t3, t4, t5, t6, t7, th;
+ uint64_t h0, h1, h2, h3;
+ unsigned char k;
+
+ /*
+ * Compute the product a*b over plain integers.
+ */
+ t0 = _umul128(a[0], b[0], &h0);
+ t1 = _umul128(a[0], b[1], &h1);
+ k = _addcarry_u64(0, t1, h0, &t1);
+ t2 = _umul128(a[0], b[2], &h2);
+ k = _addcarry_u64(k, t2, h1, &t2);
+ t3 = _umul128(a[0], b[3], &h3);
+ k = _addcarry_u64(k, t3, h2, &t3);
+ (void)_addcarry_u64(k, h3, 0, &t4);
+
+ k = _addcarry_u64(0, _umul128(a[1], b[0], &h0), t1, &t1);
+ k = _addcarry_u64(k, _umul128(a[1], b[1], &h1), t2, &t2);
+ k = _addcarry_u64(k, _umul128(a[1], b[2], &h2), t3, &t3);
+ k = _addcarry_u64(k, _umul128(a[1], b[3], &h3), t4, &t4);
+ t5 = k;
+ k = _addcarry_u64(0, t2, h0, &t2);
+ k = _addcarry_u64(k, t3, h1, &t3);
+ k = _addcarry_u64(k, t4, h2, &t4);
+ (void)_addcarry_u64(k, t5, h3, &t5);
+
+ k = _addcarry_u64(0, _umul128(a[2], b[0], &h0), t2, &t2);
+ k = _addcarry_u64(k, _umul128(a[2], b[1], &h1), t3, &t3);
+ k = _addcarry_u64(k, _umul128(a[2], b[2], &h2), t4, &t4);
+ k = _addcarry_u64(k, _umul128(a[2], b[3], &h3), t5, &t5);
+ t6 = k;
+ k = _addcarry_u64(0, t3, h0, &t3);
+ k = _addcarry_u64(k, t4, h1, &t4);
+ k = _addcarry_u64(k, t5, h2, &t5);
+ (void)_addcarry_u64(k, t6, h3, &t6);
+
+ k = _addcarry_u64(0, _umul128(a[3], b[0], &h0), t3, &t3);
+ k = _addcarry_u64(k, _umul128(a[3], b[1], &h1), t4, &t4);
+ k = _addcarry_u64(k, _umul128(a[3], b[2], &h2), t5, &t5);
+ k = _addcarry_u64(k, _umul128(a[3], b[3], &h3), t6, &t6);
+ t7 = k;
+ k = _addcarry_u64(0, t4, h0, &t4);
+ k = _addcarry_u64(k, t5, h1, &t5);
+ k = _addcarry_u64(k, t6, h2, &t6);
+ (void)_addcarry_u64(k, t7, h3, &t7);
+
+ /*
+ * Modulo p, we have:
+ *
+ * 2^255 = 19
+ * 2^510 = 19*19 = 361
+ *
+ * We split the intermediate t into three parts, in basis
+ * 2^255. The low one will be in t0..t3; the middle one in t4..t7.
+ * The upper one can only be a single bit (th), since the
+ * multiplication operands are at most 2^255+37 each.
+ */
+ th = t7 >> 62;
+ t7 = ((t7 << 1) | (t6 >> 63)) & MASK63;
+ t6 = (t6 << 1) | (t5 >> 63);
+ t5 = (t5 << 1) | (t4 >> 63);
+ t4 = (t4 << 1) | (t3 >> 63);
+ t3 &= MASK63;
+
+ /*
+ * Multiply the middle part (t4..t7) by 19. We truncate it to
+ * 255 bits; the extra bits will go along with th.
+ */
+ t4 = _umul128(t4, 19, &h0);
+ t5 = _umul128(t5, 19, &h1);
+ t6 = _umul128(t6, 19, &h2);
+ t7 = _umul128(t7, 19, &h3);
+ k = _addcarry_u64(0, t5, h0, &t5);
+ k = _addcarry_u64(k, t6, h1, &t6);
+ k = _addcarry_u64(k, t7, h2, &t7);
+ (void)_addcarry_u64(k, h3, 0, &h3);
+ th = (361 & -th) + (19 * ((h3 << 1) + (t7 >> 63)));
+ t7 &= MASK63;
+
+ /*
+ * Add elements together.
+ * At this point:
+ * t0..t3 fits on 255 bits.
+ * t4..t7 fits on 255 bits.
+ * th <= 361 + 342 = 703.
+ */
+ k = _addcarry_u64(0, t0, t4, &t0);
+ k = _addcarry_u64(k, t1, t5, &t1);
+ k = _addcarry_u64(k, t2, t6, &t2);
+ k = _addcarry_u64(k, t3, t7, &t3);
+ t4 = k;
+ k = _addcarry_u64(0, t0, th, &t0);
+ k = _addcarry_u64(k, t1, 0, &t1);
+ k = _addcarry_u64(k, t2, 0, &t2);
+ k = _addcarry_u64(k, t3, 0, &t3);
+ (void)_addcarry_u64(k, t4, 0, &t4);
+
+ th = (t4 << 1) + (t3 >> 63);
+ t3 &= MASK63;
+
+ /*
+ * Since the sum is at most 2^256 + 703, the two upper bits, in th,
+ * can only have value 0, 1 or 2. We just add th*19, which
+ * guarantees a result of at most 2^255+37.
+ */
+ k = _addcarry_u64(0, t0, 19 * th, &d[0]);
+ k = _addcarry_u64(k, t1, 0, &d[1]);
+ k = _addcarry_u64(k, t2, 0, &d[2]);
+ (void)_addcarry_u64(k, t3, 0, &d[3]);
+
+#endif
+}
+
+/*
+ * Multiplication by A24 = 121665.
+ */
+static inline void
+f255_mul_a24(uint64_t *d, const uint64_t *a)
+{
+#if BR_INT128
+
+ uint64_t t0, t1, t2, t3;
+ unsigned __int128 z;
+
+ z = (unsigned __int128)a[0] * 121665;
+ t0 = (uint64_t)z;
+ z = (unsigned __int128)a[1] * 121665 + (z >> 64);
+ t1 = (uint64_t)z;
+ z = (unsigned __int128)a[2] * 121665 + (z >> 64);
+ t2 = (uint64_t)z;
+ z = (unsigned __int128)a[3] * 121665 + (z >> 64);
+ t3 = (uint64_t)z & MASK63;
+
+ z = (unsigned __int128)t0 + (19 * (uint64_t)(z >> 63));
+ t0 = (uint64_t)z;
+ z = (unsigned __int128)t1 + (z >> 64);
+ t1 = (uint64_t)z;
+ z = (unsigned __int128)t2 + (z >> 64);
+ t2 = (uint64_t)z;
+ t3 = t3 + (uint64_t)(z >> 64);
+
+ z = (unsigned __int128)t0 + (19 & -(t3 >> 63));
+ d[0] = (uint64_t)z;
+ z = (unsigned __int128)t1 + (z >> 64);
+ d[1] = (uint64_t)z;
+ z = (unsigned __int128)t2 + (z >> 64);
+ d[2] = (uint64_t)z;
+ d[3] = (t3 & MASK63) + (uint64_t)(z >> 64);
+
+#elif BR_UMUL128
+
+ uint64_t t0, t1, t2, t3, t4, h0, h1, h2, h3;
+ unsigned char k;
+
+ t0 = _umul128(a[0], 121665, &h0);
+ t1 = _umul128(a[1], 121665, &h1);
+ k = _addcarry_u64(0, t1, h0, &t1);
+ t2 = _umul128(a[2], 121665, &h2);
+ k = _addcarry_u64(k, t2, h1, &t2);
+ t3 = _umul128(a[3], 121665, &h3);
+ k = _addcarry_u64(k, t3, h2, &t3);
+ (void)_addcarry_u64(k, h3, 0, &t4);
+
+ t4 = (t4 << 1) + (t3 >> 63);
+ t3 &= MASK63;
+ k = _addcarry_u64(0, t0, 19 * t4, &t0);
+ k = _addcarry_u64(k, t1, 0, &t1);
+ k = _addcarry_u64(k, t2, 0, &t2);
+ (void)_addcarry_u64(k, t3, 0, &t3);
+
+ t4 = 19 & -(t3 >> 63);
+ t3 &= MASK63;
+ k = _addcarry_u64(0, t0, t4, &d[0]);
+ k = _addcarry_u64(k, t1, 0, &d[1]);
+ k = _addcarry_u64(k, t2, 0, &d[2]);
+ (void)_addcarry_u64(k, t3, 0, &d[3]);
+
+#endif
+}
+
+/*
+ * Finalize reduction.
+ */
+static inline void
+f255_final_reduce(uint64_t *a)
+{
+#if BR_INT128
+
+ uint64_t t0, t1, t2, t3, m;
+ unsigned __int128 z;
+
+ /*
+ * We add 19. If the result (in t) is below 2^255, then a[]
+ * is already less than 2^255-19, thus already reduced.
+ * Otherwise, we subtract 2^255 from t[], in which case we
+ * have t = a - (2^255-19), and that's our result.
+ */
+ z = (unsigned __int128)a[0] + 19;
+ t0 = (uint64_t)z;
+ z = (unsigned __int128)a[1] + (z >> 64);
+ t1 = (uint64_t)z;
+ z = (unsigned __int128)a[2] + (z >> 64);
+ t2 = (uint64_t)z;
+ t3 = a[3] + (uint64_t)(z >> 64);
+
+ m = -(t3 >> 63);
+ t3 &= MASK63;
+ a[0] ^= m & (a[0] ^ t0);
+ a[1] ^= m & (a[1] ^ t1);
+ a[2] ^= m & (a[2] ^ t2);
+ a[3] ^= m & (a[3] ^ t3);
+
+#elif BR_UMUL128
+
+ uint64_t t0, t1, t2, t3, m;
+ unsigned char k;
+
+ /*
+ * We add 19. If the result (in t) is below 2^255, then a[]
+ * is already less than 2^255-19, thus already reduced.
+ * Otherwise, we subtract 2^255 from t[], in which case we
+ * have t = a - (2^255-19), and that's our result.
+ */
+ k = _addcarry_u64(0, a[0], 19, &t0);
+ k = _addcarry_u64(k, a[1], 0, &t1);
+ k = _addcarry_u64(k, a[2], 0, &t2);
+ (void)_addcarry_u64(k, a[3], 0, &t3);
+
+ m = -(t3 >> 63);
+ t3 &= MASK63;
+ a[0] ^= m & (a[0] ^ t0);
+ a[1] ^= m & (a[1] ^ t1);
+ a[2] ^= m & (a[2] ^ t2);
+ a[3] ^= m & (a[3] ^ t3);
+
+#endif
+}
+
+static uint32_t
+api_mul(unsigned char *G, size_t Glen,
+ const unsigned char *kb, size_t kblen, int curve)
+{
+ unsigned char k[32];
+ uint64_t x1[4], x2[4], z2[4], x3[4], z3[4];
+ uint32_t swap;
+ int i;
+
+ (void)curve;
+
+ /*
+ * Points are encoded over exactly 32 bytes. Multipliers must fit
+ * in 32 bytes as well.
+ */
+ if (Glen != 32 || kblen > 32) {
+ return 0;
+ }
+
+ /*
+ * RFC 7748 mandates that the high bit of the last point byte must
+ * be ignored/cleared.
+ */
+ x1[0] = br_dec64le(&G[ 0]);
+ x1[1] = br_dec64le(&G[ 8]);
+ x1[2] = br_dec64le(&G[16]);
+ x1[3] = br_dec64le(&G[24]) & MASK63;
+
+ /*
+ * We can use memset() to clear values, because exact-width types
+ * like uint64_t are guaranteed to have no padding bits or
+ * trap representations.
+ */
+ memset(x2, 0, sizeof x2);
+ x2[0] = 1;
+ memset(z2, 0, sizeof z2);
+ memcpy(x3, x1, sizeof x1);
+ memcpy(z3, x2, sizeof x2);
+
+ /*
+ * The multiplier is provided in big-endian notation, and
+ * possibly shorter than 32 bytes.
+ */
+ memset(k, 0, (sizeof k) - kblen);
+ memcpy(k + (sizeof k) - kblen, kb, kblen);
+ k[31] &= 0xF8;
+ k[0] &= 0x7F;
+ k[0] |= 0x40;
+
+ swap = 0;
+
+ for (i = 254; i >= 0; i --) {
+ uint64_t a[4], aa[4], b[4], bb[4], e[4];
+ uint64_t c[4], d[4], da[4], cb[4];
+ uint32_t kt;
+
+ kt = (k[31 - (i >> 3)] >> (i & 7)) & 1;
+ swap ^= kt;
+ f255_cswap(x2, x3, swap);
+ f255_cswap(z2, z3, swap);
+ swap = kt;
+
+ /* A = x_2 + z_2 */
+ f255_add(a, x2, z2);
+
+ /* AA = A^2 */
+ f255_mul(aa, a, a);
+
+ /* B = x_2 - z_2 */
+ f255_sub(b, x2, z2);
+
+ /* BB = B^2 */
+ f255_mul(bb, b, b);
+
+ /* E = AA - BB */
+ f255_sub(e, aa, bb);
+
+ /* C = x_3 + z_3 */
+ f255_add(c, x3, z3);
+
+ /* D = x_3 - z_3 */
+ f255_sub(d, x3, z3);
+
+ /* DA = D * A */
+ f255_mul(da, d, a);
+
+ /* CB = C * B */
+ f255_mul(cb, c, b);
+
+ /* x_3 = (DA + CB)^2 */
+ f255_add(x3, da, cb);
+ f255_mul(x3, x3, x3);
+
+ /* z_3 = x_1 * (DA - CB)^2 */
+ f255_sub(z3, da, cb);
+ f255_mul(z3, z3, z3);
+ f255_mul(z3, x1, z3);
+
+ /* x_2 = AA * BB */
+ f255_mul(x2, aa, bb);
+
+ /* z_2 = E * (AA + a24 * E) */
+ f255_mul_a24(z2, e);
+ f255_add(z2, aa, z2);
+ f255_mul(z2, e, z2);
+ }
+
+ f255_cswap(x2, x3, swap);
+ f255_cswap(z2, z3, swap);
+
+ /*
+ * Compute 1/z2 = z2^(p-2). Since p = 2^255-19, we can mutualize
+ * most non-squarings. We use x1 and x3, now useless, as temporaries.
+ */
+ memcpy(x1, z2, sizeof z2);
+ for (i = 0; i < 15; i ++) {
+ f255_mul(x1, x1, x1);
+ f255_mul(x1, x1, z2);
+ }
+ memcpy(x3, x1, sizeof x1);
+ for (i = 0; i < 14; i ++) {
+ int j;
+
+ for (j = 0; j < 16; j ++) {
+ f255_mul(x3, x3, x3);
+ }
+ f255_mul(x3, x3, x1);
+ }
+ for (i = 14; i >= 0; i --) {
+ f255_mul(x3, x3, x3);
+ if ((0xFFEB >> i) & 1) {
+ f255_mul(x3, z2, x3);
+ }
+ }
+
+ /*
+ * Compute x2/z2. We have 1/z2 in x3.
+ */
+ f255_mul(x2, x2, x3);
+ f255_final_reduce(x2);
+
+ /*
+ * Encode the final x2 value in little-endian.
+ */
+ br_enc64le(G, x2[0]);
+ br_enc64le(G + 8, x2[1]);
+ br_enc64le(G + 16, x2[2]);
+ br_enc64le(G + 24, x2[3]);
+ return 1;
+}
+
+static size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ const unsigned char *G;
+ size_t Glen;
+
+ G = api_generator(curve, &Glen);
+ memcpy(R, G, Glen);
+ api_mul(R, Glen, x, xlen, curve);
+ return Glen;
+}
+
+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)
+{
+ /*
+ * We don't implement this method, since it is used for ECDSA
+ * only, and there is no ECDSA over Curve25519 (which instead
+ * uses EdDSA).
+ */
+ (void)A;
+ (void)B;
+ (void)len;
+ (void)x;
+ (void)xlen;
+ (void)y;
+ (void)ylen;
+ (void)curve;
+ return 0;
+}
+
+/* see bearssl_ec.h */
+const br_ec_impl br_ec_c25519_m64 = {
+ (uint32_t)0x20000000,
+ &api_generator,
+ &api_order,
+ &api_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
+
+/* see bearssl_ec.h */
+const br_ec_impl *
+br_ec_c25519_m64_get(void)
+{
+ return &br_ec_c25519_m64;
+}
+
+#else
+
+/* see bearssl_ec.h */
+const br_ec_impl *
+br_ec_c25519_m64_get(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/contrib/bearssl/src/ec/ec_curve25519.c b/contrib/bearssl/src/ec/ec_curve25519.c
new file mode 100644
index 000000000000..a47d215ed0e4
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_curve25519.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 GEN[] = {
+ 0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00
+};
+
+static const unsigned char ORDER[] = {
+ 0x7F, 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
+};
+
+/* see inner.h */
+const br_ec_curve_def br_curve25519 = {
+ BR_EC_curve25519,
+ ORDER, sizeof ORDER,
+ GEN, sizeof GEN
+};
diff --git a/contrib/bearssl/src/ec/ec_default.c b/contrib/bearssl/src/ec/ec_default.c
new file mode 100644
index 000000000000..7bb6e0c7fc81
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_default.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 */
+const br_ec_impl *
+br_ec_get_default(void)
+{
+#if BR_LOMUL
+ return &br_ec_all_m15;
+#else
+ return &br_ec_all_m31;
+#endif
+}
diff --git a/contrib/bearssl/src/ec/ec_keygen.c b/contrib/bearssl/src/ec/ec_keygen.c
new file mode 100644
index 000000000000..02a309625d56
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_keygen.c
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ec.h */
+size_t
+br_ec_keygen(const br_prng_class **rng_ctx,
+ const br_ec_impl *impl, br_ec_private_key *sk,
+ void *kbuf, int curve)
+{
+ const unsigned char *order;
+ unsigned char *buf;
+ size_t len;
+ unsigned mask;
+
+ if (curve < 0 || curve >= 32
+ || ((impl->supported_curves >> curve) & 1) == 0)
+ {
+ return 0;
+ }
+ order = impl->order(curve, &len);
+ while (len > 0 && *order == 0) {
+ order ++;
+ len --;
+ }
+ if (kbuf == NULL || len == 0) {
+ return len;
+ }
+ mask = order[0];
+ mask |= (mask >> 1);
+ mask |= (mask >> 2);
+ mask |= (mask >> 4);
+
+ /*
+ * We generate sequences of random bits of the right size, until
+ * the value is strictly lower than the curve order (we also
+ * check for all-zero values, which are invalid).
+ */
+ buf = kbuf;
+ for (;;) {
+ size_t u;
+ unsigned cc, zz;
+
+ (*rng_ctx)->generate(rng_ctx, buf, len);
+ buf[0] &= mask;
+ cc = 0;
+ u = len;
+ zz = 0;
+ while (u -- > 0) {
+ cc = ((unsigned)(buf[u] - order[u] - cc) >> 8) & 1;
+ zz |= buf[u];
+ }
+ if (cc != 0 && zz != 0) {
+ break;
+ }
+ }
+
+ if (sk != NULL) {
+ sk->curve = curve;
+ sk->x = buf;
+ sk->xlen = len;
+ }
+ return len;
+}
diff --git a/contrib/bearssl/src/ec/ec_p256_m15.c b/contrib/bearssl/src/ec/ec_p256_m15.c
new file mode 100644
index 000000000000..8d68d1d21bdb
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_p256_m15.c
@@ -0,0 +1,2130 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * If BR_NO_ARITH_SHIFT is undefined, or defined to 0, then we _assume_
+ * that right-shifting a signed negative integer copies the sign bit
+ * (arithmetic right-shift). This is "implementation-defined behaviour",
+ * i.e. it is not undefined, but it may differ between compilers. Each
+ * compiler is supposed to document its behaviour in that respect. GCC
+ * explicitly defines that an arithmetic right shift is used. We expect
+ * all other compilers to do the same, because underlying CPU offer an
+ * arithmetic right shift opcode that could not be used otherwise.
+ */
+#if BR_NO_ARITH_SHIFT
+#define ARSH(x, n) (((uint32_t)(x) >> (n)) \
+ | ((-((uint32_t)(x) >> 31)) << (32 - (n))))
+#else
+#define ARSH(x, n) ((*(int32_t *)&(x)) >> (n))
+#endif
+
+/*
+ * Convert an integer from unsigned big-endian encoding to a sequence of
+ * 13-bit words in little-endian order. The final "partial" word is
+ * returned.
+ */
+static uint32_t
+be8_to_le13(uint32_t *dst, const unsigned char *src, size_t len)
+{
+ uint32_t acc;
+ int acc_len;
+
+ acc = 0;
+ acc_len = 0;
+ while (len -- > 0) {
+ acc |= (uint32_t)src[len] << acc_len;
+ acc_len += 8;
+ if (acc_len >= 13) {
+ *dst ++ = acc & 0x1FFF;
+ acc >>= 13;
+ acc_len -= 13;
+ }
+ }
+ return acc;
+}
+
+/*
+ * Convert an integer (13-bit words, little-endian) to unsigned
+ * big-endian encoding. The total encoding length is provided; all
+ * the destination bytes will be filled.
+ */
+static void
+le13_to_be8(unsigned char *dst, size_t len, const uint32_t *src)
+{
+ uint32_t acc;
+ int acc_len;
+
+ acc = 0;
+ acc_len = 0;
+ while (len -- > 0) {
+ if (acc_len < 8) {
+ acc |= (*src ++) << acc_len;
+ acc_len += 13;
+ }
+ dst[len] = (unsigned char)acc;
+ acc >>= 8;
+ acc_len -= 8;
+ }
+}
+
+/*
+ * Normalise an array of words to a strict 13 bits per word. Returned
+ * value is the resulting carry. The source (w) and destination (d)
+ * arrays may be identical, but shall not overlap partially.
+ */
+static inline uint32_t
+norm13(uint32_t *d, const uint32_t *w, size_t len)
+{
+ size_t u;
+ uint32_t cc;
+
+ cc = 0;
+ for (u = 0; u < len; u ++) {
+ int32_t z;
+
+ z = w[u] + cc;
+ d[u] = z & 0x1FFF;
+ cc = ARSH(z, 13);
+ }
+ return cc;
+}
+
+/*
+ * mul20() multiplies two 260-bit integers together. Each word must fit
+ * on 13 bits; source operands use 20 words, destination operand
+ * receives 40 words. All overlaps allowed.
+ *
+ * square20() computes the square of a 260-bit integer. Each word must
+ * fit on 13 bits; source operand uses 20 words, destination operand
+ * receives 40 words. All overlaps allowed.
+ */
+
+#if BR_SLOW_MUL15
+
+static void
+mul20(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ /*
+ * Two-level Karatsuba: turns a 20x20 multiplication into
+ * nine 5x5 multiplications. We use 13-bit words but do not
+ * propagate carries immediately, so words may expand:
+ *
+ * - First Karatsuba decomposition turns the 20x20 mul on
+ * 13-bit words into three 10x10 muls, two on 13-bit words
+ * and one on 14-bit words.
+ *
+ * - Second Karatsuba decomposition further splits these into:
+ *
+ * * four 5x5 muls on 13-bit words
+ * * four 5x5 muls on 14-bit words
+ * * one 5x5 mul on 15-bit words
+ *
+ * Highest word value is 8191, 16382 or 32764, for 13-bit, 14-bit
+ * or 15-bit words, respectively.
+ */
+ uint32_t u[45], v[45], w[90];
+ uint32_t cc;
+ int i;
+
+#define ZADD(dw, d_off, s1w, s1_off, s2w, s2_off) do { \
+ (dw)[5 * (d_off) + 0] = (s1w)[5 * (s1_off) + 0] \
+ + (s2w)[5 * (s2_off) + 0]; \
+ (dw)[5 * (d_off) + 1] = (s1w)[5 * (s1_off) + 1] \
+ + (s2w)[5 * (s2_off) + 1]; \
+ (dw)[5 * (d_off) + 2] = (s1w)[5 * (s1_off) + 2] \
+ + (s2w)[5 * (s2_off) + 2]; \
+ (dw)[5 * (d_off) + 3] = (s1w)[5 * (s1_off) + 3] \
+ + (s2w)[5 * (s2_off) + 3]; \
+ (dw)[5 * (d_off) + 4] = (s1w)[5 * (s1_off) + 4] \
+ + (s2w)[5 * (s2_off) + 4]; \
+ } while (0)
+
+#define ZADDT(dw, d_off, sw, s_off) do { \
+ (dw)[5 * (d_off) + 0] += (sw)[5 * (s_off) + 0]; \
+ (dw)[5 * (d_off) + 1] += (sw)[5 * (s_off) + 1]; \
+ (dw)[5 * (d_off) + 2] += (sw)[5 * (s_off) + 2]; \
+ (dw)[5 * (d_off) + 3] += (sw)[5 * (s_off) + 3]; \
+ (dw)[5 * (d_off) + 4] += (sw)[5 * (s_off) + 4]; \
+ } while (0)
+
+#define ZSUB2F(dw, d_off, s1w, s1_off, s2w, s2_off) do { \
+ (dw)[5 * (d_off) + 0] -= (s1w)[5 * (s1_off) + 0] \
+ + (s2w)[5 * (s2_off) + 0]; \
+ (dw)[5 * (d_off) + 1] -= (s1w)[5 * (s1_off) + 1] \
+ + (s2w)[5 * (s2_off) + 1]; \
+ (dw)[5 * (d_off) + 2] -= (s1w)[5 * (s1_off) + 2] \
+ + (s2w)[5 * (s2_off) + 2]; \
+ (dw)[5 * (d_off) + 3] -= (s1w)[5 * (s1_off) + 3] \
+ + (s2w)[5 * (s2_off) + 3]; \
+ (dw)[5 * (d_off) + 4] -= (s1w)[5 * (s1_off) + 4] \
+ + (s2w)[5 * (s2_off) + 4]; \
+ } while (0)
+
+#define CPR1(w, cprcc) do { \
+ uint32_t cprz = (w) + cprcc; \
+ (w) = cprz & 0x1FFF; \
+ cprcc = cprz >> 13; \
+ } while (0)
+
+#define CPR(dw, d_off) do { \
+ uint32_t cprcc; \
+ cprcc = 0; \
+ CPR1((dw)[(d_off) + 0], cprcc); \
+ CPR1((dw)[(d_off) + 1], cprcc); \
+ CPR1((dw)[(d_off) + 2], cprcc); \
+ CPR1((dw)[(d_off) + 3], cprcc); \
+ CPR1((dw)[(d_off) + 4], cprcc); \
+ CPR1((dw)[(d_off) + 5], cprcc); \
+ CPR1((dw)[(d_off) + 6], cprcc); \
+ CPR1((dw)[(d_off) + 7], cprcc); \
+ CPR1((dw)[(d_off) + 8], cprcc); \
+ (dw)[(d_off) + 9] = cprcc; \
+ } while (0)
+
+ memcpy(u, a, 20 * sizeof *a);
+ ZADD(u, 4, a, 0, a, 1);
+ ZADD(u, 5, a, 2, a, 3);
+ ZADD(u, 6, a, 0, a, 2);
+ ZADD(u, 7, a, 1, a, 3);
+ ZADD(u, 8, u, 6, u, 7);
+
+ memcpy(v, b, 20 * sizeof *b);
+ ZADD(v, 4, b, 0, b, 1);
+ ZADD(v, 5, b, 2, b, 3);
+ ZADD(v, 6, b, 0, b, 2);
+ ZADD(v, 7, b, 1, b, 3);
+ ZADD(v, 8, v, 6, v, 7);
+
+ /*
+ * Do the eight first 8x8 muls. Source words are at most 16382
+ * each, so we can add product results together "as is" in 32-bit
+ * words.
+ */
+ for (i = 0; i < 40; i += 5) {
+ w[(i << 1) + 0] = MUL15(u[i + 0], v[i + 0]);
+ w[(i << 1) + 1] = MUL15(u[i + 0], v[i + 1])
+ + MUL15(u[i + 1], v[i + 0]);
+ w[(i << 1) + 2] = MUL15(u[i + 0], v[i + 2])
+ + MUL15(u[i + 1], v[i + 1])
+ + MUL15(u[i + 2], v[i + 0]);
+ w[(i << 1) + 3] = MUL15(u[i + 0], v[i + 3])
+ + MUL15(u[i + 1], v[i + 2])
+ + MUL15(u[i + 2], v[i + 1])
+ + MUL15(u[i + 3], v[i + 0]);
+ w[(i << 1) + 4] = MUL15(u[i + 0], v[i + 4])
+ + MUL15(u[i + 1], v[i + 3])
+ + MUL15(u[i + 2], v[i + 2])
+ + MUL15(u[i + 3], v[i + 1])
+ + MUL15(u[i + 4], v[i + 0]);
+ w[(i << 1) + 5] = MUL15(u[i + 1], v[i + 4])
+ + MUL15(u[i + 2], v[i + 3])
+ + MUL15(u[i + 3], v[i + 2])
+ + MUL15(u[i + 4], v[i + 1]);
+ w[(i << 1) + 6] = MUL15(u[i + 2], v[i + 4])
+ + MUL15(u[i + 3], v[i + 3])
+ + MUL15(u[i + 4], v[i + 2]);
+ w[(i << 1) + 7] = MUL15(u[i + 3], v[i + 4])
+ + MUL15(u[i + 4], v[i + 3]);
+ w[(i << 1) + 8] = MUL15(u[i + 4], v[i + 4]);
+ w[(i << 1) + 9] = 0;
+ }
+
+ /*
+ * For the 9th multiplication, source words are up to 32764,
+ * so we must do some carry propagation. If we add up to
+ * 4 products and the carry is no more than 524224, then the
+ * result fits in 32 bits, and the next carry will be no more
+ * than 524224 (because 4*(32764^2)+524224 < 8192*524225).
+ *
+ * We thus just skip one of the products in the middle word,
+ * then do a carry propagation (this reduces words to 13 bits
+ * each, except possibly the last, which may use up to 17 bits
+ * or so), then add the missing product.
+ */
+ w[80 + 0] = MUL15(u[40 + 0], v[40 + 0]);
+ w[80 + 1] = MUL15(u[40 + 0], v[40 + 1])
+ + MUL15(u[40 + 1], v[40 + 0]);
+ w[80 + 2] = MUL15(u[40 + 0], v[40 + 2])
+ + MUL15(u[40 + 1], v[40 + 1])
+ + MUL15(u[40 + 2], v[40 + 0]);
+ w[80 + 3] = MUL15(u[40 + 0], v[40 + 3])
+ + MUL15(u[40 + 1], v[40 + 2])
+ + MUL15(u[40 + 2], v[40 + 1])
+ + MUL15(u[40 + 3], v[40 + 0]);
+ w[80 + 4] = MUL15(u[40 + 0], v[40 + 4])
+ + MUL15(u[40 + 1], v[40 + 3])
+ + MUL15(u[40 + 2], v[40 + 2])
+ + MUL15(u[40 + 3], v[40 + 1]);
+ /* + MUL15(u[40 + 4], v[40 + 0]) */
+ w[80 + 5] = MUL15(u[40 + 1], v[40 + 4])
+ + MUL15(u[40 + 2], v[40 + 3])
+ + MUL15(u[40 + 3], v[40 + 2])
+ + MUL15(u[40 + 4], v[40 + 1]);
+ w[80 + 6] = MUL15(u[40 + 2], v[40 + 4])
+ + MUL15(u[40 + 3], v[40 + 3])
+ + MUL15(u[40 + 4], v[40 + 2]);
+ w[80 + 7] = MUL15(u[40 + 3], v[40 + 4])
+ + MUL15(u[40 + 4], v[40 + 3]);
+ w[80 + 8] = MUL15(u[40 + 4], v[40 + 4]);
+
+ CPR(w, 80);
+
+ w[80 + 4] += MUL15(u[40 + 4], v[40 + 0]);
+
+ /*
+ * The products on 14-bit words in slots 6 and 7 yield values
+ * up to 5*(16382^2) each, and we need to subtract two such
+ * values from the higher word. We need the subtraction to fit
+ * in a _signed_ 32-bit integer, i.e. 31 bits + a sign bit.
+ * However, 10*(16382^2) does not fit. So we must perform a
+ * bit of reduction here.
+ */
+ CPR(w, 60);
+ CPR(w, 70);
+
+ /*
+ * Recompose results.
+ */
+
+ /* 0..1*0..1 into 0..3 */
+ ZSUB2F(w, 8, w, 0, w, 2);
+ ZSUB2F(w, 9, w, 1, w, 3);
+ ZADDT(w, 1, w, 8);
+ ZADDT(w, 2, w, 9);
+
+ /* 2..3*2..3 into 4..7 */
+ ZSUB2F(w, 10, w, 4, w, 6);
+ ZSUB2F(w, 11, w, 5, w, 7);
+ ZADDT(w, 5, w, 10);
+ ZADDT(w, 6, w, 11);
+
+ /* (0..1+2..3)*(0..1+2..3) into 12..15 */
+ ZSUB2F(w, 16, w, 12, w, 14);
+ ZSUB2F(w, 17, w, 13, w, 15);
+ ZADDT(w, 13, w, 16);
+ ZADDT(w, 14, w, 17);
+
+ /* first-level recomposition */
+ ZSUB2F(w, 12, w, 0, w, 4);
+ ZSUB2F(w, 13, w, 1, w, 5);
+ ZSUB2F(w, 14, w, 2, w, 6);
+ ZSUB2F(w, 15, w, 3, w, 7);
+ ZADDT(w, 2, w, 12);
+ ZADDT(w, 3, w, 13);
+ ZADDT(w, 4, w, 14);
+ ZADDT(w, 5, w, 15);
+
+ /*
+ * Perform carry propagation to bring all words down to 13 bits.
+ */
+ cc = norm13(d, w, 40);
+ d[39] += (cc << 13);
+
+#undef ZADD
+#undef ZADDT
+#undef ZSUB2F
+#undef CPR1
+#undef CPR
+}
+
+static inline void
+square20(uint32_t *d, const uint32_t *a)
+{
+ mul20(d, a, a);
+}
+
+#else
+
+static void
+mul20(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ uint32_t t[39];
+
+ t[ 0] = MUL15(a[ 0], b[ 0]);
+ t[ 1] = MUL15(a[ 0], b[ 1])
+ + MUL15(a[ 1], b[ 0]);
+ t[ 2] = MUL15(a[ 0], b[ 2])
+ + MUL15(a[ 1], b[ 1])
+ + MUL15(a[ 2], b[ 0]);
+ t[ 3] = MUL15(a[ 0], b[ 3])
+ + MUL15(a[ 1], b[ 2])
+ + MUL15(a[ 2], b[ 1])
+ + MUL15(a[ 3], b[ 0]);
+ t[ 4] = MUL15(a[ 0], b[ 4])
+ + MUL15(a[ 1], b[ 3])
+ + MUL15(a[ 2], b[ 2])
+ + MUL15(a[ 3], b[ 1])
+ + MUL15(a[ 4], b[ 0]);
+ t[ 5] = MUL15(a[ 0], b[ 5])
+ + MUL15(a[ 1], b[ 4])
+ + MUL15(a[ 2], b[ 3])
+ + MUL15(a[ 3], b[ 2])
+ + MUL15(a[ 4], b[ 1])
+ + MUL15(a[ 5], b[ 0]);
+ t[ 6] = MUL15(a[ 0], b[ 6])
+ + MUL15(a[ 1], b[ 5])
+ + MUL15(a[ 2], b[ 4])
+ + MUL15(a[ 3], b[ 3])
+ + MUL15(a[ 4], b[ 2])
+ + MUL15(a[ 5], b[ 1])
+ + MUL15(a[ 6], b[ 0]);
+ t[ 7] = MUL15(a[ 0], b[ 7])
+ + MUL15(a[ 1], b[ 6])
+ + MUL15(a[ 2], b[ 5])
+ + MUL15(a[ 3], b[ 4])
+ + MUL15(a[ 4], b[ 3])
+ + MUL15(a[ 5], b[ 2])
+ + MUL15(a[ 6], b[ 1])
+ + MUL15(a[ 7], b[ 0]);
+ t[ 8] = MUL15(a[ 0], b[ 8])
+ + MUL15(a[ 1], b[ 7])
+ + MUL15(a[ 2], b[ 6])
+ + MUL15(a[ 3], b[ 5])
+ + MUL15(a[ 4], b[ 4])
+ + MUL15(a[ 5], b[ 3])
+ + MUL15(a[ 6], b[ 2])
+ + MUL15(a[ 7], b[ 1])
+ + MUL15(a[ 8], b[ 0]);
+ t[ 9] = MUL15(a[ 0], b[ 9])
+ + MUL15(a[ 1], b[ 8])
+ + MUL15(a[ 2], b[ 7])
+ + MUL15(a[ 3], b[ 6])
+ + MUL15(a[ 4], b[ 5])
+ + MUL15(a[ 5], b[ 4])
+ + MUL15(a[ 6], b[ 3])
+ + MUL15(a[ 7], b[ 2])
+ + MUL15(a[ 8], b[ 1])
+ + MUL15(a[ 9], b[ 0]);
+ t[10] = MUL15(a[ 0], b[10])
+ + MUL15(a[ 1], b[ 9])
+ + MUL15(a[ 2], b[ 8])
+ + MUL15(a[ 3], b[ 7])
+ + MUL15(a[ 4], b[ 6])
+ + MUL15(a[ 5], b[ 5])
+ + MUL15(a[ 6], b[ 4])
+ + MUL15(a[ 7], b[ 3])
+ + MUL15(a[ 8], b[ 2])
+ + MUL15(a[ 9], b[ 1])
+ + MUL15(a[10], b[ 0]);
+ t[11] = MUL15(a[ 0], b[11])
+ + MUL15(a[ 1], b[10])
+ + MUL15(a[ 2], b[ 9])
+ + MUL15(a[ 3], b[ 8])
+ + MUL15(a[ 4], b[ 7])
+ + MUL15(a[ 5], b[ 6])
+ + MUL15(a[ 6], b[ 5])
+ + MUL15(a[ 7], b[ 4])
+ + MUL15(a[ 8], b[ 3])
+ + MUL15(a[ 9], b[ 2])
+ + MUL15(a[10], b[ 1])
+ + MUL15(a[11], b[ 0]);
+ t[12] = MUL15(a[ 0], b[12])
+ + MUL15(a[ 1], b[11])
+ + MUL15(a[ 2], b[10])
+ + MUL15(a[ 3], b[ 9])
+ + MUL15(a[ 4], b[ 8])
+ + MUL15(a[ 5], b[ 7])
+ + MUL15(a[ 6], b[ 6])
+ + MUL15(a[ 7], b[ 5])
+ + MUL15(a[ 8], b[ 4])
+ + MUL15(a[ 9], b[ 3])
+ + MUL15(a[10], b[ 2])
+ + MUL15(a[11], b[ 1])
+ + MUL15(a[12], b[ 0]);
+ t[13] = MUL15(a[ 0], b[13])
+ + MUL15(a[ 1], b[12])
+ + MUL15(a[ 2], b[11])
+ + MUL15(a[ 3], b[10])
+ + MUL15(a[ 4], b[ 9])
+ + MUL15(a[ 5], b[ 8])
+ + MUL15(a[ 6], b[ 7])
+ + MUL15(a[ 7], b[ 6])
+ + MUL15(a[ 8], b[ 5])
+ + MUL15(a[ 9], b[ 4])
+ + MUL15(a[10], b[ 3])
+ + MUL15(a[11], b[ 2])
+ + MUL15(a[12], b[ 1])
+ + MUL15(a[13], b[ 0]);
+ t[14] = MUL15(a[ 0], b[14])
+ + MUL15(a[ 1], b[13])
+ + MUL15(a[ 2], b[12])
+ + MUL15(a[ 3], b[11])
+ + MUL15(a[ 4], b[10])
+ + MUL15(a[ 5], b[ 9])
+ + MUL15(a[ 6], b[ 8])
+ + MUL15(a[ 7], b[ 7])
+ + MUL15(a[ 8], b[ 6])
+ + MUL15(a[ 9], b[ 5])
+ + MUL15(a[10], b[ 4])
+ + MUL15(a[11], b[ 3])
+ + MUL15(a[12], b[ 2])
+ + MUL15(a[13], b[ 1])
+ + MUL15(a[14], b[ 0]);
+ t[15] = MUL15(a[ 0], b[15])
+ + MUL15(a[ 1], b[14])
+ + MUL15(a[ 2], b[13])
+ + MUL15(a[ 3], b[12])
+ + MUL15(a[ 4], b[11])
+ + MUL15(a[ 5], b[10])
+ + MUL15(a[ 6], b[ 9])
+ + MUL15(a[ 7], b[ 8])
+ + MUL15(a[ 8], b[ 7])
+ + MUL15(a[ 9], b[ 6])
+ + MUL15(a[10], b[ 5])
+ + MUL15(a[11], b[ 4])
+ + MUL15(a[12], b[ 3])
+ + MUL15(a[13], b[ 2])
+ + MUL15(a[14], b[ 1])
+ + MUL15(a[15], b[ 0]);
+ t[16] = MUL15(a[ 0], b[16])
+ + MUL15(a[ 1], b[15])
+ + MUL15(a[ 2], b[14])
+ + MUL15(a[ 3], b[13])
+ + MUL15(a[ 4], b[12])
+ + MUL15(a[ 5], b[11])
+ + MUL15(a[ 6], b[10])
+ + MUL15(a[ 7], b[ 9])
+ + MUL15(a[ 8], b[ 8])
+ + MUL15(a[ 9], b[ 7])
+ + MUL15(a[10], b[ 6])
+ + MUL15(a[11], b[ 5])
+ + MUL15(a[12], b[ 4])
+ + MUL15(a[13], b[ 3])
+ + MUL15(a[14], b[ 2])
+ + MUL15(a[15], b[ 1])
+ + MUL15(a[16], b[ 0]);
+ t[17] = MUL15(a[ 0], b[17])
+ + MUL15(a[ 1], b[16])
+ + MUL15(a[ 2], b[15])
+ + MUL15(a[ 3], b[14])
+ + MUL15(a[ 4], b[13])
+ + MUL15(a[ 5], b[12])
+ + MUL15(a[ 6], b[11])
+ + MUL15(a[ 7], b[10])
+ + MUL15(a[ 8], b[ 9])
+ + MUL15(a[ 9], b[ 8])
+ + MUL15(a[10], b[ 7])
+ + MUL15(a[11], b[ 6])
+ + MUL15(a[12], b[ 5])
+ + MUL15(a[13], b[ 4])
+ + MUL15(a[14], b[ 3])
+ + MUL15(a[15], b[ 2])
+ + MUL15(a[16], b[ 1])
+ + MUL15(a[17], b[ 0]);
+ t[18] = MUL15(a[ 0], b[18])
+ + MUL15(a[ 1], b[17])
+ + MUL15(a[ 2], b[16])
+ + MUL15(a[ 3], b[15])
+ + MUL15(a[ 4], b[14])
+ + MUL15(a[ 5], b[13])
+ + MUL15(a[ 6], b[12])
+ + MUL15(a[ 7], b[11])
+ + MUL15(a[ 8], b[10])
+ + MUL15(a[ 9], b[ 9])
+ + MUL15(a[10], b[ 8])
+ + MUL15(a[11], b[ 7])
+ + MUL15(a[12], b[ 6])
+ + MUL15(a[13], b[ 5])
+ + MUL15(a[14], b[ 4])
+ + MUL15(a[15], b[ 3])
+ + MUL15(a[16], b[ 2])
+ + MUL15(a[17], b[ 1])
+ + MUL15(a[18], b[ 0]);
+ t[19] = MUL15(a[ 0], b[19])
+ + MUL15(a[ 1], b[18])
+ + MUL15(a[ 2], b[17])
+ + MUL15(a[ 3], b[16])
+ + MUL15(a[ 4], b[15])
+ + MUL15(a[ 5], b[14])
+ + MUL15(a[ 6], b[13])
+ + MUL15(a[ 7], b[12])
+ + MUL15(a[ 8], b[11])
+ + MUL15(a[ 9], b[10])
+ + MUL15(a[10], b[ 9])
+ + MUL15(a[11], b[ 8])
+ + MUL15(a[12], b[ 7])
+ + MUL15(a[13], b[ 6])
+ + MUL15(a[14], b[ 5])
+ + MUL15(a[15], b[ 4])
+ + MUL15(a[16], b[ 3])
+ + MUL15(a[17], b[ 2])
+ + MUL15(a[18], b[ 1])
+ + MUL15(a[19], b[ 0]);
+ t[20] = MUL15(a[ 1], b[19])
+ + MUL15(a[ 2], b[18])
+ + MUL15(a[ 3], b[17])
+ + MUL15(a[ 4], b[16])
+ + MUL15(a[ 5], b[15])
+ + MUL15(a[ 6], b[14])
+ + MUL15(a[ 7], b[13])
+ + MUL15(a[ 8], b[12])
+ + MUL15(a[ 9], b[11])
+ + MUL15(a[10], b[10])
+ + MUL15(a[11], b[ 9])
+ + MUL15(a[12], b[ 8])
+ + MUL15(a[13], b[ 7])
+ + MUL15(a[14], b[ 6])
+ + MUL15(a[15], b[ 5])
+ + MUL15(a[16], b[ 4])
+ + MUL15(a[17], b[ 3])
+ + MUL15(a[18], b[ 2])
+ + MUL15(a[19], b[ 1]);
+ t[21] = MUL15(a[ 2], b[19])
+ + MUL15(a[ 3], b[18])
+ + MUL15(a[ 4], b[17])
+ + MUL15(a[ 5], b[16])
+ + MUL15(a[ 6], b[15])
+ + MUL15(a[ 7], b[14])
+ + MUL15(a[ 8], b[13])
+ + MUL15(a[ 9], b[12])
+ + MUL15(a[10], b[11])
+ + MUL15(a[11], b[10])
+ + MUL15(a[12], b[ 9])
+ + MUL15(a[13], b[ 8])
+ + MUL15(a[14], b[ 7])
+ + MUL15(a[15], b[ 6])
+ + MUL15(a[16], b[ 5])
+ + MUL15(a[17], b[ 4])
+ + MUL15(a[18], b[ 3])
+ + MUL15(a[19], b[ 2]);
+ t[22] = MUL15(a[ 3], b[19])
+ + MUL15(a[ 4], b[18])
+ + MUL15(a[ 5], b[17])
+ + MUL15(a[ 6], b[16])
+ + MUL15(a[ 7], b[15])
+ + MUL15(a[ 8], b[14])
+ + MUL15(a[ 9], b[13])
+ + MUL15(a[10], b[12])
+ + MUL15(a[11], b[11])
+ + MUL15(a[12], b[10])
+ + MUL15(a[13], b[ 9])
+ + MUL15(a[14], b[ 8])
+ + MUL15(a[15], b[ 7])
+ + MUL15(a[16], b[ 6])
+ + MUL15(a[17], b[ 5])
+ + MUL15(a[18], b[ 4])
+ + MUL15(a[19], b[ 3]);
+ t[23] = MUL15(a[ 4], b[19])
+ + MUL15(a[ 5], b[18])
+ + MUL15(a[ 6], b[17])
+ + MUL15(a[ 7], b[16])
+ + MUL15(a[ 8], b[15])
+ + MUL15(a[ 9], b[14])
+ + MUL15(a[10], b[13])
+ + MUL15(a[11], b[12])
+ + MUL15(a[12], b[11])
+ + MUL15(a[13], b[10])
+ + MUL15(a[14], b[ 9])
+ + MUL15(a[15], b[ 8])
+ + MUL15(a[16], b[ 7])
+ + MUL15(a[17], b[ 6])
+ + MUL15(a[18], b[ 5])
+ + MUL15(a[19], b[ 4]);
+ t[24] = MUL15(a[ 5], b[19])
+ + MUL15(a[ 6], b[18])
+ + MUL15(a[ 7], b[17])
+ + MUL15(a[ 8], b[16])
+ + MUL15(a[ 9], b[15])
+ + MUL15(a[10], b[14])
+ + MUL15(a[11], b[13])
+ + MUL15(a[12], b[12])
+ + MUL15(a[13], b[11])
+ + MUL15(a[14], b[10])
+ + MUL15(a[15], b[ 9])
+ + MUL15(a[16], b[ 8])
+ + MUL15(a[17], b[ 7])
+ + MUL15(a[18], b[ 6])
+ + MUL15(a[19], b[ 5]);
+ t[25] = MUL15(a[ 6], b[19])
+ + MUL15(a[ 7], b[18])
+ + MUL15(a[ 8], b[17])
+ + MUL15(a[ 9], b[16])
+ + MUL15(a[10], b[15])
+ + MUL15(a[11], b[14])
+ + MUL15(a[12], b[13])
+ + MUL15(a[13], b[12])
+ + MUL15(a[14], b[11])
+ + MUL15(a[15], b[10])
+ + MUL15(a[16], b[ 9])
+ + MUL15(a[17], b[ 8])
+ + MUL15(a[18], b[ 7])
+ + MUL15(a[19], b[ 6]);
+ t[26] = MUL15(a[ 7], b[19])
+ + MUL15(a[ 8], b[18])
+ + MUL15(a[ 9], b[17])
+ + MUL15(a[10], b[16])
+ + MUL15(a[11], b[15])
+ + MUL15(a[12], b[14])
+ + MUL15(a[13], b[13])
+ + MUL15(a[14], b[12])
+ + MUL15(a[15], b[11])
+ + MUL15(a[16], b[10])
+ + MUL15(a[17], b[ 9])
+ + MUL15(a[18], b[ 8])
+ + MUL15(a[19], b[ 7]);
+ t[27] = MUL15(a[ 8], b[19])
+ + MUL15(a[ 9], b[18])
+ + MUL15(a[10], b[17])
+ + MUL15(a[11], b[16])
+ + MUL15(a[12], b[15])
+ + MUL15(a[13], b[14])
+ + MUL15(a[14], b[13])
+ + MUL15(a[15], b[12])
+ + MUL15(a[16], b[11])
+ + MUL15(a[17], b[10])
+ + MUL15(a[18], b[ 9])
+ + MUL15(a[19], b[ 8]);
+ t[28] = MUL15(a[ 9], b[19])
+ + MUL15(a[10], b[18])
+ + MUL15(a[11], b[17])
+ + MUL15(a[12], b[16])
+ + MUL15(a[13], b[15])
+ + MUL15(a[14], b[14])
+ + MUL15(a[15], b[13])
+ + MUL15(a[16], b[12])
+ + MUL15(a[17], b[11])
+ + MUL15(a[18], b[10])
+ + MUL15(a[19], b[ 9]);
+ t[29] = MUL15(a[10], b[19])
+ + MUL15(a[11], b[18])
+ + MUL15(a[12], b[17])
+ + MUL15(a[13], b[16])
+ + MUL15(a[14], b[15])
+ + MUL15(a[15], b[14])
+ + MUL15(a[16], b[13])
+ + MUL15(a[17], b[12])
+ + MUL15(a[18], b[11])
+ + MUL15(a[19], b[10]);
+ t[30] = MUL15(a[11], b[19])
+ + MUL15(a[12], b[18])
+ + MUL15(a[13], b[17])
+ + MUL15(a[14], b[16])
+ + MUL15(a[15], b[15])
+ + MUL15(a[16], b[14])
+ + MUL15(a[17], b[13])
+ + MUL15(a[18], b[12])
+ + MUL15(a[19], b[11]);
+ t[31] = MUL15(a[12], b[19])
+ + MUL15(a[13], b[18])
+ + MUL15(a[14], b[17])
+ + MUL15(a[15], b[16])
+ + MUL15(a[16], b[15])
+ + MUL15(a[17], b[14])
+ + MUL15(a[18], b[13])
+ + MUL15(a[19], b[12]);
+ t[32] = MUL15(a[13], b[19])
+ + MUL15(a[14], b[18])
+ + MUL15(a[15], b[17])
+ + MUL15(a[16], b[16])
+ + MUL15(a[17], b[15])
+ + MUL15(a[18], b[14])
+ + MUL15(a[19], b[13]);
+ t[33] = MUL15(a[14], b[19])
+ + MUL15(a[15], b[18])
+ + MUL15(a[16], b[17])
+ + MUL15(a[17], b[16])
+ + MUL15(a[18], b[15])
+ + MUL15(a[19], b[14]);
+ t[34] = MUL15(a[15], b[19])
+ + MUL15(a[16], b[18])
+ + MUL15(a[17], b[17])
+ + MUL15(a[18], b[16])
+ + MUL15(a[19], b[15]);
+ t[35] = MUL15(a[16], b[19])
+ + MUL15(a[17], b[18])
+ + MUL15(a[18], b[17])
+ + MUL15(a[19], b[16]);
+ t[36] = MUL15(a[17], b[19])
+ + MUL15(a[18], b[18])
+ + MUL15(a[19], b[17]);
+ t[37] = MUL15(a[18], b[19])
+ + MUL15(a[19], b[18]);
+ t[38] = MUL15(a[19], b[19]);
+ d[39] = norm13(d, t, 39);
+}
+
+static void
+square20(uint32_t *d, const uint32_t *a)
+{
+ uint32_t t[39];
+
+ t[ 0] = MUL15(a[ 0], a[ 0]);
+ t[ 1] = ((MUL15(a[ 0], a[ 1])) << 1);
+ t[ 2] = MUL15(a[ 1], a[ 1])
+ + ((MUL15(a[ 0], a[ 2])) << 1);
+ t[ 3] = ((MUL15(a[ 0], a[ 3])
+ + MUL15(a[ 1], a[ 2])) << 1);
+ t[ 4] = MUL15(a[ 2], a[ 2])
+ + ((MUL15(a[ 0], a[ 4])
+ + MUL15(a[ 1], a[ 3])) << 1);
+ t[ 5] = ((MUL15(a[ 0], a[ 5])
+ + MUL15(a[ 1], a[ 4])
+ + MUL15(a[ 2], a[ 3])) << 1);
+ t[ 6] = MUL15(a[ 3], a[ 3])
+ + ((MUL15(a[ 0], a[ 6])
+ + MUL15(a[ 1], a[ 5])
+ + MUL15(a[ 2], a[ 4])) << 1);
+ t[ 7] = ((MUL15(a[ 0], a[ 7])
+ + MUL15(a[ 1], a[ 6])
+ + MUL15(a[ 2], a[ 5])
+ + MUL15(a[ 3], a[ 4])) << 1);
+ t[ 8] = MUL15(a[ 4], a[ 4])
+ + ((MUL15(a[ 0], a[ 8])
+ + MUL15(a[ 1], a[ 7])
+ + MUL15(a[ 2], a[ 6])
+ + MUL15(a[ 3], a[ 5])) << 1);
+ t[ 9] = ((MUL15(a[ 0], a[ 9])
+ + MUL15(a[ 1], a[ 8])
+ + MUL15(a[ 2], a[ 7])
+ + MUL15(a[ 3], a[ 6])
+ + MUL15(a[ 4], a[ 5])) << 1);
+ t[10] = MUL15(a[ 5], a[ 5])
+ + ((MUL15(a[ 0], a[10])
+ + MUL15(a[ 1], a[ 9])
+ + MUL15(a[ 2], a[ 8])
+ + MUL15(a[ 3], a[ 7])
+ + MUL15(a[ 4], a[ 6])) << 1);
+ t[11] = ((MUL15(a[ 0], a[11])
+ + MUL15(a[ 1], a[10])
+ + MUL15(a[ 2], a[ 9])
+ + MUL15(a[ 3], a[ 8])
+ + MUL15(a[ 4], a[ 7])
+ + MUL15(a[ 5], a[ 6])) << 1);
+ t[12] = MUL15(a[ 6], a[ 6])
+ + ((MUL15(a[ 0], a[12])
+ + MUL15(a[ 1], a[11])
+ + MUL15(a[ 2], a[10])
+ + MUL15(a[ 3], a[ 9])
+ + MUL15(a[ 4], a[ 8])
+ + MUL15(a[ 5], a[ 7])) << 1);
+ t[13] = ((MUL15(a[ 0], a[13])
+ + MUL15(a[ 1], a[12])
+ + MUL15(a[ 2], a[11])
+ + MUL15(a[ 3], a[10])
+ + MUL15(a[ 4], a[ 9])
+ + MUL15(a[ 5], a[ 8])
+ + MUL15(a[ 6], a[ 7])) << 1);
+ t[14] = MUL15(a[ 7], a[ 7])
+ + ((MUL15(a[ 0], a[14])
+ + MUL15(a[ 1], a[13])
+ + MUL15(a[ 2], a[12])
+ + MUL15(a[ 3], a[11])
+ + MUL15(a[ 4], a[10])
+ + MUL15(a[ 5], a[ 9])
+ + MUL15(a[ 6], a[ 8])) << 1);
+ t[15] = ((MUL15(a[ 0], a[15])
+ + MUL15(a[ 1], a[14])
+ + MUL15(a[ 2], a[13])
+ + MUL15(a[ 3], a[12])
+ + MUL15(a[ 4], a[11])
+ + MUL15(a[ 5], a[10])
+ + MUL15(a[ 6], a[ 9])
+ + MUL15(a[ 7], a[ 8])) << 1);
+ t[16] = MUL15(a[ 8], a[ 8])
+ + ((MUL15(a[ 0], a[16])
+ + MUL15(a[ 1], a[15])
+ + MUL15(a[ 2], a[14])
+ + MUL15(a[ 3], a[13])
+ + MUL15(a[ 4], a[12])
+ + MUL15(a[ 5], a[11])
+ + MUL15(a[ 6], a[10])
+ + MUL15(a[ 7], a[ 9])) << 1);
+ t[17] = ((MUL15(a[ 0], a[17])
+ + MUL15(a[ 1], a[16])
+ + MUL15(a[ 2], a[15])
+ + MUL15(a[ 3], a[14])
+ + MUL15(a[ 4], a[13])
+ + MUL15(a[ 5], a[12])
+ + MUL15(a[ 6], a[11])
+ + MUL15(a[ 7], a[10])
+ + MUL15(a[ 8], a[ 9])) << 1);
+ t[18] = MUL15(a[ 9], a[ 9])
+ + ((MUL15(a[ 0], a[18])
+ + MUL15(a[ 1], a[17])
+ + MUL15(a[ 2], a[16])
+ + MUL15(a[ 3], a[15])
+ + MUL15(a[ 4], a[14])
+ + MUL15(a[ 5], a[13])
+ + MUL15(a[ 6], a[12])
+ + MUL15(a[ 7], a[11])
+ + MUL15(a[ 8], a[10])) << 1);
+ t[19] = ((MUL15(a[ 0], a[19])
+ + MUL15(a[ 1], a[18])
+ + MUL15(a[ 2], a[17])
+ + MUL15(a[ 3], a[16])
+ + MUL15(a[ 4], a[15])
+ + MUL15(a[ 5], a[14])
+ + MUL15(a[ 6], a[13])
+ + MUL15(a[ 7], a[12])
+ + MUL15(a[ 8], a[11])
+ + MUL15(a[ 9], a[10])) << 1);
+ t[20] = MUL15(a[10], a[10])
+ + ((MUL15(a[ 1], a[19])
+ + MUL15(a[ 2], a[18])
+ + MUL15(a[ 3], a[17])
+ + MUL15(a[ 4], a[16])
+ + MUL15(a[ 5], a[15])
+ + MUL15(a[ 6], a[14])
+ + MUL15(a[ 7], a[13])
+ + MUL15(a[ 8], a[12])
+ + MUL15(a[ 9], a[11])) << 1);
+ t[21] = ((MUL15(a[ 2], a[19])
+ + MUL15(a[ 3], a[18])
+ + MUL15(a[ 4], a[17])
+ + MUL15(a[ 5], a[16])
+ + MUL15(a[ 6], a[15])
+ + MUL15(a[ 7], a[14])
+ + MUL15(a[ 8], a[13])
+ + MUL15(a[ 9], a[12])
+ + MUL15(a[10], a[11])) << 1);
+ t[22] = MUL15(a[11], a[11])
+ + ((MUL15(a[ 3], a[19])
+ + MUL15(a[ 4], a[18])
+ + MUL15(a[ 5], a[17])
+ + MUL15(a[ 6], a[16])
+ + MUL15(a[ 7], a[15])
+ + MUL15(a[ 8], a[14])
+ + MUL15(a[ 9], a[13])
+ + MUL15(a[10], a[12])) << 1);
+ t[23] = ((MUL15(a[ 4], a[19])
+ + MUL15(a[ 5], a[18])
+ + MUL15(a[ 6], a[17])
+ + MUL15(a[ 7], a[16])
+ + MUL15(a[ 8], a[15])
+ + MUL15(a[ 9], a[14])
+ + MUL15(a[10], a[13])
+ + MUL15(a[11], a[12])) << 1);
+ t[24] = MUL15(a[12], a[12])
+ + ((MUL15(a[ 5], a[19])
+ + MUL15(a[ 6], a[18])
+ + MUL15(a[ 7], a[17])
+ + MUL15(a[ 8], a[16])
+ + MUL15(a[ 9], a[15])
+ + MUL15(a[10], a[14])
+ + MUL15(a[11], a[13])) << 1);
+ t[25] = ((MUL15(a[ 6], a[19])
+ + MUL15(a[ 7], a[18])
+ + MUL15(a[ 8], a[17])
+ + MUL15(a[ 9], a[16])
+ + MUL15(a[10], a[15])
+ + MUL15(a[11], a[14])
+ + MUL15(a[12], a[13])) << 1);
+ t[26] = MUL15(a[13], a[13])
+ + ((MUL15(a[ 7], a[19])
+ + MUL15(a[ 8], a[18])
+ + MUL15(a[ 9], a[17])
+ + MUL15(a[10], a[16])
+ + MUL15(a[11], a[15])
+ + MUL15(a[12], a[14])) << 1);
+ t[27] = ((MUL15(a[ 8], a[19])
+ + MUL15(a[ 9], a[18])
+ + MUL15(a[10], a[17])
+ + MUL15(a[11], a[16])
+ + MUL15(a[12], a[15])
+ + MUL15(a[13], a[14])) << 1);
+ t[28] = MUL15(a[14], a[14])
+ + ((MUL15(a[ 9], a[19])
+ + MUL15(a[10], a[18])
+ + MUL15(a[11], a[17])
+ + MUL15(a[12], a[16])
+ + MUL15(a[13], a[15])) << 1);
+ t[29] = ((MUL15(a[10], a[19])
+ + MUL15(a[11], a[18])
+ + MUL15(a[12], a[17])
+ + MUL15(a[13], a[16])
+ + MUL15(a[14], a[15])) << 1);
+ t[30] = MUL15(a[15], a[15])
+ + ((MUL15(a[11], a[19])
+ + MUL15(a[12], a[18])
+ + MUL15(a[13], a[17])
+ + MUL15(a[14], a[16])) << 1);
+ t[31] = ((MUL15(a[12], a[19])
+ + MUL15(a[13], a[18])
+ + MUL15(a[14], a[17])
+ + MUL15(a[15], a[16])) << 1);
+ t[32] = MUL15(a[16], a[16])
+ + ((MUL15(a[13], a[19])
+ + MUL15(a[14], a[18])
+ + MUL15(a[15], a[17])) << 1);
+ t[33] = ((MUL15(a[14], a[19])
+ + MUL15(a[15], a[18])
+ + MUL15(a[16], a[17])) << 1);
+ t[34] = MUL15(a[17], a[17])
+ + ((MUL15(a[15], a[19])
+ + MUL15(a[16], a[18])) << 1);
+ t[35] = ((MUL15(a[16], a[19])
+ + MUL15(a[17], a[18])) << 1);
+ t[36] = MUL15(a[18], a[18])
+ + ((MUL15(a[17], a[19])) << 1);
+ t[37] = ((MUL15(a[18], a[19])) << 1);
+ t[38] = MUL15(a[19], a[19]);
+ d[39] = norm13(d, t, 39);
+}
+
+#endif
+
+/*
+ * Modulus for field F256 (field for point coordinates in curve P-256).
+ */
+static const uint32_t F256[] = {
+ 0x1FFF, 0x1FFF, 0x1FFF, 0x1FFF, 0x1FFF, 0x1FFF, 0x1FFF, 0x001F,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0400, 0x0000,
+ 0x0000, 0x1FF8, 0x1FFF, 0x01FF
+};
+
+/*
+ * The 'b' curve equation coefficient for P-256.
+ */
+static const uint32_t P256_B[] = {
+ 0x004B, 0x1E93, 0x0F89, 0x1C78, 0x03BC, 0x187B, 0x114E, 0x1619,
+ 0x1D06, 0x0328, 0x01AF, 0x0D31, 0x1557, 0x15DE, 0x1ECF, 0x127C,
+ 0x0A3A, 0x0EC5, 0x118D, 0x00B5
+};
+
+/*
+ * Perform a "short reduction" in field F256 (field for curve P-256).
+ * The source value should be less than 262 bits; on output, it will
+ * be at most 257 bits, and less than twice the modulus.
+ */
+static void
+reduce_f256(uint32_t *d)
+{
+ uint32_t x;
+
+ x = d[19] >> 9;
+ d[19] &= 0x01FF;
+ d[17] += x << 3;
+ d[14] -= x << 10;
+ d[7] -= x << 5;
+ d[0] += x;
+ norm13(d, d, 20);
+}
+
+/*
+ * Perform a "final reduction" in field F256 (field for curve P-256).
+ * The source value must be less than twice the modulus. If the value
+ * is not lower than the modulus, then the modulus is subtracted and
+ * this function returns 1; otherwise, it leaves it untouched and it
+ * returns 0.
+ */
+static uint32_t
+reduce_final_f256(uint32_t *d)
+{
+ uint32_t t[20];
+ uint32_t cc;
+ int i;
+
+ memcpy(t, d, sizeof t);
+ cc = 0;
+ for (i = 0; i < 20; i ++) {
+ uint32_t w;
+
+ w = t[i] - F256[i] - cc;
+ cc = w >> 31;
+ t[i] = w & 0x1FFF;
+ }
+ cc ^= 1;
+ CCOPY(cc, d, t, sizeof t);
+ return cc;
+}
+
+/*
+ * Perform a multiplication of two integers modulo
+ * 2^256-2^224+2^192+2^96-1 (for NIST curve P-256). Operands are arrays
+ * of 20 words, each containing 13 bits of data, in little-endian order.
+ * On input, upper word may be up to 13 bits (hence value up to 2^260-1);
+ * on output, value fits on 257 bits and is lower than twice the modulus.
+ */
+static void
+mul_f256(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ uint32_t t[40], cc;
+ int i;
+
+ /*
+ * Compute raw multiplication. All result words fit in 13 bits
+ * each.
+ */
+ mul20(t, a, b);
+
+ /*
+ * Modular reduction: each high word in added/subtracted where
+ * necessary.
+ *
+ * The modulus is:
+ * p = 2^256 - 2^224 + 2^192 + 2^96 - 1
+ * Therefore:
+ * 2^256 = 2^224 - 2^192 - 2^96 + 1 mod p
+ *
+ * For a word x at bit offset n (n >= 256), we have:
+ * x*2^n = x*2^(n-32) - x*2^(n-64)
+ * - x*2^(n - 160) + x*2^(n-256) mod p
+ *
+ * Thus, we can nullify the high word if we reinject it at some
+ * proper emplacements.
+ */
+ for (i = 39; i >= 20; i --) {
+ uint32_t x;
+
+ x = t[i];
+ t[i - 2] += ARSH(x, 6);
+ t[i - 3] += (x << 7) & 0x1FFF;
+ t[i - 4] -= ARSH(x, 12);
+ t[i - 5] -= (x << 1) & 0x1FFF;
+ t[i - 12] -= ARSH(x, 4);
+ t[i - 13] -= (x << 9) & 0x1FFF;
+ t[i - 19] += ARSH(x, 9);
+ t[i - 20] += (x << 4) & 0x1FFF;
+ }
+
+ /*
+ * Propagate carries. This is a signed propagation, and the
+ * result may be negative. The loop above may enlarge values,
+ * but not two much: worst case is the chain involving t[i - 3],
+ * in which a value may be added to itself up to 7 times. Since
+ * starting values are 13-bit each, all words fit on 20 bits
+ * (21 to account for the sign bit).
+ */
+ cc = norm13(t, t, 20);
+
+ /*
+ * Perform modular reduction again for the bits beyond 256 (the carry
+ * and the bits 256..259). Since the largest shift below is by 10
+ * bits, and the values fit on 21 bits, values fit in 32-bit words,
+ * thereby allowing injecting full word values.
+ */
+ cc = (cc << 4) | (t[19] >> 9);
+ t[19] &= 0x01FF;
+ t[17] += cc << 3;
+ t[14] -= cc << 10;
+ t[7] -= cc << 5;
+ t[0] += cc;
+
+ /*
+ * If the carry is negative, then after carry propagation, we may
+ * end up with a value which is negative, and we don't want that.
+ * Thus, in that case, we add the modulus. Note that the subtraction
+ * result, when the carry is negative, is always smaller than the
+ * modulus, so the extra addition will not make the value exceed
+ * twice the modulus.
+ */
+ cc >>= 31;
+ t[0] -= cc;
+ t[7] += cc << 5;
+ t[14] += cc << 10;
+ t[17] -= cc << 3;
+ t[19] += cc << 9;
+
+ norm13(d, t, 20);
+}
+
+/*
+ * Square an integer modulo 2^256-2^224+2^192+2^96-1 (for NIST curve
+ * P-256). Operand is an array of 20 words, each containing 13 bits of
+ * data, in little-endian order. On input, upper word may be up to 13
+ * bits (hence value up to 2^260-1); on output, value fits on 257 bits
+ * and is lower than twice the modulus.
+ */
+static void
+square_f256(uint32_t *d, const uint32_t *a)
+{
+ uint32_t t[40], cc;
+ int i;
+
+ /*
+ * Compute raw square. All result words fit in 13 bits each.
+ */
+ square20(t, a);
+
+ /*
+ * Modular reduction: each high word in added/subtracted where
+ * necessary.
+ *
+ * The modulus is:
+ * p = 2^256 - 2^224 + 2^192 + 2^96 - 1
+ * Therefore:
+ * 2^256 = 2^224 - 2^192 - 2^96 + 1 mod p
+ *
+ * For a word x at bit offset n (n >= 256), we have:
+ * x*2^n = x*2^(n-32) - x*2^(n-64)
+ * - x*2^(n - 160) + x*2^(n-256) mod p
+ *
+ * Thus, we can nullify the high word if we reinject it at some
+ * proper emplacements.
+ */
+ for (i = 39; i >= 20; i --) {
+ uint32_t x;
+
+ x = t[i];
+ t[i - 2] += ARSH(x, 6);
+ t[i - 3] += (x << 7) & 0x1FFF;
+ t[i - 4] -= ARSH(x, 12);
+ t[i - 5] -= (x << 1) & 0x1FFF;
+ t[i - 12] -= ARSH(x, 4);
+ t[i - 13] -= (x << 9) & 0x1FFF;
+ t[i - 19] += ARSH(x, 9);
+ t[i - 20] += (x << 4) & 0x1FFF;
+ }
+
+ /*
+ * Propagate carries. This is a signed propagation, and the
+ * result may be negative. The loop above may enlarge values,
+ * but not two much: worst case is the chain involving t[i - 3],
+ * in which a value may be added to itself up to 7 times. Since
+ * starting values are 13-bit each, all words fit on 20 bits
+ * (21 to account for the sign bit).
+ */
+ cc = norm13(t, t, 20);
+
+ /*
+ * Perform modular reduction again for the bits beyond 256 (the carry
+ * and the bits 256..259). Since the largest shift below is by 10
+ * bits, and the values fit on 21 bits, values fit in 32-bit words,
+ * thereby allowing injecting full word values.
+ */
+ cc = (cc << 4) | (t[19] >> 9);
+ t[19] &= 0x01FF;
+ t[17] += cc << 3;
+ t[14] -= cc << 10;
+ t[7] -= cc << 5;
+ t[0] += cc;
+
+ /*
+ * If the carry is negative, then after carry propagation, we may
+ * end up with a value which is negative, and we don't want that.
+ * Thus, in that case, we add the modulus. Note that the subtraction
+ * result, when the carry is negative, is always smaller than the
+ * modulus, so the extra addition will not make the value exceed
+ * twice the modulus.
+ */
+ cc >>= 31;
+ t[0] -= cc;
+ t[7] += cc << 5;
+ t[14] += cc << 10;
+ t[17] -= cc << 3;
+ t[19] += cc << 9;
+
+ norm13(d, t, 20);
+}
+
+/*
+ * Jacobian coordinates for a point in P-256: affine coordinates (X,Y)
+ * are such that:
+ * X = x / z^2
+ * Y = y / z^3
+ * For the point at infinity, z = 0.
+ * Each point thus admits many possible representations.
+ *
+ * Coordinates are represented in arrays of 32-bit integers, each holding
+ * 13 bits of data. Values may also be slightly greater than the modulus,
+ * but they will always be lower than twice the modulus.
+ */
+typedef struct {
+ uint32_t x[20];
+ uint32_t y[20];
+ uint32_t z[20];
+} p256_jacobian;
+
+/*
+ * Convert a point to affine coordinates:
+ * - If the point is the point at infinity, then all three coordinates
+ * are set to 0.
+ * - Otherwise, the 'z' coordinate is set to 1, and the 'x' and 'y'
+ * coordinates are the 'X' and 'Y' affine coordinates.
+ * The coordinates are guaranteed to be lower than the modulus.
+ */
+static void
+p256_to_affine(p256_jacobian *P)
+{
+ uint32_t t1[20], t2[20];
+ int i;
+
+ /*
+ * Invert z with a modular exponentiation: the modulus is
+ * p = 2^256 - 2^224 + 2^192 + 2^96 - 1, and the exponent is
+ * p-2. Exponent bit pattern (from high to low) is:
+ * - 32 bits of value 1
+ * - 31 bits of value 0
+ * - 1 bit of value 1
+ * - 96 bits of value 0
+ * - 94 bits of value 1
+ * - 1 bit of value 0
+ * - 1 bit of value 1
+ * Thus, we precompute z^(2^31-1) to speed things up.
+ *
+ * If z = 0 (point at infinity) then the modular exponentiation
+ * will yield 0, which leads to the expected result (all three
+ * coordinates set to 0).
+ */
+
+ /*
+ * A simple square-and-multiply for z^(2^31-1). We could save about
+ * two dozen multiplications here with an addition chain, but
+ * this would require a bit more code, and extra stack buffers.
+ */
+ memcpy(t1, P->z, sizeof P->z);
+ for (i = 0; i < 30; i ++) {
+ square_f256(t1, t1);
+ mul_f256(t1, t1, P->z);
+ }
+
+ /*
+ * Square-and-multiply. Apart from the squarings, we have a few
+ * multiplications to set bits to 1; we multiply by the original z
+ * for setting 1 bit, and by t1 for setting 31 bits.
+ */
+ memcpy(t2, P->z, sizeof P->z);
+ for (i = 1; i < 256; i ++) {
+ square_f256(t2, t2);
+ switch (i) {
+ case 31:
+ case 190:
+ case 221:
+ case 252:
+ mul_f256(t2, t2, t1);
+ break;
+ case 63:
+ case 253:
+ case 255:
+ mul_f256(t2, t2, P->z);
+ break;
+ }
+ }
+
+ /*
+ * Now that we have 1/z, multiply x by 1/z^2 and y by 1/z^3.
+ */
+ mul_f256(t1, t2, t2);
+ mul_f256(P->x, t1, P->x);
+ mul_f256(t1, t1, t2);
+ mul_f256(P->y, t1, P->y);
+ reduce_final_f256(P->x);
+ reduce_final_f256(P->y);
+
+ /*
+ * Multiply z by 1/z. If z = 0, then this will yield 0, otherwise
+ * this will set z to 1.
+ */
+ mul_f256(P->z, P->z, t2);
+ reduce_final_f256(P->z);
+}
+
+/*
+ * Double a point in P-256. This function works for all valid points,
+ * including the point at infinity.
+ */
+static void
+p256_double(p256_jacobian *Q)
+{
+ /*
+ * 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
+ *
+ * These formulas work for all points, including points of order 2
+ * and points at infinity:
+ * - If y = 0 then z' = 0. But there is no such point in P-256
+ * anyway.
+ * - If z = 0 then z' = 0.
+ */
+ uint32_t t1[20], t2[20], t3[20], t4[20];
+ int i;
+
+ /*
+ * Compute z^2 in t1.
+ */
+ square_f256(t1, Q->z);
+
+ /*
+ * Compute x-z^2 in t2 and x+z^2 in t1.
+ */
+ for (i = 0; i < 20; i ++) {
+ t2[i] = (F256[i] << 1) + Q->x[i] - t1[i];
+ t1[i] += Q->x[i];
+ }
+ norm13(t1, t1, 20);
+ norm13(t2, t2, 20);
+
+ /*
+ * Compute 3*(x+z^2)*(x-z^2) in t1.
+ */
+ mul_f256(t3, t1, t2);
+ for (i = 0; i < 20; i ++) {
+ t1[i] = MUL15(3, t3[i]);
+ }
+ norm13(t1, t1, 20);
+
+ /*
+ * Compute 4*x*y^2 (in t2) and 2*y^2 (in t3).
+ */
+ square_f256(t3, Q->y);
+ for (i = 0; i < 20; i ++) {
+ t3[i] <<= 1;
+ }
+ norm13(t3, t3, 20);
+ mul_f256(t2, Q->x, t3);
+ for (i = 0; i < 20; i ++) {
+ t2[i] <<= 1;
+ }
+ norm13(t2, t2, 20);
+ reduce_f256(t2);
+
+ /*
+ * Compute x' = m^2 - 2*s.
+ */
+ square_f256(Q->x, t1);
+ for (i = 0; i < 20; i ++) {
+ Q->x[i] += (F256[i] << 2) - (t2[i] << 1);
+ }
+ norm13(Q->x, Q->x, 20);
+ reduce_f256(Q->x);
+
+ /*
+ * Compute z' = 2*y*z.
+ */
+ mul_f256(t4, Q->y, Q->z);
+ for (i = 0; i < 20; i ++) {
+ Q->z[i] = t4[i] << 1;
+ }
+ norm13(Q->z, Q->z, 20);
+ reduce_f256(Q->z);
+
+ /*
+ * Compute y' = m*(s - x') - 8*y^4. Note that we already have
+ * 2*y^2 in t3.
+ */
+ for (i = 0; i < 20; i ++) {
+ t2[i] += (F256[i] << 1) - Q->x[i];
+ }
+ norm13(t2, t2, 20);
+ mul_f256(Q->y, t1, t2);
+ square_f256(t4, t3);
+ for (i = 0; i < 20; i ++) {
+ Q->y[i] += (F256[i] << 2) - (t4[i] << 1);
+ }
+ norm13(Q->y, Q->y, 20);
+ reduce_f256(Q->y);
+}
+
+/*
+ * Add point P2 to point P1.
+ *
+ * This function computes the wrong result in the following cases:
+ *
+ * - If P1 == 0 but P2 != 0
+ * - If P1 != 0 but P2 == 0
+ * - If P1 == P2
+ *
+ * In all three cases, P1 is set to the point at infinity.
+ *
+ * Returned value is 0 if one of the following occurs:
+ *
+ * - P1 and P2 have the same Y coordinate
+ * - P1 == 0 and P2 == 0
+ * - The Y coordinate of one of the points is 0 and the other point is
+ * the point at infinity.
+ *
+ * The third case cannot actually happen with valid points, since a point
+ * with Y == 0 is a point of order 2, and there is no point of order 2 on
+ * curve P-256.
+ *
+ * Therefore, assuming that P1 != 0 and P2 != 0 on input, then the caller
+ * can apply the following:
+ *
+ * - If the result is not the point at infinity, then it is correct.
+ * - Otherwise, if the returned value is 1, then this is a case of
+ * P1+P2 == 0, so the result is indeed the point at infinity.
+ * - Otherwise, P1 == P2, so a "double" operation should have been
+ * performed.
+ */
+static uint32_t
+p256_add(p256_jacobian *P1, const p256_jacobian *P2)
+{
+ /*
+ * 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
+ */
+ uint32_t t1[20], t2[20], t3[20], t4[20], t5[20], t6[20], t7[20];
+ uint32_t ret;
+ int i;
+
+ /*
+ * Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3).
+ */
+ square_f256(t3, P2->z);
+ mul_f256(t1, P1->x, t3);
+ mul_f256(t4, P2->z, t3);
+ mul_f256(t3, P1->y, t4);
+
+ /*
+ * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
+ */
+ square_f256(t4, P1->z);
+ mul_f256(t2, P2->x, t4);
+ mul_f256(t5, P1->z, t4);
+ mul_f256(t4, P2->y, t5);
+
+ /*
+ * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4).
+ * We need to test whether r is zero, so we will do some extra
+ * reduce.
+ */
+ for (i = 0; i < 20; i ++) {
+ t2[i] += (F256[i] << 1) - t1[i];
+ t4[i] += (F256[i] << 1) - t3[i];
+ }
+ norm13(t2, t2, 20);
+ norm13(t4, t4, 20);
+ reduce_f256(t4);
+ reduce_final_f256(t4);
+ ret = 0;
+ for (i = 0; i < 20; i ++) {
+ ret |= t4[i];
+ }
+ ret = (ret | -ret) >> 31;
+
+ /*
+ * Compute u1*h^2 (in t6) and h^3 (in t5);
+ */
+ square_f256(t7, t2);
+ mul_f256(t6, t1, t7);
+ mul_f256(t5, t7, t2);
+
+ /*
+ * Compute x3 = r^2 - h^3 - 2*u1*h^2.
+ */
+ square_f256(P1->x, t4);
+ for (i = 0; i < 20; i ++) {
+ P1->x[i] += (F256[i] << 3) - t5[i] - (t6[i] << 1);
+ }
+ norm13(P1->x, P1->x, 20);
+ reduce_f256(P1->x);
+
+ /*
+ * Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
+ */
+ for (i = 0; i < 20; i ++) {
+ t6[i] += (F256[i] << 1) - P1->x[i];
+ }
+ norm13(t6, t6, 20);
+ mul_f256(P1->y, t4, t6);
+ mul_f256(t1, t5, t3);
+ for (i = 0; i < 20; i ++) {
+ P1->y[i] += (F256[i] << 1) - t1[i];
+ }
+ norm13(P1->y, P1->y, 20);
+ reduce_f256(P1->y);
+
+ /*
+ * Compute z3 = h*z1*z2.
+ */
+ mul_f256(t1, P1->z, P2->z);
+ mul_f256(P1->z, t1, t2);
+
+ return ret;
+}
+
+/*
+ * Add point P2 to point P1. This is a specialised function for the
+ * case when P2 is a non-zero point in affine coordinate.
+ *
+ * This function computes the wrong result in the following cases:
+ *
+ * - If P1 == 0
+ * - If P1 == P2
+ *
+ * In both cases, P1 is set to the point at infinity.
+ *
+ * Returned value is 0 if one of the following occurs:
+ *
+ * - P1 and P2 have the same Y coordinate
+ * - The Y coordinate of P2 is 0 and P1 is the point at infinity.
+ *
+ * The second case cannot actually happen with valid points, since a point
+ * with Y == 0 is a point of order 2, and there is no point of order 2 on
+ * curve P-256.
+ *
+ * Therefore, assuming that P1 != 0 on input, then the caller
+ * can apply the following:
+ *
+ * - If the result is not the point at infinity, then it is correct.
+ * - Otherwise, if the returned value is 1, then this is a case of
+ * P1+P2 == 0, so the result is indeed the point at infinity.
+ * - Otherwise, P1 == P2, so a "double" operation should have been
+ * performed.
+ */
+static uint32_t
+p256_add_mixed(p256_jacobian *P1, const p256_jacobian *P2)
+{
+ /*
+ * Addtions formulas are:
+ *
+ * u1 = x1
+ * u2 = x2 * z1^2
+ * s1 = y1
+ * 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
+ */
+ uint32_t t1[20], t2[20], t3[20], t4[20], t5[20], t6[20], t7[20];
+ uint32_t ret;
+ int i;
+
+ /*
+ * Compute u1 = x1 (in t1) and s1 = y1 (in t3).
+ */
+ memcpy(t1, P1->x, sizeof t1);
+ memcpy(t3, P1->y, sizeof t3);
+
+ /*
+ * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
+ */
+ square_f256(t4, P1->z);
+ mul_f256(t2, P2->x, t4);
+ mul_f256(t5, P1->z, t4);
+ mul_f256(t4, P2->y, t5);
+
+ /*
+ * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4).
+ * We need to test whether r is zero, so we will do some extra
+ * reduce.
+ */
+ for (i = 0; i < 20; i ++) {
+ t2[i] += (F256[i] << 1) - t1[i];
+ t4[i] += (F256[i] << 1) - t3[i];
+ }
+ norm13(t2, t2, 20);
+ norm13(t4, t4, 20);
+ reduce_f256(t4);
+ reduce_final_f256(t4);
+ ret = 0;
+ for (i = 0; i < 20; i ++) {
+ ret |= t4[i];
+ }
+ ret = (ret | -ret) >> 31;
+
+ /*
+ * Compute u1*h^2 (in t6) and h^3 (in t5);
+ */
+ square_f256(t7, t2);
+ mul_f256(t6, t1, t7);
+ mul_f256(t5, t7, t2);
+
+ /*
+ * Compute x3 = r^2 - h^3 - 2*u1*h^2.
+ */
+ square_f256(P1->x, t4);
+ for (i = 0; i < 20; i ++) {
+ P1->x[i] += (F256[i] << 3) - t5[i] - (t6[i] << 1);
+ }
+ norm13(P1->x, P1->x, 20);
+ reduce_f256(P1->x);
+
+ /*
+ * Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
+ */
+ for (i = 0; i < 20; i ++) {
+ t6[i] += (F256[i] << 1) - P1->x[i];
+ }
+ norm13(t6, t6, 20);
+ mul_f256(P1->y, t4, t6);
+ mul_f256(t1, t5, t3);
+ for (i = 0; i < 20; i ++) {
+ P1->y[i] += (F256[i] << 1) - t1[i];
+ }
+ norm13(P1->y, P1->y, 20);
+ reduce_f256(P1->y);
+
+ /*
+ * Compute z3 = h*z1*z2.
+ */
+ mul_f256(P1->z, P1->z, t2);
+
+ return ret;
+}
+
+/*
+ * Decode a P-256 point. This function does not support the point at
+ * infinity. Returned value is 0 if the point is invalid, 1 otherwise.
+ */
+static uint32_t
+p256_decode(p256_jacobian *P, const void *src, size_t len)
+{
+ const unsigned char *buf;
+ uint32_t tx[20], ty[20], t1[20], t2[20];
+ uint32_t bad;
+ int i;
+
+ if (len != 65) {
+ return 0;
+ }
+ buf = src;
+
+ /*
+ * First byte must be 0x04 (uncompressed format). We could support
+ * "hybrid format" (first byte is 0x06 or 0x07, and encodes the
+ * least significant bit of the Y coordinate), but it is explicitly
+ * forbidden by RFC 5480 (section 2.2).
+ */
+ bad = NEQ(buf[0], 0x04);
+
+ /*
+ * Decode the coordinates, and check that they are both lower
+ * than the modulus.
+ */
+ tx[19] = be8_to_le13(tx, buf + 1, 32);
+ ty[19] = be8_to_le13(ty, buf + 33, 32);
+ bad |= reduce_final_f256(tx);
+ bad |= reduce_final_f256(ty);
+
+ /*
+ * Check curve equation.
+ */
+ square_f256(t1, tx);
+ mul_f256(t1, tx, t1);
+ square_f256(t2, ty);
+ for (i = 0; i < 20; i ++) {
+ t1[i] += (F256[i] << 3) - MUL15(3, tx[i]) + P256_B[i] - t2[i];
+ }
+ norm13(t1, t1, 20);
+ reduce_f256(t1);
+ reduce_final_f256(t1);
+ for (i = 0; i < 20; i ++) {
+ bad |= t1[i];
+ }
+
+ /*
+ * Copy coordinates to the point structure.
+ */
+ memcpy(P->x, tx, sizeof tx);
+ memcpy(P->y, ty, sizeof ty);
+ memset(P->z, 0, sizeof P->z);
+ P->z[0] = 1;
+ return EQ(bad, 0);
+}
+
+/*
+ * Encode a point into a buffer. This function assumes that the point is
+ * valid, in affine coordinates, and not the point at infinity.
+ */
+static void
+p256_encode(void *dst, const p256_jacobian *P)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ buf[0] = 0x04;
+ le13_to_be8(buf + 1, 32, P->x);
+ le13_to_be8(buf + 33, 32, P->y);
+}
+
+/*
+ * Multiply a curve point by an integer. The integer is assumed to be
+ * lower than the curve order, and the base point must not be the point
+ * at infinity.
+ */
+static void
+p256_mul(p256_jacobian *P, const unsigned char *x, size_t xlen)
+{
+ /*
+ * qz is a flag that is initially 1, and remains equal to 1
+ * as long as the point is the point at infinity.
+ *
+ * We use a 2-bit window to handle multiplier bits by pairs.
+ * The precomputed window really is the points P2 and P3.
+ */
+ uint32_t qz;
+ p256_jacobian P2, P3, Q, T, U;
+
+ /*
+ * Compute window values.
+ */
+ P2 = *P;
+ p256_double(&P2);
+ P3 = *P;
+ p256_add(&P3, &P2);
+
+ /*
+ * We start with Q = 0. We process multiplier bits 2 by 2.
+ */
+ memset(&Q, 0, sizeof Q);
+ qz = 1;
+ while (xlen -- > 0) {
+ int k;
+
+ for (k = 6; k >= 0; k -= 2) {
+ uint32_t bits;
+ uint32_t bnz;
+
+ p256_double(&Q);
+ p256_double(&Q);
+ T = *P;
+ U = Q;
+ 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);
+ p256_add(&U, &T);
+ CCOPY(bnz & qz, &Q, &T, sizeof Q);
+ CCOPY(bnz & ~qz, &Q, &U, sizeof Q);
+ qz &= ~bnz;
+ }
+ x ++;
+ }
+ *P = Q;
+}
+
+/*
+ * Precomputed window: k*G points, where G is the curve generator, and k
+ * is an integer from 1 to 15 (inclusive). The X and Y coordinates of
+ * the point are encoded as 20 words of 13 bits each (little-endian
+ * order); 13-bit words are then grouped 2-by-2 into 32-bit words
+ * (little-endian order within each word).
+ */
+static const uint32_t Gwin[15][20] = {
+
+ { 0x04C60296, 0x02721176, 0x19D00F4A, 0x102517AC,
+ 0x13B8037D, 0x0748103C, 0x1E730E56, 0x08481FE2,
+ 0x0F97012C, 0x00D605F4, 0x1DFA11F5, 0x0C801A0D,
+ 0x0F670CBB, 0x0AED0CC5, 0x115E0E33, 0x181F0785,
+ 0x13F514A7, 0x0FF30E3B, 0x17171E1A, 0x009F18D0 },
+
+ { 0x1B341978, 0x16911F11, 0x0D9A1A60, 0x1C4E1FC8,
+ 0x1E040969, 0x096A06B0, 0x091C0030, 0x09EF1A29,
+ 0x18C40D03, 0x00F91C9E, 0x13C313D1, 0x096F0748,
+ 0x011419E0, 0x1CC713A6, 0x1DD31DAD, 0x1EE80C36,
+ 0x1ECD0C69, 0x1A0800A4, 0x08861B8E, 0x000E1DD5 },
+
+ { 0x173F1D6C, 0x02CC06F1, 0x14C21FB4, 0x043D1EB6,
+ 0x0F3606B7, 0x1A971C59, 0x1BF71951, 0x01481323,
+ 0x068D0633, 0x00BD12F9, 0x13EA1032, 0x136209E8,
+ 0x1C1E19A7, 0x06C7013E, 0x06C10AB0, 0x14C908BB,
+ 0x05830CE1, 0x1FEF18DD, 0x00620998, 0x010E0D19 },
+
+ { 0x18180852, 0x0604111A, 0x0B771509, 0x1B6F0156,
+ 0x00181FE2, 0x1DCC0AF4, 0x16EF0659, 0x11F70E80,
+ 0x11A912D0, 0x01C414D2, 0x027618C6, 0x05840FC6,
+ 0x100215C4, 0x187E0C3B, 0x12771C96, 0x150C0B5D,
+ 0x0FF705FD, 0x07981C67, 0x1AD20C63, 0x01C11C55 },
+
+ { 0x1E8113ED, 0x0A940370, 0x12920215, 0x1FA31D6F,
+ 0x1F7C0C82, 0x10CD03F7, 0x02640560, 0x081A0B5E,
+ 0x1BD21151, 0x00A21642, 0x0D0B0DA4, 0x0176113F,
+ 0x04440D1D, 0x001A1360, 0x1068012F, 0x1F141E49,
+ 0x10DF136B, 0x0E4F162B, 0x0D44104A, 0x01C1105F },
+
+ { 0x011411A9, 0x01551A4F, 0x0ADA0C6B, 0x01BD0EC8,
+ 0x18120C74, 0x112F1778, 0x099202CB, 0x0C05124B,
+ 0x195316A4, 0x01600685, 0x1E3B1FE2, 0x189014E3,
+ 0x0B5E1FD7, 0x0E0311F8, 0x08E000F7, 0x174E00DE,
+ 0x160702DF, 0x1B5A15BF, 0x03A11237, 0x01D01704 },
+
+ { 0x0C3D12A3, 0x0C501C0C, 0x17AD1300, 0x1715003F,
+ 0x03F719F8, 0x18031ED8, 0x1D980667, 0x0F681896,
+ 0x1B7D00BF, 0x011C14CE, 0x0FA000B4, 0x1C3501B0,
+ 0x0D901C55, 0x06790C10, 0x029E0736, 0x0DEB0400,
+ 0x034F183A, 0x030619B4, 0x0DEF0033, 0x00E71AC7 },
+
+ { 0x1B7D1393, 0x1B3B1076, 0x0BED1B4D, 0x13011F3A,
+ 0x0E0E1238, 0x156A132B, 0x013A02D3, 0x160A0D01,
+ 0x1CED1EE9, 0x00C5165D, 0x184C157E, 0x08141A83,
+ 0x153C0DA5, 0x1ED70F9D, 0x05170D51, 0x02CF13B8,
+ 0x18AE1771, 0x1B04113F, 0x05EC11E9, 0x015A16B3 },
+
+ { 0x04A41EE0, 0x1D1412E4, 0x1C591D79, 0x118511B7,
+ 0x14F00ACB, 0x1AE31E1C, 0x049C0D51, 0x016E061E,
+ 0x1DB71EDF, 0x01D41A35, 0x0E8208FA, 0x14441293,
+ 0x011F1E85, 0x1D54137A, 0x026B114F, 0x151D0832,
+ 0x00A50964, 0x1F9C1E1C, 0x064B12C9, 0x005409D1 },
+
+ { 0x062B123F, 0x0C0D0501, 0x183704C3, 0x08E31120,
+ 0x0A2E0A6C, 0x14440FED, 0x090A0D1E, 0x13271964,
+ 0x0B590A3A, 0x019D1D9B, 0x05780773, 0x09770A91,
+ 0x0F770CA3, 0x053F19D4, 0x02C80DED, 0x1A761304,
+ 0x091E0DD9, 0x15D201B8, 0x151109AA, 0x010F0198 },
+
+ { 0x05E101D1, 0x072314DD, 0x045F1433, 0x1A041541,
+ 0x10B3142E, 0x01840736, 0x1C1B19DB, 0x098B0418,
+ 0x1DBC083B, 0x007D1444, 0x01511740, 0x11DD1F3A,
+ 0x04ED0E2F, 0x1B4B1A62, 0x10480D04, 0x09E911A2,
+ 0x04211AFA, 0x19140893, 0x04D60CC4, 0x01210648 },
+
+ { 0x112703C4, 0x018B1BA1, 0x164C1D50, 0x05160BE0,
+ 0x0BCC1830, 0x01CB1554, 0x13291732, 0x1B2B1918,
+ 0x0DED0817, 0x00E80775, 0x0A2401D3, 0x0BFE08B3,
+ 0x0E531199, 0x058616E9, 0x04770B91, 0x110F0C55,
+ 0x19C11554, 0x0BFB1159, 0x03541C38, 0x000E1C2D },
+
+ { 0x10390C01, 0x02BB0751, 0x0AC5098E, 0x096C17AB,
+ 0x03C90E28, 0x10BD18BF, 0x002E1F2D, 0x092B0986,
+ 0x1BD700AC, 0x002E1F20, 0x1E3D1FD8, 0x077718BB,
+ 0x06F919C4, 0x187407ED, 0x11370E14, 0x081E139C,
+ 0x00481ADB, 0x14AB0289, 0x066A0EBE, 0x00C70ED6 },
+
+ { 0x0694120B, 0x124E1CC9, 0x0E2F0570, 0x17CF081A,
+ 0x078906AC, 0x066D17CF, 0x1B3207F4, 0x0C5705E9,
+ 0x10001C38, 0x00A919DE, 0x06851375, 0x0F900BD8,
+ 0x080401BA, 0x0EEE0D42, 0x1B8B11EA, 0x0B4519F0,
+ 0x090F18C0, 0x062E1508, 0x0DD909F4, 0x01EB067C },
+
+ { 0x0CDC1D5F, 0x0D1818F9, 0x07781636, 0x125B18E8,
+ 0x0D7003AF, 0x13110099, 0x1D9B1899, 0x175C1EB7,
+ 0x0E34171A, 0x01E01153, 0x081A0F36, 0x0B391783,
+ 0x1D1F147E, 0x19CE16D7, 0x11511B21, 0x1F2C10F9,
+ 0x12CA0E51, 0x05A31D39, 0x171A192E, 0x016B0E4F }
+};
+
+/*
+ * Lookup one of the Gwin[] values, by index. This is constant-time.
+ */
+static void
+lookup_Gwin(p256_jacobian *T, uint32_t idx)
+{
+ uint32_t xy[20];
+ uint32_t k;
+ size_t u;
+
+ memset(xy, 0, sizeof xy);
+ for (k = 0; k < 15; k ++) {
+ uint32_t m;
+
+ m = -EQ(idx, k + 1);
+ for (u = 0; u < 20; u ++) {
+ xy[u] |= m & Gwin[k][u];
+ }
+ }
+ for (u = 0; u < 10; u ++) {
+ T->x[(u << 1) + 0] = xy[u] & 0xFFFF;
+ T->x[(u << 1) + 1] = xy[u] >> 16;
+ T->y[(u << 1) + 0] = xy[u + 10] & 0xFFFF;
+ T->y[(u << 1) + 1] = xy[u + 10] >> 16;
+ }
+ memset(T->z, 0, sizeof T->z);
+ T->z[0] = 1;
+}
+
+/*
+ * Multiply the generator by an integer. The integer is assumed non-zero
+ * and lower than the curve order.
+ */
+static void
+p256_mulgen(p256_jacobian *P, const unsigned char *x, size_t xlen)
+{
+ /*
+ * qz is a flag that is initially 1, and remains equal to 1
+ * as long as the point is the point at infinity.
+ *
+ * We use a 4-bit window to handle multiplier bits by groups
+ * of 4. The precomputed window is constant static data, with
+ * points in affine coordinates; we use a constant-time lookup.
+ */
+ p256_jacobian Q;
+ uint32_t qz;
+
+ memset(&Q, 0, sizeof Q);
+ qz = 1;
+ while (xlen -- > 0) {
+ int k;
+ unsigned bx;
+
+ bx = *x ++;
+ for (k = 0; k < 2; k ++) {
+ uint32_t bits;
+ uint32_t bnz;
+ p256_jacobian T, U;
+
+ p256_double(&Q);
+ p256_double(&Q);
+ p256_double(&Q);
+ p256_double(&Q);
+ bits = (bx >> 4) & 0x0F;
+ bnz = NEQ(bits, 0);
+ lookup_Gwin(&T, bits);
+ U = Q;
+ p256_add_mixed(&U, &T);
+ CCOPY(bnz & qz, &Q, &T, sizeof Q);
+ CCOPY(bnz & ~qz, &Q, &U, sizeof Q);
+ qz &= ~bnz;
+ bx <<= 4;
+ }
+ }
+ *P = Q;
+}
+
+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
+};
+
+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 *
+api_generator(int curve, size_t *len)
+{
+ (void)curve;
+ *len = sizeof P256_G;
+ return P256_G;
+}
+
+static const unsigned char *
+api_order(int curve, size_t *len)
+{
+ (void)curve;
+ *len = sizeof P256_N;
+ return P256_N;
+}
+
+static size_t
+api_xoff(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return 1;
+}
+
+static uint32_t
+api_mul(unsigned char *G, size_t Glen,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ uint32_t r;
+ p256_jacobian P;
+
+ (void)curve;
+ r = p256_decode(&P, G, Glen);
+ p256_mul(&P, x, xlen);
+ if (Glen >= 65) {
+ p256_to_affine(&P);
+ p256_encode(G, &P);
+ }
+ return r;
+}
+
+static size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ p256_jacobian P;
+
+ (void)curve;
+ p256_mulgen(&P, x, xlen);
+ p256_to_affine(&P);
+ p256_encode(R, &P);
+ return 65;
+
+ /*
+ const unsigned char *G;
+ size_t Glen;
+
+ G = api_generator(curve, &Glen);
+ memcpy(R, G, Glen);
+ api_mul(R, Glen, x, xlen, curve);
+ return Glen;
+ */
+}
+
+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)
+{
+ p256_jacobian P, Q;
+ uint32_t r, t, z;
+ int i;
+
+ (void)curve;
+ r = p256_decode(&P, A, len);
+ p256_mul(&P, x, xlen);
+ if (B == NULL) {
+ p256_mulgen(&Q, y, ylen);
+ } else {
+ r &= p256_decode(&Q, B, len);
+ p256_mul(&Q, y, ylen);
+ }
+
+ /*
+ * The final addition may fail in case both points are equal.
+ */
+ t = p256_add(&P, &Q);
+ reduce_final_f256(P.z);
+ z = 0;
+ for (i = 0; i < 20; i ++) {
+ z |= P.z[i];
+ }
+ z = EQ(z, 0);
+ p256_double(&Q);
+
+ /*
+ * 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);
+ p256_to_affine(&P);
+ p256_encode(A, &P);
+ r &= ~(z & t);
+ return r;
+}
+
+/* see bearssl_ec.h */
+const br_ec_impl br_ec_p256_m15 = {
+ (uint32_t)0x00800000,
+ &api_generator,
+ &api_order,
+ &api_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
diff --git a/contrib/bearssl/src/ec/ec_p256_m31.c b/contrib/bearssl/src/ec/ec_p256_m31.c
new file mode 100644
index 000000000000..d57ef7b097ff
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_p256_m31.c
@@ -0,0 +1,1475 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * If BR_NO_ARITH_SHIFT is undefined, or defined to 0, then we _assume_
+ * that right-shifting a signed negative integer copies the sign bit
+ * (arithmetic right-shift). This is "implementation-defined behaviour",
+ * i.e. it is not undefined, but it may differ between compilers. Each
+ * compiler is supposed to document its behaviour in that respect. GCC
+ * explicitly defines that an arithmetic right shift is used. We expect
+ * all other compilers to do the same, because underlying CPU offer an
+ * arithmetic right shift opcode that could not be used otherwise.
+ */
+#if BR_NO_ARITH_SHIFT
+#define ARSH(x, n) (((uint32_t)(x) >> (n)) \
+ | ((-((uint32_t)(x) >> 31)) << (32 - (n))))
+#define ARSHW(x, n) (((uint64_t)(x) >> (n)) \
+ | ((-((uint64_t)(x) >> 63)) << (64 - (n))))
+#else
+#define ARSH(x, n) ((*(int32_t *)&(x)) >> (n))
+#define ARSHW(x, n) ((*(int64_t *)&(x)) >> (n))
+#endif
+
+/*
+ * Convert an integer from unsigned big-endian encoding to a sequence of
+ * 30-bit words in little-endian order. The final "partial" word is
+ * returned.
+ */
+static uint32_t
+be8_to_le30(uint32_t *dst, const unsigned char *src, size_t len)
+{
+ uint32_t acc;
+ int acc_len;
+
+ acc = 0;
+ acc_len = 0;
+ while (len -- > 0) {
+ uint32_t b;
+
+ b = src[len];
+ if (acc_len < 22) {
+ acc |= b << acc_len;
+ acc_len += 8;
+ } else {
+ *dst ++ = (acc | (b << acc_len)) & 0x3FFFFFFF;
+ acc = b >> (30 - acc_len);
+ acc_len -= 22;
+ }
+ }
+ return acc;
+}
+
+/*
+ * Convert an integer (30-bit words, little-endian) to unsigned
+ * big-endian encoding. The total encoding length is provided; all
+ * the destination bytes will be filled.
+ */
+static void
+le30_to_be8(unsigned char *dst, size_t len, const uint32_t *src)
+{
+ uint32_t acc;
+ int acc_len;
+
+ acc = 0;
+ acc_len = 0;
+ while (len -- > 0) {
+ if (acc_len < 8) {
+ uint32_t w;
+
+ w = *src ++;
+ dst[len] = (unsigned char)(acc | (w << acc_len));
+ acc = w >> (8 - acc_len);
+ acc_len += 22;
+ } else {
+ dst[len] = (unsigned char)acc;
+ acc >>= 8;
+ acc_len -= 8;
+ }
+ }
+}
+
+/*
+ * Multiply two integers. Source integers are represented as arrays of
+ * nine 30-bit words, for values up to 2^270-1. Result is encoded over
+ * 18 words of 30 bits each.
+ */
+static void
+mul9(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ /*
+ * Maximum intermediate result is no more than
+ * 10376293531797946367, which fits in 64 bits. Reason:
+ *
+ * 10376293531797946367 = 9 * (2^30-1)^2 + 9663676406
+ * 10376293531797946367 < 9663676407 * 2^30
+ *
+ * Thus, adding together 9 products of 30-bit integers, with
+ * a carry of at most 9663676406, yields an integer that fits
+ * on 64 bits and generates a carry of at most 9663676406.
+ */
+ uint64_t t[17];
+ uint64_t cc;
+ int i;
+
+ t[ 0] = MUL31(a[0], b[0]);
+ t[ 1] = MUL31(a[0], b[1])
+ + MUL31(a[1], b[0]);
+ t[ 2] = MUL31(a[0], b[2])
+ + MUL31(a[1], b[1])
+ + MUL31(a[2], b[0]);
+ t[ 3] = MUL31(a[0], b[3])
+ + MUL31(a[1], b[2])
+ + MUL31(a[2], b[1])
+ + MUL31(a[3], b[0]);
+ t[ 4] = MUL31(a[0], b[4])
+ + MUL31(a[1], b[3])
+ + MUL31(a[2], b[2])
+ + MUL31(a[3], b[1])
+ + MUL31(a[4], b[0]);
+ t[ 5] = MUL31(a[0], b[5])
+ + MUL31(a[1], b[4])
+ + MUL31(a[2], b[3])
+ + MUL31(a[3], b[2])
+ + MUL31(a[4], b[1])
+ + MUL31(a[5], b[0]);
+ t[ 6] = MUL31(a[0], b[6])
+ + MUL31(a[1], b[5])
+ + MUL31(a[2], b[4])
+ + MUL31(a[3], b[3])
+ + MUL31(a[4], b[2])
+ + MUL31(a[5], b[1])
+ + MUL31(a[6], b[0]);
+ t[ 7] = MUL31(a[0], b[7])
+ + MUL31(a[1], b[6])
+ + MUL31(a[2], b[5])
+ + MUL31(a[3], b[4])
+ + MUL31(a[4], b[3])
+ + MUL31(a[5], b[2])
+ + MUL31(a[6], b[1])
+ + MUL31(a[7], b[0]);
+ t[ 8] = MUL31(a[0], b[8])
+ + MUL31(a[1], b[7])
+ + MUL31(a[2], b[6])
+ + MUL31(a[3], b[5])
+ + MUL31(a[4], b[4])
+ + MUL31(a[5], b[3])
+ + MUL31(a[6], b[2])
+ + MUL31(a[7], b[1])
+ + MUL31(a[8], b[0]);
+ t[ 9] = MUL31(a[1], b[8])
+ + MUL31(a[2], b[7])
+ + MUL31(a[3], b[6])
+ + MUL31(a[4], b[5])
+ + MUL31(a[5], b[4])
+ + MUL31(a[6], b[3])
+ + MUL31(a[7], b[2])
+ + MUL31(a[8], b[1]);
+ t[10] = MUL31(a[2], b[8])
+ + MUL31(a[3], b[7])
+ + MUL31(a[4], b[6])
+ + MUL31(a[5], b[5])
+ + MUL31(a[6], b[4])
+ + MUL31(a[7], b[3])
+ + MUL31(a[8], b[2]);
+ t[11] = MUL31(a[3], b[8])
+ + MUL31(a[4], b[7])
+ + MUL31(a[5], b[6])
+ + MUL31(a[6], b[5])
+ + MUL31(a[7], b[4])
+ + MUL31(a[8], b[3]);
+ t[12] = MUL31(a[4], b[8])
+ + MUL31(a[5], b[7])
+ + MUL31(a[6], b[6])
+ + MUL31(a[7], b[5])
+ + MUL31(a[8], b[4]);
+ t[13] = MUL31(a[5], b[8])
+ + MUL31(a[6], b[7])
+ + MUL31(a[7], b[6])
+ + MUL31(a[8], b[5]);
+ t[14] = MUL31(a[6], b[8])
+ + MUL31(a[7], b[7])
+ + MUL31(a[8], b[6]);
+ t[15] = MUL31(a[7], b[8])
+ + MUL31(a[8], b[7]);
+ t[16] = MUL31(a[8], b[8]);
+
+ /*
+ * Propagate carries.
+ */
+ cc = 0;
+ for (i = 0; i < 17; i ++) {
+ uint64_t w;
+
+ w = t[i] + cc;
+ d[i] = (uint32_t)w & 0x3FFFFFFF;
+ cc = w >> 30;
+ }
+ d[17] = (uint32_t)cc;
+}
+
+/*
+ * Square a 270-bit integer, represented as an array of nine 30-bit words.
+ * Result uses 18 words of 30 bits each.
+ */
+static void
+square9(uint32_t *d, const uint32_t *a)
+{
+ uint64_t t[17];
+ uint64_t cc;
+ int i;
+
+ t[ 0] = MUL31(a[0], a[0]);
+ t[ 1] = ((MUL31(a[0], a[1])) << 1);
+ t[ 2] = MUL31(a[1], a[1])
+ + ((MUL31(a[0], a[2])) << 1);
+ t[ 3] = ((MUL31(a[0], a[3])
+ + MUL31(a[1], a[2])) << 1);
+ t[ 4] = MUL31(a[2], a[2])
+ + ((MUL31(a[0], a[4])
+ + MUL31(a[1], a[3])) << 1);
+ t[ 5] = ((MUL31(a[0], a[5])
+ + MUL31(a[1], a[4])
+ + MUL31(a[2], a[3])) << 1);
+ t[ 6] = MUL31(a[3], a[3])
+ + ((MUL31(a[0], a[6])
+ + MUL31(a[1], a[5])
+ + MUL31(a[2], a[4])) << 1);
+ t[ 7] = ((MUL31(a[0], a[7])
+ + MUL31(a[1], a[6])
+ + MUL31(a[2], a[5])
+ + MUL31(a[3], a[4])) << 1);
+ t[ 8] = MUL31(a[4], a[4])
+ + ((MUL31(a[0], a[8])
+ + MUL31(a[1], a[7])
+ + MUL31(a[2], a[6])
+ + MUL31(a[3], a[5])) << 1);
+ t[ 9] = ((MUL31(a[1], a[8])
+ + MUL31(a[2], a[7])
+ + MUL31(a[3], a[6])
+ + MUL31(a[4], a[5])) << 1);
+ t[10] = MUL31(a[5], a[5])
+ + ((MUL31(a[2], a[8])
+ + MUL31(a[3], a[7])
+ + MUL31(a[4], a[6])) << 1);
+ t[11] = ((MUL31(a[3], a[8])
+ + MUL31(a[4], a[7])
+ + MUL31(a[5], a[6])) << 1);
+ t[12] = MUL31(a[6], a[6])
+ + ((MUL31(a[4], a[8])
+ + MUL31(a[5], a[7])) << 1);
+ t[13] = ((MUL31(a[5], a[8])
+ + MUL31(a[6], a[7])) << 1);
+ t[14] = MUL31(a[7], a[7])
+ + ((MUL31(a[6], a[8])) << 1);
+ t[15] = ((MUL31(a[7], a[8])) << 1);
+ t[16] = MUL31(a[8], a[8]);
+
+ /*
+ * Propagate carries.
+ */
+ cc = 0;
+ for (i = 0; i < 17; i ++) {
+ uint64_t w;
+
+ w = t[i] + cc;
+ d[i] = (uint32_t)w & 0x3FFFFFFF;
+ cc = w >> 30;
+ }
+ d[17] = (uint32_t)cc;
+}
+
+/*
+ * Base field modulus for P-256.
+ */
+static const uint32_t F256[] = {
+
+ 0x3FFFFFFF, 0x3FFFFFFF, 0x3FFFFFFF, 0x0000003F, 0x00000000,
+ 0x00000000, 0x00001000, 0x3FFFC000, 0x0000FFFF
+};
+
+/*
+ * The 'b' curve equation coefficient for P-256.
+ */
+static const uint32_t P256_B[] = {
+
+ 0x27D2604B, 0x2F38F0F8, 0x053B0F63, 0x0741AC33, 0x1886BC65,
+ 0x2EF555DA, 0x293E7B3E, 0x0D762A8E, 0x00005AC6
+};
+
+/*
+ * Addition in the field. Source operands shall fit on 257 bits; output
+ * will be lower than twice the modulus.
+ */
+static void
+add_f256(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ uint32_t w, cc;
+ int i;
+
+ cc = 0;
+ for (i = 0; i < 9; i ++) {
+ w = a[i] + b[i] + cc;
+ d[i] = w & 0x3FFFFFFF;
+ cc = w >> 30;
+ }
+ w >>= 16;
+ d[8] &= 0xFFFF;
+ d[3] -= w << 6;
+ d[6] -= w << 12;
+ d[7] += w << 14;
+ cc = w;
+ for (i = 0; i < 9; i ++) {
+ w = d[i] + cc;
+ d[i] = w & 0x3FFFFFFF;
+ cc = ARSH(w, 30);
+ }
+}
+
+/*
+ * Subtraction in the field. Source operands shall be smaller than twice
+ * the modulus; the result will fulfil the same property.
+ */
+static void
+sub_f256(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ uint32_t w, cc;
+ int i;
+
+ /*
+ * We really compute a - b + 2*p to make sure that the result is
+ * positive.
+ */
+ w = a[0] - b[0] - 0x00002;
+ d[0] = w & 0x3FFFFFFF;
+ w = a[1] - b[1] + ARSH(w, 30);
+ d[1] = w & 0x3FFFFFFF;
+ w = a[2] - b[2] + ARSH(w, 30);
+ d[2] = w & 0x3FFFFFFF;
+ w = a[3] - b[3] + ARSH(w, 30) + 0x00080;
+ d[3] = w & 0x3FFFFFFF;
+ w = a[4] - b[4] + ARSH(w, 30);
+ d[4] = w & 0x3FFFFFFF;
+ w = a[5] - b[5] + ARSH(w, 30);
+ d[5] = w & 0x3FFFFFFF;
+ w = a[6] - b[6] + ARSH(w, 30) + 0x02000;
+ d[6] = w & 0x3FFFFFFF;
+ w = a[7] - b[7] + ARSH(w, 30) - 0x08000;
+ d[7] = w & 0x3FFFFFFF;
+ w = a[8] - b[8] + ARSH(w, 30) + 0x20000;
+ d[8] = w & 0xFFFF;
+ w >>= 16;
+ d[8] &= 0xFFFF;
+ d[3] -= w << 6;
+ d[6] -= w << 12;
+ d[7] += w << 14;
+ cc = w;
+ for (i = 0; i < 9; i ++) {
+ w = d[i] + cc;
+ d[i] = w & 0x3FFFFFFF;
+ cc = ARSH(w, 30);
+ }
+}
+
+/*
+ * Compute a multiplication in F256. Source operands shall be less than
+ * twice the modulus.
+ */
+static void
+mul_f256(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ uint32_t t[18];
+ uint64_t s[18];
+ uint64_t cc, x;
+ uint32_t z, c;
+ int i;
+
+ mul9(t, a, b);
+
+ /*
+ * Modular reduction: each high word in added/subtracted where
+ * necessary.
+ *
+ * The modulus is:
+ * p = 2^256 - 2^224 + 2^192 + 2^96 - 1
+ * Therefore:
+ * 2^256 = 2^224 - 2^192 - 2^96 + 1 mod p
+ *
+ * For a word x at bit offset n (n >= 256), we have:
+ * x*2^n = x*2^(n-32) - x*2^(n-64)
+ * - x*2^(n - 160) + x*2^(n-256) mod p
+ *
+ * Thus, we can nullify the high word if we reinject it at some
+ * proper emplacements.
+ *
+ * We use 64-bit intermediate words to allow for carries to
+ * accumulate easily, before performing the final propagation.
+ */
+ for (i = 0; i < 18; i ++) {
+ s[i] = t[i];
+ }
+
+ for (i = 17; i >= 9; i --) {
+ uint64_t y;
+
+ y = s[i];
+ s[i - 1] += ARSHW(y, 2);
+ s[i - 2] += (y << 28) & 0x3FFFFFFF;
+ s[i - 2] -= ARSHW(y, 4);
+ s[i - 3] -= (y << 26) & 0x3FFFFFFF;
+ s[i - 5] -= ARSHW(y, 10);
+ s[i - 6] -= (y << 20) & 0x3FFFFFFF;
+ s[i - 8] += ARSHW(y, 16);
+ s[i - 9] += (y << 14) & 0x3FFFFFFF;
+ }
+
+ /*
+ * Carry propagation must be signed. Moreover, we may have overdone
+ * it a bit, and obtain a negative result.
+ *
+ * The loop above ran 9 times; each time, each word was augmented
+ * by at most one extra word (in absolute value). Thus, the top
+ * word must in fine fit in 39 bits, so the carry below will fit
+ * on 9 bits.
+ */
+ cc = 0;
+ for (i = 0; i < 9; i ++) {
+ x = s[i] + cc;
+ d[i] = (uint32_t)x & 0x3FFFFFFF;
+ cc = ARSHW(x, 30);
+ }
+
+ /*
+ * All nine words fit on 30 bits, but there may be an extra
+ * carry for a few bits (at most 9), and that carry may be
+ * negative. Moreover, we want the result to fit on 257 bits.
+ * The two lines below ensure that the word in d[] has length
+ * 256 bits, and the (signed) carry (beyond 2^256) is in cc. The
+ * significant length of cc is less than 24 bits, so we will be
+ * able to switch to 32-bit operations.
+ */
+ cc = ARSHW(x, 16);
+ d[8] &= 0xFFFF;
+
+ /*
+ * One extra round of reduction, for cc*2^256, which means
+ * adding cc*(2^224-2^192-2^96+1) to a 256-bit (nonnegative)
+ * value. If cc is negative, then it may happen (rarely, but
+ * not neglectibly so) that the result would be negative. In
+ * order to avoid that, if cc is negative, then we add the
+ * modulus once. Note that if cc is negative, then propagating
+ * that carry must yield a value lower than the modulus, so
+ * adding the modulus once will keep the final result under
+ * twice the modulus.
+ */
+ z = (uint32_t)cc;
+ d[3] -= z << 6;
+ d[6] -= (z << 12) & 0x3FFFFFFF;
+ d[7] -= ARSH(z, 18);
+ d[7] += (z << 14) & 0x3FFFFFFF;
+ d[8] += ARSH(z, 16);
+ c = z >> 31;
+ d[0] -= c;
+ d[3] += c << 6;
+ d[6] += c << 12;
+ d[7] -= c << 14;
+ d[8] += c << 16;
+ for (i = 0; i < 9; i ++) {
+ uint32_t w;
+
+ w = d[i] + z;
+ d[i] = w & 0x3FFFFFFF;
+ z = ARSH(w, 30);
+ }
+}
+
+/*
+ * Compute a square in F256. Source operand shall be less than
+ * twice the modulus.
+ */
+static void
+square_f256(uint32_t *d, const uint32_t *a)
+{
+ uint32_t t[18];
+ uint64_t s[18];
+ uint64_t cc, x;
+ uint32_t z, c;
+ int i;
+
+ square9(t, a);
+
+ /*
+ * Modular reduction: each high word in added/subtracted where
+ * necessary.
+ *
+ * The modulus is:
+ * p = 2^256 - 2^224 + 2^192 + 2^96 - 1
+ * Therefore:
+ * 2^256 = 2^224 - 2^192 - 2^96 + 1 mod p
+ *
+ * For a word x at bit offset n (n >= 256), we have:
+ * x*2^n = x*2^(n-32) - x*2^(n-64)
+ * - x*2^(n - 160) + x*2^(n-256) mod p
+ *
+ * Thus, we can nullify the high word if we reinject it at some
+ * proper emplacements.
+ *
+ * We use 64-bit intermediate words to allow for carries to
+ * accumulate easily, before performing the final propagation.
+ */
+ for (i = 0; i < 18; i ++) {
+ s[i] = t[i];
+ }
+
+ for (i = 17; i >= 9; i --) {
+ uint64_t y;
+
+ y = s[i];
+ s[i - 1] += ARSHW(y, 2);
+ s[i - 2] += (y << 28) & 0x3FFFFFFF;
+ s[i - 2] -= ARSHW(y, 4);
+ s[i - 3] -= (y << 26) & 0x3FFFFFFF;
+ s[i - 5] -= ARSHW(y, 10);
+ s[i - 6] -= (y << 20) & 0x3FFFFFFF;
+ s[i - 8] += ARSHW(y, 16);
+ s[i - 9] += (y << 14) & 0x3FFFFFFF;
+ }
+
+ /*
+ * Carry propagation must be signed. Moreover, we may have overdone
+ * it a bit, and obtain a negative result.
+ *
+ * The loop above ran 9 times; each time, each word was augmented
+ * by at most one extra word (in absolute value). Thus, the top
+ * word must in fine fit in 39 bits, so the carry below will fit
+ * on 9 bits.
+ */
+ cc = 0;
+ for (i = 0; i < 9; i ++) {
+ x = s[i] + cc;
+ d[i] = (uint32_t)x & 0x3FFFFFFF;
+ cc = ARSHW(x, 30);
+ }
+
+ /*
+ * All nine words fit on 30 bits, but there may be an extra
+ * carry for a few bits (at most 9), and that carry may be
+ * negative. Moreover, we want the result to fit on 257 bits.
+ * The two lines below ensure that the word in d[] has length
+ * 256 bits, and the (signed) carry (beyond 2^256) is in cc. The
+ * significant length of cc is less than 24 bits, so we will be
+ * able to switch to 32-bit operations.
+ */
+ cc = ARSHW(x, 16);
+ d[8] &= 0xFFFF;
+
+ /*
+ * One extra round of reduction, for cc*2^256, which means
+ * adding cc*(2^224-2^192-2^96+1) to a 256-bit (nonnegative)
+ * value. If cc is negative, then it may happen (rarely, but
+ * not neglectibly so) that the result would be negative. In
+ * order to avoid that, if cc is negative, then we add the
+ * modulus once. Note that if cc is negative, then propagating
+ * that carry must yield a value lower than the modulus, so
+ * adding the modulus once will keep the final result under
+ * twice the modulus.
+ */
+ z = (uint32_t)cc;
+ d[3] -= z << 6;
+ d[6] -= (z << 12) & 0x3FFFFFFF;
+ d[7] -= ARSH(z, 18);
+ d[7] += (z << 14) & 0x3FFFFFFF;
+ d[8] += ARSH(z, 16);
+ c = z >> 31;
+ d[0] -= c;
+ d[3] += c << 6;
+ d[6] += c << 12;
+ d[7] -= c << 14;
+ d[8] += c << 16;
+ for (i = 0; i < 9; i ++) {
+ uint32_t w;
+
+ w = d[i] + z;
+ d[i] = w & 0x3FFFFFFF;
+ z = ARSH(w, 30);
+ }
+}
+
+/*
+ * Perform a "final reduction" in field F256 (field for curve P-256).
+ * The source value must be less than twice the modulus. If the value
+ * is not lower than the modulus, then the modulus is subtracted and
+ * this function returns 1; otherwise, it leaves it untouched and it
+ * returns 0.
+ */
+static uint32_t
+reduce_final_f256(uint32_t *d)
+{
+ uint32_t t[9];
+ uint32_t cc;
+ int i;
+
+ cc = 0;
+ for (i = 0; i < 9; i ++) {
+ uint32_t w;
+
+ w = d[i] - F256[i] - cc;
+ cc = w >> 31;
+ t[i] = w & 0x3FFFFFFF;
+ }
+ cc ^= 1;
+ CCOPY(cc, d, t, sizeof t);
+ return cc;
+}
+
+/*
+ * Jacobian coordinates for a point in P-256: affine coordinates (X,Y)
+ * are such that:
+ * X = x / z^2
+ * Y = y / z^3
+ * For the point at infinity, z = 0.
+ * Each point thus admits many possible representations.
+ *
+ * Coordinates are represented in arrays of 32-bit integers, each holding
+ * 30 bits of data. Values may also be slightly greater than the modulus,
+ * but they will always be lower than twice the modulus.
+ */
+typedef struct {
+ uint32_t x[9];
+ uint32_t y[9];
+ uint32_t z[9];
+} p256_jacobian;
+
+/*
+ * Convert a point to affine coordinates:
+ * - If the point is the point at infinity, then all three coordinates
+ * are set to 0.
+ * - Otherwise, the 'z' coordinate is set to 1, and the 'x' and 'y'
+ * coordinates are the 'X' and 'Y' affine coordinates.
+ * The coordinates are guaranteed to be lower than the modulus.
+ */
+static void
+p256_to_affine(p256_jacobian *P)
+{
+ uint32_t t1[9], t2[9];
+ int i;
+
+ /*
+ * Invert z with a modular exponentiation: the modulus is
+ * p = 2^256 - 2^224 + 2^192 + 2^96 - 1, and the exponent is
+ * p-2. Exponent bit pattern (from high to low) is:
+ * - 32 bits of value 1
+ * - 31 bits of value 0
+ * - 1 bit of value 1
+ * - 96 bits of value 0
+ * - 94 bits of value 1
+ * - 1 bit of value 0
+ * - 1 bit of value 1
+ * Thus, we precompute z^(2^31-1) to speed things up.
+ *
+ * If z = 0 (point at infinity) then the modular exponentiation
+ * will yield 0, which leads to the expected result (all three
+ * coordinates set to 0).
+ */
+
+ /*
+ * A simple square-and-multiply for z^(2^31-1). We could save about
+ * two dozen multiplications here with an addition chain, but
+ * this would require a bit more code, and extra stack buffers.
+ */
+ memcpy(t1, P->z, sizeof P->z);
+ for (i = 0; i < 30; i ++) {
+ square_f256(t1, t1);
+ mul_f256(t1, t1, P->z);
+ }
+
+ /*
+ * Square-and-multiply. Apart from the squarings, we have a few
+ * multiplications to set bits to 1; we multiply by the original z
+ * for setting 1 bit, and by t1 for setting 31 bits.
+ */
+ memcpy(t2, P->z, sizeof P->z);
+ for (i = 1; i < 256; i ++) {
+ square_f256(t2, t2);
+ switch (i) {
+ case 31:
+ case 190:
+ case 221:
+ case 252:
+ mul_f256(t2, t2, t1);
+ break;
+ case 63:
+ case 253:
+ case 255:
+ mul_f256(t2, t2, P->z);
+ break;
+ }
+ }
+
+ /*
+ * Now that we have 1/z, multiply x by 1/z^2 and y by 1/z^3.
+ */
+ mul_f256(t1, t2, t2);
+ mul_f256(P->x, t1, P->x);
+ mul_f256(t1, t1, t2);
+ mul_f256(P->y, t1, P->y);
+ reduce_final_f256(P->x);
+ reduce_final_f256(P->y);
+
+ /*
+ * Multiply z by 1/z. If z = 0, then this will yield 0, otherwise
+ * this will set z to 1.
+ */
+ mul_f256(P->z, P->z, t2);
+ reduce_final_f256(P->z);
+}
+
+/*
+ * Double a point in P-256. This function works for all valid points,
+ * including the point at infinity.
+ */
+static void
+p256_double(p256_jacobian *Q)
+{
+ /*
+ * 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
+ *
+ * These formulas work for all points, including points of order 2
+ * and points at infinity:
+ * - If y = 0 then z' = 0. But there is no such point in P-256
+ * anyway.
+ * - If z = 0 then z' = 0.
+ */
+ uint32_t t1[9], t2[9], t3[9], t4[9];
+
+ /*
+ * Compute z^2 in t1.
+ */
+ square_f256(t1, Q->z);
+
+ /*
+ * Compute x-z^2 in t2 and x+z^2 in t1.
+ */
+ add_f256(t2, Q->x, t1);
+ sub_f256(t1, Q->x, t1);
+
+ /*
+ * Compute 3*(x+z^2)*(x-z^2) in t1.
+ */
+ mul_f256(t3, t1, t2);
+ add_f256(t1, t3, t3);
+ add_f256(t1, t3, t1);
+
+ /*
+ * Compute 4*x*y^2 (in t2) and 2*y^2 (in t3).
+ */
+ square_f256(t3, Q->y);
+ add_f256(t3, t3, t3);
+ mul_f256(t2, Q->x, t3);
+ add_f256(t2, t2, t2);
+
+ /*
+ * Compute x' = m^2 - 2*s.
+ */
+ square_f256(Q->x, t1);
+ sub_f256(Q->x, Q->x, t2);
+ sub_f256(Q->x, Q->x, t2);
+
+ /*
+ * Compute z' = 2*y*z.
+ */
+ mul_f256(t4, Q->y, Q->z);
+ add_f256(Q->z, t4, t4);
+
+ /*
+ * Compute y' = m*(s - x') - 8*y^4. Note that we already have
+ * 2*y^2 in t3.
+ */
+ sub_f256(t2, t2, Q->x);
+ mul_f256(Q->y, t1, t2);
+ square_f256(t4, t3);
+ add_f256(t4, t4, t4);
+ sub_f256(Q->y, Q->y, t4);
+}
+
+/*
+ * Add point P2 to point P1.
+ *
+ * This function computes the wrong result in the following cases:
+ *
+ * - If P1 == 0 but P2 != 0
+ * - If P1 != 0 but P2 == 0
+ * - If P1 == P2
+ *
+ * In all three cases, P1 is set to the point at infinity.
+ *
+ * Returned value is 0 if one of the following occurs:
+ *
+ * - P1 and P2 have the same Y coordinate
+ * - P1 == 0 and P2 == 0
+ * - The Y coordinate of one of the points is 0 and the other point is
+ * the point at infinity.
+ *
+ * The third case cannot actually happen with valid points, since a point
+ * with Y == 0 is a point of order 2, and there is no point of order 2 on
+ * curve P-256.
+ *
+ * Therefore, assuming that P1 != 0 and P2 != 0 on input, then the caller
+ * can apply the following:
+ *
+ * - If the result is not the point at infinity, then it is correct.
+ * - Otherwise, if the returned value is 1, then this is a case of
+ * P1+P2 == 0, so the result is indeed the point at infinity.
+ * - Otherwise, P1 == P2, so a "double" operation should have been
+ * performed.
+ */
+static uint32_t
+p256_add(p256_jacobian *P1, const p256_jacobian *P2)
+{
+ /*
+ * 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
+ */
+ uint32_t t1[9], t2[9], t3[9], t4[9], t5[9], t6[9], t7[9];
+ uint32_t ret;
+ int i;
+
+ /*
+ * Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3).
+ */
+ square_f256(t3, P2->z);
+ mul_f256(t1, P1->x, t3);
+ mul_f256(t4, P2->z, t3);
+ mul_f256(t3, P1->y, t4);
+
+ /*
+ * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
+ */
+ square_f256(t4, P1->z);
+ mul_f256(t2, P2->x, t4);
+ mul_f256(t5, P1->z, t4);
+ mul_f256(t4, P2->y, t5);
+
+ /*
+ * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4).
+ * We need to test whether r is zero, so we will do some extra
+ * reduce.
+ */
+ sub_f256(t2, t2, t1);
+ sub_f256(t4, t4, t3);
+ reduce_final_f256(t4);
+ ret = 0;
+ for (i = 0; i < 9; i ++) {
+ ret |= t4[i];
+ }
+ ret = (ret | -ret) >> 31;
+
+ /*
+ * Compute u1*h^2 (in t6) and h^3 (in t5);
+ */
+ square_f256(t7, t2);
+ mul_f256(t6, t1, t7);
+ mul_f256(t5, t7, t2);
+
+ /*
+ * Compute x3 = r^2 - h^3 - 2*u1*h^2.
+ */
+ square_f256(P1->x, t4);
+ sub_f256(P1->x, P1->x, t5);
+ sub_f256(P1->x, P1->x, t6);
+ sub_f256(P1->x, P1->x, t6);
+
+ /*
+ * Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
+ */
+ sub_f256(t6, t6, P1->x);
+ mul_f256(P1->y, t4, t6);
+ mul_f256(t1, t5, t3);
+ sub_f256(P1->y, P1->y, t1);
+
+ /*
+ * Compute z3 = h*z1*z2.
+ */
+ mul_f256(t1, P1->z, P2->z);
+ mul_f256(P1->z, t1, t2);
+
+ return ret;
+}
+
+/*
+ * Add point P2 to point P1. This is a specialised function for the
+ * case when P2 is a non-zero point in affine coordinate.
+ *
+ * This function computes the wrong result in the following cases:
+ *
+ * - If P1 == 0
+ * - If P1 == P2
+ *
+ * In both cases, P1 is set to the point at infinity.
+ *
+ * Returned value is 0 if one of the following occurs:
+ *
+ * - P1 and P2 have the same Y coordinate
+ * - The Y coordinate of P2 is 0 and P1 is the point at infinity.
+ *
+ * The second case cannot actually happen with valid points, since a point
+ * with Y == 0 is a point of order 2, and there is no point of order 2 on
+ * curve P-256.
+ *
+ * Therefore, assuming that P1 != 0 on input, then the caller
+ * can apply the following:
+ *
+ * - If the result is not the point at infinity, then it is correct.
+ * - Otherwise, if the returned value is 1, then this is a case of
+ * P1+P2 == 0, so the result is indeed the point at infinity.
+ * - Otherwise, P1 == P2, so a "double" operation should have been
+ * performed.
+ */
+static uint32_t
+p256_add_mixed(p256_jacobian *P1, const p256_jacobian *P2)
+{
+ /*
+ * Addtions formulas are:
+ *
+ * u1 = x1
+ * u2 = x2 * z1^2
+ * s1 = y1
+ * 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
+ */
+ uint32_t t1[9], t2[9], t3[9], t4[9], t5[9], t6[9], t7[9];
+ uint32_t ret;
+ int i;
+
+ /*
+ * Compute u1 = x1 (in t1) and s1 = y1 (in t3).
+ */
+ memcpy(t1, P1->x, sizeof t1);
+ memcpy(t3, P1->y, sizeof t3);
+
+ /*
+ * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
+ */
+ square_f256(t4, P1->z);
+ mul_f256(t2, P2->x, t4);
+ mul_f256(t5, P1->z, t4);
+ mul_f256(t4, P2->y, t5);
+
+ /*
+ * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4).
+ * We need to test whether r is zero, so we will do some extra
+ * reduce.
+ */
+ sub_f256(t2, t2, t1);
+ sub_f256(t4, t4, t3);
+ reduce_final_f256(t4);
+ ret = 0;
+ for (i = 0; i < 9; i ++) {
+ ret |= t4[i];
+ }
+ ret = (ret | -ret) >> 31;
+
+ /*
+ * Compute u1*h^2 (in t6) and h^3 (in t5);
+ */
+ square_f256(t7, t2);
+ mul_f256(t6, t1, t7);
+ mul_f256(t5, t7, t2);
+
+ /*
+ * Compute x3 = r^2 - h^3 - 2*u1*h^2.
+ */
+ square_f256(P1->x, t4);
+ sub_f256(P1->x, P1->x, t5);
+ sub_f256(P1->x, P1->x, t6);
+ sub_f256(P1->x, P1->x, t6);
+
+ /*
+ * Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
+ */
+ sub_f256(t6, t6, P1->x);
+ mul_f256(P1->y, t4, t6);
+ mul_f256(t1, t5, t3);
+ sub_f256(P1->y, P1->y, t1);
+
+ /*
+ * Compute z3 = h*z1*z2.
+ */
+ mul_f256(P1->z, P1->z, t2);
+
+ return ret;
+}
+
+/*
+ * Decode a P-256 point. This function does not support the point at
+ * infinity. Returned value is 0 if the point is invalid, 1 otherwise.
+ */
+static uint32_t
+p256_decode(p256_jacobian *P, const void *src, size_t len)
+{
+ const unsigned char *buf;
+ uint32_t tx[9], ty[9], t1[9], t2[9];
+ uint32_t bad;
+ int i;
+
+ if (len != 65) {
+ return 0;
+ }
+ buf = src;
+
+ /*
+ * First byte must be 0x04 (uncompressed format). We could support
+ * "hybrid format" (first byte is 0x06 or 0x07, and encodes the
+ * least significant bit of the Y coordinate), but it is explicitly
+ * forbidden by RFC 5480 (section 2.2).
+ */
+ bad = NEQ(buf[0], 0x04);
+
+ /*
+ * Decode the coordinates, and check that they are both lower
+ * than the modulus.
+ */
+ tx[8] = be8_to_le30(tx, buf + 1, 32);
+ ty[8] = be8_to_le30(ty, buf + 33, 32);
+ bad |= reduce_final_f256(tx);
+ bad |= reduce_final_f256(ty);
+
+ /*
+ * Check curve equation.
+ */
+ square_f256(t1, tx);
+ mul_f256(t1, tx, t1);
+ square_f256(t2, ty);
+ sub_f256(t1, t1, tx);
+ sub_f256(t1, t1, tx);
+ sub_f256(t1, t1, tx);
+ add_f256(t1, t1, P256_B);
+ sub_f256(t1, t1, t2);
+ reduce_final_f256(t1);
+ for (i = 0; i < 9; i ++) {
+ bad |= t1[i];
+ }
+
+ /*
+ * Copy coordinates to the point structure.
+ */
+ memcpy(P->x, tx, sizeof tx);
+ memcpy(P->y, ty, sizeof ty);
+ memset(P->z, 0, sizeof P->z);
+ P->z[0] = 1;
+ return EQ(bad, 0);
+}
+
+/*
+ * Encode a point into a buffer. This function assumes that the point is
+ * valid, in affine coordinates, and not the point at infinity.
+ */
+static void
+p256_encode(void *dst, const p256_jacobian *P)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ buf[0] = 0x04;
+ le30_to_be8(buf + 1, 32, P->x);
+ le30_to_be8(buf + 33, 32, P->y);
+}
+
+/*
+ * Multiply a curve point by an integer. The integer is assumed to be
+ * lower than the curve order, and the base point must not be the point
+ * at infinity.
+ */
+static void
+p256_mul(p256_jacobian *P, const unsigned char *x, size_t xlen)
+{
+ /*
+ * qz is a flag that is initially 1, and remains equal to 1
+ * as long as the point is the point at infinity.
+ *
+ * We use a 2-bit window to handle multiplier bits by pairs.
+ * The precomputed window really is the points P2 and P3.
+ */
+ uint32_t qz;
+ p256_jacobian P2, P3, Q, T, U;
+
+ /*
+ * Compute window values.
+ */
+ P2 = *P;
+ p256_double(&P2);
+ P3 = *P;
+ p256_add(&P3, &P2);
+
+ /*
+ * We start with Q = 0. We process multiplier bits 2 by 2.
+ */
+ memset(&Q, 0, sizeof Q);
+ qz = 1;
+ while (xlen -- > 0) {
+ int k;
+
+ for (k = 6; k >= 0; k -= 2) {
+ uint32_t bits;
+ uint32_t bnz;
+
+ p256_double(&Q);
+ p256_double(&Q);
+ T = *P;
+ U = Q;
+ 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);
+ p256_add(&U, &T);
+ CCOPY(bnz & qz, &Q, &T, sizeof Q);
+ CCOPY(bnz & ~qz, &Q, &U, sizeof Q);
+ qz &= ~bnz;
+ }
+ x ++;
+ }
+ *P = Q;
+}
+
+/*
+ * Precomputed window: k*G points, where G is the curve generator, and k
+ * is an integer from 1 to 15 (inclusive). The X and Y coordinates of
+ * the point are encoded as 9 words of 30 bits each (little-endian
+ * order).
+ */
+static const uint32_t Gwin[15][18] = {
+
+ { 0x1898C296, 0x1284E517, 0x1EB33A0F, 0x00DF604B,
+ 0x2440F277, 0x339B958E, 0x04247F8B, 0x347CB84B,
+ 0x00006B17, 0x37BF51F5, 0x2ED901A0, 0x3315ECEC,
+ 0x338CD5DA, 0x0F9E162B, 0x1FAD29F0, 0x27F9B8EE,
+ 0x10B8BF86, 0x00004FE3 },
+
+ { 0x07669978, 0x182D23F1, 0x3F21B35A, 0x225A789D,
+ 0x351AC3C0, 0x08E00C12, 0x34F7E8A5, 0x1EC62340,
+ 0x00007CF2, 0x227873D1, 0x3812DE74, 0x0E982299,
+ 0x1F6B798F, 0x3430DBBA, 0x366B1A7D, 0x2D040293,
+ 0x154436E3, 0x00000777 },
+
+ { 0x06E7FD6C, 0x2D05986F, 0x3ADA985F, 0x31ADC87B,
+ 0x0BF165E6, 0x1FBE5475, 0x30A44C8F, 0x3934698C,
+ 0x00005ECB, 0x227D5032, 0x29E6C49E, 0x04FB83D9,
+ 0x0AAC0D8E, 0x24A2ECD8, 0x2C1B3869, 0x0FF7E374,
+ 0x19031266, 0x00008734 },
+
+ { 0x2B030852, 0x024C0911, 0x05596EF5, 0x07F8B6DE,
+ 0x262BD003, 0x3779967B, 0x08FBBA02, 0x128D4CB4,
+ 0x0000E253, 0x184ED8C6, 0x310B08FC, 0x30EE0055,
+ 0x3F25B0FC, 0x062D764E, 0x3FB97F6A, 0x33CC719D,
+ 0x15D69318, 0x0000E0F1 },
+
+ { 0x03D033ED, 0x05552837, 0x35BE5242, 0x2320BF47,
+ 0x268FDFEF, 0x13215821, 0x140D2D78, 0x02DE9454,
+ 0x00005159, 0x3DA16DA4, 0x0742ED13, 0x0D80888D,
+ 0x004BC035, 0x0A79260D, 0x06FCDAFE, 0x2727D8AE,
+ 0x1F6A2412, 0x0000E0C1 },
+
+ { 0x3C2291A9, 0x1AC2ABA4, 0x3B215B4C, 0x131D037A,
+ 0x17DDE302, 0x0C90B2E2, 0x0602C92D, 0x05CA9DA9,
+ 0x0000B01A, 0x0FC77FE2, 0x35F1214E, 0x07E16BDF,
+ 0x003DDC07, 0x2703791C, 0x3038B7EE, 0x3DAD56FE,
+ 0x041D0C8D, 0x0000E85C },
+
+ { 0x3187B2A3, 0x0018A1C0, 0x00FEF5B3, 0x3E7E2E2A,
+ 0x01FB607E, 0x2CC199F0, 0x37B4625B, 0x0EDBE82F,
+ 0x00008E53, 0x01F400B4, 0x15786A1B, 0x3041B21C,
+ 0x31CD8CF2, 0x35900053, 0x1A7E0E9B, 0x318366D0,
+ 0x076F780C, 0x000073EB },
+
+ { 0x1B6FB393, 0x13767707, 0x3CE97DBB, 0x348E2603,
+ 0x354CADC1, 0x09D0B4EA, 0x1B053404, 0x1DE76FBA,
+ 0x000062D9, 0x0F09957E, 0x295029A8, 0x3E76A78D,
+ 0x3B547DAE, 0x27CEE0A2, 0x0575DC45, 0x1D8244FF,
+ 0x332F647A, 0x0000AD5A },
+
+ { 0x10949EE0, 0x1E7A292E, 0x06DF8B3D, 0x02B2E30B,
+ 0x31F8729E, 0x24E35475, 0x30B71878, 0x35EDBFB7,
+ 0x0000EA68, 0x0DD048FA, 0x21688929, 0x0DE823FE,
+ 0x1C53FAA9, 0x0EA0C84D, 0x052A592A, 0x1FCE7870,
+ 0x11325CB2, 0x00002A27 },
+
+ { 0x04C5723F, 0x30D81A50, 0x048306E4, 0x329B11C7,
+ 0x223FB545, 0x085347A8, 0x2993E591, 0x1B5ACA8E,
+ 0x0000CEF6, 0x04AF0773, 0x28D2EEA9, 0x2751EEEC,
+ 0x037B4A7F, 0x3B4C1059, 0x08F37674, 0x2AE906E1,
+ 0x18A88A6A, 0x00008786 },
+
+ { 0x34BC21D1, 0x0CCE474D, 0x15048BF4, 0x1D0BB409,
+ 0x021CDA16, 0x20DE76C3, 0x34C59063, 0x04EDE20E,
+ 0x00003ED1, 0x282A3740, 0x0BE3BBF3, 0x29889DAE,
+ 0x03413697, 0x34C68A09, 0x210EBE93, 0x0C8A224C,
+ 0x0826B331, 0x00009099 },
+
+ { 0x0624E3C4, 0x140317BA, 0x2F82C99D, 0x260C0A2C,
+ 0x25D55179, 0x194DCC83, 0x3D95E462, 0x356F6A05,
+ 0x0000741D, 0x0D4481D3, 0x2657FC8B, 0x1BA5CA71,
+ 0x3AE44B0D, 0x07B1548E, 0x0E0D5522, 0x05FDC567,
+ 0x2D1AA70E, 0x00000770 },
+
+ { 0x06072C01, 0x23857675, 0x1EAD58A9, 0x0B8A12D9,
+ 0x1EE2FC79, 0x0177CB61, 0x0495A618, 0x20DEB82B,
+ 0x0000177C, 0x2FC7BFD8, 0x310EEF8B, 0x1FB4DF39,
+ 0x3B8530E8, 0x0F4E7226, 0x0246B6D0, 0x2A558A24,
+ 0x163353AF, 0x000063BB },
+
+ { 0x24D2920B, 0x1C249DCC, 0x2069C5E5, 0x09AB2F9E,
+ 0x36DF3CF1, 0x1991FD0C, 0x062B97A7, 0x1E80070E,
+ 0x000054E7, 0x20D0B375, 0x2E9F20BD, 0x35090081,
+ 0x1C7A9DDC, 0x22E7C371, 0x087E3016, 0x03175421,
+ 0x3C6ECA7D, 0x0000F599 },
+
+ { 0x259B9D5F, 0x0D9A318F, 0x23A0EF16, 0x00EBE4B7,
+ 0x088265AE, 0x2CDE2666, 0x2BAE7ADF, 0x1371A5C6,
+ 0x0000F045, 0x0D034F36, 0x1F967378, 0x1B5FA3F4,
+ 0x0EC8739D, 0x1643E62A, 0x1653947E, 0x22D1F4E6,
+ 0x0FB8D64B, 0x0000B5B9 }
+};
+
+/*
+ * Lookup one of the Gwin[] values, by index. This is constant-time.
+ */
+static void
+lookup_Gwin(p256_jacobian *T, uint32_t idx)
+{
+ uint32_t xy[18];
+ uint32_t k;
+ size_t u;
+
+ memset(xy, 0, sizeof xy);
+ for (k = 0; k < 15; k ++) {
+ uint32_t m;
+
+ m = -EQ(idx, k + 1);
+ for (u = 0; u < 18; u ++) {
+ xy[u] |= m & Gwin[k][u];
+ }
+ }
+ memcpy(T->x, &xy[0], sizeof T->x);
+ memcpy(T->y, &xy[9], sizeof T->y);
+ memset(T->z, 0, sizeof T->z);
+ T->z[0] = 1;
+}
+
+/*
+ * Multiply the generator by an integer. The integer is assumed non-zero
+ * and lower than the curve order.
+ */
+static void
+p256_mulgen(p256_jacobian *P, const unsigned char *x, size_t xlen)
+{
+ /*
+ * qz is a flag that is initially 1, and remains equal to 1
+ * as long as the point is the point at infinity.
+ *
+ * We use a 4-bit window to handle multiplier bits by groups
+ * of 4. The precomputed window is constant static data, with
+ * points in affine coordinates; we use a constant-time lookup.
+ */
+ p256_jacobian Q;
+ uint32_t qz;
+
+ memset(&Q, 0, sizeof Q);
+ qz = 1;
+ while (xlen -- > 0) {
+ int k;
+ unsigned bx;
+
+ bx = *x ++;
+ for (k = 0; k < 2; k ++) {
+ uint32_t bits;
+ uint32_t bnz;
+ p256_jacobian T, U;
+
+ p256_double(&Q);
+ p256_double(&Q);
+ p256_double(&Q);
+ p256_double(&Q);
+ bits = (bx >> 4) & 0x0F;
+ bnz = NEQ(bits, 0);
+ lookup_Gwin(&T, bits);
+ U = Q;
+ p256_add_mixed(&U, &T);
+ CCOPY(bnz & qz, &Q, &T, sizeof Q);
+ CCOPY(bnz & ~qz, &Q, &U, sizeof Q);
+ qz &= ~bnz;
+ bx <<= 4;
+ }
+ }
+ *P = Q;
+}
+
+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
+};
+
+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 *
+api_generator(int curve, size_t *len)
+{
+ (void)curve;
+ *len = sizeof P256_G;
+ return P256_G;
+}
+
+static const unsigned char *
+api_order(int curve, size_t *len)
+{
+ (void)curve;
+ *len = sizeof P256_N;
+ return P256_N;
+}
+
+static size_t
+api_xoff(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return 1;
+}
+
+static uint32_t
+api_mul(unsigned char *G, size_t Glen,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ uint32_t r;
+ p256_jacobian P;
+
+ (void)curve;
+ r = p256_decode(&P, G, Glen);
+ p256_mul(&P, x, xlen);
+ if (Glen >= 65) {
+ p256_to_affine(&P);
+ p256_encode(G, &P);
+ }
+ return r;
+}
+
+static size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ p256_jacobian P;
+
+ (void)curve;
+ p256_mulgen(&P, x, xlen);
+ p256_to_affine(&P);
+ p256_encode(R, &P);
+ return 65;
+
+ /*
+ const unsigned char *G;
+ size_t Glen;
+
+ G = api_generator(curve, &Glen);
+ memcpy(R, G, Glen);
+ api_mul(R, Glen, x, xlen, curve);
+ return Glen;
+ */
+}
+
+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)
+{
+ p256_jacobian P, Q;
+ uint32_t r, t, z;
+ int i;
+
+ (void)curve;
+ r = p256_decode(&P, A, len);
+ p256_mul(&P, x, xlen);
+ if (B == NULL) {
+ p256_mulgen(&Q, y, ylen);
+ } else {
+ r &= p256_decode(&Q, B, len);
+ p256_mul(&Q, y, ylen);
+ }
+
+ /*
+ * The final addition may fail in case both points are equal.
+ */
+ t = p256_add(&P, &Q);
+ reduce_final_f256(P.z);
+ z = 0;
+ for (i = 0; i < 9; i ++) {
+ z |= P.z[i];
+ }
+ z = EQ(z, 0);
+ p256_double(&Q);
+
+ /*
+ * 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);
+ p256_to_affine(&P);
+ p256_encode(A, &P);
+ r &= ~(z & t);
+ return r;
+}
+
+/* see bearssl_ec.h */
+const br_ec_impl br_ec_p256_m31 = {
+ (uint32_t)0x00800000,
+ &api_generator,
+ &api_order,
+ &api_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
diff --git a/contrib/bearssl/src/ec/ec_p256_m62.c b/contrib/bearssl/src/ec/ec_p256_m62.c
new file mode 100644
index 000000000000..3bcb95b5b19b
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_p256_m62.c
@@ -0,0 +1,1765 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#if BR_INT128 || BR_UMUL128
+
+#if BR_UMUL128
+#include <intrin.h>
+#endif
+
+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
+};
+
+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 *
+api_generator(int curve, size_t *len)
+{
+ (void)curve;
+ *len = sizeof P256_G;
+ return P256_G;
+}
+
+static const unsigned char *
+api_order(int curve, size_t *len)
+{
+ (void)curve;
+ *len = sizeof P256_N;
+ return P256_N;
+}
+
+static size_t
+api_xoff(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return 1;
+}
+
+/*
+ * A field element is encoded as five 64-bit integers, in basis 2^52.
+ * Limbs may occasionally exceed 2^52.
+ *
+ * A _partially reduced_ value is such that the following hold:
+ * - top limb is less than 2^48 + 2^30
+ * - the other limbs fit on 53 bits each
+ * In particular, such a value is less than twice the modulus p.
+ */
+
+#define BIT(n) ((uint64_t)1 << (n))
+#define MASK48 (BIT(48) - BIT(0))
+#define MASK52 (BIT(52) - BIT(0))
+
+/* R = 2^260 mod p */
+static const uint64_t F256_R[] = {
+ 0x0000000000010, 0xF000000000000, 0xFFFFFFFFFFFFF,
+ 0xFFEFFFFFFFFFF, 0x00000000FFFFF
+};
+
+/* Curve equation is y^2 = x^3 - 3*x + B. This constant is B*R mod p
+ (Montgomery representation of B). */
+static const uint64_t P256_B_MONTY[] = {
+ 0xDF6229C4BDDFD, 0xCA8843090D89C, 0x212ED6ACF005C,
+ 0x83415A220ABF7, 0x0C30061DD4874
+};
+
+/*
+ * Addition in the field. Carry propagation is not performed.
+ * On input, limbs may be up to 63 bits each; on output, they will
+ * be up to one bit more than on input.
+ */
+static inline void
+f256_add(uint64_t *d, const uint64_t *a, const uint64_t *b)
+{
+ d[0] = a[0] + b[0];
+ d[1] = a[1] + b[1];
+ d[2] = a[2] + b[2];
+ d[3] = a[3] + b[3];
+ d[4] = a[4] + b[4];
+}
+
+/*
+ * Partially reduce the provided value.
+ * Input: limbs can go up to 61 bits each.
+ * Output: partially reduced.
+ */
+static inline void
+f256_partial_reduce(uint64_t *a)
+{
+ uint64_t w, cc, s;
+
+ /*
+ * Propagate carries.
+ */
+ w = a[0];
+ a[0] = w & MASK52;
+ cc = w >> 52;
+ w = a[1] + cc;
+ a[1] = w & MASK52;
+ cc = w >> 52;
+ w = a[2] + cc;
+ a[2] = w & MASK52;
+ cc = w >> 52;
+ w = a[3] + cc;
+ a[3] = w & MASK52;
+ cc = w >> 52;
+ a[4] += cc;
+
+ s = a[4] >> 48; /* s < 2^14 */
+ a[0] += s; /* a[0] < 2^52 + 2^14 */
+ w = a[1] - (s << 44);
+ a[1] = w & MASK52; /* a[1] < 2^52 */
+ cc = -(w >> 52) & 0xFFF; /* cc < 16 */
+ w = a[2] - cc;
+ a[2] = w & MASK52; /* a[2] < 2^52 */
+ cc = w >> 63; /* cc = 0 or 1 */
+ w = a[3] - cc - (s << 36);
+ a[3] = w & MASK52; /* a[3] < 2^52 */
+ cc = w >> 63; /* cc = 0 or 1 */
+ w = a[4] & MASK48;
+ a[4] = w + (s << 16) - cc; /* a[4] < 2^48 + 2^30 */
+}
+
+/*
+ * Subtraction in the field.
+ * Input: limbs must fit on 60 bits each; in particular, the complete
+ * integer will be less than 2^268 + 2^217.
+ * Output: partially reduced.
+ */
+static inline void
+f256_sub(uint64_t *d, const uint64_t *a, const uint64_t *b)
+{
+ uint64_t t[5], w, s, cc;
+
+ /*
+ * We compute d = 2^13*p + a - b; this ensures a positive
+ * intermediate value.
+ *
+ * Each individual addition/subtraction may yield a positive or
+ * negative result; thus, we need to handle a signed carry, thus
+ * with sign extension. We prefer not to use signed types (int64_t)
+ * because conversion from unsigned to signed is cumbersome (a
+ * direct cast with the top bit set is undefined behavior; instead,
+ * we have to use pointer aliasing, using the guaranteed properties
+ * of exact-width types, but this requires the compiler to optimize
+ * away the writes and reads from RAM), and right-shifting a
+ * signed negative value is implementation-defined. Therefore,
+ * we use a custom sign extension.
+ */
+
+ w = a[0] - b[0] - BIT(13);
+ t[0] = w & MASK52;
+ cc = w >> 52;
+ cc |= -(cc & BIT(11));
+ w = a[1] - b[1] + cc;
+ t[1] = w & MASK52;
+ cc = w >> 52;
+ cc |= -(cc & BIT(11));
+ w = a[2] - b[2] + cc;
+ t[2] = (w & MASK52) + BIT(5);
+ cc = w >> 52;
+ cc |= -(cc & BIT(11));
+ w = a[3] - b[3] + cc;
+ t[3] = (w & MASK52) + BIT(49);
+ cc = w >> 52;
+ cc |= -(cc & BIT(11));
+ t[4] = (BIT(61) - BIT(29)) + a[4] - b[4] + cc;
+
+ /*
+ * Perform partial reduction. Rule is:
+ * 2^256 = 2^224 - 2^192 - 2^96 + 1 mod p
+ *
+ * At that point:
+ * 0 <= t[0] <= 2^52 - 1
+ * 0 <= t[1] <= 2^52 - 1
+ * 2^5 <= t[2] <= 2^52 + 2^5 - 1
+ * 2^49 <= t[3] <= 2^52 + 2^49 - 1
+ * 2^59 < t[4] <= 2^61 + 2^60 - 2^29
+ *
+ * Thus, the value 's' (t[4] / 2^48) will be necessarily
+ * greater than 2048, and less than 12288.
+ */
+ s = t[4] >> 48;
+
+ d[0] = t[0] + s; /* d[0] <= 2^52 + 12287 */
+ w = t[1] - (s << 44);
+ d[1] = w & MASK52; /* d[1] <= 2^52 - 1 */
+ cc = -(w >> 52) & 0xFFF; /* cc <= 48 */
+ w = t[2] - cc;
+ cc = w >> 63; /* cc = 0 or 1 */
+ d[2] = w + (cc << 52); /* d[2] <= 2^52 + 31 */
+ w = t[3] - cc - (s << 36);
+ cc = w >> 63; /* cc = 0 or 1 */
+ d[3] = w + (cc << 52); /* t[3] <= 2^52 + 2^49 - 1 */
+ d[4] = (t[4] & MASK48) + (s << 16) - cc; /* d[4] < 2^48 + 2^30 */
+
+ /*
+ * If s = 0, then none of the limbs is modified, and there cannot
+ * be an overflow; if s != 0, then (s << 16) > cc, and there is
+ * no overflow either.
+ */
+}
+
+/*
+ * Montgomery multiplication in the field.
+ * Input: limbs must fit on 56 bits each.
+ * Output: partially reduced.
+ */
+static void
+f256_montymul(uint64_t *d, const uint64_t *a, const uint64_t *b)
+{
+#if BR_INT128
+
+ int i;
+ uint64_t t[5];
+
+ t[0] = 0;
+ t[1] = 0;
+ t[2] = 0;
+ t[3] = 0;
+ t[4] = 0;
+ for (i = 0; i < 5; i ++) {
+ uint64_t x, f, cc, w, s;
+ unsigned __int128 z;
+
+ /*
+ * Since limbs of a[] and b[] fit on 56 bits each,
+ * each individual product fits on 112 bits. Also,
+ * the factor f fits on 52 bits, so f<<48 fits on
+ * 112 bits too. This guarantees that carries (cc)
+ * will fit on 62 bits, thus no overflow.
+ *
+ * The operations below compute:
+ * t <- (t + x*b + f*p) / 2^64
+ */
+ x = a[i];
+ z = (unsigned __int128)b[0] * (unsigned __int128)x
+ + (unsigned __int128)t[0];
+ f = (uint64_t)z & MASK52;
+ cc = (uint64_t)(z >> 52);
+ z = (unsigned __int128)b[1] * (unsigned __int128)x
+ + (unsigned __int128)t[1] + cc
+ + ((unsigned __int128)f << 44);
+ t[0] = (uint64_t)z & MASK52;
+ cc = (uint64_t)(z >> 52);
+ z = (unsigned __int128)b[2] * (unsigned __int128)x
+ + (unsigned __int128)t[2] + cc;
+ t[1] = (uint64_t)z & MASK52;
+ cc = (uint64_t)(z >> 52);
+ z = (unsigned __int128)b[3] * (unsigned __int128)x
+ + (unsigned __int128)t[3] + cc
+ + ((unsigned __int128)f << 36);
+ t[2] = (uint64_t)z & MASK52;
+ cc = (uint64_t)(z >> 52);
+ z = (unsigned __int128)b[4] * (unsigned __int128)x
+ + (unsigned __int128)t[4] + cc
+ + ((unsigned __int128)f << 48)
+ - ((unsigned __int128)f << 16);
+ t[3] = (uint64_t)z & MASK52;
+ t[4] = (uint64_t)(z >> 52);
+
+ /*
+ * t[4] may be up to 62 bits here; we need to do a
+ * partial reduction. Note that limbs t[0] to t[3]
+ * fit on 52 bits each.
+ */
+ s = t[4] >> 48; /* s < 2^14 */
+ t[0] += s; /* t[0] < 2^52 + 2^14 */
+ w = t[1] - (s << 44);
+ t[1] = w & MASK52; /* t[1] < 2^52 */
+ cc = -(w >> 52) & 0xFFF; /* cc < 16 */
+ w = t[2] - cc;
+ t[2] = w & MASK52; /* t[2] < 2^52 */
+ cc = w >> 63; /* cc = 0 or 1 */
+ w = t[3] - cc - (s << 36);
+ t[3] = w & MASK52; /* t[3] < 2^52 */
+ cc = w >> 63; /* cc = 0 or 1 */
+ w = t[4] & MASK48;
+ t[4] = w + (s << 16) - cc; /* t[4] < 2^48 + 2^30 */
+
+ /*
+ * The final t[4] cannot overflow because cc is 0 or 1,
+ * and cc can be 1 only if s != 0.
+ */
+ }
+
+ d[0] = t[0];
+ d[1] = t[1];
+ d[2] = t[2];
+ d[3] = t[3];
+ d[4] = t[4];
+
+#elif BR_UMUL128
+
+ int i;
+ uint64_t t[5];
+
+ t[0] = 0;
+ t[1] = 0;
+ t[2] = 0;
+ t[3] = 0;
+ t[4] = 0;
+ for (i = 0; i < 5; i ++) {
+ uint64_t x, f, cc, w, s, zh, zl;
+ unsigned char k;
+
+ /*
+ * Since limbs of a[] and b[] fit on 56 bits each,
+ * each individual product fits on 112 bits. Also,
+ * the factor f fits on 52 bits, so f<<48 fits on
+ * 112 bits too. This guarantees that carries (cc)
+ * will fit on 62 bits, thus no overflow.
+ *
+ * The operations below compute:
+ * t <- (t + x*b + f*p) / 2^64
+ */
+ x = a[i];
+ zl = _umul128(b[0], x, &zh);
+ k = _addcarry_u64(0, t[0], zl, &zl);
+ (void)_addcarry_u64(k, 0, zh, &zh);
+ f = zl & MASK52;
+ cc = (zl >> 52) | (zh << 12);
+
+ zl = _umul128(b[1], x, &zh);
+ k = _addcarry_u64(0, t[1], zl, &zl);
+ (void)_addcarry_u64(k, 0, zh, &zh);
+ k = _addcarry_u64(0, cc, zl, &zl);
+ (void)_addcarry_u64(k, 0, zh, &zh);
+ k = _addcarry_u64(0, f << 44, zl, &zl);
+ (void)_addcarry_u64(k, f >> 20, zh, &zh);
+ t[0] = zl & MASK52;
+ cc = (zl >> 52) | (zh << 12);
+
+ zl = _umul128(b[2], x, &zh);
+ k = _addcarry_u64(0, t[2], zl, &zl);
+ (void)_addcarry_u64(k, 0, zh, &zh);
+ k = _addcarry_u64(0, cc, zl, &zl);
+ (void)_addcarry_u64(k, 0, zh, &zh);
+ t[1] = zl & MASK52;
+ cc = (zl >> 52) | (zh << 12);
+
+ zl = _umul128(b[3], x, &zh);
+ k = _addcarry_u64(0, t[3], zl, &zl);
+ (void)_addcarry_u64(k, 0, zh, &zh);
+ k = _addcarry_u64(0, cc, zl, &zl);
+ (void)_addcarry_u64(k, 0, zh, &zh);
+ k = _addcarry_u64(0, f << 36, zl, &zl);
+ (void)_addcarry_u64(k, f >> 28, zh, &zh);
+ t[2] = zl & MASK52;
+ cc = (zl >> 52) | (zh << 12);
+
+ zl = _umul128(b[4], x, &zh);
+ k = _addcarry_u64(0, t[4], zl, &zl);
+ (void)_addcarry_u64(k, 0, zh, &zh);
+ k = _addcarry_u64(0, cc, zl, &zl);
+ (void)_addcarry_u64(k, 0, zh, &zh);
+ k = _addcarry_u64(0, f << 48, zl, &zl);
+ (void)_addcarry_u64(k, f >> 16, zh, &zh);
+ k = _subborrow_u64(0, zl, f << 16, &zl);
+ (void)_subborrow_u64(k, zh, f >> 48, &zh);
+ t[3] = zl & MASK52;
+ t[4] = (zl >> 52) | (zh << 12);
+
+ /*
+ * t[4] may be up to 62 bits here; we need to do a
+ * partial reduction. Note that limbs t[0] to t[3]
+ * fit on 52 bits each.
+ */
+ s = t[4] >> 48; /* s < 2^14 */
+ t[0] += s; /* t[0] < 2^52 + 2^14 */
+ w = t[1] - (s << 44);
+ t[1] = w & MASK52; /* t[1] < 2^52 */
+ cc = -(w >> 52) & 0xFFF; /* cc < 16 */
+ w = t[2] - cc;
+ t[2] = w & MASK52; /* t[2] < 2^52 */
+ cc = w >> 63; /* cc = 0 or 1 */
+ w = t[3] - cc - (s << 36);
+ t[3] = w & MASK52; /* t[3] < 2^52 */
+ cc = w >> 63; /* cc = 0 or 1 */
+ w = t[4] & MASK48;
+ t[4] = w + (s << 16) - cc; /* t[4] < 2^48 + 2^30 */
+
+ /*
+ * The final t[4] cannot overflow because cc is 0 or 1,
+ * and cc can be 1 only if s != 0.
+ */
+ }
+
+ d[0] = t[0];
+ d[1] = t[1];
+ d[2] = t[2];
+ d[3] = t[3];
+ d[4] = t[4];
+
+#endif
+}
+
+/*
+ * Montgomery squaring in the field; currently a basic wrapper around
+ * multiplication (inline, should be optimized away).
+ * TODO: see if some extra speed can be gained here.
+ */
+static inline void
+f256_montysquare(uint64_t *d, const uint64_t *a)
+{
+ f256_montymul(d, a, a);
+}
+
+/*
+ * Convert to Montgomery representation.
+ */
+static void
+f256_tomonty(uint64_t *d, const uint64_t *a)
+{
+ /*
+ * R2 = 2^520 mod p.
+ * If R = 2^260 mod p, then R2 = R^2 mod p; and the Montgomery
+ * multiplication of a by R2 is: a*R2/R = a*R mod p, i.e. the
+ * conversion to Montgomery representation.
+ */
+ static const uint64_t R2[] = {
+ 0x0000000000300, 0xFFFFFFFF00000, 0xFFFFEFFFFFFFB,
+ 0xFDFFFFFFFFFFF, 0x0000004FFFFFF
+ };
+
+ f256_montymul(d, a, R2);
+}
+
+/*
+ * Convert from Montgomery representation.
+ */
+static void
+f256_frommonty(uint64_t *d, const uint64_t *a)
+{
+ /*
+ * Montgomery multiplication by 1 is division by 2^260 modulo p.
+ */
+ static const uint64_t one[] = { 1, 0, 0, 0, 0 };
+
+ f256_montymul(d, a, one);
+}
+
+/*
+ * Inversion in the field. If the source value is 0 modulo p, then this
+ * returns 0 or p. This function uses Montgomery representation.
+ */
+static void
+f256_invert(uint64_t *d, const uint64_t *a)
+{
+ /*
+ * We compute a^(p-2) mod p. The exponent pattern (from high to
+ * low) is:
+ * - 32 bits of value 1
+ * - 31 bits of value 0
+ * - 1 bit of value 1
+ * - 96 bits of value 0
+ * - 94 bits of value 1
+ * - 1 bit of value 0
+ * - 1 bit of value 1
+ * To speed up the square-and-multiply algorithm, we precompute
+ * a^(2^31-1).
+ */
+
+ uint64_t r[5], t[5];
+ int i;
+
+ memcpy(t, a, sizeof t);
+ for (i = 0; i < 30; i ++) {
+ f256_montysquare(t, t);
+ f256_montymul(t, t, a);
+ }
+
+ memcpy(r, t, sizeof t);
+ for (i = 224; i >= 0; i --) {
+ f256_montysquare(r, r);
+ switch (i) {
+ case 0:
+ case 2:
+ case 192:
+ case 224:
+ f256_montymul(r, r, a);
+ break;
+ case 3:
+ case 34:
+ case 65:
+ f256_montymul(r, r, t);
+ break;
+ }
+ }
+ memcpy(d, r, sizeof r);
+}
+
+/*
+ * Finalize reduction.
+ * Input value should be partially reduced.
+ * On output, limbs a[0] to a[3] fit on 52 bits each, limb a[4] fits
+ * on 48 bits, and the integer is less than p.
+ */
+static inline void
+f256_final_reduce(uint64_t *a)
+{
+ uint64_t r[5], t[5], w, cc;
+ int i;
+
+ /*
+ * Propagate carries to ensure that limbs 0 to 3 fit on 52 bits.
+ */
+ cc = 0;
+ for (i = 0; i < 5; i ++) {
+ w = a[i] + cc;
+ r[i] = w & MASK52;
+ cc = w >> 52;
+ }
+
+ /*
+ * We compute t = r + (2^256 - p) = r + 2^224 - 2^192 - 2^96 + 1.
+ * If t < 2^256, then r < p, and we return r. Otherwise, we
+ * want to return r - p = t - 2^256.
+ */
+
+ /*
+ * Add 2^224 + 1, and propagate carries to ensure that limbs
+ * t[0] to t[3] fit in 52 bits each.
+ */
+ w = r[0] + 1;
+ t[0] = w & MASK52;
+ cc = w >> 52;
+ w = r[1] + cc;
+ t[1] = w & MASK52;
+ cc = w >> 52;
+ w = r[2] + cc;
+ t[2] = w & MASK52;
+ cc = w >> 52;
+ w = r[3] + cc;
+ t[3] = w & MASK52;
+ cc = w >> 52;
+ t[4] = r[4] + cc + BIT(16);
+
+ /*
+ * Subtract 2^192 + 2^96. Since we just added 2^224 + 1, the
+ * result cannot be negative.
+ */
+ w = t[1] - BIT(44);
+ t[1] = w & MASK52;
+ cc = w >> 63;
+ w = t[2] - cc;
+ t[2] = w & MASK52;
+ cc = w >> 63;
+ w = t[3] - BIT(36);
+ t[3] = w & MASK52;
+ cc = w >> 63;
+ t[4] -= cc;
+
+ /*
+ * If the top limb t[4] fits on 48 bits, then r[] is already
+ * in the proper range. Otherwise, t[] is the value to return
+ * (truncated to 256 bits).
+ */
+ cc = -(t[4] >> 48);
+ t[4] &= MASK48;
+ for (i = 0; i < 5; i ++) {
+ a[i] = r[i] ^ (cc & (r[i] ^ t[i]));
+ }
+}
+
+/*
+ * Points in affine and Jacobian coordinates.
+ *
+ * - In affine coordinates, the point-at-infinity cannot be encoded.
+ * - Jacobian coordinates (X,Y,Z) correspond to affine (X/Z^2,Y/Z^3);
+ * if Z = 0 then this is the point-at-infinity.
+ */
+typedef struct {
+ uint64_t x[5];
+ uint64_t y[5];
+} p256_affine;
+
+typedef struct {
+ uint64_t x[5];
+ uint64_t y[5];
+ uint64_t z[5];
+} p256_jacobian;
+
+/*
+ * Decode a field element (unsigned big endian notation).
+ */
+static void
+f256_decode(uint64_t *a, const unsigned char *buf)
+{
+ uint64_t w0, w1, w2, w3;
+
+ w3 = br_dec64be(buf + 0);
+ w2 = br_dec64be(buf + 8);
+ w1 = br_dec64be(buf + 16);
+ w0 = br_dec64be(buf + 24);
+ a[0] = w0 & MASK52;
+ a[1] = ((w0 >> 52) | (w1 << 12)) & MASK52;
+ a[2] = ((w1 >> 40) | (w2 << 24)) & MASK52;
+ a[3] = ((w2 >> 28) | (w3 << 36)) & MASK52;
+ a[4] = w3 >> 16;
+}
+
+/*
+ * Encode a field element (unsigned big endian notation). The field
+ * element MUST be fully reduced.
+ */
+static void
+f256_encode(unsigned char *buf, const uint64_t *a)
+{
+ uint64_t w0, w1, w2, w3;
+
+ w0 = a[0] | (a[1] << 52);
+ w1 = (a[1] >> 12) | (a[2] << 40);
+ w2 = (a[2] >> 24) | (a[3] << 28);
+ w3 = (a[3] >> 36) | (a[4] << 16);
+ br_enc64be(buf + 0, w3);
+ br_enc64be(buf + 8, w2);
+ br_enc64be(buf + 16, w1);
+ br_enc64be(buf + 24, w0);
+}
+
+/*
+ * Decode a point. The returned point is in Jacobian coordinates, but
+ * with z = 1. If the encoding is invalid, or encodes a point which is
+ * not on the curve, or encodes the point at infinity, then this function
+ * returns 0. Otherwise, 1 is returned.
+ *
+ * The buffer is assumed to have length exactly 65 bytes.
+ */
+static uint32_t
+point_decode(p256_jacobian *P, const unsigned char *buf)
+{
+ uint64_t x[5], y[5], t[5], x3[5], tt;
+ uint32_t r;
+
+ /*
+ * Header byte shall be 0x04.
+ */
+ r = EQ(buf[0], 0x04);
+
+ /*
+ * Decode X and Y coordinates, and convert them into
+ * Montgomery representation.
+ */
+ f256_decode(x, buf + 1);
+ f256_decode(y, buf + 33);
+ f256_tomonty(x, x);
+ f256_tomonty(y, y);
+
+ /*
+ * Verify y^2 = x^3 + A*x + B. In curve P-256, A = -3.
+ * Note that the Montgomery representation of 0 is 0. We must
+ * take care to apply the final reduction to make sure we have
+ * 0 and not p.
+ */
+ f256_montysquare(t, y);
+ f256_montysquare(x3, x);
+ f256_montymul(x3, x3, x);
+ f256_sub(t, t, x3);
+ f256_add(t, t, x);
+ f256_add(t, t, x);
+ f256_add(t, t, x);
+ f256_sub(t, t, P256_B_MONTY);
+ f256_final_reduce(t);
+ tt = t[0] | t[1] | t[2] | t[3] | t[4];
+ r &= EQ((uint32_t)(tt | (tt >> 32)), 0);
+
+ /*
+ * Return the point in Jacobian coordinates (and Montgomery
+ * representation).
+ */
+ memcpy(P->x, x, sizeof x);
+ memcpy(P->y, y, sizeof y);
+ memcpy(P->z, F256_R, sizeof F256_R);
+ return r;
+}
+
+/*
+ * Final conversion for a point:
+ * - The point is converted back to affine coordinates.
+ * - Final reduction is performed.
+ * - The point is encoded into the provided buffer.
+ *
+ * If the point is the point-at-infinity, all operations are performed,
+ * but the buffer contents are indeterminate, and 0 is returned. Otherwise,
+ * the encoded point is written in the buffer, and 1 is returned.
+ */
+static uint32_t
+point_encode(unsigned char *buf, const p256_jacobian *P)
+{
+ uint64_t t1[5], t2[5], z;
+
+ /* Set t1 = 1/z^2 and t2 = 1/z^3. */
+ f256_invert(t2, P->z);
+ f256_montysquare(t1, t2);
+ f256_montymul(t2, t2, t1);
+
+ /* Compute affine coordinates x (in t1) and y (in t2). */
+ f256_montymul(t1, P->x, t1);
+ f256_montymul(t2, P->y, t2);
+
+ /* Convert back from Montgomery representation, and finalize
+ reductions. */
+ f256_frommonty(t1, t1);
+ f256_frommonty(t2, t2);
+ f256_final_reduce(t1);
+ f256_final_reduce(t2);
+
+ /* Encode. */
+ buf[0] = 0x04;
+ f256_encode(buf + 1, t1);
+ f256_encode(buf + 33, t2);
+
+ /* Return success if and only if P->z != 0. */
+ z = P->z[0] | P->z[1] | P->z[2] | P->z[3] | P->z[4];
+ return NEQ((uint32_t)(z | z >> 32), 0);
+}
+
+/*
+ * Point doubling in Jacobian coordinates: point P is doubled.
+ * Note: if the source point is the point-at-infinity, then the result is
+ * still the point-at-infinity, which is correct. Moreover, if the three
+ * coordinates were zero, then they still are zero in the returned value.
+ */
+static void
+p256_double(p256_jacobian *P)
+{
+ /*
+ * 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
+ *
+ * These formulas work for all points, including points of order 2
+ * and points at infinity:
+ * - If y = 0 then z' = 0. But there is no such point in P-256
+ * anyway.
+ * - If z = 0 then z' = 0.
+ */
+ uint64_t t1[5], t2[5], t3[5], t4[5];
+
+ /*
+ * Compute z^2 in t1.
+ */
+ f256_montysquare(t1, P->z);
+
+ /*
+ * Compute x-z^2 in t2 and x+z^2 in t1.
+ */
+ f256_add(t2, P->x, t1);
+ f256_sub(t1, P->x, t1);
+
+ /*
+ * Compute 3*(x+z^2)*(x-z^2) in t1.
+ */
+ f256_montymul(t3, t1, t2);
+ f256_add(t1, t3, t3);
+ f256_add(t1, t3, t1);
+
+ /*
+ * Compute 4*x*y^2 (in t2) and 2*y^2 (in t3).
+ */
+ f256_montysquare(t3, P->y);
+ f256_add(t3, t3, t3);
+ f256_montymul(t2, P->x, t3);
+ f256_add(t2, t2, t2);
+
+ /*
+ * Compute x' = m^2 - 2*s.
+ */
+ f256_montysquare(P->x, t1);
+ f256_sub(P->x, P->x, t2);
+ f256_sub(P->x, P->x, t2);
+
+ /*
+ * Compute z' = 2*y*z.
+ */
+ f256_montymul(t4, P->y, P->z);
+ f256_add(P->z, t4, t4);
+ f256_partial_reduce(P->z);
+
+ /*
+ * Compute y' = m*(s - x') - 8*y^4. Note that we already have
+ * 2*y^2 in t3.
+ */
+ f256_sub(t2, t2, P->x);
+ f256_montymul(P->y, t1, t2);
+ f256_montysquare(t4, t3);
+ f256_add(t4, t4, t4);
+ f256_sub(P->y, P->y, t4);
+}
+
+/*
+ * Point addition (Jacobian coordinates): P1 is replaced with P1+P2.
+ * This function computes the wrong result in the following cases:
+ *
+ * - If P1 == 0 but P2 != 0
+ * - If P1 != 0 but P2 == 0
+ * - If P1 == P2
+ *
+ * In all three cases, P1 is set to the point at infinity.
+ *
+ * Returned value is 0 if one of the following occurs:
+ *
+ * - P1 and P2 have the same Y coordinate.
+ * - P1 == 0 and P2 == 0.
+ * - The Y coordinate of one of the points is 0 and the other point is
+ * the point at infinity.
+ *
+ * The third case cannot actually happen with valid points, since a point
+ * with Y == 0 is a point of order 2, and there is no point of order 2 on
+ * curve P-256.
+ *
+ * Therefore, assuming that P1 != 0 and P2 != 0 on input, then the caller
+ * can apply the following:
+ *
+ * - If the result is not the point at infinity, then it is correct.
+ * - Otherwise, if the returned value is 1, then this is a case of
+ * P1+P2 == 0, so the result is indeed the point at infinity.
+ * - Otherwise, P1 == P2, so a "double" operation should have been
+ * performed.
+ *
+ * Note that you can get a returned value of 0 with a correct result,
+ * e.g. if P1 and P2 have the same Y coordinate, but distinct X coordinates.
+ */
+static uint32_t
+p256_add(p256_jacobian *P1, const p256_jacobian *P2)
+{
+ /*
+ * 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
+ */
+ uint64_t t1[5], t2[5], t3[5], t4[5], t5[5], t6[5], t7[5], tt;
+ uint32_t ret;
+
+ /*
+ * Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3).
+ */
+ f256_montysquare(t3, P2->z);
+ f256_montymul(t1, P1->x, t3);
+ f256_montymul(t4, P2->z, t3);
+ f256_montymul(t3, P1->y, t4);
+
+ /*
+ * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
+ */
+ f256_montysquare(t4, P1->z);
+ f256_montymul(t2, P2->x, t4);
+ f256_montymul(t5, P1->z, t4);
+ f256_montymul(t4, P2->y, t5);
+
+ /*
+ * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4).
+ * We need to test whether r is zero, so we will do some extra
+ * reduce.
+ */
+ f256_sub(t2, t2, t1);
+ f256_sub(t4, t4, t3);
+ f256_final_reduce(t4);
+ tt = t4[0] | t4[1] | t4[2] | t4[3] | t4[4];
+ ret = (uint32_t)(tt | (tt >> 32));
+ ret = (ret | -ret) >> 31;
+
+ /*
+ * Compute u1*h^2 (in t6) and h^3 (in t5);
+ */
+ f256_montysquare(t7, t2);
+ f256_montymul(t6, t1, t7);
+ f256_montymul(t5, t7, t2);
+
+ /*
+ * Compute x3 = r^2 - h^3 - 2*u1*h^2.
+ */
+ f256_montysquare(P1->x, t4);
+ f256_sub(P1->x, P1->x, t5);
+ f256_sub(P1->x, P1->x, t6);
+ f256_sub(P1->x, P1->x, t6);
+
+ /*
+ * Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
+ */
+ f256_sub(t6, t6, P1->x);
+ f256_montymul(P1->y, t4, t6);
+ f256_montymul(t1, t5, t3);
+ f256_sub(P1->y, P1->y, t1);
+
+ /*
+ * Compute z3 = h*z1*z2.
+ */
+ f256_montymul(t1, P1->z, P2->z);
+ f256_montymul(P1->z, t1, t2);
+
+ return ret;
+}
+
+/*
+ * Point addition (mixed coordinates): P1 is replaced with P1+P2.
+ * This is a specialised function for the case when P2 is a non-zero point
+ * in affine coordinates.
+ *
+ * This function computes the wrong result in the following cases:
+ *
+ * - If P1 == 0
+ * - If P1 == P2
+ *
+ * In both cases, P1 is set to the point at infinity.
+ *
+ * Returned value is 0 if one of the following occurs:
+ *
+ * - P1 and P2 have the same Y (affine) coordinate.
+ * - The Y coordinate of P2 is 0 and P1 is the point at infinity.
+ *
+ * The second case cannot actually happen with valid points, since a point
+ * with Y == 0 is a point of order 2, and there is no point of order 2 on
+ * curve P-256.
+ *
+ * Therefore, assuming that P1 != 0 on input, then the caller
+ * can apply the following:
+ *
+ * - If the result is not the point at infinity, then it is correct.
+ * - Otherwise, if the returned value is 1, then this is a case of
+ * P1+P2 == 0, so the result is indeed the point at infinity.
+ * - Otherwise, P1 == P2, so a "double" operation should have been
+ * performed.
+ *
+ * Again, a value of 0 may be returned in some cases where the addition
+ * result is correct.
+ */
+static uint32_t
+p256_add_mixed(p256_jacobian *P1, const p256_affine *P2)
+{
+ /*
+ * Addtions formulas are:
+ *
+ * u1 = x1
+ * u2 = x2 * z1^2
+ * s1 = y1
+ * 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
+ */
+ uint64_t t1[5], t2[5], t3[5], t4[5], t5[5], t6[5], t7[5], tt;
+ uint32_t ret;
+
+ /*
+ * Compute u1 = x1 (in t1) and s1 = y1 (in t3).
+ */
+ memcpy(t1, P1->x, sizeof t1);
+ memcpy(t3, P1->y, sizeof t3);
+
+ /*
+ * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
+ */
+ f256_montysquare(t4, P1->z);
+ f256_montymul(t2, P2->x, t4);
+ f256_montymul(t5, P1->z, t4);
+ f256_montymul(t4, P2->y, t5);
+
+ /*
+ * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4).
+ * We need to test whether r is zero, so we will do some extra
+ * reduce.
+ */
+ f256_sub(t2, t2, t1);
+ f256_sub(t4, t4, t3);
+ f256_final_reduce(t4);
+ tt = t4[0] | t4[1] | t4[2] | t4[3] | t4[4];
+ ret = (uint32_t)(tt | (tt >> 32));
+ ret = (ret | -ret) >> 31;
+
+ /*
+ * Compute u1*h^2 (in t6) and h^3 (in t5);
+ */
+ f256_montysquare(t7, t2);
+ f256_montymul(t6, t1, t7);
+ f256_montymul(t5, t7, t2);
+
+ /*
+ * Compute x3 = r^2 - h^3 - 2*u1*h^2.
+ */
+ f256_montysquare(P1->x, t4);
+ f256_sub(P1->x, P1->x, t5);
+ f256_sub(P1->x, P1->x, t6);
+ f256_sub(P1->x, P1->x, t6);
+
+ /*
+ * Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
+ */
+ f256_sub(t6, t6, P1->x);
+ f256_montymul(P1->y, t4, t6);
+ f256_montymul(t1, t5, t3);
+ f256_sub(P1->y, P1->y, t1);
+
+ /*
+ * Compute z3 = h*z1*z2.
+ */
+ f256_montymul(P1->z, P1->z, t2);
+
+ return ret;
+}
+
+#if 0
+/* unused */
+/*
+ * Point addition (mixed coordinates, complete): P1 is replaced with P1+P2.
+ * This is a specialised function for the case when P2 is a non-zero point
+ * in affine coordinates.
+ *
+ * This function returns the correct result in all cases.
+ */
+static uint32_t
+p256_add_complete_mixed(p256_jacobian *P1, const p256_affine *P2)
+{
+ /*
+ * Addtions formulas, in the general case, are:
+ *
+ * u1 = x1
+ * u2 = x2 * z1^2
+ * s1 = y1
+ * 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
+ *
+ * These formulas mishandle the two following cases:
+ *
+ * - If P1 is the point-at-infinity (z1 = 0), then z3 is
+ * incorrectly set to 0.
+ *
+ * - If P1 = P2, then u1 = u2 and s1 = s2, and x3, y3 and z3
+ * are all set to 0.
+ *
+ * However, if P1 + P2 = 0, then u1 = u2 but s1 != s2, and then
+ * we correctly get z3 = 0 (the point-at-infinity).
+ *
+ * To fix the case P1 = 0, we perform at the end a copy of P2
+ * over P1, conditional to z1 = 0.
+ *
+ * For P1 = P2: in that case, both h and r are set to 0, and
+ * we get x3, y3 and z3 equal to 0. We can test for that
+ * occurrence to make a mask which will be all-one if P1 = P2,
+ * or all-zero otherwise; then we can compute the double of P2
+ * and add it, combined with the mask, to (x3,y3,z3).
+ *
+ * Using the doubling formulas in p256_double() on (x2,y2),
+ * simplifying since P2 is affine (i.e. z2 = 1, implicitly),
+ * we get:
+ * s = 4*x2*y2^2
+ * m = 3*(x2 + 1)*(x2 - 1)
+ * x' = m^2 - 2*s
+ * y' = m*(s - x') - 8*y2^4
+ * z' = 2*y2
+ * which requires only 6 multiplications. Added to the 11
+ * multiplications of the normal mixed addition in Jacobian
+ * coordinates, we get a cost of 17 multiplications in total.
+ */
+ uint64_t t1[5], t2[5], t3[5], t4[5], t5[5], t6[5], t7[5], tt, zz;
+ int i;
+
+ /*
+ * Set zz to -1 if P1 is the point at infinity, 0 otherwise.
+ */
+ zz = P1->z[0] | P1->z[1] | P1->z[2] | P1->z[3] | P1->z[4];
+ zz = ((zz | -zz) >> 63) - (uint64_t)1;
+
+ /*
+ * Compute u1 = x1 (in t1) and s1 = y1 (in t3).
+ */
+ memcpy(t1, P1->x, sizeof t1);
+ memcpy(t3, P1->y, sizeof t3);
+
+ /*
+ * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
+ */
+ f256_montysquare(t4, P1->z);
+ f256_montymul(t2, P2->x, t4);
+ f256_montymul(t5, P1->z, t4);
+ f256_montymul(t4, P2->y, t5);
+
+ /*
+ * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4).
+ * reduce.
+ */
+ f256_sub(t2, t2, t1);
+ f256_sub(t4, t4, t3);
+
+ /*
+ * If both h = 0 and r = 0, then P1 = P2, and we want to set
+ * the mask tt to -1; otherwise, the mask will be 0.
+ */
+ f256_final_reduce(t2);
+ f256_final_reduce(t4);
+ tt = t2[0] | t2[1] | t2[2] | t2[3] | t2[4]
+ | t4[0] | t4[1] | t4[2] | t4[3] | t4[4];
+ tt = ((tt | -tt) >> 63) - (uint64_t)1;
+
+ /*
+ * Compute u1*h^2 (in t6) and h^3 (in t5);
+ */
+ f256_montysquare(t7, t2);
+ f256_montymul(t6, t1, t7);
+ f256_montymul(t5, t7, t2);
+
+ /*
+ * Compute x3 = r^2 - h^3 - 2*u1*h^2.
+ */
+ f256_montysquare(P1->x, t4);
+ f256_sub(P1->x, P1->x, t5);
+ f256_sub(P1->x, P1->x, t6);
+ f256_sub(P1->x, P1->x, t6);
+
+ /*
+ * Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
+ */
+ f256_sub(t6, t6, P1->x);
+ f256_montymul(P1->y, t4, t6);
+ f256_montymul(t1, t5, t3);
+ f256_sub(P1->y, P1->y, t1);
+
+ /*
+ * Compute z3 = h*z1.
+ */
+ f256_montymul(P1->z, P1->z, t2);
+
+ /*
+ * The "double" result, in case P1 = P2.
+ */
+
+ /*
+ * Compute z' = 2*y2 (in t1).
+ */
+ f256_add(t1, P2->y, P2->y);
+ f256_partial_reduce(t1);
+
+ /*
+ * Compute 2*(y2^2) (in t2) and s = 4*x2*(y2^2) (in t3).
+ */
+ f256_montysquare(t2, P2->y);
+ f256_add(t2, t2, t2);
+ f256_add(t3, t2, t2);
+ f256_montymul(t3, P2->x, t3);
+
+ /*
+ * Compute m = 3*(x2^2 - 1) (in t4).
+ */
+ f256_montysquare(t4, P2->x);
+ f256_sub(t4, t4, F256_R);
+ f256_add(t5, t4, t4);
+ f256_add(t4, t4, t5);
+
+ /*
+ * Compute x' = m^2 - 2*s (in t5).
+ */
+ f256_montysquare(t5, t4);
+ f256_sub(t5, t3);
+ f256_sub(t5, t3);
+
+ /*
+ * Compute y' = m*(s - x') - 8*y2^4 (in t6).
+ */
+ f256_sub(t6, t3, t5);
+ f256_montymul(t6, t6, t4);
+ f256_montysquare(t7, t2);
+ f256_sub(t6, t6, t7);
+ f256_sub(t6, t6, t7);
+
+ /*
+ * We now have the alternate (doubling) coordinates in (t5,t6,t1).
+ * We combine them with (x3,y3,z3).
+ */
+ for (i = 0; i < 5; i ++) {
+ P1->x[i] |= tt & t5[i];
+ P1->y[i] |= tt & t6[i];
+ P1->z[i] |= tt & t1[i];
+ }
+
+ /*
+ * If P1 = 0, then we get z3 = 0 (which is invalid); if z1 is 0,
+ * then we want to replace the result with a copy of P2. The
+ * test on z1 was done at the start, in the zz mask.
+ */
+ for (i = 0; i < 5; i ++) {
+ P1->x[i] ^= zz & (P1->x[i] ^ P2->x[i]);
+ P1->y[i] ^= zz & (P1->y[i] ^ P2->y[i]);
+ P1->z[i] ^= zz & (P1->z[i] ^ F256_R[i]);
+ }
+}
+#endif
+
+/*
+ * Inner function for computing a point multiplication. A window is
+ * provided, with points 1*P to 15*P in affine coordinates.
+ *
+ * Assumptions:
+ * - All provided points are valid points on the curve.
+ * - Multiplier is non-zero, and smaller than the curve order.
+ * - Everything is in Montgomery representation.
+ */
+static void
+point_mul_inner(p256_jacobian *R, const p256_affine *W,
+ const unsigned char *k, size_t klen)
+{
+ p256_jacobian Q;
+ uint32_t qz;
+
+ memset(&Q, 0, sizeof Q);
+ qz = 1;
+ while (klen -- > 0) {
+ int i;
+ unsigned bk;
+
+ bk = *k ++;
+ for (i = 0; i < 2; i ++) {
+ uint32_t bits;
+ uint32_t bnz;
+ p256_affine T;
+ p256_jacobian U;
+ uint32_t n;
+ int j;
+ uint64_t m;
+
+ p256_double(&Q);
+ p256_double(&Q);
+ p256_double(&Q);
+ p256_double(&Q);
+ bits = (bk >> 4) & 0x0F;
+ bnz = NEQ(bits, 0);
+
+ /*
+ * Lookup point in window. If the bits are 0,
+ * we get something invalid, which is not a
+ * problem because we will use it only if the
+ * bits are non-zero.
+ */
+ memset(&T, 0, sizeof T);
+ for (n = 0; n < 15; n ++) {
+ m = -(uint64_t)EQ(bits, n + 1);
+ T.x[0] |= m & W[n].x[0];
+ T.x[1] |= m & W[n].x[1];
+ T.x[2] |= m & W[n].x[2];
+ T.x[3] |= m & W[n].x[3];
+ T.x[4] |= m & W[n].x[4];
+ T.y[0] |= m & W[n].y[0];
+ T.y[1] |= m & W[n].y[1];
+ T.y[2] |= m & W[n].y[2];
+ T.y[3] |= m & W[n].y[3];
+ T.y[4] |= m & W[n].y[4];
+ }
+
+ U = Q;
+ p256_add_mixed(&U, &T);
+
+ /*
+ * If qz is still 1, then Q was all-zeros, and this
+ * is conserved through p256_double().
+ */
+ m = -(uint64_t)(bnz & qz);
+ for (j = 0; j < 5; j ++) {
+ Q.x[j] ^= m & (Q.x[j] ^ T.x[j]);
+ Q.y[j] ^= m & (Q.y[j] ^ T.y[j]);
+ Q.z[j] ^= m & (Q.z[j] ^ F256_R[j]);
+ }
+ CCOPY(bnz & ~qz, &Q, &U, sizeof Q);
+ qz &= ~bnz;
+ bk <<= 4;
+ }
+ }
+ *R = Q;
+}
+
+/*
+ * Convert a window from Jacobian to affine coordinates. A single
+ * field inversion is used. This function works for windows up to
+ * 32 elements.
+ *
+ * The destination array (aff[]) and the source array (jac[]) may
+ * overlap, provided that the start of aff[] is not after the start of
+ * jac[]. Even if the arrays do _not_ overlap, the source array is
+ * modified.
+ */
+static void
+window_to_affine(p256_affine *aff, p256_jacobian *jac, int num)
+{
+ /*
+ * Convert the window points to affine coordinates. We use the
+ * following trick to mutualize the inversion computation: if
+ * we have z1, z2, z3, and z4, and want to invert all of them,
+ * we compute u = 1/(z1*z2*z3*z4), and then we have:
+ * 1/z1 = u*z2*z3*z4
+ * 1/z2 = u*z1*z3*z4
+ * 1/z3 = u*z1*z2*z4
+ * 1/z4 = u*z1*z2*z3
+ *
+ * The partial products are computed recursively:
+ *
+ * - on input (z_1,z_2), return (z_2,z_1) and z_1*z_2
+ * - on input (z_1,z_2,... z_n):
+ * recurse on (z_1,z_2,... z_(n/2)) -> r1 and m1
+ * recurse on (z_(n/2+1),z_(n/2+2)... z_n) -> r2 and m2
+ * multiply elements of r1 by m2 -> s1
+ * multiply elements of r2 by m1 -> s2
+ * return r1||r2 and m1*m2
+ *
+ * In the example below, we suppose that we have 14 elements.
+ * Let z1, z2,... zE be the 14 values to invert (index noted in
+ * hexadecimal, starting at 1).
+ *
+ * - Depth 1:
+ * swap(z1, z2); z12 = z1*z2
+ * swap(z3, z4); z34 = z3*z4
+ * swap(z5, z6); z56 = z5*z6
+ * swap(z7, z8); z78 = z7*z8
+ * swap(z9, zA); z9A = z9*zA
+ * swap(zB, zC); zBC = zB*zC
+ * swap(zD, zE); zDE = zD*zE
+ *
+ * - Depth 2:
+ * z1 <- z1*z34, z2 <- z2*z34, z3 <- z3*z12, z4 <- z4*z12
+ * z1234 = z12*z34
+ * z5 <- z5*z78, z6 <- z6*z78, z7 <- z7*z56, z8 <- z8*z56
+ * z5678 = z56*z78
+ * z9 <- z9*zBC, zA <- zA*zBC, zB <- zB*z9A, zC <- zC*z9A
+ * z9ABC = z9A*zBC
+ *
+ * - Depth 3:
+ * z1 <- z1*z5678, z2 <- z2*z5678, z3 <- z3*z5678, z4 <- z4*z5678
+ * z5 <- z5*z1234, z6 <- z6*z1234, z7 <- z7*z1234, z8 <- z8*z1234
+ * z12345678 = z1234*z5678
+ * z9 <- z9*zDE, zA <- zA*zDE, zB <- zB*zDE, zC <- zC*zDE
+ * zD <- zD*z9ABC, zE*z9ABC
+ * z9ABCDE = z9ABC*zDE
+ *
+ * - Depth 4:
+ * multiply z1..z8 by z9ABCDE
+ * multiply z9..zE by z12345678
+ * final z = z12345678*z9ABCDE
+ */
+
+ uint64_t z[16][5];
+ int i, k, s;
+#define zt (z[15])
+#define zu (z[14])
+#define zv (z[13])
+
+ /*
+ * First recursion step (pairwise swapping and multiplication).
+ * If there is an odd number of elements, then we "invent" an
+ * extra one with coordinate Z = 1 (in Montgomery representation).
+ */
+ for (i = 0; (i + 1) < num; i += 2) {
+ memcpy(zt, jac[i].z, sizeof zt);
+ memcpy(jac[i].z, jac[i + 1].z, sizeof zt);
+ memcpy(jac[i + 1].z, zt, sizeof zt);
+ f256_montymul(z[i >> 1], jac[i].z, jac[i + 1].z);
+ }
+ if ((num & 1) != 0) {
+ memcpy(z[num >> 1], jac[num - 1].z, sizeof zt);
+ memcpy(jac[num - 1].z, F256_R, sizeof F256_R);
+ }
+
+ /*
+ * Perform further recursion steps. At the entry of each step,
+ * the process has been done for groups of 's' points. The
+ * integer k is the log2 of s.
+ */
+ for (k = 1, s = 2; s < num; k ++, s <<= 1) {
+ int n;
+
+ for (i = 0; i < num; i ++) {
+ f256_montymul(jac[i].z, jac[i].z, z[(i >> k) ^ 1]);
+ }
+ n = (num + s - 1) >> k;
+ for (i = 0; i < (n >> 1); i ++) {
+ f256_montymul(z[i], z[i << 1], z[(i << 1) + 1]);
+ }
+ if ((n & 1) != 0) {
+ memmove(z[n >> 1], z[n], sizeof zt);
+ }
+ }
+
+ /*
+ * Invert the final result, and convert all points.
+ */
+ f256_invert(zt, z[0]);
+ for (i = 0; i < num; i ++) {
+ f256_montymul(zv, jac[i].z, zt);
+ f256_montysquare(zu, zv);
+ f256_montymul(zv, zv, zu);
+ f256_montymul(aff[i].x, jac[i].x, zu);
+ f256_montymul(aff[i].y, jac[i].y, zv);
+ }
+}
+
+/*
+ * Multiply the provided point by an integer.
+ * Assumptions:
+ * - Source point is a valid curve point.
+ * - Source point is not the point-at-infinity.
+ * - Integer is not 0, and is lower than the curve order.
+ * If these conditions are not met, then the result is indeterminate
+ * (but the process is still constant-time).
+ */
+static void
+p256_mul(p256_jacobian *P, const unsigned char *k, size_t klen)
+{
+ union {
+ p256_affine aff[15];
+ p256_jacobian jac[15];
+ } window;
+ int i;
+
+ /*
+ * Compute window, in Jacobian coordinates.
+ */
+ window.jac[0] = *P;
+ for (i = 2; i < 16; i ++) {
+ window.jac[i - 1] = window.jac[(i >> 1) - 1];
+ if ((i & 1) == 0) {
+ p256_double(&window.jac[i - 1]);
+ } else {
+ p256_add(&window.jac[i - 1], &window.jac[i >> 1]);
+ }
+ }
+
+ /*
+ * Convert the window points to affine coordinates. Point
+ * window[0] is the source point, already in affine coordinates.
+ */
+ window_to_affine(window.aff, window.jac, 15);
+
+ /*
+ * Perform point multiplication.
+ */
+ point_mul_inner(P, window.aff, k, klen);
+}
+
+/*
+ * Precomputed window for the conventional generator: P256_Gwin[n]
+ * contains (n+1)*G (affine coordinates, in Montgomery representation).
+ */
+static const p256_affine P256_Gwin[] = {
+ {
+ { 0x30D418A9143C1, 0xC4FEDB60179E7, 0x62251075BA95F,
+ 0x5C669FB732B77, 0x08905F76B5375 },
+ { 0x5357CE95560A8, 0x43A19E45CDDF2, 0x21F3258B4AB8E,
+ 0xD8552E88688DD, 0x0571FF18A5885 }
+ },
+ {
+ { 0x46D410DDD64DF, 0x0B433827D8500, 0x1490D9AA6AE3C,
+ 0xA3A832205038D, 0x06BB32E52DCF3 },
+ { 0x48D361BEE1A57, 0xB7B236FF82F36, 0x042DBE152CD7C,
+ 0xA3AA9A8FB0E92, 0x08C577517A5B8 }
+ },
+ {
+ { 0x3F904EEBC1272, 0x9E87D81FBFFAC, 0xCBBC98B027F84,
+ 0x47E46AD77DD87, 0x06936A3FD6FF7 },
+ { 0x5C1FC983A7EBD, 0xC3861FE1AB04C, 0x2EE98E583E47A,
+ 0xC06A88208311A, 0x05F06A2AB587C }
+ },
+ {
+ { 0xB50D46918DCC5, 0xD7623C17374B0, 0x100AF24650A6E,
+ 0x76ABCDAACACE8, 0x077362F591B01 },
+ { 0xF24CE4CBABA68, 0x17AD6F4472D96, 0xDDD22E1762847,
+ 0x862EB6C36DEE5, 0x04B14C39CC5AB }
+ },
+ {
+ { 0x8AAEC45C61F5C, 0x9D4B9537DBE1B, 0x76C20C90EC649,
+ 0x3C7D41CB5AAD0, 0x0907960649052 },
+ { 0x9B4AE7BA4F107, 0xF75EB882BEB30, 0x7A1F6873C568E,
+ 0x915C540A9877E, 0x03A076BB9DD1E }
+ },
+ {
+ { 0x47373E77664A1, 0xF246CEE3E4039, 0x17A3AD55AE744,
+ 0x673C50A961A5B, 0x03074B5964213 },
+ { 0x6220D377E44BA, 0x30DFF14B593D3, 0x639F11299C2B5,
+ 0x75F5424D44CEF, 0x04C9916DEA07F }
+ },
+ {
+ { 0x354EA0173B4F1, 0x3C23C00F70746, 0x23BB082BD2021,
+ 0xE03E43EAAB50C, 0x03BA5119D3123 },
+ { 0xD0303F5B9D4DE, 0x17DA67BDD2847, 0xC941956742F2F,
+ 0x8670F933BDC77, 0x0AEDD9164E240 }
+ },
+ {
+ { 0x4CD19499A78FB, 0x4BF9B345527F1, 0x2CFC6B462AB5C,
+ 0x30CDF90F02AF0, 0x0763891F62652 },
+ { 0xA3A9532D49775, 0xD7F9EBA15F59D, 0x60BBF021E3327,
+ 0xF75C23C7B84BE, 0x06EC12F2C706D }
+ },
+ {
+ { 0x6E8F264E20E8E, 0xC79A7A84175C9, 0xC8EB00ABE6BFE,
+ 0x16A4CC09C0444, 0x005B3081D0C4E },
+ { 0x777AA45F33140, 0xDCE5D45E31EB7, 0xB12F1A56AF7BE,
+ 0xF9B2B6E019A88, 0x086659CDFD835 }
+ },
+ {
+ { 0xDBD19DC21EC8C, 0x94FCF81392C18, 0x250B4998F9868,
+ 0x28EB37D2CD648, 0x0C61C947E4B34 },
+ { 0x407880DD9E767, 0x0C83FBE080C2B, 0x9BE5D2C43A899,
+ 0xAB4EF7D2D6577, 0x08719A555B3B4 }
+ },
+ {
+ { 0x260A6245E4043, 0x53E7FDFE0EA7D, 0xAC1AB59DE4079,
+ 0x072EFF3A4158D, 0x0E7090F1949C9 },
+ { 0x85612B944E886, 0xE857F61C81A76, 0xAD643D250F939,
+ 0x88DAC0DAA891E, 0x089300244125B }
+ },
+ {
+ { 0x1AA7D26977684, 0x58A345A3304B7, 0x37385EABDEDEF,
+ 0x155E409D29DEE, 0x0EE1DF780B83E },
+ { 0x12D91CBB5B437, 0x65A8956370CAC, 0xDE6D66170ED2F,
+ 0xAC9B8228CFA8A, 0x0FF57C95C3238 }
+ },
+ {
+ { 0x25634B2ED7097, 0x9156FD30DCCC4, 0x9E98110E35676,
+ 0x7594CBCD43F55, 0x038477ACC395B },
+ { 0x2B90C00EE17FF, 0xF842ED2E33575, 0x1F5BC16874838,
+ 0x7968CD06422BD, 0x0BC0876AB9E7B }
+ },
+ {
+ { 0xA35BB0CF664AF, 0x68F9707E3A242, 0x832660126E48F,
+ 0x72D2717BF54C6, 0x0AAE7333ED12C },
+ { 0x2DB7995D586B1, 0xE732237C227B5, 0x65E7DBBE29569,
+ 0xBBBD8E4193E2A, 0x052706DC3EAA1 }
+ },
+ {
+ { 0xD8B7BC60055BE, 0xD76E27E4B72BC, 0x81937003CC23E,
+ 0xA090E337424E4, 0x02AA0E43EAD3D },
+ { 0x524F6383C45D2, 0x422A41B2540B8, 0x8A4797D766355,
+ 0xDF444EFA6DE77, 0x0042170A9079A }
+ },
+};
+
+/*
+ * Multiply the conventional generator of the curve by the provided
+ * integer. Return is written in *P.
+ *
+ * Assumptions:
+ * - Integer is not 0, and is lower than the curve order.
+ * If this conditions is not met, then the result is indeterminate
+ * (but the process is still constant-time).
+ */
+static void
+p256_mulgen(p256_jacobian *P, const unsigned char *k, size_t klen)
+{
+ point_mul_inner(P, P256_Gwin, k, klen);
+}
+
+/*
+ * Return 1 if all of the following hold:
+ * - klen <= 32
+ * - k != 0
+ * - k is lower than the curve order
+ * Otherwise, return 0.
+ *
+ * Constant-time behaviour: only klen may be observable.
+ */
+static uint32_t
+check_scalar(const unsigned char *k, size_t klen)
+{
+ uint32_t z;
+ int32_t c;
+ size_t u;
+
+ if (klen > 32) {
+ return 0;
+ }
+ z = 0;
+ for (u = 0; u < klen; u ++) {
+ z |= k[u];
+ }
+ if (klen == 32) {
+ c = 0;
+ for (u = 0; u < klen; u ++) {
+ c |= -(int32_t)EQ0(c) & CMP(k[u], P256_N[u]);
+ }
+ } else {
+ c = -1;
+ }
+ return NEQ(z, 0) & LT0(c);
+}
+
+static uint32_t
+api_mul(unsigned char *G, size_t Glen,
+ const unsigned char *k, size_t klen, int curve)
+{
+ uint32_t r;
+ p256_jacobian P;
+
+ (void)curve;
+ if (Glen != 65) {
+ return 0;
+ }
+ r = check_scalar(k, klen);
+ r &= point_decode(&P, G);
+ p256_mul(&P, k, klen);
+ r &= point_encode(G, &P);
+ return r;
+}
+
+static size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *k, size_t klen, int curve)
+{
+ p256_jacobian P;
+
+ (void)curve;
+ p256_mulgen(&P, k, klen);
+ point_encode(R, &P);
+ return 65;
+}
+
+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)
+{
+ /*
+ * We might want to use Shamir's trick here: make a composite
+ * window of u*P+v*Q points, to merge the two doubling-ladders
+ * into one. This, however, has some complications:
+ *
+ * - During the computation, we may hit the point-at-infinity.
+ * Thus, we would need p256_add_complete_mixed() (complete
+ * formulas for point addition), with a higher cost (17 muls
+ * instead of 11).
+ *
+ * - A 4-bit window would be too large, since it would involve
+ * 16*16-1 = 255 points. For the same window size as in the
+ * p256_mul() case, we would need to reduce the window size
+ * to 2 bits, and thus perform twice as many non-doubling
+ * point additions.
+ *
+ * - The window may itself contain the point-at-infinity, and
+ * thus cannot be in all generality be made of affine points.
+ * Instead, we would need to make it a window of points in
+ * Jacobian coordinates. Even p256_add_complete_mixed() would
+ * be inappropriate.
+ *
+ * For these reasons, the code below performs two separate
+ * point multiplications, then computes the final point addition
+ * (which is both a "normal" addition, and a doubling, to handle
+ * all cases).
+ */
+
+ p256_jacobian P, Q;
+ uint32_t r, t, s;
+ uint64_t z;
+
+ (void)curve;
+ if (len != 65) {
+ return 0;
+ }
+ r = point_decode(&P, A);
+ p256_mul(&P, x, xlen);
+ if (B == NULL) {
+ p256_mulgen(&Q, y, ylen);
+ } else {
+ r &= point_decode(&Q, B);
+ p256_mul(&Q, y, ylen);
+ }
+
+ /*
+ * The final addition may fail in case both points are equal.
+ */
+ t = p256_add(&P, &Q);
+ f256_final_reduce(P.z);
+ z = P.z[0] | P.z[1] | P.z[2] | P.z[3] | P.z[4];
+ s = EQ((uint32_t)(z | (z >> 32)), 0);
+ p256_double(&Q);
+
+ /*
+ * If s is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we
+ * have the following:
+ *
+ * s = 0, t = 0 return P (normal addition)
+ * s = 0, t = 1 return P (normal addition)
+ * s = 1, t = 0 return Q (a 'double' case)
+ * s = 1, t = 1 report an error (P+Q = 0)
+ */
+ CCOPY(s & ~t, &P, &Q, sizeof Q);
+ point_encode(A, &P);
+ r &= ~(s & t);
+ return r;
+}
+
+/* see bearssl_ec.h */
+const br_ec_impl br_ec_p256_m62 = {
+ (uint32_t)0x00800000,
+ &api_generator,
+ &api_order,
+ &api_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
+
+/* see bearssl_ec.h */
+const br_ec_impl *
+br_ec_p256_m62_get(void)
+{
+ return &br_ec_p256_m62;
+}
+
+#else
+
+/* see bearssl_ec.h */
+const br_ec_impl *
+br_ec_p256_m62_get(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/contrib/bearssl/src/ec/ec_p256_m64.c b/contrib/bearssl/src/ec/ec_p256_m64.c
new file mode 100644
index 000000000000..5a7ea177408b
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_p256_m64.c
@@ -0,0 +1,1730 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#if BR_INT128 || BR_UMUL128
+
+#if BR_UMUL128
+#include <intrin.h>
+#endif
+
+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
+};
+
+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 *
+api_generator(int curve, size_t *len)
+{
+ (void)curve;
+ *len = sizeof P256_G;
+ return P256_G;
+}
+
+static const unsigned char *
+api_order(int curve, size_t *len)
+{
+ (void)curve;
+ *len = sizeof P256_N;
+ return P256_N;
+}
+
+static size_t
+api_xoff(int curve, size_t *len)
+{
+ (void)curve;
+ *len = 32;
+ return 1;
+}
+
+/*
+ * A field element is encoded as four 64-bit integers, in basis 2^64.
+ * Values may reach up to 2^256-1. Montgomery multiplication is used.
+ */
+
+/* R = 2^256 mod p */
+static const uint64_t F256_R[] = {
+ 0x0000000000000001, 0xFFFFFFFF00000000,
+ 0xFFFFFFFFFFFFFFFF, 0x00000000FFFFFFFE
+};
+
+/* Curve equation is y^2 = x^3 - 3*x + B. This constant is B*R mod p
+ (Montgomery representation of B). */
+static const uint64_t P256_B_MONTY[] = {
+ 0xD89CDF6229C4BDDF, 0xACF005CD78843090,
+ 0xE5A220ABF7212ED6, 0xDC30061D04874834
+};
+
+/*
+ * Addition in the field.
+ */
+static inline void
+f256_add(uint64_t *d, const uint64_t *a, const uint64_t *b)
+{
+#if BR_INT128
+ unsigned __int128 w;
+ uint64_t t;
+
+ w = (unsigned __int128)a[0] + b[0];
+ d[0] = (uint64_t)w;
+ w = (unsigned __int128)a[1] + b[1] + (w >> 64);
+ d[1] = (uint64_t)w;
+ w = (unsigned __int128)a[2] + b[2] + (w >> 64);
+ d[2] = (uint64_t)w;
+ w = (unsigned __int128)a[3] + b[3] + (w >> 64);
+ d[3] = (uint64_t)w;
+ t = (uint64_t)(w >> 64);
+
+ /*
+ * 2^256 = 2^224 - 2^192 - 2^96 + 1 in the field.
+ */
+ w = (unsigned __int128)d[0] + t;
+ d[0] = (uint64_t)w;
+ w = (unsigned __int128)d[1] + (w >> 64) - (t << 32);
+ d[1] = (uint64_t)w;
+ /* Here, carry "w >> 64" can only be 0 or -1 */
+ w = (unsigned __int128)d[2] - ((w >> 64) & 1);
+ d[2] = (uint64_t)w;
+ /* Again, carry is 0 or -1 */
+ d[3] += (uint64_t)(w >> 64) + (t << 32) - t;
+
+#elif BR_UMUL128
+
+ unsigned char cc;
+ uint64_t t;
+
+ cc = _addcarry_u64(0, a[0], b[0], &d[0]);
+ cc = _addcarry_u64(cc, a[1], b[1], &d[1]);
+ cc = _addcarry_u64(cc, a[2], b[2], &d[2]);
+ cc = _addcarry_u64(cc, a[3], b[3], &d[3]);
+
+ /*
+ * If there is a carry, then we want to subtract p, which we
+ * do by adding 2^256 - p.
+ */
+ t = cc;
+ cc = _addcarry_u64(cc, d[0], 0, &d[0]);
+ cc = _addcarry_u64(cc, d[1], -(t << 32), &d[1]);
+ cc = _addcarry_u64(cc, d[2], -t, &d[2]);
+ (void)_addcarry_u64(cc, d[3], (t << 32) - (t << 1), &d[3]);
+
+#endif
+}
+
+/*
+ * Subtraction in the field.
+ */
+static inline void
+f256_sub(uint64_t *d, const uint64_t *a, const uint64_t *b)
+{
+#if BR_INT128
+
+ unsigned __int128 w;
+ uint64_t t;
+
+ w = (unsigned __int128)a[0] - b[0];
+ d[0] = (uint64_t)w;
+ w = (unsigned __int128)a[1] - b[1] - ((w >> 64) & 1);
+ d[1] = (uint64_t)w;
+ w = (unsigned __int128)a[2] - b[2] - ((w >> 64) & 1);
+ d[2] = (uint64_t)w;
+ w = (unsigned __int128)a[3] - b[3] - ((w >> 64) & 1);
+ d[3] = (uint64_t)w;
+ t = (uint64_t)(w >> 64) & 1;
+
+ /*
+ * p = 2^256 - 2^224 + 2^192 + 2^96 - 1.
+ */
+ w = (unsigned __int128)d[0] - t;
+ d[0] = (uint64_t)w;
+ w = (unsigned __int128)d[1] + (t << 32) - ((w >> 64) & 1);
+ d[1] = (uint64_t)w;
+ /* Here, carry "w >> 64" can only be 0 or +1 */
+ w = (unsigned __int128)d[2] + (w >> 64);
+ d[2] = (uint64_t)w;
+ /* Again, carry is 0 or +1 */
+ d[3] += (uint64_t)(w >> 64) - (t << 32) + t;
+
+#elif BR_UMUL128
+
+ unsigned char cc;
+ uint64_t t;
+
+ cc = _subborrow_u64(0, a[0], b[0], &d[0]);
+ cc = _subborrow_u64(cc, a[1], b[1], &d[1]);
+ cc = _subborrow_u64(cc, a[2], b[2], &d[2]);
+ cc = _subborrow_u64(cc, a[3], b[3], &d[3]);
+
+ /*
+ * If there is a carry, then we need to add p.
+ */
+ t = cc;
+ cc = _addcarry_u64(0, d[0], -t, &d[0]);
+ cc = _addcarry_u64(cc, d[1], (-t) >> 32, &d[1]);
+ cc = _addcarry_u64(cc, d[2], 0, &d[2]);
+ (void)_addcarry_u64(cc, d[3], t - (t << 32), &d[3]);
+
+#endif
+}
+
+/*
+ * Montgomery multiplication in the field.
+ */
+static void
+f256_montymul(uint64_t *d, const uint64_t *a, const uint64_t *b)
+{
+#if BR_INT128
+
+ uint64_t x, f, t0, t1, t2, t3, t4;
+ unsigned __int128 z, ff;
+ int i;
+
+ /*
+ * When computing d <- d + a[u]*b, we also add f*p such
+ * that d + a[u]*b + f*p is a multiple of 2^64. Since
+ * p = -1 mod 2^64, we can compute f = d[0] + a[u]*b[0] mod 2^64.
+ */
+
+ /*
+ * Step 1: t <- (a[0]*b + f*p) / 2^64
+ * We have f = a[0]*b[0] mod 2^64. Since p = -1 mod 2^64, this
+ * ensures that (a[0]*b + f*p) is a multiple of 2^64.
+ *
+ * We also have: f*p = f*2^256 - f*2^224 + f*2^192 + f*2^96 - f.
+ */
+ x = a[0];
+ z = (unsigned __int128)b[0] * x;
+ f = (uint64_t)z;
+ z = (unsigned __int128)b[1] * x + (z >> 64) + (uint64_t)(f << 32);
+ t0 = (uint64_t)z;
+ z = (unsigned __int128)b[2] * x + (z >> 64) + (uint64_t)(f >> 32);
+ t1 = (uint64_t)z;
+ z = (unsigned __int128)b[3] * x + (z >> 64) + f;
+ t2 = (uint64_t)z;
+ t3 = (uint64_t)(z >> 64);
+ ff = ((unsigned __int128)f << 64) - ((unsigned __int128)f << 32);
+ z = (unsigned __int128)t2 + (uint64_t)ff;
+ t2 = (uint64_t)z;
+ z = (unsigned __int128)t3 + (z >> 64) + (ff >> 64);
+ t3 = (uint64_t)z;
+ t4 = (uint64_t)(z >> 64);
+
+ /*
+ * Steps 2 to 4: t <- (t + a[i]*b + f*p) / 2^64
+ */
+ for (i = 1; i < 4; i ++) {
+ x = a[i];
+
+ /* t <- (t + x*b - f) / 2^64 */
+ z = (unsigned __int128)b[0] * x + t0;
+ f = (uint64_t)z;
+ z = (unsigned __int128)b[1] * x + t1 + (z >> 64);
+ t0 = (uint64_t)z;
+ z = (unsigned __int128)b[2] * x + t2 + (z >> 64);
+ t1 = (uint64_t)z;
+ z = (unsigned __int128)b[3] * x + t3 + (z >> 64);
+ t2 = (uint64_t)z;
+ z = t4 + (z >> 64);
+ t3 = (uint64_t)z;
+ t4 = (uint64_t)(z >> 64);
+
+ /* t <- t + f*2^32, carry in the upper half of z */
+ z = (unsigned __int128)t0 + (uint64_t)(f << 32);
+ t0 = (uint64_t)z;
+ z = (z >> 64) + (unsigned __int128)t1 + (uint64_t)(f >> 32);
+ t1 = (uint64_t)z;
+
+ /* t <- t + f*2^192 - f*2^160 + f*2^128 */
+ ff = ((unsigned __int128)f << 64)
+ - ((unsigned __int128)f << 32) + f;
+ z = (z >> 64) + (unsigned __int128)t2 + (uint64_t)ff;
+ t2 = (uint64_t)z;
+ z = (unsigned __int128)t3 + (z >> 64) + (ff >> 64);
+ t3 = (uint64_t)z;
+ t4 += (uint64_t)(z >> 64);
+ }
+
+ /*
+ * At that point, we have computed t = (a*b + F*p) / 2^256, where
+ * F is a 256-bit integer whose limbs are the "f" coefficients
+ * in the steps above. We have:
+ * a <= 2^256-1
+ * b <= 2^256-1
+ * F <= 2^256-1
+ * Hence:
+ * a*b + F*p <= (2^256-1)*(2^256-1) + p*(2^256-1)
+ * a*b + F*p <= 2^256*(2^256 - 2 + p) + 1 - p
+ * Therefore:
+ * t < 2^256 + p - 2
+ * Since p < 2^256, it follows that:
+ * t4 can be only 0 or 1
+ * t - p < 2^256
+ * We can therefore subtract p from t, conditionally on t4, to
+ * get a nonnegative result that fits on 256 bits.
+ */
+ z = (unsigned __int128)t0 + t4;
+ t0 = (uint64_t)z;
+ z = (unsigned __int128)t1 - (t4 << 32) + (z >> 64);
+ t1 = (uint64_t)z;
+ z = (unsigned __int128)t2 - (z >> 127);
+ t2 = (uint64_t)z;
+ t3 = t3 - (uint64_t)(z >> 127) - t4 + (t4 << 32);
+
+ d[0] = t0;
+ d[1] = t1;
+ d[2] = t2;
+ d[3] = t3;
+
+#elif BR_UMUL128
+
+ uint64_t x, f, t0, t1, t2, t3, t4;
+ uint64_t zl, zh, ffl, ffh;
+ unsigned char k, m;
+ int i;
+
+ /*
+ * When computing d <- d + a[u]*b, we also add f*p such
+ * that d + a[u]*b + f*p is a multiple of 2^64. Since
+ * p = -1 mod 2^64, we can compute f = d[0] + a[u]*b[0] mod 2^64.
+ */
+
+ /*
+ * Step 1: t <- (a[0]*b + f*p) / 2^64
+ * We have f = a[0]*b[0] mod 2^64. Since p = -1 mod 2^64, this
+ * ensures that (a[0]*b + f*p) is a multiple of 2^64.
+ *
+ * We also have: f*p = f*2^256 - f*2^224 + f*2^192 + f*2^96 - f.
+ */
+ x = a[0];
+
+ zl = _umul128(b[0], x, &zh);
+ f = zl;
+ t0 = zh;
+
+ zl = _umul128(b[1], x, &zh);
+ k = _addcarry_u64(0, zl, t0, &zl);
+ (void)_addcarry_u64(k, zh, 0, &zh);
+ k = _addcarry_u64(0, zl, f << 32, &zl);
+ (void)_addcarry_u64(k, zh, 0, &zh);
+ t0 = zl;
+ t1 = zh;
+
+ zl = _umul128(b[2], x, &zh);
+ k = _addcarry_u64(0, zl, t1, &zl);
+ (void)_addcarry_u64(k, zh, 0, &zh);
+ k = _addcarry_u64(0, zl, f >> 32, &zl);
+ (void)_addcarry_u64(k, zh, 0, &zh);
+ t1 = zl;
+ t2 = zh;
+
+ zl = _umul128(b[3], x, &zh);
+ k = _addcarry_u64(0, zl, t2, &zl);
+ (void)_addcarry_u64(k, zh, 0, &zh);
+ k = _addcarry_u64(0, zl, f, &zl);
+ (void)_addcarry_u64(k, zh, 0, &zh);
+ t2 = zl;
+ t3 = zh;
+
+ t4 = _addcarry_u64(0, t3, f, &t3);
+ k = _subborrow_u64(0, t2, f << 32, &t2);
+ k = _subborrow_u64(k, t3, f >> 32, &t3);
+ (void)_subborrow_u64(k, t4, 0, &t4);
+
+ /*
+ * Steps 2 to 4: t <- (t + a[i]*b + f*p) / 2^64
+ */
+ for (i = 1; i < 4; i ++) {
+ x = a[i];
+ /* f = t0 + x * b[0]; -- computed below */
+
+ /* t <- (t + x*b - f) / 2^64 */
+ zl = _umul128(b[0], x, &zh);
+ k = _addcarry_u64(0, zl, t0, &f);
+ (void)_addcarry_u64(k, zh, 0, &t0);
+
+ zl = _umul128(b[1], x, &zh);
+ k = _addcarry_u64(0, zl, t0, &zl);
+ (void)_addcarry_u64(k, zh, 0, &zh);
+ k = _addcarry_u64(0, zl, t1, &t0);
+ (void)_addcarry_u64(k, zh, 0, &t1);
+
+ zl = _umul128(b[2], x, &zh);
+ k = _addcarry_u64(0, zl, t1, &zl);
+ (void)_addcarry_u64(k, zh, 0, &zh);
+ k = _addcarry_u64(0, zl, t2, &t1);
+ (void)_addcarry_u64(k, zh, 0, &t2);
+
+ zl = _umul128(b[3], x, &zh);
+ k = _addcarry_u64(0, zl, t2, &zl);
+ (void)_addcarry_u64(k, zh, 0, &zh);
+ k = _addcarry_u64(0, zl, t3, &t2);
+ (void)_addcarry_u64(k, zh, 0, &t3);
+
+ t4 = _addcarry_u64(0, t3, t4, &t3);
+
+ /* t <- t + f*2^32, carry in k */
+ k = _addcarry_u64(0, t0, f << 32, &t0);
+ k = _addcarry_u64(k, t1, f >> 32, &t1);
+
+ /* t <- t + f*2^192 - f*2^160 + f*2^128 */
+ m = _subborrow_u64(0, f, f << 32, &ffl);
+ (void)_subborrow_u64(m, f, f >> 32, &ffh);
+ k = _addcarry_u64(k, t2, ffl, &t2);
+ k = _addcarry_u64(k, t3, ffh, &t3);
+ (void)_addcarry_u64(k, t4, 0, &t4);
+ }
+
+ /*
+ * At that point, we have computed t = (a*b + F*p) / 2^256, where
+ * F is a 256-bit integer whose limbs are the "f" coefficients
+ * in the steps above. We have:
+ * a <= 2^256-1
+ * b <= 2^256-1
+ * F <= 2^256-1
+ * Hence:
+ * a*b + F*p <= (2^256-1)*(2^256-1) + p*(2^256-1)
+ * a*b + F*p <= 2^256*(2^256 - 2 + p) + 1 - p
+ * Therefore:
+ * t < 2^256 + p - 2
+ * Since p < 2^256, it follows that:
+ * t4 can be only 0 or 1
+ * t - p < 2^256
+ * We can therefore subtract p from t, conditionally on t4, to
+ * get a nonnegative result that fits on 256 bits.
+ */
+ k = _addcarry_u64(0, t0, t4, &t0);
+ k = _addcarry_u64(k, t1, -(t4 << 32), &t1);
+ k = _addcarry_u64(k, t2, -t4, &t2);
+ (void)_addcarry_u64(k, t3, (t4 << 32) - (t4 << 1), &t3);
+
+ d[0] = t0;
+ d[1] = t1;
+ d[2] = t2;
+ d[3] = t3;
+
+#endif
+}
+
+/*
+ * Montgomery squaring in the field; currently a basic wrapper around
+ * multiplication (inline, should be optimized away).
+ * TODO: see if some extra speed can be gained here.
+ */
+static inline void
+f256_montysquare(uint64_t *d, const uint64_t *a)
+{
+ f256_montymul(d, a, a);
+}
+
+/*
+ * Convert to Montgomery representation.
+ */
+static void
+f256_tomonty(uint64_t *d, const uint64_t *a)
+{
+ /*
+ * R2 = 2^512 mod p.
+ * If R = 2^256 mod p, then R2 = R^2 mod p; and the Montgomery
+ * multiplication of a by R2 is: a*R2/R = a*R mod p, i.e. the
+ * conversion to Montgomery representation.
+ */
+ static const uint64_t R2[] = {
+ 0x0000000000000003,
+ 0xFFFFFFFBFFFFFFFF,
+ 0xFFFFFFFFFFFFFFFE,
+ 0x00000004FFFFFFFD
+ };
+
+ f256_montymul(d, a, R2);
+}
+
+/*
+ * Convert from Montgomery representation.
+ */
+static void
+f256_frommonty(uint64_t *d, const uint64_t *a)
+{
+ /*
+ * Montgomery multiplication by 1 is division by 2^256 modulo p.
+ */
+ static const uint64_t one[] = { 1, 0, 0, 0 };
+
+ f256_montymul(d, a, one);
+}
+
+/*
+ * Inversion in the field. If the source value is 0 modulo p, then this
+ * returns 0 or p. This function uses Montgomery representation.
+ */
+static void
+f256_invert(uint64_t *d, const uint64_t *a)
+{
+ /*
+ * We compute a^(p-2) mod p. The exponent pattern (from high to
+ * low) is:
+ * - 32 bits of value 1
+ * - 31 bits of value 0
+ * - 1 bit of value 1
+ * - 96 bits of value 0
+ * - 94 bits of value 1
+ * - 1 bit of value 0
+ * - 1 bit of value 1
+ * To speed up the square-and-multiply algorithm, we precompute
+ * a^(2^31-1).
+ */
+
+ uint64_t r[4], t[4];
+ int i;
+
+ memcpy(t, a, sizeof t);
+ for (i = 0; i < 30; i ++) {
+ f256_montysquare(t, t);
+ f256_montymul(t, t, a);
+ }
+
+ memcpy(r, t, sizeof t);
+ for (i = 224; i >= 0; i --) {
+ f256_montysquare(r, r);
+ switch (i) {
+ case 0:
+ case 2:
+ case 192:
+ case 224:
+ f256_montymul(r, r, a);
+ break;
+ case 3:
+ case 34:
+ case 65:
+ f256_montymul(r, r, t);
+ break;
+ }
+ }
+ memcpy(d, r, sizeof r);
+}
+
+/*
+ * Finalize reduction.
+ * Input value fits on 256 bits. This function subtracts p if and only
+ * if the input is greater than or equal to p.
+ */
+static inline void
+f256_final_reduce(uint64_t *a)
+{
+#if BR_INT128
+
+ uint64_t t0, t1, t2, t3, cc;
+ unsigned __int128 z;
+
+ /*
+ * We add 2^224 - 2^192 - 2^96 + 1 to a. If there is no carry,
+ * then a < p; otherwise, the addition result we computed is
+ * the value we must return.
+ */
+ z = (unsigned __int128)a[0] + 1;
+ t0 = (uint64_t)z;
+ z = (unsigned __int128)a[1] + (z >> 64) - ((uint64_t)1 << 32);
+ t1 = (uint64_t)z;
+ z = (unsigned __int128)a[2] - (z >> 127);
+ t2 = (uint64_t)z;
+ z = (unsigned __int128)a[3] - (z >> 127) + 0xFFFFFFFF;
+ t3 = (uint64_t)z;
+ cc = -(uint64_t)(z >> 64);
+
+ a[0] ^= cc & (a[0] ^ t0);
+ a[1] ^= cc & (a[1] ^ t1);
+ a[2] ^= cc & (a[2] ^ t2);
+ a[3] ^= cc & (a[3] ^ t3);
+
+#elif BR_UMUL128
+
+ uint64_t t0, t1, t2, t3, m;
+ unsigned char k;
+
+ k = _addcarry_u64(0, a[0], (uint64_t)1, &t0);
+ k = _addcarry_u64(k, a[1], -((uint64_t)1 << 32), &t1);
+ k = _addcarry_u64(k, a[2], -(uint64_t)1, &t2);
+ k = _addcarry_u64(k, a[3], ((uint64_t)1 << 32) - 2, &t3);
+ m = -(uint64_t)k;
+
+ a[0] ^= m & (a[0] ^ t0);
+ a[1] ^= m & (a[1] ^ t1);
+ a[2] ^= m & (a[2] ^ t2);
+ a[3] ^= m & (a[3] ^ t3);
+
+#endif
+}
+
+/*
+ * Points in affine and Jacobian coordinates.
+ *
+ * - In affine coordinates, the point-at-infinity cannot be encoded.
+ * - Jacobian coordinates (X,Y,Z) correspond to affine (X/Z^2,Y/Z^3);
+ * if Z = 0 then this is the point-at-infinity.
+ */
+typedef struct {
+ uint64_t x[4];
+ uint64_t y[4];
+} p256_affine;
+
+typedef struct {
+ uint64_t x[4];
+ uint64_t y[4];
+ uint64_t z[4];
+} p256_jacobian;
+
+/*
+ * Decode a point. The returned point is in Jacobian coordinates, but
+ * with z = 1. If the encoding is invalid, or encodes a point which is
+ * not on the curve, or encodes the point at infinity, then this function
+ * returns 0. Otherwise, 1 is returned.
+ *
+ * The buffer is assumed to have length exactly 65 bytes.
+ */
+static uint32_t
+point_decode(p256_jacobian *P, const unsigned char *buf)
+{
+ uint64_t x[4], y[4], t[4], x3[4], tt;
+ uint32_t r;
+
+ /*
+ * Header byte shall be 0x04.
+ */
+ r = EQ(buf[0], 0x04);
+
+ /*
+ * Decode X and Y coordinates, and convert them into
+ * Montgomery representation.
+ */
+ x[3] = br_dec64be(buf + 1);
+ x[2] = br_dec64be(buf + 9);
+ x[1] = br_dec64be(buf + 17);
+ x[0] = br_dec64be(buf + 25);
+ y[3] = br_dec64be(buf + 33);
+ y[2] = br_dec64be(buf + 41);
+ y[1] = br_dec64be(buf + 49);
+ y[0] = br_dec64be(buf + 57);
+ f256_tomonty(x, x);
+ f256_tomonty(y, y);
+
+ /*
+ * Verify y^2 = x^3 + A*x + B. In curve P-256, A = -3.
+ * Note that the Montgomery representation of 0 is 0. We must
+ * take care to apply the final reduction to make sure we have
+ * 0 and not p.
+ */
+ f256_montysquare(t, y);
+ f256_montysquare(x3, x);
+ f256_montymul(x3, x3, x);
+ f256_sub(t, t, x3);
+ f256_add(t, t, x);
+ f256_add(t, t, x);
+ f256_add(t, t, x);
+ f256_sub(t, t, P256_B_MONTY);
+ f256_final_reduce(t);
+ tt = t[0] | t[1] | t[2] | t[3];
+ r &= EQ((uint32_t)(tt | (tt >> 32)), 0);
+
+ /*
+ * Return the point in Jacobian coordinates (and Montgomery
+ * representation).
+ */
+ memcpy(P->x, x, sizeof x);
+ memcpy(P->y, y, sizeof y);
+ memcpy(P->z, F256_R, sizeof F256_R);
+ return r;
+}
+
+/*
+ * Final conversion for a point:
+ * - The point is converted back to affine coordinates.
+ * - Final reduction is performed.
+ * - The point is encoded into the provided buffer.
+ *
+ * If the point is the point-at-infinity, all operations are performed,
+ * but the buffer contents are indeterminate, and 0 is returned. Otherwise,
+ * the encoded point is written in the buffer, and 1 is returned.
+ */
+static uint32_t
+point_encode(unsigned char *buf, const p256_jacobian *P)
+{
+ uint64_t t1[4], t2[4], z;
+
+ /* Set t1 = 1/z^2 and t2 = 1/z^3. */
+ f256_invert(t2, P->z);
+ f256_montysquare(t1, t2);
+ f256_montymul(t2, t2, t1);
+
+ /* Compute affine coordinates x (in t1) and y (in t2). */
+ f256_montymul(t1, P->x, t1);
+ f256_montymul(t2, P->y, t2);
+
+ /* Convert back from Montgomery representation, and finalize
+ reductions. */
+ f256_frommonty(t1, t1);
+ f256_frommonty(t2, t2);
+ f256_final_reduce(t1);
+ f256_final_reduce(t2);
+
+ /* Encode. */
+ buf[0] = 0x04;
+ br_enc64be(buf + 1, t1[3]);
+ br_enc64be(buf + 9, t1[2]);
+ br_enc64be(buf + 17, t1[1]);
+ br_enc64be(buf + 25, t1[0]);
+ br_enc64be(buf + 33, t2[3]);
+ br_enc64be(buf + 41, t2[2]);
+ br_enc64be(buf + 49, t2[1]);
+ br_enc64be(buf + 57, t2[0]);
+
+ /* Return success if and only if P->z != 0. */
+ z = P->z[0] | P->z[1] | P->z[2] | P->z[3];
+ return NEQ((uint32_t)(z | z >> 32), 0);
+}
+
+/*
+ * Point doubling in Jacobian coordinates: point P is doubled.
+ * Note: if the source point is the point-at-infinity, then the result is
+ * still the point-at-infinity, which is correct. Moreover, if the three
+ * coordinates were zero, then they still are zero in the returned value.
+ *
+ * (Note: this is true even without the final reduction: if the three
+ * coordinates are encoded as four words of value zero each, then the
+ * result will also have all-zero coordinate encodings, not the alternate
+ * encoding as the integer p.)
+ */
+static void
+p256_double(p256_jacobian *P)
+{
+ /*
+ * 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
+ *
+ * These formulas work for all points, including points of order 2
+ * and points at infinity:
+ * - If y = 0 then z' = 0. But there is no such point in P-256
+ * anyway.
+ * - If z = 0 then z' = 0.
+ */
+ uint64_t t1[4], t2[4], t3[4], t4[4];
+
+ /*
+ * Compute z^2 in t1.
+ */
+ f256_montysquare(t1, P->z);
+
+ /*
+ * Compute x-z^2 in t2 and x+z^2 in t1.
+ */
+ f256_add(t2, P->x, t1);
+ f256_sub(t1, P->x, t1);
+
+ /*
+ * Compute 3*(x+z^2)*(x-z^2) in t1.
+ */
+ f256_montymul(t3, t1, t2);
+ f256_add(t1, t3, t3);
+ f256_add(t1, t3, t1);
+
+ /*
+ * Compute 4*x*y^2 (in t2) and 2*y^2 (in t3).
+ */
+ f256_montysquare(t3, P->y);
+ f256_add(t3, t3, t3);
+ f256_montymul(t2, P->x, t3);
+ f256_add(t2, t2, t2);
+
+ /*
+ * Compute x' = m^2 - 2*s.
+ */
+ f256_montysquare(P->x, t1);
+ f256_sub(P->x, P->x, t2);
+ f256_sub(P->x, P->x, t2);
+
+ /*
+ * Compute z' = 2*y*z.
+ */
+ f256_montymul(t4, P->y, P->z);
+ f256_add(P->z, t4, t4);
+
+ /*
+ * Compute y' = m*(s - x') - 8*y^4. Note that we already have
+ * 2*y^2 in t3.
+ */
+ f256_sub(t2, t2, P->x);
+ f256_montymul(P->y, t1, t2);
+ f256_montysquare(t4, t3);
+ f256_add(t4, t4, t4);
+ f256_sub(P->y, P->y, t4);
+}
+
+/*
+ * Point addition (Jacobian coordinates): P1 is replaced with P1+P2.
+ * This function computes the wrong result in the following cases:
+ *
+ * - If P1 == 0 but P2 != 0
+ * - If P1 != 0 but P2 == 0
+ * - If P1 == P2
+ *
+ * In all three cases, P1 is set to the point at infinity.
+ *
+ * Returned value is 0 if one of the following occurs:
+ *
+ * - P1 and P2 have the same Y coordinate.
+ * - P1 == 0 and P2 == 0.
+ * - The Y coordinate of one of the points is 0 and the other point is
+ * the point at infinity.
+ *
+ * The third case cannot actually happen with valid points, since a point
+ * with Y == 0 is a point of order 2, and there is no point of order 2 on
+ * curve P-256.
+ *
+ * Therefore, assuming that P1 != 0 and P2 != 0 on input, then the caller
+ * can apply the following:
+ *
+ * - If the result is not the point at infinity, then it is correct.
+ * - Otherwise, if the returned value is 1, then this is a case of
+ * P1+P2 == 0, so the result is indeed the point at infinity.
+ * - Otherwise, P1 == P2, so a "double" operation should have been
+ * performed.
+ *
+ * Note that you can get a returned value of 0 with a correct result,
+ * e.g. if P1 and P2 have the same Y coordinate, but distinct X coordinates.
+ */
+static uint32_t
+p256_add(p256_jacobian *P1, const p256_jacobian *P2)
+{
+ /*
+ * 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
+ */
+ uint64_t t1[4], t2[4], t3[4], t4[4], t5[4], t6[4], t7[4], tt;
+ uint32_t ret;
+
+ /*
+ * Compute u1 = x1*z2^2 (in t1) and s1 = y1*z2^3 (in t3).
+ */
+ f256_montysquare(t3, P2->z);
+ f256_montymul(t1, P1->x, t3);
+ f256_montymul(t4, P2->z, t3);
+ f256_montymul(t3, P1->y, t4);
+
+ /*
+ * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
+ */
+ f256_montysquare(t4, P1->z);
+ f256_montymul(t2, P2->x, t4);
+ f256_montymul(t5, P1->z, t4);
+ f256_montymul(t4, P2->y, t5);
+
+ /*
+ * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4).
+ * We need to test whether r is zero, so we will do some extra
+ * reduce.
+ */
+ f256_sub(t2, t2, t1);
+ f256_sub(t4, t4, t3);
+ f256_final_reduce(t4);
+ tt = t4[0] | t4[1] | t4[2] | t4[3];
+ ret = (uint32_t)(tt | (tt >> 32));
+ ret = (ret | -ret) >> 31;
+
+ /*
+ * Compute u1*h^2 (in t6) and h^3 (in t5);
+ */
+ f256_montysquare(t7, t2);
+ f256_montymul(t6, t1, t7);
+ f256_montymul(t5, t7, t2);
+
+ /*
+ * Compute x3 = r^2 - h^3 - 2*u1*h^2.
+ */
+ f256_montysquare(P1->x, t4);
+ f256_sub(P1->x, P1->x, t5);
+ f256_sub(P1->x, P1->x, t6);
+ f256_sub(P1->x, P1->x, t6);
+
+ /*
+ * Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
+ */
+ f256_sub(t6, t6, P1->x);
+ f256_montymul(P1->y, t4, t6);
+ f256_montymul(t1, t5, t3);
+ f256_sub(P1->y, P1->y, t1);
+
+ /*
+ * Compute z3 = h*z1*z2.
+ */
+ f256_montymul(t1, P1->z, P2->z);
+ f256_montymul(P1->z, t1, t2);
+
+ return ret;
+}
+
+/*
+ * Point addition (mixed coordinates): P1 is replaced with P1+P2.
+ * This is a specialised function for the case when P2 is a non-zero point
+ * in affine coordinates.
+ *
+ * This function computes the wrong result in the following cases:
+ *
+ * - If P1 == 0
+ * - If P1 == P2
+ *
+ * In both cases, P1 is set to the point at infinity.
+ *
+ * Returned value is 0 if one of the following occurs:
+ *
+ * - P1 and P2 have the same Y (affine) coordinate.
+ * - The Y coordinate of P2 is 0 and P1 is the point at infinity.
+ *
+ * The second case cannot actually happen with valid points, since a point
+ * with Y == 0 is a point of order 2, and there is no point of order 2 on
+ * curve P-256.
+ *
+ * Therefore, assuming that P1 != 0 on input, then the caller
+ * can apply the following:
+ *
+ * - If the result is not the point at infinity, then it is correct.
+ * - Otherwise, if the returned value is 1, then this is a case of
+ * P1+P2 == 0, so the result is indeed the point at infinity.
+ * - Otherwise, P1 == P2, so a "double" operation should have been
+ * performed.
+ *
+ * Again, a value of 0 may be returned in some cases where the addition
+ * result is correct.
+ */
+static uint32_t
+p256_add_mixed(p256_jacobian *P1, const p256_affine *P2)
+{
+ /*
+ * Addtions formulas are:
+ *
+ * u1 = x1
+ * u2 = x2 * z1^2
+ * s1 = y1
+ * 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
+ */
+ uint64_t t1[4], t2[4], t3[4], t4[4], t5[4], t6[4], t7[4], tt;
+ uint32_t ret;
+
+ /*
+ * Compute u1 = x1 (in t1) and s1 = y1 (in t3).
+ */
+ memcpy(t1, P1->x, sizeof t1);
+ memcpy(t3, P1->y, sizeof t3);
+
+ /*
+ * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
+ */
+ f256_montysquare(t4, P1->z);
+ f256_montymul(t2, P2->x, t4);
+ f256_montymul(t5, P1->z, t4);
+ f256_montymul(t4, P2->y, t5);
+
+ /*
+ * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4).
+ * We need to test whether r is zero, so we will do some extra
+ * reduce.
+ */
+ f256_sub(t2, t2, t1);
+ f256_sub(t4, t4, t3);
+ f256_final_reduce(t4);
+ tt = t4[0] | t4[1] | t4[2] | t4[3];
+ ret = (uint32_t)(tt | (tt >> 32));
+ ret = (ret | -ret) >> 31;
+
+ /*
+ * Compute u1*h^2 (in t6) and h^3 (in t5);
+ */
+ f256_montysquare(t7, t2);
+ f256_montymul(t6, t1, t7);
+ f256_montymul(t5, t7, t2);
+
+ /*
+ * Compute x3 = r^2 - h^3 - 2*u1*h^2.
+ */
+ f256_montysquare(P1->x, t4);
+ f256_sub(P1->x, P1->x, t5);
+ f256_sub(P1->x, P1->x, t6);
+ f256_sub(P1->x, P1->x, t6);
+
+ /*
+ * Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
+ */
+ f256_sub(t6, t6, P1->x);
+ f256_montymul(P1->y, t4, t6);
+ f256_montymul(t1, t5, t3);
+ f256_sub(P1->y, P1->y, t1);
+
+ /*
+ * Compute z3 = h*z1*z2.
+ */
+ f256_montymul(P1->z, P1->z, t2);
+
+ return ret;
+}
+
+#if 0
+/* unused */
+/*
+ * Point addition (mixed coordinates, complete): P1 is replaced with P1+P2.
+ * This is a specialised function for the case when P2 is a non-zero point
+ * in affine coordinates.
+ *
+ * This function returns the correct result in all cases.
+ */
+static uint32_t
+p256_add_complete_mixed(p256_jacobian *P1, const p256_affine *P2)
+{
+ /*
+ * Addtions formulas, in the general case, are:
+ *
+ * u1 = x1
+ * u2 = x2 * z1^2
+ * s1 = y1
+ * 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
+ *
+ * These formulas mishandle the two following cases:
+ *
+ * - If P1 is the point-at-infinity (z1 = 0), then z3 is
+ * incorrectly set to 0.
+ *
+ * - If P1 = P2, then u1 = u2 and s1 = s2, and x3, y3 and z3
+ * are all set to 0.
+ *
+ * However, if P1 + P2 = 0, then u1 = u2 but s1 != s2, and then
+ * we correctly get z3 = 0 (the point-at-infinity).
+ *
+ * To fix the case P1 = 0, we perform at the end a copy of P2
+ * over P1, conditional to z1 = 0.
+ *
+ * For P1 = P2: in that case, both h and r are set to 0, and
+ * we get x3, y3 and z3 equal to 0. We can test for that
+ * occurrence to make a mask which will be all-one if P1 = P2,
+ * or all-zero otherwise; then we can compute the double of P2
+ * and add it, combined with the mask, to (x3,y3,z3).
+ *
+ * Using the doubling formulas in p256_double() on (x2,y2),
+ * simplifying since P2 is affine (i.e. z2 = 1, implicitly),
+ * we get:
+ * s = 4*x2*y2^2
+ * m = 3*(x2 + 1)*(x2 - 1)
+ * x' = m^2 - 2*s
+ * y' = m*(s - x') - 8*y2^4
+ * z' = 2*y2
+ * which requires only 6 multiplications. Added to the 11
+ * multiplications of the normal mixed addition in Jacobian
+ * coordinates, we get a cost of 17 multiplications in total.
+ */
+ uint64_t t1[4], t2[4], t3[4], t4[4], t5[4], t6[4], t7[4], tt, zz;
+ int i;
+
+ /*
+ * Set zz to -1 if P1 is the point at infinity, 0 otherwise.
+ */
+ zz = P1->z[0] | P1->z[1] | P1->z[2] | P1->z[3];
+ zz = ((zz | -zz) >> 63) - (uint64_t)1;
+
+ /*
+ * Compute u1 = x1 (in t1) and s1 = y1 (in t3).
+ */
+ memcpy(t1, P1->x, sizeof t1);
+ memcpy(t3, P1->y, sizeof t3);
+
+ /*
+ * Compute u2 = x2*z1^2 (in t2) and s2 = y2*z1^3 (in t4).
+ */
+ f256_montysquare(t4, P1->z);
+ f256_montymul(t2, P2->x, t4);
+ f256_montymul(t5, P1->z, t4);
+ f256_montymul(t4, P2->y, t5);
+
+ /*
+ * Compute h = h2 - u1 (in t2) and r = s2 - s1 (in t4).
+ * reduce.
+ */
+ f256_sub(t2, t2, t1);
+ f256_sub(t4, t4, t3);
+
+ /*
+ * If both h = 0 and r = 0, then P1 = P2, and we want to set
+ * the mask tt to -1; otherwise, the mask will be 0.
+ */
+ f256_final_reduce(t2);
+ f256_final_reduce(t4);
+ tt = t2[0] | t2[1] | t2[2] | t2[3] | t4[0] | t4[1] | t4[2] | t4[3];
+ tt = ((tt | -tt) >> 63) - (uint64_t)1;
+
+ /*
+ * Compute u1*h^2 (in t6) and h^3 (in t5);
+ */
+ f256_montysquare(t7, t2);
+ f256_montymul(t6, t1, t7);
+ f256_montymul(t5, t7, t2);
+
+ /*
+ * Compute x3 = r^2 - h^3 - 2*u1*h^2.
+ */
+ f256_montysquare(P1->x, t4);
+ f256_sub(P1->x, P1->x, t5);
+ f256_sub(P1->x, P1->x, t6);
+ f256_sub(P1->x, P1->x, t6);
+
+ /*
+ * Compute y3 = r*(u1*h^2 - x3) - s1*h^3.
+ */
+ f256_sub(t6, t6, P1->x);
+ f256_montymul(P1->y, t4, t6);
+ f256_montymul(t1, t5, t3);
+ f256_sub(P1->y, P1->y, t1);
+
+ /*
+ * Compute z3 = h*z1.
+ */
+ f256_montymul(P1->z, P1->z, t2);
+
+ /*
+ * The "double" result, in case P1 = P2.
+ */
+
+ /*
+ * Compute z' = 2*y2 (in t1).
+ */
+ f256_add(t1, P2->y, P2->y);
+
+ /*
+ * Compute 2*(y2^2) (in t2) and s = 4*x2*(y2^2) (in t3).
+ */
+ f256_montysquare(t2, P2->y);
+ f256_add(t2, t2, t2);
+ f256_add(t3, t2, t2);
+ f256_montymul(t3, P2->x, t3);
+
+ /*
+ * Compute m = 3*(x2^2 - 1) (in t4).
+ */
+ f256_montysquare(t4, P2->x);
+ f256_sub(t4, t4, F256_R);
+ f256_add(t5, t4, t4);
+ f256_add(t4, t4, t5);
+
+ /*
+ * Compute x' = m^2 - 2*s (in t5).
+ */
+ f256_montysquare(t5, t4);
+ f256_sub(t5, t3);
+ f256_sub(t5, t3);
+
+ /*
+ * Compute y' = m*(s - x') - 8*y2^4 (in t6).
+ */
+ f256_sub(t6, t3, t5);
+ f256_montymul(t6, t6, t4);
+ f256_montysquare(t7, t2);
+ f256_sub(t6, t6, t7);
+ f256_sub(t6, t6, t7);
+
+ /*
+ * We now have the alternate (doubling) coordinates in (t5,t6,t1).
+ * We combine them with (x3,y3,z3).
+ */
+ for (i = 0; i < 4; i ++) {
+ P1->x[i] |= tt & t5[i];
+ P1->y[i] |= tt & t6[i];
+ P1->z[i] |= tt & t1[i];
+ }
+
+ /*
+ * If P1 = 0, then we get z3 = 0 (which is invalid); if z1 is 0,
+ * then we want to replace the result with a copy of P2. The
+ * test on z1 was done at the start, in the zz mask.
+ */
+ for (i = 0; i < 4; i ++) {
+ P1->x[i] ^= zz & (P1->x[i] ^ P2->x[i]);
+ P1->y[i] ^= zz & (P1->y[i] ^ P2->y[i]);
+ P1->z[i] ^= zz & (P1->z[i] ^ F256_R[i]);
+ }
+}
+#endif
+
+/*
+ * Inner function for computing a point multiplication. A window is
+ * provided, with points 1*P to 15*P in affine coordinates.
+ *
+ * Assumptions:
+ * - All provided points are valid points on the curve.
+ * - Multiplier is non-zero, and smaller than the curve order.
+ * - Everything is in Montgomery representation.
+ */
+static void
+point_mul_inner(p256_jacobian *R, const p256_affine *W,
+ const unsigned char *k, size_t klen)
+{
+ p256_jacobian Q;
+ uint32_t qz;
+
+ memset(&Q, 0, sizeof Q);
+ qz = 1;
+ while (klen -- > 0) {
+ int i;
+ unsigned bk;
+
+ bk = *k ++;
+ for (i = 0; i < 2; i ++) {
+ uint32_t bits;
+ uint32_t bnz;
+ p256_affine T;
+ p256_jacobian U;
+ uint32_t n;
+ int j;
+ uint64_t m;
+
+ p256_double(&Q);
+ p256_double(&Q);
+ p256_double(&Q);
+ p256_double(&Q);
+ bits = (bk >> 4) & 0x0F;
+ bnz = NEQ(bits, 0);
+
+ /*
+ * Lookup point in window. If the bits are 0,
+ * we get something invalid, which is not a
+ * problem because we will use it only if the
+ * bits are non-zero.
+ */
+ memset(&T, 0, sizeof T);
+ for (n = 0; n < 15; n ++) {
+ m = -(uint64_t)EQ(bits, n + 1);
+ T.x[0] |= m & W[n].x[0];
+ T.x[1] |= m & W[n].x[1];
+ T.x[2] |= m & W[n].x[2];
+ T.x[3] |= m & W[n].x[3];
+ T.y[0] |= m & W[n].y[0];
+ T.y[1] |= m & W[n].y[1];
+ T.y[2] |= m & W[n].y[2];
+ T.y[3] |= m & W[n].y[3];
+ }
+
+ U = Q;
+ p256_add_mixed(&U, &T);
+
+ /*
+ * If qz is still 1, then Q was all-zeros, and this
+ * is conserved through p256_double().
+ */
+ m = -(uint64_t)(bnz & qz);
+ for (j = 0; j < 4; j ++) {
+ Q.x[j] |= m & T.x[j];
+ Q.y[j] |= m & T.y[j];
+ Q.z[j] |= m & F256_R[j];
+ }
+ CCOPY(bnz & ~qz, &Q, &U, sizeof Q);
+ qz &= ~bnz;
+ bk <<= 4;
+ }
+ }
+ *R = Q;
+}
+
+/*
+ * Convert a window from Jacobian to affine coordinates. A single
+ * field inversion is used. This function works for windows up to
+ * 32 elements.
+ *
+ * The destination array (aff[]) and the source array (jac[]) may
+ * overlap, provided that the start of aff[] is not after the start of
+ * jac[]. Even if the arrays do _not_ overlap, the source array is
+ * modified.
+ */
+static void
+window_to_affine(p256_affine *aff, p256_jacobian *jac, int num)
+{
+ /*
+ * Convert the window points to affine coordinates. We use the
+ * following trick to mutualize the inversion computation: if
+ * we have z1, z2, z3, and z4, and want to inverse all of them,
+ * we compute u = 1/(z1*z2*z3*z4), and then we have:
+ * 1/z1 = u*z2*z3*z4
+ * 1/z2 = u*z1*z3*z4
+ * 1/z3 = u*z1*z2*z4
+ * 1/z4 = u*z1*z2*z3
+ *
+ * The partial products are computed recursively:
+ *
+ * - on input (z_1,z_2), return (z_2,z_1) and z_1*z_2
+ * - on input (z_1,z_2,... z_n):
+ * recurse on (z_1,z_2,... z_(n/2)) -> r1 and m1
+ * recurse on (z_(n/2+1),z_(n/2+2)... z_n) -> r2 and m2
+ * multiply elements of r1 by m2 -> s1
+ * multiply elements of r2 by m1 -> s2
+ * return r1||r2 and m1*m2
+ *
+ * In the example below, we suppose that we have 14 elements.
+ * Let z1, z2,... zE be the 14 values to invert (index noted in
+ * hexadecimal, starting at 1).
+ *
+ * - Depth 1:
+ * swap(z1, z2); z12 = z1*z2
+ * swap(z3, z4); z34 = z3*z4
+ * swap(z5, z6); z56 = z5*z6
+ * swap(z7, z8); z78 = z7*z8
+ * swap(z9, zA); z9A = z9*zA
+ * swap(zB, zC); zBC = zB*zC
+ * swap(zD, zE); zDE = zD*zE
+ *
+ * - Depth 2:
+ * z1 <- z1*z34, z2 <- z2*z34, z3 <- z3*z12, z4 <- z4*z12
+ * z1234 = z12*z34
+ * z5 <- z5*z78, z6 <- z6*z78, z7 <- z7*z56, z8 <- z8*z56
+ * z5678 = z56*z78
+ * z9 <- z9*zBC, zA <- zA*zBC, zB <- zB*z9A, zC <- zC*z9A
+ * z9ABC = z9A*zBC
+ *
+ * - Depth 3:
+ * z1 <- z1*z5678, z2 <- z2*z5678, z3 <- z3*z5678, z4 <- z4*z5678
+ * z5 <- z5*z1234, z6 <- z6*z1234, z7 <- z7*z1234, z8 <- z8*z1234
+ * z12345678 = z1234*z5678
+ * z9 <- z9*zDE, zA <- zA*zDE, zB <- zB*zDE, zC <- zC*zDE
+ * zD <- zD*z9ABC, zE*z9ABC
+ * z9ABCDE = z9ABC*zDE
+ *
+ * - Depth 4:
+ * multiply z1..z8 by z9ABCDE
+ * multiply z9..zE by z12345678
+ * final z = z12345678*z9ABCDE
+ */
+
+ uint64_t z[16][4];
+ int i, k, s;
+#define zt (z[15])
+#define zu (z[14])
+#define zv (z[13])
+
+ /*
+ * First recursion step (pairwise swapping and multiplication).
+ * If there is an odd number of elements, then we "invent" an
+ * extra one with coordinate Z = 1 (in Montgomery representation).
+ */
+ for (i = 0; (i + 1) < num; i += 2) {
+ memcpy(zt, jac[i].z, sizeof zt);
+ memcpy(jac[i].z, jac[i + 1].z, sizeof zt);
+ memcpy(jac[i + 1].z, zt, sizeof zt);
+ f256_montymul(z[i >> 1], jac[i].z, jac[i + 1].z);
+ }
+ if ((num & 1) != 0) {
+ memcpy(z[num >> 1], jac[num - 1].z, sizeof zt);
+ memcpy(jac[num - 1].z, F256_R, sizeof F256_R);
+ }
+
+ /*
+ * Perform further recursion steps. At the entry of each step,
+ * the process has been done for groups of 's' points. The
+ * integer k is the log2 of s.
+ */
+ for (k = 1, s = 2; s < num; k ++, s <<= 1) {
+ int n;
+
+ for (i = 0; i < num; i ++) {
+ f256_montymul(jac[i].z, jac[i].z, z[(i >> k) ^ 1]);
+ }
+ n = (num + s - 1) >> k;
+ for (i = 0; i < (n >> 1); i ++) {
+ f256_montymul(z[i], z[i << 1], z[(i << 1) + 1]);
+ }
+ if ((n & 1) != 0) {
+ memmove(z[n >> 1], z[n], sizeof zt);
+ }
+ }
+
+ /*
+ * Invert the final result, and convert all points.
+ */
+ f256_invert(zt, z[0]);
+ for (i = 0; i < num; i ++) {
+ f256_montymul(zv, jac[i].z, zt);
+ f256_montysquare(zu, zv);
+ f256_montymul(zv, zv, zu);
+ f256_montymul(aff[i].x, jac[i].x, zu);
+ f256_montymul(aff[i].y, jac[i].y, zv);
+ }
+}
+
+/*
+ * Multiply the provided point by an integer.
+ * Assumptions:
+ * - Source point is a valid curve point.
+ * - Source point is not the point-at-infinity.
+ * - Integer is not 0, and is lower than the curve order.
+ * If these conditions are not met, then the result is indeterminate
+ * (but the process is still constant-time).
+ */
+static void
+p256_mul(p256_jacobian *P, const unsigned char *k, size_t klen)
+{
+ union {
+ p256_affine aff[15];
+ p256_jacobian jac[15];
+ } window;
+ int i;
+
+ /*
+ * Compute window, in Jacobian coordinates.
+ */
+ window.jac[0] = *P;
+ for (i = 2; i < 16; i ++) {
+ window.jac[i - 1] = window.jac[(i >> 1) - 1];
+ if ((i & 1) == 0) {
+ p256_double(&window.jac[i - 1]);
+ } else {
+ p256_add(&window.jac[i - 1], &window.jac[i >> 1]);
+ }
+ }
+
+ /*
+ * Convert the window points to affine coordinates. Point
+ * window[0] is the source point, already in affine coordinates.
+ */
+ window_to_affine(window.aff, window.jac, 15);
+
+ /*
+ * Perform point multiplication.
+ */
+ point_mul_inner(P, window.aff, k, klen);
+}
+
+/*
+ * Precomputed window for the conventional generator: P256_Gwin[n]
+ * contains (n+1)*G (affine coordinates, in Montgomery representation).
+ */
+static const p256_affine P256_Gwin[] = {
+ {
+ { 0x79E730D418A9143C, 0x75BA95FC5FEDB601,
+ 0x79FB732B77622510, 0x18905F76A53755C6 },
+ { 0xDDF25357CE95560A, 0x8B4AB8E4BA19E45C,
+ 0xD2E88688DD21F325, 0x8571FF1825885D85 }
+ },
+ {
+ { 0x850046D410DDD64D, 0xAA6AE3C1A433827D,
+ 0x732205038D1490D9, 0xF6BB32E43DCF3A3B },
+ { 0x2F3648D361BEE1A5, 0x152CD7CBEB236FF8,
+ 0x19A8FB0E92042DBE, 0x78C577510A5B8A3B }
+ },
+ {
+ { 0xFFAC3F904EEBC127, 0xB027F84A087D81FB,
+ 0x66AD77DD87CBBC98, 0x26936A3FB6FF747E },
+ { 0xB04C5C1FC983A7EB, 0x583E47AD0861FE1A,
+ 0x788208311A2EE98E, 0xD5F06A29E587CC07 }
+ },
+ {
+ { 0x74B0B50D46918DCC, 0x4650A6EDC623C173,
+ 0x0CDAACACE8100AF2, 0x577362F541B0176B },
+ { 0x2D96F24CE4CBABA6, 0x17628471FAD6F447,
+ 0x6B6C36DEE5DDD22E, 0x84B14C394C5AB863 }
+ },
+ {
+ { 0xBE1B8AAEC45C61F5, 0x90EC649A94B9537D,
+ 0x941CB5AAD076C20C, 0xC9079605890523C8 },
+ { 0xEB309B4AE7BA4F10, 0x73C568EFE5EB882B,
+ 0x3540A9877E7A1F68, 0x73A076BB2DD1E916 }
+ },
+ {
+ { 0x403947373E77664A, 0x55AE744F346CEE3E,
+ 0xD50A961A5B17A3AD, 0x13074B5954213673 },
+ { 0x93D36220D377E44B, 0x299C2B53ADFF14B5,
+ 0xF424D44CEF639F11, 0xA4C9916D4A07F75F }
+ },
+ {
+ { 0x0746354EA0173B4F, 0x2BD20213D23C00F7,
+ 0xF43EAAB50C23BB08, 0x13BA5119C3123E03 },
+ { 0x2847D0303F5B9D4D, 0x6742F2F25DA67BDD,
+ 0xEF933BDC77C94195, 0xEAEDD9156E240867 }
+ },
+ {
+ { 0x27F14CD19499A78F, 0x462AB5C56F9B3455,
+ 0x8F90F02AF02CFC6B, 0xB763891EB265230D },
+ { 0xF59DA3A9532D4977, 0x21E3327DCF9EBA15,
+ 0x123C7B84BE60BBF0, 0x56EC12F27706DF76 }
+ },
+ {
+ { 0x75C96E8F264E20E8, 0xABE6BFED59A7A841,
+ 0x2CC09C0444C8EB00, 0xE05B3080F0C4E16B },
+ { 0x1EB7777AA45F3314, 0x56AF7BEDCE5D45E3,
+ 0x2B6E019A88B12F1A, 0x086659CDFD835F9B }
+ },
+ {
+ { 0x2C18DBD19DC21EC8, 0x98F9868A0FCF8139,
+ 0x737D2CD648250B49, 0xCC61C94724B3428F },
+ { 0x0C2B407880DD9E76, 0xC43A8991383FBE08,
+ 0x5F7D2D65779BE5D2, 0x78719A54EB3B4AB5 }
+ },
+ {
+ { 0xEA7D260A6245E404, 0x9DE407956E7FDFE0,
+ 0x1FF3A4158DAC1AB5, 0x3E7090F1649C9073 },
+ { 0x1A7685612B944E88, 0x250F939EE57F61C8,
+ 0x0C0DAA891EAD643D, 0x68930023E125B88E }
+ },
+ {
+ { 0x04B71AA7D2697768, 0xABDEDEF5CA345A33,
+ 0x2409D29DEE37385E, 0x4EE1DF77CB83E156 },
+ { 0x0CAC12D91CBB5B43, 0x170ED2F6CA895637,
+ 0x28228CFA8ADE6D66, 0x7FF57C9553238ACA }
+ },
+ {
+ { 0xCCC425634B2ED709, 0x0E356769856FD30D,
+ 0xBCBCD43F559E9811, 0x738477AC5395B759 },
+ { 0x35752B90C00EE17F, 0x68748390742ED2E3,
+ 0x7CD06422BD1F5BC1, 0xFBC08769C9E7B797 }
+ },
+ {
+ { 0xA242A35BB0CF664A, 0x126E48F77F9707E3,
+ 0x1717BF54C6832660, 0xFAAE7332FD12C72E },
+ { 0x27B52DB7995D586B, 0xBE29569E832237C2,
+ 0xE8E4193E2A65E7DB, 0x152706DC2EAA1BBB }
+ },
+ {
+ { 0x72BCD8B7BC60055B, 0x03CC23EE56E27E4B,
+ 0xEE337424E4819370, 0xE2AA0E430AD3DA09 },
+ { 0x40B8524F6383C45D, 0xD766355442A41B25,
+ 0x64EFA6DE778A4797, 0x2042170A7079ADF4 }
+ }
+};
+
+/*
+ * Multiply the conventional generator of the curve by the provided
+ * integer. Return is written in *P.
+ *
+ * Assumptions:
+ * - Integer is not 0, and is lower than the curve order.
+ * If this conditions is not met, then the result is indeterminate
+ * (but the process is still constant-time).
+ */
+static void
+p256_mulgen(p256_jacobian *P, const unsigned char *k, size_t klen)
+{
+ point_mul_inner(P, P256_Gwin, k, klen);
+}
+
+/*
+ * Return 1 if all of the following hold:
+ * - klen <= 32
+ * - k != 0
+ * - k is lower than the curve order
+ * Otherwise, return 0.
+ *
+ * Constant-time behaviour: only klen may be observable.
+ */
+static uint32_t
+check_scalar(const unsigned char *k, size_t klen)
+{
+ uint32_t z;
+ int32_t c;
+ size_t u;
+
+ if (klen > 32) {
+ return 0;
+ }
+ z = 0;
+ for (u = 0; u < klen; u ++) {
+ z |= k[u];
+ }
+ if (klen == 32) {
+ c = 0;
+ for (u = 0; u < klen; u ++) {
+ c |= -(int32_t)EQ0(c) & CMP(k[u], P256_N[u]);
+ }
+ } else {
+ c = -1;
+ }
+ return NEQ(z, 0) & LT0(c);
+}
+
+static uint32_t
+api_mul(unsigned char *G, size_t Glen,
+ const unsigned char *k, size_t klen, int curve)
+{
+ uint32_t r;
+ p256_jacobian P;
+
+ (void)curve;
+ if (Glen != 65) {
+ return 0;
+ }
+ r = check_scalar(k, klen);
+ r &= point_decode(&P, G);
+ p256_mul(&P, k, klen);
+ r &= point_encode(G, &P);
+ return r;
+}
+
+static size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *k, size_t klen, int curve)
+{
+ p256_jacobian P;
+
+ (void)curve;
+ p256_mulgen(&P, k, klen);
+ point_encode(R, &P);
+ return 65;
+}
+
+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)
+{
+ /*
+ * We might want to use Shamir's trick here: make a composite
+ * window of u*P+v*Q points, to merge the two doubling-ladders
+ * into one. This, however, has some complications:
+ *
+ * - During the computation, we may hit the point-at-infinity.
+ * Thus, we would need p256_add_complete_mixed() (complete
+ * formulas for point addition), with a higher cost (17 muls
+ * instead of 11).
+ *
+ * - A 4-bit window would be too large, since it would involve
+ * 16*16-1 = 255 points. For the same window size as in the
+ * p256_mul() case, we would need to reduce the window size
+ * to 2 bits, and thus perform twice as many non-doubling
+ * point additions.
+ *
+ * - The window may itself contain the point-at-infinity, and
+ * thus cannot be in all generality be made of affine points.
+ * Instead, we would need to make it a window of points in
+ * Jacobian coordinates. Even p256_add_complete_mixed() would
+ * be inappropriate.
+ *
+ * For these reasons, the code below performs two separate
+ * point multiplications, then computes the final point addition
+ * (which is both a "normal" addition, and a doubling, to handle
+ * all cases).
+ */
+
+ p256_jacobian P, Q;
+ uint32_t r, t, s;
+ uint64_t z;
+
+ (void)curve;
+ if (len != 65) {
+ return 0;
+ }
+ r = point_decode(&P, A);
+ p256_mul(&P, x, xlen);
+ if (B == NULL) {
+ p256_mulgen(&Q, y, ylen);
+ } else {
+ r &= point_decode(&Q, B);
+ p256_mul(&Q, y, ylen);
+ }
+
+ /*
+ * The final addition may fail in case both points are equal.
+ */
+ t = p256_add(&P, &Q);
+ f256_final_reduce(P.z);
+ z = P.z[0] | P.z[1] | P.z[2] | P.z[3];
+ s = EQ((uint32_t)(z | (z >> 32)), 0);
+ p256_double(&Q);
+
+ /*
+ * If s is 1 then either P+Q = 0 (t = 1) or P = Q (t = 0). So we
+ * have the following:
+ *
+ * s = 0, t = 0 return P (normal addition)
+ * s = 0, t = 1 return P (normal addition)
+ * s = 1, t = 0 return Q (a 'double' case)
+ * s = 1, t = 1 report an error (P+Q = 0)
+ */
+ CCOPY(s & ~t, &P, &Q, sizeof Q);
+ point_encode(A, &P);
+ r &= ~(s & t);
+ return r;
+}
+
+/* see bearssl_ec.h */
+const br_ec_impl br_ec_p256_m64 = {
+ (uint32_t)0x00800000,
+ &api_generator,
+ &api_order,
+ &api_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
+
+/* see bearssl_ec.h */
+const br_ec_impl *
+br_ec_p256_m64_get(void)
+{
+ return &br_ec_p256_m64;
+}
+
+#else
+
+/* see bearssl_ec.h */
+const br_ec_impl *
+br_ec_p256_m64_get(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/contrib/bearssl/src/ec/ec_prime_i15.c b/contrib/bearssl/src/ec/ec_prime_i15.c
new file mode 100644
index 000000000000..0f210f240475
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_prime_i15.c
@@ -0,0 +1,820 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 p
+ * - R^2 mod p (R = 2^(15k) for the smallest k such that R >= p)
+ * - b*R mod p (b is the second curve equation parameter)
+ */
+
+static const uint16_t P256_P[] = {
+ 0x0111,
+ 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x003F, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x1000, 0x0000, 0x4000, 0x7FFF,
+ 0x7FFF, 0x0001
+};
+
+static const uint16_t P256_R2[] = {
+ 0x0111,
+ 0x0000, 0x6000, 0x0000, 0x0000, 0x0000, 0x0000, 0x7FFC, 0x7FFF,
+ 0x7FBF, 0x7FFF, 0x7FBF, 0x7FFF, 0x7FFF, 0x7FFF, 0x77FF, 0x7FFF,
+ 0x4FFF, 0x0000
+};
+
+static const uint16_t P256_B[] = {
+ 0x0111,
+ 0x770C, 0x5EEF, 0x29C4, 0x3EC4, 0x6273, 0x0486, 0x4543, 0x3993,
+ 0x3C01, 0x6B56, 0x212E, 0x57EE, 0x4882, 0x204B, 0x7483, 0x3C16,
+ 0x0187, 0x0000
+};
+
+static const uint16_t P384_P[] = {
+ 0x0199,
+ 0x7FFF, 0x7FFF, 0x0003, 0x0000, 0x0000, 0x0000, 0x7FC0, 0x7FFF,
+ 0x7EFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
+ 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
+ 0x7FFF, 0x01FF
+};
+
+static const uint16_t P384_R2[] = {
+ 0x0199,
+ 0x1000, 0x0000, 0x0000, 0x7FFF, 0x7FFF, 0x0001, 0x0000, 0x0010,
+ 0x0000, 0x0000, 0x0000, 0x7F00, 0x7FFF, 0x01FF, 0x0000, 0x1000,
+ 0x0000, 0x2000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000
+};
+
+static const uint16_t P384_B[] = {
+ 0x0199,
+ 0x7333, 0x2096, 0x70D1, 0x2310, 0x3020, 0x6197, 0x1464, 0x35BB,
+ 0x70CA, 0x0117, 0x1920, 0x4136, 0x5FC8, 0x5713, 0x4938, 0x7DD2,
+ 0x4DD2, 0x4A71, 0x0220, 0x683E, 0x2C87, 0x4DB1, 0x7BFF, 0x6C09,
+ 0x0452, 0x0084
+};
+
+static const uint16_t P521_P[] = {
+ 0x022B,
+ 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
+ 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
+ 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
+ 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF,
+ 0x7FFF, 0x7FFF, 0x07FF
+};
+
+static const uint16_t P521_R2[] = {
+ 0x022B,
+ 0x0100, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000,
+ 0x0000, 0x0000, 0x0000
+};
+
+static const uint16_t P521_B[] = {
+ 0x022B,
+ 0x7002, 0x6A07, 0x751A, 0x228F, 0x71EF, 0x5869, 0x20F4, 0x1EFC,
+ 0x7357, 0x37E0, 0x4EEC, 0x605E, 0x1652, 0x26F6, 0x31FA, 0x4A8F,
+ 0x6193, 0x3C2A, 0x3C42, 0x48C7, 0x3489, 0x6771, 0x4C57, 0x5CCD,
+ 0x2725, 0x545B, 0x503B, 0x5B42, 0x21A0, 0x2534, 0x687E, 0x70E4,
+ 0x1618, 0x27D7, 0x0465
+};
+
+typedef struct {
+ const uint16_t *p;
+ const uint16_t *b;
+ const uint16_t *R2;
+ uint16_t p0i;
+ size_t point_len;
+} curve_params;
+
+static inline const curve_params *
+id_to_curve(int curve)
+{
+ static const curve_params pp[] = {
+ { P256_P, P256_B, P256_R2, 0x0001, 65 },
+ { P384_P, P384_B, P384_R2, 0x0001, 97 },
+ { P521_P, P521_B, P521_R2, 0x0001, 133 }
+ };
+
+ return &pp[curve - BR_EC_secp256r1];
+}
+
+#define I15_LEN ((BR_MAX_EC_SIZE + 29) / 15)
+
+/*
+ * 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 {
+ uint16_t c[3][I15_LEN];
+} jacobian;
+
+/*
+ * We use a custom interpreter that uses a dozen registers, and
+ * only six 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;
+ uint16_t t[13][I15_LEN];
+ size_t u;
+
+ r = 1;
+
+ /*
+ * Copy the two operands in the dedicated registers.
+ */
+ memcpy(t[P1x], P1->c, 3 * I15_LEN * sizeof(uint16_t));
+ memcpy(t[P2x], P2->c, 3 * I15_LEN * sizeof(uint16_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], I15_LEN * sizeof(uint16_t));
+ break;
+ case 1:
+ ctl = br_i15_add(t[d], t[a], 1);
+ ctl |= NOT(br_i15_sub(t[d], cc->p, 0));
+ br_i15_sub(t[d], cc->p, ctl);
+ break;
+ case 2:
+ br_i15_add(t[d], cc->p, br_i15_sub(t[d], t[a], 1));
+ break;
+ case 3:
+ br_i15_montymul(t[d], t[a], t[b], cc->p, cc->p0i);
+ break;
+ case 4:
+ plen = (cc->p[0] - (cc->p[0] >> 4) + 7) >> 3;
+ br_i15_encode(tp, plen, cc->p);
+ tp[plen - 1] -= 2;
+ br_i15_modpow(t[d], tp, plen,
+ cc->p, cc->p0i, t[a], t[b]);
+ break;
+ default:
+ r &= ~br_i15_iszero(t[d]);
+ break;
+ }
+ }
+
+ /*
+ * Copy back result.
+ */
+ memcpy(P1->c, t[P1x], 3 * I15_LEN * sizeof(uint16_t));
+ return r;
+}
+
+static void
+set_one(uint16_t *x, const uint16_t *p)
+{
+ size_t plen;
+
+ plen = (p[0] + 31) >> 4;
+ memset(x, 0, plen * sizeof *x);
+ x[0] = p[0];
+ x[1] = 0x0001;
+}
+
+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] >> 4) + 7) >> 3;
+ if (len != 1 + (plen << 1)) {
+ return 0;
+ }
+ r = br_i15_decode_mod(P->c[0], buf + 1, plen, cc->p);
+ r &= br_i15_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] + 31) >> 4) * sizeof(uint16_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;
+ size_t plen;
+ jacobian Q, T;
+
+ buf = dst;
+ plen = (cc->p[0] - (cc->p[0] >> 4) + 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_i15_encode(buf + 1, plen, Q.c[0]);
+ br_i15_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 size_t
+api_xoff(int curve, size_t *len)
+{
+ api_generator(curve, len);
+ *len >>= 1;
+ return 1;
+}
+
+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);
+ if (Glen == cc->point_len) {
+ point_encode(G, &P, cc);
+ }
+ return r;
+}
+
+static size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ const unsigned char *G;
+ size_t Glen;
+
+ G = api_generator(curve, &Glen);
+ memcpy(R, G, Glen);
+ api_mul(R, Glen, x, xlen, curve);
+ return Glen;
+}
+
+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 independent 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);
+ if (B == NULL) {
+ size_t Glen;
+
+ B = api_generator(curve, &Glen);
+ }
+ 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_i15_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_i15 = {
+ (uint32_t)0x03800000,
+ &api_generator,
+ &api_order,
+ &api_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
diff --git a/contrib/bearssl/src/ec/ec_prime_i31.c b/contrib/bearssl/src/ec/ec_prime_i31.c
new file mode 100644
index 000000000000..0586a3b5ab6d
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_prime_i31.c
@@ -0,0 +1,819 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 six 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 size_t
+api_xoff(int curve, size_t *len)
+{
+ api_generator(curve, len);
+ *len >>= 1;
+ return 1;
+}
+
+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 size_t
+api_mulgen(unsigned char *R,
+ const unsigned char *x, size_t xlen, int curve)
+{
+ const unsigned char *G;
+ size_t Glen;
+
+ G = api_generator(curve, &Glen);
+ memcpy(R, G, Glen);
+ api_mul(R, Glen, x, xlen, curve);
+ return Glen;
+}
+
+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 independent 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);
+ if (B == NULL) {
+ size_t Glen;
+
+ B = api_generator(curve, &Glen);
+ }
+ 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_xoff,
+ &api_mul,
+ &api_mulgen,
+ &api_muladd
+};
diff --git a/contrib/bearssl/src/ec/ec_pubkey.c b/contrib/bearssl/src/ec/ec_pubkey.c
new file mode 100644
index 000000000000..383ff286c74d
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_pubkey.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+static const unsigned char POINT_LEN[] = {
+ 0, /* 0: not a valid curve ID */
+ 43, /* sect163k1 */
+ 43, /* sect163r1 */
+ 43, /* sect163r2 */
+ 51, /* sect193r1 */
+ 51, /* sect193r2 */
+ 61, /* sect233k1 */
+ 61, /* sect233r1 */
+ 61, /* sect239k1 */
+ 73, /* sect283k1 */
+ 73, /* sect283r1 */
+ 105, /* sect409k1 */
+ 105, /* sect409r1 */
+ 145, /* sect571k1 */
+ 145, /* sect571r1 */
+ 41, /* secp160k1 */
+ 41, /* secp160r1 */
+ 41, /* secp160r2 */
+ 49, /* secp192k1 */
+ 49, /* secp192r1 */
+ 57, /* secp224k1 */
+ 57, /* secp224r1 */
+ 65, /* secp256k1 */
+ 65, /* secp256r1 */
+ 97, /* secp384r1 */
+ 133, /* secp521r1 */
+ 65, /* brainpoolP256r1 */
+ 97, /* brainpoolP384r1 */
+ 129, /* brainpoolP512r1 */
+ 32, /* curve25519 */
+ 56, /* curve448 */
+};
+
+/* see bearssl_ec.h */
+size_t
+br_ec_compute_pub(const br_ec_impl *impl, br_ec_public_key *pk,
+ void *kbuf, const br_ec_private_key *sk)
+{
+ int curve;
+ size_t len;
+
+ curve = sk->curve;
+ if (curve < 0 || curve >= 32 || curve >= (int)(sizeof POINT_LEN)
+ || ((impl->supported_curves >> curve) & 1) == 0)
+ {
+ return 0;
+ }
+ if (kbuf == NULL) {
+ return POINT_LEN[curve];
+ }
+ len = impl->mulgen(kbuf, sk->x, sk->xlen, curve);
+ if (pk != NULL) {
+ pk->curve = curve;
+ pk->q = kbuf;
+ pk->qlen = len;
+ }
+ return len;
+}
diff --git a/contrib/bearssl/src/ec/ec_secp256r1.c b/contrib/bearssl/src/ec/ec_secp256r1.c
new file mode 100644
index 000000000000..a9d6c4562437
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_secp256r1.c
@@ -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
+};
diff --git a/contrib/bearssl/src/ec/ec_secp384r1.c b/contrib/bearssl/src/ec/ec_secp384r1.c
new file mode 100644
index 000000000000..693d93e4ff54
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_secp384r1.c
@@ -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
+};
diff --git a/contrib/bearssl/src/ec/ec_secp521r1.c b/contrib/bearssl/src/ec/ec_secp521r1.c
new file mode 100644
index 000000000000..161acd0ee925
--- /dev/null
+++ b/contrib/bearssl/src/ec/ec_secp521r1.c
@@ -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
+};
diff --git a/contrib/bearssl/src/ec/ecdsa_atr.c b/contrib/bearssl/src/ec/ecdsa_atr.c
new file mode 100644
index 000000000000..3a11226e4944
--- /dev/null
+++ b/contrib/bearssl/src/ec/ecdsa_atr.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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.
+ *
+ * Signature format is a SEQUENCE of two INTEGER values. We
+ * support only integers of less than 127 bytes each (signed
+ * encoding) so the resulting raw signature will have length
+ * at most 254 bytes.
+ */
+
+ unsigned char *buf, *r, *s;
+ size_t zlen, rlen, slen, off;
+ unsigned char tmp[254];
+
+ buf = sig;
+ if (sig_len < 8) {
+ return 0;
+ }
+
+ /*
+ * First byte is SEQUENCE tag.
+ */
+ if (buf[0] != 0x30) {
+ return 0;
+ }
+
+ /*
+ * The SEQUENCE length will be encoded over one or two bytes. We
+ * limit the total SEQUENCE contents to 255 bytes, because it
+ * makes things simpler; this is enough for subgroup orders up
+ * to 999 bits.
+ */
+ 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;
+ }
+
+ /*
+ * First INTEGER (r).
+ */
+ if (buf[off ++] != 0x02) {
+ return 0;
+ }
+ rlen = buf[off ++];
+ if (rlen >= 0x80) {
+ return 0;
+ }
+ r = buf + off;
+ off += rlen;
+
+ /*
+ * Second INTEGER (s).
+ */
+ 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;
+
+ /*
+ * Removing leading zeros from r and s.
+ */
+ while (rlen > 0 && *r == 0) {
+ rlen --;
+ r ++;
+ }
+ while (slen > 0 && *s == 0) {
+ slen --;
+ s ++;
+ }
+
+ /*
+ * Compute common length for the two integers, then copy integers
+ * into the temporary buffer, and finally copy it back over the
+ * signature buffer.
+ */
+ 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;
+}
diff --git a/contrib/bearssl/src/ec/ecdsa_default_sign_asn1.c b/contrib/bearssl/src/ec/ecdsa_default_sign_asn1.c
new file mode 100644
index 000000000000..afbf8acbde9f
--- /dev/null
+++ b/contrib/bearssl/src/ec/ecdsa_default_sign_asn1.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 */
+br_ecdsa_sign
+br_ecdsa_sign_asn1_get_default(void)
+{
+#if BR_LOMUL
+ return &br_ecdsa_i15_sign_asn1;
+#else
+ return &br_ecdsa_i31_sign_asn1;
+#endif
+}
diff --git a/contrib/bearssl/src/ec/ecdsa_default_sign_raw.c b/contrib/bearssl/src/ec/ecdsa_default_sign_raw.c
new file mode 100644
index 000000000000..287c97044761
--- /dev/null
+++ b/contrib/bearssl/src/ec/ecdsa_default_sign_raw.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 */
+br_ecdsa_sign
+br_ecdsa_sign_raw_get_default(void)
+{
+#if BR_LOMUL
+ return &br_ecdsa_i15_sign_raw;
+#else
+ return &br_ecdsa_i31_sign_raw;
+#endif
+}
diff --git a/contrib/bearssl/src/ec/ecdsa_default_vrfy_asn1.c b/contrib/bearssl/src/ec/ecdsa_default_vrfy_asn1.c
new file mode 100644
index 000000000000..fe0996e8e8e9
--- /dev/null
+++ b/contrib/bearssl/src/ec/ecdsa_default_vrfy_asn1.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 */
+br_ecdsa_vrfy
+br_ecdsa_vrfy_asn1_get_default(void)
+{
+#if BR_LOMUL
+ return &br_ecdsa_i15_vrfy_asn1;
+#else
+ return &br_ecdsa_i31_vrfy_asn1;
+#endif
+}
diff --git a/contrib/bearssl/src/ec/ecdsa_default_vrfy_raw.c b/contrib/bearssl/src/ec/ecdsa_default_vrfy_raw.c
new file mode 100644
index 000000000000..e564a105252e
--- /dev/null
+++ b/contrib/bearssl/src/ec/ecdsa_default_vrfy_raw.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 */
+br_ecdsa_vrfy
+br_ecdsa_vrfy_raw_get_default(void)
+{
+#if BR_LOMUL
+ return &br_ecdsa_i15_vrfy_raw;
+#else
+ return &br_ecdsa_i31_vrfy_raw;
+#endif
+}
diff --git a/contrib/bearssl/src/ec/ecdsa_i15_bits.c b/contrib/bearssl/src/ec/ecdsa_i15_bits.c
new file mode 100644
index 000000000000..402d14a660fa
--- /dev/null
+++ b/contrib/bearssl/src/ec/ecdsa_i15_bits.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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_i15_bits2int(uint16_t *x,
+ const void *src, size_t len, uint32_t ebitlen)
+{
+ uint32_t bitlen, hbitlen;
+ int sc;
+
+ bitlen = ebitlen - (ebitlen >> 4);
+ hbitlen = (uint32_t)len << 3;
+ if (hbitlen > bitlen) {
+ len = (bitlen + 7) >> 3;
+ sc = (int)((hbitlen - bitlen) & 7);
+ } else {
+ sc = 0;
+ }
+ br_i15_zero(x, ebitlen);
+ br_i15_decode(x, src, len);
+ br_i15_rshift(x, sc);
+ x[0] = ebitlen;
+}
diff --git a/contrib/bearssl/src/ec/ecdsa_i15_sign_asn1.c b/contrib/bearssl/src/ec/ecdsa_i15_sign_asn1.c
new file mode 100644
index 000000000000..ab4a283cf716
--- /dev/null
+++ b/contrib/bearssl/src/ec/ecdsa_i15_sign_asn1.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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_i15_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_i15_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;
+}
diff --git a/contrib/bearssl/src/ec/ecdsa_i15_sign_raw.c b/contrib/bearssl/src/ec/ecdsa_i15_sign_raw.c
new file mode 100644
index 000000000000..39b2e1d7ea1b
--- /dev/null
+++ b/contrib/bearssl/src/ec/ecdsa_i15_sign_raw.c
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 I15_LEN ((BR_MAX_EC_SIZE + 29) / 15)
+#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_i15_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;
+ uint16_t n[I15_LEN], r[I15_LEN], s[I15_LEN], x[I15_LEN];
+ uint16_t m[I15_LEN], k[I15_LEN], t1[I15_LEN], t2[I15_LEN];
+ unsigned char tt[ORDER_LEN << 1];
+ unsigned char eU[POINT_LEN];
+ size_t hash_len, nlen, ulen;
+ uint16_t n0i;
+ uint32_t ctl;
+ br_hmac_drbg_context drbg;
+
+ /*
+ * If the curve is not supported, then exit with an error.
+ */
+ if (((impl->supported_curves >> sk->curve) & 1) == 0) {
+ return 0;
+ }
+
+ /*
+ * 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_i15_decode(n, cd->order, nlen);
+ n0i = br_i15_ninv15(n[1]);
+
+ /*
+ * Get private key as an i15 integer. This also checks that the
+ * private key is well-defined (not zero, and less than the
+ * curve order).
+ */
+ if (!br_i15_decode_mod(x, sk->x, sk->xlen, n)) {
+ return 0;
+ }
+ if (br_i15_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_i15_bits2int(m, hash_value, hash_len, n[0]);
+ br_i15_sub(m, n, br_i15_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_i15_encode(tt, nlen, x);
+ br_i15_encode(tt + nlen, nlen, m);
+ br_hmac_drbg_init(&drbg, hf, tt, nlen << 1);
+ for (;;) {
+ br_hmac_drbg_generate(&drbg, tt, nlen);
+ br_ecdsa_i15_bits2int(k, tt, nlen, n[0]);
+ if (br_i15_iszero(k)) {
+ continue;
+ }
+ if (br_i15_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.
+ */
+ br_i15_encode(tt, nlen, k);
+ ulen = impl->mulgen(eU, tt, nlen, sk->curve);
+ br_i15_zero(r, n[0]);
+ br_i15_decode(r, &eU[1], ulen >> 1);
+ r[0] = n[0];
+ br_i15_sub(r, n, br_i15_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_i15_from_monty(k, n, n0i);
+ br_i15_from_monty(k, n, n0i);
+ memcpy(tt, cd->order, nlen);
+ tt[nlen - 1] -= 2;
+ br_i15_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_i15_to_monty() (which
+ * is slower).
+ */
+ br_i15_from_monty(m, n, n0i);
+ br_i15_montymul(t1, x, r, n, n0i);
+ ctl = br_i15_add(t1, m, 1);
+ ctl |= br_i15_sub(t1, n, 0) ^ 1;
+ br_i15_sub(t1, n, ctl);
+ br_i15_montymul(s, t1, k, n, n0i);
+
+ /*
+ * Encode r and s in the signature.
+ */
+ br_i15_encode(sig, nlen, r);
+ br_i15_encode((unsigned char *)sig + nlen, nlen, s);
+ return nlen << 1;
+}
diff --git a/contrib/bearssl/src/ec/ecdsa_i15_vrfy_asn1.c b/contrib/bearssl/src/ec/ecdsa_i15_vrfy_asn1.c
new file mode 100644
index 000000000000..f4bef997cfdb
--- /dev/null
+++ b/contrib/bearssl/src/ec/ecdsa_i15_vrfy_asn1.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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_i15_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)
+{
+ /*
+ * We use a double-sized buffer because a malformed ASN.1 signature
+ * may trigger a size expansion when converting to "raw" format.
+ */
+ unsigned char rsig[(FIELD_LEN << 2) + 24];
+
+ if (sig_len > ((sizeof rsig) >> 1)) {
+ return 0;
+ }
+ memcpy(rsig, sig, sig_len);
+ sig_len = br_ecdsa_asn1_to_raw(rsig, sig_len);
+ return br_ecdsa_i15_vrfy_raw(impl, hash, hash_len, pk, rsig, sig_len);
+}
diff --git a/contrib/bearssl/src/ec/ecdsa_i15_vrfy_raw.c b/contrib/bearssl/src/ec/ecdsa_i15_vrfy_raw.c
new file mode 100644
index 000000000000..14dd5e468f13
--- /dev/null
+++ b/contrib/bearssl/src/ec/ecdsa_i15_vrfy_raw.c
@@ -0,0 +1,166 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 I15_LEN ((BR_MAX_EC_SIZE + 29) / 15)
+#define POINT_LEN (1 + (((BR_MAX_EC_SIZE + 7) >> 3) << 1))
+
+/* see bearssl_ec.h */
+uint32_t
+br_ecdsa_i15_vrfy_raw(const br_ec_impl *impl,
+ const void *hash, size_t hash_len,
+ const br_ec_public_key *pk,
+ const void *sig, size_t sig_len)
+{
+ /*
+ * IMPORTANT: this code is fit only for curves with a prime
+ * order. This is needed so that modular reduction of the X
+ * coordinate of a point can be done with a simple subtraction.
+ */
+ const br_ec_curve_def *cd;
+ uint16_t n[I15_LEN], r[I15_LEN], s[I15_LEN], t1[I15_LEN], t2[I15_LEN];
+ unsigned char tx[(BR_MAX_EC_SIZE + 7) >> 3];
+ unsigned char ty[(BR_MAX_EC_SIZE + 7) >> 3];
+ unsigned char eU[POINT_LEN];
+ size_t nlen, rlen, ulen;
+ uint16_t n0i;
+ uint32_t res;
+
+ /*
+ * If the curve is not supported, then report an error.
+ */
+ if (((impl->supported_curves >> pk->curve) & 1) == 0) {
+ return 0;
+ }
+
+ /*
+ * Get the curve parameters (generator and order).
+ */
+ switch (pk->curve) {
+ case BR_EC_secp256r1:
+ cd = &br_secp256r1;
+ break;
+ case BR_EC_secp384r1:
+ cd = &br_secp384r1;
+ break;
+ case BR_EC_secp521r1:
+ cd = &br_secp521r1;
+ break;
+ default:
+ return 0;
+ }
+
+ /*
+ * Signature length must be even.
+ */
+ if (sig_len & 1) {
+ return 0;
+ }
+ rlen = sig_len >> 1;
+
+ /*
+ * Public key point must have the proper size for this curve.
+ */
+ if (pk->qlen != cd->generator_len) {
+ return 0;
+ }
+
+ /*
+ * Get modulus; then decode the r and s values. They must be
+ * lower than the modulus, and s must not be null.
+ */
+ nlen = cd->order_len;
+ br_i15_decode(n, cd->order, nlen);
+ n0i = br_i15_ninv15(n[1]);
+ if (!br_i15_decode_mod(r, sig, rlen, n)) {
+ return 0;
+ }
+ if (!br_i15_decode_mod(s, (const unsigned char *)sig + rlen, rlen, n)) {
+ return 0;
+ }
+ if (br_i15_iszero(s)) {
+ return 0;
+ }
+
+ /*
+ * Invert s. We do that with a modular exponentiation; we use
+ * the fact that for all the curves we support, the least
+ * significant byte is not 0 or 1, so we can subtract 2 without
+ * any carry to process.
+ * We also want 1/s in Montgomery representation, which can be
+ * done by converting _from_ Montgomery representation before
+ * the inversion (because (1/s)*R = 1/(s/R)).
+ */
+ br_i15_from_monty(s, n, n0i);
+ memcpy(tx, cd->order, nlen);
+ tx[nlen - 1] -= 2;
+ br_i15_modpow(s, tx, nlen, n, n0i, t1, t2);
+
+ /*
+ * Truncate the hash to the modulus length (in bits) and reduce
+ * it modulo the curve order. The modular reduction can be done
+ * with a subtraction since the truncation already reduced the
+ * value to the modulus bit length.
+ */
+ br_ecdsa_i15_bits2int(t1, hash, hash_len, n[0]);
+ br_i15_sub(t1, n, br_i15_sub(t1, n, 0) ^ 1);
+
+ /*
+ * Multiply the (truncated, reduced) hash value with 1/s, result in
+ * t2, encoded in ty.
+ */
+ br_i15_montymul(t2, t1, s, n, n0i);
+ br_i15_encode(ty, nlen, t2);
+
+ /*
+ * Multiply r with 1/s, result in t1, encoded in tx.
+ */
+ br_i15_montymul(t1, r, s, n, n0i);
+ br_i15_encode(tx, nlen, t1);
+
+ /*
+ * Compute the point x*Q + y*G.
+ */
+ ulen = cd->generator_len;
+ memcpy(eU, pk->q, ulen);
+ res = impl->muladd(eU, NULL, ulen,
+ tx, nlen, ty, nlen, cd->curve);
+
+ /*
+ * Get the X coordinate, reduce modulo the curve order, and
+ * compare with the 'r' value.
+ *
+ * The modular reduction can be done with subtractions because
+ * we work with curves of prime order, so the curve order is
+ * close to the field order (Hasse's theorem).
+ */
+ br_i15_zero(t1, n[0]);
+ br_i15_decode(t1, &eU[1], ulen >> 1);
+ t1[0] = n[0];
+ br_i15_sub(t1, n, br_i15_sub(t1, n, 0) ^ 1);
+ res &= ~br_i15_sub(t1, r, 1);
+ res &= br_i15_iszero(t1);
+ return res;
+}
diff --git a/contrib/bearssl/src/ec/ecdsa_i31_bits.c b/contrib/bearssl/src/ec/ecdsa_i31_bits.c
new file mode 100644
index 000000000000..9a8d67301258
--- /dev/null
+++ b/contrib/bearssl/src/ec/ecdsa_i31_bits.c
@@ -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;
+}
diff --git a/contrib/bearssl/src/ec/ecdsa_i31_sign_asn1.c b/contrib/bearssl/src/ec/ecdsa_i31_sign_asn1.c
new file mode 100644
index 000000000000..cf0d351d7fe1
--- /dev/null
+++ b/contrib/bearssl/src/ec/ecdsa_i31_sign_asn1.c
@@ -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;
+}
diff --git a/contrib/bearssl/src/ec/ecdsa_i31_sign_raw.c b/contrib/bearssl/src/ec/ecdsa_i31_sign_raw.c
new file mode 100644
index 000000000000..1df98fed2314
--- /dev/null
+++ b/contrib/bearssl/src/ec/ecdsa_i31_sign_raw.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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;
+
+ /*
+ * If the curve is not supported, then exit with an error.
+ */
+ if (((impl->supported_curves >> sk->curve) & 1) == 0) {
+ return 0;
+ }
+
+ /*
+ * 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.
+ */
+ br_i31_encode(tt, nlen, k);
+ ulen = impl->mulgen(eU, tt, nlen, sk->curve);
+ 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;
+}
diff --git a/contrib/bearssl/src/ec/ecdsa_i31_vrfy_asn1.c b/contrib/bearssl/src/ec/ecdsa_i31_vrfy_asn1.c
new file mode 100644
index 000000000000..4161aaaa3eff
--- /dev/null
+++ b/contrib/bearssl/src/ec/ecdsa_i31_vrfy_asn1.c
@@ -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"
+
+#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)
+{
+ /*
+ * We use a double-sized buffer because a malformed ASN.1 signature
+ * may trigger a size expansion when converting to "raw" format.
+ */
+ unsigned char rsig[(FIELD_LEN << 2) + 24];
+
+ if (sig_len > ((sizeof rsig) >> 1)) {
+ 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);
+}
diff --git a/contrib/bearssl/src/ec/ecdsa_i31_vrfy_raw.c b/contrib/bearssl/src/ec/ecdsa_i31_vrfy_raw.c
new file mode 100644
index 000000000000..259477fdb8fc
--- /dev/null
+++ b/contrib/bearssl/src/ec/ecdsa_i31_vrfy_raw.c
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#define I31_LEN ((BR_MAX_EC_SIZE + 61) / 31)
+#define POINT_LEN (1 + (((BR_MAX_EC_SIZE + 7) >> 3) << 1))
+
+/* see bearssl_ec.h */
+uint32_t
+br_ecdsa_i31_vrfy_raw(const br_ec_impl *impl,
+ const void *hash, size_t hash_len,
+ const br_ec_public_key *pk,
+ const void *sig, size_t sig_len)
+{
+ /*
+ * IMPORTANT: this code is fit only for curves with a prime
+ * order. This is needed so that modular reduction of the X
+ * coordinate of a point can be done with a simple subtraction.
+ */
+ const br_ec_curve_def *cd;
+ uint32_t n[I31_LEN], r[I31_LEN], s[I31_LEN], t1[I31_LEN], t2[I31_LEN];
+ unsigned char tx[(BR_MAX_EC_SIZE + 7) >> 3];
+ unsigned char ty[(BR_MAX_EC_SIZE + 7) >> 3];
+ unsigned char eU[POINT_LEN];
+ size_t nlen, rlen, ulen;
+ uint32_t n0i, res;
+
+ /*
+ * If the curve is not supported, then report an error.
+ */
+ if (((impl->supported_curves >> pk->curve) & 1) == 0) {
+ return 0;
+ }
+
+ /*
+ * Get the curve parameters (generator and order).
+ */
+ switch (pk->curve) {
+ case BR_EC_secp256r1:
+ cd = &br_secp256r1;
+ break;
+ case BR_EC_secp384r1:
+ cd = &br_secp384r1;
+ break;
+ case BR_EC_secp521r1:
+ cd = &br_secp521r1;
+ break;
+ default:
+ return 0;
+ }
+
+ /*
+ * Signature length must be even.
+ */
+ if (sig_len & 1) {
+ return 0;
+ }
+ rlen = sig_len >> 1;
+
+ /*
+ * Public key point must have the proper size for this curve.
+ */
+ if (pk->qlen != cd->generator_len) {
+ return 0;
+ }
+
+ /*
+ * Get modulus; then decode the r and s values. They must be
+ * lower than the modulus, and s must not be null.
+ */
+ nlen = cd->order_len;
+ br_i31_decode(n, cd->order, nlen);
+ n0i = br_i31_ninv31(n[1]);
+ if (!br_i31_decode_mod(r, sig, rlen, n)) {
+ return 0;
+ }
+ if (!br_i31_decode_mod(s, (const unsigned char *)sig + rlen, rlen, n)) {
+ return 0;
+ }
+ if (br_i31_iszero(s)) {
+ return 0;
+ }
+
+ /*
+ * Invert s. We do that with a modular exponentiation; we use
+ * the fact that for all the curves we support, the least
+ * significant byte is not 0 or 1, so we can subtract 2 without
+ * any carry to process.
+ * We also want 1/s in Montgomery representation, which can be
+ * done by converting _from_ Montgomery representation before
+ * the inversion (because (1/s)*R = 1/(s/R)).
+ */
+ br_i31_from_monty(s, n, n0i);
+ memcpy(tx, cd->order, nlen);
+ tx[nlen - 1] -= 2;
+ br_i31_modpow(s, tx, nlen, n, n0i, t1, t2);
+
+ /*
+ * Truncate the hash to the modulus length (in bits) and reduce
+ * it modulo the curve order. The modular reduction can be done
+ * with a subtraction since the truncation already reduced the
+ * value to the modulus bit length.
+ */
+ br_ecdsa_i31_bits2int(t1, hash, hash_len, n[0]);
+ br_i31_sub(t1, n, br_i31_sub(t1, n, 0) ^ 1);
+
+ /*
+ * Multiply the (truncated, reduced) hash value with 1/s, result in
+ * t2, encoded in ty.
+ */
+ br_i31_montymul(t2, t1, s, n, n0i);
+ br_i31_encode(ty, nlen, t2);
+
+ /*
+ * Multiply r with 1/s, result in t1, encoded in tx.
+ */
+ br_i31_montymul(t1, r, s, n, n0i);
+ br_i31_encode(tx, nlen, t1);
+
+ /*
+ * Compute the point x*Q + y*G.
+ */
+ ulen = cd->generator_len;
+ memcpy(eU, pk->q, ulen);
+ res = impl->muladd(eU, NULL, ulen,
+ tx, nlen, ty, nlen, cd->curve);
+
+ /*
+ * Get the X coordinate, reduce modulo the curve order, and
+ * compare with the 'r' value.
+ *
+ * The modular reduction can be done with subtractions because
+ * we work with curves of prime order, so the curve order is
+ * close to the field order (Hasse's theorem).
+ */
+ br_i31_zero(t1, n[0]);
+ br_i31_decode(t1, &eU[1], ulen >> 1);
+ t1[0] = n[0];
+ br_i31_sub(t1, n, br_i31_sub(t1, n, 0) ^ 1);
+ res &= ~br_i31_sub(t1, r, 1);
+ res &= br_i31_iszero(t1);
+ return res;
+}
diff --git a/contrib/bearssl/src/ec/ecdsa_rta.c b/contrib/bearssl/src/ec/ecdsa_rta.c
new file mode 100644
index 000000000000..005c62c2dbb8
--- /dev/null
+++ b/contrib/bearssl/src/ec/ecdsa_rta.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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"
+
+/*
+ * Compute ASN.1 encoded length for the provided integer. The ASN.1
+ * encoding is signed, so its leading bit must have value 0; it must
+ * also be of minimal length (so leading bytes of value 0 must be
+ * removed, except if that would contradict the rule about the sign
+ * bit).
+ */
+static size_t
+asn1_int_length(const unsigned char *x, size_t xlen)
+{
+ while (xlen > 0 && *x == 0) {
+ x ++;
+ xlen --;
+ }
+ if (xlen == 0 || *x >= 0x80) {
+ xlen ++;
+ }
+ return xlen;
+}
+
+/* see bearssl_ec.h */
+size_t
+br_ecdsa_raw_to_asn1(void *sig, size_t sig_len)
+{
+ /*
+ * Internal buffer is large enough to accommodate a signature
+ * such that r and s fit on 125 bytes each (signed encoding),
+ * meaning a curve order of up to 999 bits. This is the limit
+ * that ensures "simple" length encodings.
+ */
+ unsigned char *buf;
+ size_t hlen, rlen, slen, zlen, off;
+ unsigned char tmp[257];
+
+ buf = sig;
+ if ((sig_len & 1) != 0) {
+ return 0;
+ }
+
+ /*
+ * Compute lengths for the two integers.
+ */
+ hlen = sig_len >> 1;
+ rlen = asn1_int_length(buf, hlen);
+ slen = asn1_int_length(buf + hlen, hlen);
+ if (rlen > 125 || slen > 125) {
+ return 0;
+ }
+
+ /*
+ * SEQUENCE header.
+ */
+ tmp[0] = 0x30;
+ zlen = rlen + slen + 4;
+ if (zlen >= 0x80) {
+ tmp[1] = 0x81;
+ tmp[2] = zlen;
+ off = 3;
+ } else {
+ tmp[1] = zlen;
+ off = 2;
+ }
+
+ /*
+ * First INTEGER (r).
+ */
+ tmp[off ++] = 0x02;
+ tmp[off ++] = rlen;
+ if (rlen > hlen) {
+ tmp[off] = 0x00;
+ memcpy(tmp + off + 1, buf, hlen);
+ } else {
+ memcpy(tmp + off, buf + hlen - rlen, rlen);
+ }
+ off += rlen;
+
+ /*
+ * Second INTEGER (s).
+ */
+ tmp[off ++] = 0x02;
+ tmp[off ++] = slen;
+ if (slen > hlen) {
+ tmp[off] = 0x00;
+ memcpy(tmp + off + 1, buf + hlen, hlen);
+ } else {
+ memcpy(tmp + off, buf + sig_len - slen, slen);
+ }
+ off += slen;
+
+ /*
+ * Return ASN.1 signature.
+ */
+ memcpy(sig, tmp, off);
+ return off;
+}
diff --git a/contrib/bearssl/src/hash/dig_oid.c b/contrib/bearssl/src/hash/dig_oid.c
new file mode 100644
index 000000000000..cd9692c95999
--- /dev/null
+++ b/contrib/bearssl/src/hash/dig_oid.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * This file contains the encoded OID for the standard hash functions.
+ * Such OID appear in, for instance, the PKCS#1 v1.5 padding for RSA
+ * signatures.
+ */
+
+static const unsigned char md5_OID[] = {
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x02, 0x05
+};
+
+static const unsigned char sha1_OID[] = {
+ 0x2B, 0x0E, 0x03, 0x02, 0x1A
+};
+
+static const unsigned char sha224_OID[] = {
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
+};
+
+static const unsigned char sha256_OID[] = {
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
+};
+
+static const unsigned char sha384_OID[] = {
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
+};
+
+static const unsigned char sha512_OID[] = {
+ 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
+};
+
+/* see inner.h */
+const unsigned char *
+br_digest_OID(int digest_id, size_t *len)
+{
+ switch (digest_id) {
+ case br_md5_ID:
+ *len = sizeof md5_OID;
+ return md5_OID;
+ case br_sha1_ID:
+ *len = sizeof sha1_OID;
+ return sha1_OID;
+ case br_sha224_ID:
+ *len = sizeof sha224_OID;
+ return sha224_OID;
+ case br_sha256_ID:
+ *len = sizeof sha256_OID;
+ return sha256_OID;
+ case br_sha384_ID:
+ *len = sizeof sha384_OID;
+ return sha384_OID;
+ case br_sha512_ID:
+ *len = sizeof sha512_OID;
+ return sha512_OID;
+ default:
+ *len = 0;
+ return NULL;
+ }
+}
diff --git a/contrib/bearssl/src/hash/dig_size.c b/contrib/bearssl/src/hash/dig_size.c
new file mode 100644
index 000000000000..4625d2c65856
--- /dev/null
+++ b/contrib/bearssl/src/hash/dig_size.c
@@ -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"
+
+/* see inner.h */
+size_t
+br_digest_size_by_ID(int digest_id)
+{
+ switch (digest_id) {
+ case br_md5sha1_ID:
+ return br_md5_SIZE + br_sha1_SIZE;
+ case br_md5_ID:
+ return br_md5_SIZE;
+ case br_sha1_ID:
+ return br_sha1_SIZE;
+ case br_sha224_ID:
+ return br_sha224_SIZE;
+ case br_sha256_ID:
+ return br_sha256_SIZE;
+ case br_sha384_ID:
+ return br_sha384_SIZE;
+ case br_sha512_ID:
+ return br_sha512_SIZE;
+ default:
+ /* abort(); */
+ return 0;
+ }
+}
diff --git a/contrib/bearssl/src/hash/ghash_ctmul.c b/contrib/bearssl/src/hash/ghash_ctmul.c
new file mode 100644
index 000000000000..362320252f3b
--- /dev/null
+++ b/contrib/bearssl/src/hash/ghash_ctmul.c
@@ -0,0 +1,345 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * We compute "carryless multiplications" through normal integer
+ * multiplications, masking out enough bits to create "holes" in which
+ * carries may expand without altering our bits; we really use 8 data
+ * bits per 32-bit word, spaced every fourth bit. Accumulated carries
+ * may not exceed 8 in total, which fits in 4 bits.
+ *
+ * It would be possible to use a 3-bit spacing, allowing two operands,
+ * one with 7 non-zero data bits, the other one with 10 or 11 non-zero
+ * data bits; this asymmetric splitting makes the overall code more
+ * complex with thresholds and exceptions, and does not appear to be
+ * worth the effort.
+ */
+
+/*
+ * We cannot really autodetect whether multiplications are "slow" or
+ * not. A typical example is the ARM Cortex M0+, which exists in two
+ * versions: one with a 1-cycle multiplication opcode, the other with
+ * a 32-cycle multiplication opcode. They both use exactly the same
+ * architecture and ABI, and cannot be distinguished from each other
+ * at compile-time.
+ *
+ * Since most modern CPU (even embedded CPU) still have fast
+ * multiplications, we use the "fast mul" code by default.
+ */
+
+#if BR_SLOW_MUL
+
+/*
+ * This implementation uses Karatsuba-like reduction to make fewer
+ * integer multiplications (9 instead of 16), at the expense of extra
+ * logical operations (XOR, shifts...). On modern x86 CPU that offer
+ * fast, pipelined multiplications, this code is about twice slower than
+ * the simpler code with 16 multiplications. This tendency may be
+ * reversed on low-end platforms with expensive multiplications.
+ */
+
+#define MUL32(h, l, x, y) do { \
+ uint64_t mul32tmp = MUL(x, y); \
+ (h) = (uint32_t)(mul32tmp >> 32); \
+ (l) = (uint32_t)mul32tmp; \
+ } while (0)
+
+static inline void
+bmul(uint32_t *hi, uint32_t *lo, uint32_t x, uint32_t y)
+{
+ uint32_t x0, x1, x2, x3;
+ uint32_t y0, y1, y2, y3;
+ uint32_t a0, a1, a2, a3, a4, a5, a6, a7, a8;
+ uint32_t b0, b1, b2, b3, b4, b5, b6, b7, b8;
+
+ x0 = x & (uint32_t)0x11111111;
+ x1 = x & (uint32_t)0x22222222;
+ x2 = x & (uint32_t)0x44444444;
+ x3 = x & (uint32_t)0x88888888;
+ y0 = y & (uint32_t)0x11111111;
+ y1 = y & (uint32_t)0x22222222;
+ y2 = y & (uint32_t)0x44444444;
+ y3 = y & (uint32_t)0x88888888;
+
+ /*
+ * (x0+W*x1)*(y0+W*y1) -> a0:b0
+ * (x2+W*x3)*(y2+W*y3) -> a3:b3
+ * ((x0+x2)+W*(x1+x3))*((y0+y2)+W*(y1+y3)) -> a6:b6
+ */
+ a0 = x0;
+ b0 = y0;
+ a1 = x1 >> 1;
+ b1 = y1 >> 1;
+ a2 = a0 ^ a1;
+ b2 = b0 ^ b1;
+ a3 = x2 >> 2;
+ b3 = y2 >> 2;
+ a4 = x3 >> 3;
+ b4 = y3 >> 3;
+ a5 = a3 ^ a4;
+ b5 = b3 ^ b4;
+ a6 = a0 ^ a3;
+ b6 = b0 ^ b3;
+ a7 = a1 ^ a4;
+ b7 = b1 ^ b4;
+ a8 = a6 ^ a7;
+ b8 = b6 ^ b7;
+
+ MUL32(b0, a0, b0, a0);
+ MUL32(b1, a1, b1, a1);
+ MUL32(b2, a2, b2, a2);
+ MUL32(b3, a3, b3, a3);
+ MUL32(b4, a4, b4, a4);
+ MUL32(b5, a5, b5, a5);
+ MUL32(b6, a6, b6, a6);
+ MUL32(b7, a7, b7, a7);
+ MUL32(b8, a8, b8, a8);
+
+ a0 &= (uint32_t)0x11111111;
+ a1 &= (uint32_t)0x11111111;
+ a2 &= (uint32_t)0x11111111;
+ a3 &= (uint32_t)0x11111111;
+ a4 &= (uint32_t)0x11111111;
+ a5 &= (uint32_t)0x11111111;
+ a6 &= (uint32_t)0x11111111;
+ a7 &= (uint32_t)0x11111111;
+ a8 &= (uint32_t)0x11111111;
+ b0 &= (uint32_t)0x11111111;
+ b1 &= (uint32_t)0x11111111;
+ b2 &= (uint32_t)0x11111111;
+ b3 &= (uint32_t)0x11111111;
+ b4 &= (uint32_t)0x11111111;
+ b5 &= (uint32_t)0x11111111;
+ b6 &= (uint32_t)0x11111111;
+ b7 &= (uint32_t)0x11111111;
+ b8 &= (uint32_t)0x11111111;
+
+ a2 ^= a0 ^ a1;
+ b2 ^= b0 ^ b1;
+ a0 ^= (a2 << 1) ^ (a1 << 2);
+ b0 ^= (b2 << 1) ^ (b1 << 2);
+ a5 ^= a3 ^ a4;
+ b5 ^= b3 ^ b4;
+ a3 ^= (a5 << 1) ^ (a4 << 2);
+ b3 ^= (b5 << 1) ^ (b4 << 2);
+ a8 ^= a6 ^ a7;
+ b8 ^= b6 ^ b7;
+ a6 ^= (a8 << 1) ^ (a7 << 2);
+ b6 ^= (b8 << 1) ^ (b7 << 2);
+ a6 ^= a0 ^ a3;
+ b6 ^= b0 ^ b3;
+ *lo = a0 ^ (a6 << 2) ^ (a3 << 4);
+ *hi = b0 ^ (b6 << 2) ^ (b3 << 4) ^ (a6 >> 30) ^ (a3 >> 28);
+}
+
+#else
+
+/*
+ * Simple multiplication in GF(2)[X], using 16 integer multiplications.
+ */
+
+static inline void
+bmul(uint32_t *hi, uint32_t *lo, uint32_t x, uint32_t y)
+{
+ uint32_t x0, x1, x2, x3;
+ uint32_t y0, y1, y2, y3;
+ uint64_t z0, z1, z2, z3;
+ uint64_t z;
+
+ x0 = x & (uint32_t)0x11111111;
+ x1 = x & (uint32_t)0x22222222;
+ x2 = x & (uint32_t)0x44444444;
+ x3 = x & (uint32_t)0x88888888;
+ y0 = y & (uint32_t)0x11111111;
+ y1 = y & (uint32_t)0x22222222;
+ y2 = y & (uint32_t)0x44444444;
+ y3 = y & (uint32_t)0x88888888;
+ z0 = MUL(x0, y0) ^ MUL(x1, y3) ^ MUL(x2, y2) ^ MUL(x3, y1);
+ z1 = MUL(x0, y1) ^ MUL(x1, y0) ^ MUL(x2, y3) ^ MUL(x3, y2);
+ z2 = MUL(x0, y2) ^ MUL(x1, y1) ^ MUL(x2, y0) ^ MUL(x3, y3);
+ z3 = MUL(x0, y3) ^ MUL(x1, y2) ^ MUL(x2, y1) ^ MUL(x3, y0);
+ z0 &= (uint64_t)0x1111111111111111;
+ z1 &= (uint64_t)0x2222222222222222;
+ z2 &= (uint64_t)0x4444444444444444;
+ z3 &= (uint64_t)0x8888888888888888;
+ z = z0 | z1 | z2 | z3;
+ *lo = (uint32_t)z;
+ *hi = (uint32_t)(z >> 32);
+}
+
+#endif
+
+/* see bearssl_hash.h */
+void
+br_ghash_ctmul(void *y, const void *h, const void *data, size_t len)
+{
+ const unsigned char *buf, *hb;
+ unsigned char *yb;
+ uint32_t yw[4];
+ uint32_t hw[4];
+
+ /*
+ * Throughout the loop we handle the y and h values as arrays
+ * of 32-bit words.
+ */
+ buf = data;
+ yb = y;
+ hb = h;
+ yw[3] = br_dec32be(yb);
+ yw[2] = br_dec32be(yb + 4);
+ yw[1] = br_dec32be(yb + 8);
+ yw[0] = br_dec32be(yb + 12);
+ hw[3] = br_dec32be(hb);
+ hw[2] = br_dec32be(hb + 4);
+ hw[1] = br_dec32be(hb + 8);
+ hw[0] = br_dec32be(hb + 12);
+ while (len > 0) {
+ const unsigned char *src;
+ unsigned char tmp[16];
+ int i;
+ uint32_t a[9], b[9], zw[8];
+ uint32_t c0, c1, c2, c3, d0, d1, d2, d3, e0, e1, e2, e3;
+
+ /*
+ * Get the next 16-byte block (using zero-padding if
+ * necessary).
+ */
+ if (len >= 16) {
+ src = buf;
+ buf += 16;
+ len -= 16;
+ } else {
+ memcpy(tmp, buf, len);
+ memset(tmp + len, 0, (sizeof tmp) - len);
+ src = tmp;
+ len = 0;
+ }
+
+ /*
+ * Decode the block. The GHASH standard mandates
+ * big-endian encoding.
+ */
+ yw[3] ^= br_dec32be(src);
+ yw[2] ^= br_dec32be(src + 4);
+ yw[1] ^= br_dec32be(src + 8);
+ yw[0] ^= br_dec32be(src + 12);
+
+ /*
+ * We multiply two 128-bit field elements. We use
+ * Karatsuba to turn that into three 64-bit
+ * multiplications, which are themselves done with a
+ * total of nine 32-bit multiplications.
+ */
+
+ /*
+ * y[0,1]*h[0,1] -> 0..2
+ * y[2,3]*h[2,3] -> 3..5
+ * (y[0,1]+y[2,3])*(h[0,1]+h[2,3]) -> 6..8
+ */
+ a[0] = yw[0];
+ b[0] = hw[0];
+ a[1] = yw[1];
+ b[1] = hw[1];
+ a[2] = a[0] ^ a[1];
+ b[2] = b[0] ^ b[1];
+
+ a[3] = yw[2];
+ b[3] = hw[2];
+ a[4] = yw[3];
+ b[4] = hw[3];
+ a[5] = a[3] ^ a[4];
+ b[5] = b[3] ^ b[4];
+
+ a[6] = a[0] ^ a[3];
+ b[6] = b[0] ^ b[3];
+ a[7] = a[1] ^ a[4];
+ b[7] = b[1] ^ b[4];
+ a[8] = a[6] ^ a[7];
+ b[8] = b[6] ^ b[7];
+
+ for (i = 0; i < 9; i ++) {
+ bmul(&b[i], &a[i], b[i], a[i]);
+ }
+
+ c0 = a[0];
+ c1 = b[0] ^ a[2] ^ a[0] ^ a[1];
+ c2 = a[1] ^ b[2] ^ b[0] ^ b[1];
+ c3 = b[1];
+ d0 = a[3];
+ d1 = b[3] ^ a[5] ^ a[3] ^ a[4];
+ d2 = a[4] ^ b[5] ^ b[3] ^ b[4];
+ d3 = b[4];
+ e0 = a[6];
+ e1 = b[6] ^ a[8] ^ a[6] ^ a[7];
+ e2 = a[7] ^ b[8] ^ b[6] ^ b[7];
+ e3 = b[7];
+
+ e0 ^= c0 ^ d0;
+ e1 ^= c1 ^ d1;
+ e2 ^= c2 ^ d2;
+ e3 ^= c3 ^ d3;
+ c2 ^= e0;
+ c3 ^= e1;
+ d0 ^= e2;
+ d1 ^= e3;
+
+ /*
+ * GHASH specification has the bits "reversed" (most
+ * significant is in fact least significant), which does
+ * not matter for a carryless multiplication, except that
+ * the 255-bit result must be shifted by 1 bit.
+ */
+ zw[0] = c0 << 1;
+ zw[1] = (c1 << 1) | (c0 >> 31);
+ zw[2] = (c2 << 1) | (c1 >> 31);
+ zw[3] = (c3 << 1) | (c2 >> 31);
+ zw[4] = (d0 << 1) | (c3 >> 31);
+ zw[5] = (d1 << 1) | (d0 >> 31);
+ zw[6] = (d2 << 1) | (d1 >> 31);
+ zw[7] = (d3 << 1) | (d2 >> 31);
+
+ /*
+ * We now do the reduction modulo the field polynomial
+ * to get back to 128 bits.
+ */
+ for (i = 0; i < 4; i ++) {
+ uint32_t lw;
+
+ lw = zw[i];
+ zw[i + 4] ^= lw ^ (lw >> 1) ^ (lw >> 2) ^ (lw >> 7);
+ zw[i + 3] ^= (lw << 31) ^ (lw << 30) ^ (lw << 25);
+ }
+ memcpy(yw, zw + 4, sizeof yw);
+ }
+
+ /*
+ * Encode back the result.
+ */
+ br_enc32be(yb, yw[3]);
+ br_enc32be(yb + 4, yw[2]);
+ br_enc32be(yb + 8, yw[1]);
+ br_enc32be(yb + 12, yw[0]);
+}
diff --git a/contrib/bearssl/src/hash/ghash_ctmul32.c b/contrib/bearssl/src/hash/ghash_ctmul32.c
new file mode 100644
index 000000000000..c66af4655f3f
--- /dev/null
+++ b/contrib/bearssl/src/hash/ghash_ctmul32.c
@@ -0,0 +1,251 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * This implementation uses 32-bit multiplications, and only the low
+ * 32 bits for each multiplication result. This is meant primarily for
+ * the ARM Cortex M0 and M0+, whose multiplication opcode does not yield
+ * the upper 32 bits; but it might also be useful on architectures where
+ * access to the upper 32 bits requires use of specific registers that
+ * create contention (e.g. on i386, "mul" necessarily outputs the result
+ * in edx:eax, while "imul" can use any registers but is limited to the
+ * low 32 bits).
+ *
+ * The implementation trick that is used here is bit-reversing (bit 0
+ * is swapped with bit 31, bit 1 with bit 30, and so on). In GF(2)[X],
+ * for all values x and y, we have:
+ * rev32(x) * rev32(y) = rev64(x * y)
+ * In other words, if we bit-reverse (over 32 bits) the operands, then we
+ * bit-reverse (over 64 bits) the result.
+ */
+
+/*
+ * Multiplication in GF(2)[X], truncated to its low 32 bits.
+ */
+static inline uint32_t
+bmul32(uint32_t x, uint32_t y)
+{
+ uint32_t x0, x1, x2, x3;
+ uint32_t y0, y1, y2, y3;
+ uint32_t z0, z1, z2, z3;
+
+ x0 = x & (uint32_t)0x11111111;
+ x1 = x & (uint32_t)0x22222222;
+ x2 = x & (uint32_t)0x44444444;
+ x3 = x & (uint32_t)0x88888888;
+ y0 = y & (uint32_t)0x11111111;
+ y1 = y & (uint32_t)0x22222222;
+ y2 = y & (uint32_t)0x44444444;
+ y3 = y & (uint32_t)0x88888888;
+ z0 = (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1);
+ z1 = (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2);
+ z2 = (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3);
+ z3 = (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0);
+ z0 &= (uint32_t)0x11111111;
+ z1 &= (uint32_t)0x22222222;
+ z2 &= (uint32_t)0x44444444;
+ z3 &= (uint32_t)0x88888888;
+ return z0 | z1 | z2 | z3;
+}
+
+/*
+ * Bit-reverse a 32-bit word.
+ */
+static uint32_t
+rev32(uint32_t x)
+{
+#define RMS(m, s) do { \
+ x = ((x & (uint32_t)(m)) << (s)) \
+ | ((x >> (s)) & (uint32_t)(m)); \
+ } while (0)
+
+ RMS(0x55555555, 1);
+ RMS(0x33333333, 2);
+ RMS(0x0F0F0F0F, 4);
+ RMS(0x00FF00FF, 8);
+ return (x << 16) | (x >> 16);
+
+#undef RMS
+}
+
+/* see bearssl_hash.h */
+void
+br_ghash_ctmul32(void *y, const void *h, const void *data, size_t len)
+{
+ /*
+ * This implementation is similar to br_ghash_ctmul() except
+ * that we have to do the multiplication twice, with the
+ * "normal" and "bit reversed" operands. Hence we end up with
+ * eighteen 32-bit multiplications instead of nine.
+ */
+
+ const unsigned char *buf, *hb;
+ unsigned char *yb;
+ uint32_t yw[4];
+ uint32_t hw[4], hwr[4];
+
+ buf = data;
+ yb = y;
+ hb = h;
+ yw[3] = br_dec32be(yb);
+ yw[2] = br_dec32be(yb + 4);
+ yw[1] = br_dec32be(yb + 8);
+ yw[0] = br_dec32be(yb + 12);
+ hw[3] = br_dec32be(hb);
+ hw[2] = br_dec32be(hb + 4);
+ hw[1] = br_dec32be(hb + 8);
+ hw[0] = br_dec32be(hb + 12);
+ hwr[3] = rev32(hw[3]);
+ hwr[2] = rev32(hw[2]);
+ hwr[1] = rev32(hw[1]);
+ hwr[0] = rev32(hw[0]);
+ while (len > 0) {
+ const unsigned char *src;
+ unsigned char tmp[16];
+ int i;
+ uint32_t a[18], b[18], c[18];
+ uint32_t d0, d1, d2, d3, d4, d5, d6, d7;
+ uint32_t zw[8];
+
+ if (len >= 16) {
+ src = buf;
+ buf += 16;
+ len -= 16;
+ } else {
+ memcpy(tmp, buf, len);
+ memset(tmp + len, 0, (sizeof tmp) - len);
+ src = tmp;
+ len = 0;
+ }
+ yw[3] ^= br_dec32be(src);
+ yw[2] ^= br_dec32be(src + 4);
+ yw[1] ^= br_dec32be(src + 8);
+ yw[0] ^= br_dec32be(src + 12);
+
+ /*
+ * We are using Karatsuba: the 128x128 multiplication is
+ * reduced to three 64x64 multiplications, hence nine
+ * 32x32 multiplications. With the bit-reversal trick,
+ * we have to perform 18 32x32 multiplications.
+ */
+
+ /*
+ * y[0,1]*h[0,1] -> 0,1,4
+ * y[2,3]*h[2,3] -> 2,3,5
+ * (y[0,1]+y[2,3])*(h[0,1]+h[2,3]) -> 6,7,8
+ */
+
+ a[0] = yw[0];
+ a[1] = yw[1];
+ a[2] = yw[2];
+ a[3] = yw[3];
+ a[4] = a[0] ^ a[1];
+ a[5] = a[2] ^ a[3];
+ a[6] = a[0] ^ a[2];
+ a[7] = a[1] ^ a[3];
+ a[8] = a[6] ^ a[7];
+
+ a[ 9] = rev32(yw[0]);
+ a[10] = rev32(yw[1]);
+ a[11] = rev32(yw[2]);
+ a[12] = rev32(yw[3]);
+ a[13] = a[ 9] ^ a[10];
+ a[14] = a[11] ^ a[12];
+ a[15] = a[ 9] ^ a[11];
+ a[16] = a[10] ^ a[12];
+ a[17] = a[15] ^ a[16];
+
+ b[0] = hw[0];
+ b[1] = hw[1];
+ b[2] = hw[2];
+ b[3] = hw[3];
+ b[4] = b[0] ^ b[1];
+ b[5] = b[2] ^ b[3];
+ b[6] = b[0] ^ b[2];
+ b[7] = b[1] ^ b[3];
+ b[8] = b[6] ^ b[7];
+
+ b[ 9] = hwr[0];
+ b[10] = hwr[1];
+ b[11] = hwr[2];
+ b[12] = hwr[3];
+ b[13] = b[ 9] ^ b[10];
+ b[14] = b[11] ^ b[12];
+ b[15] = b[ 9] ^ b[11];
+ b[16] = b[10] ^ b[12];
+ b[17] = b[15] ^ b[16];
+
+ for (i = 0; i < 18; i ++) {
+ c[i] = bmul32(a[i], b[i]);
+ }
+
+ c[4] ^= c[0] ^ c[1];
+ c[5] ^= c[2] ^ c[3];
+ c[8] ^= c[6] ^ c[7];
+
+ c[13] ^= c[ 9] ^ c[10];
+ c[14] ^= c[11] ^ c[12];
+ c[17] ^= c[15] ^ c[16];
+
+ /*
+ * y[0,1]*h[0,1] -> 0,9^4,1^13,10
+ * y[2,3]*h[2,3] -> 2,11^5,3^14,12
+ * (y[0,1]+y[2,3])*(h[0,1]+h[2,3]) -> 6,15^8,7^17,16
+ */
+ d0 = c[0];
+ d1 = c[4] ^ (rev32(c[9]) >> 1);
+ d2 = c[1] ^ c[0] ^ c[2] ^ c[6] ^ (rev32(c[13]) >> 1);
+ d3 = c[4] ^ c[5] ^ c[8]
+ ^ (rev32(c[10] ^ c[9] ^ c[11] ^ c[15]) >> 1);
+ d4 = c[2] ^ c[1] ^ c[3] ^ c[7]
+ ^ (rev32(c[13] ^ c[14] ^ c[17]) >> 1);
+ d5 = c[5] ^ (rev32(c[11] ^ c[10] ^ c[12] ^ c[16]) >> 1);
+ d6 = c[3] ^ (rev32(c[14]) >> 1);
+ d7 = rev32(c[12]) >> 1;
+
+ zw[0] = d0 << 1;
+ zw[1] = (d1 << 1) | (d0 >> 31);
+ zw[2] = (d2 << 1) | (d1 >> 31);
+ zw[3] = (d3 << 1) | (d2 >> 31);
+ zw[4] = (d4 << 1) | (d3 >> 31);
+ zw[5] = (d5 << 1) | (d4 >> 31);
+ zw[6] = (d6 << 1) | (d5 >> 31);
+ zw[7] = (d7 << 1) | (d6 >> 31);
+
+ for (i = 0; i < 4; i ++) {
+ uint32_t lw;
+
+ lw = zw[i];
+ zw[i + 4] ^= lw ^ (lw >> 1) ^ (lw >> 2) ^ (lw >> 7);
+ zw[i + 3] ^= (lw << 31) ^ (lw << 30) ^ (lw << 25);
+ }
+ memcpy(yw, zw + 4, sizeof yw);
+ }
+ br_enc32be(yb, yw[3]);
+ br_enc32be(yb + 4, yw[2]);
+ br_enc32be(yb + 8, yw[1]);
+ br_enc32be(yb + 12, yw[0]);
+}
diff --git a/contrib/bearssl/src/hash/ghash_ctmul64.c b/contrib/bearssl/src/hash/ghash_ctmul64.c
new file mode 100644
index 000000000000..a46f16fee977
--- /dev/null
+++ b/contrib/bearssl/src/hash/ghash_ctmul64.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * This is the 64-bit variant of br_ghash_ctmul32(), with 64-bit operands
+ * and bit reversal of 64-bit words.
+ */
+
+static inline uint64_t
+bmul64(uint64_t x, uint64_t y)
+{
+ uint64_t x0, x1, x2, x3;
+ uint64_t y0, y1, y2, y3;
+ uint64_t z0, z1, z2, z3;
+
+ x0 = x & (uint64_t)0x1111111111111111;
+ x1 = x & (uint64_t)0x2222222222222222;
+ x2 = x & (uint64_t)0x4444444444444444;
+ x3 = x & (uint64_t)0x8888888888888888;
+ y0 = y & (uint64_t)0x1111111111111111;
+ y1 = y & (uint64_t)0x2222222222222222;
+ y2 = y & (uint64_t)0x4444444444444444;
+ y3 = y & (uint64_t)0x8888888888888888;
+ z0 = (x0 * y0) ^ (x1 * y3) ^ (x2 * y2) ^ (x3 * y1);
+ z1 = (x0 * y1) ^ (x1 * y0) ^ (x2 * y3) ^ (x3 * y2);
+ z2 = (x0 * y2) ^ (x1 * y1) ^ (x2 * y0) ^ (x3 * y3);
+ z3 = (x0 * y3) ^ (x1 * y2) ^ (x2 * y1) ^ (x3 * y0);
+ z0 &= (uint64_t)0x1111111111111111;
+ z1 &= (uint64_t)0x2222222222222222;
+ z2 &= (uint64_t)0x4444444444444444;
+ z3 &= (uint64_t)0x8888888888888888;
+ return z0 | z1 | z2 | z3;
+}
+
+static uint64_t
+rev64(uint64_t x)
+{
+#define RMS(m, s) do { \
+ x = ((x & (uint64_t)(m)) << (s)) \
+ | ((x >> (s)) & (uint64_t)(m)); \
+ } while (0)
+
+ RMS(0x5555555555555555, 1);
+ RMS(0x3333333333333333, 2);
+ RMS(0x0F0F0F0F0F0F0F0F, 4);
+ RMS(0x00FF00FF00FF00FF, 8);
+ RMS(0x0000FFFF0000FFFF, 16);
+ return (x << 32) | (x >> 32);
+
+#undef RMS
+}
+
+/* see bearssl_ghash.h */
+void
+br_ghash_ctmul64(void *y, const void *h, const void *data, size_t len)
+{
+ const unsigned char *buf, *hb;
+ unsigned char *yb;
+ uint64_t y0, y1;
+ uint64_t h0, h1, h2, h0r, h1r, h2r;
+
+ buf = data;
+ yb = y;
+ hb = h;
+ y1 = br_dec64be(yb);
+ y0 = br_dec64be(yb + 8);
+ h1 = br_dec64be(hb);
+ h0 = br_dec64be(hb + 8);
+ h0r = rev64(h0);
+ h1r = rev64(h1);
+ h2 = h0 ^ h1;
+ h2r = h0r ^ h1r;
+ while (len > 0) {
+ const unsigned char *src;
+ unsigned char tmp[16];
+ uint64_t y0r, y1r, y2, y2r;
+ uint64_t z0, z1, z2, z0h, z1h, z2h;
+ uint64_t v0, v1, v2, v3;
+
+ if (len >= 16) {
+ src = buf;
+ buf += 16;
+ len -= 16;
+ } else {
+ memcpy(tmp, buf, len);
+ memset(tmp + len, 0, (sizeof tmp) - len);
+ src = tmp;
+ len = 0;
+ }
+ y1 ^= br_dec64be(src);
+ y0 ^= br_dec64be(src + 8);
+
+ y0r = rev64(y0);
+ y1r = rev64(y1);
+ y2 = y0 ^ y1;
+ y2r = y0r ^ y1r;
+
+ z0 = bmul64(y0, h0);
+ z1 = bmul64(y1, h1);
+ z2 = bmul64(y2, h2);
+ z0h = bmul64(y0r, h0r);
+ z1h = bmul64(y1r, h1r);
+ z2h = bmul64(y2r, h2r);
+ z2 ^= z0 ^ z1;
+ z2h ^= z0h ^ z1h;
+ z0h = rev64(z0h) >> 1;
+ z1h = rev64(z1h) >> 1;
+ z2h = rev64(z2h) >> 1;
+
+ v0 = z0;
+ v1 = z0h ^ z2;
+ v2 = z1 ^ z2h;
+ v3 = z1h;
+
+ v3 = (v3 << 1) | (v2 >> 63);
+ v2 = (v2 << 1) | (v1 >> 63);
+ v1 = (v1 << 1) | (v0 >> 63);
+ v0 = (v0 << 1);
+
+ v2 ^= v0 ^ (v0 >> 1) ^ (v0 >> 2) ^ (v0 >> 7);
+ v1 ^= (v0 << 63) ^ (v0 << 62) ^ (v0 << 57);
+ v3 ^= v1 ^ (v1 >> 1) ^ (v1 >> 2) ^ (v1 >> 7);
+ v2 ^= (v1 << 63) ^ (v1 << 62) ^ (v1 << 57);
+
+ y0 = v2;
+ y1 = v3;
+ }
+
+ br_enc64be(yb, y1);
+ br_enc64be(yb + 8, y0);
+}
diff --git a/contrib/bearssl/src/hash/ghash_pclmul.c b/contrib/bearssl/src/hash/ghash_pclmul.c
new file mode 100644
index 000000000000..a58e7dc02beb
--- /dev/null
+++ b/contrib/bearssl/src/hash/ghash_pclmul.c
@@ -0,0 +1,389 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BR_ENABLE_INTRINSICS 1
+#include "inner.h"
+
+/*
+ * This is the GHASH implementation that leverages the pclmulqdq opcode
+ * (from the AES-NI instructions).
+ */
+
+#if BR_AES_X86NI
+
+/*
+ * Test CPU support for PCLMULQDQ.
+ */
+static inline int
+pclmul_supported(void)
+{
+ /*
+ * Bit mask for features in ECX:
+ * 1 PCLMULQDQ support
+ */
+ return br_cpuid(0, 0, 0x00000002, 0);
+}
+
+/* see bearssl_hash.h */
+br_ghash
+br_ghash_pclmul_get(void)
+{
+ return pclmul_supported() ? &br_ghash_pclmul : 0;
+}
+
+BR_TARGETS_X86_UP
+
+/*
+ * GHASH is defined over elements of GF(2^128) with "full little-endian"
+ * representation: leftmost byte is least significant, and, within each
+ * byte, leftmost _bit_ is least significant. The natural ordering in
+ * x86 is "mixed little-endian": bytes are ordered from least to most
+ * significant, but bits within a byte are in most-to-least significant
+ * order. Going to full little-endian representation would require
+ * reversing bits within each byte, which is doable but expensive.
+ *
+ * Instead, we go to full big-endian representation, by swapping bytes
+ * around, which is done with a single _mm_shuffle_epi8() opcode (it
+ * comes with SSSE3; all CPU that offer pclmulqdq also have SSSE3). We
+ * can use a full big-endian representation because in a carryless
+ * multiplication, we have a nice bit reversal property:
+ *
+ * rev_128(x) * rev_128(y) = rev_255(x * y)
+ *
+ * So by using full big-endian, we still get the right result, except
+ * that it is right-shifted by 1 bit. The left-shift is relatively
+ * inexpensive, and it can be mutualised.
+ *
+ *
+ * Since SSE2 opcodes do not have facilities for shitfting full 128-bit
+ * values with bit precision, we have to break down values into 64-bit
+ * chunks. We number chunks from 0 to 3 in left to right order.
+ */
+
+/*
+ * Byte-swap a complete 128-bit value. This normally uses
+ * _mm_shuffle_epi8(), which gets translated to pshufb (an SSSE3 opcode).
+ * However, this crashes old Clang versions, so, for Clang before 3.8,
+ * we use an alternate (and less efficient) version.
+ */
+#if BR_CLANG && !BR_CLANG_3_8
+#define BYTESWAP_DECL
+#define BYTESWAP_PREP (void)0
+#define BYTESWAP(x) do { \
+ __m128i byteswap1, byteswap2; \
+ byteswap1 = (x); \
+ byteswap2 = _mm_srli_epi16(byteswap1, 8); \
+ byteswap1 = _mm_slli_epi16(byteswap1, 8); \
+ byteswap1 = _mm_or_si128(byteswap1, byteswap2); \
+ byteswap1 = _mm_shufflelo_epi16(byteswap1, 0x1B); \
+ byteswap1 = _mm_shufflehi_epi16(byteswap1, 0x1B); \
+ (x) = _mm_shuffle_epi32(byteswap1, 0x4E); \
+ } while (0)
+#else
+#define BYTESWAP_DECL __m128i byteswap_index;
+#define BYTESWAP_PREP do { \
+ byteswap_index = _mm_set_epi8( \
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15); \
+ } while (0)
+#define BYTESWAP(x) do { \
+ (x) = _mm_shuffle_epi8((x), byteswap_index); \
+ } while (0)
+#endif
+
+/*
+ * Call pclmulqdq. Clang appears to have trouble with the intrinsic, so,
+ * for that compiler, we use inline assembly. Inline assembly is
+ * potentially a bit slower because the compiler does not understand
+ * what the opcode does, and thus cannot optimize instruction
+ * scheduling.
+ *
+ * We use a target of "sse2" only, so that Clang may still handle the
+ * '__m128i' type and allocate SSE2 registers.
+ */
+#if BR_CLANG
+BR_TARGET("sse2")
+static inline __m128i
+pclmulqdq00(__m128i x, __m128i y)
+{
+ __asm__ ("pclmulqdq $0x00, %1, %0" : "+x" (x) : "x" (y));
+ return x;
+}
+BR_TARGET("sse2")
+static inline __m128i
+pclmulqdq11(__m128i x, __m128i y)
+{
+ __asm__ ("pclmulqdq $0x11, %1, %0" : "+x" (x) : "x" (y));
+ return x;
+}
+#else
+#define pclmulqdq00(x, y) _mm_clmulepi64_si128(x, y, 0x00)
+#define pclmulqdq11(x, y) _mm_clmulepi64_si128(x, y, 0x11)
+#endif
+
+/*
+ * From a 128-bit value kw, compute kx as the XOR of the two 64-bit
+ * halves of kw (into the right half of kx; left half is unspecified).
+ */
+#define BK(kw, kx) do { \
+ kx = _mm_xor_si128(kw, _mm_shuffle_epi32(kw, 0x0E)); \
+ } while (0)
+
+/*
+ * Combine two 64-bit values (k0:k1) into a 128-bit (kw) value and
+ * the XOR of the two values (kx).
+ */
+#define PBK(k0, k1, kw, kx) do { \
+ kw = _mm_unpacklo_epi64(k1, k0); \
+ kx = _mm_xor_si128(k0, k1); \
+ } while (0)
+
+/*
+ * Left-shift by 1 bit a 256-bit value (in four 64-bit words).
+ */
+#define SL_256(x0, x1, x2, x3) do { \
+ x0 = _mm_or_si128( \
+ _mm_slli_epi64(x0, 1), \
+ _mm_srli_epi64(x1, 63)); \
+ x1 = _mm_or_si128( \
+ _mm_slli_epi64(x1, 1), \
+ _mm_srli_epi64(x2, 63)); \
+ x2 = _mm_or_si128( \
+ _mm_slli_epi64(x2, 1), \
+ _mm_srli_epi64(x3, 63)); \
+ x3 = _mm_slli_epi64(x3, 1); \
+ } while (0)
+
+/*
+ * Perform reduction in GF(2^128). The 256-bit value is in x0..x3;
+ * result is written in x0..x1.
+ */
+#define REDUCE_F128(x0, x1, x2, x3) do { \
+ x1 = _mm_xor_si128( \
+ x1, \
+ _mm_xor_si128( \
+ _mm_xor_si128( \
+ x3, \
+ _mm_srli_epi64(x3, 1)), \
+ _mm_xor_si128( \
+ _mm_srli_epi64(x3, 2), \
+ _mm_srli_epi64(x3, 7)))); \
+ x2 = _mm_xor_si128( \
+ _mm_xor_si128( \
+ x2, \
+ _mm_slli_epi64(x3, 63)), \
+ _mm_xor_si128( \
+ _mm_slli_epi64(x3, 62), \
+ _mm_slli_epi64(x3, 57))); \
+ x0 = _mm_xor_si128( \
+ x0, \
+ _mm_xor_si128( \
+ _mm_xor_si128( \
+ x2, \
+ _mm_srli_epi64(x2, 1)), \
+ _mm_xor_si128( \
+ _mm_srli_epi64(x2, 2), \
+ _mm_srli_epi64(x2, 7)))); \
+ x1 = _mm_xor_si128( \
+ _mm_xor_si128( \
+ x1, \
+ _mm_slli_epi64(x2, 63)), \
+ _mm_xor_si128( \
+ _mm_slli_epi64(x2, 62), \
+ _mm_slli_epi64(x2, 57))); \
+ } while (0)
+
+/*
+ * Square value kw into (dw,dx).
+ */
+#define SQUARE_F128(kw, dw, dx) do { \
+ __m128i z0, z1, z2, z3; \
+ z1 = pclmulqdq11(kw, kw); \
+ z3 = pclmulqdq00(kw, kw); \
+ z0 = _mm_shuffle_epi32(z1, 0x0E); \
+ z2 = _mm_shuffle_epi32(z3, 0x0E); \
+ SL_256(z0, z1, z2, z3); \
+ REDUCE_F128(z0, z1, z2, z3); \
+ PBK(z0, z1, dw, dx); \
+ } while (0)
+
+/* see bearssl_hash.h */
+BR_TARGET("ssse3,pclmul")
+void
+br_ghash_pclmul(void *y, const void *h, const void *data, size_t len)
+{
+ const unsigned char *buf1, *buf2;
+ unsigned char tmp[64];
+ size_t num4, num1;
+ __m128i yw, h1w, h1x;
+ BYTESWAP_DECL
+
+ /*
+ * We split data into two chunks. First chunk starts at buf1
+ * and contains num4 blocks of 64-byte values. Second chunk
+ * starts at buf2 and contains num1 blocks of 16-byte values.
+ * We want the first chunk to be as large as possible.
+ */
+ buf1 = data;
+ num4 = len >> 6;
+ len &= 63;
+ buf2 = buf1 + (num4 << 6);
+ num1 = (len + 15) >> 4;
+ if ((len & 15) != 0) {
+ memcpy(tmp, buf2, len);
+ memset(tmp + len, 0, (num1 << 4) - len);
+ buf2 = tmp;
+ }
+
+ /*
+ * Preparatory step for endian conversions.
+ */
+ BYTESWAP_PREP;
+
+ /*
+ * Load y and h.
+ */
+ yw = _mm_loadu_si128(y);
+ h1w = _mm_loadu_si128(h);
+ BYTESWAP(yw);
+ BYTESWAP(h1w);
+ BK(h1w, h1x);
+
+ if (num4 > 0) {
+ __m128i h2w, h2x, h3w, h3x, h4w, h4x;
+ __m128i t0, t1, t2, t3;
+
+ /*
+ * Compute h2 = h^2.
+ */
+ SQUARE_F128(h1w, h2w, h2x);
+
+ /*
+ * Compute h3 = h^3 = h*(h^2).
+ */
+ t1 = pclmulqdq11(h1w, h2w);
+ t3 = pclmulqdq00(h1w, h2w);
+ t2 = _mm_xor_si128(pclmulqdq00(h1x, h2x),
+ _mm_xor_si128(t1, t3));
+ t0 = _mm_shuffle_epi32(t1, 0x0E);
+ t1 = _mm_xor_si128(t1, _mm_shuffle_epi32(t2, 0x0E));
+ t2 = _mm_xor_si128(t2, _mm_shuffle_epi32(t3, 0x0E));
+ SL_256(t0, t1, t2, t3);
+ REDUCE_F128(t0, t1, t2, t3);
+ PBK(t0, t1, h3w, h3x);
+
+ /*
+ * Compute h4 = h^4 = (h^2)^2.
+ */
+ SQUARE_F128(h2w, h4w, h4x);
+
+ while (num4 -- > 0) {
+ __m128i aw0, aw1, aw2, aw3;
+ __m128i ax0, ax1, ax2, ax3;
+
+ aw0 = _mm_loadu_si128((void *)(buf1 + 0));
+ aw1 = _mm_loadu_si128((void *)(buf1 + 16));
+ aw2 = _mm_loadu_si128((void *)(buf1 + 32));
+ aw3 = _mm_loadu_si128((void *)(buf1 + 48));
+ BYTESWAP(aw0);
+ BYTESWAP(aw1);
+ BYTESWAP(aw2);
+ BYTESWAP(aw3);
+ buf1 += 64;
+
+ aw0 = _mm_xor_si128(aw0, yw);
+ BK(aw1, ax1);
+ BK(aw2, ax2);
+ BK(aw3, ax3);
+ BK(aw0, ax0);
+
+ t1 = _mm_xor_si128(
+ _mm_xor_si128(
+ pclmulqdq11(aw0, h4w),
+ pclmulqdq11(aw1, h3w)),
+ _mm_xor_si128(
+ pclmulqdq11(aw2, h2w),
+ pclmulqdq11(aw3, h1w)));
+ t3 = _mm_xor_si128(
+ _mm_xor_si128(
+ pclmulqdq00(aw0, h4w),
+ pclmulqdq00(aw1, h3w)),
+ _mm_xor_si128(
+ pclmulqdq00(aw2, h2w),
+ pclmulqdq00(aw3, h1w)));
+ t2 = _mm_xor_si128(
+ _mm_xor_si128(
+ pclmulqdq00(ax0, h4x),
+ pclmulqdq00(ax1, h3x)),
+ _mm_xor_si128(
+ pclmulqdq00(ax2, h2x),
+ pclmulqdq00(ax3, h1x)));
+ t2 = _mm_xor_si128(t2, _mm_xor_si128(t1, t3));
+ t0 = _mm_shuffle_epi32(t1, 0x0E);
+ t1 = _mm_xor_si128(t1, _mm_shuffle_epi32(t2, 0x0E));
+ t2 = _mm_xor_si128(t2, _mm_shuffle_epi32(t3, 0x0E));
+ SL_256(t0, t1, t2, t3);
+ REDUCE_F128(t0, t1, t2, t3);
+ yw = _mm_unpacklo_epi64(t1, t0);
+ }
+ }
+
+ while (num1 -- > 0) {
+ __m128i aw, ax;
+ __m128i t0, t1, t2, t3;
+
+ aw = _mm_loadu_si128((void *)buf2);
+ BYTESWAP(aw);
+ buf2 += 16;
+
+ aw = _mm_xor_si128(aw, yw);
+ BK(aw, ax);
+
+ t1 = pclmulqdq11(aw, h1w);
+ t3 = pclmulqdq00(aw, h1w);
+ t2 = pclmulqdq00(ax, h1x);
+ t2 = _mm_xor_si128(t2, _mm_xor_si128(t1, t3));
+ t0 = _mm_shuffle_epi32(t1, 0x0E);
+ t1 = _mm_xor_si128(t1, _mm_shuffle_epi32(t2, 0x0E));
+ t2 = _mm_xor_si128(t2, _mm_shuffle_epi32(t3, 0x0E));
+ SL_256(t0, t1, t2, t3);
+ REDUCE_F128(t0, t1, t2, t3);
+ yw = _mm_unpacklo_epi64(t1, t0);
+ }
+
+ BYTESWAP(yw);
+ _mm_storeu_si128(y, yw);
+}
+
+BR_TARGETS_X86_DOWN
+
+#else
+
+/* see bearssl_hash.h */
+br_ghash
+br_ghash_pclmul_get(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/contrib/bearssl/src/hash/ghash_pwr8.c b/contrib/bearssl/src/hash/ghash_pwr8.c
new file mode 100644
index 000000000000..2e7b0f4cb0c5
--- /dev/null
+++ b/contrib/bearssl/src/hash/ghash_pwr8.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BR_POWER_ASM_MACROS 1
+#include "inner.h"
+
+/*
+ * This is the GHASH implementation that leverages the POWER8 opcodes.
+ */
+
+#if BR_POWER8
+
+/*
+ * Some symbolic names for registers.
+ * HB0 = 16 bytes of value 0
+ * HB1 = 16 bytes of value 1
+ * HB2 = 16 bytes of value 2
+ * HB6 = 16 bytes of value 6
+ * HB7 = 16 bytes of value 7
+ * TT0, TT1 and TT2 are temporaries
+ *
+ * BSW holds the pattern for byteswapping 32-bit words; this is set only
+ * on little-endian systems. XBSW is the same register with the +32 offset
+ * for access with the VSX opcodes.
+ */
+#define HB0 0
+#define HB1 1
+#define HB2 2
+#define HB6 3
+#define HB7 4
+#define TT0 5
+#define TT1 6
+#define TT2 7
+
+#define BSW 8
+#define XBSW 40
+
+/*
+ * Macro to initialise the constants.
+ */
+#define INIT \
+ vxor(HB0, HB0, HB0) \
+ vspltisb(HB1, 1) \
+ vspltisb(HB2, 2) \
+ vspltisb(HB6, 6) \
+ vspltisb(HB7, 7) \
+ INIT_BSW
+
+/*
+ * Fix endianness of a value after reading it or before writing it, if
+ * necessary.
+ */
+#if BR_POWER8_LE
+#define INIT_BSW lxvw4x(XBSW, 0, %[idx2be])
+#define FIX_ENDIAN(xx) vperm(xx, xx, xx, BSW)
+#else
+#define INIT_BSW
+#define FIX_ENDIAN(xx)
+#endif
+
+/*
+ * Left-shift x0:x1 by one bit to the left. This is a corrective action
+ * needed because GHASH is defined in full little-endian specification,
+ * while the opcodes use full big-endian convention, so the 255-bit product
+ * ends up one bit to the right.
+ */
+#define SL_256(x0, x1) \
+ vsldoi(TT0, HB0, x1, 1) \
+ vsl(x0, x0, HB1) \
+ vsr(TT0, TT0, HB7) \
+ vsl(x1, x1, HB1) \
+ vxor(x0, x0, TT0)
+
+/*
+ * Reduce x0:x1 in GF(2^128), result in xd (register xd may be the same as
+ * x0 or x1, or a different register). x0 and x1 are modified.
+ */
+#define REDUCE_F128(xd, x0, x1) \
+ vxor(x0, x0, x1) \
+ vsr(TT0, x1, HB1) \
+ vsr(TT1, x1, HB2) \
+ vsr(TT2, x1, HB7) \
+ vxor(x0, x0, TT0) \
+ vxor(TT1, TT1, TT2) \
+ vxor(x0, x0, TT1) \
+ vsldoi(x1, x1, HB0, 15) \
+ vsl(TT1, x1, HB6) \
+ vsl(TT2, x1, HB1) \
+ vxor(x1, TT1, TT2) \
+ vsr(TT0, x1, HB1) \
+ vsr(TT1, x1, HB2) \
+ vsr(TT2, x1, HB7) \
+ vxor(x0, x0, x1) \
+ vxor(x0, x0, TT0) \
+ vxor(TT1, TT1, TT2) \
+ vxor(xd, x0, TT1)
+
+/* see bearssl_hash.h */
+void
+br_ghash_pwr8(void *y, const void *h, const void *data, size_t len)
+{
+ const unsigned char *buf1, *buf2;
+ size_t num4, num1;
+ unsigned char tmp[64];
+ long cc0, cc1, cc2, cc3;
+
+#if BR_POWER8_LE
+ static const uint32_t idx2be[] = {
+ 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
+ };
+#endif
+
+ buf1 = data;
+
+ /*
+ * Assembly code requires data into two chunks; first chunk
+ * must contain a number of blocks which is a multiple of 4.
+ * Since the processing for the first chunk is faster, we want
+ * to make it as big as possible.
+ *
+ * For the remainder, there are two possibilities:
+ * -- if the remainder size is a multiple of 16, then use it
+ * in place;
+ * -- otherwise, copy it to the tmp[] array and pad it with
+ * zeros.
+ */
+ num4 = len >> 6;
+ buf2 = buf1 + (num4 << 6);
+ len &= 63;
+ num1 = (len + 15) >> 4;
+ if ((len & 15) != 0) {
+ memcpy(tmp, buf2, len);
+ memset(tmp + len, 0, (num1 << 4) - len);
+ buf2 = tmp;
+ }
+
+ cc0 = 0;
+ cc1 = 16;
+ cc2 = 32;
+ cc3 = 48;
+ asm volatile (
+ INIT
+
+ /*
+ * Load current h (denoted hereafter h1) in v9.
+ */
+ lxvw4x(41, 0, %[h])
+ FIX_ENDIAN(9)
+
+ /*
+ * Load current y into v28.
+ */
+ lxvw4x(60, 0, %[y])
+ FIX_ENDIAN(28)
+
+ /*
+ * Split h1 into three registers:
+ * v17 = h1_1:h1_0
+ * v18 = 0:h1_0
+ * v19 = h1_1:0
+ */
+ xxpermdi(49, 41, 41, 2)
+ vsldoi(18, HB0, 9, 8)
+ vsldoi(19, 9, HB0, 8)
+
+ /*
+ * If num4 is 0, skip directly to the second chunk.
+ */
+ cmpldi(%[num4], 0)
+ beq(chunk1)
+
+ /*
+ * Compute h2 = h*h in v10.
+ */
+ vpmsumd(10, 18, 18)
+ vpmsumd(11, 19, 19)
+ SL_256(10, 11)
+ REDUCE_F128(10, 10, 11)
+
+ /*
+ * Compute h3 = h*h*h in v11.
+ * We first split h2 into:
+ * v10 = h2_0:h2_1
+ * v11 = 0:h2_0
+ * v12 = h2_1:0
+ * Then we do the product with h1, and reduce into v11.
+ */
+ vsldoi(11, HB0, 10, 8)
+ vsldoi(12, 10, HB0, 8)
+ vpmsumd(13, 10, 17)
+ vpmsumd(11, 11, 18)
+ vpmsumd(12, 12, 19)
+ vsldoi(14, HB0, 13, 8)
+ vsldoi(15, 13, HB0, 8)
+ vxor(11, 11, 14)
+ vxor(12, 12, 15)
+ SL_256(11, 12)
+ REDUCE_F128(11, 11, 12)
+
+ /*
+ * Compute h4 = h*h*h*h in v12. This is done by squaring h2.
+ */
+ vsldoi(12, HB0, 10, 8)
+ vsldoi(13, 10, HB0, 8)
+ vpmsumd(12, 12, 12)
+ vpmsumd(13, 13, 13)
+ SL_256(12, 13)
+ REDUCE_F128(12, 12, 13)
+
+ /*
+ * Repack h1, h2, h3 and h4:
+ * v13 = h4_0:h3_0
+ * v14 = h4_1:h3_1
+ * v15 = h2_0:h1_0
+ * v16 = h2_1:h1_1
+ */
+ xxpermdi(45, 44, 43, 0)
+ xxpermdi(46, 44, 43, 3)
+ xxpermdi(47, 42, 41, 0)
+ xxpermdi(48, 42, 41, 3)
+
+ /*
+ * Loop for each group of four blocks.
+ */
+ mtctr(%[num4])
+ label(loop4)
+ /*
+ * Read the four next blocks.
+ * v20 = y + a0 = b0
+ * v21 = a1 = b1
+ * v22 = a2 = b2
+ * v23 = a3 = b3
+ */
+ lxvw4x(52, %[cc0], %[buf1])
+ lxvw4x(53, %[cc1], %[buf1])
+ lxvw4x(54, %[cc2], %[buf1])
+ lxvw4x(55, %[cc3], %[buf1])
+ FIX_ENDIAN(20)
+ FIX_ENDIAN(21)
+ FIX_ENDIAN(22)
+ FIX_ENDIAN(23)
+ addi(%[buf1], %[buf1], 64)
+ vxor(20, 20, 28)
+
+ /*
+ * Repack the blocks into v9, v10, v11 and v12.
+ * v9 = b0_0:b1_0
+ * v10 = b0_1:b1_1
+ * v11 = b2_0:b3_0
+ * v12 = b2_1:b3_1
+ */
+ xxpermdi(41, 52, 53, 0)
+ xxpermdi(42, 52, 53, 3)
+ xxpermdi(43, 54, 55, 0)
+ xxpermdi(44, 54, 55, 3)
+
+ /*
+ * Compute the products.
+ * v20 = b0_0*h4_0 + b1_0*h3_0
+ * v21 = b0_1*h4_0 + b1_1*h3_0
+ * v22 = b0_0*h4_1 + b1_0*h3_1
+ * v23 = b0_1*h4_1 + b1_1*h3_1
+ * v24 = b2_0*h2_0 + b3_0*h1_0
+ * v25 = b2_1*h2_0 + b3_1*h1_0
+ * v26 = b2_0*h2_1 + b3_0*h1_1
+ * v27 = b2_1*h2_1 + b3_1*h1_1
+ */
+ vpmsumd(20, 13, 9)
+ vpmsumd(21, 13, 10)
+ vpmsumd(22, 14, 9)
+ vpmsumd(23, 14, 10)
+ vpmsumd(24, 15, 11)
+ vpmsumd(25, 15, 12)
+ vpmsumd(26, 16, 11)
+ vpmsumd(27, 16, 12)
+
+ /*
+ * Sum products into a single 256-bit result in v11:v12.
+ */
+ vxor(11, 20, 24)
+ vxor(12, 23, 27)
+ vxor( 9, 21, 22)
+ vxor(10, 25, 26)
+ vxor(20, 9, 10)
+ vsldoi( 9, HB0, 20, 8)
+ vsldoi(10, 20, HB0, 8)
+ vxor(11, 11, 9)
+ vxor(12, 12, 10)
+
+ /*
+ * Fix and reduce in GF(2^128); this is the new y (in v28).
+ */
+ SL_256(11, 12)
+ REDUCE_F128(28, 11, 12)
+
+ /*
+ * Loop for next group of four blocks.
+ */
+ bdnz(loop4)
+
+ /*
+ * Process second chunk, one block at a time.
+ */
+ label(chunk1)
+ cmpldi(%[num1], 0)
+ beq(done)
+
+ mtctr(%[num1])
+ label(loop1)
+ /*
+ * Load next data block and XOR it into y.
+ */
+ lxvw4x(41, 0, %[buf2])
+#if BR_POWER8_LE
+ FIX_ENDIAN(9)
+#endif
+ addi(%[buf2], %[buf2], 16)
+ vxor(9, 28, 9)
+
+ /*
+ * Split y into doublewords:
+ * v9 = y_0:y_1
+ * v10 = 0:y_0
+ * v11 = y_1:0
+ */
+ vsldoi(10, HB0, 9, 8)
+ vsldoi(11, 9, HB0, 8)
+
+ /*
+ * Compute products with h:
+ * v12 = y_0 * h_0
+ * v13 = y_1 * h_1
+ * v14 = y_1 * h_0 + y_0 * h_1
+ */
+ vpmsumd(14, 9, 17)
+ vpmsumd(12, 10, 18)
+ vpmsumd(13, 11, 19)
+
+ /*
+ * Propagate v14 into v12:v13 to finalise product.
+ */
+ vsldoi(10, HB0, 14, 8)
+ vsldoi(11, 14, HB0, 8)
+ vxor(12, 12, 10)
+ vxor(13, 13, 11)
+
+ /*
+ * Fix result and reduce into v28 (next value for y).
+ */
+ SL_256(12, 13)
+ REDUCE_F128(28, 12, 13)
+ bdnz(loop1)
+
+ label(done)
+ /*
+ * Write back the new y.
+ */
+ FIX_ENDIAN(28)
+ stxvw4x(60, 0, %[y])
+
+: [buf1] "+b" (buf1), [buf2] "+b" (buf2)
+: [y] "b" (y), [h] "b" (h), [num4] "b" (num4), [num1] "b" (num1),
+ [cc0] "b" (cc0), [cc1] "b" (cc1), [cc2] "b" (cc2), [cc3] "b" (cc3)
+#if BR_POWER8_LE
+ , [idx2be] "b" (idx2be)
+#endif
+: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9",
+ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19",
+ "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29",
+ "ctr", "memory"
+ );
+}
+
+/* see bearssl_hash.h */
+br_ghash
+br_ghash_pwr8_get(void)
+{
+ return &br_ghash_pwr8;
+}
+
+#else
+
+/* see bearssl_hash.h */
+br_ghash
+br_ghash_pwr8_get(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/contrib/bearssl/src/hash/md5.c b/contrib/bearssl/src/hash/md5.c
new file mode 100644
index 000000000000..0df7abe018bc
--- /dev/null
+++ b/contrib/bearssl/src/hash/md5.c
@@ -0,0 +1,208 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#define F(B, C, D) ((((C) ^ (D)) & (B)) ^ (D))
+#define G(B, C, D) ((((C) ^ (B)) & (D)) ^ (C))
+#define H(B, C, D) ((B) ^ (C) ^ (D))
+#define I(B, C, D) ((C) ^ ((B) | ~(D)))
+
+#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+/* see inner.h */
+const uint32_t br_md5_IV[4] = {
+ 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476
+};
+
+static const uint32_t K[64] = {
+ 0xD76AA478, 0xE8C7B756, 0x242070DB, 0xC1BDCEEE,
+ 0xF57C0FAF, 0x4787C62A, 0xA8304613, 0xFD469501,
+ 0x698098D8, 0x8B44F7AF, 0xFFFF5BB1, 0x895CD7BE,
+ 0x6B901122, 0xFD987193, 0xA679438E, 0x49B40821,
+
+ 0xF61E2562, 0xC040B340, 0x265E5A51, 0xE9B6C7AA,
+ 0xD62F105D, 0x02441453, 0xD8A1E681, 0xE7D3FBC8,
+ 0x21E1CDE6, 0xC33707D6, 0xF4D50D87, 0x455A14ED,
+ 0xA9E3E905, 0xFCEFA3F8, 0x676F02D9, 0x8D2A4C8A,
+
+ 0xFFFA3942, 0x8771F681, 0x6D9D6122, 0xFDE5380C,
+ 0xA4BEEA44, 0x4BDECFA9, 0xF6BB4B60, 0xBEBFBC70,
+ 0x289B7EC6, 0xEAA127FA, 0xD4EF3085, 0x04881D05,
+ 0xD9D4D039, 0xE6DB99E5, 0x1FA27CF8, 0xC4AC5665,
+
+ 0xF4292244, 0x432AFF97, 0xAB9423A7, 0xFC93A039,
+ 0x655B59C3, 0x8F0CCC92, 0xFFEFF47D, 0x85845DD1,
+ 0x6FA87E4F, 0xFE2CE6E0, 0xA3014314, 0x4E0811A1,
+ 0xF7537E82, 0xBD3AF235, 0x2AD7D2BB, 0xEB86D391
+};
+
+static const unsigned char MP[48] = {
+ 1, 6, 11, 0, 5, 10, 15, 4, 9, 14, 3, 8, 13, 2, 7, 12,
+ 5, 8, 11, 14, 1, 4, 7, 10, 13, 0, 3, 6, 9, 12, 15, 2,
+ 0, 7, 14, 5, 12, 3, 10, 1, 8, 15, 6, 13, 4, 11, 2, 9
+};
+
+/* see inner.h */
+void
+br_md5_round(const unsigned char *buf, uint32_t *val)
+{
+ uint32_t m[16];
+ uint32_t a, b, c, d;
+ int i;
+
+ a = val[0];
+ b = val[1];
+ c = val[2];
+ d = val[3];
+ /* obsolete
+ for (i = 0; i < 16; i ++) {
+ m[i] = br_dec32le(buf + (i << 2));
+ }
+ */
+ br_range_dec32le(m, 16, buf);
+
+ for (i = 0; i < 16; i += 4) {
+ a = b + ROTL(a + F(b, c, d) + m[i + 0] + K[i + 0], 7);
+ d = a + ROTL(d + F(a, b, c) + m[i + 1] + K[i + 1], 12);
+ c = d + ROTL(c + F(d, a, b) + m[i + 2] + K[i + 2], 17);
+ b = c + ROTL(b + F(c, d, a) + m[i + 3] + K[i + 3], 22);
+ }
+ for (i = 16; i < 32; i += 4) {
+ a = b + ROTL(a + G(b, c, d) + m[MP[i - 16]] + K[i + 0], 5);
+ d = a + ROTL(d + G(a, b, c) + m[MP[i - 15]] + K[i + 1], 9);
+ c = d + ROTL(c + G(d, a, b) + m[MP[i - 14]] + K[i + 2], 14);
+ b = c + ROTL(b + G(c, d, a) + m[MP[i - 13]] + K[i + 3], 20);
+ }
+ for (i = 32; i < 48; i += 4) {
+ a = b + ROTL(a + H(b, c, d) + m[MP[i - 16]] + K[i + 0], 4);
+ d = a + ROTL(d + H(a, b, c) + m[MP[i - 15]] + K[i + 1], 11);
+ c = d + ROTL(c + H(d, a, b) + m[MP[i - 14]] + K[i + 2], 16);
+ b = c + ROTL(b + H(c, d, a) + m[MP[i - 13]] + K[i + 3], 23);
+ }
+ for (i = 48; i < 64; i += 4) {
+ a = b + ROTL(a + I(b, c, d) + m[MP[i - 16]] + K[i + 0], 6);
+ d = a + ROTL(d + I(a, b, c) + m[MP[i - 15]] + K[i + 1], 10);
+ c = d + ROTL(c + I(d, a, b) + m[MP[i - 14]] + K[i + 2], 15);
+ b = c + ROTL(b + I(c, d, a) + m[MP[i - 13]] + K[i + 3], 21);
+ }
+
+ val[0] += a;
+ val[1] += b;
+ val[2] += c;
+ val[3] += d;
+}
+
+/* see bearssl.h */
+void
+br_md5_init(br_md5_context *cc)
+{
+ cc->vtable = &br_md5_vtable;
+ memcpy(cc->val, br_md5_IV, sizeof cc->val);
+ cc->count = 0;
+}
+
+/* see bearssl.h */
+void
+br_md5_update(br_md5_context *cc, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ size_t ptr;
+
+ buf = data;
+ ptr = (size_t)cc->count & 63;
+ while (len > 0) {
+ size_t clen;
+
+ clen = 64 - ptr;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(cc->buf + ptr, buf, clen);
+ ptr += clen;
+ buf += clen;
+ len -= clen;
+ cc->count += (uint64_t)clen;
+ if (ptr == 64) {
+ br_md5_round(cc->buf, cc->val);
+ ptr = 0;
+ }
+ }
+}
+
+/* see bearssl.h */
+void
+br_md5_out(const br_md5_context *cc, void *dst)
+{
+ unsigned char buf[64];
+ uint32_t val[4];
+ size_t ptr;
+
+ ptr = (size_t)cc->count & 63;
+ memcpy(buf, cc->buf, ptr);
+ memcpy(val, cc->val, sizeof val);
+ buf[ptr ++] = 0x80;
+ if (ptr > 56) {
+ memset(buf + ptr, 0, 64 - ptr);
+ br_md5_round(buf, val);
+ memset(buf, 0, 56);
+ } else {
+ memset(buf + ptr, 0, 56 - ptr);
+ }
+ br_enc64le(buf + 56, cc->count << 3);
+ br_md5_round(buf, val);
+ br_range_enc32le(dst, val, 4);
+}
+
+/* see bearssl.h */
+uint64_t
+br_md5_state(const br_md5_context *cc, void *dst)
+{
+ br_range_enc32le(dst, cc->val, 4);
+ return cc->count;
+}
+
+/* see bearssl.h */
+void
+br_md5_set_state(br_md5_context *cc, const void *stb, uint64_t count)
+{
+ br_range_dec32le(cc->val, 4, stb);
+ cc->count = count;
+}
+
+/* see bearssl.h */
+const br_hash_class br_md5_vtable = {
+ sizeof(br_md5_context),
+ BR_HASHDESC_ID(br_md5_ID)
+ | BR_HASHDESC_OUT(16)
+ | BR_HASHDESC_STATE(16)
+ | BR_HASHDESC_LBLEN(6)
+ | BR_HASHDESC_MD_PADDING,
+ (void (*)(const br_hash_class **))&br_md5_init,
+ (void (*)(const br_hash_class **, const void *, size_t))&br_md5_update,
+ (void (*)(const br_hash_class *const *, void *))&br_md5_out,
+ (uint64_t (*)(const br_hash_class *const *, void *))&br_md5_state,
+ (void (*)(const br_hash_class **, const void *, uint64_t))
+ &br_md5_set_state
+};
diff --git a/contrib/bearssl/src/hash/md5sha1.c b/contrib/bearssl/src/hash/md5sha1.c
new file mode 100644
index 000000000000..f701aeede45f
--- /dev/null
+++ b/contrib/bearssl/src/hash/md5sha1.c
@@ -0,0 +1,141 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl.h */
+void
+br_md5sha1_init(br_md5sha1_context *cc)
+{
+ cc->vtable = &br_md5sha1_vtable;
+ memcpy(cc->val_md5, br_md5_IV, sizeof cc->val_md5);
+ memcpy(cc->val_sha1, br_sha1_IV, sizeof cc->val_sha1);
+ cc->count = 0;
+}
+
+/* see bearssl.h */
+void
+br_md5sha1_update(br_md5sha1_context *cc, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ size_t ptr;
+
+ buf = data;
+ ptr = (size_t)cc->count & 63;
+ while (len > 0) {
+ size_t clen;
+
+ clen = 64 - ptr;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(cc->buf + ptr, buf, clen);
+ ptr += clen;
+ buf += clen;
+ len -= clen;
+ cc->count += (uint64_t)clen;
+ if (ptr == 64) {
+ br_md5_round(cc->buf, cc->val_md5);
+ br_sha1_round(cc->buf, cc->val_sha1);
+ ptr = 0;
+ }
+ }
+}
+
+/* see bearssl.h */
+void
+br_md5sha1_out(const br_md5sha1_context *cc, void *dst)
+{
+ unsigned char buf[64];
+ uint32_t val_md5[4];
+ uint32_t val_sha1[5];
+ size_t ptr;
+ unsigned char *out;
+ uint64_t count;
+
+ count = cc->count;
+ ptr = (size_t)count & 63;
+ memcpy(buf, cc->buf, ptr);
+ memcpy(val_md5, cc->val_md5, sizeof val_md5);
+ memcpy(val_sha1, cc->val_sha1, sizeof val_sha1);
+ buf[ptr ++] = 0x80;
+ if (ptr > 56) {
+ memset(buf + ptr, 0, 64 - ptr);
+ br_md5_round(buf, val_md5);
+ br_sha1_round(buf, val_sha1);
+ memset(buf, 0, 56);
+ } else {
+ memset(buf + ptr, 0, 56 - ptr);
+ }
+ count <<= 3;
+ br_enc64le(buf + 56, count);
+ br_md5_round(buf, val_md5);
+ br_enc64be(buf + 56, count);
+ br_sha1_round(buf, val_sha1);
+ out = dst;
+ br_range_enc32le(out, val_md5, 4);
+ br_range_enc32be(out + 16, val_sha1, 5);
+}
+
+/* see bearssl.h */
+uint64_t
+br_md5sha1_state(const br_md5sha1_context *cc, void *dst)
+{
+ unsigned char *out;
+
+ out = dst;
+ br_range_enc32le(out, cc->val_md5, 4);
+ br_range_enc32be(out + 16, cc->val_sha1, 5);
+ return cc->count;
+}
+
+/* see bearssl.h */
+void
+br_md5sha1_set_state(br_md5sha1_context *cc, const void *stb, uint64_t count)
+{
+ const unsigned char *buf;
+
+ buf = stb;
+ br_range_dec32le(cc->val_md5, 4, buf);
+ br_range_dec32be(cc->val_sha1, 5, buf + 16);
+ cc->count = count;
+}
+
+/* see bearssl.h */
+const br_hash_class br_md5sha1_vtable = {
+ sizeof(br_md5sha1_context),
+ BR_HASHDESC_ID(br_md5sha1_ID)
+ | BR_HASHDESC_OUT(36)
+ | BR_HASHDESC_STATE(36)
+ | BR_HASHDESC_LBLEN(6),
+ (void (*)(const br_hash_class **))&br_md5sha1_init,
+ (void (*)(const br_hash_class **, const void *, size_t))
+ &br_md5sha1_update,
+ (void (*)(const br_hash_class *const *, void *))
+ &br_md5sha1_out,
+ (uint64_t (*)(const br_hash_class *const *, void *))
+ &br_md5sha1_state,
+ (void (*)(const br_hash_class **, const void *, uint64_t))
+ &br_md5sha1_set_state
+};
diff --git a/contrib/bearssl/src/hash/mgf1.c b/contrib/bearssl/src/hash/mgf1.c
new file mode 100644
index 000000000000..7a235887b348
--- /dev/null
+++ b/contrib/bearssl/src/hash/mgf1.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_mgf1_xor(void *data, size_t len,
+ const br_hash_class *dig, const void *seed, size_t seed_len)
+{
+ unsigned char *buf;
+ size_t u, hlen;
+ uint32_t c;
+
+ buf = data;
+ hlen = br_digest_size(dig);
+ for (u = 0, c = 0; u < len; u += hlen, c ++) {
+ br_hash_compat_context hc;
+ unsigned char tmp[64];
+ size_t v;
+
+ hc.vtable = dig;
+ dig->init(&hc.vtable);
+ dig->update(&hc.vtable, seed, seed_len);
+ br_enc32be(tmp, c);
+ dig->update(&hc.vtable, tmp, 4);
+ dig->out(&hc.vtable, tmp);
+ for (v = 0; v < hlen; v ++) {
+ if ((u + v) >= len) {
+ break;
+ }
+ buf[u + v] ^= tmp[v];
+ }
+ }
+}
diff --git a/contrib/bearssl/src/hash/multihash.c b/contrib/bearssl/src/hash/multihash.c
new file mode 100644
index 000000000000..b6df2e0ed31c
--- /dev/null
+++ b/contrib/bearssl/src/hash/multihash.c
@@ -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 "inner.h"
+
+/*
+ * An aggregate context that is large enough for all supported hash
+ * functions.
+ */
+typedef union {
+ const br_hash_class *vtable;
+ br_md5_context md5;
+ br_sha1_context sha1;
+ br_sha224_context sha224;
+ br_sha256_context sha256;
+ br_sha384_context sha384;
+ br_sha512_context sha512;
+} gen_hash_context;
+
+/*
+ * Get the offset to the state for a specific hash function within the
+ * context structure. This shall be called only for the supported hash
+ * functions,
+ */
+static size_t
+get_state_offset(int id)
+{
+ if (id >= 5) {
+ /*
+ * SHA-384 has id 5, and SHA-512 has id 6. Both use
+ * eight 64-bit words for their state.
+ */
+ return offsetof(br_multihash_context, val_64)
+ + ((size_t)(id - 5) * (8 * sizeof(uint64_t)));
+ } else {
+ /*
+ * MD5 has id 1, SHA-1 has id 2, SHA-224 has id 3 and
+ * SHA-256 has id 4. They use 32-bit words for their
+ * states (4 words for MD5, 5 for SHA-1, 8 for SHA-224
+ * and 8 for SHA-256).
+ */
+ unsigned x;
+
+ x = id - 1;
+ x = ((x + (x & (x >> 1))) << 2) + (x >> 1);
+ return offsetof(br_multihash_context, val_32)
+ + x * sizeof(uint32_t);
+ }
+}
+
+/* see bearssl_hash.h */
+void
+br_multihash_zero(br_multihash_context *ctx)
+{
+ /*
+ * This is not standard, but yields very short and efficient code,
+ * and it works "everywhere".
+ */
+ memset(ctx, 0, sizeof *ctx);
+}
+
+/* see bearssl_hash.h */
+void
+br_multihash_init(br_multihash_context *ctx)
+{
+ int i;
+
+ ctx->count = 0;
+ for (i = 1; i <= 6; i ++) {
+ const br_hash_class *hc;
+
+ hc = ctx->impl[i - 1];
+ if (hc != NULL) {
+ gen_hash_context g;
+
+ hc->init(&g.vtable);
+ hc->state(&g.vtable,
+ (unsigned char *)ctx + get_state_offset(i));
+ }
+ }
+}
+
+/* see bearssl_hash.h */
+void
+br_multihash_update(br_multihash_context *ctx, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ size_t ptr;
+
+ buf = data;
+ ptr = (size_t)ctx->count & 127;
+ while (len > 0) {
+ size_t clen;
+
+ clen = 128 - ptr;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(ctx->buf + ptr, buf, clen);
+ ptr += clen;
+ buf += clen;
+ len -= clen;
+ ctx->count += (uint64_t)clen;
+ if (ptr == 128) {
+ int i;
+
+ for (i = 1; i <= 6; i ++) {
+ const br_hash_class *hc;
+
+ hc = ctx->impl[i - 1];
+ if (hc != NULL) {
+ gen_hash_context g;
+ unsigned char *state;
+
+ state = (unsigned char *)ctx
+ + get_state_offset(i);
+ hc->set_state(&g.vtable,
+ state, ctx->count - 128);
+ hc->update(&g.vtable, ctx->buf, 128);
+ hc->state(&g.vtable, state);
+ }
+ }
+ ptr = 0;
+ }
+ }
+}
+
+/* see bearssl_hash.h */
+size_t
+br_multihash_out(const br_multihash_context *ctx, int id, void *dst)
+{
+ const br_hash_class *hc;
+ gen_hash_context g;
+ const unsigned char *state;
+
+ hc = ctx->impl[id - 1];
+ if (hc == NULL) {
+ return 0;
+ }
+ state = (const unsigned char *)ctx + get_state_offset(id);
+ hc->set_state(&g.vtable, state, ctx->count & ~(uint64_t)127);
+ hc->update(&g.vtable, ctx->buf, ctx->count & (uint64_t)127);
+ hc->out(&g.vtable, dst);
+ return (hc->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
+}
diff --git a/contrib/bearssl/src/hash/sha1.c b/contrib/bearssl/src/hash/sha1.c
new file mode 100644
index 000000000000..4f65d84601e9
--- /dev/null
+++ b/contrib/bearssl/src/hash/sha1.c
@@ -0,0 +1,191 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#define F(B, C, D) ((((C) ^ (D)) & (B)) ^ (D))
+#define G(B, C, D) ((B) ^ (C) ^ (D))
+#define H(B, C, D) (((D) & (C)) | (((D) | (C)) & (B)))
+#define I(B, C, D) G(B, C, D)
+
+#define ROTL(x, n) (((x) << (n)) | ((x) >> (32 - (n))))
+
+#define K1 ((uint32_t)0x5A827999)
+#define K2 ((uint32_t)0x6ED9EBA1)
+#define K3 ((uint32_t)0x8F1BBCDC)
+#define K4 ((uint32_t)0xCA62C1D6)
+
+/* see inner.h */
+const uint32_t br_sha1_IV[5] = {
+ 0x67452301, 0xEFCDAB89, 0x98BADCFE, 0x10325476, 0xC3D2E1F0
+};
+
+/* see inner.h */
+void
+br_sha1_round(const unsigned char *buf, uint32_t *val)
+{
+ uint32_t m[80];
+ uint32_t a, b, c, d, e;
+ int i;
+
+ a = val[0];
+ b = val[1];
+ c = val[2];
+ d = val[3];
+ e = val[4];
+ br_range_dec32be(m, 16, buf);
+ for (i = 16; i < 80; i ++) {
+ uint32_t x = m[i - 3] ^ m[i - 8] ^ m[i - 14] ^ m[i - 16];
+ m[i] = ROTL(x, 1);
+ }
+
+ for (i = 0; i < 20; i += 5) {
+ e += ROTL(a, 5) + F(b, c, d) + K1 + m[i + 0]; b = ROTL(b, 30);
+ d += ROTL(e, 5) + F(a, b, c) + K1 + m[i + 1]; a = ROTL(a, 30);
+ c += ROTL(d, 5) + F(e, a, b) + K1 + m[i + 2]; e = ROTL(e, 30);
+ b += ROTL(c, 5) + F(d, e, a) + K1 + m[i + 3]; d = ROTL(d, 30);
+ a += ROTL(b, 5) + F(c, d, e) + K1 + m[i + 4]; c = ROTL(c, 30);
+ }
+ for (i = 20; i < 40; i += 5) {
+ e += ROTL(a, 5) + G(b, c, d) + K2 + m[i + 0]; b = ROTL(b, 30);
+ d += ROTL(e, 5) + G(a, b, c) + K2 + m[i + 1]; a = ROTL(a, 30);
+ c += ROTL(d, 5) + G(e, a, b) + K2 + m[i + 2]; e = ROTL(e, 30);
+ b += ROTL(c, 5) + G(d, e, a) + K2 + m[i + 3]; d = ROTL(d, 30);
+ a += ROTL(b, 5) + G(c, d, e) + K2 + m[i + 4]; c = ROTL(c, 30);
+ }
+ for (i = 40; i < 60; i += 5) {
+ e += ROTL(a, 5) + H(b, c, d) + K3 + m[i + 0]; b = ROTL(b, 30);
+ d += ROTL(e, 5) + H(a, b, c) + K3 + m[i + 1]; a = ROTL(a, 30);
+ c += ROTL(d, 5) + H(e, a, b) + K3 + m[i + 2]; e = ROTL(e, 30);
+ b += ROTL(c, 5) + H(d, e, a) + K3 + m[i + 3]; d = ROTL(d, 30);
+ a += ROTL(b, 5) + H(c, d, e) + K3 + m[i + 4]; c = ROTL(c, 30);
+ }
+ for (i = 60; i < 80; i += 5) {
+ e += ROTL(a, 5) + I(b, c, d) + K4 + m[i + 0]; b = ROTL(b, 30);
+ d += ROTL(e, 5) + I(a, b, c) + K4 + m[i + 1]; a = ROTL(a, 30);
+ c += ROTL(d, 5) + I(e, a, b) + K4 + m[i + 2]; e = ROTL(e, 30);
+ b += ROTL(c, 5) + I(d, e, a) + K4 + m[i + 3]; d = ROTL(d, 30);
+ a += ROTL(b, 5) + I(c, d, e) + K4 + m[i + 4]; c = ROTL(c, 30);
+ }
+
+ val[0] += a;
+ val[1] += b;
+ val[2] += c;
+ val[3] += d;
+ val[4] += e;
+}
+
+/* see bearssl.h */
+void
+br_sha1_init(br_sha1_context *cc)
+{
+ cc->vtable = &br_sha1_vtable;
+ memcpy(cc->val, br_sha1_IV, sizeof cc->val);
+ cc->count = 0;
+}
+
+/* see bearssl.h */
+void
+br_sha1_update(br_sha1_context *cc, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ size_t ptr;
+
+ buf = data;
+ ptr = (size_t)cc->count & 63;
+ while (len > 0) {
+ size_t clen;
+
+ clen = 64 - ptr;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(cc->buf + ptr, buf, clen);
+ ptr += clen;
+ buf += clen;
+ len -= clen;
+ cc->count += (uint64_t)clen;
+ if (ptr == 64) {
+ br_sha1_round(cc->buf, cc->val);
+ ptr = 0;
+ }
+ }
+}
+
+/* see bearssl.h */
+void
+br_sha1_out(const br_sha1_context *cc, void *dst)
+{
+ unsigned char buf[64];
+ uint32_t val[5];
+ size_t ptr;
+
+ ptr = (size_t)cc->count & 63;
+ memcpy(buf, cc->buf, ptr);
+ memcpy(val, cc->val, sizeof val);
+ buf[ptr ++] = 0x80;
+ if (ptr > 56) {
+ memset(buf + ptr, 0, 64 - ptr);
+ br_sha1_round(buf, val);
+ memset(buf, 0, 56);
+ } else {
+ memset(buf + ptr, 0, 56 - ptr);
+ }
+ br_enc64be(buf + 56, cc->count << 3);
+ br_sha1_round(buf, val);
+ br_range_enc32be(dst, val, 5);
+}
+
+/* see bearssl.h */
+uint64_t
+br_sha1_state(const br_sha1_context *cc, void *dst)
+{
+ br_range_enc32be(dst, cc->val, 5);
+ return cc->count;
+}
+
+/* see bearssl.h */
+void
+br_sha1_set_state(br_sha1_context *cc, const void *stb, uint64_t count)
+{
+ br_range_dec32be(cc->val, 5, stb);
+ cc->count = count;
+}
+
+/* see bearssl.h */
+const br_hash_class br_sha1_vtable = {
+ sizeof(br_sha1_context),
+ BR_HASHDESC_ID(br_sha1_ID)
+ | BR_HASHDESC_OUT(20)
+ | BR_HASHDESC_STATE(20)
+ | BR_HASHDESC_LBLEN(6)
+ | BR_HASHDESC_MD_PADDING
+ | BR_HASHDESC_MD_PADDING_BE,
+ (void (*)(const br_hash_class **))&br_sha1_init,
+ (void (*)(const br_hash_class **, const void *, size_t))&br_sha1_update,
+ (void (*)(const br_hash_class *const *, void *))&br_sha1_out,
+ (uint64_t (*)(const br_hash_class *const *, void *))&br_sha1_state,
+ (void (*)(const br_hash_class **, const void *, uint64_t))
+ &br_sha1_set_state
+};
diff --git a/contrib/bearssl/src/hash/sha2big.c b/contrib/bearssl/src/hash/sha2big.c
new file mode 100644
index 000000000000..5be92ed56956
--- /dev/null
+++ b/contrib/bearssl/src/hash/sha2big.c
@@ -0,0 +1,285 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#define CH(X, Y, Z) ((((Y) ^ (Z)) & (X)) ^ (Z))
+#define MAJ(X, Y, Z) (((Y) & (Z)) | (((Y) | (Z)) & (X)))
+
+#define ROTR(x, n) (((uint64_t)(x) << (64 - (n))) | ((uint64_t)(x) >> (n)))
+
+#define BSG5_0(x) (ROTR(x, 28) ^ ROTR(x, 34) ^ ROTR(x, 39))
+#define BSG5_1(x) (ROTR(x, 14) ^ ROTR(x, 18) ^ ROTR(x, 41))
+#define SSG5_0(x) (ROTR(x, 1) ^ ROTR(x, 8) ^ (uint64_t)((x) >> 7))
+#define SSG5_1(x) (ROTR(x, 19) ^ ROTR(x, 61) ^ (uint64_t)((x) >> 6))
+
+static const uint64_t IV384[8] = {
+ 0xCBBB9D5DC1059ED8, 0x629A292A367CD507,
+ 0x9159015A3070DD17, 0x152FECD8F70E5939,
+ 0x67332667FFC00B31, 0x8EB44A8768581511,
+ 0xDB0C2E0D64F98FA7, 0x47B5481DBEFA4FA4
+};
+
+static const uint64_t IV512[8] = {
+ 0x6A09E667F3BCC908, 0xBB67AE8584CAA73B,
+ 0x3C6EF372FE94F82B, 0xA54FF53A5F1D36F1,
+ 0x510E527FADE682D1, 0x9B05688C2B3E6C1F,
+ 0x1F83D9ABFB41BD6B, 0x5BE0CD19137E2179
+};
+
+static const uint64_t K[80] = {
+ 0x428A2F98D728AE22, 0x7137449123EF65CD,
+ 0xB5C0FBCFEC4D3B2F, 0xE9B5DBA58189DBBC,
+ 0x3956C25BF348B538, 0x59F111F1B605D019,
+ 0x923F82A4AF194F9B, 0xAB1C5ED5DA6D8118,
+ 0xD807AA98A3030242, 0x12835B0145706FBE,
+ 0x243185BE4EE4B28C, 0x550C7DC3D5FFB4E2,
+ 0x72BE5D74F27B896F, 0x80DEB1FE3B1696B1,
+ 0x9BDC06A725C71235, 0xC19BF174CF692694,
+ 0xE49B69C19EF14AD2, 0xEFBE4786384F25E3,
+ 0x0FC19DC68B8CD5B5, 0x240CA1CC77AC9C65,
+ 0x2DE92C6F592B0275, 0x4A7484AA6EA6E483,
+ 0x5CB0A9DCBD41FBD4, 0x76F988DA831153B5,
+ 0x983E5152EE66DFAB, 0xA831C66D2DB43210,
+ 0xB00327C898FB213F, 0xBF597FC7BEEF0EE4,
+ 0xC6E00BF33DA88FC2, 0xD5A79147930AA725,
+ 0x06CA6351E003826F, 0x142929670A0E6E70,
+ 0x27B70A8546D22FFC, 0x2E1B21385C26C926,
+ 0x4D2C6DFC5AC42AED, 0x53380D139D95B3DF,
+ 0x650A73548BAF63DE, 0x766A0ABB3C77B2A8,
+ 0x81C2C92E47EDAEE6, 0x92722C851482353B,
+ 0xA2BFE8A14CF10364, 0xA81A664BBC423001,
+ 0xC24B8B70D0F89791, 0xC76C51A30654BE30,
+ 0xD192E819D6EF5218, 0xD69906245565A910,
+ 0xF40E35855771202A, 0x106AA07032BBD1B8,
+ 0x19A4C116B8D2D0C8, 0x1E376C085141AB53,
+ 0x2748774CDF8EEB99, 0x34B0BCB5E19B48A8,
+ 0x391C0CB3C5C95A63, 0x4ED8AA4AE3418ACB,
+ 0x5B9CCA4F7763E373, 0x682E6FF3D6B2B8A3,
+ 0x748F82EE5DEFB2FC, 0x78A5636F43172F60,
+ 0x84C87814A1F0AB72, 0x8CC702081A6439EC,
+ 0x90BEFFFA23631E28, 0xA4506CEBDE82BDE9,
+ 0xBEF9A3F7B2C67915, 0xC67178F2E372532B,
+ 0xCA273ECEEA26619C, 0xD186B8C721C0C207,
+ 0xEADA7DD6CDE0EB1E, 0xF57D4F7FEE6ED178,
+ 0x06F067AA72176FBA, 0x0A637DC5A2C898A6,
+ 0x113F9804BEF90DAE, 0x1B710B35131C471B,
+ 0x28DB77F523047D84, 0x32CAAB7B40C72493,
+ 0x3C9EBE0A15C9BEBC, 0x431D67C49C100D4C,
+ 0x4CC5D4BECB3E42B6, 0x597F299CFC657E2A,
+ 0x5FCB6FAB3AD6FAEC, 0x6C44198C4A475817
+};
+
+static void
+sha2big_round(const unsigned char *buf, uint64_t *val)
+{
+
+#define SHA2BIG_STEP(A, B, C, D, E, F, G, H, j) do { \
+ uint64_t T1, T2; \
+ T1 = H + BSG5_1(E) + CH(E, F, G) + K[j] + w[j]; \
+ T2 = BSG5_0(A) + MAJ(A, B, C); \
+ D += T1; \
+ H = T1 + T2; \
+ } while (0)
+
+ int i;
+ uint64_t a, b, c, d, e, f, g, h;
+ uint64_t w[80];
+
+ br_range_dec64be(w, 16, buf);
+ for (i = 16; i < 80; i ++) {
+ w[i] = SSG5_1(w[i - 2]) + w[i - 7]
+ + SSG5_0(w[i - 15]) + w[i - 16];
+ }
+ a = val[0];
+ b = val[1];
+ c = val[2];
+ d = val[3];
+ e = val[4];
+ f = val[5];
+ g = val[6];
+ h = val[7];
+ for (i = 0; i < 80; i += 8) {
+ SHA2BIG_STEP(a, b, c, d, e, f, g, h, i + 0);
+ SHA2BIG_STEP(h, a, b, c, d, e, f, g, i + 1);
+ SHA2BIG_STEP(g, h, a, b, c, d, e, f, i + 2);
+ SHA2BIG_STEP(f, g, h, a, b, c, d, e, i + 3);
+ SHA2BIG_STEP(e, f, g, h, a, b, c, d, i + 4);
+ SHA2BIG_STEP(d, e, f, g, h, a, b, c, i + 5);
+ SHA2BIG_STEP(c, d, e, f, g, h, a, b, i + 6);
+ SHA2BIG_STEP(b, c, d, e, f, g, h, a, i + 7);
+ }
+ val[0] += a;
+ val[1] += b;
+ val[2] += c;
+ val[3] += d;
+ val[4] += e;
+ val[5] += f;
+ val[6] += g;
+ val[7] += h;
+}
+
+static void
+sha2big_update(br_sha384_context *cc, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ size_t ptr;
+
+ buf = data;
+ ptr = (size_t)cc->count & 127;
+ cc->count += (uint64_t)len;
+ while (len > 0) {
+ size_t clen;
+
+ clen = 128 - ptr;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(cc->buf + ptr, buf, clen);
+ ptr += clen;
+ buf += clen;
+ len -= clen;
+ if (ptr == 128) {
+ sha2big_round(cc->buf, cc->val);
+ ptr = 0;
+ }
+ }
+}
+
+static void
+sha2big_out(const br_sha384_context *cc, void *dst, int num)
+{
+ unsigned char buf[128];
+ uint64_t val[8];
+ size_t ptr;
+
+ ptr = (size_t)cc->count & 127;
+ memcpy(buf, cc->buf, ptr);
+ memcpy(val, cc->val, sizeof val);
+ buf[ptr ++] = 0x80;
+ if (ptr > 112) {
+ memset(buf + ptr, 0, 128 - ptr);
+ sha2big_round(buf, val);
+ memset(buf, 0, 112);
+ } else {
+ memset(buf + ptr, 0, 112 - ptr);
+ }
+ br_enc64be(buf + 112, cc->count >> 61);
+ br_enc64be(buf + 120, cc->count << 3);
+ sha2big_round(buf, val);
+ br_range_enc64be(dst, val, num);
+}
+
+/* see bearssl.h */
+void
+br_sha384_init(br_sha384_context *cc)
+{
+ cc->vtable = &br_sha384_vtable;
+ memcpy(cc->val, IV384, sizeof IV384);
+ cc->count = 0;
+}
+
+/* see bearssl.h */
+void
+br_sha384_update(br_sha384_context *cc, const void *data, size_t len)
+{
+ sha2big_update(cc, data, len);
+}
+
+/* see bearssl.h */
+void
+br_sha384_out(const br_sha384_context *cc, void *dst)
+{
+ sha2big_out(cc, dst, 6);
+}
+
+/* see bearssl.h */
+uint64_t
+br_sha384_state(const br_sha384_context *cc, void *dst)
+{
+ br_range_enc64be(dst, cc->val, 8);
+ return cc->count;
+}
+
+/* see bearssl.h */
+void
+br_sha384_set_state(br_sha384_context *cc, const void *stb, uint64_t count)
+{
+ br_range_dec64be(cc->val, 8, stb);
+ cc->count = count;
+}
+
+/* see bearssl.h */
+void
+br_sha512_init(br_sha512_context *cc)
+{
+ cc->vtable = &br_sha512_vtable;
+ memcpy(cc->val, IV512, sizeof IV512);
+ cc->count = 0;
+}
+
+/* see bearssl.h */
+void
+br_sha512_out(const br_sha512_context *cc, void *dst)
+{
+ sha2big_out(cc, dst, 8);
+}
+
+/* see bearssl.h */
+const br_hash_class br_sha384_vtable = {
+ sizeof(br_sha384_context),
+ BR_HASHDESC_ID(br_sha384_ID)
+ | BR_HASHDESC_OUT(48)
+ | BR_HASHDESC_STATE(64)
+ | BR_HASHDESC_LBLEN(7)
+ | BR_HASHDESC_MD_PADDING
+ | BR_HASHDESC_MD_PADDING_BE
+ | BR_HASHDESC_MD_PADDING_128,
+ (void (*)(const br_hash_class **))&br_sha384_init,
+ (void (*)(const br_hash_class **, const void *, size_t))
+ &br_sha384_update,
+ (void (*)(const br_hash_class *const *, void *))&br_sha384_out,
+ (uint64_t (*)(const br_hash_class *const *, void *))&br_sha384_state,
+ (void (*)(const br_hash_class **, const void *, uint64_t))
+ &br_sha384_set_state
+};
+
+/* see bearssl.h */
+const br_hash_class br_sha512_vtable = {
+ sizeof(br_sha512_context),
+ BR_HASHDESC_ID(br_sha512_ID)
+ | BR_HASHDESC_OUT(64)
+ | BR_HASHDESC_STATE(64)
+ | BR_HASHDESC_LBLEN(7)
+ | BR_HASHDESC_MD_PADDING
+ | BR_HASHDESC_MD_PADDING_BE
+ | BR_HASHDESC_MD_PADDING_128,
+ (void (*)(const br_hash_class **))&br_sha512_init,
+ (void (*)(const br_hash_class **, const void *, size_t))
+ &br_sha512_update,
+ (void (*)(const br_hash_class *const *, void *))&br_sha512_out,
+ (uint64_t (*)(const br_hash_class *const *, void *))&br_sha512_state,
+ (void (*)(const br_hash_class **, const void *, uint64_t))
+ &br_sha512_set_state
+};
diff --git a/contrib/bearssl/src/hash/sha2small.c b/contrib/bearssl/src/hash/sha2small.c
new file mode 100644
index 000000000000..ca196559e62f
--- /dev/null
+++ b/contrib/bearssl/src/hash/sha2small.c
@@ -0,0 +1,341 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#define CH(X, Y, Z) ((((Y) ^ (Z)) & (X)) ^ (Z))
+#define MAJ(X, Y, Z) (((Y) & (Z)) | (((Y) | (Z)) & (X)))
+
+#define ROTR(x, n) (((uint32_t)(x) << (32 - (n))) | ((uint32_t)(x) >> (n)))
+
+#define BSG2_0(x) (ROTR(x, 2) ^ ROTR(x, 13) ^ ROTR(x, 22))
+#define BSG2_1(x) (ROTR(x, 6) ^ ROTR(x, 11) ^ ROTR(x, 25))
+#define SSG2_0(x) (ROTR(x, 7) ^ ROTR(x, 18) ^ (uint32_t)((x) >> 3))
+#define SSG2_1(x) (ROTR(x, 17) ^ ROTR(x, 19) ^ (uint32_t)((x) >> 10))
+
+/* see inner.h */
+const uint32_t br_sha224_IV[8] = {
+ 0xC1059ED8, 0x367CD507, 0x3070DD17, 0xF70E5939,
+ 0xFFC00B31, 0x68581511, 0x64F98FA7, 0xBEFA4FA4
+};
+
+/* see inner.h */
+const uint32_t br_sha256_IV[8] = {
+ 0x6A09E667, 0xBB67AE85, 0x3C6EF372, 0xA54FF53A,
+ 0x510E527F, 0x9B05688C, 0x1F83D9AB, 0x5BE0CD19
+};
+
+static const uint32_t K[64] = {
+ 0x428A2F98, 0x71374491, 0xB5C0FBCF, 0xE9B5DBA5,
+ 0x3956C25B, 0x59F111F1, 0x923F82A4, 0xAB1C5ED5,
+ 0xD807AA98, 0x12835B01, 0x243185BE, 0x550C7DC3,
+ 0x72BE5D74, 0x80DEB1FE, 0x9BDC06A7, 0xC19BF174,
+ 0xE49B69C1, 0xEFBE4786, 0x0FC19DC6, 0x240CA1CC,
+ 0x2DE92C6F, 0x4A7484AA, 0x5CB0A9DC, 0x76F988DA,
+ 0x983E5152, 0xA831C66D, 0xB00327C8, 0xBF597FC7,
+ 0xC6E00BF3, 0xD5A79147, 0x06CA6351, 0x14292967,
+ 0x27B70A85, 0x2E1B2138, 0x4D2C6DFC, 0x53380D13,
+ 0x650A7354, 0x766A0ABB, 0x81C2C92E, 0x92722C85,
+ 0xA2BFE8A1, 0xA81A664B, 0xC24B8B70, 0xC76C51A3,
+ 0xD192E819, 0xD6990624, 0xF40E3585, 0x106AA070,
+ 0x19A4C116, 0x1E376C08, 0x2748774C, 0x34B0BCB5,
+ 0x391C0CB3, 0x4ED8AA4A, 0x5B9CCA4F, 0x682E6FF3,
+ 0x748F82EE, 0x78A5636F, 0x84C87814, 0x8CC70208,
+ 0x90BEFFFA, 0xA4506CEB, 0xBEF9A3F7, 0xC67178F2
+};
+
+/* see inner.h */
+void
+br_sha2small_round(const unsigned char *buf, uint32_t *val)
+{
+
+#define SHA2_STEP(A, B, C, D, E, F, G, H, j) do { \
+ uint32_t T1, T2; \
+ T1 = H + BSG2_1(E) + CH(E, F, G) + K[j] + w[j]; \
+ T2 = BSG2_0(A) + MAJ(A, B, C); \
+ D += T1; \
+ H = T1 + T2; \
+ } while (0)
+
+ int i;
+ uint32_t a, b, c, d, e, f, g, h;
+ uint32_t w[64];
+
+ br_range_dec32be(w, 16, buf);
+ for (i = 16; i < 64; i ++) {
+ w[i] = SSG2_1(w[i - 2]) + w[i - 7]
+ + SSG2_0(w[i - 15]) + w[i - 16];
+ }
+ a = val[0];
+ b = val[1];
+ c = val[2];
+ d = val[3];
+ e = val[4];
+ f = val[5];
+ g = val[6];
+ h = val[7];
+ for (i = 0; i < 64; i += 8) {
+ SHA2_STEP(a, b, c, d, e, f, g, h, i + 0);
+ SHA2_STEP(h, a, b, c, d, e, f, g, i + 1);
+ SHA2_STEP(g, h, a, b, c, d, e, f, i + 2);
+ SHA2_STEP(f, g, h, a, b, c, d, e, i + 3);
+ SHA2_STEP(e, f, g, h, a, b, c, d, i + 4);
+ SHA2_STEP(d, e, f, g, h, a, b, c, i + 5);
+ SHA2_STEP(c, d, e, f, g, h, a, b, i + 6);
+ SHA2_STEP(b, c, d, e, f, g, h, a, i + 7);
+ }
+ val[0] += a;
+ val[1] += b;
+ val[2] += c;
+ val[3] += d;
+ val[4] += e;
+ val[5] += f;
+ val[6] += g;
+ val[7] += h;
+
+#if 0
+/* obsolete */
+#define SHA2_MEXP1(pc) do { \
+ W[pc] = br_dec32be(buf + ((pc) << 2)); \
+ } while (0)
+
+#define SHA2_MEXP2(pc) do { \
+ W[(pc) & 0x0F] = SSG2_1(W[((pc) - 2) & 0x0F]) \
+ + W[((pc) - 7) & 0x0F] \
+ + SSG2_0(W[((pc) - 15) & 0x0F]) + W[(pc) & 0x0F]; \
+ } while (0)
+
+#define SHA2_STEPn(n, a, b, c, d, e, f, g, h, pc) do { \
+ uint32_t t1, t2; \
+ SHA2_MEXP ## n(pc); \
+ t1 = h + BSG2_1(e) + CH(e, f, g) \
+ + K[pcount + (pc)] + W[(pc) & 0x0F]; \
+ t2 = BSG2_0(a) + MAJ(a, b, c); \
+ d += t1; \
+ h = t1 + t2; \
+ } while (0)
+
+#define SHA2_STEP1(a, b, c, d, e, f, g, h, pc) \
+ SHA2_STEPn(1, a, b, c, d, e, f, g, h, pc)
+#define SHA2_STEP2(a, b, c, d, e, f, g, h, pc) \
+ SHA2_STEPn(2, a, b, c, d, e, f, g, h, pc)
+
+ uint32_t A, B, C, D, E, F, G, H;
+ uint32_t W[16];
+ unsigned pcount;
+
+ A = val[0];
+ B = val[1];
+ C = val[2];
+ D = val[3];
+ E = val[4];
+ F = val[5];
+ G = val[6];
+ H = val[7];
+ pcount = 0;
+ SHA2_STEP1(A, B, C, D, E, F, G, H, 0);
+ SHA2_STEP1(H, A, B, C, D, E, F, G, 1);
+ SHA2_STEP1(G, H, A, B, C, D, E, F, 2);
+ SHA2_STEP1(F, G, H, A, B, C, D, E, 3);
+ SHA2_STEP1(E, F, G, H, A, B, C, D, 4);
+ SHA2_STEP1(D, E, F, G, H, A, B, C, 5);
+ SHA2_STEP1(C, D, E, F, G, H, A, B, 6);
+ SHA2_STEP1(B, C, D, E, F, G, H, A, 7);
+ SHA2_STEP1(A, B, C, D, E, F, G, H, 8);
+ SHA2_STEP1(H, A, B, C, D, E, F, G, 9);
+ SHA2_STEP1(G, H, A, B, C, D, E, F, 10);
+ SHA2_STEP1(F, G, H, A, B, C, D, E, 11);
+ SHA2_STEP1(E, F, G, H, A, B, C, D, 12);
+ SHA2_STEP1(D, E, F, G, H, A, B, C, 13);
+ SHA2_STEP1(C, D, E, F, G, H, A, B, 14);
+ SHA2_STEP1(B, C, D, E, F, G, H, A, 15);
+ for (pcount = 16; pcount < 64; pcount += 16) {
+ SHA2_STEP2(A, B, C, D, E, F, G, H, 0);
+ SHA2_STEP2(H, A, B, C, D, E, F, G, 1);
+ SHA2_STEP2(G, H, A, B, C, D, E, F, 2);
+ SHA2_STEP2(F, G, H, A, B, C, D, E, 3);
+ SHA2_STEP2(E, F, G, H, A, B, C, D, 4);
+ SHA2_STEP2(D, E, F, G, H, A, B, C, 5);
+ SHA2_STEP2(C, D, E, F, G, H, A, B, 6);
+ SHA2_STEP2(B, C, D, E, F, G, H, A, 7);
+ SHA2_STEP2(A, B, C, D, E, F, G, H, 8);
+ SHA2_STEP2(H, A, B, C, D, E, F, G, 9);
+ SHA2_STEP2(G, H, A, B, C, D, E, F, 10);
+ SHA2_STEP2(F, G, H, A, B, C, D, E, 11);
+ SHA2_STEP2(E, F, G, H, A, B, C, D, 12);
+ SHA2_STEP2(D, E, F, G, H, A, B, C, 13);
+ SHA2_STEP2(C, D, E, F, G, H, A, B, 14);
+ SHA2_STEP2(B, C, D, E, F, G, H, A, 15);
+ }
+ val[0] += A;
+ val[1] += B;
+ val[2] += C;
+ val[3] += D;
+ val[4] += E;
+ val[5] += F;
+ val[6] += G;
+ val[7] += H;
+#endif
+}
+
+static void
+sha2small_update(br_sha224_context *cc, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ size_t ptr;
+
+ buf = data;
+ ptr = (size_t)cc->count & 63;
+ cc->count += (uint64_t)len;
+ while (len > 0) {
+ size_t clen;
+
+ clen = 64 - ptr;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(cc->buf + ptr, buf, clen);
+ ptr += clen;
+ buf += clen;
+ len -= clen;
+ if (ptr == 64) {
+ br_sha2small_round(cc->buf, cc->val);
+ ptr = 0;
+ }
+ }
+}
+
+static void
+sha2small_out(const br_sha224_context *cc, void *dst, int num)
+{
+ unsigned char buf[64];
+ uint32_t val[8];
+ size_t ptr;
+
+ ptr = (size_t)cc->count & 63;
+ memcpy(buf, cc->buf, ptr);
+ memcpy(val, cc->val, sizeof val);
+ buf[ptr ++] = 0x80;
+ if (ptr > 56) {
+ memset(buf + ptr, 0, 64 - ptr);
+ br_sha2small_round(buf, val);
+ memset(buf, 0, 56);
+ } else {
+ memset(buf + ptr, 0, 56 - ptr);
+ }
+ br_enc64be(buf + 56, cc->count << 3);
+ br_sha2small_round(buf, val);
+ br_range_enc32be(dst, val, num);
+}
+
+/* see bearssl.h */
+void
+br_sha224_init(br_sha224_context *cc)
+{
+ cc->vtable = &br_sha224_vtable;
+ memcpy(cc->val, br_sha224_IV, sizeof cc->val);
+ cc->count = 0;
+}
+
+/* see bearssl.h */
+void
+br_sha224_update(br_sha224_context *cc, const void *data, size_t len)
+{
+ sha2small_update(cc, data, len);
+}
+
+/* see bearssl.h */
+void
+br_sha224_out(const br_sha224_context *cc, void *dst)
+{
+ sha2small_out(cc, dst, 7);
+}
+
+/* see bearssl.h */
+uint64_t
+br_sha224_state(const br_sha224_context *cc, void *dst)
+{
+ br_range_enc32be(dst, cc->val, 8);
+ return cc->count;
+}
+
+/* see bearssl.h */
+void
+br_sha224_set_state(br_sha224_context *cc, const void *stb, uint64_t count)
+{
+ br_range_dec32be(cc->val, 8, stb);
+ cc->count = count;
+}
+
+/* see bearssl.h */
+void
+br_sha256_init(br_sha256_context *cc)
+{
+ cc->vtable = &br_sha256_vtable;
+ memcpy(cc->val, br_sha256_IV, sizeof cc->val);
+ cc->count = 0;
+}
+
+/* see bearssl.h */
+void
+br_sha256_out(const br_sha256_context *cc, void *dst)
+{
+ sha2small_out(cc, dst, 8);
+}
+
+/* see bearssl.h */
+const br_hash_class br_sha224_vtable = {
+ sizeof(br_sha224_context),
+ BR_HASHDESC_ID(br_sha224_ID)
+ | BR_HASHDESC_OUT(28)
+ | BR_HASHDESC_STATE(32)
+ | BR_HASHDESC_LBLEN(6)
+ | BR_HASHDESC_MD_PADDING
+ | BR_HASHDESC_MD_PADDING_BE,
+ (void (*)(const br_hash_class **))&br_sha224_init,
+ (void (*)(const br_hash_class **,
+ const void *, size_t))&br_sha224_update,
+ (void (*)(const br_hash_class *const *, void *))&br_sha224_out,
+ (uint64_t (*)(const br_hash_class *const *, void *))&br_sha224_state,
+ (void (*)(const br_hash_class **, const void *, uint64_t))
+ &br_sha224_set_state
+};
+
+/* see bearssl.h */
+const br_hash_class br_sha256_vtable = {
+ sizeof(br_sha256_context),
+ BR_HASHDESC_ID(br_sha256_ID)
+ | BR_HASHDESC_OUT(32)
+ | BR_HASHDESC_STATE(32)
+ | BR_HASHDESC_LBLEN(6)
+ | BR_HASHDESC_MD_PADDING
+ | BR_HASHDESC_MD_PADDING_BE,
+ (void (*)(const br_hash_class **))&br_sha256_init,
+ (void (*)(const br_hash_class **,
+ const void *, size_t))&br_sha256_update,
+ (void (*)(const br_hash_class *const *, void *))&br_sha256_out,
+ (uint64_t (*)(const br_hash_class *const *, void *))&br_sha256_state,
+ (void (*)(const br_hash_class **, const void *, uint64_t))
+ &br_sha256_set_state
+};
diff --git a/contrib/bearssl/src/inner.h b/contrib/bearssl/src/inner.h
new file mode 100644
index 000000000000..986220f0f542
--- /dev/null
+++ b/contrib/bearssl/src/inner.h
@@ -0,0 +1,2557 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef INNER_H__
+#define INNER_H__
+
+#include <string.h>
+#include <limits.h>
+
+#include "config.h"
+#include "bearssl.h"
+
+/*
+ * On MSVC, disable the warning about applying unary minus on an
+ * unsigned type: it is standard, we do it all the time, and for
+ * good reasons.
+ */
+#if _MSC_VER
+#pragma warning( disable : 4146 )
+#endif
+
+/*
+ * Maximum size for a RSA modulus (in bits). Allocated stack buffers
+ * depend on that size, so this value should be kept small. Currently,
+ * 2048-bit RSA keys offer adequate security, and should still do so for
+ * the next few decades; however, a number of widespread PKI have
+ * already set their root keys to RSA-4096, so we should be able to
+ * process such keys.
+ *
+ * This value MUST be a multiple of 64. This value MUST NOT exceed 47666
+ * (some computations in RSA key generation rely on the factor size being
+ * no more than 23833 bits). RSA key sizes beyond 3072 bits don't make a
+ * lot of sense anyway.
+ */
+#define BR_MAX_RSA_SIZE 4096
+
+/*
+ * Minimum size for a RSA modulus (in bits); this value is used only to
+ * filter out invalid parameters for key pair generation. Normally,
+ * applications should not use RSA keys smaller than 2048 bits; but some
+ * specific cases might need shorter keys, for legacy or research
+ * purposes.
+ */
+#define BR_MIN_RSA_SIZE 512
+
+/*
+ * Maximum size for a RSA factor (in bits). This is for RSA private-key
+ * operations. Default is to support factors up to a bit more than half
+ * the maximum modulus size.
+ *
+ * This value MUST be a multiple of 32.
+ */
+#define BR_MAX_RSA_FACTOR ((BR_MAX_RSA_SIZE + 64) >> 1)
+
+/*
+ * Maximum size for an EC curve (modulus or order), in bits. Size of
+ * stack buffers depends on that parameter. This size MUST be a multiple
+ * of 8 (so that decoding an integer with that many bytes does not
+ * overflow).
+ */
+#define BR_MAX_EC_SIZE 528
+
+/*
+ * Some macros to recognize the current architecture. Right now, we are
+ * interested into automatically recognizing architecture with efficient
+ * 64-bit types so that we may automatically use implementations that
+ * use 64-bit registers in that case. Future versions may detect, e.g.,
+ * availability of SSE2 intrinsics.
+ *
+ * If 'unsigned long' is a 64-bit type, then we assume that 64-bit types
+ * are efficient. Otherwise, we rely on macros that depend on compiler,
+ * OS and architecture. In any case, failure to detect the architecture
+ * as 64-bit means that the 32-bit code will be used, and that code
+ * works also on 64-bit architectures (the 64-bit code may simply be
+ * more efficient).
+ *
+ * The test on 'unsigned long' should already catch most cases, the one
+ * notable exception being Windows code where 'unsigned long' is kept to
+ * 32-bit for compatibility with all the legacy code that liberally uses
+ * the 'DWORD' type for 32-bit values.
+ *
+ * Macro names are taken from: http://nadeausoftware.com/articles/2012/02/c_c_tip_how_detect_processor_type_using_compiler_predefined_macros
+ */
+#ifndef BR_64
+#if ((ULONG_MAX >> 31) >> 31) == 3
+#define BR_64 1
+#elif defined(__ia64) || defined(__itanium__) || defined(_M_IA64)
+#define BR_64 1
+#elif defined(__powerpc64__) || defined(__ppc64__) || defined(__PPC64__) \
+ || defined(__64BIT__) || defined(_LP64) || defined(__LP64__)
+#define BR_64 1
+#elif defined(__sparc64__)
+#define BR_64 1
+#elif defined(__x86_64__) || defined(_M_X64)
+#define BR_64 1
+#elif defined(__aarch64__) || defined(_M_ARM64)
+#define BR_64 1
+#elif defined(__mips64)
+#define BR_64 1
+#endif
+#endif
+
+/*
+ * Set BR_LOMUL on platforms where it makes sense.
+ */
+#ifndef BR_LOMUL
+#if BR_ARMEL_CORTEXM_GCC
+#define BR_LOMUL 1
+#endif
+#endif
+
+/*
+ * Architecture detection.
+ */
+#ifndef BR_i386
+#if __i386__ || _M_IX86
+#define BR_i386 1
+#endif
+#endif
+
+#ifndef BR_amd64
+#if __x86_64__ || _M_X64
+#define BR_amd64 1
+#endif
+#endif
+
+/*
+ * Compiler brand and version.
+ *
+ * Implementations that use intrinsics need to detect the compiler type
+ * and version because some specific actions may be needed to activate
+ * the corresponding opcodes, both for header inclusion, and when using
+ * them in a function.
+ *
+ * BR_GCC, BR_CLANG and BR_MSC will be set to 1 for, respectively, GCC,
+ * Clang and MS Visual C. For each of them, sub-macros will be defined
+ * for versions; each sub-macro is set whenever the compiler version is
+ * at least as recent as the one corresponding to the macro.
+ */
+
+/*
+ * GCC thresholds are on versions 4.4 to 4.9 and 5.0.
+ */
+#ifndef BR_GCC
+#if __GNUC__ && !__clang__
+#define BR_GCC 1
+
+#if __GNUC__ > 4
+#define BR_GCC_5_0 1
+#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 9
+#define BR_GCC_4_9 1
+#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 8
+#define BR_GCC_4_8 1
+#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 7
+#define BR_GCC_4_7 1
+#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 6
+#define BR_GCC_4_6 1
+#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 5
+#define BR_GCC_4_5 1
+#elif __GNUC__ == 4 && __GNUC_MINOR__ >= 4
+#define BR_GCC_4_4 1
+#endif
+
+#if BR_GCC_5_0
+#define BR_GCC_4_9 1
+#endif
+#if BR_GCC_4_9
+#define BR_GCC_4_8 1
+#endif
+#if BR_GCC_4_8
+#define BR_GCC_4_7 1
+#endif
+#if BR_GCC_4_7
+#define BR_GCC_4_6 1
+#endif
+#if BR_GCC_4_6
+#define BR_GCC_4_5 1
+#endif
+#if BR_GCC_4_5
+#define BR_GCC_4_4 1
+#endif
+
+#endif
+#endif
+
+/*
+ * Clang thresholds are on versions 3.7.0 and 3.8.0.
+ */
+#ifndef BR_CLANG
+#if __clang__
+#define BR_CLANG 1
+
+#if __clang_major__ > 3 || (__clang_major__ == 3 && __clang_minor__ >= 8)
+#define BR_CLANG_3_8 1
+#elif __clang_major__ == 3 && __clang_minor__ >= 7
+#define BR_CLANG_3_7 1
+#endif
+
+#if BR_CLANG_3_8
+#define BR_CLANG_3_7 1
+#endif
+
+#endif
+#endif
+
+/*
+ * MS Visual C thresholds are on Visual Studio 2005 to 2015.
+ */
+#ifndef BR_MSC
+#if _MSC_VER
+#define BR_MSC 1
+
+#if _MSC_VER >= 1900
+#define BR_MSC_2015 1
+#elif _MSC_VER >= 1800
+#define BR_MSC_2013 1
+#elif _MSC_VER >= 1700
+#define BR_MSC_2012 1
+#elif _MSC_VER >= 1600
+#define BR_MSC_2010 1
+#elif _MSC_VER >= 1500
+#define BR_MSC_2008 1
+#elif _MSC_VER >= 1400
+#define BR_MSC_2005 1
+#endif
+
+#if BR_MSC_2015
+#define BR_MSC_2013 1
+#endif
+#if BR_MSC_2013
+#define BR_MSC_2012 1
+#endif
+#if BR_MSC_2012
+#define BR_MSC_2010 1
+#endif
+#if BR_MSC_2010
+#define BR_MSC_2008 1
+#endif
+#if BR_MSC_2008
+#define BR_MSC_2005 1
+#endif
+
+#endif
+#endif
+
+/*
+ * GCC 4.4+ and Clang 3.7+ allow tagging specific functions with a
+ * 'target' attribute that activates support for specific opcodes.
+ */
+#if BR_GCC_4_4 || BR_CLANG_3_7
+#define BR_TARGET(x) __attribute__((target(x)))
+#else
+#define BR_TARGET(x)
+#endif
+
+/*
+ * AES-NI intrinsics are available on x86 (32-bit and 64-bit) with
+ * GCC 4.8+, Clang 3.7+ and MSC 2012+.
+ */
+#ifndef BR_AES_X86NI
+#if (BR_i386 || BR_amd64) && (BR_GCC_4_8 || BR_CLANG_3_7 || BR_MSC_2012)
+#define BR_AES_X86NI 1
+#endif
+#endif
+
+/*
+ * SSE2 intrinsics are available on x86 (32-bit and 64-bit) with
+ * GCC 4.4+, Clang 3.7+ and MSC 2005+.
+ */
+#ifndef BR_SSE2
+#if (BR_i386 || BR_amd64) && (BR_GCC_4_4 || BR_CLANG_3_7 || BR_MSC_2005)
+#define BR_SSE2 1
+#endif
+#endif
+
+/*
+ * RDRAND intrinsics are available on x86 (32-bit and 64-bit) with
+ * GCC 4.6+, Clang 3.7+ and MSC 2012+.
+ */
+#ifndef BR_RDRAND
+#if (BR_i386 || BR_amd64) && (BR_GCC_4_6 || BR_CLANG_3_7 || BR_MSC_2012)
+#define BR_RDRAND 1
+#endif
+#endif
+
+/*
+ * Determine type of OS for random number generation. Macro names and
+ * values are documented on:
+ * https://sourceforge.net/p/predef/wiki/OperatingSystems/
+ *
+ * TODO: enrich the list of detected system. Also add detection for
+ * alternate system calls like getentropy(), which are usually
+ * preferable when available.
+ */
+
+#ifndef BR_USE_URANDOM
+#if defined _AIX \
+ || defined __ANDROID__ \
+ || defined __FreeBSD__ \
+ || defined __NetBSD__ \
+ || defined __OpenBSD__ \
+ || defined __DragonFly__ \
+ || defined __linux__ \
+ || (defined __sun && (defined __SVR4 || defined __svr4__)) \
+ || (defined __APPLE__ && defined __MACH__)
+#define BR_USE_URANDOM 1
+#endif
+#endif
+
+#ifndef BR_USE_WIN32_RAND
+#if defined _WIN32 || defined _WIN64
+#define BR_USE_WIN32_RAND 1
+#endif
+#endif
+
+/*
+ * POWER8 crypto support. We rely on compiler macros for the
+ * architecture, since we do not have a reliable, simple way to detect
+ * the required support at runtime (we could try running an opcode, and
+ * trapping the exception or signal on illegal instruction, but this
+ * induces some non-trivial OS dependencies that we would prefer to
+ * avoid if possible).
+ */
+#ifndef BR_POWER8
+#if __GNUC__ && ((_ARCH_PWR8 || _ARCH_PPC) && __CRYPTO__)
+#define BR_POWER8 1
+#endif
+#endif
+
+/*
+ * Detect endinanness on POWER8.
+ */
+#if BR_POWER8
+#if defined BR_POWER8_LE
+#undef BR_POWER8_BE
+#if BR_POWER8_LE
+#define BR_POWER8_BE 0
+#else
+#define BR_POWER8_BE 1
+#endif
+#elif defined BR_POWER8_BE
+#undef BR_POWER8_LE
+#if BR_POWER8_BE
+#define BR_POWER8_LE 0
+#else
+#define BR_POWER8_LE 1
+#endif
+#else
+#if __LITTLE_ENDIAN__
+#define BR_POWER8_LE 1
+#define BR_POWER8_BE 0
+#else
+#define BR_POWER8_LE 0
+#define BR_POWER8_BE 1
+#endif
+#endif
+#endif
+
+/*
+ * Detect support for 128-bit integers.
+ */
+#if !defined BR_INT128 && !defined BR_UMUL128
+#ifdef __SIZEOF_INT128__
+#define BR_INT128 1
+#elif _M_X64
+#define BR_UMUL128 1
+#endif
+#endif
+
+/*
+ * Detect support for unaligned accesses with known endianness.
+ *
+ * x86 (both 32-bit and 64-bit) is little-endian and allows unaligned
+ * accesses.
+ *
+ * POWER/PowerPC allows unaligned accesses when big-endian. POWER8 and
+ * later also allow unaligned accesses when little-endian.
+ */
+#if !defined BR_LE_UNALIGNED && !defined BR_BE_UNALIGNED
+
+#if __i386 || __i386__ || __x86_64__ || _M_IX86 || _M_X64
+#define BR_LE_UNALIGNED 1
+#elif BR_POWER8_BE
+#define BR_BE_UNALIGNED 1
+#elif BR_POWER8_LE
+#define BR_LE_UNALIGNED 1
+#elif (__powerpc__ || __powerpc64__ || _M_PPC || _ARCH_PPC || _ARCH_PPC64) \
+ && __BIG_ENDIAN__
+#define BR_BE_UNALIGNED 1
+#endif
+
+#endif
+
+/*
+ * Detect support for an OS-provided time source.
+ */
+
+#ifndef BR_USE_UNIX_TIME
+#if defined __unix__ || defined __linux__ \
+ || defined _POSIX_SOURCE || defined _POSIX_C_SOURCE \
+ || (defined __APPLE__ && defined __MACH__)
+#define BR_USE_UNIX_TIME 1
+#endif
+#endif
+
+#ifndef BR_USE_WIN32_TIME
+#if defined _WIN32 || defined _WIN64
+#define BR_USE_WIN32_TIME 1
+#endif
+#endif
+
+/* ==================================================================== */
+/*
+ * Encoding/decoding functions.
+ *
+ * 32-bit and 64-bit decoding, both little-endian and big-endian, is
+ * implemented with the inline functions below.
+ *
+ * When allowed by some compile-time options (autodetected or provided),
+ * optimised code is used, to perform direct memory access when the
+ * underlying architecture supports it, both for endianness and
+ * alignment. This, however, may trigger strict aliasing issues; the
+ * code below uses unions to perform (supposedly) safe type punning.
+ * Since the C aliasing rules are relatively complex and were amended,
+ * or at least re-explained with different phrasing, in all successive
+ * versions of the C standard, it is always a bit risky to bet that any
+ * specific version of a C compiler got it right, for some notion of
+ * "right".
+ */
+
+typedef union {
+ uint16_t u;
+ unsigned char b[sizeof(uint16_t)];
+} br_union_u16;
+
+typedef union {
+ uint32_t u;
+ unsigned char b[sizeof(uint32_t)];
+} br_union_u32;
+
+typedef union {
+ uint64_t u;
+ unsigned char b[sizeof(uint64_t)];
+} br_union_u64;
+
+static inline void
+br_enc16le(void *dst, unsigned x)
+{
+#if BR_LE_UNALIGNED
+ ((br_union_u16 *)dst)->u = x;
+#else
+ unsigned char *buf;
+
+ buf = dst;
+ buf[0] = (unsigned char)x;
+ buf[1] = (unsigned char)(x >> 8);
+#endif
+}
+
+static inline void
+br_enc16be(void *dst, unsigned x)
+{
+#if BR_BE_UNALIGNED
+ ((br_union_u16 *)dst)->u = x;
+#else
+ unsigned char *buf;
+
+ buf = dst;
+ buf[0] = (unsigned char)(x >> 8);
+ buf[1] = (unsigned char)x;
+#endif
+}
+
+static inline unsigned
+br_dec16le(const void *src)
+{
+#if BR_LE_UNALIGNED
+ return ((const br_union_u16 *)src)->u;
+#else
+ const unsigned char *buf;
+
+ buf = src;
+ return (unsigned)buf[0] | ((unsigned)buf[1] << 8);
+#endif
+}
+
+static inline unsigned
+br_dec16be(const void *src)
+{
+#if BR_BE_UNALIGNED
+ return ((const br_union_u16 *)src)->u;
+#else
+ const unsigned char *buf;
+
+ buf = src;
+ return ((unsigned)buf[0] << 8) | (unsigned)buf[1];
+#endif
+}
+
+static inline void
+br_enc32le(void *dst, uint32_t x)
+{
+#if BR_LE_UNALIGNED
+ ((br_union_u32 *)dst)->u = x;
+#else
+ unsigned char *buf;
+
+ buf = dst;
+ buf[0] = (unsigned char)x;
+ buf[1] = (unsigned char)(x >> 8);
+ buf[2] = (unsigned char)(x >> 16);
+ buf[3] = (unsigned char)(x >> 24);
+#endif
+}
+
+static inline void
+br_enc32be(void *dst, uint32_t x)
+{
+#if BR_BE_UNALIGNED
+ ((br_union_u32 *)dst)->u = x;
+#else
+ unsigned char *buf;
+
+ buf = dst;
+ buf[0] = (unsigned char)(x >> 24);
+ buf[1] = (unsigned char)(x >> 16);
+ buf[2] = (unsigned char)(x >> 8);
+ buf[3] = (unsigned char)x;
+#endif
+}
+
+static inline uint32_t
+br_dec32le(const void *src)
+{
+#if BR_LE_UNALIGNED
+ return ((const br_union_u32 *)src)->u;
+#else
+ const unsigned char *buf;
+
+ buf = src;
+ return (uint32_t)buf[0]
+ | ((uint32_t)buf[1] << 8)
+ | ((uint32_t)buf[2] << 16)
+ | ((uint32_t)buf[3] << 24);
+#endif
+}
+
+static inline uint32_t
+br_dec32be(const void *src)
+{
+#if BR_BE_UNALIGNED
+ return ((const br_union_u32 *)src)->u;
+#else
+ const unsigned char *buf;
+
+ buf = src;
+ return ((uint32_t)buf[0] << 24)
+ | ((uint32_t)buf[1] << 16)
+ | ((uint32_t)buf[2] << 8)
+ | (uint32_t)buf[3];
+#endif
+}
+
+static inline void
+br_enc64le(void *dst, uint64_t x)
+{
+#if BR_LE_UNALIGNED
+ ((br_union_u64 *)dst)->u = x;
+#else
+ unsigned char *buf;
+
+ buf = dst;
+ br_enc32le(buf, (uint32_t)x);
+ br_enc32le(buf + 4, (uint32_t)(x >> 32));
+#endif
+}
+
+static inline void
+br_enc64be(void *dst, uint64_t x)
+{
+#if BR_BE_UNALIGNED
+ ((br_union_u64 *)dst)->u = x;
+#else
+ unsigned char *buf;
+
+ buf = dst;
+ br_enc32be(buf, (uint32_t)(x >> 32));
+ br_enc32be(buf + 4, (uint32_t)x);
+#endif
+}
+
+static inline uint64_t
+br_dec64le(const void *src)
+{
+#if BR_LE_UNALIGNED
+ return ((const br_union_u64 *)src)->u;
+#else
+ const unsigned char *buf;
+
+ buf = src;
+ return (uint64_t)br_dec32le(buf)
+ | ((uint64_t)br_dec32le(buf + 4) << 32);
+#endif
+}
+
+static inline uint64_t
+br_dec64be(const void *src)
+{
+#if BR_BE_UNALIGNED
+ return ((const br_union_u64 *)src)->u;
+#else
+ const unsigned char *buf;
+
+ buf = src;
+ return ((uint64_t)br_dec32be(buf) << 32)
+ | (uint64_t)br_dec32be(buf + 4);
+#endif
+}
+
+/*
+ * Range decoding and encoding (for several successive values).
+ */
+void br_range_dec16le(uint16_t *v, size_t num, const void *src);
+void br_range_dec16be(uint16_t *v, size_t num, const void *src);
+void br_range_enc16le(void *dst, const uint16_t *v, size_t num);
+void br_range_enc16be(void *dst, const uint16_t *v, size_t num);
+
+void br_range_dec32le(uint32_t *v, size_t num, const void *src);
+void br_range_dec32be(uint32_t *v, size_t num, const void *src);
+void br_range_enc32le(void *dst, const uint32_t *v, size_t num);
+void br_range_enc32be(void *dst, const uint32_t *v, size_t num);
+
+void br_range_dec64le(uint64_t *v, size_t num, const void *src);
+void br_range_dec64be(uint64_t *v, size_t num, const void *src);
+void br_range_enc64le(void *dst, const uint64_t *v, size_t num);
+void br_range_enc64be(void *dst, const uint64_t *v, size_t num);
+
+/*
+ * Byte-swap a 32-bit integer.
+ */
+static inline uint32_t
+br_swap32(uint32_t x)
+{
+ x = ((x & (uint32_t)0x00FF00FF) << 8)
+ | ((x >> 8) & (uint32_t)0x00FF00FF);
+ return (x << 16) | (x >> 16);
+}
+
+/* ==================================================================== */
+/*
+ * Support code for hash functions.
+ */
+
+/*
+ * IV for MD5, SHA-1, SHA-224 and SHA-256.
+ */
+extern const uint32_t br_md5_IV[];
+extern const uint32_t br_sha1_IV[];
+extern const uint32_t br_sha224_IV[];
+extern const uint32_t br_sha256_IV[];
+
+/*
+ * Round functions for MD5, SHA-1, SHA-224 and SHA-256 (SHA-224 and
+ * SHA-256 use the same round function).
+ */
+void br_md5_round(const unsigned char *buf, uint32_t *val);
+void br_sha1_round(const unsigned char *buf, uint32_t *val);
+void br_sha2small_round(const unsigned char *buf, uint32_t *val);
+
+/*
+ * The core function for the TLS PRF. It computes
+ * P_hash(secret, label + seed), and XORs the result into the dst buffer.
+ */
+void br_tls_phash(void *dst, size_t len,
+ const br_hash_class *dig,
+ const void *secret, size_t secret_len, const char *label,
+ size_t seed_num, const br_tls_prf_seed_chunk *seed);
+
+/*
+ * Copy all configured hash implementations from a multihash context
+ * to another.
+ */
+static inline void
+br_multihash_copyimpl(br_multihash_context *dst,
+ const br_multihash_context *src)
+{
+ memcpy((void *)dst->impl, src->impl, sizeof src->impl);
+}
+
+/* ==================================================================== */
+/*
+ * Constant-time primitives. These functions manipulate 32-bit values in
+ * order to provide constant-time comparisons and multiplexers.
+ *
+ * Boolean values (the "ctl" bits) MUST have value 0 or 1.
+ *
+ * Implementation notes:
+ * =====================
+ *
+ * The uintN_t types are unsigned and with width exactly N bits; the C
+ * standard guarantees that computations are performed modulo 2^N, and
+ * there can be no overflow. Negation (unary '-') works on unsigned types
+ * as well.
+ *
+ * The intN_t types are guaranteed to have width exactly N bits, with no
+ * padding bit, and using two's complement representation. Casting
+ * intN_t to uintN_t really is conversion modulo 2^N. Beware that intN_t
+ * types, being signed, trigger implementation-defined behaviour on
+ * overflow (including raising some signal): with GCC, while modular
+ * arithmetics are usually applied, the optimizer may assume that
+ * overflows don't occur (unless the -fwrapv command-line option is
+ * added); Clang has the additional -ftrapv option to explicitly trap on
+ * integer overflow or underflow.
+ */
+
+/*
+ * Negate a boolean.
+ */
+static inline uint32_t
+NOT(uint32_t ctl)
+{
+ return ctl ^ 1;
+}
+
+/*
+ * Multiplexer: returns x if ctl == 1, y if ctl == 0.
+ */
+static inline uint32_t
+MUX(uint32_t ctl, uint32_t x, uint32_t y)
+{
+ return y ^ (-ctl & (x ^ y));
+}
+
+/*
+ * Equality check: returns 1 if x == y, 0 otherwise.
+ */
+static inline uint32_t
+EQ(uint32_t x, uint32_t y)
+{
+ uint32_t q;
+
+ q = x ^ y;
+ return NOT((q | -q) >> 31);
+}
+
+/*
+ * Inequality check: returns 1 if x != y, 0 otherwise.
+ */
+static inline uint32_t
+NEQ(uint32_t x, uint32_t y)
+{
+ uint32_t q;
+
+ q = x ^ y;
+ return (q | -q) >> 31;
+}
+
+/*
+ * Comparison: returns 1 if x > y, 0 otherwise.
+ */
+static inline uint32_t
+GT(uint32_t x, uint32_t y)
+{
+ /*
+ * If both x < 2^31 and x < 2^31, then y-x will have its high
+ * bit set if x > y, cleared otherwise.
+ *
+ * If either x >= 2^31 or y >= 2^31 (but not both), then the
+ * result is the high bit of x.
+ *
+ * If both x >= 2^31 and y >= 2^31, then we can virtually
+ * subtract 2^31 from both, and we are back to the first case.
+ * Since (y-2^31)-(x-2^31) = y-x, the subtraction is already
+ * fine.
+ */
+ uint32_t z;
+
+ z = y - x;
+ return (z ^ ((x ^ y) & (x ^ z))) >> 31;
+}
+
+/*
+ * Other comparisons (greater-or-equal, lower-than, lower-or-equal).
+ */
+#define GE(x, y) NOT(GT(y, x))
+#define LT(x, y) GT(y, x)
+#define LE(x, y) NOT(GT(x, y))
+
+/*
+ * General comparison: returned value is -1, 0 or 1, depending on
+ * whether x is lower than, equal to, or greater than y.
+ */
+static inline int32_t
+CMP(uint32_t x, uint32_t y)
+{
+ return (int32_t)GT(x, y) | -(int32_t)GT(y, x);
+}
+
+/*
+ * Returns 1 if x == 0, 0 otherwise. Take care that the operand is signed.
+ */
+static inline uint32_t
+EQ0(int32_t x)
+{
+ uint32_t q;
+
+ q = (uint32_t)x;
+ return ~(q | -q) >> 31;
+}
+
+/*
+ * Returns 1 if x > 0, 0 otherwise. Take care that the operand is signed.
+ */
+static inline uint32_t
+GT0(int32_t x)
+{
+ /*
+ * High bit of -x is 0 if x == 0, but 1 if x > 0.
+ */
+ uint32_t q;
+
+ q = (uint32_t)x;
+ return (~q & -q) >> 31;
+}
+
+/*
+ * Returns 1 if x >= 0, 0 otherwise. Take care that the operand is signed.
+ */
+static inline uint32_t
+GE0(int32_t x)
+{
+ return ~(uint32_t)x >> 31;
+}
+
+/*
+ * Returns 1 if x < 0, 0 otherwise. Take care that the operand is signed.
+ */
+static inline uint32_t
+LT0(int32_t x)
+{
+ return (uint32_t)x >> 31;
+}
+
+/*
+ * Returns 1 if x <= 0, 0 otherwise. Take care that the operand is signed.
+ */
+static inline uint32_t
+LE0(int32_t x)
+{
+ uint32_t q;
+
+ /*
+ * ~-x has its high bit set if and only if -x is nonnegative (as
+ * a signed int), i.e. x is in the -(2^31-1) to 0 range. We must
+ * do an OR with x itself to account for x = -2^31.
+ */
+ q = (uint32_t)x;
+ return (q | ~-q) >> 31;
+}
+
+/*
+ * Conditional copy: src[] is copied into dst[] if and only if ctl is 1.
+ * dst[] and src[] may overlap completely (but not partially).
+ */
+void br_ccopy(uint32_t ctl, void *dst, const void *src, size_t len);
+
+#define CCOPY br_ccopy
+
+/*
+ * Compute the bit length of a 32-bit integer. Returned value is between 0
+ * and 32 (inclusive).
+ */
+static inline uint32_t
+BIT_LENGTH(uint32_t x)
+{
+ uint32_t k, c;
+
+ k = NEQ(x, 0);
+ c = GT(x, 0xFFFF); x = MUX(c, x >> 16, x); k += c << 4;
+ c = GT(x, 0x00FF); x = MUX(c, x >> 8, x); k += c << 3;
+ c = GT(x, 0x000F); x = MUX(c, x >> 4, x); k += c << 2;
+ c = GT(x, 0x0003); x = MUX(c, x >> 2, x); k += c << 1;
+ k += GT(x, 0x0001);
+ return k;
+}
+
+/*
+ * Compute the minimum of x and y.
+ */
+static inline uint32_t
+MIN(uint32_t x, uint32_t y)
+{
+ return MUX(GT(x, y), y, x);
+}
+
+/*
+ * Compute the maximum of x and y.
+ */
+static inline uint32_t
+MAX(uint32_t x, uint32_t y)
+{
+ return MUX(GT(x, y), x, y);
+}
+
+/*
+ * Multiply two 32-bit integers, with a 64-bit result. This default
+ * implementation assumes that the basic multiplication operator
+ * yields constant-time code.
+ */
+#define MUL(x, y) ((uint64_t)(x) * (uint64_t)(y))
+
+#if BR_CT_MUL31
+
+/*
+ * Alternate implementation of MUL31, that will be constant-time on some
+ * (old) platforms where the default MUL31 is not. Unfortunately, it is
+ * also substantially slower, and yields larger code, on more modern
+ * platforms, which is why it is deactivated by default.
+ *
+ * MUL31_lo() must do some extra work because on some platforms, the
+ * _signed_ multiplication may return early if the top bits are 1.
+ * Simply truncating (casting) the output of MUL31() would not be
+ * sufficient, because the compiler may notice that we keep only the low
+ * word, and then replace automatically the unsigned multiplication with
+ * a signed multiplication opcode.
+ */
+#define MUL31(x, y) ((uint64_t)((x) | (uint32_t)0x80000000) \
+ * (uint64_t)((y) | (uint32_t)0x80000000) \
+ - ((uint64_t)(x) << 31) - ((uint64_t)(y) << 31) \
+ - ((uint64_t)1 << 62))
+static inline uint32_t
+MUL31_lo(uint32_t x, uint32_t y)
+{
+ uint32_t xl, xh;
+ uint32_t yl, yh;
+
+ xl = (x & 0xFFFF) | (uint32_t)0x80000000;
+ xh = (x >> 16) | (uint32_t)0x80000000;
+ yl = (y & 0xFFFF) | (uint32_t)0x80000000;
+ yh = (y >> 16) | (uint32_t)0x80000000;
+ return (xl * yl + ((xl * yh + xh * yl) << 16)) & (uint32_t)0x7FFFFFFF;
+}
+
+#else
+
+/*
+ * Multiply two 31-bit integers, with a 62-bit result. This default
+ * implementation assumes that the basic multiplication operator
+ * yields constant-time code.
+ * The MUL31_lo() macro returns only the low 31 bits of the product.
+ */
+#define MUL31(x, y) ((uint64_t)(x) * (uint64_t)(y))
+#define MUL31_lo(x, y) (((uint32_t)(x) * (uint32_t)(y)) & (uint32_t)0x7FFFFFFF)
+
+#endif
+
+/*
+ * Multiply two words together; the sum of the lengths of the two
+ * operands must not exceed 31 (for instance, one operand may use 16
+ * bits if the other fits on 15). If BR_CT_MUL15 is non-zero, then the
+ * macro will contain some extra operations that help in making the
+ * operation constant-time on some platforms, where the basic 32-bit
+ * multiplication is not constant-time.
+ */
+#if BR_CT_MUL15
+#define MUL15(x, y) (((uint32_t)(x) | (uint32_t)0x80000000) \
+ * ((uint32_t)(y) | (uint32_t)0x80000000) \
+ & (uint32_t)0x7FFFFFFF)
+#else
+#define MUL15(x, y) ((uint32_t)(x) * (uint32_t)(y))
+#endif
+
+/*
+ * Arithmetic right shift (sign bit is copied). What happens when
+ * right-shifting a negative value is _implementation-defined_, so it
+ * does not trigger undefined behaviour, but it is still up to each
+ * compiler to define (and document) what it does. Most/all compilers
+ * will do an arithmetic shift, the sign bit being used to fill the
+ * holes; this is a native operation on the underlying CPU, and it would
+ * make little sense for the compiler to do otherwise. GCC explicitly
+ * documents that it follows that convention.
+ *
+ * Still, if BR_NO_ARITH_SHIFT is defined (and non-zero), then an
+ * alternate version will be used, that does not rely on such
+ * implementation-defined behaviour. Unfortunately, it is also slower
+ * and yields bigger code, which is why it is deactivated by default.
+ */
+#if BR_NO_ARITH_SHIFT
+#define ARSH(x, n) (((uint32_t)(x) >> (n)) \
+ | ((-((uint32_t)(x) >> 31)) << (32 - (n))))
+#else
+#define ARSH(x, n) ((*(int32_t *)&(x)) >> (n))
+#endif
+
+/*
+ * Constant-time division. The dividend hi:lo is divided by the
+ * divisor d; the quotient is returned and the remainder is written
+ * in *r. If hi == d, then the quotient does not fit on 32 bits;
+ * returned value is thus truncated. If hi > d, returned values are
+ * indeterminate.
+ */
+uint32_t br_divrem(uint32_t hi, uint32_t lo, uint32_t d, uint32_t *r);
+
+/*
+ * Wrapper for br_divrem(); the remainder is returned, and the quotient
+ * is discarded.
+ */
+static inline uint32_t
+br_rem(uint32_t hi, uint32_t lo, uint32_t d)
+{
+ uint32_t r;
+
+ br_divrem(hi, lo, d, &r);
+ return r;
+}
+
+/*
+ * Wrapper for br_divrem(); the quotient is returned, and the remainder
+ * is discarded.
+ */
+static inline uint32_t
+br_div(uint32_t hi, uint32_t lo, uint32_t d)
+{
+ uint32_t r;
+
+ return br_divrem(hi, lo, d, &r);
+}
+
+/* ==================================================================== */
+
+/*
+ * Integers 'i32'
+ * --------------
+ *
+ * The 'i32' functions implement computations on big integers using
+ * an internal representation as an array of 32-bit integers. For
+ * an array x[]:
+ * -- x[0] contains the "announced bit length" of the integer
+ * -- x[1], x[2]... contain the value in little-endian order (x[1]
+ * contains the least significant 32 bits)
+ *
+ * Multiplications rely on the elementary 32x32->64 multiplication.
+ *
+ * The announced bit length specifies the number of bits that are
+ * significant in the subsequent 32-bit words. Unused bits in the
+ * last (most significant) word are set to 0; subsequent words are
+ * uninitialized and need not exist at all.
+ *
+ * The execution time and memory access patterns of all computations
+ * depend on the announced bit length, but not on the actual word
+ * values. For modular integers, the announced bit length of any integer
+ * modulo n is equal to the actual bit length of n; thus, computations
+ * on modular integers are "constant-time" (only the modulus length may
+ * leak).
+ */
+
+/*
+ * Compute the actual bit length of an integer. The argument x should
+ * point to the first (least significant) value word of the integer.
+ * The len 'xlen' contains the number of 32-bit words to access.
+ *
+ * CT: value or length of x does not leak.
+ */
+uint32_t br_i32_bit_length(uint32_t *x, size_t xlen);
+
+/*
+ * Decode an integer from its big-endian unsigned representation. The
+ * "true" bit length of the integer is computed, but all words of x[]
+ * corresponding to the full 'len' bytes of the source are set.
+ *
+ * CT: value or length of x does not leak.
+ */
+void br_i32_decode(uint32_t *x, const void *src, size_t len);
+
+/*
+ * Decode an integer from its big-endian unsigned representation. The
+ * integer MUST be lower than m[]; the announced bit length written in
+ * x[] will be equal to that of m[]. All 'len' bytes from the source are
+ * read.
+ *
+ * Returned value is 1 if the decode value fits within the modulus, 0
+ * otherwise. In the latter case, the x[] buffer will be set to 0 (but
+ * still with the announced bit length of m[]).
+ *
+ * CT: value or length of x does not leak. Memory access pattern depends
+ * only of 'len' and the announced bit length of m. Whether x fits or
+ * not does not leak either.
+ */
+uint32_t br_i32_decode_mod(uint32_t *x,
+ const void *src, size_t len, const uint32_t *m);
+
+/*
+ * Reduce an integer (a[]) modulo another (m[]). The result is written
+ * in x[] and its announced bit length is set to be equal to that of m[].
+ *
+ * x[] MUST be distinct from a[] and m[].
+ *
+ * CT: only announced bit lengths leak, not values of x, a or m.
+ */
+void br_i32_reduce(uint32_t *x, const uint32_t *a, const uint32_t *m);
+
+/*
+ * Decode an integer from its big-endian unsigned representation, and
+ * reduce it modulo the provided modulus m[]. The announced bit length
+ * of the result is set to be equal to that of the modulus.
+ *
+ * x[] MUST be distinct from m[].
+ */
+void br_i32_decode_reduce(uint32_t *x,
+ const void *src, size_t len, const uint32_t *m);
+
+/*
+ * Encode an integer into its big-endian unsigned representation. The
+ * output length in bytes is provided (parameter 'len'); if the length
+ * is too short then the integer is appropriately truncated; if it is
+ * too long then the extra bytes are set to 0.
+ */
+void br_i32_encode(void *dst, size_t len, const uint32_t *x);
+
+/*
+ * Multiply x[] by 2^32 and then add integer z, modulo m[]. This
+ * function assumes that x[] and m[] have the same announced bit
+ * length, and the announced bit length of m[] matches its true
+ * bit length.
+ *
+ * x[] and m[] MUST be distinct arrays.
+ *
+ * CT: only the common announced bit length of x and m leaks, not
+ * the values of x, z or m.
+ */
+void br_i32_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m);
+
+/*
+ * Extract one word from an integer. The offset is counted in bits.
+ * The word MUST entirely fit within the word elements corresponding
+ * to the announced bit length of a[].
+ */
+static inline uint32_t
+br_i32_word(const uint32_t *a, uint32_t off)
+{
+ size_t u;
+ unsigned j;
+
+ u = (size_t)(off >> 5) + 1;
+ j = (unsigned)off & 31;
+ if (j == 0) {
+ return a[u];
+ } else {
+ return (a[u] >> j) | (a[u + 1] << (32 - j));
+ }
+}
+
+/*
+ * Test whether an integer is zero.
+ */
+uint32_t br_i32_iszero(const uint32_t *x);
+
+/*
+ * Add b[] to a[] and return the carry (0 or 1). If ctl is 0, then a[]
+ * is unmodified, but the carry is still computed and returned. The
+ * arrays a[] and b[] MUST have the same announced bit length.
+ *
+ * a[] and b[] MAY be the same array, but partial overlap is not allowed.
+ */
+uint32_t br_i32_add(uint32_t *a, const uint32_t *b, uint32_t ctl);
+
+/*
+ * Subtract b[] from a[] and return the carry (0 or 1). If ctl is 0,
+ * then a[] is unmodified, but the carry is still computed and returned.
+ * The arrays a[] and b[] MUST have the same announced bit length.
+ *
+ * a[] and b[] MAY be the same array, but partial overlap is not allowed.
+ */
+uint32_t br_i32_sub(uint32_t *a, const uint32_t *b, uint32_t ctl);
+
+/*
+ * Compute d+a*b, result in d. The initial announced bit length of d[]
+ * MUST match that of a[]. The d[] array MUST be large enough to
+ * accommodate the full result, plus (possibly) an extra word. The
+ * resulting announced bit length of d[] will be the sum of the announced
+ * bit lengths of a[] and b[] (therefore, it may be larger than the actual
+ * bit length of the numerical result).
+ *
+ * a[] and b[] may be the same array. d[] must be disjoint from both a[]
+ * and b[].
+ */
+void br_i32_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b);
+
+/*
+ * Zeroize an integer. The announced bit length is set to the provided
+ * value, and the corresponding words are set to 0.
+ */
+static inline void
+br_i32_zero(uint32_t *x, uint32_t bit_len)
+{
+ *x ++ = bit_len;
+ memset(x, 0, ((bit_len + 31) >> 5) * sizeof *x);
+}
+
+/*
+ * Compute -(1/x) mod 2^32. If x is even, then this function returns 0.
+ */
+uint32_t br_i32_ninv32(uint32_t x);
+
+/*
+ * Convert a modular integer to Montgomery representation. The integer x[]
+ * MUST be lower than m[], but with the same announced bit length.
+ */
+void br_i32_to_monty(uint32_t *x, const uint32_t *m);
+
+/*
+ * Convert a modular integer back from Montgomery representation. The
+ * integer x[] MUST be lower than m[], but with the same announced bit
+ * length. The "m0i" parameter is equal to -(1/m0) mod 2^32, where m0 is
+ * the least significant value word of m[] (this works only if m[] is
+ * an odd integer).
+ */
+void br_i32_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i);
+
+/*
+ * Compute a modular Montgomery multiplication. d[] is filled with the
+ * value of x*y/R modulo m[] (where R is the Montgomery factor). The
+ * array d[] MUST be distinct from x[], y[] and m[]. x[] and y[] MUST be
+ * numerically lower than m[]. x[] and y[] MAY be the same array. The
+ * "m0i" parameter is equal to -(1/m0) mod 2^32, where m0 is the least
+ * significant value word of m[] (this works only if m[] is an odd
+ * integer).
+ */
+void br_i32_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y,
+ const uint32_t *m, uint32_t m0i);
+
+/*
+ * Compute a modular exponentiation. x[] MUST be an integer modulo m[]
+ * (same announced bit length, lower value). m[] MUST be odd. The
+ * exponent is in big-endian unsigned notation, over 'elen' bytes. The
+ * "m0i" parameter is equal to -(1/m0) mod 2^32, where m0 is the least
+ * significant value word of m[] (this works only if m[] is an odd
+ * integer). The t1[] and t2[] parameters must be temporary arrays,
+ * each large enough to accommodate an integer with the same size as m[].
+ */
+void br_i32_modpow(uint32_t *x, const unsigned char *e, size_t elen,
+ const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2);
+
+/* ==================================================================== */
+
+/*
+ * Integers 'i31'
+ * --------------
+ *
+ * The 'i31' functions implement computations on big integers using
+ * an internal representation as an array of 32-bit integers. For
+ * an array x[]:
+ * -- x[0] encodes the array length and the "announced bit length"
+ * of the integer: namely, if the announced bit length is k,
+ * then x[0] = ((k / 31) << 5) + (k % 31).
+ * -- x[1], x[2]... contain the value in little-endian order, 31
+ * bits per word (x[1] contains the least significant 31 bits).
+ * The upper bit of each word is 0.
+ *
+ * Multiplications rely on the elementary 32x32->64 multiplication.
+ *
+ * The announced bit length specifies the number of bits that are
+ * significant in the subsequent 32-bit words. Unused bits in the
+ * last (most significant) word are set to 0; subsequent words are
+ * uninitialized and need not exist at all.
+ *
+ * The execution time and memory access patterns of all computations
+ * depend on the announced bit length, but not on the actual word
+ * values. For modular integers, the announced bit length of any integer
+ * modulo n is equal to the actual bit length of n; thus, computations
+ * on modular integers are "constant-time" (only the modulus length may
+ * leak).
+ */
+
+/*
+ * Test whether an integer is zero.
+ */
+uint32_t br_i31_iszero(const uint32_t *x);
+
+/*
+ * Add b[] to a[] and return the carry (0 or 1). If ctl is 0, then a[]
+ * is unmodified, but the carry is still computed and returned. The
+ * arrays a[] and b[] MUST have the same announced bit length.
+ *
+ * a[] and b[] MAY be the same array, but partial overlap is not allowed.
+ */
+uint32_t br_i31_add(uint32_t *a, const uint32_t *b, uint32_t ctl);
+
+/*
+ * Subtract b[] from a[] and return the carry (0 or 1). If ctl is 0,
+ * then a[] is unmodified, but the carry is still computed and returned.
+ * The arrays a[] and b[] MUST have the same announced bit length.
+ *
+ * a[] and b[] MAY be the same array, but partial overlap is not allowed.
+ */
+uint32_t br_i31_sub(uint32_t *a, const uint32_t *b, uint32_t ctl);
+
+/*
+ * Compute the ENCODED actual bit length of an integer. The argument x
+ * should point to the first (least significant) value word of the
+ * integer. The len 'xlen' contains the number of 32-bit words to
+ * access. The upper bit of each value word MUST be 0.
+ * Returned value is ((k / 31) << 5) + (k % 31) if the bit length is k.
+ *
+ * CT: value or length of x does not leak.
+ */
+uint32_t br_i31_bit_length(uint32_t *x, size_t xlen);
+
+/*
+ * Decode an integer from its big-endian unsigned representation. The
+ * "true" bit length of the integer is computed and set in the encoded
+ * announced bit length (x[0]), but all words of x[] corresponding to
+ * the full 'len' bytes of the source are set.
+ *
+ * CT: value or length of x does not leak.
+ */
+void br_i31_decode(uint32_t *x, const void *src, size_t len);
+
+/*
+ * Decode an integer from its big-endian unsigned representation. The
+ * integer MUST be lower than m[]; the (encoded) announced bit length
+ * written in x[] will be equal to that of m[]. All 'len' bytes from the
+ * source are read.
+ *
+ * Returned value is 1 if the decode value fits within the modulus, 0
+ * otherwise. In the latter case, the x[] buffer will be set to 0 (but
+ * still with the announced bit length of m[]).
+ *
+ * CT: value or length of x does not leak. Memory access pattern depends
+ * only of 'len' and the announced bit length of m. Whether x fits or
+ * not does not leak either.
+ */
+uint32_t br_i31_decode_mod(uint32_t *x,
+ const void *src, size_t len, const uint32_t *m);
+
+/*
+ * Zeroize an integer. The announced bit length is set to the provided
+ * value, and the corresponding words are set to 0. The ENCODED bit length
+ * is expected here.
+ */
+static inline void
+br_i31_zero(uint32_t *x, uint32_t bit_len)
+{
+ *x ++ = bit_len;
+ memset(x, 0, ((bit_len + 31) >> 5) * sizeof *x);
+}
+
+/*
+ * Right-shift an integer. The shift amount must be lower than 31
+ * bits.
+ */
+void br_i31_rshift(uint32_t *x, int count);
+
+/*
+ * Reduce an integer (a[]) modulo another (m[]). The result is written
+ * in x[] and its announced bit length is set to be equal to that of m[].
+ *
+ * x[] MUST be distinct from a[] and m[].
+ *
+ * CT: only announced bit lengths leak, not values of x, a or m.
+ */
+void br_i31_reduce(uint32_t *x, const uint32_t *a, const uint32_t *m);
+
+/*
+ * Decode an integer from its big-endian unsigned representation, and
+ * reduce it modulo the provided modulus m[]. The announced bit length
+ * of the result is set to be equal to that of the modulus.
+ *
+ * x[] MUST be distinct from m[].
+ */
+void br_i31_decode_reduce(uint32_t *x,
+ const void *src, size_t len, const uint32_t *m);
+
+/*
+ * Multiply x[] by 2^31 and then add integer z, modulo m[]. This
+ * function assumes that x[] and m[] have the same announced bit
+ * length, the announced bit length of m[] matches its true
+ * bit length.
+ *
+ * x[] and m[] MUST be distinct arrays. z MUST fit in 31 bits (upper
+ * bit set to 0).
+ *
+ * CT: only the common announced bit length of x and m leaks, not
+ * the values of x, z or m.
+ */
+void br_i31_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m);
+
+/*
+ * Encode an integer into its big-endian unsigned representation. The
+ * output length in bytes is provided (parameter 'len'); if the length
+ * is too short then the integer is appropriately truncated; if it is
+ * too long then the extra bytes are set to 0.
+ */
+void br_i31_encode(void *dst, size_t len, const uint32_t *x);
+
+/*
+ * Compute -(1/x) mod 2^31. If x is even, then this function returns 0.
+ */
+uint32_t br_i31_ninv31(uint32_t x);
+
+/*
+ * Compute a modular Montgomery multiplication. d[] is filled with the
+ * value of x*y/R modulo m[] (where R is the Montgomery factor). The
+ * array d[] MUST be distinct from x[], y[] and m[]. x[] and y[] MUST be
+ * numerically lower than m[]. x[] and y[] MAY be the same array. The
+ * "m0i" parameter is equal to -(1/m0) mod 2^31, where m0 is the least
+ * significant value word of m[] (this works only if m[] is an odd
+ * integer).
+ */
+void br_i31_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y,
+ const uint32_t *m, uint32_t m0i);
+
+/*
+ * Convert a modular integer to Montgomery representation. The integer x[]
+ * MUST be lower than m[], but with the same announced bit length.
+ */
+void br_i31_to_monty(uint32_t *x, const uint32_t *m);
+
+/*
+ * Convert a modular integer back from Montgomery representation. The
+ * integer x[] MUST be lower than m[], but with the same announced bit
+ * length. The "m0i" parameter is equal to -(1/m0) mod 2^32, where m0 is
+ * the least significant value word of m[] (this works only if m[] is
+ * an odd integer).
+ */
+void br_i31_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i);
+
+/*
+ * Compute a modular exponentiation. x[] MUST be an integer modulo m[]
+ * (same announced bit length, lower value). m[] MUST be odd. The
+ * exponent is in big-endian unsigned notation, over 'elen' bytes. The
+ * "m0i" parameter is equal to -(1/m0) mod 2^31, where m0 is the least
+ * significant value word of m[] (this works only if m[] is an odd
+ * integer). The t1[] and t2[] parameters must be temporary arrays,
+ * each large enough to accommodate an integer with the same size as m[].
+ */
+void br_i31_modpow(uint32_t *x, const unsigned char *e, size_t elen,
+ const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2);
+
+/*
+ * Compute a modular exponentiation. x[] MUST be an integer modulo m[]
+ * (same announced bit length, lower value). m[] MUST be odd. The
+ * exponent is in big-endian unsigned notation, over 'elen' bytes. The
+ * "m0i" parameter is equal to -(1/m0) mod 2^31, where m0 is the least
+ * significant value word of m[] (this works only if m[] is an odd
+ * integer). The tmp[] array is used for temporaries, and has size
+ * 'twlen' words; it must be large enough to accommodate at least two
+ * temporary values with the same size as m[] (including the leading
+ * "bit length" word). If there is room for more temporaries, then this
+ * function may use the extra room for window-based optimisation,
+ * resulting in faster computations.
+ *
+ * Returned value is 1 on success, 0 on error. An error is reported if
+ * the provided tmp[] array is too short.
+ */
+uint32_t br_i31_modpow_opt(uint32_t *x, const unsigned char *e, size_t elen,
+ const uint32_t *m, uint32_t m0i, uint32_t *tmp, size_t twlen);
+
+/*
+ * Compute d+a*b, result in d. The initial announced bit length of d[]
+ * MUST match that of a[]. The d[] array MUST be large enough to
+ * accommodate the full result, plus (possibly) an extra word. The
+ * resulting announced bit length of d[] will be the sum of the announced
+ * bit lengths of a[] and b[] (therefore, it may be larger than the actual
+ * bit length of the numerical result).
+ *
+ * a[] and b[] may be the same array. d[] must be disjoint from both a[]
+ * and b[].
+ */
+void br_i31_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b);
+
+/*
+ * Compute x/y mod m, result in x. Values x and y must be between 0 and
+ * m-1, and have the same announced bit length as m. Modulus m must be
+ * odd. The "m0i" parameter is equal to -1/m mod 2^31. The array 't'
+ * must point to a temporary area that can hold at least three integers
+ * of the size of m.
+ *
+ * m may not overlap x and y. x and y may overlap each other (this can
+ * be useful to test whether a value is invertible modulo m). t must be
+ * disjoint from all other arrays.
+ *
+ * Returned value is 1 on success, 0 otherwise. Success is attained if
+ * y is invertible modulo m.
+ */
+uint32_t br_i31_moddiv(uint32_t *x, const uint32_t *y,
+ const uint32_t *m, uint32_t m0i, uint32_t *t);
+
+/* ==================================================================== */
+
+/*
+ * FIXME: document "i15" functions.
+ */
+
+static inline void
+br_i15_zero(uint16_t *x, uint16_t bit_len)
+{
+ *x ++ = bit_len;
+ memset(x, 0, ((bit_len + 15) >> 4) * sizeof *x);
+}
+
+uint32_t br_i15_iszero(const uint16_t *x);
+
+uint16_t br_i15_ninv15(uint16_t x);
+
+uint32_t br_i15_add(uint16_t *a, const uint16_t *b, uint32_t ctl);
+
+uint32_t br_i15_sub(uint16_t *a, const uint16_t *b, uint32_t ctl);
+
+void br_i15_muladd_small(uint16_t *x, uint16_t z, const uint16_t *m);
+
+void br_i15_montymul(uint16_t *d, const uint16_t *x, const uint16_t *y,
+ const uint16_t *m, uint16_t m0i);
+
+void br_i15_to_monty(uint16_t *x, const uint16_t *m);
+
+void br_i15_modpow(uint16_t *x, const unsigned char *e, size_t elen,
+ const uint16_t *m, uint16_t m0i, uint16_t *t1, uint16_t *t2);
+
+uint32_t br_i15_modpow_opt(uint16_t *x, const unsigned char *e, size_t elen,
+ const uint16_t *m, uint16_t m0i, uint16_t *tmp, size_t twlen);
+
+void br_i15_encode(void *dst, size_t len, const uint16_t *x);
+
+uint32_t br_i15_decode_mod(uint16_t *x,
+ const void *src, size_t len, const uint16_t *m);
+
+void br_i15_rshift(uint16_t *x, int count);
+
+uint32_t br_i15_bit_length(uint16_t *x, size_t xlen);
+
+void br_i15_decode(uint16_t *x, const void *src, size_t len);
+
+void br_i15_from_monty(uint16_t *x, const uint16_t *m, uint16_t m0i);
+
+void br_i15_decode_reduce(uint16_t *x,
+ const void *src, size_t len, const uint16_t *m);
+
+void br_i15_reduce(uint16_t *x, const uint16_t *a, const uint16_t *m);
+
+void br_i15_mulacc(uint16_t *d, const uint16_t *a, const uint16_t *b);
+
+uint32_t br_i15_moddiv(uint16_t *x, const uint16_t *y,
+ const uint16_t *m, uint16_t m0i, uint16_t *t);
+
+/*
+ * Variant of br_i31_modpow_opt() that internally uses 64x64->128
+ * multiplications. It expects the same parameters as br_i31_modpow_opt(),
+ * except that the temporaries should be 64-bit integers, not 32-bit
+ * integers.
+ */
+uint32_t br_i62_modpow_opt(uint32_t *x31, const unsigned char *e, size_t elen,
+ const uint32_t *m31, uint32_t m0i31, uint64_t *tmp, size_t twlen);
+
+/*
+ * Type for a function with the same API as br_i31_modpow_opt() (some
+ * implementations of this type may have stricter alignment requirements
+ * on the temporaries).
+ */
+typedef uint32_t (*br_i31_modpow_opt_type)(uint32_t *x,
+ const unsigned char *e, size_t elen,
+ const uint32_t *m, uint32_t m0i, uint32_t *tmp, size_t twlen);
+
+/*
+ * Wrapper for br_i62_modpow_opt() that uses the same type as
+ * br_i31_modpow_opt(); however, it requires its 'tmp' argument to the
+ * 64-bit aligned.
+ */
+uint32_t br_i62_modpow_opt_as_i31(uint32_t *x,
+ const unsigned char *e, size_t elen,
+ const uint32_t *m, uint32_t m0i, uint32_t *tmp, size_t twlen);
+
+/* ==================================================================== */
+
+static inline size_t
+br_digest_size(const br_hash_class *digest_class)
+{
+ return (size_t)(digest_class->desc >> BR_HASHDESC_OUT_OFF)
+ & BR_HASHDESC_OUT_MASK;
+}
+
+/*
+ * Get the output size (in bytes) of a hash function.
+ */
+size_t br_digest_size_by_ID(int digest_id);
+
+/*
+ * Get the OID (encoded OBJECT IDENTIFIER value, without tag and length)
+ * for a hash function. If digest_id is not a supported digest identifier
+ * (in particular if it is equal to 0, i.e. br_md5sha1_ID), then NULL is
+ * returned and *len is set to 0.
+ */
+const unsigned char *br_digest_OID(int digest_id, size_t *len);
+
+/* ==================================================================== */
+/*
+ * DES support functions.
+ */
+
+/*
+ * Apply DES Initial Permutation.
+ */
+void br_des_do_IP(uint32_t *xl, uint32_t *xr);
+
+/*
+ * Apply DES Final Permutation (inverse of IP).
+ */
+void br_des_do_invIP(uint32_t *xl, uint32_t *xr);
+
+/*
+ * Key schedule unit: for a DES key (8 bytes), compute 16 subkeys. Each
+ * subkey is two 28-bit words represented as two 32-bit words; the PC-2
+ * bit extration is NOT applied.
+ */
+void br_des_keysched_unit(uint32_t *skey, const void *key);
+
+/*
+ * Reversal of 16 DES sub-keys (for decryption).
+ */
+void br_des_rev_skey(uint32_t *skey);
+
+/*
+ * DES/3DES key schedule for 'des_tab' (encryption direction). Returned
+ * value is the number of rounds.
+ */
+unsigned br_des_tab_keysched(uint32_t *skey, const void *key, size_t key_len);
+
+/*
+ * DES/3DES key schedule for 'des_ct' (encryption direction). Returned
+ * value is the number of rounds.
+ */
+unsigned br_des_ct_keysched(uint32_t *skey, const void *key, size_t key_len);
+
+/*
+ * DES/3DES subkey decompression (from the compressed bitsliced subkeys).
+ */
+void br_des_ct_skey_expand(uint32_t *sk_exp,
+ unsigned num_rounds, const uint32_t *skey);
+
+/*
+ * DES/3DES block encryption/decryption ('des_tab').
+ */
+void br_des_tab_process_block(unsigned num_rounds,
+ const uint32_t *skey, void *block);
+
+/*
+ * DES/3DES block encryption/decryption ('des_ct').
+ */
+void br_des_ct_process_block(unsigned num_rounds,
+ const uint32_t *skey, void *block);
+
+/* ==================================================================== */
+/*
+ * AES support functions.
+ */
+
+/*
+ * The AES S-box (256-byte table).
+ */
+extern const unsigned char br_aes_S[];
+
+/*
+ * AES key schedule. skey[] is filled with n+1 128-bit subkeys, where n
+ * is the number of rounds (10 to 14, depending on key size). The number
+ * of rounds is returned. If the key size is invalid (not 16, 24 or 32),
+ * then 0 is returned.
+ *
+ * This implementation uses a 256-byte table and is NOT constant-time.
+ */
+unsigned br_aes_keysched(uint32_t *skey, const void *key, size_t key_len);
+
+/*
+ * AES key schedule for decryption ('aes_big' implementation).
+ */
+unsigned br_aes_big_keysched_inv(uint32_t *skey,
+ const void *key, size_t key_len);
+
+/*
+ * AES block encryption with the 'aes_big' implementation (fast, but
+ * not constant-time). This function encrypts a single block "in place".
+ */
+void br_aes_big_encrypt(unsigned num_rounds, const uint32_t *skey, void *data);
+
+/*
+ * AES block decryption with the 'aes_big' implementation (fast, but
+ * not constant-time). This function decrypts a single block "in place".
+ */
+void br_aes_big_decrypt(unsigned num_rounds, const uint32_t *skey, void *data);
+
+/*
+ * AES block encryption with the 'aes_small' implementation (small, but
+ * slow and not constant-time). This function encrypts a single block
+ * "in place".
+ */
+void br_aes_small_encrypt(unsigned num_rounds,
+ const uint32_t *skey, void *data);
+
+/*
+ * AES block decryption with the 'aes_small' implementation (small, but
+ * slow and not constant-time). This function decrypts a single block
+ * "in place".
+ */
+void br_aes_small_decrypt(unsigned num_rounds,
+ const uint32_t *skey, void *data);
+
+/*
+ * The constant-time implementation is "bitsliced": the 128-bit state is
+ * split over eight 32-bit words q* in the following way:
+ *
+ * -- Input block consists in 16 bytes:
+ * a00 a10 a20 a30 a01 a11 a21 a31 a02 a12 a22 a32 a03 a13 a23 a33
+ * In the terminology of FIPS 197, this is a 4x4 matrix which is read
+ * column by column.
+ *
+ * -- Each byte is split into eight bits which are distributed over the
+ * eight words, at the same rank. Thus, for a byte x at rank k, bit 0
+ * (least significant) of x will be at rank k in q0 (if that bit is b,
+ * then it contributes "b << k" to the value of q0), bit 1 of x will be
+ * at rank k in q1, and so on.
+ *
+ * -- Ranks given to bits are in "row order" and are either all even, or
+ * all odd. Two independent AES states are thus interleaved, one using
+ * the even ranks, the other the odd ranks. Row order means:
+ * a00 a01 a02 a03 a10 a11 a12 a13 a20 a21 a22 a23 a30 a31 a32 a33
+ *
+ * Converting input bytes from two AES blocks to bitslice representation
+ * is done in the following way:
+ * -- Decode first block into the four words q0 q2 q4 q6, in that order,
+ * using little-endian convention.
+ * -- Decode second block into the four words q1 q3 q5 q7, in that order,
+ * using little-endian convention.
+ * -- Call br_aes_ct_ortho().
+ *
+ * Converting back to bytes is done by using the reverse operations. Note
+ * that br_aes_ct_ortho() is its own inverse.
+ */
+
+/*
+ * Perform bytewise orthogonalization of eight 32-bit words. Bytes
+ * of q0..q7 are spread over all words: for a byte x that occurs
+ * at rank i in q[j] (byte x uses bits 8*i to 8*i+7 in q[j]), the bit
+ * of rank k in x (0 <= k <= 7) goes to q[k] at rank 8*i+j.
+ *
+ * This operation is an involution.
+ */
+void br_aes_ct_ortho(uint32_t *q);
+
+/*
+ * The AES S-box, as a bitsliced constant-time version. The input array
+ * consists in eight 32-bit words; 32 S-box instances are computed in
+ * parallel. Bits 0 to 7 of each S-box input (bit 0 is least significant)
+ * are spread over the words 0 to 7, at the same rank.
+ */
+void br_aes_ct_bitslice_Sbox(uint32_t *q);
+
+/*
+ * Like br_aes_bitslice_Sbox(), but for the inverse S-box.
+ */
+void br_aes_ct_bitslice_invSbox(uint32_t *q);
+
+/*
+ * Compute AES encryption on bitsliced data. Since input is stored on
+ * eight 32-bit words, two block encryptions are actually performed
+ * in parallel.
+ */
+void br_aes_ct_bitslice_encrypt(unsigned num_rounds,
+ const uint32_t *skey, uint32_t *q);
+
+/*
+ * Compute AES decryption on bitsliced data. Since input is stored on
+ * eight 32-bit words, two block decryptions are actually performed
+ * in parallel.
+ */
+void br_aes_ct_bitslice_decrypt(unsigned num_rounds,
+ const uint32_t *skey, uint32_t *q);
+
+/*
+ * AES key schedule, constant-time version. skey[] is filled with n+1
+ * 128-bit subkeys, where n is the number of rounds (10 to 14, depending
+ * on key size). The number of rounds is returned. If the key size is
+ * invalid (not 16, 24 or 32), then 0 is returned.
+ */
+unsigned br_aes_ct_keysched(uint32_t *comp_skey,
+ const void *key, size_t key_len);
+
+/*
+ * Expand AES subkeys as produced by br_aes_ct_keysched(), into
+ * a larger array suitable for br_aes_ct_bitslice_encrypt() and
+ * br_aes_ct_bitslice_decrypt().
+ */
+void br_aes_ct_skey_expand(uint32_t *skey,
+ unsigned num_rounds, const uint32_t *comp_skey);
+
+/*
+ * For the ct64 implementation, the same bitslicing technique is used,
+ * but four instances are interleaved. First instance uses bits 0, 4,
+ * 8, 12,... of each word; second instance uses bits 1, 5, 9, 13,...
+ * and so on.
+ */
+
+/*
+ * Perform bytewise orthogonalization of eight 64-bit words. Bytes
+ * of q0..q7 are spread over all words: for a byte x that occurs
+ * at rank i in q[j] (byte x uses bits 8*i to 8*i+7 in q[j]), the bit
+ * of rank k in x (0 <= k <= 7) goes to q[k] at rank 8*i+j.
+ *
+ * This operation is an involution.
+ */
+void br_aes_ct64_ortho(uint64_t *q);
+
+/*
+ * Interleave bytes for an AES input block. If input bytes are
+ * denoted 0123456789ABCDEF, and have been decoded with little-endian
+ * convention (w[0] contains 0123, with '3' being most significant;
+ * w[1] contains 4567, and so on), then output word q0 will be
+ * set to 08192A3B (again little-endian convention) and q1 will
+ * be set to 4C5D6E7F.
+ */
+void br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w);
+
+/*
+ * Perform the opposite of br_aes_ct64_interleave_in().
+ */
+void br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1);
+
+/*
+ * The AES S-box, as a bitsliced constant-time version. The input array
+ * consists in eight 64-bit words; 64 S-box instances are computed in
+ * parallel. Bits 0 to 7 of each S-box input (bit 0 is least significant)
+ * are spread over the words 0 to 7, at the same rank.
+ */
+void br_aes_ct64_bitslice_Sbox(uint64_t *q);
+
+/*
+ * Like br_aes_bitslice_Sbox(), but for the inverse S-box.
+ */
+void br_aes_ct64_bitslice_invSbox(uint64_t *q);
+
+/*
+ * Compute AES encryption on bitsliced data. Since input is stored on
+ * eight 64-bit words, four block encryptions are actually performed
+ * in parallel.
+ */
+void br_aes_ct64_bitslice_encrypt(unsigned num_rounds,
+ const uint64_t *skey, uint64_t *q);
+
+/*
+ * Compute AES decryption on bitsliced data. Since input is stored on
+ * eight 64-bit words, four block decryptions are actually performed
+ * in parallel.
+ */
+void br_aes_ct64_bitslice_decrypt(unsigned num_rounds,
+ const uint64_t *skey, uint64_t *q);
+
+/*
+ * AES key schedule, constant-time version. skey[] is filled with n+1
+ * 128-bit subkeys, where n is the number of rounds (10 to 14, depending
+ * on key size). The number of rounds is returned. If the key size is
+ * invalid (not 16, 24 or 32), then 0 is returned.
+ */
+unsigned br_aes_ct64_keysched(uint64_t *comp_skey,
+ const void *key, size_t key_len);
+
+/*
+ * Expand AES subkeys as produced by br_aes_ct64_keysched(), into
+ * a larger array suitable for br_aes_ct64_bitslice_encrypt() and
+ * br_aes_ct64_bitslice_decrypt().
+ */
+void br_aes_ct64_skey_expand(uint64_t *skey,
+ unsigned num_rounds, const uint64_t *comp_skey);
+
+/*
+ * Test support for AES-NI opcodes.
+ */
+int br_aes_x86ni_supported(void);
+
+/*
+ * AES key schedule, using x86 AES-NI instructions. This yields the
+ * subkeys in the encryption direction. Number of rounds is returned.
+ * Key size MUST be 16, 24 or 32 bytes; otherwise, 0 is returned.
+ */
+unsigned br_aes_x86ni_keysched_enc(unsigned char *skni,
+ const void *key, size_t len);
+
+/*
+ * AES key schedule, using x86 AES-NI instructions. This yields the
+ * subkeys in the decryption direction. Number of rounds is returned.
+ * Key size MUST be 16, 24 or 32 bytes; otherwise, 0 is returned.
+ */
+unsigned br_aes_x86ni_keysched_dec(unsigned char *skni,
+ const void *key, size_t len);
+
+/*
+ * Test support for AES POWER8 opcodes.
+ */
+int br_aes_pwr8_supported(void);
+
+/*
+ * AES key schedule, using POWER8 instructions. This yields the
+ * subkeys in the encryption direction. Number of rounds is returned.
+ * Key size MUST be 16, 24 or 32 bytes; otherwise, 0 is returned.
+ */
+unsigned br_aes_pwr8_keysched(unsigned char *skni,
+ const void *key, size_t len);
+
+/* ==================================================================== */
+/*
+ * RSA.
+ */
+
+/*
+ * Apply proper PKCS#1 v1.5 padding (for signatures). 'hash_oid' is
+ * the encoded hash function OID, or NULL.
+ */
+uint32_t br_rsa_pkcs1_sig_pad(const unsigned char *hash_oid,
+ const unsigned char *hash, size_t hash_len,
+ uint32_t n_bitlen, unsigned char *x);
+
+/*
+ * Check PKCS#1 v1.5 padding (for signatures). 'hash_oid' is the encoded
+ * hash function OID, or NULL. The provided 'sig' value is _after_ the
+ * modular exponentiation, i.e. it should be the padded hash. On
+ * success, the hashed message is extracted.
+ */
+uint32_t br_rsa_pkcs1_sig_unpad(const unsigned char *sig, size_t sig_len,
+ const unsigned char *hash_oid, size_t hash_len,
+ unsigned char *hash_out);
+
+/*
+ * Apply proper PSS padding. The 'x' buffer is output only: it
+ * receives the value that is to be exponentiated.
+ */
+uint32_t br_rsa_pss_sig_pad(const br_prng_class **rng,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const unsigned char *hash, size_t salt_len,
+ uint32_t n_bitlen, unsigned char *x);
+
+/*
+ * Check PSS padding. The provided value is the one _after_
+ * the modular exponentiation; it is modified by this function.
+ * This function infers the signature length from the public key
+ * size, i.e. it assumes that this has already been verified (as
+ * part of the exponentiation).
+ */
+uint32_t br_rsa_pss_sig_unpad(
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const unsigned char *hash, size_t salt_len,
+ const br_rsa_public_key *pk, unsigned char *x);
+
+/*
+ * Apply OAEP padding. Returned value is the actual padded string length,
+ * or zero on error.
+ */
+size_t br_rsa_oaep_pad(const br_prng_class **rnd, const br_hash_class *dig,
+ const void *label, size_t label_len, const br_rsa_public_key *pk,
+ void *dst, size_t dst_nax_len, const void *src, size_t src_len);
+
+/*
+ * Unravel and check OAEP padding. If the padding is correct, then 1 is
+ * returned, '*len' is adjusted to the length of the message, and the
+ * data is moved to the start of the 'data' buffer. If the padding is
+ * incorrect, then 0 is returned and '*len' is untouched. Either way,
+ * the complete buffer contents are altered.
+ */
+uint32_t br_rsa_oaep_unpad(const br_hash_class *dig,
+ const void *label, size_t label_len, void *data, size_t *len);
+
+/*
+ * Compute MGF1 for a given seed, and XOR the output into the provided
+ * buffer.
+ */
+void br_mgf1_xor(void *data, size_t len,
+ const br_hash_class *dig, const void *seed, size_t seed_len);
+
+/*
+ * Inner function for RSA key generation; used by the "i31" and "i62"
+ * implementations.
+ */
+uint32_t br_rsa_i31_keygen_inner(const br_prng_class **rng,
+ br_rsa_private_key *sk, void *kbuf_priv,
+ br_rsa_public_key *pk, void *kbuf_pub,
+ unsigned size, uint32_t pubexp, br_i31_modpow_opt_type mp31);
+
+/* ==================================================================== */
+/*
+ * Elliptic curves.
+ */
+
+/*
+ * Type for generic EC parameters: curve order (unsigned big-endian
+ * encoding) and encoded conventional generator.
+ */
+typedef struct {
+ int curve;
+ const unsigned char *order;
+ size_t order_len;
+ const unsigned char *generator;
+ size_t generator_len;
+} br_ec_curve_def;
+
+extern const br_ec_curve_def br_secp256r1;
+extern const br_ec_curve_def br_secp384r1;
+extern const br_ec_curve_def br_secp521r1;
+
+/*
+ * For Curve25519, the advertised "order" really is 2^255-1, since the
+ * point multipliction function really works over arbitrary 255-bit
+ * scalars. This value is only meant as a hint for ECDH key generation;
+ * only ECDSA uses the exact curve order, and ECDSA is not used with
+ * that specific curve.
+ */
+extern const br_ec_curve_def br_curve25519;
+
+/*
+ * Decode some bytes as an i31 integer, with truncation (corresponding
+ * to the 'bits2int' operation in RFC 6979). The target ENCODED bit
+ * length is provided as last parameter. The resulting value will have
+ * this declared bit length, and consists the big-endian unsigned decoding
+ * of exactly that many bits in the source (capped at the source length).
+ */
+void br_ecdsa_i31_bits2int(uint32_t *x,
+ const void *src, size_t len, uint32_t ebitlen);
+
+/*
+ * Decode some bytes as an i15 integer, with truncation (corresponding
+ * to the 'bits2int' operation in RFC 6979). The target ENCODED bit
+ * length is provided as last parameter. The resulting value will have
+ * this declared bit length, and consists the big-endian unsigned decoding
+ * of exactly that many bits in the source (capped at the source length).
+ */
+void br_ecdsa_i15_bits2int(uint16_t *x,
+ const void *src, size_t len, uint32_t ebitlen);
+
+/* ==================================================================== */
+/*
+ * ASN.1 support functions.
+ */
+
+/*
+ * A br_asn1_uint structure contains encoding information about an
+ * INTEGER nonnegative value: pointer to the integer contents (unsigned
+ * big-endian representation), length of the integer contents,
+ * and length of the encoded value. The data shall have minimal length:
+ * - If the integer value is zero, then 'len' must be zero.
+ * - If the integer value is not zero, then data[0] must be non-zero.
+ *
+ * Under these conditions, 'asn1len' is necessarily equal to either len
+ * or len+1.
+ */
+typedef struct {
+ const unsigned char *data;
+ size_t len;
+ size_t asn1len;
+} br_asn1_uint;
+
+/*
+ * Given an encoded integer (unsigned big-endian, with possible leading
+ * bytes of value 0), returned the "prepared INTEGER" structure.
+ */
+br_asn1_uint br_asn1_uint_prepare(const void *xdata, size_t xlen);
+
+/*
+ * Encode an ASN.1 length. The length of the encoded length is returned.
+ * If 'dest' is NULL, then no encoding is performed, but the length of
+ * the encoded length is still computed and returned.
+ */
+size_t br_asn1_encode_length(void *dest, size_t len);
+
+/*
+ * Convenient macro for computing lengths of lengths.
+ */
+#define len_of_len(len) br_asn1_encode_length(NULL, len)
+
+/*
+ * Encode a (prepared) ASN.1 INTEGER. The encoded length is returned.
+ * If 'dest' is NULL, then no encoding is performed, but the length of
+ * the encoded integer is still computed and returned.
+ */
+size_t br_asn1_encode_uint(void *dest, br_asn1_uint pp);
+
+/*
+ * Get the OID that identifies an elliptic curve. Returned value is
+ * the DER-encoded OID, with the length (always one byte) but without
+ * the tag. Thus, the first byte of the returned buffer contains the
+ * number of subsequent bytes in the value. If the curve is not
+ * recognised, NULL is returned.
+ */
+const unsigned char *br_get_curve_OID(int curve);
+
+/*
+ * Inner function for EC private key encoding. This is equivalent to
+ * the API function br_encode_ec_raw_der(), except for an extra
+ * parameter: if 'include_curve_oid' is zero, then the curve OID is
+ * _not_ included in the output blob (this is for PKCS#8 support).
+ */
+size_t br_encode_ec_raw_der_inner(void *dest,
+ const br_ec_private_key *sk, const br_ec_public_key *pk,
+ int include_curve_oid);
+
+/* ==================================================================== */
+/*
+ * SSL/TLS support functions.
+ */
+
+/*
+ * Record types.
+ */
+#define BR_SSL_CHANGE_CIPHER_SPEC 20
+#define BR_SSL_ALERT 21
+#define BR_SSL_HANDSHAKE 22
+#define BR_SSL_APPLICATION_DATA 23
+
+/*
+ * Handshake message types.
+ */
+#define BR_SSL_HELLO_REQUEST 0
+#define BR_SSL_CLIENT_HELLO 1
+#define BR_SSL_SERVER_HELLO 2
+#define BR_SSL_CERTIFICATE 11
+#define BR_SSL_SERVER_KEY_EXCHANGE 12
+#define BR_SSL_CERTIFICATE_REQUEST 13
+#define BR_SSL_SERVER_HELLO_DONE 14
+#define BR_SSL_CERTIFICATE_VERIFY 15
+#define BR_SSL_CLIENT_KEY_EXCHANGE 16
+#define BR_SSL_FINISHED 20
+
+/*
+ * Alert levels.
+ */
+#define BR_LEVEL_WARNING 1
+#define BR_LEVEL_FATAL 2
+
+/*
+ * Low-level I/O state.
+ */
+#define BR_IO_FAILED 0
+#define BR_IO_IN 1
+#define BR_IO_OUT 2
+#define BR_IO_INOUT 3
+
+/*
+ * Mark a SSL engine as failed. The provided error code is recorded if
+ * the engine was not already marked as failed. If 'err' is 0, then the
+ * engine is marked as closed (without error).
+ */
+void br_ssl_engine_fail(br_ssl_engine_context *cc, int err);
+
+/*
+ * Test whether the engine is closed (normally or as a failure).
+ */
+static inline int
+br_ssl_engine_closed(const br_ssl_engine_context *cc)
+{
+ return cc->iomode == BR_IO_FAILED;
+}
+
+/*
+ * Configure a new maximum fragment length. If possible, the maximum
+ * length for outgoing records is immediately adjusted (if there are
+ * not already too many buffered bytes for that).
+ */
+void br_ssl_engine_new_max_frag_len(
+ br_ssl_engine_context *rc, unsigned max_frag_len);
+
+/*
+ * Test whether the current incoming record has been fully received
+ * or not. This functions returns 0 only if a complete record header
+ * has been received, but some of the (possibly encrypted) payload
+ * has not yet been obtained.
+ */
+int br_ssl_engine_recvrec_finished(const br_ssl_engine_context *rc);
+
+/*
+ * Flush the current record (if not empty). This is meant to be called
+ * from the handshake processor only.
+ */
+void br_ssl_engine_flush_record(br_ssl_engine_context *cc);
+
+/*
+ * Test whether there is some accumulated payload to send.
+ */
+static inline int
+br_ssl_engine_has_pld_to_send(const br_ssl_engine_context *rc)
+{
+ return rc->oxa != rc->oxb && rc->oxa != rc->oxc;
+}
+
+/*
+ * Initialize RNG in engine. Returned value is 1 on success, 0 on error.
+ * This function will try to use the OS-provided RNG, if available. If
+ * there is no OS-provided RNG, or if it failed, and no entropy was
+ * injected by the caller, then a failure will be reported. On error,
+ * the context error code is set.
+ */
+int br_ssl_engine_init_rand(br_ssl_engine_context *cc);
+
+/*
+ * Reset the handshake-related parts of the engine.
+ */
+void br_ssl_engine_hs_reset(br_ssl_engine_context *cc,
+ void (*hsinit)(void *), void (*hsrun)(void *));
+
+/*
+ * Get the PRF to use for this context, for the provided PRF hash
+ * function ID.
+ */
+br_tls_prf_impl br_ssl_engine_get_PRF(br_ssl_engine_context *cc, int prf_id);
+
+/*
+ * Consume the provided pre-master secret and compute the corresponding
+ * master secret. The 'prf_id' is the ID of the hash function to use
+ * with the TLS 1.2 PRF (ignored if the version is TLS 1.0 or 1.1).
+ */
+void br_ssl_engine_compute_master(br_ssl_engine_context *cc,
+ int prf_id, const void *pms, size_t len);
+
+/*
+ * Switch to CBC decryption for incoming records.
+ * cc the engine context
+ * is_client non-zero for a client, zero for a server
+ * prf_id id of hash function for PRF (ignored if not TLS 1.2+)
+ * mac_id id of hash function for HMAC
+ * bc_impl block cipher implementation (CBC decryption)
+ * cipher_key_len block cipher key length (in bytes)
+ */
+void br_ssl_engine_switch_cbc_in(br_ssl_engine_context *cc,
+ int is_client, int prf_id, int mac_id,
+ const br_block_cbcdec_class *bc_impl, size_t cipher_key_len);
+
+/*
+ * Switch to CBC encryption for outgoing records.
+ * cc the engine context
+ * is_client non-zero for a client, zero for a server
+ * prf_id id of hash function for PRF (ignored if not TLS 1.2+)
+ * mac_id id of hash function for HMAC
+ * bc_impl block cipher implementation (CBC encryption)
+ * cipher_key_len block cipher key length (in bytes)
+ */
+void br_ssl_engine_switch_cbc_out(br_ssl_engine_context *cc,
+ int is_client, int prf_id, int mac_id,
+ const br_block_cbcenc_class *bc_impl, size_t cipher_key_len);
+
+/*
+ * Switch to GCM decryption for incoming records.
+ * cc the engine context
+ * is_client non-zero for a client, zero for a server
+ * prf_id id of hash function for PRF
+ * bc_impl block cipher implementation (CTR)
+ * cipher_key_len block cipher key length (in bytes)
+ */
+void br_ssl_engine_switch_gcm_in(br_ssl_engine_context *cc,
+ int is_client, int prf_id,
+ const br_block_ctr_class *bc_impl, size_t cipher_key_len);
+
+/*
+ * Switch to GCM encryption for outgoing records.
+ * cc the engine context
+ * is_client non-zero for a client, zero for a server
+ * prf_id id of hash function for PRF
+ * bc_impl block cipher implementation (CTR)
+ * cipher_key_len block cipher key length (in bytes)
+ */
+void br_ssl_engine_switch_gcm_out(br_ssl_engine_context *cc,
+ int is_client, int prf_id,
+ const br_block_ctr_class *bc_impl, size_t cipher_key_len);
+
+/*
+ * Switch to ChaCha20+Poly1305 decryption for incoming records.
+ * cc the engine context
+ * is_client non-zero for a client, zero for a server
+ * prf_id id of hash function for PRF
+ */
+void br_ssl_engine_switch_chapol_in(br_ssl_engine_context *cc,
+ int is_client, int prf_id);
+
+/*
+ * Switch to ChaCha20+Poly1305 encryption for outgoing records.
+ * cc the engine context
+ * is_client non-zero for a client, zero for a server
+ * prf_id id of hash function for PRF
+ */
+void br_ssl_engine_switch_chapol_out(br_ssl_engine_context *cc,
+ int is_client, int prf_id);
+
+/*
+ * Switch to CCM decryption for incoming records.
+ * cc the engine context
+ * is_client non-zero for a client, zero for a server
+ * prf_id id of hash function for PRF
+ * bc_impl block cipher implementation (CTR+CBC)
+ * cipher_key_len block cipher key length (in bytes)
+ * tag_len tag length (in bytes)
+ */
+void br_ssl_engine_switch_ccm_in(br_ssl_engine_context *cc,
+ int is_client, int prf_id,
+ const br_block_ctrcbc_class *bc_impl,
+ size_t cipher_key_len, size_t tag_len);
+
+/*
+ * Switch to GCM encryption for outgoing records.
+ * cc the engine context
+ * is_client non-zero for a client, zero for a server
+ * prf_id id of hash function for PRF
+ * bc_impl block cipher implementation (CTR+CBC)
+ * cipher_key_len block cipher key length (in bytes)
+ * tag_len tag length (in bytes)
+ */
+void br_ssl_engine_switch_ccm_out(br_ssl_engine_context *cc,
+ int is_client, int prf_id,
+ const br_block_ctrcbc_class *bc_impl,
+ size_t cipher_key_len, size_t tag_len);
+
+/*
+ * Calls to T0-generated code.
+ */
+void br_ssl_hs_client_init_main(void *ctx);
+void br_ssl_hs_client_run(void *ctx);
+void br_ssl_hs_server_init_main(void *ctx);
+void br_ssl_hs_server_run(void *ctx);
+
+/*
+ * Get the hash function to use for signatures, given a bit mask of
+ * supported hash functions. This implements a strict choice order
+ * (namely SHA-256, SHA-384, SHA-512, SHA-224, SHA-1). If the mask
+ * does not document support of any of these hash functions, then this
+ * functions returns 0.
+ */
+int br_ssl_choose_hash(unsigned bf);
+
+/* ==================================================================== */
+
+/*
+ * PowerPC / POWER assembly stuff. The special BR_POWER_ASM_MACROS macro
+ * must be defined before including this file; this is done by source
+ * files that use some inline assembly for PowerPC / POWER machines.
+ */
+
+#if BR_POWER_ASM_MACROS
+
+#define lxvw4x(xt, ra, rb) lxvw4x_(xt, ra, rb)
+#define stxvw4x(xt, ra, rb) stxvw4x_(xt, ra, rb)
+
+#define bdnz(foo) bdnz_(foo)
+#define bdz(foo) bdz_(foo)
+#define beq(foo) beq_(foo)
+
+#define li(rx, value) li_(rx, value)
+#define addi(rx, ra, imm) addi_(rx, ra, imm)
+#define cmpldi(rx, imm) cmpldi_(rx, imm)
+#define mtctr(rx) mtctr_(rx)
+#define vspltb(vrt, vrb, uim) vspltb_(vrt, vrb, uim)
+#define vspltw(vrt, vrb, uim) vspltw_(vrt, vrb, uim)
+#define vspltisb(vrt, imm) vspltisb_(vrt, imm)
+#define vspltisw(vrt, imm) vspltisw_(vrt, imm)
+#define vrlw(vrt, vra, vrb) vrlw_(vrt, vra, vrb)
+#define vsbox(vrt, vra) vsbox_(vrt, vra)
+#define vxor(vrt, vra, vrb) vxor_(vrt, vra, vrb)
+#define vand(vrt, vra, vrb) vand_(vrt, vra, vrb)
+#define vsro(vrt, vra, vrb) vsro_(vrt, vra, vrb)
+#define vsl(vrt, vra, vrb) vsl_(vrt, vra, vrb)
+#define vsldoi(vt, va, vb, sh) vsldoi_(vt, va, vb, sh)
+#define vsr(vrt, vra, vrb) vsr_(vrt, vra, vrb)
+#define vaddcuw(vrt, vra, vrb) vaddcuw_(vrt, vra, vrb)
+#define vadduwm(vrt, vra, vrb) vadduwm_(vrt, vra, vrb)
+#define vsububm(vrt, vra, vrb) vsububm_(vrt, vra, vrb)
+#define vsubuwm(vrt, vra, vrb) vsubuwm_(vrt, vra, vrb)
+#define vsrw(vrt, vra, vrb) vsrw_(vrt, vra, vrb)
+#define vcipher(vt, va, vb) vcipher_(vt, va, vb)
+#define vcipherlast(vt, va, vb) vcipherlast_(vt, va, vb)
+#define vncipher(vt, va, vb) vncipher_(vt, va, vb)
+#define vncipherlast(vt, va, vb) vncipherlast_(vt, va, vb)
+#define vperm(vt, va, vb, vc) vperm_(vt, va, vb, vc)
+#define vpmsumd(vt, va, vb) vpmsumd_(vt, va, vb)
+#define xxpermdi(vt, va, vb, d) xxpermdi_(vt, va, vb, d)
+
+#define lxvw4x_(xt, ra, rb) "\tlxvw4x\t" #xt "," #ra "," #rb "\n"
+#define stxvw4x_(xt, ra, rb) "\tstxvw4x\t" #xt "," #ra "," #rb "\n"
+
+#define label(foo) #foo "%=:\n"
+#define bdnz_(foo) "\tbdnz\t" #foo "%=\n"
+#define bdz_(foo) "\tbdz\t" #foo "%=\n"
+#define beq_(foo) "\tbeq\t" #foo "%=\n"
+
+#define li_(rx, value) "\tli\t" #rx "," #value "\n"
+#define addi_(rx, ra, imm) "\taddi\t" #rx "," #ra "," #imm "\n"
+#define cmpldi_(rx, imm) "\tcmpldi\t" #rx "," #imm "\n"
+#define mtctr_(rx) "\tmtctr\t" #rx "\n"
+#define vspltb_(vrt, vrb, uim) "\tvspltb\t" #vrt "," #vrb "," #uim "\n"
+#define vspltw_(vrt, vrb, uim) "\tvspltw\t" #vrt "," #vrb "," #uim "\n"
+#define vspltisb_(vrt, imm) "\tvspltisb\t" #vrt "," #imm "\n"
+#define vspltisw_(vrt, imm) "\tvspltisw\t" #vrt "," #imm "\n"
+#define vrlw_(vrt, vra, vrb) "\tvrlw\t" #vrt "," #vra "," #vrb "\n"
+#define vsbox_(vrt, vra) "\tvsbox\t" #vrt "," #vra "\n"
+#define vxor_(vrt, vra, vrb) "\tvxor\t" #vrt "," #vra "," #vrb "\n"
+#define vand_(vrt, vra, vrb) "\tvand\t" #vrt "," #vra "," #vrb "\n"
+#define vsro_(vrt, vra, vrb) "\tvsro\t" #vrt "," #vra "," #vrb "\n"
+#define vsl_(vrt, vra, vrb) "\tvsl\t" #vrt "," #vra "," #vrb "\n"
+#define vsldoi_(vt, va, vb, sh) "\tvsldoi\t" #vt "," #va "," #vb "," #sh "\n"
+#define vsr_(vrt, vra, vrb) "\tvsr\t" #vrt "," #vra "," #vrb "\n"
+#define vaddcuw_(vrt, vra, vrb) "\tvaddcuw\t" #vrt "," #vra "," #vrb "\n"
+#define vadduwm_(vrt, vra, vrb) "\tvadduwm\t" #vrt "," #vra "," #vrb "\n"
+#define vsububm_(vrt, vra, vrb) "\tvsububm\t" #vrt "," #vra "," #vrb "\n"
+#define vsubuwm_(vrt, vra, vrb) "\tvsubuwm\t" #vrt "," #vra "," #vrb "\n"
+#define vsrw_(vrt, vra, vrb) "\tvsrw\t" #vrt "," #vra "," #vrb "\n"
+#define vcipher_(vt, va, vb) "\tvcipher\t" #vt "," #va "," #vb "\n"
+#define vcipherlast_(vt, va, vb) "\tvcipherlast\t" #vt "," #va "," #vb "\n"
+#define vncipher_(vt, va, vb) "\tvncipher\t" #vt "," #va "," #vb "\n"
+#define vncipherlast_(vt, va, vb) "\tvncipherlast\t" #vt "," #va "," #vb "\n"
+#define vperm_(vt, va, vb, vc) "\tvperm\t" #vt "," #va "," #vb "," #vc "\n"
+#define vpmsumd_(vt, va, vb) "\tvpmsumd\t" #vt "," #va "," #vb "\n"
+#define xxpermdi_(vt, va, vb, d) "\txxpermdi\t" #vt "," #va "," #vb "," #d "\n"
+
+#endif
+
+/* ==================================================================== */
+/*
+ * Special "activate intrinsics" code, needed for some compiler versions.
+ * This is defined at the end of this file, so that it won't impact any
+ * of the inline functions defined previously; and it is controlled by
+ * a specific macro defined in the caller code.
+ *
+ * Calling code conventions:
+ *
+ * - Caller must define BR_ENABLE_INTRINSICS before including "inner.h".
+ * - Functions that use intrinsics must be enclosed in an "enabled"
+ * region (between BR_TARGETS_X86_UP and BR_TARGETS_X86_DOWN).
+ * - Functions that use intrinsics must be tagged with the appropriate
+ * BR_TARGET().
+ */
+
+#if BR_ENABLE_INTRINSICS && (BR_GCC_4_4 || BR_CLANG_3_7 || BR_MSC_2005)
+
+/*
+ * x86 intrinsics (both 32-bit and 64-bit).
+ */
+#if BR_i386 || BR_amd64
+
+/*
+ * On GCC before version 5.0, we need to use the pragma to enable the
+ * target options globally, because the 'target' function attribute
+ * appears to be unreliable. Before 4.6 we must also avoid the
+ * push_options / pop_options mechanism, because it tends to trigger
+ * some internal compiler errors.
+ */
+#if BR_GCC && !BR_GCC_5_0
+#if BR_GCC_4_6
+#define BR_TARGETS_X86_UP \
+ _Pragma("GCC push_options") \
+ _Pragma("GCC target(\"sse2,ssse3,sse4.1,aes,pclmul,rdrnd\")")
+#define BR_TARGETS_X86_DOWN \
+ _Pragma("GCC pop_options")
+#else
+#define BR_TARGETS_X86_UP \
+ _Pragma("GCC target(\"sse2,ssse3,sse4.1,aes,pclmul\")")
+#define BR_TARGETS_X86_DOWN
+#endif
+#pragma GCC diagnostic ignored "-Wpsabi"
+#endif
+
+#if BR_CLANG && !BR_CLANG_3_8
+#undef __SSE2__
+#undef __SSE3__
+#undef __SSSE3__
+#undef __SSE4_1__
+#undef __AES__
+#undef __PCLMUL__
+#undef __RDRND__
+#define __SSE2__ 1
+#define __SSE3__ 1
+#define __SSSE3__ 1
+#define __SSE4_1__ 1
+#define __AES__ 1
+#define __PCLMUL__ 1
+#define __RDRND__ 1
+#endif
+
+#ifndef BR_TARGETS_X86_UP
+#define BR_TARGETS_X86_UP
+#endif
+#ifndef BR_TARGETS_X86_DOWN
+#define BR_TARGETS_X86_DOWN
+#endif
+
+#if BR_GCC || BR_CLANG
+BR_TARGETS_X86_UP
+#include <x86intrin.h>
+#include <cpuid.h>
+#define br_bswap32 __builtin_bswap32
+BR_TARGETS_X86_DOWN
+#endif
+
+#if BR_MSC
+#include <stdlib.h>
+#include <intrin.h>
+#include <immintrin.h>
+#define br_bswap32 _byteswap_ulong
+#endif
+
+static inline int
+br_cpuid(uint32_t mask_eax, uint32_t mask_ebx,
+ uint32_t mask_ecx, uint32_t mask_edx)
+{
+#if BR_GCC || BR_CLANG
+ unsigned eax, ebx, ecx, edx;
+
+ if (__get_cpuid(1, &eax, &ebx, &ecx, &edx)) {
+ if ((eax & mask_eax) == mask_eax
+ && (ebx & mask_ebx) == mask_ebx
+ && (ecx & mask_ecx) == mask_ecx
+ && (edx & mask_edx) == mask_edx)
+ {
+ return 1;
+ }
+ }
+#elif BR_MSC
+ int info[4];
+
+ __cpuid(info, 1);
+ if (((uint32_t)info[0] & mask_eax) == mask_eax
+ && ((uint32_t)info[1] & mask_ebx) == mask_ebx
+ && ((uint32_t)info[2] & mask_ecx) == mask_ecx
+ && ((uint32_t)info[3] & mask_edx) == mask_edx)
+ {
+ return 1;
+ }
+#endif
+ return 0;
+}
+
+#endif
+
+#endif
+
+/* ==================================================================== */
+
+#endif
diff --git a/contrib/bearssl/src/int/i15_add.c b/contrib/bearssl/src/int/i15_add.c
new file mode 100644
index 000000000000..97e29b825f54
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_add.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+uint32_t
+br_i15_add(uint16_t *a, const uint16_t *b, uint32_t ctl)
+{
+ uint32_t cc;
+ size_t u, m;
+
+ cc = 0;
+ m = (a[0] + 31) >> 4;
+ for (u = 1; u < m; u ++) {
+ uint32_t aw, bw, naw;
+
+ aw = a[u];
+ bw = b[u];
+ naw = aw + bw + cc;
+ cc = naw >> 15;
+ a[u] = MUX(ctl, naw & 0x7FFF, aw);
+ }
+ return cc;
+}
diff --git a/contrib/bearssl/src/int/i15_bitlen.c b/contrib/bearssl/src/int/i15_bitlen.c
new file mode 100644
index 000000000000..ad74467182a1
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_bitlen.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+uint32_t
+br_i15_bit_length(uint16_t *x, size_t xlen)
+{
+ uint32_t tw, twk;
+
+ tw = 0;
+ twk = 0;
+ while (xlen -- > 0) {
+ uint32_t w, c;
+
+ c = EQ(tw, 0);
+ w = x[xlen];
+ tw = MUX(c, w, tw);
+ twk = MUX(c, (uint32_t)xlen, twk);
+ }
+ return (twk << 4) + BIT_LENGTH(tw);
+}
diff --git a/contrib/bearssl/src/int/i15_decmod.c b/contrib/bearssl/src/int/i15_decmod.c
new file mode 100644
index 000000000000..6076c57b5b7e
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_decmod.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+uint32_t
+br_i15_decode_mod(uint16_t *x, const void *src, size_t len, const uint16_t *m)
+{
+ /*
+ * Two-pass algorithm: in the first pass, we determine whether the
+ * value fits; in the second pass, we do the actual write.
+ *
+ * During the first pass, 'r' contains the comparison result so
+ * far:
+ * 0x00000000 value is equal to the modulus
+ * 0x00000001 value is greater than the modulus
+ * 0xFFFFFFFF value is lower than the modulus
+ *
+ * Since we iterate starting with the least significant bytes (at
+ * the end of src[]), each new comparison overrides the previous
+ * except when the comparison yields 0 (equal).
+ *
+ * During the second pass, 'r' is either 0xFFFFFFFF (value fits)
+ * or 0x00000000 (value does not fit).
+ *
+ * We must iterate over all bytes of the source, _and_ possibly
+ * some extra virtual bytes (with value 0) so as to cover the
+ * complete modulus as well. We also add 4 such extra bytes beyond
+ * the modulus length because it then guarantees that no accumulated
+ * partial word remains to be processed.
+ */
+ const unsigned char *buf;
+ size_t mlen, tlen;
+ int pass;
+ uint32_t r;
+
+ buf = src;
+ mlen = (m[0] + 15) >> 4;
+ tlen = (mlen << 1);
+ if (tlen < len) {
+ tlen = len;
+ }
+ tlen += 4;
+ r = 0;
+ for (pass = 0; pass < 2; pass ++) {
+ size_t u, v;
+ uint32_t acc;
+ int acc_len;
+
+ v = 1;
+ acc = 0;
+ acc_len = 0;
+ for (u = 0; u < tlen; u ++) {
+ uint32_t b;
+
+ if (u < len) {
+ b = buf[len - 1 - u];
+ } else {
+ b = 0;
+ }
+ acc |= (b << acc_len);
+ acc_len += 8;
+ if (acc_len >= 15) {
+ uint32_t xw;
+
+ xw = acc & (uint32_t)0x7FFF;
+ acc_len -= 15;
+ acc = b >> (8 - acc_len);
+ if (v <= mlen) {
+ if (pass) {
+ x[v] = r & xw;
+ } else {
+ uint32_t cc;
+
+ cc = (uint32_t)CMP(xw, m[v]);
+ r = MUX(EQ(cc, 0), r, cc);
+ }
+ } else {
+ if (!pass) {
+ r = MUX(EQ(xw, 0), r, 1);
+ }
+ }
+ v ++;
+ }
+ }
+
+ /*
+ * When we reach this point at the end of the first pass:
+ * r is either 0, 1 or -1; we want to set r to 0 if it
+ * is equal to 0 or 1, and leave it to -1 otherwise.
+ *
+ * When we reach this point at the end of the second pass:
+ * r is either 0 or -1; we want to leave that value
+ * untouched. This is a subcase of the previous.
+ */
+ r >>= 1;
+ r |= (r << 1);
+ }
+
+ x[0] = m[0];
+ return r & (uint32_t)1;
+}
diff --git a/contrib/bearssl/src/int/i15_decode.c b/contrib/bearssl/src/int/i15_decode.c
new file mode 100644
index 000000000000..fc2c0be0d0be
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_decode.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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_i15_decode(uint16_t *x, const void *src, size_t len)
+{
+ const unsigned char *buf;
+ size_t v;
+ uint32_t acc;
+ int acc_len;
+
+ buf = src;
+ v = 1;
+ acc = 0;
+ acc_len = 0;
+ while (len -- > 0) {
+ uint32_t b;
+
+ b = buf[len];
+ acc |= (b << acc_len);
+ acc_len += 8;
+ if (acc_len >= 15) {
+ x[v ++] = acc & 0x7FFF;
+ acc_len -= 15;
+ acc >>= 15;
+ }
+ }
+ if (acc_len != 0) {
+ x[v ++] = acc;
+ }
+ x[0] = br_i15_bit_length(x + 1, v - 1);
+}
diff --git a/contrib/bearssl/src/int/i15_decred.c b/contrib/bearssl/src/int/i15_decred.c
new file mode 100644
index 000000000000..81e7dd1bd7e9
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_decred.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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_i15_decode_reduce(uint16_t *x,
+ const void *src, size_t len, const uint16_t *m)
+{
+ uint32_t m_ebitlen, m_rbitlen;
+ size_t mblen, k;
+ const unsigned char *buf;
+ uint32_t acc;
+ int acc_len;
+
+ /*
+ * Get the encoded bit length.
+ */
+ m_ebitlen = m[0];
+
+ /*
+ * Special case for an invalid (null) modulus.
+ */
+ if (m_ebitlen == 0) {
+ x[0] = 0;
+ return;
+ }
+
+ /*
+ * Clear the destination.
+ */
+ br_i15_zero(x, m_ebitlen);
+
+ /*
+ * First decode directly as many bytes as possible. This requires
+ * computing the actual bit length.
+ */
+ m_rbitlen = m_ebitlen >> 4;
+ m_rbitlen = (m_ebitlen & 15) + (m_rbitlen << 4) - m_rbitlen;
+ mblen = (m_rbitlen + 7) >> 3;
+ k = mblen - 1;
+ if (k >= len) {
+ br_i15_decode(x, src, len);
+ x[0] = m_ebitlen;
+ return;
+ }
+ buf = src;
+ br_i15_decode(x, buf, k);
+ x[0] = m_ebitlen;
+
+ /*
+ * Input remaining bytes, using 15-bit words.
+ */
+ acc = 0;
+ acc_len = 0;
+ while (k < len) {
+ uint32_t v;
+
+ v = buf[k ++];
+ acc = (acc << 8) | v;
+ acc_len += 8;
+ if (acc_len >= 15) {
+ br_i15_muladd_small(x, acc >> (acc_len - 15), m);
+ acc_len -= 15;
+ acc &= ~((uint32_t)-1 << acc_len);
+ }
+ }
+
+ /*
+ * We may have some bits accumulated. We then perform a shift to
+ * be able to inject these bits as a full 15-bit word.
+ */
+ if (acc_len != 0) {
+ acc = (acc | (x[1] << acc_len)) & 0x7FFF;
+ br_i15_rshift(x, 15 - acc_len);
+ br_i15_muladd_small(x, acc, m);
+ }
+}
diff --git a/contrib/bearssl/src/int/i15_encode.c b/contrib/bearssl/src/int/i15_encode.c
new file mode 100644
index 000000000000..50668f47bc74
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_encode.c
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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_i15_encode(void *dst, size_t len, const uint16_t *x)
+{
+ unsigned char *buf;
+ size_t u, xlen;
+ uint32_t acc;
+ int acc_len;
+
+ xlen = (x[0] + 15) >> 4;
+ if (xlen == 0) {
+ memset(dst, 0, len);
+ return;
+ }
+ u = 1;
+ acc = 0;
+ acc_len = 0;
+ buf = dst;
+ while (len -- > 0) {
+ if (acc_len < 8) {
+ if (u <= xlen) {
+ acc += (uint32_t)x[u ++] << acc_len;
+ }
+ acc_len += 15;
+ }
+ buf[len] = (unsigned char)acc;
+ acc >>= 8;
+ acc_len -= 8;
+ }
+}
diff --git a/contrib/bearssl/src/int/i15_fmont.c b/contrib/bearssl/src/int/i15_fmont.c
new file mode 100644
index 000000000000..3450b7237bc4
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_fmont.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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_i15_from_monty(uint16_t *x, const uint16_t *m, uint16_t m0i)
+{
+ size_t len, u, v;
+
+ len = (m[0] + 15) >> 4;
+ for (u = 0; u < len; u ++) {
+ uint32_t f, cc;
+
+ f = MUL15(x[1], m0i) & 0x7FFF;
+ cc = 0;
+ for (v = 0; v < len; v ++) {
+ uint32_t z;
+
+ z = (uint32_t)x[v + 1] + MUL15(f, m[v + 1]) + cc;
+ cc = z >> 15;
+ if (v != 0) {
+ x[v] = z & 0x7FFF;
+ }
+ }
+ x[len] = cc;
+ }
+
+ /*
+ * We may have to do an extra subtraction, but only if the
+ * value in x[] is indeed greater than or equal to that of m[],
+ * which is why we must do two calls (first call computes the
+ * carry, second call performs the subtraction only if the carry
+ * is 0).
+ */
+ br_i15_sub(x, m, NOT(br_i15_sub(x, m, 0)));
+}
diff --git a/contrib/bearssl/src/int/i15_iszero.c b/contrib/bearssl/src/int/i15_iszero.c
new file mode 100644
index 000000000000..d4b6f10b2ac0
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_iszero.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+uint32_t
+br_i15_iszero(const uint16_t *x)
+{
+ uint32_t z;
+ size_t u;
+
+ z = 0;
+ for (u = (x[0] + 15) >> 4; u > 0; u --) {
+ z |= x[u];
+ }
+ return ~(z | -z) >> 31;
+}
diff --git a/contrib/bearssl/src/int/i15_moddiv.c b/contrib/bearssl/src/int/i15_moddiv.c
new file mode 100644
index 000000000000..45af756d3460
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_moddiv.c
@@ -0,0 +1,465 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * In this file, we handle big integers with a custom format, i.e.
+ * without the usual one-word header. Value is split into 15-bit words,
+ * each stored in a 16-bit slot (top bit is zero) in little-endian
+ * order. The length (in words) is provided explicitly. In some cases,
+ * the value can be negative (using two's complement representation). In
+ * some cases, the top word is allowed to have a 16th bit.
+ */
+
+/*
+ * Negate big integer conditionally. The value consists of 'len' words,
+ * with 15 bits in each word (the top bit of each word should be 0,
+ * except possibly for the last word). If 'ctl' is 1, the negation is
+ * computed; otherwise, if 'ctl' is 0, then the value is unchanged.
+ */
+static void
+cond_negate(uint16_t *a, size_t len, uint32_t ctl)
+{
+ size_t k;
+ uint32_t cc, xm;
+
+ cc = ctl;
+ xm = 0x7FFF & -ctl;
+ for (k = 0; k < len; k ++) {
+ uint32_t aw;
+
+ aw = a[k];
+ aw = (aw ^ xm) + cc;
+ a[k] = aw & 0x7FFF;
+ cc = (aw >> 15) & 1;
+ }
+}
+
+/*
+ * Finish modular reduction. Rules on input parameters:
+ *
+ * if neg = 1, then -m <= a < 0
+ * if neg = 0, then 0 <= a < 2*m
+ *
+ * If neg = 0, then the top word of a[] may use 16 bits.
+ *
+ * Also, modulus m must be odd.
+ */
+static void
+finish_mod(uint16_t *a, size_t len, const uint16_t *m, uint32_t neg)
+{
+ size_t k;
+ uint32_t cc, xm, ym;
+
+ /*
+ * First pass: compare a (assumed nonnegative) with m.
+ */
+ cc = 0;
+ for (k = 0; k < len; k ++) {
+ uint32_t aw, mw;
+
+ aw = a[k];
+ mw = m[k];
+ cc = (aw - mw - cc) >> 31;
+ }
+
+ /*
+ * At this point:
+ * if neg = 1, then we must add m (regardless of cc)
+ * if neg = 0 and cc = 0, then we must subtract m
+ * if neg = 0 and cc = 1, then we must do nothing
+ */
+ xm = 0x7FFF & -neg;
+ ym = -(neg | (1 - cc));
+ cc = neg;
+ for (k = 0; k < len; k ++) {
+ uint32_t aw, mw;
+
+ aw = a[k];
+ mw = (m[k] ^ xm) & ym;
+ aw = aw - mw - cc;
+ a[k] = aw & 0x7FFF;
+ cc = aw >> 31;
+ }
+}
+
+/*
+ * Compute:
+ * a <- (a*pa+b*pb)/(2^15)
+ * b <- (a*qa+b*qb)/(2^15)
+ * The division is assumed to be exact (i.e. the low word is dropped).
+ * If the final a is negative, then it is negated. Similarly for b.
+ * Returned value is the combination of two bits:
+ * bit 0: 1 if a had to be negated, 0 otherwise
+ * bit 1: 1 if b had to be negated, 0 otherwise
+ *
+ * Factors pa, pb, qa and qb must be at most 2^15 in absolute value.
+ * Source integers a and b must be nonnegative; top word is not allowed
+ * to contain an extra 16th bit.
+ */
+static uint32_t
+co_reduce(uint16_t *a, uint16_t *b, size_t len,
+ int32_t pa, int32_t pb, int32_t qa, int32_t qb)
+{
+ size_t k;
+ int32_t cca, ccb;
+ uint32_t nega, negb;
+
+ cca = 0;
+ ccb = 0;
+ for (k = 0; k < len; k ++) {
+ uint32_t wa, wb, za, zb;
+ uint16_t tta, ttb;
+
+ /*
+ * Since:
+ * |pa| <= 2^15
+ * |pb| <= 2^15
+ * 0 <= wa <= 2^15 - 1
+ * 0 <= wb <= 2^15 - 1
+ * |cca| <= 2^16 - 1
+ * Then:
+ * |za| <= (2^15-1)*(2^16) + (2^16-1) = 2^31 - 1
+ *
+ * Thus, the new value of cca is such that |cca| <= 2^16 - 1.
+ * The same applies to ccb.
+ */
+ wa = a[k];
+ wb = b[k];
+ za = wa * (uint32_t)pa + wb * (uint32_t)pb + (uint32_t)cca;
+ zb = wa * (uint32_t)qa + wb * (uint32_t)qb + (uint32_t)ccb;
+ if (k > 0) {
+ a[k - 1] = za & 0x7FFF;
+ b[k - 1] = zb & 0x7FFF;
+ }
+ tta = za >> 15;
+ ttb = zb >> 15;
+ cca = *(int16_t *)&tta;
+ ccb = *(int16_t *)&ttb;
+ }
+ a[len - 1] = (uint16_t)cca;
+ b[len - 1] = (uint16_t)ccb;
+ nega = (uint32_t)cca >> 31;
+ negb = (uint32_t)ccb >> 31;
+ cond_negate(a, len, nega);
+ cond_negate(b, len, negb);
+ return nega | (negb << 1);
+}
+
+/*
+ * Compute:
+ * a <- (a*pa+b*pb)/(2^15) mod m
+ * b <- (a*qa+b*qb)/(2^15) mod m
+ *
+ * m0i is equal to -1/m[0] mod 2^15.
+ *
+ * Factors pa, pb, qa and qb must be at most 2^15 in absolute value.
+ * Source integers a and b must be nonnegative; top word is not allowed
+ * to contain an extra 16th bit.
+ */
+static void
+co_reduce_mod(uint16_t *a, uint16_t *b, size_t len,
+ int32_t pa, int32_t pb, int32_t qa, int32_t qb,
+ const uint16_t *m, uint16_t m0i)
+{
+ size_t k;
+ int32_t cca, ccb, fa, fb;
+
+ cca = 0;
+ ccb = 0;
+ fa = ((a[0] * (uint32_t)pa + b[0] * (uint32_t)pb) * m0i) & 0x7FFF;
+ fb = ((a[0] * (uint32_t)qa + b[0] * (uint32_t)qb) * m0i) & 0x7FFF;
+ for (k = 0; k < len; k ++) {
+ uint32_t wa, wb, za, zb;
+ uint32_t tta, ttb;
+
+ /*
+ * In this loop, carries 'cca' and 'ccb' always fit on
+ * 17 bits (in absolute value).
+ */
+ wa = a[k];
+ wb = b[k];
+ za = wa * (uint32_t)pa + wb * (uint32_t)pb
+ + m[k] * (uint32_t)fa + (uint32_t)cca;
+ zb = wa * (uint32_t)qa + wb * (uint32_t)qb
+ + m[k] * (uint32_t)fb + (uint32_t)ccb;
+ if (k > 0) {
+ a[k - 1] = za & 0x7FFF;
+ b[k - 1] = zb & 0x7FFF;
+ }
+
+ /*
+ * The XOR-and-sub construction below does an arithmetic
+ * right shift in a portable way (technically, right-shifting
+ * a negative signed value is implementation-defined in C).
+ */
+#define M ((uint32_t)1 << 16)
+ tta = za >> 15;
+ ttb = zb >> 15;
+ tta = (tta ^ M) - M;
+ ttb = (ttb ^ M) - M;
+ cca = *(int32_t *)&tta;
+ ccb = *(int32_t *)&ttb;
+#undef M
+ }
+ a[len - 1] = (uint32_t)cca;
+ b[len - 1] = (uint32_t)ccb;
+
+ /*
+ * At this point:
+ * -m <= a < 2*m
+ * -m <= b < 2*m
+ * (this is a case of Montgomery reduction)
+ * The top word of 'a' and 'b' may have a 16-th bit set.
+ * We may have to add or subtract the modulus.
+ */
+ finish_mod(a, len, m, (uint32_t)cca >> 31);
+ finish_mod(b, len, m, (uint32_t)ccb >> 31);
+}
+
+/* see inner.h */
+uint32_t
+br_i15_moddiv(uint16_t *x, const uint16_t *y, const uint16_t *m, uint16_t m0i,
+ uint16_t *t)
+{
+ /*
+ * Algorithm is an extended binary GCD. We maintain four values
+ * a, b, u and v, with the following invariants:
+ *
+ * a * x = y * u mod m
+ * b * x = y * v mod m
+ *
+ * Starting values are:
+ *
+ * a = y
+ * b = m
+ * u = x
+ * v = 0
+ *
+ * The formal definition of the algorithm is a sequence of steps:
+ *
+ * - If a is even, then a <- a/2 and u <- u/2 mod m.
+ * - Otherwise, if b is even, then b <- b/2 and v <- v/2 mod m.
+ * - Otherwise, if a > b, then a <- (a-b)/2 and u <- (u-v)/2 mod m.
+ * - Otherwise, b <- (b-a)/2 and v <- (v-u)/2 mod m.
+ *
+ * Algorithm stops when a = b. At that point, they both are equal
+ * to GCD(y,m); the modular division succeeds if that value is 1.
+ * The result of the modular division is then u (or v: both are
+ * equal at that point).
+ *
+ * Each step makes either a or b shrink by at least one bit; hence,
+ * if m has bit length k bits, then 2k-2 steps are sufficient.
+ *
+ *
+ * Though complexity is quadratic in the size of m, the bit-by-bit
+ * processing is not very efficient. We can speed up processing by
+ * remarking that the decisions are taken based only on observation
+ * of the top and low bits of a and b.
+ *
+ * In the loop below, at each iteration, we use the two top words
+ * of a and b, and the low words of a and b, to compute reduction
+ * parameters pa, pb, qa and qb such that the new values for a
+ * and b are:
+ *
+ * a' = (a*pa + b*pb) / (2^15)
+ * b' = (a*qa + b*qb) / (2^15)
+ *
+ * the division being exact.
+ *
+ * Since the choices are based on the top words, they may be slightly
+ * off, requiring an optional correction: if a' < 0, then we replace
+ * pa with -pa, and pb with -pb. The total length of a and b is
+ * thus reduced by at least 14 bits at each iteration.
+ *
+ * The stopping conditions are still the same, though: when a
+ * and b become equal, they must be both odd (since m is odd,
+ * the GCD cannot be even), therefore the next operation is a
+ * subtraction, and one of the values becomes 0. At that point,
+ * nothing else happens, i.e. one value is stuck at 0, and the
+ * other one is the GCD.
+ */
+ size_t len, k;
+ uint16_t *a, *b, *u, *v;
+ uint32_t num, r;
+
+ len = (m[0] + 15) >> 4;
+ a = t;
+ b = a + len;
+ u = x + 1;
+ v = b + len;
+ memcpy(a, y + 1, len * sizeof *y);
+ memcpy(b, m + 1, len * sizeof *m);
+ memset(v, 0, len * sizeof *v);
+
+ /*
+ * Loop below ensures that a and b are reduced by some bits each,
+ * for a total of at least 14 bits.
+ */
+ for (num = ((m[0] - (m[0] >> 4)) << 1) + 14; num >= 14; num -= 14) {
+ size_t j;
+ uint32_t c0, c1;
+ uint32_t a0, a1, b0, b1;
+ uint32_t a_hi, b_hi, a_lo, b_lo;
+ int32_t pa, pb, qa, qb;
+ int i;
+
+ /*
+ * Extract top words of a and b. If j is the highest
+ * index >= 1 such that a[j] != 0 or b[j] != 0, then we want
+ * (a[j] << 15) + a[j - 1], and (b[j] << 15) + b[j - 1].
+ * If a and b are down to one word each, then we use a[0]
+ * and b[0].
+ */
+ c0 = (uint32_t)-1;
+ c1 = (uint32_t)-1;
+ a0 = 0;
+ a1 = 0;
+ b0 = 0;
+ b1 = 0;
+ j = len;
+ while (j -- > 0) {
+ uint32_t aw, bw;
+
+ aw = a[j];
+ bw = b[j];
+ a0 ^= (a0 ^ aw) & c0;
+ a1 ^= (a1 ^ aw) & c1;
+ b0 ^= (b0 ^ bw) & c0;
+ b1 ^= (b1 ^ bw) & c1;
+ c1 = c0;
+ c0 &= (((aw | bw) + 0xFFFF) >> 16) - (uint32_t)1;
+ }
+
+ /*
+ * If c1 = 0, then we grabbed two words for a and b.
+ * If c1 != 0 but c0 = 0, then we grabbed one word. It
+ * is not possible that c1 != 0 and c0 != 0, because that
+ * would mean that both integers are zero.
+ */
+ a1 |= a0 & c1;
+ a0 &= ~c1;
+ b1 |= b0 & c1;
+ b0 &= ~c1;
+ a_hi = (a0 << 15) + a1;
+ b_hi = (b0 << 15) + b1;
+ a_lo = a[0];
+ b_lo = b[0];
+
+ /*
+ * Compute reduction factors:
+ *
+ * a' = a*pa + b*pb
+ * b' = a*qa + b*qb
+ *
+ * such that a' and b' are both multiple of 2^15, but are
+ * only marginally larger than a and b.
+ */
+ pa = 1;
+ pb = 0;
+ qa = 0;
+ qb = 1;
+ for (i = 0; i < 15; i ++) {
+ /*
+ * At each iteration:
+ *
+ * a <- (a-b)/2 if: a is odd, b is odd, a_hi > b_hi
+ * b <- (b-a)/2 if: a is odd, b is odd, a_hi <= b_hi
+ * a <- a/2 if: a is even
+ * b <- b/2 if: a is odd, b is even
+ *
+ * We multiply a_lo and b_lo by 2 at each
+ * iteration, thus a division by 2 really is a
+ * non-multiplication by 2.
+ */
+ uint32_t r, oa, ob, cAB, cBA, cA;
+
+ /*
+ * cAB = 1 if b must be subtracted from a
+ * cBA = 1 if a must be subtracted from b
+ * cA = 1 if a is divided by 2, 0 otherwise
+ *
+ * Rules:
+ *
+ * cAB and cBA cannot be both 1.
+ * if a is not divided by 2, b is.
+ */
+ r = GT(a_hi, b_hi);
+ oa = (a_lo >> i) & 1;
+ ob = (b_lo >> i) & 1;
+ cAB = oa & ob & r;
+ cBA = oa & ob & NOT(r);
+ cA = cAB | NOT(oa);
+
+ /*
+ * Conditional subtractions.
+ */
+ a_lo -= b_lo & -cAB;
+ a_hi -= b_hi & -cAB;
+ pa -= qa & -(int32_t)cAB;
+ pb -= qb & -(int32_t)cAB;
+ b_lo -= a_lo & -cBA;
+ b_hi -= a_hi & -cBA;
+ qa -= pa & -(int32_t)cBA;
+ qb -= pb & -(int32_t)cBA;
+
+ /*
+ * Shifting.
+ */
+ a_lo += a_lo & (cA - 1);
+ pa += pa & ((int32_t)cA - 1);
+ pb += pb & ((int32_t)cA - 1);
+ a_hi ^= (a_hi ^ (a_hi >> 1)) & -cA;
+ b_lo += b_lo & -cA;
+ qa += qa & -(int32_t)cA;
+ qb += qb & -(int32_t)cA;
+ b_hi ^= (b_hi ^ (b_hi >> 1)) & (cA - 1);
+ }
+
+ /*
+ * Replace a and b with new values a' and b'.
+ */
+ r = co_reduce(a, b, len, pa, pb, qa, qb);
+ pa -= pa * ((r & 1) << 1);
+ pb -= pb * ((r & 1) << 1);
+ qa -= qa * (r & 2);
+ qb -= qb * (r & 2);
+ co_reduce_mod(u, v, len, pa, pb, qa, qb, m + 1, m0i);
+ }
+
+ /*
+ * Now one of the arrays should be 0, and the other contains
+ * the GCD. If a is 0, then u is 0 as well, and v contains
+ * the division result.
+ * Result is correct if and only if GCD is 1.
+ */
+ r = (a[0] | b[0]) ^ 1;
+ u[0] |= v[0];
+ for (k = 1; k < len; k ++) {
+ r |= a[k] | b[k];
+ u[k] |= v[k];
+ }
+ return EQ0(r);
+}
diff --git a/contrib/bearssl/src/int/i15_modpow.c b/contrib/bearssl/src/int/i15_modpow.c
new file mode 100644
index 000000000000..9bf304e50ad1
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_modpow.c
@@ -0,0 +1,50 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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_i15_modpow(uint16_t *x,
+ const unsigned char *e, size_t elen,
+ const uint16_t *m, uint16_t m0i, uint16_t *t1, uint16_t *t2)
+{
+ size_t mlen;
+ unsigned k;
+
+ mlen = ((m[0] + 31) >> 4) * sizeof m[0];
+ memcpy(t1, x, mlen);
+ br_i15_to_monty(t1, m);
+ br_i15_zero(x, m[0]);
+ x[1] = 1;
+ for (k = 0; k < ((unsigned)elen << 3); k ++) {
+ uint32_t ctl;
+
+ ctl = (e[elen - 1 - (k >> 3)] >> (k & 7)) & 1;
+ br_i15_montymul(t2, x, t1, m, m0i);
+ CCOPY(ctl, x, t2, mlen);
+ br_i15_montymul(t2, t1, t1, m, m0i);
+ memcpy(t1, t2, mlen);
+ }
+}
diff --git a/contrib/bearssl/src/int/i15_modpow2.c b/contrib/bearssl/src/int/i15_modpow2.c
new file mode 100644
index 000000000000..4b3211864c5b
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_modpow2.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+uint32_t
+br_i15_modpow_opt(uint16_t *x,
+ const unsigned char *e, size_t elen,
+ const uint16_t *m, uint16_t m0i, uint16_t *tmp, size_t twlen)
+{
+ size_t mlen, mwlen;
+ uint16_t *t1, *t2, *base;
+ size_t u, v;
+ uint32_t acc;
+ int acc_len, win_len;
+
+ /*
+ * Get modulus size.
+ */
+ mwlen = (m[0] + 31) >> 4;
+ mlen = mwlen * sizeof m[0];
+ mwlen += (mwlen & 1);
+ t1 = tmp;
+ t2 = tmp + mwlen;
+
+ /*
+ * Compute possible window size, with a maximum of 5 bits.
+ * When the window has size 1 bit, we use a specific code
+ * that requires only two temporaries. Otherwise, for a
+ * window of k bits, we need 2^k+1 temporaries.
+ */
+ if (twlen < (mwlen << 1)) {
+ return 0;
+ }
+ for (win_len = 5; win_len > 1; win_len --) {
+ if ((((uint32_t)1 << win_len) + 1) * mwlen <= twlen) {
+ break;
+ }
+ }
+
+ /*
+ * Everything is done in Montgomery representation.
+ */
+ br_i15_to_monty(x, m);
+
+ /*
+ * Compute window contents. If the window has size one bit only,
+ * then t2 is set to x; otherwise, t2[0] is left untouched, and
+ * t2[k] is set to x^k (for k >= 1).
+ */
+ if (win_len == 1) {
+ memcpy(t2, x, mlen);
+ } else {
+ memcpy(t2 + mwlen, x, mlen);
+ base = t2 + mwlen;
+ for (u = 2; u < ((unsigned)1 << win_len); u ++) {
+ br_i15_montymul(base + mwlen, base, x, m, m0i);
+ base += mwlen;
+ }
+ }
+
+ /*
+ * We need to set x to 1, in Montgomery representation. This can
+ * be done efficiently by setting the high word to 1, then doing
+ * one word-sized shift.
+ */
+ br_i15_zero(x, m[0]);
+ x[(m[0] + 15) >> 4] = 1;
+ br_i15_muladd_small(x, 0, m);
+
+ /*
+ * We process bits from most to least significant. At each
+ * loop iteration, we have acc_len bits in acc.
+ */
+ acc = 0;
+ acc_len = 0;
+ while (acc_len > 0 || elen > 0) {
+ int i, k;
+ uint32_t bits;
+
+ /*
+ * Get the next bits.
+ */
+ k = win_len;
+ if (acc_len < win_len) {
+ if (elen > 0) {
+ acc = (acc << 8) | *e ++;
+ elen --;
+ acc_len += 8;
+ } else {
+ k = acc_len;
+ }
+ }
+ bits = (acc >> (acc_len - k)) & (((uint32_t)1 << k) - 1);
+ acc_len -= k;
+
+ /*
+ * We could get exactly k bits. Compute k squarings.
+ */
+ for (i = 0; i < k; i ++) {
+ br_i15_montymul(t1, x, x, m, m0i);
+ memcpy(x, t1, mlen);
+ }
+
+ /*
+ * Window lookup: we want to set t2 to the window
+ * lookup value, assuming the bits are non-zero. If
+ * the window length is 1 bit only, then t2 is
+ * already set; otherwise, we do a constant-time lookup.
+ */
+ if (win_len > 1) {
+ br_i15_zero(t2, m[0]);
+ base = t2 + mwlen;
+ for (u = 1; u < ((uint32_t)1 << k); u ++) {
+ uint32_t mask;
+
+ mask = -EQ(u, bits);
+ for (v = 1; v < mwlen; v ++) {
+ t2[v] |= mask & base[v];
+ }
+ base += mwlen;
+ }
+ }
+
+ /*
+ * Multiply with the looked-up value. We keep the
+ * product only if the exponent bits are not all-zero.
+ */
+ br_i15_montymul(t1, x, t2, m, m0i);
+ CCOPY(NEQ(bits, 0), x, t1, mlen);
+ }
+
+ /*
+ * Convert back from Montgomery representation, and exit.
+ */
+ br_i15_from_monty(x, m, m0i);
+ return 1;
+}
diff --git a/contrib/bearssl/src/int/i15_montmul.c b/contrib/bearssl/src/int/i15_montmul.c
new file mode 100644
index 000000000000..e98bc32c42eb
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_montmul.c
@@ -0,0 +1,184 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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_i15_montymul(uint16_t *d, const uint16_t *x, const uint16_t *y,
+ const uint16_t *m, uint16_t m0i)
+{
+ size_t len, len4, u, v;
+ uint32_t dh;
+
+ len = (m[0] + 15) >> 4;
+ len4 = len & ~(size_t)3;
+ br_i15_zero(d, m[0]);
+ dh = 0;
+ for (u = 0; u < len; u ++) {
+ uint32_t f, xu, r, zh;
+
+ xu = x[u + 1];
+ f = MUL15((d[1] + MUL15(x[u + 1], y[1])) & 0x7FFF, m0i)
+ & 0x7FFF;
+#if BR_ARMEL_CORTEXM_GCC
+ if (len4 != 0) {
+ uint16_t *limit;
+
+ limit = d + len4;
+ asm volatile (
+"\n\
+ @ carry: r=r2 \n\
+ @ multipliers: xu=r3 f=r4 \n\
+ @ base registers: d+v=r5 y+v=r6 m+v=r7 \n\
+ @ r8 contains 0x7FFF \n\
+ @ r9 contains d+len4 \n\
+ ldr r0, %[limit] \n\
+ ldr r3, %[xu] \n\
+ mov r9, r0 \n\
+ ldr r4, %[f] \n\
+ eor r2, r2 \n\
+ ldr r5, %[d] \n\
+ sub r1, r2, #1 \n\
+ ldr r6, %[y] \n\
+ lsr r1, r1, #17 \n\
+ ldr r7, %[m] \n\
+ mov r8, r1 \n\
+loop%=: \n\
+ ldrh r0, [r6, #2] \n\
+ ldrh r1, [r7, #2] \n\
+ mul r0, r3 \n\
+ mul r1, r4 \n\
+ add r2, r0, r2 \n\
+ ldrh r0, [r5, #2] \n\
+ add r2, r1, r2 \n\
+ mov r1, r8 \n\
+ add r2, r0, r2 \n\
+ and r1, r2 \n\
+ lsr r2, r2, #15 \n\
+ strh r1, [r5, #0] \n\
+ \n\
+ ldrh r0, [r6, #4] \n\
+ ldrh r1, [r7, #4] \n\
+ mul r0, r3 \n\
+ mul r1, r4 \n\
+ add r2, r0, r2 \n\
+ ldrh r0, [r5, #4] \n\
+ add r2, r1, r2 \n\
+ mov r1, r8 \n\
+ add r2, r0, r2 \n\
+ and r1, r2 \n\
+ lsr r2, r2, #15 \n\
+ strh r1, [r5, #2] \n\
+ \n\
+ ldrh r0, [r6, #6] \n\
+ ldrh r1, [r7, #6] \n\
+ mul r0, r3 \n\
+ mul r1, r4 \n\
+ add r2, r0, r2 \n\
+ ldrh r0, [r5, #6] \n\
+ add r2, r1, r2 \n\
+ mov r1, r8 \n\
+ add r2, r0, r2 \n\
+ and r1, r2 \n\
+ lsr r2, r2, #15 \n\
+ strh r1, [r5, #4] \n\
+ \n\
+ ldrh r0, [r6, #8] \n\
+ ldrh r1, [r7, #8] \n\
+ mul r0, r3 \n\
+ mul r1, r4 \n\
+ add r2, r0, r2 \n\
+ ldrh r0, [r5, #8] \n\
+ add r2, r1, r2 \n\
+ mov r1, r8 \n\
+ add r2, r0, r2 \n\
+ and r1, r2 \n\
+ lsr r2, r2, #15 \n\
+ strh r1, [r5, #6] \n\
+ \n\
+ add r5, r5, #8 \n\
+ add r6, r6, #8 \n\
+ add r7, r7, #8 \n\
+ cmp r5, r9 \n\
+ bne loop%= \n\
+ \n\
+ str r2, %[carry] \n\
+"
+: [carry] "=m" (r)
+: [xu] "m" (xu), [f] "m" (f), [d] "m" (d), [y] "m" (y),
+ [m] "m" (m), [limit] "m" (limit)
+: "r0", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9" );
+ } else {
+ r = 0;
+ }
+ v = len4;
+#else
+ r = 0;
+ for (v = 0; v < len4; v += 4) {
+ uint32_t z;
+
+ z = d[v + 1] + MUL15(xu, y[v + 1])
+ + MUL15(f, m[v + 1]) + r;
+ r = z >> 15;
+ d[v + 0] = z & 0x7FFF;
+ z = d[v + 2] + MUL15(xu, y[v + 2])
+ + MUL15(f, m[v + 2]) + r;
+ r = z >> 15;
+ d[v + 1] = z & 0x7FFF;
+ z = d[v + 3] + MUL15(xu, y[v + 3])
+ + MUL15(f, m[v + 3]) + r;
+ r = z >> 15;
+ d[v + 2] = z & 0x7FFF;
+ z = d[v + 4] + MUL15(xu, y[v + 4])
+ + MUL15(f, m[v + 4]) + r;
+ r = z >> 15;
+ d[v + 3] = z & 0x7FFF;
+ }
+#endif
+ for (; v < len; v ++) {
+ uint32_t z;
+
+ z = d[v + 1] + MUL15(xu, y[v + 1])
+ + MUL15(f, m[v + 1]) + r;
+ r = z >> 15;
+ d[v + 0] = z & 0x7FFF;
+ }
+
+ zh = dh + r;
+ d[len] = zh & 0x7FFF;
+ dh = zh >> 15;
+ }
+
+ /*
+ * Restore the bit length (it was overwritten in the loop above).
+ */
+ d[0] = m[0];
+
+ /*
+ * d[] may be greater than m[], but it is still lower than twice
+ * the modulus.
+ */
+ br_i15_sub(d, m, NEQ(dh, 0) | NOT(br_i15_sub(d, m, 0)));
+}
diff --git a/contrib/bearssl/src/int/i15_mulacc.c b/contrib/bearssl/src/int/i15_mulacc.c
new file mode 100644
index 000000000000..7a073ac67f95
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_mulacc.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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_i15_mulacc(uint16_t *d, const uint16_t *a, const uint16_t *b)
+{
+ size_t alen, blen, u;
+ unsigned dl, dh;
+
+ alen = (a[0] + 15) >> 4;
+ blen = (b[0] + 15) >> 4;
+
+ /*
+ * Announced bit length of d[] will be the sum of the announced
+ * bit lengths of a[] and b[]; but the lengths are encoded.
+ */
+ dl = (a[0] & 15) + (b[0] & 15);
+ dh = (a[0] >> 4) + (b[0] >> 4);
+ d[0] = (dh << 4) + dl + (~(uint32_t)(dl - 15) >> 31);
+
+ for (u = 0; u < blen; u ++) {
+ uint32_t f;
+ size_t v;
+ uint32_t cc;
+
+ f = b[1 + u];
+ cc = 0;
+ for (v = 0; v < alen; v ++) {
+ uint32_t z;
+
+ z = (uint32_t)d[1 + u + v] + MUL15(f, a[1 + v]) + cc;
+ cc = z >> 15;
+ d[1 + u + v] = z & 0x7FFF;
+ }
+ d[1 + u + alen] = cc;
+ }
+}
diff --git a/contrib/bearssl/src/int/i15_muladd.c b/contrib/bearssl/src/int/i15_muladd.c
new file mode 100644
index 000000000000..c4b72168e8b0
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_muladd.c
@@ -0,0 +1,173 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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"
+
+/*
+ * Constant-time division. The divisor must not be larger than 16 bits,
+ * and the quotient must fit on 17 bits.
+ */
+static uint32_t
+divrem16(uint32_t x, uint32_t d, uint32_t *r)
+{
+ int i;
+ uint32_t q;
+
+ q = 0;
+ d <<= 16;
+ for (i = 16; i >= 0; i --) {
+ uint32_t ctl;
+
+ ctl = LE(d, x);
+ q |= ctl << i;
+ x -= (-ctl) & d;
+ d >>= 1;
+ }
+ if (r != NULL) {
+ *r = x;
+ }
+ return q;
+}
+
+/* see inner.h */
+void
+br_i15_muladd_small(uint16_t *x, uint16_t z, const uint16_t *m)
+{
+ /*
+ * Constant-time: we accept to leak the exact bit length of the
+ * modulus m.
+ */
+ unsigned m_bitlen, mblr;
+ size_t u, mlen;
+ uint32_t hi, a0, a, b, q;
+ uint32_t cc, tb, over, under;
+
+ /*
+ * Simple case: the modulus fits on one word.
+ */
+ m_bitlen = m[0];
+ if (m_bitlen == 0) {
+ return;
+ }
+ if (m_bitlen <= 15) {
+ uint32_t rem;
+
+ divrem16(((uint32_t)x[1] << 15) | z, m[1], &rem);
+ x[1] = rem;
+ return;
+ }
+ mlen = (m_bitlen + 15) >> 4;
+ mblr = m_bitlen & 15;
+
+ /*
+ * Principle: we estimate the quotient (x*2^15+z)/m by
+ * doing a 30/15 division with the high words.
+ *
+ * Let:
+ * w = 2^15
+ * a = (w*a0 + a1) * w^N + a2
+ * b = b0 * w^N + b2
+ * such that:
+ * 0 <= a0 < w
+ * 0 <= a1 < w
+ * 0 <= a2 < w^N
+ * w/2 <= b0 < w
+ * 0 <= b2 < w^N
+ * a < w*b
+ * I.e. the two top words of a are a0:a1, the top word of b is
+ * b0, we ensured that b0 is "full" (high bit set), and a is
+ * such that the quotient q = a/b fits on one word (0 <= q < w).
+ *
+ * If a = b*q + r (with 0 <= r < q), then we can estimate q by
+ * using a division on the top words:
+ * a0*w + a1 = b0*u + v (with 0 <= v < b0)
+ * Then the following holds:
+ * 0 <= u <= w
+ * u-2 <= q <= u
+ */
+ hi = x[mlen];
+ if (mblr == 0) {
+ a0 = x[mlen];
+ memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);
+ x[1] = z;
+ a = (a0 << 15) + x[mlen];
+ b = m[mlen];
+ } else {
+ a0 = (x[mlen] << (15 - mblr)) | (x[mlen - 1] >> mblr);
+ memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);
+ x[1] = z;
+ a = (a0 << 15) | (((x[mlen] << (15 - mblr))
+ | (x[mlen - 1] >> mblr)) & 0x7FFF);
+ b = (m[mlen] << (15 - mblr)) | (m[mlen - 1] >> mblr);
+ }
+ q = divrem16(a, b, NULL);
+
+ /*
+ * We computed an estimate for q, but the real one may be q,
+ * q-1 or q-2; moreover, the division may have returned a value
+ * 8000 or even 8001 if the two high words were identical, and
+ * we want to avoid values beyond 7FFF. We thus adjust q so
+ * that the "true" multiplier will be q+1, q or q-1, and q is
+ * in the 0000..7FFF range.
+ */
+ q = MUX(EQ(b, a0), 0x7FFF, q - 1 + ((q - 1) >> 31));
+
+ /*
+ * We subtract q*m from x (x has an extra high word of value 'hi').
+ * Since q may be off by 1 (in either direction), we may have to
+ * add or subtract m afterwards.
+ *
+ * The 'tb' flag will be true (1) at the end of the loop if the
+ * result is greater than or equal to the modulus (not counting
+ * 'hi' or the carry).
+ */
+ cc = 0;
+ tb = 1;
+ for (u = 1; u <= mlen; u ++) {
+ uint32_t mw, zl, xw, nxw;
+
+ mw = m[u];
+ zl = MUL15(mw, q) + cc;
+ cc = zl >> 15;
+ zl &= 0x7FFF;
+ xw = x[u];
+ nxw = xw - zl;
+ cc += nxw >> 31;
+ nxw &= 0x7FFF;
+ x[u] = nxw;
+ tb = MUX(EQ(nxw, mw), tb, GT(nxw, mw));
+ }
+
+ /*
+ * If we underestimated q, then either cc < hi (one extra bit
+ * beyond the top array word), or cc == hi and tb is true (no
+ * extra bit, but the result is not lower than the modulus).
+ *
+ * If we overestimated q, then cc > hi.
+ */
+ over = GT(cc, hi);
+ under = ~over & (tb | LT(cc, hi));
+ br_i15_add(x, m, over);
+ br_i15_sub(x, m, under);
+}
diff --git a/contrib/bearssl/src/int/i15_ninv15.c b/contrib/bearssl/src/int/i15_ninv15.c
new file mode 100644
index 000000000000..de3a3ba8934b
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_ninv15.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 */
+uint16_t
+br_i15_ninv15(uint16_t x)
+{
+ uint32_t y;
+
+ y = 2 - x;
+ y = MUL15(y, 2 - MUL15(x, y));
+ y = MUL15(y, 2 - MUL15(x, y));
+ y = MUL15(y, 2 - MUL15(x, y));
+ return MUX(x & 1, -y, 0) & 0x7FFF;
+}
diff --git a/contrib/bearssl/src/int/i15_reduce.c b/contrib/bearssl/src/int/i15_reduce.c
new file mode 100644
index 000000000000..0931b10495bb
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_reduce.c
@@ -0,0 +1,66 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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_i15_reduce(uint16_t *x, const uint16_t *a, const uint16_t *m)
+{
+ uint32_t m_bitlen, a_bitlen;
+ size_t mlen, alen, u;
+
+ m_bitlen = m[0];
+ mlen = (m_bitlen + 15) >> 4;
+
+ x[0] = m_bitlen;
+ if (m_bitlen == 0) {
+ return;
+ }
+
+ /*
+ * If the source is shorter, then simply copy all words from a[]
+ * and zero out the upper words.
+ */
+ a_bitlen = a[0];
+ alen = (a_bitlen + 15) >> 4;
+ if (a_bitlen < m_bitlen) {
+ memcpy(x + 1, a + 1, alen * sizeof *a);
+ for (u = alen; u < mlen; u ++) {
+ x[u + 1] = 0;
+ }
+ return;
+ }
+
+ /*
+ * The source length is at least equal to that of the modulus.
+ * We must thus copy N-1 words, and input the remaining words
+ * one by one.
+ */
+ memcpy(x + 1, a + 2 + (alen - mlen), (mlen - 1) * sizeof *a);
+ x[mlen] = 0;
+ for (u = 1 + alen - mlen; u > 0; u --) {
+ br_i15_muladd_small(x, a[u], m);
+ }
+}
diff --git a/contrib/bearssl/src/int/i15_rshift.c b/contrib/bearssl/src/int/i15_rshift.c
new file mode 100644
index 000000000000..f9991ab6f725
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_rshift.c
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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_i15_rshift(uint16_t *x, int count)
+{
+ size_t u, len;
+ unsigned r;
+
+ len = (x[0] + 15) >> 4;
+ if (len == 0) {
+ return;
+ }
+ r = x[1] >> count;
+ for (u = 2; u <= len; u ++) {
+ unsigned w;
+
+ w = x[u];
+ x[u - 1] = ((w << (15 - count)) | r) & 0x7FFF;
+ r = w >> count;
+ }
+ x[len] = r;
+}
diff --git a/contrib/bearssl/src/int/i15_sub.c b/contrib/bearssl/src/int/i15_sub.c
new file mode 100644
index 000000000000..1983c4dcfc89
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_sub.c
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+uint32_t
+br_i15_sub(uint16_t *a, const uint16_t *b, uint32_t ctl)
+{
+ uint32_t cc;
+ size_t u, m;
+
+ cc = 0;
+ m = (a[0] + 31) >> 4;
+ for (u = 1; u < m; u ++) {
+ uint32_t aw, bw, naw;
+
+ aw = a[u];
+ bw = b[u];
+ naw = aw - bw - cc;
+ cc = naw >> 31;
+ a[u] = MUX(ctl, naw & 0x7FFF, aw);
+ }
+ return cc;
+}
diff --git a/contrib/bearssl/src/int/i15_tmont.c b/contrib/bearssl/src/int/i15_tmont.c
new file mode 100644
index 000000000000..d5c4b8b7a053
--- /dev/null
+++ b/contrib/bearssl/src/int/i15_tmont.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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_i15_to_monty(uint16_t *x, const uint16_t *m)
+{
+ unsigned k;
+
+ for (k = (m[0] + 15) >> 4; k > 0; k --) {
+ br_i15_muladd_small(x, 0, m);
+ }
+}
diff --git a/contrib/bearssl/src/int/i31_add.c b/contrib/bearssl/src/int/i31_add.c
new file mode 100644
index 000000000000..2ca47c6b81fb
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_add.c
@@ -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"
+
+/* see inner.h */
+uint32_t
+br_i31_add(uint32_t *a, const uint32_t *b, uint32_t ctl)
+{
+ uint32_t cc;
+ size_t u, m;
+
+ cc = 0;
+ m = (a[0] + 63) >> 5;
+ for (u = 1; u < m; u ++) {
+ uint32_t aw, bw, naw;
+
+ aw = a[u];
+ bw = b[u];
+ naw = aw + bw + cc;
+ cc = naw >> 31;
+ a[u] = MUX(ctl, naw & (uint32_t)0x7FFFFFFF, aw);
+ }
+ return cc;
+}
diff --git a/contrib/bearssl/src/int/i31_bitlen.c b/contrib/bearssl/src/int/i31_bitlen.c
new file mode 100644
index 000000000000..3e127c2c82f9
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_bitlen.c
@@ -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 */
+uint32_t
+br_i31_bit_length(uint32_t *x, size_t xlen)
+{
+ uint32_t tw, twk;
+
+ tw = 0;
+ twk = 0;
+ while (xlen -- > 0) {
+ uint32_t w, c;
+
+ c = EQ(tw, 0);
+ w = x[xlen];
+ tw = MUX(c, w, tw);
+ twk = MUX(c, (uint32_t)xlen, twk);
+ }
+ return (twk << 5) + BIT_LENGTH(tw);
+}
diff --git a/contrib/bearssl/src/int/i31_decmod.c b/contrib/bearssl/src/int/i31_decmod.c
new file mode 100644
index 000000000000..3cd7bfe94b9e
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_decmod.c
@@ -0,0 +1,124 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+uint32_t
+br_i31_decode_mod(uint32_t *x, const void *src, size_t len, const uint32_t *m)
+{
+ /*
+ * Two-pass algorithm: in the first pass, we determine whether the
+ * value fits; in the second pass, we do the actual write.
+ *
+ * During the first pass, 'r' contains the comparison result so
+ * far:
+ * 0x00000000 value is equal to the modulus
+ * 0x00000001 value is greater than the modulus
+ * 0xFFFFFFFF value is lower than the modulus
+ *
+ * Since we iterate starting with the least significant bytes (at
+ * the end of src[]), each new comparison overrides the previous
+ * except when the comparison yields 0 (equal).
+ *
+ * During the second pass, 'r' is either 0xFFFFFFFF (value fits)
+ * or 0x00000000 (value does not fit).
+ *
+ * We must iterate over all bytes of the source, _and_ possibly
+ * some extra virtual bytes (with value 0) so as to cover the
+ * complete modulus as well. We also add 4 such extra bytes beyond
+ * the modulus length because it then guarantees that no accumulated
+ * partial word remains to be processed.
+ */
+ const unsigned char *buf;
+ size_t mlen, tlen;
+ int pass;
+ uint32_t r;
+
+ buf = src;
+ mlen = (m[0] + 31) >> 5;
+ tlen = (mlen << 2);
+ if (tlen < len) {
+ tlen = len;
+ }
+ tlen += 4;
+ r = 0;
+ for (pass = 0; pass < 2; pass ++) {
+ size_t u, v;
+ uint32_t acc;
+ int acc_len;
+
+ v = 1;
+ acc = 0;
+ acc_len = 0;
+ for (u = 0; u < tlen; u ++) {
+ uint32_t b;
+
+ if (u < len) {
+ b = buf[len - 1 - u];
+ } else {
+ b = 0;
+ }
+ acc |= (b << acc_len);
+ acc_len += 8;
+ if (acc_len >= 31) {
+ uint32_t xw;
+
+ xw = acc & (uint32_t)0x7FFFFFFF;
+ acc_len -= 31;
+ acc = b >> (8 - acc_len);
+ if (v <= mlen) {
+ if (pass) {
+ x[v] = r & xw;
+ } else {
+ uint32_t cc;
+
+ cc = (uint32_t)CMP(xw, m[v]);
+ r = MUX(EQ(cc, 0), r, cc);
+ }
+ } else {
+ if (!pass) {
+ r = MUX(EQ(xw, 0), r, 1);
+ }
+ }
+ v ++;
+ }
+ }
+
+ /*
+ * When we reach this point at the end of the first pass:
+ * r is either 0, 1 or -1; we want to set r to 0 if it
+ * is equal to 0 or 1, and leave it to -1 otherwise.
+ *
+ * When we reach this point at the end of the second pass:
+ * r is either 0 or -1; we want to leave that value
+ * untouched. This is a subcase of the previous.
+ */
+ r >>= 1;
+ r |= (r << 1);
+ }
+
+ x[0] = m[0];
+ return r & (uint32_t)1;
+}
diff --git a/contrib/bearssl/src/int/i31_decode.c b/contrib/bearssl/src/int/i31_decode.c
new file mode 100644
index 000000000000..8ec6d908dcff
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_decode.c
@@ -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"
+
+/* see inner.h */
+void
+br_i31_decode(uint32_t *x, const void *src, size_t len)
+{
+ const unsigned char *buf;
+ size_t u, v;
+ uint32_t acc;
+ int acc_len;
+
+ buf = src;
+ u = len;
+ v = 1;
+ acc = 0;
+ acc_len = 0;
+ while (u -- > 0) {
+ uint32_t b;
+
+ b = buf[u];
+ acc |= (b << acc_len);
+ acc_len += 8;
+ if (acc_len >= 31) {
+ x[v ++] = acc & (uint32_t)0x7FFFFFFF;
+ acc_len -= 31;
+ acc = b >> (8 - acc_len);
+ }
+ }
+ if (acc_len != 0) {
+ x[v ++] = acc;
+ }
+ x[0] = br_i31_bit_length(x + 1, v - 1);
+}
diff --git a/contrib/bearssl/src/int/i31_decred.c b/contrib/bearssl/src/int/i31_decred.c
new file mode 100644
index 000000000000..43db6624c8e4
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_decred.c
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i31_decode_reduce(uint32_t *x,
+ const void *src, size_t len, const uint32_t *m)
+{
+ uint32_t m_ebitlen, m_rbitlen;
+ size_t mblen, k;
+ const unsigned char *buf;
+ uint32_t acc;
+ int acc_len;
+
+ /*
+ * Get the encoded bit length.
+ */
+ m_ebitlen = m[0];
+
+ /*
+ * Special case for an invalid (null) modulus.
+ */
+ if (m_ebitlen == 0) {
+ x[0] = 0;
+ return;
+ }
+
+ /*
+ * Clear the destination.
+ */
+ br_i31_zero(x, m_ebitlen);
+
+ /*
+ * First decode directly as many bytes as possible. This requires
+ * computing the actual bit length.
+ */
+ m_rbitlen = m_ebitlen >> 5;
+ m_rbitlen = (m_ebitlen & 31) + (m_rbitlen << 5) - m_rbitlen;
+ mblen = (m_rbitlen + 7) >> 3;
+ k = mblen - 1;
+ if (k >= len) {
+ br_i31_decode(x, src, len);
+ x[0] = m_ebitlen;
+ return;
+ }
+ buf = src;
+ br_i31_decode(x, buf, k);
+ x[0] = m_ebitlen;
+
+ /*
+ * Input remaining bytes, using 31-bit words.
+ */
+ acc = 0;
+ acc_len = 0;
+ while (k < len) {
+ uint32_t v;
+
+ v = buf[k ++];
+ if (acc_len >= 23) {
+ acc_len -= 23;
+ acc <<= (8 - acc_len);
+ acc |= v >> acc_len;
+ br_i31_muladd_small(x, acc, m);
+ acc = v & (0xFF >> (8 - acc_len));
+ } else {
+ acc = (acc << 8) | v;
+ acc_len += 8;
+ }
+ }
+
+ /*
+ * We may have some bits accumulated. We then perform a shift to
+ * be able to inject these bits as a full 31-bit word.
+ */
+ if (acc_len != 0) {
+ acc = (acc | (x[1] << acc_len)) & 0x7FFFFFFF;
+ br_i31_rshift(x, 31 - acc_len);
+ br_i31_muladd_small(x, acc, m);
+ }
+}
diff --git a/contrib/bearssl/src/int/i31_encode.c b/contrib/bearssl/src/int/i31_encode.c
new file mode 100644
index 000000000000..b6b40c456a52
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_encode.c
@@ -0,0 +1,79 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i31_encode(void *dst, size_t len, const uint32_t *x)
+{
+ unsigned char *buf;
+ size_t k, xlen;
+ uint32_t acc;
+ int acc_len;
+
+ xlen = (x[0] + 31) >> 5;
+ if (xlen == 0) {
+ memset(dst, 0, len);
+ return;
+ }
+ buf = (unsigned char *)dst + len;
+ k = 1;
+ acc = 0;
+ acc_len = 0;
+ while (len != 0) {
+ uint32_t w;
+
+ w = (k <= xlen) ? x[k] : 0;
+ k ++;
+ if (acc_len == 0) {
+ acc = w;
+ acc_len = 31;
+ } else {
+ uint32_t z;
+
+ z = acc | (w << acc_len);
+ acc_len --;
+ acc = w >> (31 - acc_len);
+ if (len >= 4) {
+ buf -= 4;
+ len -= 4;
+ br_enc32be(buf, z);
+ } else {
+ switch (len) {
+ case 3:
+ buf[-3] = (unsigned char)(z >> 16);
+ /* fall through */
+ case 2:
+ buf[-2] = (unsigned char)(z >> 8);
+ /* fall through */
+ case 1:
+ buf[-1] = (unsigned char)z;
+ break;
+ }
+ return;
+ }
+ }
+ }
+}
diff --git a/contrib/bearssl/src/int/i31_fmont.c b/contrib/bearssl/src/int/i31_fmont.c
new file mode 100644
index 000000000000..c24b417665ac
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_fmont.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i31_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i)
+{
+ size_t len, u, v;
+
+ len = (m[0] + 31) >> 5;
+ for (u = 0; u < len; u ++) {
+ uint32_t f;
+ uint64_t cc;
+
+ f = MUL31_lo(x[1], m0i);
+ cc = 0;
+ for (v = 0; v < len; v ++) {
+ uint64_t z;
+
+ z = (uint64_t)x[v + 1] + MUL31(f, m[v + 1]) + cc;
+ cc = z >> 31;
+ if (v != 0) {
+ x[v] = (uint32_t)z & 0x7FFFFFFF;
+ }
+ }
+ x[len] = (uint32_t)cc;
+ }
+
+ /*
+ * We may have to do an extra subtraction, but only if the
+ * value in x[] is indeed greater than or equal to that of m[],
+ * which is why we must do two calls (first call computes the
+ * carry, second call performs the subtraction only if the carry
+ * is 0).
+ */
+ br_i31_sub(x, m, NOT(br_i31_sub(x, m, 0)));
+}
diff --git a/contrib/bearssl/src/int/i31_iszero.c b/contrib/bearssl/src/int/i31_iszero.c
new file mode 100644
index 000000000000..8a7ea44f4f55
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_iszero.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+uint32_t
+br_i31_iszero(const uint32_t *x)
+{
+ uint32_t z;
+ size_t u;
+
+ z = 0;
+ for (u = (x[0] + 31) >> 5; u > 0; u --) {
+ z |= x[u];
+ }
+ return ~(z | -z) >> 31;
+}
diff --git a/contrib/bearssl/src/int/i31_moddiv.c b/contrib/bearssl/src/int/i31_moddiv.c
new file mode 100644
index 000000000000..995059119767
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_moddiv.c
@@ -0,0 +1,488 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * In this file, we handle big integers with a custom format, i.e.
+ * without the usual one-word header. Value is split into 31-bit words,
+ * each stored in a 32-bit slot (top bit is zero) in little-endian
+ * order. The length (in words) is provided explicitly. In some cases,
+ * the value can be negative (using two's complement representation). In
+ * some cases, the top word is allowed to have a 32th bit.
+ */
+
+/*
+ * Negate big integer conditionally. The value consists of 'len' words,
+ * with 31 bits in each word (the top bit of each word should be 0,
+ * except possibly for the last word). If 'ctl' is 1, the negation is
+ * computed; otherwise, if 'ctl' is 0, then the value is unchanged.
+ */
+static void
+cond_negate(uint32_t *a, size_t len, uint32_t ctl)
+{
+ size_t k;
+ uint32_t cc, xm;
+
+ cc = ctl;
+ xm = -ctl >> 1;
+ for (k = 0; k < len; k ++) {
+ uint32_t aw;
+
+ aw = a[k];
+ aw = (aw ^ xm) + cc;
+ a[k] = aw & 0x7FFFFFFF;
+ cc = aw >> 31;
+ }
+}
+
+/*
+ * Finish modular reduction. Rules on input parameters:
+ *
+ * if neg = 1, then -m <= a < 0
+ * if neg = 0, then 0 <= a < 2*m
+ *
+ * If neg = 0, then the top word of a[] may use 32 bits.
+ *
+ * Also, modulus m must be odd.
+ */
+static void
+finish_mod(uint32_t *a, size_t len, const uint32_t *m, uint32_t neg)
+{
+ size_t k;
+ uint32_t cc, xm, ym;
+
+ /*
+ * First pass: compare a (assumed nonnegative) with m.
+ * Note that if the final word uses the top extra bit, then
+ * subtracting m must yield a value less than 2^31, since we
+ * assumed that a < 2*m.
+ */
+ cc = 0;
+ for (k = 0; k < len; k ++) {
+ uint32_t aw, mw;
+
+ aw = a[k];
+ mw = m[k];
+ cc = (aw - mw - cc) >> 31;
+ }
+
+ /*
+ * At this point:
+ * if neg = 1, then we must add m (regardless of cc)
+ * if neg = 0 and cc = 0, then we must subtract m
+ * if neg = 0 and cc = 1, then we must do nothing
+ */
+ xm = -neg >> 1;
+ ym = -(neg | (1 - cc));
+ cc = neg;
+ for (k = 0; k < len; k ++) {
+ uint32_t aw, mw;
+
+ aw = a[k];
+ mw = (m[k] ^ xm) & ym;
+ aw = aw - mw - cc;
+ a[k] = aw & 0x7FFFFFFF;
+ cc = aw >> 31;
+ }
+}
+
+/*
+ * Compute:
+ * a <- (a*pa+b*pb)/(2^31)
+ * b <- (a*qa+b*qb)/(2^31)
+ * The division is assumed to be exact (i.e. the low word is dropped).
+ * If the final a is negative, then it is negated. Similarly for b.
+ * Returned value is the combination of two bits:
+ * bit 0: 1 if a had to be negated, 0 otherwise
+ * bit 1: 1 if b had to be negated, 0 otherwise
+ *
+ * Factors pa, pb, qa and qb must be at most 2^31 in absolute value.
+ * Source integers a and b must be nonnegative; top word is not allowed
+ * to contain an extra 32th bit.
+ */
+static uint32_t
+co_reduce(uint32_t *a, uint32_t *b, size_t len,
+ int64_t pa, int64_t pb, int64_t qa, int64_t qb)
+{
+ size_t k;
+ int64_t cca, ccb;
+ uint32_t nega, negb;
+
+ cca = 0;
+ ccb = 0;
+ for (k = 0; k < len; k ++) {
+ uint32_t wa, wb;
+ uint64_t za, zb;
+ uint64_t tta, ttb;
+
+ /*
+ * Since:
+ * |pa| <= 2^31
+ * |pb| <= 2^31
+ * 0 <= wa <= 2^31 - 1
+ * 0 <= wb <= 2^31 - 1
+ * |cca| <= 2^32 - 1
+ * Then:
+ * |za| <= (2^31-1)*(2^32) + (2^32-1) = 2^63 - 1
+ *
+ * Thus, the new value of cca is such that |cca| <= 2^32 - 1.
+ * The same applies to ccb.
+ */
+ wa = a[k];
+ wb = b[k];
+ za = wa * (uint64_t)pa + wb * (uint64_t)pb + (uint64_t)cca;
+ zb = wa * (uint64_t)qa + wb * (uint64_t)qb + (uint64_t)ccb;
+ if (k > 0) {
+ a[k - 1] = za & 0x7FFFFFFF;
+ b[k - 1] = zb & 0x7FFFFFFF;
+ }
+
+ /*
+ * For the new values of cca and ccb, we need a signed
+ * right-shift; since, in C, right-shifting a signed
+ * negative value is implementation-defined, we use a
+ * custom portable sign extension expression.
+ */
+#define M ((uint64_t)1 << 32)
+ tta = za >> 31;
+ ttb = zb >> 31;
+ tta = (tta ^ M) - M;
+ ttb = (ttb ^ M) - M;
+ cca = *(int64_t *)&tta;
+ ccb = *(int64_t *)&ttb;
+#undef M
+ }
+ a[len - 1] = (uint32_t)cca;
+ b[len - 1] = (uint32_t)ccb;
+
+ nega = (uint32_t)((uint64_t)cca >> 63);
+ negb = (uint32_t)((uint64_t)ccb >> 63);
+ cond_negate(a, len, nega);
+ cond_negate(b, len, negb);
+ return nega | (negb << 1);
+}
+
+/*
+ * Compute:
+ * a <- (a*pa+b*pb)/(2^31) mod m
+ * b <- (a*qa+b*qb)/(2^31) mod m
+ *
+ * m0i is equal to -1/m[0] mod 2^31.
+ *
+ * Factors pa, pb, qa and qb must be at most 2^31 in absolute value.
+ * Source integers a and b must be nonnegative; top word is not allowed
+ * to contain an extra 32th bit.
+ */
+static void
+co_reduce_mod(uint32_t *a, uint32_t *b, size_t len,
+ int64_t pa, int64_t pb, int64_t qa, int64_t qb,
+ const uint32_t *m, uint32_t m0i)
+{
+ size_t k;
+ int64_t cca, ccb;
+ uint32_t fa, fb;
+
+ cca = 0;
+ ccb = 0;
+ fa = ((a[0] * (uint32_t)pa + b[0] * (uint32_t)pb) * m0i) & 0x7FFFFFFF;
+ fb = ((a[0] * (uint32_t)qa + b[0] * (uint32_t)qb) * m0i) & 0x7FFFFFFF;
+ for (k = 0; k < len; k ++) {
+ uint32_t wa, wb;
+ uint64_t za, zb;
+ uint64_t tta, ttb;
+
+ /*
+ * In this loop, carries 'cca' and 'ccb' always fit on
+ * 33 bits (in absolute value).
+ */
+ wa = a[k];
+ wb = b[k];
+ za = wa * (uint64_t)pa + wb * (uint64_t)pb
+ + m[k] * (uint64_t)fa + (uint64_t)cca;
+ zb = wa * (uint64_t)qa + wb * (uint64_t)qb
+ + m[k] * (uint64_t)fb + (uint64_t)ccb;
+ if (k > 0) {
+ a[k - 1] = (uint32_t)za & 0x7FFFFFFF;
+ b[k - 1] = (uint32_t)zb & 0x7FFFFFFF;
+ }
+
+#define M ((uint64_t)1 << 32)
+ tta = za >> 31;
+ ttb = zb >> 31;
+ tta = (tta ^ M) - M;
+ ttb = (ttb ^ M) - M;
+ cca = *(int64_t *)&tta;
+ ccb = *(int64_t *)&ttb;
+#undef M
+ }
+ a[len - 1] = (uint32_t)cca;
+ b[len - 1] = (uint32_t)ccb;
+
+ /*
+ * At this point:
+ * -m <= a < 2*m
+ * -m <= b < 2*m
+ * (this is a case of Montgomery reduction)
+ * The top word of 'a' and 'b' may have a 32-th bit set.
+ * We may have to add or subtract the modulus.
+ */
+ finish_mod(a, len, m, (uint32_t)((uint64_t)cca >> 63));
+ finish_mod(b, len, m, (uint32_t)((uint64_t)ccb >> 63));
+}
+
+/* see inner.h */
+uint32_t
+br_i31_moddiv(uint32_t *x, const uint32_t *y, const uint32_t *m, uint32_t m0i,
+ uint32_t *t)
+{
+ /*
+ * Algorithm is an extended binary GCD. We maintain four values
+ * a, b, u and v, with the following invariants:
+ *
+ * a * x = y * u mod m
+ * b * x = y * v mod m
+ *
+ * Starting values are:
+ *
+ * a = y
+ * b = m
+ * u = x
+ * v = 0
+ *
+ * The formal definition of the algorithm is a sequence of steps:
+ *
+ * - If a is even, then a <- a/2 and u <- u/2 mod m.
+ * - Otherwise, if b is even, then b <- b/2 and v <- v/2 mod m.
+ * - Otherwise, if a > b, then a <- (a-b)/2 and u <- (u-v)/2 mod m.
+ * - Otherwise, b <- (b-a)/2 and v <- (v-u)/2 mod m.
+ *
+ * Algorithm stops when a = b. At that point, they both are equal
+ * to GCD(y,m); the modular division succeeds if that value is 1.
+ * The result of the modular division is then u (or v: both are
+ * equal at that point).
+ *
+ * Each step makes either a or b shrink by at least one bit; hence,
+ * if m has bit length k bits, then 2k-2 steps are sufficient.
+ *
+ *
+ * Though complexity is quadratic in the size of m, the bit-by-bit
+ * processing is not very efficient. We can speed up processing by
+ * remarking that the decisions are taken based only on observation
+ * of the top and low bits of a and b.
+ *
+ * In the loop below, at each iteration, we use the two top words
+ * of a and b, and the low words of a and b, to compute reduction
+ * parameters pa, pb, qa and qb such that the new values for a
+ * and b are:
+ *
+ * a' = (a*pa + b*pb) / (2^31)
+ * b' = (a*qa + b*qb) / (2^31)
+ *
+ * the division being exact.
+ *
+ * Since the choices are based on the top words, they may be slightly
+ * off, requiring an optional correction: if a' < 0, then we replace
+ * pa with -pa, and pb with -pb. The total length of a and b is
+ * thus reduced by at least 30 bits at each iteration.
+ *
+ * The stopping conditions are still the same, though: when a
+ * and b become equal, they must be both odd (since m is odd,
+ * the GCD cannot be even), therefore the next operation is a
+ * subtraction, and one of the values becomes 0. At that point,
+ * nothing else happens, i.e. one value is stuck at 0, and the
+ * other one is the GCD.
+ */
+ size_t len, k;
+ uint32_t *a, *b, *u, *v;
+ uint32_t num, r;
+
+ len = (m[0] + 31) >> 5;
+ a = t;
+ b = a + len;
+ u = x + 1;
+ v = b + len;
+ memcpy(a, y + 1, len * sizeof *y);
+ memcpy(b, m + 1, len * sizeof *m);
+ memset(v, 0, len * sizeof *v);
+
+ /*
+ * Loop below ensures that a and b are reduced by some bits each,
+ * for a total of at least 30 bits.
+ */
+ for (num = ((m[0] - (m[0] >> 5)) << 1) + 30; num >= 30; num -= 30) {
+ size_t j;
+ uint32_t c0, c1;
+ uint32_t a0, a1, b0, b1;
+ uint64_t a_hi, b_hi;
+ uint32_t a_lo, b_lo;
+ int64_t pa, pb, qa, qb;
+ int i;
+
+ /*
+ * Extract top words of a and b. If j is the highest
+ * index >= 1 such that a[j] != 0 or b[j] != 0, then we want
+ * (a[j] << 31) + a[j - 1], and (b[j] << 31) + b[j - 1].
+ * If a and b are down to one word each, then we use a[0]
+ * and b[0].
+ */
+ c0 = (uint32_t)-1;
+ c1 = (uint32_t)-1;
+ a0 = 0;
+ a1 = 0;
+ b0 = 0;
+ b1 = 0;
+ j = len;
+ while (j -- > 0) {
+ uint32_t aw, bw;
+
+ aw = a[j];
+ bw = b[j];
+ a0 ^= (a0 ^ aw) & c0;
+ a1 ^= (a1 ^ aw) & c1;
+ b0 ^= (b0 ^ bw) & c0;
+ b1 ^= (b1 ^ bw) & c1;
+ c1 = c0;
+ c0 &= (((aw | bw) + 0x7FFFFFFF) >> 31) - (uint32_t)1;
+ }
+
+ /*
+ * If c1 = 0, then we grabbed two words for a and b.
+ * If c1 != 0 but c0 = 0, then we grabbed one word. It
+ * is not possible that c1 != 0 and c0 != 0, because that
+ * would mean that both integers are zero.
+ */
+ a1 |= a0 & c1;
+ a0 &= ~c1;
+ b1 |= b0 & c1;
+ b0 &= ~c1;
+ a_hi = ((uint64_t)a0 << 31) + a1;
+ b_hi = ((uint64_t)b0 << 31) + b1;
+ a_lo = a[0];
+ b_lo = b[0];
+
+ /*
+ * Compute reduction factors:
+ *
+ * a' = a*pa + b*pb
+ * b' = a*qa + b*qb
+ *
+ * such that a' and b' are both multiple of 2^31, but are
+ * only marginally larger than a and b.
+ */
+ pa = 1;
+ pb = 0;
+ qa = 0;
+ qb = 1;
+ for (i = 0; i < 31; i ++) {
+ /*
+ * At each iteration:
+ *
+ * a <- (a-b)/2 if: a is odd, b is odd, a_hi > b_hi
+ * b <- (b-a)/2 if: a is odd, b is odd, a_hi <= b_hi
+ * a <- a/2 if: a is even
+ * b <- b/2 if: a is odd, b is even
+ *
+ * We multiply a_lo and b_lo by 2 at each
+ * iteration, thus a division by 2 really is a
+ * non-multiplication by 2.
+ */
+ uint32_t r, oa, ob, cAB, cBA, cA;
+ uint64_t rz;
+
+ /*
+ * r = GT(a_hi, b_hi)
+ * But the GT() function works on uint32_t operands,
+ * so we inline a 64-bit version here.
+ */
+ rz = b_hi - a_hi;
+ r = (uint32_t)((rz ^ ((a_hi ^ b_hi)
+ & (a_hi ^ rz))) >> 63);
+
+ /*
+ * cAB = 1 if b must be subtracted from a
+ * cBA = 1 if a must be subtracted from b
+ * cA = 1 if a is divided by 2, 0 otherwise
+ *
+ * Rules:
+ *
+ * cAB and cBA cannot be both 1.
+ * if a is not divided by 2, b is.
+ */
+ oa = (a_lo >> i) & 1;
+ ob = (b_lo >> i) & 1;
+ cAB = oa & ob & r;
+ cBA = oa & ob & NOT(r);
+ cA = cAB | NOT(oa);
+
+ /*
+ * Conditional subtractions.
+ */
+ a_lo -= b_lo & -cAB;
+ a_hi -= b_hi & -(uint64_t)cAB;
+ pa -= qa & -(int64_t)cAB;
+ pb -= qb & -(int64_t)cAB;
+ b_lo -= a_lo & -cBA;
+ b_hi -= a_hi & -(uint64_t)cBA;
+ qa -= pa & -(int64_t)cBA;
+ qb -= pb & -(int64_t)cBA;
+
+ /*
+ * Shifting.
+ */
+ a_lo += a_lo & (cA - 1);
+ pa += pa & ((int64_t)cA - 1);
+ pb += pb & ((int64_t)cA - 1);
+ a_hi ^= (a_hi ^ (a_hi >> 1)) & -(uint64_t)cA;
+ b_lo += b_lo & -cA;
+ qa += qa & -(int64_t)cA;
+ qb += qb & -(int64_t)cA;
+ b_hi ^= (b_hi ^ (b_hi >> 1)) & ((uint64_t)cA - 1);
+ }
+
+ /*
+ * Replace a and b with new values a' and b'.
+ */
+ r = co_reduce(a, b, len, pa, pb, qa, qb);
+ pa -= pa * ((r & 1) << 1);
+ pb -= pb * ((r & 1) << 1);
+ qa -= qa * (r & 2);
+ qb -= qb * (r & 2);
+ co_reduce_mod(u, v, len, pa, pb, qa, qb, m + 1, m0i);
+ }
+
+ /*
+ * Now one of the arrays should be 0, and the other contains
+ * the GCD. If a is 0, then u is 0 as well, and v contains
+ * the division result.
+ * Result is correct if and only if GCD is 1.
+ */
+ r = (a[0] | b[0]) ^ 1;
+ u[0] |= v[0];
+ for (k = 1; k < len; k ++) {
+ r |= a[k] | b[k];
+ u[k] |= v[k];
+ }
+ return EQ0(r);
+}
diff --git a/contrib/bearssl/src/int/i31_modpow.c b/contrib/bearssl/src/int/i31_modpow.c
new file mode 100644
index 000000000000..4ef3f5d5ac87
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_modpow.c
@@ -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.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i31_modpow(uint32_t *x,
+ const unsigned char *e, size_t elen,
+ const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2)
+{
+ size_t mlen;
+ uint32_t k;
+
+ /*
+ * 'mlen' is the length of m[] expressed in bytes (including
+ * the "bit length" first field).
+ */
+ mlen = ((m[0] + 63) >> 5) * sizeof m[0];
+
+ /*
+ * Throughout the algorithm:
+ * -- t1[] is in Montgomery representation; it contains x, x^2,
+ * x^4, x^8...
+ * -- The result is accumulated, in normal representation, in
+ * the x[] array.
+ * -- t2[] is used as destination buffer for each multiplication.
+ *
+ * Note that there is no need to call br_i32_from_monty().
+ */
+ memcpy(t1, x, mlen);
+ br_i31_to_monty(t1, m);
+ br_i31_zero(x, m[0]);
+ x[1] = 1;
+ for (k = 0; k < ((uint32_t)elen << 3); k ++) {
+ uint32_t ctl;
+
+ ctl = (e[elen - 1 - (k >> 3)] >> (k & 7)) & 1;
+ br_i31_montymul(t2, x, t1, m, m0i);
+ CCOPY(ctl, x, t2, mlen);
+ br_i31_montymul(t2, t1, t1, m, m0i);
+ memcpy(t1, t2, mlen);
+ }
+}
diff --git a/contrib/bearssl/src/int/i31_modpow2.c b/contrib/bearssl/src/int/i31_modpow2.c
new file mode 100644
index 000000000000..0b8f8cf7ea70
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_modpow2.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+uint32_t
+br_i31_modpow_opt(uint32_t *x,
+ const unsigned char *e, size_t elen,
+ const uint32_t *m, uint32_t m0i, uint32_t *tmp, size_t twlen)
+{
+ size_t mlen, mwlen;
+ uint32_t *t1, *t2, *base;
+ size_t u, v;
+ uint32_t acc;
+ int acc_len, win_len;
+
+ /*
+ * Get modulus size.
+ */
+ mwlen = (m[0] + 63) >> 5;
+ mlen = mwlen * sizeof m[0];
+ mwlen += (mwlen & 1);
+ t1 = tmp;
+ t2 = tmp + mwlen;
+
+ /*
+ * Compute possible window size, with a maximum of 5 bits.
+ * When the window has size 1 bit, we use a specific code
+ * that requires only two temporaries. Otherwise, for a
+ * window of k bits, we need 2^k+1 temporaries.
+ */
+ if (twlen < (mwlen << 1)) {
+ return 0;
+ }
+ for (win_len = 5; win_len > 1; win_len --) {
+ if ((((uint32_t)1 << win_len) + 1) * mwlen <= twlen) {
+ break;
+ }
+ }
+
+ /*
+ * Everything is done in Montgomery representation.
+ */
+ br_i31_to_monty(x, m);
+
+ /*
+ * Compute window contents. If the window has size one bit only,
+ * then t2 is set to x; otherwise, t2[0] is left untouched, and
+ * t2[k] is set to x^k (for k >= 1).
+ */
+ if (win_len == 1) {
+ memcpy(t2, x, mlen);
+ } else {
+ memcpy(t2 + mwlen, x, mlen);
+ base = t2 + mwlen;
+ for (u = 2; u < ((unsigned)1 << win_len); u ++) {
+ br_i31_montymul(base + mwlen, base, x, m, m0i);
+ base += mwlen;
+ }
+ }
+
+ /*
+ * We need to set x to 1, in Montgomery representation. This can
+ * be done efficiently by setting the high word to 1, then doing
+ * one word-sized shift.
+ */
+ br_i31_zero(x, m[0]);
+ x[(m[0] + 31) >> 5] = 1;
+ br_i31_muladd_small(x, 0, m);
+
+ /*
+ * We process bits from most to least significant. At each
+ * loop iteration, we have acc_len bits in acc.
+ */
+ acc = 0;
+ acc_len = 0;
+ while (acc_len > 0 || elen > 0) {
+ int i, k;
+ uint32_t bits;
+
+ /*
+ * Get the next bits.
+ */
+ k = win_len;
+ if (acc_len < win_len) {
+ if (elen > 0) {
+ acc = (acc << 8) | *e ++;
+ elen --;
+ acc_len += 8;
+ } else {
+ k = acc_len;
+ }
+ }
+ bits = (acc >> (acc_len - k)) & (((uint32_t)1 << k) - 1);
+ acc_len -= k;
+
+ /*
+ * We could get exactly k bits. Compute k squarings.
+ */
+ for (i = 0; i < k; i ++) {
+ br_i31_montymul(t1, x, x, m, m0i);
+ memcpy(x, t1, mlen);
+ }
+
+ /*
+ * Window lookup: we want to set t2 to the window
+ * lookup value, assuming the bits are non-zero. If
+ * the window length is 1 bit only, then t2 is
+ * already set; otherwise, we do a constant-time lookup.
+ */
+ if (win_len > 1) {
+ br_i31_zero(t2, m[0]);
+ base = t2 + mwlen;
+ for (u = 1; u < ((uint32_t)1 << k); u ++) {
+ uint32_t mask;
+
+ mask = -EQ(u, bits);
+ for (v = 1; v < mwlen; v ++) {
+ t2[v] |= mask & base[v];
+ }
+ base += mwlen;
+ }
+ }
+
+ /*
+ * Multiply with the looked-up value. We keep the
+ * product only if the exponent bits are not all-zero.
+ */
+ br_i31_montymul(t1, x, t2, m, m0i);
+ CCOPY(NEQ(bits, 0), x, t1, mlen);
+ }
+
+ /*
+ * Convert back from Montgomery representation, and exit.
+ */
+ br_i31_from_monty(x, m, m0i);
+ return 1;
+}
diff --git a/contrib/bearssl/src/int/i31_montmul.c b/contrib/bearssl/src/int/i31_montmul.c
new file mode 100644
index 000000000000..758f8f42a33b
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_montmul.c
@@ -0,0 +1,127 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i31_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y,
+ const uint32_t *m, uint32_t m0i)
+{
+ /*
+ * Each outer loop iteration computes:
+ * d <- (d + xu*y + f*m) / 2^31
+ * We have xu <= 2^31-1 and f <= 2^31-1.
+ * Thus, if d <= 2*m-1 on input, then:
+ * 2*m-1 + 2*(2^31-1)*m <= (2^32)*m-1
+ * and the new d value is less than 2*m.
+ *
+ * We represent d over 31-bit words, with an extra word 'dh'
+ * which can thus be only 0 or 1.
+ */
+ size_t len, len4, u, v;
+ uint32_t dh;
+
+ len = (m[0] + 31) >> 5;
+ len4 = len & ~(size_t)3;
+ br_i31_zero(d, m[0]);
+ dh = 0;
+ for (u = 0; u < len; u ++) {
+ /*
+ * The carry for each operation fits on 32 bits:
+ * d[v+1] <= 2^31-1
+ * xu*y[v+1] <= (2^31-1)*(2^31-1)
+ * f*m[v+1] <= (2^31-1)*(2^31-1)
+ * r <= 2^32-1
+ * (2^31-1) + 2*(2^31-1)*(2^31-1) + (2^32-1) = 2^63 - 2^31
+ * After division by 2^31, the new r is then at most 2^32-1
+ *
+ * Using a 32-bit carry has performance benefits on 32-bit
+ * systems; however, on 64-bit architectures, we prefer to
+ * keep the carry (r) in a 64-bit register, thus avoiding some
+ * "clear high bits" operations.
+ */
+ uint32_t f, xu;
+#if BR_64
+ uint64_t r;
+#else
+ uint32_t r;
+#endif
+
+ xu = x[u + 1];
+ f = MUL31_lo((d[1] + MUL31_lo(x[u + 1], y[1])), m0i);
+
+ r = 0;
+ for (v = 0; v < len4; v += 4) {
+ uint64_t z;
+
+ z = (uint64_t)d[v + 1] + MUL31(xu, y[v + 1])
+ + MUL31(f, m[v + 1]) + r;
+ r = z >> 31;
+ d[v + 0] = (uint32_t)z & 0x7FFFFFFF;
+ z = (uint64_t)d[v + 2] + MUL31(xu, y[v + 2])
+ + MUL31(f, m[v + 2]) + r;
+ r = z >> 31;
+ d[v + 1] = (uint32_t)z & 0x7FFFFFFF;
+ z = (uint64_t)d[v + 3] + MUL31(xu, y[v + 3])
+ + MUL31(f, m[v + 3]) + r;
+ r = z >> 31;
+ d[v + 2] = (uint32_t)z & 0x7FFFFFFF;
+ z = (uint64_t)d[v + 4] + MUL31(xu, y[v + 4])
+ + MUL31(f, m[v + 4]) + r;
+ r = z >> 31;
+ d[v + 3] = (uint32_t)z & 0x7FFFFFFF;
+ }
+ for (; v < len; v ++) {
+ uint64_t z;
+
+ z = (uint64_t)d[v + 1] + MUL31(xu, y[v + 1])
+ + MUL31(f, m[v + 1]) + r;
+ r = z >> 31;
+ d[v] = (uint32_t)z & 0x7FFFFFFF;
+ }
+
+ /*
+ * Since the new dh can only be 0 or 1, the addition of
+ * the old dh with the carry MUST fit on 32 bits, and
+ * thus can be done into dh itself.
+ */
+ dh += r;
+ d[len] = dh & 0x7FFFFFFF;
+ dh >>= 31;
+ }
+
+ /*
+ * We must write back the bit length because it was overwritten in
+ * the loop (not overwriting it would require a test in the loop,
+ * which would yield bigger and slower code).
+ */
+ d[0] = m[0];
+
+ /*
+ * d[] may still be greater than m[] at that point; notably, the
+ * 'dh' word may be non-zero.
+ */
+ br_i31_sub(d, m, NEQ(dh, 0) | NOT(br_i31_sub(d, m, 0)));
+}
diff --git a/contrib/bearssl/src/int/i31_mulacc.c b/contrib/bearssl/src/int/i31_mulacc.c
new file mode 100644
index 000000000000..7410e546727c
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_mulacc.c
@@ -0,0 +1,74 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i31_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ size_t alen, blen, u;
+ uint32_t dl, dh;
+
+ alen = (a[0] + 31) >> 5;
+ blen = (b[0] + 31) >> 5;
+
+ /*
+ * We want to add the two bit lengths, but these are encoded,
+ * which requires some extra care.
+ */
+ dl = (a[0] & 31) + (b[0] & 31);
+ dh = (a[0] >> 5) + (b[0] >> 5);
+ d[0] = (dh << 5) + dl + (~(uint32_t)(dl - 31) >> 31);
+
+ for (u = 0; u < blen; u ++) {
+ uint32_t f;
+ size_t v;
+
+ /*
+ * Carry always fits on 31 bits; we want to keep it in a
+ * 32-bit register on 32-bit architectures (on a 64-bit
+ * architecture, cast down from 64 to 32 bits means
+ * clearing the high bits, which is not free; on a 32-bit
+ * architecture, the same operation really means ignoring
+ * the top register, which has negative or zero cost).
+ */
+#if BR_64
+ uint64_t cc;
+#else
+ uint32_t cc;
+#endif
+
+ f = b[1 + u];
+ cc = 0;
+ for (v = 0; v < alen; v ++) {
+ uint64_t z;
+
+ z = (uint64_t)d[1 + u + v] + MUL31(f, a[1 + v]) + cc;
+ cc = z >> 31;
+ d[1 + u + v] = (uint32_t)z & 0x7FFFFFFF;
+ }
+ d[1 + u + alen] = (uint32_t)cc;
+ }
+}
diff --git a/contrib/bearssl/src/int/i31_muladd.c b/contrib/bearssl/src/int/i31_muladd.c
new file mode 100644
index 000000000000..eecd9e2c6c53
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_muladd.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i31_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m)
+{
+ uint32_t m_bitlen;
+ unsigned mblr;
+ size_t u, mlen;
+ uint32_t a0, a1, b0, hi, g, q, tb;
+ uint32_t under, over;
+ uint32_t cc;
+
+ /*
+ * We can test on the modulus bit length since we accept to
+ * leak that length.
+ */
+ m_bitlen = m[0];
+ if (m_bitlen == 0) {
+ return;
+ }
+ if (m_bitlen <= 31) {
+ uint32_t lo;
+
+ hi = x[1] >> 1;
+ lo = (x[1] << 31) | z;
+ x[1] = br_rem(hi, lo, m[1]);
+ return;
+ }
+ mlen = (m_bitlen + 31) >> 5;
+ mblr = (unsigned)m_bitlen & 31;
+
+ /*
+ * Principle: we estimate the quotient (x*2^31+z)/m by
+ * doing a 64/32 division with the high words.
+ *
+ * Let:
+ * w = 2^31
+ * a = (w*a0 + a1) * w^N + a2
+ * b = b0 * w^N + b2
+ * such that:
+ * 0 <= a0 < w
+ * 0 <= a1 < w
+ * 0 <= a2 < w^N
+ * w/2 <= b0 < w
+ * 0 <= b2 < w^N
+ * a < w*b
+ * I.e. the two top words of a are a0:a1, the top word of b is
+ * b0, we ensured that b0 is "full" (high bit set), and a is
+ * such that the quotient q = a/b fits on one word (0 <= q < w).
+ *
+ * If a = b*q + r (with 0 <= r < q), we can estimate q by
+ * doing an Euclidean division on the top words:
+ * a0*w+a1 = b0*u + v (with 0 <= v < b0)
+ * Then the following holds:
+ * 0 <= u <= w
+ * u-2 <= q <= u
+ */
+ hi = x[mlen];
+ if (mblr == 0) {
+ a0 = x[mlen];
+ memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);
+ x[1] = z;
+ a1 = x[mlen];
+ b0 = m[mlen];
+ } else {
+ a0 = ((x[mlen] << (31 - mblr)) | (x[mlen - 1] >> mblr))
+ & 0x7FFFFFFF;
+ memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);
+ x[1] = z;
+ a1 = ((x[mlen] << (31 - mblr)) | (x[mlen - 1] >> mblr))
+ & 0x7FFFFFFF;
+ b0 = ((m[mlen] << (31 - mblr)) | (m[mlen - 1] >> mblr))
+ & 0x7FFFFFFF;
+ }
+
+ /*
+ * We estimate a divisor q. If the quotient returned by br_div()
+ * is g:
+ * -- If a0 == b0 then g == 0; we want q = 0x7FFFFFFF.
+ * -- Otherwise:
+ * -- if g == 0 then we set q = 0;
+ * -- otherwise, we set q = g - 1.
+ * The properties described above then ensure that the true
+ * quotient is q-1, q or q+1.
+ *
+ * Take care that a0, a1 and b0 are 31-bit words, not 32-bit. We
+ * must adjust the parameters to br_div() accordingly.
+ */
+ g = br_div(a0 >> 1, a1 | (a0 << 31), b0);
+ q = MUX(EQ(a0, b0), 0x7FFFFFFF, MUX(EQ(g, 0), 0, g - 1));
+
+ /*
+ * We subtract q*m from x (with the extra high word of value 'hi').
+ * Since q may be off by 1 (in either direction), we may have to
+ * add or subtract m afterwards.
+ *
+ * The 'tb' flag will be true (1) at the end of the loop if the
+ * result is greater than or equal to the modulus (not counting
+ * 'hi' or the carry).
+ */
+ cc = 0;
+ tb = 1;
+ for (u = 1; u <= mlen; u ++) {
+ uint32_t mw, zw, xw, nxw;
+ uint64_t zl;
+
+ mw = m[u];
+ zl = MUL31(mw, q) + cc;
+ cc = (uint32_t)(zl >> 31);
+ zw = (uint32_t)zl & (uint32_t)0x7FFFFFFF;
+ xw = x[u];
+ nxw = xw - zw;
+ cc += nxw >> 31;
+ nxw &= 0x7FFFFFFF;
+ x[u] = nxw;
+ tb = MUX(EQ(nxw, mw), tb, GT(nxw, mw));
+ }
+
+ /*
+ * If we underestimated q, then either cc < hi (one extra bit
+ * beyond the top array word), or cc == hi and tb is true (no
+ * extra bit, but the result is not lower than the modulus). In
+ * these cases we must subtract m once.
+ *
+ * Otherwise, we may have overestimated, which will show as
+ * cc > hi (thus a negative result). Correction is adding m once.
+ */
+ over = GT(cc, hi);
+ under = ~over & (tb | LT(cc, hi));
+ br_i31_add(x, m, over);
+ br_i31_sub(x, m, under);
+}
diff --git a/contrib/bearssl/src/int/i31_ninv31.c b/contrib/bearssl/src/int/i31_ninv31.c
new file mode 100644
index 000000000000..dd83c96a68fb
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_ninv31.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+uint32_t
+br_i31_ninv31(uint32_t x)
+{
+ uint32_t y;
+
+ y = 2 - x;
+ y *= 2 - y * x;
+ y *= 2 - y * x;
+ y *= 2 - y * x;
+ y *= 2 - y * x;
+ return MUX(x & 1, -y, 0) & 0x7FFFFFFF;
+}
diff --git a/contrib/bearssl/src/int/i31_reduce.c b/contrib/bearssl/src/int/i31_reduce.c
new file mode 100644
index 000000000000..5c9523ed152f
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_reduce.c
@@ -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.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i31_reduce(uint32_t *x, const uint32_t *a, const uint32_t *m)
+{
+ uint32_t m_bitlen, a_bitlen;
+ size_t mlen, alen, u;
+
+ m_bitlen = m[0];
+ mlen = (m_bitlen + 31) >> 5;
+
+ x[0] = m_bitlen;
+ if (m_bitlen == 0) {
+ return;
+ }
+
+ /*
+ * If the source is shorter, then simply copy all words from a[]
+ * and zero out the upper words.
+ */
+ a_bitlen = a[0];
+ alen = (a_bitlen + 31) >> 5;
+ if (a_bitlen < m_bitlen) {
+ memcpy(x + 1, a + 1, alen * sizeof *a);
+ for (u = alen; u < mlen; u ++) {
+ x[u + 1] = 0;
+ }
+ return;
+ }
+
+ /*
+ * The source length is at least equal to that of the modulus.
+ * We must thus copy N-1 words, and input the remaining words
+ * one by one.
+ */
+ memcpy(x + 1, a + 2 + (alen - mlen), (mlen - 1) * sizeof *a);
+ x[mlen] = 0;
+ for (u = 1 + alen - mlen; u > 0; u --) {
+ br_i31_muladd_small(x, a[u], m);
+ }
+}
diff --git a/contrib/bearssl/src/int/i31_rshift.c b/contrib/bearssl/src/int/i31_rshift.c
new file mode 100644
index 000000000000..db6ba0b8bbf4
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_rshift.c
@@ -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_i31_rshift(uint32_t *x, int count)
+{
+ size_t u, len;
+ uint32_t r;
+
+ len = (x[0] + 31) >> 5;
+ if (len == 0) {
+ return;
+ }
+ r = x[1] >> count;
+ for (u = 2; u <= len; u ++) {
+ uint32_t w;
+
+ w = x[u];
+ x[u - 1] = ((w << (31 - count)) | r) & 0x7FFFFFFF;
+ r = w >> count;
+ }
+ x[len] = r;
+}
diff --git a/contrib/bearssl/src/int/i31_sub.c b/contrib/bearssl/src/int/i31_sub.c
new file mode 100644
index 000000000000..391089518d75
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_sub.c
@@ -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"
+
+/* see inner.h */
+uint32_t
+br_i31_sub(uint32_t *a, const uint32_t *b, uint32_t ctl)
+{
+ uint32_t cc;
+ size_t u, m;
+
+ cc = 0;
+ m = (a[0] + 63) >> 5;
+ for (u = 1; u < m; u ++) {
+ uint32_t aw, bw, naw;
+
+ aw = a[u];
+ bw = b[u];
+ naw = aw - bw - cc;
+ cc = naw >> 31;
+ a[u] = MUX(ctl, naw & 0x7FFFFFFF, aw);
+ }
+ return cc;
+}
diff --git a/contrib/bearssl/src/int/i31_tmont.c b/contrib/bearssl/src/int/i31_tmont.c
new file mode 100644
index 000000000000..4798ff65d7c9
--- /dev/null
+++ b/contrib/bearssl/src/int/i31_tmont.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i31_to_monty(uint32_t *x, const uint32_t *m)
+{
+ uint32_t k;
+
+ for (k = (m[0] + 31) >> 5; k > 0; k --) {
+ br_i31_muladd_small(x, 0, m);
+ }
+}
diff --git a/contrib/bearssl/src/int/i32_add.c b/contrib/bearssl/src/int/i32_add.c
new file mode 100644
index 000000000000..620baffd7a3d
--- /dev/null
+++ b/contrib/bearssl/src/int/i32_add.c
@@ -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"
+
+/* see inner.h */
+uint32_t
+br_i32_add(uint32_t *a, const uint32_t *b, uint32_t ctl)
+{
+ uint32_t cc;
+ size_t u, m;
+
+ cc = 0;
+ m = (a[0] + 63) >> 5;
+ for (u = 1; u < m; u ++) {
+ uint32_t aw, bw, naw;
+
+ aw = a[u];
+ bw = b[u];
+ naw = aw + bw + cc;
+
+ /*
+ * Carry is 1 if naw < aw. Carry is also 1 if naw == aw
+ * AND the carry was already 1.
+ */
+ cc = (cc & EQ(naw, aw)) | LT(naw, aw);
+ a[u] = MUX(ctl, naw, aw);
+ }
+ return cc;
+}
diff --git a/contrib/bearssl/src/int/i32_bitlen.c b/contrib/bearssl/src/int/i32_bitlen.c
new file mode 100644
index 000000000000..40ce9fa0b35e
--- /dev/null
+++ b/contrib/bearssl/src/int/i32_bitlen.c
@@ -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 */
+uint32_t
+br_i32_bit_length(uint32_t *x, size_t xlen)
+{
+ uint32_t tw, twk;
+
+ tw = 0;
+ twk = 0;
+ while (xlen -- > 0) {
+ uint32_t w, c;
+
+ c = EQ(tw, 0);
+ w = x[xlen];
+ tw = MUX(c, w, tw);
+ twk = MUX(c, (uint32_t)xlen, twk);
+ }
+ return (twk << 5) + BIT_LENGTH(tw);
+}
diff --git a/contrib/bearssl/src/int/i32_decmod.c b/contrib/bearssl/src/int/i32_decmod.c
new file mode 100644
index 000000000000..a859af122287
--- /dev/null
+++ b/contrib/bearssl/src/int/i32_decmod.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+uint32_t
+br_i32_decode_mod(uint32_t *x, const void *src, size_t len, const uint32_t *m)
+{
+ const unsigned char *buf;
+ uint32_t r;
+ size_t u, v, mlen;
+
+ buf = src;
+
+ /*
+ * First pass: determine whether the value fits. The 'r' value
+ * will contain the comparison result, as 0x00000000 (value is
+ * equal to the modulus), 0x00000001 (value is greater than the
+ * modulus), or 0xFFFFFFFF (value is lower than the modulus).
+ */
+ mlen = (m[0] + 7) >> 3;
+ r = 0;
+ for (u = (mlen > len) ? mlen : len; u > 0; u --) {
+ uint32_t mb, xb;
+
+ v = u - 1;
+ if (v >= mlen) {
+ mb = 0;
+ } else {
+ mb = (m[1 + (v >> 2)] >> ((v & 3) << 3)) & 0xFF;
+ }
+ if (v >= len) {
+ xb = 0;
+ } else {
+ xb = buf[len - u];
+ }
+ r = MUX(EQ(r, 0), (uint32_t)CMP(xb, mb), r);
+ }
+
+ /*
+ * Only r == 0xFFFFFFFF is acceptable. We want to set r to 0xFF if
+ * the value fits, 0x00 otherwise.
+ */
+ r >>= 24;
+ br_i32_zero(x, m[0]);
+ u = (mlen > len) ? len : mlen;
+ while (u > 0) {
+ uint32_t xb;
+
+ xb = buf[len - u] & r;
+ u --;
+ x[1 + (u >> 2)] |= xb << ((u & 3) << 3);
+ }
+ return r >> 7;
+}
diff --git a/contrib/bearssl/src/int/i32_decode.c b/contrib/bearssl/src/int/i32_decode.c
new file mode 100644
index 000000000000..f28903846656
--- /dev/null
+++ b/contrib/bearssl/src/int/i32_decode.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i32_decode(uint32_t *x, const void *src, size_t len)
+{
+ const unsigned char *buf;
+ size_t u, v;
+
+ buf = src;
+ u = len;
+ v = 1;
+ for (;;) {
+ if (u < 4) {
+ uint32_t w;
+
+ if (u < 2) {
+ if (u == 0) {
+ break;
+ } else {
+ w = buf[0];
+ }
+ } else {
+ if (u == 2) {
+ w = br_dec16be(buf);
+ } else {
+ w = ((uint32_t)buf[0] << 16)
+ | br_dec16be(buf + 1);
+ }
+ }
+ x[v ++] = w;
+ break;
+ } else {
+ u -= 4;
+ x[v ++] = br_dec32be(buf + u);
+ }
+ }
+ x[0] = br_i32_bit_length(x + 1, v - 1);
+}
diff --git a/contrib/bearssl/src/int/i32_decred.c b/contrib/bearssl/src/int/i32_decred.c
new file mode 100644
index 000000000000..dc476db0d532
--- /dev/null
+++ b/contrib/bearssl/src/int/i32_decred.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i32_decode_reduce(uint32_t *x,
+ const void *src, size_t len, const uint32_t *m)
+{
+ uint32_t m_bitlen;
+ size_t mblen, k, q;
+ const unsigned char *buf;
+
+ m_bitlen = m[0];
+
+ /*
+ * Special case for an invalid modulus.
+ */
+ if (m_bitlen == 0) {
+ x[0] = 0;
+ return;
+ }
+
+ /*
+ * Clear the destination.
+ */
+ br_i32_zero(x, m_bitlen);
+
+ /*
+ * First decode directly as many bytes as possible without
+ * reduction, taking care to leave a number of bytes which
+ * is a multiple of 4.
+ */
+ mblen = (m_bitlen + 7) >> 3;
+ k = mblen - 1;
+
+ /*
+ * Up to k bytes can be safely decoded.
+ */
+ if (k >= len) {
+ br_i32_decode(x, src, len);
+ x[0] = m_bitlen;
+ return;
+ }
+
+ /*
+ * We want to first inject some bytes with direct decoding,
+ * then extra bytes by whole 32-bit words. First compute
+ * the size that should be injected that way.
+ */
+ buf = src;
+ q = (len - k + 3) & ~(size_t)3;
+
+ /*
+ * It may happen that this is more than what we already have
+ * (by at most 3 bytes). Such a case may happen only with
+ * a very short modulus. In that case, we must process the first
+ * bytes "manually".
+ */
+ if (q > len) {
+ int i;
+ uint32_t w;
+
+ w = 0;
+ for (i = 0; i < 4; i ++) {
+ w <<= 8;
+ if (q <= len) {
+ w |= buf[len - q];
+ }
+ q --;
+ }
+ br_i32_muladd_small(x, w, m);
+ } else {
+ br_i32_decode(x, buf, len - q);
+ x[0] = m_bitlen;
+ }
+
+ /*
+ * At that point, we have exactly q bytes to inject, and q is
+ * a multiple of 4.
+ */
+ for (k = len - q; k < len; k += 4) {
+ br_i32_muladd_small(x, br_dec32be(buf + k), m);
+ }
+}
diff --git a/contrib/bearssl/src/int/i32_div32.c b/contrib/bearssl/src/int/i32_div32.c
new file mode 100644
index 000000000000..d8b8023d842d
--- /dev/null
+++ b/contrib/bearssl/src/int/i32_div32.c
@@ -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.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+uint32_t
+br_divrem(uint32_t hi, uint32_t lo, uint32_t d, uint32_t *r)
+{
+ /* TODO: optimize this */
+ uint32_t q;
+ uint32_t ch, cf;
+ int k;
+
+ q = 0;
+ ch = EQ(hi, d);
+ hi = MUX(ch, 0, hi);
+ for (k = 31; k > 0; k --) {
+ int j;
+ uint32_t w, ctl, hi2, lo2;
+
+ j = 32 - k;
+ w = (hi << j) | (lo >> k);
+ ctl = GE(w, d) | (hi >> k);
+ hi2 = (w - d) >> j;
+ lo2 = lo - (d << k);
+ hi = MUX(ctl, hi2, hi);
+ lo = MUX(ctl, lo2, lo);
+ q |= ctl << k;
+ }
+ cf = GE(lo, d) | hi;
+ q |= cf;
+ *r = MUX(cf, lo - d, lo);
+ return q;
+}
diff --git a/contrib/bearssl/src/int/i32_encode.c b/contrib/bearssl/src/int/i32_encode.c
new file mode 100644
index 000000000000..303652f96294
--- /dev/null
+++ b/contrib/bearssl/src/int/i32_encode.c
@@ -0,0 +1,72 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i32_encode(void *dst, size_t len, const uint32_t *x)
+{
+ unsigned char *buf;
+ size_t k;
+
+ buf = dst;
+
+ /*
+ * Compute the announced size of x in bytes; extra bytes are
+ * filled with zeros.
+ */
+ k = (x[0] + 7) >> 3;
+ while (len > k) {
+ *buf ++ = 0;
+ len --;
+ }
+
+ /*
+ * Now we use k as index within x[]. That index starts at 1;
+ * we initialize it to the topmost complete word, and process
+ * any remaining incomplete word.
+ */
+ k = (len + 3) >> 2;
+ switch (len & 3) {
+ case 3:
+ *buf ++ = x[k] >> 16;
+ /* fall through */
+ case 2:
+ *buf ++ = x[k] >> 8;
+ /* fall through */
+ case 1:
+ *buf ++ = x[k];
+ k --;
+ }
+
+ /*
+ * Encode all complete words.
+ */
+ while (k > 0) {
+ br_enc32be(buf, x[k]);
+ k --;
+ buf += 4;
+ }
+}
diff --git a/contrib/bearssl/src/int/i32_fmont.c b/contrib/bearssl/src/int/i32_fmont.c
new file mode 100644
index 000000000000..dc1c93440010
--- /dev/null
+++ b/contrib/bearssl/src/int/i32_fmont.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i32_from_monty(uint32_t *x, const uint32_t *m, uint32_t m0i)
+{
+ size_t len, u, v;
+
+ len = (m[0] + 31) >> 5;
+ for (u = 0; u < len; u ++) {
+ uint32_t f;
+ uint64_t cc;
+
+ f = x[1] * m0i;
+ cc = 0;
+ for (v = 0; v < len; v ++) {
+ uint64_t z;
+
+ z = (uint64_t)x[v + 1] + MUL(f, m[v + 1]) + cc;
+ cc = z >> 32;
+ if (v != 0) {
+ x[v] = (uint32_t)z;
+ }
+ }
+ x[len] = (uint32_t)cc;
+ }
+
+ /*
+ * We may have to do an extra subtraction, but only if the
+ * value in x[] is indeed greater than or equal to that of m[],
+ * which is why we must do two calls (first call computes the
+ * carry, second call performs the subtraction only if the carry
+ * is 0).
+ */
+ br_i32_sub(x, m, NOT(br_i32_sub(x, m, 0)));
+}
diff --git a/contrib/bearssl/src/int/i32_iszero.c b/contrib/bearssl/src/int/i32_iszero.c
new file mode 100644
index 000000000000..659df7f24447
--- /dev/null
+++ b/contrib/bearssl/src/int/i32_iszero.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+uint32_t
+br_i32_iszero(const uint32_t *x)
+{
+ uint32_t z;
+ size_t u;
+
+ z = 0;
+ for (u = (x[0] + 31) >> 5; u > 0; u --) {
+ z |= x[u];
+ }
+ return ~(z | -z) >> 31;
+}
diff --git a/contrib/bearssl/src/int/i32_modpow.c b/contrib/bearssl/src/int/i32_modpow.c
new file mode 100644
index 000000000000..034aba06db1d
--- /dev/null
+++ b/contrib/bearssl/src/int/i32_modpow.c
@@ -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.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i32_modpow(uint32_t *x,
+ const unsigned char *e, size_t elen,
+ const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2)
+{
+ size_t mlen;
+ uint32_t k;
+
+ /*
+ * 'mlen' is the length of m[] expressed in bytes (including
+ * the "bit length" first field).
+ */
+ mlen = ((m[0] + 63) >> 5) * sizeof m[0];
+
+ /*
+ * Throughout the algorithm:
+ * -- t1[] is in Montgomery representation; it contains x, x^2,
+ * x^4, x^8...
+ * -- The result is accumulated, in normal representation, in
+ * the x[] array.
+ * -- t2[] is used as destination buffer for each multiplication.
+ *
+ * Note that there is no need to call br_i32_from_monty().
+ */
+ memcpy(t1, x, mlen);
+ br_i32_to_monty(t1, m);
+ br_i32_zero(x, m[0]);
+ x[1] = 1;
+ for (k = 0; k < ((uint32_t)elen << 3); k ++) {
+ uint32_t ctl;
+
+ ctl = (e[elen - 1 - (k >> 3)] >> (k & 7)) & 1;
+ br_i32_montymul(t2, x, t1, m, m0i);
+ CCOPY(ctl, x, t2, mlen);
+ br_i32_montymul(t2, t1, t1, m, m0i);
+ memcpy(t1, t2, mlen);
+ }
+}
diff --git a/contrib/bearssl/src/int/i32_montmul.c b/contrib/bearssl/src/int/i32_montmul.c
new file mode 100644
index 000000000000..7edb376cddd7
--- /dev/null
+++ b/contrib/bearssl/src/int/i32_montmul.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i32_montymul(uint32_t *d, const uint32_t *x, const uint32_t *y,
+ const uint32_t *m, uint32_t m0i)
+{
+ size_t len, u, v;
+ uint64_t dh;
+
+ len = (m[0] + 31) >> 5;
+ br_i32_zero(d, m[0]);
+ dh = 0;
+ for (u = 0; u < len; u ++) {
+ uint32_t f, xu;
+ uint64_t r1, r2, zh;
+
+ xu = x[u + 1];
+ f = (d[1] + x[u + 1] * y[1]) * m0i;
+ r1 = 0;
+ r2 = 0;
+ for (v = 0; v < len; v ++) {
+ uint64_t z;
+ uint32_t t;
+
+ z = (uint64_t)d[v + 1] + MUL(xu, y[v + 1]) + r1;
+ r1 = z >> 32;
+ t = (uint32_t)z;
+ z = (uint64_t)t + MUL(f, m[v + 1]) + r2;
+ r2 = z >> 32;
+ if (v != 0) {
+ d[v] = (uint32_t)z;
+ }
+ }
+ zh = dh + r1 + r2;
+ d[len] = (uint32_t)zh;
+ dh = zh >> 32;
+ }
+
+ /*
+ * d[] may still be greater than m[] at that point; notably, the
+ * 'dh' word may be non-zero.
+ */
+ br_i32_sub(d, m, NEQ(dh, 0) | NOT(br_i32_sub(d, m, 0)));
+}
diff --git a/contrib/bearssl/src/int/i32_mulacc.c b/contrib/bearssl/src/int/i32_mulacc.c
new file mode 100644
index 000000000000..55da3858038a
--- /dev/null
+++ b/contrib/bearssl/src/int/i32_mulacc.c
@@ -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.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i32_mulacc(uint32_t *d, const uint32_t *a, const uint32_t *b)
+{
+ size_t alen, blen, u;
+
+ alen = (a[0] + 31) >> 5;
+ blen = (b[0] + 31) >> 5;
+ d[0] = a[0] + b[0];
+ for (u = 0; u < blen; u ++) {
+ uint32_t f;
+ size_t v;
+#if BR_64
+ uint64_t cc;
+#else
+ uint32_t cc;
+#endif
+
+ f = b[1 + u];
+ cc = 0;
+ for (v = 0; v < alen; v ++) {
+ uint64_t z;
+
+ z = (uint64_t)d[1 + u + v] + MUL(f, a[1 + v]) + cc;
+ cc = z >> 32;
+ d[1 + u + v] = (uint32_t)z;
+ }
+ d[1 + u + alen] = (uint32_t)cc;
+ }
+}
diff --git a/contrib/bearssl/src/int/i32_muladd.c b/contrib/bearssl/src/int/i32_muladd.c
new file mode 100644
index 000000000000..dd526ad5ef20
--- /dev/null
+++ b/contrib/bearssl/src/int/i32_muladd.c
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i32_muladd_small(uint32_t *x, uint32_t z, const uint32_t *m)
+{
+ uint32_t m_bitlen;
+ size_t u, mlen;
+ uint32_t a0, a1, b0, hi, g, q, tb;
+ uint32_t chf, clow, under, over;
+ uint64_t cc;
+
+ /*
+ * We can test on the modulus bit length since we accept to
+ * leak that length.
+ */
+ m_bitlen = m[0];
+ if (m_bitlen == 0) {
+ return;
+ }
+ if (m_bitlen <= 32) {
+ x[1] = br_rem(x[1], z, m[1]);
+ return;
+ }
+ mlen = (m_bitlen + 31) >> 5;
+
+ /*
+ * Principle: we estimate the quotient (x*2^32+z)/m by
+ * doing a 64/32 division with the high words.
+ *
+ * Let:
+ * w = 2^32
+ * a = (w*a0 + a1) * w^N + a2
+ * b = b0 * w^N + b2
+ * such that:
+ * 0 <= a0 < w
+ * 0 <= a1 < w
+ * 0 <= a2 < w^N
+ * w/2 <= b0 < w
+ * 0 <= b2 < w^N
+ * a < w*b
+ * I.e. the two top words of a are a0:a1, the top word of b is
+ * b0, we ensured that b0 is "full" (high bit set), and a is
+ * such that the quotient q = a/b fits on one word (0 <= q < w).
+ *
+ * If a = b*q + r (with 0 <= r < q), we can estimate q by
+ * doing an Euclidean division on the top words:
+ * a0*w+a1 = b0*u + v (with 0 <= v < w)
+ * Then the following holds:
+ * 0 <= u <= w
+ * u-2 <= q <= u
+ */
+ a0 = br_i32_word(x, m_bitlen - 32);
+ hi = x[mlen];
+ memmove(x + 2, x + 1, (mlen - 1) * sizeof *x);
+ x[1] = z;
+ a1 = br_i32_word(x, m_bitlen - 32);
+ b0 = br_i32_word(m, m_bitlen - 32);
+
+ /*
+ * We estimate a divisor q. If the quotient returned by br_div()
+ * is g:
+ * -- If a0 == b0 then g == 0; we want q = 0xFFFFFFFF.
+ * -- Otherwise:
+ * -- if g == 0 then we set q = 0;
+ * -- otherwise, we set q = g - 1.
+ * The properties described above then ensure that the true
+ * quotient is q-1, q or q+1.
+ */
+ g = br_div(a0, a1, b0);
+ q = MUX(EQ(a0, b0), 0xFFFFFFFF, MUX(EQ(g, 0), 0, g - 1));
+
+ /*
+ * We subtract q*m from x (with the extra high word of value 'hi').
+ * Since q may be off by 1 (in either direction), we may have to
+ * add or subtract m afterwards.
+ *
+ * The 'tb' flag will be true (1) at the end of the loop if the
+ * result is greater than or equal to the modulus (not counting
+ * 'hi' or the carry).
+ */
+ cc = 0;
+ tb = 1;
+ for (u = 1; u <= mlen; u ++) {
+ uint32_t mw, zw, xw, nxw;
+ uint64_t zl;
+
+ mw = m[u];
+ zl = MUL(mw, q) + cc;
+ cc = (uint32_t)(zl >> 32);
+ zw = (uint32_t)zl;
+ xw = x[u];
+ nxw = xw - zw;
+ cc += (uint64_t)GT(nxw, xw);
+ x[u] = nxw;
+ tb = MUX(EQ(nxw, mw), tb, GT(nxw, mw));
+ }
+
+ /*
+ * If we underestimated q, then either cc < hi (one extra bit
+ * beyond the top array word), or cc == hi and tb is true (no
+ * extra bit, but the result is not lower than the modulus). In
+ * these cases we must subtract m once.
+ *
+ * Otherwise, we may have overestimated, which will show as
+ * cc > hi (thus a negative result). Correction is adding m once.
+ */
+ chf = (uint32_t)(cc >> 32);
+ clow = (uint32_t)cc;
+ over = chf | GT(clow, hi);
+ under = ~over & (tb | (~chf & LT(clow, hi)));
+ br_i32_add(x, m, over);
+ br_i32_sub(x, m, under);
+}
diff --git a/contrib/bearssl/src/int/i32_ninv32.c b/contrib/bearssl/src/int/i32_ninv32.c
new file mode 100644
index 000000000000..656443413ae9
--- /dev/null
+++ b/contrib/bearssl/src/int/i32_ninv32.c
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+uint32_t
+br_i32_ninv32(uint32_t x)
+{
+ uint32_t y;
+
+ y = 2 - x;
+ y *= 2 - y * x;
+ y *= 2 - y * x;
+ y *= 2 - y * x;
+ y *= 2 - y * x;
+ return MUX(x & 1, -y, 0);
+}
diff --git a/contrib/bearssl/src/int/i32_reduce.c b/contrib/bearssl/src/int/i32_reduce.c
new file mode 100644
index 000000000000..90fff092bc25
--- /dev/null
+++ b/contrib/bearssl/src/int/i32_reduce.c
@@ -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.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i32_reduce(uint32_t *x, const uint32_t *a, const uint32_t *m)
+{
+ uint32_t m_bitlen, a_bitlen;
+ size_t mlen, alen, u;
+
+ m_bitlen = m[0];
+ mlen = (m_bitlen + 31) >> 5;
+
+ x[0] = m_bitlen;
+ if (m_bitlen == 0) {
+ return;
+ }
+
+ /*
+ * If the source is shorter, then simply copy all words from a[]
+ * and zero out the upper words.
+ */
+ a_bitlen = a[0];
+ alen = (a_bitlen + 31) >> 5;
+ if (a_bitlen < m_bitlen) {
+ memcpy(x + 1, a + 1, alen * sizeof *a);
+ for (u = alen; u < mlen; u ++) {
+ x[u + 1] = 0;
+ }
+ return;
+ }
+
+ /*
+ * The source length is at least equal to that of the modulus.
+ * We must thus copy N-1 words, and input the remaining words
+ * one by one.
+ */
+ memcpy(x + 1, a + 2 + (alen - mlen), (mlen - 1) * sizeof *a);
+ x[mlen] = 0;
+ for (u = 1 + alen - mlen; u > 0; u --) {
+ br_i32_muladd_small(x, a[u], m);
+ }
+}
diff --git a/contrib/bearssl/src/int/i32_sub.c b/contrib/bearssl/src/int/i32_sub.c
new file mode 100644
index 000000000000..9c50023824a3
--- /dev/null
+++ b/contrib/bearssl/src/int/i32_sub.c
@@ -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"
+
+/* see inner.h */
+uint32_t
+br_i32_sub(uint32_t *a, const uint32_t *b, uint32_t ctl)
+{
+ uint32_t cc;
+ size_t u, m;
+
+ cc = 0;
+ m = (a[0] + 63) >> 5;
+ for (u = 1; u < m; u ++) {
+ uint32_t aw, bw, naw;
+
+ aw = a[u];
+ bw = b[u];
+ naw = aw - bw - cc;
+
+ /*
+ * Carry is 1 if naw > aw. Carry is 1 also if naw == aw
+ * AND the carry was already 1.
+ */
+ cc = (cc & EQ(naw, aw)) | GT(naw, aw);
+ a[u] = MUX(ctl, naw, aw);
+ }
+ return cc;
+}
diff --git a/contrib/bearssl/src/int/i32_tmont.c b/contrib/bearssl/src/int/i32_tmont.c
new file mode 100644
index 000000000000..058cd8868df8
--- /dev/null
+++ b/contrib/bearssl/src/int/i32_tmont.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_i32_to_monty(uint32_t *x, const uint32_t *m)
+{
+ uint32_t k;
+
+ for (k = (m[0] + 31) >> 5; k > 0; k --) {
+ br_i32_muladd_small(x, 0, m);
+ }
+}
diff --git a/contrib/bearssl/src/int/i62_modpow2.c b/contrib/bearssl/src/int/i62_modpow2.c
new file mode 100644
index 000000000000..2db537f0a80a
--- /dev/null
+++ b/contrib/bearssl/src/int/i62_modpow2.c
@@ -0,0 +1,493 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#if BR_INT128 || BR_UMUL128
+
+#if BR_INT128
+
+/*
+ * Compute x*y+v1+v2. Operands are 64-bit, and result is 128-bit, with
+ * high word in "hi" and low word in "lo".
+ */
+#define FMA1(hi, lo, x, y, v1, v2) do { \
+ unsigned __int128 fmaz; \
+ fmaz = (unsigned __int128)(x) * (unsigned __int128)(y) \
+ + (unsigned __int128)(v1) + (unsigned __int128)(v2); \
+ (hi) = (uint64_t)(fmaz >> 64); \
+ (lo) = (uint64_t)fmaz; \
+ } while (0)
+
+/*
+ * Compute x1*y1+x2*y2+v1+v2. Operands are 64-bit, and result is 128-bit,
+ * with high word in "hi" and low word in "lo".
+ *
+ * Callers should ensure that the two inner products, and the v1 and v2
+ * operands, are multiple of 4 (this is not used by this specific definition
+ * but may help other implementations).
+ */
+#define FMA2(hi, lo, x1, y1, x2, y2, v1, v2) do { \
+ unsigned __int128 fmaz; \
+ fmaz = (unsigned __int128)(x1) * (unsigned __int128)(y1) \
+ + (unsigned __int128)(x2) * (unsigned __int128)(y2) \
+ + (unsigned __int128)(v1) + (unsigned __int128)(v2); \
+ (hi) = (uint64_t)(fmaz >> 64); \
+ (lo) = (uint64_t)fmaz; \
+ } while (0)
+
+#elif BR_UMUL128
+
+#include <intrin.h>
+
+#define FMA1(hi, lo, x, y, v1, v2) do { \
+ uint64_t fmahi, fmalo; \
+ unsigned char fmacc; \
+ fmalo = _umul128((x), (y), &fmahi); \
+ fmacc = _addcarry_u64(0, fmalo, (v1), &fmalo); \
+ _addcarry_u64(fmacc, fmahi, 0, &fmahi); \
+ fmacc = _addcarry_u64(0, fmalo, (v2), &(lo)); \
+ _addcarry_u64(fmacc, fmahi, 0, &(hi)); \
+ } while (0)
+
+/*
+ * Normally we should use _addcarry_u64() for FMA2 too, but it makes
+ * Visual Studio crash. Instead we use this version, which leverages
+ * the fact that the vx operands, and the products, are multiple of 4.
+ * This is unfortunately slower.
+ */
+#define FMA2(hi, lo, x1, y1, x2, y2, v1, v2) do { \
+ uint64_t fma1hi, fma1lo; \
+ uint64_t fma2hi, fma2lo; \
+ uint64_t fmatt; \
+ fma1lo = _umul128((x1), (y1), &fma1hi); \
+ fma2lo = _umul128((x2), (y2), &fma2hi); \
+ fmatt = (fma1lo >> 2) + (fma2lo >> 2) \
+ + ((v1) >> 2) + ((v2) >> 2); \
+ (lo) = fmatt << 2; \
+ (hi) = fma1hi + fma2hi + (fmatt >> 62); \
+ } while (0)
+
+/*
+ * The FMA2 macro definition we would prefer to use, but it triggers
+ * an internal compiler error in Visual Studio 2015.
+ *
+#define FMA2(hi, lo, x1, y1, x2, y2, v1, v2) do { \
+ uint64_t fma1hi, fma1lo; \
+ uint64_t fma2hi, fma2lo; \
+ unsigned char fmacc; \
+ fma1lo = _umul128((x1), (y1), &fma1hi); \
+ fma2lo = _umul128((x2), (y2), &fma2hi); \
+ fmacc = _addcarry_u64(0, fma1lo, (v1), &fma1lo); \
+ _addcarry_u64(fmacc, fma1hi, 0, &fma1hi); \
+ fmacc = _addcarry_u64(0, fma2lo, (v2), &fma2lo); \
+ _addcarry_u64(fmacc, fma2hi, 0, &fma2hi); \
+ fmacc = _addcarry_u64(0, fma1lo, fma2lo, &(lo)); \
+ _addcarry_u64(fmacc, fma1hi, fma2hi, &(hi)); \
+ } while (0)
+ */
+
+#endif
+
+#define MASK62 ((uint64_t)0x3FFFFFFFFFFFFFFF)
+#define MUL62_lo(x, y) (((uint64_t)(x) * (uint64_t)(y)) & MASK62)
+
+/*
+ * Subtract b from a, and return the final carry. If 'ctl32' is 0, then
+ * a[] is kept unmodified, but the final carry is still computed and
+ * returned.
+ */
+static uint32_t
+i62_sub(uint64_t *a, const uint64_t *b, size_t num, uint32_t ctl32)
+{
+ uint64_t cc, mask;
+ size_t u;
+
+ cc = 0;
+ ctl32 = -ctl32;
+ mask = (uint64_t)ctl32 | ((uint64_t)ctl32 << 32);
+ for (u = 0; u < num; u ++) {
+ uint64_t aw, bw, dw;
+
+ aw = a[u];
+ bw = b[u];
+ dw = aw - bw - cc;
+ cc = dw >> 63;
+ dw &= MASK62;
+ a[u] = aw ^ (mask & (dw ^ aw));
+ }
+ return (uint32_t)cc;
+}
+
+/*
+ * Montgomery multiplication, over arrays of 62-bit values. The
+ * destination array (d) must be distinct from the other operands
+ * (x, y and m). All arrays are in little-endian format (least
+ * significant word comes first) over 'num' words.
+ */
+static void
+montymul(uint64_t *d, const uint64_t *x, const uint64_t *y,
+ const uint64_t *m, size_t num, uint64_t m0i)
+{
+ uint64_t dh;
+ size_t u, num4;
+
+ num4 = 1 + ((num - 1) & ~(size_t)3);
+ memset(d, 0, num * sizeof *d);
+ dh = 0;
+ for (u = 0; u < num; u ++) {
+ size_t v;
+ uint64_t f, xu;
+ uint64_t r, zh;
+ uint64_t hi, lo;
+
+ xu = x[u] << 2;
+ f = MUL62_lo(d[0] + MUL62_lo(x[u], y[0]), m0i) << 2;
+
+ FMA2(hi, lo, xu, y[0], f, m[0], d[0] << 2, 0);
+ r = hi;
+
+ for (v = 1; v < num4; v += 4) {
+ FMA2(hi, lo, xu, y[v + 0],
+ f, m[v + 0], d[v + 0] << 2, r << 2);
+ r = hi + (r >> 62);
+ d[v - 1] = lo >> 2;
+ FMA2(hi, lo, xu, y[v + 1],
+ f, m[v + 1], d[v + 1] << 2, r << 2);
+ r = hi + (r >> 62);
+ d[v + 0] = lo >> 2;
+ FMA2(hi, lo, xu, y[v + 2],
+ f, m[v + 2], d[v + 2] << 2, r << 2);
+ r = hi + (r >> 62);
+ d[v + 1] = lo >> 2;
+ FMA2(hi, lo, xu, y[v + 3],
+ f, m[v + 3], d[v + 3] << 2, r << 2);
+ r = hi + (r >> 62);
+ d[v + 2] = lo >> 2;
+ }
+ for (; v < num; v ++) {
+ FMA2(hi, lo, xu, y[v], f, m[v], d[v] << 2, r << 2);
+ r = hi + (r >> 62);
+ d[v - 1] = lo >> 2;
+ }
+
+ zh = dh + r;
+ d[num - 1] = zh & MASK62;
+ dh = zh >> 62;
+ }
+ i62_sub(d, m, num, (uint32_t)dh | NOT(i62_sub(d, m, num, 0)));
+}
+
+/*
+ * Conversion back from Montgomery representation.
+ */
+static void
+frommonty(uint64_t *x, const uint64_t *m, size_t num, uint64_t m0i)
+{
+ size_t u, v;
+
+ for (u = 0; u < num; u ++) {
+ uint64_t f, cc;
+
+ f = MUL62_lo(x[0], m0i) << 2;
+ cc = 0;
+ for (v = 0; v < num; v ++) {
+ uint64_t hi, lo;
+
+ FMA1(hi, lo, f, m[v], x[v] << 2, cc);
+ cc = hi << 2;
+ if (v != 0) {
+ x[v - 1] = lo >> 2;
+ }
+ }
+ x[num - 1] = cc >> 2;
+ }
+ i62_sub(x, m, num, NOT(i62_sub(x, m, num, 0)));
+}
+
+/* see inner.h */
+uint32_t
+br_i62_modpow_opt(uint32_t *x31, const unsigned char *e, size_t elen,
+ const uint32_t *m31, uint32_t m0i31, uint64_t *tmp, size_t twlen)
+{
+ size_t u, mw31num, mw62num;
+ uint64_t *x, *m, *t1, *t2;
+ uint64_t m0i;
+ uint32_t acc;
+ int win_len, acc_len;
+
+ /*
+ * Get modulus size, in words.
+ */
+ mw31num = (m31[0] + 31) >> 5;
+ mw62num = (mw31num + 1) >> 1;
+
+ /*
+ * In order to apply this function, we must have enough room to
+ * copy the operand and modulus into the temporary array, along
+ * with at least two temporaries. If there is not enough room,
+ * switch to br_i31_modpow(). We also use br_i31_modpow() if the
+ * modulus length is not at least four words (94 bits or more).
+ */
+ if (mw31num < 4 || (mw62num << 2) > twlen) {
+ /*
+ * We assume here that we can split an aligned uint64_t
+ * into two properly aligned uint32_t. Since both types
+ * are supposed to have an exact width with no padding,
+ * then this property must hold.
+ */
+ size_t txlen;
+
+ txlen = mw31num + 1;
+ if (twlen < txlen) {
+ return 0;
+ }
+ br_i31_modpow(x31, e, elen, m31, m0i31,
+ (uint32_t *)tmp, (uint32_t *)tmp + txlen);
+ return 1;
+ }
+
+ /*
+ * Convert x to Montgomery representation: this means that
+ * we replace x with x*2^z mod m, where z is the smallest multiple
+ * of the word size such that 2^z >= m. We want to reuse the 31-bit
+ * functions here (for constant-time operation), but we need z
+ * for a 62-bit word size.
+ */
+ for (u = 0; u < mw62num; u ++) {
+ br_i31_muladd_small(x31, 0, m31);
+ br_i31_muladd_small(x31, 0, m31);
+ }
+
+ /*
+ * Assemble operands into arrays of 62-bit words. Note that
+ * all the arrays of 62-bit words that we will handle here
+ * are without any leading size word.
+ *
+ * We also adjust tmp and twlen to account for the words used
+ * for these extra arrays.
+ */
+ m = tmp;
+ x = tmp + mw62num;
+ tmp += (mw62num << 1);
+ twlen -= (mw62num << 1);
+ for (u = 0; u < mw31num; u += 2) {
+ size_t v;
+
+ v = u >> 1;
+ if ((u + 1) == mw31num) {
+ m[v] = (uint64_t)m31[u + 1];
+ x[v] = (uint64_t)x31[u + 1];
+ } else {
+ m[v] = (uint64_t)m31[u + 1]
+ + ((uint64_t)m31[u + 2] << 31);
+ x[v] = (uint64_t)x31[u + 1]
+ + ((uint64_t)x31[u + 2] << 31);
+ }
+ }
+
+ /*
+ * Compute window size. We support windows up to 5 bits; for a
+ * window of size k bits, we need 2^k+1 temporaries (for k = 1,
+ * we use special code that uses only 2 temporaries).
+ */
+ for (win_len = 5; win_len > 1; win_len --) {
+ if ((((uint32_t)1 << win_len) + 1) * mw62num <= twlen) {
+ break;
+ }
+ }
+
+ t1 = tmp;
+ t2 = tmp + mw62num;
+
+ /*
+ * Compute m0i, which is equal to -(1/m0) mod 2^62. We were
+ * provided with m0i31, which already fulfills this property
+ * modulo 2^31; the single expression below is then sufficient.
+ */
+ m0i = (uint64_t)m0i31;
+ m0i = MUL62_lo(m0i, (uint64_t)2 + MUL62_lo(m0i, m[0]));
+
+ /*
+ * Compute window contents. If the window has size one bit only,
+ * then t2 is set to x; otherwise, t2[0] is left untouched, and
+ * t2[k] is set to x^k (for k >= 1).
+ */
+ if (win_len == 1) {
+ memcpy(t2, x, mw62num * sizeof *x);
+ } else {
+ uint64_t *base;
+
+ memcpy(t2 + mw62num, x, mw62num * sizeof *x);
+ base = t2 + mw62num;
+ for (u = 2; u < ((unsigned)1 << win_len); u ++) {
+ montymul(base + mw62num, base, x, m, mw62num, m0i);
+ base += mw62num;
+ }
+ }
+
+ /*
+ * Set x to 1, in Montgomery representation. We again use the
+ * 31-bit code.
+ */
+ br_i31_zero(x31, m31[0]);
+ x31[(m31[0] + 31) >> 5] = 1;
+ br_i31_muladd_small(x31, 0, m31);
+ if (mw31num & 1) {
+ br_i31_muladd_small(x31, 0, m31);
+ }
+ for (u = 0; u < mw31num; u += 2) {
+ size_t v;
+
+ v = u >> 1;
+ if ((u + 1) == mw31num) {
+ x[v] = (uint64_t)x31[u + 1];
+ } else {
+ x[v] = (uint64_t)x31[u + 1]
+ + ((uint64_t)x31[u + 2] << 31);
+ }
+ }
+
+ /*
+ * We process bits from most to least significant. At each
+ * loop iteration, we have acc_len bits in acc.
+ */
+ acc = 0;
+ acc_len = 0;
+ while (acc_len > 0 || elen > 0) {
+ int i, k;
+ uint32_t bits;
+ uint64_t mask1, mask2;
+
+ /*
+ * Get the next bits.
+ */
+ k = win_len;
+ if (acc_len < win_len) {
+ if (elen > 0) {
+ acc = (acc << 8) | *e ++;
+ elen --;
+ acc_len += 8;
+ } else {
+ k = acc_len;
+ }
+ }
+ bits = (acc >> (acc_len - k)) & (((uint32_t)1 << k) - 1);
+ acc_len -= k;
+
+ /*
+ * We could get exactly k bits. Compute k squarings.
+ */
+ for (i = 0; i < k; i ++) {
+ montymul(t1, x, x, m, mw62num, m0i);
+ memcpy(x, t1, mw62num * sizeof *x);
+ }
+
+ /*
+ * Window lookup: we want to set t2 to the window
+ * lookup value, assuming the bits are non-zero. If
+ * the window length is 1 bit only, then t2 is
+ * already set; otherwise, we do a constant-time lookup.
+ */
+ if (win_len > 1) {
+ uint64_t *base;
+
+ memset(t2, 0, mw62num * sizeof *t2);
+ base = t2 + mw62num;
+ for (u = 1; u < ((uint32_t)1 << k); u ++) {
+ uint64_t mask;
+ size_t v;
+
+ mask = -(uint64_t)EQ(u, bits);
+ for (v = 0; v < mw62num; v ++) {
+ t2[v] |= mask & base[v];
+ }
+ base += mw62num;
+ }
+ }
+
+ /*
+ * Multiply with the looked-up value. We keep the product
+ * only if the exponent bits are not all-zero.
+ */
+ montymul(t1, x, t2, m, mw62num, m0i);
+ mask1 = -(uint64_t)EQ(bits, 0);
+ mask2 = ~mask1;
+ for (u = 0; u < mw62num; u ++) {
+ x[u] = (mask1 & x[u]) | (mask2 & t1[u]);
+ }
+ }
+
+ /*
+ * Convert back from Montgomery representation.
+ */
+ frommonty(x, m, mw62num, m0i);
+
+ /*
+ * Convert result into 31-bit words.
+ */
+ for (u = 0; u < mw31num; u += 2) {
+ uint64_t zw;
+
+ zw = x[u >> 1];
+ x31[u + 1] = (uint32_t)zw & 0x7FFFFFFF;
+ if ((u + 1) < mw31num) {
+ x31[u + 2] = (uint32_t)(zw >> 31);
+ }
+ }
+ return 1;
+}
+
+#else
+
+/* see inner.h */
+uint32_t
+br_i62_modpow_opt(uint32_t *x31, const unsigned char *e, size_t elen,
+ const uint32_t *m31, uint32_t m0i31, uint64_t *tmp, size_t twlen)
+{
+ size_t mwlen;
+
+ mwlen = (m31[0] + 63) >> 5;
+ if (twlen < mwlen) {
+ return 0;
+ }
+ return br_i31_modpow_opt(x31, e, elen, m31, m0i31,
+ (uint32_t *)tmp, twlen << 1);
+}
+
+#endif
+
+/* see inner.h */
+uint32_t
+br_i62_modpow_opt_as_i31(uint32_t *x31, const unsigned char *e, size_t elen,
+ const uint32_t *m31, uint32_t m0i31, uint32_t *tmp, size_t twlen)
+{
+ /*
+ * As documented, this function expects the 'tmp' argument to be
+ * 64-bit aligned. This is OK since this function is internal (it
+ * is not part of BearSSL's public API).
+ */
+ return br_i62_modpow_opt(x31, e, elen, m31, m0i31,
+ (uint64_t *)tmp, twlen >> 1);
+}
diff --git a/contrib/bearssl/src/kdf/hkdf.c b/contrib/bearssl/src/kdf/hkdf.c
new file mode 100644
index 000000000000..6a36851b7350
--- /dev/null
+++ b/contrib/bearssl/src/kdf/hkdf.c
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+const unsigned char br_hkdf_no_salt = 0;
+
+/* see bearssl_kdf.h */
+void
+br_hkdf_init(br_hkdf_context *hc, const br_hash_class *digest_vtable,
+ const void *salt, size_t salt_len)
+{
+ br_hmac_key_context kc;
+ unsigned char tmp[64];
+
+ if (salt == BR_HKDF_NO_SALT) {
+ salt = tmp;
+ salt_len = br_digest_size(digest_vtable);
+ memset(tmp, 0, salt_len);
+ }
+ br_hmac_key_init(&kc, digest_vtable, salt, salt_len);
+ br_hmac_init(&hc->u.hmac_ctx, &kc, 0);
+ hc->dig_len = br_hmac_size(&hc->u.hmac_ctx);
+}
+
+/* see bearssl_kdf.h */
+void
+br_hkdf_inject(br_hkdf_context *hc, const void *ikm, size_t ikm_len)
+{
+ br_hmac_update(&hc->u.hmac_ctx, ikm, ikm_len);
+}
+
+/* see bearssl_kdf.h */
+void
+br_hkdf_flip(br_hkdf_context *hc)
+{
+ unsigned char tmp[64];
+
+ br_hmac_out(&hc->u.hmac_ctx, tmp);
+ br_hmac_key_init(&hc->u.prk_ctx,
+ br_hmac_get_digest(&hc->u.hmac_ctx), tmp, hc->dig_len);
+ hc->ptr = hc->dig_len;
+ hc->chunk_num = 0;
+}
+
+/* see bearssl_kdf.h */
+size_t
+br_hkdf_produce(br_hkdf_context *hc,
+ const void *info, size_t info_len, void *out, size_t out_len)
+{
+ size_t tlen;
+
+ tlen = 0;
+ while (out_len > 0) {
+ size_t clen;
+
+ if (hc->ptr == hc->dig_len) {
+ br_hmac_context hmac_ctx;
+ unsigned char x;
+
+ hc->chunk_num ++;
+ if (hc->chunk_num == 256) {
+ return tlen;
+ }
+ x = hc->chunk_num;
+ br_hmac_init(&hmac_ctx, &hc->u.prk_ctx, 0);
+ if (x != 1) {
+ br_hmac_update(&hmac_ctx, hc->buf, hc->dig_len);
+ }
+ br_hmac_update(&hmac_ctx, info, info_len);
+ br_hmac_update(&hmac_ctx, &x, 1);
+ br_hmac_out(&hmac_ctx, hc->buf);
+ hc->ptr = 0;
+ }
+ clen = hc->dig_len - hc->ptr;
+ if (clen > out_len) {
+ clen = out_len;
+ }
+ memcpy(out, hc->buf + hc->ptr, clen);
+ out = (unsigned char *)out + clen;
+ out_len -= clen;
+ hc->ptr += clen;
+ tlen += clen;
+ }
+ return tlen;
+}
diff --git a/contrib/bearssl/src/kdf/shake.c b/contrib/bearssl/src/kdf/shake.c
new file mode 100644
index 000000000000..80d7176dc707
--- /dev/null
+++ b/contrib/bearssl/src/kdf/shake.c
@@ -0,0 +1,590 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * Round constants.
+ */
+static const uint64_t RC[] = {
+ 0x0000000000000001, 0x0000000000008082,
+ 0x800000000000808A, 0x8000000080008000,
+ 0x000000000000808B, 0x0000000080000001,
+ 0x8000000080008081, 0x8000000000008009,
+ 0x000000000000008A, 0x0000000000000088,
+ 0x0000000080008009, 0x000000008000000A,
+ 0x000000008000808B, 0x800000000000008B,
+ 0x8000000000008089, 0x8000000000008003,
+ 0x8000000000008002, 0x8000000000000080,
+ 0x000000000000800A, 0x800000008000000A,
+ 0x8000000080008081, 0x8000000000008080,
+ 0x0000000080000001, 0x8000000080008008
+};
+
+/*
+ * XOR a block of data into the provided state. This supports only
+ * blocks whose length is a multiple of 64 bits.
+ */
+static void
+xor_block(uint64_t *A, const void *data, size_t rate)
+{
+ size_t u;
+
+ for (u = 0; u < rate; u += 8) {
+ A[u >> 3] ^= br_dec64le((const unsigned char *)data + u);
+ }
+}
+
+/*
+ * Process a block with the provided data. The data length must be a
+ * multiple of 8 (in bytes); normally, this is the "rate".
+ */
+static void
+process_block(uint64_t *A)
+{
+ uint64_t t0, t1, t2, t3, t4;
+ uint64_t tt0, tt1, tt2, tt3;
+ uint64_t t, kt;
+ uint64_t c0, c1, c2, c3, c4, bnn;
+ int j;
+
+ /*
+ * Compute the 24 rounds. This loop is partially unrolled (each
+ * iteration computes two rounds).
+ */
+ for (j = 0; j < 24; j += 2) {
+
+ tt0 = A[ 1] ^ A[ 6];
+ tt1 = A[11] ^ A[16];
+ tt0 ^= A[21] ^ tt1;
+ tt0 = (tt0 << 1) | (tt0 >> 63);
+ tt2 = A[ 4] ^ A[ 9];
+ tt3 = A[14] ^ A[19];
+ tt0 ^= A[24];
+ tt2 ^= tt3;
+ t0 = tt0 ^ tt2;
+
+ tt0 = A[ 2] ^ A[ 7];
+ tt1 = A[12] ^ A[17];
+ tt0 ^= A[22] ^ tt1;
+ tt0 = (tt0 << 1) | (tt0 >> 63);
+ tt2 = A[ 0] ^ A[ 5];
+ tt3 = A[10] ^ A[15];
+ tt0 ^= A[20];
+ tt2 ^= tt3;
+ t1 = tt0 ^ tt2;
+
+ tt0 = A[ 3] ^ A[ 8];
+ tt1 = A[13] ^ A[18];
+ tt0 ^= A[23] ^ tt1;
+ tt0 = (tt0 << 1) | (tt0 >> 63);
+ tt2 = A[ 1] ^ A[ 6];
+ tt3 = A[11] ^ A[16];
+ tt0 ^= A[21];
+ tt2 ^= tt3;
+ t2 = tt0 ^ tt2;
+
+ tt0 = A[ 4] ^ A[ 9];
+ tt1 = A[14] ^ A[19];
+ tt0 ^= A[24] ^ tt1;
+ tt0 = (tt0 << 1) | (tt0 >> 63);
+ tt2 = A[ 2] ^ A[ 7];
+ tt3 = A[12] ^ A[17];
+ tt0 ^= A[22];
+ tt2 ^= tt3;
+ t3 = tt0 ^ tt2;
+
+ tt0 = A[ 0] ^ A[ 5];
+ tt1 = A[10] ^ A[15];
+ tt0 ^= A[20] ^ tt1;
+ tt0 = (tt0 << 1) | (tt0 >> 63);
+ tt2 = A[ 3] ^ A[ 8];
+ tt3 = A[13] ^ A[18];
+ tt0 ^= A[23];
+ tt2 ^= tt3;
+ t4 = tt0 ^ tt2;
+
+ A[ 0] = A[ 0] ^ t0;
+ A[ 5] = A[ 5] ^ t0;
+ A[10] = A[10] ^ t0;
+ A[15] = A[15] ^ t0;
+ A[20] = A[20] ^ t0;
+ A[ 1] = A[ 1] ^ t1;
+ A[ 6] = A[ 6] ^ t1;
+ A[11] = A[11] ^ t1;
+ A[16] = A[16] ^ t1;
+ A[21] = A[21] ^ t1;
+ A[ 2] = A[ 2] ^ t2;
+ A[ 7] = A[ 7] ^ t2;
+ A[12] = A[12] ^ t2;
+ A[17] = A[17] ^ t2;
+ A[22] = A[22] ^ t2;
+ A[ 3] = A[ 3] ^ t3;
+ A[ 8] = A[ 8] ^ t3;
+ A[13] = A[13] ^ t3;
+ A[18] = A[18] ^ t3;
+ A[23] = A[23] ^ t3;
+ A[ 4] = A[ 4] ^ t4;
+ A[ 9] = A[ 9] ^ t4;
+ A[14] = A[14] ^ t4;
+ A[19] = A[19] ^ t4;
+ A[24] = A[24] ^ t4;
+ A[ 5] = (A[ 5] << 36) | (A[ 5] >> (64 - 36));
+ A[10] = (A[10] << 3) | (A[10] >> (64 - 3));
+ A[15] = (A[15] << 41) | (A[15] >> (64 - 41));
+ A[20] = (A[20] << 18) | (A[20] >> (64 - 18));
+ A[ 1] = (A[ 1] << 1) | (A[ 1] >> (64 - 1));
+ A[ 6] = (A[ 6] << 44) | (A[ 6] >> (64 - 44));
+ A[11] = (A[11] << 10) | (A[11] >> (64 - 10));
+ A[16] = (A[16] << 45) | (A[16] >> (64 - 45));
+ A[21] = (A[21] << 2) | (A[21] >> (64 - 2));
+ A[ 2] = (A[ 2] << 62) | (A[ 2] >> (64 - 62));
+ A[ 7] = (A[ 7] << 6) | (A[ 7] >> (64 - 6));
+ A[12] = (A[12] << 43) | (A[12] >> (64 - 43));
+ A[17] = (A[17] << 15) | (A[17] >> (64 - 15));
+ A[22] = (A[22] << 61) | (A[22] >> (64 - 61));
+ A[ 3] = (A[ 3] << 28) | (A[ 3] >> (64 - 28));
+ A[ 8] = (A[ 8] << 55) | (A[ 8] >> (64 - 55));
+ A[13] = (A[13] << 25) | (A[13] >> (64 - 25));
+ A[18] = (A[18] << 21) | (A[18] >> (64 - 21));
+ A[23] = (A[23] << 56) | (A[23] >> (64 - 56));
+ A[ 4] = (A[ 4] << 27) | (A[ 4] >> (64 - 27));
+ A[ 9] = (A[ 9] << 20) | (A[ 9] >> (64 - 20));
+ A[14] = (A[14] << 39) | (A[14] >> (64 - 39));
+ A[19] = (A[19] << 8) | (A[19] >> (64 - 8));
+ A[24] = (A[24] << 14) | (A[24] >> (64 - 14));
+ bnn = ~A[12];
+ kt = A[ 6] | A[12];
+ c0 = A[ 0] ^ kt;
+ kt = bnn | A[18];
+ c1 = A[ 6] ^ kt;
+ kt = A[18] & A[24];
+ c2 = A[12] ^ kt;
+ kt = A[24] | A[ 0];
+ c3 = A[18] ^ kt;
+ kt = A[ 0] & A[ 6];
+ c4 = A[24] ^ kt;
+ A[ 0] = c0;
+ A[ 6] = c1;
+ A[12] = c2;
+ A[18] = c3;
+ A[24] = c4;
+ bnn = ~A[22];
+ kt = A[ 9] | A[10];
+ c0 = A[ 3] ^ kt;
+ kt = A[10] & A[16];
+ c1 = A[ 9] ^ kt;
+ kt = A[16] | bnn;
+ c2 = A[10] ^ kt;
+ kt = A[22] | A[ 3];
+ c3 = A[16] ^ kt;
+ kt = A[ 3] & A[ 9];
+ c4 = A[22] ^ kt;
+ A[ 3] = c0;
+ A[ 9] = c1;
+ A[10] = c2;
+ A[16] = c3;
+ A[22] = c4;
+ bnn = ~A[19];
+ kt = A[ 7] | A[13];
+ c0 = A[ 1] ^ kt;
+ kt = A[13] & A[19];
+ c1 = A[ 7] ^ kt;
+ kt = bnn & A[20];
+ c2 = A[13] ^ kt;
+ kt = A[20] | A[ 1];
+ c3 = bnn ^ kt;
+ kt = A[ 1] & A[ 7];
+ c4 = A[20] ^ kt;
+ A[ 1] = c0;
+ A[ 7] = c1;
+ A[13] = c2;
+ A[19] = c3;
+ A[20] = c4;
+ bnn = ~A[17];
+ kt = A[ 5] & A[11];
+ c0 = A[ 4] ^ kt;
+ kt = A[11] | A[17];
+ c1 = A[ 5] ^ kt;
+ kt = bnn | A[23];
+ c2 = A[11] ^ kt;
+ kt = A[23] & A[ 4];
+ c3 = bnn ^ kt;
+ kt = A[ 4] | A[ 5];
+ c4 = A[23] ^ kt;
+ A[ 4] = c0;
+ A[ 5] = c1;
+ A[11] = c2;
+ A[17] = c3;
+ A[23] = c4;
+ bnn = ~A[ 8];
+ kt = bnn & A[14];
+ c0 = A[ 2] ^ kt;
+ kt = A[14] | A[15];
+ c1 = bnn ^ kt;
+ kt = A[15] & A[21];
+ c2 = A[14] ^ kt;
+ kt = A[21] | A[ 2];
+ c3 = A[15] ^ kt;
+ kt = A[ 2] & A[ 8];
+ c4 = A[21] ^ kt;
+ A[ 2] = c0;
+ A[ 8] = c1;
+ A[14] = c2;
+ A[15] = c3;
+ A[21] = c4;
+ A[ 0] = A[ 0] ^ RC[j + 0];
+
+ tt0 = A[ 6] ^ A[ 9];
+ tt1 = A[ 7] ^ A[ 5];
+ tt0 ^= A[ 8] ^ tt1;
+ tt0 = (tt0 << 1) | (tt0 >> 63);
+ tt2 = A[24] ^ A[22];
+ tt3 = A[20] ^ A[23];
+ tt0 ^= A[21];
+ tt2 ^= tt3;
+ t0 = tt0 ^ tt2;
+
+ tt0 = A[12] ^ A[10];
+ tt1 = A[13] ^ A[11];
+ tt0 ^= A[14] ^ tt1;
+ tt0 = (tt0 << 1) | (tt0 >> 63);
+ tt2 = A[ 0] ^ A[ 3];
+ tt3 = A[ 1] ^ A[ 4];
+ tt0 ^= A[ 2];
+ tt2 ^= tt3;
+ t1 = tt0 ^ tt2;
+
+ tt0 = A[18] ^ A[16];
+ tt1 = A[19] ^ A[17];
+ tt0 ^= A[15] ^ tt1;
+ tt0 = (tt0 << 1) | (tt0 >> 63);
+ tt2 = A[ 6] ^ A[ 9];
+ tt3 = A[ 7] ^ A[ 5];
+ tt0 ^= A[ 8];
+ tt2 ^= tt3;
+ t2 = tt0 ^ tt2;
+
+ tt0 = A[24] ^ A[22];
+ tt1 = A[20] ^ A[23];
+ tt0 ^= A[21] ^ tt1;
+ tt0 = (tt0 << 1) | (tt0 >> 63);
+ tt2 = A[12] ^ A[10];
+ tt3 = A[13] ^ A[11];
+ tt0 ^= A[14];
+ tt2 ^= tt3;
+ t3 = tt0 ^ tt2;
+
+ tt0 = A[ 0] ^ A[ 3];
+ tt1 = A[ 1] ^ A[ 4];
+ tt0 ^= A[ 2] ^ tt1;
+ tt0 = (tt0 << 1) | (tt0 >> 63);
+ tt2 = A[18] ^ A[16];
+ tt3 = A[19] ^ A[17];
+ tt0 ^= A[15];
+ tt2 ^= tt3;
+ t4 = tt0 ^ tt2;
+
+ A[ 0] = A[ 0] ^ t0;
+ A[ 3] = A[ 3] ^ t0;
+ A[ 1] = A[ 1] ^ t0;
+ A[ 4] = A[ 4] ^ t0;
+ A[ 2] = A[ 2] ^ t0;
+ A[ 6] = A[ 6] ^ t1;
+ A[ 9] = A[ 9] ^ t1;
+ A[ 7] = A[ 7] ^ t1;
+ A[ 5] = A[ 5] ^ t1;
+ A[ 8] = A[ 8] ^ t1;
+ A[12] = A[12] ^ t2;
+ A[10] = A[10] ^ t2;
+ A[13] = A[13] ^ t2;
+ A[11] = A[11] ^ t2;
+ A[14] = A[14] ^ t2;
+ A[18] = A[18] ^ t3;
+ A[16] = A[16] ^ t3;
+ A[19] = A[19] ^ t3;
+ A[17] = A[17] ^ t3;
+ A[15] = A[15] ^ t3;
+ A[24] = A[24] ^ t4;
+ A[22] = A[22] ^ t4;
+ A[20] = A[20] ^ t4;
+ A[23] = A[23] ^ t4;
+ A[21] = A[21] ^ t4;
+ A[ 3] = (A[ 3] << 36) | (A[ 3] >> (64 - 36));
+ A[ 1] = (A[ 1] << 3) | (A[ 1] >> (64 - 3));
+ A[ 4] = (A[ 4] << 41) | (A[ 4] >> (64 - 41));
+ A[ 2] = (A[ 2] << 18) | (A[ 2] >> (64 - 18));
+ A[ 6] = (A[ 6] << 1) | (A[ 6] >> (64 - 1));
+ A[ 9] = (A[ 9] << 44) | (A[ 9] >> (64 - 44));
+ A[ 7] = (A[ 7] << 10) | (A[ 7] >> (64 - 10));
+ A[ 5] = (A[ 5] << 45) | (A[ 5] >> (64 - 45));
+ A[ 8] = (A[ 8] << 2) | (A[ 8] >> (64 - 2));
+ A[12] = (A[12] << 62) | (A[12] >> (64 - 62));
+ A[10] = (A[10] << 6) | (A[10] >> (64 - 6));
+ A[13] = (A[13] << 43) | (A[13] >> (64 - 43));
+ A[11] = (A[11] << 15) | (A[11] >> (64 - 15));
+ A[14] = (A[14] << 61) | (A[14] >> (64 - 61));
+ A[18] = (A[18] << 28) | (A[18] >> (64 - 28));
+ A[16] = (A[16] << 55) | (A[16] >> (64 - 55));
+ A[19] = (A[19] << 25) | (A[19] >> (64 - 25));
+ A[17] = (A[17] << 21) | (A[17] >> (64 - 21));
+ A[15] = (A[15] << 56) | (A[15] >> (64 - 56));
+ A[24] = (A[24] << 27) | (A[24] >> (64 - 27));
+ A[22] = (A[22] << 20) | (A[22] >> (64 - 20));
+ A[20] = (A[20] << 39) | (A[20] >> (64 - 39));
+ A[23] = (A[23] << 8) | (A[23] >> (64 - 8));
+ A[21] = (A[21] << 14) | (A[21] >> (64 - 14));
+ bnn = ~A[13];
+ kt = A[ 9] | A[13];
+ c0 = A[ 0] ^ kt;
+ kt = bnn | A[17];
+ c1 = A[ 9] ^ kt;
+ kt = A[17] & A[21];
+ c2 = A[13] ^ kt;
+ kt = A[21] | A[ 0];
+ c3 = A[17] ^ kt;
+ kt = A[ 0] & A[ 9];
+ c4 = A[21] ^ kt;
+ A[ 0] = c0;
+ A[ 9] = c1;
+ A[13] = c2;
+ A[17] = c3;
+ A[21] = c4;
+ bnn = ~A[14];
+ kt = A[22] | A[ 1];
+ c0 = A[18] ^ kt;
+ kt = A[ 1] & A[ 5];
+ c1 = A[22] ^ kt;
+ kt = A[ 5] | bnn;
+ c2 = A[ 1] ^ kt;
+ kt = A[14] | A[18];
+ c3 = A[ 5] ^ kt;
+ kt = A[18] & A[22];
+ c4 = A[14] ^ kt;
+ A[18] = c0;
+ A[22] = c1;
+ A[ 1] = c2;
+ A[ 5] = c3;
+ A[14] = c4;
+ bnn = ~A[23];
+ kt = A[10] | A[19];
+ c0 = A[ 6] ^ kt;
+ kt = A[19] & A[23];
+ c1 = A[10] ^ kt;
+ kt = bnn & A[ 2];
+ c2 = A[19] ^ kt;
+ kt = A[ 2] | A[ 6];
+ c3 = bnn ^ kt;
+ kt = A[ 6] & A[10];
+ c4 = A[ 2] ^ kt;
+ A[ 6] = c0;
+ A[10] = c1;
+ A[19] = c2;
+ A[23] = c3;
+ A[ 2] = c4;
+ bnn = ~A[11];
+ kt = A[ 3] & A[ 7];
+ c0 = A[24] ^ kt;
+ kt = A[ 7] | A[11];
+ c1 = A[ 3] ^ kt;
+ kt = bnn | A[15];
+ c2 = A[ 7] ^ kt;
+ kt = A[15] & A[24];
+ c3 = bnn ^ kt;
+ kt = A[24] | A[ 3];
+ c4 = A[15] ^ kt;
+ A[24] = c0;
+ A[ 3] = c1;
+ A[ 7] = c2;
+ A[11] = c3;
+ A[15] = c4;
+ bnn = ~A[16];
+ kt = bnn & A[20];
+ c0 = A[12] ^ kt;
+ kt = A[20] | A[ 4];
+ c1 = bnn ^ kt;
+ kt = A[ 4] & A[ 8];
+ c2 = A[20] ^ kt;
+ kt = A[ 8] | A[12];
+ c3 = A[ 4] ^ kt;
+ kt = A[12] & A[16];
+ c4 = A[ 8] ^ kt;
+ A[12] = c0;
+ A[16] = c1;
+ A[20] = c2;
+ A[ 4] = c3;
+ A[ 8] = c4;
+ A[ 0] = A[ 0] ^ RC[j + 1];
+ t = A[ 5];
+ A[ 5] = A[18];
+ A[18] = A[11];
+ A[11] = A[10];
+ A[10] = A[ 6];
+ A[ 6] = A[22];
+ A[22] = A[20];
+ A[20] = A[12];
+ A[12] = A[19];
+ A[19] = A[15];
+ A[15] = A[24];
+ A[24] = A[ 8];
+ A[ 8] = t;
+ t = A[ 1];
+ A[ 1] = A[ 9];
+ A[ 9] = A[14];
+ A[14] = A[ 2];
+ A[ 2] = A[13];
+ A[13] = A[23];
+ A[23] = A[ 4];
+ A[ 4] = A[21];
+ A[21] = A[16];
+ A[16] = A[ 3];
+ A[ 3] = A[17];
+ A[17] = A[ 7];
+ A[ 7] = t;
+ }
+}
+
+/* see bearssl_kdf.h */
+void
+br_shake_init(br_shake_context *sc, int security_level)
+{
+ sc->rate = 200 - (size_t)(security_level >> 2);
+ sc->dptr = 0;
+ memset(sc->A, 0, sizeof sc->A);
+ sc->A[ 1] = ~(uint64_t)0;
+ sc->A[ 2] = ~(uint64_t)0;
+ sc->A[ 8] = ~(uint64_t)0;
+ sc->A[12] = ~(uint64_t)0;
+ sc->A[17] = ~(uint64_t)0;
+ sc->A[20] = ~(uint64_t)0;
+}
+
+/* see bearssl_kdf.h */
+void
+br_shake_inject(br_shake_context *sc, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ size_t rate, dptr;
+
+ buf = data;
+ rate = sc->rate;
+ dptr = sc->dptr;
+ while (len > 0) {
+ size_t clen;
+
+ clen = rate - dptr;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(sc->dbuf + dptr, buf, clen);
+ dptr += clen;
+ buf += clen;
+ len -= clen;
+ if (dptr == rate) {
+ xor_block(sc->A, sc->dbuf, rate);
+ process_block(sc->A);
+ dptr = 0;
+ }
+ }
+ sc->dptr = dptr;
+}
+
+/* see bearssl_kdf.h */
+void
+br_shake_flip(br_shake_context *sc)
+{
+ /*
+ * We apply padding and pre-XOR the value into the state. We
+ * set dptr to the end of the buffer, so that first call to
+ * shake_extract() will process the block.
+ */
+ if ((sc->dptr + 1) == sc->rate) {
+ sc->dbuf[sc->dptr ++] = 0x9F;
+ } else {
+ sc->dbuf[sc->dptr ++] = 0x1F;
+ memset(sc->dbuf + sc->dptr, 0x00, sc->rate - sc->dptr - 1);
+ sc->dbuf[sc->rate - 1] = 0x80;
+ sc->dptr = sc->rate;
+ }
+ xor_block(sc->A, sc->dbuf, sc->rate);
+}
+
+/* see bearssl_kdf.h */
+void
+br_shake_produce(br_shake_context *sc, void *out, size_t len)
+{
+ unsigned char *buf;
+ size_t dptr, rate;
+
+ buf = out;
+ dptr = sc->dptr;
+ rate = sc->rate;
+ while (len > 0) {
+ size_t clen;
+
+ if (dptr == rate) {
+ unsigned char *dbuf;
+ uint64_t *A;
+
+ A = sc->A;
+ dbuf = sc->dbuf;
+ process_block(A);
+ br_enc64le(dbuf + 0, A[ 0]);
+ br_enc64le(dbuf + 8, ~A[ 1]);
+ br_enc64le(dbuf + 16, ~A[ 2]);
+ br_enc64le(dbuf + 24, A[ 3]);
+ br_enc64le(dbuf + 32, A[ 4]);
+ br_enc64le(dbuf + 40, A[ 5]);
+ br_enc64le(dbuf + 48, A[ 6]);
+ br_enc64le(dbuf + 56, A[ 7]);
+ br_enc64le(dbuf + 64, ~A[ 8]);
+ br_enc64le(dbuf + 72, A[ 9]);
+ br_enc64le(dbuf + 80, A[10]);
+ br_enc64le(dbuf + 88, A[11]);
+ br_enc64le(dbuf + 96, ~A[12]);
+ br_enc64le(dbuf + 104, A[13]);
+ br_enc64le(dbuf + 112, A[14]);
+ br_enc64le(dbuf + 120, A[15]);
+ br_enc64le(dbuf + 128, A[16]);
+ br_enc64le(dbuf + 136, ~A[17]);
+ br_enc64le(dbuf + 144, A[18]);
+ br_enc64le(dbuf + 152, A[19]);
+ br_enc64le(dbuf + 160, ~A[20]);
+ br_enc64le(dbuf + 168, A[21]);
+ br_enc64le(dbuf + 176, A[22]);
+ br_enc64le(dbuf + 184, A[23]);
+ br_enc64le(dbuf + 192, A[24]);
+ dptr = 0;
+ }
+ clen = rate - dptr;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(buf, sc->dbuf + dptr, clen);
+ dptr += clen;
+ buf += clen;
+ len -= clen;
+ }
+ sc->dptr = dptr;
+}
diff --git a/contrib/bearssl/src/mac/hmac.c b/contrib/bearssl/src/mac/hmac.c
new file mode 100644
index 000000000000..b438798878a4
--- /dev/null
+++ b/contrib/bearssl/src/mac/hmac.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+static inline size_t
+block_size(const br_hash_class *dig)
+{
+ unsigned ls;
+
+ ls = (unsigned)(dig->desc >> BR_HASHDESC_LBLEN_OFF)
+ & BR_HASHDESC_LBLEN_MASK;
+ return (size_t)1 << ls;
+}
+
+static void
+process_key(const br_hash_class **hc, void *ks,
+ const void *key, size_t key_len, unsigned bb)
+{
+ unsigned char tmp[256];
+ size_t blen, u;
+
+ blen = block_size(*hc);
+ memcpy(tmp, key, key_len);
+ for (u = 0; u < key_len; u ++) {
+ tmp[u] ^= (unsigned char)bb;
+ }
+ memset(tmp + key_len, bb, blen - key_len);
+ (*hc)->init(hc);
+ (*hc)->update(hc, tmp, blen);
+ (*hc)->state(hc, ks);
+}
+
+/* see bearssl.h */
+void
+br_hmac_key_init(br_hmac_key_context *kc,
+ const br_hash_class *dig, const void *key, size_t key_len)
+{
+ br_hash_compat_context hc;
+ unsigned char kbuf[64];
+
+ kc->dig_vtable = dig;
+ hc.vtable = dig;
+ if (key_len > block_size(dig)) {
+ dig->init(&hc.vtable);
+ dig->update(&hc.vtable, key, key_len);
+ dig->out(&hc.vtable, kbuf);
+ key = kbuf;
+ key_len = br_digest_size(dig);
+ }
+ process_key(&hc.vtable, kc->ksi, key, key_len, 0x36);
+ process_key(&hc.vtable, kc->kso, key, key_len, 0x5C);
+}
+
+/* see bearssl.h */
+void
+br_hmac_init(br_hmac_context *ctx,
+ const br_hmac_key_context *kc, size_t out_len)
+{
+ const br_hash_class *dig;
+ size_t blen, hlen;
+
+ dig = kc->dig_vtable;
+ blen = block_size(dig);
+ dig->init(&ctx->dig.vtable);
+ dig->set_state(&ctx->dig.vtable, kc->ksi, (uint64_t)blen);
+ memcpy(ctx->kso, kc->kso, sizeof kc->kso);
+ hlen = br_digest_size(dig);
+ if (out_len > 0 && out_len < hlen) {
+ hlen = out_len;
+ }
+ ctx->out_len = hlen;
+}
+
+/* see bearssl.h */
+void
+br_hmac_update(br_hmac_context *ctx, const void *data, size_t len)
+{
+ ctx->dig.vtable->update(&ctx->dig.vtable, data, len);
+}
+
+/* see bearssl.h */
+size_t
+br_hmac_out(const br_hmac_context *ctx, void *out)
+{
+ const br_hash_class *dig;
+ br_hash_compat_context hc;
+ unsigned char tmp[64];
+ size_t blen, hlen;
+
+ dig = ctx->dig.vtable;
+ dig->out(&ctx->dig.vtable, tmp);
+ blen = block_size(dig);
+ dig->init(&hc.vtable);
+ dig->set_state(&hc.vtable, ctx->kso, (uint64_t)blen);
+ hlen = br_digest_size(dig);
+ dig->update(&hc.vtable, tmp, hlen);
+ dig->out(&hc.vtable, tmp);
+ memcpy(out, tmp, ctx->out_len);
+ return ctx->out_len;
+}
diff --git a/contrib/bearssl/src/mac/hmac_ct.c b/contrib/bearssl/src/mac/hmac_ct.c
new file mode 100644
index 000000000000..e1c1d8024ec2
--- /dev/null
+++ b/contrib/bearssl/src/mac/hmac_ct.c
@@ -0,0 +1,193 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+static inline size_t
+hash_size(const br_hash_class *dig)
+{
+ return (unsigned)(dig->desc >> BR_HASHDESC_OUT_OFF)
+ & BR_HASHDESC_OUT_MASK;
+}
+
+static inline size_t
+block_size(const br_hash_class *dig)
+{
+ unsigned ls;
+
+ ls = (unsigned)(dig->desc >> BR_HASHDESC_LBLEN_OFF)
+ & BR_HASHDESC_LBLEN_MASK;
+ return (size_t)1 << ls;
+}
+
+/* see bearssl.h */
+size_t
+br_hmac_outCT(const br_hmac_context *ctx,
+ const void *data, size_t len, size_t min_len, size_t max_len,
+ void *out)
+{
+ /*
+ * Method implemented here is inspired from the descriptions on:
+ * https://www.imperialviolet.org/2013/02/04/luckythirteen.html
+ *
+ * Principle: we input bytes one by one. We use a MUX to push
+ * padding bytes instead of data bytes when appropriate. At each
+ * block limit, we get the current hash function state: this is
+ * a potential output, since we handle MD padding ourselves.
+ *
+ * be 1 for big-endian, 0 for little-endian
+ * po minimal MD padding length
+ * bs block size (always a power of 2)
+ * hlen hash output size
+ */
+
+ const br_hash_class *dig;
+ br_hash_compat_context hc;
+ int be;
+ uint32_t po, bs;
+ uint32_t kr, km, kl, kz, u;
+ uint64_t count, ncount, bit_len;
+ unsigned char tmp1[64], tmp2[64];
+ size_t hlen;
+
+ /*
+ * Copy the current hash context.
+ */
+ hc = ctx->dig;
+
+ /*
+ * Get function-specific information.
+ */
+ dig = hc.vtable;
+ be = (dig->desc & BR_HASHDESC_MD_PADDING_BE) != 0;
+ po = 9;
+ if (dig->desc & BR_HASHDESC_MD_PADDING_128) {
+ po += 8;
+ }
+ bs = block_size(dig);
+ hlen = hash_size(dig);
+
+ /*
+ * Get current input length and compute total bit length.
+ */
+ count = dig->state(&hc.vtable, tmp1);
+ bit_len = (count + (uint64_t)len) << 3;
+
+ /*
+ * We can input the blocks that we are sure we will use.
+ * This offers better performance (no MUX for these blocks)
+ * and also ensures that the remaining lengths fit on 32 bits.
+ */
+ ncount = (count + (uint64_t)min_len) & ~(uint64_t)(bs - 1);
+ if (ncount > count) {
+ size_t zlen;
+
+ zlen = (size_t)(ncount - count);
+ dig->update(&hc.vtable, data, zlen);
+ data = (const unsigned char *)data + zlen;
+ len -= zlen;
+ max_len -= zlen;
+ count = ncount;
+ }
+
+ /*
+ * At that point:
+ * -- 'count' contains the number of bytes already processed
+ * (in total).
+ * -- We must input 'len' bytes. 'min_len' is unimportant: we
+ * used it to know how many full blocks we could process
+ * directly. Now only len and max_len matter.
+ *
+ * We compute kr, kl, kz and km.
+ * kr number of input bytes already in the current block
+ * km index of the first byte after the end of the last padding
+ * block, if length is max_len
+ * kz index of the last byte of the actual last padding block
+ * kl index of the start of the encoded length
+ *
+ * km, kz and kl are counted from the current offset in the
+ * input data.
+ */
+ kr = (uint32_t)count & (bs - 1);
+ kz = ((kr + (uint32_t)len + po + bs - 1) & ~(bs - 1)) - 1 - kr;
+ kl = kz - 7;
+ km = ((kr + (uint32_t)max_len + po + bs - 1) & ~(bs - 1)) - kr;
+
+ /*
+ * We must now process km bytes. For index u from 0 to km-1:
+ * d is from data[] if u < max_len, 0x00 otherwise
+ * e is an encoded length byte or 0x00, depending on u
+ * The tests for d and e need not be constant-time, since
+ * they relate only to u and max_len, not to the actual length.
+ *
+ * Actual input length is then:
+ * d if u < len
+ * 0x80 if u == len
+ * 0x00 if u > len and u < kl
+ * e if u >= kl
+ *
+ * Hash state is obtained whenever we reach a full block. This
+ * is the result we want if and only if u == kz.
+ */
+ memset(tmp2, 0, sizeof tmp2);
+ for (u = 0; u < km; u ++) {
+ uint32_t v;
+ uint32_t d, e, x0, x1;
+ unsigned char x[1];
+
+ d = (u < max_len) ? ((const unsigned char *)data)[u] : 0x00;
+ v = (kr + u) & (bs - 1);
+ if (v >= (bs - 8)) {
+ unsigned j;
+
+ j = (v - (bs - 8)) << 3;
+ if (be) {
+ e = (uint32_t)(bit_len >> (56 - j));
+ } else {
+ e = (uint32_t)(bit_len >> j);
+ }
+ e &= 0xFF;
+ } else {
+ e = 0x00;
+ }
+ x0 = MUX(EQ(u, (uint32_t)len), 0x80, d);
+ x1 = MUX(LT(u, kl), 0x00, e);
+ x[0] = MUX(LE(u, (uint32_t)len), x0, x1);
+ dig->update(&hc.vtable, x, 1);
+ if (v == (bs - 1)) {
+ dig->state(&hc.vtable, tmp1);
+ CCOPY(EQ(u, kz), tmp2, tmp1, hlen);
+ }
+ }
+
+ /*
+ * Inner hash output is in tmp2[]; we finish processing.
+ */
+ dig->init(&hc.vtable);
+ dig->set_state(&hc.vtable, ctx->kso, (uint64_t)bs);
+ dig->update(&hc.vtable, tmp2, hlen);
+ dig->out(&hc.vtable, tmp2);
+ memcpy(out, tmp2, ctx->out_len);
+ return ctx->out_len;
+}
diff --git a/contrib/bearssl/src/rand/aesctr_drbg.c b/contrib/bearssl/src/rand/aesctr_drbg.c
new file mode 100644
index 000000000000..8dbd501023c0
--- /dev/null
+++ b/contrib/bearssl/src/rand/aesctr_drbg.c
@@ -0,0 +1,206 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rand.h */
+void
+br_aesctr_drbg_init(br_aesctr_drbg_context *ctx,
+ const br_block_ctr_class *aesctr,
+ const void *seed, size_t len)
+{
+ unsigned char tmp[16];
+
+ ctx->vtable = &br_aesctr_drbg_vtable;
+ memset(tmp, 0, sizeof tmp);
+ aesctr->init(&ctx->sk.vtable, tmp, 16);
+ ctx->cc = 0;
+ br_aesctr_drbg_update(ctx, seed, len);
+}
+
+/* see bearssl_rand.h */
+void
+br_aesctr_drbg_generate(br_aesctr_drbg_context *ctx, void *out, size_t len)
+{
+ unsigned char *buf;
+ unsigned char iv[12];
+
+ buf = out;
+ memset(iv, 0, sizeof iv);
+ while (len > 0) {
+ size_t clen;
+
+ /*
+ * We generate data by blocks of at most 65280 bytes. This
+ * allows for unambiguously testing the counter overflow
+ * condition; also, it should work on 16-bit architectures
+ * (where 'size_t' is 16 bits only).
+ */
+ clen = len;
+ if (clen > 65280) {
+ clen = 65280;
+ }
+
+ /*
+ * We make sure that the counter won't exceed the configured
+ * limit.
+ */
+ if ((uint32_t)(ctx->cc + ((clen + 15) >> 4)) > 32768) {
+ clen = (32768 - ctx->cc) << 4;
+ if (clen > len) {
+ clen = len;
+ }
+ }
+
+ /*
+ * Run CTR.
+ */
+ memset(buf, 0, clen);
+ ctx->cc = ctx->sk.vtable->run(&ctx->sk.vtable,
+ iv, ctx->cc, buf, clen);
+ buf += clen;
+ len -= clen;
+
+ /*
+ * Every 32768 blocks, we force a state update.
+ */
+ if (ctx->cc >= 32768) {
+ br_aesctr_drbg_update(ctx, NULL, 0);
+ }
+ }
+}
+
+/* see bearssl_rand.h */
+void
+br_aesctr_drbg_update(br_aesctr_drbg_context *ctx, const void *seed, size_t len)
+{
+ /*
+ * We use a Hirose construction on AES-256 to make a hash function.
+ * Function definition:
+ * - running state consists in two 16-byte blocks G and H
+ * - initial values of G and H are conventional
+ * - there is a fixed block-sized constant C
+ * - for next data block m:
+ * set AES key to H||m
+ * G' = E(G) xor G
+ * H' = E(G xor C) xor G xor C
+ * G <- G', H <- H'
+ * - once all blocks have been processed, output is H||G
+ *
+ * Constants:
+ * G_init = B6 B6 ... B6
+ * H_init = A5 A5 ... A5
+ * C = 01 00 ... 00
+ *
+ * With this hash function h(), we compute the new state as
+ * follows:
+ * - produce a state-dependent value s as encryption of an
+ * all-one block with AES and the current key
+ * - compute the new key as the first 128 bits of h(s||seed)
+ *
+ * Original Hirose article:
+ * https://www.iacr.org/archive/fse2006/40470213/40470213.pdf
+ */
+
+ unsigned char s[16], iv[12];
+ unsigned char G[16], H[16];
+ int first;
+
+ /*
+ * Use an all-one IV to get a fresh output block that depends on the
+ * current seed.
+ */
+ memset(iv, 0xFF, sizeof iv);
+ memset(s, 0, 16);
+ ctx->sk.vtable->run(&ctx->sk.vtable, iv, 0xFFFFFFFF, s, 16);
+
+ /*
+ * Set G[] and H[] to conventional start values.
+ */
+ memset(G, 0xB6, sizeof G);
+ memset(H, 0x5A, sizeof H);
+
+ /*
+ * Process the concatenation of the current state and the seed
+ * with the custom hash function.
+ */
+ first = 1;
+ for (;;) {
+ unsigned char tmp[32];
+ unsigned char newG[16];
+
+ /*
+ * Assemble new key H||m into tmp[].
+ */
+ memcpy(tmp, H, 16);
+ if (first) {
+ memcpy(tmp + 16, s, 16);
+ first = 0;
+ } else {
+ size_t clen;
+
+ if (len == 0) {
+ break;
+ }
+ clen = len < 16 ? len : 16;
+ memcpy(tmp + 16, seed, clen);
+ memset(tmp + 16 + clen, 0, 16 - clen);
+ seed = (const unsigned char *)seed + clen;
+ len -= clen;
+ }
+ ctx->sk.vtable->init(&ctx->sk.vtable, tmp, 32);
+
+ /*
+ * Compute new G and H values.
+ */
+ memcpy(iv, G, 12);
+ memcpy(newG, G, 16);
+ ctx->sk.vtable->run(&ctx->sk.vtable, iv,
+ br_dec32be(G + 12), newG, 16);
+ iv[0] ^= 0x01;
+ memcpy(H, G, 16);
+ H[0] ^= 0x01;
+ ctx->sk.vtable->run(&ctx->sk.vtable, iv,
+ br_dec32be(G + 12), H, 16);
+ memcpy(G, newG, 16);
+ }
+
+ /*
+ * Output hash value is H||G. We truncate it to its first 128 bits,
+ * i.e. H; that's our new AES key.
+ */
+ ctx->sk.vtable->init(&ctx->sk.vtable, H, 16);
+ ctx->cc = 0;
+}
+
+/* see bearssl_rand.h */
+const br_prng_class br_aesctr_drbg_vtable = {
+ sizeof(br_aesctr_drbg_context),
+ (void (*)(const br_prng_class **, const void *, const void *, size_t))
+ &br_aesctr_drbg_init,
+ (void (*)(const br_prng_class **, void *, size_t))
+ &br_aesctr_drbg_generate,
+ (void (*)(const br_prng_class **, const void *, size_t))
+ &br_aesctr_drbg_update
+};
diff --git a/contrib/bearssl/src/rand/hmac_drbg.c b/contrib/bearssl/src/rand/hmac_drbg.c
new file mode 100644
index 000000000000..d746756df6d1
--- /dev/null
+++ b/contrib/bearssl/src/rand/hmac_drbg.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl.h */
+void
+br_hmac_drbg_init(br_hmac_drbg_context *ctx,
+ const br_hash_class *digest_class, const void *seed, size_t len)
+{
+ size_t hlen;
+
+ ctx->vtable = &br_hmac_drbg_vtable;
+ hlen = br_digest_size(digest_class);
+ memset(ctx->K, 0x00, hlen);
+ memset(ctx->V, 0x01, hlen);
+ ctx->digest_class = digest_class;
+ br_hmac_drbg_update(ctx, seed, len);
+}
+
+/* see bearssl.h */
+void
+br_hmac_drbg_generate(br_hmac_drbg_context *ctx, void *out, size_t len)
+{
+ const br_hash_class *dig;
+ br_hmac_key_context kc;
+ br_hmac_context hc;
+ size_t hlen;
+ unsigned char *buf;
+ unsigned char x;
+
+ dig = ctx->digest_class;
+ hlen = br_digest_size(dig);
+ br_hmac_key_init(&kc, dig, ctx->K, hlen);
+ buf = out;
+ while (len > 0) {
+ size_t clen;
+
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ br_hmac_out(&hc, ctx->V);
+ clen = hlen;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(buf, ctx->V, clen);
+ buf += clen;
+ len -= clen;
+ }
+
+ /*
+ * To prepare the state for the next request, we should call
+ * br_hmac_drbg_update() with an empty additional seed. However,
+ * we already have an initialized HMAC context with the right
+ * initial key, and we don't want to push another one on the
+ * stack, so we inline that update() call here.
+ */
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ x = 0x00;
+ br_hmac_update(&hc, &x, 1);
+ br_hmac_out(&hc, ctx->K);
+ br_hmac_key_init(&kc, dig, ctx->K, hlen);
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ br_hmac_out(&hc, ctx->V);
+}
+
+/* see bearssl.h */
+void
+br_hmac_drbg_update(br_hmac_drbg_context *ctx, const void *seed, size_t len)
+{
+ const br_hash_class *dig;
+ br_hmac_key_context kc;
+ br_hmac_context hc;
+ size_t hlen;
+ unsigned char x;
+
+ dig = ctx->digest_class;
+ hlen = br_digest_size(dig);
+
+ /*
+ * 1. K = HMAC(K, V || 0x00 || seed)
+ */
+ br_hmac_key_init(&kc, dig, ctx->K, hlen);
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ x = 0x00;
+ br_hmac_update(&hc, &x, 1);
+ br_hmac_update(&hc, seed, len);
+ br_hmac_out(&hc, ctx->K);
+ br_hmac_key_init(&kc, dig, ctx->K, hlen);
+
+ /*
+ * 2. V = HMAC(K, V)
+ */
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ br_hmac_out(&hc, ctx->V);
+
+ /*
+ * 3. If the additional seed is empty, then stop here.
+ */
+ if (len == 0) {
+ return;
+ }
+
+ /*
+ * 4. K = HMAC(K, V || 0x01 || seed)
+ */
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ x = 0x01;
+ br_hmac_update(&hc, &x, 1);
+ br_hmac_update(&hc, seed, len);
+ br_hmac_out(&hc, ctx->K);
+ br_hmac_key_init(&kc, dig, ctx->K, hlen);
+
+ /*
+ * 5. V = HMAC(K, V)
+ */
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, ctx->V, hlen);
+ br_hmac_out(&hc, ctx->V);
+}
+
+/* see bearssl.h */
+const br_prng_class br_hmac_drbg_vtable = {
+ sizeof(br_hmac_drbg_context),
+ (void (*)(const br_prng_class **, const void *, const void *, size_t))
+ &br_hmac_drbg_init,
+ (void (*)(const br_prng_class **, void *, size_t))
+ &br_hmac_drbg_generate,
+ (void (*)(const br_prng_class **, const void *, size_t))
+ &br_hmac_drbg_update
+};
diff --git a/contrib/bearssl/src/rand/sysrng.c b/contrib/bearssl/src/rand/sysrng.c
new file mode 100644
index 000000000000..5ddbcbea4fb9
--- /dev/null
+++ b/contrib/bearssl/src/rand/sysrng.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BR_ENABLE_INTRINSICS 1
+#include "inner.h"
+
+#if BR_USE_URANDOM
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#endif
+
+#if BR_USE_WIN32_RAND
+#include <windows.h>
+#include <wincrypt.h>
+#pragma comment(lib, "advapi32")
+#endif
+
+#if BR_RDRAND
+BR_TARGETS_X86_UP
+BR_TARGET("rdrnd")
+static int
+seeder_rdrand(const br_prng_class **ctx)
+{
+ unsigned char tmp[32];
+ size_t u;
+
+ for (u = 0; u < sizeof tmp; u += sizeof(uint32_t)) {
+ int j;
+ uint32_t x;
+
+ /*
+ * We use the 32-bit intrinsic so that code is compatible
+ * with both 32-bit and 64-bit architectures.
+ *
+ * Intel recommends trying at least 10 times in case of
+ * failure.
+ */
+ for (j = 0; j < 10; j ++) {
+ if (_rdrand32_step(&x)) {
+ goto next_word;
+ }
+ }
+ return 0;
+ next_word:
+ br_enc32le(tmp + u, x);
+ }
+ (*ctx)->update(ctx, tmp, sizeof tmp);
+ return 1;
+}
+BR_TARGETS_X86_DOWN
+
+static int
+rdrand_supported(void)
+{
+ /*
+ * The RDRND support is bit 30 of ECX, as returned by CPUID.
+ */
+ return br_cpuid(0, 0, 0x40000000, 0);
+}
+
+#endif
+
+#if BR_USE_URANDOM
+static int
+seeder_urandom(const br_prng_class **ctx)
+{
+ int f;
+
+ f = open("/dev/urandom", O_RDONLY);
+ if (f >= 0) {
+ unsigned char tmp[32];
+ size_t u;
+
+ for (u = 0; u < sizeof tmp;) {
+ ssize_t len;
+
+ len = read(f, tmp + u, (sizeof tmp) - u);
+ if (len < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ break;
+ }
+ u += (size_t)len;
+ }
+ close(f);
+ if (u == sizeof tmp) {
+ (*ctx)->update(ctx, tmp, sizeof tmp);
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif
+
+#if BR_USE_WIN32_RAND
+static int
+seeder_win32(const br_prng_class **ctx)
+{
+ HCRYPTPROV hp;
+
+ if (CryptAcquireContext(&hp, 0, 0, PROV_RSA_FULL,
+ CRYPT_VERIFYCONTEXT | CRYPT_SILENT))
+ {
+ BYTE buf[32];
+ BOOL r;
+
+ r = CryptGenRandom(hp, sizeof buf, buf);
+ CryptReleaseContext(hp, 0);
+ if (r) {
+ (*ctx)->update(ctx, buf, sizeof buf);
+ return 1;
+ }
+ }
+ return 0;
+}
+#endif
+
+/* see bearssl_rand.h */
+br_prng_seeder
+br_prng_seeder_system(const char **name)
+{
+#if BR_RDRAND
+ if (rdrand_supported()) {
+ if (name != NULL) {
+ *name = "rdrand";
+ }
+ return &seeder_rdrand;
+ }
+#endif
+#if BR_USE_URANDOM
+ if (name != NULL) {
+ *name = "urandom";
+ }
+ return &seeder_urandom;
+#elif BR_USE_WIN32_RAND
+ if (name != NULL) {
+ *name = "win32";
+ }
+ return &seeder_win32;
+#else
+ if (name != NULL) {
+ *name = "none";
+ }
+ return 0;
+#endif
+}
diff --git a/contrib/bearssl/src/rsa/rsa_default_keygen.c b/contrib/bearssl/src/rsa/rsa_default_keygen.c
new file mode 100644
index 000000000000..f2e83c8dadc6
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_default_keygen.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+br_rsa_keygen
+br_rsa_keygen_get_default(void)
+{
+#if BR_INT128 || BR_UMUL128
+ return &br_rsa_i62_keygen;
+#elif BR_LOMUL
+ return &br_rsa_i15_keygen;
+#else
+ return &br_rsa_i31_keygen;
+#endif
+}
diff --git a/contrib/bearssl/src/rsa/rsa_default_modulus.c b/contrib/bearssl/src/rsa/rsa_default_modulus.c
new file mode 100644
index 000000000000..57d4be56cd15
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_default_modulus.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+br_rsa_compute_modulus
+br_rsa_compute_modulus_get_default(void)
+{
+#if BR_LOMUL
+ return &br_rsa_i15_compute_modulus;
+#else
+ return &br_rsa_i31_compute_modulus;
+#endif
+}
diff --git a/contrib/bearssl/src/rsa/rsa_default_oaep_decrypt.c b/contrib/bearssl/src/rsa/rsa_default_oaep_decrypt.c
new file mode 100644
index 000000000000..7345d64ec3f0
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_default_oaep_decrypt.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+br_rsa_oaep_decrypt
+br_rsa_oaep_decrypt_get_default(void)
+{
+#if BR_INT128 || BR_UMUL128
+ return &br_rsa_i62_oaep_decrypt;
+#elif BR_LOMUL
+ return &br_rsa_i15_oaep_decrypt;
+#else
+ return &br_rsa_i31_oaep_decrypt;
+#endif
+}
diff --git a/contrib/bearssl/src/rsa/rsa_default_oaep_encrypt.c b/contrib/bearssl/src/rsa/rsa_default_oaep_encrypt.c
new file mode 100644
index 000000000000..ae33fcc6cdff
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_default_oaep_encrypt.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+br_rsa_oaep_encrypt
+br_rsa_oaep_encrypt_get_default(void)
+{
+#if BR_INT128 || BR_UMUL128
+ return &br_rsa_i62_oaep_encrypt;
+#elif BR_LOMUL
+ return &br_rsa_i15_oaep_encrypt;
+#else
+ return &br_rsa_i31_oaep_encrypt;
+#endif
+}
diff --git a/contrib/bearssl/src/rsa/rsa_default_pkcs1_sign.c b/contrib/bearssl/src/rsa/rsa_default_pkcs1_sign.c
new file mode 100644
index 000000000000..e926704f5adb
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_default_pkcs1_sign.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+br_rsa_pkcs1_sign
+br_rsa_pkcs1_sign_get_default(void)
+{
+#if BR_INT128 || BR_UMUL128
+ return &br_rsa_i62_pkcs1_sign;
+#elif BR_LOMUL
+ return &br_rsa_i15_pkcs1_sign;
+#else
+ return &br_rsa_i31_pkcs1_sign;
+#endif
+}
diff --git a/contrib/bearssl/src/rsa/rsa_default_pkcs1_vrfy.c b/contrib/bearssl/src/rsa/rsa_default_pkcs1_vrfy.c
new file mode 100644
index 000000000000..b3dbeb7bf5f7
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_default_pkcs1_vrfy.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+br_rsa_pkcs1_vrfy
+br_rsa_pkcs1_vrfy_get_default(void)
+{
+#if BR_INT128 || BR_UMUL128
+ return &br_rsa_i62_pkcs1_vrfy;
+#elif BR_LOMUL
+ return &br_rsa_i15_pkcs1_vrfy;
+#else
+ return &br_rsa_i31_pkcs1_vrfy;
+#endif
+}
diff --git a/contrib/bearssl/src/rsa/rsa_default_priv.c b/contrib/bearssl/src/rsa/rsa_default_priv.c
new file mode 100644
index 000000000000..bb0b2c008061
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_default_priv.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+br_rsa_private
+br_rsa_private_get_default(void)
+{
+#if BR_INT128 || BR_UMUL128
+ return &br_rsa_i62_private;
+#elif BR_LOMUL
+ return &br_rsa_i15_private;
+#else
+ return &br_rsa_i31_private;
+#endif
+}
diff --git a/contrib/bearssl/src/rsa/rsa_default_privexp.c b/contrib/bearssl/src/rsa/rsa_default_privexp.c
new file mode 100644
index 000000000000..cda45559be64
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_default_privexp.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+br_rsa_compute_privexp
+br_rsa_compute_privexp_get_default(void)
+{
+#if BR_LOMUL
+ return &br_rsa_i15_compute_privexp;
+#else
+ return &br_rsa_i31_compute_privexp;
+#endif
+}
diff --git a/contrib/bearssl/src/rsa/rsa_default_pss_sign.c b/contrib/bearssl/src/rsa/rsa_default_pss_sign.c
new file mode 100644
index 000000000000..ce4f3e075492
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_default_pss_sign.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+br_rsa_pss_sign
+br_rsa_pss_sign_get_default(void)
+{
+#if BR_INT128 || BR_UMUL128
+ return &br_rsa_i62_pss_sign;
+#elif BR_LOMUL
+ return &br_rsa_i15_pss_sign;
+#else
+ return &br_rsa_i31_pss_sign;
+#endif
+}
diff --git a/contrib/bearssl/src/rsa/rsa_default_pss_vrfy.c b/contrib/bearssl/src/rsa/rsa_default_pss_vrfy.c
new file mode 100644
index 000000000000..e3a9ad9fc783
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_default_pss_vrfy.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+br_rsa_pss_vrfy
+br_rsa_pss_vrfy_get_default(void)
+{
+#if BR_INT128 || BR_UMUL128
+ return &br_rsa_i62_pss_vrfy;
+#elif BR_LOMUL
+ return &br_rsa_i15_pss_vrfy;
+#else
+ return &br_rsa_i31_pss_vrfy;
+#endif
+}
diff --git a/contrib/bearssl/src/rsa/rsa_default_pub.c b/contrib/bearssl/src/rsa/rsa_default_pub.c
new file mode 100644
index 000000000000..a1f03ef381e3
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_default_pub.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+br_rsa_public
+br_rsa_public_get_default(void)
+{
+#if BR_INT128 || BR_UMUL128
+ return &br_rsa_i62_public;
+#elif BR_LOMUL
+ return &br_rsa_i15_public;
+#else
+ return &br_rsa_i31_public;
+#endif
+}
diff --git a/contrib/bearssl/src/rsa/rsa_default_pubexp.c b/contrib/bearssl/src/rsa/rsa_default_pubexp.c
new file mode 100644
index 000000000000..47bc00058638
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_default_pubexp.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+br_rsa_compute_pubexp
+br_rsa_compute_pubexp_get_default(void)
+{
+#if BR_LOMUL
+ return &br_rsa_i15_compute_pubexp;
+#else
+ return &br_rsa_i31_compute_pubexp;
+#endif
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i15_keygen.c b/contrib/bearssl/src/rsa/rsa_i15_keygen.c
new file mode 100644
index 000000000000..1c011fe0dcdf
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i15_keygen.c
@@ -0,0 +1,583 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * Make a random integer of the provided size. The size is encoded.
+ * The header word is untouched.
+ */
+static void
+mkrand(const br_prng_class **rng, uint16_t *x, uint32_t esize)
+{
+ size_t u, len;
+ unsigned m;
+
+ len = (esize + 15) >> 4;
+ (*rng)->generate(rng, x + 1, len * sizeof(uint16_t));
+ for (u = 1; u < len; u ++) {
+ x[u] &= 0x7FFF;
+ }
+ m = esize & 15;
+ if (m == 0) {
+ x[len] &= 0x7FFF;
+ } else {
+ x[len] &= 0x7FFF >> (15 - m);
+ }
+}
+
+/*
+ * This is the big-endian unsigned representation of the product of
+ * all small primes from 13 to 1481.
+ */
+static const unsigned char SMALL_PRIMES[] = {
+ 0x2E, 0xAB, 0x92, 0xD1, 0x8B, 0x12, 0x47, 0x31, 0x54, 0x0A,
+ 0x99, 0x5D, 0x25, 0x5E, 0xE2, 0x14, 0x96, 0x29, 0x1E, 0xB7,
+ 0x78, 0x70, 0xCC, 0x1F, 0xA5, 0xAB, 0x8D, 0x72, 0x11, 0x37,
+ 0xFB, 0xD8, 0x1E, 0x3F, 0x5B, 0x34, 0x30, 0x17, 0x8B, 0xE5,
+ 0x26, 0x28, 0x23, 0xA1, 0x8A, 0xA4, 0x29, 0xEA, 0xFD, 0x9E,
+ 0x39, 0x60, 0x8A, 0xF3, 0xB5, 0xA6, 0xEB, 0x3F, 0x02, 0xB6,
+ 0x16, 0xC3, 0x96, 0x9D, 0x38, 0xB0, 0x7D, 0x82, 0x87, 0x0C,
+ 0xF7, 0xBE, 0x24, 0xE5, 0x5F, 0x41, 0x04, 0x79, 0x76, 0x40,
+ 0xE7, 0x00, 0x22, 0x7E, 0xB5, 0x85, 0x7F, 0x8D, 0x01, 0x50,
+ 0xE9, 0xD3, 0x29, 0x42, 0x08, 0xB3, 0x51, 0x40, 0x7B, 0xD7,
+ 0x8D, 0xCC, 0x10, 0x01, 0x64, 0x59, 0x28, 0xB6, 0x53, 0xF3,
+ 0x50, 0x4E, 0xB1, 0xF2, 0x58, 0xCD, 0x6E, 0xF5, 0x56, 0x3E,
+ 0x66, 0x2F, 0xD7, 0x07, 0x7F, 0x52, 0x4C, 0x13, 0x24, 0xDC,
+ 0x8E, 0x8D, 0xCC, 0xED, 0x77, 0xC4, 0x21, 0xD2, 0xFD, 0x08,
+ 0xEA, 0xD7, 0xC0, 0x5C, 0x13, 0x82, 0x81, 0x31, 0x2F, 0x2B,
+ 0x08, 0xE4, 0x80, 0x04, 0x7A, 0x0C, 0x8A, 0x3C, 0xDC, 0x22,
+ 0xE4, 0x5A, 0x7A, 0xB0, 0x12, 0x5E, 0x4A, 0x76, 0x94, 0x77,
+ 0xC2, 0x0E, 0x92, 0xBA, 0x8A, 0xA0, 0x1F, 0x14, 0x51, 0x1E,
+ 0x66, 0x6C, 0x38, 0x03, 0x6C, 0xC7, 0x4A, 0x4B, 0x70, 0x80,
+ 0xAF, 0xCA, 0x84, 0x51, 0xD8, 0xD2, 0x26, 0x49, 0xF5, 0xA8,
+ 0x5E, 0x35, 0x4B, 0xAC, 0xCE, 0x29, 0x92, 0x33, 0xB7, 0xA2,
+ 0x69, 0x7D, 0x0C, 0xE0, 0x9C, 0xDB, 0x04, 0xD6, 0xB4, 0xBC,
+ 0x39, 0xD7, 0x7F, 0x9E, 0x9D, 0x78, 0x38, 0x7F, 0x51, 0x54,
+ 0x50, 0x8B, 0x9E, 0x9C, 0x03, 0x6C, 0xF5, 0x9D, 0x2C, 0x74,
+ 0x57, 0xF0, 0x27, 0x2A, 0xC3, 0x47, 0xCA, 0xB9, 0xD7, 0x5C,
+ 0xFF, 0xC2, 0xAC, 0x65, 0x4E, 0xBD
+};
+
+/*
+ * We need temporary values for at least 7 integers of the same size
+ * as a factor (including header word); more space helps with performance
+ * (in modular exponentiations), but we much prefer to remain under
+ * 2 kilobytes in total, to save stack space. The macro TEMPS below
+ * exceeds 1024 (which is a count in 16-bit words) when BR_MAX_RSA_SIZE
+ * is greater than 4350 (default value is 4096, so the 2-kB limit is
+ * maintained unless BR_MAX_RSA_SIZE was modified).
+ */
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+#define TEMPS MAX(1024, 7 * ((((BR_MAX_RSA_SIZE + 1) >> 1) + 29) / 15))
+
+/*
+ * Perform trial division on a candidate prime. This computes
+ * y = SMALL_PRIMES mod x, then tries to compute y/y mod x. The
+ * br_i15_moddiv() function will report an error if y is not invertible
+ * modulo x. Returned value is 1 on success (none of the small primes
+ * divides x), 0 on error (a non-trivial GCD is obtained).
+ *
+ * This function assumes that x is odd.
+ */
+static uint32_t
+trial_divisions(const uint16_t *x, uint16_t *t)
+{
+ uint16_t *y;
+ uint16_t x0i;
+
+ y = t;
+ t += 1 + ((x[0] + 15) >> 4);
+ x0i = br_i15_ninv15(x[1]);
+ br_i15_decode_reduce(y, SMALL_PRIMES, sizeof SMALL_PRIMES, x);
+ return br_i15_moddiv(y, y, x, x0i, t);
+}
+
+/*
+ * Perform n rounds of Miller-Rabin on the candidate prime x. This
+ * function assumes that x = 3 mod 4.
+ *
+ * Returned value is 1 on success (all rounds completed successfully),
+ * 0 otherwise.
+ */
+static uint32_t
+miller_rabin(const br_prng_class **rng, const uint16_t *x, int n,
+ uint16_t *t, size_t tlen)
+{
+ /*
+ * Since x = 3 mod 4, the Miller-Rabin test is simple:
+ * - get a random base a (such that 1 < a < x-1)
+ * - compute z = a^((x-1)/2) mod x
+ * - if z != 1 and z != x-1, the number x is composite
+ *
+ * We generate bases 'a' randomly with a size which is
+ * one bit less than x, which ensures that a < x-1. It
+ * is not useful to verify that a > 1 because the probability
+ * that we get a value a equal to 0 or 1 is much smaller
+ * than the probability of our Miller-Rabin tests not to
+ * detect a composite, which is already quite smaller than the
+ * probability of the hardware misbehaving and return a
+ * composite integer because of some glitch (e.g. bad RAM
+ * or ill-timed cosmic ray).
+ */
+ unsigned char *xm1d2;
+ size_t xlen, xm1d2_len, xm1d2_len_u16, u;
+ uint32_t asize;
+ unsigned cc;
+ uint16_t x0i;
+
+ /*
+ * Compute (x-1)/2 (encoded).
+ */
+ xm1d2 = (unsigned char *)t;
+ xm1d2_len = ((x[0] - (x[0] >> 4)) + 7) >> 3;
+ br_i15_encode(xm1d2, xm1d2_len, x);
+ cc = 0;
+ for (u = 0; u < xm1d2_len; u ++) {
+ unsigned w;
+
+ w = xm1d2[u];
+ xm1d2[u] = (unsigned char)((w >> 1) | cc);
+ cc = w << 7;
+ }
+
+ /*
+ * We used some words of the provided buffer for (x-1)/2.
+ */
+ xm1d2_len_u16 = (xm1d2_len + 1) >> 1;
+ t += xm1d2_len_u16;
+ tlen -= xm1d2_len_u16;
+
+ xlen = (x[0] + 15) >> 4;
+ asize = x[0] - 1 - EQ0(x[0] & 15);
+ x0i = br_i15_ninv15(x[1]);
+ while (n -- > 0) {
+ uint16_t *a;
+ uint32_t eq1, eqm1;
+
+ /*
+ * Generate a random base. We don't need the base to be
+ * really uniform modulo x, so we just get a random
+ * number which is one bit shorter than x.
+ */
+ a = t;
+ a[0] = x[0];
+ a[xlen] = 0;
+ mkrand(rng, a, asize);
+
+ /*
+ * Compute a^((x-1)/2) mod x. We assume here that the
+ * function will not fail (the temporary array is large
+ * enough).
+ */
+ br_i15_modpow_opt(a, xm1d2, xm1d2_len,
+ x, x0i, t + 1 + xlen, tlen - 1 - xlen);
+
+ /*
+ * We must obtain either 1 or x-1. Note that x is odd,
+ * hence x-1 differs from x only in its low word (no
+ * carry).
+ */
+ eq1 = a[1] ^ 1;
+ eqm1 = a[1] ^ (x[1] - 1);
+ for (u = 2; u <= xlen; u ++) {
+ eq1 |= a[u];
+ eqm1 |= a[u] ^ x[u];
+ }
+
+ if ((EQ0(eq1) | EQ0(eqm1)) == 0) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * Create a random prime of the provided size. 'size' is the _encoded_
+ * bit length. The two top bits and the two bottom bits are set to 1.
+ */
+static void
+mkprime(const br_prng_class **rng, uint16_t *x, uint32_t esize,
+ uint32_t pubexp, uint16_t *t, size_t tlen)
+{
+ size_t len;
+
+ x[0] = esize;
+ len = (esize + 15) >> 4;
+ for (;;) {
+ size_t u;
+ uint32_t m3, m5, m7, m11;
+ int rounds;
+
+ /*
+ * Generate random bits. We force the two top bits and the
+ * two bottom bits to 1.
+ */
+ mkrand(rng, x, esize);
+ if ((esize & 15) == 0) {
+ x[len] |= 0x6000;
+ } else if ((esize & 15) == 1) {
+ x[len] |= 0x0001;
+ x[len - 1] |= 0x4000;
+ } else {
+ x[len] |= 0x0003 << ((esize & 15) - 2);
+ }
+ x[1] |= 0x0003;
+
+ /*
+ * Trial division with low primes (3, 5, 7 and 11). We
+ * use the following properties:
+ *
+ * 2^2 = 1 mod 3
+ * 2^4 = 1 mod 5
+ * 2^3 = 1 mod 7
+ * 2^10 = 1 mod 11
+ */
+ m3 = 0;
+ m5 = 0;
+ m7 = 0;
+ m11 = 0;
+ for (u = 0; u < len; u ++) {
+ uint32_t w;
+
+ w = x[1 + u];
+ m3 += w << (u & 1);
+ m3 = (m3 & 0xFF) + (m3 >> 8);
+ m5 += w << ((4 - u) & 3);
+ m5 = (m5 & 0xFF) + (m5 >> 8);
+ m7 += w;
+ m7 = (m7 & 0x1FF) + (m7 >> 9);
+ m11 += w << (5 & -(u & 1));
+ m11 = (m11 & 0x3FF) + (m11 >> 10);
+ }
+
+ /*
+ * Maximum values of m* at this point:
+ * m3: 511
+ * m5: 2310
+ * m7: 510
+ * m11: 2047
+ * We use the same properties to make further reductions.
+ */
+
+ m3 = (m3 & 0x0F) + (m3 >> 4); /* max: 46 */
+ m3 = (m3 & 0x0F) + (m3 >> 4); /* max: 16 */
+ m3 = ((m3 * 43) >> 5) & 3;
+
+ m5 = (m5 & 0xFF) + (m5 >> 8); /* max: 263 */
+ m5 = (m5 & 0x0F) + (m5 >> 4); /* max: 30 */
+ m5 = (m5 & 0x0F) + (m5 >> 4); /* max: 15 */
+ m5 -= 10 & -GT(m5, 9);
+ m5 -= 5 & -GT(m5, 4);
+
+ m7 = (m7 & 0x3F) + (m7 >> 6); /* max: 69 */
+ m7 = (m7 & 7) + (m7 >> 3); /* max: 14 */
+ m7 = ((m7 * 147) >> 7) & 7;
+
+ /*
+ * 2^5 = 32 = -1 mod 11.
+ */
+ m11 = (m11 & 0x1F) + 66 - (m11 >> 5); /* max: 97 */
+ m11 -= 88 & -GT(m11, 87);
+ m11 -= 44 & -GT(m11, 43);
+ m11 -= 22 & -GT(m11, 21);
+ m11 -= 11 & -GT(m11, 10);
+
+ /*
+ * If any of these modulo is 0, then the candidate is
+ * not prime. Also, if pubexp is 3, 5, 7 or 11, and the
+ * corresponding modulus is 1, then the candidate must
+ * be rejected, because we need e to be invertible
+ * modulo p-1. We can use simple comparisons here
+ * because they won't leak information on a candidate
+ * that we keep, only on one that we reject (and is thus
+ * not secret).
+ */
+ if (m3 == 0 || m5 == 0 || m7 == 0 || m11 == 0) {
+ continue;
+ }
+ if ((pubexp == 3 && m3 == 1)
+ || (pubexp == 5 && m5 == 5)
+ || (pubexp == 7 && m5 == 7)
+ || (pubexp == 11 && m5 == 11))
+ {
+ continue;
+ }
+
+ /*
+ * More trial divisions.
+ */
+ if (!trial_divisions(x, t)) {
+ continue;
+ }
+
+ /*
+ * Miller-Rabin algorithm. Since we selected a random
+ * integer, not a maliciously crafted integer, we can use
+ * relatively few rounds to lower the risk of a false
+ * positive (i.e. declaring prime a non-prime) under
+ * 2^(-80). It is not useful to lower the probability much
+ * below that, since that would be substantially below
+ * the probability of the hardware misbehaving. Sufficient
+ * numbers of rounds are extracted from the Handbook of
+ * Applied Cryptography, note 4.49 (page 149).
+ *
+ * Since we work on the encoded size (esize), we need to
+ * compare with encoded thresholds.
+ */
+ if (esize < 320) {
+ rounds = 12;
+ } else if (esize < 480) {
+ rounds = 9;
+ } else if (esize < 693) {
+ rounds = 6;
+ } else if (esize < 906) {
+ rounds = 4;
+ } else if (esize < 1386) {
+ rounds = 3;
+ } else {
+ rounds = 2;
+ }
+
+ if (miller_rabin(rng, x, rounds, t, tlen)) {
+ return;
+ }
+ }
+}
+
+/*
+ * Let p be a prime (p > 2^33, p = 3 mod 4). Let m = (p-1)/2, provided
+ * as parameter (with announced bit length equal to that of p). This
+ * function computes d = 1/e mod p-1 (for an odd integer e). Returned
+ * value is 1 on success, 0 on error (an error is reported if e is not
+ * invertible modulo p-1).
+ *
+ * The temporary buffer (t) must have room for at least 4 integers of
+ * the size of p.
+ */
+static uint32_t
+invert_pubexp(uint16_t *d, const uint16_t *m, uint32_t e, uint16_t *t)
+{
+ uint16_t *f;
+ uint32_t r;
+
+ f = t;
+ t += 1 + ((m[0] + 15) >> 4);
+
+ /*
+ * Compute d = 1/e mod m. Since p = 3 mod 4, m is odd.
+ */
+ br_i15_zero(d, m[0]);
+ d[1] = 1;
+ br_i15_zero(f, m[0]);
+ f[1] = e & 0x7FFF;
+ f[2] = (e >> 15) & 0x7FFF;
+ f[3] = e >> 30;
+ r = br_i15_moddiv(d, f, m, br_i15_ninv15(m[1]), t);
+
+ /*
+ * We really want d = 1/e mod p-1, with p = 2m. By the CRT,
+ * the result is either the d we got, or d + m.
+ *
+ * Let's write e*d = 1 + k*m, for some integer k. Integers e
+ * and m are odd. If d is odd, then e*d is odd, which implies
+ * that k must be even; in that case, e*d = 1 + (k/2)*2m, and
+ * thus d is already fine. Conversely, if d is even, then k
+ * is odd, and we must add m to d in order to get the correct
+ * result.
+ */
+ br_i15_add(d, m, (uint32_t)(1 - (d[1] & 1)));
+
+ return r;
+}
+
+/*
+ * Swap two buffers in RAM. They must be disjoint.
+ */
+static void
+bufswap(void *b1, void *b2, size_t len)
+{
+ size_t u;
+ unsigned char *buf1, *buf2;
+
+ buf1 = b1;
+ buf2 = b2;
+ for (u = 0; u < len; u ++) {
+ unsigned w;
+
+ w = buf1[u];
+ buf1[u] = buf2[u];
+ buf2[u] = w;
+ }
+}
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i15_keygen(const br_prng_class **rng,
+ br_rsa_private_key *sk, void *kbuf_priv,
+ br_rsa_public_key *pk, void *kbuf_pub,
+ unsigned size, uint32_t pubexp)
+{
+ uint32_t esize_p, esize_q;
+ size_t plen, qlen, tlen;
+ uint16_t *p, *q, *t;
+ uint16_t tmp[TEMPS];
+ uint32_t r;
+
+ if (size < BR_MIN_RSA_SIZE || size > BR_MAX_RSA_SIZE) {
+ return 0;
+ }
+ if (pubexp == 0) {
+ pubexp = 3;
+ } else if (pubexp == 1 || (pubexp & 1) == 0) {
+ return 0;
+ }
+
+ esize_p = (size + 1) >> 1;
+ esize_q = size - esize_p;
+ sk->n_bitlen = size;
+ sk->p = kbuf_priv;
+ sk->plen = (esize_p + 7) >> 3;
+ sk->q = sk->p + sk->plen;
+ sk->qlen = (esize_q + 7) >> 3;
+ sk->dp = sk->q + sk->qlen;
+ sk->dplen = sk->plen;
+ sk->dq = sk->dp + sk->dplen;
+ sk->dqlen = sk->qlen;
+ sk->iq = sk->dq + sk->dqlen;
+ sk->iqlen = sk->plen;
+
+ if (pk != NULL) {
+ pk->n = kbuf_pub;
+ pk->nlen = (size + 7) >> 3;
+ pk->e = pk->n + pk->nlen;
+ pk->elen = 4;
+ br_enc32be(pk->e, pubexp);
+ while (*pk->e == 0) {
+ pk->e ++;
+ pk->elen --;
+ }
+ }
+
+ /*
+ * We now switch to encoded sizes.
+ *
+ * floor((x * 17477) / (2^18)) is equal to floor(x/15) for all
+ * integers x from 0 to 23833.
+ */
+ esize_p += MUL15(esize_p, 17477) >> 18;
+ esize_q += MUL15(esize_q, 17477) >> 18;
+ plen = (esize_p + 15) >> 4;
+ qlen = (esize_q + 15) >> 4;
+ p = tmp;
+ q = p + 1 + plen;
+ t = q + 1 + qlen;
+ tlen = ((sizeof tmp) / sizeof(uint16_t)) - (2 + plen + qlen);
+
+ /*
+ * When looking for primes p and q, we temporarily divide
+ * candidates by 2, in order to compute the inverse of the
+ * public exponent.
+ */
+
+ for (;;) {
+ mkprime(rng, p, esize_p, pubexp, t, tlen);
+ br_i15_rshift(p, 1);
+ if (invert_pubexp(t, p, pubexp, t + 1 + plen)) {
+ br_i15_add(p, p, 1);
+ p[1] |= 1;
+ br_i15_encode(sk->p, sk->plen, p);
+ br_i15_encode(sk->dp, sk->dplen, t);
+ break;
+ }
+ }
+
+ for (;;) {
+ mkprime(rng, q, esize_q, pubexp, t, tlen);
+ br_i15_rshift(q, 1);
+ if (invert_pubexp(t, q, pubexp, t + 1 + qlen)) {
+ br_i15_add(q, q, 1);
+ q[1] |= 1;
+ br_i15_encode(sk->q, sk->qlen, q);
+ br_i15_encode(sk->dq, sk->dqlen, t);
+ break;
+ }
+ }
+
+ /*
+ * If p and q have the same size, then it is possible that q > p
+ * (when the target modulus size is odd, we generate p with a
+ * greater bit length than q). If q > p, we want to swap p and q
+ * (and also dp and dq) for two reasons:
+ * - The final step below (inversion of q modulo p) is easier if
+ * p > q.
+ * - While BearSSL's RSA code is perfectly happy with RSA keys such
+ * that p < q, some other implementations have restrictions and
+ * require p > q.
+ *
+ * Note that we can do a simple non-constant-time swap here,
+ * because the only information we leak here is that we insist on
+ * returning p and q such that p > q, which is not a secret.
+ */
+ if (esize_p == esize_q && br_i15_sub(p, q, 0) == 1) {
+ bufswap(p, q, (1 + plen) * sizeof *p);
+ bufswap(sk->p, sk->q, sk->plen);
+ bufswap(sk->dp, sk->dq, sk->dplen);
+ }
+
+ /*
+ * We have produced p, q, dp and dq. We can now compute iq = 1/d mod p.
+ *
+ * We ensured that p >= q, so this is just a matter of updating the
+ * header word for q (and possibly adding an extra word).
+ *
+ * Theoretically, the call below may fail, in case we were
+ * extraordinarily unlucky, and p = q. Another failure case is if
+ * Miller-Rabin failed us _twice_, and p and q are non-prime and
+ * have a factor is common. We report the error mostly because it
+ * is cheap and we can, but in practice this never happens (or, at
+ * least, it happens way less often than hardware glitches).
+ */
+ q[0] = p[0];
+ if (plen > qlen) {
+ q[plen] = 0;
+ t ++;
+ tlen --;
+ }
+ br_i15_zero(t, p[0]);
+ t[1] = 1;
+ r = br_i15_moddiv(t, q, p, br_i15_ninv15(p[1]), t + 1 + plen);
+ br_i15_encode(sk->iq, sk->iqlen, t);
+
+ /*
+ * Compute the public modulus too, if required.
+ */
+ if (pk != NULL) {
+ br_i15_zero(t, p[0]);
+ br_i15_mulacc(t, p, q);
+ br_i15_encode(pk->n, pk->nlen, t);
+ }
+
+ return r;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i15_modulus.c b/contrib/bearssl/src/rsa/rsa_i15_modulus.c
new file mode 100644
index 000000000000..d61c7949c6fc
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i15_modulus.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+size_t
+br_rsa_i15_compute_modulus(void *n, const br_rsa_private_key *sk)
+{
+ uint16_t tmp[2 * ((BR_MAX_RSA_SIZE + 14) / 15) + 5];
+ uint16_t *t, *p, *q;
+ const unsigned char *pbuf, *qbuf;
+ size_t nlen, plen, qlen, tlen;
+
+ /*
+ * Compute actual byte and lengths for p and q.
+ */
+ pbuf = sk->p;
+ plen = sk->plen;
+ while (plen > 0 && *pbuf == 0) {
+ pbuf ++;
+ plen --;
+ }
+ qbuf = sk->q;
+ qlen = sk->qlen;
+ while (qlen > 0 && *qbuf == 0) {
+ qbuf ++;
+ qlen --;
+ }
+
+ t = tmp;
+ tlen = (sizeof tmp) / (sizeof tmp[0]);
+
+ /*
+ * Decode p.
+ */
+ if ((15 * tlen) < (plen << 3) + 15) {
+ return 0;
+ }
+ br_i15_decode(t, pbuf, plen);
+ p = t;
+ plen = (p[0] + 31) >> 4;
+ t += plen;
+ tlen -= plen;
+
+ /*
+ * Decode q.
+ */
+ if ((15 * tlen) < (qlen << 3) + 15) {
+ return 0;
+ }
+ br_i15_decode(t, qbuf, qlen);
+ q = t;
+ qlen = (q[0] + 31) >> 4;
+ t += qlen;
+ tlen -= qlen;
+
+ /*
+ * Computation can proceed only if we have enough room for the
+ * modulus.
+ */
+ if (tlen < (plen + qlen + 1)) {
+ return 0;
+ }
+
+ /*
+ * Private key already contains the modulus bit length, from which
+ * we can infer the output length. Even if n is NULL, we still had
+ * to decode p and q to make sure that the product can be computed.
+ */
+ nlen = (sk->n_bitlen + 7) >> 3;
+ if (n != NULL) {
+ br_i15_zero(t, p[0]);
+ br_i15_mulacc(t, p, q);
+ br_i15_encode(n, nlen, t);
+ }
+ return nlen;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i15_oaep_decrypt.c b/contrib/bearssl/src/rsa/rsa_i15_oaep_decrypt.c
new file mode 100644
index 000000000000..927eecd85fc8
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i15_oaep_decrypt.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i15_oaep_decrypt(const br_hash_class *dig,
+ const void *label, size_t label_len,
+ const br_rsa_private_key *sk, void *data, size_t *len)
+{
+ uint32_t r;
+
+ if (*len != ((sk->n_bitlen + 7) >> 3)) {
+ return 0;
+ }
+ r = br_rsa_i15_private(data, sk);
+ r &= br_rsa_oaep_unpad(dig, label, label_len, data, len);
+ return r;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i15_oaep_encrypt.c b/contrib/bearssl/src/rsa/rsa_i15_oaep_encrypt.c
new file mode 100644
index 000000000000..b9a6cfa488e2
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i15_oaep_encrypt.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+size_t
+br_rsa_i15_oaep_encrypt(
+ const br_prng_class **rnd, const br_hash_class *dig,
+ const void *label, size_t label_len,
+ const br_rsa_public_key *pk,
+ void *dst, size_t dst_max_len,
+ const void *src, size_t src_len)
+{
+ size_t dlen;
+
+ dlen = br_rsa_oaep_pad(rnd, dig, label, label_len,
+ pk, dst, dst_max_len, src, src_len);
+ if (dlen == 0) {
+ return 0;
+ }
+ return dlen & -(size_t)br_rsa_i15_public(dst, dlen, pk);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i15_pkcs1_sign.c b/contrib/bearssl/src/rsa/rsa_i15_pkcs1_sign.c
new file mode 100644
index 000000000000..f519423d3cc0
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i15_pkcs1_sign.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i15_pkcs1_sign(const unsigned char *hash_oid,
+ const unsigned char *hash, size_t hash_len,
+ const br_rsa_private_key *sk, unsigned char *x)
+{
+ if (!br_rsa_pkcs1_sig_pad(hash_oid, hash, hash_len, sk->n_bitlen, x)) {
+ return 0;
+ }
+ return br_rsa_i15_private(x, sk);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i15_pkcs1_vrfy.c b/contrib/bearssl/src/rsa/rsa_i15_pkcs1_vrfy.c
new file mode 100644
index 000000000000..2c3518496567
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i15_pkcs1_vrfy.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i15_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)
+{
+ unsigned char sig[BR_MAX_RSA_SIZE >> 3];
+
+ if (xlen > (sizeof sig)) {
+ return 0;
+ }
+ memcpy(sig, x, xlen);
+ if (!br_rsa_i15_public(sig, xlen, pk)) {
+ return 0;
+ }
+ return br_rsa_pkcs1_sig_unpad(sig, xlen, hash_oid, hash_len, hash_out);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i15_priv.c b/contrib/bearssl/src/rsa/rsa_i15_priv.c
new file mode 100644
index 000000000000..177cc3a6643a
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i15_priv.c
@@ -0,0 +1,209 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#define U (2 + ((BR_MAX_RSA_FACTOR + 14) / 15))
+#define TLEN (8 * U)
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i15_private(unsigned char *x, const br_rsa_private_key *sk)
+{
+ const unsigned char *p, *q;
+ size_t plen, qlen;
+ size_t fwlen;
+ uint16_t p0i, q0i;
+ size_t xlen, u;
+ uint16_t tmp[1 + TLEN];
+ long z;
+ uint16_t *mp, *mq, *s1, *s2, *t1, *t2, *t3;
+ uint32_t r;
+
+ /*
+ * Compute the actual lengths of p and q, in bytes.
+ * These lengths are not considered secret (we cannot really hide
+ * them anyway in constant-time code).
+ */
+ p = sk->p;
+ plen = sk->plen;
+ while (plen > 0 && *p == 0) {
+ p ++;
+ plen --;
+ }
+ q = sk->q;
+ qlen = sk->qlen;
+ while (qlen > 0 && *q == 0) {
+ q ++;
+ qlen --;
+ }
+
+ /*
+ * Compute the maximum factor length, in words.
+ */
+ z = (long)(plen > qlen ? plen : qlen) << 3;
+ fwlen = 1;
+ while (z > 0) {
+ z -= 15;
+ fwlen ++;
+ }
+ /*
+ * Round up the word length to an even number.
+ */
+ fwlen += (fwlen & 1);
+
+ /*
+ * We need to fit at least 6 values in the stack buffer.
+ */
+ if (6 * fwlen > TLEN) {
+ return 0;
+ }
+
+ /*
+ * Compute signature length (in bytes).
+ */
+ xlen = (sk->n_bitlen + 7) >> 3;
+
+ /*
+ * Ensure 32-bit alignment for value words.
+ */
+ mq = tmp;
+ if (((uintptr_t)mq & 2) == 0) {
+ mq ++;
+ }
+
+ /*
+ * Decode q.
+ */
+ br_i15_decode(mq, q, qlen);
+
+ /*
+ * Decode p.
+ */
+ t1 = mq + fwlen;
+ br_i15_decode(t1, p, plen);
+
+ /*
+ * Compute the modulus (product of the two factors), to compare
+ * it with the source value. We use br_i15_mulacc(), since it's
+ * already used later on.
+ */
+ t2 = mq + 2 * fwlen;
+ br_i15_zero(t2, mq[0]);
+ br_i15_mulacc(t2, mq, t1);
+
+ /*
+ * We encode the modulus into bytes, to perform the comparison
+ * with bytes. We know that the product length, in bytes, is
+ * exactly xlen.
+ * The comparison actually computes the carry when subtracting
+ * the modulus from the source value; that carry must be 1 for
+ * a value in the correct range. We keep it in r, which is our
+ * accumulator for the error code.
+ */
+ t3 = mq + 4 * fwlen;
+ br_i15_encode(t3, xlen, t2);
+ u = xlen;
+ r = 0;
+ while (u > 0) {
+ uint32_t wn, wx;
+
+ u --;
+ wn = ((unsigned char *)t3)[u];
+ wx = x[u];
+ r = ((wx - (wn + r)) >> 8) & 1;
+ }
+
+ /*
+ * Move the decoded p to another temporary buffer.
+ */
+ mp = mq + 2 * fwlen;
+ memmove(mp, t1, fwlen * sizeof *t1);
+
+ /*
+ * Compute s2 = x^dq mod q.
+ */
+ q0i = br_i15_ninv15(mq[1]);
+ s2 = mq + fwlen;
+ br_i15_decode_reduce(s2, x, xlen, mq);
+ r &= br_i15_modpow_opt(s2, sk->dq, sk->dqlen, mq, q0i,
+ mq + 3 * fwlen, TLEN - 3 * fwlen);
+
+ /*
+ * Compute s1 = x^dq mod q.
+ */
+ p0i = br_i15_ninv15(mp[1]);
+ s1 = mq + 3 * fwlen;
+ br_i15_decode_reduce(s1, x, xlen, mp);
+ r &= br_i15_modpow_opt(s1, sk->dp, sk->dplen, mp, p0i,
+ mq + 4 * fwlen, TLEN - 4 * fwlen);
+
+ /*
+ * Compute:
+ * h = (s1 - s2)*(1/q) mod p
+ * s1 is an integer modulo p, but s2 is modulo q. PKCS#1 is
+ * unclear about whether p may be lower than q (some existing,
+ * widely deployed implementations of RSA don't tolerate p < q),
+ * but we want to support that occurrence, so we need to use the
+ * reduction function.
+ *
+ * Since we use br_i15_decode_reduce() for iq (purportedly, the
+ * inverse of q modulo p), we also tolerate improperly large
+ * values for this parameter.
+ */
+ t1 = mq + 4 * fwlen;
+ t2 = mq + 5 * fwlen;
+ br_i15_reduce(t2, s2, mp);
+ br_i15_add(s1, mp, br_i15_sub(s1, t2, 1));
+ br_i15_to_monty(s1, mp);
+ br_i15_decode_reduce(t1, sk->iq, sk->iqlen, mp);
+ br_i15_montymul(t2, s1, t1, mp, p0i);
+
+ /*
+ * h is now in t2. We compute the final result:
+ * s = s2 + q*h
+ * All these operations are non-modular.
+ *
+ * We need mq, s2 and t2. We use the t3 buffer as destination.
+ * The buffers mp, s1 and t1 are no longer needed, so we can
+ * reuse them for t3. Moreover, the first step of the computation
+ * is to copy s2 into t3, after which s2 is not needed. Right
+ * now, mq is in slot 0, s2 is in slot 1, and t2 in slot 5.
+ * Therefore, we have ample room for t3 by simply using s2.
+ */
+ t3 = s2;
+ br_i15_mulacc(t3, mq, t2);
+
+ /*
+ * Encode the result. Since we already checked the value of xlen,
+ * we can just use it right away.
+ */
+ br_i15_encode(x, xlen, t3);
+
+ /*
+ * The only error conditions remaining at that point are invalid
+ * values for p and q (even integers).
+ */
+ return p0i & q0i & r;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i15_privexp.c b/contrib/bearssl/src/rsa/rsa_i15_privexp.c
new file mode 100644
index 000000000000..57d6918e7bdb
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i15_privexp.c
@@ -0,0 +1,320 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+size_t
+br_rsa_i15_compute_privexp(void *d,
+ const br_rsa_private_key *sk, uint32_t e)
+{
+ /*
+ * We want to invert e modulo phi = (p-1)(q-1). This first
+ * requires computing phi, which is easy since we have the factors
+ * p and q in the private key structure.
+ *
+ * Since p = 3 mod 4 and q = 3 mod 4, phi/4 is an odd integer.
+ * We could invert e modulo phi/4 then patch the result to
+ * modulo phi, but this would involve assembling three modulus-wide
+ * values (phi/4, 1 and e) and calling moddiv, that requires
+ * three more temporaries, for a total of six big integers, or
+ * slightly more than 3 kB of stack space for RSA-4096. This
+ * exceeds our stack requirements.
+ *
+ * Instead, we first use one step of the extended GCD:
+ *
+ * - We compute phi = k*e + r (Euclidean division of phi by e).
+ * If public exponent e is correct, then r != 0 (e must be
+ * invertible modulo phi). We also have k != 0 since we
+ * enforce non-ridiculously-small factors.
+ *
+ * - We find small u, v such that u*e - v*r = 1 (using a
+ * binary GCD; we can arrange for u < r and v < e, i.e. all
+ * values fit on 32 bits).
+ *
+ * - Solution is: d = u + v*k
+ * This last computation is exact: since u < r and v < e,
+ * the above implies d < r + e*((phi-r)/e) = phi
+ */
+
+ uint16_t tmp[4 * ((BR_MAX_RSA_FACTOR + 14) / 15) + 12];
+ uint16_t *p, *q, *k, *m, *z, *phi;
+ const unsigned char *pbuf, *qbuf;
+ size_t plen, qlen, u, len, dlen;
+ uint32_t r, a, b, u0, v0, u1, v1, he, hr;
+ int i;
+
+ /*
+ * Check that e is correct.
+ */
+ if (e < 3 || (e & 1) == 0) {
+ return 0;
+ }
+
+ /*
+ * Check lengths of p and q, and that they are both odd.
+ */
+ pbuf = sk->p;
+ plen = sk->plen;
+ while (plen > 0 && *pbuf == 0) {
+ pbuf ++;
+ plen --;
+ }
+ if (plen < 5 || plen > (BR_MAX_RSA_FACTOR / 8)
+ || (pbuf[plen - 1] & 1) != 1)
+ {
+ return 0;
+ }
+ qbuf = sk->q;
+ qlen = sk->qlen;
+ while (qlen > 0 && *qbuf == 0) {
+ qbuf ++;
+ qlen --;
+ }
+ if (qlen < 5 || qlen > (BR_MAX_RSA_FACTOR / 8)
+ || (qbuf[qlen - 1] & 1) != 1)
+ {
+ return 0;
+ }
+
+ /*
+ * Output length is that of the modulus.
+ */
+ dlen = (sk->n_bitlen + 7) >> 3;
+ if (d == NULL) {
+ return dlen;
+ }
+
+ p = tmp;
+ br_i15_decode(p, pbuf, plen);
+ plen = (p[0] + 15) >> 4;
+ q = p + 1 + plen;
+ br_i15_decode(q, qbuf, qlen);
+ qlen = (q[0] + 15) >> 4;
+
+ /*
+ * Compute phi = (p-1)*(q-1), then move it over p-1 and q-1 (that
+ * we do not need anymore). The mulacc function sets the announced
+ * bit length of t to be the sum of the announced bit lengths of
+ * p-1 and q-1, which is usually exact but may overshoot by one 1
+ * bit in some cases; we readjust it to its true length.
+ */
+ p[1] --;
+ q[1] --;
+ phi = q + 1 + qlen;
+ br_i15_zero(phi, p[0]);
+ br_i15_mulacc(phi, p, q);
+ len = (phi[0] + 15) >> 4;
+ memmove(tmp, phi, (1 + len) * sizeof *phi);
+ phi = tmp;
+ phi[0] = br_i15_bit_length(phi + 1, len);
+ len = (phi[0] + 15) >> 4;
+
+ /*
+ * Divide phi by public exponent e. The final remainder r must be
+ * non-zero (otherwise, the key is invalid). The quotient is k,
+ * which we write over phi, since we don't need phi after that.
+ */
+ r = 0;
+ for (u = len; u >= 1; u --) {
+ /*
+ * Upon entry, r < e, and phi[u] < 2^15; hence,
+ * hi:lo < e*2^15. Thus, the produced word k[u]
+ * must be lower than 2^15, and the new remainder r
+ * is lower than e.
+ */
+ uint32_t hi, lo;
+
+ hi = r >> 17;
+ lo = (r << 15) + phi[u];
+ phi[u] = br_divrem(hi, lo, e, &r);
+ }
+ if (r == 0) {
+ return 0;
+ }
+ k = phi;
+
+ /*
+ * Compute u and v such that u*e - v*r = GCD(e,r). We use
+ * a binary GCD algorithm, with 6 extra integers a, b,
+ * u0, u1, v0 and v1. Initial values are:
+ * a = e u0 = 1 v0 = 0
+ * b = r u1 = r v1 = e-1
+ * The following invariants are maintained:
+ * a = u0*e - v0*r
+ * b = u1*e - v1*r
+ * 0 < a <= e
+ * 0 < b <= r
+ * 0 <= u0 <= r
+ * 0 <= v0 <= e
+ * 0 <= u1 <= r
+ * 0 <= v1 <= e
+ *
+ * At each iteration, we reduce either a or b by one bit, and
+ * adjust u0, u1, v0 and v1 to maintain the invariants:
+ * - if a is even, then a <- a/2
+ * - otherwise, if b is even, then b <- b/2
+ * - otherwise, if a > b, then a <- (a-b)/2
+ * - otherwise, if b > a, then b <- (b-a)/2
+ * Algorithm stops when a = b. At that point, the common value
+ * is the GCD of e and r; it must be 1 (otherwise, the private
+ * key or public exponent is not valid). The (u0,v0) or (u1,v1)
+ * pairs are the solution we are looking for.
+ *
+ * Since either a or b is reduced by at least 1 bit at each
+ * iteration, 62 iterations are enough to reach the end
+ * condition.
+ *
+ * To maintain the invariants, we must compute the same operations
+ * on the u* and v* values that we do on a and b:
+ * - When a is divided by 2, u0 and v0 must be divided by 2.
+ * - When b is divided by 2, u1 and v1 must be divided by 2.
+ * - When b is subtracted from a, u1 and v1 are subtracted from
+ * u0 and v0, respectively.
+ * - When a is subtracted from b, u0 and v0 are subtracted from
+ * u1 and v1, respectively.
+ *
+ * However, we want to keep the u* and v* values in their proper
+ * ranges. The following remarks apply:
+ *
+ * - When a is divided by 2, then a is even. Therefore:
+ *
+ * * If r is odd, then u0 and v0 must have the same parity;
+ * if they are both odd, then adding r to u0 and e to v0
+ * makes them both even, and the division by 2 brings them
+ * back to the proper range.
+ *
+ * * If r is even, then u0 must be even; if v0 is odd, then
+ * adding r to u0 and e to v0 makes them both even, and the
+ * division by 2 brings them back to the proper range.
+ *
+ * Thus, all we need to do is to look at the parity of v0,
+ * and add (r,e) to (u0,v0) when v0 is odd. In order to avoid
+ * a 32-bit overflow, we can add ((r+1)/2,(e/2)+1) after the
+ * division (r+1 does not overflow since r < e; and (e/2)+1
+ * is equal to (e+1)/2 since e is odd).
+ *
+ * - When we subtract b from a, three cases may occur:
+ *
+ * * u1 <= u0 and v1 <= v0: just do the subtractions
+ *
+ * * u1 > u0 and v1 > v0: compute:
+ * (u0, v0) <- (u0 + r - u1, v0 + e - v1)
+ *
+ * * u1 <= u0 and v1 > v0: compute:
+ * (u0, v0) <- (u0 + r - u1, v0 + e - v1)
+ *
+ * The fourth case (u1 > u0 and v1 <= v0) is not possible
+ * because it would contradict "b < a" (which is the reason
+ * why we subtract b from a).
+ *
+ * The tricky case is the third one: from the equations, it
+ * seems that u0 may go out of range. However, the invariants
+ * and ranges of other values imply that, in that case, the
+ * new u0 does not actually exceed the range.
+ *
+ * We can thus handle the subtraction by adding (r,e) based
+ * solely on the comparison between v0 and v1.
+ */
+ a = e;
+ b = r;
+ u0 = 1;
+ v0 = 0;
+ u1 = r;
+ v1 = e - 1;
+ hr = (r + 1) >> 1;
+ he = (e >> 1) + 1;
+ for (i = 0; i < 62; i ++) {
+ uint32_t oa, ob, agtb, bgta;
+ uint32_t sab, sba, da, db;
+ uint32_t ctl;
+
+ oa = a & 1; /* 1 if a is odd */
+ ob = b & 1; /* 1 if b is odd */
+ agtb = GT(a, b); /* 1 if a > b */
+ bgta = GT(b, a); /* 1 if b > a */
+
+ sab = oa & ob & agtb; /* 1 if a <- a-b */
+ sba = oa & ob & bgta; /* 1 if b <- b-a */
+
+ /* a <- a-b, u0 <- u0-u1, v0 <- v0-v1 */
+ ctl = GT(v1, v0);
+ a -= b & -sab;
+ u0 -= (u1 - (r & -ctl)) & -sab;
+ v0 -= (v1 - (e & -ctl)) & -sab;
+
+ /* b <- b-a, u1 <- u1-u0 mod r, v1 <- v1-v0 mod e */
+ ctl = GT(v0, v1);
+ b -= a & -sba;
+ u1 -= (u0 - (r & -ctl)) & -sba;
+ v1 -= (v0 - (e & -ctl)) & -sba;
+
+ da = NOT(oa) | sab; /* 1 if a <- a/2 */
+ db = (oa & NOT(ob)) | sba; /* 1 if b <- b/2 */
+
+ /* a <- a/2, u0 <- u0/2, v0 <- v0/2 */
+ ctl = v0 & 1;
+ a ^= (a ^ (a >> 1)) & -da;
+ u0 ^= (u0 ^ ((u0 >> 1) + (hr & -ctl))) & -da;
+ v0 ^= (v0 ^ ((v0 >> 1) + (he & -ctl))) & -da;
+
+ /* b <- b/2, u1 <- u1/2 mod r, v1 <- v1/2 mod e */
+ ctl = v1 & 1;
+ b ^= (b ^ (b >> 1)) & -db;
+ u1 ^= (u1 ^ ((u1 >> 1) + (hr & -ctl))) & -db;
+ v1 ^= (v1 ^ ((v1 >> 1) + (he & -ctl))) & -db;
+ }
+
+ /*
+ * Check that the GCD is indeed 1. If not, then the key is invalid
+ * (and there's no harm in leaking that piece of information).
+ */
+ if (a != 1) {
+ return 0;
+ }
+
+ /*
+ * Now we have u0*e - v0*r = 1. Let's compute the result as:
+ * d = u0 + v0*k
+ * We still have k in the tmp[] array, and its announced bit
+ * length is that of phi.
+ */
+ m = k + 1 + len;
+ m[0] = (2 << 4) + 2; /* bit length is 32 bits, encoded */
+ m[1] = v0 & 0x7FFF;
+ m[2] = (v0 >> 15) & 0x7FFF;
+ m[3] = v0 >> 30;
+ z = m + 4;
+ br_i15_zero(z, k[0]);
+ z[1] = u0 & 0x7FFF;
+ z[2] = (u0 >> 15) & 0x7FFF;
+ z[3] = u0 >> 30;
+ br_i15_mulacc(z, k, m);
+
+ /*
+ * Encode the result.
+ */
+ br_i15_encode(d, dlen, z);
+ return dlen;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i15_pss_sign.c b/contrib/bearssl/src/rsa/rsa_i15_pss_sign.c
new file mode 100644
index 000000000000..dd9385b0aaab
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i15_pss_sign.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i15_pss_sign(const br_prng_class **rng,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const unsigned char *hash, size_t salt_len,
+ const br_rsa_private_key *sk, unsigned char *x)
+{
+ if (!br_rsa_pss_sig_pad(rng, hf_data, hf_mgf1, hash,
+ salt_len, sk->n_bitlen, x))
+ {
+ return 0;
+ }
+ return br_rsa_i15_private(x, sk);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i15_pss_vrfy.c b/contrib/bearssl/src/rsa/rsa_i15_pss_vrfy.c
new file mode 100644
index 000000000000..7d9f2cbc4b7b
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i15_pss_vrfy.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i15_pss_vrfy(const unsigned char *x, size_t xlen,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const void *hash, size_t salt_len, const br_rsa_public_key *pk)
+{
+ unsigned char sig[BR_MAX_RSA_SIZE >> 3];
+
+ if (xlen > (sizeof sig)) {
+ return 0;
+ }
+ memcpy(sig, x, xlen);
+ if (!br_rsa_i15_public(sig, xlen, pk)) {
+ return 0;
+ }
+ return br_rsa_pss_sig_unpad(hf_data, hf_mgf1,
+ hash, salt_len, pk, sig);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i15_pub.c b/contrib/bearssl/src/rsa/rsa_i15_pub.c
new file mode 100644
index 000000000000..9eab5e842194
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i15_pub.c
@@ -0,0 +1,113 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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"
+
+/*
+ * As a strict minimum, we need four buffers that can hold a
+ * modular integer.
+ */
+#define TLEN (4 * (2 + ((BR_MAX_RSA_SIZE + 14) / 15)))
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i15_public(unsigned char *x, size_t xlen,
+ const br_rsa_public_key *pk)
+{
+ const unsigned char *n;
+ size_t nlen;
+ uint16_t tmp[1 + TLEN];
+ uint16_t *m, *a, *t;
+ size_t fwlen;
+ long z;
+ uint16_t m0i;
+ uint32_t r;
+
+ /*
+ * Get the actual length of the modulus, and see if it fits within
+ * our stack buffer. We also check that the length of x[] is valid.
+ */
+ n = pk->n;
+ nlen = pk->nlen;
+ while (nlen > 0 && *n == 0) {
+ n ++;
+ nlen --;
+ }
+ if (nlen == 0 || nlen > (BR_MAX_RSA_SIZE >> 3) || xlen != nlen) {
+ return 0;
+ }
+ z = (long)nlen << 3;
+ fwlen = 1;
+ while (z > 0) {
+ z -= 15;
+ fwlen ++;
+ }
+ /*
+ * Round up length to an even number.
+ */
+ fwlen += (fwlen & 1);
+
+ /*
+ * The modulus gets decoded into m[].
+ * The value to exponentiate goes into a[].
+ * The temporaries for modular exponentiations are in t[].
+ *
+ * We want the first value word of each integer to be aligned
+ * on a 32-bit boundary.
+ */
+ m = tmp;
+ if (((uintptr_t)m & 2) == 0) {
+ m ++;
+ }
+ a = m + fwlen;
+ t = m + 2 * fwlen;
+
+ /*
+ * Decode the modulus.
+ */
+ br_i15_decode(m, n, nlen);
+ m0i = br_i15_ninv15(m[1]);
+
+ /*
+ * Note: if m[] is even, then m0i == 0. Otherwise, m0i must be
+ * an odd integer.
+ */
+ r = m0i & 1;
+
+ /*
+ * Decode x[] into a[]; we also check that its value is proper.
+ */
+ r &= br_i15_decode_mod(a, x, xlen, m);
+
+ /*
+ * Compute the modular exponentiation.
+ */
+ br_i15_modpow_opt(a, pk->e, pk->elen, m, m0i, t, TLEN - 2 * fwlen);
+
+ /*
+ * Encode the result.
+ */
+ br_i15_encode(x, xlen, a);
+ return r;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i15_pubexp.c b/contrib/bearssl/src/rsa/rsa_i15_pubexp.c
new file mode 100644
index 000000000000..803bff7939f3
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i15_pubexp.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * Recompute public exponent, based on factor p and reduced private
+ * exponent dp.
+ */
+static uint32_t
+get_pubexp(const unsigned char *pbuf, size_t plen,
+ const unsigned char *dpbuf, size_t dplen)
+{
+ /*
+ * dp is the inverse of e modulo p-1. If p = 3 mod 4, then
+ * p-1 = 2*((p-1)/2). Taken modulo 2, e is odd and has inverse 1;
+ * thus, dp must be odd.
+ *
+ * We compute the inverse of dp modulo (p-1)/2. This requires
+ * first reducing dp modulo (p-1)/2 (this can be done with a
+ * conditional subtract, no need to use the generic modular
+ * reduction function); then, we use moddiv.
+ */
+
+ uint16_t tmp[6 * ((BR_MAX_RSA_FACTOR + 29) / 15)];
+ uint16_t *p, *dp, *x;
+ size_t len;
+ uint32_t e;
+
+ /*
+ * Compute actual factor length (in bytes) and check that it fits
+ * under our size constraints.
+ */
+ while (plen > 0 && *pbuf == 0) {
+ pbuf ++;
+ plen --;
+ }
+ if (plen == 0 || plen < 5 || plen > (BR_MAX_RSA_FACTOR / 8)) {
+ return 0;
+ }
+
+ /*
+ * Compute actual reduced exponent length (in bytes) and check that
+ * it is not longer than p.
+ */
+ while (dplen > 0 && *dpbuf == 0) {
+ dpbuf ++;
+ dplen --;
+ }
+ if (dplen > plen || dplen == 0
+ || (dplen == plen && dpbuf[0] > pbuf[0]))
+ {
+ return 0;
+ }
+
+ /*
+ * Verify that p = 3 mod 4 and that dp is odd.
+ */
+ if ((pbuf[plen - 1] & 3) != 3 || (dpbuf[dplen - 1] & 1) != 1) {
+ return 0;
+ }
+
+ /*
+ * Decode p and compute (p-1)/2.
+ */
+ p = tmp;
+ br_i15_decode(p, pbuf, plen);
+ len = (p[0] + 31) >> 4;
+ br_i15_rshift(p, 1);
+
+ /*
+ * Decode dp and make sure its announced bit length matches that of
+ * p (we already know that the size of dp, in bits, does not exceed
+ * the size of p, so we just have to copy the header word).
+ */
+ dp = p + len;
+ memset(dp, 0, len * sizeof *dp);
+ br_i15_decode(dp, dpbuf, dplen);
+ dp[0] = p[0];
+
+ /*
+ * Subtract (p-1)/2 from dp if necessary.
+ */
+ br_i15_sub(dp, p, NOT(br_i15_sub(dp, p, 0)));
+
+ /*
+ * If another subtraction is needed, then this means that the
+ * value was invalid. We don't care to leak information about
+ * invalid keys.
+ */
+ if (br_i15_sub(dp, p, 0) == 0) {
+ return 0;
+ }
+
+ /*
+ * Invert dp modulo (p-1)/2. If the inversion fails, then the
+ * key value was invalid.
+ */
+ x = dp + len;
+ br_i15_zero(x, p[0]);
+ x[1] = 1;
+ if (br_i15_moddiv(x, dp, p, br_i15_ninv15(p[1]), x + len) == 0) {
+ return 0;
+ }
+
+ /*
+ * We now have an inverse. We must set it to zero (error) if its
+ * length is greater than 32 bits and/or if it is an even integer.
+ * Take care that the bit_length function returns an encoded
+ * bit length.
+ */
+ e = (uint32_t)x[1] | ((uint32_t)x[2] << 15) | ((uint32_t)x[3] << 30);
+ e &= -LT(br_i15_bit_length(x + 1, len - 1), 35);
+ e &= -(e & 1);
+ return e;
+}
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i15_compute_pubexp(const br_rsa_private_key *sk)
+{
+ /*
+ * Get the public exponent from both p and q. This is the right
+ * exponent if we get twice the same value.
+ */
+ uint32_t ep, eq;
+
+ ep = get_pubexp(sk->p, sk->plen, sk->dp, sk->dplen);
+ eq = get_pubexp(sk->q, sk->qlen, sk->dq, sk->dqlen);
+ return ep & -EQ(ep, eq);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i31_keygen.c b/contrib/bearssl/src/rsa/rsa_i31_keygen.c
new file mode 100644
index 000000000000..77708f8b0da4
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i31_keygen.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i31_keygen(const br_prng_class **rng,
+ br_rsa_private_key *sk, void *kbuf_priv,
+ br_rsa_public_key *pk, void *kbuf_pub,
+ unsigned size, uint32_t pubexp)
+{
+ return br_rsa_i31_keygen_inner(rng,
+ sk, kbuf_priv, pk, kbuf_pub, size, pubexp,
+ &br_i31_modpow_opt);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i31_keygen_inner.c b/contrib/bearssl/src/rsa/rsa_i31_keygen_inner.c
new file mode 100644
index 000000000000..9ec881b5f945
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i31_keygen_inner.c
@@ -0,0 +1,608 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * Make a random integer of the provided size. The size is encoded.
+ * The header word is untouched.
+ */
+static void
+mkrand(const br_prng_class **rng, uint32_t *x, uint32_t esize)
+{
+ size_t u, len;
+ unsigned m;
+
+ len = (esize + 31) >> 5;
+ (*rng)->generate(rng, x + 1, len * sizeof(uint32_t));
+ for (u = 1; u < len; u ++) {
+ x[u] &= 0x7FFFFFFF;
+ }
+ m = esize & 31;
+ if (m == 0) {
+ x[len] &= 0x7FFFFFFF;
+ } else {
+ x[len] &= 0x7FFFFFFF >> (31 - m);
+ }
+}
+
+/*
+ * This is the big-endian unsigned representation of the product of
+ * all small primes from 13 to 1481.
+ */
+static const unsigned char SMALL_PRIMES[] = {
+ 0x2E, 0xAB, 0x92, 0xD1, 0x8B, 0x12, 0x47, 0x31, 0x54, 0x0A,
+ 0x99, 0x5D, 0x25, 0x5E, 0xE2, 0x14, 0x96, 0x29, 0x1E, 0xB7,
+ 0x78, 0x70, 0xCC, 0x1F, 0xA5, 0xAB, 0x8D, 0x72, 0x11, 0x37,
+ 0xFB, 0xD8, 0x1E, 0x3F, 0x5B, 0x34, 0x30, 0x17, 0x8B, 0xE5,
+ 0x26, 0x28, 0x23, 0xA1, 0x8A, 0xA4, 0x29, 0xEA, 0xFD, 0x9E,
+ 0x39, 0x60, 0x8A, 0xF3, 0xB5, 0xA6, 0xEB, 0x3F, 0x02, 0xB6,
+ 0x16, 0xC3, 0x96, 0x9D, 0x38, 0xB0, 0x7D, 0x82, 0x87, 0x0C,
+ 0xF7, 0xBE, 0x24, 0xE5, 0x5F, 0x41, 0x04, 0x79, 0x76, 0x40,
+ 0xE7, 0x00, 0x22, 0x7E, 0xB5, 0x85, 0x7F, 0x8D, 0x01, 0x50,
+ 0xE9, 0xD3, 0x29, 0x42, 0x08, 0xB3, 0x51, 0x40, 0x7B, 0xD7,
+ 0x8D, 0xCC, 0x10, 0x01, 0x64, 0x59, 0x28, 0xB6, 0x53, 0xF3,
+ 0x50, 0x4E, 0xB1, 0xF2, 0x58, 0xCD, 0x6E, 0xF5, 0x56, 0x3E,
+ 0x66, 0x2F, 0xD7, 0x07, 0x7F, 0x52, 0x4C, 0x13, 0x24, 0xDC,
+ 0x8E, 0x8D, 0xCC, 0xED, 0x77, 0xC4, 0x21, 0xD2, 0xFD, 0x08,
+ 0xEA, 0xD7, 0xC0, 0x5C, 0x13, 0x82, 0x81, 0x31, 0x2F, 0x2B,
+ 0x08, 0xE4, 0x80, 0x04, 0x7A, 0x0C, 0x8A, 0x3C, 0xDC, 0x22,
+ 0xE4, 0x5A, 0x7A, 0xB0, 0x12, 0x5E, 0x4A, 0x76, 0x94, 0x77,
+ 0xC2, 0x0E, 0x92, 0xBA, 0x8A, 0xA0, 0x1F, 0x14, 0x51, 0x1E,
+ 0x66, 0x6C, 0x38, 0x03, 0x6C, 0xC7, 0x4A, 0x4B, 0x70, 0x80,
+ 0xAF, 0xCA, 0x84, 0x51, 0xD8, 0xD2, 0x26, 0x49, 0xF5, 0xA8,
+ 0x5E, 0x35, 0x4B, 0xAC, 0xCE, 0x29, 0x92, 0x33, 0xB7, 0xA2,
+ 0x69, 0x7D, 0x0C, 0xE0, 0x9C, 0xDB, 0x04, 0xD6, 0xB4, 0xBC,
+ 0x39, 0xD7, 0x7F, 0x9E, 0x9D, 0x78, 0x38, 0x7F, 0x51, 0x54,
+ 0x50, 0x8B, 0x9E, 0x9C, 0x03, 0x6C, 0xF5, 0x9D, 0x2C, 0x74,
+ 0x57, 0xF0, 0x27, 0x2A, 0xC3, 0x47, 0xCA, 0xB9, 0xD7, 0x5C,
+ 0xFF, 0xC2, 0xAC, 0x65, 0x4E, 0xBD
+};
+
+/*
+ * We need temporary values for at least 7 integers of the same size
+ * as a factor (including header word); more space helps with performance
+ * (in modular exponentiations), but we much prefer to remain under
+ * 2 kilobytes in total, to save stack space. The macro TEMPS below
+ * exceeds 512 (which is a count in 32-bit words) when BR_MAX_RSA_SIZE
+ * is greater than 4464 (default value is 4096, so the 2-kB limit is
+ * maintained unless BR_MAX_RSA_SIZE was modified).
+ */
+#define MAX(x, y) ((x) > (y) ? (x) : (y))
+#define ROUND2(x) ((((x) + 1) >> 1) << 1)
+
+#define TEMPS MAX(512, ROUND2(7 * ((((BR_MAX_RSA_SIZE + 1) >> 1) + 61) / 31)))
+
+/*
+ * Perform trial division on a candidate prime. This computes
+ * y = SMALL_PRIMES mod x, then tries to compute y/y mod x. The
+ * br_i31_moddiv() function will report an error if y is not invertible
+ * modulo x. Returned value is 1 on success (none of the small primes
+ * divides x), 0 on error (a non-trivial GCD is obtained).
+ *
+ * This function assumes that x is odd.
+ */
+static uint32_t
+trial_divisions(const uint32_t *x, uint32_t *t)
+{
+ uint32_t *y;
+ uint32_t x0i;
+
+ y = t;
+ t += 1 + ((x[0] + 31) >> 5);
+ x0i = br_i31_ninv31(x[1]);
+ br_i31_decode_reduce(y, SMALL_PRIMES, sizeof SMALL_PRIMES, x);
+ return br_i31_moddiv(y, y, x, x0i, t);
+}
+
+/*
+ * Perform n rounds of Miller-Rabin on the candidate prime x. This
+ * function assumes that x = 3 mod 4.
+ *
+ * Returned value is 1 on success (all rounds completed successfully),
+ * 0 otherwise.
+ */
+static uint32_t
+miller_rabin(const br_prng_class **rng, const uint32_t *x, int n,
+ uint32_t *t, size_t tlen, br_i31_modpow_opt_type mp31)
+{
+ /*
+ * Since x = 3 mod 4, the Miller-Rabin test is simple:
+ * - get a random base a (such that 1 < a < x-1)
+ * - compute z = a^((x-1)/2) mod x
+ * - if z != 1 and z != x-1, the number x is composite
+ *
+ * We generate bases 'a' randomly with a size which is
+ * one bit less than x, which ensures that a < x-1. It
+ * is not useful to verify that a > 1 because the probability
+ * that we get a value a equal to 0 or 1 is much smaller
+ * than the probability of our Miller-Rabin tests not to
+ * detect a composite, which is already quite smaller than the
+ * probability of the hardware misbehaving and return a
+ * composite integer because of some glitch (e.g. bad RAM
+ * or ill-timed cosmic ray).
+ */
+ unsigned char *xm1d2;
+ size_t xlen, xm1d2_len, xm1d2_len_u32, u;
+ uint32_t asize;
+ unsigned cc;
+ uint32_t x0i;
+
+ /*
+ * Compute (x-1)/2 (encoded).
+ */
+ xm1d2 = (unsigned char *)t;
+ xm1d2_len = ((x[0] - (x[0] >> 5)) + 7) >> 3;
+ br_i31_encode(xm1d2, xm1d2_len, x);
+ cc = 0;
+ for (u = 0; u < xm1d2_len; u ++) {
+ unsigned w;
+
+ w = xm1d2[u];
+ xm1d2[u] = (unsigned char)((w >> 1) | cc);
+ cc = w << 7;
+ }
+
+ /*
+ * We used some words of the provided buffer for (x-1)/2.
+ */
+ xm1d2_len_u32 = (xm1d2_len + 3) >> 2;
+ t += xm1d2_len_u32;
+ tlen -= xm1d2_len_u32;
+
+ xlen = (x[0] + 31) >> 5;
+ asize = x[0] - 1 - EQ0(x[0] & 31);
+ x0i = br_i31_ninv31(x[1]);
+ while (n -- > 0) {
+ uint32_t *a, *t2;
+ uint32_t eq1, eqm1;
+ size_t t2len;
+
+ /*
+ * Generate a random base. We don't need the base to be
+ * really uniform modulo x, so we just get a random
+ * number which is one bit shorter than x.
+ */
+ a = t;
+ a[0] = x[0];
+ a[xlen] = 0;
+ mkrand(rng, a, asize);
+
+ /*
+ * Compute a^((x-1)/2) mod x. We assume here that the
+ * function will not fail (the temporary array is large
+ * enough).
+ */
+ t2 = t + 1 + xlen;
+ t2len = tlen - 1 - xlen;
+ if ((t2len & 1) != 0) {
+ /*
+ * Since the source array is 64-bit aligned and
+ * has an even number of elements (TEMPS), we
+ * can use the parity of the remaining length to
+ * detect and adjust alignment.
+ */
+ t2 ++;
+ t2len --;
+ }
+ mp31(a, xm1d2, xm1d2_len, x, x0i, t2, t2len);
+
+ /*
+ * We must obtain either 1 or x-1. Note that x is odd,
+ * hence x-1 differs from x only in its low word (no
+ * carry).
+ */
+ eq1 = a[1] ^ 1;
+ eqm1 = a[1] ^ (x[1] - 1);
+ for (u = 2; u <= xlen; u ++) {
+ eq1 |= a[u];
+ eqm1 |= a[u] ^ x[u];
+ }
+
+ if ((EQ0(eq1) | EQ0(eqm1)) == 0) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+/*
+ * Create a random prime of the provided size. 'size' is the _encoded_
+ * bit length. The two top bits and the two bottom bits are set to 1.
+ */
+static void
+mkprime(const br_prng_class **rng, uint32_t *x, uint32_t esize,
+ uint32_t pubexp, uint32_t *t, size_t tlen, br_i31_modpow_opt_type mp31)
+{
+ size_t len;
+
+ x[0] = esize;
+ len = (esize + 31) >> 5;
+ for (;;) {
+ size_t u;
+ uint32_t m3, m5, m7, m11;
+ int rounds, s7, s11;
+
+ /*
+ * Generate random bits. We force the two top bits and the
+ * two bottom bits to 1.
+ */
+ mkrand(rng, x, esize);
+ if ((esize & 31) == 0) {
+ x[len] |= 0x60000000;
+ } else if ((esize & 31) == 1) {
+ x[len] |= 0x00000001;
+ x[len - 1] |= 0x40000000;
+ } else {
+ x[len] |= 0x00000003 << ((esize & 31) - 2);
+ }
+ x[1] |= 0x00000003;
+
+ /*
+ * Trial division with low primes (3, 5, 7 and 11). We
+ * use the following properties:
+ *
+ * 2^2 = 1 mod 3
+ * 2^4 = 1 mod 5
+ * 2^3 = 1 mod 7
+ * 2^10 = 1 mod 11
+ */
+ m3 = 0;
+ m5 = 0;
+ m7 = 0;
+ m11 = 0;
+ s7 = 0;
+ s11 = 0;
+ for (u = 0; u < len; u ++) {
+ uint32_t w, w3, w5, w7, w11;
+
+ w = x[1 + u];
+ w3 = (w & 0xFFFF) + (w >> 16); /* max: 98302 */
+ w5 = (w & 0xFFFF) + (w >> 16); /* max: 98302 */
+ w7 = (w & 0x7FFF) + (w >> 15); /* max: 98302 */
+ w11 = (w & 0xFFFFF) + (w >> 20); /* max: 1050622 */
+
+ m3 += w3 << (u & 1);
+ m3 = (m3 & 0xFF) + (m3 >> 8); /* max: 1025 */
+
+ m5 += w5 << ((4 - u) & 3);
+ m5 = (m5 & 0xFFF) + (m5 >> 12); /* max: 4479 */
+
+ m7 += w7 << s7;
+ m7 = (m7 & 0x1FF) + (m7 >> 9); /* max: 1280 */
+ if (++ s7 == 3) {
+ s7 = 0;
+ }
+
+ m11 += w11 << s11;
+ if (++ s11 == 10) {
+ s11 = 0;
+ }
+ m11 = (m11 & 0x3FF) + (m11 >> 10); /* max: 526847 */
+ }
+
+ m3 = (m3 & 0x3F) + (m3 >> 6); /* max: 78 */
+ m3 = (m3 & 0x0F) + (m3 >> 4); /* max: 18 */
+ m3 = ((m3 * 43) >> 5) & 3;
+
+ m5 = (m5 & 0xFF) + (m5 >> 8); /* max: 271 */
+ m5 = (m5 & 0x0F) + (m5 >> 4); /* max: 31 */
+ m5 -= 20 & -GT(m5, 19);
+ m5 -= 10 & -GT(m5, 9);
+ m5 -= 5 & -GT(m5, 4);
+
+ m7 = (m7 & 0x3F) + (m7 >> 6); /* max: 82 */
+ m7 = (m7 & 0x07) + (m7 >> 3); /* max: 16 */
+ m7 = ((m7 * 147) >> 7) & 7;
+
+ /*
+ * 2^5 = 32 = -1 mod 11.
+ */
+ m11 = (m11 & 0x3FF) + (m11 >> 10); /* max: 1536 */
+ m11 = (m11 & 0x3FF) + (m11 >> 10); /* max: 1023 */
+ m11 = (m11 & 0x1F) + 33 - (m11 >> 5); /* max: 64 */
+ m11 -= 44 & -GT(m11, 43);
+ m11 -= 22 & -GT(m11, 21);
+ m11 -= 11 & -GT(m11, 10);
+
+ /*
+ * If any of these modulo is 0, then the candidate is
+ * not prime. Also, if pubexp is 3, 5, 7 or 11, and the
+ * corresponding modulus is 1, then the candidate must
+ * be rejected, because we need e to be invertible
+ * modulo p-1. We can use simple comparisons here
+ * because they won't leak information on a candidate
+ * that we keep, only on one that we reject (and is thus
+ * not secret).
+ */
+ if (m3 == 0 || m5 == 0 || m7 == 0 || m11 == 0) {
+ continue;
+ }
+ if ((pubexp == 3 && m3 == 1)
+ || (pubexp == 5 && m5 == 5)
+ || (pubexp == 7 && m5 == 7)
+ || (pubexp == 11 && m5 == 11))
+ {
+ continue;
+ }
+
+ /*
+ * More trial divisions.
+ */
+ if (!trial_divisions(x, t)) {
+ continue;
+ }
+
+ /*
+ * Miller-Rabin algorithm. Since we selected a random
+ * integer, not a maliciously crafted integer, we can use
+ * relatively few rounds to lower the risk of a false
+ * positive (i.e. declaring prime a non-prime) under
+ * 2^(-80). It is not useful to lower the probability much
+ * below that, since that would be substantially below
+ * the probability of the hardware misbehaving. Sufficient
+ * numbers of rounds are extracted from the Handbook of
+ * Applied Cryptography, note 4.49 (page 149).
+ *
+ * Since we work on the encoded size (esize), we need to
+ * compare with encoded thresholds.
+ */
+ if (esize < 309) {
+ rounds = 12;
+ } else if (esize < 464) {
+ rounds = 9;
+ } else if (esize < 670) {
+ rounds = 6;
+ } else if (esize < 877) {
+ rounds = 4;
+ } else if (esize < 1341) {
+ rounds = 3;
+ } else {
+ rounds = 2;
+ }
+
+ if (miller_rabin(rng, x, rounds, t, tlen, mp31)) {
+ return;
+ }
+ }
+}
+
+/*
+ * Let p be a prime (p > 2^33, p = 3 mod 4). Let m = (p-1)/2, provided
+ * as parameter (with announced bit length equal to that of p). This
+ * function computes d = 1/e mod p-1 (for an odd integer e). Returned
+ * value is 1 on success, 0 on error (an error is reported if e is not
+ * invertible modulo p-1).
+ *
+ * The temporary buffer (t) must have room for at least 4 integers of
+ * the size of p.
+ */
+static uint32_t
+invert_pubexp(uint32_t *d, const uint32_t *m, uint32_t e, uint32_t *t)
+{
+ uint32_t *f;
+ uint32_t r;
+
+ f = t;
+ t += 1 + ((m[0] + 31) >> 5);
+
+ /*
+ * Compute d = 1/e mod m. Since p = 3 mod 4, m is odd.
+ */
+ br_i31_zero(d, m[0]);
+ d[1] = 1;
+ br_i31_zero(f, m[0]);
+ f[1] = e & 0x7FFFFFFF;
+ f[2] = e >> 31;
+ r = br_i31_moddiv(d, f, m, br_i31_ninv31(m[1]), t);
+
+ /*
+ * We really want d = 1/e mod p-1, with p = 2m. By the CRT,
+ * the result is either the d we got, or d + m.
+ *
+ * Let's write e*d = 1 + k*m, for some integer k. Integers e
+ * and m are odd. If d is odd, then e*d is odd, which implies
+ * that k must be even; in that case, e*d = 1 + (k/2)*2m, and
+ * thus d is already fine. Conversely, if d is even, then k
+ * is odd, and we must add m to d in order to get the correct
+ * result.
+ */
+ br_i31_add(d, m, (uint32_t)(1 - (d[1] & 1)));
+
+ return r;
+}
+
+/*
+ * Swap two buffers in RAM. They must be disjoint.
+ */
+static void
+bufswap(void *b1, void *b2, size_t len)
+{
+ size_t u;
+ unsigned char *buf1, *buf2;
+
+ buf1 = b1;
+ buf2 = b2;
+ for (u = 0; u < len; u ++) {
+ unsigned w;
+
+ w = buf1[u];
+ buf1[u] = buf2[u];
+ buf2[u] = w;
+ }
+}
+
+/* see inner.h */
+uint32_t
+br_rsa_i31_keygen_inner(const br_prng_class **rng,
+ br_rsa_private_key *sk, void *kbuf_priv,
+ br_rsa_public_key *pk, void *kbuf_pub,
+ unsigned size, uint32_t pubexp, br_i31_modpow_opt_type mp31)
+{
+ uint32_t esize_p, esize_q;
+ size_t plen, qlen, tlen;
+ uint32_t *p, *q, *t;
+ union {
+ uint32_t t32[TEMPS];
+ uint64_t t64[TEMPS >> 1]; /* for 64-bit alignment */
+ } tmp;
+ uint32_t r;
+
+ if (size < BR_MIN_RSA_SIZE || size > BR_MAX_RSA_SIZE) {
+ return 0;
+ }
+ if (pubexp == 0) {
+ pubexp = 3;
+ } else if (pubexp == 1 || (pubexp & 1) == 0) {
+ return 0;
+ }
+
+ esize_p = (size + 1) >> 1;
+ esize_q = size - esize_p;
+ sk->n_bitlen = size;
+ sk->p = kbuf_priv;
+ sk->plen = (esize_p + 7) >> 3;
+ sk->q = sk->p + sk->plen;
+ sk->qlen = (esize_q + 7) >> 3;
+ sk->dp = sk->q + sk->qlen;
+ sk->dplen = sk->plen;
+ sk->dq = sk->dp + sk->dplen;
+ sk->dqlen = sk->qlen;
+ sk->iq = sk->dq + sk->dqlen;
+ sk->iqlen = sk->plen;
+
+ if (pk != NULL) {
+ pk->n = kbuf_pub;
+ pk->nlen = (size + 7) >> 3;
+ pk->e = pk->n + pk->nlen;
+ pk->elen = 4;
+ br_enc32be(pk->e, pubexp);
+ while (*pk->e == 0) {
+ pk->e ++;
+ pk->elen --;
+ }
+ }
+
+ /*
+ * We now switch to encoded sizes.
+ *
+ * floor((x * 16913) / (2^19)) is equal to floor(x/31) for all
+ * integers x from 0 to 34966; the intermediate product fits on
+ * 30 bits, thus we can use MUL31().
+ */
+ esize_p += MUL31(esize_p, 16913) >> 19;
+ esize_q += MUL31(esize_q, 16913) >> 19;
+ plen = (esize_p + 31) >> 5;
+ qlen = (esize_q + 31) >> 5;
+ p = tmp.t32;
+ q = p + 1 + plen;
+ t = q + 1 + qlen;
+ tlen = ((sizeof tmp.t32) / sizeof(uint32_t)) - (2 + plen + qlen);
+
+ /*
+ * When looking for primes p and q, we temporarily divide
+ * candidates by 2, in order to compute the inverse of the
+ * public exponent.
+ */
+
+ for (;;) {
+ mkprime(rng, p, esize_p, pubexp, t, tlen, mp31);
+ br_i31_rshift(p, 1);
+ if (invert_pubexp(t, p, pubexp, t + 1 + plen)) {
+ br_i31_add(p, p, 1);
+ p[1] |= 1;
+ br_i31_encode(sk->p, sk->plen, p);
+ br_i31_encode(sk->dp, sk->dplen, t);
+ break;
+ }
+ }
+
+ for (;;) {
+ mkprime(rng, q, esize_q, pubexp, t, tlen, mp31);
+ br_i31_rshift(q, 1);
+ if (invert_pubexp(t, q, pubexp, t + 1 + qlen)) {
+ br_i31_add(q, q, 1);
+ q[1] |= 1;
+ br_i31_encode(sk->q, sk->qlen, q);
+ br_i31_encode(sk->dq, sk->dqlen, t);
+ break;
+ }
+ }
+
+ /*
+ * If p and q have the same size, then it is possible that q > p
+ * (when the target modulus size is odd, we generate p with a
+ * greater bit length than q). If q > p, we want to swap p and q
+ * (and also dp and dq) for two reasons:
+ * - The final step below (inversion of q modulo p) is easier if
+ * p > q.
+ * - While BearSSL's RSA code is perfectly happy with RSA keys such
+ * that p < q, some other implementations have restrictions and
+ * require p > q.
+ *
+ * Note that we can do a simple non-constant-time swap here,
+ * because the only information we leak here is that we insist on
+ * returning p and q such that p > q, which is not a secret.
+ */
+ if (esize_p == esize_q && br_i31_sub(p, q, 0) == 1) {
+ bufswap(p, q, (1 + plen) * sizeof *p);
+ bufswap(sk->p, sk->q, sk->plen);
+ bufswap(sk->dp, sk->dq, sk->dplen);
+ }
+
+ /*
+ * We have produced p, q, dp and dq. We can now compute iq = 1/d mod p.
+ *
+ * We ensured that p >= q, so this is just a matter of updating the
+ * header word for q (and possibly adding an extra word).
+ *
+ * Theoretically, the call below may fail, in case we were
+ * extraordinarily unlucky, and p = q. Another failure case is if
+ * Miller-Rabin failed us _twice_, and p and q are non-prime and
+ * have a factor is common. We report the error mostly because it
+ * is cheap and we can, but in practice this never happens (or, at
+ * least, it happens way less often than hardware glitches).
+ */
+ q[0] = p[0];
+ if (plen > qlen) {
+ q[plen] = 0;
+ t ++;
+ tlen --;
+ }
+ br_i31_zero(t, p[0]);
+ t[1] = 1;
+ r = br_i31_moddiv(t, q, p, br_i31_ninv31(p[1]), t + 1 + plen);
+ br_i31_encode(sk->iq, sk->iqlen, t);
+
+ /*
+ * Compute the public modulus too, if required.
+ */
+ if (pk != NULL) {
+ br_i31_zero(t, p[0]);
+ br_i31_mulacc(t, p, q);
+ br_i31_encode(pk->n, pk->nlen, t);
+ }
+
+ return r;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i31_modulus.c b/contrib/bearssl/src/rsa/rsa_i31_modulus.c
new file mode 100644
index 000000000000..c469cf3c9cf7
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i31_modulus.c
@@ -0,0 +1,99 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+size_t
+br_rsa_i31_compute_modulus(void *n, const br_rsa_private_key *sk)
+{
+ uint32_t tmp[2 * ((BR_MAX_RSA_SIZE + 30) / 31) + 5];
+ uint32_t *t, *p, *q;
+ const unsigned char *pbuf, *qbuf;
+ size_t nlen, plen, qlen, tlen;
+
+ /*
+ * Compute actual byte and lengths for p and q.
+ */
+ pbuf = sk->p;
+ plen = sk->plen;
+ while (plen > 0 && *pbuf == 0) {
+ pbuf ++;
+ plen --;
+ }
+ qbuf = sk->q;
+ qlen = sk->qlen;
+ while (qlen > 0 && *qbuf == 0) {
+ qbuf ++;
+ qlen --;
+ }
+
+ t = tmp;
+ tlen = (sizeof tmp) / (sizeof tmp[0]);
+
+ /*
+ * Decode p.
+ */
+ if ((31 * tlen) < (plen << 3) + 31) {
+ return 0;
+ }
+ br_i31_decode(t, pbuf, plen);
+ p = t;
+ plen = (p[0] + 63) >> 5;
+ t += plen;
+ tlen -= plen;
+
+ /*
+ * Decode q.
+ */
+ if ((31 * tlen) < (qlen << 3) + 31) {
+ return 0;
+ }
+ br_i31_decode(t, qbuf, qlen);
+ q = t;
+ qlen = (q[0] + 63) >> 5;
+ t += qlen;
+ tlen -= qlen;
+
+ /*
+ * Computation can proceed only if we have enough room for the
+ * modulus.
+ */
+ if (tlen < (plen + qlen + 1)) {
+ return 0;
+ }
+
+ /*
+ * Private key already contains the modulus bit length, from which
+ * we can infer the output length. Even if n is NULL, we still had
+ * to decode p and q to make sure that the product can be computed.
+ */
+ nlen = (sk->n_bitlen + 7) >> 3;
+ if (n != NULL) {
+ br_i31_zero(t, p[0]);
+ br_i31_mulacc(t, p, q);
+ br_i31_encode(n, nlen, t);
+ }
+ return nlen;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i31_oaep_decrypt.c b/contrib/bearssl/src/rsa/rsa_i31_oaep_decrypt.c
new file mode 100644
index 000000000000..06fdd93c9058
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i31_oaep_decrypt.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i31_oaep_decrypt(const br_hash_class *dig,
+ const void *label, size_t label_len,
+ const br_rsa_private_key *sk, void *data, size_t *len)
+{
+ uint32_t r;
+
+ if (*len != ((sk->n_bitlen + 7) >> 3)) {
+ return 0;
+ }
+ r = br_rsa_i31_private(data, sk);
+ r &= br_rsa_oaep_unpad(dig, label, label_len, data, len);
+ return r;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i31_oaep_encrypt.c b/contrib/bearssl/src/rsa/rsa_i31_oaep_encrypt.c
new file mode 100644
index 000000000000..367008ce58ef
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i31_oaep_encrypt.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+size_t
+br_rsa_i31_oaep_encrypt(
+ const br_prng_class **rnd, const br_hash_class *dig,
+ const void *label, size_t label_len,
+ const br_rsa_public_key *pk,
+ void *dst, size_t dst_max_len,
+ const void *src, size_t src_len)
+{
+ size_t dlen;
+
+ dlen = br_rsa_oaep_pad(rnd, dig, label, label_len,
+ pk, dst, dst_max_len, src, src_len);
+ if (dlen == 0) {
+ return 0;
+ }
+ return dlen & -(size_t)br_rsa_i31_public(dst, dlen, pk);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i31_pkcs1_sign.c b/contrib/bearssl/src/rsa/rsa_i31_pkcs1_sign.c
new file mode 100644
index 000000000000..784d3c2009e3
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i31_pkcs1_sign.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i31_pkcs1_sign(const unsigned char *hash_oid,
+ const unsigned char *hash, size_t hash_len,
+ const br_rsa_private_key *sk, unsigned char *x)
+{
+ if (!br_rsa_pkcs1_sig_pad(hash_oid, hash, hash_len, sk->n_bitlen, x)) {
+ return 0;
+ }
+ return br_rsa_i31_private(x, sk);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i31_pkcs1_vrfy.c b/contrib/bearssl/src/rsa/rsa_i31_pkcs1_vrfy.c
new file mode 100644
index 000000000000..e79a002d7067
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i31_pkcs1_vrfy.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i31_pkcs1_vrfy(const unsigned char *x, size_t xlen,
+ const unsigned char *hash_oid, size_t hash_len,
+ const br_rsa_public_key *pk, unsigned char *hash_out)
+{
+ unsigned char sig[BR_MAX_RSA_SIZE >> 3];
+
+ if (xlen > (sizeof sig)) {
+ return 0;
+ }
+ memcpy(sig, x, xlen);
+ if (!br_rsa_i31_public(sig, xlen, pk)) {
+ return 0;
+ }
+ return br_rsa_pkcs1_sig_unpad(sig, xlen, hash_oid, hash_len, hash_out);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i31_priv.c b/contrib/bearssl/src/rsa/rsa_i31_priv.c
new file mode 100644
index 000000000000..b1e1244e2971
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i31_priv.c
@@ -0,0 +1,203 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#define U (2 + ((BR_MAX_RSA_FACTOR + 30) / 31))
+#define TLEN (8 * U)
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i31_private(unsigned char *x, const br_rsa_private_key *sk)
+{
+ const unsigned char *p, *q;
+ size_t plen, qlen;
+ size_t fwlen;
+ uint32_t p0i, q0i;
+ size_t xlen, u;
+ uint32_t tmp[1 + TLEN];
+ long z;
+ uint32_t *mp, *mq, *s1, *s2, *t1, *t2, *t3;
+ uint32_t r;
+
+ /*
+ * Compute the actual lengths of p and q, in bytes.
+ * These lengths are not considered secret (we cannot really hide
+ * them anyway in constant-time code).
+ */
+ p = sk->p;
+ plen = sk->plen;
+ while (plen > 0 && *p == 0) {
+ p ++;
+ plen --;
+ }
+ q = sk->q;
+ qlen = sk->qlen;
+ while (qlen > 0 && *q == 0) {
+ q ++;
+ qlen --;
+ }
+
+ /*
+ * Compute the maximum factor length, in words.
+ */
+ z = (long)(plen > qlen ? plen : qlen) << 3;
+ fwlen = 1;
+ while (z > 0) {
+ z -= 31;
+ fwlen ++;
+ }
+
+ /*
+ * Round up the word length to an even number.
+ */
+ fwlen += (fwlen & 1);
+
+ /*
+ * We need to fit at least 6 values in the stack buffer.
+ */
+ if (6 * fwlen > TLEN) {
+ return 0;
+ }
+
+ /*
+ * Compute modulus length (in bytes).
+ */
+ xlen = (sk->n_bitlen + 7) >> 3;
+
+ /*
+ * Decode q.
+ */
+ mq = tmp;
+ br_i31_decode(mq, q, qlen);
+
+ /*
+ * Decode p.
+ */
+ t1 = mq + fwlen;
+ br_i31_decode(t1, p, plen);
+
+ /*
+ * Compute the modulus (product of the two factors), to compare
+ * it with the source value. We use br_i31_mulacc(), since it's
+ * already used later on.
+ */
+ t2 = mq + 2 * fwlen;
+ br_i31_zero(t2, mq[0]);
+ br_i31_mulacc(t2, mq, t1);
+
+ /*
+ * We encode the modulus into bytes, to perform the comparison
+ * with bytes. We know that the product length, in bytes, is
+ * exactly xlen.
+ * The comparison actually computes the carry when subtracting
+ * the modulus from the source value; that carry must be 1 for
+ * a value in the correct range. We keep it in r, which is our
+ * accumulator for the error code.
+ */
+ t3 = mq + 4 * fwlen;
+ br_i31_encode(t3, xlen, t2);
+ u = xlen;
+ r = 0;
+ while (u > 0) {
+ uint32_t wn, wx;
+
+ u --;
+ wn = ((unsigned char *)t3)[u];
+ wx = x[u];
+ r = ((wx - (wn + r)) >> 8) & 1;
+ }
+
+ /*
+ * Move the decoded p to another temporary buffer.
+ */
+ mp = mq + 2 * fwlen;
+ memmove(mp, t1, fwlen * sizeof *t1);
+
+ /*
+ * Compute s2 = x^dq mod q.
+ */
+ q0i = br_i31_ninv31(mq[1]);
+ s2 = mq + fwlen;
+ br_i31_decode_reduce(s2, x, xlen, mq);
+ r &= br_i31_modpow_opt(s2, sk->dq, sk->dqlen, mq, q0i,
+ mq + 3 * fwlen, TLEN - 3 * fwlen);
+
+ /*
+ * Compute s1 = x^dp mod p.
+ */
+ p0i = br_i31_ninv31(mp[1]);
+ s1 = mq + 3 * fwlen;
+ br_i31_decode_reduce(s1, x, xlen, mp);
+ r &= br_i31_modpow_opt(s1, sk->dp, sk->dplen, mp, p0i,
+ mq + 4 * fwlen, TLEN - 4 * fwlen);
+
+ /*
+ * Compute:
+ * h = (s1 - s2)*(1/q) mod p
+ * s1 is an integer modulo p, but s2 is modulo q. PKCS#1 is
+ * unclear about whether p may be lower than q (some existing,
+ * widely deployed implementations of RSA don't tolerate p < q),
+ * but we want to support that occurrence, so we need to use the
+ * reduction function.
+ *
+ * Since we use br_i31_decode_reduce() for iq (purportedly, the
+ * inverse of q modulo p), we also tolerate improperly large
+ * values for this parameter.
+ */
+ t1 = mq + 4 * fwlen;
+ t2 = mq + 5 * fwlen;
+ br_i31_reduce(t2, s2, mp);
+ br_i31_add(s1, mp, br_i31_sub(s1, t2, 1));
+ br_i31_to_monty(s1, mp);
+ br_i31_decode_reduce(t1, sk->iq, sk->iqlen, mp);
+ br_i31_montymul(t2, s1, t1, mp, p0i);
+
+ /*
+ * h is now in t2. We compute the final result:
+ * s = s2 + q*h
+ * All these operations are non-modular.
+ *
+ * We need mq, s2 and t2. We use the t3 buffer as destination.
+ * The buffers mp, s1 and t1 are no longer needed, so we can
+ * reuse them for t3. Moreover, the first step of the computation
+ * is to copy s2 into t3, after which s2 is not needed. Right
+ * now, mq is in slot 0, s2 is in slot 1, and t2 is in slot 5.
+ * Therefore, we have ample room for t3 by simply using s2.
+ */
+ t3 = s2;
+ br_i31_mulacc(t3, mq, t2);
+
+ /*
+ * Encode the result. Since we already checked the value of xlen,
+ * we can just use it right away.
+ */
+ br_i31_encode(x, xlen, t3);
+
+ /*
+ * The only error conditions remaining at that point are invalid
+ * values for p and q (even integers).
+ */
+ return p0i & q0i & r;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i31_privexp.c b/contrib/bearssl/src/rsa/rsa_i31_privexp.c
new file mode 100644
index 000000000000..eee62a096d8a
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i31_privexp.c
@@ -0,0 +1,318 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+size_t
+br_rsa_i31_compute_privexp(void *d,
+ const br_rsa_private_key *sk, uint32_t e)
+{
+ /*
+ * We want to invert e modulo phi = (p-1)(q-1). This first
+ * requires computing phi, which is easy since we have the factors
+ * p and q in the private key structure.
+ *
+ * Since p = 3 mod 4 and q = 3 mod 4, phi/4 is an odd integer.
+ * We could invert e modulo phi/4 then patch the result to
+ * modulo phi, but this would involve assembling three modulus-wide
+ * values (phi/4, 1 and e) and calling moddiv, that requires
+ * three more temporaries, for a total of six big integers, or
+ * slightly more than 3 kB of stack space for RSA-4096. This
+ * exceeds our stack requirements.
+ *
+ * Instead, we first use one step of the extended GCD:
+ *
+ * - We compute phi = k*e + r (Euclidean division of phi by e).
+ * If public exponent e is correct, then r != 0 (e must be
+ * invertible modulo phi). We also have k != 0 since we
+ * enforce non-ridiculously-small factors.
+ *
+ * - We find small u, v such that u*e - v*r = 1 (using a
+ * binary GCD; we can arrange for u < r and v < e, i.e. all
+ * values fit on 32 bits).
+ *
+ * - Solution is: d = u + v*k
+ * This last computation is exact: since u < r and v < e,
+ * the above implies d < r + e*((phi-r)/e) = phi
+ */
+
+ uint32_t tmp[4 * ((BR_MAX_RSA_FACTOR + 30) / 31) + 12];
+ uint32_t *p, *q, *k, *m, *z, *phi;
+ const unsigned char *pbuf, *qbuf;
+ size_t plen, qlen, u, len, dlen;
+ uint32_t r, a, b, u0, v0, u1, v1, he, hr;
+ int i;
+
+ /*
+ * Check that e is correct.
+ */
+ if (e < 3 || (e & 1) == 0) {
+ return 0;
+ }
+
+ /*
+ * Check lengths of p and q, and that they are both odd.
+ */
+ pbuf = sk->p;
+ plen = sk->plen;
+ while (plen > 0 && *pbuf == 0) {
+ pbuf ++;
+ plen --;
+ }
+ if (plen < 5 || plen > (BR_MAX_RSA_FACTOR / 8)
+ || (pbuf[plen - 1] & 1) != 1)
+ {
+ return 0;
+ }
+ qbuf = sk->q;
+ qlen = sk->qlen;
+ while (qlen > 0 && *qbuf == 0) {
+ qbuf ++;
+ qlen --;
+ }
+ if (qlen < 5 || qlen > (BR_MAX_RSA_FACTOR / 8)
+ || (qbuf[qlen - 1] & 1) != 1)
+ {
+ return 0;
+ }
+
+ /*
+ * Output length is that of the modulus.
+ */
+ dlen = (sk->n_bitlen + 7) >> 3;
+ if (d == NULL) {
+ return dlen;
+ }
+
+ p = tmp;
+ br_i31_decode(p, pbuf, plen);
+ plen = (p[0] + 31) >> 5;
+ q = p + 1 + plen;
+ br_i31_decode(q, qbuf, qlen);
+ qlen = (q[0] + 31) >> 5;
+
+ /*
+ * Compute phi = (p-1)*(q-1), then move it over p-1 and q-1 (that
+ * we do not need anymore). The mulacc function sets the announced
+ * bit length of t to be the sum of the announced bit lengths of
+ * p-1 and q-1, which is usually exact but may overshoot by one 1
+ * bit in some cases; we readjust it to its true length.
+ */
+ p[1] --;
+ q[1] --;
+ phi = q + 1 + qlen;
+ br_i31_zero(phi, p[0]);
+ br_i31_mulacc(phi, p, q);
+ len = (phi[0] + 31) >> 5;
+ memmove(tmp, phi, (1 + len) * sizeof *phi);
+ phi = tmp;
+ phi[0] = br_i31_bit_length(phi + 1, len);
+ len = (phi[0] + 31) >> 5;
+
+ /*
+ * Divide phi by public exponent e. The final remainder r must be
+ * non-zero (otherwise, the key is invalid). The quotient is k,
+ * which we write over phi, since we don't need phi after that.
+ */
+ r = 0;
+ for (u = len; u >= 1; u --) {
+ /*
+ * Upon entry, r < e, and phi[u] < 2^31; hence,
+ * hi:lo < e*2^31. Thus, the produced word k[u]
+ * must be lower than 2^31, and the new remainder r
+ * is lower than e.
+ */
+ uint32_t hi, lo;
+
+ hi = r >> 1;
+ lo = (r << 31) + phi[u];
+ phi[u] = br_divrem(hi, lo, e, &r);
+ }
+ if (r == 0) {
+ return 0;
+ }
+ k = phi;
+
+ /*
+ * Compute u and v such that u*e - v*r = GCD(e,r). We use
+ * a binary GCD algorithm, with 6 extra integers a, b,
+ * u0, u1, v0 and v1. Initial values are:
+ * a = e u0 = 1 v0 = 0
+ * b = r u1 = r v1 = e-1
+ * The following invariants are maintained:
+ * a = u0*e - v0*r
+ * b = u1*e - v1*r
+ * 0 < a <= e
+ * 0 < b <= r
+ * 0 <= u0 <= r
+ * 0 <= v0 <= e
+ * 0 <= u1 <= r
+ * 0 <= v1 <= e
+ *
+ * At each iteration, we reduce either a or b by one bit, and
+ * adjust u0, u1, v0 and v1 to maintain the invariants:
+ * - if a is even, then a <- a/2
+ * - otherwise, if b is even, then b <- b/2
+ * - otherwise, if a > b, then a <- (a-b)/2
+ * - otherwise, if b > a, then b <- (b-a)/2
+ * Algorithm stops when a = b. At that point, the common value
+ * is the GCD of e and r; it must be 1 (otherwise, the private
+ * key or public exponent is not valid). The (u0,v0) or (u1,v1)
+ * pairs are the solution we are looking for.
+ *
+ * Since either a or b is reduced by at least 1 bit at each
+ * iteration, 62 iterations are enough to reach the end
+ * condition.
+ *
+ * To maintain the invariants, we must compute the same operations
+ * on the u* and v* values that we do on a and b:
+ * - When a is divided by 2, u0 and v0 must be divided by 2.
+ * - When b is divided by 2, u1 and v1 must be divided by 2.
+ * - When b is subtracted from a, u1 and v1 are subtracted from
+ * u0 and v0, respectively.
+ * - When a is subtracted from b, u0 and v0 are subtracted from
+ * u1 and v1, respectively.
+ *
+ * However, we want to keep the u* and v* values in their proper
+ * ranges. The following remarks apply:
+ *
+ * - When a is divided by 2, then a is even. Therefore:
+ *
+ * * If r is odd, then u0 and v0 must have the same parity;
+ * if they are both odd, then adding r to u0 and e to v0
+ * makes them both even, and the division by 2 brings them
+ * back to the proper range.
+ *
+ * * If r is even, then u0 must be even; if v0 is odd, then
+ * adding r to u0 and e to v0 makes them both even, and the
+ * division by 2 brings them back to the proper range.
+ *
+ * Thus, all we need to do is to look at the parity of v0,
+ * and add (r,e) to (u0,v0) when v0 is odd. In order to avoid
+ * a 32-bit overflow, we can add ((r+1)/2,(e/2)+1) after the
+ * division (r+1 does not overflow since r < e; and (e/2)+1
+ * is equal to (e+1)/2 since e is odd).
+ *
+ * - When we subtract b from a, three cases may occur:
+ *
+ * * u1 <= u0 and v1 <= v0: just do the subtractions
+ *
+ * * u1 > u0 and v1 > v0: compute:
+ * (u0, v0) <- (u0 + r - u1, v0 + e - v1)
+ *
+ * * u1 <= u0 and v1 > v0: compute:
+ * (u0, v0) <- (u0 + r - u1, v0 + e - v1)
+ *
+ * The fourth case (u1 > u0 and v1 <= v0) is not possible
+ * because it would contradict "b < a" (which is the reason
+ * why we subtract b from a).
+ *
+ * The tricky case is the third one: from the equations, it
+ * seems that u0 may go out of range. However, the invariants
+ * and ranges of other values imply that, in that case, the
+ * new u0 does not actually exceed the range.
+ *
+ * We can thus handle the subtraction by adding (r,e) based
+ * solely on the comparison between v0 and v1.
+ */
+ a = e;
+ b = r;
+ u0 = 1;
+ v0 = 0;
+ u1 = r;
+ v1 = e - 1;
+ hr = (r + 1) >> 1;
+ he = (e >> 1) + 1;
+ for (i = 0; i < 62; i ++) {
+ uint32_t oa, ob, agtb, bgta;
+ uint32_t sab, sba, da, db;
+ uint32_t ctl;
+
+ oa = a & 1; /* 1 if a is odd */
+ ob = b & 1; /* 1 if b is odd */
+ agtb = GT(a, b); /* 1 if a > b */
+ bgta = GT(b, a); /* 1 if b > a */
+
+ sab = oa & ob & agtb; /* 1 if a <- a-b */
+ sba = oa & ob & bgta; /* 1 if b <- b-a */
+
+ /* a <- a-b, u0 <- u0-u1, v0 <- v0-v1 */
+ ctl = GT(v1, v0);
+ a -= b & -sab;
+ u0 -= (u1 - (r & -ctl)) & -sab;
+ v0 -= (v1 - (e & -ctl)) & -sab;
+
+ /* b <- b-a, u1 <- u1-u0 mod r, v1 <- v1-v0 mod e */
+ ctl = GT(v0, v1);
+ b -= a & -sba;
+ u1 -= (u0 - (r & -ctl)) & -sba;
+ v1 -= (v0 - (e & -ctl)) & -sba;
+
+ da = NOT(oa) | sab; /* 1 if a <- a/2 */
+ db = (oa & NOT(ob)) | sba; /* 1 if b <- b/2 */
+
+ /* a <- a/2, u0 <- u0/2, v0 <- v0/2 */
+ ctl = v0 & 1;
+ a ^= (a ^ (a >> 1)) & -da;
+ u0 ^= (u0 ^ ((u0 >> 1) + (hr & -ctl))) & -da;
+ v0 ^= (v0 ^ ((v0 >> 1) + (he & -ctl))) & -da;
+
+ /* b <- b/2, u1 <- u1/2 mod r, v1 <- v1/2 mod e */
+ ctl = v1 & 1;
+ b ^= (b ^ (b >> 1)) & -db;
+ u1 ^= (u1 ^ ((u1 >> 1) + (hr & -ctl))) & -db;
+ v1 ^= (v1 ^ ((v1 >> 1) + (he & -ctl))) & -db;
+ }
+
+ /*
+ * Check that the GCD is indeed 1. If not, then the key is invalid
+ * (and there's no harm in leaking that piece of information).
+ */
+ if (a != 1) {
+ return 0;
+ }
+
+ /*
+ * Now we have u0*e - v0*r = 1. Let's compute the result as:
+ * d = u0 + v0*k
+ * We still have k in the tmp[] array, and its announced bit
+ * length is that of phi.
+ */
+ m = k + 1 + len;
+ m[0] = (1 << 5) + 1; /* bit length is 32 bits, encoded */
+ m[1] = v0 & 0x7FFFFFFF;
+ m[2] = v0 >> 31;
+ z = m + 3;
+ br_i31_zero(z, k[0]);
+ z[1] = u0 & 0x7FFFFFFF;
+ z[2] = u0 >> 31;
+ br_i31_mulacc(z, k, m);
+
+ /*
+ * Encode the result.
+ */
+ br_i31_encode(d, dlen, z);
+ return dlen;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i31_pss_sign.c b/contrib/bearssl/src/rsa/rsa_i31_pss_sign.c
new file mode 100644
index 000000000000..b06f3e21e73a
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i31_pss_sign.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i31_pss_sign(const br_prng_class **rng,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const unsigned char *hash, size_t salt_len,
+ const br_rsa_private_key *sk, unsigned char *x)
+{
+ if (!br_rsa_pss_sig_pad(rng, hf_data, hf_mgf1, hash,
+ salt_len, sk->n_bitlen, x))
+ {
+ return 0;
+ }
+ return br_rsa_i31_private(x, sk);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i31_pss_vrfy.c b/contrib/bearssl/src/rsa/rsa_i31_pss_vrfy.c
new file mode 100644
index 000000000000..77a9b28f56ea
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i31_pss_vrfy.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i31_pss_vrfy(const unsigned char *x, size_t xlen,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const void *hash, size_t salt_len, const br_rsa_public_key *pk)
+{
+ unsigned char sig[BR_MAX_RSA_SIZE >> 3];
+
+ if (xlen > (sizeof sig)) {
+ return 0;
+ }
+ memcpy(sig, x, xlen);
+ if (!br_rsa_i31_public(sig, xlen, pk)) {
+ return 0;
+ }
+ return br_rsa_pss_sig_unpad(hf_data, hf_mgf1,
+ hash, salt_len, pk, sig);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i31_pub.c b/contrib/bearssl/src/rsa/rsa_i31_pub.c
new file mode 100644
index 000000000000..d5f3fe2cb51c
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i31_pub.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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"
+
+/*
+ * As a strict minimum, we need four buffers that can hold a
+ * modular integer.
+ */
+#define TLEN (4 * (2 + ((BR_MAX_RSA_SIZE + 30) / 31)))
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i31_public(unsigned char *x, size_t xlen,
+ const br_rsa_public_key *pk)
+{
+ const unsigned char *n;
+ size_t nlen;
+ uint32_t tmp[1 + TLEN];
+ uint32_t *m, *a, *t;
+ size_t fwlen;
+ long z;
+ uint32_t m0i, r;
+
+ /*
+ * Get the actual length of the modulus, and see if it fits within
+ * our stack buffer. We also check that the length of x[] is valid.
+ */
+ n = pk->n;
+ nlen = pk->nlen;
+ while (nlen > 0 && *n == 0) {
+ n ++;
+ nlen --;
+ }
+ if (nlen == 0 || nlen > (BR_MAX_RSA_SIZE >> 3) || xlen != nlen) {
+ return 0;
+ }
+ z = (long)nlen << 3;
+ fwlen = 1;
+ while (z > 0) {
+ z -= 31;
+ fwlen ++;
+ }
+ /*
+ * Round up length to an even number.
+ */
+ fwlen += (fwlen & 1);
+
+ /*
+ * The modulus gets decoded into m[].
+ * The value to exponentiate goes into a[].
+ * The temporaries for modular exponentiation are in t[].
+ */
+ m = tmp;
+ a = m + fwlen;
+ t = m + 2 * fwlen;
+
+ /*
+ * Decode the modulus.
+ */
+ br_i31_decode(m, n, nlen);
+ m0i = br_i31_ninv31(m[1]);
+
+ /*
+ * Note: if m[] is even, then m0i == 0. Otherwise, m0i must be
+ * an odd integer.
+ */
+ r = m0i & 1;
+
+ /*
+ * Decode x[] into a[]; we also check that its value is proper.
+ */
+ r &= br_i31_decode_mod(a, x, xlen, m);
+
+ /*
+ * Compute the modular exponentiation.
+ */
+ br_i31_modpow_opt(a, pk->e, pk->elen, m, m0i, t, TLEN - 2 * fwlen);
+
+ /*
+ * Encode the result.
+ */
+ br_i31_encode(x, xlen, a);
+ return r;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i31_pubexp.c b/contrib/bearssl/src/rsa/rsa_i31_pubexp.c
new file mode 100644
index 000000000000..f26537d8548f
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i31_pubexp.c
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * Recompute public exponent, based on factor p and reduced private
+ * exponent dp.
+ */
+static uint32_t
+get_pubexp(const unsigned char *pbuf, size_t plen,
+ const unsigned char *dpbuf, size_t dplen)
+{
+ /*
+ * dp is the inverse of e modulo p-1. If p = 3 mod 4, then
+ * p-1 = 2*((p-1)/2). Taken modulo 2, e is odd and has inverse 1;
+ * thus, dp must be odd.
+ *
+ * We compute the inverse of dp modulo (p-1)/2. This requires
+ * first reducing dp modulo (p-1)/2 (this can be done with a
+ * conditional subtract, no need to use the generic modular
+ * reduction function); then, we use moddiv.
+ */
+
+ uint32_t tmp[6 * ((BR_MAX_RSA_FACTOR + 61) / 31)];
+ uint32_t *p, *dp, *x;
+ size_t len;
+ uint32_t e;
+
+ /*
+ * Compute actual factor length (in bytes) and check that it fits
+ * under our size constraints.
+ */
+ while (plen > 0 && *pbuf == 0) {
+ pbuf ++;
+ plen --;
+ }
+ if (plen == 0 || plen < 5 || plen > (BR_MAX_RSA_FACTOR / 8)) {
+ return 0;
+ }
+
+ /*
+ * Compute actual reduced exponent length (in bytes) and check that
+ * it is not longer than p.
+ */
+ while (dplen > 0 && *dpbuf == 0) {
+ dpbuf ++;
+ dplen --;
+ }
+ if (dplen > plen || dplen == 0
+ || (dplen == plen && dpbuf[0] > pbuf[0]))
+ {
+ return 0;
+ }
+
+ /*
+ * Verify that p = 3 mod 4 and that dp is odd.
+ */
+ if ((pbuf[plen - 1] & 3) != 3 || (dpbuf[dplen - 1] & 1) != 1) {
+ return 0;
+ }
+
+ /*
+ * Decode p and compute (p-1)/2.
+ */
+ p = tmp;
+ br_i31_decode(p, pbuf, plen);
+ len = (p[0] + 63) >> 5;
+ br_i31_rshift(p, 1);
+
+ /*
+ * Decode dp and make sure its announced bit length matches that of
+ * p (we already know that the size of dp, in bits, does not exceed
+ * the size of p, so we just have to copy the header word).
+ */
+ dp = p + len;
+ memset(dp, 0, len * sizeof *dp);
+ br_i31_decode(dp, dpbuf, dplen);
+ dp[0] = p[0];
+
+ /*
+ * Subtract (p-1)/2 from dp if necessary.
+ */
+ br_i31_sub(dp, p, NOT(br_i31_sub(dp, p, 0)));
+
+ /*
+ * If another subtraction is needed, then this means that the
+ * value was invalid. We don't care to leak information about
+ * invalid keys.
+ */
+ if (br_i31_sub(dp, p, 0) == 0) {
+ return 0;
+ }
+
+ /*
+ * Invert dp modulo (p-1)/2. If the inversion fails, then the
+ * key value was invalid.
+ */
+ x = dp + len;
+ br_i31_zero(x, p[0]);
+ x[1] = 1;
+ if (br_i31_moddiv(x, dp, p, br_i31_ninv31(p[1]), x + len) == 0) {
+ return 0;
+ }
+
+ /*
+ * We now have an inverse. We must set it to zero (error) if its
+ * length is greater than 32 bits and/or if it is an even integer.
+ * Take care that the bit_length function returns an encoded
+ * bit length.
+ */
+ e = (uint32_t)x[1] | ((uint32_t)x[2] << 31);
+ e &= -LT(br_i31_bit_length(x + 1, len - 1), 34);
+ e &= -(e & 1);
+ return e;
+}
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i31_compute_pubexp(const br_rsa_private_key *sk)
+{
+ /*
+ * Get the public exponent from both p and q. This is the right
+ * exponent if we get twice the same value.
+ */
+ uint32_t ep, eq;
+
+ ep = get_pubexp(sk->p, sk->plen, sk->dp, sk->dplen);
+ eq = get_pubexp(sk->q, sk->qlen, sk->dq, sk->dqlen);
+ return ep & -EQ(ep, eq);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i32_oaep_decrypt.c b/contrib/bearssl/src/rsa/rsa_i32_oaep_decrypt.c
new file mode 100644
index 000000000000..ecfd92b1034b
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i32_oaep_decrypt.c
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i32_oaep_decrypt(const br_hash_class *dig,
+ const void *label, size_t label_len,
+ const br_rsa_private_key *sk, void *data, size_t *len)
+{
+ uint32_t r;
+
+ if (*len != ((sk->n_bitlen + 7) >> 3)) {
+ return 0;
+ }
+ r = br_rsa_i32_private(data, sk);
+ r &= br_rsa_oaep_unpad(dig, label, label_len, data, len);
+ return r;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i32_oaep_encrypt.c b/contrib/bearssl/src/rsa/rsa_i32_oaep_encrypt.c
new file mode 100644
index 000000000000..dc17f3f2bfd3
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i32_oaep_encrypt.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+size_t
+br_rsa_i32_oaep_encrypt(
+ const br_prng_class **rnd, const br_hash_class *dig,
+ const void *label, size_t label_len,
+ const br_rsa_public_key *pk,
+ void *dst, size_t dst_max_len,
+ const void *src, size_t src_len)
+{
+ size_t dlen;
+
+ dlen = br_rsa_oaep_pad(rnd, dig, label, label_len,
+ pk, dst, dst_max_len, src, src_len);
+ if (dlen == 0) {
+ return 0;
+ }
+ return dlen & -(size_t)br_rsa_i32_public(dst, dlen, pk);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i32_pkcs1_sign.c b/contrib/bearssl/src/rsa/rsa_i32_pkcs1_sign.c
new file mode 100644
index 000000000000..44b6e6d51764
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i32_pkcs1_sign.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i32_pkcs1_sign(const unsigned char *hash_oid,
+ const unsigned char *hash, size_t hash_len,
+ const br_rsa_private_key *sk, unsigned char *x)
+{
+ if (!br_rsa_pkcs1_sig_pad(hash_oid, hash, hash_len, sk->n_bitlen, x)) {
+ return 0;
+ }
+ return br_rsa_i32_private(x, sk);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i32_pkcs1_vrfy.c b/contrib/bearssl/src/rsa/rsa_i32_pkcs1_vrfy.c
new file mode 100644
index 000000000000..6ee7a198f221
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i32_pkcs1_vrfy.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i32_pkcs1_vrfy(const unsigned char *x, size_t xlen,
+ const unsigned char *hash_oid, size_t hash_len,
+ const br_rsa_public_key *pk, unsigned char *hash_out)
+{
+ unsigned char sig[BR_MAX_RSA_SIZE >> 3];
+
+ if (xlen > (sizeof sig)) {
+ return 0;
+ }
+ memcpy(sig, x, xlen);
+ if (!br_rsa_i32_public(sig, xlen, pk)) {
+ return 0;
+ }
+ return br_rsa_pkcs1_sig_unpad(sig, xlen, hash_oid, hash_len, hash_out);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i32_priv.c b/contrib/bearssl/src/rsa/rsa_i32_priv.c
new file mode 100644
index 000000000000..05c22ec39ce9
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i32_priv.c
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#define U (1 + (BR_MAX_RSA_FACTOR >> 5))
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i32_private(unsigned char *x, const br_rsa_private_key *sk)
+{
+ const unsigned char *p, *q;
+ size_t plen, qlen;
+ uint32_t tmp[6 * U];
+ uint32_t *mp, *mq, *s1, *s2, *t1, *t2, *t3;
+ uint32_t p0i, q0i;
+ size_t xlen, u;
+ uint32_t r;
+
+ /*
+ * All our temporary buffers are from the tmp[] array.
+ *
+ * The mp, mq, s1, s2, t1 and t2 buffers are large enough to
+ * contain a RSA factor. The t3 buffer can contain a complete
+ * RSA modulus. t3 shares its storage space with s2, s1 and t1,
+ * in that order (this is important, see below).
+ */
+ mq = tmp;
+ mp = tmp + U;
+ t2 = tmp + 2 * U;
+ s2 = tmp + 3 * U;
+ s1 = tmp + 4 * U;
+ t1 = tmp + 5 * U;
+ t3 = s2;
+
+ /*
+ * Compute the actual lengths (in bytes) of p and q, and check
+ * that they fit within our stack buffers.
+ */
+ p = sk->p;
+ plen = sk->plen;
+ while (plen > 0 && *p == 0) {
+ p ++;
+ plen --;
+ }
+ q = sk->q;
+ qlen = sk->qlen;
+ while (qlen > 0 && *q == 0) {
+ q ++;
+ qlen --;
+ }
+ if (plen > (BR_MAX_RSA_FACTOR >> 3)
+ || qlen > (BR_MAX_RSA_FACTOR >> 3))
+ {
+ return 0;
+ }
+
+ /*
+ * Decode p and q.
+ */
+ br_i32_decode(mp, p, plen);
+ br_i32_decode(mq, q, qlen);
+
+ /*
+ * Recompute modulus, to compare with the source value.
+ */
+ br_i32_zero(t2, mp[0]);
+ br_i32_mulacc(t2, mp, mq);
+ xlen = (sk->n_bitlen + 7) >> 3;
+ br_i32_encode(t2 + 2 * U, xlen, t2);
+ u = xlen;
+ r = 0;
+ while (u > 0) {
+ uint32_t wn, wx;
+
+ u --;
+ wn = ((unsigned char *)(t2 + 2 * U))[u];
+ wx = x[u];
+ r = ((wx - (wn + r)) >> 8) & 1;
+ }
+
+ /*
+ * Compute s1 = x^dp mod p.
+ */
+ p0i = br_i32_ninv32(mp[1]);
+ br_i32_decode_reduce(s1, x, xlen, mp);
+ br_i32_modpow(s1, sk->dp, sk->dplen, mp, p0i, t1, t2);
+
+ /*
+ * Compute s2 = x^dq mod q.
+ */
+ q0i = br_i32_ninv32(mq[1]);
+ br_i32_decode_reduce(s2, x, xlen, mq);
+ br_i32_modpow(s2, sk->dq, sk->dqlen, mq, q0i, t1, t2);
+
+ /*
+ * Compute:
+ * h = (s1 - s2)*(1/q) mod p
+ * s1 is an integer modulo p, but s2 is modulo q. PKCS#1 is
+ * unclear about whether p may be lower than q (some existing,
+ * widely deployed implementations of RSA don't tolerate p < q),
+ * but we want to support that occurrence, so we need to use the
+ * reduction function.
+ *
+ * Since we use br_i32_decode_reduce() for iq (purportedly, the
+ * inverse of q modulo p), we also tolerate improperly large
+ * values for this parameter.
+ */
+ br_i32_reduce(t2, s2, mp);
+ br_i32_add(s1, mp, br_i32_sub(s1, t2, 1));
+ br_i32_to_monty(s1, mp);
+ br_i32_decode_reduce(t1, sk->iq, sk->iqlen, mp);
+ br_i32_montymul(t2, s1, t1, mp, p0i);
+
+ /*
+ * h is now in t2. We compute the final result:
+ * s = s2 + q*h
+ * All these operations are non-modular.
+ *
+ * We need mq, s2 and t2. We use the t3 buffer as destination.
+ * The buffers mp, s1 and t1 are no longer needed. Moreover,
+ * the first step is to copy s2 into the destination buffer t3.
+ * We thus arranged for t3 to actually share space with s2, and
+ * to be followed by the space formerly used by s1 and t1.
+ */
+ br_i32_mulacc(t3, mq, t2);
+
+ /*
+ * Encode the result. Since we already checked the value of xlen,
+ * we can just use it right away.
+ */
+ br_i32_encode(x, xlen, t3);
+
+ /*
+ * The only error conditions remaining at that point are invalid
+ * values for p and q (even integers).
+ */
+ return p0i & q0i & r;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i32_pss_sign.c b/contrib/bearssl/src/rsa/rsa_i32_pss_sign.c
new file mode 100644
index 000000000000..0f72f9274e25
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i32_pss_sign.c
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i32_pss_sign(const br_prng_class **rng,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const unsigned char *hash, size_t salt_len,
+ const br_rsa_private_key *sk, unsigned char *x)
+{
+ if (!br_rsa_pss_sig_pad(rng, hf_data, hf_mgf1, hash,
+ salt_len, sk->n_bitlen, x))
+ {
+ return 0;
+ }
+ return br_rsa_i32_private(x, sk);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i32_pss_vrfy.c b/contrib/bearssl/src/rsa/rsa_i32_pss_vrfy.c
new file mode 100644
index 000000000000..2e70d2348394
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i32_pss_vrfy.c
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i32_pss_vrfy(const unsigned char *x, size_t xlen,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const void *hash, size_t salt_len, const br_rsa_public_key *pk)
+{
+ unsigned char sig[BR_MAX_RSA_SIZE >> 3];
+
+ if (xlen > (sizeof sig)) {
+ return 0;
+ }
+ memcpy(sig, x, xlen);
+ if (!br_rsa_i32_public(sig, xlen, pk)) {
+ return 0;
+ }
+ return br_rsa_pss_sig_unpad(hf_data, hf_mgf1,
+ hash, salt_len, pk, sig);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i32_pub.c b/contrib/bearssl/src/rsa/rsa_i32_pub.c
new file mode 100644
index 000000000000..6e8d8e3eb19f
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i32_pub.c
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i32_public(unsigned char *x, size_t xlen,
+ const br_rsa_public_key *pk)
+{
+ const unsigned char *n;
+ size_t nlen;
+ uint32_t m[1 + (BR_MAX_RSA_SIZE >> 5)];
+ uint32_t a[1 + (BR_MAX_RSA_SIZE >> 5)];
+ uint32_t t1[1 + (BR_MAX_RSA_SIZE >> 5)];
+ uint32_t t2[1 + (BR_MAX_RSA_SIZE >> 5)];
+ uint32_t m0i, r;
+
+ /*
+ * Get the actual length of the modulus, and see if it fits within
+ * our stack buffer. We also check that the length of x[] is valid.
+ */
+ n = pk->n;
+ nlen = pk->nlen;
+ while (nlen > 0 && *n == 0) {
+ n ++;
+ nlen --;
+ }
+ if (nlen == 0 || nlen > (BR_MAX_RSA_SIZE >> 3) || xlen != nlen) {
+ return 0;
+ }
+ br_i32_decode(m, n, nlen);
+ m0i = br_i32_ninv32(m[1]);
+
+ /*
+ * Note: if m[] is even, then m0i == 0. Otherwise, m0i must be
+ * an odd integer.
+ */
+ r = m0i & 1;
+
+ /*
+ * Decode x[] into a[]; we also check that its value is proper.
+ */
+ r &= br_i32_decode_mod(a, x, xlen, m);
+
+ /*
+ * Compute the modular exponentiation.
+ */
+ br_i32_modpow(a, pk->e, pk->elen, m, m0i, t1, t2);
+
+ /*
+ * Encode the result.
+ */
+ br_i32_encode(x, xlen, a);
+ return r;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_i62_keygen.c b/contrib/bearssl/src/rsa/rsa_i62_keygen.c
new file mode 100644
index 000000000000..8f55c3759082
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i62_keygen.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#if BR_INT128 || BR_UMUL128
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i62_keygen(const br_prng_class **rng,
+ br_rsa_private_key *sk, void *kbuf_priv,
+ br_rsa_public_key *pk, void *kbuf_pub,
+ unsigned size, uint32_t pubexp)
+{
+ return br_rsa_i31_keygen_inner(rng,
+ sk, kbuf_priv, pk, kbuf_pub, size, pubexp,
+ &br_i62_modpow_opt_as_i31);
+}
+
+/* see bearssl_rsa.h */
+br_rsa_keygen
+br_rsa_i62_keygen_get()
+{
+ return &br_rsa_i62_keygen;
+}
+
+#else
+
+/* see bearssl_rsa.h */
+br_rsa_keygen
+br_rsa_i62_keygen_get()
+{
+ return 0;
+}
+
+#endif
diff --git a/contrib/bearssl/src/rsa/rsa_i62_oaep_decrypt.c b/contrib/bearssl/src/rsa/rsa_i62_oaep_decrypt.c
new file mode 100644
index 000000000000..38470dd3b1e0
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i62_oaep_decrypt.c
@@ -0,0 +1,61 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#if BR_INT128 || BR_UMUL128
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i62_oaep_decrypt(const br_hash_class *dig,
+ const void *label, size_t label_len,
+ const br_rsa_private_key *sk, void *data, size_t *len)
+{
+ uint32_t r;
+
+ if (*len != ((sk->n_bitlen + 7) >> 3)) {
+ return 0;
+ }
+ r = br_rsa_i62_private(data, sk);
+ r &= br_rsa_oaep_unpad(dig, label, label_len, data, len);
+ return r;
+}
+
+/* see bearssl_rsa.h */
+br_rsa_oaep_decrypt
+br_rsa_i62_oaep_decrypt_get(void)
+{
+ return &br_rsa_i62_oaep_decrypt;
+}
+
+#else
+
+/* see bearssl_rsa.h */
+br_rsa_oaep_decrypt
+br_rsa_i62_oaep_decrypt_get(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/contrib/bearssl/src/rsa/rsa_i62_oaep_encrypt.c b/contrib/bearssl/src/rsa/rsa_i62_oaep_encrypt.c
new file mode 100644
index 000000000000..cf41ecb888e4
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i62_oaep_encrypt.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#if BR_INT128 || BR_UMUL128
+
+/* see bearssl_rsa.h */
+size_t
+br_rsa_i62_oaep_encrypt(
+ const br_prng_class **rnd, const br_hash_class *dig,
+ const void *label, size_t label_len,
+ const br_rsa_public_key *pk,
+ void *dst, size_t dst_max_len,
+ const void *src, size_t src_len)
+{
+ size_t dlen;
+
+ dlen = br_rsa_oaep_pad(rnd, dig, label, label_len,
+ pk, dst, dst_max_len, src, src_len);
+ if (dlen == 0) {
+ return 0;
+ }
+ return dlen & -(size_t)br_rsa_i62_public(dst, dlen, pk);
+}
+
+/* see bearssl_rsa.h */
+br_rsa_oaep_encrypt
+br_rsa_i62_oaep_encrypt_get(void)
+{
+ return &br_rsa_i62_oaep_encrypt;
+}
+
+#else
+
+/* see bearssl_rsa.h */
+br_rsa_oaep_encrypt
+br_rsa_i62_oaep_encrypt_get(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/contrib/bearssl/src/rsa/rsa_i62_pkcs1_sign.c b/contrib/bearssl/src/rsa/rsa_i62_pkcs1_sign.c
new file mode 100644
index 000000000000..a20a0846c8ec
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i62_pkcs1_sign.c
@@ -0,0 +1,57 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#if BR_INT128 || BR_UMUL128
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i62_pkcs1_sign(const unsigned char *hash_oid,
+ const unsigned char *hash, size_t hash_len,
+ const br_rsa_private_key *sk, unsigned char *x)
+{
+ if (!br_rsa_pkcs1_sig_pad(hash_oid, hash, hash_len, sk->n_bitlen, x)) {
+ return 0;
+ }
+ return br_rsa_i62_private(x, sk);
+}
+
+/* see bearssl_rsa.h */
+br_rsa_pkcs1_sign
+br_rsa_i62_pkcs1_sign_get(void)
+{
+ return &br_rsa_i62_pkcs1_sign;
+}
+
+#else
+
+/* see bearssl_rsa.h */
+br_rsa_pkcs1_sign
+br_rsa_i62_pkcs1_sign_get(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/contrib/bearssl/src/rsa/rsa_i62_pkcs1_vrfy.c b/contrib/bearssl/src/rsa/rsa_i62_pkcs1_vrfy.c
new file mode 100644
index 000000000000..6519161b12d2
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i62_pkcs1_vrfy.c
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#if BR_INT128 || BR_UMUL128
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i62_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)
+{
+ unsigned char sig[BR_MAX_RSA_SIZE >> 3];
+
+ if (xlen > (sizeof sig)) {
+ return 0;
+ }
+ memcpy(sig, x, xlen);
+ if (!br_rsa_i62_public(sig, xlen, pk)) {
+ return 0;
+ }
+ return br_rsa_pkcs1_sig_unpad(sig, xlen, hash_oid, hash_len, hash_out);
+}
+
+/* see bearssl_rsa.h */
+br_rsa_pkcs1_vrfy
+br_rsa_i62_pkcs1_vrfy_get(void)
+{
+ return &br_rsa_i62_pkcs1_vrfy;
+}
+
+#else
+
+/* see bearssl_rsa.h */
+br_rsa_pkcs1_vrfy
+br_rsa_i62_pkcs1_vrfy_get(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/contrib/bearssl/src/rsa/rsa_i62_priv.c b/contrib/bearssl/src/rsa/rsa_i62_priv.c
new file mode 100644
index 000000000000..f0da60065761
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i62_priv.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#if BR_INT128 || BR_UMUL128
+
+#define U (2 + ((BR_MAX_RSA_FACTOR + 30) / 31))
+#define TLEN (4 * U) /* TLEN is counted in 64-bit words */
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i62_private(unsigned char *x, const br_rsa_private_key *sk)
+{
+ const unsigned char *p, *q;
+ size_t plen, qlen;
+ size_t fwlen;
+ uint32_t p0i, q0i;
+ size_t xlen, u;
+ uint64_t tmp[TLEN];
+ long z;
+ uint32_t *mp, *mq, *s1, *s2, *t1, *t2, *t3;
+ uint32_t r;
+
+ /*
+ * Compute the actual lengths of p and q, in bytes.
+ * These lengths are not considered secret (we cannot really hide
+ * them anyway in constant-time code).
+ */
+ p = sk->p;
+ plen = sk->plen;
+ while (plen > 0 && *p == 0) {
+ p ++;
+ plen --;
+ }
+ q = sk->q;
+ qlen = sk->qlen;
+ while (qlen > 0 && *q == 0) {
+ q ++;
+ qlen --;
+ }
+
+ /*
+ * Compute the maximum factor length, in words.
+ */
+ z = (long)(plen > qlen ? plen : qlen) << 3;
+ fwlen = 1;
+ while (z > 0) {
+ z -= 31;
+ fwlen ++;
+ }
+
+ /*
+ * Convert size to 62-bit words.
+ */
+ fwlen = (fwlen + 1) >> 1;
+
+ /*
+ * We need to fit at least 6 values in the stack buffer.
+ */
+ if (6 * fwlen > TLEN) {
+ return 0;
+ }
+
+ /*
+ * Compute signature length (in bytes).
+ */
+ xlen = (sk->n_bitlen + 7) >> 3;
+
+ /*
+ * Decode q.
+ */
+ mq = (uint32_t *)tmp;
+ br_i31_decode(mq, q, qlen);
+
+ /*
+ * Decode p.
+ */
+ t1 = (uint32_t *)(tmp + fwlen);
+ br_i31_decode(t1, p, plen);
+
+ /*
+ * Compute the modulus (product of the two factors), to compare
+ * it with the source value. We use br_i31_mulacc(), since it's
+ * already used later on.
+ */
+ t2 = (uint32_t *)(tmp + 2 * fwlen);
+ br_i31_zero(t2, mq[0]);
+ br_i31_mulacc(t2, mq, t1);
+
+ /*
+ * We encode the modulus into bytes, to perform the comparison
+ * with bytes. We know that the product length, in bytes, is
+ * exactly xlen.
+ * The comparison actually computes the carry when subtracting
+ * the modulus from the source value; that carry must be 1 for
+ * a value in the correct range. We keep it in r, which is our
+ * accumulator for the error code.
+ */
+ t3 = (uint32_t *)(tmp + 4 * fwlen);
+ br_i31_encode(t3, xlen, t2);
+ u = xlen;
+ r = 0;
+ while (u > 0) {
+ uint32_t wn, wx;
+
+ u --;
+ wn = ((unsigned char *)t3)[u];
+ wx = x[u];
+ r = ((wx - (wn + r)) >> 8) & 1;
+ }
+
+ /*
+ * Move the decoded p to another temporary buffer.
+ */
+ mp = (uint32_t *)(tmp + 2 * fwlen);
+ memmove(mp, t1, 2 * fwlen * sizeof *t1);
+
+ /*
+ * Compute s2 = x^dq mod q.
+ */
+ q0i = br_i31_ninv31(mq[1]);
+ s2 = (uint32_t *)(tmp + fwlen);
+ br_i31_decode_reduce(s2, x, xlen, mq);
+ r &= br_i62_modpow_opt(s2, sk->dq, sk->dqlen, mq, q0i,
+ tmp + 3 * fwlen, TLEN - 3 * fwlen);
+
+ /*
+ * Compute s1 = x^dp mod p.
+ */
+ p0i = br_i31_ninv31(mp[1]);
+ s1 = (uint32_t *)(tmp + 3 * fwlen);
+ br_i31_decode_reduce(s1, x, xlen, mp);
+ r &= br_i62_modpow_opt(s1, sk->dp, sk->dplen, mp, p0i,
+ tmp + 4 * fwlen, TLEN - 4 * fwlen);
+
+ /*
+ * Compute:
+ * h = (s1 - s2)*(1/q) mod p
+ * s1 is an integer modulo p, but s2 is modulo q. PKCS#1 is
+ * unclear about whether p may be lower than q (some existing,
+ * widely deployed implementations of RSA don't tolerate p < q),
+ * but we want to support that occurrence, so we need to use the
+ * reduction function.
+ *
+ * Since we use br_i31_decode_reduce() for iq (purportedly, the
+ * inverse of q modulo p), we also tolerate improperly large
+ * values for this parameter.
+ */
+ t1 = (uint32_t *)(tmp + 4 * fwlen);
+ t2 = (uint32_t *)(tmp + 5 * fwlen);
+ br_i31_reduce(t2, s2, mp);
+ br_i31_add(s1, mp, br_i31_sub(s1, t2, 1));
+ br_i31_to_monty(s1, mp);
+ br_i31_decode_reduce(t1, sk->iq, sk->iqlen, mp);
+ br_i31_montymul(t2, s1, t1, mp, p0i);
+
+ /*
+ * h is now in t2. We compute the final result:
+ * s = s2 + q*h
+ * All these operations are non-modular.
+ *
+ * We need mq, s2 and t2. We use the t3 buffer as destination.
+ * The buffers mp, s1 and t1 are no longer needed, so we can
+ * reuse them for t3. Moreover, the first step of the computation
+ * is to copy s2 into t3, after which s2 is not needed. Right
+ * now, mq is in slot 0, s2 is in slot 1, and t2 is in slot 5.
+ * Therefore, we have ample room for t3 by simply using s2.
+ */
+ t3 = s2;
+ br_i31_mulacc(t3, mq, t2);
+
+ /*
+ * Encode the result. Since we already checked the value of xlen,
+ * we can just use it right away.
+ */
+ br_i31_encode(x, xlen, t3);
+
+ /*
+ * The only error conditions remaining at that point are invalid
+ * values for p and q (even integers).
+ */
+ return p0i & q0i & r;
+}
+
+/* see bearssl_rsa.h */
+br_rsa_private
+br_rsa_i62_private_get(void)
+{
+ return &br_rsa_i62_private;
+}
+
+#else
+
+/* see bearssl_rsa.h */
+br_rsa_private
+br_rsa_i62_private_get(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/contrib/bearssl/src/rsa/rsa_i62_pss_sign.c b/contrib/bearssl/src/rsa/rsa_i62_pss_sign.c
new file mode 100644
index 000000000000..7232f6d550c4
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i62_pss_sign.c
@@ -0,0 +1,60 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#if BR_INT128 || BR_UMUL128
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i62_pss_sign(const br_prng_class **rng,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const unsigned char *hash, size_t salt_len,
+ const br_rsa_private_key *sk, unsigned char *x)
+{
+ if (!br_rsa_pss_sig_pad(rng, hf_data, hf_mgf1, hash,
+ salt_len, sk->n_bitlen, x))
+ {
+ return 0;
+ }
+ return br_rsa_i62_private(x, sk);
+}
+
+/* see bearssl_rsa.h */
+br_rsa_pss_sign
+br_rsa_i62_pss_sign_get(void)
+{
+ return &br_rsa_i62_pss_sign;
+}
+
+#else
+
+/* see bearssl_rsa.h */
+br_rsa_pss_sign
+br_rsa_i62_pss_sign_get(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/contrib/bearssl/src/rsa/rsa_i62_pss_vrfy.c b/contrib/bearssl/src/rsa/rsa_i62_pss_vrfy.c
new file mode 100644
index 000000000000..e726e823a2b1
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i62_pss_vrfy.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#if BR_INT128 || BR_UMUL128
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i62_pss_vrfy(const unsigned char *x, size_t xlen,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const void *hash, size_t salt_len, const br_rsa_public_key *pk)
+{
+ unsigned char sig[BR_MAX_RSA_SIZE >> 3];
+
+ if (xlen > (sizeof sig)) {
+ return 0;
+ }
+ memcpy(sig, x, xlen);
+ if (!br_rsa_i62_public(sig, xlen, pk)) {
+ return 0;
+ }
+ return br_rsa_pss_sig_unpad(hf_data, hf_mgf1,
+ hash, salt_len, pk, sig);
+}
+
+/* see bearssl_rsa.h */
+br_rsa_pss_vrfy
+br_rsa_i62_pss_vrfy_get(void)
+{
+ return &br_rsa_i62_pss_vrfy;
+}
+
+#else
+
+/* see bearssl_rsa.h */
+br_rsa_pss_vrfy
+br_rsa_i62_pss_vrfy_get(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/contrib/bearssl/src/rsa/rsa_i62_pub.c b/contrib/bearssl/src/rsa/rsa_i62_pub.c
new file mode 100644
index 000000000000..70cf61bd2d73
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_i62_pub.c
@@ -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.
+ */
+
+#include "inner.h"
+
+#if BR_INT128 || BR_UMUL128
+
+/*
+ * As a strict minimum, we need four buffers that can hold a
+ * modular integer. But TLEN is expressed in 64-bit words.
+ */
+#define TLEN (2 * (2 + ((BR_MAX_RSA_SIZE + 30) / 31)))
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_i62_public(unsigned char *x, size_t xlen,
+ const br_rsa_public_key *pk)
+{
+ const unsigned char *n;
+ size_t nlen;
+ uint64_t tmp[TLEN];
+ uint32_t *m, *a;
+ size_t fwlen;
+ long z;
+ uint32_t m0i, r;
+
+ /*
+ * Get the actual length of the modulus, and see if it fits within
+ * our stack buffer. We also check that the length of x[] is valid.
+ */
+ n = pk->n;
+ nlen = pk->nlen;
+ while (nlen > 0 && *n == 0) {
+ n ++;
+ nlen --;
+ }
+ if (nlen == 0 || nlen > (BR_MAX_RSA_SIZE >> 3) || xlen != nlen) {
+ return 0;
+ }
+ z = (long)nlen << 3;
+ fwlen = 1;
+ while (z > 0) {
+ z -= 31;
+ fwlen ++;
+ }
+ /*
+ * Convert fwlen to a count in 62-bit words.
+ */
+ fwlen = (fwlen + 1) >> 1;
+
+ /*
+ * The modulus gets decoded into m[].
+ * The value to exponentiate goes into a[].
+ */
+ m = (uint32_t *)tmp;
+ a = (uint32_t *)(tmp + fwlen);
+
+ /*
+ * Decode the modulus.
+ */
+ br_i31_decode(m, n, nlen);
+ m0i = br_i31_ninv31(m[1]);
+
+ /*
+ * Note: if m[] is even, then m0i == 0. Otherwise, m0i must be
+ * an odd integer.
+ */
+ r = m0i & 1;
+
+ /*
+ * Decode x[] into a[]; we also check that its value is proper.
+ */
+ r &= br_i31_decode_mod(a, x, xlen, m);
+
+ /*
+ * Compute the modular exponentiation.
+ */
+ br_i62_modpow_opt(a, pk->e, pk->elen, m, m0i,
+ tmp + 2 * fwlen, TLEN - 2 * fwlen);
+
+ /*
+ * Encode the result.
+ */
+ br_i31_encode(x, xlen, a);
+ return r;
+}
+
+/* see bearssl_rsa.h */
+br_rsa_public
+br_rsa_i62_public_get(void)
+{
+ return &br_rsa_i62_public;
+}
+
+#else
+
+/* see bearssl_rsa.h */
+br_rsa_public
+br_rsa_i62_public_get(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/contrib/bearssl/src/rsa/rsa_oaep_pad.c b/contrib/bearssl/src/rsa/rsa_oaep_pad.c
new file mode 100644
index 000000000000..5327dc26553c
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_oaep_pad.c
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * Hash some data. This is put as a separate function so that stack
+ * allocation of the hash function context is done only for the duration
+ * of the hash.
+ */
+static void
+hash_data(const br_hash_class *dig, void *dst, const void *src, size_t len)
+{
+ br_hash_compat_context hc;
+
+ hc.vtable = dig;
+ dig->init(&hc.vtable);
+ dig->update(&hc.vtable, src, len);
+ dig->out(&hc.vtable, dst);
+}
+
+/* see inner.h */
+size_t
+br_rsa_oaep_pad(const br_prng_class **rnd, const br_hash_class *dig,
+ const void *label, size_t label_len,
+ const br_rsa_public_key *pk,
+ void *dst, size_t dst_max_len,
+ const void *src, size_t src_len)
+{
+ size_t k, hlen;
+ unsigned char *buf;
+
+ hlen = br_digest_size(dig);
+
+ /*
+ * Compute actual modulus length (in bytes).
+ */
+ k = pk->nlen;
+ while (k > 0 && pk->n[k - 1] == 0) {
+ k --;
+ }
+
+ /*
+ * An error is reported if:
+ * - the modulus is too short;
+ * - the source message length is too long;
+ * - the destination buffer is too short.
+ */
+ if (k < ((hlen << 1) + 2)
+ || src_len > (k - (hlen << 1) - 2)
+ || dst_max_len < k)
+ {
+ return 0;
+ }
+
+ /*
+ * Apply padding. At this point, things cannot fail.
+ */
+ buf = dst;
+
+ /*
+ * Assemble: DB = lHash || PS || 0x01 || M
+ * We first place the source message M with memmove(), so that
+ * overlaps between source and destination buffers are supported.
+ */
+ memmove(buf + k - src_len, src, src_len);
+ hash_data(dig, buf + 1 + hlen, label, label_len);
+ memset(buf + 1 + (hlen << 1), 0, k - src_len - (hlen << 1) - 2);
+ buf[k - src_len - 1] = 0x01;
+
+ /*
+ * Make the random seed.
+ */
+ (*rnd)->generate(rnd, buf + 1, hlen);
+
+ /*
+ * Mask DB with the mask generated from the seed.
+ */
+ br_mgf1_xor(buf + 1 + hlen, k - hlen - 1, dig, buf + 1, hlen);
+
+ /*
+ * Mask the seed with the mask generated from the masked DB.
+ */
+ br_mgf1_xor(buf + 1, hlen, dig, buf + 1 + hlen, k - hlen - 1);
+
+ /*
+ * Padding result: EM = 0x00 || maskedSeed || maskedDB.
+ */
+ buf[0] = 0x00;
+ return k;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_oaep_unpad.c b/contrib/bearssl/src/rsa/rsa_oaep_unpad.c
new file mode 100644
index 000000000000..7c4be6a83fb5
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_oaep_unpad.c
@@ -0,0 +1,145 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * Hash some data and XOR the result into the provided buffer. This is put
+ * as a separate function so that stack allocation of the hash function
+ * context is done only for the duration of the hash.
+ */
+static void
+xor_hash_data(const br_hash_class *dig, void *dst, const void *src, size_t len)
+{
+ br_hash_compat_context hc;
+ unsigned char tmp[64];
+ unsigned char *buf;
+ size_t u, hlen;
+
+ hc.vtable = dig;
+ dig->init(&hc.vtable);
+ dig->update(&hc.vtable, src, len);
+ dig->out(&hc.vtable, tmp);
+ buf = dst;
+ hlen = br_digest_size(dig);
+ for (u = 0; u < hlen; u ++) {
+ buf[u] ^= tmp[u];
+ }
+}
+
+/* see inner.h */
+uint32_t
+br_rsa_oaep_unpad(const br_hash_class *dig,
+ const void *label, size_t label_len,
+ void *data, size_t *len)
+{
+ size_t u, k, hlen;
+ unsigned char *buf;
+ uint32_t r, s, zlen;
+
+ hlen = br_digest_size(dig);
+ k = *len;
+ buf = data;
+
+ /*
+ * There must be room for the padding.
+ */
+ if (k < ((hlen << 1) + 2)) {
+ return 0;
+ }
+
+ /*
+ * Unmask the seed, then the DB value.
+ */
+ br_mgf1_xor(buf + 1, hlen, dig, buf + 1 + hlen, k - hlen - 1);
+ br_mgf1_xor(buf + 1 + hlen, k - hlen - 1, dig, buf + 1, hlen);
+
+ /*
+ * Hash the label and XOR it with the value in the array; if
+ * they are equal then these should yield only zeros.
+ */
+ xor_hash_data(dig, buf + 1 + hlen, label, label_len);
+
+ /*
+ * At that point, if the padding was correct, when we should
+ * have: 0x00 || seed || 0x00 ... 0x00 0x01 || M
+ * Padding is valid as long as:
+ * - There is at least hlen+1 leading bytes of value 0x00.
+ * - There is at least one non-zero byte.
+ * - The first (leftmost) non-zero byte has value 0x01.
+ *
+ * Ultimately, we may leak the resulting message length, i.e.
+ * the position of the byte of value 0x01, but we must take care
+ * to do so only if the number of zero bytes has been verified
+ * to be at least hlen+1.
+ *
+ * The loop below counts the number of bytes of value 0x00, and
+ * checks that the next byte has value 0x01, in constant-time.
+ *
+ * - If the initial byte (before the seed) is not 0x00, then
+ * r and s are set to 0, and stay there.
+ * - Value r is 1 until the first non-zero byte is reached
+ * (after the seed); it switches to 0 at that point.
+ * - Value s is set to 1 if and only if the data encountered
+ * at the time of the transition of r from 1 to 0 has value
+ * exactly 0x01.
+ * - Value zlen counts the number of leading bytes of value zero
+ * (after the seed).
+ */
+ r = 1 - ((buf[0] + 0xFF) >> 8);
+ s = 0;
+ zlen = 0;
+ for (u = hlen + 1; u < k; u ++) {
+ uint32_t w, nz;
+
+ w = buf[u];
+
+ /*
+ * nz == 1 only for the first non-zero byte.
+ */
+ nz = r & ((w + 0xFF) >> 8);
+ s |= nz & EQ(w, 0x01);
+ r &= NOT(nz);
+ zlen += r;
+ }
+
+ /*
+ * Padding is correct only if s == 1, _and_ zlen >= hlen.
+ */
+ s &= GE(zlen, (uint32_t)hlen);
+
+ /*
+ * At that point, padding was verified, and we are now allowed
+ * to make conditional jumps.
+ */
+ if (s) {
+ size_t plen;
+
+ plen = 2 + hlen + zlen;
+ k -= plen;
+ memmove(buf, buf + plen, k);
+ *len = k;
+ }
+ return s;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_pkcs1_sig_pad.c b/contrib/bearssl/src/rsa/rsa_pkcs1_sig_pad.c
new file mode 100644
index 000000000000..06c3bd706a4e
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_pkcs1_sig_pad.c
@@ -0,0 +1,100 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+uint32_t
+br_rsa_pkcs1_sig_pad(const unsigned char *hash_oid,
+ const unsigned char *hash, size_t hash_len,
+ uint32_t n_bitlen, unsigned char *x)
+{
+ size_t u, x3, xlen;
+
+ /*
+ * Padded hash value has format:
+ * 00 01 FF .. FF 00 30 x1 30 x2 06 x3 OID 05 00 04 x4 HASH
+ *
+ * with the following rules:
+ *
+ * -- Total length is equal to the modulus length (unsigned
+ * encoding).
+ *
+ * -- There must be at least eight bytes of value 0xFF.
+ *
+ * -- x4 is equal to the hash length (hash_len).
+ *
+ * -- x3 is equal to the encoded OID value length (hash_oid[0]).
+ *
+ * -- x2 = x3 + 4.
+ *
+ * -- x1 = x2 + x4 + 4 = x3 + x4 + 8.
+ *
+ * Note: the "05 00" is optional (signatures with and without
+ * that sequence exist in practice), but notes in PKCS#1 seem to
+ * indicate that the presence of that sequence (specifically,
+ * an ASN.1 NULL value for the hash parameters) may be slightly
+ * more "standard" than the opposite.
+ */
+ xlen = (n_bitlen + 7) >> 3;
+
+ if (hash_oid == NULL) {
+ if (xlen < hash_len + 11) {
+ return 0;
+ }
+ x[0] = 0x00;
+ x[1] = 0x01;
+ u = xlen - hash_len;
+ memset(x + 2, 0xFF, u - 3);
+ x[u - 1] = 0x00;
+ } else {
+ x3 = hash_oid[0];
+
+ /*
+ * Check that there is enough room for all the elements,
+ * including at least eight bytes of value 0xFF.
+ */
+ if (xlen < (x3 + hash_len + 21)) {
+ return 0;
+ }
+ x[0] = 0x00;
+ x[1] = 0x01;
+ u = xlen - x3 - hash_len - 11;
+ memset(x + 2, 0xFF, u - 2);
+ x[u] = 0x00;
+ x[u + 1] = 0x30;
+ x[u + 2] = x3 + hash_len + 8;
+ x[u + 3] = 0x30;
+ x[u + 4] = x3 + 4;
+ x[u + 5] = 0x06;
+ memcpy(x + u + 6, hash_oid, x3 + 1);
+ u += x3 + 7;
+ x[u ++] = 0x05;
+ x[u ++] = 0x00;
+ x[u ++] = 0x04;
+ x[u ++] = hash_len;
+ }
+ memcpy(x + u, hash, hash_len);
+ return 1;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_pkcs1_sig_unpad.c b/contrib/bearssl/src/rsa/rsa_pkcs1_sig_unpad.c
new file mode 100644
index 000000000000..c8ae08fa8e9f
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_pkcs1_sig_unpad.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_pkcs1_sig_unpad(const unsigned char *sig, size_t sig_len,
+ const unsigned char *hash_oid, size_t hash_len,
+ unsigned char *hash_out)
+{
+ static const unsigned char pad1[] = {
+ 0x00, 0x01, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF
+ };
+
+ unsigned char pad2[43];
+ size_t u, x2, x3, pad_len, zlen;
+
+ if (sig_len < 11) {
+ return 0;
+ }
+
+ /*
+ * Expected format:
+ * 00 01 FF ... FF 00 30 x1 30 x2 06 x3 OID [ 05 00 ] 04 x4 HASH
+ *
+ * with the following rules:
+ *
+ * -- Total length is that of the modulus and the signature
+ * (this was already verified by br_rsa_i31_public()).
+ *
+ * -- There are at least eight bytes of value 0xFF.
+ *
+ * -- x4 is equal to the hash length (hash_len).
+ *
+ * -- x3 is equal to the encoded OID value length (so x3 is the
+ * first byte of hash_oid[]).
+ *
+ * -- If the "05 00" is present, then x2 == x3 + 4; otherwise,
+ * x2 == x3 + 2.
+ *
+ * -- x1 == x2 + x4 + 4.
+ *
+ * So the total length after the last "FF" is either x3 + x4 + 11
+ * (with the "05 00") or x3 + x4 + 9 (without the "05 00").
+ */
+
+ /*
+ * Check the "00 01 FF .. FF 00" with at least eight 0xFF bytes.
+ * The comparison is valid because we made sure that the signature
+ * is at least 11 bytes long.
+ */
+ if (memcmp(sig, pad1, sizeof pad1) != 0) {
+ return 0;
+ }
+ for (u = sizeof pad1; u < sig_len; u ++) {
+ if (sig[u] != 0xFF) {
+ break;
+ }
+ }
+
+ /*
+ * Remaining length is sig_len - u bytes (including the 00 just
+ * after the last FF). This must be equal to one of the two
+ * possible values (depending on whether the "05 00" sequence is
+ * present or not).
+ */
+ if (hash_oid == NULL) {
+ if (sig_len - u != hash_len + 1 || sig[u] != 0x00) {
+ return 0;
+ }
+ } else {
+ x3 = hash_oid[0];
+ pad_len = x3 + 9;
+ memset(pad2, 0, pad_len);
+ zlen = sig_len - u - hash_len;
+ if (zlen == pad_len) {
+ x2 = x3 + 2;
+ } else if (zlen == pad_len + 2) {
+ x2 = x3 + 4;
+ pad_len = zlen;
+ pad2[pad_len - 4] = 0x05;
+ } else {
+ return 0;
+ }
+ pad2[1] = 0x30;
+ pad2[2] = x2 + hash_len + 4;
+ pad2[3] = 0x30;
+ pad2[4] = x2;
+ pad2[5] = 0x06;
+ memcpy(pad2 + 6, hash_oid, x3 + 1);
+ pad2[pad_len - 2] = 0x04;
+ pad2[pad_len - 1] = hash_len;
+ if (memcmp(pad2, sig + u, pad_len) != 0) {
+ return 0;
+ }
+ }
+ memcpy(hash_out, sig + sig_len - hash_len, hash_len);
+ return 1;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_pss_sig_pad.c b/contrib/bearssl/src/rsa/rsa_pss_sig_pad.c
new file mode 100644
index 000000000000..13e902745ec9
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_pss_sig_pad.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+uint32_t
+br_rsa_pss_sig_pad(const br_prng_class **rng,
+ const br_hash_class *hf_data, const br_hash_class *hf_mgf1,
+ const unsigned char *hash, size_t salt_len,
+ uint32_t n_bitlen, unsigned char *x)
+{
+ size_t xlen, hash_len;
+ br_hash_compat_context hc;
+ unsigned char *salt, *seed;
+
+ hash_len = br_digest_size(hf_data);
+
+ /*
+ * The padded string is one bit smaller than the modulus;
+ * notably, if the modulus length is equal to 1 modulo 8, then
+ * the padded string will be one _byte_ smaller, and the first
+ * byte will be set to 0. We apply these transformations here.
+ */
+ n_bitlen --;
+ if ((n_bitlen & 7) == 0) {
+ *x ++ = 0;
+ }
+ xlen = (n_bitlen + 7) >> 3;
+
+ /*
+ * Check that the modulus is large enough for the hash value
+ * length combined with the intended salt length.
+ */
+ if (hash_len > xlen || salt_len > xlen
+ || (hash_len + salt_len + 2) > xlen)
+ {
+ return 0;
+ }
+
+ /*
+ * Produce a random salt.
+ */
+ salt = x + xlen - hash_len - salt_len - 1;
+ if (salt_len != 0) {
+ (*rng)->generate(rng, salt, salt_len);
+ }
+
+ /*
+ * Compute the seed for MGF1.
+ */
+ seed = x + xlen - hash_len - 1;
+ hf_data->init(&hc.vtable);
+ memset(seed, 0, 8);
+ hf_data->update(&hc.vtable, seed, 8);
+ hf_data->update(&hc.vtable, hash, hash_len);
+ hf_data->update(&hc.vtable, salt, salt_len);
+ hf_data->out(&hc.vtable, seed);
+
+ /*
+ * Prepare string PS (padded salt). The salt is already at the
+ * right place.
+ */
+ memset(x, 0, xlen - salt_len - hash_len - 2);
+ x[xlen - salt_len - hash_len - 2] = 0x01;
+
+ /*
+ * Generate the mask and XOR it into PS.
+ */
+ br_mgf1_xor(x, xlen - hash_len - 1, hf_mgf1, seed, hash_len);
+
+ /*
+ * Clear the top bits to ensure the value is lower than the
+ * modulus.
+ */
+ x[0] &= 0xFF >> (((uint32_t)xlen << 3) - n_bitlen);
+
+ /*
+ * The seed (H) is already in the right place. We just set the
+ * last byte.
+ */
+ x[xlen - 1] = 0xBC;
+
+ return 1;
+}
diff --git a/contrib/bearssl/src/rsa/rsa_pss_sig_unpad.c b/contrib/bearssl/src/rsa/rsa_pss_sig_unpad.c
new file mode 100644
index 000000000000..a9f8ca3ac10f
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_pss_sig_unpad.c
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+uint32_t
+br_rsa_pss_sig_unpad(const br_hash_class *hf_data,
+ const br_hash_class *hf_mgf1,
+ const unsigned char *hash, size_t salt_len,
+ const br_rsa_public_key *pk, unsigned char *x)
+{
+ size_t u, xlen, hash_len;
+ br_hash_compat_context hc;
+ unsigned char *seed, *salt;
+ unsigned char tmp[64];
+ uint32_t r, n_bitlen;
+
+ hash_len = br_digest_size(hf_data);
+
+ /*
+ * Value r will be set to a non-zero value is any test fails.
+ */
+ r = 0;
+
+ /*
+ * The value bit length (as an integer) must be strictly less than
+ * that of the modulus.
+ */
+ for (u = 0; u < pk->nlen; u ++) {
+ if (pk->n[u] != 0) {
+ break;
+ }
+ }
+ if (u == pk->nlen) {
+ return 0;
+ }
+ n_bitlen = BIT_LENGTH(pk->n[u]) + ((uint32_t)(pk->nlen - u - 1) << 3);
+ n_bitlen --;
+ if ((n_bitlen & 7) == 0) {
+ r |= *x ++;
+ } else {
+ r |= x[0] & (0xFF << (n_bitlen & 7));
+ }
+ xlen = (n_bitlen + 7) >> 3;
+
+ /*
+ * Check that the modulus is large enough for the hash value
+ * length combined with the intended salt length.
+ */
+ if (hash_len > xlen || salt_len > xlen
+ || (hash_len + salt_len + 2) > xlen)
+ {
+ return 0;
+ }
+
+ /*
+ * Check value of rightmost byte.
+ */
+ r |= x[xlen - 1] ^ 0xBC;
+
+ /*
+ * Generate the mask and XOR it into the first bytes to reveal PS;
+ * we must also mask out the leading bits.
+ */
+ seed = x + xlen - hash_len - 1;
+ br_mgf1_xor(x, xlen - hash_len - 1, hf_mgf1, seed, hash_len);
+ if ((n_bitlen & 7) != 0) {
+ x[0] &= 0xFF >> (8 - (n_bitlen & 7));
+ }
+
+ /*
+ * Check that all padding bytes have the expected value.
+ */
+ for (u = 0; u < (xlen - hash_len - salt_len - 2); u ++) {
+ r |= x[u];
+ }
+ r |= x[xlen - hash_len - salt_len - 2] ^ 0x01;
+
+ /*
+ * Recompute H.
+ */
+ salt = x + xlen - hash_len - salt_len - 1;
+ hf_data->init(&hc.vtable);
+ memset(tmp, 0, 8);
+ hf_data->update(&hc.vtable, tmp, 8);
+ hf_data->update(&hc.vtable, hash, hash_len);
+ hf_data->update(&hc.vtable, salt, salt_len);
+ hf_data->out(&hc.vtable, tmp);
+
+ /*
+ * Check that the recomputed H value matches the one appearing
+ * in the string.
+ */
+ for (u = 0; u < hash_len; u ++) {
+ r |= tmp[u] ^ x[(xlen - salt_len - 1) + u];
+ }
+
+ return EQ0(r);
+}
diff --git a/contrib/bearssl/src/rsa/rsa_ssl_decrypt.c b/contrib/bearssl/src/rsa/rsa_ssl_decrypt.c
new file mode 100644
index 000000000000..047eb18c37ce
--- /dev/null
+++ b/contrib/bearssl/src/rsa/rsa_ssl_decrypt.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_rsa.h */
+uint32_t
+br_rsa_ssl_decrypt(br_rsa_private core, const br_rsa_private_key *sk,
+ unsigned char *data, size_t len)
+{
+ uint32_t x;
+ size_t u;
+
+ /*
+ * A first check on length. Since this test works only on the
+ * buffer length, it needs not (and cannot) be constant-time.
+ */
+ if (len < 59 || len != (sk->n_bitlen + 7) >> 3) {
+ return 0;
+ }
+ x = core(data, sk);
+
+ x &= EQ(data[0], 0x00);
+ x &= EQ(data[1], 0x02);
+ for (u = 2; u < (len - 49); u ++) {
+ x &= NEQ(data[u], 0);
+ }
+ x &= EQ(data[len - 49], 0x00);
+ memmove(data, data + len - 48, 48);
+ return x;
+}
diff --git a/contrib/bearssl/src/settings.c b/contrib/bearssl/src/settings.c
new file mode 100644
index 000000000000..309271cceba6
--- /dev/null
+++ b/contrib/bearssl/src/settings.c
@@ -0,0 +1,306 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 br_config_option config[] = {
+ { "BR_64",
+#if BR_64
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_AES_X86NI",
+#if BR_AES_X86NI
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_amd64",
+#if BR_amd64
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_ARMEL_CORTEXM_GCC",
+#if BR_ARMEL_CORTEXM_GCC
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_BE_UNALIGNED",
+#if BR_BE_UNALIGNED
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_CLANG",
+#if BR_CLANG
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_CLANG_3_7",
+#if BR_CLANG_3_7
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_CLANG_3_8",
+#if BR_CLANG_3_8
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_CT_MUL15",
+#if BR_CT_MUL15
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_CT_MUL31",
+#if BR_CT_MUL31
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_GCC",
+#if BR_GCC
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_GCC_4_4",
+#if BR_GCC_4_4
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_GCC_4_5",
+#if BR_GCC_4_5
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_GCC_4_6",
+#if BR_GCC_4_6
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_GCC_4_7",
+#if BR_GCC_4_7
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_GCC_4_8",
+#if BR_GCC_4_8
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_GCC_4_9",
+#if BR_GCC_4_9
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_GCC_5_0",
+#if BR_GCC_5_0
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_i386",
+#if BR_i386
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_INT128",
+#if BR_INT128
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_LE_UNALIGNED",
+#if BR_LE_UNALIGNED
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_LOMUL",
+#if BR_LOMUL
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_MAX_EC_SIZE", BR_MAX_EC_SIZE },
+ { "BR_MAX_RSA_SIZE", BR_MAX_RSA_SIZE },
+ { "BR_MAX_RSA_FACTOR", BR_MAX_RSA_FACTOR },
+ { "BR_MSC",
+#if BR_MSC
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_MSC_2005",
+#if BR_MSC_2005
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_MSC_2008",
+#if BR_MSC_2008
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_MSC_2010",
+#if BR_MSC_2010
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_MSC_2012",
+#if BR_MSC_2012
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_MSC_2013",
+#if BR_MSC_2013
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_MSC_2015",
+#if BR_MSC_2015
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_POWER8",
+#if BR_POWER8
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_RDRAND",
+#if BR_RDRAND
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_SLOW_MUL",
+#if BR_SLOW_MUL
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_SLOW_MUL15",
+#if BR_SLOW_MUL15
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_SSE2",
+#if BR_SSE2
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_UMUL128",
+#if BR_UMUL128
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_USE_UNIX_TIME",
+#if BR_USE_UNIX_TIME
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_USE_WIN32_RAND",
+#if BR_USE_WIN32_RAND
+ 1
+#else
+ 0
+#endif
+ },
+ { "BR_USE_WIN32_TIME",
+#if BR_USE_WIN32_TIME
+ 1
+#else
+ 0
+#endif
+ },
+
+ { NULL, 0 }
+};
+
+/* see bearssl.h */
+const br_config_option *
+br_get_config(void)
+{
+ return config;
+}
diff --git a/contrib/bearssl/src/ssl/prf.c b/contrib/bearssl/src/ssl/prf.c
new file mode 100644
index 000000000000..f04a5fb7c410
--- /dev/null
+++ b/contrib/bearssl/src/ssl/prf.c
@@ -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.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_tls_phash(void *dst, size_t len,
+ const br_hash_class *dig,
+ const void *secret, size_t secret_len, const char *label,
+ size_t seed_num, const br_tls_prf_seed_chunk *seed)
+{
+ unsigned char *buf;
+ unsigned char tmp[64], a[64];
+ br_hmac_key_context kc;
+ br_hmac_context hc;
+ size_t label_len, hlen, u;
+
+ if (len == 0) {
+ return;
+ }
+ buf = dst;
+ for (label_len = 0; label[label_len]; label_len ++);
+ hlen = br_digest_size(dig);
+ br_hmac_key_init(&kc, dig, secret, secret_len);
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, label, label_len);
+ for (u = 0; u < seed_num; u ++) {
+ br_hmac_update(&hc, seed[u].data, seed[u].len);
+ }
+ br_hmac_out(&hc, a);
+ for (;;) {
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, a, hlen);
+ br_hmac_update(&hc, label, label_len);
+ for (u = 0; u < seed_num; u ++) {
+ br_hmac_update(&hc, seed[u].data, seed[u].len);
+ }
+ br_hmac_out(&hc, tmp);
+ for (u = 0; u < hlen && u < len; u ++) {
+ buf[u] ^= tmp[u];
+ }
+ buf += u;
+ len -= u;
+ if (len == 0) {
+ return;
+ }
+ br_hmac_init(&hc, &kc, 0);
+ br_hmac_update(&hc, a, hlen);
+ br_hmac_out(&hc, a);
+ }
+}
diff --git a/contrib/bearssl/src/ssl/prf_md5sha1.c b/contrib/bearssl/src/ssl/prf_md5sha1.c
new file mode 100644
index 000000000000..3212833ab7bf
--- /dev/null
+++ b/contrib/bearssl/src/ssl/prf_md5sha1.c
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl.h */
+void
+br_tls10_prf(void *dst, size_t len,
+ const void *secret, size_t secret_len, const char *label,
+ size_t seed_num, const br_tls_prf_seed_chunk *seed)
+{
+ const unsigned char *s1;
+ size_t slen;
+
+ s1 = secret;
+ slen = (secret_len + 1) >> 1;
+ memset(dst, 0, len);
+ br_tls_phash(dst, len, &br_md5_vtable,
+ s1, slen, label, seed_num, seed);
+ br_tls_phash(dst, len, &br_sha1_vtable,
+ s1 + secret_len - slen, slen, label, seed_num, seed);
+}
diff --git a/contrib/bearssl/src/ssl/prf_sha256.c b/contrib/bearssl/src/ssl/prf_sha256.c
new file mode 100644
index 000000000000..76041de87277
--- /dev/null
+++ b/contrib/bearssl/src/ssl/prf_sha256.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl.h */
+void
+br_tls12_sha256_prf(void *dst, size_t len,
+ const void *secret, size_t secret_len, const char *label,
+ size_t seed_num, const br_tls_prf_seed_chunk *seed)
+{
+ memset(dst, 0, len);
+ br_tls_phash(dst, len, &br_sha256_vtable,
+ secret, secret_len, label, seed_num, seed);
+}
diff --git a/contrib/bearssl/src/ssl/prf_sha384.c b/contrib/bearssl/src/ssl/prf_sha384.c
new file mode 100644
index 000000000000..c20c4e65f824
--- /dev/null
+++ b/contrib/bearssl/src/ssl/prf_sha384.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl.h */
+void
+br_tls12_sha384_prf(void *dst, size_t len,
+ const void *secret, size_t secret_len, const char *label,
+ size_t seed_num, const br_tls_prf_seed_chunk *seed)
+{
+ memset(dst, 0, len);
+ br_tls_phash(dst, len, &br_sha384_vtable,
+ secret, secret_len, label, seed_num, seed);
+}
diff --git a/contrib/bearssl/src/ssl/ssl_ccert_single_ec.c b/contrib/bearssl/src/ssl/ssl_ccert_single_ec.c
new file mode 100644
index 000000000000..93ebcde6ed6b
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_ccert_single_ec.c
@@ -0,0 +1,156 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+static void
+cc_none0(const br_ssl_client_certificate_class **pctx)
+{
+ (void)pctx;
+}
+
+static void
+cc_none1(const br_ssl_client_certificate_class **pctx, size_t len)
+{
+ (void)pctx;
+ (void)len;
+}
+
+static void
+cc_none2(const br_ssl_client_certificate_class **pctx,
+ const unsigned char *data, size_t len)
+{
+ (void)pctx;
+ (void)data;
+ (void)len;
+}
+
+static void
+cc_choose(const br_ssl_client_certificate_class **pctx,
+ const br_ssl_client_context *cc, uint32_t auth_types,
+ br_ssl_client_certificate *choices)
+{
+ br_ssl_client_certificate_ec_context *zc;
+ int x;
+ int scurve;
+
+ zc = (br_ssl_client_certificate_ec_context *)pctx;
+ scurve = br_ssl_client_get_server_curve(cc);
+
+ if ((zc->allowed_usages & BR_KEYTYPE_KEYX) != 0
+ && scurve == zc->sk->curve)
+ {
+ int x;
+
+ x = (zc->issuer_key_type == BR_KEYTYPE_RSA) ? 16 : 17;
+ if (((auth_types >> x) & 1) != 0) {
+ choices->auth_type = BR_AUTH_ECDH;
+ choices->hash_id = -1;
+ choices->chain = zc->chain;
+ choices->chain_len = zc->chain_len;
+ }
+ }
+
+ /*
+ * For ECDSA authentication, we must choose an appropriate
+ * hash function.
+ */
+ x = br_ssl_choose_hash((unsigned)(auth_types >> 8));
+ if (x == 0 || (zc->allowed_usages & BR_KEYTYPE_SIGN) == 0) {
+ memset(choices, 0, sizeof *choices);
+ return;
+ }
+ choices->auth_type = BR_AUTH_ECDSA;
+ choices->hash_id = x;
+ choices->chain = zc->chain;
+ choices->chain_len = zc->chain_len;
+}
+
+static uint32_t
+cc_do_keyx(const br_ssl_client_certificate_class **pctx,
+ unsigned char *data, size_t *len)
+{
+ br_ssl_client_certificate_ec_context *zc;
+ uint32_t r;
+ size_t xoff, xlen;
+
+ zc = (br_ssl_client_certificate_ec_context *)pctx;
+ r = zc->iec->mul(data, *len, zc->sk->x, zc->sk->xlen, zc->sk->curve);
+ xoff = zc->iec->xoff(zc->sk->curve, &xlen);
+ memmove(data, data + xoff, xlen);
+ *len = xlen;
+ return r;
+}
+
+static size_t
+cc_do_sign(const br_ssl_client_certificate_class **pctx,
+ int hash_id, size_t hv_len, unsigned char *data, size_t len)
+{
+ br_ssl_client_certificate_ec_context *zc;
+ unsigned char hv[64];
+ const br_hash_class *hc;
+
+ zc = (br_ssl_client_certificate_ec_context *)pctx;
+ memcpy(hv, data, hv_len);
+ hc = br_multihash_getimpl(zc->mhash, hash_id);
+ if (hc == NULL) {
+ return 0;
+ }
+ if (len < 139) {
+ return 0;
+ }
+ return zc->iecdsa(zc->iec, hc, hv, zc->sk, data);
+}
+
+static const br_ssl_client_certificate_class ccert_vtable = {
+ sizeof(br_ssl_client_certificate_ec_context),
+ cc_none0, /* start_name_list */
+ cc_none1, /* start_name */
+ cc_none2, /* append_name */
+ cc_none0, /* end_name */
+ cc_none0, /* end_name_list */
+ cc_choose,
+ cc_do_keyx,
+ cc_do_sign
+};
+
+/* see bearssl_ssl.h */
+void
+br_ssl_client_set_single_ec(br_ssl_client_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk, unsigned allowed_usages,
+ unsigned cert_issuer_key_type,
+ const br_ec_impl *iec, br_ecdsa_sign iecdsa)
+{
+ cc->client_auth.single_ec.vtable = &ccert_vtable;
+ cc->client_auth.single_ec.chain = chain;
+ cc->client_auth.single_ec.chain_len = chain_len;
+ cc->client_auth.single_ec.sk = sk;
+ cc->client_auth.single_ec.allowed_usages = allowed_usages;
+ cc->client_auth.single_ec.issuer_key_type = cert_issuer_key_type;
+ cc->client_auth.single_ec.mhash = &cc->eng.mhash;
+ cc->client_auth.single_ec.iec = iec;
+ cc->client_auth.single_ec.iecdsa = iecdsa;
+ cc->client_auth_vtable = &cc->client_auth.single_ec.vtable;
+}
diff --git a/contrib/bearssl/src/ssl/ssl_ccert_single_rsa.c b/contrib/bearssl/src/ssl/ssl_ccert_single_rsa.c
new file mode 100644
index 000000000000..690df20fa8f8
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_ccert_single_rsa.c
@@ -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.
+ */
+
+#include "inner.h"
+
+static void
+cc_none0(const br_ssl_client_certificate_class **pctx)
+{
+ (void)pctx;
+}
+
+static void
+cc_none1(const br_ssl_client_certificate_class **pctx, size_t len)
+{
+ (void)pctx;
+ (void)len;
+}
+
+static void
+cc_none2(const br_ssl_client_certificate_class **pctx,
+ const unsigned char *data, size_t len)
+{
+ (void)pctx;
+ (void)data;
+ (void)len;
+}
+
+static void
+cc_choose(const br_ssl_client_certificate_class **pctx,
+ const br_ssl_client_context *cc, uint32_t auth_types,
+ br_ssl_client_certificate *choices)
+{
+ br_ssl_client_certificate_rsa_context *zc;
+ int x;
+
+ (void)cc;
+ zc = (br_ssl_client_certificate_rsa_context *)pctx;
+ x = br_ssl_choose_hash((unsigned)auth_types);
+ if (x == 0 && (auth_types & 1) == 0) {
+ memset(choices, 0, sizeof *choices);
+ }
+ choices->auth_type = BR_AUTH_RSA;
+ choices->hash_id = x;
+ choices->chain = zc->chain;
+ choices->chain_len = zc->chain_len;
+}
+
+/*
+ * OID for hash functions in RSA signatures.
+ */
+static const unsigned char HASH_OID_SHA1[] = {
+ 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
+};
+
+static const unsigned char HASH_OID_SHA224[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
+};
+
+static const unsigned char HASH_OID_SHA256[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
+};
+
+static const unsigned char HASH_OID_SHA384[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
+};
+
+static const unsigned char HASH_OID_SHA512[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
+};
+
+static const unsigned char *HASH_OID[] = {
+ HASH_OID_SHA1,
+ HASH_OID_SHA224,
+ HASH_OID_SHA256,
+ HASH_OID_SHA384,
+ HASH_OID_SHA512
+};
+
+static size_t
+cc_do_sign(const br_ssl_client_certificate_class **pctx,
+ int hash_id, size_t hv_len, unsigned char *data, size_t len)
+{
+ br_ssl_client_certificate_rsa_context *zc;
+ unsigned char hv[64];
+ const unsigned char *hash_oid;
+ size_t sig_len;
+
+ zc = (br_ssl_client_certificate_rsa_context *)pctx;
+ memcpy(hv, data, hv_len);
+ if (hash_id == 0) {
+ hash_oid = NULL;
+ } else if (hash_id >= 2 && hash_id <= 6) {
+ hash_oid = HASH_OID[hash_id - 2];
+ } else {
+ return 0;
+ }
+ sig_len = (zc->sk->n_bitlen + 7) >> 3;
+ if (len < sig_len) {
+ return 0;
+ }
+ return zc->irsasign(hash_oid, hv, hv_len, zc->sk, data) ? sig_len : 0;
+}
+
+static const br_ssl_client_certificate_class ccert_vtable = {
+ sizeof(br_ssl_client_certificate_rsa_context),
+ cc_none0, /* start_name_list */
+ cc_none1, /* start_name */
+ cc_none2, /* append_name */
+ cc_none0, /* end_name */
+ cc_none0, /* end_name_list */
+ cc_choose,
+ 0,
+ cc_do_sign
+};
+
+/* see bearssl_ssl.h */
+void
+br_ssl_client_set_single_rsa(br_ssl_client_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk, br_rsa_pkcs1_sign irsasign)
+{
+ cc->client_auth.single_rsa.vtable = &ccert_vtable;
+ cc->client_auth.single_rsa.chain = chain;
+ cc->client_auth.single_rsa.chain_len = chain_len;
+ cc->client_auth.single_rsa.sk = sk;
+ cc->client_auth.single_rsa.irsasign = irsasign;
+ cc->client_auth_vtable = &cc->client_auth.single_rsa.vtable;
+}
diff --git a/contrib/bearssl/src/ssl/ssl_client.c b/contrib/bearssl/src/ssl/ssl_client.c
new file mode 100644
index 000000000000..28c404b83a72
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_client.c
@@ -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.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_client_zero(br_ssl_client_context *cc)
+{
+ /*
+ * For really standard C, we should explicitly set to NULL all
+ * pointers, and 0 all other fields. However, on all our target
+ * architectures, a direct memset() will work, be faster, and
+ * use a lot less code.
+ */
+ memset(cc, 0, sizeof *cc);
+}
+
+/* see bearssl_ssl.h */
+int
+br_ssl_client_reset(br_ssl_client_context *cc,
+ const char *server_name, int resume_session)
+{
+ size_t n;
+
+ br_ssl_engine_set_buffer(&cc->eng, NULL, 0, 0);
+ cc->eng.version_out = cc->eng.version_min;
+ if (!resume_session) {
+ br_ssl_client_forget_session(cc);
+ }
+ if (!br_ssl_engine_init_rand(&cc->eng)) {
+ return 0;
+ }
+
+ /*
+ * We always set back the "reneg" flag to 0 because we use it
+ * to distinguish between first handshake and renegotiation.
+ * Note that "renegotiation" and "session resumption" are two
+ * different things.
+ */
+ cc->eng.reneg = 0;
+
+ if (server_name == NULL) {
+ cc->eng.server_name[0] = 0;
+ } else {
+ n = strlen(server_name) + 1;
+ if (n > sizeof cc->eng.server_name) {
+ br_ssl_engine_fail(&cc->eng, BR_ERR_BAD_PARAM);
+ return 0;
+ }
+ memcpy(cc->eng.server_name, server_name, n);
+ }
+
+ br_ssl_engine_hs_reset(&cc->eng,
+ br_ssl_hs_client_init_main, br_ssl_hs_client_run);
+ return br_ssl_engine_last_error(&cc->eng) == BR_ERR_OK;
+}
diff --git a/contrib/bearssl/src/ssl/ssl_client_default_rsapub.c b/contrib/bearssl/src/ssl/ssl_client_default_rsapub.c
new file mode 100644
index 000000000000..2cdaab89e4a9
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_client_default_rsapub.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_client_set_default_rsapub(br_ssl_client_context *cc)
+{
+ br_ssl_client_set_rsapub(cc, br_rsa_public_get_default());
+}
diff --git a/contrib/bearssl/src/ssl/ssl_client_full.c b/contrib/bearssl/src/ssl/ssl_client_full.c
new file mode 100644
index 000000000000..981434990b29
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_client_full.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_client_init_full(br_ssl_client_context *cc,
+ br_x509_minimal_context *xc,
+ const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num)
+{
+ /*
+ * The "full" profile supports all implemented cipher suites.
+ *
+ * Rationale for suite order, from most important to least
+ * important rule:
+ *
+ * -- Don't use 3DES if AES or ChaCha20 is available.
+ * -- Try to have Forward Secrecy (ECDHE suite) if possible.
+ * -- When not using Forward Secrecy, ECDH key exchange is
+ * better than RSA key exchange (slightly more expensive on the
+ * client, but much cheaper on the server, and it implies smaller
+ * messages).
+ * -- ChaCha20+Poly1305 is better than AES/GCM (faster, smaller code).
+ * -- GCM is better than CCM and CBC. CCM is better than CBC.
+ * -- CCM is preferable over CCM_8 (with CCM_8, forgeries may succeed
+ * with probability 2^(-64)).
+ * -- AES-128 is preferred over AES-256 (AES-128 is already
+ * strong enough, and AES-256 is 40% more expensive).
+ */
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+ BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ 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_CCM,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8,
+ 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_CCM,
+ BR_TLS_RSA_WITH_AES_256_CCM,
+ BR_TLS_RSA_WITH_AES_128_CCM_8,
+ BR_TLS_RSA_WITH_AES_256_CCM_8,
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ };
+
+ /*
+ * All hash functions are activated.
+ * Note: the X.509 validation engine will nonetheless refuse to
+ * validate signatures that use MD5 as hash function.
+ */
+ static const br_hash_class *hashes[] = {
+ &br_md5_vtable,
+ &br_sha1_vtable,
+ &br_sha224_vtable,
+ &br_sha256_vtable,
+ &br_sha384_vtable,
+ &br_sha512_vtable
+ };
+
+ int id;
+
+ /*
+ * Reset client context and set supported versions from TLS-1.0
+ * to TLS-1.2 (inclusive).
+ */
+ br_ssl_client_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
+
+ /*
+ * X.509 engine uses SHA-256 to hash certificate DN (for
+ * comparisons).
+ */
+ br_x509_minimal_init(xc, &br_sha256_vtable,
+ trust_anchors, trust_anchors_num);
+
+ /*
+ * Set suites and asymmetric crypto implementations. We use the
+ * "i31" code for RSA (it is somewhat faster than the "i32"
+ * implementation).
+ * TODO: change that when better implementations are made available.
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_client_set_default_rsapub(cc);
+ br_ssl_engine_set_default_rsavrfy(&cc->eng);
+ br_ssl_engine_set_default_ecdsa(&cc->eng);
+ br_x509_minimal_set_rsa(xc, br_ssl_engine_get_rsavrfy(&cc->eng));
+ br_x509_minimal_set_ecdsa(xc,
+ br_ssl_engine_get_ec(&cc->eng),
+ br_ssl_engine_get_ecdsa(&cc->eng));
+
+ /*
+ * Set supported hash functions, for the SSL engine and for the
+ * X.509 engine.
+ */
+ for (id = br_md5_ID; id <= br_sha512_ID; id ++) {
+ const br_hash_class *hc;
+
+ hc = hashes[id - 1];
+ br_ssl_engine_set_hash(&cc->eng, id, hc);
+ br_x509_minimal_set_hash(xc, id, hc);
+ }
+
+ /*
+ * Link the X.509 engine in the SSL engine.
+ */
+ br_ssl_engine_set_x509(&cc->eng, &xc->vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf);
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+ br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf);
+
+ /*
+ * Symmetric encryption. We use the "default" implementations
+ * (fastest among constant-time implementations).
+ */
+ br_ssl_engine_set_default_aes_cbc(&cc->eng);
+ br_ssl_engine_set_default_aes_ccm(&cc->eng);
+ br_ssl_engine_set_default_aes_gcm(&cc->eng);
+ br_ssl_engine_set_default_des_cbc(&cc->eng);
+ br_ssl_engine_set_default_chapol(&cc->eng);
+}
diff --git a/contrib/bearssl/src/ssl/ssl_engine.c b/contrib/bearssl/src/ssl/ssl_engine.c
new file mode 100644
index 000000000000..f4ffe1854724
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_engine.c
@@ -0,0 +1,1569 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#if 0
+/* obsolete */
+
+/*
+ * If BR_USE_URANDOM is not defined, then try to autodetect its presence
+ * through compiler macros.
+ */
+#ifndef BR_USE_URANDOM
+
+/*
+ * Macro values documented on:
+ * https://sourceforge.net/p/predef/wiki/OperatingSystems/
+ *
+ * Only the most common systems have been included here for now. This
+ * should be enriched later on.
+ */
+#if defined _AIX \
+ || defined __ANDROID__ \
+ || defined __FreeBSD__ \
+ || defined __NetBSD__ \
+ || defined __OpenBSD__ \
+ || defined __DragonFly__ \
+ || defined __linux__ \
+ || (defined __sun && (defined __SVR4 || defined __svr4__)) \
+ || (defined __APPLE__ && defined __MACH__)
+#define BR_USE_URANDOM 1
+#endif
+
+#endif
+
+/*
+ * If BR_USE_WIN32_RAND is not defined, perform autodetection here.
+ */
+#ifndef BR_USE_WIN32_RAND
+
+#if defined _WIN32 || defined _WIN64
+#define BR_USE_WIN32_RAND 1
+#endif
+
+#endif
+
+#if BR_USE_URANDOM
+#include <sys/types.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <errno.h>
+#endif
+
+#if BR_USE_WIN32_RAND
+#include <windows.h>
+#include <wincrypt.h>
+#pragma comment(lib, "advapi32")
+#endif
+
+#endif
+
+/* ==================================================================== */
+/*
+ * This part of the file does the low-level record management.
+ */
+
+/*
+ * IMPLEMENTATION NOTES
+ * ====================
+ *
+ * In this file, we designate by "input" (and the "i" letter) the "recv"
+ * operations: incoming records from the peer, from which payload data
+ * is obtained, and must be extracted by the application (or the SSL
+ * handshake engine). Similarly, "output" (and the "o" letter) is for
+ * "send": payload data injected by the application (and SSL handshake
+ * engine), to be wrapped into records, that are then conveyed to the
+ * peer over the transport medium.
+ *
+ * The input and output buffers may be distinct or shared. When
+ * shared, input and output cannot occur concurrently; the caller
+ * must make sure that it never needs to output data while input
+ * data has been received. In practice, a shared buffer prevents
+ * pipelining of HTTP requests, or similar protocols; however, a
+ * shared buffer saves RAM.
+ *
+ * The input buffer is pointed to by 'ibuf' and has size 'ibuf_len';
+ * the output buffer is pointed to by 'obuf' and has size 'obuf_len'.
+ * From the size of these buffers is derived the maximum fragment
+ * length, which will be honoured upon sending records; regardless of
+ * that length, incoming records will be processed as long as they
+ * fit in the input buffer, and their length still complies with the
+ * protocol specification (maximum plaintext payload length is 16384
+ * bytes).
+ *
+ * Three registers are used to manage buffering in ibuf, called ixa,
+ * ixb and ixc. Similarly, three registers are used to manage buffering
+ * in obuf, called oxa, oxb and oxc.
+ *
+ *
+ * At any time, the engine is in one of the following modes:
+ * -- Failed mode: an error occurs, no I/O can happen.
+ * -- Input mode: the engine can either receive record bytes from the
+ * transport layer, or it has some buffered payload bytes to yield.
+ * -- Output mode: the engine can either receive payload bytes, or it
+ * has some record bytes to send to the transport layer.
+ * -- Input/Output mode: both input and output modes are active. When
+ * the buffer is shared, this can happen only when the buffer is empty
+ * (no buffered payload bytes or record bytes in either direction).
+ *
+ *
+ * Failed mode:
+ * ------------
+ *
+ * I/O failed for some reason (invalid received data, not enough room
+ * for the next record...). No I/O may ever occur again for this context,
+ * until an explicit reset is performed. This mode, and the error code,
+ * are also used for protocol errors, especially handshake errors.
+ *
+ *
+ * Input mode:
+ * -----------
+ *
+ * ixa index within ibuf[] for the currently read data
+ * ixb maximum index within ibuf[] for the currently read data
+ * ixc number of bytes not yet received for the current record
+ *
+ * -- When ixa == ixb, there is no available data for readers. When
+ * ixa != ixb, there is available data and it starts at offset ixa.
+ *
+ * -- When waiting for the next record header, ixa and ixb are equal
+ * and contain a value ranging from 0 to 4; ixc is equal to 5-ixa.
+ *
+ * -- When the header has been received, record data is obtained. The
+ * ixc field records how many bytes are still needed to reach the
+ * end of the current record.
+ *
+ * ** If encryption is active, then ixa and ixb are kept equal, and
+ * point to the end of the currently received record bytes. When
+ * ixc reaches 0, decryption/MAC is applied, and ixa and ixb are
+ * adjusted.
+ *
+ * ** If encryption is not active, then ixa and ixb are distinct
+ * and data can be read right away. Additional record data is
+ * obtained only when ixa == ixb.
+ *
+ * Note: in input mode and no encryption, records larger than the buffer
+ * size are allowed. When encryption is active, the complete record must
+ * fit within the buffer, since it cannot be decrypted/MACed until it
+ * has been completely received.
+ *
+ * -- When receiving the next record header, 'version_in' contains the
+ * expected input version (0 if not expecting a specific version); on
+ * mismatch, the mode switches to 'failed'.
+ *
+ * -- When the header has been received, 'version_in' contains the received
+ * version. It is up to the caller to check and adjust the 'version_in' field
+ * to implement the required semantics.
+ *
+ * -- The 'record_type_in' field is updated with the incoming record type
+ * when the next record header has been received.
+ *
+ *
+ * Output mode:
+ * ------------
+ *
+ * oxa index within obuf[] for the currently accumulated data
+ * oxb maximum index within obuf[] for record data
+ * oxc pointer for start of record data, and for record sending
+ *
+ * -- When oxa != oxb, more data can be accumulated into the current
+ * record; when oxa == oxb, a closed record is being sent.
+ *
+ * -- When accumulating data, oxc points to the start of the data.
+ *
+ * -- During record sending, oxa (and oxb) point to the next record byte
+ * to send, and oxc indicates the end of the current record.
+ *
+ * Note: sent records must fit within the buffer, since the header is
+ * adjusted only when the complete record has been assembled.
+ *
+ * -- The 'version_out' and 'record_type_out' fields are used to build the
+ * record header when the mode is switched to 'sending'.
+ *
+ *
+ * Modes:
+ * ------
+ *
+ * The state register iomode contains one of the following values:
+ *
+ * BR_IO_FAILED I/O failed
+ * BR_IO_IN input mode
+ * BR_IO_OUT output mode
+ * BR_IO_INOUT input/output mode
+ *
+ * Whether encryption is active on incoming records is indicated by the
+ * incrypt flag. For outgoing records, there is no such flag; "encryption"
+ * is always considered active, but initially uses functions that do not
+ * encrypt anything. The 'incrypt' flag is needed because when there is
+ * no active encryption, records larger than the I/O buffer are accepted.
+ *
+ * Note: we do not support no-encryption modes (MAC only).
+ *
+ * TODO: implement GCM support
+ *
+ *
+ * Misc:
+ * -----
+ *
+ * 'max_frag_len' is the maximum plaintext size for an outgoing record.
+ * By default, it is set to the maximum value that fits in the provided
+ * buffers, in the following list: 512, 1024, 2048, 4096, 16384. The
+ * caller may change it if needed, but the new value MUST still fit in
+ * the buffers, and it MUST be one of the list above for compatibility
+ * with the Maximum Fragment Length extension.
+ *
+ * For incoming records, only the total buffer length and current
+ * encryption mode impact the maximum length for incoming records. The
+ * 'max_frag_len' value is still adjusted so that records up to that
+ * length can be both received and sent.
+ *
+ *
+ * Offsets and lengths:
+ * --------------------
+ *
+ * When sending fragments with TLS-1.1+, the maximum overhead is:
+ * 5 bytes for the record header
+ * 16 bytes for the explicit IV
+ * 48 bytes for the MAC (HMAC/SHA-384)
+ * 16 bytes for the padding (AES)
+ * so a total of 85 extra bytes. Note that we support block cipher sizes
+ * up to 16 bytes (AES) and HMAC output sizes up to 48 bytes (SHA-384).
+ *
+ * With TLS-1.0 and CBC mode, we apply a 1/n-1 split, for a maximum
+ * overhead of:
+ * 5 bytes for the first record header
+ * 32 bytes for the first record payload (AES-CBC + HMAC/SHA-1)
+ * 5 bytes for the second record header
+ * 20 bytes for the MAC (HMAC/SHA-1)
+ * 16 bytes for the padding (AES)
+ * -1 byte to account for the payload byte in the first record
+ * so a total of 77 extra bytes at most, less than the 85 bytes above.
+ * Note that with TLS-1.0, the MAC is HMAC with either MD5 or SHA-1, but
+ * no other hash function.
+ *
+ * The implementation does not try to send larger records when the current
+ * encryption mode has less overhead.
+ *
+ * Maximum input record overhead is:
+ * 5 bytes for the record header
+ * 16 bytes for the explicit IV (TLS-1.1+)
+ * 48 bytes for the MAC (HMAC/SHA-384)
+ * 256 bytes for the padding
+ * so a total of 325 extra bytes.
+ *
+ * When receiving the next record header, it is written into the buffer
+ * bytes 0 to 4 (inclusive). Record data is always written into buf[]
+ * starting at offset 5. When encryption is active, the plaintext data
+ * may start at a larger offset (e.g. because of an explicit IV).
+ */
+
+#define MAX_OUT_OVERHEAD 85
+#define MAX_IN_OVERHEAD 325
+
+/* see inner.h */
+void
+br_ssl_engine_fail(br_ssl_engine_context *rc, int err)
+{
+ if (rc->iomode != BR_IO_FAILED) {
+ rc->iomode = BR_IO_FAILED;
+ rc->err = err;
+ }
+}
+
+/*
+ * Adjust registers for a new incoming record.
+ */
+static void
+make_ready_in(br_ssl_engine_context *rc)
+{
+ rc->ixa = rc->ixb = 0;
+ rc->ixc = 5;
+ if (rc->iomode == BR_IO_IN) {
+ rc->iomode = BR_IO_INOUT;
+ }
+}
+
+/*
+ * Adjust registers for a new outgoing record.
+ */
+static void
+make_ready_out(br_ssl_engine_context *rc)
+{
+ size_t a, b;
+
+ a = 5;
+ b = rc->obuf_len - a;
+ rc->out.vtable->max_plaintext(&rc->out.vtable, &a, &b);
+ if ((b - a) > rc->max_frag_len) {
+ b = a + rc->max_frag_len;
+ }
+ rc->oxa = a;
+ rc->oxb = b;
+ rc->oxc = a;
+ if (rc->iomode == BR_IO_OUT) {
+ rc->iomode = BR_IO_INOUT;
+ }
+}
+
+/* see inner.h */
+void
+br_ssl_engine_new_max_frag_len(br_ssl_engine_context *rc, unsigned max_frag_len)
+{
+ size_t nxb;
+
+ rc->max_frag_len = max_frag_len;
+ nxb = rc->oxc + max_frag_len;
+ if (rc->oxa < rc->oxb && rc->oxb > nxb && rc->oxa < nxb) {
+ rc->oxb = nxb;
+ }
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_buffer(br_ssl_engine_context *rc,
+ void *buf, size_t buf_len, int bidi)
+{
+ if (buf == NULL) {
+ br_ssl_engine_set_buffers_bidi(rc, NULL, 0, NULL, 0);
+ } else {
+ /*
+ * In bidirectional mode, we want to maximise input
+ * buffer size, since we support arbitrary fragmentation
+ * when sending, but the peer will not necessarily
+ * comply to any low fragment length (in particular if
+ * we are the server, because the maximum fragment
+ * length extension is under client control).
+ *
+ * We keep a minimum size of 512 bytes for the plaintext
+ * of our outgoing records.
+ *
+ * br_ssl_engine_set_buffers_bidi() will compute the maximum
+ * fragment length for outgoing records by using the minimum
+ * of allocated spaces for both input and output records,
+ * rounded down to a standard length.
+ */
+ if (bidi) {
+ size_t w;
+
+ if (buf_len < (512 + MAX_IN_OVERHEAD
+ + 512 + MAX_OUT_OVERHEAD))
+ {
+ rc->iomode = BR_IO_FAILED;
+ rc->err = BR_ERR_BAD_PARAM;
+ return;
+ } else if (buf_len < (16384 + MAX_IN_OVERHEAD
+ + 512 + MAX_OUT_OVERHEAD))
+ {
+ w = 512 + MAX_OUT_OVERHEAD;
+ } else {
+ w = buf_len - (16384 + MAX_IN_OVERHEAD);
+ }
+ br_ssl_engine_set_buffers_bidi(rc,
+ buf, buf_len - w,
+ (unsigned char *)buf + w, w);
+ } else {
+ br_ssl_engine_set_buffers_bidi(rc,
+ buf, buf_len, NULL, 0);
+ }
+ }
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_buffers_bidi(br_ssl_engine_context *rc,
+ void *ibuf, size_t ibuf_len, void *obuf, size_t obuf_len)
+{
+ rc->iomode = BR_IO_INOUT;
+ rc->incrypt = 0;
+ rc->err = BR_ERR_OK;
+ rc->version_in = 0;
+ rc->record_type_in = 0;
+ rc->version_out = 0;
+ rc->record_type_out = 0;
+ if (ibuf == NULL) {
+ if (rc->ibuf == NULL) {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_PARAM);
+ }
+ } else {
+ unsigned u;
+
+ rc->ibuf = ibuf;
+ rc->ibuf_len = ibuf_len;
+ if (obuf == NULL) {
+ obuf = ibuf;
+ obuf_len = ibuf_len;
+ }
+ rc->obuf = obuf;
+ rc->obuf_len = obuf_len;
+
+ /*
+ * Compute the maximum fragment length, that fits for
+ * both incoming and outgoing records. This length will
+ * be used in fragment length negotiation, so we must
+ * honour it both ways. Regardless, larger incoming
+ * records will be accepted, as long as they fit in the
+ * actual buffer size.
+ */
+ for (u = 14; u >= 9; u --) {
+ size_t flen;
+
+ flen = (size_t)1 << u;
+ if (obuf_len >= flen + MAX_OUT_OVERHEAD
+ && ibuf_len >= flen + MAX_IN_OVERHEAD)
+ {
+ break;
+ }
+ }
+ if (u == 8) {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_PARAM);
+ return;
+ } else if (u == 13) {
+ u = 12;
+ }
+ rc->max_frag_len = (size_t)1 << u;
+ rc->log_max_frag_len = u;
+ rc->peer_log_max_frag_len = 0;
+ }
+ rc->out.vtable = &br_sslrec_out_clear_vtable;
+ make_ready_in(rc);
+ make_ready_out(rc);
+}
+
+/*
+ * Clear buffers in both directions.
+ */
+static void
+engine_clearbuf(br_ssl_engine_context *rc)
+{
+ make_ready_in(rc);
+ make_ready_out(rc);
+}
+
+/*
+ * Make sure the internal PRNG is initialised (but not necessarily
+ * seeded properly yet).
+ */
+static int
+rng_init(br_ssl_engine_context *cc)
+{
+ const br_hash_class *h;
+
+ if (cc->rng_init_done != 0) {
+ return 1;
+ }
+
+ /*
+ * If using TLS-1.2, then SHA-256 or SHA-384 must be present (or
+ * both); we prefer SHA-256 which is faster for 32-bit systems.
+ *
+ * If using TLS-1.0 or 1.1 then SHA-1 must be present.
+ *
+ * Though HMAC_DRBG/SHA-1 is, as far as we know, as safe as
+ * these things can be, we still prefer the SHA-2 functions over
+ * SHA-1, if only for public relations (known theoretical
+ * weaknesses of SHA-1 with regards to collisions are mostly
+ * irrelevant here, but they still make people nervous).
+ */
+ h = br_multihash_getimpl(&cc->mhash, br_sha256_ID);
+ if (!h) {
+ h = br_multihash_getimpl(&cc->mhash, br_sha384_ID);
+ if (!h) {
+ h = br_multihash_getimpl(&cc->mhash,
+ br_sha1_ID);
+ if (!h) {
+ br_ssl_engine_fail(cc, BR_ERR_BAD_STATE);
+ return 0;
+ }
+ }
+ }
+ br_hmac_drbg_init(&cc->rng, h, NULL, 0);
+ cc->rng_init_done = 1;
+ return 1;
+}
+
+/* see inner.h */
+int
+br_ssl_engine_init_rand(br_ssl_engine_context *cc)
+{
+ if (!rng_init(cc)) {
+ return 0;
+ }
+
+ /*
+ * We always try OS/hardware seeding once. If it works, then
+ * we assume proper seeding. If not, then external entropy must
+ * have been injected; otherwise, we report an error.
+ */
+ if (!cc->rng_os_rand_done) {
+ br_prng_seeder sd;
+
+ sd = br_prng_seeder_system(NULL);
+ if (sd != 0 && sd(&cc->rng.vtable)) {
+ cc->rng_init_done = 2;
+ }
+ cc->rng_os_rand_done = 1;
+ }
+ if (cc->rng_init_done < 2) {
+ br_ssl_engine_fail(cc, BR_ERR_NO_RANDOM);
+ return 0;
+ }
+ return 1;
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_inject_entropy(br_ssl_engine_context *cc,
+ const void *data, size_t len)
+{
+ /*
+ * Externally provided entropy is assumed to be "good enough"
+ * (we cannot really test its quality) so if the RNG structure
+ * could be initialised at all, then we marked the RNG as
+ * "properly seeded".
+ */
+ if (!rng_init(cc)) {
+ return;
+ }
+ br_hmac_drbg_update(&cc->rng, data, len);
+ cc->rng_init_done = 2;
+}
+
+/*
+ * We define a few internal functions that implement the low-level engine
+ * API for I/O; the external API (br_ssl_engine_sendapp_buf() and similar
+ * functions) is built upon these function, with special processing for
+ * records which are not of type "application data".
+ *
+ * recvrec_buf, recvrec_ack receives bytes from transport medium
+ * sendrec_buf, sendrec_ack send bytes to transport medium
+ * recvpld_buf, recvpld_ack receives payload data from engine
+ * sendpld_buf, sendpld_ack send payload data to engine
+ */
+
+static unsigned char *
+recvrec_buf(const br_ssl_engine_context *rc, size_t *len)
+{
+ if (rc->shutdown_recv) {
+ *len = 0;
+ return NULL;
+ }
+
+ /*
+ * Bytes from the transport can be injected only if the mode is
+ * compatible (in or in/out), and ixa == ixb; ixc then contains
+ * the number of bytes that are still expected (but it may
+ * exceed our buffer size).
+ *
+ * We cannot get "stuck" here (buffer is full, but still more
+ * data is expected) because oversized records are detected when
+ * their header is processed.
+ */
+ switch (rc->iomode) {
+ case BR_IO_IN:
+ case BR_IO_INOUT:
+ if (rc->ixa == rc->ixb) {
+ size_t z;
+
+ z = rc->ixc;
+ if (z > rc->ibuf_len - rc->ixa) {
+ z = rc->ibuf_len - rc->ixa;
+ }
+ *len = z;
+ return rc->ibuf + rc->ixa;
+ }
+ break;
+ }
+ *len = 0;
+ return NULL;
+}
+
+static void
+recvrec_ack(br_ssl_engine_context *rc, size_t len)
+{
+ unsigned char *pbuf;
+ size_t pbuf_len;
+
+ /*
+ * Adjust state if necessary (for a shared input/output buffer):
+ * we got some incoming bytes, so we cannot (temporarily) handle
+ * outgoing data.
+ */
+ if (rc->iomode == BR_IO_INOUT && rc->ibuf == rc->obuf) {
+ rc->iomode = BR_IO_IN;
+ }
+
+ /*
+ * Adjust data pointers.
+ */
+ rc->ixb = (rc->ixa += len);
+ rc->ixc -= len;
+
+ /*
+ * If we are receiving a header and did not fully obtained it
+ * yet, then just wait for the next bytes.
+ */
+ if (rc->ixa < 5) {
+ return;
+ }
+
+ /*
+ * If we just obtained a full header, process it.
+ */
+ if (rc->ixa == 5) {
+ unsigned version;
+ unsigned rlen;
+
+ /*
+ * Get record type and version. We support only versions
+ * 3.x (if the version major number does not match, then
+ * we suppose that the record format is too alien for us
+ * to process it).
+ *
+ * Note: right now, we reject clients that try to send
+ * a ClientHello in a format compatible with SSL-2.0. It
+ * is unclear whether this will ever be supported; and
+ * if we want to support it, then this might be done in
+ * in the server-specific code, not here.
+ */
+ rc->record_type_in = rc->ibuf[0];
+ version = br_dec16be(rc->ibuf + 1);
+ if ((version >> 8) != 3) {
+ br_ssl_engine_fail(rc, BR_ERR_UNSUPPORTED_VERSION);
+ return;
+ }
+
+ /*
+ * We ensure that successive records have the same
+ * version. The handshake code must check and adjust the
+ * variables when necessary to accommodate the protocol
+ * negotiation details.
+ */
+ if (rc->version_in != 0 && rc->version_in != version) {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_VERSION);
+ return;
+ }
+ rc->version_in = version;
+
+ /*
+ * Decode record length. We must check that the length
+ * is valid (relatively to the current encryption mode)
+ * and also (if encryption is active) that the record
+ * will fit in our buffer.
+ *
+ * When no encryption is active, we can process records
+ * by chunks, and thus accept any record up to the
+ * maximum allowed plaintext length (16384 bytes).
+ */
+ rlen = br_dec16be(rc->ibuf + 3);
+ if (rc->incrypt) {
+ if (!rc->in.vtable->check_length(
+ &rc->in.vtable, rlen))
+ {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_LENGTH);
+ return;
+ }
+ if (rlen > (rc->ibuf_len - 5)) {
+ br_ssl_engine_fail(rc, BR_ERR_TOO_LARGE);
+ return;
+ }
+ } else {
+ if (rlen > 16384) {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_LENGTH);
+ return;
+ }
+ }
+
+ /*
+ * If the record is completely empty then we must switch
+ * to a new record. Note that, in that case, we
+ * completely ignore the record type, which is fitting
+ * since we received no actual data of that type.
+ *
+ * A completely empty record is technically allowed as
+ * long as encryption/MAC is not active, i.e. before
+ * completion of the first handshake. It it still weird;
+ * it might conceptually be useful as a heartbeat or
+ * keep-alive mechanism while some lengthy operation is
+ * going on, e.g. interaction with a human user.
+ */
+ if (rlen == 0) {
+ make_ready_in(rc);
+ } else {
+ rc->ixa = rc->ixb = 5;
+ rc->ixc = rlen;
+ }
+ return;
+ }
+
+ /*
+ * If there is no active encryption, then the data can be read
+ * right away. Note that we do not receive bytes from the
+ * transport medium when we still have payload bytes to be
+ * acknowledged.
+ */
+ if (!rc->incrypt) {
+ rc->ixa = 5;
+ return;
+ }
+
+ /*
+ * Since encryption is active, we must wait for a full record
+ * before processing it.
+ */
+ if (rc->ixc != 0) {
+ return;
+ }
+
+ /*
+ * We got the full record. Decrypt it.
+ */
+ pbuf_len = rc->ixa - 5;
+ pbuf = rc->in.vtable->decrypt(&rc->in.vtable,
+ rc->record_type_in, rc->version_in, rc->ibuf + 5, &pbuf_len);
+ if (pbuf == 0) {
+ br_ssl_engine_fail(rc, BR_ERR_BAD_MAC);
+ return;
+ }
+ rc->ixa = (size_t)(pbuf - rc->ibuf);
+ rc->ixb = rc->ixa + pbuf_len;
+
+ /*
+ * Decryption may have yielded an empty record, in which case
+ * we get back to "ready" state immediately.
+ */
+ if (rc->ixa == rc->ixb) {
+ make_ready_in(rc);
+ }
+}
+
+/* see inner.h */
+int
+br_ssl_engine_recvrec_finished(const br_ssl_engine_context *rc)
+{
+ switch (rc->iomode) {
+ case BR_IO_IN:
+ case BR_IO_INOUT:
+ return rc->ixc == 0 || rc->ixa < 5;
+ default:
+ return 1;
+ }
+}
+
+static unsigned char *
+recvpld_buf(const br_ssl_engine_context *rc, size_t *len)
+{
+ /*
+ * There is payload data to be read only if the mode is
+ * compatible, and ixa != ixb.
+ */
+ switch (rc->iomode) {
+ case BR_IO_IN:
+ case BR_IO_INOUT:
+ *len = rc->ixb - rc->ixa;
+ return (*len == 0) ? NULL : (rc->ibuf + rc->ixa);
+ default:
+ *len = 0;
+ return NULL;
+ }
+}
+
+static void
+recvpld_ack(br_ssl_engine_context *rc, size_t len)
+{
+ rc->ixa += len;
+
+ /*
+ * If we read all the available data, then we either expect
+ * the remainder of the current record (if the current record
+ * was not finished; this may happen when encryption is not
+ * active), or go to "ready" state.
+ */
+ if (rc->ixa == rc->ixb) {
+ if (rc->ixc == 0) {
+ make_ready_in(rc);
+ } else {
+ rc->ixa = rc->ixb = 5;
+ }
+ }
+}
+
+static unsigned char *
+sendpld_buf(const br_ssl_engine_context *rc, size_t *len)
+{
+ /*
+ * Payload data can be injected only if the current mode is
+ * compatible, and oxa != oxb.
+ */
+ switch (rc->iomode) {
+ case BR_IO_OUT:
+ case BR_IO_INOUT:
+ *len = rc->oxb - rc->oxa;
+ return (*len == 0) ? NULL : (rc->obuf + rc->oxa);
+ default:
+ *len = 0;
+ return NULL;
+ }
+}
+
+/*
+ * If some payload bytes have been accumulated, then wrap them into
+ * an outgoing record. Otherwise, this function does nothing, unless
+ * 'force' is non-zero, in which case an empty record is assembled.
+ *
+ * The caller must take care not to invoke this function if the engine
+ * is not currently ready to receive payload bytes to send.
+ */
+static void
+sendpld_flush(br_ssl_engine_context *rc, int force)
+{
+ size_t xlen;
+ unsigned char *buf;
+
+ if (rc->oxa == rc->oxb) {
+ return;
+ }
+ xlen = rc->oxa - rc->oxc;
+ if (xlen == 0 && !force) {
+ return;
+ }
+ buf = rc->out.vtable->encrypt(&rc->out.vtable,
+ rc->record_type_out, rc->version_out,
+ rc->obuf + rc->oxc, &xlen);
+ rc->oxb = rc->oxa = (size_t)(buf - rc->obuf);
+ rc->oxc = rc->oxa + xlen;
+}
+
+static void
+sendpld_ack(br_ssl_engine_context *rc, size_t len)
+{
+ /*
+ * If using a shared buffer, then we may have to modify the
+ * current mode.
+ */
+ if (rc->iomode == BR_IO_INOUT && rc->ibuf == rc->obuf) {
+ rc->iomode = BR_IO_OUT;
+ }
+ rc->oxa += len;
+ if (rc->oxa >= rc->oxb) {
+ /*
+ * Set oxb to one more than oxa so that sendpld_flush()
+ * does not mistakingly believe that a record is
+ * already prepared and being sent.
+ */
+ rc->oxb = rc->oxa + 1;
+ sendpld_flush(rc, 0);
+ }
+}
+
+static unsigned char *
+sendrec_buf(const br_ssl_engine_context *rc, size_t *len)
+{
+ /*
+ * When still gathering payload bytes, oxc points to the start
+ * of the record data, so oxc <= oxa. However, when a full
+ * record has been completed, oxc points to the end of the record,
+ * so oxc > oxa.
+ */
+ switch (rc->iomode) {
+ case BR_IO_OUT:
+ case BR_IO_INOUT:
+ if (rc->oxc > rc->oxa) {
+ *len = rc->oxc - rc->oxa;
+ return rc->obuf + rc->oxa;
+ }
+ break;
+ }
+ *len = 0;
+ return NULL;
+}
+
+static void
+sendrec_ack(br_ssl_engine_context *rc, size_t len)
+{
+ rc->oxb = (rc->oxa += len);
+ if (rc->oxa == rc->oxc) {
+ make_ready_out(rc);
+ }
+}
+
+/*
+ * Test whether there is some buffered outgoing record that still must
+ * sent.
+ */
+static inline int
+has_rec_tosend(const br_ssl_engine_context *rc)
+{
+ return rc->oxa == rc->oxb && rc->oxa != rc->oxc;
+}
+
+/*
+ * The "no encryption" mode has no overhead. It limits the payload size
+ * to the maximum size allowed by the standard (16384 bytes); the caller
+ * is responsible for possibly enforcing a smaller fragment length.
+ */
+static void
+clear_max_plaintext(const br_sslrec_out_clear_context *cc,
+ size_t *start, size_t *end)
+{
+ size_t len;
+
+ (void)cc;
+ len = *end - *start;
+ if (len > 16384) {
+ *end = *start + 16384;
+ }
+}
+
+/*
+ * In "no encryption" mode, encryption is trivial (a no-operation) so
+ * we just have to encode the header.
+ */
+static unsigned char *
+clear_encrypt(br_sslrec_out_clear_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ unsigned char *buf;
+
+ (void)cc;
+ buf = (unsigned char *)data - 5;
+ buf[0] = record_type;
+ br_enc16be(buf + 1, version);
+ br_enc16be(buf + 3, *data_len);
+ *data_len += 5;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_out_class br_sslrec_out_clear_vtable = {
+ sizeof(br_sslrec_out_clear_context),
+ (void (*)(const br_sslrec_out_class *const *, size_t *, size_t *))
+ &clear_max_plaintext,
+ (unsigned char *(*)(const br_sslrec_out_class **,
+ int, unsigned, void *, size_t *))
+ &clear_encrypt
+};
+
+/* ==================================================================== */
+/*
+ * In this part of the file, we handle the various record types, and
+ * communications with the handshake processor.
+ */
+
+/*
+ * IMPLEMENTATION NOTES
+ * ====================
+ *
+ * The handshake processor is written in T0 and runs as a coroutine.
+ * It receives the contents of all records except application data, and
+ * is responsible for producing the contents of all records except
+ * application data.
+ *
+ * A state flag is maintained, which specifies whether application data
+ * is acceptable or not. When it is set:
+ *
+ * -- Application data can be injected as payload data (provided that
+ * the output buffer is ready for that).
+ *
+ * -- Incoming application data records are accepted, and yield data
+ * that the caller may retrieve.
+ *
+ * When the flag is cleared, application data is not accepted from the
+ * application, and incoming application data records trigger an error.
+ *
+ *
+ * Records of type handshake, alert or change-cipher-spec are handled
+ * by the handshake processor. The handshake processor is written in T0
+ * and runs as a coroutine; it gets invoked whenever one of the following
+ * situations is reached:
+ *
+ * -- An incoming record has type handshake, alert or change-cipher-spec,
+ * and yields data that can be read (zero-length records are thus
+ * ignored).
+ *
+ * -- An outgoing record has just finished being sent, and the "application
+ * data" flag is cleared.
+ *
+ * -- The caller wishes to perform a close (call to br_ssl_engine_close()).
+ *
+ * -- The caller wishes to perform a renegotiation (call to
+ * br_ssl_engine_renegotiate()).
+ *
+ * Whenever the handshake processor is entered, access to the payload
+ * buffers is provided, along with some information about explicit
+ * closures or renegotiations.
+ */
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_suites(br_ssl_engine_context *cc,
+ const uint16_t *suites, size_t suites_num)
+{
+ if ((suites_num * sizeof *suites) > sizeof cc->suites_buf) {
+ br_ssl_engine_fail(cc, BR_ERR_BAD_PARAM);
+ return;
+ }
+ memcpy(cc->suites_buf, suites, suites_num * sizeof *suites);
+ cc->suites_num = suites_num;
+}
+
+/*
+ * Give control to handshake processor. 'action' is 1 for a close,
+ * 2 for a renegotiation, or 0 for a jump due to I/O completion.
+ */
+static void
+jump_handshake(br_ssl_engine_context *cc, int action)
+{
+ /*
+ * We use a loop because the handshake processor actions may
+ * allow for more actions; namely, if the processor reads all
+ * input data, then it may allow for output data to be produced,
+ * in case of a shared in/out buffer.
+ */
+ for (;;) {
+ size_t hlen_in, hlen_out;
+
+ /*
+ * Get input buffer. We do not want to provide
+ * application data to the handshake processor (we could
+ * get called with an explicit close or renegotiation
+ * while there is application data ready to be read).
+ */
+ cc->hbuf_in = recvpld_buf(cc, &hlen_in);
+ if (cc->hbuf_in != NULL
+ && cc->record_type_in == BR_SSL_APPLICATION_DATA)
+ {
+ hlen_in = 0;
+ }
+
+ /*
+ * Get output buffer. The handshake processor never
+ * leaves an unfinished outgoing record, so if there is
+ * buffered output, then it MUST be some application
+ * data, so the processor cannot write to it.
+ */
+ cc->saved_hbuf_out = cc->hbuf_out = sendpld_buf(cc, &hlen_out);
+ if (cc->hbuf_out != NULL && br_ssl_engine_has_pld_to_send(cc)) {
+ hlen_out = 0;
+ }
+
+ /*
+ * Note: hlen_in and hlen_out can be both non-zero only if
+ * the input and output buffers are disjoint. Thus, we can
+ * offer both buffers to the handshake code.
+ */
+
+ cc->hlen_in = hlen_in;
+ cc->hlen_out = hlen_out;
+ cc->action = action;
+ cc->hsrun(&cc->cpu);
+ if (br_ssl_engine_closed(cc)) {
+ return;
+ }
+ if (cc->hbuf_out != cc->saved_hbuf_out) {
+ sendpld_ack(cc, cc->hbuf_out - cc->saved_hbuf_out);
+ }
+ if (hlen_in != cc->hlen_in) {
+ recvpld_ack(cc, hlen_in - cc->hlen_in);
+ if (cc->hlen_in == 0) {
+ /*
+ * We read all data bytes, which may have
+ * released the output buffer in case it
+ * is shared with the input buffer, and
+ * the handshake code might be waiting for
+ * that.
+ */
+ action = 0;
+ continue;
+ }
+ }
+ break;
+ }
+}
+
+/* see inner.h */
+void
+br_ssl_engine_flush_record(br_ssl_engine_context *cc)
+{
+ if (cc->hbuf_out != cc->saved_hbuf_out) {
+ sendpld_ack(cc, cc->hbuf_out - cc->saved_hbuf_out);
+ }
+ if (br_ssl_engine_has_pld_to_send(cc)) {
+ sendpld_flush(cc, 0);
+ }
+ cc->saved_hbuf_out = cc->hbuf_out = sendpld_buf(cc, &cc->hlen_out);
+}
+
+/* see bearssl_ssl.h */
+unsigned char *
+br_ssl_engine_sendapp_buf(const br_ssl_engine_context *cc, size_t *len)
+{
+ if (!(cc->application_data & 1)) {
+ *len = 0;
+ return NULL;
+ }
+ return sendpld_buf(cc, len);
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_sendapp_ack(br_ssl_engine_context *cc, size_t len)
+{
+ sendpld_ack(cc, len);
+}
+
+/* see bearssl_ssl.h */
+unsigned char *
+br_ssl_engine_recvapp_buf(const br_ssl_engine_context *cc, size_t *len)
+{
+ if (!(cc->application_data & 1)
+ || cc->record_type_in != BR_SSL_APPLICATION_DATA)
+ {
+ *len = 0;
+ return NULL;
+ }
+ return recvpld_buf(cc, len);
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_recvapp_ack(br_ssl_engine_context *cc, size_t len)
+{
+ recvpld_ack(cc, len);
+}
+
+/* see bearssl_ssl.h */
+unsigned char *
+br_ssl_engine_sendrec_buf(const br_ssl_engine_context *cc, size_t *len)
+{
+ return sendrec_buf(cc, len);
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_sendrec_ack(br_ssl_engine_context *cc, size_t len)
+{
+ sendrec_ack(cc, len);
+ if (len != 0 && !has_rec_tosend(cc)
+ && (cc->record_type_out != BR_SSL_APPLICATION_DATA
+ || (cc->application_data & 1) == 0))
+ {
+ jump_handshake(cc, 0);
+ }
+}
+
+/* see bearssl_ssl.h */
+unsigned char *
+br_ssl_engine_recvrec_buf(const br_ssl_engine_context *cc, size_t *len)
+{
+ return recvrec_buf(cc, len);
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_recvrec_ack(br_ssl_engine_context *cc, size_t len)
+{
+ unsigned char *buf;
+
+ recvrec_ack(cc, len);
+ if (br_ssl_engine_closed(cc)) {
+ return;
+ }
+
+ /*
+ * We just received some bytes from the peer. This may have
+ * yielded some payload bytes, in which case we must process
+ * them according to the record type.
+ */
+ buf = recvpld_buf(cc, &len);
+ if (buf != NULL) {
+ switch (cc->record_type_in) {
+ case BR_SSL_CHANGE_CIPHER_SPEC:
+ case BR_SSL_ALERT:
+ case BR_SSL_HANDSHAKE:
+ jump_handshake(cc, 0);
+ break;
+ case BR_SSL_APPLICATION_DATA:
+ if (cc->application_data == 1) {
+ break;
+ }
+
+ /*
+ * If we are currently closing, and waiting for
+ * a close_notify from the peer, then incoming
+ * application data should be discarded.
+ */
+ if (cc->application_data == 2) {
+ recvpld_ack(cc, len);
+ break;
+ }
+
+ /* Fall through */
+ default:
+ br_ssl_engine_fail(cc, BR_ERR_UNEXPECTED);
+ break;
+ }
+ }
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_close(br_ssl_engine_context *cc)
+{
+ if (!br_ssl_engine_closed(cc)) {
+ jump_handshake(cc, 1);
+ }
+}
+
+/* see bearssl_ssl.h */
+int
+br_ssl_engine_renegotiate(br_ssl_engine_context *cc)
+{
+ size_t len;
+
+ if (br_ssl_engine_closed(cc) || cc->reneg == 1
+ || (cc->flags & BR_OPT_NO_RENEGOTIATION) != 0
+ || br_ssl_engine_recvapp_buf(cc, &len) != NULL)
+ {
+ return 0;
+ }
+ jump_handshake(cc, 2);
+ return 1;
+}
+
+/* see bearssl.h */
+unsigned
+br_ssl_engine_current_state(const br_ssl_engine_context *cc)
+{
+ unsigned s;
+ size_t len;
+
+ if (br_ssl_engine_closed(cc)) {
+ return BR_SSL_CLOSED;
+ }
+
+ s = 0;
+ if (br_ssl_engine_sendrec_buf(cc, &len) != NULL) {
+ s |= BR_SSL_SENDREC;
+ }
+ if (br_ssl_engine_recvrec_buf(cc, &len) != NULL) {
+ s |= BR_SSL_RECVREC;
+ }
+ if (br_ssl_engine_sendapp_buf(cc, &len) != NULL) {
+ s |= BR_SSL_SENDAPP;
+ }
+ if (br_ssl_engine_recvapp_buf(cc, &len) != NULL) {
+ s |= BR_SSL_RECVAPP;
+ }
+ return s;
+}
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_flush(br_ssl_engine_context *cc, int force)
+{
+ if (!br_ssl_engine_closed(cc) && (cc->application_data & 1) != 0) {
+ sendpld_flush(cc, force);
+ }
+}
+
+/* see inner.h */
+void
+br_ssl_engine_hs_reset(br_ssl_engine_context *cc,
+ void (*hsinit)(void *), void (*hsrun)(void *))
+{
+ engine_clearbuf(cc);
+ cc->cpu.dp = cc->dp_stack;
+ cc->cpu.rp = cc->rp_stack;
+ hsinit(&cc->cpu);
+ cc->hsrun = hsrun;
+ cc->shutdown_recv = 0;
+ cc->application_data = 0;
+ cc->alert = 0;
+ jump_handshake(cc, 0);
+}
+
+/* see inner.h */
+br_tls_prf_impl
+br_ssl_engine_get_PRF(br_ssl_engine_context *cc, int prf_id)
+{
+ if (cc->session.version >= BR_TLS12) {
+ if (prf_id == br_sha384_ID) {
+ return cc->prf_sha384;
+ } else {
+ return cc->prf_sha256;
+ }
+ } else {
+ return cc->prf10;
+ }
+}
+
+/* see inner.h */
+void
+br_ssl_engine_compute_master(br_ssl_engine_context *cc,
+ int prf_id, const void *pms, size_t pms_len)
+{
+ br_tls_prf_impl iprf;
+ br_tls_prf_seed_chunk seed[2] = {
+ { cc->client_random, sizeof cc->client_random },
+ { cc->server_random, sizeof cc->server_random }
+ };
+
+ iprf = br_ssl_engine_get_PRF(cc, prf_id);
+ iprf(cc->session.master_secret, sizeof cc->session.master_secret,
+ pms, pms_len, "master secret", 2, seed);
+}
+
+/*
+ * Compute key block.
+ */
+static void
+compute_key_block(br_ssl_engine_context *cc, int prf_id,
+ size_t half_len, unsigned char *kb)
+{
+ br_tls_prf_impl iprf;
+ br_tls_prf_seed_chunk seed[2] = {
+ { cc->server_random, sizeof cc->server_random },
+ { cc->client_random, sizeof cc->client_random }
+ };
+
+ iprf = br_ssl_engine_get_PRF(cc, prf_id);
+ iprf(kb, half_len << 1,
+ cc->session.master_secret, sizeof cc->session.master_secret,
+ "key expansion", 2, seed);
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_cbc_in(br_ssl_engine_context *cc,
+ int is_client, int prf_id, int mac_id,
+ const br_block_cbcdec_class *bc_impl, size_t cipher_key_len)
+{
+ unsigned char kb[192];
+ unsigned char *cipher_key, *mac_key, *iv;
+ const br_hash_class *imh;
+ size_t mac_key_len, mac_out_len, iv_len;
+
+ imh = br_ssl_engine_get_hash(cc, mac_id);
+ mac_out_len = (imh->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
+ mac_key_len = mac_out_len;
+
+ /*
+ * TLS 1.1+ uses per-record explicit IV, so no IV to generate here.
+ */
+ if (cc->session.version >= BR_TLS11) {
+ iv_len = 0;
+ } else {
+ iv_len = bc_impl->block_size;
+ }
+ compute_key_block(cc, prf_id,
+ mac_key_len + cipher_key_len + iv_len, kb);
+ if (is_client) {
+ mac_key = &kb[mac_key_len];
+ cipher_key = &kb[(mac_key_len << 1) + cipher_key_len];
+ iv = &kb[((mac_key_len + cipher_key_len) << 1) + iv_len];
+ } else {
+ mac_key = &kb[0];
+ cipher_key = &kb[mac_key_len << 1];
+ iv = &kb[(mac_key_len + cipher_key_len) << 1];
+ }
+ if (iv_len == 0) {
+ iv = NULL;
+ }
+ cc->icbc_in->init(&cc->in.cbc.vtable,
+ bc_impl, cipher_key, cipher_key_len,
+ imh, mac_key, mac_key_len, mac_out_len, iv);
+ cc->incrypt = 1;
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_cbc_out(br_ssl_engine_context *cc,
+ int is_client, int prf_id, int mac_id,
+ const br_block_cbcenc_class *bc_impl, size_t cipher_key_len)
+{
+ unsigned char kb[192];
+ unsigned char *cipher_key, *mac_key, *iv;
+ const br_hash_class *imh;
+ size_t mac_key_len, mac_out_len, iv_len;
+
+ imh = br_ssl_engine_get_hash(cc, mac_id);
+ mac_out_len = (imh->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
+ mac_key_len = mac_out_len;
+
+ /*
+ * TLS 1.1+ uses per-record explicit IV, so no IV to generate here.
+ */
+ if (cc->session.version >= BR_TLS11) {
+ iv_len = 0;
+ } else {
+ iv_len = bc_impl->block_size;
+ }
+ compute_key_block(cc, prf_id,
+ mac_key_len + cipher_key_len + iv_len, kb);
+ if (is_client) {
+ mac_key = &kb[0];
+ cipher_key = &kb[mac_key_len << 1];
+ iv = &kb[(mac_key_len + cipher_key_len) << 1];
+ } else {
+ mac_key = &kb[mac_key_len];
+ cipher_key = &kb[(mac_key_len << 1) + cipher_key_len];
+ iv = &kb[((mac_key_len + cipher_key_len) << 1) + iv_len];
+ }
+ if (iv_len == 0) {
+ iv = NULL;
+ }
+ cc->icbc_out->init(&cc->out.cbc.vtable,
+ bc_impl, cipher_key, cipher_key_len,
+ imh, mac_key, mac_key_len, mac_out_len, iv);
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_gcm_in(br_ssl_engine_context *cc,
+ int is_client, int prf_id,
+ const br_block_ctr_class *bc_impl, size_t cipher_key_len)
+{
+ unsigned char kb[72];
+ unsigned char *cipher_key, *iv;
+
+ compute_key_block(cc, prf_id, cipher_key_len + 4, kb);
+ if (is_client) {
+ cipher_key = &kb[cipher_key_len];
+ iv = &kb[(cipher_key_len << 1) + 4];
+ } else {
+ cipher_key = &kb[0];
+ iv = &kb[cipher_key_len << 1];
+ }
+ cc->igcm_in->init(&cc->in.gcm.vtable.in,
+ bc_impl, cipher_key, cipher_key_len, cc->ighash, iv);
+ cc->incrypt = 1;
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_gcm_out(br_ssl_engine_context *cc,
+ int is_client, int prf_id,
+ const br_block_ctr_class *bc_impl, size_t cipher_key_len)
+{
+ unsigned char kb[72];
+ unsigned char *cipher_key, *iv;
+
+ compute_key_block(cc, prf_id, cipher_key_len + 4, kb);
+ if (is_client) {
+ cipher_key = &kb[0];
+ iv = &kb[cipher_key_len << 1];
+ } else {
+ cipher_key = &kb[cipher_key_len];
+ iv = &kb[(cipher_key_len << 1) + 4];
+ }
+ cc->igcm_out->init(&cc->out.gcm.vtable.out,
+ bc_impl, cipher_key, cipher_key_len, cc->ighash, iv);
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_chapol_in(br_ssl_engine_context *cc,
+ int is_client, int prf_id)
+{
+ unsigned char kb[88];
+ unsigned char *cipher_key, *iv;
+
+ compute_key_block(cc, prf_id, 44, kb);
+ if (is_client) {
+ cipher_key = &kb[32];
+ iv = &kb[76];
+ } else {
+ cipher_key = &kb[0];
+ iv = &kb[64];
+ }
+ cc->ichapol_in->init(&cc->in.chapol.vtable.in,
+ cc->ichacha, cc->ipoly, cipher_key, iv);
+ cc->incrypt = 1;
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_chapol_out(br_ssl_engine_context *cc,
+ int is_client, int prf_id)
+{
+ unsigned char kb[88];
+ unsigned char *cipher_key, *iv;
+
+ compute_key_block(cc, prf_id, 44, kb);
+ if (is_client) {
+ cipher_key = &kb[0];
+ iv = &kb[64];
+ } else {
+ cipher_key = &kb[32];
+ iv = &kb[76];
+ }
+ cc->ichapol_out->init(&cc->out.chapol.vtable.out,
+ cc->ichacha, cc->ipoly, cipher_key, iv);
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_ccm_in(br_ssl_engine_context *cc,
+ int is_client, int prf_id,
+ const br_block_ctrcbc_class *bc_impl,
+ size_t cipher_key_len, size_t tag_len)
+{
+ unsigned char kb[72];
+ unsigned char *cipher_key, *iv;
+
+ compute_key_block(cc, prf_id, cipher_key_len + 4, kb);
+ if (is_client) {
+ cipher_key = &kb[cipher_key_len];
+ iv = &kb[(cipher_key_len << 1) + 4];
+ } else {
+ cipher_key = &kb[0];
+ iv = &kb[cipher_key_len << 1];
+ }
+ cc->iccm_in->init(&cc->in.ccm.vtable.in,
+ bc_impl, cipher_key, cipher_key_len, iv, tag_len);
+ cc->incrypt = 1;
+}
+
+/* see inner.h */
+void
+br_ssl_engine_switch_ccm_out(br_ssl_engine_context *cc,
+ int is_client, int prf_id,
+ const br_block_ctrcbc_class *bc_impl,
+ size_t cipher_key_len, size_t tag_len)
+{
+ unsigned char kb[72];
+ unsigned char *cipher_key, *iv;
+
+ compute_key_block(cc, prf_id, cipher_key_len + 4, kb);
+ if (is_client) {
+ cipher_key = &kb[0];
+ iv = &kb[cipher_key_len << 1];
+ } else {
+ cipher_key = &kb[cipher_key_len];
+ iv = &kb[(cipher_key_len << 1) + 4];
+ }
+ cc->iccm_out->init(&cc->out.ccm.vtable.out,
+ bc_impl, cipher_key, cipher_key_len, iv, tag_len);
+}
diff --git a/contrib/bearssl/src/ssl/ssl_engine_default_aescbc.c b/contrib/bearssl/src/ssl/ssl_engine_default_aescbc.c
new file mode 100644
index 000000000000..8c5cdb570497
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_engine_default_aescbc.c
@@ -0,0 +1,64 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_default_aes_cbc(br_ssl_engine_context *cc)
+{
+#if BR_AES_X86NI || BR_POWER8
+ const br_block_cbcenc_class *ienc;
+ const br_block_cbcdec_class *idec;
+#endif
+
+ br_ssl_engine_set_cbc(cc,
+ &br_sslrec_in_cbc_vtable,
+ &br_sslrec_out_cbc_vtable);
+#if BR_AES_X86NI
+ ienc = br_aes_x86ni_cbcenc_get_vtable();
+ idec = br_aes_x86ni_cbcdec_get_vtable();
+ if (ienc != NULL && idec != NULL) {
+ br_ssl_engine_set_aes_cbc(cc, ienc, idec);
+ return;
+ }
+#endif
+#if BR_POWER8
+ ienc = br_aes_pwr8_cbcenc_get_vtable();
+ idec = br_aes_pwr8_cbcdec_get_vtable();
+ if (ienc != NULL && idec != NULL) {
+ br_ssl_engine_set_aes_cbc(cc, ienc, idec);
+ return;
+ }
+#endif
+#if BR_64
+ br_ssl_engine_set_aes_cbc(cc,
+ &br_aes_ct64_cbcenc_vtable,
+ &br_aes_ct64_cbcdec_vtable);
+#else
+ br_ssl_engine_set_aes_cbc(cc,
+ &br_aes_ct_cbcenc_vtable,
+ &br_aes_ct_cbcdec_vtable);
+#endif
+}
diff --git a/contrib/bearssl/src/ssl/ssl_engine_default_aesccm.c b/contrib/bearssl/src/ssl/ssl_engine_default_aesccm.c
new file mode 100644
index 000000000000..15c0a78f0f44
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_engine_default_aesccm.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_default_aes_ccm(br_ssl_engine_context *cc)
+{
+#if BR_AES_X86NI || BR_POWER8
+ const br_block_ctrcbc_class *ictrcbc;
+#endif
+
+ br_ssl_engine_set_ccm(cc,
+ &br_sslrec_in_ccm_vtable,
+ &br_sslrec_out_ccm_vtable);
+#if BR_AES_X86NI
+ ictrcbc = br_aes_x86ni_ctrcbc_get_vtable();
+ if (ictrcbc != NULL) {
+ br_ssl_engine_set_aes_ctrcbc(cc, ictrcbc);
+ } else {
+#if BR_64
+ br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct64_ctrcbc_vtable);
+#else
+ br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct_ctrcbc_vtable);
+#endif
+ }
+#elif BR_POWER8
+ ictrcbc = br_aes_pwr8_ctrcbc_get_vtable();
+ if (ictrcbc != NULL) {
+ br_ssl_engine_set_aes_ctrcbc(cc, ictrcbc);
+ } else {
+#if BR_64
+ br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct64_ctrcbc_vtable);
+#else
+ br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct_ctrcbc_vtable);
+#endif
+ }
+#else
+#if BR_64
+ br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct64_ctrcbc_vtable);
+#else
+ br_ssl_engine_set_aes_ctrcbc(cc, &br_aes_ct_ctrcbc_vtable);
+#endif
+#endif
+}
diff --git a/contrib/bearssl/src/ssl/ssl_engine_default_aesgcm.c b/contrib/bearssl/src/ssl/ssl_engine_default_aesgcm.c
new file mode 100644
index 000000000000..c44a7074bba5
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_engine_default_aesgcm.c
@@ -0,0 +1,89 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_default_aes_gcm(br_ssl_engine_context *cc)
+{
+#if BR_AES_X86NI || BR_POWER8
+ const br_block_ctr_class *ictr;
+ br_ghash ighash;
+#endif
+
+ br_ssl_engine_set_gcm(cc,
+ &br_sslrec_in_gcm_vtable,
+ &br_sslrec_out_gcm_vtable);
+#if BR_AES_X86NI
+ ictr = br_aes_x86ni_ctr_get_vtable();
+ if (ictr != NULL) {
+ br_ssl_engine_set_aes_ctr(cc, ictr);
+ } else {
+#if BR_64
+ br_ssl_engine_set_aes_ctr(cc, &br_aes_ct64_ctr_vtable);
+#else
+ br_ssl_engine_set_aes_ctr(cc, &br_aes_ct_ctr_vtable);
+#endif
+ }
+#elif BR_POWER8
+ ictr = br_aes_pwr8_ctr_get_vtable();
+ if (ictr != NULL) {
+ br_ssl_engine_set_aes_ctr(cc, ictr);
+ } else {
+#if BR_64
+ br_ssl_engine_set_aes_ctr(cc, &br_aes_ct64_ctr_vtable);
+#else
+ br_ssl_engine_set_aes_ctr(cc, &br_aes_ct_ctr_vtable);
+#endif
+ }
+#else
+#if BR_64
+ br_ssl_engine_set_aes_ctr(cc, &br_aes_ct64_ctr_vtable);
+#else
+ br_ssl_engine_set_aes_ctr(cc, &br_aes_ct_ctr_vtable);
+#endif
+#endif
+#if BR_AES_X86NI
+ ighash = br_ghash_pclmul_get();
+ if (ighash != 0) {
+ br_ssl_engine_set_ghash(cc, ighash);
+ return;
+ }
+#endif
+#if BR_POWER8
+ ighash = br_ghash_pwr8_get();
+ if (ighash != 0) {
+ br_ssl_engine_set_ghash(cc, ighash);
+ return;
+ }
+#endif
+#if BR_LOMUL
+ br_ssl_engine_set_ghash(cc, &br_ghash_ctmul32);
+#elif BR_64
+ br_ssl_engine_set_ghash(cc, &br_ghash_ctmul64);
+#else
+ br_ssl_engine_set_ghash(cc, &br_ghash_ctmul);
+#endif
+}
diff --git a/contrib/bearssl/src/ssl/ssl_engine_default_chapol.c b/contrib/bearssl/src/ssl/ssl_engine_default_chapol.c
new file mode 100644
index 000000000000..47a0c9847abf
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_engine_default_chapol.c
@@ -0,0 +1,65 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_default_chapol(br_ssl_engine_context *cc)
+{
+#if BR_INT128 || BR_UMUL128
+ br_poly1305_run bp;
+#endif
+#if BR_SSE2
+ br_chacha20_run bc;
+#endif
+
+ br_ssl_engine_set_chapol(cc,
+ &br_sslrec_in_chapol_vtable,
+ &br_sslrec_out_chapol_vtable);
+#if BR_SSE2
+ bc = br_chacha20_sse2_get();
+ if (bc) {
+ br_ssl_engine_set_chacha20(cc, bc);
+ } else {
+#endif
+ br_ssl_engine_set_chacha20(cc, &br_chacha20_ct_run);
+#if BR_SSE2
+ }
+#endif
+#if BR_INT128 || BR_UMUL128
+ bp = br_poly1305_ctmulq_get();
+ if (bp) {
+ br_ssl_engine_set_poly1305(cc, bp);
+ } else {
+#endif
+#if BR_LOMUL
+ br_ssl_engine_set_poly1305(cc, &br_poly1305_ctmul32_run);
+#else
+ br_ssl_engine_set_poly1305(cc, &br_poly1305_ctmul_run);
+#endif
+#if BR_INT128 || BR_UMUL128
+ }
+#endif
+}
diff --git a/contrib/bearssl/src/ssl/ssl_engine_default_descbc.c b/contrib/bearssl/src/ssl/ssl_engine_default_descbc.c
new file mode 100644
index 000000000000..0253cb2fcf18
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_engine_default_descbc.c
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_default_des_cbc(br_ssl_engine_context *cc)
+{
+ br_ssl_engine_set_cbc(cc,
+ &br_sslrec_in_cbc_vtable,
+ &br_sslrec_out_cbc_vtable);
+ br_ssl_engine_set_des_cbc(cc,
+ &br_des_ct_cbcenc_vtable,
+ &br_des_ct_cbcdec_vtable);
+}
diff --git a/contrib/bearssl/src/ssl/ssl_engine_default_ec.c b/contrib/bearssl/src/ssl/ssl_engine_default_ec.c
new file mode 100644
index 000000000000..0213ae63e2bc
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_engine_default_ec.c
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_default_ec(br_ssl_engine_context *cc)
+{
+#if BR_LOMUL
+ br_ssl_engine_set_ec(cc, &br_ec_all_m15);
+#else
+ br_ssl_engine_set_ec(cc, &br_ec_all_m31);
+#endif
+}
diff --git a/contrib/bearssl/src/ssl/ssl_engine_default_ecdsa.c b/contrib/bearssl/src/ssl/ssl_engine_default_ecdsa.c
new file mode 100644
index 000000000000..1304002570d2
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_engine_default_ecdsa.c
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_default_ecdsa(br_ssl_engine_context *cc)
+{
+#if BR_LOMUL
+ br_ssl_engine_set_ec(cc, &br_ec_all_m15);
+ br_ssl_engine_set_ecdsa(cc, &br_ecdsa_i15_vrfy_asn1);
+#else
+ br_ssl_engine_set_ec(cc, &br_ec_all_m31);
+ br_ssl_engine_set_ecdsa(cc, &br_ecdsa_i31_vrfy_asn1);
+#endif
+}
diff --git a/contrib/bearssl/src/ssl/ssl_engine_default_rsavrfy.c b/contrib/bearssl/src/ssl/ssl_engine_default_rsavrfy.c
new file mode 100644
index 000000000000..ad0628abbfcf
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_engine_default_rsavrfy.c
@@ -0,0 +1,32 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_engine_set_default_rsavrfy(br_ssl_engine_context *cc)
+{
+ br_ssl_engine_set_rsavrfy(cc, br_rsa_pkcs1_vrfy_get_default());
+}
diff --git a/contrib/bearssl/src/ssl/ssl_hashes.c b/contrib/bearssl/src/ssl/ssl_hashes.c
new file mode 100644
index 000000000000..e10a980c476a
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_hashes.c
@@ -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"
+
+/* see inner.h */
+int
+br_ssl_choose_hash(unsigned bf)
+{
+ static const unsigned char pref[] = {
+ br_sha256_ID, br_sha384_ID, br_sha512_ID,
+ br_sha224_ID, br_sha1_ID
+ };
+ size_t u;
+
+ for (u = 0; u < sizeof pref; u ++) {
+ int x;
+
+ x = pref[u];
+ if ((bf >> x) & 1) {
+ return x;
+ }
+ }
+ return 0;
+}
diff --git a/contrib/bearssl/src/ssl/ssl_hs_client.c b/contrib/bearssl/src/ssl/ssl_hs_client.c
new file mode 100644
index 000000000000..de36165aa947
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_hs_client.c
@@ -0,0 +1,1915 @@
+/* Automatically generated code; do not modify directly. */
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+} t0_context;
+
+static uint32_t
+t0_parse7E_unsigned(const unsigned char **p)
+{
+ uint32_t x;
+
+ x = 0;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ return x;
+ }
+ }
+}
+
+static int32_t
+t0_parse7E_signed(const unsigned char **p)
+{
+ int neg;
+ uint32_t x;
+
+ neg = ((**p) >> 6) & 1;
+ x = (uint32_t)-neg;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ if (neg) {
+ return -(int32_t)~x - 1;
+ } else {
+ return (int32_t)x;
+ }
+ }
+ }
+}
+
+#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80)
+#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F)
+#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8)
+#define T0_INT1(x) T0_FBYTE(x, 0)
+#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+
+/* static const unsigned char t0_datablock[]; */
+
+
+void br_ssl_hs_client_init_main(void *t0ctx);
+
+void br_ssl_hs_client_run(void *t0ctx);
+
+
+
+#include <stddef.h>
+#include <string.h>
+
+#include "inner.h"
+
+/*
+ * This macro evaluates to a pointer to the current engine context.
+ */
+#define ENG ((br_ssl_engine_context *)(void *)((unsigned char *)t0ctx - offsetof(br_ssl_engine_context, cpu)))
+
+
+
+
+
+/*
+ * This macro evaluates to a pointer to the client context, under that
+ * specific name. It must be noted that since the engine context is the
+ * first field of the br_ssl_client_context structure ('eng'), then
+ * pointers values of both types are interchangeable, modulo an
+ * appropriate cast. This also means that "addresses" computed as offsets
+ * within the structure work for both kinds of context.
+ */
+#define CTX ((br_ssl_client_context *)ENG)
+
+/*
+ * Generate the pre-master secret for RSA key exchange, and encrypt it
+ * with the server's public key. Returned value is either the encrypted
+ * data length (in bytes), or -x on error, with 'x' being an error code.
+ *
+ * This code assumes that the public key has been already verified (it
+ * was properly obtained by the X.509 engine, and it has the right type,
+ * i.e. it is of type RSA and suitable for encryption).
+ */
+static int
+make_pms_rsa(br_ssl_client_context *ctx, int prf_id)
+{
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+ const unsigned char *n;
+ unsigned char *pms;
+ size_t nlen, u;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+
+ /*
+ * Compute actual RSA key length, in case there are leading zeros.
+ */
+ n = pk->key.rsa.n;
+ nlen = pk->key.rsa.nlen;
+ while (nlen > 0 && *n == 0) {
+ n ++;
+ nlen --;
+ }
+
+ /*
+ * We need at least 59 bytes (48 bytes for pre-master secret, and
+ * 11 bytes for the PKCS#1 type 2 padding). Note that the X.509
+ * minimal engine normally blocks RSA keys shorter than 128 bytes,
+ * so this is mostly for public keys provided explicitly by the
+ * caller.
+ */
+ if (nlen < 59) {
+ return -BR_ERR_X509_WEAK_PUBLIC_KEY;
+ }
+ if (nlen > sizeof ctx->eng.pad) {
+ return -BR_ERR_LIMIT_EXCEEDED;
+ }
+
+ /*
+ * Make PMS.
+ */
+ pms = ctx->eng.pad + nlen - 48;
+ br_enc16be(pms, ctx->eng.version_max);
+ br_hmac_drbg_generate(&ctx->eng.rng, pms + 2, 46);
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, pms, 48);
+
+ /*
+ * Apply PKCS#1 type 2 padding.
+ */
+ ctx->eng.pad[0] = 0x00;
+ ctx->eng.pad[1] = 0x02;
+ ctx->eng.pad[nlen - 49] = 0x00;
+ br_hmac_drbg_generate(&ctx->eng.rng, ctx->eng.pad + 2, nlen - 51);
+ for (u = 2; u < nlen - 49; u ++) {
+ while (ctx->eng.pad[u] == 0) {
+ br_hmac_drbg_generate(&ctx->eng.rng,
+ &ctx->eng.pad[u], 1);
+ }
+ }
+
+ /*
+ * Compute RSA encryption.
+ */
+ if (!ctx->irsapub(ctx->eng.pad, nlen, &pk->key.rsa)) {
+ return -BR_ERR_LIMIT_EXCEEDED;
+ }
+ return (int)nlen;
+}
+
+/*
+ * OID for hash functions in RSA signatures.
+ */
+static const unsigned char *HASH_OID[] = {
+ BR_HASH_OID_SHA1,
+ BR_HASH_OID_SHA224,
+ BR_HASH_OID_SHA256,
+ BR_HASH_OID_SHA384,
+ BR_HASH_OID_SHA512
+};
+
+/*
+ * Check the RSA signature on the ServerKeyExchange message.
+ *
+ * hash hash function ID (2 to 6), or 0 for MD5+SHA-1 (with RSA only)
+ * use_rsa non-zero for RSA signature, zero for ECDSA
+ * sig_len signature length (in bytes); signature value is in the pad
+ *
+ * Returned value is 0 on success, or an error code.
+ */
+static int
+verify_SKE_sig(br_ssl_client_context *ctx,
+ int hash, int use_rsa, size_t sig_len)
+{
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+ br_multihash_context mhc;
+ unsigned char hv[64], head[4];
+ size_t hv_len;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+ br_multihash_zero(&mhc);
+ br_multihash_copyimpl(&mhc, &ctx->eng.mhash);
+ br_multihash_init(&mhc);
+ br_multihash_update(&mhc,
+ ctx->eng.client_random, sizeof ctx->eng.client_random);
+ br_multihash_update(&mhc,
+ ctx->eng.server_random, sizeof ctx->eng.server_random);
+ head[0] = 3;
+ head[1] = 0;
+ head[2] = ctx->eng.ecdhe_curve;
+ head[3] = ctx->eng.ecdhe_point_len;
+ br_multihash_update(&mhc, head, sizeof head);
+ br_multihash_update(&mhc,
+ ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len);
+ if (hash) {
+ hv_len = br_multihash_out(&mhc, hash, hv);
+ if (hv_len == 0) {
+ return BR_ERR_INVALID_ALGORITHM;
+ }
+ } else {
+ if (!br_multihash_out(&mhc, br_md5_ID, hv)
+ || !br_multihash_out(&mhc, br_sha1_ID, hv + 16))
+ {
+ return BR_ERR_INVALID_ALGORITHM;
+ }
+ hv_len = 36;
+ }
+ if (use_rsa) {
+ unsigned char tmp[64];
+ const unsigned char *hash_oid;
+
+ if (hash) {
+ hash_oid = HASH_OID[hash - 2];
+ } else {
+ hash_oid = NULL;
+ }
+ if (!ctx->eng.irsavrfy(ctx->eng.pad, sig_len,
+ hash_oid, hv_len, &pk->key.rsa, tmp)
+ || memcmp(tmp, hv, hv_len) != 0)
+ {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ } else {
+ if (!ctx->eng.iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec,
+ ctx->eng.pad, sig_len))
+ {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Perform client-side ECDH (or ECDHE). The point that should be sent to
+ * the server is written in the pad; returned value is either the point
+ * length (in bytes), or -x on error, with 'x' being an error code.
+ *
+ * The point _from_ the server is taken from ecdhe_point[] if 'ecdhe'
+ * is non-zero, or from the X.509 engine context if 'ecdhe' is zero
+ * (for static ECDH).
+ */
+static int
+make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id)
+{
+ int curve;
+ unsigned char key[66], point[133];
+ const unsigned char *order, *point_src;
+ size_t glen, olen, point_len, xoff, xlen;
+ unsigned char mask;
+
+ if (ecdhe) {
+ curve = ctx->eng.ecdhe_curve;
+ point_src = ctx->eng.ecdhe_point;
+ point_len = ctx->eng.ecdhe_point_len;
+ } else {
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+ curve = pk->key.ec.curve;
+ point_src = pk->key.ec.q;
+ point_len = pk->key.ec.qlen;
+ }
+ if ((ctx->eng.iec->supported_curves & ((uint32_t)1 << curve)) == 0) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ /*
+ * We need to generate our key, as a non-zero random value which
+ * is lower than the curve order, in a "large enough" range. We
+ * force top bit to 0 and bottom bit to 1, which guarantees that
+ * the value is in the proper range.
+ */
+ order = ctx->eng.iec->order(curve, &olen);
+ mask = 0xFF;
+ while (mask >= order[0]) {
+ mask >>= 1;
+ }
+ br_hmac_drbg_generate(&ctx->eng.rng, key, olen);
+ key[0] &= mask;
+ key[olen - 1] |= 0x01;
+
+ /*
+ * Compute the common ECDH point, whose X coordinate is the
+ * pre-master secret.
+ */
+ ctx->eng.iec->generator(curve, &glen);
+ if (glen != point_len) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ memcpy(point, point_src, glen);
+ if (!ctx->eng.iec->mul(point, glen, key, olen, curve)) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ /*
+ * The pre-master secret is the X coordinate.
+ */
+ xoff = ctx->eng.iec->xoff(curve, &xlen);
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, point + xoff, xlen);
+
+ ctx->eng.iec->mulgen(point, key, olen, curve);
+ memcpy(ctx->eng.pad, point, glen);
+ return (int)glen;
+}
+
+/*
+ * Perform full static ECDH. This occurs only in the context of client
+ * authentication with certificates: the server uses an EC public key,
+ * the cipher suite is of type ECDH (not ECDHE), the server requested a
+ * client certificate and accepts static ECDH, the client has a
+ * certificate with an EC public key in the same curve, and accepts
+ * static ECDH as well.
+ *
+ * Returned value is 0 on success, -1 on error.
+ */
+static int
+make_pms_static_ecdh(br_ssl_client_context *ctx, int prf_id)
+{
+ unsigned char point[133];
+ size_t point_len;
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+ point_len = pk->key.ec.qlen;
+ if (point_len > sizeof point) {
+ return -1;
+ }
+ memcpy(point, pk->key.ec.q, point_len);
+ if (!(*ctx->client_auth_vtable)->do_keyx(
+ ctx->client_auth_vtable, point, &point_len))
+ {
+ return -1;
+ }
+ br_ssl_engine_compute_master(&ctx->eng,
+ prf_id, point, point_len);
+ return 0;
+}
+
+/*
+ * Compute the client-side signature. This is invoked only when a
+ * signature-based client authentication was selected. The computed
+ * signature is in the pad; its length (in bytes) is returned. On
+ * error, 0 is returned.
+ */
+static size_t
+make_client_sign(br_ssl_client_context *ctx)
+{
+ size_t hv_len;
+
+ /*
+ * Compute hash of handshake messages so far. This "cannot" fail
+ * because the list of supported hash functions provided to the
+ * client certificate handler was trimmed to include only the
+ * hash functions that the multi-hasher supports.
+ */
+ if (ctx->hash_id) {
+ hv_len = br_multihash_out(&ctx->eng.mhash,
+ ctx->hash_id, ctx->eng.pad);
+ } else {
+ br_multihash_out(&ctx->eng.mhash,
+ br_md5_ID, ctx->eng.pad);
+ br_multihash_out(&ctx->eng.mhash,
+ br_sha1_ID, ctx->eng.pad + 16);
+ hv_len = 36;
+ }
+ return (*ctx->client_auth_vtable)->do_sign(
+ ctx->client_auth_vtable, ctx->hash_id, hv_len,
+ ctx->eng.pad, sizeof ctx->eng.pad);
+}
+
+
+
+static const unsigned char t0_datablock[] = {
+ 0x00, 0x00, 0x0A, 0x00, 0x24, 0x00, 0x2F, 0x01, 0x24, 0x00, 0x35, 0x02,
+ 0x24, 0x00, 0x3C, 0x01, 0x44, 0x00, 0x3D, 0x02, 0x44, 0x00, 0x9C, 0x03,
+ 0x04, 0x00, 0x9D, 0x04, 0x05, 0xC0, 0x03, 0x40, 0x24, 0xC0, 0x04, 0x41,
+ 0x24, 0xC0, 0x05, 0x42, 0x24, 0xC0, 0x08, 0x20, 0x24, 0xC0, 0x09, 0x21,
+ 0x24, 0xC0, 0x0A, 0x22, 0x24, 0xC0, 0x0D, 0x30, 0x24, 0xC0, 0x0E, 0x31,
+ 0x24, 0xC0, 0x0F, 0x32, 0x24, 0xC0, 0x12, 0x10, 0x24, 0xC0, 0x13, 0x11,
+ 0x24, 0xC0, 0x14, 0x12, 0x24, 0xC0, 0x23, 0x21, 0x44, 0xC0, 0x24, 0x22,
+ 0x55, 0xC0, 0x25, 0x41, 0x44, 0xC0, 0x26, 0x42, 0x55, 0xC0, 0x27, 0x11,
+ 0x44, 0xC0, 0x28, 0x12, 0x55, 0xC0, 0x29, 0x31, 0x44, 0xC0, 0x2A, 0x32,
+ 0x55, 0xC0, 0x2B, 0x23, 0x04, 0xC0, 0x2C, 0x24, 0x05, 0xC0, 0x2D, 0x43,
+ 0x04, 0xC0, 0x2E, 0x44, 0x05, 0xC0, 0x2F, 0x13, 0x04, 0xC0, 0x30, 0x14,
+ 0x05, 0xC0, 0x31, 0x33, 0x04, 0xC0, 0x32, 0x34, 0x05, 0xC0, 0x9C, 0x06,
+ 0x04, 0xC0, 0x9D, 0x07, 0x04, 0xC0, 0xA0, 0x08, 0x04, 0xC0, 0xA1, 0x09,
+ 0x04, 0xC0, 0xAC, 0x26, 0x04, 0xC0, 0xAD, 0x27, 0x04, 0xC0, 0xAE, 0x28,
+ 0x04, 0xC0, 0xAF, 0x29, 0x04, 0xCC, 0xA8, 0x15, 0x04, 0xCC, 0xA9, 0x25,
+ 0x04, 0x00, 0x00
+};
+
+static const unsigned char t0_codeblock[] = {
+ 0x00, 0x01, 0x00, 0x0A, 0x00, 0x00, 0x01, 0x00, 0x0D, 0x00, 0x00, 0x01,
+ 0x00, 0x0E, 0x00, 0x00, 0x01, 0x00, 0x0F, 0x00, 0x00, 0x01, 0x01, 0x08,
+ 0x00, 0x00, 0x01, 0x01, 0x09, 0x00, 0x00, 0x01, 0x02, 0x08, 0x00, 0x00,
+ 0x01, 0x02, 0x09, 0x00, 0x00, 0x25, 0x25, 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_CCS), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_CIPHER_SUITE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_COMPRESSION), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_FINISHED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_FRAGLEN), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_HANDSHAKE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_HELLO_DONE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_PARAM), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_SECRENEG), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_SNI), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_BAD_VERSION),
+ 0x00, 0x00, 0x01, T0_INT1(BR_ERR_EXTRA_EXTENSION), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_INVALID_ALGORITHM), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_LIMIT_EXCEEDED), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_OK),
+ 0x00, 0x00, 0x01, T0_INT1(BR_ERR_OVERSIZED_ID), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_RESUME_MISMATCH), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_UNEXPECTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_UNSUPPORTED_VERSION), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_WRONG_KEY_USAGE), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, action)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, alert)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, application_data)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_client_context, auth_type)), 0x00, 0x00,
+ 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, cipher_suite)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, client_random)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, close_received)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, ecdhe_curve)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, ecdhe_point)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, ecdhe_point_len)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, flags)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_client_context, hash_id)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_client_context, hashes)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, log_max_frag_len)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_client_context, min_clienthello_len)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, pad)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, protocol_names_num)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, record_type_in)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, record_type_out)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, reneg)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, saved_finished)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, selected_protocol)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, server_name)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, server_random)), 0x00, 0x00,
+ 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, session_id)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, session_id_len)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, shutdown_recv)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, suites_buf)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, suites_num)), 0x00, 0x00,
+ 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, version)),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_in)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, version_max)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_min)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_out)),
+ 0x00, 0x00, 0x09, 0x26, 0x58, 0x06, 0x02, 0x68, 0x28, 0x00, 0x00, 0x06,
+ 0x08, 0x2C, 0x0E, 0x05, 0x02, 0x71, 0x28, 0x04, 0x01, 0x3C, 0x00, 0x00,
+ 0x01, 0x01, 0x00, 0x01, 0x03, 0x00, 0x99, 0x26, 0x5E, 0x44, 0x9D, 0x26,
+ 0x05, 0x04, 0x60, 0x01, 0x00, 0x00, 0x02, 0x00, 0x0E, 0x06, 0x02, 0x9D,
+ 0x00, 0x5E, 0x04, 0x6B, 0x00, 0x06, 0x02, 0x68, 0x28, 0x00, 0x00, 0x26,
+ 0x89, 0x44, 0x05, 0x03, 0x01, 0x0C, 0x08, 0x44, 0x79, 0x2C, 0xAB, 0x1C,
+ 0x84, 0x01, 0x0C, 0x31, 0x00, 0x00, 0x26, 0x1F, 0x01, 0x08, 0x0B, 0x44,
+ 0x5C, 0x1F, 0x08, 0x00, 0x01, 0x03, 0x00, 0x77, 0x2E, 0x02, 0x00, 0x36,
+ 0x17, 0x01, 0x01, 0x0B, 0x77, 0x3E, 0x29, 0x1A, 0x36, 0x06, 0x07, 0x02,
+ 0x00, 0xCF, 0x03, 0x00, 0x04, 0x75, 0x01, 0x00, 0xC5, 0x02, 0x00, 0x26,
+ 0x1A, 0x17, 0x06, 0x02, 0x6F, 0x28, 0xCF, 0x04, 0x76, 0x01, 0x01, 0x00,
+ 0x77, 0x3E, 0x01, 0x16, 0x87, 0x3E, 0x01, 0x00, 0x8A, 0x3C, 0x34, 0xD5,
+ 0x29, 0xB4, 0x06, 0x09, 0x01, 0x7F, 0xAF, 0x01, 0x7F, 0xD2, 0x04, 0x80,
+ 0x53, 0xB1, 0x79, 0x2C, 0xA1, 0x01, T0_INT1(BR_KEYTYPE_SIGN), 0x17,
+ 0x06, 0x01, 0xB5, 0xB8, 0x26, 0x01, 0x0D, 0x0E, 0x06, 0x07, 0x25, 0xB7,
+ 0xB8, 0x01, 0x7F, 0x04, 0x02, 0x01, 0x00, 0x03, 0x00, 0x01, 0x0E, 0x0E,
+ 0x05, 0x02, 0x72, 0x28, 0x06, 0x02, 0x67, 0x28, 0x33, 0x06, 0x02, 0x72,
+ 0x28, 0x02, 0x00, 0x06, 0x1C, 0xD3, 0x80, 0x2E, 0x01, 0x81, 0x7F, 0x0E,
+ 0x06, 0x0D, 0x25, 0x01, 0x10, 0xDE, 0x01, 0x00, 0xDD, 0x79, 0x2C, 0xAB,
+ 0x24, 0x04, 0x04, 0xD6, 0x06, 0x01, 0xD4, 0x04, 0x01, 0xD6, 0x01, 0x7F,
+ 0xD2, 0x01, 0x7F, 0xAF, 0x01, 0x01, 0x77, 0x3E, 0x01, 0x17, 0x87, 0x3E,
+ 0x00, 0x00, 0x38, 0x38, 0x00, 0x00, 0x9A, 0x01, 0x0C, 0x11, 0x01, 0x00,
+ 0x38, 0x0E, 0x06, 0x05, 0x25, 0x01,
+ T0_INT1(BR_KEYTYPE_RSA | BR_KEYTYPE_KEYX), 0x04, 0x30, 0x01, 0x01,
+ 0x38, 0x0E, 0x06, 0x05, 0x25, 0x01,
+ T0_INT1(BR_KEYTYPE_RSA | BR_KEYTYPE_SIGN), 0x04, 0x25, 0x01, 0x02,
+ 0x38, 0x0E, 0x06, 0x05, 0x25, 0x01,
+ T0_INT1(BR_KEYTYPE_EC | BR_KEYTYPE_SIGN), 0x04, 0x1A, 0x01, 0x03,
+ 0x38, 0x0E, 0x06, 0x05, 0x25, 0x01,
+ T0_INT1(BR_KEYTYPE_EC | BR_KEYTYPE_KEYX), 0x04, 0x0F, 0x01, 0x04,
+ 0x38, 0x0E, 0x06, 0x05, 0x25, 0x01,
+ T0_INT1(BR_KEYTYPE_EC | BR_KEYTYPE_KEYX), 0x04, 0x04, 0x01, 0x00,
+ 0x44, 0x25, 0x00, 0x00, 0x82, 0x2E, 0x01, 0x0E, 0x0E, 0x06, 0x04, 0x01,
+ 0x00, 0x04, 0x02, 0x01, 0x05, 0x00, 0x00, 0x40, 0x06, 0x04, 0x01, 0x06,
+ 0x04, 0x02, 0x01, 0x00, 0x00, 0x00, 0x88, 0x2E, 0x26, 0x06, 0x08, 0x01,
+ 0x01, 0x09, 0x01, 0x11, 0x07, 0x04, 0x03, 0x25, 0x01, 0x05, 0x00, 0x01,
+ 0x41, 0x03, 0x00, 0x25, 0x01, 0x00, 0x43, 0x06, 0x03, 0x02, 0x00, 0x08,
+ 0x42, 0x06, 0x03, 0x02, 0x00, 0x08, 0x26, 0x06, 0x06, 0x01, 0x01, 0x0B,
+ 0x01, 0x06, 0x08, 0x00, 0x00, 0x8B, 0x3F, 0x26, 0x06, 0x03, 0x01, 0x09,
+ 0x08, 0x00, 0x01, 0x40, 0x26, 0x06, 0x1E, 0x01, 0x00, 0x03, 0x00, 0x26,
+ 0x06, 0x0E, 0x26, 0x01, 0x01, 0x17, 0x02, 0x00, 0x08, 0x03, 0x00, 0x01,
+ 0x01, 0x11, 0x04, 0x6F, 0x25, 0x02, 0x00, 0x01, 0x01, 0x0B, 0x01, 0x06,
+ 0x08, 0x00, 0x00, 0x7F, 0x2D, 0x44, 0x11, 0x01, 0x01, 0x17, 0x35, 0x00,
+ 0x00, 0x9F, 0xCE, 0x26, 0x01, 0x07, 0x17, 0x01, 0x00, 0x38, 0x0E, 0x06,
+ 0x09, 0x25, 0x01, 0x10, 0x17, 0x06, 0x01, 0x9F, 0x04, 0x35, 0x01, 0x01,
+ 0x38, 0x0E, 0x06, 0x2C, 0x25, 0x25, 0x01, 0x00, 0x77, 0x3E, 0xB3, 0x88,
+ 0x2E, 0x01, 0x01, 0x0E, 0x01, 0x01, 0xA8, 0x37, 0x06, 0x17, 0x29, 0x1A,
+ 0x36, 0x06, 0x04, 0xCE, 0x25, 0x04, 0x78, 0x01, 0x80, 0x64, 0xC5, 0x01,
+ 0x01, 0x77, 0x3E, 0x01, 0x17, 0x87, 0x3E, 0x04, 0x01, 0x9F, 0x04, 0x03,
+ 0x72, 0x28, 0x25, 0x04, 0xFF, 0x34, 0x01, 0x26, 0x03, 0x00, 0x09, 0x26,
+ 0x58, 0x06, 0x02, 0x68, 0x28, 0x02, 0x00, 0x00, 0x00, 0x9A, 0x01, 0x0F,
+ 0x17, 0x00, 0x00, 0x76, 0x2E, 0x01, 0x00, 0x38, 0x0E, 0x06, 0x10, 0x25,
+ 0x26, 0x01, 0x01, 0x0D, 0x06, 0x03, 0x25, 0x01, 0x02, 0x76, 0x3E, 0x01,
+ 0x00, 0x04, 0x21, 0x01, 0x01, 0x38, 0x0E, 0x06, 0x14, 0x25, 0x01, 0x00,
+ 0x76, 0x3E, 0x26, 0x01, 0x80, 0x64, 0x0E, 0x06, 0x05, 0x01, 0x82, 0x00,
+ 0x08, 0x28, 0x5A, 0x04, 0x07, 0x25, 0x01, 0x82, 0x00, 0x08, 0x28, 0x25,
+ 0x00, 0x00, 0x01, 0x00, 0x2F, 0x06, 0x05, 0x3A, 0xAC, 0x37, 0x04, 0x78,
+ 0x26, 0x06, 0x04, 0x01, 0x01, 0x8F, 0x3E, 0x00, 0x01, 0xBF, 0xAA, 0xBF,
+ 0xAA, 0xC1, 0x84, 0x44, 0x26, 0x03, 0x00, 0xB6, 0x9B, 0x9B, 0x02, 0x00,
+ 0x4D, 0x26, 0x58, 0x06, 0x0A, 0x01, 0x03, 0xA8, 0x06, 0x02, 0x72, 0x28,
+ 0x25, 0x04, 0x03, 0x5C, 0x8A, 0x3C, 0x00, 0x00, 0x2F, 0x06, 0x0B, 0x86,
+ 0x2E, 0x01, 0x14, 0x0D, 0x06, 0x02, 0x72, 0x28, 0x04, 0x11, 0xCE, 0x01,
+ 0x07, 0x17, 0x26, 0x01, 0x02, 0x0D, 0x06, 0x06, 0x06, 0x02, 0x72, 0x28,
+ 0x04, 0x70, 0x25, 0xC2, 0x01, 0x01, 0x0D, 0x33, 0x37, 0x06, 0x02, 0x61,
+ 0x28, 0x26, 0x01, 0x01, 0xC8, 0x36, 0xB2, 0x00, 0x01, 0xB8, 0x01, 0x0B,
+ 0x0E, 0x05, 0x02, 0x72, 0x28, 0x26, 0x01, 0x03, 0x0E, 0x06, 0x08, 0xC0,
+ 0x06, 0x02, 0x68, 0x28, 0x44, 0x25, 0x00, 0x44, 0x57, 0xC0, 0xAA, 0x26,
+ 0x06, 0x23, 0xC0, 0xAA, 0x26, 0x56, 0x26, 0x06, 0x18, 0x26, 0x01, 0x82,
+ 0x00, 0x0F, 0x06, 0x05, 0x01, 0x82, 0x00, 0x04, 0x01, 0x26, 0x03, 0x00,
+ 0x84, 0x02, 0x00, 0xB6, 0x02, 0x00, 0x53, 0x04, 0x65, 0x9B, 0x54, 0x04,
+ 0x5A, 0x9B, 0x9B, 0x55, 0x26, 0x06, 0x02, 0x35, 0x00, 0x25, 0x2B, 0x00,
+ 0x00, 0x79, 0x2C, 0xA1, 0x01, 0x7F, 0xB0, 0x26, 0x58, 0x06, 0x02, 0x35,
+ 0x28, 0x26, 0x05, 0x02, 0x72, 0x28, 0x38, 0x17, 0x0D, 0x06, 0x02, 0x74,
+ 0x28, 0x3B, 0x00, 0x00, 0x9C, 0xB8, 0x01, 0x14, 0x0D, 0x06, 0x02, 0x72,
+ 0x28, 0x84, 0x01, 0x0C, 0x08, 0x01, 0x0C, 0xB6, 0x9B, 0x84, 0x26, 0x01,
+ 0x0C, 0x08, 0x01, 0x0C, 0x30, 0x05, 0x02, 0x64, 0x28, 0x00, 0x00, 0xB9,
+ 0x06, 0x02, 0x72, 0x28, 0x06, 0x02, 0x66, 0x28, 0x00, 0x0A, 0xB8, 0x01,
+ 0x02, 0x0E, 0x05, 0x02, 0x72, 0x28, 0xBF, 0x03, 0x00, 0x02, 0x00, 0x95,
+ 0x2C, 0x0A, 0x02, 0x00, 0x94, 0x2C, 0x0F, 0x37, 0x06, 0x02, 0x73, 0x28,
+ 0x02, 0x00, 0x93, 0x2C, 0x0D, 0x06, 0x02, 0x6B, 0x28, 0x02, 0x00, 0x96,
+ 0x3C, 0x8C, 0x01, 0x20, 0xB6, 0x01, 0x00, 0x03, 0x01, 0xC1, 0x03, 0x02,
+ 0x02, 0x02, 0x01, 0x20, 0x0F, 0x06, 0x02, 0x70, 0x28, 0x84, 0x02, 0x02,
+ 0xB6, 0x02, 0x02, 0x8E, 0x2E, 0x0E, 0x02, 0x02, 0x01, 0x00, 0x0F, 0x17,
+ 0x06, 0x0B, 0x8D, 0x84, 0x02, 0x02, 0x30, 0x06, 0x04, 0x01, 0x7F, 0x03,
+ 0x01, 0x8D, 0x84, 0x02, 0x02, 0x31, 0x02, 0x02, 0x8E, 0x3E, 0x02, 0x00,
+ 0x92, 0x02, 0x01, 0x98, 0xBF, 0x26, 0xC3, 0x58, 0x06, 0x02, 0x62, 0x28,
+ 0x26, 0xCD, 0x02, 0x00, 0x01, 0x86, 0x03, 0x0A, 0x17, 0x06, 0x02, 0x62,
+ 0x28, 0x79, 0x02, 0x01, 0x98, 0xC1, 0x06, 0x02, 0x63, 0x28, 0x26, 0x06,
+ 0x81, 0x47, 0xBF, 0xAA, 0xA6, 0x03, 0x03, 0xA4, 0x03, 0x04, 0xA2, 0x03,
+ 0x05, 0xA5, 0x03, 0x06, 0xA7, 0x03, 0x07, 0xA3, 0x03, 0x08, 0x27, 0x03,
+ 0x09, 0x26, 0x06, 0x81, 0x18, 0xBF, 0x01, 0x00, 0x38, 0x0E, 0x06, 0x0F,
+ 0x25, 0x02, 0x03, 0x05, 0x02, 0x6C, 0x28, 0x01, 0x00, 0x03, 0x03, 0xBE,
+ 0x04, 0x80, 0x7F, 0x01, 0x01, 0x38, 0x0E, 0x06, 0x0F, 0x25, 0x02, 0x05,
+ 0x05, 0x02, 0x6C, 0x28, 0x01, 0x00, 0x03, 0x05, 0xBC, 0x04, 0x80, 0x6A,
+ 0x01, 0x83, 0xFE, 0x01, 0x38, 0x0E, 0x06, 0x0F, 0x25, 0x02, 0x04, 0x05,
+ 0x02, 0x6C, 0x28, 0x01, 0x00, 0x03, 0x04, 0xBD, 0x04, 0x80, 0x53, 0x01,
+ 0x0D, 0x38, 0x0E, 0x06, 0x0E, 0x25, 0x02, 0x06, 0x05, 0x02, 0x6C, 0x28,
+ 0x01, 0x00, 0x03, 0x06, 0xBA, 0x04, 0x3F, 0x01, 0x0A, 0x38, 0x0E, 0x06,
+ 0x0E, 0x25, 0x02, 0x07, 0x05, 0x02, 0x6C, 0x28, 0x01, 0x00, 0x03, 0x07,
+ 0xBA, 0x04, 0x2B, 0x01, 0x0B, 0x38, 0x0E, 0x06, 0x0E, 0x25, 0x02, 0x08,
+ 0x05, 0x02, 0x6C, 0x28, 0x01, 0x00, 0x03, 0x08, 0xBA, 0x04, 0x17, 0x01,
+ 0x10, 0x38, 0x0E, 0x06, 0x0E, 0x25, 0x02, 0x09, 0x05, 0x02, 0x6C, 0x28,
+ 0x01, 0x00, 0x03, 0x09, 0xAE, 0x04, 0x03, 0x6C, 0x28, 0x25, 0x04, 0xFE,
+ 0x64, 0x02, 0x04, 0x06, 0x0D, 0x02, 0x04, 0x01, 0x05, 0x0F, 0x06, 0x02,
+ 0x69, 0x28, 0x01, 0x01, 0x88, 0x3E, 0x9B, 0x04, 0x0C, 0xA4, 0x01, 0x05,
+ 0x0F, 0x06, 0x02, 0x69, 0x28, 0x01, 0x01, 0x88, 0x3E, 0x9B, 0x02, 0x01,
+ 0x00, 0x04, 0xB8, 0x01, 0x0C, 0x0E, 0x05, 0x02, 0x72, 0x28, 0xC1, 0x01,
+ 0x03, 0x0E, 0x05, 0x02, 0x6D, 0x28, 0xBF, 0x26, 0x7C, 0x3E, 0x26, 0x01,
+ 0x20, 0x10, 0x06, 0x02, 0x6D, 0x28, 0x40, 0x44, 0x11, 0x01, 0x01, 0x17,
+ 0x05, 0x02, 0x6D, 0x28, 0xC1, 0x26, 0x01, 0x81, 0x05, 0x0F, 0x06, 0x02,
+ 0x6D, 0x28, 0x26, 0x7E, 0x3E, 0x7D, 0x44, 0xB6, 0x92, 0x2C, 0x01, 0x86,
+ 0x03, 0x10, 0x03, 0x00, 0x79, 0x2C, 0xCB, 0x03, 0x01, 0x01, 0x02, 0x03,
+ 0x02, 0x02, 0x00, 0x06, 0x21, 0xC1, 0x26, 0x26, 0x01, 0x02, 0x0A, 0x44,
+ 0x01, 0x06, 0x0F, 0x37, 0x06, 0x02, 0x6D, 0x28, 0x03, 0x02, 0xC1, 0x02,
+ 0x01, 0x01, 0x01, 0x0B, 0x01, 0x03, 0x08, 0x0E, 0x05, 0x02, 0x6D, 0x28,
+ 0x04, 0x08, 0x02, 0x01, 0x06, 0x04, 0x01, 0x00, 0x03, 0x02, 0xBF, 0x26,
+ 0x03, 0x03, 0x26, 0x01, 0x84, 0x00, 0x0F, 0x06, 0x02, 0x6E, 0x28, 0x84,
+ 0x44, 0xB6, 0x02, 0x02, 0x02, 0x01, 0x02, 0x03, 0x50, 0x26, 0x06, 0x01,
+ 0x28, 0x25, 0x9B, 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0x02, 0x00, 0x97,
+ 0x02, 0x01, 0x02, 0x00, 0x39, 0x26, 0x01, 0x00, 0x0E, 0x06, 0x02, 0x60,
+ 0x00, 0xD0, 0x04, 0x74, 0x02, 0x01, 0x00, 0x03, 0x00, 0xC1, 0xAA, 0x26,
+ 0x06, 0x80, 0x43, 0xC1, 0x01, 0x01, 0x38, 0x0E, 0x06, 0x06, 0x25, 0x01,
+ 0x81, 0x7F, 0x04, 0x2E, 0x01, 0x80, 0x40, 0x38, 0x0E, 0x06, 0x07, 0x25,
+ 0x01, 0x83, 0xFE, 0x00, 0x04, 0x20, 0x01, 0x80, 0x41, 0x38, 0x0E, 0x06,
+ 0x07, 0x25, 0x01, 0x84, 0x80, 0x00, 0x04, 0x12, 0x01, 0x80, 0x42, 0x38,
+ 0x0E, 0x06, 0x07, 0x25, 0x01, 0x88, 0x80, 0x00, 0x04, 0x04, 0x01, 0x00,
+ 0x44, 0x25, 0x02, 0x00, 0x37, 0x03, 0x00, 0x04, 0xFF, 0x39, 0x9B, 0x79,
+ 0x2C, 0xC9, 0x05, 0x09, 0x02, 0x00, 0x01, 0x83, 0xFF, 0x7F, 0x17, 0x03,
+ 0x00, 0x92, 0x2C, 0x01, 0x86, 0x03, 0x10, 0x06, 0x3A, 0xBB, 0x26, 0x81,
+ 0x3D, 0x41, 0x25, 0x26, 0x01, 0x08, 0x0B, 0x37, 0x01, 0x8C, 0x80, 0x00,
+ 0x37, 0x17, 0x02, 0x00, 0x17, 0x02, 0x00, 0x01, 0x8C, 0x80, 0x00, 0x17,
+ 0x06, 0x19, 0x26, 0x01, 0x81, 0x7F, 0x17, 0x06, 0x05, 0x01, 0x84, 0x80,
+ 0x00, 0x37, 0x26, 0x01, 0x83, 0xFE, 0x00, 0x17, 0x06, 0x05, 0x01, 0x88,
+ 0x80, 0x00, 0x37, 0x03, 0x00, 0x04, 0x09, 0x02, 0x00, 0x01, 0x8C, 0x88,
+ 0x01, 0x17, 0x03, 0x00, 0x16, 0xBF, 0xAA, 0x26, 0x06, 0x23, 0xBF, 0xAA,
+ 0x26, 0x15, 0x26, 0x06, 0x18, 0x26, 0x01, 0x82, 0x00, 0x0F, 0x06, 0x05,
+ 0x01, 0x82, 0x00, 0x04, 0x01, 0x26, 0x03, 0x01, 0x84, 0x02, 0x01, 0xB6,
+ 0x02, 0x01, 0x12, 0x04, 0x65, 0x9B, 0x13, 0x04, 0x5A, 0x9B, 0x14, 0x9B,
+ 0x02, 0x00, 0x2A, 0x00, 0x00, 0xB9, 0x26, 0x5A, 0x06, 0x07, 0x25, 0x06,
+ 0x02, 0x66, 0x28, 0x04, 0x74, 0x00, 0x00, 0xC2, 0x01, 0x03, 0xC0, 0x44,
+ 0x25, 0x44, 0x00, 0x00, 0xBF, 0xC6, 0x00, 0x03, 0x01, 0x00, 0x03, 0x00,
+ 0xBF, 0xAA, 0x26, 0x06, 0x80, 0x50, 0xC1, 0x03, 0x01, 0xC1, 0x03, 0x02,
+ 0x02, 0x01, 0x01, 0x08, 0x0E, 0x06, 0x16, 0x02, 0x02, 0x01, 0x0F, 0x0C,
+ 0x06, 0x0D, 0x01, 0x01, 0x02, 0x02, 0x01, 0x10, 0x08, 0x0B, 0x02, 0x00,
+ 0x37, 0x03, 0x00, 0x04, 0x2A, 0x02, 0x01, 0x01, 0x02, 0x10, 0x02, 0x01,
+ 0x01, 0x06, 0x0C, 0x17, 0x02, 0x02, 0x01, 0x01, 0x0E, 0x02, 0x02, 0x01,
+ 0x03, 0x0E, 0x37, 0x17, 0x06, 0x11, 0x02, 0x00, 0x01, 0x01, 0x02, 0x02,
+ 0x5D, 0x01, 0x02, 0x0B, 0x02, 0x01, 0x08, 0x0B, 0x37, 0x03, 0x00, 0x04,
+ 0xFF, 0x2C, 0x9B, 0x02, 0x00, 0x00, 0x00, 0xBF, 0x01, 0x01, 0x0E, 0x05,
+ 0x02, 0x65, 0x28, 0xC1, 0x01, 0x08, 0x08, 0x82, 0x2E, 0x0E, 0x05, 0x02,
+ 0x65, 0x28, 0x00, 0x00, 0xBF, 0x88, 0x2E, 0x05, 0x15, 0x01, 0x01, 0x0E,
+ 0x05, 0x02, 0x69, 0x28, 0xC1, 0x01, 0x00, 0x0E, 0x05, 0x02, 0x69, 0x28,
+ 0x01, 0x02, 0x88, 0x3E, 0x04, 0x1C, 0x01, 0x19, 0x0E, 0x05, 0x02, 0x69,
+ 0x28, 0xC1, 0x01, 0x18, 0x0E, 0x05, 0x02, 0x69, 0x28, 0x84, 0x01, 0x18,
+ 0xB6, 0x89, 0x84, 0x01, 0x18, 0x30, 0x05, 0x02, 0x69, 0x28, 0x00, 0x00,
+ 0xBF, 0x06, 0x02, 0x6A, 0x28, 0x00, 0x00, 0x01, 0x02, 0x97, 0xC2, 0x01,
+ 0x08, 0x0B, 0xC2, 0x08, 0x00, 0x00, 0x01, 0x03, 0x97, 0xC2, 0x01, 0x08,
+ 0x0B, 0xC2, 0x08, 0x01, 0x08, 0x0B, 0xC2, 0x08, 0x00, 0x00, 0x01, 0x01,
+ 0x97, 0xC2, 0x00, 0x00, 0x3A, 0x26, 0x58, 0x05, 0x01, 0x00, 0x25, 0xD0,
+ 0x04, 0x76, 0x02, 0x03, 0x00, 0x91, 0x2E, 0x03, 0x01, 0x01, 0x00, 0x26,
+ 0x02, 0x01, 0x0A, 0x06, 0x10, 0x26, 0x01, 0x01, 0x0B, 0x90, 0x08, 0x2C,
+ 0x02, 0x00, 0x0E, 0x06, 0x01, 0x00, 0x5C, 0x04, 0x6A, 0x25, 0x01, 0x7F,
+ 0x00, 0x00, 0x01, 0x15, 0x87, 0x3E, 0x44, 0x52, 0x25, 0x52, 0x25, 0x29,
+ 0x00, 0x00, 0x01, 0x01, 0x44, 0xC4, 0x00, 0x00, 0x44, 0x38, 0x97, 0x44,
+ 0x26, 0x06, 0x05, 0xC2, 0x25, 0x5D, 0x04, 0x78, 0x25, 0x00, 0x00, 0x26,
+ 0x01, 0x81, 0xAC, 0x00, 0x0E, 0x06, 0x04, 0x25, 0x01, 0x7F, 0x00, 0x9A,
+ 0x59, 0x00, 0x02, 0x03, 0x00, 0x79, 0x2C, 0x9A, 0x03, 0x01, 0x02, 0x01,
+ 0x01, 0x0F, 0x17, 0x02, 0x01, 0x01, 0x04, 0x11, 0x01, 0x0F, 0x17, 0x02,
+ 0x01, 0x01, 0x08, 0x11, 0x01, 0x0F, 0x17, 0x01, 0x00, 0x38, 0x0E, 0x06,
+ 0x10, 0x25, 0x01, 0x00, 0x01, 0x18, 0x02, 0x00, 0x06, 0x03, 0x49, 0x04,
+ 0x01, 0x4A, 0x04, 0x81, 0x0D, 0x01, 0x01, 0x38, 0x0E, 0x06, 0x10, 0x25,
+ 0x01, 0x01, 0x01, 0x10, 0x02, 0x00, 0x06, 0x03, 0x49, 0x04, 0x01, 0x4A,
+ 0x04, 0x80, 0x77, 0x01, 0x02, 0x38, 0x0E, 0x06, 0x10, 0x25, 0x01, 0x01,
+ 0x01, 0x20, 0x02, 0x00, 0x06, 0x03, 0x49, 0x04, 0x01, 0x4A, 0x04, 0x80,
+ 0x61, 0x01, 0x03, 0x38, 0x0E, 0x06, 0x0F, 0x25, 0x25, 0x01, 0x10, 0x02,
+ 0x00, 0x06, 0x03, 0x47, 0x04, 0x01, 0x48, 0x04, 0x80, 0x4C, 0x01, 0x04,
+ 0x38, 0x0E, 0x06, 0x0E, 0x25, 0x25, 0x01, 0x20, 0x02, 0x00, 0x06, 0x03,
+ 0x47, 0x04, 0x01, 0x48, 0x04, 0x38, 0x01, 0x05, 0x38, 0x0E, 0x06, 0x0C,
+ 0x25, 0x25, 0x02, 0x00, 0x06, 0x03, 0x4B, 0x04, 0x01, 0x4C, 0x04, 0x26,
+ 0x26, 0x01, 0x09, 0x0F, 0x06, 0x02, 0x68, 0x28, 0x44, 0x25, 0x26, 0x01,
+ 0x01, 0x17, 0x01, 0x04, 0x0B, 0x01, 0x10, 0x08, 0x44, 0x01, 0x08, 0x17,
+ 0x01, 0x10, 0x44, 0x09, 0x02, 0x00, 0x06, 0x03, 0x45, 0x04, 0x01, 0x46,
+ 0x00, 0x25, 0x00, 0x00, 0x9A, 0x01, 0x0C, 0x11, 0x01, 0x02, 0x0F, 0x00,
+ 0x00, 0x9A, 0x01, 0x0C, 0x11, 0x26, 0x5B, 0x44, 0x01, 0x03, 0x0A, 0x17,
+ 0x00, 0x00, 0x9A, 0x01, 0x0C, 0x11, 0x01, 0x01, 0x0E, 0x00, 0x00, 0x9A,
+ 0x01, 0x0C, 0x11, 0x5A, 0x00, 0x00, 0x9A, 0x01, 0x81, 0x70, 0x17, 0x01,
+ 0x20, 0x0D, 0x00, 0x00, 0x1B, 0x01, 0x00, 0x75, 0x2E, 0x26, 0x06, 0x22,
+ 0x01, 0x01, 0x38, 0x0E, 0x06, 0x06, 0x25, 0x01, 0x00, 0x9E, 0x04, 0x14,
+ 0x01, 0x02, 0x38, 0x0E, 0x06, 0x0D, 0x25, 0x77, 0x2E, 0x01, 0x01, 0x0E,
+ 0x06, 0x03, 0x01, 0x10, 0x37, 0x04, 0x01, 0x25, 0x04, 0x01, 0x25, 0x7B,
+ 0x2E, 0x05, 0x33, 0x2F, 0x06, 0x30, 0x86, 0x2E, 0x01, 0x14, 0x38, 0x0E,
+ 0x06, 0x06, 0x25, 0x01, 0x02, 0x37, 0x04, 0x22, 0x01, 0x15, 0x38, 0x0E,
+ 0x06, 0x09, 0x25, 0xAD, 0x06, 0x03, 0x01, 0x7F, 0x9E, 0x04, 0x13, 0x01,
+ 0x16, 0x38, 0x0E, 0x06, 0x06, 0x25, 0x01, 0x01, 0x37, 0x04, 0x07, 0x25,
+ 0x01, 0x04, 0x37, 0x01, 0x00, 0x25, 0x1A, 0x06, 0x03, 0x01, 0x08, 0x37,
+ 0x00, 0x00, 0x1B, 0x26, 0x05, 0x13, 0x2F, 0x06, 0x10, 0x86, 0x2E, 0x01,
+ 0x15, 0x0E, 0x06, 0x08, 0x25, 0xAD, 0x01, 0x00, 0x77, 0x3E, 0x04, 0x01,
+ 0x20, 0x00, 0x00, 0xCE, 0x01, 0x07, 0x17, 0x01, 0x01, 0x0F, 0x06, 0x02,
+ 0x72, 0x28, 0x00, 0x01, 0x03, 0x00, 0x29, 0x1A, 0x06, 0x05, 0x02, 0x00,
+ 0x87, 0x3E, 0x00, 0xCE, 0x25, 0x04, 0x74, 0x00, 0x01, 0x14, 0xD1, 0x01,
+ 0x01, 0xDE, 0x29, 0x26, 0x01, 0x00, 0xC8, 0x01, 0x16, 0xD1, 0xD7, 0x29,
+ 0x00, 0x00, 0x01, 0x0B, 0xDE, 0x4E, 0x26, 0x26, 0x01, 0x03, 0x08, 0xDD,
+ 0xDD, 0x18, 0x26, 0x58, 0x06, 0x02, 0x25, 0x00, 0xDD, 0x1D, 0x26, 0x06,
+ 0x05, 0x84, 0x44, 0xD8, 0x04, 0x77, 0x25, 0x04, 0x6C, 0x00, 0x21, 0x01,
+ 0x0F, 0xDE, 0x26, 0x92, 0x2C, 0x01, 0x86, 0x03, 0x10, 0x06, 0x0C, 0x01,
+ 0x04, 0x08, 0xDD, 0x80, 0x2E, 0xDE, 0x78, 0x2E, 0xDE, 0x04, 0x02, 0x5E,
+ 0xDD, 0x26, 0xDC, 0x84, 0x44, 0xD8, 0x00, 0x02, 0xA4, 0xA6, 0x08, 0xA2,
+ 0x08, 0xA5, 0x08, 0xA7, 0x08, 0xA3, 0x08, 0x27, 0x08, 0x03, 0x00, 0x01,
+ 0x01, 0xDE, 0x01, 0x27, 0x8E, 0x2E, 0x08, 0x91, 0x2E, 0x01, 0x01, 0x0B,
+ 0x08, 0x02, 0x00, 0x06, 0x04, 0x5E, 0x02, 0x00, 0x08, 0x83, 0x2C, 0x38,
+ 0x09, 0x26, 0x5B, 0x06, 0x24, 0x02, 0x00, 0x05, 0x04, 0x44, 0x5E, 0x44,
+ 0x5F, 0x01, 0x04, 0x09, 0x26, 0x58, 0x06, 0x03, 0x25, 0x01, 0x00, 0x26,
+ 0x01, 0x04, 0x08, 0x02, 0x00, 0x08, 0x03, 0x00, 0x44, 0x01, 0x04, 0x08,
+ 0x38, 0x08, 0x44, 0x04, 0x03, 0x25, 0x01, 0x7F, 0x03, 0x01, 0xDD, 0x94,
+ 0x2C, 0xDC, 0x7A, 0x01, 0x04, 0x19, 0x7A, 0x01, 0x04, 0x08, 0x01, 0x1C,
+ 0x32, 0x7A, 0x01, 0x20, 0xD8, 0x8D, 0x8E, 0x2E, 0xDA, 0x91, 0x2E, 0x26,
+ 0x01, 0x01, 0x0B, 0xDC, 0x90, 0x44, 0x26, 0x06, 0x0F, 0x5D, 0x38, 0x2C,
+ 0x26, 0xC7, 0x05, 0x02, 0x62, 0x28, 0xDC, 0x44, 0x5E, 0x44, 0x04, 0x6E,
+ 0x60, 0x01, 0x01, 0xDE, 0x01, 0x00, 0xDE, 0x02, 0x00, 0x06, 0x81, 0x5A,
+ 0x02, 0x00, 0xDC, 0xA4, 0x06, 0x0E, 0x01, 0x83, 0xFE, 0x01, 0xDC, 0x89,
+ 0xA4, 0x01, 0x04, 0x09, 0x26, 0xDC, 0x5D, 0xDA, 0xA6, 0x06, 0x16, 0x01,
+ 0x00, 0xDC, 0x8B, 0xA6, 0x01, 0x04, 0x09, 0x26, 0xDC, 0x01, 0x02, 0x09,
+ 0x26, 0xDC, 0x01, 0x00, 0xDE, 0x01, 0x03, 0x09, 0xD9, 0xA2, 0x06, 0x0C,
+ 0x01, 0x01, 0xDC, 0x01, 0x01, 0xDC, 0x82, 0x2E, 0x01, 0x08, 0x09, 0xDE,
+ 0xA5, 0x06, 0x19, 0x01, 0x0D, 0xDC, 0xA5, 0x01, 0x04, 0x09, 0x26, 0xDC,
+ 0x01, 0x02, 0x09, 0xDC, 0x42, 0x06, 0x03, 0x01, 0x03, 0xDB, 0x43, 0x06,
+ 0x03, 0x01, 0x01, 0xDB, 0xA7, 0x26, 0x06, 0x36, 0x01, 0x0A, 0xDC, 0x01,
+ 0x04, 0x09, 0x26, 0xDC, 0x5F, 0xDC, 0x40, 0x01, 0x00, 0x26, 0x01, 0x82,
+ 0x80, 0x80, 0x80, 0x00, 0x17, 0x06, 0x0A, 0x01, 0xFD, 0xFF, 0xFF, 0xFF,
+ 0x7F, 0x17, 0x01, 0x1D, 0xDC, 0x26, 0x01, 0x20, 0x0A, 0x06, 0x0C, 0xA0,
+ 0x11, 0x01, 0x01, 0x17, 0x06, 0x02, 0x26, 0xDC, 0x5C, 0x04, 0x6E, 0x60,
+ 0x04, 0x01, 0x25, 0xA3, 0x06, 0x0A, 0x01, 0x0B, 0xDC, 0x01, 0x02, 0xDC,
+ 0x01, 0x82, 0x00, 0xDC, 0x27, 0x26, 0x06, 0x1F, 0x01, 0x10, 0xDC, 0x01,
+ 0x04, 0x09, 0x26, 0xDC, 0x5F, 0xDC, 0x85, 0x2C, 0x01, 0x00, 0xA0, 0x0F,
+ 0x06, 0x0A, 0x26, 0x1E, 0x26, 0xDE, 0x84, 0x44, 0xD8, 0x5C, 0x04, 0x72,
+ 0x60, 0x04, 0x01, 0x25, 0x02, 0x01, 0x58, 0x05, 0x11, 0x01, 0x15, 0xDC,
+ 0x02, 0x01, 0x26, 0xDC, 0x26, 0x06, 0x06, 0x5D, 0x01, 0x00, 0xDE, 0x04,
+ 0x77, 0x25, 0x00, 0x00, 0x01, 0x10, 0xDE, 0x79, 0x2C, 0x26, 0xCC, 0x06,
+ 0x0C, 0xAB, 0x23, 0x26, 0x5E, 0xDD, 0x26, 0xDC, 0x84, 0x44, 0xD8, 0x04,
+ 0x0D, 0x26, 0xCA, 0x44, 0xAB, 0x22, 0x26, 0x5C, 0xDD, 0x26, 0xDE, 0x84,
+ 0x44, 0xD8, 0x00, 0x00, 0x9C, 0x01, 0x14, 0xDE, 0x01, 0x0C, 0xDD, 0x84,
+ 0x01, 0x0C, 0xD8, 0x00, 0x00, 0x51, 0x26, 0x01, 0x00, 0x0E, 0x06, 0x02,
+ 0x60, 0x00, 0xCE, 0x25, 0x04, 0x73, 0x00, 0x26, 0xDC, 0xD8, 0x00, 0x00,
+ 0x26, 0xDE, 0xD8, 0x00, 0x01, 0x03, 0x00, 0x41, 0x25, 0x26, 0x01, 0x10,
+ 0x17, 0x06, 0x06, 0x01, 0x04, 0xDE, 0x02, 0x00, 0xDE, 0x26, 0x01, 0x08,
+ 0x17, 0x06, 0x06, 0x01, 0x03, 0xDE, 0x02, 0x00, 0xDE, 0x26, 0x01, 0x20,
+ 0x17, 0x06, 0x06, 0x01, 0x05, 0xDE, 0x02, 0x00, 0xDE, 0x26, 0x01, 0x80,
+ 0x40, 0x17, 0x06, 0x06, 0x01, 0x06, 0xDE, 0x02, 0x00, 0xDE, 0x01, 0x04,
+ 0x17, 0x06, 0x06, 0x01, 0x02, 0xDE, 0x02, 0x00, 0xDE, 0x00, 0x00, 0x26,
+ 0x01, 0x08, 0x4F, 0xDE, 0xDE, 0x00, 0x00, 0x26, 0x01, 0x10, 0x4F, 0xDE,
+ 0xDC, 0x00, 0x00, 0x26, 0x52, 0x06, 0x02, 0x25, 0x00, 0xCE, 0x25, 0x04,
+ 0x76
+};
+
+static const uint16_t t0_caddr[] = {
+ 0,
+ 5,
+ 10,
+ 15,
+ 20,
+ 25,
+ 30,
+ 35,
+ 40,
+ 44,
+ 48,
+ 52,
+ 56,
+ 60,
+ 64,
+ 68,
+ 72,
+ 76,
+ 80,
+ 84,
+ 88,
+ 92,
+ 96,
+ 100,
+ 104,
+ 108,
+ 112,
+ 116,
+ 120,
+ 124,
+ 129,
+ 134,
+ 139,
+ 144,
+ 149,
+ 154,
+ 159,
+ 164,
+ 169,
+ 174,
+ 179,
+ 184,
+ 189,
+ 194,
+ 199,
+ 204,
+ 209,
+ 214,
+ 219,
+ 224,
+ 229,
+ 234,
+ 239,
+ 244,
+ 249,
+ 254,
+ 259,
+ 264,
+ 269,
+ 274,
+ 279,
+ 284,
+ 289,
+ 294,
+ 303,
+ 316,
+ 320,
+ 345,
+ 351,
+ 370,
+ 381,
+ 422,
+ 542,
+ 546,
+ 611,
+ 626,
+ 637,
+ 655,
+ 684,
+ 694,
+ 730,
+ 740,
+ 818,
+ 832,
+ 838,
+ 897,
+ 916,
+ 951,
+ 1000,
+ 1076,
+ 1103,
+ 1134,
+ 1145,
+ 1497,
+ 1644,
+ 1668,
+ 1884,
+ 1898,
+ 1907,
+ 1911,
+ 2006,
+ 2027,
+ 2083,
+ 2090,
+ 2101,
+ 2117,
+ 2123,
+ 2134,
+ 2169,
+ 2181,
+ 2187,
+ 2202,
+ 2218,
+ 2411,
+ 2420,
+ 2433,
+ 2442,
+ 2449,
+ 2459,
+ 2565,
+ 2590,
+ 2603,
+ 2619,
+ 2637,
+ 2669,
+ 2703,
+ 3071,
+ 3107,
+ 3120,
+ 3134,
+ 3139,
+ 3144,
+ 3210,
+ 3218,
+ 3226
+};
+
+#define T0_INTERPRETED 88
+
+#define T0_ENTER(ip, rp, slot) do { \
+ const unsigned char *t0_newip; \
+ uint32_t t0_lnum; \
+ t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \
+ t0_lnum = t0_parse7E_unsigned(&t0_newip); \
+ (rp) += t0_lnum; \
+ *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \
+ (ip) = t0_newip; \
+ } while (0)
+
+#define T0_DEFENTRY(name, slot) \
+void \
+name(void *ctx) \
+{ \
+ t0_context *t0ctx = ctx; \
+ t0ctx->ip = &t0_codeblock[0]; \
+ T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
+}
+
+T0_DEFENTRY(br_ssl_hs_client_init_main, 169)
+
+#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++)
+
+void
+br_ssl_hs_client_run(void *t0ctx)
+{
+ uint32_t *dp, *rp;
+ const unsigned char *ip;
+
+#define T0_LOCAL(x) (*(rp - 2 - (x)))
+#define T0_POP() (*-- dp)
+#define T0_POPi() (*(int32_t *)(-- dp))
+#define T0_PEEK(x) (*(dp - 1 - (x)))
+#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x)))
+#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0)
+#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0)
+#define T0_RPOP() (*-- rp)
+#define T0_RPOPi() (*(int32_t *)(-- rp))
+#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0)
+#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0)
+#define T0_ROLL(x) do { \
+ size_t t0len = (size_t)(x); \
+ uint32_t t0tmp = *(dp - 1 - t0len); \
+ memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_SWAP() do { \
+ uint32_t t0tmp = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_ROT() do { \
+ uint32_t t0tmp = *(dp - 3); \
+ *(dp - 3) = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_NROT() do { \
+ uint32_t t0tmp = *(dp - 1); \
+ *(dp - 1) = *(dp - 2); \
+ *(dp - 2) = *(dp - 3); \
+ *(dp - 3) = t0tmp; \
+} while (0)
+#define T0_PICK(x) do { \
+ uint32_t t0depth = (x); \
+ T0_PUSH(T0_PEEK(t0depth)); \
+} while (0)
+#define T0_CO() do { \
+ goto t0_exit; \
+} while (0)
+#define T0_RET() goto t0_next
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ goto t0_next;
+ for (;;) {
+ uint32_t t0x;
+
+ t0_next:
+ t0x = T0_NEXT(&ip);
+ if (t0x < T0_INTERPRETED) {
+ switch (t0x) {
+ int32_t t0off;
+
+ case 0: /* ret */
+ t0x = T0_RPOP();
+ rp -= (t0x >> 16);
+ t0x &= 0xFFFF;
+ if (t0x == 0) {
+ ip = NULL;
+ goto t0_exit;
+ }
+ ip = &t0_codeblock[t0x];
+ break;
+ case 1: /* literal constant */
+ T0_PUSHi(t0_parse7E_signed(&ip));
+ break;
+ case 2: /* read local */
+ T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip)));
+ break;
+ case 3: /* write local */
+ T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP();
+ break;
+ case 4: /* jump */
+ t0off = t0_parse7E_signed(&ip);
+ ip += t0off;
+ break;
+ case 5: /* jump if */
+ t0off = t0_parse7E_signed(&ip);
+ if (T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 6: /* jump if not */
+ t0off = t0_parse7E_signed(&ip);
+ if (!T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 7: {
+ /* * */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a * b);
+
+ }
+ break;
+ case 8: {
+ /* + */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a + b);
+
+ }
+ break;
+ case 9: {
+ /* - */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a - b);
+
+ }
+ break;
+ case 10: {
+ /* < */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a < b));
+
+ }
+ break;
+ case 11: {
+ /* << */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x << c);
+
+ }
+ break;
+ case 12: {
+ /* <= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a <= b));
+
+ }
+ break;
+ case 13: {
+ /* <> */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a != b));
+
+ }
+ break;
+ case 14: {
+ /* = */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a == b));
+
+ }
+ break;
+ case 15: {
+ /* > */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a > b));
+
+ }
+ break;
+ case 16: {
+ /* >= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a >= b));
+
+ }
+ break;
+ case 17: {
+ /* >> */
+
+ int c = (int)T0_POPi();
+ int32_t x = T0_POPi();
+ T0_PUSHi(x >> c);
+
+ }
+ break;
+ case 18: {
+ /* anchor-dn-append-name */
+
+ size_t len;
+
+ len = T0_POP();
+ if (CTX->client_auth_vtable != NULL) {
+ (*CTX->client_auth_vtable)->append_name(
+ CTX->client_auth_vtable, ENG->pad, len);
+ }
+
+ }
+ break;
+ case 19: {
+ /* anchor-dn-end-name */
+
+ if (CTX->client_auth_vtable != NULL) {
+ (*CTX->client_auth_vtable)->end_name(
+ CTX->client_auth_vtable);
+ }
+
+ }
+ break;
+ case 20: {
+ /* anchor-dn-end-name-list */
+
+ if (CTX->client_auth_vtable != NULL) {
+ (*CTX->client_auth_vtable)->end_name_list(
+ CTX->client_auth_vtable);
+ }
+
+ }
+ break;
+ case 21: {
+ /* anchor-dn-start-name */
+
+ size_t len;
+
+ len = T0_POP();
+ if (CTX->client_auth_vtable != NULL) {
+ (*CTX->client_auth_vtable)->start_name(
+ CTX->client_auth_vtable, len);
+ }
+
+ }
+ break;
+ case 22: {
+ /* anchor-dn-start-name-list */
+
+ if (CTX->client_auth_vtable != NULL) {
+ (*CTX->client_auth_vtable)->start_name_list(
+ CTX->client_auth_vtable);
+ }
+
+ }
+ break;
+ case 23: {
+ /* and */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a & b);
+
+ }
+ break;
+ case 24: {
+ /* begin-cert */
+
+ if (ENG->chain_len == 0) {
+ T0_PUSHi(-1);
+ } else {
+ ENG->cert_cur = ENG->chain->data;
+ ENG->cert_len = ENG->chain->data_len;
+ ENG->chain ++;
+ ENG->chain_len --;
+ T0_PUSH(ENG->cert_len);
+ }
+
+ }
+ break;
+ case 25: {
+ /* bzero */
+
+ size_t len = (size_t)T0_POP();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ memset(addr, 0, len);
+
+ }
+ break;
+ case 26: {
+ /* can-output? */
+
+ T0_PUSHi(-(ENG->hlen_out > 0));
+
+ }
+ break;
+ case 27: {
+ /* co */
+ T0_CO();
+ }
+ break;
+ case 28: {
+ /* compute-Finished-inner */
+
+ int prf_id = T0_POP();
+ int from_client = T0_POPi();
+ unsigned char tmp[48];
+ br_tls_prf_seed_chunk seed;
+
+ br_tls_prf_impl prf = br_ssl_engine_get_PRF(ENG, prf_id);
+ seed.data = tmp;
+ if (ENG->session.version >= BR_TLS12) {
+ seed.len = br_multihash_out(&ENG->mhash, prf_id, tmp);
+ } else {
+ br_multihash_out(&ENG->mhash, br_md5_ID, tmp);
+ br_multihash_out(&ENG->mhash, br_sha1_ID, tmp + 16);
+ seed.len = 36;
+ }
+ prf(ENG->pad, 12, ENG->session.master_secret,
+ sizeof ENG->session.master_secret,
+ from_client ? "client finished" : "server finished",
+ 1, &seed);
+
+ }
+ break;
+ case 29: {
+ /* copy-cert-chunk */
+
+ size_t clen;
+
+ clen = ENG->cert_len;
+ if (clen > sizeof ENG->pad) {
+ clen = sizeof ENG->pad;
+ }
+ memcpy(ENG->pad, ENG->cert_cur, clen);
+ ENG->cert_cur += clen;
+ ENG->cert_len -= clen;
+ T0_PUSH(clen);
+
+ }
+ break;
+ case 30: {
+ /* copy-protocol-name */
+
+ size_t idx = T0_POP();
+ size_t len = strlen(ENG->protocol_names[idx]);
+ memcpy(ENG->pad, ENG->protocol_names[idx], len);
+ T0_PUSH(len);
+
+ }
+ break;
+ case 31: {
+ /* data-get8 */
+
+ size_t addr = T0_POP();
+ T0_PUSH(t0_datablock[addr]);
+
+ }
+ break;
+ case 32: {
+ /* discard-input */
+
+ ENG->hlen_in = 0;
+
+ }
+ break;
+ case 33: {
+ /* do-client-sign */
+
+ size_t sig_len;
+
+ sig_len = make_client_sign(CTX);
+ if (sig_len == 0) {
+ br_ssl_engine_fail(ENG, BR_ERR_INVALID_ALGORITHM);
+ T0_CO();
+ }
+ T0_PUSH(sig_len);
+
+ }
+ break;
+ case 34: {
+ /* do-ecdh */
+
+ unsigned prf_id = T0_POP();
+ unsigned ecdhe = T0_POP();
+ int x;
+
+ x = make_pms_ecdh(CTX, ecdhe, prf_id);
+ if (x < 0) {
+ br_ssl_engine_fail(ENG, -x);
+ T0_CO();
+ } else {
+ T0_PUSH(x);
+ }
+
+ }
+ break;
+ case 35: {
+ /* do-rsa-encrypt */
+
+ int x;
+
+ x = make_pms_rsa(CTX, T0_POP());
+ if (x < 0) {
+ br_ssl_engine_fail(ENG, -x);
+ T0_CO();
+ } else {
+ T0_PUSH(x);
+ }
+
+ }
+ break;
+ case 36: {
+ /* do-static-ecdh */
+
+ unsigned prf_id = T0_POP();
+
+ if (make_pms_static_ecdh(CTX, prf_id) < 0) {
+ br_ssl_engine_fail(ENG, BR_ERR_INVALID_ALGORITHM);
+ T0_CO();
+ }
+
+ }
+ break;
+ case 37: {
+ /* drop */
+ (void)T0_POP();
+ }
+ break;
+ case 38: {
+ /* dup */
+ T0_PUSH(T0_PEEK(0));
+ }
+ break;
+ case 39: {
+ /* ext-ALPN-length */
+
+ size_t u, len;
+
+ if (ENG->protocol_names_num == 0) {
+ T0_PUSH(0);
+ T0_RET();
+ }
+ len = 6;
+ for (u = 0; u < ENG->protocol_names_num; u ++) {
+ len += 1 + strlen(ENG->protocol_names[u]);
+ }
+ T0_PUSH(len);
+
+ }
+ break;
+ case 40: {
+ /* fail */
+
+ br_ssl_engine_fail(ENG, (int)T0_POPi());
+ T0_CO();
+
+ }
+ break;
+ case 41: {
+ /* flush-record */
+
+ br_ssl_engine_flush_record(ENG);
+
+ }
+ break;
+ case 42: {
+ /* get-client-chain */
+
+ uint32_t auth_types;
+
+ auth_types = T0_POP();
+ if (CTX->client_auth_vtable != NULL) {
+ br_ssl_client_certificate ux;
+
+ (*CTX->client_auth_vtable)->choose(CTX->client_auth_vtable,
+ CTX, auth_types, &ux);
+ CTX->auth_type = (unsigned char)ux.auth_type;
+ CTX->hash_id = (unsigned char)ux.hash_id;
+ ENG->chain = ux.chain;
+ ENG->chain_len = ux.chain_len;
+ } else {
+ CTX->hash_id = 0;
+ ENG->chain_len = 0;
+ }
+
+ }
+ break;
+ case 43: {
+ /* get-key-type-usages */
+
+ const br_x509_class *xc;
+ const br_x509_pkey *pk;
+ unsigned usages;
+
+ xc = *(ENG->x509ctx);
+ pk = xc->get_pkey(ENG->x509ctx, &usages);
+ if (pk == NULL) {
+ T0_PUSH(0);
+ } else {
+ T0_PUSH(pk->key_type | usages);
+ }
+
+ }
+ break;
+ case 44: {
+ /* get16 */
+
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*(uint16_t *)(void *)((unsigned char *)ENG + addr));
+
+ }
+ break;
+ case 45: {
+ /* get32 */
+
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*(uint32_t *)(void *)((unsigned char *)ENG + addr));
+
+ }
+ break;
+ case 46: {
+ /* get8 */
+
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*((unsigned char *)ENG + addr));
+
+ }
+ break;
+ case 47: {
+ /* has-input? */
+
+ T0_PUSHi(-(ENG->hlen_in != 0));
+
+ }
+ break;
+ case 48: {
+ /* memcmp */
+
+ size_t len = (size_t)T0_POP();
+ void *addr2 = (unsigned char *)ENG + (size_t)T0_POP();
+ void *addr1 = (unsigned char *)ENG + (size_t)T0_POP();
+ int x = memcmp(addr1, addr2, len);
+ T0_PUSH((uint32_t)-(x == 0));
+
+ }
+ break;
+ case 49: {
+ /* memcpy */
+
+ size_t len = (size_t)T0_POP();
+ void *src = (unsigned char *)ENG + (size_t)T0_POP();
+ void *dst = (unsigned char *)ENG + (size_t)T0_POP();
+ memcpy(dst, src, len);
+
+ }
+ break;
+ case 50: {
+ /* mkrand */
+
+ size_t len = (size_t)T0_POP();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ br_hmac_drbg_generate(&ENG->rng, addr, len);
+
+ }
+ break;
+ case 51: {
+ /* more-incoming-bytes? */
+
+ T0_PUSHi(ENG->hlen_in != 0 || !br_ssl_engine_recvrec_finished(ENG));
+
+ }
+ break;
+ case 52: {
+ /* multihash-init */
+
+ br_multihash_init(&ENG->mhash);
+
+ }
+ break;
+ case 53: {
+ /* neg */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(-a);
+
+ }
+ break;
+ case 54: {
+ /* not */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(~a);
+
+ }
+ break;
+ case 55: {
+ /* or */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a | b);
+
+ }
+ break;
+ case 56: {
+ /* over */
+ T0_PUSH(T0_PEEK(1));
+ }
+ break;
+ case 57: {
+ /* read-chunk-native */
+
+ size_t clen = ENG->hlen_in;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy((unsigned char *)ENG + addr, ENG->hbuf_in, clen);
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_in, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_in += clen;
+ ENG->hlen_in -= clen;
+ }
+
+ }
+ break;
+ case 58: {
+ /* read8-native */
+
+ if (ENG->hlen_in > 0) {
+ unsigned char x;
+
+ x = *ENG->hbuf_in ++;
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ T0_PUSH(x);
+ ENG->hlen_in --;
+ } else {
+ T0_PUSHi(-1);
+ }
+
+ }
+ break;
+ case 59: {
+ /* set-server-curve */
+
+ const br_x509_class *xc;
+ const br_x509_pkey *pk;
+
+ xc = *(ENG->x509ctx);
+ pk = xc->get_pkey(ENG->x509ctx, NULL);
+ CTX->server_curve =
+ (pk->key_type == BR_KEYTYPE_EC) ? pk->key.ec.curve : 0;
+
+ }
+ break;
+ case 60: {
+ /* set16 */
+
+ size_t addr = (size_t)T0_POP();
+ *(uint16_t *)(void *)((unsigned char *)ENG + addr) = (uint16_t)T0_POP();
+
+ }
+ break;
+ case 61: {
+ /* set32 */
+
+ size_t addr = (size_t)T0_POP();
+ *(uint32_t *)(void *)((unsigned char *)ENG + addr) = (uint32_t)T0_POP();
+
+ }
+ break;
+ case 62: {
+ /* set8 */
+
+ size_t addr = (size_t)T0_POP();
+ *((unsigned char *)ENG + addr) = (unsigned char)T0_POP();
+
+ }
+ break;
+ case 63: {
+ /* strlen */
+
+ void *str = (unsigned char *)ENG + (size_t)T0_POP();
+ T0_PUSH((uint32_t)strlen(str));
+
+ }
+ break;
+ case 64: {
+ /* supported-curves */
+
+ uint32_t x = ENG->iec == NULL ? 0 : ENG->iec->supported_curves;
+ T0_PUSH(x);
+
+ }
+ break;
+ case 65: {
+ /* supported-hash-functions */
+
+ int i;
+ unsigned x, num;
+
+ x = 0;
+ num = 0;
+ for (i = br_sha1_ID; i <= br_sha512_ID; i ++) {
+ if (br_multihash_getimpl(&ENG->mhash, i)) {
+ x |= 1U << i;
+ num ++;
+ }
+ }
+ T0_PUSH(x);
+ T0_PUSH(num);
+
+ }
+ break;
+ case 66: {
+ /* supports-ecdsa? */
+
+ T0_PUSHi(-(ENG->iecdsa != 0));
+
+ }
+ break;
+ case 67: {
+ /* supports-rsa-sign? */
+
+ T0_PUSHi(-(ENG->irsavrfy != 0));
+
+ }
+ break;
+ case 68: {
+ /* swap */
+ T0_SWAP();
+ }
+ break;
+ case 69: {
+ /* switch-aesccm-in */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len, tag_len;
+
+ tag_len = T0_POP();
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_ccm_in(ENG, is_client, prf_id,
+ ENG->iaes_ctrcbc, cipher_key_len, tag_len);
+
+ }
+ break;
+ case 70: {
+ /* switch-aesccm-out */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len, tag_len;
+
+ tag_len = T0_POP();
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_ccm_out(ENG, is_client, prf_id,
+ ENG->iaes_ctrcbc, cipher_key_len, tag_len);
+
+ }
+ break;
+ case 71: {
+ /* switch-aesgcm-in */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_in(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+
+ }
+ break;
+ case 72: {
+ /* switch-aesgcm-out */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_out(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+
+ }
+ break;
+ case 73: {
+ /* switch-cbc-in */
+
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_in(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcdec : ENG->ides_cbcdec, cipher_key_len);
+
+ }
+ break;
+ case 74: {
+ /* switch-cbc-out */
+
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_out(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcenc : ENG->ides_cbcenc, cipher_key_len);
+
+ }
+ break;
+ case 75: {
+ /* switch-chapol-in */
+
+ int is_client, prf_id;
+
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_chapol_in(ENG, is_client, prf_id);
+
+ }
+ break;
+ case 76: {
+ /* switch-chapol-out */
+
+ int is_client, prf_id;
+
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_chapol_out(ENG, is_client, prf_id);
+
+ }
+ break;
+ case 77: {
+ /* test-protocol-name */
+
+ size_t len = T0_POP();
+ size_t u;
+
+ for (u = 0; u < ENG->protocol_names_num; u ++) {
+ const char *name;
+
+ name = ENG->protocol_names[u];
+ if (len == strlen(name) && memcmp(ENG->pad, name, len) == 0) {
+ T0_PUSH(u);
+ T0_RET();
+ }
+ }
+ T0_PUSHi(-1);
+
+ }
+ break;
+ case 78: {
+ /* total-chain-length */
+
+ size_t u;
+ uint32_t total;
+
+ total = 0;
+ for (u = 0; u < ENG->chain_len; u ++) {
+ total += 3 + (uint32_t)ENG->chain[u].data_len;
+ }
+ T0_PUSH(total);
+
+ }
+ break;
+ case 79: {
+ /* u>> */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x >> c);
+
+ }
+ break;
+ case 80: {
+ /* verify-SKE-sig */
+
+ size_t sig_len = T0_POP();
+ int use_rsa = T0_POPi();
+ int hash = T0_POPi();
+
+ T0_PUSH(verify_SKE_sig(CTX, hash, use_rsa, sig_len));
+
+ }
+ break;
+ case 81: {
+ /* write-blob-chunk */
+
+ size_t clen = ENG->hlen_out;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy(ENG->hbuf_out, (unsigned char *)ENG + addr, clen);
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_out, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_out += clen;
+ ENG->hlen_out -= clen;
+ }
+
+ }
+ break;
+ case 82: {
+ /* write8-native */
+
+ unsigned char x;
+
+ x = (unsigned char)T0_POP();
+ if (ENG->hlen_out > 0) {
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ *ENG->hbuf_out ++ = x;
+ ENG->hlen_out --;
+ T0_PUSHi(-1);
+ } else {
+ T0_PUSHi(0);
+ }
+
+ }
+ break;
+ case 83: {
+ /* x509-append */
+
+ const br_x509_class *xc;
+ size_t len;
+
+ xc = *(ENG->x509ctx);
+ len = T0_POP();
+ xc->append(ENG->x509ctx, ENG->pad, len);
+
+ }
+ break;
+ case 84: {
+ /* x509-end-cert */
+
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ xc->end_cert(ENG->x509ctx);
+
+ }
+ break;
+ case 85: {
+ /* x509-end-chain */
+
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ T0_PUSH(xc->end_chain(ENG->x509ctx));
+
+ }
+ break;
+ case 86: {
+ /* x509-start-cert */
+
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ xc->start_cert(ENG->x509ctx, T0_POP());
+
+ }
+ break;
+ case 87: {
+ /* x509-start-chain */
+
+ const br_x509_class *xc;
+ uint32_t bc;
+
+ bc = T0_POP();
+ xc = *(ENG->x509ctx);
+ xc->start_chain(ENG->x509ctx, bc ? ENG->server_name : NULL);
+
+ }
+ break;
+ }
+
+ } else {
+ T0_ENTER(ip, rp, t0x);
+ }
+ }
+t0_exit:
+ ((t0_context *)t0ctx)->dp = dp;
+ ((t0_context *)t0ctx)->rp = rp;
+ ((t0_context *)t0ctx)->ip = ip;
+}
diff --git a/contrib/bearssl/src/ssl/ssl_hs_client.t0 b/contrib/bearssl/src/ssl/ssl_hs_client.t0
new file mode 100644
index 000000000000..23b39e719856
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_hs_client.t0
@@ -0,0 +1,1276 @@
+\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+\
+\ Permission is hereby granted, free of charge, to any person obtaining
+\ a copy of this software and associated documentation files (the
+\ "Software"), to deal in the Software without restriction, including
+\ without limitation the rights to use, copy, modify, merge, publish,
+\ distribute, sublicense, and/or sell copies of the Software, and to
+\ permit persons to whom the Software is furnished to do so, subject to
+\ the following conditions:
+\
+\ The above copyright notice and this permission notice shall be
+\ included in all copies or substantial portions of the Software.
+\
+\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+\ SOFTWARE.
+
+\ ----------------------------------------------------------------------
+\ Handshake processing code, for the client.
+\ The common T0 code (ssl_hs_common.t0) shall be read first.
+
+preamble {
+
+/*
+ * This macro evaluates to a pointer to the client context, under that
+ * specific name. It must be noted that since the engine context is the
+ * first field of the br_ssl_client_context structure ('eng'), then
+ * pointers values of both types are interchangeable, modulo an
+ * appropriate cast. This also means that "addresses" computed as offsets
+ * within the structure work for both kinds of context.
+ */
+#define CTX ((br_ssl_client_context *)ENG)
+
+/*
+ * Generate the pre-master secret for RSA key exchange, and encrypt it
+ * with the server's public key. Returned value is either the encrypted
+ * data length (in bytes), or -x on error, with 'x' being an error code.
+ *
+ * This code assumes that the public key has been already verified (it
+ * was properly obtained by the X.509 engine, and it has the right type,
+ * i.e. it is of type RSA and suitable for encryption).
+ */
+static int
+make_pms_rsa(br_ssl_client_context *ctx, int prf_id)
+{
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+ const unsigned char *n;
+ unsigned char *pms;
+ size_t nlen, u;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+
+ /*
+ * Compute actual RSA key length, in case there are leading zeros.
+ */
+ n = pk->key.rsa.n;
+ nlen = pk->key.rsa.nlen;
+ while (nlen > 0 && *n == 0) {
+ n ++;
+ nlen --;
+ }
+
+ /*
+ * We need at least 59 bytes (48 bytes for pre-master secret, and
+ * 11 bytes for the PKCS#1 type 2 padding). Note that the X.509
+ * minimal engine normally blocks RSA keys shorter than 128 bytes,
+ * so this is mostly for public keys provided explicitly by the
+ * caller.
+ */
+ if (nlen < 59) {
+ return -BR_ERR_X509_WEAK_PUBLIC_KEY;
+ }
+ if (nlen > sizeof ctx->eng.pad) {
+ return -BR_ERR_LIMIT_EXCEEDED;
+ }
+
+ /*
+ * Make PMS.
+ */
+ pms = ctx->eng.pad + nlen - 48;
+ br_enc16be(pms, ctx->eng.version_max);
+ br_hmac_drbg_generate(&ctx->eng.rng, pms + 2, 46);
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, pms, 48);
+
+ /*
+ * Apply PKCS#1 type 2 padding.
+ */
+ ctx->eng.pad[0] = 0x00;
+ ctx->eng.pad[1] = 0x02;
+ ctx->eng.pad[nlen - 49] = 0x00;
+ br_hmac_drbg_generate(&ctx->eng.rng, ctx->eng.pad + 2, nlen - 51);
+ for (u = 2; u < nlen - 49; u ++) {
+ while (ctx->eng.pad[u] == 0) {
+ br_hmac_drbg_generate(&ctx->eng.rng,
+ &ctx->eng.pad[u], 1);
+ }
+ }
+
+ /*
+ * Compute RSA encryption.
+ */
+ if (!ctx->irsapub(ctx->eng.pad, nlen, &pk->key.rsa)) {
+ return -BR_ERR_LIMIT_EXCEEDED;
+ }
+ return (int)nlen;
+}
+
+/*
+ * OID for hash functions in RSA signatures.
+ */
+static const unsigned char *HASH_OID[] = {
+ BR_HASH_OID_SHA1,
+ BR_HASH_OID_SHA224,
+ BR_HASH_OID_SHA256,
+ BR_HASH_OID_SHA384,
+ BR_HASH_OID_SHA512
+};
+
+/*
+ * Check the RSA signature on the ServerKeyExchange message.
+ *
+ * hash hash function ID (2 to 6), or 0 for MD5+SHA-1 (with RSA only)
+ * use_rsa non-zero for RSA signature, zero for ECDSA
+ * sig_len signature length (in bytes); signature value is in the pad
+ *
+ * Returned value is 0 on success, or an error code.
+ */
+static int
+verify_SKE_sig(br_ssl_client_context *ctx,
+ int hash, int use_rsa, size_t sig_len)
+{
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+ br_multihash_context mhc;
+ unsigned char hv[64], head[4];
+ size_t hv_len;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+ br_multihash_zero(&mhc);
+ br_multihash_copyimpl(&mhc, &ctx->eng.mhash);
+ br_multihash_init(&mhc);
+ br_multihash_update(&mhc,
+ ctx->eng.client_random, sizeof ctx->eng.client_random);
+ br_multihash_update(&mhc,
+ ctx->eng.server_random, sizeof ctx->eng.server_random);
+ head[0] = 3;
+ head[1] = 0;
+ head[2] = ctx->eng.ecdhe_curve;
+ head[3] = ctx->eng.ecdhe_point_len;
+ br_multihash_update(&mhc, head, sizeof head);
+ br_multihash_update(&mhc,
+ ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len);
+ if (hash) {
+ hv_len = br_multihash_out(&mhc, hash, hv);
+ if (hv_len == 0) {
+ return BR_ERR_INVALID_ALGORITHM;
+ }
+ } else {
+ if (!br_multihash_out(&mhc, br_md5_ID, hv)
+ || !br_multihash_out(&mhc, br_sha1_ID, hv + 16))
+ {
+ return BR_ERR_INVALID_ALGORITHM;
+ }
+ hv_len = 36;
+ }
+ if (use_rsa) {
+ unsigned char tmp[64];
+ const unsigned char *hash_oid;
+
+ if (hash) {
+ hash_oid = HASH_OID[hash - 2];
+ } else {
+ hash_oid = NULL;
+ }
+ if (!ctx->eng.irsavrfy(ctx->eng.pad, sig_len,
+ hash_oid, hv_len, &pk->key.rsa, tmp)
+ || memcmp(tmp, hv, hv_len) != 0)
+ {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ } else {
+ if (!ctx->eng.iecdsa(ctx->eng.iec, hv, hv_len, &pk->key.ec,
+ ctx->eng.pad, sig_len))
+ {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ }
+ return 0;
+}
+
+/*
+ * Perform client-side ECDH (or ECDHE). The point that should be sent to
+ * the server is written in the pad; returned value is either the point
+ * length (in bytes), or -x on error, with 'x' being an error code.
+ *
+ * The point _from_ the server is taken from ecdhe_point[] if 'ecdhe'
+ * is non-zero, or from the X.509 engine context if 'ecdhe' is zero
+ * (for static ECDH).
+ */
+static int
+make_pms_ecdh(br_ssl_client_context *ctx, unsigned ecdhe, int prf_id)
+{
+ int curve;
+ unsigned char key[66], point[133];
+ const unsigned char *order, *point_src;
+ size_t glen, olen, point_len, xoff, xlen;
+ unsigned char mask;
+
+ if (ecdhe) {
+ curve = ctx->eng.ecdhe_curve;
+ point_src = ctx->eng.ecdhe_point;
+ point_len = ctx->eng.ecdhe_point_len;
+ } else {
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+ curve = pk->key.ec.curve;
+ point_src = pk->key.ec.q;
+ point_len = pk->key.ec.qlen;
+ }
+ if ((ctx->eng.iec->supported_curves & ((uint32_t)1 << curve)) == 0) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ /*
+ * We need to generate our key, as a non-zero random value which
+ * is lower than the curve order, in a "large enough" range. We
+ * force top bit to 0 and bottom bit to 1, which guarantees that
+ * the value is in the proper range.
+ */
+ order = ctx->eng.iec->order(curve, &olen);
+ mask = 0xFF;
+ while (mask >= order[0]) {
+ mask >>= 1;
+ }
+ br_hmac_drbg_generate(&ctx->eng.rng, key, olen);
+ key[0] &= mask;
+ key[olen - 1] |= 0x01;
+
+ /*
+ * Compute the common ECDH point, whose X coordinate is the
+ * pre-master secret.
+ */
+ ctx->eng.iec->generator(curve, &glen);
+ if (glen != point_len) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ memcpy(point, point_src, glen);
+ if (!ctx->eng.iec->mul(point, glen, key, olen, curve)) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+
+ /*
+ * The pre-master secret is the X coordinate.
+ */
+ xoff = ctx->eng.iec->xoff(curve, &xlen);
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, point + xoff, xlen);
+
+ ctx->eng.iec->mulgen(point, key, olen, curve);
+ memcpy(ctx->eng.pad, point, glen);
+ return (int)glen;
+}
+
+/*
+ * Perform full static ECDH. This occurs only in the context of client
+ * authentication with certificates: the server uses an EC public key,
+ * the cipher suite is of type ECDH (not ECDHE), the server requested a
+ * client certificate and accepts static ECDH, the client has a
+ * certificate with an EC public key in the same curve, and accepts
+ * static ECDH as well.
+ *
+ * Returned value is 0 on success, -1 on error.
+ */
+static int
+make_pms_static_ecdh(br_ssl_client_context *ctx, int prf_id)
+{
+ unsigned char point[133];
+ size_t point_len;
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+ point_len = pk->key.ec.qlen;
+ if (point_len > sizeof point) {
+ return -1;
+ }
+ memcpy(point, pk->key.ec.q, point_len);
+ if (!(*ctx->client_auth_vtable)->do_keyx(
+ ctx->client_auth_vtable, point, &point_len))
+ {
+ return -1;
+ }
+ br_ssl_engine_compute_master(&ctx->eng,
+ prf_id, point, point_len);
+ return 0;
+}
+
+/*
+ * Compute the client-side signature. This is invoked only when a
+ * signature-based client authentication was selected. The computed
+ * signature is in the pad; its length (in bytes) is returned. On
+ * error, 0 is returned.
+ */
+static size_t
+make_client_sign(br_ssl_client_context *ctx)
+{
+ size_t hv_len;
+
+ /*
+ * Compute hash of handshake messages so far. This "cannot" fail
+ * because the list of supported hash functions provided to the
+ * client certificate handler was trimmed to include only the
+ * hash functions that the multi-hasher supports.
+ */
+ if (ctx->hash_id) {
+ hv_len = br_multihash_out(&ctx->eng.mhash,
+ ctx->hash_id, ctx->eng.pad);
+ } else {
+ br_multihash_out(&ctx->eng.mhash,
+ br_md5_ID, ctx->eng.pad);
+ br_multihash_out(&ctx->eng.mhash,
+ br_sha1_ID, ctx->eng.pad + 16);
+ hv_len = 36;
+ }
+ return (*ctx->client_auth_vtable)->do_sign(
+ ctx->client_auth_vtable, ctx->hash_id, hv_len,
+ ctx->eng.pad, sizeof ctx->eng.pad);
+}
+
+}
+
+\ =======================================================================
+
+: addr-ctx:
+ next-word { field }
+ "addr-" field + 0 1 define-word
+ 0 8191 "offsetof(br_ssl_client_context, " field + ")" + make-CX
+ postpone literal postpone ; ;
+
+addr-ctx: min_clienthello_len
+addr-ctx: hashes
+addr-ctx: auth_type
+addr-ctx: hash_id
+
+\ Length of the Secure Renegotiation extension. This is 5 for the
+\ first handshake, 17 for a renegotiation (if the server supports the
+\ extension), or 0 if we know that the server does not support the
+\ extension.
+: ext-reneg-length ( -- n )
+ addr-reneg get8 dup if 1 - 17 * else drop 5 then ;
+
+\ Length of SNI extension.
+: ext-sni-length ( -- len )
+ addr-server_name strlen dup if 9 + then ;
+
+\ Length of Maximum Fragment Length extension.
+: ext-frag-length ( -- len )
+ addr-log_max_frag_len get8 14 = if 0 else 5 then ;
+
+\ Length of Signatures extension.
+: ext-signatures-length ( -- len )
+ supported-hash-functions { num } drop 0
+ supports-rsa-sign? if num + then
+ supports-ecdsa? if num + then
+ dup if 1 << 6 + then ;
+
+\ Write supported hash functions ( sign -- )
+: write-hashes
+ { sign }
+ supported-hash-functions drop
+ \ We advertise hash functions in the following preference order:
+ \ SHA-256 SHA-224 SHA-384 SHA-512 SHA-1
+ \ Rationale:
+ \ -- SHA-256 and SHA-224 are more efficient on 32-bit architectures
+ \ -- SHA-1 is less than ideally collision-resistant
+ dup 0x10 and if 4 write8 sign write8 then
+ dup 0x08 and if 3 write8 sign write8 then
+ dup 0x20 and if 5 write8 sign write8 then
+ dup 0x40 and if 6 write8 sign write8 then
+ 0x04 and if 2 write8 sign write8 then ;
+
+\ Length of Supported Curves extension.
+: ext-supported-curves-length ( -- len )
+ supported-curves dup if
+ 0 { x }
+ begin dup while
+ dup 1 and x + >x
+ 1 >>
+ repeat
+ drop x 1 << 6 +
+ then ;
+
+\ Length of Supported Point Formats extension.
+: ext-point-format-length ( -- len )
+ supported-curves if 6 else 0 then ;
+
+\ Length of ALPN extension.
+cc: ext-ALPN-length ( -- len ) {
+ size_t u, len;
+
+ if (ENG->protocol_names_num == 0) {
+ T0_PUSH(0);
+ T0_RET();
+ }
+ len = 6;
+ for (u = 0; u < ENG->protocol_names_num; u ++) {
+ len += 1 + strlen(ENG->protocol_names[u]);
+ }
+ T0_PUSH(len);
+}
+
+\ Write handshake message: ClientHello
+: write-ClientHello ( -- )
+ { ; total-ext-length }
+
+ \ Compute length for extensions (without the general two-byte header).
+ \ This does not take padding extension into account.
+ ext-reneg-length ext-sni-length + ext-frag-length +
+ ext-signatures-length +
+ ext-supported-curves-length + ext-point-format-length +
+ ext-ALPN-length +
+ >total-ext-length
+
+ \ ClientHello type
+ 1 write8
+
+ \ Compute and write length
+ 39 addr-session_id_len get8 + addr-suites_num get8 1 << +
+ total-ext-length if 2+ total-ext-length + then
+ \ Compute padding (if requested).
+ addr-min_clienthello_len get16 over - dup 0> if
+ \ We well add a Pad ClientHello extension, which has its
+ \ own header (4 bytes) and might be the only extension
+ \ (2 extra bytes for the extension list header).
+ total-ext-length ifnot swap 2+ swap 2- then
+ \ Account for the extension header.
+ 4 - dup 0< if drop 0 then
+ \ Adjust total extension length.
+ dup 4 + total-ext-length + >total-ext-length
+ \ Adjust ClientHello length.
+ swap 4 + over + swap
+ else
+ drop
+ -1
+ then
+ { ext-padding-amount }
+ write24
+
+ \ Protocol version
+ addr-version_max get16 write16
+
+ \ Client random
+ addr-client_random 4 bzero
+ addr-client_random 4 + 28 mkrand
+ addr-client_random 32 write-blob
+
+ \ Session ID
+ addr-session_id addr-session_id_len get8 write-blob-head8
+
+ \ Supported cipher suites. We also check here that we indeed
+ \ support all these suites.
+ addr-suites_num get8 dup 1 << write16
+ addr-suites_buf swap
+ begin
+ dup while 1-
+ over get16
+ dup suite-supported? ifnot ERR_BAD_CIPHER_SUITE fail then
+ write16
+ swap 2+ swap
+ repeat
+ 2drop
+
+ \ Compression methods (only "null" compression)
+ 1 write8 0 write8
+
+ \ Extensions
+ total-ext-length if
+ total-ext-length write16
+ ext-reneg-length if
+ 0xFF01 write16 \ extension type (0xFF01)
+ addr-saved_finished
+ ext-reneg-length 4 - dup write16 \ extension length
+ 1- write-blob-head8 \ verify data
+ then
+ ext-sni-length if
+ 0x0000 write16 \ extension type (0)
+ addr-server_name
+ ext-sni-length 4 - dup write16 \ extension length
+ 2 - dup write16 \ ServerNameList length
+ 0 write8 \ name type: host_name
+ 3 - write-blob-head16 \ the name itself
+ then
+ ext-frag-length if
+ 0x0001 write16 \ extension type (1)
+ 0x0001 write16 \ extension length
+ addr-log_max_frag_len get8 8 - write8
+ then
+ ext-signatures-length if
+ 0x000D write16 \ extension type (13)
+ ext-signatures-length 4 - dup write16 \ extension length
+ 2 - write16 \ list length
+ supports-ecdsa? if 3 write-hashes then
+ supports-rsa-sign? if 1 write-hashes then
+ then
+ \ TODO: add an API to specify preference order for curves.
+ \ Right now we send Curve25519 first, then other curves in
+ \ increasing ID values (hence P-256 in second).
+ ext-supported-curves-length dup if
+ 0x000A write16 \ extension type (10)
+ 4 - dup write16 \ extension length
+ 2- write16 \ list length
+ supported-curves 0
+ dup 0x20000000 and if
+ 0xDFFFFFFF and 29 write16
+ then
+ begin dup 32 < while
+ dup2 >> 1 and if dup write16 then
+ 1+
+ repeat
+ 2drop
+ else
+ drop
+ then
+ ext-point-format-length if
+ 0x000B write16 \ extension type (11)
+ 0x0002 write16 \ extension length
+ 0x0100 write16 \ value: 1 format: uncompressed
+ then
+ ext-ALPN-length dup if
+ 0x0010 write16 \ extension type (16)
+ 4 - dup write16 \ extension length
+ 2- write16 \ list length
+ addr-protocol_names_num get16 0
+ begin
+ dup2 > while
+ dup copy-protocol-name
+ dup write8 addr-pad swap write-blob
+ 1+
+ repeat
+ 2drop
+ else
+ drop
+ then
+ ext-padding-amount 0< ifnot
+ 0x0015 write16 \ extension value (21)
+ ext-padding-amount
+ dup write16 \ extension length
+ begin dup while
+ 1- 0 write8 repeat \ value (only zeros)
+ drop
+ then
+ then
+ ;
+
+\ =======================================================================
+
+\ Parse server SNI extension. If present, then it should be empty.
+: read-server-sni ( lim -- lim )
+ read16 if ERR_BAD_SNI fail then ;
+
+\ Parse server Max Fragment Length extension. If present, then it should
+\ advertise the same length as the client. Note that whether the server
+\ sends it or not changes nothing for us: we won't send any record larger
+\ than the advertised value anyway, and we will accept incoming records
+\ up to our input buffer length.
+: read-server-frag ( lim -- lim )
+ read16 1 = ifnot ERR_BAD_FRAGLEN fail then
+ read8 8 + addr-log_max_frag_len get8 = ifnot ERR_BAD_FRAGLEN fail then ;
+
+\ Parse server Secure Renegotiation extension. This is called only if
+\ the client sent that extension, so we only have two cases to
+\ distinguish: first handshake, and renegotiation; in the latter case,
+\ we know that the server supports the extension, otherwise the client
+\ would not have sent it.
+: read-server-reneg ( lim -- lim )
+ read16
+ addr-reneg get8 ifnot
+ \ "reneg" is 0, so this is a first handshake. The server's
+ \ extension MUST be empty. We also learn that the server
+ \ supports the extension.
+ 1 = ifnot ERR_BAD_SECRENEG fail then
+ read8 0 = ifnot ERR_BAD_SECRENEG fail then
+ 2 addr-reneg set8
+ else
+ \ "reneg" is non-zero, and we sent an extension, so it must
+ \ be 2 and this is a renegotiation. We must verify that
+ \ the extension contents have length exactly 24 bytes and
+ \ match the saved client and server "Finished".
+ 25 = ifnot ERR_BAD_SECRENEG fail then
+ read8 24 = ifnot ERR_BAD_SECRENEG fail then
+ addr-pad 24 read-blob
+ addr-saved_finished addr-pad 24 memcmp ifnot
+ ERR_BAD_SECRENEG fail
+ then
+ then ;
+
+\ Read the ALPN extension from the server. It must contain a single name,
+\ and that name must match one of our names.
+: read-ALPN-from-server ( lim -- lim )
+ \ Extension contents length.
+ read16 open-elt
+ \ Length of list of names.
+ read16 open-elt
+ \ There should be a single name.
+ read8 addr-pad swap dup { len } read-blob
+ close-elt
+ close-elt
+ len test-protocol-name dup 0< if
+ 3 flag? if ERR_UNEXPECTED fail then
+ drop
+ else
+ 1+ addr-selected_protocol set16
+ then ;
+
+\ Save a value in a 16-bit field, or check it in case of session resumption.
+: check-resume ( val addr resume -- )
+ if get16 = ifnot ERR_RESUME_MISMATCH fail then else set16 then ;
+
+cc: DEBUG-BLOB ( addr len -- ) {
+ extern int printf(const char *fmt, ...);
+
+ size_t len = T0_POP();
+ unsigned char *buf = (unsigned char *)CTX + T0_POP();
+ size_t u;
+
+ printf("BLOB:");
+ for (u = 0; u < len; u ++) {
+ if (u % 16 == 0) {
+ printf("\n ");
+ }
+ printf(" %02x", buf[u]);
+ }
+ printf("\n");
+}
+
+\ Parse incoming ServerHello. Returned value is true (-1) on session
+\ resumption.
+: read-ServerHello ( -- bool )
+ \ Get header, and check message type.
+ read-handshake-header 2 = ifnot ERR_UNEXPECTED fail then
+
+ \ Get protocol version.
+ read16 { version }
+ version addr-version_min get16 < version addr-version_max get16 > or if
+ ERR_UNSUPPORTED_VERSION fail
+ then
+
+ \ Enforce chosen version for subsequent records in both directions.
+ version addr-version_in get16 <> if ERR_BAD_VERSION fail then
+ version addr-version_out set16
+
+ \ Server random.
+ addr-server_random 32 read-blob
+
+ \ The "session resumption" flag.
+ 0 { resume }
+
+ \ Session ID.
+ read8 { idlen }
+ idlen 32 > if ERR_OVERSIZED_ID fail then
+ addr-pad idlen read-blob
+ idlen addr-session_id_len get8 = idlen 0 > and if
+ addr-session_id addr-pad idlen memcmp if
+ \ Server session ID is non-empty and matches what
+ \ we sent, so this is a session resumption.
+ -1 >resume
+ then
+ then
+ addr-session_id addr-pad idlen memcpy
+ idlen addr-session_id_len set8
+
+ \ Record version.
+ version addr-version resume check-resume
+
+ \ Cipher suite. We check that it is part of the list of cipher
+ \ suites that we advertised.
+ read16
+ dup scan-suite 0< if ERR_BAD_CIPHER_SUITE fail then
+ \ Also check that the cipher suite is compatible with the
+ \ announced version: suites that don't use HMAC/SHA-1 are
+ \ for TLS-1.2 only, not older versions.
+ dup use-tls12? version 0x0303 < and if ERR_BAD_CIPHER_SUITE fail then
+ addr-cipher_suite resume check-resume
+
+ \ Compression method. Should be 0 (no compression).
+ read8 if ERR_BAD_COMPRESSION fail then
+
+ \ Parse extensions (if any). If there is no extension, then the
+ \ read limit (on the TOS) should be 0 at that point.
+ dup if
+ \ Length of extension list.
+ \ message size.
+ read16 open-elt
+
+ \ Enumerate extensions. For each of them, check that we
+ \ sent an extension of that type, and did not see it
+ \ yet; and then process it.
+ ext-sni-length { ok-sni }
+ ext-reneg-length { ok-reneg }
+ ext-frag-length { ok-frag }
+ ext-signatures-length { ok-signatures }
+ ext-supported-curves-length { ok-curves }
+ ext-point-format-length { ok-points }
+ ext-ALPN-length { ok-ALPN }
+ begin dup while
+ read16
+ case
+ \ Server Name Indication. The server may
+ \ send such an extension if it uses the SNI
+ \ from the client, but that "response
+ \ extension" is supposed to be empty.
+ 0x0000 of
+ ok-sni ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-sni
+ read-server-sni
+ endof
+
+ \ Max Frag Length. The contents shall be
+ \ a single byte whose value matches the one
+ \ sent by the client.
+ 0x0001 of
+ ok-frag ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-frag
+ read-server-frag
+ endof
+
+ \ Secure Renegotiation.
+ 0xFF01 of
+ ok-reneg ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-reneg
+ read-server-reneg
+ endof
+
+ \ Signature Algorithms.
+ \ Normally, the server should never send this
+ \ extension (so says RFC 5246 #7.4.1.4.1),
+ \ but some existing servers do.
+ 0x000D of
+ ok-signatures ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-signatures
+ read-ignore-16
+ endof
+
+ \ Supported Curves.
+ 0x000A of
+ ok-curves ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-curves
+ read-ignore-16
+ endof
+
+ \ Supported Point Formats.
+ 0x000B of
+ ok-points ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-points
+ read-ignore-16
+ endof
+
+ \ ALPN.
+ 0x0010 of
+ ok-ALPN ifnot
+ ERR_EXTRA_EXTENSION fail
+ then
+ 0 >ok-ALPN
+ read-ALPN-from-server
+ endof
+
+ ERR_EXTRA_EXTENSION fail
+ endcase
+ repeat
+
+ \ If we sent a secure renegotiation extension but did not
+ \ receive a response, then the server does not support
+ \ secure renegotiation. This is a hard failure if this
+ \ is a renegotiation.
+ ok-reneg if
+ ok-reneg 5 > if ERR_BAD_SECRENEG fail then
+ 1 addr-reneg set8
+ then
+ close-elt
+ else
+ \ No extension received at all, so the server does not
+ \ support secure renegotiation. This is a hard failure
+ \ if the server was previously known to support it (i.e.
+ \ this is a renegotiation).
+ ext-reneg-length 5 > if ERR_BAD_SECRENEG fail then
+ 1 addr-reneg set8
+ then
+ close-elt
+ resume
+ ;
+
+cc: set-server-curve ( -- ) {
+ const br_x509_class *xc;
+ const br_x509_pkey *pk;
+
+ xc = *(ENG->x509ctx);
+ pk = xc->get_pkey(ENG->x509ctx, NULL);
+ CTX->server_curve =
+ (pk->key_type == BR_KEYTYPE_EC) ? pk->key.ec.curve : 0;
+}
+
+\ Read Certificate message from server.
+: read-Certificate-from-server ( -- )
+ addr-cipher_suite get16 expected-key-type
+ -1 read-Certificate
+ dup 0< if neg fail then
+ dup ifnot ERR_UNEXPECTED fail then
+ over and <> if ERR_WRONG_KEY_USAGE fail then
+
+ \ Set server curve (used for static ECDH).
+ set-server-curve ;
+
+\ Verify signature on ECDHE point sent by the server.
+\ 'hash' is the hash function to use (1 to 6, or 0 for RSA with MD5+SHA-1)
+\ 'use-rsa' is 0 for ECDSA, -1 for for RSA
+\ 'sig-len' is the signature length (in bytes)
+\ The signature itself is in the pad.
+cc: verify-SKE-sig ( hash use-rsa sig-len -- err ) {
+ size_t sig_len = T0_POP();
+ int use_rsa = T0_POPi();
+ int hash = T0_POPi();
+
+ T0_PUSH(verify_SKE_sig(CTX, hash, use_rsa, sig_len));
+}
+
+\ Parse ServerKeyExchange
+: read-ServerKeyExchange ( -- )
+ \ Get header, and check message type.
+ read-handshake-header 12 = ifnot ERR_UNEXPECTED fail then
+
+ \ We expect a named curve, and we must support it.
+ read8 3 = ifnot ERR_INVALID_ALGORITHM fail then
+ read16 dup addr-ecdhe_curve set8
+ dup 32 >= if ERR_INVALID_ALGORITHM fail then
+ supported-curves swap >> 1 and ifnot ERR_INVALID_ALGORITHM fail then
+
+ \ Read the server point.
+ read8
+ dup 133 > if ERR_INVALID_ALGORITHM fail then
+ dup addr-ecdhe_point_len set8
+ addr-ecdhe_point swap read-blob
+
+ \ If using TLS-1.2+, then the hash function and signature algorithm
+ \ are explicitly provided; the signature algorithm must match what
+ \ the cipher suite specifies. With TLS-1.0 and 1.1, the signature
+ \ algorithm is inferred from the cipher suite, and the hash is
+ \ either MD5+SHA-1 (for RSA signatures) or SHA-1 (for ECDSA).
+ addr-version get16 0x0303 >= { tls1.2+ }
+ addr-cipher_suite get16 use-rsa-ecdhe? { use-rsa }
+ 2 { hash }
+ tls1.2+ if
+ \ Read hash function; accept only the SHA-* identifiers
+ \ (from SHA-1 to SHA-512, no MD5 here).
+ read8
+ dup dup 2 < swap 6 > or if ERR_INVALID_ALGORITHM fail then
+ >hash
+ read8
+ \ Get expected signature algorithm and compare with what
+ \ the server just sent. Expected value is 1 for RSA, 3
+ \ for ECDSA. Note that 'use-rsa' evaluates to -1 for RSA,
+ \ 0 for ECDSA.
+ use-rsa 1 << 3 + = ifnot ERR_INVALID_ALGORITHM fail then
+ else
+ \ For MD5+SHA-1, we set 'hash' to 0.
+ use-rsa if 0 >hash then
+ then
+
+ \ Read signature into the pad.
+ read16 dup { sig-len }
+
+ dup 512 > if ERR_LIMIT_EXCEEDED fail then
+ addr-pad swap read-blob
+
+ \ Verify signature.
+ hash use-rsa sig-len verify-SKE-sig
+ dup if fail then drop
+
+ close-elt ;
+
+\ Client certificate: start processing of anchor names.
+cc: anchor-dn-start-name-list ( -- ) {
+ if (CTX->client_auth_vtable != NULL) {
+ (*CTX->client_auth_vtable)->start_name_list(
+ CTX->client_auth_vtable);
+ }
+}
+
+\ Client certificate: start a new anchor DN (length is 16-bit).
+cc: anchor-dn-start-name ( length -- ) {
+ size_t len;
+
+ len = T0_POP();
+ if (CTX->client_auth_vtable != NULL) {
+ (*CTX->client_auth_vtable)->start_name(
+ CTX->client_auth_vtable, len);
+ }
+}
+
+\ Client certificate: push some data for current anchor DN.
+cc: anchor-dn-append-name ( length -- ) {
+ size_t len;
+
+ len = T0_POP();
+ if (CTX->client_auth_vtable != NULL) {
+ (*CTX->client_auth_vtable)->append_name(
+ CTX->client_auth_vtable, ENG->pad, len);
+ }
+}
+
+\ Client certificate: end current anchor DN.
+cc: anchor-dn-end-name ( -- ) {
+ if (CTX->client_auth_vtable != NULL) {
+ (*CTX->client_auth_vtable)->end_name(
+ CTX->client_auth_vtable);
+ }
+}
+
+\ Client certificate: end list of anchor DN.
+cc: anchor-dn-end-name-list ( -- ) {
+ if (CTX->client_auth_vtable != NULL) {
+ (*CTX->client_auth_vtable)->end_name_list(
+ CTX->client_auth_vtable);
+ }
+}
+
+\ Client certificate: obtain the client certificate chain.
+cc: get-client-chain ( auth_types -- ) {
+ uint32_t auth_types;
+
+ auth_types = T0_POP();
+ if (CTX->client_auth_vtable != NULL) {
+ br_ssl_client_certificate ux;
+
+ (*CTX->client_auth_vtable)->choose(CTX->client_auth_vtable,
+ CTX, auth_types, &ux);
+ CTX->auth_type = (unsigned char)ux.auth_type;
+ CTX->hash_id = (unsigned char)ux.hash_id;
+ ENG->chain = ux.chain;
+ ENG->chain_len = ux.chain_len;
+ } else {
+ CTX->hash_id = 0;
+ ENG->chain_len = 0;
+ }
+}
+
+\ Parse CertificateRequest. Header has already been read.
+: read-contents-CertificateRequest ( lim -- )
+ \ Read supported client authentication types. We keep only
+ \ RSA, ECDSA, and ECDH.
+ 0 { auth_types }
+ read8 open-elt
+ begin dup while
+ read8 case
+ 1 of 0x0000FF endof
+ 64 of 0x00FF00 endof
+ 65 of 0x010000 endof
+ 66 of 0x020000 endof
+ 0 swap
+ endcase
+ auth_types or >auth_types
+ repeat
+ close-elt
+
+ \ Full static ECDH is allowed only if the cipher suite is ECDH
+ \ (not ECDHE). It would be theoretically feasible to use static
+ \ ECDH on the client side with an ephemeral key pair from the
+ \ server, but RFC 4492 (section 3) forbids it because ECDHE suites
+ \ are supposed to provide forward secrecy, and static ECDH would
+ \ negate that property.
+ addr-cipher_suite get16 use-ecdh? ifnot
+ auth_types 0xFFFF and >auth_types
+ then
+
+ \ Note: if the cipher suite is ECDH, then the X.509 validation
+ \ engine was invoked with the BR_KEYTYPE_EC | BR_KEYTYPE_KEYX
+ \ combination, so the server's public key has already been
+ \ checked to be fit for a key exchange.
+
+ \ With TLS 1.2:
+ \ - rsa_fixed_ecdh and ecdsa_fixed_ecdh are synoymous.
+ \ - There is an explicit list of supported sign+hash.
+ \ With TLS 1.0,
+ addr-version get16 0x0303 >= if
+ \ With TLS 1.2:
+ \ - There is an explicit list of supported sign+hash.
+ \ - The ECDH flags must be adjusted for RSA/ECDSA
+ \ support.
+ read-list-sign-algos dup addr-hashes set32
+
+ \ Trim down the list depending on what hash functions
+ \ we support (since the hashing itself is done by the SSL
+ \ engine, not by the certificate handler).
+ supported-hash-functions drop dup 8 << or 0x030000 or and
+
+ auth_types and
+ auth_types 0x030000 and if
+ dup 0x0000FF and if 0x010000 or then
+ dup 0x00FF00 and if 0x020000 or then
+ then
+ >auth_types
+ else
+ \ TLS 1.0 or 1.1. The hash function is fixed for signatures
+ \ (MD5+SHA-1 for RSA, SHA-1 for ECDSA).
+ auth_types 0x030401 and >auth_types
+ then
+
+ \ Parse list of anchor DN.
+ anchor-dn-start-name-list
+ read16 open-elt
+ begin dup while
+ read16 open-elt
+ dup anchor-dn-start-name
+
+ \ We read the DN by chunks through the pad, so
+ \ as to use the existing reading function (read-blob)
+ \ that also ensures proper hashing.
+ begin
+ dup while
+ dup 256 > if 256 else dup then { len }
+ addr-pad len read-blob
+ len anchor-dn-append-name
+ repeat
+ close-elt
+ anchor-dn-end-name
+ repeat
+ close-elt
+ anchor-dn-end-name-list
+
+ \ We should have reached the message end.
+ close-elt
+
+ \ Obtain the client chain.
+ auth_types get-client-chain
+ ;
+
+\ (obsolete)
+\ Write an empty Certificate message.
+\ : write-empty-Certificate ( -- )
+\ 11 write8 3 write24 0 write24 ;
+
+cc: do-rsa-encrypt ( prf_id -- nlen ) {
+ int x;
+
+ x = make_pms_rsa(CTX, T0_POP());
+ if (x < 0) {
+ br_ssl_engine_fail(ENG, -x);
+ T0_CO();
+ } else {
+ T0_PUSH(x);
+ }
+}
+
+cc: do-ecdh ( echde prf_id -- ulen ) {
+ unsigned prf_id = T0_POP();
+ unsigned ecdhe = T0_POP();
+ int x;
+
+ x = make_pms_ecdh(CTX, ecdhe, prf_id);
+ if (x < 0) {
+ br_ssl_engine_fail(ENG, -x);
+ T0_CO();
+ } else {
+ T0_PUSH(x);
+ }
+}
+
+cc: do-static-ecdh ( prf-id -- ) {
+ unsigned prf_id = T0_POP();
+
+ if (make_pms_static_ecdh(CTX, prf_id) < 0) {
+ br_ssl_engine_fail(ENG, BR_ERR_INVALID_ALGORITHM);
+ T0_CO();
+ }
+}
+
+cc: do-client-sign ( -- sig_len ) {
+ size_t sig_len;
+
+ sig_len = make_client_sign(CTX);
+ if (sig_len == 0) {
+ br_ssl_engine_fail(ENG, BR_ERR_INVALID_ALGORITHM);
+ T0_CO();
+ }
+ T0_PUSH(sig_len);
+}
+
+\ Write ClientKeyExchange.
+: write-ClientKeyExchange ( -- )
+ 16 write8
+ addr-cipher_suite get16
+ dup use-rsa-keyx? if
+ prf-id do-rsa-encrypt
+ dup 2+ write24
+ dup write16
+ addr-pad swap write-blob
+ else
+ dup use-ecdhe? swap prf-id do-ecdh
+ dup 1+ write24
+ dup write8
+ addr-pad swap write-blob
+ then ;
+
+\ Write CertificateVerify. This is invoked only if a client certificate
+\ was requested and sent, and the authentication is not full static ECDH.
+: write-CertificateVerify ( -- )
+ do-client-sign
+ 15 write8 dup
+ addr-version get16 0x0303 >= if
+ 4 + write24
+ addr-hash_id get8 write8
+ addr-auth_type get8 write8
+ else
+ 2+ write24
+ then
+ dup write16 addr-pad swap write-blob ;
+
+\ =======================================================================
+
+\ Perform a handshake.
+: do-handshake ( -- )
+ 0 addr-application_data set8
+ 22 addr-record_type_out set8
+ 0 addr-selected_protocol set16
+ multihash-init
+
+ write-ClientHello
+ flush-record
+ read-ServerHello
+
+ if
+ \ Session resumption.
+ -1 read-CCS-Finished
+ -1 write-CCS-Finished
+
+ else
+
+ \ Not a session resumption.
+
+ \ Read certificate; then check key type and usages against
+ \ cipher suite.
+ read-Certificate-from-server
+
+ \ Depending on cipher suite, we may now expect a
+ \ ServerKeyExchange.
+ addr-cipher_suite get16 expected-key-type
+ CX 0 63 { BR_KEYTYPE_SIGN } and if
+ read-ServerKeyExchange
+ then
+
+ \ Get next header.
+ read-handshake-header
+
+ \ If this is a CertificateRequest, parse it, then read
+ \ next header.
+ dup 13 = if
+ drop read-contents-CertificateRequest
+ read-handshake-header
+ -1
+ else
+ 0
+ then
+ { seen-CR }
+
+ \ At that point, we should have a ServerHelloDone,
+ \ whose length must be 0.
+ 14 = ifnot ERR_UNEXPECTED fail then
+ if ERR_BAD_HELLO_DONE fail then
+
+ \ There should not be more bytes in the record at that point.
+ more-incoming-bytes? if ERR_UNEXPECTED fail then
+
+ seen-CR if
+ \ If the server requested a client certificate, then
+ \ we must write a Certificate message (it may be
+ \ empty).
+ write-Certificate
+
+ \ If using static ECDH, then the ClientKeyExchange
+ \ is empty, and there is no CertificateVerify.
+ \ Otherwise, there is a ClientKeyExchange; there
+ \ will then be a CertificateVerify if a client chain
+ \ was indeed sent.
+ addr-hash_id get8 0xFF = if
+ drop
+ 16 write8 0 write24
+ addr-cipher_suite get16 prf-id do-static-ecdh
+ else
+ write-ClientKeyExchange
+ if write-CertificateVerify then
+ then
+ else
+ write-ClientKeyExchange
+ then
+
+ -1 write-CCS-Finished
+ -1 read-CCS-Finished
+ then
+
+ \ Now we should be invoked only in case of renegotiation.
+ 1 addr-application_data set8
+ 23 addr-record_type_out set8 ;
+
+\ Read a HelloRequest message.
+: read-HelloRequest ( -- )
+ \ A HelloRequest has length 0 and type 0.
+ read-handshake-header-core
+ if ERR_UNEXPECTED fail then
+ if ERR_BAD_HANDSHAKE fail then ;
+
+\ Entry point.
+: main ( -- ! )
+ \ Perform initial handshake.
+ do-handshake
+
+ begin
+ \ Wait for further invocation. At that point, we should
+ \ get either an explicit call for renegotiation, or
+ \ an incoming HelloRequest handshake message.
+ wait-co
+ dup 0x07 and case
+ 0x00 of
+ 0x10 and if
+ do-handshake
+ then
+ endof
+ 0x01 of
+ drop
+ 0 addr-application_data set8
+ read-HelloRequest
+ \ Reject renegotiations if the peer does not
+ \ support secure renegotiation, or if the
+ \ "no renegotiation" flag is set.
+ addr-reneg get8 1 = 1 flag? or if
+ flush-record
+ begin can-output? not while
+ wait-co drop
+ repeat
+ 100 send-warning
+ \ We rejected the renegotiation,
+ \ but the connection is not dead.
+ \ We must set back things into
+ \ working "application data" state.
+ 1 addr-application_data set8
+ 23 addr-record_type_out set8
+ else
+ do-handshake
+ then
+ endof
+ ERR_UNEXPECTED fail
+ endcase
+ again
+ ;
diff --git a/contrib/bearssl/src/ssl/ssl_hs_common.t0 b/contrib/bearssl/src/ssl/ssl_hs_common.t0
new file mode 100644
index 000000000000..4674891c412f
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_hs_common.t0
@@ -0,0 +1,1382 @@
+\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+\
+\ Permission is hereby granted, free of charge, to any person obtaining
+\ a copy of this software and associated documentation files (the
+\ "Software"), to deal in the Software without restriction, including
+\ without limitation the rights to use, copy, modify, merge, publish,
+\ distribute, sublicense, and/or sell copies of the Software, and to
+\ permit persons to whom the Software is furnished to do so, subject to
+\ the following conditions:
+\
+\ The above copyright notice and this permission notice shall be
+\ included in all copies or substantial portions of the Software.
+\
+\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+\ SOFTWARE.
+
+\ ----------------------------------------------------------------------
+\ This is the common T0 code for processing handshake messages (code that
+\ is used by both client and server).
+
+preamble {
+
+#include <stddef.h>
+#include <string.h>
+
+#include "inner.h"
+
+/*
+ * This macro evaluates to a pointer to the current engine context.
+ */
+#define ENG ((br_ssl_engine_context *)(void *)((unsigned char *)t0ctx - offsetof(br_ssl_engine_context, cpu)))
+
+}
+
+\ IMPLEMENTATION NOTES
+\ ====================
+\
+\ This code handles all records except application data records.
+\ Application data is accepted (incoming records, outgoing payload data)
+\ only when the application_data flag is set, which is done at the end
+\ of the handshake; and it is cleared whenever a renegotiation or a
+\ closure takes place.
+\
+\ Incoming alerts are processed on the fly; fatal alerts terminate the
+\ context, while warnings are ignored, except for close_notify, which
+\ triggers the closure procedure. That procedure never returns (it ends
+\ with an 'ERR_OK fail' call). We can thus make this processing right
+\ into the read functions.
+\
+\ Specific actions from the caller (closure or renegotiation) may happen
+\ only when jumping back into the T0 code, i.e. just after a 'co' call.
+\ Similarly, incoming record type may change only while the caller has
+\ control, so we need to check that type only when returning from a 'co'.
+\
+\ The handshake processor needs to defer back to the caller ('co') only
+\ in one of the following situations:
+\
+\ -- Some handshake data is expected.
+\
+\ -- The handshake is finished, and application data may flow. There may
+\ be some incoming handshake data (HelloRequest from the server). This
+\ is the only situation where a renegotiation call won't be ignored.
+\
+\ -- Some change-cipher-spec data is expected.
+\
+\ -- An alert record is expected. Other types of incoming records will be
+\ skipped.
+\
+\ -- Waiting for the currently accumulated record to be sent and the
+\ output buffer to become free again for another record.
+
+\ Placeholder for handling not yet implemented functionalities.
+: NYI ( -- ! )
+ "NOT YET IMPLEMENTED!" puts cr -1 fail ;
+
+\ Debug function that prints a string (and a newline) on stderr.
+cc: DBG ( addr -- ) {
+ extern void *stderr;
+ extern int fprintf(void *, const char *, ...);
+ fprintf(stderr, "%s\n", &t0_datablock[T0_POPi()]);
+}
+
+\ Debug function that prints a string and an integer value (followed
+\ by a newline) on stderr.
+cc: DBG2 ( addr x -- ) {
+ extern void *stderr;
+ extern int fprintf(void *, const char *, ...);
+ int32_t x = T0_POPi();
+ fprintf(stderr, "%s: %ld (0x%08lX)\n",
+ &t0_datablock[T0_POPi()], (long)x, (unsigned long)(uint32_t)x);
+}
+
+\ Mark the context as failed with a specific error code. This also
+\ returns control to the caller.
+cc: fail ( err -- ! ) {
+ br_ssl_engine_fail(ENG, (int)T0_POPi());
+ T0_CO();
+}
+
+\ Read a byte from the context (address is offset in context).
+cc: get8 ( addr -- val ) {
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*((unsigned char *)ENG + addr));
+}
+
+\ Read a 16-bit word from the context (address is offset in context).
+cc: get16 ( addr -- val ) {
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*(uint16_t *)(void *)((unsigned char *)ENG + addr));
+}
+
+\ Read a 32-bit word from the context (address is offset in context).
+cc: get32 ( addr -- val ) {
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*(uint32_t *)(void *)((unsigned char *)ENG + addr));
+}
+
+\ Set a byte in the context (address is offset in context).
+cc: set8 ( val addr -- ) {
+ size_t addr = (size_t)T0_POP();
+ *((unsigned char *)ENG + addr) = (unsigned char)T0_POP();
+}
+
+\ Set a 16-bit word in the context (address is offset in context).
+cc: set16 ( val addr -- ) {
+ size_t addr = (size_t)T0_POP();
+ *(uint16_t *)(void *)((unsigned char *)ENG + addr) = (uint16_t)T0_POP();
+}
+
+\ Set a 32-bit word in the context (address is offset in context).
+cc: set32 ( val addr -- ) {
+ size_t addr = (size_t)T0_POP();
+ *(uint32_t *)(void *)((unsigned char *)ENG + addr) = (uint32_t)T0_POP();
+}
+
+\ Define a word that evaluates as an address of a field within the
+\ engine context. The field name (C identifier) must follow in the
+\ source. For field 'foo', the defined word is 'addr-foo'.
+: addr-eng:
+ next-word { field }
+ "addr-" field + 0 1 define-word
+ 0 8191 "offsetof(br_ssl_engine_context, " field + ")" + make-CX
+ postpone literal postpone ; ;
+
+addr-eng: max_frag_len
+addr-eng: log_max_frag_len
+addr-eng: peer_log_max_frag_len
+addr-eng: shutdown_recv
+addr-eng: record_type_in
+addr-eng: record_type_out
+addr-eng: version_in
+addr-eng: version_out
+addr-eng: application_data
+addr-eng: version_min
+addr-eng: version_max
+addr-eng: suites_buf
+addr-eng: suites_num
+addr-eng: server_name
+addr-eng: client_random
+addr-eng: server_random
+addr-eng: ecdhe_curve
+addr-eng: ecdhe_point
+addr-eng: ecdhe_point_len
+addr-eng: reneg
+addr-eng: saved_finished
+addr-eng: flags
+addr-eng: pad
+addr-eng: action
+addr-eng: alert
+addr-eng: close_received
+addr-eng: protocol_names_num
+addr-eng: selected_protocol
+
+\ Similar to 'addr-eng:', for fields in the 'session' substructure.
+: addr-session-field:
+ next-word { field }
+ "addr-" field + 0 1 define-word
+ 0 8191 "offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, " field + ")" + make-CX
+ postpone literal postpone ; ;
+
+addr-session-field: session_id
+addr-session-field: session_id_len
+addr-session-field: version
+addr-session-field: cipher_suite
+addr-session-field: master_secret
+
+\ Check a server flag by index.
+: flag? ( index -- bool )
+ addr-flags get32 swap >> 1 and neg ;
+
+\ Define a word that evaluates to an error constant. This assumes that
+\ all relevant error codes are in the 0..63 range.
+: err:
+ next-word { name }
+ name 0 1 define-word
+ 0 63 "BR_" name + make-CX postpone literal postpone ; ;
+
+err: ERR_OK
+err: ERR_BAD_PARAM
+err: ERR_BAD_STATE
+err: ERR_UNSUPPORTED_VERSION
+err: ERR_BAD_VERSION
+err: ERR_BAD_LENGTH
+err: ERR_TOO_LARGE
+err: ERR_BAD_MAC
+err: ERR_NO_RANDOM
+err: ERR_UNKNOWN_TYPE
+err: ERR_UNEXPECTED
+err: ERR_BAD_CCS
+err: ERR_BAD_ALERT
+err: ERR_BAD_HANDSHAKE
+err: ERR_OVERSIZED_ID
+err: ERR_BAD_CIPHER_SUITE
+err: ERR_BAD_COMPRESSION
+err: ERR_BAD_FRAGLEN
+err: ERR_BAD_SECRENEG
+err: ERR_EXTRA_EXTENSION
+err: ERR_BAD_SNI
+err: ERR_BAD_HELLO_DONE
+err: ERR_LIMIT_EXCEEDED
+err: ERR_BAD_FINISHED
+err: ERR_RESUME_MISMATCH
+err: ERR_INVALID_ALGORITHM
+err: ERR_BAD_SIGNATURE
+err: ERR_WRONG_KEY_USAGE
+err: ERR_NO_CLIENT_AUTH
+
+\ Get supported curves (bit mask).
+cc: supported-curves ( -- x ) {
+ uint32_t x = ENG->iec == NULL ? 0 : ENG->iec->supported_curves;
+ T0_PUSH(x);
+}
+
+\ Get supported hash functions (bit mask and number).
+\ Note: this (on purpose) skips MD5.
+cc: supported-hash-functions ( -- x num ) {
+ int i;
+ unsigned x, num;
+
+ x = 0;
+ num = 0;
+ for (i = br_sha1_ID; i <= br_sha512_ID; i ++) {
+ if (br_multihash_getimpl(&ENG->mhash, i)) {
+ x |= 1U << i;
+ num ++;
+ }
+ }
+ T0_PUSH(x);
+ T0_PUSH(num);
+}
+
+\ Test support for RSA signatures.
+cc: supports-rsa-sign? ( -- bool ) {
+ T0_PUSHi(-(ENG->irsavrfy != 0));
+}
+
+\ Test support for ECDSA signatures.
+cc: supports-ecdsa? ( -- bool ) {
+ T0_PUSHi(-(ENG->iecdsa != 0));
+}
+
+\ (Re)initialise the multihasher.
+cc: multihash-init ( -- ) {
+ br_multihash_init(&ENG->mhash);
+}
+
+\ Flush the current record: if some payload data has been accumulated,
+\ close the record and schedule it for sending. If there is no such data,
+\ this function does nothing.
+cc: flush-record ( -- ) {
+ br_ssl_engine_flush_record(ENG);
+}
+
+\ Yield control to the caller.
+\ When the control is returned to us, react to the new context. Returned
+\ value is a bitwise combination of the following:
+\ 0x01 handshake data is available
+\ 0x02 change-cipher-spec data is available
+\ 0x04 some data other than handshake or change-cipher-spec is available
+\ 0x08 output buffer is ready for a new outgoing record
+\ 0x10 renegotiation is requested and not to be ignored
+\ Flags 0x01, 0x02 and 0x04 are mutually exclusive.
+: wait-co ( -- state )
+ co
+ 0
+ addr-action get8 dup if
+ case
+ 1 of 0 do-close endof
+ 2 of addr-application_data get8 1 = if
+ 0x10 or
+ then endof
+ endcase
+ else
+ drop
+ then
+ addr-close_received get8 ifnot
+ has-input? if
+ addr-record_type_in get8 case
+
+ \ ChangeCipherSpec
+ 20 of 0x02 or endof
+
+ \ Alert -- if close_notify received, trigger
+ \ the closure sequence.
+ 21 of process-alerts if -1 do-close then endof
+
+ \ Handshake
+ 22 of 0x01 or endof
+
+ \ Not CCS, Alert or Handshake.
+ drop 0x04 or 0
+ endcase
+ then
+ then
+ can-output? if 0x08 or then ;
+
+\ Send an alert message. This shall be called only when there is room for
+\ an outgoing record.
+: send-alert ( level alert -- )
+ 21 addr-record_type_out set8
+ swap write8-native drop write8-native drop
+ flush-record ;
+
+\ Send an alert message of level "warning". This shall be called only when
+\ there is room for an outgoing record.
+: send-warning ( alert -- )
+ 1 swap send-alert ;
+
+\ Fail by sending a fatal alert.
+: fail-alert ( alert -- ! )
+ { alert }
+ flush-record
+ begin can-output? not while wait-co drop repeat
+ 2 alert send-alert
+ begin can-output? not while wait-co drop repeat
+ alert 512 + fail ;
+
+\ Perform the close operation:
+\ -- Prevent new application data from the caller.
+\ -- Incoming data is discarded (except alerts).
+\ -- Outgoing data is flushed.
+\ -- A close_notify alert is sent.
+\ -- If 'cnr' is zero, then incoming data is discarded until a close_notify
+\ is received.
+\ -- At the end, the context is terminated.
+\
+\ cnr shall be either 0 or -1.
+: do-close ( cnr -- ! )
+ \ 'cnr' is set to non-zero when a close_notify is received from
+ \ the peer.
+ { cnr }
+
+ \ Get out of application data state. If we were accepting
+ \ application data (flag is 1), and we still expect a close_notify
+ \ from the peer (cnr is 0), then we should set the flag to 2.
+ \ In all other cases, flag should be set to 0.
+ addr-application_data get8 cnr not and 1 << addr-application_data set8
+
+ \ Flush existing payload if any.
+ flush-record
+
+ \ Wait for room to send the close_notify. Since individual records
+ \ can always hold at least 512 bytes, we know that when there is
+ \ room, then there is room for a complete close_notify (two bytes).
+ begin can-output? not while cnr wait-for-close >cnr repeat
+
+ \ Write the close_notify and flush it.
+ \ 21 addr-record_type_out set8
+ \ 1 write8-native 0 write8-native 2drop
+ \ flush-record
+ 0 send-warning
+
+ \ Loop until our record has been sent (we know it's gone when
+ \ writing is again possible) and a close_notify has been received.
+ cnr
+ begin
+ dup can-output? and if ERR_OK fail then
+ wait-for-close
+ again ;
+
+\ Yield control to the engine, with a possible flush. If 'cnr' is 0,
+\ then input is analysed: all input is discarded, until a close_notify
+\ is received.
+: wait-for-close ( cnr -- cnr )
+ co
+ dup ifnot
+ has-input? if
+ addr-record_type_in get8 21 = if
+ drop process-alerts
+ \ If we received a close_notify then we
+ \ no longer accept incoming application
+ \ data records.
+ 0 addr-application_data set8
+ else
+ discard-input
+ then
+ then
+ then ;
+
+\ Test whether there is some accumulated payload that still needs to be
+\ sent.
+cc: payload-to-send? ( -- bool ) {
+ T0_PUSHi(-br_ssl_engine_has_pld_to_send(ENG));
+}
+
+\ Test whether there is some available input data.
+cc: has-input? ( -- bool ) {
+ T0_PUSHi(-(ENG->hlen_in != 0));
+}
+
+\ Test whether some payload bytes may be written.
+cc: can-output? ( -- bool ) {
+ T0_PUSHi(-(ENG->hlen_out > 0));
+}
+
+\ Discard current input entirely.
+cc: discard-input ( -- ) {
+ ENG->hlen_in = 0;
+}
+
+\ Low-level read for one byte. If there is no available byte right
+\ away, then -1 is returned. Otherwise, the byte value is returned.
+\ If the current record type is "handshake" then the read byte is also
+\ injected in the multi-hasher.
+cc: read8-native ( -- x ) {
+ if (ENG->hlen_in > 0) {
+ unsigned char x;
+
+ x = *ENG->hbuf_in ++;
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ T0_PUSH(x);
+ ENG->hlen_in --;
+ } else {
+ T0_PUSHi(-1);
+ }
+}
+
+\ Low-level read for several bytes. On entry, this expects an address
+\ (offset in the engine context) and a length; these values designate
+\ where the chunk should go. Upon exit, the new address and length
+\ are pushed; that output length contains how many bytes could not be
+\ read. If there is no available byte for reading, the address and
+\ length are unchanged.
+\ If the current record type is "handshake" then the read bytes are
+\ injected in the multi-hasher.
+cc: read-chunk-native ( addr len -- addr len ) {
+ size_t clen = ENG->hlen_in;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy((unsigned char *)ENG + addr, ENG->hbuf_in, clen);
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_in, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_in += clen;
+ ENG->hlen_in -= clen;
+ }
+}
+
+\ Process available alert bytes. If a fatal alert is received, then the
+\ context is terminated; otherwise, this returns either true (-1) if a
+\ close_notify was received, false (0) otherwise.
+: process-alerts ( -- bool )
+ 0
+ begin has-input? while read8-native process-alert-byte or repeat
+ dup if 1 addr-shutdown_recv set8 then ;
+
+\ Process an alert byte. Returned value is non-zero if this is a close_notify,
+\ zero otherwise.
+: process-alert-byte ( x -- bool )
+ addr-alert get8 case
+ 0 of
+ \ 'alert' field is 0, so this byte shall be a level.
+ \ Levels shall be 1 (warning) or 2 (fatal); we convert
+ \ all other values to "fatal".
+ dup 1 <> if drop 2 then
+ addr-alert set8 0
+ endof
+ 1 of
+ 0 addr-alert set8
+ \ close_notify has value 0.
+ \ no_renegotiation has value 100, and we treat it
+ \ as a fatal alert.
+ dup 100 = if 256 + fail then
+ 0=
+ endof
+ \ Fatal alert implies context termination.
+ drop 256 + fail
+ endcase ;
+
+\ In general we only deal with handshake data here. Alerts are processed
+\ in specific code right when they are received, and ChangeCipherSpec has
+\ its own handling code. So we need to check that the data is "handshake"
+\ only when returning from a coroutine call.
+
+\ Yield control to the engine. Alerts are processed; if incoming data is
+\ neither handshake or alert, then an error is triggered.
+: wait-for-handshake ( -- )
+ wait-co 0x07 and 0x01 > if ERR_UNEXPECTED fail then ;
+
+\ Flush outgoing data (if any), then wait for the output buffer to be
+\ clear; when this is done, set the output record type to the specified
+\ value.
+: wait-rectype-out ( rectype -- )
+ { rectype }
+ flush-record
+ begin
+ can-output? if rectype addr-record_type_out set8 ret then
+ wait-co drop
+ again ;
+
+\ Read one byte of handshake data. Block until that byte is available.
+\ This does not check any length.
+: read8-nc ( -- x )
+ begin
+ read8-native dup 0< ifnot ret then
+ drop wait-for-handshake
+ again ;
+
+\ Test whether there are some more bytes in the current record. These
+\ bytes have not necessarily been received yet (processing of unencrypted
+\ records may begin before all bytes are received).
+cc: more-incoming-bytes? ( -- bool ) {
+ T0_PUSHi(ENG->hlen_in != 0 || !br_ssl_engine_recvrec_finished(ENG));
+}
+
+\ For reading functions, the TOS is supposed to contain the number of bytes
+\ that can still be read (from encapsulating structure header), and it is
+\ updated.
+
+: check-len ( lim len -- lim )
+ - dup 0< if ERR_BAD_PARAM fail then ;
+
+\ Read one byte of handshake data. This pushes an integer in the 0..255 range.
+: read8 ( lim -- lim x )
+ 1 check-len read8-nc ;
+
+\ Read a 16-bit value (in the 0..65535 range)
+: read16 ( lim -- lim n )
+ 2 check-len read8-nc 8 << read8-nc + ;
+
+\ Read a 24-bit value (in the 0..16777215 range)
+: read24 ( lim -- lim n )
+ 3 check-len read8-nc 8 << read8-nc + 8 << read8-nc + ;
+
+\ Read some bytes. The "address" is an offset within the context
+\ structure.
+: read-blob ( lim addr len -- lim )
+ { addr len }
+ len check-len
+ addr len
+ begin
+ read-chunk-native
+ dup 0 = if 2drop ret then
+ wait-for-handshake
+ again ;
+
+\ Read some bytes and drop them.
+: skip-blob ( lim len -- lim )
+ swap over check-len swap
+ begin dup while read8-nc drop 1- repeat
+ drop ;
+
+\ Read a 16-bit length, then skip exactly that many bytes.
+: read-ignore-16 ( lim -- lim )
+ read16 skip-blob ;
+
+\ Open a substructure: the inner structure length is checked against,
+\ and subtracted, from the output structure current limit.
+: open-elt ( lim len -- lim-outer lim-inner )
+ dup { len }
+ - dup 0< if ERR_BAD_PARAM fail then
+ len ;
+
+\ Close the current structure. This checks that the limit is 0.
+: close-elt ( lim -- )
+ if ERR_BAD_PARAM fail then ;
+
+\ Write one byte of handshake data.
+: write8 ( n -- )
+ begin
+ dup write8-native if drop ret then
+ wait-co drop
+ again ;
+
+\ Low-level write for one byte. On exit, it pushes either -1 (byte was
+\ written) or 0 (no room in output buffer).
+cc: write8-native ( x -- bool ) {
+ unsigned char x;
+
+ x = (unsigned char)T0_POP();
+ if (ENG->hlen_out > 0) {
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ *ENG->hbuf_out ++ = x;
+ ENG->hlen_out --;
+ T0_PUSHi(-1);
+ } else {
+ T0_PUSHi(0);
+ }
+}
+
+\ Write a 16-bit value.
+: write16 ( n -- )
+ dup 8 u>> write8 write8 ;
+
+\ Write a 24-bit value.
+: write24 ( n -- )
+ dup 16 u>> write8 write16 ;
+
+\ Write some bytes. The "address" is an offset within the context
+\ structure.
+: write-blob ( addr len -- )
+ begin
+ write-blob-chunk
+ dup 0 = if 2drop ret then
+ wait-co drop
+ again ;
+
+cc: write-blob-chunk ( addr len -- addr len ) {
+ size_t clen = ENG->hlen_out;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy(ENG->hbuf_out, (unsigned char *)ENG + addr, clen);
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_out, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_out += clen;
+ ENG->hlen_out -= clen;
+ }
+}
+
+\ Write a blob with the length as header (over one byte)
+: write-blob-head8 ( addr len -- )
+ dup write8 write-blob ;
+
+\ Write a blob with the length as header (over two bytes)
+: write-blob-head16 ( addr len -- )
+ dup write16 write-blob ;
+
+\ Perform a byte-to-byte comparison between two blobs. Each blob is
+\ provided as an "address" (offset in the context structure); the
+\ length is common. Returned value is true (-1) if the two blobs are
+\ equal, false (0) otherwise.
+cc: memcmp ( addr1 addr2 len -- bool ) {
+ size_t len = (size_t)T0_POP();
+ void *addr2 = (unsigned char *)ENG + (size_t)T0_POP();
+ void *addr1 = (unsigned char *)ENG + (size_t)T0_POP();
+ int x = memcmp(addr1, addr2, len);
+ T0_PUSH((uint32_t)-(x == 0));
+}
+
+\ Copy bytes between two areas, whose addresses are provided as
+\ offsets in the context structure.
+cc: memcpy ( dst src len -- ) {
+ size_t len = (size_t)T0_POP();
+ void *src = (unsigned char *)ENG + (size_t)T0_POP();
+ void *dst = (unsigned char *)ENG + (size_t)T0_POP();
+ memcpy(dst, src, len);
+}
+
+\ Get string length (zero-terminated). The string address is provided as
+\ an offset relative to the context start. Returned length does not include
+\ the terminated 0.
+cc: strlen ( str -- len ) {
+ void *str = (unsigned char *)ENG + (size_t)T0_POP();
+ T0_PUSH((uint32_t)strlen(str));
+}
+
+\ Fill a buffer with zeros. The buffer address is an offset in the context.
+cc: bzero ( addr len -- ) {
+ size_t len = (size_t)T0_POP();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ memset(addr, 0, len);
+}
+
+\ Scan the list of supported cipher suites for a given value. If found,
+\ then the list index at which it was found is returned; otherwise, -1
+\ is returned.
+: scan-suite ( suite -- index )
+ { suite }
+ addr-suites_num get8 { num }
+ 0
+ begin dup num < while
+ dup 1 << addr-suites_buf + get16 suite = if ret then
+ 1+
+ repeat
+ drop -1 ;
+
+\ =======================================================================
+
+\ Generate random bytes into buffer (address is offset in context).
+cc: mkrand ( addr len -- ) {
+ size_t len = (size_t)T0_POP();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ br_hmac_drbg_generate(&ENG->rng, addr, len);
+}
+
+\ Read a handshake message header: type and length. These are returned
+\ in reverse order (type is TOS, length is below it).
+: read-handshake-header-core ( -- lim type )
+ read8-nc 3 read24 swap drop swap ;
+
+\ Read a handshake message header: type and length. If the header is for
+\ a HelloRequest message, then it is discarded and a new header is read
+\ (repeatedly if necessary).
+: read-handshake-header ( -- lim type )
+ begin
+ read-handshake-header-core dup 0= while
+ drop if ERR_BAD_HANDSHAKE fail then
+ repeat ;
+
+\ =======================================================================
+
+\ Cipher suite processing.
+\
+\ Unfortunately, cipher suite identifiers are attributed mostly arbitrary,
+\ so we have to map the cipher suite numbers we support into aggregate
+\ words that encode the information we need. Table below is organized
+\ as a sequence of pairs of 16-bit words, the first being the cipher suite
+\ identifier, the second encoding the algorithm elements. The suites are
+\ ordered by increasing cipher suite ID, so that fast lookups may be
+\ performed with a binary search (not implemented for the moment, since it
+\ does not appear to matter much in practice).
+\
+\ Algorithm elements are encoded over 4 bits each, in the following order
+\ (most significant to least significant):
+\
+\ -- Server key type:
+\ 0 RSA (RSA key exchange)
+\ 1 ECDHE-RSA (ECDHE key exchange, RSA signature)
+\ 2 ECDHE-ECDSA (ECDHE key exchange, ECDSA signature)
+\ 3 ECDH-RSA (ECDH key exchange, certificate is RSA-signed)
+\ 4 ECDH-ECDSA (ECDH key exchange, certificate is ECDSA-signed)
+\ -- Encryption algorithm:
+\ 0 3DES/CBC
+\ 1 AES-128/CBC
+\ 2 AES-256/CBC
+\ 3 AES-128/GCM
+\ 4 AES-256/GCM
+\ 5 ChaCha20/Poly1305
+\ 6 AES-128/CCM
+\ 7 AES-256/CCM
+\ 8 AES-128/CCM8
+\ 9 AES-256/CCM8
+\ -- MAC algorithm:
+\ 0 none (for suites with AEAD encryption)
+\ 2 HMAC/SHA-1
+\ 4 HMAC/SHA-256
+\ 5 HMAC/SHA-384
+\ -- PRF for TLS-1.2:
+\ 4 with SHA-256
+\ 5 with SHA-384
+\
+\ WARNING: if adding a new cipher suite that does not use SHA-256 for the
+\ PRF (with TLS 1.2), be sure to check the suites_sha384[] array defined
+\ in ssl/ssl_keyexport.c
+
+data: cipher-suite-def
+
+hexb| 000A 0024 | \ TLS_RSA_WITH_3DES_EDE_CBC_SHA
+hexb| 002F 0124 | \ TLS_RSA_WITH_AES_128_CBC_SHA
+hexb| 0035 0224 | \ TLS_RSA_WITH_AES_256_CBC_SHA
+hexb| 003C 0144 | \ TLS_RSA_WITH_AES_128_CBC_SHA256
+hexb| 003D 0244 | \ TLS_RSA_WITH_AES_256_CBC_SHA256
+
+hexb| 009C 0304 | \ TLS_RSA_WITH_AES_128_GCM_SHA256
+hexb| 009D 0405 | \ TLS_RSA_WITH_AES_256_GCM_SHA384
+
+hexb| C003 4024 | \ TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA
+hexb| C004 4124 | \ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA
+hexb| C005 4224 | \ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA
+hexb| C008 2024 | \ TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA
+hexb| C009 2124 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA
+hexb| C00A 2224 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA
+hexb| C00D 3024 | \ TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
+hexb| C00E 3124 | \ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA
+hexb| C00F 3224 | \ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA
+hexb| C012 1024 | \ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA
+hexb| C013 1124 | \ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA
+hexb| C014 1224 | \ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA
+
+hexb| C023 2144 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256
+hexb| C024 2255 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384
+hexb| C025 4144 | \ TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256
+hexb| C026 4255 | \ TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384
+hexb| C027 1144 | \ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256
+hexb| C028 1255 | \ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384
+hexb| C029 3144 | \ TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256
+hexb| C02A 3255 | \ TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384
+hexb| C02B 2304 | \ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+hexb| C02C 2405 | \ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384
+hexb| C02D 4304 | \ TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+hexb| C02E 4405 | \ TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384
+hexb| C02F 1304 | \ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+hexb| C030 1405 | \ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384
+hexb| C031 3304 | \ TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+hexb| C032 3405 | \ TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+
+hexb| C09C 0604 | \ TLS_RSA_WITH_AES_128_CCM
+hexb| C09D 0704 | \ TLS_RSA_WITH_AES_256_CCM
+hexb| C0A0 0804 | \ TLS_RSA_WITH_AES_128_CCM_8
+hexb| C0A1 0904 | \ TLS_RSA_WITH_AES_256_CCM_8
+hexb| C0AC 2604 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CCM
+hexb| C0AD 2704 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CCM
+hexb| C0AE 2804 | \ TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8
+hexb| C0AF 2904 | \ TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8
+
+hexb| CCA8 1504 | \ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+hexb| CCA9 2504 | \ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
+
+hexb| 0000 | \ List terminator.
+
+\ Convert cipher suite identifier to element words. This returns 0 if
+\ the cipher suite is not known.
+: cipher-suite-to-elements ( suite -- elts )
+ { id }
+ cipher-suite-def
+ begin
+ dup 2+ swap data-get16
+ dup ifnot 2drop 0 ret then
+ id = if data-get16 ret then
+ 2+
+ again ;
+
+\ Check that a given cipher suite is supported. Note that this also
+\ returns true (-1) for the TLS_FALLBACK_SCSV pseudo-ciphersuite.
+: suite-supported? ( suite -- bool )
+ dup 0x5600 = if drop -1 ret then
+ cipher-suite-to-elements 0<> ;
+
+\ Get expected key type for cipher suite. The key type is one of
+\ BR_KEYTYPE_RSA or BR_KEYTYPE_EC, combined with either BR_KEYTYPE_KEYX
+\ (RSA encryption or static ECDH) or BR_KEYTYPE_SIGN (RSA or ECDSA
+\ signature, for ECDHE cipher suites).
+: expected-key-type ( suite -- key-type )
+ cipher-suite-to-elements 12 >>
+ case
+ 0 of CX 0 63 { BR_KEYTYPE_RSA | BR_KEYTYPE_KEYX } endof
+ 1 of CX 0 63 { BR_KEYTYPE_RSA | BR_KEYTYPE_SIGN } endof
+ 2 of CX 0 63 { BR_KEYTYPE_EC | BR_KEYTYPE_SIGN } endof
+ 3 of CX 0 63 { BR_KEYTYPE_EC | BR_KEYTYPE_KEYX } endof
+ 4 of CX 0 63 { BR_KEYTYPE_EC | BR_KEYTYPE_KEYX } endof
+ 0 swap
+ endcase ;
+
+\ Test whether the cipher suite uses RSA key exchange.
+: use-rsa-keyx? ( suite -- bool )
+ cipher-suite-to-elements 12 >> 0= ;
+
+\ Test whether the cipher suite uses ECDHE key exchange, signed with RSA.
+: use-rsa-ecdhe? ( suite -- bool )
+ cipher-suite-to-elements 12 >> 1 = ;
+
+\ Test whether the cipher suite uses ECDHE key exchange, signed with ECDSA.
+: use-ecdsa-ecdhe? ( suite -- bool )
+ cipher-suite-to-elements 12 >> 2 = ;
+
+\ Test whether the cipher suite uses ECDHE key exchange (with RSA or ECDSA).
+: use-ecdhe? ( suite -- bool )
+ cipher-suite-to-elements 12 >> dup 0> swap 3 < and ;
+
+\ Test whether the cipher suite uses ECDH (static) key exchange.
+: use-ecdh? ( suite -- bool )
+ cipher-suite-to-elements 12 >> 2 > ;
+
+\ Get identifier for the PRF (TLS 1.2).
+: prf-id ( suite -- id )
+ cipher-suite-to-elements 15 and ;
+
+\ Test whether a cipher suite is only for TLS-1.2. Cipher suites that
+\ can be used with TLS-1.0 or 1.1 use HMAC/SHA-1. RFC do not formally
+\ forbid using a CBC-based TLS-1.2 cipher suite, e.g. based on HMAC/SHA-256,
+\ with older protocol versions; however, servers should not do that, since
+\ it may confuse clients. Since the server code does not try such games,
+\ for consistency, the client should reject it as well (normal servers
+\ don't do that, so any attempt is a sign of foul play).
+: use-tls12? ( suite -- bool )
+ cipher-suite-to-elements 0xF0 and 0x20 <> ;
+
+\ Switch to negotiated security parameters for input or output.
+: switch-encryption ( is-client for-input -- )
+ { for-input }
+ addr-cipher_suite get16 cipher-suite-to-elements { elts }
+
+ \ prf_id
+ elts 15 and
+
+ \ mac_id
+ elts 4 >> 15 and
+
+ \ cipher type and key length
+ elts 8 >> 15 and case
+ \ 3DES/CBC
+ 0 of 0 24
+ for-input if
+ switch-cbc-in
+ else
+ switch-cbc-out
+ then
+ endof
+
+ \ AES-128/CBC
+ 1 of 1 16
+ for-input if
+ switch-cbc-in
+ else
+ switch-cbc-out
+ then
+ endof
+
+ \ AES-256/CBC
+ 2 of 1 32
+ for-input if
+ switch-cbc-in
+ else
+ switch-cbc-out
+ then
+ endof
+
+ \ AES-128/GCM
+ 3 of drop 16
+ for-input if
+ switch-aesgcm-in
+ else
+ switch-aesgcm-out
+ then
+ endof
+
+ \ AES-256/GCM
+ 4 of drop 32
+ for-input if
+ switch-aesgcm-in
+ else
+ switch-aesgcm-out
+ then
+ endof
+
+ \ ChaCha20+Poly1305
+ 5 of drop
+ for-input if
+ switch-chapol-in
+ else
+ switch-chapol-out
+ then
+ endof
+
+ \ Now we only have AES/CCM suites (6 to 9). Since the
+ \ input is between 0 and 15, and we checked values 0 to 5,
+ \ we only need to reject values larger than 9.
+ dup 9 > if
+ ERR_BAD_PARAM fail
+ then
+
+ \ Stack: is_client prf_id mac_id cipher_id
+ \ We want to remove the mac_id (it is zero for CCM suites)
+ \ and replace the cipher_id with the key and tag lengths.
+ \ The following table applies:
+ \ id key length tag length
+ \ 6 16 16
+ \ 7 32 16
+ \ 8 16 8
+ \ 9 32 8
+ swap drop
+ dup 1 and 4 << 16 + swap
+ 8 and 16 swap -
+ for-input if
+ switch-aesccm-in
+ else
+ switch-aesccm-out
+ then
+ ret
+ endcase
+ ;
+
+cc: switch-cbc-out ( is_client prf_id mac_id aes cipher_key_len -- ) {
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_out(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcenc : ENG->ides_cbcenc, cipher_key_len);
+}
+
+cc: switch-cbc-in ( is_client prf_id mac_id aes cipher_key_len -- ) {
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_in(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcdec : ENG->ides_cbcdec, cipher_key_len);
+}
+
+cc: switch-aesgcm-out ( is_client prf_id cipher_key_len -- ) {
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_out(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+}
+
+cc: switch-aesgcm-in ( is_client prf_id cipher_key_len -- ) {
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_in(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+}
+
+cc: switch-chapol-out ( is_client prf_id -- ) {
+ int is_client, prf_id;
+
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_chapol_out(ENG, is_client, prf_id);
+}
+
+cc: switch-chapol-in ( is_client prf_id -- ) {
+ int is_client, prf_id;
+
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_chapol_in(ENG, is_client, prf_id);
+}
+
+cc: switch-aesccm-out ( is_client prf_id cipher_key_len tag_len -- ) {
+ int is_client, prf_id;
+ unsigned cipher_key_len, tag_len;
+
+ tag_len = T0_POP();
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_ccm_out(ENG, is_client, prf_id,
+ ENG->iaes_ctrcbc, cipher_key_len, tag_len);
+}
+
+cc: switch-aesccm-in ( is_client prf_id cipher_key_len tag_len -- ) {
+ int is_client, prf_id;
+ unsigned cipher_key_len, tag_len;
+
+ tag_len = T0_POP();
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_ccm_in(ENG, is_client, prf_id,
+ ENG->iaes_ctrcbc, cipher_key_len, tag_len);
+}
+
+\ Write Finished message.
+: write-Finished ( from_client -- )
+ compute-Finished
+ 20 write8 12 write24 addr-pad 12 write-blob ;
+
+\ Read Finished message.
+: read-Finished ( from_client -- )
+ compute-Finished
+ read-handshake-header 20 <> if ERR_UNEXPECTED fail then
+ addr-pad 12 + 12 read-blob
+ close-elt
+ addr-pad dup 12 + 12 memcmp ifnot ERR_BAD_FINISHED fail then ;
+
+\ Compute the "Finished" contents (either the value to send, or the
+\ expected value). The 12-byte string is written in the pad. The
+\ "from_client" value is non-zero for the Finished sent by the client.
+\ The computed value is also saved in the relevant buffer for handling
+\ secure renegotiation.
+: compute-Finished ( from_client -- )
+ dup addr-saved_finished swap ifnot 12 + then swap
+ addr-cipher_suite get16 prf-id compute-Finished-inner
+ addr-pad 12 memcpy ;
+
+cc: compute-Finished-inner ( from_client prf_id -- ) {
+ int prf_id = T0_POP();
+ int from_client = T0_POPi();
+ unsigned char tmp[48];
+ br_tls_prf_seed_chunk seed;
+
+ br_tls_prf_impl prf = br_ssl_engine_get_PRF(ENG, prf_id);
+ seed.data = tmp;
+ if (ENG->session.version >= BR_TLS12) {
+ seed.len = br_multihash_out(&ENG->mhash, prf_id, tmp);
+ } else {
+ br_multihash_out(&ENG->mhash, br_md5_ID, tmp);
+ br_multihash_out(&ENG->mhash, br_sha1_ID, tmp + 16);
+ seed.len = 36;
+ }
+ prf(ENG->pad, 12, ENG->session.master_secret,
+ sizeof ENG->session.master_secret,
+ from_client ? "client finished" : "server finished",
+ 1, &seed);
+}
+
+\ Receive ChangeCipherSpec and Finished from the peer.
+: read-CCS-Finished ( is-client -- )
+ has-input? if
+ addr-record_type_in get8 20 <> if ERR_UNEXPECTED fail then
+ else
+ begin
+ wait-co 0x07 and dup 0x02 <> while
+ if ERR_UNEXPECTED fail then
+ repeat
+ drop
+ then
+ read8-nc 1 <> more-incoming-bytes? or if ERR_BAD_CCS fail then
+ dup 1 switch-encryption
+
+ \ Read and verify Finished from peer.
+ not read-Finished ;
+
+\ Send ChangeCipherSpec and Finished to the peer.
+: write-CCS-Finished ( is-client -- )
+ \ Flush and wait for output buffer to be clear, so that we may
+ \ write our ChangeCipherSpec. We must switch immediately after
+ \ triggering the flush.
+ 20 wait-rectype-out
+ 1 write8
+ flush-record
+ dup 0 switch-encryption
+ 22 wait-rectype-out
+ write-Finished
+ flush-record ;
+
+\ Read and parse a list of supported signature algorithms (with hash
+\ functions). The resulting bit field is returned.
+: read-list-sign-algos ( lim -- lim value )
+ 0 { hashes }
+ read16 open-elt
+ begin dup while
+ read8 { hash } read8 { sign }
+
+ \ If hash is 0x08 then this is a "new algorithm" identifier,
+ \ and we set the corresponding bit if it is in the 0..15
+ \ range. Otherwise, we keep the value only if the signature
+ \ is either 1 (RSA) or 3 (ECDSA), and the hash is one of the
+ \ SHA-* functions (2 to 6). Note that we reject MD5.
+ hash 8 = if
+ sign 15 <= if
+ 1 sign 16 + << hashes or >hashes
+ then
+ else
+ hash 2 >= hash 6 <= and
+ sign 1 = sign 3 = or
+ and if
+ hashes 1 sign 1- 2 << hash + << or >hashes
+ then
+ then
+ repeat
+ close-elt
+ hashes ;
+
+\ =======================================================================
+
+\ Compute total chain length. This includes the individual certificate
+\ headers, but not the total chain header. This also sets the cert_cur,
+\ cert_len and chain_len context fields.
+cc: total-chain-length ( -- len ) {
+ size_t u;
+ uint32_t total;
+
+ total = 0;
+ for (u = 0; u < ENG->chain_len; u ++) {
+ total += 3 + (uint32_t)ENG->chain[u].data_len;
+ }
+ T0_PUSH(total);
+}
+
+\ Get length for current certificate in the chain; if the chain end was
+\ reached, then this returns -1.
+cc: begin-cert ( -- len ) {
+ if (ENG->chain_len == 0) {
+ T0_PUSHi(-1);
+ } else {
+ ENG->cert_cur = ENG->chain->data;
+ ENG->cert_len = ENG->chain->data_len;
+ ENG->chain ++;
+ ENG->chain_len --;
+ T0_PUSH(ENG->cert_len);
+ }
+}
+
+\ Copy a chunk of certificate data into the pad. Returned value is the
+\ chunk length, or 0 if the certificate end is reached.
+cc: copy-cert-chunk ( -- len ) {
+ size_t clen;
+
+ clen = ENG->cert_len;
+ if (clen > sizeof ENG->pad) {
+ clen = sizeof ENG->pad;
+ }
+ memcpy(ENG->pad, ENG->cert_cur, clen);
+ ENG->cert_cur += clen;
+ ENG->cert_len -= clen;
+ T0_PUSH(clen);
+}
+
+\ Write a Certificate message. Total chain length (excluding the 3-byte
+\ header) is returned; it is 0 if the chain is empty.
+: write-Certificate ( -- total_chain_len )
+ 11 write8
+ total-chain-length dup
+ dup 3 + write24 write24
+ begin
+ begin-cert
+ dup 0< if drop ret then write24
+ begin copy-cert-chunk dup while
+ addr-pad swap write-blob
+ repeat
+ drop
+ again ;
+
+cc: x509-start-chain ( by_client -- ) {
+ const br_x509_class *xc;
+ uint32_t bc;
+
+ bc = T0_POP();
+ xc = *(ENG->x509ctx);
+ xc->start_chain(ENG->x509ctx, bc ? ENG->server_name : NULL);
+}
+
+cc: x509-start-cert ( length -- ) {
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ xc->start_cert(ENG->x509ctx, T0_POP());
+}
+
+cc: x509-append ( length -- ) {
+ const br_x509_class *xc;
+ size_t len;
+
+ xc = *(ENG->x509ctx);
+ len = T0_POP();
+ xc->append(ENG->x509ctx, ENG->pad, len);
+}
+
+cc: x509-end-cert ( -- ) {
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ xc->end_cert(ENG->x509ctx);
+}
+
+cc: x509-end-chain ( -- err ) {
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ T0_PUSH(xc->end_chain(ENG->x509ctx));
+}
+
+cc: get-key-type-usages ( -- key-type-usages ) {
+ const br_x509_class *xc;
+ const br_x509_pkey *pk;
+ unsigned usages;
+
+ xc = *(ENG->x509ctx);
+ pk = xc->get_pkey(ENG->x509ctx, &usages);
+ if (pk == NULL) {
+ T0_PUSH(0);
+ } else {
+ T0_PUSH(pk->key_type | usages);
+ }
+}
+
+\ Read a Certificate message.
+\ Parameter: non-zero if this is a read by the client of a certificate
+\ sent by the server; zero otherwise.
+\ Returned value:
+\ - Empty: 0
+\ - Valid: combination of key type and allowed key usages.
+\ - Invalid: negative (-x for error code x)
+: read-Certificate ( by_client -- key-type-usages )
+ \ Get header, and check message type.
+ read-handshake-header 11 = ifnot ERR_UNEXPECTED fail then
+
+ \ If the chain is empty, do some special processing.
+ dup 3 = if
+ read24 if ERR_BAD_PARAM fail then
+ swap drop ret
+ then
+
+ \ Start processing the chain through the X.509 engine.
+ swap x509-start-chain
+
+ \ Total chain length is a 24-bit integer.
+ read24 open-elt
+ begin
+ dup while
+ read24 open-elt
+ dup x509-start-cert
+
+ \ We read the certificate by chunks through the pad, so
+ \ as to use the existing reading function (read-blob)
+ \ that also ensures proper hashing.
+ begin
+ dup while
+ dup 256 > if 256 else dup then { len }
+ addr-pad len read-blob
+ len x509-append
+ repeat
+ close-elt
+ x509-end-cert
+ repeat
+
+ \ We must close the chain AND the handshake message.
+ close-elt
+ close-elt
+
+ \ Chain processing is finished; get the error code.
+ x509-end-chain
+ dup if neg ret then drop
+
+ \ Return key type and usages.
+ get-key-type-usages ;
+
+\ =======================================================================
+
+\ Copy a specific protocol name from the list to the pad. The byte
+\ length is returned.
+cc: copy-protocol-name ( idx -- len ) {
+ size_t idx = T0_POP();
+ size_t len = strlen(ENG->protocol_names[idx]);
+ memcpy(ENG->pad, ENG->protocol_names[idx], len);
+ T0_PUSH(len);
+}
+
+\ Compare name in pad with the configured list of protocol names.
+\ If a match is found, then the index is returned; otherwise, -1
+\ is returned.
+cc: test-protocol-name ( len -- n ) {
+ size_t len = T0_POP();
+ size_t u;
+
+ for (u = 0; u < ENG->protocol_names_num; u ++) {
+ const char *name;
+
+ name = ENG->protocol_names[u];
+ if (len == strlen(name) && memcmp(ENG->pad, name, len) == 0) {
+ T0_PUSH(u);
+ T0_RET();
+ }
+ }
+ T0_PUSHi(-1);
+}
diff --git a/contrib/bearssl/src/ssl/ssl_hs_server.c b/contrib/bearssl/src/ssl/ssl_hs_server.c
new file mode 100644
index 000000000000..5f8cae79fc97
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_hs_server.c
@@ -0,0 +1,2009 @@
+/* Automatically generated code; do not modify directly. */
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+} t0_context;
+
+static uint32_t
+t0_parse7E_unsigned(const unsigned char **p)
+{
+ uint32_t x;
+
+ x = 0;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ return x;
+ }
+ }
+}
+
+static int32_t
+t0_parse7E_signed(const unsigned char **p)
+{
+ int neg;
+ uint32_t x;
+
+ neg = ((**p) >> 6) & 1;
+ x = (uint32_t)-neg;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ if (neg) {
+ return -(int32_t)~x - 1;
+ } else {
+ return (int32_t)x;
+ }
+ }
+ }
+}
+
+#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80)
+#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F)
+#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8)
+#define T0_INT1(x) T0_FBYTE(x, 0)
+#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+
+/* static const unsigned char t0_datablock[]; */
+
+
+void br_ssl_hs_server_init_main(void *t0ctx);
+
+void br_ssl_hs_server_run(void *t0ctx);
+
+
+
+#include <stddef.h>
+#include <string.h>
+
+#include "inner.h"
+
+/*
+ * This macro evaluates to a pointer to the current engine context.
+ */
+#define ENG ((br_ssl_engine_context *)(void *)((unsigned char *)t0ctx - offsetof(br_ssl_engine_context, cpu)))
+
+
+
+
+
+/*
+ * This macro evaluates to a pointer to the server context, under that
+ * specific name. It must be noted that since the engine context is the
+ * first field of the br_ssl_server_context structure ('eng'), then
+ * pointers values of both types are interchangeable, modulo an
+ * appropriate cast. This also means that "addresses" computed as offsets
+ * within the structure work for both kinds of context.
+ */
+#define CTX ((br_ssl_server_context *)ENG)
+
+/*
+ * Decrypt the pre-master secret (RSA key exchange).
+ */
+static void
+do_rsa_decrypt(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *epms, size_t len)
+{
+ uint32_t x;
+ unsigned char rpms[48];
+
+ /*
+ * Decrypt the PMS.
+ */
+ x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable, epms, &len);
+
+ /*
+ * Set the first two bytes to the maximum supported client
+ * protocol version. These bytes are used for version rollback
+ * detection; forceing the two bytes will make the master secret
+ * wrong if the bytes are not correct. This process is
+ * recommended by RFC 5246 (section 7.4.7.1).
+ */
+ br_enc16be(epms, ctx->client_max_version);
+
+ /*
+ * Make a random PMS and copy it above the decrypted value if the
+ * decryption failed. Note that we use a constant-time conditional
+ * copy.
+ */
+ br_hmac_drbg_generate(&ctx->eng.rng, rpms, sizeof rpms);
+ br_ccopy(x ^ 1, epms, rpms, sizeof rpms);
+
+ /*
+ * Compute master secret.
+ */
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, epms, 48);
+
+ /*
+ * Clear the pre-master secret from RAM: it is normally a buffer
+ * in the context, hence potentially long-lived.
+ */
+ memset(epms, 0, len);
+}
+
+/*
+ * Common part for ECDH and ECDHE.
+ */
+static void
+ecdh_common(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *xcoor, size_t xcoor_len, uint32_t ctl)
+{
+ unsigned char rpms[80];
+
+ if (xcoor_len > sizeof rpms) {
+ xcoor_len = sizeof rpms;
+ ctl = 0;
+ }
+
+ /*
+ * Make a random PMS and copy it above the decrypted value if the
+ * decryption failed. Note that we use a constant-time conditional
+ * copy.
+ */
+ br_hmac_drbg_generate(&ctx->eng.rng, rpms, xcoor_len);
+ br_ccopy(ctl ^ 1, xcoor, rpms, xcoor_len);
+
+ /*
+ * Compute master secret.
+ */
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, xcoor, xcoor_len);
+
+ /*
+ * Clear the pre-master secret from RAM: it is normally a buffer
+ * in the context, hence potentially long-lived.
+ */
+ memset(xcoor, 0, xcoor_len);
+}
+
+/*
+ * Do the ECDH key exchange (not ECDHE).
+ */
+static void
+do_ecdh(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *cpoint, size_t cpoint_len)
+{
+ uint32_t x;
+
+ /*
+ * Finalise the key exchange.
+ */
+ x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable,
+ cpoint, &cpoint_len);
+ ecdh_common(ctx, prf_id, cpoint, cpoint_len, x);
+}
+
+/*
+ * Do the full static ECDH key exchange. When this function is called,
+ * it has already been verified that the cipher suite uses ECDH (not ECDHE),
+ * and the client's public key (from its certificate) has type EC and is
+ * apt for key exchange.
+ */
+static void
+do_static_ecdh(br_ssl_server_context *ctx, int prf_id)
+{
+ unsigned char cpoint[133];
+ size_t cpoint_len;
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+ cpoint_len = pk->key.ec.qlen;
+ if (cpoint_len > sizeof cpoint) {
+ /*
+ * If the point is larger than our buffer then we need to
+ * restrict it. Length 2 is not a valid point length, so
+ * the ECDH will fail.
+ */
+ cpoint_len = 2;
+ }
+ memcpy(cpoint, pk->key.ec.q, cpoint_len);
+ do_ecdh(ctx, prf_id, cpoint, cpoint_len);
+}
+
+static size_t
+hash_data(br_ssl_server_context *ctx,
+ void *dst, int hash_id, const void *src, size_t len)
+{
+ const br_hash_class *hf;
+ br_hash_compat_context hc;
+
+ if (hash_id == 0) {
+ unsigned char tmp[36];
+
+ hf = br_multihash_getimpl(&ctx->eng.mhash, br_md5_ID);
+ if (hf == NULL) {
+ return 0;
+ }
+ hf->init(&hc.vtable);
+ hf->update(&hc.vtable, src, len);
+ hf->out(&hc.vtable, tmp);
+ hf = br_multihash_getimpl(&ctx->eng.mhash, br_sha1_ID);
+ if (hf == NULL) {
+ return 0;
+ }
+ hf->init(&hc.vtable);
+ hf->update(&hc.vtable, src, len);
+ hf->out(&hc.vtable, tmp + 16);
+ memcpy(dst, tmp, 36);
+ return 36;
+ } else {
+ hf = br_multihash_getimpl(&ctx->eng.mhash, hash_id);
+ if (hf == NULL) {
+ return 0;
+ }
+ hf->init(&hc.vtable);
+ hf->update(&hc.vtable, src, len);
+ hf->out(&hc.vtable, dst);
+ return (hf->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
+ }
+}
+
+/*
+ * Do the ECDHE key exchange (part 1: generation of transient key, and
+ * computing of the point to send to the client). Returned value is the
+ * signature length (in bytes), or -x on error (with x being an error
+ * code). The encoded point is written in the ecdhe_point[] context buffer
+ * (length in ecdhe_point_len).
+ */
+static int
+do_ecdhe_part1(br_ssl_server_context *ctx, int curve)
+{
+ unsigned algo_id;
+ unsigned mask;
+ const unsigned char *order;
+ size_t olen, glen;
+ size_t hv_len, sig_len;
+
+ if (!((ctx->eng.iec->supported_curves >> curve) & 1)) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+ ctx->eng.ecdhe_curve = curve;
+
+ /*
+ * Generate our private key. We need a non-zero random value
+ * which is lower than the curve order, in a "large enough"
+ * range. We force the top bit to 0 and bottom bit to 1, which
+ * does the trick. Note that contrary to what happens in ECDSA,
+ * this is not a problem if we do not cover the full range of
+ * possible values.
+ */
+ order = ctx->eng.iec->order(curve, &olen);
+ mask = 0xFF;
+ while (mask >= order[0]) {
+ mask >>= 1;
+ }
+ br_hmac_drbg_generate(&ctx->eng.rng, ctx->ecdhe_key, olen);
+ ctx->ecdhe_key[0] &= mask;
+ ctx->ecdhe_key[olen - 1] |= 0x01;
+ ctx->ecdhe_key_len = olen;
+
+ /*
+ * Compute our ECDH point.
+ */
+ glen = ctx->eng.iec->mulgen(ctx->eng.ecdhe_point,
+ ctx->ecdhe_key, olen, curve);
+ ctx->eng.ecdhe_point_len = glen;
+
+ /*
+ * Assemble the message to be signed, and possibly hash it.
+ */
+ memcpy(ctx->eng.pad, ctx->eng.client_random, 32);
+ memcpy(ctx->eng.pad + 32, ctx->eng.server_random, 32);
+ ctx->eng.pad[64 + 0] = 0x03;
+ ctx->eng.pad[64 + 1] = 0x00;
+ ctx->eng.pad[64 + 2] = curve;
+ ctx->eng.pad[64 + 3] = ctx->eng.ecdhe_point_len;
+ memcpy(ctx->eng.pad + 64 + 4,
+ ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len);
+ hv_len = 64 + 4 + ctx->eng.ecdhe_point_len;
+ algo_id = ctx->sign_hash_id;
+ if (algo_id >= (unsigned)0xFF00) {
+ hv_len = hash_data(ctx, ctx->eng.pad, algo_id & 0xFF,
+ ctx->eng.pad, hv_len);
+ if (hv_len == 0) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+ }
+
+ sig_len = (*ctx->policy_vtable)->do_sign(ctx->policy_vtable,
+ algo_id, ctx->eng.pad, hv_len, sizeof ctx->eng.pad);
+ return sig_len ? (int)sig_len : -BR_ERR_INVALID_ALGORITHM;
+}
+
+/*
+ * Do the ECDHE key exchange (part 2: computation of the shared secret
+ * from the point sent by the client).
+ */
+static void
+do_ecdhe_part2(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *cpoint, size_t cpoint_len)
+{
+ int curve;
+ uint32_t ctl;
+ size_t xoff, xlen;
+
+ curve = ctx->eng.ecdhe_curve;
+
+ /*
+ * Finalise the key exchange.
+ */
+ ctl = ctx->eng.iec->mul(cpoint, cpoint_len,
+ ctx->ecdhe_key, ctx->ecdhe_key_len, curve);
+ xoff = ctx->eng.iec->xoff(curve, &xlen);
+ ecdh_common(ctx, prf_id, cpoint + xoff, xlen, ctl);
+
+ /*
+ * Clear the ECDHE private key. Forward Secrecy is achieved insofar
+ * as that key does not get stolen, so we'd better destroy it
+ * as soon as it ceases to be useful.
+ */
+ memset(ctx->ecdhe_key, 0, ctx->ecdhe_key_len);
+}
+
+/*
+ * Offset for hash value within the pad (when obtaining all hash values,
+ * in preparation for verification of the CertificateVerify message).
+ * Order is MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512; last value
+ * is used to get the total length.
+ */
+static const unsigned char HASH_PAD_OFF[] = { 0, 16, 36, 64, 96, 144, 208 };
+
+/*
+ * OID for hash functions in RSA signatures.
+ */
+static const unsigned char HASH_OID_SHA1[] = {
+ 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
+};
+
+static const unsigned char HASH_OID_SHA224[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
+};
+
+static const unsigned char HASH_OID_SHA256[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
+};
+
+static const unsigned char HASH_OID_SHA384[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
+};
+
+static const unsigned char HASH_OID_SHA512[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
+};
+
+static const unsigned char *HASH_OID[] = {
+ HASH_OID_SHA1,
+ HASH_OID_SHA224,
+ HASH_OID_SHA256,
+ HASH_OID_SHA384,
+ HASH_OID_SHA512
+};
+
+/*
+ * Verify the signature in CertificateVerify. Returned value is 0 on
+ * success, or a non-zero error code. Lack of implementation of the
+ * designated signature algorithm is reported as a "bad signature"
+ * error (because it means that the peer did not honour our advertised
+ * set of supported signature algorithms).
+ */
+static int
+verify_CV_sig(br_ssl_server_context *ctx, size_t sig_len)
+{
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+ int id;
+
+ id = ctx->hash_CV_id;
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+ if (pk->key_type == BR_KEYTYPE_RSA) {
+ unsigned char tmp[64];
+ const unsigned char *hash_oid;
+
+ if (id == 0) {
+ hash_oid = NULL;
+ } else {
+ hash_oid = HASH_OID[id - 2];
+ }
+ if (ctx->eng.irsavrfy == 0) {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ if (!ctx->eng.irsavrfy(ctx->eng.pad, sig_len,
+ hash_oid, ctx->hash_CV_len, &pk->key.rsa, tmp)
+ || memcmp(tmp, ctx->hash_CV, ctx->hash_CV_len) != 0)
+ {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ } else {
+ if (ctx->eng.iecdsa == 0) {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ if (!ctx->eng.iecdsa(ctx->eng.iec,
+ ctx->hash_CV, ctx->hash_CV_len,
+ &pk->key.ec, ctx->eng.pad, sig_len))
+ {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ }
+ return 0;
+}
+
+
+
+static const unsigned char t0_datablock[] = {
+ 0x00, 0x00, 0x0A, 0x00, 0x24, 0x00, 0x2F, 0x01, 0x24, 0x00, 0x35, 0x02,
+ 0x24, 0x00, 0x3C, 0x01, 0x44, 0x00, 0x3D, 0x02, 0x44, 0x00, 0x9C, 0x03,
+ 0x04, 0x00, 0x9D, 0x04, 0x05, 0xC0, 0x03, 0x40, 0x24, 0xC0, 0x04, 0x41,
+ 0x24, 0xC0, 0x05, 0x42, 0x24, 0xC0, 0x08, 0x20, 0x24, 0xC0, 0x09, 0x21,
+ 0x24, 0xC0, 0x0A, 0x22, 0x24, 0xC0, 0x0D, 0x30, 0x24, 0xC0, 0x0E, 0x31,
+ 0x24, 0xC0, 0x0F, 0x32, 0x24, 0xC0, 0x12, 0x10, 0x24, 0xC0, 0x13, 0x11,
+ 0x24, 0xC0, 0x14, 0x12, 0x24, 0xC0, 0x23, 0x21, 0x44, 0xC0, 0x24, 0x22,
+ 0x55, 0xC0, 0x25, 0x41, 0x44, 0xC0, 0x26, 0x42, 0x55, 0xC0, 0x27, 0x11,
+ 0x44, 0xC0, 0x28, 0x12, 0x55, 0xC0, 0x29, 0x31, 0x44, 0xC0, 0x2A, 0x32,
+ 0x55, 0xC0, 0x2B, 0x23, 0x04, 0xC0, 0x2C, 0x24, 0x05, 0xC0, 0x2D, 0x43,
+ 0x04, 0xC0, 0x2E, 0x44, 0x05, 0xC0, 0x2F, 0x13, 0x04, 0xC0, 0x30, 0x14,
+ 0x05, 0xC0, 0x31, 0x33, 0x04, 0xC0, 0x32, 0x34, 0x05, 0xC0, 0x9C, 0x06,
+ 0x04, 0xC0, 0x9D, 0x07, 0x04, 0xC0, 0xA0, 0x08, 0x04, 0xC0, 0xA1, 0x09,
+ 0x04, 0xC0, 0xAC, 0x26, 0x04, 0xC0, 0xAD, 0x27, 0x04, 0xC0, 0xAE, 0x28,
+ 0x04, 0xC0, 0xAF, 0x29, 0x04, 0xCC, 0xA8, 0x15, 0x04, 0xCC, 0xA9, 0x25,
+ 0x04, 0x00, 0x00
+};
+
+static const unsigned char t0_codeblock[] = {
+ 0x00, 0x01, 0x00, 0x0B, 0x00, 0x00, 0x01, 0x00, 0x0E, 0x00, 0x00, 0x01,
+ 0x00, 0x0F, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01, 0x01, 0x08,
+ 0x00, 0x00, 0x01, 0x01, 0x09, 0x00, 0x00, 0x01, 0x02, 0x08, 0x00, 0x00,
+ 0x01, 0x02, 0x09, 0x00, 0x00, 0x29, 0x29, 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_CCS), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_FINISHED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_FRAGLEN), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_HANDSHAKE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_PARAM), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_SECRENEG), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_SIGNATURE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_BAD_VERSION), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_INVALID_ALGORITHM), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_LIMIT_EXCEEDED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_NO_CLIENT_AUTH), 0x00, 0x00, 0x01, T0_INT1(BR_ERR_OK),
+ 0x00, 0x00, 0x01, T0_INT1(BR_ERR_OVERSIZED_ID), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_UNEXPECTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_WRONG_KEY_USAGE), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, action)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, alert)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, application_data)), 0x00, 0x00,
+ 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, cipher_suite)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_server_context, client_max_version)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, client_random)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_server_context, client_suites)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_server_context, client_suites_num)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, close_received)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_server_context, curves)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, ecdhe_point)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, ecdhe_point_len)),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, flags)),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_server_context, hashes)),
+ 0x00, 0x00, 0x7B, 0x01,
+ T0_INT2(BR_MAX_CIPHER_SUITES * sizeof(br_suite_translated)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, log_max_frag_len)),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, pad)), 0x00,
+ 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, peer_log_max_frag_len)), 0x00,
+ 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, protocol_names_num)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, record_type_in)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, record_type_out)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, reneg)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, saved_finished)), 0x00,
+ 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, selected_protocol)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, server_name)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, server_random)), 0x00, 0x00,
+ 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, session_id)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, session_id_len)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, shutdown_recv)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_server_context, sign_hash_id)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, suites_buf)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, suites_num)), 0x00,
+ 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, session) + offsetof(br_ssl_session_parameters, version)),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_in)),
+ 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_ssl_engine_context, version_max)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_min)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(br_ssl_engine_context, version_out)),
+ 0x00, 0x00, 0x09, 0x2A, 0x5D, 0x06, 0x02, 0x6A, 0x2B, 0x00, 0x00, 0x01,
+ 0x01, 0x00, 0x01, 0x03, 0x00, 0x9B, 0x2A, 0x63, 0x47, 0x9F, 0x2A, 0x05,
+ 0x04, 0x65, 0x01, 0x00, 0x00, 0x02, 0x00, 0x0F, 0x06, 0x02, 0x9F, 0x00,
+ 0x63, 0x04, 0x6B, 0x00, 0x06, 0x02, 0x6A, 0x2B, 0x00, 0x00, 0x2A, 0x8B,
+ 0x47, 0x05, 0x03, 0x01, 0x0C, 0x08, 0x47, 0x78, 0x2E, 0xA8, 0x1C, 0x85,
+ 0x01, 0x0C, 0x33, 0x00, 0x00, 0x2A, 0x22, 0x01, 0x08, 0x0C, 0x47, 0x61,
+ 0x22, 0x08, 0x00, 0x01, 0x03, 0x00, 0x77, 0x30, 0x02, 0x00, 0x38, 0x13,
+ 0x01, 0x01, 0x0C, 0x77, 0x42, 0x2C, 0x19, 0x38, 0x06, 0x07, 0x02, 0x00,
+ 0xD0, 0x03, 0x00, 0x04, 0x75, 0x01, 0x00, 0xC7, 0x02, 0x00, 0x2A, 0x19,
+ 0x13, 0x06, 0x02, 0x71, 0x2B, 0xD0, 0x04, 0x76, 0x00, 0x01, 0x00, 0x77,
+ 0x42, 0x01, 0x16, 0x89, 0x42, 0x01, 0x00, 0x8C, 0x40, 0x36, 0xB1, 0x35,
+ 0x06, 0x02, 0x73, 0x2B, 0x06, 0x0A, 0xD7, 0x01, 0x00, 0xD3, 0x01, 0x00,
+ 0xAD, 0x04, 0x80, 0x46, 0xD7, 0xD4, 0x29, 0xD9, 0x50, 0x06, 0x01, 0xD5,
+ 0xD8, 0x2C, 0x50, 0x06, 0x31, 0x01, 0x00, 0xAE, 0x2A, 0x5D, 0x06, 0x0F,
+ 0x01, 0x02, 0xA4, 0x05, 0x02, 0x37, 0x2B, 0x29, 0xB2, 0xB0, 0x2A, 0xC9,
+ 0x29, 0x04, 0x19, 0x2A, 0x5F, 0x06, 0x0B, 0x29, 0x01, 0x02, 0xA4, 0x05,
+ 0x02, 0x70, 0x2B, 0xB2, 0x04, 0x0A, 0xB4, 0x2A, 0x05, 0x04, 0x29, 0xAB,
+ 0x04, 0x02, 0xB3, 0xAF, 0x04, 0x01, 0xB2, 0x01, 0x00, 0xAD, 0x01, 0x00,
+ 0xD3, 0x3E, 0x01, 0x01, 0x77, 0x42, 0x01, 0x17, 0x89, 0x42, 0x00, 0x00,
+ 0x3A, 0x3A, 0x00, 0x01, 0x03, 0x00, 0x2C, 0x19, 0x38, 0x06, 0x04, 0xCF,
+ 0x29, 0x04, 0x78, 0x01, 0x02, 0x02, 0x00, 0xC6, 0x19, 0x38, 0x06, 0x04,
+ 0xCF, 0x29, 0x04, 0x78, 0x02, 0x00, 0x01, 0x84, 0x00, 0x08, 0x2B, 0x00,
+ 0x00, 0x81, 0x2F, 0x47, 0x12, 0x01, 0x01, 0x13, 0x37, 0x00, 0x00, 0x2A,
+ 0x05, 0x04, 0x29, 0x01, 0x7F, 0x00, 0x01, 0x00, 0xA2, 0x12, 0x01, 0x01,
+ 0x13, 0x5F, 0x06, 0x03, 0x61, 0x04, 0x75, 0x47, 0x29, 0x00, 0x00, 0x01,
+ 0x7F, 0xA1, 0xCF, 0x2A, 0x01, 0x07, 0x13, 0x01, 0x00, 0x3A, 0x0F, 0x06,
+ 0x0D, 0x29, 0x01, 0x10, 0x13, 0x06, 0x05, 0x01, 0x00, 0x77, 0x42, 0xC5,
+ 0x04, 0x33, 0x01, 0x01, 0x3A, 0x0F, 0x06, 0x2A, 0x29, 0x29, 0x8A, 0x30,
+ 0x01, 0x01, 0x0F, 0x01, 0x01, 0xA4, 0x39, 0x06, 0x18, 0xC8, 0x2C, 0x19,
+ 0x38, 0x06, 0x04, 0xCF, 0x29, 0x04, 0x78, 0x01, 0x80, 0x64, 0xC7, 0x01,
+ 0x01, 0x77, 0x42, 0x01, 0x17, 0x89, 0x42, 0x04, 0x03, 0x01, 0x00, 0xA1,
+ 0x04, 0x03, 0x73, 0x2B, 0x29, 0x04, 0xFF, 0x32, 0x01, 0x2A, 0x03, 0x00,
+ 0x09, 0x2A, 0x5D, 0x06, 0x02, 0x6A, 0x2B, 0x02, 0x00, 0x00, 0x00, 0x9C,
+ 0x01, 0x0F, 0x13, 0x00, 0x00, 0x76, 0x30, 0x01, 0x00, 0x3A, 0x0F, 0x06,
+ 0x10, 0x29, 0x2A, 0x01, 0x01, 0x0E, 0x06, 0x03, 0x29, 0x01, 0x02, 0x76,
+ 0x42, 0x01, 0x00, 0x04, 0x21, 0x01, 0x01, 0x3A, 0x0F, 0x06, 0x14, 0x29,
+ 0x01, 0x00, 0x76, 0x42, 0x2A, 0x01, 0x80, 0x64, 0x0F, 0x06, 0x05, 0x01,
+ 0x82, 0x00, 0x08, 0x2B, 0x5F, 0x04, 0x07, 0x29, 0x01, 0x82, 0x00, 0x08,
+ 0x2B, 0x29, 0x00, 0x00, 0x01, 0x00, 0x31, 0x06, 0x05, 0x3D, 0xA9, 0x39,
+ 0x04, 0x78, 0x2A, 0x06, 0x04, 0x01, 0x01, 0x91, 0x42, 0x00, 0x00, 0x01,
+ 0x1F, 0x13, 0x01, 0x12, 0x0F, 0x05, 0x02, 0x74, 0x2B, 0x78, 0x2E, 0x2A,
+ 0xCB, 0x05, 0x02, 0x73, 0x2B, 0xA8, 0x28, 0x00, 0x02, 0x87, 0x2E, 0x05,
+ 0x02, 0xBC, 0x00, 0xC0, 0xA7, 0xC0, 0xA7, 0x01, 0x7E, 0x03, 0x00, 0x2A,
+ 0x06, 0x17, 0xC2, 0x2A, 0x03, 0x01, 0x85, 0x47, 0xB6, 0x02, 0x01, 0x51,
+ 0x2A, 0x02, 0x00, 0x53, 0x06, 0x04, 0x03, 0x00, 0x04, 0x01, 0x29, 0x04,
+ 0x66, 0x9D, 0x9D, 0x02, 0x00, 0x61, 0x8C, 0x40, 0x00, 0x00, 0x31, 0x06,
+ 0x0B, 0x88, 0x30, 0x01, 0x14, 0x0E, 0x06, 0x02, 0x73, 0x2B, 0x04, 0x11,
+ 0xCF, 0x01, 0x07, 0x13, 0x2A, 0x01, 0x02, 0x0E, 0x06, 0x06, 0x06, 0x02,
+ 0x73, 0x2B, 0x04, 0x70, 0x29, 0xC3, 0x01, 0x01, 0x0E, 0x35, 0x39, 0x06,
+ 0x02, 0x66, 0x2B, 0x2A, 0x01, 0x01, 0xCA, 0x38, 0xB5, 0x00, 0x01, 0xBA,
+ 0x01, 0x0B, 0x0F, 0x05, 0x02, 0x73, 0x2B, 0x2A, 0x01, 0x03, 0x0F, 0x06,
+ 0x08, 0xC1, 0x06, 0x02, 0x6A, 0x2B, 0x47, 0x29, 0x00, 0x47, 0x5C, 0xC1,
+ 0xA7, 0x2A, 0x06, 0x23, 0xC1, 0xA7, 0x2A, 0x5B, 0x2A, 0x06, 0x18, 0x2A,
+ 0x01, 0x82, 0x00, 0x10, 0x06, 0x05, 0x01, 0x82, 0x00, 0x04, 0x01, 0x2A,
+ 0x03, 0x00, 0x85, 0x02, 0x00, 0xB6, 0x02, 0x00, 0x58, 0x04, 0x65, 0x9D,
+ 0x59, 0x04, 0x5A, 0x9D, 0x9D, 0x5A, 0x2A, 0x06, 0x02, 0x37, 0x00, 0x29,
+ 0x2D, 0x00, 0x02, 0x2A, 0x01, 0x20, 0x13, 0x05, 0x02, 0x74, 0x2B, 0x01,
+ 0x0F, 0x13, 0x03, 0x00, 0xB0, 0x95, 0x2E, 0x01, 0x86, 0x03, 0x11, 0x06,
+ 0x23, 0xC0, 0x2A, 0x01, 0x81, 0x7F, 0x13, 0x61, 0x01, 0x01, 0x12, 0x02,
+ 0x00, 0x0F, 0x05, 0x02, 0x6C, 0x2B, 0x01, 0x08, 0x12, 0x2A, 0x01, 0x02,
+ 0x0B, 0x3A, 0x01, 0x06, 0x10, 0x39, 0x06, 0x02, 0x6E, 0x2B, 0x04, 0x0D,
+ 0x02, 0x00, 0x01, 0x01, 0x0F, 0x06, 0x04, 0x01, 0x00, 0x04, 0x02, 0x01,
+ 0x02, 0x20, 0x05, 0x02, 0x6E, 0x2B, 0xC0, 0x2A, 0x03, 0x01, 0x2A, 0x01,
+ 0x84, 0x00, 0x10, 0x06, 0x02, 0x6F, 0x2B, 0x85, 0x47, 0xB6, 0x02, 0x01,
+ 0x55, 0x2A, 0x06, 0x01, 0x2B, 0x29, 0x9D, 0x00, 0x00, 0x1D, 0xBA, 0x01,
+ 0x0F, 0x0F, 0x05, 0x02, 0x73, 0x2B, 0x00, 0x0A, 0xBA, 0x01, 0x01, 0x0F,
+ 0x05, 0x02, 0x73, 0x2B, 0xC0, 0x2A, 0x03, 0x00, 0x79, 0x40, 0x7A, 0x01,
+ 0x20, 0xB6, 0xC2, 0x2A, 0x01, 0x20, 0x10, 0x06, 0x02, 0x72, 0x2B, 0x2A,
+ 0x90, 0x42, 0x8F, 0x47, 0xB6, 0x1A, 0x03, 0x01, 0xC0, 0xA7, 0x01, 0x00,
+ 0x03, 0x02, 0x01, 0x00, 0x03, 0x03, 0x83, 0xA2, 0x17, 0x3A, 0x08, 0x03,
+ 0x04, 0x03, 0x05, 0x2A, 0x06, 0x80, 0x6D, 0xC0, 0x2A, 0x03, 0x06, 0x02,
+ 0x01, 0x06, 0x0A, 0x2A, 0x78, 0x2E, 0x0F, 0x06, 0x04, 0x01, 0x7F, 0x03,
+ 0x03, 0x2A, 0x01, 0x81, 0x7F, 0x0F, 0x06, 0x0A, 0x8A, 0x30, 0x06, 0x02,
+ 0x6B, 0x2B, 0x01, 0x7F, 0x03, 0x02, 0x2A, 0x01, 0x81, 0xAC, 0x00, 0x0F,
+ 0x06, 0x11, 0x02, 0x00, 0x98, 0x2E, 0x11, 0x02, 0x00, 0x97, 0x2E, 0x0B,
+ 0x13, 0x06, 0x04, 0x01, 0x7F, 0x03, 0x00, 0xC4, 0x2A, 0x5D, 0x06, 0x03,
+ 0x29, 0x04, 0x26, 0x01, 0x00, 0xA4, 0x06, 0x0B, 0x01, 0x02, 0x0C, 0x7B,
+ 0x08, 0x02, 0x06, 0x47, 0x40, 0x04, 0x16, 0x29, 0x02, 0x05, 0x02, 0x04,
+ 0x11, 0x06, 0x02, 0x69, 0x2B, 0x02, 0x06, 0x02, 0x05, 0x40, 0x02, 0x05,
+ 0x01, 0x04, 0x08, 0x03, 0x05, 0x04, 0xFF, 0x0F, 0x29, 0x01, 0x00, 0x03,
+ 0x07, 0xC2, 0xA7, 0x2A, 0x06, 0x09, 0xC2, 0x05, 0x04, 0x01, 0x7F, 0x03,
+ 0x07, 0x04, 0x74, 0x9D, 0x01, 0x00, 0x8D, 0x42, 0x01, 0x88, 0x04, 0x82,
+ 0x41, 0x01, 0x84, 0x80, 0x80, 0x00, 0x7E, 0x41, 0x2A, 0x06, 0x80, 0x4E,
+ 0xC0, 0xA7, 0x2A, 0x06, 0x80, 0x47, 0xC0, 0x01, 0x00, 0x3A, 0x0F, 0x06,
+ 0x04, 0x29, 0xB9, 0x04, 0x39, 0x01, 0x01, 0x3A, 0x0F, 0x06, 0x04, 0x29,
+ 0xB7, 0x04, 0x2F, 0x01, 0x83, 0xFE, 0x01, 0x3A, 0x0F, 0x06, 0x04, 0x29,
+ 0xB8, 0x04, 0x23, 0x01, 0x0D, 0x3A, 0x0F, 0x06, 0x04, 0x29, 0xBE, 0x04,
+ 0x19, 0x01, 0x0A, 0x3A, 0x0F, 0x06, 0x04, 0x29, 0xBF, 0x04, 0x0F, 0x01,
+ 0x10, 0x3A, 0x0F, 0x06, 0x04, 0x29, 0xAC, 0x04, 0x05, 0x29, 0xBC, 0x01,
+ 0x00, 0x29, 0x04, 0xFF, 0x35, 0x9D, 0x9D, 0x02, 0x01, 0x02, 0x03, 0x13,
+ 0x03, 0x01, 0x02, 0x00, 0x5D, 0x06, 0x08, 0x79, 0x2E, 0x99, 0x40, 0x01,
+ 0x80, 0x56, 0xA3, 0x97, 0x2E, 0x2A, 0x02, 0x00, 0x10, 0x06, 0x03, 0x29,
+ 0x02, 0x00, 0x2A, 0x01, 0x86, 0x00, 0x0B, 0x06, 0x02, 0x6D, 0x2B, 0x02,
+ 0x00, 0x98, 0x2E, 0x0B, 0x06, 0x04, 0x01, 0x80, 0x46, 0xA3, 0x02, 0x01,
+ 0x06, 0x10, 0x95, 0x2E, 0x02, 0x00, 0x0D, 0x06, 0x05, 0x29, 0x95, 0x2E,
+ 0x04, 0x04, 0x01, 0x00, 0x03, 0x01, 0x2A, 0x95, 0x40, 0x2A, 0x96, 0x40,
+ 0x2A, 0x99, 0x40, 0x01, 0x86, 0x03, 0x11, 0x03, 0x08, 0x02, 0x02, 0x06,
+ 0x04, 0x01, 0x02, 0x8A, 0x42, 0x8A, 0x30, 0x05, 0x04, 0x01, 0x01, 0x8A,
+ 0x42, 0x02, 0x07, 0x05, 0x03, 0x01, 0x28, 0xA3, 0x44, 0x29, 0x01, 0x82,
+ 0x01, 0x07, 0x01, 0xFC, 0x80, 0x00, 0x39, 0x82, 0x2F, 0x13, 0x2A, 0x82,
+ 0x41, 0x2A, 0x01, 0x81, 0x7F, 0x13, 0x5E, 0x37, 0x47, 0x01, 0x08, 0x12,
+ 0x5E, 0x01, 0x02, 0x13, 0x39, 0x01, 0x0C, 0x0C, 0x03, 0x09, 0x7E, 0x2F,
+ 0x43, 0x13, 0x2A, 0x7E, 0x41, 0x05, 0x04, 0x01, 0x00, 0x03, 0x09, 0x02,
+ 0x01, 0x06, 0x03, 0x01, 0x7F, 0x00, 0x8F, 0x01, 0x20, 0x34, 0x01, 0x20,
+ 0x90, 0x42, 0x7B, 0x2A, 0x03, 0x05, 0x2A, 0x02, 0x04, 0x0B, 0x06, 0x80,
+ 0x49, 0x2A, 0x2E, 0x2A, 0x9C, 0x2A, 0x01, 0x0C, 0x12, 0x2A, 0x01, 0x01,
+ 0x0F, 0x47, 0x01, 0x02, 0x0F, 0x39, 0x06, 0x0A, 0x2A, 0x02, 0x09, 0x13,
+ 0x05, 0x04, 0x65, 0x01, 0x00, 0x2A, 0x02, 0x08, 0x05, 0x0E, 0x2A, 0x01,
+ 0x81, 0x70, 0x13, 0x01, 0x20, 0x0E, 0x06, 0x04, 0x65, 0x01, 0x00, 0x2A,
+ 0x2A, 0x06, 0x10, 0x02, 0x05, 0x63, 0x40, 0x02, 0x05, 0x40, 0x02, 0x05,
+ 0x01, 0x04, 0x08, 0x03, 0x05, 0x04, 0x01, 0x65, 0x01, 0x04, 0x08, 0x04,
+ 0xFF, 0x30, 0x29, 0x02, 0x05, 0x7B, 0x09, 0x01, 0x02, 0x12, 0x2A, 0x05,
+ 0x03, 0x01, 0x28, 0xA3, 0x7C, 0x42, 0x8C, 0x2E, 0x01, 0x83, 0xFF, 0x7F,
+ 0x0F, 0x06, 0x0D, 0x01, 0x03, 0xA4, 0x06, 0x04, 0x01, 0x80, 0x78, 0xA3,
+ 0x01, 0x00, 0x8C, 0x40, 0x18, 0x05, 0x03, 0x01, 0x28, 0xA3, 0x01, 0x00,
+ 0x00, 0x00, 0xB4, 0xB3, 0x00, 0x04, 0x78, 0x2E, 0xCE, 0x06, 0x16, 0xC0,
+ 0x2A, 0x01, 0x84, 0x00, 0x10, 0x06, 0x02, 0x6F, 0x2B, 0x2A, 0x03, 0x00,
+ 0x85, 0x47, 0xB6, 0x02, 0x00, 0x78, 0x2E, 0xA8, 0x27, 0x78, 0x2E, 0x2A,
+ 0xCC, 0x47, 0xCB, 0x03, 0x01, 0x03, 0x02, 0x02, 0x01, 0x02, 0x02, 0x39,
+ 0x06, 0x14, 0xC2, 0x2A, 0x03, 0x03, 0x85, 0x47, 0xB6, 0x02, 0x03, 0x78,
+ 0x2E, 0xA8, 0x02, 0x02, 0x06, 0x03, 0x26, 0x04, 0x01, 0x24, 0x9D, 0x00,
+ 0x00, 0xBA, 0x01, 0x10, 0x0F, 0x05, 0x02, 0x73, 0x2B, 0x00, 0x00, 0x9E,
+ 0xBA, 0x01, 0x14, 0x0E, 0x06, 0x02, 0x73, 0x2B, 0x85, 0x01, 0x0C, 0x08,
+ 0x01, 0x0C, 0xB6, 0x9D, 0x85, 0x2A, 0x01, 0x0C, 0x08, 0x01, 0x0C, 0x32,
+ 0x05, 0x02, 0x67, 0x2B, 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0x02, 0x00,
+ 0x9A, 0x02, 0x01, 0x02, 0x00, 0x3C, 0x2A, 0x01, 0x00, 0x0F, 0x06, 0x02,
+ 0x65, 0x00, 0xD1, 0x04, 0x74, 0x00, 0xC0, 0x01, 0x01, 0x0E, 0x06, 0x02,
+ 0x68, 0x2B, 0xC2, 0x2A, 0x2A, 0x5F, 0x47, 0x01, 0x05, 0x11, 0x39, 0x06,
+ 0x02, 0x68, 0x2B, 0x01, 0x08, 0x08, 0x2A, 0x84, 0x30, 0x0B, 0x06, 0x0D,
+ 0x2A, 0x01, 0x01, 0x47, 0x0C, 0x3F, 0x2A, 0x84, 0x42, 0x86, 0x42, 0x04,
+ 0x01, 0x29, 0x00, 0x00, 0xC0, 0x8A, 0x30, 0x01, 0x00, 0x3A, 0x0F, 0x06,
+ 0x13, 0x29, 0x01, 0x01, 0x0F, 0x05, 0x02, 0x6B, 0x2B, 0xC2, 0x06, 0x02,
+ 0x6B, 0x2B, 0x01, 0x02, 0x8A, 0x42, 0x04, 0x28, 0x01, 0x02, 0x3A, 0x0F,
+ 0x06, 0x1F, 0x29, 0x01, 0x0D, 0x0F, 0x05, 0x02, 0x6B, 0x2B, 0xC2, 0x01,
+ 0x0C, 0x0F, 0x05, 0x02, 0x6B, 0x2B, 0x85, 0x01, 0x0C, 0xB6, 0x8B, 0x85,
+ 0x01, 0x0C, 0x32, 0x05, 0x02, 0x6B, 0x2B, 0x04, 0x03, 0x6B, 0x2B, 0x29,
+ 0x00, 0x00, 0xC0, 0xA7, 0xC0, 0xA7, 0x2A, 0x06, 0x1D, 0xC2, 0x06, 0x03,
+ 0xBC, 0x04, 0x15, 0xC0, 0x2A, 0x01, 0x81, 0x7F, 0x0D, 0x06, 0x0C, 0x2A,
+ 0x8D, 0x08, 0x01, 0x00, 0x47, 0x42, 0x8D, 0x47, 0xB6, 0x04, 0x01, 0xC9,
+ 0x04, 0x60, 0x9D, 0x9D, 0x00, 0x00, 0xBB, 0x2A, 0x5F, 0x06, 0x07, 0x29,
+ 0x06, 0x02, 0x69, 0x2B, 0x04, 0x74, 0x00, 0x00, 0xC3, 0x01, 0x03, 0xC1,
+ 0x47, 0x29, 0x47, 0x00, 0x00, 0xC0, 0xC9, 0x00, 0x03, 0x01, 0x00, 0x03,
+ 0x00, 0xC0, 0xA7, 0x2A, 0x06, 0x80, 0x50, 0xC2, 0x03, 0x01, 0xC2, 0x03,
+ 0x02, 0x02, 0x01, 0x01, 0x08, 0x0F, 0x06, 0x16, 0x02, 0x02, 0x01, 0x0F,
+ 0x0D, 0x06, 0x0D, 0x01, 0x01, 0x02, 0x02, 0x01, 0x10, 0x08, 0x0C, 0x02,
+ 0x00, 0x39, 0x03, 0x00, 0x04, 0x2A, 0x02, 0x01, 0x01, 0x02, 0x11, 0x02,
+ 0x01, 0x01, 0x06, 0x0D, 0x13, 0x02, 0x02, 0x01, 0x01, 0x0F, 0x02, 0x02,
+ 0x01, 0x03, 0x0F, 0x39, 0x13, 0x06, 0x11, 0x02, 0x00, 0x01, 0x01, 0x02,
+ 0x02, 0x62, 0x01, 0x02, 0x0C, 0x02, 0x01, 0x08, 0x0C, 0x39, 0x03, 0x00,
+ 0x04, 0xFF, 0x2C, 0x9D, 0x02, 0x00, 0x00, 0x00, 0xC0, 0xA7, 0xBD, 0x82,
+ 0x41, 0x9D, 0x00, 0x00, 0xC0, 0xA7, 0xC0, 0xA7, 0x01, 0x00, 0x7E, 0x41,
+ 0x2A, 0x06, 0x15, 0xC0, 0x2A, 0x01, 0x20, 0x0B, 0x06, 0x0B, 0x01, 0x01,
+ 0x47, 0x0C, 0x7E, 0x2F, 0x39, 0x7E, 0x41, 0x04, 0x01, 0x29, 0x04, 0x68,
+ 0x9D, 0x9D, 0x00, 0x00, 0x01, 0x02, 0x9A, 0xC3, 0x01, 0x08, 0x0C, 0xC3,
+ 0x08, 0x00, 0x00, 0x01, 0x03, 0x9A, 0xC3, 0x01, 0x08, 0x0C, 0xC3, 0x08,
+ 0x01, 0x08, 0x0C, 0xC3, 0x08, 0x00, 0x00, 0x01, 0x01, 0x9A, 0xC3, 0x00,
+ 0x00, 0x3D, 0x2A, 0x5D, 0x05, 0x01, 0x00, 0x29, 0xD1, 0x04, 0x76, 0x02,
+ 0x03, 0x00, 0x94, 0x30, 0x03, 0x01, 0x01, 0x00, 0x2A, 0x02, 0x01, 0x0B,
+ 0x06, 0x10, 0x2A, 0x01, 0x01, 0x0C, 0x93, 0x08, 0x2E, 0x02, 0x00, 0x0F,
+ 0x06, 0x01, 0x00, 0x61, 0x04, 0x6A, 0x29, 0x01, 0x7F, 0x00, 0x00, 0x2C,
+ 0x19, 0x38, 0x06, 0x04, 0xCF, 0x29, 0x04, 0x78, 0x01, 0x16, 0x89, 0x42,
+ 0x01, 0x00, 0xE2, 0x01, 0x00, 0xE1, 0x2C, 0x01, 0x17, 0x89, 0x42, 0x00,
+ 0x00, 0x01, 0x15, 0x89, 0x42, 0x47, 0x57, 0x29, 0x57, 0x29, 0x2C, 0x00,
+ 0x00, 0x01, 0x01, 0x47, 0xC6, 0x00, 0x00, 0xBB, 0x01, 0x01, 0x0F, 0x05,
+ 0x02, 0x73, 0x2B, 0x2A, 0xC9, 0x29, 0x00, 0x00, 0x47, 0x3A, 0x9A, 0x47,
+ 0x2A, 0x06, 0x05, 0xC3, 0x29, 0x62, 0x04, 0x78, 0x29, 0x00, 0x02, 0x03,
+ 0x00, 0x78, 0x2E, 0x9C, 0x03, 0x01, 0x02, 0x01, 0x01, 0x0F, 0x13, 0x02,
+ 0x01, 0x01, 0x04, 0x12, 0x01, 0x0F, 0x13, 0x02, 0x01, 0x01, 0x08, 0x12,
+ 0x01, 0x0F, 0x13, 0x01, 0x00, 0x3A, 0x0F, 0x06, 0x10, 0x29, 0x01, 0x00,
+ 0x01, 0x18, 0x02, 0x00, 0x06, 0x03, 0x4C, 0x04, 0x01, 0x4D, 0x04, 0x81,
+ 0x0D, 0x01, 0x01, 0x3A, 0x0F, 0x06, 0x10, 0x29, 0x01, 0x01, 0x01, 0x10,
+ 0x02, 0x00, 0x06, 0x03, 0x4C, 0x04, 0x01, 0x4D, 0x04, 0x80, 0x77, 0x01,
+ 0x02, 0x3A, 0x0F, 0x06, 0x10, 0x29, 0x01, 0x01, 0x01, 0x20, 0x02, 0x00,
+ 0x06, 0x03, 0x4C, 0x04, 0x01, 0x4D, 0x04, 0x80, 0x61, 0x01, 0x03, 0x3A,
+ 0x0F, 0x06, 0x0F, 0x29, 0x29, 0x01, 0x10, 0x02, 0x00, 0x06, 0x03, 0x4A,
+ 0x04, 0x01, 0x4B, 0x04, 0x80, 0x4C, 0x01, 0x04, 0x3A, 0x0F, 0x06, 0x0E,
+ 0x29, 0x29, 0x01, 0x20, 0x02, 0x00, 0x06, 0x03, 0x4A, 0x04, 0x01, 0x4B,
+ 0x04, 0x38, 0x01, 0x05, 0x3A, 0x0F, 0x06, 0x0C, 0x29, 0x29, 0x02, 0x00,
+ 0x06, 0x03, 0x4E, 0x04, 0x01, 0x4F, 0x04, 0x26, 0x2A, 0x01, 0x09, 0x10,
+ 0x06, 0x02, 0x6A, 0x2B, 0x47, 0x29, 0x2A, 0x01, 0x01, 0x13, 0x01, 0x04,
+ 0x0C, 0x01, 0x10, 0x08, 0x47, 0x01, 0x08, 0x13, 0x01, 0x10, 0x47, 0x09,
+ 0x02, 0x00, 0x06, 0x03, 0x48, 0x04, 0x01, 0x49, 0x00, 0x29, 0x00, 0x00,
+ 0x9C, 0x01, 0x0C, 0x12, 0x01, 0x02, 0x10, 0x00, 0x00, 0x9C, 0x01, 0x0C,
+ 0x12, 0x2A, 0x60, 0x47, 0x01, 0x03, 0x0B, 0x13, 0x00, 0x00, 0x9C, 0x01,
+ 0x0C, 0x12, 0x01, 0x01, 0x0F, 0x00, 0x00, 0x9C, 0x01, 0x0C, 0x12, 0x5F,
+ 0x00, 0x00, 0x1B, 0x01, 0x00, 0x75, 0x30, 0x2A, 0x06, 0x22, 0x01, 0x01,
+ 0x3A, 0x0F, 0x06, 0x06, 0x29, 0x01, 0x00, 0xA0, 0x04, 0x14, 0x01, 0x02,
+ 0x3A, 0x0F, 0x06, 0x0D, 0x29, 0x77, 0x30, 0x01, 0x01, 0x0F, 0x06, 0x03,
+ 0x01, 0x10, 0x39, 0x04, 0x01, 0x29, 0x04, 0x01, 0x29, 0x7D, 0x30, 0x05,
+ 0x33, 0x31, 0x06, 0x30, 0x88, 0x30, 0x01, 0x14, 0x3A, 0x0F, 0x06, 0x06,
+ 0x29, 0x01, 0x02, 0x39, 0x04, 0x22, 0x01, 0x15, 0x3A, 0x0F, 0x06, 0x09,
+ 0x29, 0xAA, 0x06, 0x03, 0x01, 0x7F, 0xA0, 0x04, 0x13, 0x01, 0x16, 0x3A,
+ 0x0F, 0x06, 0x06, 0x29, 0x01, 0x01, 0x39, 0x04, 0x07, 0x29, 0x01, 0x04,
+ 0x39, 0x01, 0x00, 0x29, 0x19, 0x06, 0x03, 0x01, 0x08, 0x39, 0x00, 0x00,
+ 0x1B, 0x2A, 0x05, 0x13, 0x31, 0x06, 0x10, 0x88, 0x30, 0x01, 0x15, 0x0F,
+ 0x06, 0x08, 0x29, 0xAA, 0x01, 0x00, 0x77, 0x42, 0x04, 0x01, 0x23, 0x00,
+ 0x00, 0xCF, 0x01, 0x07, 0x13, 0x01, 0x01, 0x10, 0x06, 0x02, 0x73, 0x2B,
+ 0x00, 0x01, 0x03, 0x00, 0x2C, 0x19, 0x06, 0x05, 0x02, 0x00, 0x89, 0x42,
+ 0x00, 0xCF, 0x29, 0x04, 0x74, 0x00, 0x01, 0x14, 0xD2, 0x01, 0x01, 0xE2,
+ 0x2C, 0x2A, 0x01, 0x00, 0xCA, 0x01, 0x16, 0xD2, 0xD6, 0x2C, 0x00, 0x00,
+ 0x01, 0x0B, 0xE2, 0x52, 0x2A, 0x2A, 0x01, 0x03, 0x08, 0xE1, 0xE1, 0x14,
+ 0x2A, 0x5D, 0x06, 0x02, 0x29, 0x00, 0xE1, 0x1E, 0x2A, 0x06, 0x05, 0x85,
+ 0x47, 0xDA, 0x04, 0x77, 0x29, 0x04, 0x6C, 0x00, 0x01, 0x00, 0xDC, 0x95,
+ 0x2E, 0x01, 0x86, 0x03, 0x11, 0x06, 0x05, 0x63, 0x01, 0x00, 0xDD, 0x08,
+ 0x50, 0x08, 0x01, 0x03, 0x08, 0x01, 0x0D, 0xE2, 0xE1, 0x01, 0x00, 0xDC,
+ 0xE2, 0x01, 0x01, 0xDC, 0x29, 0x95, 0x2E, 0x01, 0x86, 0x03, 0x11, 0x06,
+ 0x08, 0x01, 0x00, 0xDD, 0xE0, 0x01, 0x01, 0xDD, 0x29, 0x50, 0xE0, 0x16,
+ 0x15, 0x2A, 0x5D, 0x06, 0x02, 0x29, 0x00, 0xE0, 0x1F, 0x2A, 0x06, 0x05,
+ 0x85, 0x47, 0xDA, 0x04, 0x77, 0x29, 0x04, 0x6C, 0x00, 0x9E, 0x01, 0x14,
+ 0xE2, 0x01, 0x0C, 0xE1, 0x85, 0x01, 0x0C, 0xDA, 0x00, 0x04, 0x03, 0x00,
+ 0x01, 0x02, 0xE2, 0x01, 0x80, 0x46, 0x8A, 0x30, 0x01, 0x02, 0x0F, 0x06,
+ 0x0C, 0x02, 0x00, 0x06, 0x04, 0x01, 0x05, 0x04, 0x02, 0x01, 0x1D, 0x04,
+ 0x02, 0x01, 0x00, 0x03, 0x01, 0x86, 0x30, 0x06, 0x04, 0x01, 0x05, 0x04,
+ 0x02, 0x01, 0x00, 0x03, 0x02, 0x8C, 0x2E, 0x2A, 0x06, 0x05, 0x62, 0x21,
+ 0x01, 0x07, 0x08, 0x03, 0x03, 0x02, 0x01, 0x02, 0x02, 0x08, 0x02, 0x03,
+ 0x08, 0x2A, 0x06, 0x03, 0x01, 0x02, 0x08, 0x08, 0xE1, 0x95, 0x2E, 0xE0,
+ 0x8E, 0x01, 0x04, 0x17, 0x8E, 0x01, 0x04, 0x08, 0x01, 0x1C, 0x34, 0x8E,
+ 0x01, 0x20, 0xDA, 0x01, 0x20, 0xE2, 0x8F, 0x01, 0x20, 0xDA, 0x78, 0x2E,
+ 0xE0, 0x01, 0x00, 0xE2, 0x02, 0x01, 0x02, 0x02, 0x08, 0x02, 0x03, 0x08,
+ 0x2A, 0x06, 0x80, 0x40, 0xE0, 0x02, 0x01, 0x2A, 0x06, 0x10, 0x01, 0x83,
+ 0xFE, 0x01, 0xE0, 0x01, 0x04, 0x09, 0x2A, 0xE0, 0x62, 0x8B, 0x47, 0xDB,
+ 0x04, 0x01, 0x29, 0x02, 0x02, 0x06, 0x0C, 0x01, 0x01, 0xE0, 0x01, 0x01,
+ 0xE0, 0x86, 0x30, 0x01, 0x08, 0x09, 0xE2, 0x02, 0x03, 0x2A, 0x06, 0x11,
+ 0x01, 0x10, 0xE0, 0x01, 0x04, 0x09, 0x2A, 0xE0, 0x64, 0x2A, 0xE0, 0x62,
+ 0x85, 0x47, 0xDB, 0x04, 0x01, 0x29, 0x04, 0x01, 0x29, 0x00, 0x00, 0x01,
+ 0x0E, 0xE2, 0x01, 0x00, 0xE1, 0x00, 0x03, 0x78, 0x2E, 0xCC, 0x05, 0x01,
+ 0x00, 0x7E, 0x2F, 0x2A, 0x01, 0x82, 0x80, 0x80, 0x80, 0x00, 0x13, 0x06,
+ 0x05, 0x29, 0x01, 0x1D, 0x04, 0x0E, 0x2A, 0x01, 0x83, 0xC0, 0x80, 0x80,
+ 0x00, 0x13, 0x2A, 0x06, 0x01, 0x47, 0x29, 0xA5, 0x03, 0x00, 0x02, 0x00,
+ 0x25, 0x2A, 0x5D, 0x06, 0x02, 0x37, 0x2B, 0x03, 0x01, 0x95, 0x2E, 0x01,
+ 0x86, 0x03, 0x11, 0x03, 0x02, 0x01, 0x0C, 0xE2, 0x02, 0x01, 0x80, 0x30,
+ 0x08, 0x02, 0x02, 0x01, 0x02, 0x13, 0x08, 0x01, 0x06, 0x08, 0xE1, 0x01,
+ 0x03, 0xE2, 0x02, 0x00, 0xE0, 0x7F, 0x80, 0x30, 0xDB, 0x02, 0x02, 0x06,
+ 0x1C, 0x92, 0x2E, 0x2A, 0x01, 0x83, 0xFE, 0x00, 0x0B, 0x06, 0x03, 0xE0,
+ 0x04, 0x0F, 0x01, 0x81, 0x7F, 0x13, 0xE2, 0x78, 0x2E, 0xCD, 0x01, 0x01,
+ 0x0C, 0x01, 0x03, 0x08, 0xE2, 0x02, 0x01, 0xE0, 0x85, 0x02, 0x01, 0xDA,
+ 0x00, 0x00, 0x56, 0x2A, 0x01, 0x00, 0x0F, 0x06, 0x02, 0x65, 0x00, 0xCF,
+ 0x29, 0x04, 0x73, 0x00, 0x2A, 0xE2, 0xDA, 0x00, 0x00, 0x01, 0x00, 0x78,
+ 0x2E, 0xCB, 0x06, 0x0C, 0x63, 0x3A, 0x06, 0x08, 0x01, 0x80, 0x41, 0xE2,
+ 0x01, 0x80, 0x42, 0xE2, 0x46, 0x06, 0x07, 0x61, 0x3A, 0x06, 0x03, 0x01,
+ 0x01, 0xE2, 0x45, 0x06, 0x08, 0x61, 0x3A, 0x06, 0x04, 0x01, 0x80, 0x40,
+ 0xE2, 0x47, 0x29, 0x00, 0x01, 0x01, 0x00, 0x03, 0x00, 0x46, 0x45, 0x39,
+ 0x05, 0x14, 0x01, 0x01, 0x01, 0x80, 0x7C, 0xDE, 0x03, 0x00, 0x01, 0x03,
+ 0x01, 0x80, 0x7C, 0xDE, 0x02, 0x00, 0x08, 0x47, 0x29, 0x00, 0x46, 0x06,
+ 0x07, 0x01, 0x01, 0x44, 0x29, 0xDE, 0x03, 0x00, 0x45, 0x06, 0x0A, 0x01,
+ 0x03, 0x44, 0x29, 0xDE, 0x02, 0x00, 0x08, 0x03, 0x00, 0x29, 0x02, 0x00,
+ 0x00, 0x00, 0x01, 0x00, 0x01, 0x04, 0xDF, 0x01, 0x05, 0xDF, 0x01, 0x06,
+ 0xDF, 0x01, 0x03, 0xDF, 0x01, 0x02, 0xDF, 0x0A, 0x65, 0x00, 0x01, 0x03,
+ 0x00, 0x3A, 0x01, 0x01, 0x02, 0x00, 0x0C, 0x13, 0x05, 0x01, 0x00, 0x63,
+ 0x01, 0x03, 0x3B, 0x06, 0x07, 0x02, 0x00, 0xE2, 0x01, 0x02, 0x3B, 0xE2,
+ 0x00, 0x00, 0x2A, 0x01, 0x08, 0x54, 0xE2, 0xE2, 0x00, 0x00, 0x2A, 0x01,
+ 0x10, 0x54, 0xE2, 0xE0, 0x00, 0x00, 0x2A, 0x57, 0x06, 0x02, 0x29, 0x00,
+ 0xCF, 0x29, 0x04, 0x76
+};
+
+static const uint16_t t0_caddr[] = {
+ 0,
+ 5,
+ 10,
+ 15,
+ 20,
+ 25,
+ 30,
+ 35,
+ 40,
+ 44,
+ 48,
+ 52,
+ 56,
+ 60,
+ 64,
+ 68,
+ 72,
+ 76,
+ 80,
+ 84,
+ 88,
+ 92,
+ 96,
+ 100,
+ 104,
+ 109,
+ 114,
+ 119,
+ 124,
+ 129,
+ 134,
+ 139,
+ 144,
+ 149,
+ 154,
+ 159,
+ 164,
+ 169,
+ 174,
+ 180,
+ 185,
+ 190,
+ 195,
+ 200,
+ 205,
+ 210,
+ 215,
+ 220,
+ 225,
+ 230,
+ 235,
+ 240,
+ 245,
+ 250,
+ 255,
+ 260,
+ 265,
+ 270,
+ 275,
+ 280,
+ 285,
+ 290,
+ 299,
+ 303,
+ 328,
+ 334,
+ 353,
+ 364,
+ 405,
+ 516,
+ 520,
+ 553,
+ 563,
+ 587,
+ 669,
+ 683,
+ 689,
+ 748,
+ 767,
+ 789,
+ 838,
+ 887,
+ 963,
+ 1065,
+ 1076,
+ 1670,
+ 1674,
+ 1741,
+ 1751,
+ 1782,
+ 1806,
+ 1852,
+ 1922,
+ 1962,
+ 1976,
+ 1985,
+ 1989,
+ 2084,
+ 2092,
+ 2128,
+ 2139,
+ 2155,
+ 2161,
+ 2172,
+ 2207,
+ 2233,
+ 2245,
+ 2251,
+ 2264,
+ 2279,
+ 2472,
+ 2481,
+ 2494,
+ 2503,
+ 2510,
+ 2616,
+ 2641,
+ 2654,
+ 2670,
+ 2688,
+ 2720,
+ 2793,
+ 2806,
+ 2987,
+ 2995,
+ 3122,
+ 3136,
+ 3141,
+ 3185,
+ 3242,
+ 3263,
+ 3290,
+ 3298,
+ 3306
+};
+
+#define T0_INTERPRETED 93
+
+#define T0_ENTER(ip, rp, slot) do { \
+ const unsigned char *t0_newip; \
+ uint32_t t0_lnum; \
+ t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \
+ t0_lnum = t0_parse7E_unsigned(&t0_newip); \
+ (rp) += t0_lnum; \
+ *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \
+ (ip) = t0_newip; \
+ } while (0)
+
+#define T0_DEFENTRY(name, slot) \
+void \
+name(void *ctx) \
+{ \
+ t0_context *t0ctx = ctx; \
+ t0ctx->ip = &t0_codeblock[0]; \
+ T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
+}
+
+T0_DEFENTRY(br_ssl_hs_server_init_main, 166)
+
+#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++)
+
+void
+br_ssl_hs_server_run(void *t0ctx)
+{
+ uint32_t *dp, *rp;
+ const unsigned char *ip;
+
+#define T0_LOCAL(x) (*(rp - 2 - (x)))
+#define T0_POP() (*-- dp)
+#define T0_POPi() (*(int32_t *)(-- dp))
+#define T0_PEEK(x) (*(dp - 1 - (x)))
+#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x)))
+#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0)
+#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0)
+#define T0_RPOP() (*-- rp)
+#define T0_RPOPi() (*(int32_t *)(-- rp))
+#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0)
+#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0)
+#define T0_ROLL(x) do { \
+ size_t t0len = (size_t)(x); \
+ uint32_t t0tmp = *(dp - 1 - t0len); \
+ memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_SWAP() do { \
+ uint32_t t0tmp = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_ROT() do { \
+ uint32_t t0tmp = *(dp - 3); \
+ *(dp - 3) = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_NROT() do { \
+ uint32_t t0tmp = *(dp - 1); \
+ *(dp - 1) = *(dp - 2); \
+ *(dp - 2) = *(dp - 3); \
+ *(dp - 3) = t0tmp; \
+} while (0)
+#define T0_PICK(x) do { \
+ uint32_t t0depth = (x); \
+ T0_PUSH(T0_PEEK(t0depth)); \
+} while (0)
+#define T0_CO() do { \
+ goto t0_exit; \
+} while (0)
+#define T0_RET() goto t0_next
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ goto t0_next;
+ for (;;) {
+ uint32_t t0x;
+
+ t0_next:
+ t0x = T0_NEXT(&ip);
+ if (t0x < T0_INTERPRETED) {
+ switch (t0x) {
+ int32_t t0off;
+
+ case 0: /* ret */
+ t0x = T0_RPOP();
+ rp -= (t0x >> 16);
+ t0x &= 0xFFFF;
+ if (t0x == 0) {
+ ip = NULL;
+ goto t0_exit;
+ }
+ ip = &t0_codeblock[t0x];
+ break;
+ case 1: /* literal constant */
+ T0_PUSHi(t0_parse7E_signed(&ip));
+ break;
+ case 2: /* read local */
+ T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip)));
+ break;
+ case 3: /* write local */
+ T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP();
+ break;
+ case 4: /* jump */
+ t0off = t0_parse7E_signed(&ip);
+ ip += t0off;
+ break;
+ case 5: /* jump if */
+ t0off = t0_parse7E_signed(&ip);
+ if (T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 6: /* jump if not */
+ t0off = t0_parse7E_signed(&ip);
+ if (!T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 7: {
+ /* * */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a * b);
+
+ }
+ break;
+ case 8: {
+ /* + */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a + b);
+
+ }
+ break;
+ case 9: {
+ /* - */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a - b);
+
+ }
+ break;
+ case 10: {
+ /* -rot */
+ T0_NROT();
+ }
+ break;
+ case 11: {
+ /* < */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a < b));
+
+ }
+ break;
+ case 12: {
+ /* << */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x << c);
+
+ }
+ break;
+ case 13: {
+ /* <= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a <= b));
+
+ }
+ break;
+ case 14: {
+ /* <> */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a != b));
+
+ }
+ break;
+ case 15: {
+ /* = */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a == b));
+
+ }
+ break;
+ case 16: {
+ /* > */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a > b));
+
+ }
+ break;
+ case 17: {
+ /* >= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a >= b));
+
+ }
+ break;
+ case 18: {
+ /* >> */
+
+ int c = (int)T0_POPi();
+ int32_t x = T0_POPi();
+ T0_PUSHi(x >> c);
+
+ }
+ break;
+ case 19: {
+ /* and */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a & b);
+
+ }
+ break;
+ case 20: {
+ /* begin-cert */
+
+ if (ENG->chain_len == 0) {
+ T0_PUSHi(-1);
+ } else {
+ ENG->cert_cur = ENG->chain->data;
+ ENG->cert_len = ENG->chain->data_len;
+ ENG->chain ++;
+ ENG->chain_len --;
+ T0_PUSH(ENG->cert_len);
+ }
+
+ }
+ break;
+ case 21: {
+ /* begin-ta-name */
+
+ const br_x500_name *dn;
+ if (CTX->cur_dn_index >= CTX->num_tas) {
+ T0_PUSHi(-1);
+ } else {
+ if (CTX->ta_names == NULL) {
+ dn = &CTX->tas[CTX->cur_dn_index].dn;
+ } else {
+ dn = &CTX->ta_names[CTX->cur_dn_index];
+ }
+ CTX->cur_dn_index ++;
+ CTX->cur_dn = dn->data;
+ CTX->cur_dn_len = dn->len;
+ T0_PUSH(CTX->cur_dn_len);
+ }
+
+ }
+ break;
+ case 22: {
+ /* begin-ta-name-list */
+
+ CTX->cur_dn_index = 0;
+
+ }
+ break;
+ case 23: {
+ /* bzero */
+
+ size_t len = (size_t)T0_POP();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ memset(addr, 0, len);
+
+ }
+ break;
+ case 24: {
+ /* call-policy-handler */
+
+ int x;
+ br_ssl_server_choices choices;
+
+ x = (*CTX->policy_vtable)->choose(
+ CTX->policy_vtable, CTX, &choices);
+ ENG->session.cipher_suite = choices.cipher_suite;
+ CTX->sign_hash_id = choices.algo_id;
+ ENG->chain = choices.chain;
+ ENG->chain_len = choices.chain_len;
+ T0_PUSHi(-(x != 0));
+
+ }
+ break;
+ case 25: {
+ /* can-output? */
+
+ T0_PUSHi(-(ENG->hlen_out > 0));
+
+ }
+ break;
+ case 26: {
+ /* check-resume */
+
+ if (ENG->session.session_id_len == 32
+ && CTX->cache_vtable != NULL && (*CTX->cache_vtable)->load(
+ CTX->cache_vtable, CTX, &ENG->session))
+ {
+ T0_PUSHi(-1);
+ } else {
+ T0_PUSH(0);
+ }
+
+ }
+ break;
+ case 27: {
+ /* co */
+ T0_CO();
+ }
+ break;
+ case 28: {
+ /* compute-Finished-inner */
+
+ int prf_id = T0_POP();
+ int from_client = T0_POPi();
+ unsigned char tmp[48];
+ br_tls_prf_seed_chunk seed;
+
+ br_tls_prf_impl prf = br_ssl_engine_get_PRF(ENG, prf_id);
+ seed.data = tmp;
+ if (ENG->session.version >= BR_TLS12) {
+ seed.len = br_multihash_out(&ENG->mhash, prf_id, tmp);
+ } else {
+ br_multihash_out(&ENG->mhash, br_md5_ID, tmp);
+ br_multihash_out(&ENG->mhash, br_sha1_ID, tmp + 16);
+ seed.len = 36;
+ }
+ prf(ENG->pad, 12, ENG->session.master_secret,
+ sizeof ENG->session.master_secret,
+ from_client ? "client finished" : "server finished",
+ 1, &seed);
+
+ }
+ break;
+ case 29: {
+ /* compute-hash-CV */
+
+ int i;
+
+ for (i = 1; i <= 6; i ++) {
+ br_multihash_out(&ENG->mhash, i,
+ ENG->pad + HASH_PAD_OFF[i - 1]);
+ }
+
+ }
+ break;
+ case 30: {
+ /* copy-cert-chunk */
+
+ size_t clen;
+
+ clen = ENG->cert_len;
+ if (clen > sizeof ENG->pad) {
+ clen = sizeof ENG->pad;
+ }
+ memcpy(ENG->pad, ENG->cert_cur, clen);
+ ENG->cert_cur += clen;
+ ENG->cert_len -= clen;
+ T0_PUSH(clen);
+
+ }
+ break;
+ case 31: {
+ /* copy-dn-chunk */
+
+ size_t clen;
+
+ clen = CTX->cur_dn_len;
+ if (clen > sizeof ENG->pad) {
+ clen = sizeof ENG->pad;
+ }
+ memcpy(ENG->pad, CTX->cur_dn, clen);
+ CTX->cur_dn += clen;
+ CTX->cur_dn_len -= clen;
+ T0_PUSH(clen);
+
+ }
+ break;
+ case 32: {
+ /* copy-hash-CV */
+
+ int id = T0_POP();
+ size_t off, len;
+
+ if (id == 0) {
+ off = 0;
+ len = 36;
+ } else {
+ if (br_multihash_getimpl(&ENG->mhash, id) == 0) {
+ T0_PUSH(0);
+ T0_RET();
+ }
+ off = HASH_PAD_OFF[id - 1];
+ len = HASH_PAD_OFF[id] - off;
+ }
+ memcpy(CTX->hash_CV, ENG->pad + off, len);
+ CTX->hash_CV_len = len;
+ CTX->hash_CV_id = id;
+ T0_PUSHi(-1);
+
+ }
+ break;
+ case 33: {
+ /* copy-protocol-name */
+
+ size_t idx = T0_POP();
+ size_t len = strlen(ENG->protocol_names[idx]);
+ memcpy(ENG->pad, ENG->protocol_names[idx], len);
+ T0_PUSH(len);
+
+ }
+ break;
+ case 34: {
+ /* data-get8 */
+
+ size_t addr = T0_POP();
+ T0_PUSH(t0_datablock[addr]);
+
+ }
+ break;
+ case 35: {
+ /* discard-input */
+
+ ENG->hlen_in = 0;
+
+ }
+ break;
+ case 36: {
+ /* do-ecdh */
+
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_ecdh(CTX, prf_id, ENG->pad, len);
+
+ }
+ break;
+ case 37: {
+ /* do-ecdhe-part1 */
+
+ int curve = T0_POPi();
+ T0_PUSHi(do_ecdhe_part1(CTX, curve));
+
+ }
+ break;
+ case 38: {
+ /* do-ecdhe-part2 */
+
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_ecdhe_part2(CTX, prf_id, ENG->pad, len);
+
+ }
+ break;
+ case 39: {
+ /* do-rsa-decrypt */
+
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_rsa_decrypt(CTX, prf_id, ENG->pad, len);
+
+ }
+ break;
+ case 40: {
+ /* do-static-ecdh */
+
+ do_static_ecdh(CTX, T0_POP());
+
+ }
+ break;
+ case 41: {
+ /* drop */
+ (void)T0_POP();
+ }
+ break;
+ case 42: {
+ /* dup */
+ T0_PUSH(T0_PEEK(0));
+ }
+ break;
+ case 43: {
+ /* fail */
+
+ br_ssl_engine_fail(ENG, (int)T0_POPi());
+ T0_CO();
+
+ }
+ break;
+ case 44: {
+ /* flush-record */
+
+ br_ssl_engine_flush_record(ENG);
+
+ }
+ break;
+ case 45: {
+ /* get-key-type-usages */
+
+ const br_x509_class *xc;
+ const br_x509_pkey *pk;
+ unsigned usages;
+
+ xc = *(ENG->x509ctx);
+ pk = xc->get_pkey(ENG->x509ctx, &usages);
+ if (pk == NULL) {
+ T0_PUSH(0);
+ } else {
+ T0_PUSH(pk->key_type | usages);
+ }
+
+ }
+ break;
+ case 46: {
+ /* get16 */
+
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*(uint16_t *)(void *)((unsigned char *)ENG + addr));
+
+ }
+ break;
+ case 47: {
+ /* get32 */
+
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*(uint32_t *)(void *)((unsigned char *)ENG + addr));
+
+ }
+ break;
+ case 48: {
+ /* get8 */
+
+ size_t addr = (size_t)T0_POP();
+ T0_PUSH(*((unsigned char *)ENG + addr));
+
+ }
+ break;
+ case 49: {
+ /* has-input? */
+
+ T0_PUSHi(-(ENG->hlen_in != 0));
+
+ }
+ break;
+ case 50: {
+ /* memcmp */
+
+ size_t len = (size_t)T0_POP();
+ void *addr2 = (unsigned char *)ENG + (size_t)T0_POP();
+ void *addr1 = (unsigned char *)ENG + (size_t)T0_POP();
+ int x = memcmp(addr1, addr2, len);
+ T0_PUSH((uint32_t)-(x == 0));
+
+ }
+ break;
+ case 51: {
+ /* memcpy */
+
+ size_t len = (size_t)T0_POP();
+ void *src = (unsigned char *)ENG + (size_t)T0_POP();
+ void *dst = (unsigned char *)ENG + (size_t)T0_POP();
+ memcpy(dst, src, len);
+
+ }
+ break;
+ case 52: {
+ /* mkrand */
+
+ size_t len = (size_t)T0_POP();
+ void *addr = (unsigned char *)ENG + (size_t)T0_POP();
+ br_hmac_drbg_generate(&ENG->rng, addr, len);
+
+ }
+ break;
+ case 53: {
+ /* more-incoming-bytes? */
+
+ T0_PUSHi(ENG->hlen_in != 0 || !br_ssl_engine_recvrec_finished(ENG));
+
+ }
+ break;
+ case 54: {
+ /* multihash-init */
+
+ br_multihash_init(&ENG->mhash);
+
+ }
+ break;
+ case 55: {
+ /* neg */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(-a);
+
+ }
+ break;
+ case 56: {
+ /* not */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(~a);
+
+ }
+ break;
+ case 57: {
+ /* or */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a | b);
+
+ }
+ break;
+ case 58: {
+ /* over */
+ T0_PUSH(T0_PEEK(1));
+ }
+ break;
+ case 59: {
+ /* pick */
+ T0_PICK(T0_POP());
+ }
+ break;
+ case 60: {
+ /* read-chunk-native */
+
+ size_t clen = ENG->hlen_in;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy((unsigned char *)ENG + addr, ENG->hbuf_in, clen);
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_in, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_in += clen;
+ ENG->hlen_in -= clen;
+ }
+
+ }
+ break;
+ case 61: {
+ /* read8-native */
+
+ if (ENG->hlen_in > 0) {
+ unsigned char x;
+
+ x = *ENG->hbuf_in ++;
+ if (ENG->record_type_in == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ T0_PUSH(x);
+ ENG->hlen_in --;
+ } else {
+ T0_PUSHi(-1);
+ }
+
+ }
+ break;
+ case 62: {
+ /* save-session */
+
+ if (CTX->cache_vtable != NULL) {
+ (*CTX->cache_vtable)->save(
+ CTX->cache_vtable, CTX, &ENG->session);
+ }
+
+ }
+ break;
+ case 63: {
+ /* set-max-frag-len */
+
+ size_t max_frag_len = T0_POP();
+
+ br_ssl_engine_new_max_frag_len(ENG, max_frag_len);
+
+ /*
+ * We must adjust our own output limit. Since we call this only
+ * after receiving a ClientHello and before beginning to send
+ * the ServerHello, the next output record should be empty at
+ * that point, so we can use max_frag_len as a limit.
+ */
+ if (ENG->hlen_out > max_frag_len) {
+ ENG->hlen_out = max_frag_len;
+ }
+
+ }
+ break;
+ case 64: {
+ /* set16 */
+
+ size_t addr = (size_t)T0_POP();
+ *(uint16_t *)(void *)((unsigned char *)ENG + addr) = (uint16_t)T0_POP();
+
+ }
+ break;
+ case 65: {
+ /* set32 */
+
+ size_t addr = (size_t)T0_POP();
+ *(uint32_t *)(void *)((unsigned char *)ENG + addr) = (uint32_t)T0_POP();
+
+ }
+ break;
+ case 66: {
+ /* set8 */
+
+ size_t addr = (size_t)T0_POP();
+ *((unsigned char *)ENG + addr) = (unsigned char)T0_POP();
+
+ }
+ break;
+ case 67: {
+ /* supported-curves */
+
+ uint32_t x = ENG->iec == NULL ? 0 : ENG->iec->supported_curves;
+ T0_PUSH(x);
+
+ }
+ break;
+ case 68: {
+ /* supported-hash-functions */
+
+ int i;
+ unsigned x, num;
+
+ x = 0;
+ num = 0;
+ for (i = br_sha1_ID; i <= br_sha512_ID; i ++) {
+ if (br_multihash_getimpl(&ENG->mhash, i)) {
+ x |= 1U << i;
+ num ++;
+ }
+ }
+ T0_PUSH(x);
+ T0_PUSH(num);
+
+ }
+ break;
+ case 69: {
+ /* supports-ecdsa? */
+
+ T0_PUSHi(-(ENG->iecdsa != 0));
+
+ }
+ break;
+ case 70: {
+ /* supports-rsa-sign? */
+
+ T0_PUSHi(-(ENG->irsavrfy != 0));
+
+ }
+ break;
+ case 71: {
+ /* swap */
+ T0_SWAP();
+ }
+ break;
+ case 72: {
+ /* switch-aesccm-in */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len, tag_len;
+
+ tag_len = T0_POP();
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_ccm_in(ENG, is_client, prf_id,
+ ENG->iaes_ctrcbc, cipher_key_len, tag_len);
+
+ }
+ break;
+ case 73: {
+ /* switch-aesccm-out */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len, tag_len;
+
+ tag_len = T0_POP();
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_ccm_out(ENG, is_client, prf_id,
+ ENG->iaes_ctrcbc, cipher_key_len, tag_len);
+
+ }
+ break;
+ case 74: {
+ /* switch-aesgcm-in */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_in(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+
+ }
+ break;
+ case 75: {
+ /* switch-aesgcm-out */
+
+ int is_client, prf_id;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_gcm_out(ENG, is_client, prf_id,
+ ENG->iaes_ctr, cipher_key_len);
+
+ }
+ break;
+ case 76: {
+ /* switch-cbc-in */
+
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_in(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcdec : ENG->ides_cbcdec, cipher_key_len);
+
+ }
+ break;
+ case 77: {
+ /* switch-cbc-out */
+
+ int is_client, prf_id, mac_id, aes;
+ unsigned cipher_key_len;
+
+ cipher_key_len = T0_POP();
+ aes = T0_POP();
+ mac_id = T0_POP();
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_cbc_out(ENG, is_client, prf_id, mac_id,
+ aes ? ENG->iaes_cbcenc : ENG->ides_cbcenc, cipher_key_len);
+
+ }
+ break;
+ case 78: {
+ /* switch-chapol-in */
+
+ int is_client, prf_id;
+
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_chapol_in(ENG, is_client, prf_id);
+
+ }
+ break;
+ case 79: {
+ /* switch-chapol-out */
+
+ int is_client, prf_id;
+
+ prf_id = T0_POP();
+ is_client = T0_POP();
+ br_ssl_engine_switch_chapol_out(ENG, is_client, prf_id);
+
+ }
+ break;
+ case 80: {
+ /* ta-names-total-length */
+
+ size_t u, len;
+
+ len = 0;
+ if (CTX->ta_names != NULL) {
+ for (u = 0; u < CTX->num_tas; u ++) {
+ len += CTX->ta_names[u].len + 2;
+ }
+ } else if (CTX->tas != NULL) {
+ for (u = 0; u < CTX->num_tas; u ++) {
+ len += CTX->tas[u].dn.len + 2;
+ }
+ }
+ T0_PUSH(len);
+
+ }
+ break;
+ case 81: {
+ /* test-protocol-name */
+
+ size_t len = T0_POP();
+ size_t u;
+
+ for (u = 0; u < ENG->protocol_names_num; u ++) {
+ const char *name;
+
+ name = ENG->protocol_names[u];
+ if (len == strlen(name) && memcmp(ENG->pad, name, len) == 0) {
+ T0_PUSH(u);
+ T0_RET();
+ }
+ }
+ T0_PUSHi(-1);
+
+ }
+ break;
+ case 82: {
+ /* total-chain-length */
+
+ size_t u;
+ uint32_t total;
+
+ total = 0;
+ for (u = 0; u < ENG->chain_len; u ++) {
+ total += 3 + (uint32_t)ENG->chain[u].data_len;
+ }
+ T0_PUSH(total);
+
+ }
+ break;
+ case 83: {
+ /* u< */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a < b));
+
+ }
+ break;
+ case 84: {
+ /* u>> */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x >> c);
+
+ }
+ break;
+ case 85: {
+ /* verify-CV-sig */
+
+ int err;
+
+ err = verify_CV_sig(CTX, T0_POP());
+ T0_PUSHi(err);
+
+ }
+ break;
+ case 86: {
+ /* write-blob-chunk */
+
+ size_t clen = ENG->hlen_out;
+ if (clen > 0) {
+ uint32_t addr, len;
+
+ len = T0_POP();
+ addr = T0_POP();
+ if ((size_t)len < clen) {
+ clen = (size_t)len;
+ }
+ memcpy(ENG->hbuf_out, (unsigned char *)ENG + addr, clen);
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, ENG->hbuf_out, clen);
+ }
+ T0_PUSH(addr + (uint32_t)clen);
+ T0_PUSH(len - (uint32_t)clen);
+ ENG->hbuf_out += clen;
+ ENG->hlen_out -= clen;
+ }
+
+ }
+ break;
+ case 87: {
+ /* write8-native */
+
+ unsigned char x;
+
+ x = (unsigned char)T0_POP();
+ if (ENG->hlen_out > 0) {
+ if (ENG->record_type_out == BR_SSL_HANDSHAKE) {
+ br_multihash_update(&ENG->mhash, &x, 1);
+ }
+ *ENG->hbuf_out ++ = x;
+ ENG->hlen_out --;
+ T0_PUSHi(-1);
+ } else {
+ T0_PUSHi(0);
+ }
+
+ }
+ break;
+ case 88: {
+ /* x509-append */
+
+ const br_x509_class *xc;
+ size_t len;
+
+ xc = *(ENG->x509ctx);
+ len = T0_POP();
+ xc->append(ENG->x509ctx, ENG->pad, len);
+
+ }
+ break;
+ case 89: {
+ /* x509-end-cert */
+
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ xc->end_cert(ENG->x509ctx);
+
+ }
+ break;
+ case 90: {
+ /* x509-end-chain */
+
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ T0_PUSH(xc->end_chain(ENG->x509ctx));
+
+ }
+ break;
+ case 91: {
+ /* x509-start-cert */
+
+ const br_x509_class *xc;
+
+ xc = *(ENG->x509ctx);
+ xc->start_cert(ENG->x509ctx, T0_POP());
+
+ }
+ break;
+ case 92: {
+ /* x509-start-chain */
+
+ const br_x509_class *xc;
+ uint32_t bc;
+
+ bc = T0_POP();
+ xc = *(ENG->x509ctx);
+ xc->start_chain(ENG->x509ctx, bc ? ENG->server_name : NULL);
+
+ }
+ break;
+ }
+
+ } else {
+ T0_ENTER(ip, rp, t0x);
+ }
+ }
+t0_exit:
+ ((t0_context *)t0ctx)->dp = dp;
+ ((t0_context *)t0ctx)->rp = rp;
+ ((t0_context *)t0ctx)->ip = ip;
+}
diff --git a/contrib/bearssl/src/ssl/ssl_hs_server.t0 b/contrib/bearssl/src/ssl/ssl_hs_server.t0
new file mode 100644
index 000000000000..9f6e934e1be9
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_hs_server.t0
@@ -0,0 +1,1510 @@
+\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+\
+\ Permission is hereby granted, free of charge, to any person obtaining
+\ a copy of this software and associated documentation files (the
+\ "Software"), to deal in the Software without restriction, including
+\ without limitation the rights to use, copy, modify, merge, publish,
+\ distribute, sublicense, and/or sell copies of the Software, and to
+\ permit persons to whom the Software is furnished to do so, subject to
+\ the following conditions:
+\
+\ The above copyright notice and this permission notice shall be
+\ included in all copies or substantial portions of the Software.
+\
+\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+\ SOFTWARE.
+
+\ ----------------------------------------------------------------------
+\ Handshake processing code, for the server.
+\ The common T0 code (ssl_hs_common.t0) shall be read first.
+
+preamble {
+
+/*
+ * This macro evaluates to a pointer to the server context, under that
+ * specific name. It must be noted that since the engine context is the
+ * first field of the br_ssl_server_context structure ('eng'), then
+ * pointers values of both types are interchangeable, modulo an
+ * appropriate cast. This also means that "addresses" computed as offsets
+ * within the structure work for both kinds of context.
+ */
+#define CTX ((br_ssl_server_context *)ENG)
+
+/*
+ * Decrypt the pre-master secret (RSA key exchange).
+ */
+static void
+do_rsa_decrypt(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *epms, size_t len)
+{
+ uint32_t x;
+ unsigned char rpms[48];
+
+ /*
+ * Decrypt the PMS.
+ */
+ x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable, epms, &len);
+
+ /*
+ * Set the first two bytes to the maximum supported client
+ * protocol version. These bytes are used for version rollback
+ * detection; forceing the two bytes will make the master secret
+ * wrong if the bytes are not correct. This process is
+ * recommended by RFC 5246 (section 7.4.7.1).
+ */
+ br_enc16be(epms, ctx->client_max_version);
+
+ /*
+ * Make a random PMS and copy it above the decrypted value if the
+ * decryption failed. Note that we use a constant-time conditional
+ * copy.
+ */
+ br_hmac_drbg_generate(&ctx->eng.rng, rpms, sizeof rpms);
+ br_ccopy(x ^ 1, epms, rpms, sizeof rpms);
+
+ /*
+ * Compute master secret.
+ */
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, epms, 48);
+
+ /*
+ * Clear the pre-master secret from RAM: it is normally a buffer
+ * in the context, hence potentially long-lived.
+ */
+ memset(epms, 0, len);
+}
+
+/*
+ * Common part for ECDH and ECDHE.
+ */
+static void
+ecdh_common(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *xcoor, size_t xcoor_len, uint32_t ctl)
+{
+ unsigned char rpms[80];
+
+ if (xcoor_len > sizeof rpms) {
+ xcoor_len = sizeof rpms;
+ ctl = 0;
+ }
+
+ /*
+ * Make a random PMS and copy it above the decrypted value if the
+ * decryption failed. Note that we use a constant-time conditional
+ * copy.
+ */
+ br_hmac_drbg_generate(&ctx->eng.rng, rpms, xcoor_len);
+ br_ccopy(ctl ^ 1, xcoor, rpms, xcoor_len);
+
+ /*
+ * Compute master secret.
+ */
+ br_ssl_engine_compute_master(&ctx->eng, prf_id, xcoor, xcoor_len);
+
+ /*
+ * Clear the pre-master secret from RAM: it is normally a buffer
+ * in the context, hence potentially long-lived.
+ */
+ memset(xcoor, 0, xcoor_len);
+}
+
+/*
+ * Do the ECDH key exchange (not ECDHE).
+ */
+static void
+do_ecdh(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *cpoint, size_t cpoint_len)
+{
+ uint32_t x;
+
+ /*
+ * Finalise the key exchange.
+ */
+ x = (*ctx->policy_vtable)->do_keyx(ctx->policy_vtable,
+ cpoint, &cpoint_len);
+ ecdh_common(ctx, prf_id, cpoint, cpoint_len, x);
+}
+
+/*
+ * Do the full static ECDH key exchange. When this function is called,
+ * it has already been verified that the cipher suite uses ECDH (not ECDHE),
+ * and the client's public key (from its certificate) has type EC and is
+ * apt for key exchange.
+ */
+static void
+do_static_ecdh(br_ssl_server_context *ctx, int prf_id)
+{
+ unsigned char cpoint[133];
+ size_t cpoint_len;
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+ cpoint_len = pk->key.ec.qlen;
+ if (cpoint_len > sizeof cpoint) {
+ /*
+ * If the point is larger than our buffer then we need to
+ * restrict it. Length 2 is not a valid point length, so
+ * the ECDH will fail.
+ */
+ cpoint_len = 2;
+ }
+ memcpy(cpoint, pk->key.ec.q, cpoint_len);
+ do_ecdh(ctx, prf_id, cpoint, cpoint_len);
+}
+
+static size_t
+hash_data(br_ssl_server_context *ctx,
+ void *dst, int hash_id, const void *src, size_t len)
+{
+ const br_hash_class *hf;
+ br_hash_compat_context hc;
+
+ if (hash_id == 0) {
+ unsigned char tmp[36];
+
+ hf = br_multihash_getimpl(&ctx->eng.mhash, br_md5_ID);
+ if (hf == NULL) {
+ return 0;
+ }
+ hf->init(&hc.vtable);
+ hf->update(&hc.vtable, src, len);
+ hf->out(&hc.vtable, tmp);
+ hf = br_multihash_getimpl(&ctx->eng.mhash, br_sha1_ID);
+ if (hf == NULL) {
+ return 0;
+ }
+ hf->init(&hc.vtable);
+ hf->update(&hc.vtable, src, len);
+ hf->out(&hc.vtable, tmp + 16);
+ memcpy(dst, tmp, 36);
+ return 36;
+ } else {
+ hf = br_multihash_getimpl(&ctx->eng.mhash, hash_id);
+ if (hf == NULL) {
+ return 0;
+ }
+ hf->init(&hc.vtable);
+ hf->update(&hc.vtable, src, len);
+ hf->out(&hc.vtable, dst);
+ return (hf->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK;
+ }
+}
+
+/*
+ * Do the ECDHE key exchange (part 1: generation of transient key, and
+ * computing of the point to send to the client). Returned value is the
+ * signature length (in bytes), or -x on error (with x being an error
+ * code). The encoded point is written in the ecdhe_point[] context buffer
+ * (length in ecdhe_point_len).
+ */
+static int
+do_ecdhe_part1(br_ssl_server_context *ctx, int curve)
+{
+ unsigned algo_id;
+ unsigned mask;
+ const unsigned char *order;
+ size_t olen, glen;
+ size_t hv_len, sig_len;
+
+ if (!((ctx->eng.iec->supported_curves >> curve) & 1)) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+ ctx->eng.ecdhe_curve = curve;
+
+ /*
+ * Generate our private key. We need a non-zero random value
+ * which is lower than the curve order, in a "large enough"
+ * range. We force the top bit to 0 and bottom bit to 1, which
+ * does the trick. Note that contrary to what happens in ECDSA,
+ * this is not a problem if we do not cover the full range of
+ * possible values.
+ */
+ order = ctx->eng.iec->order(curve, &olen);
+ mask = 0xFF;
+ while (mask >= order[0]) {
+ mask >>= 1;
+ }
+ br_hmac_drbg_generate(&ctx->eng.rng, ctx->ecdhe_key, olen);
+ ctx->ecdhe_key[0] &= mask;
+ ctx->ecdhe_key[olen - 1] |= 0x01;
+ ctx->ecdhe_key_len = olen;
+
+ /*
+ * Compute our ECDH point.
+ */
+ glen = ctx->eng.iec->mulgen(ctx->eng.ecdhe_point,
+ ctx->ecdhe_key, olen, curve);
+ ctx->eng.ecdhe_point_len = glen;
+
+ /*
+ * Assemble the message to be signed, and possibly hash it.
+ */
+ memcpy(ctx->eng.pad, ctx->eng.client_random, 32);
+ memcpy(ctx->eng.pad + 32, ctx->eng.server_random, 32);
+ ctx->eng.pad[64 + 0] = 0x03;
+ ctx->eng.pad[64 + 1] = 0x00;
+ ctx->eng.pad[64 + 2] = curve;
+ ctx->eng.pad[64 + 3] = ctx->eng.ecdhe_point_len;
+ memcpy(ctx->eng.pad + 64 + 4,
+ ctx->eng.ecdhe_point, ctx->eng.ecdhe_point_len);
+ hv_len = 64 + 4 + ctx->eng.ecdhe_point_len;
+ algo_id = ctx->sign_hash_id;
+ if (algo_id >= (unsigned)0xFF00) {
+ hv_len = hash_data(ctx, ctx->eng.pad, algo_id & 0xFF,
+ ctx->eng.pad, hv_len);
+ if (hv_len == 0) {
+ return -BR_ERR_INVALID_ALGORITHM;
+ }
+ }
+
+ sig_len = (*ctx->policy_vtable)->do_sign(ctx->policy_vtable,
+ algo_id, ctx->eng.pad, hv_len, sizeof ctx->eng.pad);
+ return sig_len ? (int)sig_len : -BR_ERR_INVALID_ALGORITHM;
+}
+
+/*
+ * Do the ECDHE key exchange (part 2: computation of the shared secret
+ * from the point sent by the client).
+ */
+static void
+do_ecdhe_part2(br_ssl_server_context *ctx, int prf_id,
+ unsigned char *cpoint, size_t cpoint_len)
+{
+ int curve;
+ uint32_t ctl;
+ size_t xoff, xlen;
+
+ curve = ctx->eng.ecdhe_curve;
+
+ /*
+ * Finalise the key exchange.
+ */
+ ctl = ctx->eng.iec->mul(cpoint, cpoint_len,
+ ctx->ecdhe_key, ctx->ecdhe_key_len, curve);
+ xoff = ctx->eng.iec->xoff(curve, &xlen);
+ ecdh_common(ctx, prf_id, cpoint + xoff, xlen, ctl);
+
+ /*
+ * Clear the ECDHE private key. Forward Secrecy is achieved insofar
+ * as that key does not get stolen, so we'd better destroy it
+ * as soon as it ceases to be useful.
+ */
+ memset(ctx->ecdhe_key, 0, ctx->ecdhe_key_len);
+}
+
+/*
+ * Offset for hash value within the pad (when obtaining all hash values,
+ * in preparation for verification of the CertificateVerify message).
+ * Order is MD5, SHA-1, SHA-224, SHA-256, SHA-384, SHA-512; last value
+ * is used to get the total length.
+ */
+static const unsigned char HASH_PAD_OFF[] = { 0, 16, 36, 64, 96, 144, 208 };
+
+/*
+ * OID for hash functions in RSA signatures.
+ */
+static const unsigned char HASH_OID_SHA1[] = {
+ 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
+};
+
+static const unsigned char HASH_OID_SHA224[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
+};
+
+static const unsigned char HASH_OID_SHA256[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
+};
+
+static const unsigned char HASH_OID_SHA384[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
+};
+
+static const unsigned char HASH_OID_SHA512[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
+};
+
+static const unsigned char *HASH_OID[] = {
+ HASH_OID_SHA1,
+ HASH_OID_SHA224,
+ HASH_OID_SHA256,
+ HASH_OID_SHA384,
+ HASH_OID_SHA512
+};
+
+/*
+ * Verify the signature in CertificateVerify. Returned value is 0 on
+ * success, or a non-zero error code. Lack of implementation of the
+ * designated signature algorithm is reported as a "bad signature"
+ * error (because it means that the peer did not honour our advertised
+ * set of supported signature algorithms).
+ */
+static int
+verify_CV_sig(br_ssl_server_context *ctx, size_t sig_len)
+{
+ const br_x509_class **xc;
+ const br_x509_pkey *pk;
+ int id;
+
+ id = ctx->hash_CV_id;
+ xc = ctx->eng.x509ctx;
+ pk = (*xc)->get_pkey(xc, NULL);
+ if (pk->key_type == BR_KEYTYPE_RSA) {
+ unsigned char tmp[64];
+ const unsigned char *hash_oid;
+
+ if (id == 0) {
+ hash_oid = NULL;
+ } else {
+ hash_oid = HASH_OID[id - 2];
+ }
+ if (ctx->eng.irsavrfy == 0) {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ if (!ctx->eng.irsavrfy(ctx->eng.pad, sig_len,
+ hash_oid, ctx->hash_CV_len, &pk->key.rsa, tmp)
+ || memcmp(tmp, ctx->hash_CV, ctx->hash_CV_len) != 0)
+ {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ } else {
+ if (ctx->eng.iecdsa == 0) {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ if (!ctx->eng.iecdsa(ctx->eng.iec,
+ ctx->hash_CV, ctx->hash_CV_len,
+ &pk->key.ec, ctx->eng.pad, sig_len))
+ {
+ return BR_ERR_BAD_SIGNATURE;
+ }
+ }
+ return 0;
+}
+
+}
+
+\ =======================================================================
+
+: addr-ctx:
+ next-word { field }
+ "addr-" field + 0 1 define-word
+ 0 8191 "offsetof(br_ssl_server_context, " field + ")" + make-CX
+ postpone literal postpone ; ;
+
+addr-ctx: client_max_version
+addr-ctx: client_suites
+addr-ctx: client_suites_num
+addr-ctx: hashes
+addr-ctx: curves
+addr-ctx: sign_hash_id
+
+\ Get address and length of the client_suites[] buffer. Length is expressed
+\ in bytes.
+: addr-len-client_suites ( -- addr len )
+ addr-client_suites
+ CX 0 1023 { BR_MAX_CIPHER_SUITES * sizeof(br_suite_translated) } ;
+
+\ Read the client SNI extension.
+: read-client-sni ( lim -- lim )
+ \ Open extension value.
+ read16 open-elt
+
+ \ Open ServerNameList.
+ read16 open-elt
+
+ \ Find if there is a name of type 0 (host_name) with a length
+ \ that fits in our dedicated buffer.
+ begin dup while
+ read8 if
+ read-ignore-16
+ else
+ read16
+ dup 255 <= if
+ dup addr-server_name + 0 swap set8
+ addr-server_name swap read-blob
+ else
+ skip-blob
+ then
+ then
+ repeat
+
+ \ Close ServerNameList.
+ close-elt
+
+ \ Close extension value.
+ close-elt ;
+
+\ Set the new maximum fragment length. BEWARE: this shall be called only
+\ after reading the ClientHello and before writing the ServerHello.
+cc: set-max-frag-len ( len -- ) {
+ size_t max_frag_len = T0_POP();
+
+ br_ssl_engine_new_max_frag_len(ENG, max_frag_len);
+
+ /*
+ * We must adjust our own output limit. Since we call this only
+ * after receiving a ClientHello and before beginning to send
+ * the ServerHello, the next output record should be empty at
+ * that point, so we can use max_frag_len as a limit.
+ */
+ if (ENG->hlen_out > max_frag_len) {
+ ENG->hlen_out = max_frag_len;
+ }
+}
+
+\ Read the client Max Frag Length extension.
+: read-client-frag ( lim -- lim )
+ \ Extension value must have length exactly 1 byte.
+ read16 1 <> if ERR_BAD_FRAGLEN fail then
+ read8
+
+ \ The byte value must be 1, 2, 3 or 4.
+ dup dup 0= swap 5 >= or if ERR_BAD_FRAGLEN fail then
+
+ \ If our own maximum fragment length is greater, then we reduce
+ \ our length.
+ 8 + dup addr-log_max_frag_len get8 < if
+ dup 1 swap << set-max-frag-len
+ dup addr-log_max_frag_len set8
+ addr-peer_log_max_frag_len set8
+ else
+ drop
+ then ;
+
+\ Read the Secure Renegotiation extension from the client.
+: read-client-reneg ( lim -- lim )
+ \ Get value length.
+ read16
+
+ \ The "reneg" value is one of:
+ \ 0 on first handshake, client support is unknown
+ \ 1 client does not support secure renegotiation
+ \ 2 client supports secure renegotiation
+ addr-reneg get8 case
+ 0 of
+ \ First handshake, value length shall be 1.
+ 1 = ifnot ERR_BAD_SECRENEG fail then
+ read8 if ERR_BAD_SECRENEG fail then
+ 2 addr-reneg set8
+ endof
+ 2 of
+ \ Renegotiation, value shall consist of 13 bytes
+ \ (header + copy of the saved client "Finished").
+ 13 = ifnot ERR_BAD_SECRENEG fail then
+ read8 12 = ifnot ERR_BAD_SECRENEG fail then
+ addr-pad 12 read-blob
+ addr-saved_finished addr-pad 12 memcmp ifnot
+ ERR_BAD_SECRENEG fail
+ then
+ endof
+
+ \ If "reneg" is 1 then the client is not supposed to support
+ \ the extension, and it sends it nonetheless, which means
+ \ foul play.
+ ERR_BAD_SECRENEG fail
+ endcase ;
+
+\ Read the Signature Algorithms extension.
+: read-signatures ( lim -- lim )
+ \ Open extension value.
+ read16 open-elt
+
+ read-list-sign-algos addr-hashes set32
+
+ \ Close extension value.
+ close-elt ;
+
+\ Read the Supported Curves extension.
+: read-supported-curves ( lim -- lim )
+ \ Open extension value.
+ read16 open-elt
+
+ \ Open list of curve identifiers.
+ read16 open-elt
+
+ \ Get all supported curves.
+ 0 addr-curves set32
+ begin dup while
+ read16 dup 32 < if
+ 1 swap << addr-curves get32 or addr-curves set32
+ else
+ drop
+ then
+ repeat
+ close-elt
+ close-elt ;
+
+\ Read the ALPN extension from client.
+: read-ALPN-from-client ( lim -- lim )
+ \ If we do not have configured names, then we just ignore the
+ \ extension.
+ addr-protocol_names_num get16 ifnot read-ignore-16 ret then
+
+ \ Open extension value.
+ read16 open-elt
+
+ \ Open list of protocol names.
+ read16 open-elt
+
+ \ Get all names and test for their support. We keep the one with
+ \ the lowest index (because we apply server's preferences, as
+ \ recommended by RFC 7301, section 3.2. We set the 'found' variable
+ \ to -2 and use an unsigned comparison, making -2 a huge value.
+ -2 { found }
+ begin dup while
+ read8 dup { len } addr-pad swap read-blob
+ len test-protocol-name dup found u< if
+ >found
+ else
+ drop
+ then
+ repeat
+
+ \ End of extension.
+ close-elt
+ close-elt
+
+ \ Write back found name index (or not). If no match was found,
+ \ then we write -1 (0xFFFF) in the index value, not 0, so that
+ \ the caller knows that we tried to match, and failed.
+ found 1+ addr-selected_protocol set16 ;
+
+\ Call policy handler to get cipher suite, hash function identifier and
+\ certificate chain. Returned value is 0 (false) on failure.
+cc: call-policy-handler ( -- bool ) {
+ int x;
+ br_ssl_server_choices choices;
+
+ x = (*CTX->policy_vtable)->choose(
+ CTX->policy_vtable, CTX, &choices);
+ ENG->session.cipher_suite = choices.cipher_suite;
+ CTX->sign_hash_id = choices.algo_id;
+ ENG->chain = choices.chain;
+ ENG->chain_len = choices.chain_len;
+ T0_PUSHi(-(x != 0));
+}
+
+\ Check for a remembered session.
+cc: check-resume ( -- bool ) {
+ if (ENG->session.session_id_len == 32
+ && CTX->cache_vtable != NULL && (*CTX->cache_vtable)->load(
+ CTX->cache_vtable, CTX, &ENG->session))
+ {
+ T0_PUSHi(-1);
+ } else {
+ T0_PUSH(0);
+ }
+}
+
+\ Save the current session.
+cc: save-session ( -- ) {
+ if (CTX->cache_vtable != NULL) {
+ (*CTX->cache_vtable)->save(
+ CTX->cache_vtable, CTX, &ENG->session);
+ }
+}
+
+\ Read and drop ClientHello. This is used when a client-triggered
+\ renegotiation attempt is rejected.
+: skip-ClientHello ( -- )
+ read-handshake-header-core
+ 1 = ifnot ERR_UNEXPECTED fail then
+ dup skip-blob drop ;
+
+\ Read ClientHello. If the session is resumed, then -1 is returned.
+: read-ClientHello ( -- resume )
+ \ Get header, and check message type.
+ read-handshake-header 1 = ifnot ERR_UNEXPECTED fail then
+
+ \ Get maximum protocol version from client.
+ read16 dup { client-version-max } addr-client_max_version set16
+
+ \ Client random.
+ addr-client_random 32 read-blob
+
+ \ Client session ID.
+ read8 dup 32 > if ERR_OVERSIZED_ID fail then
+ dup addr-session_id_len set8
+ addr-session_id swap read-blob
+
+ \ Lookup session for resumption. We should do that here because
+ \ we need to verify that the remembered cipher suite is still
+ \ matched by this ClientHello.
+ check-resume { resume }
+
+ \ Cipher suites. We read all cipher suites from client, each time
+ \ matching against our own list. We accumulate suites in the
+ \ client_suites[] context buffer: we keep suites that are
+ \ supported by both the client and the server (so the list size
+ \ cannot exceed that of the server list), and we keep them in
+ \ either client or server preference order (depending on the
+ \ relevant flag).
+ \
+ \ We also need to identify the pseudo cipher suite for secure
+ \ renegotiation here.
+ read16 open-elt
+ 0 { reneg-scsv }
+ 0 { resume-suite }
+ addr-len-client_suites dup2 bzero
+ over + { css-off css-max }
+ begin
+ dup while
+ read16 dup { suite }
+
+ \ Check that when resuming a session, the requested
+ \ suite is still valid.
+ resume if
+ dup addr-cipher_suite get16 = if
+ -1 >resume-suite
+ then
+ then
+
+ \ Special handling for TLS_EMPTY_RENEGOTIATION_INFO_SCSV.
+ \ This fake cipher suite may occur only in the first
+ \ handshake.
+ dup 0x00FF = if
+ addr-reneg get8 if ERR_BAD_SECRENEG fail then
+ -1 >reneg-scsv
+ then
+
+ \ Special handling for TLS_FALLBACK_SCSV. If the client
+ \ maximum version is less than our own maximum version,
+ \ then this is an undue downgrade. We mark it by setting
+ \ the client max version to 0x10000.
+ dup 0x5600 = if
+ client-version-max addr-version_min get16 >=
+ client-version-max addr-version_max get16 < and if
+ -1 >client-version-max
+ then
+ then
+
+ \ Test whether the suite is supported by the server.
+ scan-suite dup 0< if
+ \ We do not support this cipher suite. Note
+ \ that this also covers the case of pseudo
+ \ cipher suites.
+ drop
+ else
+ \ If we use server order, then we place the
+ \ suite at the computed offset; otherwise, we
+ \ append it to the list at the current place.
+ 0 flag? if
+ 2 << addr-client_suites + suite swap set16
+ else
+ drop
+ \ We need to test for list length because
+ \ the client list may have duplicates,
+ \ that we do not filter. Duplicates are
+ \ invalid so this is not a problem if we
+ \ reject such clients.
+ css-off css-max >= if
+ ERR_BAD_HANDSHAKE fail
+ then
+ suite css-off set16
+ css-off 4 + >css-off
+ then
+ then
+ repeat
+ drop
+
+ \ Compression methods. We need method 0 (no compression).
+ 0 { ok-compression }
+ read8 open-elt
+ begin dup while
+ read8 ifnot -1 >ok-compression then
+ repeat
+ close-elt
+
+ \ Set default values for parameters that may be affected by
+ \ extensions:
+ \ -- server name is empty
+ \ -- client is reputed to know RSA and ECDSA, both with SHA-1
+ \ -- the default elliptic curve is P-256 (secp256r1, id = 23)
+ 0 addr-server_name set8
+ 0x0404 addr-hashes set32
+ 0x800000 addr-curves set32
+
+ \ Process extensions, if any.
+ dup if
+ read16 open-elt
+ begin dup while
+ read16 case
+ \ Server Name Indication.
+ 0x0000 of
+ read-client-sni
+ endof
+ \ Max Frag Length.
+ 0x0001 of
+ read-client-frag
+ endof
+ \ Secure Renegotiation.
+ 0xFF01 of
+ read-client-reneg
+ endof
+ \ Signature Algorithms.
+ 0x000D of
+ read-signatures
+ endof
+ \ Supported Curves.
+ 0x000A of
+ read-supported-curves
+ endof
+ \ Supported Point Formats.
+ \ We only support "uncompressed", that all
+ \ implementations are supposed to support,
+ \ so we can simply ignore that extension.
+ \ 0x000B of
+ \ read-ignore-16
+ \ endof
+
+ \ ALPN
+ 0x0010 of
+ read-ALPN-from-client
+ endof
+
+ \ Other extensions are ignored.
+ drop read-ignore-16 0
+ endcase
+ repeat
+ close-elt
+ then
+
+ \ Close message.
+ close-elt
+
+ \ Cancel session resumption if the cipher suite was not found.
+ resume resume-suite and >resume
+
+ \ Now check the received data. Since the client is expecting an
+ \ answer, we can send an appropriate fatal alert on any error.
+
+ \ Compute protocol version as the minimum of our maximum version,
+ \ and the maximum version sent by the client. If that is less than
+ \ 0x0300 (SSL-3.0), then fail. Otherwise, we may at least send an
+ \ alert with that version. We still reject versions lower than our
+ \ configured minimum.
+ \ As a special case, in case of undue downgrade, we send a specific
+ \ alert (see RFC 7507). Note that this case may happen only if
+ \ we would otherwise accept the client's version.
+ client-version-max 0< if
+ addr-client_max_version get16 addr-version_out set16
+ 86 fail-alert
+ then
+ addr-version_max get16
+ dup client-version-max > if drop client-version-max then
+ dup 0x0300 < if ERR_BAD_VERSION fail then
+ client-version-max addr-version_min get16 < if
+ 70 fail-alert
+ then
+ \ If resuming the session, then enforce the previously negotiated
+ \ version (if still possible).
+ resume if
+ addr-version get16 client-version-max <= if
+ drop addr-version get16
+ else
+ 0 >resume
+ then
+ then
+ dup addr-version set16
+ dup addr-version_in set16
+ dup addr-version_out set16
+ 0x0303 >= { can-tls12 }
+
+ \ If the client sent TLS_EMPTY_RENEGOTIATION_INFO_SCSV, then
+ \ we should mark the client as "supporting secure renegotiation".
+ reneg-scsv if 2 addr-reneg set8 then
+
+ \ If, at that point, the 'reneg' value is still 0, then the client
+ \ did not send the extension or the SCSV, so we have to assume
+ \ that secure renegotiation is not supported by that client.
+ addr-reneg get8 ifnot 1 addr-reneg set8 then
+
+ \ Check compression.
+ ok-compression ifnot 40 fail-alert then
+
+ \ Filter hash function support by what the server also supports.
+ \ If no common hash function remains with RSA and/or ECDSA, then
+ \ the corresponding ECDHE suites are not possible.
+ supported-hash-functions drop 257 * 0xFFFF0000 or
+ addr-hashes get32 and dup addr-hashes set32
+ \ In 'can-ecdhe', bit 12 is set if ECDHE_RSA is possible, bit 13 is
+ \ set if ECDHE_ECDSA is possible.
+ dup 0xFF and 0<> neg
+ swap 8 >> 0<> 2 and or 12 << { can-ecdhe }
+
+ \ Filter supported curves. If there is no common curve between
+ \ client and us, then ECDHE suites cannot be used. Note that we
+ \ may still allow ECDH, depending on the EC key handler.
+ addr-curves get32 supported-curves and dup addr-curves set32
+ ifnot 0 >can-ecdhe then
+
+ \ If resuming a session, then the next steps are not necessary;
+ \ we won't invoke the policy handler.
+ resume if -1 ret then
+
+ \ We are not resuming, so a new session ID should be generated.
+ \ We don't check that the new ID is distinct from the one sent
+ \ by the client because probability of such an event is 2^(-256),
+ \ i.e. much (much) lower than that of an undetected transmission
+ \ error or hardware miscomputation, and with similar consequences
+ \ (handshake simply fails).
+ addr-session_id 32 mkrand
+ 32 addr-session_id_len set8
+
+ \ Translate common cipher suites, then squeeze out holes: there
+ \ may be holes because of the way we fill the list when the
+ \ server preference order is enforced, and also in case some
+ \ suites are filtered out. In particular:
+ \ -- ECDHE suites are removed if there is no common hash function
+ \ (for the relevant signature algorithm) or no common curve.
+ \ -- TLS-1.2-only suites are removed if the negotiated version is
+ \ TLS-1.1 or lower.
+ addr-client_suites dup >css-off
+ begin dup css-max < while
+ dup get16 dup cipher-suite-to-elements
+ dup 12 >> dup 1 = swap 2 = or if
+ dup can-ecdhe and ifnot
+ 2drop 0 dup
+ then
+ then
+ can-tls12 ifnot
+ \ Suites compatible with TLS-1.0 and TLS-1.1 are
+ \ exactly the ones that use HMAC/SHA-1.
+ dup 0xF0 and 0x20 <> if
+ 2drop 0 dup
+ then
+ then
+ dup if
+ css-off 2+ set16 css-off set16
+ css-off 4 + >css-off
+ else
+ 2drop
+ then
+ 4 +
+ repeat
+ drop
+ css-off addr-client_suites - 2 >>
+ dup ifnot
+ \ No common cipher suite: handshake failure.
+ 40 fail-alert
+ then
+ addr-client_suites_num set8
+
+ \ Check ALPN.
+ addr-selected_protocol get16 0xFFFF = if
+ 3 flag? if 120 fail-alert then
+ 0 addr-selected_protocol set16
+ then
+
+ \ Call policy handler to obtain the cipher suite and other
+ \ parameters.
+ call-policy-handler ifnot 40 fail-alert then
+
+ \ We are not resuming a session.
+ 0 ;
+
+\ Write ServerHello.
+: write-ServerHello ( initial -- )
+ { initial }
+ \ Compute ServerHello length.
+ 2 write8 70
+
+ \ Compute length of Secure Renegotiation extension.
+ addr-reneg get8 2 = if
+ initial if 5 else 29 then
+ else
+ 0
+ then
+ { ext-reneg-len }
+
+ \ Compute length of Max Fragment Length extension.
+ addr-peer_log_max_frag_len get8 if 5 else 0 then
+ { ext-max-frag-len }
+
+ \ Compute length of ALPN extension. This also copy the
+ \ selected protocol name into the pad.
+ addr-selected_protocol get16 dup if 1- copy-protocol-name 7 + then
+ { ext-ALPN-len }
+
+ \ Adjust ServerHello length to account for the extensions.
+ ext-reneg-len ext-max-frag-len + ext-ALPN-len + dup if 2 + then +
+ write24
+
+ \ Protocol version
+ addr-version get16 write16
+
+ \ Server random
+ addr-server_random 4 bzero
+ addr-server_random 4 + 28 mkrand
+ addr-server_random 32 write-blob
+
+ \ Session ID
+ \ TODO: if we have no session cache at all, we might send here
+ \ an empty session ID. This would save a bit of network
+ \ bandwidth.
+ 32 write8
+ addr-session_id 32 write-blob
+
+ \ Cipher suite
+ addr-cipher_suite get16 write16
+
+ \ Compression method
+ 0 write8
+
+ \ Extensions
+ ext-reneg-len ext-max-frag-len + ext-ALPN-len + dup if
+ write16
+ ext-reneg-len dup if
+ 0xFF01 write16
+ 4 - dup write16
+ 1- addr-saved_finished swap write-blob-head8
+ else
+ drop
+ then
+ ext-max-frag-len if
+ 0x0001 write16
+ 1 write16 addr-peer_log_max_frag_len get8 8 - write8
+ then
+ ext-ALPN-len dup if
+ \ Note: the selected protocol name was previously
+ \ copied into the pad.
+ 0x0010 write16
+ 4 - dup write16
+ 2- dup write16
+ 1- addr-pad swap write-blob-head8
+ else
+ drop
+ then
+ else
+ drop
+ then ;
+
+\ Do the first part of ECDHE. Returned value is the computed signature
+\ length, or a negative error code on error.
+cc: do-ecdhe-part1 ( curve -- len ) {
+ int curve = T0_POPi();
+ T0_PUSHi(do_ecdhe_part1(CTX, curve));
+}
+
+\ Get index of first bit set to 1 (in low to high order).
+: lowest-1 ( bits -- n )
+ dup ifnot drop -1 ret then
+ 0 begin dup2 >> 1 and 0= while 1+ repeat
+ swap drop ;
+
+\ Write the Server Key Exchange message (if applicable).
+: write-ServerKeyExchange ( -- )
+ addr-cipher_suite get16 use-ecdhe? ifnot ret then
+
+ \ We must select an appropriate curve among the curves that
+ \ are supported both by us and the peer. Right now, we apply
+ \ a fixed preference order: Curve25519, P-256, P-384, P-521,
+ \ then the common curve with the lowest ID.
+ \ (TODO: add some option to make that behaviour configurable.)
+ \
+ \ This loop always terminates because previous processing made
+ \ sure that ECDHE suites are not selectable if there is no common
+ \ curve.
+ addr-curves get32
+ dup 0x20000000 and if
+ drop 29
+ else
+ dup 0x38000000 and dup if swap then
+ drop lowest-1
+ then
+ { curve-id }
+
+ \ Compute the signed curve point to send.
+ curve-id do-ecdhe-part1 dup 0< if neg fail then { sig-len }
+
+ \ If using TLS-1.2+, then the hash function and signature
+ \ algorithm are explicitly encoded in the message.
+ addr-version get16 0x0303 >= { tls1.2+ }
+
+ 12 write8
+ sig-len addr-ecdhe_point_len get8 + tls1.2+ 2 and + 6 + write24
+
+ \ Curve parameters: named curve with 16-bit ID.
+ 3 write8 curve-id write16
+
+ \ Public point.
+ addr-ecdhe_point addr-ecdhe_point_len get8 write-blob-head8
+
+ \ If TLS-1.2+, write hash and signature identifiers.
+ tls1.2+ if
+ \ sign_hash_id contains either a hash identifier,
+ \ or the complete 16-bit value to write.
+ addr-sign_hash_id get16
+ dup 0xFF00 < if
+ write16
+ else
+ 0xFF and write8
+ \ 'use-rsa-ecdhe?' returns -1 for RSA, 0 for
+ \ ECDSA. The byte on the wire shall be 1 for RSA,
+ \ 3 for ECDSA.
+ addr-cipher_suite get16 use-rsa-ecdhe? 1 << 3 + write8
+ then
+ then
+
+ \ Signature.
+ sig-len write16
+ addr-pad sig-len write-blob ;
+
+\ Get length of the list of anchor names to send to the client. The length
+\ includes the per-name 2-byte header, but _not_ the 2-byte header for
+\ the list itself. If no client certificate is requested, then this
+\ returns 0.
+cc: ta-names-total-length ( -- len ) {
+ size_t u, len;
+
+ len = 0;
+ if (CTX->ta_names != NULL) {
+ for (u = 0; u < CTX->num_tas; u ++) {
+ len += CTX->ta_names[u].len + 2;
+ }
+ } else if (CTX->tas != NULL) {
+ for (u = 0; u < CTX->num_tas; u ++) {
+ len += CTX->tas[u].dn.len + 2;
+ }
+ }
+ T0_PUSH(len);
+}
+
+\ Compute length and optionally write the contents of the list of
+\ supported client authentication methods.
+: write-list-auth ( do_write -- len )
+ 0
+ addr-cipher_suite get16 use-ecdh? if
+ 2+ over if 65 write8 66 write8 then
+ then
+ supports-rsa-sign? if 1+ over if 1 write8 then then
+ supports-ecdsa? if 1+ over if 64 write8 then then
+ swap drop ;
+
+: write-signhash-inner2 ( dow algo hashes len id -- dow algo hashes len )
+ { id }
+ over 1 id << and ifnot ret then
+ 2+
+ 3 pick if id write8 2 pick write8 then ;
+
+: write-signhash-inner1 ( dow algo hashes -- dow len )
+ 0
+ 4 write-signhash-inner2
+ 5 write-signhash-inner2
+ 6 write-signhash-inner2
+ 3 write-signhash-inner2
+ 2 write-signhash-inner2
+ -rot 2drop ;
+
+\ Compute length and optionally write the contents of the list of
+\ supported sign+hash algorithms.
+: write-list-signhash ( do_write -- len )
+ 0 { len }
+ \ If supporting neither RSA nor ECDSA in the engine, then we
+ \ will do only static ECDH, and thus we claim support for
+ \ everything (for the X.509 validator).
+ supports-rsa-sign? supports-ecdsa? or ifnot
+ 1 0x7C write-signhash-inner1 >len
+ 3 0x7C write-signhash-inner1 len +
+ swap drop ret
+ then
+ supports-rsa-sign? if
+ 1 supported-hash-functions drop
+ write-signhash-inner1 >len
+ then
+ supports-ecdsa? if
+ 3 supported-hash-functions drop
+ write-signhash-inner1 len + >len
+ then
+ drop len ;
+
+\ Initialise index for sending the list of anchor DN.
+cc: begin-ta-name-list ( -- ) {
+ CTX->cur_dn_index = 0;
+}
+
+\ Switch to next DN in the list. Returned value is the DN length, or -1
+\ if the end of the list was reached.
+cc: begin-ta-name ( -- len ) {
+ const br_x500_name *dn;
+ if (CTX->cur_dn_index >= CTX->num_tas) {
+ T0_PUSHi(-1);
+ } else {
+ if (CTX->ta_names == NULL) {
+ dn = &CTX->tas[CTX->cur_dn_index].dn;
+ } else {
+ dn = &CTX->ta_names[CTX->cur_dn_index];
+ }
+ CTX->cur_dn_index ++;
+ CTX->cur_dn = dn->data;
+ CTX->cur_dn_len = dn->len;
+ T0_PUSH(CTX->cur_dn_len);
+ }
+}
+
+\ Copy a chunk of the current DN into the pad. Returned value is the
+\ chunk length; this is 0 when the end of the current DN is reached.
+cc: copy-dn-chunk ( -- len ) {
+ size_t clen;
+
+ clen = CTX->cur_dn_len;
+ if (clen > sizeof ENG->pad) {
+ clen = sizeof ENG->pad;
+ }
+ memcpy(ENG->pad, CTX->cur_dn, clen);
+ CTX->cur_dn += clen;
+ CTX->cur_dn_len -= clen;
+ T0_PUSH(clen);
+}
+
+\ Write a CertificateRequest message.
+: write-CertificateRequest ( -- )
+ \ The list of client authentication types includes:
+ \ rsa_sign (1)
+ \ ecdsa_sign (64)
+ \ rsa_fixed_ecdh (65)
+ \ ecdsa_fixed_ecdh (66)
+ \ rsa_sign and ecdsa_sign require, respectively, RSA and ECDSA
+ \ support. Static ECDH requires that the cipher suite is ECDH.
+ \ When we ask for static ECDH, we always send both rsa_fixed_ecdh
+ \ and ecdsa_fixed_ecdh because what matters there is what the
+ \ X.509 engine may support, and we do not control that.
+ \
+ \ With TLS 1.2, we must also send a list of supported signature
+ \ and hash algorithms. That list is supposed to qualify both
+ \ the engine itself, and the X.509 validator, which are separate
+ \ in BearSSL. There again, we use the engine capabilities in that
+ \ list, and resort to a generic all-support list if only
+ \ static ECDH is accepted.
+ \
+ \ (In practice, client implementations tend to have at most one
+ \ or two certificates, and send the chain regardless of what
+ \ algorithms are used in it.)
+
+ 0 write-list-auth
+ addr-version get16 0x0303 >= if
+ 2+ 0 write-list-signhash +
+ then
+ ta-names-total-length + 3 +
+
+ \ Message header
+ 13 write8 write24
+
+ \ List of authentication methods
+ 0 write-list-auth write8 1 write-list-auth drop
+
+ \ For TLS 1.2+, list of sign+hash
+ addr-version get16 0x0303 >= if
+ 0 write-list-signhash write16 1 write-list-signhash drop
+ then
+
+ \ Trust anchor names
+ ta-names-total-length write16
+ begin-ta-name-list
+ begin
+ begin-ta-name
+ dup 0< if drop ret then write16
+ begin copy-dn-chunk dup while
+ addr-pad swap write-blob
+ repeat
+ drop
+ again ;
+
+\ Write the Server Hello Done message.
+: write-ServerHelloDone ( -- )
+ 14 write8 0 write24 ;
+
+\ Perform RSA decryption of the client-sent pre-master secret. The value
+\ is in the pad, and its length is provided as parameter.
+cc: do-rsa-decrypt ( len prf_id -- ) {
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_rsa_decrypt(CTX, prf_id, ENG->pad, len);
+}
+
+\ Perform ECDH (not ECDHE). The point from the client is in the pad, and
+\ its length is provided as parameter.
+cc: do-ecdh ( len prf_id -- ) {
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_ecdh(CTX, prf_id, ENG->pad, len);
+}
+
+\ Do the second part of ECDHE.
+cc: do-ecdhe-part2 ( len prf_id -- ) {
+ int prf_id = T0_POPi();
+ size_t len = T0_POP();
+ do_ecdhe_part2(CTX, prf_id, ENG->pad, len);
+}
+
+\ Perform static ECDH. The point from the client is the public key
+\ extracted from its certificate.
+cc: do-static-ecdh ( prf_id -- ) {
+ do_static_ecdh(CTX, T0_POP());
+}
+
+\ Read a ClientKeyExchange header.
+: read-ClientKeyExchange-header ( -- len )
+ read-handshake-header 16 = ifnot ERR_UNEXPECTED fail then ;
+
+\ Read the Client Key Exchange contents (non-empty case).
+: read-ClientKeyExchange-contents ( lim -- )
+ \ What we should get depends on the cipher suite.
+ addr-cipher_suite get16 use-rsa-keyx? if
+ \ RSA key exchange: we expect a RSA-encrypted value.
+ read16
+ dup 512 > if ERR_LIMIT_EXCEEDED fail then
+ dup { enc-rsa-len }
+ addr-pad swap read-blob
+ enc-rsa-len addr-cipher_suite get16 prf-id do-rsa-decrypt
+ then
+ addr-cipher_suite get16 dup use-ecdhe? swap use-ecdh? { ecdhe ecdh }
+ ecdh ecdhe or if
+ \ ECDH or ECDHE key exchange: we expect an EC point.
+ read8 dup { ec-point-len }
+ addr-pad swap read-blob
+ ec-point-len addr-cipher_suite get16 prf-id
+ ecdhe if do-ecdhe-part2 else do-ecdh then
+ then
+ close-elt ;
+
+\ Read the Client Key Exchange (normal case).
+: read-ClientKeyExchange ( -- )
+ read-ClientKeyExchange-header
+ read-ClientKeyExchange-contents ;
+
+\ Obtain all possible hash values for handshake messages so far. This
+\ is done because we need the hash value for the CertificateVerify
+\ _before_ knowing which hash function will actually be used, as this
+\ information is obtained from decoding the message header itself.
+\ All hash values are stored in the pad (208 bytes in total).
+cc: compute-hash-CV ( -- ) {
+ int i;
+
+ for (i = 1; i <= 6; i ++) {
+ br_multihash_out(&ENG->mhash, i,
+ ENG->pad + HASH_PAD_OFF[i - 1]);
+ }
+}
+
+\ Copy the proper hash value from the pad into the dedicated buffer.
+\ Returned value is true (-1) on success, false (0) on error (error
+\ being an unimplemented hash function). The id has already been verified
+\ to be either 0 (for MD5+SHA-1) or one of the SHA-* functions.
+cc: copy-hash-CV ( hash_id -- bool ) {
+ int id = T0_POP();
+ size_t off, len;
+
+ if (id == 0) {
+ off = 0;
+ len = 36;
+ } else {
+ if (br_multihash_getimpl(&ENG->mhash, id) == 0) {
+ T0_PUSH(0);
+ T0_RET();
+ }
+ off = HASH_PAD_OFF[id - 1];
+ len = HASH_PAD_OFF[id] - off;
+ }
+ memcpy(CTX->hash_CV, ENG->pad + off, len);
+ CTX->hash_CV_len = len;
+ CTX->hash_CV_id = id;
+ T0_PUSHi(-1);
+}
+
+\ Verify signature in CertificateVerify. Output is 0 on success, or a
+\ non-zero error code.
+cc: verify-CV-sig ( sig-len -- err ) {
+ int err;
+
+ err = verify_CV_sig(CTX, T0_POP());
+ T0_PUSHi(err);
+}
+
+\ Process static ECDH.
+: process-static-ECDH ( ktu -- )
+ \ Static ECDH is allowed only if the cipher suite uses ECDH, and
+ \ the client's public key has type EC and allows key exchange.
+ \ BR_KEYTYPE_KEYX is 0x10, and BR_KEYTYPE_EC is 2.
+ 0x1F and 0x12 = ifnot ERR_WRONG_KEY_USAGE fail then
+ addr-cipher_suite get16
+ dup use-ecdh? ifnot ERR_UNEXPECTED fail then
+ prf-id
+ do-static-ecdh ;
+
+\ Read CertificateVerify header.
+: read-CertificateVerify-header ( -- lim )
+ compute-hash-CV
+ read-handshake-header 15 = ifnot ERR_UNEXPECTED fail then ;
+
+\ Read CertificateVerify. The client key type + usage is expected on the
+\ stack.
+: read-CertificateVerify ( ktu -- )
+ \ Check that the key allows for signatures.
+ dup 0x20 and ifnot ERR_WRONG_KEY_USAGE fail then
+ 0x0F and { key-type }
+
+ \ Get header.
+ read-CertificateVerify-header
+
+ \ With TLS 1.2+, there is an explicit hash + signature indication,
+ \ which must be compatible with the key type.
+ addr-version get16 0x0303 >= if
+ \ Get hash function, then signature algorithm. The
+ \ signature algorithm is 1 (RSA) or 3 (ECDSA) while our
+ \ symbolic constants for key types are 1 (RSA) or 2 (EC).
+ read16
+ dup 0xFF and 1+ 1 >> key-type = ifnot
+ ERR_BAD_SIGNATURE fail
+ then
+ 8 >>
+
+ \ We support only SHA-1, SHA-224, SHA-256, SHA-384
+ \ and SHA-512. We explicitly reject MD5.
+ dup 2 < over 6 > or if ERR_INVALID_ALGORITHM fail then
+ else
+ \ With TLS 1.0 and 1.1, hash is MD5+SHA-1 (0) for RSA,
+ \ SHA-1 (2) for ECDSA.
+ key-type 0x01 = if 0 else 2 then
+ then
+ copy-hash-CV ifnot ERR_INVALID_ALGORITHM fail then
+
+ \ Read signature.
+ read16 dup { sig-len }
+ dup 512 > if ERR_LIMIT_EXCEEDED fail then
+ addr-pad swap read-blob
+ sig-len verify-CV-sig
+ dup if fail then drop
+
+ close-elt ;
+
+\ Send a HelloRequest.
+: send-HelloRequest ( -- )
+ flush-record
+ begin can-output? not while wait-co drop repeat
+ 22 addr-record_type_out set8
+ 0 write8 0 write24 flush-record
+ 23 addr-record_type_out set8 ;
+
+\ Make a handshake.
+: do-handshake ( initial -- )
+ 0 addr-application_data set8
+ 22 addr-record_type_out set8
+ 0 addr-selected_protocol set16
+ multihash-init
+ read-ClientHello
+ more-incoming-bytes? if ERR_UNEXPECTED fail then
+ if
+ \ Session resumption
+ write-ServerHello
+ 0 write-CCS-Finished
+ 0 read-CCS-Finished
+ else
+ \ Not a session resumption
+ write-ServerHello
+ write-Certificate drop
+ write-ServerKeyExchange
+ ta-names-total-length if
+ write-CertificateRequest
+ then
+ write-ServerHelloDone
+ flush-record
+
+ \ If we sent a CertificateRequest then we expect a
+ \ Certificate message.
+ ta-names-total-length if
+ \ Read client certificate.
+ 0 read-Certificate
+
+ choice
+ dup 0< uf
+ \ Client certificate validation failed.
+ 2 flag? ifnot neg fail then
+ drop
+ read-ClientKeyExchange
+ read-CertificateVerify-header
+ dup skip-blob drop
+ enduf
+ dup 0= uf
+ \ Client sent no certificate at all.
+ drop
+ 2 flag? ifnot
+ ERR_NO_CLIENT_AUTH fail
+ then
+ read-ClientKeyExchange
+ enduf
+
+ \ Client certificate was validated.
+ read-ClientKeyExchange-header
+ dup ifnot
+ \ Empty ClientKeyExchange.
+ drop
+ process-static-ECDH
+ else
+ read-ClientKeyExchange-contents
+ read-CertificateVerify
+ then
+ endchoice
+ else
+ \ No client certificate request, we just expect
+ \ a non-empty ClientKeyExchange.
+ read-ClientKeyExchange
+ then
+ 0 read-CCS-Finished
+ 0 write-CCS-Finished
+ save-session
+ then
+ 1 addr-application_data set8
+ 23 addr-record_type_out set8 ;
+
+\ Entry point.
+: main ( -- ! )
+ \ Perform initial handshake.
+ -1 do-handshake
+
+ begin
+ \ Wait for further invocation. At that point, we should
+ \ get either an explicit call for renegotiation, or
+ \ an incoming ClientHello handshake message.
+ wait-co
+ dup 0x07 and case
+ 0x00 of
+ 0x10 and if
+ \ The best we can do is ask for a
+ \ renegotiation, then wait for it
+ \ to happen.
+ 0 addr-application_data set8
+ send-HelloRequest
+ then
+ endof
+ 0x01 of
+ \ Reject renegotiations if the peer does not
+ \ support secure renegotiation, or if the
+ \ "no renegotiation" flag is set.
+ drop
+ addr-reneg get8 1 = 1 flag? or if
+ skip-ClientHello
+ flush-record
+ begin can-output? not while
+ wait-co drop
+ repeat
+ 100 send-warning
+ \ Put back connection in "application
+ \ data" state: it's not dead yet.
+ 1 addr-application_data set8
+ 23 addr-record_type_out set8
+ else
+ 0 do-handshake
+ then
+ endof
+ ERR_UNEXPECTED fail
+ endcase
+ again
+ ;
diff --git a/contrib/bearssl/src/ssl/ssl_io.c b/contrib/bearssl/src/ssl/ssl_io.c
new file mode 100644
index 000000000000..1952615959ef
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_io.c
@@ -0,0 +1,261 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_sslio_init(br_sslio_context *ctx,
+ br_ssl_engine_context *engine,
+ int (*low_read)(void *read_context,
+ unsigned char *data, size_t len),
+ void *read_context,
+ int (*low_write)(void *write_context,
+ const unsigned char *data, size_t len),
+ void *write_context)
+{
+ ctx->engine = engine;
+ ctx->low_read = low_read;
+ ctx->read_context = read_context;
+ ctx->low_write = low_write;
+ ctx->write_context = write_context;
+}
+
+/*
+ * Run the engine, until the specified target state is achieved, or
+ * an error occurs. The target state is SENDAPP, RECVAPP, or the
+ * combination of both (the combination matches either). When a match is
+ * achieved, this function returns 0. On error, it returns -1.
+ */
+static int
+run_until(br_sslio_context *ctx, unsigned target)
+{
+ for (;;) {
+ unsigned state;
+
+ state = br_ssl_engine_current_state(ctx->engine);
+ if (state & BR_SSL_CLOSED) {
+ return -1;
+ }
+
+ /*
+ * If there is some record data to send, do it. This takes
+ * precedence over everything else.
+ */
+ if (state & BR_SSL_SENDREC) {
+ unsigned char *buf;
+ size_t len;
+ int wlen;
+
+ buf = br_ssl_engine_sendrec_buf(ctx->engine, &len);
+ wlen = ctx->low_write(ctx->write_context, buf, len);
+ if (wlen < 0) {
+ /*
+ * If we received a close_notify and we
+ * still send something, then we have our
+ * own response close_notify to send, and
+ * the peer is allowed by RFC 5246 not to
+ * wait for it.
+ */
+ if (!ctx->engine->shutdown_recv) {
+ br_ssl_engine_fail(
+ ctx->engine, BR_ERR_IO);
+ }
+ return -1;
+ }
+ if (wlen > 0) {
+ br_ssl_engine_sendrec_ack(ctx->engine, wlen);
+ }
+ continue;
+ }
+
+ /*
+ * If we reached our target, then we are finished.
+ */
+ if (state & target) {
+ return 0;
+ }
+
+ /*
+ * If some application data must be read, and we did not
+ * exit, then this means that we are trying to write data,
+ * and that's not possible until the application data is
+ * read. This may happen if using a shared in/out buffer,
+ * and the underlying protocol is not strictly half-duplex.
+ * This is unrecoverable here, so we report an error.
+ */
+ if (state & BR_SSL_RECVAPP) {
+ return -1;
+ }
+
+ /*
+ * If we reached that point, then either we are trying
+ * to read data and there is some, or the engine is stuck
+ * until a new record is obtained.
+ */
+ if (state & BR_SSL_RECVREC) {
+ unsigned char *buf;
+ size_t len;
+ int rlen;
+
+ buf = br_ssl_engine_recvrec_buf(ctx->engine, &len);
+ rlen = ctx->low_read(ctx->read_context, buf, len);
+ if (rlen < 0) {
+ br_ssl_engine_fail(ctx->engine, BR_ERR_IO);
+ return -1;
+ }
+ if (rlen > 0) {
+ br_ssl_engine_recvrec_ack(ctx->engine, rlen);
+ }
+ continue;
+ }
+
+ /*
+ * We can reach that point if the target RECVAPP, and
+ * the state contains SENDAPP only. This may happen with
+ * a shared in/out buffer. In that case, we must flush
+ * the buffered data to "make room" for a new incoming
+ * record.
+ */
+ br_ssl_engine_flush(ctx->engine, 0);
+ }
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_read(br_sslio_context *ctx, void *dst, size_t len)
+{
+ unsigned char *buf;
+ size_t alen;
+
+ if (len == 0) {
+ return 0;
+ }
+ if (run_until(ctx, BR_SSL_RECVAPP) < 0) {
+ return -1;
+ }
+ buf = br_ssl_engine_recvapp_buf(ctx->engine, &alen);
+ if (alen > len) {
+ alen = len;
+ }
+ memcpy(dst, buf, alen);
+ br_ssl_engine_recvapp_ack(ctx->engine, alen);
+ return (int)alen;
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_read_all(br_sslio_context *ctx, void *dst, size_t len)
+{
+ unsigned char *buf;
+
+ buf = dst;
+ while (len > 0) {
+ int rlen;
+
+ rlen = br_sslio_read(ctx, buf, len);
+ if (rlen < 0) {
+ return -1;
+ }
+ buf += rlen;
+ len -= (size_t)rlen;
+ }
+ return 0;
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_write(br_sslio_context *ctx, const void *src, size_t len)
+{
+ unsigned char *buf;
+ size_t alen;
+
+ if (len == 0) {
+ return 0;
+ }
+ if (run_until(ctx, BR_SSL_SENDAPP) < 0) {
+ return -1;
+ }
+ buf = br_ssl_engine_sendapp_buf(ctx->engine, &alen);
+ if (alen > len) {
+ alen = len;
+ }
+ memcpy(buf, src, alen);
+ br_ssl_engine_sendapp_ack(ctx->engine, alen);
+ return (int)alen;
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_write_all(br_sslio_context *ctx, const void *src, size_t len)
+{
+ const unsigned char *buf;
+
+ buf = src;
+ while (len > 0) {
+ int wlen;
+
+ wlen = br_sslio_write(ctx, buf, len);
+ if (wlen < 0) {
+ return -1;
+ }
+ buf += wlen;
+ len -= (size_t)wlen;
+ }
+ return 0;
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_flush(br_sslio_context *ctx)
+{
+ /*
+ * We trigger a flush. We know the data is gone when there is
+ * no longer any record data to send, and we can either read
+ * or write application data. The call to run_until() does the
+ * job because it ensures that any assembled record data is
+ * first sent down the wire before considering anything else.
+ */
+ br_ssl_engine_flush(ctx->engine, 0);
+ return run_until(ctx, BR_SSL_SENDAPP | BR_SSL_RECVAPP);
+}
+
+/* see bearssl_ssl.h */
+int
+br_sslio_close(br_sslio_context *ctx)
+{
+ br_ssl_engine_close(ctx->engine);
+ while (br_ssl_engine_current_state(ctx->engine) != BR_SSL_CLOSED) {
+ /*
+ * Discard any incoming application data.
+ */
+ size_t len;
+
+ run_until(ctx, BR_SSL_RECVAPP);
+ if (br_ssl_engine_recvapp_buf(ctx->engine, &len) != NULL) {
+ br_ssl_engine_recvapp_ack(ctx->engine, len);
+ }
+ }
+ return br_ssl_engine_last_error(ctx->engine) == BR_ERR_OK;
+}
diff --git a/contrib/bearssl/src/ssl/ssl_keyexport.c b/contrib/bearssl/src/ssl/ssl_keyexport.c
new file mode 100644
index 000000000000..58e6dc3cde46
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_keyexport.c
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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"
+
+/*
+ * Supported cipher suites that use SHA-384 for the PRF when selected
+ * for TLS 1.2. All other cipher suites are deemed to use SHA-256.
+ */
+static const uint16_t suites_sha384[] = {
+ BR_TLS_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384
+};
+
+/* see bearssl_ssl.h */
+int
+br_ssl_key_export(br_ssl_engine_context *cc,
+ void *dst, size_t len, const char *label,
+ const void *context, size_t context_len)
+{
+ br_tls_prf_seed_chunk chunks[4];
+ br_tls_prf_impl iprf;
+ size_t num_chunks, u;
+ unsigned char tmp[2];
+ int prf_id;
+
+ if (cc->application_data != 1) {
+ return 0;
+ }
+ chunks[0].data = cc->client_random;
+ chunks[0].len = sizeof cc->client_random;
+ chunks[1].data = cc->server_random;
+ chunks[1].len = sizeof cc->server_random;
+ if (context != NULL) {
+ br_enc16be(tmp, (unsigned)context_len);
+ chunks[2].data = tmp;
+ chunks[2].len = 2;
+ chunks[3].data = context;
+ chunks[3].len = context_len;
+ num_chunks = 4;
+ } else {
+ num_chunks = 2;
+ }
+ prf_id = BR_SSLPRF_SHA256;
+ for (u = 0; u < (sizeof suites_sha384) / sizeof(uint16_t); u ++) {
+ if (suites_sha384[u] == cc->session.cipher_suite) {
+ prf_id = BR_SSLPRF_SHA384;
+ }
+ }
+ iprf = br_ssl_engine_get_PRF(cc, prf_id);
+ iprf(dst, len,
+ cc->session.master_secret, sizeof cc->session.master_secret,
+ label, num_chunks, chunks);
+ return 1;
+}
diff --git a/contrib/bearssl/src/ssl/ssl_lru.c b/contrib/bearssl/src/ssl/ssl_lru.c
new file mode 100644
index 000000000000..4c71011f0885
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_lru.c
@@ -0,0 +1,537 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * Each entry consists in a fixed number of bytes. Entries are concatenated
+ * in the store block. "Addresses" are really offsets in the block,
+ * expressed over 32 bits (so the cache may have size at most 4 GB, which
+ * "ought to be enough for everyone"). The "null address" is 0xFFFFFFFF.
+ * Note that since the storage block alignment is in no way guaranteed, we
+ * perform only accesses that can handle unaligned data.
+ *
+ * Two concurrent data structures are maintained:
+ *
+ * -- Entries are organised in a doubly-linked list; saved entries are added
+ * at the head, and loaded entries are moved to the head. Eviction uses
+ * the list tail (this is the LRU algorithm).
+ *
+ * -- Entries are indexed with a binary tree: all left descendants of a
+ * node have a lower session ID (in lexicographic order), while all
+ * right descendants have a higher session ID. The tree is heuristically
+ * balanced.
+ *
+ * Entry format:
+ *
+ * session ID 32 bytes
+ * master secret 48 bytes
+ * protocol version 2 bytes (big endian)
+ * cipher suite 2 bytes (big endian)
+ * list prev 4 bytes (big endian)
+ * list next 4 bytes (big endian)
+ * tree left child 4 bytes (big endian)
+ * tree right child 4 bytes (big endian)
+ *
+ * If an entry has a protocol version set to 0, then it is "disabled":
+ * it was a session pushed to the cache at some point, but it has
+ * been explicitly removed.
+ *
+ * We need to keep the tree balanced because an attacker could make
+ * handshakes, selecting some specific sessions (by reusing them) to
+ * try to make us make an imbalanced tree that makes lookups expensive
+ * (a denial-of-service attack that would persist as long as the cache
+ * remains, i.e. even after the attacker made all his connections).
+ * To do that, we replace the session ID (or the start of the session ID)
+ * with a HMAC value computed over the replaced part; the hash function
+ * implementation and the key are obtained from the server context upon
+ * first save() call.
+ *
+ * Theoretically, an attacker could use the exact timing of the lookup
+ * to infer the current tree topology, and try to revive entries to make
+ * it as unbalanced as possible. However, since the session ID are
+ * chosen randomly by the server, and the attacker cannot see the
+ * indexing values and must thus rely on blind selection, it should be
+ * exponentially difficult for the attacker to maintain a large
+ * imbalance.
+ */
+#define SESSION_ID_LEN 32
+#define MASTER_SECRET_LEN 48
+
+#define SESSION_ID_OFF 0
+#define MASTER_SECRET_OFF 32
+#define VERSION_OFF 80
+#define CIPHER_SUITE_OFF 82
+#define LIST_PREV_OFF 84
+#define LIST_NEXT_OFF 88
+#define TREE_LEFT_OFF 92
+#define TREE_RIGHT_OFF 96
+
+#define LRU_ENTRY_LEN 100
+
+#define ADDR_NULL ((uint32_t)-1)
+
+#define GETSET(name, off) \
+static inline uint32_t get_ ## name(br_ssl_session_cache_lru *cc, uint32_t x) \
+{ \
+ return br_dec32be(cc->store + x + (off)); \
+} \
+static inline void set_ ## name(br_ssl_session_cache_lru *cc, \
+ uint32_t x, uint32_t val) \
+{ \
+ br_enc32be(cc->store + x + (off), val); \
+}
+
+GETSET(prev, LIST_PREV_OFF)
+GETSET(next, LIST_NEXT_OFF)
+GETSET(left, TREE_LEFT_OFF)
+GETSET(right, TREE_RIGHT_OFF)
+
+/*
+ * Transform the session ID by replacing the first N bytes with a HMAC
+ * value computed over these bytes, using the random key K (the HMAC
+ * value is truncated if needed). HMAC will use the same hash function
+ * as the DRBG in the SSL server context, so with SHA-256, SHA-384,
+ * or SHA-1, depending on what is available.
+ *
+ * The risk of collision is considered too small to be a concern; and
+ * the impact of a collision is low (the handshake won't succeed). This
+ * risk is much lower than any transmission error, which would lead to
+ * the same consequences.
+ *
+ * Source and destination arrays msut be disjoint.
+ */
+static void
+mask_id(br_ssl_session_cache_lru *cc,
+ const unsigned char *src, unsigned char *dst)
+{
+ br_hmac_key_context hkc;
+ br_hmac_context hc;
+
+ memcpy(dst, src, SESSION_ID_LEN);
+ br_hmac_key_init(&hkc, cc->hash, cc->index_key, sizeof cc->index_key);
+ br_hmac_init(&hc, &hkc, SESSION_ID_LEN);
+ br_hmac_update(&hc, src, SESSION_ID_LEN);
+ br_hmac_out(&hc, dst);
+}
+
+/*
+ * Find a node by ID. Returned value is the node address, or ADDR_NULL if
+ * the node is not found.
+ *
+ * If addr_link is not NULL, then '*addr_link' is set to the address of the
+ * last followed link. If the found node is the root, or if the tree is
+ * empty, then '*addr_link' is set to ADDR_NULL.
+ */
+static uint32_t
+find_node(br_ssl_session_cache_lru *cc, const unsigned char *id,
+ uint32_t *addr_link)
+{
+ uint32_t x, y;
+
+ x = cc->root;
+ y = ADDR_NULL;
+ while (x != ADDR_NULL) {
+ int r;
+
+ r = memcmp(id, cc->store + x + SESSION_ID_OFF, SESSION_ID_LEN);
+ if (r < 0) {
+ y = x + TREE_LEFT_OFF;
+ x = get_left(cc, x);
+ } else if (r == 0) {
+ if (addr_link != NULL) {
+ *addr_link = y;
+ }
+ return x;
+ } else {
+ y = x + TREE_RIGHT_OFF;
+ x = get_right(cc, x);
+ }
+ }
+ if (addr_link != NULL) {
+ *addr_link = y;
+ }
+ return ADDR_NULL;
+}
+
+/*
+ * For node x, find its replacement upon removal.
+ *
+ * -- If node x has no child, then this returns ADDR_NULL.
+ * -- Otherwise, if node x has a left child, then the replacement is the
+ * rightmost left-descendent.
+ * -- Otherwise, the replacement is the leftmost right-descendent.
+ *
+ * If a node is returned, then '*al' is set to the address of the field
+ * that points to that node. Otherwise (node x has no child), '*al' is
+ * set to ADDR_NULL.
+ *
+ * Note that the replacement node, when found, is always a descendent
+ * of node 'x', so it cannot be the tree root. Thus, '*al' can be set
+ * to ADDR_NULL only when no node is found and ADDR_NULL is returned.
+ */
+static uint32_t
+find_replacement_node(br_ssl_session_cache_lru *cc, uint32_t x, uint32_t *al)
+{
+ uint32_t y1, y2;
+
+ y1 = get_left(cc, x);
+ if (y1 != ADDR_NULL) {
+ y2 = x + TREE_LEFT_OFF;
+ for (;;) {
+ uint32_t z;
+
+ z = get_right(cc, y1);
+ if (z == ADDR_NULL) {
+ *al = y2;
+ return y1;
+ }
+ y2 = y1 + TREE_RIGHT_OFF;
+ y1 = z;
+ }
+ }
+ y1 = get_right(cc, x);
+ if (y1 != ADDR_NULL) {
+ y2 = x + TREE_RIGHT_OFF;
+ for (;;) {
+ uint32_t z;
+
+ z = get_left(cc, y1);
+ if (z == ADDR_NULL) {
+ *al = y2;
+ return y1;
+ }
+ y2 = y1 + TREE_LEFT_OFF;
+ y1 = z;
+ }
+ }
+ *al = ADDR_NULL;
+ return ADDR_NULL;
+}
+
+/*
+ * Set the link at address 'alx' to point to node 'x'. If 'alx' is
+ * ADDR_NULL, then this sets the tree root to 'x'.
+ */
+static inline void
+set_link(br_ssl_session_cache_lru *cc, uint32_t alx, uint32_t x)
+{
+ if (alx == ADDR_NULL) {
+ cc->root = x;
+ } else {
+ br_enc32be(cc->store + alx, x);
+ }
+}
+
+/*
+ * Remove node 'x' from the tree. This function shall not be called if
+ * node 'x' is not part of the tree.
+ */
+static void
+remove_node(br_ssl_session_cache_lru *cc, uint32_t x)
+{
+ uint32_t alx, y, aly;
+
+ /*
+ * Removal algorithm:
+ * ------------------
+ *
+ * - If we remove the root, then the tree becomes empty.
+ *
+ * - If the removed node has no child, then we can simply remove
+ * it, with nothing else to do.
+ *
+ * - Otherwise, the removed node must be replaced by either its
+ * rightmost left-descendent, or its leftmost right-descendent.
+ * The replacement node itself must be removed from its current
+ * place. By definition, that replacement node has either no
+ * child, or at most a single child that will replace it in the
+ * tree.
+ */
+
+ /*
+ * Find node back and its ancestor link. If the node was the
+ * root, then alx is set to ADDR_NULL.
+ */
+ find_node(cc, cc->store + x + SESSION_ID_OFF, &alx);
+
+ /*
+ * Find replacement node 'y', and 'aly' is set to the address of
+ * the link to that replacement node. If the removed node has no
+ * child, then both 'y' and 'aly' are set to ADDR_NULL.
+ */
+ y = find_replacement_node(cc, x, &aly);
+
+ if (y != ADDR_NULL) {
+ uint32_t z;
+
+ /*
+ * The unlinked replacement node may have one child (but
+ * not two) that takes its place.
+ */
+ z = get_left(cc, y);
+ if (z == ADDR_NULL) {
+ z = get_right(cc, y);
+ }
+ set_link(cc, aly, z);
+
+ /*
+ * Link the replacement node in its new place, overwriting
+ * the current link to the node 'x' (which removes 'x').
+ */
+ set_link(cc, alx, y);
+
+ /*
+ * The replacement node adopts the left and right children
+ * of the removed node. Note that this also works even if
+ * the replacement node was a direct descendent of the
+ * removed node, since we unlinked it previously.
+ */
+ set_left(cc, y, get_left(cc, x));
+ set_right(cc, y, get_right(cc, x));
+ } else {
+ /*
+ * No replacement, we simply unlink the node 'x'.
+ */
+ set_link(cc, alx, ADDR_NULL);
+ }
+}
+
+static void
+lru_save(const br_ssl_session_cache_class **ctx,
+ br_ssl_server_context *server_ctx,
+ const br_ssl_session_parameters *params)
+{
+ br_ssl_session_cache_lru *cc;
+ unsigned char id[SESSION_ID_LEN];
+ uint32_t x, alx;
+
+ cc = (br_ssl_session_cache_lru *)ctx;
+
+ /*
+ * If the buffer is too small, we don't record anything. This
+ * test avoids problems in subsequent code.
+ */
+ if (cc->store_len < LRU_ENTRY_LEN) {
+ return;
+ }
+
+ /*
+ * Upon the first save in a session cache instance, we obtain
+ * a random key for our indexing.
+ */
+ if (!cc->init_done) {
+ br_hmac_drbg_generate(&server_ctx->eng.rng,
+ cc->index_key, sizeof cc->index_key);
+ cc->hash = br_hmac_drbg_get_hash(&server_ctx->eng.rng);
+ cc->init_done = 1;
+ }
+ mask_id(cc, params->session_id, id);
+
+ /*
+ * Look for the node in the tree. If the same ID is already used,
+ * then reject it. This is a collision event, which should be
+ * exceedingly rare.
+ * Note: we do NOT record the emplacement here, because the
+ * removal of an entry may change the tree topology.
+ */
+ if (find_node(cc, id, NULL) != ADDR_NULL) {
+ return;
+ }
+
+ /*
+ * Find some room for the new parameters. If the cache is not
+ * full yet, add it to the end of the area and bump the pointer up.
+ * Otherwise, evict the list tail entry. Note that we already
+ * filtered out the case of a ridiculously small buffer that
+ * cannot hold any entry at all; thus, if there is no room for an
+ * extra entry, then the cache cannot be empty.
+ */
+ if (cc->store_ptr > (cc->store_len - LRU_ENTRY_LEN)) {
+ /*
+ * Evict tail. If the buffer has room for a single entry,
+ * then this may also be the head.
+ */
+ x = cc->tail;
+ cc->tail = get_prev(cc, x);
+ if (cc->tail == ADDR_NULL) {
+ cc->head = ADDR_NULL;
+ } else {
+ set_next(cc, cc->tail, ADDR_NULL);
+ }
+
+ /*
+ * Remove the node from the tree.
+ */
+ remove_node(cc, x);
+ } else {
+ /*
+ * Allocate room for new node.
+ */
+ x = cc->store_ptr;
+ cc->store_ptr += LRU_ENTRY_LEN;
+ }
+
+ /*
+ * Find the emplacement for the new node, and link it.
+ */
+ find_node(cc, id, &alx);
+ set_link(cc, alx, x);
+ set_left(cc, x, ADDR_NULL);
+ set_right(cc, x, ADDR_NULL);
+
+ /*
+ * New entry becomes new list head. It may also become the list
+ * tail if the cache was empty at that point.
+ */
+ if (cc->head == ADDR_NULL) {
+ cc->tail = x;
+ } else {
+ set_prev(cc, cc->head, x);
+ }
+ set_prev(cc, x, ADDR_NULL);
+ set_next(cc, x, cc->head);
+ cc->head = x;
+
+ /*
+ * Fill data in the entry.
+ */
+ memcpy(cc->store + x + SESSION_ID_OFF, id, SESSION_ID_LEN);
+ memcpy(cc->store + x + MASTER_SECRET_OFF,
+ params->master_secret, MASTER_SECRET_LEN);
+ br_enc16be(cc->store + x + VERSION_OFF, params->version);
+ br_enc16be(cc->store + x + CIPHER_SUITE_OFF, params->cipher_suite);
+}
+
+static int
+lru_load(const br_ssl_session_cache_class **ctx,
+ br_ssl_server_context *server_ctx,
+ br_ssl_session_parameters *params)
+{
+ br_ssl_session_cache_lru *cc;
+ unsigned char id[SESSION_ID_LEN];
+ uint32_t x;
+
+ (void)server_ctx;
+ cc = (br_ssl_session_cache_lru *)ctx;
+ if (!cc->init_done) {
+ return 0;
+ }
+ mask_id(cc, params->session_id, id);
+ x = find_node(cc, id, NULL);
+ if (x != ADDR_NULL) {
+ unsigned version;
+
+ version = br_dec16be(cc->store + x + VERSION_OFF);
+ if (version == 0) {
+ /*
+ * Entry is disabled, we pretend we did not find it.
+ * Notably, we don't move it to the front of the
+ * LRU list.
+ */
+ return 0;
+ }
+ params->version = version;
+ params->cipher_suite = br_dec16be(
+ cc->store + x + CIPHER_SUITE_OFF);
+ memcpy(params->master_secret,
+ cc->store + x + MASTER_SECRET_OFF,
+ MASTER_SECRET_LEN);
+ if (x != cc->head) {
+ /*
+ * Found node is not at list head, so move
+ * it to the head.
+ */
+ uint32_t p, n;
+
+ p = get_prev(cc, x);
+ n = get_next(cc, x);
+ set_next(cc, p, n);
+ if (n == ADDR_NULL) {
+ cc->tail = p;
+ } else {
+ set_prev(cc, n, p);
+ }
+ set_prev(cc, cc->head, x);
+ set_next(cc, x, cc->head);
+ set_prev(cc, x, ADDR_NULL);
+ cc->head = x;
+ }
+ return 1;
+ }
+ return 0;
+}
+
+static const br_ssl_session_cache_class lru_class = {
+ sizeof(br_ssl_session_cache_lru),
+ &lru_save,
+ &lru_load
+};
+
+/* see inner.h */
+void
+br_ssl_session_cache_lru_init(br_ssl_session_cache_lru *cc,
+ unsigned char *store, size_t store_len)
+{
+ cc->vtable = &lru_class;
+ cc->store = store;
+ cc->store_len = store_len;
+ cc->store_ptr = 0;
+ cc->init_done = 0;
+ cc->head = ADDR_NULL;
+ cc->tail = ADDR_NULL;
+ cc->root = ADDR_NULL;
+}
+
+/* see bearssl_ssl.h */
+void br_ssl_session_cache_lru_forget(
+ br_ssl_session_cache_lru *cc, const unsigned char *id)
+{
+ unsigned char mid[SESSION_ID_LEN];
+ uint32_t addr;
+
+ /*
+ * If the cache is not initialised yet, then it is empty, and
+ * there is nothing to forget.
+ */
+ if (!cc->init_done) {
+ return;
+ }
+
+ /*
+ * Look for the node in the tree. If found, the entry is marked
+ * as "disabled"; it will be reused in due course, as it ages
+ * through the list.
+ *
+ * We do not go through the complex moves of actually releasing
+ * the entry right away because explicitly forgetting sessions
+ * should be a rare event, meant mostly for testing purposes,
+ * so this is not worth the extra code size.
+ */
+ mask_id(cc, id, mid);
+ addr = find_node(cc, mid, NULL);
+ if (addr != ADDR_NULL) {
+ br_enc16be(cc->store + addr + VERSION_OFF, 0);
+ }
+}
diff --git a/contrib/bearssl/src/ssl/ssl_rec_cbc.c b/contrib/bearssl/src/ssl/ssl_rec_cbc.c
new file mode 100644
index 000000000000..c0806049e3cd
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_rec_cbc.c
@@ -0,0 +1,440 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+static void
+in_cbc_init(br_sslrec_in_cbc_context *cc,
+ const br_block_cbcdec_class *bc_impl,
+ const void *bc_key, size_t bc_key_len,
+ const br_hash_class *dig_impl,
+ const void *mac_key, size_t mac_key_len, size_t mac_out_len,
+ const void *iv)
+{
+ cc->vtable = &br_sslrec_in_cbc_vtable;
+ cc->seq = 0;
+ bc_impl->init(&cc->bc.vtable, bc_key, bc_key_len);
+ br_hmac_key_init(&cc->mac, dig_impl, mac_key, mac_key_len);
+ cc->mac_len = mac_out_len;
+ if (iv == NULL) {
+ memset(cc->iv, 0, sizeof cc->iv);
+ cc->explicit_IV = 1;
+ } else {
+ memcpy(cc->iv, iv, bc_impl->block_size);
+ cc->explicit_IV = 0;
+ }
+}
+
+static int
+cbc_check_length(const br_sslrec_in_cbc_context *cc, size_t rlen)
+{
+ /*
+ * Plaintext size: at most 16384 bytes
+ * Padding: at most 256 bytes
+ * MAC: mac_len extra bytes
+ * TLS 1.1+: each record has an explicit IV
+ *
+ * Minimum length includes at least one byte of padding, and the
+ * MAC.
+ *
+ * Total length must be a multiple of the block size.
+ */
+ size_t blen;
+ size_t min_len, max_len;
+
+ blen = cc->bc.vtable->block_size;
+ min_len = (blen + cc->mac_len) & ~(blen - 1);
+ max_len = (16384 + 256 + cc->mac_len) & ~(blen - 1);
+ if (cc->explicit_IV) {
+ min_len += blen;
+ max_len += blen;
+ }
+ return min_len <= rlen && rlen <= max_len;
+}
+
+/*
+ * Rotate array buf[] of length 'len' to the left (towards low indices)
+ * by 'num' bytes if ctl is 1; otherwise, leave it unchanged. This is
+ * constant-time. 'num' MUST be lower than 'len'. 'len' MUST be lower
+ * than or equal to 64.
+ */
+static void
+cond_rotate(uint32_t ctl, unsigned char *buf, size_t len, size_t num)
+{
+ unsigned char tmp[64];
+ size_t u, v;
+
+ for (u = 0, v = num; u < len; u ++) {
+ tmp[u] = MUX(ctl, buf[v], buf[u]);
+ if (++ v == len) {
+ v = 0;
+ }
+ }
+ memcpy(buf, tmp, len);
+}
+
+static unsigned char *
+cbc_decrypt(br_sslrec_in_cbc_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ /*
+ * We represent all lengths on 32-bit integers, because:
+ * -- SSL record lengths always fit in 32 bits;
+ * -- our constant-time primitives operate on 32-bit integers.
+ */
+ unsigned char *buf;
+ uint32_t u, v, len, blen, min_len, max_len;
+ uint32_t good, pad_len, rot_count, len_withmac, len_nomac;
+ unsigned char tmp1[64], tmp2[64];
+ int i;
+ br_hmac_context hc;
+
+ buf = data;
+ len = *data_len;
+ blen = cc->bc.vtable->block_size;
+
+ /*
+ * Decrypt data, and skip the explicit IV (if applicable). Note
+ * that the total length is supposed to have been verified by
+ * the caller. If there is an explicit IV, then we actually
+ * "decrypt" it using the implicit IV (from previous record),
+ * which is useless but harmless.
+ */
+ cc->bc.vtable->run(&cc->bc.vtable, cc->iv, data, len);
+ if (cc->explicit_IV) {
+ buf += blen;
+ len -= blen;
+ }
+
+ /*
+ * Compute minimum and maximum length of plaintext + MAC. These
+ * lengths can be inferred from the outside: they are not secret.
+ */
+ min_len = (cc->mac_len + 256 < len) ? len - 256 : cc->mac_len;
+ max_len = len - 1;
+
+ /*
+ * Use the last decrypted byte to compute the actual payload
+ * length. Take care not to underflow (we use unsigned types).
+ */
+ pad_len = buf[max_len];
+ good = LE(pad_len, (uint32_t)(max_len - min_len));
+ len = MUX(good, (uint32_t)(max_len - pad_len), min_len);
+
+ /*
+ * Check padding contents: all padding bytes must be equal to
+ * the value of pad_len.
+ */
+ for (u = min_len; u < max_len; u ++) {
+ good &= LT(u, len) | EQ(buf[u], pad_len);
+ }
+
+ /*
+ * Extract the MAC value. This is done in one pass, but results
+ * in a "rotated" MAC value depending on where it actually
+ * occurs. The 'rot_count' value is set to the offset of the
+ * first MAC byte within tmp1[].
+ *
+ * min_len and max_len are also adjusted to the minimum and
+ * maximum lengths of the plaintext alone (without the MAC).
+ */
+ len_withmac = (uint32_t)len;
+ len_nomac = len_withmac - cc->mac_len;
+ min_len -= cc->mac_len;
+ rot_count = 0;
+ memset(tmp1, 0, cc->mac_len);
+ v = 0;
+ for (u = min_len; u < max_len; u ++) {
+ tmp1[v] |= MUX(GE(u, len_nomac) & LT(u, len_withmac),
+ buf[u], 0x00);
+ rot_count = MUX(EQ(u, len_nomac), v, rot_count);
+ if (++ v == cc->mac_len) {
+ v = 0;
+ }
+ }
+ max_len -= cc->mac_len;
+
+ /*
+ * Rotate back the MAC value. The loop below does the constant-time
+ * rotation in time n*log n for a MAC output of length n. We assume
+ * that the MAC output length is no more than 64 bytes, so the
+ * rotation count fits on 6 bits.
+ */
+ for (i = 5; i >= 0; i --) {
+ uint32_t rc;
+
+ rc = (uint32_t)1 << i;
+ cond_rotate(rot_count >> i, tmp1, cc->mac_len, rc);
+ rot_count &= ~rc;
+ }
+
+ /*
+ * Recompute the HMAC value. The input is the concatenation of
+ * the sequence number (8 bytes), the record header (5 bytes),
+ * and the payload.
+ *
+ * At that point, min_len is the minimum plaintext length, but
+ * max_len still includes the MAC length.
+ */
+ br_enc64be(tmp2, cc->seq ++);
+ tmp2[8] = (unsigned char)record_type;
+ br_enc16be(tmp2 + 9, version);
+ br_enc16be(tmp2 + 11, len_nomac);
+ br_hmac_init(&hc, &cc->mac, cc->mac_len);
+ br_hmac_update(&hc, tmp2, 13);
+ br_hmac_outCT(&hc, buf, len_nomac, min_len, max_len, tmp2);
+
+ /*
+ * Compare the extracted and recomputed MAC values.
+ */
+ for (u = 0; u < cc->mac_len; u ++) {
+ good &= EQ0(tmp1[u] ^ tmp2[u]);
+ }
+
+ /*
+ * Check that the plaintext length is valid. The previous
+ * check was on the encrypted length, but the padding may have
+ * turned shorter than expected.
+ *
+ * Once this final test is done, the critical "constant-time"
+ * section ends and we can make conditional jumps again.
+ */
+ good &= LE(len_nomac, 16384);
+
+ if (!good) {
+ return 0;
+ }
+ *data_len = len_nomac;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_in_cbc_class br_sslrec_in_cbc_vtable = {
+ {
+ sizeof(br_sslrec_in_cbc_context),
+ (int (*)(const br_sslrec_in_class *const *, size_t))
+ &cbc_check_length,
+ (unsigned char *(*)(const br_sslrec_in_class **,
+ int, unsigned, void *, size_t *))
+ &cbc_decrypt
+ },
+ (void (*)(const br_sslrec_in_cbc_class **,
+ const br_block_cbcdec_class *, const void *, size_t,
+ const br_hash_class *, const void *, size_t, size_t,
+ const void *))
+ &in_cbc_init
+};
+
+/*
+ * For CBC output:
+ *
+ * -- With TLS 1.1+, there is an explicit IV. Generation method uses
+ * HMAC, computed over the current sequence number, and the current MAC
+ * key. The resulting value is truncated to the size of a block, and
+ * added at the head of the plaintext; it will get encrypted along with
+ * the data. This custom generation mechanism is "safe" under the
+ * assumption that HMAC behaves like a random oracle; since the MAC for
+ * a record is computed over the concatenation of the sequence number,
+ * the record header and the plaintext, the HMAC-for-IV will not collide
+ * with the normal HMAC.
+ *
+ * -- With TLS 1.0, for application data, we want to enforce a 1/n-1
+ * split, as a countermeasure against chosen-plaintext attacks. We thus
+ * need to leave some room in the buffer for that extra record.
+ */
+
+static void
+out_cbc_init(br_sslrec_out_cbc_context *cc,
+ const br_block_cbcenc_class *bc_impl,
+ const void *bc_key, size_t bc_key_len,
+ const br_hash_class *dig_impl,
+ const void *mac_key, size_t mac_key_len, size_t mac_out_len,
+ const void *iv)
+{
+ cc->vtable = &br_sslrec_out_cbc_vtable;
+ cc->seq = 0;
+ bc_impl->init(&cc->bc.vtable, bc_key, bc_key_len);
+ br_hmac_key_init(&cc->mac, dig_impl, mac_key, mac_key_len);
+ cc->mac_len = mac_out_len;
+ if (iv == NULL) {
+ memset(cc->iv, 0, sizeof cc->iv);
+ cc->explicit_IV = 1;
+ } else {
+ memcpy(cc->iv, iv, bc_impl->block_size);
+ cc->explicit_IV = 0;
+ }
+}
+
+static void
+cbc_max_plaintext(const br_sslrec_out_cbc_context *cc,
+ size_t *start, size_t *end)
+{
+ size_t blen, len;
+
+ blen = cc->bc.vtable->block_size;
+ if (cc->explicit_IV) {
+ *start += blen;
+ } else {
+ *start += 4 + ((cc->mac_len + blen + 1) & ~(blen - 1));
+ }
+ len = (*end - *start) & ~(blen - 1);
+ len -= 1 + cc->mac_len;
+ if (len > 16384) {
+ len = 16384;
+ }
+ *end = *start + len;
+}
+
+static unsigned char *
+cbc_encrypt(br_sslrec_out_cbc_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ unsigned char *buf, *rbuf;
+ size_t len, blen, plen;
+ unsigned char tmp[13];
+ br_hmac_context hc;
+
+ buf = data;
+ len = *data_len;
+ blen = cc->bc.vtable->block_size;
+
+ /*
+ * If using TLS 1.0, with more than one byte of plaintext, and
+ * the record is application data, then we need to compute
+ * a "split". We do not perform the split on other record types
+ * because it turned out that some existing, deployed
+ * implementations of SSL/TLS do not tolerate the splitting of
+ * some message types (in particular the Finished message).
+ *
+ * If using TLS 1.1+, then there is an explicit IV. We produce
+ * that IV by adding an extra initial plaintext block, whose
+ * value is computed with HMAC over the record sequence number.
+ */
+ if (cc->explicit_IV) {
+ /*
+ * We use here the fact that all the HMAC variants we
+ * support can produce at least 16 bytes, while all the
+ * block ciphers we support have blocks of no more than
+ * 16 bytes. Thus, we can always truncate the HMAC output
+ * down to the block size.
+ */
+ br_enc64be(tmp, cc->seq);
+ br_hmac_init(&hc, &cc->mac, blen);
+ br_hmac_update(&hc, tmp, 8);
+ br_hmac_out(&hc, buf - blen);
+ rbuf = buf - blen - 5;
+ } else {
+ if (len > 1 && record_type == BR_SSL_APPLICATION_DATA) {
+ /*
+ * To do the split, we use a recursive invocation;
+ * since we only give one byte to the inner call,
+ * the recursion stops there.
+ *
+ * We need to compute the exact size of the extra
+ * record, so that the two resulting records end up
+ * being sequential in RAM.
+ *
+ * We use here the fact that cbc_max_plaintext()
+ * adjusted the start offset to leave room for the
+ * initial fragment.
+ */
+ size_t xlen;
+
+ rbuf = buf - 4
+ - ((cc->mac_len + blen + 1) & ~(blen - 1));
+ rbuf[0] = buf[0];
+ xlen = 1;
+ rbuf = cbc_encrypt(cc, record_type,
+ version, rbuf, &xlen);
+ buf ++;
+ len --;
+ } else {
+ rbuf = buf - 5;
+ }
+ }
+
+ /*
+ * Compute MAC.
+ */
+ br_enc64be(tmp, cc->seq ++);
+ tmp[8] = record_type;
+ br_enc16be(tmp + 9, version);
+ br_enc16be(tmp + 11, len);
+ br_hmac_init(&hc, &cc->mac, cc->mac_len);
+ br_hmac_update(&hc, tmp, 13);
+ br_hmac_update(&hc, buf, len);
+ br_hmac_out(&hc, buf + len);
+ len += cc->mac_len;
+
+ /*
+ * Add padding.
+ */
+ plen = blen - (len & (blen - 1));
+ memset(buf + len, (unsigned)plen - 1, plen);
+ len += plen;
+
+ /*
+ * If an explicit IV is used, the corresponding extra block was
+ * already put in place earlier; we just have to account for it
+ * here.
+ */
+ if (cc->explicit_IV) {
+ buf -= blen;
+ len += blen;
+ }
+
+ /*
+ * Encrypt the whole thing. If there is an explicit IV, we also
+ * encrypt it, which is fine (encryption of a uniformly random
+ * block is still a uniformly random block).
+ */
+ cc->bc.vtable->run(&cc->bc.vtable, cc->iv, buf, len);
+
+ /*
+ * Add the header and return.
+ */
+ buf[-5] = record_type;
+ br_enc16be(buf - 4, version);
+ br_enc16be(buf - 2, len);
+ *data_len = (size_t)((buf + len) - rbuf);
+ return rbuf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_out_cbc_class br_sslrec_out_cbc_vtable = {
+ {
+ sizeof(br_sslrec_out_cbc_context),
+ (void (*)(const br_sslrec_out_class *const *,
+ size_t *, size_t *))
+ &cbc_max_plaintext,
+ (unsigned char *(*)(const br_sslrec_out_class **,
+ int, unsigned, void *, size_t *))
+ &cbc_encrypt
+ },
+ (void (*)(const br_sslrec_out_cbc_class **,
+ const br_block_cbcenc_class *, const void *, size_t,
+ const br_hash_class *, const void *, size_t, size_t,
+ const void *))
+ &out_cbc_init
+};
diff --git a/contrib/bearssl/src/ssl/ssl_rec_ccm.c b/contrib/bearssl/src/ssl/ssl_rec_ccm.c
new file mode 100644
index 000000000000..92c329521581
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_rec_ccm.c
@@ -0,0 +1,213 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * CCM initialisation. This does everything except setting the vtable,
+ * which depends on whether this is a context for encrypting or for
+ * decrypting.
+ */
+static void
+gen_ccm_init(br_sslrec_ccm_context *cc,
+ const br_block_ctrcbc_class *bc_impl,
+ const void *key, size_t key_len,
+ const void *iv, size_t tag_len)
+{
+ cc->seq = 0;
+ bc_impl->init(&cc->bc.vtable, key, key_len);
+ memcpy(cc->iv, iv, sizeof cc->iv);
+ cc->tag_len = tag_len;
+}
+
+static void
+in_ccm_init(br_sslrec_ccm_context *cc,
+ const br_block_ctrcbc_class *bc_impl,
+ const void *key, size_t key_len,
+ const void *iv, size_t tag_len)
+{
+ cc->vtable.in = &br_sslrec_in_ccm_vtable;
+ gen_ccm_init(cc, bc_impl, key, key_len, iv, tag_len);
+}
+
+static int
+ccm_check_length(const br_sslrec_ccm_context *cc, size_t rlen)
+{
+ /*
+ * CCM overhead is 8 bytes for nonce_explicit, and the tag
+ * (normally 8 or 16 bytes, depending on cipher suite).
+ */
+ size_t over;
+
+ over = 8 + cc->tag_len;
+ return rlen >= over && rlen <= (16384 + over);
+}
+
+static unsigned char *
+ccm_decrypt(br_sslrec_ccm_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ br_ccm_context zc;
+ unsigned char *buf;
+ unsigned char nonce[12], header[13];
+ size_t len;
+
+ buf = (unsigned char *)data + 8;
+ len = *data_len - (8 + cc->tag_len);
+
+ /*
+ * Make nonce (implicit + explicit parts).
+ */
+ memcpy(nonce, cc->iv, sizeof cc->iv);
+ memcpy(nonce + 4, data, 8);
+
+ /*
+ * Assemble synthetic header for the AAD.
+ */
+ br_enc64be(header, cc->seq ++);
+ header[8] = (unsigned char)record_type;
+ br_enc16be(header + 9, version);
+ br_enc16be(header + 11, len);
+
+ /*
+ * Perform CCM decryption.
+ */
+ br_ccm_init(&zc, &cc->bc.vtable);
+ br_ccm_reset(&zc, nonce, sizeof nonce, sizeof header, len, cc->tag_len);
+ br_ccm_aad_inject(&zc, header, sizeof header);
+ br_ccm_flip(&zc);
+ br_ccm_run(&zc, 0, buf, len);
+ if (!br_ccm_check_tag(&zc, buf + len)) {
+ return NULL;
+ }
+ *data_len = len;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_in_ccm_class br_sslrec_in_ccm_vtable = {
+ {
+ sizeof(br_sslrec_ccm_context),
+ (int (*)(const br_sslrec_in_class *const *, size_t))
+ &ccm_check_length,
+ (unsigned char *(*)(const br_sslrec_in_class **,
+ int, unsigned, void *, size_t *))
+ &ccm_decrypt
+ },
+ (void (*)(const br_sslrec_in_ccm_class **,
+ const br_block_ctrcbc_class *, const void *, size_t,
+ const void *, size_t))
+ &in_ccm_init
+};
+
+static void
+out_ccm_init(br_sslrec_ccm_context *cc,
+ const br_block_ctrcbc_class *bc_impl,
+ const void *key, size_t key_len,
+ const void *iv, size_t tag_len)
+{
+ cc->vtable.out = &br_sslrec_out_ccm_vtable;
+ gen_ccm_init(cc, bc_impl, key, key_len, iv, tag_len);
+}
+
+static void
+ccm_max_plaintext(const br_sslrec_ccm_context *cc,
+ size_t *start, size_t *end)
+{
+ size_t len;
+
+ *start += 8;
+ len = *end - *start - cc->tag_len;
+ if (len > 16384) {
+ len = 16384;
+ }
+ *end = *start + len;
+}
+
+static unsigned char *
+ccm_encrypt(br_sslrec_ccm_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ br_ccm_context zc;
+ unsigned char *buf;
+ unsigned char nonce[12], header[13];
+ size_t len;
+
+ buf = (unsigned char *)data;
+ len = *data_len;
+
+ /*
+ * Make nonce; the explicit part is an encoding of the sequence
+ * number.
+ */
+ memcpy(nonce, cc->iv, sizeof cc->iv);
+ br_enc64be(nonce + 4, cc->seq);
+
+ /*
+ * Assemble synthetic header for the AAD.
+ */
+ br_enc64be(header, cc->seq ++);
+ header[8] = (unsigned char)record_type;
+ br_enc16be(header + 9, version);
+ br_enc16be(header + 11, len);
+
+ /*
+ * Perform CCM encryption.
+ */
+ br_ccm_init(&zc, &cc->bc.vtable);
+ br_ccm_reset(&zc, nonce, sizeof nonce, sizeof header, len, cc->tag_len);
+ br_ccm_aad_inject(&zc, header, sizeof header);
+ br_ccm_flip(&zc);
+ br_ccm_run(&zc, 1, buf, len);
+ br_ccm_get_tag(&zc, buf + len);
+
+ /*
+ * Assemble header and adjust pointer/length.
+ */
+ len += 8 + cc->tag_len;
+ buf -= 13;
+ memcpy(buf + 5, nonce + 4, 8);
+ buf[0] = (unsigned char)record_type;
+ br_enc16be(buf + 1, version);
+ br_enc16be(buf + 3, len);
+ *data_len = len + 5;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_out_ccm_class br_sslrec_out_ccm_vtable = {
+ {
+ sizeof(br_sslrec_ccm_context),
+ (void (*)(const br_sslrec_out_class *const *,
+ size_t *, size_t *))
+ &ccm_max_plaintext,
+ (unsigned char *(*)(const br_sslrec_out_class **,
+ int, unsigned, void *, size_t *))
+ &ccm_encrypt
+ },
+ (void (*)(const br_sslrec_out_ccm_class **,
+ const br_block_ctrcbc_class *, const void *, size_t,
+ const void *, size_t))
+ &out_ccm_init
+};
diff --git a/contrib/bearssl/src/ssl/ssl_rec_chapol.c b/contrib/bearssl/src/ssl/ssl_rec_chapol.c
new file mode 100644
index 000000000000..73b3c7855473
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_rec_chapol.c
@@ -0,0 +1,177 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+static void
+gen_chapol_init(br_sslrec_chapol_context *cc,
+ br_chacha20_run ichacha, br_poly1305_run ipoly,
+ const void *key, const void *iv)
+{
+ cc->seq = 0;
+ cc->ichacha = ichacha;
+ cc->ipoly = ipoly;
+ memcpy(cc->key, key, sizeof cc->key);
+ memcpy(cc->iv, iv, sizeof cc->iv);
+}
+
+static void
+gen_chapol_process(br_sslrec_chapol_context *cc,
+ int record_type, unsigned version, void *data, size_t len,
+ void *tag, int encrypt)
+{
+ unsigned char header[13];
+ unsigned char nonce[12];
+ uint64_t seq;
+ size_t u;
+
+ seq = cc->seq ++;
+ br_enc64be(header, seq);
+ header[8] = (unsigned char)record_type;
+ br_enc16be(header + 9, version);
+ br_enc16be(header + 11, len);
+ memcpy(nonce, cc->iv, 12);
+ for (u = 0; u < 8; u ++) {
+ nonce[11 - u] ^= (unsigned char)seq;
+ seq >>= 8;
+ }
+ cc->ipoly(cc->key, nonce, data, len, header, sizeof header,
+ tag, cc->ichacha, encrypt);
+}
+
+static void
+in_chapol_init(br_sslrec_chapol_context *cc,
+ br_chacha20_run ichacha, br_poly1305_run ipoly,
+ const void *key, const void *iv)
+{
+ cc->vtable.in = &br_sslrec_in_chapol_vtable;
+ gen_chapol_init(cc, ichacha, ipoly, key, iv);
+}
+
+static int
+chapol_check_length(const br_sslrec_chapol_context *cc, size_t rlen)
+{
+ /*
+ * Overhead is just the authentication tag (16 bytes).
+ */
+ (void)cc;
+ return rlen >= 16 && rlen <= (16384 + 16);
+}
+
+static unsigned char *
+chapol_decrypt(br_sslrec_chapol_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ unsigned char *buf;
+ size_t u, len;
+ unsigned char tag[16];
+ unsigned bad;
+
+ buf = data;
+ len = *data_len - 16;
+ gen_chapol_process(cc, record_type, version, buf, len, tag, 0);
+ bad = 0;
+ for (u = 0; u < 16; u ++) {
+ bad |= tag[u] ^ buf[len + u];
+ }
+ if (bad) {
+ return NULL;
+ }
+ *data_len = len;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_in_chapol_class br_sslrec_in_chapol_vtable = {
+ {
+ sizeof(br_sslrec_chapol_context),
+ (int (*)(const br_sslrec_in_class *const *, size_t))
+ &chapol_check_length,
+ (unsigned char *(*)(const br_sslrec_in_class **,
+ int, unsigned, void *, size_t *))
+ &chapol_decrypt
+ },
+ (void (*)(const br_sslrec_in_chapol_class **,
+ br_chacha20_run, br_poly1305_run,
+ const void *, const void *))
+ &in_chapol_init
+};
+
+static void
+out_chapol_init(br_sslrec_chapol_context *cc,
+ br_chacha20_run ichacha, br_poly1305_run ipoly,
+ const void *key, const void *iv)
+{
+ cc->vtable.out = &br_sslrec_out_chapol_vtable;
+ gen_chapol_init(cc, ichacha, ipoly, key, iv);
+}
+
+static void
+chapol_max_plaintext(const br_sslrec_chapol_context *cc,
+ size_t *start, size_t *end)
+{
+ size_t len;
+
+ (void)cc;
+ len = *end - *start - 16;
+ if (len > 16384) {
+ len = 16384;
+ }
+ *end = *start + len;
+}
+
+static unsigned char *
+chapol_encrypt(br_sslrec_chapol_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ unsigned char *buf;
+ size_t len;
+
+ buf = data;
+ len = *data_len;
+ gen_chapol_process(cc, record_type, version, buf, len, buf + len, 1);
+ buf -= 5;
+ buf[0] = (unsigned char)record_type;
+ br_enc16be(buf + 1, version);
+ br_enc16be(buf + 3, len + 16);
+ *data_len = len + 21;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_out_chapol_class br_sslrec_out_chapol_vtable = {
+ {
+ sizeof(br_sslrec_chapol_context),
+ (void (*)(const br_sslrec_out_class *const *,
+ size_t *, size_t *))
+ &chapol_max_plaintext,
+ (unsigned char *(*)(const br_sslrec_out_class **,
+ int, unsigned, void *, size_t *))
+ &chapol_encrypt
+ },
+ (void (*)(const br_sslrec_out_chapol_class **,
+ br_chacha20_run, br_poly1305_run,
+ const void *, const void *))
+ &out_chapol_init
+};
diff --git a/contrib/bearssl/src/ssl/ssl_rec_gcm.c b/contrib/bearssl/src/ssl/ssl_rec_gcm.c
new file mode 100644
index 000000000000..70df2777b7e3
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_rec_gcm.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * GCM initialisation. This does everything except setting the vtable,
+ * which depends on whether this is a context for encrypting or for
+ * decrypting.
+ */
+static void
+gen_gcm_init(br_sslrec_gcm_context *cc,
+ const br_block_ctr_class *bc_impl,
+ const void *key, size_t key_len,
+ br_ghash gh_impl,
+ const void *iv)
+{
+ unsigned char tmp[12];
+
+ cc->seq = 0;
+ bc_impl->init(&cc->bc.vtable, key, key_len);
+ cc->gh = gh_impl;
+ memcpy(cc->iv, iv, sizeof cc->iv);
+ memset(cc->h, 0, sizeof cc->h);
+ memset(tmp, 0, sizeof tmp);
+ bc_impl->run(&cc->bc.vtable, tmp, 0, cc->h, sizeof cc->h);
+}
+
+static void
+in_gcm_init(br_sslrec_gcm_context *cc,
+ const br_block_ctr_class *bc_impl,
+ const void *key, size_t key_len,
+ br_ghash gh_impl,
+ const void *iv)
+{
+ cc->vtable.in = &br_sslrec_in_gcm_vtable;
+ gen_gcm_init(cc, bc_impl, key, key_len, gh_impl, iv);
+}
+
+static int
+gcm_check_length(const br_sslrec_gcm_context *cc, size_t rlen)
+{
+ /*
+ * GCM adds a fixed overhead:
+ * 8 bytes for the nonce_explicit (before the ciphertext)
+ * 16 bytes for the authentication tag (after the ciphertext)
+ */
+ (void)cc;
+ return rlen >= 24 && rlen <= (16384 + 24);
+}
+
+/*
+ * Compute the authentication tag. The value written in 'tag' must still
+ * be CTR-encrypted.
+ */
+static void
+do_tag(br_sslrec_gcm_context *cc,
+ int record_type, unsigned version,
+ void *data, size_t len, void *tag)
+{
+ unsigned char header[13];
+ unsigned char footer[16];
+
+ /*
+ * Compute authentication tag. Three elements must be injected in
+ * sequence, each possibly 0-padded to reach a length multiple
+ * of the block size: the 13-byte header (sequence number, record
+ * type, protocol version, record length), the cipher text, and
+ * the word containing the encodings of the bit lengths of the two
+ * other elements.
+ */
+ br_enc64be(header, cc->seq ++);
+ header[8] = (unsigned char)record_type;
+ br_enc16be(header + 9, version);
+ br_enc16be(header + 11, len);
+ br_enc64be(footer, (uint64_t)(sizeof header) << 3);
+ br_enc64be(footer + 8, (uint64_t)len << 3);
+ memset(tag, 0, 16);
+ cc->gh(tag, cc->h, header, sizeof header);
+ cc->gh(tag, cc->h, data, len);
+ cc->gh(tag, cc->h, footer, sizeof footer);
+}
+
+/*
+ * Do CTR encryption. This also does CTR encryption of a single block at
+ * address 'xortag' with the counter value appropriate for the final
+ * processing of the authentication tag.
+ */
+static void
+do_ctr(br_sslrec_gcm_context *cc, const void *nonce, void *data, size_t len,
+ void *xortag)
+{
+ unsigned char iv[12];
+
+ memcpy(iv, cc->iv, 4);
+ memcpy(iv + 4, nonce, 8);
+ cc->bc.vtable->run(&cc->bc.vtable, iv, 2, data, len);
+ cc->bc.vtable->run(&cc->bc.vtable, iv, 1, xortag, 16);
+}
+
+static unsigned char *
+gcm_decrypt(br_sslrec_gcm_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ unsigned char *buf;
+ size_t len, u;
+ uint32_t bad;
+ unsigned char tag[16];
+
+ buf = (unsigned char *)data + 8;
+ len = *data_len - 24;
+ do_tag(cc, record_type, version, buf, len, tag);
+ do_ctr(cc, data, buf, len, tag);
+
+ /*
+ * Compare the computed tag with the value from the record. It
+ * is possibly useless to do a constant-time comparison here,
+ * but it does not hurt.
+ */
+ bad = 0;
+ for (u = 0; u < 16; u ++) {
+ bad |= tag[u] ^ buf[len + u];
+ }
+ if (bad) {
+ return NULL;
+ }
+ *data_len = len;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_in_gcm_class br_sslrec_in_gcm_vtable = {
+ {
+ sizeof(br_sslrec_gcm_context),
+ (int (*)(const br_sslrec_in_class *const *, size_t))
+ &gcm_check_length,
+ (unsigned char *(*)(const br_sslrec_in_class **,
+ int, unsigned, void *, size_t *))
+ &gcm_decrypt
+ },
+ (void (*)(const br_sslrec_in_gcm_class **,
+ const br_block_ctr_class *, const void *, size_t,
+ br_ghash, const void *))
+ &in_gcm_init
+};
+
+static void
+out_gcm_init(br_sslrec_gcm_context *cc,
+ const br_block_ctr_class *bc_impl,
+ const void *key, size_t key_len,
+ br_ghash gh_impl,
+ const void *iv)
+{
+ cc->vtable.out = &br_sslrec_out_gcm_vtable;
+ gen_gcm_init(cc, bc_impl, key, key_len, gh_impl, iv);
+}
+
+static void
+gcm_max_plaintext(const br_sslrec_gcm_context *cc,
+ size_t *start, size_t *end)
+{
+ size_t len;
+
+ (void)cc;
+ *start += 8;
+ len = *end - *start - 16;
+ if (len > 16384) {
+ len = 16384;
+ }
+ *end = *start + len;
+}
+
+static unsigned char *
+gcm_encrypt(br_sslrec_gcm_context *cc,
+ int record_type, unsigned version, void *data, size_t *data_len)
+{
+ unsigned char *buf;
+ size_t u, len;
+ unsigned char tmp[16];
+
+ buf = (unsigned char *)data;
+ len = *data_len;
+ memset(tmp, 0, sizeof tmp);
+ br_enc64be(buf - 8, cc->seq);
+ do_ctr(cc, buf - 8, buf, len, tmp);
+ do_tag(cc, record_type, version, buf, len, buf + len);
+ for (u = 0; u < 16; u ++) {
+ buf[len + u] ^= tmp[u];
+ }
+ len += 24;
+ buf -= 13;
+ buf[0] = (unsigned char)record_type;
+ br_enc16be(buf + 1, version);
+ br_enc16be(buf + 3, len);
+ *data_len = len + 5;
+ return buf;
+}
+
+/* see bearssl_ssl.h */
+const br_sslrec_out_gcm_class br_sslrec_out_gcm_vtable = {
+ {
+ sizeof(br_sslrec_gcm_context),
+ (void (*)(const br_sslrec_out_class *const *,
+ size_t *, size_t *))
+ &gcm_max_plaintext,
+ (unsigned char *(*)(const br_sslrec_out_class **,
+ int, unsigned, void *, size_t *))
+ &gcm_encrypt
+ },
+ (void (*)(const br_sslrec_out_gcm_class **,
+ const br_block_ctr_class *, const void *, size_t,
+ br_ghash, const void *))
+ &out_gcm_init
+};
diff --git a/contrib/bearssl/src/ssl/ssl_scert_single_ec.c b/contrib/bearssl/src/ssl/ssl_scert_single_ec.c
new file mode 100644
index 000000000000..ce8d7539ab90
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_scert_single_ec.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+static int
+se_choose(const br_ssl_server_policy_class **pctx,
+ const br_ssl_server_context *cc,
+ br_ssl_server_choices *choices)
+{
+ br_ssl_server_policy_ec_context *pc;
+ const br_suite_translated *st;
+ size_t u, st_num;
+ unsigned hash_id;
+
+ pc = (br_ssl_server_policy_ec_context *)pctx;
+ st = br_ssl_server_get_client_suites(cc, &st_num);
+ hash_id = br_ssl_choose_hash(br_ssl_server_get_client_hashes(cc) >> 8);
+ if (cc->eng.session.version < BR_TLS12) {
+ hash_id = br_sha1_ID;
+ }
+ choices->chain = pc->chain;
+ choices->chain_len = pc->chain_len;
+ for (u = 0; u < st_num; u ++) {
+ unsigned tt;
+
+ tt = st[u][1];
+ switch (tt >> 12) {
+ case BR_SSLKEYX_ECDH_RSA:
+ if ((pc->allowed_usages & BR_KEYTYPE_KEYX) != 0
+ && pc->cert_issuer_key_type == BR_KEYTYPE_RSA)
+ {
+ choices->cipher_suite = st[u][0];
+ return 1;
+ }
+ break;
+ case BR_SSLKEYX_ECDH_ECDSA:
+ if ((pc->allowed_usages & BR_KEYTYPE_KEYX) != 0
+ && pc->cert_issuer_key_type == BR_KEYTYPE_EC)
+ {
+ choices->cipher_suite = st[u][0];
+ return 1;
+ }
+ break;
+ case BR_SSLKEYX_ECDHE_ECDSA:
+ if ((pc->allowed_usages & BR_KEYTYPE_SIGN) != 0
+ && hash_id != 0)
+ {
+ choices->cipher_suite = st[u][0];
+ choices->algo_id = hash_id + 0xFF00;
+ return 1;
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static uint32_t
+se_do_keyx(const br_ssl_server_policy_class **pctx,
+ unsigned char *data, size_t *len)
+{
+ br_ssl_server_policy_ec_context *pc;
+ uint32_t r;
+ size_t xoff, xlen;
+
+ pc = (br_ssl_server_policy_ec_context *)pctx;
+ r = pc->iec->mul(data, *len, pc->sk->x, pc->sk->xlen, pc->sk->curve);
+ xoff = pc->iec->xoff(pc->sk->curve, &xlen);
+ memmove(data, data + xoff, xlen);
+ *len = xlen;
+ return r;
+}
+
+static size_t
+se_do_sign(const br_ssl_server_policy_class **pctx,
+ unsigned algo_id, unsigned char *data, size_t hv_len, size_t len)
+{
+ br_ssl_server_policy_ec_context *pc;
+ unsigned char hv[64];
+ const br_hash_class *hc;
+
+ algo_id &= 0xFF;
+ pc = (br_ssl_server_policy_ec_context *)pctx;
+ hc = br_multihash_getimpl(pc->mhash, algo_id);
+ if (hc == NULL) {
+ return 0;
+ }
+ memcpy(hv, data, hv_len);
+ if (len < 139) {
+ return 0;
+ }
+ return pc->iecdsa(pc->iec, hc, hv, pc->sk, data);
+}
+
+static const br_ssl_server_policy_class se_policy_vtable = {
+ sizeof(br_ssl_server_policy_ec_context),
+ se_choose,
+ se_do_keyx,
+ se_do_sign
+};
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_set_single_ec(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk, unsigned allowed_usages,
+ unsigned cert_issuer_key_type,
+ const br_ec_impl *iec, br_ecdsa_sign iecdsa)
+{
+ cc->chain_handler.single_ec.vtable = &se_policy_vtable;
+ cc->chain_handler.single_ec.chain = chain;
+ cc->chain_handler.single_ec.chain_len = chain_len;
+ cc->chain_handler.single_ec.sk = sk;
+ cc->chain_handler.single_ec.allowed_usages = allowed_usages;
+ cc->chain_handler.single_ec.cert_issuer_key_type = cert_issuer_key_type;
+ cc->chain_handler.single_ec.mhash = &cc->eng.mhash;
+ cc->chain_handler.single_ec.iec = iec;
+ cc->chain_handler.single_ec.iecdsa = iecdsa;
+ cc->policy_vtable = &cc->chain_handler.single_ec.vtable;
+}
diff --git a/contrib/bearssl/src/ssl/ssl_scert_single_rsa.c b/contrib/bearssl/src/ssl/ssl_scert_single_rsa.c
new file mode 100644
index 000000000000..b2c77679fe38
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_scert_single_rsa.c
@@ -0,0 +1,162 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+static int
+sr_choose(const br_ssl_server_policy_class **pctx,
+ const br_ssl_server_context *cc,
+ br_ssl_server_choices *choices)
+{
+ br_ssl_server_policy_rsa_context *pc;
+ const br_suite_translated *st;
+ size_t u, st_num;
+ unsigned hash_id;
+ int fh;
+
+ pc = (br_ssl_server_policy_rsa_context *)pctx;
+ st = br_ssl_server_get_client_suites(cc, &st_num);
+ if (cc->eng.session.version < BR_TLS12) {
+ hash_id = 0;
+ fh = 1;
+ } else {
+ hash_id = br_ssl_choose_hash(
+ br_ssl_server_get_client_hashes(cc));
+ fh = (hash_id != 0);
+ }
+ choices->chain = pc->chain;
+ choices->chain_len = pc->chain_len;
+ for (u = 0; u < st_num; u ++) {
+ unsigned tt;
+
+ tt = st[u][1];
+ switch (tt >> 12) {
+ case BR_SSLKEYX_RSA:
+ if ((pc->allowed_usages & BR_KEYTYPE_KEYX) != 0) {
+ choices->cipher_suite = st[u][0];
+ return 1;
+ }
+ break;
+ case BR_SSLKEYX_ECDHE_RSA:
+ if ((pc->allowed_usages & BR_KEYTYPE_SIGN) != 0 && fh) {
+ choices->cipher_suite = st[u][0];
+ choices->algo_id = hash_id + 0xFF00;
+ return 1;
+ }
+ break;
+ }
+ }
+ return 0;
+}
+
+static uint32_t
+sr_do_keyx(const br_ssl_server_policy_class **pctx,
+ unsigned char *data, size_t *len)
+{
+ br_ssl_server_policy_rsa_context *pc;
+
+ pc = (br_ssl_server_policy_rsa_context *)pctx;
+ return br_rsa_ssl_decrypt(pc->irsacore, pc->sk, data, *len);
+}
+
+/*
+ * OID for hash functions in RSA signatures.
+ */
+static const unsigned char HASH_OID_SHA1[] = {
+ 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
+};
+
+static const unsigned char HASH_OID_SHA224[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
+};
+
+static const unsigned char HASH_OID_SHA256[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
+};
+
+static const unsigned char HASH_OID_SHA384[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
+};
+
+static const unsigned char HASH_OID_SHA512[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
+};
+
+static const unsigned char *HASH_OID[] = {
+ HASH_OID_SHA1,
+ HASH_OID_SHA224,
+ HASH_OID_SHA256,
+ HASH_OID_SHA384,
+ HASH_OID_SHA512
+};
+
+static size_t
+sr_do_sign(const br_ssl_server_policy_class **pctx,
+ unsigned algo_id, unsigned char *data, size_t hv_len, size_t len)
+{
+ br_ssl_server_policy_rsa_context *pc;
+ unsigned char hv[64];
+ size_t sig_len;
+ const unsigned char *hash_oid;
+
+ pc = (br_ssl_server_policy_rsa_context *)pctx;
+ memcpy(hv, data, hv_len);
+ algo_id &= 0xFF;
+ if (algo_id == 0) {
+ hash_oid = NULL;
+ } else if (algo_id >= 2 && algo_id <= 6) {
+ hash_oid = HASH_OID[algo_id - 2];
+ } else {
+ return 0;
+ }
+ sig_len = (pc->sk->n_bitlen + 7) >> 3;
+ if (len < sig_len) {
+ return 0;
+ }
+ return pc->irsasign(hash_oid, hv, hv_len, pc->sk, data) ? sig_len : 0;
+}
+
+static const br_ssl_server_policy_class sr_policy_vtable = {
+ sizeof(br_ssl_server_policy_rsa_context),
+ sr_choose,
+ sr_do_keyx,
+ sr_do_sign
+};
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_set_single_rsa(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk, unsigned allowed_usages,
+ br_rsa_private irsacore, br_rsa_pkcs1_sign irsasign)
+{
+ cc->chain_handler.single_rsa.vtable = &sr_policy_vtable;
+ cc->chain_handler.single_rsa.chain = chain;
+ cc->chain_handler.single_rsa.chain_len = chain_len;
+ cc->chain_handler.single_rsa.sk = sk;
+ cc->chain_handler.single_rsa.allowed_usages = allowed_usages;
+ cc->chain_handler.single_rsa.irsacore = irsacore;
+ cc->chain_handler.single_rsa.irsasign = irsasign;
+ cc->policy_vtable = &cc->chain_handler.single_rsa.vtable;
+}
diff --git a/contrib/bearssl/src/ssl/ssl_server.c b/contrib/bearssl/src/ssl/ssl_server.c
new file mode 100644
index 000000000000..5578b630f655
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_server.c
@@ -0,0 +1,52 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_zero(br_ssl_server_context *cc)
+{
+ /*
+ * For really standard C, we should explicitly set to NULL all
+ * pointers, and 0 all other fields. However, on all our target
+ * architectures, a direct memset() will work, be faster, and
+ * use a lot less code.
+ */
+ memset(cc, 0, sizeof *cc);
+}
+
+/* see bearssl_ssl.h */
+int
+br_ssl_server_reset(br_ssl_server_context *cc)
+{
+ br_ssl_engine_set_buffer(&cc->eng, NULL, 0, 0);
+ if (!br_ssl_engine_init_rand(&cc->eng)) {
+ return 0;
+ }
+ cc->eng.reneg = 0;
+ br_ssl_engine_hs_reset(&cc->eng,
+ br_ssl_hs_server_init_main, br_ssl_hs_server_run);
+ return br_ssl_engine_last_error(&cc->eng) == BR_ERR_OK;
+}
diff --git a/contrib/bearssl/src/ssl/ssl_server_full_ec.c b/contrib/bearssl/src/ssl/ssl_server_full_ec.c
new file mode 100644
index 000000000000..bccc0930d456
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_server_full_ec.c
@@ -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.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_full_ec(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ unsigned cert_issuer_key_type, const br_ec_private_key *sk)
+{
+ /*
+ * The "full" profile supports all implemented cipher suites.
+ *
+ * Rationale for suite order, from most important to least
+ * important rule:
+ *
+ * -- Don't use 3DES if AES is available.
+ * -- Try to have Forward Secrecy (ECDHE suite) if possible.
+ * -- ChaCha20+Poly1305 is better than AES/GCM (faster, smaller).
+ * -- GCM is better than CCM and CBC. CCM is better than CBC.
+ * -- CCM is better than CCM_8.
+ * -- AES-128 is preferred over AES-256 (AES-128 is already
+ * strong enough, and AES-256 is 40% more expensive).
+ *
+ * Note that for ECDH suites, the list will be automatically
+ * filtered based on the issuing CA key type.
+ */
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA
+ };
+
+ /*
+ * All hash functions are activated.
+ * Note: the X.509 validation engine will nonetheless refuse to
+ * validate signatures that use MD5 as hash function.
+ */
+ static const br_hash_class *hashes[] = {
+ &br_md5_vtable,
+ &br_sha1_vtable,
+ &br_sha224_vtable,
+ &br_sha256_vtable,
+ &br_sha384_vtable,
+ &br_sha512_vtable
+ };
+
+ int id;
+
+ /*
+ * Reset server context and set supported versions from TLS-1.0
+ * to TLS-1.2 (inclusive).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
+
+ /*
+ * Set suites and elliptic curve implementation (for ECDHE).
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_engine_set_default_ec(&cc->eng);
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
+ BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
+ cert_issuer_key_type,
+ br_ssl_engine_get_ec(&cc->eng),
+#if BR_LOMUL
+ br_ecdsa_i15_sign_asn1
+#else
+ br_ecdsa_i31_sign_asn1
+#endif
+ );
+
+ /*
+ * Set supported hash functions.
+ */
+ for (id = br_md5_ID; id <= br_sha512_ID; id ++) {
+ const br_hash_class *hc;
+
+ hc = hashes[id - 1];
+ br_ssl_engine_set_hash(&cc->eng, id, hc);
+ }
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf);
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+ br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_aes_cbc(&cc->eng);
+ br_ssl_engine_set_default_aes_ccm(&cc->eng);
+ br_ssl_engine_set_default_aes_gcm(&cc->eng);
+ br_ssl_engine_set_default_des_cbc(&cc->eng);
+ br_ssl_engine_set_default_chapol(&cc->eng);
+}
diff --git a/contrib/bearssl/src/ssl/ssl_server_full_rsa.c b/contrib/bearssl/src/ssl/ssl_server_full_rsa.c
new file mode 100644
index 000000000000..d67c07611b54
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_server_full_rsa.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_full_rsa(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk)
+{
+ /*
+ * The "full" profile supports all implemented cipher suites.
+ *
+ * Rationale for suite order, from most important to least
+ * important rule:
+ *
+ * -- Don't use 3DES if AES is available.
+ * -- Try to have Forward Secrecy (ECDHE suite) if possible.
+ * -- ChaCha20+Poly1305 is better than AES/GCM (faster, smaller).
+ * -- GCM is better than CBC.
+ * -- AES-128 is preferred over AES-256 (AES-128 is already
+ * strong enough, and AES-256 is 40% more expensive).
+ */
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ 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_CCM,
+ BR_TLS_RSA_WITH_AES_256_CCM,
+ BR_TLS_RSA_WITH_AES_128_CCM_8,
+ BR_TLS_RSA_WITH_AES_256_CCM_8,
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA,
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA,
+ BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA
+ };
+
+ /*
+ * All hash functions are activated.
+ * Note: the X.509 validation engine will nonetheless refuse to
+ * validate signatures that use MD5 as hash function.
+ */
+ static const br_hash_class *hashes[] = {
+ &br_md5_vtable,
+ &br_sha1_vtable,
+ &br_sha224_vtable,
+ &br_sha256_vtable,
+ &br_sha384_vtable,
+ &br_sha512_vtable
+ };
+
+ int id;
+
+ /*
+ * Reset server context and set supported versions from TLS-1.0
+ * to TLS-1.2 (inclusive).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS10, BR_TLS12);
+
+ /*
+ * Set suites and elliptic curve implementation (for ECDHE).
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_engine_set_default_ec(&cc->eng);
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_rsa(cc, chain, chain_len, sk,
+ BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
+ br_rsa_private_get_default(),
+ br_rsa_pkcs1_sign_get_default());
+
+ /*
+ * Set supported hash functions.
+ */
+ for (id = br_md5_ID; id <= br_sha512_ID; id ++) {
+ const br_hash_class *hc;
+
+ hc = hashes[id - 1];
+ br_ssl_engine_set_hash(&cc->eng, id, hc);
+ }
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf10(&cc->eng, &br_tls10_prf);
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+ br_ssl_engine_set_prf_sha384(&cc->eng, &br_tls12_sha384_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_aes_cbc(&cc->eng);
+ br_ssl_engine_set_default_aes_ccm(&cc->eng);
+ br_ssl_engine_set_default_aes_gcm(&cc->eng);
+ br_ssl_engine_set_default_des_cbc(&cc->eng);
+ br_ssl_engine_set_default_chapol(&cc->eng);
+}
diff --git a/contrib/bearssl/src/ssl/ssl_server_mine2c.c b/contrib/bearssl/src/ssl/ssl_server_mine2c.c
new file mode 100644
index 000000000000..bf61b565c095
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_server_mine2c.c
@@ -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.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_mine2c(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_CHACHA20_POLY1305_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites and elliptic curve implementation (for ECDHE).
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m15);
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_rsa(cc, chain, chain_len, sk,
+ BR_KEYTYPE_SIGN, 0, br_rsa_i31_pkcs1_sign);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_chapol(&cc->eng);
+}
diff --git a/contrib/bearssl/src/ssl/ssl_server_mine2g.c b/contrib/bearssl/src/ssl/ssl_server_mine2g.c
new file mode 100644
index 000000000000..80fa5b11cd58
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_server_mine2g.c
@@ -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.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_mine2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites and elliptic curve implementation (for ECDHE).
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m15);
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_rsa(cc, chain, chain_len, sk,
+ BR_KEYTYPE_SIGN, 0, br_rsa_i31_pkcs1_sign);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_aes_gcm(&cc->eng);
+}
diff --git a/contrib/bearssl/src/ssl/ssl_server_minf2c.c b/contrib/bearssl/src/ssl/ssl_server_minf2c.c
new file mode 100644
index 000000000000..3f4423693d9c
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_server_minf2c.c
@@ -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.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_minf2c(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites and elliptic curve implementation (for ECDHE).
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m15);
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
+ BR_KEYTYPE_SIGN, 0, &br_ec_all_m15, br_ecdsa_i31_sign_asn1);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_chapol(&cc->eng);
+}
diff --git a/contrib/bearssl/src/ssl/ssl_server_minf2g.c b/contrib/bearssl/src/ssl/ssl_server_minf2g.c
new file mode 100644
index 000000000000..8613de1e3696
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_server_minf2g.c
@@ -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.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_minf2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites and elliptic curve implementation (for ECDHE).
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+ br_ssl_engine_set_ec(&cc->eng, &br_ec_all_m15);
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
+ BR_KEYTYPE_SIGN, 0, &br_ec_all_m15, br_ecdsa_i31_sign_asn1);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_aes_gcm(&cc->eng);
+}
diff --git a/contrib/bearssl/src/ssl/ssl_server_minr2g.c b/contrib/bearssl/src/ssl/ssl_server_minr2g.c
new file mode 100644
index 000000000000..83c238b4747c
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_server_minr2g.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_minr2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_rsa_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_RSA_WITH_AES_128_GCM_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites.
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_rsa(cc, chain, chain_len, sk,
+ BR_KEYTYPE_KEYX, br_rsa_i31_private, 0);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_aes_gcm(&cc->eng);
+}
diff --git a/contrib/bearssl/src/ssl/ssl_server_minu2g.c b/contrib/bearssl/src/ssl/ssl_server_minu2g.c
new file mode 100644
index 000000000000..6721384218fa
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_server_minu2g.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_minu2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites.
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
+ BR_KEYTYPE_KEYX, BR_KEYTYPE_RSA, &br_ec_all_m15, 0);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_aes_gcm(&cc->eng);
+}
diff --git a/contrib/bearssl/src/ssl/ssl_server_minv2g.c b/contrib/bearssl/src/ssl/ssl_server_minv2g.c
new file mode 100644
index 000000000000..194e654efe76
--- /dev/null
+++ b/contrib/bearssl/src/ssl/ssl_server_minv2g.c
@@ -0,0 +1,70 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_ssl.h */
+void
+br_ssl_server_init_minv2g(br_ssl_server_context *cc,
+ const br_x509_certificate *chain, size_t chain_len,
+ const br_ec_private_key *sk)
+{
+ static const uint16_t suites[] = {
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256
+ };
+
+ /*
+ * Reset server context and set supported versions to TLS-1.2 (only).
+ */
+ br_ssl_server_zero(cc);
+ br_ssl_engine_set_versions(&cc->eng, BR_TLS12, BR_TLS12);
+
+ /*
+ * Set suites.
+ */
+ br_ssl_engine_set_suites(&cc->eng, suites,
+ (sizeof suites) / (sizeof suites[0]));
+
+ /*
+ * Set the "server policy": handler for the certificate chain
+ * and private key operations.
+ */
+ br_ssl_server_set_single_ec(cc, chain, chain_len, sk,
+ BR_KEYTYPE_KEYX, BR_KEYTYPE_EC, &br_ec_all_m15, 0);
+
+ /*
+ * Set supported hash functions.
+ */
+ br_ssl_engine_set_hash(&cc->eng, br_sha256_ID, &br_sha256_vtable);
+
+ /*
+ * Set the PRF implementations.
+ */
+ br_ssl_engine_set_prf_sha256(&cc->eng, &br_tls12_sha256_prf);
+
+ /*
+ * Symmetric encryption.
+ */
+ br_ssl_engine_set_default_aes_gcm(&cc->eng);
+}
diff --git a/contrib/bearssl/src/symcipher/aes_big_cbcdec.c b/contrib/bearssl/src/symcipher/aes_big_cbcdec.c
new file mode 100644
index 000000000000..d969a3bf12b7
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_big_cbcdec.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_aes_big_cbcdec_init(br_aes_big_cbcdec_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_big_cbcdec_vtable;
+ ctx->num_rounds = br_aes_big_keysched_inv(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_big_cbcdec_run(const br_aes_big_cbcdec_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+
+ ivbuf = iv;
+ buf = data;
+ while (len > 0) {
+ unsigned char tmp[16];
+ int i;
+
+ memcpy(tmp, buf, 16);
+ br_aes_big_decrypt(ctx->num_rounds, ctx->skey, buf);
+ for (i = 0; i < 16; i ++) {
+ buf[i] ^= ivbuf[i];
+ }
+ memcpy(ivbuf, tmp, 16);
+ buf += 16;
+ len -= 16;
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class br_aes_big_cbcdec_vtable = {
+ sizeof(br_aes_big_cbcdec_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcdec_class **, const void *, size_t))
+ &br_aes_big_cbcdec_init,
+ (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t))
+ &br_aes_big_cbcdec_run
+};
diff --git a/contrib/bearssl/src/symcipher/aes_big_cbcenc.c b/contrib/bearssl/src/symcipher/aes_big_cbcenc.c
new file mode 100644
index 000000000000..265e53b80550
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_big_cbcenc.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_aes_big_cbcenc_init(br_aes_big_cbcenc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_big_cbcenc_vtable;
+ ctx->num_rounds = br_aes_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_big_cbcenc_run(const br_aes_big_cbcenc_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+
+ ivbuf = iv;
+ buf = data;
+ while (len > 0) {
+ int i;
+
+ for (i = 0; i < 16; i ++) {
+ buf[i] ^= ivbuf[i];
+ }
+ br_aes_big_encrypt(ctx->num_rounds, ctx->skey, buf);
+ memcpy(ivbuf, buf, 16);
+ buf += 16;
+ len -= 16;
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class br_aes_big_cbcenc_vtable = {
+ sizeof(br_aes_big_cbcenc_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcenc_class **, const void *, size_t))
+ &br_aes_big_cbcenc_init,
+ (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t))
+ &br_aes_big_cbcenc_run
+};
diff --git a/contrib/bearssl/src/symcipher/aes_big_ctr.c b/contrib/bearssl/src/symcipher/aes_big_ctr.c
new file mode 100644
index 000000000000..18fbb84671b4
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_big_ctr.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_aes_big_ctr_init(br_aes_big_ctr_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_big_ctr_vtable;
+ ctx->num_rounds = br_aes_keysched(ctx->skey, key, len);
+}
+
+static void
+xorbuf(void *dst, const void *src, size_t len)
+{
+ unsigned char *d;
+ const unsigned char *s;
+
+ d = dst;
+ s = src;
+ while (len -- > 0) {
+ *d ++ ^= *s ++;
+ }
+}
+
+/* see bearssl_block.h */
+uint32_t
+br_aes_big_ctr_run(const br_aes_big_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len)
+{
+ unsigned char *buf;
+
+ buf = data;
+ while (len > 0) {
+ unsigned char tmp[16];
+
+ memcpy(tmp, iv, 12);
+ br_enc32be(tmp + 12, cc ++);
+ br_aes_big_encrypt(ctx->num_rounds, ctx->skey, tmp);
+ if (len <= 16) {
+ xorbuf(buf, tmp, len);
+ break;
+ }
+ xorbuf(buf, tmp, 16);
+ buf += 16;
+ len -= 16;
+ }
+ return cc;
+}
+
+/* see bearssl_block.h */
+const br_block_ctr_class br_aes_big_ctr_vtable = {
+ sizeof(br_aes_big_ctr_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_ctr_class **, const void *, size_t))
+ &br_aes_big_ctr_init,
+ (uint32_t (*)(const br_block_ctr_class *const *,
+ const void *, uint32_t, void *, size_t))
+ &br_aes_big_ctr_run
+};
diff --git a/contrib/bearssl/src/symcipher/aes_big_ctrcbc.c b/contrib/bearssl/src/symcipher/aes_big_ctrcbc.c
new file mode 100644
index 000000000000..d45ca7696366
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_big_ctrcbc.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_aes_big_ctrcbc_init(br_aes_big_ctrcbc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_big_ctrcbc_vtable;
+ ctx->num_rounds = br_aes_keysched(ctx->skey, key, len);
+}
+
+static void
+xorbuf(void *dst, const void *src, size_t len)
+{
+ unsigned char *d;
+ const unsigned char *s;
+
+ d = dst;
+ s = src;
+ while (len -- > 0) {
+ *d ++ ^= *s ++;
+ }
+}
+
+/* see bearssl_block.h */
+void
+br_aes_big_ctrcbc_ctr(const br_aes_big_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len)
+{
+ unsigned char *buf, *bctr;
+ uint32_t cc0, cc1, cc2, cc3;
+
+ buf = data;
+ bctr = ctr;
+ cc3 = br_dec32be(bctr + 0);
+ cc2 = br_dec32be(bctr + 4);
+ cc1 = br_dec32be(bctr + 8);
+ cc0 = br_dec32be(bctr + 12);
+ while (len > 0) {
+ unsigned char tmp[16];
+ uint32_t carry;
+
+ br_enc32be(tmp + 0, cc3);
+ br_enc32be(tmp + 4, cc2);
+ br_enc32be(tmp + 8, cc1);
+ br_enc32be(tmp + 12, cc0);
+ br_aes_big_encrypt(ctx->num_rounds, ctx->skey, tmp);
+ xorbuf(buf, tmp, 16);
+ buf += 16;
+ len -= 16;
+ cc0 ++;
+ carry = (~(cc0 | -cc0)) >> 31;
+ cc1 += carry;
+ carry &= (~(cc1 | -cc1)) >> 31;
+ cc2 += carry;
+ carry &= (~(cc2 | -cc2)) >> 31;
+ cc3 += carry;
+ }
+ br_enc32be(bctr + 0, cc3);
+ br_enc32be(bctr + 4, cc2);
+ br_enc32be(bctr + 8, cc1);
+ br_enc32be(bctr + 12, cc0);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_big_ctrcbc_mac(const br_aes_big_ctrcbc_keys *ctx,
+ void *cbcmac, const void *data, size_t len)
+{
+ const unsigned char *buf;
+
+ buf = data;
+ while (len > 0) {
+ xorbuf(cbcmac, buf, 16);
+ br_aes_big_encrypt(ctx->num_rounds, ctx->skey, cbcmac);
+ buf += 16;
+ len -= 16;
+ }
+}
+
+/* see bearssl_block.h */
+void
+br_aes_big_ctrcbc_encrypt(const br_aes_big_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len)
+{
+ br_aes_big_ctrcbc_ctr(ctx, ctr, data, len);
+ br_aes_big_ctrcbc_mac(ctx, cbcmac, data, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_big_ctrcbc_decrypt(const br_aes_big_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len)
+{
+ br_aes_big_ctrcbc_mac(ctx, cbcmac, data, len);
+ br_aes_big_ctrcbc_ctr(ctx, ctr, data, len);
+}
+
+/* see bearssl_block.h */
+const br_block_ctrcbc_class br_aes_big_ctrcbc_vtable = {
+ sizeof(br_aes_big_ctrcbc_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_ctrcbc_class **, const void *, size_t))
+ &br_aes_big_ctrcbc_init,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, void *, size_t))
+ &br_aes_big_ctrcbc_encrypt,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, void *, size_t))
+ &br_aes_big_ctrcbc_decrypt,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, size_t))
+ &br_aes_big_ctrcbc_ctr,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, const void *, size_t))
+ &br_aes_big_ctrcbc_mac
+};
diff --git a/contrib/bearssl/src/symcipher/aes_big_dec.c b/contrib/bearssl/src/symcipher/aes_big_dec.c
new file mode 100644
index 000000000000..a5d0e3c64a07
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_big_dec.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * Inverse S-box (used in key schedule for decryption).
+ */
+static const unsigned char iS[] = {
+ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E,
+ 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,
+ 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32,
+ 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
+ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49,
+ 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,
+ 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50,
+ 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
+ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05,
+ 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,
+ 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41,
+ 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
+ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8,
+ 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,
+ 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B,
+ 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
+ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59,
+ 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,
+ 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D,
+ 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63,
+ 0x55, 0x21, 0x0C, 0x7D
+};
+
+static const uint32_t iSsm0[] = {
+ 0x51F4A750, 0x7E416553, 0x1A17A4C3, 0x3A275E96, 0x3BAB6BCB, 0x1F9D45F1,
+ 0xACFA58AB, 0x4BE30393, 0x2030FA55, 0xAD766DF6, 0x88CC7691, 0xF5024C25,
+ 0x4FE5D7FC, 0xC52ACBD7, 0x26354480, 0xB562A38F, 0xDEB15A49, 0x25BA1B67,
+ 0x45EA0E98, 0x5DFEC0E1, 0xC32F7502, 0x814CF012, 0x8D4697A3, 0x6BD3F9C6,
+ 0x038F5FE7, 0x15929C95, 0xBF6D7AEB, 0x955259DA, 0xD4BE832D, 0x587421D3,
+ 0x49E06929, 0x8EC9C844, 0x75C2896A, 0xF48E7978, 0x99583E6B, 0x27B971DD,
+ 0xBEE14FB6, 0xF088AD17, 0xC920AC66, 0x7DCE3AB4, 0x63DF4A18, 0xE51A3182,
+ 0x97513360, 0x62537F45, 0xB16477E0, 0xBB6BAE84, 0xFE81A01C, 0xF9082B94,
+ 0x70486858, 0x8F45FD19, 0x94DE6C87, 0x527BF8B7, 0xAB73D323, 0x724B02E2,
+ 0xE31F8F57, 0x6655AB2A, 0xB2EB2807, 0x2FB5C203, 0x86C57B9A, 0xD33708A5,
+ 0x302887F2, 0x23BFA5B2, 0x02036ABA, 0xED16825C, 0x8ACF1C2B, 0xA779B492,
+ 0xF307F2F0, 0x4E69E2A1, 0x65DAF4CD, 0x0605BED5, 0xD134621F, 0xC4A6FE8A,
+ 0x342E539D, 0xA2F355A0, 0x058AE132, 0xA4F6EB75, 0x0B83EC39, 0x4060EFAA,
+ 0x5E719F06, 0xBD6E1051, 0x3E218AF9, 0x96DD063D, 0xDD3E05AE, 0x4DE6BD46,
+ 0x91548DB5, 0x71C45D05, 0x0406D46F, 0x605015FF, 0x1998FB24, 0xD6BDE997,
+ 0x894043CC, 0x67D99E77, 0xB0E842BD, 0x07898B88, 0xE7195B38, 0x79C8EEDB,
+ 0xA17C0A47, 0x7C420FE9, 0xF8841EC9, 0x00000000, 0x09808683, 0x322BED48,
+ 0x1E1170AC, 0x6C5A724E, 0xFD0EFFFB, 0x0F853856, 0x3DAED51E, 0x362D3927,
+ 0x0A0FD964, 0x685CA621, 0x9B5B54D1, 0x24362E3A, 0x0C0A67B1, 0x9357E70F,
+ 0xB4EE96D2, 0x1B9B919E, 0x80C0C54F, 0x61DC20A2, 0x5A774B69, 0x1C121A16,
+ 0xE293BA0A, 0xC0A02AE5, 0x3C22E043, 0x121B171D, 0x0E090D0B, 0xF28BC7AD,
+ 0x2DB6A8B9, 0x141EA9C8, 0x57F11985, 0xAF75074C, 0xEE99DDBB, 0xA37F60FD,
+ 0xF701269F, 0x5C72F5BC, 0x44663BC5, 0x5BFB7E34, 0x8B432976, 0xCB23C6DC,
+ 0xB6EDFC68, 0xB8E4F163, 0xD731DCCA, 0x42638510, 0x13972240, 0x84C61120,
+ 0x854A247D, 0xD2BB3DF8, 0xAEF93211, 0xC729A16D, 0x1D9E2F4B, 0xDCB230F3,
+ 0x0D8652EC, 0x77C1E3D0, 0x2BB3166C, 0xA970B999, 0x119448FA, 0x47E96422,
+ 0xA8FC8CC4, 0xA0F03F1A, 0x567D2CD8, 0x223390EF, 0x87494EC7, 0xD938D1C1,
+ 0x8CCAA2FE, 0x98D40B36, 0xA6F581CF, 0xA57ADE28, 0xDAB78E26, 0x3FADBFA4,
+ 0x2C3A9DE4, 0x5078920D, 0x6A5FCC9B, 0x547E4662, 0xF68D13C2, 0x90D8B8E8,
+ 0x2E39F75E, 0x82C3AFF5, 0x9F5D80BE, 0x69D0937C, 0x6FD52DA9, 0xCF2512B3,
+ 0xC8AC993B, 0x10187DA7, 0xE89C636E, 0xDB3BBB7B, 0xCD267809, 0x6E5918F4,
+ 0xEC9AB701, 0x834F9AA8, 0xE6956E65, 0xAAFFE67E, 0x21BCCF08, 0xEF15E8E6,
+ 0xBAE79BD9, 0x4A6F36CE, 0xEA9F09D4, 0x29B07CD6, 0x31A4B2AF, 0x2A3F2331,
+ 0xC6A59430, 0x35A266C0, 0x744EBC37, 0xFC82CAA6, 0xE090D0B0, 0x33A7D815,
+ 0xF104984A, 0x41ECDAF7, 0x7FCD500E, 0x1791F62F, 0x764DD68D, 0x43EFB04D,
+ 0xCCAA4D54, 0xE49604DF, 0x9ED1B5E3, 0x4C6A881B, 0xC12C1FB8, 0x4665517F,
+ 0x9D5EEA04, 0x018C355D, 0xFA877473, 0xFB0B412E, 0xB3671D5A, 0x92DBD252,
+ 0xE9105633, 0x6DD64713, 0x9AD7618C, 0x37A10C7A, 0x59F8148E, 0xEB133C89,
+ 0xCEA927EE, 0xB761C935, 0xE11CE5ED, 0x7A47B13C, 0x9CD2DF59, 0x55F2733F,
+ 0x1814CE79, 0x73C737BF, 0x53F7CDEA, 0x5FFDAA5B, 0xDF3D6F14, 0x7844DB86,
+ 0xCAAFF381, 0xB968C43E, 0x3824342C, 0xC2A3405F, 0x161DC372, 0xBCE2250C,
+ 0x283C498B, 0xFF0D9541, 0x39A80171, 0x080CB3DE, 0xD8B4E49C, 0x6456C190,
+ 0x7BCB8461, 0xD532B670, 0x486C5C74, 0xD0B85742
+};
+
+static unsigned
+mul2(unsigned x)
+{
+ x <<= 1;
+ return x ^ ((unsigned)(-(int)(x >> 8)) & 0x11B);
+}
+
+static unsigned
+mul9(unsigned x)
+{
+ return x ^ mul2(mul2(mul2(x)));
+}
+
+static unsigned
+mulb(unsigned x)
+{
+ unsigned x2;
+
+ x2 = mul2(x);
+ return x ^ x2 ^ mul2(mul2(x2));
+}
+
+static unsigned
+muld(unsigned x)
+{
+ unsigned x4;
+
+ x4 = mul2(mul2(x));
+ return x ^ x4 ^ mul2(x4);
+}
+
+static unsigned
+mule(unsigned x)
+{
+ unsigned x2, x4;
+
+ x2 = mul2(x);
+ x4 = mul2(x2);
+ return x2 ^ x4 ^ mul2(x4);
+}
+
+/* see inner.h */
+unsigned
+br_aes_big_keysched_inv(uint32_t *skey, const void *key, size_t key_len)
+{
+ unsigned num_rounds;
+ int i, m;
+
+ /*
+ * Sub-keys for decryption are distinct from encryption sub-keys
+ * in that InvMixColumns() is already applied for the inner
+ * rounds.
+ */
+ num_rounds = br_aes_keysched(skey, key, key_len);
+ m = (int)(num_rounds << 2);
+ for (i = 4; i < m; i ++) {
+ uint32_t p;
+ unsigned p0, p1, p2, p3;
+ uint32_t q0, q1, q2, q3;
+
+ p = skey[i];
+ p0 = p >> 24;
+ p1 = (p >> 16) & 0xFF;
+ p2 = (p >> 8) & 0xFF;
+ p3 = p & 0xFF;
+ q0 = mule(p0) ^ mulb(p1) ^ muld(p2) ^ mul9(p3);
+ q1 = mul9(p0) ^ mule(p1) ^ mulb(p2) ^ muld(p3);
+ q2 = muld(p0) ^ mul9(p1) ^ mule(p2) ^ mulb(p3);
+ q3 = mulb(p0) ^ muld(p1) ^ mul9(p2) ^ mule(p3);
+ skey[i] = (q0 << 24) | (q1 << 16) | (q2 << 8) | q3;
+ }
+ return num_rounds;
+}
+
+static inline uint32_t
+rotr(uint32_t x, int n)
+{
+ return (x << (32 - n)) | (x >> n);
+}
+
+#define iSboxExt0(x) (iSsm0[x])
+#define iSboxExt1(x) (rotr(iSsm0[x], 8))
+#define iSboxExt2(x) (rotr(iSsm0[x], 16))
+#define iSboxExt3(x) (rotr(iSsm0[x], 24))
+
+/* see bearssl.h */
+void
+br_aes_big_decrypt(unsigned num_rounds, const uint32_t *skey, void *data)
+{
+ unsigned char *buf;
+ uint32_t s0, s1, s2, s3;
+ uint32_t t0, t1, t2, t3;
+ unsigned u;
+
+ buf = data;
+ s0 = br_dec32be(buf);
+ s1 = br_dec32be(buf + 4);
+ s2 = br_dec32be(buf + 8);
+ s3 = br_dec32be(buf + 12);
+ s0 ^= skey[(num_rounds << 2) + 0];
+ s1 ^= skey[(num_rounds << 2) + 1];
+ s2 ^= skey[(num_rounds << 2) + 2];
+ s3 ^= skey[(num_rounds << 2) + 3];
+ for (u = num_rounds - 1; u > 0; u --) {
+ uint32_t v0 = iSboxExt0(s0 >> 24)
+ ^ iSboxExt1((s3 >> 16) & 0xFF)
+ ^ iSboxExt2((s2 >> 8) & 0xFF)
+ ^ iSboxExt3(s1 & 0xFF);
+ uint32_t v1 = iSboxExt0(s1 >> 24)
+ ^ iSboxExt1((s0 >> 16) & 0xFF)
+ ^ iSboxExt2((s3 >> 8) & 0xFF)
+ ^ iSboxExt3(s2 & 0xFF);
+ uint32_t v2 = iSboxExt0(s2 >> 24)
+ ^ iSboxExt1((s1 >> 16) & 0xFF)
+ ^ iSboxExt2((s0 >> 8) & 0xFF)
+ ^ iSboxExt3(s3 & 0xFF);
+ uint32_t v3 = iSboxExt0(s3 >> 24)
+ ^ iSboxExt1((s2 >> 16) & 0xFF)
+ ^ iSboxExt2((s1 >> 8) & 0xFF)
+ ^ iSboxExt3(s0 & 0xFF);
+ s0 = v0;
+ s1 = v1;
+ s2 = v2;
+ s3 = v3;
+ s0 ^= skey[u << 2];
+ s1 ^= skey[(u << 2) + 1];
+ s2 ^= skey[(u << 2) + 2];
+ s3 ^= skey[(u << 2) + 3];
+ }
+ t0 = ((uint32_t)iS[s0 >> 24] << 24)
+ | ((uint32_t)iS[(s3 >> 16) & 0xFF] << 16)
+ | ((uint32_t)iS[(s2 >> 8) & 0xFF] << 8)
+ | (uint32_t)iS[s1 & 0xFF];
+ t1 = ((uint32_t)iS[s1 >> 24] << 24)
+ | ((uint32_t)iS[(s0 >> 16) & 0xFF] << 16)
+ | ((uint32_t)iS[(s3 >> 8) & 0xFF] << 8)
+ | (uint32_t)iS[s2 & 0xFF];
+ t2 = ((uint32_t)iS[s2 >> 24] << 24)
+ | ((uint32_t)iS[(s1 >> 16) & 0xFF] << 16)
+ | ((uint32_t)iS[(s0 >> 8) & 0xFF] << 8)
+ | (uint32_t)iS[s3 & 0xFF];
+ t3 = ((uint32_t)iS[s3 >> 24] << 24)
+ | ((uint32_t)iS[(s2 >> 16) & 0xFF] << 16)
+ | ((uint32_t)iS[(s1 >> 8) & 0xFF] << 8)
+ | (uint32_t)iS[s0 & 0xFF];
+ s0 = t0 ^ skey[0];
+ s1 = t1 ^ skey[1];
+ s2 = t2 ^ skey[2];
+ s3 = t3 ^ skey[3];
+ br_enc32be(buf, s0);
+ br_enc32be(buf + 4, s1);
+ br_enc32be(buf + 8, s2);
+ br_enc32be(buf + 12, s3);
+}
diff --git a/contrib/bearssl/src/symcipher/aes_big_enc.c b/contrib/bearssl/src/symcipher/aes_big_enc.c
new file mode 100644
index 000000000000..bbabb9a6e909
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_big_enc.c
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#define S br_aes_S
+
+static const uint32_t Ssm0[] = {
+ 0xC66363A5, 0xF87C7C84, 0xEE777799, 0xF67B7B8D, 0xFFF2F20D, 0xD66B6BBD,
+ 0xDE6F6FB1, 0x91C5C554, 0x60303050, 0x02010103, 0xCE6767A9, 0x562B2B7D,
+ 0xE7FEFE19, 0xB5D7D762, 0x4DABABE6, 0xEC76769A, 0x8FCACA45, 0x1F82829D,
+ 0x89C9C940, 0xFA7D7D87, 0xEFFAFA15, 0xB25959EB, 0x8E4747C9, 0xFBF0F00B,
+ 0x41ADADEC, 0xB3D4D467, 0x5FA2A2FD, 0x45AFAFEA, 0x239C9CBF, 0x53A4A4F7,
+ 0xE4727296, 0x9BC0C05B, 0x75B7B7C2, 0xE1FDFD1C, 0x3D9393AE, 0x4C26266A,
+ 0x6C36365A, 0x7E3F3F41, 0xF5F7F702, 0x83CCCC4F, 0x6834345C, 0x51A5A5F4,
+ 0xD1E5E534, 0xF9F1F108, 0xE2717193, 0xABD8D873, 0x62313153, 0x2A15153F,
+ 0x0804040C, 0x95C7C752, 0x46232365, 0x9DC3C35E, 0x30181828, 0x379696A1,
+ 0x0A05050F, 0x2F9A9AB5, 0x0E070709, 0x24121236, 0x1B80809B, 0xDFE2E23D,
+ 0xCDEBEB26, 0x4E272769, 0x7FB2B2CD, 0xEA75759F, 0x1209091B, 0x1D83839E,
+ 0x582C2C74, 0x341A1A2E, 0x361B1B2D, 0xDC6E6EB2, 0xB45A5AEE, 0x5BA0A0FB,
+ 0xA45252F6, 0x763B3B4D, 0xB7D6D661, 0x7DB3B3CE, 0x5229297B, 0xDDE3E33E,
+ 0x5E2F2F71, 0x13848497, 0xA65353F5, 0xB9D1D168, 0x00000000, 0xC1EDED2C,
+ 0x40202060, 0xE3FCFC1F, 0x79B1B1C8, 0xB65B5BED, 0xD46A6ABE, 0x8DCBCB46,
+ 0x67BEBED9, 0x7239394B, 0x944A4ADE, 0x984C4CD4, 0xB05858E8, 0x85CFCF4A,
+ 0xBBD0D06B, 0xC5EFEF2A, 0x4FAAAAE5, 0xEDFBFB16, 0x864343C5, 0x9A4D4DD7,
+ 0x66333355, 0x11858594, 0x8A4545CF, 0xE9F9F910, 0x04020206, 0xFE7F7F81,
+ 0xA05050F0, 0x783C3C44, 0x259F9FBA, 0x4BA8A8E3, 0xA25151F3, 0x5DA3A3FE,
+ 0x804040C0, 0x058F8F8A, 0x3F9292AD, 0x219D9DBC, 0x70383848, 0xF1F5F504,
+ 0x63BCBCDF, 0x77B6B6C1, 0xAFDADA75, 0x42212163, 0x20101030, 0xE5FFFF1A,
+ 0xFDF3F30E, 0xBFD2D26D, 0x81CDCD4C, 0x180C0C14, 0x26131335, 0xC3ECEC2F,
+ 0xBE5F5FE1, 0x359797A2, 0x884444CC, 0x2E171739, 0x93C4C457, 0x55A7A7F2,
+ 0xFC7E7E82, 0x7A3D3D47, 0xC86464AC, 0xBA5D5DE7, 0x3219192B, 0xE6737395,
+ 0xC06060A0, 0x19818198, 0x9E4F4FD1, 0xA3DCDC7F, 0x44222266, 0x542A2A7E,
+ 0x3B9090AB, 0x0B888883, 0x8C4646CA, 0xC7EEEE29, 0x6BB8B8D3, 0x2814143C,
+ 0xA7DEDE79, 0xBC5E5EE2, 0x160B0B1D, 0xADDBDB76, 0xDBE0E03B, 0x64323256,
+ 0x743A3A4E, 0x140A0A1E, 0x924949DB, 0x0C06060A, 0x4824246C, 0xB85C5CE4,
+ 0x9FC2C25D, 0xBDD3D36E, 0x43ACACEF, 0xC46262A6, 0x399191A8, 0x319595A4,
+ 0xD3E4E437, 0xF279798B, 0xD5E7E732, 0x8BC8C843, 0x6E373759, 0xDA6D6DB7,
+ 0x018D8D8C, 0xB1D5D564, 0x9C4E4ED2, 0x49A9A9E0, 0xD86C6CB4, 0xAC5656FA,
+ 0xF3F4F407, 0xCFEAEA25, 0xCA6565AF, 0xF47A7A8E, 0x47AEAEE9, 0x10080818,
+ 0x6FBABAD5, 0xF0787888, 0x4A25256F, 0x5C2E2E72, 0x381C1C24, 0x57A6A6F1,
+ 0x73B4B4C7, 0x97C6C651, 0xCBE8E823, 0xA1DDDD7C, 0xE874749C, 0x3E1F1F21,
+ 0x964B4BDD, 0x61BDBDDC, 0x0D8B8B86, 0x0F8A8A85, 0xE0707090, 0x7C3E3E42,
+ 0x71B5B5C4, 0xCC6666AA, 0x904848D8, 0x06030305, 0xF7F6F601, 0x1C0E0E12,
+ 0xC26161A3, 0x6A35355F, 0xAE5757F9, 0x69B9B9D0, 0x17868691, 0x99C1C158,
+ 0x3A1D1D27, 0x279E9EB9, 0xD9E1E138, 0xEBF8F813, 0x2B9898B3, 0x22111133,
+ 0xD26969BB, 0xA9D9D970, 0x078E8E89, 0x339494A7, 0x2D9B9BB6, 0x3C1E1E22,
+ 0x15878792, 0xC9E9E920, 0x87CECE49, 0xAA5555FF, 0x50282878, 0xA5DFDF7A,
+ 0x038C8C8F, 0x59A1A1F8, 0x09898980, 0x1A0D0D17, 0x65BFBFDA, 0xD7E6E631,
+ 0x844242C6, 0xD06868B8, 0x824141C3, 0x299999B0, 0x5A2D2D77, 0x1E0F0F11,
+ 0x7BB0B0CB, 0xA85454FC, 0x6DBBBBD6, 0x2C16163A
+};
+
+static inline uint32_t
+rotr(uint32_t x, int n)
+{
+ return (x << (32 - n)) | (x >> n);
+}
+
+#define SboxExt0(x) (Ssm0[x])
+#define SboxExt1(x) (rotr(Ssm0[x], 8))
+#define SboxExt2(x) (rotr(Ssm0[x], 16))
+#define SboxExt3(x) (rotr(Ssm0[x], 24))
+
+
+/* see bearssl.h */
+void
+br_aes_big_encrypt(unsigned num_rounds, const uint32_t *skey, void *data)
+{
+ unsigned char *buf;
+ uint32_t s0, s1, s2, s3;
+ uint32_t t0, t1, t2, t3;
+ unsigned u;
+
+ buf = data;
+ s0 = br_dec32be(buf);
+ s1 = br_dec32be(buf + 4);
+ s2 = br_dec32be(buf + 8);
+ s3 = br_dec32be(buf + 12);
+ s0 ^= skey[0];
+ s1 ^= skey[1];
+ s2 ^= skey[2];
+ s3 ^= skey[3];
+ for (u = 1; u < num_rounds; u ++) {
+ uint32_t v0, v1, v2, v3;
+
+ v0 = SboxExt0(s0 >> 24)
+ ^ SboxExt1((s1 >> 16) & 0xFF)
+ ^ SboxExt2((s2 >> 8) & 0xFF)
+ ^ SboxExt3(s3 & 0xFF);
+ v1 = SboxExt0(s1 >> 24)
+ ^ SboxExt1((s2 >> 16) & 0xFF)
+ ^ SboxExt2((s3 >> 8) & 0xFF)
+ ^ SboxExt3(s0 & 0xFF);
+ v2 = SboxExt0(s2 >> 24)
+ ^ SboxExt1((s3 >> 16) & 0xFF)
+ ^ SboxExt2((s0 >> 8) & 0xFF)
+ ^ SboxExt3(s1 & 0xFF);
+ v3 = SboxExt0(s3 >> 24)
+ ^ SboxExt1((s0 >> 16) & 0xFF)
+ ^ SboxExt2((s1 >> 8) & 0xFF)
+ ^ SboxExt3(s2 & 0xFF);
+ s0 = v0;
+ s1 = v1;
+ s2 = v2;
+ s3 = v3;
+ s0 ^= skey[u << 2];
+ s1 ^= skey[(u << 2) + 1];
+ s2 ^= skey[(u << 2) + 2];
+ s3 ^= skey[(u << 2) + 3];
+ }
+ t0 = ((uint32_t)S[s0 >> 24] << 24)
+ | ((uint32_t)S[(s1 >> 16) & 0xFF] << 16)
+ | ((uint32_t)S[(s2 >> 8) & 0xFF] << 8)
+ | (uint32_t)S[s3 & 0xFF];
+ t1 = ((uint32_t)S[s1 >> 24] << 24)
+ | ((uint32_t)S[(s2 >> 16) & 0xFF] << 16)
+ | ((uint32_t)S[(s3 >> 8) & 0xFF] << 8)
+ | (uint32_t)S[s0 & 0xFF];
+ t2 = ((uint32_t)S[s2 >> 24] << 24)
+ | ((uint32_t)S[(s3 >> 16) & 0xFF] << 16)
+ | ((uint32_t)S[(s0 >> 8) & 0xFF] << 8)
+ | (uint32_t)S[s1 & 0xFF];
+ t3 = ((uint32_t)S[s3 >> 24] << 24)
+ | ((uint32_t)S[(s0 >> 16) & 0xFF] << 16)
+ | ((uint32_t)S[(s1 >> 8) & 0xFF] << 8)
+ | (uint32_t)S[s2 & 0xFF];
+ s0 = t0 ^ skey[num_rounds << 2];
+ s1 = t1 ^ skey[(num_rounds << 2) + 1];
+ s2 = t2 ^ skey[(num_rounds << 2) + 2];
+ s3 = t3 ^ skey[(num_rounds << 2) + 3];
+ br_enc32be(buf, s0);
+ br_enc32be(buf + 4, s1);
+ br_enc32be(buf + 8, s2);
+ br_enc32be(buf + 12, s3);
+}
diff --git a/contrib/bearssl/src/symcipher/aes_common.c b/contrib/bearssl/src/symcipher/aes_common.c
new file mode 100644
index 000000000000..72c64fb16ea0
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_common.c
@@ -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.
+ */
+
+#include "inner.h"
+
+static const uint32_t Rcon[] = {
+ 0x01000000, 0x02000000, 0x04000000, 0x08000000, 0x10000000, 0x20000000,
+ 0x40000000, 0x80000000, 0x1B000000, 0x36000000
+};
+
+#define S br_aes_S
+
+/* see inner.h */
+const unsigned char br_aes_S[] = {
+ 0x63, 0x7C, 0x77, 0x7B, 0xF2, 0x6B, 0x6F, 0xC5, 0x30, 0x01, 0x67, 0x2B,
+ 0xFE, 0xD7, 0xAB, 0x76, 0xCA, 0x82, 0xC9, 0x7D, 0xFA, 0x59, 0x47, 0xF0,
+ 0xAD, 0xD4, 0xA2, 0xAF, 0x9C, 0xA4, 0x72, 0xC0, 0xB7, 0xFD, 0x93, 0x26,
+ 0x36, 0x3F, 0xF7, 0xCC, 0x34, 0xA5, 0xE5, 0xF1, 0x71, 0xD8, 0x31, 0x15,
+ 0x04, 0xC7, 0x23, 0xC3, 0x18, 0x96, 0x05, 0x9A, 0x07, 0x12, 0x80, 0xE2,
+ 0xEB, 0x27, 0xB2, 0x75, 0x09, 0x83, 0x2C, 0x1A, 0x1B, 0x6E, 0x5A, 0xA0,
+ 0x52, 0x3B, 0xD6, 0xB3, 0x29, 0xE3, 0x2F, 0x84, 0x53, 0xD1, 0x00, 0xED,
+ 0x20, 0xFC, 0xB1, 0x5B, 0x6A, 0xCB, 0xBE, 0x39, 0x4A, 0x4C, 0x58, 0xCF,
+ 0xD0, 0xEF, 0xAA, 0xFB, 0x43, 0x4D, 0x33, 0x85, 0x45, 0xF9, 0x02, 0x7F,
+ 0x50, 0x3C, 0x9F, 0xA8, 0x51, 0xA3, 0x40, 0x8F, 0x92, 0x9D, 0x38, 0xF5,
+ 0xBC, 0xB6, 0xDA, 0x21, 0x10, 0xFF, 0xF3, 0xD2, 0xCD, 0x0C, 0x13, 0xEC,
+ 0x5F, 0x97, 0x44, 0x17, 0xC4, 0xA7, 0x7E, 0x3D, 0x64, 0x5D, 0x19, 0x73,
+ 0x60, 0x81, 0x4F, 0xDC, 0x22, 0x2A, 0x90, 0x88, 0x46, 0xEE, 0xB8, 0x14,
+ 0xDE, 0x5E, 0x0B, 0xDB, 0xE0, 0x32, 0x3A, 0x0A, 0x49, 0x06, 0x24, 0x5C,
+ 0xC2, 0xD3, 0xAC, 0x62, 0x91, 0x95, 0xE4, 0x79, 0xE7, 0xC8, 0x37, 0x6D,
+ 0x8D, 0xD5, 0x4E, 0xA9, 0x6C, 0x56, 0xF4, 0xEA, 0x65, 0x7A, 0xAE, 0x08,
+ 0xBA, 0x78, 0x25, 0x2E, 0x1C, 0xA6, 0xB4, 0xC6, 0xE8, 0xDD, 0x74, 0x1F,
+ 0x4B, 0xBD, 0x8B, 0x8A, 0x70, 0x3E, 0xB5, 0x66, 0x48, 0x03, 0xF6, 0x0E,
+ 0x61, 0x35, 0x57, 0xB9, 0x86, 0xC1, 0x1D, 0x9E, 0xE1, 0xF8, 0x98, 0x11,
+ 0x69, 0xD9, 0x8E, 0x94, 0x9B, 0x1E, 0x87, 0xE9, 0xCE, 0x55, 0x28, 0xDF,
+ 0x8C, 0xA1, 0x89, 0x0D, 0xBF, 0xE6, 0x42, 0x68, 0x41, 0x99, 0x2D, 0x0F,
+ 0xB0, 0x54, 0xBB, 0x16
+};
+
+static uint32_t
+SubWord(uint32_t x)
+{
+ return ((uint32_t)S[x >> 24] << 24)
+ | ((uint32_t)S[(x >> 16) & 0xFF] << 16)
+ | ((uint32_t)S[(x >> 8) & 0xFF] << 8)
+ | (uint32_t)S[x & 0xFF];
+}
+
+/* see inner.h */
+unsigned
+br_aes_keysched(uint32_t *skey, const void *key, size_t key_len)
+{
+ unsigned num_rounds;
+ int i, j, k, nk, nkf;
+
+ switch (key_len) {
+ case 16:
+ num_rounds = 10;
+ break;
+ case 24:
+ num_rounds = 12;
+ break;
+ case 32:
+ num_rounds = 14;
+ break;
+ default:
+ /* abort(); */
+ return 0;
+ }
+ nk = (int)(key_len >> 2);
+ nkf = (int)((num_rounds + 1) << 2);
+ for (i = 0; i < nk; i ++) {
+ skey[i] = br_dec32be((const unsigned char *)key + (i << 2));
+ }
+ for (i = nk, j = 0, k = 0; i < nkf; i ++) {
+ uint32_t tmp;
+
+ tmp = skey[i - 1];
+ if (j == 0) {
+ tmp = (tmp << 8) | (tmp >> 24);
+ tmp = SubWord(tmp) ^ Rcon[k];
+ } else if (nk > 6 && j == 4) {
+ tmp = SubWord(tmp);
+ }
+ skey[i] = skey[i - nk] ^ tmp;
+ if (++ j == nk) {
+ j = 0;
+ k ++;
+ }
+ }
+ return num_rounds;
+}
diff --git a/contrib/bearssl/src/symcipher/aes_ct.c b/contrib/bearssl/src/symcipher/aes_ct.c
new file mode 100644
index 000000000000..66776d9e206c
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_ct.c
@@ -0,0 +1,328 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_aes_ct_bitslice_Sbox(uint32_t *q)
+{
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint32_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint32_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint32_t y20, y21;
+ uint32_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint32_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint32_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint32_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint32_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint32_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint32_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint32_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint32_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint32_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+/* see inner.h */
+void
+br_aes_ct_ortho(uint32_t *q)
+{
+#define SWAPN(cl, ch, s, x, y) do { \
+ uint32_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint32_t)cl) | ((b & (uint32_t)cl) << (s)); \
+ (y) = ((a & (uint32_t)ch) >> (s)) | (b & (uint32_t)ch); \
+ } while (0)
+
+#define SWAP2(x, y) SWAPN(0x55555555, 0xAAAAAAAA, 1, x, y)
+#define SWAP4(x, y) SWAPN(0x33333333, 0xCCCCCCCC, 2, x, y)
+#define SWAP8(x, y) SWAPN(0x0F0F0F0F, 0xF0F0F0F0, 4, x, y)
+
+ SWAP2(q[0], q[1]);
+ SWAP2(q[2], q[3]);
+ SWAP2(q[4], q[5]);
+ SWAP2(q[6], q[7]);
+
+ SWAP4(q[0], q[2]);
+ SWAP4(q[1], q[3]);
+ SWAP4(q[4], q[6]);
+ SWAP4(q[5], q[7]);
+
+ SWAP8(q[0], q[4]);
+ SWAP8(q[1], q[5]);
+ SWAP8(q[2], q[6]);
+ SWAP8(q[3], q[7]);
+}
+
+static const unsigned char Rcon[] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
+};
+
+static uint32_t
+sub_word(uint32_t x)
+{
+ uint32_t q[8];
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ q[i] = x;
+ }
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_Sbox(q);
+ br_aes_ct_ortho(q);
+ return q[0];
+}
+
+/* see inner.h */
+unsigned
+br_aes_ct_keysched(uint32_t *comp_skey, const void *key, size_t key_len)
+{
+ unsigned num_rounds;
+ int i, j, k, nk, nkf;
+ uint32_t tmp;
+ uint32_t skey[120];
+
+ switch (key_len) {
+ case 16:
+ num_rounds = 10;
+ break;
+ case 24:
+ num_rounds = 12;
+ break;
+ case 32:
+ num_rounds = 14;
+ break;
+ default:
+ /* abort(); */
+ return 0;
+ }
+ nk = (int)(key_len >> 2);
+ nkf = (int)((num_rounds + 1) << 2);
+ tmp = 0;
+ for (i = 0; i < nk; i ++) {
+ tmp = br_dec32le((const unsigned char *)key + (i << 2));
+ skey[(i << 1) + 0] = tmp;
+ skey[(i << 1) + 1] = tmp;
+ }
+ for (i = nk, j = 0, k = 0; i < nkf; i ++) {
+ if (j == 0) {
+ tmp = (tmp << 24) | (tmp >> 8);
+ tmp = sub_word(tmp) ^ Rcon[k];
+ } else if (nk > 6 && j == 4) {
+ tmp = sub_word(tmp);
+ }
+ tmp ^= skey[(i - nk) << 1];
+ skey[(i << 1) + 0] = tmp;
+ skey[(i << 1) + 1] = tmp;
+ if (++ j == nk) {
+ j = 0;
+ k ++;
+ }
+ }
+ for (i = 0; i < nkf; i += 4) {
+ br_aes_ct_ortho(skey + (i << 1));
+ }
+ for (i = 0, j = 0; i < nkf; i ++, j += 2) {
+ comp_skey[i] = (skey[j + 0] & 0x55555555)
+ | (skey[j + 1] & 0xAAAAAAAA);
+ }
+ return num_rounds;
+}
+
+/* see inner.h */
+void
+br_aes_ct_skey_expand(uint32_t *skey,
+ unsigned num_rounds, const uint32_t *comp_skey)
+{
+ unsigned u, v, n;
+
+ n = (num_rounds + 1) << 2;
+ for (u = 0, v = 0; u < n; u ++, v += 2) {
+ uint32_t x, y;
+
+ x = y = comp_skey[u];
+ x &= 0x55555555;
+ skey[v + 0] = x | (x << 1);
+ y &= 0xAAAAAAAA;
+ skey[v + 1] = y | (y >> 1);
+ }
+}
diff --git a/contrib/bearssl/src/symcipher/aes_ct64.c b/contrib/bearssl/src/symcipher/aes_ct64.c
new file mode 100644
index 000000000000..15238116d70c
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_ct64.c
@@ -0,0 +1,398 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_aes_ct64_bitslice_Sbox(uint64_t *q)
+{
+ /*
+ * This S-box implementation is a straightforward translation of
+ * the circuit described by Boyar and Peralta in "A new
+ * combinational logic minimization technique with applications
+ * to cryptology" (https://eprint.iacr.org/2009/191.pdf).
+ *
+ * Note that variables x* (input) and s* (output) are numbered
+ * in "reverse" order (x0 is the high bit, x7 is the low bit).
+ */
+
+ uint64_t x0, x1, x2, x3, x4, x5, x6, x7;
+ uint64_t y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint64_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint64_t y20, y21;
+ uint64_t z0, z1, z2, z3, z4, z5, z6, z7, z8, z9;
+ uint64_t z10, z11, z12, z13, z14, z15, z16, z17;
+ uint64_t t0, t1, t2, t3, t4, t5, t6, t7, t8, t9;
+ uint64_t t10, t11, t12, t13, t14, t15, t16, t17, t18, t19;
+ uint64_t t20, t21, t22, t23, t24, t25, t26, t27, t28, t29;
+ uint64_t t30, t31, t32, t33, t34, t35, t36, t37, t38, t39;
+ uint64_t t40, t41, t42, t43, t44, t45, t46, t47, t48, t49;
+ uint64_t t50, t51, t52, t53, t54, t55, t56, t57, t58, t59;
+ uint64_t t60, t61, t62, t63, t64, t65, t66, t67;
+ uint64_t s0, s1, s2, s3, s4, s5, s6, s7;
+
+ x0 = q[7];
+ x1 = q[6];
+ x2 = q[5];
+ x3 = q[4];
+ x4 = q[3];
+ x5 = q[2];
+ x6 = q[1];
+ x7 = q[0];
+
+ /*
+ * Top linear transformation.
+ */
+ y14 = x3 ^ x5;
+ y13 = x0 ^ x6;
+ y9 = x0 ^ x3;
+ y8 = x0 ^ x5;
+ t0 = x1 ^ x2;
+ y1 = t0 ^ x7;
+ y4 = y1 ^ x3;
+ y12 = y13 ^ y14;
+ y2 = y1 ^ x0;
+ y5 = y1 ^ x6;
+ y3 = y5 ^ y8;
+ t1 = x4 ^ y12;
+ y15 = t1 ^ x5;
+ y20 = t1 ^ x1;
+ y6 = y15 ^ x7;
+ y10 = y15 ^ t0;
+ y11 = y20 ^ y9;
+ y7 = x7 ^ y11;
+ y17 = y10 ^ y11;
+ y19 = y10 ^ y8;
+ y16 = t0 ^ y11;
+ y21 = y13 ^ y16;
+ y18 = x0 ^ y16;
+
+ /*
+ * Non-linear section.
+ */
+ t2 = y12 & y15;
+ t3 = y3 & y6;
+ t4 = t3 ^ t2;
+ t5 = y4 & x7;
+ t6 = t5 ^ t2;
+ t7 = y13 & y16;
+ t8 = y5 & y1;
+ t9 = t8 ^ t7;
+ t10 = y2 & y7;
+ t11 = t10 ^ t7;
+ t12 = y9 & y11;
+ t13 = y14 & y17;
+ t14 = t13 ^ t12;
+ t15 = y8 & y10;
+ t16 = t15 ^ t12;
+ t17 = t4 ^ t14;
+ t18 = t6 ^ t16;
+ t19 = t9 ^ t14;
+ t20 = t11 ^ t16;
+ t21 = t17 ^ y20;
+ t22 = t18 ^ y19;
+ t23 = t19 ^ y21;
+ t24 = t20 ^ y18;
+
+ t25 = t21 ^ t22;
+ t26 = t21 & t23;
+ t27 = t24 ^ t26;
+ t28 = t25 & t27;
+ t29 = t28 ^ t22;
+ t30 = t23 ^ t24;
+ t31 = t22 ^ t26;
+ t32 = t31 & t30;
+ t33 = t32 ^ t24;
+ t34 = t23 ^ t33;
+ t35 = t27 ^ t33;
+ t36 = t24 & t35;
+ t37 = t36 ^ t34;
+ t38 = t27 ^ t36;
+ t39 = t29 & t38;
+ t40 = t25 ^ t39;
+
+ t41 = t40 ^ t37;
+ t42 = t29 ^ t33;
+ t43 = t29 ^ t40;
+ t44 = t33 ^ t37;
+ t45 = t42 ^ t41;
+ z0 = t44 & y15;
+ z1 = t37 & y6;
+ z2 = t33 & x7;
+ z3 = t43 & y16;
+ z4 = t40 & y1;
+ z5 = t29 & y7;
+ z6 = t42 & y11;
+ z7 = t45 & y17;
+ z8 = t41 & y10;
+ z9 = t44 & y12;
+ z10 = t37 & y3;
+ z11 = t33 & y4;
+ z12 = t43 & y13;
+ z13 = t40 & y5;
+ z14 = t29 & y2;
+ z15 = t42 & y9;
+ z16 = t45 & y14;
+ z17 = t41 & y8;
+
+ /*
+ * Bottom linear transformation.
+ */
+ t46 = z15 ^ z16;
+ t47 = z10 ^ z11;
+ t48 = z5 ^ z13;
+ t49 = z9 ^ z10;
+ t50 = z2 ^ z12;
+ t51 = z2 ^ z5;
+ t52 = z7 ^ z8;
+ t53 = z0 ^ z3;
+ t54 = z6 ^ z7;
+ t55 = z16 ^ z17;
+ t56 = z12 ^ t48;
+ t57 = t50 ^ t53;
+ t58 = z4 ^ t46;
+ t59 = z3 ^ t54;
+ t60 = t46 ^ t57;
+ t61 = z14 ^ t57;
+ t62 = t52 ^ t58;
+ t63 = t49 ^ t58;
+ t64 = z4 ^ t59;
+ t65 = t61 ^ t62;
+ t66 = z1 ^ t63;
+ s0 = t59 ^ t63;
+ s6 = t56 ^ ~t62;
+ s7 = t48 ^ ~t60;
+ t67 = t64 ^ t65;
+ s3 = t53 ^ t66;
+ s4 = t51 ^ t66;
+ s5 = t47 ^ t65;
+ s1 = t64 ^ ~s3;
+ s2 = t55 ^ ~t67;
+
+ q[7] = s0;
+ q[6] = s1;
+ q[5] = s2;
+ q[4] = s3;
+ q[3] = s4;
+ q[2] = s5;
+ q[1] = s6;
+ q[0] = s7;
+}
+
+/* see inner.h */
+void
+br_aes_ct64_ortho(uint64_t *q)
+{
+#define SWAPN(cl, ch, s, x, y) do { \
+ uint64_t a, b; \
+ a = (x); \
+ b = (y); \
+ (x) = (a & (uint64_t)cl) | ((b & (uint64_t)cl) << (s)); \
+ (y) = ((a & (uint64_t)ch) >> (s)) | (b & (uint64_t)ch); \
+ } while (0)
+
+#define SWAP2(x, y) SWAPN(0x5555555555555555, 0xAAAAAAAAAAAAAAAA, 1, x, y)
+#define SWAP4(x, y) SWAPN(0x3333333333333333, 0xCCCCCCCCCCCCCCCC, 2, x, y)
+#define SWAP8(x, y) SWAPN(0x0F0F0F0F0F0F0F0F, 0xF0F0F0F0F0F0F0F0, 4, x, y)
+
+ SWAP2(q[0], q[1]);
+ SWAP2(q[2], q[3]);
+ SWAP2(q[4], q[5]);
+ SWAP2(q[6], q[7]);
+
+ SWAP4(q[0], q[2]);
+ SWAP4(q[1], q[3]);
+ SWAP4(q[4], q[6]);
+ SWAP4(q[5], q[7]);
+
+ SWAP8(q[0], q[4]);
+ SWAP8(q[1], q[5]);
+ SWAP8(q[2], q[6]);
+ SWAP8(q[3], q[7]);
+}
+
+/* see inner.h */
+void
+br_aes_ct64_interleave_in(uint64_t *q0, uint64_t *q1, const uint32_t *w)
+{
+ uint64_t x0, x1, x2, x3;
+
+ x0 = w[0];
+ x1 = w[1];
+ x2 = w[2];
+ x3 = w[3];
+ x0 |= (x0 << 16);
+ x1 |= (x1 << 16);
+ x2 |= (x2 << 16);
+ x3 |= (x3 << 16);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ x0 |= (x0 << 8);
+ x1 |= (x1 << 8);
+ x2 |= (x2 << 8);
+ x3 |= (x3 << 8);
+ x0 &= (uint64_t)0x00FF00FF00FF00FF;
+ x1 &= (uint64_t)0x00FF00FF00FF00FF;
+ x2 &= (uint64_t)0x00FF00FF00FF00FF;
+ x3 &= (uint64_t)0x00FF00FF00FF00FF;
+ *q0 = x0 | (x2 << 8);
+ *q1 = x1 | (x3 << 8);
+}
+
+/* see inner.h */
+void
+br_aes_ct64_interleave_out(uint32_t *w, uint64_t q0, uint64_t q1)
+{
+ uint64_t x0, x1, x2, x3;
+
+ x0 = q0 & (uint64_t)0x00FF00FF00FF00FF;
+ x1 = q1 & (uint64_t)0x00FF00FF00FF00FF;
+ x2 = (q0 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x3 = (q1 >> 8) & (uint64_t)0x00FF00FF00FF00FF;
+ x0 |= (x0 >> 8);
+ x1 |= (x1 >> 8);
+ x2 |= (x2 >> 8);
+ x3 |= (x3 >> 8);
+ x0 &= (uint64_t)0x0000FFFF0000FFFF;
+ x1 &= (uint64_t)0x0000FFFF0000FFFF;
+ x2 &= (uint64_t)0x0000FFFF0000FFFF;
+ x3 &= (uint64_t)0x0000FFFF0000FFFF;
+ w[0] = (uint32_t)x0 | (uint32_t)(x0 >> 16);
+ w[1] = (uint32_t)x1 | (uint32_t)(x1 >> 16);
+ w[2] = (uint32_t)x2 | (uint32_t)(x2 >> 16);
+ w[3] = (uint32_t)x3 | (uint32_t)(x3 >> 16);
+}
+
+static const unsigned char Rcon[] = {
+ 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80, 0x1B, 0x36
+};
+
+static uint32_t
+sub_word(uint32_t x)
+{
+ uint64_t q[8];
+
+ memset(q, 0, sizeof q);
+ q[0] = x;
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_bitslice_Sbox(q);
+ br_aes_ct64_ortho(q);
+ return (uint32_t)q[0];
+}
+
+/* see inner.h */
+unsigned
+br_aes_ct64_keysched(uint64_t *comp_skey, const void *key, size_t key_len)
+{
+ unsigned num_rounds;
+ int i, j, k, nk, nkf;
+ uint32_t tmp;
+ uint32_t skey[60];
+
+ switch (key_len) {
+ case 16:
+ num_rounds = 10;
+ break;
+ case 24:
+ num_rounds = 12;
+ break;
+ case 32:
+ num_rounds = 14;
+ break;
+ default:
+ /* abort(); */
+ return 0;
+ }
+ nk = (int)(key_len >> 2);
+ nkf = (int)((num_rounds + 1) << 2);
+ br_range_dec32le(skey, (key_len >> 2), key);
+ tmp = skey[(key_len >> 2) - 1];
+ for (i = nk, j = 0, k = 0; i < nkf; i ++) {
+ if (j == 0) {
+ tmp = (tmp << 24) | (tmp >> 8);
+ tmp = sub_word(tmp) ^ Rcon[k];
+ } else if (nk > 6 && j == 4) {
+ tmp = sub_word(tmp);
+ }
+ tmp ^= skey[i - nk];
+ skey[i] = tmp;
+ if (++ j == nk) {
+ j = 0;
+ k ++;
+ }
+ }
+
+ for (i = 0, j = 0; i < nkf; i += 4, j += 2) {
+ uint64_t q[8];
+
+ br_aes_ct64_interleave_in(&q[0], &q[4], skey + i);
+ q[1] = q[0];
+ q[2] = q[0];
+ q[3] = q[0];
+ q[5] = q[4];
+ q[6] = q[4];
+ q[7] = q[4];
+ br_aes_ct64_ortho(q);
+ comp_skey[j + 0] =
+ (q[0] & (uint64_t)0x1111111111111111)
+ | (q[1] & (uint64_t)0x2222222222222222)
+ | (q[2] & (uint64_t)0x4444444444444444)
+ | (q[3] & (uint64_t)0x8888888888888888);
+ comp_skey[j + 1] =
+ (q[4] & (uint64_t)0x1111111111111111)
+ | (q[5] & (uint64_t)0x2222222222222222)
+ | (q[6] & (uint64_t)0x4444444444444444)
+ | (q[7] & (uint64_t)0x8888888888888888);
+ }
+ return num_rounds;
+}
+
+/* see inner.h */
+void
+br_aes_ct64_skey_expand(uint64_t *skey,
+ unsigned num_rounds, const uint64_t *comp_skey)
+{
+ unsigned u, v, n;
+
+ n = (num_rounds + 1) << 1;
+ for (u = 0, v = 0; u < n; u ++, v += 4) {
+ uint64_t x0, x1, x2, x3;
+
+ x0 = x1 = x2 = x3 = comp_skey[u];
+ x0 &= (uint64_t)0x1111111111111111;
+ x1 &= (uint64_t)0x2222222222222222;
+ x2 &= (uint64_t)0x4444444444444444;
+ x3 &= (uint64_t)0x8888888888888888;
+ x1 >>= 1;
+ x2 >>= 2;
+ x3 >>= 3;
+ skey[v + 0] = (x0 << 4) - x0;
+ skey[v + 1] = (x1 << 4) - x1;
+ skey[v + 2] = (x2 << 4) - x2;
+ skey[v + 3] = (x3 << 4) - x3;
+ }
+}
diff --git a/contrib/bearssl/src/symcipher/aes_ct64_cbcdec.c b/contrib/bearssl/src/symcipher/aes_ct64_cbcdec.c
new file mode 100644
index 000000000000..5a7360bc3c08
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_ct64_cbcdec.c
@@ -0,0 +1,104 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_aes_ct64_cbcdec_init(br_aes_ct64_cbcdec_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_ct64_cbcdec_vtable;
+ ctx->num_rounds = br_aes_ct64_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_ct64_cbcdec_run(const br_aes_ct64_cbcdec_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf;
+ uint64_t sk_exp[120];
+ uint32_t ivw[4];
+
+ br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+ br_range_dec32le(ivw, 4, iv);
+ buf = data;
+ while (len > 0) {
+ uint64_t q[8];
+ uint32_t w1[16], w2[16];
+ int i;
+
+ if (len >= 64) {
+ br_range_dec32le(w1, 16, buf);
+ } else {
+ br_range_dec32le(w1, len >> 2, buf);
+ }
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_in(
+ &q[i], &q[i + 4], w1 + (i << 2));
+ }
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_bitslice_decrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct64_ortho(q);
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_out(
+ w2 + (i << 2), q[i], q[i + 4]);
+ }
+ for (i = 0; i < 4; i ++) {
+ w2[i] ^= ivw[i];
+ }
+ if (len >= 64) {
+ for (i = 4; i < 16; i ++) {
+ w2[i] ^= w1[i - 4];
+ }
+ memcpy(ivw, w1 + 12, sizeof ivw);
+ br_range_enc32le(buf, w2, 16);
+ } else {
+ int j;
+
+ j = (int)(len >> 2);
+ for (i = 4; i < j; i ++) {
+ w2[i] ^= w1[i - 4];
+ }
+ memcpy(ivw, w1 + j - 4, sizeof ivw);
+ br_range_enc32le(buf, w2, j);
+ break;
+ }
+ buf += 64;
+ len -= 64;
+ }
+ br_range_enc32le(iv, ivw, 4);
+}
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class br_aes_ct64_cbcdec_vtable = {
+ sizeof(br_aes_ct64_cbcdec_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcdec_class **, const void *, size_t))
+ &br_aes_ct64_cbcdec_init,
+ (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t))
+ &br_aes_ct64_cbcdec_run
+};
diff --git a/contrib/bearssl/src/symcipher/aes_ct64_cbcenc.c b/contrib/bearssl/src/symcipher/aes_ct64_cbcenc.c
new file mode 100644
index 000000000000..6cb9dece70ed
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_ct64_cbcenc.c
@@ -0,0 +1,81 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_aes_ct64_cbcenc_init(br_aes_ct64_cbcenc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_ct64_cbcenc_vtable;
+ ctx->num_rounds = br_aes_ct64_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_ct64_cbcenc_run(const br_aes_ct64_cbcenc_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf;
+ uint64_t sk_exp[120];
+ uint32_t ivw[4];
+
+ br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+ br_range_dec32le(ivw, 4, iv);
+ buf = data;
+ while (len > 0) {
+ uint32_t w[4];
+ uint64_t q[8];
+
+ w[0] = ivw[0] ^ br_dec32le(buf);
+ w[1] = ivw[1] ^ br_dec32le(buf + 4);
+ w[2] = ivw[2] ^ br_dec32le(buf + 8);
+ w[3] = ivw[3] ^ br_dec32le(buf + 12);
+ br_aes_ct64_interleave_in(&q[0], &q[4], w);
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_interleave_out(w, q[0], q[4]);
+ memcpy(ivw, w, sizeof w);
+ br_enc32le(buf, w[0]);
+ br_enc32le(buf + 4, w[1]);
+ br_enc32le(buf + 8, w[2]);
+ br_enc32le(buf + 12, w[3]);
+ buf += 16;
+ len -= 16;
+ }
+ br_range_enc32le(iv, ivw, 4);
+}
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class br_aes_ct64_cbcenc_vtable = {
+ sizeof(br_aes_ct64_cbcenc_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcenc_class **, const void *, size_t))
+ &br_aes_ct64_cbcenc_init,
+ (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t))
+ &br_aes_ct64_cbcenc_run
+};
diff --git a/contrib/bearssl/src/symcipher/aes_ct64_ctr.c b/contrib/bearssl/src/symcipher/aes_ct64_ctr.c
new file mode 100644
index 000000000000..1275873db530
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_ct64_ctr.c
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_aes_ct64_ctr_init(br_aes_ct64_ctr_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_ct64_ctr_vtable;
+ ctx->num_rounds = br_aes_ct64_keysched(ctx->skey, key, len);
+}
+
+static void
+xorbuf(void *dst, const void *src, size_t len)
+{
+ unsigned char *d;
+ const unsigned char *s;
+
+ d = dst;
+ s = src;
+ while (len -- > 0) {
+ *d ++ ^= *s ++;
+ }
+}
+
+/* see bearssl_block.h */
+uint32_t
+br_aes_ct64_ctr_run(const br_aes_ct64_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len)
+{
+ unsigned char *buf;
+ uint32_t ivw[16];
+ uint64_t sk_exp[120];
+
+ br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+ br_range_dec32le(ivw, 3, iv);
+ memcpy(ivw + 4, ivw, 3 * sizeof(uint32_t));
+ memcpy(ivw + 8, ivw, 3 * sizeof(uint32_t));
+ memcpy(ivw + 12, ivw, 3 * sizeof(uint32_t));
+ buf = data;
+ while (len > 0) {
+ uint64_t q[8];
+ uint32_t w[16];
+ unsigned char tmp[64];
+ int i;
+
+ /*
+ * TODO: see if we can save on the first br_aes_ct64_ortho()
+ * call, since iv0/iv1/iv2 are constant for the whole run.
+ */
+ memcpy(w, ivw, sizeof ivw);
+ w[3] = br_swap32(cc);
+ w[7] = br_swap32(cc + 1);
+ w[11] = br_swap32(cc + 2);
+ w[15] = br_swap32(cc + 3);
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_in(
+ &q[i], &q[i + 4], w + (i << 2));
+ }
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct64_ortho(q);
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_out(
+ w + (i << 2), q[i], q[i + 4]);
+ }
+ br_range_enc32le(tmp, w, 16);
+ if (len <= 64) {
+ xorbuf(buf, tmp, len);
+ cc += (uint32_t)len >> 4;
+ break;
+ }
+ xorbuf(buf, tmp, 64);
+ buf += 64;
+ len -= 64;
+ cc += 4;
+ }
+ return cc;
+}
+
+/* see bearssl_block.h */
+const br_block_ctr_class br_aes_ct64_ctr_vtable = {
+ sizeof(br_aes_ct64_ctr_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_ctr_class **, const void *, size_t))
+ &br_aes_ct64_ctr_init,
+ (uint32_t (*)(const br_block_ctr_class *const *,
+ const void *, uint32_t, void *, size_t))
+ &br_aes_ct64_ctr_run
+};
diff --git a/contrib/bearssl/src/symcipher/aes_ct64_ctrcbc.c b/contrib/bearssl/src/symcipher/aes_ct64_ctrcbc.c
new file mode 100644
index 000000000000..21bb8efad91b
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_ct64_ctrcbc.c
@@ -0,0 +1,433 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_aes_ct64_ctrcbc_init(br_aes_ct64_ctrcbc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_ct64_ctrcbc_vtable;
+ ctx->num_rounds = br_aes_ct64_keysched(ctx->skey, key, len);
+}
+
+static void
+xorbuf(void *dst, const void *src, size_t len)
+{
+ unsigned char *d;
+ const unsigned char *s;
+
+ d = dst;
+ s = src;
+ while (len -- > 0) {
+ *d ++ ^= *s ++;
+ }
+}
+
+/* see bearssl_block.h */
+void
+br_aes_ct64_ctrcbc_ctr(const br_aes_ct64_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len)
+{
+ unsigned char *buf;
+ unsigned char *ivbuf;
+ uint32_t iv0, iv1, iv2, iv3;
+ uint64_t sk_exp[120];
+
+ br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+
+ /*
+ * We keep the counter as four 32-bit values, with big-endian
+ * convention, because that's what is expected for purposes of
+ * incrementing the counter value.
+ */
+ ivbuf = ctr;
+ iv0 = br_dec32be(ivbuf + 0);
+ iv1 = br_dec32be(ivbuf + 4);
+ iv2 = br_dec32be(ivbuf + 8);
+ iv3 = br_dec32be(ivbuf + 12);
+
+ buf = data;
+ while (len > 0) {
+ uint64_t q[8];
+ uint32_t w[16];
+ unsigned char tmp[64];
+ int i, j;
+
+ /*
+ * The bitslice implementation expects values in
+ * little-endian convention, so we have to byteswap them.
+ */
+ j = (len >= 64) ? 16 : (int)(len >> 2);
+ for (i = 0; i < j; i += 4) {
+ uint32_t carry;
+
+ w[i + 0] = br_swap32(iv0);
+ w[i + 1] = br_swap32(iv1);
+ w[i + 2] = br_swap32(iv2);
+ w[i + 3] = br_swap32(iv3);
+ iv3 ++;
+ carry = ~(iv3 | -iv3) >> 31;
+ iv2 += carry;
+ carry &= -(~(iv2 | -iv2) >> 31);
+ iv1 += carry;
+ carry &= -(~(iv1 | -iv1) >> 31);
+ iv0 += carry;
+ }
+ memset(w + i, 0, (16 - i) * sizeof(uint32_t));
+
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_in(
+ &q[i], &q[i + 4], w + (i << 2));
+ }
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct64_ortho(q);
+ for (i = 0; i < 4; i ++) {
+ br_aes_ct64_interleave_out(
+ w + (i << 2), q[i], q[i + 4]);
+ }
+
+ br_range_enc32le(tmp, w, 16);
+ if (len <= 64) {
+ xorbuf(buf, tmp, len);
+ break;
+ }
+ xorbuf(buf, tmp, 64);
+ buf += 64;
+ len -= 64;
+ }
+ br_enc32be(ivbuf + 0, iv0);
+ br_enc32be(ivbuf + 4, iv1);
+ br_enc32be(ivbuf + 8, iv2);
+ br_enc32be(ivbuf + 12, iv3);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_ct64_ctrcbc_mac(const br_aes_ct64_ctrcbc_keys *ctx,
+ void *cbcmac, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ uint32_t cm0, cm1, cm2, cm3;
+ uint64_t q[8];
+ uint64_t sk_exp[120];
+
+ br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+
+ cm0 = br_dec32le((unsigned char *)cbcmac + 0);
+ cm1 = br_dec32le((unsigned char *)cbcmac + 4);
+ cm2 = br_dec32le((unsigned char *)cbcmac + 8);
+ cm3 = br_dec32le((unsigned char *)cbcmac + 12);
+
+ buf = data;
+ memset(q, 0, sizeof q);
+ while (len > 0) {
+ uint32_t w[4];
+
+ w[0] = cm0 ^ br_dec32le(buf + 0);
+ w[1] = cm1 ^ br_dec32le(buf + 4);
+ w[2] = cm2 ^ br_dec32le(buf + 8);
+ w[3] = cm3 ^ br_dec32le(buf + 12);
+
+ br_aes_ct64_interleave_in(&q[0], &q[4], w);
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_interleave_out(w, q[0], q[4]);
+
+ cm0 = w[0];
+ cm1 = w[1];
+ cm2 = w[2];
+ cm3 = w[3];
+ buf += 16;
+ len -= 16;
+ }
+
+ br_enc32le((unsigned char *)cbcmac + 0, cm0);
+ br_enc32le((unsigned char *)cbcmac + 4, cm1);
+ br_enc32le((unsigned char *)cbcmac + 8, cm2);
+ br_enc32le((unsigned char *)cbcmac + 12, cm3);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_ct64_ctrcbc_encrypt(const br_aes_ct64_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len)
+{
+ /*
+ * When encrypting, the CBC-MAC processing must be lagging by
+ * one block, since it operates on the encrypted values, so
+ * it must wait for that encryption to complete.
+ */
+
+ unsigned char *buf;
+ unsigned char *ivbuf;
+ uint32_t iv0, iv1, iv2, iv3;
+ uint32_t cm0, cm1, cm2, cm3;
+ uint64_t sk_exp[120];
+ uint64_t q[8];
+ int first_iter;
+
+ br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+
+ /*
+ * We keep the counter as four 32-bit values, with big-endian
+ * convention, because that's what is expected for purposes of
+ * incrementing the counter value.
+ */
+ ivbuf = ctr;
+ iv0 = br_dec32be(ivbuf + 0);
+ iv1 = br_dec32be(ivbuf + 4);
+ iv2 = br_dec32be(ivbuf + 8);
+ iv3 = br_dec32be(ivbuf + 12);
+
+ /*
+ * The current CBC-MAC value is kept in little-endian convention.
+ */
+ cm0 = br_dec32le((unsigned char *)cbcmac + 0);
+ cm1 = br_dec32le((unsigned char *)cbcmac + 4);
+ cm2 = br_dec32le((unsigned char *)cbcmac + 8);
+ cm3 = br_dec32le((unsigned char *)cbcmac + 12);
+
+ buf = data;
+ first_iter = 1;
+ memset(q, 0, sizeof q);
+ while (len > 0) {
+ uint32_t w[8], carry;
+
+ /*
+ * The bitslice implementation expects values in
+ * little-endian convention, so we have to byteswap them.
+ */
+ w[0] = br_swap32(iv0);
+ w[1] = br_swap32(iv1);
+ w[2] = br_swap32(iv2);
+ w[3] = br_swap32(iv3);
+ iv3 ++;
+ carry = ~(iv3 | -iv3) >> 31;
+ iv2 += carry;
+ carry &= -(~(iv2 | -iv2) >> 31);
+ iv1 += carry;
+ carry &= -(~(iv1 | -iv1) >> 31);
+ iv0 += carry;
+
+ /*
+ * The block for CBC-MAC.
+ */
+ w[4] = cm0;
+ w[5] = cm1;
+ w[6] = cm2;
+ w[7] = cm3;
+
+ br_aes_ct64_interleave_in(&q[0], &q[4], w);
+ br_aes_ct64_interleave_in(&q[1], &q[5], w + 4);
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_interleave_out(w, q[0], q[4]);
+ br_aes_ct64_interleave_out(w + 4, q[1], q[5]);
+
+ /*
+ * We do the XOR with the plaintext in 32-bit registers,
+ * so that the value are available for CBC-MAC processing
+ * as well.
+ */
+ w[0] ^= br_dec32le(buf + 0);
+ w[1] ^= br_dec32le(buf + 4);
+ w[2] ^= br_dec32le(buf + 8);
+ w[3] ^= br_dec32le(buf + 12);
+ br_enc32le(buf + 0, w[0]);
+ br_enc32le(buf + 4, w[1]);
+ br_enc32le(buf + 8, w[2]);
+ br_enc32le(buf + 12, w[3]);
+
+ buf += 16;
+ len -= 16;
+
+ /*
+ * We set the cm* values to the block to encrypt in the
+ * next iteration.
+ */
+ if (first_iter) {
+ first_iter = 0;
+ cm0 ^= w[0];
+ cm1 ^= w[1];
+ cm2 ^= w[2];
+ cm3 ^= w[3];
+ } else {
+ cm0 = w[0] ^ w[4];
+ cm1 = w[1] ^ w[5];
+ cm2 = w[2] ^ w[6];
+ cm3 = w[3] ^ w[7];
+ }
+
+ /*
+ * If this was the last iteration, then compute the
+ * extra block encryption to complete CBC-MAC.
+ */
+ if (len == 0) {
+ w[0] = cm0;
+ w[1] = cm1;
+ w[2] = cm2;
+ w[3] = cm3;
+ br_aes_ct64_interleave_in(&q[0], &q[4], w);
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_bitslice_encrypt(
+ ctx->num_rounds, sk_exp, q);
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_interleave_out(w, q[0], q[4]);
+ cm0 = w[0];
+ cm1 = w[1];
+ cm2 = w[2];
+ cm3 = w[3];
+ break;
+ }
+ }
+
+ br_enc32be(ivbuf + 0, iv0);
+ br_enc32be(ivbuf + 4, iv1);
+ br_enc32be(ivbuf + 8, iv2);
+ br_enc32be(ivbuf + 12, iv3);
+ br_enc32le((unsigned char *)cbcmac + 0, cm0);
+ br_enc32le((unsigned char *)cbcmac + 4, cm1);
+ br_enc32le((unsigned char *)cbcmac + 8, cm2);
+ br_enc32le((unsigned char *)cbcmac + 12, cm3);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_ct64_ctrcbc_decrypt(const br_aes_ct64_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len)
+{
+ unsigned char *buf;
+ unsigned char *ivbuf;
+ uint32_t iv0, iv1, iv2, iv3;
+ uint32_t cm0, cm1, cm2, cm3;
+ uint64_t sk_exp[120];
+ uint64_t q[8];
+
+ br_aes_ct64_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+
+ /*
+ * We keep the counter as four 32-bit values, with big-endian
+ * convention, because that's what is expected for purposes of
+ * incrementing the counter value.
+ */
+ ivbuf = ctr;
+ iv0 = br_dec32be(ivbuf + 0);
+ iv1 = br_dec32be(ivbuf + 4);
+ iv2 = br_dec32be(ivbuf + 8);
+ iv3 = br_dec32be(ivbuf + 12);
+
+ /*
+ * The current CBC-MAC value is kept in little-endian convention.
+ */
+ cm0 = br_dec32le((unsigned char *)cbcmac + 0);
+ cm1 = br_dec32le((unsigned char *)cbcmac + 4);
+ cm2 = br_dec32le((unsigned char *)cbcmac + 8);
+ cm3 = br_dec32le((unsigned char *)cbcmac + 12);
+
+ buf = data;
+ memset(q, 0, sizeof q);
+ while (len > 0) {
+ uint32_t w[8], carry;
+ unsigned char tmp[16];
+
+ /*
+ * The bitslice implementation expects values in
+ * little-endian convention, so we have to byteswap them.
+ */
+ w[0] = br_swap32(iv0);
+ w[1] = br_swap32(iv1);
+ w[2] = br_swap32(iv2);
+ w[3] = br_swap32(iv3);
+ iv3 ++;
+ carry = ~(iv3 | -iv3) >> 31;
+ iv2 += carry;
+ carry &= -(~(iv2 | -iv2) >> 31);
+ iv1 += carry;
+ carry &= -(~(iv1 | -iv1) >> 31);
+ iv0 += carry;
+
+ /*
+ * The block for CBC-MAC.
+ */
+ w[4] = cm0 ^ br_dec32le(buf + 0);
+ w[5] = cm1 ^ br_dec32le(buf + 4);
+ w[6] = cm2 ^ br_dec32le(buf + 8);
+ w[7] = cm3 ^ br_dec32le(buf + 12);
+
+ br_aes_ct64_interleave_in(&q[0], &q[4], w);
+ br_aes_ct64_interleave_in(&q[1], &q[5], w + 4);
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct64_ortho(q);
+ br_aes_ct64_interleave_out(w, q[0], q[4]);
+ br_aes_ct64_interleave_out(w + 4, q[1], q[5]);
+
+ br_enc32le(tmp + 0, w[0]);
+ br_enc32le(tmp + 4, w[1]);
+ br_enc32le(tmp + 8, w[2]);
+ br_enc32le(tmp + 12, w[3]);
+ xorbuf(buf, tmp, 16);
+ cm0 = w[4];
+ cm1 = w[5];
+ cm2 = w[6];
+ cm3 = w[7];
+ buf += 16;
+ len -= 16;
+ }
+
+ br_enc32be(ivbuf + 0, iv0);
+ br_enc32be(ivbuf + 4, iv1);
+ br_enc32be(ivbuf + 8, iv2);
+ br_enc32be(ivbuf + 12, iv3);
+ br_enc32le((unsigned char *)cbcmac + 0, cm0);
+ br_enc32le((unsigned char *)cbcmac + 4, cm1);
+ br_enc32le((unsigned char *)cbcmac + 8, cm2);
+ br_enc32le((unsigned char *)cbcmac + 12, cm3);
+}
+
+/* see bearssl_block.h */
+const br_block_ctrcbc_class br_aes_ct64_ctrcbc_vtable = {
+ sizeof(br_aes_ct64_ctrcbc_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_ctrcbc_class **, const void *, size_t))
+ &br_aes_ct64_ctrcbc_init,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, void *, size_t))
+ &br_aes_ct64_ctrcbc_encrypt,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, void *, size_t))
+ &br_aes_ct64_ctrcbc_decrypt,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, size_t))
+ &br_aes_ct64_ctrcbc_ctr,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, const void *, size_t))
+ &br_aes_ct64_ctrcbc_mac
+};
diff --git a/contrib/bearssl/src/symcipher/aes_ct64_dec.c b/contrib/bearssl/src/symcipher/aes_ct64_dec.c
new file mode 100644
index 000000000000..ab00e099a53b
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_ct64_dec.c
@@ -0,0 +1,159 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_aes_ct64_bitslice_invSbox(uint64_t *q)
+{
+ /*
+ * See br_aes_ct_bitslice_invSbox(). This is the natural extension
+ * to 64-bit registers.
+ */
+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;
+
+ q0 = ~q[0];
+ q1 = ~q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = ~q[5];
+ q6 = ~q[6];
+ q7 = q[7];
+ q[7] = q1 ^ q4 ^ q6;
+ q[6] = q0 ^ q3 ^ q5;
+ q[5] = q7 ^ q2 ^ q4;
+ q[4] = q6 ^ q1 ^ q3;
+ q[3] = q5 ^ q0 ^ q2;
+ q[2] = q4 ^ q7 ^ q1;
+ q[1] = q3 ^ q6 ^ q0;
+ q[0] = q2 ^ q5 ^ q7;
+
+ br_aes_ct64_bitslice_Sbox(q);
+
+ q0 = ~q[0];
+ q1 = ~q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = ~q[5];
+ q6 = ~q[6];
+ q7 = q[7];
+ q[7] = q1 ^ q4 ^ q6;
+ q[6] = q0 ^ q3 ^ q5;
+ q[5] = q7 ^ q2 ^ q4;
+ q[4] = q6 ^ q1 ^ q3;
+ q[3] = q5 ^ q0 ^ q2;
+ q[2] = q4 ^ q7 ^ q1;
+ q[1] = q3 ^ q6 ^ q0;
+ q[0] = q2 ^ q5 ^ q7;
+}
+
+static void
+add_round_key(uint64_t *q, const uint64_t *sk)
+{
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ q[i] ^= sk[i];
+ }
+}
+
+static void
+inv_shift_rows(uint64_t *q)
+{
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ uint64_t x;
+
+ x = q[i];
+ q[i] = (x & (uint64_t)0x000000000000FFFF)
+ | ((x & (uint64_t)0x000000000FFF0000) << 4)
+ | ((x & (uint64_t)0x00000000F0000000) >> 12)
+ | ((x & (uint64_t)0x000000FF00000000) << 8)
+ | ((x & (uint64_t)0x0000FF0000000000) >> 8)
+ | ((x & (uint64_t)0x000F000000000000) << 12)
+ | ((x & (uint64_t)0xFFF0000000000000) >> 4);
+ }
+}
+
+static inline uint64_t
+rotr32(uint64_t x)
+{
+ return (x << 32) | (x >> 32);
+}
+
+static void
+inv_mix_columns(uint64_t *q)
+{
+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint64_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 16) | (q0 << 48);
+ r1 = (q1 >> 16) | (q1 << 48);
+ r2 = (q2 >> 16) | (q2 << 48);
+ r3 = (q3 >> 16) | (q3 << 48);
+ r4 = (q4 >> 16) | (q4 << 48);
+ r5 = (q5 >> 16) | (q5 << 48);
+ r6 = (q6 >> 16) | (q6 << 48);
+ r7 = (q7 >> 16) | (q7 << 48);
+
+ q[0] = q5 ^ q6 ^ q7 ^ r0 ^ r5 ^ r7 ^ rotr32(q0 ^ q5 ^ q6 ^ r0 ^ r5);
+ q[1] = q0 ^ q5 ^ r0 ^ r1 ^ r5 ^ r6 ^ r7 ^ rotr32(q1 ^ q5 ^ q7 ^ r1 ^ r5 ^ r6);
+ q[2] = q0 ^ q1 ^ q6 ^ r1 ^ r2 ^ r6 ^ r7 ^ rotr32(q0 ^ q2 ^ q6 ^ r2 ^ r6 ^ r7);
+ q[3] = q0 ^ q1 ^ q2 ^ q5 ^ q6 ^ r0 ^ r2 ^ r3 ^ r5 ^ rotr32(q0 ^ q1 ^ q3 ^ q5 ^ q6 ^ q7 ^ r0 ^ r3 ^ r5 ^ r7);
+ q[4] = q1 ^ q2 ^ q3 ^ q5 ^ r1 ^ r3 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr32(q1 ^ q2 ^ q4 ^ q5 ^ q7 ^ r1 ^ r4 ^ r5 ^ r6);
+ q[5] = q2 ^ q3 ^ q4 ^ q6 ^ r2 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr32(q2 ^ q3 ^ q5 ^ q6 ^ r2 ^ r5 ^ r6 ^ r7);
+ q[6] = q3 ^ q4 ^ q5 ^ q7 ^ r3 ^ r5 ^ r6 ^ r7 ^ rotr32(q3 ^ q4 ^ q6 ^ q7 ^ r3 ^ r6 ^ r7);
+ q[7] = q4 ^ q5 ^ q6 ^ r4 ^ r6 ^ r7 ^ rotr32(q4 ^ q5 ^ q7 ^ r4 ^ r7);
+}
+
+/* see inner.h */
+void
+br_aes_ct64_bitslice_decrypt(unsigned num_rounds,
+ const uint64_t *skey, uint64_t *q)
+{
+ unsigned u;
+
+ add_round_key(q, skey + (num_rounds << 3));
+ for (u = num_rounds - 1; u > 0; u --) {
+ inv_shift_rows(q);
+ br_aes_ct64_bitslice_invSbox(q);
+ add_round_key(q, skey + (u << 3));
+ inv_mix_columns(q);
+ }
+ inv_shift_rows(q);
+ br_aes_ct64_bitslice_invSbox(q);
+ add_round_key(q, skey);
+}
diff --git a/contrib/bearssl/src/symcipher/aes_ct64_enc.c b/contrib/bearssl/src/symcipher/aes_ct64_enc.c
new file mode 100644
index 000000000000..78631cedc448
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_ct64_enc.c
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+static inline void
+add_round_key(uint64_t *q, const uint64_t *sk)
+{
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void
+shift_rows(uint64_t *q)
+{
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ uint64_t x;
+
+ x = q[i];
+ q[i] = (x & (uint64_t)0x000000000000FFFF)
+ | ((x & (uint64_t)0x00000000FFF00000) >> 4)
+ | ((x & (uint64_t)0x00000000000F0000) << 12)
+ | ((x & (uint64_t)0x0000FF0000000000) >> 8)
+ | ((x & (uint64_t)0x000000FF00000000) << 8)
+ | ((x & (uint64_t)0xF000000000000000) >> 12)
+ | ((x & (uint64_t)0x0FFF000000000000) << 4);
+ }
+}
+
+static inline uint64_t
+rotr32(uint64_t x)
+{
+ return (x << 32) | (x >> 32);
+}
+
+static inline void
+mix_columns(uint64_t *q)
+{
+ uint64_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint64_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 16) | (q0 << 48);
+ r1 = (q1 >> 16) | (q1 << 48);
+ r2 = (q2 >> 16) | (q2 << 48);
+ r3 = (q3 >> 16) | (q3 << 48);
+ r4 = (q4 >> 16) | (q4 << 48);
+ r5 = (q5 >> 16) | (q5 << 48);
+ r6 = (q6 >> 16) | (q6 << 48);
+ r7 = (q7 >> 16) | (q7 << 48);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr32(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr32(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr32(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr32(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr32(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr32(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr32(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr32(q7 ^ r7);
+}
+
+/* see inner.h */
+void
+br_aes_ct64_bitslice_encrypt(unsigned num_rounds,
+ const uint64_t *skey, uint64_t *q)
+{
+ unsigned u;
+
+ add_round_key(q, skey);
+ for (u = 1; u < num_rounds; u ++) {
+ br_aes_ct64_bitslice_Sbox(q);
+ shift_rows(q);
+ mix_columns(q);
+ add_round_key(q, skey + (u << 3));
+ }
+ br_aes_ct64_bitslice_Sbox(q);
+ shift_rows(q);
+ add_round_key(q, skey + (num_rounds << 3));
+}
diff --git a/contrib/bearssl/src/symcipher/aes_ct_cbcdec.c b/contrib/bearssl/src/symcipher/aes_ct_cbcdec.c
new file mode 100644
index 000000000000..522645adf266
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_ct_cbcdec.c
@@ -0,0 +1,111 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_aes_ct_cbcdec_init(br_aes_ct_cbcdec_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_ct_cbcdec_vtable;
+ ctx->num_rounds = br_aes_ct_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_ct_cbcdec_run(const br_aes_ct_cbcdec_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+ uint32_t iv0, iv1, iv2, iv3;
+ uint32_t sk_exp[120];
+
+ br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+ ivbuf = iv;
+ iv0 = br_dec32le(ivbuf);
+ iv1 = br_dec32le(ivbuf + 4);
+ iv2 = br_dec32le(ivbuf + 8);
+ iv3 = br_dec32le(ivbuf + 12);
+ buf = data;
+ while (len > 0) {
+ uint32_t q[8], sq[8];
+
+ q[0] = br_dec32le(buf);
+ q[2] = br_dec32le(buf + 4);
+ q[4] = br_dec32le(buf + 8);
+ q[6] = br_dec32le(buf + 12);
+ if (len >= 32) {
+ q[1] = br_dec32le(buf + 16);
+ q[3] = br_dec32le(buf + 20);
+ q[5] = br_dec32le(buf + 24);
+ q[7] = br_dec32le(buf + 28);
+ } else {
+ q[1] = 0;
+ q[3] = 0;
+ q[5] = 0;
+ q[7] = 0;
+ }
+ memcpy(sq, q, sizeof q);
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_decrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+ br_enc32le(buf, q[0] ^ iv0);
+ br_enc32le(buf + 4, q[2] ^ iv1);
+ br_enc32le(buf + 8, q[4] ^ iv2);
+ br_enc32le(buf + 12, q[6] ^ iv3);
+ if (len < 32) {
+ iv0 = sq[0];
+ iv1 = sq[2];
+ iv2 = sq[4];
+ iv3 = sq[6];
+ break;
+ }
+ br_enc32le(buf + 16, q[1] ^ sq[0]);
+ br_enc32le(buf + 20, q[3] ^ sq[2]);
+ br_enc32le(buf + 24, q[5] ^ sq[4]);
+ br_enc32le(buf + 28, q[7] ^ sq[6]);
+ iv0 = sq[1];
+ iv1 = sq[3];
+ iv2 = sq[5];
+ iv3 = sq[7];
+ buf += 32;
+ len -= 32;
+ }
+ br_enc32le(ivbuf, iv0);
+ br_enc32le(ivbuf + 4, iv1);
+ br_enc32le(ivbuf + 8, iv2);
+ br_enc32le(ivbuf + 12, iv3);
+}
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class br_aes_ct_cbcdec_vtable = {
+ sizeof(br_aes_ct_cbcdec_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcdec_class **, const void *, size_t))
+ &br_aes_ct_cbcdec_init,
+ (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t))
+ &br_aes_ct_cbcdec_run
+};
diff --git a/contrib/bearssl/src/symcipher/aes_ct_cbcenc.c b/contrib/bearssl/src/symcipher/aes_ct_cbcenc.c
new file mode 100644
index 000000000000..cb85977b2a93
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_ct_cbcenc.c
@@ -0,0 +1,91 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_aes_ct_cbcenc_init(br_aes_ct_cbcenc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_ct_cbcenc_vtable;
+ ctx->num_rounds = br_aes_ct_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_ct_cbcenc_run(const br_aes_ct_cbcenc_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+ uint32_t q[8];
+ uint32_t iv0, iv1, iv2, iv3;
+ uint32_t sk_exp[120];
+
+ q[1] = 0;
+ q[3] = 0;
+ q[5] = 0;
+ q[7] = 0;
+ br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+ ivbuf = iv;
+ iv0 = br_dec32le(ivbuf);
+ iv1 = br_dec32le(ivbuf + 4);
+ iv2 = br_dec32le(ivbuf + 8);
+ iv3 = br_dec32le(ivbuf + 12);
+ buf = data;
+ while (len > 0) {
+ q[0] = iv0 ^ br_dec32le(buf);
+ q[2] = iv1 ^ br_dec32le(buf + 4);
+ q[4] = iv2 ^ br_dec32le(buf + 8);
+ q[6] = iv3 ^ br_dec32le(buf + 12);
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+ iv0 = q[0];
+ iv1 = q[2];
+ iv2 = q[4];
+ iv3 = q[6];
+ br_enc32le(buf, iv0);
+ br_enc32le(buf + 4, iv1);
+ br_enc32le(buf + 8, iv2);
+ br_enc32le(buf + 12, iv3);
+ buf += 16;
+ len -= 16;
+ }
+ br_enc32le(ivbuf, iv0);
+ br_enc32le(ivbuf + 4, iv1);
+ br_enc32le(ivbuf + 8, iv2);
+ br_enc32le(ivbuf + 12, iv3);
+}
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class br_aes_ct_cbcenc_vtable = {
+ sizeof(br_aes_ct_cbcenc_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcenc_class **, const void *, size_t))
+ &br_aes_ct_cbcenc_init,
+ (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t))
+ &br_aes_ct_cbcenc_run
+};
diff --git a/contrib/bearssl/src/symcipher/aes_ct_ctr.c b/contrib/bearssl/src/symcipher/aes_ct_ctr.c
new file mode 100644
index 000000000000..f407689edf3c
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_ct_ctr.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_aes_ct_ctr_init(br_aes_ct_ctr_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_ct_ctr_vtable;
+ ctx->num_rounds = br_aes_ct_keysched(ctx->skey, key, len);
+}
+
+static void
+xorbuf(void *dst, const void *src, size_t len)
+{
+ unsigned char *d;
+ const unsigned char *s;
+
+ d = dst;
+ s = src;
+ while (len -- > 0) {
+ *d ++ ^= *s ++;
+ }
+}
+
+/* see bearssl_block.h */
+uint32_t
+br_aes_ct_ctr_run(const br_aes_ct_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len)
+{
+ unsigned char *buf;
+ const unsigned char *ivbuf;
+ uint32_t iv0, iv1, iv2;
+ uint32_t sk_exp[120];
+
+ br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+ ivbuf = iv;
+ iv0 = br_dec32le(ivbuf);
+ iv1 = br_dec32le(ivbuf + 4);
+ iv2 = br_dec32le(ivbuf + 8);
+ buf = data;
+ while (len > 0) {
+ uint32_t q[8];
+ unsigned char tmp[32];
+
+ /*
+ * TODO: see if we can save on the first br_aes_ct_ortho()
+ * call, since iv0/iv1/iv2 are constant for the whole run.
+ */
+ q[0] = q[1] = iv0;
+ q[2] = q[3] = iv1;
+ q[4] = q[5] = iv2;
+ q[6] = br_swap32(cc);
+ q[7] = br_swap32(cc + 1);
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+ br_enc32le(tmp, q[0]);
+ br_enc32le(tmp + 4, q[2]);
+ br_enc32le(tmp + 8, q[4]);
+ br_enc32le(tmp + 12, q[6]);
+ br_enc32le(tmp + 16, q[1]);
+ br_enc32le(tmp + 20, q[3]);
+ br_enc32le(tmp + 24, q[5]);
+ br_enc32le(tmp + 28, q[7]);
+
+ if (len <= 32) {
+ xorbuf(buf, tmp, len);
+ cc ++;
+ if (len > 16) {
+ cc ++;
+ }
+ break;
+ }
+ xorbuf(buf, tmp, 32);
+ buf += 32;
+ len -= 32;
+ cc += 2;
+ }
+ return cc;
+}
+
+/* see bearssl_block.h */
+const br_block_ctr_class br_aes_ct_ctr_vtable = {
+ sizeof(br_aes_ct_ctr_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_ctr_class **, const void *, size_t))
+ &br_aes_ct_ctr_init,
+ (uint32_t (*)(const br_block_ctr_class *const *,
+ const void *, uint32_t, void *, size_t))
+ &br_aes_ct_ctr_run
+};
diff --git a/contrib/bearssl/src/symcipher/aes_ct_ctrcbc.c b/contrib/bearssl/src/symcipher/aes_ct_ctrcbc.c
new file mode 100644
index 000000000000..8ae9fc7524ff
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_ct_ctrcbc.c
@@ -0,0 +1,422 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_aes_ct_ctrcbc_init(br_aes_ct_ctrcbc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_ct_ctrcbc_vtable;
+ ctx->num_rounds = br_aes_ct_keysched(ctx->skey, key, len);
+}
+
+static void
+xorbuf(void *dst, const void *src, size_t len)
+{
+ unsigned char *d;
+ const unsigned char *s;
+
+ d = dst;
+ s = src;
+ while (len -- > 0) {
+ *d ++ ^= *s ++;
+ }
+}
+
+/* see bearssl_block.h */
+void
+br_aes_ct_ctrcbc_ctr(const br_aes_ct_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len)
+{
+ unsigned char *buf;
+ unsigned char *ivbuf;
+ uint32_t iv0, iv1, iv2, iv3;
+ uint32_t sk_exp[120];
+
+ br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+
+ /*
+ * We keep the counter as four 32-bit values, with big-endian
+ * convention, because that's what is expected for purposes of
+ * incrementing the counter value.
+ */
+ ivbuf = ctr;
+ iv0 = br_dec32be(ivbuf + 0);
+ iv1 = br_dec32be(ivbuf + 4);
+ iv2 = br_dec32be(ivbuf + 8);
+ iv3 = br_dec32be(ivbuf + 12);
+
+ buf = data;
+ while (len > 0) {
+ uint32_t q[8], carry;
+ unsigned char tmp[32];
+
+ /*
+ * The bitslice implementation expects values in
+ * little-endian convention, so we have to byteswap them.
+ */
+ q[0] = br_swap32(iv0);
+ q[2] = br_swap32(iv1);
+ q[4] = br_swap32(iv2);
+ q[6] = br_swap32(iv3);
+ iv3 ++;
+ carry = ~(iv3 | -iv3) >> 31;
+ iv2 += carry;
+ carry &= -(~(iv2 | -iv2) >> 31);
+ iv1 += carry;
+ carry &= -(~(iv1 | -iv1) >> 31);
+ iv0 += carry;
+ q[1] = br_swap32(iv0);
+ q[3] = br_swap32(iv1);
+ q[5] = br_swap32(iv2);
+ q[7] = br_swap32(iv3);
+ if (len > 16) {
+ iv3 ++;
+ carry = ~(iv3 | -iv3) >> 31;
+ iv2 += carry;
+ carry &= -(~(iv2 | -iv2) >> 31);
+ iv1 += carry;
+ carry &= -(~(iv1 | -iv1) >> 31);
+ iv0 += carry;
+ }
+
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+
+ br_enc32le(tmp, q[0]);
+ br_enc32le(tmp + 4, q[2]);
+ br_enc32le(tmp + 8, q[4]);
+ br_enc32le(tmp + 12, q[6]);
+ br_enc32le(tmp + 16, q[1]);
+ br_enc32le(tmp + 20, q[3]);
+ br_enc32le(tmp + 24, q[5]);
+ br_enc32le(tmp + 28, q[7]);
+
+ if (len <= 32) {
+ xorbuf(buf, tmp, len);
+ break;
+ }
+ xorbuf(buf, tmp, 32);
+ buf += 32;
+ len -= 32;
+ }
+ br_enc32be(ivbuf + 0, iv0);
+ br_enc32be(ivbuf + 4, iv1);
+ br_enc32be(ivbuf + 8, iv2);
+ br_enc32be(ivbuf + 12, iv3);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_ct_ctrcbc_mac(const br_aes_ct_ctrcbc_keys *ctx,
+ void *cbcmac, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ uint32_t cm0, cm1, cm2, cm3;
+ uint32_t q[8];
+ uint32_t sk_exp[120];
+
+ br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+
+ buf = data;
+ cm0 = br_dec32le((unsigned char *)cbcmac + 0);
+ cm1 = br_dec32le((unsigned char *)cbcmac + 4);
+ cm2 = br_dec32le((unsigned char *)cbcmac + 8);
+ cm3 = br_dec32le((unsigned char *)cbcmac + 12);
+ q[1] = 0;
+ q[3] = 0;
+ q[5] = 0;
+ q[7] = 0;
+
+ while (len > 0) {
+ q[0] = cm0 ^ br_dec32le(buf + 0);
+ q[2] = cm1 ^ br_dec32le(buf + 4);
+ q[4] = cm2 ^ br_dec32le(buf + 8);
+ q[6] = cm3 ^ br_dec32le(buf + 12);
+
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+
+ cm0 = q[0];
+ cm1 = q[2];
+ cm2 = q[4];
+ cm3 = q[6];
+ buf += 16;
+ len -= 16;
+ }
+
+ br_enc32le((unsigned char *)cbcmac + 0, cm0);
+ br_enc32le((unsigned char *)cbcmac + 4, cm1);
+ br_enc32le((unsigned char *)cbcmac + 8, cm2);
+ br_enc32le((unsigned char *)cbcmac + 12, cm3);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_ct_ctrcbc_encrypt(const br_aes_ct_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len)
+{
+ /*
+ * When encrypting, the CBC-MAC processing must be lagging by
+ * one block, since it operates on the encrypted values, so
+ * it must wait for that encryption to complete.
+ */
+
+ unsigned char *buf;
+ unsigned char *ivbuf;
+ uint32_t iv0, iv1, iv2, iv3;
+ uint32_t cm0, cm1, cm2, cm3;
+ uint32_t sk_exp[120];
+ int first_iter;
+
+ br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+
+ /*
+ * We keep the counter as four 32-bit values, with big-endian
+ * convention, because that's what is expected for purposes of
+ * incrementing the counter value.
+ */
+ ivbuf = ctr;
+ iv0 = br_dec32be(ivbuf + 0);
+ iv1 = br_dec32be(ivbuf + 4);
+ iv2 = br_dec32be(ivbuf + 8);
+ iv3 = br_dec32be(ivbuf + 12);
+
+ /*
+ * The current CBC-MAC value is kept in little-endian convention.
+ */
+ cm0 = br_dec32le((unsigned char *)cbcmac + 0);
+ cm1 = br_dec32le((unsigned char *)cbcmac + 4);
+ cm2 = br_dec32le((unsigned char *)cbcmac + 8);
+ cm3 = br_dec32le((unsigned char *)cbcmac + 12);
+
+ buf = data;
+ first_iter = 1;
+ while (len > 0) {
+ uint32_t q[8], carry;
+
+ /*
+ * The bitslice implementation expects values in
+ * little-endian convention, so we have to byteswap them.
+ */
+ q[0] = br_swap32(iv0);
+ q[2] = br_swap32(iv1);
+ q[4] = br_swap32(iv2);
+ q[6] = br_swap32(iv3);
+ iv3 ++;
+ carry = ~(iv3 | -iv3) >> 31;
+ iv2 += carry;
+ carry &= -(~(iv2 | -iv2) >> 31);
+ iv1 += carry;
+ carry &= -(~(iv1 | -iv1) >> 31);
+ iv0 += carry;
+
+ /*
+ * The odd values are used for CBC-MAC.
+ */
+ q[1] = cm0;
+ q[3] = cm1;
+ q[5] = cm2;
+ q[7] = cm3;
+
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+
+ /*
+ * We do the XOR with the plaintext in 32-bit registers,
+ * so that the value are available for CBC-MAC processing
+ * as well.
+ */
+ q[0] ^= br_dec32le(buf + 0);
+ q[2] ^= br_dec32le(buf + 4);
+ q[4] ^= br_dec32le(buf + 8);
+ q[6] ^= br_dec32le(buf + 12);
+ br_enc32le(buf + 0, q[0]);
+ br_enc32le(buf + 4, q[2]);
+ br_enc32le(buf + 8, q[4]);
+ br_enc32le(buf + 12, q[6]);
+
+ buf += 16;
+ len -= 16;
+
+ /*
+ * We set the cm* values to the block to encrypt in the
+ * next iteration.
+ */
+ if (first_iter) {
+ first_iter = 0;
+ cm0 ^= q[0];
+ cm1 ^= q[2];
+ cm2 ^= q[4];
+ cm3 ^= q[6];
+ } else {
+ cm0 = q[0] ^ q[1];
+ cm1 = q[2] ^ q[3];
+ cm2 = q[4] ^ q[5];
+ cm3 = q[6] ^ q[7];
+ }
+
+ /*
+ * If this was the last iteration, then compute the
+ * extra block encryption to complete CBC-MAC.
+ */
+ if (len == 0) {
+ q[0] = cm0;
+ q[2] = cm1;
+ q[4] = cm2;
+ q[6] = cm3;
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+ cm0 = q[0];
+ cm1 = q[2];
+ cm2 = q[4];
+ cm3 = q[6];
+ break;
+ }
+ }
+
+ br_enc32be(ivbuf + 0, iv0);
+ br_enc32be(ivbuf + 4, iv1);
+ br_enc32be(ivbuf + 8, iv2);
+ br_enc32be(ivbuf + 12, iv3);
+ br_enc32le((unsigned char *)cbcmac + 0, cm0);
+ br_enc32le((unsigned char *)cbcmac + 4, cm1);
+ br_enc32le((unsigned char *)cbcmac + 8, cm2);
+ br_enc32le((unsigned char *)cbcmac + 12, cm3);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_ct_ctrcbc_decrypt(const br_aes_ct_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len)
+{
+ unsigned char *buf;
+ unsigned char *ivbuf;
+ uint32_t iv0, iv1, iv2, iv3;
+ uint32_t cm0, cm1, cm2, cm3;
+ uint32_t sk_exp[120];
+
+ br_aes_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+
+ /*
+ * We keep the counter as four 32-bit values, with big-endian
+ * convention, because that's what is expected for purposes of
+ * incrementing the counter value.
+ */
+ ivbuf = ctr;
+ iv0 = br_dec32be(ivbuf + 0);
+ iv1 = br_dec32be(ivbuf + 4);
+ iv2 = br_dec32be(ivbuf + 8);
+ iv3 = br_dec32be(ivbuf + 12);
+
+ /*
+ * The current CBC-MAC value is kept in little-endian convention.
+ */
+ cm0 = br_dec32le((unsigned char *)cbcmac + 0);
+ cm1 = br_dec32le((unsigned char *)cbcmac + 4);
+ cm2 = br_dec32le((unsigned char *)cbcmac + 8);
+ cm3 = br_dec32le((unsigned char *)cbcmac + 12);
+
+ buf = data;
+ while (len > 0) {
+ uint32_t q[8], carry;
+ unsigned char tmp[16];
+
+ /*
+ * The bitslice implementation expects values in
+ * little-endian convention, so we have to byteswap them.
+ */
+ q[0] = br_swap32(iv0);
+ q[2] = br_swap32(iv1);
+ q[4] = br_swap32(iv2);
+ q[6] = br_swap32(iv3);
+ iv3 ++;
+ carry = ~(iv3 | -iv3) >> 31;
+ iv2 += carry;
+ carry &= -(~(iv2 | -iv2) >> 31);
+ iv1 += carry;
+ carry &= -(~(iv1 | -iv1) >> 31);
+ iv0 += carry;
+
+ /*
+ * The odd values are used for CBC-MAC.
+ */
+ q[1] = cm0 ^ br_dec32le(buf + 0);
+ q[3] = cm1 ^ br_dec32le(buf + 4);
+ q[5] = cm2 ^ br_dec32le(buf + 8);
+ q[7] = cm3 ^ br_dec32le(buf + 12);
+
+ br_aes_ct_ortho(q);
+ br_aes_ct_bitslice_encrypt(ctx->num_rounds, sk_exp, q);
+ br_aes_ct_ortho(q);
+
+ br_enc32le(tmp + 0, q[0]);
+ br_enc32le(tmp + 4, q[2]);
+ br_enc32le(tmp + 8, q[4]);
+ br_enc32le(tmp + 12, q[6]);
+ xorbuf(buf, tmp, 16);
+ cm0 = q[1];
+ cm1 = q[3];
+ cm2 = q[5];
+ cm3 = q[7];
+ buf += 16;
+ len -= 16;
+ }
+
+ br_enc32be(ivbuf + 0, iv0);
+ br_enc32be(ivbuf + 4, iv1);
+ br_enc32be(ivbuf + 8, iv2);
+ br_enc32be(ivbuf + 12, iv3);
+ br_enc32le((unsigned char *)cbcmac + 0, cm0);
+ br_enc32le((unsigned char *)cbcmac + 4, cm1);
+ br_enc32le((unsigned char *)cbcmac + 8, cm2);
+ br_enc32le((unsigned char *)cbcmac + 12, cm3);
+}
+
+/* see bearssl_block.h */
+const br_block_ctrcbc_class br_aes_ct_ctrcbc_vtable = {
+ sizeof(br_aes_ct_ctrcbc_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_ctrcbc_class **, const void *, size_t))
+ &br_aes_ct_ctrcbc_init,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, void *, size_t))
+ &br_aes_ct_ctrcbc_encrypt,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, void *, size_t))
+ &br_aes_ct_ctrcbc_decrypt,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, size_t))
+ &br_aes_ct_ctrcbc_ctr,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, const void *, size_t))
+ &br_aes_ct_ctrcbc_mac
+};
diff --git a/contrib/bearssl/src/symcipher/aes_ct_dec.c b/contrib/bearssl/src/symcipher/aes_ct_dec.c
new file mode 100644
index 000000000000..7f32d2bd446d
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_ct_dec.c
@@ -0,0 +1,170 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+void
+br_aes_ct_bitslice_invSbox(uint32_t *q)
+{
+ /*
+ * AES S-box is:
+ * S(x) = A(I(x)) ^ 0x63
+ * where I() is inversion in GF(256), and A() is a linear
+ * transform (0 is formally defined to be its own inverse).
+ * Since inversion is an involution, the inverse S-box can be
+ * computed from the S-box as:
+ * iS(x) = B(S(B(x ^ 0x63)) ^ 0x63)
+ * where B() is the inverse of A(). Indeed, for any y in GF(256):
+ * iS(S(y)) = B(A(I(B(A(I(y)) ^ 0x63 ^ 0x63))) ^ 0x63 ^ 0x63) = y
+ *
+ * Note: we reuse the implementation of the forward S-box,
+ * instead of duplicating it here, so that total code size is
+ * lower. By merging the B() transforms into the S-box circuit
+ * we could make faster CBC decryption, but CBC decryption is
+ * already quite faster than CBC encryption because we can
+ * process two blocks in parallel.
+ */
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+
+ q0 = ~q[0];
+ q1 = ~q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = ~q[5];
+ q6 = ~q[6];
+ q7 = q[7];
+ q[7] = q1 ^ q4 ^ q6;
+ q[6] = q0 ^ q3 ^ q5;
+ q[5] = q7 ^ q2 ^ q4;
+ q[4] = q6 ^ q1 ^ q3;
+ q[3] = q5 ^ q0 ^ q2;
+ q[2] = q4 ^ q7 ^ q1;
+ q[1] = q3 ^ q6 ^ q0;
+ q[0] = q2 ^ q5 ^ q7;
+
+ br_aes_ct_bitslice_Sbox(q);
+
+ q0 = ~q[0];
+ q1 = ~q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = ~q[5];
+ q6 = ~q[6];
+ q7 = q[7];
+ q[7] = q1 ^ q4 ^ q6;
+ q[6] = q0 ^ q3 ^ q5;
+ q[5] = q7 ^ q2 ^ q4;
+ q[4] = q6 ^ q1 ^ q3;
+ q[3] = q5 ^ q0 ^ q2;
+ q[2] = q4 ^ q7 ^ q1;
+ q[1] = q3 ^ q6 ^ q0;
+ q[0] = q2 ^ q5 ^ q7;
+}
+
+static void
+add_round_key(uint32_t *q, const uint32_t *sk)
+{
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ q[i] ^= sk[i];
+ }
+}
+
+static void
+inv_shift_rows(uint32_t *q)
+{
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ uint32_t x;
+
+ x = q[i];
+ q[i] = (x & 0x000000FF)
+ | ((x & 0x00003F00) << 2) | ((x & 0x0000C000) >> 6)
+ | ((x & 0x000F0000) << 4) | ((x & 0x00F00000) >> 4)
+ | ((x & 0x03000000) << 6) | ((x & 0xFC000000) >> 2);
+ }
+}
+
+static inline uint32_t
+rotr16(uint32_t x)
+{
+ return (x << 16) | (x >> 16);
+}
+
+static void
+inv_mix_columns(uint32_t *q)
+{
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint32_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 8) | (q0 << 24);
+ r1 = (q1 >> 8) | (q1 << 24);
+ r2 = (q2 >> 8) | (q2 << 24);
+ r3 = (q3 >> 8) | (q3 << 24);
+ r4 = (q4 >> 8) | (q4 << 24);
+ r5 = (q5 >> 8) | (q5 << 24);
+ r6 = (q6 >> 8) | (q6 << 24);
+ r7 = (q7 >> 8) | (q7 << 24);
+
+ q[0] = q5 ^ q6 ^ q7 ^ r0 ^ r5 ^ r7 ^ rotr16(q0 ^ q5 ^ q6 ^ r0 ^ r5);
+ q[1] = q0 ^ q5 ^ r0 ^ r1 ^ r5 ^ r6 ^ r7 ^ rotr16(q1 ^ q5 ^ q7 ^ r1 ^ r5 ^ r6);
+ q[2] = q0 ^ q1 ^ q6 ^ r1 ^ r2 ^ r6 ^ r7 ^ rotr16(q0 ^ q2 ^ q6 ^ r2 ^ r6 ^ r7);
+ q[3] = q0 ^ q1 ^ q2 ^ q5 ^ q6 ^ r0 ^ r2 ^ r3 ^ r5 ^ rotr16(q0 ^ q1 ^ q3 ^ q5 ^ q6 ^ q7 ^ r0 ^ r3 ^ r5 ^ r7);
+ q[4] = q1 ^ q2 ^ q3 ^ q5 ^ r1 ^ r3 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr16(q1 ^ q2 ^ q4 ^ q5 ^ q7 ^ r1 ^ r4 ^ r5 ^ r6);
+ q[5] = q2 ^ q3 ^ q4 ^ q6 ^ r2 ^ r4 ^ r5 ^ r6 ^ r7 ^ rotr16(q2 ^ q3 ^ q5 ^ q6 ^ r2 ^ r5 ^ r6 ^ r7);
+ q[6] = q3 ^ q4 ^ q5 ^ q7 ^ r3 ^ r5 ^ r6 ^ r7 ^ rotr16(q3 ^ q4 ^ q6 ^ q7 ^ r3 ^ r6 ^ r7);
+ q[7] = q4 ^ q5 ^ q6 ^ r4 ^ r6 ^ r7 ^ rotr16(q4 ^ q5 ^ q7 ^ r4 ^ r7);
+}
+
+/* see inner.h */
+void
+br_aes_ct_bitslice_decrypt(unsigned num_rounds,
+ const uint32_t *skey, uint32_t *q)
+{
+ unsigned u;
+
+ add_round_key(q, skey + (num_rounds << 3));
+ for (u = num_rounds - 1; u > 0; u --) {
+ inv_shift_rows(q);
+ br_aes_ct_bitslice_invSbox(q);
+ add_round_key(q, skey + (u << 3));
+ inv_mix_columns(q);
+ }
+ inv_shift_rows(q);
+ br_aes_ct_bitslice_invSbox(q);
+ add_round_key(q, skey);
+}
diff --git a/contrib/bearssl/src/symcipher/aes_ct_enc.c b/contrib/bearssl/src/symcipher/aes_ct_enc.c
new file mode 100644
index 000000000000..089bf3567d36
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_ct_enc.c
@@ -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.
+ */
+
+#include "inner.h"
+
+static inline void
+add_round_key(uint32_t *q, const uint32_t *sk)
+{
+ q[0] ^= sk[0];
+ q[1] ^= sk[1];
+ q[2] ^= sk[2];
+ q[3] ^= sk[3];
+ q[4] ^= sk[4];
+ q[5] ^= sk[5];
+ q[6] ^= sk[6];
+ q[7] ^= sk[7];
+}
+
+static inline void
+shift_rows(uint32_t *q)
+{
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ uint32_t x;
+
+ x = q[i];
+ q[i] = (x & 0x000000FF)
+ | ((x & 0x0000FC00) >> 2) | ((x & 0x00000300) << 6)
+ | ((x & 0x00F00000) >> 4) | ((x & 0x000F0000) << 4)
+ | ((x & 0xC0000000) >> 6) | ((x & 0x3F000000) << 2);
+ }
+}
+
+static inline uint32_t
+rotr16(uint32_t x)
+{
+ return (x << 16) | (x >> 16);
+}
+
+static inline void
+mix_columns(uint32_t *q)
+{
+ uint32_t q0, q1, q2, q3, q4, q5, q6, q7;
+ uint32_t r0, r1, r2, r3, r4, r5, r6, r7;
+
+ q0 = q[0];
+ q1 = q[1];
+ q2 = q[2];
+ q3 = q[3];
+ q4 = q[4];
+ q5 = q[5];
+ q6 = q[6];
+ q7 = q[7];
+ r0 = (q0 >> 8) | (q0 << 24);
+ r1 = (q1 >> 8) | (q1 << 24);
+ r2 = (q2 >> 8) | (q2 << 24);
+ r3 = (q3 >> 8) | (q3 << 24);
+ r4 = (q4 >> 8) | (q4 << 24);
+ r5 = (q5 >> 8) | (q5 << 24);
+ r6 = (q6 >> 8) | (q6 << 24);
+ r7 = (q7 >> 8) | (q7 << 24);
+
+ q[0] = q7 ^ r7 ^ r0 ^ rotr16(q0 ^ r0);
+ q[1] = q0 ^ r0 ^ q7 ^ r7 ^ r1 ^ rotr16(q1 ^ r1);
+ q[2] = q1 ^ r1 ^ r2 ^ rotr16(q2 ^ r2);
+ q[3] = q2 ^ r2 ^ q7 ^ r7 ^ r3 ^ rotr16(q3 ^ r3);
+ q[4] = q3 ^ r3 ^ q7 ^ r7 ^ r4 ^ rotr16(q4 ^ r4);
+ q[5] = q4 ^ r4 ^ r5 ^ rotr16(q5 ^ r5);
+ q[6] = q5 ^ r5 ^ r6 ^ rotr16(q6 ^ r6);
+ q[7] = q6 ^ r6 ^ r7 ^ rotr16(q7 ^ r7);
+}
+
+/* see inner.h */
+void
+br_aes_ct_bitslice_encrypt(unsigned num_rounds,
+ const uint32_t *skey, uint32_t *q)
+{
+ unsigned u;
+
+ add_round_key(q, skey);
+ for (u = 1; u < num_rounds; u ++) {
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows(q);
+ mix_columns(q);
+ add_round_key(q, skey + (u << 3));
+ }
+ br_aes_ct_bitslice_Sbox(q);
+ shift_rows(q);
+ add_round_key(q, skey + (num_rounds << 3));
+}
diff --git a/contrib/bearssl/src/symcipher/aes_pwr8.c b/contrib/bearssl/src/symcipher/aes_pwr8.c
new file mode 100644
index 000000000000..b2c63c32e5a5
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_pwr8.c
@@ -0,0 +1,445 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BR_POWER_ASM_MACROS 1
+#include "inner.h"
+
+/*
+ * This code contains the AES key schedule implementation using the
+ * POWER8 opcodes.
+ */
+
+#if BR_POWER8
+
+static void
+key_schedule_128(unsigned char *sk, const unsigned char *key)
+{
+ long cc;
+
+ static const uint32_t fmod[] = { 0x11B, 0x11B, 0x11B, 0x11B };
+#if BR_POWER8_LE
+ static const uint32_t idx2be[] = {
+ 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
+ };
+#endif
+
+ cc = 0;
+
+ /*
+ * We use the VSX instructions for loading and storing the
+ * key/subkeys, since they support unaligned accesses. The rest
+ * of the computation is VMX only. VMX register 0 is VSX
+ * register 32.
+ */
+ asm volatile (
+
+ /*
+ * v0 = all-zero word
+ * v1 = constant -8 / +8, copied into four words
+ * v2 = current subkey
+ * v3 = Rcon (x4 words)
+ * v6 = constant 8, copied into four words
+ * v7 = constant 0x11B, copied into four words
+ * v8 = constant for byteswapping words
+ */
+ vspltisw(0, 0)
+#if BR_POWER8_LE
+ vspltisw(1, -8)
+#else
+ vspltisw(1, 8)
+#endif
+ lxvw4x(34, 0, %[key])
+ vspltisw(3, 1)
+ vspltisw(6, 8)
+ lxvw4x(39, 0, %[fmod])
+#if BR_POWER8_LE
+ lxvw4x(40, 0, %[idx2be])
+#endif
+
+ /*
+ * First subkey is a copy of the key itself.
+ */
+#if BR_POWER8_LE
+ vperm(4, 2, 2, 8)
+ stxvw4x(36, 0, %[sk])
+#else
+ stxvw4x(34, 0, %[sk])
+#endif
+
+ /*
+ * Loop must run 10 times.
+ */
+ li(%[cc], 10)
+ mtctr(%[cc])
+ label(loop)
+ /* Increment subkey address */
+ addi(%[sk], %[sk], 16)
+
+ /* Compute SubWord(RotWord(temp)) xor Rcon (into v4, splat) */
+ vrlw(4, 2, 1)
+ vsbox(4, 4)
+#if BR_POWER8_LE
+ vxor(4, 4, 3)
+#else
+ vsldoi(5, 3, 0, 3)
+ vxor(4, 4, 5)
+#endif
+ vspltw(4, 4, 3)
+
+ /* XOR words for next subkey */
+ vsldoi(5, 0, 2, 12)
+ vxor(2, 2, 5)
+ vsldoi(5, 0, 2, 12)
+ vxor(2, 2, 5)
+ vsldoi(5, 0, 2, 12)
+ vxor(2, 2, 5)
+ vxor(2, 2, 4)
+
+ /* Store next subkey */
+#if BR_POWER8_LE
+ vperm(4, 2, 2, 8)
+ stxvw4x(36, 0, %[sk])
+#else
+ stxvw4x(34, 0, %[sk])
+#endif
+
+ /* Update Rcon */
+ vadduwm(3, 3, 3)
+ vsrw(4, 3, 6)
+ vsubuwm(4, 0, 4)
+ vand(4, 4, 7)
+ vxor(3, 3, 4)
+
+ bdnz(loop)
+
+: [sk] "+b" (sk), [cc] "+b" (cc)
+: [key] "b" (key), [fmod] "b" (fmod)
+#if BR_POWER8_LE
+ , [idx2be] "b" (idx2be)
+#endif
+: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "ctr", "memory"
+ );
+}
+
+static void
+key_schedule_192(unsigned char *sk, const unsigned char *key)
+{
+ long cc;
+
+#if BR_POWER8_LE
+ static const uint32_t idx2be[] = {
+ 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
+ };
+#endif
+
+ cc = 0;
+
+ /*
+ * We use the VSX instructions for loading and storing the
+ * key/subkeys, since they support unaligned accesses. The rest
+ * of the computation is VMX only. VMX register 0 is VSX
+ * register 32.
+ */
+ asm volatile (
+
+ /*
+ * v0 = all-zero word
+ * v1 = constant -8 / +8, copied into four words
+ * v2, v3 = current subkey
+ * v5 = Rcon (x4 words) (already shifted on big-endian)
+ * v6 = constant 8, copied into four words
+ * v8 = constant for byteswapping words
+ *
+ * The left two words of v3 are ignored.
+ */
+ vspltisw(0, 0)
+#if BR_POWER8_LE
+ vspltisw(1, -8)
+#else
+ vspltisw(1, 8)
+#endif
+ li(%[cc], 8)
+ lxvw4x(34, 0, %[key])
+ lxvw4x(35, %[cc], %[key])
+ vsldoi(3, 3, 0, 8)
+ vspltisw(5, 1)
+#if !BR_POWER8_LE
+ vsldoi(5, 5, 0, 3)
+#endif
+ vspltisw(6, 8)
+#if BR_POWER8_LE
+ lxvw4x(40, 0, %[idx2be])
+#endif
+
+ /*
+ * Loop must run 8 times. Each iteration produces 256
+ * bits of subkeys, with a 64-bit overlap.
+ */
+ li(%[cc], 8)
+ mtctr(%[cc])
+ li(%[cc], 16)
+ label(loop)
+
+ /*
+ * Last 6 words in v2:v3l. Compute next 6 words into
+ * v3r:v4.
+ */
+ vrlw(10, 3, 1)
+ vsbox(10, 10)
+ vxor(10, 10, 5)
+ vspltw(10, 10, 1)
+ vsldoi(11, 0, 10, 8)
+
+ vsldoi(12, 0, 2, 12)
+ vxor(12, 2, 12)
+ vsldoi(13, 0, 12, 12)
+ vxor(12, 12, 13)
+ vsldoi(13, 0, 12, 12)
+ vxor(12, 12, 13)
+
+ vspltw(13, 12, 3)
+ vxor(13, 13, 3)
+ vsldoi(14, 0, 3, 12)
+ vxor(13, 13, 14)
+
+ vsldoi(4, 12, 13, 8)
+ vsldoi(14, 0, 3, 8)
+ vsldoi(3, 14, 12, 8)
+
+ vxor(3, 3, 11)
+ vxor(4, 4, 10)
+
+ /*
+ * Update Rcon. Since for a 192-bit key, we use only 8
+ * such constants, we will not hit the field modulus,
+ * so a simple shift (addition) works well.
+ */
+ vadduwm(5, 5, 5)
+
+ /*
+ * Write out the two left 128-bit words
+ */
+#if BR_POWER8_LE
+ vperm(10, 2, 2, 8)
+ vperm(11, 3, 3, 8)
+ stxvw4x(42, 0, %[sk])
+ stxvw4x(43, %[cc], %[sk])
+#else
+ stxvw4x(34, 0, %[sk])
+ stxvw4x(35, %[cc], %[sk])
+#endif
+ addi(%[sk], %[sk], 24)
+
+ /*
+ * Shift words for next iteration.
+ */
+ vsldoi(2, 3, 4, 8)
+ vsldoi(3, 4, 0, 8)
+
+ bdnz(loop)
+
+ /*
+ * The loop wrote the first 50 subkey words, but we need
+ * to produce 52, so we must do one last write.
+ */
+#if BR_POWER8_LE
+ vperm(10, 2, 2, 8)
+ stxvw4x(42, 0, %[sk])
+#else
+ stxvw4x(34, 0, %[sk])
+#endif
+
+: [sk] "+b" (sk), [cc] "+b" (cc)
+: [key] "b" (key)
+#if BR_POWER8_LE
+ , [idx2be] "b" (idx2be)
+#endif
+: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
+ "v8", "v9", "v10", "v11", "v12", "v13", "v14", "ctr", "memory"
+ );
+}
+
+static void
+key_schedule_256(unsigned char *sk, const unsigned char *key)
+{
+ long cc;
+
+#if BR_POWER8_LE
+ static const uint32_t idx2be[] = {
+ 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
+ };
+#endif
+
+ cc = 0;
+
+ /*
+ * We use the VSX instructions for loading and storing the
+ * key/subkeys, since they support unaligned accesses. The rest
+ * of the computation is VMX only. VMX register 0 is VSX
+ * register 32.
+ */
+ asm volatile (
+
+ /*
+ * v0 = all-zero word
+ * v1 = constant -8 / +8, copied into four words
+ * v2, v3 = current subkey
+ * v6 = Rcon (x4 words) (already shifted on big-endian)
+ * v7 = constant 8, copied into four words
+ * v8 = constant for byteswapping words
+ *
+ * The left two words of v3 are ignored.
+ */
+ vspltisw(0, 0)
+#if BR_POWER8_LE
+ vspltisw(1, -8)
+#else
+ vspltisw(1, 8)
+#endif
+ li(%[cc], 16)
+ lxvw4x(34, 0, %[key])
+ lxvw4x(35, %[cc], %[key])
+ vspltisw(6, 1)
+#if !BR_POWER8_LE
+ vsldoi(6, 6, 0, 3)
+#endif
+ vspltisw(7, 8)
+#if BR_POWER8_LE
+ lxvw4x(40, 0, %[idx2be])
+#endif
+
+ /*
+ * Loop must run 7 times. Each iteration produces two
+ * subkeys.
+ */
+ li(%[cc], 7)
+ mtctr(%[cc])
+ li(%[cc], 16)
+ label(loop)
+
+ /*
+ * Current words are in v2:v3. Compute next word in v4.
+ */
+ vrlw(10, 3, 1)
+ vsbox(10, 10)
+ vxor(10, 10, 6)
+ vspltw(10, 10, 3)
+
+ vsldoi(4, 0, 2, 12)
+ vxor(4, 2, 4)
+ vsldoi(5, 0, 4, 12)
+ vxor(4, 4, 5)
+ vsldoi(5, 0, 4, 12)
+ vxor(4, 4, 5)
+ vxor(4, 4, 10)
+
+ /*
+ * Then other word in v5.
+ */
+ vsbox(10, 4)
+ vspltw(10, 10, 3)
+
+ vsldoi(5, 0, 3, 12)
+ vxor(5, 3, 5)
+ vsldoi(11, 0, 5, 12)
+ vxor(5, 5, 11)
+ vsldoi(11, 0, 5, 12)
+ vxor(5, 5, 11)
+ vxor(5, 5, 10)
+
+ /*
+ * Update Rcon. Since for a 256-bit key, we use only 7
+ * such constants, we will not hit the field modulus,
+ * so a simple shift (addition) works well.
+ */
+ vadduwm(6, 6, 6)
+
+ /*
+ * Write out the two left 128-bit words
+ */
+#if BR_POWER8_LE
+ vperm(10, 2, 2, 8)
+ vperm(11, 3, 3, 8)
+ stxvw4x(42, 0, %[sk])
+ stxvw4x(43, %[cc], %[sk])
+#else
+ stxvw4x(34, 0, %[sk])
+ stxvw4x(35, %[cc], %[sk])
+#endif
+ addi(%[sk], %[sk], 32)
+
+ /*
+ * Replace v2:v3 with v4:v5.
+ */
+ vxor(2, 0, 4)
+ vxor(3, 0, 5)
+
+ bdnz(loop)
+
+ /*
+ * The loop wrote the first 14 subkeys, but we need 15,
+ * so we must do an extra write.
+ */
+#if BR_POWER8_LE
+ vperm(10, 2, 2, 8)
+ stxvw4x(42, 0, %[sk])
+#else
+ stxvw4x(34, 0, %[sk])
+#endif
+
+: [sk] "+b" (sk), [cc] "+b" (cc)
+: [key] "b" (key)
+#if BR_POWER8_LE
+ , [idx2be] "b" (idx2be)
+#endif
+: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7",
+ "v8", "v9", "v10", "v11", "v12", "v13", "v14", "ctr", "memory"
+ );
+}
+
+/* see inner.h */
+int
+br_aes_pwr8_supported(void)
+{
+ return 1;
+}
+
+/* see inner.h */
+unsigned
+br_aes_pwr8_keysched(unsigned char *sk, const void *key, size_t len)
+{
+ switch (len) {
+ case 16:
+ key_schedule_128(sk, key);
+ return 10;
+ case 24:
+ key_schedule_192(sk, key);
+ return 12;
+ default:
+ key_schedule_256(sk, key);
+ return 14;
+ }
+}
+
+#endif
diff --git a/contrib/bearssl/src/symcipher/aes_pwr8_cbcdec.c b/contrib/bearssl/src/symcipher/aes_pwr8_cbcdec.c
new file mode 100644
index 000000000000..e535ba6f62a8
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_pwr8_cbcdec.c
@@ -0,0 +1,670 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BR_POWER_ASM_MACROS 1
+#include "inner.h"
+
+#if BR_POWER8
+
+/* see bearssl_block.h */
+void
+br_aes_pwr8_cbcdec_init(br_aes_pwr8_cbcdec_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_pwr8_cbcdec_vtable;
+ ctx->num_rounds = br_aes_pwr8_keysched(ctx->skey.skni, key, len);
+}
+
+static void
+cbcdec_128(const unsigned char *sk,
+ const unsigned char *iv, unsigned char *buf, size_t num_blocks)
+{
+ long cc0, cc1, cc2, cc3;
+
+#if BR_POWER8_LE
+ static const uint32_t idx2be[] = {
+ 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
+ };
+#endif
+
+ cc0 = 0;
+ cc1 = 16;
+ cc2 = 32;
+ cc3 = 48;
+ asm volatile (
+
+ /*
+ * Load subkeys into v0..v10
+ */
+ lxvw4x(32, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(33, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(34, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(35, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(36, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(37, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(38, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(39, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(40, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(41, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(42, %[cc0], %[sk])
+ li(%[cc0], 0)
+
+#if BR_POWER8_LE
+ /*
+ * v15 = constant for byteswapping words
+ */
+ lxvw4x(47, 0, %[idx2be])
+#endif
+ /*
+ * Load IV into v24.
+ */
+ lxvw4x(56, 0, %[iv])
+#if BR_POWER8_LE
+ vperm(24, 24, 24, 15)
+#endif
+
+ mtctr(%[num_blocks])
+ label(loop)
+ /*
+ * Load next ciphertext words in v16..v19. Also save them
+ * in v20..v23.
+ */
+ lxvw4x(48, %[cc0], %[buf])
+ lxvw4x(49, %[cc1], %[buf])
+ lxvw4x(50, %[cc2], %[buf])
+ lxvw4x(51, %[cc3], %[buf])
+#if BR_POWER8_LE
+ vperm(16, 16, 16, 15)
+ vperm(17, 17, 17, 15)
+ vperm(18, 18, 18, 15)
+ vperm(19, 19, 19, 15)
+#endif
+ vand(20, 16, 16)
+ vand(21, 17, 17)
+ vand(22, 18, 18)
+ vand(23, 19, 19)
+
+ /*
+ * Decrypt the blocks.
+ */
+ vxor(16, 16, 10)
+ vxor(17, 17, 10)
+ vxor(18, 18, 10)
+ vxor(19, 19, 10)
+ vncipher(16, 16, 9)
+ vncipher(17, 17, 9)
+ vncipher(18, 18, 9)
+ vncipher(19, 19, 9)
+ vncipher(16, 16, 8)
+ vncipher(17, 17, 8)
+ vncipher(18, 18, 8)
+ vncipher(19, 19, 8)
+ vncipher(16, 16, 7)
+ vncipher(17, 17, 7)
+ vncipher(18, 18, 7)
+ vncipher(19, 19, 7)
+ vncipher(16, 16, 6)
+ vncipher(17, 17, 6)
+ vncipher(18, 18, 6)
+ vncipher(19, 19, 6)
+ vncipher(16, 16, 5)
+ vncipher(17, 17, 5)
+ vncipher(18, 18, 5)
+ vncipher(19, 19, 5)
+ vncipher(16, 16, 4)
+ vncipher(17, 17, 4)
+ vncipher(18, 18, 4)
+ vncipher(19, 19, 4)
+ vncipher(16, 16, 3)
+ vncipher(17, 17, 3)
+ vncipher(18, 18, 3)
+ vncipher(19, 19, 3)
+ vncipher(16, 16, 2)
+ vncipher(17, 17, 2)
+ vncipher(18, 18, 2)
+ vncipher(19, 19, 2)
+ vncipher(16, 16, 1)
+ vncipher(17, 17, 1)
+ vncipher(18, 18, 1)
+ vncipher(19, 19, 1)
+ vncipherlast(16, 16, 0)
+ vncipherlast(17, 17, 0)
+ vncipherlast(18, 18, 0)
+ vncipherlast(19, 19, 0)
+
+ /*
+ * XOR decrypted blocks with IV / previous block.
+ */
+ vxor(16, 16, 24)
+ vxor(17, 17, 20)
+ vxor(18, 18, 21)
+ vxor(19, 19, 22)
+
+ /*
+ * Store back result (with byteswap)
+ */
+#if BR_POWER8_LE
+ vperm(16, 16, 16, 15)
+ vperm(17, 17, 17, 15)
+ vperm(18, 18, 18, 15)
+ vperm(19, 19, 19, 15)
+#endif
+ stxvw4x(48, %[cc0], %[buf])
+ stxvw4x(49, %[cc1], %[buf])
+ stxvw4x(50, %[cc2], %[buf])
+ stxvw4x(51, %[cc3], %[buf])
+
+ /*
+ * Fourth encrypted block is IV for next run.
+ */
+ vand(24, 23, 23)
+
+ addi(%[buf], %[buf], 64)
+
+ bdnz(loop)
+
+: [cc0] "+b" (cc0), [cc1] "+b" (cc1), [cc2] "+b" (cc2), [cc3] "+b" (cc3),
+ [buf] "+b" (buf)
+: [sk] "b" (sk), [iv] "b" (iv), [num_blocks] "b" (num_blocks >> 2)
+#if BR_POWER8_LE
+ , [idx2be] "b" (idx2be)
+#endif
+: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9",
+ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19",
+ "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29",
+ "ctr", "memory"
+ );
+}
+
+static void
+cbcdec_192(const unsigned char *sk,
+ const unsigned char *iv, unsigned char *buf, size_t num_blocks)
+{
+ long cc0, cc1, cc2, cc3;
+
+#if BR_POWER8_LE
+ static const uint32_t idx2be[] = {
+ 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
+ };
+#endif
+
+ cc0 = 0;
+ cc1 = 16;
+ cc2 = 32;
+ cc3 = 48;
+ asm volatile (
+
+ /*
+ * Load subkeys into v0..v12
+ */
+ lxvw4x(32, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(33, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(34, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(35, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(36, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(37, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(38, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(39, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(40, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(41, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(42, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(43, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(44, %[cc0], %[sk])
+ li(%[cc0], 0)
+
+#if BR_POWER8_LE
+ /*
+ * v15 = constant for byteswapping words
+ */
+ lxvw4x(47, 0, %[idx2be])
+#endif
+ /*
+ * Load IV into v24.
+ */
+ lxvw4x(56, 0, %[iv])
+#if BR_POWER8_LE
+ vperm(24, 24, 24, 15)
+#endif
+
+ mtctr(%[num_blocks])
+ label(loop)
+ /*
+ * Load next ciphertext words in v16..v19. Also save them
+ * in v20..v23.
+ */
+ lxvw4x(48, %[cc0], %[buf])
+ lxvw4x(49, %[cc1], %[buf])
+ lxvw4x(50, %[cc2], %[buf])
+ lxvw4x(51, %[cc3], %[buf])
+#if BR_POWER8_LE
+ vperm(16, 16, 16, 15)
+ vperm(17, 17, 17, 15)
+ vperm(18, 18, 18, 15)
+ vperm(19, 19, 19, 15)
+#endif
+ vand(20, 16, 16)
+ vand(21, 17, 17)
+ vand(22, 18, 18)
+ vand(23, 19, 19)
+
+ /*
+ * Decrypt the blocks.
+ */
+ vxor(16, 16, 12)
+ vxor(17, 17, 12)
+ vxor(18, 18, 12)
+ vxor(19, 19, 12)
+ vncipher(16, 16, 11)
+ vncipher(17, 17, 11)
+ vncipher(18, 18, 11)
+ vncipher(19, 19, 11)
+ vncipher(16, 16, 10)
+ vncipher(17, 17, 10)
+ vncipher(18, 18, 10)
+ vncipher(19, 19, 10)
+ vncipher(16, 16, 9)
+ vncipher(17, 17, 9)
+ vncipher(18, 18, 9)
+ vncipher(19, 19, 9)
+ vncipher(16, 16, 8)
+ vncipher(17, 17, 8)
+ vncipher(18, 18, 8)
+ vncipher(19, 19, 8)
+ vncipher(16, 16, 7)
+ vncipher(17, 17, 7)
+ vncipher(18, 18, 7)
+ vncipher(19, 19, 7)
+ vncipher(16, 16, 6)
+ vncipher(17, 17, 6)
+ vncipher(18, 18, 6)
+ vncipher(19, 19, 6)
+ vncipher(16, 16, 5)
+ vncipher(17, 17, 5)
+ vncipher(18, 18, 5)
+ vncipher(19, 19, 5)
+ vncipher(16, 16, 4)
+ vncipher(17, 17, 4)
+ vncipher(18, 18, 4)
+ vncipher(19, 19, 4)
+ vncipher(16, 16, 3)
+ vncipher(17, 17, 3)
+ vncipher(18, 18, 3)
+ vncipher(19, 19, 3)
+ vncipher(16, 16, 2)
+ vncipher(17, 17, 2)
+ vncipher(18, 18, 2)
+ vncipher(19, 19, 2)
+ vncipher(16, 16, 1)
+ vncipher(17, 17, 1)
+ vncipher(18, 18, 1)
+ vncipher(19, 19, 1)
+ vncipherlast(16, 16, 0)
+ vncipherlast(17, 17, 0)
+ vncipherlast(18, 18, 0)
+ vncipherlast(19, 19, 0)
+
+ /*
+ * XOR decrypted blocks with IV / previous block.
+ */
+ vxor(16, 16, 24)
+ vxor(17, 17, 20)
+ vxor(18, 18, 21)
+ vxor(19, 19, 22)
+
+ /*
+ * Store back result (with byteswap)
+ */
+#if BR_POWER8_LE
+ vperm(16, 16, 16, 15)
+ vperm(17, 17, 17, 15)
+ vperm(18, 18, 18, 15)
+ vperm(19, 19, 19, 15)
+#endif
+ stxvw4x(48, %[cc0], %[buf])
+ stxvw4x(49, %[cc1], %[buf])
+ stxvw4x(50, %[cc2], %[buf])
+ stxvw4x(51, %[cc3], %[buf])
+
+ /*
+ * Fourth encrypted block is IV for next run.
+ */
+ vand(24, 23, 23)
+
+ addi(%[buf], %[buf], 64)
+
+ bdnz(loop)
+
+: [cc0] "+b" (cc0), [cc1] "+b" (cc1), [cc2] "+b" (cc2), [cc3] "+b" (cc3),
+ [buf] "+b" (buf)
+: [sk] "b" (sk), [iv] "b" (iv), [num_blocks] "b" (num_blocks >> 2)
+#if BR_POWER8_LE
+ , [idx2be] "b" (idx2be)
+#endif
+: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9",
+ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19",
+ "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29",
+ "ctr", "memory"
+ );
+}
+
+static void
+cbcdec_256(const unsigned char *sk,
+ const unsigned char *iv, unsigned char *buf, size_t num_blocks)
+{
+ long cc0, cc1, cc2, cc3;
+
+#if BR_POWER8_LE
+ static const uint32_t idx2be[] = {
+ 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
+ };
+#endif
+
+ cc0 = 0;
+ cc1 = 16;
+ cc2 = 32;
+ cc3 = 48;
+ asm volatile (
+
+ /*
+ * Load subkeys into v0..v14
+ */
+ lxvw4x(32, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(33, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(34, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(35, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(36, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(37, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(38, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(39, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(40, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(41, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(42, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(43, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(44, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(45, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(46, %[cc0], %[sk])
+ li(%[cc0], 0)
+
+#if BR_POWER8_LE
+ /*
+ * v15 = constant for byteswapping words
+ */
+ lxvw4x(47, 0, %[idx2be])
+#endif
+ /*
+ * Load IV into v24.
+ */
+ lxvw4x(56, 0, %[iv])
+#if BR_POWER8_LE
+ vperm(24, 24, 24, 15)
+#endif
+
+ mtctr(%[num_blocks])
+ label(loop)
+ /*
+ * Load next ciphertext words in v16..v19. Also save them
+ * in v20..v23.
+ */
+ lxvw4x(48, %[cc0], %[buf])
+ lxvw4x(49, %[cc1], %[buf])
+ lxvw4x(50, %[cc2], %[buf])
+ lxvw4x(51, %[cc3], %[buf])
+#if BR_POWER8_LE
+ vperm(16, 16, 16, 15)
+ vperm(17, 17, 17, 15)
+ vperm(18, 18, 18, 15)
+ vperm(19, 19, 19, 15)
+#endif
+ vand(20, 16, 16)
+ vand(21, 17, 17)
+ vand(22, 18, 18)
+ vand(23, 19, 19)
+
+ /*
+ * Decrypt the blocks.
+ */
+ vxor(16, 16, 14)
+ vxor(17, 17, 14)
+ vxor(18, 18, 14)
+ vxor(19, 19, 14)
+ vncipher(16, 16, 13)
+ vncipher(17, 17, 13)
+ vncipher(18, 18, 13)
+ vncipher(19, 19, 13)
+ vncipher(16, 16, 12)
+ vncipher(17, 17, 12)
+ vncipher(18, 18, 12)
+ vncipher(19, 19, 12)
+ vncipher(16, 16, 11)
+ vncipher(17, 17, 11)
+ vncipher(18, 18, 11)
+ vncipher(19, 19, 11)
+ vncipher(16, 16, 10)
+ vncipher(17, 17, 10)
+ vncipher(18, 18, 10)
+ vncipher(19, 19, 10)
+ vncipher(16, 16, 9)
+ vncipher(17, 17, 9)
+ vncipher(18, 18, 9)
+ vncipher(19, 19, 9)
+ vncipher(16, 16, 8)
+ vncipher(17, 17, 8)
+ vncipher(18, 18, 8)
+ vncipher(19, 19, 8)
+ vncipher(16, 16, 7)
+ vncipher(17, 17, 7)
+ vncipher(18, 18, 7)
+ vncipher(19, 19, 7)
+ vncipher(16, 16, 6)
+ vncipher(17, 17, 6)
+ vncipher(18, 18, 6)
+ vncipher(19, 19, 6)
+ vncipher(16, 16, 5)
+ vncipher(17, 17, 5)
+ vncipher(18, 18, 5)
+ vncipher(19, 19, 5)
+ vncipher(16, 16, 4)
+ vncipher(17, 17, 4)
+ vncipher(18, 18, 4)
+ vncipher(19, 19, 4)
+ vncipher(16, 16, 3)
+ vncipher(17, 17, 3)
+ vncipher(18, 18, 3)
+ vncipher(19, 19, 3)
+ vncipher(16, 16, 2)
+ vncipher(17, 17, 2)
+ vncipher(18, 18, 2)
+ vncipher(19, 19, 2)
+ vncipher(16, 16, 1)
+ vncipher(17, 17, 1)
+ vncipher(18, 18, 1)
+ vncipher(19, 19, 1)
+ vncipherlast(16, 16, 0)
+ vncipherlast(17, 17, 0)
+ vncipherlast(18, 18, 0)
+ vncipherlast(19, 19, 0)
+
+ /*
+ * XOR decrypted blocks with IV / previous block.
+ */
+ vxor(16, 16, 24)
+ vxor(17, 17, 20)
+ vxor(18, 18, 21)
+ vxor(19, 19, 22)
+
+ /*
+ * Store back result (with byteswap)
+ */
+#if BR_POWER8_LE
+ vperm(16, 16, 16, 15)
+ vperm(17, 17, 17, 15)
+ vperm(18, 18, 18, 15)
+ vperm(19, 19, 19, 15)
+#endif
+ stxvw4x(48, %[cc0], %[buf])
+ stxvw4x(49, %[cc1], %[buf])
+ stxvw4x(50, %[cc2], %[buf])
+ stxvw4x(51, %[cc3], %[buf])
+
+ /*
+ * Fourth encrypted block is IV for next run.
+ */
+ vand(24, 23, 23)
+
+ addi(%[buf], %[buf], 64)
+
+ bdnz(loop)
+
+: [cc0] "+b" (cc0), [cc1] "+b" (cc1), [cc2] "+b" (cc2), [cc3] "+b" (cc3),
+ [buf] "+b" (buf)
+: [sk] "b" (sk), [iv] "b" (iv), [num_blocks] "b" (num_blocks >> 2)
+#if BR_POWER8_LE
+ , [idx2be] "b" (idx2be)
+#endif
+: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9",
+ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19",
+ "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29",
+ "ctr", "memory"
+ );
+}
+
+/* see bearssl_block.h */
+void
+br_aes_pwr8_cbcdec_run(const br_aes_pwr8_cbcdec_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char nextiv[16];
+ unsigned char *buf;
+
+ if (len == 0) {
+ return;
+ }
+ buf = data;
+ memcpy(nextiv, buf + len - 16, 16);
+ if (len >= 64) {
+ size_t num_blocks;
+ unsigned char tmp[16];
+
+ num_blocks = (len >> 4) & ~(size_t)3;
+ memcpy(tmp, buf + (num_blocks << 4) - 16, 16);
+ switch (ctx->num_rounds) {
+ case 10:
+ cbcdec_128(ctx->skey.skni, iv, buf, num_blocks);
+ break;
+ case 12:
+ cbcdec_192(ctx->skey.skni, iv, buf, num_blocks);
+ break;
+ default:
+ cbcdec_256(ctx->skey.skni, iv, buf, num_blocks);
+ break;
+ }
+ buf += num_blocks << 4;
+ len &= 63;
+ memcpy(iv, tmp, 16);
+ }
+ if (len > 0) {
+ unsigned char tmp[64];
+
+ memcpy(tmp, buf, len);
+ memset(tmp + len, 0, (sizeof tmp) - len);
+ switch (ctx->num_rounds) {
+ case 10:
+ cbcdec_128(ctx->skey.skni, iv, tmp, 4);
+ break;
+ case 12:
+ cbcdec_192(ctx->skey.skni, iv, tmp, 4);
+ break;
+ default:
+ cbcdec_256(ctx->skey.skni, iv, tmp, 4);
+ break;
+ }
+ memcpy(buf, tmp, len);
+ }
+ memcpy(iv, nextiv, 16);
+}
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class br_aes_pwr8_cbcdec_vtable = {
+ sizeof(br_aes_pwr8_cbcdec_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcdec_class **, const void *, size_t))
+ &br_aes_pwr8_cbcdec_init,
+ (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t))
+ &br_aes_pwr8_cbcdec_run
+};
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class *
+br_aes_pwr8_cbcdec_get_vtable(void)
+{
+ return br_aes_pwr8_supported() ? &br_aes_pwr8_cbcdec_vtable : NULL;
+}
+
+#else
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class *
+br_aes_pwr8_cbcdec_get_vtable(void)
+{
+ return NULL;
+}
+
+#endif
diff --git a/contrib/bearssl/src/symcipher/aes_pwr8_cbcenc.c b/contrib/bearssl/src/symcipher/aes_pwr8_cbcenc.c
new file mode 100644
index 000000000000..00f8eca72cda
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_pwr8_cbcenc.c
@@ -0,0 +1,417 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BR_POWER_ASM_MACROS 1
+#include "inner.h"
+
+#if BR_POWER8
+
+/* see bearssl_block.h */
+void
+br_aes_pwr8_cbcenc_init(br_aes_pwr8_cbcenc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_pwr8_cbcenc_vtable;
+ ctx->num_rounds = br_aes_pwr8_keysched(ctx->skey.skni, key, len);
+}
+
+static void
+cbcenc_128(const unsigned char *sk,
+ const unsigned char *iv, unsigned char *buf, size_t len)
+{
+ long cc;
+
+#if BR_POWER8_LE
+ static const uint32_t idx2be[] = {
+ 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
+ };
+#endif
+
+ cc = 0;
+ asm volatile (
+
+ /*
+ * Load subkeys into v0..v10
+ */
+ lxvw4x(32, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(33, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(34, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(35, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(36, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(37, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(38, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(39, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(40, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(41, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(42, %[cc], %[sk])
+
+#if BR_POWER8_LE
+ /*
+ * v15 = constant for byteswapping words
+ */
+ lxvw4x(47, 0, %[idx2be])
+#endif
+ /*
+ * Load IV into v16.
+ */
+ lxvw4x(48, 0, %[iv])
+#if BR_POWER8_LE
+ vperm(16, 16, 16, 15)
+#endif
+
+ mtctr(%[num_blocks])
+ label(loop)
+ /*
+ * Load next plaintext word and XOR with current IV.
+ */
+ lxvw4x(49, 0, %[buf])
+#if BR_POWER8_LE
+ vperm(17, 17, 17, 15)
+#endif
+ vxor(16, 16, 17)
+
+ /*
+ * Encrypt the block.
+ */
+ vxor(16, 16, 0)
+ vcipher(16, 16, 1)
+ vcipher(16, 16, 2)
+ vcipher(16, 16, 3)
+ vcipher(16, 16, 4)
+ vcipher(16, 16, 5)
+ vcipher(16, 16, 6)
+ vcipher(16, 16, 7)
+ vcipher(16, 16, 8)
+ vcipher(16, 16, 9)
+ vcipherlast(16, 16, 10)
+
+ /*
+ * Store back result (with byteswap)
+ */
+#if BR_POWER8_LE
+ vperm(17, 16, 16, 15)
+ stxvw4x(49, 0, %[buf])
+#else
+ stxvw4x(48, 0, %[buf])
+#endif
+ addi(%[buf], %[buf], 16)
+
+ bdnz(loop)
+
+: [cc] "+b" (cc), [buf] "+b" (buf)
+: [sk] "b" (sk), [iv] "b" (iv), [num_blocks] "b" (len >> 4)
+#if BR_POWER8_LE
+ , [idx2be] "b" (idx2be)
+#endif
+: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9",
+ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19",
+ "ctr", "memory"
+ );
+}
+
+static void
+cbcenc_192(const unsigned char *sk,
+ const unsigned char *iv, unsigned char *buf, size_t len)
+{
+ long cc;
+
+#if BR_POWER8_LE
+ static const uint32_t idx2be[] = {
+ 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
+ };
+#endif
+
+ cc = 0;
+ asm volatile (
+
+ /*
+ * Load subkeys into v0..v12
+ */
+ lxvw4x(32, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(33, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(34, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(35, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(36, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(37, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(38, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(39, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(40, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(41, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(42, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(43, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(44, %[cc], %[sk])
+
+#if BR_POWER8_LE
+ /*
+ * v15 = constant for byteswapping words
+ */
+ lxvw4x(47, 0, %[idx2be])
+#endif
+ /*
+ * Load IV into v16.
+ */
+ lxvw4x(48, 0, %[iv])
+#if BR_POWER8_LE
+ vperm(16, 16, 16, 15)
+#endif
+
+ mtctr(%[num_blocks])
+ label(loop)
+ /*
+ * Load next plaintext word and XOR with current IV.
+ */
+ lxvw4x(49, 0, %[buf])
+#if BR_POWER8_LE
+ vperm(17, 17, 17, 15)
+#endif
+ vxor(16, 16, 17)
+
+ /*
+ * Encrypt the block.
+ */
+ vxor(16, 16, 0)
+ vcipher(16, 16, 1)
+ vcipher(16, 16, 2)
+ vcipher(16, 16, 3)
+ vcipher(16, 16, 4)
+ vcipher(16, 16, 5)
+ vcipher(16, 16, 6)
+ vcipher(16, 16, 7)
+ vcipher(16, 16, 8)
+ vcipher(16, 16, 9)
+ vcipher(16, 16, 10)
+ vcipher(16, 16, 11)
+ vcipherlast(16, 16, 12)
+
+ /*
+ * Store back result (with byteswap)
+ */
+#if BR_POWER8_LE
+ vperm(17, 16, 16, 15)
+ stxvw4x(49, 0, %[buf])
+#else
+ stxvw4x(48, 0, %[buf])
+#endif
+ addi(%[buf], %[buf], 16)
+
+ bdnz(loop)
+
+: [cc] "+b" (cc), [buf] "+b" (buf)
+: [sk] "b" (sk), [iv] "b" (iv), [num_blocks] "b" (len >> 4)
+#if BR_POWER8_LE
+ , [idx2be] "b" (idx2be)
+#endif
+: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9",
+ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19",
+ "ctr", "memory"
+ );
+}
+
+static void
+cbcenc_256(const unsigned char *sk,
+ const unsigned char *iv, unsigned char *buf, size_t len)
+{
+ long cc;
+
+#if BR_POWER8_LE
+ static const uint32_t idx2be[] = {
+ 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
+ };
+#endif
+
+ cc = 0;
+ asm volatile (
+
+ /*
+ * Load subkeys into v0..v14
+ */
+ lxvw4x(32, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(33, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(34, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(35, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(36, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(37, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(38, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(39, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(40, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(41, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(42, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(43, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(44, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(45, %[cc], %[sk])
+ addi(%[cc], %[cc], 16)
+ lxvw4x(46, %[cc], %[sk])
+
+#if BR_POWER8_LE
+ /*
+ * v15 = constant for byteswapping words
+ */
+ lxvw4x(47, 0, %[idx2be])
+#endif
+ /*
+ * Load IV into v16.
+ */
+ lxvw4x(48, 0, %[iv])
+#if BR_POWER8_LE
+ vperm(16, 16, 16, 15)
+#endif
+
+ mtctr(%[num_blocks])
+ label(loop)
+ /*
+ * Load next plaintext word and XOR with current IV.
+ */
+ lxvw4x(49, 0, %[buf])
+#if BR_POWER8_LE
+ vperm(17, 17, 17, 15)
+#endif
+ vxor(16, 16, 17)
+
+ /*
+ * Encrypt the block.
+ */
+ vxor(16, 16, 0)
+ vcipher(16, 16, 1)
+ vcipher(16, 16, 2)
+ vcipher(16, 16, 3)
+ vcipher(16, 16, 4)
+ vcipher(16, 16, 5)
+ vcipher(16, 16, 6)
+ vcipher(16, 16, 7)
+ vcipher(16, 16, 8)
+ vcipher(16, 16, 9)
+ vcipher(16, 16, 10)
+ vcipher(16, 16, 11)
+ vcipher(16, 16, 12)
+ vcipher(16, 16, 13)
+ vcipherlast(16, 16, 14)
+
+ /*
+ * Store back result (with byteswap)
+ */
+#if BR_POWER8_LE
+ vperm(17, 16, 16, 15)
+ stxvw4x(49, 0, %[buf])
+#else
+ stxvw4x(48, 0, %[buf])
+#endif
+ addi(%[buf], %[buf], 16)
+
+ bdnz(loop)
+
+: [cc] "+b" (cc), [buf] "+b" (buf)
+: [sk] "b" (sk), [iv] "b" (iv), [num_blocks] "b" (len >> 4)
+#if BR_POWER8_LE
+ , [idx2be] "b" (idx2be)
+#endif
+: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9",
+ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19",
+ "ctr", "memory"
+ );
+}
+
+/* see bearssl_block.h */
+void
+br_aes_pwr8_cbcenc_run(const br_aes_pwr8_cbcenc_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ if (len > 0) {
+ switch (ctx->num_rounds) {
+ case 10:
+ cbcenc_128(ctx->skey.skni, iv, data, len);
+ break;
+ case 12:
+ cbcenc_192(ctx->skey.skni, iv, data, len);
+ break;
+ default:
+ cbcenc_256(ctx->skey.skni, iv, data, len);
+ break;
+ }
+ memcpy(iv, (unsigned char *)data + (len - 16), 16);
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class br_aes_pwr8_cbcenc_vtable = {
+ sizeof(br_aes_pwr8_cbcenc_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcenc_class **, const void *, size_t))
+ &br_aes_pwr8_cbcenc_init,
+ (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t))
+ &br_aes_pwr8_cbcenc_run
+};
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class *
+br_aes_pwr8_cbcenc_get_vtable(void)
+{
+ return br_aes_pwr8_supported() ? &br_aes_pwr8_cbcenc_vtable : NULL;
+}
+
+#else
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class *
+br_aes_pwr8_cbcenc_get_vtable(void)
+{
+ return NULL;
+}
+
+#endif
diff --git a/contrib/bearssl/src/symcipher/aes_pwr8_ctr.c b/contrib/bearssl/src/symcipher/aes_pwr8_ctr.c
new file mode 100644
index 000000000000..f5d20c0b4812
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_pwr8_ctr.c
@@ -0,0 +1,717 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BR_POWER_ASM_MACROS 1
+#include "inner.h"
+
+#if BR_POWER8
+
+/* see bearssl_block.h */
+void
+br_aes_pwr8_ctr_init(br_aes_pwr8_ctr_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_pwr8_ctr_vtable;
+ ctx->num_rounds = br_aes_pwr8_keysched(ctx->skey.skni, key, len);
+}
+
+static void
+ctr_128(const unsigned char *sk, const unsigned char *ivbuf,
+ unsigned char *buf, size_t num_blocks)
+{
+ long cc0, cc1, cc2, cc3;
+
+#if BR_POWER8_LE
+ static const uint32_t idx2be[] = {
+ 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
+ };
+#endif
+ static const uint32_t ctrinc[] = {
+ 0, 0, 0, 4
+ };
+
+ cc0 = 0;
+ cc1 = 16;
+ cc2 = 32;
+ cc3 = 48;
+ asm volatile (
+
+ /*
+ * Load subkeys into v0..v10
+ */
+ lxvw4x(32, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(33, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(34, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(35, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(36, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(37, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(38, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(39, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(40, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(41, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(42, %[cc0], %[sk])
+ li(%[cc0], 0)
+
+#if BR_POWER8_LE
+ /*
+ * v15 = constant for byteswapping words
+ */
+ lxvw4x(47, 0, %[idx2be])
+#endif
+ /*
+ * v28 = increment for IV counter.
+ */
+ lxvw4x(60, 0, %[ctrinc])
+
+ /*
+ * Load IV into v16..v19
+ */
+ lxvw4x(48, %[cc0], %[ivbuf])
+ lxvw4x(49, %[cc1], %[ivbuf])
+ lxvw4x(50, %[cc2], %[ivbuf])
+ lxvw4x(51, %[cc3], %[ivbuf])
+#if BR_POWER8_LE
+ vperm(16, 16, 16, 15)
+ vperm(17, 17, 17, 15)
+ vperm(18, 18, 18, 15)
+ vperm(19, 19, 19, 15)
+#endif
+
+ mtctr(%[num_blocks])
+ label(loop)
+ /*
+ * Compute next IV into v24..v27
+ */
+ vadduwm(24, 16, 28)
+ vadduwm(25, 17, 28)
+ vadduwm(26, 18, 28)
+ vadduwm(27, 19, 28)
+
+ /*
+ * Load next data blocks. We do this early on but we
+ * won't need them until IV encryption is done.
+ */
+ lxvw4x(52, %[cc0], %[buf])
+ lxvw4x(53, %[cc1], %[buf])
+ lxvw4x(54, %[cc2], %[buf])
+ lxvw4x(55, %[cc3], %[buf])
+
+ /*
+ * Encrypt the current IV.
+ */
+ vxor(16, 16, 0)
+ vxor(17, 17, 0)
+ vxor(18, 18, 0)
+ vxor(19, 19, 0)
+ vcipher(16, 16, 1)
+ vcipher(17, 17, 1)
+ vcipher(18, 18, 1)
+ vcipher(19, 19, 1)
+ vcipher(16, 16, 2)
+ vcipher(17, 17, 2)
+ vcipher(18, 18, 2)
+ vcipher(19, 19, 2)
+ vcipher(16, 16, 3)
+ vcipher(17, 17, 3)
+ vcipher(18, 18, 3)
+ vcipher(19, 19, 3)
+ vcipher(16, 16, 4)
+ vcipher(17, 17, 4)
+ vcipher(18, 18, 4)
+ vcipher(19, 19, 4)
+ vcipher(16, 16, 5)
+ vcipher(17, 17, 5)
+ vcipher(18, 18, 5)
+ vcipher(19, 19, 5)
+ vcipher(16, 16, 6)
+ vcipher(17, 17, 6)
+ vcipher(18, 18, 6)
+ vcipher(19, 19, 6)
+ vcipher(16, 16, 7)
+ vcipher(17, 17, 7)
+ vcipher(18, 18, 7)
+ vcipher(19, 19, 7)
+ vcipher(16, 16, 8)
+ vcipher(17, 17, 8)
+ vcipher(18, 18, 8)
+ vcipher(19, 19, 8)
+ vcipher(16, 16, 9)
+ vcipher(17, 17, 9)
+ vcipher(18, 18, 9)
+ vcipher(19, 19, 9)
+ vcipherlast(16, 16, 10)
+ vcipherlast(17, 17, 10)
+ vcipherlast(18, 18, 10)
+ vcipherlast(19, 19, 10)
+
+#if BR_POWER8_LE
+ vperm(16, 16, 16, 15)
+ vperm(17, 17, 17, 15)
+ vperm(18, 18, 18, 15)
+ vperm(19, 19, 19, 15)
+#endif
+
+ /*
+ * Load next plaintext word and XOR with encrypted IV.
+ */
+ vxor(16, 20, 16)
+ vxor(17, 21, 17)
+ vxor(18, 22, 18)
+ vxor(19, 23, 19)
+ stxvw4x(48, %[cc0], %[buf])
+ stxvw4x(49, %[cc1], %[buf])
+ stxvw4x(50, %[cc2], %[buf])
+ stxvw4x(51, %[cc3], %[buf])
+
+ addi(%[buf], %[buf], 64)
+
+ /*
+ * Update IV.
+ */
+ vand(16, 24, 24)
+ vand(17, 25, 25)
+ vand(18, 26, 26)
+ vand(19, 27, 27)
+
+ bdnz(loop)
+
+: [cc0] "+b" (cc0), [cc1] "+b" (cc1), [cc2] "+b" (cc2), [cc3] "+b" (cc3),
+ [buf] "+b" (buf)
+: [sk] "b" (sk), [ivbuf] "b" (ivbuf), [num_blocks] "b" (num_blocks >> 2),
+ [ctrinc] "b" (ctrinc)
+#if BR_POWER8_LE
+ , [idx2be] "b" (idx2be)
+#endif
+: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9",
+ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19",
+ "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29",
+ "ctr", "memory"
+ );
+}
+
+static void
+ctr_192(const unsigned char *sk, const unsigned char *ivbuf,
+ unsigned char *buf, size_t num_blocks)
+{
+ long cc0, cc1, cc2, cc3;
+
+#if BR_POWER8_LE
+ static const uint32_t idx2be[] = {
+ 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
+ };
+#endif
+ static const uint32_t ctrinc[] = {
+ 0, 0, 0, 4
+ };
+
+ cc0 = 0;
+ cc1 = 16;
+ cc2 = 32;
+ cc3 = 48;
+ asm volatile (
+
+ /*
+ * Load subkeys into v0..v12
+ */
+ lxvw4x(32, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(33, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(34, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(35, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(36, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(37, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(38, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(39, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(40, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(41, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(42, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(43, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(44, %[cc0], %[sk])
+ li(%[cc0], 0)
+
+#if BR_POWER8_LE
+ /*
+ * v15 = constant for byteswapping words
+ */
+ lxvw4x(47, 0, %[idx2be])
+#endif
+ /*
+ * v28 = increment for IV counter.
+ */
+ lxvw4x(60, 0, %[ctrinc])
+
+ /*
+ * Load IV into v16..v19
+ */
+ lxvw4x(48, %[cc0], %[ivbuf])
+ lxvw4x(49, %[cc1], %[ivbuf])
+ lxvw4x(50, %[cc2], %[ivbuf])
+ lxvw4x(51, %[cc3], %[ivbuf])
+#if BR_POWER8_LE
+ vperm(16, 16, 16, 15)
+ vperm(17, 17, 17, 15)
+ vperm(18, 18, 18, 15)
+ vperm(19, 19, 19, 15)
+#endif
+
+ mtctr(%[num_blocks])
+ label(loop)
+ /*
+ * Compute next IV into v24..v27
+ */
+ vadduwm(24, 16, 28)
+ vadduwm(25, 17, 28)
+ vadduwm(26, 18, 28)
+ vadduwm(27, 19, 28)
+
+ /*
+ * Load next data blocks. We do this early on but we
+ * won't need them until IV encryption is done.
+ */
+ lxvw4x(52, %[cc0], %[buf])
+ lxvw4x(53, %[cc1], %[buf])
+ lxvw4x(54, %[cc2], %[buf])
+ lxvw4x(55, %[cc3], %[buf])
+
+ /*
+ * Encrypt the current IV.
+ */
+ vxor(16, 16, 0)
+ vxor(17, 17, 0)
+ vxor(18, 18, 0)
+ vxor(19, 19, 0)
+ vcipher(16, 16, 1)
+ vcipher(17, 17, 1)
+ vcipher(18, 18, 1)
+ vcipher(19, 19, 1)
+ vcipher(16, 16, 2)
+ vcipher(17, 17, 2)
+ vcipher(18, 18, 2)
+ vcipher(19, 19, 2)
+ vcipher(16, 16, 3)
+ vcipher(17, 17, 3)
+ vcipher(18, 18, 3)
+ vcipher(19, 19, 3)
+ vcipher(16, 16, 4)
+ vcipher(17, 17, 4)
+ vcipher(18, 18, 4)
+ vcipher(19, 19, 4)
+ vcipher(16, 16, 5)
+ vcipher(17, 17, 5)
+ vcipher(18, 18, 5)
+ vcipher(19, 19, 5)
+ vcipher(16, 16, 6)
+ vcipher(17, 17, 6)
+ vcipher(18, 18, 6)
+ vcipher(19, 19, 6)
+ vcipher(16, 16, 7)
+ vcipher(17, 17, 7)
+ vcipher(18, 18, 7)
+ vcipher(19, 19, 7)
+ vcipher(16, 16, 8)
+ vcipher(17, 17, 8)
+ vcipher(18, 18, 8)
+ vcipher(19, 19, 8)
+ vcipher(16, 16, 9)
+ vcipher(17, 17, 9)
+ vcipher(18, 18, 9)
+ vcipher(19, 19, 9)
+ vcipher(16, 16, 10)
+ vcipher(17, 17, 10)
+ vcipher(18, 18, 10)
+ vcipher(19, 19, 10)
+ vcipher(16, 16, 11)
+ vcipher(17, 17, 11)
+ vcipher(18, 18, 11)
+ vcipher(19, 19, 11)
+ vcipherlast(16, 16, 12)
+ vcipherlast(17, 17, 12)
+ vcipherlast(18, 18, 12)
+ vcipherlast(19, 19, 12)
+
+#if BR_POWER8_LE
+ vperm(16, 16, 16, 15)
+ vperm(17, 17, 17, 15)
+ vperm(18, 18, 18, 15)
+ vperm(19, 19, 19, 15)
+#endif
+
+ /*
+ * Load next plaintext word and XOR with encrypted IV.
+ */
+ vxor(16, 20, 16)
+ vxor(17, 21, 17)
+ vxor(18, 22, 18)
+ vxor(19, 23, 19)
+ stxvw4x(48, %[cc0], %[buf])
+ stxvw4x(49, %[cc1], %[buf])
+ stxvw4x(50, %[cc2], %[buf])
+ stxvw4x(51, %[cc3], %[buf])
+
+ addi(%[buf], %[buf], 64)
+
+ /*
+ * Update IV.
+ */
+ vand(16, 24, 24)
+ vand(17, 25, 25)
+ vand(18, 26, 26)
+ vand(19, 27, 27)
+
+ bdnz(loop)
+
+: [cc0] "+b" (cc0), [cc1] "+b" (cc1), [cc2] "+b" (cc2), [cc3] "+b" (cc3),
+ [buf] "+b" (buf)
+: [sk] "b" (sk), [ivbuf] "b" (ivbuf), [num_blocks] "b" (num_blocks >> 2),
+ [ctrinc] "b" (ctrinc)
+#if BR_POWER8_LE
+ , [idx2be] "b" (idx2be)
+#endif
+: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9",
+ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19",
+ "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29",
+ "ctr", "memory"
+ );
+}
+
+static void
+ctr_256(const unsigned char *sk, const unsigned char *ivbuf,
+ unsigned char *buf, size_t num_blocks)
+{
+ long cc0, cc1, cc2, cc3;
+
+#if BR_POWER8_LE
+ static const uint32_t idx2be[] = {
+ 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
+ };
+#endif
+ static const uint32_t ctrinc[] = {
+ 0, 0, 0, 4
+ };
+
+ cc0 = 0;
+ cc1 = 16;
+ cc2 = 32;
+ cc3 = 48;
+ asm volatile (
+
+ /*
+ * Load subkeys into v0..v14
+ */
+ lxvw4x(32, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(33, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(34, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(35, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(36, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(37, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(38, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(39, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(40, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(41, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(42, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(43, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(44, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(45, %[cc0], %[sk])
+ addi(%[cc0], %[cc0], 16)
+ lxvw4x(46, %[cc0], %[sk])
+ li(%[cc0], 0)
+
+#if BR_POWER8_LE
+ /*
+ * v15 = constant for byteswapping words
+ */
+ lxvw4x(47, 0, %[idx2be])
+#endif
+ /*
+ * v28 = increment for IV counter.
+ */
+ lxvw4x(60, 0, %[ctrinc])
+
+ /*
+ * Load IV into v16..v19
+ */
+ lxvw4x(48, %[cc0], %[ivbuf])
+ lxvw4x(49, %[cc1], %[ivbuf])
+ lxvw4x(50, %[cc2], %[ivbuf])
+ lxvw4x(51, %[cc3], %[ivbuf])
+#if BR_POWER8_LE
+ vperm(16, 16, 16, 15)
+ vperm(17, 17, 17, 15)
+ vperm(18, 18, 18, 15)
+ vperm(19, 19, 19, 15)
+#endif
+
+ mtctr(%[num_blocks])
+ label(loop)
+ /*
+ * Compute next IV into v24..v27
+ */
+ vadduwm(24, 16, 28)
+ vadduwm(25, 17, 28)
+ vadduwm(26, 18, 28)
+ vadduwm(27, 19, 28)
+
+ /*
+ * Load next data blocks. We do this early on but we
+ * won't need them until IV encryption is done.
+ */
+ lxvw4x(52, %[cc0], %[buf])
+ lxvw4x(53, %[cc1], %[buf])
+ lxvw4x(54, %[cc2], %[buf])
+ lxvw4x(55, %[cc3], %[buf])
+
+ /*
+ * Encrypt the current IV.
+ */
+ vxor(16, 16, 0)
+ vxor(17, 17, 0)
+ vxor(18, 18, 0)
+ vxor(19, 19, 0)
+ vcipher(16, 16, 1)
+ vcipher(17, 17, 1)
+ vcipher(18, 18, 1)
+ vcipher(19, 19, 1)
+ vcipher(16, 16, 2)
+ vcipher(17, 17, 2)
+ vcipher(18, 18, 2)
+ vcipher(19, 19, 2)
+ vcipher(16, 16, 3)
+ vcipher(17, 17, 3)
+ vcipher(18, 18, 3)
+ vcipher(19, 19, 3)
+ vcipher(16, 16, 4)
+ vcipher(17, 17, 4)
+ vcipher(18, 18, 4)
+ vcipher(19, 19, 4)
+ vcipher(16, 16, 5)
+ vcipher(17, 17, 5)
+ vcipher(18, 18, 5)
+ vcipher(19, 19, 5)
+ vcipher(16, 16, 6)
+ vcipher(17, 17, 6)
+ vcipher(18, 18, 6)
+ vcipher(19, 19, 6)
+ vcipher(16, 16, 7)
+ vcipher(17, 17, 7)
+ vcipher(18, 18, 7)
+ vcipher(19, 19, 7)
+ vcipher(16, 16, 8)
+ vcipher(17, 17, 8)
+ vcipher(18, 18, 8)
+ vcipher(19, 19, 8)
+ vcipher(16, 16, 9)
+ vcipher(17, 17, 9)
+ vcipher(18, 18, 9)
+ vcipher(19, 19, 9)
+ vcipher(16, 16, 10)
+ vcipher(17, 17, 10)
+ vcipher(18, 18, 10)
+ vcipher(19, 19, 10)
+ vcipher(16, 16, 11)
+ vcipher(17, 17, 11)
+ vcipher(18, 18, 11)
+ vcipher(19, 19, 11)
+ vcipher(16, 16, 12)
+ vcipher(17, 17, 12)
+ vcipher(18, 18, 12)
+ vcipher(19, 19, 12)
+ vcipher(16, 16, 13)
+ vcipher(17, 17, 13)
+ vcipher(18, 18, 13)
+ vcipher(19, 19, 13)
+ vcipherlast(16, 16, 14)
+ vcipherlast(17, 17, 14)
+ vcipherlast(18, 18, 14)
+ vcipherlast(19, 19, 14)
+
+#if BR_POWER8_LE
+ vperm(16, 16, 16, 15)
+ vperm(17, 17, 17, 15)
+ vperm(18, 18, 18, 15)
+ vperm(19, 19, 19, 15)
+#endif
+
+ /*
+ * Load next plaintext word and XOR with encrypted IV.
+ */
+ vxor(16, 20, 16)
+ vxor(17, 21, 17)
+ vxor(18, 22, 18)
+ vxor(19, 23, 19)
+ stxvw4x(48, %[cc0], %[buf])
+ stxvw4x(49, %[cc1], %[buf])
+ stxvw4x(50, %[cc2], %[buf])
+ stxvw4x(51, %[cc3], %[buf])
+
+ addi(%[buf], %[buf], 64)
+
+ /*
+ * Update IV.
+ */
+ vand(16, 24, 24)
+ vand(17, 25, 25)
+ vand(18, 26, 26)
+ vand(19, 27, 27)
+
+ bdnz(loop)
+
+: [cc0] "+b" (cc0), [cc1] "+b" (cc1), [cc2] "+b" (cc2), [cc3] "+b" (cc3),
+ [buf] "+b" (buf)
+: [sk] "b" (sk), [ivbuf] "b" (ivbuf), [num_blocks] "b" (num_blocks >> 2),
+ [ctrinc] "b" (ctrinc)
+#if BR_POWER8_LE
+ , [idx2be] "b" (idx2be)
+#endif
+: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9",
+ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19",
+ "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29",
+ "ctr", "memory"
+ );
+}
+
+/* see bearssl_block.h */
+uint32_t
+br_aes_pwr8_ctr_run(const br_aes_pwr8_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len)
+{
+ unsigned char *buf;
+ unsigned char ivbuf[64];
+
+ buf = data;
+ memcpy(ivbuf + 0, iv, 12);
+ memcpy(ivbuf + 16, iv, 12);
+ memcpy(ivbuf + 32, iv, 12);
+ memcpy(ivbuf + 48, iv, 12);
+ if (len >= 64) {
+ br_enc32be(ivbuf + 12, cc + 0);
+ br_enc32be(ivbuf + 28, cc + 1);
+ br_enc32be(ivbuf + 44, cc + 2);
+ br_enc32be(ivbuf + 60, cc + 3);
+ switch (ctx->num_rounds) {
+ case 10:
+ ctr_128(ctx->skey.skni, ivbuf, buf,
+ (len >> 4) & ~(size_t)3);
+ break;
+ case 12:
+ ctr_192(ctx->skey.skni, ivbuf, buf,
+ (len >> 4) & ~(size_t)3);
+ break;
+ default:
+ ctr_256(ctx->skey.skni, ivbuf, buf,
+ (len >> 4) & ~(size_t)3);
+ break;
+ }
+ cc += (len >> 4) & ~(size_t)3;
+ buf += len & ~(size_t)63;
+ len &= 63;
+ }
+ if (len > 0) {
+ unsigned char tmp[64];
+
+ memcpy(tmp, buf, len);
+ memset(tmp + len, 0, (sizeof tmp) - len);
+ br_enc32be(ivbuf + 12, cc + 0);
+ br_enc32be(ivbuf + 28, cc + 1);
+ br_enc32be(ivbuf + 44, cc + 2);
+ br_enc32be(ivbuf + 60, cc + 3);
+ switch (ctx->num_rounds) {
+ case 10:
+ ctr_128(ctx->skey.skni, ivbuf, tmp, 4);
+ break;
+ case 12:
+ ctr_192(ctx->skey.skni, ivbuf, tmp, 4);
+ break;
+ default:
+ ctr_256(ctx->skey.skni, ivbuf, tmp, 4);
+ break;
+ }
+ memcpy(buf, tmp, len);
+ cc += (len + 15) >> 4;
+ }
+ return cc;
+}
+
+/* see bearssl_block.h */
+const br_block_ctr_class br_aes_pwr8_ctr_vtable = {
+ sizeof(br_aes_pwr8_ctr_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_ctr_class **, const void *, size_t))
+ &br_aes_pwr8_ctr_init,
+ (uint32_t (*)(const br_block_ctr_class *const *,
+ const void *, uint32_t, void *, size_t))
+ &br_aes_pwr8_ctr_run
+};
+
+/* see bearssl_block.h */
+const br_block_ctr_class *
+br_aes_pwr8_ctr_get_vtable(void)
+{
+ return br_aes_pwr8_supported() ? &br_aes_pwr8_ctr_vtable : NULL;
+}
+
+#else
+
+/* see bearssl_block.h */
+const br_block_ctr_class *
+br_aes_pwr8_ctr_get_vtable(void)
+{
+ return NULL;
+}
+
+#endif
diff --git a/contrib/bearssl/src/symcipher/aes_pwr8_ctrcbc.c b/contrib/bearssl/src/symcipher/aes_pwr8_ctrcbc.c
new file mode 100644
index 000000000000..a67d30b63a0b
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_pwr8_ctrcbc.c
@@ -0,0 +1,946 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BR_POWER_ASM_MACROS 1
+#include "inner.h"
+
+#if BR_POWER8
+
+/* see bearssl_block.h */
+const br_block_ctrcbc_class *
+br_aes_pwr8_ctrcbc_get_vtable(void)
+{
+ return br_aes_pwr8_supported() ? &br_aes_pwr8_ctrcbc_vtable : NULL;
+}
+
+/* see bearssl_block.h */
+void
+br_aes_pwr8_ctrcbc_init(br_aes_pwr8_ctrcbc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_pwr8_ctrcbc_vtable;
+ ctx->num_rounds = br_aes_pwr8_keysched(ctx->skey.skni, key, len);
+}
+
+/*
+ * Register conventions for CTR + CBC-MAC:
+ *
+ * AES subkeys are in registers 0 to 10/12/14 (depending on keys size)
+ * Register v15 contains the byteswap index register (little-endian only)
+ * Register v16 contains the CTR counter value
+ * Register v17 contains the CBC-MAC current value
+ * Registers v18 to v27 are scratch
+ * Counter increment uses v28, v29 and v30
+ *
+ * For CTR alone:
+ *
+ * AES subkeys are in registers 0 to 10/12/14 (depending on keys size)
+ * Register v15 contains the byteswap index register (little-endian only)
+ * Registers v16 to v19 contain the CTR counter values (four blocks)
+ * Registers v20 to v27 are scratch
+ * Counter increment uses v28, v29 and v30
+ */
+
+#define LOAD_SUBKEYS_128 \
+ lxvw4x(32, %[cc], %[sk]) \
+ addi(%[cc], %[cc], 16) \
+ lxvw4x(33, %[cc], %[sk]) \
+ addi(%[cc], %[cc], 16) \
+ lxvw4x(34, %[cc], %[sk]) \
+ addi(%[cc], %[cc], 16) \
+ lxvw4x(35, %[cc], %[sk]) \
+ addi(%[cc], %[cc], 16) \
+ lxvw4x(36, %[cc], %[sk]) \
+ addi(%[cc], %[cc], 16) \
+ lxvw4x(37, %[cc], %[sk]) \
+ addi(%[cc], %[cc], 16) \
+ lxvw4x(38, %[cc], %[sk]) \
+ addi(%[cc], %[cc], 16) \
+ lxvw4x(39, %[cc], %[sk]) \
+ addi(%[cc], %[cc], 16) \
+ lxvw4x(40, %[cc], %[sk]) \
+ addi(%[cc], %[cc], 16) \
+ lxvw4x(41, %[cc], %[sk]) \
+ addi(%[cc], %[cc], 16) \
+ lxvw4x(42, %[cc], %[sk])
+
+#define LOAD_SUBKEYS_192 \
+ LOAD_SUBKEYS_128 \
+ addi(%[cc], %[cc], 16) \
+ lxvw4x(43, %[cc], %[sk]) \
+ addi(%[cc], %[cc], 16) \
+ lxvw4x(44, %[cc], %[sk])
+
+#define LOAD_SUBKEYS_256 \
+ LOAD_SUBKEYS_192 \
+ addi(%[cc], %[cc], 16) \
+ lxvw4x(45, %[cc], %[sk]) \
+ addi(%[cc], %[cc], 16) \
+ lxvw4x(46, %[cc], %[sk])
+
+#define BLOCK_ENCRYPT_128(x) \
+ vxor(x, x, 0) \
+ vcipher(x, x, 1) \
+ vcipher(x, x, 2) \
+ vcipher(x, x, 3) \
+ vcipher(x, x, 4) \
+ vcipher(x, x, 5) \
+ vcipher(x, x, 6) \
+ vcipher(x, x, 7) \
+ vcipher(x, x, 8) \
+ vcipher(x, x, 9) \
+ vcipherlast(x, x, 10)
+
+#define BLOCK_ENCRYPT_192(x) \
+ vxor(x, x, 0) \
+ vcipher(x, x, 1) \
+ vcipher(x, x, 2) \
+ vcipher(x, x, 3) \
+ vcipher(x, x, 4) \
+ vcipher(x, x, 5) \
+ vcipher(x, x, 6) \
+ vcipher(x, x, 7) \
+ vcipher(x, x, 8) \
+ vcipher(x, x, 9) \
+ vcipher(x, x, 10) \
+ vcipher(x, x, 11) \
+ vcipherlast(x, x, 12)
+
+#define BLOCK_ENCRYPT_256(x) \
+ vxor(x, x, 0) \
+ vcipher(x, x, 1) \
+ vcipher(x, x, 2) \
+ vcipher(x, x, 3) \
+ vcipher(x, x, 4) \
+ vcipher(x, x, 5) \
+ vcipher(x, x, 6) \
+ vcipher(x, x, 7) \
+ vcipher(x, x, 8) \
+ vcipher(x, x, 9) \
+ vcipher(x, x, 10) \
+ vcipher(x, x, 11) \
+ vcipher(x, x, 12) \
+ vcipher(x, x, 13) \
+ vcipherlast(x, x, 14)
+
+#define BLOCK_ENCRYPT_X2_128(x, y) \
+ vxor(x, x, 0) \
+ vxor(y, y, 0) \
+ vcipher(x, x, 1) \
+ vcipher(y, y, 1) \
+ vcipher(x, x, 2) \
+ vcipher(y, y, 2) \
+ vcipher(x, x, 3) \
+ vcipher(y, y, 3) \
+ vcipher(x, x, 4) \
+ vcipher(y, y, 4) \
+ vcipher(x, x, 5) \
+ vcipher(y, y, 5) \
+ vcipher(x, x, 6) \
+ vcipher(y, y, 6) \
+ vcipher(x, x, 7) \
+ vcipher(y, y, 7) \
+ vcipher(x, x, 8) \
+ vcipher(y, y, 8) \
+ vcipher(x, x, 9) \
+ vcipher(y, y, 9) \
+ vcipherlast(x, x, 10) \
+ vcipherlast(y, y, 10)
+
+#define BLOCK_ENCRYPT_X2_192(x, y) \
+ vxor(x, x, 0) \
+ vxor(y, y, 0) \
+ vcipher(x, x, 1) \
+ vcipher(y, y, 1) \
+ vcipher(x, x, 2) \
+ vcipher(y, y, 2) \
+ vcipher(x, x, 3) \
+ vcipher(y, y, 3) \
+ vcipher(x, x, 4) \
+ vcipher(y, y, 4) \
+ vcipher(x, x, 5) \
+ vcipher(y, y, 5) \
+ vcipher(x, x, 6) \
+ vcipher(y, y, 6) \
+ vcipher(x, x, 7) \
+ vcipher(y, y, 7) \
+ vcipher(x, x, 8) \
+ vcipher(y, y, 8) \
+ vcipher(x, x, 9) \
+ vcipher(y, y, 9) \
+ vcipher(x, x, 10) \
+ vcipher(y, y, 10) \
+ vcipher(x, x, 11) \
+ vcipher(y, y, 11) \
+ vcipherlast(x, x, 12) \
+ vcipherlast(y, y, 12)
+
+#define BLOCK_ENCRYPT_X2_256(x, y) \
+ vxor(x, x, 0) \
+ vxor(y, y, 0) \
+ vcipher(x, x, 1) \
+ vcipher(y, y, 1) \
+ vcipher(x, x, 2) \
+ vcipher(y, y, 2) \
+ vcipher(x, x, 3) \
+ vcipher(y, y, 3) \
+ vcipher(x, x, 4) \
+ vcipher(y, y, 4) \
+ vcipher(x, x, 5) \
+ vcipher(y, y, 5) \
+ vcipher(x, x, 6) \
+ vcipher(y, y, 6) \
+ vcipher(x, x, 7) \
+ vcipher(y, y, 7) \
+ vcipher(x, x, 8) \
+ vcipher(y, y, 8) \
+ vcipher(x, x, 9) \
+ vcipher(y, y, 9) \
+ vcipher(x, x, 10) \
+ vcipher(y, y, 10) \
+ vcipher(x, x, 11) \
+ vcipher(y, y, 11) \
+ vcipher(x, x, 12) \
+ vcipher(y, y, 12) \
+ vcipher(x, x, 13) \
+ vcipher(y, y, 13) \
+ vcipherlast(x, x, 14) \
+ vcipherlast(y, y, 14)
+
+#define BLOCK_ENCRYPT_X4_128(x0, x1, x2, x3) \
+ vxor(x0, x0, 0) \
+ vxor(x1, x1, 0) \
+ vxor(x2, x2, 0) \
+ vxor(x3, x3, 0) \
+ vcipher(x0, x0, 1) \
+ vcipher(x1, x1, 1) \
+ vcipher(x2, x2, 1) \
+ vcipher(x3, x3, 1) \
+ vcipher(x0, x0, 2) \
+ vcipher(x1, x1, 2) \
+ vcipher(x2, x2, 2) \
+ vcipher(x3, x3, 2) \
+ vcipher(x0, x0, 3) \
+ vcipher(x1, x1, 3) \
+ vcipher(x2, x2, 3) \
+ vcipher(x3, x3, 3) \
+ vcipher(x0, x0, 4) \
+ vcipher(x1, x1, 4) \
+ vcipher(x2, x2, 4) \
+ vcipher(x3, x3, 4) \
+ vcipher(x0, x0, 5) \
+ vcipher(x1, x1, 5) \
+ vcipher(x2, x2, 5) \
+ vcipher(x3, x3, 5) \
+ vcipher(x0, x0, 6) \
+ vcipher(x1, x1, 6) \
+ vcipher(x2, x2, 6) \
+ vcipher(x3, x3, 6) \
+ vcipher(x0, x0, 7) \
+ vcipher(x1, x1, 7) \
+ vcipher(x2, x2, 7) \
+ vcipher(x3, x3, 7) \
+ vcipher(x0, x0, 8) \
+ vcipher(x1, x1, 8) \
+ vcipher(x2, x2, 8) \
+ vcipher(x3, x3, 8) \
+ vcipher(x0, x0, 9) \
+ vcipher(x1, x1, 9) \
+ vcipher(x2, x2, 9) \
+ vcipher(x3, x3, 9) \
+ vcipherlast(x0, x0, 10) \
+ vcipherlast(x1, x1, 10) \
+ vcipherlast(x2, x2, 10) \
+ vcipherlast(x3, x3, 10)
+
+#define BLOCK_ENCRYPT_X4_192(x0, x1, x2, x3) \
+ vxor(x0, x0, 0) \
+ vxor(x1, x1, 0) \
+ vxor(x2, x2, 0) \
+ vxor(x3, x3, 0) \
+ vcipher(x0, x0, 1) \
+ vcipher(x1, x1, 1) \
+ vcipher(x2, x2, 1) \
+ vcipher(x3, x3, 1) \
+ vcipher(x0, x0, 2) \
+ vcipher(x1, x1, 2) \
+ vcipher(x2, x2, 2) \
+ vcipher(x3, x3, 2) \
+ vcipher(x0, x0, 3) \
+ vcipher(x1, x1, 3) \
+ vcipher(x2, x2, 3) \
+ vcipher(x3, x3, 3) \
+ vcipher(x0, x0, 4) \
+ vcipher(x1, x1, 4) \
+ vcipher(x2, x2, 4) \
+ vcipher(x3, x3, 4) \
+ vcipher(x0, x0, 5) \
+ vcipher(x1, x1, 5) \
+ vcipher(x2, x2, 5) \
+ vcipher(x3, x3, 5) \
+ vcipher(x0, x0, 6) \
+ vcipher(x1, x1, 6) \
+ vcipher(x2, x2, 6) \
+ vcipher(x3, x3, 6) \
+ vcipher(x0, x0, 7) \
+ vcipher(x1, x1, 7) \
+ vcipher(x2, x2, 7) \
+ vcipher(x3, x3, 7) \
+ vcipher(x0, x0, 8) \
+ vcipher(x1, x1, 8) \
+ vcipher(x2, x2, 8) \
+ vcipher(x3, x3, 8) \
+ vcipher(x0, x0, 9) \
+ vcipher(x1, x1, 9) \
+ vcipher(x2, x2, 9) \
+ vcipher(x3, x3, 9) \
+ vcipher(x0, x0, 10) \
+ vcipher(x1, x1, 10) \
+ vcipher(x2, x2, 10) \
+ vcipher(x3, x3, 10) \
+ vcipher(x0, x0, 11) \
+ vcipher(x1, x1, 11) \
+ vcipher(x2, x2, 11) \
+ vcipher(x3, x3, 11) \
+ vcipherlast(x0, x0, 12) \
+ vcipherlast(x1, x1, 12) \
+ vcipherlast(x2, x2, 12) \
+ vcipherlast(x3, x3, 12)
+
+#define BLOCK_ENCRYPT_X4_256(x0, x1, x2, x3) \
+ vxor(x0, x0, 0) \
+ vxor(x1, x1, 0) \
+ vxor(x2, x2, 0) \
+ vxor(x3, x3, 0) \
+ vcipher(x0, x0, 1) \
+ vcipher(x1, x1, 1) \
+ vcipher(x2, x2, 1) \
+ vcipher(x3, x3, 1) \
+ vcipher(x0, x0, 2) \
+ vcipher(x1, x1, 2) \
+ vcipher(x2, x2, 2) \
+ vcipher(x3, x3, 2) \
+ vcipher(x0, x0, 3) \
+ vcipher(x1, x1, 3) \
+ vcipher(x2, x2, 3) \
+ vcipher(x3, x3, 3) \
+ vcipher(x0, x0, 4) \
+ vcipher(x1, x1, 4) \
+ vcipher(x2, x2, 4) \
+ vcipher(x3, x3, 4) \
+ vcipher(x0, x0, 5) \
+ vcipher(x1, x1, 5) \
+ vcipher(x2, x2, 5) \
+ vcipher(x3, x3, 5) \
+ vcipher(x0, x0, 6) \
+ vcipher(x1, x1, 6) \
+ vcipher(x2, x2, 6) \
+ vcipher(x3, x3, 6) \
+ vcipher(x0, x0, 7) \
+ vcipher(x1, x1, 7) \
+ vcipher(x2, x2, 7) \
+ vcipher(x3, x3, 7) \
+ vcipher(x0, x0, 8) \
+ vcipher(x1, x1, 8) \
+ vcipher(x2, x2, 8) \
+ vcipher(x3, x3, 8) \
+ vcipher(x0, x0, 9) \
+ vcipher(x1, x1, 9) \
+ vcipher(x2, x2, 9) \
+ vcipher(x3, x3, 9) \
+ vcipher(x0, x0, 10) \
+ vcipher(x1, x1, 10) \
+ vcipher(x2, x2, 10) \
+ vcipher(x3, x3, 10) \
+ vcipher(x0, x0, 11) \
+ vcipher(x1, x1, 11) \
+ vcipher(x2, x2, 11) \
+ vcipher(x3, x3, 11) \
+ vcipher(x0, x0, 12) \
+ vcipher(x1, x1, 12) \
+ vcipher(x2, x2, 12) \
+ vcipher(x3, x3, 12) \
+ vcipher(x0, x0, 13) \
+ vcipher(x1, x1, 13) \
+ vcipher(x2, x2, 13) \
+ vcipher(x3, x3, 13) \
+ vcipherlast(x0, x0, 14) \
+ vcipherlast(x1, x1, 14) \
+ vcipherlast(x2, x2, 14) \
+ vcipherlast(x3, x3, 14)
+
+#if BR_POWER8_LE
+static const uint32_t idx2be[] = {
+ 0x03020100, 0x07060504, 0x0B0A0908, 0x0F0E0D0C
+};
+#define BYTESWAP_INIT lxvw4x(47, 0, %[idx2be])
+#define BYTESWAP(x) vperm(x, x, x, 15)
+#define BYTESWAPX(d, s) vperm(d, s, s, 15)
+#define BYTESWAP_REG , [idx2be] "b" (idx2be)
+#else
+#define BYTESWAP_INIT
+#define BYTESWAP(x)
+#define BYTESWAPX(d, s) vand(d, s, s)
+#define BYTESWAP_REG
+#endif
+
+static const uint32_t ctrinc[] = {
+ 0, 0, 0, 1
+};
+static const uint32_t ctrinc_x4[] = {
+ 0, 0, 0, 4
+};
+#define INCR_128_INIT lxvw4x(60, 0, %[ctrinc])
+#define INCR_128_X4_INIT lxvw4x(60, 0, %[ctrinc_x4])
+#define INCR_128(d, s) \
+ vaddcuw(29, s, 28) \
+ vadduwm(d, s, 28) \
+ vsldoi(30, 29, 29, 4) \
+ vaddcuw(29, d, 30) \
+ vadduwm(d, d, 30) \
+ vsldoi(30, 29, 29, 4) \
+ vaddcuw(29, d, 30) \
+ vadduwm(d, d, 30) \
+ vsldoi(30, 29, 29, 4) \
+ vadduwm(d, d, 30)
+
+#define MKCTR(size) \
+static void \
+ctr_ ## size(const unsigned char *sk, \
+ unsigned char *ctrbuf, unsigned char *buf, size_t num_blocks_x4) \
+{ \
+ long cc, cc0, cc1, cc2, cc3; \
+ \
+ cc = 0; \
+ cc0 = 0; \
+ cc1 = 16; \
+ cc2 = 32; \
+ cc3 = 48; \
+ asm volatile ( \
+ \
+ /* \
+ * Load subkeys into v0..v10 \
+ */ \
+ LOAD_SUBKEYS_ ## size \
+ li(%[cc], 0) \
+ \
+ BYTESWAP_INIT \
+ INCR_128_X4_INIT \
+ \
+ /* \
+ * Load current CTR counters into v16 to v19. \
+ */ \
+ lxvw4x(48, %[cc0], %[ctrbuf]) \
+ lxvw4x(49, %[cc1], %[ctrbuf]) \
+ lxvw4x(50, %[cc2], %[ctrbuf]) \
+ lxvw4x(51, %[cc3], %[ctrbuf]) \
+ BYTESWAP(16) \
+ BYTESWAP(17) \
+ BYTESWAP(18) \
+ BYTESWAP(19) \
+ \
+ mtctr(%[num_blocks_x4]) \
+ \
+ label(loop) \
+ /* \
+ * Compute next counter values into v20..v23. \
+ */ \
+ INCR_128(20, 16) \
+ INCR_128(21, 17) \
+ INCR_128(22, 18) \
+ INCR_128(23, 19) \
+ \
+ /* \
+ * Encrypt counter values and XOR into next data blocks. \
+ */ \
+ lxvw4x(56, %[cc0], %[buf]) \
+ lxvw4x(57, %[cc1], %[buf]) \
+ lxvw4x(58, %[cc2], %[buf]) \
+ lxvw4x(59, %[cc3], %[buf]) \
+ BYTESWAP(24) \
+ BYTESWAP(25) \
+ BYTESWAP(26) \
+ BYTESWAP(27) \
+ BLOCK_ENCRYPT_X4_ ## size(16, 17, 18, 19) \
+ vxor(16, 16, 24) \
+ vxor(17, 17, 25) \
+ vxor(18, 18, 26) \
+ vxor(19, 19, 27) \
+ BYTESWAP(16) \
+ BYTESWAP(17) \
+ BYTESWAP(18) \
+ BYTESWAP(19) \
+ stxvw4x(48, %[cc0], %[buf]) \
+ stxvw4x(49, %[cc1], %[buf]) \
+ stxvw4x(50, %[cc2], %[buf]) \
+ stxvw4x(51, %[cc3], %[buf]) \
+ \
+ /* \
+ * Update counters and data pointer. \
+ */ \
+ vand(16, 20, 20) \
+ vand(17, 21, 21) \
+ vand(18, 22, 22) \
+ vand(19, 23, 23) \
+ addi(%[buf], %[buf], 64) \
+ \
+ bdnz(loop) \
+ \
+ /* \
+ * Write back new counter values. \
+ */ \
+ BYTESWAP(16) \
+ BYTESWAP(17) \
+ BYTESWAP(18) \
+ BYTESWAP(19) \
+ stxvw4x(48, %[cc0], %[ctrbuf]) \
+ stxvw4x(49, %[cc1], %[ctrbuf]) \
+ stxvw4x(50, %[cc2], %[ctrbuf]) \
+ stxvw4x(51, %[cc3], %[ctrbuf]) \
+ \
+: [cc] "+b" (cc), [buf] "+b" (buf), \
+ [cc0] "+b" (cc0), [cc1] "+b" (cc1), [cc2] "+b" (cc2), [cc3] "+b" (cc3) \
+: [sk] "b" (sk), [ctrbuf] "b" (ctrbuf), \
+ [num_blocks_x4] "b" (num_blocks_x4), [ctrinc_x4] "b" (ctrinc_x4) \
+ BYTESWAP_REG \
+: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", \
+ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", \
+ "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", \
+ "v30", "ctr", "memory" \
+ ); \
+}
+
+MKCTR(128)
+MKCTR(192)
+MKCTR(256)
+
+#define MKCBCMAC(size) \
+static void \
+cbcmac_ ## size(const unsigned char *sk, \
+ unsigned char *cbcmac, const unsigned char *buf, size_t num_blocks) \
+{ \
+ long cc; \
+ \
+ cc = 0; \
+ asm volatile ( \
+ \
+ /* \
+ * Load subkeys into v0..v10 \
+ */ \
+ LOAD_SUBKEYS_ ## size \
+ li(%[cc], 0) \
+ \
+ BYTESWAP_INIT \
+ \
+ /* \
+ * Load current CBC-MAC value into v16. \
+ */ \
+ lxvw4x(48, %[cc], %[cbcmac]) \
+ BYTESWAP(16) \
+ \
+ mtctr(%[num_blocks]) \
+ \
+ label(loop) \
+ /* \
+ * Load next block, XOR into current CBC-MAC value, \
+ * and then encrypt it. \
+ */ \
+ lxvw4x(49, %[cc], %[buf]) \
+ BYTESWAP(17) \
+ vxor(16, 16, 17) \
+ BLOCK_ENCRYPT_ ## size(16) \
+ addi(%[buf], %[buf], 16) \
+ \
+ bdnz(loop) \
+ \
+ /* \
+ * Write back new CBC-MAC value. \
+ */ \
+ BYTESWAP(16) \
+ stxvw4x(48, %[cc], %[cbcmac]) \
+ \
+: [cc] "+b" (cc), [buf] "+b" (buf) \
+: [sk] "b" (sk), [cbcmac] "b" (cbcmac), [num_blocks] "b" (num_blocks) \
+ BYTESWAP_REG \
+: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", \
+ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", \
+ "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", \
+ "v30", "ctr", "memory" \
+ ); \
+}
+
+MKCBCMAC(128)
+MKCBCMAC(192)
+MKCBCMAC(256)
+
+#define MKENCRYPT(size) \
+static void \
+ctrcbc_ ## size ## _encrypt(const unsigned char *sk, \
+ unsigned char *ctr, unsigned char *cbcmac, unsigned char *buf, \
+ size_t num_blocks) \
+{ \
+ long cc; \
+ \
+ cc = 0; \
+ asm volatile ( \
+ \
+ /* \
+ * Load subkeys into v0..v10 \
+ */ \
+ LOAD_SUBKEYS_ ## size \
+ li(%[cc], 0) \
+ \
+ BYTESWAP_INIT \
+ INCR_128_INIT \
+ \
+ /* \
+ * Load current CTR counter into v16, and current \
+ * CBC-MAC IV into v17. \
+ */ \
+ lxvw4x(48, %[cc], %[ctr]) \
+ lxvw4x(49, %[cc], %[cbcmac]) \
+ BYTESWAP(16) \
+ BYTESWAP(17) \
+ \
+ /* \
+ * At each iteration, we do two parallel encryption: \
+ * - new counter value for encryption of the next block; \
+ * - CBC-MAC over the previous encrypted block. \
+ * Thus, each plaintext block implies two AES instances, \
+ * over two successive iterations. This requires a single \
+ * counter encryption before the loop, and a single \
+ * CBC-MAC encryption after the loop. \
+ */ \
+ \
+ /* \
+ * Encrypt first block (into v20). \
+ */ \
+ lxvw4x(52, %[cc], %[buf]) \
+ BYTESWAP(20) \
+ INCR_128(22, 16) \
+ BLOCK_ENCRYPT_ ## size(16) \
+ vxor(20, 20, 16) \
+ BYTESWAPX(21, 20) \
+ stxvw4x(53, %[cc], %[buf]) \
+ vand(16, 22, 22) \
+ addi(%[buf], %[buf], 16) \
+ \
+ /* \
+ * Load loop counter; skip the loop if there is only \
+ * one block in total (already handled by the boundary \
+ * conditions). \
+ */ \
+ mtctr(%[num_blocks]) \
+ bdz(fastexit) \
+ \
+ label(loop) \
+ /* \
+ * Upon loop entry: \
+ * v16 counter value for next block \
+ * v17 current CBC-MAC value \
+ * v20 encrypted previous block \
+ */ \
+ vxor(17, 17, 20) \
+ INCR_128(22, 16) \
+ lxvw4x(52, %[cc], %[buf]) \
+ BYTESWAP(20) \
+ BLOCK_ENCRYPT_X2_ ## size(16, 17) \
+ vxor(20, 20, 16) \
+ BYTESWAPX(21, 20) \
+ stxvw4x(53, %[cc], %[buf]) \
+ addi(%[buf], %[buf], 16) \
+ vand(16, 22, 22) \
+ \
+ bdnz(loop) \
+ \
+ label(fastexit) \
+ vxor(17, 17, 20) \
+ BLOCK_ENCRYPT_ ## size(17) \
+ BYTESWAP(16) \
+ BYTESWAP(17) \
+ stxvw4x(48, %[cc], %[ctr]) \
+ stxvw4x(49, %[cc], %[cbcmac]) \
+ \
+: [cc] "+b" (cc), [buf] "+b" (buf) \
+: [sk] "b" (sk), [ctr] "b" (ctr), [cbcmac] "b" (cbcmac), \
+ [num_blocks] "b" (num_blocks), [ctrinc] "b" (ctrinc) \
+ BYTESWAP_REG \
+: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", \
+ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", \
+ "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", \
+ "v30", "ctr", "memory" \
+ ); \
+}
+
+MKENCRYPT(128)
+MKENCRYPT(192)
+MKENCRYPT(256)
+
+#define MKDECRYPT(size) \
+static void \
+ctrcbc_ ## size ## _decrypt(const unsigned char *sk, \
+ unsigned char *ctr, unsigned char *cbcmac, unsigned char *buf, \
+ size_t num_blocks) \
+{ \
+ long cc; \
+ \
+ cc = 0; \
+ asm volatile ( \
+ \
+ /* \
+ * Load subkeys into v0..v10 \
+ */ \
+ LOAD_SUBKEYS_ ## size \
+ li(%[cc], 0) \
+ \
+ BYTESWAP_INIT \
+ INCR_128_INIT \
+ \
+ /* \
+ * Load current CTR counter into v16, and current \
+ * CBC-MAC IV into v17. \
+ */ \
+ lxvw4x(48, %[cc], %[ctr]) \
+ lxvw4x(49, %[cc], %[cbcmac]) \
+ BYTESWAP(16) \
+ BYTESWAP(17) \
+ \
+ /* \
+ * At each iteration, we do two parallel encryption: \
+ * - new counter value for decryption of the next block; \
+ * - CBC-MAC over the next encrypted block. \
+ * Each iteration performs the two AES instances related \
+ * to the current block; there is thus no need for some \
+ * extra pre-loop and post-loop work as in encryption. \
+ */ \
+ \
+ mtctr(%[num_blocks]) \
+ \
+ label(loop) \
+ /* \
+ * Upon loop entry: \
+ * v16 counter value for next block \
+ * v17 current CBC-MAC value \
+ */ \
+ lxvw4x(52, %[cc], %[buf]) \
+ BYTESWAP(20) \
+ vxor(17, 17, 20) \
+ INCR_128(22, 16) \
+ BLOCK_ENCRYPT_X2_ ## size(16, 17) \
+ vxor(20, 20, 16) \
+ BYTESWAPX(21, 20) \
+ stxvw4x(53, %[cc], %[buf]) \
+ addi(%[buf], %[buf], 16) \
+ vand(16, 22, 22) \
+ \
+ bdnz(loop) \
+ \
+ /* \
+ * Store back counter and CBC-MAC value. \
+ */ \
+ BYTESWAP(16) \
+ BYTESWAP(17) \
+ stxvw4x(48, %[cc], %[ctr]) \
+ stxvw4x(49, %[cc], %[cbcmac]) \
+ \
+: [cc] "+b" (cc), [buf] "+b" (buf) \
+: [sk] "b" (sk), [ctr] "b" (ctr), [cbcmac] "b" (cbcmac), \
+ [num_blocks] "b" (num_blocks), [ctrinc] "b" (ctrinc) \
+ BYTESWAP_REG \
+: "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", "v8", "v9", \
+ "v10", "v11", "v12", "v13", "v14", "v15", "v16", "v17", "v18", "v19", \
+ "v20", "v21", "v22", "v23", "v24", "v25", "v26", "v27", "v28", "v29", \
+ "v30", "ctr", "memory" \
+ ); \
+}
+
+MKDECRYPT(128)
+MKDECRYPT(192)
+MKDECRYPT(256)
+
+/* see bearssl_block.h */
+void
+br_aes_pwr8_ctrcbc_encrypt(const br_aes_pwr8_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len)
+{
+ if (len == 0) {
+ return;
+ }
+ switch (ctx->num_rounds) {
+ case 10:
+ ctrcbc_128_encrypt(ctx->skey.skni, ctr, cbcmac, data, len >> 4);
+ break;
+ case 12:
+ ctrcbc_192_encrypt(ctx->skey.skni, ctr, cbcmac, data, len >> 4);
+ break;
+ default:
+ ctrcbc_256_encrypt(ctx->skey.skni, ctr, cbcmac, data, len >> 4);
+ break;
+ }
+}
+
+/* see bearssl_block.h */
+void
+br_aes_pwr8_ctrcbc_decrypt(const br_aes_pwr8_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len)
+{
+ if (len == 0) {
+ return;
+ }
+ switch (ctx->num_rounds) {
+ case 10:
+ ctrcbc_128_decrypt(ctx->skey.skni, ctr, cbcmac, data, len >> 4);
+ break;
+ case 12:
+ ctrcbc_192_decrypt(ctx->skey.skni, ctr, cbcmac, data, len >> 4);
+ break;
+ default:
+ ctrcbc_256_decrypt(ctx->skey.skni, ctr, cbcmac, data, len >> 4);
+ break;
+ }
+}
+
+static inline void
+incr_ctr(void *dst, const void *src)
+{
+ uint64_t hi, lo;
+
+ hi = br_dec64be(src);
+ lo = br_dec64be((const unsigned char *)src + 8);
+ lo ++;
+ hi += ((lo | -lo) >> 63) ^ (uint64_t)1;
+ br_enc64be(dst, hi);
+ br_enc64be((unsigned char *)dst + 8, lo);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_pwr8_ctrcbc_ctr(const br_aes_pwr8_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len)
+{
+ unsigned char ctrbuf[64];
+
+ memcpy(ctrbuf, ctr, 16);
+ incr_ctr(ctrbuf + 16, ctrbuf);
+ incr_ctr(ctrbuf + 32, ctrbuf + 16);
+ incr_ctr(ctrbuf + 48, ctrbuf + 32);
+ if (len >= 64) {
+ switch (ctx->num_rounds) {
+ case 10:
+ ctr_128(ctx->skey.skni, ctrbuf, data, len >> 6);
+ break;
+ case 12:
+ ctr_192(ctx->skey.skni, ctrbuf, data, len >> 6);
+ break;
+ default:
+ ctr_256(ctx->skey.skni, ctrbuf, data, len >> 6);
+ break;
+ }
+ data = (unsigned char *)data + (len & ~(size_t)63);
+ len &= 63;
+ }
+ if (len > 0) {
+ unsigned char tmp[64];
+
+ if (len >= 32) {
+ if (len >= 48) {
+ memcpy(ctr, ctrbuf + 48, 16);
+ } else {
+ memcpy(ctr, ctrbuf + 32, 16);
+ }
+ } else {
+ if (len >= 16) {
+ memcpy(ctr, ctrbuf + 16, 16);
+ }
+ }
+ memcpy(tmp, data, len);
+ memset(tmp + len, 0, (sizeof tmp) - len);
+ switch (ctx->num_rounds) {
+ case 10:
+ ctr_128(ctx->skey.skni, ctrbuf, tmp, 1);
+ break;
+ case 12:
+ ctr_192(ctx->skey.skni, ctrbuf, tmp, 1);
+ break;
+ default:
+ ctr_256(ctx->skey.skni, ctrbuf, tmp, 1);
+ break;
+ }
+ memcpy(data, tmp, len);
+ } else {
+ memcpy(ctr, ctrbuf, 16);
+ }
+}
+
+/* see bearssl_block.h */
+void
+br_aes_pwr8_ctrcbc_mac(const br_aes_pwr8_ctrcbc_keys *ctx,
+ void *cbcmac, const void *data, size_t len)
+{
+ if (len > 0) {
+ switch (ctx->num_rounds) {
+ case 10:
+ cbcmac_128(ctx->skey.skni, cbcmac, data, len >> 4);
+ break;
+ case 12:
+ cbcmac_192(ctx->skey.skni, cbcmac, data, len >> 4);
+ break;
+ default:
+ cbcmac_256(ctx->skey.skni, cbcmac, data, len >> 4);
+ break;
+ }
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_ctrcbc_class br_aes_pwr8_ctrcbc_vtable = {
+ sizeof(br_aes_pwr8_ctrcbc_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_ctrcbc_class **, const void *, size_t))
+ &br_aes_pwr8_ctrcbc_init,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, void *, size_t))
+ &br_aes_pwr8_ctrcbc_encrypt,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, void *, size_t))
+ &br_aes_pwr8_ctrcbc_decrypt,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, size_t))
+ &br_aes_pwr8_ctrcbc_ctr,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, const void *, size_t))
+ &br_aes_pwr8_ctrcbc_mac
+};
+
+#else
+
+/* see bearssl_block.h */
+const br_block_ctrcbc_class *
+br_aes_pwr8_ctrcbc_get_vtable(void)
+{
+ return NULL;
+}
+
+#endif
diff --git a/contrib/bearssl/src/symcipher/aes_small_cbcdec.c b/contrib/bearssl/src/symcipher/aes_small_cbcdec.c
new file mode 100644
index 000000000000..8567244b5811
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_small_cbcdec.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_aes_small_cbcdec_init(br_aes_small_cbcdec_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_small_cbcdec_vtable;
+ ctx->num_rounds = br_aes_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_small_cbcdec_run(const br_aes_small_cbcdec_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+
+ ivbuf = iv;
+ buf = data;
+ while (len > 0) {
+ unsigned char tmp[16];
+ int i;
+
+ memcpy(tmp, buf, 16);
+ br_aes_small_decrypt(ctx->num_rounds, ctx->skey, buf);
+ for (i = 0; i < 16; i ++) {
+ buf[i] ^= ivbuf[i];
+ }
+ memcpy(ivbuf, tmp, 16);
+ buf += 16;
+ len -= 16;
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class br_aes_small_cbcdec_vtable = {
+ sizeof(br_aes_small_cbcdec_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcdec_class **, const void *, size_t))
+ &br_aes_small_cbcdec_init,
+ (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t))
+ &br_aes_small_cbcdec_run
+};
diff --git a/contrib/bearssl/src/symcipher/aes_small_cbcenc.c b/contrib/bearssl/src/symcipher/aes_small_cbcenc.c
new file mode 100644
index 000000000000..0dc2910aa254
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_small_cbcenc.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_aes_small_cbcenc_init(br_aes_small_cbcenc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_small_cbcenc_vtable;
+ ctx->num_rounds = br_aes_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_small_cbcenc_run(const br_aes_small_cbcenc_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+
+ ivbuf = iv;
+ buf = data;
+ while (len > 0) {
+ int i;
+
+ for (i = 0; i < 16; i ++) {
+ buf[i] ^= ivbuf[i];
+ }
+ br_aes_small_encrypt(ctx->num_rounds, ctx->skey, buf);
+ memcpy(ivbuf, buf, 16);
+ buf += 16;
+ len -= 16;
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class br_aes_small_cbcenc_vtable = {
+ sizeof(br_aes_small_cbcenc_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcenc_class **, const void *, size_t))
+ &br_aes_small_cbcenc_init,
+ (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t))
+ &br_aes_small_cbcenc_run
+};
diff --git a/contrib/bearssl/src/symcipher/aes_small_ctr.c b/contrib/bearssl/src/symcipher/aes_small_ctr.c
new file mode 100644
index 000000000000..d5d371c6c18a
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_small_ctr.c
@@ -0,0 +1,84 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_aes_small_ctr_init(br_aes_small_ctr_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_small_ctr_vtable;
+ ctx->num_rounds = br_aes_keysched(ctx->skey, key, len);
+}
+
+static void
+xorbuf(void *dst, const void *src, size_t len)
+{
+ unsigned char *d;
+ const unsigned char *s;
+
+ d = dst;
+ s = src;
+ while (len -- > 0) {
+ *d ++ ^= *s ++;
+ }
+}
+
+/* see bearssl_block.h */
+uint32_t
+br_aes_small_ctr_run(const br_aes_small_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len)
+{
+ unsigned char *buf;
+
+ buf = data;
+ while (len > 0) {
+ unsigned char tmp[16];
+
+ memcpy(tmp, iv, 12);
+ br_enc32be(tmp + 12, cc ++);
+ br_aes_small_encrypt(ctx->num_rounds, ctx->skey, tmp);
+ if (len <= 16) {
+ xorbuf(buf, tmp, len);
+ break;
+ }
+ xorbuf(buf, tmp, 16);
+ buf += 16;
+ len -= 16;
+ }
+ return cc;
+}
+
+/* see bearssl_block.h */
+const br_block_ctr_class br_aes_small_ctr_vtable = {
+ sizeof(br_aes_small_ctr_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_ctr_class **, const void *, size_t))
+ &br_aes_small_ctr_init,
+ (uint32_t (*)(const br_block_ctr_class *const *,
+ const void *, uint32_t, void *, size_t))
+ &br_aes_small_ctr_run
+};
diff --git a/contrib/bearssl/src/symcipher/aes_small_ctrcbc.c b/contrib/bearssl/src/symcipher/aes_small_ctrcbc.c
new file mode 100644
index 000000000000..2d6ba3293b81
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_small_ctrcbc.c
@@ -0,0 +1,142 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_aes_small_ctrcbc_init(br_aes_small_ctrcbc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_small_ctrcbc_vtable;
+ ctx->num_rounds = br_aes_keysched(ctx->skey, key, len);
+}
+
+static void
+xorbuf(void *dst, const void *src, size_t len)
+{
+ unsigned char *d;
+ const unsigned char *s;
+
+ d = dst;
+ s = src;
+ while (len -- > 0) {
+ *d ++ ^= *s ++;
+ }
+}
+
+/* see bearssl_block.h */
+void
+br_aes_small_ctrcbc_ctr(const br_aes_small_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len)
+{
+ unsigned char *buf, *bctr;
+ uint32_t cc0, cc1, cc2, cc3;
+
+ buf = data;
+ bctr = ctr;
+ cc3 = br_dec32be(bctr + 0);
+ cc2 = br_dec32be(bctr + 4);
+ cc1 = br_dec32be(bctr + 8);
+ cc0 = br_dec32be(bctr + 12);
+ while (len > 0) {
+ unsigned char tmp[16];
+ uint32_t carry;
+
+ br_enc32be(tmp + 0, cc3);
+ br_enc32be(tmp + 4, cc2);
+ br_enc32be(tmp + 8, cc1);
+ br_enc32be(tmp + 12, cc0);
+ br_aes_small_encrypt(ctx->num_rounds, ctx->skey, tmp);
+ xorbuf(buf, tmp, 16);
+ buf += 16;
+ len -= 16;
+ cc0 ++;
+ carry = (~(cc0 | -cc0)) >> 31;
+ cc1 += carry;
+ carry &= (~(cc1 | -cc1)) >> 31;
+ cc2 += carry;
+ carry &= (~(cc2 | -cc2)) >> 31;
+ cc3 += carry;
+ }
+ br_enc32be(bctr + 0, cc3);
+ br_enc32be(bctr + 4, cc2);
+ br_enc32be(bctr + 8, cc1);
+ br_enc32be(bctr + 12, cc0);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_small_ctrcbc_mac(const br_aes_small_ctrcbc_keys *ctx,
+ void *cbcmac, const void *data, size_t len)
+{
+ const unsigned char *buf;
+
+ buf = data;
+ while (len > 0) {
+ xorbuf(cbcmac, buf, 16);
+ br_aes_small_encrypt(ctx->num_rounds, ctx->skey, cbcmac);
+ buf += 16;
+ len -= 16;
+ }
+}
+
+/* see bearssl_block.h */
+void
+br_aes_small_ctrcbc_encrypt(const br_aes_small_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len)
+{
+ br_aes_small_ctrcbc_ctr(ctx, ctr, data, len);
+ br_aes_small_ctrcbc_mac(ctx, cbcmac, data, len);
+}
+
+/* see bearssl_block.h */
+void
+br_aes_small_ctrcbc_decrypt(const br_aes_small_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len)
+{
+ br_aes_small_ctrcbc_mac(ctx, cbcmac, data, len);
+ br_aes_small_ctrcbc_ctr(ctx, ctr, data, len);
+}
+
+/* see bearssl_block.h */
+const br_block_ctrcbc_class br_aes_small_ctrcbc_vtable = {
+ sizeof(br_aes_small_ctrcbc_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_ctrcbc_class **, const void *, size_t))
+ &br_aes_small_ctrcbc_init,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, void *, size_t))
+ &br_aes_small_ctrcbc_encrypt,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, void *, size_t))
+ &br_aes_small_ctrcbc_decrypt,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, size_t))
+ &br_aes_small_ctrcbc_ctr,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, const void *, size_t))
+ &br_aes_small_ctrcbc_mac
+};
diff --git a/contrib/bearssl/src/symcipher/aes_small_dec.c b/contrib/bearssl/src/symcipher/aes_small_dec.c
new file mode 100644
index 000000000000..59dca8ec400e
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_small_dec.c
@@ -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"
+
+/*
+ * Inverse S-box.
+ */
+static const unsigned char iS[] = {
+ 0x52, 0x09, 0x6A, 0xD5, 0x30, 0x36, 0xA5, 0x38, 0xBF, 0x40, 0xA3, 0x9E,
+ 0x81, 0xF3, 0xD7, 0xFB, 0x7C, 0xE3, 0x39, 0x82, 0x9B, 0x2F, 0xFF, 0x87,
+ 0x34, 0x8E, 0x43, 0x44, 0xC4, 0xDE, 0xE9, 0xCB, 0x54, 0x7B, 0x94, 0x32,
+ 0xA6, 0xC2, 0x23, 0x3D, 0xEE, 0x4C, 0x95, 0x0B, 0x42, 0xFA, 0xC3, 0x4E,
+ 0x08, 0x2E, 0xA1, 0x66, 0x28, 0xD9, 0x24, 0xB2, 0x76, 0x5B, 0xA2, 0x49,
+ 0x6D, 0x8B, 0xD1, 0x25, 0x72, 0xF8, 0xF6, 0x64, 0x86, 0x68, 0x98, 0x16,
+ 0xD4, 0xA4, 0x5C, 0xCC, 0x5D, 0x65, 0xB6, 0x92, 0x6C, 0x70, 0x48, 0x50,
+ 0xFD, 0xED, 0xB9, 0xDA, 0x5E, 0x15, 0x46, 0x57, 0xA7, 0x8D, 0x9D, 0x84,
+ 0x90, 0xD8, 0xAB, 0x00, 0x8C, 0xBC, 0xD3, 0x0A, 0xF7, 0xE4, 0x58, 0x05,
+ 0xB8, 0xB3, 0x45, 0x06, 0xD0, 0x2C, 0x1E, 0x8F, 0xCA, 0x3F, 0x0F, 0x02,
+ 0xC1, 0xAF, 0xBD, 0x03, 0x01, 0x13, 0x8A, 0x6B, 0x3A, 0x91, 0x11, 0x41,
+ 0x4F, 0x67, 0xDC, 0xEA, 0x97, 0xF2, 0xCF, 0xCE, 0xF0, 0xB4, 0xE6, 0x73,
+ 0x96, 0xAC, 0x74, 0x22, 0xE7, 0xAD, 0x35, 0x85, 0xE2, 0xF9, 0x37, 0xE8,
+ 0x1C, 0x75, 0xDF, 0x6E, 0x47, 0xF1, 0x1A, 0x71, 0x1D, 0x29, 0xC5, 0x89,
+ 0x6F, 0xB7, 0x62, 0x0E, 0xAA, 0x18, 0xBE, 0x1B, 0xFC, 0x56, 0x3E, 0x4B,
+ 0xC6, 0xD2, 0x79, 0x20, 0x9A, 0xDB, 0xC0, 0xFE, 0x78, 0xCD, 0x5A, 0xF4,
+ 0x1F, 0xDD, 0xA8, 0x33, 0x88, 0x07, 0xC7, 0x31, 0xB1, 0x12, 0x10, 0x59,
+ 0x27, 0x80, 0xEC, 0x5F, 0x60, 0x51, 0x7F, 0xA9, 0x19, 0xB5, 0x4A, 0x0D,
+ 0x2D, 0xE5, 0x7A, 0x9F, 0x93, 0xC9, 0x9C, 0xEF, 0xA0, 0xE0, 0x3B, 0x4D,
+ 0xAE, 0x2A, 0xF5, 0xB0, 0xC8, 0xEB, 0xBB, 0x3C, 0x83, 0x53, 0x99, 0x61,
+ 0x17, 0x2B, 0x04, 0x7E, 0xBA, 0x77, 0xD6, 0x26, 0xE1, 0x69, 0x14, 0x63,
+ 0x55, 0x21, 0x0C, 0x7D
+};
+
+static void
+add_round_key(unsigned *state, const uint32_t *skeys)
+{
+ int i;
+
+ for (i = 0; i < 16; i += 4) {
+ uint32_t k;
+
+ k = *skeys ++;
+ state[i + 0] ^= (unsigned)(k >> 24);
+ state[i + 1] ^= (unsigned)(k >> 16) & 0xFF;
+ state[i + 2] ^= (unsigned)(k >> 8) & 0xFF;
+ state[i + 3] ^= (unsigned)k & 0xFF;
+ }
+}
+
+static void
+inv_sub_bytes(unsigned *state)
+{
+ int i;
+
+ for (i = 0; i < 16; i ++) {
+ state[i] = iS[state[i]];
+ }
+}
+
+static void
+inv_shift_rows(unsigned *state)
+{
+ unsigned tmp;
+
+ tmp = state[13];
+ state[13] = state[9];
+ state[9] = state[5];
+ state[5] = state[1];
+ state[1] = tmp;
+
+ tmp = state[2];
+ state[2] = state[10];
+ state[10] = tmp;
+ tmp = state[6];
+ state[6] = state[14];
+ state[14] = tmp;
+
+ tmp = state[3];
+ state[3] = state[7];
+ state[7] = state[11];
+ state[11] = state[15];
+ state[15] = tmp;
+}
+
+static inline unsigned
+gf256red(unsigned x)
+{
+ unsigned y;
+
+ y = x >> 8;
+ return (x ^ y ^ (y << 1) ^ (y << 3) ^ (y << 4)) & 0xFF;
+}
+
+static void
+inv_mix_columns(unsigned *state)
+{
+ int i;
+
+ for (i = 0; i < 16; i += 4) {
+ unsigned s0, s1, s2, s3;
+ unsigned t0, t1, t2, t3;
+
+ s0 = state[i + 0];
+ s1 = state[i + 1];
+ s2 = state[i + 2];
+ s3 = state[i + 3];
+ t0 = (s0 << 1) ^ (s0 << 2) ^ (s0 << 3)
+ ^ s1 ^ (s1 << 1) ^ (s1 << 3)
+ ^ s2 ^ (s2 << 2) ^ (s2 << 3)
+ ^ s3 ^ (s3 << 3);
+ t1 = s0 ^ (s0 << 3)
+ ^ (s1 << 1) ^ (s1 << 2) ^ (s1 << 3)
+ ^ s2 ^ (s2 << 1) ^ (s2 << 3)
+ ^ s3 ^ (s3 << 2) ^ (s3 << 3);
+ t2 = s0 ^ (s0 << 2) ^ (s0 << 3)
+ ^ s1 ^ (s1 << 3)
+ ^ (s2 << 1) ^ (s2 << 2) ^ (s2 << 3)
+ ^ s3 ^ (s3 << 1) ^ (s3 << 3);
+ t3 = s0 ^ (s0 << 1) ^ (s0 << 3)
+ ^ s1 ^ (s1 << 2) ^ (s1 << 3)
+ ^ s2 ^ (s2 << 3)
+ ^ (s3 << 1) ^ (s3 << 2) ^ (s3 << 3);
+ state[i + 0] = gf256red(t0);
+ state[i + 1] = gf256red(t1);
+ state[i + 2] = gf256red(t2);
+ state[i + 3] = gf256red(t3);
+ }
+}
+
+/* see inner.h */
+void
+br_aes_small_decrypt(unsigned num_rounds, const uint32_t *skey, void *data)
+{
+ unsigned char *buf;
+ unsigned state[16];
+ unsigned u;
+
+ buf = data;
+ for (u = 0; u < 16; u ++) {
+ state[u] = buf[u];
+ }
+ add_round_key(state, skey + (num_rounds << 2));
+ for (u = num_rounds - 1; u > 0; u --) {
+ inv_shift_rows(state);
+ inv_sub_bytes(state);
+ add_round_key(state, skey + (u << 2));
+ inv_mix_columns(state);
+ }
+ inv_shift_rows(state);
+ inv_sub_bytes(state);
+ add_round_key(state, skey);
+ for (u = 0; u < 16; u ++) {
+ buf[u] = state[u];
+ }
+}
diff --git a/contrib/bearssl/src/symcipher/aes_small_enc.c b/contrib/bearssl/src/symcipher/aes_small_enc.c
new file mode 100644
index 000000000000..29f48a8f4f6e
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_small_enc.c
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#define S br_aes_S
+
+static void
+add_round_key(unsigned *state, const uint32_t *skeys)
+{
+ int i;
+
+ for (i = 0; i < 16; i += 4) {
+ uint32_t k;
+
+ k = *skeys ++;
+ state[i + 0] ^= (unsigned)(k >> 24);
+ state[i + 1] ^= (unsigned)(k >> 16) & 0xFF;
+ state[i + 2] ^= (unsigned)(k >> 8) & 0xFF;
+ state[i + 3] ^= (unsigned)k & 0xFF;
+ }
+}
+
+static void
+sub_bytes(unsigned *state)
+{
+ int i;
+
+ for (i = 0; i < 16; i ++) {
+ state[i] = S[state[i]];
+ }
+}
+
+static void
+shift_rows(unsigned *state)
+{
+ unsigned tmp;
+
+ tmp = state[1];
+ state[1] = state[5];
+ state[5] = state[9];
+ state[9] = state[13];
+ state[13] = tmp;
+
+ tmp = state[2];
+ state[2] = state[10];
+ state[10] = tmp;
+ tmp = state[6];
+ state[6] = state[14];
+ state[14] = tmp;
+
+ tmp = state[15];
+ state[15] = state[11];
+ state[11] = state[7];
+ state[7] = state[3];
+ state[3] = tmp;
+}
+
+static void
+mix_columns(unsigned *state)
+{
+ int i;
+
+ for (i = 0; i < 16; i += 4) {
+ unsigned s0, s1, s2, s3;
+ unsigned t0, t1, t2, t3;
+
+ s0 = state[i + 0];
+ s1 = state[i + 1];
+ s2 = state[i + 2];
+ s3 = state[i + 3];
+ t0 = (s0 << 1) ^ s1 ^ (s1 << 1) ^ s2 ^ s3;
+ t1 = s0 ^ (s1 << 1) ^ s2 ^ (s2 << 1) ^ s3;
+ t2 = s0 ^ s1 ^ (s2 << 1) ^ s3 ^ (s3 << 1);
+ t3 = s0 ^ (s0 << 1) ^ s1 ^ s2 ^ (s3 << 1);
+ state[i + 0] = t0 ^ ((unsigned)(-(int)(t0 >> 8)) & 0x11B);
+ state[i + 1] = t1 ^ ((unsigned)(-(int)(t1 >> 8)) & 0x11B);
+ state[i + 2] = t2 ^ ((unsigned)(-(int)(t2 >> 8)) & 0x11B);
+ state[i + 3] = t3 ^ ((unsigned)(-(int)(t3 >> 8)) & 0x11B);
+ }
+}
+
+/* see inner.h */
+void
+br_aes_small_encrypt(unsigned num_rounds, const uint32_t *skey, void *data)
+{
+ unsigned char *buf;
+ unsigned state[16];
+ unsigned u;
+
+ buf = data;
+ for (u = 0; u < 16; u ++) {
+ state[u] = buf[u];
+ }
+ add_round_key(state, skey);
+ for (u = 1; u < num_rounds; u ++) {
+ sub_bytes(state);
+ shift_rows(state);
+ mix_columns(state);
+ add_round_key(state, skey + (u << 2));
+ }
+ sub_bytes(state);
+ shift_rows(state);
+ add_round_key(state, skey + (num_rounds << 2));
+ for (u = 0; u < 16; u ++) {
+ buf[u] = state[u];
+ }
+}
diff --git a/contrib/bearssl/src/symcipher/aes_x86ni.c b/contrib/bearssl/src/symcipher/aes_x86ni.c
new file mode 100644
index 000000000000..d5408f1360fa
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_x86ni.c
@@ -0,0 +1,240 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BR_ENABLE_INTRINSICS 1
+#include "inner.h"
+
+/*
+ * This code contains the AES key schedule implementation using the
+ * AES-NI opcodes.
+ */
+
+#if BR_AES_X86NI
+
+/* see inner.h */
+int
+br_aes_x86ni_supported(void)
+{
+ /*
+ * Bit mask for features in ECX:
+ * 19 SSE4.1 (used for _mm_insert_epi32(), for AES-CTR)
+ * 25 AES-NI
+ */
+ return br_cpuid(0, 0, 0x02080000, 0);
+}
+
+BR_TARGETS_X86_UP
+
+BR_TARGET("sse2,aes")
+static inline __m128i
+expand_step128(__m128i k, __m128i k2)
+{
+ k = _mm_xor_si128(k, _mm_slli_si128(k, 4));
+ k = _mm_xor_si128(k, _mm_slli_si128(k, 4));
+ k = _mm_xor_si128(k, _mm_slli_si128(k, 4));
+ k2 = _mm_shuffle_epi32(k2, 0xFF);
+ return _mm_xor_si128(k, k2);
+}
+
+BR_TARGET("sse2,aes")
+static inline void
+expand_step192(__m128i *t1, __m128i *t2, __m128i *t3)
+{
+ __m128i t4;
+
+ *t2 = _mm_shuffle_epi32(*t2, 0x55);
+ t4 = _mm_slli_si128(*t1, 0x4);
+ *t1 = _mm_xor_si128(*t1, t4);
+ t4 = _mm_slli_si128(t4, 0x4);
+ *t1 = _mm_xor_si128(*t1, t4);
+ t4 = _mm_slli_si128(t4, 0x4);
+ *t1 = _mm_xor_si128(*t1, t4);
+ *t1 = _mm_xor_si128(*t1, *t2);
+ *t2 = _mm_shuffle_epi32(*t1, 0xFF);
+ t4 = _mm_slli_si128(*t3, 0x4);
+ *t3 = _mm_xor_si128(*t3, t4);
+ *t3 = _mm_xor_si128(*t3, *t2);
+}
+
+BR_TARGET("sse2,aes")
+static inline void
+expand_step256_1(__m128i *t1, __m128i *t2)
+{
+ __m128i t4;
+
+ *t2 = _mm_shuffle_epi32(*t2, 0xFF);
+ t4 = _mm_slli_si128(*t1, 0x4);
+ *t1 = _mm_xor_si128(*t1, t4);
+ t4 = _mm_slli_si128(t4, 0x4);
+ *t1 = _mm_xor_si128(*t1, t4);
+ t4 = _mm_slli_si128(t4, 0x4);
+ *t1 = _mm_xor_si128(*t1, t4);
+ *t1 = _mm_xor_si128(*t1, *t2);
+}
+
+BR_TARGET("sse2,aes")
+static inline void
+expand_step256_2(__m128i *t1, __m128i *t3)
+{
+ __m128i t2, t4;
+
+ t4 = _mm_aeskeygenassist_si128(*t1, 0x0);
+ t2 = _mm_shuffle_epi32(t4, 0xAA);
+ t4 = _mm_slli_si128(*t3, 0x4);
+ *t3 = _mm_xor_si128(*t3, t4);
+ t4 = _mm_slli_si128(t4, 0x4);
+ *t3 = _mm_xor_si128(*t3, t4);
+ t4 = _mm_slli_si128(t4, 0x4);
+ *t3 = _mm_xor_si128(*t3, t4);
+ *t3 = _mm_xor_si128(*t3, t2);
+}
+
+/*
+ * Perform key schedule for AES, encryption direction. Subkeys are written
+ * in sk[], and the number of rounds is returned. Key length MUST be 16,
+ * 24 or 32 bytes.
+ */
+BR_TARGET("sse2,aes")
+static unsigned
+x86ni_keysched(__m128i *sk, const void *key, size_t len)
+{
+ const unsigned char *kb;
+
+#define KEXP128(k, i, rcon) do { \
+ k = expand_step128(k, _mm_aeskeygenassist_si128(k, rcon)); \
+ sk[i] = k; \
+ } while (0)
+
+#define KEXP192(i, rcon1, rcon2) do { \
+ sk[(i) + 0] = t1; \
+ sk[(i) + 1] = t3; \
+ t2 = _mm_aeskeygenassist_si128(t3, rcon1); \
+ expand_step192(&t1, &t2, &t3); \
+ sk[(i) + 1] = _mm_castpd_si128(_mm_shuffle_pd( \
+ _mm_castsi128_pd(sk[(i) + 1]), \
+ _mm_castsi128_pd(t1), 0)); \
+ sk[(i) + 2] = _mm_castpd_si128(_mm_shuffle_pd( \
+ _mm_castsi128_pd(t1), \
+ _mm_castsi128_pd(t3), 1)); \
+ t2 = _mm_aeskeygenassist_si128(t3, rcon2); \
+ expand_step192(&t1, &t2, &t3); \
+ } while (0)
+
+#define KEXP256(i, rcon) do { \
+ sk[(i) + 0] = t3; \
+ t2 = _mm_aeskeygenassist_si128(t3, rcon); \
+ expand_step256_1(&t1, &t2); \
+ sk[(i) + 1] = t1; \
+ expand_step256_2(&t1, &t3); \
+ } while (0)
+
+ kb = key;
+ switch (len) {
+ __m128i t1, t2, t3;
+
+ case 16:
+ t1 = _mm_loadu_si128((const void *)kb);
+ sk[0] = t1;
+ KEXP128(t1, 1, 0x01);
+ KEXP128(t1, 2, 0x02);
+ KEXP128(t1, 3, 0x04);
+ KEXP128(t1, 4, 0x08);
+ KEXP128(t1, 5, 0x10);
+ KEXP128(t1, 6, 0x20);
+ KEXP128(t1, 7, 0x40);
+ KEXP128(t1, 8, 0x80);
+ KEXP128(t1, 9, 0x1B);
+ KEXP128(t1, 10, 0x36);
+ return 10;
+
+ case 24:
+ t1 = _mm_loadu_si128((const void *)kb);
+ t3 = _mm_loadu_si128((const void *)(kb + 8));
+ t3 = _mm_shuffle_epi32(t3, 0x4E);
+ KEXP192(0, 0x01, 0x02);
+ KEXP192(3, 0x04, 0x08);
+ KEXP192(6, 0x10, 0x20);
+ KEXP192(9, 0x40, 0x80);
+ sk[12] = t1;
+ return 12;
+
+ case 32:
+ t1 = _mm_loadu_si128((const void *)kb);
+ t3 = _mm_loadu_si128((const void *)(kb + 16));
+ sk[0] = t1;
+ KEXP256( 1, 0x01);
+ KEXP256( 3, 0x02);
+ KEXP256( 5, 0x04);
+ KEXP256( 7, 0x08);
+ KEXP256( 9, 0x10);
+ KEXP256(11, 0x20);
+ sk[13] = t3;
+ t2 = _mm_aeskeygenassist_si128(t3, 0x40);
+ expand_step256_1(&t1, &t2);
+ sk[14] = t1;
+ return 14;
+
+ default:
+ return 0;
+ }
+
+#undef KEXP128
+#undef KEXP192
+#undef KEXP256
+}
+
+/* see inner.h */
+BR_TARGET("sse2,aes")
+unsigned
+br_aes_x86ni_keysched_enc(unsigned char *skni, const void *key, size_t len)
+{
+ __m128i sk[15];
+ unsigned num_rounds;
+
+ num_rounds = x86ni_keysched(sk, key, len);
+ memcpy(skni, sk, (num_rounds + 1) << 4);
+ return num_rounds;
+}
+
+/* see inner.h */
+BR_TARGET("sse2,aes")
+unsigned
+br_aes_x86ni_keysched_dec(unsigned char *skni, const void *key, size_t len)
+{
+ __m128i sk[15];
+ unsigned u, num_rounds;
+
+ num_rounds = x86ni_keysched(sk, key, len);
+ _mm_storeu_si128((void *)skni, sk[num_rounds]);
+ for (u = 1; u < num_rounds; u ++) {
+ _mm_storeu_si128((void *)(skni + (u << 4)),
+ _mm_aesimc_si128(sk[num_rounds - u]));
+ }
+ _mm_storeu_si128((void *)(skni + (num_rounds << 4)), sk[0]);
+ return num_rounds;
+}
+
+BR_TARGETS_X86_DOWN
+
+#endif
diff --git a/contrib/bearssl/src/symcipher/aes_x86ni_cbcdec.c b/contrib/bearssl/src/symcipher/aes_x86ni_cbcdec.c
new file mode 100644
index 000000000000..862b1b5bd228
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_x86ni_cbcdec.c
@@ -0,0 +1,223 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BR_ENABLE_INTRINSICS 1
+#include "inner.h"
+
+#if BR_AES_X86NI
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class *
+br_aes_x86ni_cbcdec_get_vtable(void)
+{
+ return br_aes_x86ni_supported() ? &br_aes_x86ni_cbcdec_vtable : NULL;
+}
+
+/* see bearssl_block.h */
+void
+br_aes_x86ni_cbcdec_init(br_aes_x86ni_cbcdec_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_x86ni_cbcdec_vtable;
+ ctx->num_rounds = br_aes_x86ni_keysched_dec(ctx->skey.skni, key, len);
+}
+
+BR_TARGETS_X86_UP
+
+/* see bearssl_block.h */
+BR_TARGET("sse2,aes")
+void
+br_aes_x86ni_cbcdec_run(const br_aes_x86ni_cbcdec_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf;
+ unsigned num_rounds;
+ __m128i sk[15], ivx;
+ unsigned u;
+
+ buf = data;
+ ivx = _mm_loadu_si128(iv);
+ num_rounds = ctx->num_rounds;
+ for (u = 0; u <= num_rounds; u ++) {
+ sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4)));
+ }
+ while (len > 0) {
+ __m128i x0, x1, x2, x3, e0, e1, e2, e3;
+
+ x0 = _mm_loadu_si128((void *)(buf + 0));
+ if (len >= 64) {
+ x1 = _mm_loadu_si128((void *)(buf + 16));
+ x2 = _mm_loadu_si128((void *)(buf + 32));
+ x3 = _mm_loadu_si128((void *)(buf + 48));
+ } else {
+ x0 = _mm_loadu_si128((void *)(buf + 0));
+ if (len >= 32) {
+ x1 = _mm_loadu_si128((void *)(buf + 16));
+ if (len >= 48) {
+ x2 = _mm_loadu_si128(
+ (void *)(buf + 32));
+ x3 = x2;
+ } else {
+ x2 = x0;
+ x3 = x1;
+ }
+ } else {
+ x1 = x0;
+ x2 = x0;
+ x3 = x0;
+ }
+ }
+ e0 = x0;
+ e1 = x1;
+ e2 = x2;
+ e3 = x3;
+ x0 = _mm_xor_si128(x0, sk[0]);
+ x1 = _mm_xor_si128(x1, sk[0]);
+ x2 = _mm_xor_si128(x2, sk[0]);
+ x3 = _mm_xor_si128(x3, sk[0]);
+ x0 = _mm_aesdec_si128(x0, sk[1]);
+ x1 = _mm_aesdec_si128(x1, sk[1]);
+ x2 = _mm_aesdec_si128(x2, sk[1]);
+ x3 = _mm_aesdec_si128(x3, sk[1]);
+ x0 = _mm_aesdec_si128(x0, sk[2]);
+ x1 = _mm_aesdec_si128(x1, sk[2]);
+ x2 = _mm_aesdec_si128(x2, sk[2]);
+ x3 = _mm_aesdec_si128(x3, sk[2]);
+ x0 = _mm_aesdec_si128(x0, sk[3]);
+ x1 = _mm_aesdec_si128(x1, sk[3]);
+ x2 = _mm_aesdec_si128(x2, sk[3]);
+ x3 = _mm_aesdec_si128(x3, sk[3]);
+ x0 = _mm_aesdec_si128(x0, sk[4]);
+ x1 = _mm_aesdec_si128(x1, sk[4]);
+ x2 = _mm_aesdec_si128(x2, sk[4]);
+ x3 = _mm_aesdec_si128(x3, sk[4]);
+ x0 = _mm_aesdec_si128(x0, sk[5]);
+ x1 = _mm_aesdec_si128(x1, sk[5]);
+ x2 = _mm_aesdec_si128(x2, sk[5]);
+ x3 = _mm_aesdec_si128(x3, sk[5]);
+ x0 = _mm_aesdec_si128(x0, sk[6]);
+ x1 = _mm_aesdec_si128(x1, sk[6]);
+ x2 = _mm_aesdec_si128(x2, sk[6]);
+ x3 = _mm_aesdec_si128(x3, sk[6]);
+ x0 = _mm_aesdec_si128(x0, sk[7]);
+ x1 = _mm_aesdec_si128(x1, sk[7]);
+ x2 = _mm_aesdec_si128(x2, sk[7]);
+ x3 = _mm_aesdec_si128(x3, sk[7]);
+ x0 = _mm_aesdec_si128(x0, sk[8]);
+ x1 = _mm_aesdec_si128(x1, sk[8]);
+ x2 = _mm_aesdec_si128(x2, sk[8]);
+ x3 = _mm_aesdec_si128(x3, sk[8]);
+ x0 = _mm_aesdec_si128(x0, sk[9]);
+ x1 = _mm_aesdec_si128(x1, sk[9]);
+ x2 = _mm_aesdec_si128(x2, sk[9]);
+ x3 = _mm_aesdec_si128(x3, sk[9]);
+ if (num_rounds == 10) {
+ x0 = _mm_aesdeclast_si128(x0, sk[10]);
+ x1 = _mm_aesdeclast_si128(x1, sk[10]);
+ x2 = _mm_aesdeclast_si128(x2, sk[10]);
+ x3 = _mm_aesdeclast_si128(x3, sk[10]);
+ } else if (num_rounds == 12) {
+ x0 = _mm_aesdec_si128(x0, sk[10]);
+ x1 = _mm_aesdec_si128(x1, sk[10]);
+ x2 = _mm_aesdec_si128(x2, sk[10]);
+ x3 = _mm_aesdec_si128(x3, sk[10]);
+ x0 = _mm_aesdec_si128(x0, sk[11]);
+ x1 = _mm_aesdec_si128(x1, sk[11]);
+ x2 = _mm_aesdec_si128(x2, sk[11]);
+ x3 = _mm_aesdec_si128(x3, sk[11]);
+ x0 = _mm_aesdeclast_si128(x0, sk[12]);
+ x1 = _mm_aesdeclast_si128(x1, sk[12]);
+ x2 = _mm_aesdeclast_si128(x2, sk[12]);
+ x3 = _mm_aesdeclast_si128(x3, sk[12]);
+ } else {
+ x0 = _mm_aesdec_si128(x0, sk[10]);
+ x1 = _mm_aesdec_si128(x1, sk[10]);
+ x2 = _mm_aesdec_si128(x2, sk[10]);
+ x3 = _mm_aesdec_si128(x3, sk[10]);
+ x0 = _mm_aesdec_si128(x0, sk[11]);
+ x1 = _mm_aesdec_si128(x1, sk[11]);
+ x2 = _mm_aesdec_si128(x2, sk[11]);
+ x3 = _mm_aesdec_si128(x3, sk[11]);
+ x0 = _mm_aesdec_si128(x0, sk[12]);
+ x1 = _mm_aesdec_si128(x1, sk[12]);
+ x2 = _mm_aesdec_si128(x2, sk[12]);
+ x3 = _mm_aesdec_si128(x3, sk[12]);
+ x0 = _mm_aesdec_si128(x0, sk[13]);
+ x1 = _mm_aesdec_si128(x1, sk[13]);
+ x2 = _mm_aesdec_si128(x2, sk[13]);
+ x3 = _mm_aesdec_si128(x3, sk[13]);
+ x0 = _mm_aesdeclast_si128(x0, sk[14]);
+ x1 = _mm_aesdeclast_si128(x1, sk[14]);
+ x2 = _mm_aesdeclast_si128(x2, sk[14]);
+ x3 = _mm_aesdeclast_si128(x3, sk[14]);
+ }
+ x0 = _mm_xor_si128(x0, ivx);
+ x1 = _mm_xor_si128(x1, e0);
+ x2 = _mm_xor_si128(x2, e1);
+ x3 = _mm_xor_si128(x3, e2);
+ ivx = e3;
+ _mm_storeu_si128((void *)(buf + 0), x0);
+ if (len >= 64) {
+ _mm_storeu_si128((void *)(buf + 16), x1);
+ _mm_storeu_si128((void *)(buf + 32), x2);
+ _mm_storeu_si128((void *)(buf + 48), x3);
+ buf += 64;
+ len -= 64;
+ } else {
+ if (len >= 32) {
+ _mm_storeu_si128((void *)(buf + 16), x1);
+ if (len >= 48) {
+ _mm_storeu_si128(
+ (void *)(buf + 32), x2);
+ }
+ }
+ break;
+ }
+ }
+ _mm_storeu_si128(iv, ivx);
+}
+
+BR_TARGETS_X86_DOWN
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class br_aes_x86ni_cbcdec_vtable = {
+ sizeof(br_aes_x86ni_cbcdec_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcdec_class **, const void *, size_t))
+ &br_aes_x86ni_cbcdec_init,
+ (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t))
+ &br_aes_x86ni_cbcdec_run
+};
+
+#else
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class *
+br_aes_x86ni_cbcdec_get_vtable(void)
+{
+ return NULL;
+}
+
+#endif
diff --git a/contrib/bearssl/src/symcipher/aes_x86ni_cbcenc.c b/contrib/bearssl/src/symcipher/aes_x86ni_cbcenc.c
new file mode 100644
index 000000000000..85feecdb0d46
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_x86ni_cbcenc.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BR_ENABLE_INTRINSICS 1
+#include "inner.h"
+
+#if BR_AES_X86NI
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class *
+br_aes_x86ni_cbcenc_get_vtable(void)
+{
+ return br_aes_x86ni_supported() ? &br_aes_x86ni_cbcenc_vtable : NULL;
+}
+
+/* see bearssl_block.h */
+void
+br_aes_x86ni_cbcenc_init(br_aes_x86ni_cbcenc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_x86ni_cbcenc_vtable;
+ ctx->num_rounds = br_aes_x86ni_keysched_enc(ctx->skey.skni, key, len);
+}
+
+BR_TARGETS_X86_UP
+
+/* see bearssl_block.h */
+BR_TARGET("sse2,aes")
+void
+br_aes_x86ni_cbcenc_run(const br_aes_x86ni_cbcenc_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf;
+ unsigned num_rounds;
+ __m128i sk[15], ivx;
+ unsigned u;
+
+ buf = data;
+ ivx = _mm_loadu_si128(iv);
+ num_rounds = ctx->num_rounds;
+ for (u = 0; u <= num_rounds; u ++) {
+ sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4)));
+ }
+ while (len > 0) {
+ __m128i x;
+
+ x = _mm_xor_si128(_mm_loadu_si128((void *)buf), ivx);
+ x = _mm_xor_si128(x, sk[0]);
+ x = _mm_aesenc_si128(x, sk[1]);
+ x = _mm_aesenc_si128(x, sk[2]);
+ x = _mm_aesenc_si128(x, sk[3]);
+ x = _mm_aesenc_si128(x, sk[4]);
+ x = _mm_aesenc_si128(x, sk[5]);
+ x = _mm_aesenc_si128(x, sk[6]);
+ x = _mm_aesenc_si128(x, sk[7]);
+ x = _mm_aesenc_si128(x, sk[8]);
+ x = _mm_aesenc_si128(x, sk[9]);
+ if (num_rounds == 10) {
+ x = _mm_aesenclast_si128(x, sk[10]);
+ } else if (num_rounds == 12) {
+ x = _mm_aesenc_si128(x, sk[10]);
+ x = _mm_aesenc_si128(x, sk[11]);
+ x = _mm_aesenclast_si128(x, sk[12]);
+ } else {
+ x = _mm_aesenc_si128(x, sk[10]);
+ x = _mm_aesenc_si128(x, sk[11]);
+ x = _mm_aesenc_si128(x, sk[12]);
+ x = _mm_aesenc_si128(x, sk[13]);
+ x = _mm_aesenclast_si128(x, sk[14]);
+ }
+ ivx = x;
+ _mm_storeu_si128((void *)buf, x);
+ buf += 16;
+ len -= 16;
+ }
+ _mm_storeu_si128(iv, ivx);
+}
+
+BR_TARGETS_X86_DOWN
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class br_aes_x86ni_cbcenc_vtable = {
+ sizeof(br_aes_x86ni_cbcenc_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_cbcenc_class **, const void *, size_t))
+ &br_aes_x86ni_cbcenc_init,
+ (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t))
+ &br_aes_x86ni_cbcenc_run
+};
+
+#else
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class *
+br_aes_x86ni_cbcenc_get_vtable(void)
+{
+ return NULL;
+}
+
+#endif
diff --git a/contrib/bearssl/src/symcipher/aes_x86ni_ctr.c b/contrib/bearssl/src/symcipher/aes_x86ni_ctr.c
new file mode 100644
index 000000000000..1cddd6065dd7
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_x86ni_ctr.c
@@ -0,0 +1,211 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BR_ENABLE_INTRINSICS 1
+#include "inner.h"
+
+#if BR_AES_X86NI
+
+/* see bearssl_block.h */
+const br_block_ctr_class *
+br_aes_x86ni_ctr_get_vtable(void)
+{
+ return br_aes_x86ni_supported() ? &br_aes_x86ni_ctr_vtable : NULL;
+}
+
+/* see bearssl_block.h */
+void
+br_aes_x86ni_ctr_init(br_aes_x86ni_ctr_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_x86ni_ctr_vtable;
+ ctx->num_rounds = br_aes_x86ni_keysched_enc(ctx->skey.skni, key, len);
+}
+
+BR_TARGETS_X86_UP
+
+/* see bearssl_block.h */
+BR_TARGET("sse2,sse4.1,aes")
+uint32_t
+br_aes_x86ni_ctr_run(const br_aes_x86ni_ctr_keys *ctx,
+ const void *iv, uint32_t cc, void *data, size_t len)
+{
+ unsigned char *buf;
+ unsigned char ivbuf[16];
+ unsigned num_rounds;
+ __m128i sk[15];
+ __m128i ivx;
+ unsigned u;
+
+ buf = data;
+ memcpy(ivbuf, iv, 12);
+ num_rounds = ctx->num_rounds;
+ for (u = 0; u <= num_rounds; u ++) {
+ sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4)));
+ }
+ ivx = _mm_loadu_si128((void *)ivbuf);
+ while (len > 0) {
+ __m128i x0, x1, x2, x3;
+
+ x0 = _mm_insert_epi32(ivx, br_bswap32(cc + 0), 3);
+ x1 = _mm_insert_epi32(ivx, br_bswap32(cc + 1), 3);
+ x2 = _mm_insert_epi32(ivx, br_bswap32(cc + 2), 3);
+ x3 = _mm_insert_epi32(ivx, br_bswap32(cc + 3), 3);
+ x0 = _mm_xor_si128(x0, sk[0]);
+ x1 = _mm_xor_si128(x1, sk[0]);
+ x2 = _mm_xor_si128(x2, sk[0]);
+ x3 = _mm_xor_si128(x3, sk[0]);
+ x0 = _mm_aesenc_si128(x0, sk[1]);
+ x1 = _mm_aesenc_si128(x1, sk[1]);
+ x2 = _mm_aesenc_si128(x2, sk[1]);
+ x3 = _mm_aesenc_si128(x3, sk[1]);
+ x0 = _mm_aesenc_si128(x0, sk[2]);
+ x1 = _mm_aesenc_si128(x1, sk[2]);
+ x2 = _mm_aesenc_si128(x2, sk[2]);
+ x3 = _mm_aesenc_si128(x3, sk[2]);
+ x0 = _mm_aesenc_si128(x0, sk[3]);
+ x1 = _mm_aesenc_si128(x1, sk[3]);
+ x2 = _mm_aesenc_si128(x2, sk[3]);
+ x3 = _mm_aesenc_si128(x3, sk[3]);
+ x0 = _mm_aesenc_si128(x0, sk[4]);
+ x1 = _mm_aesenc_si128(x1, sk[4]);
+ x2 = _mm_aesenc_si128(x2, sk[4]);
+ x3 = _mm_aesenc_si128(x3, sk[4]);
+ x0 = _mm_aesenc_si128(x0, sk[5]);
+ x1 = _mm_aesenc_si128(x1, sk[5]);
+ x2 = _mm_aesenc_si128(x2, sk[5]);
+ x3 = _mm_aesenc_si128(x3, sk[5]);
+ x0 = _mm_aesenc_si128(x0, sk[6]);
+ x1 = _mm_aesenc_si128(x1, sk[6]);
+ x2 = _mm_aesenc_si128(x2, sk[6]);
+ x3 = _mm_aesenc_si128(x3, sk[6]);
+ x0 = _mm_aesenc_si128(x0, sk[7]);
+ x1 = _mm_aesenc_si128(x1, sk[7]);
+ x2 = _mm_aesenc_si128(x2, sk[7]);
+ x3 = _mm_aesenc_si128(x3, sk[7]);
+ x0 = _mm_aesenc_si128(x0, sk[8]);
+ x1 = _mm_aesenc_si128(x1, sk[8]);
+ x2 = _mm_aesenc_si128(x2, sk[8]);
+ x3 = _mm_aesenc_si128(x3, sk[8]);
+ x0 = _mm_aesenc_si128(x0, sk[9]);
+ x1 = _mm_aesenc_si128(x1, sk[9]);
+ x2 = _mm_aesenc_si128(x2, sk[9]);
+ x3 = _mm_aesenc_si128(x3, sk[9]);
+ if (num_rounds == 10) {
+ x0 = _mm_aesenclast_si128(x0, sk[10]);
+ x1 = _mm_aesenclast_si128(x1, sk[10]);
+ x2 = _mm_aesenclast_si128(x2, sk[10]);
+ x3 = _mm_aesenclast_si128(x3, sk[10]);
+ } else if (num_rounds == 12) {
+ x0 = _mm_aesenc_si128(x0, sk[10]);
+ x1 = _mm_aesenc_si128(x1, sk[10]);
+ x2 = _mm_aesenc_si128(x2, sk[10]);
+ x3 = _mm_aesenc_si128(x3, sk[10]);
+ x0 = _mm_aesenc_si128(x0, sk[11]);
+ x1 = _mm_aesenc_si128(x1, sk[11]);
+ x2 = _mm_aesenc_si128(x2, sk[11]);
+ x3 = _mm_aesenc_si128(x3, sk[11]);
+ x0 = _mm_aesenclast_si128(x0, sk[12]);
+ x1 = _mm_aesenclast_si128(x1, sk[12]);
+ x2 = _mm_aesenclast_si128(x2, sk[12]);
+ x3 = _mm_aesenclast_si128(x3, sk[12]);
+ } else {
+ x0 = _mm_aesenc_si128(x0, sk[10]);
+ x1 = _mm_aesenc_si128(x1, sk[10]);
+ x2 = _mm_aesenc_si128(x2, sk[10]);
+ x3 = _mm_aesenc_si128(x3, sk[10]);
+ x0 = _mm_aesenc_si128(x0, sk[11]);
+ x1 = _mm_aesenc_si128(x1, sk[11]);
+ x2 = _mm_aesenc_si128(x2, sk[11]);
+ x3 = _mm_aesenc_si128(x3, sk[11]);
+ x0 = _mm_aesenc_si128(x0, sk[12]);
+ x1 = _mm_aesenc_si128(x1, sk[12]);
+ x2 = _mm_aesenc_si128(x2, sk[12]);
+ x3 = _mm_aesenc_si128(x3, sk[12]);
+ x0 = _mm_aesenc_si128(x0, sk[13]);
+ x1 = _mm_aesenc_si128(x1, sk[13]);
+ x2 = _mm_aesenc_si128(x2, sk[13]);
+ x3 = _mm_aesenc_si128(x3, sk[13]);
+ x0 = _mm_aesenclast_si128(x0, sk[14]);
+ x1 = _mm_aesenclast_si128(x1, sk[14]);
+ x2 = _mm_aesenclast_si128(x2, sk[14]);
+ x3 = _mm_aesenclast_si128(x3, sk[14]);
+ }
+ if (len >= 64) {
+ x0 = _mm_xor_si128(x0,
+ _mm_loadu_si128((void *)(buf + 0)));
+ x1 = _mm_xor_si128(x1,
+ _mm_loadu_si128((void *)(buf + 16)));
+ x2 = _mm_xor_si128(x2,
+ _mm_loadu_si128((void *)(buf + 32)));
+ x3 = _mm_xor_si128(x3,
+ _mm_loadu_si128((void *)(buf + 48)));
+ _mm_storeu_si128((void *)(buf + 0), x0);
+ _mm_storeu_si128((void *)(buf + 16), x1);
+ _mm_storeu_si128((void *)(buf + 32), x2);
+ _mm_storeu_si128((void *)(buf + 48), x3);
+ buf += 64;
+ len -= 64;
+ cc += 4;
+ } else {
+ unsigned char tmp[64];
+
+ _mm_storeu_si128((void *)(tmp + 0), x0);
+ _mm_storeu_si128((void *)(tmp + 16), x1);
+ _mm_storeu_si128((void *)(tmp + 32), x2);
+ _mm_storeu_si128((void *)(tmp + 48), x3);
+ for (u = 0; u < len; u ++) {
+ buf[u] ^= tmp[u];
+ }
+ cc += (uint32_t)len >> 4;
+ break;
+ }
+ }
+ return cc;
+}
+
+BR_TARGETS_X86_DOWN
+
+/* see bearssl_block.h */
+const br_block_ctr_class br_aes_x86ni_ctr_vtable = {
+ sizeof(br_aes_x86ni_ctr_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_ctr_class **, const void *, size_t))
+ &br_aes_x86ni_ctr_init,
+ (uint32_t (*)(const br_block_ctr_class *const *,
+ const void *, uint32_t, void *, size_t))
+ &br_aes_x86ni_ctr_run
+};
+
+#else
+
+/* see bearssl_block.h */
+const br_block_ctr_class *
+br_aes_x86ni_ctr_get_vtable(void)
+{
+ return NULL;
+}
+
+#endif
diff --git a/contrib/bearssl/src/symcipher/aes_x86ni_ctrcbc.c b/contrib/bearssl/src/symcipher/aes_x86ni_ctrcbc.c
new file mode 100644
index 000000000000..f57fead6858a
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/aes_x86ni_ctrcbc.c
@@ -0,0 +1,596 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BR_ENABLE_INTRINSICS 1
+#include "inner.h"
+
+#if BR_AES_X86NI
+
+/* see bearssl_block.h */
+const br_block_ctrcbc_class *
+br_aes_x86ni_ctrcbc_get_vtable(void)
+{
+ return br_aes_x86ni_supported() ? &br_aes_x86ni_ctrcbc_vtable : NULL;
+}
+
+/* see bearssl_block.h */
+void
+br_aes_x86ni_ctrcbc_init(br_aes_x86ni_ctrcbc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_aes_x86ni_ctrcbc_vtable;
+ ctx->num_rounds = br_aes_x86ni_keysched_enc(ctx->skey.skni, key, len);
+}
+
+BR_TARGETS_X86_UP
+
+/* see bearssl_block.h */
+BR_TARGET("sse2,sse4.1,aes")
+void
+br_aes_x86ni_ctrcbc_ctr(const br_aes_x86ni_ctrcbc_keys *ctx,
+ void *ctr, void *data, size_t len)
+{
+ unsigned char *buf;
+ unsigned num_rounds;
+ __m128i sk[15];
+ __m128i ivx0, ivx1, ivx2, ivx3;
+ __m128i erev, zero, one, four, notthree;
+ unsigned u;
+
+ buf = data;
+ num_rounds = ctx->num_rounds;
+ for (u = 0; u <= num_rounds; u ++) {
+ sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4)));
+ }
+
+ /*
+ * Some SSE2 constants.
+ */
+ erev = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15);
+ zero = _mm_setzero_si128();
+ one = _mm_set_epi64x(0, 1);
+ four = _mm_set_epi64x(0, 4);
+ notthree = _mm_sub_epi64(zero, four);
+
+ /*
+ * Decode the counter in big-endian and pre-increment the other
+ * three counters.
+ */
+ ivx0 = _mm_shuffle_epi8(_mm_loadu_si128((void *)ctr), erev);
+ ivx1 = _mm_add_epi64(ivx0, one);
+ ivx1 = _mm_sub_epi64(ivx1,
+ _mm_slli_si128(_mm_cmpeq_epi64(ivx1, zero), 8));
+ ivx2 = _mm_add_epi64(ivx1, one);
+ ivx2 = _mm_sub_epi64(ivx2,
+ _mm_slli_si128(_mm_cmpeq_epi64(ivx2, zero), 8));
+ ivx3 = _mm_add_epi64(ivx2, one);
+ ivx3 = _mm_sub_epi64(ivx3,
+ _mm_slli_si128(_mm_cmpeq_epi64(ivx3, zero), 8));
+ while (len > 0) {
+ __m128i x0, x1, x2, x3;
+
+ /*
+ * Load counter values; we need to byteswap them because
+ * the specification says that they use big-endian.
+ */
+ x0 = _mm_shuffle_epi8(ivx0, erev);
+ x1 = _mm_shuffle_epi8(ivx1, erev);
+ x2 = _mm_shuffle_epi8(ivx2, erev);
+ x3 = _mm_shuffle_epi8(ivx3, erev);
+
+ x0 = _mm_xor_si128(x0, sk[0]);
+ x1 = _mm_xor_si128(x1, sk[0]);
+ x2 = _mm_xor_si128(x2, sk[0]);
+ x3 = _mm_xor_si128(x3, sk[0]);
+ x0 = _mm_aesenc_si128(x0, sk[1]);
+ x1 = _mm_aesenc_si128(x1, sk[1]);
+ x2 = _mm_aesenc_si128(x2, sk[1]);
+ x3 = _mm_aesenc_si128(x3, sk[1]);
+ x0 = _mm_aesenc_si128(x0, sk[2]);
+ x1 = _mm_aesenc_si128(x1, sk[2]);
+ x2 = _mm_aesenc_si128(x2, sk[2]);
+ x3 = _mm_aesenc_si128(x3, sk[2]);
+ x0 = _mm_aesenc_si128(x0, sk[3]);
+ x1 = _mm_aesenc_si128(x1, sk[3]);
+ x2 = _mm_aesenc_si128(x2, sk[3]);
+ x3 = _mm_aesenc_si128(x3, sk[3]);
+ x0 = _mm_aesenc_si128(x0, sk[4]);
+ x1 = _mm_aesenc_si128(x1, sk[4]);
+ x2 = _mm_aesenc_si128(x2, sk[4]);
+ x3 = _mm_aesenc_si128(x3, sk[4]);
+ x0 = _mm_aesenc_si128(x0, sk[5]);
+ x1 = _mm_aesenc_si128(x1, sk[5]);
+ x2 = _mm_aesenc_si128(x2, sk[5]);
+ x3 = _mm_aesenc_si128(x3, sk[5]);
+ x0 = _mm_aesenc_si128(x0, sk[6]);
+ x1 = _mm_aesenc_si128(x1, sk[6]);
+ x2 = _mm_aesenc_si128(x2, sk[6]);
+ x3 = _mm_aesenc_si128(x3, sk[6]);
+ x0 = _mm_aesenc_si128(x0, sk[7]);
+ x1 = _mm_aesenc_si128(x1, sk[7]);
+ x2 = _mm_aesenc_si128(x2, sk[7]);
+ x3 = _mm_aesenc_si128(x3, sk[7]);
+ x0 = _mm_aesenc_si128(x0, sk[8]);
+ x1 = _mm_aesenc_si128(x1, sk[8]);
+ x2 = _mm_aesenc_si128(x2, sk[8]);
+ x3 = _mm_aesenc_si128(x3, sk[8]);
+ x0 = _mm_aesenc_si128(x0, sk[9]);
+ x1 = _mm_aesenc_si128(x1, sk[9]);
+ x2 = _mm_aesenc_si128(x2, sk[9]);
+ x3 = _mm_aesenc_si128(x3, sk[9]);
+ if (num_rounds == 10) {
+ x0 = _mm_aesenclast_si128(x0, sk[10]);
+ x1 = _mm_aesenclast_si128(x1, sk[10]);
+ x2 = _mm_aesenclast_si128(x2, sk[10]);
+ x3 = _mm_aesenclast_si128(x3, sk[10]);
+ } else if (num_rounds == 12) {
+ x0 = _mm_aesenc_si128(x0, sk[10]);
+ x1 = _mm_aesenc_si128(x1, sk[10]);
+ x2 = _mm_aesenc_si128(x2, sk[10]);
+ x3 = _mm_aesenc_si128(x3, sk[10]);
+ x0 = _mm_aesenc_si128(x0, sk[11]);
+ x1 = _mm_aesenc_si128(x1, sk[11]);
+ x2 = _mm_aesenc_si128(x2, sk[11]);
+ x3 = _mm_aesenc_si128(x3, sk[11]);
+ x0 = _mm_aesenclast_si128(x0, sk[12]);
+ x1 = _mm_aesenclast_si128(x1, sk[12]);
+ x2 = _mm_aesenclast_si128(x2, sk[12]);
+ x3 = _mm_aesenclast_si128(x3, sk[12]);
+ } else {
+ x0 = _mm_aesenc_si128(x0, sk[10]);
+ x1 = _mm_aesenc_si128(x1, sk[10]);
+ x2 = _mm_aesenc_si128(x2, sk[10]);
+ x3 = _mm_aesenc_si128(x3, sk[10]);
+ x0 = _mm_aesenc_si128(x0, sk[11]);
+ x1 = _mm_aesenc_si128(x1, sk[11]);
+ x2 = _mm_aesenc_si128(x2, sk[11]);
+ x3 = _mm_aesenc_si128(x3, sk[11]);
+ x0 = _mm_aesenc_si128(x0, sk[12]);
+ x1 = _mm_aesenc_si128(x1, sk[12]);
+ x2 = _mm_aesenc_si128(x2, sk[12]);
+ x3 = _mm_aesenc_si128(x3, sk[12]);
+ x0 = _mm_aesenc_si128(x0, sk[13]);
+ x1 = _mm_aesenc_si128(x1, sk[13]);
+ x2 = _mm_aesenc_si128(x2, sk[13]);
+ x3 = _mm_aesenc_si128(x3, sk[13]);
+ x0 = _mm_aesenclast_si128(x0, sk[14]);
+ x1 = _mm_aesenclast_si128(x1, sk[14]);
+ x2 = _mm_aesenclast_si128(x2, sk[14]);
+ x3 = _mm_aesenclast_si128(x3, sk[14]);
+ }
+ if (len >= 64) {
+ x0 = _mm_xor_si128(x0,
+ _mm_loadu_si128((void *)(buf + 0)));
+ x1 = _mm_xor_si128(x1,
+ _mm_loadu_si128((void *)(buf + 16)));
+ x2 = _mm_xor_si128(x2,
+ _mm_loadu_si128((void *)(buf + 32)));
+ x3 = _mm_xor_si128(x3,
+ _mm_loadu_si128((void *)(buf + 48)));
+ _mm_storeu_si128((void *)(buf + 0), x0);
+ _mm_storeu_si128((void *)(buf + 16), x1);
+ _mm_storeu_si128((void *)(buf + 32), x2);
+ _mm_storeu_si128((void *)(buf + 48), x3);
+ buf += 64;
+ len -= 64;
+ } else {
+ unsigned char tmp[64];
+
+ _mm_storeu_si128((void *)(tmp + 0), x0);
+ _mm_storeu_si128((void *)(tmp + 16), x1);
+ _mm_storeu_si128((void *)(tmp + 32), x2);
+ _mm_storeu_si128((void *)(tmp + 48), x3);
+ for (u = 0; u < len; u ++) {
+ buf[u] ^= tmp[u];
+ }
+ switch (len) {
+ case 16:
+ ivx0 = ivx1;
+ break;
+ case 32:
+ ivx0 = ivx2;
+ break;
+ case 48:
+ ivx0 = ivx3;
+ break;
+ }
+ break;
+ }
+
+ /*
+ * Add 4 to each counter value. For carry propagation
+ * into the upper 64-bit words, we would need to compare
+ * the results with 4, but SSE2+ has only _signed_
+ * comparisons. Instead, we mask out the low two bits,
+ * and check whether the remaining bits are zero.
+ */
+ ivx0 = _mm_add_epi64(ivx0, four);
+ ivx1 = _mm_add_epi64(ivx1, four);
+ ivx2 = _mm_add_epi64(ivx2, four);
+ ivx3 = _mm_add_epi64(ivx3, four);
+ ivx0 = _mm_sub_epi64(ivx0,
+ _mm_slli_si128(_mm_cmpeq_epi64(
+ _mm_and_si128(ivx0, notthree), zero), 8));
+ ivx1 = _mm_sub_epi64(ivx1,
+ _mm_slli_si128(_mm_cmpeq_epi64(
+ _mm_and_si128(ivx1, notthree), zero), 8));
+ ivx2 = _mm_sub_epi64(ivx2,
+ _mm_slli_si128(_mm_cmpeq_epi64(
+ _mm_and_si128(ivx2, notthree), zero), 8));
+ ivx3 = _mm_sub_epi64(ivx3,
+ _mm_slli_si128(_mm_cmpeq_epi64(
+ _mm_and_si128(ivx3, notthree), zero), 8));
+ }
+
+ /*
+ * Write back new counter value. The loop took care to put the
+ * right counter value in ivx0.
+ */
+ _mm_storeu_si128((void *)ctr, _mm_shuffle_epi8(ivx0, erev));
+}
+
+/* see bearssl_block.h */
+BR_TARGET("sse2,sse4.1,aes")
+void
+br_aes_x86ni_ctrcbc_mac(const br_aes_x86ni_ctrcbc_keys *ctx,
+ void *cbcmac, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ unsigned num_rounds;
+ __m128i sk[15], ivx;
+ unsigned u;
+
+ buf = data;
+ ivx = _mm_loadu_si128(cbcmac);
+ num_rounds = ctx->num_rounds;
+ for (u = 0; u <= num_rounds; u ++) {
+ sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4)));
+ }
+ while (len > 0) {
+ __m128i x;
+
+ x = _mm_xor_si128(_mm_loadu_si128((void *)buf), ivx);
+ x = _mm_xor_si128(x, sk[0]);
+ x = _mm_aesenc_si128(x, sk[1]);
+ x = _mm_aesenc_si128(x, sk[2]);
+ x = _mm_aesenc_si128(x, sk[3]);
+ x = _mm_aesenc_si128(x, sk[4]);
+ x = _mm_aesenc_si128(x, sk[5]);
+ x = _mm_aesenc_si128(x, sk[6]);
+ x = _mm_aesenc_si128(x, sk[7]);
+ x = _mm_aesenc_si128(x, sk[8]);
+ x = _mm_aesenc_si128(x, sk[9]);
+ if (num_rounds == 10) {
+ x = _mm_aesenclast_si128(x, sk[10]);
+ } else if (num_rounds == 12) {
+ x = _mm_aesenc_si128(x, sk[10]);
+ x = _mm_aesenc_si128(x, sk[11]);
+ x = _mm_aesenclast_si128(x, sk[12]);
+ } else {
+ x = _mm_aesenc_si128(x, sk[10]);
+ x = _mm_aesenc_si128(x, sk[11]);
+ x = _mm_aesenc_si128(x, sk[12]);
+ x = _mm_aesenc_si128(x, sk[13]);
+ x = _mm_aesenclast_si128(x, sk[14]);
+ }
+ ivx = x;
+ buf += 16;
+ len -= 16;
+ }
+ _mm_storeu_si128(cbcmac, ivx);
+}
+
+/* see bearssl_block.h */
+BR_TARGET("sse2,sse4.1,aes")
+void
+br_aes_x86ni_ctrcbc_encrypt(const br_aes_x86ni_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len)
+{
+ unsigned char *buf;
+ unsigned num_rounds;
+ __m128i sk[15];
+ __m128i ivx, cmx;
+ __m128i erev, zero, one;
+ unsigned u;
+ int first_iter;
+
+ num_rounds = ctx->num_rounds;
+ for (u = 0; u <= num_rounds; u ++) {
+ sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4)));
+ }
+
+ /*
+ * Some SSE2 constants.
+ */
+ erev = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15);
+ zero = _mm_setzero_si128();
+ one = _mm_set_epi64x(0, 1);
+
+ /*
+ * Decode the counter in big-endian.
+ */
+ ivx = _mm_shuffle_epi8(_mm_loadu_si128(ctr), erev);
+ cmx = _mm_loadu_si128(cbcmac);
+
+ buf = data;
+ first_iter = 1;
+ while (len > 0) {
+ __m128i dx, x0, x1;
+
+ /*
+ * Load initial values:
+ * dx encrypted block of data
+ * x0 counter (for CTR encryption)
+ * x1 input for CBC-MAC
+ */
+ dx = _mm_loadu_si128((void *)buf);
+ x0 = _mm_shuffle_epi8(ivx, erev);
+ x1 = cmx;
+
+ x0 = _mm_xor_si128(x0, sk[0]);
+ x1 = _mm_xor_si128(x1, sk[0]);
+ x0 = _mm_aesenc_si128(x0, sk[1]);
+ x1 = _mm_aesenc_si128(x1, sk[1]);
+ x0 = _mm_aesenc_si128(x0, sk[2]);
+ x1 = _mm_aesenc_si128(x1, sk[2]);
+ x0 = _mm_aesenc_si128(x0, sk[3]);
+ x1 = _mm_aesenc_si128(x1, sk[3]);
+ x0 = _mm_aesenc_si128(x0, sk[4]);
+ x1 = _mm_aesenc_si128(x1, sk[4]);
+ x0 = _mm_aesenc_si128(x0, sk[5]);
+ x1 = _mm_aesenc_si128(x1, sk[5]);
+ x0 = _mm_aesenc_si128(x0, sk[6]);
+ x1 = _mm_aesenc_si128(x1, sk[6]);
+ x0 = _mm_aesenc_si128(x0, sk[7]);
+ x1 = _mm_aesenc_si128(x1, sk[7]);
+ x0 = _mm_aesenc_si128(x0, sk[8]);
+ x1 = _mm_aesenc_si128(x1, sk[8]);
+ x0 = _mm_aesenc_si128(x0, sk[9]);
+ x1 = _mm_aesenc_si128(x1, sk[9]);
+ if (num_rounds == 10) {
+ x0 = _mm_aesenclast_si128(x0, sk[10]);
+ x1 = _mm_aesenclast_si128(x1, sk[10]);
+ } else if (num_rounds == 12) {
+ x0 = _mm_aesenc_si128(x0, sk[10]);
+ x1 = _mm_aesenc_si128(x1, sk[10]);
+ x0 = _mm_aesenc_si128(x0, sk[11]);
+ x1 = _mm_aesenc_si128(x1, sk[11]);
+ x0 = _mm_aesenclast_si128(x0, sk[12]);
+ x1 = _mm_aesenclast_si128(x1, sk[12]);
+ } else {
+ x0 = _mm_aesenc_si128(x0, sk[10]);
+ x1 = _mm_aesenc_si128(x1, sk[10]);
+ x0 = _mm_aesenc_si128(x0, sk[11]);
+ x1 = _mm_aesenc_si128(x1, sk[11]);
+ x0 = _mm_aesenc_si128(x0, sk[12]);
+ x1 = _mm_aesenc_si128(x1, sk[12]);
+ x0 = _mm_aesenc_si128(x0, sk[13]);
+ x1 = _mm_aesenc_si128(x1, sk[13]);
+ x0 = _mm_aesenclast_si128(x0, sk[14]);
+ x1 = _mm_aesenclast_si128(x1, sk[14]);
+ }
+
+ x0 = _mm_xor_si128(x0, dx);
+ if (first_iter) {
+ cmx = _mm_xor_si128(cmx, x0);
+ first_iter = 0;
+ } else {
+ cmx = _mm_xor_si128(x1, x0);
+ }
+ _mm_storeu_si128((void *)buf, x0);
+
+ buf += 16;
+ len -= 16;
+
+ /*
+ * Increment the counter value.
+ */
+ ivx = _mm_add_epi64(ivx, one);
+ ivx = _mm_sub_epi64(ivx,
+ _mm_slli_si128(_mm_cmpeq_epi64(ivx, zero), 8));
+
+ /*
+ * If this was the last iteration, then compute the
+ * extra block encryption to complete CBC-MAC.
+ */
+ if (len == 0) {
+ cmx = _mm_xor_si128(cmx, sk[0]);
+ cmx = _mm_aesenc_si128(cmx, sk[1]);
+ cmx = _mm_aesenc_si128(cmx, sk[2]);
+ cmx = _mm_aesenc_si128(cmx, sk[3]);
+ cmx = _mm_aesenc_si128(cmx, sk[4]);
+ cmx = _mm_aesenc_si128(cmx, sk[5]);
+ cmx = _mm_aesenc_si128(cmx, sk[6]);
+ cmx = _mm_aesenc_si128(cmx, sk[7]);
+ cmx = _mm_aesenc_si128(cmx, sk[8]);
+ cmx = _mm_aesenc_si128(cmx, sk[9]);
+ if (num_rounds == 10) {
+ cmx = _mm_aesenclast_si128(cmx, sk[10]);
+ } else if (num_rounds == 12) {
+ cmx = _mm_aesenc_si128(cmx, sk[10]);
+ cmx = _mm_aesenc_si128(cmx, sk[11]);
+ cmx = _mm_aesenclast_si128(cmx, sk[12]);
+ } else {
+ cmx = _mm_aesenc_si128(cmx, sk[10]);
+ cmx = _mm_aesenc_si128(cmx, sk[11]);
+ cmx = _mm_aesenc_si128(cmx, sk[12]);
+ cmx = _mm_aesenc_si128(cmx, sk[13]);
+ cmx = _mm_aesenclast_si128(cmx, sk[14]);
+ }
+ break;
+ }
+ }
+
+ /*
+ * Write back new counter value and CBC-MAC value.
+ */
+ _mm_storeu_si128(ctr, _mm_shuffle_epi8(ivx, erev));
+ _mm_storeu_si128(cbcmac, cmx);
+}
+
+/* see bearssl_block.h */
+BR_TARGET("sse2,sse4.1,aes")
+void
+br_aes_x86ni_ctrcbc_decrypt(const br_aes_x86ni_ctrcbc_keys *ctx,
+ void *ctr, void *cbcmac, void *data, size_t len)
+{
+ unsigned char *buf;
+ unsigned num_rounds;
+ __m128i sk[15];
+ __m128i ivx, cmx;
+ __m128i erev, zero, one;
+ unsigned u;
+
+ num_rounds = ctx->num_rounds;
+ for (u = 0; u <= num_rounds; u ++) {
+ sk[u] = _mm_loadu_si128((void *)(ctx->skey.skni + (u << 4)));
+ }
+
+ /*
+ * Some SSE2 constants.
+ */
+ erev = _mm_set_epi8(0, 1, 2, 3, 4, 5, 6, 7,
+ 8, 9, 10, 11, 12, 13, 14, 15);
+ zero = _mm_setzero_si128();
+ one = _mm_set_epi64x(0, 1);
+
+ /*
+ * Decode the counter in big-endian.
+ */
+ ivx = _mm_shuffle_epi8(_mm_loadu_si128(ctr), erev);
+ cmx = _mm_loadu_si128(cbcmac);
+
+ buf = data;
+ while (len > 0) {
+ __m128i dx, x0, x1;
+
+ /*
+ * Load initial values:
+ * dx encrypted block of data
+ * x0 counter (for CTR encryption)
+ * x1 input for CBC-MAC
+ */
+ dx = _mm_loadu_si128((void *)buf);
+ x0 = _mm_shuffle_epi8(ivx, erev);
+ x1 = _mm_xor_si128(cmx, dx);
+
+ x0 = _mm_xor_si128(x0, sk[0]);
+ x1 = _mm_xor_si128(x1, sk[0]);
+ x0 = _mm_aesenc_si128(x0, sk[1]);
+ x1 = _mm_aesenc_si128(x1, sk[1]);
+ x0 = _mm_aesenc_si128(x0, sk[2]);
+ x1 = _mm_aesenc_si128(x1, sk[2]);
+ x0 = _mm_aesenc_si128(x0, sk[3]);
+ x1 = _mm_aesenc_si128(x1, sk[3]);
+ x0 = _mm_aesenc_si128(x0, sk[4]);
+ x1 = _mm_aesenc_si128(x1, sk[4]);
+ x0 = _mm_aesenc_si128(x0, sk[5]);
+ x1 = _mm_aesenc_si128(x1, sk[5]);
+ x0 = _mm_aesenc_si128(x0, sk[6]);
+ x1 = _mm_aesenc_si128(x1, sk[6]);
+ x0 = _mm_aesenc_si128(x0, sk[7]);
+ x1 = _mm_aesenc_si128(x1, sk[7]);
+ x0 = _mm_aesenc_si128(x0, sk[8]);
+ x1 = _mm_aesenc_si128(x1, sk[8]);
+ x0 = _mm_aesenc_si128(x0, sk[9]);
+ x1 = _mm_aesenc_si128(x1, sk[9]);
+ if (num_rounds == 10) {
+ x0 = _mm_aesenclast_si128(x0, sk[10]);
+ x1 = _mm_aesenclast_si128(x1, sk[10]);
+ } else if (num_rounds == 12) {
+ x0 = _mm_aesenc_si128(x0, sk[10]);
+ x1 = _mm_aesenc_si128(x1, sk[10]);
+ x0 = _mm_aesenc_si128(x0, sk[11]);
+ x1 = _mm_aesenc_si128(x1, sk[11]);
+ x0 = _mm_aesenclast_si128(x0, sk[12]);
+ x1 = _mm_aesenclast_si128(x1, sk[12]);
+ } else {
+ x0 = _mm_aesenc_si128(x0, sk[10]);
+ x1 = _mm_aesenc_si128(x1, sk[10]);
+ x0 = _mm_aesenc_si128(x0, sk[11]);
+ x1 = _mm_aesenc_si128(x1, sk[11]);
+ x0 = _mm_aesenc_si128(x0, sk[12]);
+ x1 = _mm_aesenc_si128(x1, sk[12]);
+ x0 = _mm_aesenc_si128(x0, sk[13]);
+ x1 = _mm_aesenc_si128(x1, sk[13]);
+ x0 = _mm_aesenclast_si128(x0, sk[14]);
+ x1 = _mm_aesenclast_si128(x1, sk[14]);
+ }
+ x0 = _mm_xor_si128(x0, dx);
+ cmx = x1;
+ _mm_storeu_si128((void *)buf, x0);
+
+ buf += 16;
+ len -= 16;
+
+ /*
+ * Increment the counter value.
+ */
+ ivx = _mm_add_epi64(ivx, one);
+ ivx = _mm_sub_epi64(ivx,
+ _mm_slli_si128(_mm_cmpeq_epi64(ivx, zero), 8));
+ }
+
+ /*
+ * Write back new counter value and CBC-MAC value.
+ */
+ _mm_storeu_si128(ctr, _mm_shuffle_epi8(ivx, erev));
+ _mm_storeu_si128(cbcmac, cmx);
+}
+
+BR_TARGETS_X86_DOWN
+
+/* see bearssl_block.h */
+const br_block_ctrcbc_class br_aes_x86ni_ctrcbc_vtable = {
+ sizeof(br_aes_x86ni_ctrcbc_keys),
+ 16,
+ 4,
+ (void (*)(const br_block_ctrcbc_class **, const void *, size_t))
+ &br_aes_x86ni_ctrcbc_init,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, void *, size_t))
+ &br_aes_x86ni_ctrcbc_encrypt,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, void *, size_t))
+ &br_aes_x86ni_ctrcbc_decrypt,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, void *, size_t))
+ &br_aes_x86ni_ctrcbc_ctr,
+ (void (*)(const br_block_ctrcbc_class *const *,
+ void *, const void *, size_t))
+ &br_aes_x86ni_ctrcbc_mac
+};
+
+#else
+
+/* see bearssl_block.h */
+const br_block_ctrcbc_class *
+br_aes_x86ni_ctrcbc_get_vtable(void)
+{
+ return NULL;
+}
+
+#endif
diff --git a/contrib/bearssl/src/symcipher/chacha20_ct.c b/contrib/bearssl/src/symcipher/chacha20_ct.c
new file mode 100644
index 000000000000..9961eb119f21
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/chacha20_ct.c
@@ -0,0 +1,106 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+uint32_t
+br_chacha20_ct_run(const void *key,
+ const void *iv, uint32_t cc, void *data, size_t len)
+{
+ unsigned char *buf;
+ uint32_t kw[8], ivw[3];
+ size_t u;
+
+ static const uint32_t CW[] = {
+ 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
+ };
+
+ buf = data;
+ for (u = 0; u < 8; u ++) {
+ kw[u] = br_dec32le((const unsigned char *)key + (u << 2));
+ }
+ for (u = 0; u < 3; u ++) {
+ ivw[u] = br_dec32le((const unsigned char *)iv + (u << 2));
+ }
+ while (len > 0) {
+ uint32_t state[16];
+ int i;
+ size_t clen;
+ unsigned char tmp[64];
+
+ memcpy(&state[0], CW, sizeof CW);
+ memcpy(&state[4], kw, sizeof kw);
+ state[12] = cc;
+ memcpy(&state[13], ivw, sizeof ivw);
+ for (i = 0; i < 10; i ++) {
+
+#define QROUND(a, b, c, d) do { \
+ state[a] += state[b]; \
+ state[d] ^= state[a]; \
+ state[d] = (state[d] << 16) | (state[d] >> 16); \
+ state[c] += state[d]; \
+ state[b] ^= state[c]; \
+ state[b] = (state[b] << 12) | (state[b] >> 20); \
+ state[a] += state[b]; \
+ state[d] ^= state[a]; \
+ state[d] = (state[d] << 8) | (state[d] >> 24); \
+ state[c] += state[d]; \
+ state[b] ^= state[c]; \
+ state[b] = (state[b] << 7) | (state[b] >> 25); \
+ } while (0)
+
+ QROUND( 0, 4, 8, 12);
+ QROUND( 1, 5, 9, 13);
+ QROUND( 2, 6, 10, 14);
+ QROUND( 3, 7, 11, 15);
+ QROUND( 0, 5, 10, 15);
+ QROUND( 1, 6, 11, 12);
+ QROUND( 2, 7, 8, 13);
+ QROUND( 3, 4, 9, 14);
+
+#undef QROUND
+
+ }
+ for (u = 0; u < 4; u ++) {
+ br_enc32le(&tmp[u << 2], state[u] + CW[u]);
+ }
+ for (u = 4; u < 12; u ++) {
+ br_enc32le(&tmp[u << 2], state[u] + kw[u - 4]);
+ }
+ br_enc32le(&tmp[48], state[12] + cc);
+ for (u = 13; u < 16; u ++) {
+ br_enc32le(&tmp[u << 2], state[u] + ivw[u - 13]);
+ }
+
+ clen = len < 64 ? len : 64;
+ for (u = 0; u < clen; u ++) {
+ buf[u] ^= tmp[u];
+ }
+ buf += clen;
+ len -= clen;
+ cc ++;
+ }
+ return cc;
+}
diff --git a/contrib/bearssl/src/symcipher/chacha20_sse2.c b/contrib/bearssl/src/symcipher/chacha20_sse2.c
new file mode 100644
index 000000000000..92b4a4a83591
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/chacha20_sse2.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#define BR_ENABLE_INTRINSICS 1
+#include "inner.h"
+
+#if BR_SSE2
+
+/*
+ * This file contains a ChaCha20 implementation that leverages SSE2
+ * opcodes for better performance.
+ */
+
+/* see bearssl_block.h */
+br_chacha20_run
+br_chacha20_sse2_get(void)
+{
+ /*
+ * If using 64-bit mode, then SSE2 opcodes should be automatically
+ * available, since they are part of the ABI.
+ *
+ * In 32-bit mode, we use CPUID to detect the SSE2 feature.
+ */
+
+#if BR_amd64
+ return &br_chacha20_sse2_run;
+#else
+
+ /*
+ * SSE2 support is indicated by bit 26 in EDX.
+ */
+ if (br_cpuid(0, 0, 0, 0x04000000)) {
+ return &br_chacha20_sse2_run;
+ } else {
+ return 0;
+ }
+#endif
+}
+
+BR_TARGETS_X86_UP
+
+/* see bearssl_block.h */
+BR_TARGET("sse2")
+uint32_t
+br_chacha20_sse2_run(const void *key,
+ const void *iv, uint32_t cc, void *data, size_t len)
+{
+ unsigned char *buf;
+ uint32_t ivtmp[4];
+ __m128i kw0, kw1;
+ __m128i iw, cw;
+ __m128i one;
+
+ static const uint32_t CW[] = {
+ 0x61707865, 0x3320646e, 0x79622d32, 0x6b206574
+ };
+
+ buf = data;
+ kw0 = _mm_loadu_si128(key);
+ kw1 = _mm_loadu_si128((const void *)((const unsigned char *)key + 16));
+ ivtmp[0] = cc;
+ memcpy(ivtmp + 1, iv, 12);
+ iw = _mm_loadu_si128((const void *)ivtmp);
+ cw = _mm_loadu_si128((const void *)CW);
+ one = _mm_set_epi32(0, 0, 0, 1);
+
+ while (len > 0) {
+ /*
+ * sj contains state words 4*j to 4*j+3.
+ */
+ __m128i s0, s1, s2, s3;
+ int i;
+
+ s0 = cw;
+ s1 = kw0;
+ s2 = kw1;
+ s3 = iw;
+ for (i = 0; i < 10; i ++) {
+ /*
+ * Even round is straightforward application on
+ * the state words.
+ */
+ s0 = _mm_add_epi32(s0, s1);
+ s3 = _mm_xor_si128(s3, s0);
+ s3 = _mm_or_si128(
+ _mm_slli_epi32(s3, 16),
+ _mm_srli_epi32(s3, 16));
+
+ s2 = _mm_add_epi32(s2, s3);
+ s1 = _mm_xor_si128(s1, s2);
+ s1 = _mm_or_si128(
+ _mm_slli_epi32(s1, 12),
+ _mm_srli_epi32(s1, 20));
+
+ s0 = _mm_add_epi32(s0, s1);
+ s3 = _mm_xor_si128(s3, s0);
+ s3 = _mm_or_si128(
+ _mm_slli_epi32(s3, 8),
+ _mm_srli_epi32(s3, 24));
+
+ s2 = _mm_add_epi32(s2, s3);
+ s1 = _mm_xor_si128(s1, s2);
+ s1 = _mm_or_si128(
+ _mm_slli_epi32(s1, 7),
+ _mm_srli_epi32(s1, 25));
+
+ /*
+ * For the odd round, we must rotate some state
+ * words so that the computations apply on the
+ * right combinations of words.
+ */
+ s1 = _mm_shuffle_epi32(s1, 0x39);
+ s2 = _mm_shuffle_epi32(s2, 0x4E);
+ s3 = _mm_shuffle_epi32(s3, 0x93);
+
+ s0 = _mm_add_epi32(s0, s1);
+ s3 = _mm_xor_si128(s3, s0);
+ s3 = _mm_or_si128(
+ _mm_slli_epi32(s3, 16),
+ _mm_srli_epi32(s3, 16));
+
+ s2 = _mm_add_epi32(s2, s3);
+ s1 = _mm_xor_si128(s1, s2);
+ s1 = _mm_or_si128(
+ _mm_slli_epi32(s1, 12),
+ _mm_srli_epi32(s1, 20));
+
+ s0 = _mm_add_epi32(s0, s1);
+ s3 = _mm_xor_si128(s3, s0);
+ s3 = _mm_or_si128(
+ _mm_slli_epi32(s3, 8),
+ _mm_srli_epi32(s3, 24));
+
+ s2 = _mm_add_epi32(s2, s3);
+ s1 = _mm_xor_si128(s1, s2);
+ s1 = _mm_or_si128(
+ _mm_slli_epi32(s1, 7),
+ _mm_srli_epi32(s1, 25));
+
+ /*
+ * After the odd round, we rotate back the values
+ * to undo the rotate at the start of the odd round.
+ */
+ s1 = _mm_shuffle_epi32(s1, 0x93);
+ s2 = _mm_shuffle_epi32(s2, 0x4E);
+ s3 = _mm_shuffle_epi32(s3, 0x39);
+ }
+
+ /*
+ * Addition with the initial state.
+ */
+ s0 = _mm_add_epi32(s0, cw);
+ s1 = _mm_add_epi32(s1, kw0);
+ s2 = _mm_add_epi32(s2, kw1);
+ s3 = _mm_add_epi32(s3, iw);
+
+ /*
+ * Increment block counter.
+ */
+ iw = _mm_add_epi32(iw, one);
+
+ /*
+ * XOR final state with the data.
+ */
+ if (len < 64) {
+ unsigned char tmp[64];
+ size_t u;
+
+ _mm_storeu_si128((void *)(tmp + 0), s0);
+ _mm_storeu_si128((void *)(tmp + 16), s1);
+ _mm_storeu_si128((void *)(tmp + 32), s2);
+ _mm_storeu_si128((void *)(tmp + 48), s3);
+ for (u = 0; u < len; u ++) {
+ buf[u] ^= tmp[u];
+ }
+ break;
+ } else {
+ __m128i b0, b1, b2, b3;
+
+ b0 = _mm_loadu_si128((const void *)(buf + 0));
+ b1 = _mm_loadu_si128((const void *)(buf + 16));
+ b2 = _mm_loadu_si128((const void *)(buf + 32));
+ b3 = _mm_loadu_si128((const void *)(buf + 48));
+ b0 = _mm_xor_si128(b0, s0);
+ b1 = _mm_xor_si128(b1, s1);
+ b2 = _mm_xor_si128(b2, s2);
+ b3 = _mm_xor_si128(b3, s3);
+ _mm_storeu_si128((void *)(buf + 0), b0);
+ _mm_storeu_si128((void *)(buf + 16), b1);
+ _mm_storeu_si128((void *)(buf + 32), b2);
+ _mm_storeu_si128((void *)(buf + 48), b3);
+ buf += 64;
+ len -= 64;
+ }
+ }
+
+ /*
+ * _mm_extract_epi32() requires SSE4.1. We prefer to stick to
+ * raw SSE2, thus we use _mm_extract_epi16().
+ */
+ return (uint32_t)_mm_extract_epi16(iw, 0)
+ | ((uint32_t)_mm_extract_epi16(iw, 1) << 16);
+}
+
+BR_TARGETS_X86_DOWN
+
+#else
+
+/* see bearssl_block.h */
+br_chacha20_run
+br_chacha20_sse2_get(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/contrib/bearssl/src/symcipher/des_ct.c b/contrib/bearssl/src/symcipher/des_ct.c
new file mode 100644
index 000000000000..581c0ab29455
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/des_ct.c
@@ -0,0 +1,411 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * During key schedule, we need to apply bit extraction PC-2 then permute
+ * things into our bitslice representation. PC-2 extracts 48 bits out
+ * of two 28-bit words (kl and kr), and we store these bits into two
+ * 32-bit words sk0 and sk1.
+ *
+ * -- bit 16+x of sk0 comes from bit QL0[x] of kl
+ * -- bit x of sk0 comes from bit QR0[x] of kr
+ * -- bit 16+x of sk1 comes from bit QL1[x] of kl
+ * -- bit x of sk1 comes from bit QR1[x] of kr
+ */
+
+static const unsigned char QL0[] = {
+ 17, 4, 27, 23, 13, 22, 7, 18,
+ 16, 24, 2, 20, 1, 8, 15, 26
+};
+
+static const unsigned char QR0[] = {
+ 25, 19, 9, 1, 5, 11, 23, 8,
+ 17, 0, 22, 3, 6, 20, 27, 24
+};
+
+static const unsigned char QL1[] = {
+ 28, 28, 14, 11, 28, 28, 25, 0,
+ 28, 28, 5, 9, 28, 28, 12, 21
+};
+
+static const unsigned char QR1[] = {
+ 28, 28, 15, 4, 28, 28, 26, 16,
+ 28, 28, 12, 7, 28, 28, 10, 14
+};
+
+/*
+ * 32-bit rotation. The C compiler is supposed to recognize it as a
+ * rotation and use the local architecture rotation opcode (if available).
+ */
+static inline uint32_t
+rotl(uint32_t x, int n)
+{
+ return (x << n) | (x >> (32 - n));
+}
+
+/*
+ * Compute key schedule for 8 key bytes (produces 32 subkey words).
+ */
+static void
+keysched_unit(uint32_t *skey, const void *key)
+{
+ int i;
+
+ br_des_keysched_unit(skey, key);
+
+ /*
+ * Apply PC-2 + bitslicing.
+ */
+ for (i = 0; i < 16; i ++) {
+ uint32_t kl, kr, sk0, sk1;
+ int j;
+
+ kl = skey[(i << 1) + 0];
+ kr = skey[(i << 1) + 1];
+ sk0 = 0;
+ sk1 = 0;
+ for (j = 0; j < 16; j ++) {
+ sk0 <<= 1;
+ sk1 <<= 1;
+ sk0 |= ((kl >> QL0[j]) & (uint32_t)1) << 16;
+ sk0 |= (kr >> QR0[j]) & (uint32_t)1;
+ sk1 |= ((kl >> QL1[j]) & (uint32_t)1) << 16;
+ sk1 |= (kr >> QR1[j]) & (uint32_t)1;
+ }
+
+ skey[(i << 1) + 0] = sk0;
+ skey[(i << 1) + 1] = sk1;
+ }
+
+#if 0
+ /*
+ * Speed-optimized version for PC-2 + bitslicing.
+ * (Unused. Kept for reference only.)
+ */
+ sk0 = kl & (uint32_t)0x00100000;
+ sk0 |= (kl & (uint32_t)0x08008000) << 2;
+ sk0 |= (kl & (uint32_t)0x00400000) << 4;
+ sk0 |= (kl & (uint32_t)0x00800000) << 5;
+ sk0 |= (kl & (uint32_t)0x00040000) << 6;
+ sk0 |= (kl & (uint32_t)0x00010000) << 7;
+ sk0 |= (kl & (uint32_t)0x00000100) << 10;
+ sk0 |= (kl & (uint32_t)0x00022000) << 14;
+ sk0 |= (kl & (uint32_t)0x00000082) << 18;
+ sk0 |= (kl & (uint32_t)0x00000004) << 19;
+ sk0 |= (kl & (uint32_t)0x04000000) >> 10;
+ sk0 |= (kl & (uint32_t)0x00000010) << 26;
+ sk0 |= (kl & (uint32_t)0x01000000) >> 2;
+
+ sk0 |= kr & (uint32_t)0x00000100;
+ sk0 |= (kr & (uint32_t)0x00000008) << 1;
+ sk0 |= (kr & (uint32_t)0x00000200) << 4;
+ sk0 |= rotl(kr & (uint32_t)0x08000021, 6);
+ sk0 |= (kr & (uint32_t)0x01000000) >> 24;
+ sk0 |= (kr & (uint32_t)0x00000002) << 11;
+ sk0 |= (kr & (uint32_t)0x00100000) >> 18;
+ sk0 |= (kr & (uint32_t)0x00400000) >> 17;
+ sk0 |= (kr & (uint32_t)0x00800000) >> 14;
+ sk0 |= (kr & (uint32_t)0x02020000) >> 10;
+ sk0 |= (kr & (uint32_t)0x00080000) >> 5;
+ sk0 |= (kr & (uint32_t)0x00000040) >> 3;
+ sk0 |= (kr & (uint32_t)0x00000800) >> 1;
+
+ sk1 = kl & (uint32_t)0x02000000;
+ sk1 |= (kl & (uint32_t)0x00001000) << 5;
+ sk1 |= (kl & (uint32_t)0x00000200) << 11;
+ sk1 |= (kl & (uint32_t)0x00004000) << 15;
+ sk1 |= (kl & (uint32_t)0x00000020) << 16;
+ sk1 |= (kl & (uint32_t)0x00000800) << 17;
+ sk1 |= (kl & (uint32_t)0x00000001) << 24;
+ sk1 |= (kl & (uint32_t)0x00200000) >> 5;
+
+ sk1 |= (kr & (uint32_t)0x00000010) << 8;
+ sk1 |= (kr & (uint32_t)0x04000000) >> 17;
+ sk1 |= (kr & (uint32_t)0x00004000) >> 14;
+ sk1 |= (kr & (uint32_t)0x00000400) >> 9;
+ sk1 |= (kr & (uint32_t)0x00010000) >> 8;
+ sk1 |= (kr & (uint32_t)0x00001000) >> 7;
+ sk1 |= (kr & (uint32_t)0x00000080) >> 3;
+ sk1 |= (kr & (uint32_t)0x00008000) >> 2;
+#endif
+}
+
+/* see inner.h */
+unsigned
+br_des_ct_keysched(uint32_t *skey, const void *key, size_t key_len)
+{
+ switch (key_len) {
+ case 8:
+ keysched_unit(skey, key);
+ return 1;
+ case 16:
+ keysched_unit(skey, key);
+ keysched_unit(skey + 32, (const unsigned char *)key + 8);
+ br_des_rev_skey(skey + 32);
+ memcpy(skey + 64, skey, 32 * sizeof *skey);
+ return 3;
+ default:
+ keysched_unit(skey, key);
+ keysched_unit(skey + 32, (const unsigned char *)key + 8);
+ br_des_rev_skey(skey + 32);
+ keysched_unit(skey + 64, (const unsigned char *)key + 16);
+ return 3;
+ }
+}
+
+/*
+ * DES confusion function. This function performs expansion E (32 to
+ * 48 bits), XOR with subkey, S-boxes, and permutation P.
+ */
+static inline uint32_t
+Fconf(uint32_t r0, const uint32_t *sk)
+{
+ /*
+ * Each 6->4 S-box is virtually turned into four 6->1 boxes; we
+ * thus end up with 32 boxes that we call "T-boxes" here. We will
+ * evaluate them with bitslice code.
+ *
+ * Each T-box is a circuit of multiplexers (sort of) and thus
+ * takes 70 inputs: the 6 actual T-box inputs, and 64 constants
+ * that describe the T-box output for all combinations of the
+ * 6 inputs. With this model, all T-boxes are identical (with
+ * distinct inputs) and thus can be executed in parallel with
+ * bitslice code.
+ *
+ * T-boxes are numbered from 0 to 31, in least-to-most
+ * significant order. Thus, S-box S1 corresponds to T-boxes 31,
+ * 30, 29 and 28, in that order. T-box 'n' is computed with the
+ * bits at rank 'n' in the 32-bit words.
+ *
+ * Words x0 to x5 contain the T-box inputs 0 to 5.
+ */
+ uint32_t x0, x1, x2, x3, x4, x5, z0;
+ uint32_t y0, y1, y2, y3, y4, y5, y6, y7, y8, y9;
+ uint32_t y10, y11, y12, y13, y14, y15, y16, y17, y18, y19;
+ uint32_t y20, y21, y22, y23, y24, y25, y26, y27, y28, y29;
+ uint32_t y30;
+
+ /*
+ * Spread input bits over the 6 input words x*.
+ */
+ x1 = r0 & (uint32_t)0x11111111;
+ x2 = (r0 >> 1) & (uint32_t)0x11111111;
+ x3 = (r0 >> 2) & (uint32_t)0x11111111;
+ x4 = (r0 >> 3) & (uint32_t)0x11111111;
+ x1 = (x1 << 4) - x1;
+ x2 = (x2 << 4) - x2;
+ x3 = (x3 << 4) - x3;
+ x4 = (x4 << 4) - x4;
+ x0 = (x4 << 4) | (x4 >> 28);
+ x5 = (x1 >> 4) | (x1 << 28);
+
+ /*
+ * XOR with the subkey for this round.
+ */
+ x0 ^= sk[0];
+ x1 ^= sk[1];
+ x2 ^= sk[2];
+ x3 ^= sk[3];
+ x4 ^= sk[4];
+ x5 ^= sk[5];
+
+ /*
+ * The T-boxes are done in parallel, since they all use a
+ * "tree of multiplexer". We use "fake multiplexers":
+ *
+ * y = a ^ (x & b)
+ *
+ * computes y as either 'a' (if x == 0) or 'a ^ b' (if x == 1).
+ */
+ y0 = (uint32_t)0xEFA72C4D ^ (x0 & (uint32_t)0xEC7AC69C);
+ y1 = (uint32_t)0xAEAAEDFF ^ (x0 & (uint32_t)0x500FB821);
+ y2 = (uint32_t)0x37396665 ^ (x0 & (uint32_t)0x40EFA809);
+ y3 = (uint32_t)0x68D7B833 ^ (x0 & (uint32_t)0xA5EC0B28);
+ y4 = (uint32_t)0xC9C755BB ^ (x0 & (uint32_t)0x252CF820);
+ y5 = (uint32_t)0x73FC3606 ^ (x0 & (uint32_t)0x40205801);
+ y6 = (uint32_t)0xA2A0A918 ^ (x0 & (uint32_t)0xE220F929);
+ y7 = (uint32_t)0x8222BD90 ^ (x0 & (uint32_t)0x44A3F9E1);
+ y8 = (uint32_t)0xD6B6AC77 ^ (x0 & (uint32_t)0x794F104A);
+ y9 = (uint32_t)0x3069300C ^ (x0 & (uint32_t)0x026F320B);
+ y10 = (uint32_t)0x6CE0D5CC ^ (x0 & (uint32_t)0x7640B01A);
+ y11 = (uint32_t)0x59A9A22D ^ (x0 & (uint32_t)0x238F1572);
+ y12 = (uint32_t)0xAC6D0BD4 ^ (x0 & (uint32_t)0x7A63C083);
+ y13 = (uint32_t)0x21C83200 ^ (x0 & (uint32_t)0x11CCA000);
+ y14 = (uint32_t)0xA0E62188 ^ (x0 & (uint32_t)0x202F69AA);
+ /* y15 = (uint32_t)0x00000000 ^ (x0 & (uint32_t)0x00000000); */
+ y16 = (uint32_t)0xAF7D655A ^ (x0 & (uint32_t)0x51B33BE9);
+ y17 = (uint32_t)0xF0168AA3 ^ (x0 & (uint32_t)0x3B0FE8AE);
+ y18 = (uint32_t)0x90AA30C6 ^ (x0 & (uint32_t)0x90BF8816);
+ y19 = (uint32_t)0x5AB2750A ^ (x0 & (uint32_t)0x09E34F9B);
+ y20 = (uint32_t)0x5391BE65 ^ (x0 & (uint32_t)0x0103BE88);
+ y21 = (uint32_t)0x93372BAF ^ (x0 & (uint32_t)0x49AC8E25);
+ y22 = (uint32_t)0xF288210C ^ (x0 & (uint32_t)0x922C313D);
+ y23 = (uint32_t)0x920AF5C0 ^ (x0 & (uint32_t)0x70EF31B0);
+ y24 = (uint32_t)0x63D312C0 ^ (x0 & (uint32_t)0x6A707100);
+ y25 = (uint32_t)0x537B3006 ^ (x0 & (uint32_t)0xB97C9011);
+ y26 = (uint32_t)0xA2EFB0A5 ^ (x0 & (uint32_t)0xA320C959);
+ y27 = (uint32_t)0xBC8F96A5 ^ (x0 & (uint32_t)0x6EA0AB4A);
+ y28 = (uint32_t)0xFAD176A5 ^ (x0 & (uint32_t)0x6953DDF8);
+ y29 = (uint32_t)0x665A14A3 ^ (x0 & (uint32_t)0xF74F3E2B);
+ y30 = (uint32_t)0xF2EFF0CC ^ (x0 & (uint32_t)0xF0306CAD);
+ /* y31 = (uint32_t)0x00000000 ^ (x0 & (uint32_t)0x00000000); */
+
+ y0 = y0 ^ (x1 & y1);
+ y1 = y2 ^ (x1 & y3);
+ y2 = y4 ^ (x1 & y5);
+ y3 = y6 ^ (x1 & y7);
+ y4 = y8 ^ (x1 & y9);
+ y5 = y10 ^ (x1 & y11);
+ y6 = y12 ^ (x1 & y13);
+ y7 = y14; /* was: y14 ^ (x1 & y15) */
+ y8 = y16 ^ (x1 & y17);
+ y9 = y18 ^ (x1 & y19);
+ y10 = y20 ^ (x1 & y21);
+ y11 = y22 ^ (x1 & y23);
+ y12 = y24 ^ (x1 & y25);
+ y13 = y26 ^ (x1 & y27);
+ y14 = y28 ^ (x1 & y29);
+ y15 = y30; /* was: y30 ^ (x1 & y31) */
+
+ y0 = y0 ^ (x2 & y1);
+ y1 = y2 ^ (x2 & y3);
+ y2 = y4 ^ (x2 & y5);
+ y3 = y6 ^ (x2 & y7);
+ y4 = y8 ^ (x2 & y9);
+ y5 = y10 ^ (x2 & y11);
+ y6 = y12 ^ (x2 & y13);
+ y7 = y14 ^ (x2 & y15);
+
+ y0 = y0 ^ (x3 & y1);
+ y1 = y2 ^ (x3 & y3);
+ y2 = y4 ^ (x3 & y5);
+ y3 = y6 ^ (x3 & y7);
+
+ y0 = y0 ^ (x4 & y1);
+ y1 = y2 ^ (x4 & y3);
+
+ y0 = y0 ^ (x5 & y1);
+
+ /*
+ * The P permutation:
+ * -- Each bit move is converted into a mask + left rotation.
+ * -- Rotations that use the same movement are coalesced together.
+ * -- Left and right shifts are used as alternatives to a rotation
+ * where appropriate (this will help architectures that do not have
+ * a rotation opcode).
+ */
+ z0 = (y0 & (uint32_t)0x00000004) << 3;
+ z0 |= (y0 & (uint32_t)0x00004000) << 4;
+ z0 |= rotl(y0 & 0x12020120, 5);
+ z0 |= (y0 & (uint32_t)0x00100000) << 6;
+ z0 |= (y0 & (uint32_t)0x00008000) << 9;
+ z0 |= (y0 & (uint32_t)0x04000000) >> 22;
+ z0 |= (y0 & (uint32_t)0x00000001) << 11;
+ z0 |= rotl(y0 & 0x20000200, 12);
+ z0 |= (y0 & (uint32_t)0x00200000) >> 19;
+ z0 |= (y0 & (uint32_t)0x00000040) << 14;
+ z0 |= (y0 & (uint32_t)0x00010000) << 15;
+ z0 |= (y0 & (uint32_t)0x00000002) << 16;
+ z0 |= rotl(y0 & 0x40801800, 17);
+ z0 |= (y0 & (uint32_t)0x00080000) >> 13;
+ z0 |= (y0 & (uint32_t)0x00000010) << 21;
+ z0 |= (y0 & (uint32_t)0x01000000) >> 10;
+ z0 |= rotl(y0 & 0x88000008, 24);
+ z0 |= (y0 & (uint32_t)0x00000480) >> 7;
+ z0 |= (y0 & (uint32_t)0x00442000) >> 6;
+ return z0;
+}
+
+/*
+ * Process one block through 16 successive rounds, omitting the swap
+ * in the final round.
+ */
+static void
+process_block_unit(uint32_t *pl, uint32_t *pr, const uint32_t *sk_exp)
+{
+ int i;
+ uint32_t l, r;
+
+ l = *pl;
+ r = *pr;
+ for (i = 0; i < 16; i ++) {
+ uint32_t t;
+
+ t = l ^ Fconf(r, sk_exp);
+ l = r;
+ r = t;
+ sk_exp += 6;
+ }
+ *pl = r;
+ *pr = l;
+}
+
+/* see inner.h */
+void
+br_des_ct_process_block(unsigned num_rounds,
+ const uint32_t *sk_exp, void *block)
+{
+ unsigned char *buf;
+ uint32_t l, r;
+
+ buf = block;
+ l = br_dec32be(buf);
+ r = br_dec32be(buf + 4);
+ br_des_do_IP(&l, &r);
+ while (num_rounds -- > 0) {
+ process_block_unit(&l, &r, sk_exp);
+ sk_exp += 96;
+ }
+ br_des_do_invIP(&l, &r);
+ br_enc32be(buf, l);
+ br_enc32be(buf + 4, r);
+}
+
+/* see inner.h */
+void
+br_des_ct_skey_expand(uint32_t *sk_exp,
+ unsigned num_rounds, const uint32_t *skey)
+{
+ num_rounds <<= 4;
+ while (num_rounds -- > 0) {
+ uint32_t v, w0, w1, w2, w3;
+
+ v = *skey ++;
+ w0 = v & 0x11111111;
+ w1 = (v >> 1) & 0x11111111;
+ w2 = (v >> 2) & 0x11111111;
+ w3 = (v >> 3) & 0x11111111;
+ *sk_exp ++ = (w0 << 4) - w0;
+ *sk_exp ++ = (w1 << 4) - w1;
+ *sk_exp ++ = (w2 << 4) - w2;
+ *sk_exp ++ = (w3 << 4) - w3;
+ v = *skey ++;
+ w0 = v & 0x11111111;
+ w1 = (v >> 1) & 0x11111111;
+ *sk_exp ++ = (w0 << 4) - w0;
+ *sk_exp ++ = (w1 << 4) - w1;
+ }
+}
diff --git a/contrib/bearssl/src/symcipher/des_ct_cbcdec.c b/contrib/bearssl/src/symcipher/des_ct_cbcdec.c
new file mode 100644
index 000000000000..d208a3d2a685
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/des_ct_cbcdec.c
@@ -0,0 +1,87 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_des_ct_cbcdec_init(br_des_ct_cbcdec_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_des_ct_cbcdec_vtable;
+ ctx->num_rounds = br_des_ct_keysched(ctx->skey, key, len);
+ if (len == 8) {
+ br_des_rev_skey(ctx->skey);
+ } else {
+ int i;
+
+ for (i = 0; i < 48; i += 2) {
+ uint32_t t;
+
+ t = ctx->skey[i];
+ ctx->skey[i] = ctx->skey[94 - i];
+ ctx->skey[94 - i] = t;
+ t = ctx->skey[i + 1];
+ ctx->skey[i + 1] = ctx->skey[95 - i];
+ ctx->skey[95 - i] = t;
+ }
+ }
+}
+
+/* see bearssl_block.h */
+void
+br_des_ct_cbcdec_run(const br_des_ct_cbcdec_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+ uint32_t sk_exp[288];
+
+ br_des_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+ ivbuf = iv;
+ buf = data;
+ while (len > 0) {
+ unsigned char tmp[8];
+ int i;
+
+ memcpy(tmp, buf, 8);
+ br_des_ct_process_block(ctx->num_rounds, sk_exp, buf);
+ for (i = 0; i < 8; i ++) {
+ buf[i] ^= ivbuf[i];
+ }
+ memcpy(ivbuf, tmp, 8);
+ buf += 8;
+ len -= 8;
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class br_des_ct_cbcdec_vtable = {
+ sizeof(br_des_ct_cbcdec_keys),
+ 8,
+ 3,
+ (void (*)(const br_block_cbcdec_class **, const void *, size_t))
+ &br_des_ct_cbcdec_init,
+ (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t))
+ &br_des_ct_cbcdec_run
+};
diff --git a/contrib/bearssl/src/symcipher/des_ct_cbcenc.c b/contrib/bearssl/src/symcipher/des_ct_cbcenc.c
new file mode 100644
index 000000000000..4b3610e0796d
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/des_ct_cbcenc.c
@@ -0,0 +1,69 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_des_ct_cbcenc_init(br_des_ct_cbcenc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_des_ct_cbcenc_vtable;
+ ctx->num_rounds = br_des_ct_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_des_ct_cbcenc_run(const br_des_ct_cbcenc_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+ uint32_t sk_exp[288];
+
+ br_des_ct_skey_expand(sk_exp, ctx->num_rounds, ctx->skey);
+ ivbuf = iv;
+ buf = data;
+ while (len > 0) {
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ buf[i] ^= ivbuf[i];
+ }
+ br_des_ct_process_block(ctx->num_rounds, sk_exp, buf);
+ memcpy(ivbuf, buf, 8);
+ buf += 8;
+ len -= 8;
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class br_des_ct_cbcenc_vtable = {
+ sizeof(br_des_ct_cbcenc_keys),
+ 8,
+ 3,
+ (void (*)(const br_block_cbcenc_class **, const void *, size_t))
+ &br_des_ct_cbcenc_init,
+ (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t))
+ &br_des_ct_cbcenc_run
+};
diff --git a/contrib/bearssl/src/symcipher/des_support.c b/contrib/bearssl/src/symcipher/des_support.c
new file mode 100644
index 000000000000..37f6db32d36c
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/des_support.c
@@ -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 "inner.h"
+
+/* see inner.h */
+void
+br_des_do_IP(uint32_t *xl, uint32_t *xr)
+{
+ /*
+ * Permutation algorithm is initially from Richard Outerbridge;
+ * implementation here is adapted from Crypto++ "des.cpp" file
+ * (which is in public domain).
+ */
+ uint32_t l, r, t;
+
+ l = *xl;
+ r = *xr;
+ t = ((l >> 4) ^ r) & (uint32_t)0x0F0F0F0F;
+ r ^= t;
+ l ^= t << 4;
+ t = ((l >> 16) ^ r) & (uint32_t)0x0000FFFF;
+ r ^= t;
+ l ^= t << 16;
+ t = ((r >> 2) ^ l) & (uint32_t)0x33333333;
+ l ^= t;
+ r ^= t << 2;
+ t = ((r >> 8) ^ l) & (uint32_t)0x00FF00FF;
+ l ^= t;
+ r ^= t << 8;
+ t = ((l >> 1) ^ r) & (uint32_t)0x55555555;
+ r ^= t;
+ l ^= t << 1;
+ *xl = l;
+ *xr = r;
+}
+
+/* see inner.h */
+void
+br_des_do_invIP(uint32_t *xl, uint32_t *xr)
+{
+ /*
+ * See br_des_do_IP().
+ */
+ uint32_t l, r, t;
+
+ l = *xl;
+ r = *xr;
+ t = ((l >> 1) ^ r) & 0x55555555;
+ r ^= t;
+ l ^= t << 1;
+ t = ((r >> 8) ^ l) & 0x00FF00FF;
+ l ^= t;
+ r ^= t << 8;
+ t = ((r >> 2) ^ l) & 0x33333333;
+ l ^= t;
+ r ^= t << 2;
+ t = ((l >> 16) ^ r) & 0x0000FFFF;
+ r ^= t;
+ l ^= t << 16;
+ t = ((l >> 4) ^ r) & 0x0F0F0F0F;
+ r ^= t;
+ l ^= t << 4;
+ *xl = l;
+ *xr = r;
+}
+
+/* see inner.h */
+void
+br_des_keysched_unit(uint32_t *skey, const void *key)
+{
+ uint32_t xl, xr, kl, kr;
+ int i;
+
+ xl = br_dec32be(key);
+ xr = br_dec32be((const unsigned char *)key + 4);
+
+ /*
+ * Permutation PC-1 is quite similar to the IP permutation.
+ * Definition of IP (in FIPS 46-3 notations) is:
+ * 58 50 42 34 26 18 10 2
+ * 60 52 44 36 28 20 12 4
+ * 62 54 46 38 30 22 14 6
+ * 64 56 48 40 32 24 16 8
+ * 57 49 41 33 25 17 9 1
+ * 59 51 43 35 27 19 11 3
+ * 61 53 45 37 29 21 13 5
+ * 63 55 47 39 31 23 15 7
+ *
+ * Definition of PC-1 is:
+ * 57 49 41 33 25 17 9 1
+ * 58 50 42 34 26 18 10 2
+ * 59 51 43 35 27 19 11 3
+ * 60 52 44 36
+ * 63 55 47 39 31 23 15 7
+ * 62 54 46 38 30 22 14 6
+ * 61 53 45 37 29 21 13 5
+ * 28 20 12 4
+ */
+ br_des_do_IP(&xl, &xr);
+ kl = ((xr & (uint32_t)0xFF000000) >> 4)
+ | ((xl & (uint32_t)0xFF000000) >> 12)
+ | ((xr & (uint32_t)0x00FF0000) >> 12)
+ | ((xl & (uint32_t)0x00FF0000) >> 20);
+ kr = ((xr & (uint32_t)0x000000FF) << 20)
+ | ((xl & (uint32_t)0x0000FF00) << 4)
+ | ((xr & (uint32_t)0x0000FF00) >> 4)
+ | ((xl & (uint32_t)0x000F0000) >> 16);
+
+ /*
+ * For each round, rotate the two 28-bit words kl and kr.
+ * The extraction of the 48-bit subkey (PC-2) is not done yet.
+ */
+ for (i = 0; i < 16; i ++) {
+ if ((1 << i) & 0x8103) {
+ kl = (kl << 1) | (kl >> 27);
+ kr = (kr << 1) | (kr >> 27);
+ } else {
+ kl = (kl << 2) | (kl >> 26);
+ kr = (kr << 2) | (kr >> 26);
+ }
+ kl &= (uint32_t)0x0FFFFFFF;
+ kr &= (uint32_t)0x0FFFFFFF;
+ skey[(i << 1) + 0] = kl;
+ skey[(i << 1) + 1] = kr;
+ }
+}
+
+/* see inner.h */
+void
+br_des_rev_skey(uint32_t *skey)
+{
+ int i;
+
+ for (i = 0; i < 16; i += 2) {
+ uint32_t t;
+
+ t = skey[i + 0];
+ skey[i + 0] = skey[30 - i];
+ skey[30 - i] = t;
+ t = skey[i + 1];
+ skey[i + 1] = skey[31 - i];
+ skey[31 - i] = t;
+ }
+}
diff --git a/contrib/bearssl/src/symcipher/des_tab.c b/contrib/bearssl/src/symcipher/des_tab.c
new file mode 100644
index 000000000000..3f8e4f9f2c0f
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/des_tab.c
@@ -0,0 +1,310 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * PC2left[x] tells where bit x goes when applying PC-2. 'x' is a bit
+ * position in the left rotated key word. Both position are in normal
+ * order (rightmost bit is 0).
+ */
+static const unsigned char PC2left[] = {
+ 16, 3, 7, 24, 20, 11, 24,
+ 13, 2, 10, 24, 22, 5, 15,
+ 23, 1, 9, 21, 12, 24, 6,
+ 4, 14, 18, 8, 17, 0, 19
+};
+
+/*
+ * Similar to PC2left[x], for the right rotated key word.
+ */
+static const unsigned char PC2right[] = {
+ 8, 18, 24, 6, 22, 15, 3,
+ 10, 12, 19, 5, 14, 11, 24,
+ 4, 23, 16, 9, 24, 20, 2,
+ 24, 7, 13, 0, 21, 17, 1
+};
+
+/*
+ * S-boxes and PC-1 merged.
+ */
+static const uint32_t S1[] = {
+ 0x00808200, 0x00000000, 0x00008000, 0x00808202,
+ 0x00808002, 0x00008202, 0x00000002, 0x00008000,
+ 0x00000200, 0x00808200, 0x00808202, 0x00000200,
+ 0x00800202, 0x00808002, 0x00800000, 0x00000002,
+ 0x00000202, 0x00800200, 0x00800200, 0x00008200,
+ 0x00008200, 0x00808000, 0x00808000, 0x00800202,
+ 0x00008002, 0x00800002, 0x00800002, 0x00008002,
+ 0x00000000, 0x00000202, 0x00008202, 0x00800000,
+ 0x00008000, 0x00808202, 0x00000002, 0x00808000,
+ 0x00808200, 0x00800000, 0x00800000, 0x00000200,
+ 0x00808002, 0x00008000, 0x00008200, 0x00800002,
+ 0x00000200, 0x00000002, 0x00800202, 0x00008202,
+ 0x00808202, 0x00008002, 0x00808000, 0x00800202,
+ 0x00800002, 0x00000202, 0x00008202, 0x00808200,
+ 0x00000202, 0x00800200, 0x00800200, 0x00000000,
+ 0x00008002, 0x00008200, 0x00000000, 0x00808002
+};
+
+static const uint32_t S2[] = {
+ 0x40084010, 0x40004000, 0x00004000, 0x00084010,
+ 0x00080000, 0x00000010, 0x40080010, 0x40004010,
+ 0x40000010, 0x40084010, 0x40084000, 0x40000000,
+ 0x40004000, 0x00080000, 0x00000010, 0x40080010,
+ 0x00084000, 0x00080010, 0x40004010, 0x00000000,
+ 0x40000000, 0x00004000, 0x00084010, 0x40080000,
+ 0x00080010, 0x40000010, 0x00000000, 0x00084000,
+ 0x00004010, 0x40084000, 0x40080000, 0x00004010,
+ 0x00000000, 0x00084010, 0x40080010, 0x00080000,
+ 0x40004010, 0x40080000, 0x40084000, 0x00004000,
+ 0x40080000, 0x40004000, 0x00000010, 0x40084010,
+ 0x00084010, 0x00000010, 0x00004000, 0x40000000,
+ 0x00004010, 0x40084000, 0x00080000, 0x40000010,
+ 0x00080010, 0x40004010, 0x40000010, 0x00080010,
+ 0x00084000, 0x00000000, 0x40004000, 0x00004010,
+ 0x40000000, 0x40080010, 0x40084010, 0x00084000
+};
+
+static const uint32_t S3[] = {
+ 0x00000104, 0x04010100, 0x00000000, 0x04010004,
+ 0x04000100, 0x00000000, 0x00010104, 0x04000100,
+ 0x00010004, 0x04000004, 0x04000004, 0x00010000,
+ 0x04010104, 0x00010004, 0x04010000, 0x00000104,
+ 0x04000000, 0x00000004, 0x04010100, 0x00000100,
+ 0x00010100, 0x04010000, 0x04010004, 0x00010104,
+ 0x04000104, 0x00010100, 0x00010000, 0x04000104,
+ 0x00000004, 0x04010104, 0x00000100, 0x04000000,
+ 0x04010100, 0x04000000, 0x00010004, 0x00000104,
+ 0x00010000, 0x04010100, 0x04000100, 0x00000000,
+ 0x00000100, 0x00010004, 0x04010104, 0x04000100,
+ 0x04000004, 0x00000100, 0x00000000, 0x04010004,
+ 0x04000104, 0x00010000, 0x04000000, 0x04010104,
+ 0x00000004, 0x00010104, 0x00010100, 0x04000004,
+ 0x04010000, 0x04000104, 0x00000104, 0x04010000,
+ 0x00010104, 0x00000004, 0x04010004, 0x00010100
+};
+
+static const uint32_t S4[] = {
+ 0x80401000, 0x80001040, 0x80001040, 0x00000040,
+ 0x00401040, 0x80400040, 0x80400000, 0x80001000,
+ 0x00000000, 0x00401000, 0x00401000, 0x80401040,
+ 0x80000040, 0x00000000, 0x00400040, 0x80400000,
+ 0x80000000, 0x00001000, 0x00400000, 0x80401000,
+ 0x00000040, 0x00400000, 0x80001000, 0x00001040,
+ 0x80400040, 0x80000000, 0x00001040, 0x00400040,
+ 0x00001000, 0x00401040, 0x80401040, 0x80000040,
+ 0x00400040, 0x80400000, 0x00401000, 0x80401040,
+ 0x80000040, 0x00000000, 0x00000000, 0x00401000,
+ 0x00001040, 0x00400040, 0x80400040, 0x80000000,
+ 0x80401000, 0x80001040, 0x80001040, 0x00000040,
+ 0x80401040, 0x80000040, 0x80000000, 0x00001000,
+ 0x80400000, 0x80001000, 0x00401040, 0x80400040,
+ 0x80001000, 0x00001040, 0x00400000, 0x80401000,
+ 0x00000040, 0x00400000, 0x00001000, 0x00401040
+};
+
+static const uint32_t S5[] = {
+ 0x00000080, 0x01040080, 0x01040000, 0x21000080,
+ 0x00040000, 0x00000080, 0x20000000, 0x01040000,
+ 0x20040080, 0x00040000, 0x01000080, 0x20040080,
+ 0x21000080, 0x21040000, 0x00040080, 0x20000000,
+ 0x01000000, 0x20040000, 0x20040000, 0x00000000,
+ 0x20000080, 0x21040080, 0x21040080, 0x01000080,
+ 0x21040000, 0x20000080, 0x00000000, 0x21000000,
+ 0x01040080, 0x01000000, 0x21000000, 0x00040080,
+ 0x00040000, 0x21000080, 0x00000080, 0x01000000,
+ 0x20000000, 0x01040000, 0x21000080, 0x20040080,
+ 0x01000080, 0x20000000, 0x21040000, 0x01040080,
+ 0x20040080, 0x00000080, 0x01000000, 0x21040000,
+ 0x21040080, 0x00040080, 0x21000000, 0x21040080,
+ 0x01040000, 0x00000000, 0x20040000, 0x21000000,
+ 0x00040080, 0x01000080, 0x20000080, 0x00040000,
+ 0x00000000, 0x20040000, 0x01040080, 0x20000080
+};
+
+static const uint32_t S6[] = {
+ 0x10000008, 0x10200000, 0x00002000, 0x10202008,
+ 0x10200000, 0x00000008, 0x10202008, 0x00200000,
+ 0x10002000, 0x00202008, 0x00200000, 0x10000008,
+ 0x00200008, 0x10002000, 0x10000000, 0x00002008,
+ 0x00000000, 0x00200008, 0x10002008, 0x00002000,
+ 0x00202000, 0x10002008, 0x00000008, 0x10200008,
+ 0x10200008, 0x00000000, 0x00202008, 0x10202000,
+ 0x00002008, 0x00202000, 0x10202000, 0x10000000,
+ 0x10002000, 0x00000008, 0x10200008, 0x00202000,
+ 0x10202008, 0x00200000, 0x00002008, 0x10000008,
+ 0x00200000, 0x10002000, 0x10000000, 0x00002008,
+ 0x10000008, 0x10202008, 0x00202000, 0x10200000,
+ 0x00202008, 0x10202000, 0x00000000, 0x10200008,
+ 0x00000008, 0x00002000, 0x10200000, 0x00202008,
+ 0x00002000, 0x00200008, 0x10002008, 0x00000000,
+ 0x10202000, 0x10000000, 0x00200008, 0x10002008
+};
+
+static const uint32_t S7[] = {
+ 0x00100000, 0x02100001, 0x02000401, 0x00000000,
+ 0x00000400, 0x02000401, 0x00100401, 0x02100400,
+ 0x02100401, 0x00100000, 0x00000000, 0x02000001,
+ 0x00000001, 0x02000000, 0x02100001, 0x00000401,
+ 0x02000400, 0x00100401, 0x00100001, 0x02000400,
+ 0x02000001, 0x02100000, 0x02100400, 0x00100001,
+ 0x02100000, 0x00000400, 0x00000401, 0x02100401,
+ 0x00100400, 0x00000001, 0x02000000, 0x00100400,
+ 0x02000000, 0x00100400, 0x00100000, 0x02000401,
+ 0x02000401, 0x02100001, 0x02100001, 0x00000001,
+ 0x00100001, 0x02000000, 0x02000400, 0x00100000,
+ 0x02100400, 0x00000401, 0x00100401, 0x02100400,
+ 0x00000401, 0x02000001, 0x02100401, 0x02100000,
+ 0x00100400, 0x00000000, 0x00000001, 0x02100401,
+ 0x00000000, 0x00100401, 0x02100000, 0x00000400,
+ 0x02000001, 0x02000400, 0x00000400, 0x00100001
+};
+
+static const uint32_t S8[] = {
+ 0x08000820, 0x00000800, 0x00020000, 0x08020820,
+ 0x08000000, 0x08000820, 0x00000020, 0x08000000,
+ 0x00020020, 0x08020000, 0x08020820, 0x00020800,
+ 0x08020800, 0x00020820, 0x00000800, 0x00000020,
+ 0x08020000, 0x08000020, 0x08000800, 0x00000820,
+ 0x00020800, 0x00020020, 0x08020020, 0x08020800,
+ 0x00000820, 0x00000000, 0x00000000, 0x08020020,
+ 0x08000020, 0x08000800, 0x00020820, 0x00020000,
+ 0x00020820, 0x00020000, 0x08020800, 0x00000800,
+ 0x00000020, 0x08020020, 0x00000800, 0x00020820,
+ 0x08000800, 0x00000020, 0x08000020, 0x08020000,
+ 0x08020020, 0x08000000, 0x00020000, 0x08000820,
+ 0x00000000, 0x08020820, 0x00020020, 0x08000020,
+ 0x08020000, 0x08000800, 0x08000820, 0x00000000,
+ 0x08020820, 0x00020800, 0x00020800, 0x00000820,
+ 0x00000820, 0x00020020, 0x08000000, 0x08020800
+};
+
+static inline uint32_t
+Fconf(uint32_t r0, uint32_t skl, uint32_t skr)
+{
+ uint32_t r1;
+
+ r1 = (r0 << 16) | (r0 >> 16);
+ return
+ S1[((r1 >> 11) ^ (skl >> 18)) & 0x3F]
+ | S2[((r0 >> 23) ^ (skl >> 12)) & 0x3F]
+ | S3[((r0 >> 19) ^ (skl >> 6)) & 0x3F]
+ | S4[((r0 >> 15) ^ (skl )) & 0x3F]
+ | S5[((r0 >> 11) ^ (skr >> 18)) & 0x3F]
+ | S6[((r0 >> 7) ^ (skr >> 12)) & 0x3F]
+ | S7[((r0 >> 3) ^ (skr >> 6)) & 0x3F]
+ | S8[((r1 >> 15) ^ (skr )) & 0x3F];
+}
+
+static void
+process_block_unit(uint32_t *pl, uint32_t *pr, const uint32_t *skey)
+{
+ int i;
+ uint32_t l, r;
+
+ l = *pl;
+ r = *pr;
+ for (i = 0; i < 16; i ++) {
+ uint32_t t;
+
+ t = l ^ Fconf(r, skey[(i << 1) + 0], skey[(i << 1) + 1]);
+ l = r;
+ r = t;
+ }
+ *pl = r;
+ *pr = l;
+}
+
+/* see inner.h */
+void
+br_des_tab_process_block(unsigned num_rounds, const uint32_t *skey, void *block)
+{
+ unsigned char *buf;
+ uint32_t l, r;
+
+ buf = block;
+ l = br_dec32be(buf);
+ r = br_dec32be(buf + 4);
+ br_des_do_IP(&l, &r);
+ while (num_rounds -- > 0) {
+ process_block_unit(&l, &r, skey);
+ skey += 32;
+ }
+ br_des_do_invIP(&l, &r);
+ br_enc32be(buf, l);
+ br_enc32be(buf + 4, r);
+}
+
+static void
+keysched_unit(uint32_t *skey, const void *key)
+{
+ int i;
+
+ br_des_keysched_unit(skey, key);
+
+ /*
+ * Apply PC-2 to get the 48-bit subkeys.
+ */
+ for (i = 0; i < 16; i ++) {
+ uint32_t xl, xr, ul, ur;
+ int j;
+
+ xl = skey[(i << 1) + 0];
+ xr = skey[(i << 1) + 1];
+ ul = 0;
+ ur = 0;
+ for (j = 0; j < 28; j ++) {
+ ul |= (xl & 1) << PC2left[j];
+ ur |= (xr & 1) << PC2right[j];
+ xl >>= 1;
+ xr >>= 1;
+ }
+ skey[(i << 1) + 0] = ul;
+ skey[(i << 1) + 1] = ur;
+ }
+}
+
+/* see inner.h */
+unsigned
+br_des_tab_keysched(uint32_t *skey, const void *key, size_t key_len)
+{
+ switch (key_len) {
+ case 8:
+ keysched_unit(skey, key);
+ return 1;
+ case 16:
+ keysched_unit(skey, key);
+ keysched_unit(skey + 32, (const unsigned char *)key + 8);
+ br_des_rev_skey(skey + 32);
+ memcpy(skey + 64, skey, 32 * sizeof *skey);
+ return 3;
+ default:
+ keysched_unit(skey, key);
+ keysched_unit(skey + 32, (const unsigned char *)key + 8);
+ br_des_rev_skey(skey + 32);
+ keysched_unit(skey + 64, (const unsigned char *)key + 16);
+ return 3;
+ }
+}
diff --git a/contrib/bearssl/src/symcipher/des_tab_cbcdec.c b/contrib/bearssl/src/symcipher/des_tab_cbcdec.c
new file mode 100644
index 000000000000..e7eabe9d0d2e
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/des_tab_cbcdec.c
@@ -0,0 +1,85 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_des_tab_cbcdec_init(br_des_tab_cbcdec_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_des_tab_cbcdec_vtable;
+ ctx->num_rounds = br_des_tab_keysched(ctx->skey, key, len);
+ if (len == 8) {
+ br_des_rev_skey(ctx->skey);
+ } else {
+ int i;
+
+ for (i = 0; i < 48; i += 2) {
+ uint32_t t;
+
+ t = ctx->skey[i];
+ ctx->skey[i] = ctx->skey[94 - i];
+ ctx->skey[94 - i] = t;
+ t = ctx->skey[i + 1];
+ ctx->skey[i + 1] = ctx->skey[95 - i];
+ ctx->skey[95 - i] = t;
+ }
+ }
+}
+
+/* see bearssl_block.h */
+void
+br_des_tab_cbcdec_run(const br_des_tab_cbcdec_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+
+ ivbuf = iv;
+ buf = data;
+ while (len > 0) {
+ unsigned char tmp[8];
+ int i;
+
+ memcpy(tmp, buf, 8);
+ br_des_tab_process_block(ctx->num_rounds, ctx->skey, buf);
+ for (i = 0; i < 8; i ++) {
+ buf[i] ^= ivbuf[i];
+ }
+ memcpy(ivbuf, tmp, 8);
+ buf += 8;
+ len -= 8;
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_cbcdec_class br_des_tab_cbcdec_vtable = {
+ sizeof(br_des_tab_cbcdec_keys),
+ 8,
+ 3,
+ (void (*)(const br_block_cbcdec_class **, const void *, size_t))
+ &br_des_tab_cbcdec_init,
+ (void (*)(const br_block_cbcdec_class *const *, void *, void *, size_t))
+ &br_des_tab_cbcdec_run
+};
diff --git a/contrib/bearssl/src/symcipher/des_tab_cbcenc.c b/contrib/bearssl/src/symcipher/des_tab_cbcenc.c
new file mode 100644
index 000000000000..3a45ba3e58a1
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/des_tab_cbcenc.c
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_block.h */
+void
+br_des_tab_cbcenc_init(br_des_tab_cbcenc_keys *ctx,
+ const void *key, size_t len)
+{
+ ctx->vtable = &br_des_tab_cbcenc_vtable;
+ ctx->num_rounds = br_des_tab_keysched(ctx->skey, key, len);
+}
+
+/* see bearssl_block.h */
+void
+br_des_tab_cbcenc_run(const br_des_tab_cbcenc_keys *ctx,
+ void *iv, void *data, size_t len)
+{
+ unsigned char *buf, *ivbuf;
+
+ ivbuf = iv;
+ buf = data;
+ while (len > 0) {
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ buf[i] ^= ivbuf[i];
+ }
+ br_des_tab_process_block(ctx->num_rounds, ctx->skey, buf);
+ memcpy(ivbuf, buf, 8);
+ buf += 8;
+ len -= 8;
+ }
+}
+
+/* see bearssl_block.h */
+const br_block_cbcenc_class br_des_tab_cbcenc_vtable = {
+ sizeof(br_des_tab_cbcenc_keys),
+ 8,
+ 3,
+ (void (*)(const br_block_cbcenc_class **, const void *, size_t))
+ &br_des_tab_cbcenc_init,
+ (void (*)(const br_block_cbcenc_class *const *, void *, void *, size_t))
+ &br_des_tab_cbcenc_run
+};
diff --git a/contrib/bearssl/src/symcipher/poly1305_ctmul.c b/contrib/bearssl/src/symcipher/poly1305_ctmul.c
new file mode 100644
index 000000000000..150e610a9c9b
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/poly1305_ctmul.c
@@ -0,0 +1,260 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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"
+
+/*
+ * Perform the inner processing of blocks for Poly1305. The accumulator
+ * and the r key are provided as arrays of 26-bit words (these words
+ * are allowed to have an extra bit, i.e. use 27 bits).
+ *
+ * On output, all accumulator words fit on 26 bits, except acc[1], which
+ * may be slightly larger (but by a very small amount only).
+ */
+static void
+poly1305_inner(uint32_t *acc, const uint32_t *r, const void *data, size_t len)
+{
+ /*
+ * Implementation notes: we split the 130-bit values into five
+ * 26-bit words. This gives us some space for carries.
+ *
+ * This code is inspired from the public-domain code available
+ * on:
+ * https://github.com/floodyberry/poly1305-donna
+ *
+ * Since we compute modulo 2^130-5, the "upper words" become
+ * low words with a factor of 5; that is, x*2^130 = x*5 mod p.
+ */
+ const unsigned char *buf;
+ uint32_t a0, a1, a2, a3, a4;
+ uint32_t r0, r1, r2, r3, r4;
+ uint32_t u1, u2, u3, u4;
+
+ r0 = r[0];
+ r1 = r[1];
+ r2 = r[2];
+ r3 = r[3];
+ r4 = r[4];
+
+ u1 = r1 * 5;
+ u2 = r2 * 5;
+ u3 = r3 * 5;
+ u4 = r4 * 5;
+
+ a0 = acc[0];
+ a1 = acc[1];
+ a2 = acc[2];
+ a3 = acc[3];
+ a4 = acc[4];
+
+ buf = data;
+ while (len > 0) {
+ uint64_t w0, w1, w2, w3, w4;
+ uint64_t c;
+ unsigned char tmp[16];
+
+ /*
+ * If there is a partial block, right-pad it with zeros.
+ */
+ if (len < 16) {
+ memset(tmp, 0, sizeof tmp);
+ memcpy(tmp, buf, len);
+ buf = tmp;
+ len = 16;
+ }
+
+ /*
+ * Decode next block and apply the "high bit"; that value
+ * is added to the accumulator.
+ */
+ a0 += br_dec32le(buf) & 0x03FFFFFF;
+ a1 += (br_dec32le(buf + 3) >> 2) & 0x03FFFFFF;
+ a2 += (br_dec32le(buf + 6) >> 4) & 0x03FFFFFF;
+ a3 += (br_dec32le(buf + 9) >> 6) & 0x03FFFFFF;
+ a4 += (br_dec32le(buf + 12) >> 8) | 0x01000000;
+
+ /*
+ * Compute multiplication.
+ */
+#define M(x, y) ((uint64_t)(x) * (uint64_t)(y))
+
+ w0 = M(a0, r0) + M(a1, u4) + M(a2, u3) + M(a3, u2) + M(a4, u1);
+ w1 = M(a0, r1) + M(a1, r0) + M(a2, u4) + M(a3, u3) + M(a4, u2);
+ w2 = M(a0, r2) + M(a1, r1) + M(a2, r0) + M(a3, u4) + M(a4, u3);
+ w3 = M(a0, r3) + M(a1, r2) + M(a2, r1) + M(a3, r0) + M(a4, u4);
+ w4 = M(a0, r4) + M(a1, r3) + M(a2, r2) + M(a3, r1) + M(a4, r0);
+
+#undef M
+ /*
+ * Perform some (partial) modular reduction. This step is
+ * enough to keep values in ranges such that there won't
+ * be carry overflows. Most of the reduction was done in
+ * the multiplication step (by using the 'u*' values, and
+ * using the fact that 2^130 = -5 mod p); here we perform
+ * some carry propagation.
+ */
+ c = w0 >> 26;
+ a0 = (uint32_t)w0 & 0x3FFFFFF;
+ w1 += c;
+ c = w1 >> 26;
+ a1 = (uint32_t)w1 & 0x3FFFFFF;
+ w2 += c;
+ c = w2 >> 26;
+ a2 = (uint32_t)w2 & 0x3FFFFFF;
+ w3 += c;
+ c = w3 >> 26;
+ a3 = (uint32_t)w3 & 0x3FFFFFF;
+ w4 += c;
+ c = w4 >> 26;
+ a4 = (uint32_t)w4 & 0x3FFFFFF;
+ a0 += (uint32_t)c * 5;
+ a1 += a0 >> 26;
+ a0 &= 0x3FFFFFF;
+
+ buf += 16;
+ len -= 16;
+ }
+
+ acc[0] = a0;
+ acc[1] = a1;
+ acc[2] = a2;
+ acc[3] = a3;
+ acc[4] = a4;
+}
+
+/* see bearssl_block.h */
+void
+br_poly1305_ctmul_run(const void *key, const void *iv,
+ void *data, size_t len, const void *aad, size_t aad_len,
+ void *tag, br_chacha20_run ichacha, int encrypt)
+{
+ unsigned char pkey[32], foot[16];
+ uint32_t r[5], acc[5], cc, ctl, hi;
+ uint64_t w;
+ int i;
+
+ /*
+ * Compute the MAC key. The 'r' value is the first 16 bytes of
+ * pkey[].
+ */
+ memset(pkey, 0, sizeof pkey);
+ ichacha(key, iv, 0, pkey, sizeof pkey);
+
+ /*
+ * If encrypting, ChaCha20 must run first, followed by Poly1305.
+ * When decrypting, the operations are reversed.
+ */
+ if (encrypt) {
+ ichacha(key, iv, 1, data, len);
+ }
+
+ /*
+ * Run Poly1305. We must process the AAD, then ciphertext, then
+ * the footer (with the lengths). Note that the AAD and ciphertext
+ * are meant to be padded with zeros up to the next multiple of 16,
+ * and the length of the footer is 16 bytes as well.
+ */
+
+ /*
+ * Decode the 'r' value into 26-bit words, with the "clamping"
+ * operation applied.
+ */
+ r[0] = br_dec32le(pkey) & 0x03FFFFFF;
+ r[1] = (br_dec32le(pkey + 3) >> 2) & 0x03FFFF03;
+ r[2] = (br_dec32le(pkey + 6) >> 4) & 0x03FFC0FF;
+ r[3] = (br_dec32le(pkey + 9) >> 6) & 0x03F03FFF;
+ r[4] = (br_dec32le(pkey + 12) >> 8) & 0x000FFFFF;
+
+ /*
+ * Accumulator is 0.
+ */
+ memset(acc, 0, sizeof acc);
+
+ /*
+ * Process the additional authenticated data, ciphertext, and
+ * footer in due order.
+ */
+ br_enc64le(foot, (uint64_t)aad_len);
+ br_enc64le(foot + 8, (uint64_t)len);
+ poly1305_inner(acc, r, aad, aad_len);
+ poly1305_inner(acc, r, data, len);
+ poly1305_inner(acc, r, foot, sizeof foot);
+
+ /*
+ * Finalise modular reduction. This is done with carry propagation
+ * and applying the '2^130 = -5 mod p' rule. Note that the output
+ * of poly1035_inner() is already mostly reduced, since only
+ * acc[1] may be (very slightly) above 2^26. A single loop back
+ * to acc[1] will be enough to make the value fit in 130 bits.
+ */
+ cc = 0;
+ for (i = 1; i <= 6; i ++) {
+ int j;
+
+ j = (i >= 5) ? i - 5 : i;
+ acc[j] += cc;
+ cc = acc[j] >> 26;
+ acc[j] &= 0x03FFFFFF;
+ }
+
+ /*
+ * We may still have a value in the 2^130-5..2^130-1 range, in
+ * which case we must reduce it again. The code below selects,
+ * in constant-time, between 'acc' and 'acc-p',
+ */
+ ctl = GT(acc[0], 0x03FFFFFA);
+ for (i = 1; i < 5; i ++) {
+ ctl &= EQ(acc[i], 0x03FFFFFF);
+ }
+ cc = 5;
+ for (i = 0; i < 5; i ++) {
+ uint32_t t;
+
+ t = (acc[i] + cc);
+ cc = t >> 26;
+ t &= 0x03FFFFFF;
+ acc[i] = MUX(ctl, t, acc[i]);
+ }
+
+ /*
+ * Convert back the accumulator to 32-bit words, and add the
+ * 's' value (second half of pkey[]). That addition is done
+ * modulo 2^128.
+ */
+ w = (uint64_t)acc[0] + ((uint64_t)acc[1] << 26) + br_dec32le(pkey + 16);
+ br_enc32le((unsigned char *)tag, (uint32_t)w);
+ w = (w >> 32) + ((uint64_t)acc[2] << 20) + br_dec32le(pkey + 20);
+ br_enc32le((unsigned char *)tag + 4, (uint32_t)w);
+ w = (w >> 32) + ((uint64_t)acc[3] << 14) + br_dec32le(pkey + 24);
+ br_enc32le((unsigned char *)tag + 8, (uint32_t)w);
+ hi = (uint32_t)(w >> 32) + (acc[4] << 8) + br_dec32le(pkey + 28);
+ br_enc32le((unsigned char *)tag + 12, hi);
+
+ /*
+ * If decrypting, then ChaCha20 runs _after_ Poly1305.
+ */
+ if (!encrypt) {
+ ichacha(key, iv, 1, data, len);
+ }
+}
diff --git a/contrib/bearssl/src/symcipher/poly1305_ctmul32.c b/contrib/bearssl/src/symcipher/poly1305_ctmul32.c
new file mode 100644
index 000000000000..15d9635dd440
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/poly1305_ctmul32.c
@@ -0,0 +1,297 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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"
+
+/*
+ * Perform the inner processing of blocks for Poly1305.
+ */
+static void
+poly1305_inner(uint32_t *a, const uint32_t *r, const void *data, size_t len)
+{
+ /*
+ * Implementation notes: we split the 130-bit values into ten
+ * 13-bit words. This gives us some space for carries and allows
+ * using only 32x32->32 multiplications, which are way faster than
+ * 32x32->64 multiplications on the ARM Cortex-M0/M0+, and also
+ * help in making constant-time code on the Cortex-M3.
+ *
+ * Since we compute modulo 2^130-5, the "upper words" become
+ * low words with a factor of 5; that is, x*2^130 = x*5 mod p.
+ * This has already been integrated in the r[] array, which
+ * is extended to the 0..18 range.
+ *
+ * In each loop iteration, a[] and r[] words are 13-bit each,
+ * except a[1] which may use 14 bits.
+ */
+ const unsigned char *buf;
+
+ buf = data;
+ while (len > 0) {
+ unsigned char tmp[16];
+ uint32_t b[10];
+ unsigned u, v;
+ uint32_t z, cc1, cc2;
+
+ /*
+ * If there is a partial block, right-pad it with zeros.
+ */
+ if (len < 16) {
+ memset(tmp, 0, sizeof tmp);
+ memcpy(tmp, buf, len);
+ buf = tmp;
+ len = 16;
+ }
+
+ /*
+ * Decode next block and apply the "high bit"; that value
+ * is added to the accumulator.
+ */
+ v = br_dec16le(buf);
+ a[0] += v & 0x01FFF;
+ v >>= 13;
+ v |= buf[2] << 3;
+ v |= buf[3] << 11;
+ a[1] += v & 0x01FFF;
+ v >>= 13;
+ v |= buf[4] << 6;
+ a[2] += v & 0x01FFF;
+ v >>= 13;
+ v |= buf[5] << 1;
+ v |= buf[6] << 9;
+ a[3] += v & 0x01FFF;
+ v >>= 13;
+ v |= buf[7] << 4;
+ v |= buf[8] << 12;
+ a[4] += v & 0x01FFF;
+ v >>= 13;
+ v |= buf[9] << 7;
+ a[5] += v & 0x01FFF;
+ v >>= 13;
+ v |= buf[10] << 2;
+ v |= buf[11] << 10;
+ a[6] += v & 0x01FFF;
+ v >>= 13;
+ v |= buf[12] << 5;
+ a[7] += v & 0x01FFF;
+ v = br_dec16le(buf + 13);
+ a[8] += v & 0x01FFF;
+ v >>= 13;
+ v |= buf[15] << 3;
+ a[9] += v | 0x00800;
+
+ /*
+ * At that point, all a[] values fit on 14 bits, while
+ * all r[] values fit on 13 bits. Thus products fit on
+ * 27 bits, and we can accumulate up to 31 of them in
+ * a 32-bit word and still have some room for carries.
+ */
+
+ /*
+ * Now a[] contains words with values up to 14 bits each.
+ * We perform the multiplication with r[].
+ *
+ * The extended words of r[] may be larger than 13 bits
+ * (they are 5 times a 13-bit word) so the full summation
+ * may yield values up to 46 times a 27-bit word, which
+ * does not fit on a 32-bit word. To avoid that issue, we
+ * must split the loop below in two, with a carry
+ * propagation operation in the middle.
+ */
+ cc1 = 0;
+ for (u = 0; u < 10; u ++) {
+ uint32_t s;
+
+ s = cc1
+ + MUL15(a[0], r[u + 9 - 0])
+ + MUL15(a[1], r[u + 9 - 1])
+ + MUL15(a[2], r[u + 9 - 2])
+ + MUL15(a[3], r[u + 9 - 3])
+ + MUL15(a[4], r[u + 9 - 4]);
+ b[u] = s & 0x1FFF;
+ cc1 = s >> 13;
+ }
+ cc2 = 0;
+ for (u = 0; u < 10; u ++) {
+ uint32_t s;
+
+ s = b[u] + cc2
+ + MUL15(a[5], r[u + 9 - 5])
+ + MUL15(a[6], r[u + 9 - 6])
+ + MUL15(a[7], r[u + 9 - 7])
+ + MUL15(a[8], r[u + 9 - 8])
+ + MUL15(a[9], r[u + 9 - 9]);
+ b[u] = s & 0x1FFF;
+ cc2 = s >> 13;
+ }
+ memcpy(a, b, sizeof b);
+
+ /*
+ * The two carries "loop back" with a factor of 5. We
+ * propagate them into a[0] and a[1].
+ */
+ z = cc1 + cc2;
+ z += (z << 2) + a[0];
+ a[0] = z & 0x1FFF;
+ a[1] += z >> 13;
+
+ buf += 16;
+ len -= 16;
+ }
+}
+
+/* see bearssl_block.h */
+void
+br_poly1305_ctmul32_run(const void *key, const void *iv,
+ void *data, size_t len, const void *aad, size_t aad_len,
+ void *tag, br_chacha20_run ichacha, int encrypt)
+{
+ unsigned char pkey[32], foot[16];
+ uint32_t z, r[19], acc[10], cc, ctl;
+ int i;
+
+ /*
+ * Compute the MAC key. The 'r' value is the first 16 bytes of
+ * pkey[].
+ */
+ memset(pkey, 0, sizeof pkey);
+ ichacha(key, iv, 0, pkey, sizeof pkey);
+
+ /*
+ * If encrypting, ChaCha20 must run first, followed by Poly1305.
+ * When decrypting, the operations are reversed.
+ */
+ if (encrypt) {
+ ichacha(key, iv, 1, data, len);
+ }
+
+ /*
+ * Run Poly1305. We must process the AAD, then ciphertext, then
+ * the footer (with the lengths). Note that the AAD and ciphertext
+ * are meant to be padded with zeros up to the next multiple of 16,
+ * and the length of the footer is 16 bytes as well.
+ */
+
+ /*
+ * Decode the 'r' value into 13-bit words, with the "clamping"
+ * operation applied.
+ */
+ z = br_dec32le(pkey) & 0x03FFFFFF;
+ r[9] = z & 0x1FFF;
+ r[10] = z >> 13;
+ z = (br_dec32le(pkey + 3) >> 2) & 0x03FFFF03;
+ r[11] = z & 0x1FFF;
+ r[12] = z >> 13;
+ z = (br_dec32le(pkey + 6) >> 4) & 0x03FFC0FF;
+ r[13] = z & 0x1FFF;
+ r[14] = z >> 13;
+ z = (br_dec32le(pkey + 9) >> 6) & 0x03F03FFF;
+ r[15] = z & 0x1FFF;
+ r[16] = z >> 13;
+ z = (br_dec32le(pkey + 12) >> 8) & 0x000FFFFF;
+ r[17] = z & 0x1FFF;
+ r[18] = z >> 13;
+
+ /*
+ * Extend r[] with the 5x factor pre-applied.
+ */
+ for (i = 0; i < 9; i ++) {
+ r[i] = MUL15(5, r[i + 10]);
+ }
+
+ /*
+ * Accumulator is 0.
+ */
+ memset(acc, 0, sizeof acc);
+
+ /*
+ * Process the additional authenticated data, ciphertext, and
+ * footer in due order.
+ */
+ br_enc64le(foot, (uint64_t)aad_len);
+ br_enc64le(foot + 8, (uint64_t)len);
+ poly1305_inner(acc, r, aad, aad_len);
+ poly1305_inner(acc, r, data, len);
+ poly1305_inner(acc, r, foot, sizeof foot);
+
+ /*
+ * Finalise modular reduction. This is done with carry propagation
+ * and applying the '2^130 = -5 mod p' rule. Note that the output
+ * of poly1035_inner() is already mostly reduced, since only
+ * acc[1] may be (very slightly) above 2^13. A single loop back
+ * to acc[1] will be enough to make the value fit in 130 bits.
+ */
+ cc = 0;
+ for (i = 1; i < 10; i ++) {
+ z = acc[i] + cc;
+ acc[i] = z & 0x1FFF;
+ cc = z >> 13;
+ }
+ z = acc[0] + cc + (cc << 2);
+ acc[0] = z & 0x1FFF;
+ acc[1] += z >> 13;
+
+ /*
+ * We may still have a value in the 2^130-5..2^130-1 range, in
+ * which case we must reduce it again. The code below selects,
+ * in constant-time, between 'acc' and 'acc-p',
+ */
+ ctl = GT(acc[0], 0x1FFA);
+ for (i = 1; i < 10; i ++) {
+ ctl &= EQ(acc[i], 0x1FFF);
+ }
+ acc[0] = MUX(ctl, acc[0] - 0x1FFB, acc[0]);
+ for (i = 1; i < 10; i ++) {
+ acc[i] &= ~(-ctl);
+ }
+
+ /*
+ * Convert back the accumulator to 32-bit words, and add the
+ * 's' value (second half of pkey[]). That addition is done
+ * modulo 2^128.
+ */
+ z = acc[0] + (acc[1] << 13) + br_dec16le(pkey + 16);
+ br_enc16le((unsigned char *)tag, z & 0xFFFF);
+ z = (z >> 16) + (acc[2] << 10) + br_dec16le(pkey + 18);
+ br_enc16le((unsigned char *)tag + 2, z & 0xFFFF);
+ z = (z >> 16) + (acc[3] << 7) + br_dec16le(pkey + 20);
+ br_enc16le((unsigned char *)tag + 4, z & 0xFFFF);
+ z = (z >> 16) + (acc[4] << 4) + br_dec16le(pkey + 22);
+ br_enc16le((unsigned char *)tag + 6, z & 0xFFFF);
+ z = (z >> 16) + (acc[5] << 1) + (acc[6] << 14) + br_dec16le(pkey + 24);
+ br_enc16le((unsigned char *)tag + 8, z & 0xFFFF);
+ z = (z >> 16) + (acc[7] << 11) + br_dec16le(pkey + 26);
+ br_enc16le((unsigned char *)tag + 10, z & 0xFFFF);
+ z = (z >> 16) + (acc[8] << 8) + br_dec16le(pkey + 28);
+ br_enc16le((unsigned char *)tag + 12, z & 0xFFFF);
+ z = (z >> 16) + (acc[9] << 5) + br_dec16le(pkey + 30);
+ br_enc16le((unsigned char *)tag + 14, z & 0xFFFF);
+
+ /*
+ * If decrypting, then ChaCha20 runs _after_ Poly1305.
+ */
+ if (!encrypt) {
+ ichacha(key, iv, 1, data, len);
+ }
+}
diff --git a/contrib/bearssl/src/symcipher/poly1305_ctmulq.c b/contrib/bearssl/src/symcipher/poly1305_ctmulq.c
new file mode 100644
index 000000000000..b00683a68c6b
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/poly1305_ctmulq.c
@@ -0,0 +1,475 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+#if BR_INT128 || BR_UMUL128
+
+#if BR_INT128
+
+#define MUL128(hi, lo, x, y) do { \
+ unsigned __int128 mul128tmp; \
+ mul128tmp = (unsigned __int128)(x) * (unsigned __int128)(y); \
+ (hi) = (uint64_t)(mul128tmp >> 64); \
+ (lo) = (uint64_t)mul128tmp; \
+ } while (0)
+
+#elif BR_UMUL128
+
+#include <intrin.h>
+
+#define MUL128(hi, lo, x, y) do { \
+ (lo) = _umul128((x), (y), &(hi)); \
+ } while (0)
+
+#endif
+
+#define MASK42 ((uint64_t)0x000003FFFFFFFFFF)
+#define MASK44 ((uint64_t)0x00000FFFFFFFFFFF)
+
+/*
+ * The "accumulator" word is nominally a 130-bit value. We split it into
+ * words of 44 bits, each held in a 64-bit variable.
+ *
+ * If the current accumulator is a = a0 + a1*W + a2*W^2 (where W = 2^44)
+ * and r = r0 + r1*W + r2*W^2, then:
+ *
+ * a*r = (a0*r0)
+ * + (a0*r1 + a1*r0) * W
+ * + (a0*r2 + a1*r1 + a2*r0) * W^2
+ * + (a1*r2 + a2*r1) * W^3
+ * + (a2*r2) * W^4
+ *
+ * We want to reduce that value modulo p = 2^130-5, so W^3 = 20 mod p,
+ * and W^4 = 20*W mod p. Thus, if we define u1 = 20*r1 and u2 = 20*r2,
+ * then the equations above become:
+ *
+ * b0 = a0*r0 + a1*u2 + a2*u1
+ * b1 = a0*r1 + a1*r0 + a2*u2
+ * b2 = a0*r2 + a1*r1 + a2*r0
+ *
+ * In order to make u1 fit in 44 bits, we can change these equations
+ * into:
+ *
+ * b0 = a0*r0 + a1*u2 + a2*t1
+ * b1 = a0*r1 + a1*r0 + a2*t2
+ * b2 = a0*r2 + a1*r1 + a2*r0
+ *
+ * Where t1 is u1 truncated to 44 bits, and t2 is u2 added to the extra
+ * bits of u1. Note that since r is clamped down to a 124-bit value, the
+ * values u2 and t2 fit on 44 bits too.
+ *
+ * The bx values are larger than 44 bits, so we may split them into a
+ * lower half (cx, 44 bits) and an upper half (dx). The new values for
+ * the accumulator are then:
+ *
+ * e0 = c0 + 20*d2
+ * e1 = c1 + d0
+ * e2 = c2 + d1
+ *
+ * The equations allow for some room, i.e. the ax values may be larger
+ * than 44 bits. Similarly, the ex values will usually be larger than
+ * the ax. Thus, some sort of carry propagation must be done regularly,
+ * though not necessarily at each iteration. In particular, we do not
+ * need to compute the additions (for the bx values) over 128-bit
+ * quantities; we can stick to 64-bit computations.
+ *
+ *
+ * Since the 128-bit result of a 64x64 multiplication is actually
+ * represented over two 64-bit registers, it is cheaper to arrange for
+ * any split that happens between the "high" and "low" halves to be on
+ * that 64-bit boundary. This is done by left shifting the rx, ux and tx
+ * by 20 bits (since they all fit on 44 bits each, this shift is
+ * always possible).
+ */
+
+static void
+poly1305_inner_big(uint64_t *acc, uint64_t *r, const void *data, size_t len)
+{
+
+#define MX(hi, lo, m0, m1, m2) do { \
+ uint64_t mxhi, mxlo; \
+ MUL128(mxhi, mxlo, a0, m0); \
+ (hi) = mxhi; \
+ (lo) = mxlo >> 20; \
+ MUL128(mxhi, mxlo, a1, m1); \
+ (hi) += mxhi; \
+ (lo) += mxlo >> 20; \
+ MUL128(mxhi, mxlo, a2, m2); \
+ (hi) += mxhi; \
+ (lo) += mxlo >> 20; \
+ } while (0)
+
+ const unsigned char *buf;
+ uint64_t a0, a1, a2;
+ uint64_t r0, r1, r2, t1, t2, u2;
+
+ r0 = r[0];
+ r1 = r[1];
+ r2 = r[2];
+ t1 = r[3];
+ t2 = r[4];
+ u2 = r[5];
+ a0 = acc[0];
+ a1 = acc[1];
+ a2 = acc[2];
+ buf = data;
+
+ while (len > 0) {
+ uint64_t v0, v1, v2;
+ uint64_t c0, c1, c2, d0, d1, d2;
+
+ v0 = br_dec64le(buf + 0);
+ v1 = br_dec64le(buf + 8);
+ v2 = v1 >> 24;
+ v1 = ((v0 >> 44) | (v1 << 20)) & MASK44;
+ v0 &= MASK44;
+ a0 += v0;
+ a1 += v1;
+ a2 += v2 + ((uint64_t)1 << 40);
+ MX(d0, c0, r0, u2, t1);
+ MX(d1, c1, r1, r0, t2);
+ MX(d2, c2, r2, r1, r0);
+ a0 = c0 + 20 * d2;
+ a1 = c1 + d0;
+ a2 = c2 + d1;
+
+ v0 = br_dec64le(buf + 16);
+ v1 = br_dec64le(buf + 24);
+ v2 = v1 >> 24;
+ v1 = ((v0 >> 44) | (v1 << 20)) & MASK44;
+ v0 &= MASK44;
+ a0 += v0;
+ a1 += v1;
+ a2 += v2 + ((uint64_t)1 << 40);
+ MX(d0, c0, r0, u2, t1);
+ MX(d1, c1, r1, r0, t2);
+ MX(d2, c2, r2, r1, r0);
+ a0 = c0 + 20 * d2;
+ a1 = c1 + d0;
+ a2 = c2 + d1;
+
+ v0 = br_dec64le(buf + 32);
+ v1 = br_dec64le(buf + 40);
+ v2 = v1 >> 24;
+ v1 = ((v0 >> 44) | (v1 << 20)) & MASK44;
+ v0 &= MASK44;
+ a0 += v0;
+ a1 += v1;
+ a2 += v2 + ((uint64_t)1 << 40);
+ MX(d0, c0, r0, u2, t1);
+ MX(d1, c1, r1, r0, t2);
+ MX(d2, c2, r2, r1, r0);
+ a0 = c0 + 20 * d2;
+ a1 = c1 + d0;
+ a2 = c2 + d1;
+
+ v0 = br_dec64le(buf + 48);
+ v1 = br_dec64le(buf + 56);
+ v2 = v1 >> 24;
+ v1 = ((v0 >> 44) | (v1 << 20)) & MASK44;
+ v0 &= MASK44;
+ a0 += v0;
+ a1 += v1;
+ a2 += v2 + ((uint64_t)1 << 40);
+ MX(d0, c0, r0, u2, t1);
+ MX(d1, c1, r1, r0, t2);
+ MX(d2, c2, r2, r1, r0);
+ a0 = c0 + 20 * d2;
+ a1 = c1 + d0;
+ a2 = c2 + d1;
+
+ a1 += a0 >> 44;
+ a0 &= MASK44;
+ a2 += a1 >> 44;
+ a1 &= MASK44;
+ a0 += 20 * (a2 >> 44);
+ a2 &= MASK44;
+
+ buf += 64;
+ len -= 64;
+ }
+ acc[0] = a0;
+ acc[1] = a1;
+ acc[2] = a2;
+
+#undef MX
+}
+
+static void
+poly1305_inner_small(uint64_t *acc, uint64_t *r, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ uint64_t a0, a1, a2;
+ uint64_t r0, r1, r2, t1, t2, u2;
+
+ r0 = r[0];
+ r1 = r[1];
+ r2 = r[2];
+ t1 = r[3];
+ t2 = r[4];
+ u2 = r[5];
+ a0 = acc[0];
+ a1 = acc[1];
+ a2 = acc[2];
+ buf = data;
+
+ while (len > 0) {
+ uint64_t v0, v1, v2;
+ uint64_t c0, c1, c2, d0, d1, d2;
+ unsigned char tmp[16];
+
+ if (len < 16) {
+ memcpy(tmp, buf, len);
+ memset(tmp + len, 0, (sizeof tmp) - len);
+ buf = tmp;
+ len = 16;
+ }
+ v0 = br_dec64le(buf + 0);
+ v1 = br_dec64le(buf + 8);
+
+ v2 = v1 >> 24;
+ v1 = ((v0 >> 44) | (v1 << 20)) & MASK44;
+ v0 &= MASK44;
+
+ a0 += v0;
+ a1 += v1;
+ a2 += v2 + ((uint64_t)1 << 40);
+
+#define MX(hi, lo, m0, m1, m2) do { \
+ uint64_t mxhi, mxlo; \
+ MUL128(mxhi, mxlo, a0, m0); \
+ (hi) = mxhi; \
+ (lo) = mxlo >> 20; \
+ MUL128(mxhi, mxlo, a1, m1); \
+ (hi) += mxhi; \
+ (lo) += mxlo >> 20; \
+ MUL128(mxhi, mxlo, a2, m2); \
+ (hi) += mxhi; \
+ (lo) += mxlo >> 20; \
+ } while (0)
+
+ MX(d0, c0, r0, u2, t1);
+ MX(d1, c1, r1, r0, t2);
+ MX(d2, c2, r2, r1, r0);
+
+#undef MX
+
+ a0 = c0 + 20 * d2;
+ a1 = c1 + d0;
+ a2 = c2 + d1;
+
+ a1 += a0 >> 44;
+ a0 &= MASK44;
+ a2 += a1 >> 44;
+ a1 &= MASK44;
+ a0 += 20 * (a2 >> 44);
+ a2 &= MASK44;
+
+ buf += 16;
+ len -= 16;
+ }
+ acc[0] = a0;
+ acc[1] = a1;
+ acc[2] = a2;
+}
+
+static inline void
+poly1305_inner(uint64_t *acc, uint64_t *r, const void *data, size_t len)
+{
+ if (len >= 64) {
+ size_t len2;
+
+ len2 = len & ~(size_t)63;
+ poly1305_inner_big(acc, r, data, len2);
+ data = (const unsigned char *)data + len2;
+ len -= len2;
+ }
+ if (len > 0) {
+ poly1305_inner_small(acc, r, data, len);
+ }
+}
+
+/* see bearssl_block.h */
+void
+br_poly1305_ctmulq_run(const void *key, const void *iv,
+ void *data, size_t len, const void *aad, size_t aad_len,
+ void *tag, br_chacha20_run ichacha, int encrypt)
+{
+ unsigned char pkey[32], foot[16];
+ uint64_t r[6], acc[3], r0, r1;
+ uint32_t v0, v1, v2, v3, v4;
+ uint64_t w0, w1, w2, w3;
+ uint32_t ctl;
+
+ /*
+ * Compute the MAC key. The 'r' value is the first 16 bytes of
+ * pkey[].
+ */
+ memset(pkey, 0, sizeof pkey);
+ ichacha(key, iv, 0, pkey, sizeof pkey);
+
+ /*
+ * If encrypting, ChaCha20 must run first, followed by Poly1305.
+ * When decrypting, the operations are reversed.
+ */
+ if (encrypt) {
+ ichacha(key, iv, 1, data, len);
+ }
+
+ /*
+ * Run Poly1305. We must process the AAD, then ciphertext, then
+ * the footer (with the lengths). Note that the AAD and ciphertext
+ * are meant to be padded with zeros up to the next multiple of 16,
+ * and the length of the footer is 16 bytes as well.
+ */
+
+ /*
+ * Apply the "clamping" on r.
+ */
+ pkey[ 3] &= 0x0F;
+ pkey[ 4] &= 0xFC;
+ pkey[ 7] &= 0x0F;
+ pkey[ 8] &= 0xFC;
+ pkey[11] &= 0x0F;
+ pkey[12] &= 0xFC;
+ pkey[15] &= 0x0F;
+
+ /*
+ * Decode the 'r' value into 44-bit words, left-shifted by 20 bits.
+ * Also compute the u1 and u2 values.
+ */
+ r0 = br_dec64le(pkey + 0);
+ r1 = br_dec64le(pkey + 8);
+ r[0] = r0 << 20;
+ r[1] = ((r0 >> 24) | (r1 << 40)) & ~(uint64_t)0xFFFFF;
+ r[2] = (r1 >> 4) & ~(uint64_t)0xFFFFF;
+ r1 = 20 * (r[1] >> 20);
+ r[3] = r1 << 20;
+ r[5] = 20 * r[2];
+ r[4] = (r[5] + (r1 >> 24)) & ~(uint64_t)0xFFFFF;
+
+ /*
+ * Accumulator is 0.
+ */
+ acc[0] = 0;
+ acc[1] = 0;
+ acc[2] = 0;
+
+ /*
+ * Process the additional authenticated data, ciphertext, and
+ * footer in due order.
+ */
+ br_enc64le(foot, (uint64_t)aad_len);
+ br_enc64le(foot + 8, (uint64_t)len);
+ poly1305_inner(acc, r, aad, aad_len);
+ poly1305_inner(acc, r, data, len);
+ poly1305_inner_small(acc, r, foot, sizeof foot);
+
+ /*
+ * Finalise modular reduction. At that point, the value consists
+ * in three 44-bit values (the lowest one might be slightly above
+ * 2^44). Two loops shall be sufficient.
+ */
+ acc[1] += (acc[0] >> 44);
+ acc[0] &= MASK44;
+ acc[2] += (acc[1] >> 44);
+ acc[1] &= MASK44;
+ acc[0] += 5 * (acc[2] >> 42);
+ acc[2] &= MASK42;
+ acc[1] += (acc[0] >> 44);
+ acc[0] &= MASK44;
+ acc[2] += (acc[1] >> 44);
+ acc[1] &= MASK44;
+ acc[0] += 5 * (acc[2] >> 42);
+ acc[2] &= MASK42;
+
+ /*
+ * The value may still fall in the 2^130-5..2^130-1 range, in
+ * which case we must reduce it again. The code below selects,
+ * in constant-time, between 'acc' and 'acc-p'. We encode the
+ * value over four 32-bit integers to finish the operation.
+ */
+ v0 = (uint32_t)acc[0];
+ v1 = (uint32_t)(acc[0] >> 32) | ((uint32_t)acc[1] << 12);
+ v2 = (uint32_t)(acc[1] >> 20) | ((uint32_t)acc[2] << 24);
+ v3 = (uint32_t)(acc[2] >> 8);
+ v4 = (uint32_t)(acc[2] >> 40);
+
+ ctl = GT(v0, 0xFFFFFFFA);
+ ctl &= EQ(v1, 0xFFFFFFFF);
+ ctl &= EQ(v2, 0xFFFFFFFF);
+ ctl &= EQ(v3, 0xFFFFFFFF);
+ ctl &= EQ(v4, 0x00000003);
+ v0 = MUX(ctl, v0 + 5, v0);
+ v1 = MUX(ctl, 0, v1);
+ v2 = MUX(ctl, 0, v2);
+ v3 = MUX(ctl, 0, v3);
+
+ /*
+ * Add the "s" value. This is done modulo 2^128. Don't forget
+ * carry propagation...
+ */
+ w0 = (uint64_t)v0 + (uint64_t)br_dec32le(pkey + 16);
+ w1 = (uint64_t)v1 + (uint64_t)br_dec32le(pkey + 20) + (w0 >> 32);
+ w2 = (uint64_t)v2 + (uint64_t)br_dec32le(pkey + 24) + (w1 >> 32);
+ w3 = (uint64_t)v3 + (uint64_t)br_dec32le(pkey + 28) + (w2 >> 32);
+ v0 = (uint32_t)w0;
+ v1 = (uint32_t)w1;
+ v2 = (uint32_t)w2;
+ v3 = (uint32_t)w3;
+
+ /*
+ * Encode the tag.
+ */
+ br_enc32le((unsigned char *)tag + 0, v0);
+ br_enc32le((unsigned char *)tag + 4, v1);
+ br_enc32le((unsigned char *)tag + 8, v2);
+ br_enc32le((unsigned char *)tag + 12, v3);
+
+ /*
+ * If decrypting, then ChaCha20 runs _after_ Poly1305.
+ */
+ if (!encrypt) {
+ ichacha(key, iv, 1, data, len);
+ }
+}
+
+/* see bearssl_block.h */
+br_poly1305_run
+br_poly1305_ctmulq_get(void)
+{
+ return &br_poly1305_ctmulq_run;
+}
+
+#else
+
+/* see bearssl_block.h */
+br_poly1305_run
+br_poly1305_ctmulq_get(void)
+{
+ return 0;
+}
+
+#endif
diff --git a/contrib/bearssl/src/symcipher/poly1305_i15.c b/contrib/bearssl/src/symcipher/poly1305_i15.c
new file mode 100644
index 000000000000..6f89212193d1
--- /dev/null
+++ b/contrib/bearssl/src/symcipher/poly1305_i15.c
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/*
+ * This is a "reference" implementation of Poly1305 that uses the
+ * generic "i15" code for big integers. It is slow, but it handles all
+ * big-integer operations with generic code, thereby avoiding most
+ * tricky situations with carry propagation and modular reduction.
+ */
+
+/*
+ * Modulus: 2^130-5.
+ */
+static const uint16_t P1305[] = {
+ 0x008A,
+ 0x7FFB, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x7FFF, 0x03FF
+};
+
+/*
+ * -p mod 2^15.
+ */
+#define P0I 0x4CCD
+
+/*
+ * R^2 mod p, for conversion to Montgomery representation (R = 2^135,
+ * since we use 9 words of 15 bits each, and 15*9 = 135).
+ */
+static const uint16_t R2[] = {
+ 0x008A,
+ 0x6400, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000, 0x0000
+};
+
+/*
+ * Perform the inner processing of blocks for Poly1305. The "r" array
+ * is in Montgomery representation, while the "a" array is not.
+ */
+static void
+poly1305_inner(uint16_t *a, const uint16_t *r, const void *data, size_t len)
+{
+ const unsigned char *buf;
+
+ buf = data;
+ while (len > 0) {
+ unsigned char tmp[16], rev[16];
+ uint16_t b[10];
+ uint32_t ctl;
+ int i;
+
+ /*
+ * If there is a partial block, right-pad it with zeros.
+ */
+ if (len < 16) {
+ memset(tmp, 0, sizeof tmp);
+ memcpy(tmp, buf, len);
+ buf = tmp;
+ len = 16;
+ }
+
+ /*
+ * Decode next block and apply the "high bit". Since
+ * decoding is little-endian, we must byte-swap the buffer.
+ */
+ for (i = 0; i < 16; i ++) {
+ rev[i] = buf[15 - i];
+ }
+ br_i15_decode_mod(b, rev, sizeof rev, P1305);
+ b[9] |= 0x0100;
+
+ /*
+ * Add the accumulator to the decoded block (modular
+ * addition).
+ */
+ ctl = br_i15_add(b, a, 1);
+ ctl |= NOT(br_i15_sub(b, P1305, 0));
+ br_i15_sub(b, P1305, ctl);
+
+ /*
+ * Multiply by r, result is the new accumulator value.
+ */
+ br_i15_montymul(a, b, r, P1305, P0I);
+
+ buf += 16;
+ len -= 16;
+ }
+}
+
+/*
+ * Byteswap a 16-byte value.
+ */
+static void
+byteswap16(unsigned char *buf)
+{
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ unsigned x;
+
+ x = buf[i];
+ buf[i] = buf[15 - i];
+ buf[15 - i] = x;
+ }
+}
+
+/* see bearssl_block.h */
+void
+br_poly1305_i15_run(const void *key, const void *iv,
+ void *data, size_t len, const void *aad, size_t aad_len,
+ void *tag, br_chacha20_run ichacha, int encrypt)
+{
+ unsigned char pkey[32], foot[16];
+ uint16_t t[10], r[10], acc[10];
+
+ /*
+ * Compute the MAC key. The 'r' value is the first 16 bytes of
+ * pkey[].
+ */
+ memset(pkey, 0, sizeof pkey);
+ ichacha(key, iv, 0, pkey, sizeof pkey);
+
+ /*
+ * If encrypting, ChaCha20 must run first, followed by Poly1305.
+ * When decrypting, the operations are reversed.
+ */
+ if (encrypt) {
+ ichacha(key, iv, 1, data, len);
+ }
+
+ /*
+ * Run Poly1305. We must process the AAD, then ciphertext, then
+ * the footer (with the lengths). Note that the AAD and ciphertext
+ * are meant to be padded with zeros up to the next multiple of 16,
+ * and the length of the footer is 16 bytes as well.
+ */
+
+ /*
+ * Apply the "clamping" operation on the encoded 'r' value.
+ */
+ pkey[ 3] &= 0x0F;
+ pkey[ 7] &= 0x0F;
+ pkey[11] &= 0x0F;
+ pkey[15] &= 0x0F;
+ pkey[ 4] &= 0xFC;
+ pkey[ 8] &= 0xFC;
+ pkey[12] &= 0xFC;
+
+ /*
+ * Decode the clamped 'r' value. Decoding should use little-endian
+ * so we must byteswap the value first.
+ */
+ byteswap16(pkey);
+ br_i15_decode_mod(t, pkey, 16, P1305);
+
+ /*
+ * Convert 'r' to Montgomery representation.
+ */
+ br_i15_montymul(r, t, R2, P1305, P0I);
+
+ /*
+ * Accumulator is 0.
+ */
+ br_i15_zero(acc, 0x8A);
+
+ /*
+ * Process the additional authenticated data, ciphertext, and
+ * footer in due order.
+ */
+ br_enc64le(foot, (uint64_t)aad_len);
+ br_enc64le(foot + 8, (uint64_t)len);
+ poly1305_inner(acc, r, aad, aad_len);
+ poly1305_inner(acc, r, data, len);
+ poly1305_inner(acc, r, foot, sizeof foot);
+
+ /*
+ * Decode the value 's'. Again, a byteswap is needed.
+ */
+ byteswap16(pkey + 16);
+ br_i15_decode_mod(t, pkey + 16, 16, P1305);
+
+ /*
+ * Add the value 's' to the accumulator. That addition is done
+ * modulo 2^128, so we just ignore the carry.
+ */
+ br_i15_add(acc, t, 1);
+
+ /*
+ * Encode the result (128 low bits) to the tag. Encoding should
+ * be little-endian.
+ */
+ br_i15_encode(tag, 16, acc);
+ byteswap16(tag);
+
+ /*
+ * If decrypting, then ChaCha20 runs _after_ Poly1305.
+ */
+ if (!encrypt) {
+ ichacha(key, iv, 1, data, len);
+ }
+}
diff --git a/contrib/bearssl/src/x509/asn1.t0 b/contrib/bearssl/src/x509/asn1.t0
new file mode 100644
index 000000000000..ba59252632e9
--- /dev/null
+++ b/contrib/bearssl/src/x509/asn1.t0
@@ -0,0 +1,757 @@
+\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+\
+\ Permission is hereby granted, free of charge, to any person obtaining
+\ a copy of this software and associated documentation files (the
+\ "Software"), to deal in the Software without restriction, including
+\ without limitation the rights to use, copy, modify, merge, publish,
+\ distribute, sublicense, and/or sell copies of the Software, and to
+\ permit persons to whom the Software is furnished to do so, subject to
+\ the following conditions:
+\
+\ The above copyright notice and this permission notice shall be
+\ included in all copies or substantial portions of the Software.
+\
+\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+\ SOFTWARE.
+
+\ =======================================================================
+
+\ This file contains code which is common to all engines that do some
+\ ASN.1 decoding. It should not be compiled on its own, but only along
+\ with another file (e.g. x509_minimal.t0) which uses it.
+\
+\ Users must define several things:
+\
+\ -- In the preamble, a macro called "CTX" that evaluates to the current
+\ context structure.
+\
+\ -- In the preamble, a macro called "CONTEXT_NAME" that evaluates to the
+\ context structure type. This will be invoked during compilation.
+\
+\ -- A word called "read8-low" ( -- x ) that reads the next byte, or -1
+\ if the input buffer is empty. That word is usually written in C.
+\
+\ -- A word called "read-blob-inner" ( addr len -- addr len ) that is
+\ the multi-byte version of read8-low.
+\
+\ -- A word called "skip-remaining-inner" ( lim -- lim ) which reads but
+\ drops some input bytes.
+
+preamble {
+
+#include "inner.h"
+
+}
+
+\ Read next source character, skipping blanks.
+: skip-blanks begin char dup 32 > if ret then drop again ;
+
+: fail-oid
+ "Invalid OID" puts cr exitvm ;
+
+\ Read a decimal integer, followed by either a dot or whitespace.
+\ Note: this does not check for overflows.
+: parse-number ( -- val nextchar )
+ char decval
+ begin
+ char
+ dup dup `. = swap 32 <= or if ret then
+ decval swap 10 * +
+ again ;
+
+\ Encode a number in unsigned 7E format.
+: encode7E ( val -- )
+ 0 encode7E-inner ;
+
+: encode7E-inner ( val eb -- )
+ swap dup 0x7F > if
+ dup 7 u>> 0x80 encode7E-inner 0x7F and
+ then
+ or data-add8 ;
+
+\ Decode an OID from source, and encode it. First byte is length,
+\ followed by encoded ASN.1 DER value. The OID is encoded in the
+\ current data block.
+: OID
+ \ Get current data address, and push a 0 for length.
+ current-data 0 data-add8
+ \ Skip blanks and get first digit, which must be 0, 1 or 2.
+ skip-blanks decval dup 2 > if fail-oid then
+ 40 *
+ \ Next character must be a dot.
+ char `. <> if fail-oid then
+ \ Second group must be one or two digits.
+ parse-number { nextchar }
+ dup 40 >= if fail-oid then
+ + encode7E
+ \ While next character is a dot, keep encoding numbers.
+ begin nextchar `. = while
+ parse-number >nextchar
+ encode7E
+ repeat
+ \ Write back length in the first byte.
+ dup current-data swap - 1- swap data-set8
+ ; immediate
+
+\ Define a new data word for an encoded OID. The OID is read from the
+\ source.
+: OID:
+ new-data-block next-word define-data-word postpone OID ;
+
+\ Define a word that evaluates to the address of a field within the
+\ context.
+: addr:
+ next-word { field }
+ "addr-" field + 0 1 define-word
+ 0 8191 "offsetof(CONTEXT_NAME, " field + ")" + make-CX
+ postpone literal postpone ; ;
+
+addr: pad
+
+\ Define a word that evaluates to an error code through a macro name.
+: err:
+ next-word { name }
+ name 0 1 define-word
+ 0 63 "BR_" name + make-CX postpone literal postpone ; ;
+
+err: ERR_X509_INVALID_VALUE
+err: ERR_X509_TRUNCATED
+err: ERR_X509_EMPTY_CHAIN
+err: ERR_X509_INNER_TRUNC
+err: ERR_X509_BAD_TAG_CLASS
+err: ERR_X509_BAD_TAG_VALUE
+err: ERR_X509_INDEFINITE_LENGTH
+err: ERR_X509_EXTRA_ELEMENT
+err: ERR_X509_UNEXPECTED
+err: ERR_X509_NOT_CONSTRUCTED
+err: ERR_X509_NOT_PRIMITIVE
+err: ERR_X509_PARTIAL_BYTE
+err: ERR_X509_BAD_BOOLEAN
+err: ERR_X509_OVERFLOW
+err: ERR_X509_BAD_DN
+err: ERR_X509_BAD_TIME
+err: ERR_X509_UNSUPPORTED
+err: ERR_X509_LIMIT_EXCEEDED
+err: ERR_X509_WRONG_KEY_TYPE
+err: ERR_X509_BAD_SIGNATURE
+err: ERR_X509_EXPIRED
+err: ERR_X509_DN_MISMATCH
+err: ERR_X509_BAD_SERVER_NAME
+err: ERR_X509_CRITICAL_EXTENSION
+err: ERR_X509_NOT_CA
+err: ERR_X509_FORBIDDEN_KEY_USAGE
+err: ERR_X509_WEAK_PUBLIC_KEY
+
+: KEYTYPE_RSA CX 0 15 { BR_KEYTYPE_RSA } ;
+: KEYTYPE_EC CX 0 15 { BR_KEYTYPE_EC } ;
+
+cc: fail ( err -- ! ) {
+ CTX->err = T0_POPi();
+ T0_CO();
+}
+
+\ Read one byte from the stream.
+: read8-nc ( -- x )
+ begin
+ read8-low dup 0 >= if ret then
+ drop co
+ again ;
+
+\ Read one byte, enforcing current read limit.
+: read8 ( lim -- lim x )
+ dup ifnot ERR_X509_INNER_TRUNC fail then
+ 1- read8-nc ;
+
+\ Read a 16-bit value, big-endian encoding.
+: read16be ( lim -- lim x )
+ read8 8 << swap read8 rot + ;
+
+\ Read a 16-bit value, little-endian encoding.
+: read16le ( lim -- lim x )
+ read8 swap read8 8 << rot + ;
+
+\ Read all bytes from the current element, then close it (i.e. drop the
+\ limit). Destination address is an offset within the context.
+: read-blob ( lim addr -- )
+ swap
+ begin dup while read-blob-inner dup if co then repeat
+ 2drop ;
+
+\ Skip remaining bytes in the current structure, but do not close it
+\ (thus, this leaves the value 0 on the stack).
+: skip-remaining ( lim -- lim )
+ begin dup while skip-remaining-inner dup if co then repeat ;
+
+: skip-remaining-inner ( lim -- lim )
+ 0 over read-blob-inner -rot 2drop ;
+
+cc: set8 ( val addr -- ) {
+ uint32_t addr = T0_POP();
+ *((unsigned char *)CTX + addr) = (unsigned char)T0_POP();
+}
+
+cc: set16 ( val addr -- ) {
+ uint32_t addr = T0_POP();
+ *(uint16_t *)(void *)((unsigned char *)CTX + addr) = T0_POP();
+}
+
+cc: set32 ( val addr -- ) {
+ uint32_t addr = T0_POP();
+ *(uint32_t *)(void *)((unsigned char *)CTX + addr) = T0_POP();
+}
+
+cc: get8 ( addr -- val ) {
+ uint32_t addr = T0_POP();
+ T0_PUSH(*((unsigned char *)CTX + addr));
+}
+
+cc: get16 ( addr -- val ) {
+ uint32_t addr = T0_POP();
+ T0_PUSH(*(uint16_t *)(void *)((unsigned char *)CTX + addr));
+}
+
+cc: get32 ( addr -- val ) {
+ uint32_t addr = T0_POP();
+ T0_PUSH(*(uint32_t *)(void *)((unsigned char *)CTX + addr));
+}
+
+\ Read an ASN.1 tag. This function returns the "constructed" status
+\ and the tag value. The constructed status is a boolean (-1 for
+\ constructed, 0 for primitive). The tag value is either 0 to 31 for
+\ a universal tag, or 32+x for a contextual tag of value x. Tag classes
+\ "application" and "private" are rejected. Universal tags beyond 30
+\ are rejected. Contextual tags beyond 30 are rejected. Thus, accepted
+\ tags will necessarily fit on exactly one byte. This does not support
+\ the whole of ASN.1/BER, but is sufficient for certificate parsing.
+: read-tag ( lim -- lim constructed value )
+ read8 { fb }
+
+ \ Constructed flag is bit 5.
+ fb 5 >> 0x01 and neg
+
+ \ Class is in bits 6 and 7. Accepted classes are 00 (universal)
+ \ and 10 (context). We check that bit 6 is 0, and shift back
+ \ bit 7 so that we get 0 (universal) or 32 (context).
+ fb 6 >> dup 0x01 and if ERR_X509_BAD_TAG_CLASS fail then
+ 4 <<
+
+ \ Tag value is in bits 0..4. If the value is 31, then this is
+ \ an extended tag, encoded over subsequent bytes, and we do
+ \ not support that.
+ fb 0x1F and dup 0x1F = if ERR_X509_BAD_TAG_VALUE fail then
+ + ;
+
+\ Read a tag, but only if not at the end of the current object. If there
+\ is no room for another element (limit is zero), then this will push a
+\ synthetic "no tag" value (primitive, with value -1).
+: read-tag-or-end ( lim -- lim constructed value )
+ dup ifnot 0 -1 ret then
+ read-tag ;
+
+\ Compare the read tag with the provided value. If equal, then the
+\ element is skipped, and a new tag is read (or end of object).
+: iftag-skip ( lim constructed value ref -- lim constructed value )
+ over = if
+ 2drop
+ read-length-open-elt skip-close-elt
+ read-tag-or-end
+ then ;
+
+\ Read an ASN.1 length. This supports only definite lengths (theoretically,
+\ certificates may use an indefinite length for the outer structure, using
+\ DER only in the TBS, but this never happens in practice, except in a
+\ single example certificate from 15 years ago that also fails to decode
+\ properly for other reasons).
+: read-length ( lim -- lim length )
+ read8
+ \ Lengths in 0x00..0x7F get encoded as a single byte.
+ dup 0x80 < if ret then
+
+ \ If the byte is 0x80 then this is an indefinite length, and we
+ \ do not support that.
+ 0x80 - dup ifnot ERR_X509_INDEFINITE_LENGTH fail then
+
+ \ Masking out bit 7, this yields the number of bytes over which
+ \ the value is encoded. Since the total certificate length must
+ \ fit over 3 bytes (this is a consequence of SSL/TLS message
+ \ format), we can reject big lengths and keep the length in a
+ \ single integer.
+ { n } 0
+ begin n 0 > while n 1- >n
+ dup 0x7FFFFF > if ERR_X509_INNER_TRUNC fail then
+ 8 << swap read8 rot +
+ repeat ;
+
+\ Open a sub-structure. This subtracts the length from the limit, and
+\ pushes the length back as new limit.
+: open-elt ( lim length -- lim_outer lim_inner )
+ dup2 < if ERR_X509_INNER_TRUNC fail then
+ dup { len } - len ;
+
+\ Read a length and open the value as a sub-structure.
+: read-length-open-elt ( lim -- lim_outer lim_inner )
+ read-length open-elt ;
+
+\ Close a sub-structure. This verifies that there is no remaining
+\ element to read.
+: close-elt ( lim -- )
+ if ERR_X509_EXTRA_ELEMENT fail then ;
+
+\ Skip remaining bytes in the current structure, then close it.
+: skip-close-elt ( lim -- )
+ skip-remaining drop ;
+
+\ Read a length and then skip the value.
+: read-length-skip ( lim -- lim )
+ read-length-open-elt skip-close-elt ;
+
+\ Check that a given tag is constructed and has the expected value.
+: check-tag-constructed ( constructed value refvalue -- )
+ = ifnot ERR_X509_UNEXPECTED fail then
+ check-constructed ;
+
+\ Check that the top value is true; report a "not constructed"
+\ error otherwise.
+: check-constructed ( constructed -- )
+ ifnot ERR_X509_NOT_CONSTRUCTED fail then ;
+
+\ Check that a given tag is primitive and has the expected value.
+: check-tag-primitive ( constructed value refvalue -- )
+ = ifnot ERR_X509_UNEXPECTED fail then
+ check-primitive ;
+
+\ Check that the top value is true; report a "not primitive"
+\ error otherwise.
+: check-primitive ( constructed -- )
+ if ERR_X509_NOT_PRIMITIVE fail then ;
+
+\ Check that the tag is for a constructed SEQUENCE.
+: check-sequence ( constructed value -- )
+ 0x10 check-tag-constructed ;
+
+\ Read a tag, check that it is for a constructed SEQUENCE, and open
+\ it as a sub-element.
+: read-sequence-open ( lim -- lim_outer lim_inner )
+ read-tag check-sequence read-length-open-elt ;
+
+\ Read the next element as a BIT STRING with no ignore bits, and open
+\ it as a sub-element.
+: read-bits-open ( lim -- lim_outer lim_inner )
+ read-tag 0x03 check-tag-primitive
+ read-length-open-elt
+ read8 if ERR_X509_PARTIAL_BYTE fail then ;
+
+OID: rsaEncryption 1.2.840.113549.1.1.1
+
+OID: sha1WithRSAEncryption 1.2.840.113549.1.1.5
+OID: sha224WithRSAEncryption 1.2.840.113549.1.1.14
+OID: sha256WithRSAEncryption 1.2.840.113549.1.1.11
+OID: sha384WithRSAEncryption 1.2.840.113549.1.1.12
+OID: sha512WithRSAEncryption 1.2.840.113549.1.1.13
+
+OID: id-sha1 1.3.14.3.2.26
+OID: id-sha224 2.16.840.1.101.3.4.2.4
+OID: id-sha256 2.16.840.1.101.3.4.2.1
+OID: id-sha384 2.16.840.1.101.3.4.2.2
+OID: id-sha512 2.16.840.1.101.3.4.2.3
+
+OID: id-ecPublicKey 1.2.840.10045.2.1
+
+OID: ansix9p256r1 1.2.840.10045.3.1.7
+OID: ansix9p384r1 1.3.132.0.34
+OID: ansix9p521r1 1.3.132.0.35
+
+OID: ecdsa-with-SHA1 1.2.840.10045.4.1
+OID: ecdsa-with-SHA224 1.2.840.10045.4.3.1
+OID: ecdsa-with-SHA256 1.2.840.10045.4.3.2
+OID: ecdsa-with-SHA384 1.2.840.10045.4.3.3
+OID: ecdsa-with-SHA512 1.2.840.10045.4.3.4
+
+OID: id-at-commonName 2.5.4.3
+
+\ Read a "small value". This assumes that the tag has just been read
+\ and processed, but not the length. The first pad byte is set to the
+\ value length; the encoded value itself follows. If the value length
+\ exceeds 255 bytes, then a single 0 is written in the pad, and this
+\ method returns false (0). Otherwise, it returns true (-1).
+\ Either way, the element is fully read.
+: read-small-value ( lim -- lim bool )
+ read-length-open-elt
+ dup 255 > if skip-close-elt 0 addr-pad set8 0 ret then
+ dup addr-pad set8
+ addr-pad 1+ read-blob
+ -1 ;
+
+\ Read an OID as a "small value" (tag, length and value). A boolean
+\ value is returned, which is true (-1) if the OID value fits on the pad,
+\ false (0) otherwise.
+: read-OID ( lim -- lim bool )
+ read-tag 0x06 check-tag-primitive read-small-value ;
+
+\ Read a UTF-8 code point. On error, return 0. Reading a code point of
+\ value 0 is considered to be an error.
+: read-UTF8 ( lim -- lim val )
+ read8
+ choice
+ dup 0x80 < uf ret enduf
+ dup 0xC0 < uf drop 0 ret enduf
+ dup 0xE0 < uf 0x1F and 1 read-UTF8-next 0x80 0x7FF enduf
+ dup 0xF0 < uf 0x0F and 2 read-UTF8-next 0x800 0xFFFF enduf
+ dup 0xF8 < uf 0x07 and 3 read-UTF8-next 0x10000 0x10FFFF enduf
+ drop 0 ret
+ endchoice
+ between? ifnot drop 0 then
+ ;
+
+\ Read n subsequent bytes to complete the provided first byte. The final
+\ value is -1 on error, or the code point numerical value. The final
+\ value is duplicated.
+: read-UTF8-next ( lim val n -- lim val val )
+ begin dup while
+ -rot
+ read-UTF8-chunk
+ rot 1-
+ repeat
+ drop dup ;
+
+\ Read one byte, that should be a trailing UTF-8 byte, and complement the
+\ current value. On error, value is set to -1.
+: read-UTF8-chunk ( lim val -- lim val )
+ swap
+ \ If we are at the end of the value, report an error but don't fail.
+ dup ifnot 2drop 0 -1 ret then
+ read8 rot
+ dup 0< if swap drop ret then 6 <<
+ swap dup 6 >> 2 <> if 2drop -1 ret then
+ 0x3F and + ;
+
+: high-surrogate? ( x -- x bool )
+ dup 0xD800 0xDBFF between? ;
+
+: low-surrogate? ( x -- x bool )
+ dup 0xDC00 0xDFFF between? ;
+
+: assemble-surrogate-pair ( hi lim lo -- lim val )
+ low-surrogate? ifnot rot 2drop 0 ret then
+ rot 10 << + 0x35FDC00 - ;
+
+\ Read a UTF-16 code point (big-endian). Returned value is 0 on error.
+: read-UTF16BE ( lim -- lim val )
+ read16be
+ choice
+ high-surrogate? uf
+ swap dup ifnot 2drop 0 0 ret then
+ read16be assemble-surrogate-pair
+ enduf
+ low-surrogate? uf
+ drop 0
+ enduf
+ endchoice ;
+
+\ Read a UTF-16 code point (little-endian). Returned value is 0 on error.
+: read-UTF16LE ( lim -- lim val )
+ read16le
+ choice
+ high-surrogate? uf
+ swap dup ifnot 2drop 0 0 ret then
+ read16le assemble-surrogate-pair
+ enduf
+ low-surrogate? uf
+ drop 0
+ enduf
+ endchoice ;
+
+\ Add byte to current pad value. Offset is updated, or set to 0 on error.
+: pad-append ( off val -- off )
+ over dup 0= swap 256 >= or if 2drop 0 ret then
+ over addr-pad + set8 1+ ;
+
+\ Add UTF-8 chunk byte to the pad. The 'nn' parameter is the shift count.
+: pad-append-UTF8-chunk ( off val nn -- off )
+ >> 0x3F and 0x80 or pad-append ;
+
+\ Test whether a code point is invalid when encoding. This rejects the
+\ 66 noncharacters, and also the surrogate range; this function does NOT
+\ check that the value is in the 0..10FFFF range.
+: valid-unicode? ( val -- bool )
+ dup 0xFDD0 0xFEDF between? if drop 0 ret then
+ dup 0xD800 0xDFFF between? if drop 0 ret then
+ 0xFFFF and 0xFFFE < ;
+
+\ Encode a code point in UTF-8. Offset is in the pad; it is updated, or
+\ set to 0 on error. Leading BOM are ignored.
+: encode-UTF8 ( val off -- off )
+ \ Skip leading BOM (U+FEFF when off is 1).
+ dup2 1 = swap 0xFEFF = and if swap drop ret then
+
+ swap dup { val }
+ dup valid-unicode? ifnot 2drop 0 ret then
+ choice
+ dup 0x80 < uf pad-append enduf
+ dup 0x800 < uf
+ 6 >> 0xC0 or pad-append
+ val 0 pad-append-UTF8-chunk
+ enduf
+ dup 0xFFFF < uf
+ 12 >> 0xE0 or pad-append
+ val 6 pad-append-UTF8-chunk
+ val 0 pad-append-UTF8-chunk
+ enduf
+ 18 >> 0xF0 or pad-append
+ val 12 pad-append-UTF8-chunk
+ val 6 pad-append-UTF8-chunk
+ val 0 pad-append-UTF8-chunk
+ endchoice ;
+
+\ Read a string value into the pad; this function checks that the source
+\ characters are UTF-8 and non-zero. The string length (in bytes) is
+\ written in the first pad byte. Returned value is true (-1) on success,
+\ false (0) on error.
+: read-value-UTF8 ( lim -- lim bool )
+ read-length-open-elt
+ 1 { off }
+ begin dup while
+ read-UTF8 dup ifnot drop skip-close-elt 0 ret then
+ off encode-UTF8 >off
+ repeat
+ drop off dup ifnot ret then 1- addr-pad set8 -1 ;
+
+\ Decode a UTF-16 string into the pad. The string is converted to UTF-8,
+\ and the length is written in the first pad byte. A leading BOM is
+\ honoured (big-endian is assumed if there is no BOM). A code point of
+\ value 0 is an error. Returned value is true (-1) on success, false (0)
+\ on error.
+: read-value-UTF16 ( lim -- lim bool )
+ read-length-open-elt
+ dup ifnot addr-pad set8 -1 ret then
+ 1 { off }
+ read-UTF16BE dup 0xFFFE = if
+ \ Leading BOM, and indicates little-endian.
+ drop
+ begin dup while
+ read-UTF16LE dup ifnot drop skip-close-elt 0 ret then
+ off encode-UTF8 >off
+ repeat
+ else
+ dup ifnot drop skip-close-elt 0 ret then
+ \ Big-endian BOM, or no BOM.
+ begin
+ off encode-UTF8 >off
+ dup while
+ read-UTF16BE dup ifnot drop skip-close-elt 0 ret then
+ repeat
+ then
+ drop off dup ifnot ret then 1- addr-pad set8 -1 ;
+
+\ Decode a latin-1 string into the pad. The string is converted to UTF-8,
+\ and the length is written in the first pad byte. A source byte of
+\ value 0 is an error. Returned value is true (-1) on success, false (0)
+\ on error.
+: read-value-latin1 ( lim -- lim bool )
+ read-length-open-elt
+ 1 { off }
+ begin dup while
+ read8 dup ifnot drop skip-close-elt 0 ret then
+ off encode-UTF8 >off
+ repeat
+ drop off dup ifnot ret then 1- addr-pad set8 -1 ;
+
+\ Read a value and interpret it as an INTEGER or ENUMERATED value. If
+\ the integer value does not fit on an unsigned 32-bit value, an error
+\ is reported. This function assumes that the tag has just been read
+\ and processed, but not the length.
+: read-small-int-value ( lim -- lim x )
+ read-length-open-elt
+ dup ifnot ERR_X509_OVERFLOW fail then
+ read8 dup 0x80 >= if ERR_X509_OVERFLOW fail then
+ { x }
+ begin dup while
+ read8 x dup 0xFFFFFF >= if ERR_X509_OVERFLOW fail then
+ 8 << + >x
+ repeat
+ drop x ;
+
+\ Compare the OID in the pad with an OID in the constant data block.
+\ Returned value is -1 on equality, 0 otherwise.
+cc: eqOID ( addrConst -- bool ) {
+ const unsigned char *a2 = &t0_datablock[T0_POP()];
+ const unsigned char *a1 = &CTX->pad[0];
+ size_t len = a1[0];
+ int x;
+ if (len == a2[0]) {
+ x = -(memcmp(a1 + 1, a2 + 1, len) == 0);
+ } else {
+ x = 0;
+ }
+ T0_PUSH((uint32_t)x);
+}
+
+\ Compare two blobs in the context. Returned value is -1 on equality, 0
+\ otherwise.
+cc: eqblob ( addr1 addr2 len -- bool ) {
+ size_t len = T0_POP();
+ const unsigned char *a2 = (const unsigned char *)CTX + T0_POP();
+ const unsigned char *a1 = (const unsigned char *)CTX + T0_POP();
+ T0_PUSHi(-(memcmp(a1, a2, len) == 0));
+}
+
+\ Check that a value is in a given range (inclusive).
+: between? ( x min max -- bool )
+ { min max } dup min >= swap max <= and ;
+
+\ Convert the provided byte value into a number in the 0..9 range,
+\ assuming that it is an ASCII digit. A non-digit triggers an error
+\ (a "bad time" error since this is used in date/time decoding).
+: digit-dec ( char -- value )
+ `0 - dup 0 9 between? ifnot ERR_X509_BAD_TIME fail then ;
+
+\ Read two ASCII digits and return the value in the 0..99 range. An
+\ error is reported if the characters are not ASCII digits.
+: read-dec2 ( lim -- lim x )
+ read8 digit-dec 10 * { x } read8 digit-dec x + ;
+
+\ Read two ASCII digits and check that the value is in the provided
+\ range (inclusive).
+: read-dec2-range ( lim min max -- lim x )
+ { min max }
+ read-dec2 dup min max between? ifnot ERR_X509_BAD_TIME fail then ;
+
+\ Maximum days in a month and accumulated day count. Each
+\ 16-bit value contains the month day count in its lower 5 bits. The first
+\ 12 values are for a normal year, the other 12 for a leap year.
+data: month-to-days
+hexb| 001F 03FC 077F 0B5E 0F1F 12FE 16BF 1A9F 1E7E 223F 261E 29DF |
+hexb| 001F 03FD 079F 0B7E 0F3F 131E 16DF 1ABF 1E9E 225F 263E 29FF |
+
+\ Read a date (UTCTime or GeneralizedTime). The date value is converted
+\ to a day count and a second count. The day count starts at 0 for
+\ January 1st, 0 AD (that's they year before 1 AD, also known as 1 BC)
+\ in a proleptic Gregorian calendar (i.e. Gregorian rules are assumed to
+\ extend indefinitely in the past). The second count is between 0 and
+\ 86400 (inclusive, in case of a leap second).
+: read-date ( lim -- lim days seconds )
+ \ Read tag; must be UTCTime or GeneralizedTime. Year count is
+ \ 4 digits with GeneralizedTime, 2 digits with UTCTime.
+ read-tag
+ dup 0x17 0x18 between? ifnot ERR_X509_BAD_TIME fail then
+ 0x18 = { y4d }
+ check-primitive
+ read-length-open-elt
+
+ \ We compute the days and seconds counts during decoding, in
+ \ order to minimize the number of needed temporary variables.
+ { ; days seconds x }
+
+ \ Year is 4-digit with GeneralizedTime. With UTCTime, the year
+ \ is in the 1950..2049 range, and only the last two digits are
+ \ present in the encoding.
+ read-dec2
+ y4d if
+ 100 * >x read-dec2 x +
+ else
+ dup 50 < if 100 + then 1900 +
+ then
+ >x
+ x 365 * x 3 + 4 / + x 99 + 100 / - x 399 + 400 / + >days
+
+ \ Month is 1..12. Number of days in a months depend on the
+ \ month and on the year (year count is in x at that point).
+ 1 12 read-dec2-range
+ 1- 1 <<
+ x 4 % 0= x 100 % 0<> x 400 % 0= or and if 24 + then
+ month-to-days + data-get16
+ dup 5 >> days + >days
+ 0x1F and
+
+ \ Day. At this point, the TOS contains the maximum day count for
+ \ the current month.
+ 1 swap read-dec2-range
+ days + 1- >days
+
+ \ Hour, minute and seconds. Count of seconds is allowed to go to
+ \ 60 in case of leap seconds (in practice, leap seconds really
+ \ occur only at the very end of the day, so this computation is
+ \ exact for a real leap second, and a spurious leap second only
+ \ implies a one-second shift that we can ignore).
+ 0 23 read-dec2-range 3600 * >seconds
+ 0 59 read-dec2-range 60 * seconds + >seconds
+ 0 60 read-dec2-range seconds + >seconds
+
+ \ At this point, we may have fractional seconds. This should
+ \ happen only with GeneralizedTime, but we accept it for UTCTime
+ \ too (and, anyway, we ignore these fractional seconds).
+ read8 dup `. = if
+ drop
+ begin read8 dup `0 `9 between? while drop repeat
+ then
+
+ \ The time zone should be 'Z', not followed by anything. Other
+ \ time zone indications are not DER and thus not supposed to
+ \ appear in certificates.
+ `Z <> if ERR_X509_BAD_TIME fail then
+ close-elt
+ days seconds ;
+
+\ Read an INTEGER (tag, length and value). The INTEGER is supposed to be
+\ positive; its unsigned big-endian encoding is stored in the provided
+\ in-context buffer. Returned value is the decoded length. If the integer
+\ did not fit, or the value is negative, then an error is reported.
+: read-integer ( lim addr len -- lim dlen )
+ rot read-tag 0x02 check-tag-primitive -rot
+ read-integer-next ;
+
+\ Identical to read-integer, but the tag has already been read and checked.
+: read-integer-next ( lim addr len -- lim dlen )
+ dup { addr len origlen }
+ read-length-open-elt
+ \ Read first byte; sign bit must be 0.
+ read8 dup 0x80 >= if ERR_X509_OVERFLOW fail then
+ \ Skip leading bytes of value 0. If there are only bytes of
+ \ value 0, then return.
+ begin dup 0 = while
+ drop dup ifnot drop 0 ret then
+ read8
+ repeat
+ \ At that point, we have the first non-zero byte on the stack.
+ begin
+ len dup ifnot ERR_X509_LIMIT_EXCEEDED fail then 1- >len
+ addr set8 addr 1+ >addr
+ dup while read8
+ repeat
+ drop origlen len - ;
+
+\ Read a BOOLEAN value. This should be called immediately after reading
+\ the tag.
+: read-boolean ( lim constructed value -- lim bool )
+ 0x01 check-tag-primitive
+ read-length 1 <> if ERR_X509_BAD_BOOLEAN fail then
+ read8 0<> ;
+
+\ Identify an elliptic curve: read the OID, then check it against the
+\ known curve OID.
+: read-curve-ID ( lim -- lim curve )
+ read-OID ifnot ERR_X509_UNSUPPORTED fail then
+ choice
+ ansix9p256r1 eqOID uf 23 enduf
+ ansix9p384r1 eqOID uf 24 enduf
+ ansix9p521r1 eqOID uf 25 enduf
+ ERR_X509_UNSUPPORTED fail
+ endchoice ;
+
+\ A convenient debug word: print the current data stack contents.
+cc: DEBUG ( -- ) {
+ extern int printf(const char *fmt, ...);
+ uint32_t *p;
+
+ printf("<stack:");
+ for (p = &CTX->dp_stack[0]; p != dp; p ++) {
+ printf(" %lu", (unsigned long)*p);
+ }
+ printf(" >\n");
+}
diff --git a/contrib/bearssl/src/x509/asn1enc.c b/contrib/bearssl/src/x509/asn1enc.c
new file mode 100644
index 000000000000..7a7496334f18
--- /dev/null
+++ b/contrib/bearssl/src/x509/asn1enc.c
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+br_asn1_uint
+br_asn1_uint_prepare(const void *xdata, size_t xlen)
+{
+ const unsigned char *x;
+ br_asn1_uint t;
+
+ x = xdata;
+ while (xlen > 0 && *x == 0) {
+ x ++;
+ xlen --;
+ }
+ t.data = x;
+ t.len = xlen;
+ t.asn1len = xlen;
+ if (xlen == 0 || x[0] >= 0x80) {
+ t.asn1len ++;
+ }
+ return t;
+}
+
+/* see inner.h */
+size_t
+br_asn1_encode_length(void *dest, size_t len)
+{
+ unsigned char *buf;
+ size_t z;
+ int i, j;
+
+ buf = dest;
+ if (len < 0x80) {
+ if (buf != NULL) {
+ *buf = len;
+ }
+ return 1;
+ }
+ i = 0;
+ for (z = len; z != 0; z >>= 8) {
+ i ++;
+ }
+ if (buf != NULL) {
+ *buf ++ = 0x80 + i;
+ for (j = i - 1; j >= 0; j --) {
+ *buf ++ = len >> (j << 3);
+ }
+ }
+ return i + 1;
+}
+
+/* see inner.h */
+size_t
+br_asn1_encode_uint(void *dest, br_asn1_uint pp)
+{
+ unsigned char *buf;
+ size_t lenlen;
+
+ if (dest == NULL) {
+ return 1 + br_asn1_encode_length(NULL, pp.asn1len) + pp.asn1len;
+ }
+ buf = dest;
+ *buf ++ = 0x02;
+ lenlen = br_asn1_encode_length(buf, pp.asn1len);
+ buf += lenlen;
+ *buf = 0x00;
+ memcpy(buf + pp.asn1len - pp.len, pp.data, pp.len);
+ return 1 + lenlen + pp.asn1len;
+}
diff --git a/contrib/bearssl/src/x509/encode_ec_pk8der.c b/contrib/bearssl/src/x509/encode_ec_pk8der.c
new file mode 100644
index 000000000000..53717ce3d9e9
--- /dev/null
+++ b/contrib/bearssl/src/x509/encode_ec_pk8der.c
@@ -0,0 +1,110 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_x509.h */
+size_t
+br_encode_ec_pkcs8_der(void *dest,
+ const br_ec_private_key *sk, const br_ec_public_key *pk)
+{
+ /*
+ * ASN.1 format:
+ *
+ * OneAsymmetricKey ::= SEQUENCE {
+ * version Version,
+ * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ * privateKey PrivateKey,
+ * attributes [0] Attributes OPTIONAL,
+ * ...,
+ * [[2: publicKey [1] PublicKey OPTIONAL ]],
+ * ...
+ * }
+ *
+ * We don't include attributes or public key (the public key
+ * is included in the private key value instead). The
+ * 'version' field is an INTEGER that we will set to 0
+ * (meaning 'v1', compatible with previous versions of PKCS#8).
+ * The 'privateKeyAlgorithm' structure is an AlgorithmIdentifier
+ * whose OID should be id-ecPublicKey, with, as parameters, the
+ * curve OID. The 'privateKey' is an OCTET STRING, whose value
+ * is the "raw DER" encoding of the key pair.
+ */
+
+ /*
+ * OID id-ecPublicKey (1.2.840.10045.2.1), DER-encoded (with
+ * the tag).
+ */
+ static const unsigned char OID_ECPUBKEY[] = {
+ 0x06, 0x07, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x02, 0x01
+ };
+
+ size_t len_version, len_privateKeyAlgorithm, len_privateKeyValue;
+ size_t len_privateKey, len_seq;
+ const unsigned char *oid;
+
+ oid = br_get_curve_OID(sk->curve);
+ if (oid == NULL) {
+ return 0;
+ }
+ len_version = 3;
+ len_privateKeyAlgorithm = 2 + sizeof OID_ECPUBKEY + 2 + oid[0];
+ len_privateKeyValue = br_encode_ec_raw_der_inner(NULL, sk, pk, 0);
+ len_privateKey = 1 + len_of_len(len_privateKeyValue)
+ + len_privateKeyValue;
+ len_seq = len_version + len_privateKeyAlgorithm + len_privateKey;
+
+ if (dest == NULL) {
+ return 1 + len_of_len(len_seq) + len_seq;
+ } else {
+ unsigned char *buf;
+ size_t lenlen;
+
+ buf = dest;
+ *buf ++ = 0x30; /* SEQUENCE tag */
+ lenlen = br_asn1_encode_length(buf, len_seq);
+ buf += lenlen;
+
+ /* version */
+ *buf ++ = 0x02;
+ *buf ++ = 0x01;
+ *buf ++ = 0x00;
+
+ /* privateKeyAlgorithm */
+ *buf ++ = 0x30;
+ *buf ++ = (sizeof OID_ECPUBKEY) + 2 + oid[0];
+ memcpy(buf, OID_ECPUBKEY, sizeof OID_ECPUBKEY);
+ buf += sizeof OID_ECPUBKEY;
+ *buf ++ = 0x06;
+ memcpy(buf, oid, 1 + oid[0]);
+ buf += 1 + oid[0];
+
+ /* privateKey */
+ *buf ++ = 0x04;
+ buf += br_asn1_encode_length(buf, len_privateKeyValue);
+ br_encode_ec_raw_der_inner(buf, sk, pk, 0);
+
+ return 1 + lenlen + len_seq;
+ }
+}
diff --git a/contrib/bearssl/src/x509/encode_ec_rawder.c b/contrib/bearssl/src/x509/encode_ec_rawder.c
new file mode 100644
index 000000000000..5985909adeba
--- /dev/null
+++ b/contrib/bearssl/src/x509/encode_ec_rawder.c
@@ -0,0 +1,161 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see inner.h */
+const unsigned char *
+br_get_curve_OID(int curve)
+{
+ static const unsigned char OID_secp256r1[] = {
+ 0x08, 0x2a, 0x86, 0x48, 0xce, 0x3d, 0x03, 0x01, 0x07
+ };
+ static const unsigned char OID_secp384r1[] = {
+ 0x05, 0x2b, 0x81, 0x04, 0x00, 0x22
+ };
+ static const unsigned char OID_secp521r1[] = {
+ 0x05, 0x2b, 0x81, 0x04, 0x00, 0x23
+ };
+
+ switch (curve) {
+ case BR_EC_secp256r1: return OID_secp256r1;
+ case BR_EC_secp384r1: return OID_secp384r1;
+ case BR_EC_secp521r1: return OID_secp521r1;
+ default:
+ return NULL;
+ }
+}
+
+/* see inner.h */
+size_t
+br_encode_ec_raw_der_inner(void *dest,
+ const br_ec_private_key *sk, const br_ec_public_key *pk,
+ int include_curve_oid)
+{
+ /*
+ * ASN.1 format:
+ *
+ * ECPrivateKey ::= SEQUENCE {
+ * version INTEGER { ecPrivkeyVer1(1) } (ecPrivkeyVer1),
+ * privateKey OCTET STRING,
+ * parameters [0] ECParameters {{ NamedCurve }} OPTIONAL,
+ * publicKey [1] BIT STRING OPTIONAL
+ * }
+ *
+ * The tages '[0]' and '[1]' are explicit. The 'ECParameters'
+ * is a CHOICE; in our case, it will always be an OBJECT IDENTIFIER
+ * that identifies the curve.
+ *
+ * The value of the 'privateKey' field is the raw unsigned big-endian
+ * encoding of the private key (integer modulo the curve subgroup
+ * order); there is no INTEGER tag, and the leading bit may be 1.
+ * Also, leading bytes of value 0x00 are _not_ removed.
+ *
+ * The 'publicKey' contents are the raw encoded public key point,
+ * normally uncompressed (leading byte of value 0x04, followed
+ * by the unsigned big-endian encodings of the X and Y coordinates,
+ * padded to the full field length if necessary).
+ */
+
+ size_t len_version, len_privateKey, len_parameters, len_publicKey;
+ size_t len_publicKey_bits, len_seq;
+ const unsigned char *oid;
+
+ if (include_curve_oid) {
+ oid = br_get_curve_OID(sk->curve);
+ if (oid == NULL) {
+ return 0;
+ }
+ } else {
+ oid = NULL;
+ }
+ len_version = 3;
+ len_privateKey = 1 + len_of_len(sk->xlen) + sk->xlen;
+ if (include_curve_oid) {
+ len_parameters = 4 + oid[0];
+ } else {
+ len_parameters = 0;
+ }
+ if (pk == NULL) {
+ len_publicKey = 0;
+ len_publicKey_bits = 0;
+ } else {
+ len_publicKey_bits = 2 + len_of_len(pk->qlen) + pk->qlen;
+ len_publicKey = 1 + len_of_len(len_publicKey_bits)
+ + len_publicKey_bits;
+ }
+ len_seq = len_version + len_privateKey + len_parameters + len_publicKey;
+ if (dest == NULL) {
+ return 1 + len_of_len(len_seq) + len_seq;
+ } else {
+ unsigned char *buf;
+ size_t lenlen;
+
+ buf = dest;
+ *buf ++ = 0x30; /* SEQUENCE tag */
+ lenlen = br_asn1_encode_length(buf, len_seq);
+ buf += lenlen;
+
+ /* version */
+ *buf ++ = 0x02;
+ *buf ++ = 0x01;
+ *buf ++ = 0x01;
+
+ /* privateKey */
+ *buf ++ = 0x04;
+ buf += br_asn1_encode_length(buf, sk->xlen);
+ memcpy(buf, sk->x, sk->xlen);
+ buf += sk->xlen;
+
+ /* parameters */
+ if (include_curve_oid) {
+ *buf ++ = 0xA0;
+ *buf ++ = oid[0] + 2;
+ *buf ++ = 0x06;
+ memcpy(buf, oid, oid[0] + 1);
+ buf += oid[0] + 1;
+ }
+
+ /* publicKey */
+ if (pk != NULL) {
+ *buf ++ = 0xA1;
+ buf += br_asn1_encode_length(buf, len_publicKey_bits);
+ *buf ++ = 0x03;
+ buf += br_asn1_encode_length(buf, pk->qlen + 1);
+ *buf ++ = 0x00;
+ memcpy(buf, pk->q, pk->qlen);
+ /* buf += pk->qlen; */
+ }
+
+ return 1 + lenlen + len_seq;
+ }
+}
+
+/* see bearssl_x509.h */
+size_t
+br_encode_ec_raw_der(void *dest,
+ const br_ec_private_key *sk, const br_ec_public_key *pk)
+{
+ return br_encode_ec_raw_der_inner(dest, sk, pk, 1);
+}
diff --git a/contrib/bearssl/src/x509/encode_rsa_pk8der.c b/contrib/bearssl/src/x509/encode_rsa_pk8der.c
new file mode 100644
index 000000000000..c053503d361f
--- /dev/null
+++ b/contrib/bearssl/src/x509/encode_rsa_pk8der.c
@@ -0,0 +1,97 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_x509.h */
+size_t
+br_encode_rsa_pkcs8_der(void *dest, const br_rsa_private_key *sk,
+ const br_rsa_public_key *pk, const void *d, size_t dlen)
+{
+ /*
+ * ASN.1 format:
+ *
+ * OneAsymmetricKey ::= SEQUENCE {
+ * version Version,
+ * privateKeyAlgorithm PrivateKeyAlgorithmIdentifier,
+ * privateKey PrivateKey,
+ * attributes [0] Attributes OPTIONAL,
+ * ...,
+ * [[2: publicKey [1] PublicKey OPTIONAL ]],
+ * ...
+ * }
+ *
+ * We don't include attributes or public key. The 'version' field
+ * is an INTEGER that we will set to 0 (meaning 'v1', compatible
+ * with previous versions of PKCS#8). The 'privateKeyAlgorithm'
+ * structure is an AlgorithmIdentifier whose OID should be
+ * rsaEncryption, with NULL parameters. The 'privateKey' is an
+ * OCTET STRING, whose value is the "raw DER" encoding of the
+ * key pair.
+ *
+ * Since the private key value comes last, this function really
+ * adds a header, which is mostly fixed (only some lengths have
+ * to be modified.
+ */
+
+ /*
+ * Concatenation of:
+ * - DER encoding of an INTEGER of value 0 (the 'version' field)
+ * - DER encoding of a PrivateKeyAlgorithmIdentifier that uses
+ * the rsaEncryption OID, and NULL parameters
+ * - An OCTET STRING tag
+ */
+ static const unsigned char PK8_HEAD[] = {
+ 0x02, 0x01, 0x00,
+ 0x30, 0x0d, 0x06, 0x09, 0x2a, 0x86, 0x48, 0x86,
+ 0xf7, 0x0d, 0x01, 0x01, 0x01, 0x05, 0x00,
+ 0x04
+ };
+
+ size_t len_raw, len_seq;
+
+ len_raw = br_encode_rsa_raw_der(NULL, sk, pk, d, dlen);
+ len_seq = (sizeof PK8_HEAD) + len_of_len(len_raw) + len_raw;
+ if (dest == NULL) {
+ return 1 + len_of_len(len_seq) + len_seq;
+ } else {
+ unsigned char *buf;
+ size_t lenlen;
+
+ buf = dest;
+ *buf ++ = 0x30; /* SEQUENCE tag */
+ lenlen = br_asn1_encode_length(buf, len_seq);
+ buf += lenlen;
+
+ /* version, privateKeyAlgorithm, privateKey tag */
+ memcpy(buf, PK8_HEAD, sizeof PK8_HEAD);
+ buf += sizeof PK8_HEAD;
+
+ /* privateKey */
+ buf += br_asn1_encode_length(buf, len_raw);
+ br_encode_rsa_raw_der(buf, sk, pk, d, dlen);
+
+ return 1 + lenlen + len_seq;
+ }
+}
diff --git a/contrib/bearssl/src/x509/encode_rsa_rawder.c b/contrib/bearssl/src/x509/encode_rsa_rawder.c
new file mode 100644
index 000000000000..1a8052b03f1c
--- /dev/null
+++ b/contrib/bearssl/src/x509/encode_rsa_rawder.c
@@ -0,0 +1,96 @@
+/*
+ * Copyright (c) 2018 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_x509.h */
+size_t
+br_encode_rsa_raw_der(void *dest, const br_rsa_private_key *sk,
+ const br_rsa_public_key *pk, const void *d, size_t dlen)
+{
+ /*
+ * ASN.1 format:
+ *
+ * RSAPrivateKey ::= SEQUENCE {
+ * version Version,
+ * modulus INTEGER, -- n
+ * publicExponent INTEGER, -- e
+ * privateExponent INTEGER, -- d
+ * prime1 INTEGER, -- p
+ * prime2 INTEGER, -- q
+ * exponent1 INTEGER, -- d mod (p-1)
+ * exponent2 INTEGER, -- d mod (q-1)
+ * coefficient INTEGER, -- (inverse of q) mod p
+ * otherPrimeInfos OtherPrimeInfos OPTIONAL
+ * }
+ *
+ * The 'version' field is an INTEGER of value 0 (meaning: there
+ * are exactly two prime factors), and 'otherPrimeInfos' will
+ * be absent (because there are exactly two prime factors).
+ */
+
+ br_asn1_uint num[9];
+ size_t u, slen;
+
+ /*
+ * For all INTEGER values, get the pointer and length for the
+ * data bytes.
+ */
+ num[0] = br_asn1_uint_prepare(NULL, 0);
+ num[1] = br_asn1_uint_prepare(pk->n, pk->nlen);
+ num[2] = br_asn1_uint_prepare(pk->e, pk->elen);
+ num[3] = br_asn1_uint_prepare(d, dlen);
+ num[4] = br_asn1_uint_prepare(sk->p, sk->plen);
+ num[5] = br_asn1_uint_prepare(sk->q, sk->qlen);
+ num[6] = br_asn1_uint_prepare(sk->dp, sk->dplen);
+ num[7] = br_asn1_uint_prepare(sk->dq, sk->dqlen);
+ num[8] = br_asn1_uint_prepare(sk->iq, sk->iqlen);
+
+ /*
+ * Get the length of the SEQUENCE contents.
+ */
+ slen = 0;
+ for (u = 0; u < 9; u ++) {
+ uint32_t ilen;
+
+ ilen = num[u].asn1len;
+ slen += 1 + len_of_len(ilen) + ilen;
+ }
+
+ if (dest == NULL) {
+ return 1 + len_of_len(slen) + slen;
+ } else {
+ unsigned char *buf;
+ size_t lenlen;
+
+ buf = dest;
+ *buf ++ = 0x30; /* SEQUENCE tag */
+ lenlen = br_asn1_encode_length(buf, slen);
+ buf += lenlen;
+ for (u = 0; u < 9; u ++) {
+ buf += br_asn1_encode_uint(buf, num[u]);
+ }
+ return 1 + lenlen + slen;
+ }
+}
diff --git a/contrib/bearssl/src/x509/skey_decoder.c b/contrib/bearssl/src/x509/skey_decoder.c
new file mode 100644
index 000000000000..f4e43e7bfc40
--- /dev/null
+++ b/contrib/bearssl/src/x509/skey_decoder.c
@@ -0,0 +1,650 @@
+/* Automatically generated code; do not modify directly. */
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+} t0_context;
+
+static uint32_t
+t0_parse7E_unsigned(const unsigned char **p)
+{
+ uint32_t x;
+
+ x = 0;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ return x;
+ }
+ }
+}
+
+static int32_t
+t0_parse7E_signed(const unsigned char **p)
+{
+ int neg;
+ uint32_t x;
+
+ neg = ((**p) >> 6) & 1;
+ x = (uint32_t)-neg;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ if (neg) {
+ return -(int32_t)~x - 1;
+ } else {
+ return (int32_t)x;
+ }
+ }
+ }
+}
+
+#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80)
+#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F)
+#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8)
+#define T0_INT1(x) T0_FBYTE(x, 0)
+#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+
+/* static const unsigned char t0_datablock[]; */
+
+
+void br_skey_decoder_init_main(void *t0ctx);
+
+void br_skey_decoder_run(void *t0ctx);
+
+
+
+#include "inner.h"
+
+
+
+
+
+#include "inner.h"
+
+#define CTX ((br_skey_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_skey_decoder_context, cpu)))
+#define CONTEXT_NAME br_skey_decoder_context
+
+/* see bearssl_x509.h */
+void
+br_skey_decoder_init(br_skey_decoder_context *ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+ ctx->cpu.dp = &ctx->dp_stack[0];
+ ctx->cpu.rp = &ctx->rp_stack[0];
+ br_skey_decoder_init_main(&ctx->cpu);
+ br_skey_decoder_run(&ctx->cpu);
+}
+
+/* see bearssl_x509.h */
+void
+br_skey_decoder_push(br_skey_decoder_context *ctx,
+ const void *data, size_t len)
+{
+ ctx->hbuf = data;
+ ctx->hlen = len;
+ br_skey_decoder_run(&ctx->cpu);
+}
+
+
+
+static const unsigned char t0_datablock[] = {
+ 0x00, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x07,
+ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x08, 0x2A, 0x86, 0x48, 0xCE,
+ 0x3D, 0x03, 0x01, 0x07, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22, 0x05, 0x2B,
+ 0x81, 0x04, 0x00, 0x23
+};
+
+static const unsigned char t0_codeblock[] = {
+ 0x00, 0x01, 0x01, 0x07, 0x00, 0x00, 0x01, 0x01, 0x08, 0x00, 0x00, 0x13,
+ 0x13, 0x00, 0x00, 0x01, T0_INT1(BR_ERR_X509_BAD_TAG_CLASS), 0x00, 0x00,
+ 0x01, T0_INT1(BR_ERR_X509_BAD_TAG_VALUE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_EXTRA_ELEMENT), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_INDEFINITE_LENGTH), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_INNER_TRUNC), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_INVALID_VALUE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_LIMIT_EXCEEDED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_NOT_CONSTRUCTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_NOT_PRIMITIVE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_OVERFLOW), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_UNEXPECTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_UNSUPPORTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_KEYTYPE_EC), 0x00, 0x00, 0x01, T0_INT1(BR_KEYTYPE_RSA),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, key_data)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, key_type)), 0x00, 0x00,
+ 0x33, 0x48, 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, pad)),
+ 0x00, 0x00, 0x01, 0x13, 0x00, 0x00, 0x01, 0x1C, 0x00, 0x00, 0x01, 0x22,
+ 0x00, 0x00, 0x05, 0x02, 0x2C, 0x16, 0x00, 0x00, 0x06, 0x02, 0x2D, 0x16,
+ 0x00, 0x00, 0x01, 0x10, 0x3D, 0x00, 0x00, 0x0D, 0x05, 0x02, 0x2F, 0x16,
+ 0x3A, 0x00, 0x00, 0x0D, 0x05, 0x02, 0x2F, 0x16, 0x3B, 0x00, 0x00, 0x06,
+ 0x02, 0x27, 0x16, 0x00, 0x01, 0x03, 0x00, 0x54, 0x57, 0x01, 0x02, 0x3E,
+ 0x55, 0x23, 0x06, 0x02, 0x30, 0x16, 0x57, 0x01, 0x04, 0x3E, 0x02, 0x00,
+ 0x41, 0x3F, 0x00, 0x02, 0x03, 0x00, 0x53, 0x14, 0x14, 0x03, 0x01, 0x48,
+ 0x0E, 0x06, 0x02, 0x30, 0x16, 0x33, 0x4C, 0x58, 0x01, 0x7F, 0x19, 0x0D,
+ 0x06, 0x04, 0x13, 0x13, 0x04, 0x29, 0x01, 0x20, 0x19, 0x0D, 0x06, 0x16,
+ 0x13, 0x3A, 0x53, 0x4D, 0x02, 0x00, 0x06, 0x09, 0x02, 0x00, 0x0C, 0x06,
+ 0x02, 0x2A, 0x16, 0x04, 0x02, 0x03, 0x00, 0x3F, 0x04, 0x0D, 0x01, 0x21,
+ 0x19, 0x0D, 0x06, 0x04, 0x13, 0x3A, 0x04, 0x03, 0x30, 0x16, 0x13, 0x5D,
+ 0x02, 0x00, 0x05, 0x02, 0x30, 0x16, 0x02, 0x00, 0x02, 0x01, 0x1D, 0x00,
+ 0x02, 0x53, 0x4B, 0x05, 0x02, 0x30, 0x16, 0x5B, 0x15, 0x06, 0x07, 0x5D,
+ 0x01, 0x7F, 0x03, 0x01, 0x04, 0x16, 0x46, 0x15, 0x06, 0x10, 0x01, 0x00,
+ 0x03, 0x01, 0x14, 0x06, 0x03, 0x4D, 0x04, 0x02, 0x01, 0x00, 0x03, 0x00,
+ 0x04, 0x02, 0x30, 0x16, 0x3F, 0x57, 0x01, 0x04, 0x3E, 0x53, 0x02, 0x01,
+ 0x06, 0x03, 0x43, 0x04, 0x03, 0x02, 0x00, 0x40, 0x3F, 0x5D, 0x02, 0x01,
+ 0x06, 0x03, 0x32, 0x04, 0x01, 0x31, 0x00, 0x00, 0x54, 0x57, 0x01, 0x02,
+ 0x3E, 0x55, 0x06, 0x02, 0x30, 0x16, 0x57, 0x01, 0x02, 0x3E, 0x44, 0x3F,
+ 0x00, 0x07, 0x35, 0x50, 0x14, 0x05, 0x02, 0x2F, 0x16, 0x23, 0x01, 0x03,
+ 0x0B, 0x33, 0x17, 0x47, 0x07, 0x03, 0x00, 0x4F, 0x4F, 0x35, 0x4E, 0x14,
+ 0x14, 0x03, 0x01, 0x03, 0x02, 0x51, 0x14, 0x03, 0x03, 0x02, 0x02, 0x07,
+ 0x14, 0x03, 0x02, 0x51, 0x14, 0x03, 0x04, 0x02, 0x02, 0x07, 0x14, 0x03,
+ 0x02, 0x51, 0x14, 0x03, 0x05, 0x02, 0x02, 0x07, 0x14, 0x03, 0x02, 0x51,
+ 0x03, 0x06, 0x02, 0x00, 0x02, 0x01, 0x02, 0x03, 0x02, 0x04, 0x02, 0x05,
+ 0x02, 0x06, 0x1E, 0x00, 0x00, 0x19, 0x19, 0x00, 0x00, 0x01, 0x0B, 0x00,
+ 0x00, 0x01, 0x00, 0x20, 0x14, 0x06, 0x08, 0x01, 0x01, 0x21, 0x20, 0x22,
+ 0x20, 0x04, 0x75, 0x13, 0x00, 0x00, 0x01,
+ T0_INT2(3 * BR_X509_BUFSIZE_KEY), 0x00, 0x01, 0x01, 0x87, 0xFF, 0xFF,
+ 0x7F, 0x54, 0x57, 0x01, 0x02, 0x3E, 0x55, 0x01, 0x01, 0x0E, 0x06, 0x02,
+ 0x30, 0x16, 0x57, 0x01, 0x02, 0x19, 0x0D, 0x06, 0x06, 0x13, 0x3B, 0x44,
+ 0x32, 0x04, 0x1C, 0x01, 0x04, 0x19, 0x0D, 0x06, 0x08, 0x13, 0x3B, 0x01,
+ 0x00, 0x41, 0x31, 0x04, 0x0E, 0x01, 0x10, 0x19, 0x0D, 0x06, 0x05, 0x13,
+ 0x3A, 0x42, 0x04, 0x03, 0x30, 0x16, 0x13, 0x03, 0x00, 0x3F, 0x02, 0x00,
+ 0x34, 0x1F, 0x5A, 0x27, 0x16, 0x00, 0x01, 0x45, 0x0A, 0x06, 0x02, 0x29,
+ 0x16, 0x14, 0x03, 0x00, 0x08, 0x02, 0x00, 0x00, 0x00, 0x57, 0x01, 0x06,
+ 0x3E, 0x56, 0x00, 0x00, 0x20, 0x14, 0x06, 0x07, 0x1A, 0x14, 0x06, 0x01,
+ 0x12, 0x04, 0x76, 0x24, 0x00, 0x00, 0x4B, 0x05, 0x02, 0x30, 0x16, 0x37,
+ 0x15, 0x06, 0x04, 0x01, 0x17, 0x04, 0x12, 0x38, 0x15, 0x06, 0x04, 0x01,
+ 0x18, 0x04, 0x0A, 0x39, 0x15, 0x06, 0x04, 0x01, 0x19, 0x04, 0x02, 0x30,
+ 0x16, 0x00, 0x00, 0x1C, 0x57, 0x01, 0x02, 0x3E, 0x09, 0x50, 0x00, 0x00,
+ 0x35, 0x4E, 0x13, 0x00, 0x03, 0x14, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02,
+ 0x53, 0x59, 0x14, 0x01, 0x81, 0x00, 0x0F, 0x06, 0x02, 0x2E, 0x16, 0x14,
+ 0x01, 0x00, 0x0D, 0x06, 0x0B, 0x13, 0x14, 0x05, 0x04, 0x13, 0x01, 0x00,
+ 0x00, 0x59, 0x04, 0x6F, 0x02, 0x01, 0x14, 0x05, 0x02, 0x2B, 0x16, 0x23,
+ 0x03, 0x01, 0x02, 0x02, 0x1F, 0x02, 0x02, 0x22, 0x03, 0x02, 0x14, 0x06,
+ 0x03, 0x59, 0x04, 0x68, 0x13, 0x02, 0x00, 0x02, 0x01, 0x08, 0x00, 0x00,
+ 0x14, 0x35, 0x1C, 0x08, 0x20, 0x1C, 0x07, 0x20, 0x4E, 0x00, 0x01, 0x59,
+ 0x14, 0x01, 0x81, 0x00, 0x0A, 0x06, 0x01, 0x00, 0x01, 0x81, 0x00, 0x08,
+ 0x14, 0x05, 0x02, 0x28, 0x16, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01,
+ 0x00, 0x0E, 0x06, 0x19, 0x02, 0x00, 0x23, 0x03, 0x00, 0x14, 0x01, 0x83,
+ 0xFF, 0xFF, 0x7F, 0x0E, 0x06, 0x02, 0x29, 0x16, 0x01, 0x08, 0x0B, 0x20,
+ 0x59, 0x1C, 0x07, 0x04, 0x60, 0x00, 0x00, 0x52, 0x4A, 0x00, 0x00, 0x57,
+ 0x3C, 0x53, 0x00, 0x01, 0x53, 0x14, 0x05, 0x02, 0x2E, 0x16, 0x59, 0x14,
+ 0x01, 0x81, 0x00, 0x0F, 0x06, 0x02, 0x2E, 0x16, 0x03, 0x00, 0x14, 0x06,
+ 0x16, 0x59, 0x02, 0x00, 0x14, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x0F, 0x06,
+ 0x02, 0x2E, 0x16, 0x01, 0x08, 0x0B, 0x07, 0x03, 0x00, 0x04, 0x67, 0x13,
+ 0x02, 0x00, 0x00, 0x00, 0x53, 0x14, 0x01, 0x81, 0x7F, 0x0E, 0x06, 0x08,
+ 0x5C, 0x01, 0x00, 0x36, 0x1F, 0x01, 0x00, 0x00, 0x14, 0x36, 0x1F, 0x36,
+ 0x22, 0x4C, 0x01, 0x7F, 0x00, 0x01, 0x59, 0x03, 0x00, 0x02, 0x00, 0x01,
+ 0x05, 0x10, 0x01, 0x01, 0x11, 0x18, 0x02, 0x00, 0x01, 0x06, 0x10, 0x14,
+ 0x01, 0x01, 0x11, 0x06, 0x02, 0x25, 0x16, 0x01, 0x04, 0x0B, 0x02, 0x00,
+ 0x01, 0x1F, 0x11, 0x14, 0x01, 0x1F, 0x0D, 0x06, 0x02, 0x26, 0x16, 0x07,
+ 0x00, 0x00, 0x14, 0x05, 0x05, 0x01, 0x00, 0x01, 0x7F, 0x00, 0x57, 0x00,
+ 0x00, 0x14, 0x05, 0x02, 0x29, 0x16, 0x23, 0x5A, 0x00, 0x00, 0x1B, 0x14,
+ 0x01, 0x00, 0x0F, 0x06, 0x01, 0x00, 0x13, 0x12, 0x04, 0x74, 0x00, 0x01,
+ 0x01, 0x00, 0x00, 0x5D, 0x13, 0x00, 0x00, 0x14, 0x06, 0x07, 0x5E, 0x14,
+ 0x06, 0x01, 0x12, 0x04, 0x76, 0x00, 0x00, 0x01, 0x00, 0x19, 0x1A, 0x09,
+ 0x24, 0x00
+};
+
+static const uint16_t t0_caddr[] = {
+ 0,
+ 5,
+ 10,
+ 14,
+ 18,
+ 22,
+ 26,
+ 30,
+ 34,
+ 38,
+ 42,
+ 46,
+ 50,
+ 54,
+ 58,
+ 62,
+ 66,
+ 70,
+ 75,
+ 80,
+ 84,
+ 89,
+ 93,
+ 97,
+ 101,
+ 107,
+ 113,
+ 118,
+ 126,
+ 134,
+ 140,
+ 163,
+ 244,
+ 311,
+ 329,
+ 404,
+ 408,
+ 412,
+ 429,
+ 434,
+ 505,
+ 519,
+ 526,
+ 540,
+ 573,
+ 582,
+ 587,
+ 654,
+ 665,
+ 721,
+ 725,
+ 730,
+ 778,
+ 804,
+ 848,
+ 859,
+ 868,
+ 881,
+ 885,
+ 889,
+ 901
+};
+
+#define T0_INTERPRETED 34
+
+#define T0_ENTER(ip, rp, slot) do { \
+ const unsigned char *t0_newip; \
+ uint32_t t0_lnum; \
+ t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \
+ t0_lnum = t0_parse7E_unsigned(&t0_newip); \
+ (rp) += t0_lnum; \
+ *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \
+ (ip) = t0_newip; \
+ } while (0)
+
+#define T0_DEFENTRY(name, slot) \
+void \
+name(void *ctx) \
+{ \
+ t0_context *t0ctx = ctx; \
+ t0ctx->ip = &t0_codeblock[0]; \
+ T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
+}
+
+T0_DEFENTRY(br_skey_decoder_init_main, 73)
+
+#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++)
+
+void
+br_skey_decoder_run(void *t0ctx)
+{
+ uint32_t *dp, *rp;
+ const unsigned char *ip;
+
+#define T0_LOCAL(x) (*(rp - 2 - (x)))
+#define T0_POP() (*-- dp)
+#define T0_POPi() (*(int32_t *)(-- dp))
+#define T0_PEEK(x) (*(dp - 1 - (x)))
+#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x)))
+#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0)
+#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0)
+#define T0_RPOP() (*-- rp)
+#define T0_RPOPi() (*(int32_t *)(-- rp))
+#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0)
+#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0)
+#define T0_ROLL(x) do { \
+ size_t t0len = (size_t)(x); \
+ uint32_t t0tmp = *(dp - 1 - t0len); \
+ memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_SWAP() do { \
+ uint32_t t0tmp = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_ROT() do { \
+ uint32_t t0tmp = *(dp - 3); \
+ *(dp - 3) = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_NROT() do { \
+ uint32_t t0tmp = *(dp - 1); \
+ *(dp - 1) = *(dp - 2); \
+ *(dp - 2) = *(dp - 3); \
+ *(dp - 3) = t0tmp; \
+} while (0)
+#define T0_PICK(x) do { \
+ uint32_t t0depth = (x); \
+ T0_PUSH(T0_PEEK(t0depth)); \
+} while (0)
+#define T0_CO() do { \
+ goto t0_exit; \
+} while (0)
+#define T0_RET() goto t0_next
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ goto t0_next;
+ for (;;) {
+ uint32_t t0x;
+
+ t0_next:
+ t0x = T0_NEXT(&ip);
+ if (t0x < T0_INTERPRETED) {
+ switch (t0x) {
+ int32_t t0off;
+
+ case 0: /* ret */
+ t0x = T0_RPOP();
+ rp -= (t0x >> 16);
+ t0x &= 0xFFFF;
+ if (t0x == 0) {
+ ip = NULL;
+ goto t0_exit;
+ }
+ ip = &t0_codeblock[t0x];
+ break;
+ case 1: /* literal constant */
+ T0_PUSHi(t0_parse7E_signed(&ip));
+ break;
+ case 2: /* read local */
+ T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip)));
+ break;
+ case 3: /* write local */
+ T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP();
+ break;
+ case 4: /* jump */
+ t0off = t0_parse7E_signed(&ip);
+ ip += t0off;
+ break;
+ case 5: /* jump if */
+ t0off = t0_parse7E_signed(&ip);
+ if (T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 6: /* jump if not */
+ t0off = t0_parse7E_signed(&ip);
+ if (!T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 7: {
+ /* + */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a + b);
+
+ }
+ break;
+ case 8: {
+ /* - */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a - b);
+
+ }
+ break;
+ case 9: {
+ /* -rot */
+ T0_NROT();
+ }
+ break;
+ case 10: {
+ /* < */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a < b));
+
+ }
+ break;
+ case 11: {
+ /* << */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x << c);
+
+ }
+ break;
+ case 12: {
+ /* <> */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a != b));
+
+ }
+ break;
+ case 13: {
+ /* = */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a == b));
+
+ }
+ break;
+ case 14: {
+ /* > */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a > b));
+
+ }
+ break;
+ case 15: {
+ /* >= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a >= b));
+
+ }
+ break;
+ case 16: {
+ /* >> */
+
+ int c = (int)T0_POPi();
+ int32_t x = T0_POPi();
+ T0_PUSHi(x >> c);
+
+ }
+ break;
+ case 17: {
+ /* and */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a & b);
+
+ }
+ break;
+ case 18: {
+ /* co */
+ T0_CO();
+ }
+ break;
+ case 19: {
+ /* drop */
+ (void)T0_POP();
+ }
+ break;
+ case 20: {
+ /* dup */
+ T0_PUSH(T0_PEEK(0));
+ }
+ break;
+ case 21: {
+ /* eqOID */
+
+ const unsigned char *a2 = &t0_datablock[T0_POP()];
+ const unsigned char *a1 = &CTX->pad[0];
+ size_t len = a1[0];
+ int x;
+ if (len == a2[0]) {
+ x = -(memcmp(a1 + 1, a2 + 1, len) == 0);
+ } else {
+ x = 0;
+ }
+ T0_PUSH((uint32_t)x);
+
+ }
+ break;
+ case 22: {
+ /* fail */
+
+ CTX->err = T0_POPi();
+ T0_CO();
+
+ }
+ break;
+ case 23: {
+ /* get8 */
+
+ uint32_t addr = T0_POP();
+ T0_PUSH(*((unsigned char *)CTX + addr));
+
+ }
+ break;
+ case 24: {
+ /* neg */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(-a);
+
+ }
+ break;
+ case 25: {
+ /* over */
+ T0_PUSH(T0_PEEK(1));
+ }
+ break;
+ case 26: {
+ /* read-blob-inner */
+
+ uint32_t len = T0_POP();
+ uint32_t addr = T0_POP();
+ size_t clen = CTX->hlen;
+ if (clen > len) {
+ clen = (size_t)len;
+ }
+ if (addr != 0) {
+ memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
+ }
+ CTX->hbuf += clen;
+ CTX->hlen -= clen;
+ T0_PUSH(addr + clen);
+ T0_PUSH(len - clen);
+
+ }
+ break;
+ case 27: {
+ /* read8-low */
+
+ if (CTX->hlen == 0) {
+ T0_PUSHi(-1);
+ } else {
+ CTX->hlen --;
+ T0_PUSH(*CTX->hbuf ++);
+ }
+
+ }
+ break;
+ case 28: {
+ /* rot */
+ T0_ROT();
+ }
+ break;
+ case 29: {
+ /* set-ec-key */
+
+ size_t xlen = T0_POP();
+ uint32_t curve = T0_POP();
+ CTX->key.ec.curve = curve;
+ CTX->key.ec.x = CTX->key_data;
+ CTX->key.ec.xlen = xlen;
+
+ }
+ break;
+ case 30: {
+ /* set-rsa-key */
+
+ size_t iqlen = T0_POP();
+ size_t dqlen = T0_POP();
+ size_t dplen = T0_POP();
+ size_t qlen = T0_POP();
+ size_t plen = T0_POP();
+ uint32_t n_bitlen = T0_POP();
+ size_t off;
+
+ CTX->key.rsa.n_bitlen = n_bitlen;
+ CTX->key.rsa.p = CTX->key_data;
+ CTX->key.rsa.plen = plen;
+ off = plen;
+ CTX->key.rsa.q = CTX->key_data + off;
+ CTX->key.rsa.qlen = qlen;
+ off += qlen;
+ CTX->key.rsa.dp = CTX->key_data + off;
+ CTX->key.rsa.dplen = dplen;
+ off += dplen;
+ CTX->key.rsa.dq = CTX->key_data + off;
+ CTX->key.rsa.dqlen = dqlen;
+ off += dqlen;
+ CTX->key.rsa.iq = CTX->key_data + off;
+ CTX->key.rsa.iqlen = iqlen;
+
+ }
+ break;
+ case 31: {
+ /* set8 */
+
+ uint32_t addr = T0_POP();
+ *((unsigned char *)CTX + addr) = (unsigned char)T0_POP();
+
+ }
+ break;
+ case 32: {
+ /* swap */
+ T0_SWAP();
+ }
+ break;
+ case 33: {
+ /* u>> */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x >> c);
+
+ }
+ break;
+ }
+
+ } else {
+ T0_ENTER(ip, rp, t0x);
+ }
+ }
+t0_exit:
+ ((t0_context *)t0ctx)->dp = dp;
+ ((t0_context *)t0ctx)->rp = rp;
+ ((t0_context *)t0ctx)->ip = ip;
+}
diff --git a/contrib/bearssl/src/x509/skey_decoder.t0 b/contrib/bearssl/src/x509/skey_decoder.t0
new file mode 100644
index 000000000000..5b5942111816
--- /dev/null
+++ b/contrib/bearssl/src/x509/skey_decoder.t0
@@ -0,0 +1,373 @@
+\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+\
+\ Permission is hereby granted, free of charge, to any person obtaining
+\ a copy of this software and associated documentation files (the
+\ "Software"), to deal in the Software without restriction, including
+\ without limitation the rights to use, copy, modify, merge, publish,
+\ distribute, sublicense, and/or sell copies of the Software, and to
+\ permit persons to whom the Software is furnished to do so, subject to
+\ the following conditions:
+\
+\ The above copyright notice and this permission notice shall be
+\ included in all copies or substantial portions of the Software.
+\
+\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+\ SOFTWARE.
+
+preamble {
+
+#include "inner.h"
+
+#define CTX ((br_skey_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_skey_decoder_context, cpu)))
+#define CONTEXT_NAME br_skey_decoder_context
+
+/* see bearssl_x509.h */
+void
+br_skey_decoder_init(br_skey_decoder_context *ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+ ctx->cpu.dp = &ctx->dp_stack[0];
+ ctx->cpu.rp = &ctx->rp_stack[0];
+ br_skey_decoder_init_main(&ctx->cpu);
+ br_skey_decoder_run(&ctx->cpu);
+}
+
+/* see bearssl_x509.h */
+void
+br_skey_decoder_push(br_skey_decoder_context *ctx,
+ const void *data, size_t len)
+{
+ ctx->hbuf = data;
+ ctx->hlen = len;
+ br_skey_decoder_run(&ctx->cpu);
+}
+
+}
+
+addr: key_type
+addr: key_data
+
+cc: read8-low ( -- x ) {
+ if (CTX->hlen == 0) {
+ T0_PUSHi(-1);
+ } else {
+ CTX->hlen --;
+ T0_PUSH(*CTX->hbuf ++);
+ }
+}
+
+cc: read-blob-inner ( addr len -- addr len ) {
+ uint32_t len = T0_POP();
+ uint32_t addr = T0_POP();
+ size_t clen = CTX->hlen;
+ if (clen > len) {
+ clen = (size_t)len;
+ }
+ if (addr != 0) {
+ memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
+ }
+ CTX->hbuf += clen;
+ CTX->hlen -= clen;
+ T0_PUSH(addr + clen);
+ T0_PUSH(len - clen);
+}
+
+\ Get the length of the key_data buffer.
+: len-key_data
+ CX 0 8191 { 3 * BR_X509_BUFSIZE_KEY } ;
+
+\ Get the address and length for the key_data buffer.
+: addr-len-key_data ( -- addr len )
+ addr-key_data len-key_data ;
+
+\ Set the private key (RSA).
+cc: set-rsa-key ( n_bitlen plen qlen dplen dqlen iqlen -- ) {
+ size_t iqlen = T0_POP();
+ size_t dqlen = T0_POP();
+ size_t dplen = T0_POP();
+ size_t qlen = T0_POP();
+ size_t plen = T0_POP();
+ uint32_t n_bitlen = T0_POP();
+ size_t off;
+
+ CTX->key.rsa.n_bitlen = n_bitlen;
+ CTX->key.rsa.p = CTX->key_data;
+ CTX->key.rsa.plen = plen;
+ off = plen;
+ CTX->key.rsa.q = CTX->key_data + off;
+ CTX->key.rsa.qlen = qlen;
+ off += qlen;
+ CTX->key.rsa.dp = CTX->key_data + off;
+ CTX->key.rsa.dplen = dplen;
+ off += dplen;
+ CTX->key.rsa.dq = CTX->key_data + off;
+ CTX->key.rsa.dqlen = dqlen;
+ off += dqlen;
+ CTX->key.rsa.iq = CTX->key_data + off;
+ CTX->key.rsa.iqlen = iqlen;
+}
+
+\ Set the private key (EC).
+cc: set-ec-key ( curve xlen -- ) {
+ size_t xlen = T0_POP();
+ uint32_t curve = T0_POP();
+ CTX->key.ec.curve = curve;
+ CTX->key.ec.x = CTX->key_data;
+ CTX->key.ec.xlen = xlen;
+}
+
+\ Get the bit length for an integer (unsigned).
+: int-bit-length ( x -- bitlen )
+ 0 swap
+ begin dup while 1 u>> swap 1+ swap repeat
+ drop ;
+
+\ Read an INTEGER into the key_data buffer, but then ignore it.
+: read-integer-ignore ( lim -- lim )
+ addr-len-key_data read-integer drop ;
+
+\ Read an INTEGER into the key_data buffer, at the provided offset.
+\ Returned value is the integer length (in bytes).
+: read-integer-off ( lim off -- lim dlen )
+ dup addr-len-key_data rot - swap rot + swap read-integer ;
+
+\ Decode RSA key, starting with the SEQUENCE tag.
+: decode-RSA ( lim -- lim )
+ read-sequence-open
+
+ \ Version should be 0.
+ read-tag 0x02 check-tag-primitive read-small-int-value if
+ ERR_X509_UNSUPPORTED fail
+ then
+
+ \ Read tag for the modulus; should be INTEGER. Then use the
+ \ decode-RSA-next function for the remainder of the key.
+ read-tag 0x02 check-tag-primitive
+ decode-RSA-next
+
+ \ Close the SEQUENCE.
+ close-elt ;
+
+\ Decode RSA key; the version, and the tag for the modulus, have been
+\ read.
+: decode-RSA-next ( lim -- lim )
+ \ Modulus: we read it but we do not keep it; we merely gather
+ \ the modulus bit length.
+ addr-len-key_data read-integer-next
+ dup ifnot ERR_X509_UNEXPECTED fail then
+ 1- 3 << addr-key_data get8 int-bit-length + { n_bitlen }
+
+ \ Public exponent: read but skip.
+ read-integer-ignore
+
+ \ Private exponent: read but skip.
+ read-integer-ignore
+
+ \ First prime factor.
+ addr-len-key_data read-integer dup dup { off plen }
+
+ \ Second prime factor.
+ read-integer-off dup { qlen } off + dup >off
+
+ \ First reduced private exponent.
+ read-integer-off dup { dplen } off + dup >off
+
+ \ Second reduced private exponent.
+ read-integer-off dup { dqlen } off + dup >off
+
+ \ CRT coefficient.
+ read-integer-off { iqlen }
+
+ \ Set RSA key.
+ n_bitlen plen qlen dplen dqlen iqlen set-rsa-key
+
+ \ The caller will close the sequence, thereby validating that there
+ \ is no extra field.
+ ;
+
+\ Decode an EC key, starting with the SEQUENCE tag.
+: decode-EC ( lim curve -- lim )
+ { curve }
+ read-sequence-open
+
+ \ Version should be 1.
+ read-tag 0x02 check-tag-primitive read-small-int-value 1- if
+ ERR_X509_UNSUPPORTED fail
+ then
+
+ \ Read tag for the private key; should be OCTET STRING. Then use the
+ \ decode-EC-next function for the remainder of the key.
+ read-tag 0x04 check-tag-primitive
+ curve decode-EC-next
+
+ \ Close the SEQUENCE.
+ close-elt ;
+
+\ Decode an EC key; the version, and the tag for the OCTET STRING, have
+\ already been read. The curve ID is provided (0 if unknown).
+: decode-EC-next ( lim curve -- lim )
+ { curve }
+
+ \ Read the private key proper.
+ read-length-open-elt
+ dup dup { xlen } len-key_data > if ERR_X509_UNSUPPORTED fail then
+ addr-key_data read-blob
+
+ \ Next element might be the curve identifier.
+ read-tag-or-end
+ case
+
+ \ End of structure.
+ -1 of drop endof
+
+ \ Curve parameters; we support only named curves.
+ 0x20 of
+ check-constructed read-length-open-elt
+ read-curve-ID
+ curve if
+ curve <> if ERR_X509_INVALID_VALUE fail then
+ else
+ >curve
+ then
+ close-elt
+ endof
+
+ \ Public key. We ignore it.
+ 0x21 of check-constructed endof
+
+ ERR_X509_UNSUPPORTED fail
+ endcase
+ skip-remaining
+
+ \ The curve must have been defined one way or another.
+ curve ifnot ERR_X509_UNSUPPORTED fail then
+
+ \ Set the EC key.
+ curve xlen set-ec-key
+
+ \ The caller will close the sequence.
+ ;
+
+\ Decode a PKCS#8 object. The version and the tag for the AlgorithmIdentifier
+\ structure have already been read. This function returns the key type.
+: decode-PKCS8-next ( lim -- lim keytype )
+ \ Decode the AlgorithmIdentifier.
+ read-length-open-elt
+ read-OID ifnot ERR_X509_UNSUPPORTED fail then
+ { ; is-rsa curve }
+ choice
+ rsaEncryption eqOID uf
+ \ RSA private key. We ignore the parameters.
+ skip-remaining -1 >is-rsa
+ enduf
+ id-ecPublicKey eqOID uf
+ \ EC private key. Parameters, if present, shall
+ \ identify the curve.
+ 0 >is-rsa
+ dup if read-curve-ID else 0 then >curve
+ enduf
+
+ ERR_X509_UNSUPPORTED fail
+ endchoice
+ close-elt
+
+ \ Open private key value and decode it.
+ read-tag 0x04 check-tag-primitive
+ read-length-open-elt
+ is-rsa if
+ decode-RSA
+ else
+ curve decode-EC
+ then
+ close-elt
+
+ \ We ignore any extra field, i.e. attributes or public key.
+ skip-remaining
+
+ \ Return the key type.
+ is-rsa if KEYTYPE_RSA else KEYTYPE_EC then
+ ;
+
+\ Decode a private key.
+: main ( -- ! )
+ \ RSA private key format is defined in PKCS#1 (RFC 3447):
+ \ RSAPrivateKey ::= SEQUENCE {
+ \ version INTEGER, -- 0 or 1
+ \ n INTEGER,
+ \ e INTEGER,
+ \ d INTEGER,
+ \ p INTEGER,
+ \ q INTEGER,
+ \ dp INTEGER,
+ \ dq INTEGER,
+ \ iq INTEGER,
+ \ other OtherPrimeInfos OPTIONAL
+ \ }
+ \ We do not support keys with more than two primes (these have
+ \ version 1); thus, we expect the version field to be 0, and
+ \ the 'other' field to be absent.
+ \
+ \ EC private key format is defined in RFC 5915:
+ \ ECPrivateKey ::= SEQUENCE {
+ \ version INTEGER, -- always 1
+ \ privateKey OCTET STRING,
+ \ parameters [0] EXPLICIT OBJECT IDENTIFIER OPTIONAL,
+ \ publicKey [1] EXPLICIT BIT STRING OPTIONAL
+ \ }
+ \ The "parameters" might conceptually be a complex curve description
+ \ structure but we support only named curves. The private key
+ \ contents are the unsigned big-endian encoding of the key value,
+ \ which is exactly what we want.
+ \
+ \ PKCS#8 (unencrypted) is:
+ \ OneAsymmetricKey ::= SEQUENCE {
+ \ version INTEGER, -- 0 or 1
+ \ algorithm AlgorithmIdentifier,
+ \ privateKey OCTET STRING,
+ \ attributes [0] IMPLICIT Attributes OPTIONAL,
+ \ publicKey [1] IMPLICIT BIT STRING OPTIONAL
+ \ }
+ \ The 'publicKey' field is an add-on from RFC 5958 and may be
+ \ present only if the 'version' is v2 (i.e. has value 1). We
+ \ ignore it anyway.
+
+ \ An arbitrary upper limit on the private key size.
+ 0xFFFFFF
+
+ \ Open the outer SEQUENCE.
+ read-sequence-open
+
+ \ All our schemas begin with a small INTEGER which is either 0 or
+ \ 1. We don't care which it is.
+ read-tag 0x02 check-tag-primitive read-small-int-value 1 > if
+ ERR_X509_UNSUPPORTED fail
+ then
+
+ \ Get next tag: it should be either an INTEGER (RSA private key),
+ \ an OCTET STRING (EC private key), or a SEQUENCE (for an
+ \ AlgorithmIdentifier, in a PKCS#8 object).
+ read-tag
+ case
+ 0x02 of check-primitive decode-RSA-next KEYTYPE_RSA endof
+ 0x04 of check-primitive 0 decode-EC-next KEYTYPE_EC endof
+ 0x10 of check-constructed decode-PKCS8-next endof
+ ERR_X509_UNSUPPORTED fail
+ endcase
+ { key-type }
+
+ \ Close the SEQUENCE.
+ close-elt
+
+ \ Set the key type, which marks the decoding as a success.
+ key-type addr-key_type set8
+
+ \ Read one byte, then fail: if the read succeeds, then there is
+ \ some trailing byte.
+ read8-nc ERR_X509_EXTRA_ELEMENT fail
+ ;
diff --git a/contrib/bearssl/src/x509/x509_decoder.c b/contrib/bearssl/src/x509/x509_decoder.c
new file mode 100644
index 000000000000..8dd970f13f71
--- /dev/null
+++ b/contrib/bearssl/src/x509/x509_decoder.c
@@ -0,0 +1,773 @@
+/* Automatically generated code; do not modify directly. */
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+} t0_context;
+
+static uint32_t
+t0_parse7E_unsigned(const unsigned char **p)
+{
+ uint32_t x;
+
+ x = 0;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ return x;
+ }
+ }
+}
+
+static int32_t
+t0_parse7E_signed(const unsigned char **p)
+{
+ int neg;
+ uint32_t x;
+
+ neg = ((**p) >> 6) & 1;
+ x = (uint32_t)-neg;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ if (neg) {
+ return -(int32_t)~x - 1;
+ } else {
+ return (int32_t)x;
+ }
+ }
+ }
+}
+
+#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80)
+#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F)
+#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8)
+#define T0_INT1(x) T0_FBYTE(x, 0)
+#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+
+/* static const unsigned char t0_datablock[]; */
+
+
+void br_x509_decoder_init_main(void *t0ctx);
+
+void br_x509_decoder_run(void *t0ctx);
+
+
+
+#include "inner.h"
+
+
+
+
+
+#include "inner.h"
+
+#define CTX ((br_x509_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_decoder_context, cpu)))
+#define CONTEXT_NAME br_x509_decoder_context
+
+/* see bearssl_x509.h */
+void
+br_x509_decoder_init(br_x509_decoder_context *ctx,
+ void (*append_dn)(void *ctx, const void *buf, size_t len),
+ void *append_dn_ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+ /* obsolete
+ ctx->err = 0;
+ ctx->hbuf = NULL;
+ ctx->hlen = 0;
+ */
+ ctx->append_dn = append_dn;
+ ctx->append_dn_ctx = append_dn_ctx;
+ ctx->cpu.dp = &ctx->dp_stack[0];
+ ctx->cpu.rp = &ctx->rp_stack[0];
+ br_x509_decoder_init_main(&ctx->cpu);
+ br_x509_decoder_run(&ctx->cpu);
+}
+
+/* see bearssl_x509.h */
+void
+br_x509_decoder_push(br_x509_decoder_context *ctx,
+ const void *data, size_t len)
+{
+ ctx->hbuf = data;
+ ctx->hlen = len;
+ br_x509_decoder_run(&ctx->cpu);
+}
+
+
+
+static const unsigned char t0_datablock[] = {
+ 0x00, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, 0x09, 0x2A, 0x86,
+ 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0E, 0x09, 0x2A, 0x86, 0x48, 0x86,
+ 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
+ 0x01, 0x01, 0x0C, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01,
+ 0x0D, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x08, 0x2A, 0x86,
+ 0x48, 0xCE, 0x3D, 0x03, 0x01, 0x07, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22,
+ 0x05, 0x2B, 0x81, 0x04, 0x00, 0x23, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
+ 0x04, 0x01, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x01, 0x08,
+ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x08, 0x2A, 0x86, 0x48,
+ 0xCE, 0x3D, 0x04, 0x03, 0x03, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04,
+ 0x03, 0x04, 0x00, 0x1F, 0x03, 0xFC, 0x07, 0x7F, 0x0B, 0x5E, 0x0F, 0x1F,
+ 0x12, 0xFE, 0x16, 0xBF, 0x1A, 0x9F, 0x1E, 0x7E, 0x22, 0x3F, 0x26, 0x1E,
+ 0x29, 0xDF, 0x00, 0x1F, 0x03, 0xFD, 0x07, 0x9F, 0x0B, 0x7E, 0x0F, 0x3F,
+ 0x13, 0x1E, 0x16, 0xDF, 0x1A, 0xBF, 0x1E, 0x9E, 0x22, 0x5F, 0x26, 0x3E,
+ 0x29, 0xFF, 0x03, 0x55, 0x1D, 0x13
+};
+
+static const unsigned char t0_codeblock[] = {
+ 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01, 0x00, 0x11, 0x00, 0x00, 0x01,
+ 0x01, 0x09, 0x00, 0x00, 0x01, 0x01, 0x0A, 0x00, 0x00, 0x1A, 0x1A, 0x00,
+ 0x00, 0x01, T0_INT1(BR_ERR_X509_BAD_BOOLEAN), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_TAG_CLASS), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_TAG_VALUE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_TIME), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_EXTRA_ELEMENT), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_INDEFINITE_LENGTH), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_INNER_TRUNC), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_LIMIT_EXCEEDED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_NOT_CONSTRUCTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_NOT_PRIMITIVE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_OVERFLOW), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_PARTIAL_BYTE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_UNEXPECTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_UNSUPPORTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_KEYTYPE_EC), 0x00, 0x00, 0x01, T0_INT1(BR_KEYTYPE_RSA),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, copy_dn)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(CONTEXT_NAME, decoded)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, isCA)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_x509_decoder_context, pkey_data)), 0x01,
+ T0_INT2(BR_X509_BUFSIZE_KEY), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, notafter_days)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, notafter_seconds)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, notbefore_days)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, notbefore_seconds)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, pad)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, signer_hash_id)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, signer_key_type)), 0x00, 0x00, 0x01,
+ 0x80, 0x45, 0x00, 0x00, 0x01, 0x80, 0x4E, 0x00, 0x00, 0x01, 0x80, 0x54,
+ 0x00, 0x00, 0x01, 0x81, 0x36, 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0x1B,
+ 0x02, 0x01, 0x13, 0x26, 0x02, 0x00, 0x0F, 0x15, 0x00, 0x00, 0x05, 0x02,
+ 0x34, 0x1D, 0x00, 0x00, 0x06, 0x02, 0x35, 0x1D, 0x00, 0x00, 0x01, 0x10,
+ 0x4F, 0x00, 0x00, 0x11, 0x05, 0x02, 0x38, 0x1D, 0x4C, 0x00, 0x00, 0x11,
+ 0x05, 0x02, 0x38, 0x1D, 0x4D, 0x00, 0x00, 0x06, 0x02, 0x30, 0x1D, 0x00,
+ 0x00, 0x1B, 0x19, 0x01, 0x08, 0x0E, 0x26, 0x29, 0x19, 0x09, 0x00, 0x00,
+ 0x01, 0x30, 0x0A, 0x1B, 0x01, 0x00, 0x01, 0x09, 0x4B, 0x05, 0x02, 0x2F,
+ 0x1D, 0x00, 0x00, 0x20, 0x20, 0x00, 0x00, 0x01, 0x80, 0x5A, 0x00, 0x00,
+ 0x01, 0x80, 0x62, 0x00, 0x00, 0x01, 0x80, 0x6B, 0x00, 0x00, 0x01, 0x80,
+ 0x74, 0x00, 0x00, 0x01, 0x80, 0x7D, 0x00, 0x00, 0x01, 0x3D, 0x00, 0x00,
+ 0x20, 0x11, 0x06, 0x04, 0x2B, 0x6B, 0x7A, 0x71, 0x00, 0x04, 0x01, 0x00,
+ 0x3D, 0x25, 0x01, 0x00, 0x3C, 0x25, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x6D,
+ 0x6D, 0x70, 0x1B, 0x01, 0x20, 0x11, 0x06, 0x11, 0x1A, 0x4C, 0x6B, 0x70,
+ 0x01, 0x02, 0x50, 0x6E, 0x01, 0x02, 0x12, 0x06, 0x02, 0x39, 0x1D, 0x51,
+ 0x70, 0x01, 0x02, 0x50, 0x6C, 0x6D, 0x7A, 0x6D, 0x7A, 0x6D, 0x65, 0x43,
+ 0x24, 0x42, 0x24, 0x65, 0x41, 0x24, 0x40, 0x24, 0x51, 0x01, 0x01, 0x3C,
+ 0x25, 0x6D, 0x7A, 0x01, 0x00, 0x3C, 0x25, 0x6D, 0x6D, 0x60, 0x05, 0x02,
+ 0x39, 0x1D, 0x74, 0x1C, 0x06, 0x1C, 0x7A, 0x61, 0x6D, 0x3F, 0x68, 0x03,
+ 0x00, 0x3F, 0x26, 0x02, 0x00, 0x09, 0x26, 0x02, 0x00, 0x0A, 0x68, 0x03,
+ 0x01, 0x51, 0x51, 0x02, 0x00, 0x02, 0x01, 0x18, 0x04, 0x1E, 0x5A, 0x1C,
+ 0x06, 0x18, 0x64, 0x03, 0x02, 0x51, 0x61, 0x1B, 0x03, 0x03, 0x1B, 0x3F,
+ 0x23, 0x0D, 0x06, 0x02, 0x33, 0x1D, 0x62, 0x02, 0x02, 0x02, 0x03, 0x17,
+ 0x04, 0x02, 0x39, 0x1D, 0x51, 0x01, 0x00, 0x3E, 0x25, 0x71, 0x01, 0x21,
+ 0x5B, 0x01, 0x22, 0x5B, 0x1B, 0x01, 0x23, 0x11, 0x06, 0x28, 0x1A, 0x4C,
+ 0x6B, 0x6D, 0x1B, 0x06, 0x1D, 0x6D, 0x60, 0x1A, 0x70, 0x1B, 0x01, 0x01,
+ 0x11, 0x06, 0x03, 0x63, 0x1A, 0x70, 0x01, 0x04, 0x50, 0x6B, 0x4A, 0x1C,
+ 0x06, 0x03, 0x5F, 0x04, 0x01, 0x7B, 0x51, 0x51, 0x04, 0x60, 0x51, 0x51,
+ 0x04, 0x08, 0x01, 0x7F, 0x11, 0x05, 0x02, 0x38, 0x1D, 0x1A, 0x51, 0x6D,
+ 0x60, 0x06, 0x80, 0x63, 0x75, 0x1C, 0x06, 0x06, 0x01, 0x02, 0x3B, 0x04,
+ 0x80, 0x57, 0x76, 0x1C, 0x06, 0x06, 0x01, 0x03, 0x3B, 0x04, 0x80, 0x4D,
+ 0x77, 0x1C, 0x06, 0x06, 0x01, 0x04, 0x3B, 0x04, 0x80, 0x43, 0x78, 0x1C,
+ 0x06, 0x05, 0x01, 0x05, 0x3B, 0x04, 0x3A, 0x79, 0x1C, 0x06, 0x05, 0x01,
+ 0x06, 0x3B, 0x04, 0x31, 0x55, 0x1C, 0x06, 0x05, 0x01, 0x02, 0x3A, 0x04,
+ 0x28, 0x56, 0x1C, 0x06, 0x05, 0x01, 0x03, 0x3A, 0x04, 0x1F, 0x57, 0x1C,
+ 0x06, 0x05, 0x01, 0x04, 0x3A, 0x04, 0x16, 0x58, 0x1C, 0x06, 0x05, 0x01,
+ 0x05, 0x3A, 0x04, 0x0D, 0x59, 0x1C, 0x06, 0x05, 0x01, 0x06, 0x3A, 0x04,
+ 0x04, 0x01, 0x00, 0x01, 0x00, 0x04, 0x04, 0x01, 0x00, 0x01, 0x00, 0x46,
+ 0x25, 0x45, 0x25, 0x7A, 0x61, 0x7A, 0x51, 0x1A, 0x01, 0x01, 0x3D, 0x25,
+ 0x73, 0x30, 0x1D, 0x00, 0x00, 0x01, 0x81, 0x06, 0x00, 0x01, 0x54, 0x0D,
+ 0x06, 0x02, 0x32, 0x1D, 0x1B, 0x03, 0x00, 0x0A, 0x02, 0x00, 0x00, 0x00,
+ 0x6D, 0x71, 0x1B, 0x01, 0x01, 0x11, 0x06, 0x08, 0x63, 0x01, 0x01, 0x15,
+ 0x3E, 0x25, 0x04, 0x01, 0x2B, 0x7A, 0x00, 0x00, 0x70, 0x01, 0x06, 0x50,
+ 0x6F, 0x00, 0x00, 0x70, 0x01, 0x03, 0x50, 0x6B, 0x72, 0x06, 0x02, 0x37,
+ 0x1D, 0x00, 0x00, 0x26, 0x1B, 0x06, 0x07, 0x21, 0x1B, 0x06, 0x01, 0x16,
+ 0x04, 0x76, 0x2B, 0x00, 0x00, 0x01, 0x01, 0x50, 0x6A, 0x01, 0x01, 0x10,
+ 0x06, 0x02, 0x2C, 0x1D, 0x72, 0x27, 0x00, 0x00, 0x60, 0x05, 0x02, 0x39,
+ 0x1D, 0x47, 0x1C, 0x06, 0x04, 0x01, 0x17, 0x04, 0x12, 0x48, 0x1C, 0x06,
+ 0x04, 0x01, 0x18, 0x04, 0x0A, 0x49, 0x1C, 0x06, 0x04, 0x01, 0x19, 0x04,
+ 0x02, 0x39, 0x1D, 0x00, 0x04, 0x70, 0x1B, 0x01, 0x17, 0x01, 0x18, 0x4B,
+ 0x05, 0x02, 0x2F, 0x1D, 0x01, 0x18, 0x11, 0x03, 0x00, 0x4D, 0x6B, 0x66,
+ 0x02, 0x00, 0x06, 0x0C, 0x01, 0x80, 0x64, 0x08, 0x03, 0x01, 0x66, 0x02,
+ 0x01, 0x09, 0x04, 0x0E, 0x1B, 0x01, 0x32, 0x0D, 0x06, 0x04, 0x01, 0x80,
+ 0x64, 0x09, 0x01, 0x8E, 0x6C, 0x09, 0x03, 0x01, 0x02, 0x01, 0x01, 0x82,
+ 0x6D, 0x08, 0x02, 0x01, 0x01, 0x03, 0x09, 0x01, 0x04, 0x0C, 0x09, 0x02,
+ 0x01, 0x01, 0x80, 0x63, 0x09, 0x01, 0x80, 0x64, 0x0C, 0x0A, 0x02, 0x01,
+ 0x01, 0x83, 0x0F, 0x09, 0x01, 0x83, 0x10, 0x0C, 0x09, 0x03, 0x03, 0x01,
+ 0x01, 0x01, 0x0C, 0x67, 0x2A, 0x01, 0x01, 0x0E, 0x02, 0x01, 0x01, 0x04,
+ 0x07, 0x28, 0x02, 0x01, 0x01, 0x80, 0x64, 0x07, 0x27, 0x02, 0x01, 0x01,
+ 0x83, 0x10, 0x07, 0x28, 0x1F, 0x15, 0x06, 0x03, 0x01, 0x18, 0x09, 0x5D,
+ 0x09, 0x52, 0x1B, 0x01, 0x05, 0x14, 0x02, 0x03, 0x09, 0x03, 0x03, 0x01,
+ 0x1F, 0x15, 0x01, 0x01, 0x26, 0x67, 0x02, 0x03, 0x09, 0x2A, 0x03, 0x03,
+ 0x01, 0x00, 0x01, 0x17, 0x67, 0x01, 0x9C, 0x10, 0x08, 0x03, 0x02, 0x01,
+ 0x00, 0x01, 0x3B, 0x67, 0x01, 0x3C, 0x08, 0x02, 0x02, 0x09, 0x03, 0x02,
+ 0x01, 0x00, 0x01, 0x3C, 0x67, 0x02, 0x02, 0x09, 0x03, 0x02, 0x72, 0x1B,
+ 0x01, 0x2E, 0x11, 0x06, 0x0D, 0x1A, 0x72, 0x1B, 0x01, 0x30, 0x01, 0x39,
+ 0x4B, 0x06, 0x03, 0x1A, 0x04, 0x74, 0x01, 0x80, 0x5A, 0x10, 0x06, 0x02,
+ 0x2F, 0x1D, 0x51, 0x02, 0x03, 0x02, 0x02, 0x00, 0x01, 0x72, 0x53, 0x01,
+ 0x0A, 0x08, 0x03, 0x00, 0x72, 0x53, 0x02, 0x00, 0x09, 0x00, 0x02, 0x03,
+ 0x00, 0x03, 0x01, 0x66, 0x1B, 0x02, 0x01, 0x02, 0x00, 0x4B, 0x05, 0x02,
+ 0x2F, 0x1D, 0x00, 0x00, 0x23, 0x70, 0x01, 0x02, 0x50, 0x0B, 0x69, 0x00,
+ 0x03, 0x1B, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02, 0x6B, 0x72, 0x1B, 0x01,
+ 0x81, 0x00, 0x13, 0x06, 0x02, 0x36, 0x1D, 0x1B, 0x01, 0x00, 0x11, 0x06,
+ 0x0B, 0x1A, 0x1B, 0x05, 0x04, 0x1A, 0x01, 0x00, 0x00, 0x72, 0x04, 0x6F,
+ 0x02, 0x01, 0x1B, 0x05, 0x02, 0x33, 0x1D, 0x2A, 0x03, 0x01, 0x02, 0x02,
+ 0x25, 0x02, 0x02, 0x29, 0x03, 0x02, 0x1B, 0x06, 0x03, 0x72, 0x04, 0x68,
+ 0x1A, 0x02, 0x00, 0x02, 0x01, 0x0A, 0x00, 0x01, 0x72, 0x1B, 0x01, 0x81,
+ 0x00, 0x0D, 0x06, 0x01, 0x00, 0x01, 0x81, 0x00, 0x0A, 0x1B, 0x05, 0x02,
+ 0x31, 0x1D, 0x03, 0x00, 0x01, 0x00, 0x02, 0x00, 0x01, 0x00, 0x12, 0x06,
+ 0x19, 0x02, 0x00, 0x2A, 0x03, 0x00, 0x1B, 0x01, 0x83, 0xFF, 0xFF, 0x7F,
+ 0x12, 0x06, 0x02, 0x32, 0x1D, 0x01, 0x08, 0x0E, 0x26, 0x72, 0x23, 0x09,
+ 0x04, 0x60, 0x00, 0x00, 0x6A, 0x5E, 0x00, 0x00, 0x6B, 0x7A, 0x00, 0x00,
+ 0x70, 0x4E, 0x6B, 0x00, 0x01, 0x6B, 0x1B, 0x05, 0x02, 0x36, 0x1D, 0x72,
+ 0x1B, 0x01, 0x81, 0x00, 0x13, 0x06, 0x02, 0x36, 0x1D, 0x03, 0x00, 0x1B,
+ 0x06, 0x16, 0x72, 0x02, 0x00, 0x1B, 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x13,
+ 0x06, 0x02, 0x36, 0x1D, 0x01, 0x08, 0x0E, 0x09, 0x03, 0x00, 0x04, 0x67,
+ 0x1A, 0x02, 0x00, 0x00, 0x00, 0x6B, 0x1B, 0x01, 0x81, 0x7F, 0x12, 0x06,
+ 0x08, 0x7A, 0x01, 0x00, 0x44, 0x25, 0x01, 0x00, 0x00, 0x1B, 0x44, 0x25,
+ 0x44, 0x29, 0x62, 0x01, 0x7F, 0x00, 0x01, 0x72, 0x03, 0x00, 0x02, 0x00,
+ 0x01, 0x05, 0x14, 0x01, 0x01, 0x15, 0x1E, 0x02, 0x00, 0x01, 0x06, 0x14,
+ 0x1B, 0x01, 0x01, 0x15, 0x06, 0x02, 0x2D, 0x1D, 0x01, 0x04, 0x0E, 0x02,
+ 0x00, 0x01, 0x1F, 0x15, 0x1B, 0x01, 0x1F, 0x11, 0x06, 0x02, 0x2E, 0x1D,
+ 0x09, 0x00, 0x00, 0x1B, 0x05, 0x05, 0x01, 0x00, 0x01, 0x7F, 0x00, 0x70,
+ 0x00, 0x00, 0x1B, 0x05, 0x02, 0x32, 0x1D, 0x2A, 0x73, 0x00, 0x00, 0x22,
+ 0x1B, 0x01, 0x00, 0x13, 0x06, 0x01, 0x00, 0x1A, 0x16, 0x04, 0x74, 0x00,
+ 0x01, 0x01, 0x00, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x01, 0x15, 0x00, 0x00,
+ 0x01, 0x1F, 0x00, 0x00, 0x01, 0x29, 0x00, 0x00, 0x01, 0x33, 0x00, 0x00,
+ 0x7B, 0x1A, 0x00, 0x00, 0x1B, 0x06, 0x07, 0x7C, 0x1B, 0x06, 0x01, 0x16,
+ 0x04, 0x76, 0x00, 0x00, 0x01, 0x00, 0x20, 0x21, 0x0B, 0x2B, 0x00
+};
+
+static const uint16_t t0_caddr[] = {
+ 0,
+ 5,
+ 10,
+ 15,
+ 20,
+ 24,
+ 28,
+ 32,
+ 36,
+ 40,
+ 44,
+ 48,
+ 52,
+ 56,
+ 60,
+ 64,
+ 68,
+ 72,
+ 76,
+ 80,
+ 84,
+ 88,
+ 93,
+ 98,
+ 103,
+ 111,
+ 116,
+ 121,
+ 126,
+ 131,
+ 136,
+ 141,
+ 146,
+ 151,
+ 156,
+ 161,
+ 166,
+ 181,
+ 187,
+ 193,
+ 198,
+ 206,
+ 214,
+ 220,
+ 231,
+ 246,
+ 250,
+ 255,
+ 260,
+ 265,
+ 270,
+ 275,
+ 279,
+ 289,
+ 620,
+ 625,
+ 639,
+ 659,
+ 666,
+ 678,
+ 692,
+ 707,
+ 740,
+ 960,
+ 974,
+ 991,
+ 1000,
+ 1067,
+ 1123,
+ 1127,
+ 1131,
+ 1136,
+ 1184,
+ 1210,
+ 1254,
+ 1265,
+ 1274,
+ 1287,
+ 1291,
+ 1295,
+ 1299,
+ 1303,
+ 1307,
+ 1311,
+ 1315,
+ 1327
+};
+
+#define T0_INTERPRETED 39
+
+#define T0_ENTER(ip, rp, slot) do { \
+ const unsigned char *t0_newip; \
+ uint32_t t0_lnum; \
+ t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \
+ t0_lnum = t0_parse7E_unsigned(&t0_newip); \
+ (rp) += t0_lnum; \
+ *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \
+ (ip) = t0_newip; \
+ } while (0)
+
+#define T0_DEFENTRY(name, slot) \
+void \
+name(void *ctx) \
+{ \
+ t0_context *t0ctx = ctx; \
+ t0ctx->ip = &t0_codeblock[0]; \
+ T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
+}
+
+T0_DEFENTRY(br_x509_decoder_init_main, 92)
+
+#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++)
+
+void
+br_x509_decoder_run(void *t0ctx)
+{
+ uint32_t *dp, *rp;
+ const unsigned char *ip;
+
+#define T0_LOCAL(x) (*(rp - 2 - (x)))
+#define T0_POP() (*-- dp)
+#define T0_POPi() (*(int32_t *)(-- dp))
+#define T0_PEEK(x) (*(dp - 1 - (x)))
+#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x)))
+#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0)
+#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0)
+#define T0_RPOP() (*-- rp)
+#define T0_RPOPi() (*(int32_t *)(-- rp))
+#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0)
+#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0)
+#define T0_ROLL(x) do { \
+ size_t t0len = (size_t)(x); \
+ uint32_t t0tmp = *(dp - 1 - t0len); \
+ memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_SWAP() do { \
+ uint32_t t0tmp = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_ROT() do { \
+ uint32_t t0tmp = *(dp - 3); \
+ *(dp - 3) = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_NROT() do { \
+ uint32_t t0tmp = *(dp - 1); \
+ *(dp - 1) = *(dp - 2); \
+ *(dp - 2) = *(dp - 3); \
+ *(dp - 3) = t0tmp; \
+} while (0)
+#define T0_PICK(x) do { \
+ uint32_t t0depth = (x); \
+ T0_PUSH(T0_PEEK(t0depth)); \
+} while (0)
+#define T0_CO() do { \
+ goto t0_exit; \
+} while (0)
+#define T0_RET() goto t0_next
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ goto t0_next;
+ for (;;) {
+ uint32_t t0x;
+
+ t0_next:
+ t0x = T0_NEXT(&ip);
+ if (t0x < T0_INTERPRETED) {
+ switch (t0x) {
+ int32_t t0off;
+
+ case 0: /* ret */
+ t0x = T0_RPOP();
+ rp -= (t0x >> 16);
+ t0x &= 0xFFFF;
+ if (t0x == 0) {
+ ip = NULL;
+ goto t0_exit;
+ }
+ ip = &t0_codeblock[t0x];
+ break;
+ case 1: /* literal constant */
+ T0_PUSHi(t0_parse7E_signed(&ip));
+ break;
+ case 2: /* read local */
+ T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip)));
+ break;
+ case 3: /* write local */
+ T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP();
+ break;
+ case 4: /* jump */
+ t0off = t0_parse7E_signed(&ip);
+ ip += t0off;
+ break;
+ case 5: /* jump if */
+ t0off = t0_parse7E_signed(&ip);
+ if (T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 6: /* jump if not */
+ t0off = t0_parse7E_signed(&ip);
+ if (!T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 7: {
+ /* %25 */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSHi(a % b);
+
+ }
+ break;
+ case 8: {
+ /* * */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a * b);
+
+ }
+ break;
+ case 9: {
+ /* + */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a + b);
+
+ }
+ break;
+ case 10: {
+ /* - */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a - b);
+
+ }
+ break;
+ case 11: {
+ /* -rot */
+ T0_NROT();
+ }
+ break;
+ case 12: {
+ /* / */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSHi(a / b);
+
+ }
+ break;
+ case 13: {
+ /* < */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a < b));
+
+ }
+ break;
+ case 14: {
+ /* << */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x << c);
+
+ }
+ break;
+ case 15: {
+ /* <= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a <= b));
+
+ }
+ break;
+ case 16: {
+ /* <> */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a != b));
+
+ }
+ break;
+ case 17: {
+ /* = */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a == b));
+
+ }
+ break;
+ case 18: {
+ /* > */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a > b));
+
+ }
+ break;
+ case 19: {
+ /* >= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a >= b));
+
+ }
+ break;
+ case 20: {
+ /* >> */
+
+ int c = (int)T0_POPi();
+ int32_t x = T0_POPi();
+ T0_PUSHi(x >> c);
+
+ }
+ break;
+ case 21: {
+ /* and */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a & b);
+
+ }
+ break;
+ case 22: {
+ /* co */
+ T0_CO();
+ }
+ break;
+ case 23: {
+ /* copy-ec-pkey */
+
+ size_t qlen = T0_POP();
+ uint32_t curve = T0_POP();
+ CTX->pkey.key_type = BR_KEYTYPE_EC;
+ CTX->pkey.key.ec.curve = curve;
+ CTX->pkey.key.ec.q = CTX->pkey_data;
+ CTX->pkey.key.ec.qlen = qlen;
+
+ }
+ break;
+ case 24: {
+ /* copy-rsa-pkey */
+
+ size_t elen = T0_POP();
+ size_t nlen = T0_POP();
+ CTX->pkey.key_type = BR_KEYTYPE_RSA;
+ CTX->pkey.key.rsa.n = CTX->pkey_data;
+ CTX->pkey.key.rsa.nlen = nlen;
+ CTX->pkey.key.rsa.e = CTX->pkey_data + nlen;
+ CTX->pkey.key.rsa.elen = elen;
+
+ }
+ break;
+ case 25: {
+ /* data-get8 */
+
+ size_t addr = T0_POP();
+ T0_PUSH(t0_datablock[addr]);
+
+ }
+ break;
+ case 26: {
+ /* drop */
+ (void)T0_POP();
+ }
+ break;
+ case 27: {
+ /* dup */
+ T0_PUSH(T0_PEEK(0));
+ }
+ break;
+ case 28: {
+ /* eqOID */
+
+ const unsigned char *a2 = &t0_datablock[T0_POP()];
+ const unsigned char *a1 = &CTX->pad[0];
+ size_t len = a1[0];
+ int x;
+ if (len == a2[0]) {
+ x = -(memcmp(a1 + 1, a2 + 1, len) == 0);
+ } else {
+ x = 0;
+ }
+ T0_PUSH((uint32_t)x);
+
+ }
+ break;
+ case 29: {
+ /* fail */
+
+ CTX->err = T0_POPi();
+ T0_CO();
+
+ }
+ break;
+ case 30: {
+ /* neg */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(-a);
+
+ }
+ break;
+ case 31: {
+ /* or */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a | b);
+
+ }
+ break;
+ case 32: {
+ /* over */
+ T0_PUSH(T0_PEEK(1));
+ }
+ break;
+ case 33: {
+ /* read-blob-inner */
+
+ uint32_t len = T0_POP();
+ uint32_t addr = T0_POP();
+ size_t clen = CTX->hlen;
+ if (clen > len) {
+ clen = (size_t)len;
+ }
+ if (addr != 0) {
+ memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
+ }
+ if (CTX->copy_dn && CTX->append_dn) {
+ CTX->append_dn(CTX->append_dn_ctx, CTX->hbuf, clen);
+ }
+ CTX->hbuf += clen;
+ CTX->hlen -= clen;
+ T0_PUSH(addr + clen);
+ T0_PUSH(len - clen);
+
+ }
+ break;
+ case 34: {
+ /* read8-low */
+
+ if (CTX->hlen == 0) {
+ T0_PUSHi(-1);
+ } else {
+ unsigned char x = *CTX->hbuf ++;
+ if (CTX->copy_dn && CTX->append_dn) {
+ CTX->append_dn(CTX->append_dn_ctx, &x, 1);
+ }
+ CTX->hlen --;
+ T0_PUSH(x);
+ }
+
+ }
+ break;
+ case 35: {
+ /* rot */
+ T0_ROT();
+ }
+ break;
+ case 36: {
+ /* set32 */
+
+ uint32_t addr = T0_POP();
+ *(uint32_t *)(void *)((unsigned char *)CTX + addr) = T0_POP();
+
+ }
+ break;
+ case 37: {
+ /* set8 */
+
+ uint32_t addr = T0_POP();
+ *((unsigned char *)CTX + addr) = (unsigned char)T0_POP();
+
+ }
+ break;
+ case 38: {
+ /* swap */
+ T0_SWAP();
+ }
+ break;
+ }
+
+ } else {
+ T0_ENTER(ip, rp, t0x);
+ }
+ }
+t0_exit:
+ ((t0_context *)t0ctx)->dp = dp;
+ ((t0_context *)t0ctx)->rp = rp;
+ ((t0_context *)t0ctx)->ip = ip;
+}
diff --git a/contrib/bearssl/src/x509/x509_decoder.t0 b/contrib/bearssl/src/x509/x509_decoder.t0
new file mode 100644
index 000000000000..0bf276fba6ab
--- /dev/null
+++ b/contrib/bearssl/src/x509/x509_decoder.t0
@@ -0,0 +1,321 @@
+\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+\
+\ Permission is hereby granted, free of charge, to any person obtaining
+\ a copy of this software and associated documentation files (the
+\ "Software"), to deal in the Software without restriction, including
+\ without limitation the rights to use, copy, modify, merge, publish,
+\ distribute, sublicense, and/or sell copies of the Software, and to
+\ permit persons to whom the Software is furnished to do so, subject to
+\ the following conditions:
+\
+\ The above copyright notice and this permission notice shall be
+\ included in all copies or substantial portions of the Software.
+\
+\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+\ SOFTWARE.
+
+preamble {
+
+#include "inner.h"
+
+#define CTX ((br_x509_decoder_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_decoder_context, cpu)))
+#define CONTEXT_NAME br_x509_decoder_context
+
+/* see bearssl_x509.h */
+void
+br_x509_decoder_init(br_x509_decoder_context *ctx,
+ void (*append_dn)(void *ctx, const void *buf, size_t len),
+ void *append_dn_ctx)
+{
+ memset(ctx, 0, sizeof *ctx);
+ /* obsolete
+ ctx->err = 0;
+ ctx->hbuf = NULL;
+ ctx->hlen = 0;
+ */
+ ctx->append_dn = append_dn;
+ ctx->append_dn_ctx = append_dn_ctx;
+ ctx->cpu.dp = &ctx->dp_stack[0];
+ ctx->cpu.rp = &ctx->rp_stack[0];
+ br_x509_decoder_init_main(&ctx->cpu);
+ br_x509_decoder_run(&ctx->cpu);
+}
+
+/* see bearssl_x509.h */
+void
+br_x509_decoder_push(br_x509_decoder_context *ctx,
+ const void *data, size_t len)
+{
+ ctx->hbuf = data;
+ ctx->hlen = len;
+ br_x509_decoder_run(&ctx->cpu);
+}
+
+}
+
+addr: decoded
+addr: notbefore_days
+addr: notbefore_seconds
+addr: notafter_days
+addr: notafter_seconds
+addr: isCA
+addr: copy_dn
+addr: signer_key_type
+addr: signer_hash_id
+
+cc: read8-low ( -- x ) {
+ if (CTX->hlen == 0) {
+ T0_PUSHi(-1);
+ } else {
+ unsigned char x = *CTX->hbuf ++;
+ if (CTX->copy_dn && CTX->append_dn) {
+ CTX->append_dn(CTX->append_dn_ctx, &x, 1);
+ }
+ CTX->hlen --;
+ T0_PUSH(x);
+ }
+}
+
+cc: read-blob-inner ( addr len -- addr len ) {
+ uint32_t len = T0_POP();
+ uint32_t addr = T0_POP();
+ size_t clen = CTX->hlen;
+ if (clen > len) {
+ clen = (size_t)len;
+ }
+ if (addr != 0) {
+ memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
+ }
+ if (CTX->copy_dn && CTX->append_dn) {
+ CTX->append_dn(CTX->append_dn_ctx, CTX->hbuf, clen);
+ }
+ CTX->hbuf += clen;
+ CTX->hlen -= clen;
+ T0_PUSH(addr + clen);
+ T0_PUSH(len - clen);
+}
+
+\ Get the address and length for the pkey_data buffer.
+: addr-len-pkey_data ( -- addr len )
+ CX 0 8191 { offsetof(br_x509_decoder_context, pkey_data) }
+ CX 0 8191 { BR_X509_BUFSIZE_KEY } ;
+
+\ Copy the public key (RSA) to the permanent buffer.
+cc: copy-rsa-pkey ( nlen elen -- ) {
+ size_t elen = T0_POP();
+ size_t nlen = T0_POP();
+ CTX->pkey.key_type = BR_KEYTYPE_RSA;
+ CTX->pkey.key.rsa.n = CTX->pkey_data;
+ CTX->pkey.key.rsa.nlen = nlen;
+ CTX->pkey.key.rsa.e = CTX->pkey_data + nlen;
+ CTX->pkey.key.rsa.elen = elen;
+}
+
+\ Copy the public key (EC) to the permanent buffer.
+cc: copy-ec-pkey ( curve qlen -- ) {
+ size_t qlen = T0_POP();
+ uint32_t curve = T0_POP();
+ CTX->pkey.key_type = BR_KEYTYPE_EC;
+ CTX->pkey.key.ec.curve = curve;
+ CTX->pkey.key.ec.q = CTX->pkey_data;
+ CTX->pkey.key.ec.qlen = qlen;
+}
+
+\ Extensions with specific processing.
+OID: basicConstraints 2.5.29.19
+
+\ Process a Basic Constraints extension. We want the "CA" flag only.
+: process-basicConstraints ( lim -- lim )
+ read-sequence-open
+ read-tag-or-end dup 0x01 = if
+ read-boolean 1 and addr-isCA set8
+ else
+ 2drop
+ then
+ skip-close-elt
+ ;
+
+\ Decode a certificate.
+: main ( -- ! )
+
+ \ Initialise state flags.
+ 0 addr-decoded set8
+ 0 addr-copy_dn set8
+
+ \ An arbitrary limit for the total certificate size.
+ 0xFFFFFF
+
+ \ Open the outer SEQUENCE.
+ read-sequence-open
+
+ \ TBS
+ read-sequence-open
+
+ \ First element may be an explicit version. We accept only
+ \ versions 0 to 2 (certificates v1 to v3).
+ read-tag dup 0x20 = if
+ drop check-constructed read-length-open-elt
+ read-tag
+ 0x02 check-tag-primitive
+ read-small-int-value
+ 2 > if ERR_X509_UNSUPPORTED fail then
+ close-elt
+ read-tag
+ then
+
+ \ Serial number. We just check that the tag is correct.
+ 0x02 check-tag-primitive read-length-skip
+
+ \ Signature algorithm.
+ read-sequence-open skip-close-elt
+
+ \ Issuer name.
+ read-sequence-open skip-close-elt
+
+ \ Validity dates.
+ read-sequence-open
+ read-date addr-notbefore_seconds set32 addr-notbefore_days set32
+ read-date addr-notafter_seconds set32 addr-notafter_days set32
+ close-elt
+
+ \ Subject name.
+ 1 addr-copy_dn set8
+ read-sequence-open skip-close-elt
+ 0 addr-copy_dn set8
+
+ \ Public Key.
+ read-sequence-open
+ \ Algorithm Identifier. Right now we are only interested in the
+ \ OID, since we only support RSA keys.
+ \ TODO: support EC keys
+ read-sequence-open
+ read-OID ifnot ERR_X509_UNSUPPORTED fail then
+ choice
+ \ RSA public key.
+ rsaEncryption eqOID uf
+ skip-close-elt
+ \ Public key itself: the BIT STRING contains bytes
+ \ (no partial byte) and these bytes encode the
+ \ actual value.
+ read-bits-open
+ \ RSA public key is a SEQUENCE of two
+ \ INTEGER. We get both INTEGER values into
+ \ the pkey_data[] buffer, if they fit.
+ read-sequence-open
+ addr-len-pkey_data
+ read-integer { nlen }
+ addr-len-pkey_data swap nlen + swap nlen -
+ read-integer { elen }
+ close-elt
+ close-elt
+ nlen elen copy-rsa-pkey
+ enduf
+
+ \ EC public key.
+ id-ecPublicKey eqOID uf
+ \ We support only named curves, for which the
+ \ "parameters" field in the AlgorithmIdentifier
+ \ field should be an OID.
+ read-curve-ID { curve }
+ close-elt
+ read-bits-open
+ dup { qlen }
+ dup addr-len-pkey_data rot < if
+ ERR_X509_LIMIT_EXCEEDED fail
+ then
+ read-blob
+ curve qlen copy-ec-pkey
+ enduf
+ ERR_X509_UNSUPPORTED fail
+ endchoice
+ close-elt
+
+ \ This flag will be set to true if the Basic Constraints extension
+ \ is encountered.
+ 0 addr-isCA set8
+
+ \ Skip issuerUniqueID and subjectUniqueID, and process extensions
+ \ if present. Extensions are an explicit context tag of value 3
+ \ around a SEQUENCE OF extensions. Each extension is a SEQUENCE
+ \ with an OID, an optional boolean, and a value; the value is
+ \ an OCTET STRING.
+ read-tag-or-end
+ 0x21 iftag-skip
+ 0x22 iftag-skip
+ dup 0x23 = if
+ drop
+ check-constructed read-length-open-elt
+ read-sequence-open
+ begin dup while
+ read-sequence-open
+ read-OID drop
+ read-tag dup 0x01 = if
+ read-boolean drop
+ read-tag
+ then
+ 0x04 check-tag-primitive read-length-open-elt
+ choice
+ \ Extensions with specific processing.
+ basicConstraints eqOID uf
+ process-basicConstraints
+ enduf
+ skip-remaining
+ endchoice
+ close-elt
+ close-elt
+ repeat
+ close-elt
+ close-elt
+ else
+ -1 = ifnot ERR_X509_UNEXPECTED fail then
+ drop
+ then
+
+ close-elt
+
+ \ signature algorithm
+ read-sequence-open
+ read-OID if
+ choice
+ sha1WithRSAEncryption eqOID uf 2 KEYTYPE_RSA enduf
+ sha224WithRSAEncryption eqOID uf 3 KEYTYPE_RSA enduf
+ sha256WithRSAEncryption eqOID uf 4 KEYTYPE_RSA enduf
+ sha384WithRSAEncryption eqOID uf 5 KEYTYPE_RSA enduf
+ sha512WithRSAEncryption eqOID uf 6 KEYTYPE_RSA enduf
+
+ ecdsa-with-SHA1 eqOID uf 2 KEYTYPE_EC enduf
+ ecdsa-with-SHA224 eqOID uf 3 KEYTYPE_EC enduf
+ ecdsa-with-SHA256 eqOID uf 4 KEYTYPE_EC enduf
+ ecdsa-with-SHA384 eqOID uf 5 KEYTYPE_EC enduf
+ ecdsa-with-SHA512 eqOID uf 6 KEYTYPE_EC enduf
+
+ 0 0
+ endchoice
+ else
+ 0 0
+ then
+ addr-signer_key_type set8
+ addr-signer_hash_id set8
+ skip-close-elt
+ \ read-sequence-open skip-close-elt
+
+ \ signature value
+ read-bits-open skip-close-elt
+
+ \ Close the outer SEQUENCE.
+ close-elt
+ drop
+
+ \ Mark the decoding as successful.
+ 1 addr-decoded set8
+
+ \ Read one byte, then fail: if the read succeeds, then there is
+ \ some trailing byte.
+ read8-nc ERR_X509_EXTRA_ELEMENT fail
+ ;
diff --git a/contrib/bearssl/src/x509/x509_knownkey.c b/contrib/bearssl/src/x509/x509_knownkey.c
new file mode 100644
index 000000000000..7674f3fd041a
--- /dev/null
+++ b/contrib/bearssl/src/x509/x509_knownkey.c
@@ -0,0 +1,105 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_x509.h */
+void
+br_x509_knownkey_init_rsa(br_x509_knownkey_context *ctx,
+ const br_rsa_public_key *pk, unsigned usages)
+{
+ ctx->vtable = &br_x509_knownkey_vtable;
+ ctx->pkey.key_type = BR_KEYTYPE_RSA;
+ ctx->pkey.key.rsa = *pk;
+ ctx->usages = usages;
+}
+
+/* see bearssl_x509.h */
+void
+br_x509_knownkey_init_ec(br_x509_knownkey_context *ctx,
+ const br_ec_public_key *pk, unsigned usages)
+{
+ ctx->vtable = &br_x509_knownkey_vtable;
+ ctx->pkey.key_type = BR_KEYTYPE_EC;
+ ctx->pkey.key.ec = *pk;
+ ctx->usages = usages;
+}
+
+static void
+kk_start_chain(const br_x509_class **ctx, const char *server_name)
+{
+ (void)ctx;
+ (void)server_name;
+}
+
+static void
+kk_start_cert(const br_x509_class **ctx, uint32_t length)
+{
+ (void)ctx;
+ (void)length;
+}
+
+static void
+kk_append(const br_x509_class **ctx, const unsigned char *buf, size_t len)
+{
+ (void)ctx;
+ (void)buf;
+ (void)len;
+}
+
+static void
+kk_end_cert(const br_x509_class **ctx)
+{
+ (void)ctx;
+}
+
+static unsigned
+kk_end_chain(const br_x509_class **ctx)
+{
+ (void)ctx;
+ return 0;
+}
+
+static const br_x509_pkey *
+kk_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
+{
+ const br_x509_knownkey_context *xc;
+
+ xc = (const br_x509_knownkey_context *)ctx;
+ if (usages != NULL) {
+ *usages = xc->usages;
+ }
+ return &xc->pkey;
+}
+
+/* see bearssl_x509.h */
+const br_x509_class br_x509_knownkey_vtable = {
+ sizeof(br_x509_knownkey_context),
+ kk_start_chain,
+ kk_start_cert,
+ kk_append,
+ kk_end_cert,
+ kk_end_chain,
+ kk_get_pkey
+};
diff --git a/contrib/bearssl/src/x509/x509_minimal.c b/contrib/bearssl/src/x509/x509_minimal.c
new file mode 100644
index 000000000000..3b876ef81980
--- /dev/null
+++ b/contrib/bearssl/src/x509/x509_minimal.c
@@ -0,0 +1,1713 @@
+/* Automatically generated code; do not modify directly. */
+
+#include <stddef.h>
+#include <stdint.h>
+
+typedef struct {
+ uint32_t *dp;
+ uint32_t *rp;
+ const unsigned char *ip;
+} t0_context;
+
+static uint32_t
+t0_parse7E_unsigned(const unsigned char **p)
+{
+ uint32_t x;
+
+ x = 0;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ return x;
+ }
+ }
+}
+
+static int32_t
+t0_parse7E_signed(const unsigned char **p)
+{
+ int neg;
+ uint32_t x;
+
+ neg = ((**p) >> 6) & 1;
+ x = (uint32_t)-neg;
+ for (;;) {
+ unsigned y;
+
+ y = *(*p) ++;
+ x = (x << 7) | (uint32_t)(y & 0x7F);
+ if (y < 0x80) {
+ if (neg) {
+ return -(int32_t)~x - 1;
+ } else {
+ return (int32_t)x;
+ }
+ }
+ }
+}
+
+#define T0_VBYTE(x, n) (unsigned char)((((uint32_t)(x) >> (n)) & 0x7F) | 0x80)
+#define T0_FBYTE(x, n) (unsigned char)(((uint32_t)(x) >> (n)) & 0x7F)
+#define T0_SBYTE(x) (unsigned char)((((uint32_t)(x) >> 28) + 0xF8) ^ 0xF8)
+#define T0_INT1(x) T0_FBYTE(x, 0)
+#define T0_INT2(x) T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT3(x) T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT4(x) T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+#define T0_INT5(x) T0_SBYTE(x), T0_VBYTE(x, 21), T0_VBYTE(x, 14), T0_VBYTE(x, 7), T0_FBYTE(x, 0)
+
+/* static const unsigned char t0_datablock[]; */
+
+
+void br_x509_minimal_init_main(void *t0ctx);
+
+void br_x509_minimal_run(void *t0ctx);
+
+
+
+#include "inner.h"
+
+
+
+
+
+#include "inner.h"
+
+/*
+ * Implementation Notes
+ * --------------------
+ *
+ * The C code pushes the data by chunks; all decoding is done in the
+ * T0 code. The cert_length value is set to the certificate length when
+ * a new certificate is started; the T0 code picks it up as outer limit,
+ * and decoding functions use it to ensure that no attempt is made at
+ * reading past it. The T0 code also checks that once the certificate is
+ * decoded, there are no trailing bytes.
+ *
+ * The T0 code sets cert_length to 0 when the certificate is fully
+ * decoded.
+ *
+ * The C code must still perform two checks:
+ *
+ * -- If the certificate length is 0, then the T0 code will not be
+ * invoked at all. This invalid condition must thus be reported by the
+ * C code.
+ *
+ * -- When reaching the end of certificate, the C code must verify that
+ * the certificate length has been set to 0, thereby signaling that
+ * the T0 code properly decoded a certificate.
+ *
+ * Processing of a chain works in the following way:
+ *
+ * -- The error flag is set to a non-zero value when validation is
+ * finished. The value is either BR_ERR_X509_OK (validation is
+ * successful) or another non-zero error code. When a non-zero error
+ * code is obtained, the remaining bytes in the current certificate and
+ * the subsequent certificates (if any) are completely ignored.
+ *
+ * -- Each certificate is decoded in due course, with the following
+ * "interesting points":
+ *
+ * -- Start of the TBS: the multihash engine is reset and activated.
+ *
+ * -- Start of the issuer DN: the secondary hash engine is started,
+ * to process the encoded issuer DN.
+ *
+ * -- End of the issuer DN: the secondary hash engine is stopped. The
+ * resulting hash value is computed and then copied into the
+ * next_dn_hash[] buffer.
+ *
+ * -- Start of the subject DN: the secondary hash engine is started,
+ * to process the encoded subject DN.
+ *
+ * -- For the EE certificate only: the Common Name, if any, is matched
+ * against the expected server name.
+ *
+ * -- End of the subject DN: the secondary hash engine is stopped. The
+ * resulting hash value is computed into the pad. It is then processed:
+ *
+ * -- If this is the EE certificate, then the hash is ignored
+ * (except for direct trust processing, see later; the hash is
+ * simply left in current_dn_hash[]).
+ *
+ * -- Otherwise, the hashed subject DN is compared with the saved
+ * hash value (in saved_dn_hash[]). They must match.
+ *
+ * Either way, the next_dn_hash[] value is then copied into the
+ * saved_dn_hash[] value. Thus, at that point, saved_dn_hash[]
+ * contains the hash of the issuer DN for the current certificate,
+ * and current_dn_hash[] contains the hash of the subject DN for the
+ * current certificate.
+ *
+ * -- Public key: it is decoded into the cert_pkey[] buffer. Unknown
+ * key types are reported at that point.
+ *
+ * -- If this is the EE certificate, then the key type is compared
+ * with the expected key type (initialization parameter). The public
+ * key data is copied to ee_pkey_data[]. The key and hashed subject
+ * DN are also compared with the "direct trust" keys; if the key
+ * and DN are matched, then validation ends with a success.
+ *
+ * -- Otherwise, the saved signature (cert_sig[]) is verified
+ * against the saved TBS hash (tbs_hash[]) and that freshly
+ * decoded public key. Failure here ends validation with an error.
+ *
+ * -- Extensions: extension values are processed in due order.
+ *
+ * -- Basic Constraints: for all certificates except EE, must be
+ * present, indicate a CA, and have a path legnth compatible with
+ * the chain length so far.
+ *
+ * -- Key Usage: for the EE, if present, must allow signatures
+ * or encryption/key exchange, as required for the cipher suite.
+ * For non-EE, if present, must have the "certificate sign" bit.
+ *
+ * -- Subject Alt Name: for the EE, dNSName names are matched
+ * against the server name. Ignored for non-EE.
+ *
+ * -- Authority Key Identifier, Subject Key Identifier, Issuer
+ * Alt Name, Subject Directory Attributes, CRL Distribution Points
+ * Freshest CRL, Authority Info Access and Subject Info Access
+ * extensions are always ignored: they either contain only
+ * informative data, or they relate to revocation processing, which
+ * we explicitly do not support.
+ *
+ * -- All other extensions are ignored if non-critical. If a
+ * critical extension other than the ones above is encountered,
+ * then a failure is reported.
+ *
+ * -- End of the TBS: the multihash engine is stopped.
+ *
+ * -- Signature algorithm: the signature algorithm on the
+ * certificate is decoded. A failure is reported if that algorithm
+ * is unknown. The hashed TBS corresponding to the signature hash
+ * function is computed and stored in tbs_hash[] (if not supported,
+ * then a failure is reported). The hash OID and length are stored
+ * in cert_sig_hash_oid and cert_sig_hash_len.
+ *
+ * -- Signature value: the signature value is copied into the
+ * cert_sig[] array.
+ *
+ * -- Certificate end: the hashed issuer DN (saved_dn_hash[]) is
+ * looked up in the trust store (CA trust anchors only); for all
+ * that match, the signature (cert_sig[]) is verified against the
+ * anchor public key (hashed TBS is in tbs_hash[]). If one of these
+ * signatures is valid, then validation ends with a success.
+ *
+ * -- If the chain end is reached without obtaining a validation success,
+ * then validation is reported as failed.
+ */
+
+#if BR_USE_UNIX_TIME
+#include <time.h>
+#endif
+
+#if BR_USE_WIN32_TIME
+#include <windows.h>
+#endif
+
+/*
+ * The T0 compiler will produce these prototypes declarations in the
+ * header.
+ *
+void br_x509_minimal_init_main(void *ctx);
+void br_x509_minimal_run(void *ctx);
+ */
+
+/* see bearssl_x509.h */
+void
+br_x509_minimal_init(br_x509_minimal_context *ctx,
+ const br_hash_class *dn_hash_impl,
+ const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num)
+{
+ memset(ctx, 0, sizeof *ctx);
+ ctx->vtable = &br_x509_minimal_vtable;
+ ctx->dn_hash_impl = dn_hash_impl;
+ ctx->trust_anchors = trust_anchors;
+ ctx->trust_anchors_num = trust_anchors_num;
+}
+
+static void
+xm_start_chain(const br_x509_class **ctx, const char *server_name)
+{
+ br_x509_minimal_context *cc;
+ size_t u;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ for (u = 0; u < cc->num_name_elts; u ++) {
+ cc->name_elts[u].status = 0;
+ cc->name_elts[u].buf[0] = 0;
+ }
+ memset(&cc->pkey, 0, sizeof cc->pkey);
+ cc->num_certs = 0;
+ cc->err = 0;
+ cc->cpu.dp = cc->dp_stack;
+ cc->cpu.rp = cc->rp_stack;
+ br_x509_minimal_init_main(&cc->cpu);
+ if (server_name == NULL || *server_name == 0) {
+ cc->server_name = NULL;
+ } else {
+ cc->server_name = server_name;
+ }
+}
+
+static void
+xm_start_cert(const br_x509_class **ctx, uint32_t length)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err != 0) {
+ return;
+ }
+ if (length == 0) {
+ cc->err = BR_ERR_X509_TRUNCATED;
+ return;
+ }
+ cc->cert_length = length;
+}
+
+static void
+xm_append(const br_x509_class **ctx, const unsigned char *buf, size_t len)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err != 0) {
+ return;
+ }
+ cc->hbuf = buf;
+ cc->hlen = len;
+ br_x509_minimal_run(&cc->cpu);
+}
+
+static void
+xm_end_cert(const br_x509_class **ctx)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err == 0 && cc->cert_length != 0) {
+ cc->err = BR_ERR_X509_TRUNCATED;
+ }
+ cc->num_certs ++;
+}
+
+static unsigned
+xm_end_chain(const br_x509_class **ctx)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err == 0) {
+ if (cc->num_certs == 0) {
+ cc->err = BR_ERR_X509_EMPTY_CHAIN;
+ } else {
+ cc->err = BR_ERR_X509_NOT_TRUSTED;
+ }
+ } else if (cc->err == BR_ERR_X509_OK) {
+ return 0;
+ }
+ return (unsigned)cc->err;
+}
+
+static const br_x509_pkey *
+xm_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err == BR_ERR_X509_OK
+ || cc->err == BR_ERR_X509_NOT_TRUSTED)
+ {
+ if (usages != NULL) {
+ *usages = cc->key_usages;
+ }
+ return &((br_x509_minimal_context *)(void *)ctx)->pkey;
+ } else {
+ return NULL;
+ }
+}
+
+/* see bearssl_x509.h */
+const br_x509_class br_x509_minimal_vtable = {
+ sizeof(br_x509_minimal_context),
+ xm_start_chain,
+ xm_start_cert,
+ xm_append,
+ xm_end_cert,
+ xm_end_chain,
+ xm_get_pkey
+};
+
+#define CTX ((br_x509_minimal_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_minimal_context, cpu)))
+#define CONTEXT_NAME br_x509_minimal_context
+
+#define DNHASH_LEN ((CTX->dn_hash_impl->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK)
+
+/*
+ * Hash a DN (from a trust anchor) into the provided buffer. This uses the
+ * DN hash implementation and context structure from the X.509 engine
+ * context.
+ */
+static void
+hash_dn(br_x509_minimal_context *ctx, const void *dn, size_t len,
+ unsigned char *out)
+{
+ ctx->dn_hash_impl->init(&ctx->dn_hash.vtable);
+ ctx->dn_hash_impl->update(&ctx->dn_hash.vtable, dn, len);
+ ctx->dn_hash_impl->out(&ctx->dn_hash.vtable, out);
+}
+
+/*
+ * Compare two big integers for equality. The integers use unsigned big-endian
+ * encoding; extra leading bytes (of value 0) are allowed.
+ */
+static int
+eqbigint(const unsigned char *b1, size_t len1,
+ const unsigned char *b2, size_t len2)
+{
+ while (len1 > 0 && *b1 == 0) {
+ b1 ++;
+ len1 --;
+ }
+ while (len2 > 0 && *b2 == 0) {
+ b2 ++;
+ len2 --;
+ }
+ if (len1 != len2) {
+ return 0;
+ }
+ return memcmp(b1, b2, len1) == 0;
+}
+
+/*
+ * Compare two strings for equality, in a case-insensitive way. This
+ * function handles casing only for ASCII letters.
+ */
+static int
+eqnocase(const void *s1, const void *s2, size_t len)
+{
+ const unsigned char *buf1, *buf2;
+
+ buf1 = s1;
+ buf2 = s2;
+ while (len -- > 0) {
+ int x1, x2;
+
+ x1 = *buf1 ++;
+ x2 = *buf2 ++;
+ if (x1 >= 'A' && x1 <= 'Z') {
+ x1 += 'a' - 'A';
+ }
+ if (x2 >= 'A' && x2 <= 'Z') {
+ x2 += 'a' - 'A';
+ }
+ if (x1 != x2) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int verify_signature(br_x509_minimal_context *ctx,
+ const br_x509_pkey *pk);
+
+
+
+static const unsigned char t0_datablock[] = {
+ 0x00, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x01, 0x09,
+ 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x05, 0x09, 0x2A, 0x86,
+ 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01, 0x0E, 0x09, 0x2A, 0x86, 0x48, 0x86,
+ 0xF7, 0x0D, 0x01, 0x01, 0x0B, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D,
+ 0x01, 0x01, 0x0C, 0x09, 0x2A, 0x86, 0x48, 0x86, 0xF7, 0x0D, 0x01, 0x01,
+ 0x0D, 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A, 0x09, 0x60, 0x86, 0x48, 0x01,
+ 0x65, 0x03, 0x04, 0x02, 0x04, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03,
+ 0x04, 0x02, 0x01, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02,
+ 0x02, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x07,
+ 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x02, 0x01, 0x08, 0x2A, 0x86, 0x48, 0xCE,
+ 0x3D, 0x03, 0x01, 0x07, 0x05, 0x2B, 0x81, 0x04, 0x00, 0x22, 0x05, 0x2B,
+ 0x81, 0x04, 0x00, 0x23, 0x07, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x01,
+ 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x01, 0x08, 0x2A, 0x86,
+ 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x02, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D,
+ 0x04, 0x03, 0x03, 0x08, 0x2A, 0x86, 0x48, 0xCE, 0x3D, 0x04, 0x03, 0x04,
+ 0x03, 0x55, 0x04, 0x03, 0x00, 0x1F, 0x03, 0xFC, 0x07, 0x7F, 0x0B, 0x5E,
+ 0x0F, 0x1F, 0x12, 0xFE, 0x16, 0xBF, 0x1A, 0x9F, 0x1E, 0x7E, 0x22, 0x3F,
+ 0x26, 0x1E, 0x29, 0xDF, 0x00, 0x1F, 0x03, 0xFD, 0x07, 0x9F, 0x0B, 0x7E,
+ 0x0F, 0x3F, 0x13, 0x1E, 0x16, 0xDF, 0x1A, 0xBF, 0x1E, 0x9E, 0x22, 0x5F,
+ 0x26, 0x3E, 0x29, 0xFF, 0x03, 0x55, 0x1D, 0x13, 0x03, 0x55, 0x1D, 0x0F,
+ 0x03, 0x55, 0x1D, 0x11, 0x03, 0x55, 0x1D, 0x20, 0x08, 0x2B, 0x06, 0x01,
+ 0x05, 0x05, 0x07, 0x02, 0x01, 0x03, 0x55, 0x1D, 0x23, 0x03, 0x55, 0x1D,
+ 0x0E, 0x03, 0x55, 0x1D, 0x12, 0x03, 0x55, 0x1D, 0x09, 0x03, 0x55, 0x1D,
+ 0x1F, 0x03, 0x55, 0x1D, 0x2E, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07,
+ 0x01, 0x01, 0x08, 0x2B, 0x06, 0x01, 0x05, 0x05, 0x07, 0x01, 0x0B
+};
+
+static const unsigned char t0_codeblock[] = {
+ 0x00, 0x01, 0x00, 0x0D, 0x00, 0x00, 0x01, 0x00, 0x10, 0x00, 0x00, 0x01,
+ 0x00, 0x11, 0x00, 0x00, 0x01, 0x01, 0x09, 0x00, 0x00, 0x01, 0x01, 0x0A,
+ 0x00, 0x00, 0x24, 0x24, 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_BOOLEAN), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_DN), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_SERVER_NAME), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_TAG_CLASS), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_TAG_VALUE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_BAD_TIME), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_CRITICAL_EXTENSION), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_DN_MISMATCH), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_EXPIRED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_EXTRA_ELEMENT), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_FORBIDDEN_KEY_USAGE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_INDEFINITE_LENGTH), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_INNER_TRUNC), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_LIMIT_EXCEEDED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_NOT_CA), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_NOT_CONSTRUCTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_NOT_PRIMITIVE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_OVERFLOW), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_PARTIAL_BYTE), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_UNEXPECTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_UNSUPPORTED), 0x00, 0x00, 0x01,
+ T0_INT1(BR_ERR_X509_WEAK_PUBLIC_KEY), 0x00, 0x00, 0x01,
+ T0_INT1(BR_KEYTYPE_EC), 0x00, 0x00, 0x01, T0_INT1(BR_KEYTYPE_RSA),
+ 0x00, 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_length)), 0x00,
+ 0x00, 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig_hash_len)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig_hash_oid)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(CONTEXT_NAME, cert_sig_len)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, cert_signer_key_type)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(CONTEXT_NAME, current_dn_hash)), 0x00, 0x00,
+ 0x01, T0_INT2(offsetof(CONTEXT_NAME, key_usages)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(br_x509_minimal_context, pkey_data)), 0x01,
+ T0_INT2(BR_X509_BUFSIZE_KEY), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, min_rsa_size)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, next_dn_hash)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, num_certs)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, pad)), 0x00, 0x00, 0x01,
+ T0_INT2(offsetof(CONTEXT_NAME, saved_dn_hash)), 0x00, 0x00, 0xC9, 0x71,
+ 0x00, 0x00, 0x01, 0x80, 0x73, 0x00, 0x00, 0x01, 0x80, 0x7C, 0x00, 0x00,
+ 0x01, 0x81, 0x02, 0x00, 0x00, 0x92, 0x05, 0x05, 0x34, 0x42, 0x01, 0x00,
+ 0x00, 0x34, 0x01, 0x0A, 0x0E, 0x09, 0x01, 0x9A, 0xFF, 0xB8, 0x00, 0x0A,
+ 0x00, 0x00, 0x01, 0x82, 0x19, 0x00, 0x00, 0x01, 0x82, 0x01, 0x00, 0x00,
+ 0x01, 0x81, 0x68, 0x00, 0x04, 0x03, 0x00, 0x03, 0x01, 0x03, 0x02, 0x03,
+ 0x03, 0x02, 0x03, 0x02, 0x01, 0x11, 0x06, 0x07, 0x02, 0x02, 0x02, 0x00,
+ 0x0D, 0x04, 0x05, 0x02, 0x03, 0x02, 0x01, 0x0D, 0x00, 0x02, 0x03, 0x00,
+ 0x03, 0x01, 0x25, 0x02, 0x01, 0x13, 0x3B, 0x02, 0x00, 0x0F, 0x15, 0x00,
+ 0x00, 0x01, 0x81, 0x74, 0x00, 0x00, 0x05, 0x02, 0x52, 0x28, 0x00, 0x00,
+ 0x06, 0x02, 0x53, 0x28, 0x00, 0x00, 0x01, 0x10, 0x77, 0x00, 0x00, 0x11,
+ 0x05, 0x02, 0x56, 0x28, 0x74, 0x00, 0x00, 0x11, 0x05, 0x02, 0x56, 0x28,
+ 0x75, 0x00, 0x00, 0x06, 0x02, 0x4C, 0x28, 0x00, 0x00, 0x01, 0x82, 0x11,
+ 0x00, 0x00, 0x25, 0x20, 0x01, 0x08, 0x0E, 0x3B, 0x40, 0x20, 0x09, 0x00,
+ 0x09, 0x03, 0x00, 0x5B, 0x2B, 0xAF, 0x39, 0xAF, 0xB3, 0x25, 0x01, 0x20,
+ 0x11, 0x06, 0x11, 0x24, 0x74, 0xAD, 0xB3, 0x01, 0x02, 0x78, 0xB0, 0x01,
+ 0x02, 0x12, 0x06, 0x02, 0x57, 0x28, 0x79, 0xB3, 0x01, 0x02, 0x78, 0xAE,
+ 0xAF, 0xC2, 0x9C, 0x65, 0x61, 0x21, 0x16, 0xAF, 0xA7, 0x29, 0x69, 0x06,
+ 0x02, 0x4B, 0x28, 0xA7, 0x29, 0x71, 0x06, 0x02, 0x4B, 0x28, 0x79, 0x02,
+ 0x00, 0x06, 0x05, 0x9D, 0x03, 0x01, 0x04, 0x09, 0x9C, 0x61, 0x68, 0x21,
+ 0x27, 0x05, 0x02, 0x4A, 0x28, 0x68, 0x65, 0x21, 0x16, 0xAF, 0xAF, 0x9E,
+ 0x05, 0x02, 0x57, 0x28, 0xBC, 0x26, 0x06, 0x27, 0xC2, 0xA4, 0xAF, 0x63,
+ 0xAA, 0x03, 0x03, 0x63, 0x3B, 0x02, 0x03, 0x09, 0x3B, 0x02, 0x03, 0x0A,
+ 0xAA, 0x03, 0x04, 0x79, 0x64, 0x2A, 0x01, 0x81, 0x00, 0x09, 0x02, 0x03,
+ 0x12, 0x06, 0x02, 0x58, 0x28, 0x79, 0x5A, 0x03, 0x02, 0x04, 0x3A, 0x88,
+ 0x26, 0x06, 0x34, 0x9E, 0x05, 0x02, 0x57, 0x28, 0x6A, 0x26, 0x06, 0x04,
+ 0x01, 0x17, 0x04, 0x12, 0x6B, 0x26, 0x06, 0x04, 0x01, 0x18, 0x04, 0x0A,
+ 0x6C, 0x26, 0x06, 0x04, 0x01, 0x19, 0x04, 0x02, 0x57, 0x28, 0x03, 0x05,
+ 0x79, 0xA4, 0x25, 0x03, 0x06, 0x25, 0x63, 0x34, 0x0D, 0x06, 0x02, 0x50,
+ 0x28, 0xA5, 0x59, 0x03, 0x02, 0x04, 0x02, 0x57, 0x28, 0x79, 0x02, 0x00,
+ 0x06, 0x21, 0x02, 0x02, 0x5A, 0x30, 0x11, 0x06, 0x08, 0x24, 0x02, 0x03,
+ 0x02, 0x04, 0x1D, 0x04, 0x10, 0x59, 0x30, 0x11, 0x06, 0x08, 0x24, 0x02,
+ 0x05, 0x02, 0x06, 0x1C, 0x04, 0x03, 0x57, 0x28, 0x24, 0x04, 0x24, 0x02,
+ 0x02, 0x5A, 0x30, 0x11, 0x06, 0x08, 0x24, 0x02, 0x03, 0x02, 0x04, 0x23,
+ 0x04, 0x10, 0x59, 0x30, 0x11, 0x06, 0x08, 0x24, 0x02, 0x05, 0x02, 0x06,
+ 0x22, 0x04, 0x03, 0x57, 0x28, 0x24, 0x25, 0x06, 0x01, 0x28, 0x24, 0x01,
+ 0x00, 0x03, 0x07, 0xB4, 0x01, 0x21, 0x8F, 0x01, 0x22, 0x8F, 0x25, 0x01,
+ 0x23, 0x11, 0x06, 0x81, 0x26, 0x24, 0x74, 0xAD, 0xAF, 0x25, 0x06, 0x81,
+ 0x1A, 0x01, 0x00, 0x03, 0x08, 0xAF, 0x9E, 0x24, 0xB3, 0x25, 0x01, 0x01,
+ 0x11, 0x06, 0x04, 0xA6, 0x03, 0x08, 0xB3, 0x01, 0x04, 0x78, 0xAD, 0x70,
+ 0x26, 0x06, 0x0F, 0x02, 0x00, 0x06, 0x03, 0xC3, 0x04, 0x05, 0x99, 0x01,
+ 0x7F, 0x03, 0x07, 0x04, 0x80, 0x6C, 0x91, 0x26, 0x06, 0x06, 0x02, 0x00,
+ 0x9B, 0x04, 0x80, 0x62, 0xC5, 0x26, 0x06, 0x11, 0x02, 0x00, 0x06, 0x09,
+ 0x01, 0x00, 0x03, 0x01, 0x98, 0x03, 0x01, 0x04, 0x01, 0xC3, 0x04, 0x80,
+ 0x4D, 0x73, 0x26, 0x06, 0x0A, 0x02, 0x08, 0x06, 0x03, 0x9A, 0x04, 0x01,
+ 0xC3, 0x04, 0x3F, 0x6F, 0x26, 0x06, 0x03, 0xC3, 0x04, 0x38, 0xC8, 0x26,
+ 0x06, 0x03, 0xC3, 0x04, 0x31, 0x90, 0x26, 0x06, 0x03, 0xC3, 0x04, 0x2A,
+ 0xC6, 0x26, 0x06, 0x03, 0xC3, 0x04, 0x23, 0x7A, 0x26, 0x06, 0x03, 0xC3,
+ 0x04, 0x1C, 0x85, 0x26, 0x06, 0x03, 0xC3, 0x04, 0x15, 0x6E, 0x26, 0x06,
+ 0x03, 0xC3, 0x04, 0x0E, 0xC7, 0x26, 0x06, 0x03, 0xC3, 0x04, 0x07, 0x02,
+ 0x08, 0x06, 0x02, 0x49, 0x28, 0xC3, 0x79, 0x79, 0x04, 0xFE, 0x62, 0x79,
+ 0x79, 0x04, 0x08, 0x01, 0x7F, 0x11, 0x05, 0x02, 0x56, 0x28, 0x24, 0x79,
+ 0x3A, 0x02, 0x00, 0x06, 0x08, 0x02, 0x01, 0x3C, 0x2F, 0x05, 0x02, 0x45,
+ 0x28, 0x02, 0x00, 0x06, 0x01, 0x17, 0x02, 0x00, 0x02, 0x07, 0x2F, 0x05,
+ 0x02, 0x51, 0x28, 0xB3, 0x76, 0xAD, 0x9E, 0x06, 0x80, 0x77, 0xBD, 0x26,
+ 0x06, 0x07, 0x01, 0x02, 0x5A, 0x8A, 0x04, 0x80, 0x5E, 0xBE, 0x26, 0x06,
+ 0x07, 0x01, 0x03, 0x5A, 0x8B, 0x04, 0x80, 0x53, 0xBF, 0x26, 0x06, 0x07,
+ 0x01, 0x04, 0x5A, 0x8C, 0x04, 0x80, 0x48, 0xC0, 0x26, 0x06, 0x06, 0x01,
+ 0x05, 0x5A, 0x8D, 0x04, 0x3E, 0xC1, 0x26, 0x06, 0x06, 0x01, 0x06, 0x5A,
+ 0x8E, 0x04, 0x34, 0x7F, 0x26, 0x06, 0x06, 0x01, 0x02, 0x59, 0x8A, 0x04,
+ 0x2A, 0x80, 0x26, 0x06, 0x06, 0x01, 0x03, 0x59, 0x8B, 0x04, 0x20, 0x81,
+ 0x26, 0x06, 0x06, 0x01, 0x04, 0x59, 0x8C, 0x04, 0x16, 0x82, 0x26, 0x06,
+ 0x06, 0x01, 0x05, 0x59, 0x8D, 0x04, 0x0C, 0x83, 0x26, 0x06, 0x06, 0x01,
+ 0x06, 0x59, 0x8E, 0x04, 0x02, 0x57, 0x28, 0x5E, 0x35, 0x60, 0x37, 0x1B,
+ 0x25, 0x05, 0x02, 0x57, 0x28, 0x5D, 0x37, 0x04, 0x02, 0x57, 0x28, 0xC2,
+ 0xA4, 0x25, 0x01, T0_INT2(BR_X509_BUFSIZE_SIG), 0x12, 0x06, 0x02, 0x50,
+ 0x28, 0x25, 0x5F, 0x35, 0x5C, 0xA5, 0x79, 0x79, 0x01, 0x00, 0x5B, 0x36,
+ 0x18, 0x00, 0x00, 0x01, 0x30, 0x0A, 0x25, 0x01, 0x00, 0x01, 0x09, 0x72,
+ 0x05, 0x02, 0x48, 0x28, 0x00, 0x00, 0x30, 0x30, 0x00, 0x00, 0x01, 0x81,
+ 0x08, 0x00, 0x00, 0x01, 0x81, 0x10, 0x00, 0x00, 0x01, 0x81, 0x19, 0x00,
+ 0x00, 0x01, 0x81, 0x22, 0x00, 0x00, 0x01, 0x81, 0x2B, 0x00, 0x01, 0x7E,
+ 0x01, 0x01, 0x11, 0x3B, 0x01, 0x83, 0xFD, 0x7F, 0x11, 0x15, 0x06, 0x03,
+ 0x3B, 0x24, 0x00, 0x3B, 0x25, 0x03, 0x00, 0x25, 0xCA, 0x05, 0x04, 0x42,
+ 0x01, 0x00, 0x00, 0x25, 0x01, 0x81, 0x00, 0x0D, 0x06, 0x04, 0x96, 0x04,
+ 0x80, 0x49, 0x25, 0x01, 0x90, 0x00, 0x0D, 0x06, 0x0F, 0x01, 0x06, 0x14,
+ 0x01, 0x81, 0x40, 0x2F, 0x96, 0x02, 0x00, 0x01, 0x00, 0x97, 0x04, 0x33,
+ 0x25, 0x01, 0x83, 0xFF, 0x7F, 0x0D, 0x06, 0x14, 0x01, 0x0C, 0x14, 0x01,
+ 0x81, 0x60, 0x2F, 0x96, 0x02, 0x00, 0x01, 0x06, 0x97, 0x02, 0x00, 0x01,
+ 0x00, 0x97, 0x04, 0x17, 0x01, 0x12, 0x14, 0x01, 0x81, 0x70, 0x2F, 0x96,
+ 0x02, 0x00, 0x01, 0x0C, 0x97, 0x02, 0x00, 0x01, 0x06, 0x97, 0x02, 0x00,
+ 0x01, 0x00, 0x97, 0x00, 0x00, 0x01, 0x82, 0x15, 0x00, 0x00, 0x25, 0x01,
+ 0x83, 0xB0, 0x00, 0x01, 0x83, 0xB7, 0x7F, 0x72, 0x00, 0x00, 0x01, 0x81,
+ 0x34, 0x00, 0x00, 0x01, 0x80, 0x6B, 0x00, 0x00, 0x01, 0x81, 0x78, 0x00,
+ 0x00, 0x01, 0x3D, 0x00, 0x00, 0x01, 0x80, 0x43, 0x00, 0x00, 0x01, 0x80,
+ 0x4D, 0x00, 0x00, 0x01, 0x80, 0x57, 0x00, 0x00, 0x01, 0x80, 0x61, 0x00,
+ 0x00, 0x30, 0x11, 0x06, 0x04, 0x42, 0xAD, 0xC2, 0xB4, 0x00, 0x00, 0x01,
+ 0x82, 0x09, 0x00, 0x00, 0x01, 0x81, 0x6C, 0x00, 0x00, 0x25, 0x01, 0x83,
+ 0xB8, 0x00, 0x01, 0x83, 0xBF, 0x7F, 0x72, 0x00, 0x00, 0x01, 0x30, 0x62,
+ 0x37, 0x01, 0x7F, 0x7C, 0x19, 0x01, 0x00, 0x7C, 0x19, 0x04, 0x7A, 0x00,
+ 0x01, 0x81, 0x38, 0x00, 0x01, 0x7E, 0x0D, 0x06, 0x02, 0x4F, 0x28, 0x25,
+ 0x03, 0x00, 0x0A, 0x02, 0x00, 0x00, 0x00, 0x30, 0x25, 0x3F, 0x3B, 0x01,
+ 0x82, 0x00, 0x13, 0x2F, 0x06, 0x04, 0x42, 0x01, 0x00, 0x00, 0x30, 0x67,
+ 0x09, 0x37, 0x40, 0x00, 0x00, 0x14, 0x01, 0x3F, 0x15, 0x01, 0x81, 0x00,
+ 0x2F, 0x96, 0x00, 0x02, 0x01, 0x00, 0x03, 0x00, 0xAF, 0x25, 0x06, 0x80,
+ 0x59, 0xB3, 0x01, 0x20, 0x30, 0x11, 0x06, 0x17, 0x24, 0x74, 0xAD, 0x9E,
+ 0x24, 0x01, 0x7F, 0x2E, 0x03, 0x01, 0xB3, 0x01, 0x20, 0x77, 0xAD, 0xB2,
+ 0x02, 0x01, 0x1F, 0x79, 0x79, 0x04, 0x38, 0x01, 0x21, 0x30, 0x11, 0x06,
+ 0x08, 0x24, 0x75, 0xB6, 0x01, 0x01, 0x1E, 0x04, 0x2A, 0x01, 0x22, 0x30,
+ 0x11, 0x06, 0x11, 0x24, 0x75, 0xB6, 0x25, 0x06, 0x06, 0x2C, 0x02, 0x00,
+ 0x2F, 0x03, 0x00, 0x01, 0x02, 0x1E, 0x04, 0x13, 0x01, 0x26, 0x30, 0x11,
+ 0x06, 0x08, 0x24, 0x75, 0xB6, 0x01, 0x06, 0x1E, 0x04, 0x05, 0x42, 0xAE,
+ 0x01, 0x00, 0x24, 0x04, 0xFF, 0x23, 0x79, 0x02, 0x00, 0x00, 0x00, 0xAF,
+ 0xB4, 0x25, 0x01, 0x01, 0x11, 0x06, 0x08, 0xA6, 0x05, 0x02, 0x51, 0x28,
+ 0xB4, 0x04, 0x02, 0x51, 0x28, 0x25, 0x01, 0x02, 0x11, 0x06, 0x0C, 0x24,
+ 0x75, 0xB0, 0x66, 0x2B, 0x41, 0x0D, 0x06, 0x02, 0x51, 0x28, 0xB4, 0x01,
+ 0x7F, 0x10, 0x06, 0x02, 0x56, 0x28, 0x24, 0x79, 0x00, 0x00, 0xAF, 0x25,
+ 0x06, 0x1A, 0xAF, 0x9E, 0x24, 0x25, 0x06, 0x11, 0xAF, 0x25, 0x06, 0x0C,
+ 0xAF, 0x9E, 0x24, 0x89, 0x26, 0x05, 0x02, 0x49, 0x28, 0xC2, 0x04, 0x71,
+ 0x79, 0x79, 0x04, 0x63, 0x79, 0x00, 0x02, 0x03, 0x00, 0xB3, 0x01, 0x03,
+ 0x78, 0xAD, 0xBA, 0x03, 0x01, 0x02, 0x01, 0x01, 0x07, 0x12, 0x06, 0x02,
+ 0x56, 0x28, 0x25, 0x01, 0x00, 0x30, 0x11, 0x06, 0x05, 0x24, 0x4D, 0x28,
+ 0x04, 0x15, 0x01, 0x01, 0x30, 0x11, 0x06, 0x0A, 0x24, 0xBA, 0x02, 0x01,
+ 0x14, 0x02, 0x01, 0x0E, 0x04, 0x05, 0x24, 0xBA, 0x01, 0x00, 0x24, 0x02,
+ 0x00, 0x06, 0x19, 0x01, 0x00, 0x30, 0x01, 0x38, 0x15, 0x06, 0x03, 0x01,
+ 0x10, 0x2F, 0x3B, 0x01, 0x81, 0x40, 0x15, 0x06, 0x03, 0x01, 0x20, 0x2F,
+ 0x62, 0x37, 0x04, 0x07, 0x01, 0x04, 0x15, 0x05, 0x02, 0x4D, 0x28, 0xC2,
+ 0x00, 0x00, 0x38, 0xAF, 0xC2, 0x1A, 0x00, 0x03, 0x01, 0x00, 0x03, 0x00,
+ 0x38, 0xAF, 0x25, 0x06, 0x30, 0xB3, 0x01, 0x11, 0x77, 0xAD, 0x25, 0x05,
+ 0x02, 0x44, 0x28, 0x25, 0x06, 0x20, 0xAF, 0x9E, 0x24, 0x87, 0x26, 0x03,
+ 0x01, 0x01, 0x00, 0x2E, 0x03, 0x02, 0xB2, 0x25, 0x02, 0x01, 0x15, 0x06,
+ 0x07, 0x2C, 0x06, 0x04, 0x01, 0x7F, 0x03, 0x00, 0x02, 0x02, 0x1F, 0x79,
+ 0x04, 0x5D, 0x79, 0x04, 0x4D, 0x79, 0x1A, 0x02, 0x00, 0x00, 0x00, 0xB3,
+ 0x01, 0x06, 0x78, 0xB1, 0x00, 0x00, 0xB8, 0x86, 0x06, 0x0E, 0x3B, 0x25,
+ 0x05, 0x06, 0x42, 0x01, 0x00, 0x01, 0x00, 0x00, 0xB8, 0x6D, 0x04, 0x08,
+ 0x92, 0x06, 0x05, 0x24, 0x01, 0x00, 0x04, 0x00, 0x00, 0x00, 0xB9, 0x86,
+ 0x06, 0x0E, 0x3B, 0x25, 0x05, 0x06, 0x42, 0x01, 0x00, 0x01, 0x00, 0x00,
+ 0xB9, 0x6D, 0x04, 0x08, 0x92, 0x06, 0x05, 0x24, 0x01, 0x00, 0x04, 0x00,
+ 0x00, 0x00, 0xBA, 0x25, 0x01, 0x81, 0x00, 0x0D, 0x06, 0x04, 0x00, 0x04,
+ 0x80, 0x55, 0x25, 0x01, 0x81, 0x40, 0x0D, 0x06, 0x07, 0x24, 0x01, 0x00,
+ 0x00, 0x04, 0x80, 0x47, 0x25, 0x01, 0x81, 0x60, 0x0D, 0x06, 0x0E, 0x01,
+ 0x1F, 0x15, 0x01, 0x01, 0xA3, 0x01, 0x81, 0x00, 0x01, 0x8F, 0x7F, 0x04,
+ 0x32, 0x25, 0x01, 0x81, 0x70, 0x0D, 0x06, 0x0F, 0x01, 0x0F, 0x15, 0x01,
+ 0x02, 0xA3, 0x01, 0x90, 0x00, 0x01, 0x83, 0xFF, 0x7F, 0x04, 0x1C, 0x25,
+ 0x01, 0x81, 0x78, 0x0D, 0x06, 0x11, 0x01, 0x07, 0x15, 0x01, 0x03, 0xA3,
+ 0x01, 0x84, 0x80, 0x00, 0x01, 0x80, 0xC3, 0xFF, 0x7F, 0x04, 0x04, 0x24,
+ 0x01, 0x00, 0x00, 0x72, 0x05, 0x03, 0x24, 0x01, 0x00, 0x00, 0x00, 0x3B,
+ 0x25, 0x05, 0x06, 0x42, 0x01, 0x00, 0x01, 0x7F, 0x00, 0xBA, 0x34, 0x25,
+ 0x3D, 0x06, 0x03, 0x3B, 0x24, 0x00, 0x01, 0x06, 0x0E, 0x3B, 0x25, 0x01,
+ 0x06, 0x14, 0x01, 0x02, 0x10, 0x06, 0x04, 0x42, 0x01, 0x7F, 0x00, 0x01,
+ 0x3F, 0x15, 0x09, 0x00, 0x00, 0x25, 0x06, 0x06, 0x0B, 0xA2, 0x34, 0x41,
+ 0x04, 0x77, 0x24, 0x25, 0x00, 0x00, 0xB3, 0x01, 0x03, 0x78, 0xAD, 0xBA,
+ 0x06, 0x02, 0x55, 0x28, 0x00, 0x00, 0x3B, 0x25, 0x06, 0x07, 0x31, 0x25,
+ 0x06, 0x01, 0x19, 0x04, 0x76, 0x42, 0x00, 0x00, 0x01, 0x01, 0x78, 0xAC,
+ 0x01, 0x01, 0x10, 0x06, 0x02, 0x43, 0x28, 0xBA, 0x3E, 0x00, 0x04, 0xB3,
+ 0x25, 0x01, 0x17, 0x01, 0x18, 0x72, 0x05, 0x02, 0x48, 0x28, 0x01, 0x18,
+ 0x11, 0x03, 0x00, 0x75, 0xAD, 0xA8, 0x02, 0x00, 0x06, 0x0C, 0x01, 0x80,
+ 0x64, 0x08, 0x03, 0x01, 0xA8, 0x02, 0x01, 0x09, 0x04, 0x0E, 0x25, 0x01,
+ 0x32, 0x0D, 0x06, 0x04, 0x01, 0x80, 0x64, 0x09, 0x01, 0x8E, 0x6C, 0x09,
+ 0x03, 0x01, 0x02, 0x01, 0x01, 0x82, 0x6D, 0x08, 0x02, 0x01, 0x01, 0x03,
+ 0x09, 0x01, 0x04, 0x0C, 0x09, 0x02, 0x01, 0x01, 0x80, 0x63, 0x09, 0x01,
+ 0x80, 0x64, 0x0C, 0x0A, 0x02, 0x01, 0x01, 0x83, 0x0F, 0x09, 0x01, 0x83,
+ 0x10, 0x0C, 0x09, 0x03, 0x03, 0x01, 0x01, 0x01, 0x0C, 0xA9, 0x41, 0x01,
+ 0x01, 0x0E, 0x02, 0x01, 0x01, 0x04, 0x07, 0x3F, 0x02, 0x01, 0x01, 0x80,
+ 0x64, 0x07, 0x3E, 0x02, 0x01, 0x01, 0x83, 0x10, 0x07, 0x3F, 0x2F, 0x15,
+ 0x06, 0x03, 0x01, 0x18, 0x09, 0x94, 0x09, 0x7B, 0x25, 0x01, 0x05, 0x14,
+ 0x02, 0x03, 0x09, 0x03, 0x03, 0x01, 0x1F, 0x15, 0x01, 0x01, 0x3B, 0xA9,
+ 0x02, 0x03, 0x09, 0x41, 0x03, 0x03, 0x01, 0x00, 0x01, 0x17, 0xA9, 0x01,
+ 0x9C, 0x10, 0x08, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3B, 0xA9, 0x01, 0x3C,
+ 0x08, 0x02, 0x02, 0x09, 0x03, 0x02, 0x01, 0x00, 0x01, 0x3C, 0xA9, 0x02,
+ 0x02, 0x09, 0x03, 0x02, 0xBA, 0x25, 0x01, 0x2E, 0x11, 0x06, 0x0D, 0x24,
+ 0xBA, 0x25, 0x01, 0x30, 0x01, 0x39, 0x72, 0x06, 0x03, 0x24, 0x04, 0x74,
+ 0x01, 0x80, 0x5A, 0x10, 0x06, 0x02, 0x48, 0x28, 0x79, 0x02, 0x03, 0x02,
+ 0x02, 0x00, 0x01, 0xBA, 0x7D, 0x01, 0x0A, 0x08, 0x03, 0x00, 0xBA, 0x7D,
+ 0x02, 0x00, 0x09, 0x00, 0x02, 0x03, 0x00, 0x03, 0x01, 0xA8, 0x25, 0x02,
+ 0x01, 0x02, 0x00, 0x72, 0x05, 0x02, 0x48, 0x28, 0x00, 0x00, 0x34, 0xB3,
+ 0x01, 0x02, 0x78, 0x0B, 0xAB, 0x00, 0x03, 0x25, 0x03, 0x00, 0x03, 0x01,
+ 0x03, 0x02, 0xAD, 0xBA, 0x25, 0x01, 0x81, 0x00, 0x13, 0x06, 0x02, 0x54,
+ 0x28, 0x25, 0x01, 0x00, 0x11, 0x06, 0x0B, 0x24, 0x25, 0x05, 0x04, 0x24,
+ 0x01, 0x00, 0x00, 0xBA, 0x04, 0x6F, 0x02, 0x01, 0x25, 0x05, 0x02, 0x50,
+ 0x28, 0x41, 0x03, 0x01, 0x02, 0x02, 0x37, 0x02, 0x02, 0x40, 0x03, 0x02,
+ 0x25, 0x06, 0x03, 0xBA, 0x04, 0x68, 0x24, 0x02, 0x00, 0x02, 0x01, 0x0A,
+ 0x00, 0x01, 0xBA, 0x25, 0x01, 0x81, 0x00, 0x0D, 0x06, 0x01, 0x00, 0x01,
+ 0x81, 0x00, 0x0A, 0x25, 0x05, 0x02, 0x4E, 0x28, 0x03, 0x00, 0x01, 0x00,
+ 0x02, 0x00, 0x01, 0x00, 0x12, 0x06, 0x19, 0x02, 0x00, 0x41, 0x03, 0x00,
+ 0x25, 0x01, 0x83, 0xFF, 0xFF, 0x7F, 0x12, 0x06, 0x02, 0x4F, 0x28, 0x01,
+ 0x08, 0x0E, 0x3B, 0xBA, 0x34, 0x09, 0x04, 0x60, 0x00, 0x00, 0xAC, 0x95,
+ 0x00, 0x00, 0xAD, 0xC2, 0x00, 0x00, 0xB3, 0x76, 0xAD, 0x00, 0x01, 0xAD,
+ 0x25, 0x05, 0x02, 0x54, 0x28, 0xBA, 0x25, 0x01, 0x81, 0x00, 0x13, 0x06,
+ 0x02, 0x54, 0x28, 0x03, 0x00, 0x25, 0x06, 0x16, 0xBA, 0x02, 0x00, 0x25,
+ 0x01, 0x87, 0xFF, 0xFF, 0x7F, 0x13, 0x06, 0x02, 0x54, 0x28, 0x01, 0x08,
+ 0x0E, 0x09, 0x03, 0x00, 0x04, 0x67, 0x24, 0x02, 0x00, 0x00, 0x00, 0xAD,
+ 0x25, 0x01, 0x81, 0x7F, 0x12, 0x06, 0x08, 0xC2, 0x01, 0x00, 0x67, 0x37,
+ 0x01, 0x00, 0x00, 0x25, 0x67, 0x37, 0x67, 0x40, 0xA5, 0x01, 0x7F, 0x00,
+ 0x00, 0xB3, 0x01, 0x0C, 0x30, 0x11, 0x06, 0x05, 0x24, 0x75, 0xB6, 0x04,
+ 0x3E, 0x01, 0x12, 0x30, 0x11, 0x06, 0x05, 0x24, 0x75, 0xB7, 0x04, 0x33,
+ 0x01, 0x13, 0x30, 0x11, 0x06, 0x05, 0x24, 0x75, 0xB7, 0x04, 0x28, 0x01,
+ 0x14, 0x30, 0x11, 0x06, 0x05, 0x24, 0x75, 0xB7, 0x04, 0x1D, 0x01, 0x16,
+ 0x30, 0x11, 0x06, 0x05, 0x24, 0x75, 0xB7, 0x04, 0x12, 0x01, 0x1E, 0x30,
+ 0x11, 0x06, 0x05, 0x24, 0x75, 0xB5, 0x04, 0x07, 0x42, 0xAE, 0x01, 0x00,
+ 0x01, 0x00, 0x24, 0x00, 0x01, 0xBA, 0x03, 0x00, 0x02, 0x00, 0x01, 0x05,
+ 0x14, 0x01, 0x01, 0x15, 0x2D, 0x02, 0x00, 0x01, 0x06, 0x14, 0x25, 0x01,
+ 0x01, 0x15, 0x06, 0x02, 0x46, 0x28, 0x01, 0x04, 0x0E, 0x02, 0x00, 0x01,
+ 0x1F, 0x15, 0x25, 0x01, 0x1F, 0x11, 0x06, 0x02, 0x47, 0x28, 0x09, 0x00,
+ 0x00, 0x25, 0x05, 0x05, 0x01, 0x00, 0x01, 0x7F, 0x00, 0xB3, 0x00, 0x01,
+ 0xAD, 0x25, 0x05, 0x05, 0x67, 0x37, 0x01, 0x7F, 0x00, 0x01, 0x01, 0x03,
+ 0x00, 0x9F, 0x25, 0x01, 0x83, 0xFF, 0x7E, 0x11, 0x06, 0x16, 0x24, 0x25,
+ 0x06, 0x10, 0xA0, 0x25, 0x05, 0x05, 0x24, 0xC2, 0x01, 0x00, 0x00, 0x02,
+ 0x00, 0x84, 0x03, 0x00, 0x04, 0x6D, 0x04, 0x1B, 0x25, 0x05, 0x05, 0x24,
+ 0xC2, 0x01, 0x00, 0x00, 0x02, 0x00, 0x84, 0x03, 0x00, 0x25, 0x06, 0x0B,
+ 0x9F, 0x25, 0x05, 0x05, 0x24, 0xC2, 0x01, 0x00, 0x00, 0x04, 0x6D, 0x24,
+ 0x02, 0x00, 0x25, 0x05, 0x01, 0x00, 0x41, 0x67, 0x37, 0x01, 0x7F, 0x00,
+ 0x01, 0xAD, 0x01, 0x01, 0x03, 0x00, 0x25, 0x06, 0x10, 0xA1, 0x25, 0x05,
+ 0x05, 0x24, 0xC2, 0x01, 0x00, 0x00, 0x02, 0x00, 0x84, 0x03, 0x00, 0x04,
+ 0x6D, 0x24, 0x02, 0x00, 0x25, 0x05, 0x01, 0x00, 0x41, 0x67, 0x37, 0x01,
+ 0x7F, 0x00, 0x01, 0xAD, 0x01, 0x01, 0x03, 0x00, 0x25, 0x06, 0x10, 0xBA,
+ 0x25, 0x05, 0x05, 0x24, 0xC2, 0x01, 0x00, 0x00, 0x02, 0x00, 0x84, 0x03,
+ 0x00, 0x04, 0x6D, 0x24, 0x02, 0x00, 0x25, 0x05, 0x01, 0x00, 0x41, 0x67,
+ 0x37, 0x01, 0x7F, 0x00, 0x00, 0xBA, 0x01, 0x08, 0x0E, 0x3B, 0xBA, 0x34,
+ 0x09, 0x00, 0x00, 0xBA, 0x3B, 0xBA, 0x01, 0x08, 0x0E, 0x34, 0x09, 0x00,
+ 0x00, 0x25, 0x05, 0x02, 0x4F, 0x28, 0x41, 0xBB, 0x00, 0x00, 0x32, 0x25,
+ 0x01, 0x00, 0x13, 0x06, 0x01, 0x00, 0x24, 0x19, 0x04, 0x74, 0x00, 0x01,
+ 0x01, 0x00, 0x00, 0x01, 0x0B, 0x00, 0x00, 0x01, 0x15, 0x00, 0x00, 0x01,
+ 0x1F, 0x00, 0x00, 0x01, 0x29, 0x00, 0x00, 0x01, 0x33, 0x00, 0x00, 0xC3,
+ 0x24, 0x00, 0x00, 0x25, 0x06, 0x07, 0xC4, 0x25, 0x06, 0x01, 0x19, 0x04,
+ 0x76, 0x00, 0x00, 0x01, 0x00, 0x30, 0x31, 0x0B, 0x42, 0x00, 0x00, 0x01,
+ 0x81, 0x70, 0x00, 0x00, 0x01, 0x82, 0x0D, 0x00, 0x00, 0x01, 0x82, 0x22,
+ 0x00, 0x00, 0x01, 0x82, 0x05, 0x00, 0x00, 0x01, 0x03, 0x33, 0x01, 0x03,
+ 0x33, 0x00, 0x00, 0x25, 0x01, 0x83, 0xFB, 0x50, 0x01, 0x83, 0xFD, 0x5F,
+ 0x72, 0x06, 0x04, 0x24, 0x01, 0x00, 0x00, 0x25, 0x01, 0x83, 0xB0, 0x00,
+ 0x01, 0x83, 0xBF, 0x7F, 0x72, 0x06, 0x04, 0x24, 0x01, 0x00, 0x00, 0x01,
+ 0x83, 0xFF, 0x7F, 0x15, 0x01, 0x83, 0xFF, 0x7E, 0x0D, 0x00
+};
+
+static const uint16_t t0_caddr[] = {
+ 0,
+ 5,
+ 10,
+ 15,
+ 20,
+ 25,
+ 29,
+ 33,
+ 37,
+ 41,
+ 45,
+ 49,
+ 53,
+ 57,
+ 61,
+ 65,
+ 69,
+ 73,
+ 77,
+ 81,
+ 85,
+ 89,
+ 93,
+ 97,
+ 101,
+ 105,
+ 109,
+ 113,
+ 117,
+ 121,
+ 125,
+ 130,
+ 135,
+ 140,
+ 145,
+ 150,
+ 155,
+ 160,
+ 165,
+ 173,
+ 178,
+ 183,
+ 188,
+ 193,
+ 198,
+ 202,
+ 207,
+ 212,
+ 217,
+ 238,
+ 243,
+ 248,
+ 253,
+ 282,
+ 297,
+ 302,
+ 308,
+ 314,
+ 319,
+ 327,
+ 335,
+ 341,
+ 346,
+ 357,
+ 992,
+ 1007,
+ 1011,
+ 1016,
+ 1021,
+ 1026,
+ 1031,
+ 1036,
+ 1150,
+ 1155,
+ 1167,
+ 1172,
+ 1177,
+ 1182,
+ 1186,
+ 1191,
+ 1196,
+ 1201,
+ 1206,
+ 1216,
+ 1221,
+ 1226,
+ 1238,
+ 1253,
+ 1258,
+ 1272,
+ 1294,
+ 1305,
+ 1408,
+ 1455,
+ 1488,
+ 1579,
+ 1585,
+ 1648,
+ 1655,
+ 1683,
+ 1711,
+ 1816,
+ 1858,
+ 1871,
+ 1883,
+ 1897,
+ 1912,
+ 2132,
+ 2146,
+ 2163,
+ 2172,
+ 2239,
+ 2295,
+ 2299,
+ 2303,
+ 2308,
+ 2356,
+ 2382,
+ 2458,
+ 2502,
+ 2513,
+ 2598,
+ 2636,
+ 2674,
+ 2684,
+ 2694,
+ 2703,
+ 2716,
+ 2720,
+ 2724,
+ 2728,
+ 2732,
+ 2736,
+ 2740,
+ 2744,
+ 2756,
+ 2764,
+ 2769,
+ 2774,
+ 2779,
+ 2784,
+ 2792
+};
+
+#define T0_INTERPRETED 61
+
+#define T0_ENTER(ip, rp, slot) do { \
+ const unsigned char *t0_newip; \
+ uint32_t t0_lnum; \
+ t0_newip = &t0_codeblock[t0_caddr[(slot) - T0_INTERPRETED]]; \
+ t0_lnum = t0_parse7E_unsigned(&t0_newip); \
+ (rp) += t0_lnum; \
+ *((rp) ++) = (uint32_t)((ip) - &t0_codeblock[0]) + (t0_lnum << 16); \
+ (ip) = t0_newip; \
+ } while (0)
+
+#define T0_DEFENTRY(name, slot) \
+void \
+name(void *ctx) \
+{ \
+ t0_context *t0ctx = ctx; \
+ t0ctx->ip = &t0_codeblock[0]; \
+ T0_ENTER(t0ctx->ip, t0ctx->rp, slot); \
+}
+
+T0_DEFENTRY(br_x509_minimal_init_main, 147)
+
+#define T0_NEXT(t0ipp) (*(*(t0ipp)) ++)
+
+void
+br_x509_minimal_run(void *t0ctx)
+{
+ uint32_t *dp, *rp;
+ const unsigned char *ip;
+
+#define T0_LOCAL(x) (*(rp - 2 - (x)))
+#define T0_POP() (*-- dp)
+#define T0_POPi() (*(int32_t *)(-- dp))
+#define T0_PEEK(x) (*(dp - 1 - (x)))
+#define T0_PEEKi(x) (*(int32_t *)(dp - 1 - (x)))
+#define T0_PUSH(v) do { *dp = (v); dp ++; } while (0)
+#define T0_PUSHi(v) do { *(int32_t *)dp = (v); dp ++; } while (0)
+#define T0_RPOP() (*-- rp)
+#define T0_RPOPi() (*(int32_t *)(-- rp))
+#define T0_RPUSH(v) do { *rp = (v); rp ++; } while (0)
+#define T0_RPUSHi(v) do { *(int32_t *)rp = (v); rp ++; } while (0)
+#define T0_ROLL(x) do { \
+ size_t t0len = (size_t)(x); \
+ uint32_t t0tmp = *(dp - 1 - t0len); \
+ memmove(dp - t0len - 1, dp - t0len, t0len * sizeof *dp); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_SWAP() do { \
+ uint32_t t0tmp = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_ROT() do { \
+ uint32_t t0tmp = *(dp - 3); \
+ *(dp - 3) = *(dp - 2); \
+ *(dp - 2) = *(dp - 1); \
+ *(dp - 1) = t0tmp; \
+} while (0)
+#define T0_NROT() do { \
+ uint32_t t0tmp = *(dp - 1); \
+ *(dp - 1) = *(dp - 2); \
+ *(dp - 2) = *(dp - 3); \
+ *(dp - 3) = t0tmp; \
+} while (0)
+#define T0_PICK(x) do { \
+ uint32_t t0depth = (x); \
+ T0_PUSH(T0_PEEK(t0depth)); \
+} while (0)
+#define T0_CO() do { \
+ goto t0_exit; \
+} while (0)
+#define T0_RET() goto t0_next
+
+ dp = ((t0_context *)t0ctx)->dp;
+ rp = ((t0_context *)t0ctx)->rp;
+ ip = ((t0_context *)t0ctx)->ip;
+ goto t0_next;
+ for (;;) {
+ uint32_t t0x;
+
+ t0_next:
+ t0x = T0_NEXT(&ip);
+ if (t0x < T0_INTERPRETED) {
+ switch (t0x) {
+ int32_t t0off;
+
+ case 0: /* ret */
+ t0x = T0_RPOP();
+ rp -= (t0x >> 16);
+ t0x &= 0xFFFF;
+ if (t0x == 0) {
+ ip = NULL;
+ goto t0_exit;
+ }
+ ip = &t0_codeblock[t0x];
+ break;
+ case 1: /* literal constant */
+ T0_PUSHi(t0_parse7E_signed(&ip));
+ break;
+ case 2: /* read local */
+ T0_PUSH(T0_LOCAL(t0_parse7E_unsigned(&ip)));
+ break;
+ case 3: /* write local */
+ T0_LOCAL(t0_parse7E_unsigned(&ip)) = T0_POP();
+ break;
+ case 4: /* jump */
+ t0off = t0_parse7E_signed(&ip);
+ ip += t0off;
+ break;
+ case 5: /* jump if */
+ t0off = t0_parse7E_signed(&ip);
+ if (T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 6: /* jump if not */
+ t0off = t0_parse7E_signed(&ip);
+ if (!T0_POP()) {
+ ip += t0off;
+ }
+ break;
+ case 7: {
+ /* %25 */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSHi(a % b);
+
+ }
+ break;
+ case 8: {
+ /* * */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a * b);
+
+ }
+ break;
+ case 9: {
+ /* + */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a + b);
+
+ }
+ break;
+ case 10: {
+ /* - */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a - b);
+
+ }
+ break;
+ case 11: {
+ /* -rot */
+ T0_NROT();
+ }
+ break;
+ case 12: {
+ /* / */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSHi(a / b);
+
+ }
+ break;
+ case 13: {
+ /* < */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a < b));
+
+ }
+ break;
+ case 14: {
+ /* << */
+
+ int c = (int)T0_POPi();
+ uint32_t x = T0_POP();
+ T0_PUSH(x << c);
+
+ }
+ break;
+ case 15: {
+ /* <= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a <= b));
+
+ }
+ break;
+ case 16: {
+ /* <> */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a != b));
+
+ }
+ break;
+ case 17: {
+ /* = */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(-(uint32_t)(a == b));
+
+ }
+ break;
+ case 18: {
+ /* > */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a > b));
+
+ }
+ break;
+ case 19: {
+ /* >= */
+
+ int32_t b = T0_POPi();
+ int32_t a = T0_POPi();
+ T0_PUSH(-(uint32_t)(a >= b));
+
+ }
+ break;
+ case 20: {
+ /* >> */
+
+ int c = (int)T0_POPi();
+ int32_t x = T0_POPi();
+ T0_PUSHi(x >> c);
+
+ }
+ break;
+ case 21: {
+ /* and */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a & b);
+
+ }
+ break;
+ case 22: {
+ /* blobcopy */
+
+ size_t len = T0_POP();
+ unsigned char *src = (unsigned char *)CTX + T0_POP();
+ unsigned char *dst = (unsigned char *)CTX + T0_POP();
+ memcpy(dst, src, len);
+
+ }
+ break;
+ case 23: {
+ /* check-direct-trust */
+
+ size_t u;
+
+ for (u = 0; u < CTX->trust_anchors_num; u ++) {
+ const br_x509_trust_anchor *ta;
+ unsigned char hashed_DN[64];
+ int kt;
+
+ ta = &CTX->trust_anchors[u];
+ if (ta->flags & BR_X509_TA_CA) {
+ continue;
+ }
+ hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
+ if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) {
+ continue;
+ }
+ kt = CTX->pkey.key_type;
+ if ((ta->pkey.key_type & 0x0F) != kt) {
+ continue;
+ }
+ switch (kt) {
+
+ case BR_KEYTYPE_RSA:
+ if (!eqbigint(CTX->pkey.key.rsa.n,
+ CTX->pkey.key.rsa.nlen,
+ ta->pkey.key.rsa.n,
+ ta->pkey.key.rsa.nlen)
+ || !eqbigint(CTX->pkey.key.rsa.e,
+ CTX->pkey.key.rsa.elen,
+ ta->pkey.key.rsa.e,
+ ta->pkey.key.rsa.elen))
+ {
+ continue;
+ }
+ break;
+
+ case BR_KEYTYPE_EC:
+ if (CTX->pkey.key.ec.curve != ta->pkey.key.ec.curve
+ || CTX->pkey.key.ec.qlen != ta->pkey.key.ec.qlen
+ || memcmp(CTX->pkey.key.ec.q,
+ ta->pkey.key.ec.q,
+ ta->pkey.key.ec.qlen) != 0)
+ {
+ continue;
+ }
+ break;
+
+ default:
+ continue;
+ }
+
+ /*
+ * Direct trust match!
+ */
+ CTX->err = BR_ERR_X509_OK;
+ T0_CO();
+ }
+
+ }
+ break;
+ case 24: {
+ /* check-trust-anchor-CA */
+
+ size_t u;
+
+ for (u = 0; u < CTX->trust_anchors_num; u ++) {
+ const br_x509_trust_anchor *ta;
+ unsigned char hashed_DN[64];
+
+ ta = &CTX->trust_anchors[u];
+ if (!(ta->flags & BR_X509_TA_CA)) {
+ continue;
+ }
+ hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
+ if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) {
+ continue;
+ }
+ if (verify_signature(CTX, &ta->pkey) == 0) {
+ CTX->err = BR_ERR_X509_OK;
+ T0_CO();
+ }
+ }
+
+ }
+ break;
+ case 25: {
+ /* co */
+ T0_CO();
+ }
+ break;
+ case 26: {
+ /* compute-dn-hash */
+
+ CTX->dn_hash_impl->out(&CTX->dn_hash.vtable, CTX->current_dn_hash);
+ CTX->do_dn_hash = 0;
+
+ }
+ break;
+ case 27: {
+ /* compute-tbs-hash */
+
+ int id = T0_POPi();
+ size_t len;
+ len = br_multihash_out(&CTX->mhash, id, CTX->tbs_hash);
+ T0_PUSH(len);
+
+ }
+ break;
+ case 28: {
+ /* copy-ee-ec-pkey */
+
+ size_t qlen = T0_POP();
+ uint32_t curve = T0_POP();
+ memcpy(CTX->ee_pkey_data, CTX->pkey_data, qlen);
+ CTX->pkey.key_type = BR_KEYTYPE_EC;
+ CTX->pkey.key.ec.curve = curve;
+ CTX->pkey.key.ec.q = CTX->ee_pkey_data;
+ CTX->pkey.key.ec.qlen = qlen;
+
+ }
+ break;
+ case 29: {
+ /* copy-ee-rsa-pkey */
+
+ size_t elen = T0_POP();
+ size_t nlen = T0_POP();
+ memcpy(CTX->ee_pkey_data, CTX->pkey_data, nlen + elen);
+ CTX->pkey.key_type = BR_KEYTYPE_RSA;
+ CTX->pkey.key.rsa.n = CTX->ee_pkey_data;
+ CTX->pkey.key.rsa.nlen = nlen;
+ CTX->pkey.key.rsa.e = CTX->ee_pkey_data + nlen;
+ CTX->pkey.key.rsa.elen = elen;
+
+ }
+ break;
+ case 30: {
+ /* copy-name-SAN */
+
+ unsigned tag = T0_POP();
+ unsigned ok = T0_POP();
+ size_t u, len;
+
+ len = CTX->pad[0];
+ for (u = 0; u < CTX->num_name_elts; u ++) {
+ br_name_element *ne;
+
+ ne = &CTX->name_elts[u];
+ if (ne->status == 0 && ne->oid[0] == 0 && ne->oid[1] == tag) {
+ if (ok && ne->len > len) {
+ memcpy(ne->buf, CTX->pad + 1, len);
+ ne->buf[len] = 0;
+ ne->status = 1;
+ } else {
+ ne->status = -1;
+ }
+ break;
+ }
+ }
+
+ }
+ break;
+ case 31: {
+ /* copy-name-element */
+
+ size_t len;
+ int32_t off = T0_POPi();
+ int ok = T0_POPi();
+
+ if (off >= 0) {
+ br_name_element *ne = &CTX->name_elts[off];
+
+ if (ok) {
+ len = CTX->pad[0];
+ if (len < ne->len) {
+ memcpy(ne->buf, CTX->pad + 1, len);
+ ne->buf[len] = 0;
+ ne->status = 1;
+ } else {
+ ne->status = -1;
+ }
+ } else {
+ ne->status = -1;
+ }
+ }
+
+ }
+ break;
+ case 32: {
+ /* data-get8 */
+
+ size_t addr = T0_POP();
+ T0_PUSH(t0_datablock[addr]);
+
+ }
+ break;
+ case 33: {
+ /* dn-hash-length */
+
+ T0_PUSH(DNHASH_LEN);
+
+ }
+ break;
+ case 34: {
+ /* do-ecdsa-vrfy */
+
+ size_t qlen = T0_POP();
+ int curve = T0_POP();
+ br_x509_pkey pk;
+
+ pk.key_type = BR_KEYTYPE_EC;
+ pk.key.ec.curve = curve;
+ pk.key.ec.q = CTX->pkey_data;
+ pk.key.ec.qlen = qlen;
+ T0_PUSH(verify_signature(CTX, &pk));
+
+ }
+ break;
+ case 35: {
+ /* do-rsa-vrfy */
+
+ size_t elen = T0_POP();
+ size_t nlen = T0_POP();
+ br_x509_pkey pk;
+
+ pk.key_type = BR_KEYTYPE_RSA;
+ pk.key.rsa.n = CTX->pkey_data;
+ pk.key.rsa.nlen = nlen;
+ pk.key.rsa.e = CTX->pkey_data + nlen;
+ pk.key.rsa.elen = elen;
+ T0_PUSH(verify_signature(CTX, &pk));
+
+ }
+ break;
+ case 36: {
+ /* drop */
+ (void)T0_POP();
+ }
+ break;
+ case 37: {
+ /* dup */
+ T0_PUSH(T0_PEEK(0));
+ }
+ break;
+ case 38: {
+ /* eqOID */
+
+ const unsigned char *a2 = &t0_datablock[T0_POP()];
+ const unsigned char *a1 = &CTX->pad[0];
+ size_t len = a1[0];
+ int x;
+ if (len == a2[0]) {
+ x = -(memcmp(a1 + 1, a2 + 1, len) == 0);
+ } else {
+ x = 0;
+ }
+ T0_PUSH((uint32_t)x);
+
+ }
+ break;
+ case 39: {
+ /* eqblob */
+
+ size_t len = T0_POP();
+ const unsigned char *a2 = (const unsigned char *)CTX + T0_POP();
+ const unsigned char *a1 = (const unsigned char *)CTX + T0_POP();
+ T0_PUSHi(-(memcmp(a1, a2, len) == 0));
+
+ }
+ break;
+ case 40: {
+ /* fail */
+
+ CTX->err = T0_POPi();
+ T0_CO();
+
+ }
+ break;
+ case 41: {
+ /* get-system-date */
+
+ if (CTX->days == 0 && CTX->seconds == 0) {
+#if BR_USE_UNIX_TIME
+ time_t x = time(NULL);
+
+ T0_PUSH((uint32_t)(x / 86400) + 719528);
+ T0_PUSH((uint32_t)(x % 86400));
+#elif BR_USE_WIN32_TIME
+ FILETIME ft;
+ uint64_t x;
+
+ GetSystemTimeAsFileTime(&ft);
+ x = ((uint64_t)ft.dwHighDateTime << 32)
+ + (uint64_t)ft.dwLowDateTime;
+ x = (x / 10000000);
+ T0_PUSH((uint32_t)(x / 86400) + 584754);
+ T0_PUSH((uint32_t)(x % 86400));
+#else
+ CTX->err = BR_ERR_X509_TIME_UNKNOWN;
+ T0_CO();
+#endif
+ } else {
+ T0_PUSH(CTX->days);
+ T0_PUSH(CTX->seconds);
+ }
+
+ }
+ break;
+ case 42: {
+ /* get16 */
+
+ uint32_t addr = T0_POP();
+ T0_PUSH(*(uint16_t *)(void *)((unsigned char *)CTX + addr));
+
+ }
+ break;
+ case 43: {
+ /* get32 */
+
+ uint32_t addr = T0_POP();
+ T0_PUSH(*(uint32_t *)(void *)((unsigned char *)CTX + addr));
+
+ }
+ break;
+ case 44: {
+ /* match-server-name */
+
+ size_t n1, n2;
+
+ if (CTX->server_name == NULL) {
+ T0_PUSH(0);
+ T0_RET();
+ }
+ n1 = strlen(CTX->server_name);
+ n2 = CTX->pad[0];
+ if (n1 == n2 && eqnocase(&CTX->pad[1], CTX->server_name, n1)) {
+ T0_PUSHi(-1);
+ T0_RET();
+ }
+ if (n2 >= 2 && CTX->pad[1] == '*' && CTX->pad[2] == '.') {
+ size_t u;
+
+ u = 0;
+ while (u < n1 && CTX->server_name[u] != '.') {
+ u ++;
+ }
+ u ++;
+ n1 -= u;
+ if ((n2 - 2) == n1
+ && eqnocase(&CTX->pad[3], CTX->server_name + u, n1))
+ {
+ T0_PUSHi(-1);
+ T0_RET();
+ }
+ }
+ T0_PUSH(0);
+
+ }
+ break;
+ case 45: {
+ /* neg */
+
+ uint32_t a = T0_POP();
+ T0_PUSH(-a);
+
+ }
+ break;
+ case 46: {
+ /* offset-name-element */
+
+ unsigned san = T0_POP();
+ size_t u;
+
+ for (u = 0; u < CTX->num_name_elts; u ++) {
+ if (CTX->name_elts[u].status == 0) {
+ const unsigned char *oid;
+ size_t len, off;
+
+ oid = CTX->name_elts[u].oid;
+ if (san) {
+ if (oid[0] != 0 || oid[1] != 0) {
+ continue;
+ }
+ off = 2;
+ } else {
+ off = 0;
+ }
+ len = oid[off];
+ if (len != 0 && len == CTX->pad[0]
+ && memcmp(oid + off + 1,
+ CTX->pad + 1, len) == 0)
+ {
+ T0_PUSH(u);
+ T0_RET();
+ }
+ }
+ }
+ T0_PUSHi(-1);
+
+ }
+ break;
+ case 47: {
+ /* or */
+
+ uint32_t b = T0_POP();
+ uint32_t a = T0_POP();
+ T0_PUSH(a | b);
+
+ }
+ break;
+ case 48: {
+ /* over */
+ T0_PUSH(T0_PEEK(1));
+ }
+ break;
+ case 49: {
+ /* read-blob-inner */
+
+ uint32_t len = T0_POP();
+ uint32_t addr = T0_POP();
+ size_t clen = CTX->hlen;
+ if (clen > len) {
+ clen = (size_t)len;
+ }
+ if (addr != 0) {
+ memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
+ }
+ if (CTX->do_mhash) {
+ br_multihash_update(&CTX->mhash, CTX->hbuf, clen);
+ }
+ if (CTX->do_dn_hash) {
+ CTX->dn_hash_impl->update(
+ &CTX->dn_hash.vtable, CTX->hbuf, clen);
+ }
+ CTX->hbuf += clen;
+ CTX->hlen -= clen;
+ T0_PUSH(addr + clen);
+ T0_PUSH(len - clen);
+
+ }
+ break;
+ case 50: {
+ /* read8-low */
+
+ if (CTX->hlen == 0) {
+ T0_PUSHi(-1);
+ } else {
+ unsigned char x = *CTX->hbuf ++;
+ if (CTX->do_mhash) {
+ br_multihash_update(&CTX->mhash, &x, 1);
+ }
+ if (CTX->do_dn_hash) {
+ CTX->dn_hash_impl->update(&CTX->dn_hash.vtable, &x, 1);
+ }
+ CTX->hlen --;
+ T0_PUSH(x);
+ }
+
+ }
+ break;
+ case 51: {
+ /* roll */
+ T0_ROLL(T0_POP());
+ }
+ break;
+ case 52: {
+ /* rot */
+ T0_ROT();
+ }
+ break;
+ case 53: {
+ /* set16 */
+
+ uint32_t addr = T0_POP();
+ *(uint16_t *)(void *)((unsigned char *)CTX + addr) = T0_POP();
+
+ }
+ break;
+ case 54: {
+ /* set32 */
+
+ uint32_t addr = T0_POP();
+ *(uint32_t *)(void *)((unsigned char *)CTX + addr) = T0_POP();
+
+ }
+ break;
+ case 55: {
+ /* set8 */
+
+ uint32_t addr = T0_POP();
+ *((unsigned char *)CTX + addr) = (unsigned char)T0_POP();
+
+ }
+ break;
+ case 56: {
+ /* start-dn-hash */
+
+ CTX->dn_hash_impl->init(&CTX->dn_hash.vtable);
+ CTX->do_dn_hash = 1;
+
+ }
+ break;
+ case 57: {
+ /* start-tbs-hash */
+
+ br_multihash_init(&CTX->mhash);
+ CTX->do_mhash = 1;
+
+ }
+ break;
+ case 58: {
+ /* stop-tbs-hash */
+
+ CTX->do_mhash = 0;
+
+ }
+ break;
+ case 59: {
+ /* swap */
+ T0_SWAP();
+ }
+ break;
+ case 60: {
+ /* zero-server-name */
+
+ T0_PUSHi(-(CTX->server_name == NULL));
+
+ }
+ break;
+ }
+
+ } else {
+ T0_ENTER(ip, rp, t0x);
+ }
+ }
+t0_exit:
+ ((t0_context *)t0ctx)->dp = dp;
+ ((t0_context *)t0ctx)->rp = rp;
+ ((t0_context *)t0ctx)->ip = ip;
+}
+
+
+
+/*
+ * Verify the signature on the certificate with the provided public key.
+ * This function checks the public key type with regards to the expected
+ * type. Returned value is either 0 on success, or a non-zero error code.
+ */
+static int
+verify_signature(br_x509_minimal_context *ctx, const br_x509_pkey *pk)
+{
+ int kt;
+
+ kt = ctx->cert_signer_key_type;
+ if ((pk->key_type & 0x0F) != kt) {
+ return BR_ERR_X509_WRONG_KEY_TYPE;
+ }
+ switch (kt) {
+ unsigned char tmp[64];
+
+ case BR_KEYTYPE_RSA:
+ if (ctx->irsa == 0) {
+ return BR_ERR_X509_UNSUPPORTED;
+ }
+ if (!ctx->irsa(ctx->cert_sig, ctx->cert_sig_len,
+ &t0_datablock[ctx->cert_sig_hash_oid],
+ ctx->cert_sig_hash_len, &pk->key.rsa, tmp))
+ {
+ return BR_ERR_X509_BAD_SIGNATURE;
+ }
+ if (memcmp(ctx->tbs_hash, tmp, ctx->cert_sig_hash_len) != 0) {
+ return BR_ERR_X509_BAD_SIGNATURE;
+ }
+ return 0;
+
+ case BR_KEYTYPE_EC:
+ if (ctx->iecdsa == 0) {
+ return BR_ERR_X509_UNSUPPORTED;
+ }
+ if (!ctx->iecdsa(ctx->iec, ctx->tbs_hash,
+ ctx->cert_sig_hash_len, &pk->key.ec,
+ ctx->cert_sig, ctx->cert_sig_len))
+ {
+ return BR_ERR_X509_BAD_SIGNATURE;
+ }
+ return 0;
+
+ default:
+ return BR_ERR_X509_UNSUPPORTED;
+ }
+}
+
+
diff --git a/contrib/bearssl/src/x509/x509_minimal.t0 b/contrib/bearssl/src/x509/x509_minimal.t0
new file mode 100644
index 000000000000..1e60016dcd71
--- /dev/null
+++ b/contrib/bearssl/src/x509/x509_minimal.t0
@@ -0,0 +1,1508 @@
+\ Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+\
+\ Permission is hereby granted, free of charge, to any person obtaining
+\ a copy of this software and associated documentation files (the
+\ "Software"), to deal in the Software without restriction, including
+\ without limitation the rights to use, copy, modify, merge, publish,
+\ distribute, sublicense, and/or sell copies of the Software, and to
+\ permit persons to whom the Software is furnished to do so, subject to
+\ the following conditions:
+\
+\ The above copyright notice and this permission notice shall be
+\ included in all copies or substantial portions of the Software.
+\
+\ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+\ EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+\ MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+\ NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+\ BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+\ ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+\ CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+\ SOFTWARE.
+
+preamble {
+
+#include "inner.h"
+
+/*
+ * Implementation Notes
+ * --------------------
+ *
+ * The C code pushes the data by chunks; all decoding is done in the
+ * T0 code. The cert_length value is set to the certificate length when
+ * a new certificate is started; the T0 code picks it up as outer limit,
+ * and decoding functions use it to ensure that no attempt is made at
+ * reading past it. The T0 code also checks that once the certificate is
+ * decoded, there are no trailing bytes.
+ *
+ * The T0 code sets cert_length to 0 when the certificate is fully
+ * decoded.
+ *
+ * The C code must still perform two checks:
+ *
+ * -- If the certificate length is 0, then the T0 code will not be
+ * invoked at all. This invalid condition must thus be reported by the
+ * C code.
+ *
+ * -- When reaching the end of certificate, the C code must verify that
+ * the certificate length has been set to 0, thereby signaling that
+ * the T0 code properly decoded a certificate.
+ *
+ * Processing of a chain works in the following way:
+ *
+ * -- The error flag is set to a non-zero value when validation is
+ * finished. The value is either BR_ERR_X509_OK (validation is
+ * successful) or another non-zero error code. When a non-zero error
+ * code is obtained, the remaining bytes in the current certificate and
+ * the subsequent certificates (if any) are completely ignored.
+ *
+ * -- Each certificate is decoded in due course, with the following
+ * "interesting points":
+ *
+ * -- Start of the TBS: the multihash engine is reset and activated.
+ *
+ * -- Start of the issuer DN: the secondary hash engine is started,
+ * to process the encoded issuer DN.
+ *
+ * -- End of the issuer DN: the secondary hash engine is stopped. The
+ * resulting hash value is computed and then copied into the
+ * next_dn_hash[] buffer.
+ *
+ * -- Start of the subject DN: the secondary hash engine is started,
+ * to process the encoded subject DN.
+ *
+ * -- For the EE certificate only: the Common Name, if any, is matched
+ * against the expected server name.
+ *
+ * -- End of the subject DN: the secondary hash engine is stopped. The
+ * resulting hash value is computed into the pad. It is then processed:
+ *
+ * -- If this is the EE certificate, then the hash is ignored
+ * (except for direct trust processing, see later; the hash is
+ * simply left in current_dn_hash[]).
+ *
+ * -- Otherwise, the hashed subject DN is compared with the saved
+ * hash value (in saved_dn_hash[]). They must match.
+ *
+ * Either way, the next_dn_hash[] value is then copied into the
+ * saved_dn_hash[] value. Thus, at that point, saved_dn_hash[]
+ * contains the hash of the issuer DN for the current certificate,
+ * and current_dn_hash[] contains the hash of the subject DN for the
+ * current certificate.
+ *
+ * -- Public key: it is decoded into the cert_pkey[] buffer. Unknown
+ * key types are reported at that point.
+ *
+ * -- If this is the EE certificate, then the key type is compared
+ * with the expected key type (initialization parameter). The public
+ * key data is copied to ee_pkey_data[]. The key and hashed subject
+ * DN are also compared with the "direct trust" keys; if the key
+ * and DN are matched, then validation ends with a success.
+ *
+ * -- Otherwise, the saved signature (cert_sig[]) is verified
+ * against the saved TBS hash (tbs_hash[]) and that freshly
+ * decoded public key. Failure here ends validation with an error.
+ *
+ * -- Extensions: extension values are processed in due order.
+ *
+ * -- Basic Constraints: for all certificates except EE, must be
+ * present, indicate a CA, and have a path legnth compatible with
+ * the chain length so far.
+ *
+ * -- Key Usage: for the EE, if present, must allow signatures
+ * or encryption/key exchange, as required for the cipher suite.
+ * For non-EE, if present, must have the "certificate sign" bit.
+ *
+ * -- Subject Alt Name: for the EE, dNSName names are matched
+ * against the server name. Ignored for non-EE.
+ *
+ * -- Authority Key Identifier, Subject Key Identifier, Issuer
+ * Alt Name, Subject Directory Attributes, CRL Distribution Points
+ * Freshest CRL, Authority Info Access and Subject Info Access
+ * extensions are always ignored: they either contain only
+ * informative data, or they relate to revocation processing, which
+ * we explicitly do not support.
+ *
+ * -- All other extensions are ignored if non-critical. If a
+ * critical extension other than the ones above is encountered,
+ * then a failure is reported.
+ *
+ * -- End of the TBS: the multihash engine is stopped.
+ *
+ * -- Signature algorithm: the signature algorithm on the
+ * certificate is decoded. A failure is reported if that algorithm
+ * is unknown. The hashed TBS corresponding to the signature hash
+ * function is computed and stored in tbs_hash[] (if not supported,
+ * then a failure is reported). The hash OID and length are stored
+ * in cert_sig_hash_oid and cert_sig_hash_len.
+ *
+ * -- Signature value: the signature value is copied into the
+ * cert_sig[] array.
+ *
+ * -- Certificate end: the hashed issuer DN (saved_dn_hash[]) is
+ * looked up in the trust store (CA trust anchors only); for all
+ * that match, the signature (cert_sig[]) is verified against the
+ * anchor public key (hashed TBS is in tbs_hash[]). If one of these
+ * signatures is valid, then validation ends with a success.
+ *
+ * -- If the chain end is reached without obtaining a validation success,
+ * then validation is reported as failed.
+ */
+
+#if BR_USE_UNIX_TIME
+#include <time.h>
+#endif
+
+#if BR_USE_WIN32_TIME
+#include <windows.h>
+#endif
+
+/*
+ * The T0 compiler will produce these prototypes declarations in the
+ * header.
+ *
+void br_x509_minimal_init_main(void *ctx);
+void br_x509_minimal_run(void *ctx);
+ */
+
+/* see bearssl_x509.h */
+void
+br_x509_minimal_init(br_x509_minimal_context *ctx,
+ const br_hash_class *dn_hash_impl,
+ const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num)
+{
+ memset(ctx, 0, sizeof *ctx);
+ ctx->vtable = &br_x509_minimal_vtable;
+ ctx->dn_hash_impl = dn_hash_impl;
+ ctx->trust_anchors = trust_anchors;
+ ctx->trust_anchors_num = trust_anchors_num;
+}
+
+static void
+xm_start_chain(const br_x509_class **ctx, const char *server_name)
+{
+ br_x509_minimal_context *cc;
+ size_t u;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ for (u = 0; u < cc->num_name_elts; u ++) {
+ cc->name_elts[u].status = 0;
+ cc->name_elts[u].buf[0] = 0;
+ }
+ memset(&cc->pkey, 0, sizeof cc->pkey);
+ cc->num_certs = 0;
+ cc->err = 0;
+ cc->cpu.dp = cc->dp_stack;
+ cc->cpu.rp = cc->rp_stack;
+ br_x509_minimal_init_main(&cc->cpu);
+ if (server_name == NULL || *server_name == 0) {
+ cc->server_name = NULL;
+ } else {
+ cc->server_name = server_name;
+ }
+}
+
+static void
+xm_start_cert(const br_x509_class **ctx, uint32_t length)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err != 0) {
+ return;
+ }
+ if (length == 0) {
+ cc->err = BR_ERR_X509_TRUNCATED;
+ return;
+ }
+ cc->cert_length = length;
+}
+
+static void
+xm_append(const br_x509_class **ctx, const unsigned char *buf, size_t len)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err != 0) {
+ return;
+ }
+ cc->hbuf = buf;
+ cc->hlen = len;
+ br_x509_minimal_run(&cc->cpu);
+}
+
+static void
+xm_end_cert(const br_x509_class **ctx)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err == 0 && cc->cert_length != 0) {
+ cc->err = BR_ERR_X509_TRUNCATED;
+ }
+ cc->num_certs ++;
+}
+
+static unsigned
+xm_end_chain(const br_x509_class **ctx)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err == 0) {
+ if (cc->num_certs == 0) {
+ cc->err = BR_ERR_X509_EMPTY_CHAIN;
+ } else {
+ cc->err = BR_ERR_X509_NOT_TRUSTED;
+ }
+ } else if (cc->err == BR_ERR_X509_OK) {
+ return 0;
+ }
+ return (unsigned)cc->err;
+}
+
+static const br_x509_pkey *
+xm_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
+{
+ br_x509_minimal_context *cc;
+
+ cc = (br_x509_minimal_context *)(void *)ctx;
+ if (cc->err == BR_ERR_X509_OK
+ || cc->err == BR_ERR_X509_NOT_TRUSTED)
+ {
+ if (usages != NULL) {
+ *usages = cc->key_usages;
+ }
+ return &((br_x509_minimal_context *)(void *)ctx)->pkey;
+ } else {
+ return NULL;
+ }
+}
+
+/* see bearssl_x509.h */
+const br_x509_class br_x509_minimal_vtable = {
+ sizeof(br_x509_minimal_context),
+ xm_start_chain,
+ xm_start_cert,
+ xm_append,
+ xm_end_cert,
+ xm_end_chain,
+ xm_get_pkey
+};
+
+#define CTX ((br_x509_minimal_context *)(void *)((unsigned char *)t0ctx - offsetof(br_x509_minimal_context, cpu)))
+#define CONTEXT_NAME br_x509_minimal_context
+
+#define DNHASH_LEN ((CTX->dn_hash_impl->desc >> BR_HASHDESC_OUT_OFF) & BR_HASHDESC_OUT_MASK)
+
+/*
+ * Hash a DN (from a trust anchor) into the provided buffer. This uses the
+ * DN hash implementation and context structure from the X.509 engine
+ * context.
+ */
+static void
+hash_dn(br_x509_minimal_context *ctx, const void *dn, size_t len,
+ unsigned char *out)
+{
+ ctx->dn_hash_impl->init(&ctx->dn_hash.vtable);
+ ctx->dn_hash_impl->update(&ctx->dn_hash.vtable, dn, len);
+ ctx->dn_hash_impl->out(&ctx->dn_hash.vtable, out);
+}
+
+/*
+ * Compare two big integers for equality. The integers use unsigned big-endian
+ * encoding; extra leading bytes (of value 0) are allowed.
+ */
+static int
+eqbigint(const unsigned char *b1, size_t len1,
+ const unsigned char *b2, size_t len2)
+{
+ while (len1 > 0 && *b1 == 0) {
+ b1 ++;
+ len1 --;
+ }
+ while (len2 > 0 && *b2 == 0) {
+ b2 ++;
+ len2 --;
+ }
+ if (len1 != len2) {
+ return 0;
+ }
+ return memcmp(b1, b2, len1) == 0;
+}
+
+/*
+ * Compare two strings for equality, in a case-insensitive way. This
+ * function handles casing only for ASCII letters.
+ */
+static int
+eqnocase(const void *s1, const void *s2, size_t len)
+{
+ const unsigned char *buf1, *buf2;
+
+ buf1 = s1;
+ buf2 = s2;
+ while (len -- > 0) {
+ int x1, x2;
+
+ x1 = *buf1 ++;
+ x2 = *buf2 ++;
+ if (x1 >= 'A' && x1 <= 'Z') {
+ x1 += 'a' - 'A';
+ }
+ if (x2 >= 'A' && x2 <= 'Z') {
+ x2 += 'a' - 'A';
+ }
+ if (x1 != x2) {
+ return 0;
+ }
+ }
+ return 1;
+}
+
+static int verify_signature(br_x509_minimal_context *ctx,
+ const br_x509_pkey *pk);
+
+}
+
+postamble {
+
+/*
+ * Verify the signature on the certificate with the provided public key.
+ * This function checks the public key type with regards to the expected
+ * type. Returned value is either 0 on success, or a non-zero error code.
+ */
+static int
+verify_signature(br_x509_minimal_context *ctx, const br_x509_pkey *pk)
+{
+ int kt;
+
+ kt = ctx->cert_signer_key_type;
+ if ((pk->key_type & 0x0F) != kt) {
+ return BR_ERR_X509_WRONG_KEY_TYPE;
+ }
+ switch (kt) {
+ unsigned char tmp[64];
+
+ case BR_KEYTYPE_RSA:
+ if (ctx->irsa == 0) {
+ return BR_ERR_X509_UNSUPPORTED;
+ }
+ if (!ctx->irsa(ctx->cert_sig, ctx->cert_sig_len,
+ &t0_datablock[ctx->cert_sig_hash_oid],
+ ctx->cert_sig_hash_len, &pk->key.rsa, tmp))
+ {
+ return BR_ERR_X509_BAD_SIGNATURE;
+ }
+ if (memcmp(ctx->tbs_hash, tmp, ctx->cert_sig_hash_len) != 0) {
+ return BR_ERR_X509_BAD_SIGNATURE;
+ }
+ return 0;
+
+ case BR_KEYTYPE_EC:
+ if (ctx->iecdsa == 0) {
+ return BR_ERR_X509_UNSUPPORTED;
+ }
+ if (!ctx->iecdsa(ctx->iec, ctx->tbs_hash,
+ ctx->cert_sig_hash_len, &pk->key.ec,
+ ctx->cert_sig, ctx->cert_sig_len))
+ {
+ return BR_ERR_X509_BAD_SIGNATURE;
+ }
+ return 0;
+
+ default:
+ return BR_ERR_X509_UNSUPPORTED;
+ }
+}
+
+}
+
+cc: read8-low ( -- x ) {
+ if (CTX->hlen == 0) {
+ T0_PUSHi(-1);
+ } else {
+ unsigned char x = *CTX->hbuf ++;
+ if (CTX->do_mhash) {
+ br_multihash_update(&CTX->mhash, &x, 1);
+ }
+ if (CTX->do_dn_hash) {
+ CTX->dn_hash_impl->update(&CTX->dn_hash.vtable, &x, 1);
+ }
+ CTX->hlen --;
+ T0_PUSH(x);
+ }
+}
+
+addr: cert_length
+addr: num_certs
+
+cc: read-blob-inner ( addr len -- addr len ) {
+ uint32_t len = T0_POP();
+ uint32_t addr = T0_POP();
+ size_t clen = CTX->hlen;
+ if (clen > len) {
+ clen = (size_t)len;
+ }
+ if (addr != 0) {
+ memcpy((unsigned char *)CTX + addr, CTX->hbuf, clen);
+ }
+ if (CTX->do_mhash) {
+ br_multihash_update(&CTX->mhash, CTX->hbuf, clen);
+ }
+ if (CTX->do_dn_hash) {
+ CTX->dn_hash_impl->update(
+ &CTX->dn_hash.vtable, CTX->hbuf, clen);
+ }
+ CTX->hbuf += clen;
+ CTX->hlen -= clen;
+ T0_PUSH(addr + clen);
+ T0_PUSH(len - clen);
+}
+
+\ Compute the TBS hash, using the provided hash ID. The hash value is
+\ written in the tbs_hash[] array, and the hash length is returned. If
+\ the requested hash function is not supported, then 0 is returned.
+cc: compute-tbs-hash ( id -- hashlen ) {
+ int id = T0_POPi();
+ size_t len;
+ len = br_multihash_out(&CTX->mhash, id, CTX->tbs_hash);
+ T0_PUSH(len);
+}
+
+\ Push true (-1) if no server name is expected in the EE certificate.
+cc: zero-server-name ( -- bool ) {
+ T0_PUSHi(-(CTX->server_name == NULL));
+}
+
+addr: key_usages
+addr: cert_sig
+addr: cert_sig_len
+addr: cert_signer_key_type
+addr: cert_sig_hash_oid
+addr: cert_sig_hash_len
+addr: tbs_hash
+addr: min_rsa_size
+
+\ Start TBS hash computation. The hash functions are reinitialised.
+cc: start-tbs-hash ( -- ) {
+ br_multihash_init(&CTX->mhash);
+ CTX->do_mhash = 1;
+}
+
+\ Stop TBS hash computation.
+cc: stop-tbs-hash ( -- ) {
+ CTX->do_mhash = 0;
+}
+
+\ Start DN hash computation.
+cc: start-dn-hash ( -- ) {
+ CTX->dn_hash_impl->init(&CTX->dn_hash.vtable);
+ CTX->do_dn_hash = 1;
+}
+
+\ Terminate DN hash computation and write the DN hash into the
+\ current_dn_hash buffer.
+cc: compute-dn-hash ( -- ) {
+ CTX->dn_hash_impl->out(&CTX->dn_hash.vtable, CTX->current_dn_hash);
+ CTX->do_dn_hash = 0;
+}
+
+\ Get the length of hash values obtained with the DN hasher.
+cc: dn-hash-length ( -- len ) {
+ T0_PUSH(DNHASH_LEN);
+}
+
+\ Copy data between two areas in the context.
+cc: blobcopy ( addr-dst addr-src len -- ) {
+ size_t len = T0_POP();
+ unsigned char *src = (unsigned char *)CTX + T0_POP();
+ unsigned char *dst = (unsigned char *)CTX + T0_POP();
+ memcpy(dst, src, len);
+}
+
+addr: current_dn_hash
+addr: next_dn_hash
+addr: saved_dn_hash
+
+\ Read a DN, hashing it into current_dn_hash. The DN contents are not
+\ inspected (only the outer tag, for SEQUENCE, is checked).
+: read-DN ( lim -- lim )
+ start-dn-hash
+ read-sequence-open skip-close-elt
+ compute-dn-hash ;
+
+cc: offset-name-element ( san -- n ) {
+ unsigned san = T0_POP();
+ size_t u;
+
+ for (u = 0; u < CTX->num_name_elts; u ++) {
+ if (CTX->name_elts[u].status == 0) {
+ const unsigned char *oid;
+ size_t len, off;
+
+ oid = CTX->name_elts[u].oid;
+ if (san) {
+ if (oid[0] != 0 || oid[1] != 0) {
+ continue;
+ }
+ off = 2;
+ } else {
+ off = 0;
+ }
+ len = oid[off];
+ if (len != 0 && len == CTX->pad[0]
+ && memcmp(oid + off + 1,
+ CTX->pad + 1, len) == 0)
+ {
+ T0_PUSH(u);
+ T0_RET();
+ }
+ }
+ }
+ T0_PUSHi(-1);
+}
+
+cc: copy-name-element ( bool offbuf -- ) {
+ size_t len;
+ int32_t off = T0_POPi();
+ int ok = T0_POPi();
+
+ if (off >= 0) {
+ br_name_element *ne = &CTX->name_elts[off];
+
+ if (ok) {
+ len = CTX->pad[0];
+ if (len < ne->len) {
+ memcpy(ne->buf, CTX->pad + 1, len);
+ ne->buf[len] = 0;
+ ne->status = 1;
+ } else {
+ ne->status = -1;
+ }
+ } else {
+ ne->status = -1;
+ }
+ }
+}
+
+cc: copy-name-SAN ( bool tag -- ) {
+ unsigned tag = T0_POP();
+ unsigned ok = T0_POP();
+ size_t u, len;
+
+ len = CTX->pad[0];
+ for (u = 0; u < CTX->num_name_elts; u ++) {
+ br_name_element *ne;
+
+ ne = &CTX->name_elts[u];
+ if (ne->status == 0 && ne->oid[0] == 0 && ne->oid[1] == tag) {
+ if (ok && ne->len > len) {
+ memcpy(ne->buf, CTX->pad + 1, len);
+ ne->buf[len] = 0;
+ ne->status = 1;
+ } else {
+ ne->status = -1;
+ }
+ break;
+ }
+ }
+}
+
+\ Read a value, decoding string types. If the string type is recognised
+\ and the value could be converted to UTF-8 into the pad, then true (-1)
+\ is returned; in all other cases, false (0) is returned. Either way, the
+\ object is consumed.
+: read-string ( lim -- lim bool )
+ read-tag case
+ \ UTF8String
+ 12 of check-primitive read-value-UTF8 endof
+ \ NumericString
+ 18 of check-primitive read-value-latin1 endof
+ \ PrintableString
+ 19 of check-primitive read-value-latin1 endof
+ \ TeletexString
+ 20 of check-primitive read-value-latin1 endof
+ \ IA5String
+ 22 of check-primitive read-value-latin1 endof
+ \ BMPString
+ 30 of check-primitive read-value-UTF16 endof
+ 2drop read-length-skip 0 0
+ endcase ;
+
+\ Read a DN for the EE. The normalized DN hash is computed and stored in the
+\ current_dn_hash.
+\ Name elements are gathered. Also, the Common Name is matched against the
+\ intended server name.
+\ Returned value is true (-1) if the CN matches the intended server name,
+\ false (0) otherwise.
+: read-DN-EE ( lim -- lim bool )
+ \ Flag will be set to true if there is a CN and it matches the
+ \ intended server name.
+ 0 { eename-matches }
+
+ \ Activate DN hashing.
+ start-dn-hash
+
+ \ Parse the DN structure: it is a SEQUENCE of SET of
+ \ AttributeTypeAndValue. Each AttributeTypeAndValue is a
+ \ SEQUENCE { OBJECT IDENTIFIER, ANY }.
+ read-sequence-open
+ begin
+ dup while
+
+ read-tag 0x11 check-tag-constructed read-length-open-elt
+ dup ifnot ERR_X509_BAD_DN fail then
+ begin
+ dup while
+
+ read-sequence-open
+
+ \ Read the OID. If the OID could not be read (too
+ \ long) then the first pad byte will be 0.
+ read-OID drop
+
+ \ If it is the Common Name then we'll need to
+ \ match it against the intended server name (if
+ \ applicable).
+ id-at-commonName eqOID { isCN }
+
+ \ Get offset for reception buffer for that element
+ \ (or -1).
+ 0 offset-name-element { offbuf }
+
+ \ Try to read the value as a string.
+ read-string
+
+ \ If the value could be decoded as a string,
+ \ copy it and/or match it, as appropriate.
+ dup isCN and if
+ match-server-name if
+ -1 >eename-matches
+ then
+ then
+ offbuf copy-name-element
+
+ \ Close the SEQUENCE
+ close-elt
+
+ repeat
+ close-elt
+ repeat
+ close-elt
+
+ \ Compute DN hash and deactivate DN hashing.
+ compute-dn-hash
+
+ \ Return the CN match flag.
+ eename-matches ;
+
+\ Get the validation date and time from the context or system.
+cc: get-system-date ( -- days seconds ) {
+ if (CTX->days == 0 && CTX->seconds == 0) {
+#if BR_USE_UNIX_TIME
+ time_t x = time(NULL);
+
+ T0_PUSH((uint32_t)(x / 86400) + 719528);
+ T0_PUSH((uint32_t)(x % 86400));
+#elif BR_USE_WIN32_TIME
+ FILETIME ft;
+ uint64_t x;
+
+ GetSystemTimeAsFileTime(&ft);
+ x = ((uint64_t)ft.dwHighDateTime << 32)
+ + (uint64_t)ft.dwLowDateTime;
+ x = (x / 10000000);
+ T0_PUSH((uint32_t)(x / 86400) + 584754);
+ T0_PUSH((uint32_t)(x % 86400));
+#else
+ CTX->err = BR_ERR_X509_TIME_UNKNOWN;
+ T0_CO();
+#endif
+ } else {
+ T0_PUSH(CTX->days);
+ T0_PUSH(CTX->seconds);
+ }
+}
+
+\ Compare two dates (days+seconds) together.
+: before ( days1 seconds1 days2 seconds2 -- bool )
+ { d1 s1 d2 s2 }
+ d1 d2 = if s1 s2 < else d1 d2 < then ;
+
+: after ( days1 seconds1 days2 seconds2 -- bool )
+ swap2 before ;
+
+\ Swap the top two elements with the two elements immediately below.
+: swap2 ( a b c d -- c d a b )
+ 3 roll 3 roll ;
+
+\ Match the name in the pad with the expected server name. Returned value
+\ is true (-1) on match, false (0) otherwise. If there is no expected
+\ server name, then 0 is returned.
+\ Match conditions: either an exact match (case insensitive), or a
+\ wildcard match, if the found name starts with "*.". We only match a
+\ starting wildcard, and only against a complete DN name component.
+cc: match-server-name ( -- bool ) {
+ size_t n1, n2;
+
+ if (CTX->server_name == NULL) {
+ T0_PUSH(0);
+ T0_RET();
+ }
+ n1 = strlen(CTX->server_name);
+ n2 = CTX->pad[0];
+ if (n1 == n2 && eqnocase(&CTX->pad[1], CTX->server_name, n1)) {
+ T0_PUSHi(-1);
+ T0_RET();
+ }
+ if (n2 >= 2 && CTX->pad[1] == '*' && CTX->pad[2] == '.') {
+ size_t u;
+
+ u = 0;
+ while (u < n1 && CTX->server_name[u] != '.') {
+ u ++;
+ }
+ u ++;
+ n1 -= u;
+ if ((n2 - 2) == n1
+ && eqnocase(&CTX->pad[3], CTX->server_name + u, n1))
+ {
+ T0_PUSHi(-1);
+ T0_RET();
+ }
+ }
+ T0_PUSH(0);
+}
+
+\ Get the address and length for the pkey_data buffer.
+: addr-len-pkey_data ( -- addr len )
+ CX 0 8191 { offsetof(br_x509_minimal_context, pkey_data) }
+ CX 0 8191 { BR_X509_BUFSIZE_KEY } ;
+
+\ Copy the EE public key to the permanent buffer (RSA).
+cc: copy-ee-rsa-pkey ( nlen elen -- ) {
+ size_t elen = T0_POP();
+ size_t nlen = T0_POP();
+ memcpy(CTX->ee_pkey_data, CTX->pkey_data, nlen + elen);
+ CTX->pkey.key_type = BR_KEYTYPE_RSA;
+ CTX->pkey.key.rsa.n = CTX->ee_pkey_data;
+ CTX->pkey.key.rsa.nlen = nlen;
+ CTX->pkey.key.rsa.e = CTX->ee_pkey_data + nlen;
+ CTX->pkey.key.rsa.elen = elen;
+}
+
+\ Copy the EE public key to the permanent buffer (EC).
+cc: copy-ee-ec-pkey ( curve qlen -- ) {
+ size_t qlen = T0_POP();
+ uint32_t curve = T0_POP();
+ memcpy(CTX->ee_pkey_data, CTX->pkey_data, qlen);
+ CTX->pkey.key_type = BR_KEYTYPE_EC;
+ CTX->pkey.key.ec.curve = curve;
+ CTX->pkey.key.ec.q = CTX->ee_pkey_data;
+ CTX->pkey.key.ec.qlen = qlen;
+}
+
+\ Check whether the current certificate (EE) is directly trusted.
+cc: check-direct-trust ( -- ) {
+ size_t u;
+
+ for (u = 0; u < CTX->trust_anchors_num; u ++) {
+ const br_x509_trust_anchor *ta;
+ unsigned char hashed_DN[64];
+ int kt;
+
+ ta = &CTX->trust_anchors[u];
+ if (ta->flags & BR_X509_TA_CA) {
+ continue;
+ }
+ hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
+ if (memcmp(hashed_DN, CTX->current_dn_hash, DNHASH_LEN)) {
+ continue;
+ }
+ kt = CTX->pkey.key_type;
+ if ((ta->pkey.key_type & 0x0F) != kt) {
+ continue;
+ }
+ switch (kt) {
+
+ case BR_KEYTYPE_RSA:
+ if (!eqbigint(CTX->pkey.key.rsa.n,
+ CTX->pkey.key.rsa.nlen,
+ ta->pkey.key.rsa.n,
+ ta->pkey.key.rsa.nlen)
+ || !eqbigint(CTX->pkey.key.rsa.e,
+ CTX->pkey.key.rsa.elen,
+ ta->pkey.key.rsa.e,
+ ta->pkey.key.rsa.elen))
+ {
+ continue;
+ }
+ break;
+
+ case BR_KEYTYPE_EC:
+ if (CTX->pkey.key.ec.curve != ta->pkey.key.ec.curve
+ || CTX->pkey.key.ec.qlen != ta->pkey.key.ec.qlen
+ || memcmp(CTX->pkey.key.ec.q,
+ ta->pkey.key.ec.q,
+ ta->pkey.key.ec.qlen) != 0)
+ {
+ continue;
+ }
+ break;
+
+ default:
+ continue;
+ }
+
+ /*
+ * Direct trust match!
+ */
+ CTX->err = BR_ERR_X509_OK;
+ T0_CO();
+ }
+}
+
+\ Check the signature on the certificate with regards to all trusted CA.
+\ We use the issuer hash (in saved_dn_hash[]) as CA identifier.
+cc: check-trust-anchor-CA ( -- ) {
+ size_t u;
+
+ for (u = 0; u < CTX->trust_anchors_num; u ++) {
+ const br_x509_trust_anchor *ta;
+ unsigned char hashed_DN[64];
+
+ ta = &CTX->trust_anchors[u];
+ if (!(ta->flags & BR_X509_TA_CA)) {
+ continue;
+ }
+ hash_dn(CTX, ta->dn.data, ta->dn.len, hashed_DN);
+ if (memcmp(hashed_DN, CTX->saved_dn_hash, DNHASH_LEN)) {
+ continue;
+ }
+ if (verify_signature(CTX, &ta->pkey) == 0) {
+ CTX->err = BR_ERR_X509_OK;
+ T0_CO();
+ }
+ }
+}
+
+\ Verify RSA signature. This uses the public key that was just decoded
+\ into CTX->pkey_data; the modulus and exponent length are provided as
+\ parameters. The resulting hash value is compared with the one in
+\ tbs_hash. Returned value is 0 on success, or a non-zero error code.
+cc: do-rsa-vrfy ( nlen elen -- err ) {
+ size_t elen = T0_POP();
+ size_t nlen = T0_POP();
+ br_x509_pkey pk;
+
+ pk.key_type = BR_KEYTYPE_RSA;
+ pk.key.rsa.n = CTX->pkey_data;
+ pk.key.rsa.nlen = nlen;
+ pk.key.rsa.e = CTX->pkey_data + nlen;
+ pk.key.rsa.elen = elen;
+ T0_PUSH(verify_signature(CTX, &pk));
+}
+
+\ Verify ECDSA signature. This uses the public key that was just decoded
+\ into CTX->pkey_dayta; the curve ID and public point length are provided
+\ as parameters. The hash value in tbs_hash is used. Returned value is 0
+\ on success, or non-zero error code.
+cc: do-ecdsa-vrfy ( curve qlen -- err ) {
+ size_t qlen = T0_POP();
+ int curve = T0_POP();
+ br_x509_pkey pk;
+
+ pk.key_type = BR_KEYTYPE_EC;
+ pk.key.ec.curve = curve;
+ pk.key.ec.q = CTX->pkey_data;
+ pk.key.ec.qlen = qlen;
+ T0_PUSH(verify_signature(CTX, &pk));
+}
+
+cc: print-bytes ( addr len -- ) {
+ extern int printf(const char *fmt, ...);
+ size_t len = T0_POP();
+ unsigned char *buf = (unsigned char *)CTX + T0_POP();
+ size_t u;
+
+ for (u = 0; u < len; u ++) {
+ printf("%02X", buf[u]);
+ }
+}
+
+cc: printOID ( -- ) {
+ extern int printf(const char *fmt, ...);
+ size_t u, len;
+
+ len = CTX->pad[0];
+ if (len == 0) {
+ printf("*");
+ T0_RET();
+ }
+ printf("%u.%u", CTX->pad[1] / 40, CTX->pad[1] % 40);
+ u = 2;
+ while (u <= len) {
+ unsigned long ul;
+
+ ul = 0;
+ for (;;) {
+ int x;
+
+ if (u > len) {
+ printf("BAD");
+ T0_RET();
+ }
+ x = CTX->pad[u ++];
+ ul = (ul << 7) + (x & 0x7F);
+ if (!(x & 0x80)) {
+ break;
+ }
+ }
+ printf(".%lu", ul);
+ }
+}
+
+\ Extensions with specific processing.
+OID: basicConstraints 2.5.29.19
+OID: keyUsage 2.5.29.15
+OID: subjectAltName 2.5.29.17
+OID: certificatePolicies 2.5.29.32
+
+\ Policy qualifier "pointer to CPS"
+OID: id-qt-cps 1.3.6.1.5.5.7.2.1
+
+\ Extensions which are ignored when encountered, even if critical.
+OID: authorityKeyIdentifier 2.5.29.35
+OID: subjectKeyIdentifier 2.5.29.14
+OID: issuerAltName 2.5.29.18
+OID: subjectDirectoryAttributes 2.5.29.9
+OID: crlDistributionPoints 2.5.29.31
+OID: freshestCRL 2.5.29.46
+OID: authorityInfoAccess 1.3.6.1.5.5.7.1.1
+OID: subjectInfoAccess 1.3.6.1.5.5.7.1.11
+
+\ Process a Basic Constraints extension. This should be called only if
+\ the certificate is not the EE. We check that the extension contains
+\ the "CA" flag, and that the path length, if specified, is compatible
+\ with the current chain length.
+: process-basicConstraints ( lim -- lim )
+ read-sequence-open
+ read-tag-or-end
+ dup 0x01 = if
+ read-boolean ifnot ERR_X509_NOT_CA fail then
+ read-tag-or-end
+ else
+ ERR_X509_NOT_CA fail
+ then
+ dup 0x02 = if
+ drop check-primitive read-small-int-value
+ addr-num_certs get32 1- < if ERR_X509_NOT_CA fail then
+ read-tag-or-end
+ then
+ -1 <> if ERR_X509_UNEXPECTED fail then
+ drop
+ close-elt
+ ;
+
+\ Process a Key Usage extension.
+\ For the EE certificate:
+\ -- if the key usage contains keyEncipherment (2), dataEncipherment (3)
+\ or keyAgreement (4), then the "key exchange" usage is allowed;
+\ -- if the key usage contains digitalSignature (0) or nonRepudiation (1),
+\ then the "signature" usage is allowed.
+\ For CA certificates, the extension must contain keyCertSign (5).
+: process-keyUsage ( lim ee -- lim )
+ { ee }
+
+ \ Read tag for the BIT STRING and open it.
+ read-tag 0x03 check-tag-primitive
+ read-length-open-elt
+ \ First byte indicates number of ignored bits in the last byte. It
+ \ must be between 0 and 7.
+ read8 { ign }
+ ign 7 > if ERR_X509_UNEXPECTED fail then
+ \ Depending on length, we have either 0, 1 or more bytes to read.
+ dup case
+ 0 of ERR_X509_FORBIDDEN_KEY_USAGE fail endof
+ 1 of read8 ign >> ign << endof
+ drop read8 0
+ endcase
+
+ \ Check bits.
+ ee if
+ \ EE: get usages.
+ 0
+ over 0x38 and if 0x10 or then
+ swap 0xC0 and if 0x20 or then
+ addr-key_usages set8
+ else
+ \ Not EE: keyCertSign must be set.
+ 0x04 and ifnot ERR_X509_FORBIDDEN_KEY_USAGE fail then
+ then
+
+ \ We don't care about subsequent bytes.
+ skip-close-elt ;
+
+\ Process a Certificate Policies extension.
+\
+\ Since we don't actually support full policies processing, this function
+\ only checks that the extension contents can be safely ignored. Indeed,
+\ we don't validate against a specific set of policies (in RFC 5280
+\ terminology, user-initial-policy-set only contains the special value
+\ any-policy). Moreover, we don't support policy constraints (if a
+\ critical Policy Constraints extension is encountered, the validation
+\ will fail). Therefore, we can safely ignore the contents of this
+\ extension, except if it is critical AND one of the policy OID has a
+\ qualifier which is distinct from id-qt-cps (because id-qt-cps is
+\ specially designated by RFC 5280 has having no mandated action).
+\
+\ This function is called only if the extension is critical.
+: process-certPolicies ( lim -- lim )
+ \ Extension value is a SEQUENCE OF PolicyInformation.
+ read-sequence-open
+ begin dup while
+ \ PolicyInformation ::= SEQUENCE {
+ \ policyIdentifier OBJECT IDENTIFIER,
+ \ policyQualifiers SEQUENCE OF PolicyQualifierInfo OPTIONAL
+ \ }
+ read-sequence-open
+ read-OID drop
+ dup if
+ read-sequence-open
+ begin dup while
+ \ PolicyQualifierInfo ::= SEQUENCE {
+ \ policyQualifierId OBJECT IDENTIFIER,
+ \ qualifier ANY
+ \ }
+ read-sequence-open
+ read-OID drop id-qt-cps eqOID ifnot
+ ERR_X509_CRITICAL_EXTENSION fail
+ then
+ skip-close-elt
+ repeat
+ close-elt
+ then
+ close-elt
+ repeat
+ close-elt ;
+
+\ Process a Subject Alt Name extension. Returned value is a boolean set
+\ to true if the expected server name was matched against a dNSName in
+\ the extension.
+: process-SAN ( lim -- lim bool )
+ 0 { m }
+ read-sequence-open
+ begin dup while
+ \ Read the tag. If the tag is context-0, then parse an
+ \ 'otherName'. If the tag is context-2, then parse a
+ \ dNSName. If the tag is context-1 or context-6,
+ \ parse
+ read-tag case
+ \ OtherName
+ 0x20 of
+ \ OtherName ::= SEQUENCE {
+ \ type-id OBJECT IDENTIFIER,
+ \ value [0] EXPLICIT ANY
+ \ }
+ check-constructed read-length-open-elt
+ read-OID drop
+ -1 offset-name-element { offbuf }
+ read-tag 0x20 check-tag-constructed
+ read-length-open-elt
+ read-string offbuf copy-name-element
+ close-elt
+ close-elt
+ endof
+ \ rfc822Name (IA5String)
+ 0x21 of
+ check-primitive
+ read-value-UTF8 1 copy-name-SAN
+ endof
+ \ dNSName (IA5String)
+ 0x22 of
+ check-primitive
+ read-value-UTF8
+ dup if match-server-name m or >m then
+ 2 copy-name-SAN
+ endof
+ \ uniformResourceIdentifier (IA5String)
+ 0x26 of
+ check-primitive
+ read-value-UTF8 6 copy-name-SAN
+ endof
+ 2drop read-length-skip 0
+ endcase
+
+ \ We check only names of type dNSName; they use IA5String,
+ \ which is basically ASCII.
+ \ read-tag 0x22 = if
+ \ check-primitive
+ \ read-small-value drop
+ \ match-server-name m or >m
+ \ else
+ \ drop read-length-skip
+ \ then
+ repeat
+ close-elt
+ m ;
+
+\ Decode a certificate. The "ee" boolean must be true for the EE.
+: decode-certificate ( ee -- )
+ { ee }
+
+ \ Obtain the total certificate length.
+ addr-cert_length get32
+
+ \ Open the outer SEQUENCE.
+ read-sequence-open
+
+ \ TBS
+ \ Activate hashing.
+ start-tbs-hash
+ read-sequence-open
+
+ \ First element may be an explicit version. We accept only
+ \ versions 0 to 2 (certificates v1 to v3).
+ read-tag dup 0x20 = if
+ drop check-constructed read-length-open-elt
+ read-tag
+ 0x02 check-tag-primitive
+ read-small-int-value
+ 2 > if ERR_X509_UNSUPPORTED fail then
+ close-elt
+ read-tag
+ then
+
+ \ Serial number. We just check that the tag is correct.
+ 0x02 check-tag-primitive
+ read-length-skip
+
+ \ Signature algorithm. This structure is redundant with the one
+ \ on the outside; we just skip it.
+ read-sequence-open skip-close-elt
+
+ \ Issuer name: hashed, then copied into next_dn_hash[].
+ read-DN
+ addr-next_dn_hash addr-current_dn_hash dn-hash-length blobcopy
+
+ \ Validity dates.
+ read-sequence-open
+ read-date get-system-date after if ERR_X509_EXPIRED fail then
+ read-date get-system-date before if ERR_X509_EXPIRED fail then
+ close-elt
+
+ \ Subject name.
+ ee if
+ \ For the EE, we must check whether the Common Name, if
+ \ any, matches the expected server name.
+ read-DN-EE { eename }
+ else
+ \ For a non-EE certificate, the hashed subject DN must match
+ \ the saved hashed issuer DN from the previous certificate.
+ read-DN
+ addr-current_dn_hash addr-saved_dn_hash dn-hash-length eqblob
+ ifnot ERR_X509_DN_MISMATCH fail then
+ then
+ \ Move the hashed issuer DN for this certificate into the
+ \ saved_dn_hash[] array.
+ addr-saved_dn_hash addr-next_dn_hash dn-hash-length blobcopy
+
+ \ Public Key.
+ read-sequence-open
+ \ Algorithm Identifier. Right now we are only interested in the
+ \ OID, since we only support RSA keys.
+ read-sequence-open
+ read-OID ifnot ERR_X509_UNSUPPORTED fail then
+ { ; pkey-type }
+ choice
+ \ RSA public key.
+ rsaEncryption eqOID uf
+ skip-close-elt
+ \ Public key itself: the BIT STRING contains bytes
+ \ (no partial byte) and these bytes encode the
+ \ actual value.
+ read-bits-open
+ \ RSA public key is a SEQUENCE of two
+ \ INTEGER. We get both INTEGER values into
+ \ the pkey_data[] buffer, if they fit.
+ read-sequence-open
+ addr-len-pkey_data
+ read-integer { nlen }
+ addr-len-pkey_data swap nlen + swap nlen -
+ read-integer { elen }
+ close-elt
+
+ \ Check that the public key fits our minimal
+ \ size requirements. Note that the integer
+ \ decoder already skipped the leading bytes
+ \ of value 0, so we are working on the true
+ \ modulus length here.
+ addr-min_rsa_size get16 128 + nlen > if
+ ERR_X509_WEAK_PUBLIC_KEY fail
+ then
+ close-elt
+ KEYTYPE_RSA >pkey-type
+ enduf
+
+ \ EC public key.
+ id-ecPublicKey eqOID uf
+ \ We support only named curves, for which the
+ \ "parameters" field in the AlgorithmIdentifier
+ \ field should be an OID.
+ read-OID ifnot ERR_X509_UNSUPPORTED fail then
+ choice
+ ansix9p256r1 eqOID uf 23 enduf
+ ansix9p384r1 eqOID uf 24 enduf
+ ansix9p521r1 eqOID uf 25 enduf
+ ERR_X509_UNSUPPORTED fail
+ endchoice
+ { curve }
+ close-elt
+ read-bits-open
+ dup { qlen }
+ dup addr-len-pkey_data rot < if
+ ERR_X509_LIMIT_EXCEEDED fail
+ then
+ read-blob
+ KEYTYPE_EC >pkey-type
+ enduf
+
+ \ Not a recognised public key type.
+ ERR_X509_UNSUPPORTED fail
+ endchoice
+ close-elt
+
+ \ Process public key.
+ ee if
+ \ For the EE certificate, copy the key data to the
+ \ relevant buffer.
+ pkey-type case
+ KEYTYPE_RSA of nlen elen copy-ee-rsa-pkey endof
+ KEYTYPE_EC of curve qlen copy-ee-ec-pkey endof
+ ERR_X509_UNSUPPORTED fail
+ endcase
+ else
+ \ Verify signature on previous certificate. We invoke
+ \ the RSA implementation.
+ pkey-type case
+ KEYTYPE_RSA of nlen elen do-rsa-vrfy endof
+ KEYTYPE_EC of curve qlen do-ecdsa-vrfy endof
+ ERR_X509_UNSUPPORTED fail
+ endcase
+ dup if fail then
+ drop
+ then
+
+ \ This flag will be set to true if the Basic Constraints extension
+ \ is encountered.
+ 0 { seenBC }
+
+ \ Skip issuerUniqueID and subjectUniqueID, and process extensions
+ \ if present. Extensions are an explicit context tag of value 3
+ \ around a SEQUENCE OF extensions. Each extension is a SEQUENCE
+ \ with an OID, an optional boolean, and a value; the value is
+ \ an OCTET STRING.
+ read-tag-or-end
+ 0x21 iftag-skip
+ 0x22 iftag-skip
+ dup 0x23 = if
+ drop
+ check-constructed read-length-open-elt
+ read-sequence-open
+ begin dup while
+ 0 { critical }
+ read-sequence-open
+ read-OID drop
+ read-tag dup 0x01 = if
+ read-boolean >critical
+ read-tag
+ then
+ 0x04 check-tag-primitive read-length-open-elt
+ choice
+ \ Extensions with specific processing.
+ basicConstraints eqOID uf
+ ee if
+ skip-remaining
+ else
+ process-basicConstraints
+ -1 >seenBC
+ then
+ enduf
+ keyUsage eqOID uf
+ ee process-keyUsage
+ enduf
+ subjectAltName eqOID uf
+ ee if
+ 0 >eename
+ process-SAN >eename
+ else
+ skip-remaining
+ then
+ enduf
+
+ \ We don't implement full processing of
+ \ policies. The call below mostly checks
+ \ that the contents of the Certificate
+ \ Policies extension can be safely ignored.
+ certificatePolicies eqOID uf
+ critical if
+ process-certPolicies
+ else
+ skip-remaining
+ then
+ enduf
+
+ \ Extensions which are always ignored,
+ \ even if critical.
+ authorityKeyIdentifier eqOID uf
+ skip-remaining
+ enduf
+ subjectKeyIdentifier eqOID uf
+ skip-remaining
+ enduf
+ issuerAltName eqOID uf
+ skip-remaining
+ enduf
+ subjectDirectoryAttributes eqOID uf
+ skip-remaining
+ enduf
+ crlDistributionPoints eqOID uf
+ skip-remaining
+ enduf
+ freshestCRL eqOID uf
+ skip-remaining
+ enduf
+ authorityInfoAccess eqOID uf
+ skip-remaining
+ enduf
+ subjectInfoAccess eqOID uf
+ skip-remaining
+ enduf
+
+ \ Unrecognized extensions trigger a failure
+ \ if critical; otherwise, they are just
+ \ ignored.
+ critical if
+ ERR_X509_CRITICAL_EXTENSION fail
+ then
+ skip-remaining
+ endchoice
+ close-elt
+ close-elt
+ repeat
+ close-elt
+ close-elt
+ else
+ -1 = ifnot ERR_X509_UNEXPECTED fail then
+ drop
+ then
+
+ close-elt
+ \ Terminate hashing.
+ stop-tbs-hash
+
+ \ For the EE certificate, verify that the intended server name
+ \ was matched.
+ ee if
+ eename zero-server-name or ifnot
+ ERR_X509_BAD_SERVER_NAME fail
+ then
+ then
+
+ \ If this is the EE certificate, then direct trust may apply.
+ \ Note: we do this at this point, not immediately after decoding
+ \ the public key, because even in case of direct trust we still
+ \ want to check the server name with regards to the SAN extension.
+ \ However, we want to check direct trust before trying to decode
+ \ the signature algorithm, because it should work even if that
+ \ algorithm is not supported.
+ ee if check-direct-trust then
+
+ \ Non-EE certificates MUST have a Basic Constraints extension
+ \ (that marks them as being CA).
+ ee seenBC or ifnot ERR_X509_NOT_CA fail then
+
+ \ signature algorithm
+ read-tag check-sequence read-length-open-elt
+ \ Read and understand the OID. Right now, we support only
+ \ RSA with PKCS#1 v1.5 padding, and hash functions SHA-1,
+ \ SHA-224, SHA-256, SHA-384 and SHA-512. We purposely do NOT
+ \ support MD5 here.
+ \ TODO: add support for RSA/PSS
+ read-OID if
+ \ Based on the signature OID, we get:
+ \ -- the signing key type
+ \ -- the hash function numeric identifier
+ \ -- the hash function OID
+ choice
+ sha1WithRSAEncryption eqOID
+ uf 2 KEYTYPE_RSA id-sha1 enduf
+ sha224WithRSAEncryption eqOID
+ uf 3 KEYTYPE_RSA id-sha224 enduf
+ sha256WithRSAEncryption eqOID
+ uf 4 KEYTYPE_RSA id-sha256 enduf
+ sha384WithRSAEncryption eqOID
+ uf 5 KEYTYPE_RSA id-sha384 enduf
+ sha512WithRSAEncryption eqOID
+ uf 6 KEYTYPE_RSA id-sha512 enduf
+
+ ecdsa-with-SHA1 eqOID
+ uf 2 KEYTYPE_EC id-sha1 enduf
+ ecdsa-with-SHA224 eqOID
+ uf 3 KEYTYPE_EC id-sha224 enduf
+ ecdsa-with-SHA256 eqOID
+ uf 4 KEYTYPE_EC id-sha256 enduf
+ ecdsa-with-SHA384 eqOID
+ uf 5 KEYTYPE_EC id-sha384 enduf
+ ecdsa-with-SHA512 eqOID
+ uf 6 KEYTYPE_EC id-sha512 enduf
+ ERR_X509_UNSUPPORTED fail
+ endchoice
+ addr-cert_sig_hash_oid set16
+ addr-cert_signer_key_type set8
+
+ \ Compute the TBS hash into tbs_hash.
+ compute-tbs-hash
+ dup ifnot ERR_X509_UNSUPPORTED fail then
+ addr-cert_sig_hash_len set8
+ else
+ ERR_X509_UNSUPPORTED fail
+ then
+ \ We ignore the parameters, whether they are present or not,
+ \ because we got all the information from the OID.
+ skip-close-elt
+
+ \ signature value
+ read-bits-open
+ dup CX 0 8191 { BR_X509_BUFSIZE_SIG } > if
+ ERR_X509_LIMIT_EXCEEDED fail
+ then
+ dup addr-cert_sig_len set16
+ addr-cert_sig read-blob
+
+ \ Close the outer SEQUENCE.
+ close-elt
+
+ \ Close the advertised total certificate length. This checks that
+ \ there is no trailing garbage after the certificate.
+ close-elt
+
+ \ Flag the certificate as fully processed.
+ 0 addr-cert_length set32
+
+ \ Check whether the issuer for the current certificate is known
+ \ as a trusted CA; in which case, verify the signature.
+ check-trust-anchor-CA ;
+
+: main
+ \ Unless restricted by a Key Usage extension, all usages are
+ \ deemed allowed.
+ 0x30 addr-key_usages set8
+ -1 decode-certificate
+ co
+ begin
+ 0 decode-certificate co
+ again
+ ;
diff --git a/contrib/bearssl/src/x509/x509_minimal_full.c b/contrib/bearssl/src/x509/x509_minimal_full.c
new file mode 100644
index 000000000000..2b544267faa1
--- /dev/null
+++ b/contrib/bearssl/src/x509/x509_minimal_full.c
@@ -0,0 +1,59 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "inner.h"
+
+/* see bearssl_x509.h */
+void
+br_x509_minimal_init_full(br_x509_minimal_context *xc,
+ const br_x509_trust_anchor *trust_anchors, size_t trust_anchors_num)
+{
+ /*
+ * All hash functions are activated.
+ * Note: the X.509 validation engine will nonetheless refuse to
+ * validate signatures that use MD5 as hash function.
+ */
+ static const br_hash_class *hashes[] = {
+ &br_md5_vtable,
+ &br_sha1_vtable,
+ &br_sha224_vtable,
+ &br_sha256_vtable,
+ &br_sha384_vtable,
+ &br_sha512_vtable
+ };
+
+ int id;
+
+ br_x509_minimal_init(xc, &br_sha256_vtable,
+ trust_anchors, trust_anchors_num);
+ br_x509_minimal_set_rsa(xc, &br_rsa_i31_pkcs1_vrfy);
+ br_x509_minimal_set_ecdsa(xc,
+ &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
+ for (id = br_md5_ID; id <= br_sha512_ID; id ++) {
+ const br_hash_class *hc;
+
+ hc = hashes[id - 1];
+ br_x509_minimal_set_hash(xc, id, hc);
+ }
+}
diff --git a/contrib/bearssl/test/test_crypto.c b/contrib/bearssl/test/test_crypto.c
new file mode 100644
index 000000000000..ae1d170f7a0b
--- /dev/null
+++ b/contrib/bearssl/test/test_crypto.c
@@ -0,0 +1,9475 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include "bearssl.h"
+#include "inner.h"
+
+/*
+ * Decode an hexadecimal string. Returned value is the number of decoded
+ * bytes.
+ */
+static size_t
+hextobin(unsigned char *dst, const char *src)
+{
+ size_t num;
+ unsigned acc;
+ int z;
+
+ num = 0;
+ z = 0;
+ acc = 0;
+ while (*src != 0) {
+ int c = *src ++;
+ if (c >= '0' && c <= '9') {
+ c -= '0';
+ } else if (c >= 'A' && c <= 'F') {
+ c -= ('A' - 10);
+ } else if (c >= 'a' && c <= 'f') {
+ c -= ('a' - 10);
+ } else {
+ continue;
+ }
+ if (z) {
+ *dst ++ = (acc << 4) + c;
+ num ++;
+ } else {
+ acc = c;
+ }
+ z = !z;
+ }
+ return num;
+}
+
+static void
+check_equals(const char *banner, const void *v1, const void *v2, size_t len)
+{
+ size_t u;
+ const unsigned char *b;
+
+ if (memcmp(v1, v2, len) == 0) {
+ return;
+ }
+ fprintf(stderr, "\n%s failed\n", banner);
+ fprintf(stderr, "v1: ");
+ for (u = 0, b = v1; u < len; u ++) {
+ fprintf(stderr, "%02X", b[u]);
+ }
+ fprintf(stderr, "\nv2: ");
+ for (u = 0, b = v2; u < len; u ++) {
+ fprintf(stderr, "%02X", b[u]);
+ }
+ fprintf(stderr, "\n");
+ exit(EXIT_FAILURE);
+}
+
+#define HASH_SIZE(cname) br_ ## cname ## _SIZE
+
+#define TEST_HASH(Name, cname) \
+static void \
+test_ ## cname ## _internal(char *data, char *refres) \
+{ \
+ br_ ## cname ## _context mc; \
+ unsigned char res[HASH_SIZE(cname)], ref[HASH_SIZE(cname)]; \
+ size_t u, n; \
+ \
+ hextobin(ref, refres); \
+ n = strlen(data); \
+ br_ ## cname ## _init(&mc); \
+ br_ ## cname ## _update(&mc, data, n); \
+ br_ ## cname ## _out(&mc, res); \
+ check_equals("KAT " #Name " 1", res, ref, HASH_SIZE(cname)); \
+ br_ ## cname ## _init(&mc); \
+ for (u = 0; u < n; u ++) { \
+ br_ ## cname ## _update(&mc, data + u, 1); \
+ } \
+ br_ ## cname ## _out(&mc, res); \
+ check_equals("KAT " #Name " 2", res, ref, HASH_SIZE(cname)); \
+ for (u = 0; u < n; u ++) { \
+ br_ ## cname ## _context mc2; \
+ br_ ## cname ## _init(&mc); \
+ br_ ## cname ## _update(&mc, data, u); \
+ mc2 = mc; \
+ br_ ## cname ## _update(&mc, data + u, n - u); \
+ br_ ## cname ## _out(&mc, res); \
+ check_equals("KAT " #Name " 3", res, ref, HASH_SIZE(cname)); \
+ br_ ## cname ## _update(&mc2, data + u, n - u); \
+ br_ ## cname ## _out(&mc2, res); \
+ check_equals("KAT " #Name " 4", res, ref, HASH_SIZE(cname)); \
+ } \
+ memset(&mc, 0, sizeof mc); \
+ memset(res, 0, sizeof res); \
+ br_ ## cname ## _vtable.init(&mc.vtable); \
+ mc.vtable->update(&mc.vtable, data, n); \
+ mc.vtable->out(&mc.vtable, res); \
+ check_equals("KAT " #Name " 5", res, ref, HASH_SIZE(cname)); \
+ memset(res, 0, sizeof res); \
+ mc.vtable->init(&mc.vtable); \
+ mc.vtable->update(&mc.vtable, data, n); \
+ mc.vtable->out(&mc.vtable, res); \
+ check_equals("KAT " #Name " 6", res, ref, HASH_SIZE(cname)); \
+}
+
+#define KAT_MILLION_A(Name, cname, refres) do { \
+ br_ ## cname ## _context mc; \
+ unsigned char buf[1000]; \
+ unsigned char res[HASH_SIZE(cname)], ref[HASH_SIZE(cname)]; \
+ int i; \
+ \
+ hextobin(ref, refres); \
+ memset(buf, 'a', sizeof buf); \
+ br_ ## cname ## _init(&mc); \
+ for (i = 0; i < 1000; i ++) { \
+ br_ ## cname ## _update(&mc, buf, sizeof buf); \
+ } \
+ br_ ## cname ## _out(&mc, res); \
+ check_equals("KAT " #Name " 5", res, ref, HASH_SIZE(cname)); \
+ } while (0)
+
+TEST_HASH(MD5, md5)
+TEST_HASH(SHA-1, sha1)
+TEST_HASH(SHA-224, sha224)
+TEST_HASH(SHA-256, sha256)
+TEST_HASH(SHA-384, sha384)
+TEST_HASH(SHA-512, sha512)
+
+static void
+test_MD5(void)
+{
+ printf("Test MD5: ");
+ fflush(stdout);
+ test_md5_internal("", "d41d8cd98f00b204e9800998ecf8427e");
+ test_md5_internal("a", "0cc175b9c0f1b6a831c399e269772661");
+ test_md5_internal("abc", "900150983cd24fb0d6963f7d28e17f72");
+ test_md5_internal("message digest", "f96b697d7cb7938d525a2f31aaf161d0");
+ test_md5_internal("abcdefghijklmnopqrstuvwxyz",
+ "c3fcd3d76192e4007dfb496cca67e13b");
+ test_md5_internal("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstu"
+ "vwxyz0123456789", "d174ab98d277d9f5a5611c2c9f419d9f");
+ test_md5_internal("1234567890123456789012345678901234567890123456789"
+ "0123456789012345678901234567890",
+ "57edf4a22be3c955ac49da2e2107b67a");
+ KAT_MILLION_A(MD5, md5,
+ "7707d6ae4e027c70eea2a935c2296f21");
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_SHA1(void)
+{
+ printf("Test SHA-1: ");
+ fflush(stdout);
+ test_sha1_internal("abc", "a9993e364706816aba3e25717850c26c9cd0d89d");
+ test_sha1_internal("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlm"
+ "nomnopnopq", "84983e441c3bd26ebaae4aa1f95129e5e54670f1");
+
+ KAT_MILLION_A(SHA-1, sha1,
+ "34aa973cd4c4daa4f61eeb2bdbad27316534016f");
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_SHA224(void)
+{
+ printf("Test SHA-224: ");
+ fflush(stdout);
+ test_sha224_internal("abc",
+ "23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7");
+ test_sha224_internal("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlm"
+ "nomnopnopq",
+ "75388b16512776cc5dba5da1fd890150b0c6455cb4f58b1952522525");
+
+ KAT_MILLION_A(SHA-224, sha224,
+ "20794655980c91d8bbb4c1ea97618a4bf03f42581948b2ee4ee7ad67");
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_SHA256(void)
+{
+ printf("Test SHA-256: ");
+ fflush(stdout);
+ test_sha256_internal("abc",
+ "ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad");
+ test_sha256_internal("abcdbcdecdefdefgefghfghighijhijkijkljklmklmnlm"
+ "nomnopnopq",
+ "248d6a61d20638b8e5c026930c3e6039a33ce45964ff2167f6ecedd419db06c1");
+
+ KAT_MILLION_A(SHA-256, sha256,
+ "cdc76e5c9914fb9281a1c7e284d73e67f1809a48a497200e046d39ccc7112cd0");
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_SHA384(void)
+{
+ printf("Test SHA-384: ");
+ fflush(stdout);
+ test_sha384_internal("abc",
+ "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded163"
+ "1a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7");
+ test_sha384_internal(
+ "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+ "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
+ "09330c33f71147e83d192fc782cd1b4753111b173b3b05d2"
+ "2fa08086e3b0f712fcc7c71a557e2db966c3e9fa91746039");
+
+ KAT_MILLION_A(SHA-384, sha384,
+ "9d0e1809716474cb086e834e310a4a1ced149e9c00f24852"
+ "7972cec5704c2a5b07b8b3dc38ecc4ebae97ddd87f3d8985");
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_SHA512(void)
+{
+ printf("Test SHA-512: ");
+ fflush(stdout);
+ test_sha512_internal("abc",
+ "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a"
+ "2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f");
+ test_sha512_internal(
+ "abcdefghbcdefghicdefghijdefghijkefghijklfghijklmghijklmn"
+ "hijklmnoijklmnopjklmnopqklmnopqrlmnopqrsmnopqrstnopqrstu",
+ "8e959b75dae313da8cf4f72814fc143f8f7779c6eb9f7fa17299aeadb6889018"
+ "501d289e4900f7e4331b99dec4b5433ac7d329eeb6dd26545e96e55b874be909");
+
+ KAT_MILLION_A(SHA-512, sha512,
+ "e718483d0ce769644e2e42c7bc15b4638e1f98b13b2044285632a803afa973eb"
+ "de0ff244877ea60a4cb0432ce577c31beb009c5c2c49aa2e4eadb217ad8cc09b");
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_MD5_SHA1(void)
+{
+ unsigned char buf[500], out[36], outM[16], outS[20];
+ unsigned char seed[1];
+ br_hmac_drbg_context rc;
+ br_md5_context mc;
+ br_sha1_context sc;
+ br_md5sha1_context cc;
+ size_t u;
+
+ printf("Test MD5+SHA-1: ");
+ fflush(stdout);
+
+ seed[0] = 0;
+ br_hmac_drbg_init(&rc, &br_sha256_vtable, seed, sizeof seed);
+ for (u = 0; u < sizeof buf; u ++) {
+ size_t v;
+
+ br_hmac_drbg_generate(&rc, buf, u);
+ br_md5_init(&mc);
+ br_md5_update(&mc, buf, u);
+ br_md5_out(&mc, outM);
+ br_sha1_init(&sc);
+ br_sha1_update(&sc, buf, u);
+ br_sha1_out(&sc, outS);
+ br_md5sha1_init(&cc);
+ br_md5sha1_update(&cc, buf, u);
+ br_md5sha1_out(&cc, out);
+ check_equals("MD5+SHA-1 [1]", out, outM, 16);
+ check_equals("MD5+SHA-1 [2]", out + 16, outS, 20);
+ br_md5sha1_init(&cc);
+ for (v = 0; v < u; v ++) {
+ br_md5sha1_update(&cc, buf + v, 1);
+ }
+ br_md5sha1_out(&cc, out);
+ check_equals("MD5+SHA-1 [3]", out, outM, 16);
+ check_equals("MD5+SHA-1 [4]", out + 16, outS, 20);
+ }
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+/*
+ * Compute a hash function, on some data, by ID. Returned value is
+ * hash output length.
+ */
+static size_t
+do_hash(int id, const void *data, size_t len, void *out)
+{
+ br_md5_context cmd5;
+ br_sha1_context csha1;
+ br_sha224_context csha224;
+ br_sha256_context csha256;
+ br_sha384_context csha384;
+ br_sha512_context csha512;
+
+ switch (id) {
+ case br_md5_ID:
+ br_md5_init(&cmd5);
+ br_md5_update(&cmd5, data, len);
+ br_md5_out(&cmd5, out);
+ return 16;
+ case br_sha1_ID:
+ br_sha1_init(&csha1);
+ br_sha1_update(&csha1, data, len);
+ br_sha1_out(&csha1, out);
+ return 20;
+ case br_sha224_ID:
+ br_sha224_init(&csha224);
+ br_sha224_update(&csha224, data, len);
+ br_sha224_out(&csha224, out);
+ return 28;
+ case br_sha256_ID:
+ br_sha256_init(&csha256);
+ br_sha256_update(&csha256, data, len);
+ br_sha256_out(&csha256, out);
+ return 32;
+ case br_sha384_ID:
+ br_sha384_init(&csha384);
+ br_sha384_update(&csha384, data, len);
+ br_sha384_out(&csha384, out);
+ return 48;
+ case br_sha512_ID:
+ br_sha512_init(&csha512);
+ br_sha512_update(&csha512, data, len);
+ br_sha512_out(&csha512, out);
+ return 64;
+ default:
+ fprintf(stderr, "Uknown hash function: %d\n", id);
+ exit(EXIT_FAILURE);
+ return 0;
+ }
+}
+
+/*
+ * Tests for a multihash. Returned value should be 258 multiplied by the
+ * number of hash functions implemented by the context.
+ */
+static int
+test_multihash_inner(br_multihash_context *mc)
+{
+ /*
+ * Try hashing messages for all lengths from 0 to 257 bytes
+ * (inclusive). Each attempt is done twice, with data input
+ * either in one go, or byte by byte. In the byte by byte
+ * test, intermediate result are obtained and checked.
+ */
+ size_t len;
+ unsigned char buf[258];
+ int i;
+ int tcount;
+
+ tcount = 0;
+ for (len = 0; len < sizeof buf; len ++) {
+ br_sha1_context sc;
+ unsigned char tmp[20];
+
+ br_sha1_init(&sc);
+ br_sha1_update(&sc, buf, len);
+ br_sha1_out(&sc, tmp);
+ buf[len] = tmp[0];
+ }
+ for (len = 0; len <= 257; len ++) {
+ size_t u;
+
+ br_multihash_init(mc);
+ br_multihash_update(mc, buf, len);
+ for (i = 1; i <= 6; i ++) {
+ unsigned char tmp[64], tmp2[64];
+ size_t olen, olen2;
+
+ olen = br_multihash_out(mc, i, tmp);
+ if (olen == 0) {
+ continue;
+ }
+ olen2 = do_hash(i, buf, len, tmp2);
+ if (olen != olen2) {
+ fprintf(stderr,
+ "Bad hash output length: %u / %u\n",
+ (unsigned)olen, (unsigned)olen2);
+ exit(EXIT_FAILURE);
+ }
+ check_equals("Hash output", tmp, tmp2, olen);
+ tcount ++;
+ }
+
+ br_multihash_init(mc);
+ for (u = 0; u < len; u ++) {
+ br_multihash_update(mc, buf + u, 1);
+ for (i = 1; i <= 6; i ++) {
+ unsigned char tmp[64], tmp2[64];
+ size_t olen, olen2;
+
+ olen = br_multihash_out(mc, i, tmp);
+ if (olen == 0) {
+ continue;
+ }
+ olen2 = do_hash(i, buf, u + 1, tmp2);
+ if (olen != olen2) {
+ fprintf(stderr, "Bad hash output"
+ " length: %u / %u\n",
+ (unsigned)olen,
+ (unsigned)olen2);
+ exit(EXIT_FAILURE);
+ }
+ check_equals("Hash output", tmp, tmp2, olen);
+ }
+ }
+ }
+ return tcount;
+}
+
+static void
+test_multihash(void)
+{
+ br_multihash_context mc;
+
+ printf("Test MultiHash: ");
+ fflush(stdout);
+
+ br_multihash_zero(&mc);
+ br_multihash_setimpl(&mc, br_md5_ID, &br_md5_vtable);
+ if (test_multihash_inner(&mc) != 258) {
+ fprintf(stderr, "Failed test count\n");
+ }
+ printf(".");
+ fflush(stdout);
+
+ br_multihash_zero(&mc);
+ br_multihash_setimpl(&mc, br_sha1_ID, &br_sha1_vtable);
+ if (test_multihash_inner(&mc) != 258) {
+ fprintf(stderr, "Failed test count\n");
+ }
+ printf(".");
+ fflush(stdout);
+
+ br_multihash_zero(&mc);
+ br_multihash_setimpl(&mc, br_sha224_ID, &br_sha224_vtable);
+ if (test_multihash_inner(&mc) != 258) {
+ fprintf(stderr, "Failed test count\n");
+ }
+ printf(".");
+ fflush(stdout);
+
+ br_multihash_zero(&mc);
+ br_multihash_setimpl(&mc, br_sha256_ID, &br_sha256_vtable);
+ if (test_multihash_inner(&mc) != 258) {
+ fprintf(stderr, "Failed test count\n");
+ }
+ printf(".");
+ fflush(stdout);
+
+ br_multihash_zero(&mc);
+ br_multihash_setimpl(&mc, br_sha384_ID, &br_sha384_vtable);
+ if (test_multihash_inner(&mc) != 258) {
+ fprintf(stderr, "Failed test count\n");
+ }
+ printf(".");
+ fflush(stdout);
+
+ br_multihash_zero(&mc);
+ br_multihash_setimpl(&mc, br_sha512_ID, &br_sha512_vtable);
+ if (test_multihash_inner(&mc) != 258) {
+ fprintf(stderr, "Failed test count\n");
+ }
+ printf(".");
+ fflush(stdout);
+
+ br_multihash_zero(&mc);
+ br_multihash_setimpl(&mc, br_md5_ID, &br_md5_vtable);
+ br_multihash_setimpl(&mc, br_sha1_ID, &br_sha1_vtable);
+ br_multihash_setimpl(&mc, br_sha224_ID, &br_sha224_vtable);
+ br_multihash_setimpl(&mc, br_sha256_ID, &br_sha256_vtable);
+ br_multihash_setimpl(&mc, br_sha384_ID, &br_sha384_vtable);
+ br_multihash_setimpl(&mc, br_sha512_ID, &br_sha512_vtable);
+ if (test_multihash_inner(&mc) != 258 * 6) {
+ fprintf(stderr, "Failed test count\n");
+ }
+ printf(".");
+ fflush(stdout);
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+do_KAT_HMAC_bin_bin(const br_hash_class *digest_class,
+ const void *key, size_t key_len,
+ const void *data, size_t data_len, const char *href)
+{
+ br_hmac_key_context kc;
+ br_hmac_context ctx;
+ unsigned char tmp[64], ref[64];
+ size_t u, len;
+
+ len = hextobin(ref, href);
+ br_hmac_key_init(&kc, digest_class, key, key_len);
+ br_hmac_init(&ctx, &kc, 0);
+ br_hmac_update(&ctx, data, data_len);
+ br_hmac_out(&ctx, tmp);
+ check_equals("KAT HMAC 1", tmp, ref, len);
+
+ br_hmac_init(&ctx, &kc, 0);
+ for (u = 0; u < data_len; u ++) {
+ br_hmac_update(&ctx, (const unsigned char *)data + u, 1);
+ }
+ br_hmac_out(&ctx, tmp);
+ check_equals("KAT HMAC 2", tmp, ref, len);
+
+ for (u = 0; u < data_len; u ++) {
+ br_hmac_init(&ctx, &kc, 0);
+ br_hmac_update(&ctx, data, u);
+ br_hmac_out(&ctx, tmp);
+ br_hmac_update(&ctx,
+ (const unsigned char *)data + u, data_len - u);
+ br_hmac_out(&ctx, tmp);
+ check_equals("KAT HMAC 3", tmp, ref, len);
+ }
+}
+
+static void
+do_KAT_HMAC_str_str(const br_hash_class *digest_class, const char *key,
+ const char *data, const char *href)
+{
+ do_KAT_HMAC_bin_bin(digest_class, key, strlen(key),
+ data, strlen(data), href);
+}
+
+static void
+do_KAT_HMAC_hex_hex(const br_hash_class *digest_class, const char *skey,
+ const char *sdata, const char *href)
+{
+ unsigned char key[1024];
+ unsigned char data[1024];
+
+ do_KAT_HMAC_bin_bin(digest_class, key, hextobin(key, skey),
+ data, hextobin(data, sdata), href);
+}
+
+static void
+do_KAT_HMAC_hex_str(const br_hash_class *digest_class,
+ const char *skey, const char *data, const char *href)
+{
+ unsigned char key[1024];
+
+ do_KAT_HMAC_bin_bin(digest_class, key, hextobin(key, skey),
+ data, strlen(data), href);
+}
+
+static void
+test_HMAC_CT(const br_hash_class *digest_class,
+ const void *key, size_t key_len, const void *data)
+{
+ br_hmac_key_context kc;
+ br_hmac_context hc1, hc2;
+ unsigned char buf1[64], buf2[64];
+ size_t u, v;
+
+ br_hmac_key_init(&kc, digest_class, key, key_len);
+
+ for (u = 0; u < 2; u ++) {
+ for (v = 0; v < 130; v ++) {
+ size_t min_len, max_len;
+ size_t w;
+
+ min_len = v;
+ max_len = v + 256;
+ for (w = min_len; w <= max_len; w ++) {
+ char tmp[30];
+ size_t hlen1, hlen2;
+
+ br_hmac_init(&hc1, &kc, 0);
+ br_hmac_update(&hc1, data, u + w);
+ hlen1 = br_hmac_out(&hc1, buf1);
+ br_hmac_init(&hc2, &kc, 0);
+ br_hmac_update(&hc2, data, u);
+ hlen2 = br_hmac_outCT(&hc2,
+ (const unsigned char *)data + u, w,
+ min_len, max_len, buf2);
+ if (hlen1 != hlen2) {
+ fprintf(stderr, "HMAC length mismatch:"
+ " %u / %u\n", (unsigned)hlen1,
+ (unsigned)hlen2);
+ exit(EXIT_FAILURE);
+ }
+ sprintf(tmp, "HMAC CT %u,%u,%u",
+ (unsigned)u, (unsigned)v, (unsigned)w);
+ check_equals(tmp, buf1, buf2, hlen1);
+ }
+ }
+ printf(".");
+ fflush(stdout);
+ }
+ printf(" ");
+ fflush(stdout);
+}
+
+static void
+test_HMAC(void)
+{
+ unsigned char data[1000];
+ unsigned x;
+ size_t u;
+ const char key[] = "test HMAC key";
+
+ printf("Test HMAC: ");
+ fflush(stdout);
+ do_KAT_HMAC_hex_str(&br_md5_vtable,
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "Hi There",
+ "9294727a3638bb1c13f48ef8158bfc9d");
+ do_KAT_HMAC_str_str(&br_md5_vtable,
+ "Jefe",
+ "what do ya want for nothing?",
+ "750c783e6ab0b503eaa86e310a5db738");
+ do_KAT_HMAC_hex_hex(&br_md5_vtable,
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD",
+ "56be34521d144c88dbb8c733f0e8b3f6");
+ do_KAT_HMAC_hex_hex(&br_md5_vtable,
+ "0102030405060708090a0b0c0d0e0f10111213141516171819",
+ "CDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCD",
+ "697eaf0aca3a3aea3a75164746ffaa79");
+ do_KAT_HMAC_hex_str(&br_md5_vtable,
+ "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
+ "Test With Truncation",
+ "56461ef2342edc00f9bab995690efd4c");
+ do_KAT_HMAC_hex_str(&br_md5_vtable,
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "Test Using Larger Than Block-Size Key - Hash Key First",
+ "6b1ab7fe4bd7bf8f0b62e6ce61b9d0cd");
+ do_KAT_HMAC_hex_str(&br_md5_vtable,
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
+ "6f630fad67cda0ee1fb1f562db3aa53e");
+
+ do_KAT_HMAC_hex_str(&br_sha1_vtable,
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "Hi There",
+ "b617318655057264e28bc0b6fb378c8ef146be00");
+ do_KAT_HMAC_str_str(&br_sha1_vtable,
+ "Jefe",
+ "what do ya want for nothing?",
+ "effcdf6ae5eb2fa2d27416d5f184df9c259a7c79");
+ do_KAT_HMAC_hex_hex(&br_sha1_vtable,
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "DDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDDD",
+ "125d7342b9ac11cd91a39af48aa17b4f63f175d3");
+ do_KAT_HMAC_hex_hex(&br_sha1_vtable,
+ "0102030405060708090a0b0c0d0e0f10111213141516171819",
+ "CDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCDCD",
+ "4c9007f4026250c6bc8414f9bf50c86c2d7235da");
+ do_KAT_HMAC_hex_str(&br_sha1_vtable,
+ "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
+ "Test With Truncation",
+ "4c1a03424b55e07fe7f27be1d58bb9324a9a5a04");
+ do_KAT_HMAC_hex_str(&br_sha1_vtable,
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "Test Using Larger Than Block-Size Key - Hash Key First",
+ "aa4ae5e15272d00e95705637ce8a3b55ed402112");
+ do_KAT_HMAC_hex_str(&br_sha1_vtable,
+ "AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA",
+ "Test Using Larger Than Block-Size Key and Larger Than One Block-Size Data",
+ "e8e99d0f45237d786d6bbaa7965c7808bbff1a91");
+
+ /* From RFC 4231 */
+
+ do_KAT_HMAC_hex_hex(&br_sha224_vtable,
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "4869205468657265",
+ "896fb1128abbdf196832107cd49df33f"
+ "47b4b1169912ba4f53684b22");
+
+ do_KAT_HMAC_hex_hex(&br_sha256_vtable,
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "4869205468657265",
+ "b0344c61d8db38535ca8afceaf0bf12b"
+ "881dc200c9833da726e9376c2e32cff7");
+
+ do_KAT_HMAC_hex_hex(&br_sha384_vtable,
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "4869205468657265",
+ "afd03944d84895626b0825f4ab46907f"
+ "15f9dadbe4101ec682aa034c7cebc59c"
+ "faea9ea9076ede7f4af152e8b2fa9cb6");
+
+ do_KAT_HMAC_hex_hex(&br_sha512_vtable,
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "4869205468657265",
+ "87aa7cdea5ef619d4ff0b4241a1d6cb0"
+ "2379f4e2ce4ec2787ad0b30545e17cde"
+ "daa833b7d6b8a702038b274eaea3f4e4"
+ "be9d914eeb61f1702e696c203a126854");
+
+ do_KAT_HMAC_hex_hex(&br_sha224_vtable,
+ "4a656665",
+ "7768617420646f2079612077616e7420"
+ "666f72206e6f7468696e673f",
+ "a30e01098bc6dbbf45690f3a7e9e6d0f"
+ "8bbea2a39e6148008fd05e44");
+
+ do_KAT_HMAC_hex_hex(&br_sha256_vtable,
+ "4a656665",
+ "7768617420646f2079612077616e7420"
+ "666f72206e6f7468696e673f",
+ "5bdcc146bf60754e6a042426089575c7"
+ "5a003f089d2739839dec58b964ec3843");
+
+ do_KAT_HMAC_hex_hex(&br_sha384_vtable,
+ "4a656665",
+ "7768617420646f2079612077616e7420"
+ "666f72206e6f7468696e673f",
+ "af45d2e376484031617f78d2b58a6b1b"
+ "9c7ef464f5a01b47e42ec3736322445e"
+ "8e2240ca5e69e2c78b3239ecfab21649");
+
+ do_KAT_HMAC_hex_hex(&br_sha512_vtable,
+ "4a656665",
+ "7768617420646f2079612077616e7420"
+ "666f72206e6f7468696e673f",
+ "164b7a7bfcf819e2e395fbe73b56e0a3"
+ "87bd64222e831fd610270cd7ea250554"
+ "9758bf75c05a994a6d034f65f8f0e6fd"
+ "caeab1a34d4a6b4b636e070a38bce737");
+
+ do_KAT_HMAC_hex_hex(&br_sha224_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaa",
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddd",
+ "7fb3cb3588c6c1f6ffa9694d7d6ad264"
+ "9365b0c1f65d69d1ec8333ea");
+
+ do_KAT_HMAC_hex_hex(&br_sha256_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaa",
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddd",
+ "773ea91e36800e46854db8ebd09181a7"
+ "2959098b3ef8c122d9635514ced565fe");
+
+ do_KAT_HMAC_hex_hex(&br_sha384_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaa",
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddd",
+ "88062608d3e6ad8a0aa2ace014c8a86f"
+ "0aa635d947ac9febe83ef4e55966144b"
+ "2a5ab39dc13814b94e3ab6e101a34f27");
+
+ do_KAT_HMAC_hex_hex(&br_sha512_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaa",
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddddddddddddddddddddddddddddddd"
+ "dddd",
+ "fa73b0089d56a284efb0f0756c890be9"
+ "b1b5dbdd8ee81a3655f83e33b2279d39"
+ "bf3e848279a722c806b485a47e67c807"
+ "b946a337bee8942674278859e13292fb");
+
+ do_KAT_HMAC_hex_hex(&br_sha224_vtable,
+ "0102030405060708090a0b0c0d0e0f10"
+ "111213141516171819",
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcd",
+ "6c11506874013cac6a2abc1bb382627c"
+ "ec6a90d86efc012de7afec5a");
+
+ do_KAT_HMAC_hex_hex(&br_sha256_vtable,
+ "0102030405060708090a0b0c0d0e0f10"
+ "111213141516171819",
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcd",
+ "82558a389a443c0ea4cc819899f2083a"
+ "85f0faa3e578f8077a2e3ff46729665b");
+
+ do_KAT_HMAC_hex_hex(&br_sha384_vtable,
+ "0102030405060708090a0b0c0d0e0f10"
+ "111213141516171819",
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcd",
+ "3e8a69b7783c25851933ab6290af6ca7"
+ "7a9981480850009cc5577c6e1f573b4e"
+ "6801dd23c4a7d679ccf8a386c674cffb");
+
+ do_KAT_HMAC_hex_hex(&br_sha512_vtable,
+ "0102030405060708090a0b0c0d0e0f10"
+ "111213141516171819",
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd"
+ "cdcd",
+ "b0ba465637458c6990e5a8c5f61d4af7"
+ "e576d97ff94b872de76f8050361ee3db"
+ "a91ca5c11aa25eb4d679275cc5788063"
+ "a5f19741120c4f2de2adebeb10a298dd");
+
+ do_KAT_HMAC_hex_hex(&br_sha224_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54657374205573696e67204c61726765"
+ "72205468616e20426c6f636b2d53697a"
+ "65204b6579202d2048617368204b6579"
+ "204669727374",
+ "95e9a0db962095adaebe9b2d6f0dbce2"
+ "d499f112f2d2b7273fa6870e");
+
+ do_KAT_HMAC_hex_hex(&br_sha256_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54657374205573696e67204c61726765"
+ "72205468616e20426c6f636b2d53697a"
+ "65204b6579202d2048617368204b6579"
+ "204669727374",
+ "60e431591ee0b67f0d8a26aacbf5b77f"
+ "8e0bc6213728c5140546040f0ee37f54");
+
+ do_KAT_HMAC_hex_hex(&br_sha384_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54657374205573696e67204c61726765"
+ "72205468616e20426c6f636b2d53697a"
+ "65204b6579202d2048617368204b6579"
+ "204669727374",
+ "4ece084485813e9088d2c63a041bc5b4"
+ "4f9ef1012a2b588f3cd11f05033ac4c6"
+ "0c2ef6ab4030fe8296248df163f44952");
+
+ do_KAT_HMAC_hex_hex(&br_sha512_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54657374205573696e67204c61726765"
+ "72205468616e20426c6f636b2d53697a"
+ "65204b6579202d2048617368204b6579"
+ "204669727374",
+ "80b24263c7c1a3ebb71493c1dd7be8b4"
+ "9b46d1f41b4aeec1121b013783f8f352"
+ "6b56d037e05f2598bd0fd2215d6a1e52"
+ "95e64f73f63f0aec8b915a985d786598");
+
+ do_KAT_HMAC_hex_hex(&br_sha224_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54686973206973206120746573742075"
+ "73696e672061206c6172676572207468"
+ "616e20626c6f636b2d73697a65206b65"
+ "7920616e642061206c61726765722074"
+ "68616e20626c6f636b2d73697a652064"
+ "6174612e20546865206b6579206e6565"
+ "647320746f2062652068617368656420"
+ "6265666f7265206265696e6720757365"
+ "642062792074686520484d414320616c"
+ "676f726974686d2e",
+ "3a854166ac5d9f023f54d517d0b39dbd"
+ "946770db9c2b95c9f6f565d1");
+
+ do_KAT_HMAC_hex_hex(&br_sha256_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54686973206973206120746573742075"
+ "73696e672061206c6172676572207468"
+ "616e20626c6f636b2d73697a65206b65"
+ "7920616e642061206c61726765722074"
+ "68616e20626c6f636b2d73697a652064"
+ "6174612e20546865206b6579206e6565"
+ "647320746f2062652068617368656420"
+ "6265666f7265206265696e6720757365"
+ "642062792074686520484d414320616c"
+ "676f726974686d2e",
+ "9b09ffa71b942fcb27635fbcd5b0e944"
+ "bfdc63644f0713938a7f51535c3a35e2");
+
+ do_KAT_HMAC_hex_hex(&br_sha384_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54686973206973206120746573742075"
+ "73696e672061206c6172676572207468"
+ "616e20626c6f636b2d73697a65206b65"
+ "7920616e642061206c61726765722074"
+ "68616e20626c6f636b2d73697a652064"
+ "6174612e20546865206b6579206e6565"
+ "647320746f2062652068617368656420"
+ "6265666f7265206265696e6720757365"
+ "642062792074686520484d414320616c"
+ "676f726974686d2e",
+ "6617178e941f020d351e2f254e8fd32c"
+ "602420feb0b8fb9adccebb82461e99c5"
+ "a678cc31e799176d3860e6110c46523e");
+
+ do_KAT_HMAC_hex_hex(&br_sha512_vtable,
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"
+ "aaaaaa",
+ "54686973206973206120746573742075"
+ "73696e672061206c6172676572207468"
+ "616e20626c6f636b2d73697a65206b65"
+ "7920616e642061206c61726765722074"
+ "68616e20626c6f636b2d73697a652064"
+ "6174612e20546865206b6579206e6565"
+ "647320746f2062652068617368656420"
+ "6265666f7265206265696e6720757365"
+ "642062792074686520484d414320616c"
+ "676f726974686d2e",
+ "e37b6a775dc87dbaa4dfa9f96e5e3ffd"
+ "debd71f8867289865df5a32d20cdc944"
+ "b6022cac3c4982b10d5eeb55c3e4de15"
+ "134676fb6de0446065c97440fa8c6a58");
+
+ for (x = 1, u = 0; u < sizeof data; u ++) {
+ data[u] = x;
+ x = (x * 45) % 257;
+ }
+ printf("(MD5) ");
+ test_HMAC_CT(&br_md5_vtable, key, sizeof key, data);
+ printf("(SHA-1) ");
+ test_HMAC_CT(&br_sha1_vtable, key, sizeof key, data);
+ printf("(SHA-224) ");
+ test_HMAC_CT(&br_sha224_vtable, key, sizeof key, data);
+ printf("(SHA-256) ");
+ test_HMAC_CT(&br_sha256_vtable, key, sizeof key, data);
+ printf("(SHA-384) ");
+ test_HMAC_CT(&br_sha384_vtable, key, sizeof key, data);
+ printf("(SHA-512) ");
+ test_HMAC_CT(&br_sha512_vtable, key, sizeof key, data);
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_HKDF_inner(const br_hash_class *dig, const char *ikmhex,
+ const char *salthex, const char *infohex, const char *okmhex)
+{
+ unsigned char ikm[100], saltbuf[100], info[100], okm[100], tmp[107];
+ const unsigned char *salt;
+ size_t ikm_len, salt_len, info_len, okm_len;
+ br_hkdf_context hc;
+ size_t u;
+
+ ikm_len = hextobin(ikm, ikmhex);
+ if (salthex == NULL) {
+ salt = BR_HKDF_NO_SALT;
+ salt_len = 0;
+ } else {
+ salt = saltbuf;
+ salt_len = hextobin(saltbuf, salthex);
+ }
+ info_len = hextobin(info, infohex);
+ okm_len = hextobin(okm, okmhex);
+
+ br_hkdf_init(&hc, dig, salt, salt_len);
+ br_hkdf_inject(&hc, ikm, ikm_len);
+ br_hkdf_flip(&hc);
+ br_hkdf_produce(&hc, info, info_len, tmp, okm_len);
+ check_equals("KAT HKDF 1", tmp, okm, okm_len);
+
+ br_hkdf_init(&hc, dig, salt, salt_len);
+ for (u = 0; u < ikm_len; u ++) {
+ br_hkdf_inject(&hc, &ikm[u], 1);
+ }
+ br_hkdf_flip(&hc);
+ for (u = 0; u < okm_len; u ++) {
+ br_hkdf_produce(&hc, info, info_len, &tmp[u], 1);
+ }
+ check_equals("KAT HKDF 2", tmp, okm, okm_len);
+
+ br_hkdf_init(&hc, dig, salt, salt_len);
+ br_hkdf_inject(&hc, ikm, ikm_len);
+ br_hkdf_flip(&hc);
+ for (u = 0; u < okm_len; u += 7) {
+ br_hkdf_produce(&hc, info, info_len, &tmp[u], 7);
+ }
+ check_equals("KAT HKDF 3", tmp, okm, okm_len);
+
+ printf(".");
+ fflush(stdout);
+}
+
+static void
+test_HKDF(void)
+{
+ printf("Test HKDF: ");
+ fflush(stdout);
+
+ test_HKDF_inner(&br_sha256_vtable,
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "000102030405060708090a0b0c",
+ "f0f1f2f3f4f5f6f7f8f9",
+ "3cb25f25faacd57a90434f64d0362f2a2d2d0a90cf1a5a4c5db02d56ecc4c5bf34007208d5b887185865");
+
+ test_HKDF_inner(&br_sha256_vtable,
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f",
+ "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
+ "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+ "b11e398dc80327a1c8e7f78c596a49344f012eda2d4efad8a050cc4c19afa97c59045a99cac7827271cb41c65e590e09da3275600c2f09b8367793a9aca3db71cc30c58179ec3e87c14c01d5c1f3434f1d87");
+
+ test_HKDF_inner(&br_sha256_vtable,
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "",
+ "",
+ "8da4e775a563c18f715f802a063c5a31b8a11f5c5ee1879ec3454e5f3c738d2d9d201395faa4b61a96c8");
+
+ test_HKDF_inner(&br_sha1_vtable,
+ "0b0b0b0b0b0b0b0b0b0b0b",
+ "000102030405060708090a0b0c",
+ "f0f1f2f3f4f5f6f7f8f9",
+ "085a01ea1b10f36933068b56efa5ad81a4f14b822f5b091568a9cdd4f155fda2c22e422478d305f3f896");
+
+ test_HKDF_inner(&br_sha1_vtable,
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f404142434445464748494a4b4c4d4e4f",
+ "606162636465666768696a6b6c6d6e6f707172737475767778797a7b7c7d7e7f808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9fa0a1a2a3a4a5a6a7a8a9aaabacadaeaf",
+ "b0b1b2b3b4b5b6b7b8b9babbbcbdbebfc0c1c2c3c4c5c6c7c8c9cacbcccdcecfd0d1d2d3d4d5d6d7d8d9dadbdcdddedfe0e1e2e3e4e5e6e7e8e9eaebecedeeeff0f1f2f3f4f5f6f7f8f9fafbfcfdfeff",
+ "0bd770a74d1160f7c9f12cd5912a06ebff6adcae899d92191fe4305673ba2ffe8fa3f1a4e5ad79f3f334b3b202b2173c486ea37ce3d397ed034c7f9dfeb15c5e927336d0441f4c4300e2cff0d0900b52d3b4");
+
+ test_HKDF_inner(&br_sha1_vtable,
+ "0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b0b",
+ "",
+ "",
+ "0ac1af7002b3d761d1e55298da9d0506b9ae52057220a306e07b6b87e8df21d0ea00033de03984d34918");
+
+ test_HKDF_inner(&br_sha1_vtable,
+ "0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c0c",
+ NULL,
+ "",
+ "2c91117204d745f3500d636a62f64f0ab3bae548aa53d423b0d1f27ebba6f5e5673a081d70cce7acfc48");
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+/*
+ * Known-answer test vectors for SHAKE128, from the NIST validation test
+ * suite. Each vector is a pair (input,output).
+ */
+static const char *const KAT_SHAKE128[] = {
+
+ "e4e932fc9907620ebebffd32b10fda7890a5bc20e5f41d5589882a18c2960e7aafd8730ee697469e5b0abb1d84de92ddba169802e31570374ef9939fde2b960e6b34ac7a65d36bacba4cd33bfa028cbbba486f32367548cb3a36dacf422924d0e0a7e3285ee158a2a42e4b765da3507b56e54998263b2c7b14e7078e35b74127d5d7220018e995e6e1572db5f3e8678357922f1cfd90a5afa6b420c600fd737b136c70e9dd14",
+ "459ce4fa824ee1910a678abc77c1f769",
+
+ "18636f702f216b1b9302e59d82192f4e002f82d526c3f04cbd4f9b9f0bcd2535ed7a67d326da66bdf7fc821ef0fff1a905d56c81e4472856863908d104301133ad111e39552cd542ef78d9b35f20419b893f4a93aee848e9f86ae3fd53d27fea7fb1fc69631fa0f3a5ff51267785086ab4f682d42baf394b3b6992e9a0bb58a38ce0692df9bbaf183e18523ee1352c5fad817e0c04a3e1c476be7f5e92f482a6fb29cd4bbf09ea",
+ "b7b9db481898f888e5ee4ed629859844",
+
+ "5d9ff9fe63c328ddbe0c865ac6ba605c52a14ee8e4870ba320ce849283532f2551959e74cf1a54c8b30ed75dd92e076637e4ad5213b3574e73d6640bd6245bc121378174dccdaa769e6e4f2dc650e1166c775d0a982021c0b160fe9438098e86b6cdc786f2a6d1ef68751551f7e99773daa28598d9961002c0b47ab511c8707df69f9b32796b723bf7685251d2c0d08567ad4e8540ddcc1b8a1a01f6c92aaaadcaf42301d9e53463",
+ "f50af2684408915871948779a14c147c",
+
+ "38c0be76e7b60f262f1499e328e0519f864bbb9d134d00345d8942d0ab762c3936c0cd1896eca6b77b3c01089dd285e9f61708a62e5ea4bf57c50decda5c215fb18ac149d7ace09ffdfed91e7fbf068d96908e42cf1e7ee7bc001c7ee9e378a311e44311923de4681f24c92eb5f0fb13d07ef679ded3b733f402168dc050568dbf97fb79afe8db994874783e27ad8d040ba8e75343c6762c6793a42247eee5a6216b908817f5edbbdf",
+ "e4786ad8f2ea9c8e420a6f50b5feec9a",
+
+ "ec586d52ad2ced1f96bd9458a5a1f64bc1b4cce1fa52517513c9ebe63d0d0eeb26ae5da73208137e08baa22651599a01bc65cbaa467baeceb8cd013d71d0b2406534fe2e6619da3aa380928f6effb09f42ba1fb7048e90d7898f1dc259b52c51b2d2970cd0c70afb6cf8acba83fd01cc589b0f31bcf2bf3b8df7879d7d2546c514706f6cf97b6a6b6d0a37d018ba553108f0e240f70f03a0ccee86f76589c64594f6cf74679bc330ad9f",
+ "191a3710c72d11da7a2410bc73ba9d9f",
+
+ "c201dfe59e03574476e3c220c971c1685ea96ea137daed2ac10845c54d8e6e53c307acdf956f1bdef3868ab53e758c7cbeb4cd02972ba311f998e5f3983000345c8947aa59b78bb301b6ecbe9808ee0de99ed0b938fc19f677997398bd84bcd6f34d5b4ed123d04a093a8f42c1700fa2472f1ecc00957761a2d296bda3d2cbc0f21d8ed4e4fb122b71db1d49a0f516c3402f6046d93de6dae20df7683462557abfbf88437c8678dfa2613b",
+ "464121895e5c9d85190bcee0437453dd",
+
+ "bd34acd613e0e0da6bebc45ba73fefa0bd8aa8ebba34040a07944f29eb63adea527101b8cd960e58d9ecddc0643b5e2d8db55170ace4678892e0a57612c50a4dc0647189f839b9a1229e22e0353dfa707acb7ab893f4ebe8bb910cd14f21b8fb8e77c4f19db027e0cd685d60212e0d920b34e96b774bd54f0a0f4ce2ac5f001b4411c19ac2e3a03b63b454eb30f4ddbac959673260d370e708c32d5030682ad56a99322972ba6eda6be9d027",
+ "8e167ceae101ea0b3b98175f66e46b0e",
+
+ "166b4fec6967c2a25f80c0075379978124833b84894c3cb3a538f649dcee08b8e41707901f6273a128cce964ac1e9b977bb7fe28de8bc2542c6c07109889cea84d34ada6bde8c8f5358afc46b5ef5db3009fe3a2efd860ed0ad6b540595246c27849abf7eafea9e5af42607519f3c51ddbc353bc633afec56aff69a0c953584d8ede684b4faefeb8be7d7db97e32bc1c35abb73ce3ba8425726d89f98e93ed93b67b4c6993ffafb789c1bbda8d",
+ "eb2fa0e8e04e698ca511d6abf7de84fb",
+
+ "62c625d31a400c5ff092d6fd638f1ea911ad912f2aabffea2377b1d2af4efeb6eb2519c5d8482d530f41acdab0fbe43f9c27d357e4df3caa8189fa7745ff95f811ed13e6497a1040852a1149890216d078ee6eb34461cfa6693ba631dbefacf83ce5ba3f531ddeadba16ae50d6eedce20cca0b4b3278e16644535e0859676c3fd5d6b7d7df7bbe2316cc2bfa7f055fffc2835225976d9a737b9ac905a7affc544288b1b7d6dad92901162f4c6d90",
+ "bb0acc4423c1d8cfc788e748ade8d5fd",
+
+ "8af63bbe701b84ff9b0c9d2fd830e28b7d557af3fcf4874bb7b69f2116388090d70bff64a600427eeea22f7bee0324900fbce9b8752fe312d40f8a8485231da5d94694daadb3d6bf3e7f2cc83f67f52829cc9cf1d3fcc87d42b3d20ec2e27cb135aee068acbca68734ac7a5ff3e3bd1a738e7be63de39e56aaaa6104f6fd077c964ccc55cba41ca1783003883100e52f94096fdfdc6dcd63b3fd1db148fc24cda22640eb34f19ed4b113ad8a2144d3",
+ "4a824cae0f236eab147bd6ebf66eafc2",
+
+ "a8c0f0e4afcda47e02afaaa2357c589e6b94168a6f6f142b019938186efa5b1b645bb4da032694b7376d54f4462e8c1ba5d6869d1003f3b9d98edc9f81c9dbd685058adb7a583c0b5c9debc224bb72c5982bfcdd67b4bdc57579e0467436c0a1b4c75a2d3cea034119455654f6ab7163ed9b61949d09da187d612b556fca724599a80c1970645023156f7df2e584f0bf4c2e9b08d98bb27a984fa7149c0b598adbb089e73f4f8d77f92248e419d0599f",
+ "4800f8f5e598a26ee05a0ea141f849d0",
+
+ "a035c12af3fb705602540bd0f4a00395e1625edf2d44af4a145b463585aba46b34ee3203eb9132842000f54dcd234e347c28486ea18414af2d3445916049403adfa3ed3906fdb3b27f2aa4bb149df405c12fb0bf0e1dacb79c50bec3fde2295fc8dd5c97ed46dd28475a80e27017dc50d9feff9b1a1861ac86371791037e49221923e6e44874962d9f18f1898a98ee5dec1e9eca6d7c1ad4166fbac41b2587caf7fef3e7be90c80aafed5f7a0928127321",
+ "2d124d81a4a45ad9c0b91cca23cc2991",
+
+ "d41739834414a0792470d53dee0f3f6c5a197314d3a14d75278440048294eab69df6eb7a33c9f807b5082bd93eb29d76c92837f6a2d6c5c21a154c9c7f509ee04b662b099c501a76e404996fe2997163d1abdd73df019c35e06d45b144f4dbb0462fa13767f12f4e1b2bc605c20ce1b9d96c0c94726af953e154d14cb9c8c8aff719f40c7cf45f15c1445ba6c65215024b316d60435905a686929874c6148e64c4eccd90c3a1d1553d18ff57d6b536c58ec3",
+ "551fc7eceeee151523be716538258e2e",
+
+ "5bbb333460ffac345e4d2bc2dba303ef75b85c57233590fabd22d547bf9e1d7a4ad43a286b2a4618a0bb42559808fd813bea376ceacc07e608167ad1b9ec7d7ae919fd2991464cf63570c7dfb299b61836bd73a29007cf1faa45b1e5539a00514272c35d58bb877526530187afbcf55a6f1757209c50af4eab96c2ab160e6ea75dc8d6ef4bf2bf3e7a4b3a7619db84efede22a0f960e701b14f0f44c89b18f2640017c05ef51bcf93942b8d3775d2980b80435",
+ "2c98dce5b1ec5f1f23554a755fac7700",
+
+ "8040a7296d7553886e5b25c7cf1f64a6a0a143185a83abf5c5813bef18008ec762e9bcc12ab7235552cf67274210b73942ac525f26364af431fc88cc34961169f6bf8872d864f360b9fbc27b18160d0578381db509e72e678402731157555bf9026b1325c1a34c136b863eab9a58ec720cedaa0049bfddb4863d03a6ca65f3dd4f9465c32b9db4d52f19e39f10ffdfe8c475032a2fe5e145ff524073d5ed617fa5e387325f7ab50fcf5cba40c2326bcf6a753019",
+ "c0bb8427ef0ca4e457d2887878d91310",
+
+ "cbaceb762e6c2f5f96052d4a681b899b84de459d198b3624bd35b471bdc59655b1405e9a5448b09e93e60941e486ad01d943e164f5655b97be28f75413c0ab08c099bd3650e33316234e8c83c012ad146b331e88fb037667e6e814e69e5f100b20417113c946a1116cc71ed7a3c87119623564d0d26c70dd5cfc75ef03acaea6f8c0e3f96877e0d599d8270635aee25be6d21b0522a82f4149ec8037edaf6b21709c7aafd580daaad00a0fd91fcfe6211d90abef95",
+ "626bd9eb0982b6db884d38e8c234854e",
+
+ "1bbee570394bc18d0f8713c7149cabb84e0567dd184510e922d97f5fb96b045f494808c02014f06074bd45b8a8ad12b4cb448ec16285fb27670fce99914f100ad6f504c32fa40ab39beec306667f76f9ab98b3ec18c036b8f1b60d4457a9fe53cbab23a0ee64d72d8a03d6d8d67a9f2ff6eb1d85c25d8746c8b4858794e094e12f54ab80e5ba1f774be5c456810755ffb52415b5e8c6b776f5f37b8bcf5c9b5d0ad7e58a9d0fa938e67ad5aaee8c5f11ef2be3a41362",
+ "a489ab3eb43f65ffbd4d4c34169ee762",
+
+ "aeacffca0e87bfdb2e6e74bfb67c9c90a8b6fb918b9be164cafcab7d570d8cd693bd8ee47243d3cbdaf921ce4d6e9e09c8b6d762eb0507bd597d976f6243e1f5e0d839e75ea72e2780da0d5e9f72a7a9b397548f762c3837c6a7c5d74b2081705ba70ab91adb5758e6b94058f2b141d830ff7b007538fb3ad8233f9e5bcbf6adcdd20843ee08d6c7d53cc3a58f53f3fe0997539e2f51d92e56990daad76dc816fd013b6d225634db140e9d2bbe7f45830406e44fee9d59",
+ "4eaa27b085d08fc6a7473e672ea2ca1b",
+
+ "a22314d2173ca4d53897924c4b395f0ae52c7fff4880525cee9055f866879af35f22759903b779898676a216feefd4ed75d484f83c00b58383b9279e2732cbc2cb5479b72abee5b4ab0bd0c937537b7a47f461ad419225c6045cca10c191225f0e4389f3355cd3a0d2de822c9d6f3cf984147de3fd3d8a6c9a02a617ddac87114f770b16cc96289321782108d94a00b153bd40651809cabe6c32237a2389e321b67769e89676cdd6c060162592ecadebdd7512fa3bfece04",
+ "eea88229becc3608df892998b80cf57b",
+
+ "f99bba3e3b14c8de38c8edecd9c983aa641320a251130f45596a00d2cfeefe7933f1a2c105c78627d782fd07a60001c06a286d14ec706dcdd8a232a613e1ea684ee7ef54dc903ec1c09c2c060bb0549a659fd47ae9e8b9cb3680b7c1c2d11ebf720209c06879d8f51d9ee1afafe263807c01bb9def83db879a89f7eb85c681c6c6cc58cc52893d0b131186cc3b9e16bad7d48c46a74abb492d475beb04c9fdc573cc454242c8534bcc7c822356ea558f9fa3ae3bb844415916",
+ "5109746cb7a61482e6e28de02db1a4a5",
+
+ "564da8460dc0c3d20b1fda3628349a399ba52446b5d3626fd0039ab282bc437b166f186b3c5e6c58ffb6bd95f8fe8b73c1b56a07ad37572eb6e148cfb7750760dcc03fac567ad7d3536d80922dda8ac4e118fc29c47ee3677183ea4e06242b6090864591c3ddaf4bef8c4cb52f8e3f35e4140034616faf21e831a9b8d68f5a841a0a52a2eb4f9ac9bb5b488766e251cdb0f29faeeed463640333ad948e7f3ad362948c68379740539f219d8f3ba069952efa0021d273a738aad0",
+ "f43552da8b2623a130196e70a770230d",
+
+ "8a54e8bf30eeb2e098955f2eef10af3c0a32391656fdff82120e4785bb35a629c8635e7e98c9eadfa93ed6760ae1d40313000dd85339b528cadfe28258a09e9976643a462477e6d022eb7f6a6338a8fdbf261c28e8ed43869f9a032f28b4d881fb202720bc42cf3b6d650211e35d53b4766a0f0dfd60d121fa05519211bb7d69bf5fcb124870cda8f17406747097fcb0a1968e907adb888341ea75b6fcfbb4d92ae8ce27b04a07a016df3399f330cb77a67040b847a68f33de0f16",
+ "c51c6e34cef091a05dfcf30d45b21536",
+
+ "2a64753a74d768b82c5638a0b24ef0da181bc7d6e2c4ffdb0ae50d9c48ecfa0d90880974db5f9ac32a004e25c8186cd7d0e88439f0f652256c03e47f663eff0d5cb7c089f2167ff5f28df82f910badc5f4b3860af28cbb6a1c7af3fafa6dae5398d8e0a14165def78be77ee6948f7a4d8a64167271ed0352203082368de1cd874bd3b2e351b28170fdf42871590d9d179ce27c99f481f287820fd95ba60124517e907e78a9662e09519e3ef868ebdcca311700a603b04fae4afe4090",
+ "2d2ee67938422ae12f8cfa8b2e744577",
+
+ "a7d645b70f27f01617e76abc2ae514164f18d6fd4f3464e71a7fc05a67e101a79b3b52d4ecfa3ddac6ec2a116d5222e8e536d9d90fffec9c1442679b06db8aa7c53dcde92006211b3dd779f83b6289f015c4cd21ca16ce83bb3ea162540bb012ee82bddef4722341454f5f59da3cd098a96abbbdc9a19202d61c7697979afa50deb22a9bb067ccb4a6fce51c930a7f4767cfaa9454c9c1832f83ee2318b0f0c95d761c079c0ca2dc28871229aef11f64199ca290b2b5e26d8c1c12ec1f",
+ "ec989e0290fc737952de37dd1ebc01c6",
+
+ "3436fe321f2a41478164b8b408a7a8f54ff2a79cb2020bf36118a2e3b3fca414bd42e55624cc4f402f909016209b10f0c55626194a098bb6519d0fa844a68ab3eaa116df39797b1e6c51eb30557df0c4f3d1a2e0471f1d8264fb3288c6c15dcde4daf795083aad2b5f2d31c84c542fb702ea83b7524ca9a1c1b9754ade5604abd375f23f3916cdad31aecaa7b028b7121a2a316713991759925f3fb8366c6795defa6ea77416c4ed095c1f9527026f1d621815b8310d4ff3fc76f798760b",
+ "bb5e48212442ad7ae83697092024c22b",
+
+ "01bdb4f89f84b728a9d6b3a03f60709900571c1a2a0f912702cad73677ceeae202babde3d0197e3e23381cb9f6350792e05937703aa76f9a84b5c36705bb58f6b2ea6b1e51ff94a8de174cbc2ec5ae9ad2627a8b3ea45f162b727a7639f71a4cd9f6c6926a5d81d0a21c4c923037ed199f1aef517e2eea03bea9044c5baab84e3f85d625635bcb1c37ef232144b44c770f2b9dab416b96c906016acfb3fbba62ab40a4c08323fcf66437d953b164541cea3a8c81d186eed0cb23b3e98813a9",
+ "8bb7ffa4572616f3bc7c33bd70bbcd59",
+
+ "9ae51ed483306c9a5a6db027f03cd4472cf3a71df5f1e11852306123d01ab81c259eeb88128275858efb8cff207ba5278dca3a21b358cbfdb5d223e958f3dca5ad9d2537f128c3dfb1fa564d3157de120f7b7d5524e67fc7abf897d9a5bd6b2c7c0a5348e6c95e920c919778ec7a86effb2ff91f0f44045c7dca46597e216e98d80efe25ba0d4f84e7e9d5e81689a5a6990d34e83e1a62a67371b7d2adc7ecd30ad1ad35359e9d9f8a299b057a2f441e313eb819770fa18cd41572adf856edc4",
+ "e7f66f49f70d506a9b5508cc50f65cf2",
+
+ "899c81ea1162514ea7a2d3487d0efcc4648a3067f891131918d59cc19a266b4f3c955c00ddd95cddedf27b86220c432d6ca548e52cf2011da17fd667a2177a7f93e37b8892d51898f1485277e9e046a48cb8b999fcbcf550db53d40602421a3f76cd070a971e2d869beb80a53b54ac30ac0aab0cd1b696bbaf99bb25216ff199cd9a280f567c44b0d4252c98812e1ddab4e445c414aa8d650598b64d6768a7948093051e36b7051c823c7ed6213743a98d8eaf4b2b5e8157c699ea053cf4e53877",
+ "52173b139c76a744b7a4d2221d4178c4",
+
+ "e50422869373abac1c26e738fb3ccb577b65975a7998ba096b04ef3aa148ada2cbe6beeabcf52d056d1766c245ab999d97445fdb6d59a0d6843eb4959752c89fe07b8411ddcfebef509482b8896bb43de7c875b29da52606b278b8704c62154b2da9bb237e68aa10cb85814250e4e4de73da200991e51241fd9a45f446de5a4bb959ad4727283510e9d2ac8a207ef0284163aa05d27f2d316e8ca1480f30604a8d74a0a661775398af644bb584a1a2c55c4959d0e7dd3f7c0c3614962fbeefeeafe0",
+ "f4c517a82c850c3c4c96d23a8f3106b8",
+
+ "066febbe205ea342cde69fd4c72889442e14a5977d886252bdbc2ff5f8dd8fc5f1f870ce121ab929a6b6227b484648be9b3501443cfdecf8f58d4de834ed1800bb244c18985a8232583ac6fc789aa59d1c5e87ad03994085bbf6e1ba1157d4e4ccbb28a49b6529e54b3b34613d6cc9671855e2dcbba6838176c093737962eaf88c85ab780184d4cae78013b28103dca7f7e3b8d94a6ae0728db30a1c535783c4644a7e9eb4ffac6a95d30cf52ba805e220d0b2aa9a2e7de26a97efbd877ec6d1bad148",
+ "bac7162dc8328911fa639f26ba952ab0",
+
+ "ccf92b17b9cf0d8577c1f3db9c19d3c86f16bab4058611f6aa97204783ebd07671eab55e375c4b16e03780675bb5738369aa7cf3b9156cd250f516392f5e0efa30cbb09132b66457756621f947093029e10233938c846513086023252d1bac9dd3442598f004e0b200f7dd79aa3a9122a0c6e77bc7fc8521988050f3c64b32c620fc1b5bba6f458e4791bdcfca731fd66e9da093b1a45264c8ffa48b3f1628dfe19c9ac1d71f1d5214ddc7e4f0da60ae122f67c394a55645628228d5e3a3174fdccbaab4",
+ "19a9eadf9c7c000fe340603f27bd830b",
+
+ "a37dcfab50a317e6a7cc51524b5d611a53652b59fc7df0229af3dac4d527d54c1134a14b2ed325d9727d07d9c3d0797f1a34561034be6de98b551dc384132235eaedae7a9b97bb7581a2a0f2c4e8e32f3e294f9b30f646dd33ce58187188146e14f01dc3ffb581c3bc834726b66c4732a98c3f8256ed22077ba8b34c024d53fe798517abc2f61eca0c6722fc02254c9141a54d4e106aaa6d4b2957e6a12c88ed00f4c4bc4c223b92579859fc0edb9b53f0bba286c53786198c9b6c6eb5eb5b4490844b7d06",
+ "b9e1455d06233d14b8d3020441351a76",
+
+ "0248b909e1f31ee855a03b6c81366757aa3732d2eca0b06a2b1015584c2d8205a4431fcdb02f6a03077ccf368ecb78b3eb78664b3c7ac157088b6cf9758adda4bc1d2cdedb9a69448a2833cf6f21865795bbd5551be859ed297aa82c288b898e331c07c3c8fcc4b2c4ec90bf8e003a499248a677f1b020357625f079cdf92fcbef89d904e11d23569e0f0e8c52303c93c867023a269bc036d8d36d69ca9c7664daacc92a8dc42c3600dbd4c02278333d216011252271def835ce4783883c0760dbcc00bc33bb",
+ "ea4606777e21f27d4ae860b3c25283b7",
+
+ "ce283768aa91488c75c71ee80a4df9495377b6a9ae3351a5962aa8317f08818a0117cf6c391331866d3abc2beea2fa4a43cf32a08385ea2c03dbabe3319104a6c0a3d171061ebed5a23306a8618a81fb63d9dd4c79b42bfdd2a79e05d78290e653f4c6dfd75bf5625ddb85c82bad9444faba3e1558691c004bb50afe37822e320131361d7572e015e559c0f313b53e0d529dde64e74bc41eb52e77361a3ae5721483a795a80a87d684d63f92e347843eb1a8439fef032b3d5a396b154751bd8ed211a3ae37cbf0",
+ "dca4d5f9f9b7f8011f4c2f547ce42847",
+
+ "19265f48c1ea240990847dc15d8198785d55ea6243ef7012ac903beabbdc2bd60032fb3a9f397d28aebb27d7deb7cf505eb1b36bfc4dbcfa8e1c044490b695b50e0974d3c5f0de748508d12ed9bfce10eaadde8fa128d3c30c12d0d403f60baf0b53d2fd7a38cc55dc1182b096c11d1ec9f171b879a73bd6ef1aa7825bc5162cbeba1d9f0739d1337c8142445ce645e4c32477cdcdf37e99fedb9236e24a3d94f0e45ea0b41a74762efe19d27555cdc89feef5b6e533237603fe98d8deae084f69799deac9043e86",
+ "688e532e15bde53b0b652291edfb7681",
+
+ "1080391fa810c50c7437ec058459d3a8cd23c33071c187474151151c809871b6eaf4cf88f592f84557e1eef5c847d3490912072b25b1919af724c0b5ecb111150bd95460328a0b1ba29613c0bd6486110fe6dfab8cca5fde18f5b0bc4d2dc970781511d2e45fc7385c3da18eeb18b3a9e68593d82c75bbbcadab2e5a29745f6f3a924e039579f4418dbee186d9cc24b896d96bd990186bdcbd3082b70aee9bb95a36531ecc405ae13d011bd10fe69fe728c8aed73d1d38e5506bf4fa770347f7e0eb6749121cc0be75",
+ "cbf8ee5d477630dac9457a9a0659497d",
+
+ "0a13ad2c7a239b4ba73ea6592ae84ea9",
+ "5feaf99c15f48851943ff9baa6e5055d8377f0dd347aa4dbece51ad3a6d9ce0c01aee9fe2260b80a4673a909b532adcdd1e421c32d6460535b5fe392a58d2634979a5a104d6c470aa3306c400b061db91c463b2848297bca2bc26d1864ba49d7ff949ebca50fbf79a5e63716dc82b600bd52ca7437ed774d169f6bf02e46487956fba2230f34cd2a0485484d",
+
+ NULL
+};
+
+/*
+ * Known-answer test vectors for SHAKE256, from the NIST validation test
+ * suite. Each vector is a pair (input,output).
+ */
+static const char *const KAT_SHAKE256[] = {
+ "389fe2a4eecdab928818c1aa6f14fabd41b8ff1a246247b05b1b4672171ce1008f922683529f3ad8dca192f268b66679068063b7ed25a1b5129ad4a1fa22c673cc1105d1aad6d82f4138783a9fe07d77451897277ed27e6fefec2cb56eb2494d18a5e7559d7b6fdddf66db4cbc9926fe270901327e70c8241798b4761dd652d49ad434d8d4",
+ "50717d9da0d528c3da799a3307ec74fc086a7d45acfb157774ac28e01ecc74f7",
+
+ "719effd45ed3a8394bf6c49b43f35879176a598601bd6f598867f966a38f512d21dc51b1488c162cbdc00301a41a09f2078a26937c652cfe02b8c4c92ddbb23583495ba825ae845eb2425c5b6856bda48c2cafae0c0c2e1764942d94be50da2b5d8b24a23b647a37f124d691d8cefbf76ef8fbc0fbdafb0a74a53aaf9f165075784ab485d4d4",
+ "6881babbb48e9eea72eeb3524db56e4efc323f3350b6be3cdb1f9c6826e359da",
+
+ "362f1eb00b37a9613b1ae82b90452579d42f8b1f9ede95f86badc6cdf04c9b79af08be4bc94d7cac136979026b92a2d44d2b642ea1431b47d75fce61367919f171486a007cc271d19de0d1c4c6a11c7a2251fe3aee0bb8938a7dd043d0eb0758a4768c95cc9f6f1703075839487879b47c29c10b2c3e5326ac8f363c65aa4ef76f1b8bd363eb60",
+ "c6ce60c1852ea780ed845aac4ca6a30e09f5c0064c9675865178717cfeb1dc97",
+
+ "d8f12b97f81d47aebbfb7314ff04172cf2be71c3778e238bcccdeecb691fbd542b00e5b7b1a0abb507f107f781fea700ea7e375fdea9e029754a0ea62216774bda3c59e8783d022360fe9625621c0d93e27f7bc03632942150716f019d048a752ccc0f93139c55df0f4aaa066a0550cf22e8c54e47d0475ba56b9842a392ffbc6bd98f1e4b64abd1",
+ "e2e1c432dd07c2ee89a78f31211c92eeb5306c4fa4db93c4e5cd43080d6079e4",
+
+ "a10d05d7e51e75dc150f640ec4722837220b86df2a3580ca1c826ec22ea250977e8663634cc4f212663e6f22e3ffc2a81465e194b885a1356fcbcc0072e1738d80d285e21c70a1f4f5f3296ba6e298a69f3715ff63be4850f5be6cb68cdba5948e3b94dbbce82989aa75b97073e55139aac849a894a71c2294a2776ce6588fb59007b8d796f434da6e",
+ "02f17bf86dc7b7f9c3fb96e4b3a10ca574cd0f8dedda50f3dda8008ce9e8fec9",
+
+ "152009657b680243c03af091d05cce6d1e0c3220a1f178ae1c521daba386694f5bab51cd819b9be1ae1c43a859571eb59d8cbd613c039462e5465ba0b28db544f57a10113406ccf772bc9fe5b02538e0b483225209c1eca447ab870e955befae6bf30dd89d92ddae9580ccf0dfac6415ec592a9a0f14c79acce9679f52d65fb8468012cbc225152d9ed2",
+ "b341f4114eee547eddeb2e7363b11d1e31d5e1eb5c18ea702b9d96b404938bad",
+
+ "eaf4249b5347c2395104a96d39fbf5322c9af2f8ec6a8c45efdc06a2b246efb5502952ab53b52ed9ca8f25a29cd1789b1b5333eddc29a5fbc76c13456a3eae8c9208c1381d062ff60a061da5d26cec73fb7a6a43eace4953f92cd01bc97ed078da19da095842afd938f1f83f84d53703f397fec2bd635f94ada5a3eb78103ebf4de503e8ad7295cb7dd91e",
+ "d14c7422c0832687786f1722f69c81fbe25b5889886bf85c7c7271bf7575517b",
+
+ "a03e55ee76150a6498634099ae418184228320bc838dbfe8276913761516ec9021226f4b597ba622a0823ca499618169c79eb44af2f182d1cc53caefd458a3ed7bbea0a5854653f2b3c20f659f70f23ae786238a8d0e59c29ef49d53125e50abf43b6f65c31f16bc174e43468717dddfcb63f5e21e8d4ba0e674140a97cffab1d5c165f1d9aef968154c60ad",
+ "fa889888d3b984c1577fe7c38ca86f0df859291502fe0b2f6e82c778babff377",
+
+ "2fb4178a0af42b155a739e2910b004e0781c1bca697ca479bf8e71430aefc043883cc7a151779013d2ad07a47cd652b5bdfd604130a1c565115ac51ff3c0ae56b5886c1ab2f0572e385e4fc33c430b874b46aedec49f9b6f45c08be3633bdde99ee02d7e9325276b74cc9d0fb6bfd85e093f2c2a8d3dcfa24308ec18c229f2072b8b32545ee0a9d46e3f1a0f53",
+ "254a115343d0ebd865e5d3ff6c61c3f9b65fe96ea92865a5681b1f1f0d1b00e9",
+
+ "dd344dd531f415a590a9c1838f242af8605bc0c29c1a71283ff5cd8af581683c94c48095e9e9e042b73804e0fd467ecb78699930696f3b6a9890108b99a0e4384e8a51bbadf99b53c358d8cef9fd545a97a13399861458f35a2e86309009c546136d086f058c0c7fbdf083750cb17250c5ebd8247c6f906c8db978a26123d30dec58ecdb7a0afd6face84efcbdca",
+ "2d56bef53fde76ef9849f97be2ed22d3c3d10f23b049eca2a8aba0d1fec33119",
+
+ "353111e447fee6f0bd05d562f30626ab9fb06384a620c49034a5eb3c0bc6d1eb1b86015053e6041ab8ac1cd7b4633512b0a318bfe592e2da6eabb44aa2bead0ba238158c2ea5db56bd7342efccf9d7fe76b8a6af45e0ad594816915f65749054f1d1b7627e4355ecf4e3af72e4d0f5b51877751c6f110f57e86ce942fcef640c31d94e98ecc959238683cb28a3f178",
+ "11b27034db724b46882a3086815a835947d19322885e08595be271c511ef783d",
+
+ "c4e5a5afa1c7d2edd5a21db8b4891ed53c926131f82c69d323b3f410114281fecbc9102bfa5f298e06d91fbd7e9b9661bbae43e7c013f3796557cf2db568de7c94a7cbf5a53ee9326ab4740cadbf1a0b1f59b92040156b977eb4c047a1f34a0c66a85f776a0d1ac34a5ca30b099cb0bbb2ba4c453edbd815b7f14fc69e8cce968bf453171374c428eef8342459db6359",
+ "f1ebe75725c26b82ffb59c5a577edaa2f24e49c9070cb9ca007e65938f33dae4",
+
+ "3b79da982ac5f2a0646374472826361c9d2d2e481414db678e67e0967e5cf3cdd0c1f570293362207191ecd78fb063347350d8135a4f02614d1de12feb70a0046939c078d7d673fea589460265290334d217d6231274ae0d3891e6f50da725f710c983d9bb16ede20833caef34f9dec3c36a6f9fc4eaa71256ac3a136b6a494dcc5985ba5e5c9773a377c0c78387bc8a4d",
+ "1fc7c4802141e2db7a9199c747d885a72d8f068262863843c9f4cbb19db38994",
+
+ "cf9552db2edd8947fd7fbbb2f7189a578343e742891ae6fb85fa0f64da8706e468f0cdc5607539db5726a2679aeddf3ac2ce711e886eff71dad203132e6ac283164e814414c7f686b011fd02c95f8c262920e9725c811a22c1339e0de16e5acd0036d620f2dda98e30c9324c2b778961e0c0b507ad5b205463a448199c9bb60b4f303420a1be3b3cfed5ab0d693cbe331036",
+ "b51adb0c2375c9d302ba61859040fa4bfa0091275eec1053fc13950aae706c25",
+
+ "4ebc9225da5f168c07ef62f621d742cd7c71bbd063269f5e51d65ef164791fe90e070f8b0e96f9499ec21843ee52290fd219c3b5b719ebfedcefe4efbf6b4490d57e4df27d59796f37d35734110b96fd634f5f20bc3de9cd1c28479464be84270ae7f16211f0be8839e8c8d0734ab22097dd371859d9be527a4b2fe83bba0637170ba6e3b1a2ef1c0cca121ffa57a4ffd78af2",
+ "54a3fd90ae00dfc77644ca16b4964c3b32a4641c5305704ee25d9f8fdbfb5c7f",
+
+ "a83f74dcbb48d679db402433020e33dacfa2c37f1e39b2d9dcdc70e81a2ab3d75f586c274376f90a39f49c0dad642cfa4f810afdae7157050847646d60cc6adcd27f7c6a24dab9049dd7c6111ab37c555ef2dd16aaa34d7e8de5ff41feaaad80a8bb8cec85fd7f2eaef28a8772828ab3a5fc24143a58fc0c15bf27ab1a4de28a8a1584f68f65b151154cd1b6dc5ac0dccba7c73d",
+ "5d084841c35b1cd9c43082746960ff5bb2d3de78f9bfdd80dc9ca4f5eae2a66d",
+
+ "734f872c431ab145706b7517e496a3be98bca885fca0105a99b54980f47caa84b60cb3720bf29748483cf7abd0d1f1d9380459dfa968460c86e5d1a54f0b19dac6a78bf9509460e29dd466bb8bdf04e5483b782eb74d6448166f897add43d295e946942ad9a814fab95b4aaede6ae4c8108c8edaeff971f58f7cf96566c9dc9b6812586b70d5bc78e2f829ec8e179a6cd81d224b16",
+ "14ec5a3c2ad919aa0f0492f206710347e742e7a58d6fdfd4b2c93dc2183b7b6f",
+
+ "10112498600da6e925d54d3e8cb0cdc90d0488b243d404b9fb879d1c8beb77bb6579b77aebdbf3e785abe61df17e69e8db219f29ae226f7ca9923719350abef876ec6b3920ebb5c28ccedb2a0b70d5d67a0c8a6116b74341922e60a867d24aa96cf1a89ca647d6c361c5922e7f91f9db114db322249c6a50dde28093c94c01166e11d66c26f73c322d1875f0f8e6bd41c86d803480d8",
+ "c9a88a3f221a857cc994a858f7cb4567979ada7834a265278e55de04c1fe496a",
+
+ "6969a27ad5d0aae6479b2b044bb4b043642375ff503ccb538e17be2f1e41f6aa88b1db991ffefd6087cfb20875920192b671be8b7381f7e1b33d8ff5213429f110fe475cbc74b3ecd2211f9b33f308fcf536e0d0abc36bd5e7756adefddd7728093730ec339c97313179b9e40e3f8e2a2a5c21f5836bf0d632a7961239a6a7f77b44dc700cdd70d8abbfc90c8dde5bc45dcaca2380df4e",
+ "bcdec7a8776380df27a4613cb50b7221995d3f752fa55691798ac2dfa0b15599",
+
+ "163cf8e89b260a81a3d6e4787587a304b35eab8b84faebcef14c626290a9e15f601d135cf503bc9ad5d23e7f213a6146787053f618c6ee90467e3a8df1e03387928acc375608339f7fa45788077fa82f87e11d3c58ce7cf3f8dad6aeaf3e508b722a2a62075df9fa6af4377c707ffe27aa5a11468c3b1c5fce073dae13eac2d1c9a635c5502b96115e69e741a262ee96a78336fcfc34573c",
+ "181d10fa5a58ca57077be52eda53910135087312ca7711084e4a5213c81cb4a2",
+
+ "3a023141ab4db8b08c5cb6792ad97abdf0116d512ea8f4141a8b987f1527657d2fd98f7deca55cc6492a3d0bfad53e40f656a1ac3550c63eb8554f24cb11819a87c5ec009af84e304b69b50eb847e46162a4f8e1ec284b902002994e332461a84ab08ef23cad57959aff64a9ed9632c73ee5b818dc964bb2597cbf25d6c9cf508081be7a5b2e3f9e3fd69305202af11a92002a7b8b038d4c6b",
+ "b75b698857675f8aff2b482ac437925af3ea86198484cbc87b60e6dacb13e7e8",
+
+ "2fd7ed70c6946b11c819775fd45bc0924c02e131ab6d4a3618f67e6d3b77801d4f0d87ea781bf9fa57929757dc70f5945c872eb4e480d547cc1f2fd68fc99f81da4361e7e2bc7b46fb0ef1e3674139ad6b50ee1da830c960a90fccb8b9dac020f701e22fac7eda3edb14eccd1ad47223a1e68a35a1860cc9d74dbfdb60b2cc40cfd072897d6afc2a202cf0dc9f338a3f25d068c4758987ca7d61",
+ "85c9275ec610ffbcd7f785c0ad24b7700b32ee352e6720f1ea2305bdb7f45277",
+
+ "cecb838187223873bab25205a54dadb1ab5a633958cbef3aa04f930467c8f7a947ff12548d964ddc843fe699f72c9377f1c76948c7a2fb5f58b1c65a94b7cd3f3bfe80cbe74be2064d11eb1bc0e52b67f732b1d00f2e2b58d30c4ff13c7479943430958d9f283f199c9029320860bdaa450404773955c74e99c9f47367e642cfb9fd1843bd14ac3cfa246887d885916763a62ae54c011668304e7e",
+ "3a5dd05e009e7f985a2668885dd0ea30c5502a1b5c575db6a4c1149c2e6229c1",
+
+ "283dfdb2e1dc081e3c2b377ba5bc6491cc4af08c40fbfa5e3fe2d45fcdc8b736032cb5fdaa88f0a008d60a86fa53dc7443836bae2475175f2d48163a52ee216241306d87f3f2dd5281b976043a6a135af2555ab39c71ee741ce9e6ac56d87ff48b510d9ae5a338fe50db643b8c8a710a80c8a5e4d278e667b4ce2dfb010f37b588987e7ca822676a1d44bd7419395e4e96e43489eb1167ff9efed170",
+ "5643c4252210fd45a2a67cd0a97d37e80d1b4a3c2fc86b0c3a3b4d3c1723b9ec",
+
+ "f32d2e50e8d5df7ce59a9d60255a19f48bffe790e3b1e0ba6b4bc53d920b257bff8d8003d5faac66367d784706f690b2f1f3a0afafdcbc16866d00a41169734f418d31d7a1c3ca9ede99e5b986f1294710fa5d011d5fcd13fdbef02b755b49cfbf168bf3d39a00cbe5d82bde2fb4ad5cf0fd65b1b5a3db5ad724dff745486da2830ed480f3e61795542094dd88a5e3989ae501e5ff10ae921c89133309",
+ "1ead94e30440b647d4cb4d7b3ed6b87ac07e8d72b3e5f28352bf14a78232ff1d",
+
+ "8bbc18eab6bcd9a3d6b90ec56d3be949e02a8866d69c7808e1ec787e600c7f72a41c001f513b6cbe079df94142dda2447f956e41a12df60392f0215d2d65331b5cdc06397d4796530b4bc45d7a975394627537b4e09e0f6c3a53f00fc1a9648cfc25b2a00288604a28ecf780dc100620d1f169295d9acb2b1f3c6afce4811aadcb1e8dbca8a8d18ba7a81a1132f1c2d014318e07dec7332889d4198c5e95",
+ "429f15c653f92734bfe4d1749e84da8c28861b70c5158bf59809ece810221774",
+
+ "a3d0eecfeff88df1cdd1e86df7bd2ec3ba60bcedfc9c42ef7dc021b05dfc1808df19201a6c6694e4dbf69514ef08ad1d21c7b28ba034ee9397607cefaedef5e9d3784db53a21f703a22b50d5dbba3a8e8579074c1a8b9a782fc5c89cf61a047408563c476110fe77acd9df58c2ba1d3e6dde83da718b8dc6cd57cd5e3e988dd2051cb679ea1af16881690b44acf09e54615eeedaad1b11a4f97e53de8d40d8",
+ "afccfd3b18f6d292d2e125884b721b3e3099c4dac8aef05ab0fba26799043d02",
+
+ "2ecb657808b29574b020545fb7f94071406047ef4de20c003cf08cbd91930187f55b079d7f99fded33cdae2bc8623021af990d4650c4a19197b4c38faf74a8b40d3803efb1907180a8e1150ed6167ff4f293d3ddd26a2790e9d22c0d0ed511d87e48a4952500bbd51943d230687df5941334e1dc5a3e66a43a320f5c351c059c517531b76352a1938ddb2db806ff5aa619667e6c71a7257693bcb4a7acb34ca8",
+ "c994acd17e08e8efd3ba83915245781e3727bac445672c44e6335e4f7deaf90b",
+
+ "e649888592d192c5fb59f10560f5f5a7b0ac21739c35dd80f1fe6b5825731c572f7cc4549c476b84e049459aea7fe533fbfaad72b79a89e77d1addb6f44cbbf5e6a65a5552fec305bc92ced3c84b4d95074387c71184e875d413f65c2b2d874cb3d031d0da7d0311383d72f823e296937d8f97bad17a62f29ef1a091f39be8233c01330d5c4c9170fc501b5022ca29f605e6c59220055f2585bcc29e742046432c",
+ "88a9aa4b4ffac981d1ef0e8b233cb309695f89211cd4e94d50760909e3cb919c",
+
+ "816b0bffd99b0f7821e6093ef152723a9cb45f7a082ef8d6bdf72cd33b5aa3c79102f43e2b74199decdd20057d0e227ae4c57945582e2e9653a9b16eeacecdbc5aaedac7e35c35cbd9adede7f83bbf36f8b0453d61416a85a17821885b3757d203fa2560a85c4b4c10dddaac0ae230b700fd2929cc6f94e9ccebe4e9399d284eb46b3ed2227b4366baf54d1b5c0a5d4225358fd240c0940bff8b62592a092a7b978b",
+ "c593f3d663c48426ce892f22584d49a3335cce3456194b7b5ee4814fab477fcb",
+
+ "a10918880cf31a8551af80bcb0d1a6ed71ca42c71e533967ef0fb71c866b7e6ddcca7e5d7cdfa6edef59fbe377c6e7ca00b1d33a530ef8598dd971a2cff995e5386a858f109b012c4615802a1d5e7fe0221d19cf617ed827d8d8cb8d2c8ed81b9b3354a832f1d14a402b371a0a611737c0543b0eb06b82d8ba56eb6304f1ef16ef6b143049a7bf50c4e2493aa69756d8c39f627fa89d9d741a99f9afbfeb81de1a5bec",
+ "d557aed03eb7c4c4c8091efdee992c9ad7f8d2e79e9296b40a08acae37868d48",
+
+ "de7ba70e45c879ad6c90ada6fda071c2b692840f7893eeca9b69ef8285b4357b7b735151b6cb6cddba04365ce3d520ce41e1cb9da681c07ffcc4619ddcb420f55ddbeefd2a06f689d8498cee7643606865a3f8b96aeb5d1301751438f4b34fe02dba655bc80280776d6795a4dd749a56cae1f3abec5a2d4e5183ee9bf5382c0492199eb3b946707022673bc641f0346119a3a4bb555698f895f6d90e06cc1e2835ff814d",
+ "06cfdd9cd7ce04abcdbf3121a9ba379505dbbb52f148c9d28ad9b50facf573ab",
+
+ "6e9a5752ff8ae7c385b088e651ef2543daae1624562052f787c9e0f5d83e8f01a82ce7d3e69b5f55de74d14d52412a3dcd356687346cbcd59e7315b8650bc3907e2a70ab054354b11cc7ac3ff6ec67d22fad22e75f125660eeb1d02a2a75621d969ed92385092e9de8b20102657742c9a91f328afe9a8a60208af9914c03d4719b8f0a838e7656e2ea3cb8dfc66a25ece2927eb93a8dbf9cdb077936f63e82543306ea1347",
+ "cb1e8082bb94629f162f20d815bcf3b212007bc049951a29ddb18a1f556bf3d1",
+
+ "b05007119789d382fa750d2087dde79b37a5459c24522b649ac976b07059cbdf99fcce56f6da94246e0f5ae241ae77dd99068f7863240acb5c99c4906f7d06403eb3b679ff6fcaa389f602d3aea5d7efcc35af149f3d523459f8a104f5498615c8fc2740594f5f4872b16ebb77c9ef19f7ba0b3881a6ede7b97175d2aac731a65e608975ac82395b52c805624423a7a3431e0daeb066c12ca389a9c338fef03a296644dea211",
+ "9021fefc1a020cd0c579e3dd67a66dacfabedde9cd36ddfc7d5c5c7c47be2721",
+
+ "a19909e14ddf9b3c470df6bb604604ad767c38c83b2b747937472b791173c3a10a733dffcae417295f2a71d183ab709a1d3be02a0bd61d811f95338967db44eeb2cf2a2f4f105ef618a418a5b031b831086f653328ddf43c2cb30b698c188638a196199a65cb374a7b61335c6f40a6193e01100a19a6c2536689fb4308935128e0ae5268937d6ccd8e4a0a21484000fbc7da29d8669b4e6dd5004a3c61b36c6676011dc0628ec3",
+ "7dcbf4dd9c27fd8340f51c553898502cec53d3bc83198352fc58465625c076a2",
+
+ "b0dffe4a5f64f612359397e4e070a8fa01296c1d8cee25177104d76a7c154e4279cb62a99d9d7afa21e84f983041f3df030a115b4b437638cfa3d0fa56e7b66fc76be9e18ff7da8f43db6c5f863efacd2eb39c27a20da6fc867572d29bb96017e0e71a5afe1b1dbbe29575a0ac0ec7aac84c95e85af5be4ae0a14458133252230d687e7cb1b04b65483df2c5685a62601aff85053ba2c509234fcff585fb967c96169bb0725f6d75",
+ "8e7023d18902a9184a0191f1c7a2b79030e833800baeeb33e2d0673500245dfa",
+
+ "dda3625c78f733c7df0b5f4987cd30d7207afa40ca07f3b686c0458aea2f62371a3f98a2f3a1e5a0896f0cb9d40fe82ca65b0132e0fe5d87e621992750483855e3763ae2bf98f0acd9201065acf105962c7b88e3fc277490e0f5d6447563440d209271a544a4fef4b86892d578392c1d9a23b8da8448e1d85d82276ac14a3166b9d96472ea8cb47e0c8dba929eb007cad89bb99fe22a4c674312b21f9cc4a56996943cd1191abc54bf",
+ "ad83957a387225aad811b0737f582dbe7eb616187a8ba8e09b00db5d0bee4a7b",
+
+ "5cd623be5b6bf6d1bcb414c826d0f4ce60793791b6d82dae9f9e9b699e50bba266e2850541882d80b2c9edfa59d504421818ff45740f37853e5b9bc67214af0a5f5fd5c00843cc39cbb8765b4001de99643c7923f738ac5922868f865dd3f1cb90759c597843d9e34daa3754a2fd89bd8c0d2e9106fa95149448ff11273587cb414a603759315f6881c6b94b46700d94d8b2a5f86bfdf99ddcc974cf98e47bf4ba09acc273b463afaf35",
+ "f754a71e3439760aec2d763751e160d05d3de0809dd4fd6aeef588da8b86a517",
+
+ "42c0a452e83840ae858c094c044961d5f2195ddb34a21cd1f5ab575be3803ac99b9872dd617688d515cd6da562e756853947c9ab7e8ef85a019b4f1baff6494b0a6f87d5d602234115fe42ee3667e89b8a98112cf72cfdabf01fcb8ea4314938768b0bc2aea5bafa6e67aface78fc021cc525ae60746d1ceac7ff33a2bf8e398c935252a5127f5090650dd69dd28861ee9becf6017a21ccb1b03f0a9aa15bf74eab5fd9727507b75c701f3",
+ "d5980482d666dde4f2c3a99b45e523fd6410be999a96ba8c5df397c950605e70",
+
+ "fece673103322483b85340e991e478c2c15e2d795a98adb5b697b4cf17a733898aaa4ffd11b1add300c9edb7a818740a33286fd8cf82140b0f7f2bde8d5bce94d58b6d697e5015c99a8df1c051d611b2c8c96a4c48a11eba9c08fe1aba2d4d31a617c75d9439e2cb4d4654ead346d52048ea26bb0c1c522a26db346de54639cac6f668c299919f43e09c1f1f78914abd7b32ac0f641c39c3749fd5be55cd1ac6fed1557ed683d1981c395946",
+ "17f4b2f60cb364da5e8a62db58e07eb1c44b888c433adc1e62461879cd271463",
+
+ "a542b2bdf8e04ec2a004cccd2f89e7bfd17ace1ad285c91360ac20e9913e3976a806000494c28b61b9d7ff36f342ad94d8d281d03e949d91fe8f4127f7b2ee1e550bcb13133a47c7be2400727cece45a4e1f95a3922e1269cc22950ca58bb7cb34b9da957d2fc81b3755982ad36dd238b9c8d33dd53a72c452cbe341a5afdca5ce79f730da8b5886add18f06feafbf57a33700430fa003c919f3f56dff08a5d3aab1e88c33353d30a700adad07",
+ "50cf700b5b6c802e20da4c1f9b75bd0a6632678212bd0e2418201f3a10389994",
+
+ "8fa67f49db80f22bc267a70e5636dfbc8a21c83d9691fe4b9c3051068b3fc9e94430e7fdfb712e4ce086e299ff5a104e65d7ceb685b4c46cda8eeb14cd3b9548d85baed5ec2f412810af3d034cd67a75c541f70829f8663c4d8cea3415621fb0954e5b3b756333a69a0a41b402522517f087ca9b4a06eba23f4fd5d02c5c6e07c132769660b50dadc5c07515ec751a1d2fd2cfd8b0855b85f602344fdbd28a37a52e874e73ccd627dbf9628cd1e8",
+ "3379265620eb781d6b59e331cc525e60e8c063e19f96cfabb2fda9aa83cdeba5",
+
+ "23ae9cd31da25c0187c0247be19e089872742d772f73d0efde5889c97b40d12ddbbec35b8f2b1f9c0b3d947708db3f2726306f4dd6ffabe37736f671bfc551835db0825adc6314e2cb479fe41b92497dc8638dcfbc0e3bf6f0b4c03dd418a892f1ad6138ccf442bc0e04cb2ae36a2f80a0340f63a849891190fc719781e0de44dedde95d2783b1121e9fa3b1280cf81af5cc7e7363579c1da03390e68fc5fc806e67a132b5bb6acd413eace2b120ac",
+ "a17a00ac106c0af50c4f449d3cdcc2cdbb9848d2d85a36ff434099162e25606c",
+
+ "3bfa57a5f9f60203059defd501977628908ee42116e4674dc0a52a32c5bac02aeb60c6714cd9c47c5a61558c21648884ccee85f76b637486f3709a698641c54bf5f5eb5b844f0ea0edae628ca73fb2d567710080e8a96c3fe83857fc738ac7b6639f0d8c28bfa617c56a60fd1b8fbdc36afe9ce3151e161fa5e3a71411fb8e123d48762bc093558aea7f950706bb72f8dc7ca3497a2b3ccf345ad3d9eafde10889d76c61d432e3a165d34ad0ee2d9619",
+ "1a2cfebf3483c33a5eba84121737d892cf8bd6c3ba324fd4ae4c2db42872e54f",
+
+ "e9b9525afd5634cf8d16df4ae7e12e8ae206c6ed6e7d4dd96f6fd75accf7a10cc22b023c7f569e4aec88dd51ca519c0a00c922ee33d3559b98a32d79067e6a9d50c182eed125de864841455be751991ea635c163ddbde6031223e2be0fd9f5253885bab81c4b5a4b4a4a00ae66698d8c7c538c9493c068d786f7dc710f90ac6c257f93e1884e7c609aaaf5927021e01d292a6bc87e6643e09b2505da2d2cf639bdb6f3b33cb8ab8fdf690b512d02fa9956",
+ "3ff47b4bf4f908aace95b0468a54b7e6644fe07df69ae327c0ff2e45325b97b9",
+
+ "13ec10c6b27a6ce6fdd5e2314e8626a28a69f313ec62f29b044cde1aff32e61228c252b9affe6a4ca93593a55932bc10aeb3f85b0c1d6c2c506d6c970e72e1f01c3aeede55cad3b1971111f60e1fcf48b5937c691952b691617f6a058ba73decf83b2b5e2b446ebfce52a24bf5b526f1a7f0c5659b6b96713f68208cfe38c2adc3af5361b9d5051c56de8fcc975d8bb48db41c7818cfd574f312d652f08f38dc857dac0e88e55e70379f20a37b7dc4396ec6",
+ "9703a69f279ef15b843b355f86b3f7098a46eafcad625920d93e0e3fb136fc5f",
+
+ "3d8263a177af8c5beabc76a4388e0816ab1bf1f5856e985791f15688feebe4ac6d480fa64999b339575be66d8e7c7435281b8c4ef990b86a00ac128e3c41b6b9c0e573c60af4c69391d408639d7de6815b38122731a6389d4f0534a587af82175ee3f5c963c8acb1bfaf434e0e9946436df9eb46d4bb0038a7842295873c300f6ecaff76fb1e4fdb0a75fef588d87cc486e67f738bd4f8832fb24526e5f0a8e91920f8967bfd96599aada321b4437049cc8836",
+ "e82d636a61c7657029699374a2da3dfabfae366e7708c7e4ba2dacd8b786a36f",
+
+ "01f793fa05548645f644a64ee1b5ff7fd38eaa233f874cd59f3ddf385e86b5e9f601b9b256f2f901864d61988d11c98593d7335543ab4d85731a3e39078c9e3012d5c6f83f064b5e7089c529a46dd5081efe66c8c49932cac5be88b57e674d689f98423389388446fb1f5969ee7029eebd29cbe489f8038edc5148148cbdca77e375b3cafc2fada07038a5c133c3cf21b881eb125c71c6b801fa03bdf9371b472792a3276094ce5417fb32973a0dcf87572d4db8",
+ "98bf0fd777137c94300ab5b1bff7b3f487a03a788e6bb96c715ba6f10ba1922b",
+
+ "71a986d2f662bf36dcbadbba0657f4e2797b569610e2d82271ee6d813f01f6db922a5a4ca405d9e7cddc9dfbb1129294b8c27845bea337250c2f721887045e50288ad513acd6a6be8dce300a308e2f8e600bd585fbf61dd2ebe45c4158ab18101c0f1eae789ecfc205d8bb6fed9371d65a9e94dd2fa5322ff75452851abfcc2357025ea56e24fbfb1d4266b34ee900768fc3dfd6c2761f4716c97d6a36092192c0abbc81f832d372be535b5dbd578576e6c2dbf61d",
+ "27255d504a38296857b8d382dc8ad4f1ca03ef3a8d1983e54bc01ef97b04e581",
+
+ "69ee06f5f53f74c76674751f8fa80efb42f43e71132ae0fc5ec6d2148c21570191e8baf0b9cd3547a57c103690d10d8ed84804d7b9b5cb9d5b35580a0f642abad5d0e5ca23ae3c32e1cc1355b8c7e5d78c7e64af47c6607dd960ea1d7d28b97c3d8ecdaab84a5131234cc6a68ef25e7d687ea62146c76845e02fd0745cd4cdf0d00bbab9020a3eec72e4714e9abb4029743012573d1fac9c798a513937d22ebd962df61f8854ca0ad67c5b7864885282b77df076b436",
+ "600b41954a9398ee66ea0e603c8c80d936fbc8be98c74f44ae13b0aa4b50b8d5",
+
+ "2a74e9800ce49aac07af3df2e451f245d4ffa5304c318574135eb7f39a064bcc8bf66fc8a4c8e2f5c6a9ac90495f0d28938ab301e9292fb78461aa23e87ad482712b1ed42f172983f4977e45aaba7f43ea8a9e7bcb91cc63f89c34cf06bf2a1404995e6e53d9569fb8011bd9af6b32de0289cd669b7043c19698bebd9bdd33ca6bca985cb81751913a70eb14ff790c41030eaa8a00cf7c1987dcaeb650ddd9eccf46326707d902a1a36c56be43ecf7b414a29caea3b55f",
+ "4e549f206099a8b3183fa3b86af220b1b6554ac3d8d52c54d093e68f60597256",
+
+ "5b2e2f2fd3ecc733a6198d34e5d143c176b60c3cc3dac6deafdf99fbce5cd088d583e8da4f01e7b09226f074f24613be345f691a46fb610b2d5855503ec761659152744db3a1a78f9b1fce7fdf584dbe28a52e04e40c701d3a62a13243b2af4a77e3fb106594afd7a84b52db16cf99ca3ad2808305d39a1dc043a52b45e7623e6f7da4accfa2a690a0f3a112fd739ee9522d891e111a8812a6448bc2ac2c234a616997a8579335c36d5fe6acfe0b052358fd715d70a7e104",
+ "24a3de94be98126ce95cfd3140754230b6880c71cfe4ec215c3f451bdc8bb690",
+
+ "013944b7958b6b3686b14bdb042f2f5b42768edc20fdd6a90894692b15f6e5157b9da9de23da95749524102f1bb150032343d6fbe64537e247162243fea59f95f53e95aff2a38f82775fbf06e7574475e9a2a8b8119aad1ebe3349543e8cef9239c410124c0fe2c6f409604aae4a92185c3a0efbeb26bfc63394e5451ed45d740dd823ef774615aad3caf9e2b9b1c25344b40facba11f5406fe1fefee6a571a33a22d42ebc6fb094de4c94b650b55c9068b7b3b3c783d7f53a",
+ "009661924d01ad811d4c598580eb954362b8554c5e9cd13686acbe41ac8c3940",
+
+ "72c2880163482bbe822cf72ff0e02be7081d271b366fd94c0cf37926925f76a9de44b086e590e7cc915773c314d336187ba9d03b866d1106b769b49fa99a4a9fa3fc74746d085504627a4792c757cde65b2fcaa82f9ff00eb81b7ab723ea1ed6e8723d92a2b65ead1e1dda64b275d897d0377c2ada0d5cab38913435a958da94d62f74a92da4e810ecc994017c344074014a50892fbe3e265f5448e2e2eb662295ba7f81b5dadc76f504dd31ce9debc517efad8cd5ba7fc754eb",
+ "77cf32d62a3d0622cd90f7c858ce1ae3bda60f9edc9cf50f7ecc9d7253d8d18d",
+
+ "c6dad2ff2cba3ed8873955178068b5704cbccf1e8c62eed472d275f726a7670a68ae2d6a763d943b30c616a27aab5a34e254feaf838093e828d8e905b5ca8decc39491fc8b9f8bfa050fe04e5198436f5593789ca8515ecdaeaf2ce905eafb3920b5851d32892cfd4e3d3e83ccd67707eea0c74bc47e56694c7ec609deb0b8d7c739913535a37e2c5377b5a9b40efee6f5a472269eae83a54a6d3dcf08c4ccb000473dac5a9489705be6cf28d1e7e1f2b2c60293008aee6aefa61b",
+ "8708b77ac39005607b179857c037f64860540e80ed7c7a4240e09ae62c88f87e",
+
+ "02553a2117e654ac28d948a6f67a83daf2089a95ff6631ff78131baa755cc36c4ad0ca6a51f5f176ea393a9bbf2b4af54deb12c6a0dfaec75da88dbc0655d34b7ad6fb0ebbb3c1e7f4fe3f94bb865683934d4fe7b53cc20b1016b7e68eab0cf1994e1735de888ba8500ea0b970f16e2acc159a1ec6e435739743e15194c53603af1f640640dd19600653a53368d55c92012b3b935c3fcfa6fc195325a00d192cc5332baa6b1831b81cb3952a2b9be6643a777a70feb5584d477f5489",
+ "376b551c1e8f908d7e1979efa436ab69013d2e85c34430dc826179b4f94480ae",
+
+ "9945c4f0e067b943986b6841b8fd21109e91d2f2549c711a11039abf03d37a6e4b34eba44a98e09c1b38046660c19e39424ab80ab38a805df648ee5c6212a72663322269c1de093325afe205d955ee2acf885146e5417432672ba807d5540c79e729b067cfa1faafbeb84947a91fd98a4d32e7cf712a15406b940feae5026f10e100dec5fb497cbaee3b83545a892701c530c0cddfac2a300a6b6c2a19829992589ff4accd3e57f9be20d65374f99f393e6a2467b82e7da94c9807f2fa",
+ "a4ab2e8f96b69097d84596b628e7bb76f460c001043ce5fa6e379fd29d1eabba",
+
+ "a4d7897eaf5c49979b361c39a67f47e26c2f75e5ffe0645539d4de245138eb8cadaa45aef7fa0c7a732dbbce90c85be2bd4bf6e37dfb4fdebee4d0e0671fc45c3051c6ccb674799bcfda7a431a6e93b3db3e32f30636190a9a2e5620302876e0d4d2f6201353fac4554341df6efb591c6f100f5dc21a2aa176ba592bd7db69e14237bbf2371df6bbb072f9ecb1f714e621c97768d82eea6bf98ebf4a82c005262188ff894a5dd549866f88b00ee82bd99872515d71fac230ccb472c55a60",
+ "9510ff5231813a865918badd0011f05915364165492ef17b85929a63e4951589",
+
+ "22813ee9edc5c2a90d8b3f07b48d9534e60f08312dc296d68fe78719bdb7478d8d037129aa182c4b8ae5bafca1604e76d5251ee43160ba68ddee9c624ebf00f0ba7ff6b1cf75b5cfa4ab323cf04ff13b7a591b23d06ed25f3c04c1baf4c8f7da913cf509c2a5053c4224ce4d0723268cbdf2277672b285c493731ea81799d353fa8497baed70c59a4c99b7b950a39470863a69667ff67c9ec981ddb41ffb3d63dd9d034bb79d9df1a95214083199e4efbd770a7a5f005ef5c877236674b6dd",
+ "44f8a8b05fc643566f1f53a93a122f7902d2cab68bb02267c0479339371a7304",
+
+ "eebfa2629596f61a926c4cd472ecb03eb2ecaf7f7650b12f7d2b8aa755284b7ccb295e46a62dd2a69577f38765ed1ea377bed34972470c5e3538cda310f2fd353334745a66f7557afb969e6c0132fdf4bb55e68951d5e25bc4fc2a9427e574de0d290d263ebc28a0ae11760caf85f63765fa0fc47ac2dc2c14c0c70404c9597f415050339443f2209430a2eed5acb1765df5768457d6a1db0ccbcc7a0e66531eb6f16608d1555c00973b4a9add70d5b88b8e44504fd9da709367627fad840bc5",
+ "9949d3ac3c05b4a08b85fa371811fd3f0b50c71950fef50acbb59c450ab1c587",
+
+ "ddf38f51b732aea3fdf1fe4c756d17961262163d737f407fad17e9724a19959a92425cbb099193ec38fca8edb0614eba4dbfda60b8a6ed102fec547289a22c3b74464a02023ada50647545f6f57959a37a85a4b5a70b2050e66416ad55c33cb50d6820cfaa16caf608c69d0e4a9d7f78211c3ae44b97216659e8f6cdb6640b30e50ea8c90a0bad06ac5678deb9b50962caec6494a930377b11debd77b46de2d382a2a8992902c9aad88d9e0d49a93f88fe5dec6dcbbfacb794b0335558c609c66e",
+ "954473b4965a57c4cbb20e199b8730487eb621f5fd694a1eb1667940da0d6728",
+
+ "184e1b9ccec71f837dca25838db073d51cacc26246fda091a468135d12e67faab69ac9d93e05bd9a687dad01c8db5bddc6751a45e64c2f734c867dd67f1e62626ddadc2baf7df0320f3e4c7e477a2b6f0ca679504b87372bb3a522e173fd8f7945f69ab9ab967ff378f6482293f3a936f82728abff188060e1ae48a778ebd09846d64cacb9b83487ad8bea1433b09ed791e06f7f8a65d2bbdf8a384f1550eb677962392b624bd593b6e77a7daf17d1fddfb995f472d8f5e4b41f3a02d394a98de583",
+ "0a7506e1b6cc43acdb4f2ec456e069e6e4b7608deb70dbe7ccb88578658be9da",
+
+ "c436d19f05550b6979bdc69bfd27ea4cd80c1a60f00a8b093e89178c7f9e8d492c304cf6ad59102bca0e0b23620338c15fc9ecd1e939ae91da16486f72ee1e154d41bfa391e6ba3b6ca9b3c3be39b5e61242ca5cd3d6c96cbd1170af91fdb2160db3522e1bc3b1a349d6e50479920ac5d9bedd8a16a787a3cdc2b6d24392f25555cc2f20b2ba9e6b47ddc96cfbd6df669d874ce21a758d3cf4704362ef7786d90ed67b01bd91299950058885accddbcf44e340ed4807864218653ee7ff7215aa1e1761",
+ "206be726fc681367387ff0a15303533058070f9655438ad8142cf39a0523b2ce",
+
+ "daf7c7526cdb85127df59220fbcb67dc5069ef58dc069a18a2e4ad164178dc0927cb1ae70120b0a975d78c4e1491dc228a95dc401873ec5645e7e6a8d0ffae58e8800be49f87b5f09d6caf4611ebd61bee86bb945325ae884a001b88b6be1a1c87de41503057bc6f5b7ba00fdb217d4de203335a746506371bf8f4bcddfd45df6bad65339bd9efaf18ce0ab1587bf842cfd6ec9c637b1cea1f96184e2b045a28fcb51e96c85574373d2b9335724170821ec58f6108af1929bea430458a1a7f80a2be1580",
+ "742389244ad26d7a16d1f2b01e9c83e987a283bbf3aa2907a556746fe8c98c38",
+
+ "597dadb776945e01c564f17eed4b5c1bbb34eebb13bce37d2d93363efe24b660f3785cc9e557dc2e4ab17a91a83d1f085060acc148508e43897993f66a20fbe65d46d3c4d9cf7e2e97e3952f0195f10ae8c20533753c719f6228d53d69a5e3c5fdafb9b039426d8716c2e961e09af9a8eb24a21b82c9b6192069a51ce3fc96843d7ab696edf9d0c42d151f2e2d95606ac14c2a80563c82392b02ab9abe6e3bab8471747ddc3cd06a46a6de9fd0ce4dd8d202466bdbe00088ebbb8ebfe341fbc2395a986df0",
+ "892985bdf2379f8ae138aac016894ee23408955d627cfa699fa5fa1439340a91",
+
+ "0efc14917a94f5320eb734c2b9e45f659d06c9f5c454deff0e76b30f6ee9e22e56a494a870fcdf138fc5538ce5bacf44761f993ccca4ae4ced8d576a8a10fd2979fe3e8066a641cdc5f746190ae4819e1d0d2886089bcbf6f36be44b5370afa45e523ba0c25bc169969436f1912b1c7b7a189d5edf00da050a5a813b31d09da5ede8b390ede30aeeece64a9ae05749e4758a2149b99d868219a056c18cf972370e07cdd95006c264ae33ab9e6130afdff6a9dbd1fe38747408868c65ccb4d45fa9f9b102528c",
+ "73088e0551c89477bcb675245c5c6347b4230390285832c7d723bf668c8061fb",
+
+ "9ac34ec974d28b18b7bcf6982eac60ebc670b0674e2acd697b49bfeb2fb81159fa5579a1e2a5bb8a5fc6ca46aaa5304a3771b15d804f2bef054fc1ad919e3852befea1c0bb74394f4d408d651412e247107bd32e64a23c9e593857f3a5ae253deea5104d8aa6ce108913881cf55d3c89587860027f8cc81b7eeec9e5f44e9fc190320c71d4a3427519250394d4ed07b9174f9e005b7696117c575fad05e76d86ae8cde5423d25d25076046f4392a0a7e56e8d6517fc66f265c5d617060e258354f9dce1dfe9de6",
+ "17cba68f47a0615b3513d28a44feda6ad36b6e6eb1ead7232f4e2a4e1a64bf50",
+
+ "d00df64c4bb9e2fd16fb6f9ca746d6cf162015ec7326e41a5d51e9b3d0792fed3f17d5bae34f03ec522e229d53304dcef105024ece941edeba410892846b2c7a1039ab82aa9750979a7bc70bf96d093bc3461b6f2d38f801380eccc286b562996cfce06d4a98b245176bc4ae4006f45eb36cc71636185acdfe429c0a7d5fbb927be7dc43685a0f40f185824ed102f57eeafe6d0d943e2d883564e233126f1eac648207ccafe651ce4f5169b35369f3e48f84771aedb2577b04fd0506ecef72305055cacfc4435e38",
+ "67302648e0082254d8d342b4eb8070ef9a44e0fc55c3d9a3f20613e4824aff21",
+
+ "fff5deb2bc7f43bd2db44ceff874e9c3b7c1a2f54cc6889f74186ca2a03d5047006b1b26e0919147379c81887df3403ebe43571fed8279607a2eb81a26d6f8f217dca3f927799ed182017c127069f2eb6f068b0d85979dc4d4867c676f6bedf36cd2def33b3e54a3366ea45478dee612f391a785bd0ede15aba921512103199228d434dbc1e899047a6861183e5b04fb716c11503dee2399261d10a0e5a76317736b0d7b6480573e76791b246ae734ee12203336ac3f539a6e6cb01c625eb3c9741dd199ca0d759753",
+ "bf64c9ab7042245fb2d8054edd699086dbe27a1ce904174d28bc0831ed9acf97",
+
+ "8d8001e2c096f1b88e7c9224a086efd4797fbf74a8033a2d422a2b6b8f6747e4",
+ "2e975f6a8a14f0704d51b13667d8195c219f71e6345696c49fa4b9d08e9225d3d39393425152c97e71dd24601c11abcfa0f12f53c680bd3ae757b8134a9c10d429615869217fdd5885c4db174985703a6d6de94a667eac3023443a8337ae1bc601b76d7d38ec3c34463105f0d3949d78e562a039e4469548b609395de5a4fd43c46ca9fd6ee29ada5efc07d84d553249450dab4a49c483ded250c9338f85cd937ae66bb436f3b4026e859fda1ca571432f3bfc09e7c03ca4d183b741111ca0483d0edabc03feb23b17ee48e844ba2408d9dcfd0139d2e8c7310125aee801c61ab7900d1efc47c078281766f361c5e6111346235e1dc38325666c",
+
+ NULL
+};
+
+static void
+test_SHAKE_KAT(int security_level, const char *const *kat)
+{
+ size_t u;
+
+ for (u = 0; kat[u] != NULL; u += 2) {
+ unsigned char msg[250], out[250], ref[250];
+ size_t msg_len, out_len, v;
+ br_shake_context sc;
+
+ msg_len = hextobin(msg, kat[u]);
+ out_len = hextobin(ref, kat[u + 1]);
+ br_shake_init(&sc, security_level);
+ br_shake_inject(&sc, msg, msg_len);
+ br_shake_flip(&sc);
+ br_shake_produce(&sc, out, out_len);
+ check_equals("KAT 1", out, ref, out_len);
+
+ br_shake_init(&sc, security_level);
+ for (v = 0; v < msg_len; v ++) {
+ br_shake_inject(&sc, msg + v, 1);
+ }
+ br_shake_flip(&sc);
+ br_shake_produce(&sc, out, out_len);
+ check_equals("KAT 2", out, ref, out_len);
+
+ br_shake_init(&sc, security_level);
+ br_shake_inject(&sc, msg, msg_len);
+ br_shake_flip(&sc);
+ for (v = 0; v < out_len; v ++) {
+ unsigned char x;
+
+ br_shake_produce(&sc, &x, 1);
+ if (x != ref[v]) {
+ fprintf(stderr, "KAT 3 (byte %u)\n",
+ (unsigned)v);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ printf(".");
+ fflush(stdout);
+ }
+}
+
+static void
+test_SHAKE_MonteCarlo(int security_level,
+ size_t minoutlen, size_t maxoutlen, const char *smsg, const char *sref)
+{
+ unsigned char out[250], ref[250];
+ size_t len, rlen, outlen, range;
+ int i, j;
+
+ hextobin(out, smsg);
+ outlen = maxoutlen;
+ range = maxoutlen - minoutlen + 1;
+ for (j = 0; j < 100; j ++) {
+ for (i = 1; i < 1001; i ++) {
+ br_shake_context sc;
+
+ len = outlen;
+ br_shake_init(&sc, security_level);
+ br_shake_inject(&sc, out, 16);
+ br_shake_flip(&sc);
+ br_shake_produce(&sc, out, len);
+ if (len < 16) {
+ memset(out + len, 0, 16 - len);
+ }
+ outlen = minoutlen
+ + (br_dec16be(out + len - 2) % range);
+ }
+ printf(".");
+ fflush(stdout);
+ }
+ rlen = hextobin(ref, sref);
+ if (rlen != len) {
+ fprintf(stderr, "MC: bad length (%u vs %u)\n",
+ (unsigned)len, (unsigned)rlen);
+ exit(EXIT_FAILURE);
+ }
+ check_equals("KAT MC", out, ref, len);
+}
+
+static void
+test_SHAKE(void)
+{
+ printf("Test SHAKE: ");
+ fflush(stdout);
+
+ test_SHAKE_KAT(128, KAT_SHAKE128);
+
+ printf(" ");
+ fflush(stdout);
+
+ test_SHAKE_MonteCarlo(128, 16, 140,
+ "c8b310cb97efa3855434998fa81c7674",
+ "4aa371f0099b04a909f9b1680e8b52a21c6510ea2640137d501ffa114bf84717b1f725d64bae4ae5d87a");
+
+ printf(" ");
+ fflush(stdout);
+
+ test_SHAKE_KAT(256, KAT_SHAKE256);
+
+ printf(" ");
+ fflush(stdout);
+
+ test_SHAKE_MonteCarlo(256, 2, 250,
+ "48a0321b3653e4e86446d00f6a036efd",
+ "d4c8c26ded38cca426d8d1c8f8aedb5c543541333839deca8713cfd8684480fe923f57c3a5c89cb61427c220c7");
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+static void
+test_HMAC_DRBG(void)
+{
+ br_hmac_drbg_context ctx;
+ unsigned char seed[42], tmp[30];
+ unsigned char ref1[30], ref2[30], ref3[30];
+ size_t seed_len;
+
+ printf("Test HMAC_DRBG: ");
+ fflush(stdout);
+
+ seed_len = hextobin(seed,
+ "009A4D6792295A7F730FC3F2B49CBC0F62E862272F"
+ "01795EDF0D54DB760F156D0DAC04C0322B3A204224");
+ hextobin(ref1,
+ "9305A46DE7FF8EB107194DEBD3FD48AA"
+ "20D5E7656CBE0EA69D2A8D4E7C67");
+ hextobin(ref2,
+ "C70C78608A3B5BE9289BE90EF6E81A9E"
+ "2C1516D5751D2F75F50033E45F73");
+ hextobin(ref3,
+ "475E80E992140567FCC3A50DAB90FE84"
+ "BCD7BB03638E9C4656A06F37F650");
+ br_hmac_drbg_init(&ctx, &br_sha256_vtable, seed, seed_len);
+ br_hmac_drbg_generate(&ctx, tmp, sizeof tmp);
+ check_equals("KAT HMAC_DRBG 1", tmp, ref1, sizeof tmp);
+ br_hmac_drbg_generate(&ctx, tmp, sizeof tmp);
+ check_equals("KAT HMAC_DRBG 2", tmp, ref2, sizeof tmp);
+ br_hmac_drbg_generate(&ctx, tmp, sizeof tmp);
+ check_equals("KAT HMAC_DRBG 3", tmp, ref3, sizeof tmp);
+
+ memset(&ctx, 0, sizeof ctx);
+ br_hmac_drbg_vtable.init(&ctx.vtable,
+ &br_sha256_vtable, seed, seed_len);
+ ctx.vtable->generate(&ctx.vtable, tmp, sizeof tmp);
+ check_equals("KAT HMAC_DRBG 4", tmp, ref1, sizeof tmp);
+ ctx.vtable->generate(&ctx.vtable, tmp, sizeof tmp);
+ check_equals("KAT HMAC_DRBG 5", tmp, ref2, sizeof tmp);
+ ctx.vtable->generate(&ctx.vtable, tmp, sizeof tmp);
+ check_equals("KAT HMAC_DRBG 6", tmp, ref3, sizeof tmp);
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_AESCTR_DRBG(void)
+{
+ br_aesctr_drbg_context ctx;
+ const br_block_ctr_class *ictr;
+ unsigned char tmp1[64], tmp2[64];
+
+ printf("Test AESCTR_DRBG: ");
+ fflush(stdout);
+
+ ictr = br_aes_x86ni_ctr_get_vtable();
+ if (ictr == NULL) {
+ ictr = br_aes_pwr8_ctr_get_vtable();
+ if (ictr == NULL) {
+#if BR_64
+ ictr = &br_aes_ct64_ctr_vtable;
+#else
+ ictr = &br_aes_ct_ctr_vtable;
+#endif
+ }
+ }
+ br_aesctr_drbg_init(&ctx, ictr, NULL, 0);
+ ctx.vtable->generate(&ctx.vtable, tmp1, sizeof tmp1);
+ ctx.vtable->update(&ctx.vtable, "new seed", 8);
+ ctx.vtable->generate(&ctx.vtable, tmp2, sizeof tmp2);
+
+ if (memcmp(tmp1, tmp2, sizeof tmp1) == 0) {
+ fprintf(stderr, "AESCTR_DRBG failure\n");
+ exit(EXIT_FAILURE);
+ }
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+do_KAT_PRF(br_tls_prf_impl prf,
+ const char *ssecret, const char *label, const char *sseed,
+ const char *sref)
+{
+ unsigned char secret[100], seed[100], ref[500], out[500];
+ size_t secret_len, seed_len, ref_len;
+ br_tls_prf_seed_chunk chunks[2];
+
+ secret_len = hextobin(secret, ssecret);
+ seed_len = hextobin(seed, sseed);
+ ref_len = hextobin(ref, sref);
+
+ chunks[0].data = seed;
+ chunks[0].len = seed_len;
+ prf(out, ref_len, secret, secret_len, label, 1, chunks);
+ check_equals("TLS PRF KAT 1", out, ref, ref_len);
+
+ chunks[0].data = seed;
+ chunks[0].len = seed_len;
+ chunks[1].data = NULL;
+ chunks[1].len = 0;
+ prf(out, ref_len, secret, secret_len, label, 2, chunks);
+ check_equals("TLS PRF KAT 2", out, ref, ref_len);
+
+ chunks[0].data = NULL;
+ chunks[0].len = 0;
+ chunks[1].data = seed;
+ chunks[1].len = seed_len;
+ prf(out, ref_len, secret, secret_len, label, 2, chunks);
+ check_equals("TLS PRF KAT 3", out, ref, ref_len);
+
+ chunks[0].data = seed;
+ chunks[0].len = seed_len >> 1;
+ chunks[1].data = seed + chunks[0].len;
+ chunks[1].len = seed_len - chunks[0].len;
+ prf(out, ref_len, secret, secret_len, label, 2, chunks);
+ check_equals("TLS PRF KAT 4", out, ref, ref_len);
+}
+
+static void
+test_PRF(void)
+{
+ printf("Test TLS PRF: ");
+ fflush(stdout);
+
+ /*
+ * Test vector taken from an email that was on:
+ * http://www.imc.org/ietf-tls/mail-archive/msg01589.html
+ * but no longer exists there; a version archived in 2008
+ * can be found on http://www.archive.org/
+ */
+ do_KAT_PRF(&br_tls10_prf,
+ "abababababababababababababababababababababababababababababababababababababababababababababababab",
+ "PRF Testvector",
+ "cdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcdcd",
+ "d3d4d1e349b5d515044666d51de32bab258cb521b6b053463e354832fd976754443bcf9a296519bc289abcbc1187e4ebd31e602353776c408aafb74cbc85eff69255f9788faa184cbb957a9819d84a5d7eb006eb459d3ae8de9810454b8b2d8f1afbc655a8c9a013");
+
+ /*
+ * Test vectors are taken from:
+ * https://www.ietf.org/mail-archive/web/tls/current/msg03416.html
+ */
+ do_KAT_PRF(&br_tls12_sha256_prf,
+ "9bbe436ba940f017b17652849a71db35",
+ "test label",
+ "a0ba9f936cda311827a6f796ffd5198c",
+ "e3f229ba727be17b8d122620557cd453c2aab21d07c3d495329b52d4e61edb5a6b301791e90d35c9c9a46b4e14baf9af0fa022f7077def17abfd3797c0564bab4fbc91666e9def9b97fce34f796789baa48082d122ee42c5a72e5a5110fff70187347b66");
+ do_KAT_PRF(&br_tls12_sha384_prf,
+ "b80b733d6ceefcdc71566ea48e5567df",
+ "test label",
+ "cd665cf6a8447dd6ff8b27555edb7465",
+ "7b0c18e9ced410ed1804f2cfa34a336a1c14dffb4900bb5fd7942107e81c83cde9ca0faa60be9fe34f82b1233c9146a0e534cb400fed2700884f9dc236f80edd8bfa961144c9e8d792eca722a7b32fc3d416d473ebc2c5fd4abfdad05d9184259b5bf8cd4d90fa0d31e2dec479e4f1a26066f2eea9a69236a3e52655c9e9aee691c8f3a26854308d5eaa3be85e0990703d73e56f");
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+/*
+ * AES known-answer tests. Order: key, plaintext, ciphertext.
+ */
+static const char *const KAT_AES[] = {
+ /*
+ * From FIPS-197.
+ */
+ "000102030405060708090a0b0c0d0e0f",
+ "00112233445566778899aabbccddeeff",
+ "69c4e0d86a7b0430d8cdb78070b4c55a",
+
+ "000102030405060708090a0b0c0d0e0f1011121314151617",
+ "00112233445566778899aabbccddeeff",
+ "dda97ca4864cdfe06eaf70a0ec0d7191",
+
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
+ "00112233445566778899aabbccddeeff",
+ "8ea2b7ca516745bfeafc49904b496089",
+
+ /*
+ * From NIST validation suite (ECBVarTxt128.rsp).
+ */
+ "00000000000000000000000000000000",
+ "80000000000000000000000000000000",
+ "3ad78e726c1ec02b7ebfe92b23d9ec34",
+
+ "00000000000000000000000000000000",
+ "c0000000000000000000000000000000",
+ "aae5939c8efdf2f04e60b9fe7117b2c2",
+
+ "00000000000000000000000000000000",
+ "e0000000000000000000000000000000",
+ "f031d4d74f5dcbf39daaf8ca3af6e527",
+
+ "00000000000000000000000000000000",
+ "f0000000000000000000000000000000",
+ "96d9fd5cc4f07441727df0f33e401a36",
+
+ "00000000000000000000000000000000",
+ "f8000000000000000000000000000000",
+ "30ccdb044646d7e1f3ccea3dca08b8c0",
+
+ "00000000000000000000000000000000",
+ "fc000000000000000000000000000000",
+ "16ae4ce5042a67ee8e177b7c587ecc82",
+
+ "00000000000000000000000000000000",
+ "fe000000000000000000000000000000",
+ "b6da0bb11a23855d9c5cb1b4c6412e0a",
+
+ "00000000000000000000000000000000",
+ "ff000000000000000000000000000000",
+ "db4f1aa530967d6732ce4715eb0ee24b",
+
+ "00000000000000000000000000000000",
+ "ff800000000000000000000000000000",
+ "a81738252621dd180a34f3455b4baa2f",
+
+ "00000000000000000000000000000000",
+ "ffc00000000000000000000000000000",
+ "77e2b508db7fd89234caf7939ee5621a",
+
+ "00000000000000000000000000000000",
+ "ffe00000000000000000000000000000",
+ "b8499c251f8442ee13f0933b688fcd19",
+
+ "00000000000000000000000000000000",
+ "fff00000000000000000000000000000",
+ "965135f8a81f25c9d630b17502f68e53",
+
+ "00000000000000000000000000000000",
+ "fff80000000000000000000000000000",
+ "8b87145a01ad1c6cede995ea3670454f",
+
+ "00000000000000000000000000000000",
+ "fffc0000000000000000000000000000",
+ "8eae3b10a0c8ca6d1d3b0fa61e56b0b2",
+
+ "00000000000000000000000000000000",
+ "fffe0000000000000000000000000000",
+ "64b4d629810fda6bafdf08f3b0d8d2c5",
+
+ "00000000000000000000000000000000",
+ "ffff0000000000000000000000000000",
+ "d7e5dbd3324595f8fdc7d7c571da6c2a",
+
+ "00000000000000000000000000000000",
+ "ffff8000000000000000000000000000",
+ "f3f72375264e167fca9de2c1527d9606",
+
+ "00000000000000000000000000000000",
+ "ffffc000000000000000000000000000",
+ "8ee79dd4f401ff9b7ea945d86666c13b",
+
+ "00000000000000000000000000000000",
+ "ffffe000000000000000000000000000",
+ "dd35cea2799940b40db3f819cb94c08b",
+
+ "00000000000000000000000000000000",
+ "fffff000000000000000000000000000",
+ "6941cb6b3e08c2b7afa581ebdd607b87",
+
+ "00000000000000000000000000000000",
+ "fffff800000000000000000000000000",
+ "2c20f439f6bb097b29b8bd6d99aad799",
+
+ "00000000000000000000000000000000",
+ "fffffc00000000000000000000000000",
+ "625d01f058e565f77ae86378bd2c49b3",
+
+ "00000000000000000000000000000000",
+ "fffffe00000000000000000000000000",
+ "c0b5fd98190ef45fbb4301438d095950",
+
+ "00000000000000000000000000000000",
+ "ffffff00000000000000000000000000",
+ "13001ff5d99806efd25da34f56be854b",
+
+ "00000000000000000000000000000000",
+ "ffffff80000000000000000000000000",
+ "3b594c60f5c8277a5113677f94208d82",
+
+ "00000000000000000000000000000000",
+ "ffffffc0000000000000000000000000",
+ "e9c0fc1818e4aa46bd2e39d638f89e05",
+
+ "00000000000000000000000000000000",
+ "ffffffe0000000000000000000000000",
+ "f8023ee9c3fdc45a019b4e985c7e1a54",
+
+ "00000000000000000000000000000000",
+ "fffffff0000000000000000000000000",
+ "35f40182ab4662f3023baec1ee796b57",
+
+ "00000000000000000000000000000000",
+ "fffffff8000000000000000000000000",
+ "3aebbad7303649b4194a6945c6cc3694",
+
+ "00000000000000000000000000000000",
+ "fffffffc000000000000000000000000",
+ "a2124bea53ec2834279bed7f7eb0f938",
+
+ "00000000000000000000000000000000",
+ "fffffffe000000000000000000000000",
+ "b9fb4399fa4facc7309e14ec98360b0a",
+
+ "00000000000000000000000000000000",
+ "ffffffff000000000000000000000000",
+ "c26277437420c5d634f715aea81a9132",
+
+ "00000000000000000000000000000000",
+ "ffffffff800000000000000000000000",
+ "171a0e1b2dd424f0e089af2c4c10f32f",
+
+ "00000000000000000000000000000000",
+ "ffffffffc00000000000000000000000",
+ "7cadbe402d1b208fe735edce00aee7ce",
+
+ "00000000000000000000000000000000",
+ "ffffffffe00000000000000000000000",
+ "43b02ff929a1485af6f5c6d6558baa0f",
+
+ "00000000000000000000000000000000",
+ "fffffffff00000000000000000000000",
+ "092faacc9bf43508bf8fa8613ca75dea",
+
+ "00000000000000000000000000000000",
+ "fffffffff80000000000000000000000",
+ "cb2bf8280f3f9742c7ed513fe802629c",
+
+ "00000000000000000000000000000000",
+ "fffffffffc0000000000000000000000",
+ "215a41ee442fa992a6e323986ded3f68",
+
+ "00000000000000000000000000000000",
+ "fffffffffe0000000000000000000000",
+ "f21e99cf4f0f77cea836e11a2fe75fb1",
+
+ "00000000000000000000000000000000",
+ "ffffffffff0000000000000000000000",
+ "95e3a0ca9079e646331df8b4e70d2cd6",
+
+ "00000000000000000000000000000000",
+ "ffffffffff8000000000000000000000",
+ "4afe7f120ce7613f74fc12a01a828073",
+
+ "00000000000000000000000000000000",
+ "ffffffffffc000000000000000000000",
+ "827f000e75e2c8b9d479beed913fe678",
+
+ "00000000000000000000000000000000",
+ "ffffffffffe000000000000000000000",
+ "35830c8e7aaefe2d30310ef381cbf691",
+
+ "00000000000000000000000000000000",
+ "fffffffffff000000000000000000000",
+ "191aa0f2c8570144f38657ea4085ebe5",
+
+ "00000000000000000000000000000000",
+ "fffffffffff800000000000000000000",
+ "85062c2c909f15d9269b6c18ce99c4f0",
+
+ "00000000000000000000000000000000",
+ "fffffffffffc00000000000000000000",
+ "678034dc9e41b5a560ed239eeab1bc78",
+
+ "00000000000000000000000000000000",
+ "fffffffffffe00000000000000000000",
+ "c2f93a4ce5ab6d5d56f1b93cf19911c1",
+
+ "00000000000000000000000000000000",
+ "ffffffffffff00000000000000000000",
+ "1c3112bcb0c1dcc749d799743691bf82",
+
+ "00000000000000000000000000000000",
+ "ffffffffffff80000000000000000000",
+ "00c55bd75c7f9c881989d3ec1911c0d4",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffc0000000000000000000",
+ "ea2e6b5ef182b7dff3629abd6a12045f",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffe0000000000000000000",
+ "22322327e01780b17397f24087f8cc6f",
+
+ "00000000000000000000000000000000",
+ "fffffffffffff0000000000000000000",
+ "c9cacb5cd11692c373b2411768149ee7",
+
+ "00000000000000000000000000000000",
+ "fffffffffffff8000000000000000000",
+ "a18e3dbbca577860dab6b80da3139256",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffc000000000000000000",
+ "79b61c37bf328ecca8d743265a3d425c",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffe000000000000000000",
+ "d2d99c6bcc1f06fda8e27e8ae3f1ccc7",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffff000000000000000000",
+ "1bfd4b91c701fd6b61b7f997829d663b",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffff800000000000000000",
+ "11005d52f25f16bdc9545a876a63490a",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffc00000000000000000",
+ "3a4d354f02bb5a5e47d39666867f246a",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffe00000000000000000",
+ "d451b8d6e1e1a0ebb155fbbf6e7b7dc3",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffff00000000000000000",
+ "6898d4f42fa7ba6a10ac05e87b9f2080",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffff80000000000000000",
+ "b611295e739ca7d9b50f8e4c0e754a3f",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffc0000000000000000",
+ "7d33fc7d8abe3ca1936759f8f5deaf20",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffe0000000000000000",
+ "3b5e0f566dc96c298f0c12637539b25c",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffff0000000000000000",
+ "f807c3e7985fe0f5a50e2cdb25c5109e",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffff8000000000000000",
+ "41f992a856fb278b389a62f5d274d7e9",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffc000000000000000",
+ "10d3ed7a6fe15ab4d91acbc7d0767ab1",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffe000000000000000",
+ "21feecd45b2e675973ac33bf0c5424fc",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffff000000000000000",
+ "1480cb3955ba62d09eea668f7c708817",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffff800000000000000",
+ "66404033d6b72b609354d5496e7eb511",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffc00000000000000",
+ "1c317a220a7d700da2b1e075b00266e1",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffe00000000000000",
+ "ab3b89542233f1271bf8fd0c0f403545",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffff00000000000000",
+ "d93eae966fac46dca927d6b114fa3f9e",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffff80000000000000",
+ "1bdec521316503d9d5ee65df3ea94ddf",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffc0000000000000",
+ "eef456431dea8b4acf83bdae3717f75f",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffe0000000000000",
+ "06f2519a2fafaa596bfef5cfa15c21b9",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffff0000000000000",
+ "251a7eac7e2fe809e4aa8d0d7012531a",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffff8000000000000",
+ "3bffc16e4c49b268a20f8d96a60b4058",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffc000000000000",
+ "e886f9281999c5bb3b3e8862e2f7c988",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffe000000000000",
+ "563bf90d61beef39f48dd625fcef1361",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffff000000000000",
+ "4d37c850644563c69fd0acd9a049325b",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffff800000000000",
+ "b87c921b91829ef3b13ca541ee1130a6",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffc00000000000",
+ "2e65eb6b6ea383e109accce8326b0393",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffe00000000000",
+ "9ca547f7439edc3e255c0f4d49aa8990",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffff00000000000",
+ "a5e652614c9300f37816b1f9fd0c87f9",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffff80000000000",
+ "14954f0b4697776f44494fe458d814ed",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffc0000000000",
+ "7c8d9ab6c2761723fe42f8bb506cbcf7",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffe0000000000",
+ "db7e1932679fdd99742aab04aa0d5a80",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffff0000000000",
+ "4c6a1c83e568cd10f27c2d73ded19c28",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffff8000000000",
+ "90ecbe6177e674c98de412413f7ac915",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffc000000000",
+ "90684a2ac55fe1ec2b8ebd5622520b73",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffe000000000",
+ "7472f9a7988607ca79707795991035e6",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffff000000000",
+ "56aff089878bf3352f8df172a3ae47d8",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffff800000000",
+ "65c0526cbe40161b8019a2a3171abd23",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffc00000000",
+ "377be0be33b4e3e310b4aabda173f84f",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffe00000000",
+ "9402e9aa6f69de6504da8d20c4fcaa2f",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffff00000000",
+ "123c1f4af313ad8c2ce648b2e71fb6e1",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffff80000000",
+ "1ffc626d30203dcdb0019fb80f726cf4",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffc0000000",
+ "76da1fbe3a50728c50fd2e621b5ad885",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffe0000000",
+ "082eb8be35f442fb52668e16a591d1d6",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffff0000000",
+ "e656f9ecf5fe27ec3e4a73d00c282fb3",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffff8000000",
+ "2ca8209d63274cd9a29bb74bcd77683a",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffc000000",
+ "79bf5dce14bb7dd73a8e3611de7ce026",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffe000000",
+ "3c849939a5d29399f344c4a0eca8a576",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffff000000",
+ "ed3c0a94d59bece98835da7aa4f07ca2",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffff800000",
+ "63919ed4ce10196438b6ad09d99cd795",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffc00000",
+ "7678f3a833f19fea95f3c6029e2bc610",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffe00000",
+ "3aa426831067d36b92be7c5f81c13c56",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffff00000",
+ "9272e2d2cdd11050998c845077a30ea0",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffff80000",
+ "088c4b53f5ec0ff814c19adae7f6246c",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffc0000",
+ "4010a5e401fdf0a0354ddbcc0d012b17",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffe0000",
+ "a87a385736c0a6189bd6589bd8445a93",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffff0000",
+ "545f2b83d9616dccf60fa9830e9cd287",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffff8000",
+ "4b706f7f92406352394037a6d4f4688d",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffc000",
+ "b7972b3941c44b90afa7b264bfba7387",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffe000",
+ "6f45732cf10881546f0fd23896d2bb60",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffff000",
+ "2e3579ca15af27f64b3c955a5bfc30ba",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffff800",
+ "34a2c5a91ae2aec99b7d1b5fa6780447",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffc00",
+ "a4d6616bd04f87335b0e53351227a9ee",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffe00",
+ "7f692b03945867d16179a8cefc83ea3f",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffff00",
+ "3bd141ee84a0e6414a26e7a4f281f8a2",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffff80",
+ "d1788f572d98b2b16ec5d5f3922b99bc",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffc0",
+ "0833ff6f61d98a57b288e8c3586b85a6",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffe0",
+ "8568261797de176bf0b43becc6285afb",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffff0",
+ "f9b0fda0c4a898f5b9e6f661c4ce4d07",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffff8",
+ "8ade895913685c67c5269f8aae42983e",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffffc",
+ "39bde67d5c8ed8a8b1c37eb8fa9f5ac0",
+
+ "00000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffffe",
+ "5c005e72c1418c44f569f2ea33ba54f3",
+
+ "00000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffff",
+ "3f5b8cc9ea855a0afa7347d23e8d664e",
+
+ /*
+ * From NIST validation suite (ECBVarTxt192.rsp).
+ */
+ "000000000000000000000000000000000000000000000000",
+ "80000000000000000000000000000000",
+ "6cd02513e8d4dc986b4afe087a60bd0c",
+
+ "000000000000000000000000000000000000000000000000",
+ "c0000000000000000000000000000000",
+ "2ce1f8b7e30627c1c4519eada44bc436",
+
+ "000000000000000000000000000000000000000000000000",
+ "e0000000000000000000000000000000",
+ "9946b5f87af446f5796c1fee63a2da24",
+
+ "000000000000000000000000000000000000000000000000",
+ "f0000000000000000000000000000000",
+ "2a560364ce529efc21788779568d5555",
+
+ "000000000000000000000000000000000000000000000000",
+ "f8000000000000000000000000000000",
+ "35c1471837af446153bce55d5ba72a0a",
+
+ "000000000000000000000000000000000000000000000000",
+ "fc000000000000000000000000000000",
+ "ce60bc52386234f158f84341e534cd9e",
+
+ "000000000000000000000000000000000000000000000000",
+ "fe000000000000000000000000000000",
+ "8c7c27ff32bcf8dc2dc57c90c2903961",
+
+ "000000000000000000000000000000000000000000000000",
+ "ff000000000000000000000000000000",
+ "32bb6a7ec84499e166f936003d55a5bb",
+
+ "000000000000000000000000000000000000000000000000",
+ "ff800000000000000000000000000000",
+ "a5c772e5c62631ef660ee1d5877f6d1b",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffc00000000000000000000000000000",
+ "030d7e5b64f380a7e4ea5387b5cd7f49",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffe00000000000000000000000000000",
+ "0dc9a2610037009b698f11bb7e86c83e",
+
+ "000000000000000000000000000000000000000000000000",
+ "fff00000000000000000000000000000",
+ "0046612c766d1840c226364f1fa7ed72",
+
+ "000000000000000000000000000000000000000000000000",
+ "fff80000000000000000000000000000",
+ "4880c7e08f27befe78590743c05e698b",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffc0000000000000000000000000000",
+ "2520ce829a26577f0f4822c4ecc87401",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffe0000000000000000000000000000",
+ "8765e8acc169758319cb46dc7bcf3dca",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffff0000000000000000000000000000",
+ "e98f4ba4f073df4baa116d011dc24a28",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffff8000000000000000000000000000",
+ "f378f68c5dbf59e211b3a659a7317d94",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffc000000000000000000000000000",
+ "283d3b069d8eb9fb432d74b96ca762b4",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffe000000000000000000000000000",
+ "a7e1842e8a87861c221a500883245c51",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffff000000000000000000000000000",
+ "77aa270471881be070fb52c7067ce732",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffff800000000000000000000000000",
+ "01b0f476d484f43f1aeb6efa9361a8ac",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffc00000000000000000000000000",
+ "1c3a94f1c052c55c2d8359aff2163b4f",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffe00000000000000000000000000",
+ "e8a067b604d5373d8b0f2e05a03b341b",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffff00000000000000000000000000",
+ "a7876ec87f5a09bfea42c77da30fd50e",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffff80000000000000000000000000",
+ "0cf3e9d3a42be5b854ca65b13f35f48d",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffc0000000000000000000000000",
+ "6c62f6bbcab7c3e821c9290f08892dda",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffe0000000000000000000000000",
+ "7f5e05bd2068738196fee79ace7e3aec",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffff0000000000000000000000000",
+ "440e0d733255cda92fb46e842fe58054",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffff8000000000000000000000000",
+ "aa5d5b1c4ea1b7a22e5583ac2e9ed8a7",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffc000000000000000000000000",
+ "77e537e89e8491e8662aae3bc809421d",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffe000000000000000000000000",
+ "997dd3e9f1598bfa73f75973f7e93b76",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffff000000000000000000000000",
+ "1b38d4f7452afefcb7fc721244e4b72e",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffff800000000000000000000000",
+ "0be2b18252e774dda30cdda02c6906e3",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffc00000000000000000000000",
+ "d2695e59c20361d82652d7d58b6f11b2",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffe00000000000000000000000",
+ "902d88d13eae52089abd6143cfe394e9",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffff00000000000000000000000",
+ "d49bceb3b823fedd602c305345734bd2",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffff80000000000000000000000",
+ "707b1dbb0ffa40ef7d95def421233fae",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffc0000000000000000000000",
+ "7ca0c1d93356d9eb8aa952084d75f913",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffe0000000000000000000000",
+ "f2cbf9cb186e270dd7bdb0c28febc57d",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffff0000000000000000000000",
+ "c94337c37c4e790ab45780bd9c3674a0",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffff8000000000000000000000",
+ "8e3558c135252fb9c9f367ed609467a1",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffc000000000000000000000",
+ "1b72eeaee4899b443914e5b3a57fba92",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffe000000000000000000000",
+ "011865f91bc56868d051e52c9efd59b7",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffff000000000000000000000",
+ "e4771318ad7a63dd680f6e583b7747ea",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffff800000000000000000000",
+ "61e3d194088dc8d97e9e6db37457eac5",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffc00000000000000000000",
+ "36ff1ec9ccfbc349e5d356d063693ad6",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffe00000000000000000000",
+ "3cc9e9a9be8cc3f6fb2ea24088e9bb19",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffff00000000000000000000",
+ "1ee5ab003dc8722e74905d9a8fe3d350",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffff80000000000000000000",
+ "245339319584b0a412412869d6c2eada",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffc0000000000000000000",
+ "7bd496918115d14ed5380852716c8814",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffe0000000000000000000",
+ "273ab2f2b4a366a57d582a339313c8b1",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffff0000000000000000000",
+ "113365a9ffbe3b0ca61e98507554168b",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffff8000000000000000000",
+ "afa99c997ac478a0dea4119c9e45f8b1",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffc000000000000000000",
+ "9216309a7842430b83ffb98638011512",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffe000000000000000000",
+ "62abc792288258492a7cb45145f4b759",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffff000000000000000000",
+ "534923c169d504d7519c15d30e756c50",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffff800000000000000000",
+ "fa75e05bcdc7e00c273fa33f6ee441d2",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffc00000000000000000",
+ "7d350fa6057080f1086a56b17ec240db",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffe00000000000000000",
+ "f34e4a6324ea4a5c39a661c8fe5ada8f",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffff00000000000000000",
+ "0882a16f44088d42447a29ac090ec17e",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffff80000000000000000",
+ "3a3c15bfc11a9537c130687004e136ee",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffc0000000000000000",
+ "22c0a7678dc6d8cf5c8a6d5a9960767c",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffe0000000000000000",
+ "b46b09809d68b9a456432a79bdc2e38c",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffff0000000000000000",
+ "93baaffb35fbe739c17c6ac22eecf18f",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffff8000000000000000",
+ "c8aa80a7850675bc007c46df06b49868",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffc000000000000000",
+ "12c6f3877af421a918a84b775858021d",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffe000000000000000",
+ "33f123282c5d633924f7d5ba3f3cab11",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffff000000000000000",
+ "a8f161002733e93ca4527d22c1a0c5bb",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffff800000000000000",
+ "b72f70ebf3e3fda23f508eec76b42c02",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffc00000000000000",
+ "6a9d965e6274143f25afdcfc88ffd77c",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffe00000000000000",
+ "a0c74fd0b9361764ce91c5200b095357",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffff00000000000000",
+ "091d1fdc2bd2c346cd5046a8c6209146",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffff80000000000000",
+ "e2a37580116cfb71856254496ab0aca8",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffc0000000000000",
+ "e0b3a00785917c7efc9adba322813571",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffe0000000000000",
+ "733d41f4727b5ef0df4af4cf3cffa0cb",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffff0000000000000",
+ "a99ebb030260826f981ad3e64490aa4f",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffff8000000000000",
+ "73f34c7d3eae5e80082c1647524308ee",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffc000000000000",
+ "40ebd5ad082345b7a2097ccd3464da02",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffe000000000000",
+ "7cc4ae9a424b2cec90c97153c2457ec5",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffff000000000000",
+ "54d632d03aba0bd0f91877ebdd4d09cb",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffff800000000000",
+ "d3427be7e4d27cd54f5fe37b03cf0897",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffc00000000000",
+ "b2099795e88cc158fd75ea133d7e7fbe",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffe00000000000",
+ "a6cae46fb6fadfe7a2c302a34242817b",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffff00000000000",
+ "026a7024d6a902e0b3ffccbaa910cc3f",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffff80000000000",
+ "156f07767a85a4312321f63968338a01",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffc0000000000",
+ "15eec9ebf42b9ca76897d2cd6c5a12e2",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffe0000000000",
+ "db0d3a6fdcc13f915e2b302ceeb70fd8",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffff0000000000",
+ "71dbf37e87a2e34d15b20e8f10e48924",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffff8000000000",
+ "c745c451e96ff3c045e4367c833e3b54",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffc000000000",
+ "340da09c2dd11c3b679d08ccd27dd595",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffe000000000",
+ "8279f7c0c2a03ee660c6d392db025d18",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffff000000000",
+ "a4b2c7d8eba531ff47c5041a55fbd1ec",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffff800000000",
+ "74569a2ca5a7bd5131ce8dc7cbfbf72f",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffc00000000",
+ "3713da0c0219b63454035613b5a403dd",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffe00000000",
+ "8827551ddcc9df23fa72a3de4e9f0b07",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffff00000000",
+ "2e3febfd625bfcd0a2c06eb460da1732",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffff80000000",
+ "ee82e6ba488156f76496311da6941deb",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffc0000000",
+ "4770446f01d1f391256e85a1b30d89d3",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffe0000000",
+ "af04b68f104f21ef2afb4767cf74143c",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffff0000000",
+ "cf3579a9ba38c8e43653173e14f3a4c6",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffff8000000",
+ "b3bba904f4953e09b54800af2f62e7d4",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffc000000",
+ "fc4249656e14b29eb9c44829b4c59a46",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffe000000",
+ "9b31568febe81cfc2e65af1c86d1a308",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffff000000",
+ "9ca09c25f273a766db98a480ce8dfedc",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffff800000",
+ "b909925786f34c3c92d971883c9fbedf",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffc00000",
+ "82647f1332fe570a9d4d92b2ee771d3b",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffe00000",
+ "3604a7e80832b3a99954bca6f5b9f501",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffff00000",
+ "884607b128c5de3ab39a529a1ef51bef",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffff80000",
+ "670cfa093d1dbdb2317041404102435e",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffc0000",
+ "7a867195f3ce8769cbd336502fbb5130",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffe0000",
+ "52efcf64c72b2f7ca5b3c836b1078c15",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffff0000",
+ "4019250f6eefb2ac5ccbcae044e75c7e",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffff8000",
+ "022c4f6f5a017d292785627667ddef24",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffc000",
+ "e9c21078a2eb7e03250f71000fa9e3ed",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffe000",
+ "a13eaeeb9cd391da4e2b09490b3e7fad",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffff000",
+ "c958a171dca1d4ed53e1af1d380803a9",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffff800",
+ "21442e07a110667f2583eaeeee44dc8c",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffc00",
+ "59bbb353cf1dd867a6e33737af655e99",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffe00",
+ "43cd3b25375d0ce41087ff9fe2829639",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffff00",
+ "6b98b17e80d1118e3516bd768b285a84",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffff80",
+ "ae47ed3676ca0c08deea02d95b81db58",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffc0",
+ "34ec40dc20413795ed53628ea748720b",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffe0",
+ "4dc68163f8e9835473253542c8a65d46",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffff0",
+ "2aabb999f43693175af65c6c612c46fb",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffff8",
+ "e01f94499dac3547515c5b1d756f0f58",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffffc",
+ "9d12435a46480ce00ea349f71799df9a",
+
+ "000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffffe",
+ "cef41d16d266bdfe46938ad7884cc0cf",
+
+ "000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffff",
+ "b13db4da1f718bc6904797c82bcf2d32",
+
+ /*
+ * From NIST validation suite (ECBVarTxt256.rsp).
+ */
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "80000000000000000000000000000000",
+ "ddc6bf790c15760d8d9aeb6f9a75fd4e",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "c0000000000000000000000000000000",
+ "0a6bdc6d4c1e6280301fd8e97ddbe601",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "e0000000000000000000000000000000",
+ "9b80eefb7ebe2d2b16247aa0efc72f5d",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "f0000000000000000000000000000000",
+ "7f2c5ece07a98d8bee13c51177395ff7",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "f8000000000000000000000000000000",
+ "7818d800dcf6f4be1e0e94f403d1e4c2",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fc000000000000000000000000000000",
+ "e74cd1c92f0919c35a0324123d6177d3",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fe000000000000000000000000000000",
+ "8092a4dcf2da7e77e93bdd371dfed82e",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ff000000000000000000000000000000",
+ "49af6b372135acef10132e548f217b17",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ff800000000000000000000000000000",
+ "8bcd40f94ebb63b9f7909676e667f1e7",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffc00000000000000000000000000000",
+ "fe1cffb83f45dcfb38b29be438dbd3ab",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffe00000000000000000000000000000",
+ "0dc58a8d886623705aec15cb1e70dc0e",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fff00000000000000000000000000000",
+ "c218faa16056bd0774c3e8d79c35a5e4",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fff80000000000000000000000000000",
+ "047bba83f7aa841731504e012208fc9e",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffc0000000000000000000000000000",
+ "dc8f0e4915fd81ba70a331310882f6da",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffe0000000000000000000000000000",
+ "1569859ea6b7206c30bf4fd0cbfac33c",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffff0000000000000000000000000000",
+ "300ade92f88f48fa2df730ec16ef44cd",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffff8000000000000000000000000000",
+ "1fe6cc3c05965dc08eb0590c95ac71d0",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffc000000000000000000000000000",
+ "59e858eaaa97fec38111275b6cf5abc0",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffe000000000000000000000000000",
+ "2239455e7afe3b0616100288cc5a723b",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffff000000000000000000000000000",
+ "3ee500c5c8d63479717163e55c5c4522",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffff800000000000000000000000000",
+ "d5e38bf15f16d90e3e214041d774daa8",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffc00000000000000000000000000",
+ "b1f4066e6f4f187dfe5f2ad1b17819d0",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffe00000000000000000000000000",
+ "6ef4cc4de49b11065d7af2909854794a",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffff00000000000000000000000000",
+ "ac86bc606b6640c309e782f232bf367f",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffff80000000000000000000000000",
+ "36aff0ef7bf3280772cf4cac80a0d2b2",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffc0000000000000000000000000",
+ "1f8eedea0f62a1406d58cfc3ecea72cf",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffe0000000000000000000000000",
+ "abf4154a3375a1d3e6b1d454438f95a6",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffff0000000000000000000000000",
+ "96f96e9d607f6615fc192061ee648b07",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffff8000000000000000000000000",
+ "cf37cdaaa0d2d536c71857634c792064",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffc000000000000000000000000",
+ "fbd6640c80245c2b805373f130703127",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffe000000000000000000000000",
+ "8d6a8afe55a6e481badae0d146f436db",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffff000000000000000000000000",
+ "6a4981f2915e3e68af6c22385dd06756",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffff800000000000000000000000",
+ "42a1136e5f8d8d21d3101998642d573b",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffc00000000000000000000000",
+ "9b471596dc69ae1586cee6158b0b0181",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffe00000000000000000000000",
+ "753665c4af1eff33aa8b628bf8741cfd",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffff00000000000000000000000",
+ "9a682acf40be01f5b2a4193c9a82404d",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffff80000000000000000000000",
+ "54fafe26e4287f17d1935f87eb9ade01",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffc0000000000000000000000",
+ "49d541b2e74cfe73e6a8e8225f7bd449",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffe0000000000000000000000",
+ "11a45530f624ff6f76a1b3826626ff7b",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffff0000000000000000000000",
+ "f96b0c4a8bc6c86130289f60b43b8fba",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffff8000000000000000000000",
+ "48c7d0e80834ebdc35b6735f76b46c8b",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffc000000000000000000000",
+ "2463531ab54d66955e73edc4cb8eaa45",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffe000000000000000000000",
+ "ac9bd8e2530469134b9d5b065d4f565b",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffff000000000000000000000",
+ "3f5f9106d0e52f973d4890e6f37e8a00",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffff800000000000000000000",
+ "20ebc86f1304d272e2e207e59db639f0",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffc00000000000000000000",
+ "e67ae6426bf9526c972cff072b52252c",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffe00000000000000000000",
+ "1a518dddaf9efa0d002cc58d107edfc8",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffff00000000000000000000",
+ "ead731af4d3a2fe3b34bed047942a49f",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffff80000000000000000000",
+ "b1d4efe40242f83e93b6c8d7efb5eae9",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffc0000000000000000000",
+ "cd2b1fec11fd906c5c7630099443610a",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffe0000000000000000000",
+ "a1853fe47fe29289d153161d06387d21",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffff0000000000000000000",
+ "4632154179a555c17ea604d0889fab14",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffff8000000000000000000",
+ "dd27cac6401a022e8f38f9f93e774417",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffc000000000000000000",
+ "c090313eb98674f35f3123385fb95d4d",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffe000000000000000000",
+ "cc3526262b92f02edce548f716b9f45c",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffff000000000000000000",
+ "c0838d1a2b16a7c7f0dfcc433c399c33",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffff800000000000000000",
+ "0d9ac756eb297695eed4d382eb126d26",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffc00000000000000000",
+ "56ede9dda3f6f141bff1757fa689c3e1",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffe00000000000000000",
+ "768f520efe0f23e61d3ec8ad9ce91774",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffff00000000000000000",
+ "b1144ddfa75755213390e7c596660490",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffff80000000000000000",
+ "1d7c0c4040b355b9d107a99325e3b050",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffc0000000000000000",
+ "d8e2bb1ae8ee3dcf5bf7d6c38da82a1a",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffe0000000000000000",
+ "faf82d178af25a9886a47e7f789b98d7",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffff0000000000000000",
+ "9b58dbfd77fe5aca9cfc190cd1b82d19",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffff8000000000000000",
+ "77f392089042e478ac16c0c86a0b5db5",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffc000000000000000",
+ "19f08e3420ee69b477ca1420281c4782",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffe000000000000000",
+ "a1b19beee4e117139f74b3c53fdcb875",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffff000000000000000",
+ "a37a5869b218a9f3a0868d19aea0ad6a",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffff800000000000000",
+ "bc3594e865bcd0261b13202731f33580",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffc00000000000000",
+ "811441ce1d309eee7185e8c752c07557",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffe00000000000000",
+ "959971ce4134190563518e700b9874d1",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffff00000000000000",
+ "76b5614a042707c98e2132e2e805fe63",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffff80000000000000",
+ "7d9fa6a57530d0f036fec31c230b0cc6",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffc0000000000000",
+ "964153a83bf6989a4ba80daa91c3e081",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffe0000000000000",
+ "a013014d4ce8054cf2591d06f6f2f176",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffff0000000000000",
+ "d1c5f6399bf382502e385eee1474a869",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffff8000000000000",
+ "0007e20b8298ec354f0f5fe7470f36bd",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffc000000000000",
+ "b95ba05b332da61ef63a2b31fcad9879",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffe000000000000",
+ "4620a49bd967491561669ab25dce45f4",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffff000000000000",
+ "12e71214ae8e04f0bb63d7425c6f14d5",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffff800000000000",
+ "4cc42fc1407b008fe350907c092e80ac",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffc00000000000",
+ "08b244ce7cbc8ee97fbba808cb146fda",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffe00000000000",
+ "39b333e8694f21546ad1edd9d87ed95b",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffff00000000000",
+ "3b271f8ab2e6e4a20ba8090f43ba78f3",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffff80000000000",
+ "9ad983f3bf651cd0393f0a73cccdea50",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffc0000000000",
+ "8f476cbff75c1f725ce18e4bbcd19b32",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffe0000000000",
+ "905b6267f1d6ab5320835a133f096f2a",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffff0000000000",
+ "145b60d6d0193c23f4221848a892d61a",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffff8000000000",
+ "55cfb3fb6d75cad0445bbc8dafa25b0f",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffc000000000",
+ "7b8e7098e357ef71237d46d8b075b0f5",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffe000000000",
+ "2bf27229901eb40f2df9d8398d1505ae",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffff000000000",
+ "83a63402a77f9ad5c1e931a931ecd706",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffff800000000",
+ "6f8ba6521152d31f2bada1843e26b973",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffc00000000",
+ "e5c3b8e30fd2d8e6239b17b44bd23bbd",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffe00000000",
+ "1ac1f7102c59933e8b2ddc3f14e94baa",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffff00000000",
+ "21d9ba49f276b45f11af8fc71a088e3d",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffff80000000",
+ "649f1cddc3792b4638635a392bc9bade",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffc0000000",
+ "e2775e4b59c1bc2e31a2078c11b5a08c",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffe0000000",
+ "2be1fae5048a25582a679ca10905eb80",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffff0000000",
+ "da86f292c6f41ea34fb2068df75ecc29",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffff8000000",
+ "220df19f85d69b1b562fa69a3c5beca5",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffc000000",
+ "1f11d5d0355e0b556ccdb6c7f5083b4d",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffe000000",
+ "62526b78be79cb384633c91f83b4151b",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffff000000",
+ "90ddbcb950843592dd47bbef00fdc876",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffff800000",
+ "2fd0e41c5b8402277354a7391d2618e2",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffc00000",
+ "3cdf13e72dee4c581bafec70b85f9660",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffe00000",
+ "afa2ffc137577092e2b654fa199d2c43",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffff00000",
+ "8d683ee63e60d208e343ce48dbc44cac",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffff80000",
+ "705a4ef8ba2133729c20185c3d3a4763",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffc0000",
+ "0861a861c3db4e94194211b77ed761b9",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffe0000",
+ "4b00c27e8b26da7eab9d3a88dec8b031",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffff0000",
+ "5f397bf03084820cc8810d52e5b666e9",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffff8000",
+ "63fafabb72c07bfbd3ddc9b1203104b8",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffc000",
+ "683e2140585b18452dd4ffbb93c95df9",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffe000",
+ "286894e48e537f8763b56707d7d155c8",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffff000",
+ "a423deabc173dcf7e2c4c53e77d37cd1",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffff800",
+ "eb8168313e1cfdfdb5e986d5429cf172",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffc00",
+ "27127daafc9accd2fb334ec3eba52323",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffe00",
+ "ee0715b96f72e3f7a22a5064fc592f4c",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffff00",
+ "29ee526770f2a11dcfa989d1ce88830f",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffff80",
+ "0493370e054b09871130fe49af730a5a",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffc0",
+ "9b7b940f6c509f9e44a4ee140448ee46",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffe0",
+ "2915be4a1ecfdcbe3e023811a12bb6c7",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffff0",
+ "7240e524bc51d8c4d440b1be55d1062c",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffff8",
+ "da63039d38cb4612b2dc36ba26684b93",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffffc",
+ "0f59cb5a4b522e2ac56c1a64f558ad9a",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "fffffffffffffffffffffffffffffffe",
+ "7bfe9d876c6d63c1d035da8fe21c409d",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "ffffffffffffffffffffffffffffffff",
+ "acdace8078a32b1a182bfa4987ca1347",
+
+ /*
+ * Table end marker.
+ */
+ NULL
+};
+
+/*
+ * AES known-answer tests for CBC. Order: key, IV, plaintext, ciphertext.
+ */
+static const char *const KAT_AES_CBC[] = {
+ /*
+ * From NIST validation suite "Multiblock Message Test"
+ * (cbcmmt128.rsp).
+ */
+ "1f8e4973953f3fb0bd6b16662e9a3c17",
+ "2fe2b333ceda8f98f4a99b40d2cd34a8",
+ "45cf12964fc824ab76616ae2f4bf0822",
+ "0f61c4d44c5147c03c195ad7e2cc12b2",
+
+ "0700d603a1c514e46b6191ba430a3a0c",
+ "aad1583cd91365e3bb2f0c3430d065bb",
+ "068b25c7bfb1f8bdd4cfc908f69dffc5ddc726a197f0e5f720f730393279be91",
+ "c4dc61d9725967a3020104a9738f23868527ce839aab1752fd8bdb95a82c4d00",
+
+ "3348aa51e9a45c2dbe33ccc47f96e8de",
+ "19153c673160df2b1d38c28060e59b96",
+ "9b7cee827a26575afdbb7c7a329f887238052e3601a7917456ba61251c214763d5e1847a6ad5d54127a399ab07ee3599",
+ "d5aed6c9622ec451a15db12819952b6752501cf05cdbf8cda34a457726ded97818e1f127a28d72db5652749f0c6afee5",
+
+ "b7f3c9576e12dd0db63e8f8fac2b9a39",
+ "c80f095d8bb1a060699f7c19974a1aa0",
+ "9ac19954ce1319b354d3220460f71c1e373f1cd336240881160cfde46ebfed2e791e8d5a1a136ebd1dc469dec00c4187722b841cdabcb22c1be8a14657da200e",
+ "19b9609772c63f338608bf6eb52ca10be65097f89c1e0905c42401fd47791ae2c5440b2d473116ca78bd9ff2fb6015cfd316524eae7dcb95ae738ebeae84a467",
+
+ "b6f9afbfe5a1562bba1368fc72ac9d9c",
+ "3f9d5ebe250ee7ce384b0d00ee849322",
+ "db397ec22718dbffb9c9d13de0efcd4611bf792be4fce0dc5f25d4f577ed8cdbd4eb9208d593dda3d4653954ab64f05676caa3ce9bfa795b08b67ceebc923fdc89a8c431188e9e482d8553982cf304d1",
+ "10ea27b19e16b93af169c4a88e06e35c99d8b420980b058e34b4b8f132b13766f72728202b089f428fecdb41c79f8aa0d0ef68f5786481cca29e2126f69bc14160f1ae2187878ba5c49cf3961e1b7ee9",
+
+ "bbe7b7ba07124ff1ae7c3416fe8b465e",
+ "7f65b5ee3630bed6b84202d97fb97a1e",
+ "2aad0c2c4306568bad7447460fd3dac054346d26feddbc9abd9110914011b4794be2a9a00a519a51a5b5124014f4ed2735480db21b434e99a911bb0b60fe0253763725b628d5739a5117b7ee3aefafc5b4c1bf446467e7bf5f78f31ff7caf187",
+ "3b8611bfc4973c5cd8e982b073b33184cd26110159172e44988eb5ff5661a1e16fad67258fcbfee55469267a12dc374893b4e3533d36f5634c3095583596f135aa8cd1138dc898bc5651ee35a92ebf89ab6aeb5366653bc60a70e0074fc11efe",
+
+ "89a553730433f7e6d67d16d373bd5360",
+ "f724558db3433a523f4e51a5bea70497",
+ "807bc4ea684eedcfdcca30180680b0f1ae2814f35f36d053c5aea6595a386c1442770f4d7297d8b91825ee7237241da8925dd594ccf676aecd46ca2068e8d37a3a0ec8a7d5185a201e663b5ff36ae197110188a23503763b8218826d23ced74b31e9f6e2d7fbfa6cb43420c7807a8625",
+ "406af1429a478c3d07e555c5287a60500d37fc39b68e5bbb9bafd6ddb223828561d6171a308d5b1a4551e8a5e7d572918d25c968d3871848d2f16635caa9847f38590b1df58ab5efb985f2c66cfaf86f61b3f9c0afad6c963c49cee9b8bc81a2ddb06c967f325515a4849eec37ce721a",
+
+ "c491ca31f91708458e29a925ec558d78",
+ "9ef934946e5cd0ae97bd58532cb49381",
+ "cb6a787e0dec56f9a165957f81af336ca6b40785d9e94093c6190e5152649f882e874d79ac5e167bd2a74ce5ae088d2ee854f6539e0a94796b1e1bd4c9fcdbc79acbef4d01eeb89776d18af71ae2a4fc47dd66df6c4dbe1d1850e466549a47b636bcc7c2b3a62495b56bb67b6d455f1eebd9bfefecbca6c7f335cfce9b45cb9d",
+ "7b2931f5855f717145e00f152a9f4794359b1ffcb3e55f594e33098b51c23a6c74a06c1d94fded7fd2ae42c7db7acaef5844cb33aeddc6852585ed0020a6699d2cb53809cefd169148ce42292afab063443978306c582c18b9ce0da3d084ce4d3c482cfd8fcf1a85084e89fb88b40a084d5e972466d07666126fb761f84078f2",
+
+ "f6e87d71b0104d6eb06a68dc6a71f498",
+ "1c245f26195b76ebebc2edcac412a2f8",
+ "f82bef3c73a6f7f80db285726d691db6bf55eec25a859d3ba0e0445f26b9bb3b16a3161ed1866e4dd8f2e5f8ecb4e46d74a7a78c20cdfc7bcc9e479ba7a0caba9438238ad0c01651d5d98de37f03ddce6e6b4bd4ab03cf9e8ed818aedfa1cf963b932067b97d776dce1087196e7e913f7448e38244509f0caf36bd8217e15336d35c149fd4e41707893fdb84014f8729",
+ "b09512f3eff9ed0d85890983a73dadbb7c3678d52581be64a8a8fc586f490f2521297a478a0598040ebd0f5509fafb0969f9d9e600eaef33b1b93eed99687b167f89a5065aac439ce46f3b8d22d30865e64e45ef8cd30b6984353a844a11c8cd60dba0e8866b3ee30d24b3fa8a643b328353e06010fa8273c8fd54ef0a2b6930e5520aae5cd5902f9b86a33592ca4365",
+
+ "2c14413751c31e2730570ba3361c786b",
+ "1dbbeb2f19abb448af849796244a19d7",
+ "40d930f9a05334d9816fe204999c3f82a03f6a0457a8c475c94553d1d116693adc618049f0a769a2eed6a6cb14c0143ec5cccdbc8dec4ce560cfd206225709326d4de7948e54d603d01b12d7fed752fb23f1aa4494fbb00130e9ded4e77e37c079042d828040c325b1a5efd15fc842e44014ca4374bf38f3c3fc3ee327733b0c8aee1abcd055772f18dc04603f7b2c1ea69ff662361f2be0a171bbdcea1e5d3f",
+ "6be8a12800455a320538853e0cba31bd2d80ea0c85164a4c5c261ae485417d93effe2ebc0d0a0b51d6ea18633d210cf63c0c4ddbc27607f2e81ed9113191ef86d56f3b99be6c415a4150299fb846ce7160b40b63baf1179d19275a2e83698376d28b92548c68e06e6d994e2c1501ed297014e702cdefee2f656447706009614d801de1caaf73f8b7fa56cf1ba94b631933bbe577624380850f117435a0355b2b",
+
+ /*
+ * From NIST validation suite "Multiblock Message Test"
+ * (cbcmmt192.rsp).
+ */
+ "ba75f4d1d9d7cf7f551445d56cc1a8ab2a078e15e049dc2c",
+ "531ce78176401666aa30db94ec4a30eb",
+ "c51fc276774dad94bcdc1d2891ec8668",
+ "70dd95a14ee975e239df36ff4aee1d5d",
+
+ "eab3b19c581aa873e1981c83ab8d83bbf8025111fb2e6b21",
+ "f3d6667e8d4d791e60f7505ba383eb05",
+ "9d4e4cccd1682321856df069e3f1c6fa391a083a9fb02d59db74c14081b3acc4",
+ "51d44779f90d40a80048276c035cb49ca2a47bcb9b9cf7270b9144793787d53f",
+
+ "16c93bb398f1fc0cf6d68fc7a5673cdf431fa147852b4a2d",
+ "eaaeca2e07ddedf562f94df63f0a650f",
+ "c5ce958613bf741718c17444484ebaf1050ddcacb59b9590178cbe69d7ad7919608cb03af13bbe04f3506b718a301ea0",
+ "ed6a50e0c6921d52d6647f75d67b4fd56ace1fedb8b5a6a997b4d131640547d22c5d884a75e6752b5846b5b33a5181f4",
+
+ "067bb17b4df785697eaccf961f98e212cb75e6797ce935cb",
+ "8b59c9209c529ca8391c9fc0ce033c38",
+ "db3785a889b4bd387754da222f0e4c2d2bfe0d79e05bc910fba941beea30f1239eacf0068f4619ec01c368e986fca6b7c58e490579d29611bd10087986eff54f",
+ "d5f5589760bf9c762228fde236de1fa2dd2dad448db3fa9be0c4196efd46a35c84dd1ac77d9db58c95918cb317a6430a08d2fb6a8e8b0f1c9b72c7a344dc349f",
+
+ "0fd39de83e0be77a79c8a4a612e3dd9c8aae2ce35e7a2bf8",
+ "7e1d629b84f93b079be51f9a5f5cb23c",
+ "38fbda37e28fa86d9d83a4345e419dea95d28c7818ff25925db6ac3aedaf0a86154e20a4dfcc5b1b4192895393e5eb5846c88bdbd41ecf7af3104f410eaee470f5d9017ed460475f626953035a13db1f",
+ "edadae2f9a45ff3473e02d904c94d94a30a4d92da4deb6bcb4b0774472694571842039f21c496ef93fd658842c735f8a81fcd0aa578442ab893b18f606aed1bab11f81452dd45e9b56adf2eccf4ea095",
+
+ "e3fecc75f0075a09b383dfd389a3d33cc9b854b3b254c0f4",
+ "36eab883afef936cc38f63284619cd19",
+ "931b2f5f3a5820d53a6beaaa6431083a3488f4eb03b0f5b57ef838e1579623103bd6e6800377538b2e51ef708f3c4956432e8a8ee6a34e190642b26ad8bdae6c2af9a6c7996f3b6004d2671e41f1c9f40ee03d1c4a52b0a0654a331f15f34dce",
+ "75395974bd32b3665654a6c8e396b88ae34b123575872a7ab687d8e76b46df911a8a590cd01d2f5c330be3a6626e9dd3aa5e10ed14e8ff829811b6fed50f3f533ca4385a1cbca78f5c4744e50f2f8359165c2485d1324e76c3eae76a0ccac629",
+
+ "f9c27565eb07947c8cb51b79248430f7b1066c3d2fdc3d13",
+ "2bd67cc89ab7948d644a49672843cbd9",
+ "6abcc270173cf114d44847e911a050db57ba7a2e2c161c6f37ccb6aaa4677bddcaf50cad0b5f8758fcf7c0ebc650ceb5cd52cafb8f8dd3edcece55d9f1f08b9fa8f54365cf56e28b9596a7e1dd1d3418e4444a7724add4cf79d527b183ec88de4be4eeff29c80a97e54f85351cb189ee",
+ "ca282924a61187feb40520979106e5cc861957f23828dcb7285e0eaac8a0ca2a6b60503d63d6039f4693dba32fa1f73ae2e709ca94911f28a5edd1f30eaddd54680c43acc9c74cd90d8bb648b4e544275f47e514daa20697f66c738eb30337f017fca1a26da4d1a0cc0a0e98e2463070",
+
+ "fb09cf9e00dbf883689d079c920077c0073c31890b55bab5",
+ "e3c89bd097c3abddf64f4881db6dbfe2",
+ "c1a37683fb289467dd1b2c89efba16bbd2ee24cf18d19d44596ded2682c79a2f711c7a32bf6a24badd32a4ee637c73b7a41da6258635650f91fb9ffa45bdfc3cb122136241b3deced8996aa51ea8d3e81c9d70e006a44bc0571ed48623a0d622a93fa9da290baaedf5d9e876c94620945ff8ecc83f27379ed55cf490c5790f27",
+ "8158e21420f25b59d6ae943fa1cbf21f02e979f419dab0126a721b7eef55bee9ad97f5ccff7d239057bbc19a8c378142f7672f1d5e7e17d7bebcb0070e8355cace6660171a53b61816ae824a6ef69ce470b6ffd3b5bb4b438874d91d27854d3b6f25860d3868958de3307d62b1339bdddb8a318c0ce0f33c17caf0e9f6040820",
+
+ "bca6fa3c67fd294e958f66fe8bd64f45f428f5bc8e9733a7",
+ "92a47f2833f1450d1da41717bdc6e83c",
+ "5becbc31d8bead6d36ae014a5863d14a431e6b55d29ea6baaa417271716db3a33b2e506b452086dfe690834ac2de30bc41254ec5401ec47d064237c7792fdcd7914d8af20eb114756642d519021a8c75a92f6bc53d326ae9a5b7e1b10a9756574692934d9939fc399e0c203f7edf8e7e6482eadd31a0400770e897b48c6bca2b404593045080e93377358c42a0f4dede",
+ "926db248cc1ba20f0c57631a7c8aef094f791937b905949e3460240e8bfa6fa483115a1b310b6e4369caebc5262888377b1ddaa5800ea496a2bdff0f9a1031e7129c9a20e35621e7f0b8baca0d87030f2ae7ca8593c8599677a06fd4b26009ead08fecac24caa9cf2cad3b470c8227415a7b1e0f2eab3fad96d70a209c8bb26c627677e2531b9435ca6e3c444d195b5f",
+
+ "162ad50ee64a0702aa551f571dedc16b2c1b6a1e4d4b5eee",
+ "24408038161a2ccae07b029bb66355c1",
+ "be8abf00901363987a82cc77d0ec91697ba3857f9e4f84bd79406c138d02698f003276d0449120bef4578d78fecabe8e070e11710b3f0a2744bd52434ec70015884c181ebdfd51c604a71c52e4c0e110bc408cd462b248a80b8a8ac06bb952ac1d7faed144807f1a731b7febcaf7835762defe92eccfc7a9944e1c702cffe6bc86733ed321423121085ac02df8962bcbc1937092eebf0e90a8b20e3dd8c244ae",
+ "c82cf2c476dea8cb6a6e607a40d2f0391be82ea9ec84a537a6820f9afb997b76397d005424faa6a74dc4e8c7aa4a8900690f894b6d1dca80675393d2243adac762f159301e357e98b724762310cd5a7bafe1c2a030dba46fd93a9fdb89cc132ca9c17dc72031ec6822ee5a9d99dbca66c784c01b0885cbb62e29d97801927ec415a5d215158d325f9ee689437ad1b7684ad33c0d92739451ac87f39ff8c31b84",
+
+ /*
+ * From NIST validation suite "Multiblock Message Test"
+ * (cbcmmt256.rsp).
+ */
+ "6ed76d2d97c69fd1339589523931f2a6cff554b15f738f21ec72dd97a7330907",
+ "851e8764776e6796aab722dbb644ace8",
+ "6282b8c05c5c1530b97d4816ca434762",
+ "6acc04142e100a65f51b97adf5172c41",
+
+ "dce26c6b4cfb286510da4eecd2cffe6cdf430f33db9b5f77b460679bd49d13ae",
+ "fdeaa134c8d7379d457175fd1a57d3fc",
+ "50e9eee1ac528009e8cbcd356975881f957254b13f91d7c6662d10312052eb00",
+ "2fa0df722a9fd3b64cb18fb2b3db55ff2267422757289413f8f657507412a64c",
+
+ "fe8901fecd3ccd2ec5fdc7c7a0b50519c245b42d611a5ef9e90268d59f3edf33",
+ "bd416cb3b9892228d8f1df575692e4d0",
+ "8d3aa196ec3d7c9b5bb122e7fe77fb1295a6da75abe5d3a510194d3a8a4157d5c89d40619716619859da3ec9b247ced9",
+ "608e82c7ab04007adb22e389a44797fed7de090c8c03ca8a2c5acd9e84df37fbc58ce8edb293e98f02b640d6d1d72464",
+
+ "0493ff637108af6a5b8e90ac1fdf035a3d4bafd1afb573be7ade9e8682e663e5",
+ "c0cd2bebccbb6c49920bd5482ac756e8",
+ "8b37f9148df4bb25956be6310c73c8dc58ea9714ff49b643107b34c9bff096a94fedd6823526abc27a8e0b16616eee254ab4567dd68e8ccd4c38ac563b13639c",
+ "05d5c77729421b08b737e41119fa4438d1f570cc772a4d6c3df7ffeda0384ef84288ce37fc4c4c7d1125a499b051364c389fd639bdda647daa3bdadab2eb5594",
+
+ "9adc8fbd506e032af7fa20cf5343719de6d1288c158c63d6878aaf64ce26ca85",
+ "11958dc6ab81e1c7f01631e9944e620f",
+ "c7917f84f747cd8c4b4fedc2219bdbc5f4d07588389d8248854cf2c2f89667a2d7bcf53e73d32684535f42318e24cd45793950b3825e5d5c5c8fcd3e5dda4ce9246d18337ef3052d8b21c5561c8b660e",
+ "9c99e68236bb2e929db1089c7750f1b356d39ab9d0c40c3e2f05108ae9d0c30b04832ccdbdc08ebfa426b7f5efde986ed05784ce368193bb3699bc691065ac62e258b9aa4cc557e2b45b49ce05511e65",
+
+ "73b8faf00b3302ac99855cf6f9e9e48518690a5906a4869d4dcf48d282faae2a",
+ "b3cb97a80a539912b8c21f450d3b9395",
+ "3adea6e06e42c4f041021491f2775ef6378cb08824165edc4f6448e232175b60d0345b9f9c78df6596ec9d22b7b9e76e8f3c76b32d5d67273f1d83fe7a6fc3dd3c49139170fa5701b3beac61b490f0a9e13f844640c4500f9ad3087adfb0ae10",
+ "ac3d6dbafe2e0f740632fd9e820bf6044cd5b1551cbb9cc03c0b25c39ccb7f33b83aacfca40a3265f2bbff879153448acacb88fcfb3bb7b10fe463a68c0109f028382e3e557b1adf02ed648ab6bb895df0205d26ebbfa9a5fd8cebd8e4bee3dc",
+
+ "9ddf3745896504ff360a51a3eb49c01b79fccebc71c3abcb94a949408b05b2c9",
+ "e79026639d4aa230b5ccffb0b29d79bc",
+ "cf52e5c3954c51b94c9e38acb8c9a7c76aebdaa9943eae0a1ce155a2efdb4d46985d935511471452d9ee64d2461cb2991d59fc0060697f9a671672163230f367fed1422316e52d29eceacb8768f56d9b80f6d278093c9a8acd3cfd7edd8ebd5c293859f64d2f8486ae1bd593c65bc014",
+ "34df561bd2cfebbcb7af3b4b8d21ca5258312e7e2e4e538e35ad2490b6112f0d7f148f6aa8d522a7f3c61d785bd667db0e1dc4606c318ea4f26af4fe7d11d4dcff0456511b4aed1a0d91ba4a1fd6cd9029187bc5881a5a07fe02049d39368e83139b12825bae2c7be81e6f12c61bb5c5",
+
+ "458b67bf212d20f3a57fce392065582dcefbf381aa22949f8338ab9052260e1d",
+ "4c12effc5963d40459602675153e9649",
+ "256fd73ce35ae3ea9c25dd2a9454493e96d8633fe633b56176dce8785ce5dbbb84dbf2c8a2eeb1e96b51899605e4f13bbc11b93bf6f39b3469be14858b5b720d4a522d36feed7a329c9b1e852c9280c47db8039c17c4921571a07d1864128330e09c308ddea1694e95c84500f1a61e614197e86a30ecc28df64ccb3ccf5437aa",
+ "90b7b9630a2378f53f501ab7beff039155008071bc8438e789932cfd3eb1299195465e6633849463fdb44375278e2fdb1310821e6492cf80ff15cb772509fb426f3aeee27bd4938882fd2ae6b5bd9d91fa4a43b17bb439ebbe59c042310163a82a5fe5388796eee35a181a1271f00be29b852d8fa759bad01ff4678f010594cd",
+
+ "d2412db0845d84e5732b8bbd642957473b81fb99ca8bff70e7920d16c1dbec89",
+ "51c619fcf0b23f0c7925f400a6cacb6d",
+ "026006c4a71a180c9929824d9d095b8faaa86fc4fa25ecac61d85ff6de92dfa8702688c02a282c1b8af4449707f22d75e91991015db22374c95f8f195d5bb0afeb03040ff8965e0e1339dba5653e174f8aa5a1b39fe3ac839ce307a4e44b4f8f1b0063f738ec18acdbff2ebfe07383e734558723e741f0a1836dafdf9de82210a9248bc113b3c1bc8b4e252ca01bd803",
+ "0254b23463bcabec5a395eb74c8fb0eb137a07bc6f5e9f61ec0b057de305714f8fa294221c91a159c315939b81e300ee902192ec5f15254428d8772f79324ec43298ca21c00b370273ee5e5ed90e43efa1e05a5d171209fe34f9f29237dba2a6726650fd3b1321747d1208863c6c3c6b3e2d879ab5f25782f08ba8f2abbe63e0bedb4a227e81afb36bb6645508356d34",
+
+ "48be597e632c16772324c8d3fa1d9c5a9ecd010f14ec5d110d3bfec376c5532b",
+ "d6d581b8cf04ebd3b6eaa1b53f047ee1",
+ "0c63d413d3864570e70bb6618bf8a4b9585586688c32bba0a5ecc1362fada74ada32c52acfd1aa7444ba567b4e7daaecf7cc1cb29182af164ae5232b002868695635599807a9a7f07a1f137e97b1e1c9dabc89b6a5e4afa9db5855edaa575056a8f4f8242216242bb0c256310d9d329826ac353d715fa39f80cec144d6424558f9f70b98c920096e0f2c855d594885a00625880e9dfb734163cecef72cf030b8",
+ "fc5873e50de8faf4c6b84ba707b0854e9db9ab2e9f7d707fbba338c6843a18fc6facebaf663d26296fb329b4d26f18494c79e09e779647f9bafa87489630d79f4301610c2300c19dbf3148b7cac8c4f4944102754f332e92b6f7c5e75bc6179eb877a078d4719009021744c14f13fd2a55a2b9c44d18000685a845a4f632c7c56a77306efa66a24d05d088dcd7c13fe24fc447275965db9e4d37fbc9304448cd",
+
+ /*
+ * End-of-table marker.
+ */
+ NULL
+};
+
+/*
+ * AES known-answer tests for CTR. Order: key, IV, plaintext, ciphertext.
+ */
+static const char *const KAT_AES_CTR[] = {
+ /*
+ * From RFC 3686.
+ */
+ "ae6852f8121067cc4bf7a5765577f39e",
+ "000000300000000000000000",
+ "53696e676c6520626c6f636b206d7367",
+ "e4095d4fb7a7b3792d6175a3261311b8",
+
+ "7e24067817fae0d743d6ce1f32539163",
+ "006cb6dbc0543b59da48d90b",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
+ "5104a106168a72d9790d41ee8edad388eb2e1efc46da57c8fce630df9141be28",
+
+ "7691be035e5020a8ac6e618529f9a0dc",
+ "00e0017b27777f3f4a1786f0",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223",
+ "c1cf48a89f2ffdd9cf4652e9efdb72d74540a42bde6d7836d59a5ceaaef3105325b2072f",
+
+ "16af5b145fc9f579c175f93e3bfb0eed863d06ccfdb78515",
+ "0000004836733c147d6d93cb",
+ "53696e676c6520626c6f636b206d7367",
+ "4b55384fe259c9c84e7935a003cbe928",
+
+ "7c5cb2401b3dc33c19e7340819e0f69c678c3db8e6f6a91a",
+ "0096b03b020c6eadc2cb500d",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
+ "453243fc609b23327edfaafa7131cd9f8490701c5ad4a79cfc1fe0ff42f4fb00",
+
+ "02bf391ee8ecb159b959617b0965279bf59b60a786d3e0fe",
+ "0007bdfd5cbd60278dcc0912",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223",
+ "96893fc55e5c722f540b7dd1ddf7e758d288bc95c69165884536c811662f2188abee0935",
+
+ "776beff2851db06f4c8a0542c8696f6c6a81af1eec96b4d37fc1d689e6c1c104",
+ "00000060db5672c97aa8f0b2",
+ "53696e676c6520626c6f636b206d7367",
+ "145ad01dbf824ec7560863dc71e3e0c0",
+
+ "f6d66d6bd52d59bb0796365879eff886c66dd51a5b6a99744b50590c87a23884",
+ "00faac24c1585ef15a43d875",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f",
+ "f05e231b3894612c49ee000b804eb2a9b8306b508f839d6a5530831d9344af1c",
+
+ "ff7a617ce69148e4f1726e2f43581de2aa62d9f805532edff1eed687fb54153d",
+ "001cc5b751a51d70a1c11148",
+ "000102030405060708090a0b0c0d0e0f101112131415161718191a1b1c1d1e1f20212223",
+ "eb6c52821d0bbbf7ce7594462aca4faab407df866569fd07f48cc0b583d6071f1ec0e6b8",
+
+ /*
+ * End-of-table marker.
+ */
+ NULL
+};
+
+static void
+monte_carlo_AES_encrypt(const br_block_cbcenc_class *ve,
+ char *skey, char *splain, char *scipher)
+{
+ unsigned char key[32];
+ unsigned char buf[16];
+ unsigned char pbuf[16];
+ unsigned char cipher[16];
+ size_t key_len;
+ int i, j, k;
+ br_aes_gen_cbcenc_keys v_ec;
+ const br_block_cbcenc_class **ec;
+
+ ec = &v_ec.vtable;
+ key_len = hextobin(key, skey);
+ hextobin(buf, splain);
+ hextobin(cipher, scipher);
+ for (i = 0; i < 100; i ++) {
+ ve->init(ec, key, key_len);
+ for (j = 0; j < 1000; j ++) {
+ unsigned char iv[16];
+
+ memcpy(pbuf, buf, sizeof buf);
+ memset(iv, 0, sizeof iv);
+ ve->run(ec, iv, buf, sizeof buf);
+ }
+ switch (key_len) {
+ case 16:
+ for (k = 0; k < 16; k ++) {
+ key[k] ^= buf[k];
+ }
+ break;
+ case 24:
+ for (k = 0; k < 8; k ++) {
+ key[k] ^= pbuf[8 + k];
+ }
+ for (k = 0; k < 16; k ++) {
+ key[8 + k] ^= buf[k];
+ }
+ break;
+ default:
+ for (k = 0; k < 16; k ++) {
+ key[k] ^= pbuf[k];
+ key[16 + k] ^= buf[k];
+ }
+ break;
+ }
+ printf(".");
+ fflush(stdout);
+ }
+ printf(" ");
+ fflush(stdout);
+ check_equals("MC AES encrypt", buf, cipher, sizeof buf);
+}
+
+static void
+monte_carlo_AES_decrypt(const br_block_cbcdec_class *vd,
+ char *skey, char *scipher, char *splain)
+{
+ unsigned char key[32];
+ unsigned char buf[16];
+ unsigned char pbuf[16];
+ unsigned char plain[16];
+ size_t key_len;
+ int i, j, k;
+ br_aes_gen_cbcdec_keys v_dc;
+ const br_block_cbcdec_class **dc;
+
+ dc = &v_dc.vtable;
+ key_len = hextobin(key, skey);
+ hextobin(buf, scipher);
+ hextobin(plain, splain);
+ for (i = 0; i < 100; i ++) {
+ vd->init(dc, key, key_len);
+ for (j = 0; j < 1000; j ++) {
+ unsigned char iv[16];
+
+ memcpy(pbuf, buf, sizeof buf);
+ memset(iv, 0, sizeof iv);
+ vd->run(dc, iv, buf, sizeof buf);
+ }
+ switch (key_len) {
+ case 16:
+ for (k = 0; k < 16; k ++) {
+ key[k] ^= buf[k];
+ }
+ break;
+ case 24:
+ for (k = 0; k < 8; k ++) {
+ key[k] ^= pbuf[8 + k];
+ }
+ for (k = 0; k < 16; k ++) {
+ key[8 + k] ^= buf[k];
+ }
+ break;
+ default:
+ for (k = 0; k < 16; k ++) {
+ key[k] ^= pbuf[k];
+ key[16 + k] ^= buf[k];
+ }
+ break;
+ }
+ printf(".");
+ fflush(stdout);
+ }
+ printf(" ");
+ fflush(stdout);
+ check_equals("MC AES decrypt", buf, plain, sizeof buf);
+}
+
+static void
+test_AES_generic(char *name,
+ const br_block_cbcenc_class *ve,
+ const br_block_cbcdec_class *vd,
+ const br_block_ctr_class *vc,
+ int with_MC, int with_CBC)
+{
+ size_t u;
+
+ printf("Test %s: ", name);
+ fflush(stdout);
+
+ if (ve->block_size != 16 || vd->block_size != 16
+ || ve->log_block_size != 4 || vd->log_block_size != 4)
+ {
+ fprintf(stderr, "%s failed: wrong block size\n", name);
+ exit(EXIT_FAILURE);
+ }
+
+ for (u = 0; KAT_AES[u]; u += 3) {
+ unsigned char key[32];
+ unsigned char plain[16];
+ unsigned char cipher[16];
+ unsigned char buf[16];
+ unsigned char iv[16];
+ size_t key_len;
+ br_aes_gen_cbcenc_keys v_ec;
+ br_aes_gen_cbcdec_keys v_dc;
+ const br_block_cbcenc_class **ec;
+ const br_block_cbcdec_class **dc;
+
+ ec = &v_ec.vtable;
+ dc = &v_dc.vtable;
+ key_len = hextobin(key, KAT_AES[u]);
+ hextobin(plain, KAT_AES[u + 1]);
+ hextobin(cipher, KAT_AES[u + 2]);
+ ve->init(ec, key, key_len);
+ memcpy(buf, plain, sizeof plain);
+ memset(iv, 0, sizeof iv);
+ ve->run(ec, iv, buf, sizeof buf);
+ check_equals("KAT AES encrypt", buf, cipher, sizeof cipher);
+ vd->init(dc, key, key_len);
+ memset(iv, 0, sizeof iv);
+ vd->run(dc, iv, buf, sizeof buf);
+ check_equals("KAT AES decrypt", buf, plain, sizeof plain);
+ }
+
+ if (with_CBC) {
+ for (u = 0; KAT_AES_CBC[u]; u += 4) {
+ unsigned char key[32];
+ unsigned char ivref[16];
+ unsigned char plain[200];
+ unsigned char cipher[200];
+ unsigned char buf[200];
+ unsigned char iv[16];
+ size_t key_len, data_len, v;
+ br_aes_gen_cbcenc_keys v_ec;
+ br_aes_gen_cbcdec_keys v_dc;
+ const br_block_cbcenc_class **ec;
+ const br_block_cbcdec_class **dc;
+
+ ec = &v_ec.vtable;
+ dc = &v_dc.vtable;
+ key_len = hextobin(key, KAT_AES_CBC[u]);
+ hextobin(ivref, KAT_AES_CBC[u + 1]);
+ data_len = hextobin(plain, KAT_AES_CBC[u + 2]);
+ hextobin(cipher, KAT_AES_CBC[u + 3]);
+ ve->init(ec, key, key_len);
+
+ memcpy(buf, plain, data_len);
+ memcpy(iv, ivref, 16);
+ ve->run(ec, iv, buf, data_len);
+ check_equals("KAT CBC AES encrypt",
+ buf, cipher, data_len);
+ vd->init(dc, key, key_len);
+ memcpy(iv, ivref, 16);
+ vd->run(dc, iv, buf, data_len);
+ check_equals("KAT CBC AES decrypt",
+ buf, plain, data_len);
+
+ memcpy(buf, plain, data_len);
+ memcpy(iv, ivref, 16);
+ for (v = 0; v < data_len; v += 16) {
+ ve->run(ec, iv, buf + v, 16);
+ }
+ check_equals("KAT CBC AES encrypt (2)",
+ buf, cipher, data_len);
+ memcpy(iv, ivref, 16);
+ for (v = 0; v < data_len; v += 16) {
+ vd->run(dc, iv, buf + v, 16);
+ }
+ check_equals("KAT CBC AES decrypt (2)",
+ buf, plain, data_len);
+ }
+
+ /*
+ * We want to check proper IV management for CBC:
+ * encryption and decryption must properly copy the _last_
+ * encrypted block as new IV, for all sizes.
+ */
+ for (u = 1; u <= 35; u ++) {
+ br_hmac_drbg_context rng;
+ unsigned char x;
+ size_t key_len, data_len;
+ size_t v;
+
+ br_hmac_drbg_init(&rng, &br_sha256_vtable,
+ "seed for AES/CBC", 16);
+ x = u;
+ br_hmac_drbg_update(&rng, &x, 1);
+ data_len = u << 4;
+ for (key_len = 16; key_len <= 32; key_len += 16) {
+ unsigned char key[32];
+ unsigned char iv[16], iv1[16], iv2[16];
+ unsigned char plain[35 * 16];
+ unsigned char tmp1[sizeof plain];
+ unsigned char tmp2[sizeof plain];
+ br_aes_gen_cbcenc_keys v_ec;
+ br_aes_gen_cbcdec_keys v_dc;
+ const br_block_cbcenc_class **ec;
+ const br_block_cbcdec_class **dc;
+
+ br_hmac_drbg_generate(&rng, key, key_len);
+ br_hmac_drbg_generate(&rng, iv, sizeof iv);
+ br_hmac_drbg_generate(&rng, plain, data_len);
+
+ ec = &v_ec.vtable;
+ ve->init(ec, key, key_len);
+ memcpy(iv1, iv, sizeof iv);
+ memcpy(tmp1, plain, data_len);
+ ve->run(ec, iv1, tmp1, data_len);
+ check_equals("IV CBC AES (1)",
+ tmp1 + data_len - 16, iv1, 16);
+ memcpy(iv2, iv, sizeof iv);
+ memcpy(tmp2, plain, data_len);
+ for (v = 0; v < data_len; v += 16) {
+ ve->run(ec, iv2, tmp2 + v, 16);
+ }
+ check_equals("IV CBC AES (2)",
+ tmp2 + data_len - 16, iv2, 16);
+ check_equals("IV CBC AES (3)",
+ tmp1, tmp2, data_len);
+
+ dc = &v_dc.vtable;
+ vd->init(dc, key, key_len);
+ memcpy(iv1, iv, sizeof iv);
+ vd->run(dc, iv1, tmp1, data_len);
+ check_equals("IV CBC AES (4)", iv1, iv2, 16);
+ check_equals("IV CBC AES (5)",
+ tmp1, plain, data_len);
+ memcpy(iv2, iv, sizeof iv);
+ for (v = 0; v < data_len; v += 16) {
+ vd->run(dc, iv2, tmp2 + v, 16);
+ }
+ check_equals("IV CBC AES (6)", iv1, iv2, 16);
+ check_equals("IV CBC AES (7)",
+ tmp2, plain, data_len);
+ }
+ }
+ }
+
+ if (vc != NULL) {
+ if (vc->block_size != 16 || vc->log_block_size != 4) {
+ fprintf(stderr, "%s failed: wrong block size\n", name);
+ exit(EXIT_FAILURE);
+ }
+ for (u = 0; KAT_AES_CTR[u]; u += 4) {
+ unsigned char key[32];
+ unsigned char iv[12];
+ unsigned char plain[200];
+ unsigned char cipher[200];
+ unsigned char buf[200];
+ size_t key_len, data_len, v;
+ uint32_t c;
+ br_aes_gen_ctr_keys v_xc;
+ const br_block_ctr_class **xc;
+
+ xc = &v_xc.vtable;
+ key_len = hextobin(key, KAT_AES_CTR[u]);
+ hextobin(iv, KAT_AES_CTR[u + 1]);
+ data_len = hextobin(plain, KAT_AES_CTR[u + 2]);
+ hextobin(cipher, KAT_AES_CTR[u + 3]);
+ vc->init(xc, key, key_len);
+ memcpy(buf, plain, data_len);
+ vc->run(xc, iv, 1, buf, data_len);
+ check_equals("KAT CTR AES (1)", buf, cipher, data_len);
+ vc->run(xc, iv, 1, buf, data_len);
+ check_equals("KAT CTR AES (2)", buf, plain, data_len);
+
+ memcpy(buf, plain, data_len);
+ c = 1;
+ for (v = 0; v < data_len; v += 32) {
+ size_t clen;
+
+ clen = data_len - v;
+ if (clen > 32) {
+ clen = 32;
+ }
+ c = vc->run(xc, iv, c, buf + v, clen);
+ }
+ check_equals("KAT CTR AES (3)", buf, cipher, data_len);
+
+ memcpy(buf, plain, data_len);
+ c = 1;
+ for (v = 0; v < data_len; v += 16) {
+ size_t clen;
+
+ clen = data_len - v;
+ if (clen > 16) {
+ clen = 16;
+ }
+ c = vc->run(xc, iv, c, buf + v, clen);
+ }
+ check_equals("KAT CTR AES (4)", buf, cipher, data_len);
+ }
+ }
+
+ if (with_MC) {
+ monte_carlo_AES_encrypt(
+ ve,
+ "139a35422f1d61de3c91787fe0507afd",
+ "b9145a768b7dc489a096b546f43b231f",
+ "fb2649694783b551eacd9d5db6126d47");
+ monte_carlo_AES_decrypt(
+ vd,
+ "0c60e7bf20ada9baa9e1ddf0d1540726",
+ "b08a29b11a500ea3aca42c36675b9785",
+ "d1d2bfdc58ffcad2341b095bce55221e");
+
+ monte_carlo_AES_encrypt(
+ ve,
+ "b9a63e09e1dfc42e93a90d9bad739e5967aef672eedd5da9",
+ "85a1f7a58167b389cddc8a9ff175ee26",
+ "5d1196da8f184975e240949a25104554");
+ monte_carlo_AES_decrypt(
+ vd,
+ "4b97585701c03fbebdfa8555024f589f1482c58a00fdd9fd",
+ "d0bd0e02ded155e4516be83f42d347a4",
+ "b63ef1b79507a62eba3dafcec54a6328");
+
+ monte_carlo_AES_encrypt(
+ ve,
+ "f9e8389f5b80712e3886cc1fa2d28a3b8c9cd88a2d4a54c6aa86ce0fef944be0",
+ "b379777f9050e2a818f2940cbbd9aba4",
+ "c5d2cb3d5b7ff0e23e308967ee074825");
+ monte_carlo_AES_decrypt(
+ vd,
+ "2b09ba39b834062b9e93f48373b8dd018dedf1e5ba1b8af831ebbacbc92a2643",
+ "89649bd0115f30bd878567610223a59d",
+ "e3d3868f578caf34e36445bf14cefc68");
+ }
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_AES_big(void)
+{
+ test_AES_generic("AES_big",
+ &br_aes_big_cbcenc_vtable,
+ &br_aes_big_cbcdec_vtable,
+ &br_aes_big_ctr_vtable,
+ 1, 1);
+}
+
+static void
+test_AES_small(void)
+{
+ test_AES_generic("AES_small",
+ &br_aes_small_cbcenc_vtable,
+ &br_aes_small_cbcdec_vtable,
+ &br_aes_small_ctr_vtable,
+ 1, 1);
+}
+
+static void
+test_AES_ct(void)
+{
+ test_AES_generic("AES_ct",
+ &br_aes_ct_cbcenc_vtable,
+ &br_aes_ct_cbcdec_vtable,
+ &br_aes_ct_ctr_vtable,
+ 1, 1);
+}
+
+static void
+test_AES_ct64(void)
+{
+ test_AES_generic("AES_ct64",
+ &br_aes_ct64_cbcenc_vtable,
+ &br_aes_ct64_cbcdec_vtable,
+ &br_aes_ct64_ctr_vtable,
+ 1, 1);
+}
+
+static void
+test_AES_x86ni(void)
+{
+ const br_block_cbcenc_class *x_cbcenc;
+ const br_block_cbcdec_class *x_cbcdec;
+ const br_block_ctr_class *x_ctr;
+ int hcbcenc, hcbcdec, hctr;
+
+ x_cbcenc = br_aes_x86ni_cbcenc_get_vtable();
+ x_cbcdec = br_aes_x86ni_cbcdec_get_vtable();
+ x_ctr = br_aes_x86ni_ctr_get_vtable();
+ hcbcenc = (x_cbcenc != NULL);
+ hcbcdec = (x_cbcdec != NULL);
+ hctr = (x_ctr != NULL);
+ if (hcbcenc != hctr || hcbcdec != hctr) {
+ fprintf(stderr, "AES_x86ni availability mismatch (%d/%d/%d)\n",
+ hcbcenc, hcbcdec, hctr);
+ exit(EXIT_FAILURE);
+ }
+ if (hctr) {
+ test_AES_generic("AES_x86ni",
+ x_cbcenc, x_cbcdec, x_ctr, 1, 1);
+ } else {
+ printf("Test AES_x86ni: UNAVAILABLE\n");
+ }
+}
+
+static void
+test_AES_pwr8(void)
+{
+ const br_block_cbcenc_class *x_cbcenc;
+ const br_block_cbcdec_class *x_cbcdec;
+ const br_block_ctr_class *x_ctr;
+ int hcbcenc, hcbcdec, hctr;
+
+ x_cbcenc = br_aes_pwr8_cbcenc_get_vtable();
+ x_cbcdec = br_aes_pwr8_cbcdec_get_vtable();
+ x_ctr = br_aes_pwr8_ctr_get_vtable();
+ hcbcenc = (x_cbcenc != NULL);
+ hcbcdec = (x_cbcdec != NULL);
+ hctr = (x_ctr != NULL);
+ if (hcbcenc != hctr || hcbcdec != hctr) {
+ fprintf(stderr, "AES_pwr8 availability mismatch (%d/%d/%d)\n",
+ hcbcenc, hcbcdec, hctr);
+ exit(EXIT_FAILURE);
+ }
+ if (hctr) {
+ test_AES_generic("AES_pwr8",
+ x_cbcenc, x_cbcdec, x_ctr, 1, 1);
+ } else {
+ printf("Test AES_pwr8: UNAVAILABLE\n");
+ }
+}
+
+/*
+ * Custom CTR + CBC-MAC AES implementation. Can also do CTR-only, and
+ * CBC-MAC-only. The 'aes_big' implementation (CTR) is used. This is
+ * meant for comparisons.
+ *
+ * If 'ctr' is NULL then no encryption/decryption is done; otherwise,
+ * CTR encryption/decryption is performed (full-block counter) and the
+ * 'ctr' array is updated with the new counter value.
+ *
+ * If 'cbcmac' is NULL then no CBC-MAC is done; otherwise, CBC-MAC is
+ * applied on the encrypted data, with 'cbcmac' as IV and destination
+ * buffer for the output. If 'ctr' is not NULL and 'encrypt' is non-zero,
+ * then CBC-MAC is computed over the result of CTR processing; otherwise,
+ * CBC-MAC is computed over the input data itself.
+ */
+static void
+do_aes_ctrcbc(const void *key, size_t key_len, int encrypt,
+ void *ctr, void *cbcmac, unsigned char *data, size_t len)
+{
+ br_aes_big_ctr_keys bc;
+ int i;
+
+ br_aes_big_ctr_init(&bc, key, key_len);
+ for (i = 0; i < 2; i ++) {
+ /*
+ * CBC-MAC is computed on the encrypted data, so in
+ * first pass if decrypting, second pass if encrypting.
+ */
+ if (cbcmac != NULL
+ && ((encrypt && i == 1) || (!encrypt && i == 0)))
+ {
+ unsigned char zz[16];
+ size_t u;
+
+ memcpy(zz, cbcmac, sizeof zz);
+ for (u = 0; u < len; u += 16) {
+ unsigned char tmp[16];
+ size_t v;
+
+ for (v = 0; v < 16; v ++) {
+ tmp[v] = zz[v] ^ data[u + v];
+ }
+ memset(zz, 0, sizeof zz);
+ br_aes_big_ctr_run(&bc,
+ tmp, br_dec32be(tmp + 12), zz, 16);
+ }
+ memcpy(cbcmac, zz, sizeof zz);
+ }
+
+ /*
+ * CTR encryption/decryption is done only in the first pass.
+ * We process data block per block, because the CTR-only
+ * class uses a 32-bit counter, while the CTR+CBC-MAC
+ * class uses a 128-bit counter.
+ */
+ if (ctr != NULL && i == 0) {
+ unsigned char zz[16];
+ size_t u;
+
+ memcpy(zz, ctr, sizeof zz);
+ for (u = 0; u < len; u += 16) {
+ int i;
+
+ br_aes_big_ctr_run(&bc,
+ zz, br_dec32be(zz + 12), data + u, 16);
+ for (i = 15; i >= 0; i --) {
+ zz[i] = (zz[i] + 1) & 0xFF;
+ if (zz[i] != 0) {
+ break;
+ }
+ }
+ }
+ memcpy(ctr, zz, sizeof zz);
+ }
+ }
+}
+
+static void
+test_AES_CTRCBC_inner(const char *name, const br_block_ctrcbc_class *vt)
+{
+ br_hmac_drbg_context rng;
+ size_t key_len;
+
+ printf("Test AES CTR/CBC-MAC %s: ", name);
+ fflush(stdout);
+
+ br_hmac_drbg_init(&rng, &br_sha256_vtable, name, strlen(name));
+ for (key_len = 16; key_len <= 32; key_len += 8) {
+ br_aes_gen_ctrcbc_keys bc;
+ unsigned char key[32];
+ size_t data_len;
+
+ br_hmac_drbg_generate(&rng, key, key_len);
+ vt->init(&bc.vtable, key, key_len);
+ for (data_len = 0; data_len <= 512; data_len += 16) {
+ unsigned char plain[512];
+ unsigned char data1[sizeof plain];
+ unsigned char data2[sizeof plain];
+ unsigned char ctr[16], cbcmac[16];
+ unsigned char ctr1[16], cbcmac1[16];
+ unsigned char ctr2[16], cbcmac2[16];
+ int i;
+
+ br_hmac_drbg_generate(&rng, plain, data_len);
+
+ for (i = 0; i <= 16; i ++) {
+ if (i == 0) {
+ br_hmac_drbg_generate(&rng, ctr, 16);
+ } else {
+ memset(ctr, 0, i - 1);
+ memset(ctr + i - 1, 0xFF, 17 - i);
+ }
+ br_hmac_drbg_generate(&rng, cbcmac, 16);
+
+ memcpy(data1, plain, data_len);
+ memcpy(ctr1, ctr, 16);
+ vt->ctr(&bc.vtable, ctr1, data1, data_len);
+ memcpy(data2, plain, data_len);
+ memcpy(ctr2, ctr, 16);
+ do_aes_ctrcbc(key, key_len, 1,
+ ctr2, NULL, data2, data_len);
+ check_equals("CTR-only data",
+ data1, data2, data_len);
+ check_equals("CTR-only counter",
+ ctr1, ctr2, 16);
+
+ memcpy(data1, plain, data_len);
+ memcpy(cbcmac1, cbcmac, 16);
+ vt->mac(&bc.vtable, cbcmac1, data1, data_len);
+ memcpy(data2, plain, data_len);
+ memcpy(cbcmac2, cbcmac, 16);
+ do_aes_ctrcbc(key, key_len, 1,
+ NULL, cbcmac2, data2, data_len);
+ check_equals("CBC-MAC-only",
+ cbcmac1, cbcmac2, 16);
+
+ memcpy(data1, plain, data_len);
+ memcpy(ctr1, ctr, 16);
+ memcpy(cbcmac1, cbcmac, 16);
+ vt->encrypt(&bc.vtable,
+ ctr1, cbcmac1, data1, data_len);
+ memcpy(data2, plain, data_len);
+ memcpy(ctr2, ctr, 16);
+ memcpy(cbcmac2, cbcmac, 16);
+ do_aes_ctrcbc(key, key_len, 1,
+ ctr2, cbcmac2, data2, data_len);
+ check_equals("encrypt: combined data",
+ data1, data2, data_len);
+ check_equals("encrypt: combined counter",
+ ctr1, ctr2, 16);
+ check_equals("encrypt: combined CBC-MAC",
+ cbcmac1, cbcmac2, 16);
+
+ memcpy(ctr1, ctr, 16);
+ memcpy(cbcmac1, cbcmac, 16);
+ vt->decrypt(&bc.vtable,
+ ctr1, cbcmac1, data1, data_len);
+ memcpy(ctr2, ctr, 16);
+ memcpy(cbcmac2, cbcmac, 16);
+ do_aes_ctrcbc(key, key_len, 0,
+ ctr2, cbcmac2, data2, data_len);
+ check_equals("decrypt: combined data",
+ data1, data2, data_len);
+ check_equals("decrypt: combined counter",
+ ctr1, ctr2, 16);
+ check_equals("decrypt: combined CBC-MAC",
+ cbcmac1, cbcmac2, 16);
+ }
+
+ printf(".");
+ fflush(stdout);
+ }
+
+ printf(" ");
+ fflush(stdout);
+ }
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_AES_CTRCBC_big(void)
+{
+ test_AES_CTRCBC_inner("big", &br_aes_big_ctrcbc_vtable);
+}
+
+static void
+test_AES_CTRCBC_small(void)
+{
+ test_AES_CTRCBC_inner("small", &br_aes_small_ctrcbc_vtable);
+}
+
+static void
+test_AES_CTRCBC_ct(void)
+{
+ test_AES_CTRCBC_inner("ct", &br_aes_ct_ctrcbc_vtable);
+}
+
+static void
+test_AES_CTRCBC_ct64(void)
+{
+ test_AES_CTRCBC_inner("ct64", &br_aes_ct64_ctrcbc_vtable);
+}
+
+static void
+test_AES_CTRCBC_x86ni(void)
+{
+ const br_block_ctrcbc_class *vt;
+
+ vt = br_aes_x86ni_ctrcbc_get_vtable();
+ if (vt != NULL) {
+ test_AES_CTRCBC_inner("x86ni", vt);
+ } else {
+ printf("Test AES CTR/CBC-MAC x86ni: UNAVAILABLE\n");
+ }
+}
+
+static void
+test_AES_CTRCBC_pwr8(void)
+{
+ const br_block_ctrcbc_class *vt;
+
+ vt = br_aes_pwr8_ctrcbc_get_vtable();
+ if (vt != NULL) {
+ test_AES_CTRCBC_inner("pwr8", vt);
+ } else {
+ printf("Test AES CTR/CBC-MAC pwr8: UNAVAILABLE\n");
+ }
+}
+
+/*
+ * DES known-answer tests. Order: plaintext, key, ciphertext.
+ * (mostly from NIST SP 800-20).
+ */
+static const char *const KAT_DES[] = {
+ "10316E028C8F3B4A", "0000000000000000", "82DCBAFBDEAB6602",
+ "8000000000000000", "0000000000000000", "95A8D72813DAA94D",
+ "4000000000000000", "0000000000000000", "0EEC1487DD8C26D5",
+ "2000000000000000", "0000000000000000", "7AD16FFB79C45926",
+ "1000000000000000", "0000000000000000", "D3746294CA6A6CF3",
+ "0800000000000000", "0000000000000000", "809F5F873C1FD761",
+ "0400000000000000", "0000000000000000", "C02FAFFEC989D1FC",
+ "0200000000000000", "0000000000000000", "4615AA1D33E72F10",
+ "0100000000000000", "0000000000000000", "8CA64DE9C1B123A7",
+ "0080000000000000", "0000000000000000", "2055123350C00858",
+ "0040000000000000", "0000000000000000", "DF3B99D6577397C8",
+ "0020000000000000", "0000000000000000", "31FE17369B5288C9",
+ "0010000000000000", "0000000000000000", "DFDD3CC64DAE1642",
+ "0008000000000000", "0000000000000000", "178C83CE2B399D94",
+ "0004000000000000", "0000000000000000", "50F636324A9B7F80",
+ "0002000000000000", "0000000000000000", "A8468EE3BC18F06D",
+ "0001000000000000", "0000000000000000", "8CA64DE9C1B123A7",
+ "0000800000000000", "0000000000000000", "A2DC9E92FD3CDE92",
+ "0000400000000000", "0000000000000000", "CAC09F797D031287",
+ "0000200000000000", "0000000000000000", "90BA680B22AEB525",
+ "0000100000000000", "0000000000000000", "CE7A24F350E280B6",
+ "0000080000000000", "0000000000000000", "882BFF0AA01A0B87",
+ "0000040000000000", "0000000000000000", "25610288924511C2",
+ "0000020000000000", "0000000000000000", "C71516C29C75D170",
+ "0000010000000000", "0000000000000000", "8CA64DE9C1B123A7",
+ "0000008000000000", "0000000000000000", "5199C29A52C9F059",
+ "0000004000000000", "0000000000000000", "C22F0A294A71F29F",
+ "0000002000000000", "0000000000000000", "EE371483714C02EA",
+ "0000001000000000", "0000000000000000", "A81FBD448F9E522F",
+ "0000000800000000", "0000000000000000", "4F644C92E192DFED",
+ "0000000400000000", "0000000000000000", "1AFA9A66A6DF92AE",
+ "0000000200000000", "0000000000000000", "B3C1CC715CB879D8",
+ "0000000100000000", "0000000000000000", "8CA64DE9C1B123A7",
+ "0000000080000000", "0000000000000000", "19D032E64AB0BD8B",
+ "0000000040000000", "0000000000000000", "3CFAA7A7DC8720DC",
+ "0000000020000000", "0000000000000000", "B7265F7F447AC6F3",
+ "0000000010000000", "0000000000000000", "9DB73B3C0D163F54",
+ "0000000008000000", "0000000000000000", "8181B65BABF4A975",
+ "0000000004000000", "0000000000000000", "93C9B64042EAA240",
+ "0000000002000000", "0000000000000000", "5570530829705592",
+ "0000000001000000", "0000000000000000", "8CA64DE9C1B123A7",
+ "0000000000800000", "0000000000000000", "8638809E878787A0",
+ "0000000000400000", "0000000000000000", "41B9A79AF79AC208",
+ "0000000000200000", "0000000000000000", "7A9BE42F2009A892",
+ "0000000000100000", "0000000000000000", "29038D56BA6D2745",
+ "0000000000080000", "0000000000000000", "5495C6ABF1E5DF51",
+ "0000000000040000", "0000000000000000", "AE13DBD561488933",
+ "0000000000020000", "0000000000000000", "024D1FFA8904E389",
+ "0000000000010000", "0000000000000000", "8CA64DE9C1B123A7",
+ "0000000000008000", "0000000000000000", "D1399712F99BF02E",
+ "0000000000004000", "0000000000000000", "14C1D7C1CFFEC79E",
+ "0000000000002000", "0000000000000000", "1DE5279DAE3BED6F",
+ "0000000000001000", "0000000000000000", "E941A33F85501303",
+ "0000000000000800", "0000000000000000", "DA99DBBC9A03F379",
+ "0000000000000400", "0000000000000000", "B7FC92F91D8E92E9",
+ "0000000000000200", "0000000000000000", "AE8E5CAA3CA04E85",
+ "0000000000000100", "0000000000000000", "8CA64DE9C1B123A7",
+ "0000000000000080", "0000000000000000", "9CC62DF43B6EED74",
+ "0000000000000040", "0000000000000000", "D863DBB5C59A91A0",
+ "0000000000000020", "0000000000000000", "A1AB2190545B91D7",
+ "0000000000000010", "0000000000000000", "0875041E64C570F7",
+ "0000000000000008", "0000000000000000", "5A594528BEBEF1CC",
+ "0000000000000004", "0000000000000000", "FCDB3291DE21F0C0",
+ "0000000000000002", "0000000000000000", "869EFD7F9F265A09",
+ "0000000000000001", "0000000000000000", "8CA64DE9C1B123A7",
+ "0000000000000000", "8000000000000000", "95F8A5E5DD31D900",
+ "0000000000000000", "4000000000000000", "DD7F121CA5015619",
+ "0000000000000000", "2000000000000000", "2E8653104F3834EA",
+ "0000000000000000", "1000000000000000", "4BD388FF6CD81D4F",
+ "0000000000000000", "0800000000000000", "20B9E767B2FB1456",
+ "0000000000000000", "0400000000000000", "55579380D77138EF",
+ "0000000000000000", "0200000000000000", "6CC5DEFAAF04512F",
+ "0000000000000000", "0100000000000000", "0D9F279BA5D87260",
+ "0000000000000000", "0080000000000000", "D9031B0271BD5A0A",
+ "0000000000000000", "0040000000000000", "424250B37C3DD951",
+ "0000000000000000", "0020000000000000", "B8061B7ECD9A21E5",
+ "0000000000000000", "0010000000000000", "F15D0F286B65BD28",
+ "0000000000000000", "0008000000000000", "ADD0CC8D6E5DEBA1",
+ "0000000000000000", "0004000000000000", "E6D5F82752AD63D1",
+ "0000000000000000", "0002000000000000", "ECBFE3BD3F591A5E",
+ "0000000000000000", "0001000000000000", "F356834379D165CD",
+ "0000000000000000", "0000800000000000", "2B9F982F20037FA9",
+ "0000000000000000", "0000400000000000", "889DE068A16F0BE6",
+ "0000000000000000", "0000200000000000", "E19E275D846A1298",
+ "0000000000000000", "0000100000000000", "329A8ED523D71AEC",
+ "0000000000000000", "0000080000000000", "E7FCE22557D23C97",
+ "0000000000000000", "0000040000000000", "12A9F5817FF2D65D",
+ "0000000000000000", "0000020000000000", "A484C3AD38DC9C19",
+ "0000000000000000", "0000010000000000", "FBE00A8A1EF8AD72",
+ "0000000000000000", "0000008000000000", "750D079407521363",
+ "0000000000000000", "0000004000000000", "64FEED9C724C2FAF",
+ "0000000000000000", "0000002000000000", "F02B263B328E2B60",
+ "0000000000000000", "0000001000000000", "9D64555A9A10B852",
+ "0000000000000000", "0000000800000000", "D106FF0BED5255D7",
+ "0000000000000000", "0000000400000000", "E1652C6B138C64A5",
+ "0000000000000000", "0000000200000000", "E428581186EC8F46",
+ "0000000000000000", "0000000100000000", "AEB5F5EDE22D1A36",
+ "0000000000000000", "0000000080000000", "E943D7568AEC0C5C",
+ "0000000000000000", "0000000040000000", "DF98C8276F54B04B",
+ "0000000000000000", "0000000020000000", "B160E4680F6C696F",
+ "0000000000000000", "0000000010000000", "FA0752B07D9C4AB8",
+ "0000000000000000", "0000000008000000", "CA3A2B036DBC8502",
+ "0000000000000000", "0000000004000000", "5E0905517BB59BCF",
+ "0000000000000000", "0000000002000000", "814EEB3B91D90726",
+ "0000000000000000", "0000000001000000", "4D49DB1532919C9F",
+ "0000000000000000", "0000000000800000", "25EB5FC3F8CF0621",
+ "0000000000000000", "0000000000400000", "AB6A20C0620D1C6F",
+ "0000000000000000", "0000000000200000", "79E90DBC98F92CCA",
+ "0000000000000000", "0000000000100000", "866ECEDD8072BB0E",
+ "0000000000000000", "0000000000080000", "8B54536F2F3E64A8",
+ "0000000000000000", "0000000000040000", "EA51D3975595B86B",
+ "0000000000000000", "0000000000020000", "CAFFC6AC4542DE31",
+ "0000000000000000", "0000000000010000", "8DD45A2DDF90796C",
+ "0000000000000000", "0000000000008000", "1029D55E880EC2D0",
+ "0000000000000000", "0000000000004000", "5D86CB23639DBEA9",
+ "0000000000000000", "0000000000002000", "1D1CA853AE7C0C5F",
+ "0000000000000000", "0000000000001000", "CE332329248F3228",
+ "0000000000000000", "0000000000000800", "8405D1ABE24FB942",
+ "0000000000000000", "0000000000000400", "E643D78090CA4207",
+ "0000000000000000", "0000000000000200", "48221B9937748A23",
+ "0000000000000000", "0000000000000100", "DD7C0BBD61FAFD54",
+ "0000000000000000", "0000000000000080", "2FBC291A570DB5C4",
+ "0000000000000000", "0000000000000040", "E07C30D7E4E26E12",
+ "0000000000000000", "0000000000000020", "0953E2258E8E90A1",
+ "0000000000000000", "0000000000000010", "5B711BC4CEEBF2EE",
+ "0000000000000000", "0000000000000008", "CC083F1E6D9E85F6",
+ "0000000000000000", "0000000000000004", "D2FD8867D50D2DFE",
+ "0000000000000000", "0000000000000002", "06E7EA22CE92708F",
+ "0000000000000000", "0000000000000001", "166B40B44ABA4BD6",
+ "0000000000000000", "0000000000000000", "8CA64DE9C1B123A7",
+ "0101010101010101", "0101010101010101", "994D4DC157B96C52",
+ "0202020202020202", "0202020202020202", "E127C2B61D98E6E2",
+ "0303030303030303", "0303030303030303", "984C91D78A269CE3",
+ "0404040404040404", "0404040404040404", "1F4570BB77550683",
+ "0505050505050505", "0505050505050505", "3990ABF98D672B16",
+ "0606060606060606", "0606060606060606", "3F5150BBA081D585",
+ "0707070707070707", "0707070707070707", "C65242248C9CF6F2",
+ "0808080808080808", "0808080808080808", "10772D40FAD24257",
+ "0909090909090909", "0909090909090909", "F0139440647A6E7B",
+ "0A0A0A0A0A0A0A0A", "0A0A0A0A0A0A0A0A", "0A288603044D740C",
+ "0B0B0B0B0B0B0B0B", "0B0B0B0B0B0B0B0B", "6359916942F7438F",
+ "0C0C0C0C0C0C0C0C", "0C0C0C0C0C0C0C0C", "934316AE443CF08B",
+ "0D0D0D0D0D0D0D0D", "0D0D0D0D0D0D0D0D", "E3F56D7F1130A2B7",
+ "0E0E0E0E0E0E0E0E", "0E0E0E0E0E0E0E0E", "A2E4705087C6B6B4",
+ "0F0F0F0F0F0F0F0F", "0F0F0F0F0F0F0F0F", "D5D76E09A447E8C3",
+ "1010101010101010", "1010101010101010", "DD7515F2BFC17F85",
+ "1111111111111111", "1111111111111111", "F40379AB9E0EC533",
+ "1212121212121212", "1212121212121212", "96CD27784D1563E5",
+ "1313131313131313", "1313131313131313", "2911CF5E94D33FE1",
+ "1414141414141414", "1414141414141414", "377B7F7CA3E5BBB3",
+ "1515151515151515", "1515151515151515", "701AA63832905A92",
+ "1616161616161616", "1616161616161616", "2006E716C4252D6D",
+ "1717171717171717", "1717171717171717", "452C1197422469F8",
+ "1818181818181818", "1818181818181818", "C33FD1EB49CB64DA",
+ "1919191919191919", "1919191919191919", "7572278F364EB50D",
+ "1A1A1A1A1A1A1A1A", "1A1A1A1A1A1A1A1A", "69E51488403EF4C3",
+ "1B1B1B1B1B1B1B1B", "1B1B1B1B1B1B1B1B", "FF847E0ADF192825",
+ "1C1C1C1C1C1C1C1C", "1C1C1C1C1C1C1C1C", "521B7FB3B41BB791",
+ "1D1D1D1D1D1D1D1D", "1D1D1D1D1D1D1D1D", "26059A6A0F3F6B35",
+ "1E1E1E1E1E1E1E1E", "1E1E1E1E1E1E1E1E", "F24A8D2231C77538",
+ "1F1F1F1F1F1F1F1F", "1F1F1F1F1F1F1F1F", "4FD96EC0D3304EF6",
+ "2020202020202020", "2020202020202020", "18A9D580A900B699",
+ "2121212121212121", "2121212121212121", "88586E1D755B9B5A",
+ "2222222222222222", "2222222222222222", "0F8ADFFB11DC2784",
+ "2323232323232323", "2323232323232323", "2F30446C8312404A",
+ "2424242424242424", "2424242424242424", "0BA03D9E6C196511",
+ "2525252525252525", "2525252525252525", "3E55E997611E4B7D",
+ "2626262626262626", "2626262626262626", "B2522FB5F158F0DF",
+ "2727272727272727", "2727272727272727", "2109425935406AB8",
+ "2828282828282828", "2828282828282828", "11A16028F310FF16",
+ "2929292929292929", "2929292929292929", "73F0C45F379FE67F",
+ "2A2A2A2A2A2A2A2A", "2A2A2A2A2A2A2A2A", "DCAD4338F7523816",
+ "2B2B2B2B2B2B2B2B", "2B2B2B2B2B2B2B2B", "B81634C1CEAB298C",
+ "2C2C2C2C2C2C2C2C", "2C2C2C2C2C2C2C2C", "DD2CCB29B6C4C349",
+ "2D2D2D2D2D2D2D2D", "2D2D2D2D2D2D2D2D", "7D07A77A2ABD50A7",
+ "2E2E2E2E2E2E2E2E", "2E2E2E2E2E2E2E2E", "30C1B0C1FD91D371",
+ "2F2F2F2F2F2F2F2F", "2F2F2F2F2F2F2F2F", "C4427B31AC61973B",
+ "3030303030303030", "3030303030303030", "F47BB46273B15EB5",
+ "3131313131313131", "3131313131313131", "655EA628CF62585F",
+ "3232323232323232", "3232323232323232", "AC978C247863388F",
+ "3333333333333333", "3333333333333333", "0432ED386F2DE328",
+ "3434343434343434", "3434343434343434", "D254014CB986B3C2",
+ "3535353535353535", "3535353535353535", "B256E34BEDB49801",
+ "3636363636363636", "3636363636363636", "37F8759EB77E7BFC",
+ "3737373737373737", "3737373737373737", "5013CA4F62C9CEA0",
+ "3838383838383838", "3838383838383838", "8940F7B3EACA5939",
+ "3939393939393939", "3939393939393939", "E22B19A55086774B",
+ "3A3A3A3A3A3A3A3A", "3A3A3A3A3A3A3A3A", "B04A2AAC925ABB0B",
+ "3B3B3B3B3B3B3B3B", "3B3B3B3B3B3B3B3B", "8D250D58361597FC",
+ "3C3C3C3C3C3C3C3C", "3C3C3C3C3C3C3C3C", "51F0114FB6A6CD37",
+ "3D3D3D3D3D3D3D3D", "3D3D3D3D3D3D3D3D", "9D0BB4DB830ECB73",
+ "3E3E3E3E3E3E3E3E", "3E3E3E3E3E3E3E3E", "E96089D6368F3E1A",
+ "3F3F3F3F3F3F3F3F", "3F3F3F3F3F3F3F3F", "5C4CA877A4E1E92D",
+ "4040404040404040", "4040404040404040", "6D55DDBC8DEA95FF",
+ "4141414141414141", "4141414141414141", "19DF84AC95551003",
+ "4242424242424242", "4242424242424242", "724E7332696D08A7",
+ "4343434343434343", "4343434343434343", "B91810B8CDC58FE2",
+ "4444444444444444", "4444444444444444", "06E23526EDCCD0C4",
+ "4545454545454545", "4545454545454545", "EF52491D5468D441",
+ "4646464646464646", "4646464646464646", "48019C59E39B90C5",
+ "4747474747474747", "4747474747474747", "0544083FB902D8C0",
+ "4848484848484848", "4848484848484848", "63B15CADA668CE12",
+ "4949494949494949", "4949494949494949", "EACC0C1264171071",
+ "4A4A4A4A4A4A4A4A", "4A4A4A4A4A4A4A4A", "9D2B8C0AC605F274",
+ "4B4B4B4B4B4B4B4B", "4B4B4B4B4B4B4B4B", "C90F2F4C98A8FB2A",
+ "4C4C4C4C4C4C4C4C", "4C4C4C4C4C4C4C4C", "03481B4828FD1D04",
+ "4D4D4D4D4D4D4D4D", "4D4D4D4D4D4D4D4D", "C78FC45A1DCEA2E2",
+ "4E4E4E4E4E4E4E4E", "4E4E4E4E4E4E4E4E", "DB96D88C3460D801",
+ "4F4F4F4F4F4F4F4F", "4F4F4F4F4F4F4F4F", "6C69E720F5105518",
+ "5050505050505050", "5050505050505050", "0D262E418BC893F3",
+ "5151515151515151", "5151515151515151", "6AD84FD7848A0A5C",
+ "5252525252525252", "5252525252525252", "C365CB35B34B6114",
+ "5353535353535353", "5353535353535353", "1155392E877F42A9",
+ "5454545454545454", "5454545454545454", "531BE5F9405DA715",
+ "5555555555555555", "5555555555555555", "3BCDD41E6165A5E8",
+ "5656565656565656", "5656565656565656", "2B1FF5610A19270C",
+ "5757575757575757", "5757575757575757", "D90772CF3F047CFD",
+ "5858585858585858", "5858585858585858", "1BEA27FFB72457B7",
+ "5959595959595959", "5959595959595959", "85C3E0C429F34C27",
+ "5A5A5A5A5A5A5A5A", "5A5A5A5A5A5A5A5A", "F9038021E37C7618",
+ "5B5B5B5B5B5B5B5B", "5B5B5B5B5B5B5B5B", "35BC6FF838DBA32F",
+ "5C5C5C5C5C5C5C5C", "5C5C5C5C5C5C5C5C", "4927ACC8CE45ECE7",
+ "5D5D5D5D5D5D5D5D", "5D5D5D5D5D5D5D5D", "E812EE6E3572985C",
+ "5E5E5E5E5E5E5E5E", "5E5E5E5E5E5E5E5E", "9BB93A89627BF65F",
+ "5F5F5F5F5F5F5F5F", "5F5F5F5F5F5F5F5F", "EF12476884CB74CA",
+ "6060606060606060", "6060606060606060", "1BF17E00C09E7CBF",
+ "6161616161616161", "6161616161616161", "29932350C098DB5D",
+ "6262626262626262", "6262626262626262", "B476E6499842AC54",
+ "6363636363636363", "6363636363636363", "5C662C29C1E96056",
+ "6464646464646464", "6464646464646464", "3AF1703D76442789",
+ "6565656565656565", "6565656565656565", "86405D9B425A8C8C",
+ "6666666666666666", "6666666666666666", "EBBF4810619C2C55",
+ "6767676767676767", "6767676767676767", "F8D1CD7367B21B5D",
+ "6868686868686868", "6868686868686868", "9EE703142BF8D7E2",
+ "6969696969696969", "6969696969696969", "5FDFFFC3AAAB0CB3",
+ "6A6A6A6A6A6A6A6A", "6A6A6A6A6A6A6A6A", "26C940AB13574231",
+ "6B6B6B6B6B6B6B6B", "6B6B6B6B6B6B6B6B", "1E2DC77E36A84693",
+ "6C6C6C6C6C6C6C6C", "6C6C6C6C6C6C6C6C", "0F4FF4D9BC7E2244",
+ "6D6D6D6D6D6D6D6D", "6D6D6D6D6D6D6D6D", "A4C9A0D04D3280CD",
+ "6E6E6E6E6E6E6E6E", "6E6E6E6E6E6E6E6E", "9FAF2C96FE84919D",
+ "6F6F6F6F6F6F6F6F", "6F6F6F6F6F6F6F6F", "115DBC965E6096C8",
+ "7070707070707070", "7070707070707070", "AF531E9520994017",
+ "7171717171717171", "7171717171717171", "B971ADE70E5C89EE",
+ "7272727272727272", "7272727272727272", "415D81C86AF9C376",
+ "7373737373737373", "7373737373737373", "8DFB864FDB3C6811",
+ "7474747474747474", "7474747474747474", "10B1C170E3398F91",
+ "7575757575757575", "7575757575757575", "CFEF7A1C0218DB1E",
+ "7676767676767676", "7676767676767676", "DBAC30A2A40B1B9C",
+ "7777777777777777", "7777777777777777", "89D3BF37052162E9",
+ "7878787878787878", "7878787878787878", "80D9230BDAEB67DC",
+ "7979797979797979", "7979797979797979", "3440911019AD68D7",
+ "7A7A7A7A7A7A7A7A", "7A7A7A7A7A7A7A7A", "9626FE57596E199E",
+ "7B7B7B7B7B7B7B7B", "7B7B7B7B7B7B7B7B", "DEA0B796624BB5BA",
+ "7C7C7C7C7C7C7C7C", "7C7C7C7C7C7C7C7C", "E9E40542BDDB3E9D",
+ "7D7D7D7D7D7D7D7D", "7D7D7D7D7D7D7D7D", "8AD99914B354B911",
+ "7E7E7E7E7E7E7E7E", "7E7E7E7E7E7E7E7E", "6F85B98DD12CB13B",
+ "7F7F7F7F7F7F7F7F", "7F7F7F7F7F7F7F7F", "10130DA3C3A23924",
+ "8080808080808080", "8080808080808080", "EFECF25C3C5DC6DB",
+ "8181818181818181", "8181818181818181", "907A46722ED34EC4",
+ "8282828282828282", "8282828282828282", "752666EB4CAB46EE",
+ "8383838383838383", "8383838383838383", "161BFABD4224C162",
+ "8484848484848484", "8484848484848484", "215F48699DB44A45",
+ "8585858585858585", "8585858585858585", "69D901A8A691E661",
+ "8686868686868686", "8686868686868686", "CBBF6EEFE6529728",
+ "8787878787878787", "8787878787878787", "7F26DCF425149823",
+ "8888888888888888", "8888888888888888", "762C40C8FADE9D16",
+ "8989898989898989", "8989898989898989", "2453CF5D5BF4E463",
+ "8A8A8A8A8A8A8A8A", "8A8A8A8A8A8A8A8A", "301085E3FDE724E1",
+ "8B8B8B8B8B8B8B8B", "8B8B8B8B8B8B8B8B", "EF4E3E8F1CC6706E",
+ "8C8C8C8C8C8C8C8C", "8C8C8C8C8C8C8C8C", "720479B024C397EE",
+ "8D8D8D8D8D8D8D8D", "8D8D8D8D8D8D8D8D", "BEA27E3795063C89",
+ "8E8E8E8E8E8E8E8E", "8E8E8E8E8E8E8E8E", "468E5218F1A37611",
+ "8F8F8F8F8F8F8F8F", "8F8F8F8F8F8F8F8F", "50ACE16ADF66BFE8",
+ "9090909090909090", "9090909090909090", "EEA24369A19F6937",
+ "9191919191919191", "9191919191919191", "6050D369017B6E62",
+ "9292929292929292", "9292929292929292", "5B365F2FB2CD7F32",
+ "9393939393939393", "9393939393939393", "F0B00B264381DDBB",
+ "9494949494949494", "9494949494949494", "E1D23881C957B96C",
+ "9595959595959595", "9595959595959595", "D936BF54ECA8BDCE",
+ "9696969696969696", "9696969696969696", "A020003C5554F34C",
+ "9797979797979797", "9797979797979797", "6118FCEBD407281D",
+ "9898989898989898", "9898989898989898", "072E328C984DE4A2",
+ "9999999999999999", "9999999999999999", "1440B7EF9E63D3AA",
+ "9A9A9A9A9A9A9A9A", "9A9A9A9A9A9A9A9A", "79BFA264BDA57373",
+ "9B9B9B9B9B9B9B9B", "9B9B9B9B9B9B9B9B", "C50E8FC289BBD876",
+ "9C9C9C9C9C9C9C9C", "9C9C9C9C9C9C9C9C", "A399D3D63E169FA9",
+ "9D9D9D9D9D9D9D9D", "9D9D9D9D9D9D9D9D", "4B8919B667BD53AB",
+ "9E9E9E9E9E9E9E9E", "9E9E9E9E9E9E9E9E", "D66CDCAF3F6724A2",
+ "9F9F9F9F9F9F9F9F", "9F9F9F9F9F9F9F9F", "E40E81FF3F618340",
+ "A0A0A0A0A0A0A0A0", "A0A0A0A0A0A0A0A0", "10EDB8977B348B35",
+ "A1A1A1A1A1A1A1A1", "A1A1A1A1A1A1A1A1", "6446C5769D8409A0",
+ "A2A2A2A2A2A2A2A2", "A2A2A2A2A2A2A2A2", "17ED1191CA8D67A3",
+ "A3A3A3A3A3A3A3A3", "A3A3A3A3A3A3A3A3", "B6D8533731BA1318",
+ "A4A4A4A4A4A4A4A4", "A4A4A4A4A4A4A4A4", "CA439007C7245CD0",
+ "A5A5A5A5A5A5A5A5", "A5A5A5A5A5A5A5A5", "06FC7FDE1C8389E7",
+ "A6A6A6A6A6A6A6A6", "A6A6A6A6A6A6A6A6", "7A3C1F3BD60CB3D8",
+ "A7A7A7A7A7A7A7A7", "A7A7A7A7A7A7A7A7", "E415D80048DBA848",
+ "A8A8A8A8A8A8A8A8", "A8A8A8A8A8A8A8A8", "26F88D30C0FB8302",
+ "A9A9A9A9A9A9A9A9", "A9A9A9A9A9A9A9A9", "D4E00A9EF5E6D8F3",
+ "AAAAAAAAAAAAAAAA", "AAAAAAAAAAAAAAAA", "C4322BE19E9A5A17",
+ "ABABABABABABABAB", "ABABABABABABABAB", "ACE41A06BFA258EA",
+ "ACACACACACACACAC", "ACACACACACACACAC", "EEAAC6D17880BD56",
+ "ADADADADADADADAD", "ADADADADADADADAD", "3C9A34CA4CB49EEB",
+ "AEAEAEAEAEAEAEAE", "AEAEAEAEAEAEAEAE", "9527B0287B75F5A3",
+ "AFAFAFAFAFAFAFAF", "AFAFAFAFAFAFAFAF", "F2D9D1BE74376C0C",
+ "B0B0B0B0B0B0B0B0", "B0B0B0B0B0B0B0B0", "939618DF0AEFAAE7",
+ "B1B1B1B1B1B1B1B1", "B1B1B1B1B1B1B1B1", "24692773CB9F27FE",
+ "B2B2B2B2B2B2B2B2", "B2B2B2B2B2B2B2B2", "38703BA5E2315D1D",
+ "B3B3B3B3B3B3B3B3", "B3B3B3B3B3B3B3B3", "FCB7E4B7D702E2FB",
+ "B4B4B4B4B4B4B4B4", "B4B4B4B4B4B4B4B4", "36F0D0B3675704D5",
+ "B5B5B5B5B5B5B5B5", "B5B5B5B5B5B5B5B5", "62D473F539FA0D8B",
+ "B6B6B6B6B6B6B6B6", "B6B6B6B6B6B6B6B6", "1533F3ED9BE8EF8E",
+ "B7B7B7B7B7B7B7B7", "B7B7B7B7B7B7B7B7", "9C4EA352599731ED",
+ "B8B8B8B8B8B8B8B8", "B8B8B8B8B8B8B8B8", "FABBF7C046FD273F",
+ "B9B9B9B9B9B9B9B9", "B9B9B9B9B9B9B9B9", "B7FE63A61C646F3A",
+ "BABABABABABABABA", "BABABABABABABABA", "10ADB6E2AB972BBE",
+ "BBBBBBBBBBBBBBBB", "BBBBBBBBBBBBBBBB", "F91DCAD912332F3B",
+ "BCBCBCBCBCBCBCBC", "BCBCBCBCBCBCBCBC", "46E7EF47323A701D",
+ "BDBDBDBDBDBDBDBD", "BDBDBDBDBDBDBDBD", "8DB18CCD9692F758",
+ "BEBEBEBEBEBEBEBE", "BEBEBEBEBEBEBEBE", "E6207B536AAAEFFC",
+ "BFBFBFBFBFBFBFBF", "BFBFBFBFBFBFBFBF", "92AA224372156A00",
+ "C0C0C0C0C0C0C0C0", "C0C0C0C0C0C0C0C0", "A3B357885B1E16D2",
+ "C1C1C1C1C1C1C1C1", "C1C1C1C1C1C1C1C1", "169F7629C970C1E5",
+ "C2C2C2C2C2C2C2C2", "C2C2C2C2C2C2C2C2", "62F44B247CF1348C",
+ "C3C3C3C3C3C3C3C3", "C3C3C3C3C3C3C3C3", "AE0FEEB0495932C8",
+ "C4C4C4C4C4C4C4C4", "C4C4C4C4C4C4C4C4", "72DAF2A7C9EA6803",
+ "C5C5C5C5C5C5C5C5", "C5C5C5C5C5C5C5C5", "4FB5D5536DA544F4",
+ "C6C6C6C6C6C6C6C6", "C6C6C6C6C6C6C6C6", "1DD4E65AAF7988B4",
+ "C7C7C7C7C7C7C7C7", "C7C7C7C7C7C7C7C7", "76BF084C1535A6C6",
+ "C8C8C8C8C8C8C8C8", "C8C8C8C8C8C8C8C8", "AFEC35B09D36315F",
+ "C9C9C9C9C9C9C9C9", "C9C9C9C9C9C9C9C9", "C8078A6148818403",
+ "CACACACACACACACA", "CACACACACACACACA", "4DA91CB4124B67FE",
+ "CBCBCBCBCBCBCBCB", "CBCBCBCBCBCBCBCB", "2DABFEB346794C3D",
+ "CCCCCCCCCCCCCCCC", "CCCCCCCCCCCCCCCC", "FBCD12C790D21CD7",
+ "CDCDCDCDCDCDCDCD", "CDCDCDCDCDCDCDCD", "536873DB879CC770",
+ "CECECECECECECECE", "CECECECECECECECE", "9AA159D7309DA7A0",
+ "CFCFCFCFCFCFCFCF", "CFCFCFCFCFCFCFCF", "0B844B9D8C4EA14A",
+ "D0D0D0D0D0D0D0D0", "D0D0D0D0D0D0D0D0", "3BBD84CE539E68C4",
+ "D1D1D1D1D1D1D1D1", "D1D1D1D1D1D1D1D1", "CF3E4F3E026E2C8E",
+ "D2D2D2D2D2D2D2D2", "D2D2D2D2D2D2D2D2", "82F85885D542AF58",
+ "D3D3D3D3D3D3D3D3", "D3D3D3D3D3D3D3D3", "22D334D6493B3CB6",
+ "D4D4D4D4D4D4D4D4", "D4D4D4D4D4D4D4D4", "47E9CB3E3154D673",
+ "D5D5D5D5D5D5D5D5", "D5D5D5D5D5D5D5D5", "2352BCC708ADC7E9",
+ "D6D6D6D6D6D6D6D6", "D6D6D6D6D6D6D6D6", "8C0F3BA0C8601980",
+ "D7D7D7D7D7D7D7D7", "D7D7D7D7D7D7D7D7", "EE5E9FD70CEF00E9",
+ "D8D8D8D8D8D8D8D8", "D8D8D8D8D8D8D8D8", "DEF6BDA6CABF9547",
+ "D9D9D9D9D9D9D9D9", "D9D9D9D9D9D9D9D9", "4DADD04A0EA70F20",
+ "DADADADADADADADA", "DADADADADADADADA", "C1AA16689EE1B482",
+ "DBDBDBDBDBDBDBDB", "DBDBDBDBDBDBDBDB", "F45FC26193E69AEE",
+ "DCDCDCDCDCDCDCDC", "DCDCDCDCDCDCDCDC", "D0CFBB937CEDBFB5",
+ "DDDDDDDDDDDDDDDD", "DDDDDDDDDDDDDDDD", "F0752004EE23D87B",
+ "DEDEDEDEDEDEDEDE", "DEDEDEDEDEDEDEDE", "77A791E28AA464A5",
+ "DFDFDFDFDFDFDFDF", "DFDFDFDFDFDFDFDF", "E7562A7F56FF4966",
+ "E0E0E0E0E0E0E0E0", "E0E0E0E0E0E0E0E0", "B026913F2CCFB109",
+ "E1E1E1E1E1E1E1E1", "E1E1E1E1E1E1E1E1", "0DB572DDCE388AC7",
+ "E2E2E2E2E2E2E2E2", "E2E2E2E2E2E2E2E2", "D9FA6595F0C094CA",
+ "E3E3E3E3E3E3E3E3", "E3E3E3E3E3E3E3E3", "ADE4804C4BE4486E",
+ "E4E4E4E4E4E4E4E4", "E4E4E4E4E4E4E4E4", "007B81F520E6D7DA",
+ "E5E5E5E5E5E5E5E5", "E5E5E5E5E5E5E5E5", "961AEB77BFC10B3C",
+ "E6E6E6E6E6E6E6E6", "E6E6E6E6E6E6E6E6", "8A8DD870C9B14AF2",
+ "E7E7E7E7E7E7E7E7", "E7E7E7E7E7E7E7E7", "3CC02E14B6349B25",
+ "E8E8E8E8E8E8E8E8", "E8E8E8E8E8E8E8E8", "BAD3EE68BDDB9607",
+ "E9E9E9E9E9E9E9E9", "E9E9E9E9E9E9E9E9", "DFF918E93BDAD292",
+ "EAEAEAEAEAEAEAEA", "EAEAEAEAEAEAEAEA", "8FE559C7CD6FA56D",
+ "EBEBEBEBEBEBEBEB", "EBEBEBEBEBEBEBEB", "C88480835C1A444C",
+ "ECECECECECECECEC", "ECECECECECECECEC", "D6EE30A16B2CC01E",
+ "EDEDEDEDEDEDEDED", "EDEDEDEDEDEDEDED", "6932D887B2EA9C1A",
+ "EEEEEEEEEEEEEEEE", "EEEEEEEEEEEEEEEE", "0BFC865461F13ACC",
+ "EFEFEFEFEFEFEFEF", "EFEFEFEFEFEFEFEF", "228AEA0D403E807A",
+ "F0F0F0F0F0F0F0F0", "F0F0F0F0F0F0F0F0", "2A2891F65BB8173C",
+ "F1F1F1F1F1F1F1F1", "F1F1F1F1F1F1F1F1", "5D1B8FAF7839494B",
+ "F2F2F2F2F2F2F2F2", "F2F2F2F2F2F2F2F2", "1C0A9280EECF5D48",
+ "F3F3F3F3F3F3F3F3", "F3F3F3F3F3F3F3F3", "6CBCE951BBC30F74",
+ "F4F4F4F4F4F4F4F4", "F4F4F4F4F4F4F4F4", "9CA66E96BD08BC70",
+ "F5F5F5F5F5F5F5F5", "F5F5F5F5F5F5F5F5", "F5D779FCFBB28BF3",
+ "F6F6F6F6F6F6F6F6", "F6F6F6F6F6F6F6F6", "0FEC6BBF9B859184",
+ "F7F7F7F7F7F7F7F7", "F7F7F7F7F7F7F7F7", "EF88D2BF052DBDA8",
+ "F8F8F8F8F8F8F8F8", "F8F8F8F8F8F8F8F8", "39ADBDDB7363090D",
+ "F9F9F9F9F9F9F9F9", "F9F9F9F9F9F9F9F9", "C0AEAF445F7E2A7A",
+ "FAFAFAFAFAFAFAFA", "FAFAFAFAFAFAFAFA", "C66F54067298D4E9",
+ "FBFBFBFBFBFBFBFB", "FBFBFBFBFBFBFBFB", "E0BA8F4488AAF97C",
+ "FCFCFCFCFCFCFCFC", "FCFCFCFCFCFCFCFC", "67B36E2875D9631C",
+ "FDFDFDFDFDFDFDFD", "FDFDFDFDFDFDFDFD", "1ED83D49E267191D",
+ "FEFEFEFEFEFEFEFE", "FEFEFEFEFEFEFEFE", "66B2B23EA84693AD",
+ "FFFFFFFFFFFFFFFF", "FFFFFFFFFFFFFFFF", "7359B2163E4EDC58",
+ "0001020304050607", "0011223344556677", "3EF0A891CF8ED990",
+ "2BD6459F82C5B300", "EA024714AD5C4D84", "126EFE8ED312190A",
+
+ NULL
+};
+
+/*
+ * Known-answer tests for DES/3DES in CBC mode. Order: key, IV,
+ * plaintext, ciphertext.
+ */
+static const char *const KAT_DES_CBC[] = {
+ /*
+ * From NIST validation suite (tdesmmt.zip).
+ */
+ "34a41a8c293176c1b30732ecfe38ae8a34a41a8c293176c1",
+ "f55b4855228bd0b4",
+ "7dd880d2a9ab411c",
+ "c91892948b6cadb4",
+
+ "70a88fa1dfb9942fa77f40157ffef2ad70a88fa1dfb9942f",
+ "ece08ce2fdc6ce80",
+ "bc225304d5a3a5c9918fc5006cbc40cc",
+ "27f67dc87af7ddb4b68f63fa7c2d454a",
+
+ "e091790be55be0bc0780153861a84adce091790be55be0bc",
+ "fd7d430f86fbbffe",
+ "03c7fffd7f36499c703dedc9df4de4a92dd4382e576d6ae9",
+ "053aeba85dd3a23bfbe8440a432f9578f312be60fb9f0035",
+
+ "857feacd16157c58e5347a70e56e578a857feacd16157c58",
+ "002dcb6d46ef0969",
+ "1f13701c7f0d7385307507a18e89843ebd295bd5e239ef109347a6898c6d3fd5",
+ "a0e4edde34f05bd8397ce279e49853e9387ba04be562f5fa19c3289c3f5a3391",
+
+ "a173545b265875ba852331fbb95b49a8a173545b265875ba",
+ "ab385756391d364c",
+ "d08894c565608d9ae51dda63b85b3b33b1703bb5e4f1abcbb8794e743da5d6f3bf630f2e9b6d5b54",
+ "370b47acf89ac6bdbb13c9a7336787dc41e1ad8beead32281d0609fb54968404bdf2894892590658",
+
+ "26376bcb2f23df1083cd684fe00ed3c726376bcb2f23df10",
+ "33acfb0f3d240ea6",
+ "903a1911da1e6877f23c1985a9b61786ef438e0ce1240885035ad60fc916b18e5d71a1fb9c5d1eff61db75c0076f6efb",
+ "7a4f7510f6ec0b93e2495d21a8355684d303a770ebda2e0e51ff33d72b20cb73e58e2e3de2ef6b2e12c504c0f181ba63",
+
+ "3e1f98135d027cec752f67765408a7913e1f98135d027cec",
+ "11f5f2304b28f68b",
+ "7c022f5af24f7925d323d4d0e20a2ce49272c5e764b22c806f4b6ddc406d864fe5bd1c3f45556d3eb30c8676c2f8b54a5a32423a0bd95a07",
+ "2bb4b131fa4ae0b4f0378a2cdb68556af6eee837613016d7ea936f3931f25f8b3ae351d5e9d00be665676e2400408b5db9892d95421e7f1a",
+
+ "13b9d549cd136ec7bf9e9810ef2cdcbf13b9d549cd136ec7",
+ "a82c1b1057badcc8",
+ "1fff1563bc1645b55cb23ea34a0049dfc06607150614b621dedcb07f20433402a2d869c95ac4a070c7a3da838c928a385f899c5d21ecb58f4e5cbdad98d39b8c",
+ "75f804d4a2c542a31703e23df26cc38861a0729090e6eae5672c1db8c0b09fba9b125bbca7d6c7d330b3859e6725c6d26de21c4e3af7f5ea94df3cde2349ce37",
+
+ "20320dfdad579bb57c6e4acd769dbadf20320dfdad579bb5",
+ "879201b5857ccdea",
+ "0431283cc8bb4dc7750a9d5c68578486932091632a12d0a79f2c54e3d122130881fff727050f317a40fcd1a8d13793458b99fc98254ba6a233e3d95b55cf5a3faff78809999ea4bf",
+ "85d17840eb2af5fc727027336bfd71a2b31bd14a1d9eb64f8a08bfc4f56eaa9ca7654a5ae698287869cc27324813730de4f1384e0b8cfbc472ff5470e3c5e4bd8ceb23dc2d91988c",
+
+ "23abb073a2df34cb3d1fdce6b092582c23abb073a2df34cb",
+ "7d7fbf19e8562d32",
+ "31e718fd95e6d7ca4f94763191add2674ab07c909d88c486916c16d60a048a0cf8cdb631cebec791362cd0c202eb61e166b65c1f65d0047c8aec57d3d84b9e17032442dce148e1191b06a12c284cc41e",
+ "c9a3f75ab6a7cd08a7fd53ca540aafe731d257ee1c379fadcc4cc1a06e7c12bddbeb7562c436d1da849ed072629e82a97b56d9becc25ff4f16f21c5f2a01911604f0b5c49df96cb641faee662ca8aa68",
+
+ "b5cb1504802326c73df186e3e352a20de643b0d63ee30e37",
+ "43f791134c5647ba",
+ "dcc153cef81d6f24",
+ "92538bd8af18d3ba",
+
+ "a49d7564199e97cb529d2c9d97bf2f98d35edf57ba1f7358",
+ "c2e999cb6249023c",
+ "c689aee38a301bb316da75db36f110b5",
+ "e9afaba5ec75ea1bbe65506655bb4ecb",
+
+ "1a5d4c0825072a15a8ad9dfdaeda8c048adffb85bc4fced0",
+ "7fcfa736f7548b6f",
+ "983c3edacd939406010e1bc6ff9e12320ac5008117fa8f84",
+ "d84fa24f38cf451ca2c9adc960120bd8ff9871584fe31cee",
+
+ "d98aadc76d4a3716158c32866efbb9ce834af2297379a49d",
+ "3c5220327c502b44",
+ "6174079dda53ca723ebf00a66837f8d5ce648c08acaa5ee45ffe62210ef79d3e",
+ "f5bd4d600bed77bec78409e3530ebda1d815506ed53103015b87e371ae000958",
+
+ "ef6d3e54266d978ffb0b8ce6689d803e2cd34cc802fd0252",
+ "38bae5bce06d0ad9",
+ "c4f228b537223cd01c0debb5d9d4e12ba71656618d119b2f8f0af29d23efa3a9e43c4c458a1b79a0",
+ "9e3289fb18379f55aa4e45a7e0e6df160b33b75f8627ad0954f8fdcb78cee55a4664caeda1000fe5",
+
+ "625bc19b19df83abfb2f5bec9d4f2062017525a75bc26e70",
+ "bd0cff364ff69a91",
+ "8152d2ab876c3c8201403a5a406d3feaf27319dbea6ad01e24f4d18203704b86de70da6bbb6d638e5aba3ff576b79b28",
+ "706fe7a973fac40e25b2b4499ce527078944c70e976d017b6af86a3a7a6b52943a72ba18a58000d2b61fdc3bfef2bc4a",
+
+ "b6383176046e6880a1023bf45768b5bf5119022fe054bfe5",
+ "ec13ca541c43401e",
+ "cd5a886e9af011346c4dba36a424f96a78a1ddf28aaa4188bf65451f4efaffc7179a6dd237c0ae35d9b672314e5cb032612597f7e462c6f3",
+ "b030f976f46277ee211c4a324d5c87555d1084513a1223d3b84416b52bbc28f4b77f3a9d8d0d91dc37d3dbe8af8be98f74674b02f9a38527",
+
+ "3d8cf273d343b9aedccddacb91ad86206737adc86b4a49a7",
+ "bb3a9a0c71c62ef0",
+ "1fde3991c32ce220b5b6666a9234f2fd7bd24b921829fd9cdc6eb4218be9eac9faa9c2351777349128086b6d58776bc86ff2f76ee1b3b2850a318462b8983fa1",
+ "422ce705a46bb52ad928dab6c863166d617c6fc24003633120d91918314bbf464cea7345c3c35f2042f2d6929735d74d7728f22fea618a0b9cf5b1281acb13fb",
+
+ "fbceb5cb646b925be0b92f7f6b493d5e5b16e9159732732a",
+ "2e17b3c7025ae86b",
+ "4c309bc8e1e464fdd2a2b8978645d668d455f7526bd8d7b6716a722f6a900b815c4a73cc30e788065c1dfca7bf5958a6cc5440a5ebe7f8691c20278cde95db764ff8ce8994ece89c",
+ "c02129bdf4bbbd75e71605a00b12c80db6b4e05308e916615011f09147ed915dd1bc67f27f9e027e4e13df36b55464a31c11b4d1fe3d855d89df492e1a7201b995c1ba16a8dbabee",
+
+ "9b162a0df8ad9b61c88676e3d586434570b902f12a2046e0",
+ "ebd6fefe029ad54b",
+ "f4c1c918e77355c8156f0fd778da52bff121ae5f2f44eaf4d2754946d0e10d1f18ce3a0176e69c18b7d20b6e0d0bee5eb5edfe4bd60e4d92adcd86bce72e76f94ee5cbcaa8b01cfddcea2ade575e66ac",
+ "1ff3c8709f403a8eff291aedf50c010df5c5ff64a8b205f1fce68564798897a390db16ee0d053856b75898009731da290fcc119dad987277aacef694872e880c4bb41471063fae05c89f25e4bd0cad6a",
+
+ NULL
+};
+
+static void
+xor_buf(unsigned char *dst, const unsigned char *src, size_t len)
+{
+ while (len -- > 0) {
+ *dst ++ ^= *src ++;
+ }
+}
+
+static void
+monte_carlo_DES_encrypt(const br_block_cbcenc_class *ve)
+{
+ unsigned char k1[8], k2[8], k3[8];
+ unsigned char buf[8];
+ unsigned char cipher[8];
+ int i, j;
+ br_des_gen_cbcenc_keys v_ec;
+ void *ec;
+
+ ec = &v_ec;
+ hextobin(k1, "9ec2372c86379df4");
+ hextobin(k2, "ad7ac4464f73805d");
+ hextobin(k3, "20c4f87564527c91");
+ hextobin(buf, "b624d6bd41783ab1");
+ hextobin(cipher, "eafd97b190b167fe");
+ for (i = 0; i < 400; i ++) {
+ unsigned char key[24];
+
+ memcpy(key, k1, 8);
+ memcpy(key + 8, k2, 8);
+ memcpy(key + 16, k3, 8);
+ ve->init(ec, key, sizeof key);
+ for (j = 0; j < 10000; j ++) {
+ unsigned char iv[8];
+
+ memset(iv, 0, sizeof iv);
+ ve->run(ec, iv, buf, sizeof buf);
+ switch (j) {
+ case 9997: xor_buf(k3, buf, 8); break;
+ case 9998: xor_buf(k2, buf, 8); break;
+ case 9999: xor_buf(k1, buf, 8); break;
+ }
+ }
+ printf(".");
+ fflush(stdout);
+ }
+ printf(" ");
+ fflush(stdout);
+ check_equals("MC DES encrypt", buf, cipher, sizeof buf);
+}
+
+static void
+monte_carlo_DES_decrypt(const br_block_cbcdec_class *vd)
+{
+ unsigned char k1[8], k2[8], k3[8];
+ unsigned char buf[8];
+ unsigned char plain[8];
+ int i, j;
+ br_des_gen_cbcdec_keys v_dc;
+ void *dc;
+
+ dc = &v_dc;
+ hextobin(k1, "79b63486e0ce37e0");
+ hextobin(k2, "08e65231abae3710");
+ hextobin(k3, "1f5eb69e925ef185");
+ hextobin(buf, "2783aa729432fe96");
+ hextobin(plain, "44937ca532cdbf98");
+ for (i = 0; i < 400; i ++) {
+ unsigned char key[24];
+
+ memcpy(key, k1, 8);
+ memcpy(key + 8, k2, 8);
+ memcpy(key + 16, k3, 8);
+ vd->init(dc, key, sizeof key);
+ for (j = 0; j < 10000; j ++) {
+ unsigned char iv[8];
+
+ memset(iv, 0, sizeof iv);
+ vd->run(dc, iv, buf, sizeof buf);
+ switch (j) {
+ case 9997: xor_buf(k3, buf, 8); break;
+ case 9998: xor_buf(k2, buf, 8); break;
+ case 9999: xor_buf(k1, buf, 8); break;
+ }
+ }
+ printf(".");
+ fflush(stdout);
+ }
+ printf(" ");
+ fflush(stdout);
+ check_equals("MC DES decrypt", buf, plain, sizeof buf);
+}
+
+static void
+test_DES_generic(char *name,
+ const br_block_cbcenc_class *ve,
+ const br_block_cbcdec_class *vd,
+ int with_MC, int with_CBC)
+{
+ size_t u;
+
+ printf("Test %s: ", name);
+ fflush(stdout);
+
+ if (ve->block_size != 8 || vd->block_size != 8) {
+ fprintf(stderr, "%s failed: wrong block size\n", name);
+ exit(EXIT_FAILURE);
+ }
+
+ for (u = 0; KAT_DES[u]; u += 3) {
+ unsigned char key[24];
+ unsigned char plain[8];
+ unsigned char cipher[8];
+ unsigned char buf[8];
+ unsigned char iv[8];
+ size_t key_len;
+ br_des_gen_cbcenc_keys v_ec;
+ br_des_gen_cbcdec_keys v_dc;
+ const br_block_cbcenc_class **ec;
+ const br_block_cbcdec_class **dc;
+
+ ec = &v_ec.vtable;
+ dc = &v_dc.vtable;
+ key_len = hextobin(key, KAT_DES[u]);
+ hextobin(plain, KAT_DES[u + 1]);
+ hextobin(cipher, KAT_DES[u + 2]);
+ ve->init(ec, key, key_len);
+ memcpy(buf, plain, sizeof plain);
+ memset(iv, 0, sizeof iv);
+ ve->run(ec, iv, buf, sizeof buf);
+ check_equals("KAT DES encrypt", buf, cipher, sizeof cipher);
+ vd->init(dc, key, key_len);
+ memset(iv, 0, sizeof iv);
+ vd->run(dc, iv, buf, sizeof buf);
+ check_equals("KAT DES decrypt", buf, plain, sizeof plain);
+
+ if (key_len == 8) {
+ memcpy(key + 8, key, 8);
+ memcpy(key + 16, key, 8);
+ ve->init(ec, key, 24);
+ memcpy(buf, plain, sizeof plain);
+ memset(iv, 0, sizeof iv);
+ ve->run(ec, iv, buf, sizeof buf);
+ check_equals("KAT DES->3 encrypt",
+ buf, cipher, sizeof cipher);
+ vd->init(dc, key, 24);
+ memset(iv, 0, sizeof iv);
+ vd->run(dc, iv, buf, sizeof buf);
+ check_equals("KAT DES->3 decrypt",
+ buf, plain, sizeof plain);
+ }
+ }
+
+ if (with_CBC) {
+ for (u = 0; KAT_DES_CBC[u]; u += 4) {
+ unsigned char key[24];
+ unsigned char ivref[8];
+ unsigned char plain[200];
+ unsigned char cipher[200];
+ unsigned char buf[200];
+ unsigned char iv[8];
+ size_t key_len, data_len, v;
+ br_des_gen_cbcenc_keys v_ec;
+ br_des_gen_cbcdec_keys v_dc;
+ const br_block_cbcenc_class **ec;
+ const br_block_cbcdec_class **dc;
+
+ ec = &v_ec.vtable;
+ dc = &v_dc.vtable;
+ key_len = hextobin(key, KAT_DES_CBC[u]);
+ hextobin(ivref, KAT_DES_CBC[u + 1]);
+ data_len = hextobin(plain, KAT_DES_CBC[u + 2]);
+ hextobin(cipher, KAT_DES_CBC[u + 3]);
+ ve->init(ec, key, key_len);
+
+ memcpy(buf, plain, data_len);
+ memcpy(iv, ivref, 8);
+ ve->run(ec, iv, buf, data_len);
+ check_equals("KAT CBC DES encrypt",
+ buf, cipher, data_len);
+ vd->init(dc, key, key_len);
+ memcpy(iv, ivref, 8);
+ vd->run(dc, iv, buf, data_len);
+ check_equals("KAT CBC DES decrypt",
+ buf, plain, data_len);
+
+ memcpy(buf, plain, data_len);
+ memcpy(iv, ivref, 8);
+ for (v = 0; v < data_len; v += 8) {
+ ve->run(ec, iv, buf + v, 8);
+ }
+ check_equals("KAT CBC DES encrypt (2)",
+ buf, cipher, data_len);
+ memcpy(iv, ivref, 8);
+ for (v = 0; v < data_len; v += 8) {
+ vd->run(dc, iv, buf + v, 8);
+ }
+ check_equals("KAT CBC DES decrypt (2)",
+ buf, plain, data_len);
+ }
+ }
+
+ if (with_MC) {
+ monte_carlo_DES_encrypt(ve);
+ monte_carlo_DES_decrypt(vd);
+ }
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_DES_tab(void)
+{
+ test_DES_generic("DES_tab",
+ &br_des_tab_cbcenc_vtable,
+ &br_des_tab_cbcdec_vtable,
+ 1, 1);
+}
+
+static void
+test_DES_ct(void)
+{
+ test_DES_generic("DES_ct",
+ &br_des_ct_cbcenc_vtable,
+ &br_des_ct_cbcdec_vtable,
+ 1, 1);
+}
+
+static const struct {
+ const char *skey;
+ const char *snonce;
+ uint32_t counter;
+ const char *splain;
+ const char *scipher;
+} KAT_CHACHA20[] = {
+ {
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "000000000000000000000000",
+ 0,
+ "00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ "76b8e0ada0f13d90405d6ae55386bd28bdd219b8a08ded1aa836efcc8b770dc7da41597c5157488d7724e03fb8d84a376a43b8f41518a11cc387b669b2ee6586"
+ },
+ {
+ "0000000000000000000000000000000000000000000000000000000000000001",
+ "000000000000000000000002",
+ 1,
+ "416e79207375626d697373696f6e20746f20746865204945544620696e74656e6465642062792074686520436f6e7472696275746f7220666f72207075626c69636174696f6e20617320616c6c206f722070617274206f6620616e204945544620496e7465726e65742d4472616674206f722052464320616e6420616e792073746174656d656e74206d6164652077697468696e2074686520636f6e74657874206f6620616e204945544620616374697669747920697320636f6e7369646572656420616e20224945544620436f6e747269627574696f6e222e20537563682073746174656d656e747320696e636c756465206f72616c2073746174656d656e747320696e20494554462073657373696f6e732c2061732077656c6c206173207772697474656e20616e6420656c656374726f6e696320636f6d6d756e69636174696f6e73206d61646520617420616e792074696d65206f7220706c6163652c207768696368206172652061646472657373656420746f",
+ "a3fbf07df3fa2fde4f376ca23e82737041605d9f4f4f57bd8cff2c1d4b7955ec2a97948bd3722915c8f3d337f7d370050e9e96d647b7c39f56e031ca5eb6250d4042e02785ececfa4b4bb5e8ead0440e20b6e8db09d881a7c6132f420e52795042bdfa7773d8a9051447b3291ce1411c680465552aa6c405b7764d5e87bea85ad00f8449ed8f72d0d662ab052691ca66424bc86d2df80ea41f43abf937d3259dc4b2d0dfb48a6c9139ddd7f76966e928e635553ba76c5c879d7b35d49eb2e62b0871cdac638939e25e8a1e0ef9d5280fa8ca328b351c3c765989cbcf3daa8b6ccc3aaf9f3979c92b3720fc88dc95ed84a1be059c6499b9fda236e7e818b04b0bc39c1e876b193bfe5569753f88128cc08aaa9b63d1a16f80ef2554d7189c411f5869ca52c5b83fa36ff216b9c1d30062bebcfd2dc5bce0911934fda79a86f6e698ced759c3ff9b6477338f3da4f9cd8514ea9982ccafb341b2384dd902f3d1ab7ac61dd29c6f21ba5b862f3730e37cfdc4fd806c22f221"
+ },
+ {
+ "1c9240a5eb55d38af333888604f6b5f0473917c1402b80099dca5cbc207075c0",
+ "000000000000000000000002",
+ 42,
+ "2754776173206272696c6c69672c20616e642074686520736c6974687920746f7665730a446964206779726520616e642067696d626c6520696e2074686520776162653a0a416c6c206d696d737920776572652074686520626f726f676f7665732c0a416e6420746865206d6f6d65207261746873206f757467726162652e",
+ "62e6347f95ed87a45ffae7426f27a1df5fb69110044c0d73118effa95b01e5cf166d3df2d721caf9b21e5fb14c616871fd84c54f9d65b283196c7fe4f60553ebf39c6402c42234e32a356b3e764312a61a5532055716ead6962568f87d3f3f7704c6a8d1bcd1bf4d50d6154b6da731b187b58dfd728afa36757a797ac188d1"
+ },
+ { 0, 0, 0, 0, 0 }
+};
+
+static void
+test_ChaCha20_generic(const char *name, br_chacha20_run cr)
+{
+ size_t u;
+
+ printf("Test %s: ", name);
+ fflush(stdout);
+ if (cr == 0) {
+ printf("UNAVAILABLE\n");
+ return;
+ }
+
+ for (u = 0; KAT_CHACHA20[u].skey; u ++) {
+ unsigned char key[32], nonce[12], plain[400], cipher[400];
+ uint32_t cc;
+ size_t v, len;
+
+ hextobin(key, KAT_CHACHA20[u].skey);
+ hextobin(nonce, KAT_CHACHA20[u].snonce);
+ cc = KAT_CHACHA20[u].counter;
+ len = hextobin(plain, KAT_CHACHA20[u].splain);
+ hextobin(cipher, KAT_CHACHA20[u].scipher);
+
+ for (v = 0; v < len; v ++) {
+ unsigned char tmp[400];
+ size_t w;
+ uint32_t cc2;
+
+ memset(tmp, 0, sizeof tmp);
+ memcpy(tmp, plain, v);
+ if (cr(key, nonce, cc, tmp, v)
+ != cc + (uint32_t)((v + 63) >> 6))
+ {
+ fprintf(stderr, "ChaCha20: wrong counter\n");
+ exit(EXIT_FAILURE);
+ }
+ if (memcmp(tmp, cipher, v) != 0) {
+ fprintf(stderr, "ChaCha20 KAT fail (1)\n");
+ exit(EXIT_FAILURE);
+ }
+ for (w = v; w < sizeof tmp; w ++) {
+ if (tmp[w] != 0) {
+ fprintf(stderr, "ChaCha20: overrun\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+ for (w = 0, cc2 = cc; w < v; w += 64, cc2 ++) {
+ size_t x;
+
+ x = v - w;
+ if (x > 64) {
+ x = 64;
+ }
+ if (cr(key, nonce, cc2, tmp + w, x)
+ != (cc2 + 1))
+ {
+ fprintf(stderr, "ChaCha20:"
+ " wrong counter (2)\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+ if (memcmp(tmp, plain, v) != 0) {
+ fprintf(stderr, "ChaCha20 KAT fail (2)\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ printf(".");
+ fflush(stdout);
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+static void
+test_ChaCha20_ct(void)
+{
+ test_ChaCha20_generic("ChaCha20_ct", &br_chacha20_ct_run);
+}
+
+static void
+test_ChaCha20_sse2(void)
+{
+ test_ChaCha20_generic("ChaCha20_sse2", br_chacha20_sse2_get());
+}
+
+static const struct {
+ const char *splain;
+ const char *saad;
+ const char *skey;
+ const char *snonce;
+ const char *scipher;
+ const char *stag;
+} KAT_POLY1305[] = {
+ {
+ "4c616469657320616e642047656e746c656d656e206f662074686520636c617373206f66202739393a204966204920636f756c64206f6666657220796f75206f6e6c79206f6e652074697020666f7220746865206675747572652c2073756e73637265656e20776f756c642062652069742e",
+ "50515253c0c1c2c3c4c5c6c7",
+ "808182838485868788898a8b8c8d8e8f909192939495969798999a9b9c9d9e9f",
+ "070000004041424344454647",
+ "d31a8d34648e60db7b86afbc53ef7ec2a4aded51296e08fea9e2b5a736ee62d63dbea45e8ca9671282fafb69da92728b1a71de0a9e060b2905d6a5b67ecd3b3692ddbd7f2d778b8c9803aee328091b58fab324e4fad675945585808b4831d7bc3ff4def08e4b7a9de576d26586cec64b6116",
+ "1ae10b594f09e26a7e902ecbd0600691"
+ },
+ { 0, 0, 0, 0, 0, 0 }
+};
+
+static void
+test_Poly1305_inner(const char *name, br_poly1305_run ipoly,
+ br_poly1305_run iref)
+{
+ size_t u;
+ br_hmac_drbg_context rng;
+
+ printf("Test %s: ", name);
+ fflush(stdout);
+
+ for (u = 0; KAT_POLY1305[u].skey; u ++) {
+ unsigned char key[32], nonce[12], plain[400], cipher[400];
+ unsigned char aad[400], tag[16], data[400], tmp[16];
+ size_t len, aad_len;
+
+ len = hextobin(plain, KAT_POLY1305[u].splain);
+ aad_len = hextobin(aad, KAT_POLY1305[u].saad);
+ hextobin(key, KAT_POLY1305[u].skey);
+ hextobin(nonce, KAT_POLY1305[u].snonce);
+ hextobin(cipher, KAT_POLY1305[u].scipher);
+ hextobin(tag, KAT_POLY1305[u].stag);
+
+ memcpy(data, plain, len);
+ ipoly(key, nonce, data, len,
+ aad, aad_len, tmp, br_chacha20_ct_run, 1);
+ check_equals("ChaCha20+Poly1305 KAT (1)", data, cipher, len);
+ check_equals("ChaCha20+Poly1305 KAT (2)", tmp, tag, 16);
+ ipoly(key, nonce, data, len,
+ aad, aad_len, tmp, br_chacha20_ct_run, 0);
+ check_equals("ChaCha20+Poly1305 KAT (3)", data, plain, len);
+ check_equals("ChaCha20+Poly1305 KAT (4)", tmp, tag, 16);
+
+ printf(".");
+ fflush(stdout);
+ }
+
+ printf(" ");
+ fflush(stdout);
+
+ /*
+ * We compare the "ipoly" and "iref" implementations together on
+ * a bunch of pseudo-random messages.
+ */
+ br_hmac_drbg_init(&rng, &br_sha256_vtable, "seed for Poly1305", 17);
+ for (u = 0; u < 100; u ++) {
+ unsigned char plain[100], aad[100], tmp[100];
+ unsigned char key[32], iv[12], tag1[16], tag2[16];
+
+ br_hmac_drbg_generate(&rng, key, sizeof key);
+ br_hmac_drbg_generate(&rng, iv, sizeof iv);
+ br_hmac_drbg_generate(&rng, plain, u);
+ br_hmac_drbg_generate(&rng, aad, u);
+ memcpy(tmp, plain, u);
+ memset(tmp + u, 0xFF, (sizeof tmp) - u);
+ ipoly(key, iv, tmp, u, aad, u, tag1,
+ &br_chacha20_ct_run, 1);
+ memset(tmp + u, 0x00, (sizeof tmp) - u);
+ iref(key, iv, tmp, u, aad, u, tag2,
+ &br_chacha20_ct_run, 0);
+ if (memcmp(tmp, plain, u) != 0) {
+ fprintf(stderr, "cross enc/dec failed\n");
+ exit(EXIT_FAILURE);
+ }
+ if (memcmp(tag1, tag2, sizeof tag1) != 0) {
+ fprintf(stderr, "cross MAC failed\n");
+ exit(EXIT_FAILURE);
+ }
+ printf(".");
+ fflush(stdout);
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+static void
+test_Poly1305_ctmul(void)
+{
+ test_Poly1305_inner("Poly1305_ctmul", &br_poly1305_ctmul_run,
+ &br_poly1305_i15_run);
+}
+
+static void
+test_Poly1305_ctmul32(void)
+{
+ test_Poly1305_inner("Poly1305_ctmul32", &br_poly1305_ctmul32_run,
+ &br_poly1305_i15_run);
+}
+
+static void
+test_Poly1305_i15(void)
+{
+ test_Poly1305_inner("Poly1305_i15", &br_poly1305_i15_run,
+ &br_poly1305_ctmul_run);
+}
+
+static void
+test_Poly1305_ctmulq(void)
+{
+ br_poly1305_run bp;
+
+ bp = br_poly1305_ctmulq_get();
+ if (bp == 0) {
+ printf("Test Poly1305_ctmulq: UNAVAILABLE\n");
+ } else {
+ test_Poly1305_inner("Poly1305_ctmulq", bp,
+ &br_poly1305_ctmul_run);
+ }
+}
+
+/*
+ * A 1024-bit RSA key, generated with OpenSSL.
+ */
+static const unsigned char RSA_N[] = {
+ 0xBF, 0xB4, 0xA6, 0x2E, 0x87, 0x3F, 0x9C, 0x8D,
+ 0xA0, 0xC4, 0x2E, 0x7B, 0x59, 0x36, 0x0F, 0xB0,
+ 0xFF, 0xE1, 0x25, 0x49, 0xE5, 0xE6, 0x36, 0xB0,
+ 0x48, 0xC2, 0x08, 0x6B, 0x77, 0xA7, 0xC0, 0x51,
+ 0x66, 0x35, 0x06, 0xA9, 0x59, 0xDF, 0x17, 0x7F,
+ 0x15, 0xF6, 0xB4, 0xE5, 0x44, 0xEE, 0x72, 0x3C,
+ 0x53, 0x11, 0x52, 0xC9, 0xC9, 0x61, 0x4F, 0x92,
+ 0x33, 0x64, 0x70, 0x43, 0x07, 0xF1, 0x3F, 0x7F,
+ 0x15, 0xAC, 0xF0, 0xC1, 0x54, 0x7D, 0x55, 0xC0,
+ 0x29, 0xDC, 0x9E, 0xCC, 0xE4, 0x1D, 0x11, 0x72,
+ 0x45, 0xF4, 0xD2, 0x70, 0xFC, 0x34, 0xB2, 0x1F,
+ 0xF3, 0xAD, 0x6A, 0xF0, 0xE5, 0x56, 0x11, 0xF8,
+ 0x0C, 0x3A, 0x8B, 0x04, 0x46, 0x7C, 0x77, 0xD9,
+ 0x41, 0x1F, 0x40, 0xBE, 0x93, 0x80, 0x9D, 0x23,
+ 0x75, 0x80, 0x12, 0x26, 0x5A, 0x72, 0x1C, 0xDD,
+ 0x47, 0xB3, 0x2A, 0x33, 0xD8, 0x19, 0x61, 0xE3
+};
+static const unsigned char RSA_E[] = {
+ 0x01, 0x00, 0x01
+};
+/* unused
+static const unsigned char RSA_D[] = {
+ 0xAE, 0x56, 0x0B, 0x56, 0x7E, 0xDA, 0x83, 0x75,
+ 0x6C, 0xC1, 0x5C, 0x00, 0x02, 0x96, 0x1E, 0x58,
+ 0xF9, 0xA9, 0xF7, 0x2E, 0x27, 0xEB, 0x5E, 0xCA,
+ 0x9B, 0xB0, 0x10, 0xD6, 0x22, 0x7F, 0xA4, 0x6E,
+ 0xA2, 0x03, 0x10, 0xE6, 0xCB, 0x7B, 0x0D, 0x34,
+ 0x1E, 0x76, 0x37, 0xF5, 0xD3, 0xE5, 0x00, 0x70,
+ 0x09, 0x9E, 0xD4, 0x69, 0xFB, 0x40, 0x0A, 0x8B,
+ 0xCB, 0x3E, 0xC8, 0xB4, 0xBC, 0xB1, 0x50, 0xEA,
+ 0x9D, 0xD9, 0x89, 0x8A, 0x98, 0x40, 0x79, 0xD1,
+ 0x07, 0x66, 0xA7, 0x90, 0x63, 0x82, 0xB1, 0xE0,
+ 0x24, 0xD0, 0x89, 0x6A, 0xEC, 0xC5, 0xF3, 0x21,
+ 0x7D, 0xB8, 0xA5, 0x45, 0x3A, 0x3B, 0x34, 0x42,
+ 0xC2, 0x82, 0x3C, 0x8D, 0xFA, 0x5D, 0xA0, 0xA8,
+ 0x24, 0xC8, 0x40, 0x22, 0x19, 0xCB, 0xB5, 0x85,
+ 0x67, 0x69, 0x60, 0xE4, 0xD0, 0x7E, 0xA3, 0x3B,
+ 0xF7, 0x70, 0x50, 0xC9, 0x5C, 0x97, 0x29, 0x49
+};
+*/
+static const unsigned char RSA_P[] = {
+ 0xF2, 0xE7, 0x6F, 0x66, 0x2E, 0xC4, 0x03, 0xD4,
+ 0x89, 0x24, 0xCC, 0xE1, 0xCD, 0x3F, 0x01, 0x82,
+ 0xC1, 0xFB, 0xAF, 0x44, 0xFA, 0xCC, 0x0E, 0xAA,
+ 0x9D, 0x74, 0xA9, 0x65, 0xEF, 0xED, 0x4C, 0x87,
+ 0xF0, 0xB3, 0xC6, 0xEA, 0x61, 0x85, 0xDE, 0x4E,
+ 0x66, 0xB2, 0x5A, 0x9F, 0x7A, 0x41, 0xC5, 0x66,
+ 0x57, 0xDF, 0x88, 0xF0, 0xB5, 0xF2, 0xC7, 0x7E,
+ 0xE6, 0x55, 0x21, 0x96, 0x83, 0xD8, 0xAB, 0x57
+};
+static const unsigned char RSA_Q[] = {
+ 0xCA, 0x0A, 0x92, 0xBF, 0x58, 0xB0, 0x2E, 0xF6,
+ 0x66, 0x50, 0xB1, 0x48, 0x29, 0x42, 0x86, 0x6C,
+ 0x98, 0x06, 0x7E, 0xB8, 0xB5, 0x4F, 0xFB, 0xC4,
+ 0xF3, 0xC3, 0x36, 0x91, 0x07, 0xB6, 0xDB, 0xE9,
+ 0x56, 0x3C, 0x51, 0x7D, 0xB5, 0xEC, 0x0A, 0xA9,
+ 0x7C, 0x66, 0xF9, 0xD8, 0x25, 0xDE, 0xD2, 0x94,
+ 0x5A, 0x58, 0xF1, 0x93, 0xE4, 0xF0, 0x5F, 0x27,
+ 0xBD, 0x83, 0xC7, 0xCA, 0x48, 0x6A, 0xB2, 0x55
+};
+static const unsigned char RSA_DP[] = {
+ 0xAF, 0x97, 0xBE, 0x60, 0x0F, 0xCE, 0x83, 0x36,
+ 0x51, 0x2D, 0xD9, 0x2E, 0x22, 0x41, 0x39, 0xC6,
+ 0x5C, 0x94, 0xA4, 0xCF, 0x28, 0xBD, 0xFA, 0x9C,
+ 0x3B, 0xD6, 0xE9, 0xDE, 0x56, 0xE3, 0x24, 0x3F,
+ 0xE1, 0x31, 0x14, 0xCA, 0xBA, 0x55, 0x1B, 0xAF,
+ 0x71, 0x6D, 0xDD, 0x35, 0x0C, 0x1C, 0x1F, 0xA7,
+ 0x2C, 0x3E, 0xDB, 0xAF, 0xA6, 0xD8, 0x2A, 0x7F,
+ 0x01, 0xE2, 0xE8, 0xB4, 0xF5, 0xFA, 0xDB, 0x61
+};
+static const unsigned char RSA_DQ[] = {
+ 0x29, 0xC0, 0x4B, 0x98, 0xFD, 0x13, 0xD3, 0x70,
+ 0x99, 0xAE, 0x1D, 0x24, 0x83, 0x5A, 0x3A, 0xFB,
+ 0x1F, 0xE3, 0x5F, 0xB6, 0x7D, 0xC9, 0x5C, 0x86,
+ 0xD3, 0xB4, 0xC8, 0x86, 0xE9, 0xE8, 0x30, 0xC3,
+ 0xA4, 0x4D, 0x6C, 0xAD, 0xA4, 0xB5, 0x75, 0x72,
+ 0x96, 0xC1, 0x94, 0xE9, 0xC4, 0xD1, 0xAA, 0x04,
+ 0x7C, 0x33, 0x1B, 0x20, 0xEB, 0xD3, 0x7C, 0x66,
+ 0x72, 0xF4, 0x53, 0x8A, 0x0A, 0xB2, 0xF9, 0xCD
+};
+static const unsigned char RSA_IQ[] = {
+ 0xE8, 0xEB, 0x04, 0x79, 0xA5, 0xC1, 0x79, 0xDE,
+ 0xD5, 0x49, 0xA1, 0x0B, 0x48, 0xB9, 0x0E, 0x55,
+ 0x74, 0x2C, 0x54, 0xEE, 0xA8, 0xB0, 0x01, 0xC2,
+ 0xD2, 0x3C, 0x3E, 0x47, 0x3A, 0x7C, 0xC8, 0x3D,
+ 0x2E, 0x33, 0x54, 0x4D, 0x40, 0x29, 0x41, 0x74,
+ 0xBA, 0xE1, 0x93, 0x09, 0xEC, 0xE0, 0x1B, 0x4D,
+ 0x1F, 0x2A, 0xCA, 0x4A, 0x0B, 0x5F, 0xE6, 0xBE,
+ 0x59, 0x0A, 0xC4, 0xC9, 0xD9, 0x82, 0xAC, 0xE1
+};
+
+static const br_rsa_public_key RSA_PK = {
+ (void *)RSA_N, sizeof RSA_N,
+ (void *)RSA_E, sizeof RSA_E
+};
+
+static const br_rsa_private_key RSA_SK = {
+ 1024,
+ (void *)RSA_P, sizeof RSA_P,
+ (void *)RSA_Q, sizeof RSA_Q,
+ (void *)RSA_DP, sizeof RSA_DP,
+ (void *)RSA_DQ, sizeof RSA_DQ,
+ (void *)RSA_IQ, sizeof RSA_IQ
+};
+
+/*
+ * A 2048-bit RSA key, generated with OpenSSL.
+ */
+static const unsigned char RSA2048_N[] = {
+ 0xEA, 0xB1, 0xB0, 0x87, 0x60, 0xE2, 0x69, 0xF5,
+ 0xC9, 0x3F, 0xCB, 0x4F, 0x9E, 0x7D, 0xD0, 0x56,
+ 0x54, 0x8F, 0xF5, 0x59, 0x97, 0x04, 0x3F, 0x30,
+ 0xE1, 0xFB, 0x7B, 0xF5, 0xA0, 0xEB, 0xA7, 0x7B,
+ 0x29, 0x96, 0x7B, 0x32, 0x48, 0x48, 0xA4, 0x99,
+ 0x90, 0x92, 0x48, 0xFB, 0xDC, 0xEC, 0x8A, 0x3B,
+ 0xE0, 0x57, 0x6E, 0xED, 0x1C, 0x5B, 0x78, 0xCF,
+ 0x07, 0x41, 0x96, 0x4C, 0x2F, 0xA2, 0xD1, 0xC8,
+ 0xA0, 0x5F, 0xFC, 0x2A, 0x5B, 0x3F, 0xBC, 0xD7,
+ 0xE6, 0x91, 0xF1, 0x44, 0xD6, 0xD8, 0x41, 0x66,
+ 0x3E, 0x80, 0xEE, 0x98, 0x73, 0xD5, 0x32, 0x60,
+ 0x7F, 0xDF, 0xBF, 0xB2, 0x0B, 0xA5, 0xCA, 0x11,
+ 0x88, 0x1A, 0x0E, 0xA1, 0x61, 0x4C, 0x5A, 0x70,
+ 0xCE, 0x12, 0xC0, 0x61, 0xF5, 0x50, 0x0E, 0xF6,
+ 0xC1, 0xC2, 0x88, 0x8B, 0xE5, 0xCE, 0xAE, 0x90,
+ 0x65, 0x23, 0xA7, 0xAD, 0xCB, 0x04, 0x17, 0x00,
+ 0xA2, 0xDB, 0xB0, 0x21, 0x49, 0xDD, 0x3C, 0x2E,
+ 0x8C, 0x47, 0x27, 0xF2, 0x84, 0x51, 0x63, 0xEB,
+ 0xF8, 0xAF, 0x63, 0xA7, 0x89, 0xE1, 0xF0, 0x2F,
+ 0xF9, 0x9C, 0x0A, 0x8A, 0xBC, 0x57, 0x05, 0xB0,
+ 0xEF, 0xA0, 0xDA, 0x67, 0x70, 0xAF, 0x3F, 0xA4,
+ 0x92, 0xFC, 0x4A, 0xAC, 0xEF, 0x89, 0x41, 0x58,
+ 0x57, 0x63, 0x0F, 0x6A, 0x89, 0x68, 0x45, 0x4C,
+ 0x20, 0xF9, 0x7F, 0x50, 0x9D, 0x8C, 0x52, 0xC4,
+ 0xC1, 0x33, 0xCD, 0x42, 0x35, 0x12, 0xEC, 0x82,
+ 0xF9, 0xC1, 0xB7, 0x60, 0x7B, 0x52, 0x61, 0xD0,
+ 0xAE, 0xFD, 0x4B, 0x68, 0xB1, 0x55, 0x0E, 0xAB,
+ 0x99, 0x24, 0x52, 0x60, 0x8E, 0xDB, 0x90, 0x34,
+ 0x61, 0xE3, 0x95, 0x7C, 0x34, 0x64, 0x06, 0xCB,
+ 0x44, 0x17, 0x70, 0x78, 0xC1, 0x1B, 0x87, 0x8F,
+ 0xCF, 0xB0, 0x7D, 0x93, 0x59, 0x84, 0x49, 0xF5,
+ 0x55, 0xBB, 0x48, 0xCA, 0xD3, 0x76, 0x1E, 0x7F
+};
+static const unsigned char RSA2048_E[] = {
+ 0x01, 0x00, 0x01
+};
+static const unsigned char RSA2048_P[] = {
+ 0xF9, 0xA7, 0xB5, 0xC4, 0xE8, 0x52, 0xEC, 0xB1,
+ 0x33, 0x6A, 0x68, 0x32, 0x63, 0x2D, 0xBA, 0xE5,
+ 0x61, 0x14, 0x69, 0x82, 0xC8, 0x31, 0x14, 0xD5,
+ 0xC2, 0x6C, 0x1A, 0xBE, 0xA0, 0x68, 0xA6, 0xC5,
+ 0xEA, 0x40, 0x59, 0xFB, 0x0A, 0x30, 0x3D, 0xD5,
+ 0xDD, 0x94, 0xAE, 0x0C, 0x9F, 0xEE, 0x19, 0x0C,
+ 0xA8, 0xF2, 0x85, 0x27, 0x60, 0xAA, 0xD5, 0x7C,
+ 0x59, 0x91, 0x1F, 0xAF, 0x5E, 0x00, 0xC8, 0x2D,
+ 0xCA, 0xB4, 0x70, 0xA1, 0xF8, 0x8C, 0x0A, 0xB3,
+ 0x08, 0x95, 0x03, 0x9E, 0xA4, 0x6B, 0x9D, 0x55,
+ 0x47, 0xE0, 0xEC, 0xB3, 0x21, 0x7C, 0xE4, 0x16,
+ 0x91, 0xE3, 0xD7, 0x1B, 0x3D, 0x81, 0xF1, 0xED,
+ 0x16, 0xF9, 0x05, 0x0E, 0xA6, 0x9F, 0x37, 0x73,
+ 0x18, 0x1B, 0x9C, 0x9D, 0x33, 0xAD, 0x25, 0xEF,
+ 0x3A, 0xC0, 0x4B, 0x34, 0x24, 0xF5, 0xFD, 0x59,
+ 0xF5, 0x65, 0xE6, 0x92, 0x2A, 0x04, 0x06, 0x3D
+};
+static const unsigned char RSA2048_Q[] = {
+ 0xF0, 0xA8, 0xA4, 0x20, 0xDD, 0xF3, 0x99, 0xE6,
+ 0x1C, 0xB1, 0x21, 0xE8, 0x66, 0x68, 0x48, 0x00,
+ 0x04, 0xE3, 0x21, 0xA3, 0xE8, 0xC5, 0xFD, 0x85,
+ 0x6D, 0x2C, 0x98, 0xE3, 0x36, 0x39, 0x3E, 0x80,
+ 0xB7, 0x36, 0xA5, 0xA9, 0xBB, 0xEB, 0x1E, 0xB8,
+ 0xEB, 0x44, 0x65, 0xE8, 0x81, 0x7D, 0xE0, 0x87,
+ 0xC1, 0x08, 0x94, 0xDD, 0x92, 0x40, 0xF4, 0x8B,
+ 0x3C, 0xB5, 0xC1, 0xAD, 0x9D, 0x4C, 0x14, 0xCD,
+ 0xD9, 0x2D, 0xB6, 0xE4, 0x99, 0xB3, 0x71, 0x63,
+ 0x64, 0xE1, 0x31, 0x7E, 0x34, 0x95, 0x96, 0x52,
+ 0x85, 0x27, 0xBE, 0x40, 0x10, 0x0A, 0x9E, 0x01,
+ 0x1C, 0xBB, 0xB2, 0x5B, 0x40, 0x85, 0x65, 0x6E,
+ 0xA0, 0x88, 0x73, 0xF6, 0x22, 0xCC, 0x23, 0x26,
+ 0x62, 0xAD, 0x92, 0x57, 0x57, 0xF4, 0xD4, 0xDF,
+ 0xD9, 0x7C, 0xDE, 0xAD, 0xD2, 0x1F, 0x32, 0x29,
+ 0xBA, 0xE7, 0xE2, 0x32, 0xA1, 0xA0, 0xBF, 0x6B
+};
+static const unsigned char RSA2048_DP[] = {
+ 0xB2, 0xF9, 0xD7, 0x66, 0xC5, 0x83, 0x05, 0x6A,
+ 0x77, 0xC8, 0xB5, 0xD0, 0x41, 0xA7, 0xBC, 0x0F,
+ 0xCB, 0x4B, 0xFD, 0xE4, 0x23, 0x2E, 0x84, 0x98,
+ 0x46, 0x1C, 0x88, 0x03, 0xD7, 0x2D, 0x8F, 0x39,
+ 0xDD, 0x98, 0xAA, 0xA9, 0x3D, 0x01, 0x9E, 0xA2,
+ 0xDE, 0x8A, 0x43, 0x48, 0x8B, 0xB2, 0xFE, 0xC4,
+ 0x43, 0xAE, 0x31, 0x65, 0x2C, 0x78, 0xEC, 0x39,
+ 0x8C, 0x60, 0x6C, 0xCD, 0xA4, 0xDF, 0x7C, 0xA2,
+ 0xCF, 0x6A, 0x12, 0x41, 0x1B, 0xD5, 0x11, 0xAA,
+ 0x8D, 0xE1, 0x7E, 0x49, 0xD1, 0xE7, 0xD0, 0x50,
+ 0x1E, 0x0A, 0x92, 0xC6, 0x4C, 0xA0, 0xA3, 0x47,
+ 0xC6, 0xE9, 0x07, 0x01, 0xE1, 0x53, 0x72, 0x23,
+ 0x9D, 0x4F, 0x82, 0x9F, 0xA1, 0x36, 0x0D, 0x63,
+ 0x76, 0x89, 0xFC, 0xF9, 0xF9, 0xDD, 0x0C, 0x8F,
+ 0xF7, 0x97, 0x79, 0x92, 0x75, 0x58, 0xE0, 0x7B,
+ 0x08, 0x61, 0x38, 0x2D, 0xDA, 0xEF, 0x2D, 0xA5
+};
+static const unsigned char RSA2048_DQ[] = {
+ 0x8B, 0x69, 0x56, 0x33, 0x08, 0x00, 0x8F, 0x3D,
+ 0xC3, 0x8F, 0x45, 0x52, 0x48, 0xC8, 0xCE, 0x34,
+ 0xDC, 0x9F, 0xEB, 0x23, 0xF5, 0xBB, 0x84, 0x62,
+ 0xDF, 0xDC, 0xBE, 0xF0, 0x98, 0xBF, 0xCE, 0x9A,
+ 0x68, 0x08, 0x4B, 0x2D, 0xA9, 0x83, 0xC9, 0xF7,
+ 0x5B, 0xAA, 0xF2, 0xD2, 0x1E, 0xF9, 0x99, 0xB1,
+ 0x6A, 0xBC, 0x9A, 0xE8, 0x44, 0x4A, 0x46, 0x9F,
+ 0xC6, 0x5A, 0x90, 0x49, 0x0F, 0xDF, 0x3C, 0x0A,
+ 0x07, 0x6E, 0xB9, 0x0D, 0x72, 0x90, 0x85, 0xF6,
+ 0x0B, 0x41, 0x7D, 0x17, 0x5C, 0x44, 0xEF, 0xA0,
+ 0xFC, 0x2C, 0x0A, 0xC5, 0x37, 0xC5, 0xBE, 0xC4,
+ 0x6C, 0x2D, 0xBB, 0x63, 0xAB, 0x5B, 0xDB, 0x67,
+ 0x9B, 0xAD, 0x90, 0x67, 0x9C, 0xBE, 0xDE, 0xF9,
+ 0xE4, 0x9E, 0x22, 0x31, 0x60, 0xED, 0x9E, 0xC7,
+ 0xD2, 0x48, 0xC9, 0x02, 0xAE, 0xBF, 0x8D, 0xA2,
+ 0xA8, 0xF8, 0x9D, 0x8B, 0xB1, 0x1F, 0xDA, 0xE3
+};
+static const unsigned char RSA2048_IQ[] = {
+ 0xB5, 0x48, 0xD4, 0x48, 0x5A, 0x33, 0xCD, 0x13,
+ 0xFE, 0xC6, 0xF7, 0x01, 0x0A, 0x3E, 0x40, 0xA3,
+ 0x45, 0x94, 0x6F, 0x85, 0xE4, 0x68, 0x66, 0xEC,
+ 0x69, 0x6A, 0x3E, 0xE0, 0x62, 0x3F, 0x0C, 0xEF,
+ 0x21, 0xCC, 0xDA, 0xAD, 0x75, 0x98, 0x12, 0xCA,
+ 0x9E, 0x31, 0xDD, 0x95, 0x0D, 0xBD, 0x55, 0xEB,
+ 0x92, 0xF7, 0x9E, 0xBD, 0xFC, 0x28, 0x35, 0x96,
+ 0x31, 0xDC, 0x53, 0x80, 0xA3, 0x57, 0x89, 0x3C,
+ 0x4A, 0xEC, 0x40, 0x75, 0x13, 0xAC, 0x4F, 0x36,
+ 0x3A, 0x86, 0x9A, 0xA6, 0x58, 0xC9, 0xED, 0xCB,
+ 0xD6, 0xBB, 0xB2, 0xD9, 0xAA, 0x04, 0xC4, 0xE8,
+ 0x47, 0x3E, 0xBD, 0x14, 0x9B, 0x8F, 0x61, 0x70,
+ 0x69, 0x66, 0x23, 0x62, 0x18, 0xE3, 0x52, 0x98,
+ 0xE3, 0x22, 0xE9, 0x6F, 0xDA, 0x28, 0x68, 0x08,
+ 0xB8, 0xB9, 0x8B, 0x97, 0x8B, 0x77, 0x3F, 0xCA,
+ 0x9D, 0x9D, 0xBE, 0xD5, 0x2D, 0x3E, 0xC2, 0x11
+};
+
+static const br_rsa_public_key RSA2048_PK = {
+ (void *)RSA2048_N, sizeof RSA2048_N,
+ (void *)RSA2048_E, sizeof RSA2048_E
+};
+
+static const br_rsa_private_key RSA2048_SK = {
+ 2048,
+ (void *)RSA2048_P, sizeof RSA2048_P,
+ (void *)RSA2048_Q, sizeof RSA2048_Q,
+ (void *)RSA2048_DP, sizeof RSA2048_DP,
+ (void *)RSA2048_DQ, sizeof RSA2048_DQ,
+ (void *)RSA2048_IQ, sizeof RSA2048_IQ
+};
+
+/*
+ * A 4096-bit RSA key, generated with OpenSSL.
+ */
+static const unsigned char RSA4096_N[] = {
+ 0xAA, 0x17, 0x71, 0xBC, 0x92, 0x3E, 0xB5, 0xBD,
+ 0x3E, 0x64, 0xCF, 0x03, 0x9B, 0x24, 0x65, 0x33,
+ 0x5F, 0xB4, 0x47, 0x89, 0xE5, 0x63, 0xE4, 0xA0,
+ 0x5A, 0x51, 0x95, 0x07, 0x73, 0xEE, 0x00, 0xF6,
+ 0x3E, 0x31, 0x0E, 0xDA, 0x15, 0xC3, 0xAA, 0x21,
+ 0x6A, 0xCD, 0xFF, 0x46, 0x6B, 0xDF, 0x0A, 0x7F,
+ 0x8A, 0xC2, 0x25, 0x19, 0x47, 0x44, 0xD8, 0x52,
+ 0xC1, 0x56, 0x25, 0x6A, 0xE0, 0xD2, 0x61, 0x11,
+ 0x2C, 0xF7, 0x73, 0x9F, 0x5F, 0x74, 0xAA, 0xDD,
+ 0xDE, 0xAF, 0x81, 0xF6, 0x0C, 0x1A, 0x3A, 0xF9,
+ 0xC5, 0x47, 0x82, 0x75, 0x1D, 0x41, 0xF0, 0xB2,
+ 0xFD, 0xBA, 0xE2, 0xA4, 0xA1, 0xB8, 0x32, 0x48,
+ 0x06, 0x0D, 0x29, 0x2F, 0x44, 0x14, 0xF5, 0xAC,
+ 0x54, 0x83, 0xC4, 0xB6, 0x85, 0x85, 0x9B, 0x1C,
+ 0x05, 0x61, 0x28, 0x62, 0x24, 0xA8, 0xF0, 0xE6,
+ 0x80, 0xA7, 0x91, 0xE8, 0xC7, 0x8E, 0x52, 0x17,
+ 0xBE, 0xAF, 0xC6, 0x0A, 0xA3, 0xFB, 0xD1, 0x04,
+ 0x15, 0x3B, 0x14, 0x35, 0xA5, 0x41, 0xF5, 0x30,
+ 0xFE, 0xEF, 0x53, 0xA7, 0x89, 0x91, 0x78, 0x30,
+ 0xBE, 0x3A, 0xB1, 0x4B, 0x2E, 0x4A, 0x0E, 0x25,
+ 0x1D, 0xCF, 0x51, 0x54, 0x52, 0xF1, 0x88, 0x85,
+ 0x36, 0x23, 0xDE, 0xBA, 0x66, 0x25, 0x60, 0x8D,
+ 0x45, 0xD7, 0xD8, 0x10, 0x41, 0x64, 0xC7, 0x4B,
+ 0xCE, 0x72, 0x13, 0xD7, 0x20, 0xF8, 0x2A, 0x74,
+ 0xA5, 0x05, 0xF4, 0x5A, 0x90, 0xF4, 0x9C, 0xE7,
+ 0xC9, 0xCF, 0x1E, 0xD5, 0x9C, 0xAC, 0xE5, 0x00,
+ 0x83, 0x73, 0x9F, 0xE7, 0xC6, 0x93, 0xC0, 0x06,
+ 0xA7, 0xB8, 0xF8, 0x46, 0x90, 0xC8, 0x78, 0x27,
+ 0x2E, 0xCC, 0xC0, 0x2A, 0x20, 0xC5, 0xFC, 0x63,
+ 0x22, 0xA1, 0xD6, 0x16, 0xAD, 0x9C, 0xD6, 0xFC,
+ 0x7A, 0x6E, 0x9C, 0x98, 0x51, 0xEE, 0x6B, 0x6D,
+ 0x8F, 0xEF, 0xCE, 0x7C, 0x5D, 0x16, 0xB0, 0xCE,
+ 0x9C, 0xEE, 0x92, 0xCF, 0xB7, 0xEB, 0x41, 0x36,
+ 0x3A, 0x6C, 0xF2, 0x0D, 0x26, 0x11, 0x2F, 0x6C,
+ 0x27, 0x62, 0xA2, 0xCC, 0x63, 0x53, 0xBD, 0xFC,
+ 0x9F, 0xBE, 0x9B, 0xBD, 0xE5, 0xA7, 0xDA, 0xD4,
+ 0xF8, 0xED, 0x5E, 0x59, 0x2D, 0xAC, 0xCD, 0x13,
+ 0xEB, 0xE5, 0x9E, 0x39, 0x82, 0x8B, 0xFD, 0xA8,
+ 0xFB, 0xCB, 0x86, 0x27, 0xC7, 0x4B, 0x4C, 0xD0,
+ 0xBA, 0x12, 0xD0, 0x76, 0x1A, 0xDB, 0x30, 0xC5,
+ 0xB3, 0x2C, 0x4C, 0xC5, 0x32, 0x03, 0x05, 0x67,
+ 0x8D, 0xD0, 0x14, 0x37, 0x59, 0x2B, 0xE3, 0x1C,
+ 0x25, 0x3E, 0xA5, 0xE4, 0xF1, 0x0D, 0x34, 0xBB,
+ 0xD5, 0xF6, 0x76, 0x45, 0x5B, 0x0F, 0x1E, 0x07,
+ 0x0A, 0xBA, 0x9D, 0x71, 0x87, 0xDE, 0x45, 0x50,
+ 0xE5, 0x0F, 0x32, 0xBB, 0x5C, 0x32, 0x2D, 0x40,
+ 0xCD, 0x19, 0x95, 0x4E, 0xC5, 0x54, 0x3A, 0x9A,
+ 0x46, 0x9B, 0x85, 0xFE, 0x53, 0xB7, 0xD8, 0x65,
+ 0x6D, 0x68, 0x0C, 0xBB, 0xE3, 0x3D, 0x8E, 0x64,
+ 0xBE, 0x27, 0x15, 0xAB, 0x12, 0x20, 0xD9, 0x84,
+ 0xF5, 0x02, 0xE4, 0xBB, 0xDD, 0xAB, 0x59, 0x51,
+ 0xF4, 0xE1, 0x79, 0xBE, 0xB8, 0xA3, 0x8E, 0xD1,
+ 0x1C, 0xB0, 0xFA, 0x48, 0x76, 0xC2, 0x9D, 0x7A,
+ 0x01, 0xA5, 0xAF, 0x8C, 0xBA, 0xAA, 0x4C, 0x06,
+ 0x2B, 0x0A, 0x62, 0xF0, 0x79, 0x5B, 0x42, 0xFC,
+ 0xF8, 0xBF, 0xD4, 0xDD, 0x62, 0x32, 0xE3, 0xCE,
+ 0xF1, 0x2C, 0xE6, 0xED, 0xA8, 0x8A, 0x41, 0xA3,
+ 0xC1, 0x1E, 0x07, 0xB6, 0x43, 0x10, 0x80, 0xB7,
+ 0xF3, 0xD0, 0x53, 0x2A, 0x9A, 0x98, 0xA7, 0x4F,
+ 0x9E, 0xA3, 0x3E, 0x1B, 0xDA, 0x93, 0x15, 0xF2,
+ 0xF4, 0x20, 0xA5, 0xA8, 0x4F, 0x8A, 0xBA, 0xED,
+ 0xB1, 0x17, 0x6C, 0x0F, 0xD9, 0x8F, 0x38, 0x11,
+ 0xF3, 0xD9, 0x5E, 0x88, 0xA1, 0xA1, 0x82, 0x8B,
+ 0x30, 0xD7, 0xC6, 0xCE, 0x4E, 0x30, 0x55, 0x57
+};
+static const unsigned char RSA4096_E[] = {
+ 0x01, 0x00, 0x01
+};
+static const unsigned char RSA4096_P[] = {
+ 0xD3, 0x7A, 0x22, 0xD8, 0x9B, 0xBF, 0x42, 0xB4,
+ 0x53, 0x04, 0x10, 0x6A, 0x84, 0xFD, 0x7C, 0x1D,
+ 0xF6, 0xF4, 0x10, 0x65, 0xAA, 0xE5, 0xE1, 0x4E,
+ 0xB4, 0x37, 0xF7, 0xAC, 0xF7, 0xD3, 0xB2, 0x3B,
+ 0xFE, 0xE7, 0x63, 0x42, 0xE9, 0xF0, 0x3C, 0xE0,
+ 0x42, 0xB4, 0xBB, 0x09, 0xD0, 0xB2, 0x7C, 0x70,
+ 0xA4, 0x11, 0x97, 0x90, 0x01, 0xD0, 0x0E, 0x7B,
+ 0xAF, 0x7D, 0x30, 0x4E, 0x6B, 0x3A, 0xCC, 0x50,
+ 0x4E, 0xAF, 0x2F, 0xC3, 0xC2, 0x4F, 0x7E, 0xC5,
+ 0xB3, 0x76, 0x33, 0xFB, 0xA7, 0xB1, 0x96, 0xA5,
+ 0x46, 0x41, 0xC6, 0xDA, 0x5A, 0xFD, 0x17, 0x0A,
+ 0x6A, 0x86, 0x54, 0x83, 0xE1, 0x57, 0xE7, 0xAF,
+ 0x8C, 0x42, 0xE5, 0x39, 0xF2, 0xC7, 0xFC, 0x4A,
+ 0x3D, 0x3C, 0x94, 0x89, 0xC2, 0xC6, 0x2D, 0x0A,
+ 0x5F, 0xD0, 0x21, 0x23, 0x5C, 0xC9, 0xC8, 0x44,
+ 0x8A, 0x96, 0x72, 0x4D, 0x96, 0xC6, 0x17, 0x0C,
+ 0x36, 0x43, 0x7F, 0xD8, 0xA0, 0x7A, 0x31, 0x7E,
+ 0xCE, 0x13, 0xE3, 0x13, 0x2E, 0xE0, 0x91, 0xC2,
+ 0x61, 0x13, 0x16, 0x8D, 0x99, 0xCB, 0xA9, 0x2C,
+ 0x4D, 0x9D, 0xDD, 0x1D, 0x03, 0xE7, 0xA7, 0x50,
+ 0xF4, 0x16, 0x43, 0xB1, 0x7F, 0x99, 0x61, 0x3F,
+ 0xA5, 0x59, 0x91, 0x16, 0xC3, 0x06, 0x63, 0x59,
+ 0xE9, 0xDA, 0xB5, 0x06, 0x2E, 0x0C, 0xD9, 0xAB,
+ 0x93, 0x89, 0x12, 0x82, 0xFB, 0x90, 0xD9, 0x30,
+ 0x60, 0xF7, 0x35, 0x2D, 0x18, 0x78, 0xEB, 0x2B,
+ 0xA1, 0x06, 0x67, 0x37, 0xDE, 0x72, 0x20, 0xD2,
+ 0x80, 0xE5, 0x2C, 0xD7, 0x5E, 0xC7, 0x67, 0x2D,
+ 0x40, 0xE7, 0x7A, 0xCF, 0x4A, 0x69, 0x9D, 0xA7,
+ 0x90, 0x9F, 0x3B, 0xDF, 0x07, 0x97, 0x64, 0x69,
+ 0x06, 0x4F, 0xBA, 0xF4, 0xE5, 0xBD, 0x71, 0x60,
+ 0x36, 0xB7, 0xA3, 0xDE, 0x76, 0xC5, 0x38, 0xD7,
+ 0x1D, 0x9A, 0xFC, 0x36, 0x3D, 0x3B, 0xDC, 0xCF
+};
+static const unsigned char RSA4096_Q[] = {
+ 0xCD, 0xE6, 0xC6, 0xA6, 0x42, 0x4C, 0x45, 0x65,
+ 0x8B, 0x85, 0x76, 0xFC, 0x21, 0xB6, 0x57, 0x79,
+ 0x3C, 0xE4, 0xE3, 0x85, 0x55, 0x2F, 0x59, 0xD3,
+ 0x3F, 0x74, 0xAF, 0x9F, 0x11, 0x04, 0x10, 0x8B,
+ 0xF9, 0x5F, 0x4D, 0x25, 0xEE, 0x20, 0xF9, 0x69,
+ 0x3B, 0x02, 0xB6, 0x43, 0x0D, 0x0C, 0xED, 0x30,
+ 0x31, 0x57, 0xE7, 0x9A, 0x57, 0x24, 0x6B, 0x4A,
+ 0x5E, 0xA2, 0xBF, 0xD4, 0x47, 0x7D, 0xFA, 0x78,
+ 0x51, 0x86, 0x80, 0x68, 0x85, 0x7C, 0x7B, 0x08,
+ 0x4A, 0x35, 0x24, 0x4F, 0x8B, 0x24, 0x49, 0xF8,
+ 0x16, 0x06, 0x9C, 0x57, 0x4E, 0x94, 0x4C, 0xBD,
+ 0x6E, 0x53, 0x52, 0xC9, 0xC1, 0x64, 0x43, 0x22,
+ 0x1E, 0xDD, 0xEB, 0xAC, 0x90, 0x58, 0xCA, 0xBA,
+ 0x9C, 0xAC, 0xCF, 0xDD, 0x08, 0x6D, 0xB7, 0x31,
+ 0xDB, 0x0D, 0x83, 0xE6, 0x50, 0xA6, 0x69, 0xB1,
+ 0x1C, 0x68, 0x92, 0xB4, 0xB5, 0x76, 0xDE, 0xBD,
+ 0x4F, 0xA5, 0x30, 0xED, 0x23, 0xFF, 0xE5, 0x80,
+ 0x21, 0xAB, 0xED, 0xE6, 0xDC, 0x32, 0x3D, 0xF7,
+ 0x45, 0xB8, 0x19, 0x3D, 0x8E, 0x15, 0x7C, 0xE5,
+ 0x0D, 0xC8, 0x9B, 0x7D, 0x1F, 0x7C, 0x14, 0x14,
+ 0x41, 0x09, 0xA7, 0xEB, 0xFB, 0xD9, 0x5F, 0x9A,
+ 0x94, 0xB6, 0xD5, 0xA0, 0x2C, 0xAF, 0xB5, 0xEF,
+ 0x5C, 0x5A, 0x8E, 0x34, 0xA1, 0x8F, 0xEB, 0x38,
+ 0x0F, 0x31, 0x6E, 0x45, 0x21, 0x7A, 0xAA, 0xAF,
+ 0x6C, 0xB1, 0x8E, 0xB2, 0xB9, 0xD4, 0x1E, 0xEF,
+ 0x66, 0xD8, 0x4E, 0x3D, 0xF2, 0x0C, 0xF1, 0xBA,
+ 0xFB, 0xA9, 0x27, 0xD2, 0x45, 0x54, 0x83, 0x4B,
+ 0x10, 0xC4, 0x9A, 0x32, 0x9C, 0xC7, 0x9A, 0xCF,
+ 0x4E, 0xBF, 0x07, 0xFC, 0x27, 0xB7, 0x96, 0x1D,
+ 0xDE, 0x9D, 0xE4, 0x84, 0x68, 0x00, 0x9A, 0x9F,
+ 0x3D, 0xE6, 0xC7, 0x26, 0x11, 0x48, 0x79, 0xFA,
+ 0x09, 0x76, 0xC8, 0x25, 0x3A, 0xE4, 0x70, 0xF9
+};
+static const unsigned char RSA4096_DP[] = {
+ 0x5C, 0xE3, 0x3E, 0xBF, 0x09, 0xD9, 0xFE, 0x80,
+ 0x9A, 0x1E, 0x24, 0xDF, 0xC4, 0xBE, 0x5A, 0x70,
+ 0x06, 0xF2, 0xB8, 0xE9, 0x0F, 0x21, 0x9D, 0xCF,
+ 0x26, 0x15, 0x97, 0x32, 0x60, 0x40, 0x99, 0xFF,
+ 0x04, 0x3D, 0xBA, 0x39, 0xBF, 0xEB, 0x87, 0xB1,
+ 0xB1, 0x5B, 0x14, 0xF4, 0x80, 0xB8, 0x85, 0x34,
+ 0x2C, 0xBC, 0x95, 0x67, 0xE9, 0x83, 0xEB, 0x78,
+ 0xA4, 0x62, 0x46, 0x7F, 0x8B, 0x55, 0xEE, 0x3C,
+ 0x2F, 0xF3, 0x7E, 0xF5, 0x6B, 0x39, 0xE3, 0xA3,
+ 0x0E, 0xEA, 0x92, 0x76, 0xAC, 0xF7, 0xB2, 0x05,
+ 0xB2, 0x50, 0x5D, 0xF9, 0xB7, 0x11, 0x87, 0xB7,
+ 0x49, 0x86, 0xEB, 0x44, 0x6A, 0x0C, 0x64, 0x75,
+ 0x95, 0x14, 0x24, 0xFF, 0x49, 0x06, 0x52, 0x68,
+ 0x81, 0x71, 0x44, 0x85, 0x26, 0x0A, 0x49, 0xEA,
+ 0x4E, 0x9F, 0x6A, 0x8E, 0xCF, 0xC8, 0xC9, 0xB0,
+ 0x61, 0x77, 0x27, 0x89, 0xB0, 0xFA, 0x1D, 0x51,
+ 0x7D, 0xDC, 0x34, 0x21, 0x80, 0x8B, 0x6B, 0x86,
+ 0x19, 0x1A, 0x5F, 0x19, 0x23, 0xF3, 0xFB, 0xD1,
+ 0xF7, 0x35, 0x9D, 0x28, 0x61, 0x2F, 0x35, 0x85,
+ 0x82, 0x2A, 0x1E, 0xDF, 0x09, 0xC2, 0x0C, 0x99,
+ 0xE0, 0x3C, 0x8F, 0x4B, 0x3D, 0x92, 0xAF, 0x46,
+ 0x77, 0x68, 0x59, 0xF4, 0x37, 0x81, 0x6C, 0xCE,
+ 0x27, 0x8B, 0xAB, 0x0B, 0xA5, 0xDA, 0x7B, 0x19,
+ 0x83, 0xDA, 0x27, 0x49, 0x65, 0x1A, 0x00, 0x6B,
+ 0xE1, 0x8B, 0x73, 0xCD, 0xF4, 0xFB, 0xD7, 0xBF,
+ 0xF8, 0x20, 0x89, 0xE1, 0xDE, 0x51, 0x1E, 0xDD,
+ 0x97, 0x44, 0x12, 0x68, 0x1E, 0xF7, 0x52, 0xF8,
+ 0x6B, 0x93, 0xC1, 0x3B, 0x9F, 0xA1, 0xB8, 0x5F,
+ 0xCB, 0x84, 0x45, 0x95, 0xF7, 0x0D, 0xA6, 0x4B,
+ 0x03, 0x3C, 0xAE, 0x0F, 0xB7, 0x81, 0x78, 0x75,
+ 0x1C, 0x53, 0x99, 0x24, 0xB3, 0xE2, 0x78, 0xCE,
+ 0xF3, 0xF0, 0x09, 0x6C, 0x01, 0x85, 0x73, 0xBD
+};
+static const unsigned char RSA4096_DQ[] = {
+ 0xCD, 0x88, 0xAC, 0x8B, 0x92, 0x6A, 0xA8, 0x6B,
+ 0x71, 0x16, 0xCD, 0x6B, 0x6A, 0x0B, 0xA6, 0xCD,
+ 0xF3, 0x27, 0x58, 0xA6, 0xE4, 0x1D, 0xDC, 0x40,
+ 0xAF, 0x7B, 0x3F, 0x44, 0x3D, 0xAC, 0x1D, 0x08,
+ 0x5C, 0xE9, 0xF1, 0x0D, 0x07, 0xE4, 0x0A, 0x94,
+ 0x2C, 0xBF, 0xCC, 0x48, 0xAA, 0x62, 0x58, 0xF2,
+ 0x5E, 0x8F, 0x2D, 0x36, 0x37, 0xFE, 0xB6, 0xCB,
+ 0x0A, 0x24, 0xD3, 0xF0, 0x87, 0x5D, 0x0E, 0x05,
+ 0xC4, 0xFB, 0xCA, 0x7A, 0x8B, 0xA5, 0x72, 0xFB,
+ 0x17, 0x78, 0x6C, 0xC2, 0xAA, 0x56, 0x93, 0x2F,
+ 0xFE, 0x6C, 0xA2, 0xEB, 0xD4, 0x18, 0xDD, 0x71,
+ 0xCB, 0x0B, 0x89, 0xFC, 0xB3, 0xFB, 0xED, 0xB7,
+ 0xC5, 0xB0, 0x29, 0x6D, 0x9C, 0xB9, 0xC5, 0xC4,
+ 0xFA, 0x58, 0xD7, 0x36, 0x01, 0x0F, 0xE4, 0x6A,
+ 0xF4, 0x0B, 0x4D, 0xBB, 0x3E, 0x8E, 0x9F, 0xBA,
+ 0x98, 0x6D, 0x1A, 0xE5, 0x20, 0xAF, 0x84, 0x30,
+ 0xDD, 0xAC, 0x3C, 0x66, 0xBC, 0x24, 0xD9, 0x67,
+ 0x4A, 0x35, 0x61, 0xC9, 0xAD, 0xCC, 0xC9, 0x66,
+ 0x68, 0x46, 0x19, 0x8C, 0x04, 0xA5, 0x16, 0x83,
+ 0x5F, 0x7A, 0xFD, 0x1B, 0xAD, 0xAE, 0x22, 0x2D,
+ 0x05, 0xAF, 0x29, 0xDC, 0xBB, 0x0E, 0x86, 0x0C,
+ 0xBC, 0x9E, 0xB6, 0x28, 0xA9, 0xF2, 0xCC, 0x5E,
+ 0x1F, 0x86, 0x95, 0xA5, 0x9C, 0x11, 0x19, 0xF0,
+ 0x5F, 0xDA, 0x2C, 0x04, 0xFE, 0x22, 0x80, 0xF7,
+ 0x94, 0x3C, 0xBA, 0x01, 0x56, 0xD6, 0x93, 0xFA,
+ 0xCE, 0x62, 0xE5, 0xD7, 0x98, 0x23, 0xAB, 0xB9,
+ 0xC7, 0x35, 0x57, 0xF6, 0xE2, 0x16, 0x36, 0xE9,
+ 0x5B, 0xD7, 0xA5, 0x45, 0x18, 0x93, 0x77, 0xC9,
+ 0xB1, 0x05, 0xA8, 0x66, 0xE1, 0x0E, 0xB5, 0xDF,
+ 0x23, 0x35, 0xE1, 0xC2, 0xFA, 0x3E, 0x80, 0x1A,
+ 0xAD, 0xA4, 0x0C, 0xEF, 0xC7, 0x18, 0xDE, 0x09,
+ 0xE6, 0x20, 0x98, 0x31, 0xF1, 0xD3, 0xCF, 0xA1
+};
+static const unsigned char RSA4096_IQ[] = {
+ 0x76, 0xD7, 0x75, 0xDF, 0xA3, 0x0C, 0x9D, 0x64,
+ 0x6E, 0x00, 0x82, 0x2E, 0x5C, 0x5E, 0x43, 0xC4,
+ 0xD2, 0x28, 0xB0, 0xB1, 0xA8, 0xD8, 0x26, 0x91,
+ 0xA0, 0xF5, 0xC8, 0x69, 0xFF, 0x24, 0x33, 0xAB,
+ 0x67, 0xC7, 0xA3, 0xAE, 0xBB, 0x17, 0x27, 0x5B,
+ 0x5A, 0xCD, 0x67, 0xA3, 0x70, 0x91, 0x9E, 0xD5,
+ 0xF1, 0x97, 0x00, 0x0A, 0x30, 0x64, 0x3D, 0x9B,
+ 0xBF, 0xB5, 0x8C, 0xAC, 0xC7, 0x20, 0x0A, 0xD2,
+ 0x76, 0x36, 0x36, 0x5D, 0xE4, 0xAC, 0x5D, 0xBC,
+ 0x44, 0x32, 0xB0, 0x76, 0x33, 0x40, 0xDD, 0x29,
+ 0x22, 0xE0, 0xFF, 0x55, 0x4C, 0xCE, 0x3F, 0x43,
+ 0x34, 0x95, 0x94, 0x7C, 0x22, 0x0D, 0xAB, 0x20,
+ 0x38, 0x70, 0xC3, 0x4A, 0x19, 0xCF, 0x81, 0xCE,
+ 0x79, 0x28, 0x6C, 0xC2, 0xA3, 0xB3, 0x48, 0x20,
+ 0x2D, 0x3E, 0x74, 0x45, 0x2C, 0xAA, 0x9F, 0xA5,
+ 0xC2, 0xE3, 0x2D, 0x41, 0x95, 0xBD, 0x78, 0xAB,
+ 0x6A, 0xA8, 0x7A, 0x45, 0x52, 0xE2, 0x66, 0xE7,
+ 0x6C, 0x38, 0x03, 0xA5, 0xDA, 0xAD, 0x94, 0x3C,
+ 0x6A, 0xA1, 0xA2, 0xD5, 0xCD, 0xDE, 0x05, 0xCC,
+ 0x6E, 0x3D, 0x8A, 0xF6, 0x9A, 0xA5, 0x0F, 0xA9,
+ 0x18, 0xC4, 0xF9, 0x9C, 0x2F, 0xB3, 0xF1, 0x30,
+ 0x38, 0x60, 0x69, 0x09, 0x67, 0x2C, 0xE9, 0x42,
+ 0x68, 0x3C, 0x70, 0x32, 0x1A, 0x44, 0x32, 0x02,
+ 0x82, 0x9F, 0x60, 0xE8, 0xA4, 0x42, 0x74, 0xA2,
+ 0xA2, 0x5A, 0x99, 0xDC, 0xC8, 0xCA, 0x15, 0x4D,
+ 0xFF, 0xF1, 0x8A, 0x23, 0xD8, 0xD3, 0xB1, 0x9A,
+ 0xB4, 0x0B, 0xBB, 0xE8, 0x38, 0x74, 0x0C, 0x52,
+ 0xC7, 0x8B, 0x63, 0x4C, 0xEA, 0x7D, 0x5F, 0x58,
+ 0x34, 0x53, 0x3E, 0x23, 0x10, 0xBB, 0x60, 0x6B,
+ 0x52, 0x9D, 0x89, 0x9F, 0xF0, 0x5F, 0xCE, 0xB3,
+ 0x9C, 0x0E, 0x75, 0x0F, 0x87, 0xF6, 0x66, 0xA5,
+ 0x4C, 0x94, 0x84, 0xFE, 0x94, 0xB9, 0x04, 0xB7
+};
+
+static const br_rsa_public_key RSA4096_PK = {
+ (void *)RSA4096_N, sizeof RSA4096_N,
+ (void *)RSA4096_E, sizeof RSA4096_E
+};
+
+static const br_rsa_private_key RSA4096_SK = {
+ 4096,
+ (void *)RSA4096_P, sizeof RSA4096_P,
+ (void *)RSA4096_Q, sizeof RSA4096_Q,
+ (void *)RSA4096_DP, sizeof RSA4096_DP,
+ (void *)RSA4096_DQ, sizeof RSA4096_DQ,
+ (void *)RSA4096_IQ, sizeof RSA4096_IQ
+};
+
+static void
+test_RSA_core(const char *name, br_rsa_public fpub, br_rsa_private fpriv)
+{
+ unsigned char t1[512], t2[512], t3[512];
+ size_t len;
+
+ printf("Test %s: ", name);
+ fflush(stdout);
+
+ /*
+ * A KAT test (computed with OpenSSL).
+ */
+ len = hextobin(t1, "45A3DC6A106BCD3BD0E48FB579643AA3FF801E5903E80AA9B43A695A8E7F454E93FA208B69995FF7A6D5617C2FEB8E546375A664977A48931842AAE796B5A0D64393DCA35F3490FC157F5BD83B9D58C2F7926E6AE648A2BD96CAB8FCCD3D35BB11424AD47D973FF6D69CA774841AEC45DFAE99CCF79893E7047FDE6CB00AA76D");
+ hextobin(t2, "0001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF003021300906052B0E03021A05000414A94A8FE5CCB19BA61C4C0873D391E987982FBBD3");
+ memcpy(t3, t1, len);
+ if (!fpub(t3, len, &RSA_PK)) {
+ fprintf(stderr, "RSA public operation failed (1)\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("KAT RSA pub", t2, t3, len);
+ if (!fpriv(t3, &RSA_SK)) {
+ fprintf(stderr, "RSA private operation failed (1)\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("KAT RSA priv (1)", t1, t3, len);
+
+ /*
+ * Another KAT test, with a (fake) hash value slightly different
+ * (last byte is 0xD9 instead of 0xD3).
+ */
+ len = hextobin(t1, "32C2DB8B2C73BBCA9960CB3F11FEDEE7B699359EF2EEC3A632E56B7FF3DE2F371E5179BAB03F17E0BB20D2891ACAB679F95DA9B43A01DAAD192FADD25D8ACCF1498EC80F5BBCAC88EA59D60E3BC9D3CE27743981DE42385FFFFF04DD2D716E1A46C04A28ECAF6CD200DAB81083A830D61538D69BB39A183107BD50302AA6BC28");
+ hextobin(t2, "0001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF003021300906052B0E03021A05000414A94A8FE5CCB19BA61C4C0873D391E987982FBBD9");
+ memcpy(t3, t1, len);
+ if (!fpub(t3, len, &RSA_PK)) {
+ fprintf(stderr, "RSA public operation failed (2)\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("KAT RSA pub", t2, t3, len);
+ if (!fpriv(t3, &RSA_SK)) {
+ fprintf(stderr, "RSA private operation failed (2)\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("KAT RSA priv (2)", t1, t3, len);
+
+ /*
+ * Third KAT vector is invalid, because the encrypted value is
+ * out of range: instead of x, value is x+n (where n is the
+ * modulus). Mathematically, this still works, but implementations
+ * are supposed to reject such cases.
+ */
+ len = hextobin(t1, "F27781B9B3B358583A24F9BA6B34EE98B67A5AE8D8D4FA567BA773EB6B85EF88848680640A1E2F5FD117876E5FB928B64C6EFC7E03632A3F4C941E15657C0C705F3BB8D0B03A0249143674DB1FE6E5406D690BF2DA76EA7FF3AC6FCE12C7801252FAD52D332BE4AB41F9F8CF1728CDF98AB8E8C20E0C350E4F707A6402C01E0B");
+ hextobin(t2, "BFB6A62E873F9C8DA0C42E7B59360FB0FFE12549E5E636B048C2086B77A7C051663506A959DF177F15F6B4E544EE723C531152C9C9614F923364704307F13F7F15ACF0C1547D55C029DC9ECCE41D117245F4D270FC34B21FF3AD6AEFE58633281540902F547F79F3461F44D33CCB2D094231ADCC76BE25511B4513BB70491DBC");
+ memcpy(t3, t1, len);
+ if (fpub(t3, len, &RSA_PK)) {
+ size_t u;
+ fprintf(stderr, "RSA public operation should have failed"
+ " (value out of range)\n");
+ fprintf(stderr, "x = ");
+ for (u = 0; u < len; u ++) {
+ fprintf(stderr, "%02X", t3[u]);
+ }
+ fprintf(stderr, "\n");
+ exit(EXIT_FAILURE);
+ }
+ memcpy(t3, t2, len);
+ if (fpriv(t3, &RSA_SK)) {
+ size_t u;
+ fprintf(stderr, "RSA private operation should have failed"
+ " (value out of range)\n");
+ fprintf(stderr, "x = ");
+ for (u = 0; u < len; u ++) {
+ fprintf(stderr, "%02X", t3[u]);
+ }
+ fprintf(stderr, "\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * RSA-2048 test vector.
+ */
+ len = hextobin(t1, "B188ED4EF173A30AED3889926E3CF1CE03FE3BAA7AB122B119A8CD529062F235A7B321008FB898894A624B3E6C8C5374950E78FAC86651345FE2ABA0791968284F23B0D794F8DCDDA924518854822CB7FF2AA9F205AACD909BB5EA541534CC00DBC2EF7727B9FE1BAFE6241B931E8BD01E13632E5AF9E94F4A335772B61F24D6F6AA642AEABB173E36F546CB02B19A1E5D4E27E3EB67F2E986E9F084D4BD266543800B1DC96088A05DFA9AFA595398E9A766D41DD8DA4F74F36C9D74867F0BF7BFA8622EE43C79DA0CEAC14B5D39DE074BDB89D84145BC19D8B2D0EA74DBF2DC29E907BF7C7506A2603CD8BC25EFE955D0125EDB2685EF158B020C9FC539242A");
+ hextobin(t2, "0001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF003031300D060960864801650304020105000420A5A0A792A09438811584A68E240C6C89F1FB1C53C0C86E270B942635F4F6B24A");
+ memcpy(t3, t1, len);
+ if (!fpub(t3, len, &RSA2048_PK)) {
+ fprintf(stderr, "RSA public operation failed (2048)\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("KAT RSA pub", t2, t3, len);
+ if (!fpriv(t3, &RSA2048_SK)) {
+ fprintf(stderr, "RSA private operation failed (2048)\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("KAT RSA priv (2048)", t1, t3, len);
+
+ /*
+ * RSA-4096 test vector.
+ */
+ len = hextobin(t1, "7D35B6B4D85252D08A2658C0B04126CC617B0E56B2A782A5FA2722AD05BD49538111682C12DA2C5FA1B9C30FB1AB8DA2C6A49EB4226A4D32290CF091FBB22EC499C7B18192C230B29F957DAF551F1EAD1917BA9E03D757100BD1F96B829708A6188A3927436113BB21E175D436BBB7A90E20162203FFB8F675313DFB21EFDA3EA0C7CC9B605AE7FB47E2DD2A9C4D5F124D7DE1B690AF9ADFEDC6055E0F9D2C9A891FB2501F3055D6DA7E94D51672BA1E86AEB782E4B020F70E0DF5399262909FC5B4770B987F2826EF2099A15F3CD5A0D6FE82E0C85FBA2C53C77305F534A7B0C7EA0D5244E37F1C1318EEF7079995F0642E4AB80EB0ED60DB4955FB652ED372DAC787581054A827C37A25C7B4DE7AE7EF3D099D47D6682ADF02BCC4DE04DDF2920F7124CF5B4955705E4BDB97A0BF341B584797878B4D3795134A9469FB391E4E4988F0AA451027CBC2ED6121FC23B26BF593E3C51DEDD53B62E23050D5B41CA34204679916A87AF1B17873A0867924D0C303942ADA478B769487FCEF861D4B20DCEE6942CCB84184833CDB258167258631C796BC1977D001354E2EE168ABE3B45FC969EA7F22B8E133C57A10FBB25ED19694E89C399CF7723B3C0DF0CC9F57A8ED0959EFC392FB31B8ADAEA969E2DEE8282CB245E5677368F00CCE4BA52C07C16BE7F9889D57191D5B2FE552D72B3415C64C09EE622457766EC809344A1EFE");
+ hextobin(t2, "0001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF003031300D0609608648016503040201050004205B60DD5AD5B3C62E0DA25FD0D8CB26325E1CE32CC9ED234B288235BCCF6ED2C8");
+ memcpy(t3, t1, len);
+ if (!fpub(t3, len, &RSA4096_PK)) {
+ fprintf(stderr, "RSA public operation failed (4096)\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("KAT RSA pub", t2, t3, len);
+ if (!fpriv(t3, &RSA4096_SK)) {
+ fprintf(stderr, "RSA private operation failed (4096)\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("KAT RSA priv (4096)", t1, t3, len);
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static const unsigned char SHA1_OID[] = {
+ 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
+};
+
+static void
+test_RSA_sign(const char *name, br_rsa_private fpriv,
+ br_rsa_pkcs1_sign fsign, br_rsa_pkcs1_vrfy fvrfy)
+{
+ unsigned char t1[128], t2[128];
+ unsigned char hv[20], tmp[20];
+ unsigned char rsa_n[128], rsa_e[3], rsa_p[64], rsa_q[64];
+ unsigned char rsa_dp[64], rsa_dq[64], rsa_iq[64];
+ br_rsa_public_key rsa_pk;
+ br_rsa_private_key rsa_sk;
+ unsigned char hv2[64], tmp2[64], sig[128];
+ br_sha1_context hc;
+ size_t u;
+
+ printf("Test %s: ", name);
+ fflush(stdout);
+
+ /*
+ * Verify the KAT test (computed with OpenSSL).
+ */
+ hextobin(t1, "45A3DC6A106BCD3BD0E48FB579643AA3FF801E5903E80AA9B43A695A8E7F454E93FA208B69995FF7A6D5617C2FEB8E546375A664977A48931842AAE796B5A0D64393DCA35F3490FC157F5BD83B9D58C2F7926E6AE648A2BD96CAB8FCCD3D35BB11424AD47D973FF6D69CA774841AEC45DFAE99CCF79893E7047FDE6CB00AA76D");
+ br_sha1_init(&hc);
+ br_sha1_update(&hc, "test", 4);
+ br_sha1_out(&hc, hv);
+ if (!fvrfy(t1, sizeof t1, SHA1_OID, sizeof tmp, &RSA_PK, tmp)) {
+ fprintf(stderr, "Signature verification failed\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("Extracted hash value", hv, tmp, sizeof tmp);
+
+ /*
+ * Regenerate the signature. This should yield the same value as
+ * the KAT test, since PKCS#1 v1.5 signatures are deterministic
+ * (except the usual detail about hash function parameter
+ * encoding, but OpenSSL uses the same convention as BearSSL).
+ */
+ if (!fsign(SHA1_OID, hv, 20, &RSA_SK, t2)) {
+ fprintf(stderr, "Signature generation failed\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("Regenerated signature", t1, t2, sizeof t1);
+
+ /*
+ * Use the raw private core to generate fake signatures, where
+ * one byte of the padded hash value is altered. They should all be
+ * rejected.
+ */
+ hextobin(t2, "0001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF003021300906052B0E03021A05000414A94A8FE5CCB19BA61C4C0873D391E987982FBBD3");
+ for (u = 0; u < (sizeof t2) - 20; u ++) {
+ memcpy(t1, t2, sizeof t2);
+ t1[u] ^= 0x01;
+ if (!fpriv(t1, &RSA_SK)) {
+ fprintf(stderr, "RSA private key operation failed\n");
+ exit(EXIT_FAILURE);
+ }
+ if (fvrfy(t1, sizeof t1, SHA1_OID, sizeof tmp, &RSA_PK, tmp)) {
+ fprintf(stderr,
+ "Signature verification should have failed\n");
+ exit(EXIT_FAILURE);
+ }
+ printf(".");
+ fflush(stdout);
+ }
+
+ /*
+ * Another KAT test, which historically showed a bug.
+ */
+ rsa_pk.n = rsa_n;
+ rsa_pk.nlen = hextobin(rsa_n, "E65DAEF196D22C300B3DAE1CE5157EDF821BB6038E419D8D363A8B2DA84A1321042330E6F87A8BD8FE6BA1D2A17031955ED2315CC5FD2397197E238A5E0D2D0AFD25717E814EC4D2BBA887327A3C5B3A450FD8D547BDFCBB0F73B997CA13DD5E7572C4D5BAA764A349BAB2F868ACF4574AE2C7AEC94B77D2EE00A21B6CB175BB");
+ rsa_pk.e = rsa_e;
+ rsa_pk.elen = hextobin(rsa_e, "010001");
+
+ rsa_sk.n_bitlen = 1024;
+ rsa_sk.p = rsa_p;
+ rsa_sk.plen = hextobin(rsa_p, "FF58513DBA4F3F42DFDFD3E6AFB6BD62DE27E06BA3C9D9F9B542CB21228C2AAE67936514161C8FDC1A248A50195CAF22ADC50DA89BFED1B9EEFBB37304241357");
+ rsa_sk.q = rsa_q;
+ rsa_sk.qlen = hextobin(rsa_q, "E6F4F66818B7442297DDEB45E9B3D438E5B57BB5EF86EFF2462AD6B9C10F383517CDD2E7E36EAD4BEBCC57CFE8AA985F7E7B38B96D30FFBE9ED9FE21B1CFB63D");
+ rsa_sk.dp = rsa_dp;
+ rsa_sk.dplen = hextobin(rsa_dp, "6F89517B682D83919F9EF2BDBA955526A1A9C382E139A3A84AC01160B8E9871F458901C7035D988D6931FAE4C01F57350BB89E9DBEFE50F829E6F25CD43B39E3");
+ rsa_sk.dq = rsa_dq;
+ rsa_sk.dqlen = hextobin(rsa_dq, "409E08D2D7176F58BE64B88EB6F4394C31F8B4C412600E821A5FA1F416AFCB6A0F5EE6C33A3E9CFDC0DB4B3640427A9F3D23FC9AE491F0FBC435F98433DB8981");
+ rsa_sk.iq = rsa_iq;
+ rsa_sk.iqlen = hextobin(rsa_iq, "CF333D6AD66D02B4D11C8C23CA669D14D71803ADC3943BE03B1E48F52F385BCFDDFD0F85AD02A984E504FC6612549D4E7867B7D09DD13196BFC3FAA4B57393A9");
+ hextobin(sig, "CFB84D161E6DB130736FC6212EBE575571AF341CEF5757C19952A5364C90E3C47549E520E26253DAE70F645F31FA8B5DA9AE282741D3CA4B1CC365B7BD75D6D61D4CFD9AD9EDD17D23E0BA7D9775138DBABC7FF2A57587FE1EA1B51E8F3C68326E26FF89D8CF92BDD4C787D04857DFC3266E6B33B92AA08809929C72642F35C2");
+
+ hextobin(hv2, "F66C62B38E1CC69C378C0E16574AE5C6443FDFA3E85C6205C00B3231CAA3074EC1481BDC22AB575E6CF3CCD9EDA6B39F83923FC0E6475C799D257545F77233B4");
+ if (!fsign(BR_HASH_OID_SHA512, hv2, 64, &rsa_sk, t2)) {
+ fprintf(stderr, "Signature generation failed (2)\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("Regenerated signature (2)", t2, sig, sizeof t2);
+ if (!fvrfy(t2, sizeof t2, BR_HASH_OID_SHA512,
+ sizeof tmp2, &rsa_pk, tmp2))
+ {
+ fprintf(stderr, "Signature verification failed (2)\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("Extracted hash value (2)", hv2, tmp2, sizeof tmp2);
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+/*
+ * Fake RNG that returns exactly the provided bytes.
+ */
+typedef struct {
+ const br_prng_class *vtable;
+ unsigned char buf[128];
+ size_t ptr, len;
+} rng_fake_ctx;
+
+static void rng_fake_init(rng_fake_ctx *cc,
+ const void *params, const void *seed, size_t len);
+static void rng_fake_generate(rng_fake_ctx *cc, void *dst, size_t len);
+static void rng_fake_update(rng_fake_ctx *cc, const void *src, size_t len);
+
+static const br_prng_class rng_fake_vtable = {
+ sizeof(rng_fake_ctx),
+ (void (*)(const br_prng_class **,
+ const void *, const void *, size_t))&rng_fake_init,
+ (void (*)(const br_prng_class **,
+ void *, size_t))&rng_fake_generate,
+ (void (*)(const br_prng_class **,
+ const void *, size_t))&rng_fake_update
+};
+
+static void
+rng_fake_init(rng_fake_ctx *cc, const void *params,
+ const void *seed, size_t len)
+{
+ (void)params;
+ if (len > sizeof cc->buf) {
+ fprintf(stderr, "seed is too large (%lu bytes)\n",
+ (unsigned long)len);
+ exit(EXIT_FAILURE);
+ }
+ cc->vtable = &rng_fake_vtable;
+ memcpy(cc->buf, seed, len);
+ cc->ptr = 0;
+ cc->len = len;
+}
+
+static void
+rng_fake_generate(rng_fake_ctx *cc, void *dst, size_t len)
+{
+ if (len > (cc->len - cc->ptr)) {
+ fprintf(stderr, "asking for more data than expected\n");
+ exit(EXIT_FAILURE);
+ }
+ memcpy(dst, cc->buf + cc->ptr, len);
+ cc->ptr += len;
+}
+
+static void
+rng_fake_update(rng_fake_ctx *cc, const void *src, size_t len)
+{
+ (void)cc;
+ (void)src;
+ (void)len;
+ fprintf(stderr, "unexpected update\n");
+ exit(EXIT_FAILURE);
+}
+
+/*
+ * Test vectors from pkcs-1v2-1d2-vec.zip (originally from ftp.rsa.com).
+ * There are ten RSA keys, and for each RSA key, there are 6 messages,
+ * each with an explicit salt.
+ *
+ * Field order:
+ * modulus (n)
+ * public exponent (e)
+ * first factor (p)
+ * second factor (q)
+ * first private exponent (dp)
+ * second private exponent (dq)
+ * CRT coefficient (iq)
+ * message 1
+ * salt 1 (20-byte random value)
+ * signature 1
+ * message 2
+ * salt 2 (20-byte random value)
+ * signature 2
+ * ...
+ * message 6
+ * salt 6 (20-byte random value)
+ * signature 6
+ *
+ * This pattern is repeated for all keys. The array stops on a NULL.
+ */
+static const char *KAT_RSA_PSS[] = {
+
+ /* 1024-bit key */
+ "a56e4a0e701017589a5187dc7ea841d156f2ec0e36ad52a44dfeb1e61f7ad991d8c51056ffedb162b4c0f283a12a88a394dff526ab7291cbb307ceabfce0b1dfd5cd9508096d5b2b8b6df5d671ef6377c0921cb23c270a70e2598e6ff89d19f105acc2d3f0cb35f29280e1386b6f64c4ef22e1e1f20d0ce8cffb2249bd9a2137",
+ "010001",
+ "33a5042a90b27d4f5451ca9bbbd0b44771a101af884340aef9885f2a4bbe92e894a724ac3c568c8f97853ad07c0266c8c6a3ca0929f1e8f11231884429fc4d9ae55fee896a10ce707c3ed7e734e44727a39574501a532683109c2abacaba283c31b4bd2f53c3ee37e352cee34f9e503bd80c0622ad79c6dcee883547c6a3b325",
+ "e7e8942720a877517273a356053ea2a1bc0c94aa72d55c6e86296b2dfc967948c0a72cbccca7eacb35706e09a1df55a1535bd9b3cc34160b3b6dcd3eda8e6443",
+ "b69dca1cf7d4d7ec81e75b90fcca874abcde123fd2700180aa90479b6e48de8d67ed24f9f19d85ba275874f542cd20dc723e6963364a1f9425452b269a6799fd",
+ "28fa13938655be1f8a159cbaca5a72ea190c30089e19cd274a556f36c4f6e19f554b34c077790427bbdd8dd3ede2448328f385d81b30e8e43b2fffa027861979",
+ "1a8b38f398fa712049898d7fb79ee0a77668791299cdfa09efc0e507acb21ed74301ef5bfd48be455eaeb6e1678255827580a8e4e8e14151d1510a82a3f2e729",
+ "27156aba4126d24a81f3a528cbfb27f56886f840a9f6e86e17a44b94fe9319584b8e22fdde1e5a2e3bd8aa5ba8d8584194eb2190acf832b847f13a3d24a79f4d",
+
+ "cdc87da223d786df3b45e0bbbc721326d1ee2af806cc315475cc6f0d9c66e1b62371d45ce2392e1ac92844c310102f156a0d8d52c1f4c40ba3aa65095786cb769757a6563ba958fed0bcc984e8b517a3d5f515b23b8a41e74aa867693f90dfb061a6e86dfaaee64472c00e5f20945729cbebe77f06ce78e08f4098fba41f9d6193c0317e8b60d4b6084acb42d29e3808a3bc372d85e331170fcbf7cc72d0b71c296648b3a4d10f416295d0807aa625cab2744fd9ea8fd223c42537029828bd16be02546f130fd2e33b936d2676e08aed1b73318b750a0167d0",
+ "dee959c7e06411361420ff80185ed57f3e6776af",
+ "9074308fb598e9701b2294388e52f971faac2b60a5145af185df5287b5ed2887e57ce7fd44dc8634e407c8e0e4360bc226f3ec227f9d9e54638e8d31f5051215df6ebb9c2f9579aa77598a38f914b5b9c1bd83c4e2f9f382a0d0aa3542ffee65984a601bc69eb28deb27dca12c82c2d4c3f66cd500f1ff2b994d8a4e30cbb33c",
+
+ "851384cdfe819c22ed6c4ccb30daeb5cf059bc8e1166b7e3530c4c233e2b5f8f71a1cca582d43ecc72b1bca16dfc7013226b9e",
+ "ef2869fa40c346cb183dab3d7bffc98fd56df42d",
+ "3ef7f46e831bf92b32274142a585ffcefbdca7b32ae90d10fb0f0c729984f04ef29a9df0780775ce43739b97838390db0a5505e63de927028d9d29b219ca2c4517832558a55d694a6d25b9dab66003c4cccd907802193be5170d26147d37b93590241be51c25055f47ef62752cfbe21418fafe98c22c4d4d47724fdb5669e843",
+
+ "a4b159941761c40c6a82f2b80d1b94f5aa2654fd17e12d588864679b54cd04ef8bd03012be8dc37f4b83af7963faff0dfa225477437c48017ff2be8191cf3955fc07356eab3f322f7f620e21d254e5db4324279fe067e0910e2e81ca2cab31c745e67a54058eb50d993cdb9ed0b4d029c06d21a94ca661c3ce27fae1d6cb20f4564d66ce4767583d0e5f060215b59017be85ea848939127bd8c9c4d47b51056c031cf336f17c9980f3b8f5b9b6878e8b797aa43b882684333e17893fe9caa6aa299f7ed1a18ee2c54864b7b2b99b72618fb02574d139ef50f019c9eef416971338e7d470",
+ "710b9c4747d800d4de87f12afdce6df18107cc77",
+ "666026fba71bd3e7cf13157cc2c51a8e4aa684af9778f91849f34335d141c00154c4197621f9624a675b5abc22ee7d5baaffaae1c9baca2cc373b3f33e78e6143c395a91aa7faca664eb733afd14d8827259d99a7550faca501ef2b04e33c23aa51f4b9e8282efdb728cc0ab09405a91607c6369961bc8270d2d4f39fce612b1",
+
+ "bc656747fa9eafb3f0",
+ "056f00985de14d8ef5cea9e82f8c27bef720335e",
+ "4609793b23e9d09362dc21bb47da0b4f3a7622649a47d464019b9aeafe53359c178c91cd58ba6bcb78be0346a7bc637f4b873d4bab38ee661f199634c547a1ad8442e03da015b136e543f7ab07c0c13e4225b8de8cce25d4f6eb8400f81f7e1833b7ee6e334d370964ca79fdb872b4d75223b5eeb08101591fb532d155a6de87",
+
+ "b45581547e5427770c768e8b82b75564e0ea4e9c32594d6bff706544de0a8776c7a80b4576550eee1b2acabc7e8b7d3ef7bb5b03e462c11047eadd00629ae575480ac1470fe046f13a2bf5af17921dc4b0aa8b02bee6334911651d7f8525d10f32b51d33be520d3ddf5a709955a3dfe78283b9e0ab54046d150c177f037fdccc5be4ea5f68b5e5a38c9d7edcccc4975f455a6909b4",
+ "80e70ff86a08de3ec60972b39b4fbfdcea67ae8e",
+ "1d2aad221ca4d31ddf13509239019398e3d14b32dc34dc5af4aeaea3c095af73479cf0a45e5629635a53a018377615b16cb9b13b3e09d671eb71e387b8545c5960da5a64776e768e82b2c93583bf104c3fdb23512b7b4e89f633dd0063a530db4524b01c3f384c09310e315a79dcd3d684022a7f31c865a664e316978b759fad",
+
+ "10aae9a0ab0b595d0841207b700d48d75faedde3b775cd6b4cc88ae06e4694ec74ba18f8520d4f5ea69cbbe7cc2beba43efdc10215ac4eb32dc302a1f53dc6c4352267e7936cfebf7c8d67035784a3909fa859c7b7b59b8e39c5c2349f1886b705a30267d402f7486ab4f58cad5d69adb17ab8cd0ce1caf5025af4ae24b1fb8794c6070cc09a51e2f9911311e3877d0044c71c57a993395008806b723ac38373d395481818528c1e7053739282053529510e935cd0fa77b8fa53cc2d474bd4fb3cc5c672d6ffdc90a00f9848712c4bcfe46c60573659b11e6457e861f0f604b6138d144f8ce4e2da73",
+ "a8ab69dd801f0074c2a1fc60649836c616d99681",
+ "2a34f6125e1f6b0bf971e84fbd41c632be8f2c2ace7de8b6926e31ff93e9af987fbc06e51e9be14f5198f91f3f953bd67da60a9df59764c3dc0fe08e1cbef0b75f868d10ad3fba749fef59fb6dac46a0d6e504369331586f58e4628f39aa278982543bc0eeb537dc61958019b394fb273f215858a0a01ac4d650b955c67f4c58",
+
+ /* 1025-bit key */
+ "01d40c1bcf97a68ae7cdbd8a7bf3e34fa19dcca4ef75a47454375f94514d88fed006fb829f8419ff87d6315da68a1ff3a0938e9abb3464011c303ad99199cf0c7c7a8b477dce829e8844f625b115e5e9c4a59cf8f8113b6834336a2fd2689b472cbb5e5cabe674350c59b6c17e176874fb42f8fc3d176a017edc61fd326c4b33c9",
+ "010001",
+ "027d147e4673057377fd1ea201565772176a7dc38358d376045685a2e787c23c15576bc16b9f444402d6bfc5d98a3e88ea13ef67c353eca0c0ddba9255bd7b8bb50a644afdfd1dd51695b252d22e7318d1b6687a1c10ff75545f3db0fe602d5f2b7f294e3601eab7b9d1cecd767f64692e3e536ca2846cb0c2dd486a39fa75b1",
+ "016601e926a0f8c9e26ecab769ea65a5e7c52cc9e080ef519457c644da6891c5a104d3ea7955929a22e7c68a7af9fcad777c3ccc2b9e3d3650bce404399b7e59d1",
+ "014eafa1d4d0184da7e31f877d1281ddda625664869e8379e67ad3b75eae74a580e9827abd6eb7a002cb5411f5266797768fb8e95ae40e3e8a01f35ff89e56c079",
+ "e247cce504939b8f0a36090de200938755e2444b29539a7da7a902f6056835c0db7b52559497cfe2c61a8086d0213c472c78851800b171f6401de2e9c2756f31",
+ "b12fba757855e586e46f64c38a70c68b3f548d93d787b399999d4c8f0bbd2581c21e19ed0018a6d5d3df86424b3abcad40199d31495b61309f27c1bf55d487c1",
+ "564b1e1fa003bda91e89090425aac05b91da9ee25061e7628d5f51304a84992fdc33762bd378a59f030a334d532bd0dae8f298ea9ed844636ad5fb8cbdc03cad",
+
+ "daba032066263faedb659848115278a52c44faa3a76f37515ed336321072c40a9d9b53bc05014078adf520875146aae70ff060226dcb7b1f1fc27e9360",
+ "57bf160bcb02bb1dc7280cf0458530b7d2832ff7",
+ "014c5ba5338328ccc6e7a90bf1c0ab3fd606ff4796d3c12e4b639ed9136a5fec6c16d8884bdd99cfdc521456b0742b736868cf90de099adb8d5ffd1deff39ba4007ab746cefdb22d7df0e225f54627dc65466131721b90af445363a8358b9f607642f78fab0ab0f43b7168d64bae70d8827848d8ef1e421c5754ddf42c2589b5b3",
+
+ "e4f8601a8a6da1be34447c0959c058570c3668cfd51dd5f9ccd6ad4411fe8213486d78a6c49f93efc2ca2288cebc2b9b60bd04b1e220d86e3d4848d709d032d1e8c6a070c6af9a499fcf95354b14ba6127c739de1bb0fd16431e46938aec0cf8ad9eb72e832a7035de9b7807bdc0ed8b68eb0f5ac2216be40ce920c0db0eddd3860ed788efaccaca502d8f2bd6d1a7c1f41ff46f1681c8f1f818e9c4f6d91a0c7803ccc63d76a6544d843e084e363b8acc55aa531733edb5dee5b5196e9f03e8b731b3776428d9e457fe3fbcb3db7274442d785890e9cb0854b6444dace791d7273de1889719338a77fe",
+ "7f6dd359e604e60870e898e47b19bf2e5a7b2a90",
+ "010991656cca182b7f29d2dbc007e7ae0fec158eb6759cb9c45c5ff87c7635dd46d150882f4de1e9ae65e7f7d9018f6836954a47c0a81a8a6b6f83f2944d6081b1aa7c759b254b2c34b691da67cc0226e20b2f18b42212761dcd4b908a62b371b5918c5742af4b537e296917674fb914194761621cc19a41f6fb953fbcbb649dea",
+
+ "52a1d96c8ac39e41e455809801b927a5b445c10d902a0dcd3850d22a66d2bb0703e67d5867114595aabf5a7aeb5a8f87034bbb30e13cfd4817a9be76230023606d0286a3faf8a4d22b728ec518079f9e64526e3a0cc7941aa338c437997c680ccac67c66bfa1",
+ "fca862068bce2246724b708a0519da17e648688c",
+ "007f0030018f53cdc71f23d03659fde54d4241f758a750b42f185f87578520c30742afd84359b6e6e8d3ed959dc6fe486bedc8e2cf001f63a7abe16256a1b84df0d249fc05d3194ce5f0912742dbbf80dd174f6c51f6bad7f16cf3364eba095a06267dc3793803ac7526aebe0a475d38b8c2247ab51c4898df7047dc6adf52c6c4",
+
+ "a7182c83ac18be6570a106aa9d5c4e3dbbd4afaeb0c60c4a23e1969d79ff",
+ "8070ef2de945c02387684ba0d33096732235d440",
+ "009cd2f4edbe23e12346ae8c76dd9ad3230a62076141f16c152ba18513a48ef6f010e0e37fd3df10a1ec629a0cb5a3b5d2893007298c30936a95903b6ba85555d9ec3673a06108fd62a2fda56d1ce2e85c4db6b24a81ca3b496c36d4fd06eb7c9166d8e94877c42bea622b3bfe9251fdc21d8d5371badad78a488214796335b40b",
+
+ "86a83d4a72ee932a4f5630af6579a386b78fe88999e0abd2d49034a4bfc854dd94f1094e2e8cd7a179d19588e4aefc1b1bd25e95e3dd461f",
+ "17639a4e88d722c4fca24d079a8b29c32433b0c9",
+ "00ec430824931ebd3baa43034dae98ba646b8c36013d1671c3cf1cf8260c374b19f8e1cc8d965012405e7e9bf7378612dfcc85fce12cda11f950bd0ba8876740436c1d2595a64a1b32efcfb74a21c873b3cc33aaf4e3dc3953de67f0674c0453b4fd9f604406d441b816098cb106fe3472bc251f815f59db2e4378a3addc181ecf",
+
+ "049f9154d871ac4a7c7ab45325ba7545a1ed08f70525b2667cf1",
+ "37810def1055ed922b063df798de5d0aabf886ee",
+ "00475b1648f814a8dc0abdc37b5527f543b666bb6e39d30e5b49d3b876dccc58eac14e32a2d55c2616014456ad2f246fc8e3d560da3ddf379a1c0bd200f10221df078c219a151bc8d4ec9d2fc2564467811014ef15d8ea01c2ebbff8c2c8efab38096e55fcbe3285c7aa558851254faffa92c1c72b78758663ef4582843139d7a6",
+
+ /* 1026-bit key */
+ "02f246ef451ed3eebb9a310200cc25859c048e4be798302991112eb68ce6db674e280da21feded1ae74880ca522b18db249385012827c515f0e466a1ffa691d98170574e9d0eadb087586ca48933da3cc953d95bd0ed50de10ddcb6736107d6c831c7f663e833ca4c097e700ce0fb945f88fb85fe8e5a773172565b914a471a443",
+ "010001",
+ "651451733b56de5ac0a689a4aeb6e6894a69014e076c88dd7a667eab3232bbccd2fc44ba2fa9c31db46f21edd1fdb23c5c128a5da5bab91e7f952b67759c7cff705415ac9fa0907c7ca6178f668fb948d869da4cc3b7356f4008dfd5449d32ee02d9a477eb69fc29266e5d9070512375a50fbbcc27e238ad98425f6ebbf88991",
+ "01bd36e18ece4b0fdb2e9c9d548bd1a7d6e2c21c6fdc35074a1d05b1c6c8b3d558ea2639c9a9a421680169317252558bd148ad215aac550e2dcf12a82d0ebfe853",
+ "01b1b656ad86d8e19d5dc86292b3a192fdf6e0dd37877bad14822fa00190cab265f90d3f02057b6f54d6ecb14491e5adeacebc48bf0ebd2a2ad26d402e54f61651",
+ "1f2779fd2e3e5e6bae05539518fba0cd0ead1aa4513a7cba18f1cf10e3f68195693d278a0f0ee72f89f9bc760d80e2f9d0261d516501c6ae39f14a476ce2ccf5",
+ "011a0d36794b04a854aab4b2462d439a5046c91d940b2bc6f75b62956fef35a2a6e63c5309817f307bbff9d59e7e331bd363f6d66849b18346adea169f0ae9aec1",
+ "0b30f0ecf558752fb3a6ce4ba2b8c675f659eba6c376585a1b39712d038ae3d2b46fcb418ae15d0905da6440e1513a30b9b7d6668fbc5e88e5ab7a175e73ba35",
+
+ "594b37333bbb2c84524a87c1a01f75fcec0e3256f108e38dca36d70d0057",
+ "f31ad6c8cf89df78ed77feacbcc2f8b0a8e4cfaa",
+ "0088b135fb1794b6b96c4a3e678197f8cac52b64b2fe907d6f27de761124964a99a01a882740ecfaed6c01a47464bb05182313c01338a8cd097214cd68ca103bd57d3bc9e816213e61d784f182467abf8a01cf253e99a156eaa8e3e1f90e3c6e4e3aa2d83ed0345b89fafc9c26077c14b6ac51454fa26e446e3a2f153b2b16797f",
+
+ "8b769528884a0d1ffd090cf102993e796dadcfbddd38e44ff6324ca451",
+ "fcf9f0e1f199a3d1d0da681c5b8606fc642939f7",
+ "02a5f0a858a0864a4f65017a7d69454f3f973a2999839b7bbc48bf78641169179556f595fa41f6ff18e286c2783079bc0910ee9cc34f49ba681124f923dfa88f426141a368a5f5a930c628c2c3c200e18a7644721a0cbec6dd3f6279bde3e8f2be5e2d4ee56f97e7ceaf33054be7042bd91a63bb09f897bd41e81197dee99b11af",
+
+ "1abdba489c5ada2f995ed16f19d5a94d9e6ec34a8d84f84557d26e5ef9b02b22887e3f9a4b690ad1149209c20c61431f0c017c36c2657b35d7b07d3f5ad8708507a9c1b831df835a56f831071814ea5d3d8d8f6ade40cba38b42db7a2d3d7a29c8f0a79a7838cf58a9757fa2fe4c40df9baa193bfc6f92b123ad57b07ace3e6ac068c9f106afd9eeb03b4f37c25dbfbcfb3071f6f9771766d072f3bb070af6605532973ae25051",
+ "986e7c43dbb671bd41b9a7f4b6afc80e805f2423",
+ "0244bcd1c8c16955736c803be401272e18cb990811b14f72db964124d5fa760649cbb57afb8755dbb62bf51f466cf23a0a1607576e983d778fceffa92df7548aea8ea4ecad2c29dd9f95bc07fe91ecf8bee255bfe8762fd7690aa9bfa4fa0849ef728c2c42c4532364522df2ab7f9f8a03b63f7a499175828668f5ef5a29e3802c",
+
+ "8fb431f5ee792b6c2ac7db53cc428655aeb32d03f4e889c5c25de683c461b53acf89f9f8d3aabdf6b9f0c2a1de12e15b49edb3919a652fe9491c25a7fce1f722c2543608b69dc375ec",
+ "f8312d9c8eea13ec0a4c7b98120c87509087c478",
+ "0196f12a005b98129c8df13c4cb16f8aa887d3c40d96df3a88e7532ef39cd992f273abc370bc1be6f097cfebbf0118fd9ef4b927155f3df22b904d90702d1f7ba7a52bed8b8942f412cd7bd676c9d18e170391dcd345c06a730964b3f30bcce0bb20ba106f9ab0eeb39cf8a6607f75c0347f0af79f16afa081d2c92d1ee6f836b8",
+
+ "fef4161dfaaf9c5295051dfc1ff3810c8c9ec2e866f7075422c8ec4216a9c4ff49427d483cae10c8534a41b2fd15fee06960ec6fb3f7a7e94a2f8a2e3e43dc4a40576c3097ac953b1de86f0b4ed36d644f23ae14425529622464ca0cbf0b1741347238157fab59e4de5524096d62baec63ac64",
+ "50327efec6292f98019fc67a2a6638563e9b6e2d",
+ "021eca3ab4892264ec22411a752d92221076d4e01c0e6f0dde9afd26ba5acf6d739ef987545d16683e5674c9e70f1de649d7e61d48d0caeb4fb4d8b24fba84a6e3108fee7d0705973266ac524b4ad280f7ae17dc59d96d3351586b5a3bdb895d1e1f7820ac6135d8753480998382ba32b7349559608c38745290a85ef4e9f9bd83",
+
+ "efd237bb098a443aeeb2bf6c3f8c81b8c01b7fcb3feb",
+ "b0de3fc25b65f5af96b1d5cc3b27d0c6053087b3",
+ "012fafec862f56e9e92f60ab0c77824f4299a0ca734ed26e0644d5d222c7f0bde03964f8e70a5cb65ed44e44d56ae0edf1ff86ca032cc5dd4404dbb76ab854586c44eed8336d08d457ce6c03693b45c0f1efef93624b95b8ec169c616d20e5538ebc0b6737a6f82b4bc0570924fc6b35759a3348426279f8b3d7744e2d222426ce",
+
+ /* 1027-bit key */
+ "054adb7886447efe6f57e0368f06cf52b0a3370760d161cef126b91be7f89c421b62a6ec1da3c311d75ed50e0ab5fff3fd338acc3aa8a4e77ee26369acb81ba900fa83f5300cf9bb6c53ad1dc8a178b815db4235a9a9da0c06de4e615ea1277ce559e9c108de58c14a81aa77f5a6f8d1335494498848c8b95940740be7bf7c3705",
+ "010001",
+ "fa041f8cd9697ceed38ec8caa275523b4dd72b09a301d3541d72f5d31c05cbce2d6983b36183af10690bd46c46131e35789431a556771dd0049b57461bf060c1f68472e8a67c25f357e5b6b4738fa541a730346b4a07649a2dfa806a69c975b6aba64678acc7f5913e89c622f2d8abb1e3e32554e39df94ba60c002e387d9011",
+ "029232336d2838945dba9dd7723f4e624a05f7375b927a87abe6a893a1658fd49f47f6c7b0fa596c65fa68a23f0ab432962d18d4343bd6fd671a5ea8d148413995",
+ "020ef5efe7c5394aed2272f7e81a74f4c02d145894cb1b3cab23a9a0710a2afc7e3329acbb743d01f680c4d02afb4c8fde7e20930811bb2b995788b5e872c20bb1",
+ "026e7e28010ecf2412d9523ad704647fb4fe9b66b1a681581b0e15553a89b1542828898f27243ebab45ff5e1acb9d4df1b051fbc62824dbc6f6c93261a78b9a759",
+ "012ddcc86ef655998c39ddae11718669e5e46cf1495b07e13b1014cd69b3af68304ad2a6b64321e78bf3bbca9bb494e91d451717e2d97564c6549465d0205cf421",
+ "010600c4c21847459fe576703e2ebecae8a5094ee63f536bf4ac68d3c13e5e4f12ac5cc10ab6a2d05a199214d1824747d551909636b774c22cac0b837599abcc75",
+
+ "9fb03b827c8217d9",
+ "ed7c98c95f30974fbe4fbddcf0f28d6021c0e91d",
+ "0323d5b7bf20ba4539289ae452ae4297080feff4518423ff4811a817837e7d82f1836cdfab54514ff0887bddeebf40bf99b047abc3ecfa6a37a3ef00f4a0c4a88aae0904b745c846c4107e8797723e8ac810d9e3d95dfa30ff4966f4d75d13768d20857f2b1406f264cfe75e27d7652f4b5ed3575f28a702f8c4ed9cf9b2d44948",
+
+ "0ca2ad77797ece86de5bf768750ddb5ed6a3116ad99bbd17edf7f782f0db1cd05b0f677468c5ea420dc116b10e80d110de2b0461ea14a38be68620392e7e893cb4ea9393fb886c20ff790642305bf302003892e54df9f667509dc53920df583f50a3dd61abb6fab75d600377e383e6aca6710eeea27156e06752c94ce25ae99fcbf8592dbe2d7e27453cb44de07100ebb1a2a19811a478adbeab270f94e8fe369d90b3ca612f9f",
+ "22d71d54363a4217aa55113f059b3384e3e57e44",
+ "049d0185845a264d28feb1e69edaec090609e8e46d93abb38371ce51f4aa65a599bdaaa81d24fba66a08a116cb644f3f1e653d95c89db8bbd5daac2709c8984000178410a7c6aa8667ddc38c741f710ec8665aa9052be929d4e3b16782c1662114c5414bb0353455c392fc28f3db59054b5f365c49e1d156f876ee10cb4fd70598",
+
+ "288062afc08fcdb7c5f8650b29837300461dd5676c17a20a3c8fb5148949e3f73d66b3ae82c7240e27c5b3ec4328ee7d6ddf6a6a0c9b5b15bcda196a9d0c76b119d534d85abd123962d583b76ce9d180bce1ca",
+ "4af870fbc6516012ca916c70ba862ac7e8243617",
+ "03fbc410a2ced59500fb99f9e2af2781ada74e13145624602782e2994813eefca0519ecd253b855fb626a90d771eae028b0c47a199cbd9f8e3269734af4163599090713a3fa910fa0960652721432b971036a7181a2bc0cab43b0b598bc6217461d7db305ff7e954c5b5bb231c39e791af6bcfa76b147b081321f72641482a2aad",
+
+ "6f4f9ab9501199cef55c6cf408fe7b36c557c49d420a4763d2463c8ad44b3cfc5be2742c0e7d9b0f6608f08c7f47b693ee",
+ "40d2e180fae1eac439c190b56c2c0e14ddf9a226",
+ "0486644bc66bf75d28335a6179b10851f43f09bded9fac1af33252bb9953ba4298cd6466b27539a70adaa3f89b3db3c74ab635d122f4ee7ce557a61e59b82ffb786630e5f9db53c77d9a0c12fab5958d4c2ce7daa807cd89ba2cc7fcd02ff470ca67b229fcce814c852c73cc93bea35be68459ce478e9d4655d121c8472f371d4f",
+
+ "e17d20385d501955823c3f666254c1d3dd36ad5168b8f18d286fdcf67a7dad94097085fab7ed86fe2142a28771717997ef1a7a08884efc39356d76077aaf82459a7fad45848875f2819b098937fe923bcc9dc442d72d754d812025090c9bc03db3080c138dd63b355d0b4b85d6688ac19f4de15084a0ba4e373b93ef4a555096691915dc23c00e954cdeb20a47cd55d16c3d8681d46ed7f2ed5ea42795be17baed25f0f4d113b3636addd585f16a8b5aec0c8fa9c5f03cbf3b9b73",
+ "2497dc2b4615dfae5a663d49ffd56bf7efc11304",
+ "022a80045353904cb30cbb542d7d4990421a6eec16a8029a8422adfd22d6aff8c4cc0294af110a0c067ec86a7d364134459bb1ae8ff836d5a8a2579840996b320b19f13a13fad378d931a65625dae2739f0c53670b35d9d3cbac08e733e4ec2b83af4b9196d63e7c4ff1ddeae2a122791a125bfea8deb0de8ccf1f4ffaf6e6fb0a",
+
+ "afbc19d479249018fdf4e09f618726440495de11ddeee38872d775fcea74a23896b5343c9c38d46af0dba224d047580cc60a65e9391cf9b59b36a860598d4e8216722f993b91cfae87bc255af89a6a199bca4a391eadbc3a24903c0bd667368f6be78e3feabfb4ffd463122763740ffbbefeab9a25564bc5d1c24c93e422f75073e2ad72bf45b10df00b52a147128e73fee33fa3f0577d77f80fbc2df1bed313290c12777f50",
+ "a334db6faebf11081a04f87c2d621cdec7930b9b",
+ "00938dcb6d583046065f69c78da7a1f1757066a7fa75125a9d2929f0b79a60b627b082f11f5b196f28eb9daa6f21c05e5140f6aef1737d2023075c05ecf04a028c686a2ab3e7d5a0664f295ce12995e890908b6ad21f0839eb65b70393a7b5afd9871de0caa0cedec5b819626756209d13ab1e7bb9546a26ff37e9a51af9fd562e",
+
+ /* 1028-bit key */
+ "0d10f661f29940f5ed39aa260966deb47843679d2b6fb25b3de370f3ac7c19916391fd25fb527ebfa6a4b4df45a1759d996c4bb4ebd18828c44fc52d0191871740525f47a4b0cc8da325ed8aa676b0d0f626e0a77f07692170acac8082f42faa7dc7cd123e730e31a87985204cabcbe6670d43a2dd2b2ddef5e05392fc213bc507",
+ "010001",
+ "03ce08b104fff396a979bd3e4e46925b6319ddb63acbcfd819f17d16b8077b3a87101ff34b77fe48b8b205a96e9151ba8ecea64d0cce7b23c3e6a6b83058bc49dae816ae736db5a4708e2ad435232b567f9096ce59ff28061e79ab1c02d717e6b23cea6db8eb5192fa7c1eab227dba74621c45601896eef13792c8440beb15aac1",
+ "03f2f331f4142d4f24b43aa10279a89652d4e7537221a1a7b2a25deb551e5de9ac497411c227a94e45f91c2d1c13cc046cf4ce14e32d058734210d44a87ee1b73f",
+ "034f090d73b55803030cf0361a5d8081bfb79f851523feac0a2124d08d4013ff08487771a870d0479dc0686c62f7718dfecf024b17c9267678059171339cc00839",
+ "02aa663adbf51ab887a018cb426e78bc2fe182dcb2f7bcb50441d17fdf0f06798b5071c6e2f5feb4d54ad8182311c1ef62d4c49f18d1f51f54b2d2cffba4da1be5",
+ "02bbe706078b5c0b391512d411db1b199b5a5664b84042ead37fe994ae72b9532dfbfb3e9e6981a0fbb806513141b7c2163fe56c395e4bfaee57e3833f9b918df9",
+ "0242b6cd00d30a767aee9a898ead453c8eaea63d500b7d1e00713edae51ce36b23b664df26e63e266ec8f76e6e63ed1ba41eb033b120f7ea5212ae21a98fbc16",
+
+ "30c7d557458b436decfdc14d06cb7b96b06718c48d7de57482a868ae7f065870a6216506d11b779323dfdf046cf5775129134b4d5689e4d9c0ce1e12d7d4b06cb5fc5820decfa41baf59bf257b32f025b7679b445b9499c92555145885992f1b76f84891ee4d3be0f5150fd5901e3a4c8ed43fd36b61d022e65ad5008dbf33293c22bfbfd07321f0f1d5fa9fdf0014c2fcb0358aad0e354b0d29",
+ "081b233b43567750bd6e78f396a88b9f6a445151",
+ "0ba373f76e0921b70a8fbfe622f0bf77b28a3db98e361051c3d7cb92ad0452915a4de9c01722f6823eeb6adf7e0ca8290f5de3e549890ac2a3c5950ab217ba58590894952de96f8df111b2575215da6c161590c745be612476ee578ed384ab33e3ece97481a252f5c79a98b5532ae00cdd62f2ecc0cd1baefe80d80b962193ec1d",
+
+ "e7b32e1556ea1b2795046ac69739d22ac8966bf11c116f614b166740e96b90653e5750945fcf772186c03790a07fda323e1a61916b06ee2157db3dff80d67d5e39a53ae268c8f09ed99a732005b0bc6a04af4e08d57a00e7201b3060efaadb73113bfc087fd837093aa25235b8c149f56215f031c24ad5bde7f29960df7d524070f7449c6f785084be1a0f733047f336f9154738674547db02a9f44dfc6e60301081e1ce99847f3b5b601ff06b4d5776a9740b9aa0d34058fd3b906e4f7859dfb07d7173e5e6f6350adac21f27b2307469",
+ "bd0ce19549d0700120cbe51077dbbbb00a8d8b09",
+ "08180de825e4b8b014a32da8ba761555921204f2f90d5f24b712908ff84f3e220ad17997c0dd6e706630ba3e84add4d5e7ab004e58074b549709565d43ad9e97b5a7a1a29e85b9f90f4aafcdf58321de8c5974ef9abf2d526f33c0f2f82e95d158ea6b81f1736db8d1af3d6ac6a83b32d18bae0ff1b2fe27de4c76ed8c7980a34e",
+
+ "8d8396e36507fe1ef6a19017548e0c716674c2fec233adb2f775665ec41f2bd0ba396b061a9daa7e866f7c23fd3531954300a342f924535ea1498c48f6c879932865fc02000c528723b7ad0335745b51209a0afed932af8f0887c219004d2abd894ea92559ee3198af3a734fe9b9638c263a728ad95a5ae8ce3eb15839f3aa7852bb390706e7760e43a71291a2e3f827237deda851874c517665f545f27238df86557f375d09ccd8bd15d8ccf61f5d78ca5c7f5cde782e6bf5d0057056d4bad98b3d2f9575e824ab7a33ff57b0ac100ab0d6ead7aa0b50f6e4d3e5ec0b966b",
+ "815779a91b3a8bd049bf2aeb920142772222c9ca",
+ "05e0fdbdf6f756ef733185ccfa8ced2eb6d029d9d56e35561b5db8e70257ee6fd019d2f0bbf669fe9b9821e78df6d41e31608d58280f318ee34f559941c8df13287574bac000b7e58dc4f414ba49fb127f9d0f8936638c76e85356c994f79750f7fa3cf4fd482df75e3fb9978cd061f7abb17572e6e63e0bde12cbdcf18c68b979",
+
+ "328c659e0a6437433cceb73c14",
+ "9aec4a7480d5bbc42920d7ca235db674989c9aac",
+ "0bc989853bc2ea86873271ce183a923ab65e8a53100e6df5d87a24c4194eb797813ee2a187c097dd872d591da60c568605dd7e742d5af4e33b11678ccb63903204a3d080b0902c89aba8868f009c0f1c0cb85810bbdd29121abb8471ff2d39e49fd92d56c655c8e037ad18fafbdc92c95863f7f61ea9efa28fea401369d19daea1",
+
+ "f37b962379a47d415a376eec8973150bcb34edd5ab654041b61430560c2144582ba133c867d852d6b8e23321901302ecb45b09ec88b1527178fa043263f3067d9ffe973032a99f4cb08ad2c7e0a2456cdd57a7df56fe6053527a5aeb67d7e552063c1ca97b1beffa7b39e997caf27878ea0f62cbebc8c21df4c889a202851e949088490c249b6e9acf1d8063f5be2343989bf95c4da01a2be78b4ab6b378015bc37957f76948b5e58e440c28453d40d7cfd57e7d690600474ab5e75973b1ea0c5f1e45d14190afe2f4eb6d3bdf71f1d2f8bb156a1c295d04aaeb9d689dce79ed62bc443e",
+ "e20c1e9878512c39970f58375e1549a68b64f31d",
+ "0aefa943b698b9609edf898ad22744ac28dc239497cea369cbbd84f65c95c0ad776b594740164b59a739c6ff7c2f07c7c077a86d95238fe51e1fcf33574a4ae0684b42a3f6bf677d91820ca89874467b2c23add77969c80717430d0efc1d3695892ce855cb7f7011630f4df26def8ddf36fc23905f57fa6243a485c770d5681fcd",
+
+ "c6103c330c1ef718c141e47b8fa859be4d5b96259e7d142070ecd485839dba5a8369c17c1114035e532d195c74f44a0476a2d3e8a4da210016caced0e367cb867710a4b5aa2df2b8e5daf5fdc647807d4d5ebb6c56b9763ccdae4dea3308eb0ac2a89501cb209d2639fa5bf87ce790747d3cb2d295e84564f2f637824f0c13028129b0aa4a422d162282",
+ "23291e4a3307e8bbb776623ab34e4a5f4cc8a8db",
+ "02802dccfa8dfaf5279bf0b4a29ba1b157611faeaaf419b8919d15941900c1339e7e92e6fae562c53e6cc8e84104b110bce03ad18525e3c49a0eadad5d3f28f244a8ed89edbafbb686277cfa8ae909714d6b28f4bf8e293aa04c41efe7c0a81266d5c061e2575be032aa464674ff71626219bd74cc45f0e7ed4e3ff96eee758e8f",
+
+ /* 1029-bit key */
+ "164ca31cff609f3a0e7101b039f2e4fe6dd37519ab98598d179e174996598071f47d3a04559158d7be373cf1aa53f0aa6ef09039e5678c2a4c63900514c8c4f8aaed5de12a5f10b09c311af8c0ffb5b7a297f2efc63b8d6b0510931f0b98e48bf5fc6ec4e7b8db1ffaeb08c38e02adb8f03a48229c99e969431f61cb8c4dc698d1",
+ "010001",
+ "03b664ee3b7566723fc6eaf28abb430a3980f1126c81de8ad709eab39ac9dcd0b1550b3729d87068e952009df544534c1f50829a78f4591eb8fd57140426a6bb0405b6a6f51a57d9267b7bbc653391a699a2a90dac8ae226bcc60fa8cd934c73c7b03b1f6b818158631838a8612e6e6ea92be24f8324faf5b1fd8587225267ba6f",
+ "04f0548c9626ab1ebf1244934741d99a06220efa2a5856aa0e75730b2ec96adc86be894fa2803b53a5e85d276acbd29ab823f80a7391bb54a5051672fb04eeb543",
+ "0483e0ae47915587743ff345362b555d3962d98bb6f15f848b4c92b1771ca8ed107d8d3ee65ec44517dd0faa481a387e902f7a2e747c269e7ea44480bc538b8e5b",
+ "03a8e8aea9920c1aa3b2f0d846e4b850d81ca306a51c83544f949f64f90dcf3f8e2661f07e561220a180388fbe273e70e2e5dca83a0e1348dd6490c731d6ece1ab",
+ "0135bdcdb60bf2197c436ed34b32cd8b4fc77778832ba76703551fb242b301699593af77fd8fc394a8526ad23cc41a03806bd897fe4b0ea646558aaddcc99e8a25",
+ "0304c03d9c736503a984abbd9ba22301407c4a2ab1dd85766481b60d45401152e692be14f4121d9aa3fd6e0b4d1d3a973538a31d42ee6e1e5ef620231a2bbaf35f",
+
+ "0a20b774addc2fa51245ed7cb9da609e50cac6636a52543f97458eed7340f8d53ffc64918f949078ee03ef60d42b5fec246050bd5505cd8cb597bad3c4e713b0ef30644e76adabb0de01a1561efb255158c74fc801e6e919e581b46f0f0ddd08e4f34c7810b5ed8318f91d7c8c",
+ "5b4ea2ef629cc22f3b538e016904b47b1e40bfd5",
+ "04c0cfacec04e5badbece159a5a1103f69b3f32ba593cb4cc4b1b7ab455916a96a27cd2678ea0f46ba37f7fc9c86325f29733b389f1d97f43e7201c0f348fc45fe42892335362eee018b5b161f2f9393031225c713012a576bc88e23052489868d9010cbf033ecc568e8bc152bdc59d560e41291915d28565208e22aeec9ef85d1",
+
+ "2aaff6631f621ce615760a9ebce94bb333077ad86488c861d4b76d29c1f48746c611ae1e03ced4445d7cfa1fe5f62e1b3f08452bde3b6ef81973bafbb57f97bceef873985395b8260589aa88cb7db50ab469262e551bdcd9a56f275a0ac4fe484700c35f3dbf2b469ede864741b86fa59172a360ba95a02e139be50ddfb7cf0b42faeabbfbbaa86a4497699c4f2dfd5b08406af7e14144427c253ec0efa20eaf9a8be8cd49ce1f1bc4e93e619cf2aa8ed4fb39bc8590d0f7b96488f7317ac9abf7bee4e3a0e715",
+ "83146a9e782722c28b014f98b4267bda2ac9504f",
+ "0a2314250cf52b6e4e908de5b35646bcaa24361da8160fb0f9257590ab3ace42b0dc3e77ad2db7c203a20bd952fbb56b1567046ecfaa933d7b1000c3de9ff05b7d989ba46fd43bc4c2d0a3986b7ffa13471d37eb5b47d64707bd290cfd6a9f393ad08ec1e3bd71bb5792615035cdaf2d8929aed3be098379377e777ce79aaa4773",
+
+ "0f6195d04a6e6fc7e2c9600dbf840c39ea8d4d624fd53507016b0e26858a5e0aecd7ada543ae5c0ab3a62599cba0a54e6bf446e262f989978f9ddf5e9a41",
+ "a87b8aed07d7b8e2daf14ddca4ac68c4d0aabff8",
+ "086df6b500098c120f24ff8423f727d9c61a5c9007d3b6a31ce7cf8f3cbec1a26bb20e2bd4a046793299e03e37a21b40194fb045f90b18bf20a47992ccd799cf9c059c299c0526854954aade8a6ad9d97ec91a1145383f42468b231f4d72f23706d9853c3fa43ce8ace8bfe7484987a1ec6a16c8daf81f7c8bf42774707a9df456",
+
+ "337d25fe9810ebca0de4d4658d3ceb8e0fe4c066aba3bcc48b105d3bf7e0257d44fecea6596f4d0c59a08402833678f70620f9138dfeb7ded905e4a6d5f05c473d55936652e2a5df43c0cfda7bacaf3087f4524b06cf42157d01539739f7fddec9d58125df31a32eab06c19b71f1d5bf",
+ "a37932f8a7494a942d6f767438e724d6d0c0ef18",
+ "0b5b11ad549863ffa9c51a14a1106c2a72cc8b646e5c7262509786105a984776534ca9b54c1cc64bf2d5a44fd7e8a69db699d5ea52087a4748fd2abc1afed1e5d6f7c89025530bdaa2213d7e030fa55df6f34bcf1ce46d2edf4e3ae4f3b01891a068c9e3a44bbc43133edad6ecb9f35400c4252a5762d65744b99cb9f4c559329f",
+
+ "84ec502b072e8287789d8f9235829ea3b187afd4d4c785611bda5f9eb3cb96717efa7007227f1c08cbcb972e667235e0fb7d431a6570326d2ecce35adb373dc753b3be5f829b89175493193fab16badb41371b3aac0ae670076f24bef420c135add7cee8d35fbc944d79fafb9e307a13b0f556cb654a06f973ed22672330197ef5a748bf826a5db2383a25364b686b9372bb2339aeb1ac9e9889327d016f1670776db06201adbdcaf8a5e3b74e108b73",
+ "7b790c1d62f7b84e94df6af28917cf571018110e",
+ "02d71fa9b53e4654fefb7f08385cf6b0ae3a817942ebf66c35ac67f0b069952a3ce9c7e1f1b02e480a9500836de5d64cdb7ecde04542f7a79988787e24c2ba05f5fd482c023ed5c30e04839dc44bed2a3a3a4fee01113c891a47d32eb8025c28cb050b5cdb576c70fe76ef523405c08417faf350b037a43c379339fcb18d3a356b",
+
+ "9906d89f97a9fdedd3ccd824db687326f30f00aa25a7fca2afcb3b0f86cd41e73f0e8ff7d2d83f59e28ed31a5a0d551523374de22e4c7e8ff568b386ee3dc41163f10bf67bb006261c9082f9af90bf1d9049a6b9fae71c7f84fbe6e55f02789de774f230f115026a4b4e96c55b04a95da3aacbb2cece8f81764a1f1c99515411087cf7d34aeded0932c183",
+ "fbbe059025b69b89fb14ae2289e7aaafe60c0fcd",
+ "0a40a16e2fe2b38d1df90546167cf9469c9e3c3681a3442b4b2c2f581deb385ce99fc6188bb02a841d56e76d301891e24560550fcc2a26b55f4ccb26d837d350a154bcaca8392d98fa67959e9727b78cad03269f56968fc56b68bd679926d83cc9cb215550645ccda31c760ff35888943d2d8a1d351e81e5d07b86182e751081ef",
+
+ /* 1030-bit key */
+ "37c9da4a66c8c408b8da27d0c9d79f8ccb1eafc1d2fe48746d940b7c4ef5dee18ad12647cefaa0c4b3188b221c515386759b93f02024b25ab9242f8357d8f3fd49640ee5e643eaf6c64deefa7089727c8ff03993333915c6ef21bf5975b6e50d118b51008ec33e9f01a0a545a10a836a43ddbca9d8b5c5d3548022d7064ea29ab3",
+ "010001",
+ "3bed999052d957bc06d651eef6e3a98094b1621bd38b5449bd6c4aea3de7e084679a4484ded25be0f0826cf3377825414b14d4d61db14de626fbb80e5f4faec956f9a0a2d24f99576380f084eb62e46a57d554278b535626193ce02060575eb66c5798d36f6c5d40fb00d809b42a73102c1c74ee95bd71420fffef6318b52c29",
+ "07eefb424b0e3a40e4208ee5afb280b22317308114dde0b4b64f730184ec68da6ce2867a9f48ed7726d5e2614ed04a5410736c8c714ee702474298c6292af07535",
+ "070830dbf947eac0228de26314b59b66994cc60e8360e75d3876298f8f8a7d141da064e5ca026a973e28f254738cee669c721b034cb5f8e244dadd7cd1e159d547",
+ "0524d20c3d95cff75af2313483227d8702717aa576de155f960515501adb1d70e1c04de91b75b161dbf0398356127ededa7bbc19a32dc1621cc9f53c265d0ce331",
+ "05f984a1f23c938d6a0e89724bcf3dd93f9946926037fe7c6b13a29e5284855f89089591d440975627bf5c9e3a8b5ca79c772ad273e40d321af4a6c97dfded78d3",
+ "ddd918adada29dcab981ff9acba4257023c09a3801ccce098ce268f855d0df570cd6e7b9b14bd9a5a9254cbc315be6f8ba1e2546ddd569c5ea19eed8353bde5e",
+
+ "9ead0e01945640674eb41cad435e2374eaefa8ad7197d97913c44957d8d83f40d76ee60e39bf9c0f9eaf3021421a074d1ade962c6e9d3dc3bb174fe4dfe652b09115495b8fd2794174020a0602b5ca51848cfc96ce5eb57fc0a2adc1dda36a7cc452641a14911b37e45bfa11daa5c7ecdb74f6d0100d1d3e39e752800e203397de0233077b9a88855537fae927f924380d780f98e18dcff39c5ea741b17d6fdd1885bc9d581482d771ceb562d78a8bf88f0c75b11363e5e36cd479ceb0545f9da84203e0e6e508375cc9e844b88b7ac7a0a201ea0f1bee9a2c577920ca02c01b9d8320e974a56f4efb5763b96255abbf8037bf1802cf018f56379493e569a9",
+ "b7867a59958cb54328f8775e6546ec06d27eaa50",
+ "187f390723c8902591f0154bae6d4ecbffe067f0e8b795476ea4f4d51ccc810520bb3ca9bca7d0b1f2ea8a17d873fa27570acd642e3808561cb9e975ccfd80b23dc5771cdb3306a5f23159dacbd3aa2db93d46d766e09ed15d900ad897a8d274dc26b47e994a27e97e2268a766533ae4b5e42a2fcaf755c1c4794b294c60555823",
+
+ "8d80d2d08dbd19c154df3f14673a14bd03735231f24e86bf153d0e69e74cbff7b1836e664de83f680124370fc0f96c9b65c07a366b644c4ab3",
+ "0c09582266df086310821ba7e18df64dfee6de09",
+ "10fd89768a60a67788abb5856a787c8561f3edcf9a83e898f7dc87ab8cce79429b43e56906941a886194f137e591fe7c339555361fbbe1f24feb2d4bcdb80601f3096bc9132deea60ae13082f44f9ad41cd628936a4d51176e42fc59cb76db815ce5ab4db99a104aafea68f5d330329ebf258d4ede16064bd1d00393d5e1570eb8",
+
+ "808405cdfc1a58b9bb0397c720722a81fffb76278f335917ef9c473814b3e016ba2973cd2765f8f3f82d6cc38aa7f8551827fe8d1e3884b7e61c94683b8f82f1843bdae2257eeec9812ad4c2cf283c34e0b0ae0fe3cb990cf88f2ef9",
+ "28039dcfe106d3b8296611258c4a56651c9e92dd",
+ "2b31fde99859b977aa09586d8e274662b25a2a640640b457f594051cb1e7f7a911865455242926cf88fe80dfa3a75ba9689844a11e634a82b075afbd69c12a0df9d25f84ad4945df3dc8fe90c3cefdf26e95f0534304b5bdba20d3e5640a2ebfb898aac35ae40f26fce5563c2f9f24f3042af76f3c7072d687bbfb959a88460af1",
+
+ "f337b9bad937de22a1a052dff11134a8ce26976202981939b91e0715ae5e609649da1adfcef3f4cca59b238360e7d1e496c7bf4b204b5acff9bbd6166a1d87a36ef2247373751039f8a800b8399807b3a85f44893497c0d05fb7017b82228152de6f25e6116dcc7503c786c875c28f3aa607e94ab0f19863ab1b5073770b0cd5f533acde30c6fb953cf3da680264e30fc11bff9a19bffab4779b6223c3fb3fe0f71abade4eb7c09c41e24c22d23fa148e6a173feb63984d1bc6ee3a02d915b752ceaf92a3015eceb38ca586c6801b37c34cefb2cff25ea23c08662dcab26a7a93a285d05d3044c",
+ "a77821ebbbef24628e4e12e1d0ea96de398f7b0f",
+ "32c7ca38ff26949a15000c4ba04b2b13b35a3810e568184d7ecabaa166b7ffabddf2b6cf4ba07124923790f2e5b1a5be040aea36fe132ec130e1f10567982d17ac3e89b8d26c3094034e762d2e031264f01170beecb3d1439e05846f25458367a7d9c02060444672671e64e877864559ca19b2074d588a281b5804d23772fbbe19",
+
+ "45013cebafd960b255476a8e2598b9aa32efbe6dc1f34f4a498d8cf5a2b4548d08c55d5f95f7bcc9619163056f2d58b52fa032",
+ "9d5ad8eb452134b65dc3a98b6a73b5f741609cd6",
+ "07eb651d75f1b52bc263b2e198336e99fbebc4f332049a922a10815607ee2d989db3a4495b7dccd38f58a211fb7e193171a3d891132437ebca44f318b280509e52b5fa98fcce8205d9697c8ee4b7ff59d4c59c79038a1970bd2a0d451ecdc5ef11d9979c9d35f8c70a6163717607890d586a7c6dc01c79f86a8f28e85235f8c2f1",
+
+ "2358097086c899323e75d9c90d0c09f12d9d54edfbdf70a9c2eb5a04d8f36b9b2bdf2aabe0a5bda1968937f9d6ebd3b6b257efb3136d4131f9acb59b85e2602c2a3fcdc835494a1f4e5ec18b226c80232b36a75a45fdf09a7ea9e98efbde1450d1194bf12e15a4c5f9eb5c0bce5269e0c3b28cfab655d81a61a20b4be2f54459bb25a0db94c52218be109a7426de83014424789aaa90e5056e632a698115e282c1a56410f26c2072f193481a9dcd880572005e64f4082ecf",
+ "3f2efc595880a7d47fcf3cba04983ea54c4b73fb",
+ "18da3cdcfe79bfb77fd9c32f377ad399146f0a8e810620233271a6e3ed3248903f5cdc92dc79b55d3e11615aa056a795853792a3998c349ca5c457e8ca7d29d796aa24f83491709befcfb1510ea513c92829a3f00b104f655634f320752e130ec0ccf6754ff893db302932bb025eb60e87822598fc619e0e981737a9a4c4152d33",
+
+ /* 1031-bit key */
+ "495370a1fb18543c16d3631e3163255df62be6eee890d5f25509e4f778a8ea6fbbbcdf85dff64e0d972003ab3681fbba6dd41fd541829b2e582de9f2a4a4e0a2d0900bef4753db3cee0ee06c7dfae8b1d53b5953218f9cceea695b08668edeaadced9463b1d790d5ebf27e9115b46cad4d9a2b8efab0561b0810344739ada0733f",
+ "010001",
+ "6c66ffe98980c38fcdeab5159898836165f4b4b817c4f6a8d486ee4ea9130fe9b9092bd136d184f95f504a607eac565846d2fdd6597a8967c7396ef95a6eeebb4578a643966dca4d8ee3de842de63279c618159c1ab54a89437b6a6120e4930afb52a4ba6ced8a4947ac64b30a3497cbe701c2d6266d517219ad0ec6d347dbe9",
+ "08dad7f11363faa623d5d6d5e8a319328d82190d7127d2846c439b0ab72619b0a43a95320e4ec34fc3a9cea876422305bd76c5ba7be9e2f410c8060645a1d29edb",
+ "0847e732376fc7900f898ea82eb2b0fc418565fdae62f7d9ec4ce2217b97990dd272db157f99f63c0dcbb9fbacdbd4c4dadb6df67756358ca4174825b48f49706d",
+ "05c2a83c124b3621a2aa57ea2c3efe035eff4560f33ddebb7adab81fce69a0c8c2edc16520dda83d59a23be867963ac65f2cc710bbcfb96ee103deb771d105fd85",
+ "04cae8aa0d9faa165c87b682ec140b8ed3b50b24594b7a3b2c220b3669bb819f984f55310a1ae7823651d4a02e99447972595139363434e5e30a7e7d241551e1b9",
+ "07d3e47bf686600b11ac283ce88dbb3f6051e8efd04680e44c171ef531b80b2b7c39fc766320e2cf15d8d99820e96ff30dc69691839c4b40d7b06e45307dc91f3f",
+
+ "81332f4be62948415ea1d899792eeacf6c6e1db1da8be13b5cea41db2fed467092e1ff398914c714259775f595f8547f735692a575e6923af78f22c6997ddb90fb6f72d7bb0dd5744a31decd3dc3685849836ed34aec596304ad11843c4f88489f209735f5fb7fdaf7cec8addc5818168f880acbf490d51005b7a8e84e43e54287977571dd99eea4b161eb2df1f5108f12a4142a83322edb05a75487a3435c9a78ce53ed93bc550857d7a9fb",
+ "1d65491d79c864b373009be6f6f2467bac4c78fa",
+ "0262ac254bfa77f3c1aca22c5179f8f040422b3c5bafd40a8f21cf0fa5a667ccd5993d42dbafb409c520e25fce2b1ee1e716577f1efa17f3da28052f40f0419b23106d7845aaf01125b698e7a4dfe92d3967bb00c4d0d35ba3552ab9a8b3eef07c7fecdbc5424ac4db1e20cb37d0b2744769940ea907e17fbbca673b20522380c5",
+
+ "e2f96eaf0e05e7ba326ecca0ba7fd2f7c02356f3cede9d0faabf4fcc8e60a973e5595fd9ea08",
+ "435c098aa9909eb2377f1248b091b68987ff1838",
+ "2707b9ad5115c58c94e932e8ec0a280f56339e44a1b58d4ddcff2f312e5f34dcfe39e89c6a94dcee86dbbdae5b79ba4e0819a9e7bfd9d982e7ee6c86ee68396e8b3a14c9c8f34b178eb741f9d3f121109bf5c8172fada2e768f9ea1433032c004a8aa07eb990000a48dc94c8bac8aabe2b09b1aa46c0a2aa0e12f63fbba775ba7e",
+
+ "e35c6ed98f64a6d5a648fcab8adb16331db32e5d15c74a40edf94c3dc4a4de792d190889f20f1e24ed12054a6b28798fcb42d1c548769b734c96373142092aed277603f4738df4dc1446586d0ec64da4fb60536db2ae17fc7e3c04bbfbbbd907bf117c08636fa16f95f51a6216934d3e34f85030f17bbbc5ba69144058aff081e0b19cf03c17195c5e888ba58f6fe0a02e5c3bda9719a7",
+ "c6ebbe76df0c4aea32c474175b2f136862d04529",
+ "2ad20509d78cf26d1b6c406146086e4b0c91a91c2bd164c87b966b8faa42aa0ca446022323ba4b1a1b89706d7f4c3be57d7b69702d168ab5955ee290356b8c4a29ed467d547ec23cbadf286ccb5863c6679da467fc9324a151c7ec55aac6db4084f82726825cfe1aa421bc64049fb42f23148f9c25b2dc300437c38d428aa75f96",
+
+ "dbc5f750a7a14be2b93e838d18d14a8695e52e8add9c0ac733b8f56d2747e529a0cca532dd49b902aefed514447f9e81d16195c2853868cb9b30f7d0d495c69d01b5c5d50b27045db3866c2324a44a110b1717746de457d1c8c45c3cd2a92970c3d59632055d4c98a41d6e99e2a3ddd5f7f9979ab3cd18f37505d25141de2a1bff17b3a7dce9419ecc385cf11d72840f19953fd0509251f6cafde2893d0e75c781ba7a5012ca401a4fa99e04b3c3249f926d5afe82cc87dab22c3c1b105de48e34ace9c9124e59597ac7ebf8",
+ "021fdcc6ebb5e19b1cb16e9c67f27681657fe20a",
+ "1e24e6e58628e5175044a9eb6d837d48af1260b0520e87327de7897ee4d5b9f0df0be3e09ed4dea8c1454ff3423bb08e1793245a9df8bf6ab3968c8eddc3b5328571c77f091cc578576912dfebd164b9de5454fe0be1c1f6385b328360ce67ec7a05f6e30eb45c17c48ac70041d2cab67f0a2ae7aafdcc8d245ea3442a6300ccc7",
+
+ "04dc251be72e88e5723485b6383a637e2fefe07660c519a560b8bc18bdedb86eae2364ea53ba9dca6eb3d2e7d6b806af42b3e87f291b4a8881d5bf572cc9a85e19c86acb28f098f9da0383c566d3c0f58cfd8f395dcf602e5cd40e8c7183f714996e2297ef",
+ "c558d7167cbb4508ada042971e71b1377eea4269",
+ "33341ba3576a130a50e2a5cf8679224388d5693f5accc235ac95add68e5eb1eec31666d0ca7a1cda6f70a1aa762c05752a51950cdb8af3c5379f18cfe6b5bc55a4648226a15e912ef19ad77adeea911d67cfefd69ba43fa4119135ff642117ba985a7e0100325e9519f1ca6a9216bda055b5785015291125e90dcd07a2ca9673ee",
+
+ "0ea37df9a6fea4a8b610373c24cf390c20fa6e2135c400c8a34f5c183a7e8ea4c9ae090ed31759f42dc77719cca400ecdcc517acfc7ac6902675b2ef30c509665f3321482fc69a9fb570d15e01c845d0d8e50d2a24cbf1cf0e714975a5db7b18d9e9e9cb91b5cb16869060ed18b7b56245503f0caf90352b8de81cb5a1d9c6336092f0cd",
+ "76fd4e64fdc98eb927a0403e35a084e76ba9f92a",
+ "1ed1d848fb1edb44129bd9b354795af97a069a7a00d0151048593e0c72c3517ff9ff2a41d0cb5a0ac860d736a199704f7cb6a53986a88bbd8abcc0076a2ce847880031525d449da2ac78356374c536e343faa7cba42a5aaa6506087791c06a8e989335aed19bfab2d5e67e27fb0c2875af896c21b6e8e7309d04e4f6727e69463e",
+
+ /* 1536-bit key */
+ "e6bd692ac96645790403fdd0f5beb8b9bf92ed10007fc365046419dd06c05c5b5b2f48ecf989e4ce269109979cbb40b4a0ad24d22483d1ee315ad4ccb1534268352691c524f6dd8e6c29d224cf246973aec86c5bf6b1401a850d1b9ad1bb8cbcec47b06f0f8c7f45d3fc8f319299c5433ddbc2b3053b47ded2ecd4a4caefd614833dc8bb622f317ed076b8057fe8de3f84480ad5e83e4a61904a4f248fb397027357e1d30e463139815c6fd4fd5ac5b8172a45230ecb6318a04f1455d84e5a8b",
+ "010001",
+ "6a7fd84fb85fad073b34406db74f8d61a6abc12196a961dd79565e9da6e5187bce2d980250f7359575359270d91590bb0e427c71460b55d51410b191bcf309fea131a92c8e702738fa719f1e0041f52e40e91f229f4d96a1e6f172e15596b4510a6daec26105f2bebc53316b87bdf21311666070e8dfee69d52c71a976caae79c72b68d28580dc686d9f5129d225f82b3d615513a882b3db91416b48ce08888213e37eeb9af800d81cab328ce420689903c00c7b5fd31b75503a6d419684d629",
+ "f8eb97e98df12664eefdb761596a69ddcd0e76daece6ed4bf5a1b50ac086f7928a4d2f8726a77e515b74da41988f220b1cc87aa1fc810ce99a82f2d1ce821edced794c6941f42c7a1a0b8c4d28c75ec60b652279f6154a762aed165d47dee367",
+ "ed4d71d0a6e24b93c2e5f6b4bbe05f5fb0afa042d204fe3378d365c2f288b6a8dad7efe45d153eef40cacc7b81ff934002d108994b94a5e4728cd9c963375ae49965bda55cbf0efed8d6553b4027f2d86208a6e6b489c176128092d629e49d3d",
+ "2bb68bddfb0c4f56c8558bffaf892d8043037841e7fa81cfa61a38c5e39b901c8ee71122a5da2227bd6cdeeb481452c12ad3d61d5e4f776a0ab556591befe3e59e5a7fddb8345e1f2f35b9f4cee57c32414c086aec993e9353e480d9eec6289f",
+ "4ff897709fad079746494578e70fd8546130eeab5627c49b080f05ee4ad9f3e4b7cba9d6a5dff113a41c3409336833f190816d8a6bc42e9bec56b7567d0f3c9c696db619b245d901dd856db7c8092e77e9a1cccd56ee4dba42c5fdb61aec2669",
+ "77b9d1137b50404a982729316efafc7dfe66d34e5a182600d5f30a0a8512051c560d081d4d0a1835ec3d25a60f4e4d6aa948b2bf3dbb5b124cbbc3489255a3a948372f6978496745f943e1db4f18382ceaa505dfc65757bb3f857a58dce52156",
+
+ "a88e265855e9d7ca36c68795f0b31b591cd6587c71d060a0b3f7f3eaef43795922028bc2b6ad467cfc2d7f659c5385aa70ba3672cdde4cfe4970cc7904601b278872bf51321c4a972f3c95570f3445d4f57980e0f20df54846e6a52c668f1288c03f95006ea32f562d40d52af9feb32f0fa06db65b588a237b34e592d55cf979f903a642ef64d2ed542aa8c77dc1dd762f45a59303ed75e541ca271e2b60ca709e44fa0661131e8d5d4163fd8d398566ce26de8730e72f9cca737641c244159420637028df0a18079d6208ea8b4711a2c750f5",
+ "c0a425313df8d7564bd2434d311523d5257eed80",
+ "586107226c3ce013a7c8f04d1a6a2959bb4b8e205ba43a27b50f124111bc35ef589b039f5932187cb696d7d9a32c0c38300a5cdda4834b62d2eb240af33f79d13dfbf095bf599e0d9686948c1964747b67e89c9aba5cd85016236f566cc5802cb13ead51bc7ca6bef3b94dcbdbb1d570469771df0e00b1a8a06777472d2316279edae86474668d4e1efff95f1de61c6020da32ae92bbf16520fef3cf4d88f61121f24bbd9fe91b59caf1235b2a93ff81fc403addf4ebdea84934a9cdaf8e1a9e",
+
+ "c8c9c6af04acda414d227ef23e0820c3732c500dc87275e95b0d095413993c2658bc1d988581ba879c2d201f14cb88ced153a01969a7bf0a7be79c84c1486bc12b3fa6c59871b6827c8ce253ca5fefa8a8c690bf326e8e37cdb96d90a82ebab69f86350e1822e8bd536a2e",
+ "b307c43b4850a8dac2f15f32e37839ef8c5c0e91",
+ "80b6d643255209f0a456763897ac9ed259d459b49c2887e5882ecb4434cfd66dd7e1699375381e51cd7f554f2c271704b399d42b4be2540a0eca61951f55267f7c2878c122842dadb28b01bd5f8c025f7e228418a673c03d6bc0c736d0a29546bd67f786d9d692ccea778d71d98c2063b7a71092187a4d35af108111d83e83eae46c46aa34277e06044589903788f1d5e7cee25fb485e92949118814d6f2c3ee361489016f327fb5bc517eb50470bffa1afa5f4ce9aa0ce5b8ee19bf5501b958",
+
+ "0afad42ccd4fc60654a55002d228f52a4a5fe03b8bbb08ca82daca558b44dbe1266e50c0e745a36d9d2904e3408abcd1fd569994063f4a75cc72f2fee2a0cd893a43af1c5b8b487df0a71610024e4f6ddf9f28ad0813c1aab91bcb3c9064d5ff742deffea657094139369e5ea6f4a96319a5cc8224145b545062758fefd1fe3409ae169259c6cdfd6b5f2958e314faecbe69d2cace58ee55179ab9b3e6d1ecc14a557c5febe988595264fc5da1c571462eca798a18a1a4940cdab4a3e92009ccd42e1e947b1314e32238a2dece7d23a89b5b30c751fd0a4a430d2c548594",
+ "9a2b007e80978bbb192c354eb7da9aedfc74dbf5",
+ "484408f3898cd5f53483f80819efbf2708c34d27a8b2a6fae8b322f9240237f981817aca1846f1084daa6d7c0795f6e5bf1af59c38e1858437ce1f7ec419b98c8736adf6dd9a00b1806d2bd3ad0a73775e05f52dfef3a59ab4b08143f0df05cd1ad9d04bececa6daa4a2129803e200cbc77787caf4c1d0663a6c5987b605952019782caf2ec1426d68fb94ed1d4be816a7ed081b77e6ab330b3ffc073820fecde3727fcbe295ee61a050a343658637c3fd659cfb63736de32d9f90d3c2f63eca",
+
+ "1dfd43b46c93db82629bdae2bd0a12b882ea04c3b465f5cf93023f01059626dbbe99f26bb1be949dddd16dc7f3debb19a194627f0b224434df7d8700e9e98b06e360c12fdbe3d19f51c9684eb9089ecbb0a2f0450399d3f59eac7294085d044f5393c6ce737423d8b86c415370d389e30b9f0a3c02d25d0082e8ad6f3f1ef24a45c3cf82b383367063a4d4613e4264f01b2dac2e5aa42043f8fb5f69fa871d14fb273e767a531c40f02f343bc2fb45a0c7e0f6be2561923a77211d66a6e2dbb43c366350beae22da3ac2c1f5077096fcb5c4bf255f7574351ae0b1e1f03632817c0856d4a8ba97afbdc8b85855402bc56926fcec209f9ea8",
+ "70f382bddf4d5d2dd88b3bc7b7308be632b84045",
+ "84ebeb481be59845b46468bafb471c0112e02b235d84b5d911cbd1926ee5074ae0424495cb20e82308b8ebb65f419a03fb40e72b78981d88aad143053685172c97b29c8b7bf0ae73b5b2263c403da0ed2f80ff7450af7828eb8b86f0028bd2a8b176a4d228cccea18394f238b09ff758cc00bc04301152355742f282b54e663a919e709d8da24ade5500a7b9aa50226e0ca52923e6c2d860ec50ff480fa57477e82b0565f4379f79c772d5c2da80af9fbf325ece6fc20b00961614bee89a183e",
+
+ "1bdc6e7c98fb8cf54e9b097b66a831e9cfe52d9d4888448ee4b0978093ba1d7d73ae78b3a62ba4ad95cd289ccb9e005226bb3d178bccaa821fb044a4e21ee97696c14d0678c94c2dae93b0ad73922218553daa7e44ebe57725a7a45cc72b9b2138a6b17c8db411ce8279ee1241aff0a8bec6f77f87edb0c69cb27236e3435a800b192e4f11e519e3fe30fc30eaccca4fbb41769029bf708e817a9e683805be67fa100984683b74838e3bcffa79366eed1d481c76729118838f31ba8a048a93c1be4424598e8df6328b7a77880a3f9c7e2e8dfca8eb5a26fb86bdc556d42bbe01d9fa6ed80646491c9341",
+ "d689257a86effa68212c5e0c619eca295fb91b67",
+ "82102df8cb91e7179919a04d26d335d64fbc2f872c44833943241de8454810274cdf3db5f42d423db152af7135f701420e39b494a67cbfd19f9119da233a23da5c6439b5ba0d2bc373eee3507001378d4a4073856b7fe2aba0b5ee93b27f4afec7d4d120921c83f606765b02c19e4d6a1a3b95fa4c422951be4f52131077ef17179729cddfbdb56950dbaceefe78cb16640a099ea56d24389eef10f8fecb31ba3ea3b227c0a86698bb89e3e9363905bf22777b2a3aa521b65b4cef76d83bde4c",
+
+ "88c7a9f1360401d90e53b101b61c5325c3c75db1b411fbeb8e830b75e96b56670ad245404e16793544ee354bc613a90cc9848715a73db5893e7f6d279815c0c1de83ef8e2956e3a56ed26a888d7a9cdcd042f4b16b7fa51ef1a0573662d16a302d0ec5b285d2e03ad96529c87b3d374db372d95b2443d061b6b1a350ba87807ed083afd1eb05c3f52f4eba5ed2227714fdb50b9d9d9dd6814f62f6272fcd5cdbce7a9ef797",
+ "c25f13bf67d081671a0481a1f1820d613bba2276",
+ "a7fdb0d259165ca2c88d00bbf1028a867d337699d061193b17a9648e14ccbbaadeacaacdec815e7571294ebb8a117af205fa078b47b0712c199e3ad05135c504c24b81705115740802487992ffd511d4afc6b854491eb3f0dd523139542ff15c3101ee85543517c6a3c79417c67e2dd9aa741e9a29b06dcb593c2336b3670ae3afbac7c3e76e215473e866e338ca244de00b62624d6b9426822ceae9f8cc460895f41250073fd45c5a1e7b425c204a423a699159f6903e710b37a7bb2bc8049f",
+
+ /* 2048-bit key */
+ "a5dd867ac4cb02f90b9457d48c14a770ef991c56c39c0ec65fd11afa8937cea57b9be7ac73b45c0017615b82d622e318753b6027c0fd157be12f8090fee2a7adcd0eef759f88ba4997c7a42d58c9aa12cb99ae001fe521c13bb5431445a8d5ae4f5e4c7e948ac227d3604071f20e577e905fbeb15dfaf06d1de5ae6253d63a6a2120b31a5da5dabc9550600e20f27d3739e2627925fea3cc509f21dff04e6eea4549c540d6809ff9307eede91fff58733d8385a237d6d3705a33e391900992070df7adf1357cf7e3700ce3667de83f17b8df1778db381dce09cb4ad058a511001a738198ee27cf55a13b754539906582ec8b174bd58d5d1f3d767c613721ae05",
+ "010001",
+ "2d2ff567b3fe74e06191b7fded6de112290c670692430d5969184047da234c9693deed1673ed429539c969d372c04d6b47e0f5b8cee0843e5c22835dbd3b05a0997984ae6058b11bc4907cbf67ed84fa9ae252dfb0d0cd49e618e35dfdfe59bca3ddd66c33cebbc77ad441aa695e13e324b518f01c60f5a85c994ad179f2a6b5fbe93402b11767be01bf073444d6ba1dd2bca5bd074d4a5fae3531ad1303d84b30d897318cbbba04e03c2e66de6d91f82f96ea1d4bb54a5aae102d594657f5c9789553512b296dea29d8023196357e3e3a6e958f39e3c2344038ea604b31edc6f0f7ff6e7181a57c92826a268f86768e96f878562fc71d85d69e448612f7048f",
+ "cfd50283feeeb97f6f08d73cbc7b3836f82bbcd499479f5e6f76fdfcb8b38c4f71dc9e88bd6a6f76371afd65d2af1862b32afb34a95f71b8b132043ffebe3a952baf7592448148c03f9c69b1d68e4ce5cf32c86baf46fed301ca1ab403069b32f456b91f71898ab081cd8c4252ef5271915c9794b8f295851da7510f99cb73eb",
+ "cc4e90d2a1b3a065d3b2d1f5a8fce31b544475664eab561d2971b99fb7bef844e8ec1f360b8c2ac8359692971ea6a38f723fcc211f5dbcb177a0fdac5164a1d4ff7fbb4e829986353cb983659a148cdd420c7d31ba3822ea90a32be46c030e8c17e1fa0ad37859e06b0aa6fa3b216d9cbe6c0e22339769c0a615913e5da719cf",
+ "1c2d1fc32f6bc4004fd85dfde0fbbf9a4c38f9c7c4e41dea1aa88234a201cd92f3b7da526583a98ad85bb360fb983b711e23449d561d1778d7a515486bcbf47b46c9e9e1a3a1f77000efbeb09a8afe47e5b857cda99cb16d7fff9b712e3bd60ca96d9c7973d616d46934a9c050281c004399ceff1db7dda78766a8a9b9cb0873",
+ "cb3b3c04caa58c60be7d9b2debb3e39643f4f57397be08236a1e9eafaa706536e71c3acfe01cc651f23c9e05858fee13bb6a8afc47df4edc9a4ba30bcecb73d0157852327ee789015c2e8dee7b9f05a0f31ac94eb6173164740c5c95147cd5f3b5ae2cb4a83787f01d8ab31f27c2d0eea2dd8a11ab906aba207c43c6ee125331",
+ "12f6b2cf1374a736fad05616050f96ab4b61d1177c7f9d525a29f3d180e77667e99d99abf0525d0758660f3752655b0f25b8df8431d9a8ff77c16c12a0a5122a9f0bf7cfd5a266a35c159f991208b90316ff444f3e0b6bd0e93b8a7a2448e957e3dda6cfcf2266b106013ac46808d3b3887b3b00344baac9530b4ce708fc32b6",
+
+ "883177e5126b9be2d9a9680327d5370c6f26861f5820c43da67a3ad609",
+ "04e215ee6ff934b9da70d7730c8734abfcecde89",
+ "82c2b160093b8aa3c0f7522b19f87354066c77847abf2a9fce542d0e84e920c5afb49ffdfdace16560ee94a1369601148ebad7a0e151cf16331791a5727d05f21e74e7eb811440206935d744765a15e79f015cb66c532c87a6a05961c8bfad741a9a6657022894393e7223739796c02a77455d0f555b0ec01ddf259b6207fd0fd57614cef1a5573baaff4ec00069951659b85f24300a25160ca8522dc6e6727e57d019d7e63629b8fe5e89e25cc15beb3a647577559299280b9b28f79b0409000be25bbd96408ba3b43cc486184dd1c8e62553fa1af4040f60663de7f5e49c04388e257f1ce89c95dab48a315d9b66b1b7628233876ff2385230d070d07e1666",
+
+ "dd670a01465868adc93f26131957a50c52fb777cdbaa30892c9e12361164ec13979d43048118e4445db87bee58dd987b3425d02071d8dbae80708b039dbb64dbd1de5657d9fed0c118a54143742e0ff3c87f74e45857647af3f79eb0a14c9d75ea9a1a04b7cf478a897a708fd988f48e801edb0b7039df8c23bb3c56f4e821ac",
+ "8b2bdd4b40faf545c778ddf9bc1a49cb57f9b71b",
+ "14ae35d9dd06ba92f7f3b897978aed7cd4bf5ff0b585a40bd46ce1b42cd2703053bb9044d64e813d8f96db2dd7007d10118f6f8f8496097ad75e1ff692341b2892ad55a633a1c55e7f0a0ad59a0e203a5b8278aec54dd8622e2831d87174f8caff43ee6c46445345d84a59659bfb92ecd4c818668695f34706f66828a89959637f2bf3e3251c24bdba4d4b7649da0022218b119c84e79a6527ec5b8a5f861c159952e23ec05e1e717346faefe8b1686825bd2b262fb2531066c0de09acde2e4231690728b5d85e115a2f6b92b79c25abc9bd9399ff8bcf825a52ea1f56ea76dd26f43baafa18bfa92a504cbd35699e26d1dcc5a2887385f3c63232f06f3244c3",
+
+ "48b2b6a57a63c84cea859d65c668284b08d96bdcaabe252db0e4a96cb1bac6019341db6fbefb8d106b0e90eda6bcc6c6262f37e7ea9c7e5d226bd7df85ec5e71efff2f54c5db577ff729ff91b842491de2741d0c631607df586b905b23b91af13da12304bf83eca8a73e871ff9db",
+ "4e96fc1b398f92b44671010c0dc3efd6e20c2d73",
+ "6e3e4d7b6b15d2fb46013b8900aa5bbb3939cf2c095717987042026ee62c74c54cffd5d7d57efbbf950a0f5c574fa09d3fc1c9f513b05b4ff50dd8df7edfa20102854c35e592180119a70ce5b085182aa02d9ea2aa90d1df03f2daae885ba2f5d05afdac97476f06b93b5bc94a1a80aa9116c4d615f333b098892b25fface266f5db5a5a3bcc10a824ed55aad35b727834fb8c07da28fcf416a5d9b2224f1f8b442b36f91e456fdea2d7cfe3367268de0307a4c74e924159ed33393d5e0655531c77327b89821bdedf880161c78cd4196b5419f7acc3f13e5ebf161b6e7c6724716ca33b85c2e25640192ac2859651d50bde7eb976e51cec828b98b6563b86bb",
+
+ "0b8777c7f839baf0a64bbbdbc5ce79755c57a205b845c174e2d2e90546a089c4e6ec8adffa23a7ea97bae6b65d782b82db5d2b5a56d22a29a05e7c4433e2b82a621abba90add05ce393fc48a840542451a",
+ "c7cd698d84b65128d8835e3a8b1eb0e01cb541ec",
+ "34047ff96c4dc0dc90b2d4ff59a1a361a4754b255d2ee0af7d8bf87c9bc9e7ddeede33934c63ca1c0e3d262cb145ef932a1f2c0a997aa6a34f8eaee7477d82ccf09095a6b8acad38d4eec9fb7eab7ad02da1d11d8e54c1825e55bf58c2a23234b902be124f9e9038a8f68fa45dab72f66e0945bf1d8bacc9044c6f07098c9fcec58a3aab100c805178155f030a124c450e5acbda47d0e4f10b80a23f803e774d023b0015c20b9f9bbe7c91296338d5ecb471cafb032007b67a60be5f69504a9f01abb3cb467b260e2bce860be8d95bf92c0c8e1496ed1e528593a4abb6df462dde8a0968dffe4683116857a232f5ebf6c85be238745ad0f38f767a5fdbf486fb",
+
+ "f1036e008e71e964dadc9219ed30e17f06b4b68a955c16b312b1eddf028b74976bed6b3f6a63d4e77859243c9cccdc98016523abb02483b35591c33aad81213bb7c7bb1a470aabc10d44256c4d4559d916",
+ "efa8bff96212b2f4a3f371a10d574152655f5dfb",
+ "7e0935ea18f4d6c1d17ce82eb2b3836c55b384589ce19dfe743363ac9948d1f346b7bfddfe92efd78adb21faefc89ade42b10f374003fe122e67429a1cb8cbd1f8d9014564c44d120116f4990f1a6e38774c194bd1b8213286b077b0499d2e7b3f434ab12289c556684deed78131934bb3dd6537236f7c6f3dcb09d476be07721e37e1ceed9b2f7b406887bd53157305e1c8b4f84d733bc1e186fe06cc59b6edb8f4bd7ffefdf4f7ba9cfb9d570689b5a1a4109a746a690893db3799255a0cb9215d2d1cd490590e952e8c8786aa0011265252470c041dfbc3eec7c3cbf71c24869d115c0cb4a956f56d530b80ab589acfefc690751ddf36e8d383f83cedd2cc",
+
+ "25f10895a87716c137450bb9519dfaa1f207faa942ea88abf71e9c17980085b555aebab76264ae2a3ab93c2d12981191ddac6fb5949eb36aee3c5da940f00752c916d94608fa7d97ba6a2915b688f20323d4e9d96801d89a72ab5892dc2117c07434fcf972e058cf8c41ca4b4ff554f7d5068ad3155fced0f3125bc04f9193378a8f5c4c3b8cb4dd6d1cc69d30ecca6eaa51e36a05730e9e342e855baf099defb8afd7",
+ "ad8b1523703646224b660b550885917ca2d1df28",
+ "6d3b5b87f67ea657af21f75441977d2180f91b2c5f692de82955696a686730d9b9778d970758ccb26071c2209ffbd6125be2e96ea81b67cb9b9308239fda17f7b2b64ecda096b6b935640a5a1cb42a9155b1c9ef7a633a02c59f0d6ee59b852c43b35029e73c940ff0410e8f114eed46bbd0fae165e42be2528a401c3b28fd818ef3232dca9f4d2a0f5166ec59c42396d6c11dbc1215a56fa17169db9575343ef34f9de32a49cdc3174922f229c23e18e45df9353119ec4319cedce7a17c64088c1f6f52be29634100b3919d38f3d1ed94e6891e66a73b8fb849f5874df59459e298c7bbce2eee782a195aa66fe2d0732b25e595f57d3e061b1fc3e4063bf98f",
+
+ NULL
+};
+
+static void
+test_RSA_PSS(const char *name,
+ br_rsa_pss_sign sign, br_rsa_pss_vrfy vrfy)
+{
+ size_t u;
+
+ printf("Test %s: ", name);
+ fflush(stdout);
+
+ u = 0;
+ while (KAT_RSA_PSS[u] != NULL) {
+ unsigned char n[512];
+ unsigned char e[8];
+ unsigned char d[512];
+ unsigned char p[256];
+ unsigned char q[256];
+ unsigned char dp[256];
+ unsigned char dq[256];
+ unsigned char iq[256];
+ br_rsa_public_key pk;
+ br_rsa_private_key sk;
+ size_t v;
+
+ pk.n = n;
+ pk.nlen = hextobin(n, KAT_RSA_PSS[u ++]);
+ pk.e = e;
+ pk.elen = hextobin(e, KAT_RSA_PSS[u ++]);
+
+ /*
+ * 'd' is in the test vectors, but we don't use it.
+ */
+ hextobin(d, KAT_RSA_PSS[u ++]);
+
+ for (v = 0; n[v] == 0; v ++);
+ sk.n_bitlen = BIT_LENGTH(n[v]) + ((pk.nlen - 1 - v) << 3);
+ sk.p = p;
+ sk.plen = hextobin(p, KAT_RSA_PSS[u ++]);
+ sk.q = q;
+ sk.qlen = hextobin(q, KAT_RSA_PSS[u ++]);
+ sk.dp = dp;
+ sk.dplen = hextobin(dp, KAT_RSA_PSS[u ++]);
+ sk.dq = dq;
+ sk.dqlen = hextobin(dq, KAT_RSA_PSS[u ++]);
+ sk.iq = iq;
+ sk.iqlen = hextobin(iq, KAT_RSA_PSS[u ++]);
+
+ for (v = 0; v < 6; v ++) {
+ unsigned char plain[512], salt[128], sig[512];
+ size_t plain_len, salt_len, sig_len;
+ rng_fake_ctx rng;
+ unsigned char hash[20], tmp[513];
+ br_sha1_context sc;
+
+ plain_len = hextobin(plain, KAT_RSA_PSS[u ++]);
+ salt_len = hextobin(salt, KAT_RSA_PSS[u ++]);
+ sig_len = hextobin(sig, KAT_RSA_PSS[u ++]);
+
+ br_sha1_init(&sc);
+ br_sha1_update(&sc, plain, plain_len);
+ br_sha1_out(&sc, hash);
+ rng_fake_init(&rng, NULL, salt, salt_len);
+
+ memset(tmp, 0, sizeof tmp);
+ if (sign(&rng.vtable,
+ &br_sha1_vtable, &br_sha1_vtable,
+ hash, salt_len, &sk, tmp) != 1)
+ {
+ fprintf(stderr, "signature failed\n");
+ }
+ if (rng.ptr != rng.len) {
+ fprintf(stderr, "salt not fully consumed\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("KAT RSA/PSS sign", tmp, sig, sig_len);
+
+ if (vrfy(sig, sig_len,
+ &br_sha1_vtable, &br_sha1_vtable,
+ hash, salt_len, &pk) != 1)
+ {
+ fprintf(stderr, "verification failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ sig[sig_len >> 1] ^= 0x01;
+ if (vrfy(sig, sig_len,
+ &br_sha1_vtable, &br_sha1_vtable,
+ hash, salt_len, &pk) != 0)
+ {
+ fprintf(stderr,
+ "verification should have failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ printf(".");
+ fflush(stdout);
+ }
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+/*
+ * Test vectors from pkcs-1v2-1d2-vec.zip (originally from ftp.rsa.com).
+ * There are ten RSA keys, and for each RSA key, there are 6 messages,
+ * each with an explicit seed.
+ *
+ * Field order:
+ * modulus (n)
+ * public exponent (e)
+ * first factor (p)
+ * second factor (q)
+ * first private exponent (dp)
+ * second private exponent (dq)
+ * CRT coefficient (iq)
+ * cleartext 1
+ * seed 1 (20-byte random value)
+ * ciphertext 1
+ * cleartext 2
+ * seed 2 (20-byte random value)
+ * ciphertext 2
+ * ...
+ * cleartext 6
+ * seed 6 (20-byte random value)
+ * ciphertext 6
+ *
+ * This pattern is repeated for all keys. The array stops on a NULL.
+ */
+static const char *KAT_RSA_OAEP[] = {
+ /* 1024-bit key, from oeap-int.txt */
+ "BBF82F090682CE9C2338AC2B9DA871F7368D07EED41043A440D6B6F07454F51FB8DFBAAF035C02AB61EA48CEEB6FCD4876ED520D60E1EC4619719D8A5B8B807FAFB8E0A3DFC737723EE6B4B7D93A2584EE6A649D060953748834B2454598394EE0AAB12D7B61A51F527A9A41F6C1687FE2537298CA2A8F5946F8E5FD091DBDCB",
+ "11",
+ "EECFAE81B1B9B3C908810B10A1B5600199EB9F44AEF4FDA493B81A9E3D84F632124EF0236E5D1E3B7E28FAE7AA040A2D5B252176459D1F397541BA2A58FB6599",
+ "C97FB1F027F453F6341233EAAAD1D9353F6C42D08866B1D05A0F2035028B9D869840B41666B42E92EA0DA3B43204B5CFCE3352524D0416A5A441E700AF461503",
+ "54494CA63EBA0337E4E24023FCD69A5AEB07DDDC0183A4D0AC9B54B051F2B13ED9490975EAB77414FF59C1F7692E9A2E202B38FC910A474174ADC93C1F67C981",
+ "471E0290FF0AF0750351B7F878864CA961ADBD3A8A7E991C5C0556A94C3146A7F9803F8F6F8AE342E931FD8AE47A220D1B99A495849807FE39F9245A9836DA3D",
+ "B06C4FDABB6301198D265BDBAE9423B380F271F73453885093077FCD39E2119FC98632154F5883B167A967BF402B4E9E2E0F9656E698EA3666EDFB25798039F7",
+
+ /* oaep-int.txt contains only one message, so we repeat it six
+ times to respect our array format. */
+ "D436E99569FD32A7C8A05BBC90D32C49",
+ "AAFD12F659CAE63489B479E5076DDEC2F06CB58F",
+ "1253E04DC0A5397BB44A7AB87E9BF2A039A33D1E996FC82A94CCD30074C95DF763722017069E5268DA5D1C0B4F872CF653C11DF82314A67968DFEAE28DEF04BB6D84B1C31D654A1970E5783BD6EB96A024C2CA2F4A90FE9F2EF5C9C140E5BB48DA9536AD8700C84FC9130ADEA74E558D51A74DDF85D8B50DE96838D6063E0955",
+
+ "D436E99569FD32A7C8A05BBC90D32C49",
+ "AAFD12F659CAE63489B479E5076DDEC2F06CB58F",
+ "1253E04DC0A5397BB44A7AB87E9BF2A039A33D1E996FC82A94CCD30074C95DF763722017069E5268DA5D1C0B4F872CF653C11DF82314A67968DFEAE28DEF04BB6D84B1C31D654A1970E5783BD6EB96A024C2CA2F4A90FE9F2EF5C9C140E5BB48DA9536AD8700C84FC9130ADEA74E558D51A74DDF85D8B50DE96838D6063E0955",
+
+ "D436E99569FD32A7C8A05BBC90D32C49",
+ "AAFD12F659CAE63489B479E5076DDEC2F06CB58F",
+ "1253E04DC0A5397BB44A7AB87E9BF2A039A33D1E996FC82A94CCD30074C95DF763722017069E5268DA5D1C0B4F872CF653C11DF82314A67968DFEAE28DEF04BB6D84B1C31D654A1970E5783BD6EB96A024C2CA2F4A90FE9F2EF5C9C140E5BB48DA9536AD8700C84FC9130ADEA74E558D51A74DDF85D8B50DE96838D6063E0955",
+
+ "D436E99569FD32A7C8A05BBC90D32C49",
+ "AAFD12F659CAE63489B479E5076DDEC2F06CB58F",
+ "1253E04DC0A5397BB44A7AB87E9BF2A039A33D1E996FC82A94CCD30074C95DF763722017069E5268DA5D1C0B4F872CF653C11DF82314A67968DFEAE28DEF04BB6D84B1C31D654A1970E5783BD6EB96A024C2CA2F4A90FE9F2EF5C9C140E5BB48DA9536AD8700C84FC9130ADEA74E558D51A74DDF85D8B50DE96838D6063E0955",
+
+ "D436E99569FD32A7C8A05BBC90D32C49",
+ "AAFD12F659CAE63489B479E5076DDEC2F06CB58F",
+ "1253E04DC0A5397BB44A7AB87E9BF2A039A33D1E996FC82A94CCD30074C95DF763722017069E5268DA5D1C0B4F872CF653C11DF82314A67968DFEAE28DEF04BB6D84B1C31D654A1970E5783BD6EB96A024C2CA2F4A90FE9F2EF5C9C140E5BB48DA9536AD8700C84FC9130ADEA74E558D51A74DDF85D8B50DE96838D6063E0955",
+
+ "D436E99569FD32A7C8A05BBC90D32C49",
+ "AAFD12F659CAE63489B479E5076DDEC2F06CB58F",
+ "1253E04DC0A5397BB44A7AB87E9BF2A039A33D1E996FC82A94CCD30074C95DF763722017069E5268DA5D1C0B4F872CF653C11DF82314A67968DFEAE28DEF04BB6D84B1C31D654A1970E5783BD6EB96A024C2CA2F4A90FE9F2EF5C9C140E5BB48DA9536AD8700C84FC9130ADEA74E558D51A74DDF85D8B50DE96838D6063E0955",
+
+ /* 1024-bit key */
+ "A8B3B284AF8EB50B387034A860F146C4919F318763CD6C5598C8AE4811A1E0ABC4C7E0B082D693A5E7FCED675CF4668512772C0CBC64A742C6C630F533C8CC72F62AE833C40BF25842E984BB78BDBF97C0107D55BDB662F5C4E0FAB9845CB5148EF7392DD3AAFF93AE1E6B667BB3D4247616D4F5BA10D4CFD226DE88D39F16FB",
+ "010001",
+ "D32737E7267FFE1341B2D5C0D150A81B586FB3132BED2F8D5262864A9CB9F30AF38BE448598D413A172EFB802C21ACF1C11C520C2F26A471DCAD212EAC7CA39D",
+ "CC8853D1D54DA630FAC004F471F281C7B8982D8224A490EDBEB33D3E3D5CC93C4765703D1DD791642F1F116A0DD852BE2419B2AF72BFE9A030E860B0288B5D77",
+ "0E12BF1718E9CEF5599BA1C3882FE8046A90874EEFCE8F2CCC20E4F2741FB0A33A3848AEC9C9305FBECBD2D76819967D4671ACC6431E4037968DB37878E695C1",
+ "95297B0F95A2FA67D00707D609DFD4FC05C89DAFC2EF6D6EA55BEC771EA333734D9251E79082ECDA866EFEF13C459E1A631386B7E354C899F5F112CA85D71583",
+ "4F456C502493BDC0ED2AB756A3A6ED4D67352A697D4216E93212B127A63D5411CE6FA98D5DBEFD73263E3728142743818166ED7DD63687DD2A8CA1D2F4FBD8E1",
+
+ "6628194E12073DB03BA94CDA9EF9532397D50DBA79B987004AFEFE34",
+ "18B776EA21069D69776A33E96BAD48E1DDA0A5EF",
+ "354FE67B4A126D5D35FE36C777791A3F7BA13DEF484E2D3908AFF722FAD468FB21696DE95D0BE911C2D3174F8AFCC201035F7B6D8E69402DE5451618C21A535FA9D7BFC5B8DD9FC243F8CF927DB31322D6E881EAA91A996170E657A05A266426D98C88003F8477C1227094A0D9FA1E8C4024309CE1ECCCB5210035D47AC72E8A",
+
+ "750C4047F547E8E41411856523298AC9BAE245EFAF1397FBE56F9DD5",
+ "0CC742CE4A9B7F32F951BCB251EFD925FE4FE35F",
+ "640DB1ACC58E0568FE5407E5F9B701DFF8C3C91E716C536FC7FCEC6CB5B71C1165988D4A279E1577D730FC7A29932E3F00C81515236D8D8E31017A7A09DF4352D904CDEB79AA583ADCC31EA698A4C05283DABA9089BE5491F67C1A4EE48DC74BBBE6643AEF846679B4CB395A352D5ED115912DF696FFE0702932946D71492B44",
+
+ "D94AE0832E6445CE42331CB06D531A82B1DB4BAAD30F746DC916DF24D4E3C2451FFF59A6423EB0E1D02D4FE646CF699DFD818C6E97B051",
+ "2514DF4695755A67B288EAF4905C36EEC66FD2FD",
+ "423736ED035F6026AF276C35C0B3741B365E5F76CA091B4E8C29E2F0BEFEE603595AA8322D602D2E625E95EB81B2F1C9724E822ECA76DB8618CF09C5343503A4360835B5903BC637E3879FB05E0EF32685D5AEC5067CD7CC96FE4B2670B6EAC3066B1FCF5686B68589AAFB7D629B02D8F8625CA3833624D4800FB081B1CF94EB",
+
+ "52E650D98E7F2A048B4F86852153B97E01DD316F346A19F67A85",
+ "C4435A3E1A18A68B6820436290A37CEFB85DB3FB",
+ "45EAD4CA551E662C9800F1ACA8283B0525E6ABAE30BE4B4ABA762FA40FD3D38E22ABEFC69794F6EBBBC05DDBB11216247D2F412FD0FBA87C6E3ACD888813646FD0E48E785204F9C3F73D6D8239562722DDDD8771FEC48B83A31EE6F592C4CFD4BC88174F3B13A112AAE3B9F7B80E0FC6F7255BA880DC7D8021E22AD6A85F0755",
+
+ "8DA89FD9E5F974A29FEFFB462B49180F6CF9E802",
+ "B318C42DF3BE0F83FEA823F5A7B47ED5E425A3B5",
+ "36F6E34D94A8D34DAACBA33A2139D00AD85A9345A86051E73071620056B920E219005855A213A0F23897CDCD731B45257C777FE908202BEFDD0B58386B1244EA0CF539A05D5D10329DA44E13030FD760DCD644CFEF2094D1910D3F433E1C7C6DD18BC1F2DF7F643D662FB9DD37EAD9059190F4FA66CA39E869C4EB449CBDC439",
+
+ "26521050844271",
+ "E4EC0982C2336F3A677F6A356174EB0CE887ABC2",
+ "42CEE2617B1ECEA4DB3F4829386FBD61DAFBF038E180D837C96366DF24C097B4AB0FAC6BDF590D821C9F10642E681AD05B8D78B378C0F46CE2FAD63F74E0AD3DF06B075D7EB5F5636F8D403B9059CA761B5C62BB52AA45002EA70BAACE08DED243B9D8CBD62A68ADE265832B56564E43A6FA42ED199A099769742DF1539E8255",
+
+ /* 1025-bit key */
+ "01947C7FCE90425F47279E70851F25D5E62316FE8A1DF19371E3E628E260543E4901EF6081F68C0B8141190D2AE8DABA7D1250EC6DB636E944EC3722877C7C1D0A67F14B1694C5F0379451A43E49A32DDE83670B73DA91A1C99BC23B436A60055C610F0BAF99C1A079565B95A3F1526632D1D4DA60F20EDA25E653C4F002766F45",
+ "010001",
+ "0159DBDE04A33EF06FB608B80B190F4D3E22BCC13AC8E4A081033ABFA416EDB0B338AA08B57309EA5A5240E7DC6E54378C69414C31D97DDB1F406DB3769CC41A43",
+ "012B652F30403B38B40995FD6FF41A1ACC8ADA70373236B7202D39B2EE30CFB46DB09511F6F307CC61CC21606C18A75B8A62F822DF031BA0DF0DAFD5506F568BD7",
+ "436EF508DE736519C2DA4C580D98C82CB7452A3FB5EFADC3B9C7789A1BC6584F795ADDBBD32439C74686552ECB6C2C307A4D3AF7F539EEC157248C7B31F1A255",
+ "012B15A89F3DFB2B39073E73F02BDD0C1A7B379DD435F05CDDE2EFF9E462948B7CEC62EE9050D5E0816E0785A856B49108DCB75F3683874D1CA6329A19013066FF",
+ "0270DB17D5914B018D76118B24389A7350EC836B0063A21721236FD8EDB6D89B51E7EEB87B611B7132CB7EA7356C23151C1E7751507C786D9EE1794170A8C8E8",
+
+ "8FF00CAA605C702830634D9A6C3D42C652B58CF1D92FEC570BEEE7",
+ "8C407B5EC2899E5099C53E8CE793BF94E71B1782",
+ "0181AF8922B9FCB4D79D92EBE19815992FC0C1439D8BCD491398A0F4AD3A329A5BD9385560DB532683C8B7DA04E4B12AED6AACDF471C34C9CDA891ADDCC2DF3456653AA6382E9AE59B54455257EB099D562BBE10453F2B6D13C59C02E10F1F8ABB5DA0D0570932DACF2D0901DB729D0FEFCC054E70968EA540C81B04BCAEFE720E",
+
+ "2D",
+ "B600CF3C2E506D7F16778C910D3A8B003EEE61D5",
+ "018759FF1DF63B2792410562314416A8AEAF2AC634B46F940AB82D64DBF165EEE33011DA749D4BAB6E2FCD18129C9E49277D8453112B429A222A8471B070993998E758861C4D3F6D749D91C4290D332C7A4AB3F7EA35FF3A07D497C955FF0FFC95006B62C6D296810D9BFAB024196C7934012C2DF978EF299ABA239940CBA10245",
+
+ "74FC88C51BC90F77AF9D5E9A4A70133D4B4E0B34DA3C37C7EF8E",
+ "A73768AEEAA91F9D8C1ED6F9D2B63467F07CCAE3",
+ "018802BAB04C60325E81C4962311F2BE7C2ADCE93041A00719C88F957575F2C79F1B7BC8CED115C706B311C08A2D986CA3B6A9336B147C29C6F229409DDEC651BD1FDD5A0B7F610C9937FDB4A3A762364B8B3206B4EA485FD098D08F63D4AA8BB2697D027B750C32D7F74EAF5180D2E9B66B17CB2FA55523BC280DA10D14BE2053",
+
+ "A7EB2A5036931D27D4E891326D99692FFADDA9BF7EFD3E34E622C4ADC085F721DFE885072C78A203B151739BE540FA8C153A10F00A",
+ "9A7B3B0E708BD96F8190ECAB4FB9B2B3805A8156",
+ "00A4578CBC176318A638FBA7D01DF15746AF44D4F6CD96D7E7C495CBF425B09C649D32BF886DA48FBAF989A2117187CAFB1FB580317690E3CCD446920B7AF82B31DB5804D87D01514ACBFA9156E782F867F6BED9449E0E9A2C09BCECC6AA087636965E34B3EC766F2FE2E43018A2FDDEB140616A0E9D82E5331024EE0652FC7641",
+
+ "2EF2B066F854C33F3BDCBB5994A435E73D6C6C",
+ "EB3CEBBC4ADC16BB48E88C8AEC0E34AF7F427FD3",
+ "00EBC5F5FDA77CFDAD3C83641A9025E77D72D8A6FB33A810F5950F8D74C73E8D931E8634D86AB1246256AE07B6005B71B7F2FB98351218331CE69B8FFBDC9DA08BBC9C704F876DEB9DF9FC2EC065CAD87F9090B07ACC17AA7F997B27ACA48806E897F771D95141FE4526D8A5301B678627EFAB707FD40FBEBD6E792A25613E7AEC",
+
+ "8A7FB344C8B6CB2CF2EF1F643F9A3218F6E19BBA89C0",
+ "4C45CF4D57C98E3D6D2095ADC51C489EB50DFF84",
+ "010839EC20C27B9052E55BEFB9B77E6FC26E9075D7A54378C646ABDF51E445BD5715DE81789F56F1803D9170764A9E93CB78798694023EE7393CE04BC5D8F8C5A52C171D43837E3ACA62F609EB0AA5FFB0960EF04198DD754F57F7FBE6ABF765CF118B4CA443B23B5AAB266F952326AC4581100644325F8B721ACD5D04FF14EF3A",
+
+ /* 2048-bit key */
+ "AE45ED5601CEC6B8CC05F803935C674DDBE0D75C4C09FD7951FC6B0CAEC313A8DF39970C518BFFBA5ED68F3F0D7F22A4029D413F1AE07E4EBE9E4177CE23E7F5404B569E4EE1BDCF3C1FB03EF113802D4F855EB9B5134B5A7C8085ADCAE6FA2FA1417EC3763BE171B0C62B760EDE23C12AD92B980884C641F5A8FAC26BDAD4A03381A22FE1B754885094C82506D4019A535A286AFEB271BB9BA592DE18DCF600C2AEEAE56E02F7CF79FC14CF3BDC7CD84FEBBBF950CA90304B2219A7AA063AEFA2C3C1980E560CD64AFE779585B6107657B957857EFDE6010988AB7DE417FC88D8F384C4E6E72C3F943E0C31C0C4A5CC36F879D8A3AC9D7D59860EAADA6B83BB",
+ "010001",
+ "ECF5AECD1E5515FFFACBD75A2816C6EBF49018CDFB4638E185D66A7396B6F8090F8018C7FD95CC34B857DC17F0CC6516BB1346AB4D582CADAD7B4103352387B70338D084047C9D9539B6496204B3DD6EA442499207BEC01F964287FF6336C3984658336846F56E46861881C10233D2176BF15A5E96DDC780BC868AA77D3CE769",
+ "BC46C464FC6AC4CA783B0EB08A3C841B772F7E9B2F28BABD588AE885E1A0C61E4858A0FB25AC299990F35BE85164C259BA1175CDD7192707135184992B6C29B746DD0D2CABE142835F7D148CC161524B4A09946D48B828473F1CE76B6CB6886C345C03E05F41D51B5C3A90A3F24073C7D74A4FE25D9CF21C75960F3FC3863183",
+ "C73564571D00FB15D08A3DE9957A50915D7126E9442DACF42BC82E862E5673FF6A008ED4D2E374617DF89F17A160B43B7FDA9CB6B6B74218609815F7D45CA263C159AA32D272D127FAF4BC8CA2D77378E8AEB19B0AD7DA3CB3DE0AE7314980F62B6D4B0A875D1DF03C1BAE39CCD833EF6CD7E2D9528BF084D1F969E794E9F6C1",
+ "2658B37F6DF9C1030BE1DB68117FA9D87E39EA2B693B7E6D3A2F70947413EEC6142E18FB8DFCB6AC545D7C86A0AD48F8457170F0EFB26BC48126C53EFD1D16920198DC2A1107DC282DB6A80CD3062360BA3FA13F70E4312FF1A6CD6B8FC4CD9C5C3DB17C6D6A57212F73AE29F619327BAD59B153858585BA4E28B60A62A45E49",
+ "6F38526B3925085534EF3E415A836EDE8B86158A2C7CBFECCB0BD834304FEC683BA8D4F479C433D43416E63269623CEA100776D85AFF401D3FFF610EE65411CE3B1363D63A9709EEDE42647CEA561493D54570A879C18682CD97710B96205EC31117D73B5F36223FADD6E8BA90DD7C0EE61D44E163251E20C7F66EB305117CB8",
+
+ "8BBA6BF82A6C0F86D5F1756E97956870B08953B06B4EB205BC1694EE",
+ "47E1AB7119FEE56C95EE5EAAD86F40D0AA63BD33",
+ "53EA5DC08CD260FB3B858567287FA91552C30B2FEBFBA213F0AE87702D068D19BAB07FE574523DFB42139D68C3C5AFEEE0BFE4CB7969CBF382B804D6E61396144E2D0E60741F8993C3014B58B9B1957A8BABCD23AF854F4C356FB1662AA72BFCC7E586559DC4280D160C126785A723EBEEBEFF71F11594440AAEF87D10793A8774A239D4A04C87FE1467B9DAF85208EC6C7255794A96CC29142F9A8BD418E3C1FD67344B0CD0829DF3B2BEC60253196293C6B34D3F75D32F213DD45C6273D505ADF4CCED1057CB758FC26AEEFA441255ED4E64C199EE075E7F16646182FDB464739B68AB5DAFF0E63E9552016824F054BF4D3C8C90A97BB6B6553284EB429FCC",
+
+ "E6AD181F053B58A904F2457510373E57",
+ "6D17F5B4C1FFAC351D195BF7B09D09F09A4079CF",
+ "A2B1A430A9D657E2FA1C2BB5ED43FFB25C05A308FE9093C01031795F5874400110828AE58FB9B581CE9DDDD3E549AE04A0985459BDE6C626594E7B05DC4278B2A1465C1368408823C85E96DC66C3A30983C639664FC4569A37FE21E5A195B5776EED2DF8D8D361AF686E750229BBD663F161868A50615E0C337BEC0CA35FEC0BB19C36EB2E0BBCC0582FA1D93AACDB061063F59F2CE1EE43605E5D89ECA183D2ACDFE9F81011022AD3B43A3DD417DAC94B4E11EA81B192966E966B182082E71964607B4F8002F36299844A11F2AE0FAEAC2EAE70F8F4F98088ACDCD0AC556E9FCCC511521908FAD26F04C64201450305778758B0538BF8B5BB144A828E629795",
+
+ "510A2CF60E866FA2340553C94EA39FBC256311E83E94454B4124",
+ "385387514DECCC7C740DD8CDF9DAEE49A1CBFD54",
+ "9886C3E6764A8B9A84E84148EBD8C3B1AA8050381A78F668714C16D9CFD2A6EDC56979C535D9DEE3B44B85C18BE8928992371711472216D95DDA98D2EE8347C9B14DFFDFF84AA48D25AC06F7D7E65398AC967B1CE90925F67DCE049B7F812DB0742997A74D44FE81DBE0E7A3FEAF2E5C40AF888D550DDBBE3BC20657A29543F8FC2913B9BD1A61B2AB2256EC409BBD7DC0D17717EA25C43F42ED27DF8738BF4AFC6766FF7AFF0859555EE283920F4C8A63C4A7340CBAFDDC339ECDB4B0515002F96C932B5B79167AF699C0AD3FCCFDF0F44E85A70262BF2E18FE34B850589975E867FF969D48EABF212271546CDC05A69ECB526E52870C836F307BD798780EDE",
+
+ "BCDD190DA3B7D300DF9A06E22CAAE2A75F10C91FF667B7C16BDE8B53064A2649A94045C9",
+ "5CACA6A0F764161A9684F85D92B6E0EF37CA8B65",
+ "6318E9FB5C0D05E5307E1683436E903293AC4642358AAA223D7163013ABA87E2DFDA8E60C6860E29A1E92686163EA0B9175F329CA3B131A1EDD3A77759A8B97BAD6A4F8F4396F28CF6F39CA58112E48160D6E203DAA5856F3ACA5FFED577AF499408E3DFD233E3E604DBE34A9C4C9082DE65527CAC6331D29DC80E0508A0FA7122E7F329F6CCA5CFA34D4D1DA417805457E008BEC549E478FF9E12A763C477D15BBB78F5B69BD57830FC2C4ED686D79BC72A95D85F88134C6B0AFE56A8CCFBC855828BB339BD17909CF1D70DE3335AE07039093E606D655365DE6550B872CD6DE1D440EE031B61945F629AD8A353B0D40939E96A3C450D2A8D5EEE9F678093C8",
+
+ "A7DD6C7DC24B46F9DD5F1E91ADA4C3B3DF947E877232A9",
+ "95BCA9E3859894B3DD869FA7ECD5BBC6401BF3E4",
+ "75290872CCFD4A4505660D651F56DA6DAA09CA1301D890632F6A992F3D565CEE464AFDED40ED3B5BE9356714EA5AA7655F4A1366C2F17C728F6F2C5A5D1F8E28429BC4E6F8F2CFF8DA8DC0E0A9808E45FD09EA2FA40CB2B6CE6FFFF5C0E159D11B68D90A85F7B84E103B09E682666480C657505C0929259468A314786D74EAB131573CF234BF57DB7D9E66CC6748192E002DC0DEEA930585F0831FDCD9BC33D51F79ED2FFC16BCF4D59812FCEBCAA3F9069B0E445686D644C25CCF63B456EE5FA6FFE96F19CDF751FED9EAF35957754DBF4BFEA5216AA1844DC507CB2D080E722EBA150308C2B5FF1193620F1766ECF4481BAFB943BD292877F2136CA494ABA0",
+
+ "EAF1A73A1B0C4609537DE69CD9228BBCFB9A8CA8C6C3EFAF056FE4A7F4634ED00B7C39EC6922D7B8EA2C04EBAC",
+ "9F47DDF42E97EEA856A9BDBC714EB3AC22F6EB32",
+ "2D207A73432A8FB4C03051B3F73B28A61764098DFA34C47A20995F8115AA6816679B557E82DBEE584908C6E69782D7DEB34DBD65AF063D57FCA76A5FD069492FD6068D9984D209350565A62E5C77F23038C12CB10C6634709B547C46F6B4A709BD85CA122D74465EF97762C29763E06DBC7A9E738C78BFCA0102DC5E79D65B973F28240CAAB2E161A78B57D262457ED8195D53E3C7AE9DA021883C6DB7C24AFDD2322EAC972AD3C354C5FCEF1E146C3A0290FB67ADF007066E00428D2CEC18CE58F9328698DEFEF4B2EB5EC76918FDE1C198CBB38B7AFC67626A9AEFEC4322BFD90D2563481C9A221F78C8272C82D1B62AB914E1C69F6AF6EF30CA5260DB4A46",
+
+ NULL
+};
+
+static void
+test_RSA_OAEP(const char *name,
+ br_rsa_oaep_encrypt menc, br_rsa_oaep_decrypt mdec)
+{
+ size_t u;
+
+ printf("Test %s: ", name);
+ fflush(stdout);
+
+ u = 0;
+ while (KAT_RSA_OAEP[u] != NULL) {
+ unsigned char n[512];
+ unsigned char e[8];
+ unsigned char p[256];
+ unsigned char q[256];
+ unsigned char dp[256];
+ unsigned char dq[256];
+ unsigned char iq[256];
+ br_rsa_public_key pk;
+ br_rsa_private_key sk;
+ size_t v;
+
+ pk.n = n;
+ pk.nlen = hextobin(n, KAT_RSA_OAEP[u ++]);
+ pk.e = e;
+ pk.elen = hextobin(e, KAT_RSA_OAEP[u ++]);
+
+ for (v = 0; n[v] == 0; v ++);
+ sk.n_bitlen = BIT_LENGTH(n[v]) + ((pk.nlen - 1 - v) << 3);
+ sk.p = p;
+ sk.plen = hextobin(p, KAT_RSA_OAEP[u ++]);
+ sk.q = q;
+ sk.qlen = hextobin(q, KAT_RSA_OAEP[u ++]);
+ sk.dp = dp;
+ sk.dplen = hextobin(dp, KAT_RSA_OAEP[u ++]);
+ sk.dq = dq;
+ sk.dqlen = hextobin(dq, KAT_RSA_OAEP[u ++]);
+ sk.iq = iq;
+ sk.iqlen = hextobin(iq, KAT_RSA_OAEP[u ++]);
+
+ for (v = 0; v < 6; v ++) {
+ unsigned char plain[512], seed[128], cipher[512];
+ size_t plain_len, seed_len, cipher_len;
+ rng_fake_ctx rng;
+ unsigned char tmp[513];
+ size_t len;
+
+ plain_len = hextobin(plain, KAT_RSA_OAEP[u ++]);
+ seed_len = hextobin(seed, KAT_RSA_OAEP[u ++]);
+ cipher_len = hextobin(cipher, KAT_RSA_OAEP[u ++]);
+ rng_fake_init(&rng, NULL, seed, seed_len);
+
+ len = menc(&rng.vtable, &br_sha1_vtable, NULL, 0, &pk,
+ tmp, sizeof tmp, plain, plain_len);
+ if (len != cipher_len) {
+ fprintf(stderr,
+ "wrong encrypted length: %lu vs %lu\n",
+ (unsigned long)len,
+ (unsigned long)cipher_len);
+ }
+ if (rng.ptr != rng.len) {
+ fprintf(stderr, "seed not fully consumed\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("KAT RSA/OAEP encrypt", tmp, cipher, len);
+
+ if (mdec(&br_sha1_vtable, NULL, 0,
+ &sk, tmp, &len) != 1)
+ {
+ fprintf(stderr, "decryption failed\n");
+ exit(EXIT_FAILURE);
+ }
+ if (len != plain_len) {
+ fprintf(stderr,
+ "wrong decrypted length: %lu vs %lu\n",
+ (unsigned long)len,
+ (unsigned long)plain_len);
+ }
+ check_equals("KAT RSA/OAEP decrypt", tmp, plain, len);
+
+ /*
+ * Try with a different label; it should fail.
+ */
+ memcpy(tmp, cipher, cipher_len);
+ len = cipher_len;
+ if (mdec(&br_sha1_vtable, "T", 1,
+ &sk, tmp, &len) != 0)
+ {
+ fprintf(stderr, "decryption should have failed"
+ " (wrong label)\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Try with a the wrong length; it should fail.
+ */
+ tmp[0] = 0x00;
+ memcpy(tmp + 1, cipher, cipher_len);
+ len = cipher_len + 1;
+ if (mdec(&br_sha1_vtable, "T", 1,
+ &sk, tmp, &len) != 0)
+ {
+ fprintf(stderr, "decryption should have failed"
+ " (wrong length)\n");
+ exit(EXIT_FAILURE);
+ }
+
+ printf(".");
+ fflush(stdout);
+ }
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+static void
+test_RSA_keygen(const char *name, br_rsa_keygen kg, br_rsa_compute_modulus cm,
+ br_rsa_compute_pubexp ce, br_rsa_compute_privexp cd,
+ br_rsa_public pub, br_rsa_pkcs1_sign sign, br_rsa_pkcs1_vrfy vrfy)
+{
+ br_hmac_drbg_context rng;
+ int i;
+
+ printf("Test %s: ", name);
+ fflush(stdout);
+
+ br_hmac_drbg_init(&rng, &br_sha256_vtable, "seed for RSA keygen", 19);
+
+ for (i = 0; i <= 42; i ++) {
+ unsigned size;
+ uint32_t pubexp, z;
+ br_rsa_private_key sk;
+ br_rsa_public_key pk, pk2;
+ unsigned char kbuf_priv[BR_RSA_KBUF_PRIV_SIZE(2048)];
+ unsigned char kbuf_pub[BR_RSA_KBUF_PUB_SIZE(2048)];
+ unsigned char n2[256], d[256], msg1[256], msg2[256];
+ uint32_t mod[256];
+ uint32_t cc;
+ size_t u, v;
+ unsigned char sig[257], hv[32], hv2[sizeof hv];
+ unsigned mask1, mask2;
+ int j;
+
+ if (i <= 35) {
+ size = 1024 + i;
+ pubexp = 17;
+ } else if (i <= 40) {
+ size = 2048;
+ pubexp = (i << 1) - 69;
+ } else {
+ size = 2048;
+ pubexp = 0xFFFFFFFF;
+ }
+
+ if (!kg(&rng.vtable,
+ &sk, kbuf_priv, &pk, kbuf_pub, size, pubexp))
+ {
+ fprintf(stderr, "RSA key pair generation failure\n");
+ exit(EXIT_FAILURE);
+ }
+
+ z = pubexp;
+ for (u = pk.elen; u > 0; u --) {
+ if (pk.e[u - 1] != (z & 0xFF)) {
+ fprintf(stderr, "wrong public exponent\n");
+ exit(EXIT_FAILURE);
+ }
+ z >>= 8;
+ }
+ if (z != 0) {
+ fprintf(stderr, "truncated public exponent\n");
+ exit(EXIT_FAILURE);
+ }
+
+ memset(mod, 0, sizeof mod);
+ for (u = 0; u < sk.plen; u ++) {
+ for (v = 0; v < sk.qlen; v ++) {
+ mod[u + v] += (uint32_t)sk.p[sk.plen - 1 - u]
+ * (uint32_t)sk.q[sk.qlen - 1 - v];
+ }
+ }
+ cc = 0;
+ for (u = 0; u < sk.plen + sk.qlen; u ++) {
+ mod[u] += cc;
+ cc = mod[u] >> 8;
+ mod[u] &= 0xFF;
+ }
+ for (u = 0; u < pk.nlen; u ++) {
+ if (mod[pk.nlen - 1 - u] != pk.n[u]) {
+ fprintf(stderr, "wrong modulus\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+ if (sk.n_bitlen != size) {
+ fprintf(stderr, "wrong key size\n");
+ exit(EXIT_FAILURE);
+ }
+ if (pk.nlen != (size + 7) >> 3) {
+ fprintf(stderr, "wrong modulus size (bytes)\n");
+ exit(EXIT_FAILURE);
+ }
+ mask1 = 0x01 << ((size + 7) & 7);
+ mask2 = 0xFF & -mask1;
+ if ((pk.n[0] & mask2) != mask1) {
+ fprintf(stderr, "wrong modulus size (bits)\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (cm(NULL, &sk) != pk.nlen) {
+ fprintf(stderr, "wrong recomputed modulus length\n");
+ exit(EXIT_FAILURE);
+ }
+ if (cm(n2, &sk) != pk.nlen || memcmp(pk.n, n2, pk.nlen) != 0) {
+ fprintf(stderr, "wrong recomputed modulus value\n");
+ exit(EXIT_FAILURE);
+ }
+
+ z = ce(&sk);
+ if (z != pubexp) {
+ fprintf(stderr,
+ "wrong recomputed pubexp: %lu (exp: %lu)\n",
+ (unsigned long)z, (unsigned long)pubexp);
+ exit(EXIT_FAILURE);
+ }
+
+ if (cd(NULL, &sk, pubexp) != pk.nlen) {
+ fprintf(stderr,
+ "wrong recomputed privexp length (1)\n");
+ exit(EXIT_FAILURE);
+ }
+ if (cd(d, &sk, pubexp) != pk.nlen) {
+ fprintf(stderr,
+ "wrong recomputed privexp length (2)\n");
+ exit(EXIT_FAILURE);
+ }
+ /*
+ * To check that the private exponent is correct, we make
+ * it into a _public_ key, and use the public-key operation
+ * to perform the modular exponentiation.
+ */
+ pk2 = pk;
+ pk2.e = d;
+ pk2.elen = pk.nlen;
+ rng.vtable->generate(&rng.vtable, msg1, pk.nlen);
+ msg1[0] = 0x00;
+ memcpy(msg2, msg1, pk.nlen);
+ if (!pub(msg2, pk.nlen, &pk2) || !pub(msg2, pk.nlen, &pk)) {
+ fprintf(stderr, "public-key operation error\n");
+ exit(EXIT_FAILURE);
+ }
+ if (memcmp(msg1, msg2, pk.nlen) != 0) {
+ fprintf(stderr, "wrong recomputed privexp\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * We test the RSA operation over a some random messages.
+ */
+ for (j = 0; j < 20; j ++) {
+ rng.vtable->generate(&rng.vtable, hv, sizeof hv);
+ memset(sig, 0, sizeof sig);
+ sig[pk.nlen] = 0x00;
+ if (!sign(BR_HASH_OID_SHA256,
+ hv, sizeof hv, &sk, sig))
+ {
+ fprintf(stderr,
+ "signature error (%d)\n", j);
+ exit(EXIT_FAILURE);
+ }
+ if (sig[pk.nlen] != 0x00) {
+ fprintf(stderr,
+ "signature length error (%d)\n", j);
+ exit(EXIT_FAILURE);
+ }
+ if (!vrfy(sig, pk.nlen, BR_HASH_OID_SHA256, sizeof hv,
+ &pk, hv2))
+ {
+ fprintf(stderr,
+ "signature verif error (%d)\n", j);
+ exit(EXIT_FAILURE);
+ }
+ if (memcmp(hv, hv2, sizeof hv) != 0) {
+ fprintf(stderr,
+ "signature extract error (%d)\n", j);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ printf(".");
+ fflush(stdout);
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+static void
+test_RSA_i15(void)
+{
+ test_RSA_core("RSA i15 core", &br_rsa_i15_public, &br_rsa_i15_private);
+ test_RSA_sign("RSA i15 sign", &br_rsa_i15_private,
+ &br_rsa_i15_pkcs1_sign, &br_rsa_i15_pkcs1_vrfy);
+ test_RSA_OAEP("RSA i15 OAEP",
+ &br_rsa_i15_oaep_encrypt, &br_rsa_i15_oaep_decrypt);
+ test_RSA_PSS("RSA i15 PSS",
+ &br_rsa_i15_pss_sign, &br_rsa_i15_pss_vrfy);
+ test_RSA_keygen("RSA i15 keygen", &br_rsa_i15_keygen,
+ &br_rsa_i15_compute_modulus, &br_rsa_i15_compute_pubexp,
+ &br_rsa_i15_compute_privexp, &br_rsa_i15_public,
+ &br_rsa_i15_pkcs1_sign, &br_rsa_i15_pkcs1_vrfy);
+}
+
+static void
+test_RSA_i31(void)
+{
+ test_RSA_core("RSA i31 core", &br_rsa_i31_public, &br_rsa_i31_private);
+ test_RSA_sign("RSA i31 sign", &br_rsa_i31_private,
+ &br_rsa_i31_pkcs1_sign, &br_rsa_i31_pkcs1_vrfy);
+ test_RSA_OAEP("RSA i31 OAEP",
+ &br_rsa_i31_oaep_encrypt, &br_rsa_i31_oaep_decrypt);
+ test_RSA_PSS("RSA i31 PSS",
+ &br_rsa_i31_pss_sign, &br_rsa_i31_pss_vrfy);
+ test_RSA_keygen("RSA i31 keygen", &br_rsa_i31_keygen,
+ &br_rsa_i31_compute_modulus, &br_rsa_i31_compute_pubexp,
+ &br_rsa_i31_compute_privexp, &br_rsa_i31_public,
+ &br_rsa_i31_pkcs1_sign, &br_rsa_i31_pkcs1_vrfy);
+}
+
+static void
+test_RSA_i32(void)
+{
+ test_RSA_core("RSA i32 core", &br_rsa_i32_public, &br_rsa_i32_private);
+ test_RSA_sign("RSA i32 sign", &br_rsa_i32_private,
+ &br_rsa_i32_pkcs1_sign, &br_rsa_i32_pkcs1_vrfy);
+ test_RSA_OAEP("RSA i32 OAEP",
+ &br_rsa_i32_oaep_encrypt, &br_rsa_i32_oaep_decrypt);
+ test_RSA_PSS("RSA i32 PSS",
+ &br_rsa_i32_pss_sign, &br_rsa_i32_pss_vrfy);
+}
+
+static void
+test_RSA_i62(void)
+{
+ br_rsa_public pub;
+ br_rsa_private priv;
+ br_rsa_pkcs1_sign sign;
+ br_rsa_pkcs1_vrfy vrfy;
+ br_rsa_pss_sign pss_sign;
+ br_rsa_pss_vrfy pss_vrfy;
+ br_rsa_oaep_encrypt menc;
+ br_rsa_oaep_decrypt mdec;
+ br_rsa_keygen kgen;
+
+ pub = br_rsa_i62_public_get();
+ priv = br_rsa_i62_private_get();
+ sign = br_rsa_i62_pkcs1_sign_get();
+ vrfy = br_rsa_i62_pkcs1_vrfy_get();
+ pss_sign = br_rsa_i62_pss_sign_get();
+ pss_vrfy = br_rsa_i62_pss_vrfy_get();
+ menc = br_rsa_i62_oaep_encrypt_get();
+ mdec = br_rsa_i62_oaep_decrypt_get();
+ kgen = br_rsa_i62_keygen_get();
+ if (pub) {
+ if (!priv || !sign || !vrfy || !pss_sign || !pss_vrfy
+ || !menc || !mdec || !kgen)
+ {
+ fprintf(stderr, "Inconsistent i62 availability\n");
+ exit(EXIT_FAILURE);
+ }
+ test_RSA_core("RSA i62 core", pub, priv);
+ test_RSA_sign("RSA i62 sign", priv, sign, vrfy);
+ test_RSA_OAEP("RSA i62 OAEP", menc, mdec);
+ test_RSA_PSS("RSA i62 PSS", pss_sign, pss_vrfy);
+ test_RSA_keygen("RSA i62 keygen", kgen,
+ &br_rsa_i31_compute_modulus, &br_rsa_i31_compute_pubexp,
+ &br_rsa_i31_compute_privexp, pub,
+ sign, vrfy);
+ } else {
+ if (priv || sign || vrfy || pss_sign || pss_vrfy
+ || menc || mdec || kgen)
+ {
+ fprintf(stderr, "Inconsistent i62 availability\n");
+ exit(EXIT_FAILURE);
+ }
+ printf("Test RSA i62: UNAVAILABLE\n");
+ }
+}
+
+#if 0
+static void
+test_RSA_signatures(void)
+{
+ uint32_t n[40], e[2], p[20], q[20], dp[20], dq[20], iq[20], x[40];
+ unsigned char hv[20], sig[128];
+ unsigned char ref[128], tmp[128];
+ br_sha1_context hc;
+
+ printf("Test RSA signatures: ");
+ fflush(stdout);
+
+ /*
+ * Decode RSA key elements.
+ */
+ br_int_decode(n, sizeof n / sizeof n[0], RSA_N, sizeof RSA_N);
+ br_int_decode(e, sizeof e / sizeof e[0], RSA_E, sizeof RSA_E);
+ br_int_decode(p, sizeof p / sizeof p[0], RSA_P, sizeof RSA_P);
+ br_int_decode(q, sizeof q / sizeof q[0], RSA_Q, sizeof RSA_Q);
+ br_int_decode(dp, sizeof dp / sizeof dp[0], RSA_DP, sizeof RSA_DP);
+ br_int_decode(dq, sizeof dq / sizeof dq[0], RSA_DQ, sizeof RSA_DQ);
+ br_int_decode(iq, sizeof iq / sizeof iq[0], RSA_IQ, sizeof RSA_IQ);
+
+ /*
+ * Decode reference signature (computed with OpenSSL).
+ */
+ hextobin(ref, "45A3DC6A106BCD3BD0E48FB579643AA3FF801E5903E80AA9B43A695A8E7F454E93FA208B69995FF7A6D5617C2FEB8E546375A664977A48931842AAE796B5A0D64393DCA35F3490FC157F5BD83B9D58C2F7926E6AE648A2BD96CAB8FCCD3D35BB11424AD47D973FF6D69CA774841AEC45DFAE99CCF79893E7047FDE6CB00AA76D");
+
+ /*
+ * Recompute signature. Since PKCS#1 v1.5 signatures are
+ * deterministic, we should get the same as the reference signature.
+ */
+ br_sha1_init(&hc);
+ br_sha1_update(&hc, "test", 4);
+ br_sha1_out(&hc, hv);
+ if (!br_rsa_sign(sig, sizeof sig, p, q, dp, dq, iq, br_sha1_ID, hv)) {
+ fprintf(stderr, "RSA-1024/SHA-1 sig generate failed\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("KAT RSA-sign 1", sig, ref, sizeof sig);
+
+ /*
+ * Verify signature.
+ */
+ if (!br_rsa_verify(sig, sizeof sig, n, e, br_sha1_ID, hv)) {
+ fprintf(stderr, "RSA-1024/SHA-1 sig verify failed\n");
+ exit(EXIT_FAILURE);
+ }
+ hv[5] ^= 0x01;
+ if (br_rsa_verify(sig, sizeof sig, n, e, br_sha1_ID, hv)) {
+ fprintf(stderr, "RSA-1024/SHA-1 sig verify should have failed\n");
+ exit(EXIT_FAILURE);
+ }
+ hv[5] ^= 0x01;
+
+ /*
+ * Generate a signature with the alternate encoding (no NULL) and
+ * verify it.
+ */
+ hextobin(tmp, "0001FFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFFF00301F300706052B0E03021A0414A94A8FE5CCB19BA61C4C0873D391E987982FBBD3");
+ br_int_decode(x, sizeof x / sizeof x[0], tmp, sizeof tmp);
+ x[0] = n[0];
+ br_rsa_private_core(x, p, q, dp, dq, iq);
+ br_int_encode(sig, sizeof sig, x);
+ if (!br_rsa_verify(sig, sizeof sig, n, e, br_sha1_ID, hv)) {
+ fprintf(stderr, "RSA-1024/SHA-1 sig verify (alt) failed\n");
+ exit(EXIT_FAILURE);
+ }
+ hv[5] ^= 0x01;
+ if (br_rsa_verify(sig, sizeof sig, n, e, br_sha1_ID, hv)) {
+ fprintf(stderr, "RSA-1024/SHA-1 sig verify (alt) should have failed\n");
+ exit(EXIT_FAILURE);
+ }
+ hv[5] ^= 0x01;
+
+ printf("done.\n");
+ fflush(stdout);
+}
+#endif
+
+/*
+ * From: http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf
+ */
+static const char *const KAT_GHASH[] = {
+
+ "66e94bd4ef8a2c3b884cfa59ca342b2e",
+ "",
+ "",
+ "00000000000000000000000000000000",
+
+ "66e94bd4ef8a2c3b884cfa59ca342b2e",
+ "",
+ "0388dace60b6a392f328c2b971b2fe78",
+ "f38cbb1ad69223dcc3457ae5b6b0f885",
+
+ "b83b533708bf535d0aa6e52980d53b78",
+ "",
+ "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985",
+ "7f1b32b81b820d02614f8895ac1d4eac",
+
+ "b83b533708bf535d0aa6e52980d53b78",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091",
+ "698e57f70e6ecc7fd9463b7260a9ae5f",
+
+ "b83b533708bf535d0aa6e52980d53b78",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598",
+ "df586bb4c249b92cb6922877e444d37b",
+
+ "b83b533708bf535d0aa6e52980d53b78",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5",
+ "1c5afe9760d3932f3c9a878aac3dc3de",
+
+ "aae06992acbf52a3e8f4a96ec9300bd7",
+ "",
+ "98e7247c07f0fe411c267e4384b0f600",
+ "e2c63f0ac44ad0e02efa05ab6743d4ce",
+
+ "466923ec9ae682214f2c082badb39249",
+ "",
+ "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256",
+ "51110d40f6c8fff0eb1ae33445a889f0",
+
+ "466923ec9ae682214f2c082badb39249",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710",
+ "ed2ce3062e4a8ec06db8b4c490e8a268",
+
+ "466923ec9ae682214f2c082badb39249",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7",
+ "1e6a133806607858ee80eaf237064089",
+
+ "466923ec9ae682214f2c082badb39249",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "d27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e4581e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b",
+ "82567fb0b4cc371801eadec005968e94",
+
+ "dc95c078a2408989ad48a21492842087",
+ "",
+ "cea7403d4d606b6e074ec5d3baf39d18",
+ "83de425c5edc5d498f382c441041ca92",
+
+ "acbef20579b4b8ebce889bac8732dad7",
+ "",
+ "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad",
+ "4db870d37cb75fcb46097c36230d1612",
+
+ "acbef20579b4b8ebce889bac8732dad7",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662",
+ "8bd0c4d8aacd391e67cca447e8c38f65",
+
+ "acbef20579b4b8ebce889bac8732dad7",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f",
+ "75a34288b8c68f811c52b2e9a2f97f63",
+
+ "acbef20579b4b8ebce889bac8732dad7",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f",
+ "d5ffcf6fc5ac4d69722187421a7f170b",
+
+ NULL,
+};
+
+static void
+test_GHASH(const char *name, br_ghash gh)
+{
+ size_t u;
+
+ printf("Test %s: ", name);
+ fflush(stdout);
+
+ for (u = 0; KAT_GHASH[u]; u += 4) {
+ unsigned char h[16];
+ unsigned char a[100];
+ size_t a_len;
+ unsigned char c[100];
+ size_t c_len;
+ unsigned char p[16];
+ unsigned char y[16];
+ unsigned char ref[16];
+
+ hextobin(h, KAT_GHASH[u]);
+ a_len = hextobin(a, KAT_GHASH[u + 1]);
+ c_len = hextobin(c, KAT_GHASH[u + 2]);
+ hextobin(ref, KAT_GHASH[u + 3]);
+ memset(y, 0, sizeof y);
+ gh(y, h, a, a_len);
+ gh(y, h, c, c_len);
+ memset(p, 0, sizeof p);
+ br_enc32be(p + 4, (uint32_t)a_len << 3);
+ br_enc32be(p + 12, (uint32_t)c_len << 3);
+ gh(y, h, p, sizeof p);
+ check_equals("KAT GHASH", y, ref, sizeof ref);
+ }
+
+ for (u = 0; u <= 1024; u ++) {
+ unsigned char key[32], iv[12];
+ unsigned char buf[1024 + 32];
+ unsigned char y0[16], y1[16];
+ char tmp[100];
+
+ memset(key, 0, sizeof key);
+ memset(iv, 0, sizeof iv);
+ br_enc32be(key, u);
+ memset(buf, 0, sizeof buf);
+ br_chacha20_ct_run(key, iv, 1, buf, sizeof buf);
+
+ memcpy(y0, buf, 16);
+ br_ghash_ctmul32(y0, buf + 16, buf + 32, u);
+ memcpy(y1, buf, 16);
+ gh(y1, buf + 16, buf + 32, u);
+ sprintf(tmp, "XREF %s (len = %u)", name, (unsigned)u);
+ check_equals(tmp, y0, y1, 16);
+
+ if ((u & 31) == 0) {
+ printf(".");
+ fflush(stdout);
+ }
+ }
+
+ printf("done.\n");
+ fflush(stdout);
+}
+
+static void
+test_GHASH_ctmul(void)
+{
+ test_GHASH("GHASH_ctmul", br_ghash_ctmul);
+}
+
+static void
+test_GHASH_ctmul32(void)
+{
+ test_GHASH("GHASH_ctmul32", br_ghash_ctmul32);
+}
+
+static void
+test_GHASH_ctmul64(void)
+{
+ test_GHASH("GHASH_ctmul64", br_ghash_ctmul64);
+}
+
+static void
+test_GHASH_pclmul(void)
+{
+ br_ghash gh;
+
+ gh = br_ghash_pclmul_get();
+ if (gh == 0) {
+ printf("Test GHASH_pclmul: UNAVAILABLE\n");
+ } else {
+ test_GHASH("GHASH_pclmul", gh);
+ }
+}
+
+static void
+test_GHASH_pwr8(void)
+{
+ br_ghash gh;
+
+ gh = br_ghash_pwr8_get();
+ if (gh == 0) {
+ printf("Test GHASH_pwr8: UNAVAILABLE\n");
+ } else {
+ test_GHASH("GHASH_pwr8", gh);
+ }
+}
+
+/*
+ * From: http://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf
+ *
+ * Order: key, plaintext, AAD, IV, ciphertext, tag
+ */
+static const char *const KAT_GCM[] = {
+ "00000000000000000000000000000000",
+ "",
+ "",
+ "000000000000000000000000",
+ "",
+ "58e2fccefa7e3061367f1d57a4e7455a",
+
+ "00000000000000000000000000000000",
+ "00000000000000000000000000000000",
+ "",
+ "000000000000000000000000",
+ "0388dace60b6a392f328c2b971b2fe78",
+ "ab6e47d42cec13bdf53a67b21257bddf",
+
+ "feffe9928665731c6d6a8f9467308308",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
+ "",
+ "cafebabefacedbaddecaf888",
+ "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091473f5985",
+ "4d5c2af327cd64a62cf35abd2ba6fab4",
+
+ "feffe9928665731c6d6a8f9467308308",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "cafebabefacedbaddecaf888",
+ "42831ec2217774244b7221b784d0d49ce3aa212f2c02a4e035c17e2329aca12e21d514b25466931c7d8f6a5aac84aa051ba30b396a0aac973d58e091",
+ "5bc94fbc3221a5db94fae95ae7121a47",
+
+ "feffe9928665731c6d6a8f9467308308",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "cafebabefacedbad",
+ "61353b4c2806934a777ff51fa22a4755699b2a714fcdc6f83766e5f97b6c742373806900e49f24b22b097544d4896b424989b5e1ebac0f07c23f4598",
+ "3612d2e79e3b0785561be14aaca2fccb",
+
+ "feffe9928665731c6d6a8f9467308308",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
+ "8ce24998625615b603a033aca13fb894be9112a5c3a211a8ba262a3cca7e2ca701e4a9a4fba43c90ccdcb281d48c7c6fd62875d2aca417034c34aee5",
+ "619cc5aefffe0bfa462af43c1699d050",
+
+ "000000000000000000000000000000000000000000000000",
+ "",
+ "",
+ "000000000000000000000000",
+ "",
+ "cd33b28ac773f74ba00ed1f312572435",
+
+ "000000000000000000000000000000000000000000000000",
+ "00000000000000000000000000000000",
+ "",
+ "000000000000000000000000",
+ "98e7247c07f0fe411c267e4384b0f600",
+ "2ff58d80033927ab8ef4d4587514f0fb",
+
+ "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
+ "",
+ "cafebabefacedbaddecaf888",
+ "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710acade256",
+ "9924a7c8587336bfb118024db8674a14",
+
+ "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "cafebabefacedbaddecaf888",
+ "3980ca0b3c00e841eb06fac4872a2757859e1ceaa6efd984628593b40ca1e19c7d773d00c144c525ac619d18c84a3f4718e2448b2fe324d9ccda2710",
+ "2519498e80f1478f37ba55bd6d27618c",
+
+ "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "cafebabefacedbad",
+ "0f10f599ae14a154ed24b36e25324db8c566632ef2bbb34f8347280fc4507057fddc29df9a471f75c66541d4d4dad1c9e93a19a58e8b473fa0f062f7",
+ "65dcc57fcf623a24094fcca40d3533f8",
+
+ "feffe9928665731c6d6a8f9467308308feffe9928665731c",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
+ "d27e88681ce3243c4830165a8fdcf9ff1de9a1d8e6b447ef6ef7b79828666e4581e79012af34ddd9e2f037589b292db3e67c036745fa22e7e9b7373b",
+ "dcf566ff291c25bbb8568fc3d376a6d9",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "",
+ "",
+ "000000000000000000000000",
+ "",
+ "530f8afbc74536b9a963b4f1c4cb738b",
+
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "00000000000000000000000000000000",
+ "",
+ "000000000000000000000000",
+ "cea7403d4d606b6e074ec5d3baf39d18",
+ "d0d1c8a799996bf0265b98b5d48ab919",
+
+ "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b391aafd255",
+ "",
+ "cafebabefacedbaddecaf888",
+ "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662898015ad",
+ "b094dac5d93471bdec1a502270e3cc6c",
+
+ "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "cafebabefacedbaddecaf888",
+ "522dc1f099567d07f47f37a32a84427d643a8cdcbfe5c0c97598a2bd2555d1aa8cb08e48590dbb3da7b08b1056828838c5f61e6393ba7a0abcc9f662",
+ "76fc6ece0f4e1768cddf8853bb2d551b",
+
+ "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "cafebabefacedbad",
+ "c3762df1ca787d32ae47c13bf19844cbaf1ae14d0b976afac52ff7d79bba9de0feb582d33934a4f0954cc2363bc73f7862ac430e64abe499f47c9b1f",
+ "3a337dbf46a792c45e454913fe2ea8f2",
+
+ "feffe9928665731c6d6a8f9467308308feffe9928665731c6d6a8f9467308308",
+ "d9313225f88406e5a55909c5aff5269a86a7a9531534f7da2e4c303d8a318a721c3c0c95956809532fcf0e2449a6b525b16aedf5aa0de657ba637b39",
+ "feedfacedeadbeeffeedfacedeadbeefabaddad2",
+ "9313225df88406e555909c5aff5269aa6a7a9538534f7da1e4c303d2a318a728c3c0c95156809539fcf0e2429a6b525416aedbf5a0de6a57a637b39b",
+ "5a8def2f0c9e53f1f75d7853659e2a20eeb2b22aafde6419a058ab4f6f746bf40fc0c3b780f244452da3ebf1c5d82cdea2418997200ef82e44ae7e3f",
+ "a44a8266ee1c8eb0c8b5d4cf5ae9f19a",
+
+ NULL
+};
+
+static void
+test_GCM(void)
+{
+ size_t u;
+
+ printf("Test GCM: ");
+ fflush(stdout);
+
+ for (u = 0; KAT_GCM[u]; u += 6) {
+ unsigned char key[32];
+ unsigned char plain[100];
+ unsigned char aad[100];
+ unsigned char iv[100];
+ unsigned char cipher[100];
+ unsigned char tag[100];
+ size_t key_len, plain_len, aad_len, iv_len;
+ br_aes_ct_ctr_keys bc;
+ br_gcm_context gc;
+ unsigned char tmp[100], out[16];
+ size_t v, tag_len;
+
+ key_len = hextobin(key, KAT_GCM[u]);
+ plain_len = hextobin(plain, KAT_GCM[u + 1]);
+ aad_len = hextobin(aad, KAT_GCM[u + 2]);
+ iv_len = hextobin(iv, KAT_GCM[u + 3]);
+ hextobin(cipher, KAT_GCM[u + 4]);
+ hextobin(tag, KAT_GCM[u + 5]);
+
+ br_aes_ct_ctr_init(&bc, key, key_len);
+ br_gcm_init(&gc, &bc.vtable, br_ghash_ctmul32);
+
+ memset(tmp, 0x54, sizeof tmp);
+
+ /*
+ * Basic operation.
+ */
+ memcpy(tmp, plain, plain_len);
+ br_gcm_reset(&gc, iv, iv_len);
+ br_gcm_aad_inject(&gc, aad, aad_len);
+ br_gcm_flip(&gc);
+ br_gcm_run(&gc, 1, tmp, plain_len);
+ br_gcm_get_tag(&gc, out);
+ check_equals("KAT GCM 1", tmp, cipher, plain_len);
+ check_equals("KAT GCM 2", out, tag, 16);
+
+ br_gcm_reset(&gc, iv, iv_len);
+ br_gcm_aad_inject(&gc, aad, aad_len);
+ br_gcm_flip(&gc);
+ br_gcm_run(&gc, 0, tmp, plain_len);
+ check_equals("KAT GCM 3", tmp, plain, plain_len);
+ if (!br_gcm_check_tag(&gc, tag)) {
+ fprintf(stderr, "Tag not verified (1)\n");
+ exit(EXIT_FAILURE);
+ }
+
+ for (v = plain_len; v < sizeof tmp; v ++) {
+ if (tmp[v] != 0x54) {
+ fprintf(stderr, "overflow on data\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /*
+ * Byte-by-byte injection.
+ */
+ br_gcm_reset(&gc, iv, iv_len);
+ for (v = 0; v < aad_len; v ++) {
+ br_gcm_aad_inject(&gc, aad + v, 1);
+ }
+ br_gcm_flip(&gc);
+ for (v = 0; v < plain_len; v ++) {
+ br_gcm_run(&gc, 1, tmp + v, 1);
+ }
+ check_equals("KAT GCM 4", tmp, cipher, plain_len);
+ if (!br_gcm_check_tag(&gc, tag)) {
+ fprintf(stderr, "Tag not verified (2)\n");
+ exit(EXIT_FAILURE);
+ }
+
+ br_gcm_reset(&gc, iv, iv_len);
+ for (v = 0; v < aad_len; v ++) {
+ br_gcm_aad_inject(&gc, aad + v, 1);
+ }
+ br_gcm_flip(&gc);
+ for (v = 0; v < plain_len; v ++) {
+ br_gcm_run(&gc, 0, tmp + v, 1);
+ }
+ br_gcm_get_tag(&gc, out);
+ check_equals("KAT GCM 5", tmp, plain, plain_len);
+ check_equals("KAT GCM 6", out, tag, 16);
+
+ /*
+ * Check that alterations are detected.
+ */
+ for (v = 0; v < aad_len; v ++) {
+ memcpy(tmp, cipher, plain_len);
+ br_gcm_reset(&gc, iv, iv_len);
+ aad[v] ^= 0x04;
+ br_gcm_aad_inject(&gc, aad, aad_len);
+ aad[v] ^= 0x04;
+ br_gcm_flip(&gc);
+ br_gcm_run(&gc, 0, tmp, plain_len);
+ check_equals("KAT GCM 7", tmp, plain, plain_len);
+ if (br_gcm_check_tag(&gc, tag)) {
+ fprintf(stderr, "Tag should have changed\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /*
+ * Tag truncation.
+ */
+ for (tag_len = 1; tag_len <= 16; tag_len ++) {
+ memset(out, 0x54, sizeof out);
+ memcpy(tmp, plain, plain_len);
+ br_gcm_reset(&gc, iv, iv_len);
+ br_gcm_aad_inject(&gc, aad, aad_len);
+ br_gcm_flip(&gc);
+ br_gcm_run(&gc, 1, tmp, plain_len);
+ br_gcm_get_tag_trunc(&gc, out, tag_len);
+ check_equals("KAT GCM 8", out, tag, tag_len);
+ for (v = tag_len; v < sizeof out; v ++) {
+ if (out[v] != 0x54) {
+ fprintf(stderr, "overflow on tag\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ memcpy(tmp, plain, plain_len);
+ br_gcm_reset(&gc, iv, iv_len);
+ br_gcm_aad_inject(&gc, aad, aad_len);
+ br_gcm_flip(&gc);
+ br_gcm_run(&gc, 1, tmp, plain_len);
+ if (!br_gcm_check_tag_trunc(&gc, out, tag_len)) {
+ fprintf(stderr, "Tag not verified (3)\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ printf(".");
+ fflush(stdout);
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+/*
+ * From "The EAX Mode of Operation (A Two-Pass Authenticated Encryption
+ * Scheme Optimized for Simplicity and Efficiency)" (Bellare, Rogaway,
+ * Wagner), presented at FSE 2004. Full article is available at:
+ * http://web.cs.ucdavis.edu/~rogaway/papers/eax.html
+ *
+ * EAX specification concatenates the authentication tag at the end of
+ * the ciphertext; in our API and the vectors below, the tag is separate.
+ *
+ * Order is: plaintext, key, nonce, header, ciphertext, tag.
+ */
+static const char *const KAT_EAX[] = {
+ "",
+ "233952dee4d5ed5f9b9c6d6ff80ff478",
+ "62ec67f9c3a4a407fcb2a8c49031a8b3",
+ "6bfb914fd07eae6b",
+ "",
+ "e037830e8389f27b025a2d6527e79d01",
+
+ "f7fb",
+ "91945d3f4dcbee0bf45ef52255f095a4",
+ "becaf043b0a23d843194ba972c66debd",
+ "fa3bfd4806eb53fa",
+ "19dd",
+ "5c4c9331049d0bdab0277408f67967e5",
+
+ "1a47cb4933",
+ "01f74ad64077f2e704c0f60ada3dd523",
+ "70c3db4f0d26368400a10ed05d2bff5e",
+ "234a3463c1264ac6",
+ "d851d5bae0",
+ "3a59f238a23e39199dc9266626c40f80",
+
+ "481c9e39b1",
+ "d07cf6cbb7f313bdde66b727afd3c5e8",
+ "8408dfff3c1a2b1292dc199e46b7d617",
+ "33cce2eabff5a79d",
+ "632a9d131a",
+ "d4c168a4225d8e1ff755939974a7bede",
+
+ "40d0c07da5e4",
+ "35b6d0580005bbc12b0587124557d2c2",
+ "fdb6b06676eedc5c61d74276e1f8e816",
+ "aeb96eaebe2970e9",
+ "071dfe16c675",
+ "cb0677e536f73afe6a14b74ee49844dd",
+
+ "4de3b35c3fc039245bd1fb7d",
+ "bd8e6e11475e60b268784c38c62feb22",
+ "6eac5c93072d8e8513f750935e46da1b",
+ "d4482d1ca78dce0f",
+ "835bb4f15d743e350e728414",
+ "abb8644fd6ccb86947c5e10590210a4f",
+
+ "8b0a79306c9ce7ed99dae4f87f8dd61636",
+ "7c77d6e813bed5ac98baa417477a2e7d",
+ "1a8c98dcd73d38393b2bf1569deefc19",
+ "65d2017990d62528",
+ "02083e3979da014812f59f11d52630da30",
+ "137327d10649b0aa6e1c181db617d7f2",
+
+ "1bda122bce8a8dbaf1877d962b8592dd2d56",
+ "5fff20cafab119ca2fc73549e20f5b0d",
+ "dde59b97d722156d4d9aff2bc7559826",
+ "54b9f04e6a09189a",
+ "2ec47b2c4954a489afc7ba4897edcdae8cc3",
+ "3b60450599bd02c96382902aef7f832a",
+
+ "6cf36720872b8513f6eab1a8a44438d5ef11",
+ "a4a4782bcffd3ec5e7ef6d8c34a56123",
+ "b781fcf2f75fa5a8de97a9ca48e522ec",
+ "899a175897561d7e",
+ "0de18fd0fdd91e7af19f1d8ee8733938b1e8",
+ "e7f6d2231618102fdb7fe55ff1991700",
+
+ "ca40d7446e545ffaed3bd12a740a659ffbbb3ceab7",
+ "8395fcf1e95bebd697bd010bc766aac3",
+ "22e7add93cfc6393c57ec0b3c17d6b44",
+ "126735fcc320d25a",
+ "cb8920f87a6c75cff39627b56e3ed197c552d295a7",
+ "cfc46afc253b4652b1af3795b124ab6e",
+
+ NULL
+};
+
+static void
+test_EAX_inner(const char *name, const br_block_ctrcbc_class *vt)
+{
+ size_t u;
+
+ printf("Test EAX %s: ", name);
+ fflush(stdout);
+
+ for (u = 0; KAT_EAX[u]; u += 6) {
+ unsigned char plain[100];
+ unsigned char key[32];
+ unsigned char nonce[100];
+ unsigned char aad[100];
+ unsigned char cipher[100];
+ unsigned char tag[100];
+ size_t plain_len, key_len, nonce_len, aad_len;
+ br_aes_gen_ctrcbc_keys bc;
+ br_eax_context ec;
+ br_eax_state st;
+ unsigned char tmp[100], out[16];
+ size_t v, tag_len;
+
+ plain_len = hextobin(plain, KAT_EAX[u]);
+ key_len = hextobin(key, KAT_EAX[u + 1]);
+ nonce_len = hextobin(nonce, KAT_EAX[u + 2]);
+ aad_len = hextobin(aad, KAT_EAX[u + 3]);
+ hextobin(cipher, KAT_EAX[u + 4]);
+ hextobin(tag, KAT_EAX[u + 5]);
+
+ vt->init(&bc.vtable, key, key_len);
+ br_eax_init(&ec, &bc.vtable);
+
+ memset(tmp, 0x54, sizeof tmp);
+
+ /*
+ * Basic operation.
+ */
+ memcpy(tmp, plain, plain_len);
+ br_eax_reset(&ec, nonce, nonce_len);
+ br_eax_aad_inject(&ec, aad, aad_len);
+ br_eax_flip(&ec);
+ br_eax_run(&ec, 1, tmp, plain_len);
+ br_eax_get_tag(&ec, out);
+ check_equals("KAT EAX 1", tmp, cipher, plain_len);
+ check_equals("KAT EAX 2", out, tag, 16);
+
+ br_eax_reset(&ec, nonce, nonce_len);
+ br_eax_aad_inject(&ec, aad, aad_len);
+ br_eax_flip(&ec);
+ br_eax_run(&ec, 0, tmp, plain_len);
+ check_equals("KAT EAX 3", tmp, plain, plain_len);
+ if (!br_eax_check_tag(&ec, tag)) {
+ fprintf(stderr, "Tag not verified (1)\n");
+ exit(EXIT_FAILURE);
+ }
+
+ for (v = plain_len; v < sizeof tmp; v ++) {
+ if (tmp[v] != 0x54) {
+ fprintf(stderr, "overflow on data\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /*
+ * Byte-by-byte injection.
+ */
+ br_eax_reset(&ec, nonce, nonce_len);
+ for (v = 0; v < aad_len; v ++) {
+ br_eax_aad_inject(&ec, aad + v, 1);
+ }
+ br_eax_flip(&ec);
+ for (v = 0; v < plain_len; v ++) {
+ br_eax_run(&ec, 1, tmp + v, 1);
+ }
+ check_equals("KAT EAX 4", tmp, cipher, plain_len);
+ if (!br_eax_check_tag(&ec, tag)) {
+ fprintf(stderr, "Tag not verified (2)\n");
+ exit(EXIT_FAILURE);
+ }
+
+ br_eax_reset(&ec, nonce, nonce_len);
+ for (v = 0; v < aad_len; v ++) {
+ br_eax_aad_inject(&ec, aad + v, 1);
+ }
+ br_eax_flip(&ec);
+ for (v = 0; v < plain_len; v ++) {
+ br_eax_run(&ec, 0, tmp + v, 1);
+ }
+ br_eax_get_tag(&ec, out);
+ check_equals("KAT EAX 5", tmp, plain, plain_len);
+ check_equals("KAT EAX 6", out, tag, 16);
+
+ /*
+ * Check that alterations are detected.
+ */
+ for (v = 0; v < aad_len; v ++) {
+ memcpy(tmp, cipher, plain_len);
+ br_eax_reset(&ec, nonce, nonce_len);
+ aad[v] ^= 0x04;
+ br_eax_aad_inject(&ec, aad, aad_len);
+ aad[v] ^= 0x04;
+ br_eax_flip(&ec);
+ br_eax_run(&ec, 0, tmp, plain_len);
+ check_equals("KAT EAX 7", tmp, plain, plain_len);
+ if (br_eax_check_tag(&ec, tag)) {
+ fprintf(stderr, "Tag should have changed\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /*
+ * Tag truncation.
+ */
+ for (tag_len = 1; tag_len <= 16; tag_len ++) {
+ memset(out, 0x54, sizeof out);
+ memcpy(tmp, plain, plain_len);
+ br_eax_reset(&ec, nonce, nonce_len);
+ br_eax_aad_inject(&ec, aad, aad_len);
+ br_eax_flip(&ec);
+ br_eax_run(&ec, 1, tmp, plain_len);
+ br_eax_get_tag_trunc(&ec, out, tag_len);
+ check_equals("KAT EAX 8", out, tag, tag_len);
+ for (v = tag_len; v < sizeof out; v ++) {
+ if (out[v] != 0x54) {
+ fprintf(stderr, "overflow on tag\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ memcpy(tmp, plain, plain_len);
+ br_eax_reset(&ec, nonce, nonce_len);
+ br_eax_aad_inject(&ec, aad, aad_len);
+ br_eax_flip(&ec);
+ br_eax_run(&ec, 1, tmp, plain_len);
+ if (!br_eax_check_tag_trunc(&ec, out, tag_len)) {
+ fprintf(stderr, "Tag not verified (3)\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ printf(".");
+ fflush(stdout);
+
+ /*
+ * For capture tests, we need the message to be non-empty.
+ */
+ if (plain_len == 0) {
+ continue;
+ }
+
+ /*
+ * Captured state, pre-AAD. This requires the AAD and the
+ * message to be non-empty.
+ */
+ br_eax_capture(&ec, &st);
+
+ if (aad_len > 0) {
+ br_eax_reset_pre_aad(&ec, &st, nonce, nonce_len);
+ br_eax_aad_inject(&ec, aad, aad_len);
+ br_eax_flip(&ec);
+ memcpy(tmp, plain, plain_len);
+ br_eax_run(&ec, 1, tmp, plain_len);
+ br_eax_get_tag(&ec, out);
+ check_equals("KAT EAX 9", tmp, cipher, plain_len);
+ check_equals("KAT EAX 10", out, tag, 16);
+
+ br_eax_reset_pre_aad(&ec, &st, nonce, nonce_len);
+ br_eax_aad_inject(&ec, aad, aad_len);
+ br_eax_flip(&ec);
+ br_eax_run(&ec, 0, tmp, plain_len);
+ br_eax_get_tag(&ec, out);
+ check_equals("KAT EAX 11", tmp, plain, plain_len);
+ check_equals("KAT EAX 12", out, tag, 16);
+ }
+
+ /*
+ * Captured state, post-AAD. This requires the message to
+ * be non-empty.
+ */
+ br_eax_reset(&ec, nonce, nonce_len);
+ br_eax_aad_inject(&ec, aad, aad_len);
+ br_eax_flip(&ec);
+ br_eax_get_aad_mac(&ec, &st);
+
+ br_eax_reset_post_aad(&ec, &st, nonce, nonce_len);
+ memcpy(tmp, plain, plain_len);
+ br_eax_run(&ec, 1, tmp, plain_len);
+ br_eax_get_tag(&ec, out);
+ check_equals("KAT EAX 13", tmp, cipher, plain_len);
+ check_equals("KAT EAX 14", out, tag, 16);
+
+ br_eax_reset_post_aad(&ec, &st, nonce, nonce_len);
+ br_eax_run(&ec, 0, tmp, plain_len);
+ br_eax_get_tag(&ec, out);
+ check_equals("KAT EAX 15", tmp, plain, plain_len);
+ check_equals("KAT EAX 16", out, tag, 16);
+
+ printf(".");
+ fflush(stdout);
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+static void
+test_EAX(void)
+{
+ const br_block_ctrcbc_class *x_ctrcbc;
+
+ test_EAX_inner("aes_big", &br_aes_big_ctrcbc_vtable);
+ test_EAX_inner("aes_small", &br_aes_small_ctrcbc_vtable);
+ test_EAX_inner("aes_ct", &br_aes_ct_ctrcbc_vtable);
+ test_EAX_inner("aes_ct64", &br_aes_ct64_ctrcbc_vtable);
+
+ x_ctrcbc = br_aes_x86ni_ctrcbc_get_vtable();
+ if (x_ctrcbc != NULL) {
+ test_EAX_inner("aes_x86ni", x_ctrcbc);
+ } else {
+ printf("Test EAX aes_x86ni: UNAVAILABLE\n");
+ }
+
+ x_ctrcbc = br_aes_pwr8_ctrcbc_get_vtable();
+ if (x_ctrcbc != NULL) {
+ test_EAX_inner("aes_pwr8", x_ctrcbc);
+ } else {
+ printf("Test EAX aes_pwr8: UNAVAILABLE\n");
+ }
+}
+
+/*
+ * From NIST SP 800-38C, appendix C.
+ *
+ * CCM specification concatenates the authentication tag at the end of
+ * the ciphertext; in our API and the vectors below, the tag is separate.
+ *
+ * Order is: key, nonce, aad, plaintext, ciphertext, tag.
+ */
+static const char *const KAT_CCM[] = {
+ "404142434445464748494a4b4c4d4e4f",
+ "10111213141516",
+ "0001020304050607",
+ "20212223",
+ "7162015b",
+ "4dac255d",
+
+ "404142434445464748494a4b4c4d4e4f",
+ "1011121314151617",
+ "000102030405060708090a0b0c0d0e0f",
+ "202122232425262728292a2b2c2d2e2f",
+ "d2a1f0e051ea5f62081a7792073d593d",
+ "1fc64fbfaccd",
+
+ "404142434445464748494a4b4c4d4e4f",
+ "101112131415161718191a1b",
+ "000102030405060708090a0b0c0d0e0f10111213",
+ "202122232425262728292a2b2c2d2e2f3031323334353637",
+ "e3b201a9f5b71a7a9b1ceaeccd97e70b6176aad9a4428aa5",
+ "484392fbc1b09951",
+
+ "404142434445464748494a4b4c4d4e4f",
+ "101112131415161718191a1b1c",
+ NULL,
+ "202122232425262728292a2b2c2d2e2f303132333435363738393a3b3c3d3e3f",
+ "69915dad1e84c6376a68c2967e4dab615ae0fd1faec44cc484828529463ccf72",
+ "b4ac6bec93e8598e7f0dadbcea5b",
+
+ NULL
+};
+
+static void
+test_CCM_inner(const char *name, const br_block_ctrcbc_class *vt)
+{
+ size_t u;
+
+ printf("Test CCM %s: ", name);
+ fflush(stdout);
+
+ for (u = 0; KAT_CCM[u]; u += 6) {
+ unsigned char plain[100];
+ unsigned char key[32];
+ unsigned char nonce[100];
+ unsigned char aad_buf[100], *aad;
+ unsigned char cipher[100];
+ unsigned char tag[100];
+ size_t plain_len, key_len, nonce_len, aad_len, tag_len;
+ br_aes_gen_ctrcbc_keys bc;
+ br_ccm_context ec;
+ unsigned char tmp[100], out[16];
+ size_t v;
+
+ key_len = hextobin(key, KAT_CCM[u]);
+ nonce_len = hextobin(nonce, KAT_CCM[u + 1]);
+ if (KAT_CCM[u + 2] == NULL) {
+ aad_len = 65536;
+ aad = malloc(aad_len);
+ if (aad == NULL) {
+ fprintf(stderr, "OOM error\n");
+ exit(EXIT_FAILURE);
+ }
+ for (v = 0; v < 65536; v ++) {
+ aad[v] = (unsigned char)v;
+ }
+ } else {
+ aad = aad_buf;
+ aad_len = hextobin(aad, KAT_CCM[u + 2]);
+ }
+ plain_len = hextobin(plain, KAT_CCM[u + 3]);
+ hextobin(cipher, KAT_CCM[u + 4]);
+ tag_len = hextobin(tag, KAT_CCM[u + 5]);
+
+ vt->init(&bc.vtable, key, key_len);
+ br_ccm_init(&ec, &bc.vtable);
+
+ memset(tmp, 0x54, sizeof tmp);
+
+ /*
+ * Basic operation.
+ */
+ memcpy(tmp, plain, plain_len);
+ if (!br_ccm_reset(&ec, nonce, nonce_len,
+ aad_len, plain_len, tag_len))
+ {
+ fprintf(stderr, "CCM reset failed\n");
+ exit(EXIT_FAILURE);
+ }
+ br_ccm_aad_inject(&ec, aad, aad_len);
+ br_ccm_flip(&ec);
+ br_ccm_run(&ec, 1, tmp, plain_len);
+ if (br_ccm_get_tag(&ec, out) != tag_len) {
+ fprintf(stderr, "CCM returned wrong tag length\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("KAT CCM 1", tmp, cipher, plain_len);
+ check_equals("KAT CCM 2", out, tag, tag_len);
+
+ br_ccm_reset(&ec, nonce, nonce_len,
+ aad_len, plain_len, tag_len);
+ br_ccm_aad_inject(&ec, aad, aad_len);
+ br_ccm_flip(&ec);
+ br_ccm_run(&ec, 0, tmp, plain_len);
+ check_equals("KAT CCM 3", tmp, plain, plain_len);
+ if (!br_ccm_check_tag(&ec, tag)) {
+ fprintf(stderr, "Tag not verified (1)\n");
+ exit(EXIT_FAILURE);
+ }
+
+ for (v = plain_len; v < sizeof tmp; v ++) {
+ if (tmp[v] != 0x54) {
+ fprintf(stderr, "overflow on data\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /*
+ * Byte-by-byte injection.
+ */
+ br_ccm_reset(&ec, nonce, nonce_len,
+ aad_len, plain_len, tag_len);
+ for (v = 0; v < aad_len; v ++) {
+ br_ccm_aad_inject(&ec, aad + v, 1);
+ }
+ br_ccm_flip(&ec);
+ for (v = 0; v < plain_len; v ++) {
+ br_ccm_run(&ec, 1, tmp + v, 1);
+ }
+ check_equals("KAT CCM 4", tmp, cipher, plain_len);
+ if (!br_ccm_check_tag(&ec, tag)) {
+ fprintf(stderr, "Tag not verified (2)\n");
+ exit(EXIT_FAILURE);
+ }
+
+ br_ccm_reset(&ec, nonce, nonce_len,
+ aad_len, plain_len, tag_len);
+ for (v = 0; v < aad_len; v ++) {
+ br_ccm_aad_inject(&ec, aad + v, 1);
+ }
+ br_ccm_flip(&ec);
+ for (v = 0; v < plain_len; v ++) {
+ br_ccm_run(&ec, 0, tmp + v, 1);
+ }
+ br_ccm_get_tag(&ec, out);
+ check_equals("KAT CCM 5", tmp, plain, plain_len);
+ check_equals("KAT CCM 6", out, tag, tag_len);
+
+ /*
+ * Check that alterations are detected.
+ */
+ for (v = 0; v < aad_len; v ++) {
+ memcpy(tmp, cipher, plain_len);
+ br_ccm_reset(&ec, nonce, nonce_len,
+ aad_len, plain_len, tag_len);
+ aad[v] ^= 0x04;
+ br_ccm_aad_inject(&ec, aad, aad_len);
+ aad[v] ^= 0x04;
+ br_ccm_flip(&ec);
+ br_ccm_run(&ec, 0, tmp, plain_len);
+ check_equals("KAT CCM 7", tmp, plain, plain_len);
+ if (br_ccm_check_tag(&ec, tag)) {
+ fprintf(stderr, "Tag should have changed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * When the AAD is really big, we don't want to do
+ * the complete quadratic operation.
+ */
+ if (v >= 32) {
+ break;
+ }
+ }
+
+ if (aad != aad_buf) {
+ free(aad);
+ }
+
+ printf(".");
+ fflush(stdout);
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+static void
+test_CCM(void)
+{
+ const br_block_ctrcbc_class *x_ctrcbc;
+
+ test_CCM_inner("aes_big", &br_aes_big_ctrcbc_vtable);
+ test_CCM_inner("aes_small", &br_aes_small_ctrcbc_vtable);
+ test_CCM_inner("aes_ct", &br_aes_ct_ctrcbc_vtable);
+ test_CCM_inner("aes_ct64", &br_aes_ct64_ctrcbc_vtable);
+
+ x_ctrcbc = br_aes_x86ni_ctrcbc_get_vtable();
+ if (x_ctrcbc != NULL) {
+ test_CCM_inner("aes_x86ni", x_ctrcbc);
+ } else {
+ printf("Test CCM aes_x86ni: UNAVAILABLE\n");
+ }
+
+ x_ctrcbc = br_aes_pwr8_ctrcbc_get_vtable();
+ if (x_ctrcbc != NULL) {
+ test_CCM_inner("aes_pwr8", x_ctrcbc);
+ } else {
+ printf("Test CCM aes_pwr8: UNAVAILABLE\n");
+ }
+}
+
+static void
+test_EC_inner(const char *sk, const char *sU,
+ const br_ec_impl *impl, int curve)
+{
+ unsigned char bk[70];
+ unsigned char eG[150], eU[150];
+ uint32_t n[22], n0i;
+ size_t klen, ulen, nlen;
+ const br_ec_curve_def *cd;
+ br_hmac_drbg_context rng;
+ int i;
+
+ klen = hextobin(bk, sk);
+ ulen = hextobin(eU, sU);
+ switch (curve) {
+ case BR_EC_secp256r1:
+ cd = &br_secp256r1;
+ break;
+ case BR_EC_secp384r1:
+ cd = &br_secp384r1;
+ break;
+ case BR_EC_secp521r1:
+ cd = &br_secp521r1;
+ break;
+ default:
+ fprintf(stderr, "Unknown curve: %d\n", curve);
+ exit(EXIT_FAILURE);
+ break;
+ }
+ if (ulen != cd->generator_len) {
+ fprintf(stderr, "KAT vector wrong (%lu / %lu)\n",
+ (unsigned long)ulen,
+ (unsigned long)cd->generator_len);
+ }
+ memcpy(eG, cd->generator, ulen);
+ if (impl->mul(eG, ulen, bk, klen, curve) != 1) {
+ fprintf(stderr, "KAT multiplication failed\n");
+ exit(EXIT_FAILURE);
+ }
+ if (memcmp(eG, eU, ulen) != 0) {
+ fprintf(stderr, "KAT mul: mismatch\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Test the two-point-mul function. We want to test the basic
+ * functionality, and the following special cases:
+ * x = y
+ * x + y = curve order
+ */
+ nlen = cd->order_len;
+ br_i31_decode(n, cd->order, nlen);
+ n0i = br_i31_ninv31(n[1]);
+ br_hmac_drbg_init(&rng, &br_sha256_vtable, "seed for EC", 11);
+ for (i = 0; i < 10; i ++) {
+ unsigned char ba[80], bb[80], bx[80], by[80], bz[80];
+ uint32_t a[22], b[22], x[22], y[22], z[22], t1[22], t2[22];
+ uint32_t r;
+ unsigned char eA[160], eB[160], eC[160], eD[160];
+
+ /*
+ * Generate random a and b, and compute A = a*G and B = b*G.
+ */
+ br_hmac_drbg_generate(&rng, ba, sizeof ba);
+ br_i31_decode_reduce(a, ba, sizeof ba, n);
+ br_i31_encode(ba, nlen, a);
+ br_hmac_drbg_generate(&rng, bb, sizeof bb);
+ br_i31_decode_reduce(b, bb, sizeof bb, n);
+ br_i31_encode(bb, nlen, b);
+ memcpy(eA, cd->generator, ulen);
+ impl->mul(eA, ulen, ba, nlen, cd->curve);
+ memcpy(eB, cd->generator, ulen);
+ impl->mul(eB, ulen, bb, nlen, cd->curve);
+
+ /*
+ * Generate random x and y (modulo n).
+ */
+ br_hmac_drbg_generate(&rng, bx, sizeof bx);
+ br_i31_decode_reduce(x, bx, sizeof bx, n);
+ br_i31_encode(bx, nlen, x);
+ br_hmac_drbg_generate(&rng, by, sizeof by);
+ br_i31_decode_reduce(y, by, sizeof by, n);
+ br_i31_encode(by, nlen, y);
+
+ /*
+ * Compute z = a*x + b*y (mod n).
+ */
+ memcpy(t1, x, sizeof x);
+ br_i31_to_monty(t1, n);
+ br_i31_montymul(z, a, t1, n, n0i);
+ memcpy(t1, y, sizeof y);
+ br_i31_to_monty(t1, n);
+ br_i31_montymul(t2, b, t1, n, n0i);
+ r = br_i31_add(z, t2, 1);
+ r |= br_i31_sub(z, n, 0) ^ 1;
+ br_i31_sub(z, n, r);
+ br_i31_encode(bz, nlen, z);
+
+ /*
+ * Compute C = x*A + y*B with muladd(), and also
+ * D = z*G with mul(). The two points must match.
+ */
+ memcpy(eC, eA, ulen);
+ if (impl->muladd(eC, eB, ulen,
+ bx, nlen, by, nlen, cd->curve) != 1)
+ {
+ fprintf(stderr, "muladd() failed (1)\n");
+ exit(EXIT_FAILURE);
+ }
+ memcpy(eD, cd->generator, ulen);
+ if (impl->mul(eD, ulen, bz, nlen, cd->curve) != 1) {
+ fprintf(stderr, "mul() failed (1)\n");
+ exit(EXIT_FAILURE);
+ }
+ if (memcmp(eC, eD, nlen) != 0) {
+ fprintf(stderr, "mul() / muladd() mismatch\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Also recomputed D = z*G with mulgen(). This must
+ * again match.
+ */
+ memset(eD, 0, ulen);
+ if (impl->mulgen(eD, bz, nlen, cd->curve) != ulen) {
+ fprintf(stderr, "mulgen() failed: wrong length\n");
+ exit(EXIT_FAILURE);
+ }
+ if (memcmp(eC, eD, nlen) != 0) {
+ fprintf(stderr, "mulgen() / muladd() mismatch\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Check with x*A = y*B. We do so by setting b = x and y = a.
+ */
+ memcpy(b, x, sizeof x);
+ br_i31_encode(bb, nlen, b);
+ memcpy(eB, cd->generator, ulen);
+ impl->mul(eB, ulen, bb, nlen, cd->curve);
+ memcpy(y, a, sizeof a);
+ br_i31_encode(by, nlen, y);
+
+ memcpy(t1, x, sizeof x);
+ br_i31_to_monty(t1, n);
+ br_i31_montymul(z, a, t1, n, n0i);
+ memcpy(t1, y, sizeof y);
+ br_i31_to_monty(t1, n);
+ br_i31_montymul(t2, b, t1, n, n0i);
+ r = br_i31_add(z, t2, 1);
+ r |= br_i31_sub(z, n, 0) ^ 1;
+ br_i31_sub(z, n, r);
+ br_i31_encode(bz, nlen, z);
+
+ memcpy(eC, eA, ulen);
+ if (impl->muladd(eC, eB, ulen,
+ bx, nlen, by, nlen, cd->curve) != 1)
+ {
+ fprintf(stderr, "muladd() failed (2)\n");
+ exit(EXIT_FAILURE);
+ }
+ memcpy(eD, cd->generator, ulen);
+ if (impl->mul(eD, ulen, bz, nlen, cd->curve) != 1) {
+ fprintf(stderr, "mul() failed (2)\n");
+ exit(EXIT_FAILURE);
+ }
+ if (memcmp(eC, eD, nlen) != 0) {
+ fprintf(stderr,
+ "mul() / muladd() mismatch (x*A=y*B)\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Check with x*A + y*B = 0. At that point, b = x, so we
+ * just need to set y = -a (mod n).
+ */
+ memcpy(y, n, sizeof n);
+ br_i31_sub(y, a, 1);
+ br_i31_encode(by, nlen, y);
+ memcpy(eC, eA, ulen);
+ if (impl->muladd(eC, eB, ulen,
+ bx, nlen, by, nlen, cd->curve) != 0)
+ {
+ fprintf(stderr, "muladd() should have failed\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ printf(".");
+ fflush(stdout);
+}
+
+static void
+test_EC_P256_carry_inner(const br_ec_impl *impl, const char *sP, const char *sQ)
+{
+ unsigned char P[65], Q[sizeof P], k[1];
+ size_t plen, qlen;
+
+ plen = hextobin(P, sP);
+ qlen = hextobin(Q, sQ);
+ if (plen != sizeof P || qlen != sizeof P) {
+ fprintf(stderr, "KAT is incorrect\n");
+ exit(EXIT_FAILURE);
+ }
+ k[0] = 0x10;
+ if (impl->mul(P, plen, k, 1, BR_EC_secp256r1) != 1) {
+ fprintf(stderr, "P-256 multiplication failed\n");
+ exit(EXIT_FAILURE);
+ }
+ check_equals("P256_carry", P, Q, plen);
+ printf(".");
+ fflush(stdout);
+}
+
+static void
+test_EC_P256_carry(const br_ec_impl *impl)
+{
+ test_EC_P256_carry_inner(impl,
+ "0435BAA24B2B6E1B3C88E22A383BD88CC4B9A3166E7BCF94FF6591663AE066B33B821EBA1B4FC8EA609A87EB9A9C9A1CCD5C9F42FA1365306F64D7CAA718B8C978",
+ "0447752A76CA890328D34E675C4971EC629132D1FC4863EDB61219B72C4E58DC5E9D51E7B293488CFD913C3CF20E438BB65C2BA66A7D09EABB45B55E804260C5EB");
+ test_EC_P256_carry_inner(impl,
+ "04DCAE9D9CE211223602024A6933BD42F77B6BF4EAB9C8915F058C149419FADD2CC9FC0707B270A1B5362BA4D249AFC8AC3DA1EFCA8270176EEACA525B49EE19E6",
+ "048DAC7B0BE9B3206FCE8B24B6B4AEB122F2A67D13E536B390B6585CA193427E63F222388B5F51D744D6F5D47536D89EEEC89552BCB269E7828019C4410DFE980A");
+}
+
+static void
+test_EC_KAT(const char *name, const br_ec_impl *impl, uint32_t curve_mask)
+{
+ printf("Test %s: ", name);
+ fflush(stdout);
+
+ if (curve_mask & ((uint32_t)1 << BR_EC_secp256r1)) {
+ test_EC_inner(
+ "C9AFA9D845BA75166B5C215767B1D6934E50C3DB36E89B127B8A622B120F6721",
+ "0460FED4BA255A9D31C961EB74C6356D68C049B8923B61FA6CE669622E60F29FB67903FE1008B8BC99A41AE9E95628BC64F2F1B20C2D7E9F5177A3C294D4462299",
+ impl, BR_EC_secp256r1);
+ test_EC_P256_carry(impl);
+ }
+ if (curve_mask & ((uint32_t)1 << BR_EC_secp384r1)) {
+ test_EC_inner(
+ "6B9D3DAD2E1B8C1C05B19875B6659F4DE23C3B667BF297BA9AA47740787137D896D5724E4C70A825F872C9EA60D2EDF5",
+ "04EC3A4E415B4E19A4568618029F427FA5DA9A8BC4AE92E02E06AAE5286B300C64DEF8F0EA9055866064A254515480BC138015D9B72D7D57244EA8EF9AC0C621896708A59367F9DFB9F54CA84B3F1C9DB1288B231C3AE0D4FE7344FD2533264720",
+ impl, BR_EC_secp384r1);
+ }
+ if (curve_mask & ((uint32_t)1 << BR_EC_secp521r1)) {
+ test_EC_inner(
+ "00FAD06DAA62BA3B25D2FB40133DA757205DE67F5BB0018FEE8C86E1B68C7E75CAA896EB32F1F47C70855836A6D16FCC1466F6D8FBEC67DB89EC0C08B0E996B83538",
+ "0401894550D0785932E00EAA23B694F213F8C3121F86DC97A04E5A7167DB4E5BCD371123D46E45DB6B5D5370A7F20FB633155D38FFA16D2BD761DCAC474B9A2F5023A400493101C962CD4D2FDDF782285E64584139C2F91B47F87FF82354D6630F746A28A0DB25741B5B34A828008B22ACC23F924FAAFBD4D33F81EA66956DFEAA2BFDFCF5",
+ impl, BR_EC_secp521r1);
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+static void
+test_EC_keygen(const char *name, const br_ec_impl *impl, uint32_t curves)
+{
+ int curve;
+ br_hmac_drbg_context rng;
+
+ printf("Test %s keygen: ", name);
+ fflush(stdout);
+
+ br_hmac_drbg_init(&rng, &br_sha256_vtable, "seed for EC keygen", 18);
+ br_hmac_drbg_update(&rng, name, strlen(name));
+
+ for (curve = -1; curve <= 35; curve ++) {
+ br_ec_private_key sk;
+ br_ec_public_key pk;
+ unsigned char kbuf_priv[BR_EC_KBUF_PRIV_MAX_SIZE];
+ unsigned char kbuf_pub[BR_EC_KBUF_PUB_MAX_SIZE];
+
+ if (curve < 0 || curve >= 32 || ((curves >> curve) & 1) == 0) {
+ if (br_ec_keygen(&rng.vtable, impl,
+ &sk, kbuf_priv, curve) != 0)
+ {
+ fprintf(stderr, "br_ec_keygen() did not"
+ " reject unsupported curve %d\n",
+ curve);
+ exit(EXIT_FAILURE);
+ }
+ sk.curve = curve;
+ if (br_ec_compute_pub(impl, NULL, NULL, &sk) != 0) {
+ fprintf(stderr, "br_ec_keygen() did not"
+ " reject unsupported curve %d\n",
+ curve);
+ exit(EXIT_FAILURE);
+ }
+ } else {
+ size_t len, u;
+ unsigned char tmp_priv[sizeof kbuf_priv];
+ unsigned char tmp_pub[sizeof kbuf_pub];
+ unsigned z;
+
+ len = br_ec_keygen(&rng.vtable, impl,
+ NULL, NULL, curve);
+ if (len == 0) {
+ fprintf(stderr, "br_ec_keygen() rejects"
+ " supported curve %d\n", curve);
+ exit(EXIT_FAILURE);
+ }
+ if (len > sizeof kbuf_priv) {
+ fprintf(stderr, "oversized kbuf_priv\n");
+ exit(EXIT_FAILURE);
+ }
+ memset(kbuf_priv, 0, sizeof kbuf_priv);
+ if (br_ec_keygen(&rng.vtable, impl,
+ NULL, kbuf_priv, curve) != len)
+ {
+ fprintf(stderr, "kbuf_priv length mismatch\n");
+ exit(EXIT_FAILURE);
+ }
+ z = 0;
+ for (u = 0; u < len; u ++) {
+ z |= kbuf_priv[u];
+ }
+ if (z == 0) {
+ fprintf(stderr, "kbuf_priv not initialized\n");
+ exit(EXIT_FAILURE);
+ }
+ for (u = len; u < sizeof kbuf_priv; u ++) {
+ if (kbuf_priv[u] != 0) {
+ fprintf(stderr, "kbuf_priv overflow\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+ if (br_ec_keygen(&rng.vtable, impl,
+ NULL, tmp_priv, curve) != len)
+ {
+ fprintf(stderr, "tmp_priv length mismatch\n");
+ exit(EXIT_FAILURE);
+ }
+ if (memcmp(kbuf_priv, tmp_priv, len) == 0) {
+ fprintf(stderr, "keygen stutter\n");
+ exit(EXIT_FAILURE);
+ }
+ memset(&sk, 0, sizeof sk);
+ if (br_ec_keygen(&rng.vtable, impl,
+ &sk, kbuf_priv, curve) != len)
+ {
+ fprintf(stderr,
+ "kbuf_priv length mismatch (2)\n");
+ exit(EXIT_FAILURE);
+ }
+ if (sk.curve != curve || sk.x != kbuf_priv
+ || sk.xlen != len)
+ {
+ fprintf(stderr, "sk not initialized\n");
+ exit(EXIT_FAILURE);
+ }
+
+ len = br_ec_compute_pub(impl, NULL, NULL, &sk);
+ if (len > sizeof kbuf_pub) {
+ fprintf(stderr, "oversized kbuf_pub\n");
+ exit(EXIT_FAILURE);
+ }
+ memset(kbuf_pub, 0, sizeof kbuf_pub);
+ if (br_ec_compute_pub(impl, NULL,
+ kbuf_pub, &sk) != len)
+ {
+ fprintf(stderr, "kbuf_pub length mismatch\n");
+ exit(EXIT_FAILURE);
+ }
+ for (u = len; u < sizeof kbuf_pub; u ++) {
+ if (kbuf_pub[u] != 0) {
+ fprintf(stderr, "kbuf_pub overflow\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+ memset(&pk, 0, sizeof pk);
+ if (br_ec_compute_pub(impl, &pk,
+ tmp_pub, &sk) != len)
+ {
+ fprintf(stderr, "tmp_pub length mismatch\n");
+ exit(EXIT_FAILURE);
+ }
+ if (memcmp(kbuf_pub, tmp_pub, len) != 0) {
+ fprintf(stderr, "pubkey mismatch\n");
+ exit(EXIT_FAILURE);
+ }
+ if (pk.curve != curve || pk.q != tmp_pub
+ || pk.qlen != len)
+ {
+ fprintf(stderr, "pk not initialized\n");
+ exit(EXIT_FAILURE);
+ }
+
+ if (impl->mulgen(kbuf_pub,
+ sk.x, sk.xlen, curve) != len
+ || memcmp(pk.q, kbuf_pub, len) != 0)
+ {
+ fprintf(stderr, "wrong pubkey\n");
+ exit(EXIT_FAILURE);
+ }
+ }
+ printf(".");
+ fflush(stdout);
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+static void
+test_EC_prime_i15(void)
+{
+ test_EC_KAT("EC_prime_i15", &br_ec_prime_i15,
+ (uint32_t)1 << BR_EC_secp256r1
+ | (uint32_t)1 << BR_EC_secp384r1
+ | (uint32_t)1 << BR_EC_secp521r1);
+ test_EC_keygen("EC_prime_i15", &br_ec_prime_i15,
+ (uint32_t)1 << BR_EC_secp256r1
+ | (uint32_t)1 << BR_EC_secp384r1
+ | (uint32_t)1 << BR_EC_secp521r1);
+}
+
+static void
+test_EC_prime_i31(void)
+{
+ test_EC_KAT("EC_prime_i31", &br_ec_prime_i31,
+ (uint32_t)1 << BR_EC_secp256r1
+ | (uint32_t)1 << BR_EC_secp384r1
+ | (uint32_t)1 << BR_EC_secp521r1);
+ test_EC_keygen("EC_prime_i31", &br_ec_prime_i31,
+ (uint32_t)1 << BR_EC_secp256r1
+ | (uint32_t)1 << BR_EC_secp384r1
+ | (uint32_t)1 << BR_EC_secp521r1);
+}
+
+static void
+test_EC_p256_m15(void)
+{
+ test_EC_KAT("EC_p256_m15", &br_ec_p256_m15,
+ (uint32_t)1 << BR_EC_secp256r1);
+ test_EC_keygen("EC_p256_m15", &br_ec_p256_m15,
+ (uint32_t)1 << BR_EC_secp256r1);
+}
+
+static void
+test_EC_p256_m31(void)
+{
+ test_EC_KAT("EC_p256_m31", &br_ec_p256_m31,
+ (uint32_t)1 << BR_EC_secp256r1);
+ test_EC_keygen("EC_p256_m31", &br_ec_p256_m31,
+ (uint32_t)1 << BR_EC_secp256r1);
+}
+
+static void
+test_EC_p256_m62(void)
+{
+ const br_ec_impl *ec;
+
+ ec = br_ec_p256_m62_get();
+ if (ec != NULL) {
+ test_EC_KAT("EC_p256_m62", ec,
+ (uint32_t)1 << BR_EC_secp256r1);
+ test_EC_keygen("EC_p256_m62", ec,
+ (uint32_t)1 << BR_EC_secp256r1);
+ } else {
+ printf("Test EC_p256_m62: UNAVAILABLE\n");
+ printf("Test EC_p256_m62 keygen: UNAVAILABLE\n");
+ }
+}
+
+static void
+test_EC_p256_m64(void)
+{
+ const br_ec_impl *ec;
+
+ ec = br_ec_p256_m64_get();
+ if (ec != NULL) {
+ test_EC_KAT("EC_p256_m64", ec,
+ (uint32_t)1 << BR_EC_secp256r1);
+ test_EC_keygen("EC_p256_m64", ec,
+ (uint32_t)1 << BR_EC_secp256r1);
+ } else {
+ printf("Test EC_p256_m64: UNAVAILABLE\n");
+ printf("Test EC_p256_m64 keygen: UNAVAILABLE\n");
+ }
+}
+
+const struct {
+ const char *scalar_le;
+ const char *u_in;
+ const char *u_out;
+} C25519_KAT[] = {
+ { "A546E36BF0527C9D3B16154B82465EDD62144C0AC1FC5A18506A2244BA449AC4",
+ "E6DB6867583030DB3594C1A424B15F7C726624EC26B3353B10A903A6D0AB1C4C",
+ "C3DA55379DE9C6908E94EA4DF28D084F32ECCF03491C71F754B4075577A28552" },
+ { "4B66E9D4D1B4673C5AD22691957D6AF5C11B6421E0EA01D42CA4169E7918BA0D",
+ "E5210F12786811D3F4B7959D0538AE2C31DBE7106FC03C3EFC4CD549C715A493",
+ "95CBDE9476E8907D7AADE45CB4B873F88B595A68799FA152E6F8F7647AAC7957" },
+ { 0, 0, 0 }
+};
+
+static void
+revbytes(unsigned char *buf, size_t len)
+{
+ size_t u;
+
+ for (u = 0; u < (len >> 1); u ++) {
+ unsigned t;
+
+ t = buf[u];
+ buf[u] = buf[len - 1 - u];
+ buf[len - 1 - u] = t;
+ }
+}
+
+static void
+test_EC_c25519(const char *name, const br_ec_impl *iec)
+{
+ unsigned char bu[32], bk[32], br[32];
+ size_t v;
+ int i;
+
+ printf("Test %s: ", name);
+ fflush(stdout);
+ for (v = 0; C25519_KAT[v].scalar_le; v ++) {
+ hextobin(bk, C25519_KAT[v].scalar_le);
+ revbytes(bk, sizeof bk);
+ hextobin(bu, C25519_KAT[v].u_in);
+ hextobin(br, C25519_KAT[v].u_out);
+ if (!iec->mul(bu, sizeof bu, bk, sizeof bk, BR_EC_curve25519)) {
+ fprintf(stderr, "Curve25519 multiplication failed\n");
+ exit(EXIT_FAILURE);
+ }
+ if (memcmp(bu, br, sizeof bu) != 0) {
+ fprintf(stderr, "Curve25519 failed KAT\n");
+ exit(EXIT_FAILURE);
+ }
+ printf(".");
+ fflush(stdout);
+ }
+ printf(" ");
+ fflush(stdout);
+
+ memset(bu, 0, sizeof bu);
+ bu[0] = 0x09;
+ memcpy(bk, bu, sizeof bu);
+ for (i = 1; i <= 1000; i ++) {
+ revbytes(bk, sizeof bk);
+ if (!iec->mul(bu, sizeof bu, bk, sizeof bk, BR_EC_curve25519)) {
+ fprintf(stderr, "Curve25519 multiplication failed"
+ " (iter=%d)\n", i);
+ exit(EXIT_FAILURE);
+ }
+ revbytes(bk, sizeof bk);
+ for (v = 0; v < sizeof bu; v ++) {
+ unsigned t;
+
+ t = bu[v];
+ bu[v] = bk[v];
+ bk[v] = t;
+ }
+ if (i == 1 || i == 1000) {
+ const char *sref;
+
+ sref = (i == 1)
+ ? "422C8E7A6227D7BCA1350B3E2BB7279F7897B87BB6854B783C60E80311AE3079"
+ : "684CF59BA83309552800EF566F2F4D3C1C3887C49360E3875F2EB94D99532C51";
+ hextobin(br, sref);
+ if (memcmp(bk, br, sizeof bk) != 0) {
+ fprintf(stderr,
+ "Curve25519 failed KAT (iter=%d)\n", i);
+ exit(EXIT_FAILURE);
+ }
+ }
+ if (i % 100 == 0) {
+ printf(".");
+ fflush(stdout);
+ }
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+static void
+test_EC_c25519_i15(void)
+{
+ test_EC_c25519("EC_c25519_i15", &br_ec_c25519_i15);
+ test_EC_keygen("EC_c25519_i15", &br_ec_c25519_i15,
+ (uint32_t)1 << BR_EC_curve25519);
+}
+
+static void
+test_EC_c25519_i31(void)
+{
+ test_EC_c25519("EC_c25519_i31", &br_ec_c25519_i31);
+ test_EC_keygen("EC_c25519_i31", &br_ec_c25519_i31,
+ (uint32_t)1 << BR_EC_curve25519);
+}
+
+static void
+test_EC_c25519_m15(void)
+{
+ test_EC_c25519("EC_c25519_m15", &br_ec_c25519_m15);
+ test_EC_keygen("EC_c25519_m15", &br_ec_c25519_m15,
+ (uint32_t)1 << BR_EC_curve25519);
+}
+
+static void
+test_EC_c25519_m31(void)
+{
+ test_EC_c25519("EC_c25519_m31", &br_ec_c25519_m31);
+ test_EC_keygen("EC_c25519_m31", &br_ec_c25519_m31,
+ (uint32_t)1 << BR_EC_curve25519);
+}
+
+static void
+test_EC_c25519_m62(void)
+{
+ const br_ec_impl *ec;
+
+ ec = br_ec_c25519_m62_get();
+ if (ec != NULL) {
+ test_EC_c25519("EC_c25519_m62", ec);
+ test_EC_keygen("EC_c25519_m62", ec,
+ (uint32_t)1 << BR_EC_curve25519);
+ } else {
+ printf("Test EC_c25519_m62: UNAVAILABLE\n");
+ printf("Test EC_c25519_m62 keygen: UNAVAILABLE\n");
+ }
+}
+
+static void
+test_EC_c25519_m64(void)
+{
+ const br_ec_impl *ec;
+
+ ec = br_ec_c25519_m64_get();
+ if (ec != NULL) {
+ test_EC_c25519("EC_c25519_m64", ec);
+ test_EC_keygen("EC_c25519_m64", ec,
+ (uint32_t)1 << BR_EC_curve25519);
+ } else {
+ printf("Test EC_c25519_m64: UNAVAILABLE\n");
+ printf("Test EC_c25519_m64 keygen: UNAVAILABLE\n");
+ }
+}
+
+static const unsigned char EC_P256_PUB_POINT[] = {
+ 0x04, 0x60, 0xFE, 0xD4, 0xBA, 0x25, 0x5A, 0x9D,
+ 0x31, 0xC9, 0x61, 0xEB, 0x74, 0xC6, 0x35, 0x6D,
+ 0x68, 0xC0, 0x49, 0xB8, 0x92, 0x3B, 0x61, 0xFA,
+ 0x6C, 0xE6, 0x69, 0x62, 0x2E, 0x60, 0xF2, 0x9F,
+ 0xB6, 0x79, 0x03, 0xFE, 0x10, 0x08, 0xB8, 0xBC,
+ 0x99, 0xA4, 0x1A, 0xE9, 0xE9, 0x56, 0x28, 0xBC,
+ 0x64, 0xF2, 0xF1, 0xB2, 0x0C, 0x2D, 0x7E, 0x9F,
+ 0x51, 0x77, 0xA3, 0xC2, 0x94, 0xD4, 0x46, 0x22,
+ 0x99
+};
+
+static const unsigned char EC_P256_PRIV_X[] = {
+ 0xC9, 0xAF, 0xA9, 0xD8, 0x45, 0xBA, 0x75, 0x16,
+ 0x6B, 0x5C, 0x21, 0x57, 0x67, 0xB1, 0xD6, 0x93,
+ 0x4E, 0x50, 0xC3, 0xDB, 0x36, 0xE8, 0x9B, 0x12,
+ 0x7B, 0x8A, 0x62, 0x2B, 0x12, 0x0F, 0x67, 0x21
+};
+
+static const br_ec_public_key EC_P256_PUB = {
+ BR_EC_secp256r1,
+ (unsigned char *)EC_P256_PUB_POINT, sizeof EC_P256_PUB_POINT
+};
+
+static const br_ec_private_key EC_P256_PRIV = {
+ BR_EC_secp256r1,
+ (unsigned char *)EC_P256_PRIV_X, sizeof EC_P256_PRIV_X
+};
+
+static const unsigned char EC_P384_PUB_POINT[] = {
+ 0x04, 0xEC, 0x3A, 0x4E, 0x41, 0x5B, 0x4E, 0x19,
+ 0xA4, 0x56, 0x86, 0x18, 0x02, 0x9F, 0x42, 0x7F,
+ 0xA5, 0xDA, 0x9A, 0x8B, 0xC4, 0xAE, 0x92, 0xE0,
+ 0x2E, 0x06, 0xAA, 0xE5, 0x28, 0x6B, 0x30, 0x0C,
+ 0x64, 0xDE, 0xF8, 0xF0, 0xEA, 0x90, 0x55, 0x86,
+ 0x60, 0x64, 0xA2, 0x54, 0x51, 0x54, 0x80, 0xBC,
+ 0x13, 0x80, 0x15, 0xD9, 0xB7, 0x2D, 0x7D, 0x57,
+ 0x24, 0x4E, 0xA8, 0xEF, 0x9A, 0xC0, 0xC6, 0x21,
+ 0x89, 0x67, 0x08, 0xA5, 0x93, 0x67, 0xF9, 0xDF,
+ 0xB9, 0xF5, 0x4C, 0xA8, 0x4B, 0x3F, 0x1C, 0x9D,
+ 0xB1, 0x28, 0x8B, 0x23, 0x1C, 0x3A, 0xE0, 0xD4,
+ 0xFE, 0x73, 0x44, 0xFD, 0x25, 0x33, 0x26, 0x47,
+ 0x20
+};
+
+static const unsigned char EC_P384_PRIV_X[] = {
+ 0x6B, 0x9D, 0x3D, 0xAD, 0x2E, 0x1B, 0x8C, 0x1C,
+ 0x05, 0xB1, 0x98, 0x75, 0xB6, 0x65, 0x9F, 0x4D,
+ 0xE2, 0x3C, 0x3B, 0x66, 0x7B, 0xF2, 0x97, 0xBA,
+ 0x9A, 0xA4, 0x77, 0x40, 0x78, 0x71, 0x37, 0xD8,
+ 0x96, 0xD5, 0x72, 0x4E, 0x4C, 0x70, 0xA8, 0x25,
+ 0xF8, 0x72, 0xC9, 0xEA, 0x60, 0xD2, 0xED, 0xF5
+};
+
+static const br_ec_public_key EC_P384_PUB = {
+ BR_EC_secp384r1,
+ (unsigned char *)EC_P384_PUB_POINT, sizeof EC_P384_PUB_POINT
+};
+
+static const br_ec_private_key EC_P384_PRIV = {
+ BR_EC_secp384r1,
+ (unsigned char *)EC_P384_PRIV_X, sizeof EC_P384_PRIV_X
+};
+
+static const unsigned char EC_P521_PUB_POINT[] = {
+ 0x04, 0x01, 0x89, 0x45, 0x50, 0xD0, 0x78, 0x59,
+ 0x32, 0xE0, 0x0E, 0xAA, 0x23, 0xB6, 0x94, 0xF2,
+ 0x13, 0xF8, 0xC3, 0x12, 0x1F, 0x86, 0xDC, 0x97,
+ 0xA0, 0x4E, 0x5A, 0x71, 0x67, 0xDB, 0x4E, 0x5B,
+ 0xCD, 0x37, 0x11, 0x23, 0xD4, 0x6E, 0x45, 0xDB,
+ 0x6B, 0x5D, 0x53, 0x70, 0xA7, 0xF2, 0x0F, 0xB6,
+ 0x33, 0x15, 0x5D, 0x38, 0xFF, 0xA1, 0x6D, 0x2B,
+ 0xD7, 0x61, 0xDC, 0xAC, 0x47, 0x4B, 0x9A, 0x2F,
+ 0x50, 0x23, 0xA4, 0x00, 0x49, 0x31, 0x01, 0xC9,
+ 0x62, 0xCD, 0x4D, 0x2F, 0xDD, 0xF7, 0x82, 0x28,
+ 0x5E, 0x64, 0x58, 0x41, 0x39, 0xC2, 0xF9, 0x1B,
+ 0x47, 0xF8, 0x7F, 0xF8, 0x23, 0x54, 0xD6, 0x63,
+ 0x0F, 0x74, 0x6A, 0x28, 0xA0, 0xDB, 0x25, 0x74,
+ 0x1B, 0x5B, 0x34, 0xA8, 0x28, 0x00, 0x8B, 0x22,
+ 0xAC, 0xC2, 0x3F, 0x92, 0x4F, 0xAA, 0xFB, 0xD4,
+ 0xD3, 0x3F, 0x81, 0xEA, 0x66, 0x95, 0x6D, 0xFE,
+ 0xAA, 0x2B, 0xFD, 0xFC, 0xF5
+};
+
+static const unsigned char EC_P521_PRIV_X[] = {
+ 0x00, 0xFA, 0xD0, 0x6D, 0xAA, 0x62, 0xBA, 0x3B,
+ 0x25, 0xD2, 0xFB, 0x40, 0x13, 0x3D, 0xA7, 0x57,
+ 0x20, 0x5D, 0xE6, 0x7F, 0x5B, 0xB0, 0x01, 0x8F,
+ 0xEE, 0x8C, 0x86, 0xE1, 0xB6, 0x8C, 0x7E, 0x75,
+ 0xCA, 0xA8, 0x96, 0xEB, 0x32, 0xF1, 0xF4, 0x7C,
+ 0x70, 0x85, 0x58, 0x36, 0xA6, 0xD1, 0x6F, 0xCC,
+ 0x14, 0x66, 0xF6, 0xD8, 0xFB, 0xEC, 0x67, 0xDB,
+ 0x89, 0xEC, 0x0C, 0x08, 0xB0, 0xE9, 0x96, 0xB8,
+ 0x35, 0x38
+};
+
+static const br_ec_public_key EC_P521_PUB = {
+ BR_EC_secp521r1,
+ (unsigned char *)EC_P521_PUB_POINT, sizeof EC_P521_PUB_POINT
+};
+
+static const br_ec_private_key EC_P521_PRIV = {
+ BR_EC_secp521r1,
+ (unsigned char *)EC_P521_PRIV_X, sizeof EC_P521_PRIV_X
+};
+
+typedef struct {
+ const br_ec_public_key *pub;
+ const br_ec_private_key *priv;
+ const br_hash_class *hf;
+ const char *msg;
+ const char *sk;
+ const char *sraw;
+ const char *sasn1;
+} ecdsa_kat_vector;
+
+const ecdsa_kat_vector ECDSA_KAT[] = {
+
+ /* Test vectors for P-256, from RFC 6979. */
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha1_vtable, "sample",
+ "882905F1227FD620FBF2ABF21244F0BA83D0DC3A9103DBBEE43A1FB858109DB4",
+ "61340C88C3AAEBEB4F6D667F672CA9759A6CCAA9FA8811313039EE4A35471D326D7F147DAC089441BB2E2FE8F7A3FA264B9C475098FDCF6E00D7C996E1B8B7EB",
+ "3044022061340C88C3AAEBEB4F6D667F672CA9759A6CCAA9FA8811313039EE4A35471D3202206D7F147DAC089441BB2E2FE8F7A3FA264B9C475098FDCF6E00D7C996E1B8B7EB"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha224_vtable, "sample",
+ "103F90EE9DC52E5E7FB5132B7033C63066D194321491862059967C715985D473",
+ "53B2FFF5D1752B2C689DF257C04C40A587FABABB3F6FC2702F1343AF7CA9AA3FB9AFB64FDC03DC1A131C7D2386D11E349F070AA432A4ACC918BEA988BF75C74C",
+ "3045022053B2FFF5D1752B2C689DF257C04C40A587FABABB3F6FC2702F1343AF7CA9AA3F022100B9AFB64FDC03DC1A131C7D2386D11E349F070AA432A4ACC918BEA988BF75C74C"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha256_vtable, "sample",
+ "A6E3C57DD01ABE90086538398355DD4C3B17AA873382B0F24D6129493D8AAD60",
+ "EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8",
+ "3046022100EFD48B2AACB6A8FD1140DD9CD45E81D69D2C877B56AAF991C34D0EA84EAF3716022100F7CB1C942D657C41D436C7A1B6E29F65F3E900DBB9AFF4064DC4AB2F843ACDA8"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha384_vtable, "sample",
+ "09F634B188CEFD98E7EC88B1AA9852D734D0BC272F7D2A47DECC6EBEB375AAD4",
+ "0EAFEA039B20E9B42309FB1D89E213057CBF973DC0CFC8F129EDDDC800EF77194861F0491E6998B9455193E34E7B0D284DDD7149A74B95B9261F13ABDE940954",
+ "304402200EAFEA039B20E9B42309FB1D89E213057CBF973DC0CFC8F129EDDDC800EF771902204861F0491E6998B9455193E34E7B0D284DDD7149A74B95B9261F13ABDE940954"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha512_vtable, "sample",
+ "5FA81C63109BADB88C1F367B47DA606DA28CAD69AA22C4FE6AD7DF73A7173AA5",
+ "8496A60B5E9B47C825488827E0495B0E3FA109EC4568FD3F8D1097678EB97F002362AB1ADBE2B8ADF9CB9EDAB740EA6049C028114F2460F96554F61FAE3302FE",
+ "30450221008496A60B5E9B47C825488827E0495B0E3FA109EC4568FD3F8D1097678EB97F0002202362AB1ADBE2B8ADF9CB9EDAB740EA6049C028114F2460F96554F61FAE3302FE"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha1_vtable, "test",
+ "8C9520267C55D6B980DF741E56B4ADEE114D84FBFA2E62137954164028632A2E",
+ "0CBCC86FD6ABD1D99E703E1EC50069EE5C0B4BA4B9AC60E409E8EC5910D81A8901B9D7B73DFAA60D5651EC4591A0136F87653E0FD780C3B1BC872FFDEAE479B1",
+ "304402200CBCC86FD6ABD1D99E703E1EC50069EE5C0B4BA4B9AC60E409E8EC5910D81A89022001B9D7B73DFAA60D5651EC4591A0136F87653E0FD780C3B1BC872FFDEAE479B1"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha224_vtable, "test",
+ "669F4426F2688B8BE0DB3A6BD1989BDAEFFF84B649EEB84F3DD26080F667FAA7",
+ "C37EDB6F0AE79D47C3C27E962FA269BB4F441770357E114EE511F662EC34A692C820053A05791E521FCAAD6042D40AEA1D6B1A540138558F47D0719800E18F2D",
+ "3046022100C37EDB6F0AE79D47C3C27E962FA269BB4F441770357E114EE511F662EC34A692022100C820053A05791E521FCAAD6042D40AEA1D6B1A540138558F47D0719800E18F2D"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha256_vtable, "test",
+ "D16B6AE827F17175E040871A1C7EC3500192C4C92677336EC2537ACAEE0008E0",
+ "F1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D38367019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083",
+ "3045022100F1ABB023518351CD71D881567B1EA663ED3EFCF6C5132B354F28D3B0B7D383670220019F4113742A2B14BD25926B49C649155F267E60D3814B4C0CC84250E46F0083"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha384_vtable, "test",
+ "16AEFFA357260B04B1DD199693960740066C1A8F3E8EDD79070AA914D361B3B8",
+ "83910E8B48BB0C74244EBDF7F07A1C5413D61472BD941EF3920E623FBCCEBEB68DDBEC54CF8CD5874883841D712142A56A8D0F218F5003CB0296B6B509619F2C",
+ "304602210083910E8B48BB0C74244EBDF7F07A1C5413D61472BD941EF3920E623FBCCEBEB60221008DDBEC54CF8CD5874883841D712142A56A8D0F218F5003CB0296B6B509619F2C"
+ },
+ {
+ &EC_P256_PUB,
+ &EC_P256_PRIV,
+ &br_sha512_vtable, "test",
+ "6915D11632ACA3C40D5D51C08DAF9C555933819548784480E93499000D9F0B7F",
+ "461D93F31B6540894788FD206C07CFA0CC35F46FA3C91816FFF1040AD1581A0439AF9F15DE0DB8D97E72719C74820D304CE5226E32DEDAE67519E840D1194E55",
+ "30440220461D93F31B6540894788FD206C07CFA0CC35F46FA3C91816FFF1040AD1581A04022039AF9F15DE0DB8D97E72719C74820D304CE5226E32DEDAE67519E840D1194E55"
+ },
+
+ /* Test vectors for P-384, from RFC 6979. */
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha1_vtable, "sample",
+ "4471EF7518BB2C7C20F62EAE1C387AD0C5E8E470995DB4ACF694466E6AB096630F29E5938D25106C3C340045A2DB01A7",
+ "EC748D839243D6FBEF4FC5C4859A7DFFD7F3ABDDF72014540C16D73309834FA37B9BA002899F6FDA3A4A9386790D4EB2A3BCFA947BEEF4732BF247AC17F71676CB31A847B9FF0CBC9C9ED4C1A5B3FACF26F49CA031D4857570CCB5CA4424A443",
+ "3066023100EC748D839243D6FBEF4FC5C4859A7DFFD7F3ABDDF72014540C16D73309834FA37B9BA002899F6FDA3A4A9386790D4EB2023100A3BCFA947BEEF4732BF247AC17F71676CB31A847B9FF0CBC9C9ED4C1A5B3FACF26F49CA031D4857570CCB5CA4424A443"
+ },
+
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha224_vtable, "sample",
+ "A4E4D2F0E729EB786B31FC20AD5D849E304450E0AE8E3E341134A5C1AFA03CAB8083EE4E3C45B06A5899EA56C51B5879",
+ "42356E76B55A6D9B4631C865445DBE54E056D3B3431766D0509244793C3F9366450F76EE3DE43F5A125333A6BE0601229DA0C81787064021E78DF658F2FBB0B042BF304665DB721F077A4298B095E4834C082C03D83028EFBF93A3C23940CA8D",
+ "3065023042356E76B55A6D9B4631C865445DBE54E056D3B3431766D0509244793C3F9366450F76EE3DE43F5A125333A6BE0601220231009DA0C81787064021E78DF658F2FBB0B042BF304665DB721F077A4298B095E4834C082C03D83028EFBF93A3C23940CA8D"
+ },
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha256_vtable, "sample",
+ "180AE9F9AEC5438A44BC159A1FCB277C7BE54FA20E7CF404B490650A8ACC414E375572342863C899F9F2EDF9747A9B60",
+ "21B13D1E013C7FA1392D03C5F99AF8B30C570C6F98D4EA8E354B63A21D3DAA33BDE1E888E63355D92FA2B3C36D8FB2CDF3AA443FB107745BF4BD77CB3891674632068A10CA67E3D45DB2266FA7D1FEEBEFDC63ECCD1AC42EC0CB8668A4FA0AB0",
+ "3065023021B13D1E013C7FA1392D03C5F99AF8B30C570C6F98D4EA8E354B63A21D3DAA33BDE1E888E63355D92FA2B3C36D8FB2CD023100F3AA443FB107745BF4BD77CB3891674632068A10CA67E3D45DB2266FA7D1FEEBEFDC63ECCD1AC42EC0CB8668A4FA0AB0"
+ },
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha384_vtable, "sample",
+ "94ED910D1A099DAD3254E9242AE85ABDE4BA15168EAF0CA87A555FD56D10FBCA2907E3E83BA95368623B8C4686915CF9",
+ "94EDBB92A5ECB8AAD4736E56C691916B3F88140666CE9FA73D64C4EA95AD133C81A648152E44ACF96E36DD1E80FABE4699EF4AEB15F178CEA1FE40DB2603138F130E740A19624526203B6351D0A3A94FA329C145786E679E7B82C71A38628AC8",
+ "306602310094EDBB92A5ECB8AAD4736E56C691916B3F88140666CE9FA73D64C4EA95AD133C81A648152E44ACF96E36DD1E80FABE4602310099EF4AEB15F178CEA1FE40DB2603138F130E740A19624526203B6351D0A3A94FA329C145786E679E7B82C71A38628AC8"
+ },
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha512_vtable, "sample",
+ "92FC3C7183A883E24216D1141F1A8976C5B0DD797DFA597E3D7B32198BD35331A4E966532593A52980D0E3AAA5E10EC3",
+ "ED0959D5880AB2D869AE7F6C2915C6D60F96507F9CB3E047C0046861DA4A799CFE30F35CC900056D7C99CD7882433709512C8CCEEE3890A84058CE1E22DBC2198F42323CE8ACA9135329F03C068E5112DC7CC3EF3446DEFCEB01A45C2667FDD5",
+ "3065023100ED0959D5880AB2D869AE7F6C2915C6D60F96507F9CB3E047C0046861DA4A799CFE30F35CC900056D7C99CD78824337090230512C8CCEEE3890A84058CE1E22DBC2198F42323CE8ACA9135329F03C068E5112DC7CC3EF3446DEFCEB01A45C2667FDD5"
+ },
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha1_vtable, "test",
+ "66CC2C8F4D303FC962E5FF6A27BD79F84EC812DDAE58CF5243B64A4AD8094D47EC3727F3A3C186C15054492E30698497",
+ "4BC35D3A50EF4E30576F58CD96CE6BF638025EE624004A1F7789A8B8E43D0678ACD9D29876DAF46638645F7F404B11C7D5A6326C494ED3FF614703878961C0FDE7B2C278F9A65FD8C4B7186201A2991695BA1C84541327E966FA7B50F7382282",
+ "306502304BC35D3A50EF4E30576F58CD96CE6BF638025EE624004A1F7789A8B8E43D0678ACD9D29876DAF46638645F7F404B11C7023100D5A6326C494ED3FF614703878961C0FDE7B2C278F9A65FD8C4B7186201A2991695BA1C84541327E966FA7B50F7382282"
+ },
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha224_vtable, "test",
+ "18FA39DB95AA5F561F30FA3591DC59C0FA3653A80DAFFA0B48D1A4C6DFCBFF6E3D33BE4DC5EB8886A8ECD093F2935726",
+ "E8C9D0B6EA72A0E7837FEA1D14A1A9557F29FAA45D3E7EE888FC5BF954B5E62464A9A817C47FF78B8C11066B24080E7207041D4A7A0379AC7232FF72E6F77B6DDB8F09B16CCE0EC3286B2BD43FA8C6141C53EA5ABEF0D8231077A04540A96B66",
+ "3065023100E8C9D0B6EA72A0E7837FEA1D14A1A9557F29FAA45D3E7EE888FC5BF954B5E62464A9A817C47FF78B8C11066B24080E72023007041D4A7A0379AC7232FF72E6F77B6DDB8F09B16CCE0EC3286B2BD43FA8C6141C53EA5ABEF0D8231077A04540A96B66"
+ },
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha256_vtable, "test",
+ "0CFAC37587532347DC3389FDC98286BBA8C73807285B184C83E62E26C401C0FAA48DD070BA79921A3457ABFF2D630AD7",
+ "6D6DEFAC9AB64DABAFE36C6BF510352A4CC27001263638E5B16D9BB51D451559F918EEDAF2293BE5B475CC8F0188636B2D46F3BECBCC523D5F1A1256BF0C9B024D879BA9E838144C8BA6BAEB4B53B47D51AB373F9845C0514EEFB14024787265",
+ "306402306D6DEFAC9AB64DABAFE36C6BF510352A4CC27001263638E5B16D9BB51D451559F918EEDAF2293BE5B475CC8F0188636B02302D46F3BECBCC523D5F1A1256BF0C9B024D879BA9E838144C8BA6BAEB4B53B47D51AB373F9845C0514EEFB14024787265"
+ },
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha384_vtable, "test",
+ "015EE46A5BF88773ED9123A5AB0807962D193719503C527B031B4C2D225092ADA71F4A459BC0DA98ADB95837DB8312EA",
+ "8203B63D3C853E8D77227FB377BCF7B7B772E97892A80F36AB775D509D7A5FEB0542A7F0812998DA8F1DD3CA3CF023DBDDD0760448D42D8A43AF45AF836FCE4DE8BE06B485E9B61B827C2F13173923E06A739F040649A667BF3B828246BAA5A5",
+ "30660231008203B63D3C853E8D77227FB377BCF7B7B772E97892A80F36AB775D509D7A5FEB0542A7F0812998DA8F1DD3CA3CF023DB023100DDD0760448D42D8A43AF45AF836FCE4DE8BE06B485E9B61B827C2F13173923E06A739F040649A667BF3B828246BAA5A5"
+ },
+ {
+ &EC_P384_PUB,
+ &EC_P384_PRIV,
+ &br_sha512_vtable, "test",
+ "3780C4F67CB15518B6ACAE34C9F83568D2E12E47DEAB6C50A4E4EE5319D1E8CE0E2CC8A136036DC4B9C00E6888F66B6C",
+ "A0D5D090C9980FAF3C2CE57B7AE951D31977DD11C775D314AF55F76C676447D06FB6495CD21B4B6E340FC236584FB277976984E59B4C77B0E8E4460DCA3D9F20E07B9BB1F63BEEFAF576F6B2E8B224634A2092CD3792E0159AD9CEE37659C736",
+ "3066023100A0D5D090C9980FAF3C2CE57B7AE951D31977DD11C775D314AF55F76C676447D06FB6495CD21B4B6E340FC236584FB277023100976984E59B4C77B0E8E4460DCA3D9F20E07B9BB1F63BEEFAF576F6B2E8B224634A2092CD3792E0159AD9CEE37659C736"
+ },
+
+ /* Test vectors for P-521, from RFC 6979. */
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha1_vtable, "sample",
+ "0089C071B419E1C2820962321787258469511958E80582E95D8378E0C2CCDB3CB42BEDE42F50E3FA3C71F5A76724281D31D9C89F0F91FC1BE4918DB1C03A5838D0F9",
+ "00343B6EC45728975EA5CBA6659BBB6062A5FF89EEA58BE3C80B619F322C87910FE092F7D45BB0F8EEE01ED3F20BABEC079D202AE677B243AB40B5431D497C55D75D00E7B0E675A9B24413D448B8CC119D2BF7B2D2DF032741C096634D6D65D0DBE3D5694625FB9E8104D3B842C1B0E2D0B98BEA19341E8676AEF66AE4EBA3D5475D5D16",
+ "3081870241343B6EC45728975EA5CBA6659BBB6062A5FF89EEA58BE3C80B619F322C87910FE092F7D45BB0F8EEE01ED3F20BABEC079D202AE677B243AB40B5431D497C55D75D024200E7B0E675A9B24413D448B8CC119D2BF7B2D2DF032741C096634D6D65D0DBE3D5694625FB9E8104D3B842C1B0E2D0B98BEA19341E8676AEF66AE4EBA3D5475D5D16"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha224_vtable, "sample",
+ "0121415EC2CD7726330A61F7F3FA5DE14BE9436019C4DB8CB4041F3B54CF31BE0493EE3F427FB906393D895A19C9523F3A1D54BB8702BD4AA9C99DAB2597B92113F3",
+ "01776331CFCDF927D666E032E00CF776187BC9FDD8E69D0DABB4109FFE1B5E2A30715F4CC923A4A5E94D2503E9ACFED92857B7F31D7152E0F8C00C15FF3D87E2ED2E0050CB5265417FE2320BBB5A122B8E1A32BD699089851128E360E620A30C7E17BA41A666AF126CE100E5799B153B60528D5300D08489CA9178FB610A2006C254B41F",
+ "308187024201776331CFCDF927D666E032E00CF776187BC9FDD8E69D0DABB4109FFE1B5E2A30715F4CC923A4A5E94D2503E9ACFED92857B7F31D7152E0F8C00C15FF3D87E2ED2E024150CB5265417FE2320BBB5A122B8E1A32BD699089851128E360E620A30C7E17BA41A666AF126CE100E5799B153B60528D5300D08489CA9178FB610A2006C254B41F"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha256_vtable, "sample",
+ "00EDF38AFCAAECAB4383358B34D67C9F2216C8382AAEA44A3DAD5FDC9C32575761793FEF24EB0FC276DFC4F6E3EC476752F043CF01415387470BCBD8678ED2C7E1A0",
+ "01511BB4D675114FE266FC4372B87682BAECC01D3CC62CF2303C92B3526012659D16876E25C7C1E57648F23B73564D67F61C6F14D527D54972810421E7D87589E1A7004A171143A83163D6DF460AAF61522695F207A58B95C0644D87E52AA1A347916E4F7A72930B1BC06DBE22CE3F58264AFD23704CBB63B29B931F7DE6C9D949A7ECFC",
+ "308187024201511BB4D675114FE266FC4372B87682BAECC01D3CC62CF2303C92B3526012659D16876E25C7C1E57648F23B73564D67F61C6F14D527D54972810421E7D87589E1A702414A171143A83163D6DF460AAF61522695F207A58B95C0644D87E52AA1A347916E4F7A72930B1BC06DBE22CE3F58264AFD23704CBB63B29B931F7DE6C9D949A7ECFC"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha384_vtable, "sample",
+ "01546A108BC23A15D6F21872F7DED661FA8431DDBD922D0DCDB77CC878C8553FFAD064C95A920A750AC9137E527390D2D92F153E66196966EA554D9ADFCB109C4211",
+ "01EA842A0E17D2DE4F92C15315C63DDF72685C18195C2BB95E572B9C5136CA4B4B576AD712A52BE9730627D16054BA40CC0B8D3FF035B12AE75168397F5D50C6745101F21A3CEE066E1961025FB048BD5FE2B7924D0CD797BABE0A83B66F1E35EEAF5FDE143FA85DC394A7DEE766523393784484BDF3E00114A1C857CDE1AA203DB65D61",
+ "308188024201EA842A0E17D2DE4F92C15315C63DDF72685C18195C2BB95E572B9C5136CA4B4B576AD712A52BE9730627D16054BA40CC0B8D3FF035B12AE75168397F5D50C67451024201F21A3CEE066E1961025FB048BD5FE2B7924D0CD797BABE0A83B66F1E35EEAF5FDE143FA85DC394A7DEE766523393784484BDF3E00114A1C857CDE1AA203DB65D61"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha512_vtable, "sample",
+ "01DAE2EA071F8110DC26882D4D5EAE0621A3256FC8847FB9022E2B7D28E6F10198B1574FDD03A9053C08A1854A168AA5A57470EC97DD5CE090124EF52A2F7ECBFFD3",
+ "00C328FAFCBD79DD77850370C46325D987CB525569FB63C5D3BC53950E6D4C5F174E25A1EE9017B5D450606ADD152B534931D7D4E8455CC91F9B15BF05EC36E377FA00617CCE7CF5064806C467F678D3B4080D6F1CC50AF26CA209417308281B68AF282623EAA63E5B5C0723D8B8C37FF0777B1A20F8CCB1DCCC43997F1EE0E44DA4A67A",
+ "308187024200C328FAFCBD79DD77850370C46325D987CB525569FB63C5D3BC53950E6D4C5F174E25A1EE9017B5D450606ADD152B534931D7D4E8455CC91F9B15BF05EC36E377FA0241617CCE7CF5064806C467F678D3B4080D6F1CC50AF26CA209417308281B68AF282623EAA63E5B5C0723D8B8C37FF0777B1A20F8CCB1DCCC43997F1EE0E44DA4A67A"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha1_vtable, "test",
+ "00BB9F2BF4FE1038CCF4DABD7139A56F6FD8BB1386561BD3C6A4FC818B20DF5DDBA80795A947107A1AB9D12DAA615B1ADE4F7A9DC05E8E6311150F47F5C57CE8B222",
+ "013BAD9F29ABE20DE37EBEB823C252CA0F63361284015A3BF430A46AAA80B87B0693F0694BD88AFE4E661FC33B094CD3B7963BED5A727ED8BD6A3A202ABE009D036701E9BB81FF7944CA409AD138DBBEE228E1AFCC0C890FC78EC8604639CB0DBDC90F717A99EAD9D272855D00162EE9527567DD6A92CBD629805C0445282BBC916797FF",
+ "3081880242013BAD9F29ABE20DE37EBEB823C252CA0F63361284015A3BF430A46AAA80B87B0693F0694BD88AFE4E661FC33B094CD3B7963BED5A727ED8BD6A3A202ABE009D0367024201E9BB81FF7944CA409AD138DBBEE228E1AFCC0C890FC78EC8604639CB0DBDC90F717A99EAD9D272855D00162EE9527567DD6A92CBD629805C0445282BBC916797FF"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha224_vtable, "test",
+ "0040D09FCF3C8A5F62CF4FB223CBBB2B9937F6B0577C27020A99602C25A01136987E452988781484EDBBCF1C47E554E7FC901BC3085E5206D9F619CFF07E73D6F706",
+ "01C7ED902E123E6815546065A2C4AF977B22AA8EADDB68B2C1110E7EA44D42086BFE4A34B67DDC0E17E96536E358219B23A706C6A6E16BA77B65E1C595D43CAE17FB0177336676304FCB343CE028B38E7B4FBA76C1C1B277DA18CAD2A8478B2A9A9F5BEC0F3BA04F35DB3E4263569EC6AADE8C92746E4C82F8299AE1B8F1739F8FD519A4",
+ "308188024201C7ED902E123E6815546065A2C4AF977B22AA8EADDB68B2C1110E7EA44D42086BFE4A34B67DDC0E17E96536E358219B23A706C6A6E16BA77B65E1C595D43CAE17FB02420177336676304FCB343CE028B38E7B4FBA76C1C1B277DA18CAD2A8478B2A9A9F5BEC0F3BA04F35DB3E4263569EC6AADE8C92746E4C82F8299AE1B8F1739F8FD519A4"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha256_vtable, "test",
+ "001DE74955EFAABC4C4F17F8E84D881D1310B5392D7700275F82F145C61E843841AF09035BF7A6210F5A431A6A9E81C9323354A9E69135D44EBD2FCAA7731B909258",
+ "000E871C4A14F993C6C7369501900C4BC1E9C7B0B4BA44E04868B30B41D8071042EB28C4C250411D0CE08CD197E4188EA4876F279F90B3D8D74A3C76E6F1E4656AA800CD52DBAA33B063C3A6CD8058A1FB0A46A4754B034FCC644766CA14DA8CA5CA9FDE00E88C1AD60CCBA759025299079D7A427EC3CC5B619BFBC828E7769BCD694E86",
+ "30818702410E871C4A14F993C6C7369501900C4BC1E9C7B0B4BA44E04868B30B41D8071042EB28C4C250411D0CE08CD197E4188EA4876F279F90B3D8D74A3C76E6F1E4656AA8024200CD52DBAA33B063C3A6CD8058A1FB0A46A4754B034FCC644766CA14DA8CA5CA9FDE00E88C1AD60CCBA759025299079D7A427EC3CC5B619BFBC828E7769BCD694E86"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha384_vtable, "test",
+ "01F1FC4A349A7DA9A9E116BFDD055DC08E78252FF8E23AC276AC88B1770AE0B5DCEB1ED14A4916B769A523CE1E90BA22846AF11DF8B300C38818F713DADD85DE0C88",
+ "014BEE21A18B6D8B3C93FAB08D43E739707953244FDBE924FA926D76669E7AC8C89DF62ED8975C2D8397A65A49DCC09F6B0AC62272741924D479354D74FF6075578C0133330865C067A0EAF72362A65E2D7BC4E461E8C8995C3B6226A21BD1AA78F0ED94FE536A0DCA35534F0CD1510C41525D163FE9D74D134881E35141ED5E8E95B979",
+ "3081880242014BEE21A18B6D8B3C93FAB08D43E739707953244FDBE924FA926D76669E7AC8C89DF62ED8975C2D8397A65A49DCC09F6B0AC62272741924D479354D74FF6075578C02420133330865C067A0EAF72362A65E2D7BC4E461E8C8995C3B6226A21BD1AA78F0ED94FE536A0DCA35534F0CD1510C41525D163FE9D74D134881E35141ED5E8E95B979"
+ },
+ {
+ &EC_P521_PUB,
+ &EC_P521_PRIV,
+ &br_sha512_vtable, "test",
+ "016200813020EC986863BEDFC1B121F605C1215645018AEA1A7B215A564DE9EB1B38A67AA1128B80CE391C4FB71187654AAA3431027BFC7F395766CA988C964DC56D",
+ "013E99020ABF5CEE7525D16B69B229652AB6BDF2AFFCAEF38773B4B7D08725F10CDB93482FDCC54EDCEE91ECA4166B2A7C6265EF0CE2BD7051B7CEF945BABD47EE6D01FBD0013C674AA79CB39849527916CE301C66EA7CE8B80682786AD60F98F7E78A19CA69EFF5C57400E3B3A0AD66CE0978214D13BAF4E9AC60752F7B155E2DE4DCE3",
+ "3081880242013E99020ABF5CEE7525D16B69B229652AB6BDF2AFFCAEF38773B4B7D08725F10CDB93482FDCC54EDCEE91ECA4166B2A7C6265EF0CE2BD7051B7CEF945BABD47EE6D024201FBD0013C674AA79CB39849527916CE301C66EA7CE8B80682786AD60F98F7E78A19CA69EFF5C57400E3B3A0AD66CE0978214D13BAF4E9AC60752F7B155E2DE4DCE3"
+ },
+
+ /* Terminator for list of test vectors. */
+ {
+ 0, 0, 0, 0, 0, 0, 0
+ }
+};
+
+static void
+test_ECDSA_KAT(const br_ec_impl *iec,
+ br_ecdsa_sign sign, br_ecdsa_vrfy vrfy, int asn1)
+{
+ size_t u;
+
+ for (u = 0;; u ++) {
+ const ecdsa_kat_vector *kv;
+ unsigned char hash[64];
+ size_t hash_len;
+ unsigned char sig[150], sig2[150];
+ size_t sig_len, sig2_len;
+ br_hash_compat_context hc;
+
+ kv = &ECDSA_KAT[u];
+ if (kv->pub == 0) {
+ break;
+ }
+ kv->hf->init(&hc.vtable);
+ kv->hf->update(&hc.vtable, kv->msg, strlen(kv->msg));
+ kv->hf->out(&hc.vtable, hash);
+ hash_len = (kv->hf->desc >> BR_HASHDESC_OUT_OFF)
+ & BR_HASHDESC_OUT_MASK;
+ if (asn1) {
+ sig_len = hextobin(sig, kv->sasn1);
+ } else {
+ sig_len = hextobin(sig, kv->sraw);
+ }
+
+ if (vrfy(iec, hash, hash_len,
+ kv->pub, sig, sig_len) != 1)
+ {
+ fprintf(stderr, "ECDSA KAT verify failed (1)\n");
+ exit(EXIT_FAILURE);
+ }
+ hash[0] ^= 0x80;
+ if (vrfy(iec, hash, hash_len,
+ kv->pub, sig, sig_len) != 0)
+ {
+ fprintf(stderr, "ECDSA KAT verify shoud have failed\n");
+ exit(EXIT_FAILURE);
+ }
+ hash[0] ^= 0x80;
+ if (vrfy(iec, hash, hash_len,
+ kv->pub, sig, sig_len) != 1)
+ {
+ fprintf(stderr, "ECDSA KAT verify failed (2)\n");
+ exit(EXIT_FAILURE);
+ }
+
+ sig2_len = sign(iec, kv->hf, hash, kv->priv, sig2);
+ if (sig2_len == 0) {
+ fprintf(stderr, "ECDSA KAT sign failed\n");
+ exit(EXIT_FAILURE);
+ }
+ if (sig2_len != sig_len || memcmp(sig, sig2, sig_len) != 0) {
+ fprintf(stderr, "ECDSA KAT wrong signature value\n");
+ exit(EXIT_FAILURE);
+ }
+
+ printf(".");
+ fflush(stdout);
+ }
+}
+
+static void
+test_ECDSA_i31(void)
+{
+ printf("Test ECDSA/i31: ");
+ fflush(stdout);
+ printf("[raw]");
+ fflush(stdout);
+ test_ECDSA_KAT(&br_ec_prime_i31,
+ &br_ecdsa_i31_sign_raw, &br_ecdsa_i31_vrfy_raw, 0);
+ printf(" [asn1]");
+ fflush(stdout);
+ test_ECDSA_KAT(&br_ec_prime_i31,
+ &br_ecdsa_i31_sign_asn1, &br_ecdsa_i31_vrfy_asn1, 1);
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+static void
+test_ECDSA_i15(void)
+{
+ printf("Test ECDSA/i15: ");
+ fflush(stdout);
+ printf("[raw]");
+ fflush(stdout);
+ test_ECDSA_KAT(&br_ec_prime_i15,
+ &br_ecdsa_i15_sign_raw, &br_ecdsa_i15_vrfy_raw, 0);
+ printf(" [asn1]");
+ fflush(stdout);
+ test_ECDSA_KAT(&br_ec_prime_i31,
+ &br_ecdsa_i15_sign_asn1, &br_ecdsa_i15_vrfy_asn1, 1);
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+static void
+test_modpow_i31(void)
+{
+ br_hmac_drbg_context hc;
+ int k;
+
+ printf("Test ModPow/i31: ");
+
+ br_hmac_drbg_init(&hc, &br_sha256_vtable, "seed modpow", 11);
+ for (k = 10; k <= 500; k ++) {
+ size_t blen;
+ unsigned char bm[128], bx[128], bx1[128], bx2[128];
+ unsigned char be[128];
+ unsigned mask;
+ uint32_t x1[35], m1[35];
+ uint16_t x2[70], m2[70];
+ uint32_t tmp1[1000];
+ uint16_t tmp2[2000];
+
+ blen = (k + 7) >> 3;
+ br_hmac_drbg_generate(&hc, bm, blen);
+ br_hmac_drbg_generate(&hc, bx, blen);
+ br_hmac_drbg_generate(&hc, be, blen);
+ bm[blen - 1] |= 0x01;
+ mask = 0xFF >> ((int)(blen << 3) - k);
+ bm[0] &= mask;
+ bm[0] |= (mask - (mask >> 1));
+ bx[0] &= (mask >> 1);
+
+ br_i31_decode(m1, bm, blen);
+ br_i31_decode_mod(x1, bx, blen, m1);
+ br_i31_modpow_opt(x1, be, blen, m1, br_i31_ninv31(m1[1]),
+ tmp1, (sizeof tmp1) / (sizeof tmp1[0]));
+ br_i31_encode(bx1, blen, x1);
+
+ br_i15_decode(m2, bm, blen);
+ br_i15_decode_mod(x2, bx, blen, m2);
+ br_i15_modpow_opt(x2, be, blen, m2, br_i15_ninv15(m2[1]),
+ tmp2, (sizeof tmp2) / (sizeof tmp2[0]));
+ br_i15_encode(bx2, blen, x2);
+
+ check_equals("ModPow i31/i15", bx1, bx2, blen);
+
+ printf(".");
+ fflush(stdout);
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+static void
+test_modpow_i62(void)
+{
+ br_hmac_drbg_context hc;
+ int k;
+
+ printf("Test ModPow/i62: ");
+
+ br_hmac_drbg_init(&hc, &br_sha256_vtable, "seed modpow", 11);
+ for (k = 10; k <= 500; k ++) {
+ size_t blen;
+ unsigned char bm[128], bx[128], bx1[128], bx2[128];
+ unsigned char be[128];
+ unsigned mask;
+ uint32_t x1[35], m1[35];
+ uint16_t x2[70], m2[70];
+ uint64_t tmp1[500];
+ uint16_t tmp2[2000];
+
+ blen = (k + 7) >> 3;
+ br_hmac_drbg_generate(&hc, bm, blen);
+ br_hmac_drbg_generate(&hc, bx, blen);
+ br_hmac_drbg_generate(&hc, be, blen);
+ bm[blen - 1] |= 0x01;
+ mask = 0xFF >> ((int)(blen << 3) - k);
+ bm[0] &= mask;
+ bm[0] |= (mask - (mask >> 1));
+ bx[0] &= (mask >> 1);
+
+ br_i31_decode(m1, bm, blen);
+ br_i31_decode_mod(x1, bx, blen, m1);
+ br_i62_modpow_opt(x1, be, blen, m1, br_i31_ninv31(m1[1]),
+ tmp1, (sizeof tmp1) / (sizeof tmp1[0]));
+ br_i31_encode(bx1, blen, x1);
+
+ br_i15_decode(m2, bm, blen);
+ br_i15_decode_mod(x2, bx, blen, m2);
+ br_i15_modpow_opt(x2, be, blen, m2, br_i15_ninv15(m2[1]),
+ tmp2, (sizeof tmp2) / (sizeof tmp2[0]));
+ br_i15_encode(bx2, blen, x2);
+
+ check_equals("ModPow i62/i15", bx1, bx2, blen);
+
+ printf(".");
+ fflush(stdout);
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+static int
+eq_name(const char *s1, const char *s2)
+{
+ for (;;) {
+ int c1, c2;
+
+ for (;;) {
+ c1 = *s1 ++;
+ if (c1 >= 'A' && c1 <= 'Z') {
+ c1 += 'a' - 'A';
+ } else {
+ switch (c1) {
+ case '-': case '_': case '.': case ' ':
+ continue;
+ }
+ }
+ break;
+ }
+ for (;;) {
+ c2 = *s2 ++;
+ if (c2 >= 'A' && c2 <= 'Z') {
+ c2 += 'a' - 'A';
+ } else {
+ switch (c2) {
+ case '-': case '_': case '.': case ' ':
+ continue;
+ }
+ }
+ break;
+ }
+ if (c1 != c2) {
+ return 0;
+ }
+ if (c1 == 0) {
+ return 1;
+ }
+ }
+}
+
+#define STU(x) { &test_ ## x, #x }
+
+static const struct {
+ void (*fn)(void);
+ const char *name;
+} tfns[] = {
+ STU(MD5),
+ STU(SHA1),
+ STU(SHA224),
+ STU(SHA256),
+ STU(SHA384),
+ STU(SHA512),
+ STU(MD5_SHA1),
+ STU(multihash),
+ STU(HMAC),
+ STU(HKDF),
+ STU(SHAKE),
+ STU(HMAC_DRBG),
+ STU(AESCTR_DRBG),
+ STU(PRF),
+ STU(AES_big),
+ STU(AES_small),
+ STU(AES_ct),
+ STU(AES_ct64),
+ STU(AES_pwr8),
+ STU(AES_x86ni),
+ STU(AES_CTRCBC_big),
+ STU(AES_CTRCBC_small),
+ STU(AES_CTRCBC_ct),
+ STU(AES_CTRCBC_ct64),
+ STU(AES_CTRCBC_x86ni),
+ STU(AES_CTRCBC_pwr8),
+ STU(DES_tab),
+ STU(DES_ct),
+ STU(ChaCha20_ct),
+ STU(ChaCha20_sse2),
+ STU(Poly1305_ctmul),
+ STU(Poly1305_ctmul32),
+ STU(Poly1305_ctmulq),
+ STU(Poly1305_i15),
+ STU(RSA_i15),
+ STU(RSA_i31),
+ STU(RSA_i32),
+ STU(RSA_i62),
+ STU(GHASH_ctmul),
+ STU(GHASH_ctmul32),
+ STU(GHASH_ctmul64),
+ STU(GHASH_pclmul),
+ STU(GHASH_pwr8),
+ STU(CCM),
+ STU(EAX),
+ STU(GCM),
+ STU(EC_prime_i15),
+ STU(EC_prime_i31),
+ STU(EC_p256_m15),
+ STU(EC_p256_m31),
+ STU(EC_p256_m62),
+ STU(EC_p256_m64),
+ STU(EC_c25519_i15),
+ STU(EC_c25519_i31),
+ STU(EC_c25519_m15),
+ STU(EC_c25519_m31),
+ STU(EC_c25519_m62),
+ STU(EC_c25519_m64),
+ STU(ECDSA_i15),
+ STU(ECDSA_i31),
+ STU(modpow_i31),
+ STU(modpow_i62),
+ { 0, 0 }
+};
+
+int
+main(int argc, char *argv[])
+{
+ size_t u;
+
+ if (argc <= 1) {
+ printf("usage: testcrypto all | name...\n");
+ printf("individual test names:\n");
+ for (u = 0; tfns[u].name; u ++) {
+ printf(" %s\n", tfns[u].name);
+ }
+ } else {
+ for (u = 0; tfns[u].name; u ++) {
+ int i;
+
+ for (i = 1; i < argc; i ++) {
+ if (eq_name(argv[i], tfns[u].name)
+ || eq_name(argv[i], "all"))
+ {
+ tfns[u].fn();
+ break;
+ }
+ }
+ }
+ }
+ return 0;
+}
diff --git a/contrib/bearssl/test/test_math.c b/contrib/bearssl/test/test_math.c
new file mode 100644
index 000000000000..b36f9f787104
--- /dev/null
+++ b/contrib/bearssl/test/test_math.c
@@ -0,0 +1,482 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdarg.h>
+#include <time.h>
+
+#include <gmp.h>
+
+#include "bearssl.h"
+#include "inner.h"
+
+/*
+ * Pointers to implementations.
+ */
+typedef struct {
+ uint32_t word_size;
+ void (*zero)(uint32_t *x, uint32_t bit_len);
+ void (*decode)(uint32_t *x, const void *src, size_t len);
+ uint32_t (*decode_mod)(uint32_t *x,
+ const void *src, size_t len, const uint32_t *m);
+ void (*reduce)(uint32_t *x, const uint32_t *a, const uint32_t *m);
+ void (*decode_reduce)(uint32_t *x,
+ const void *src, size_t len, const uint32_t *m);
+ void (*encode)(void *dst, size_t len, const uint32_t *x);
+ uint32_t (*add)(uint32_t *a, const uint32_t *b, uint32_t ctl);
+ uint32_t (*sub)(uint32_t *a, const uint32_t *b, uint32_t ctl);
+ uint32_t (*ninv)(uint32_t x);
+ void (*montymul)(uint32_t *d, const uint32_t *x, const uint32_t *y,
+ const uint32_t *m, uint32_t m0i);
+ void (*to_monty)(uint32_t *x, const uint32_t *m);
+ void (*from_monty)(uint32_t *x, const uint32_t *m, uint32_t m0i);
+ void (*modpow)(uint32_t *x, const unsigned char *e, size_t elen,
+ const uint32_t *m, uint32_t m0i, uint32_t *t1, uint32_t *t2);
+} int_impl;
+
+static const int_impl i31_impl = {
+ 31,
+ &br_i31_zero,
+ &br_i31_decode,
+ &br_i31_decode_mod,
+ &br_i31_reduce,
+ &br_i31_decode_reduce,
+ &br_i31_encode,
+ &br_i31_add,
+ &br_i31_sub,
+ &br_i31_ninv31,
+ &br_i31_montymul,
+ &br_i31_to_monty,
+ &br_i31_from_monty,
+ &br_i31_modpow
+};
+static const int_impl i32_impl = {
+ 32,
+ &br_i32_zero,
+ &br_i32_decode,
+ &br_i32_decode_mod,
+ &br_i32_reduce,
+ &br_i32_decode_reduce,
+ &br_i32_encode,
+ &br_i32_add,
+ &br_i32_sub,
+ &br_i32_ninv32,
+ &br_i32_montymul,
+ &br_i32_to_monty,
+ &br_i32_from_monty,
+ &br_i32_modpow
+};
+
+static const int_impl *impl;
+
+static gmp_randstate_t RNG;
+
+/*
+ * Get a random prime of length 'size' bits. This function also guarantees
+ * that x-1 is not a multiple of 65537.
+ */
+static void
+rand_prime(mpz_t x, int size)
+{
+ for (;;) {
+ mpz_urandomb(x, RNG, size - 1);
+ mpz_setbit(x, 0);
+ mpz_setbit(x, size - 1);
+ if (mpz_probab_prime_p(x, 50)) {
+ mpz_sub_ui(x, x, 1);
+ if (mpz_divisible_ui_p(x, 65537)) {
+ continue;
+ }
+ mpz_add_ui(x, x, 1);
+ return;
+ }
+ }
+}
+
+/*
+ * Print out a GMP integer (for debug).
+ */
+static void
+print_z(mpz_t z)
+{
+ unsigned char zb[1000];
+ size_t zlen, k;
+
+ mpz_export(zb, &zlen, 1, 1, 0, 0, z);
+ if (zlen == 0) {
+ printf(" 00");
+ return;
+ }
+ if ((zlen & 3) != 0) {
+ k = 4 - (zlen & 3);
+ memmove(zb + k, zb, zlen);
+ memset(zb, 0, k);
+ zlen += k;
+ }
+ for (k = 0; k < zlen; k += 4) {
+ printf(" %02X%02X%02X%02X",
+ zb[k], zb[k + 1], zb[k + 2], zb[k + 3]);
+ }
+}
+
+/*
+ * Print out an i31 or i32 integer (for debug).
+ */
+static void
+print_u(uint32_t *x)
+{
+ size_t k;
+
+ if (x[0] == 0) {
+ printf(" 00000000 (0, 0)");
+ return;
+ }
+ for (k = (x[0] + 31) >> 5; k > 0; k --) {
+ printf(" %08lX", (unsigned long)x[k]);
+ }
+ printf(" (%u, %u)", (unsigned)(x[0] >> 5), (unsigned)(x[0] & 31));
+}
+
+/*
+ * Check that an i31/i32 number and a GMP number are equal.
+ */
+static void
+check_eqz(uint32_t *x, mpz_t z)
+{
+ unsigned char xb[1000];
+ unsigned char zb[1000];
+ size_t xlen, zlen;
+ int good;
+
+ xlen = ((x[0] + 31) & ~(uint32_t)31) >> 3;
+ impl->encode(xb, xlen, x);
+ mpz_export(zb, &zlen, 1, 1, 0, 0, z);
+ good = 1;
+ if (xlen < zlen) {
+ good = 0;
+ } else if (xlen > zlen) {
+ size_t u;
+
+ for (u = xlen; u > zlen; u --) {
+ if (xb[xlen - u] != 0) {
+ good = 0;
+ break;
+ }
+ }
+ }
+ good = good && memcmp(xb + xlen - zlen, zb, zlen) == 0;
+ if (!good) {
+ size_t u;
+
+ printf("Mismatch:\n");
+ printf(" x = ");
+ print_u(x);
+ printf("\n");
+ printf(" ex = ");
+ for (u = 0; u < xlen; u ++) {
+ printf("%02X", xb[u]);
+ }
+ printf("\n");
+ printf(" z = ");
+ print_z(z);
+ printf("\n");
+ exit(EXIT_FAILURE);
+ }
+}
+
+/* obsolete
+static void
+mp_to_br(uint32_t *mx, uint32_t x_bitlen, mpz_t x)
+{
+ uint32_t x_ebitlen;
+ size_t xlen;
+
+ if (mpz_sizeinbase(x, 2) > x_bitlen) {
+ abort();
+ }
+ x_ebitlen = ((x_bitlen / 31) << 5) + (x_bitlen % 31);
+ br_i31_zero(mx, x_ebitlen);
+ mpz_export(mx + 1, &xlen, -1, sizeof *mx, 0, 1, x);
+}
+*/
+
+static void
+test_modint(void)
+{
+ int i, j, k;
+ mpz_t p, a, b, v, t1;
+
+ printf("Test modular integers: ");
+ fflush(stdout);
+
+ gmp_randinit_mt(RNG);
+ mpz_init(p);
+ mpz_init(a);
+ mpz_init(b);
+ mpz_init(v);
+ mpz_init(t1);
+ mpz_set_ui(t1, (unsigned long)time(NULL));
+ gmp_randseed(RNG, t1);
+ for (k = 2; k <= 128; k ++) {
+ for (i = 0; i < 10; i ++) {
+ unsigned char ep[100], ea[100], eb[100], ev[100];
+ size_t plen, alen, blen, vlen;
+ uint32_t mp[40], ma[40], mb[40], mv[60], mx[100];
+ uint32_t mt1[40], mt2[40], mt3[40];
+ uint32_t ctl;
+ uint32_t mp0i;
+
+ rand_prime(p, k);
+ mpz_urandomm(a, RNG, p);
+ mpz_urandomm(b, RNG, p);
+ mpz_urandomb(v, RNG, k + 60);
+ if (mpz_sgn(b) == 0) {
+ mpz_set_ui(b, 1);
+ }
+ mpz_export(ep, &plen, 1, 1, 0, 0, p);
+ mpz_export(ea, &alen, 1, 1, 0, 0, a);
+ mpz_export(eb, &blen, 1, 1, 0, 0, b);
+ mpz_export(ev, &vlen, 1, 1, 0, 0, v);
+
+ impl->decode(mp, ep, plen);
+ if (impl->decode_mod(ma, ea, alen, mp) != 1) {
+ printf("Decode error\n");
+ printf(" ea = ");
+ print_z(a);
+ printf("\n");
+ printf(" p = ");
+ print_u(mp);
+ printf("\n");
+ exit(EXIT_FAILURE);
+ }
+ mp0i = impl->ninv(mp[1]);
+ if (impl->decode_mod(mb, eb, blen, mp) != 1) {
+ printf("Decode error\n");
+ printf(" eb = ");
+ print_z(b);
+ printf("\n");
+ printf(" p = ");
+ print_u(mp);
+ printf("\n");
+ exit(EXIT_FAILURE);
+ }
+ impl->decode(mv, ev, vlen);
+ check_eqz(mp, p);
+ check_eqz(ma, a);
+ check_eqz(mb, b);
+ check_eqz(mv, v);
+
+ impl->decode_mod(ma, ea, alen, mp);
+ impl->decode_mod(mb, eb, blen, mp);
+ ctl = impl->add(ma, mb, 1);
+ ctl |= impl->sub(ma, mp, 0) ^ (uint32_t)1;
+ impl->sub(ma, mp, ctl);
+ mpz_add(t1, a, b);
+ mpz_mod(t1, t1, p);
+ check_eqz(ma, t1);
+
+ impl->decode_mod(ma, ea, alen, mp);
+ impl->decode_mod(mb, eb, blen, mp);
+ impl->add(ma, mp, impl->sub(ma, mb, 1));
+ mpz_sub(t1, a, b);
+ mpz_mod(t1, t1, p);
+ check_eqz(ma, t1);
+
+ impl->decode_reduce(ma, ev, vlen, mp);
+ mpz_mod(t1, v, p);
+ check_eqz(ma, t1);
+
+ impl->decode(mv, ev, vlen);
+ impl->reduce(ma, mv, mp);
+ mpz_mod(t1, v, p);
+ check_eqz(ma, t1);
+
+ impl->decode_mod(ma, ea, alen, mp);
+ impl->to_monty(ma, mp);
+ mpz_mul_2exp(t1, a, ((k + impl->word_size - 1)
+ / impl->word_size) * impl->word_size);
+ mpz_mod(t1, t1, p);
+ check_eqz(ma, t1);
+ impl->from_monty(ma, mp, mp0i);
+ check_eqz(ma, a);
+
+ impl->decode_mod(ma, ea, alen, mp);
+ impl->decode_mod(mb, eb, blen, mp);
+ impl->to_monty(ma, mp);
+ impl->montymul(mt1, ma, mb, mp, mp0i);
+ mpz_mul(t1, a, b);
+ mpz_mod(t1, t1, p);
+ check_eqz(mt1, t1);
+
+ impl->decode_mod(ma, ea, alen, mp);
+ impl->modpow(ma, ev, vlen, mp, mp0i, mt1, mt2);
+ mpz_powm(t1, a, v, p);
+ check_eqz(ma, t1);
+
+ /*
+ br_modint_decode(ma, mp, ea, alen);
+ br_modint_decode(mb, mp, eb, blen);
+ if (!br_modint_div(ma, mb, mp, mt1, mt2, mt3)) {
+ fprintf(stderr, "division failed\n");
+ exit(EXIT_FAILURE);
+ }
+ mpz_sub_ui(t1, p, 2);
+ mpz_powm(t1, b, t1, p);
+ mpz_mul(t1, a, t1);
+ mpz_mod(t1, t1, p);
+ check_eqz(ma, t1);
+
+ br_modint_decode(ma, mp, ea, alen);
+ br_modint_decode(mb, mp, eb, blen);
+ for (j = 0; j <= (2 * k + 5); j ++) {
+ br_int_add(mx, j, ma, mb);
+ mpz_add(t1, a, b);
+ mpz_tdiv_r_2exp(t1, t1, j);
+ check_eqz(mx, t1);
+
+ br_int_mul(mx, j, ma, mb);
+ mpz_mul(t1, a, b);
+ mpz_tdiv_r_2exp(t1, t1, j);
+ check_eqz(mx, t1);
+ }
+ */
+ }
+ printf(".");
+ fflush(stdout);
+ }
+ mpz_clear(p);
+ mpz_clear(a);
+ mpz_clear(b);
+ mpz_clear(v);
+ mpz_clear(t1);
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+
+#if 0
+static void
+test_RSA_core(void)
+{
+ int i, j, k;
+ mpz_t n, e, d, p, q, dp, dq, iq, t1, t2, phi;
+
+ printf("Test RSA core: ");
+ fflush(stdout);
+
+ gmp_randinit_mt(RNG);
+ mpz_init(n);
+ mpz_init(e);
+ mpz_init(d);
+ mpz_init(p);
+ mpz_init(q);
+ mpz_init(dp);
+ mpz_init(dq);
+ mpz_init(iq);
+ mpz_init(t1);
+ mpz_init(t2);
+ mpz_init(phi);
+ mpz_set_ui(t1, (unsigned long)time(NULL));
+ gmp_randseed(RNG, t1);
+
+ /*
+ * To test corner cases, we want to try RSA keys such that the
+ * lengths of both factors can be arbitrary modulo 2^32. Factors
+ * p and q need not be of the same length; p can be greater than
+ * q and q can be greater than p.
+ *
+ * To keep computation time reasonable, we use p and q factors of
+ * less than 128 bits; this is way too small for secure RSA,
+ * but enough to exercise all code paths (since we work only with
+ * 32-bit words).
+ */
+ for (i = 64; i <= 96; i ++) {
+ rand_prime(p, i);
+ for (j = i - 33; j <= i + 33; j ++) {
+ uint32_t mp[40], mq[40], mdp[40], mdq[40], miq[40];
+
+ /*
+ * Generate a RSA key pair, with p of length i bits,
+ * and q of length j bits.
+ */
+ do {
+ rand_prime(q, j);
+ } while (mpz_cmp(p, q) == 0);
+ mpz_mul(n, p, q);
+ mpz_set_ui(e, 65537);
+ mpz_sub_ui(t1, p, 1);
+ mpz_sub_ui(t2, q, 1);
+ mpz_mul(phi, t1, t2);
+ mpz_invert(d, e, phi);
+ mpz_mod(dp, d, t1);
+ mpz_mod(dq, d, t2);
+ mpz_invert(iq, q, p);
+
+ /*
+ * Convert the key pair elements to BearSSL arrays.
+ */
+ mp_to_br(mp, mpz_sizeinbase(p, 2), p);
+ mp_to_br(mq, mpz_sizeinbase(q, 2), q);
+ mp_to_br(mdp, mpz_sizeinbase(dp, 2), dp);
+ mp_to_br(mdq, mpz_sizeinbase(dq, 2), dq);
+ mp_to_br(miq, mp[0], iq);
+
+ /*
+ * Compute and check ten public/private operations.
+ */
+ for (k = 0; k < 10; k ++) {
+ uint32_t mx[40];
+
+ mpz_urandomm(t1, RNG, n);
+ mpz_powm(t2, t1, e, n);
+ mp_to_br(mx, mpz_sizeinbase(n, 2), t2);
+ br_rsa_private_core(mx, mp, mq, mdp, mdq, miq);
+ check_eqz(mx, t1);
+ }
+ }
+ printf(".");
+ fflush(stdout);
+ }
+
+ printf(" done.\n");
+ fflush(stdout);
+}
+#endif
+
+int
+main(void)
+{
+ printf("===== i32 ======\n");
+ impl = &i32_impl;
+ test_modint();
+ printf("===== i31 ======\n");
+ impl = &i31_impl;
+ test_modint();
+ /*
+ test_RSA_core();
+ */
+ return 0;
+}
diff --git a/contrib/bearssl/test/test_speed.c b/contrib/bearssl/test/test_speed.c
new file mode 100644
index 000000000000..eb1b9646f516
--- /dev/null
+++ b/contrib/bearssl/test/test_speed.c
@@ -0,0 +1,1772 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <time.h>
+#include "inner.h"
+
+#define HASH_SIZE(cname) br_ ## cname ## _SIZE
+
+#define SPEED_HASH(Name, cname) \
+static void \
+test_speed_ ## cname(void) \
+{ \
+ unsigned char buf[8192]; \
+ unsigned char tmp[HASH_SIZE(cname)]; \
+ br_ ## cname ## _context mc; \
+ int i; \
+ long num; \
+ \
+ memset(buf, 'T', sizeof buf); \
+ for (i = 0; i < 10; i ++) { \
+ br_ ## cname ## _init(&mc); \
+ br_ ## cname ## _update(&mc, buf, sizeof buf); \
+ br_ ## cname ## _out(&mc, tmp); \
+ } \
+ num = 10; \
+ for (;;) { \
+ clock_t begin, end; \
+ double tt; \
+ long k; \
+ \
+ br_ ## cname ## _init(&mc); \
+ begin = clock(); \
+ for (k = num; k > 0; k --) { \
+ br_ ## cname ## _update(&mc, buf, sizeof buf); \
+ } \
+ end = clock(); \
+ br_ ## cname ## _out(&mc, tmp); \
+ tt = (double)(end - begin) / CLOCKS_PER_SEC; \
+ if (tt >= 2.0) { \
+ printf("%-30s %8.2f MB/s\n", #Name, \
+ ((double)sizeof buf) * (double)num \
+ / (tt * 1000000.0)); \
+ fflush(stdout); \
+ return; \
+ } \
+ num <<= 1; \
+ } \
+}
+
+#define BLOCK_SIZE(cname) br_ ## cname ## _BLOCK_SIZE
+
+#define SPEED_BLOCKCIPHER_CBC(Name, fname, cname, klen, dir) \
+static void \
+test_speed_ ## fname(void) \
+{ \
+ unsigned char key[klen]; \
+ unsigned char buf[8192 - (8192 % BLOCK_SIZE(cname))]; \
+ unsigned char iv[BLOCK_SIZE(cname)]; \
+ const br_block_cbc ## dir ## _class *vt; \
+ br_ ## cname ## _cbc ## dir ## _keys ec; \
+ int i; \
+ long num; \
+ \
+ memset(key, 'T', sizeof key); \
+ memset(buf, 'P', sizeof buf); \
+ memset(iv, 'X', sizeof iv); \
+ vt = br_ ## cname ## _cbc ## dir ## _get_vtable(); \
+ if (vt == NULL) { \
+ printf("%-30s UNAVAILABLE\n", #Name); \
+ fflush(stdout); \
+ return; \
+ } \
+ for (i = 0; i < 10; i ++) { \
+ vt->init(&ec.vtable, key, sizeof key); \
+ vt->run(&ec.vtable, iv, buf, sizeof buf); \
+ } \
+ num = 10; \
+ for (;;) { \
+ clock_t begin, end; \
+ double tt; \
+ long k; \
+ \
+ vt->init(&ec.vtable, key, sizeof key); \
+ begin = clock(); \
+ for (k = num; k > 0; k --) { \
+ vt->run(&ec.vtable, iv, buf, sizeof buf); \
+ } \
+ end = clock(); \
+ tt = (double)(end - begin) / CLOCKS_PER_SEC; \
+ if (tt >= 2.0) { \
+ printf("%-30s %8.2f MB/s\n", #Name, \
+ ((double)sizeof buf) * (double)num \
+ / (tt * 1000000.0)); \
+ fflush(stdout); \
+ return; \
+ } \
+ num <<= 1; \
+ } \
+}
+
+#define SPEED_BLOCKCIPHER_CTR(Name, fname, cname, klen) \
+static void \
+test_speed_ ## fname(void) \
+{ \
+ unsigned char key[klen]; \
+ unsigned char buf[8192 - (8192 % BLOCK_SIZE(cname))]; \
+ unsigned char iv[BLOCK_SIZE(cname) - 4]; \
+ const br_block_ctr_class *vt; \
+ br_ ## cname ## _ctr_keys ec; \
+ int i; \
+ long num; \
+ \
+ memset(key, 'T', sizeof key); \
+ memset(buf, 'P', sizeof buf); \
+ memset(iv, 'X', sizeof iv); \
+ vt = br_ ## cname ## _ctr_get_vtable(); \
+ if (vt == NULL) { \
+ printf("%-30s UNAVAILABLE\n", #Name); \
+ fflush(stdout); \
+ return; \
+ } \
+ for (i = 0; i < 10; i ++) { \
+ vt->init(&ec.vtable, key, sizeof key); \
+ vt->run(&ec.vtable, iv, 1, buf, sizeof buf); \
+ } \
+ num = 10; \
+ for (;;) { \
+ clock_t begin, end; \
+ double tt; \
+ long k; \
+ \
+ vt->init(&ec.vtable, key, sizeof key); \
+ begin = clock(); \
+ for (k = num; k > 0; k --) { \
+ vt->run(&ec.vtable, iv, 1, buf, sizeof buf); \
+ } \
+ end = clock(); \
+ tt = (double)(end - begin) / CLOCKS_PER_SEC; \
+ if (tt >= 2.0) { \
+ printf("%-30s %8.2f MB/s\n", #Name, \
+ ((double)sizeof buf) * (double)num \
+ / (tt * 1000000.0)); \
+ fflush(stdout); \
+ return; \
+ } \
+ num <<= 1; \
+ } \
+}
+
+#define SPEED_CHACHA20(Name, fname) \
+static void \
+test_speed_ ## fname(void) \
+{ \
+ br_chacha20_run bc; \
+ unsigned char key[32]; \
+ unsigned char buf[8192]; \
+ unsigned char iv[12]; \
+ int i; \
+ long num; \
+ \
+ bc = br_ ## fname ## _get(); \
+ if (bc == 0) { \
+ printf("%-30s UNAVAILABLE\n", #Name); \
+ fflush(stdout); \
+ return; \
+ } \
+ memset(key, 'T', sizeof key); \
+ memset(buf, 'P', sizeof buf); \
+ memset(iv, 'X', sizeof iv); \
+ for (i = 0; i < 10; i ++) { \
+ bc(key, iv, i, buf, sizeof buf); \
+ } \
+ num = 10; \
+ for (;;) { \
+ clock_t begin, end; \
+ double tt; \
+ long k; \
+ \
+ begin = clock(); \
+ for (k = num; k > 0; k --) { \
+ bc(key, iv, (uint32_t)k, buf, sizeof buf); \
+ } \
+ end = clock(); \
+ tt = (double)(end - begin) / CLOCKS_PER_SEC; \
+ if (tt >= 2.0) { \
+ printf("%-30s %8.2f MB/s\n", #Name, \
+ ((double)sizeof buf) * (double)num \
+ / (tt * 1000000.0)); \
+ fflush(stdout); \
+ return; \
+ } \
+ num <<= 1; \
+ } \
+}
+
+SPEED_HASH(MD5, md5)
+SPEED_HASH(SHA-1, sha1)
+SPEED_HASH(SHA-256, sha256)
+SPEED_HASH(SHA-512, sha512)
+
+/*
+ * There are no vtable selection functions for the portable implementations,
+ * so we define some custom macros.
+ */
+#define br_aes_big_cbcenc_get_vtable() (&br_aes_big_cbcenc_vtable)
+#define br_aes_big_cbcdec_get_vtable() (&br_aes_big_cbcdec_vtable)
+#define br_aes_big_ctr_get_vtable() (&br_aes_big_ctr_vtable)
+#define br_aes_big_ctrcbc_get_vtable() (&br_aes_big_ctrcbc_vtable)
+#define br_aes_small_cbcenc_get_vtable() (&br_aes_small_cbcenc_vtable)
+#define br_aes_small_cbcdec_get_vtable() (&br_aes_small_cbcdec_vtable)
+#define br_aes_small_ctr_get_vtable() (&br_aes_small_ctr_vtable)
+#define br_aes_small_ctrcbc_get_vtable() (&br_aes_small_ctrcbc_vtable)
+#define br_aes_ct_cbcenc_get_vtable() (&br_aes_ct_cbcenc_vtable)
+#define br_aes_ct_cbcdec_get_vtable() (&br_aes_ct_cbcdec_vtable)
+#define br_aes_ct_ctr_get_vtable() (&br_aes_ct_ctr_vtable)
+#define br_aes_ct_ctrcbc_get_vtable() (&br_aes_ct_ctrcbc_vtable)
+#define br_aes_ct64_cbcenc_get_vtable() (&br_aes_ct64_cbcenc_vtable)
+#define br_aes_ct64_cbcdec_get_vtable() (&br_aes_ct64_cbcdec_vtable)
+#define br_aes_ct64_ctr_get_vtable() (&br_aes_ct64_ctr_vtable)
+#define br_aes_ct64_ctrcbc_get_vtable() (&br_aes_ct64_ctrcbc_vtable)
+#define br_chacha20_ct_get() (&br_chacha20_ct_run)
+
+#define SPEED_AES(iname) \
+SPEED_BLOCKCIPHER_CBC(AES-128 CBC encrypt (iname), aes128_ ## iname ## _cbcenc, aes_ ## iname, 16, enc) \
+SPEED_BLOCKCIPHER_CBC(AES-128 CBC decrypt (iname), aes128_ ## iname ## _cbcdec, aes_ ## iname, 16, dec) \
+SPEED_BLOCKCIPHER_CBC(AES-192 CBC encrypt (iname), aes192_ ## iname ## _cbcenc, aes_ ## iname, 24, enc) \
+SPEED_BLOCKCIPHER_CBC(AES-192 CBC decrypt (iname), aes192_ ## iname ## _cbcdec, aes_ ## iname, 24, dec) \
+SPEED_BLOCKCIPHER_CBC(AES-256 CBC encrypt (iname), aes256_ ## iname ## _cbcenc, aes_ ## iname, 32, enc) \
+SPEED_BLOCKCIPHER_CBC(AES-256 CBC decrypt (iname), aes256_ ## iname ## _cbcdec, aes_ ## iname, 32, dec) \
+SPEED_BLOCKCIPHER_CTR(AES-128 CTR (iname), aes128_ ## iname ## _ctr, aes_ ## iname, 16) \
+SPEED_BLOCKCIPHER_CTR(AES-192 CTR (iname), aes192_ ## iname ## _ctr, aes_ ## iname, 24) \
+SPEED_BLOCKCIPHER_CTR(AES-256 CTR (iname), aes256_ ## iname ## _ctr, aes_ ## iname, 32)
+
+SPEED_AES(big)
+SPEED_AES(small)
+SPEED_AES(ct)
+SPEED_AES(ct64)
+SPEED_AES(x86ni)
+SPEED_AES(pwr8)
+
+#define br_des_tab_cbcenc_get_vtable() (&br_des_tab_cbcenc_vtable)
+#define br_des_tab_cbcdec_get_vtable() (&br_des_tab_cbcdec_vtable)
+#define br_des_ct_cbcenc_get_vtable() (&br_des_ct_cbcenc_vtable)
+#define br_des_ct_cbcdec_get_vtable() (&br_des_ct_cbcdec_vtable)
+
+#define SPEED_DES(iname) \
+SPEED_BLOCKCIPHER_CBC(DES CBC encrypt (iname), des_ ## iname ## _cbcenc, des_ ## iname, 8, enc) \
+SPEED_BLOCKCIPHER_CBC(DES CBC decrypt (iname), des_ ## iname ## _cbcdec, des_ ## iname, 8, dec) \
+SPEED_BLOCKCIPHER_CBC(3DES CBC encrypt (iname), 3des_ ## iname ## _cbcenc, des_ ## iname, 24, enc) \
+SPEED_BLOCKCIPHER_CBC(3DES CBC decrypt (iname), 3des_ ## iname ## _cbcdec, des_ ## iname, 24, dec)
+
+SPEED_DES(tab)
+SPEED_DES(ct)
+
+SPEED_CHACHA20(ChaCha20 (ct), chacha20_ct)
+SPEED_CHACHA20(ChaCha20 (sse2), chacha20_sse2)
+
+static void
+test_speed_ghash_inner(char *name, br_ghash gh)
+{
+ unsigned char buf[8192], h[16], y[16];
+ int i;
+ long num;
+
+ memset(buf, 'T', sizeof buf);
+ memset(h, 'P', sizeof h);
+ memset(y, 0, sizeof y);
+ for (i = 0; i < 10; i ++) {
+ gh(y, h, buf, sizeof buf);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ gh(y, h, buf, sizeof buf);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f MB/s\n", name,
+ ((double)sizeof buf) * (double)num
+ / (tt * 1000000.0));
+ fflush(stdout);
+ return;
+ }
+ num <<= 1;
+ }
+}
+
+static void
+test_speed_ghash_ctmul(void)
+{
+ test_speed_ghash_inner("GHASH (ctmul)", &br_ghash_ctmul);
+}
+
+static void
+test_speed_ghash_ctmul32(void)
+{
+ test_speed_ghash_inner("GHASH (ctmul32)", &br_ghash_ctmul32);
+}
+
+static void
+test_speed_ghash_ctmul64(void)
+{
+ test_speed_ghash_inner("GHASH (ctmul64)", &br_ghash_ctmul64);
+}
+
+static void
+test_speed_ghash_pclmul(void)
+{
+ br_ghash gh;
+
+ gh = br_ghash_pclmul_get();
+ if (gh == 0) {
+ printf("%-30s UNAVAILABLE\n", "GHASH (pclmul)");
+ fflush(stdout);
+ } else {
+ test_speed_ghash_inner("GHASH (pclmul)", gh);
+ }
+}
+
+static void
+test_speed_ghash_pwr8(void)
+{
+ br_ghash gh;
+
+ gh = br_ghash_pwr8_get();
+ if (gh == 0) {
+ printf("%-30s UNAVAILABLE\n", "GHASH (pwr8)");
+ fflush(stdout);
+ } else {
+ test_speed_ghash_inner("GHASH (pwr8)", gh);
+ }
+}
+
+static uint32_t
+fake_chacha20(const void *key, const void *iv,
+ uint32_t cc, void *data, size_t len)
+{
+ (void)key;
+ (void)iv;
+ (void)data;
+ (void)len;
+ return cc + (uint32_t)((len + 63) >> 6);
+}
+
+/*
+ * To speed-test Poly1305, we run it with a do-nothing stub instead of
+ * ChaCha20.
+ */
+static void
+test_speed_poly1305_inner(char *name, br_poly1305_run pl)
+{
+ unsigned char buf[8192], key[32], iv[12], aad[13], tag[16];
+ int i;
+ long num;
+
+ memset(key, 'K', sizeof key);
+ memset(iv, 'I', sizeof iv);
+ memset(aad, 'A', sizeof aad);
+ memset(buf, 'T', sizeof buf);
+ for (i = 0; i < 10; i ++) {
+ pl(key, iv, buf, sizeof buf,
+ aad, sizeof aad, tag, &fake_chacha20, 0);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ pl(key, iv, buf, sizeof buf,
+ aad, sizeof aad, tag, &fake_chacha20, 0);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f MB/s\n", name,
+ ((double)sizeof buf) * (double)num
+ / (tt * 1000000.0));
+ fflush(stdout);
+ return;
+ }
+ num <<= 1;
+ }
+}
+
+static void
+test_speed_poly1305_ctmul(void)
+{
+ test_speed_poly1305_inner("Poly1305 (ctmul)", &br_poly1305_ctmul_run);
+}
+
+static void
+test_speed_poly1305_ctmul32(void)
+{
+ test_speed_poly1305_inner("Poly1305 (ctmul32)",
+ &br_poly1305_ctmul32_run);
+}
+
+static void
+test_speed_poly1305_ctmulq(void)
+{
+ br_poly1305_run bp;
+
+ bp = br_poly1305_ctmulq_get();
+ if (bp == 0) {
+ printf("%-30s UNAVAILABLE\n", "Poly1305 (ctmulq)");
+ } else {
+ test_speed_poly1305_inner("Poly1305 (ctmulq)", bp);
+ }
+}
+
+static void
+test_speed_poly1305_i15(void)
+{
+ test_speed_poly1305_inner("Poly1305 (i15)", &br_poly1305_i15_run);
+}
+
+static void
+test_speed_eax_inner(char *name,
+ const br_block_ctrcbc_class *vt, size_t key_len)
+{
+ unsigned char buf[8192], key[32], nonce[16], aad[16], tag[16];
+ int i;
+ long num;
+ br_aes_gen_ctrcbc_keys ac;
+ br_eax_context ec;
+
+ if (vt == NULL) {
+ printf("%-30s UNAVAILABLE\n", name);
+ fflush(stdout);
+ return;
+ }
+ memset(key, 'K', key_len);
+ memset(nonce, 'N', sizeof nonce);
+ memset(aad, 'A', sizeof aad);
+ memset(buf, 'T', sizeof buf);
+ for (i = 0; i < 10; i ++) {
+ vt->init(&ac.vtable, key, key_len);
+ br_eax_init(&ec, &ac.vtable);
+ br_eax_reset(&ec, nonce, sizeof nonce);
+ br_eax_aad_inject(&ec, aad, sizeof aad);
+ br_eax_flip(&ec);
+ br_eax_run(&ec, 1, buf, sizeof buf);
+ br_eax_get_tag(&ec, tag);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ vt->init(&ac.vtable, key, key_len);
+ br_eax_init(&ec, &ac.vtable);
+ br_eax_reset(&ec, nonce, sizeof nonce);
+ br_eax_aad_inject(&ec, aad, sizeof aad);
+ br_eax_flip(&ec);
+ br_eax_run(&ec, 1, buf, sizeof buf);
+ br_eax_get_tag(&ec, tag);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f MB/s\n", name,
+ ((double)sizeof buf) * (double)num
+ / (tt * 1000000.0));
+ fflush(stdout);
+ return;
+ }
+ num <<= 1;
+ }
+}
+
+#define SPEED_EAX(Algo, algo, keysize, impl) \
+static void \
+test_speed_eax_ ## algo ## keysize ## _ ## impl(void) \
+{ \
+ test_speed_eax_inner("EAX " #Algo "-" #keysize "(" #impl ")", \
+ br_ ## algo ## _ ## impl ## _ctrcbc_get_vtable() \
+ , (keysize) >> 3); \
+}
+
+SPEED_EAX(AES, aes, 128, big)
+SPEED_EAX(AES, aes, 128, small)
+SPEED_EAX(AES, aes, 128, ct)
+SPEED_EAX(AES, aes, 128, ct64)
+SPEED_EAX(AES, aes, 128, x86ni)
+SPEED_EAX(AES, aes, 128, pwr8)
+SPEED_EAX(AES, aes, 192, big)
+SPEED_EAX(AES, aes, 192, small)
+SPEED_EAX(AES, aes, 192, ct)
+SPEED_EAX(AES, aes, 192, ct64)
+SPEED_EAX(AES, aes, 192, x86ni)
+SPEED_EAX(AES, aes, 192, pwr8)
+SPEED_EAX(AES, aes, 256, big)
+SPEED_EAX(AES, aes, 256, small)
+SPEED_EAX(AES, aes, 256, ct)
+SPEED_EAX(AES, aes, 256, ct64)
+SPEED_EAX(AES, aes, 256, x86ni)
+SPEED_EAX(AES, aes, 256, pwr8)
+
+static void
+test_speed_shake_inner(int security_level)
+{
+ unsigned char buf[8192];
+ br_shake_context sc;
+ int i;
+ long num;
+
+ memset(buf, 'D', sizeof buf);
+ br_shake_init(&sc, security_level);
+ for (i = 0; i < 10; i ++) {
+ br_shake_inject(&sc, buf, sizeof buf);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ br_shake_inject(&sc, buf, sizeof buf);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("SHAKE%-3d (inject) %8.2f MB/s\n",
+ security_level,
+ ((double)sizeof buf) * (double)num
+ / (tt * 1000000.0));
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+
+ br_shake_flip(&sc);
+ for (i = 0; i < 10; i ++) {
+ br_shake_produce(&sc, buf, sizeof buf);
+ }
+
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ br_shake_produce(&sc, buf, sizeof buf);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("SHAKE%-3d (produce) %8.2f MB/s\n",
+ security_level,
+ ((double)sizeof buf) * (double)num
+ / (tt * 1000000.0));
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+}
+
+static void
+test_speed_shake128(void)
+{
+ test_speed_shake_inner(128);
+}
+
+static void
+test_speed_shake256(void)
+{
+ test_speed_shake_inner(256);
+}
+
+static const unsigned char RSA_N[] = {
+ 0xE9, 0xF2, 0x4A, 0x2F, 0x96, 0xDF, 0x0A, 0x23,
+ 0x01, 0x85, 0xF1, 0x2C, 0xB2, 0xA8, 0xEF, 0x23,
+ 0xCE, 0x2E, 0xB0, 0x4E, 0x18, 0x31, 0x95, 0x5B,
+ 0x98, 0x2D, 0x9B, 0x8C, 0xE3, 0x1A, 0x2B, 0x96,
+ 0xB5, 0xC7, 0xEE, 0xED, 0x72, 0x43, 0x2D, 0xFE,
+ 0x7F, 0x61, 0x33, 0xEA, 0x14, 0xFC, 0xDE, 0x80,
+ 0x17, 0x42, 0xF0, 0xF3, 0xC3, 0xC7, 0x89, 0x47,
+ 0x76, 0x5B, 0xFA, 0x33, 0xC4, 0x8C, 0x94, 0xDE,
+ 0x6A, 0x75, 0xD8, 0x1A, 0xF4, 0x49, 0xBC, 0xF3,
+ 0xB7, 0x9E, 0x2C, 0x8D, 0xEC, 0x5A, 0xEE, 0xBF,
+ 0x4B, 0x5A, 0x7F, 0xEF, 0x21, 0x39, 0xDB, 0x1D,
+ 0x83, 0x5E, 0x7E, 0x2F, 0xAA, 0x5E, 0xBA, 0x28,
+ 0xC3, 0xA2, 0x53, 0x19, 0xFB, 0x2F, 0x78, 0x6B,
+ 0x14, 0x60, 0x49, 0x3C, 0xCC, 0x1B, 0xE9, 0x1E,
+ 0x3D, 0x10, 0xA4, 0xEB, 0x7F, 0x66, 0x98, 0xF6,
+ 0xC3, 0xAC, 0x35, 0xF5, 0x01, 0x84, 0xFF, 0x7D,
+ 0x1F, 0x72, 0xBE, 0xB4, 0xD1, 0x89, 0xC8, 0xDD,
+ 0x44, 0xE7, 0xB5, 0x2E, 0x2C, 0xE1, 0x85, 0xF5,
+ 0x15, 0x50, 0xA9, 0x08, 0xC7, 0x67, 0xD9, 0x2B,
+ 0x6C, 0x11, 0xB3, 0xEB, 0x28, 0x8D, 0xF4, 0xCC,
+ 0xE3, 0xC3, 0xC5, 0x04, 0x0E, 0x7C, 0x8D, 0xDB,
+ 0x39, 0x06, 0x6A, 0x74, 0x75, 0xDF, 0xA8, 0x0F,
+ 0xDA, 0x67, 0x5A, 0x73, 0x1E, 0xFD, 0x8E, 0x4C,
+ 0xEE, 0x17, 0xEE, 0x1E, 0x67, 0xDB, 0x98, 0x70,
+ 0x60, 0xF7, 0xB9, 0xB5, 0x1F, 0x19, 0x93, 0xD6,
+ 0x3F, 0x2F, 0x1F, 0xB6, 0x5B, 0x59, 0xAA, 0x85,
+ 0xBB, 0x25, 0xE4, 0x13, 0xEF, 0xE7, 0xB9, 0x87,
+ 0x9C, 0x3F, 0x5E, 0xE4, 0x08, 0xA3, 0x51, 0xCF,
+ 0x8B, 0xAD, 0xF4, 0xE6, 0x1A, 0x5F, 0x51, 0xDD,
+ 0xA8, 0xBE, 0xE8, 0xD1, 0x20, 0x19, 0x61, 0x6C,
+ 0x18, 0xAB, 0xCA, 0x0A, 0xD9, 0x82, 0xA6, 0x94,
+ 0xD5, 0x69, 0x2A, 0xF6, 0x43, 0x66, 0x31, 0x09
+};
+
+static const unsigned char RSA_E[] = {
+ 0x01, 0x00, 0x01
+};
+
+static const unsigned char RSA_P[] = {
+ 0xFD, 0x39, 0x40, 0x56, 0x20, 0x80, 0xC5, 0x81,
+ 0x4C, 0x5F, 0x0C, 0x1A, 0x52, 0x84, 0x03, 0x2F,
+ 0xCE, 0x82, 0xB0, 0xD8, 0x30, 0x23, 0x7F, 0x77,
+ 0x45, 0xC2, 0x01, 0xC4, 0x68, 0x96, 0x0D, 0xA7,
+ 0x22, 0xA9, 0x6C, 0xA9, 0x1A, 0x33, 0xE5, 0x2F,
+ 0xB5, 0x07, 0x9A, 0xF9, 0xEA, 0x33, 0xA5, 0xC8,
+ 0x96, 0x60, 0x6A, 0xCA, 0xEB, 0xE5, 0x6E, 0x09,
+ 0x46, 0x7E, 0x2D, 0xEF, 0x93, 0x7D, 0x56, 0xED,
+ 0x75, 0x70, 0x3B, 0x96, 0xC4, 0xD5, 0xDB, 0x0B,
+ 0x3F, 0x69, 0xDF, 0x06, 0x18, 0x76, 0xF4, 0xCF,
+ 0xF8, 0x84, 0x22, 0xDF, 0xBD, 0x71, 0x62, 0x7B,
+ 0x67, 0x99, 0xBC, 0x09, 0x95, 0x54, 0xA4, 0x98,
+ 0x83, 0xF5, 0xA9, 0xCF, 0x09, 0xA5, 0x1F, 0x61,
+ 0x25, 0xB4, 0x70, 0x6C, 0x91, 0xB8, 0xB3, 0xD0,
+ 0xCE, 0x9C, 0x45, 0x65, 0x9B, 0xEF, 0xD4, 0x70,
+ 0xBE, 0x86, 0xD2, 0x98, 0x5D, 0xEB, 0xE3, 0xFF
+};
+
+static const unsigned char RSA_Q[] = {
+ 0xEC, 0x82, 0xEE, 0x63, 0x5F, 0x40, 0x52, 0xDB,
+ 0x38, 0x7A, 0x37, 0x6A, 0x54, 0x5B, 0xD9, 0xA0,
+ 0x73, 0xB4, 0xBB, 0x52, 0xB2, 0x84, 0x07, 0xD0,
+ 0xCC, 0x82, 0x0D, 0x20, 0xB3, 0xFA, 0xD5, 0xB6,
+ 0x25, 0x92, 0x35, 0x4D, 0xB4, 0xC7, 0x36, 0x48,
+ 0xCE, 0x5E, 0x21, 0x4A, 0xA6, 0x74, 0x65, 0xF4,
+ 0x7D, 0x1D, 0xBC, 0x3B, 0xE2, 0xF4, 0x3E, 0x11,
+ 0x58, 0x10, 0x6C, 0x04, 0x46, 0x9E, 0x8D, 0x57,
+ 0xE0, 0x04, 0xE2, 0xEC, 0x47, 0xCF, 0xB3, 0x2A,
+ 0xFD, 0x4C, 0x55, 0x18, 0xDB, 0xDE, 0x3B, 0xDC,
+ 0xF4, 0x5B, 0xDA, 0xF3, 0x1A, 0xC8, 0x41, 0x6F,
+ 0x73, 0x3B, 0xFE, 0x3C, 0xA0, 0xDB, 0xBA, 0x6E,
+ 0x65, 0xA5, 0xE8, 0x02, 0xA5, 0x6C, 0xEA, 0x03,
+ 0xF6, 0x99, 0xF7, 0xCB, 0x4B, 0xB7, 0x11, 0x51,
+ 0x93, 0x88, 0x3F, 0xF9, 0x06, 0x85, 0xA9, 0x1E,
+ 0xCA, 0x64, 0xF8, 0x11, 0xA5, 0x1A, 0xCA, 0xF7
+};
+
+static const unsigned char RSA_DP[] = {
+ 0x77, 0x95, 0xE0, 0x02, 0x4C, 0x9B, 0x43, 0xAA,
+ 0xCA, 0x4C, 0x60, 0xC4, 0xD5, 0x8F, 0x2E, 0x8A,
+ 0x17, 0x36, 0xB5, 0x19, 0x83, 0xB2, 0x5F, 0xF2,
+ 0x0D, 0xE9, 0x8F, 0x38, 0x18, 0x44, 0x34, 0xF2,
+ 0x67, 0x76, 0x27, 0xB0, 0xBC, 0x85, 0x21, 0x89,
+ 0x24, 0x2F, 0x11, 0x4B, 0x51, 0x05, 0x4F, 0x17,
+ 0xA9, 0x9C, 0xA3, 0x12, 0x6D, 0xD1, 0x0D, 0xE4,
+ 0x27, 0x7C, 0x53, 0x69, 0x3E, 0xF8, 0x04, 0x63,
+ 0x64, 0x00, 0xBA, 0xC3, 0x7A, 0xF5, 0x9B, 0xDA,
+ 0x75, 0xFA, 0x23, 0xAF, 0x17, 0x42, 0xA6, 0x5E,
+ 0xC8, 0xF8, 0x6E, 0x17, 0xC7, 0xB9, 0x92, 0x4E,
+ 0xC1, 0x20, 0x63, 0x23, 0x0B, 0x78, 0xCB, 0xBA,
+ 0x93, 0x27, 0x23, 0x28, 0x79, 0x5F, 0x97, 0xB0,
+ 0x23, 0x44, 0x51, 0x8B, 0x94, 0x4D, 0xEB, 0xED,
+ 0x82, 0x85, 0x5E, 0x68, 0x9B, 0xF9, 0xE9, 0x13,
+ 0xCD, 0x86, 0x92, 0x52, 0x0E, 0x98, 0xE6, 0x35
+};
+
+static const unsigned char RSA_DQ[] = {
+ 0xD8, 0xDD, 0x71, 0xB3, 0x62, 0xBA, 0xBB, 0x7E,
+ 0xD1, 0xF9, 0x96, 0xE8, 0x83, 0xB3, 0xB9, 0x08,
+ 0x9C, 0x30, 0x03, 0x77, 0xDF, 0xC2, 0x9A, 0xDC,
+ 0x05, 0x39, 0xD6, 0xC9, 0xBE, 0xDE, 0x68, 0xA9,
+ 0xDD, 0x27, 0x84, 0x82, 0xDD, 0x19, 0xB1, 0x97,
+ 0xEE, 0xCA, 0x77, 0x22, 0x59, 0x20, 0xEF, 0xFF,
+ 0xCF, 0xDD, 0xBD, 0x24, 0xF8, 0x84, 0xD6, 0x88,
+ 0xD6, 0xC4, 0x30, 0x17, 0x77, 0x9D, 0x98, 0xA3,
+ 0x14, 0x01, 0xC7, 0x05, 0xBB, 0x0F, 0x23, 0x0D,
+ 0x6F, 0x37, 0x57, 0xEC, 0x34, 0x67, 0x41, 0x62,
+ 0xE8, 0x19, 0x75, 0xD9, 0x66, 0x1C, 0x6B, 0x8B,
+ 0xC3, 0x11, 0x26, 0x9C, 0xF7, 0x2E, 0xA3, 0x72,
+ 0xE8, 0xF7, 0xC8, 0x96, 0xEC, 0x92, 0xC2, 0xBD,
+ 0xA1, 0x98, 0x2A, 0x93, 0x99, 0xB8, 0xA2, 0x43,
+ 0xB7, 0xD0, 0xBE, 0x40, 0x1C, 0x8F, 0xE0, 0xB4,
+ 0x20, 0x07, 0x97, 0x43, 0xAE, 0xAD, 0xB3, 0x9F
+};
+
+static const unsigned char RSA_IQ[] = {
+ 0xB7, 0xE2, 0x60, 0xA9, 0x62, 0xEC, 0xEC, 0x0B,
+ 0x57, 0x02, 0x96, 0xF9, 0x36, 0x35, 0x2C, 0x37,
+ 0xAF, 0xC2, 0xEE, 0x71, 0x49, 0x26, 0x8E, 0x0F,
+ 0x27, 0xB1, 0xFA, 0x0F, 0xEA, 0xDC, 0xF0, 0x8B,
+ 0x53, 0x6C, 0xB2, 0x46, 0x27, 0xCD, 0x29, 0xA2,
+ 0x35, 0x0F, 0x5D, 0x8A, 0x3F, 0x20, 0x8C, 0x13,
+ 0x3D, 0xA1, 0xFF, 0x85, 0x91, 0x99, 0xE8, 0x50,
+ 0xED, 0xF1, 0x29, 0x00, 0xEE, 0x24, 0x90, 0xB5,
+ 0x5F, 0x3A, 0x74, 0x26, 0xD7, 0xA2, 0x24, 0x8D,
+ 0x89, 0x88, 0xD8, 0x35, 0x22, 0x22, 0x8A, 0x66,
+ 0x5D, 0x5C, 0xDE, 0x83, 0x8C, 0xFA, 0x27, 0xE6,
+ 0xB9, 0xEB, 0x72, 0x08, 0xCD, 0x53, 0x4B, 0x93,
+ 0x0F, 0xAD, 0xC3, 0xF8, 0x7C, 0xFE, 0x84, 0xD7,
+ 0x08, 0xF3, 0xBE, 0x3D, 0x60, 0x1E, 0x95, 0x8D,
+ 0x44, 0x5B, 0x65, 0x7E, 0xC1, 0x30, 0xC3, 0x84,
+ 0xC0, 0xB0, 0xFE, 0xBF, 0x28, 0x54, 0x1E, 0xC4
+};
+
+static const br_rsa_public_key RSA_PK = {
+ (void *)RSA_N, sizeof RSA_N,
+ (void *)RSA_E, sizeof RSA_E
+};
+
+static const br_rsa_private_key RSA_SK = {
+ 2048,
+ (void *)RSA_P, sizeof RSA_P,
+ (void *)RSA_Q, sizeof RSA_Q,
+ (void *)RSA_DP, sizeof RSA_DP,
+ (void *)RSA_DQ, sizeof RSA_DQ,
+ (void *)RSA_IQ, sizeof RSA_IQ
+};
+
+static void
+test_speed_rsa_inner(char *name,
+ br_rsa_public fpub, br_rsa_private fpriv, br_rsa_keygen kgen)
+{
+ unsigned char tmp[sizeof RSA_N];
+ int i;
+ long num;
+ /*
+ br_hmac_drbg_context rng;
+ */
+ br_aesctr_drbg_context rng;
+ const br_block_ctr_class *ictr;
+
+ memset(tmp, 'R', sizeof tmp);
+ tmp[0] = 0;
+ for (i = 0; i < 10; i ++) {
+ if (!fpriv(tmp, &RSA_SK)) {
+ abort();
+ }
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ fpriv(tmp, &RSA_SK);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f priv/s\n", name,
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+ for (i = 0; i < 10; i ++) {
+ if (!fpub(tmp, sizeof tmp, &RSA_PK)) {
+ abort();
+ }
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ fpub(tmp, sizeof tmp, &RSA_PK);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f pub/s\n", name,
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+
+ if (kgen == 0) {
+ printf("%-30s KEYGEN UNAVAILABLE\n", name);
+ fflush(stdout);
+ return;
+ }
+ /*
+ br_hmac_drbg_init(&rng, &br_sha256_vtable, "RSA keygen seed", 15);
+ */
+ ictr = br_aes_x86ni_ctr_get_vtable();
+ if (ictr == NULL) {
+ ictr = br_aes_pwr8_ctr_get_vtable();
+ if (ictr == NULL) {
+#if BR_64
+ ictr = &br_aes_ct64_ctr_vtable;
+#else
+ ictr = &br_aes_ct_ctr_vtable;
+#endif
+ }
+ }
+ br_aesctr_drbg_init(&rng, ictr, "RSA keygen seed", 15);
+
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ br_rsa_private_key sk;
+ unsigned char kbuf[BR_RSA_KBUF_PRIV_SIZE(1024)];
+
+ kgen(&rng.vtable, &sk, kbuf, NULL, NULL, 1024, 0);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 10.0) {
+ printf("%-30s %8.2f kgen[1024]/s\n", name,
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ br_rsa_private_key sk;
+ unsigned char kbuf[BR_RSA_KBUF_PRIV_SIZE(2048)];
+
+ kgen(&rng.vtable, &sk, kbuf, NULL, NULL, 2048, 0);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 10.0) {
+ printf("%-30s %8.2f kgen[2048]/s\n", name,
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+}
+
+static void
+test_speed_rsa_i15(void)
+{
+ test_speed_rsa_inner("RSA i15",
+ &br_rsa_i15_public, &br_rsa_i15_private, &br_rsa_i15_keygen);
+}
+
+static void
+test_speed_rsa_i31(void)
+{
+ test_speed_rsa_inner("RSA i31",
+ &br_rsa_i31_public, &br_rsa_i31_private, &br_rsa_i31_keygen);
+}
+
+static void
+test_speed_rsa_i32(void)
+{
+ test_speed_rsa_inner("RSA i32",
+ &br_rsa_i32_public, &br_rsa_i32_private, 0);
+}
+
+static void
+test_speed_rsa_i62(void)
+{
+ br_rsa_public pub;
+ br_rsa_private priv;
+ br_rsa_keygen kgen;
+
+ pub = br_rsa_i62_public_get();
+ priv = br_rsa_i62_private_get();
+ kgen = br_rsa_i62_keygen_get();
+ if (pub) {
+ test_speed_rsa_inner("RSA i62", pub, priv, kgen);
+ } else {
+ printf("%-30s UNAVAILABLE\n", "RSA i62");
+ }
+}
+
+static void
+test_speed_ec_inner_1(const char *name,
+ const br_ec_impl *impl, const br_ec_curve_def *cd)
+{
+ unsigned char bx[80], U[160];
+ uint32_t x[22], n[22];
+ size_t nlen, ulen;
+ int i;
+ long num;
+
+ nlen = cd->order_len;
+ br_i31_decode(n, cd->order, nlen);
+ memset(bx, 'T', sizeof bx);
+ br_i31_decode_reduce(x, bx, sizeof bx, n);
+ br_i31_encode(bx, nlen, x);
+ ulen = cd->generator_len;
+ memcpy(U, cd->generator, ulen);
+ for (i = 0; i < 10; i ++) {
+ impl->mul(U, ulen, bx, nlen, cd->curve);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ impl->mul(U, ulen, bx, nlen, cd->curve);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f mul/s\n", name,
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+}
+
+static void
+test_speed_ec_inner_2(const char *name,
+ const br_ec_impl *impl, const br_ec_curve_def *cd)
+{
+ unsigned char bx[80], U[160];
+ uint32_t x[22], n[22];
+ size_t nlen;
+ int i;
+ long num;
+
+ nlen = cd->order_len;
+ br_i31_decode(n, cd->order, nlen);
+ memset(bx, 'T', sizeof bx);
+ br_i31_decode_reduce(x, bx, sizeof bx, n);
+ br_i31_encode(bx, nlen, x);
+ for (i = 0; i < 10; i ++) {
+ impl->mulgen(U, bx, nlen, cd->curve);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ impl->mulgen(U, bx, nlen, cd->curve);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f mul/s\n", name,
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+}
+
+static void
+test_speed_ec_inner(const char *name,
+ const br_ec_impl *impl, const br_ec_curve_def *cd)
+{
+ char tmp[50];
+
+ test_speed_ec_inner_1(name, impl, cd);
+ sprintf(tmp, "%s (FP)", name);
+ test_speed_ec_inner_2(tmp, impl, cd);
+}
+
+static void
+test_speed_ec_p256_m15(void)
+{
+ test_speed_ec_inner("EC p256_m15",
+ &br_ec_p256_m15, &br_secp256r1);
+}
+
+static void
+test_speed_ec_p256_m31(void)
+{
+ test_speed_ec_inner("EC p256_m31",
+ &br_ec_p256_m31, &br_secp256r1);
+}
+
+static void
+test_speed_ec_p256_m62(void)
+{
+ const br_ec_impl *ec;
+
+ ec = br_ec_p256_m62_get();
+ if (ec != NULL) {
+ test_speed_ec_inner("EC p256_m62", ec, &br_secp256r1);
+ } else {
+ printf("%-30s UNAVAILABLE\n", "EC p256_m62");
+ }
+}
+
+static void
+test_speed_ec_p256_m64(void)
+{
+ const br_ec_impl *ec;
+
+ ec = br_ec_p256_m64_get();
+ if (ec != NULL) {
+ test_speed_ec_inner("EC p256_m64", ec, &br_secp256r1);
+ } else {
+ printf("%-30s UNAVAILABLE\n", "EC p256_m64");
+ }
+}
+
+static void
+test_speed_ec_prime_i15(void)
+{
+ test_speed_ec_inner("EC prime_i15 P-256",
+ &br_ec_prime_i15, &br_secp256r1);
+ test_speed_ec_inner("EC prime_i15 P-384",
+ &br_ec_prime_i15, &br_secp384r1);
+ test_speed_ec_inner("EC prime_i15 P-521",
+ &br_ec_prime_i15, &br_secp521r1);
+}
+
+static void
+test_speed_ec_prime_i31(void)
+{
+ test_speed_ec_inner("EC prime_i31 P-256",
+ &br_ec_prime_i31, &br_secp256r1);
+ test_speed_ec_inner("EC prime_i31 P-384",
+ &br_ec_prime_i31, &br_secp384r1);
+ test_speed_ec_inner("EC prime_i31 P-521",
+ &br_ec_prime_i31, &br_secp521r1);
+}
+
+static void
+test_speed_ec_c25519_i15(void)
+{
+ test_speed_ec_inner("EC c25519_i15",
+ &br_ec_c25519_i15, &br_curve25519);
+}
+
+static void
+test_speed_ec_c25519_i31(void)
+{
+ test_speed_ec_inner("EC c25519_i31",
+ &br_ec_c25519_i31, &br_curve25519);
+}
+
+static void
+test_speed_ec_c25519_m15(void)
+{
+ test_speed_ec_inner("EC c25519_m15",
+ &br_ec_c25519_m15, &br_curve25519);
+}
+
+static void
+test_speed_ec_c25519_m31(void)
+{
+ test_speed_ec_inner("EC c25519_m31",
+ &br_ec_c25519_m31, &br_curve25519);
+}
+
+static void
+test_speed_ec_c25519_m62(void)
+{
+ const br_ec_impl *ec;
+
+ ec = br_ec_c25519_m62_get();
+ if (ec != NULL) {
+ test_speed_ec_inner("EC c25519_m62", ec, &br_curve25519);
+ } else {
+ printf("%-30s UNAVAILABLE\n", "EC c25519_m62");
+ }
+}
+
+static void
+test_speed_ec_c25519_m64(void)
+{
+ const br_ec_impl *ec;
+
+ ec = br_ec_c25519_m64_get();
+ if (ec != NULL) {
+ test_speed_ec_inner("EC c25519_m64", ec, &br_curve25519);
+ } else {
+ printf("%-30s UNAVAILABLE\n", "EC c25519_m64");
+ }
+}
+
+static void
+test_speed_ecdsa_inner(const char *name,
+ const br_ec_impl *impl, const br_ec_curve_def *cd,
+ br_ecdsa_sign sign, br_ecdsa_vrfy vrfy)
+{
+ unsigned char bx[80], U[160], hv[32], sig[160];
+ uint32_t x[22], n[22];
+ size_t nlen, ulen, sig_len;
+ int i;
+ long num;
+ br_ec_private_key sk;
+ br_ec_public_key pk;
+
+ nlen = cd->order_len;
+ br_i31_decode(n, cd->order, nlen);
+ memset(bx, 'T', sizeof bx);
+ br_i31_decode_reduce(x, bx, sizeof bx, n);
+ br_i31_encode(bx, nlen, x);
+ ulen = cd->generator_len;
+ memcpy(U, cd->generator, ulen);
+ impl->mul(U, ulen, bx, nlen, cd->curve);
+ sk.curve = cd->curve;
+ sk.x = bx;
+ sk.xlen = nlen;
+ pk.curve = cd->curve;
+ pk.q = U;
+ pk.qlen = ulen;
+
+ memset(hv, 'H', sizeof hv);
+ sig_len = sign(impl, &br_sha256_vtable, hv, &sk, sig);
+ if (vrfy(impl, hv, sizeof hv, &pk, sig, sig_len) != 1) {
+ fprintf(stderr, "self-test sign/verify failed\n");
+ exit(EXIT_FAILURE);
+ }
+
+ for (i = 0; i < 10; i ++) {
+ hv[1] ++;
+ sign(impl, &br_sha256_vtable, hv, &sk, sig);
+ vrfy(impl, hv, sizeof hv, &pk, sig, sig_len);
+ }
+
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ hv[1] ++;
+ sig_len = sign(impl, &br_sha256_vtable, hv, &sk, sig);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f sign/s\n", name,
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ vrfy(impl, hv, sizeof hv, &pk, sig, sig_len);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f verify/s\n", name,
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+}
+
+static void
+test_speed_ecdsa_p256_m15(void)
+{
+ test_speed_ecdsa_inner("ECDSA m15 P-256",
+ &br_ec_p256_m15, &br_secp256r1,
+ &br_ecdsa_i15_sign_asn1,
+ &br_ecdsa_i15_vrfy_asn1);
+}
+
+static void
+test_speed_ecdsa_p256_m31(void)
+{
+ test_speed_ecdsa_inner("ECDSA m31 P-256",
+ &br_ec_p256_m31, &br_secp256r1,
+ &br_ecdsa_i31_sign_asn1,
+ &br_ecdsa_i31_vrfy_asn1);
+}
+
+static void
+test_speed_ecdsa_p256_m62(void)
+{
+ const br_ec_impl *ec;
+
+ ec = br_ec_p256_m62_get();
+ if (ec != NULL) {
+ test_speed_ecdsa_inner("ECDSA m62 P-256",
+ ec, &br_secp256r1,
+ &br_ecdsa_i31_sign_asn1,
+ &br_ecdsa_i31_vrfy_asn1);
+ } else {
+ printf("%-30s UNAVAILABLE\n", "ECDSA m62 P-256");
+ }
+}
+
+static void
+test_speed_ecdsa_p256_m64(void)
+{
+ const br_ec_impl *ec;
+
+ ec = br_ec_p256_m64_get();
+ if (ec != NULL) {
+ test_speed_ecdsa_inner("ECDSA m64 P-256",
+ ec, &br_secp256r1,
+ &br_ecdsa_i31_sign_asn1,
+ &br_ecdsa_i31_vrfy_asn1);
+ } else {
+ printf("%-30s UNAVAILABLE\n", "ECDSA m64 P-256");
+ }
+}
+
+static void
+test_speed_ecdsa_i15(void)
+{
+ test_speed_ecdsa_inner("ECDSA i15 P-256",
+ &br_ec_prime_i15, &br_secp256r1,
+ &br_ecdsa_i15_sign_asn1,
+ &br_ecdsa_i15_vrfy_asn1);
+ test_speed_ecdsa_inner("ECDSA i15 P-384",
+ &br_ec_prime_i15, &br_secp384r1,
+ &br_ecdsa_i15_sign_asn1,
+ &br_ecdsa_i15_vrfy_asn1);
+ test_speed_ecdsa_inner("ECDSA i15 P-521",
+ &br_ec_prime_i15, &br_secp521r1,
+ &br_ecdsa_i15_sign_asn1,
+ &br_ecdsa_i15_vrfy_asn1);
+}
+
+static void
+test_speed_ecdsa_i31(void)
+{
+ test_speed_ecdsa_inner("ECDSA i31 P-256",
+ &br_ec_prime_i31, &br_secp256r1,
+ &br_ecdsa_i31_sign_asn1,
+ &br_ecdsa_i31_vrfy_asn1);
+ test_speed_ecdsa_inner("ECDSA i31 P-384",
+ &br_ec_prime_i31, &br_secp384r1,
+ &br_ecdsa_i31_sign_asn1,
+ &br_ecdsa_i31_vrfy_asn1);
+ test_speed_ecdsa_inner("ECDSA i31 P-521",
+ &br_ec_prime_i31, &br_secp521r1,
+ &br_ecdsa_i31_sign_asn1,
+ &br_ecdsa_i31_vrfy_asn1);
+}
+
+static void
+test_speed_i31(void)
+{
+ static const unsigned char bp[] = {
+ /* A 521-bit prime integer (order of the P-521 curve). */
+ 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
+ };
+
+ unsigned char tmp[60 + sizeof bp];
+ uint32_t p[20], x[20], y[20], z[20], uu[60], p0i;
+ int i;
+ long num;
+
+ br_i31_decode(p, bp, sizeof bp);
+ p0i = br_i31_ninv31(p[1]);
+ memset(tmp, 'T', sizeof tmp);
+ br_i31_decode_reduce(x, tmp, sizeof tmp, p);
+ memset(tmp, 'U', sizeof tmp);
+ br_i31_decode_reduce(y, tmp, sizeof tmp, p);
+
+ for (i = 0; i < 10; i ++) {
+ br_i31_to_monty(x, p);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ br_i31_to_monty(x, p);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f ops/s\n", "i31 to_monty",
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+
+ for (i = 0; i < 10; i ++) {
+ br_i31_from_monty(x, p, p0i);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ br_i31_from_monty(x, p, p0i);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f ops/s\n", "i31 from_monty",
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+
+ for (i = 0; i < 10; i ++) {
+ br_i31_montymul(z, x, y, p, p0i);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ br_i31_montymul(z, x, y, p, p0i);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f ops/s\n", "i31 montymul",
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+
+ for (i = 0; i < 10; i ++) {
+ br_i31_moddiv(x, y, p, p0i, uu);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ br_i31_moddiv(x, y, p, p0i, uu);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f ops/s\n", "i31 moddiv",
+ (double)num / tt);
+ fflush(stdout);
+ break;
+ }
+ num <<= 1;
+ }
+}
+
+#if 0
+
+static unsigned char P2048[] = {
+ 0xFD, 0xB6, 0xE0, 0x3E, 0x00, 0x49, 0x4C, 0xF0, 0x69, 0x3A, 0xDD, 0x7D,
+ 0xF8, 0xA2, 0x41, 0xB0, 0x6C, 0x67, 0xC5, 0xBA, 0xB8, 0x46, 0x80, 0xF5,
+ 0xBF, 0xAB, 0x98, 0xFC, 0x84, 0x73, 0xA5, 0x63, 0xC9, 0x52, 0x12, 0xDA,
+ 0x4C, 0xC1, 0x5B, 0x9D, 0x8D, 0xDF, 0xCD, 0xFE, 0xC5, 0xAD, 0x5A, 0x6F,
+ 0xDD, 0x02, 0xD9, 0xEC, 0x71, 0xEF, 0xEB, 0xB6, 0x95, 0xED, 0x94, 0x25,
+ 0x0E, 0x63, 0xDD, 0x6A, 0x52, 0xC7, 0x93, 0xAF, 0x85, 0x9D, 0x2C, 0xBE,
+ 0x5C, 0xBE, 0x35, 0xD8, 0xDD, 0x39, 0xEF, 0x1B, 0xB1, 0x49, 0x67, 0xB2,
+ 0x33, 0xC9, 0x7C, 0xE1, 0x51, 0x79, 0x51, 0x59, 0xCA, 0x6E, 0x2A, 0xDF,
+ 0x0D, 0x76, 0x1C, 0xE7, 0xA5, 0xC0, 0x1E, 0x6C, 0x56, 0x3A, 0x32, 0xE5,
+ 0xB5, 0xC5, 0xD4, 0xDB, 0xFE, 0xFF, 0xF8, 0xF2, 0x96, 0xA9, 0xC9, 0x65,
+ 0x59, 0x9E, 0x01, 0x79, 0x9D, 0x38, 0x68, 0x0F, 0xAD, 0x43, 0x3A, 0xD6,
+ 0x84, 0x0A, 0xE2, 0xEF, 0x96, 0xC1, 0x6D, 0x89, 0x74, 0x19, 0x63, 0x82,
+ 0x3B, 0xA0, 0x9C, 0xBA, 0x78, 0xDE, 0xDC, 0xC2, 0xE7, 0xD4, 0xFA, 0xD6,
+ 0x19, 0x21, 0x29, 0xAE, 0x5E, 0xF4, 0x38, 0x81, 0xC6, 0x9E, 0x0E, 0x3C,
+ 0xCD, 0xC0, 0xDC, 0x93, 0x5D, 0xFD, 0x9A, 0x5C, 0xAB, 0x54, 0x1F, 0xFF,
+ 0x9C, 0x12, 0x1B, 0x4C, 0xDF, 0x2D, 0x9C, 0x85, 0xF9, 0x68, 0x15, 0x89,
+ 0x42, 0x9B, 0x6C, 0x45, 0x89, 0x3A, 0xBC, 0xE9, 0x19, 0x91, 0xBE, 0x0C,
+ 0xEF, 0x90, 0xCC, 0xF6, 0xD6, 0xF0, 0x3D, 0x5C, 0xF5, 0xE5, 0x0F, 0x2F,
+ 0x02, 0x8A, 0x83, 0x4B, 0x93, 0x2F, 0x14, 0x12, 0x1F, 0x56, 0x9A, 0x12,
+ 0x58, 0x88, 0xAE, 0x60, 0xB8, 0x5A, 0xE4, 0xA1, 0xBF, 0x4A, 0x81, 0x84,
+ 0xAB, 0xBB, 0xE4, 0xD0, 0x1D, 0x41, 0xD9, 0x0A, 0xAB, 0x1E, 0x47, 0x5B,
+ 0x31, 0xAC, 0x2B, 0x73
+};
+
+static unsigned char G2048[] = {
+ 0x02
+};
+
+static void
+test_speed_modpow(void)
+{
+ uint32_t mx[65], mp[65], me[65], t1[65], t2[65], len;
+ unsigned char e[64];
+ int i;
+ long num;
+
+ len = br_int_decode(mp, sizeof mp / sizeof mp[0],
+ P2048, sizeof P2048);
+ if (len != 65) {
+ abort();
+ }
+ memset(e, 'P', sizeof e);
+ if (!br_int_decode(me, sizeof me / sizeof me[0], e, sizeof e)) {
+ abort();
+ }
+ if (!br_modint_decode(mx, mp, G2048, sizeof G2048)) {
+ abort();
+ }
+ for (i = 0; i < 10; i ++) {
+ br_modint_to_monty(mx, mp);
+ br_modint_montypow(mx, me, mp, t1, t2);
+ br_modint_from_monty(mx, mp);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ br_modint_to_monty(mx, mp);
+ br_modint_montypow(mx, me, mp, t1, t2);
+ br_modint_from_monty(mx, mp);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f exp/s\n", "pow[2048:256]",
+ (double)num / tt);
+ fflush(stdout);
+ return;
+ }
+ num <<= 1;
+ }
+}
+
+static void
+test_speed_moddiv(void)
+{
+ uint32_t mx[65], my[65], mp[65], t1[65], t2[65], t3[65], len;
+ unsigned char x[255], y[255];
+ int i;
+ long num;
+
+ len = br_int_decode(mp, sizeof mp / sizeof mp[0],
+ P2048, sizeof P2048);
+ if (len != 65) {
+ abort();
+ }
+ memset(x, 'T', sizeof x);
+ memset(y, 'P', sizeof y);
+ if (!br_modint_decode(mx, mp, x, sizeof x)) {
+ abort();
+ }
+ if (!br_modint_decode(my, mp, y, sizeof y)) {
+ abort();
+ }
+ for (i = 0; i < 10; i ++) {
+ br_modint_div(mx, my, mp, t1, t2, t3);
+ }
+ num = 10;
+ for (;;) {
+ clock_t begin, end;
+ double tt;
+ long k;
+
+ begin = clock();
+ for (k = num; k > 0; k --) {
+ br_modint_div(mx, my, mp, t1, t2, t3);
+ }
+ end = clock();
+ tt = (double)(end - begin) / CLOCKS_PER_SEC;
+ if (tt >= 2.0) {
+ printf("%-30s %8.2f div/s\n", "div[2048]",
+ (double)num / tt);
+ fflush(stdout);
+ return;
+ }
+ num <<= 1;
+ }
+}
+#endif
+
+#define STU(x) { test_speed_ ## x, #x }
+
+static const struct {
+ void (*fn)(void);
+ char *name;
+} tfns[] = {
+ STU(md5),
+ STU(sha1),
+ STU(sha256),
+ STU(sha512),
+
+ STU(aes128_big_cbcenc),
+ STU(aes128_big_cbcdec),
+ STU(aes192_big_cbcenc),
+ STU(aes192_big_cbcdec),
+ STU(aes256_big_cbcenc),
+ STU(aes256_big_cbcdec),
+ STU(aes128_big_ctr),
+ STU(aes192_big_ctr),
+ STU(aes256_big_ctr),
+
+ STU(aes128_small_cbcenc),
+ STU(aes128_small_cbcdec),
+ STU(aes192_small_cbcenc),
+ STU(aes192_small_cbcdec),
+ STU(aes256_small_cbcenc),
+ STU(aes256_small_cbcdec),
+ STU(aes128_small_ctr),
+ STU(aes192_small_ctr),
+ STU(aes256_small_ctr),
+
+ STU(aes128_ct_cbcenc),
+ STU(aes128_ct_cbcdec),
+ STU(aes192_ct_cbcenc),
+ STU(aes192_ct_cbcdec),
+ STU(aes256_ct_cbcenc),
+ STU(aes256_ct_cbcdec),
+ STU(aes128_ct_ctr),
+ STU(aes192_ct_ctr),
+ STU(aes256_ct_ctr),
+
+ STU(aes128_ct64_cbcenc),
+ STU(aes128_ct64_cbcdec),
+ STU(aes192_ct64_cbcenc),
+ STU(aes192_ct64_cbcdec),
+ STU(aes256_ct64_cbcenc),
+ STU(aes256_ct64_cbcdec),
+ STU(aes128_ct64_ctr),
+ STU(aes192_ct64_ctr),
+ STU(aes256_ct64_ctr),
+
+ STU(aes128_x86ni_cbcenc),
+ STU(aes128_x86ni_cbcdec),
+ STU(aes192_x86ni_cbcenc),
+ STU(aes192_x86ni_cbcdec),
+ STU(aes256_x86ni_cbcenc),
+ STU(aes256_x86ni_cbcdec),
+ STU(aes128_x86ni_ctr),
+ STU(aes192_x86ni_ctr),
+ STU(aes256_x86ni_ctr),
+
+ STU(aes128_pwr8_cbcenc),
+ STU(aes128_pwr8_cbcdec),
+ STU(aes192_pwr8_cbcenc),
+ STU(aes192_pwr8_cbcdec),
+ STU(aes256_pwr8_cbcenc),
+ STU(aes256_pwr8_cbcdec),
+ STU(aes128_pwr8_ctr),
+ STU(aes192_pwr8_ctr),
+ STU(aes256_pwr8_ctr),
+
+ STU(des_tab_cbcenc),
+ STU(des_tab_cbcdec),
+ STU(3des_tab_cbcenc),
+ STU(3des_tab_cbcdec),
+
+ STU(des_ct_cbcenc),
+ STU(des_ct_cbcdec),
+ STU(3des_ct_cbcenc),
+ STU(3des_ct_cbcdec),
+
+ STU(chacha20_ct),
+ STU(chacha20_sse2),
+
+ STU(ghash_ctmul),
+ STU(ghash_ctmul32),
+ STU(ghash_ctmul64),
+ STU(ghash_pclmul),
+ STU(ghash_pwr8),
+
+ STU(poly1305_ctmul),
+ STU(poly1305_ctmul32),
+ STU(poly1305_ctmulq),
+ STU(poly1305_i15),
+
+ STU(eax_aes128_big),
+ STU(eax_aes192_big),
+ STU(eax_aes256_big),
+ STU(eax_aes128_small),
+ STU(eax_aes192_small),
+ STU(eax_aes256_small),
+ STU(eax_aes128_ct),
+ STU(eax_aes192_ct),
+ STU(eax_aes256_ct),
+ STU(eax_aes128_ct64),
+ STU(eax_aes192_ct64),
+ STU(eax_aes256_ct64),
+ STU(eax_aes128_x86ni),
+ STU(eax_aes192_x86ni),
+ STU(eax_aes256_x86ni),
+ STU(eax_aes128_pwr8),
+ STU(eax_aes192_pwr8),
+ STU(eax_aes256_pwr8),
+
+ STU(shake128),
+ STU(shake256),
+
+ STU(rsa_i15),
+ STU(rsa_i31),
+ STU(rsa_i32),
+ STU(rsa_i62),
+ STU(ec_prime_i15),
+ STU(ec_prime_i31),
+ STU(ec_p256_m15),
+ STU(ec_p256_m31),
+ STU(ec_p256_m62),
+ STU(ec_p256_m64),
+ STU(ec_c25519_i15),
+ STU(ec_c25519_i31),
+ STU(ec_c25519_m15),
+ STU(ec_c25519_m31),
+ STU(ec_c25519_m62),
+ STU(ec_c25519_m64),
+ STU(ecdsa_p256_m15),
+ STU(ecdsa_p256_m31),
+ STU(ecdsa_p256_m62),
+ STU(ecdsa_p256_m64),
+ STU(ecdsa_i15),
+ STU(ecdsa_i31),
+
+ STU(i31)
+};
+
+static int
+eq_name(const char *s1, const char *s2)
+{
+ for (;;) {
+ int c1, c2;
+
+ for (;;) {
+ c1 = *s1 ++;
+ if (c1 >= 'A' && c1 <= 'Z') {
+ c1 += 'a' - 'A';
+ } else {
+ switch (c1) {
+ case '-': case '_': case '.': case ' ':
+ continue;
+ }
+ }
+ break;
+ }
+ for (;;) {
+ c2 = *s2 ++;
+ if (c2 >= 'A' && c2 <= 'Z') {
+ c2 += 'a' - 'A';
+ } else {
+ switch (c2) {
+ case '-': case '_': case '.': case ' ':
+ continue;
+ }
+ }
+ break;
+ }
+ if (c1 != c2) {
+ return 0;
+ }
+ if (c1 == 0) {
+ return 1;
+ }
+ }
+}
+
+int
+main(int argc, char *argv[])
+{
+ size_t u;
+
+ if (argc <= 1) {
+ printf("usage: testspeed all | name...\n");
+ printf("individual test names:\n");
+ for (u = 0; u < (sizeof tfns) / (sizeof tfns[0]); u ++) {
+ printf(" %s\n", tfns[u].name);
+ }
+ } else {
+ for (u = 0; u < (sizeof tfns) / (sizeof tfns[0]); u ++) {
+ int i;
+
+ for (i = 1; i < argc; i ++) {
+ if (eq_name(argv[i], tfns[u].name)
+ || eq_name(argv[i], "all"))
+ {
+ tfns[u].fn();
+ break;
+ }
+ }
+ }
+ }
+ return 0;
+}
diff --git a/contrib/bearssl/test/test_x509.c b/contrib/bearssl/test/test_x509.c
new file mode 100644
index 000000000000..2c61cf5dd245
--- /dev/null
+++ b/contrib/bearssl/test/test_x509.c
@@ -0,0 +1,2058 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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>
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <unistd.h>
+#endif
+
+#include "bearssl.h"
+
+#define STR(x) STR_(x)
+#define STR_(x) #x
+#ifdef SRCDIRNAME
+#define DIRNAME STR(SRCDIRNAME) "/test/x509"
+#else
+#define DIRNAME "test/x509"
+#endif
+#define CONFFILE DIRNAME "/alltests.txt"
+#define DEFAULT_TIME "2016-08-30T18:00:00Z"
+
+static void *
+xmalloc(size_t len)
+{
+ void *buf;
+
+ if (len == 0) {
+ return NULL;
+ }
+ buf = malloc(len);
+ if (buf == NULL) {
+ fprintf(stderr, "error: cannot allocate %lu byte(s)\n",
+ (unsigned long)len);
+ exit(EXIT_FAILURE);
+ }
+ return buf;
+}
+
+static void
+xfree(void *buf)
+{
+ if (buf != NULL) {
+ free(buf);
+ }
+}
+
+static char *
+xstrdup(const char *name)
+{
+ size_t n;
+ char *s;
+
+ if (name == NULL) {
+ return NULL;
+ }
+ n = strlen(name) + 1;
+ s = xmalloc(n);
+ memcpy(s, name, n);
+ return s;
+}
+
+typedef struct {
+ char *buf;
+ size_t ptr, len;
+} string_builder;
+
+static string_builder *
+SB_new(void)
+{
+ string_builder *sb;
+
+ sb = xmalloc(sizeof *sb);
+ sb->len = 8;
+ sb->buf = xmalloc(sb->len);
+ sb->ptr = 0;
+ return sb;
+}
+
+static void
+SB_expand(string_builder *sb, size_t extra_len)
+{
+ size_t nlen;
+ char *nbuf;
+
+ if (extra_len < (sb->len - sb->ptr)) {
+ return;
+ }
+ nlen = sb->len << 1;
+ if (extra_len > (nlen - sb->ptr)) {
+ nlen = sb->ptr + extra_len;
+ }
+ nbuf = xmalloc(nlen);
+ memcpy(nbuf, sb->buf, sb->ptr);
+ xfree(sb->buf);
+ sb->buf = nbuf;
+ sb->len = nlen;
+}
+
+static void
+SB_append_char(string_builder *sb, int c)
+{
+ SB_expand(sb, 1);
+ sb->buf[sb->ptr ++] = c;
+}
+
+/* unused
+static void
+SB_append_string(string_builder *sb, const char *s)
+{
+ size_t n;
+
+ n = strlen(s);
+ SB_expand(sb, n);
+ memcpy(sb->buf + sb->ptr, s, n);
+ sb->ptr += n;
+}
+*/
+
+/* unused
+static char *
+SB_to_string(string_builder *sb)
+{
+ char *s;
+
+ s = xmalloc(sb->ptr + 1);
+ memcpy(s, sb->buf, sb->ptr);
+ s[sb->ptr] = 0;
+ return s;
+}
+*/
+
+static char *
+SB_contents(string_builder *sb)
+{
+ return sb->buf;
+}
+
+static size_t
+SB_length(string_builder *sb)
+{
+ return sb->ptr;
+}
+
+static void
+SB_set_length(string_builder *sb, size_t len)
+{
+ if (sb->ptr < len) {
+ SB_expand(sb, len - sb->ptr);
+ memset(sb->buf + sb->ptr, ' ', len - sb->ptr);
+ }
+ sb->ptr = len;
+}
+
+static void
+SB_reset(string_builder *sb)
+{
+ SB_set_length(sb, 0);
+}
+
+static void
+SB_free(string_builder *sb)
+{
+ xfree(sb->buf);
+ xfree(sb);
+}
+
+typedef struct ht_elt_ {
+ char *name;
+ void *value;
+ struct ht_elt_ *next;
+} ht_elt;
+
+typedef struct {
+ size_t size;
+ ht_elt **buckets;
+ size_t num_buckets;
+} HT;
+
+static HT *
+HT_new(void)
+{
+ HT *ht;
+ size_t u;
+
+ ht = xmalloc(sizeof *ht);
+ ht->size = 0;
+ ht->num_buckets = 8;
+ ht->buckets = xmalloc(ht->num_buckets * sizeof(ht_elt *));
+ for (u = 0; u < ht->num_buckets; u ++) {
+ ht->buckets[u] = NULL;
+ }
+ return ht;
+}
+
+static uint32_t
+hash_string(const char *name)
+{
+ uint32_t hc;
+
+ hc = 0;
+ while (*name) {
+ int x;
+
+ hc = (hc << 5) - hc;
+ x = *(const unsigned char *)name;
+ if (x >= 'A' && x <= 'Z') {
+ x += 'a' - 'A';
+ }
+ hc += (uint32_t)x;
+ name ++;
+ }
+ return hc;
+}
+
+static int
+eqstring(const char *s1, const char *s2)
+{
+ while (*s1 && *s2) {
+ int x1, x2;
+
+ x1 = *(const unsigned char *)s1;
+ x2 = *(const unsigned char *)s2;
+ if (x1 >= 'A' && x1 <= 'Z') {
+ x1 += 'a' - 'A';
+ }
+ if (x2 >= 'A' && x2 <= 'Z') {
+ x2 += 'a' - 'A';
+ }
+ if (x1 != x2) {
+ return 0;
+ }
+ s1 ++;
+ s2 ++;
+ }
+ return !(*s1 || *s2);
+}
+
+static void
+HT_expand(HT *ht)
+{
+ size_t n, n2, u;
+ ht_elt **new_buckets;
+
+ n = ht->num_buckets;
+ n2 = n << 1;
+ new_buckets = xmalloc(n2 * sizeof *new_buckets);
+ for (u = 0; u < n2; u ++) {
+ new_buckets[u] = NULL;
+ }
+ for (u = 0; u < n; u ++) {
+ ht_elt *e, *f;
+
+ f = NULL;
+ for (e = ht->buckets[u]; e != NULL; e = f) {
+ uint32_t hc;
+ size_t v;
+
+ hc = hash_string(e->name);
+ v = (size_t)(hc & ((uint32_t)n2 - 1));
+ f = e->next;
+ e->next = new_buckets[v];
+ new_buckets[v] = e;
+ }
+ }
+ xfree(ht->buckets);
+ ht->buckets = new_buckets;
+ ht->num_buckets = n2;
+}
+
+static void *
+HT_put(HT *ht, const char *name, void *value)
+{
+ uint32_t hc;
+ size_t k;
+ ht_elt *e, **prev;
+
+ hc = hash_string(name);
+ k = (size_t)(hc & ((uint32_t)ht->num_buckets - 1));
+ prev = &ht->buckets[k];
+ e = *prev;
+ while (e != NULL) {
+ if (eqstring(name, e->name)) {
+ void *old_value;
+
+ old_value = e->value;
+ if (value == NULL) {
+ *prev = e->next;
+ xfree(e->name);
+ xfree(e);
+ ht->size --;
+ } else {
+ e->value = value;
+ }
+ return old_value;
+ }
+ prev = &e->next;
+ e = *prev;
+ }
+ if (value != NULL) {
+ e = xmalloc(sizeof *e);
+ e->name = xstrdup(name);
+ e->value = value;
+ e->next = ht->buckets[k];
+ ht->buckets[k] = e;
+ ht->size ++;
+ if (ht->size > ht->num_buckets) {
+ HT_expand(ht);
+ }
+ }
+ return NULL;
+}
+
+/* unused
+static void *
+HT_remove(HT *ht, const char *name)
+{
+ return HT_put(ht, name, NULL);
+}
+*/
+
+static void *
+HT_get(const HT *ht, const char *name)
+{
+ uint32_t hc;
+ size_t k;
+ ht_elt *e;
+
+ hc = hash_string(name);
+ k = (size_t)(hc & ((uint32_t)ht->num_buckets - 1));
+ for (e = ht->buckets[k]; e != NULL; e = e->next) {
+ if (eqstring(name, e->name)) {
+ return e->value;
+ }
+ }
+ return NULL;
+}
+
+static void
+HT_clear(HT *ht, void (*free_value)(void *value))
+{
+ size_t u;
+
+ for (u = 0; u < ht->num_buckets; u ++) {
+ ht_elt *e, *f;
+
+ f = NULL;
+ for (e = ht->buckets[u]; e != NULL; e = f) {
+ f = e->next;
+ xfree(e->name);
+ if (free_value != 0) {
+ free_value(e->value);
+ }
+ xfree(e);
+ }
+ ht->buckets[u] = NULL;
+ }
+ ht->size = 0;
+}
+
+static void
+HT_free(HT *ht, void (*free_value)(void *value))
+{
+ HT_clear(ht, free_value);
+ xfree(ht->buckets);
+ xfree(ht);
+}
+
+/* unused
+static size_t
+HT_size(HT *ht)
+{
+ return ht->size;
+}
+*/
+
+static unsigned char *
+read_all(FILE *f, size_t *len)
+{
+ unsigned char *buf;
+ size_t ptr, blen;
+
+ blen = 1024;
+ buf = xmalloc(blen);
+ ptr = 0;
+ for (;;) {
+ size_t rlen;
+
+ if (ptr == blen) {
+ unsigned char *buf2;
+
+ blen <<= 1;
+ buf2 = xmalloc(blen);
+ memcpy(buf2, buf, ptr);
+ xfree(buf);
+ buf = buf2;
+ }
+ rlen = fread(buf + ptr, 1, blen - ptr, f);
+ if (rlen == 0) {
+ unsigned char *buf3;
+
+ buf3 = xmalloc(ptr);
+ memcpy(buf3, buf, ptr);
+ xfree(buf);
+ *len = ptr;
+ return buf3;
+ }
+ ptr += rlen;
+ }
+}
+
+static unsigned char *
+read_file(const char *name, size_t *len)
+{
+ FILE *f;
+ unsigned char *buf;
+
+#ifdef DIRNAME
+ char *dname;
+
+ dname = xmalloc(strlen(DIRNAME) + strlen(name) + 2);
+ sprintf(dname, "%s/%s", DIRNAME, name);
+ name = dname;
+#endif
+ f = fopen(name, "rb");
+ if (f == NULL) {
+ fprintf(stderr, "could not open file '%s'\n", name);
+ exit(EXIT_FAILURE);
+ }
+ buf = read_all(f, len);
+ if (ferror(f)) {
+ fprintf(stderr, "read error on file '%s'\n", name);
+ exit(EXIT_FAILURE);
+ }
+ fclose(f);
+#ifdef DIRNAME
+ xfree(dname);
+#endif
+ return buf;
+}
+
+static int
+parse_dec(const char *s, unsigned len, int *val)
+{
+ int acc;
+
+ acc = 0;
+ while (len -- > 0) {
+ int c;
+
+ c = *s ++;
+ if (c >= '0' && c <= '9') {
+ acc = (acc * 10) + (c - '0');
+ } else {
+ return -1;
+ }
+ }
+ *val = acc;
+ return 0;
+}
+
+static int
+parse_choice(const char *s, const char *acceptable)
+{
+ int c;
+
+ c = *s;
+ while (*acceptable) {
+ if (c == *acceptable ++) {
+ return 0;
+ }
+ }
+ return -1;
+}
+
+static int
+month_length(int year, int month)
+{
+ static const int base_month_length[] = {
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+ };
+
+ int x;
+
+ x = base_month_length[month - 1];
+ if (month == 2 && year % 4 == 0
+ && (year % 100 != 0 || year % 400 == 0))
+ {
+ x ++;
+ }
+ return x;
+}
+
+/*
+ * Convert a time string to a days+seconds count. Returned value is 0
+ * on success, -1 on error.
+ */
+static int
+string_to_time(const char *s, uint32_t *days, uint32_t *seconds)
+{
+ int year, month, day, hour, minute, second;
+ int day_of_year, leaps, i;
+
+ if (parse_dec(s, 4, &year) < 0) {
+ return -1;
+ }
+ s += 4;
+ if (parse_choice(s ++, "-:/ ") < 0) {
+ return -1;
+ }
+ if (parse_dec(s, 2, &month) < 0) {
+ return -1;
+ }
+ s += 2;
+ if (parse_choice(s ++, "-:/ ") < 0) {
+ return -1;
+ }
+ if (parse_dec(s, 2, &day) < 0) {
+ return -1;
+ }
+ s += 2;
+ if (parse_choice(s ++, " T") < 0) {
+ return -1;
+ }
+ if (parse_dec(s, 2, &hour) < 0) {
+ return -1;
+ }
+ s += 2;
+ if (parse_choice(s ++, "-:/ ") < 0) {
+ return -1;
+ }
+ if (parse_dec(s, 2, &minute) < 0) {
+ return -1;
+ }
+ s += 2;
+ if (parse_choice(s ++, "-:/ ") < 0) {
+ return -1;
+ }
+ if (parse_dec(s, 2, &second) < 0) {
+ return -1;
+ }
+ s += 2;
+ if (*s == '.') {
+ while (*s && *s >= '0' && *s <= '9') {
+ s ++;
+ }
+ }
+ if (*s) {
+ if (*s ++ != 'Z') {
+ return -1;
+ }
+ if (*s) {
+ return -1;
+ }
+ }
+
+ if (month < 1 || month > 12) {
+ return -1;
+ }
+ day_of_year = 0;
+ for (i = 1; i < month; i ++) {
+ day_of_year += month_length(year, i);
+ }
+ if (day < 1 || day > month_length(year, month)) {
+ return -1;
+ }
+ day_of_year += (day - 1);
+ leaps = (year + 3) / 4 - (year + 99) / 100 + (year + 399) / 400;
+
+ if (hour > 23 || minute > 59 || second > 60) {
+ return -1;
+ }
+ *days = (uint32_t)year * 365 + (uint32_t)leaps + day_of_year;
+ *seconds = (uint32_t)hour * 3600 + minute * 60 + second;
+ return 0;
+}
+
+static FILE *conf;
+static int conf_delayed_char;
+static long conf_linenum;
+static string_builder *line_builder;
+static long current_linenum;
+
+static void
+conf_init(const char *fname)
+{
+ conf = fopen(fname, "r");
+ if (conf == NULL) {
+ fprintf(stderr, "could not open file '%s'\n", fname);
+ exit(EXIT_FAILURE);
+ }
+ conf_delayed_char = -1;
+ conf_linenum = 1;
+ line_builder = SB_new();
+}
+
+static void
+conf_close(void)
+{
+ if (conf != NULL) {
+ if (ferror(conf)) {
+ fprintf(stderr, "read error on configuration file\n");
+ exit(EXIT_FAILURE);
+ }
+ fclose(conf);
+ conf = NULL;
+ }
+ if (line_builder != NULL) {
+ SB_free(line_builder);
+ line_builder = NULL;
+ }
+}
+
+/*
+ * Get next character from the config file.
+ */
+static int
+conf_next_low(void)
+{
+ int x;
+
+ x = conf_delayed_char;
+ if (x >= 0) {
+ conf_delayed_char = -1;
+ } else {
+ x = fgetc(conf);
+ if (x == EOF) {
+ x = -1;
+ }
+ }
+ if (x == '\r') {
+ x = fgetc(conf);
+ if (x == EOF) {
+ x = -1;
+ }
+ if (x != '\n') {
+ conf_delayed_char = x;
+ x = '\n';
+ }
+ }
+ if (x == '\n') {
+ conf_linenum ++;
+ }
+ return x;
+}
+
+static int
+is_ws(int x)
+{
+ return x <= 32;
+}
+
+static int
+is_name_char(int c)
+{
+ return (c >= 'A' && c <= 'Z')
+ || (c >= 'a' && c <= 'z')
+ || (c >= '0' && c <= '9')
+ || (c == '_' || c == '-' || c == '.');
+}
+
+/*
+ * Read a complete line. This handles line continuation; empty lines and
+ * comment lines are skipped; leading and trailing whitespace is removed.
+ * Returned value is 0 (line read) or -1 (no line, EOF reached). The line
+ * contents are accumulated in the line_builder.
+ */
+static int
+conf_next_line(void)
+{
+ for (;;) {
+ int c;
+ int lcwb;
+
+ SB_reset(line_builder);
+
+ /*
+ * Get first non-whitespace character. This skips empty
+ * lines. Comment lines (first non-whitespace character
+ * is a semicolon) are also skipped.
+ */
+ for (;;) {
+ c = conf_next_low();
+ if (c < 0) {
+ return -1;
+ }
+ if (is_ws(c)) {
+ continue;
+ }
+ if (c == ';') {
+ for (;;) {
+ c = conf_next_low();
+ if (c < 0) {
+ return -1;
+ }
+ if (c == '\n') {
+ break;
+ }
+ }
+ continue;
+ }
+ break;
+ }
+
+ /*
+ * Read up the remaining of the line. The line continuation
+ * sequence (final backslash) is detected and processed.
+ */
+ current_linenum = conf_linenum;
+ lcwb = (c == '\\');
+ SB_append_char(line_builder, c);
+ for (;;) {
+ c = conf_next_low();
+ if (c < 0) {
+ break;
+ }
+ if (lcwb) {
+ if (c == '\n') {
+ SB_set_length(line_builder,
+ SB_length(line_builder) - 1);
+ }
+ lcwb = 0;
+ continue;
+ }
+ if (c == '\n') {
+ break;
+ } else if (c == '\\') {
+ lcwb = 1;
+ }
+ SB_append_char(line_builder, c);
+ }
+
+ /*
+ * Remove trailing whitespace (if any).
+ */
+ for (;;) {
+ size_t u;
+
+ u = SB_length(line_builder);
+ if (u == 0 || !is_ws(
+ SB_contents(line_builder)[u - 1]))
+ {
+ break;
+ }
+ SB_set_length(line_builder, u - 1);
+ }
+
+ /*
+ * We might end up with a totally empty line (in case there
+ * was a line continuation but nothing else), in which case
+ * we must loop.
+ */
+ if (SB_length(line_builder) > 0) {
+ return 0;
+ }
+ }
+}
+
+/*
+ * Test whether the current line is a section header. If yes, then the
+ * header name is extracted, and returned as a newly allocated string.
+ * Otherwise, NULL is returned.
+ */
+static char *
+parse_header_name(void)
+{
+ char *buf, *name;
+ size_t u, v, w, len;
+
+ buf = SB_contents(line_builder);
+ len = SB_length(line_builder);
+ if (len < 2 || buf[0] != '[' || buf[len - 1] != ']') {
+ return NULL;
+ }
+ u = 1;
+ v = len - 1;
+ while (u < v && is_ws(buf[u])) {
+ u ++;
+ }
+ while (u < v && is_ws(buf[v - 1])) {
+ v --;
+ }
+ if (u == v) {
+ return NULL;
+ }
+ for (w = u; w < v; w ++) {
+ if (!is_name_char(buf[w])) {
+ return NULL;
+ }
+ }
+ len = v - u;
+ name = xmalloc(len + 1);
+ memcpy(name, buf + u, len);
+ name[len] = 0;
+ return name;
+}
+
+/*
+ * Parse the current line as a 'name = value' pair. The pair is pushed into
+ * the provided hash table. On error (including a duplicate key name),
+ * this function returns -1; otherwise, it returns 0.
+ */
+static int
+parse_keyvalue(HT *d)
+{
+ char *buf, *name, *value;
+ size_t u, len;
+
+ buf = SB_contents(line_builder);
+ len = SB_length(line_builder);
+ for (u = 0; u < len; u ++) {
+ if (!is_name_char(buf[u])) {
+ break;
+ }
+ }
+ if (u == 0) {
+ return -1;
+ }
+ name = xmalloc(u + 1);
+ memcpy(name, buf, u);
+ name[u] = 0;
+ if (HT_get(d, name) != NULL) {
+ xfree(name);
+ return -1;
+ }
+ while (u < len && is_ws(buf[u])) {
+ u ++;
+ }
+ if (u >= len || buf[u] != '=') {
+ xfree(name);
+ return -1;
+ }
+ u ++;
+ while (u < len && is_ws(buf[u])) {
+ u ++;
+ }
+ value = xmalloc(len - u + 1);
+ memcpy(value, buf + u, len - u);
+ value[len - u] = 0;
+ HT_put(d, name, value);
+ xfree(name);
+ return 0;
+}
+
+/*
+ * Public keys, indexed by name. Elements are pointers to br_x509_pkey
+ * structures.
+ */
+static HT *keys;
+
+/*
+ * Trust anchors, indexed by name. Elements are pointers to
+ * test_trust_anchor structures.
+ */
+static HT *trust_anchors;
+
+typedef struct {
+ unsigned char *dn;
+ size_t dn_len;
+ unsigned flags;
+ char *key_name;
+} test_trust_anchor;
+
+/*
+ * Test case: trust anchors, certificates (file names), key type and
+ * usage, expected status and EE public key.
+ */
+typedef struct {
+ char *name;
+ char **ta_names;
+ char **cert_names;
+ char *servername;
+ unsigned key_type_usage;
+ unsigned status;
+ char *ee_key_name;
+ unsigned hashes;
+ uint32_t days, seconds;
+} test_case;
+
+static test_case *all_chains;
+static size_t all_chains_ptr, all_chains_len;
+
+static void
+free_key(void *value)
+{
+ br_x509_pkey *pk;
+
+ pk = value;
+ switch (pk->key_type) {
+ case BR_KEYTYPE_RSA:
+ xfree((void *)pk->key.rsa.n);
+ xfree((void *)pk->key.rsa.e);
+ break;
+ case BR_KEYTYPE_EC:
+ xfree((void *)pk->key.ec.q);
+ break;
+ default:
+ fprintf(stderr, "unknown key type: %d\n", pk->key_type);
+ exit(EXIT_FAILURE);
+ break;
+ }
+ xfree(pk);
+}
+
+static void
+free_trust_anchor(void *value)
+{
+ test_trust_anchor *ttc;
+
+ ttc = value;
+ xfree(ttc->dn);
+ xfree(ttc->key_name);
+ xfree(ttc);
+}
+
+static void
+free_test_case_contents(test_case *tc)
+{
+ size_t u;
+
+ xfree(tc->name);
+ for (u = 0; tc->ta_names[u]; u ++) {
+ xfree(tc->ta_names[u]);
+ }
+ xfree(tc->ta_names);
+ for (u = 0; tc->cert_names[u]; u ++) {
+ xfree(tc->cert_names[u]);
+ }
+ xfree(tc->cert_names);
+ xfree(tc->servername);
+ xfree(tc->ee_key_name);
+}
+
+static char *
+get_value(char *objtype, HT *objdata, long linenum, char *name)
+{
+ char *value;
+
+ value = HT_get(objdata, name);
+ if (value == NULL) {
+ fprintf(stderr,
+ "missing property '%s' in section '%s' (line %ld)\n",
+ name, objtype, linenum);
+ exit(EXIT_FAILURE);
+ }
+ return value;
+}
+
+static unsigned char *
+parse_hex(const char *name, long linenum, const char *value, size_t *len)
+{
+ unsigned char *buf;
+
+ buf = NULL;
+ for (;;) {
+ size_t u, ptr;
+ int acc, z;
+
+ ptr = 0;
+ acc = 0;
+ z = 0;
+ for (u = 0; value[u]; u ++) {
+ int c;
+
+ c = value[u];
+ if (c >= '0' && c <= '9') {
+ c -= '0';
+ } else if (c >= 'A' && c <= 'F') {
+ c -= 'A' - 10;
+ } else if (c >= 'a' && c <= 'f') {
+ c -= 'a' - 10;
+ } else if (c == ' ' || c == ':') {
+ continue;
+ } else {
+ fprintf(stderr, "invalid hexadecimal character"
+ " in '%s' (line %ld)\n",
+ name, linenum);
+ exit(EXIT_FAILURE);
+ }
+ if (z) {
+ if (buf != NULL) {
+ buf[ptr] = (acc << 4) + c;
+ }
+ ptr ++;
+ } else {
+ acc = c;
+ }
+ z = !z;
+ }
+ if (z) {
+ fprintf(stderr, "invalid hexadecimal value (partial"
+ " byte) in '%s' (line %ld)\n",
+ name, linenum);
+ exit(EXIT_FAILURE);
+ }
+ if (buf == NULL) {
+ buf = xmalloc(ptr);
+ } else {
+ *len = ptr;
+ return buf;
+ }
+ }
+}
+
+static char **
+split_names(const char *value)
+{
+ char **names;
+ size_t len;
+
+ names = NULL;
+ len = strlen(value);
+ for (;;) {
+ size_t u, ptr;
+
+ ptr = 0;
+ u = 0;
+ while (u < len) {
+ size_t v;
+
+ while (u < len && is_ws(value[u])) {
+ u ++;
+ }
+ v = u;
+ while (v < len && !is_ws(value[v])) {
+ v ++;
+ }
+ if (v > u) {
+ if (names != NULL) {
+ char *name;
+
+ name = xmalloc(v - u + 1);
+ memcpy(name, value + u, v - u);
+ name[v - u] = 0;
+ names[ptr] = name;
+ }
+ ptr ++;
+ }
+ u = v;
+ }
+ if (names == NULL) {
+ names = xmalloc((ptr + 1) * sizeof *names);
+ } else {
+ names[ptr] = NULL;
+ return names;
+ }
+ }
+}
+
+static int
+string_to_hash(const char *name)
+{
+ char tmp[20];
+ size_t u, v;
+
+ for (u = 0, v = 0; name[u]; u ++) {
+ int c;
+
+ c = name[u];
+ if ((c >= '0' && c <= '9')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= 'a' && c <= 'z'))
+ {
+ tmp[v ++] = c;
+ if (v == sizeof tmp) {
+ return -1;
+ }
+ }
+ }
+ tmp[v] = 0;
+ if (eqstring(tmp, "md5")) {
+ return br_md5_ID;
+ } else if (eqstring(tmp, "sha1")) {
+ return br_sha1_ID;
+ } else if (eqstring(tmp, "sha224")) {
+ return br_sha224_ID;
+ } else if (eqstring(tmp, "sha256")) {
+ return br_sha256_ID;
+ } else if (eqstring(tmp, "sha384")) {
+ return br_sha384_ID;
+ } else if (eqstring(tmp, "sha512")) {
+ return br_sha512_ID;
+ } else {
+ return -1;
+ }
+}
+
+static int
+string_to_curve(const char *name)
+{
+ char tmp[20];
+ size_t u, v;
+
+ for (u = 0, v = 0; name[u]; u ++) {
+ int c;
+
+ c = name[u];
+ if ((c >= '0' && c <= '9')
+ || (c >= 'A' && c <= 'Z')
+ || (c >= 'a' && c <= 'z'))
+ {
+ tmp[v ++] = c;
+ if (v == sizeof tmp) {
+ return -1;
+ }
+ }
+ }
+ tmp[v] = 0;
+ if (eqstring(tmp, "p256") || eqstring(tmp, "secp256r1")) {
+ return BR_EC_secp256r1;
+ } else if (eqstring(tmp, "p384") || eqstring(tmp, "secp384r1")) {
+ return BR_EC_secp384r1;
+ } else if (eqstring(tmp, "p521") || eqstring(tmp, "secp521r1")) {
+ return BR_EC_secp521r1;
+ } else {
+ return -1;
+ }
+}
+
+static void
+parse_object(char *objtype, HT *objdata, long linenum)
+{
+ char *name;
+
+ name = get_value(objtype, objdata, linenum, "name");
+ if (eqstring(objtype, "key")) {
+ char *stype;
+ br_x509_pkey *pk;
+
+ stype = get_value(objtype, objdata, linenum, "type");
+ pk = xmalloc(sizeof *pk);
+ if (eqstring(stype, "RSA")) {
+ char *sn, *se;
+
+ sn = get_value(objtype, objdata, linenum, "n");
+ se = get_value(objtype, objdata, linenum, "e");
+ pk->key_type = BR_KEYTYPE_RSA;
+ pk->key.rsa.n = parse_hex("modulus", linenum,
+ sn, &pk->key.rsa.nlen);
+ pk->key.rsa.e = parse_hex("exponent", linenum,
+ se, &pk->key.rsa.elen);
+ } else if (eqstring(stype, "EC")) {
+ char *sc, *sq;
+ int curve;
+
+ sc = get_value(objtype, objdata, linenum, "curve");
+ sq = get_value(objtype, objdata, linenum, "q");
+ curve = string_to_curve(sc);
+ if (curve < 0) {
+ fprintf(stderr, "unknown curve name: '%s'"
+ " (line %ld)\n", sc, linenum);
+ exit(EXIT_FAILURE);
+ }
+ pk->key_type = BR_KEYTYPE_EC;
+ pk->key.ec.curve = curve;
+ pk->key.ec.q = parse_hex("public point", linenum,
+ sq, &pk->key.ec.qlen);
+ } else {
+ fprintf(stderr, "unknown key type '%s' (line %ld)\n",
+ stype, linenum);
+ exit(EXIT_FAILURE);
+ }
+ if (HT_put(keys, name, pk) != NULL) {
+ fprintf(stderr, "duplicate key: '%s' (line %ld)\n",
+ name, linenum);
+ exit(EXIT_FAILURE);
+ }
+ } else if (eqstring(objtype, "anchor")) {
+ char *dnfile, *kname, *tatype;
+ test_trust_anchor *tta;
+
+ dnfile = get_value(objtype, objdata, linenum, "DN_file");
+ kname = get_value(objtype, objdata, linenum, "key");
+ tatype = get_value(objtype, objdata, linenum, "type");
+ tta = xmalloc(sizeof *tta);
+ tta->dn = read_file(dnfile, &tta->dn_len);
+ tta->key_name = xstrdup(kname);
+ if (eqstring(tatype, "CA")) {
+ tta->flags = BR_X509_TA_CA;
+ } else if (eqstring(tatype, "EE")) {
+ tta->flags = 0;
+ } else {
+ fprintf(stderr,
+ "unknown trust anchor type: '%s' (line %ld)\n",
+ tatype, linenum);
+ }
+ if (HT_put(trust_anchors, name, tta) != NULL) {
+ fprintf(stderr,
+ "duplicate trust anchor: '%s' (line %ld)\n",
+ name, linenum);
+ exit(EXIT_FAILURE);
+ }
+ } else if (eqstring(objtype, "chain")) {
+ test_case tc;
+ char *ktype, *kusage, *sstatus, *shashes, *stime;
+
+ ktype = get_value(objtype, objdata, linenum, "keytype");
+ kusage = get_value(objtype, objdata, linenum, "keyusage");
+ sstatus = get_value(objtype, objdata, linenum, "status");
+ tc.name = xstrdup(name);
+ tc.ta_names = split_names(
+ get_value(objtype, objdata, linenum, "anchors"));
+ tc.cert_names = split_names(
+ get_value(objtype, objdata, linenum, "chain"));
+ tc.servername = xstrdup(HT_get(objdata, "servername"));
+ if (eqstring(ktype, "RSA")) {
+ tc.key_type_usage = BR_KEYTYPE_RSA;
+ } else if (eqstring(ktype, "EC")) {
+ tc.key_type_usage = BR_KEYTYPE_EC;
+ } else {
+ fprintf(stderr,
+ "unknown key type: '%s' (line %ld)\n",
+ ktype, linenum);
+ exit(EXIT_FAILURE);
+ }
+ if (eqstring(kusage, "KEYX")) {
+ tc.key_type_usage |= BR_KEYTYPE_KEYX;
+ } else if (eqstring(kusage, "SIGN")) {
+ tc.key_type_usage |= BR_KEYTYPE_SIGN;
+ } else {
+ fprintf(stderr,
+ "unknown key usage: '%s' (line %ld)\n",
+ kusage, linenum);
+ exit(EXIT_FAILURE);
+ }
+ tc.status = (unsigned)atoi(sstatus);
+ if (tc.status == 0) {
+ tc.ee_key_name = xstrdup(
+ get_value(objtype, objdata, linenum, "eekey"));
+ } else {
+ tc.ee_key_name = NULL;
+ }
+ shashes = HT_get(objdata, "hashes");
+ if (shashes == NULL) {
+ tc.hashes = (unsigned)-1;
+ } else {
+ char **hns;
+ size_t u;
+
+ tc.hashes = 0;
+ hns = split_names(shashes);
+ for (u = 0;; u ++) {
+ char *hn;
+ int id;
+
+ hn = hns[u];
+ if (hn == NULL) {
+ break;
+ }
+ id = string_to_hash(hn);
+ if (id < 0) {
+ fprintf(stderr,
+ "unknown hash function '%s'"
+ " (line %ld)\n", hn, linenum);
+ exit(EXIT_FAILURE);
+ }
+ tc.hashes |= (unsigned)1 << id;
+ xfree(hn);
+ }
+ xfree(hns);
+ }
+ stime = HT_get(objdata, "time");
+ if (stime == NULL) {
+ stime = DEFAULT_TIME;
+ }
+ if (string_to_time(stime, &tc.days, &tc.seconds) < 0) {
+ fprintf(stderr, "invalid time string '%s' (line %ld)\n",
+ stime, linenum);
+ exit(EXIT_FAILURE);
+ }
+ if (all_chains_ptr == all_chains_len) {
+ if (all_chains_len == 0) {
+ all_chains_len = 8;
+ all_chains = xmalloc(
+ all_chains_len * sizeof *all_chains);
+ } else {
+ test_case *ntc;
+ size_t nlen;
+
+ nlen = all_chains_len << 1;
+ ntc = xmalloc(nlen * sizeof *ntc);
+ memcpy(ntc, all_chains,
+ all_chains_len * sizeof *all_chains);
+ xfree(all_chains);
+ all_chains = ntc;
+ all_chains_len = nlen;
+ }
+ }
+ all_chains[all_chains_ptr ++] = tc;
+ } else {
+ fprintf(stderr, "unknown section type '%s' (line %ld)\n",
+ objtype, linenum);
+ exit(EXIT_FAILURE);
+ }
+}
+
+static void
+process_conf_file(const char *fname)
+{
+ char *objtype;
+ HT *objdata;
+ long objlinenum;
+
+ keys = HT_new();
+ trust_anchors = HT_new();
+ all_chains = NULL;
+ all_chains_ptr = 0;
+ all_chains_len = 0;
+ conf_init(fname);
+ objtype = NULL;
+ objdata = HT_new();
+ objlinenum = 0;
+ for (;;) {
+ char *hname;
+
+ if (conf_next_line() < 0) {
+ break;
+ }
+ hname = parse_header_name();
+ if (hname != NULL) {
+ if (objtype != NULL) {
+ parse_object(objtype, objdata, objlinenum);
+ HT_clear(objdata, xfree);
+ xfree(objtype);
+ }
+ objtype = hname;
+ objlinenum = current_linenum;
+ continue;
+ }
+ if (objtype == NULL) {
+ fprintf(stderr, "no current section (line %ld)\n",
+ current_linenum);
+ exit(EXIT_FAILURE);
+ }
+ if (parse_keyvalue(objdata) < 0) {
+ fprintf(stderr, "wrong configuration, line %ld\n",
+ current_linenum);
+ exit(EXIT_FAILURE);
+ }
+ }
+ if (objtype != NULL) {
+ parse_object(objtype, objdata, objlinenum);
+ xfree(objtype);
+ }
+ HT_free(objdata, xfree);
+ conf_close();
+}
+
+static const struct {
+ int id;
+ const br_hash_class *impl;
+} hash_impls[] = {
+ { br_md5_ID, &br_md5_vtable },
+ { br_sha1_ID, &br_sha1_vtable },
+ { br_sha224_ID, &br_sha224_vtable },
+ { br_sha256_ID, &br_sha256_vtable },
+ { br_sha384_ID, &br_sha384_vtable },
+ { br_sha512_ID, &br_sha512_vtable },
+ { 0, NULL }
+};
+
+typedef struct {
+ unsigned char *data;
+ size_t len;
+} blob;
+
+static int
+eqbigint(const unsigned char *b1, size_t b1_len,
+ const unsigned char *b2, size_t b2_len)
+{
+ while (b1_len > 0 && *b1 == 0) {
+ b1 ++;
+ b1_len --;
+ }
+ while (b2_len > 0 && *b2 == 0) {
+ b2 ++;
+ b2_len --;
+ }
+ return b1_len == b2_len && memcmp(b1, b2, b1_len) == 0;
+}
+
+static int
+eqpkey(const br_x509_pkey *pk1, const br_x509_pkey *pk2)
+{
+ if (pk1 == pk2) {
+ return 1;
+ }
+ if (pk1 == NULL || pk2 == NULL) {
+ return 0;
+ }
+ if (pk1->key_type != pk2->key_type) {
+ return 0;
+ }
+ switch (pk1->key_type) {
+ case BR_KEYTYPE_RSA:
+ return eqbigint(pk1->key.rsa.n, pk1->key.rsa.nlen,
+ pk2->key.rsa.n, pk2->key.rsa.nlen)
+ && eqbigint(pk1->key.rsa.e, pk1->key.rsa.elen,
+ pk2->key.rsa.e, pk2->key.rsa.elen);
+ case BR_KEYTYPE_EC:
+ return pk1->key.ec.curve == pk2->key.ec.curve
+ && pk1->key.ec.qlen == pk2->key.ec.qlen
+ && memcmp(pk1->key.ec.q,
+ pk2->key.ec.q, pk1->key.ec.qlen) == 0;
+ default:
+ fprintf(stderr, "unknown key type: %d\n", pk1->key_type);
+ exit(EXIT_FAILURE);
+ break;
+ }
+ return 0;
+}
+
+static size_t max_dp_usage;
+static size_t max_rp_usage;
+
+static void
+run_test_case(test_case *tc)
+{
+ br_x509_minimal_context ctx;
+ br_x509_trust_anchor *anchors;
+ size_t num_anchors;
+ size_t u;
+ const br_hash_class *dnhash;
+ size_t num_certs;
+ blob *certs;
+ br_x509_pkey *ee_pkey_ref;
+ const br_x509_pkey *ee_pkey;
+ unsigned usages;
+ unsigned status;
+
+ printf("%s: ", tc->name);
+ fflush(stdout);
+
+ /*
+ * Get the hash function to use for hashing DN. We can use just
+ * any supported hash function, but for the elegance of things,
+ * we will use one of the hash function implementations
+ * supported for this test case (with SHA-1 as fallback).
+ */
+ dnhash = &br_sha1_vtable;
+ for (u = 0; hash_impls[u].id; u ++) {
+ if ((tc->hashes & ((unsigned)1 << (hash_impls[u].id))) != 0) {
+ dnhash = hash_impls[u].impl;
+ }
+ }
+
+ /*
+ * Get trust anchors.
+ */
+ for (num_anchors = 0; tc->ta_names[num_anchors]; num_anchors ++);
+ anchors = xmalloc(num_anchors * sizeof *anchors);
+ for (u = 0; tc->ta_names[u]; u ++) {
+ test_trust_anchor *tta;
+ br_x509_pkey *tak;
+
+ tta = HT_get(trust_anchors, tc->ta_names[u]);
+ if (tta == NULL) {
+ fprintf(stderr, "no such trust anchor: '%s'\n",
+ tc->ta_names[u]);
+ exit(EXIT_FAILURE);
+ }
+ tak = HT_get(keys, tta->key_name);
+ if (tak == NULL) {
+ fprintf(stderr, "no such public key: '%s'\n",
+ tta->key_name);
+ exit(EXIT_FAILURE);
+ }
+ anchors[u].dn.data = tta->dn;
+ anchors[u].dn.len = tta->dn_len;
+ anchors[u].flags = tta->flags;
+ anchors[u].pkey = *tak;
+ }
+
+ /*
+ * Read all relevant certificates.
+ */
+ for (num_certs = 0; tc->cert_names[num_certs]; num_certs ++);
+ certs = xmalloc(num_certs * sizeof *certs);
+ for (u = 0; u < num_certs; u ++) {
+ certs[u].data = read_file(tc->cert_names[u], &certs[u].len);
+ }
+
+ /*
+ * Get expected EE public key (if any).
+ */
+ if (tc->ee_key_name == NULL) {
+ ee_pkey_ref = NULL;
+ } else {
+ ee_pkey_ref = HT_get(keys, tc->ee_key_name);
+ if (ee_pkey_ref == NULL) {
+ fprintf(stderr, "no such public key: '%s'\n",
+ tc->ee_key_name);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /*
+ * Initialise the engine.
+ */
+ br_x509_minimal_init(&ctx, dnhash, anchors, num_anchors);
+ for (u = 0; hash_impls[u].id; u ++) {
+ int id;
+
+ id = hash_impls[u].id;
+ if ((tc->hashes & ((unsigned)1 << id)) != 0) {
+ br_x509_minimal_set_hash(&ctx, id, hash_impls[u].impl);
+ }
+ }
+ br_x509_minimal_set_rsa(&ctx, br_rsa_pkcs1_vrfy_get_default());
+ br_x509_minimal_set_ecdsa(&ctx,
+ br_ec_get_default(), br_ecdsa_vrfy_asn1_get_default());
+
+ /*
+ * Set the validation date.
+ */
+ br_x509_minimal_set_time(&ctx, tc->days, tc->seconds);
+
+ /*
+ * Put "canaries" to detect actual stack usage.
+ */
+ for (u = 0; u < (sizeof ctx.dp_stack) / sizeof(uint32_t); u ++) {
+ ctx.dp_stack[u] = 0xA7C083FE;
+ }
+ for (u = 0; u < (sizeof ctx.rp_stack) / sizeof(uint32_t); u ++) {
+ ctx.rp_stack[u] = 0xA7C083FE;
+ }
+
+ /*
+ * Run the engine. We inject certificates by chunks of 100 bytes
+ * in order to exercise the coroutine API.
+ */
+ ctx.vtable->start_chain(&ctx.vtable, tc->servername);
+ for (u = 0; u < num_certs; u ++) {
+ size_t v;
+
+ ctx.vtable->start_cert(&ctx.vtable, certs[u].len);
+ v = 0;
+ while (v < certs[u].len) {
+ size_t w;
+
+ w = certs[u].len - v;
+ if (w > 100) {
+ w = 100;
+ }
+ ctx.vtable->append(&ctx.vtable, certs[u].data + v, w);
+ v += w;
+ }
+ ctx.vtable->end_cert(&ctx.vtable);
+ }
+ status = ctx.vtable->end_chain(&ctx.vtable);
+ ee_pkey = ctx.vtable->get_pkey(&ctx.vtable, &usages);
+
+ /*
+ * Check key type and usage.
+ */
+ if (ee_pkey != NULL) {
+ unsigned ktu;
+
+ ktu = ee_pkey->key_type | usages;
+ if (tc->key_type_usage != (ktu & tc->key_type_usage)) {
+ fprintf(stderr, "wrong key type + usage"
+ " (expected 0x%02X, got 0x%02X)\n",
+ tc->key_type_usage, ktu);
+ exit(EXIT_FAILURE);
+ }
+ }
+
+ /*
+ * Check results. Note that we may still get a public key if
+ * the path is "not trusted" (but otherwise fine).
+ */
+ if (status != tc->status) {
+ fprintf(stderr, "wrong status (got %d, expected %d)\n",
+ status, tc->status);
+ exit(EXIT_FAILURE);
+ }
+ if (status == BR_ERR_X509_NOT_TRUSTED) {
+ ee_pkey = NULL;
+ }
+ if (!eqpkey(ee_pkey, ee_pkey_ref)) {
+ fprintf(stderr, "wrong EE public key\n");
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Check stack usage.
+ */
+ for (u = (sizeof ctx.dp_stack) / sizeof(uint32_t); u > 0; u --) {
+ if (ctx.dp_stack[u - 1] != 0xA7C083FE) {
+ if (max_dp_usage < u) {
+ max_dp_usage = u;
+ }
+ break;
+ }
+ }
+ for (u = (sizeof ctx.rp_stack) / sizeof(uint32_t); u > 0; u --) {
+ if (ctx.rp_stack[u - 1] != 0xA7C083FE) {
+ if (max_rp_usage < u) {
+ max_rp_usage = u;
+ }
+ break;
+ }
+ }
+
+ /*
+ * Release everything.
+ */
+ for (u = 0; u < num_certs; u ++) {
+ xfree(certs[u].data);
+ }
+ xfree(certs);
+ xfree(anchors);
+ printf("OK\n");
+}
+
+/*
+ * A custom structure for tests, synchronised with the test certificate
+ * names.crt.
+ *
+ * If num is 1 or more, then this is a DN element with OID '1.1.1.1.num'.
+ * If num is -1 or less, then this is a SAN element of type -num.
+ * If num is 0, then this is a SAN element of type OtherName with
+ * OID 1.3.6.1.4.1.311.20.2.3 (Microsoft UPN).
+ */
+typedef struct {
+ int num;
+ int status;
+ const char *expected;
+} name_element_test;
+
+static name_element_test names_ref[] = {
+ /* === DN tests === */
+ {
+ /* [12] 66:6f:6f */
+ 1, 1, "foo"
+ },
+ {
+ /* [12] 62:61:72 */
+ 1, 1, "bar"
+ },
+ {
+ /* [18] 31:32:33:34 */
+ 2, 1, "1234"
+ },
+ {
+ /* [19] 66:6f:6f */
+ 3, 1, "foo"
+ },
+ {
+ /* [20] 66:6f:6f */
+ 4, 1, "foo"
+ },
+ {
+ /* [22] 66:6f:6f */
+ 5, 1, "foo"
+ },
+ {
+ /* [30] 00:66:00:6f:00:6f */
+ 6, 1, "foo"
+ },
+ {
+ /* [30] fe:ff:00:66:00:6f:00:6f */
+ 7, 1, "foo"
+ },
+ {
+ /* [30] ff:fe:66:00:6f:00:6f:00 */
+ 8, 1, "foo"
+ },
+ {
+ /* [20] 63:61:66:e9 */
+ 9, 1, "caf\xC3\xA9"
+ },
+ {
+ /* [12] 63:61:66:c3:a9 */
+ 10, 1, "caf\xC3\xA9"
+ },
+ {
+ /* [12] 63:61:66:e0:83:a9 */
+ 11, -1, NULL
+ },
+ {
+ /* [12] 63:61:66:e3:90:8c */
+ 12, 1, "caf\xE3\x90\x8C"
+ },
+ {
+ /* [30] 00:63:00:61:00:66:34:0c */
+ 13, 1, "caf\xE3\x90\x8C"
+ },
+ {
+ /* [12] 63:61:66:c3 */
+ 14, -1, NULL
+ },
+ {
+ /* [30] d8:42:df:f4:00:67:00:6f */
+ 15, 1, "\xF0\xA0\xAF\xB4go"
+ },
+ {
+ /* [30] 00:66:d8:42 */
+ 16, -1, NULL
+ },
+ {
+ /* [30] d8:42:00:66 */
+ 17, -1, NULL
+ },
+ {
+ /* [30] df:f4:00:66 */
+ 18, -1, NULL
+ },
+ {
+ /* [12] 66:00:6f */
+ 19, -1, NULL
+ },
+ {
+ /* [30] 00:00:34:0c */
+ 20, -1, NULL
+ },
+ {
+ /* [30] 34:0c:00:00:00:66 */
+ 21, -1, NULL
+ },
+ {
+ /* [12] ef:bb:bf:66:6f:6f */
+ 22, 1, "foo"
+ },
+ {
+ /* [30] 00:66:ff:fe:00:6f */
+ 23, -1, NULL
+ },
+ {
+ /* [30] 00:66:ff:fd:00:6f */
+ 24, 1, "f\xEF\xBF\xBDo"
+ },
+
+ /* === Value not found in the DN === */
+ {
+ 127, 0, NULL
+ },
+
+ /* === SAN tests === */
+ {
+ /* SAN OtherName (Microsoft UPN) */
+ 0, 1, "foo@bar.com"
+ },
+ {
+ /* SAN rfc822Name */
+ -1, 1, "bar@foo.com"
+ },
+ {
+ /* SAN dNSName */
+ -2, 1, "example.com"
+ },
+ {
+ /* SAN dNSName */
+ -2, 1, "www.example.com"
+ },
+ {
+ /* uniformResourceIdentifier */
+ -6, 1, "http://www.example.com/"
+ }
+};
+
+static void
+free_name_elements(br_name_element *elts, size_t num)
+{
+ size_t u;
+
+ for (u = 0; u < num; u ++) {
+ xfree((void *)elts[u].oid);
+ xfree(elts[u].buf);
+ }
+ xfree(elts);
+}
+
+static void
+test_name_extraction(void)
+{
+ unsigned char *data;
+ size_t len;
+ br_x509_minimal_context ctx;
+ uint32_t days, seconds;
+ size_t u;
+ unsigned status;
+ br_name_element *names;
+ size_t num_names;
+ int good;
+
+ printf("Name extraction: ");
+ fflush(stdout);
+ data = read_file("names.crt", &len);
+ br_x509_minimal_init(&ctx, &br_sha256_vtable, NULL, 0);
+ for (u = 0; hash_impls[u].id; u ++) {
+ int id;
+
+ id = hash_impls[u].id;
+ br_x509_minimal_set_hash(&ctx, id, hash_impls[u].impl);
+ }
+ br_x509_minimal_set_rsa(&ctx, br_rsa_pkcs1_vrfy_get_default());
+ br_x509_minimal_set_ecdsa(&ctx,
+ br_ec_get_default(), br_ecdsa_vrfy_asn1_get_default());
+ string_to_time(DEFAULT_TIME, &days, &seconds);
+ br_x509_minimal_set_time(&ctx, days, seconds);
+
+ num_names = (sizeof names_ref) / (sizeof names_ref[0]);
+ names = xmalloc(num_names * sizeof *names);
+ for (u = 0; u < num_names; u ++) {
+ int num;
+ unsigned char *oid;
+
+ num = names_ref[u].num;
+ if (num > 0) {
+ oid = xmalloc(5);
+ oid[0] = 4;
+ oid[1] = 0x29;
+ oid[2] = 0x01;
+ oid[3] = 0x01;
+ oid[4] = num;
+ } else if (num == 0) {
+ oid = xmalloc(13);
+ oid[0] = 0x00;
+ oid[1] = 0x00;
+ oid[2] = 0x0A;
+ oid[3] = 0x2B;
+ oid[4] = 0x06;
+ oid[5] = 0x01;
+ oid[6] = 0x04;
+ oid[7] = 0x01;
+ oid[8] = 0x82;
+ oid[9] = 0x37;
+ oid[10] = 0x14;
+ oid[11] = 0x02;
+ oid[12] = 0x03;
+ } else {
+ oid = xmalloc(2);
+ oid[0] = 0x00;
+ oid[1] = -num;
+ }
+ names[u].oid = oid;
+ names[u].buf = xmalloc(256);
+ names[u].len = 256;
+ }
+ br_x509_minimal_set_name_elements(&ctx, names, num_names);
+
+ /*
+ * Put "canaries" to detect actual stack usage.
+ */
+ for (u = 0; u < (sizeof ctx.dp_stack) / sizeof(uint32_t); u ++) {
+ ctx.dp_stack[u] = 0xA7C083FE;
+ }
+ for (u = 0; u < (sizeof ctx.rp_stack) / sizeof(uint32_t); u ++) {
+ ctx.rp_stack[u] = 0xA7C083FE;
+ }
+
+ /*
+ * Run the engine. Since we set no trust anchor, we expect a status
+ * of "not trusted".
+ */
+ ctx.vtable->start_chain(&ctx.vtable, NULL);
+ ctx.vtable->start_cert(&ctx.vtable, len);
+ ctx.vtable->append(&ctx.vtable, data, len);
+ ctx.vtable->end_cert(&ctx.vtable);
+ status = ctx.vtable->end_chain(&ctx.vtable);
+ if (status != BR_ERR_X509_NOT_TRUSTED) {
+ fprintf(stderr, "wrong status: %u\n", status);
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ * Check stack usage.
+ */
+ for (u = (sizeof ctx.dp_stack) / sizeof(uint32_t); u > 0; u --) {
+ if (ctx.dp_stack[u - 1] != 0xA7C083FE) {
+ if (max_dp_usage < u) {
+ max_dp_usage = u;
+ }
+ break;
+ }
+ }
+ for (u = (sizeof ctx.rp_stack) / sizeof(uint32_t); u > 0; u --) {
+ if (ctx.rp_stack[u - 1] != 0xA7C083FE) {
+ if (max_rp_usage < u) {
+ max_rp_usage = u;
+ }
+ break;
+ }
+ }
+
+ good = 1;
+ for (u = 0; u < num_names; u ++) {
+ if (names[u].status != names_ref[u].status) {
+ printf("ERR: name %u (id=%d): status=%d, expected=%d\n",
+ (unsigned)u, names_ref[u].num,
+ names[u].status, names_ref[u].status);
+ if (names[u].status > 0) {
+ unsigned char *p;
+
+ printf(" obtained:");
+ p = (unsigned char *)names[u].buf;
+ while (*p) {
+ printf(" %02X", *p ++);
+ }
+ printf("\n");
+ }
+ good = 0;
+ continue;
+ }
+ if (names_ref[u].expected == NULL) {
+ if (names[u].buf[0] != 0) {
+ printf("ERR: name %u not zero-terminated\n",
+ (unsigned)u);
+ good = 0;
+ continue;
+ }
+ } else {
+ if (strcmp(names[u].buf, names_ref[u].expected) != 0) {
+ unsigned char *p;
+
+ printf("ERR: name %u (id=%d): wrong value\n",
+ (unsigned)u, names_ref[u].num);
+ printf(" expected:");
+ p = (unsigned char *)names_ref[u].expected;
+ while (*p) {
+ printf(" %02X", *p ++);
+ }
+ printf("\n");
+ printf(" obtained:");
+ p = (unsigned char *)names[u].buf;
+ while (*p) {
+ printf(" %02X", *p ++);
+ }
+ printf("\n");
+ good = 0;
+ continue;
+ }
+ }
+ }
+ if (!good) {
+ exit(EXIT_FAILURE);
+ }
+
+ /*
+ for (u = 0; u < num_names; u ++) {
+ printf("%u: (%d)", (unsigned)u, names[u].status);
+ if (names[u].status > 0) {
+ size_t v;
+
+ for (v = 0; names[u].buf[v]; v ++) {
+ printf(" %02x", names[u].buf[v]);
+ }
+ }
+ printf("\n");
+ }
+ */
+
+ xfree(data);
+ free_name_elements(names, num_names);
+ printf("OK\n");
+}
+
+int
+main(int argc, const char *argv[])
+{
+ size_t u;
+
+#ifdef SRCDIRNAME
+ /*
+ * We want to change the current directory to that of the
+ * executable, so that test files are reliably located. We
+ * do that only if SRCDIRNAME is defined (old Makefile would
+ * not do that).
+ */
+ if (argc >= 1) {
+ const char *arg, *c;
+
+ arg = argv[0];
+ for (c = arg + strlen(arg);; c --) {
+ int sep, r;
+
+#ifdef _WIN32
+ sep = (*c == '/') || (*c == '\\');
+#else
+ sep = (*c == '/');
+#endif
+ if (sep) {
+ size_t len;
+ char *dn;
+
+ len = 1 + (c - arg);
+ dn = xmalloc(len + 1);
+ memcpy(dn, arg, len);
+ dn[len] = 0;
+#ifdef _WIN32
+ r = _chdir(dn);
+#else
+ r = chdir(dn);
+#endif
+ if (r != 0) {
+ fprintf(stderr, "warning: could not"
+ " set directory to '%s'\n", dn);
+ }
+ xfree(dn);
+ break;
+ }
+ if (c == arg) {
+ break;
+ }
+ }
+ }
+#else
+ (void)argc;
+ (void)argv;
+#endif
+
+ process_conf_file(CONFFILE);
+
+ max_dp_usage = 0;
+ max_rp_usage = 0;
+ for (u = 0; u < all_chains_ptr; u ++) {
+ run_test_case(&all_chains[u]);
+ }
+ test_name_extraction();
+
+ printf("Maximum data stack usage: %u\n", (unsigned)max_dp_usage);
+ printf("Maximum return stack usage: %u\n", (unsigned)max_rp_usage);
+
+ HT_free(keys, free_key);
+ HT_free(trust_anchors, free_trust_anchor);
+ for (u = 0; u < all_chains_ptr; u ++) {
+ free_test_case_contents(&all_chains[u]);
+ }
+ xfree(all_chains);
+
+ return 0;
+}
diff --git a/contrib/bearssl/test/x509/alltests.txt b/contrib/bearssl/test/x509/alltests.txt
new file mode 100644
index 000000000000..a635a6396324
--- /dev/null
+++ b/contrib/bearssl/test/x509/alltests.txt
@@ -0,0 +1,722 @@
+; Most/all of these test chains use the same structure:
+; root -> ica1 -> ica2 -> ee
+; "ica1" is "Intermediate CA 1"
+; "ee" is "end-entity", i.e. the client or server certificate itself
+;
+; In SSL/TLS order, the EE comes first. The root may or may not be included
+; as a self-signed certificate.
+
+[key]
+name = root-rsa2048
+type = RSA
+n = B6D934D450FDB3AF7A73F1CE38BF5D6F45E1FD4EB198C6608326D217D1C5B79AA3C1DE6339979CF05E5CC81C17B988196DF0B62E3050A1546E93C0DBCF30CB9F1E2779F1C3995235AA3DB6DFB0AD7CCB49CDC0EDE766102AE9CE281F2150FA774C2DDAEF3C58EB4EBFCEE9FB1ADAA383A3CDA3CA9380DCDAF317CC7AAB33809CB2D47F463FC53CDC6194B727296E2ABC5B0936D4C63B0DEBBECEDB1D1CBC106A7171B3F2CA289A77F28AEC42EFB14A8EE2F21A322ACDC0A6462C9AC28537917F46A19381A17466DFBAB339209193FA1DA1A885E7E4F907F610F6A82701B67F12C340C3C9E2B0AB49183A64B659B795B59636DF2269AA726A544E2729A30E9715
+e = 010001
+
+[key]
+name = root-p256
+type = EC
+curve = P-256
+q = 047174BAABB9302E81D5E557F9F320680C9CF964DBB4200D6DEA40D04A6E42FDB69A682544F6DF7BC4FCDEDD7BBBC5DB7C763F4166406EDBA787C2E5D8C5F37F8D
+
+[key]
+name = root-p384
+type = EC
+curve = P-384
+q = 040ED28B3F7F0A38A6DB72CB4DAC8198C3D595BFABEE2E4A3CC6797F1A272C57AD715F96B5FDA29C4DD87B75B1438B6A92C4FD0282A3080A857F28AB31FF8B49F805470A01EE551F7F27C914E7E780AE474558D6F5539BAE806626514FE560478B
+
+[key]
+name = root-p521
+type = EC
+curve = P-521
+q = 040168E669615D1B20F2E753D2C86312F51094D3E5C6CF49E8D73418278CD769FE40A84AD4F34865D59D94D5685B389E0CFD0450754CAE81ED1D4A91D0773F7A002ED701DEF2DBDEFC7554E74CD600693DBDE1A7E09CD9044774C744C7CE575BF8B645FF79FCCE06116F61D44FDAE62D3046F4EB41DECB8219B279A5B8CE2A47F3DF0D463B
+
+[key]
+name = root-new
+type = EC
+curve = P-256
+q = 0465D02336D3ACEB9A000B33A6EECA9745EFD72A0F7C0B138FAAA564E705A3269A479BB5A041DC1D244EA1D2BB9639C79187D3D63CEF79EDD1DC65E80027E75997
+
+[key]
+name = ica1-rsa2048
+type = RSA
+n = B3E86BAF9C1652E3810C50AB25CECC0DC7F21F7F50DF2C5C35D6622E632741A7E453A84B27FA1391A3FA094A2F3B5ECF77B38AC1CD49959C750D6474EFE4D74BB9A19B68D2307148EAF74B14DF3F47A9D8BBEC8F28CCFADFB41F947C96FC080528F9E8F42F2FEE629C8A3AE0855860B60F2D30B4C04154914C1F5FADF119F0C022A67DD83F793459427B5BB541C4647F52CF3C3722A12F7925942441C23FFAC775FB48B50D18A7F454F32E6ED84358C4AB50E805AD91B61E0175B3549CDEA09915FBACF15C974951CCEF58126F736BB33414010F5A9DFAAAD693D3E2EAC3ABBC4EEDCC51A1B8F894B6B42CA8862B1FF6514329525E1389B36A78604E4EC01BA5
+e = 010001
+
+[key]
+name = ica2-rsa2048
+type = RSA
+n = AE15F7CBEEE3961BCA63D22681B2D8163423735684FCFDB2E98E9DD0D9D0D706A191EF8D4F604E16BDE6529EE557867B7A7FFCBC34AD86EC9150ADD5C7D18D83E95ABA2FDB0DB92131FAA2FD91EC37836261809C6A82253309DF8F7893EACFDB93B0A2687CEA873E369C4B379A71E52084C3789A2BA42C7E76D561A9131272F14B411BC6A555BA9D8965C06699C0F17C9B61B24E6601B0A9C4FDC8C1D0C789BE2746DE6271BA27F52A850F436026BC2A9D07AAD608DC26D86956A1D308DED858936B0EC2AF783E2574D49F001820BFD7158DB9D13D8900A01264E186C0D580F124B2D2FB4C677CAE3DC9BF47026DE47C0D4490518CCD026237F86FB96701C695
+e = 010001
+
+[key]
+name = ee-rsa2048
+type = RSA
+n = D47A1D27BA2B3A67B2916AFBE78344CAED1C75ADDD4D8362D6AA6895B224217B15AE2A996815ED66F0B858E7D3F52EC6D92A5EE70E2EE7FC6759C0C8617D4BA46FDD9FD9C8858764C7BA1A0F29D496A8789A6B6220A932D0EEA98C286147A2502A63F621DEDAD8D5F07FC5008270E6A3BF5C89274F51927703C3B0CC2E3BEC23F22F5341AF8993FFD280B14397DED619A092127A3D6679E1C1BCE17770A28B3D4684533FE44E424137921E1FFD38B3F7EF873980D356CFF4E013DE64B072A40384C441ED6FFA3EE2CA0420D2D7DC2C822B7AE26DA11C48DBCF894F34973D28A853DAE7C1E17315A330767F8F2342143D5134D25AAD3C9BCBC8FE7F6E8E40F3BD
+e = 010001
+
+[key]
+name = ee-p256
+type = EC
+curve = P-256
+q = 045F389DA7FF4D8AAFF63439461AFC3ADFF423AAA9EAFBC508DE008EBE79A537584C6DDD01CAAB47DF89B6C7171F38FC1D2014DD45C0E08F934E380BFCE999A149
+
+[key]
+name = ee-p384
+type = EC
+curve = P-384
+q = 0415A488877F3D14830E29A1C2F2C0745CE8CF5E684304D1668972389BA615B34E9648D5A7861E49DFFFBFFFEAD7FC6AF11BC4516C3557332DD86DDFDE2A236CCEA844EBD594CCD3ED5B7AE0061BD6595737B59FE754BCDAB6FE38D34D93DBBF30
+
+[key]
+name = ee-p521
+type = EC
+curve = P-521
+q = 040060547ACA9D520FB3272833236CBF8E71AC286A3001FBB1E2C3FD8BAB0817DDE4E4FA53550F120D678F4D55AE4FF36C7C8EAE9E32A08A44FC66F45331E08946077A0139B87FE54B986012A94838C8006034941CD0512E596436D2E8E61CA93585D5C06EAD5094585B5B2A3E013803B3E6AAA1D4156EF09E8352029BB70AC6BF338F918B
+
+; Trust anchor: the root.
+[anchor]
+name = root
+DN_file = dn-root.der
+key = root-rsa2048
+type = CA
+
+; Trust anchor: root with an ECDSA key (in P-256 curve)
+[anchor]
+name = root-p256
+DN_file = dn-root.der
+key = root-p256
+type = CA
+
+; Trust anchor: root with an ECDSA key (in P-384 curve)
+[anchor]
+name = root-p384
+DN_file = dn-root.der
+key = root-p384
+type = CA
+
+; Trust anchor: root with an ECDSA key (in P-521 curve)
+[anchor]
+name = root-p521
+DN_file = dn-root.der
+key = root-p521
+type = CA
+
+; Trust anchor: another root with an ECDSA key (in P-256 curve)
+[anchor]
+name = root-new
+DN_file = dn-root-new.der
+key = root-new
+type = CA
+
+; Intermediate CA 1 as trust anchor.
+[anchor]
+name = ica1
+DN_file = dn-ica1.der
+key = ica1-rsa2048
+type = CA
+
+; Intermediate CA 2 as trust anchor.
+[anchor]
+name = ica2
+DN_file = dn-ica2.der
+key = ica2-rsa2048
+type = CA
+
+; EE certificate as trust anchor (direct trust only).
+[anchor]
+name = ee
+DN_file = dn-ee.der
+key = ee-rsa2048
+type = EE
+
+; Base valid chain.
+[chain]
+name = base
+anchors = root
+chain = ee.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Valid chain except that no trust anchor is provided; this should fail
+; with BR_ERR_X509_NOT_TRUSTED.
+[chain]
+name = noTA
+anchors =
+chain = ee.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 62
+
+; Use of intermediate CA 1 as anchor (extra certificates are ignored).
+[chain]
+name = anchorICA1
+anchors = ica1
+chain = ee.crt ica2.crt junk.crt junk.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Use of intermediate CA 2 as anchor (extra certificates are ignored).
+[chain]
+name = anchorICA2
+anchors = ica2
+chain = ee.crt junk.crt junk.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Direct trust of EE.
+[chain]
+name = directTrust
+anchors = ee
+chain = ee.crt junk.crt junk.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Server name check: name does not match the SAN nor the CN.
+[chain]
+name = wrongName1
+anchors = root
+chain = ee.crt ica2.crt ica1.crt
+servername = foo.example.com
+keytype = RSA
+keyusage = KEYX
+status = 56
+
+; Server name check: name matches the CN but not the SAN, and there is
+; a SAN so the CN is ignored.
+[chain]
+name = wrongName2
+anchors = root
+chain = ee-names.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 56
+
+; Server name check: name does not match CN, but matches the first SAN
+; name.
+[chain]
+name = goodName1
+anchors = root
+chain = ee-names.crt ica2.crt ica1.crt
+servername = foo.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Server name check: name does not match CN, but matches the second SAN
+; name.
+[chain]
+name = goodName2
+anchors = root
+chain = ee-names.crt ica2.crt ica1.crt
+servername = barqux.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Server name check: no SAN, but the CN matches the server name.
+[chain]
+name = goodName3
+anchors = root
+chain = ee-names2.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Server name check: no SAN, and the CN does not match the server name.
+[chain]
+name = wrongName3
+anchors = root
+chain = ee-names2.crt ica2.crt ica1.crt
+servername = foo.example.com
+keytype = RSA
+keyusage = KEYX
+status = 56
+
+; Server name check: no SAN, and the CN does not match the server name,
+; although its byte contents seem to match (but with BMPString encoding).
+[chain]
+name = wrongName4
+anchors = root
+chain = ee-names3.crt ica2.crt ica1.crt
+servername = www1.example.com
+keytype = RSA
+keyusage = KEYX
+status = 56
+
+; Server name check: no SAN, and the CN uses BMPString encoding, but we
+; do not actually request a server name check, so this should pass.
+[chain]
+name = ignoreName1
+anchors = root
+chain = ee-names3.crt ica2.crt ica1.crt
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Wildcard processing: the name 'localhost' should not match because
+; the engine recognises the wildcard only in a '*.' starting sequence,
+; so the lone '*' in a SAN will not be accepted.
+[chain]
+name = wildcard1
+anchors = root
+chain = ee-names4.crt ica2.crt ica1.crt
+servername = localhost
+keytype = RSA
+keyusage = KEYX
+status = 56
+
+; Wildcard processing: the name 'example.com' will be matched by '*.com'.
+[chain]
+name = wildcard2
+anchors = root
+chain = ee-names4.crt ica2.crt ica1.crt
+servername = example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Wildcard processing: the name 'www.example.com' will be matched by
+; '*.example.com'.
+[chain]
+name = wildcard3
+anchors = root
+chain = ee-names4.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Wildcard processing: the name 'foo.foo.example.com' will not be matched by
+; 'foo.*.example.com' because we accept the wildcard only in the first name
+; component.
+[chain]
+name = wildcard4
+anchors = root
+chain = ee-names4.crt ica2.crt ica1.crt
+servername = foo.foo.example.com
+keytype = RSA
+keyusage = KEYX
+status = 56
+
+; Wildcard processing: the name 'foo.bar.example.com' will not be matched by
+; 'foo.*.example.com', but '*.bar.example.com' will fit.
+[chain]
+name = wildcard5
+anchors = root
+chain = ee-names4.crt ica2.crt ica1.crt
+servername = foo.bar.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Wildcard processing: the name 'foo.bar.example.foobar' will not be matched by
+; '*.*.example.foobar' because we support only a single level of wildcard.
+[chain]
+name = wildcard6
+anchors = root
+chain = ee-names4.crt ica2.crt ica1.crt
+servername = foo.bar.example.foobar
+keytype = RSA
+keyusage = KEYX
+status = 56
+
+; Wildcard processing: the name 'foo.*.example.foobar' will be matched
+; by '*.*.example.foobar' because the '*' in the provided server name matches
+; the second '*' in '*.*.example.foobar'. This is a corner case with no
+; practical impact because expected server names are usually extracted from
+; URL and cannot have embedded '*' in them.
+[chain]
+name = wildcard7
+anchors = root
+chain = ee-names4.crt ica2.crt ica1.crt
+servername = foo.*.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Hash function support: the chain uses only SHA-256.
+[chain]
+name = hashSHA256Only
+anchors = root
+chain = ee.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+hashes = sha256
+eekey = ee-rsa2048
+status = 0
+
+; Hash function support: the chain uses only SHA-256.
+[chain]
+name = hashSHA256Unsupported
+anchors = root
+chain = ee.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+hashes = md5 sha1 sha224 sha384 sha512
+status = 49
+
+; Hash function support: signature on EE uses SHA-1.
+[chain]
+name = hashSHA1
+anchors = root
+chain = ee-sha1.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Hash function support: signature on EE uses SHA-224.
+[chain]
+name = hashSHA224
+anchors = root
+chain = ee-sha224.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Hash function support: signature on EE uses SHA-384.
+[chain]
+name = hashSHA384
+anchors = root
+chain = ee-sha384.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Hash function support: signature on EE uses SHA-512.
+[chain]
+name = hashSHA512
+anchors = root
+chain = ee-sha512.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Hash function support: signature on EE uses MD5. This is rejected by
+; the engine (even though MD5 is supported as a hash function).
+[chain]
+name = hashMD5
+anchors = root
+chain = ee-md5.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 49
+
+; EE certificate has trailing garbage (an extra byte), which should be
+; rejected.
+[chain]
+name = trailingGarbage
+anchors = root
+chain = ee-trailing.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 40
+
+; Signature on EE certificate is incorrect (one byte modified in signature).
+[chain]
+name = badSignature1
+anchors = root
+chain = ee-badsig1.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 52
+
+; Signature on EE certificate is incorrect (one byte modified in serial
+; number).
+[chain]
+name = badSignature2
+anchors = root
+chain = ee-badsig2.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 52
+
+; Signature on EE certificate is incorrect but this is ignored because we
+; use a direct trust model here.
+[chain]
+name = ignoredSignature1
+anchors = ee
+chain = ee-badsig1.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Signature on EE certificate is incorrect but this is ignored because we
+; use a direct trust model here.
+[chain]
+name = ignoredSignature2
+anchors = ee
+chain = ee-badsig2.crt ica2.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Intermediate CA 1 has a 1016-bit RSA key, which should be rejected
+; with BR_ERR_X509_WEAK_PUBLIC_KEY.
+[chain]
+name = rsa1016
+anchors = root
+chain = ee.crt ica2-1016.crt ica1-1016.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 60
+
+; Intermediate CA 1 has a 1017-bit RSA key, which should be accepted
+; (because that's 128 bytes, which is the lower limit).
+[chain]
+name = rsa1017
+anchors = root
+chain = ee.crt ica2-1017.crt ica1-1017.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; Intermediate CA 1 has a 4096-bit RSA key, which should be supported.
+[chain]
+name = rsa4096
+anchors = root
+chain = ee.crt ica2-4096.crt ica1-4096.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; EE is valid from 2010/02/17 11:40:35 to 2098/07/20 15:11:08. The
+; start date is in UTCTime, the end date is in GeneralizedTime.
+[chain]
+name = date1
+anchors = ica2
+chain = ee-dates.crt ica2.crt ica1.crt
+time = 2010-02-17 11:40:34Z
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 54
+
+; EE is valid from 2010/02/17 11:40:35 to 2098/07/20 15:11:08. The
+; start date is in UTCTime, the end date is in GeneralizedTime.
+[chain]
+name = date2
+anchors = ica2
+chain = ee-dates.crt ica2.crt ica1.crt
+time = 2010-02-17 11:40:36Z
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; EE is valid from 2010/02/17 11:40:35 to 2098/07/20 15:11:08. The
+; start date is in UTCTime, the end date is in GeneralizedTime.
+[chain]
+name = date3
+anchors = ica2
+chain = ee-dates.crt ica2.crt ica1.crt
+time = 2098-07-20 15:11:07Z
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; EE is valid from 2010/02/17 11:40:35 to 2098/07/20 15:11:08. The
+; start date is in UTCTime, the end date is in GeneralizedTime.
+[chain]
+name = date4
+anchors = ica2
+chain = ee-dates.crt ica2.crt ica1.crt
+time = 2098-07-20 15:11:09Z
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 54
+
+; Intermediate CA 2 certificate is not a CA.
+[chain]
+name = notCA
+anchors = root
+chain = ee-dates.crt ica2-notCA.crt ica1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+status = 58
+
+; A chain using ECDSA with P-256.
+[chain]
+name = secp256r1
+anchors = root-p256
+chain = ee-p256.crt ica2-p256.crt ica1-p256.crt
+servername = www.example.com
+keytype = EC
+keyusage = SIGN
+eekey = ee-p256
+status = 0
+
+; A chain using ECDSA with P-384.
+[chain]
+name = secp384r1
+anchors = root-p384
+chain = ee-p384.crt ica2-p384.crt ica1-p384.crt
+servername = www.example.com
+keytype = EC
+keyusage = SIGN
+eekey = ee-p384
+status = 0
+
+; A chain using ECDSA with P-521.
+[chain]
+name = secp521r1
+anchors = root-p521
+chain = ee-p521.crt ica2-p521.crt ica1-p521.crt
+servername = www.example.com
+keytype = EC
+keyusage = SIGN
+eekey = ee-p521
+status = 0
+
+; A chain using ECDSA with P-256, signature on EE uses SHA-1.
+[chain]
+name = secp256r1-sha1
+anchors = root-p256
+chain = ee-p256-sha1.crt ica2-p256.crt ica1-p256.crt
+servername = www.example.com
+keytype = EC
+keyusage = SIGN
+eekey = ee-p256
+status = 0
+
+; A chain using ECDSA with P-256, signature on EE uses SHA-224.
+[chain]
+name = secp256r1-sha224
+anchors = root-p256
+chain = ee-p256-sha224.crt ica2-p256.crt ica1-p256.crt
+servername = www.example.com
+keytype = EC
+keyusage = SIGN
+eekey = ee-p256
+status = 0
+
+; A chain using ECDSA with P-256, signature on EE uses SHA-256.
+[chain]
+name = secp256r1-sha256
+anchors = root-p256
+chain = ee-p256-sha256.crt ica2-p256.crt ica1-p256.crt
+servername = www.example.com
+keytype = EC
+keyusage = SIGN
+eekey = ee-p256
+status = 0
+
+; A chain using ECDSA with P-256, signature on EE uses SHA-384.
+[chain]
+name = secp256r1-sha384
+anchors = root-p256
+chain = ee-p256-sha384.crt ica2-p256.crt ica1-p256.crt
+servername = www.example.com
+keytype = EC
+keyusage = SIGN
+eekey = ee-p256
+status = 0
+
+; A chain using ECDSA with P-256, signature on EE uses SHA-512.
+[chain]
+name = secp256r1-sha512
+anchors = root-p256
+chain = ee-p256-sha512.crt ica2-p256.crt ica1-p256.crt
+servername = www.example.com
+keytype = EC
+keyusage = SIGN
+eekey = ee-p256
+status = 0
+
+; EE certificate has a Certificate Policies extension, but it is not
+; critical.
+[chain]
+name = certpol-noncrit
+anchors = root-new
+chain = ee-cp1.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; EE certificate has a critical Certificate Policies extension, but it
+; contains no policy qualifier.
+[chain]
+name = certpol-noqual
+anchors = root-new
+chain = ee-cp2.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; EE certificate has a critical Certificate Policies extension, and it
+; contains some qualifiers, but they are all id-qt-cps.
+[chain]
+name = certpol-qualcps
+anchors = root-new
+chain = ee-cp3.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 0
+
+; EE certificate has a critical Certificate Policies extension, and it
+; contains a qualifier distinct from id-qt-cps. This implies rejection
+; of the path.
+[chain]
+name = certpol-qualother
+anchors = root-new
+chain = ee-cp4.crt
+servername = www.example.com
+keytype = RSA
+keyusage = KEYX
+eekey = ee-rsa2048
+status = 57
diff --git a/contrib/bearssl/test/x509/dn-ee.der b/contrib/bearssl/test/x509/dn-ee.der
new file mode 100644
index 000000000000..ca1c9ed414fe
--- /dev/null
+++ b/contrib/bearssl/test/x509/dn-ee.der
@@ -0,0 +1 @@
+0'1 0 UCA10Uwww.example.com \ No newline at end of file
diff --git a/contrib/bearssl/test/x509/dn-ica1.der b/contrib/bearssl/test/x509/dn-ica1.der
new file mode 100644
index 000000000000..3b0103fc6f5b
--- /dev/null
+++ b/contrib/bearssl/test/x509/dn-ica1.der
@@ -0,0 +1 @@
+011 0 UCA1"0 UExample Intermediate CA 1 \ No newline at end of file
diff --git a/contrib/bearssl/test/x509/dn-ica2.der b/contrib/bearssl/test/x509/dn-ica2.der
new file mode 100644
index 000000000000..d8cddad1d7dd
--- /dev/null
+++ b/contrib/bearssl/test/x509/dn-ica2.der
@@ -0,0 +1 @@
+011 0 UCA1"0 UExample Intermediate CA 2 \ No newline at end of file
diff --git a/contrib/bearssl/test/x509/dn-root-new.der b/contrib/bearssl/test/x509/dn-root-new.der
new file mode 100644
index 000000000000..2ec557573cfb
--- /dev/null
+++ b/contrib/bearssl/test/x509/dn-root-new.der
@@ -0,0 +1 @@
+0(1 0 UCA10UExample Root New \ No newline at end of file
diff --git a/contrib/bearssl/test/x509/dn-root.der b/contrib/bearssl/test/x509/dn-root.der
new file mode 100644
index 000000000000..ea891f9f0136
--- /dev/null
+++ b/contrib/bearssl/test/x509/dn-root.der
@@ -0,0 +1 @@
+0$1 0 UCA10U Example Root \ No newline at end of file
diff --git a/contrib/bearssl/test/x509/ee-badsig1.crt b/contrib/bearssl/test/x509/ee-badsig1.crt
new file mode 100644
index 000000000000..03bcc771e455
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-badsig1.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-badsig2.crt b/contrib/bearssl/test/x509/ee-badsig2.crt
new file mode 100644
index 000000000000..127309dd4d97
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-badsig2.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-cp1.crt b/contrib/bearssl/test/x509/ee-cp1.crt
new file mode 100644
index 000000000000..95f52e3f31d0
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-cp1.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-cp2.crt b/contrib/bearssl/test/x509/ee-cp2.crt
new file mode 100644
index 000000000000..357bc780b568
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-cp2.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-cp3.crt b/contrib/bearssl/test/x509/ee-cp3.crt
new file mode 100644
index 000000000000..2a319dcc7cf2
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-cp3.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-cp4.crt b/contrib/bearssl/test/x509/ee-cp4.crt
new file mode 100644
index 000000000000..d367f99108f9
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-cp4.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-dates.crt b/contrib/bearssl/test/x509/ee-dates.crt
new file mode 100644
index 000000000000..9dfa40a1c7be
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-dates.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-md5.crt b/contrib/bearssl/test/x509/ee-md5.crt
new file mode 100644
index 000000000000..1d5724d63536
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-md5.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-names.crt b/contrib/bearssl/test/x509/ee-names.crt
new file mode 100644
index 000000000000..5631de8ca06f
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-names.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-names2.crt b/contrib/bearssl/test/x509/ee-names2.crt
new file mode 100644
index 000000000000..f1f8133aea66
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-names2.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-names3.crt b/contrib/bearssl/test/x509/ee-names3.crt
new file mode 100644
index 000000000000..2b6bb2a8d350
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-names3.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-names4.crt b/contrib/bearssl/test/x509/ee-names4.crt
new file mode 100644
index 000000000000..6c24d1f41dcf
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-names4.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-p256-sha1.crt b/contrib/bearssl/test/x509/ee-p256-sha1.crt
new file mode 100644
index 000000000000..6da9ca7fa918
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-p256-sha1.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-p256-sha224.crt b/contrib/bearssl/test/x509/ee-p256-sha224.crt
new file mode 100644
index 000000000000..165868ba21bc
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-p256-sha224.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-p256-sha256.crt b/contrib/bearssl/test/x509/ee-p256-sha256.crt
new file mode 100644
index 000000000000..de3c29e1a970
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-p256-sha256.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-p256-sha384.crt b/contrib/bearssl/test/x509/ee-p256-sha384.crt
new file mode 100644
index 000000000000..c117aca7358c
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-p256-sha384.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-p256-sha512.crt b/contrib/bearssl/test/x509/ee-p256-sha512.crt
new file mode 100644
index 000000000000..f8a6016db00e
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-p256-sha512.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-p256.crt b/contrib/bearssl/test/x509/ee-p256.crt
new file mode 100644
index 000000000000..de3c29e1a970
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-p256.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-p384.crt b/contrib/bearssl/test/x509/ee-p384.crt
new file mode 100644
index 000000000000..bda5ea92af1d
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-p384.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-p521.crt b/contrib/bearssl/test/x509/ee-p521.crt
new file mode 100644
index 000000000000..281160c4af0e
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-p521.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-sha1.crt b/contrib/bearssl/test/x509/ee-sha1.crt
new file mode 100644
index 000000000000..6fbadac9c9e3
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-sha1.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-sha224.crt b/contrib/bearssl/test/x509/ee-sha224.crt
new file mode 100644
index 000000000000..7f1fa9d86456
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-sha224.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-sha384.crt b/contrib/bearssl/test/x509/ee-sha384.crt
new file mode 100644
index 000000000000..15e3ffce41cb
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-sha384.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-sha512.crt b/contrib/bearssl/test/x509/ee-sha512.crt
new file mode 100644
index 000000000000..f5721a84aa97
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-sha512.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee-trailing.crt b/contrib/bearssl/test/x509/ee-trailing.crt
new file mode 100644
index 000000000000..810c94cae245
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee-trailing.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ee.crt b/contrib/bearssl/test/x509/ee.crt
new file mode 100644
index 000000000000..8914d31a2ec0
--- /dev/null
+++ b/contrib/bearssl/test/x509/ee.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ica1-1016.crt b/contrib/bearssl/test/x509/ica1-1016.crt
new file mode 100644
index 000000000000..4735602c2d82
--- /dev/null
+++ b/contrib/bearssl/test/x509/ica1-1016.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ica1-1017.crt b/contrib/bearssl/test/x509/ica1-1017.crt
new file mode 100644
index 000000000000..3f7946649e9a
--- /dev/null
+++ b/contrib/bearssl/test/x509/ica1-1017.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ica1-4096.crt b/contrib/bearssl/test/x509/ica1-4096.crt
new file mode 100644
index 000000000000..9cc49bcf5687
--- /dev/null
+++ b/contrib/bearssl/test/x509/ica1-4096.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ica1-p256.crt b/contrib/bearssl/test/x509/ica1-p256.crt
new file mode 100644
index 000000000000..e96d9aff1f32
--- /dev/null
+++ b/contrib/bearssl/test/x509/ica1-p256.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ica1-p384.crt b/contrib/bearssl/test/x509/ica1-p384.crt
new file mode 100644
index 000000000000..695f8a640dcf
--- /dev/null
+++ b/contrib/bearssl/test/x509/ica1-p384.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ica1-p521.crt b/contrib/bearssl/test/x509/ica1-p521.crt
new file mode 100644
index 000000000000..017da0b78ea9
--- /dev/null
+++ b/contrib/bearssl/test/x509/ica1-p521.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ica1.crt b/contrib/bearssl/test/x509/ica1.crt
new file mode 100644
index 000000000000..ea3bfe3b386f
--- /dev/null
+++ b/contrib/bearssl/test/x509/ica1.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ica2-1016.crt b/contrib/bearssl/test/x509/ica2-1016.crt
new file mode 100644
index 000000000000..55ab9562c35e
--- /dev/null
+++ b/contrib/bearssl/test/x509/ica2-1016.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ica2-1017.crt b/contrib/bearssl/test/x509/ica2-1017.crt
new file mode 100644
index 000000000000..2b88a5caf5fd
--- /dev/null
+++ b/contrib/bearssl/test/x509/ica2-1017.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ica2-4096.crt b/contrib/bearssl/test/x509/ica2-4096.crt
new file mode 100644
index 000000000000..efc702dce615
--- /dev/null
+++ b/contrib/bearssl/test/x509/ica2-4096.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ica2-notCA.crt b/contrib/bearssl/test/x509/ica2-notCA.crt
new file mode 100644
index 000000000000..21fb8350ec4e
--- /dev/null
+++ b/contrib/bearssl/test/x509/ica2-notCA.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ica2-p256.crt b/contrib/bearssl/test/x509/ica2-p256.crt
new file mode 100644
index 000000000000..94f8ccadce15
--- /dev/null
+++ b/contrib/bearssl/test/x509/ica2-p256.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ica2-p384.crt b/contrib/bearssl/test/x509/ica2-p384.crt
new file mode 100644
index 000000000000..5dcbb0cf622c
--- /dev/null
+++ b/contrib/bearssl/test/x509/ica2-p384.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ica2-p521.crt b/contrib/bearssl/test/x509/ica2-p521.crt
new file mode 100644
index 000000000000..d7d47571f5fe
--- /dev/null
+++ b/contrib/bearssl/test/x509/ica2-p521.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/ica2.crt b/contrib/bearssl/test/x509/ica2.crt
new file mode 100644
index 000000000000..09bdaa66581f
--- /dev/null
+++ b/contrib/bearssl/test/x509/ica2.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/junk.crt b/contrib/bearssl/test/x509/junk.crt
new file mode 100644
index 000000000000..54e2084f6c7e
--- /dev/null
+++ b/contrib/bearssl/test/x509/junk.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/names.crt b/contrib/bearssl/test/x509/names.crt
new file mode 100644
index 000000000000..fe738c3573d5
--- /dev/null
+++ b/contrib/bearssl/test/x509/names.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/root-p256.crt b/contrib/bearssl/test/x509/root-p256.crt
new file mode 100644
index 000000000000..819654afce13
--- /dev/null
+++ b/contrib/bearssl/test/x509/root-p256.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/root-p384.crt b/contrib/bearssl/test/x509/root-p384.crt
new file mode 100644
index 000000000000..bd397d57b99a
--- /dev/null
+++ b/contrib/bearssl/test/x509/root-p384.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/root-p521.crt b/contrib/bearssl/test/x509/root-p521.crt
new file mode 100644
index 000000000000..a95e82b3fcc9
--- /dev/null
+++ b/contrib/bearssl/test/x509/root-p521.crt
Binary files differ
diff --git a/contrib/bearssl/test/x509/root.crt b/contrib/bearssl/test/x509/root.crt
new file mode 100644
index 000000000000..4352b51c107f
--- /dev/null
+++ b/contrib/bearssl/test/x509/root.crt
Binary files differ
diff --git a/contrib/bearssl/tools/brssl.c b/contrib/bearssl/tools/brssl.c
new file mode 100644
index 000000000000..91372b09f421
--- /dev/null
+++ b/contrib/bearssl/tools/brssl.c
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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>
+
+/*
+ * Network stuff on Windows requires some specific code.
+ */
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#pragma comment(lib, "Ws2_32.lib")
+#endif
+
+#include "brssl.h"
+
+static void
+usage(void)
+{
+ fprintf(stderr, "usage: brssl command [ options ]\n");
+ fprintf(stderr, "available commands:\n");
+ fprintf(stderr, " client run SSL client\n");
+ fprintf(stderr, " server run SSL server\n");
+ fprintf(stderr, " verify verify certificate chain\n");
+ fprintf(stderr, " skey decode private key\n");
+ fprintf(stderr, " ta decode trust anchors\n");
+ fprintf(stderr, " chain make C code for certificate chains\n");
+ fprintf(stderr, " twrch run the Twrch protocol\n");
+ fprintf(stderr, " impl report on implementations\n");
+}
+
+int
+main(int argc, char *argv[])
+{
+ char *cmd;
+
+ if (argc < 2) {
+ usage();
+ return EXIT_FAILURE;
+ }
+#ifdef _WIN32
+ {
+ WSADATA wd;
+ int r;
+
+ r = WSAStartup(MAKEWORD(2, 2), &wd);
+ if (r != 0) {
+ fprintf(stderr, "WARNING: network initialisation"
+ " failed (WSAStartup() returned %d)\n", r);
+ }
+ }
+#endif
+ cmd = argv[1];
+ if (eqstr(cmd, "client")) {
+ if (do_client(argc - 2, argv + 2) < 0) {
+ return EXIT_FAILURE;
+ }
+ } else if (eqstr(cmd, "server")) {
+ if (do_server(argc - 2, argv + 2) < 0) {
+ return EXIT_FAILURE;
+ }
+ } else if (eqstr(cmd, "verify")) {
+ if (do_verify(argc - 2, argv + 2) < 0) {
+ return EXIT_FAILURE;
+ }
+ } else if (eqstr(cmd, "skey")) {
+ if (do_skey(argc - 2, argv + 2) < 0) {
+ return EXIT_FAILURE;
+ }
+ } else if (eqstr(cmd, "ta")) {
+ if (do_ta(argc - 2, argv + 2) < 0) {
+ return EXIT_FAILURE;
+ }
+ } else if (eqstr(cmd, "chain")) {
+ if (do_chain(argc - 2, argv + 2) < 0) {
+ return EXIT_FAILURE;
+ }
+ } else if (eqstr(cmd, "twrch")) {
+ int ret;
+
+ ret = do_twrch(argc - 2, argv + 2);
+ if (ret < 0) {
+ return EXIT_FAILURE;
+ } else {
+ return ret;
+ }
+ } else if (eqstr(cmd, "impl")) {
+ if (do_impl(argc - 2, argv + 2) < 0) {
+ return EXIT_FAILURE;
+ }
+ } else {
+ fprintf(stderr, "unknown command: '%s'\n", cmd);
+ usage();
+ return EXIT_FAILURE;
+ }
+ return 0;
+}
diff --git a/contrib/bearssl/tools/brssl.h b/contrib/bearssl/tools/brssl.h
new file mode 100644
index 000000000000..62ea7e9ff1a9
--- /dev/null
+++ b/contrib/bearssl/tools/brssl.h
@@ -0,0 +1,572 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#ifndef BRSSL_H__
+#define BRSSL_H__
+
+#ifndef _STANDALONE
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+
+#elif !defined(STAND_H)
+#include <stand.h>
+#endif
+
+#include "bearssl.h"
+
+/*
+ * malloc() wrapper:
+ * -- If len is 0, then NULL is returned.
+ * -- If len is non-zero, and allocation fails, then an error message is
+ * printed and the process exits with an error code.
+ */
+void *xmalloc(size_t len);
+
+/*
+ * free() wrapper, meant to release blocks allocated with xmalloc().
+ */
+void xfree(void *buf);
+
+/*
+ * Duplicate a character string into a newly allocated block.
+ */
+char *xstrdup(const void *src);
+
+/*
+ * Allocate a new block with the provided length, filled with a copy
+ * of exactly that many bytes starting at address 'src'.
+ */
+void *xblobdup(const void *src, size_t len);
+
+/*
+ * Duplicate a public key, into newly allocated blocks. The returned
+ * key must be later on released with xfreepkey().
+ */
+br_x509_pkey *xpkeydup(const br_x509_pkey *pk);
+
+/*
+ * Release a public key that was allocated with xpkeydup(). If pk is NULL,
+ * this function does nothing.
+ */
+void xfreepkey(br_x509_pkey *pk);
+
+/*
+ * Macros for growable arrays.
+ */
+
+/*
+ * Make a structure type for a vector of 'type'.
+ */
+#define VECTOR(type) struct { \
+ type *buf; \
+ size_t ptr, len; \
+ }
+
+/*
+ * Constant initialiser for a vector.
+ */
+#define VEC_INIT { 0, 0, 0 }
+
+/*
+ * Clear a vector.
+ */
+#define VEC_CLEAR(vec) do { \
+ xfree((vec).buf); \
+ (vec).buf = NULL; \
+ (vec).ptr = 0; \
+ (vec).len = 0; \
+ } while (0)
+
+/*
+ * Clear a vector, first calling the provided function on each vector
+ * element.
+ */
+#define VEC_CLEAREXT(vec, fun) do { \
+ size_t vec_tmp; \
+ for (vec_tmp = 0; vec_tmp < (vec).ptr; vec_tmp ++) { \
+ (fun)(&(vec).buf[vec_tmp]); \
+ } \
+ VEC_CLEAR(vec); \
+ } while (0)
+
+/*
+ * Add a value at the end of a vector.
+ */
+#define VEC_ADD(vec, x) do { \
+ (vec).buf = vector_expand((vec).buf, sizeof *((vec).buf), \
+ &(vec).ptr, &(vec).len, 1); \
+ (vec).buf[(vec).ptr ++] = (x); \
+ } while (0)
+
+/*
+ * Add several values at the end of a vector.
+ */
+#define VEC_ADDMANY(vec, xp, num) do { \
+ size_t vec_num = (num); \
+ (vec).buf = vector_expand((vec).buf, sizeof *((vec).buf), \
+ &(vec).ptr, &(vec).len, vec_num); \
+ memcpy((vec).buf + (vec).ptr, \
+ (xp), vec_num * sizeof *((vec).buf)); \
+ (vec).ptr += vec_num; \
+ } while (0)
+
+/*
+ * Access a vector element by index. This is a lvalue, and can be modified.
+ */
+#define VEC_ELT(vec, idx) ((vec).buf[idx])
+
+/*
+ * Get current vector length.
+ */
+#define VEC_LEN(vec) ((vec).ptr)
+
+/*
+ * Copy all vector elements into a newly allocated block.
+ */
+#define VEC_TOARRAY(vec) xblobdup((vec).buf, sizeof *((vec).buf) * (vec).ptr)
+
+/*
+ * Internal function used to handle memory allocations for vectors.
+ */
+void *vector_expand(void *buf,
+ size_t esize, size_t *ptr, size_t *len, size_t extra);
+
+/*
+ * Type for a vector of bytes.
+ */
+typedef VECTOR(unsigned char) bvector;
+
+/*
+ * Compare two strings for equality; returned value is 1 if the strings
+ * are to be considered equal, 0 otherwise. Comparison is case-insensitive
+ * (ASCII letters only) and skips some characters (all whitespace, defined
+ * as ASCII codes 0 to 32 inclusive, and also '-', '_', '.', '/', '+' and
+ * ':').
+ */
+int eqstr(const char *s1, const char *s2);
+
+/*
+ * Convert a string to a positive integer (size_t). Returned value is
+ * (size_t)-1 on error. On error, an explicit error message is printed.
+ */
+size_t parse_size(const char *s);
+
+/*
+ * Structure for a known protocol version.
+ */
+typedef struct {
+ const char *name;
+ unsigned version;
+ const char *comment;
+} protocol_version;
+
+/*
+ * Known protocol versions. Last element has a NULL name.
+ */
+extern const protocol_version protocol_versions[];
+
+/*
+ * Parse a version name. If the name is not recognized, then an error
+ * message is printed, and 0 is returned.
+ */
+unsigned parse_version(const char *name, size_t len);
+
+/*
+ * Type for a known hash function.
+ */
+typedef struct {
+ const char *name;
+ const br_hash_class *hclass;
+ const char *comment;
+} hash_function;
+
+/*
+ * Known hash functions. Last element has a NULL name.
+ */
+extern const hash_function hash_functions[];
+
+/*
+ * Parse hash function names. This function expects a comma-separated
+ * list of names, and returns a bit mask corresponding to the matched
+ * names. If one of the name does not match, or the list is empty, then
+ * an error message is printed, and 0 is returned.
+ */
+unsigned parse_hash_functions(const char *arg);
+
+/*
+ * Get a curve name (by ID). If the curve ID is not known, this returns
+ * NULL.
+ */
+const char *get_curve_name(int id);
+
+/*
+ * Get a curve name (by ID). The name is written in the provided buffer
+ * (zero-terminated). If the curve ID is not known, the name is
+ * "unknown (***)" where "***" is the decimal value of the identifier.
+ * If the name does not fit in the provided buffer, then dst[0] is set
+ * to 0 (unless len is 0, in which case nothing is written), and -1 is
+ * returned. Otherwise, the name is written in dst[] (with a terminating
+ * 0), and this function returns 0.
+ */
+int get_curve_name_ext(int id, char *dst, size_t len);
+
+/*
+ * Type for a known cipher suite.
+ */
+typedef struct {
+ const char *name;
+ uint16_t suite;
+ unsigned req;
+ const char *comment;
+} cipher_suite;
+
+/*
+ * Known cipher suites. Last element has a NULL name.
+ */
+extern const cipher_suite cipher_suites[];
+
+/*
+ * Flags for cipher suite requirements.
+ */
+#define REQ_TLS12 0x0001 /* suite needs TLS 1.2 */
+#define REQ_SHA1 0x0002 /* suite needs SHA-1 */
+#define REQ_SHA256 0x0004 /* suite needs SHA-256 */
+#define REQ_SHA384 0x0008 /* suite needs SHA-384 */
+#define REQ_AESCBC 0x0010 /* suite needs AES/CBC encryption */
+#define REQ_AESGCM 0x0020 /* suite needs AES/GCM encryption */
+#define REQ_AESCCM 0x0040 /* suite needs AES/CCM encryption */
+#define REQ_CHAPOL 0x0080 /* suite needs ChaCha20+Poly1305 */
+#define REQ_3DESCBC 0x0100 /* suite needs 3DES/CBC encryption */
+#define REQ_RSAKEYX 0x0200 /* suite uses RSA key exchange */
+#define REQ_ECDHE_RSA 0x0400 /* suite uses ECDHE_RSA key exchange */
+#define REQ_ECDHE_ECDSA 0x0800 /* suite uses ECDHE_ECDSA key exchange */
+#define REQ_ECDH 0x1000 /* suite uses static ECDH key exchange */
+
+/*
+ * Parse a list of cipher suite names. The names are comma-separated. If
+ * one of the name is not recognised, or the list is empty, then an
+ * appropriate error message is printed, and NULL is returned.
+ * The returned array is allocated with xmalloc() and must be released
+ * by the caller. That array is terminated with a dummy entry whose 'name'
+ * field is NULL. The number of entries (not counting the dummy entry)
+ * is also written into '*num'.
+ */
+cipher_suite *parse_suites(const char *arg, size_t *num);
+
+/*
+ * Get the name of a cipher suite. Returned value is NULL if the suite is
+ * not recognized.
+ */
+const char *get_suite_name(unsigned suite);
+
+/*
+ * Get the name of a cipher suite. The name is written in the provided
+ * buffer; if the suite is not recognised, then the name is
+ * "unknown (0x****)" where "****" is the hexadecimal value of the suite.
+ * If the name does not fit in the provided buffer, then dst[0] is set
+ * to 0 (unless len is 0, in which case nothing is written), and -1 is
+ * returned. Otherwise, the name is written in dst[] (with a terminating
+ * 0), and this function returns 0.
+ */
+int get_suite_name_ext(unsigned suite, char *dst, size_t len);
+
+/*
+ * Tell whether a cipher suite uses ECDHE key exchange.
+ */
+int uses_ecdhe(unsigned suite);
+
+/*
+ * Print out all known names (for protocol versions, cipher suites...).
+ */
+void list_names(void);
+
+/*
+ * Print out all known elliptic curve names.
+ */
+void list_curves(void);
+
+/*
+ * Get the symbolic name for an elliptic curve (by ID).
+ */
+const char *ec_curve_name(int curve);
+
+/*
+ * Get a curve by symbolic name. If the name is not recognized, -1 is
+ * returned.
+ */
+int get_curve_by_name(const char *str);
+
+/*
+ * Get the symbolic name for a hash function name (by ID).
+ */
+const char *hash_function_name(int id);
+
+/*
+ * Read a file completely. The returned block is allocated with xmalloc()
+ * and must be released by the caller.
+ * If the file cannot be found or read completely, or is empty, then an
+ * appropriate error message is written, and NULL is returned.
+ */
+unsigned char *read_file(const char *fname, size_t *len);
+
+/*
+ * Write a file completely. This returns 0 on success, -1 on error. On
+ * error, an appropriate error message is printed.
+ */
+int write_file(const char *fname, const void *data, size_t len);
+
+/*
+ * This function returns non-zero if the provided buffer "looks like"
+ * a DER-encoded ASN.1 object (criteria: it has the tag for a SEQUENCE
+ * with a definite length that matches the total object length).
+ */
+int looks_like_DER(const unsigned char *buf, size_t len);
+
+/*
+ * Type for a named blob (the 'name' is a normalised PEM header name).
+ */
+typedef struct {
+ char *name;
+ unsigned char *data;
+ size_t data_len;
+} pem_object;
+
+/*
+ * Release the contents of a named blob (buffer and name).
+ */
+void free_pem_object_contents(pem_object *po);
+
+/*
+ * Decode a buffer as a PEM file, and return all objects. On error, NULL
+ * is returned and an error message is printed. Absence of any object
+ * is an error.
+ *
+ * The returned array is terminated by a dummy object whose 'name' is
+ * NULL. The number of objects (not counting the dummy terminator) is
+ * written in '*num'.
+ */
+pem_object *decode_pem(const void *src, size_t len, size_t *num);
+
+/*
+ * Get the certificate(s) from a file. This accepts both a single
+ * DER-encoded certificate, and a text file that contains
+ * PEM-encoded certificates (and possibly other objects, which are
+ * then ignored).
+ *
+ * On decoding error, or if the file turns out to contain no certificate
+ * at all, then an error message is printed and NULL is returned.
+ *
+ * The returned array, and all referenced buffers, are allocated with
+ * xmalloc() and must be released by the caller. The returned array
+ * ends with a dummy entry whose 'data' field is NULL.
+ * The number of decoded certificates (not counting the dummy entry)
+ * is written into '*num'.
+ */
+br_x509_certificate *read_certificates(const char *fname, size_t *num);
+
+/*
+ * Release certificates. This releases all certificate data arrays,
+ * and the whole array as well.
+ */
+void free_certificates(br_x509_certificate *certs, size_t num);
+
+/*
+ * Interpret a certificate as a trust anchor. The trust anchor is
+ * newly allocated with xmalloc() and the caller must release it.
+ * On decoding error, an error message is printed, and this function
+ * returns NULL.
+ */
+br_x509_trust_anchor *certificate_to_trust_anchor(br_x509_certificate *xc);
+
+/*
+ * Type for a vector of trust anchors.
+ */
+typedef VECTOR(br_x509_trust_anchor) anchor_list;
+
+/*
+ * Release contents for a trust anchor (assuming they were dynamically
+ * allocated with xmalloc()). The structure itself is NOT released.
+ */
+void free_ta_contents(br_x509_trust_anchor *ta);
+
+/*
+ * Decode certificates from a file and interpret them as trust anchors.
+ * The trust anchors are added to the provided list. The number of found
+ * anchors is returned; on error, 0 is returned (finding no anchor at
+ * all is considered an error). An appropriate error message is displayed.
+ */
+size_t read_trust_anchors(anchor_list *dst, const char *fname);
+
+/*
+ * Get the "signer key type" for the certificate (key type of the
+ * issuing CA). On error, this prints a message on stderr, and returns 0.
+ */
+int get_cert_signer_algo(br_x509_certificate *xc);
+
+/*
+ * Special "no anchor" X.509 validator that wraps around another X.509
+ * validator and turns "not trusted" error codes into success. This is
+ * by definition insecure, but convenient for debug purposes.
+ */
+typedef struct {
+ const br_x509_class *vtable;
+ const br_x509_class **inner;
+} x509_noanchor_context;
+extern const br_x509_class x509_noanchor_vtable;
+
+/*
+ * Initialise a "no anchor" X.509 validator.
+ */
+void x509_noanchor_init(x509_noanchor_context *xwc,
+ const br_x509_class **inner);
+
+/*
+ * Aggregate type for a private key.
+ */
+typedef struct {
+ int key_type; /* BR_KEYTYPE_RSA or BR_KEYTYPE_EC */
+ union {
+ br_rsa_private_key rsa;
+ br_ec_private_key ec;
+ } key;
+} private_key;
+
+/*
+ * Decode a private key from a file. On error, this prints an error
+ * message and returns NULL.
+ */
+private_key *read_private_key(const char *fname);
+
+/*
+ * Free a private key.
+ */
+void free_private_key(private_key *sk);
+
+/*
+ * Get the encoded OID for a given hash function (to use with PKCS#1
+ * signatures). If the hash function ID is 0 (for MD5+SHA-1), or if
+ * the ID is not one of the SHA-* functions (SHA-1, SHA-224, SHA-256,
+ * SHA-384, SHA-512), then this function returns NULL.
+ */
+const unsigned char *get_hash_oid(int id);
+
+/*
+ * Get a hash implementation by ID. This returns NULL if the hash
+ * implementation is not available.
+ */
+const br_hash_class *get_hash_impl(int id);
+
+/*
+ * Find the symbolic name and the description for an error. If 'err' is
+ * recognised then the error symbolic name is returned; if 'comment' is
+ * not NULL then '*comment' is then set to a descriptive human-readable
+ * message. If the error code 'err' is not recognised, then '*comment' is
+ * untouched and this function returns NULL.
+ */
+const char *find_error_name(int err, const char **comment);
+
+/*
+ * Find the symbolic name for an algorithm implementation. Provided
+ * pointer should be a pointer to a vtable or to a function, where
+ * appropriate. If not recognised, then the string "UNKNOWN" is returned.
+ *
+ * If 'long_name' is non-zero, then the returned name recalls the
+ * algorithm type as well; otherwise, only the core implementation name
+ * is returned (e.g. the long name could be 'aes_big_cbcenc' while the
+ * short name is 'big').
+ */
+const char *get_algo_name(const void *algo, int long_name);
+
+/*
+ * Run a SSL engine, with a socket connected to the peer, and using
+ * stdin/stdout to exchange application data. The socket must be a
+ * non-blocking descriptor.
+ *
+ * To help with Win32 compatibility, the socket descriptor is provided
+ * as an "unsigned long" value.
+ *
+ * Returned value:
+ * 0 SSL connection closed successfully
+ * x > 0 SSL error "x"
+ * -1 early socket close
+ * -2 stdout was closed, or something failed badly
+ */
+int run_ssl_engine(br_ssl_engine_context *eng,
+ unsigned long fd, unsigned flags);
+
+#define RUN_ENGINE_VERBOSE 0x0001 /* enable verbose messages */
+#define RUN_ENGINE_TRACE 0x0002 /* hex dump of records */
+
+/*
+ * Do the "client" command. Returned value is 0 on success, -1 on failure.
+ * Command-line arguments start _after_ the command name.
+ */
+int do_client(int argc, char *argv[]);
+
+/*
+ * Do the "server" command. Returned value is 0 on success, -1 on failure.
+ * Command-line arguments start _after_ the command name.
+ */
+int do_server(int argc, char *argv[]);
+
+/*
+ * Do the "verify" command. Returned value is 0 on success, -1 on failure.
+ * Command-line arguments start _after_ the command name.
+ */
+int do_verify(int argc, char *argv[]);
+
+/*
+ * Do the "skey" command. Returned value is 0 on success, -1 on failure.
+ * Command-line arguments start _after_ the command name.
+ */
+int do_skey(int argc, char *argv[]);
+
+/*
+ * Do the "ta" command. Returned value is 0 on success, -1 on failure.
+ * Command-line arguments start _after_ the command name.
+ */
+int do_ta(int argc, char *argv[]);
+
+/*
+ * Do the "chain" command. Returned value is 0 on success, -1 on failure.
+ * Command-line arguments start _after_ the command name.
+ */
+int do_chain(int argc, char *argv[]);
+
+/*
+ * Do the "twrch" command. Returned value is 0 on success, -1 on failure
+ * (processing or arguments), or a non-zero exit code. Command-line
+ * arguments start _after_ the command name.
+ */
+int do_twrch(int argc, char *argv[]);
+
+/*
+ * Do the "impl" command. Returned value is 0 on success, -1 on failure.
+ * Command-line arguments start _after_ the command name.
+ */
+int do_impl(int argc, char *argv[]);
+
+#endif
diff --git a/contrib/bearssl/tools/certs.c b/contrib/bearssl/tools/certs.c
new file mode 100644
index 000000000000..8986446ee130
--- /dev/null
+++ b/contrib/bearssl/tools/certs.c
@@ -0,0 +1,237 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+
+static void
+dn_append(void *ctx, const void *buf, size_t len)
+{
+ VEC_ADDMANY(*(bvector *)ctx, buf, len);
+}
+
+static int
+certificate_to_trust_anchor_inner(br_x509_trust_anchor *ta,
+ br_x509_certificate *xc)
+{
+ br_x509_decoder_context dc;
+ bvector vdn = VEC_INIT;
+ br_x509_pkey *pk;
+
+ br_x509_decoder_init(&dc, dn_append, &vdn);
+ br_x509_decoder_push(&dc, xc->data, xc->data_len);
+ pk = br_x509_decoder_get_pkey(&dc);
+ if (pk == NULL) {
+ fprintf(stderr, "ERROR: CA decoding failed with error %d\n",
+ br_x509_decoder_last_error(&dc));
+ VEC_CLEAR(vdn);
+ return -1;
+ }
+ ta->dn.data = VEC_TOARRAY(vdn);
+ ta->dn.len = VEC_LEN(vdn);
+ VEC_CLEAR(vdn);
+ ta->flags = 0;
+ if (br_x509_decoder_isCA(&dc)) {
+ ta->flags |= BR_X509_TA_CA;
+ }
+ switch (pk->key_type) {
+ case BR_KEYTYPE_RSA:
+ ta->pkey.key_type = BR_KEYTYPE_RSA;
+ ta->pkey.key.rsa.n = xblobdup(pk->key.rsa.n, pk->key.rsa.nlen);
+ ta->pkey.key.rsa.nlen = pk->key.rsa.nlen;
+ ta->pkey.key.rsa.e = xblobdup(pk->key.rsa.e, pk->key.rsa.elen);
+ ta->pkey.key.rsa.elen = pk->key.rsa.elen;
+ break;
+ case BR_KEYTYPE_EC:
+ ta->pkey.key_type = BR_KEYTYPE_EC;
+ ta->pkey.key.ec.curve = pk->key.ec.curve;
+ ta->pkey.key.ec.q = xblobdup(pk->key.ec.q, pk->key.ec.qlen);
+ ta->pkey.key.ec.qlen = pk->key.ec.qlen;
+ break;
+ default:
+ fprintf(stderr, "ERROR: unsupported public key type in CA\n");
+ xfree(ta->dn.data);
+ return -1;
+ }
+ return 0;
+}
+
+/* see brssl.h */
+br_x509_trust_anchor *
+certificate_to_trust_anchor(br_x509_certificate *xc)
+{
+ br_x509_trust_anchor ta;
+
+ if (certificate_to_trust_anchor_inner(&ta, xc) < 0) {
+ return NULL;
+ } else {
+ return xblobdup(&ta, sizeof ta);
+ }
+}
+
+/* see brssl.h */
+void
+free_ta_contents(br_x509_trust_anchor *ta)
+{
+ xfree(ta->dn.data);
+ switch (ta->pkey.key_type) {
+ case BR_KEYTYPE_RSA:
+ xfree(ta->pkey.key.rsa.n);
+ xfree(ta->pkey.key.rsa.e);
+ break;
+ case BR_KEYTYPE_EC:
+ xfree(ta->pkey.key.ec.q);
+ break;
+ }
+}
+
+/* see brssl.h */
+size_t
+read_trust_anchors(anchor_list *dst, const char *fname)
+{
+ br_x509_certificate *xcs;
+ anchor_list tas = VEC_INIT;
+ size_t u, num;
+
+ xcs = read_certificates(fname, &num);
+ if (xcs == NULL) {
+ return 0;
+ }
+ for (u = 0; u < num; u ++) {
+ br_x509_trust_anchor ta;
+
+ if (certificate_to_trust_anchor_inner(&ta, &xcs[u]) < 0) {
+ VEC_CLEAREXT(tas, free_ta_contents);
+ free_certificates(xcs, num);
+ return 0;
+ }
+ VEC_ADD(tas, ta);
+ }
+ VEC_ADDMANY(*dst, &VEC_ELT(tas, 0), num);
+ VEC_CLEAR(tas);
+ free_certificates(xcs, num);
+ return num;
+}
+
+/* see brssl.h */
+int
+get_cert_signer_algo(br_x509_certificate *xc)
+{
+ br_x509_decoder_context dc;
+ int err;
+
+ br_x509_decoder_init(&dc, 0, 0);
+ br_x509_decoder_push(&dc, xc->data, xc->data_len);
+ err = br_x509_decoder_last_error(&dc);
+ if (err != 0) {
+ fprintf(stderr,
+ "ERROR: certificate decoding failed with error %d\n",
+ -err);
+ return 0;
+ }
+ return br_x509_decoder_get_signer_key_type(&dc);
+}
+
+static void
+xwc_start_chain(const br_x509_class **ctx, const char *server_name)
+{
+ x509_noanchor_context *xwc;
+
+ xwc = (x509_noanchor_context *)ctx;
+ (*xwc->inner)->start_chain(xwc->inner, server_name);
+}
+
+static void
+xwc_start_cert(const br_x509_class **ctx, uint32_t length)
+{
+ x509_noanchor_context *xwc;
+
+ xwc = (x509_noanchor_context *)ctx;
+ (*xwc->inner)->start_cert(xwc->inner, length);
+}
+
+static void
+xwc_append(const br_x509_class **ctx, const unsigned char *buf, size_t len)
+{
+ x509_noanchor_context *xwc;
+
+ xwc = (x509_noanchor_context *)ctx;
+ (*xwc->inner)->append(xwc->inner, buf, len);
+}
+
+static void
+xwc_end_cert(const br_x509_class **ctx)
+{
+ x509_noanchor_context *xwc;
+
+ xwc = (x509_noanchor_context *)ctx;
+ (*xwc->inner)->end_cert(xwc->inner);
+}
+
+static unsigned
+xwc_end_chain(const br_x509_class **ctx)
+{
+ x509_noanchor_context *xwc;
+ unsigned r;
+
+ xwc = (x509_noanchor_context *)ctx;
+ r = (*xwc->inner)->end_chain(xwc->inner);
+ if (r == BR_ERR_X509_NOT_TRUSTED) {
+ r = 0;
+ }
+ return r;
+}
+
+static const br_x509_pkey *
+xwc_get_pkey(const br_x509_class *const *ctx, unsigned *usages)
+{
+ x509_noanchor_context *xwc;
+
+ xwc = (x509_noanchor_context *)ctx;
+ return (*xwc->inner)->get_pkey(xwc->inner, usages);
+}
+
+/* see brssl.h */
+const br_x509_class x509_noanchor_vtable = {
+ sizeof(x509_noanchor_context),
+ xwc_start_chain,
+ xwc_start_cert,
+ xwc_append,
+ xwc_end_cert,
+ xwc_end_chain,
+ xwc_get_pkey
+};
+
+/* see brssl.h */
+void
+x509_noanchor_init(x509_noanchor_context *xwc, const br_x509_class **inner)
+{
+ xwc->vtable = &x509_noanchor_vtable;
+ xwc->inner = inner;
+}
diff --git a/contrib/bearssl/tools/chain.c b/contrib/bearssl/tools/chain.c
new file mode 100644
index 000000000000..671f5e83b9c9
--- /dev/null
+++ b/contrib/bearssl/tools/chain.c
@@ -0,0 +1,154 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+#include "bearssl.h"
+
+static void
+print_blob(const char *name, const unsigned char *buf, size_t len)
+{
+ size_t u;
+
+ printf("\nstatic const unsigned char %s[] = {", name);
+ for (u = 0; u < len; u ++) {
+ if (u != 0) {
+ printf(",");
+ }
+ if (u % 12 == 0) {
+ printf("\n\t");
+ } else {
+ printf(" ");
+ }
+ printf("0x%02X", buf[u]);
+ }
+ printf("\n};\n");
+}
+
+static void
+usage_chain(void)
+{
+ fprintf(stderr,
+"usage: brssl chain [ options ] file...\n");
+ fprintf(stderr,
+"options:\n");
+ fprintf(stderr,
+" -q suppress verbose messages\n");
+}
+
+/* see brssl.h */
+int
+do_chain(int argc, char *argv[])
+{
+ int retcode;
+ int verbose;
+ int i, num_files;
+ long k, ctr;
+
+ retcode = 0;
+ verbose = 1;
+ num_files = 0;
+ for (i = 0; i < argc; i ++) {
+ const char *arg;
+
+ arg = argv[i];
+ if (arg[0] != '-') {
+ num_files ++;
+ continue;
+ }
+ argv[i] = NULL;
+ if (eqstr(arg, "-v") || eqstr(arg, "-verbose")) {
+ verbose = 1;
+ } else if (eqstr(arg, "-q") || eqstr(arg, "-quiet")) {
+ verbose = 0;
+ } else {
+ fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
+ usage_chain();
+ goto chain_exit_error;
+ }
+ }
+ if (num_files == 0) {
+ fprintf(stderr, "ERROR: no certificate file provided\n");
+ usage_chain();
+ goto chain_exit_error;
+ }
+
+ ctr = 0;
+ for (i = 0; i < argc; i ++) {
+ const char *fname;
+ br_x509_certificate *xcs;
+ size_t u, num;
+
+ fname = argv[i];
+ if (fname == NULL) {
+ continue;
+ }
+ if (verbose) {
+ fprintf(stderr, "Reading file '%s': ", fname);
+ fflush(stderr);
+ }
+ xcs = read_certificates(fname, &num);
+ if (xcs == NULL) {
+ goto chain_exit_error;
+ }
+ if (verbose) {
+ fprintf(stderr, "%lu certificate%s\n",
+ (unsigned long)num, num > 1 ? "s" : "");
+ }
+ for (u = 0; u < num; u ++) {
+ char tmp[50];
+
+ sprintf(tmp, "CERT%ld", ctr ++);
+ print_blob(tmp, xcs[u].data, xcs[u].data_len);
+ xfree(xcs[u].data);
+ }
+ xfree(xcs);
+ }
+
+ printf("\nstatic const br_x509_certificate CHAIN[] = {");
+ for (k = 0; k < ctr; k ++) {
+ if (k != 0) {
+ printf(",");
+ }
+ printf("\n\t{ (unsigned char *)CERT%ld, sizeof CERT%ld }",
+ k, k);
+ }
+ printf("\n};\n");
+ printf("\n#define CHAIN_LEN %ld\n", ctr);
+
+ /*
+ * Release allocated structures.
+ */
+chain_exit:
+ return retcode;
+
+chain_exit_error:
+ retcode = -1;
+ goto chain_exit;
+}
diff --git a/contrib/bearssl/tools/client.c b/contrib/bearssl/tools/client.c
new file mode 100644
index 000000000000..9838857275ec
--- /dev/null
+++ b/contrib/bearssl/tools/client.c
@@ -0,0 +1,1112 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 <signal.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define SOCKET int
+#define INVALID_SOCKET (-1)
+#endif
+
+#include "brssl.h"
+
+static int
+host_connect(const char *host, const char *port, int verbose)
+{
+ struct addrinfo hints, *si, *p;
+ SOCKET 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 INVALID_SOCKET;
+ }
+ fd = INVALID_SOCKET;
+ for (p = si; p != NULL; p = p->ai_next) {
+ if (verbose) {
+ 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 *)
+ (void *)sa)->sin_addr;
+ } else if (sa->sa_family == AF_INET6) {
+ addr = &((struct sockaddr_in6 *)
+ (void *)sa)->sin6_addr;
+ } else {
+ addr = NULL;
+ }
+ if (addr != NULL) {
+ if (!inet_ntop(p->ai_family, addr,
+ tmp, sizeof tmp))
+ {
+ strcpy(tmp, "<invalid>");
+ }
+ } 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 == INVALID_SOCKET) {
+ if (verbose) {
+ perror("socket()");
+ }
+ continue;
+ }
+ if (connect(fd, p->ai_addr, p->ai_addrlen) == INVALID_SOCKET) {
+ if (verbose) {
+ perror("connect()");
+ }
+#ifdef _WIN32
+ closesocket(fd);
+#else
+ close(fd);
+#endif
+ continue;
+ }
+ break;
+ }
+ if (p == NULL) {
+ freeaddrinfo(si);
+ fprintf(stderr, "ERROR: failed to connect\n");
+ return INVALID_SOCKET;
+ }
+ freeaddrinfo(si);
+ if (verbose) {
+ fprintf(stderr, "connected.\n");
+ }
+
+ /*
+ * We make the socket non-blocking, since we are going to use
+ * poll() or select() to organise I/O.
+ */
+#ifdef _WIN32
+ {
+ u_long arg;
+
+ arg = 1;
+ ioctlsocket(fd, FIONBIO, &arg);
+ }
+#else
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+#endif
+ return fd;
+}
+
+typedef struct {
+ const br_ssl_client_certificate_class *vtable;
+ int verbose;
+ br_x509_certificate *chain;
+ size_t chain_len;
+ private_key *sk;
+ int issuer_key_type;
+} ccert_context;
+
+static void
+cc_start_name_list(const br_ssl_client_certificate_class **pctx)
+{
+ ccert_context *zc;
+
+ zc = (ccert_context *)pctx;
+ if (zc->verbose) {
+ fprintf(stderr, "Server requests a client certificate.\n");
+ fprintf(stderr, "--- anchor DN list start ---\n");
+ }
+}
+
+static void
+cc_start_name(const br_ssl_client_certificate_class **pctx, size_t len)
+{
+ ccert_context *zc;
+
+ zc = (ccert_context *)pctx;
+ if (zc->verbose) {
+ fprintf(stderr, "new anchor name, length = %u\n",
+ (unsigned)len);
+ }
+}
+
+static void
+cc_append_name(const br_ssl_client_certificate_class **pctx,
+ const unsigned char *data, size_t len)
+{
+ ccert_context *zc;
+
+ zc = (ccert_context *)pctx;
+ if (zc->verbose) {
+ size_t u;
+
+ for (u = 0; u < len; u ++) {
+ if (u == 0) {
+ fprintf(stderr, " ");
+ } else if (u > 0 && u % 16 == 0) {
+ fprintf(stderr, "\n ");
+ }
+ fprintf(stderr, " %02x", data[u]);
+ }
+ if (len > 0) {
+ fprintf(stderr, "\n");
+ }
+ }
+}
+
+static void
+cc_end_name(const br_ssl_client_certificate_class **pctx)
+{
+ (void)pctx;
+}
+
+static void
+cc_end_name_list(const br_ssl_client_certificate_class **pctx)
+{
+ ccert_context *zc;
+
+ zc = (ccert_context *)pctx;
+ if (zc->verbose) {
+ fprintf(stderr, "--- anchor DN list end ---\n");
+ }
+}
+
+static void
+print_hashes(unsigned hh, unsigned hh2)
+{
+ int i;
+
+ for (i = 0; i < 8; i ++) {
+ const char *name;
+
+ name = hash_function_name(i);
+ if (((hh >> i) & 1) != 0) {
+ fprintf(stderr, " %s", name);
+ } else if (((hh2 >> i) & 1) != 0) {
+ fprintf(stderr, " (%s)", name);
+ }
+ }
+}
+
+static int
+choose_hash(unsigned hh)
+{
+ static const int f[] = {
+ br_sha256_ID, br_sha224_ID, br_sha384_ID, br_sha512_ID,
+ br_sha1_ID, br_md5sha1_ID, -1
+ };
+
+ size_t u;
+
+ for (u = 0; f[u] >= 0; u ++) {
+ if (((hh >> f[u]) & 1) != 0) {
+ return f[u];
+ }
+ }
+ return -1;
+}
+
+static void
+cc_choose(const br_ssl_client_certificate_class **pctx,
+ const br_ssl_client_context *cc, uint32_t auth_types,
+ br_ssl_client_certificate *choices)
+{
+ ccert_context *zc;
+ int scurve;
+
+ zc = (ccert_context *)pctx;
+ scurve = br_ssl_client_get_server_curve(cc);
+ if (zc->verbose) {
+ unsigned hashes;
+
+ hashes = br_ssl_client_get_server_hashes(cc);
+ if ((auth_types & 0x00FF) != 0) {
+ fprintf(stderr, "supported: RSA signatures:");
+ print_hashes(auth_types, hashes);
+ fprintf(stderr, "\n");
+ }
+ if ((auth_types & 0xFF00) != 0) {
+ fprintf(stderr, "supported: ECDSA signatures:");
+ print_hashes(auth_types >> 8, hashes >> 8);
+ fprintf(stderr, "\n");
+ }
+ if ((auth_types & 0x010000) != 0) {
+ fprintf(stderr, "supported:"
+ " fixed ECDH (cert signed with RSA)\n");
+ }
+ if ((auth_types & 0x020000) != 0) {
+ fprintf(stderr, "supported:"
+ " fixed ECDH (cert signed with ECDSA)\n");
+ }
+ if (scurve) {
+ fprintf(stderr, "server key curve: %s (%d)\n",
+ ec_curve_name(scurve), scurve);
+ } else {
+ fprintf(stderr, "server key is not EC\n");
+ }
+ }
+ switch (zc->sk->key_type) {
+ case BR_KEYTYPE_RSA:
+ if ((choices->hash_id = choose_hash(auth_types)) >= 0) {
+ if (zc->verbose) {
+ fprintf(stderr, "using RSA, hash = %d (%s)\n",
+ choices->hash_id,
+ hash_function_name(choices->hash_id));
+ }
+ choices->auth_type = BR_AUTH_RSA;
+ choices->chain = zc->chain;
+ choices->chain_len = zc->chain_len;
+ return;
+ }
+ break;
+ case BR_KEYTYPE_EC:
+ if (zc->issuer_key_type != 0
+ && scurve == zc->sk->key.ec.curve)
+ {
+ int x;
+
+ x = (zc->issuer_key_type == BR_KEYTYPE_RSA) ? 16 : 17;
+ if (((auth_types >> x) & 1) != 0) {
+ if (zc->verbose) {
+ fprintf(stderr, "using static ECDH\n");
+ }
+ choices->auth_type = BR_AUTH_ECDH;
+ choices->hash_id = -1;
+ choices->chain = zc->chain;
+ choices->chain_len = zc->chain_len;
+ return;
+ }
+ }
+ if ((choices->hash_id = choose_hash(auth_types >> 8)) >= 0) {
+ if (zc->verbose) {
+ fprintf(stderr, "using ECDSA, hash = %d (%s)\n",
+ choices->hash_id,
+ hash_function_name(choices->hash_id));
+ }
+ choices->auth_type = BR_AUTH_ECDSA;
+ choices->chain = zc->chain;
+ choices->chain_len = zc->chain_len;
+ return;
+ }
+ break;
+ }
+ if (zc->verbose) {
+ fprintf(stderr, "no matching client certificate\n");
+ }
+ choices->chain = NULL;
+ choices->chain_len = 0;
+}
+
+static uint32_t
+cc_do_keyx(const br_ssl_client_certificate_class **pctx,
+ unsigned char *data, size_t *len)
+{
+ const br_ec_impl *iec;
+ ccert_context *zc;
+ size_t xoff, xlen;
+ uint32_t r;
+
+ zc = (ccert_context *)pctx;
+ iec = br_ec_get_default();
+ r = iec->mul(data, *len, zc->sk->key.ec.x,
+ zc->sk->key.ec.xlen, zc->sk->key.ec.curve);
+ xoff = iec->xoff(zc->sk->key.ec.curve, &xlen);
+ memmove(data, data + xoff, xlen);
+ *len = xlen;
+ return r;
+}
+
+static size_t
+cc_do_sign(const br_ssl_client_certificate_class **pctx,
+ int hash_id, size_t hv_len, unsigned char *data, size_t len)
+{
+ ccert_context *zc;
+ unsigned char hv[64];
+
+ zc = (ccert_context *)pctx;
+ memcpy(hv, data, hv_len);
+ switch (zc->sk->key_type) {
+ const br_hash_class *hc;
+ const unsigned char *hash_oid;
+ uint32_t x;
+ size_t sig_len;
+
+ case BR_KEYTYPE_RSA:
+ hash_oid = get_hash_oid(hash_id);
+ if (hash_oid == NULL && hash_id != 0) {
+ if (zc->verbose) {
+ fprintf(stderr, "ERROR: cannot RSA-sign with"
+ " unknown hash function: %d\n",
+ hash_id);
+ }
+ return 0;
+ }
+ sig_len = (zc->sk->key.rsa.n_bitlen + 7) >> 3;
+ if (len < sig_len) {
+ if (zc->verbose) {
+ fprintf(stderr, "ERROR: cannot RSA-sign,"
+ " buffer is too small"
+ " (sig=%lu, buf=%lu)\n",
+ (unsigned long)sig_len,
+ (unsigned long)len);
+ }
+ return 0;
+ }
+ x = br_rsa_pkcs1_sign_get_default()(
+ hash_oid, hv, hv_len, &zc->sk->key.rsa, data);
+ if (!x) {
+ if (zc->verbose) {
+ fprintf(stderr, "ERROR: RSA-sign failure\n");
+ }
+ return 0;
+ }
+ return sig_len;
+
+ case BR_KEYTYPE_EC:
+ hc = get_hash_impl(hash_id);
+ if (hc == NULL) {
+ if (zc->verbose) {
+ fprintf(stderr, "ERROR: cannot ECDSA-sign with"
+ " unknown hash function: %d\n",
+ hash_id);
+ }
+ return 0;
+ }
+ if (len < 139) {
+ if (zc->verbose) {
+ fprintf(stderr, "ERROR: cannot ECDSA-sign"
+ " (output buffer = %lu)\n",
+ (unsigned long)len);
+ }
+ return 0;
+ }
+ sig_len = br_ecdsa_sign_asn1_get_default()(
+ br_ec_get_default(), hc, hv, &zc->sk->key.ec, data);
+ if (sig_len == 0) {
+ if (zc->verbose) {
+ fprintf(stderr, "ERROR: ECDSA-sign failure\n");
+ }
+ return 0;
+ }
+ return sig_len;
+
+ default:
+ return 0;
+ }
+}
+
+static const br_ssl_client_certificate_class ccert_vtable = {
+ sizeof(ccert_context),
+ cc_start_name_list,
+ cc_start_name,
+ cc_append_name,
+ cc_end_name,
+ cc_end_name_list,
+ cc_choose,
+ cc_do_keyx,
+ cc_do_sign
+};
+
+static void
+free_alpn(void *alpn)
+{
+ xfree(*(char **)alpn);
+}
+
+static void
+usage_client(void)
+{
+ fprintf(stderr,
+"usage: brssl client server[:port] [ options ]\n");
+ fprintf(stderr,
+"options:\n");
+ fprintf(stderr,
+" -q suppress verbose messages\n");
+ fprintf(stderr,
+" -trace activate extra debug messages (dump of all packets)\n");
+ fprintf(stderr,
+" -sni name use this specific name for SNI\n");
+ fprintf(stderr,
+" -nosni do not send any SNI\n");
+ fprintf(stderr,
+" -mono use monodirectional buffering\n");
+ fprintf(stderr,
+" -buf length set the I/O buffer length (in bytes)\n");
+ fprintf(stderr,
+" -CA file add certificates in 'file' to trust anchors\n");
+ fprintf(stderr,
+" -cert file set client certificate chain\n");
+ fprintf(stderr,
+" -key file set client private key (for certificate authentication)\n");
+ fprintf(stderr,
+" -nostaticecdh prohibit full-static ECDH (client certificate)\n");
+ fprintf(stderr,
+" -list list supported names (protocols, algorithms...)\n");
+ fprintf(stderr,
+" -vmin name set minimum supported version (default: TLS-1.0)\n");
+ fprintf(stderr,
+" -vmax name set maximum supported version (default: TLS-1.2)\n");
+ fprintf(stderr,
+" -cs names set list of supported cipher suites (comma-separated)\n");
+ fprintf(stderr,
+" -hf names add support for some hash functions (comma-separated)\n");
+ fprintf(stderr,
+" -minhello len set minimum ClientHello length (in bytes)\n");
+ fprintf(stderr,
+" -fallback send the TLS_FALLBACK_SCSV (i.e. claim a downgrade)\n");
+ fprintf(stderr,
+" -noreneg prohibit renegotiations\n");
+ fprintf(stderr,
+" -alpn name add protocol name to list of protocols (ALPN extension)\n");
+ fprintf(stderr,
+" -strictalpn fail on ALPN mismatch\n");
+}
+
+/* see brssl.h */
+int
+do_client(int argc, char *argv[])
+{
+ int retcode;
+ int verbose;
+ int trace;
+ int i, bidi;
+ const char *server_name;
+ char *host;
+ char *port;
+ const char *sni;
+ anchor_list anchors = VEC_INIT;
+ unsigned vmin, vmax;
+ VECTOR(char *) alpn_names = VEC_INIT;
+ cipher_suite *suites;
+ size_t num_suites;
+ uint16_t *suite_ids;
+ unsigned hfuns;
+ size_t u;
+ br_ssl_client_context cc;
+ br_x509_minimal_context xc;
+ x509_noanchor_context xwc;
+ const br_hash_class *dnhash;
+ ccert_context zc;
+ br_x509_certificate *chain;
+ size_t chain_len;
+ private_key *sk;
+ int nostaticecdh;
+ unsigned char *iobuf;
+ size_t iobuf_len;
+ size_t minhello_len;
+ int fallback;
+ uint32_t flags;
+ SOCKET fd;
+
+ retcode = 0;
+ verbose = 1;
+ trace = 0;
+ server_name = NULL;
+ host = NULL;
+ port = NULL;
+ sni = NULL;
+ bidi = 1;
+ vmin = 0;
+ vmax = 0;
+ suites = NULL;
+ num_suites = 0;
+ hfuns = 0;
+ suite_ids = NULL;
+ chain = NULL;
+ chain_len = 0;
+ sk = NULL;
+ nostaticecdh = 0;
+ iobuf = NULL;
+ iobuf_len = 0;
+ minhello_len = (size_t)-1;
+ fallback = 0;
+ flags = 0;
+ fd = INVALID_SOCKET;
+ for (i = 0; i < argc; i ++) {
+ const char *arg;
+
+ arg = argv[i];
+ if (arg[0] != '-') {
+ if (server_name != NULL) {
+ fprintf(stderr,
+ "ERROR: duplicate server name\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ server_name = arg;
+ continue;
+ }
+ if (eqstr(arg, "-v") || eqstr(arg, "-verbose")) {
+ verbose = 1;
+ } else if (eqstr(arg, "-q") || eqstr(arg, "-quiet")) {
+ verbose = 0;
+ } else if (eqstr(arg, "-trace")) {
+ trace = 1;
+ } else if (eqstr(arg, "-sni")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-sni'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ if (sni != NULL) {
+ fprintf(stderr, "ERROR: duplicate SNI\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ sni = argv[i];
+ } else if (eqstr(arg, "-nosni")) {
+ if (sni != NULL) {
+ fprintf(stderr, "ERROR: duplicate SNI\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ sni = "";
+ } else if (eqstr(arg, "-mono")) {
+ bidi = 0;
+ } else if (eqstr(arg, "-buf")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-buf'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ arg = argv[i];
+ if (iobuf_len != 0) {
+ fprintf(stderr,
+ "ERROR: duplicate I/O buffer length\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ iobuf_len = parse_size(arg);
+ if (iobuf_len == (size_t)-1) {
+ usage_client();
+ goto client_exit_error;
+ }
+ } else if (eqstr(arg, "-CA")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-CA'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ arg = argv[i];
+ if (read_trust_anchors(&anchors, arg) == 0) {
+ usage_client();
+ goto client_exit_error;
+ }
+ } else if (eqstr(arg, "-cert")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-cert'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ if (chain != NULL) {
+ fprintf(stderr,
+ "ERROR: duplicate certificate chain\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ arg = argv[i];
+ chain = read_certificates(arg, &chain_len);
+ if (chain == NULL || chain_len == 0) {
+ goto client_exit_error;
+ }
+ } else if (eqstr(arg, "-key")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-key'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ if (sk != NULL) {
+ fprintf(stderr,
+ "ERROR: duplicate private key\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ arg = argv[i];
+ sk = read_private_key(arg);
+ if (sk == NULL) {
+ goto client_exit_error;
+ }
+ } else if (eqstr(arg, "-nostaticecdh")) {
+ nostaticecdh = 1;
+ } else if (eqstr(arg, "-list")) {
+ list_names();
+ goto client_exit;
+ } else if (eqstr(arg, "-vmin")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-vmin'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ arg = argv[i];
+ if (vmin != 0) {
+ fprintf(stderr,
+ "ERROR: duplicate minimum version\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ vmin = parse_version(arg, strlen(arg));
+ if (vmin == 0) {
+ fprintf(stderr,
+ "ERROR: unrecognised version '%s'\n",
+ arg);
+ usage_client();
+ goto client_exit_error;
+ }
+ } else if (eqstr(arg, "-vmax")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-vmax'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ arg = argv[i];
+ if (vmax != 0) {
+ fprintf(stderr,
+ "ERROR: duplicate maximum version\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ vmax = parse_version(arg, strlen(arg));
+ if (vmax == 0) {
+ fprintf(stderr,
+ "ERROR: unrecognised version '%s'\n",
+ arg);
+ usage_client();
+ goto client_exit_error;
+ }
+ } else if (eqstr(arg, "-cs")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-cs'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ arg = argv[i];
+ if (suites != NULL) {
+ fprintf(stderr, "ERROR: duplicate list"
+ " of cipher suites\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ suites = parse_suites(arg, &num_suites);
+ if (suites == NULL) {
+ usage_client();
+ goto client_exit_error;
+ }
+ } else if (eqstr(arg, "-hf")) {
+ unsigned x;
+
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-hf'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ arg = argv[i];
+ x = parse_hash_functions(arg);
+ if (x == 0) {
+ usage_client();
+ goto client_exit_error;
+ }
+ hfuns |= x;
+ } else if (eqstr(arg, "-minhello")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-minhello'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ arg = argv[i];
+ if (minhello_len != (size_t)-1) {
+ fprintf(stderr, "ERROR: duplicate minimum"
+ " ClientHello length\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ minhello_len = parse_size(arg);
+ /*
+ * Minimum ClientHello length must fit on 16 bits.
+ */
+ if (minhello_len == (size_t)-1
+ || (((minhello_len >> 12) >> 4) != 0))
+ {
+ usage_client();
+ goto client_exit_error;
+ }
+ } else if (eqstr(arg, "-fallback")) {
+ fallback = 1;
+ } else if (eqstr(arg, "-noreneg")) {
+ flags |= BR_OPT_NO_RENEGOTIATION;
+ } else if (eqstr(arg, "-alpn")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-alpn'\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ VEC_ADD(alpn_names, xstrdup(argv[i]));
+ } else if (eqstr(arg, "-strictalpn")) {
+ flags |= BR_OPT_FAIL_ON_ALPN_MISMATCH;
+ } else {
+ fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
+ usage_client();
+ goto client_exit_error;
+ }
+ }
+ if (server_name == NULL) {
+ fprintf(stderr, "ERROR: no server name/address provided\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ for (u = strlen(server_name); u > 0; u --) {
+ int c = server_name[u - 1];
+ if (c == ':') {
+ break;
+ }
+ if (c < '0' || c > '9') {
+ u = 0;
+ break;
+ }
+ }
+ if (u == 0) {
+ host = xstrdup(server_name);
+ port = xstrdup("443");
+ } else {
+ port = xstrdup(server_name + u);
+ host = xmalloc(u);
+ memcpy(host, server_name, u - 1);
+ host[u - 1] = 0;
+ }
+ if (sni == NULL) {
+ sni = host;
+ }
+
+ if (chain == NULL && sk != NULL) {
+ fprintf(stderr, "ERROR: private key specified, but"
+ " no certificate chain\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ if (chain != NULL && sk == NULL) {
+ fprintf(stderr, "ERROR: certificate chain specified, but"
+ " no private key\n");
+ usage_client();
+ goto client_exit_error;
+ }
+
+ if (vmin == 0) {
+ vmin = BR_TLS10;
+ }
+ if (vmax == 0) {
+ vmax = BR_TLS12;
+ }
+ if (vmax < vmin) {
+ fprintf(stderr, "ERROR: impossible minimum/maximum protocol"
+ " version combination\n");
+ usage_client();
+ goto client_exit_error;
+ }
+ if (suites == NULL) {
+ num_suites = 0;
+
+ for (u = 0; cipher_suites[u].name; u ++) {
+ if ((cipher_suites[u].req & REQ_TLS12) == 0
+ || vmax >= BR_TLS12)
+ {
+ num_suites ++;
+ }
+ }
+ suites = xmalloc(num_suites * sizeof *suites);
+ num_suites = 0;
+ for (u = 0; cipher_suites[u].name; u ++) {
+ if ((cipher_suites[u].req & REQ_TLS12) == 0
+ || vmax >= BR_TLS12)
+ {
+ suites[num_suites ++] = cipher_suites[u];
+ }
+ }
+ }
+ if (hfuns == 0) {
+ hfuns = (unsigned)-1;
+ }
+ if (iobuf_len == 0) {
+ if (bidi) {
+ iobuf_len = BR_SSL_BUFSIZE_BIDI;
+ } else {
+ iobuf_len = BR_SSL_BUFSIZE_MONO;
+ }
+ }
+ iobuf = xmalloc(iobuf_len);
+
+ /*
+ * Compute implementation requirements and inject implementations.
+ */
+ suite_ids = xmalloc((num_suites + 1) * sizeof *suite_ids);
+ br_ssl_client_zero(&cc);
+ br_ssl_engine_set_versions(&cc.eng, vmin, vmax);
+ dnhash = NULL;
+ for (u = 0; hash_functions[u].name; u ++) {
+ const br_hash_class *hc;
+ int id;
+
+ hc = hash_functions[u].hclass;
+ id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
+ if ((hfuns & ((unsigned)1 << id)) != 0) {
+ dnhash = hc;
+ }
+ }
+ if (dnhash == NULL) {
+ fprintf(stderr, "ERROR: no supported hash function\n");
+ goto client_exit_error;
+ }
+ br_x509_minimal_init(&xc, dnhash,
+ &VEC_ELT(anchors, 0), VEC_LEN(anchors));
+ if (vmin <= BR_TLS11) {
+ if (!(hfuns & (1 << br_md5_ID))) {
+ fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need MD5\n");
+ goto client_exit_error;
+ }
+ if (!(hfuns & (1 << br_sha1_ID))) {
+ fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need SHA-1\n");
+ goto client_exit_error;
+ }
+ }
+ for (u = 0; u < num_suites; u ++) {
+ unsigned req;
+
+ req = suites[u].req;
+ suite_ids[u] = suites[u].suite;
+ if ((req & REQ_TLS12) != 0 && vmax < BR_TLS12) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires TLS 1.2\n",
+ suites[u].name);
+ goto client_exit_error;
+ }
+ if ((req & REQ_SHA1) != 0 && !(hfuns & (1 << br_sha1_ID))) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires SHA-1\n",
+ suites[u].name);
+ goto client_exit_error;
+ }
+ if ((req & REQ_SHA256) != 0 && !(hfuns & (1 << br_sha256_ID))) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires SHA-256\n",
+ suites[u].name);
+ goto client_exit_error;
+ }
+ if ((req & REQ_SHA384) != 0 && !(hfuns & (1 << br_sha384_ID))) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires SHA-384\n",
+ suites[u].name);
+ goto client_exit_error;
+ }
+ /* TODO: algorithm implementation selection */
+ if ((req & REQ_AESCBC) != 0) {
+ br_ssl_engine_set_default_aes_cbc(&cc.eng);
+ }
+ if ((req & REQ_AESCCM) != 0) {
+ br_ssl_engine_set_default_aes_ccm(&cc.eng);
+ }
+ if ((req & REQ_AESGCM) != 0) {
+ br_ssl_engine_set_default_aes_gcm(&cc.eng);
+ }
+ if ((req & REQ_CHAPOL) != 0) {
+ br_ssl_engine_set_default_chapol(&cc.eng);
+ }
+ if ((req & REQ_3DESCBC) != 0) {
+ br_ssl_engine_set_default_des_cbc(&cc.eng);
+ }
+ if ((req & REQ_RSAKEYX) != 0) {
+ br_ssl_client_set_default_rsapub(&cc);
+ }
+ if ((req & REQ_ECDHE_RSA) != 0) {
+ br_ssl_engine_set_default_ec(&cc.eng);
+ br_ssl_engine_set_default_rsavrfy(&cc.eng);
+ }
+ if ((req & REQ_ECDHE_ECDSA) != 0) {
+ br_ssl_engine_set_default_ecdsa(&cc.eng);
+ }
+ if ((req & REQ_ECDH) != 0) {
+ br_ssl_engine_set_default_ec(&cc.eng);
+ }
+ }
+ if (fallback) {
+ suite_ids[num_suites ++] = 0x5600;
+ }
+ br_ssl_engine_set_suites(&cc.eng, suite_ids, num_suites);
+
+ for (u = 0; hash_functions[u].name; u ++) {
+ const br_hash_class *hc;
+ int id;
+
+ hc = hash_functions[u].hclass;
+ id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
+ if ((hfuns & ((unsigned)1 << id)) != 0) {
+ br_ssl_engine_set_hash(&cc.eng, id, hc);
+ br_x509_minimal_set_hash(&xc, id, hc);
+ }
+ }
+ if (vmin <= BR_TLS11) {
+ br_ssl_engine_set_prf10(&cc.eng, &br_tls10_prf);
+ }
+ if (vmax >= BR_TLS12) {
+ if ((hfuns & ((unsigned)1 << br_sha256_ID)) != 0) {
+ br_ssl_engine_set_prf_sha256(&cc.eng,
+ &br_tls12_sha256_prf);
+ }
+ if ((hfuns & ((unsigned)1 << br_sha384_ID)) != 0) {
+ br_ssl_engine_set_prf_sha384(&cc.eng,
+ &br_tls12_sha384_prf);
+ }
+ }
+ br_x509_minimal_set_rsa(&xc, br_rsa_pkcs1_vrfy_get_default());
+ br_x509_minimal_set_ecdsa(&xc,
+ br_ec_get_default(), br_ecdsa_vrfy_asn1_get_default());
+
+ /*
+ * If there is no provided trust anchor, then certificate validation
+ * will always fail. In that situation, we use our custom wrapper
+ * that tolerates unknown anchors.
+ */
+ if (VEC_LEN(anchors) == 0) {
+ if (verbose) {
+ fprintf(stderr,
+ "WARNING: no configured trust anchor\n");
+ }
+ x509_noanchor_init(&xwc, &xc.vtable);
+ br_ssl_engine_set_x509(&cc.eng, &xwc.vtable);
+ } else {
+ br_ssl_engine_set_x509(&cc.eng, &xc.vtable);
+ }
+
+ if (minhello_len != (size_t)-1) {
+ br_ssl_client_set_min_clienthello_len(&cc, minhello_len);
+ }
+ br_ssl_engine_set_all_flags(&cc.eng, flags);
+ if (VEC_LEN(alpn_names) != 0) {
+ br_ssl_engine_set_protocol_names(&cc.eng,
+ (const char **)&VEC_ELT(alpn_names, 0),
+ VEC_LEN(alpn_names));
+ }
+
+ if (chain != NULL) {
+ zc.vtable = &ccert_vtable;
+ zc.verbose = verbose;
+ zc.chain = chain;
+ zc.chain_len = chain_len;
+ zc.sk = sk;
+ if (nostaticecdh || sk->key_type != BR_KEYTYPE_EC) {
+ zc.issuer_key_type = 0;
+ } else {
+ zc.issuer_key_type = get_cert_signer_algo(&chain[0]);
+ if (zc.issuer_key_type == 0) {
+ goto client_exit_error;
+ }
+ }
+ br_ssl_client_set_client_certificate(&cc, &zc.vtable);
+ }
+
+ br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi);
+ br_ssl_client_reset(&cc, sni, 0);
+
+ /*
+ * On Unix systems, we need to avoid SIGPIPE.
+ */
+#ifndef _WIN32
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+ /*
+ * Connect to the peer.
+ */
+ fd = host_connect(host, port, verbose);
+ if (fd == INVALID_SOCKET) {
+ goto client_exit_error;
+ }
+
+ /*
+ * Run the engine until completion.
+ */
+ if (run_ssl_engine(&cc.eng, fd,
+ (verbose ? RUN_ENGINE_VERBOSE : 0)
+ | (trace ? RUN_ENGINE_TRACE : 0)) != 0)
+ {
+ goto client_exit_error;
+ } else {
+ goto client_exit;
+ }
+
+ /*
+ * Release allocated structures.
+ */
+client_exit:
+ xfree(host);
+ xfree(port);
+ xfree(suites);
+ xfree(suite_ids);
+ VEC_CLEAREXT(anchors, &free_ta_contents);
+ VEC_CLEAREXT(alpn_names, &free_alpn);
+ free_certificates(chain, chain_len);
+ free_private_key(sk);
+ xfree(iobuf);
+ if (fd != INVALID_SOCKET) {
+#ifdef _WIN32
+ closesocket(fd);
+#else
+ close(fd);
+#endif
+ }
+ return retcode;
+
+client_exit_error:
+ retcode = -1;
+ goto client_exit;
+}
diff --git a/contrib/bearssl/tools/errors.c b/contrib/bearssl/tools/errors.c
new file mode 100644
index 000000000000..22f0c3058d4d
--- /dev/null
+++ b/contrib/bearssl/tools/errors.c
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+#include "bearssl.h"
+
+static struct {
+ int err;
+ const char *name;
+ const char *comment;
+} errors[] = {
+ {
+ BR_ERR_BAD_PARAM,
+ "BR_ERR_BAD_PARAM",
+ "Caller-provided parameter is incorrect."
+ }, {
+ BR_ERR_BAD_STATE,
+ "BR_ERR_BAD_STATE",
+ "Operation requested by the caller cannot be applied with"
+ " the current context state (e.g. reading data while"
+ " outgoing data is waiting to be sent)."
+ }, {
+ BR_ERR_UNSUPPORTED_VERSION,
+ "BR_ERR_UNSUPPORTED_VERSION",
+ "Incoming protocol or record version is unsupported."
+ }, {
+ BR_ERR_BAD_VERSION,
+ "BR_ERR_BAD_VERSION",
+ "Incoming record version does not match the expected version."
+ }, {
+ BR_ERR_BAD_LENGTH,
+ "BR_ERR_BAD_LENGTH",
+ "Incoming record length is invalid."
+ }, {
+ BR_ERR_TOO_LARGE,
+ "BR_ERR_TOO_LARGE",
+ "Incoming record is too large to be processed, or buffer"
+ " is too small for the handshake message to send."
+ }, {
+ BR_ERR_BAD_MAC,
+ "BR_ERR_BAD_MAC",
+ "Decryption found an invalid padding, or the record MAC is"
+ " not correct."
+ }, {
+ BR_ERR_NO_RANDOM,
+ "BR_ERR_NO_RANDOM",
+ "No initial entropy was provided, and none can be obtained"
+ " from the OS."
+ }, {
+ BR_ERR_UNKNOWN_TYPE,
+ "BR_ERR_UNKNOWN_TYPE",
+ "Incoming record type is unknown."
+ }, {
+ BR_ERR_UNEXPECTED,
+ "BR_ERR_UNEXPECTED",
+ "Incoming record or message has wrong type with regards to"
+ " the current engine state."
+ }, {
+ BR_ERR_BAD_CCS,
+ "BR_ERR_BAD_CCS",
+ "ChangeCipherSpec message from the peer has invalid contents."
+ }, {
+ BR_ERR_BAD_ALERT,
+ "BR_ERR_BAD_ALERT",
+ "Alert message from the peer has invalid contents"
+ " (odd length)."
+ }, {
+ BR_ERR_BAD_HANDSHAKE,
+ "BR_ERR_BAD_HANDSHAKE",
+ "Incoming handshake message decoding failed."
+ }, {
+ BR_ERR_OVERSIZED_ID,
+ "BR_ERR_OVERSIZED_ID",
+ "ServerHello contains a session ID which is larger than"
+ " 32 bytes."
+ }, {
+ BR_ERR_BAD_CIPHER_SUITE,
+ "BR_ERR_BAD_CIPHER_SUITE",
+ "Server wants to use a cipher suite that we did not claim"
+ " to support. This is also reported if we tried to advertise"
+ " a cipher suite that we do not support."
+ }, {
+ BR_ERR_BAD_COMPRESSION,
+ "BR_ERR_BAD_COMPRESSION",
+ "Server wants to use a compression that we did not claim"
+ " to support."
+ }, {
+ BR_ERR_BAD_FRAGLEN,
+ "BR_ERR_BAD_FRAGLEN",
+ "Server's max fragment length does not match client's."
+ }, {
+ BR_ERR_BAD_SECRENEG,
+ "BR_ERR_BAD_SECRENEG",
+ "Secure renegotiation failed."
+ }, {
+ BR_ERR_EXTRA_EXTENSION,
+ "BR_ERR_EXTRA_EXTENSION",
+ "Server sent an extension type that we did not announce,"
+ " or used the same extension type several times in a"
+ " single ServerHello."
+ }, {
+ BR_ERR_BAD_SNI,
+ "BR_ERR_BAD_SNI",
+ "Invalid Server Name Indication contents (when used by"
+ " the server, this extension shall be empty)."
+ }, {
+ BR_ERR_BAD_HELLO_DONE,
+ "BR_ERR_BAD_HELLO_DONE",
+ "Invalid ServerHelloDone from the server (length is not 0)."
+ }, {
+ BR_ERR_LIMIT_EXCEEDED,
+ "BR_ERR_LIMIT_EXCEEDED",
+ "Internal limit exceeded (e.g. server's public key is too"
+ " large)."
+ }, {
+ BR_ERR_BAD_FINISHED,
+ "BR_ERR_BAD_FINISHED",
+ "Finished message from peer does not match the expected"
+ " value."
+ }, {
+ BR_ERR_RESUME_MISMATCH,
+ "BR_ERR_RESUME_MISMATCH",
+ "Session resumption attempt with distinct version or cipher"
+ " suite."
+ }, {
+ BR_ERR_INVALID_ALGORITHM,
+ "BR_ERR_INVALID_ALGORITHM",
+ "Unsupported or invalid algorithm (ECDHE curve, signature"
+ " algorithm, hash function)."
+ }, {
+ BR_ERR_BAD_SIGNATURE,
+ "BR_ERR_BAD_SIGNATURE",
+ "Invalid signature in ServerKeyExchange or"
+ " CertificateVerify message."
+ }, {
+ BR_ERR_WRONG_KEY_USAGE,
+ "BR_ERR_WRONG_KEY_USAGE",
+ "Peer's public key does not have the proper type or is"
+ " not allowed for the requested operation."
+ }, {
+ BR_ERR_NO_CLIENT_AUTH,
+ "BR_ERR_NO_CLIENT_AUTH",
+ "Client did not send a certificate upon request, or the"
+ " client certificate could not be validated."
+ }, {
+ BR_ERR_IO,
+ "BR_ERR_IO",
+ "I/O error or premature close on transport stream."
+ }, {
+ BR_ERR_X509_INVALID_VALUE,
+ "BR_ERR_X509_INVALID_VALUE",
+ "Invalid value in an ASN.1 structure."
+ },
+ {
+ BR_ERR_X509_TRUNCATED,
+ "BR_ERR_X509_TRUNCATED",
+ "Truncated certificate or other ASN.1 object."
+ },
+ {
+ BR_ERR_X509_EMPTY_CHAIN,
+ "BR_ERR_X509_EMPTY_CHAIN",
+ "Empty certificate chain (no certificate at all)."
+ },
+ {
+ BR_ERR_X509_INNER_TRUNC,
+ "BR_ERR_X509_INNER_TRUNC",
+ "Decoding error: inner element extends beyond outer element"
+ " size."
+ },
+ {
+ BR_ERR_X509_BAD_TAG_CLASS,
+ "BR_ERR_X509_BAD_TAG_CLASS",
+ "Decoding error: unsupported tag class (application or"
+ " private)."
+ },
+ {
+ BR_ERR_X509_BAD_TAG_VALUE,
+ "BR_ERR_X509_BAD_TAG_VALUE",
+ "Decoding error: unsupported tag value."
+ },
+ {
+ BR_ERR_X509_INDEFINITE_LENGTH,
+ "BR_ERR_X509_INDEFINITE_LENGTH",
+ "Decoding error: indefinite length."
+ },
+ {
+ BR_ERR_X509_EXTRA_ELEMENT,
+ "BR_ERR_X509_EXTRA_ELEMENT",
+ "Decoding error: extraneous element."
+ },
+ {
+ BR_ERR_X509_UNEXPECTED,
+ "BR_ERR_X509_UNEXPECTED",
+ "Decoding error: unexpected element."
+ },
+ {
+ BR_ERR_X509_NOT_CONSTRUCTED,
+ "BR_ERR_X509_NOT_CONSTRUCTED",
+ "Decoding error: expected constructed element, but is"
+ " primitive."
+ },
+ {
+ BR_ERR_X509_NOT_PRIMITIVE,
+ "BR_ERR_X509_NOT_PRIMITIVE",
+ "Decoding error: expected primitive element, but is"
+ " constructed."
+ },
+ {
+ BR_ERR_X509_PARTIAL_BYTE,
+ "BR_ERR_X509_PARTIAL_BYTE",
+ "Decoding error: BIT STRING length is not multiple of 8."
+ },
+ {
+ BR_ERR_X509_BAD_BOOLEAN,
+ "BR_ERR_X509_BAD_BOOLEAN",
+ "Decoding error: BOOLEAN value has invalid length."
+ },
+ {
+ BR_ERR_X509_OVERFLOW,
+ "BR_ERR_X509_OVERFLOW",
+ "Decoding error: value is off-limits."
+ },
+ {
+ BR_ERR_X509_BAD_DN,
+ "BR_ERR_X509_BAD_DN",
+ "Invalid distinguished name."
+ },
+ {
+ BR_ERR_X509_BAD_TIME,
+ "BR_ERR_X509_BAD_TIME",
+ "Invalid date/time representation."
+ },
+ {
+ BR_ERR_X509_UNSUPPORTED,
+ "BR_ERR_X509_UNSUPPORTED",
+ "Certificate contains unsupported features that cannot be"
+ " ignored."
+ },
+ {
+ BR_ERR_X509_LIMIT_EXCEEDED,
+ "BR_ERR_X509_LIMIT_EXCEEDED",
+ "Key or signature size exceeds internal limits."
+ },
+ {
+ BR_ERR_X509_WRONG_KEY_TYPE,
+ "BR_ERR_X509_WRONG_KEY_TYPE",
+ "Key type does not match that which was expected."
+ },
+ {
+ BR_ERR_X509_BAD_SIGNATURE,
+ "BR_ERR_X509_BAD_SIGNATURE",
+ "Signature is invalid."
+ },
+ {
+ BR_ERR_X509_TIME_UNKNOWN,
+ "BR_ERR_X509_TIME_UNKNOWN",
+ "Validation time is unknown."
+ },
+ {
+ BR_ERR_X509_EXPIRED,
+ "BR_ERR_X509_EXPIRED",
+ "Certificate is expired or not yet valid."
+ },
+ {
+ BR_ERR_X509_DN_MISMATCH,
+ "BR_ERR_X509_DN_MISMATCH",
+ "Issuer/Subject DN mismatch in the chain."
+ },
+ {
+ BR_ERR_X509_BAD_SERVER_NAME,
+ "BR_ERR_X509_BAD_SERVER_NAME",
+ "Expected server name was not found in the chain."
+ },
+ {
+ BR_ERR_X509_CRITICAL_EXTENSION,
+ "BR_ERR_X509_CRITICAL_EXTENSION",
+ "Unknown critical extension in certificate."
+ },
+ {
+ BR_ERR_X509_NOT_CA,
+ "BR_ERR_X509_NOT_CA",
+ "Not a CA, or path length constraint violation."
+ },
+ {
+ BR_ERR_X509_FORBIDDEN_KEY_USAGE,
+ "BR_ERR_X509_FORBIDDEN_KEY_USAGE",
+ "Key Usage extension prohibits intended usage."
+ },
+ {
+ BR_ERR_X509_WEAK_PUBLIC_KEY,
+ "BR_ERR_X509_WEAK_PUBLIC_KEY",
+ "Public key found in certificate is too small."
+ },
+ {
+ BR_ERR_X509_NOT_TRUSTED,
+ "BR_ERR_X509_NOT_TRUSTED",
+ "Chain could not be linked to a trust anchor."
+ },
+ { 0, 0, 0 }
+};
+
+/* see brssl.h */
+const char *
+find_error_name(int err, const char **comment)
+{
+ size_t u;
+
+ for (u = 0; errors[u].name; u ++) {
+ if (errors[u].err == err) {
+ if (comment != NULL) {
+ *comment = errors[u].comment;
+ }
+ return errors[u].name;
+ }
+ }
+ return NULL;
+}
diff --git a/contrib/bearssl/tools/files.c b/contrib/bearssl/tools/files.c
new file mode 100644
index 000000000000..8bf67cc3b4f3
--- /dev/null
+++ b/contrib/bearssl/tools/files.c
@@ -0,0 +1,329 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+
+/* see brssl.h */
+unsigned char *
+read_file(const char *fname, size_t *len)
+{
+ bvector vbuf = VEC_INIT;
+ FILE *f;
+
+ *len = 0;
+ f = fopen(fname, "rb");
+ if (f == NULL) {
+ fprintf(stderr,
+ "ERROR: could not open file '%s' for reading\n", fname);
+ return NULL;
+ }
+ for (;;) {
+ unsigned char tmp[1024];
+ size_t rlen;
+
+ rlen = fread(tmp, 1, sizeof tmp, f);
+ if (rlen == 0) {
+ unsigned char *buf;
+
+ if (ferror(f)) {
+ fprintf(stderr,
+ "ERROR: read error on file '%s'\n",
+ fname);
+ fclose(f);
+ return NULL;
+ }
+ buf = VEC_TOARRAY(vbuf);
+ *len = VEC_LEN(vbuf);
+ VEC_CLEAR(vbuf);
+ fclose(f);
+ return buf;
+ }
+ VEC_ADDMANY(vbuf, tmp, rlen);
+ }
+}
+
+/* see brssl.h */
+int
+write_file(const char *fname, const void *data, size_t len)
+{
+ FILE *f;
+ const unsigned char *buf;
+
+ f = fopen(fname, "wb");
+ if (f == NULL) {
+ fprintf(stderr,
+ "ERROR: could not open file '%s' for reading\n", fname);
+ return -1;
+ }
+ buf = data;
+ while (len > 0) {
+ size_t wlen;
+
+ wlen = fwrite(buf, 1, len, f);
+ if (wlen == 0) {
+ fprintf(stderr,
+ "ERROR: could not write all bytes to '%s'\n",
+ fname);
+ fclose(f);
+ return -1;
+ }
+ buf += wlen;
+ len -= wlen;
+ }
+ if (ferror(f)) {
+ fprintf(stderr, "ERROR: write error on file '%s'\n", fname);
+ fclose(f);
+ return -1;
+ }
+ fclose(f);
+ return 0;
+}
+
+/* see brssl.h */
+int
+looks_like_DER(const unsigned char *buf, size_t len)
+{
+ int fb;
+ size_t dlen;
+
+ if (len < 2) {
+ return 0;
+ }
+ if (*buf ++ != 0x30) {
+ return 0;
+ }
+ fb = *buf ++;
+ len -= 2;
+ if (fb < 0x80) {
+ return (size_t)fb == len;
+ } else if (fb == 0x80) {
+ return 0;
+ } else {
+ fb -= 0x80;
+ if (len < (size_t)fb + 2) {
+ return 0;
+ }
+ len -= (size_t)fb;
+ dlen = 0;
+ while (fb -- > 0) {
+ if (dlen > (len >> 8)) {
+ return 0;
+ }
+ dlen = (dlen << 8) + (size_t)*buf ++;
+ }
+ return dlen == len;
+ }
+}
+
+static void
+vblob_append(void *cc, const void *data, size_t len)
+{
+ bvector *bv;
+
+ bv = cc;
+ VEC_ADDMANY(*bv, data, len);
+}
+
+/* see brssl.h */
+void
+free_pem_object_contents(pem_object *po)
+{
+ if (po != NULL) {
+ xfree(po->name);
+ xfree(po->data);
+ }
+}
+
+/* see brssl.h */
+pem_object *
+decode_pem(const void *src, size_t len, size_t *num)
+{
+ VECTOR(pem_object) pem_list = VEC_INIT;
+ br_pem_decoder_context pc;
+ pem_object po, *pos;
+ const unsigned char *buf;
+ bvector bv = VEC_INIT;
+ int inobj;
+ int extra_nl;
+
+ *num = 0;
+ br_pem_decoder_init(&pc);
+ buf = src;
+ inobj = 0;
+ po.name = NULL;
+ po.data = NULL;
+ po.data_len = 0;
+ extra_nl = 1;
+ while (len > 0) {
+ size_t tlen;
+
+ tlen = br_pem_decoder_push(&pc, buf, len);
+ buf += tlen;
+ len -= tlen;
+ switch (br_pem_decoder_event(&pc)) {
+
+ case BR_PEM_BEGIN_OBJ:
+ po.name = xstrdup(br_pem_decoder_name(&pc));
+ br_pem_decoder_setdest(&pc, vblob_append, &bv);
+ inobj = 1;
+ break;
+
+ case BR_PEM_END_OBJ:
+ if (inobj) {
+ po.data = VEC_TOARRAY(bv);
+ po.data_len = VEC_LEN(bv);
+ VEC_ADD(pem_list, po);
+ VEC_CLEAR(bv);
+ po.name = NULL;
+ po.data = NULL;
+ po.data_len = 0;
+ inobj = 0;
+ }
+ break;
+
+ case BR_PEM_ERROR:
+ xfree(po.name);
+ VEC_CLEAR(bv);
+ fprintf(stderr,
+ "ERROR: invalid PEM encoding\n");
+ VEC_CLEAREXT(pem_list, &free_pem_object_contents);
+ return NULL;
+ }
+
+ /*
+ * We add an extra newline at the end, in order to
+ * support PEM files that lack the newline on their last
+ * line (this is somwehat invalid, but PEM format is not
+ * standardised and such files do exist in the wild, so
+ * we'd better accept them).
+ */
+ if (len == 0 && extra_nl) {
+ extra_nl = 0;
+ buf = (const unsigned char *)"\n";
+ len = 1;
+ }
+ }
+ if (inobj) {
+ fprintf(stderr, "ERROR: unfinished PEM object\n");
+ xfree(po.name);
+ VEC_CLEAR(bv);
+ VEC_CLEAREXT(pem_list, &free_pem_object_contents);
+ return NULL;
+ }
+
+ *num = VEC_LEN(pem_list);
+ VEC_ADD(pem_list, po);
+ pos = VEC_TOARRAY(pem_list);
+ VEC_CLEAR(pem_list);
+ return pos;
+}
+
+/* see brssl.h */
+br_x509_certificate *
+read_certificates(const char *fname, size_t *num)
+{
+ VECTOR(br_x509_certificate) cert_list = VEC_INIT;
+ unsigned char *buf;
+ size_t len;
+ pem_object *pos;
+ size_t u, num_pos;
+ br_x509_certificate *xcs;
+ br_x509_certificate dummy;
+
+ *num = 0;
+
+ /*
+ * TODO: reading the whole file is crude; we could parse them
+ * in a streamed fashion. But it does not matter much in practice.
+ */
+ buf = read_file(fname, &len);
+ if (buf == NULL) {
+ return NULL;
+ }
+
+ /*
+ * Check for a DER-encoded certificate.
+ */
+ if (looks_like_DER(buf, len)) {
+ xcs = xmalloc(2 * sizeof *xcs);
+ xcs[0].data = buf;
+ xcs[0].data_len = len;
+ xcs[1].data = NULL;
+ xcs[1].data_len = 0;
+ *num = 1;
+ return xcs;
+ }
+
+ pos = decode_pem(buf, len, &num_pos);
+ xfree(buf);
+ if (pos == NULL) {
+ return NULL;
+ }
+ for (u = 0; u < num_pos; u ++) {
+ if (eqstr(pos[u].name, "CERTIFICATE")
+ || eqstr(pos[u].name, "X509 CERTIFICATE"))
+ {
+ br_x509_certificate xc;
+
+ xc.data = pos[u].data;
+ xc.data_len = pos[u].data_len;
+ pos[u].data = NULL;
+ VEC_ADD(cert_list, xc);
+ }
+ }
+ for (u = 0; u < num_pos; u ++) {
+ free_pem_object_contents(&pos[u]);
+ }
+ xfree(pos);
+
+ if (VEC_LEN(cert_list) == 0) {
+ fprintf(stderr, "ERROR: no certificate in file '%s'\n", fname);
+ return NULL;
+ }
+ *num = VEC_LEN(cert_list);
+ dummy.data = NULL;
+ dummy.data_len = 0;
+ VEC_ADD(cert_list, dummy);
+ xcs = VEC_TOARRAY(cert_list);
+ VEC_CLEAR(cert_list);
+ return xcs;
+}
+
+/* see brssl.h */
+void
+free_certificates(br_x509_certificate *certs, size_t num)
+{
+ size_t u;
+
+ for (u = 0; u < num; u ++) {
+ xfree(certs[u].data);
+ }
+ xfree(certs);
+}
diff --git a/contrib/bearssl/tools/impl.c b/contrib/bearssl/tools/impl.c
new file mode 100644
index 000000000000..e00cc327dce4
--- /dev/null
+++ b/contrib/bearssl/tools/impl.c
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+#include "bearssl.h"
+
+/* see brssl.h */
+int
+do_impl(int argc, char *argv[])
+{
+ const br_config_option *opt;
+
+ (void)argc;
+ (void)argv;
+
+ for (opt = br_get_config(); opt->name != NULL; opt ++) {
+ printf("%-25s %8ld\n", opt->name, opt->value);
+ }
+
+ return 0;
+}
diff --git a/contrib/bearssl/tools/keys.c b/contrib/bearssl/tools/keys.c
new file mode 100644
index 000000000000..6e54676380a6
--- /dev/null
+++ b/contrib/bearssl/tools/keys.c
@@ -0,0 +1,234 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+#include "bearssl.h"
+
+static private_key *
+decode_key(const unsigned char *buf, size_t len)
+{
+ br_skey_decoder_context dc;
+ int err;
+ private_key *sk;
+
+ br_skey_decoder_init(&dc);
+ br_skey_decoder_push(&dc, buf, len);
+ err = br_skey_decoder_last_error(&dc);
+ if (err != 0) {
+ const char *errname, *errmsg;
+
+ fprintf(stderr, "ERROR (decoding): err=%d\n", err);
+ errname = find_error_name(err, &errmsg);
+ if (errname != NULL) {
+ fprintf(stderr, " %s: %s\n", errname, errmsg);
+ } else {
+ fprintf(stderr, " (unknown)\n");
+ }
+ return NULL;
+ }
+ switch (br_skey_decoder_key_type(&dc)) {
+ const br_rsa_private_key *rk;
+ const br_ec_private_key *ek;
+
+ case BR_KEYTYPE_RSA:
+ rk = br_skey_decoder_get_rsa(&dc);
+ sk = xmalloc(sizeof *sk);
+ sk->key_type = BR_KEYTYPE_RSA;
+ sk->key.rsa.n_bitlen = rk->n_bitlen;
+ sk->key.rsa.p = xblobdup(rk->p, rk->plen);
+ sk->key.rsa.plen = rk->plen;
+ sk->key.rsa.q = xblobdup(rk->q, rk->qlen);
+ sk->key.rsa.qlen = rk->qlen;
+ sk->key.rsa.dp = xblobdup(rk->dp, rk->dplen);
+ sk->key.rsa.dplen = rk->dplen;
+ sk->key.rsa.dq = xblobdup(rk->dq, rk->dqlen);
+ sk->key.rsa.dqlen = rk->dqlen;
+ sk->key.rsa.iq = xblobdup(rk->iq, rk->iqlen);
+ sk->key.rsa.iqlen = rk->iqlen;
+ break;
+
+ case BR_KEYTYPE_EC:
+ ek = br_skey_decoder_get_ec(&dc);
+ sk = xmalloc(sizeof *sk);
+ sk->key_type = BR_KEYTYPE_EC;
+ sk->key.ec.curve = ek->curve;
+ sk->key.ec.x = xblobdup(ek->x, ek->xlen);
+ sk->key.ec.xlen = ek->xlen;
+ break;
+
+ default:
+ fprintf(stderr, "Unknown key type: %d\n",
+ br_skey_decoder_key_type(&dc));
+ sk = NULL;
+ break;
+ }
+
+ return sk;
+}
+
+/* see brssl.h */
+private_key *
+read_private_key(const char *fname)
+{
+ unsigned char *buf;
+ size_t len;
+ private_key *sk;
+ pem_object *pos;
+ size_t num, u;
+
+ buf = NULL;
+ pos = NULL;
+ sk = NULL;
+ buf = read_file(fname, &len);
+ if (buf == NULL) {
+ goto deckey_exit;
+ }
+ if (looks_like_DER(buf, len)) {
+ sk = decode_key(buf, len);
+ goto deckey_exit;
+ } else {
+ pos = decode_pem(buf, len, &num);
+ if (pos == NULL) {
+ goto deckey_exit;
+ }
+ for (u = 0; pos[u].name; u ++) {
+ const char *name;
+
+ name = pos[u].name;
+ if (eqstr(name, "RSA PRIVATE KEY")
+ || eqstr(name, "EC PRIVATE KEY")
+ || eqstr(name, "PRIVATE KEY"))
+ {
+ sk = decode_key(pos[u].data, pos[u].data_len);
+ goto deckey_exit;
+ }
+ }
+ fprintf(stderr, "ERROR: no private key in file '%s'\n", fname);
+ goto deckey_exit;
+ }
+
+deckey_exit:
+ if (buf != NULL) {
+ xfree(buf);
+ }
+ if (pos != NULL) {
+ for (u = 0; pos[u].name; u ++) {
+ free_pem_object_contents(&pos[u]);
+ }
+ xfree(pos);
+ }
+ return sk;
+}
+
+/* see brssl.h */
+void
+free_private_key(private_key *sk)
+{
+ if (sk == NULL) {
+ return;
+ }
+ switch (sk->key_type) {
+ case BR_KEYTYPE_RSA:
+ xfree(sk->key.rsa.p);
+ xfree(sk->key.rsa.q);
+ xfree(sk->key.rsa.dp);
+ xfree(sk->key.rsa.dq);
+ xfree(sk->key.rsa.iq);
+ break;
+ case BR_KEYTYPE_EC:
+ xfree(sk->key.ec.x);
+ break;
+ }
+ xfree(sk);
+}
+
+/*
+ * OID for hash functions in RSA signatures.
+ */
+static const unsigned char HASH_OID_SHA1[] = {
+ 0x05, 0x2B, 0x0E, 0x03, 0x02, 0x1A
+};
+
+static const unsigned char HASH_OID_SHA224[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04
+};
+
+static const unsigned char HASH_OID_SHA256[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01
+};
+
+static const unsigned char HASH_OID_SHA384[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02
+};
+
+static const unsigned char HASH_OID_SHA512[] = {
+ 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03
+};
+
+static const unsigned char *HASH_OID[] = {
+ HASH_OID_SHA1,
+ HASH_OID_SHA224,
+ HASH_OID_SHA256,
+ HASH_OID_SHA384,
+ HASH_OID_SHA512
+};
+
+/* see brssl.h */
+const unsigned char *
+get_hash_oid(int id)
+{
+ if (id >= 2 && id <= 6) {
+ return HASH_OID[id - 2];
+ } else {
+ return NULL;
+ }
+}
+
+/* see brssl.h */
+const br_hash_class *
+get_hash_impl(int hash_id)
+{
+ size_t u;
+
+ if (hash_id == 0) {
+ return &br_md5sha1_vtable;
+ }
+ for (u = 0; hash_functions[u].name; u ++) {
+ const br_hash_class *hc;
+ int id;
+
+ hc = hash_functions[u].hclass;
+ id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
+ if (id == hash_id) {
+ return hc;
+ }
+ }
+ return NULL;
+}
diff --git a/contrib/bearssl/tools/names.c b/contrib/bearssl/tools/names.c
new file mode 100644
index 000000000000..3751d93fa416
--- /dev/null
+++ b/contrib/bearssl/tools/names.c
@@ -0,0 +1,1056 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "brssl.h"
+#include "bearssl.h"
+
+/* see brssl.h */
+const protocol_version protocol_versions[] = {
+ { "tls10", BR_TLS10, "TLS 1.0" },
+ { "tls11", BR_TLS11, "TLS 1.1" },
+ { "tls12", BR_TLS12, "TLS 1.2" },
+ { NULL, 0, NULL }
+};
+
+/* see brssl.h */
+const hash_function hash_functions[] = {
+ { "md5", &br_md5_vtable, "MD5" },
+ { "sha1", &br_sha1_vtable, "SHA-1" },
+ { "sha224", &br_sha224_vtable, "SHA-224" },
+ { "sha256", &br_sha256_vtable, "SHA-256" },
+ { "sha384", &br_sha384_vtable, "SHA-384" },
+ { "sha512", &br_sha512_vtable, "SHA-512" },
+ { NULL, 0, NULL }
+};
+
+/* see brssl.h */
+const cipher_suite cipher_suites[] = {
+ {
+ "ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256",
+ BR_TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256,
+ REQ_ECDHE_ECDSA | REQ_CHAPOL | REQ_SHA256 | REQ_TLS12,
+ "ECDHE with ECDSA, ChaCha20+Poly1305 encryption (TLS 1.2+)"
+ },
+ {
+ "ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256",
+ BR_TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256,
+ REQ_ECDHE_RSA | REQ_CHAPOL | REQ_SHA256 | REQ_TLS12,
+ "ECDHE with RSA, ChaCha20+Poly1305 encryption (TLS 1.2+)"
+ },
+ {
+ "ECDHE_ECDSA_WITH_AES_128_GCM_SHA256",
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ REQ_ECDHE_ECDSA | REQ_AESGCM | REQ_SHA256 | REQ_TLS12,
+ "ECDHE with ECDSA, AES-128/GCM encryption (TLS 1.2+)"
+ },
+ {
+ "ECDHE_RSA_WITH_AES_128_GCM_SHA256",
+ BR_TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ REQ_ECDHE_RSA | REQ_AESGCM | REQ_SHA256 | REQ_TLS12,
+ "ECDHE with RSA, AES-128/GCM encryption (TLS 1.2+)"
+ },
+ {
+ "ECDHE_ECDSA_WITH_AES_256_GCM_SHA384",
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ REQ_ECDHE_ECDSA | REQ_AESGCM | REQ_SHA384 | REQ_TLS12,
+ "ECDHE with ECDSA, AES-256/GCM encryption (TLS 1.2+)"
+ },
+ {
+ "ECDHE_RSA_WITH_AES_256_GCM_SHA384",
+ BR_TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ REQ_ECDHE_RSA | REQ_AESGCM | REQ_SHA384 | REQ_TLS12,
+ "ECDHE with RSA, AES-256/GCM encryption (TLS 1.2+)"
+ },
+ {
+ "ECDHE_ECDSA_WITH_AES_128_CCM",
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM,
+ REQ_ECDHE_ECDSA | REQ_AESCCM | REQ_SHA256 | REQ_TLS12,
+ "ECDHE with ECDSA, AES-128/CCM encryption (TLS 1.2+)"
+ },
+ {
+ "ECDHE_ECDSA_WITH_AES_256_CCM",
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM,
+ REQ_ECDHE_ECDSA | REQ_AESCCM | REQ_SHA256 | REQ_TLS12,
+ "ECDHE with ECDSA, AES-256/CCM encryption (TLS 1.2+)"
+ },
+ {
+ "ECDHE_ECDSA_WITH_AES_128_CCM_8",
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CCM_8,
+ REQ_ECDHE_ECDSA | REQ_AESCCM | REQ_SHA256 | REQ_TLS12,
+ "ECDHE with ECDSA, AES-128/CCM_8 encryption (TLS 1.2+)"
+ },
+ {
+ "ECDHE_ECDSA_WITH_AES_256_CCM_8",
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CCM_8,
+ REQ_ECDHE_ECDSA | REQ_AESCCM | REQ_SHA256 | REQ_TLS12,
+ "ECDHE with ECDSA, AES-256/CCM_8 encryption (TLS 1.2+)"
+ },
+ {
+ "ECDHE_ECDSA_WITH_AES_128_CBC_SHA256",
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ REQ_ECDHE_ECDSA | REQ_AESCBC | REQ_SHA256 | REQ_TLS12,
+ "ECDHE with ECDSA, AES-128/CBC + SHA-256 (TLS 1.2+)"
+ },
+ {
+ "ECDHE_RSA_WITH_AES_128_CBC_SHA256",
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ REQ_ECDHE_RSA | REQ_AESCBC | REQ_SHA256 | REQ_TLS12,
+ "ECDHE with RSA, AES-128/CBC + SHA-256 (TLS 1.2+)"
+ },
+ {
+ "ECDHE_ECDSA_WITH_AES_256_CBC_SHA384",
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384,
+ REQ_ECDHE_ECDSA | REQ_AESCBC | REQ_SHA384 | REQ_TLS12,
+ "ECDHE with ECDSA, AES-256/CBC + SHA-384 (TLS 1.2+)"
+ },
+ {
+ "ECDHE_RSA_WITH_AES_256_CBC_SHA384",
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA384,
+ REQ_ECDHE_RSA | REQ_AESCBC | REQ_SHA384 | REQ_TLS12,
+ "ECDHE with RSA, AES-256/CBC + SHA-384 (TLS 1.2+)"
+ },
+ {
+ "ECDHE_ECDSA_WITH_AES_128_CBC_SHA",
+ BR_TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ REQ_ECDHE_ECDSA | REQ_AESCBC | REQ_SHA1,
+ "ECDHE with ECDSA, AES-128/CBC + SHA-1"
+ },
+ {
+ "ECDHE_RSA_WITH_AES_128_CBC_SHA",
+ BR_TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ REQ_ECDHE_RSA | REQ_AESCBC | REQ_SHA1,
+ "ECDHE with RSA, AES-128/CBC + SHA-1"
+ },
+ {
+ "ECDHE_ECDSA_WITH_AES_256_CBC_SHA",
+ BR_TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ REQ_ECDHE_ECDSA | REQ_AESCBC | REQ_SHA1,
+ "ECDHE with ECDSA, AES-256/CBC + SHA-1"
+ },
+ {
+ "ECDHE_RSA_WITH_AES_256_CBC_SHA",
+ BR_TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ REQ_ECDHE_RSA | REQ_AESCBC | REQ_SHA1,
+ "ECDHE with RSA, AES-256/CBC + SHA-1"
+ },
+ {
+ "ECDH_ECDSA_WITH_AES_128_GCM_SHA256",
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_GCM_SHA256,
+ REQ_ECDH | REQ_AESGCM | REQ_SHA256 | REQ_TLS12,
+ "ECDH key exchange (EC cert), AES-128/GCM (TLS 1.2+)"
+ },
+ {
+ "ECDH_RSA_WITH_AES_128_GCM_SHA256",
+ BR_TLS_ECDH_RSA_WITH_AES_128_GCM_SHA256,
+ REQ_ECDH | REQ_AESGCM | REQ_SHA256 | REQ_TLS12,
+ "ECDH key exchange (RSA cert), AES-128/GCM (TLS 1.2+)"
+ },
+ {
+ "ECDH_ECDSA_WITH_AES_256_GCM_SHA384",
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_GCM_SHA384,
+ REQ_ECDH | REQ_AESGCM | REQ_SHA384 | REQ_TLS12,
+ "ECDH key exchange (EC cert), AES-256/GCM (TLS 1.2+)"
+ },
+ {
+ "ECDH_RSA_WITH_AES_256_GCM_SHA384",
+ BR_TLS_ECDH_RSA_WITH_AES_256_GCM_SHA384,
+ REQ_ECDH | REQ_AESGCM | REQ_SHA384 | REQ_TLS12,
+ "ECDH key exchange (RSA cert), AES-256/GCM (TLS 1.2+)"
+ },
+ {
+ "ECDH_ECDSA_WITH_AES_128_CBC_SHA256",
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA256,
+ REQ_ECDH | REQ_AESCBC | REQ_SHA256 | REQ_TLS12,
+ "ECDH key exchange (EC cert), AES-128/CBC + HMAC/SHA-256 (TLS 1.2+)"
+ },
+ {
+ "ECDH_RSA_WITH_AES_128_CBC_SHA256",
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA256,
+ REQ_ECDH | REQ_AESCBC | REQ_SHA256 | REQ_TLS12,
+ "ECDH key exchange (RSA cert), AES-128/CBC + HMAC/SHA-256 (TLS 1.2+)"
+ },
+ {
+ "ECDH_ECDSA_WITH_AES_256_CBC_SHA384",
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA384,
+ REQ_ECDH | REQ_AESCBC | REQ_SHA384 | REQ_TLS12,
+ "ECDH key exchange (EC cert), AES-256/CBC + HMAC/SHA-384 (TLS 1.2+)"
+ },
+ {
+ "ECDH_RSA_WITH_AES_256_CBC_SHA384",
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA384,
+ REQ_ECDH | REQ_AESCBC | REQ_SHA384 | REQ_TLS12,
+ "ECDH key exchange (RSA cert), AES-256/CBC + HMAC/SHA-384 (TLS 1.2+)"
+ },
+ {
+ "ECDH_ECDSA_WITH_AES_128_CBC_SHA",
+ BR_TLS_ECDH_ECDSA_WITH_AES_128_CBC_SHA,
+ REQ_ECDH | REQ_AESCBC | REQ_SHA1,
+ "ECDH key exchange (EC cert), AES-128/CBC + HMAC/SHA-1"
+ },
+ {
+ "ECDH_RSA_WITH_AES_128_CBC_SHA",
+ BR_TLS_ECDH_RSA_WITH_AES_128_CBC_SHA,
+ REQ_ECDH | REQ_AESCBC | REQ_SHA1,
+ "ECDH key exchange (RSA cert), AES-128/CBC + HMAC/SHA-1"
+ },
+ {
+ "ECDH_ECDSA_WITH_AES_256_CBC_SHA",
+ BR_TLS_ECDH_ECDSA_WITH_AES_256_CBC_SHA,
+ REQ_ECDH | REQ_AESCBC | REQ_SHA1,
+ "ECDH key exchange (EC cert), AES-256/CBC + HMAC/SHA-1"
+ },
+ {
+ "ECDH_RSA_WITH_AES_256_CBC_SHA",
+ BR_TLS_ECDH_RSA_WITH_AES_256_CBC_SHA,
+ REQ_ECDH | REQ_AESCBC | REQ_SHA1,
+ "ECDH key exchange (RSA cert), AES-256/CBC + HMAC/SHA-1"
+ },
+ {
+ "RSA_WITH_AES_128_GCM_SHA256",
+ BR_TLS_RSA_WITH_AES_128_GCM_SHA256,
+ REQ_RSAKEYX | REQ_AESGCM | REQ_SHA256 | REQ_TLS12,
+ "RSA key exchange, AES-128/GCM encryption (TLS 1.2+)"
+ },
+ {
+ "RSA_WITH_AES_256_GCM_SHA384",
+ BR_TLS_RSA_WITH_AES_256_GCM_SHA384,
+ REQ_RSAKEYX | REQ_AESGCM | REQ_SHA384 | REQ_TLS12,
+ "RSA key exchange, AES-256/GCM encryption (TLS 1.2+)"
+ },
+ {
+ "RSA_WITH_AES_128_CCM",
+ BR_TLS_RSA_WITH_AES_128_CCM,
+ REQ_RSAKEYX | REQ_AESCCM | REQ_SHA256 | REQ_TLS12,
+ "RSA key exchange, AES-128/CCM encryption (TLS 1.2+)"
+ },
+ {
+ "RSA_WITH_AES_256_CCM",
+ BR_TLS_RSA_WITH_AES_256_CCM,
+ REQ_RSAKEYX | REQ_AESCCM | REQ_SHA256 | REQ_TLS12,
+ "RSA key exchange, AES-256/CCM encryption (TLS 1.2+)"
+ },
+ {
+ "RSA_WITH_AES_128_CCM_8",
+ BR_TLS_RSA_WITH_AES_128_CCM_8,
+ REQ_RSAKEYX | REQ_AESCCM | REQ_SHA256 | REQ_TLS12,
+ "RSA key exchange, AES-128/CCM_8 encryption (TLS 1.2+)"
+ },
+ {
+ "RSA_WITH_AES_256_CCM_8",
+ BR_TLS_RSA_WITH_AES_256_CCM_8,
+ REQ_RSAKEYX | REQ_AESCCM | REQ_SHA256 | REQ_TLS12,
+ "RSA key exchange, AES-256/CCM_8 encryption (TLS 1.2+)"
+ },
+ {
+ "RSA_WITH_AES_128_CBC_SHA256",
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA256,
+ REQ_RSAKEYX | REQ_AESCBC | REQ_SHA256 | REQ_TLS12,
+ "RSA key exchange, AES-128/CBC + HMAC/SHA-256 (TLS 1.2+)"
+ },
+ {
+ "RSA_WITH_AES_256_CBC_SHA256",
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA256,
+ REQ_RSAKEYX | REQ_AESCBC | REQ_SHA256 | REQ_TLS12,
+ "RSA key exchange, AES-256/CBC + HMAC/SHA-256 (TLS 1.2+)"
+ },
+ {
+ "RSA_WITH_AES_128_CBC_SHA",
+ BR_TLS_RSA_WITH_AES_128_CBC_SHA,
+ REQ_RSAKEYX | REQ_AESCBC | REQ_SHA1,
+ "RSA key exchange, AES-128/CBC + HMAC/SHA-1"
+ },
+ {
+ "RSA_WITH_AES_256_CBC_SHA",
+ BR_TLS_RSA_WITH_AES_256_CBC_SHA,
+ REQ_RSAKEYX | REQ_AESCBC | REQ_SHA1,
+ "RSA key exchange, AES-256/CBC + HMAC/SHA-1"
+ },
+ {
+ "ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA",
+ BR_TLS_ECDHE_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ REQ_ECDHE_ECDSA | REQ_3DESCBC | REQ_SHA1,
+ "ECDHE with ECDSA, 3DES/CBC + SHA-1"
+ },
+ {
+ "ECDHE_RSA_WITH_3DES_EDE_CBC_SHA",
+ BR_TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ REQ_ECDHE_RSA | REQ_3DESCBC | REQ_SHA1,
+ "ECDHE with RSA, 3DES/CBC + SHA-1"
+ },
+ {
+ "ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA",
+ BR_TLS_ECDH_ECDSA_WITH_3DES_EDE_CBC_SHA,
+ REQ_ECDH | REQ_3DESCBC | REQ_SHA1,
+ "ECDH key exchange (EC cert), 3DES/CBC + HMAC/SHA-1"
+ },
+ {
+ "ECDH_RSA_WITH_3DES_EDE_CBC_SHA",
+ BR_TLS_ECDH_RSA_WITH_3DES_EDE_CBC_SHA,
+ REQ_ECDH | REQ_3DESCBC | REQ_SHA1,
+ "ECDH key exchange (RSA cert), 3DES/CBC + HMAC/SHA-1"
+ },
+ {
+ "RSA_WITH_3DES_EDE_CBC_SHA",
+ BR_TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ REQ_RSAKEYX | REQ_3DESCBC | REQ_SHA1,
+ "RSA key exchange, 3DES/CBC + HMAC/SHA-1"
+ },
+ { NULL, 0, 0, NULL }
+};
+
+static const struct {
+ int id;
+ const char *name;
+ const char *sid[4];
+} curves[] = {
+ { BR_EC_sect163k1,
+ "sect163k1",
+ { "sect163k1", "K-163", NULL, NULL } },
+ { BR_EC_sect163r1,
+ "sect163r1",
+ { "sect163r1", NULL, NULL, NULL } },
+ { BR_EC_sect163r2,
+ "sect163r2",
+ { "sect163r2", "B-163", NULL, NULL } },
+ { BR_EC_sect193r1,
+ "sect193r1",
+ { "sect193r1", NULL, NULL, NULL } },
+ { BR_EC_sect193r2,
+ "sect193r2",
+ { "sect193r2", NULL, NULL, NULL } },
+ { BR_EC_sect233k1,
+ "sect233k1",
+ { "sect233k1", "K-233", NULL, NULL } },
+ { BR_EC_sect233r1,
+ "sect233r1",
+ { "sect233r1", "B-233", NULL, NULL } },
+ { BR_EC_sect239k1,
+ "sect239k1",
+ { "sect239k1", NULL, NULL, NULL } },
+ { BR_EC_sect283k1,
+ "sect283k1",
+ { "sect283k1", "K-283", NULL, NULL } },
+ { BR_EC_sect283r1,
+ "sect283r1",
+ { "sect283r1", "B-283", NULL, NULL } },
+ { BR_EC_sect409k1,
+ "sect409k1",
+ { "sect409k1", "K-409", NULL, NULL } },
+ { BR_EC_sect409r1,
+ "sect409r1",
+ { "sect409r1", "B-409", NULL, NULL } },
+ { BR_EC_sect571k1,
+ "sect571k1",
+ { "sect571k1", "K-571", NULL, NULL } },
+ { BR_EC_sect571r1,
+ "sect571r1",
+ { "sect571r1", "B-571", NULL, NULL } },
+ { BR_EC_secp160k1,
+ "secp160k1",
+ { "secp160k1", NULL, NULL, NULL } },
+ { BR_EC_secp160r1,
+ "secp160r1",
+ { "secp160r1", NULL, NULL, NULL } },
+ { BR_EC_secp160r2,
+ "secp160r2",
+ { "secp160r2", NULL, NULL, NULL } },
+ { BR_EC_secp192k1,
+ "secp192k1",
+ { "secp192k1", NULL, NULL, NULL } },
+ { BR_EC_secp192r1,
+ "secp192r1",
+ { "secp192r1", "P-192", NULL, NULL } },
+ { BR_EC_secp224k1,
+ "secp224k1",
+ { "secp224k1", NULL, NULL, NULL } },
+ { BR_EC_secp224r1,
+ "secp224r1",
+ { "secp224r1", "P-224", NULL, NULL } },
+ { BR_EC_secp256k1,
+ "secp256k1",
+ { "secp256k1", NULL, NULL, NULL } },
+ { BR_EC_secp256r1,
+ "secp256r1 (P-256)",
+ { "secp256r1", "P-256", "prime256v1", NULL } },
+ { BR_EC_secp384r1,
+ "secp384r1 (P-384)",
+ { "secp384r1", "P-384", NULL, NULL } },
+ { BR_EC_secp521r1,
+ "secp521r1 (P-521)",
+ { "secp521r1", "P-521", NULL, NULL } },
+ { BR_EC_brainpoolP256r1,
+ "brainpoolP256r1",
+ { "brainpoolP256r1", NULL, NULL, NULL } },
+ { BR_EC_brainpoolP384r1,
+ "brainpoolP384r1",
+ { "brainpoolP384r1", NULL, NULL, NULL } },
+ { BR_EC_brainpoolP512r1,
+ "brainpoolP512r1",
+ { "brainpoolP512r1", NULL, NULL, NULL } },
+ { BR_EC_curve25519,
+ "Curve25519",
+ { "curve25519", "c25519", NULL, NULL } },
+ { BR_EC_curve448,
+ "Curve448",
+ { "curve448", "c448", NULL, NULL } },
+ { 0, 0, { 0, 0, 0, 0 } }
+};
+
+static const struct {
+ const char *long_name;
+ const char *short_name;
+ const void *impl;
+} algo_names[] = {
+ /* Block ciphers */
+ { "aes_big_cbcenc", "big", &br_aes_big_cbcenc_vtable },
+ { "aes_big_cbcdec", "big", &br_aes_big_cbcdec_vtable },
+ { "aes_big_ctr", "big", &br_aes_big_ctr_vtable },
+ { "aes_big_ctrcbc", "big", &br_aes_big_ctrcbc_vtable },
+ { "aes_small_cbcenc", "small", &br_aes_small_cbcenc_vtable },
+ { "aes_small_cbcdec", "small", &br_aes_small_cbcdec_vtable },
+ { "aes_small_ctr", "small", &br_aes_small_ctr_vtable },
+ { "aes_small_ctrcbc", "small", &br_aes_small_ctrcbc_vtable },
+ { "aes_ct_cbcenc", "ct", &br_aes_ct_cbcenc_vtable },
+ { "aes_ct_cbcdec", "ct", &br_aes_ct_cbcdec_vtable },
+ { "aes_ct_ctr", "ct", &br_aes_ct_ctr_vtable },
+ { "aes_ct_ctrcbc", "ct", &br_aes_ct_ctrcbc_vtable },
+ { "aes_ct64_cbcenc", "ct64", &br_aes_ct64_cbcenc_vtable },
+ { "aes_ct64_cbcdec", "ct64", &br_aes_ct64_cbcdec_vtable },
+ { "aes_ct64_ctr", "ct64", &br_aes_ct64_ctr_vtable },
+ { "aes_ct64_ctrcbc", "ct64", &br_aes_ct64_ctrcbc_vtable },
+
+ { "des_tab_cbcenc", "tab", &br_des_tab_cbcenc_vtable },
+ { "des_tab_cbcdec", "tab", &br_des_tab_cbcdec_vtable },
+ { "des_ct_cbcenc", "ct", &br_des_ct_cbcenc_vtable },
+ { "des_ct_cbcdec", "ct", &br_des_ct_cbcdec_vtable },
+
+ { "chacha20_ct", "ct", &br_chacha20_ct_run },
+
+ { "ghash_ctmul", "ctmul", &br_ghash_ctmul },
+ { "ghash_ctmul32", "ctmul32", &br_ghash_ctmul32 },
+ { "ghash_ctmul64", "ctmul64", &br_ghash_ctmul64 },
+
+ { "poly1305_ctmul", "ctmul", &br_poly1305_ctmul_run },
+ { "poly1305_ctmul32", "ctmul32", &br_poly1305_ctmul32_run },
+
+ { "ec_all_m15", "all_m15", &br_ec_all_m15 },
+ { "ec_all_m31", "all_m31", &br_ec_all_m31 },
+ { "ec_c25519_i15", "c25519_i15", &br_ec_c25519_i15 },
+ { "ec_c25519_i31", "c25519_i31", &br_ec_c25519_i31 },
+ { "ec_c25519_m15", "c25519_m15", &br_ec_c25519_m15 },
+ { "ec_c25519_m31", "c25519_m31", &br_ec_c25519_m31 },
+ { "ec_p256_m15", "p256_m15", &br_ec_p256_m15 },
+ { "ec_p256_m31", "p256_m31", &br_ec_p256_m31 },
+ { "ec_prime_i15", "prime_i15", &br_ec_prime_i15 },
+ { "ec_prime_i31", "prime_i31", &br_ec_prime_i31 },
+
+ { "ecdsa_i15_sign_asn1", "i15_asn1", &br_ecdsa_i15_sign_asn1 },
+ { "ecdsa_i15_sign_raw", "i15_raw", &br_ecdsa_i15_sign_raw },
+ { "ecdsa_i31_sign_asn1", "i31_asn1", &br_ecdsa_i31_sign_asn1 },
+ { "ecdsa_i31_sign_raw", "i31_raw", &br_ecdsa_i31_sign_raw },
+ { "ecdsa_i15_vrfy_asn1", "i15_asn1", &br_ecdsa_i15_vrfy_asn1 },
+ { "ecdsa_i15_vrfy_raw", "i15_raw", &br_ecdsa_i15_vrfy_raw },
+ { "ecdsa_i31_vrfy_asn1", "i31_asn1", &br_ecdsa_i31_vrfy_asn1 },
+ { "ecdsa_i31_vrfy_raw", "i31_raw", &br_ecdsa_i31_vrfy_raw },
+
+ { "rsa_i15_pkcs1_sign", "i15", &br_rsa_i15_pkcs1_sign },
+ { "rsa_i31_pkcs1_sign", "i31", &br_rsa_i31_pkcs1_sign },
+ { "rsa_i32_pkcs1_sign", "i32", &br_rsa_i32_pkcs1_sign },
+ { "rsa_i15_pkcs1_vrfy", "i15", &br_rsa_i15_pkcs1_vrfy },
+ { "rsa_i31_pkcs1_vrfy", "i31", &br_rsa_i31_pkcs1_vrfy },
+ { "rsa_i32_pkcs1_vrfy", "i32", &br_rsa_i32_pkcs1_vrfy },
+
+ { 0, 0, 0 }
+};
+
+static const struct {
+ const char *long_name;
+ const char *short_name;
+ const void *(*get)(void);
+} algo_names_dyn[] = {
+ { "aes_pwr8_cbcenc", "pwr8",
+ (const void *(*)(void))&br_aes_pwr8_cbcenc_get_vtable },
+ { "aes_pwr8_cbcdec", "pwr8",
+ (const void *(*)(void))&br_aes_pwr8_cbcdec_get_vtable },
+ { "aes_pwr8_ctr", "pwr8",
+ (const void *(*)(void))&br_aes_pwr8_ctr_get_vtable },
+ { "aes_pwr8_ctrcbc", "pwr8",
+ (const void *(*)(void))&br_aes_pwr8_ctrcbc_get_vtable },
+ { "aes_x86ni_cbcenc", "x86ni",
+ (const void *(*)(void))&br_aes_x86ni_cbcenc_get_vtable },
+ { "aes_x86ni_cbcdec", "x86ni",
+ (const void *(*)(void))&br_aes_x86ni_cbcdec_get_vtable },
+ { "aes_x86ni_ctr", "x86ni",
+ (const void *(*)(void))&br_aes_x86ni_ctr_get_vtable },
+ { "aes_x86ni_ctrcbc", "x86ni",
+ (const void *(*)(void))&br_aes_x86ni_ctrcbc_get_vtable },
+ { "chacha20_sse2", "sse2",
+ (const void *(*)(void))&br_chacha20_sse2_get },
+ { "ghash_pclmul", "pclmul",
+ (const void *(*)(void))&br_ghash_pclmul_get },
+ { "ghash_pwr8", "pwr8",
+ (const void *(*)(void))&br_ghash_pwr8_get },
+ { "poly1305_ctmulq", "ctmulq",
+ (const void *(*)(void))&br_poly1305_ctmulq_get },
+ { "rsa_i62_pkcs1_sign", "i62",
+ (const void *(*)(void))&br_rsa_i62_pkcs1_sign_get },
+ { "rsa_i62_pkcs1_vrfy", "i62",
+ (const void *(*)(void))&br_rsa_i62_pkcs1_vrfy_get },
+ { "ec_c25519_m62", "m62",
+ (const void *(*)(void))&br_ec_c25519_m62_get },
+ { "ec_c25519_m64", "m64",
+ (const void *(*)(void))&br_ec_c25519_m64_get },
+ { "ec_p256_m62", "m62",
+ (const void *(*)(void))&br_ec_p256_m62_get },
+ { "ec_p256_m64", "m64",
+ (const void *(*)(void))&br_ec_p256_m64_get },
+ { 0, 0, 0, }
+};
+
+/* see brssl.h */
+const char *
+get_algo_name(const void *impl, int long_name)
+{
+ size_t u;
+
+ for (u = 0; algo_names[u].long_name; u ++) {
+ if (impl == algo_names[u].impl) {
+ return long_name
+ ? algo_names[u].long_name
+ : algo_names[u].short_name;
+ }
+ }
+ for (u = 0; algo_names_dyn[u].long_name; u ++) {
+ if (impl == algo_names_dyn[u].get()) {
+ return long_name
+ ? algo_names_dyn[u].long_name
+ : algo_names_dyn[u].short_name;
+ }
+ }
+ return "UNKNOWN";
+}
+
+/* see brssl.h */
+const char *
+get_curve_name(int id)
+{
+ size_t u;
+
+ for (u = 0; curves[u].name; u ++) {
+ if (curves[u].id == id) {
+ return curves[u].name;
+ }
+ }
+ return NULL;
+}
+
+/* see brssl.h */
+int
+get_curve_name_ext(int id, char *dst, size_t len)
+{
+ const char *name;
+ char tmp[30];
+ size_t n;
+
+ name = get_curve_name(id);
+ if (name == NULL) {
+ sprintf(tmp, "unknown (%d)", id);
+ name = tmp;
+ }
+ n = 1 + strlen(name);
+ if (n > len) {
+ if (len > 0) {
+ dst[0] = 0;
+ }
+ return -1;
+ }
+ memcpy(dst, name, n);
+ return 0;
+}
+
+/* see brssl.h */
+const char *
+get_suite_name(unsigned suite)
+{
+ size_t u;
+
+ for (u = 0; cipher_suites[u].name; u ++) {
+ if (cipher_suites[u].suite == suite) {
+ return cipher_suites[u].name;
+ }
+ }
+ return NULL;
+}
+
+/* see brssl.h */
+int
+get_suite_name_ext(unsigned suite, char *dst, size_t len)
+{
+ const char *name;
+ char tmp[30];
+ size_t n;
+
+ name = get_suite_name(suite);
+ if (name == NULL) {
+ sprintf(tmp, "unknown (0x%04X)", suite);
+ name = tmp;
+ }
+ n = 1 + strlen(name);
+ if (n > len) {
+ if (len > 0) {
+ dst[0] = 0;
+ }
+ return -1;
+ }
+ memcpy(dst, name, n);
+ return 0;
+}
+
+/* see brssl.h */
+int
+uses_ecdhe(unsigned suite)
+{
+ size_t u;
+
+ for (u = 0; cipher_suites[u].name; u ++) {
+ if (cipher_suites[u].suite == suite) {
+ return (cipher_suites[u].req
+ & (REQ_ECDHE_RSA | REQ_ECDHE_ECDSA)) != 0;
+ }
+ }
+ return 0;
+}
+
+/* see brssl.h */
+void
+list_names(void)
+{
+ size_t u;
+
+ printf("Protocol versions:\n");
+ for (u = 0; protocol_versions[u].name; u ++) {
+ printf(" %-8s %s\n",
+ protocol_versions[u].name,
+ protocol_versions[u].comment);
+ }
+ printf("Hash functions:\n");
+ for (u = 0; hash_functions[u].name; u ++) {
+ printf(" %-8s %s\n",
+ hash_functions[u].name,
+ hash_functions[u].comment);
+ }
+ printf("Cipher suites:\n");
+ for (u = 0; cipher_suites[u].name; u ++) {
+ printf(" %s\n %s\n",
+ cipher_suites[u].name,
+ cipher_suites[u].comment);
+ }
+}
+
+/* see brssl.h */
+void
+list_curves(void)
+{
+ size_t u;
+ for (u = 0; curves[u].name; u ++) {
+ size_t v;
+
+ for (v = 0; curves[u].sid[v]; v ++) {
+ if (v == 0) {
+ printf(" ");
+ } else if (v == 1) {
+ printf(" (");
+ } else {
+ printf(", ");
+ }
+ printf("%s", curves[u].sid[v]);
+ }
+ if (v > 1) {
+ printf(")");
+ }
+ printf("\n");
+ }
+}
+
+static int
+is_ign(int c)
+{
+ if (c == 0) {
+ return 0;
+ }
+ if (c <= 32 || c == '-' || c == '_' || c == '.'
+ || c == '/' || c == '+' || c == ':')
+ {
+ return 1;
+ }
+ return 0;
+}
+
+/*
+ * Get next non-ignored character, normalised:
+ * ASCII letters are converted to lowercase
+ * control characters, space, '-', '_', '.', '/', '+' and ':' are ignored
+ * A terminating zero is returned as 0.
+ */
+static int
+next_char(const char **ps, const char *limit)
+{
+ for (;;) {
+ int c;
+
+ if (*ps == limit) {
+ return 0;
+ }
+ c = *(*ps) ++;
+ if (c == 0) {
+ return 0;
+ }
+ if (c >= 'A' && c <= 'Z') {
+ c += 'a' - 'A';
+ }
+ if (!is_ign(c)) {
+ return c;
+ }
+ }
+}
+
+/*
+ * Partial string equality comparison, with normalisation.
+ */
+static int
+eqstr_chunk(const char *s1, size_t s1_len, const char *s2, size_t s2_len)
+{
+ const char *lim1, *lim2;
+
+ lim1 = s1 + s1_len;
+ lim2 = s2 + s2_len;
+ for (;;) {
+ int c1, c2;
+
+ c1 = next_char(&s1, lim1);
+ c2 = next_char(&s2, lim2);
+ if (c1 != c2) {
+ return 0;
+ }
+ if (c1 == 0) {
+ return 1;
+ }
+ }
+}
+
+/* see brssl.h */
+int
+eqstr(const char *s1, const char *s2)
+{
+ return eqstr_chunk(s1, strlen(s1), s2, strlen(s2));
+}
+
+static int
+hexval(int c)
+{
+ if (c >= '0' && c <= '9') {
+ return c - '0';
+ } else if (c >= 'A' && c <= 'F') {
+ return c - 'A' + 10;
+ } else if (c >= 'a' && c <= 'f') {
+ return c - 'a' + 10;
+ } else {
+ return -1;
+ }
+}
+
+/* see brssl.h */
+size_t
+parse_size(const char *s)
+{
+ int radix;
+ size_t acc;
+ const char *t;
+
+ t = s;
+ if (t[0] == '0' && (t[1] == 'x' || t[1] == 'X')) {
+ radix = 16;
+ t += 2;
+ } else {
+ radix = 10;
+ }
+ acc = 0;
+ for (;;) {
+ int c, d;
+ size_t z;
+
+ c = *t ++;
+ if (c == 0) {
+ return acc;
+ }
+ d = hexval(c);
+ if (d < 0 || d >= radix) {
+ fprintf(stderr, "ERROR: not a valid digit: '%c'\n", c);
+ return (size_t)-1;
+ }
+ z = acc * (size_t)radix + (size_t)d;
+ if (z < (size_t)d || (z / (size_t)radix) != acc
+ || z == (size_t)-1)
+ {
+ fprintf(stderr, "ERROR: value too large: %s\n", s);
+ return (size_t)-1;
+ }
+ acc = z;
+ }
+}
+
+/*
+ * Comma-separated list enumeration. This returns a pointer to the first
+ * word in the string, skipping leading ignored characters. '*len' is
+ * set to the word length (not counting trailing ignored characters).
+ * '*str' is updated to point to immediately after the next comma, or to
+ * the terminating zero, whichever comes first.
+ *
+ * Empty words are skipped. If there is no next non-empty word, then this
+ * function returns NULL and sets *len to 0.
+ */
+static const char *
+next_word(const char **str, size_t *len)
+{
+ int c;
+ const char *begin;
+ size_t u;
+
+ /*
+ * Find next non-ignored character which is not a comma.
+ */
+ for (;;) {
+ c = **str;
+ if (c == 0) {
+ *len = 0;
+ return NULL;
+ }
+ if (!is_ign(c) && c != ',') {
+ break;
+ }
+ (*str) ++;
+ }
+
+ /*
+ * Find next comma or terminator.
+ */
+ begin = *str;
+ for (;;) {
+ c = *(*str);
+ if (c == 0 || c == ',') {
+ break;
+ }
+ (*str) ++;
+ }
+
+ /*
+ * Remove trailing ignored characters.
+ */
+ u = (size_t)(*str - begin);
+ while (u > 0 && is_ign(begin[u - 1])) {
+ u --;
+ }
+ if (c == ',') {
+ (*str) ++;
+ }
+ *len = u;
+ return begin;
+}
+
+/* see brssl.h */
+unsigned
+parse_version(const char *name, size_t len)
+{
+ size_t u;
+
+ for (u = 0;; u ++) {
+ const char *ref;
+
+ ref = protocol_versions[u].name;
+ if (ref == NULL) {
+ fprintf(stderr, "ERROR: unrecognised protocol"
+ " version name: '%s'\n", name);
+ return 0;
+ }
+ if (eqstr_chunk(ref, strlen(ref), name, len)) {
+ return protocol_versions[u].version;
+ }
+ }
+}
+
+/* see brssl.h */
+unsigned
+parse_hash_functions(const char *arg)
+{
+ unsigned r;
+
+ r = 0;
+ for (;;) {
+ const char *name;
+ size_t len;
+ size_t u;
+
+ name = next_word(&arg, &len);
+ if (name == NULL) {
+ break;
+ }
+ for (u = 0;; u ++) {
+ const char *ref;
+
+ ref = hash_functions[u].name;
+ if (ref == 0) {
+ fprintf(stderr, "ERROR: unrecognised"
+ " hash function name: '");
+ fwrite(name, 1, len, stderr);
+ fprintf(stderr, "'\n");
+ return 0;
+ }
+ if (eqstr_chunk(ref, strlen(ref), name, len)) {
+ int id;
+
+ id = (hash_functions[u].hclass->desc
+ >> BR_HASHDESC_ID_OFF)
+ & BR_HASHDESC_ID_MASK;
+ r |= (unsigned)1 << id;
+ break;
+ }
+ }
+ }
+ if (r == 0) {
+ fprintf(stderr, "ERROR: no hash function name provided\n");
+ }
+ return r;
+}
+
+/* see brssl.h */
+cipher_suite *
+parse_suites(const char *arg, size_t *num)
+{
+ VECTOR(cipher_suite) suites = VEC_INIT;
+ cipher_suite *r;
+
+ for (;;) {
+ const char *name;
+ size_t u, len;
+
+ name = next_word(&arg, &len);
+ if (name == NULL) {
+ break;
+ }
+ for (u = 0;; u ++) {
+ const char *ref;
+
+ ref = cipher_suites[u].name;
+ if (ref == NULL) {
+ fprintf(stderr, "ERROR: unrecognised"
+ " cipher suite '");
+ fwrite(name, 1, len, stderr);
+ fprintf(stderr, "'\n");
+ return 0;
+ }
+ if (eqstr_chunk(ref, strlen(ref), name, len)) {
+ VEC_ADD(suites, cipher_suites[u]);
+ break;
+ }
+ }
+ }
+ if (VEC_LEN(suites) == 0) {
+ fprintf(stderr, "ERROR: no cipher suite provided\n");
+ }
+ r = VEC_TOARRAY(suites);
+ *num = VEC_LEN(suites);
+ VEC_CLEAR(suites);
+ return r;
+}
+
+/* see brssl.h */
+const char *
+ec_curve_name(int curve)
+{
+ switch (curve) {
+ case BR_EC_sect163k1: return "sect163k1";
+ case BR_EC_sect163r1: return "sect163r1";
+ case BR_EC_sect163r2: return "sect163r2";
+ case BR_EC_sect193r1: return "sect193r1";
+ case BR_EC_sect193r2: return "sect193r2";
+ case BR_EC_sect233k1: return "sect233k1";
+ case BR_EC_sect233r1: return "sect233r1";
+ case BR_EC_sect239k1: return "sect239k1";
+ case BR_EC_sect283k1: return "sect283k1";
+ case BR_EC_sect283r1: return "sect283r1";
+ case BR_EC_sect409k1: return "sect409k1";
+ case BR_EC_sect409r1: return "sect409r1";
+ case BR_EC_sect571k1: return "sect571k1";
+ case BR_EC_sect571r1: return "sect571r1";
+ case BR_EC_secp160k1: return "secp160k1";
+ case BR_EC_secp160r1: return "secp160r1";
+ case BR_EC_secp160r2: return "secp160r2";
+ case BR_EC_secp192k1: return "secp192k1";
+ case BR_EC_secp192r1: return "secp192r1";
+ case BR_EC_secp224k1: return "secp224k1";
+ case BR_EC_secp224r1: return "secp224r1";
+ case BR_EC_secp256k1: return "secp256k1";
+ case BR_EC_secp256r1: return "secp256r1";
+ case BR_EC_secp384r1: return "secp384r1";
+ case BR_EC_secp521r1: return "secp521r1";
+ case BR_EC_brainpoolP256r1: return "brainpoolP256r1";
+ case BR_EC_brainpoolP384r1: return "brainpoolP384r1";
+ case BR_EC_brainpoolP512r1: return "brainpoolP512r1";
+ default:
+ return "unknown";
+ }
+}
+
+/* see brssl.h */
+int
+get_curve_by_name(const char *str)
+{
+ size_t u, v;
+
+ for (u = 0; curves[u].name; u ++) {
+ for (v = 0; curves[u].sid[v]; v ++) {
+ if (eqstr(curves[u].sid[v], str)) {
+ return curves[u].id;
+ }
+ }
+ }
+ return -1;
+}
+
+/* see brssl.h */
+const char *
+hash_function_name(int id)
+{
+ switch (id) {
+ case br_md5sha1_ID: return "MD5+SHA-1";
+ case br_md5_ID: return "MD5";
+ case br_sha1_ID: return "SHA-1";
+ case br_sha224_ID: return "SHA-224";
+ case br_sha256_ID: return "SHA-256";
+ case br_sha384_ID: return "SHA-384";
+ case br_sha512_ID: return "SHA-512";
+ default:
+ return "unknown";
+ }
+}
diff --git a/contrib/bearssl/tools/server.c b/contrib/bearssl/tools/server.c
new file mode 100644
index 000000000000..a97de35dee8e
--- /dev/null
+++ b/contrib/bearssl/tools/server.c
@@ -0,0 +1,1235 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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 <signal.h>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <fcntl.h>
+
+#define SOCKET int
+#define INVALID_SOCKET (-1)
+#define SOCKADDR_STORAGE struct sockaddr_storage
+#endif
+
+#include "brssl.h"
+
+static SOCKET
+host_bind(const char *host, const char *port, int verbose)
+{
+ struct addrinfo hints, *si, *p;
+ SOCKET 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 INVALID_SOCKET;
+ }
+ fd = INVALID_SOCKET;
+ 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;
+ int opt;
+
+ sa = (struct sockaddr *)p->ai_addr;
+ if (sa->sa_family == AF_INET) {
+ memcpy(&sa4, sa, sizeof sa4);
+ 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) {
+ memcpy(&sa6, sa, sizeof sa6);
+ 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 (verbose) {
+ char tmp[INET6_ADDRSTRLEN + 50];
+
+ if (addr != NULL) {
+ if (!inet_ntop(p->ai_family, addr,
+ tmp, sizeof tmp))
+ {
+ strcpy(tmp, "<invalid>");
+ }
+ } 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 == INVALID_SOCKET) {
+ if (verbose) {
+ perror("socket()");
+ }
+ continue;
+ }
+ opt = 1;
+ setsockopt(fd, SOL_SOCKET, SO_REUSEADDR,
+ (void *)&opt, sizeof opt);
+#ifdef IPV6_V6ONLY
+ /*
+ * We want to make sure that the server socket works for
+ * both IPv4 and IPv6. But IPV6_V6ONLY is not defined on
+ * some very old systems.
+ */
+ opt = 0;
+ setsockopt(fd, IPPROTO_IPV6, IPV6_V6ONLY,
+ (void *)&opt, sizeof opt);
+#endif
+ if (bind(fd, sa, sa_len) < 0) {
+ if (verbose) {
+ perror("bind()");
+ }
+#ifdef _WIN32
+ closesocket(fd);
+#else
+ close(fd);
+#endif
+ continue;
+ }
+ break;
+ }
+ if (p == NULL) {
+ freeaddrinfo(si);
+ fprintf(stderr, "ERROR: failed to bind\n");
+ return INVALID_SOCKET;
+ }
+ freeaddrinfo(si);
+ if (listen(fd, 5) < 0) {
+ if (verbose) {
+ perror("listen()");
+ }
+#ifdef _WIN32
+ closesocket(fd);
+#else
+ close(fd);
+#endif
+ return INVALID_SOCKET;
+ }
+ if (verbose) {
+ fprintf(stderr, "bound.\n");
+ }
+ return fd;
+}
+
+static SOCKET
+accept_client(SOCKET server_fd, int verbose, int nonblock)
+{
+ int fd;
+ SOCKADDR_STORAGE sa;
+ socklen_t sa_len;
+
+ sa_len = sizeof sa;
+ fd = accept(server_fd, (struct sockaddr *)&sa, &sa_len);
+ if (fd == INVALID_SOCKET) {
+ if (verbose) {
+ perror("accept()");
+ }
+ return INVALID_SOCKET;
+ }
+ if (verbose) {
+ char tmp[INET6_ADDRSTRLEN + 50];
+ const char *name;
+
+ name = NULL;
+ switch (((struct sockaddr *)&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_INET6,
+ &((struct sockaddr_in6 *)&sa)->sin6_addr,
+ tmp, sizeof tmp);
+ break;
+ }
+ if (name == NULL) {
+ sprintf(tmp, "<unknown: %lu>", (unsigned long)
+ ((struct sockaddr *)&sa)->sa_family);
+ name = tmp;
+ }
+ fprintf(stderr, "accepting connection from: %s\n", name);
+ }
+
+ /*
+ * We make the socket non-blocking, since we are going to use
+ * poll() or select() to organise I/O.
+ */
+ if (nonblock) {
+#ifdef _WIN32
+ u_long arg;
+
+ arg = 1;
+ ioctlsocket(fd, FIONBIO, &arg);
+#else
+ fcntl(fd, F_SETFL, O_NONBLOCK);
+#endif
+ }
+ return fd;
+}
+
+static void
+usage_server(void)
+{
+ fprintf(stderr,
+"usage: brssl server [ options ]\n");
+ fprintf(stderr,
+"options:\n");
+ fprintf(stderr,
+" -q suppress verbose messages\n");
+ fprintf(stderr,
+" -trace activate extra debug messages (dump of all packets)\n");
+ fprintf(stderr,
+" -b name bind to a specific address or host name\n");
+ fprintf(stderr,
+" -p port bind to a specific port (default: 4433)\n");
+ fprintf(stderr,
+" -mono use monodirectional buffering\n");
+ fprintf(stderr,
+" -buf length set the I/O buffer length (in bytes)\n");
+ fprintf(stderr,
+" -cache length set the session cache storage length (in bytes)\n");
+ fprintf(stderr,
+" -cert fname read certificate chain from file 'fname'\n");
+ fprintf(stderr,
+" -key fname read private key from file 'fname'\n");
+ fprintf(stderr,
+" -CA file add trust anchors from 'file' (for client auth)\n");
+ fprintf(stderr,
+" -anon_ok request but do not require a client certificate\n");
+ fprintf(stderr,
+" -list list supported names (protocols, algorithms...)\n");
+ fprintf(stderr,
+" -vmin name set minimum supported version (default: TLS-1.0)\n");
+ fprintf(stderr,
+" -vmax name set maximum supported version (default: TLS-1.2)\n");
+ fprintf(stderr,
+" -cs names set list of supported cipher suites (comma-separated)\n");
+ fprintf(stderr,
+" -hf names add support for some hash functions (comma-separated)\n");
+ fprintf(stderr,
+" -cbhash test hashing in policy callback\n");
+ fprintf(stderr,
+" -serverpref enforce server's preferences for cipher suites\n");
+ fprintf(stderr,
+" -noreneg prohibit renegotiations\n");
+ fprintf(stderr,
+" -alpn name add protocol name to list of protocols (ALPN extension)\n");
+ fprintf(stderr,
+" -strictalpn fail on ALPN mismatch\n");
+ exit(EXIT_FAILURE);
+}
+
+typedef struct {
+ const br_ssl_server_policy_class *vtable;
+ int verbose;
+ br_x509_certificate *chain;
+ size_t chain_len;
+ int cert_signer_algo;
+ private_key *sk;
+ int cbhash;
+} policy_context;
+
+static void
+print_hashes(unsigned chashes)
+{
+ int i;
+
+ for (i = 2; i <= 6; i ++) {
+ if ((chashes >> i) & 1) {
+ int z;
+
+ switch (i) {
+ case 3: z = 224; break;
+ case 4: z = 256; break;
+ case 5: z = 384; break;
+ case 6: z = 512; break;
+ default:
+ z = 1;
+ break;
+ }
+ fprintf(stderr, " sha%d", z);
+ }
+ }
+}
+
+static unsigned
+choose_hash(unsigned chashes)
+{
+ unsigned hash_id;
+
+ for (hash_id = 6; hash_id >= 2; hash_id --) {
+ if (((chashes >> hash_id) & 1) != 0) {
+ return hash_id;
+ }
+ }
+ /*
+ * Normally unreachable.
+ */
+ return 0;
+}
+
+static int
+sp_choose(const br_ssl_server_policy_class **pctx,
+ const br_ssl_server_context *cc,
+ br_ssl_server_choices *choices)
+{
+ policy_context *pc;
+ const br_suite_translated *st;
+ size_t u, st_num;
+ unsigned chashes;
+
+ pc = (policy_context *)pctx;
+ st = br_ssl_server_get_client_suites(cc, &st_num);
+ chashes = br_ssl_server_get_client_hashes(cc);
+ if (pc->verbose) {
+ fprintf(stderr, "Client parameters:\n");
+ fprintf(stderr, " Maximum version: ");
+ switch (cc->client_max_version) {
+ case BR_SSL30:
+ fprintf(stderr, "SSL 3.0");
+ break;
+ case BR_TLS10:
+ fprintf(stderr, "TLS 1.0");
+ break;
+ case BR_TLS11:
+ fprintf(stderr, "TLS 1.1");
+ break;
+ case BR_TLS12:
+ fprintf(stderr, "TLS 1.2");
+ break;
+ default:
+ fprintf(stderr, "unknown (0x%04X)",
+ (unsigned)cc->client_max_version);
+ break;
+ }
+ fprintf(stderr, "\n");
+ fprintf(stderr, " Compatible cipher suites:\n");
+ for (u = 0; u < st_num; u ++) {
+ char csn[80];
+
+ get_suite_name_ext(st[u][0], csn, sizeof csn);
+ fprintf(stderr, " %s\n", csn);
+ }
+ fprintf(stderr, " Common sign+hash functions:\n");
+ if ((chashes & 0xFF) != 0) {
+ fprintf(stderr, " with RSA:");
+ print_hashes(chashes);
+ fprintf(stderr, "\n");
+ }
+ if ((chashes >> 8) != 0) {
+ fprintf(stderr, " with ECDSA:");
+ print_hashes(chashes >> 8);
+ fprintf(stderr, "\n");
+ }
+ }
+ for (u = 0; u < st_num; u ++) {
+ unsigned tt;
+
+ tt = st[u][1];
+ switch (tt >> 12) {
+ case BR_SSLKEYX_RSA:
+ if (pc->sk->key_type == BR_KEYTYPE_RSA) {
+ choices->cipher_suite = st[u][0];
+ goto choose_ok;
+ }
+ break;
+ case BR_SSLKEYX_ECDHE_RSA:
+ if (pc->sk->key_type == BR_KEYTYPE_RSA) {
+ choices->cipher_suite = st[u][0];
+ if (br_ssl_engine_get_version(&cc->eng)
+ < BR_TLS12)
+ {
+ if (pc->cbhash) {
+ choices->algo_id = 0x0001;
+ } else {
+ choices->algo_id = 0xFF00;
+ }
+ } else {
+ unsigned id;
+
+ id = choose_hash(chashes);
+ if (pc->cbhash) {
+ choices->algo_id =
+ (id << 8) + 0x01;
+ } else {
+ choices->algo_id = 0xFF00 + id;
+ }
+ }
+ goto choose_ok;
+ }
+ break;
+ case BR_SSLKEYX_ECDHE_ECDSA:
+ if (pc->sk->key_type == BR_KEYTYPE_EC) {
+ choices->cipher_suite = st[u][0];
+ if (br_ssl_engine_get_version(&cc->eng)
+ < BR_TLS12)
+ {
+ if (pc->cbhash) {
+ choices->algo_id = 0x0203;
+ } else {
+ choices->algo_id =
+ 0xFF00 + br_sha1_ID;
+ }
+ } else {
+ unsigned id;
+
+ id = choose_hash(chashes >> 8);
+ if (pc->cbhash) {
+ choices->algo_id =
+ (id << 8) + 0x03;
+ } else {
+ choices->algo_id =
+ 0xFF00 + id;
+ }
+ }
+ goto choose_ok;
+ }
+ break;
+ case BR_SSLKEYX_ECDH_RSA:
+ if (pc->sk->key_type == BR_KEYTYPE_EC
+ && pc->cert_signer_algo == BR_KEYTYPE_RSA)
+ {
+ choices->cipher_suite = st[u][0];
+ goto choose_ok;
+ }
+ break;
+ case BR_SSLKEYX_ECDH_ECDSA:
+ if (pc->sk->key_type == BR_KEYTYPE_EC
+ && pc->cert_signer_algo == BR_KEYTYPE_EC)
+ {
+ choices->cipher_suite = st[u][0];
+ goto choose_ok;
+ }
+ break;
+ }
+ }
+ return 0;
+
+choose_ok:
+ choices->chain = pc->chain;
+ choices->chain_len = pc->chain_len;
+ if (pc->verbose) {
+ char csn[80];
+
+ get_suite_name_ext(choices->cipher_suite, csn, sizeof csn);
+ fprintf(stderr, "Using: %s\n", csn);
+ }
+ return 1;
+}
+
+static uint32_t
+sp_do_keyx(const br_ssl_server_policy_class **pctx,
+ unsigned char *data, size_t *len)
+{
+ policy_context *pc;
+ uint32_t r;
+ size_t xoff, xlen;
+
+ pc = (policy_context *)pctx;
+ switch (pc->sk->key_type) {
+ const br_ec_impl *iec;
+
+ case BR_KEYTYPE_RSA:
+ return br_rsa_ssl_decrypt(
+ br_rsa_private_get_default(),
+ &pc->sk->key.rsa, data, *len);
+ case BR_KEYTYPE_EC:
+ iec = br_ec_get_default();
+ r = iec->mul(data, *len, pc->sk->key.ec.x,
+ pc->sk->key.ec.xlen, pc->sk->key.ec.curve);
+ xoff = iec->xoff(pc->sk->key.ec.curve, &xlen);
+ memmove(data, data + xoff, xlen);
+ *len = xlen;
+ return r;
+ default:
+ fprintf(stderr, "ERROR: unknown private key type (%d)\n",
+ (int)pc->sk->key_type);
+ return 0;
+ }
+}
+
+static size_t
+sp_do_sign(const br_ssl_server_policy_class **pctx,
+ unsigned algo_id, unsigned char *data, size_t hv_len, size_t len)
+{
+ policy_context *pc;
+ unsigned char hv[64];
+
+ pc = (policy_context *)pctx;
+ if (algo_id >= 0xFF00) {
+ algo_id &= 0xFF;
+ memcpy(hv, data, hv_len);
+ } else {
+ const br_hash_class *hc;
+ br_hash_compat_context zc;
+
+ if (pc->verbose) {
+ fprintf(stderr, "Callback hashing, algo = 0x%04X,"
+ " data_len = %lu\n",
+ algo_id, (unsigned long)hv_len);
+ }
+ algo_id >>= 8;
+ hc = get_hash_impl(algo_id);
+ if (hc == NULL) {
+ if (pc->verbose) {
+ fprintf(stderr,
+ "ERROR: unsupported hash function %u\n",
+ algo_id);
+ }
+ return 0;
+ }
+ hc->init(&zc.vtable);
+ hc->update(&zc.vtable, data, hv_len);
+ hc->out(&zc.vtable, hv);
+ hv_len = (hc->desc >> BR_HASHDESC_OUT_OFF)
+ & BR_HASHDESC_OUT_MASK;
+ }
+ switch (pc->sk->key_type) {
+ size_t sig_len;
+ uint32_t x;
+ const unsigned char *hash_oid;
+ const br_hash_class *hc;
+
+ case BR_KEYTYPE_RSA:
+ hash_oid = get_hash_oid(algo_id);
+ if (hash_oid == NULL && algo_id != 0) {
+ if (pc->verbose) {
+ fprintf(stderr, "ERROR: cannot RSA-sign with"
+ " unknown hash function: %u\n",
+ algo_id);
+ }
+ return 0;
+ }
+ sig_len = (pc->sk->key.rsa.n_bitlen + 7) >> 3;
+ if (len < sig_len) {
+ if (pc->verbose) {
+ fprintf(stderr, "ERROR: cannot RSA-sign,"
+ " buffer is too small"
+ " (sig=%lu, buf=%lu)\n",
+ (unsigned long)sig_len,
+ (unsigned long)len);
+ }
+ return 0;
+ }
+ x = br_rsa_pkcs1_sign_get_default()(
+ hash_oid, hv, hv_len, &pc->sk->key.rsa, data);
+ if (!x) {
+ if (pc->verbose) {
+ fprintf(stderr, "ERROR: RSA-sign failure\n");
+ }
+ return 0;
+ }
+ return sig_len;
+
+ case BR_KEYTYPE_EC:
+ hc = get_hash_impl(algo_id);
+ if (hc == NULL) {
+ if (pc->verbose) {
+ fprintf(stderr, "ERROR: cannot ECDSA-sign with"
+ " unknown hash function: %u\n",
+ algo_id);
+ }
+ return 0;
+ }
+ if (len < 139) {
+ if (pc->verbose) {
+ fprintf(stderr, "ERROR: cannot ECDSA-sign"
+ " (output buffer = %lu)\n",
+ (unsigned long)len);
+ }
+ return 0;
+ }
+ sig_len = br_ecdsa_sign_asn1_get_default()(
+ br_ec_get_default(), hc, hv, &pc->sk->key.ec, data);
+ if (sig_len == 0) {
+ if (pc->verbose) {
+ fprintf(stderr, "ERROR: ECDSA-sign failure\n");
+ }
+ return 0;
+ }
+ return sig_len;
+
+ default:
+ return 0;
+ }
+}
+
+static const br_ssl_server_policy_class policy_vtable = {
+ sizeof(policy_context),
+ sp_choose,
+ sp_do_keyx,
+ sp_do_sign
+};
+
+void
+free_alpn(void *alpn)
+{
+ xfree(*(char **)alpn);
+}
+
+/* see brssl.h */
+int
+do_server(int argc, char *argv[])
+{
+ int retcode;
+ int verbose;
+ int trace;
+ int i, bidi;
+ const char *bind_name;
+ const char *port;
+ unsigned vmin, vmax;
+ cipher_suite *suites;
+ size_t num_suites;
+ uint16_t *suite_ids;
+ unsigned hfuns;
+ int cbhash;
+ br_x509_certificate *chain;
+ size_t chain_len;
+ int cert_signer_algo;
+ private_key *sk;
+ anchor_list anchors = VEC_INIT;
+ VECTOR(char *) alpn_names = VEC_INIT;
+ br_x509_minimal_context xc;
+ const br_hash_class *dnhash;
+ size_t u;
+ br_ssl_server_context cc;
+ policy_context pc;
+ br_ssl_session_cache_lru lru;
+ unsigned char *iobuf, *cache;
+ size_t iobuf_len, cache_len;
+ uint32_t flags;
+ SOCKET server_fd, fd;
+
+ retcode = 0;
+ verbose = 1;
+ trace = 0;
+ bind_name = NULL;
+ port = NULL;
+ bidi = 1;
+ vmin = 0;
+ vmax = 0;
+ suites = NULL;
+ num_suites = 0;
+ hfuns = 0;
+ cbhash = 0;
+ suite_ids = NULL;
+ chain = NULL;
+ chain_len = 0;
+ sk = NULL;
+ iobuf = NULL;
+ iobuf_len = 0;
+ cache = NULL;
+ cache_len = (size_t)-1;
+ flags = 0;
+ server_fd = INVALID_SOCKET;
+ fd = INVALID_SOCKET;
+ for (i = 0; i < argc; i ++) {
+ const char *arg;
+
+ arg = argv[i];
+ if (arg[0] != '-') {
+ usage_server();
+ goto server_exit_error;
+ }
+ if (eqstr(arg, "-v") || eqstr(arg, "-verbose")) {
+ verbose = 1;
+ } else if (eqstr(arg, "-q") || eqstr(arg, "-quiet")) {
+ verbose = 0;
+ } else if (eqstr(arg, "-trace")) {
+ trace = 1;
+ } else if (eqstr(arg, "-b")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-b'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ if (bind_name != NULL) {
+ fprintf(stderr, "ERROR: duplicate bind host\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ bind_name = argv[i];
+ } else if (eqstr(arg, "-p")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-p'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ if (port != NULL) {
+ fprintf(stderr, "ERROR: duplicate bind port\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ port = argv[i];
+ } else if (eqstr(arg, "-mono")) {
+ bidi = 0;
+ } else if (eqstr(arg, "-buf")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-buf'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ arg = argv[i];
+ if (iobuf_len != 0) {
+ fprintf(stderr,
+ "ERROR: duplicate I/O buffer length\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ iobuf_len = parse_size(arg);
+ if (iobuf_len == (size_t)-1) {
+ usage_server();
+ goto server_exit_error;
+ }
+ } else if (eqstr(arg, "-cache")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-cache'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ arg = argv[i];
+ if (cache_len != (size_t)-1) {
+ fprintf(stderr, "ERROR: duplicate session"
+ " cache length\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ cache_len = parse_size(arg);
+ if (cache_len == (size_t)-1) {
+ usage_server();
+ goto server_exit_error;
+ }
+ } else if (eqstr(arg, "-cert")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-cert'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ if (chain != NULL) {
+ fprintf(stderr,
+ "ERROR: duplicate certificate chain\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ arg = argv[i];
+ chain = read_certificates(arg, &chain_len);
+ if (chain == NULL || chain_len == 0) {
+ goto server_exit_error;
+ }
+ } else if (eqstr(arg, "-key")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-key'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ if (sk != NULL) {
+ fprintf(stderr,
+ "ERROR: duplicate private key\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ arg = argv[i];
+ sk = read_private_key(arg);
+ if (sk == NULL) {
+ goto server_exit_error;
+ }
+ } else if (eqstr(arg, "-CA")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-CA'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ arg = argv[i];
+ if (read_trust_anchors(&anchors, arg) == 0) {
+ usage_server();
+ goto server_exit_error;
+ }
+ } else if (eqstr(arg, "-anon_ok")) {
+ flags |= BR_OPT_TOLERATE_NO_CLIENT_AUTH;
+ } else if (eqstr(arg, "-list")) {
+ list_names();
+ goto server_exit;
+ } else if (eqstr(arg, "-vmin")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-vmin'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ arg = argv[i];
+ if (vmin != 0) {
+ fprintf(stderr,
+ "ERROR: duplicate minimum version\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ vmin = parse_version(arg, strlen(arg));
+ if (vmin == 0) {
+ fprintf(stderr,
+ "ERROR: unrecognised version '%s'\n",
+ arg);
+ usage_server();
+ goto server_exit_error;
+ }
+ } else if (eqstr(arg, "-vmax")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-vmax'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ arg = argv[i];
+ if (vmax != 0) {
+ fprintf(stderr,
+ "ERROR: duplicate maximum version\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ vmax = parse_version(arg, strlen(arg));
+ if (vmax == 0) {
+ fprintf(stderr,
+ "ERROR: unrecognised version '%s'\n",
+ arg);
+ usage_server();
+ goto server_exit_error;
+ }
+ } else if (eqstr(arg, "-cs")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-cs'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ arg = argv[i];
+ if (suites != NULL) {
+ fprintf(stderr, "ERROR: duplicate list"
+ " of cipher suites\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ suites = parse_suites(arg, &num_suites);
+ if (suites == NULL) {
+ usage_server();
+ goto server_exit_error;
+ }
+ } else if (eqstr(arg, "-hf")) {
+ unsigned x;
+
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-hf'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ arg = argv[i];
+ x = parse_hash_functions(arg);
+ if (x == 0) {
+ usage_server();
+ goto server_exit_error;
+ }
+ hfuns |= x;
+ } else if (eqstr(arg, "-cbhash")) {
+ cbhash = 1;
+ } else if (eqstr(arg, "-serverpref")) {
+ flags |= BR_OPT_ENFORCE_SERVER_PREFERENCES;
+ } else if (eqstr(arg, "-noreneg")) {
+ flags |= BR_OPT_NO_RENEGOTIATION;
+ } else if (eqstr(arg, "-alpn")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-alpn'\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ VEC_ADD(alpn_names, xstrdup(argv[i]));
+ } else if (eqstr(arg, "-strictalpn")) {
+ flags |= BR_OPT_FAIL_ON_ALPN_MISMATCH;
+ } else {
+ fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
+ usage_server();
+ goto server_exit_error;
+ }
+ }
+ if (port == NULL) {
+ port = "4433";
+ }
+ if (vmin == 0) {
+ vmin = BR_TLS10;
+ }
+ if (vmax == 0) {
+ vmax = BR_TLS12;
+ }
+ if (vmax < vmin) {
+ fprintf(stderr, "ERROR: impossible minimum/maximum protocol"
+ " version combination\n");
+ usage_server();
+ goto server_exit_error;
+ }
+ if (suites == NULL) {
+ num_suites = 0;
+
+ for (u = 0; cipher_suites[u].name; u ++) {
+ if ((cipher_suites[u].req & REQ_TLS12) == 0
+ || vmax >= BR_TLS12)
+ {
+ num_suites ++;
+ }
+ }
+ suites = xmalloc(num_suites * sizeof *suites);
+ num_suites = 0;
+ for (u = 0; cipher_suites[u].name; u ++) {
+ if ((cipher_suites[u].req & REQ_TLS12) == 0
+ || vmax >= BR_TLS12)
+ {
+ suites[num_suites ++] = cipher_suites[u];
+ }
+ }
+ }
+ if (hfuns == 0) {
+ hfuns = (unsigned)-1;
+ }
+ if (chain == NULL || chain_len == 0) {
+ fprintf(stderr, "ERROR: no certificate chain provided\n");
+ goto server_exit_error;
+ }
+ if (sk == NULL) {
+ fprintf(stderr, "ERROR: no private key provided\n");
+ goto server_exit_error;
+ }
+ switch (sk->key_type) {
+ int curve;
+ uint32_t supp;
+
+ case BR_KEYTYPE_RSA:
+ break;
+ case BR_KEYTYPE_EC:
+ curve = sk->key.ec.curve;
+ supp = br_ec_get_default()->supported_curves;
+ if (curve > 31 || !((supp >> curve) & 1)) {
+ fprintf(stderr, "ERROR: private key curve (%d)"
+ " is not supported\n", curve);
+ goto server_exit_error;
+ }
+ break;
+ default:
+ fprintf(stderr, "ERROR: unsupported private key type (%d)\n",
+ sk->key_type);
+ break;
+ }
+ cert_signer_algo = get_cert_signer_algo(chain);
+ if (cert_signer_algo == 0) {
+ goto server_exit_error;
+ }
+ if (verbose) {
+ const char *csas;
+
+ switch (cert_signer_algo) {
+ case BR_KEYTYPE_RSA: csas = "RSA"; break;
+ case BR_KEYTYPE_EC: csas = "EC"; break;
+ default:
+ csas = "unknown";
+ break;
+ }
+ fprintf(stderr, "Issuing CA key type: %d (%s)\n",
+ cert_signer_algo, csas);
+ }
+ if (iobuf_len == 0) {
+ if (bidi) {
+ iobuf_len = BR_SSL_BUFSIZE_BIDI;
+ } else {
+ iobuf_len = BR_SSL_BUFSIZE_MONO;
+ }
+ }
+ iobuf = xmalloc(iobuf_len);
+ if (cache_len == (size_t)-1) {
+ cache_len = 5000;
+ }
+ cache = xmalloc(cache_len);
+
+ /*
+ * Compute implementation requirements and inject implementations.
+ */
+ suite_ids = xmalloc(num_suites * sizeof *suite_ids);
+ br_ssl_server_zero(&cc);
+ br_ssl_engine_set_versions(&cc.eng, vmin, vmax);
+ br_ssl_engine_set_all_flags(&cc.eng, flags);
+ if (vmin <= BR_TLS11) {
+ if (!(hfuns & (1 << br_md5_ID))) {
+ fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need MD5\n");
+ goto server_exit_error;
+ }
+ if (!(hfuns & (1 << br_sha1_ID))) {
+ fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need SHA-1\n");
+ goto server_exit_error;
+ }
+ }
+ for (u = 0; u < num_suites; u ++) {
+ unsigned req;
+
+ req = suites[u].req;
+ suite_ids[u] = suites[u].suite;
+ if ((req & REQ_TLS12) != 0 && vmax < BR_TLS12) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires TLS 1.2\n",
+ suites[u].name);
+ goto server_exit_error;
+ }
+ if ((req & REQ_SHA1) != 0 && !(hfuns & (1 << br_sha1_ID))) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires SHA-1\n",
+ suites[u].name);
+ goto server_exit_error;
+ }
+ if ((req & REQ_SHA256) != 0 && !(hfuns & (1 << br_sha256_ID))) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires SHA-256\n",
+ suites[u].name);
+ goto server_exit_error;
+ }
+ if ((req & REQ_SHA384) != 0 && !(hfuns & (1 << br_sha384_ID))) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires SHA-384\n",
+ suites[u].name);
+ goto server_exit_error;
+ }
+ /* TODO: algorithm implementation selection */
+ if ((req & REQ_AESCBC) != 0) {
+ br_ssl_engine_set_default_aes_cbc(&cc.eng);
+ }
+ if ((req & REQ_AESCCM) != 0) {
+ br_ssl_engine_set_default_aes_ccm(&cc.eng);
+ }
+ if ((req & REQ_AESGCM) != 0) {
+ br_ssl_engine_set_default_aes_gcm(&cc.eng);
+ }
+ if ((req & REQ_CHAPOL) != 0) {
+ br_ssl_engine_set_default_chapol(&cc.eng);
+ }
+ if ((req & REQ_3DESCBC) != 0) {
+ br_ssl_engine_set_default_des_cbc(&cc.eng);
+ }
+ if ((req & (REQ_ECDHE_RSA | REQ_ECDHE_ECDSA)) != 0) {
+ br_ssl_engine_set_default_ec(&cc.eng);
+ }
+ }
+ br_ssl_engine_set_suites(&cc.eng, suite_ids, num_suites);
+
+ dnhash = NULL;
+ for (u = 0; hash_functions[u].name; u ++) {
+ const br_hash_class *hc;
+ int id;
+
+ hc = hash_functions[u].hclass;
+ id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
+ if ((hfuns & ((unsigned)1 << id)) != 0) {
+ dnhash = hc;
+ br_ssl_engine_set_hash(&cc.eng, id, hc);
+ }
+ }
+ if (vmin <= BR_TLS11) {
+ br_ssl_engine_set_prf10(&cc.eng, &br_tls10_prf);
+ }
+ if (vmax >= BR_TLS12) {
+ if ((hfuns & ((unsigned)1 << br_sha256_ID)) != 0) {
+ br_ssl_engine_set_prf_sha256(&cc.eng,
+ &br_tls12_sha256_prf);
+ }
+ if ((hfuns & ((unsigned)1 << br_sha384_ID)) != 0) {
+ br_ssl_engine_set_prf_sha384(&cc.eng,
+ &br_tls12_sha384_prf);
+ }
+ }
+
+ br_ssl_session_cache_lru_init(&lru, cache, cache_len);
+ br_ssl_server_set_cache(&cc, &lru.vtable);
+
+ if (VEC_LEN(alpn_names) != 0) {
+ br_ssl_engine_set_protocol_names(&cc.eng,
+ (const char **)&VEC_ELT(alpn_names, 0),
+ VEC_LEN(alpn_names));
+ }
+
+ /*
+ * Set the policy handler (that chooses the actual cipher suite,
+ * selects the certificate chain, and runs the private key
+ * operations).
+ */
+ pc.vtable = &policy_vtable;
+ pc.verbose = verbose;
+ pc.chain = chain;
+ pc.chain_len = chain_len;
+ pc.cert_signer_algo = cert_signer_algo;
+ pc.sk = sk;
+ pc.cbhash = cbhash;
+ br_ssl_server_set_policy(&cc, &pc.vtable);
+
+ /*
+ * If trust anchors have been configured, then set an X.509
+ * validation engine and activate client certificate
+ * authentication.
+ */
+ if (VEC_LEN(anchors) != 0) {
+ br_x509_minimal_init(&xc, dnhash,
+ &VEC_ELT(anchors, 0), VEC_LEN(anchors));
+ for (u = 0; hash_functions[u].name; u ++) {
+ const br_hash_class *hc;
+ int id;
+
+ hc = hash_functions[u].hclass;
+ id = (hc->desc >> BR_HASHDESC_ID_OFF)
+ & BR_HASHDESC_ID_MASK;
+ if ((hfuns & ((unsigned)1 << id)) != 0) {
+ br_x509_minimal_set_hash(&xc, id, hc);
+ }
+ }
+ br_ssl_engine_set_default_rsavrfy(&cc.eng);
+ br_ssl_engine_set_default_ecdsa(&cc.eng);
+ br_x509_minimal_set_rsa(&xc, br_rsa_pkcs1_vrfy_get_default());
+ br_x509_minimal_set_ecdsa(&xc,
+ br_ec_get_default(), br_ecdsa_vrfy_asn1_get_default());
+ br_ssl_engine_set_x509(&cc.eng, &xc.vtable);
+ br_ssl_server_set_trust_anchor_names_alt(&cc,
+ &VEC_ELT(anchors, 0), VEC_LEN(anchors));
+ }
+
+ br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi);
+
+ /*
+ * On Unix systems, we need to ignore SIGPIPE.
+ */
+#ifndef _WIN32
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+ /*
+ * Open the server socket.
+ */
+ server_fd = host_bind(bind_name, port, verbose);
+ if (server_fd == INVALID_SOCKET) {
+ goto server_exit_error;
+ }
+
+ /*
+ * Process incoming clients, one at a time. Note that we do not
+ * accept any client until the previous connection has finished:
+ * this is voluntary, since the tool uses stdin/stdout for
+ * application data, and thus cannot really run two connections
+ * simultaneously.
+ */
+ for (;;) {
+ int x;
+ unsigned run_flags;
+
+ fd = accept_client(server_fd, verbose, 1);
+ if (fd == INVALID_SOCKET) {
+ goto server_exit_error;
+ }
+ br_ssl_server_reset(&cc);
+ run_flags = (verbose ? RUN_ENGINE_VERBOSE : 0)
+ | (trace ? RUN_ENGINE_TRACE : 0);
+ x = run_ssl_engine(&cc.eng, fd, run_flags);
+#ifdef _WIN32
+ closesocket(fd);
+#else
+ close(fd);
+#endif
+ fd = INVALID_SOCKET;
+ if (x < -1) {
+ goto server_exit_error;
+ }
+ }
+
+ /*
+ * Release allocated structures.
+ */
+server_exit:
+ xfree(suites);
+ xfree(suite_ids);
+ free_certificates(chain, chain_len);
+ free_private_key(sk);
+ VEC_CLEAREXT(anchors, &free_ta_contents);
+ VEC_CLEAREXT(alpn_names, &free_alpn);
+ xfree(iobuf);
+ xfree(cache);
+ if (fd != INVALID_SOCKET) {
+#ifdef _WIN32
+ closesocket(fd);
+#else
+ close(fd);
+#endif
+ }
+ if (server_fd != INVALID_SOCKET) {
+#ifdef _WIN32
+ closesocket(server_fd);
+#else
+ close(server_fd);
+#endif
+ }
+ return retcode;
+
+server_exit_error:
+ retcode = -1;
+ goto server_exit;
+}
diff --git a/contrib/bearssl/tools/skey.c b/contrib/bearssl/tools/skey.c
new file mode 100644
index 000000000000..90ecf636d61c
--- /dev/null
+++ b/contrib/bearssl/tools/skey.c
@@ -0,0 +1,784 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+#include "bearssl.h"
+
+typedef struct {
+ int print_text;
+ int print_C;
+ const char *rawder;
+ const char *rawpem;
+ const char *pk8der;
+ const char *pk8pem;
+} outspec;
+
+static void
+print_int_text(const char *name, const unsigned char *buf, size_t len)
+{
+ size_t u;
+
+ printf("%s = ", name);
+ for (u = 0; u < len; u ++) {
+ printf("%02X", buf[u]);
+ }
+ printf("\n");
+}
+
+static void
+print_int_C(const char *name, const unsigned char *buf, size_t len)
+{
+ size_t u;
+
+ printf("\nstatic const unsigned char %s[] = {", name);
+ for (u = 0; u < len; u ++) {
+ if (u != 0) {
+ printf(",");
+ }
+ if (u % 12 == 0) {
+ printf("\n\t");
+ } else {
+ printf(" ");
+ }
+ printf("0x%02X", buf[u]);
+ }
+ printf("\n};\n");
+}
+
+static int
+write_to_file(const char *name, const void *data, size_t len)
+{
+ FILE *f;
+
+ f = fopen(name, "wb");
+ if (f == NULL) {
+ fprintf(stderr,
+ "ERROR: cannot open file '%s' for writing\n",
+ name);
+ return 0;
+ }
+ if (fwrite(data, 1, len, f) != len) {
+ fclose(f);
+ fprintf(stderr,
+ "ERROR: cannot write to file '%s'\n",
+ name);
+ return 0;
+ }
+ fclose(f);
+ return 1;
+}
+
+static int
+write_to_pem_file(const char *name,
+ const void *data, size_t len, const char *banner)
+{
+ void *pem;
+ size_t pemlen;
+ int r;
+
+ pemlen = br_pem_encode(NULL, NULL, len, banner, 0);
+ pem = xmalloc(pemlen + 1);
+ br_pem_encode(pem, data, len, banner, 0);
+ r = write_to_file(name, pem, pemlen);
+ xfree(pem);
+ return r;
+}
+
+static int
+print_rsa(const br_rsa_private_key *sk, outspec *os)
+{
+ int ret;
+ unsigned char *n, *d, *buf;
+ uint32_t e;
+ size_t nlen, dlen, len;
+ br_rsa_compute_modulus cm;
+ br_rsa_compute_pubexp ce;
+ br_rsa_compute_privexp cd;
+ br_rsa_public_key pk;
+ unsigned char ebuf[4];
+
+ n = NULL;
+ d = NULL;
+ buf = NULL;
+ ret = 1;
+ if (os->print_text) {
+ print_int_text("p ", sk->p, sk->plen);
+ print_int_text("q ", sk->q, sk->qlen);
+ print_int_text("dp", sk->dp, sk->dplen);
+ print_int_text("dq", sk->dq, sk->dqlen);
+ print_int_text("iq", sk->iq, sk->iqlen);
+ }
+ if (os->print_C) {
+ print_int_C("RSA_P", sk->p, sk->plen);
+ print_int_C("RSA_Q", sk->q, sk->qlen);
+ print_int_C("RSA_DP", sk->dp, sk->dplen);
+ print_int_C("RSA_DQ", sk->dq, sk->dqlen);
+ print_int_C("RSA_IQ", sk->iq, sk->iqlen);
+ printf("\nstatic const br_rsa_private_key RSA = {\n");
+ printf("\t%lu,\n", (unsigned long)sk->n_bitlen);
+ printf("\t(unsigned char *)RSA_P, sizeof RSA_P,\n");
+ printf("\t(unsigned char *)RSA_Q, sizeof RSA_Q,\n");
+ printf("\t(unsigned char *)RSA_DP, sizeof RSA_DP,\n");
+ printf("\t(unsigned char *)RSA_DQ, sizeof RSA_DQ,\n");
+ printf("\t(unsigned char *)RSA_IQ, sizeof RSA_IQ\n");
+ printf("};\n");
+ }
+
+ if (os->rawder == NULL && os->rawpem == NULL
+ && os->pk8der == NULL && os->pk8pem == NULL)
+ {
+ return ret;
+ }
+
+ cm = br_rsa_compute_modulus_get_default();
+ ce = br_rsa_compute_pubexp_get_default();
+ cd = br_rsa_compute_privexp_get_default();
+ nlen = cm(NULL, sk);
+ if (nlen == 0) {
+ goto print_RSA_error;
+ }
+ n = xmalloc(nlen);
+ if (cm(n, sk) != nlen) {
+ goto print_RSA_error;
+ }
+ e = ce(sk);
+ if (e == 0) {
+ goto print_RSA_error;
+ }
+ dlen = cd(NULL, sk, e);
+ if (dlen == 0) {
+ goto print_RSA_error;
+ }
+ d = xmalloc(dlen);
+ if (cd(d, sk, e) != dlen) {
+ goto print_RSA_error;
+ }
+ ebuf[0] = e >> 24;
+ ebuf[1] = e >> 16;
+ ebuf[2] = e >> 8;
+ ebuf[3] = e;
+ pk.n = n;
+ pk.nlen = nlen;
+ pk.e = ebuf;
+ pk.elen = sizeof ebuf;
+
+ if (os->rawder != NULL || os->rawpem != NULL) {
+ len = br_encode_rsa_raw_der(NULL, sk, &pk, d, dlen);
+ if (len == 0) {
+ goto print_RSA_error;
+ }
+ buf = xmalloc(len);
+ if (br_encode_rsa_raw_der(buf, sk, &pk, d, dlen) != len) {
+ goto print_RSA_error;
+ }
+ if (os->rawder != NULL) {
+ ret &= write_to_file(os->rawder, buf, len);
+ }
+ if (os->rawpem != NULL) {
+ ret &= write_to_pem_file(os->rawpem,
+ buf, len, "RSA PRIVATE KEY");
+ }
+ xfree(buf);
+ buf = NULL;
+ }
+
+ if (os->pk8der != NULL || os->pk8pem != NULL) {
+ len = br_encode_rsa_pkcs8_der(NULL, sk, &pk, d, dlen);
+ if (len == 0) {
+ goto print_RSA_error;
+ }
+ buf = xmalloc(len);
+ if (br_encode_rsa_pkcs8_der(buf, sk, &pk, d, dlen) != len) {
+ goto print_RSA_error;
+ }
+ if (os->pk8der != NULL) {
+ ret &= write_to_file(os->pk8der, buf, len);
+ }
+ if (os->pk8pem != NULL) {
+ ret &= write_to_pem_file(os->pk8pem,
+ buf, len, "PRIVATE KEY");
+ }
+ xfree(buf);
+ buf = NULL;
+ }
+
+print_RSA_exit:
+ xfree(n);
+ xfree(d);
+ xfree(buf);
+ return ret;
+
+print_RSA_error:
+ fprintf(stderr, "ERROR: cannot encode RSA key\n");
+ ret = 0;
+ goto print_RSA_exit;
+}
+
+static int
+print_ec(const br_ec_private_key *sk, outspec *os)
+{
+ br_ec_public_key pk;
+ unsigned kbuf[BR_EC_KBUF_PUB_MAX_SIZE];
+ unsigned char *buf;
+ size_t len;
+ int r;
+
+ if (os->print_text) {
+ print_int_text("x", sk->x, sk->xlen);
+ }
+ if (os->print_C) {
+ print_int_C("EC_X", sk->x, sk->xlen);
+ printf("\nstatic const br_ec_private_key EC = {\n");
+ printf("\t%d,\n", sk->curve);
+ printf("\t(unsigned char *)EC_X, sizeof EC_X\n");
+ printf("};\n");
+ }
+
+ if (os->rawder == NULL && os->rawpem == NULL
+ && os->pk8der == NULL && os->pk8pem == NULL)
+ {
+ return 1;
+ }
+ if (br_ec_compute_pub(br_ec_get_default(), &pk, kbuf, sk) == 0) {
+ fprintf(stderr,
+ "ERROR: cannot re-encode (unsupported curve)\n");
+ return 0;
+ }
+
+ r = 1;
+ if (os->rawder != NULL || os->rawpem != NULL) {
+ len = br_encode_ec_raw_der(NULL, sk, &pk);
+ if (len == 0) {
+ fprintf(stderr, "ERROR: cannot re-encode"
+ " (unsupported curve)\n");
+ return 0;
+ }
+ buf = xmalloc(len);
+ if (br_encode_ec_raw_der(buf, sk, &pk) != len) {
+ fprintf(stderr, "ERROR: re-encode failure\n");
+ xfree(buf);
+ return 0;
+ }
+ if (os->rawder != NULL) {
+ r &= write_to_file(os->rawder, buf, len);
+ }
+ if (os->rawpem != NULL) {
+ r &= write_to_pem_file(os->rawpem,
+ buf, len, "EC PRIVATE KEY");
+ }
+ xfree(buf);
+ }
+ if (os->pk8der != NULL || os->pk8pem != NULL) {
+ len = br_encode_ec_pkcs8_der(NULL, sk, &pk);
+ if (len == 0) {
+ fprintf(stderr, "ERROR: cannot re-encode"
+ " (unsupported curve)\n");
+ return 0;
+ }
+ buf = xmalloc(len);
+ if (br_encode_ec_pkcs8_der(buf, sk, &pk) != len) {
+ fprintf(stderr, "ERROR: re-encode failure\n");
+ xfree(buf);
+ return 0;
+ }
+ if (os->pk8der != NULL) {
+ r &= write_to_file(os->pk8der, buf, len);
+ }
+ if (os->pk8pem != NULL) {
+ r &= write_to_pem_file(os->pk8pem,
+ buf, len, "PRIVATE KEY");
+ }
+ xfree(buf);
+ }
+ return r;
+}
+
+static int
+parse_rsa_spec(const char *kgen_spec, unsigned *size, uint32_t *pubexp)
+{
+ const char *p;
+ char *end;
+ unsigned long ul;
+
+ p = kgen_spec;
+ if (*p != 'r' && *p != 'R') {
+ return 0;
+ }
+ p ++;
+ if (*p != 's' && *p != 'S') {
+ return 0;
+ }
+ p ++;
+ if (*p != 'a' && *p != 'A') {
+ return 0;
+ }
+ p ++;
+ if (*p == 0) {
+ *size = 2048;
+ *pubexp = 3;
+ return 1;
+ } else if (*p != ':') {
+ return 0;
+ }
+ p ++;
+ ul = strtoul(p, &end, 10);
+ if (ul < 512 || ul > 32768) {
+ return 0;
+ }
+ *size = ul;
+ p = end;
+ if (*p == 0) {
+ *pubexp = 3;
+ return 1;
+ } else if (*p != ':') {
+ return 0;
+ }
+ p ++;
+ ul = strtoul(p, &end, 10);
+ if ((ul & 1) == 0 || ul == 1 || ((ul >> 30) >> 2) != 0) {
+ return 0;
+ }
+ *pubexp = ul;
+ if (*end != 0) {
+ return 0;
+ }
+ return 1;
+}
+
+static int
+keygen_rsa(unsigned size, uint32_t pubexp, outspec *os)
+{
+ br_hmac_drbg_context rng;
+ br_prng_seeder seeder;
+ br_rsa_keygen kg;
+ br_rsa_private_key sk;
+ unsigned char *kbuf_priv;
+ uint32_t r;
+
+ seeder = br_prng_seeder_system(NULL);
+ if (seeder == 0) {
+ fprintf(stderr, "ERROR: no system source of randomness\n");
+ return 0;
+ }
+ br_hmac_drbg_init(&rng, &br_sha256_vtable, NULL, 0);
+ if (!seeder(&rng.vtable)) {
+ fprintf(stderr, "ERROR: system source of randomness failed\n");
+ return 0;
+ }
+ kbuf_priv = xmalloc(BR_RSA_KBUF_PRIV_SIZE(size));
+ kg = br_rsa_keygen_get_default();
+ r = kg(&rng.vtable, &sk, kbuf_priv, NULL, NULL, size, pubexp);
+ if (!r) {
+ fprintf(stderr, "ERROR: RSA key pair generation failed\n");
+ } else {
+ r = print_rsa(&sk, os);
+ }
+ xfree(kbuf_priv);
+ return r;
+}
+
+static int
+parse_ec_spec(const char *kgen_spec, int *curve)
+{
+ const char *p;
+
+ *curve = 0;
+ p = kgen_spec;
+ if (*p != 'e' && *p != 'E') {
+ return 0;
+ }
+ p ++;
+ if (*p != 'c' && *p != 'C') {
+ return 0;
+ }
+ p ++;
+ if (*p == 0) {
+ *curve = BR_EC_secp256r1;
+ return 1;
+ }
+ if (*p != ':') {
+ return 0;
+ }
+ *curve = get_curve_by_name(p);
+ return *curve > 0;
+}
+
+static int
+keygen_ec(int curve, outspec *os)
+{
+ br_hmac_drbg_context rng;
+ br_prng_seeder seeder;
+ const br_ec_impl *impl;
+ br_ec_private_key sk;
+ unsigned char kbuf_priv[BR_EC_KBUF_PRIV_MAX_SIZE];
+ size_t len;
+
+ seeder = br_prng_seeder_system(NULL);
+ if (seeder == 0) {
+ fprintf(stderr, "ERROR: no system source of randomness\n");
+ return 0;
+ }
+ br_hmac_drbg_init(&rng, &br_sha256_vtable, NULL, 0);
+ if (!seeder(&rng.vtable)) {
+ fprintf(stderr, "ERROR: system source of randomness failed\n");
+ return 0;
+ }
+ impl = br_ec_get_default();
+ len = br_ec_keygen(&rng.vtable, impl, &sk, kbuf_priv, curve);
+ if (len == 0) {
+ fprintf(stderr, "ERROR: curve is not supported\n");
+ return 0;
+ }
+ return print_ec(&sk, os);
+}
+
+static int
+decode_key(const unsigned char *buf, size_t len, outspec *os)
+{
+ br_skey_decoder_context dc;
+ int err, ret;
+
+ br_skey_decoder_init(&dc);
+ br_skey_decoder_push(&dc, buf, len);
+ err = br_skey_decoder_last_error(&dc);
+ if (err != 0) {
+ const char *errname, *errmsg;
+
+ fprintf(stderr, "ERROR (decoding): err=%d\n", err);
+ errname = find_error_name(err, &errmsg);
+ if (errname != NULL) {
+ fprintf(stderr, " %s: %s\n", errname, errmsg);
+ } else {
+ fprintf(stderr, " (unknown)\n");
+ }
+ return 0;
+ }
+ ret = 1;
+ switch (br_skey_decoder_key_type(&dc)) {
+ const br_rsa_private_key *rk;
+ const br_ec_private_key *ek;
+
+ case BR_KEYTYPE_RSA:
+ rk = br_skey_decoder_get_rsa(&dc);
+ printf("RSA key (%lu bits)\n", (unsigned long)rk->n_bitlen);
+ ret = print_rsa(rk, os);
+ break;
+
+ case BR_KEYTYPE_EC:
+ ek = br_skey_decoder_get_ec(&dc);
+ printf("EC key (curve = %d: %s)\n",
+ ek->curve, ec_curve_name(ek->curve));
+ ret = print_ec(ek, os);
+ break;
+
+ default:
+ fprintf(stderr, "Unknown key type: %d\n",
+ br_skey_decoder_key_type(&dc));
+ ret = 0;
+ break;
+ }
+
+ return ret;
+}
+
+static void
+usage_skey(void)
+{
+ fprintf(stderr,
+"usage: brssl skey [ options ] file...\n");
+ fprintf(stderr,
+"options:\n");
+ fprintf(stderr,
+" -q suppress verbose messages\n");
+ fprintf(stderr,
+" -text print private key details (human-readable)\n");
+ fprintf(stderr,
+" -C print private key details (C code)\n");
+ fprintf(stderr,
+" -rawder file save private key in 'file' (raw format, DER)\n");
+ fprintf(stderr,
+" -rawpem file save private key in 'file' (raw format, PEM)\n");
+ fprintf(stderr,
+" -pk8der file save private key in 'file' (PKCS#8 format, DER)\n");
+ fprintf(stderr,
+" -pk8pem file save private key in 'file' (PKCS#8 format, PEM)\n");
+ fprintf(stderr,
+" -gen spec generate a new key using the provided key specification\n");
+ fprintf(stderr,
+" -list list known elliptic curve names\n");
+ fprintf(stderr,
+"Key specification begins with a key type, followed by optional parameters\n");
+ fprintf(stderr,
+"that depend on the key type, separated by colon characters:\n");
+ fprintf(stderr,
+" rsa[:size[:pubexep]] RSA key (defaults: size = 2048, pubexp = 3)\n");
+ fprintf(stderr,
+" ec[:curvename] EC key (default curve: secp256r1)\n");
+}
+
+/* see brssl.h */
+int
+do_skey(int argc, char *argv[])
+{
+ int retcode;
+ int verbose;
+ int i, num_files;
+ outspec os;
+ unsigned char *buf;
+ size_t len;
+ pem_object *pos;
+ const char *kgen_spec;
+
+ retcode = 0;
+ verbose = 1;
+ os.print_text = 0;
+ os.print_C = 0;
+ os.rawder = NULL;
+ os.rawpem = NULL;
+ os.pk8der = NULL;
+ os.pk8pem = NULL;
+ num_files = 0;
+ buf = NULL;
+ pos = NULL;
+ kgen_spec = NULL;
+ for (i = 0; i < argc; i ++) {
+ const char *arg;
+
+ arg = argv[i];
+ if (arg[0] != '-') {
+ num_files ++;
+ continue;
+ }
+ argv[i] = NULL;
+ if (eqstr(arg, "-v") || eqstr(arg, "-verbose")) {
+ verbose = 1;
+ } else if (eqstr(arg, "-q") || eqstr(arg, "-quiet")) {
+ verbose = 0;
+ } else if (eqstr(arg, "-text")) {
+ os.print_text = 1;
+ } else if (eqstr(arg, "-C")) {
+ os.print_C = 1;
+ } else if (eqstr(arg, "-rawder")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-rawder'\n");
+ usage_skey();
+ goto skey_exit_error;
+ }
+ if (os.rawder != NULL) {
+ fprintf(stderr,
+ "ERROR: multiple '-rawder' options\n");
+ usage_skey();
+ goto skey_exit_error;
+ }
+ os.rawder = argv[i];
+ argv[i] = NULL;
+ } else if (eqstr(arg, "-rawpem")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-rawpem'\n");
+ usage_skey();
+ goto skey_exit_error;
+ }
+ if (os.rawpem != NULL) {
+ fprintf(stderr,
+ "ERROR: multiple '-rawpem' options\n");
+ usage_skey();
+ goto skey_exit_error;
+ }
+ os.rawpem = argv[i];
+ argv[i] = NULL;
+ } else if (eqstr(arg, "-pk8der")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-pk8der'\n");
+ usage_skey();
+ goto skey_exit_error;
+ }
+ if (os.pk8der != NULL) {
+ fprintf(stderr,
+ "ERROR: multiple '-pk8der' options\n");
+ usage_skey();
+ goto skey_exit_error;
+ }
+ os.pk8der = argv[i];
+ argv[i] = NULL;
+ } else if (eqstr(arg, "-pk8pem")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-pk8pem'\n");
+ usage_skey();
+ goto skey_exit_error;
+ }
+ if (os.pk8pem != NULL) {
+ fprintf(stderr,
+ "ERROR: multiple '-pk8pem' options\n");
+ usage_skey();
+ goto skey_exit_error;
+ }
+ os.pk8pem = argv[i];
+ argv[i] = NULL;
+ } else if (eqstr(arg, "-gen")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-gen'\n");
+ usage_skey();
+ goto skey_exit_error;
+ }
+ if (kgen_spec != NULL) {
+ fprintf(stderr,
+ "ERROR: multiple '-gen' options\n");
+ usage_skey();
+ goto skey_exit_error;
+ }
+ kgen_spec = argv[i];
+ argv[i] = NULL;
+ } else if (eqstr(arg, "-list")) {
+ list_curves();
+ goto skey_exit;
+ } else {
+ fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
+ usage_skey();
+ goto skey_exit_error;
+ }
+ }
+ if (kgen_spec != NULL) {
+ unsigned rsa_size;
+ uint32_t rsa_pubexp;
+ int curve;
+
+ if (num_files != 0) {
+ fprintf(stderr,
+ "ERROR: key files provided while generating\n");
+ usage_skey();
+ goto skey_exit_error;
+ }
+
+ if (parse_rsa_spec(kgen_spec, &rsa_size, &rsa_pubexp)) {
+ if (!keygen_rsa(rsa_size, rsa_pubexp, &os)) {
+ goto skey_exit_error;
+ }
+ } else if (parse_ec_spec(kgen_spec, &curve)) {
+ if (!keygen_ec(curve, &os)) {
+ goto skey_exit_error;
+ }
+ } else {
+ fprintf(stderr,
+ "ERROR: unknown key specification: '%s'\n",
+ kgen_spec);
+ usage_skey();
+ goto skey_exit_error;
+ }
+ } else if (num_files == 0) {
+ fprintf(stderr, "ERROR: no private key provided\n");
+ usage_skey();
+ goto skey_exit_error;
+ }
+
+ for (i = 0; i < argc; i ++) {
+ const char *fname;
+
+ fname = argv[i];
+ if (fname == NULL) {
+ continue;
+ }
+ buf = read_file(fname, &len);
+ if (buf == NULL) {
+ goto skey_exit_error;
+ }
+ if (looks_like_DER(buf, len)) {
+ if (verbose) {
+ fprintf(stderr, "File '%s': ASN.1/DER object\n",
+ fname);
+ }
+ if (!decode_key(buf, len, &os)) {
+ goto skey_exit_error;
+ }
+ } else {
+ size_t u, num;
+
+ if (verbose) {
+ fprintf(stderr, "File '%s': decoding as PEM\n",
+ fname);
+ }
+ pos = decode_pem(buf, len, &num);
+ if (pos == NULL) {
+ goto skey_exit_error;
+ }
+ for (u = 0; pos[u].name; u ++) {
+ const char *name;
+
+ name = pos[u].name;
+ if (eqstr(name, "RSA PRIVATE KEY")
+ || eqstr(name, "EC PRIVATE KEY")
+ || eqstr(name, "PRIVATE KEY"))
+ {
+ if (!decode_key(pos[u].data,
+ pos[u].data_len, &os))
+ {
+ goto skey_exit_error;
+ }
+ } else {
+ if (verbose) {
+ fprintf(stderr,
+ "(skipping '%s')\n",
+ name);
+ }
+ }
+ }
+ for (u = 0; pos[u].name; u ++) {
+ free_pem_object_contents(&pos[u]);
+ }
+ xfree(pos);
+ pos = NULL;
+ }
+ xfree(buf);
+ buf = NULL;
+ }
+
+ /*
+ * Release allocated structures.
+ */
+skey_exit:
+ xfree(buf);
+ if (pos != NULL) {
+ size_t u;
+
+ for (u = 0; pos[u].name; u ++) {
+ free_pem_object_contents(&pos[u]);
+ }
+ xfree(pos);
+ }
+ return retcode;
+
+skey_exit_error:
+ retcode = -1;
+ goto skey_exit;
+}
diff --git a/contrib/bearssl/tools/sslio.c b/contrib/bearssl/tools/sslio.c
new file mode 100644
index 000000000000..ef7dd3f6765a
--- /dev/null
+++ b/contrib/bearssl/tools/sslio.c
@@ -0,0 +1,760 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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>
+
+#ifdef _WIN32
+#include <winsock2.h>
+#include <ws2tcpip.h>
+#else
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <poll.h>
+
+#define SOCKET int
+#define INVALID_SOCKET (-1)
+#endif
+
+#include "brssl.h"
+
+static void
+dump_blob(const char *name, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ size_t u;
+
+ buf = data;
+ fprintf(stderr, "%s (len = %lu)", name, (unsigned long)len);
+ for (u = 0; u < len; u ++) {
+ if ((u & 15) == 0) {
+ fprintf(stderr, "\n%08lX ", (unsigned long)u);
+ } else if ((u & 7) == 0) {
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, " %02x", buf[u]);
+ }
+ fprintf(stderr, "\n");
+}
+
+/*
+ * Inspect the provided data in case it is a "command" to trigger a
+ * special behaviour. If the command is recognised, then it is executed
+ * and this function returns 1. Otherwise, this function returns 0.
+ */
+static int
+run_command(br_ssl_engine_context *cc, unsigned char *buf, size_t len)
+{
+ /*
+ * A single static slot for saving session parameters.
+ */
+ static br_ssl_session_parameters slot;
+ static int slot_used = 0;
+
+ size_t u;
+
+ if (len < 2 || len > 3) {
+ return 0;
+ }
+ if (len == 3 && (buf[1] != '\r' || buf[2] != '\n')) {
+ return 0;
+ }
+ if (len == 2 && buf[1] != '\n') {
+ return 0;
+ }
+ switch (buf[0]) {
+ case 'Q':
+ fprintf(stderr, "closing...\n");
+ br_ssl_engine_close(cc);
+ return 1;
+ case 'R':
+ if (br_ssl_engine_renegotiate(cc)) {
+ fprintf(stderr, "renegotiating...\n");
+ } else {
+ fprintf(stderr, "not renegotiating.\n");
+ }
+ return 1;
+ case 'F':
+ /*
+ * Session forget is nominally client-only. But the
+ * session parameters are in the engine structure, which
+ * is the first field of the client context, so the cast
+ * still works properly. On the server, this forgetting
+ * has no effect.
+ */
+ fprintf(stderr, "forgetting session...\n");
+ br_ssl_client_forget_session((br_ssl_client_context *)cc);
+ return 1;
+ case 'S':
+ fprintf(stderr, "saving session parameters...\n");
+ br_ssl_engine_get_session_parameters(cc, &slot);
+ fprintf(stderr, " id = ");
+ for (u = 0; u < slot.session_id_len; u ++) {
+ fprintf(stderr, "%02X", slot.session_id[u]);
+ }
+ fprintf(stderr, "\n");
+ slot_used = 1;
+ return 1;
+ case 'P':
+ if (slot_used) {
+ fprintf(stderr, "restoring session parameters...\n");
+ fprintf(stderr, " id = ");
+ for (u = 0; u < slot.session_id_len; u ++) {
+ fprintf(stderr, "%02X", slot.session_id[u]);
+ }
+ fprintf(stderr, "\n");
+ br_ssl_engine_set_session_parameters(cc, &slot);
+ return 1;
+ }
+ return 0;
+ default:
+ return 0;
+ }
+}
+
+#ifdef _WIN32
+
+typedef struct {
+ unsigned char buf[1024];
+ size_t ptr, len;
+} in_buffer;
+
+static int
+in_return_bytes(in_buffer *bb, unsigned char *buf, size_t len)
+{
+ if (bb->ptr < bb->len) {
+ size_t clen;
+
+ if (buf == NULL) {
+ return 1;
+ }
+ clen = bb->len - bb->ptr;
+ if (clen > len) {
+ clen = len;
+ }
+ memcpy(buf, bb->buf + bb->ptr, clen);
+ bb->ptr += clen;
+ if (bb->ptr == bb->len) {
+ bb->ptr = bb->len = 0;
+ }
+ return (int)clen;
+ }
+ return 0;
+}
+
+/*
+ * A buffered version of in_read(), using a buffer to return only
+ * full lines when feasible.
+ */
+static int
+in_read_buffered(HANDLE h_in, in_buffer *bb, unsigned char *buf, size_t len)
+{
+ int n;
+
+ if (len == 0) {
+ return 0;
+ }
+ n = in_return_bytes(bb, buf, len);
+ if (n != 0) {
+ return n;
+ }
+ for (;;) {
+ INPUT_RECORD inrec;
+ DWORD v;
+
+ if (!PeekConsoleInput(h_in, &inrec, 1, &v)) {
+ fprintf(stderr, "ERROR: PeekConsoleInput()"
+ " failed with 0x%08lX\n",
+ (unsigned long)GetLastError());
+ return -1;
+ }
+ if (v == 0) {
+ return 0;
+ }
+ if (!ReadConsoleInput(h_in, &inrec, 1, &v)) {
+ fprintf(stderr, "ERROR: ReadConsoleInput()"
+ " failed with 0x%08lX\n",
+ (unsigned long)GetLastError());
+ return -1;
+ }
+ if (v == 0) {
+ return 0;
+ }
+ if (inrec.EventType == KEY_EVENT
+ && inrec.Event.KeyEvent.bKeyDown)
+ {
+ int c;
+
+ c = inrec.Event.KeyEvent.uChar.AsciiChar;
+ if (c == '\n' || c == '\r' || c == '\t'
+ || (c >= 32 && c != 127))
+ {
+ if (c == '\r') {
+ c = '\n';
+ }
+ bb->buf[bb->ptr ++] = (unsigned char)c;
+ printf("%c", c);
+ fflush(stdout);
+ bb->len = bb->ptr;
+ if (bb->len == sizeof bb->buf || c == '\n') {
+ bb->ptr = 0;
+ return in_return_bytes(bb, buf, len);
+ }
+ }
+ }
+ }
+}
+
+static int
+in_avail_buffered(HANDLE h_in, in_buffer *bb)
+{
+ return in_read_buffered(h_in, bb, NULL, 1);
+}
+
+#endif
+
+/* see brssl.h */
+int
+run_ssl_engine(br_ssl_engine_context *cc, unsigned long fd, unsigned flags)
+{
+ int hsdetails;
+ int retcode;
+ int verbose;
+ int trace;
+#ifdef _WIN32
+ WSAEVENT fd_event;
+ int can_send, can_recv;
+ HANDLE h_in, h_out;
+ in_buffer bb;
+#endif
+
+ hsdetails = 0;
+ retcode = 0;
+ verbose = (flags & RUN_ENGINE_VERBOSE) != 0;
+ trace = (flags & RUN_ENGINE_TRACE) != 0;
+
+ /*
+ * Print algorithm details.
+ */
+ if (verbose) {
+ const char *rngname;
+
+ fprintf(stderr, "Algorithms:\n");
+ br_prng_seeder_system(&rngname);
+ fprintf(stderr, " RNG: %s\n", rngname);
+ if (cc->iaes_cbcenc != 0) {
+ fprintf(stderr, " AES/CBC (enc): %s\n",
+ get_algo_name(cc->iaes_cbcenc, 0));
+ }
+ if (cc->iaes_cbcdec != 0) {
+ fprintf(stderr, " AES/CBC (dec): %s\n",
+ get_algo_name(cc->iaes_cbcdec, 0));
+ }
+ if (cc->iaes_ctr != 0) {
+ fprintf(stderr, " AES/CTR: %s\n",
+ get_algo_name(cc->iaes_cbcdec, 0));
+ }
+ if (cc->iaes_ctrcbc != 0) {
+ fprintf(stderr, " AES/CCM: %s\n",
+ get_algo_name(cc->iaes_ctrcbc, 0));
+ }
+ if (cc->ides_cbcenc != 0) {
+ fprintf(stderr, " DES/CBC (enc): %s\n",
+ get_algo_name(cc->ides_cbcenc, 0));
+ }
+ if (cc->ides_cbcdec != 0) {
+ fprintf(stderr, " DES/CBC (dec): %s\n",
+ get_algo_name(cc->ides_cbcdec, 0));
+ }
+ if (cc->ighash != 0) {
+ fprintf(stderr, " GHASH (GCM): %s\n",
+ get_algo_name(cc->ighash, 0));
+ }
+ if (cc->ichacha != 0) {
+ fprintf(stderr, " ChaCha20: %s\n",
+ get_algo_name(cc->ichacha, 0));
+ }
+ if (cc->ipoly != 0) {
+ fprintf(stderr, " Poly1305: %s\n",
+ get_algo_name(cc->ipoly, 0));
+ }
+ if (cc->iec != 0) {
+ fprintf(stderr, " EC: %s\n",
+ get_algo_name(cc->iec, 0));
+ }
+ if (cc->iecdsa != 0) {
+ fprintf(stderr, " ECDSA: %s\n",
+ get_algo_name(cc->iecdsa, 0));
+ }
+ if (cc->irsavrfy != 0) {
+ fprintf(stderr, " RSA (vrfy): %s\n",
+ get_algo_name(cc->irsavrfy, 0));
+ }
+ }
+
+#ifdef _WIN32
+ fd_event = WSA_INVALID_EVENT;
+ can_send = 0;
+ can_recv = 0;
+ bb.ptr = bb.len = 0;
+#endif
+
+ /*
+ * On Unix systems, we need to follow three descriptors:
+ * standard input (0), standard output (1), and the socket
+ * itself (for both read and write). This is done with a poll()
+ * call.
+ *
+ * On Windows systems, we use WSAEventSelect() to associate
+ * an event handle with the network activity, and we use
+ * WaitForMultipleObjectsEx() on that handle and the standard
+ * input handle, when appropriate. Standard output is assumed
+ * to be always writeable, and standard input to be the console;
+ * this does not work well (or at all) with redirections (to
+ * pipes or files) but it should be enough for a debug tool
+ * (TODO: make something that handles redirections as well).
+ */
+
+#ifdef _WIN32
+ fd_event = WSACreateEvent();
+ if (fd_event == WSA_INVALID_EVENT) {
+ fprintf(stderr, "ERROR: WSACreateEvent() failed with %d\n",
+ WSAGetLastError());
+ retcode = -2;
+ goto engine_exit;
+ }
+ WSAEventSelect(fd, fd_event, FD_READ | FD_WRITE | FD_CLOSE);
+ h_in = GetStdHandle(STD_INPUT_HANDLE);
+ h_out = GetStdHandle(STD_OUTPUT_HANDLE);
+ SetConsoleMode(h_in, ENABLE_ECHO_INPUT
+ | ENABLE_LINE_INPUT
+ | ENABLE_PROCESSED_INPUT
+ | ENABLE_PROCESSED_OUTPUT
+ | ENABLE_WRAP_AT_EOL_OUTPUT);
+#else
+ /*
+ * Make sure that stdin and stdout are non-blocking.
+ */
+ fcntl(0, F_SETFL, O_NONBLOCK);
+ fcntl(1, F_SETFL, O_NONBLOCK);
+#endif
+
+ /*
+ * Perform the loop.
+ */
+ for (;;) {
+ unsigned st;
+ int sendrec, recvrec, sendapp, recvapp;
+#ifdef _WIN32
+ HANDLE pfd[2];
+ DWORD wt;
+#else
+ struct pollfd pfd[3];
+ int n;
+#endif
+ size_t u, k_fd, k_in, k_out;
+ int sendrec_ok, recvrec_ok, sendapp_ok, recvapp_ok;
+
+ /*
+ * Get current engine state.
+ */
+ st = br_ssl_engine_current_state(cc);
+ if (st == BR_SSL_CLOSED) {
+ int err;
+
+ err = br_ssl_engine_last_error(cc);
+ if (err == BR_ERR_OK) {
+ if (verbose) {
+ fprintf(stderr,
+ "SSL closed normally\n");
+ }
+ retcode = 0;
+ goto engine_exit;
+ } else {
+ fprintf(stderr, "ERROR: SSL error %d", err);
+ retcode = err;
+ if (err >= BR_ERR_SEND_FATAL_ALERT) {
+ err -= BR_ERR_SEND_FATAL_ALERT;
+ fprintf(stderr,
+ " (sent alert %d)\n", err);
+ } else if (err >= BR_ERR_RECV_FATAL_ALERT) {
+ err -= BR_ERR_RECV_FATAL_ALERT;
+ fprintf(stderr,
+ " (received alert %d)\n", err);
+ } else {
+ const char *ename;
+
+ ename = find_error_name(err, NULL);
+ if (ename == NULL) {
+ ename = "unknown";
+ }
+ fprintf(stderr, " (%s)\n", ename);
+ }
+ goto engine_exit;
+ }
+ }
+
+ /*
+ * Compute descriptors that must be polled, depending
+ * on engine state.
+ */
+ sendrec = ((st & BR_SSL_SENDREC) != 0);
+ recvrec = ((st & BR_SSL_RECVREC) != 0);
+ sendapp = ((st & BR_SSL_SENDAPP) != 0);
+ recvapp = ((st & BR_SSL_RECVAPP) != 0);
+ if (verbose && sendapp && !hsdetails) {
+ char csn[80];
+ const char *pname;
+
+ fprintf(stderr, "Handshake completed\n");
+ fprintf(stderr, " version: ");
+ switch (cc->session.version) {
+ case BR_SSL30:
+ fprintf(stderr, "SSL 3.0");
+ break;
+ case BR_TLS10:
+ fprintf(stderr, "TLS 1.0");
+ break;
+ case BR_TLS11:
+ fprintf(stderr, "TLS 1.1");
+ break;
+ case BR_TLS12:
+ fprintf(stderr, "TLS 1.2");
+ break;
+ default:
+ fprintf(stderr, "unknown (0x%04X)",
+ (unsigned)cc->session.version);
+ break;
+ }
+ fprintf(stderr, "\n");
+ get_suite_name_ext(
+ cc->session.cipher_suite, csn, sizeof csn);
+ fprintf(stderr, " cipher suite: %s\n", csn);
+ if (uses_ecdhe(cc->session.cipher_suite)) {
+ get_curve_name_ext(
+ br_ssl_engine_get_ecdhe_curve(cc),
+ csn, sizeof csn);
+ fprintf(stderr,
+ " ECDHE curve: %s\n", csn);
+ }
+ fprintf(stderr, " secure renegotiation: %s\n",
+ cc->reneg == 1 ? "no" : "yes");
+ pname = br_ssl_engine_get_selected_protocol(cc);
+ if (pname != NULL) {
+ fprintf(stderr,
+ " protocol name (ALPN): %s\n",
+ pname);
+ }
+ hsdetails = 1;
+ }
+
+ k_fd = (size_t)-1;
+ k_in = (size_t)-1;
+ k_out = (size_t)-1;
+
+ u = 0;
+#ifdef _WIN32
+ /*
+ * If we recorded that we can send or receive data, and we
+ * want to do exactly that, then we don't wait; we just do
+ * it.
+ */
+ recvapp_ok = 0;
+ sendrec_ok = 0;
+ recvrec_ok = 0;
+ sendapp_ok = 0;
+
+ if (sendrec && can_send) {
+ sendrec_ok = 1;
+ } else if (recvrec && can_recv) {
+ recvrec_ok = 1;
+ } else if (recvapp) {
+ recvapp_ok = 1;
+ } else if (sendapp && in_avail_buffered(h_in, &bb)) {
+ sendapp_ok = 1;
+ } else {
+ /*
+ * If we cannot do I/O right away, then we must
+ * wait for some event, and try again.
+ */
+ pfd[u] = (HANDLE)fd_event;
+ k_fd = u;
+ u ++;
+ if (sendapp) {
+ pfd[u] = h_in;
+ k_in = u;
+ u ++;
+ }
+ wt = WaitForMultipleObjectsEx(u, pfd,
+ FALSE, INFINITE, FALSE);
+ if (wt == WAIT_FAILED) {
+ fprintf(stderr, "ERROR:"
+ " WaitForMultipleObjectsEx()"
+ " failed with 0x%08lX",
+ (unsigned long)GetLastError());
+ retcode = -2;
+ goto engine_exit;
+ }
+ if (wt == k_fd) {
+ WSANETWORKEVENTS e;
+
+ if (WSAEnumNetworkEvents(fd, fd_event, &e)) {
+ fprintf(stderr, "ERROR:"
+ " WSAEnumNetworkEvents()"
+ " failed with %d\n",
+ WSAGetLastError());
+ retcode = -2;
+ goto engine_exit;
+ }
+ if (e.lNetworkEvents & (FD_WRITE | FD_CLOSE)) {
+ can_send = 1;
+ }
+ if (e.lNetworkEvents & (FD_READ | FD_CLOSE)) {
+ can_recv = 1;
+ }
+ }
+ continue;
+ }
+#else
+ if (sendrec || recvrec) {
+ pfd[u].fd = fd;
+ pfd[u].revents = 0;
+ pfd[u].events = 0;
+ if (sendrec) {
+ pfd[u].events |= POLLOUT;
+ }
+ if (recvrec) {
+ pfd[u].events |= POLLIN;
+ }
+ k_fd = u;
+ u ++;
+ }
+ if (sendapp) {
+ pfd[u].fd = 0;
+ pfd[u].revents = 0;
+ pfd[u].events = POLLIN;
+ k_in = u;
+ u ++;
+ }
+ if (recvapp) {
+ pfd[u].fd = 1;
+ pfd[u].revents = 0;
+ pfd[u].events = POLLOUT;
+ k_out = u;
+ u ++;
+ }
+ n = poll(pfd, u, -1);
+ if (n < 0) {
+ if (errno == EINTR) {
+ continue;
+ }
+ perror("ERROR: poll()");
+ retcode = -2;
+ goto engine_exit;
+ }
+ if (n == 0) {
+ continue;
+ }
+
+ /*
+ * We transform closures/errors into read+write accesses
+ * so as to force the read() or write() call that will
+ * detect the situation.
+ */
+ while (u -- > 0) {
+ if (pfd[u].revents & (POLLERR | POLLHUP)) {
+ pfd[u].revents |= POLLIN | POLLOUT;
+ }
+ }
+
+ recvapp_ok = recvapp && (pfd[k_out].revents & POLLOUT) != 0;
+ sendrec_ok = sendrec && (pfd[k_fd].revents & POLLOUT) != 0;
+ recvrec_ok = recvrec && (pfd[k_fd].revents & POLLIN) != 0;
+ sendapp_ok = sendapp && (pfd[k_in].revents & POLLIN) != 0;
+#endif
+
+ /*
+ * We give preference to outgoing data, on stdout and on
+ * the socket.
+ */
+ if (recvapp_ok) {
+ unsigned char *buf;
+ size_t len;
+#ifdef _WIN32
+ DWORD wlen;
+#else
+ ssize_t wlen;
+#endif
+
+ buf = br_ssl_engine_recvapp_buf(cc, &len);
+#ifdef _WIN32
+ if (!WriteFile(h_out, buf, len, &wlen, NULL)) {
+ if (verbose) {
+ fprintf(stderr, "stdout closed...\n");
+ }
+ retcode = -2;
+ goto engine_exit;
+ }
+#else
+ wlen = write(1, buf, len);
+ if (wlen <= 0) {
+ if (verbose) {
+ fprintf(stderr, "stdout closed...\n");
+ }
+ retcode = -2;
+ goto engine_exit;
+ }
+#endif
+ br_ssl_engine_recvapp_ack(cc, wlen);
+ continue;
+ }
+ if (sendrec_ok) {
+ unsigned char *buf;
+ size_t len;
+ int wlen;
+
+ buf = br_ssl_engine_sendrec_buf(cc, &len);
+ wlen = send(fd, buf, len, 0);
+ if (wlen <= 0) {
+#ifdef _WIN32
+ int err;
+
+ err = WSAGetLastError();
+ if (err == EWOULDBLOCK
+ || err == WSAEWOULDBLOCK)
+ {
+ can_send = 0;
+ continue;
+ }
+#else
+ if (errno == EINTR || errno == EWOULDBLOCK) {
+ continue;
+ }
+#endif
+ if (verbose) {
+ fprintf(stderr, "socket closed...\n");
+ }
+ retcode = -1;
+ goto engine_exit;
+ }
+ if (trace) {
+ dump_blob("Outgoing bytes", buf, wlen);
+ }
+ br_ssl_engine_sendrec_ack(cc, wlen);
+ continue;
+ }
+ if (recvrec_ok) {
+ unsigned char *buf;
+ size_t len;
+ int rlen;
+
+ buf = br_ssl_engine_recvrec_buf(cc, &len);
+ rlen = recv(fd, buf, len, 0);
+ if (rlen == 0) {
+ if (verbose) {
+ fprintf(stderr, "socket closed...\n");
+ }
+ retcode = -1;
+ goto engine_exit;
+ }
+ if (rlen < 0) {
+#ifdef _WIN32
+ int err;
+
+ err = WSAGetLastError();
+ if (err == EWOULDBLOCK
+ || err == WSAEWOULDBLOCK)
+ {
+ can_recv = 0;
+ continue;
+ }
+#else
+ if (errno == EINTR || errno == EWOULDBLOCK) {
+ continue;
+ }
+#endif
+ if (verbose) {
+ fprintf(stderr, "socket broke...\n");
+ }
+ retcode = -1;
+ goto engine_exit;
+ }
+ if (trace) {
+ dump_blob("Incoming bytes", buf, rlen);
+ }
+ br_ssl_engine_recvrec_ack(cc, rlen);
+ continue;
+ }
+ if (sendapp_ok) {
+ unsigned char *buf;
+ size_t len;
+#ifdef _WIN32
+ int rlen;
+#else
+ ssize_t rlen;
+#endif
+
+ buf = br_ssl_engine_sendapp_buf(cc, &len);
+#ifdef _WIN32
+ rlen = in_read_buffered(h_in, &bb, buf, len);
+#else
+ rlen = read(0, buf, len);
+#endif
+ if (rlen <= 0) {
+ if (verbose) {
+ fprintf(stderr, "stdin closed...\n");
+ }
+ br_ssl_engine_close(cc);
+ } else if (!run_command(cc, buf, rlen)) {
+ br_ssl_engine_sendapp_ack(cc, rlen);
+ }
+ br_ssl_engine_flush(cc, 0);
+ continue;
+ }
+
+ /* We should never reach that point. */
+ fprintf(stderr, "ERROR: poll() misbehaves\n");
+ retcode = -2;
+ goto engine_exit;
+ }
+
+ /*
+ * Release allocated structures.
+ */
+engine_exit:
+#ifdef _WIN32
+ if (fd_event != WSA_INVALID_EVENT) {
+ WSACloseEvent(fd_event);
+ }
+#endif
+ return retcode;
+}
diff --git a/contrib/bearssl/tools/ta.c b/contrib/bearssl/tools/ta.c
new file mode 100644
index 000000000000..df72e2bf57ce
--- /dev/null
+++ b/contrib/bearssl/tools/ta.c
@@ -0,0 +1,254 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+#include "bearssl.h"
+
+static const char *
+curve_to_sym(int curve)
+{
+ switch (curve) {
+ case BR_EC_sect163k1: return "BR_EC_sect163k1";
+ case BR_EC_sect163r1: return "BR_EC_sect163r1";
+ case BR_EC_sect163r2: return "BR_EC_sect163r2";
+ case BR_EC_sect193r1: return "BR_EC_sect193r1";
+ case BR_EC_sect193r2: return "BR_EC_sect193r2";
+ case BR_EC_sect233k1: return "BR_EC_sect233k1";
+ case BR_EC_sect233r1: return "BR_EC_sect233r1";
+ case BR_EC_sect239k1: return "BR_EC_sect239k1";
+ case BR_EC_sect283k1: return "BR_EC_sect283k1";
+ case BR_EC_sect283r1: return "BR_EC_sect283r1";
+ case BR_EC_sect409k1: return "BR_EC_sect409k1";
+ case BR_EC_sect409r1: return "BR_EC_sect409r1";
+ case BR_EC_sect571k1: return "BR_EC_sect571k1";
+ case BR_EC_sect571r1: return "BR_EC_sect571r1";
+ case BR_EC_secp160k1: return "BR_EC_secp160k1";
+ case BR_EC_secp160r1: return "BR_EC_secp160r1";
+ case BR_EC_secp160r2: return "BR_EC_secp160r2";
+ case BR_EC_secp192k1: return "BR_EC_secp192k1";
+ case BR_EC_secp192r1: return "BR_EC_secp192r1";
+ case BR_EC_secp224k1: return "BR_EC_secp224k1";
+ case BR_EC_secp224r1: return "BR_EC_secp224r1";
+ case BR_EC_secp256k1: return "BR_EC_secp256k1";
+ case BR_EC_secp256r1: return "BR_EC_secp256r1";
+ case BR_EC_secp384r1: return "BR_EC_secp384r1";
+ case BR_EC_secp521r1: return "BR_EC_secp521r1";
+ case BR_EC_brainpoolP256r1: return "BR_EC_brainpoolP256r1";
+ case BR_EC_brainpoolP384r1: return "BR_EC_brainpoolP384r1";
+ case BR_EC_brainpoolP512r1: return "BR_EC_brainpoolP512r1";
+ }
+ return NULL;
+}
+
+static void
+print_blob(const char *name, const unsigned char *buf, size_t len)
+{
+ size_t u;
+
+ printf("\nstatic const unsigned char %s[] = {", name);
+ for (u = 0; u < len; u ++) {
+ if (u != 0) {
+ printf(",");
+ }
+ if (u % 12 == 0) {
+ printf("\n\t");
+ } else {
+ printf(" ");
+ }
+ printf("0x%02X", buf[u]);
+ }
+ printf("\n};\n");
+}
+
+static int
+print_ta_internals(br_x509_trust_anchor *ta, long ctr)
+{
+ char tmp[25];
+
+ sprintf(tmp, "TA%ld_DN", ctr);
+ print_blob(tmp, ta->dn.data, ta->dn.len);
+ switch (ta->pkey.key_type) {
+ case BR_KEYTYPE_RSA:
+ sprintf(tmp, "TA%ld_RSA_N", ctr);
+ print_blob(tmp, ta->pkey.key.rsa.n, ta->pkey.key.rsa.nlen);
+ sprintf(tmp, "TA%ld_RSA_E", ctr);
+ print_blob(tmp, ta->pkey.key.rsa.e, ta->pkey.key.rsa.elen);
+ break;
+ case BR_KEYTYPE_EC:
+ sprintf(tmp, "TA%ld_EC_Q", ctr);
+ print_blob(tmp, ta->pkey.key.ec.q, ta->pkey.key.ec.qlen);
+ break;
+ default:
+ fprintf(stderr, "ERROR: unknown anchor key type '%d'\n",
+ ta->pkey.key_type);
+ return -1;
+ }
+ return 0;
+}
+
+static void
+print_ta(br_x509_trust_anchor *ta, long ctr)
+{
+ char tmp[25];
+
+ printf("\t{\n");
+ printf("\t\t{ (unsigned char *)TA%ld_DN, sizeof TA%ld_DN },\n",
+ ctr, ctr);
+ printf("\t\t%s,\n", (ta->flags & BR_X509_TA_CA)
+ ? "BR_X509_TA_CA" : "0");
+ printf("\t\t{\n");
+ switch (ta->pkey.key_type) {
+ const char *cname;
+
+ case BR_KEYTYPE_RSA:
+ printf("\t\t\tBR_KEYTYPE_RSA,\n");
+ printf("\t\t\t{ .rsa = {\n");
+ printf("\t\t\t\t(unsigned char *)TA%ld_RSA_N,"
+ " sizeof TA%ld_RSA_N,\n", ctr, ctr);
+ printf("\t\t\t\t(unsigned char *)TA%ld_RSA_E,"
+ " sizeof TA%ld_RSA_E,\n", ctr, ctr);
+ printf("\t\t\t} }\n");
+ break;
+ case BR_KEYTYPE_EC:
+ printf("\t\t\tBR_KEYTYPE_EC,\n");
+ printf("\t\t\t{ .ec = {\n");
+ cname = curve_to_sym(ta->pkey.key.ec.curve);
+ if (cname == NULL) {
+ sprintf(tmp, "%d", ta->pkey.key.ec.curve);
+ cname = tmp;
+ }
+ printf("\t\t\t\t%s,\n", cname);
+ printf("\t\t\t\t(unsigned char *)TA%ld_EC_Q,"
+ " sizeof TA%ld_EC_Q,\n", ctr, ctr);
+ printf("\t\t\t} }\n");
+ }
+ printf("\t\t}\n");
+ printf("\t}");
+}
+
+static void
+usage_ta(void)
+{
+ fprintf(stderr,
+"usage: brssl ta [ options ] file...\n");
+ fprintf(stderr,
+"options:\n");
+ fprintf(stderr,
+" -q suppress verbose messages\n");
+}
+
+/* see brssl.h */
+int
+do_ta(int argc, char *argv[])
+{
+ int retcode;
+ int verbose;
+ int i, num_files;
+ anchor_list tas = VEC_INIT;
+ size_t u, num;
+
+ retcode = 0;
+ verbose = 1;
+ num_files = 0;
+ for (i = 0; i < argc; i ++) {
+ const char *arg;
+
+ arg = argv[i];
+ if (arg[0] != '-') {
+ num_files ++;
+ continue;
+ }
+ argv[i] = NULL;
+ if (eqstr(arg, "-v") || eqstr(arg, "-verbose")) {
+ verbose = 1;
+ } else if (eqstr(arg, "-q") || eqstr(arg, "-quiet")) {
+ verbose = 0;
+ } else {
+ fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
+ usage_ta();
+ goto ta_exit_error;
+ }
+ }
+ if (num_files == 0) {
+ fprintf(stderr, "ERROR: no certificate file provided\n");
+ usage_ta();
+ goto ta_exit_error;
+ }
+
+ for (i = 0; i < argc; i ++) {
+ const char *fname;
+ size_t len1, len2;
+
+ fname = argv[i];
+ if (fname == NULL) {
+ continue;
+ }
+ if (verbose) {
+ fprintf(stderr, "Reading file '%s': ", fname);
+ fflush(stderr);
+ }
+ len1 = VEC_LEN(tas);
+ if (read_trust_anchors(&tas, fname) == 0) {
+ goto ta_exit_error;
+ }
+ len2 = VEC_LEN(tas) - len1;
+ if (verbose) {
+ fprintf(stderr, "%lu trust anchor%s\n",
+ (unsigned long)len2, len2 > 1 ? "s" : "");
+ }
+ }
+ num = VEC_LEN(tas);
+ for (u = 0; u < num; u ++) {
+ if (print_ta_internals(&VEC_ELT(tas, u), u) < 0) {
+ goto ta_exit_error;
+ }
+ }
+ printf("\nstatic const br_x509_trust_anchor TAs[%ld] = {", (long)num);
+ for (u = 0; u < num; u ++) {
+ if (u != 0) {
+ printf(",");
+ }
+ printf("\n");
+ print_ta(&VEC_ELT(tas, u), u);
+ }
+ printf("\n};\n");
+ printf("\n#define TAs_NUM %ld\n", (long)num);
+
+ /*
+ * Release allocated structures.
+ */
+ta_exit:
+ VEC_CLEAREXT(tas, free_ta_contents);
+ return retcode;
+
+ta_exit_error:
+ retcode = -1;
+ goto ta_exit;
+}
diff --git a/contrib/bearssl/tools/twrch.c b/contrib/bearssl/tools/twrch.c
new file mode 100644
index 000000000000..9cce03e504cc
--- /dev/null
+++ b/contrib/bearssl/tools/twrch.c
@@ -0,0 +1,1069 @@
+/*
+ * Copyright (c) 2017 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION 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>
+
+#ifdef _WIN32
+#include <windows.h>
+#else
+#include <signal.h>
+#include <sys/types.h>
+#include <unistd.h>
+#endif
+
+#include "brssl.h"
+
+static int verbose = 0;
+
+static void
+usage_twrch(void)
+{
+ fprintf(stderr,
+"usage: brssl twrch [ options ]\n");
+ fprintf(stderr,
+"options:\n");
+ fprintf(stderr,
+" -trace dump all packets on stderr\n");
+ fprintf(stderr,
+" -v verbose error messages on stderr\n");
+ fprintf(stderr,
+" -server act as an SSL server\n");
+ fprintf(stderr,
+" -client act as an SSL client\n");
+ fprintf(stderr,
+" -sni name use specified name for SNI\n");
+ fprintf(stderr,
+" -mono use monodirectional buffering\n");
+ fprintf(stderr,
+" -buf length set the I/O buffer length (in bytes)\n");
+ fprintf(stderr,
+" -cache length set the session cache storage length (in bytes)\n");
+ fprintf(stderr,
+" -cert fname read certificate chain from file 'fname'\n");
+ fprintf(stderr,
+" -key fname read private key from file 'fname'\n");
+ fprintf(stderr,
+" -CA file add trust anchors from 'file' (for peer auth)\n");
+ fprintf(stderr,
+" -anon_ok request but do not require a client certificate\n");
+ fprintf(stderr,
+" -nostaticecdh prohibit full-static ECDH (client only)\n");
+ fprintf(stderr,
+" -list list supported names (protocols, algorithms...)\n");
+ fprintf(stderr,
+" -vmin name set minimum supported version (default: TLS-1.0)\n");
+ fprintf(stderr,
+" -vmax name set maximum supported version (default: TLS-1.2)\n");
+ fprintf(stderr,
+" -cs names set list of supported cipher suites (comma-separated)\n");
+ fprintf(stderr,
+" -hf names add support for some hash functions (comma-separated)\n");
+ fprintf(stderr,
+" -minhello len set minimum ClientHello length (in bytes)\n");
+ fprintf(stderr,
+" -serverpref enforce server's preferences for cipher suites\n");
+ fprintf(stderr,
+" -noreneg prohibit renegotiations\n");
+ fprintf(stderr,
+" -alpn name add protocol name to list of protocols (ALPN extension)\n");
+ fprintf(stderr,
+" -strictalpn fail on ALPN mismatch\n");
+}
+
+static void
+free_alpn(void *alpn)
+{
+ xfree(*(char **)alpn);
+}
+
+static void
+dump_blob(const char *name, const void *data, size_t len)
+{
+ const unsigned char *buf;
+ size_t u;
+
+ buf = data;
+ fprintf(stderr, "%s (len = %lu)", name, (unsigned long)len);
+ for (u = 0; u < len; u ++) {
+ if ((u & 15) == 0) {
+ fprintf(stderr, "\n%08lX ", (unsigned long)u);
+ } else if ((u & 7) == 0) {
+ fprintf(stderr, " ");
+ }
+ fprintf(stderr, " %02x", buf[u]);
+ }
+ fprintf(stderr, "\n");
+}
+
+/*
+ * Callback for reading bytes from standard input.
+ */
+static int
+stdin_read(void *ctx, unsigned char *buf, size_t len)
+{
+ for (;;) {
+#ifdef _WIN32
+ DWORD rlen;
+#else
+ ssize_t rlen;
+#endif
+ int eof;
+
+#ifdef _WIN32
+ eof = !ReadFile(GetStdHandle(STD_INPUT_HANDLE),
+ buf, len, &rlen, NULL) || rlen == 0;
+#else
+ rlen = read(0, buf, len);
+ if (rlen <= 0) {
+ if (rlen < 0 && errno == EINTR) {
+ continue;
+ }
+ eof = 1;
+ } else {
+ eof = 0;
+ }
+#endif
+ if (eof) {
+ if (*(int *)ctx) {
+ if (verbose) {
+ fprintf(stderr, "recv: EOF\n");
+ }
+ }
+ return -1;
+ }
+ if (*(int *)ctx) {
+ dump_blob("recv", buf, (size_t)rlen);
+ }
+ return (int)rlen;
+ }
+}
+
+/*
+ * Callback for writing bytes on standard output.
+ */
+static int
+stdout_write(void *ctx, const unsigned char *buf, size_t len)
+{
+ for (;;) {
+#ifdef _WIN32
+ DWORD wlen;
+#else
+ ssize_t wlen;
+#endif
+ int eof;
+
+#ifdef _WIN32
+ eof = !WriteFile(GetStdHandle(STD_OUTPUT_HANDLE),
+ buf, len, &wlen, NULL);
+#else
+ wlen = write(1, buf, len);
+ if (wlen <= 0) {
+ if (wlen < 0 && errno == EINTR) {
+ continue;
+ }
+ eof = 1;
+ } else {
+ eof = 0;
+ }
+#endif
+ if (eof) {
+ if (*(int *)ctx) {
+ if (verbose) {
+ fprintf(stderr, "send: EOF\n");
+ }
+ }
+ return -1;
+ }
+ if (*(int *)ctx) {
+ dump_blob("send", buf, (size_t)wlen);
+ }
+ return (int)wlen;
+ }
+}
+
+static void
+print_error(int err)
+{
+ const char *name, *comment;
+
+ name = find_error_name(err, &comment);
+ if (name != NULL) {
+ fprintf(stderr, "ERR %d: %s\n %s\n", err, name, comment);
+ return;
+ }
+ if (err >= BR_ERR_RECV_FATAL_ALERT
+ && err < BR_ERR_RECV_FATAL_ALERT + 256)
+ {
+ fprintf(stderr, "ERR %d: received fatal alert %d\n",
+ err, err - BR_ERR_RECV_FATAL_ALERT);
+ return;
+ }
+ if (err >= BR_ERR_SEND_FATAL_ALERT
+ && err < BR_ERR_SEND_FATAL_ALERT + 256)
+ {
+ fprintf(stderr, "ERR %d: sent fatal alert %d\n",
+ err, err - BR_ERR_SEND_FATAL_ALERT);
+ return;
+ }
+ fprintf(stderr, "ERR %d: UNKNOWN\n", err);
+}
+
+/* see brssl.h */
+int
+do_twrch(int argc, char *argv[])
+{
+ int retcode;
+ int trace;
+ int is_client;
+ int is_server;
+ const char *sni;
+ int i, bidi;
+ unsigned vmin, vmax;
+ cipher_suite *suites;
+ size_t num_suites;
+ uint16_t *suite_ids;
+ unsigned hfuns;
+ br_x509_certificate *chain;
+ size_t chain_len;
+ int cert_signer_algo;
+ private_key *sk;
+ int nostaticecdh;
+ anchor_list anchors = VEC_INIT;
+ VECTOR(char *) alpn_names = VEC_INIT;
+ br_x509_minimal_context xc;
+ x509_noanchor_context xwc;
+ const br_hash_class *dnhash;
+ size_t u;
+ union {
+ br_ssl_engine_context eng;
+ br_ssl_server_context srv;
+ br_ssl_client_context cnt;
+ } cc;
+ br_ssl_session_cache_lru lru;
+ unsigned char *iobuf, *cache;
+ size_t iobuf_len, cache_len, minhello_len;
+ br_sslio_context ioc;
+ uint32_t flags;
+ int reconnect;
+
+ retcode = 0;
+ trace = 0;
+ is_client = 0;
+ is_server = 0;
+ sni = NULL;
+ bidi = 1;
+ vmin = 0;
+ vmax = 0;
+ suites = NULL;
+ num_suites = 0;
+ suite_ids = NULL;
+ hfuns = 0;
+ chain = NULL;
+ chain_len = 0;
+ cert_signer_algo = 0;
+ sk = NULL;
+ nostaticecdh = 0;
+ iobuf = NULL;
+ iobuf_len = 0;
+ cache = NULL;
+ cache_len = (size_t)-1;
+ minhello_len = (size_t)-1;
+ flags = 0;
+ reconnect = 0;
+ for (i = 0; i < argc; i ++) {
+ const char *arg;
+
+ arg = argv[i];
+ if (arg[0] != '-') {
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ if (eqstr(arg, "-trace")) {
+ trace = 1;
+ } else if (eqstr(arg, "-v")) {
+ verbose = 1;
+ } else if (eqstr(arg, "-server")) {
+ is_server = 1;
+ } else if (eqstr(arg, "-client")) {
+ is_client = 1;
+ } else if (eqstr(arg, "-sni")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-sni'\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ arg = argv[i];
+ if (sni != NULL) {
+ fprintf(stderr, "ERROR: duplicate SNI\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ sni = arg;
+ } else if (eqstr(arg, "-mono")) {
+ bidi = 0;
+ } else if (eqstr(arg, "-buf")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-buf'\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ arg = argv[i];
+ if (iobuf_len != 0) {
+ fprintf(stderr,
+ "ERROR: duplicate I/O buffer length\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ iobuf_len = parse_size(arg);
+ if (iobuf_len == (size_t)-1) {
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ } else if (eqstr(arg, "-cache")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-cache'\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ arg = argv[i];
+ if (cache_len != (size_t)-1) {
+ fprintf(stderr, "ERROR: duplicate session"
+ " cache length\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ cache_len = parse_size(arg);
+ if (cache_len == (size_t)-1) {
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ } else if (eqstr(arg, "-cert")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-cert'\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ if (chain != NULL) {
+ fprintf(stderr,
+ "ERROR: duplicate certificate chain\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ arg = argv[i];
+ chain = read_certificates(arg, &chain_len);
+ if (chain == NULL || chain_len == 0) {
+ goto twrch_exit_error;
+ }
+ } else if (eqstr(arg, "-key")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-key'\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ if (sk != NULL) {
+ fprintf(stderr,
+ "ERROR: duplicate private key\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ arg = argv[i];
+ sk = read_private_key(arg);
+ if (sk == NULL) {
+ goto twrch_exit_error;
+ }
+ } else if (eqstr(arg, "-CA")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-CA'\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ arg = argv[i];
+ if (read_trust_anchors(&anchors, arg) == 0) {
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ } else if (eqstr(arg, "-anon_ok")) {
+ flags |= BR_OPT_TOLERATE_NO_CLIENT_AUTH;
+ } else if (eqstr(arg, "-nostaticecdh")) {
+ nostaticecdh = 1;
+ } else if (eqstr(arg, "-list")) {
+ list_names();
+ goto twrch_exit;
+ } else if (eqstr(arg, "-vmin")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-vmin'\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ arg = argv[i];
+ if (vmin != 0) {
+ fprintf(stderr,
+ "ERROR: duplicate minimum version\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ vmin = parse_version(arg, strlen(arg));
+ if (vmin == 0) {
+ fprintf(stderr,
+ "ERROR: unrecognised version '%s'\n",
+ arg);
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ } else if (eqstr(arg, "-vmax")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-vmax'\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ arg = argv[i];
+ if (vmax != 0) {
+ fprintf(stderr,
+ "ERROR: duplicate maximum version\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ vmax = parse_version(arg, strlen(arg));
+ if (vmax == 0) {
+ fprintf(stderr,
+ "ERROR: unrecognised version '%s'\n",
+ arg);
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ } else if (eqstr(arg, "-cs")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-cs'\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ arg = argv[i];
+ if (suites != NULL) {
+ fprintf(stderr, "ERROR: duplicate list"
+ " of cipher suites\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ suites = parse_suites(arg, &num_suites);
+ if (suites == NULL) {
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ } else if (eqstr(arg, "-hf")) {
+ unsigned x;
+
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-hf'\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ arg = argv[i];
+ x = parse_hash_functions(arg);
+ if (x == 0) {
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ hfuns |= x;
+ } else if (eqstr(arg, "-minhello")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-minhello'\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ arg = argv[i];
+ if (minhello_len != (size_t)-1) {
+ fprintf(stderr, "ERROR: duplicate minimum"
+ " ClientHello length\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ minhello_len = parse_size(arg);
+ /*
+ * Minimum ClientHello length must fit on 16 bits.
+ */
+ if (minhello_len == (size_t)-1
+ || (((minhello_len >> 12) >> 4) != 0))
+ {
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ } else if (eqstr(arg, "-serverpref")) {
+ flags |= BR_OPT_ENFORCE_SERVER_PREFERENCES;
+ } else if (eqstr(arg, "-noreneg")) {
+ flags |= BR_OPT_NO_RENEGOTIATION;
+ } else if (eqstr(arg, "-alpn")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-alpn'\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ VEC_ADD(alpn_names, xstrdup(argv[i]));
+ } else if (eqstr(arg, "-strictalpn")) {
+ flags |= BR_OPT_FAIL_ON_ALPN_MISMATCH;
+ } else {
+ fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ }
+
+ /*
+ * Verify consistency of options.
+ */
+ if (!is_client && !is_server) {
+ fprintf(stderr, "ERROR:"
+ " one of -server and -client must be specified\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ if (is_client && is_server) {
+ fprintf(stderr, "ERROR:"
+ " -server and -client may not be both specified\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+
+ if (vmin == 0) {
+ vmin = BR_TLS10;
+ }
+ if (vmax == 0) {
+ vmax = BR_TLS12;
+ }
+ if (vmax < vmin) {
+ fprintf(stderr, "ERROR: impossible minimum/maximum protocol"
+ " version combination\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ if (is_server) {
+ if (chain == NULL) {
+ fprintf(stderr, "ERROR: no certificate specified"
+ " for server (-cert)\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ if (sk == NULL) {
+ fprintf(stderr, "ERROR: no private key specified"
+ " for server (-key)\n");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ } else {
+ if (chain == NULL && sk != NULL) {
+ fprintf(stderr, "ERROR: private key (-key)"
+ " but no certificate (-cert)");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ if (chain != NULL && sk == NULL) {
+ fprintf(stderr, "ERROR: certificate (-cert)"
+ " but no private key (-key)");
+ usage_twrch();
+ goto twrch_exit_error;
+ }
+ }
+ if (suites == NULL) {
+ num_suites = 0;
+
+ for (u = 0; cipher_suites[u].name; u ++) {
+ if ((cipher_suites[u].req & REQ_TLS12) == 0
+ || vmax >= BR_TLS12)
+ {
+ num_suites ++;
+ }
+ }
+ suites = xmalloc(num_suites * sizeof *suites);
+ num_suites = 0;
+ for (u = 0; cipher_suites[u].name; u ++) {
+ if ((cipher_suites[u].req & REQ_TLS12) == 0
+ || vmax >= BR_TLS12)
+ {
+ suites[num_suites ++] = cipher_suites[u];
+ }
+ }
+ }
+ if (hfuns == 0) {
+ hfuns = (unsigned)-1;
+ }
+ if (sk != NULL) {
+ switch (sk->key_type) {
+ int curve;
+ uint32_t supp;
+
+ case BR_KEYTYPE_RSA:
+ break;
+ case BR_KEYTYPE_EC:
+ curve = sk->key.ec.curve;
+ supp = br_ec_get_default()->supported_curves;
+ if (curve > 31 || !((supp >> curve) & 1)) {
+ fprintf(stderr, "ERROR: private key curve (%d)"
+ " is not supported\n", curve);
+ goto twrch_exit_error;
+ }
+ break;
+ default:
+ fprintf(stderr, "ERROR: unsupported"
+ " private key type (%d)\n", sk->key_type);
+ goto twrch_exit_error;
+ }
+ }
+ if (chain != NULL) {
+ cert_signer_algo = get_cert_signer_algo(chain);
+ if (cert_signer_algo == 0) {
+ goto twrch_exit_error;
+ }
+ }
+ if (iobuf_len == 0) {
+ if (bidi) {
+ iobuf_len = BR_SSL_BUFSIZE_BIDI;
+ } else {
+ iobuf_len = BR_SSL_BUFSIZE_MONO;
+ }
+ }
+ iobuf = xmalloc(iobuf_len);
+ if (is_server) {
+ if (cache_len == (size_t)-1) {
+ cache_len = 5000;
+ }
+ cache = xmalloc(cache_len);
+ }
+
+ /*
+ * Initialise the relevant context.
+ */
+ if (is_client) {
+ br_ssl_client_zero(&cc.cnt);
+ } else {
+ br_ssl_server_zero(&cc.srv);
+ }
+
+ /*
+ * Compute implementation requirements and inject implementations.
+ */
+ suite_ids = xmalloc(num_suites * sizeof *suite_ids);
+ br_ssl_engine_set_versions(&cc.eng, vmin, vmax);
+ br_ssl_engine_set_all_flags(&cc.eng, flags);
+ if (vmin <= BR_TLS11) {
+ if (!(hfuns & (1 << br_md5_ID))) {
+ fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need MD5\n");
+ goto twrch_exit_error;
+ }
+ if (!(hfuns & (1 << br_sha1_ID))) {
+ fprintf(stderr, "ERROR: TLS 1.0 and 1.1 need SHA-1\n");
+ goto twrch_exit_error;
+ }
+ }
+ for (u = 0; u < num_suites; u ++) {
+ unsigned req;
+
+ req = suites[u].req;
+ suite_ids[u] = suites[u].suite;
+ if ((req & REQ_TLS12) != 0 && vmax < BR_TLS12) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires TLS 1.2\n",
+ suites[u].name);
+ goto twrch_exit_error;
+ }
+ if ((req & REQ_SHA1) != 0 && !(hfuns & (1 << br_sha1_ID))) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires SHA-1\n",
+ suites[u].name);
+ goto twrch_exit_error;
+ }
+ if ((req & REQ_SHA256) != 0 && !(hfuns & (1 << br_sha256_ID))) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires SHA-256\n",
+ suites[u].name);
+ goto twrch_exit_error;
+ }
+ if ((req & REQ_SHA384) != 0 && !(hfuns & (1 << br_sha384_ID))) {
+ fprintf(stderr,
+ "ERROR: cipher suite %s requires SHA-384\n",
+ suites[u].name);
+ goto twrch_exit_error;
+ }
+ /* TODO: algorithm implementation selection */
+ if ((req & REQ_AESCBC) != 0) {
+ br_ssl_engine_set_default_aes_cbc(&cc.eng);
+ }
+ if ((req & REQ_AESCCM) != 0) {
+ br_ssl_engine_set_default_aes_ccm(&cc.eng);
+ }
+ if ((req & REQ_AESGCM) != 0) {
+ br_ssl_engine_set_default_aes_gcm(&cc.eng);
+ }
+ if ((req & REQ_CHAPOL) != 0) {
+ br_ssl_engine_set_default_chapol(&cc.eng);
+ }
+ if ((req & REQ_3DESCBC) != 0) {
+ br_ssl_engine_set_default_des_cbc(&cc.eng);
+ }
+ if (is_client && (req & REQ_RSAKEYX) != 0) {
+ br_ssl_client_set_default_rsapub(&cc.cnt);
+ }
+ if (is_client && (req & REQ_ECDHE_RSA) != 0) {
+ br_ssl_engine_set_default_rsavrfy(&cc.eng);
+ }
+ if (is_client && (req & REQ_ECDH) != 0) {
+ br_ssl_engine_set_default_ec(&cc.eng);
+ }
+ if ((req & (REQ_ECDHE_RSA | REQ_ECDHE_ECDSA)) != 0) {
+ br_ssl_engine_set_default_ec(&cc.eng);
+ }
+ }
+ br_ssl_engine_set_suites(&cc.eng, suite_ids, num_suites);
+
+ dnhash = NULL;
+ for (u = 0; hash_functions[u].name; u ++) {
+ const br_hash_class *hc;
+ int id;
+
+ hc = hash_functions[u].hclass;
+ id = (hc->desc >> BR_HASHDESC_ID_OFF) & BR_HASHDESC_ID_MASK;
+ if ((hfuns & ((unsigned)1 << id)) != 0) {
+ dnhash = hc;
+ br_ssl_engine_set_hash(&cc.eng, id, hc);
+ }
+ }
+ if (vmin <= BR_TLS11) {
+ br_ssl_engine_set_prf10(&cc.eng, &br_tls10_prf);
+ }
+ if (vmax >= BR_TLS12) {
+ if ((hfuns & ((unsigned)1 << br_sha256_ID)) != 0) {
+ br_ssl_engine_set_prf_sha256(&cc.eng,
+ &br_tls12_sha256_prf);
+ }
+ if ((hfuns & ((unsigned)1 << br_sha384_ID)) != 0) {
+ br_ssl_engine_set_prf_sha384(&cc.eng,
+ &br_tls12_sha384_prf);
+ }
+ }
+ if (VEC_LEN(alpn_names) != 0) {
+ br_ssl_engine_set_protocol_names(&cc.eng,
+ (const char **)&VEC_ELT(alpn_names, 0),
+ VEC_LEN(alpn_names));
+ }
+
+ /*
+ * In server role, we use a session cache (size can be
+ * specified; if size is zero, then no cache is set).
+ */
+ if (is_server && cache != NULL) {
+ br_ssl_session_cache_lru_init(&lru, cache, cache_len);
+ br_ssl_server_set_cache(&cc.srv, &lru.vtable);
+ }
+
+ /*
+ * For a server, set the policy handler.
+ */
+ if (is_server) {
+ switch (sk->key_type) {
+ case BR_KEYTYPE_RSA:
+ br_ssl_server_set_single_rsa(&cc.srv,
+ chain, chain_len, &sk->key.rsa,
+ BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
+ br_rsa_private_get_default(),
+ br_rsa_pkcs1_sign_get_default());
+ break;
+ case BR_KEYTYPE_EC:
+ br_ssl_server_set_single_ec(&cc.srv,
+ chain, chain_len, &sk->key.ec,
+ BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN,
+ cert_signer_algo,
+ br_ec_get_default(),
+ br_ecdsa_sign_asn1_get_default());
+ break;
+ default:
+ fprintf(stderr, "ERROR: unsupported"
+ " private key type (%d)\n", sk->key_type);
+ goto twrch_exit_error;
+ }
+ }
+
+ /*
+ * For a client, if a certificate was specified, use it.
+ */
+ if (is_client && chain != NULL) {
+ switch (sk->key_type) {
+ unsigned usages;
+
+ case BR_KEYTYPE_RSA:
+ br_ssl_client_set_single_rsa(&cc.cnt,
+ chain, chain_len, &sk->key.rsa,
+ br_rsa_pkcs1_sign_get_default());
+ break;
+ case BR_KEYTYPE_EC:
+ if (nostaticecdh) {
+ cert_signer_algo = 0;
+ usages = BR_KEYTYPE_SIGN;
+ } else {
+ usages = BR_KEYTYPE_KEYX | BR_KEYTYPE_SIGN;
+ }
+ br_ssl_client_set_single_ec(&cc.cnt,
+ chain, chain_len, &sk->key.ec,
+ usages, cert_signer_algo,
+ br_ec_get_default(),
+ br_ecdsa_sign_asn1_get_default());
+ break;
+ default:
+ fprintf(stderr, "ERROR: unsupported"
+ " private key type (%d)\n", sk->key_type);
+ goto twrch_exit_error;
+ }
+ }
+
+ /*
+ * On a client, or if trust anchors have been configured, then
+ * set an X.509 validation engine. If there are no trust anchors
+ * (client only), then a "no anchor" wrapper will be applied.
+ */
+ if (is_client || VEC_LEN(anchors) != 0) {
+ br_x509_minimal_init(&xc, dnhash,
+ &VEC_ELT(anchors, 0), VEC_LEN(anchors));
+ for (u = 0; hash_functions[u].name; u ++) {
+ const br_hash_class *hc;
+ int id;
+
+ hc = hash_functions[u].hclass;
+ id = (hc->desc >> BR_HASHDESC_ID_OFF)
+ & BR_HASHDESC_ID_MASK;
+ if ((hfuns & ((unsigned)1 << id)) != 0) {
+ br_x509_minimal_set_hash(&xc, id, hc);
+ }
+ }
+ br_ssl_engine_set_default_rsavrfy(&cc.eng);
+ br_ssl_engine_set_default_ecdsa(&cc.eng);
+ br_x509_minimal_set_rsa(&xc, br_rsa_pkcs1_vrfy_get_default());
+ br_x509_minimal_set_ecdsa(&xc,
+ br_ec_get_default(), br_ecdsa_vrfy_asn1_get_default());
+ br_ssl_engine_set_x509(&cc.eng, &xc.vtable);
+
+ if (VEC_LEN(anchors) == 0) {
+ x509_noanchor_init(&xwc, &xc.vtable);
+ br_ssl_engine_set_x509(&cc.eng, &xwc.vtable);
+ } else {
+ br_ssl_engine_set_x509(&cc.eng, &xc.vtable);
+ }
+ if (is_server) {
+ br_ssl_server_set_trust_anchor_names_alt(&cc.srv,
+ &VEC_ELT(anchors, 0), VEC_LEN(anchors));
+ }
+ }
+
+ /*
+ * Set I/O buffer.
+ */
+ br_ssl_engine_set_buffer(&cc.eng, iobuf, iobuf_len, bidi);
+
+ /*
+ * Start the engine.
+ */
+ if (is_client) {
+ br_ssl_client_reset(&cc.cnt, sni, 0);
+ }
+ if (is_server) {
+ br_ssl_server_reset(&cc.srv);
+ }
+
+ /*
+ * On Unix systems, we want to ignore SIGPIPE: if the peer
+ * closes the connection abruptly, then we want to report it
+ * as a "normal" error (exit code = 1).
+ */
+#ifndef _WIN32
+ signal(SIGPIPE, SIG_IGN);
+#endif
+
+ /*
+ * Initialize the callbacks for exchanging data over stdin and
+ * stdout.
+ */
+ br_sslio_init(&ioc, &cc.eng, stdin_read, &trace, stdout_write, &trace);
+
+ /*
+ * Run the Twrch protocol.
+ */
+ for (;;) {
+ br_sha1_context sc;
+ unsigned char hv[20], tmp[41];
+ uint64_t count;
+ int fb, i;
+
+ /*
+ * Read line, byte by byte, hashing it on the fly.
+ */
+ br_sha1_init(&sc);
+ count = 0;
+ fb = 0;
+ for (;;) {
+ unsigned char x;
+
+ if (br_sslio_read(&ioc, &x, 1) < 0) {
+ if (count == 0 && reconnect) {
+ reconnect = 0;
+ if (br_sslio_close(&ioc) < 0) {
+ goto twrch_loop_finished;
+ }
+ if (is_client) {
+ br_ssl_client_reset(
+ &cc.cnt, sni, 1);
+ }
+ if (is_server) {
+ br_ssl_server_reset(&cc.srv);
+ }
+ br_sslio_init(&ioc, &cc.eng,
+ stdin_read, &trace,
+ stdout_write, &trace);
+ continue;
+ }
+ goto twrch_loop_finished;
+ }
+ if (count == 0) {
+ fb = x;
+ }
+ if (x == 0x0A) {
+ break;
+ }
+ br_sha1_update(&sc, &x, 1);
+ count ++;
+ }
+ if (count == 1) {
+ switch (fb) {
+ case 'C':
+ br_sslio_close(&ioc);
+ goto twrch_loop_finished;
+ case 'T':
+ if (br_sslio_close(&ioc) < 0) {
+ goto twrch_loop_finished;
+ }
+ if (is_client) {
+ br_ssl_client_reset(&cc.cnt, sni, 1);
+ }
+ if (is_server) {
+ br_ssl_server_reset(&cc.srv);
+ }
+ br_sslio_init(&ioc, &cc.eng,
+ stdin_read, &trace,
+ stdout_write, &trace);
+ continue;
+ case 'G':
+ if (!br_ssl_engine_renegotiate(&cc.eng)) {
+ br_sslio_write_all(&ioc, "DENIED\n", 7);
+ br_sslio_flush(&ioc);
+ } else {
+ br_sslio_write_all(&ioc, "OK\n", 3);
+ br_sslio_flush(&ioc);
+ }
+ continue;
+ case 'R':
+ reconnect = 1;
+ br_sslio_write_all(&ioc, "OK\n", 3);
+ br_sslio_flush(&ioc);
+ continue;
+ case 'U':
+ if (is_client) {
+ br_ssl_client_forget_session(&cc.cnt);
+ }
+ if (is_server && cache != NULL) {
+ br_ssl_session_parameters pp;
+
+ br_ssl_engine_get_session_parameters(
+ &cc.eng, &pp);
+ if (pp.session_id_len == 32) {
+ br_ssl_session_cache_lru_forget(
+ &lru, pp.session_id);
+ }
+ }
+ br_sslio_write_all(&ioc, "DONE\n", 5);
+ br_sslio_flush(&ioc);
+ continue;
+ }
+ }
+ br_sha1_out(&sc, hv);
+ for (i = 0; i < 20; i ++) {
+ int x;
+
+ x = hv[i];
+ tmp[(i << 1) + 0] = "0123456789abcdef"[x >> 4];
+ tmp[(i << 1) + 1] = "0123456789abcdef"[x & 15];
+ }
+ tmp[40] = 0x0A;
+ br_sslio_write_all(&ioc, tmp, 41);
+ br_sslio_flush(&ioc);
+ }
+
+twrch_loop_finished:
+ if (br_ssl_engine_current_state(&cc.eng) == BR_SSL_CLOSED) {
+ int err;
+
+ err = br_ssl_engine_last_error(&cc.eng);
+ if (err == 0) {
+ retcode = 0;
+ } else {
+ if (verbose) {
+ print_error(err);
+ }
+ retcode = 1;
+ }
+ } else {
+ if (verbose) {
+ fprintf(stderr, "Engine not closed!\n");
+ }
+ retcode = 1;
+ }
+
+ /*
+ * Release allocated structures.
+ */
+twrch_exit:
+ xfree(suites);
+ xfree(suite_ids);
+ free_certificates(chain, chain_len);
+ free_private_key(sk);
+ VEC_CLEAREXT(anchors, &free_ta_contents);
+ VEC_CLEAREXT(alpn_names, &free_alpn);
+ xfree(iobuf);
+ xfree(cache);
+ return retcode;
+
+twrch_exit_error:
+ retcode = -1;
+ goto twrch_exit;
+}
diff --git a/contrib/bearssl/tools/vector.c b/contrib/bearssl/tools/vector.c
new file mode 100644
index 000000000000..96df3072b01b
--- /dev/null
+++ b/contrib/bearssl/tools/vector.c
@@ -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.
+ */
+
+#include "brssl.h"
+
+/*
+ * Prepare a vector buffer for adding 'extra' elements.
+ * buf current buffer
+ * esize size of a vector element
+ * ptr pointer to the 'ptr' vector field
+ * len pointer to the 'len' vector field
+ * extra number of elements to add
+ *
+ * If the buffer must be enlarged, then this function allocates the new
+ * buffer and releases the old one. The new buffer address is then returned.
+ * If the buffer needs not be enlarged, then the buffer address is returned.
+ *
+ * In case of enlargement, the 'len' field is adjusted accordingly. The
+ * 'ptr' field is not modified.
+ */
+void *
+vector_expand(void *buf,
+ size_t esize, size_t *ptr, size_t *len, size_t extra)
+{
+ size_t nlen;
+ void *nbuf;
+
+ if (*len - *ptr >= extra) {
+ return buf;
+ }
+ nlen = (*len << 1);
+ if (nlen - *ptr < extra) {
+ nlen = extra + *ptr;
+ if (nlen < 8) {
+ nlen = 8;
+ }
+ }
+ nbuf = xmalloc(nlen * esize);
+ if (buf != NULL) {
+ memcpy(nbuf, buf, *len * esize);
+ xfree(buf);
+ }
+ *len = nlen;
+ return nbuf;
+}
diff --git a/contrib/bearssl/tools/verify.c b/contrib/bearssl/tools/verify.c
new file mode 100644
index 000000000000..74055784c769
--- /dev/null
+++ b/contrib/bearssl/tools/verify.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+
+#include "brssl.h"
+#include "bearssl.h"
+
+static unsigned
+rsa_bit_length(const br_rsa_public_key *pk)
+{
+ size_t u;
+ unsigned x, bl;
+
+ for (u = 0; u < pk->nlen; u ++) {
+ if (pk->n[u] != 0) {
+ break;
+ }
+ }
+ if (u == pk->nlen) {
+ return 0;
+ }
+ bl = (unsigned)(pk->nlen - u - 1) << 3;
+ x = pk->n[u];
+ while (x != 0) {
+ bl ++;
+ x >>= 1;
+ }
+ return bl;
+}
+
+static void
+print_rsa(const br_rsa_public_key *pk, int print_text, int print_C)
+{
+ if (print_text) {
+ size_t u;
+
+ printf("n = ");
+ for (u = 0; u < pk->nlen; u ++) {
+ printf("%02X", pk->n[u]);
+ }
+ printf("\n");
+ printf("e = ");
+ for (u = 0; u < pk->elen; u ++) {
+ printf("%02X", pk->e[u]);
+ }
+ printf("\n");
+ }
+ if (print_C) {
+ size_t u;
+
+ printf("\nstatic const unsigned char RSA_N[] = {");
+ for (u = 0; u < pk->nlen; u ++) {
+ if (u != 0) {
+ printf(",");
+ }
+ if (u % 12 == 0) {
+ printf("\n\t");
+ } else {
+ printf(" ");
+ }
+ printf("0x%02X", pk->n[u]);
+ }
+ printf("\n};\n");
+ printf("\nstatic const unsigned char RSA_E[] = {");
+ for (u = 0; u < pk->elen; u ++) {
+ if (u != 0) {
+ printf(",");
+ }
+ if (u % 12 == 0) {
+ printf("\n\t");
+ } else {
+ printf(" ");
+ }
+ printf("0x%02X", pk->e[u]);
+ }
+ printf("\n};\n");
+ printf("\nstatic const br_rsa_public_key RSA = {\n");
+ printf("\t(unsigned char *)RSA_N, sizeof RSA_N,\n");
+ printf("\t(unsigned char *)RSA_E, sizeof RSA_E\n");
+ printf("};\n");
+ }
+}
+
+static void
+print_ec(const br_ec_public_key *pk, int print_text, int print_C)
+{
+ if (print_text) {
+ size_t u;
+
+ printf("Q = ");
+ for (u = 0; u < pk->qlen; u ++) {
+ printf("%02X", pk->q[u]);
+ }
+ printf("\n");
+ }
+ if (print_C) {
+ size_t u;
+
+ printf("\nstatic const unsigned char EC_Q[] = {");
+ for (u = 0; u < pk->qlen; u ++) {
+ if (u != 0) {
+ printf(",");
+ }
+ if (u % 12 == 0) {
+ printf("\n\t");
+ } else {
+ printf(" ");
+ }
+ printf("0x%02X", pk->q[u]);
+ }
+ printf("\n};\n");
+ printf("\nstatic const br_ec_public_key EC = {\n");
+ printf("\t%d,\n", pk->curve);
+ printf("\t(unsigned char *)EC_Q, sizeof EC_Q\n");
+ printf("};\n");
+ }
+}
+
+static void
+usage_verify(void)
+{
+ fprintf(stderr,
+"usage: brssl verify [ options ] file...\n");
+ fprintf(stderr,
+"options:\n");
+ fprintf(stderr,
+" -q suppress verbose messages\n");
+ fprintf(stderr,
+" -sni name check presence of a specific server name\n");
+ fprintf(stderr,
+" -CA file add certificates in 'file' to trust anchors\n");
+ fprintf(stderr,
+" -text print public key details (human-readable)\n");
+ fprintf(stderr,
+" -C print public key details (C code)\n");
+}
+
+typedef VECTOR(br_x509_certificate) cert_list;
+
+static void
+free_cert_contents(br_x509_certificate *xc)
+{
+ xfree(xc->data);
+}
+
+/* see brssl.h */
+int
+do_verify(int argc, char *argv[])
+{
+ int retcode;
+ int verbose;
+ int i;
+ const char *sni;
+ anchor_list anchors = VEC_INIT;
+ cert_list chain = VEC_INIT;
+ size_t u;
+ br_x509_minimal_context mc;
+ int err;
+ int print_text, print_C;
+ br_x509_pkey *pk;
+ const br_x509_pkey *tpk;
+ unsigned usages;
+
+ retcode = 0;
+ verbose = 1;
+ sni = NULL;
+ print_text = 0;
+ print_C = 0;
+ pk = NULL;
+ for (i = 0; i < argc; i ++) {
+ const char *arg;
+
+ arg = argv[i];
+ if (arg[0] != '-') {
+ br_x509_certificate *xcs;
+ size_t num;
+
+ xcs = read_certificates(arg, &num);
+ if (xcs == NULL) {
+ usage_verify();
+ goto verify_exit_error;
+ }
+ VEC_ADDMANY(chain, xcs, num);
+ xfree(xcs);
+ continue;
+ }
+ if (eqstr(arg, "-v") || eqstr(arg, "-verbose")) {
+ verbose = 1;
+ } else if (eqstr(arg, "-q") || eqstr(arg, "-quiet")) {
+ verbose = 0;
+ } else if (eqstr(arg, "-sni")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-sni'\n");
+ usage_verify();
+ goto verify_exit_error;
+ }
+ if (sni != NULL) {
+ fprintf(stderr, "ERROR: duplicate SNI\n");
+ usage_verify();
+ goto verify_exit_error;
+ }
+ sni = argv[i];
+ continue;
+ } else if (eqstr(arg, "-CA")) {
+ if (++ i >= argc) {
+ fprintf(stderr,
+ "ERROR: no argument for '-CA'\n");
+ usage_verify();
+ goto verify_exit_error;
+ }
+ arg = argv[i];
+ if (read_trust_anchors(&anchors, arg) == 0) {
+ usage_verify();
+ goto verify_exit_error;
+ }
+ continue;
+ } else if (eqstr(arg, "-text")) {
+ print_text = 1;
+ } else if (eqstr(arg, "-C")) {
+ print_C = 1;
+ } else {
+ fprintf(stderr, "ERROR: unknown option: '%s'\n", arg);
+ usage_verify();
+ goto verify_exit_error;
+ }
+ }
+ if (VEC_LEN(chain) == 0) {
+ fprintf(stderr, "ERROR: no certificate chain provided\n");
+ usage_verify();
+ goto verify_exit_error;
+ }
+ br_x509_minimal_init(&mc, &br_sha256_vtable,
+ &VEC_ELT(anchors, 0), VEC_LEN(anchors));
+ br_x509_minimal_set_hash(&mc, br_sha1_ID, &br_sha1_vtable);
+ br_x509_minimal_set_hash(&mc, br_sha224_ID, &br_sha224_vtable);
+ br_x509_minimal_set_hash(&mc, br_sha256_ID, &br_sha256_vtable);
+ br_x509_minimal_set_hash(&mc, br_sha384_ID, &br_sha384_vtable);
+ br_x509_minimal_set_hash(&mc, br_sha512_ID, &br_sha512_vtable);
+ br_x509_minimal_set_rsa(&mc, &br_rsa_i31_pkcs1_vrfy);
+ br_x509_minimal_set_ecdsa(&mc,
+ &br_ec_prime_i31, &br_ecdsa_i31_vrfy_asn1);
+
+ mc.vtable->start_chain(&mc.vtable, sni);
+ for (u = 0; u < VEC_LEN(chain); u ++) {
+ br_x509_certificate *xc;
+
+ xc = &VEC_ELT(chain, u);
+ mc.vtable->start_cert(&mc.vtable, xc->data_len);
+ mc.vtable->append(&mc.vtable, xc->data, xc->data_len);
+ mc.vtable->end_cert(&mc.vtable);
+ }
+ err = mc.vtable->end_chain(&mc.vtable);
+ tpk = mc.vtable->get_pkey(&mc.vtable, &usages);
+ if (tpk != NULL) {
+ pk = xpkeydup(tpk);
+ }
+
+ if (err == 0) {
+ if (verbose) {
+ int hkx;
+
+ fprintf(stderr, "Validation success; usages:");
+ hkx = 0;
+ if (usages & BR_KEYTYPE_KEYX) {
+ fprintf(stderr, " key exchange");
+ hkx = 1;
+ }
+ if (usages & BR_KEYTYPE_SIGN) {
+ if (hkx) {
+ fprintf(stderr, ",");
+ }
+ fprintf(stderr, " signature");
+ }
+ fprintf(stderr, "\n");
+ }
+ } else {
+ if (verbose) {
+ const char *errname, *errmsg;
+
+ fprintf(stderr, "Validation failed, err = %d", err);
+ errname = find_error_name(err, &errmsg);
+ if (errname != NULL) {
+ fprintf(stderr, " (%s): %s\n", errname, errmsg);
+ } else {
+ fprintf(stderr, " (unknown)\n");
+ }
+ }
+ retcode = -1;
+ }
+ if (pk != NULL) {
+ switch (pk->key_type) {
+ case BR_KEYTYPE_RSA:
+ if (verbose) {
+ fprintf(stderr, "Key type: RSA (%u bits)\n",
+ rsa_bit_length(&pk->key.rsa));
+ }
+ print_rsa(&pk->key.rsa, print_text, print_C);
+ break;
+ case BR_KEYTYPE_EC:
+ if (verbose) {
+ fprintf(stderr, "Key type: EC (%s)\n",
+ ec_curve_name(pk->key.ec.curve));
+ }
+ print_ec(&pk->key.ec, print_text, print_C);
+ break;
+ default:
+ if (verbose) {
+ fprintf(stderr, "Unknown key type\n");
+ break;
+ }
+ }
+ }
+
+ /*
+ * Release allocated structures.
+ */
+verify_exit:
+ VEC_CLEAREXT(anchors, &free_ta_contents);
+ VEC_CLEAREXT(chain, &free_cert_contents);
+ xfreepkey(pk);
+ return retcode;
+
+verify_exit_error:
+ retcode = -1;
+ goto verify_exit;
+}
diff --git a/contrib/bearssl/tools/xmem.c b/contrib/bearssl/tools/xmem.c
new file mode 100644
index 000000000000..ad192a4b5712
--- /dev/null
+++ b/contrib/bearssl/tools/xmem.c
@@ -0,0 +1,132 @@
+/*
+ * Copyright (c) 2016 Thomas Pornin <pornin@bolet.org>
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining
+ * a copy of this software and associated documentation files (the
+ * "Software"), to deal in the Software without restriction, including
+ * without limitation the rights to use, copy, modify, merge, publish,
+ * distribute, sublicense, and/or sell copies of the Software, and to
+ * permit persons to whom the Software is furnished to do so, subject to
+ * the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be
+ * included in all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ */
+
+#include "brssl.h"
+
+/* see brssl.h */
+void *
+xmalloc(size_t len)
+{
+ void *buf;
+
+ if (len == 0) {
+ return NULL;
+ }
+ buf = malloc(len);
+ if (buf == NULL) {
+#ifndef _STANDALONE
+ fprintf(stderr, "ERROR: could not allocate %lu byte(s)\n",
+ (unsigned long)len);
+ exit(EXIT_FAILURE);
+#else
+;
+#endif
+ }
+ return buf;
+}
+
+/* see brssl.h */
+void
+xfree(void *buf)
+{
+ if (buf != NULL) {
+ free(buf);
+ }
+}
+
+/* see brssl.h */
+void *
+xblobdup(const void *src, size_t len)
+{
+ void *buf;
+
+ buf = xmalloc(len);
+ memcpy(buf, src, len);
+ return buf;
+}
+
+/* see brssl.h */
+char *
+xstrdup(const void *src)
+{
+ return xblobdup(src, strlen(src) + 1);
+}
+
+/* see brssl.h */
+br_x509_pkey *
+xpkeydup(const br_x509_pkey *pk)
+{
+ br_x509_pkey *pk2;
+
+ pk2 = xmalloc(sizeof *pk2);
+ pk2->key_type = pk->key_type;
+ switch (pk->key_type) {
+ case BR_KEYTYPE_RSA:
+ pk2->key.rsa.n = xblobdup(pk->key.rsa.n, pk->key.rsa.nlen);
+ pk2->key.rsa.nlen = pk->key.rsa.nlen;
+ pk2->key.rsa.e = xblobdup(pk->key.rsa.e, pk->key.rsa.elen);
+ pk2->key.rsa.elen = pk->key.rsa.elen;
+ break;
+ case BR_KEYTYPE_EC:
+ pk2->key.ec.curve = pk->key.ec.curve;
+ pk2->key.ec.q = xblobdup(pk->key.ec.q, pk->key.ec.qlen);
+ pk2->key.ec.qlen = pk->key.ec.qlen;
+ break;
+ default:
+#ifndef _STANDALONE
+ fprintf(stderr, "Unknown public key type: %u\n",
+ (unsigned)pk->key_type);
+ exit(EXIT_FAILURE);
+#else
+;
+#endif
+ }
+ return pk2;
+}
+
+/* see brssl.h */
+void
+xfreepkey(br_x509_pkey *pk)
+{
+ if (pk != NULL) {
+ switch (pk->key_type) {
+ case BR_KEYTYPE_RSA:
+ xfree(pk->key.rsa.n);
+ xfree(pk->key.rsa.e);
+ break;
+ case BR_KEYTYPE_EC:
+ xfree(pk->key.ec.q);
+ break;
+ default:
+#ifndef _STANDALONE
+ fprintf(stderr, "Unknown public key type: %u\n",
+ (unsigned)pk->key_type);
+ exit(EXIT_FAILURE);
+#else
+;
+#endif
+ }
+ xfree(pk);
+ }
+}