summaryrefslogtreecommitdiffstats
path: root/src/crypto
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/crypto/aes/aes_gcm.go186
-rw-r--r--src/crypto/aes/aes_test.go383
-rw-r--r--src/crypto/aes/asm_amd64.s274
-rw-r--r--src/crypto/aes/asm_arm64.s281
-rw-r--r--src/crypto/aes/asm_ppc64x.s675
-rw-r--r--src/crypto/aes/asm_s390x.s191
-rw-r--r--src/crypto/aes/block.go182
-rw-r--r--src/crypto/aes/cbc_ppc64x.go74
-rw-r--r--src/crypto/aes/cbc_s390x.go66
-rw-r--r--src/crypto/aes/cipher.go82
-rw-r--r--src/crypto/aes/cipher_asm.go113
-rw-r--r--src/crypto/aes/cipher_generic.go26
-rw-r--r--src/crypto/aes/cipher_s390x.go96
-rw-r--r--src/crypto/aes/const.go365
-rw-r--r--src/crypto/aes/ctr_s390x.go84
-rw-r--r--src/crypto/aes/gcm_amd64.s1286
-rw-r--r--src/crypto/aes/gcm_arm64.s1021
-rw-r--r--src/crypto/aes/gcm_ppc64x.go265
-rw-r--r--src/crypto/aes/gcm_ppc64x.s590
-rw-r--r--src/crypto/aes/gcm_s390x.go371
-rw-r--r--src/crypto/aes/modes.go37
-rw-r--r--src/crypto/aes/modes_test.go112
-rw-r--r--src/crypto/boring/boring.go21
-rw-r--r--src/crypto/boring/boring_test.go22
-rw-r--r--src/crypto/boring/notboring_test.go14
-rw-r--r--src/crypto/cipher/benchmark_test.go137
-rw-r--r--src/crypto/cipher/cbc.go189
-rw-r--r--src/crypto/cipher/cbc_aes_test.go104
-rw-r--r--src/crypto/cipher/cfb.go83
-rw-r--r--src/crypto/cipher/cfb_test.go113
-rw-r--r--src/crypto/cipher/cipher.go61
-rw-r--r--src/crypto/cipher/cipher_test.go90
-rw-r--r--src/crypto/cipher/common_test.go28
-rw-r--r--src/crypto/cipher/ctr.go95
-rw-r--r--src/crypto/cipher/ctr_aes_test.go102
-rw-r--r--src/crypto/cipher/ctr_test.go55
-rw-r--r--src/crypto/cipher/example_test.go363
-rw-r--r--src/crypto/cipher/export_test.go9
-rw-r--r--src/crypto/cipher/fuzz_test.go103
-rw-r--r--src/crypto/cipher/gcm.go427
-rw-r--r--src/crypto/cipher/gcm_test.go511
-rw-r--r--src/crypto/cipher/io.go53
-rw-r--r--src/crypto/cipher/ofb.go77
-rw-r--r--src/crypto/cipher/ofb_test.go102
-rw-r--r--src/crypto/crypto.go223
-rw-r--r--src/crypto/des/block.go259
-rw-r--r--src/crypto/des/cipher.go155
-rw-r--r--src/crypto/des/const.go142
-rw-r--r--src/crypto/des/des_test.go1583
-rw-r--r--src/crypto/des/example_test.go25
-rw-r--r--src/crypto/dsa/dsa.go309
-rw-r--r--src/crypto/dsa/dsa_test.go143
-rw-r--r--src/crypto/ecdh/ecdh.go184
-rw-r--r--src/crypto/ecdh/ecdh_test.go525
-rw-r--r--src/crypto/ecdh/nist.go275
-rw-r--r--src/crypto/ecdh/x25519.go136
-rw-r--r--src/crypto/ecdsa/boring.go106
-rw-r--r--src/crypto/ecdsa/ecdsa.go660
-rw-r--r--src/crypto/ecdsa/ecdsa_legacy.go188
-rw-r--r--src/crypto/ecdsa/ecdsa_noasm.go17
-rw-r--r--src/crypto/ecdsa/ecdsa_s390x.go177
-rw-r--r--src/crypto/ecdsa/ecdsa_s390x.s28
-rw-r--r--src/crypto/ecdsa/ecdsa_s390x_test.go32
-rw-r--r--src/crypto/ecdsa/ecdsa_test.go589
-rw-r--r--src/crypto/ecdsa/equal_test.go75
-rw-r--r--src/crypto/ecdsa/example_test.go32
-rw-r--r--src/crypto/ecdsa/notboring.go16
-rw-r--r--src/crypto/ecdsa/testdata/SigVer.rsp.bz2bin0 -> 95485 bytes
-rw-r--r--src/crypto/ed25519/ed25519.go337
-rw-r--r--src/crypto/ed25519/ed25519_test.go384
-rw-r--r--src/crypto/ed25519/ed25519vectors_test.go120
-rw-r--r--src/crypto/ed25519/testdata/sign.input.gzbin0 -> 50330 bytes
-rw-r--r--src/crypto/elliptic/elliptic.go275
-rw-r--r--src/crypto/elliptic/elliptic_test.go405
-rw-r--r--src/crypto/elliptic/nistec.go294
-rw-r--r--src/crypto/elliptic/nistec_p256.go29
-rw-r--r--src/crypto/elliptic/p224_test.go325
-rw-r--r--src/crypto/elliptic/p256_test.go152
-rw-r--r--src/crypto/elliptic/params.go333
-rw-r--r--src/crypto/hmac/hmac.go180
-rw-r--r--src/crypto/hmac/hmac_test.go695
-rw-r--r--src/crypto/internal/alias/alias.go30
-rw-r--r--src/crypto/internal/alias/alias_test.go46
-rw-r--r--src/crypto/internal/bigmod/_asm/go.mod12
-rw-r--r--src/crypto/internal/bigmod/_asm/go.sum32
-rw-r--r--src/crypto/internal/bigmod/_asm/nat_amd64_asm.go131
-rw-r--r--src/crypto/internal/bigmod/nat.go703
-rw-r--r--src/crypto/internal/bigmod/nat_amd64.go8
-rw-r--r--src/crypto/internal/bigmod/nat_amd64.s68
-rw-r--r--src/crypto/internal/bigmod/nat_noasm.go11
-rw-r--r--src/crypto/internal/bigmod/nat_test.go412
-rw-r--r--src/crypto/internal/boring/Dockerfile63
-rw-r--r--src/crypto/internal/boring/LICENSE202
-rw-r--r--src/crypto/internal/boring/README.md39
-rw-r--r--src/crypto/internal/boring/aes.go385
-rw-r--r--src/crypto/internal/boring/bbig/big.go33
-rw-r--r--src/crypto/internal/boring/bcache/cache.go140
-rw-r--r--src/crypto/internal/boring/bcache/cache_test.go122
-rw-r--r--src/crypto/internal/boring/bcache/stub.s6
-rw-r--r--src/crypto/internal/boring/boring.go126
-rw-r--r--src/crypto/internal/boring/boring_test.go34
-rwxr-xr-xsrc/crypto/internal/boring/build-boring.sh44
-rwxr-xr-xsrc/crypto/internal/boring/build-goboring.sh237
-rwxr-xr-xsrc/crypto/internal/boring/build.sh46
-rw-r--r--src/crypto/internal/boring/div_test.c83
-rw-r--r--src/crypto/internal/boring/doc.go19
-rw-r--r--src/crypto/internal/boring/ecdh.go224
-rw-r--r--src/crypto/internal/boring/ecdsa.go172
-rw-r--r--src/crypto/internal/boring/fipstls/stub.s12
-rw-r--r--src/crypto/internal/boring/fipstls/tls.go52
-rw-r--r--src/crypto/internal/boring/goboringcrypto.h255
-rw-r--r--src/crypto/internal/boring/hmac.go153
-rw-r--r--src/crypto/internal/boring/notboring.go122
-rw-r--r--src/crypto/internal/boring/rand.go24
-rw-r--r--src/crypto/internal/boring/rsa.go379
-rw-r--r--src/crypto/internal/boring/sha.go599
-rw-r--r--src/crypto/internal/boring/sig/sig.go17
-rw-r--r--src/crypto/internal/boring/sig/sig_amd64.s54
-rw-r--r--src/crypto/internal/boring/sig/sig_other.s20
-rw-r--r--src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.sysobin0 -> 2555664 bytes
-rw-r--r--src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.sysobin0 -> 1980296 bytes
-rw-r--r--src/crypto/internal/boring/syso/syso.go9
-rw-r--r--src/crypto/internal/edwards25519/doc.go22
-rw-r--r--src/crypto/internal/edwards25519/edwards25519.go426
-rw-r--r--src/crypto/internal/edwards25519/edwards25519_test.go313
-rw-r--r--src/crypto/internal/edwards25519/field/_asm/fe_amd64_asm.go294
-rw-r--r--src/crypto/internal/edwards25519/field/_asm/go.mod12
-rw-r--r--src/crypto/internal/edwards25519/field/_asm/go.sum32
-rw-r--r--src/crypto/internal/edwards25519/field/fe.go420
-rw-r--r--src/crypto/internal/edwards25519/field/fe_alias_test.go140
-rw-r--r--src/crypto/internal/edwards25519/field/fe_amd64.go15
-rw-r--r--src/crypto/internal/edwards25519/field/fe_amd64.s378
-rw-r--r--src/crypto/internal/edwards25519/field/fe_amd64_noasm.go11
-rw-r--r--src/crypto/internal/edwards25519/field/fe_arm64.go15
-rw-r--r--src/crypto/internal/edwards25519/field/fe_arm64.s42
-rw-r--r--src/crypto/internal/edwards25519/field/fe_arm64_noasm.go11
-rw-r--r--src/crypto/internal/edwards25519/field/fe_bench_test.go49
-rw-r--r--src/crypto/internal/edwards25519/field/fe_generic.go266
-rw-r--r--src/crypto/internal/edwards25519/field/fe_test.go560
-rw-r--r--src/crypto/internal/edwards25519/scalar.go343
-rw-r--r--src/crypto/internal/edwards25519/scalar_alias_test.go108
-rw-r--r--src/crypto/internal/edwards25519/scalar_fiat.go1147
-rw-r--r--src/crypto/internal/edwards25519/scalar_test.go249
-rw-r--r--src/crypto/internal/edwards25519/scalarmult.go214
-rw-r--r--src/crypto/internal/edwards25519/scalarmult_test.go209
-rw-r--r--src/crypto/internal/edwards25519/tables.go129
-rw-r--r--src/crypto/internal/edwards25519/tables_test.go119
-rw-r--r--src/crypto/internal/nistec/fiat/Dockerfile12
-rw-r--r--src/crypto/internal/nistec/fiat/README34
-rw-r--r--src/crypto/internal/nistec/fiat/fiat_test.go64
-rw-r--r--src/crypto/internal/nistec/fiat/generate.go330
-rw-r--r--src/crypto/internal/nistec/fiat/p224.go134
-rw-r--r--src/crypto/internal/nistec/fiat/p224_fiat64.go1461
-rw-r--r--src/crypto/internal/nistec/fiat/p224_invert.go87
-rw-r--r--src/crypto/internal/nistec/fiat/p256.go134
-rw-r--r--src/crypto/internal/nistec/fiat/p256_fiat64.go1400
-rw-r--r--src/crypto/internal/nistec/fiat/p256_invert.go84
-rw-r--r--src/crypto/internal/nistec/fiat/p384.go134
-rw-r--r--src/crypto/internal/nistec/fiat/p384_fiat64.go3036
-rw-r--r--src/crypto/internal/nistec/fiat/p384_invert.go102
-rw-r--r--src/crypto/internal/nistec/fiat/p521.go134
-rw-r--r--src/crypto/internal/nistec/fiat/p521_fiat64.go5541
-rw-r--r--src/crypto/internal/nistec/fiat/p521_invert.go89
-rw-r--r--src/crypto/internal/nistec/generate.go639
-rw-r--r--src/crypto/internal/nistec/nistec.go15
-rw-r--r--src/crypto/internal/nistec/nistec_test.go297
-rw-r--r--src/crypto/internal/nistec/p224.go453
-rw-r--r--src/crypto/internal/nistec/p224_sqrt.go132
-rw-r--r--src/crypto/internal/nistec/p256.go509
-rw-r--r--src/crypto/internal/nistec/p256_asm.go744
-rw-r--r--src/crypto/internal/nistec/p256_asm_amd64.s2350
-rw-r--r--src/crypto/internal/nistec/p256_asm_arm64.s1533
-rw-r--r--src/crypto/internal/nistec/p256_asm_ppc64le.s2208
-rw-r--r--src/crypto/internal/nistec/p256_asm_s390x.s2418
-rw-r--r--src/crypto/internal/nistec/p256_asm_table.binbin0 -> 88064 bytes
-rw-r--r--src/crypto/internal/nistec/p256_asm_table_test.go49
-rw-r--r--src/crypto/internal/nistec/p256_ordinv.go102
-rw-r--r--src/crypto/internal/nistec/p256_ordinv_noasm.go13
-rw-r--r--src/crypto/internal/nistec/p256_ordinv_test.go94
-rw-r--r--src/crypto/internal/nistec/p384.go540
-rw-r--r--src/crypto/internal/nistec/p521.go469
-rw-r--r--src/crypto/internal/randutil/randutil.go38
-rw-r--r--src/crypto/issue21104_test.go61
-rw-r--r--src/crypto/md5/example_test.go42
-rw-r--r--src/crypto/md5/gen.go259
-rw-r--r--src/crypto/md5/md5.go183
-rw-r--r--src/crypto/md5/md5_test.go294
-rw-r--r--src/crypto/md5/md5block.go125
-rw-r--r--src/crypto/md5/md5block_386.s182
-rw-r--r--src/crypto/md5/md5block_amd64.s179
-rw-r--r--src/crypto/md5/md5block_arm.s299
-rw-r--r--src/crypto/md5/md5block_arm64.s167
-rw-r--r--src/crypto/md5/md5block_decl.go13
-rw-r--r--src/crypto/md5/md5block_generic.go13
-rw-r--r--src/crypto/md5/md5block_ppc64x.s212
-rw-r--r--src/crypto/md5/md5block_s390x.s175
-rw-r--r--src/crypto/rand/example_test.go28
-rw-r--r--src/crypto/rand/rand.go44
-rw-r--r--src/crypto/rand/rand_batched_test.go75
-rw-r--r--src/crypto/rand/rand_getentropy.go14
-rw-r--r--src/crypto/rand/rand_getrandom.go48
-rw-r--r--src/crypto/rand/rand_js.go28
-rw-r--r--src/crypto/rand/rand_plan9.go87
-rw-r--r--src/crypto/rand/rand_test.go43
-rw-r--r--src/crypto/rand/rand_unix.go87
-rw-r--r--src/crypto/rand/rand_windows.go26
-rw-r--r--src/crypto/rand/util.go99
-rw-r--r--src/crypto/rand/util_test.go149
-rw-r--r--src/crypto/rc4/rc4.go80
-rw-r--r--src/crypto/rc4/rc4_test.go162
-rw-r--r--src/crypto/rsa/boring.go130
-rw-r--r--src/crypto/rsa/boring_test.go148
-rw-r--r--src/crypto/rsa/equal_test.go51
-rw-r--r--src/crypto/rsa/example_test.go157
-rw-r--r--src/crypto/rsa/notboring.go16
-rw-r--r--src/crypto/rsa/pkcs1v15.go375
-rw-r--r--src/crypto/rsa/pkcs1v15_test.go315
-rw-r--r--src/crypto/rsa/pss.go372
-rw-r--r--src/crypto/rsa/pss_test.go308
-rw-r--r--src/crypto/rsa/rsa.go737
-rw-r--r--src/crypto/rsa/rsa_export_test.go10
-rw-r--r--src/crypto/rsa/rsa_test.go882
-rw-r--r--src/crypto/rsa/testdata/pss-vect.txt.bz2bin0 -> 28526 bytes
-rw-r--r--src/crypto/sha1/boring.go25
-rw-r--r--src/crypto/sha1/example_test.go42
-rw-r--r--src/crypto/sha1/fallback_test.go34
-rw-r--r--src/crypto/sha1/issue15617_test.go27
-rw-r--r--src/crypto/sha1/notboring.go20
-rw-r--r--src/crypto/sha1/sha1.go264
-rw-r--r--src/crypto/sha1/sha1_test.go274
-rw-r--r--src/crypto/sha1/sha1block.go83
-rw-r--r--src/crypto/sha1/sha1block_386.s233
-rw-r--r--src/crypto/sha1/sha1block_amd64.go34
-rw-r--r--src/crypto/sha1/sha1block_amd64.s1500
-rw-r--r--src/crypto/sha1/sha1block_arm.s217
-rw-r--r--src/crypto/sha1/sha1block_arm64.go26
-rw-r--r--src/crypto/sha1/sha1block_arm64.s152
-rw-r--r--src/crypto/sha1/sha1block_decl.go11
-rw-r--r--src/crypto/sha1/sha1block_generic.go11
-rw-r--r--src/crypto/sha1/sha1block_s390x.go9
-rw-r--r--src/crypto/sha1/sha1block_s390x.s20
-rw-r--r--src/crypto/sha256/example_test.go41
-rw-r--r--src/crypto/sha256/fallback_test.go35
-rw-r--r--src/crypto/sha256/sha256.go275
-rw-r--r--src/crypto/sha256/sha256_test.go368
-rw-r--r--src/crypto/sha256/sha256block.go128
-rw-r--r--src/crypto/sha256/sha256block_386.s283
-rw-r--r--src/crypto/sha256/sha256block_amd64.go9
-rw-r--r--src/crypto/sha256/sha256block_amd64.s1031
-rw-r--r--src/crypto/sha256/sha256block_arm64.go21
-rw-r--r--src/crypto/sha256/sha256block_arm64.s119
-rw-r--r--src/crypto/sha256/sha256block_decl.go11
-rw-r--r--src/crypto/sha256/sha256block_generic.go11
-rw-r--r--src/crypto/sha256/sha256block_ppc64x.s453
-rw-r--r--src/crypto/sha256/sha256block_s390x.go9
-rw-r--r--src/crypto/sha256/sha256block_s390x.s20
-rw-r--r--src/crypto/sha512/fallback_test.go37
-rw-r--r--src/crypto/sha512/sha512.go384
-rw-r--r--src/crypto/sha512/sha512_test.go952
-rw-r--r--src/crypto/sha512/sha512block.go144
-rw-r--r--src/crypto/sha512/sha512block_amd64.go25
-rw-r--r--src/crypto/sha512/sha512block_amd64.s1468
-rw-r--r--src/crypto/sha512/sha512block_arm64.go18
-rw-r--r--src/crypto/sha512/sha512block_arm64.s135
-rw-r--r--src/crypto/sha512/sha512block_decl.go11
-rw-r--r--src/crypto/sha512/sha512block_generic.go11
-rw-r--r--src/crypto/sha512/sha512block_ppc64x.s465
-rw-r--r--src/crypto/sha512/sha512block_s390x.go9
-rw-r--r--src/crypto/sha512/sha512block_s390x.s20
-rw-r--r--src/crypto/subtle/constant_time.go62
-rw-r--r--src/crypto/subtle/constant_time_test.go159
-rw-r--r--src/crypto/subtle/xor.go24
-rw-r--r--src/crypto/subtle/xor_amd64.go10
-rw-r--r--src/crypto/subtle/xor_amd64.s56
-rw-r--r--src/crypto/subtle/xor_arm64.go10
-rw-r--r--src/crypto/subtle/xor_arm64.s69
-rw-r--r--src/crypto/subtle/xor_generic.go64
-rw-r--r--src/crypto/subtle/xor_ppc64x.go10
-rw-r--r--src/crypto/subtle/xor_ppc64x.s87
-rw-r--r--src/crypto/subtle/xor_test.go106
-rw-r--r--src/crypto/tls/alert.go99
-rw-r--r--src/crypto/tls/auth.go293
-rw-r--r--src/crypto/tls/auth_test.go168
-rw-r--r--src/crypto/tls/boring.go98
-rw-r--r--src/crypto/tls/boring_test.go617
-rw-r--r--src/crypto/tls/cache.go95
-rw-r--r--src/crypto/tls/cache_test.go117
-rw-r--r--src/crypto/tls/cipher_suites.go702
-rw-r--r--src/crypto/tls/common.go1510
-rw-r--r--src/crypto/tls/common_string.go116
-rw-r--r--src/crypto/tls/conn.go1575
-rw-r--r--src/crypto/tls/conn_test.go287
-rw-r--r--src/crypto/tls/example_test.go232
-rw-r--r--src/crypto/tls/fipsonly/fipsonly.go29
-rw-r--r--src/crypto/tls/fipsonly/fipsonly_test.go18
-rw-r--r--src/crypto/tls/generate_cert.go171
-rw-r--r--src/crypto/tls/handshake_client.go1055
-rw-r--r--src/crypto/tls/handshake_client_test.go2721
-rw-r--r--src/crypto/tls/handshake_client_tls13.go709
-rw-r--r--src/crypto/tls/handshake_messages.go1852
-rw-r--r--src/crypto/tls/handshake_messages_test.go495
-rw-r--r--src/crypto/tls/handshake_server.go897
-rw-r--r--src/crypto/tls/handshake_server_test.go2047
-rw-r--r--src/crypto/tls/handshake_server_tls13.go893
-rw-r--r--src/crypto/tls/handshake_test.go530
-rw-r--r--src/crypto/tls/handshake_unix_test.go18
-rw-r--r--src/crypto/tls/key_agreement.go366
-rw-r--r--src/crypto/tls/key_schedule.go158
-rw-r--r--src/crypto/tls/key_schedule_test.go175
-rw-r--r--src/crypto/tls/link_test.go107
-rw-r--r--src/crypto/tls/notboring.go20
-rw-r--r--src/crypto/tls/prf.go283
-rw-r--r--src/crypto/tls/prf_test.go140
-rw-r--r--src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA134
-rw-r--r--src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA138
-rw-r--r--src/crypto/tls/testdata/Client-TLSv10-ClientCert-Ed25519110
-rw-r--r--src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA133
-rw-r--r--src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA137
-rw-r--r--src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES91
-rw-r--r--src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES95
-rw-r--r--src/crypto/tls/testdata/Client-TLSv10-Ed255190
-rw-r--r--src/crypto/tls/testdata/Client-TLSv10-ExportKeyingMaterial95
-rw-r--r--src/crypto/tls/testdata/Client-TLSv10-RSA-RC484
-rw-r--r--src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES93
-rw-r--r--src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES97
-rw-r--r--src/crypto/tls/testdata/Client-TLSv11-Ed255190
-rw-r--r--src/crypto/tls/testdata/Client-TLSv11-RSA-RC484
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA25686
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-AES128-SHA25695
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA38486
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ALPN93
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch91
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA139
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA139
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ClientCert-Ed25519119
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384137
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA138
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA137
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSAPKCS1v15134
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSAPSS142
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES93
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM88
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES128-SHA25697
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA38488
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-CHACHA20-POLY130584
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES97
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES128-SHA256101
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-CHACHA20-POLY130588
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-Ed2551968
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-ExportKeyingMaterial90
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-P256-ECDHE98
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-RSA-RC484
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-RenegotiateOnce244
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice343
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwiceRejected247
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected95
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-SCT113
-rw-r--r--src/crypto/tls/testdata/Client-TLSv12-X25519-ECDHE92
-rw-r--r--src/crypto/tls/testdata/Client-TLSv13-AES128-SHA25690
-rw-r--r--src/crypto/tls/testdata/Client-TLSv13-AES256-SHA38492
-rw-r--r--src/crypto/tls/testdata/Client-TLSv13-ALPN93
-rw-r--r--src/crypto/tls/testdata/Client-TLSv13-CHACHA20-SHA25690
-rw-r--r--src/crypto/tls/testdata/Client-TLSv13-ClientCert-ECDSA-RSA139
-rw-r--r--src/crypto/tls/testdata/Client-TLSv13-ClientCert-Ed25519122
-rw-r--r--src/crypto/tls/testdata/Client-TLSv13-ClientCert-RSA-ECDSA134
-rw-r--r--src/crypto/tls/testdata/Client-TLSv13-ClientCert-RSA-RSAPSS143
-rw-r--r--src/crypto/tls/testdata/Client-TLSv13-ECDSA86
-rw-r--r--src/crypto/tls/testdata/Client-TLSv13-Ed2551968
-rw-r--r--src/crypto/tls/testdata/Client-TLSv13-ExportKeyingMaterial90
-rw-r--r--src/crypto/tls/testdata/Client-TLSv13-HelloRetryRequest119
-rw-r--r--src/crypto/tls/testdata/Client-TLSv13-KeyUpdate102
-rw-r--r--src/crypto/tls/testdata/Client-TLSv13-P256-ECDHE94
-rw-r--r--src/crypto/tls/testdata/Client-TLSv13-X25519-ECDHE90
-rw-r--r--src/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES79
-rw-r--r--src/crypto/tls/testdata/Server-TLSv10-ExportKeyingMaterial93
-rw-r--r--src/crypto/tls/testdata/Server-TLSv10-RSA-3DES76
-rw-r--r--src/crypto/tls/testdata/Server-TLSv10-RSA-AES79
-rw-r--r--src/crypto/tls/testdata/Server-TLSv10-RSA-RC473
-rw-r--r--src/crypto/tls/testdata/Server-TLSv11-FallbackSCSV11
-rw-r--r--src/crypto/tls/testdata/Server-TLSv11-RSA-RC473
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-ALPN92
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-ALPN-Fallback91
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch14
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-ALPN-NotConfigured91
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven126
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndEd25519Given109
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven125
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndPKCS1v15Given125
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven85
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES84
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-Ed2551958
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-ExportKeyingMaterial89
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-IssueTicket91
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable91
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-P25686
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-RSA-3DES80
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-RSA-AES84
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM82
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA38482
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-RSA-RC476
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-RSA-RSAPKCS1v1577
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-RSA-RSAPSS77
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-Resume46
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled91
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-SNI84
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate84
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound84
-rw-r--r--src/crypto/tls/testdata/Server-TLSv12-X2551982
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-AES128-SHA256100
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-AES256-SHA384103
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-ALPN100
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-ALPN-Fallback100
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-ALPN-NoMatch27
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-ALPN-NotConfigured100
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-CHACHA20-SHA256100
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-ClientAuthRequestedAndECDSAGiven179
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-ClientAuthRequestedAndEd25519Given149
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-ClientAuthRequestedAndGiven177
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-ClientAuthRequestedNotGiven104
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-ECDHE-ECDSA-AES94
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-Ed2551976
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-ExportKeyingMaterial99
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-HelloRetryRequest123
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-IssueTicket99
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-IssueTicketPreDisable99
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-P256102
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-RSA-RSAPSS97
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-RSA-RSAPSS-TooSmall15
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-Resume60
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-Resume-HelloRetryRequest96
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-ResumeDisabled99
-rw-r--r--src/crypto/tls/testdata/Server-TLSv13-X2551998
-rw-r--r--src/crypto/tls/testdata/example-cert.pem11
-rw-r--r--src/crypto/tls/testdata/example-key.pem5
-rw-r--r--src/crypto/tls/ticket.go185
-rw-r--r--src/crypto/tls/tls.go356
-rw-r--r--src/crypto/tls/tls_test.go1611
-rw-r--r--src/crypto/x509/boring.go39
-rw-r--r--src/crypto/x509/boring_test.go142
-rw-r--r--src/crypto/x509/cert_pool.go268
-rw-r--r--src/crypto/x509/cert_pool_test.go108
-rw-r--r--src/crypto/x509/example_test.go137
-rw-r--r--src/crypto/x509/hybrid_pool_test.go123
-rw-r--r--src/crypto/x509/internal/macos/corefoundation.go219
-rw-r--r--src/crypto/x509/internal/macos/corefoundation.s43
-rw-r--r--src/crypto/x509/internal/macos/security.go247
-rw-r--r--src/crypto/x509/internal/macos/security.s35
-rw-r--r--src/crypto/x509/name_constraints_test.go2171
-rw-r--r--src/crypto/x509/notboring.go9
-rw-r--r--src/crypto/x509/parser.go1175
-rw-r--r--src/crypto/x509/parser_test.go103
-rw-r--r--src/crypto/x509/pem_decrypt.go252
-rw-r--r--src/crypto/x509/pem_decrypt_test.go249
-rw-r--r--src/crypto/x509/pkcs1.go173
-rw-r--r--src/crypto/x509/pkcs8.go175
-rw-r--r--src/crypto/x509/pkcs8_test.go175
-rw-r--r--src/crypto/x509/pkix/pkix.go320
-rw-r--r--src/crypto/x509/root.go72
-rw-r--r--src/crypto/x509/root_aix.go15
-rw-r--r--src/crypto/x509/root_bsd.go22
-rw-r--r--src/crypto/x509/root_darwin.go130
-rw-r--r--src/crypto/x509/root_darwin_test.go122
-rw-r--r--src/crypto/x509/root_js.go13
-rw-r--r--src/crypto/x509/root_linux.go22
-rw-r--r--src/crypto/x509/root_plan9.go39
-rw-r--r--src/crypto/x509/root_solaris.go17
-rw-r--r--src/crypto/x509/root_test.go108
-rw-r--r--src/crypto/x509/root_unix.go108
-rw-r--r--src/crypto/x509/root_unix_test.go228
-rw-r--r--src/crypto/x509/root_windows.go276
-rw-r--r--src/crypto/x509/root_windows_test.go115
-rw-r--r--src/crypto/x509/sec1.go136
-rw-r--r--src/crypto/x509/sec1_test.go66
-rw-r--r--src/crypto/x509/test-file.crt32
-rw-r--r--src/crypto/x509/testdata/test-dir.crt31
-rw-r--r--src/crypto/x509/verify.go1179
-rw-r--r--src/crypto/x509/verify_test.go2636
-rw-r--r--src/crypto/x509/x509.go2371
-rw-r--r--src/crypto/x509/x509_test.go3844
-rw-r--r--src/crypto/x509/x509_test_import.go56
480 files changed, 122178 insertions, 0 deletions
diff --git a/src/crypto/aes/aes_gcm.go b/src/crypto/aes/aes_gcm.go
new file mode 100644
index 0000000..f77d279
--- /dev/null
+++ b/src/crypto/aes/aes_gcm.go
@@ -0,0 +1,186 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build amd64 || arm64
+
+package aes
+
+import (
+ "crypto/cipher"
+ "crypto/internal/alias"
+ "crypto/subtle"
+ "errors"
+)
+
+// The following functions are defined in gcm_*.s.
+
+//go:noescape
+func gcmAesInit(productTable *[256]byte, ks []uint32)
+
+//go:noescape
+func gcmAesData(productTable *[256]byte, data []byte, T *[16]byte)
+
+//go:noescape
+func gcmAesEnc(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32)
+
+//go:noescape
+func gcmAesDec(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32)
+
+//go:noescape
+func gcmAesFinish(productTable *[256]byte, tagMask, T *[16]byte, pLen, dLen uint64)
+
+const (
+ gcmBlockSize = 16
+ gcmTagSize = 16
+ gcmMinimumTagSize = 12 // NIST SP 800-38D recommends tags with 12 or more bytes.
+ gcmStandardNonceSize = 12
+)
+
+var errOpen = errors.New("cipher: message authentication failed")
+
+// Assert that aesCipherGCM implements the gcmAble interface.
+var _ gcmAble = (*aesCipherGCM)(nil)
+
+// NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only
+// called by crypto/cipher.NewGCM via the gcmAble interface.
+func (c *aesCipherGCM) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
+ g := &gcmAsm{ks: c.enc, nonceSize: nonceSize, tagSize: tagSize}
+ gcmAesInit(&g.productTable, g.ks)
+ return g, nil
+}
+
+type gcmAsm struct {
+ // ks is the key schedule, the length of which depends on the size of
+ // the AES key.
+ ks []uint32
+ // productTable contains pre-computed multiples of the binary-field
+ // element used in GHASH.
+ productTable [256]byte
+ // nonceSize contains the expected size of the nonce, in bytes.
+ nonceSize int
+ // tagSize contains the size of the tag, in bytes.
+ tagSize int
+}
+
+func (g *gcmAsm) NonceSize() int {
+ return g.nonceSize
+}
+
+func (g *gcmAsm) Overhead() int {
+ return g.tagSize
+}
+
+// sliceForAppend takes a slice and a requested number of bytes. It returns a
+// slice with the contents of the given slice followed by that many bytes and a
+// second slice that aliases into it and contains only the extra bytes. If the
+// original slice has sufficient capacity then no allocation is performed.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+ if total := len(in) + n; cap(in) >= total {
+ head = in[:total]
+ } else {
+ head = make([]byte, total)
+ copy(head, in)
+ }
+ tail = head[len(in):]
+ return
+}
+
+// Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for
+// details.
+func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
+ if len(nonce) != g.nonceSize {
+ panic("crypto/cipher: incorrect nonce length given to GCM")
+ }
+ if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
+ panic("crypto/cipher: message too large for GCM")
+ }
+
+ var counter, tagMask [gcmBlockSize]byte
+
+ if len(nonce) == gcmStandardNonceSize {
+ // Init counter to nonce||1
+ copy(counter[:], nonce)
+ counter[gcmBlockSize-1] = 1
+ } else {
+ // Otherwise counter = GHASH(nonce)
+ gcmAesData(&g.productTable, nonce, &counter)
+ gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
+ }
+
+ encryptBlockAsm(len(g.ks)/4-1, &g.ks[0], &tagMask[0], &counter[0])
+
+ var tagOut [gcmTagSize]byte
+ gcmAesData(&g.productTable, data, &tagOut)
+
+ ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
+ if alias.InexactOverlap(out[:len(plaintext)], plaintext) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+ if len(plaintext) > 0 {
+ gcmAesEnc(&g.productTable, out, plaintext, &counter, &tagOut, g.ks)
+ }
+ gcmAesFinish(&g.productTable, &tagMask, &tagOut, uint64(len(plaintext)), uint64(len(data)))
+ copy(out[len(plaintext):], tagOut[:])
+
+ return ret
+}
+
+// Open authenticates and decrypts ciphertext. See the cipher.AEAD interface
+// for details.
+func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
+ if len(nonce) != g.nonceSize {
+ panic("crypto/cipher: incorrect nonce length given to GCM")
+ }
+ // Sanity check to prevent the authentication from always succeeding if an implementation
+ // leaves tagSize uninitialized, for example.
+ if g.tagSize < gcmMinimumTagSize {
+ panic("crypto/cipher: incorrect GCM tag size")
+ }
+
+ if len(ciphertext) < g.tagSize {
+ return nil, errOpen
+ }
+ if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(BlockSize)+uint64(g.tagSize) {
+ return nil, errOpen
+ }
+
+ tag := ciphertext[len(ciphertext)-g.tagSize:]
+ ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
+
+ // See GCM spec, section 7.1.
+ var counter, tagMask [gcmBlockSize]byte
+
+ if len(nonce) == gcmStandardNonceSize {
+ // Init counter to nonce||1
+ copy(counter[:], nonce)
+ counter[gcmBlockSize-1] = 1
+ } else {
+ // Otherwise counter = GHASH(nonce)
+ gcmAesData(&g.productTable, nonce, &counter)
+ gcmAesFinish(&g.productTable, &tagMask, &counter, uint64(len(nonce)), uint64(0))
+ }
+
+ encryptBlockAsm(len(g.ks)/4-1, &g.ks[0], &tagMask[0], &counter[0])
+
+ var expectedTag [gcmTagSize]byte
+ gcmAesData(&g.productTable, data, &expectedTag)
+
+ ret, out := sliceForAppend(dst, len(ciphertext))
+ if alias.InexactOverlap(out, ciphertext) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+ if len(ciphertext) > 0 {
+ gcmAesDec(&g.productTable, out, ciphertext, &counter, &expectedTag, g.ks)
+ }
+ gcmAesFinish(&g.productTable, &tagMask, &expectedTag, uint64(len(ciphertext)), uint64(len(data)))
+
+ if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
+ for i := range out {
+ out[i] = 0
+ }
+ return nil, errOpen
+ }
+
+ return ret, nil
+}
diff --git a/src/crypto/aes/aes_test.go b/src/crypto/aes/aes_test.go
new file mode 100644
index 0000000..1e8bac4
--- /dev/null
+++ b/src/crypto/aes/aes_test.go
@@ -0,0 +1,383 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aes
+
+import (
+ "testing"
+)
+
+// See const.go for overview of math here.
+
+// Test that powx is initialized correctly.
+// (Can adapt this code to generate it too.)
+func TestPowx(t *testing.T) {
+ p := 1
+ for i := 0; i < len(powx); i++ {
+ if powx[i] != byte(p) {
+ t.Errorf("powx[%d] = %#x, want %#x", i, powx[i], p)
+ }
+ p <<= 1
+ if p&0x100 != 0 {
+ p ^= poly
+ }
+ }
+}
+
+// Multiply b and c as GF(2) polynomials modulo poly
+func mul(b, c uint32) uint32 {
+ i := b
+ j := c
+ s := uint32(0)
+ for k := uint32(1); k < 0x100 && j != 0; k <<= 1 {
+ // Invariant: k == 1<<n, i == b * xⁿ
+
+ if j&k != 0 {
+ // s += i in GF(2); xor in binary
+ s ^= i
+ j ^= k // turn off bit to end loop early
+ }
+
+ // i *= x in GF(2) modulo the polynomial
+ i <<= 1
+ if i&0x100 != 0 {
+ i ^= poly
+ }
+ }
+ return s
+}
+
+// Test all mul inputs against bit-by-bit n² algorithm.
+func TestMul(t *testing.T) {
+ for i := uint32(0); i < 256; i++ {
+ for j := uint32(0); j < 256; j++ {
+ // Multiply i, j bit by bit.
+ s := uint8(0)
+ for k := uint(0); k < 8; k++ {
+ for l := uint(0); l < 8; l++ {
+ if i&(1<<k) != 0 && j&(1<<l) != 0 {
+ s ^= powx[k+l]
+ }
+ }
+ }
+ if x := mul(i, j); x != uint32(s) {
+ t.Fatalf("mul(%#x, %#x) = %#x, want %#x", i, j, x, s)
+ }
+ }
+ }
+}
+
+// Check that S-boxes are inverses of each other.
+// They have more structure that we could test,
+// but if this sanity check passes, we'll assume
+// the cut and paste from the FIPS PDF worked.
+func TestSboxes(t *testing.T) {
+ for i := 0; i < 256; i++ {
+ if j := sbox0[sbox1[i]]; j != byte(i) {
+ t.Errorf("sbox0[sbox1[%#x]] = %#x", i, j)
+ }
+ if j := sbox1[sbox0[i]]; j != byte(i) {
+ t.Errorf("sbox1[sbox0[%#x]] = %#x", i, j)
+ }
+ }
+}
+
+// Test that encryption tables are correct.
+// (Can adapt this code to generate them too.)
+func TestTe(t *testing.T) {
+ for i := 0; i < 256; i++ {
+ s := uint32(sbox0[i])
+ s2 := mul(s, 2)
+ s3 := mul(s, 3)
+ w := s2<<24 | s<<16 | s<<8 | s3
+ te := [][256]uint32{te0, te1, te2, te3}
+ for j := 0; j < 4; j++ {
+ if x := te[j][i]; x != w {
+ t.Fatalf("te[%d][%d] = %#x, want %#x", j, i, x, w)
+ }
+ w = w<<24 | w>>8
+ }
+ }
+}
+
+// Test that decryption tables are correct.
+// (Can adapt this code to generate them too.)
+func TestTd(t *testing.T) {
+ for i := 0; i < 256; i++ {
+ s := uint32(sbox1[i])
+ s9 := mul(s, 0x9)
+ sb := mul(s, 0xb)
+ sd := mul(s, 0xd)
+ se := mul(s, 0xe)
+ w := se<<24 | s9<<16 | sd<<8 | sb
+ td := [][256]uint32{td0, td1, td2, td3}
+ for j := 0; j < 4; j++ {
+ if x := td[j][i]; x != w {
+ t.Fatalf("td[%d][%d] = %#x, want %#x", j, i, x, w)
+ }
+ w = w<<24 | w>>8
+ }
+ }
+}
+
+// Test vectors are from FIPS 197:
+// https://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+
+// Appendix A of FIPS 197: Key expansion examples
+type KeyTest struct {
+ key []byte
+ enc []uint32
+ dec []uint32 // decryption expansion; not in FIPS 197, computed from C implementation.
+}
+
+var keyTests = []KeyTest{
+ {
+ // A.1. Expansion of a 128-bit Cipher Key
+ []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c},
+ []uint32{
+ 0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x09cf4f3c,
+ 0xa0fafe17, 0x88542cb1, 0x23a33939, 0x2a6c7605,
+ 0xf2c295f2, 0x7a96b943, 0x5935807a, 0x7359f67f,
+ 0x3d80477d, 0x4716fe3e, 0x1e237e44, 0x6d7a883b,
+ 0xef44a541, 0xa8525b7f, 0xb671253b, 0xdb0bad00,
+ 0xd4d1c6f8, 0x7c839d87, 0xcaf2b8bc, 0x11f915bc,
+ 0x6d88a37a, 0x110b3efd, 0xdbf98641, 0xca0093fd,
+ 0x4e54f70e, 0x5f5fc9f3, 0x84a64fb2, 0x4ea6dc4f,
+ 0xead27321, 0xb58dbad2, 0x312bf560, 0x7f8d292f,
+ 0xac7766f3, 0x19fadc21, 0x28d12941, 0x575c006e,
+ 0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6,
+ },
+ []uint32{
+ 0xd014f9a8, 0xc9ee2589, 0xe13f0cc8, 0xb6630ca6,
+ 0xc7b5a63, 0x1319eafe, 0xb0398890, 0x664cfbb4,
+ 0xdf7d925a, 0x1f62b09d, 0xa320626e, 0xd6757324,
+ 0x12c07647, 0xc01f22c7, 0xbc42d2f3, 0x7555114a,
+ 0x6efcd876, 0xd2df5480, 0x7c5df034, 0xc917c3b9,
+ 0x6ea30afc, 0xbc238cf6, 0xae82a4b4, 0xb54a338d,
+ 0x90884413, 0xd280860a, 0x12a12842, 0x1bc89739,
+ 0x7c1f13f7, 0x4208c219, 0xc021ae48, 0x969bf7b,
+ 0xcc7505eb, 0x3e17d1ee, 0x82296c51, 0xc9481133,
+ 0x2b3708a7, 0xf262d405, 0xbc3ebdbf, 0x4b617d62,
+ 0x2b7e1516, 0x28aed2a6, 0xabf71588, 0x9cf4f3c,
+ },
+ },
+ {
+ // A.2. Expansion of a 192-bit Cipher Key
+ []byte{
+ 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
+ 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b,
+ },
+ []uint32{
+ 0x8e73b0f7, 0xda0e6452, 0xc810f32b, 0x809079e5,
+ 0x62f8ead2, 0x522c6b7b, 0xfe0c91f7, 0x2402f5a5,
+ 0xec12068e, 0x6c827f6b, 0x0e7a95b9, 0x5c56fec2,
+ 0x4db7b4bd, 0x69b54118, 0x85a74796, 0xe92538fd,
+ 0xe75fad44, 0xbb095386, 0x485af057, 0x21efb14f,
+ 0xa448f6d9, 0x4d6dce24, 0xaa326360, 0x113b30e6,
+ 0xa25e7ed5, 0x83b1cf9a, 0x27f93943, 0x6a94f767,
+ 0xc0a69407, 0xd19da4e1, 0xec1786eb, 0x6fa64971,
+ 0x485f7032, 0x22cb8755, 0xe26d1352, 0x33f0b7b3,
+ 0x40beeb28, 0x2f18a259, 0x6747d26b, 0x458c553e,
+ 0xa7e1466c, 0x9411f1df, 0x821f750a, 0xad07d753,
+ 0xca400538, 0x8fcc5006, 0x282d166a, 0xbc3ce7b5,
+ 0xe98ba06f, 0x448c773c, 0x8ecc7204, 0x01002202,
+ },
+ nil,
+ },
+ {
+ // A.3. Expansion of a 256-bit Cipher Key
+ []byte{
+ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+ 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4,
+ },
+ []uint32{
+ 0x603deb10, 0x15ca71be, 0x2b73aef0, 0x857d7781,
+ 0x1f352c07, 0x3b6108d7, 0x2d9810a3, 0x0914dff4,
+ 0x9ba35411, 0x8e6925af, 0xa51a8b5f, 0x2067fcde,
+ 0xa8b09c1a, 0x93d194cd, 0xbe49846e, 0xb75d5b9a,
+ 0xd59aecb8, 0x5bf3c917, 0xfee94248, 0xde8ebe96,
+ 0xb5a9328a, 0x2678a647, 0x98312229, 0x2f6c79b3,
+ 0x812c81ad, 0xdadf48ba, 0x24360af2, 0xfab8b464,
+ 0x98c5bfc9, 0xbebd198e, 0x268c3ba7, 0x09e04214,
+ 0x68007bac, 0xb2df3316, 0x96e939e4, 0x6c518d80,
+ 0xc814e204, 0x76a9fb8a, 0x5025c02d, 0x59c58239,
+ 0xde136967, 0x6ccc5a71, 0xfa256395, 0x9674ee15,
+ 0x5886ca5d, 0x2e2f31d7, 0x7e0af1fa, 0x27cf73c3,
+ 0x749c47ab, 0x18501dda, 0xe2757e4f, 0x7401905a,
+ 0xcafaaae3, 0xe4d59b34, 0x9adf6ace, 0xbd10190d,
+ 0xfe4890d1, 0xe6188d0b, 0x046df344, 0x706c631e,
+ },
+ nil,
+ },
+}
+
+// Test key expansion against FIPS 197 examples.
+func TestExpandKey(t *testing.T) {
+L:
+ for i, tt := range keyTests {
+ enc := make([]uint32, len(tt.enc))
+ var dec []uint32
+ if tt.dec != nil {
+ dec = make([]uint32, len(tt.dec))
+ }
+ // This test could only test Go version of expandKey because asm
+ // version might use different memory layout for expanded keys
+ // This is OK because we don't expose expanded keys to the outside
+ expandKeyGo(tt.key, enc, dec)
+ for j, v := range enc {
+ if v != tt.enc[j] {
+ t.Errorf("key %d: enc[%d] = %#x, want %#x", i, j, v, tt.enc[j])
+ continue L
+ }
+ }
+ for j, v := range dec {
+ if v != tt.dec[j] {
+ t.Errorf("key %d: dec[%d] = %#x, want %#x", i, j, v, tt.dec[j])
+ continue L
+ }
+ }
+ }
+}
+
+// Appendix B, C of FIPS 197: Cipher examples, Example vectors.
+type CryptTest struct {
+ key []byte
+ in []byte
+ out []byte
+}
+
+var encryptTests = []CryptTest{
+ {
+ // Appendix B.
+ []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c},
+ []byte{0x32, 0x43, 0xf6, 0xa8, 0x88, 0x5a, 0x30, 0x8d, 0x31, 0x31, 0x98, 0xa2, 0xe0, 0x37, 0x07, 0x34},
+ []byte{0x39, 0x25, 0x84, 0x1d, 0x02, 0xdc, 0x09, 0xfb, 0xdc, 0x11, 0x85, 0x97, 0x19, 0x6a, 0x0b, 0x32},
+ },
+ {
+ // Appendix C.1. AES-128
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f},
+ []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+ []byte{0x69, 0xc4, 0xe0, 0xd8, 0x6a, 0x7b, 0x04, 0x30, 0xd8, 0xcd, 0xb7, 0x80, 0x70, 0xb4, 0xc5, 0x5a},
+ },
+ {
+ // Appendix C.2. AES-192
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ },
+ []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+ []byte{0xdd, 0xa9, 0x7c, 0xa4, 0x86, 0x4c, 0xdf, 0xe0, 0x6e, 0xaf, 0x70, 0xa0, 0xec, 0x0d, 0x71, 0x91},
+ },
+ {
+ // Appendix C.3. AES-256
+ []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ },
+ []byte{0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88, 0x99, 0xaa, 0xbb, 0xcc, 0xdd, 0xee, 0xff},
+ []byte{0x8e, 0xa2, 0xb7, 0xca, 0x51, 0x67, 0x45, 0xbf, 0xea, 0xfc, 0x49, 0x90, 0x4b, 0x49, 0x60, 0x89},
+ },
+}
+
+// Test Cipher Encrypt method against FIPS 197 examples.
+func TestCipherEncrypt(t *testing.T) {
+ for i, tt := range encryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+ continue
+ }
+ out := make([]byte, len(tt.in))
+ c.Encrypt(out, tt.in)
+ for j, v := range out {
+ if v != tt.out[j] {
+ t.Errorf("Cipher.Encrypt %d: out[%d] = %#x, want %#x", i, j, v, tt.out[j])
+ break
+ }
+ }
+ }
+}
+
+// Test Cipher Decrypt against FIPS 197 examples.
+func TestCipherDecrypt(t *testing.T) {
+ for i, tt := range encryptTests {
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("NewCipher(%d bytes) = %s", len(tt.key), err)
+ continue
+ }
+ plain := make([]byte, len(tt.in))
+ c.Decrypt(plain, tt.out)
+ for j, v := range plain {
+ if v != tt.in[j] {
+ t.Errorf("decryptBlock %d: plain[%d] = %#x, want %#x", i, j, v, tt.in[j])
+ break
+ }
+ }
+ }
+}
+
+// Test short input/output.
+// Assembly used to not notice.
+// See issue 7928.
+func TestShortBlocks(t *testing.T) {
+ bytes := func(n int) []byte { return make([]byte, n) }
+
+ c, _ := NewCipher(bytes(16))
+
+ mustPanic(t, "crypto/aes: input not full block", func() { c.Encrypt(bytes(1), bytes(1)) })
+ mustPanic(t, "crypto/aes: input not full block", func() { c.Decrypt(bytes(1), bytes(1)) })
+ mustPanic(t, "crypto/aes: input not full block", func() { c.Encrypt(bytes(100), bytes(1)) })
+ mustPanic(t, "crypto/aes: input not full block", func() { c.Decrypt(bytes(100), bytes(1)) })
+ mustPanic(t, "crypto/aes: output not full block", func() { c.Encrypt(bytes(1), bytes(100)) })
+ mustPanic(t, "crypto/aes: output not full block", func() { c.Decrypt(bytes(1), bytes(100)) })
+}
+
+func mustPanic(t *testing.T, msg string, f func()) {
+ defer func() {
+ err := recover()
+ if err == nil {
+ t.Errorf("function did not panic, wanted %q", msg)
+ } else if err != msg {
+ t.Errorf("got panic %v, wanted %q", err, msg)
+ }
+ }()
+ f()
+}
+
+func BenchmarkEncrypt(b *testing.B) {
+ tt := encryptTests[0]
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ b.Fatal("NewCipher:", err)
+ }
+ out := make([]byte, len(tt.in))
+ b.SetBytes(int64(len(out)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ c.Encrypt(out, tt.in)
+ }
+}
+
+func BenchmarkDecrypt(b *testing.B) {
+ tt := encryptTests[0]
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ b.Fatal("NewCipher:", err)
+ }
+ out := make([]byte, len(tt.out))
+ b.SetBytes(int64(len(out)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ c.Decrypt(out, tt.out)
+ }
+}
+
+func BenchmarkExpand(b *testing.B) {
+ tt := encryptTests[0]
+ n := len(tt.key) + 28
+ c := &aesCipher{make([]uint32, n), make([]uint32, n)}
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ expandKey(tt.key, c.enc, c.dec)
+ }
+}
diff --git a/src/crypto/aes/asm_amd64.s b/src/crypto/aes/asm_amd64.s
new file mode 100644
index 0000000..ed831bf
--- /dev/null
+++ b/src/crypto/aes/asm_amd64.s
@@ -0,0 +1,274 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
+TEXT ·encryptBlockAsm(SB),NOSPLIT,$0
+ MOVQ nr+0(FP), CX
+ MOVQ xk+8(FP), AX
+ MOVQ dst+16(FP), DX
+ MOVQ src+24(FP), BX
+ MOVUPS 0(AX), X1
+ MOVUPS 0(BX), X0
+ ADDQ $16, AX
+ PXOR X1, X0
+ SUBQ $12, CX
+ JE Lenc192
+ JB Lenc128
+Lenc256:
+ MOVUPS 0(AX), X1
+ AESENC X1, X0
+ MOVUPS 16(AX), X1
+ AESENC X1, X0
+ ADDQ $32, AX
+Lenc192:
+ MOVUPS 0(AX), X1
+ AESENC X1, X0
+ MOVUPS 16(AX), X1
+ AESENC X1, X0
+ ADDQ $32, AX
+Lenc128:
+ MOVUPS 0(AX), X1
+ AESENC X1, X0
+ MOVUPS 16(AX), X1
+ AESENC X1, X0
+ MOVUPS 32(AX), X1
+ AESENC X1, X0
+ MOVUPS 48(AX), X1
+ AESENC X1, X0
+ MOVUPS 64(AX), X1
+ AESENC X1, X0
+ MOVUPS 80(AX), X1
+ AESENC X1, X0
+ MOVUPS 96(AX), X1
+ AESENC X1, X0
+ MOVUPS 112(AX), X1
+ AESENC X1, X0
+ MOVUPS 128(AX), X1
+ AESENC X1, X0
+ MOVUPS 144(AX), X1
+ AESENCLAST X1, X0
+ MOVUPS X0, 0(DX)
+ RET
+
+// func decryptBlockAsm(nr int, xk *uint32, dst, src *byte)
+TEXT ·decryptBlockAsm(SB),NOSPLIT,$0
+ MOVQ nr+0(FP), CX
+ MOVQ xk+8(FP), AX
+ MOVQ dst+16(FP), DX
+ MOVQ src+24(FP), BX
+ MOVUPS 0(AX), X1
+ MOVUPS 0(BX), X0
+ ADDQ $16, AX
+ PXOR X1, X0
+ SUBQ $12, CX
+ JE Ldec192
+ JB Ldec128
+Ldec256:
+ MOVUPS 0(AX), X1
+ AESDEC X1, X0
+ MOVUPS 16(AX), X1
+ AESDEC X1, X0
+ ADDQ $32, AX
+Ldec192:
+ MOVUPS 0(AX), X1
+ AESDEC X1, X0
+ MOVUPS 16(AX), X1
+ AESDEC X1, X0
+ ADDQ $32, AX
+Ldec128:
+ MOVUPS 0(AX), X1
+ AESDEC X1, X0
+ MOVUPS 16(AX), X1
+ AESDEC X1, X0
+ MOVUPS 32(AX), X1
+ AESDEC X1, X0
+ MOVUPS 48(AX), X1
+ AESDEC X1, X0
+ MOVUPS 64(AX), X1
+ AESDEC X1, X0
+ MOVUPS 80(AX), X1
+ AESDEC X1, X0
+ MOVUPS 96(AX), X1
+ AESDEC X1, X0
+ MOVUPS 112(AX), X1
+ AESDEC X1, X0
+ MOVUPS 128(AX), X1
+ AESDEC X1, X0
+ MOVUPS 144(AX), X1
+ AESDECLAST X1, X0
+ MOVUPS X0, 0(DX)
+ RET
+
+// func expandKeyAsm(nr int, key *byte, enc, dec *uint32) {
+// Note that round keys are stored in uint128 format, not uint32
+TEXT ·expandKeyAsm(SB),NOSPLIT,$0
+ MOVQ nr+0(FP), CX
+ MOVQ key+8(FP), AX
+ MOVQ enc+16(FP), BX
+ MOVQ dec+24(FP), DX
+ MOVUPS (AX), X0
+ // enc
+ MOVUPS X0, (BX)
+ ADDQ $16, BX
+ PXOR X4, X4 // _expand_key_* expect X4 to be zero
+ CMPL CX, $12
+ JE Lexp_enc192
+ JB Lexp_enc128
+Lexp_enc256:
+ MOVUPS 16(AX), X2
+ MOVUPS X2, (BX)
+ ADDQ $16, BX
+ AESKEYGENASSIST $0x01, X2, X1
+ CALL _expand_key_256a<>(SB)
+ AESKEYGENASSIST $0x01, X0, X1
+ CALL _expand_key_256b<>(SB)
+ AESKEYGENASSIST $0x02, X2, X1
+ CALL _expand_key_256a<>(SB)
+ AESKEYGENASSIST $0x02, X0, X1
+ CALL _expand_key_256b<>(SB)
+ AESKEYGENASSIST $0x04, X2, X1
+ CALL _expand_key_256a<>(SB)
+ AESKEYGENASSIST $0x04, X0, X1
+ CALL _expand_key_256b<>(SB)
+ AESKEYGENASSIST $0x08, X2, X1
+ CALL _expand_key_256a<>(SB)
+ AESKEYGENASSIST $0x08, X0, X1
+ CALL _expand_key_256b<>(SB)
+ AESKEYGENASSIST $0x10, X2, X1
+ CALL _expand_key_256a<>(SB)
+ AESKEYGENASSIST $0x10, X0, X1
+ CALL _expand_key_256b<>(SB)
+ AESKEYGENASSIST $0x20, X2, X1
+ CALL _expand_key_256a<>(SB)
+ AESKEYGENASSIST $0x20, X0, X1
+ CALL _expand_key_256b<>(SB)
+ AESKEYGENASSIST $0x40, X2, X1
+ CALL _expand_key_256a<>(SB)
+ JMP Lexp_dec
+Lexp_enc192:
+ MOVQ 16(AX), X2
+ AESKEYGENASSIST $0x01, X2, X1
+ CALL _expand_key_192a<>(SB)
+ AESKEYGENASSIST $0x02, X2, X1
+ CALL _expand_key_192b<>(SB)
+ AESKEYGENASSIST $0x04, X2, X1
+ CALL _expand_key_192a<>(SB)
+ AESKEYGENASSIST $0x08, X2, X1
+ CALL _expand_key_192b<>(SB)
+ AESKEYGENASSIST $0x10, X2, X1
+ CALL _expand_key_192a<>(SB)
+ AESKEYGENASSIST $0x20, X2, X1
+ CALL _expand_key_192b<>(SB)
+ AESKEYGENASSIST $0x40, X2, X1
+ CALL _expand_key_192a<>(SB)
+ AESKEYGENASSIST $0x80, X2, X1
+ CALL _expand_key_192b<>(SB)
+ JMP Lexp_dec
+Lexp_enc128:
+ AESKEYGENASSIST $0x01, X0, X1
+ CALL _expand_key_128<>(SB)
+ AESKEYGENASSIST $0x02, X0, X1
+ CALL _expand_key_128<>(SB)
+ AESKEYGENASSIST $0x04, X0, X1
+ CALL _expand_key_128<>(SB)
+ AESKEYGENASSIST $0x08, X0, X1
+ CALL _expand_key_128<>(SB)
+ AESKEYGENASSIST $0x10, X0, X1
+ CALL _expand_key_128<>(SB)
+ AESKEYGENASSIST $0x20, X0, X1
+ CALL _expand_key_128<>(SB)
+ AESKEYGENASSIST $0x40, X0, X1
+ CALL _expand_key_128<>(SB)
+ AESKEYGENASSIST $0x80, X0, X1
+ CALL _expand_key_128<>(SB)
+ AESKEYGENASSIST $0x1b, X0, X1
+ CALL _expand_key_128<>(SB)
+ AESKEYGENASSIST $0x36, X0, X1
+ CALL _expand_key_128<>(SB)
+Lexp_dec:
+ // dec
+ SUBQ $16, BX
+ MOVUPS (BX), X1
+ MOVUPS X1, (DX)
+ DECQ CX
+Lexp_dec_loop:
+ MOVUPS -16(BX), X1
+ AESIMC X1, X0
+ MOVUPS X0, 16(DX)
+ SUBQ $16, BX
+ ADDQ $16, DX
+ DECQ CX
+ JNZ Lexp_dec_loop
+ MOVUPS -16(BX), X0
+ MOVUPS X0, 16(DX)
+ RET
+
+TEXT _expand_key_128<>(SB),NOSPLIT,$0
+ PSHUFD $0xff, X1, X1
+ SHUFPS $0x10, X0, X4
+ PXOR X4, X0
+ SHUFPS $0x8c, X0, X4
+ PXOR X4, X0
+ PXOR X1, X0
+ MOVUPS X0, (BX)
+ ADDQ $16, BX
+ RET
+
+TEXT _expand_key_192a<>(SB),NOSPLIT,$0
+ PSHUFD $0x55, X1, X1
+ SHUFPS $0x10, X0, X4
+ PXOR X4, X0
+ SHUFPS $0x8c, X0, X4
+ PXOR X4, X0
+ PXOR X1, X0
+
+ MOVAPS X2, X5
+ MOVAPS X2, X6
+ PSLLDQ $0x4, X5
+ PSHUFD $0xff, X0, X3
+ PXOR X3, X2
+ PXOR X5, X2
+
+ MOVAPS X0, X1
+ SHUFPS $0x44, X0, X6
+ MOVUPS X6, (BX)
+ SHUFPS $0x4e, X2, X1
+ MOVUPS X1, 16(BX)
+ ADDQ $32, BX
+ RET
+
+TEXT _expand_key_192b<>(SB),NOSPLIT,$0
+ PSHUFD $0x55, X1, X1
+ SHUFPS $0x10, X0, X4
+ PXOR X4, X0
+ SHUFPS $0x8c, X0, X4
+ PXOR X4, X0
+ PXOR X1, X0
+
+ MOVAPS X2, X5
+ PSLLDQ $0x4, X5
+ PSHUFD $0xff, X0, X3
+ PXOR X3, X2
+ PXOR X5, X2
+
+ MOVUPS X0, (BX)
+ ADDQ $16, BX
+ RET
+
+TEXT _expand_key_256a<>(SB),NOSPLIT,$0
+ JMP _expand_key_128<>(SB)
+
+TEXT _expand_key_256b<>(SB),NOSPLIT,$0
+ PSHUFD $0xaa, X1, X1
+ SHUFPS $0x10, X2, X4
+ PXOR X4, X2
+ SHUFPS $0x8c, X2, X4
+ PXOR X4, X2
+ PXOR X1, X2
+
+ MOVUPS X2, (BX)
+ ADDQ $16, BX
+ RET
diff --git a/src/crypto/aes/asm_arm64.s b/src/crypto/aes/asm_arm64.s
new file mode 100644
index 0000000..13aee5c
--- /dev/null
+++ b/src/crypto/aes/asm_arm64.s
@@ -0,0 +1,281 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+DATA rotInvSRows<>+0x00(SB)/8, $0x080f0205040b0e01
+DATA rotInvSRows<>+0x08(SB)/8, $0x00070a0d0c030609
+GLOBL rotInvSRows<>(SB), (NOPTR+RODATA), $16
+DATA invSRows<>+0x00(SB)/8, $0x0b0e0104070a0d00
+DATA invSRows<>+0x08(SB)/8, $0x0306090c0f020508
+GLOBL invSRows<>(SB), (NOPTR+RODATA), $16
+// func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
+TEXT ·encryptBlockAsm(SB),NOSPLIT,$0
+ MOVD nr+0(FP), R9
+ MOVD xk+8(FP), R10
+ MOVD dst+16(FP), R11
+ MOVD src+24(FP), R12
+
+ VLD1 (R12), [V0.B16]
+
+ CMP $12, R9
+ BLT enc128
+ BEQ enc196
+enc256:
+ VLD1.P 32(R10), [V1.B16, V2.B16]
+ AESE V1.B16, V0.B16
+ AESMC V0.B16, V0.B16
+ AESE V2.B16, V0.B16
+ AESMC V0.B16, V0.B16
+enc196:
+ VLD1.P 32(R10), [V3.B16, V4.B16]
+ AESE V3.B16, V0.B16
+ AESMC V0.B16, V0.B16
+ AESE V4.B16, V0.B16
+ AESMC V0.B16, V0.B16
+enc128:
+ VLD1.P 64(R10), [V5.B16, V6.B16, V7.B16, V8.B16]
+ VLD1.P 64(R10), [V9.B16, V10.B16, V11.B16, V12.B16]
+ VLD1.P 48(R10), [V13.B16, V14.B16, V15.B16]
+ AESE V5.B16, V0.B16
+ AESMC V0.B16, V0.B16
+ AESE V6.B16, V0.B16
+ AESMC V0.B16, V0.B16
+ AESE V7.B16, V0.B16
+ AESMC V0.B16, V0.B16
+ AESE V8.B16, V0.B16
+ AESMC V0.B16, V0.B16
+ AESE V9.B16, V0.B16
+ AESMC V0.B16, V0.B16
+ AESE V10.B16, V0.B16
+ AESMC V0.B16, V0.B16
+ AESE V11.B16, V0.B16
+ AESMC V0.B16, V0.B16
+ AESE V12.B16, V0.B16
+ AESMC V0.B16, V0.B16
+ AESE V13.B16, V0.B16
+ AESMC V0.B16, V0.B16
+ AESE V14.B16, V0.B16
+ VEOR V0.B16, V15.B16, V0.B16
+ VST1 [V0.B16], (R11)
+ RET
+
+// func decryptBlockAsm(nr int, xk *uint32, dst, src *byte)
+TEXT ·decryptBlockAsm(SB),NOSPLIT,$0
+ MOVD nr+0(FP), R9
+ MOVD xk+8(FP), R10
+ MOVD dst+16(FP), R11
+ MOVD src+24(FP), R12
+
+ VLD1 (R12), [V0.B16]
+
+ CMP $12, R9
+ BLT dec128
+ BEQ dec196
+dec256:
+ VLD1.P 32(R10), [V1.B16, V2.B16]
+ AESD V1.B16, V0.B16
+ AESIMC V0.B16, V0.B16
+ AESD V2.B16, V0.B16
+ AESIMC V0.B16, V0.B16
+dec196:
+ VLD1.P 32(R10), [V3.B16, V4.B16]
+ AESD V3.B16, V0.B16
+ AESIMC V0.B16, V0.B16
+ AESD V4.B16, V0.B16
+ AESIMC V0.B16, V0.B16
+dec128:
+ VLD1.P 64(R10), [V5.B16, V6.B16, V7.B16, V8.B16]
+ VLD1.P 64(R10), [V9.B16, V10.B16, V11.B16, V12.B16]
+ VLD1.P 48(R10), [V13.B16, V14.B16, V15.B16]
+ AESD V5.B16, V0.B16
+ AESIMC V0.B16, V0.B16
+ AESD V6.B16, V0.B16
+ AESIMC V0.B16, V0.B16
+ AESD V7.B16, V0.B16
+ AESIMC V0.B16, V0.B16
+ AESD V8.B16, V0.B16
+ AESIMC V0.B16, V0.B16
+ AESD V9.B16, V0.B16
+ AESIMC V0.B16, V0.B16
+ AESD V10.B16, V0.B16
+ AESIMC V0.B16, V0.B16
+ AESD V11.B16, V0.B16
+ AESIMC V0.B16, V0.B16
+ AESD V12.B16, V0.B16
+ AESIMC V0.B16, V0.B16
+ AESD V13.B16, V0.B16
+ AESIMC V0.B16, V0.B16
+ AESD V14.B16, V0.B16
+ VEOR V0.B16, V15.B16, V0.B16
+ VST1 [V0.B16], (R11)
+ RET
+
+// func expandKeyAsm(nr int, key *byte, enc, dec *uint32) {
+// Note that round keys are stored in uint128 format, not uint32
+TEXT ·expandKeyAsm(SB),NOSPLIT,$0
+ MOVD nr+0(FP), R8
+ MOVD key+8(FP), R9
+ MOVD enc+16(FP), R10
+ MOVD dec+24(FP), R11
+ LDP rotInvSRows<>(SB), (R0, R1)
+ VMOV R0, V3.D[0]
+ VMOV R1, V3.D[1]
+ VEOR V0.B16, V0.B16, V0.B16 // All zeroes
+ MOVW $1, R13
+ TBZ $1, R8, ks192
+ TBNZ $2, R8, ks256
+ LDPW (R9), (R4, R5)
+ LDPW 8(R9), (R6, R7)
+ STPW.P (R4, R5), 8(R10)
+ STPW.P (R6, R7), 8(R10)
+ MOVW $0x1b, R14
+ks128Loop:
+ VMOV R7, V2.S[0]
+ WORD $0x4E030042 // TBL V3.B16, [V2.B16], V2.B16
+ AESE V0.B16, V2.B16 // Use AES to compute the SBOX
+ EORW R13, R4
+ LSLW $1, R13 // Compute next Rcon
+ ANDSW $0x100, R13, ZR
+ CSELW NE, R14, R13, R13 // Fake modulo
+ SUBS $1, R8
+ VMOV V2.S[0], R0
+ EORW R0, R4
+ EORW R4, R5
+ EORW R5, R6
+ EORW R6, R7
+ STPW.P (R4, R5), 8(R10)
+ STPW.P (R6, R7), 8(R10)
+ BNE ks128Loop
+ CBZ R11, ksDone // If dec is nil we are done
+ SUB $176, R10
+ // Decryption keys are encryption keys with InverseMixColumns applied
+ VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16]
+ VMOV V0.B16, V7.B16
+ AESIMC V1.B16, V6.B16
+ AESIMC V2.B16, V5.B16
+ AESIMC V3.B16, V4.B16
+ VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16]
+ AESIMC V0.B16, V11.B16
+ AESIMC V1.B16, V10.B16
+ AESIMC V2.B16, V9.B16
+ AESIMC V3.B16, V8.B16
+ VLD1 (R10), [V0.B16, V1.B16, V2.B16]
+ AESIMC V0.B16, V14.B16
+ AESIMC V1.B16, V13.B16
+ VMOV V2.B16, V12.B16
+ VST1.P [V12.B16, V13.B16, V14.B16], 48(R11)
+ VST1.P [V8.B16, V9.B16, V10.B16, V11.B16], 64(R11)
+ VST1 [V4.B16, V5.B16, V6.B16, V7.B16], (R11)
+ B ksDone
+ks192:
+ LDPW (R9), (R2, R3)
+ LDPW 8(R9), (R4, R5)
+ LDPW 16(R9), (R6, R7)
+ STPW.P (R2, R3), 8(R10)
+ STPW.P (R4, R5), 8(R10)
+ SUB $4, R8
+ks192Loop:
+ STPW.P (R6, R7), 8(R10)
+ VMOV R7, V2.S[0]
+ WORD $0x4E030042 //TBL V3.B16, [V2.B16], V2.B16
+ AESE V0.B16, V2.B16
+ EORW R13, R2
+ LSLW $1, R13
+ SUBS $1, R8
+ VMOV V2.S[0], R0
+ EORW R0, R2
+ EORW R2, R3
+ EORW R3, R4
+ EORW R4, R5
+ EORW R5, R6
+ EORW R6, R7
+ STPW.P (R2, R3), 8(R10)
+ STPW.P (R4, R5), 8(R10)
+ BNE ks192Loop
+ CBZ R11, ksDone
+ SUB $208, R10
+ VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16]
+ VMOV V0.B16, V7.B16
+ AESIMC V1.B16, V6.B16
+ AESIMC V2.B16, V5.B16
+ AESIMC V3.B16, V4.B16
+ VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16]
+ AESIMC V0.B16, V11.B16
+ AESIMC V1.B16, V10.B16
+ AESIMC V2.B16, V9.B16
+ AESIMC V3.B16, V8.B16
+ VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16]
+ AESIMC V0.B16, V15.B16
+ AESIMC V1.B16, V14.B16
+ AESIMC V2.B16, V13.B16
+ AESIMC V3.B16, V12.B16
+ VLD1 (R10), [V0.B16]
+ VST1.P [V0.B16], 16(R11)
+ VST1.P [V12.B16, V13.B16, V14.B16, V15.B16], 64(R11)
+ VST1.P [V8.B16, V9.B16, V10.B16, V11.B16], 64(R11)
+ VST1 [V4.B16, V5.B16, V6.B16, V7.B16], (R11)
+ B ksDone
+ks256:
+ LDP invSRows<>(SB), (R0, R1)
+ VMOV R0, V4.D[0]
+ VMOV R1, V4.D[1]
+ LDPW (R9), (R0, R1)
+ LDPW 8(R9), (R2, R3)
+ LDPW 16(R9), (R4, R5)
+ LDPW 24(R9), (R6, R7)
+ STPW.P (R0, R1), 8(R10)
+ STPW.P (R2, R3), 8(R10)
+ SUB $7, R8
+ks256Loop:
+ STPW.P (R4, R5), 8(R10)
+ STPW.P (R6, R7), 8(R10)
+ VMOV R7, V2.S[0]
+ WORD $0x4E030042 //TBL V3.B16, [V2.B16], V2.B16
+ AESE V0.B16, V2.B16
+ EORW R13, R0
+ LSLW $1, R13
+ SUBS $1, R8
+ VMOV V2.S[0], R9
+ EORW R9, R0
+ EORW R0, R1
+ EORW R1, R2
+ EORW R2, R3
+ VMOV R3, V2.S[0]
+ WORD $0x4E040042 //TBL V3.B16, [V2.B16], V2.B16
+ AESE V0.B16, V2.B16
+ VMOV V2.S[0], R9
+ EORW R9, R4
+ EORW R4, R5
+ EORW R5, R6
+ EORW R6, R7
+ STPW.P (R0, R1), 8(R10)
+ STPW.P (R2, R3), 8(R10)
+ BNE ks256Loop
+ CBZ R11, ksDone
+ SUB $240, R10
+ VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16]
+ VMOV V0.B16, V7.B16
+ AESIMC V1.B16, V6.B16
+ AESIMC V2.B16, V5.B16
+ AESIMC V3.B16, V4.B16
+ VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16]
+ AESIMC V0.B16, V11.B16
+ AESIMC V1.B16, V10.B16
+ AESIMC V2.B16, V9.B16
+ AESIMC V3.B16, V8.B16
+ VLD1.P 64(R10), [V0.B16, V1.B16, V2.B16, V3.B16]
+ AESIMC V0.B16, V15.B16
+ AESIMC V1.B16, V14.B16
+ AESIMC V2.B16, V13.B16
+ AESIMC V3.B16, V12.B16
+ VLD1 (R10), [V0.B16, V1.B16, V2.B16]
+ AESIMC V0.B16, V18.B16
+ AESIMC V1.B16, V17.B16
+ VMOV V2.B16, V16.B16
+ VST1.P [V16.B16, V17.B16, V18.B16], 48(R11)
+ VST1.P [V12.B16, V13.B16, V14.B16, V15.B16], 64(R11)
+ VST1.P [V8.B16, V9.B16, V10.B16, V11.B16], 64(R11)
+ VST1 [V4.B16, V5.B16, V6.B16, V7.B16], (R11)
+ksDone:
+ RET
diff --git a/src/crypto/aes/asm_ppc64x.s b/src/crypto/aes/asm_ppc64x.s
new file mode 100644
index 0000000..8ac97ec
--- /dev/null
+++ b/src/crypto/aes/asm_ppc64x.s
@@ -0,0 +1,675 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build ppc64 || ppc64le
+
+// Based on CRYPTOGAMS code with the following comment:
+// # ====================================================================
+// # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+// # project. The module is, however, dual licensed under OpenSSL and
+// # CRYPTOGAMS licenses depending on where you obtain it. For further
+// # details see http://www.openssl.org/~appro/cryptogams/.
+// # ====================================================================
+
+// Original code can be found at the link below:
+// https://github.com/dot-asm/cryptogams/blob/master/ppc/aesp8-ppc.pl
+
+// Some function names were changed to be consistent with Go function
+// names. For instance, function aes_p8_set_{en,de}crypt_key become
+// set{En,De}cryptKeyAsm. I also split setEncryptKeyAsm in two parts
+// and a new session was created (doEncryptKeyAsm). This was necessary to
+// avoid arguments overwriting when setDecryptKeyAsm calls setEncryptKeyAsm.
+// There were other modifications as well but kept the same functionality.
+
+#include "textflag.h"
+
+// For expandKeyAsm
+#define INP R3
+#define BITS R4
+#define OUTENC R5 // Pointer to next expanded encrypt key
+#define PTR R6
+#define CNT R7
+#define ROUNDS R8
+#define OUTDEC R9 // Pointer to next expanded decrypt key
+#define TEMP R19
+#define ZERO V0
+#define IN0 V1
+#define IN1 V2
+#define KEY V3
+#define RCON V4
+#define MASK V5
+#define TMP V6
+#define STAGE V7
+#define OUTPERM V8
+#define OUTMASK V9
+#define OUTHEAD V10
+#define OUTTAIL V11
+
+// For P9 instruction emulation
+#define ESPERM V21 // Endian swapping permute into BE
+#define TMP2 V22 // Temporary for P8_STXVB16X/P8_STXVB16X
+
+// For {en,de}cryptBlockAsm
+#define BLK_INP R3
+#define BLK_OUT R4
+#define BLK_KEY R5
+#define BLK_ROUNDS R6
+#define BLK_IDX R7
+
+DATA ·rcon+0x00(SB)/8, $0x0f0e0d0c0b0a0908 // Permute for vector doubleword endian swap
+DATA ·rcon+0x08(SB)/8, $0x0706050403020100
+DATA ·rcon+0x10(SB)/8, $0x0100000001000000 // RCON
+DATA ·rcon+0x18(SB)/8, $0x0100000001000000 // RCON
+DATA ·rcon+0x20(SB)/8, $0x1b0000001b000000
+DATA ·rcon+0x28(SB)/8, $0x1b0000001b000000
+DATA ·rcon+0x30(SB)/8, $0x0d0e0f0c0d0e0f0c // MASK
+DATA ·rcon+0x38(SB)/8, $0x0d0e0f0c0d0e0f0c // MASK
+DATA ·rcon+0x40(SB)/8, $0x0000000000000000
+DATA ·rcon+0x48(SB)/8, $0x0000000000000000
+GLOBL ·rcon(SB), RODATA, $80
+
+#ifdef GOARCH_ppc64le
+# ifdef GOPPC64_power9
+#define P8_LXVB16X(RA,RB,VT) LXVB16X (RA+RB), VT
+#define P8_STXVB16X(VS,RA,RB) STXVB16X VS, (RA+RB)
+#define XXBRD_ON_LE(VA,VT) XXBRD VA, VT
+# else
+// On POWER8/ppc64le, emulate the POWER9 instructions by loading unaligned
+// doublewords and byte-swapping each doubleword to emulate BE load/stores.
+#define NEEDS_ESPERM
+#define P8_LXVB16X(RA,RB,VT) \
+ LXVD2X (RA+RB), VT \
+ VPERM VT, VT, ESPERM, VT
+
+#define P8_STXVB16X(VS,RA,RB) \
+ VPERM VS, VS, ESPERM, TMP2 \
+ STXVD2X TMP2, (RA+RB)
+
+#define XXBRD_ON_LE(VA,VT) \
+ VPERM VA, VA, ESPERM, VT
+
+# endif // defined(GOPPC64_power9)
+#else
+#define P8_LXVB16X(RA,RB,VT) LXVD2X (RA+RB), VT
+#define P8_STXVB16X(VS,RA,RB) STXVD2X VS, (RA+RB)
+#define XXBRD_ON_LE(VA, VT)
+#endif // defined(GOARCH_ppc64le)
+
+// func setEncryptKeyAsm(nr int, key *byte, enc *uint32, dec *uint32)
+TEXT ·expandKeyAsm(SB), NOSPLIT|NOFRAME, $0
+ // Load the arguments inside the registers
+ MOVD nr+0(FP), ROUNDS
+ MOVD key+8(FP), INP
+ MOVD enc+16(FP), OUTENC
+ MOVD dec+24(FP), OUTDEC
+
+#ifdef NEEDS_ESPERM
+ MOVD $·rcon(SB), PTR // PTR points to rcon addr
+ LVX (PTR), ESPERM
+ ADD $0x10, PTR
+#else
+ MOVD $·rcon+0x10(SB), PTR // PTR points to rcon addr (skipping permute vector)
+#endif
+
+ // Get key from memory and write aligned into VR
+ P8_LXVB16X(INP, R0, IN0)
+ ADD $0x10, INP, INP
+ MOVD $0x20, TEMP
+
+ CMPW ROUNDS, $12
+ LVX (PTR)(R0), RCON // lvx 4,0,6 Load first 16 bytes into RCON
+ LVX (PTR)(TEMP), MASK
+ ADD $0x10, PTR, PTR // addi 6,6,0x10 PTR to next 16 bytes of RCON
+ MOVD $8, CNT // li 7,8 CNT = 8
+ VXOR ZERO, ZERO, ZERO // vxor 0,0,0 Zero to be zero :)
+ MOVD CNT, CTR // mtctr 7 Set the counter to 8 (rounds)
+
+ // The expanded decrypt key is the expanded encrypt key stored in reverse order.
+ // Move OUTDEC to the last key location, and store in descending order.
+ ADD $160, OUTDEC, OUTDEC
+ BLT loop128
+ ADD $32, OUTDEC, OUTDEC
+ BEQ l192
+ ADD $32, OUTDEC, OUTDEC
+ JMP l256
+
+loop128:
+ // Key schedule (Round 1 to 8)
+ VPERM IN0, IN0, MASK, KEY // vperm 3,1,1,5 Rotate-n-splat
+ VSLDOI $12, ZERO, IN0, TMP // vsldoi 6,0,1,12
+ STXVD2X IN0, (R0+OUTENC)
+ STXVD2X IN0, (R0+OUTDEC)
+ VCIPHERLAST KEY, RCON, KEY // vcipherlast 3,3,4
+ ADD $16, OUTENC, OUTENC
+ ADD $-16, OUTDEC, OUTDEC
+
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+ VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+ VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+ VADDUWM RCON, RCON, RCON // vadduwm 4,4,4
+ VXOR IN0, KEY, IN0 // vxor 1,1,3
+ BC 0x10, 0, loop128 // bdnz .Loop128
+
+ LVX (PTR)(R0), RCON // lvx 4,0,6 Last two round keys
+
+ // Key schedule (Round 9)
+ VPERM IN0, IN0, MASK, KEY // vperm 3,1,1,5 Rotate-n-spat
+ VSLDOI $12, ZERO, IN0, TMP // vsldoi 6,0,1,12
+ STXVD2X IN0, (R0+OUTENC)
+ STXVD2X IN0, (R0+OUTDEC)
+ VCIPHERLAST KEY, RCON, KEY // vcipherlast 3,3,4
+ ADD $16, OUTENC, OUTENC
+ ADD $-16, OUTDEC, OUTDEC
+
+ // Key schedule (Round 10)
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+ VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+ VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+ VADDUWM RCON, RCON, RCON // vadduwm 4,4,4
+ VXOR IN0, KEY, IN0 // vxor 1,1,3
+
+ VPERM IN0, IN0, MASK, KEY // vperm 3,1,1,5 Rotate-n-splat
+ VSLDOI $12, ZERO, IN0, TMP // vsldoi 6,0,1,12
+ STXVD2X IN0, (R0+OUTENC)
+ STXVD2X IN0, (R0+OUTDEC)
+ VCIPHERLAST KEY, RCON, KEY // vcipherlast 3,3,4
+ ADD $16, OUTENC, OUTENC
+ ADD $-16, OUTDEC, OUTDEC
+
+ // Key schedule (Round 11)
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+ VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+ VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+ VXOR IN0, KEY, IN0 // vxor 1,1,3
+ STXVD2X IN0, (R0+OUTENC)
+ STXVD2X IN0, (R0+OUTDEC)
+
+ RET
+
+l192:
+ LXSDX (INP+R0), IN1 // Load next 8 bytes into upper half of VSR.
+ XXBRD_ON_LE(IN1, IN1) // and convert to BE ordering on LE hosts.
+ MOVD $4, CNT // li 7,4
+ STXVD2X IN0, (R0+OUTENC)
+ STXVD2X IN0, (R0+OUTDEC)
+ ADD $16, OUTENC, OUTENC
+ ADD $-16, OUTDEC, OUTDEC
+ VSPLTISB $8, KEY // vspltisb 3,8
+ MOVD CNT, CTR // mtctr 7
+ VSUBUBM MASK, KEY, MASK // vsububm 5,5,3
+
+loop192:
+ VPERM IN1, IN1, MASK, KEY // vperm 3,2,2,5
+ VSLDOI $12, ZERO, IN0, TMP // vsldoi 6,0,1,12
+ VCIPHERLAST KEY, RCON, KEY // vcipherlast 3,3,4
+
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+ VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+ VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+
+ VSLDOI $8, ZERO, IN1, STAGE // vsldoi 7,0,2,8
+ VSPLTW $3, IN0, TMP // vspltw 6,1,3
+ VXOR TMP, IN1, TMP // vxor 6,6,2
+ VSLDOI $12, ZERO, IN1, IN1 // vsldoi 2,0,2,12
+ VADDUWM RCON, RCON, RCON // vadduwm 4,4,4
+ VXOR IN1, TMP, IN1 // vxor 2,2,6
+ VXOR IN0, KEY, IN0 // vxor 1,1,3
+ VXOR IN1, KEY, IN1 // vxor 2,2,3
+ VSLDOI $8, STAGE, IN0, STAGE // vsldoi 7,7,1,8
+
+ VPERM IN1, IN1, MASK, KEY // vperm 3,2,2,5
+ VSLDOI $12, ZERO, IN0, TMP // vsldoi 6,0,1,12
+ STXVD2X STAGE, (R0+OUTENC)
+ STXVD2X STAGE, (R0+OUTDEC)
+ VCIPHERLAST KEY, RCON, KEY // vcipherlast 3,3,4
+ ADD $16, OUTENC, OUTENC
+ ADD $-16, OUTDEC, OUTDEC
+
+ VSLDOI $8, IN0, IN1, STAGE // vsldoi 7,1,2,8
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+ VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12
+ STXVD2X STAGE, (R0+OUTENC)
+ STXVD2X STAGE, (R0+OUTDEC)
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+ VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+ ADD $16, OUTENC, OUTENC
+ ADD $-16, OUTDEC, OUTDEC
+
+ VSPLTW $3, IN0, TMP // vspltw 6,1,3
+ VXOR TMP, IN1, TMP // vxor 6,6,2
+ VSLDOI $12, ZERO, IN1, IN1 // vsldoi 2,0,2,12
+ VADDUWM RCON, RCON, RCON // vadduwm 4,4,4
+ VXOR IN1, TMP, IN1 // vxor 2,2,6
+ VXOR IN0, KEY, IN0 // vxor 1,1,3
+ VXOR IN1, KEY, IN1 // vxor 2,2,3
+ STXVD2X IN0, (R0+OUTENC)
+ STXVD2X IN0, (R0+OUTDEC)
+ ADD $16, OUTENC, OUTENC
+ ADD $-16, OUTDEC, OUTDEC
+ BC 0x10, 0, loop192 // bdnz .Loop192
+
+ RET
+
+l256:
+ P8_LXVB16X(INP, R0, IN1)
+ MOVD $7, CNT // li 7,7
+ STXVD2X IN0, (R0+OUTENC)
+ STXVD2X IN0, (R0+OUTDEC)
+ ADD $16, OUTENC, OUTENC
+ ADD $-16, OUTDEC, OUTDEC
+ MOVD CNT, CTR // mtctr 7
+
+loop256:
+ VPERM IN1, IN1, MASK, KEY // vperm 3,2,2,5
+ VSLDOI $12, ZERO, IN0, TMP // vsldoi 6,0,1,12
+ STXVD2X IN1, (R0+OUTENC)
+ STXVD2X IN1, (R0+OUTDEC)
+ VCIPHERLAST KEY, RCON, KEY // vcipherlast 3,3,4
+ ADD $16, OUTENC, OUTENC
+ ADD $-16, OUTDEC, OUTDEC
+
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+ VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+ VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12
+ VXOR IN0, TMP, IN0 // vxor 1,1,6
+ VADDUWM RCON, RCON, RCON // vadduwm 4,4,4
+ VXOR IN0, KEY, IN0 // vxor 1,1,3
+ STXVD2X IN0, (R0+OUTENC)
+ STXVD2X IN0, (R0+OUTDEC)
+ ADD $16, OUTENC, OUTENC
+ ADD $-16, OUTDEC, OUTDEC
+ BC 0x12, 0, done // bdz .Ldone
+
+ VSPLTW $3, IN0, KEY // vspltw 3,1,3
+ VSLDOI $12, ZERO, IN1, TMP // vsldoi 6,0,2,12
+ VSBOX KEY, KEY // vsbox 3,3
+
+ VXOR IN1, TMP, IN1 // vxor 2,2,6
+ VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12
+ VXOR IN1, TMP, IN1 // vxor 2,2,6
+ VSLDOI $12, ZERO, TMP, TMP // vsldoi 6,0,6,12
+ VXOR IN1, TMP, IN1 // vxor 2,2,6
+
+ VXOR IN1, KEY, IN1 // vxor 2,2,3
+ JMP loop256 // b .Loop256
+
+done:
+ RET
+
+// func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
+TEXT ·encryptBlockAsm(SB), NOSPLIT|NOFRAME, $0
+ MOVD nr+0(FP), R6 // Round count/Key size
+ MOVD xk+8(FP), R5 // Key pointer
+ MOVD dst+16(FP), R3 // Dest pointer
+ MOVD src+24(FP), R4 // Src pointer
+#ifdef NEEDS_ESPERM
+ MOVD $·rcon(SB), R7
+ LVX (R7), ESPERM // Permute value for P8_ macros.
+#endif
+
+ // Set CR{1,2,3}EQ to hold the key size information.
+ CMPU R6, $10, CR1
+ CMPU R6, $12, CR2
+ CMPU R6, $14, CR3
+
+ MOVD $16, R6
+ MOVD $32, R7
+ MOVD $48, R8
+ MOVD $64, R9
+ MOVD $80, R10
+ MOVD $96, R11
+ MOVD $112, R12
+
+ // Load text in BE order
+ P8_LXVB16X(R4, R0, V0)
+
+ // V1, V2 will hold keys, V0 is a temp.
+ // At completion, V2 will hold the ciphertext.
+ // Load xk[0:3] and xor with text
+ LXVD2X (R0+R5), V1
+ VXOR V0, V1, V0
+
+ // Load xk[4:11] and cipher
+ LXVD2X (R6+R5), V1
+ LXVD2X (R7+R5), V2
+ VCIPHER V0, V1, V0
+ VCIPHER V0, V2, V0
+
+ // Load xk[12:19] and cipher
+ LXVD2X (R8+R5), V1
+ LXVD2X (R9+R5), V2
+ VCIPHER V0, V1, V0
+ VCIPHER V0, V2, V0
+
+ // Load xk[20:27] and cipher
+ LXVD2X (R10+R5), V1
+ LXVD2X (R11+R5), V2
+ VCIPHER V0, V1, V0
+ VCIPHER V0, V2, V0
+
+ // Increment xk pointer to reuse constant offsets in R6-R12.
+ ADD $112, R5
+
+ // Load xk[28:35] and cipher
+ LXVD2X (R0+R5), V1
+ LXVD2X (R6+R5), V2
+ VCIPHER V0, V1, V0
+ VCIPHER V0, V2, V0
+
+ // Load xk[36:43] and cipher
+ LXVD2X (R7+R5), V1
+ LXVD2X (R8+R5), V2
+ BEQ CR1, Ldec_tail // Key size 10?
+ VCIPHER V0, V1, V0
+ VCIPHER V0, V2, V0
+
+ // Load xk[44:51] and cipher
+ LXVD2X (R9+R5), V1
+ LXVD2X (R10+R5), V2
+ BEQ CR2, Ldec_tail // Key size 12?
+ VCIPHER V0, V1, V0
+ VCIPHER V0, V2, V0
+
+ // Load xk[52:59] and cipher
+ LXVD2X (R11+R5), V1
+ LXVD2X (R12+R5), V2
+ BNE CR3, Linvalid_key_len // Not key size 14?
+ // Fallthrough to final cipher
+
+Ldec_tail:
+ // Cipher last two keys such that key information is
+ // cleared from V1 and V2.
+ VCIPHER V0, V1, V1
+ VCIPHERLAST V1, V2, V2
+
+ // Store the result in BE order.
+ P8_STXVB16X(V2, R3, R0)
+ RET
+
+Linvalid_key_len:
+ // Segfault, this should never happen. Only 3 keys sizes are created/used.
+ MOVD R0, 0(R0)
+ RET
+
+// func decryptBlockAsm(nr int, xk *uint32, dst, src *byte)
+TEXT ·decryptBlockAsm(SB), NOSPLIT|NOFRAME, $0
+ MOVD nr+0(FP), R6 // Round count/Key size
+ MOVD xk+8(FP), R5 // Key pointer
+ MOVD dst+16(FP), R3 // Dest pointer
+ MOVD src+24(FP), R4 // Src pointer
+#ifdef NEEDS_ESPERM
+ MOVD $·rcon(SB), R7
+ LVX (R7), ESPERM // Permute value for P8_ macros.
+#endif
+
+ // Set CR{1,2,3}EQ to hold the key size information.
+ CMPU R6, $10, CR1
+ CMPU R6, $12, CR2
+ CMPU R6, $14, CR3
+
+ MOVD $16, R6
+ MOVD $32, R7
+ MOVD $48, R8
+ MOVD $64, R9
+ MOVD $80, R10
+ MOVD $96, R11
+ MOVD $112, R12
+
+ // Load text in BE order
+ P8_LXVB16X(R4, R0, V0)
+
+ // V1, V2 will hold keys, V0 is a temp.
+ // At completion, V2 will hold the text.
+ // Load xk[0:3] and xor with ciphertext
+ LXVD2X (R0+R5), V1
+ VXOR V0, V1, V0
+
+ // Load xk[4:11] and cipher
+ LXVD2X (R6+R5), V1
+ LXVD2X (R7+R5), V2
+ VNCIPHER V0, V1, V0
+ VNCIPHER V0, V2, V0
+
+ // Load xk[12:19] and cipher
+ LXVD2X (R8+R5), V1
+ LXVD2X (R9+R5), V2
+ VNCIPHER V0, V1, V0
+ VNCIPHER V0, V2, V0
+
+ // Load xk[20:27] and cipher
+ LXVD2X (R10+R5), V1
+ LXVD2X (R11+R5), V2
+ VNCIPHER V0, V1, V0
+ VNCIPHER V0, V2, V0
+
+ // Increment xk pointer to reuse constant offsets in R6-R12.
+ ADD $112, R5
+
+ // Load xk[28:35] and cipher
+ LXVD2X (R0+R5), V1
+ LXVD2X (R6+R5), V2
+ VNCIPHER V0, V1, V0
+ VNCIPHER V0, V2, V0
+
+ // Load xk[36:43] and cipher
+ LXVD2X (R7+R5), V1
+ LXVD2X (R8+R5), V2
+ BEQ CR1, Ldec_tail // Key size 10?
+ VNCIPHER V0, V1, V0
+ VNCIPHER V0, V2, V0
+
+ // Load xk[44:51] and cipher
+ LXVD2X (R9+R5), V1
+ LXVD2X (R10+R5), V2
+ BEQ CR2, Ldec_tail // Key size 12?
+ VNCIPHER V0, V1, V0
+ VNCIPHER V0, V2, V0
+
+ // Load xk[52:59] and cipher
+ LXVD2X (R11+R5), V1
+ LXVD2X (R12+R5), V2
+ BNE CR3, Linvalid_key_len // Not key size 14?
+ // Fallthrough to final cipher
+
+Ldec_tail:
+ // Cipher last two keys such that key information is
+ // cleared from V1 and V2.
+ VNCIPHER V0, V1, V1
+ VNCIPHERLAST V1, V2, V2
+
+ // Store the result in BE order.
+ P8_STXVB16X(V2, R3, R0)
+ RET
+
+Linvalid_key_len:
+ // Segfault, this should never happen. Only 3 keys sizes are created/used.
+ MOVD R0, 0(R0)
+ RET
+
+// Remove defines from above so they can be defined here
+#undef INP
+#undef OUTENC
+#undef ROUNDS
+#undef KEY
+#undef TMP
+
+#define INP R3
+#define OUTP R4
+#define LEN R5
+#define KEYP R6
+#define ROUNDS R7
+#define IVP R8
+#define ENC R9
+
+#define INOUT V2
+#define TMP V3
+#define IVEC V4
+
+// Load the crypt key into VSRs.
+//
+// The expanded key is stored and loaded using
+// STXVD2X/LXVD2X. The in-memory byte ordering
+// depends on the endianness of the machine. The
+// expanded keys are generated by expandKeyAsm above.
+//
+// Rkeyp holds the key pointer. It is clobbered. Once
+// the expanded keys are loaded, it is not needed.
+//
+// R12,R14-R21 are scratch registers.
+// For keyp of 10, V6, V11-V20 hold the expanded key.
+// For keyp of 12, V6, V9-V20 hold the expanded key.
+// For keyp of 14, V6, V7-V20 hold the expanded key.
+#define LOAD_KEY(Rkeyp) \
+ MOVD $16, R12 \
+ MOVD $32, R14 \
+ MOVD $48, R15 \
+ MOVD $64, R16 \
+ MOVD $80, R17 \
+ MOVD $96, R18 \
+ MOVD $112, R19 \
+ MOVD $128, R20 \
+ MOVD $144, R21 \
+ LXVD2X (R0+Rkeyp), V6 \
+ ADD $16, Rkeyp \
+ BEQ CR1, L_start10 \
+ BEQ CR2, L_start12 \
+ LXVD2X (R0+Rkeyp), V7 \
+ LXVD2X (R12+Rkeyp), V8 \
+ ADD $32, Rkeyp \
+ L_start12: \
+ LXVD2X (R0+Rkeyp), V9 \
+ LXVD2X (R12+Rkeyp), V10 \
+ ADD $32, Rkeyp \
+ L_start10: \
+ LXVD2X (R0+Rkeyp), V11 \
+ LXVD2X (R12+Rkeyp), V12 \
+ LXVD2X (R14+Rkeyp), V13 \
+ LXVD2X (R15+Rkeyp), V14 \
+ LXVD2X (R16+Rkeyp), V15 \
+ LXVD2X (R17+Rkeyp), V16 \
+ LXVD2X (R18+Rkeyp), V17 \
+ LXVD2X (R19+Rkeyp), V18 \
+ LXVD2X (R20+Rkeyp), V19 \
+ LXVD2X (R21+Rkeyp), V20
+
+// Perform aes cipher operation for keysize 10/12/14 using the keys
+// loaded by LOAD_KEY, and key size information held in CR1EQ/CR2EQ.
+//
+// Vxor is ideally V6 (Key[0-3]), but for slightly improved encrypting
+// performance V6 and IVEC can be swapped (xor is both associative and
+// commutative) during encryption:
+//
+// VXOR INOUT, IVEC, INOUT
+// VXOR INOUT, V6, INOUT
+//
+// into
+//
+// VXOR INOUT, V6, INOUT
+// VXOR INOUT, IVEC, INOUT
+//
+#define CIPHER_BLOCK(Vin, Vxor, Vout, vcipher, vciphel, label10, label12) \
+ VXOR Vin, Vxor, Vout \
+ BEQ CR1, label10 \
+ BEQ CR2, label12 \
+ vcipher Vout, V7, Vout \
+ vcipher Vout, V8, Vout \
+ label12: \
+ vcipher Vout, V9, Vout \
+ vcipher Vout, V10, Vout \
+ label10: \
+ vcipher Vout, V11, Vout \
+ vcipher Vout, V12, Vout \
+ vcipher Vout, V13, Vout \
+ vcipher Vout, V14, Vout \
+ vcipher Vout, V15, Vout \
+ vcipher Vout, V16, Vout \
+ vcipher Vout, V17, Vout \
+ vcipher Vout, V18, Vout \
+ vcipher Vout, V19, Vout \
+ vciphel Vout, V20, Vout \
+
+#define CLEAR_KEYS() \
+ VXOR V6, V6, V6 \
+ VXOR V7, V7, V7 \
+ VXOR V8, V8, V8 \
+ VXOR V9, V9, V9 \
+ VXOR V10, V10, V10 \
+ VXOR V11, V11, V11 \
+ VXOR V12, V12, V12 \
+ VXOR V13, V13, V13 \
+ VXOR V14, V14, V14 \
+ VXOR V15, V15, V15 \
+ VXOR V16, V16, V16 \
+ VXOR V17, V17, V17 \
+ VXOR V18, V18, V18 \
+ VXOR V19, V19, V19 \
+ VXOR V20, V20, V20
+
+//func cryptBlocksChain(src, dst *byte, length int, key *uint32, iv *byte, enc int, nr int)
+TEXT ·cryptBlocksChain(SB), NOSPLIT|NOFRAME, $0
+ MOVD src+0(FP), INP
+ MOVD dst+8(FP), OUTP
+ MOVD length+16(FP), LEN
+ MOVD key+24(FP), KEYP
+ MOVD iv+32(FP), IVP
+ MOVD enc+40(FP), ENC
+ MOVD nr+48(FP), ROUNDS
+
+#ifdef NEEDS_ESPERM
+ MOVD $·rcon(SB), R11
+ LVX (R11), ESPERM // Permute value for P8_ macros.
+#endif
+
+ // Assume len > 0 && len % blockSize == 0.
+ CMPW ENC, $0
+ P8_LXVB16X(IVP, R0, IVEC)
+ CMPU ROUNDS, $10, CR1
+ CMPU ROUNDS, $12, CR2 // Only sizes 10/12/14 are supported.
+
+ // Setup key in VSRs, and set loop count in CTR.
+ LOAD_KEY(KEYP)
+ SRD $4, LEN
+ MOVD LEN, CTR
+
+ BEQ Lcbc_dec
+
+ PCALIGN $32
+Lcbc_enc:
+ P8_LXVB16X(INP, R0, INOUT)
+ ADD $16, INP
+ VXOR INOUT, V6, INOUT
+ CIPHER_BLOCK(INOUT, IVEC, INOUT, VCIPHER, VCIPHERLAST, Lcbc_enc10, Lcbc_enc12)
+ VOR INOUT, INOUT, IVEC // ciphertext (INOUT) is IVEC for next block.
+ P8_STXVB16X(INOUT, OUTP, R0)
+ ADD $16, OUTP
+ BDNZ Lcbc_enc
+
+ P8_STXVB16X(INOUT, IVP, R0)
+ CLEAR_KEYS()
+ RET
+
+ PCALIGN $32
+Lcbc_dec:
+ P8_LXVB16X(INP, R0, TMP)
+ ADD $16, INP
+ CIPHER_BLOCK(TMP, V6, INOUT, VNCIPHER, VNCIPHERLAST, Lcbc_dec10, Lcbc_dec12)
+ VXOR INOUT, IVEC, INOUT
+ VOR TMP, TMP, IVEC // TMP is IVEC for next block.
+ P8_STXVB16X(INOUT, OUTP, R0)
+ ADD $16, OUTP
+ BDNZ Lcbc_dec
+
+ P8_STXVB16X(IVEC, IVP, R0)
+ CLEAR_KEYS()
+ RET
diff --git a/src/crypto/aes/asm_s390x.s b/src/crypto/aes/asm_s390x.s
new file mode 100644
index 0000000..0c60ac2
--- /dev/null
+++ b/src/crypto/aes/asm_s390x.s
@@ -0,0 +1,191 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// func cryptBlocks(c code, key, dst, src *byte, length int)
+TEXT ·cryptBlocks(SB),NOSPLIT,$0-40
+ MOVD key+8(FP), R1
+ MOVD dst+16(FP), R2
+ MOVD src+24(FP), R4
+ MOVD length+32(FP), R5
+ MOVD c+0(FP), R0
+loop:
+ WORD $0xB92E0024 // cipher message (KM)
+ BVS loop // branch back if interrupted
+ XOR R0, R0
+ RET
+
+// func cryptBlocksChain(c code, iv, key, dst, src *byte, length int)
+TEXT ·cryptBlocksChain(SB),NOSPLIT,$48-48
+ LA params-48(SP), R1
+ MOVD iv+8(FP), R8
+ MOVD key+16(FP), R9
+ MVC $16, 0(R8), 0(R1) // move iv into params
+ MVC $32, 0(R9), 16(R1) // move key into params
+ MOVD dst+24(FP), R2
+ MOVD src+32(FP), R4
+ MOVD length+40(FP), R5
+ MOVD c+0(FP), R0
+loop:
+ WORD $0xB92F0024 // cipher message with chaining (KMC)
+ BVS loop // branch back if interrupted
+ XOR R0, R0
+ MVC $16, 0(R1), 0(R8) // update iv
+ RET
+
+// func xorBytes(dst, a, b []byte) int
+TEXT ·xorBytes(SB),NOSPLIT,$0-80
+ MOVD dst_base+0(FP), R1
+ MOVD a_base+24(FP), R2
+ MOVD b_base+48(FP), R3
+ MOVD a_len+32(FP), R4
+ MOVD b_len+56(FP), R5
+ CMPBLE R4, R5, skip
+ MOVD R5, R4
+skip:
+ MOVD R4, ret+72(FP)
+ MOVD $0, R5
+ CMPBLT R4, $8, tail
+loop:
+ MOVD 0(R2)(R5*1), R7
+ MOVD 0(R3)(R5*1), R8
+ XOR R7, R8
+ MOVD R8, 0(R1)(R5*1)
+ LAY 8(R5), R5
+ SUB $8, R4
+ CMPBGE R4, $8, loop
+tail:
+ CMPBEQ R4, $0, done
+ MOVB 0(R2)(R5*1), R7
+ MOVB 0(R3)(R5*1), R8
+ XOR R7, R8
+ MOVB R8, 0(R1)(R5*1)
+ LAY 1(R5), R5
+ SUB $1, R4
+ BR tail
+done:
+ RET
+
+// func cryptBlocksGCM(fn code, key, dst, src, buf []byte, cnt *[16]byte)
+TEXT ·cryptBlocksGCM(SB),NOSPLIT,$0-112
+ MOVD src_len+64(FP), R0
+ MOVD buf_base+80(FP), R1
+ MOVD cnt+104(FP), R12
+ LMG (R12), R2, R3
+
+ // Check that the src size is less than or equal to the buffer size.
+ MOVD buf_len+88(FP), R4
+ CMP R0, R4
+ BGT crash
+
+ // Check that the src size is a multiple of 16-bytes.
+ MOVD R0, R4
+ AND $0xf, R4
+ BLT crash // non-zero
+
+ // Check that the src size is less than or equal to the dst size.
+ MOVD dst_len+40(FP), R4
+ CMP R0, R4
+ BGT crash
+
+ MOVD R2, R4
+ MOVD R2, R6
+ MOVD R2, R8
+ MOVD R3, R5
+ MOVD R3, R7
+ MOVD R3, R9
+ ADDW $1, R5
+ ADDW $2, R7
+ ADDW $3, R9
+incr:
+ CMP R0, $64
+ BLT tail
+ STMG R2, R9, (R1)
+ ADDW $4, R3
+ ADDW $4, R5
+ ADDW $4, R7
+ ADDW $4, R9
+ MOVD $64(R1), R1
+ SUB $64, R0
+ BR incr
+tail:
+ CMP R0, $0
+ BEQ crypt
+ STMG R2, R3, (R1)
+ ADDW $1, R3
+ MOVD $16(R1), R1
+ SUB $16, R0
+ BR tail
+crypt:
+ STMG R2, R3, (R12) // update next counter value
+ MOVD fn+0(FP), R0 // function code (encryption)
+ MOVD key_base+8(FP), R1 // key
+ MOVD buf_base+80(FP), R2 // counter values
+ MOVD dst_base+32(FP), R4 // dst
+ MOVD src_base+56(FP), R6 // src
+ MOVD src_len+64(FP), R7 // len
+loop:
+ WORD $0xB92D2046 // cipher message with counter (KMCTR)
+ BVS loop // branch back if interrupted
+ RET
+crash:
+ MOVD $0, (R0)
+ RET
+
+// func ghash(key *gcmHashKey, hash *[16]byte, data []byte)
+TEXT ·ghash(SB),NOSPLIT,$32-40
+ MOVD $65, R0 // GHASH function code
+ MOVD key+0(FP), R2
+ LMG (R2), R6, R7
+ MOVD hash+8(FP), R8
+ LMG (R8), R4, R5
+ MOVD $params-32(SP), R1
+ STMG R4, R7, (R1)
+ LMG data+16(FP), R2, R3 // R2=base, R3=len
+loop:
+ WORD $0xB93E0002 // compute intermediate message digest (KIMD)
+ BVS loop // branch back if interrupted
+ MVC $16, (R1), (R8)
+ MOVD $0, R0
+ RET
+
+// func kmaGCM(fn code, key, dst, src, aad []byte, tag *[16]byte, cnt *gcmCount)
+TEXT ·kmaGCM(SB),NOSPLIT,$112-120
+ MOVD fn+0(FP), R0
+ MOVD $params-112(SP), R1
+
+ // load ptr/len pairs
+ LMG dst+32(FP), R2, R3 // R2=base R3=len
+ LMG src+56(FP), R4, R5 // R4=base R5=len
+ LMG aad+80(FP), R6, R7 // R6=base R7=len
+
+ // setup parameters
+ MOVD cnt+112(FP), R8
+ XC $12, (R1), (R1) // reserved
+ MVC $4, 12(R8), 12(R1) // set chain value
+ MVC $16, (R8), 64(R1) // set initial counter value
+ XC $32, 16(R1), 16(R1) // set hash subkey and tag
+ SLD $3, R7, R12
+ MOVD R12, 48(R1) // set total AAD length
+ SLD $3, R5, R12
+ MOVD R12, 56(R1) // set total plaintext/ciphertext length
+
+ LMG key+8(FP), R8, R9 // R8=base R9=len
+ MVC $16, (R8), 80(R1) // set key
+ CMPBEQ R9, $16, kma
+ MVC $8, 16(R8), 96(R1)
+ CMPBEQ R9, $24, kma
+ MVC $8, 24(R8), 104(R1)
+
+kma:
+ WORD $0xb9296024 // kma %r6,%r2,%r4
+ BVS kma
+
+ MOVD tag+104(FP), R2
+ MVC $16, 16(R1), 0(R2) // copy tag to output
+ MOVD cnt+112(FP), R8
+ MVC $4, 12(R1), 12(R8) // update counter value
+
+ RET
diff --git a/src/crypto/aes/block.go b/src/crypto/aes/block.go
new file mode 100644
index 0000000..53308ae
--- /dev/null
+++ b/src/crypto/aes/block.go
@@ -0,0 +1,182 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This Go implementation is derived in part from the reference
+// ANSI C implementation, which carries the following notice:
+//
+// rijndael-alg-fst.c
+//
+// @version 3.0 (December 2000)
+//
+// Optimised ANSI C code for the Rijndael cipher (now AES)
+//
+// @author Vincent Rijmen <vincent.rijmen@esat.kuleuven.ac.be>
+// @author Antoon Bosselaers <antoon.bosselaers@esat.kuleuven.ac.be>
+// @author Paulo Barreto <paulo.barreto@terra.com.br>
+//
+// This code is hereby placed in the public domain.
+//
+// THIS SOFTWARE IS PROVIDED BY THE AUTHORS ''AS IS'' AND ANY EXPRESS
+// OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+// ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE
+// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
+// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+// BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
+// WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE
+// OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
+// EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+// See FIPS 197 for specification, and see Daemen and Rijmen's Rijndael submission
+// for implementation details.
+// https://csrc.nist.gov/csrc/media/publications/fips/197/final/documents/fips-197.pdf
+// https://csrc.nist.gov/archive/aes/rijndael/Rijndael-ammended.pdf
+
+package aes
+
+import (
+ "encoding/binary"
+)
+
+// Encrypt one block from src into dst, using the expanded key xk.
+func encryptBlockGo(xk []uint32, dst, src []byte) {
+ _ = src[15] // early bounds check
+ s0 := binary.BigEndian.Uint32(src[0:4])
+ s1 := binary.BigEndian.Uint32(src[4:8])
+ s2 := binary.BigEndian.Uint32(src[8:12])
+ s3 := binary.BigEndian.Uint32(src[12:16])
+
+ // First round just XORs input with key.
+ s0 ^= xk[0]
+ s1 ^= xk[1]
+ s2 ^= xk[2]
+ s3 ^= xk[3]
+
+ // Middle rounds shuffle using tables.
+ // Number of rounds is set by length of expanded key.
+ nr := len(xk)/4 - 2 // - 2: one above, one more below
+ k := 4
+ var t0, t1, t2, t3 uint32
+ for r := 0; r < nr; r++ {
+ t0 = xk[k+0] ^ te0[uint8(s0>>24)] ^ te1[uint8(s1>>16)] ^ te2[uint8(s2>>8)] ^ te3[uint8(s3)]
+ t1 = xk[k+1] ^ te0[uint8(s1>>24)] ^ te1[uint8(s2>>16)] ^ te2[uint8(s3>>8)] ^ te3[uint8(s0)]
+ t2 = xk[k+2] ^ te0[uint8(s2>>24)] ^ te1[uint8(s3>>16)] ^ te2[uint8(s0>>8)] ^ te3[uint8(s1)]
+ t3 = xk[k+3] ^ te0[uint8(s3>>24)] ^ te1[uint8(s0>>16)] ^ te2[uint8(s1>>8)] ^ te3[uint8(s2)]
+ k += 4
+ s0, s1, s2, s3 = t0, t1, t2, t3
+ }
+
+ // Last round uses s-box directly and XORs to produce output.
+ s0 = uint32(sbox0[t0>>24])<<24 | uint32(sbox0[t1>>16&0xff])<<16 | uint32(sbox0[t2>>8&0xff])<<8 | uint32(sbox0[t3&0xff])
+ s1 = uint32(sbox0[t1>>24])<<24 | uint32(sbox0[t2>>16&0xff])<<16 | uint32(sbox0[t3>>8&0xff])<<8 | uint32(sbox0[t0&0xff])
+ s2 = uint32(sbox0[t2>>24])<<24 | uint32(sbox0[t3>>16&0xff])<<16 | uint32(sbox0[t0>>8&0xff])<<8 | uint32(sbox0[t1&0xff])
+ s3 = uint32(sbox0[t3>>24])<<24 | uint32(sbox0[t0>>16&0xff])<<16 | uint32(sbox0[t1>>8&0xff])<<8 | uint32(sbox0[t2&0xff])
+
+ s0 ^= xk[k+0]
+ s1 ^= xk[k+1]
+ s2 ^= xk[k+2]
+ s3 ^= xk[k+3]
+
+ _ = dst[15] // early bounds check
+ binary.BigEndian.PutUint32(dst[0:4], s0)
+ binary.BigEndian.PutUint32(dst[4:8], s1)
+ binary.BigEndian.PutUint32(dst[8:12], s2)
+ binary.BigEndian.PutUint32(dst[12:16], s3)
+}
+
+// Decrypt one block from src into dst, using the expanded key xk.
+func decryptBlockGo(xk []uint32, dst, src []byte) {
+ _ = src[15] // early bounds check
+ s0 := binary.BigEndian.Uint32(src[0:4])
+ s1 := binary.BigEndian.Uint32(src[4:8])
+ s2 := binary.BigEndian.Uint32(src[8:12])
+ s3 := binary.BigEndian.Uint32(src[12:16])
+
+ // First round just XORs input with key.
+ s0 ^= xk[0]
+ s1 ^= xk[1]
+ s2 ^= xk[2]
+ s3 ^= xk[3]
+
+ // Middle rounds shuffle using tables.
+ // Number of rounds is set by length of expanded key.
+ nr := len(xk)/4 - 2 // - 2: one above, one more below
+ k := 4
+ var t0, t1, t2, t3 uint32
+ for r := 0; r < nr; r++ {
+ t0 = xk[k+0] ^ td0[uint8(s0>>24)] ^ td1[uint8(s3>>16)] ^ td2[uint8(s2>>8)] ^ td3[uint8(s1)]
+ t1 = xk[k+1] ^ td0[uint8(s1>>24)] ^ td1[uint8(s0>>16)] ^ td2[uint8(s3>>8)] ^ td3[uint8(s2)]
+ t2 = xk[k+2] ^ td0[uint8(s2>>24)] ^ td1[uint8(s1>>16)] ^ td2[uint8(s0>>8)] ^ td3[uint8(s3)]
+ t3 = xk[k+3] ^ td0[uint8(s3>>24)] ^ td1[uint8(s2>>16)] ^ td2[uint8(s1>>8)] ^ td3[uint8(s0)]
+ k += 4
+ s0, s1, s2, s3 = t0, t1, t2, t3
+ }
+
+ // Last round uses s-box directly and XORs to produce output.
+ s0 = uint32(sbox1[t0>>24])<<24 | uint32(sbox1[t3>>16&0xff])<<16 | uint32(sbox1[t2>>8&0xff])<<8 | uint32(sbox1[t1&0xff])
+ s1 = uint32(sbox1[t1>>24])<<24 | uint32(sbox1[t0>>16&0xff])<<16 | uint32(sbox1[t3>>8&0xff])<<8 | uint32(sbox1[t2&0xff])
+ s2 = uint32(sbox1[t2>>24])<<24 | uint32(sbox1[t1>>16&0xff])<<16 | uint32(sbox1[t0>>8&0xff])<<8 | uint32(sbox1[t3&0xff])
+ s3 = uint32(sbox1[t3>>24])<<24 | uint32(sbox1[t2>>16&0xff])<<16 | uint32(sbox1[t1>>8&0xff])<<8 | uint32(sbox1[t0&0xff])
+
+ s0 ^= xk[k+0]
+ s1 ^= xk[k+1]
+ s2 ^= xk[k+2]
+ s3 ^= xk[k+3]
+
+ _ = dst[15] // early bounds check
+ binary.BigEndian.PutUint32(dst[0:4], s0)
+ binary.BigEndian.PutUint32(dst[4:8], s1)
+ binary.BigEndian.PutUint32(dst[8:12], s2)
+ binary.BigEndian.PutUint32(dst[12:16], s3)
+}
+
+// Apply sbox0 to each byte in w.
+func subw(w uint32) uint32 {
+ return uint32(sbox0[w>>24])<<24 |
+ uint32(sbox0[w>>16&0xff])<<16 |
+ uint32(sbox0[w>>8&0xff])<<8 |
+ uint32(sbox0[w&0xff])
+}
+
+// Rotate
+func rotw(w uint32) uint32 { return w<<8 | w>>24 }
+
+// Key expansion algorithm. See FIPS-197, Figure 11.
+// Their rcon[i] is our powx[i-1] << 24.
+func expandKeyGo(key []byte, enc, dec []uint32) {
+ // Encryption key setup.
+ var i int
+ nk := len(key) / 4
+ for i = 0; i < nk; i++ {
+ enc[i] = binary.BigEndian.Uint32(key[4*i:])
+ }
+ for ; i < len(enc); i++ {
+ t := enc[i-1]
+ if i%nk == 0 {
+ t = subw(rotw(t)) ^ (uint32(powx[i/nk-1]) << 24)
+ } else if nk > 6 && i%nk == 4 {
+ t = subw(t)
+ }
+ enc[i] = enc[i-nk] ^ t
+ }
+
+ // Derive decryption key from encryption key.
+ // Reverse the 4-word round key sets from enc to produce dec.
+ // All sets but the first and last get the MixColumn transform applied.
+ if dec == nil {
+ return
+ }
+ n := len(enc)
+ for i := 0; i < n; i += 4 {
+ ei := n - i - 4
+ for j := 0; j < 4; j++ {
+ x := enc[ei+j]
+ if i > 0 && i+4 < n {
+ x = td0[sbox0[x>>24]] ^ td1[sbox0[x>>16&0xff]] ^ td2[sbox0[x>>8&0xff]] ^ td3[sbox0[x&0xff]]
+ }
+ dec[i+j] = x
+ }
+ }
+}
diff --git a/src/crypto/aes/cbc_ppc64x.go b/src/crypto/aes/cbc_ppc64x.go
new file mode 100644
index 0000000..c23c371
--- /dev/null
+++ b/src/crypto/aes/cbc_ppc64x.go
@@ -0,0 +1,74 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build ppc64 || ppc64le
+
+package aes
+
+import (
+ "crypto/cipher"
+ "crypto/internal/alias"
+)
+
+// Assert that aesCipherAsm implements the cbcEncAble and cbcDecAble interfaces.
+var _ cbcEncAble = (*aesCipherAsm)(nil)
+var _ cbcDecAble = (*aesCipherAsm)(nil)
+
+const cbcEncrypt = 1
+const cbcDecrypt = 0
+
+type cbc struct {
+ b *aesCipherAsm
+ enc int
+ iv [BlockSize]byte
+}
+
+func (b *aesCipherAsm) NewCBCEncrypter(iv []byte) cipher.BlockMode {
+ var c cbc
+ c.b = b
+ c.enc = cbcEncrypt
+ copy(c.iv[:], iv)
+ return &c
+}
+
+func (b *aesCipherAsm) NewCBCDecrypter(iv []byte) cipher.BlockMode {
+ var c cbc
+ c.b = b
+ c.enc = cbcDecrypt
+ copy(c.iv[:], iv)
+ return &c
+}
+
+func (x *cbc) BlockSize() int { return BlockSize }
+
+// cryptBlocksChain invokes the cipher message identifying encrypt or decrypt.
+//
+//go:noescape
+func cryptBlocksChain(src, dst *byte, length int, key *uint32, iv *byte, enc int, nr int)
+
+func (x *cbc) CryptBlocks(dst, src []byte) {
+ if len(src)%BlockSize != 0 {
+ panic("crypto/cipher: input not full blocks")
+ }
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if alias.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+ if len(src) > 0 {
+ if x.enc == cbcEncrypt {
+ cryptBlocksChain(&src[0], &dst[0], len(src), &x.b.enc[0], &x.iv[0], x.enc, len(x.b.enc)/4-1)
+ } else {
+ cryptBlocksChain(&src[0], &dst[0], len(src), &x.b.dec[0], &x.iv[0], x.enc, len(x.b.dec)/4-1)
+ }
+ }
+}
+
+func (x *cbc) SetIV(iv []byte) {
+ if len(iv) != BlockSize {
+ panic("cipher: incorrect length IV")
+ }
+ copy(x.iv[:], iv)
+}
diff --git a/src/crypto/aes/cbc_s390x.go b/src/crypto/aes/cbc_s390x.go
new file mode 100644
index 0000000..eaa21f8
--- /dev/null
+++ b/src/crypto/aes/cbc_s390x.go
@@ -0,0 +1,66 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aes
+
+import (
+ "crypto/cipher"
+ "crypto/internal/alias"
+)
+
+// Assert that aesCipherAsm implements the cbcEncAble and cbcDecAble interfaces.
+var _ cbcEncAble = (*aesCipherAsm)(nil)
+var _ cbcDecAble = (*aesCipherAsm)(nil)
+
+type cbc struct {
+ b *aesCipherAsm
+ c code
+ iv [BlockSize]byte
+}
+
+func (b *aesCipherAsm) NewCBCEncrypter(iv []byte) cipher.BlockMode {
+ var c cbc
+ c.b = b
+ c.c = b.function
+ copy(c.iv[:], iv)
+ return &c
+}
+
+func (b *aesCipherAsm) NewCBCDecrypter(iv []byte) cipher.BlockMode {
+ var c cbc
+ c.b = b
+ c.c = b.function + 128 // decrypt function code is encrypt + 128
+ copy(c.iv[:], iv)
+ return &c
+}
+
+func (x *cbc) BlockSize() int { return BlockSize }
+
+// cryptBlocksChain invokes the cipher message with chaining (KMC) instruction
+// with the given function code. The length must be a multiple of BlockSize (16).
+//
+//go:noescape
+func cryptBlocksChain(c code, iv, key, dst, src *byte, length int)
+
+func (x *cbc) CryptBlocks(dst, src []byte) {
+ if len(src)%BlockSize != 0 {
+ panic("crypto/cipher: input not full blocks")
+ }
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if alias.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+ if len(src) > 0 {
+ cryptBlocksChain(x.c, &x.iv[0], &x.b.key[0], &dst[0], &src[0], len(src))
+ }
+}
+
+func (x *cbc) SetIV(iv []byte) {
+ if len(iv) != BlockSize {
+ panic("cipher: incorrect length IV")
+ }
+ copy(x.iv[:], iv)
+}
diff --git a/src/crypto/aes/cipher.go b/src/crypto/aes/cipher.go
new file mode 100644
index 0000000..183c169
--- /dev/null
+++ b/src/crypto/aes/cipher.go
@@ -0,0 +1,82 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aes
+
+import (
+ "crypto/cipher"
+ "crypto/internal/alias"
+ "crypto/internal/boring"
+ "strconv"
+)
+
+// The AES block size in bytes.
+const BlockSize = 16
+
+// A cipher is an instance of AES encryption using a particular key.
+type aesCipher struct {
+ enc []uint32
+ dec []uint32
+}
+
+type KeySizeError int
+
+func (k KeySizeError) Error() string {
+ return "crypto/aes: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a new cipher.Block.
+// The key argument should be the AES key,
+// either 16, 24, or 32 bytes to select
+// AES-128, AES-192, or AES-256.
+func NewCipher(key []byte) (cipher.Block, error) {
+ k := len(key)
+ switch k {
+ default:
+ return nil, KeySizeError(k)
+ case 16, 24, 32:
+ break
+ }
+ if boring.Enabled {
+ return boring.NewAESCipher(key)
+ }
+ return newCipher(key)
+}
+
+// newCipherGeneric creates and returns a new cipher.Block
+// implemented in pure Go.
+func newCipherGeneric(key []byte) (cipher.Block, error) {
+ n := len(key) + 28
+ c := aesCipher{make([]uint32, n), make([]uint32, n)}
+ expandKeyGo(key, c.enc, c.dec)
+ return &c, nil
+}
+
+func (c *aesCipher) BlockSize() int { return BlockSize }
+
+func (c *aesCipher) Encrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/aes: output not full block")
+ }
+ if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/aes: invalid buffer overlap")
+ }
+ encryptBlockGo(c.enc, dst, src)
+}
+
+func (c *aesCipher) Decrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/aes: output not full block")
+ }
+ if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/aes: invalid buffer overlap")
+ }
+ decryptBlockGo(c.dec, dst, src)
+}
diff --git a/src/crypto/aes/cipher_asm.go b/src/crypto/aes/cipher_asm.go
new file mode 100644
index 0000000..90031c5
--- /dev/null
+++ b/src/crypto/aes/cipher_asm.go
@@ -0,0 +1,113 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build amd64 || arm64 || ppc64 || ppc64le
+
+package aes
+
+import (
+ "crypto/cipher"
+ "crypto/internal/alias"
+ "crypto/internal/boring"
+ "internal/cpu"
+ "internal/goarch"
+)
+
+// defined in asm_*.s
+
+//go:noescape
+func encryptBlockAsm(nr int, xk *uint32, dst, src *byte)
+
+//go:noescape
+func decryptBlockAsm(nr int, xk *uint32, dst, src *byte)
+
+//go:noescape
+func expandKeyAsm(nr int, key *byte, enc *uint32, dec *uint32)
+
+type aesCipherAsm struct {
+ aesCipher
+}
+
+// aesCipherGCM implements crypto/cipher.gcmAble so that crypto/cipher.NewGCM
+// will use the optimised implementation in aes_gcm.go when possible.
+// Instances of this type only exist when hasGCMAsm returns true. Likewise,
+// the gcmAble implementation is in aes_gcm.go.
+type aesCipherGCM struct {
+ aesCipherAsm
+}
+
+var supportsAES = cpu.X86.HasAES || cpu.ARM64.HasAES || goarch.IsPpc64 == 1 || goarch.IsPpc64le == 1
+var supportsGFMUL = cpu.X86.HasPCLMULQDQ || cpu.ARM64.HasPMULL
+
+func newCipher(key []byte) (cipher.Block, error) {
+ if !supportsAES {
+ return newCipherGeneric(key)
+ }
+ n := len(key) + 28
+ c := aesCipherAsm{aesCipher{make([]uint32, n), make([]uint32, n)}}
+ var rounds int
+ switch len(key) {
+ case 128 / 8:
+ rounds = 10
+ case 192 / 8:
+ rounds = 12
+ case 256 / 8:
+ rounds = 14
+ default:
+ return nil, KeySizeError(len(key))
+ }
+
+ expandKeyAsm(rounds, &key[0], &c.enc[0], &c.dec[0])
+ if supportsAES && supportsGFMUL {
+ return &aesCipherGCM{c}, nil
+ }
+ return &c, nil
+}
+
+func (c *aesCipherAsm) BlockSize() int { return BlockSize }
+
+func (c *aesCipherAsm) Encrypt(dst, src []byte) {
+ boring.Unreachable()
+ if len(src) < BlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/aes: output not full block")
+ }
+ if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/aes: invalid buffer overlap")
+ }
+ encryptBlockAsm(len(c.enc)/4-1, &c.enc[0], &dst[0], &src[0])
+}
+
+func (c *aesCipherAsm) Decrypt(dst, src []byte) {
+ boring.Unreachable()
+ if len(src) < BlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/aes: output not full block")
+ }
+ if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/aes: invalid buffer overlap")
+ }
+ decryptBlockAsm(len(c.dec)/4-1, &c.dec[0], &dst[0], &src[0])
+}
+
+// expandKey is used by BenchmarkExpand to ensure that the asm implementation
+// of key expansion is used for the benchmark when it is available.
+func expandKey(key []byte, enc, dec []uint32) {
+ if supportsAES {
+ rounds := 10 // rounds needed for AES128
+ switch len(key) {
+ case 192 / 8:
+ rounds = 12
+ case 256 / 8:
+ rounds = 14
+ }
+ expandKeyAsm(rounds, &key[0], &enc[0], &dec[0])
+ } else {
+ expandKeyGo(key, enc, dec)
+ }
+}
diff --git a/src/crypto/aes/cipher_generic.go b/src/crypto/aes/cipher_generic.go
new file mode 100644
index 0000000..8a8a3ff
--- /dev/null
+++ b/src/crypto/aes/cipher_generic.go
@@ -0,0 +1,26 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !amd64 && !s390x && !ppc64 && !ppc64le && !arm64
+
+package aes
+
+import (
+ "crypto/cipher"
+)
+
+// newCipher calls the newCipherGeneric function
+// directly. Platforms with hardware accelerated
+// implementations of AES should implement their
+// own version of newCipher (which may then call
+// newCipherGeneric if needed).
+func newCipher(key []byte) (cipher.Block, error) {
+ return newCipherGeneric(key)
+}
+
+// expandKey is used by BenchmarkExpand and should
+// call an assembly implementation if one is available.
+func expandKey(key []byte, enc, dec []uint32) {
+ expandKeyGo(key, enc, dec)
+}
diff --git a/src/crypto/aes/cipher_s390x.go b/src/crypto/aes/cipher_s390x.go
new file mode 100644
index 0000000..8dd3d8f
--- /dev/null
+++ b/src/crypto/aes/cipher_s390x.go
@@ -0,0 +1,96 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aes
+
+import (
+ "crypto/cipher"
+ "crypto/internal/alias"
+ "internal/cpu"
+)
+
+type code int
+
+// Function codes for the cipher message family of instructions.
+const (
+ aes128 code = 18
+ aes192 = 19
+ aes256 = 20
+)
+
+type aesCipherAsm struct {
+ function code // code for cipher message instruction
+ key []byte // key (128, 192 or 256 bits)
+ storage [32]byte // array backing key slice
+}
+
+// cryptBlocks invokes the cipher message (KM) instruction with
+// the given function code. This is equivalent to AES in ECB
+// mode. The length must be a multiple of BlockSize (16).
+//
+//go:noescape
+func cryptBlocks(c code, key, dst, src *byte, length int)
+
+func newCipher(key []byte) (cipher.Block, error) {
+ // The aesCipherAsm type implements the cbcEncAble, cbcDecAble,
+ // ctrAble and gcmAble interfaces. We therefore need to check
+ // for all the features required to implement these modes.
+ // Keep in sync with crypto/tls/common.go.
+ if !(cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR && (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)) {
+ return newCipherGeneric(key)
+ }
+
+ var function code
+ switch len(key) {
+ case 128 / 8:
+ function = aes128
+ case 192 / 8:
+ function = aes192
+ case 256 / 8:
+ function = aes256
+ default:
+ return nil, KeySizeError(len(key))
+ }
+
+ var c aesCipherAsm
+ c.function = function
+ c.key = c.storage[:len(key)]
+ copy(c.key, key)
+ return &c, nil
+}
+
+func (c *aesCipherAsm) BlockSize() int { return BlockSize }
+
+func (c *aesCipherAsm) Encrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/aes: output not full block")
+ }
+ if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/aes: invalid buffer overlap")
+ }
+ cryptBlocks(c.function, &c.key[0], &dst[0], &src[0], BlockSize)
+}
+
+func (c *aesCipherAsm) Decrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/aes: output not full block")
+ }
+ if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/aes: invalid buffer overlap")
+ }
+ // The decrypt function code is equal to the function code + 128.
+ cryptBlocks(c.function+128, &c.key[0], &dst[0], &src[0], BlockSize)
+}
+
+// expandKey is used by BenchmarkExpand. cipher message (KM) does not need key
+// expansion so there is no assembly equivalent.
+func expandKey(key []byte, enc, dec []uint32) {
+ expandKeyGo(key, enc, dec)
+}
diff --git a/src/crypto/aes/const.go b/src/crypto/aes/const.go
new file mode 100644
index 0000000..4eca4b9
--- /dev/null
+++ b/src/crypto/aes/const.go
@@ -0,0 +1,365 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package aes implements AES encryption (formerly Rijndael), as defined in
+// U.S. Federal Information Processing Standards Publication 197.
+//
+// The AES operations in this package are not implemented using constant-time algorithms.
+// An exception is when running on systems with enabled hardware support for AES
+// that makes these operations constant-time. Examples include amd64 systems using AES-NI
+// extensions and s390x systems using Message-Security-Assist extensions.
+// On such systems, when the result of NewCipher is passed to cipher.NewGCM,
+// the GHASH operation used by GCM is also constant-time.
+package aes
+
+// This file contains AES constants - 8720 bytes of initialized data.
+
+// https://csrc.nist.gov/publications/fips/fips197/fips-197.pdf
+
+// AES is based on the mathematical behavior of binary polynomials
+// (polynomials over GF(2)) modulo the irreducible polynomial x⁸ + x⁴ + x³ + x + 1.
+// Addition of these binary polynomials corresponds to binary xor.
+// Reducing mod poly corresponds to binary xor with poly every
+// time a 0x100 bit appears.
+const poly = 1<<8 | 1<<4 | 1<<3 | 1<<1 | 1<<0 // x⁸ + x⁴ + x³ + x + 1
+
+// Powers of x mod poly in GF(2).
+var powx = [16]byte{
+ 0x01,
+ 0x02,
+ 0x04,
+ 0x08,
+ 0x10,
+ 0x20,
+ 0x40,
+ 0x80,
+ 0x1b,
+ 0x36,
+ 0x6c,
+ 0xd8,
+ 0xab,
+ 0x4d,
+ 0x9a,
+ 0x2f,
+}
+
+// FIPS-197 Figure 7. S-box substitution values in hexadecimal format.
+var sbox0 = [256]byte{
+ 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,
+}
+
+// FIPS-197 Figure 14. Inverse S-box substitution values in hexadecimal format.
+var sbox1 = [256]byte{
+ 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,
+}
+
+// Lookup tables for encryption.
+// These can be recomputed by adapting the tests in aes_test.go.
+
+var te0 = [256]uint32{
+ 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,
+}
+var te1 = [256]uint32{
+ 0xa5c66363, 0x84f87c7c, 0x99ee7777, 0x8df67b7b, 0x0dfff2f2, 0xbdd66b6b, 0xb1de6f6f, 0x5491c5c5,
+ 0x50603030, 0x03020101, 0xa9ce6767, 0x7d562b2b, 0x19e7fefe, 0x62b5d7d7, 0xe64dabab, 0x9aec7676,
+ 0x458fcaca, 0x9d1f8282, 0x4089c9c9, 0x87fa7d7d, 0x15effafa, 0xebb25959, 0xc98e4747, 0x0bfbf0f0,
+ 0xec41adad, 0x67b3d4d4, 0xfd5fa2a2, 0xea45afaf, 0xbf239c9c, 0xf753a4a4, 0x96e47272, 0x5b9bc0c0,
+ 0xc275b7b7, 0x1ce1fdfd, 0xae3d9393, 0x6a4c2626, 0x5a6c3636, 0x417e3f3f, 0x02f5f7f7, 0x4f83cccc,
+ 0x5c683434, 0xf451a5a5, 0x34d1e5e5, 0x08f9f1f1, 0x93e27171, 0x73abd8d8, 0x53623131, 0x3f2a1515,
+ 0x0c080404, 0x5295c7c7, 0x65462323, 0x5e9dc3c3, 0x28301818, 0xa1379696, 0x0f0a0505, 0xb52f9a9a,
+ 0x090e0707, 0x36241212, 0x9b1b8080, 0x3ddfe2e2, 0x26cdebeb, 0x694e2727, 0xcd7fb2b2, 0x9fea7575,
+ 0x1b120909, 0x9e1d8383, 0x74582c2c, 0x2e341a1a, 0x2d361b1b, 0xb2dc6e6e, 0xeeb45a5a, 0xfb5ba0a0,
+ 0xf6a45252, 0x4d763b3b, 0x61b7d6d6, 0xce7db3b3, 0x7b522929, 0x3edde3e3, 0x715e2f2f, 0x97138484,
+ 0xf5a65353, 0x68b9d1d1, 0x00000000, 0x2cc1eded, 0x60402020, 0x1fe3fcfc, 0xc879b1b1, 0xedb65b5b,
+ 0xbed46a6a, 0x468dcbcb, 0xd967bebe, 0x4b723939, 0xde944a4a, 0xd4984c4c, 0xe8b05858, 0x4a85cfcf,
+ 0x6bbbd0d0, 0x2ac5efef, 0xe54faaaa, 0x16edfbfb, 0xc5864343, 0xd79a4d4d, 0x55663333, 0x94118585,
+ 0xcf8a4545, 0x10e9f9f9, 0x06040202, 0x81fe7f7f, 0xf0a05050, 0x44783c3c, 0xba259f9f, 0xe34ba8a8,
+ 0xf3a25151, 0xfe5da3a3, 0xc0804040, 0x8a058f8f, 0xad3f9292, 0xbc219d9d, 0x48703838, 0x04f1f5f5,
+ 0xdf63bcbc, 0xc177b6b6, 0x75afdada, 0x63422121, 0x30201010, 0x1ae5ffff, 0x0efdf3f3, 0x6dbfd2d2,
+ 0x4c81cdcd, 0x14180c0c, 0x35261313, 0x2fc3ecec, 0xe1be5f5f, 0xa2359797, 0xcc884444, 0x392e1717,
+ 0x5793c4c4, 0xf255a7a7, 0x82fc7e7e, 0x477a3d3d, 0xacc86464, 0xe7ba5d5d, 0x2b321919, 0x95e67373,
+ 0xa0c06060, 0x98198181, 0xd19e4f4f, 0x7fa3dcdc, 0x66442222, 0x7e542a2a, 0xab3b9090, 0x830b8888,
+ 0xca8c4646, 0x29c7eeee, 0xd36bb8b8, 0x3c281414, 0x79a7dede, 0xe2bc5e5e, 0x1d160b0b, 0x76addbdb,
+ 0x3bdbe0e0, 0x56643232, 0x4e743a3a, 0x1e140a0a, 0xdb924949, 0x0a0c0606, 0x6c482424, 0xe4b85c5c,
+ 0x5d9fc2c2, 0x6ebdd3d3, 0xef43acac, 0xa6c46262, 0xa8399191, 0xa4319595, 0x37d3e4e4, 0x8bf27979,
+ 0x32d5e7e7, 0x438bc8c8, 0x596e3737, 0xb7da6d6d, 0x8c018d8d, 0x64b1d5d5, 0xd29c4e4e, 0xe049a9a9,
+ 0xb4d86c6c, 0xfaac5656, 0x07f3f4f4, 0x25cfeaea, 0xafca6565, 0x8ef47a7a, 0xe947aeae, 0x18100808,
+ 0xd56fbaba, 0x88f07878, 0x6f4a2525, 0x725c2e2e, 0x24381c1c, 0xf157a6a6, 0xc773b4b4, 0x5197c6c6,
+ 0x23cbe8e8, 0x7ca1dddd, 0x9ce87474, 0x213e1f1f, 0xdd964b4b, 0xdc61bdbd, 0x860d8b8b, 0x850f8a8a,
+ 0x90e07070, 0x427c3e3e, 0xc471b5b5, 0xaacc6666, 0xd8904848, 0x05060303, 0x01f7f6f6, 0x121c0e0e,
+ 0xa3c26161, 0x5f6a3535, 0xf9ae5757, 0xd069b9b9, 0x91178686, 0x5899c1c1, 0x273a1d1d, 0xb9279e9e,
+ 0x38d9e1e1, 0x13ebf8f8, 0xb32b9898, 0x33221111, 0xbbd26969, 0x70a9d9d9, 0x89078e8e, 0xa7339494,
+ 0xb62d9b9b, 0x223c1e1e, 0x92158787, 0x20c9e9e9, 0x4987cece, 0xffaa5555, 0x78502828, 0x7aa5dfdf,
+ 0x8f038c8c, 0xf859a1a1, 0x80098989, 0x171a0d0d, 0xda65bfbf, 0x31d7e6e6, 0xc6844242, 0xb8d06868,
+ 0xc3824141, 0xb0299999, 0x775a2d2d, 0x111e0f0f, 0xcb7bb0b0, 0xfca85454, 0xd66dbbbb, 0x3a2c1616,
+}
+var te2 = [256]uint32{
+ 0x63a5c663, 0x7c84f87c, 0x7799ee77, 0x7b8df67b, 0xf20dfff2, 0x6bbdd66b, 0x6fb1de6f, 0xc55491c5,
+ 0x30506030, 0x01030201, 0x67a9ce67, 0x2b7d562b, 0xfe19e7fe, 0xd762b5d7, 0xabe64dab, 0x769aec76,
+ 0xca458fca, 0x829d1f82, 0xc94089c9, 0x7d87fa7d, 0xfa15effa, 0x59ebb259, 0x47c98e47, 0xf00bfbf0,
+ 0xadec41ad, 0xd467b3d4, 0xa2fd5fa2, 0xafea45af, 0x9cbf239c, 0xa4f753a4, 0x7296e472, 0xc05b9bc0,
+ 0xb7c275b7, 0xfd1ce1fd, 0x93ae3d93, 0x266a4c26, 0x365a6c36, 0x3f417e3f, 0xf702f5f7, 0xcc4f83cc,
+ 0x345c6834, 0xa5f451a5, 0xe534d1e5, 0xf108f9f1, 0x7193e271, 0xd873abd8, 0x31536231, 0x153f2a15,
+ 0x040c0804, 0xc75295c7, 0x23654623, 0xc35e9dc3, 0x18283018, 0x96a13796, 0x050f0a05, 0x9ab52f9a,
+ 0x07090e07, 0x12362412, 0x809b1b80, 0xe23ddfe2, 0xeb26cdeb, 0x27694e27, 0xb2cd7fb2, 0x759fea75,
+ 0x091b1209, 0x839e1d83, 0x2c74582c, 0x1a2e341a, 0x1b2d361b, 0x6eb2dc6e, 0x5aeeb45a, 0xa0fb5ba0,
+ 0x52f6a452, 0x3b4d763b, 0xd661b7d6, 0xb3ce7db3, 0x297b5229, 0xe33edde3, 0x2f715e2f, 0x84971384,
+ 0x53f5a653, 0xd168b9d1, 0x00000000, 0xed2cc1ed, 0x20604020, 0xfc1fe3fc, 0xb1c879b1, 0x5bedb65b,
+ 0x6abed46a, 0xcb468dcb, 0xbed967be, 0x394b7239, 0x4ade944a, 0x4cd4984c, 0x58e8b058, 0xcf4a85cf,
+ 0xd06bbbd0, 0xef2ac5ef, 0xaae54faa, 0xfb16edfb, 0x43c58643, 0x4dd79a4d, 0x33556633, 0x85941185,
+ 0x45cf8a45, 0xf910e9f9, 0x02060402, 0x7f81fe7f, 0x50f0a050, 0x3c44783c, 0x9fba259f, 0xa8e34ba8,
+ 0x51f3a251, 0xa3fe5da3, 0x40c08040, 0x8f8a058f, 0x92ad3f92, 0x9dbc219d, 0x38487038, 0xf504f1f5,
+ 0xbcdf63bc, 0xb6c177b6, 0xda75afda, 0x21634221, 0x10302010, 0xff1ae5ff, 0xf30efdf3, 0xd26dbfd2,
+ 0xcd4c81cd, 0x0c14180c, 0x13352613, 0xec2fc3ec, 0x5fe1be5f, 0x97a23597, 0x44cc8844, 0x17392e17,
+ 0xc45793c4, 0xa7f255a7, 0x7e82fc7e, 0x3d477a3d, 0x64acc864, 0x5de7ba5d, 0x192b3219, 0x7395e673,
+ 0x60a0c060, 0x81981981, 0x4fd19e4f, 0xdc7fa3dc, 0x22664422, 0x2a7e542a, 0x90ab3b90, 0x88830b88,
+ 0x46ca8c46, 0xee29c7ee, 0xb8d36bb8, 0x143c2814, 0xde79a7de, 0x5ee2bc5e, 0x0b1d160b, 0xdb76addb,
+ 0xe03bdbe0, 0x32566432, 0x3a4e743a, 0x0a1e140a, 0x49db9249, 0x060a0c06, 0x246c4824, 0x5ce4b85c,
+ 0xc25d9fc2, 0xd36ebdd3, 0xacef43ac, 0x62a6c462, 0x91a83991, 0x95a43195, 0xe437d3e4, 0x798bf279,
+ 0xe732d5e7, 0xc8438bc8, 0x37596e37, 0x6db7da6d, 0x8d8c018d, 0xd564b1d5, 0x4ed29c4e, 0xa9e049a9,
+ 0x6cb4d86c, 0x56faac56, 0xf407f3f4, 0xea25cfea, 0x65afca65, 0x7a8ef47a, 0xaee947ae, 0x08181008,
+ 0xbad56fba, 0x7888f078, 0x256f4a25, 0x2e725c2e, 0x1c24381c, 0xa6f157a6, 0xb4c773b4, 0xc65197c6,
+ 0xe823cbe8, 0xdd7ca1dd, 0x749ce874, 0x1f213e1f, 0x4bdd964b, 0xbddc61bd, 0x8b860d8b, 0x8a850f8a,
+ 0x7090e070, 0x3e427c3e, 0xb5c471b5, 0x66aacc66, 0x48d89048, 0x03050603, 0xf601f7f6, 0x0e121c0e,
+ 0x61a3c261, 0x355f6a35, 0x57f9ae57, 0xb9d069b9, 0x86911786, 0xc15899c1, 0x1d273a1d, 0x9eb9279e,
+ 0xe138d9e1, 0xf813ebf8, 0x98b32b98, 0x11332211, 0x69bbd269, 0xd970a9d9, 0x8e89078e, 0x94a73394,
+ 0x9bb62d9b, 0x1e223c1e, 0x87921587, 0xe920c9e9, 0xce4987ce, 0x55ffaa55, 0x28785028, 0xdf7aa5df,
+ 0x8c8f038c, 0xa1f859a1, 0x89800989, 0x0d171a0d, 0xbfda65bf, 0xe631d7e6, 0x42c68442, 0x68b8d068,
+ 0x41c38241, 0x99b02999, 0x2d775a2d, 0x0f111e0f, 0xb0cb7bb0, 0x54fca854, 0xbbd66dbb, 0x163a2c16,
+}
+var te3 = [256]uint32{
+ 0x6363a5c6, 0x7c7c84f8, 0x777799ee, 0x7b7b8df6, 0xf2f20dff, 0x6b6bbdd6, 0x6f6fb1de, 0xc5c55491,
+ 0x30305060, 0x01010302, 0x6767a9ce, 0x2b2b7d56, 0xfefe19e7, 0xd7d762b5, 0xababe64d, 0x76769aec,
+ 0xcaca458f, 0x82829d1f, 0xc9c94089, 0x7d7d87fa, 0xfafa15ef, 0x5959ebb2, 0x4747c98e, 0xf0f00bfb,
+ 0xadadec41, 0xd4d467b3, 0xa2a2fd5f, 0xafafea45, 0x9c9cbf23, 0xa4a4f753, 0x727296e4, 0xc0c05b9b,
+ 0xb7b7c275, 0xfdfd1ce1, 0x9393ae3d, 0x26266a4c, 0x36365a6c, 0x3f3f417e, 0xf7f702f5, 0xcccc4f83,
+ 0x34345c68, 0xa5a5f451, 0xe5e534d1, 0xf1f108f9, 0x717193e2, 0xd8d873ab, 0x31315362, 0x15153f2a,
+ 0x04040c08, 0xc7c75295, 0x23236546, 0xc3c35e9d, 0x18182830, 0x9696a137, 0x05050f0a, 0x9a9ab52f,
+ 0x0707090e, 0x12123624, 0x80809b1b, 0xe2e23ddf, 0xebeb26cd, 0x2727694e, 0xb2b2cd7f, 0x75759fea,
+ 0x09091b12, 0x83839e1d, 0x2c2c7458, 0x1a1a2e34, 0x1b1b2d36, 0x6e6eb2dc, 0x5a5aeeb4, 0xa0a0fb5b,
+ 0x5252f6a4, 0x3b3b4d76, 0xd6d661b7, 0xb3b3ce7d, 0x29297b52, 0xe3e33edd, 0x2f2f715e, 0x84849713,
+ 0x5353f5a6, 0xd1d168b9, 0x00000000, 0xeded2cc1, 0x20206040, 0xfcfc1fe3, 0xb1b1c879, 0x5b5bedb6,
+ 0x6a6abed4, 0xcbcb468d, 0xbebed967, 0x39394b72, 0x4a4ade94, 0x4c4cd498, 0x5858e8b0, 0xcfcf4a85,
+ 0xd0d06bbb, 0xefef2ac5, 0xaaaae54f, 0xfbfb16ed, 0x4343c586, 0x4d4dd79a, 0x33335566, 0x85859411,
+ 0x4545cf8a, 0xf9f910e9, 0x02020604, 0x7f7f81fe, 0x5050f0a0, 0x3c3c4478, 0x9f9fba25, 0xa8a8e34b,
+ 0x5151f3a2, 0xa3a3fe5d, 0x4040c080, 0x8f8f8a05, 0x9292ad3f, 0x9d9dbc21, 0x38384870, 0xf5f504f1,
+ 0xbcbcdf63, 0xb6b6c177, 0xdada75af, 0x21216342, 0x10103020, 0xffff1ae5, 0xf3f30efd, 0xd2d26dbf,
+ 0xcdcd4c81, 0x0c0c1418, 0x13133526, 0xecec2fc3, 0x5f5fe1be, 0x9797a235, 0x4444cc88, 0x1717392e,
+ 0xc4c45793, 0xa7a7f255, 0x7e7e82fc, 0x3d3d477a, 0x6464acc8, 0x5d5de7ba, 0x19192b32, 0x737395e6,
+ 0x6060a0c0, 0x81819819, 0x4f4fd19e, 0xdcdc7fa3, 0x22226644, 0x2a2a7e54, 0x9090ab3b, 0x8888830b,
+ 0x4646ca8c, 0xeeee29c7, 0xb8b8d36b, 0x14143c28, 0xdede79a7, 0x5e5ee2bc, 0x0b0b1d16, 0xdbdb76ad,
+ 0xe0e03bdb, 0x32325664, 0x3a3a4e74, 0x0a0a1e14, 0x4949db92, 0x06060a0c, 0x24246c48, 0x5c5ce4b8,
+ 0xc2c25d9f, 0xd3d36ebd, 0xacacef43, 0x6262a6c4, 0x9191a839, 0x9595a431, 0xe4e437d3, 0x79798bf2,
+ 0xe7e732d5, 0xc8c8438b, 0x3737596e, 0x6d6db7da, 0x8d8d8c01, 0xd5d564b1, 0x4e4ed29c, 0xa9a9e049,
+ 0x6c6cb4d8, 0x5656faac, 0xf4f407f3, 0xeaea25cf, 0x6565afca, 0x7a7a8ef4, 0xaeaee947, 0x08081810,
+ 0xbabad56f, 0x787888f0, 0x25256f4a, 0x2e2e725c, 0x1c1c2438, 0xa6a6f157, 0xb4b4c773, 0xc6c65197,
+ 0xe8e823cb, 0xdddd7ca1, 0x74749ce8, 0x1f1f213e, 0x4b4bdd96, 0xbdbddc61, 0x8b8b860d, 0x8a8a850f,
+ 0x707090e0, 0x3e3e427c, 0xb5b5c471, 0x6666aacc, 0x4848d890, 0x03030506, 0xf6f601f7, 0x0e0e121c,
+ 0x6161a3c2, 0x35355f6a, 0x5757f9ae, 0xb9b9d069, 0x86869117, 0xc1c15899, 0x1d1d273a, 0x9e9eb927,
+ 0xe1e138d9, 0xf8f813eb, 0x9898b32b, 0x11113322, 0x6969bbd2, 0xd9d970a9, 0x8e8e8907, 0x9494a733,
+ 0x9b9bb62d, 0x1e1e223c, 0x87879215, 0xe9e920c9, 0xcece4987, 0x5555ffaa, 0x28287850, 0xdfdf7aa5,
+ 0x8c8c8f03, 0xa1a1f859, 0x89898009, 0x0d0d171a, 0xbfbfda65, 0xe6e631d7, 0x4242c684, 0x6868b8d0,
+ 0x4141c382, 0x9999b029, 0x2d2d775a, 0x0f0f111e, 0xb0b0cb7b, 0x5454fca8, 0xbbbbd66d, 0x16163a2c,
+}
+
+// Lookup tables for decryption.
+// These can be recomputed by adapting the tests in aes_test.go.
+
+var td0 = [256]uint32{
+ 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,
+}
+var td1 = [256]uint32{
+ 0x5051f4a7, 0x537e4165, 0xc31a17a4, 0x963a275e, 0xcb3bab6b, 0xf11f9d45, 0xabacfa58, 0x934be303,
+ 0x552030fa, 0xf6ad766d, 0x9188cc76, 0x25f5024c, 0xfc4fe5d7, 0xd7c52acb, 0x80263544, 0x8fb562a3,
+ 0x49deb15a, 0x6725ba1b, 0x9845ea0e, 0xe15dfec0, 0x02c32f75, 0x12814cf0, 0xa38d4697, 0xc66bd3f9,
+ 0xe7038f5f, 0x9515929c, 0xebbf6d7a, 0xda955259, 0x2dd4be83, 0xd3587421, 0x2949e069, 0x448ec9c8,
+ 0x6a75c289, 0x78f48e79, 0x6b99583e, 0xdd27b971, 0xb6bee14f, 0x17f088ad, 0x66c920ac, 0xb47dce3a,
+ 0x1863df4a, 0x82e51a31, 0x60975133, 0x4562537f, 0xe0b16477, 0x84bb6bae, 0x1cfe81a0, 0x94f9082b,
+ 0x58704868, 0x198f45fd, 0x8794de6c, 0xb7527bf8, 0x23ab73d3, 0xe2724b02, 0x57e31f8f, 0x2a6655ab,
+ 0x07b2eb28, 0x032fb5c2, 0x9a86c57b, 0xa5d33708, 0xf2302887, 0xb223bfa5, 0xba02036a, 0x5ced1682,
+ 0x2b8acf1c, 0x92a779b4, 0xf0f307f2, 0xa14e69e2, 0xcd65daf4, 0xd50605be, 0x1fd13462, 0x8ac4a6fe,
+ 0x9d342e53, 0xa0a2f355, 0x32058ae1, 0x75a4f6eb, 0x390b83ec, 0xaa4060ef, 0x065e719f, 0x51bd6e10,
+ 0xf93e218a, 0x3d96dd06, 0xaedd3e05, 0x464de6bd, 0xb591548d, 0x0571c45d, 0x6f0406d4, 0xff605015,
+ 0x241998fb, 0x97d6bde9, 0xcc894043, 0x7767d99e, 0xbdb0e842, 0x8807898b, 0x38e7195b, 0xdb79c8ee,
+ 0x47a17c0a, 0xe97c420f, 0xc9f8841e, 0x00000000, 0x83098086, 0x48322bed, 0xac1e1170, 0x4e6c5a72,
+ 0xfbfd0eff, 0x560f8538, 0x1e3daed5, 0x27362d39, 0x640a0fd9, 0x21685ca6, 0xd19b5b54, 0x3a24362e,
+ 0xb10c0a67, 0x0f9357e7, 0xd2b4ee96, 0x9e1b9b91, 0x4f80c0c5, 0xa261dc20, 0x695a774b, 0x161c121a,
+ 0x0ae293ba, 0xe5c0a02a, 0x433c22e0, 0x1d121b17, 0x0b0e090d, 0xadf28bc7, 0xb92db6a8, 0xc8141ea9,
+ 0x8557f119, 0x4caf7507, 0xbbee99dd, 0xfda37f60, 0x9ff70126, 0xbc5c72f5, 0xc544663b, 0x345bfb7e,
+ 0x768b4329, 0xdccb23c6, 0x68b6edfc, 0x63b8e4f1, 0xcad731dc, 0x10426385, 0x40139722, 0x2084c611,
+ 0x7d854a24, 0xf8d2bb3d, 0x11aef932, 0x6dc729a1, 0x4b1d9e2f, 0xf3dcb230, 0xec0d8652, 0xd077c1e3,
+ 0x6c2bb316, 0x99a970b9, 0xfa119448, 0x2247e964, 0xc4a8fc8c, 0x1aa0f03f, 0xd8567d2c, 0xef223390,
+ 0xc787494e, 0xc1d938d1, 0xfe8ccaa2, 0x3698d40b, 0xcfa6f581, 0x28a57ade, 0x26dab78e, 0xa43fadbf,
+ 0xe42c3a9d, 0x0d507892, 0x9b6a5fcc, 0x62547e46, 0xc2f68d13, 0xe890d8b8, 0x5e2e39f7, 0xf582c3af,
+ 0xbe9f5d80, 0x7c69d093, 0xa96fd52d, 0xb3cf2512, 0x3bc8ac99, 0xa710187d, 0x6ee89c63, 0x7bdb3bbb,
+ 0x09cd2678, 0xf46e5918, 0x01ec9ab7, 0xa8834f9a, 0x65e6956e, 0x7eaaffe6, 0x0821bccf, 0xe6ef15e8,
+ 0xd9bae79b, 0xce4a6f36, 0xd4ea9f09, 0xd629b07c, 0xaf31a4b2, 0x312a3f23, 0x30c6a594, 0xc035a266,
+ 0x37744ebc, 0xa6fc82ca, 0xb0e090d0, 0x1533a7d8, 0x4af10498, 0xf741ecda, 0x0e7fcd50, 0x2f1791f6,
+ 0x8d764dd6, 0x4d43efb0, 0x54ccaa4d, 0xdfe49604, 0xe39ed1b5, 0x1b4c6a88, 0xb8c12c1f, 0x7f466551,
+ 0x049d5eea, 0x5d018c35, 0x73fa8774, 0x2efb0b41, 0x5ab3671d, 0x5292dbd2, 0x33e91056, 0x136dd647,
+ 0x8c9ad761, 0x7a37a10c, 0x8e59f814, 0x89eb133c, 0xeecea927, 0x35b761c9, 0xede11ce5, 0x3c7a47b1,
+ 0x599cd2df, 0x3f55f273, 0x791814ce, 0xbf73c737, 0xea53f7cd, 0x5b5ffdaa, 0x14df3d6f, 0x867844db,
+ 0x81caaff3, 0x3eb968c4, 0x2c382434, 0x5fc2a340, 0x72161dc3, 0x0cbce225, 0x8b283c49, 0x41ff0d95,
+ 0x7139a801, 0xde080cb3, 0x9cd8b4e4, 0x906456c1, 0x617bcb84, 0x70d532b6, 0x74486c5c, 0x42d0b857,
+}
+var td2 = [256]uint32{
+ 0xa75051f4, 0x65537e41, 0xa4c31a17, 0x5e963a27, 0x6bcb3bab, 0x45f11f9d, 0x58abacfa, 0x03934be3,
+ 0xfa552030, 0x6df6ad76, 0x769188cc, 0x4c25f502, 0xd7fc4fe5, 0xcbd7c52a, 0x44802635, 0xa38fb562,
+ 0x5a49deb1, 0x1b6725ba, 0x0e9845ea, 0xc0e15dfe, 0x7502c32f, 0xf012814c, 0x97a38d46, 0xf9c66bd3,
+ 0x5fe7038f, 0x9c951592, 0x7aebbf6d, 0x59da9552, 0x832dd4be, 0x21d35874, 0x692949e0, 0xc8448ec9,
+ 0x896a75c2, 0x7978f48e, 0x3e6b9958, 0x71dd27b9, 0x4fb6bee1, 0xad17f088, 0xac66c920, 0x3ab47dce,
+ 0x4a1863df, 0x3182e51a, 0x33609751, 0x7f456253, 0x77e0b164, 0xae84bb6b, 0xa01cfe81, 0x2b94f908,
+ 0x68587048, 0xfd198f45, 0x6c8794de, 0xf8b7527b, 0xd323ab73, 0x02e2724b, 0x8f57e31f, 0xab2a6655,
+ 0x2807b2eb, 0xc2032fb5, 0x7b9a86c5, 0x08a5d337, 0x87f23028, 0xa5b223bf, 0x6aba0203, 0x825ced16,
+ 0x1c2b8acf, 0xb492a779, 0xf2f0f307, 0xe2a14e69, 0xf4cd65da, 0xbed50605, 0x621fd134, 0xfe8ac4a6,
+ 0x539d342e, 0x55a0a2f3, 0xe132058a, 0xeb75a4f6, 0xec390b83, 0xefaa4060, 0x9f065e71, 0x1051bd6e,
+ 0x8af93e21, 0x063d96dd, 0x05aedd3e, 0xbd464de6, 0x8db59154, 0x5d0571c4, 0xd46f0406, 0x15ff6050,
+ 0xfb241998, 0xe997d6bd, 0x43cc8940, 0x9e7767d9, 0x42bdb0e8, 0x8b880789, 0x5b38e719, 0xeedb79c8,
+ 0x0a47a17c, 0x0fe97c42, 0x1ec9f884, 0x00000000, 0x86830980, 0xed48322b, 0x70ac1e11, 0x724e6c5a,
+ 0xfffbfd0e, 0x38560f85, 0xd51e3dae, 0x3927362d, 0xd9640a0f, 0xa621685c, 0x54d19b5b, 0x2e3a2436,
+ 0x67b10c0a, 0xe70f9357, 0x96d2b4ee, 0x919e1b9b, 0xc54f80c0, 0x20a261dc, 0x4b695a77, 0x1a161c12,
+ 0xba0ae293, 0x2ae5c0a0, 0xe0433c22, 0x171d121b, 0x0d0b0e09, 0xc7adf28b, 0xa8b92db6, 0xa9c8141e,
+ 0x198557f1, 0x074caf75, 0xddbbee99, 0x60fda37f, 0x269ff701, 0xf5bc5c72, 0x3bc54466, 0x7e345bfb,
+ 0x29768b43, 0xc6dccb23, 0xfc68b6ed, 0xf163b8e4, 0xdccad731, 0x85104263, 0x22401397, 0x112084c6,
+ 0x247d854a, 0x3df8d2bb, 0x3211aef9, 0xa16dc729, 0x2f4b1d9e, 0x30f3dcb2, 0x52ec0d86, 0xe3d077c1,
+ 0x166c2bb3, 0xb999a970, 0x48fa1194, 0x642247e9, 0x8cc4a8fc, 0x3f1aa0f0, 0x2cd8567d, 0x90ef2233,
+ 0x4ec78749, 0xd1c1d938, 0xa2fe8cca, 0x0b3698d4, 0x81cfa6f5, 0xde28a57a, 0x8e26dab7, 0xbfa43fad,
+ 0x9de42c3a, 0x920d5078, 0xcc9b6a5f, 0x4662547e, 0x13c2f68d, 0xb8e890d8, 0xf75e2e39, 0xaff582c3,
+ 0x80be9f5d, 0x937c69d0, 0x2da96fd5, 0x12b3cf25, 0x993bc8ac, 0x7da71018, 0x636ee89c, 0xbb7bdb3b,
+ 0x7809cd26, 0x18f46e59, 0xb701ec9a, 0x9aa8834f, 0x6e65e695, 0xe67eaaff, 0xcf0821bc, 0xe8e6ef15,
+ 0x9bd9bae7, 0x36ce4a6f, 0x09d4ea9f, 0x7cd629b0, 0xb2af31a4, 0x23312a3f, 0x9430c6a5, 0x66c035a2,
+ 0xbc37744e, 0xcaa6fc82, 0xd0b0e090, 0xd81533a7, 0x984af104, 0xdaf741ec, 0x500e7fcd, 0xf62f1791,
+ 0xd68d764d, 0xb04d43ef, 0x4d54ccaa, 0x04dfe496, 0xb5e39ed1, 0x881b4c6a, 0x1fb8c12c, 0x517f4665,
+ 0xea049d5e, 0x355d018c, 0x7473fa87, 0x412efb0b, 0x1d5ab367, 0xd25292db, 0x5633e910, 0x47136dd6,
+ 0x618c9ad7, 0x0c7a37a1, 0x148e59f8, 0x3c89eb13, 0x27eecea9, 0xc935b761, 0xe5ede11c, 0xb13c7a47,
+ 0xdf599cd2, 0x733f55f2, 0xce791814, 0x37bf73c7, 0xcdea53f7, 0xaa5b5ffd, 0x6f14df3d, 0xdb867844,
+ 0xf381caaf, 0xc43eb968, 0x342c3824, 0x405fc2a3, 0xc372161d, 0x250cbce2, 0x498b283c, 0x9541ff0d,
+ 0x017139a8, 0xb3de080c, 0xe49cd8b4, 0xc1906456, 0x84617bcb, 0xb670d532, 0x5c74486c, 0x5742d0b8,
+}
+var td3 = [256]uint32{
+ 0xf4a75051, 0x4165537e, 0x17a4c31a, 0x275e963a, 0xab6bcb3b, 0x9d45f11f, 0xfa58abac, 0xe303934b,
+ 0x30fa5520, 0x766df6ad, 0xcc769188, 0x024c25f5, 0xe5d7fc4f, 0x2acbd7c5, 0x35448026, 0x62a38fb5,
+ 0xb15a49de, 0xba1b6725, 0xea0e9845, 0xfec0e15d, 0x2f7502c3, 0x4cf01281, 0x4697a38d, 0xd3f9c66b,
+ 0x8f5fe703, 0x929c9515, 0x6d7aebbf, 0x5259da95, 0xbe832dd4, 0x7421d358, 0xe0692949, 0xc9c8448e,
+ 0xc2896a75, 0x8e7978f4, 0x583e6b99, 0xb971dd27, 0xe14fb6be, 0x88ad17f0, 0x20ac66c9, 0xce3ab47d,
+ 0xdf4a1863, 0x1a3182e5, 0x51336097, 0x537f4562, 0x6477e0b1, 0x6bae84bb, 0x81a01cfe, 0x082b94f9,
+ 0x48685870, 0x45fd198f, 0xde6c8794, 0x7bf8b752, 0x73d323ab, 0x4b02e272, 0x1f8f57e3, 0x55ab2a66,
+ 0xeb2807b2, 0xb5c2032f, 0xc57b9a86, 0x3708a5d3, 0x2887f230, 0xbfa5b223, 0x036aba02, 0x16825ced,
+ 0xcf1c2b8a, 0x79b492a7, 0x07f2f0f3, 0x69e2a14e, 0xdaf4cd65, 0x05bed506, 0x34621fd1, 0xa6fe8ac4,
+ 0x2e539d34, 0xf355a0a2, 0x8ae13205, 0xf6eb75a4, 0x83ec390b, 0x60efaa40, 0x719f065e, 0x6e1051bd,
+ 0x218af93e, 0xdd063d96, 0x3e05aedd, 0xe6bd464d, 0x548db591, 0xc45d0571, 0x06d46f04, 0x5015ff60,
+ 0x98fb2419, 0xbde997d6, 0x4043cc89, 0xd99e7767, 0xe842bdb0, 0x898b8807, 0x195b38e7, 0xc8eedb79,
+ 0x7c0a47a1, 0x420fe97c, 0x841ec9f8, 0x00000000, 0x80868309, 0x2bed4832, 0x1170ac1e, 0x5a724e6c,
+ 0x0efffbfd, 0x8538560f, 0xaed51e3d, 0x2d392736, 0x0fd9640a, 0x5ca62168, 0x5b54d19b, 0x362e3a24,
+ 0x0a67b10c, 0x57e70f93, 0xee96d2b4, 0x9b919e1b, 0xc0c54f80, 0xdc20a261, 0x774b695a, 0x121a161c,
+ 0x93ba0ae2, 0xa02ae5c0, 0x22e0433c, 0x1b171d12, 0x090d0b0e, 0x8bc7adf2, 0xb6a8b92d, 0x1ea9c814,
+ 0xf1198557, 0x75074caf, 0x99ddbbee, 0x7f60fda3, 0x01269ff7, 0x72f5bc5c, 0x663bc544, 0xfb7e345b,
+ 0x4329768b, 0x23c6dccb, 0xedfc68b6, 0xe4f163b8, 0x31dccad7, 0x63851042, 0x97224013, 0xc6112084,
+ 0x4a247d85, 0xbb3df8d2, 0xf93211ae, 0x29a16dc7, 0x9e2f4b1d, 0xb230f3dc, 0x8652ec0d, 0xc1e3d077,
+ 0xb3166c2b, 0x70b999a9, 0x9448fa11, 0xe9642247, 0xfc8cc4a8, 0xf03f1aa0, 0x7d2cd856, 0x3390ef22,
+ 0x494ec787, 0x38d1c1d9, 0xcaa2fe8c, 0xd40b3698, 0xf581cfa6, 0x7ade28a5, 0xb78e26da, 0xadbfa43f,
+ 0x3a9de42c, 0x78920d50, 0x5fcc9b6a, 0x7e466254, 0x8d13c2f6, 0xd8b8e890, 0x39f75e2e, 0xc3aff582,
+ 0x5d80be9f, 0xd0937c69, 0xd52da96f, 0x2512b3cf, 0xac993bc8, 0x187da710, 0x9c636ee8, 0x3bbb7bdb,
+ 0x267809cd, 0x5918f46e, 0x9ab701ec, 0x4f9aa883, 0x956e65e6, 0xffe67eaa, 0xbccf0821, 0x15e8e6ef,
+ 0xe79bd9ba, 0x6f36ce4a, 0x9f09d4ea, 0xb07cd629, 0xa4b2af31, 0x3f23312a, 0xa59430c6, 0xa266c035,
+ 0x4ebc3774, 0x82caa6fc, 0x90d0b0e0, 0xa7d81533, 0x04984af1, 0xecdaf741, 0xcd500e7f, 0x91f62f17,
+ 0x4dd68d76, 0xefb04d43, 0xaa4d54cc, 0x9604dfe4, 0xd1b5e39e, 0x6a881b4c, 0x2c1fb8c1, 0x65517f46,
+ 0x5eea049d, 0x8c355d01, 0x877473fa, 0x0b412efb, 0x671d5ab3, 0xdbd25292, 0x105633e9, 0xd647136d,
+ 0xd7618c9a, 0xa10c7a37, 0xf8148e59, 0x133c89eb, 0xa927eece, 0x61c935b7, 0x1ce5ede1, 0x47b13c7a,
+ 0xd2df599c, 0xf2733f55, 0x14ce7918, 0xc737bf73, 0xf7cdea53, 0xfdaa5b5f, 0x3d6f14df, 0x44db8678,
+ 0xaff381ca, 0x68c43eb9, 0x24342c38, 0xa3405fc2, 0x1dc37216, 0xe2250cbc, 0x3c498b28, 0x0d9541ff,
+ 0xa8017139, 0x0cb3de08, 0xb4e49cd8, 0x56c19064, 0xcb84617b, 0x32b670d5, 0x6c5c7448, 0xb85742d0,
+}
diff --git a/src/crypto/aes/ctr_s390x.go b/src/crypto/aes/ctr_s390x.go
new file mode 100644
index 0000000..0d3a58e
--- /dev/null
+++ b/src/crypto/aes/ctr_s390x.go
@@ -0,0 +1,84 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aes
+
+import (
+ "crypto/cipher"
+ "crypto/internal/alias"
+ "encoding/binary"
+)
+
+// Assert that aesCipherAsm implements the ctrAble interface.
+var _ ctrAble = (*aesCipherAsm)(nil)
+
+// xorBytes xors the contents of a and b and places the resulting values into
+// dst. If a and b are not the same length then the number of bytes processed
+// will be equal to the length of shorter of the two. Returns the number
+// of bytes processed.
+//
+//go:noescape
+func xorBytes(dst, a, b []byte) int
+
+// streamBufferSize is the number of bytes of encrypted counter values to cache.
+const streamBufferSize = 32 * BlockSize
+
+type aesctr struct {
+ block *aesCipherAsm // block cipher
+ ctr [2]uint64 // next value of the counter (big endian)
+ buffer []byte // buffer for the encrypted counter values
+ storage [streamBufferSize]byte // array backing buffer slice
+}
+
+// NewCTR returns a Stream which encrypts/decrypts using the AES block
+// cipher in counter mode. The length of iv must be the same as BlockSize.
+func (c *aesCipherAsm) NewCTR(iv []byte) cipher.Stream {
+ if len(iv) != BlockSize {
+ panic("cipher.NewCTR: IV length must equal block size")
+ }
+ var ac aesctr
+ ac.block = c
+ ac.ctr[0] = binary.BigEndian.Uint64(iv[0:]) // high bits
+ ac.ctr[1] = binary.BigEndian.Uint64(iv[8:]) // low bits
+ ac.buffer = ac.storage[:0]
+ return &ac
+}
+
+func (c *aesctr) refill() {
+ // Fill up the buffer with an incrementing count.
+ c.buffer = c.storage[:streamBufferSize]
+ c0, c1 := c.ctr[0], c.ctr[1]
+ for i := 0; i < streamBufferSize; i += 16 {
+ binary.BigEndian.PutUint64(c.buffer[i+0:], c0)
+ binary.BigEndian.PutUint64(c.buffer[i+8:], c1)
+
+ // Increment in big endian: c0 is high, c1 is low.
+ c1++
+ if c1 == 0 {
+ // add carry
+ c0++
+ }
+ }
+ c.ctr[0], c.ctr[1] = c0, c1
+ // Encrypt the buffer using AES in ECB mode.
+ cryptBlocks(c.block.function, &c.block.key[0], &c.buffer[0], &c.buffer[0], streamBufferSize)
+}
+
+func (c *aesctr) XORKeyStream(dst, src []byte) {
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if alias.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+ for len(src) > 0 {
+ if len(c.buffer) == 0 {
+ c.refill()
+ }
+ n := xorBytes(dst, src, c.buffer)
+ c.buffer = c.buffer[n:]
+ src = src[n:]
+ dst = dst[n:]
+ }
+}
diff --git a/src/crypto/aes/gcm_amd64.s b/src/crypto/aes/gcm_amd64.s
new file mode 100644
index 0000000..e6eedf3
--- /dev/null
+++ b/src/crypto/aes/gcm_amd64.s
@@ -0,0 +1,1286 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This is an optimized implementation of AES-GCM using AES-NI and CLMUL-NI
+// The implementation uses some optimization as described in:
+// [1] Gueron, S., Kounavis, M.E.: Intel® Carry-Less Multiplication
+// Instruction and its Usage for Computing the GCM Mode rev. 2.02
+// [2] Gueron, S., Krasnov, V.: Speeding up Counter Mode in Software and
+// Hardware
+
+#include "textflag.h"
+
+#define B0 X0
+#define B1 X1
+#define B2 X2
+#define B3 X3
+#define B4 X4
+#define B5 X5
+#define B6 X6
+#define B7 X7
+
+#define ACC0 X8
+#define ACC1 X9
+#define ACCM X10
+
+#define T0 X11
+#define T1 X12
+#define T2 X13
+#define POLY X14
+#define BSWAP X15
+
+DATA bswapMask<>+0x00(SB)/8, $0x08090a0b0c0d0e0f
+DATA bswapMask<>+0x08(SB)/8, $0x0001020304050607
+
+DATA gcmPoly<>+0x00(SB)/8, $0x0000000000000001
+DATA gcmPoly<>+0x08(SB)/8, $0xc200000000000000
+
+DATA andMask<>+0x00(SB)/8, $0x00000000000000ff
+DATA andMask<>+0x08(SB)/8, $0x0000000000000000
+DATA andMask<>+0x10(SB)/8, $0x000000000000ffff
+DATA andMask<>+0x18(SB)/8, $0x0000000000000000
+DATA andMask<>+0x20(SB)/8, $0x0000000000ffffff
+DATA andMask<>+0x28(SB)/8, $0x0000000000000000
+DATA andMask<>+0x30(SB)/8, $0x00000000ffffffff
+DATA andMask<>+0x38(SB)/8, $0x0000000000000000
+DATA andMask<>+0x40(SB)/8, $0x000000ffffffffff
+DATA andMask<>+0x48(SB)/8, $0x0000000000000000
+DATA andMask<>+0x50(SB)/8, $0x0000ffffffffffff
+DATA andMask<>+0x58(SB)/8, $0x0000000000000000
+DATA andMask<>+0x60(SB)/8, $0x00ffffffffffffff
+DATA andMask<>+0x68(SB)/8, $0x0000000000000000
+DATA andMask<>+0x70(SB)/8, $0xffffffffffffffff
+DATA andMask<>+0x78(SB)/8, $0x0000000000000000
+DATA andMask<>+0x80(SB)/8, $0xffffffffffffffff
+DATA andMask<>+0x88(SB)/8, $0x00000000000000ff
+DATA andMask<>+0x90(SB)/8, $0xffffffffffffffff
+DATA andMask<>+0x98(SB)/8, $0x000000000000ffff
+DATA andMask<>+0xa0(SB)/8, $0xffffffffffffffff
+DATA andMask<>+0xa8(SB)/8, $0x0000000000ffffff
+DATA andMask<>+0xb0(SB)/8, $0xffffffffffffffff
+DATA andMask<>+0xb8(SB)/8, $0x00000000ffffffff
+DATA andMask<>+0xc0(SB)/8, $0xffffffffffffffff
+DATA andMask<>+0xc8(SB)/8, $0x000000ffffffffff
+DATA andMask<>+0xd0(SB)/8, $0xffffffffffffffff
+DATA andMask<>+0xd8(SB)/8, $0x0000ffffffffffff
+DATA andMask<>+0xe0(SB)/8, $0xffffffffffffffff
+DATA andMask<>+0xe8(SB)/8, $0x00ffffffffffffff
+
+GLOBL bswapMask<>(SB), (NOPTR+RODATA), $16
+GLOBL gcmPoly<>(SB), (NOPTR+RODATA), $16
+GLOBL andMask<>(SB), (NOPTR+RODATA), $240
+
+// func gcmAesFinish(productTable *[256]byte, tagMask, T *[16]byte, pLen, dLen uint64)
+TEXT ·gcmAesFinish(SB),NOSPLIT,$0
+#define pTbl DI
+#define tMsk SI
+#define tPtr DX
+#define plen AX
+#define dlen CX
+
+ MOVQ productTable+0(FP), pTbl
+ MOVQ tagMask+8(FP), tMsk
+ MOVQ T+16(FP), tPtr
+ MOVQ pLen+24(FP), plen
+ MOVQ dLen+32(FP), dlen
+
+ MOVOU (tPtr), ACC0
+ MOVOU (tMsk), T2
+
+ MOVOU bswapMask<>(SB), BSWAP
+ MOVOU gcmPoly<>(SB), POLY
+
+ SHLQ $3, plen
+ SHLQ $3, dlen
+
+ MOVQ plen, B0
+ PINSRQ $1, dlen, B0
+
+ PXOR ACC0, B0
+
+ MOVOU (16*14)(pTbl), ACC0
+ MOVOU (16*15)(pTbl), ACCM
+ MOVOU ACC0, ACC1
+
+ PCLMULQDQ $0x00, B0, ACC0
+ PCLMULQDQ $0x11, B0, ACC1
+ PSHUFD $78, B0, T0
+ PXOR B0, T0
+ PCLMULQDQ $0x00, T0, ACCM
+
+ PXOR ACC0, ACCM
+ PXOR ACC1, ACCM
+ MOVOU ACCM, T0
+ PSRLDQ $8, ACCM
+ PSLLDQ $8, T0
+ PXOR ACCM, ACC1
+ PXOR T0, ACC0
+
+ MOVOU POLY, T0
+ PCLMULQDQ $0x01, ACC0, T0
+ PSHUFD $78, ACC0, ACC0
+ PXOR T0, ACC0
+
+ MOVOU POLY, T0
+ PCLMULQDQ $0x01, ACC0, T0
+ PSHUFD $78, ACC0, ACC0
+ PXOR T0, ACC0
+
+ PXOR ACC1, ACC0
+
+ PSHUFB BSWAP, ACC0
+ PXOR T2, ACC0
+ MOVOU ACC0, (tPtr)
+
+ RET
+#undef pTbl
+#undef tMsk
+#undef tPtr
+#undef plen
+#undef dlen
+
+// func gcmAesInit(productTable *[256]byte, ks []uint32)
+TEXT ·gcmAesInit(SB),NOSPLIT,$0
+#define dst DI
+#define KS SI
+#define NR DX
+
+ MOVQ productTable+0(FP), dst
+ MOVQ ks_base+8(FP), KS
+ MOVQ ks_len+16(FP), NR
+
+ SHRQ $2, NR
+ DECQ NR
+
+ MOVOU bswapMask<>(SB), BSWAP
+ MOVOU gcmPoly<>(SB), POLY
+
+ // Encrypt block 0, with the AES key to generate the hash key H
+ MOVOU (16*0)(KS), B0
+ MOVOU (16*1)(KS), T0
+ AESENC T0, B0
+ MOVOU (16*2)(KS), T0
+ AESENC T0, B0
+ MOVOU (16*3)(KS), T0
+ AESENC T0, B0
+ MOVOU (16*4)(KS), T0
+ AESENC T0, B0
+ MOVOU (16*5)(KS), T0
+ AESENC T0, B0
+ MOVOU (16*6)(KS), T0
+ AESENC T0, B0
+ MOVOU (16*7)(KS), T0
+ AESENC T0, B0
+ MOVOU (16*8)(KS), T0
+ AESENC T0, B0
+ MOVOU (16*9)(KS), T0
+ AESENC T0, B0
+ MOVOU (16*10)(KS), T0
+ CMPQ NR, $12
+ JB initEncLast
+ AESENC T0, B0
+ MOVOU (16*11)(KS), T0
+ AESENC T0, B0
+ MOVOU (16*12)(KS), T0
+ JE initEncLast
+ AESENC T0, B0
+ MOVOU (16*13)(KS), T0
+ AESENC T0, B0
+ MOVOU (16*14)(KS), T0
+initEncLast:
+ AESENCLAST T0, B0
+
+ PSHUFB BSWAP, B0
+ // H * 2
+ PSHUFD $0xff, B0, T0
+ MOVOU B0, T1
+ PSRAL $31, T0
+ PAND POLY, T0
+ PSRLL $31, T1
+ PSLLDQ $4, T1
+ PSLLL $1, B0
+ PXOR T0, B0
+ PXOR T1, B0
+ // Karatsuba pre-computations
+ MOVOU B0, (16*14)(dst)
+ PSHUFD $78, B0, B1
+ PXOR B0, B1
+ MOVOU B1, (16*15)(dst)
+
+ MOVOU B0, B2
+ MOVOU B1, B3
+ // Now prepare powers of H and pre-computations for them
+ MOVQ $7, AX
+
+initLoop:
+ MOVOU B2, T0
+ MOVOU B2, T1
+ MOVOU B3, T2
+ PCLMULQDQ $0x00, B0, T0
+ PCLMULQDQ $0x11, B0, T1
+ PCLMULQDQ $0x00, B1, T2
+
+ PXOR T0, T2
+ PXOR T1, T2
+ MOVOU T2, B4
+ PSLLDQ $8, B4
+ PSRLDQ $8, T2
+ PXOR B4, T0
+ PXOR T2, T1
+
+ MOVOU POLY, B2
+ PCLMULQDQ $0x01, T0, B2
+ PSHUFD $78, T0, T0
+ PXOR B2, T0
+ MOVOU POLY, B2
+ PCLMULQDQ $0x01, T0, B2
+ PSHUFD $78, T0, T0
+ PXOR T0, B2
+ PXOR T1, B2
+
+ MOVOU B2, (16*12)(dst)
+ PSHUFD $78, B2, B3
+ PXOR B2, B3
+ MOVOU B3, (16*13)(dst)
+
+ DECQ AX
+ LEAQ (-16*2)(dst), dst
+ JNE initLoop
+
+ RET
+#undef NR
+#undef KS
+#undef dst
+
+// func gcmAesData(productTable *[256]byte, data []byte, T *[16]byte)
+TEXT ·gcmAesData(SB),NOSPLIT,$0
+#define pTbl DI
+#define aut SI
+#define tPtr CX
+#define autLen DX
+
+#define reduceRound(a) MOVOU POLY, T0; PCLMULQDQ $0x01, a, T0; PSHUFD $78, a, a; PXOR T0, a
+#define mulRoundAAD(X ,i) \
+ MOVOU (16*(i*2))(pTbl), T1;\
+ MOVOU T1, T2;\
+ PCLMULQDQ $0x00, X, T1;\
+ PXOR T1, ACC0;\
+ PCLMULQDQ $0x11, X, T2;\
+ PXOR T2, ACC1;\
+ PSHUFD $78, X, T1;\
+ PXOR T1, X;\
+ MOVOU (16*(i*2+1))(pTbl), T1;\
+ PCLMULQDQ $0x00, X, T1;\
+ PXOR T1, ACCM
+
+ MOVQ productTable+0(FP), pTbl
+ MOVQ data_base+8(FP), aut
+ MOVQ data_len+16(FP), autLen
+ MOVQ T+32(FP), tPtr
+
+ PXOR ACC0, ACC0
+ MOVOU bswapMask<>(SB), BSWAP
+ MOVOU gcmPoly<>(SB), POLY
+
+ TESTQ autLen, autLen
+ JEQ dataBail
+
+ CMPQ autLen, $13 // optimize the TLS case
+ JE dataTLS
+ CMPQ autLen, $128
+ JB startSinglesLoop
+ JMP dataOctaLoop
+
+dataTLS:
+ MOVOU (16*14)(pTbl), T1
+ MOVOU (16*15)(pTbl), T2
+ PXOR B0, B0
+ MOVQ (aut), B0
+ PINSRD $2, 8(aut), B0
+ PINSRB $12, 12(aut), B0
+ XORQ autLen, autLen
+ JMP dataMul
+
+dataOctaLoop:
+ CMPQ autLen, $128
+ JB startSinglesLoop
+ SUBQ $128, autLen
+
+ MOVOU (16*0)(aut), X0
+ MOVOU (16*1)(aut), X1
+ MOVOU (16*2)(aut), X2
+ MOVOU (16*3)(aut), X3
+ MOVOU (16*4)(aut), X4
+ MOVOU (16*5)(aut), X5
+ MOVOU (16*6)(aut), X6
+ MOVOU (16*7)(aut), X7
+ LEAQ (16*8)(aut), aut
+ PSHUFB BSWAP, X0
+ PSHUFB BSWAP, X1
+ PSHUFB BSWAP, X2
+ PSHUFB BSWAP, X3
+ PSHUFB BSWAP, X4
+ PSHUFB BSWAP, X5
+ PSHUFB BSWAP, X6
+ PSHUFB BSWAP, X7
+ PXOR ACC0, X0
+
+ MOVOU (16*0)(pTbl), ACC0
+ MOVOU (16*1)(pTbl), ACCM
+ MOVOU ACC0, ACC1
+ PSHUFD $78, X0, T1
+ PXOR X0, T1
+ PCLMULQDQ $0x00, X0, ACC0
+ PCLMULQDQ $0x11, X0, ACC1
+ PCLMULQDQ $0x00, T1, ACCM
+
+ mulRoundAAD(X1, 1)
+ mulRoundAAD(X2, 2)
+ mulRoundAAD(X3, 3)
+ mulRoundAAD(X4, 4)
+ mulRoundAAD(X5, 5)
+ mulRoundAAD(X6, 6)
+ mulRoundAAD(X7, 7)
+
+ PXOR ACC0, ACCM
+ PXOR ACC1, ACCM
+ MOVOU ACCM, T0
+ PSRLDQ $8, ACCM
+ PSLLDQ $8, T0
+ PXOR ACCM, ACC1
+ PXOR T0, ACC0
+ reduceRound(ACC0)
+ reduceRound(ACC0)
+ PXOR ACC1, ACC0
+ JMP dataOctaLoop
+
+startSinglesLoop:
+ MOVOU (16*14)(pTbl), T1
+ MOVOU (16*15)(pTbl), T2
+
+dataSinglesLoop:
+
+ CMPQ autLen, $16
+ JB dataEnd
+ SUBQ $16, autLen
+
+ MOVOU (aut), B0
+dataMul:
+ PSHUFB BSWAP, B0
+ PXOR ACC0, B0
+
+ MOVOU T1, ACC0
+ MOVOU T2, ACCM
+ MOVOU T1, ACC1
+
+ PSHUFD $78, B0, T0
+ PXOR B0, T0
+ PCLMULQDQ $0x00, B0, ACC0
+ PCLMULQDQ $0x11, B0, ACC1
+ PCLMULQDQ $0x00, T0, ACCM
+
+ PXOR ACC0, ACCM
+ PXOR ACC1, ACCM
+ MOVOU ACCM, T0
+ PSRLDQ $8, ACCM
+ PSLLDQ $8, T0
+ PXOR ACCM, ACC1
+ PXOR T0, ACC0
+
+ MOVOU POLY, T0
+ PCLMULQDQ $0x01, ACC0, T0
+ PSHUFD $78, ACC0, ACC0
+ PXOR T0, ACC0
+
+ MOVOU POLY, T0
+ PCLMULQDQ $0x01, ACC0, T0
+ PSHUFD $78, ACC0, ACC0
+ PXOR T0, ACC0
+ PXOR ACC1, ACC0
+
+ LEAQ 16(aut), aut
+
+ JMP dataSinglesLoop
+
+dataEnd:
+
+ TESTQ autLen, autLen
+ JEQ dataBail
+
+ PXOR B0, B0
+ LEAQ -1(aut)(autLen*1), aut
+
+dataLoadLoop:
+
+ PSLLDQ $1, B0
+ PINSRB $0, (aut), B0
+
+ LEAQ -1(aut), aut
+ DECQ autLen
+ JNE dataLoadLoop
+
+ JMP dataMul
+
+dataBail:
+ MOVOU ACC0, (tPtr)
+ RET
+#undef pTbl
+#undef aut
+#undef tPtr
+#undef autLen
+
+// func gcmAesEnc(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32)
+TEXT ·gcmAesEnc(SB),0,$256-96
+#define pTbl DI
+#define ctx DX
+#define ctrPtr CX
+#define ptx SI
+#define ks AX
+#define tPtr R8
+#define ptxLen R9
+#define aluCTR R10
+#define aluTMP R11
+#define aluK R12
+#define NR R13
+
+#define increment(i) ADDL $1, aluCTR; MOVL aluCTR, aluTMP; XORL aluK, aluTMP; BSWAPL aluTMP; MOVL aluTMP, (3*4 + 8*16 + i*16)(SP)
+#define aesRnd(k) AESENC k, B0; AESENC k, B1; AESENC k, B2; AESENC k, B3; AESENC k, B4; AESENC k, B5; AESENC k, B6; AESENC k, B7
+#define aesRound(i) MOVOU (16*i)(ks), T0;AESENC T0, B0; AESENC T0, B1; AESENC T0, B2; AESENC T0, B3; AESENC T0, B4; AESENC T0, B5; AESENC T0, B6; AESENC T0, B7
+#define aesRndLast(k) AESENCLAST k, B0; AESENCLAST k, B1; AESENCLAST k, B2; AESENCLAST k, B3; AESENCLAST k, B4; AESENCLAST k, B5; AESENCLAST k, B6; AESENCLAST k, B7
+#define combinedRound(i) \
+ MOVOU (16*i)(ks), T0;\
+ AESENC T0, B0;\
+ AESENC T0, B1;\
+ AESENC T0, B2;\
+ AESENC T0, B3;\
+ MOVOU (16*(i*2))(pTbl), T1;\
+ MOVOU T1, T2;\
+ AESENC T0, B4;\
+ AESENC T0, B5;\
+ AESENC T0, B6;\
+ AESENC T0, B7;\
+ MOVOU (16*i)(SP), T0;\
+ PCLMULQDQ $0x00, T0, T1;\
+ PXOR T1, ACC0;\
+ PSHUFD $78, T0, T1;\
+ PCLMULQDQ $0x11, T0, T2;\
+ PXOR T1, T0;\
+ PXOR T2, ACC1;\
+ MOVOU (16*(i*2+1))(pTbl), T2;\
+ PCLMULQDQ $0x00, T2, T0;\
+ PXOR T0, ACCM
+#define mulRound(i) \
+ MOVOU (16*i)(SP), T0;\
+ MOVOU (16*(i*2))(pTbl), T1;\
+ MOVOU T1, T2;\
+ PCLMULQDQ $0x00, T0, T1;\
+ PXOR T1, ACC0;\
+ PCLMULQDQ $0x11, T0, T2;\
+ PXOR T2, ACC1;\
+ PSHUFD $78, T0, T1;\
+ PXOR T1, T0;\
+ MOVOU (16*(i*2+1))(pTbl), T1;\
+ PCLMULQDQ $0x00, T0, T1;\
+ PXOR T1, ACCM
+
+ MOVQ productTable+0(FP), pTbl
+ MOVQ dst+8(FP), ctx
+ MOVQ src_base+32(FP), ptx
+ MOVQ src_len+40(FP), ptxLen
+ MOVQ ctr+56(FP), ctrPtr
+ MOVQ T+64(FP), tPtr
+ MOVQ ks_base+72(FP), ks
+ MOVQ ks_len+80(FP), NR
+
+ SHRQ $2, NR
+ DECQ NR
+
+ MOVOU bswapMask<>(SB), BSWAP
+ MOVOU gcmPoly<>(SB), POLY
+
+ MOVOU (tPtr), ACC0
+ PXOR ACC1, ACC1
+ PXOR ACCM, ACCM
+ MOVOU (ctrPtr), B0
+ MOVL (3*4)(ctrPtr), aluCTR
+ MOVOU (ks), T0
+ MOVL (3*4)(ks), aluK
+ BSWAPL aluCTR
+ BSWAPL aluK
+
+ PXOR B0, T0
+ MOVOU T0, (8*16 + 0*16)(SP)
+ increment(0)
+
+ CMPQ ptxLen, $128
+ JB gcmAesEncSingles
+ SUBQ $128, ptxLen
+
+ // We have at least 8 blocks to encrypt, prepare the rest of the counters
+ MOVOU T0, (8*16 + 1*16)(SP)
+ increment(1)
+ MOVOU T0, (8*16 + 2*16)(SP)
+ increment(2)
+ MOVOU T0, (8*16 + 3*16)(SP)
+ increment(3)
+ MOVOU T0, (8*16 + 4*16)(SP)
+ increment(4)
+ MOVOU T0, (8*16 + 5*16)(SP)
+ increment(5)
+ MOVOU T0, (8*16 + 6*16)(SP)
+ increment(6)
+ MOVOU T0, (8*16 + 7*16)(SP)
+ increment(7)
+
+ MOVOU (8*16 + 0*16)(SP), B0
+ MOVOU (8*16 + 1*16)(SP), B1
+ MOVOU (8*16 + 2*16)(SP), B2
+ MOVOU (8*16 + 3*16)(SP), B3
+ MOVOU (8*16 + 4*16)(SP), B4
+ MOVOU (8*16 + 5*16)(SP), B5
+ MOVOU (8*16 + 6*16)(SP), B6
+ MOVOU (8*16 + 7*16)(SP), B7
+
+ aesRound(1)
+ increment(0)
+ aesRound(2)
+ increment(1)
+ aesRound(3)
+ increment(2)
+ aesRound(4)
+ increment(3)
+ aesRound(5)
+ increment(4)
+ aesRound(6)
+ increment(5)
+ aesRound(7)
+ increment(6)
+ aesRound(8)
+ increment(7)
+ aesRound(9)
+ MOVOU (16*10)(ks), T0
+ CMPQ NR, $12
+ JB encLast1
+ aesRnd(T0)
+ aesRound(11)
+ MOVOU (16*12)(ks), T0
+ JE encLast1
+ aesRnd(T0)
+ aesRound(13)
+ MOVOU (16*14)(ks), T0
+encLast1:
+ aesRndLast(T0)
+
+ MOVOU (16*0)(ptx), T0
+ PXOR T0, B0
+ MOVOU (16*1)(ptx), T0
+ PXOR T0, B1
+ MOVOU (16*2)(ptx), T0
+ PXOR T0, B2
+ MOVOU (16*3)(ptx), T0
+ PXOR T0, B3
+ MOVOU (16*4)(ptx), T0
+ PXOR T0, B4
+ MOVOU (16*5)(ptx), T0
+ PXOR T0, B5
+ MOVOU (16*6)(ptx), T0
+ PXOR T0, B6
+ MOVOU (16*7)(ptx), T0
+ PXOR T0, B7
+
+ MOVOU B0, (16*0)(ctx)
+ PSHUFB BSWAP, B0
+ PXOR ACC0, B0
+ MOVOU B1, (16*1)(ctx)
+ PSHUFB BSWAP, B1
+ MOVOU B2, (16*2)(ctx)
+ PSHUFB BSWAP, B2
+ MOVOU B3, (16*3)(ctx)
+ PSHUFB BSWAP, B3
+ MOVOU B4, (16*4)(ctx)
+ PSHUFB BSWAP, B4
+ MOVOU B5, (16*5)(ctx)
+ PSHUFB BSWAP, B5
+ MOVOU B6, (16*6)(ctx)
+ PSHUFB BSWAP, B6
+ MOVOU B7, (16*7)(ctx)
+ PSHUFB BSWAP, B7
+
+ MOVOU B0, (16*0)(SP)
+ MOVOU B1, (16*1)(SP)
+ MOVOU B2, (16*2)(SP)
+ MOVOU B3, (16*3)(SP)
+ MOVOU B4, (16*4)(SP)
+ MOVOU B5, (16*5)(SP)
+ MOVOU B6, (16*6)(SP)
+ MOVOU B7, (16*7)(SP)
+
+ LEAQ 128(ptx), ptx
+ LEAQ 128(ctx), ctx
+
+gcmAesEncOctetsLoop:
+
+ CMPQ ptxLen, $128
+ JB gcmAesEncOctetsEnd
+ SUBQ $128, ptxLen
+
+ MOVOU (8*16 + 0*16)(SP), B0
+ MOVOU (8*16 + 1*16)(SP), B1
+ MOVOU (8*16 + 2*16)(SP), B2
+ MOVOU (8*16 + 3*16)(SP), B3
+ MOVOU (8*16 + 4*16)(SP), B4
+ MOVOU (8*16 + 5*16)(SP), B5
+ MOVOU (8*16 + 6*16)(SP), B6
+ MOVOU (8*16 + 7*16)(SP), B7
+
+ MOVOU (16*0)(SP), T0
+ PSHUFD $78, T0, T1
+ PXOR T0, T1
+
+ MOVOU (16*0)(pTbl), ACC0
+ MOVOU (16*1)(pTbl), ACCM
+ MOVOU ACC0, ACC1
+
+ PCLMULQDQ $0x00, T1, ACCM
+ PCLMULQDQ $0x00, T0, ACC0
+ PCLMULQDQ $0x11, T0, ACC1
+
+ combinedRound(1)
+ increment(0)
+ combinedRound(2)
+ increment(1)
+ combinedRound(3)
+ increment(2)
+ combinedRound(4)
+ increment(3)
+ combinedRound(5)
+ increment(4)
+ combinedRound(6)
+ increment(5)
+ combinedRound(7)
+ increment(6)
+
+ aesRound(8)
+ increment(7)
+
+ PXOR ACC0, ACCM
+ PXOR ACC1, ACCM
+ MOVOU ACCM, T0
+ PSRLDQ $8, ACCM
+ PSLLDQ $8, T0
+ PXOR ACCM, ACC1
+ PXOR T0, ACC0
+
+ reduceRound(ACC0)
+ aesRound(9)
+
+ reduceRound(ACC0)
+ PXOR ACC1, ACC0
+
+ MOVOU (16*10)(ks), T0
+ CMPQ NR, $12
+ JB encLast2
+ aesRnd(T0)
+ aesRound(11)
+ MOVOU (16*12)(ks), T0
+ JE encLast2
+ aesRnd(T0)
+ aesRound(13)
+ MOVOU (16*14)(ks), T0
+encLast2:
+ aesRndLast(T0)
+
+ MOVOU (16*0)(ptx), T0
+ PXOR T0, B0
+ MOVOU (16*1)(ptx), T0
+ PXOR T0, B1
+ MOVOU (16*2)(ptx), T0
+ PXOR T0, B2
+ MOVOU (16*3)(ptx), T0
+ PXOR T0, B3
+ MOVOU (16*4)(ptx), T0
+ PXOR T0, B4
+ MOVOU (16*5)(ptx), T0
+ PXOR T0, B5
+ MOVOU (16*6)(ptx), T0
+ PXOR T0, B6
+ MOVOU (16*7)(ptx), T0
+ PXOR T0, B7
+
+ MOVOU B0, (16*0)(ctx)
+ PSHUFB BSWAP, B0
+ PXOR ACC0, B0
+ MOVOU B1, (16*1)(ctx)
+ PSHUFB BSWAP, B1
+ MOVOU B2, (16*2)(ctx)
+ PSHUFB BSWAP, B2
+ MOVOU B3, (16*3)(ctx)
+ PSHUFB BSWAP, B3
+ MOVOU B4, (16*4)(ctx)
+ PSHUFB BSWAP, B4
+ MOVOU B5, (16*5)(ctx)
+ PSHUFB BSWAP, B5
+ MOVOU B6, (16*6)(ctx)
+ PSHUFB BSWAP, B6
+ MOVOU B7, (16*7)(ctx)
+ PSHUFB BSWAP, B7
+
+ MOVOU B0, (16*0)(SP)
+ MOVOU B1, (16*1)(SP)
+ MOVOU B2, (16*2)(SP)
+ MOVOU B3, (16*3)(SP)
+ MOVOU B4, (16*4)(SP)
+ MOVOU B5, (16*5)(SP)
+ MOVOU B6, (16*6)(SP)
+ MOVOU B7, (16*7)(SP)
+
+ LEAQ 128(ptx), ptx
+ LEAQ 128(ctx), ctx
+
+ JMP gcmAesEncOctetsLoop
+
+gcmAesEncOctetsEnd:
+
+ MOVOU (16*0)(SP), T0
+ MOVOU (16*0)(pTbl), ACC0
+ MOVOU (16*1)(pTbl), ACCM
+ MOVOU ACC0, ACC1
+ PSHUFD $78, T0, T1
+ PXOR T0, T1
+ PCLMULQDQ $0x00, T0, ACC0
+ PCLMULQDQ $0x11, T0, ACC1
+ PCLMULQDQ $0x00, T1, ACCM
+
+ mulRound(1)
+ mulRound(2)
+ mulRound(3)
+ mulRound(4)
+ mulRound(5)
+ mulRound(6)
+ mulRound(7)
+
+ PXOR ACC0, ACCM
+ PXOR ACC1, ACCM
+ MOVOU ACCM, T0
+ PSRLDQ $8, ACCM
+ PSLLDQ $8, T0
+ PXOR ACCM, ACC1
+ PXOR T0, ACC0
+
+ reduceRound(ACC0)
+ reduceRound(ACC0)
+ PXOR ACC1, ACC0
+
+ TESTQ ptxLen, ptxLen
+ JE gcmAesEncDone
+
+ SUBQ $7, aluCTR
+
+gcmAesEncSingles:
+
+ MOVOU (16*1)(ks), B1
+ MOVOU (16*2)(ks), B2
+ MOVOU (16*3)(ks), B3
+ MOVOU (16*4)(ks), B4
+ MOVOU (16*5)(ks), B5
+ MOVOU (16*6)(ks), B6
+ MOVOU (16*7)(ks), B7
+
+ MOVOU (16*14)(pTbl), T2
+
+gcmAesEncSinglesLoop:
+
+ CMPQ ptxLen, $16
+ JB gcmAesEncTail
+ SUBQ $16, ptxLen
+
+ MOVOU (8*16 + 0*16)(SP), B0
+ increment(0)
+
+ AESENC B1, B0
+ AESENC B2, B0
+ AESENC B3, B0
+ AESENC B4, B0
+ AESENC B5, B0
+ AESENC B6, B0
+ AESENC B7, B0
+ MOVOU (16*8)(ks), T0
+ AESENC T0, B0
+ MOVOU (16*9)(ks), T0
+ AESENC T0, B0
+ MOVOU (16*10)(ks), T0
+ CMPQ NR, $12
+ JB encLast3
+ AESENC T0, B0
+ MOVOU (16*11)(ks), T0
+ AESENC T0, B0
+ MOVOU (16*12)(ks), T0
+ JE encLast3
+ AESENC T0, B0
+ MOVOU (16*13)(ks), T0
+ AESENC T0, B0
+ MOVOU (16*14)(ks), T0
+encLast3:
+ AESENCLAST T0, B0
+
+ MOVOU (ptx), T0
+ PXOR T0, B0
+ MOVOU B0, (ctx)
+
+ PSHUFB BSWAP, B0
+ PXOR ACC0, B0
+
+ MOVOU T2, ACC0
+ MOVOU T2, ACC1
+ MOVOU (16*15)(pTbl), ACCM
+
+ PSHUFD $78, B0, T0
+ PXOR B0, T0
+ PCLMULQDQ $0x00, B0, ACC0
+ PCLMULQDQ $0x11, B0, ACC1
+ PCLMULQDQ $0x00, T0, ACCM
+
+ PXOR ACC0, ACCM
+ PXOR ACC1, ACCM
+ MOVOU ACCM, T0
+ PSRLDQ $8, ACCM
+ PSLLDQ $8, T0
+ PXOR ACCM, ACC1
+ PXOR T0, ACC0
+
+ reduceRound(ACC0)
+ reduceRound(ACC0)
+ PXOR ACC1, ACC0
+
+ LEAQ (16*1)(ptx), ptx
+ LEAQ (16*1)(ctx), ctx
+
+ JMP gcmAesEncSinglesLoop
+
+gcmAesEncTail:
+ TESTQ ptxLen, ptxLen
+ JE gcmAesEncDone
+
+ MOVOU (8*16 + 0*16)(SP), B0
+ AESENC B1, B0
+ AESENC B2, B0
+ AESENC B3, B0
+ AESENC B4, B0
+ AESENC B5, B0
+ AESENC B6, B0
+ AESENC B7, B0
+ MOVOU (16*8)(ks), T0
+ AESENC T0, B0
+ MOVOU (16*9)(ks), T0
+ AESENC T0, B0
+ MOVOU (16*10)(ks), T0
+ CMPQ NR, $12
+ JB encLast4
+ AESENC T0, B0
+ MOVOU (16*11)(ks), T0
+ AESENC T0, B0
+ MOVOU (16*12)(ks), T0
+ JE encLast4
+ AESENC T0, B0
+ MOVOU (16*13)(ks), T0
+ AESENC T0, B0
+ MOVOU (16*14)(ks), T0
+encLast4:
+ AESENCLAST T0, B0
+ MOVOU B0, T0
+
+ LEAQ -1(ptx)(ptxLen*1), ptx
+
+ MOVQ ptxLen, aluTMP
+ SHLQ $4, aluTMP
+
+ LEAQ andMask<>(SB), aluCTR
+ MOVOU -16(aluCTR)(aluTMP*1), T1
+
+ PXOR B0, B0
+ptxLoadLoop:
+ PSLLDQ $1, B0
+ PINSRB $0, (ptx), B0
+ LEAQ -1(ptx), ptx
+ DECQ ptxLen
+ JNE ptxLoadLoop
+
+ PXOR T0, B0
+ PAND T1, B0
+ MOVOU B0, (ctx) // I assume there is always space, due to TAG in the end of the CT
+
+ PSHUFB BSWAP, B0
+ PXOR ACC0, B0
+
+ MOVOU T2, ACC0
+ MOVOU T2, ACC1
+ MOVOU (16*15)(pTbl), ACCM
+
+ PSHUFD $78, B0, T0
+ PXOR B0, T0
+ PCLMULQDQ $0x00, B0, ACC0
+ PCLMULQDQ $0x11, B0, ACC1
+ PCLMULQDQ $0x00, T0, ACCM
+
+ PXOR ACC0, ACCM
+ PXOR ACC1, ACCM
+ MOVOU ACCM, T0
+ PSRLDQ $8, ACCM
+ PSLLDQ $8, T0
+ PXOR ACCM, ACC1
+ PXOR T0, ACC0
+
+ reduceRound(ACC0)
+ reduceRound(ACC0)
+ PXOR ACC1, ACC0
+
+gcmAesEncDone:
+ MOVOU ACC0, (tPtr)
+ RET
+#undef increment
+
+// func gcmAesDec(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32)
+TEXT ·gcmAesDec(SB),0,$128-96
+#define increment(i) ADDL $1, aluCTR; MOVL aluCTR, aluTMP; XORL aluK, aluTMP; BSWAPL aluTMP; MOVL aluTMP, (3*4 + i*16)(SP)
+#define combinedDecRound(i) \
+ MOVOU (16*i)(ks), T0;\
+ AESENC T0, B0;\
+ AESENC T0, B1;\
+ AESENC T0, B2;\
+ AESENC T0, B3;\
+ MOVOU (16*(i*2))(pTbl), T1;\
+ MOVOU T1, T2;\
+ AESENC T0, B4;\
+ AESENC T0, B5;\
+ AESENC T0, B6;\
+ AESENC T0, B7;\
+ MOVOU (16*i)(ctx), T0;\
+ PSHUFB BSWAP, T0;\
+ PCLMULQDQ $0x00, T0, T1;\
+ PXOR T1, ACC0;\
+ PSHUFD $78, T0, T1;\
+ PCLMULQDQ $0x11, T0, T2;\
+ PXOR T1, T0;\
+ PXOR T2, ACC1;\
+ MOVOU (16*(i*2+1))(pTbl), T2;\
+ PCLMULQDQ $0x00, T2, T0;\
+ PXOR T0, ACCM
+
+ MOVQ productTable+0(FP), pTbl
+ MOVQ dst+8(FP), ptx
+ MOVQ src_base+32(FP), ctx
+ MOVQ src_len+40(FP), ptxLen
+ MOVQ ctr+56(FP), ctrPtr
+ MOVQ T+64(FP), tPtr
+ MOVQ ks_base+72(FP), ks
+ MOVQ ks_len+80(FP), NR
+
+ SHRQ $2, NR
+ DECQ NR
+
+ MOVOU bswapMask<>(SB), BSWAP
+ MOVOU gcmPoly<>(SB), POLY
+
+ MOVOU (tPtr), ACC0
+ PXOR ACC1, ACC1
+ PXOR ACCM, ACCM
+ MOVOU (ctrPtr), B0
+ MOVL (3*4)(ctrPtr), aluCTR
+ MOVOU (ks), T0
+ MOVL (3*4)(ks), aluK
+ BSWAPL aluCTR
+ BSWAPL aluK
+
+ PXOR B0, T0
+ MOVOU T0, (0*16)(SP)
+ increment(0)
+
+ CMPQ ptxLen, $128
+ JB gcmAesDecSingles
+
+ MOVOU T0, (1*16)(SP)
+ increment(1)
+ MOVOU T0, (2*16)(SP)
+ increment(2)
+ MOVOU T0, (3*16)(SP)
+ increment(3)
+ MOVOU T0, (4*16)(SP)
+ increment(4)
+ MOVOU T0, (5*16)(SP)
+ increment(5)
+ MOVOU T0, (6*16)(SP)
+ increment(6)
+ MOVOU T0, (7*16)(SP)
+ increment(7)
+
+gcmAesDecOctetsLoop:
+
+ CMPQ ptxLen, $128
+ JB gcmAesDecEndOctets
+ SUBQ $128, ptxLen
+
+ MOVOU (0*16)(SP), B0
+ MOVOU (1*16)(SP), B1
+ MOVOU (2*16)(SP), B2
+ MOVOU (3*16)(SP), B3
+ MOVOU (4*16)(SP), B4
+ MOVOU (5*16)(SP), B5
+ MOVOU (6*16)(SP), B6
+ MOVOU (7*16)(SP), B7
+
+ MOVOU (16*0)(ctx), T0
+ PSHUFB BSWAP, T0
+ PXOR ACC0, T0
+ PSHUFD $78, T0, T1
+ PXOR T0, T1
+
+ MOVOU (16*0)(pTbl), ACC0
+ MOVOU (16*1)(pTbl), ACCM
+ MOVOU ACC0, ACC1
+
+ PCLMULQDQ $0x00, T1, ACCM
+ PCLMULQDQ $0x00, T0, ACC0
+ PCLMULQDQ $0x11, T0, ACC1
+
+ combinedDecRound(1)
+ increment(0)
+ combinedDecRound(2)
+ increment(1)
+ combinedDecRound(3)
+ increment(2)
+ combinedDecRound(4)
+ increment(3)
+ combinedDecRound(5)
+ increment(4)
+ combinedDecRound(6)
+ increment(5)
+ combinedDecRound(7)
+ increment(6)
+
+ aesRound(8)
+ increment(7)
+
+ PXOR ACC0, ACCM
+ PXOR ACC1, ACCM
+ MOVOU ACCM, T0
+ PSRLDQ $8, ACCM
+ PSLLDQ $8, T0
+ PXOR ACCM, ACC1
+ PXOR T0, ACC0
+
+ reduceRound(ACC0)
+ aesRound(9)
+
+ reduceRound(ACC0)
+ PXOR ACC1, ACC0
+
+ MOVOU (16*10)(ks), T0
+ CMPQ NR, $12
+ JB decLast1
+ aesRnd(T0)
+ aesRound(11)
+ MOVOU (16*12)(ks), T0
+ JE decLast1
+ aesRnd(T0)
+ aesRound(13)
+ MOVOU (16*14)(ks), T0
+decLast1:
+ aesRndLast(T0)
+
+ MOVOU (16*0)(ctx), T0
+ PXOR T0, B0
+ MOVOU (16*1)(ctx), T0
+ PXOR T0, B1
+ MOVOU (16*2)(ctx), T0
+ PXOR T0, B2
+ MOVOU (16*3)(ctx), T0
+ PXOR T0, B3
+ MOVOU (16*4)(ctx), T0
+ PXOR T0, B4
+ MOVOU (16*5)(ctx), T0
+ PXOR T0, B5
+ MOVOU (16*6)(ctx), T0
+ PXOR T0, B6
+ MOVOU (16*7)(ctx), T0
+ PXOR T0, B7
+
+ MOVOU B0, (16*0)(ptx)
+ MOVOU B1, (16*1)(ptx)
+ MOVOU B2, (16*2)(ptx)
+ MOVOU B3, (16*3)(ptx)
+ MOVOU B4, (16*4)(ptx)
+ MOVOU B5, (16*5)(ptx)
+ MOVOU B6, (16*6)(ptx)
+ MOVOU B7, (16*7)(ptx)
+
+ LEAQ 128(ptx), ptx
+ LEAQ 128(ctx), ctx
+
+ JMP gcmAesDecOctetsLoop
+
+gcmAesDecEndOctets:
+
+ SUBQ $7, aluCTR
+
+gcmAesDecSingles:
+
+ MOVOU (16*1)(ks), B1
+ MOVOU (16*2)(ks), B2
+ MOVOU (16*3)(ks), B3
+ MOVOU (16*4)(ks), B4
+ MOVOU (16*5)(ks), B5
+ MOVOU (16*6)(ks), B6
+ MOVOU (16*7)(ks), B7
+
+ MOVOU (16*14)(pTbl), T2
+
+gcmAesDecSinglesLoop:
+
+ CMPQ ptxLen, $16
+ JB gcmAesDecTail
+ SUBQ $16, ptxLen
+
+ MOVOU (ctx), B0
+ MOVOU B0, T1
+ PSHUFB BSWAP, B0
+ PXOR ACC0, B0
+
+ MOVOU T2, ACC0
+ MOVOU T2, ACC1
+ MOVOU (16*15)(pTbl), ACCM
+
+ PCLMULQDQ $0x00, B0, ACC0
+ PCLMULQDQ $0x11, B0, ACC1
+ PSHUFD $78, B0, T0
+ PXOR B0, T0
+ PCLMULQDQ $0x00, T0, ACCM
+
+ PXOR ACC0, ACCM
+ PXOR ACC1, ACCM
+ MOVOU ACCM, T0
+ PSRLDQ $8, ACCM
+ PSLLDQ $8, T0
+ PXOR ACCM, ACC1
+ PXOR T0, ACC0
+
+ reduceRound(ACC0)
+ reduceRound(ACC0)
+ PXOR ACC1, ACC0
+
+ MOVOU (0*16)(SP), B0
+ increment(0)
+ AESENC B1, B0
+ AESENC B2, B0
+ AESENC B3, B0
+ AESENC B4, B0
+ AESENC B5, B0
+ AESENC B6, B0
+ AESENC B7, B0
+ MOVOU (16*8)(ks), T0
+ AESENC T0, B0
+ MOVOU (16*9)(ks), T0
+ AESENC T0, B0
+ MOVOU (16*10)(ks), T0
+ CMPQ NR, $12
+ JB decLast2
+ AESENC T0, B0
+ MOVOU (16*11)(ks), T0
+ AESENC T0, B0
+ MOVOU (16*12)(ks), T0
+ JE decLast2
+ AESENC T0, B0
+ MOVOU (16*13)(ks), T0
+ AESENC T0, B0
+ MOVOU (16*14)(ks), T0
+decLast2:
+ AESENCLAST T0, B0
+
+ PXOR T1, B0
+ MOVOU B0, (ptx)
+
+ LEAQ (16*1)(ptx), ptx
+ LEAQ (16*1)(ctx), ctx
+
+ JMP gcmAesDecSinglesLoop
+
+gcmAesDecTail:
+
+ TESTQ ptxLen, ptxLen
+ JE gcmAesDecDone
+
+ MOVQ ptxLen, aluTMP
+ SHLQ $4, aluTMP
+ LEAQ andMask<>(SB), aluCTR
+ MOVOU -16(aluCTR)(aluTMP*1), T1
+
+ MOVOU (ctx), B0 // I assume there is TAG attached to the ctx, and there is no read overflow
+ PAND T1, B0
+
+ MOVOU B0, T1
+ PSHUFB BSWAP, B0
+ PXOR ACC0, B0
+
+ MOVOU (16*14)(pTbl), ACC0
+ MOVOU (16*15)(pTbl), ACCM
+ MOVOU ACC0, ACC1
+
+ PCLMULQDQ $0x00, B0, ACC0
+ PCLMULQDQ $0x11, B0, ACC1
+ PSHUFD $78, B0, T0
+ PXOR B0, T0
+ PCLMULQDQ $0x00, T0, ACCM
+
+ PXOR ACC0, ACCM
+ PXOR ACC1, ACCM
+ MOVOU ACCM, T0
+ PSRLDQ $8, ACCM
+ PSLLDQ $8, T0
+ PXOR ACCM, ACC1
+ PXOR T0, ACC0
+
+ reduceRound(ACC0)
+ reduceRound(ACC0)
+ PXOR ACC1, ACC0
+
+ MOVOU (0*16)(SP), B0
+ increment(0)
+ AESENC B1, B0
+ AESENC B2, B0
+ AESENC B3, B0
+ AESENC B4, B0
+ AESENC B5, B0
+ AESENC B6, B0
+ AESENC B7, B0
+ MOVOU (16*8)(ks), T0
+ AESENC T0, B0
+ MOVOU (16*9)(ks), T0
+ AESENC T0, B0
+ MOVOU (16*10)(ks), T0
+ CMPQ NR, $12
+ JB decLast3
+ AESENC T0, B0
+ MOVOU (16*11)(ks), T0
+ AESENC T0, B0
+ MOVOU (16*12)(ks), T0
+ JE decLast3
+ AESENC T0, B0
+ MOVOU (16*13)(ks), T0
+ AESENC T0, B0
+ MOVOU (16*14)(ks), T0
+decLast3:
+ AESENCLAST T0, B0
+ PXOR T1, B0
+
+ptxStoreLoop:
+ PEXTRB $0, B0, (ptx)
+ PSRLDQ $1, B0
+ LEAQ 1(ptx), ptx
+ DECQ ptxLen
+
+ JNE ptxStoreLoop
+
+gcmAesDecDone:
+
+ MOVOU ACC0, (tPtr)
+ RET
diff --git a/src/crypto/aes/gcm_arm64.s b/src/crypto/aes/gcm_arm64.s
new file mode 100644
index 0000000..61c868c
--- /dev/null
+++ b/src/crypto/aes/gcm_arm64.s
@@ -0,0 +1,1021 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+#define B0 V0
+#define B1 V1
+#define B2 V2
+#define B3 V3
+#define B4 V4
+#define B5 V5
+#define B6 V6
+#define B7 V7
+
+#define ACC0 V8
+#define ACC1 V9
+#define ACCM V10
+
+#define T0 V11
+#define T1 V12
+#define T2 V13
+#define T3 V14
+
+#define POLY V15
+#define ZERO V16
+#define INC V17
+#define CTR V18
+
+#define K0 V19
+#define K1 V20
+#define K2 V21
+#define K3 V22
+#define K4 V23
+#define K5 V24
+#define K6 V25
+#define K7 V26
+#define K8 V27
+#define K9 V28
+#define K10 V29
+#define K11 V30
+#define KLAST V31
+
+#define reduce() \
+ VEOR ACC0.B16, ACCM.B16, ACCM.B16 \
+ VEOR ACC1.B16, ACCM.B16, ACCM.B16 \
+ VEXT $8, ZERO.B16, ACCM.B16, T0.B16 \
+ VEXT $8, ACCM.B16, ZERO.B16, ACCM.B16 \
+ VEOR ACCM.B16, ACC0.B16, ACC0.B16 \
+ VEOR T0.B16, ACC1.B16, ACC1.B16 \
+ VPMULL POLY.D1, ACC0.D1, T0.Q1 \
+ VEXT $8, ACC0.B16, ACC0.B16, ACC0.B16 \
+ VEOR T0.B16, ACC0.B16, ACC0.B16 \
+ VPMULL POLY.D1, ACC0.D1, T0.Q1 \
+ VEOR T0.B16, ACC1.B16, ACC1.B16 \
+ VEXT $8, ACC1.B16, ACC1.B16, ACC1.B16 \
+ VEOR ACC1.B16, ACC0.B16, ACC0.B16 \
+
+// func gcmAesFinish(productTable *[256]byte, tagMask, T *[16]byte, pLen, dLen uint64)
+TEXT ·gcmAesFinish(SB),NOSPLIT,$0
+#define pTbl R0
+#define tMsk R1
+#define tPtr R2
+#define plen R3
+#define dlen R4
+
+ MOVD $0xC2, R1
+ LSL $56, R1
+ MOVD $1, R0
+ VMOV R1, POLY.D[0]
+ VMOV R0, POLY.D[1]
+ VEOR ZERO.B16, ZERO.B16, ZERO.B16
+
+ MOVD productTable+0(FP), pTbl
+ MOVD tagMask+8(FP), tMsk
+ MOVD T+16(FP), tPtr
+ MOVD pLen+24(FP), plen
+ MOVD dLen+32(FP), dlen
+
+ VLD1 (tPtr), [ACC0.B16]
+ VLD1 (tMsk), [B1.B16]
+
+ LSL $3, plen
+ LSL $3, dlen
+
+ VMOV dlen, B0.D[0]
+ VMOV plen, B0.D[1]
+
+ ADD $14*16, pTbl
+ VLD1.P (pTbl), [T1.B16, T2.B16]
+
+ VEOR ACC0.B16, B0.B16, B0.B16
+
+ VEXT $8, B0.B16, B0.B16, T0.B16
+ VEOR B0.B16, T0.B16, T0.B16
+ VPMULL B0.D1, T1.D1, ACC1.Q1
+ VPMULL2 B0.D2, T1.D2, ACC0.Q1
+ VPMULL T0.D1, T2.D1, ACCM.Q1
+
+ reduce()
+
+ VREV64 ACC0.B16, ACC0.B16
+ VEOR B1.B16, ACC0.B16, ACC0.B16
+
+ VST1 [ACC0.B16], (tPtr)
+ RET
+#undef pTbl
+#undef tMsk
+#undef tPtr
+#undef plen
+#undef dlen
+
+// func gcmAesInit(productTable *[256]byte, ks []uint32)
+TEXT ·gcmAesInit(SB),NOSPLIT,$0
+#define pTbl R0
+#define KS R1
+#define NR R2
+#define I R3
+ MOVD productTable+0(FP), pTbl
+ MOVD ks_base+8(FP), KS
+ MOVD ks_len+16(FP), NR
+
+ MOVD $0xC2, I
+ LSL $56, I
+ VMOV I, POLY.D[0]
+ MOVD $1, I
+ VMOV I, POLY.D[1]
+ VEOR ZERO.B16, ZERO.B16, ZERO.B16
+
+ // Encrypt block 0 with the AES key to generate the hash key H
+ VLD1.P 64(KS), [T0.B16, T1.B16, T2.B16, T3.B16]
+ VEOR B0.B16, B0.B16, B0.B16
+ AESE T0.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE T1.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE T2.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE T3.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ VLD1.P 64(KS), [T0.B16, T1.B16, T2.B16, T3.B16]
+ AESE T0.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE T1.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE T2.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE T3.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ TBZ $4, NR, initEncFinish
+ VLD1.P 32(KS), [T0.B16, T1.B16]
+ AESE T0.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE T1.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ TBZ $3, NR, initEncFinish
+ VLD1.P 32(KS), [T0.B16, T1.B16]
+ AESE T0.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE T1.B16, B0.B16
+ AESMC B0.B16, B0.B16
+initEncFinish:
+ VLD1 (KS), [T0.B16, T1.B16, T2.B16]
+ AESE T0.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE T1.B16, B0.B16
+ VEOR T2.B16, B0.B16, B0.B16
+
+ VREV64 B0.B16, B0.B16
+
+ // Multiply by 2 modulo P
+ VMOV B0.D[0], I
+ ASR $63, I
+ VMOV I, T1.D[0]
+ VMOV I, T1.D[1]
+ VAND POLY.B16, T1.B16, T1.B16
+ VUSHR $63, B0.D2, T2.D2
+ VEXT $8, ZERO.B16, T2.B16, T2.B16
+ VSHL $1, B0.D2, B0.D2
+ VEOR T1.B16, B0.B16, B0.B16
+ VEOR T2.B16, B0.B16, B0.B16 // Can avoid this when VSLI is available
+
+ // Karatsuba pre-computation
+ VEXT $8, B0.B16, B0.B16, B1.B16
+ VEOR B0.B16, B1.B16, B1.B16
+
+ ADD $14*16, pTbl
+ VST1 [B0.B16, B1.B16], (pTbl)
+ SUB $2*16, pTbl
+
+ VMOV B0.B16, B2.B16
+ VMOV B1.B16, B3.B16
+
+ MOVD $7, I
+
+initLoop:
+ // Compute powers of H
+ SUBS $1, I
+
+ VPMULL B0.D1, B2.D1, T1.Q1
+ VPMULL2 B0.D2, B2.D2, T0.Q1
+ VPMULL B1.D1, B3.D1, T2.Q1
+ VEOR T0.B16, T2.B16, T2.B16
+ VEOR T1.B16, T2.B16, T2.B16
+ VEXT $8, ZERO.B16, T2.B16, T3.B16
+ VEXT $8, T2.B16, ZERO.B16, T2.B16
+ VEOR T2.B16, T0.B16, T0.B16
+ VEOR T3.B16, T1.B16, T1.B16
+ VPMULL POLY.D1, T0.D1, T2.Q1
+ VEXT $8, T0.B16, T0.B16, T0.B16
+ VEOR T2.B16, T0.B16, T0.B16
+ VPMULL POLY.D1, T0.D1, T2.Q1
+ VEXT $8, T0.B16, T0.B16, T0.B16
+ VEOR T2.B16, T0.B16, T0.B16
+ VEOR T1.B16, T0.B16, B2.B16
+ VMOV B2.B16, B3.B16
+ VEXT $8, B2.B16, B2.B16, B2.B16
+ VEOR B2.B16, B3.B16, B3.B16
+
+ VST1 [B2.B16, B3.B16], (pTbl)
+ SUB $2*16, pTbl
+
+ BNE initLoop
+ RET
+#undef I
+#undef NR
+#undef KS
+#undef pTbl
+
+// func gcmAesData(productTable *[256]byte, data []byte, T *[16]byte)
+TEXT ·gcmAesData(SB),NOSPLIT,$0
+#define pTbl R0
+#define aut R1
+#define tPtr R2
+#define autLen R3
+#define H0 R4
+#define pTblSave R5
+
+#define mulRound(X) \
+ VLD1.P 32(pTbl), [T1.B16, T2.B16] \
+ VREV64 X.B16, X.B16 \
+ VEXT $8, X.B16, X.B16, T0.B16 \
+ VEOR X.B16, T0.B16, T0.B16 \
+ VPMULL X.D1, T1.D1, T3.Q1 \
+ VEOR T3.B16, ACC1.B16, ACC1.B16 \
+ VPMULL2 X.D2, T1.D2, T3.Q1 \
+ VEOR T3.B16, ACC0.B16, ACC0.B16 \
+ VPMULL T0.D1, T2.D1, T3.Q1 \
+ VEOR T3.B16, ACCM.B16, ACCM.B16
+
+ MOVD productTable+0(FP), pTbl
+ MOVD data_base+8(FP), aut
+ MOVD data_len+16(FP), autLen
+ MOVD T+32(FP), tPtr
+
+ VEOR ACC0.B16, ACC0.B16, ACC0.B16
+ CBZ autLen, dataBail
+
+ MOVD $0xC2, H0
+ LSL $56, H0
+ VMOV H0, POLY.D[0]
+ MOVD $1, H0
+ VMOV H0, POLY.D[1]
+ VEOR ZERO.B16, ZERO.B16, ZERO.B16
+ MOVD pTbl, pTblSave
+
+ CMP $13, autLen
+ BEQ dataTLS
+ CMP $128, autLen
+ BLT startSinglesLoop
+ B octetsLoop
+
+dataTLS:
+ ADD $14*16, pTbl
+ VLD1.P (pTbl), [T1.B16, T2.B16]
+ VEOR B0.B16, B0.B16, B0.B16
+
+ MOVD (aut), H0
+ VMOV H0, B0.D[0]
+ MOVW 8(aut), H0
+ VMOV H0, B0.S[2]
+ MOVB 12(aut), H0
+ VMOV H0, B0.B[12]
+
+ MOVD $0, autLen
+ B dataMul
+
+octetsLoop:
+ CMP $128, autLen
+ BLT startSinglesLoop
+ SUB $128, autLen
+
+ VLD1.P 32(aut), [B0.B16, B1.B16]
+
+ VLD1.P 32(pTbl), [T1.B16, T2.B16]
+ VREV64 B0.B16, B0.B16
+ VEOR ACC0.B16, B0.B16, B0.B16
+ VEXT $8, B0.B16, B0.B16, T0.B16
+ VEOR B0.B16, T0.B16, T0.B16
+ VPMULL B0.D1, T1.D1, ACC1.Q1
+ VPMULL2 B0.D2, T1.D2, ACC0.Q1
+ VPMULL T0.D1, T2.D1, ACCM.Q1
+
+ mulRound(B1)
+ VLD1.P 32(aut), [B2.B16, B3.B16]
+ mulRound(B2)
+ mulRound(B3)
+ VLD1.P 32(aut), [B4.B16, B5.B16]
+ mulRound(B4)
+ mulRound(B5)
+ VLD1.P 32(aut), [B6.B16, B7.B16]
+ mulRound(B6)
+ mulRound(B7)
+
+ MOVD pTblSave, pTbl
+ reduce()
+ B octetsLoop
+
+startSinglesLoop:
+
+ ADD $14*16, pTbl
+ VLD1.P (pTbl), [T1.B16, T2.B16]
+
+singlesLoop:
+
+ CMP $16, autLen
+ BLT dataEnd
+ SUB $16, autLen
+
+ VLD1.P 16(aut), [B0.B16]
+dataMul:
+ VREV64 B0.B16, B0.B16
+ VEOR ACC0.B16, B0.B16, B0.B16
+
+ VEXT $8, B0.B16, B0.B16, T0.B16
+ VEOR B0.B16, T0.B16, T0.B16
+ VPMULL B0.D1, T1.D1, ACC1.Q1
+ VPMULL2 B0.D2, T1.D2, ACC0.Q1
+ VPMULL T0.D1, T2.D1, ACCM.Q1
+
+ reduce()
+
+ B singlesLoop
+
+dataEnd:
+
+ CBZ autLen, dataBail
+ VEOR B0.B16, B0.B16, B0.B16
+ ADD autLen, aut
+
+dataLoadLoop:
+ MOVB.W -1(aut), H0
+ VEXT $15, B0.B16, ZERO.B16, B0.B16
+ VMOV H0, B0.B[0]
+ SUBS $1, autLen
+ BNE dataLoadLoop
+ B dataMul
+
+dataBail:
+ VST1 [ACC0.B16], (tPtr)
+ RET
+
+#undef pTbl
+#undef aut
+#undef tPtr
+#undef autLen
+#undef H0
+#undef pTblSave
+
+// func gcmAesEnc(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32)
+TEXT ·gcmAesEnc(SB),NOSPLIT,$0
+#define pTbl R0
+#define dstPtr R1
+#define ctrPtr R2
+#define srcPtr R3
+#define ks R4
+#define tPtr R5
+#define srcPtrLen R6
+#define aluCTR R7
+#define aluTMP R8
+#define aluK R9
+#define NR R10
+#define H0 R11
+#define H1 R12
+#define curK R13
+#define pTblSave R14
+
+#define aesrndx8(K) \
+ AESE K.B16, B0.B16 \
+ AESMC B0.B16, B0.B16 \
+ AESE K.B16, B1.B16 \
+ AESMC B1.B16, B1.B16 \
+ AESE K.B16, B2.B16 \
+ AESMC B2.B16, B2.B16 \
+ AESE K.B16, B3.B16 \
+ AESMC B3.B16, B3.B16 \
+ AESE K.B16, B4.B16 \
+ AESMC B4.B16, B4.B16 \
+ AESE K.B16, B5.B16 \
+ AESMC B5.B16, B5.B16 \
+ AESE K.B16, B6.B16 \
+ AESMC B6.B16, B6.B16 \
+ AESE K.B16, B7.B16 \
+ AESMC B7.B16, B7.B16
+
+#define aesrndlastx8(K) \
+ AESE K.B16, B0.B16 \
+ AESE K.B16, B1.B16 \
+ AESE K.B16, B2.B16 \
+ AESE K.B16, B3.B16 \
+ AESE K.B16, B4.B16 \
+ AESE K.B16, B5.B16 \
+ AESE K.B16, B6.B16 \
+ AESE K.B16, B7.B16
+
+ MOVD productTable+0(FP), pTbl
+ MOVD dst+8(FP), dstPtr
+ MOVD src_base+32(FP), srcPtr
+ MOVD src_len+40(FP), srcPtrLen
+ MOVD ctr+56(FP), ctrPtr
+ MOVD T+64(FP), tPtr
+ MOVD ks_base+72(FP), ks
+ MOVD ks_len+80(FP), NR
+
+ MOVD $0xC2, H1
+ LSL $56, H1
+ MOVD $1, H0
+ VMOV H1, POLY.D[0]
+ VMOV H0, POLY.D[1]
+ VEOR ZERO.B16, ZERO.B16, ZERO.B16
+ // Compute NR from len(ks)
+ MOVD pTbl, pTblSave
+ // Current tag, after AAD
+ VLD1 (tPtr), [ACC0.B16]
+ VEOR ACC1.B16, ACC1.B16, ACC1.B16
+ VEOR ACCM.B16, ACCM.B16, ACCM.B16
+ // Prepare initial counter, and the increment vector
+ VLD1 (ctrPtr), [CTR.B16]
+ VEOR INC.B16, INC.B16, INC.B16
+ MOVD $1, H0
+ VMOV H0, INC.S[3]
+ VREV32 CTR.B16, CTR.B16
+ VADD CTR.S4, INC.S4, CTR.S4
+ // Skip to <8 blocks loop
+ CMP $128, srcPtrLen
+
+ MOVD ks, H0
+ // For AES-128 round keys are stored in: K0 .. K10, KLAST
+ VLD1.P 64(H0), [K0.B16, K1.B16, K2.B16, K3.B16]
+ VLD1.P 64(H0), [K4.B16, K5.B16, K6.B16, K7.B16]
+ VLD1.P 48(H0), [K8.B16, K9.B16, K10.B16]
+ VMOV K10.B16, KLAST.B16
+
+ BLT startSingles
+ // There are at least 8 blocks to encrypt
+ TBZ $4, NR, octetsLoop
+
+ // For AES-192 round keys occupy: K0 .. K7, K10, K11, K8, K9, KLAST
+ VMOV K8.B16, K10.B16
+ VMOV K9.B16, K11.B16
+ VMOV KLAST.B16, K8.B16
+ VLD1.P 16(H0), [K9.B16]
+ VLD1.P 16(H0), [KLAST.B16]
+ TBZ $3, NR, octetsLoop
+ // For AES-256 round keys occupy: K0 .. K7, K10, K11, mem, mem, K8, K9, KLAST
+ VMOV KLAST.B16, K8.B16
+ VLD1.P 16(H0), [K9.B16]
+ VLD1.P 16(H0), [KLAST.B16]
+ ADD $10*16, ks, H0
+ MOVD H0, curK
+
+octetsLoop:
+ SUB $128, srcPtrLen
+
+ VMOV CTR.B16, B0.B16
+ VADD B0.S4, INC.S4, B1.S4
+ VREV32 B0.B16, B0.B16
+ VADD B1.S4, INC.S4, B2.S4
+ VREV32 B1.B16, B1.B16
+ VADD B2.S4, INC.S4, B3.S4
+ VREV32 B2.B16, B2.B16
+ VADD B3.S4, INC.S4, B4.S4
+ VREV32 B3.B16, B3.B16
+ VADD B4.S4, INC.S4, B5.S4
+ VREV32 B4.B16, B4.B16
+ VADD B5.S4, INC.S4, B6.S4
+ VREV32 B5.B16, B5.B16
+ VADD B6.S4, INC.S4, B7.S4
+ VREV32 B6.B16, B6.B16
+ VADD B7.S4, INC.S4, CTR.S4
+ VREV32 B7.B16, B7.B16
+
+ aesrndx8(K0)
+ aesrndx8(K1)
+ aesrndx8(K2)
+ aesrndx8(K3)
+ aesrndx8(K4)
+ aesrndx8(K5)
+ aesrndx8(K6)
+ aesrndx8(K7)
+ TBZ $4, NR, octetsFinish
+ aesrndx8(K10)
+ aesrndx8(K11)
+ TBZ $3, NR, octetsFinish
+ VLD1.P 32(curK), [T1.B16, T2.B16]
+ aesrndx8(T1)
+ aesrndx8(T2)
+ MOVD H0, curK
+octetsFinish:
+ aesrndx8(K8)
+ aesrndlastx8(K9)
+
+ VEOR KLAST.B16, B0.B16, B0.B16
+ VEOR KLAST.B16, B1.B16, B1.B16
+ VEOR KLAST.B16, B2.B16, B2.B16
+ VEOR KLAST.B16, B3.B16, B3.B16
+ VEOR KLAST.B16, B4.B16, B4.B16
+ VEOR KLAST.B16, B5.B16, B5.B16
+ VEOR KLAST.B16, B6.B16, B6.B16
+ VEOR KLAST.B16, B7.B16, B7.B16
+
+ VLD1.P 32(srcPtr), [T1.B16, T2.B16]
+ VEOR B0.B16, T1.B16, B0.B16
+ VEOR B1.B16, T2.B16, B1.B16
+ VST1.P [B0.B16, B1.B16], 32(dstPtr)
+ VLD1.P 32(srcPtr), [T1.B16, T2.B16]
+ VEOR B2.B16, T1.B16, B2.B16
+ VEOR B3.B16, T2.B16, B3.B16
+ VST1.P [B2.B16, B3.B16], 32(dstPtr)
+ VLD1.P 32(srcPtr), [T1.B16, T2.B16]
+ VEOR B4.B16, T1.B16, B4.B16
+ VEOR B5.B16, T2.B16, B5.B16
+ VST1.P [B4.B16, B5.B16], 32(dstPtr)
+ VLD1.P 32(srcPtr), [T1.B16, T2.B16]
+ VEOR B6.B16, T1.B16, B6.B16
+ VEOR B7.B16, T2.B16, B7.B16
+ VST1.P [B6.B16, B7.B16], 32(dstPtr)
+
+ VLD1.P 32(pTbl), [T1.B16, T2.B16]
+ VREV64 B0.B16, B0.B16
+ VEOR ACC0.B16, B0.B16, B0.B16
+ VEXT $8, B0.B16, B0.B16, T0.B16
+ VEOR B0.B16, T0.B16, T0.B16
+ VPMULL B0.D1, T1.D1, ACC1.Q1
+ VPMULL2 B0.D2, T1.D2, ACC0.Q1
+ VPMULL T0.D1, T2.D1, ACCM.Q1
+
+ mulRound(B1)
+ mulRound(B2)
+ mulRound(B3)
+ mulRound(B4)
+ mulRound(B5)
+ mulRound(B6)
+ mulRound(B7)
+ MOVD pTblSave, pTbl
+ reduce()
+
+ CMP $128, srcPtrLen
+ BGE octetsLoop
+
+startSingles:
+ CBZ srcPtrLen, done
+ ADD $14*16, pTbl
+ // Preload H and its Karatsuba precomp
+ VLD1.P (pTbl), [T1.B16, T2.B16]
+ // Preload AES round keys
+ ADD $128, ks
+ VLD1.P 48(ks), [K8.B16, K9.B16, K10.B16]
+ VMOV K10.B16, KLAST.B16
+ TBZ $4, NR, singlesLoop
+ VLD1.P 32(ks), [B1.B16, B2.B16]
+ VMOV B2.B16, KLAST.B16
+ TBZ $3, NR, singlesLoop
+ VLD1.P 32(ks), [B3.B16, B4.B16]
+ VMOV B4.B16, KLAST.B16
+
+singlesLoop:
+ CMP $16, srcPtrLen
+ BLT tail
+ SUB $16, srcPtrLen
+
+ VLD1.P 16(srcPtr), [T0.B16]
+ VEOR KLAST.B16, T0.B16, T0.B16
+
+ VREV32 CTR.B16, B0.B16
+ VADD CTR.S4, INC.S4, CTR.S4
+
+ AESE K0.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K1.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K2.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K3.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K4.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K5.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K6.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K7.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K8.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K9.B16, B0.B16
+ TBZ $4, NR, singlesLast
+ AESMC B0.B16, B0.B16
+ AESE K10.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE B1.B16, B0.B16
+ TBZ $3, NR, singlesLast
+ AESMC B0.B16, B0.B16
+ AESE B2.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE B3.B16, B0.B16
+singlesLast:
+ VEOR T0.B16, B0.B16, B0.B16
+encReduce:
+ VST1.P [B0.B16], 16(dstPtr)
+
+ VREV64 B0.B16, B0.B16
+ VEOR ACC0.B16, B0.B16, B0.B16
+
+ VEXT $8, B0.B16, B0.B16, T0.B16
+ VEOR B0.B16, T0.B16, T0.B16
+ VPMULL B0.D1, T1.D1, ACC1.Q1
+ VPMULL2 B0.D2, T1.D2, ACC0.Q1
+ VPMULL T0.D1, T2.D1, ACCM.Q1
+
+ reduce()
+
+ B singlesLoop
+tail:
+ CBZ srcPtrLen, done
+
+ VEOR T0.B16, T0.B16, T0.B16
+ VEOR T3.B16, T3.B16, T3.B16
+ MOVD $0, H1
+ SUB $1, H1
+ ADD srcPtrLen, srcPtr
+
+ TBZ $3, srcPtrLen, ld4
+ MOVD.W -8(srcPtr), H0
+ VMOV H0, T0.D[0]
+ VMOV H1, T3.D[0]
+ld4:
+ TBZ $2, srcPtrLen, ld2
+ MOVW.W -4(srcPtr), H0
+ VEXT $12, T0.B16, ZERO.B16, T0.B16
+ VEXT $12, T3.B16, ZERO.B16, T3.B16
+ VMOV H0, T0.S[0]
+ VMOV H1, T3.S[0]
+ld2:
+ TBZ $1, srcPtrLen, ld1
+ MOVH.W -2(srcPtr), H0
+ VEXT $14, T0.B16, ZERO.B16, T0.B16
+ VEXT $14, T3.B16, ZERO.B16, T3.B16
+ VMOV H0, T0.H[0]
+ VMOV H1, T3.H[0]
+ld1:
+ TBZ $0, srcPtrLen, ld0
+ MOVB.W -1(srcPtr), H0
+ VEXT $15, T0.B16, ZERO.B16, T0.B16
+ VEXT $15, T3.B16, ZERO.B16, T3.B16
+ VMOV H0, T0.B[0]
+ VMOV H1, T3.B[0]
+ld0:
+
+ MOVD ZR, srcPtrLen
+ VEOR KLAST.B16, T0.B16, T0.B16
+ VREV32 CTR.B16, B0.B16
+
+ AESE K0.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K1.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K2.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K3.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K4.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K5.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K6.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K7.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K8.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K9.B16, B0.B16
+ TBZ $4, NR, tailLast
+ AESMC B0.B16, B0.B16
+ AESE K10.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE B1.B16, B0.B16
+ TBZ $3, NR, tailLast
+ AESMC B0.B16, B0.B16
+ AESE B2.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE B3.B16, B0.B16
+
+tailLast:
+ VEOR T0.B16, B0.B16, B0.B16
+ VAND T3.B16, B0.B16, B0.B16
+ B encReduce
+
+done:
+ VST1 [ACC0.B16], (tPtr)
+ RET
+
+// func gcmAesDec(productTable *[256]byte, dst, src []byte, ctr, T *[16]byte, ks []uint32)
+TEXT ·gcmAesDec(SB),NOSPLIT,$0
+ MOVD productTable+0(FP), pTbl
+ MOVD dst+8(FP), dstPtr
+ MOVD src_base+32(FP), srcPtr
+ MOVD src_len+40(FP), srcPtrLen
+ MOVD ctr+56(FP), ctrPtr
+ MOVD T+64(FP), tPtr
+ MOVD ks_base+72(FP), ks
+ MOVD ks_len+80(FP), NR
+
+ MOVD $0xC2, H1
+ LSL $56, H1
+ MOVD $1, H0
+ VMOV H1, POLY.D[0]
+ VMOV H0, POLY.D[1]
+ VEOR ZERO.B16, ZERO.B16, ZERO.B16
+ // Compute NR from len(ks)
+ MOVD pTbl, pTblSave
+ // Current tag, after AAD
+ VLD1 (tPtr), [ACC0.B16]
+ VEOR ACC1.B16, ACC1.B16, ACC1.B16
+ VEOR ACCM.B16, ACCM.B16, ACCM.B16
+ // Prepare initial counter, and the increment vector
+ VLD1 (ctrPtr), [CTR.B16]
+ VEOR INC.B16, INC.B16, INC.B16
+ MOVD $1, H0
+ VMOV H0, INC.S[3]
+ VREV32 CTR.B16, CTR.B16
+ VADD CTR.S4, INC.S4, CTR.S4
+
+ MOVD ks, H0
+ // For AES-128 round keys are stored in: K0 .. K10, KLAST
+ VLD1.P 64(H0), [K0.B16, K1.B16, K2.B16, K3.B16]
+ VLD1.P 64(H0), [K4.B16, K5.B16, K6.B16, K7.B16]
+ VLD1.P 48(H0), [K8.B16, K9.B16, K10.B16]
+ VMOV K10.B16, KLAST.B16
+
+ // Skip to <8 blocks loop
+ CMP $128, srcPtrLen
+ BLT startSingles
+ // There are at least 8 blocks to encrypt
+ TBZ $4, NR, octetsLoop
+
+ // For AES-192 round keys occupy: K0 .. K7, K10, K11, K8, K9, KLAST
+ VMOV K8.B16, K10.B16
+ VMOV K9.B16, K11.B16
+ VMOV KLAST.B16, K8.B16
+ VLD1.P 16(H0), [K9.B16]
+ VLD1.P 16(H0), [KLAST.B16]
+ TBZ $3, NR, octetsLoop
+ // For AES-256 round keys occupy: K0 .. K7, K10, K11, mem, mem, K8, K9, KLAST
+ VMOV KLAST.B16, K8.B16
+ VLD1.P 16(H0), [K9.B16]
+ VLD1.P 16(H0), [KLAST.B16]
+ ADD $10*16, ks, H0
+ MOVD H0, curK
+
+octetsLoop:
+ SUB $128, srcPtrLen
+
+ VMOV CTR.B16, B0.B16
+ VADD B0.S4, INC.S4, B1.S4
+ VREV32 B0.B16, B0.B16
+ VADD B1.S4, INC.S4, B2.S4
+ VREV32 B1.B16, B1.B16
+ VADD B2.S4, INC.S4, B3.S4
+ VREV32 B2.B16, B2.B16
+ VADD B3.S4, INC.S4, B4.S4
+ VREV32 B3.B16, B3.B16
+ VADD B4.S4, INC.S4, B5.S4
+ VREV32 B4.B16, B4.B16
+ VADD B5.S4, INC.S4, B6.S4
+ VREV32 B5.B16, B5.B16
+ VADD B6.S4, INC.S4, B7.S4
+ VREV32 B6.B16, B6.B16
+ VADD B7.S4, INC.S4, CTR.S4
+ VREV32 B7.B16, B7.B16
+
+ aesrndx8(K0)
+ aesrndx8(K1)
+ aesrndx8(K2)
+ aesrndx8(K3)
+ aesrndx8(K4)
+ aesrndx8(K5)
+ aesrndx8(K6)
+ aesrndx8(K7)
+ TBZ $4, NR, octetsFinish
+ aesrndx8(K10)
+ aesrndx8(K11)
+ TBZ $3, NR, octetsFinish
+ VLD1.P 32(curK), [T1.B16, T2.B16]
+ aesrndx8(T1)
+ aesrndx8(T2)
+ MOVD H0, curK
+octetsFinish:
+ aesrndx8(K8)
+ aesrndlastx8(K9)
+
+ VEOR KLAST.B16, B0.B16, T1.B16
+ VEOR KLAST.B16, B1.B16, T2.B16
+ VEOR KLAST.B16, B2.B16, B2.B16
+ VEOR KLAST.B16, B3.B16, B3.B16
+ VEOR KLAST.B16, B4.B16, B4.B16
+ VEOR KLAST.B16, B5.B16, B5.B16
+ VEOR KLAST.B16, B6.B16, B6.B16
+ VEOR KLAST.B16, B7.B16, B7.B16
+
+ VLD1.P 32(srcPtr), [B0.B16, B1.B16]
+ VEOR B0.B16, T1.B16, T1.B16
+ VEOR B1.B16, T2.B16, T2.B16
+ VST1.P [T1.B16, T2.B16], 32(dstPtr)
+
+ VLD1.P 32(pTbl), [T1.B16, T2.B16]
+ VREV64 B0.B16, B0.B16
+ VEOR ACC0.B16, B0.B16, B0.B16
+ VEXT $8, B0.B16, B0.B16, T0.B16
+ VEOR B0.B16, T0.B16, T0.B16
+ VPMULL B0.D1, T1.D1, ACC1.Q1
+ VPMULL2 B0.D2, T1.D2, ACC0.Q1
+ VPMULL T0.D1, T2.D1, ACCM.Q1
+ mulRound(B1)
+
+ VLD1.P 32(srcPtr), [B0.B16, B1.B16]
+ VEOR B2.B16, B0.B16, T1.B16
+ VEOR B3.B16, B1.B16, T2.B16
+ VST1.P [T1.B16, T2.B16], 32(dstPtr)
+ mulRound(B0)
+ mulRound(B1)
+
+ VLD1.P 32(srcPtr), [B0.B16, B1.B16]
+ VEOR B4.B16, B0.B16, T1.B16
+ VEOR B5.B16, B1.B16, T2.B16
+ VST1.P [T1.B16, T2.B16], 32(dstPtr)
+ mulRound(B0)
+ mulRound(B1)
+
+ VLD1.P 32(srcPtr), [B0.B16, B1.B16]
+ VEOR B6.B16, B0.B16, T1.B16
+ VEOR B7.B16, B1.B16, T2.B16
+ VST1.P [T1.B16, T2.B16], 32(dstPtr)
+ mulRound(B0)
+ mulRound(B1)
+
+ MOVD pTblSave, pTbl
+ reduce()
+
+ CMP $128, srcPtrLen
+ BGE octetsLoop
+
+startSingles:
+ CBZ srcPtrLen, done
+ ADD $14*16, pTbl
+ // Preload H and its Karatsuba precomp
+ VLD1.P (pTbl), [T1.B16, T2.B16]
+ // Preload AES round keys
+ ADD $128, ks
+ VLD1.P 48(ks), [K8.B16, K9.B16, K10.B16]
+ VMOV K10.B16, KLAST.B16
+ TBZ $4, NR, singlesLoop
+ VLD1.P 32(ks), [B1.B16, B2.B16]
+ VMOV B2.B16, KLAST.B16
+ TBZ $3, NR, singlesLoop
+ VLD1.P 32(ks), [B3.B16, B4.B16]
+ VMOV B4.B16, KLAST.B16
+
+singlesLoop:
+ CMP $16, srcPtrLen
+ BLT tail
+ SUB $16, srcPtrLen
+
+ VLD1.P 16(srcPtr), [T0.B16]
+ VREV64 T0.B16, B5.B16
+ VEOR KLAST.B16, T0.B16, T0.B16
+
+ VREV32 CTR.B16, B0.B16
+ VADD CTR.S4, INC.S4, CTR.S4
+
+ AESE K0.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K1.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K2.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K3.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K4.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K5.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K6.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K7.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K8.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K9.B16, B0.B16
+ TBZ $4, NR, singlesLast
+ AESMC B0.B16, B0.B16
+ AESE K10.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE B1.B16, B0.B16
+ TBZ $3, NR, singlesLast
+ AESMC B0.B16, B0.B16
+ AESE B2.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE B3.B16, B0.B16
+singlesLast:
+ VEOR T0.B16, B0.B16, B0.B16
+
+ VST1.P [B0.B16], 16(dstPtr)
+
+ VEOR ACC0.B16, B5.B16, B5.B16
+ VEXT $8, B5.B16, B5.B16, T0.B16
+ VEOR B5.B16, T0.B16, T0.B16
+ VPMULL B5.D1, T1.D1, ACC1.Q1
+ VPMULL2 B5.D2, T1.D2, ACC0.Q1
+ VPMULL T0.D1, T2.D1, ACCM.Q1
+ reduce()
+
+ B singlesLoop
+tail:
+ CBZ srcPtrLen, done
+
+ VREV32 CTR.B16, B0.B16
+ VADD CTR.S4, INC.S4, CTR.S4
+
+ AESE K0.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K1.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K2.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K3.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K4.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K5.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K6.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K7.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K8.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE K9.B16, B0.B16
+ TBZ $4, NR, tailLast
+ AESMC B0.B16, B0.B16
+ AESE K10.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE B1.B16, B0.B16
+ TBZ $3, NR, tailLast
+ AESMC B0.B16, B0.B16
+ AESE B2.B16, B0.B16
+ AESMC B0.B16, B0.B16
+ AESE B3.B16, B0.B16
+tailLast:
+ VEOR KLAST.B16, B0.B16, B0.B16
+
+ // Assuming it is safe to load past dstPtr due to the presence of the tag
+ VLD1 (srcPtr), [B5.B16]
+
+ VEOR B5.B16, B0.B16, B0.B16
+
+ VEOR T3.B16, T3.B16, T3.B16
+ MOVD $0, H1
+ SUB $1, H1
+
+ TBZ $3, srcPtrLen, ld4
+ VMOV B0.D[0], H0
+ MOVD.P H0, 8(dstPtr)
+ VMOV H1, T3.D[0]
+ VEXT $8, ZERO.B16, B0.B16, B0.B16
+ld4:
+ TBZ $2, srcPtrLen, ld2
+ VMOV B0.S[0], H0
+ MOVW.P H0, 4(dstPtr)
+ VEXT $12, T3.B16, ZERO.B16, T3.B16
+ VMOV H1, T3.S[0]
+ VEXT $4, ZERO.B16, B0.B16, B0.B16
+ld2:
+ TBZ $1, srcPtrLen, ld1
+ VMOV B0.H[0], H0
+ MOVH.P H0, 2(dstPtr)
+ VEXT $14, T3.B16, ZERO.B16, T3.B16
+ VMOV H1, T3.H[0]
+ VEXT $2, ZERO.B16, B0.B16, B0.B16
+ld1:
+ TBZ $0, srcPtrLen, ld0
+ VMOV B0.B[0], H0
+ MOVB.P H0, 1(dstPtr)
+ VEXT $15, T3.B16, ZERO.B16, T3.B16
+ VMOV H1, T3.B[0]
+ld0:
+
+ VAND T3.B16, B5.B16, B5.B16
+ VREV64 B5.B16, B5.B16
+
+ VEOR ACC0.B16, B5.B16, B5.B16
+ VEXT $8, B5.B16, B5.B16, T0.B16
+ VEOR B5.B16, T0.B16, T0.B16
+ VPMULL B5.D1, T1.D1, ACC1.Q1
+ VPMULL2 B5.D2, T1.D2, ACC0.Q1
+ VPMULL T0.D1, T2.D1, ACCM.Q1
+ reduce()
+done:
+ VST1 [ACC0.B16], (tPtr)
+
+ RET
diff --git a/src/crypto/aes/gcm_ppc64x.go b/src/crypto/aes/gcm_ppc64x.go
new file mode 100644
index 0000000..44b2705
--- /dev/null
+++ b/src/crypto/aes/gcm_ppc64x.go
@@ -0,0 +1,265 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build ppc64le || ppc64
+
+package aes
+
+import (
+ "crypto/cipher"
+ "crypto/subtle"
+ "encoding/binary"
+ "errors"
+ "runtime"
+)
+
+// This file implements GCM using an optimized GHASH function.
+
+//go:noescape
+func gcmInit(productTable *[256]byte, h []byte)
+
+//go:noescape
+func gcmHash(output []byte, productTable *[256]byte, inp []byte, len int)
+
+//go:noescape
+func gcmMul(output []byte, productTable *[256]byte)
+
+const (
+ gcmCounterSize = 16
+ gcmBlockSize = 16
+ gcmTagSize = 16
+ gcmStandardNonceSize = 12
+)
+
+var errOpen = errors.New("cipher: message authentication failed")
+
+// Assert that aesCipherGCM implements the gcmAble interface.
+var _ gcmAble = (*aesCipherAsm)(nil)
+
+type gcmAsm struct {
+ cipher *aesCipherAsm
+ // ks is the key schedule, the length of which depends on the size of
+ // the AES key.
+ ks []uint32
+ // productTable contains pre-computed multiples of the binary-field
+ // element used in GHASH.
+ productTable [256]byte
+ // nonceSize contains the expected size of the nonce, in bytes.
+ nonceSize int
+ // tagSize contains the size of the tag, in bytes.
+ tagSize int
+}
+
+// NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only
+// called by crypto/cipher.NewGCM via the gcmAble interface.
+func (c *aesCipherAsm) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
+ var h1, h2 uint64
+ g := &gcmAsm{cipher: c, ks: c.enc, nonceSize: nonceSize, tagSize: tagSize}
+
+ hle := make([]byte, gcmBlockSize)
+
+ c.Encrypt(hle, hle)
+
+ // Reverse the bytes in each 8 byte chunk
+ // Load little endian, store big endian
+ if runtime.GOARCH == "ppc64le" {
+ h1 = binary.LittleEndian.Uint64(hle[:8])
+ h2 = binary.LittleEndian.Uint64(hle[8:])
+ } else {
+ h1 = binary.BigEndian.Uint64(hle[:8])
+ h2 = binary.BigEndian.Uint64(hle[8:])
+ }
+ binary.BigEndian.PutUint64(hle[:8], h1)
+ binary.BigEndian.PutUint64(hle[8:], h2)
+ gcmInit(&g.productTable, hle)
+
+ return g, nil
+}
+
+func (g *gcmAsm) NonceSize() int {
+ return g.nonceSize
+}
+
+func (g *gcmAsm) Overhead() int {
+ return g.tagSize
+}
+
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+ if total := len(in) + n; cap(in) >= total {
+ head = in[:total]
+ } else {
+ head = make([]byte, total)
+ copy(head, in)
+ }
+ tail = head[len(in):]
+ return
+}
+
+// deriveCounter computes the initial GCM counter state from the given nonce.
+func (g *gcmAsm) deriveCounter(counter *[gcmBlockSize]byte, nonce []byte) {
+ if len(nonce) == gcmStandardNonceSize {
+ copy(counter[:], nonce)
+ counter[gcmBlockSize-1] = 1
+ } else {
+ var hash [16]byte
+ g.paddedGHASH(&hash, nonce)
+ lens := gcmLengths(0, uint64(len(nonce))*8)
+ g.paddedGHASH(&hash, lens[:])
+ copy(counter[:], hash[:])
+ }
+}
+
+// counterCrypt encrypts in using AES in counter mode and places the result
+// into out. counter is the initial count value and will be updated with the next
+// count value. The length of out must be greater than or equal to the length
+// of in.
+func (g *gcmAsm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) {
+ var mask [gcmBlockSize]byte
+
+ for len(in) >= gcmBlockSize {
+ // Hint to avoid bounds check
+ _, _ = in[15], out[15]
+ g.cipher.Encrypt(mask[:], counter[:])
+ gcmInc32(counter)
+
+ // XOR 16 bytes each loop iteration in 8 byte chunks
+ in0 := binary.LittleEndian.Uint64(in[0:])
+ in1 := binary.LittleEndian.Uint64(in[8:])
+ m0 := binary.LittleEndian.Uint64(mask[:8])
+ m1 := binary.LittleEndian.Uint64(mask[8:])
+ binary.LittleEndian.PutUint64(out[:8], in0^m0)
+ binary.LittleEndian.PutUint64(out[8:], in1^m1)
+ out = out[16:]
+ in = in[16:]
+ }
+
+ if len(in) > 0 {
+ g.cipher.Encrypt(mask[:], counter[:])
+ gcmInc32(counter)
+ // XOR leftover bytes
+ for i, inb := range in {
+ out[i] = inb ^ mask[i]
+ }
+ }
+}
+
+// increments the rightmost 32-bits of the count value by 1.
+func gcmInc32(counterBlock *[16]byte) {
+ c := counterBlock[len(counterBlock)-4:]
+ x := binary.BigEndian.Uint32(c) + 1
+ binary.BigEndian.PutUint32(c, x)
+}
+
+// paddedGHASH pads data with zeroes until its length is a multiple of
+// 16-bytes. It then calculates a new value for hash using the ghash
+// algorithm.
+func (g *gcmAsm) paddedGHASH(hash *[16]byte, data []byte) {
+ if siz := len(data) - (len(data) % gcmBlockSize); siz > 0 {
+ gcmHash(hash[:], &g.productTable, data[:], siz)
+ data = data[siz:]
+ }
+ if len(data) > 0 {
+ var s [16]byte
+ copy(s[:], data)
+ gcmHash(hash[:], &g.productTable, s[:], len(s))
+ }
+}
+
+// auth calculates GHASH(ciphertext, additionalData), masks the result with
+// tagMask and writes the result to out.
+func (g *gcmAsm) auth(out, ciphertext, aad []byte, tagMask *[gcmTagSize]byte) {
+ var hash [16]byte
+ g.paddedGHASH(&hash, aad)
+ g.paddedGHASH(&hash, ciphertext)
+ lens := gcmLengths(uint64(len(aad))*8, uint64(len(ciphertext))*8)
+ g.paddedGHASH(&hash, lens[:])
+
+ copy(out, hash[:])
+ for i := range out {
+ out[i] ^= tagMask[i]
+ }
+}
+
+// Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for
+// details.
+func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
+ if len(nonce) != g.nonceSize {
+ panic("cipher: incorrect nonce length given to GCM")
+ }
+ if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
+ panic("cipher: message too large for GCM")
+ }
+
+ ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
+
+ var counter, tagMask [gcmBlockSize]byte
+ g.deriveCounter(&counter, nonce)
+
+ g.cipher.Encrypt(tagMask[:], counter[:])
+ gcmInc32(&counter)
+
+ g.counterCrypt(out, plaintext, &counter)
+ g.auth(out[len(plaintext):], out[:len(plaintext)], data, &tagMask)
+
+ return ret
+}
+
+// Open authenticates and decrypts ciphertext. See the cipher.AEAD interface
+// for details.
+func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
+ if len(nonce) != g.nonceSize {
+ panic("cipher: incorrect nonce length given to GCM")
+ }
+ if len(ciphertext) < g.tagSize {
+ return nil, errOpen
+ }
+ if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(BlockSize)+uint64(g.tagSize) {
+ return nil, errOpen
+ }
+
+ tag := ciphertext[len(ciphertext)-g.tagSize:]
+ ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
+
+ var counter, tagMask [gcmBlockSize]byte
+ g.deriveCounter(&counter, nonce)
+
+ g.cipher.Encrypt(tagMask[:], counter[:])
+ gcmInc32(&counter)
+
+ var expectedTag [gcmTagSize]byte
+ g.auth(expectedTag[:], ciphertext, data, &tagMask)
+
+ ret, out := sliceForAppend(dst, len(ciphertext))
+
+ if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
+ for i := range out {
+ out[i] = 0
+ }
+ return nil, errOpen
+ }
+
+ g.counterCrypt(out, ciphertext, &counter)
+ return ret, nil
+}
+
+func gcmLengths(len0, len1 uint64) [16]byte {
+ return [16]byte{
+ byte(len0 >> 56),
+ byte(len0 >> 48),
+ byte(len0 >> 40),
+ byte(len0 >> 32),
+ byte(len0 >> 24),
+ byte(len0 >> 16),
+ byte(len0 >> 8),
+ byte(len0),
+ byte(len1 >> 56),
+ byte(len1 >> 48),
+ byte(len1 >> 40),
+ byte(len1 >> 32),
+ byte(len1 >> 24),
+ byte(len1 >> 16),
+ byte(len1 >> 8),
+ byte(len1),
+ }
+}
diff --git a/src/crypto/aes/gcm_ppc64x.s b/src/crypto/aes/gcm_ppc64x.s
new file mode 100644
index 0000000..72f0b8e
--- /dev/null
+++ b/src/crypto/aes/gcm_ppc64x.s
@@ -0,0 +1,590 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build ppc64 || ppc64le
+
+// Based on CRYPTOGAMS code with the following comment:
+// # ====================================================================
+// # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+// # project. The module is, however, dual licensed under OpenSSL and
+// # CRYPTOGAMS licenses depending on where you obtain it. For further
+// # details see http://www.openssl.org/~appro/cryptogams/.
+// # ====================================================================
+
+// This implementation is based on the ppc64 asm generated by the
+// script https://github.com/dot-asm/cryptogams/blob/master/ppc/ghashp8-ppc.pl
+// from commit d47afb3c.
+
+// Changes were made due to differences in the ABI and some register usage.
+// Some arguments were changed due to the way the Go code passes them.
+
+#include "textflag.h"
+
+#define XIP R3
+#define HTBL R4
+#define INP R5
+#define LEN R6
+
+#define XL V0
+#define XM V1
+#define XH V2
+#define IN V3
+#define ZERO V4
+#define T0 V5
+#define T1 V6
+#define T2 V7
+#define XC2 V8
+#define H V9
+#define HH V10
+#define HL V11
+#define LEMASK V12
+#define XL1 V13
+#define XM1 V14
+#define XH1 V15
+#define IN1 V16
+#define H2 V17
+#define H2H V18
+#define H2L V19
+#define XL3 V20
+#define XM2 V21
+#define IN2 V22
+#define H3L V23
+#define H3 V24
+#define H3H V25
+#define XH3 V26
+#define XM3 V27
+#define IN3 V28
+#define H4L V29
+#define H4 V30
+#define H4H V31
+
+#define IN0 IN
+#define H21L HL
+#define H21H HH
+#define LOPERM H2L
+#define HIPERM H2H
+
+#define VXL VS32
+#define VIN VS35
+#define VXC2 VS40
+#define VH VS41
+#define VHH VS42
+#define VHL VS43
+#define VIN1 VS48
+#define VH2 VS49
+#define VH2H VS50
+#define VH2L VS51
+
+#define VIN2 VS54
+#define VH3L VS55
+#define VH3 VS56
+#define VH3H VS57
+#define VIN3 VS60
+#define VH4L VS61
+#define VH4 VS62
+#define VH4H VS63
+
+#define VIN0 VIN
+
+// func gcmInit(productTable *[256]byte, h []byte)
+TEXT ·gcmInit(SB), NOSPLIT, $0-32
+ MOVD productTable+0(FP), XIP
+ MOVD h+8(FP), HTBL
+
+ MOVD $0x10, R8
+ MOVD $0x20, R9
+ MOVD $0x30, R10
+ LXVD2X (HTBL)(R0), VH // Load H
+
+ VSPLTISB $-16, XC2 // 0xf0
+ VSPLTISB $1, T0 // one
+ VADDUBM XC2, XC2, XC2 // 0xe0
+ VXOR ZERO, ZERO, ZERO
+ VOR XC2, T0, XC2 // 0xe1
+ VSLDOI $15, XC2, ZERO, XC2 // 0xe1...
+ VSLDOI $1, ZERO, T0, T1 // ...1
+ VADDUBM XC2, XC2, XC2 // 0xc2...
+ VSPLTISB $7, T2
+ VOR XC2, T1, XC2 // 0xc2....01
+ VSPLTB $0, H, T1 // most significant byte
+ VSL H, T0, H // H<<=1
+ VSRAB T1, T2, T1 // broadcast carry bit
+ VAND T1, XC2, T1
+ VXOR H, T1, IN // twisted H
+
+ VSLDOI $8, IN, IN, H // twist even more ...
+ VSLDOI $8, ZERO, XC2, XC2 // 0xc2.0
+ VSLDOI $8, ZERO, H, HL // ... and split
+ VSLDOI $8, H, ZERO, HH
+
+ STXVD2X VXC2, (XIP+R0) // save pre-computed table
+ STXVD2X VHL, (XIP+R8)
+ MOVD $0x40, R8
+ STXVD2X VH, (XIP+R9)
+ MOVD $0x50, R9
+ STXVD2X VHH, (XIP+R10)
+ MOVD $0x60, R10
+
+ VPMSUMD IN, HL, XL // H.lo·H.lo
+ VPMSUMD IN, H, XM // H.hi·H.lo+H.lo·H.hi
+ VPMSUMD IN, HH, XH // H.hi·H.hi
+
+ VPMSUMD XL, XC2, T2 // 1st reduction phase
+
+ VSLDOI $8, XM, ZERO, T0
+ VSLDOI $8, ZERO, XM, T1
+ VXOR XL, T0, XL
+ VXOR XH, T1, XH
+
+ VSLDOI $8, XL, XL, XL
+ VXOR XL, T2, XL
+
+ VSLDOI $8, XL, XL, T1 // 2nd reduction phase
+ VPMSUMD XL, XC2, XL
+ VXOR T1, XH, T1
+ VXOR XL, T1, IN1
+
+ VSLDOI $8, IN1, IN1, H2
+ VSLDOI $8, ZERO, H2, H2L
+ VSLDOI $8, H2, ZERO, H2H
+
+ STXVD2X VH2L, (XIP+R8) // save H^2
+ MOVD $0x70, R8
+ STXVD2X VH2, (XIP+R9)
+ MOVD $0x80, R9
+ STXVD2X VH2H, (XIP+R10)
+ MOVD $0x90, R10
+
+ VPMSUMD IN, H2L, XL // H.lo·H^2.lo
+ VPMSUMD IN1, H2L, XL1 // H^2.lo·H^2.lo
+ VPMSUMD IN, H2, XM // H.hi·H^2.lo+H.lo·H^2.hi
+ VPMSUMD IN1, H2, XM1 // H^2.hi·H^2.lo+H^2.lo·H^2.hi
+ VPMSUMD IN, H2H, XH // H.hi·H^2.hi
+ VPMSUMD IN1, H2H, XH1 // H^2.hi·H^2.hi
+
+ VPMSUMD XL, XC2, T2 // 1st reduction phase
+ VPMSUMD XL1, XC2, HH // 1st reduction phase
+
+ VSLDOI $8, XM, ZERO, T0
+ VSLDOI $8, ZERO, XM, T1
+ VSLDOI $8, XM1, ZERO, HL
+ VSLDOI $8, ZERO, XM1, H
+ VXOR XL, T0, XL
+ VXOR XH, T1, XH
+ VXOR XL1, HL, XL1
+ VXOR XH1, H, XH1
+
+ VSLDOI $8, XL, XL, XL
+ VSLDOI $8, XL1, XL1, XL1
+ VXOR XL, T2, XL
+ VXOR XL1, HH, XL1
+
+ VSLDOI $8, XL, XL, T1 // 2nd reduction phase
+ VSLDOI $8, XL1, XL1, H // 2nd reduction phase
+ VPMSUMD XL, XC2, XL
+ VPMSUMD XL1, XC2, XL1
+ VXOR T1, XH, T1
+ VXOR H, XH1, H
+ VXOR XL, T1, XL
+ VXOR XL1, H, XL1
+
+ VSLDOI $8, XL, XL, H
+ VSLDOI $8, XL1, XL1, H2
+ VSLDOI $8, ZERO, H, HL
+ VSLDOI $8, H, ZERO, HH
+ VSLDOI $8, ZERO, H2, H2L
+ VSLDOI $8, H2, ZERO, H2H
+
+ STXVD2X VHL, (XIP+R8) // save H^3
+ MOVD $0xa0, R8
+ STXVD2X VH, (XIP+R9)
+ MOVD $0xb0, R9
+ STXVD2X VHH, (XIP+R10)
+ MOVD $0xc0, R10
+ STXVD2X VH2L, (XIP+R8) // save H^4
+ STXVD2X VH2, (XIP+R9)
+ STXVD2X VH2H, (XIP+R10)
+
+ RET
+
+// func gcmHash(output []byte, productTable *[256]byte, inp []byte, len int)
+TEXT ·gcmHash(SB), NOSPLIT, $0-64
+ MOVD output+0(FP), XIP
+ MOVD productTable+24(FP), HTBL
+ MOVD inp+32(FP), INP
+ MOVD len+56(FP), LEN
+
+ MOVD $0x10, R8
+ MOVD $0x20, R9
+ MOVD $0x30, R10
+ LXVD2X (XIP)(R0), VXL // load Xi
+
+ LXVD2X (HTBL)(R8), VHL // load pre-computed table
+ MOVD $0x40, R8
+ LXVD2X (HTBL)(R9), VH
+ MOVD $0x50, R9
+ LXVD2X (HTBL)(R10), VHH
+ MOVD $0x60, R10
+ LXVD2X (HTBL)(R0), VXC2
+#ifdef GOARCH_ppc64le
+ LVSL (R0)(R0), LEMASK
+ VSPLTISB $0x07, T0
+ VXOR LEMASK, T0, LEMASK
+ VPERM XL, XL, LEMASK, XL
+#endif
+ VXOR ZERO, ZERO, ZERO
+
+ CMPU LEN, $64
+ BGE gcm_ghash_p8_4x
+
+ LXVD2X (INP)(R0), VIN
+ ADD $16, INP, INP
+ SUBCCC $16, LEN, LEN
+#ifdef GOARCH_ppc64le
+ VPERM IN, IN, LEMASK, IN
+#endif
+ VXOR IN, XL, IN
+ BEQ short
+
+ LXVD2X (HTBL)(R8), VH2L // load H^2
+ MOVD $16, R8
+ LXVD2X (HTBL)(R9), VH2
+ ADD LEN, INP, R9 // end of input
+ LXVD2X (HTBL)(R10), VH2H
+
+loop_2x:
+ LXVD2X (INP)(R0), VIN1
+#ifdef GOARCH_ppc64le
+ VPERM IN1, IN1, LEMASK, IN1
+#endif
+
+ SUBC $32, LEN, LEN
+ VPMSUMD IN, H2L, XL // H^2.lo·Xi.lo
+ VPMSUMD IN1, HL, XL1 // H.lo·Xi+1.lo
+ SUBE R11, R11, R11 // borrow?-1:0
+ VPMSUMD IN, H2, XM // H^2.hi·Xi.lo+H^2.lo·Xi.hi
+ VPMSUMD IN1, H, XM1 // H.hi·Xi+1.lo+H.lo·Xi+1.hi
+ AND LEN, R11, R11
+ VPMSUMD IN, H2H, XH // H^2.hi·Xi.hi
+ VPMSUMD IN1, HH, XH1 // H.hi·Xi+1.hi
+ ADD R11, INP, INP
+
+ VXOR XL, XL1, XL
+ VXOR XM, XM1, XM
+
+ VPMSUMD XL, XC2, T2 // 1st reduction phase
+
+ VSLDOI $8, XM, ZERO, T0
+ VSLDOI $8, ZERO, XM, T1
+ VXOR XH, XH1, XH
+ VXOR XL, T0, XL
+ VXOR XH, T1, XH
+
+ VSLDOI $8, XL, XL, XL
+ VXOR XL, T2, XL
+ LXVD2X (INP)(R8), VIN
+ ADD $32, INP, INP
+
+ VSLDOI $8, XL, XL, T1 // 2nd reduction phase
+ VPMSUMD XL, XC2, XL
+#ifdef GOARCH_ppc64le
+ VPERM IN, IN, LEMASK, IN
+#endif
+ VXOR T1, XH, T1
+ VXOR IN, T1, IN
+ VXOR IN, XL, IN
+ CMP R9, INP
+ BGT loop_2x // done yet?
+
+ CMPWU LEN, $0
+ BNE even
+
+short:
+ VPMSUMD IN, HL, XL // H.lo·Xi.lo
+ VPMSUMD IN, H, XM // H.hi·Xi.lo+H.lo·Xi.hi
+ VPMSUMD IN, HH, XH // H.hi·Xi.hi
+
+ VPMSUMD XL, XC2, T2 // 1st reduction phase
+
+ VSLDOI $8, XM, ZERO, T0
+ VSLDOI $8, ZERO, XM, T1
+ VXOR XL, T0, XL
+ VXOR XH, T1, XH
+
+ VSLDOI $8, XL, XL, XL
+ VXOR XL, T2, XL
+
+ VSLDOI $8, XL, XL, T1 // 2nd reduction phase
+ VPMSUMD XL, XC2, XL
+ VXOR T1, XH, T1
+
+even:
+ VXOR XL, T1, XL
+#ifdef GOARCH_ppc64le
+ VPERM XL, XL, LEMASK, XL
+#endif
+ STXVD2X VXL, (XIP+R0)
+
+ OR R12, R12, R12 // write out Xi
+ RET
+
+gcm_ghash_p8_4x:
+ LVSL (R8)(R0), T0 // 0x0001..0e0f
+ MOVD $0x70, R8
+ LXVD2X (HTBL)(R9), VH2
+ MOVD $0x80, R9
+ VSPLTISB $8, T1 // 0x0808..0808
+ MOVD $0x90, R10
+ LXVD2X (HTBL)(R8), VH3L // load H^3
+ MOVD $0xa0, R8
+ LXVD2X (HTBL)(R9), VH3
+ MOVD $0xb0, R9
+ LXVD2X (HTBL)(R10), VH3H
+ MOVD $0xc0, R10
+ LXVD2X (HTBL)(R8), VH4L // load H^4
+ MOVD $0x10, R8
+ LXVD2X (HTBL)(R9), VH4
+ MOVD $0x20, R9
+ LXVD2X (HTBL)(R10), VH4H
+ MOVD $0x30, R10
+
+ VSLDOI $8, ZERO, T1, T2 // 0x0000..0808
+ VADDUBM T0, T2, HIPERM // 0x0001..1617
+ VADDUBM T1, HIPERM, LOPERM // 0x0809..1e1f
+
+ SRD $4, LEN, LEN // this allows to use sign bit as carry
+
+ LXVD2X (INP)(R0), VIN0 // load input
+ LXVD2X (INP)(R8), VIN1
+ SUBCCC $8, LEN, LEN
+ LXVD2X (INP)(R9), VIN2
+ LXVD2X (INP)(R10), VIN3
+ ADD $0x40, INP, INP
+#ifdef GOARCH_ppc64le
+ VPERM IN0, IN0, LEMASK, IN0
+ VPERM IN1, IN1, LEMASK, IN1
+ VPERM IN2, IN2, LEMASK, IN2
+ VPERM IN3, IN3, LEMASK, IN3
+#endif
+
+ VXOR IN0, XL, XH
+
+ VPMSUMD IN1, H3L, XL1
+ VPMSUMD IN1, H3, XM1
+ VPMSUMD IN1, H3H, XH1
+
+ VPERM H2, H, HIPERM, H21L
+ VPERM IN2, IN3, LOPERM, T0
+ VPERM H2, H, LOPERM, H21H
+ VPERM IN2, IN3, HIPERM, T1
+ VPMSUMD IN2, H2, XM2 // H^2.lo·Xi+2.hi+H^2.hi·Xi+2.lo
+ VPMSUMD T0, H21L, XL3 // H^2.lo·Xi+2.lo+H.lo·Xi+3.lo
+ VPMSUMD IN3, H, XM3 // H.hi·Xi+3.lo +H.lo·Xi+3.hi
+ VPMSUMD T1, H21H, XH3 // H^2.hi·Xi+2.hi+H.hi·Xi+3.hi
+
+ VXOR XM2, XM1, XM2
+ VXOR XL3, XL1, XL3
+ VXOR XM3, XM2, XM3
+ VXOR XH3, XH1, XH3
+
+ BLT tail_4x
+
+loop_4x:
+ LXVD2X (INP)(R0), VIN0
+ LXVD2X (INP)(R8), VIN1
+ SUBCCC $4, LEN, LEN
+ LXVD2X (INP)(R9), VIN2
+ LXVD2X (INP)(R10), VIN3
+ ADD $0x40, INP, INP
+#ifdef GOARCH_ppc64le
+ VPERM IN1, IN1, LEMASK, IN1
+ VPERM IN2, IN2, LEMASK, IN2
+ VPERM IN3, IN3, LEMASK, IN3
+ VPERM IN0, IN0, LEMASK, IN0
+#endif
+
+ VPMSUMD XH, H4L, XL // H^4.lo·Xi.lo
+ VPMSUMD XH, H4, XM // H^4.hi·Xi.lo+H^4.lo·Xi.hi
+ VPMSUMD XH, H4H, XH // H^4.hi·Xi.hi
+ VPMSUMD IN1, H3L, XL1
+ VPMSUMD IN1, H3, XM1
+ VPMSUMD IN1, H3H, XH1
+
+ VXOR XL, XL3, XL
+ VXOR XM, XM3, XM
+ VXOR XH, XH3, XH
+ VPERM IN2, IN3, LOPERM, T0
+ VPERM IN2, IN3, HIPERM, T1
+
+ VPMSUMD XL, XC2, T2 // 1st reduction phase
+ VPMSUMD T0, H21L, XL3 // H.lo·Xi+3.lo +H^2.lo·Xi+2.lo
+ VPMSUMD T1, H21H, XH3 // H.hi·Xi+3.hi +H^2.hi·Xi+2.hi
+
+ VSLDOI $8, XM, ZERO, T0
+ VSLDOI $8, ZERO, XM, T1
+ VXOR XL, T0, XL
+ VXOR XH, T1, XH
+
+ VSLDOI $8, XL, XL, XL
+ VXOR XL, T2, XL
+
+ VSLDOI $8, XL, XL, T1 // 2nd reduction phase
+ VPMSUMD IN2, H2, XM2 // H^2.hi·Xi+2.lo+H^2.lo·Xi+2.hi
+ VPMSUMD IN3, H, XM3 // H.hi·Xi+3.lo +H.lo·Xi+3.hi
+ VPMSUMD XL, XC2, XL
+
+ VXOR XL3, XL1, XL3
+ VXOR XH3, XH1, XH3
+ VXOR XH, IN0, XH
+ VXOR XM2, XM1, XM2
+ VXOR XH, T1, XH
+ VXOR XM3, XM2, XM3
+ VXOR XH, XL, XH
+ BGE loop_4x
+
+tail_4x:
+ VPMSUMD XH, H4L, XL // H^4.lo·Xi.lo
+ VPMSUMD XH, H4, XM // H^4.hi·Xi.lo+H^4.lo·Xi.hi
+ VPMSUMD XH, H4H, XH // H^4.hi·Xi.hi
+
+ VXOR XL, XL3, XL
+ VXOR XM, XM3, XM
+
+ VPMSUMD XL, XC2, T2 // 1st reduction phase
+
+ VSLDOI $8, XM, ZERO, T0
+ VSLDOI $8, ZERO, XM, T1
+ VXOR XH, XH3, XH
+ VXOR XL, T0, XL
+ VXOR XH, T1, XH
+
+ VSLDOI $8, XL, XL, XL
+ VXOR XL, T2, XL
+
+ VSLDOI $8, XL, XL, T1 // 2nd reduction phase
+ VPMSUMD XL, XC2, XL
+ VXOR T1, XH, T1
+ VXOR XL, T1, XL
+
+ ADDCCC $4, LEN, LEN
+ BEQ done_4x
+
+ LXVD2X (INP)(R0), VIN0
+ CMPU LEN, $2
+ MOVD $-4, LEN
+ BLT one
+ LXVD2X (INP)(R8), VIN1
+ BEQ two
+
+three:
+ LXVD2X (INP)(R9), VIN2
+#ifdef GOARCH_ppc64le
+ VPERM IN0, IN0, LEMASK, IN0
+ VPERM IN1, IN1, LEMASK, IN1
+ VPERM IN2, IN2, LEMASK, IN2
+#endif
+
+ VXOR IN0, XL, XH
+ VOR H3L, H3L, H4L
+ VOR H3, H3, H4
+ VOR H3H, H3H, H4H
+
+ VPERM IN1, IN2, LOPERM, T0
+ VPERM IN1, IN2, HIPERM, T1
+ VPMSUMD IN1, H2, XM2 // H^2.lo·Xi+1.hi+H^2.hi·Xi+1.lo
+ VPMSUMD IN2, H, XM3 // H.hi·Xi+2.lo +H.lo·Xi+2.hi
+ VPMSUMD T0, H21L, XL3 // H^2.lo·Xi+1.lo+H.lo·Xi+2.lo
+ VPMSUMD T1, H21H, XH3 // H^2.hi·Xi+1.hi+H.hi·Xi+2.hi
+
+ VXOR XM3, XM2, XM3
+ JMP tail_4x
+
+two:
+#ifdef GOARCH_ppc64le
+ VPERM IN0, IN0, LEMASK, IN0
+ VPERM IN1, IN1, LEMASK, IN1
+#endif
+
+ VXOR IN, XL, XH
+ VPERM ZERO, IN1, LOPERM, T0
+ VPERM ZERO, IN1, HIPERM, T1
+
+ VSLDOI $8, ZERO, H2, H4L
+ VOR H2, H2, H4
+ VSLDOI $8, H2, ZERO, H4H
+
+ VPMSUMD T0, H21L, XL3 // H.lo·Xi+1.lo
+ VPMSUMD IN1, H, XM3 // H.hi·Xi+1.lo+H.lo·Xi+2.hi
+ VPMSUMD T1, H21H, XH3 // H.hi·Xi+1.hi
+
+ JMP tail_4x
+
+one:
+#ifdef GOARCH_ppc64le
+ VPERM IN0, IN0, LEMASK, IN0
+#endif
+
+ VSLDOI $8, ZERO, H, H4L
+ VOR H, H, H4
+ VSLDOI $8, H, ZERO, H4H
+
+ VXOR IN0, XL, XH
+ VXOR XL3, XL3, XL3
+ VXOR XM3, XM3, XM3
+ VXOR XH3, XH3, XH3
+
+ JMP tail_4x
+
+done_4x:
+#ifdef GOARCH_ppc64le
+ VPERM XL, XL, LEMASK, XL
+#endif
+ STXVD2X VXL, (XIP+R0) // write out Xi
+ RET
+
+// func gcmMul(output []byte, productTable *[256]byte)
+TEXT ·gcmMul(SB), NOSPLIT, $0-32
+ MOVD output+0(FP), XIP
+ MOVD productTable+24(FP), HTBL
+
+ MOVD $0x10, R8
+ MOVD $0x20, R9
+ MOVD $0x30, R10
+ LXVD2X (XIP)(R0), VIN // load Xi
+
+ LXVD2X (HTBL)(R8), VHL // Load pre-computed table
+ LXVD2X (HTBL)(R9), VH
+ LXVD2X (HTBL)(R10), VHH
+ LXVD2X (HTBL)(R0), VXC2
+#ifdef GOARCH_ppc64le
+ VSPLTISB $0x07, T0
+ VXOR LEMASK, T0, LEMASK
+ VPERM IN, IN, LEMASK, IN
+#endif
+ VXOR ZERO, ZERO, ZERO
+
+ VPMSUMD IN, HL, XL // H.lo·Xi.lo
+ VPMSUMD IN, H, XM // H.hi·Xi.lo+H.lo·Xi.hi
+ VPMSUMD IN, HH, XH // H.hi·Xi.hi
+
+ VPMSUMD XL, XC2, T2 // 1st reduction phase
+
+ VSLDOI $8, XM, ZERO, T0
+ VSLDOI $8, ZERO, XM, T1
+ VXOR XL, T0, XL
+ VXOR XH, T1, XH
+
+ VSLDOI $8, XL, XL, XL
+ VXOR XL, T2, XL
+
+ VSLDOI $8, XL, XL, T1 // 2nd reduction phase
+ VPMSUMD XL, XC2, XL
+ VXOR T1, XH, T1
+ VXOR XL, T1, XL
+
+#ifdef GOARCH_ppc64le
+ VPERM XL, XL, LEMASK, XL
+#endif
+ STXVD2X VXL, (XIP+R0) // write out Xi
+ RET
diff --git a/src/crypto/aes/gcm_s390x.go b/src/crypto/aes/gcm_s390x.go
new file mode 100644
index 0000000..d95f169
--- /dev/null
+++ b/src/crypto/aes/gcm_s390x.go
@@ -0,0 +1,371 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aes
+
+import (
+ "crypto/cipher"
+ "crypto/internal/alias"
+ "crypto/subtle"
+ "encoding/binary"
+ "errors"
+ "internal/cpu"
+)
+
+// This file contains two implementations of AES-GCM. The first implementation
+// (gcmAsm) uses the KMCTR instruction to encrypt using AES in counter mode and
+// the KIMD instruction for GHASH. The second implementation (gcmKMA) uses the
+// newer KMA instruction which performs both operations.
+
+// gcmCount represents a 16-byte big-endian count value.
+type gcmCount [16]byte
+
+// inc increments the rightmost 32-bits of the count value by 1.
+func (x *gcmCount) inc() {
+ binary.BigEndian.PutUint32(x[len(x)-4:], binary.BigEndian.Uint32(x[len(x)-4:])+1)
+}
+
+// gcmLengths writes len0 || len1 as big-endian values to a 16-byte array.
+func gcmLengths(len0, len1 uint64) [16]byte {
+ v := [16]byte{}
+ binary.BigEndian.PutUint64(v[0:], len0)
+ binary.BigEndian.PutUint64(v[8:], len1)
+ return v
+}
+
+// gcmHashKey represents the 16-byte hash key required by the GHASH algorithm.
+type gcmHashKey [16]byte
+
+type gcmAsm struct {
+ block *aesCipherAsm
+ hashKey gcmHashKey
+ nonceSize int
+ tagSize int
+}
+
+const (
+ gcmBlockSize = 16
+ gcmTagSize = 16
+ gcmMinimumTagSize = 12 // NIST SP 800-38D recommends tags with 12 or more bytes.
+ gcmStandardNonceSize = 12
+)
+
+var errOpen = errors.New("cipher: message authentication failed")
+
+// Assert that aesCipherAsm implements the gcmAble interface.
+var _ gcmAble = (*aesCipherAsm)(nil)
+
+// NewGCM returns the AES cipher wrapped in Galois Counter Mode. This is only
+// called by crypto/cipher.NewGCM via the gcmAble interface.
+func (c *aesCipherAsm) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
+ var hk gcmHashKey
+ c.Encrypt(hk[:], hk[:])
+ g := gcmAsm{
+ block: c,
+ hashKey: hk,
+ nonceSize: nonceSize,
+ tagSize: tagSize,
+ }
+ if cpu.S390X.HasAESGCM {
+ g := gcmKMA{g}
+ return &g, nil
+ }
+ return &g, nil
+}
+
+func (g *gcmAsm) NonceSize() int {
+ return g.nonceSize
+}
+
+func (g *gcmAsm) Overhead() int {
+ return g.tagSize
+}
+
+// sliceForAppend takes a slice and a requested number of bytes. It returns a
+// slice with the contents of the given slice followed by that many bytes and a
+// second slice that aliases into it and contains only the extra bytes. If the
+// original slice has sufficient capacity then no allocation is performed.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+ if total := len(in) + n; cap(in) >= total {
+ head = in[:total]
+ } else {
+ head = make([]byte, total)
+ copy(head, in)
+ }
+ tail = head[len(in):]
+ return
+}
+
+// ghash uses the GHASH algorithm to hash data with the given key. The initial
+// hash value is given by hash which will be updated with the new hash value.
+// The length of data must be a multiple of 16-bytes.
+//
+//go:noescape
+func ghash(key *gcmHashKey, hash *[16]byte, data []byte)
+
+// paddedGHASH pads data with zeroes until its length is a multiple of
+// 16-bytes. It then calculates a new value for hash using the GHASH algorithm.
+func (g *gcmAsm) paddedGHASH(hash *[16]byte, data []byte) {
+ siz := len(data) &^ 0xf // align size to 16-bytes
+ if siz > 0 {
+ ghash(&g.hashKey, hash, data[:siz])
+ data = data[siz:]
+ }
+ if len(data) > 0 {
+ var s [16]byte
+ copy(s[:], data)
+ ghash(&g.hashKey, hash, s[:])
+ }
+}
+
+// cryptBlocksGCM encrypts src using AES in counter mode using the given
+// function code and key. The rightmost 32-bits of the counter are incremented
+// between each block as required by the GCM spec. The initial counter value
+// is given by cnt, which is updated with the value of the next counter value
+// to use.
+//
+// The lengths of both dst and buf must be greater than or equal to the length
+// of src. buf may be partially or completely overwritten during the execution
+// of the function.
+//
+//go:noescape
+func cryptBlocksGCM(fn code, key, dst, src, buf []byte, cnt *gcmCount)
+
+// counterCrypt encrypts src using AES in counter mode and places the result
+// into dst. cnt is the initial count value and will be updated with the next
+// count value. The length of dst must be greater than or equal to the length
+// of src.
+func (g *gcmAsm) counterCrypt(dst, src []byte, cnt *gcmCount) {
+ // Copying src into a buffer improves performance on some models when
+ // src and dst point to the same underlying array. We also need a
+ // buffer for counter values.
+ var ctrbuf, srcbuf [2048]byte
+ for len(src) >= 16 {
+ siz := len(src)
+ if len(src) > len(ctrbuf) {
+ siz = len(ctrbuf)
+ }
+ siz &^= 0xf // align siz to 16-bytes
+ copy(srcbuf[:], src[:siz])
+ cryptBlocksGCM(g.block.function, g.block.key, dst[:siz], srcbuf[:siz], ctrbuf[:], cnt)
+ src = src[siz:]
+ dst = dst[siz:]
+ }
+ if len(src) > 0 {
+ var x [16]byte
+ g.block.Encrypt(x[:], cnt[:])
+ for i := range src {
+ dst[i] = src[i] ^ x[i]
+ }
+ cnt.inc()
+ }
+}
+
+// deriveCounter computes the initial GCM counter state from the given nonce.
+// See NIST SP 800-38D, section 7.1.
+func (g *gcmAsm) deriveCounter(nonce []byte) gcmCount {
+ // GCM has two modes of operation with respect to the initial counter
+ // state: a "fast path" for 96-bit (12-byte) nonces, and a "slow path"
+ // for nonces of other lengths. For a 96-bit nonce, the nonce, along
+ // with a four-byte big-endian counter starting at one, is used
+ // directly as the starting counter. For other nonce sizes, the counter
+ // is computed by passing it through the GHASH function.
+ var counter gcmCount
+ if len(nonce) == gcmStandardNonceSize {
+ copy(counter[:], nonce)
+ counter[gcmBlockSize-1] = 1
+ } else {
+ var hash [16]byte
+ g.paddedGHASH(&hash, nonce)
+ lens := gcmLengths(0, uint64(len(nonce))*8)
+ g.paddedGHASH(&hash, lens[:])
+ copy(counter[:], hash[:])
+ }
+ return counter
+}
+
+// auth calculates GHASH(ciphertext, additionalData), masks the result with
+// tagMask and writes the result to out.
+func (g *gcmAsm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]byte) {
+ var hash [16]byte
+ g.paddedGHASH(&hash, additionalData)
+ g.paddedGHASH(&hash, ciphertext)
+ lens := gcmLengths(uint64(len(additionalData))*8, uint64(len(ciphertext))*8)
+ g.paddedGHASH(&hash, lens[:])
+
+ copy(out, hash[:])
+ for i := range out {
+ out[i] ^= tagMask[i]
+ }
+}
+
+// Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for
+// details.
+func (g *gcmAsm) Seal(dst, nonce, plaintext, data []byte) []byte {
+ if len(nonce) != g.nonceSize {
+ panic("crypto/cipher: incorrect nonce length given to GCM")
+ }
+ if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
+ panic("crypto/cipher: message too large for GCM")
+ }
+
+ ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
+ if alias.InexactOverlap(out[:len(plaintext)], plaintext) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+
+ counter := g.deriveCounter(nonce)
+
+ var tagMask [gcmBlockSize]byte
+ g.block.Encrypt(tagMask[:], counter[:])
+ counter.inc()
+
+ var tagOut [gcmTagSize]byte
+ g.counterCrypt(out, plaintext, &counter)
+ g.auth(tagOut[:], out[:len(plaintext)], data, &tagMask)
+ copy(out[len(plaintext):], tagOut[:])
+
+ return ret
+}
+
+// Open authenticates and decrypts ciphertext. See the cipher.AEAD interface
+// for details.
+func (g *gcmAsm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
+ if len(nonce) != g.nonceSize {
+ panic("crypto/cipher: incorrect nonce length given to GCM")
+ }
+ // Sanity check to prevent the authentication from always succeeding if an implementation
+ // leaves tagSize uninitialized, for example.
+ if g.tagSize < gcmMinimumTagSize {
+ panic("crypto/cipher: incorrect GCM tag size")
+ }
+ if len(ciphertext) < g.tagSize {
+ return nil, errOpen
+ }
+ if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(BlockSize)+uint64(g.tagSize) {
+ return nil, errOpen
+ }
+
+ tag := ciphertext[len(ciphertext)-g.tagSize:]
+ ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
+
+ counter := g.deriveCounter(nonce)
+
+ var tagMask [gcmBlockSize]byte
+ g.block.Encrypt(tagMask[:], counter[:])
+ counter.inc()
+
+ var expectedTag [gcmTagSize]byte
+ g.auth(expectedTag[:], ciphertext, data, &tagMask)
+
+ ret, out := sliceForAppend(dst, len(ciphertext))
+ if alias.InexactOverlap(out, ciphertext) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+
+ if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
+ // The AESNI code decrypts and authenticates concurrently, and
+ // so overwrites dst in the event of a tag mismatch. That
+ // behavior is mimicked here in order to be consistent across
+ // platforms.
+ for i := range out {
+ out[i] = 0
+ }
+ return nil, errOpen
+ }
+
+ g.counterCrypt(out, ciphertext, &counter)
+ return ret, nil
+}
+
+// gcmKMA implements the cipher.AEAD interface using the KMA instruction. It should
+// only be used if hasKMA is true.
+type gcmKMA struct {
+ gcmAsm
+}
+
+// flags for the KMA instruction
+const (
+ kmaHS = 1 << 10 // hash subkey supplied
+ kmaLAAD = 1 << 9 // last series of additional authenticated data
+ kmaLPC = 1 << 8 // last series of plaintext or ciphertext blocks
+ kmaDecrypt = 1 << 7 // decrypt
+)
+
+// kmaGCM executes the encryption or decryption operation given by fn. The tag
+// will be calculated and written to tag. cnt should contain the current
+// counter state and will be overwritten with the updated counter state.
+// TODO(mundaym): could pass in hash subkey
+//
+//go:noescape
+func kmaGCM(fn code, key, dst, src, aad []byte, tag *[16]byte, cnt *gcmCount)
+
+// Seal encrypts and authenticates plaintext. See the cipher.AEAD interface for
+// details.
+func (g *gcmKMA) Seal(dst, nonce, plaintext, data []byte) []byte {
+ if len(nonce) != g.nonceSize {
+ panic("crypto/cipher: incorrect nonce length given to GCM")
+ }
+ if uint64(len(plaintext)) > ((1<<32)-2)*BlockSize {
+ panic("crypto/cipher: message too large for GCM")
+ }
+
+ ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
+ if alias.InexactOverlap(out[:len(plaintext)], plaintext) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+
+ counter := g.deriveCounter(nonce)
+ fc := g.block.function | kmaLAAD | kmaLPC
+
+ var tag [gcmTagSize]byte
+ kmaGCM(fc, g.block.key, out[:len(plaintext)], plaintext, data, &tag, &counter)
+ copy(out[len(plaintext):], tag[:])
+
+ return ret
+}
+
+// Open authenticates and decrypts ciphertext. See the cipher.AEAD interface
+// for details.
+func (g *gcmKMA) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
+ if len(nonce) != g.nonceSize {
+ panic("crypto/cipher: incorrect nonce length given to GCM")
+ }
+ if len(ciphertext) < g.tagSize {
+ return nil, errOpen
+ }
+ if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(BlockSize)+uint64(g.tagSize) {
+ return nil, errOpen
+ }
+
+ tag := ciphertext[len(ciphertext)-g.tagSize:]
+ ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
+ ret, out := sliceForAppend(dst, len(ciphertext))
+ if alias.InexactOverlap(out, ciphertext) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+
+ if g.tagSize < gcmMinimumTagSize {
+ panic("crypto/cipher: incorrect GCM tag size")
+ }
+
+ counter := g.deriveCounter(nonce)
+ fc := g.block.function | kmaLAAD | kmaLPC | kmaDecrypt
+
+ var expectedTag [gcmTagSize]byte
+ kmaGCM(fc, g.block.key, out[:len(ciphertext)], ciphertext, data, &expectedTag, &counter)
+
+ if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
+ // The AESNI code decrypts and authenticates concurrently, and
+ // so overwrites dst in the event of a tag mismatch. That
+ // behavior is mimicked here in order to be consistent across
+ // platforms.
+ for i := range out {
+ out[i] = 0
+ }
+ return nil, errOpen
+ }
+
+ return ret, nil
+}
diff --git a/src/crypto/aes/modes.go b/src/crypto/aes/modes.go
new file mode 100644
index 0000000..5c0b08e
--- /dev/null
+++ b/src/crypto/aes/modes.go
@@ -0,0 +1,37 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aes
+
+import (
+ "crypto/cipher"
+)
+
+// gcmAble is implemented by cipher.Blocks that can provide an optimized
+// implementation of GCM through the AEAD interface.
+// See crypto/cipher/gcm.go.
+type gcmAble interface {
+ NewGCM(nonceSize, tagSize int) (cipher.AEAD, error)
+}
+
+// cbcEncAble is implemented by cipher.Blocks that can provide an optimized
+// implementation of CBC encryption through the cipher.BlockMode interface.
+// See crypto/cipher/cbc.go.
+type cbcEncAble interface {
+ NewCBCEncrypter(iv []byte) cipher.BlockMode
+}
+
+// cbcDecAble is implemented by cipher.Blocks that can provide an optimized
+// implementation of CBC decryption through the cipher.BlockMode interface.
+// See crypto/cipher/cbc.go.
+type cbcDecAble interface {
+ NewCBCDecrypter(iv []byte) cipher.BlockMode
+}
+
+// ctrAble is implemented by cipher.Blocks that can provide an optimized
+// implementation of CTR through the cipher.Stream interface.
+// See crypto/cipher/ctr.go.
+type ctrAble interface {
+ NewCTR(iv []byte) cipher.Stream
+}
diff --git a/src/crypto/aes/modes_test.go b/src/crypto/aes/modes_test.go
new file mode 100644
index 0000000..a3364c9
--- /dev/null
+++ b/src/crypto/aes/modes_test.go
@@ -0,0 +1,112 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package aes
+
+import (
+ "crypto/cipher"
+ "testing"
+)
+
+// Check that the optimized implementations of cipher modes will
+// be picked up correctly.
+
+// testInterface can be asserted to check that a type originates
+// from this test group.
+type testInterface interface {
+ InAESPackage() bool
+}
+
+// testBlock implements the cipher.Block interface and any *Able
+// interfaces that need to be tested.
+type testBlock struct{}
+
+func (*testBlock) BlockSize() int { return 0 }
+func (*testBlock) Encrypt(a, b []byte) {}
+func (*testBlock) Decrypt(a, b []byte) {}
+func (*testBlock) NewGCM(int, int) (cipher.AEAD, error) {
+ return &testAEAD{}, nil
+}
+func (*testBlock) NewCBCEncrypter([]byte) cipher.BlockMode {
+ return &testBlockMode{}
+}
+func (*testBlock) NewCBCDecrypter([]byte) cipher.BlockMode {
+ return &testBlockMode{}
+}
+func (*testBlock) NewCTR([]byte) cipher.Stream {
+ return &testStream{}
+}
+
+// testAEAD implements the cipher.AEAD interface.
+type testAEAD struct{}
+
+func (*testAEAD) NonceSize() int { return 0 }
+func (*testAEAD) Overhead() int { return 0 }
+func (*testAEAD) Seal(a, b, c, d []byte) []byte { return []byte{} }
+func (*testAEAD) Open(a, b, c, d []byte) ([]byte, error) { return []byte{}, nil }
+func (*testAEAD) InAESPackage() bool { return true }
+
+// Test the gcmAble interface is detected correctly by the cipher package.
+func TestGCMAble(t *testing.T) {
+ b := cipher.Block(&testBlock{})
+ if _, ok := b.(gcmAble); !ok {
+ t.Fatalf("testBlock does not implement the gcmAble interface")
+ }
+ aead, err := cipher.NewGCM(b)
+ if err != nil {
+ t.Fatalf("%v", err)
+ }
+ if _, ok := aead.(testInterface); !ok {
+ t.Fatalf("cipher.NewGCM did not use gcmAble interface")
+ }
+}
+
+// testBlockMode implements the cipher.BlockMode interface.
+type testBlockMode struct{}
+
+func (*testBlockMode) BlockSize() int { return 0 }
+func (*testBlockMode) CryptBlocks(a, b []byte) {}
+func (*testBlockMode) InAESPackage() bool { return true }
+
+// Test the cbcEncAble interface is detected correctly by the cipher package.
+func TestCBCEncAble(t *testing.T) {
+ b := cipher.Block(&testBlock{})
+ if _, ok := b.(cbcEncAble); !ok {
+ t.Fatalf("testBlock does not implement the cbcEncAble interface")
+ }
+ bm := cipher.NewCBCEncrypter(b, []byte{})
+ if _, ok := bm.(testInterface); !ok {
+ t.Fatalf("cipher.NewCBCEncrypter did not use cbcEncAble interface")
+ }
+}
+
+// Test the cbcDecAble interface is detected correctly by the cipher package.
+func TestCBCDecAble(t *testing.T) {
+ b := cipher.Block(&testBlock{})
+ if _, ok := b.(cbcDecAble); !ok {
+ t.Fatalf("testBlock does not implement the cbcDecAble interface")
+ }
+ bm := cipher.NewCBCDecrypter(b, []byte{})
+ if _, ok := bm.(testInterface); !ok {
+ t.Fatalf("cipher.NewCBCDecrypter did not use cbcDecAble interface")
+ }
+}
+
+// testStream implements the cipher.Stream interface.
+type testStream struct{}
+
+func (*testStream) XORKeyStream(a, b []byte) {}
+func (*testStream) InAESPackage() bool { return true }
+
+// Test the ctrAble interface is detected correctly by the cipher package.
+func TestCTRAble(t *testing.T) {
+ b := cipher.Block(&testBlock{})
+ if _, ok := b.(ctrAble); !ok {
+ t.Fatalf("testBlock does not implement the ctrAble interface")
+ }
+ s := cipher.NewCTR(b, []byte{})
+ if _, ok := s.(testInterface); !ok {
+ t.Fatalf("cipher.NewCTR did not use ctrAble interface")
+ }
+}
diff --git a/src/crypto/boring/boring.go b/src/crypto/boring/boring.go
new file mode 100644
index 0000000..097c37e
--- /dev/null
+++ b/src/crypto/boring/boring.go
@@ -0,0 +1,21 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto
+
+// Package boring exposes functions that are only available when building with
+// Go+BoringCrypto. This package is available on all targets as long as the
+// Go+BoringCrypto toolchain is used. Use the Enabled function to determine
+// whether the BoringCrypto core is actually in use.
+//
+// Any time the Go+BoringCrypto toolchain is used, the "boringcrypto" build tag
+// is satisfied, so that applications can tag files that use this package.
+package boring
+
+import "crypto/internal/boring"
+
+// Enabled reports whether BoringCrypto handles supported crypto operations.
+func Enabled() bool {
+ return boring.Enabled
+}
diff --git a/src/crypto/boring/boring_test.go b/src/crypto/boring/boring_test.go
new file mode 100644
index 0000000..33e5f1b
--- /dev/null
+++ b/src/crypto/boring/boring_test.go
@@ -0,0 +1,22 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto
+
+package boring_test
+
+import (
+ "crypto/boring"
+ "runtime"
+ "testing"
+)
+
+func TestEnabled(t *testing.T) {
+ supportedPlatform := runtime.GOOS == "linux" && (runtime.GOARCH == "amd64" || runtime.GOARCH == "arm64")
+ if supportedPlatform && !boring.Enabled() {
+ t.Error("Enabled returned false on a supported platform")
+ } else if !supportedPlatform && boring.Enabled() {
+ t.Error("Enabled returned true on an unsupported platform")
+ }
+}
diff --git a/src/crypto/boring/notboring_test.go b/src/crypto/boring/notboring_test.go
new file mode 100644
index 0000000..ffe18e9
--- /dev/null
+++ b/src/crypto/boring/notboring_test.go
@@ -0,0 +1,14 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (goexperiment.boringcrypto && !boringcrypto) || (!goexperiment.boringcrypto && boringcrypto)
+// +build goexperiment.boringcrypto,!boringcrypto !goexperiment.boringcrypto,boringcrypto
+
+package boring_test
+
+import "testing"
+
+func TestNotBoring(t *testing.T) {
+ t.Error("goexperiment.boringcrypto and boringcrypto should be equivalent build tags")
+}
diff --git a/src/crypto/cipher/benchmark_test.go b/src/crypto/cipher/benchmark_test.go
new file mode 100644
index 0000000..eb02cd0
--- /dev/null
+++ b/src/crypto/cipher/benchmark_test.go
@@ -0,0 +1,137 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher_test
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "strconv"
+ "testing"
+)
+
+func benchmarkAESGCMSeal(b *testing.B, buf []byte, keySize int) {
+ b.ReportAllocs()
+ b.SetBytes(int64(len(buf)))
+
+ var key = make([]byte, keySize)
+ var nonce [12]byte
+ var ad [13]byte
+ aes, _ := aes.NewCipher(key[:])
+ aesgcm, _ := cipher.NewGCM(aes)
+ var out []byte
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ out = aesgcm.Seal(out[:0], nonce[:], buf, ad[:])
+ }
+}
+
+func benchmarkAESGCMOpen(b *testing.B, buf []byte, keySize int) {
+ b.ReportAllocs()
+ b.SetBytes(int64(len(buf)))
+
+ var key = make([]byte, keySize)
+ var nonce [12]byte
+ var ad [13]byte
+ aes, _ := aes.NewCipher(key[:])
+ aesgcm, _ := cipher.NewGCM(aes)
+ var out []byte
+
+ ct := aesgcm.Seal(nil, nonce[:], buf[:], ad[:])
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ out, _ = aesgcm.Open(out[:0], nonce[:], ct, ad[:])
+ }
+}
+
+func BenchmarkAESGCM(b *testing.B) {
+ for _, length := range []int{64, 1350, 8 * 1024} {
+ b.Run("Open-128-"+strconv.Itoa(length), func(b *testing.B) {
+ benchmarkAESGCMOpen(b, make([]byte, length), 128/8)
+ })
+ b.Run("Seal-128-"+strconv.Itoa(length), func(b *testing.B) {
+ benchmarkAESGCMSeal(b, make([]byte, length), 128/8)
+ })
+
+ b.Run("Open-256-"+strconv.Itoa(length), func(b *testing.B) {
+ benchmarkAESGCMOpen(b, make([]byte, length), 256/8)
+ })
+ b.Run("Seal-256-"+strconv.Itoa(length), func(b *testing.B) {
+ benchmarkAESGCMSeal(b, make([]byte, length), 256/8)
+ })
+ }
+}
+
+func benchmarkAESStream(b *testing.B, mode func(cipher.Block, []byte) cipher.Stream, buf []byte) {
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var iv [16]byte
+ aes, _ := aes.NewCipher(key[:])
+ stream := mode(aes, iv[:])
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ stream.XORKeyStream(buf, buf)
+ }
+}
+
+// If we test exactly 1K blocks, we would generate exact multiples of
+// the cipher's block size, and the cipher stream fragments would
+// always be wordsize aligned, whereas non-aligned is a more typical
+// use-case.
+const almost1K = 1024 - 5
+const almost8K = 8*1024 - 5
+
+func BenchmarkAESCFBEncrypt1K(b *testing.B) {
+ benchmarkAESStream(b, cipher.NewCFBEncrypter, make([]byte, almost1K))
+}
+
+func BenchmarkAESCFBDecrypt1K(b *testing.B) {
+ benchmarkAESStream(b, cipher.NewCFBDecrypter, make([]byte, almost1K))
+}
+
+func BenchmarkAESCFBDecrypt8K(b *testing.B) {
+ benchmarkAESStream(b, cipher.NewCFBDecrypter, make([]byte, almost8K))
+}
+
+func BenchmarkAESOFB1K(b *testing.B) {
+ benchmarkAESStream(b, cipher.NewOFB, make([]byte, almost1K))
+}
+
+func BenchmarkAESCTR1K(b *testing.B) {
+ benchmarkAESStream(b, cipher.NewCTR, make([]byte, almost1K))
+}
+
+func BenchmarkAESCTR8K(b *testing.B) {
+ benchmarkAESStream(b, cipher.NewCTR, make([]byte, almost8K))
+}
+
+func BenchmarkAESCBCEncrypt1K(b *testing.B) {
+ buf := make([]byte, 1024)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var iv [16]byte
+ aes, _ := aes.NewCipher(key[:])
+ cbc := cipher.NewCBCEncrypter(aes, iv[:])
+ for i := 0; i < b.N; i++ {
+ cbc.CryptBlocks(buf, buf)
+ }
+}
+
+func BenchmarkAESCBCDecrypt1K(b *testing.B) {
+ buf := make([]byte, 1024)
+ b.SetBytes(int64(len(buf)))
+
+ var key [16]byte
+ var iv [16]byte
+ aes, _ := aes.NewCipher(key[:])
+ cbc := cipher.NewCBCDecrypter(aes, iv[:])
+ for i := 0; i < b.N; i++ {
+ cbc.CryptBlocks(buf, buf)
+ }
+}
diff --git a/src/crypto/cipher/cbc.go b/src/crypto/cipher/cbc.go
new file mode 100644
index 0000000..51a1420
--- /dev/null
+++ b/src/crypto/cipher/cbc.go
@@ -0,0 +1,189 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Cipher block chaining (CBC) mode.
+
+// CBC provides confidentiality by xoring (chaining) each plaintext block
+// with the previous ciphertext block before applying the block cipher.
+
+// See NIST SP 800-38A, pp 10-11
+
+package cipher
+
+import (
+ "bytes"
+ "crypto/internal/alias"
+ "crypto/subtle"
+)
+
+type cbc struct {
+ b Block
+ blockSize int
+ iv []byte
+ tmp []byte
+}
+
+func newCBC(b Block, iv []byte) *cbc {
+ return &cbc{
+ b: b,
+ blockSize: b.BlockSize(),
+ iv: bytes.Clone(iv),
+ tmp: make([]byte, b.BlockSize()),
+ }
+}
+
+type cbcEncrypter cbc
+
+// cbcEncAble is an interface implemented by ciphers that have a specific
+// optimized implementation of CBC encryption, like crypto/aes.
+// NewCBCEncrypter will check for this interface and return the specific
+// BlockMode if found.
+type cbcEncAble interface {
+ NewCBCEncrypter(iv []byte) BlockMode
+}
+
+// NewCBCEncrypter returns a BlockMode which encrypts in cipher block chaining
+// mode, using the given Block. The length of iv must be the same as the
+// Block's block size.
+func NewCBCEncrypter(b Block, iv []byte) BlockMode {
+ if len(iv) != b.BlockSize() {
+ panic("cipher.NewCBCEncrypter: IV length must equal block size")
+ }
+ if cbc, ok := b.(cbcEncAble); ok {
+ return cbc.NewCBCEncrypter(iv)
+ }
+ return (*cbcEncrypter)(newCBC(b, iv))
+}
+
+// newCBCGenericEncrypter returns a BlockMode which encrypts in cipher block chaining
+// mode, using the given Block. The length of iv must be the same as the
+// Block's block size. This always returns the generic non-asm encrypter for use
+// in fuzz testing.
+func newCBCGenericEncrypter(b Block, iv []byte) BlockMode {
+ if len(iv) != b.BlockSize() {
+ panic("cipher.NewCBCEncrypter: IV length must equal block size")
+ }
+ return (*cbcEncrypter)(newCBC(b, iv))
+}
+
+func (x *cbcEncrypter) BlockSize() int { return x.blockSize }
+
+func (x *cbcEncrypter) CryptBlocks(dst, src []byte) {
+ if len(src)%x.blockSize != 0 {
+ panic("crypto/cipher: input not full blocks")
+ }
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if alias.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+
+ iv := x.iv
+
+ for len(src) > 0 {
+ // Write the xor to dst, then encrypt in place.
+ subtle.XORBytes(dst[:x.blockSize], src[:x.blockSize], iv)
+ x.b.Encrypt(dst[:x.blockSize], dst[:x.blockSize])
+
+ // Move to the next block with this block as the next iv.
+ iv = dst[:x.blockSize]
+ src = src[x.blockSize:]
+ dst = dst[x.blockSize:]
+ }
+
+ // Save the iv for the next CryptBlocks call.
+ copy(x.iv, iv)
+}
+
+func (x *cbcEncrypter) SetIV(iv []byte) {
+ if len(iv) != len(x.iv) {
+ panic("cipher: incorrect length IV")
+ }
+ copy(x.iv, iv)
+}
+
+type cbcDecrypter cbc
+
+// cbcDecAble is an interface implemented by ciphers that have a specific
+// optimized implementation of CBC decryption, like crypto/aes.
+// NewCBCDecrypter will check for this interface and return the specific
+// BlockMode if found.
+type cbcDecAble interface {
+ NewCBCDecrypter(iv []byte) BlockMode
+}
+
+// NewCBCDecrypter returns a BlockMode which decrypts in cipher block chaining
+// mode, using the given Block. The length of iv must be the same as the
+// Block's block size and must match the iv used to encrypt the data.
+func NewCBCDecrypter(b Block, iv []byte) BlockMode {
+ if len(iv) != b.BlockSize() {
+ panic("cipher.NewCBCDecrypter: IV length must equal block size")
+ }
+ if cbc, ok := b.(cbcDecAble); ok {
+ return cbc.NewCBCDecrypter(iv)
+ }
+ return (*cbcDecrypter)(newCBC(b, iv))
+}
+
+// newCBCGenericDecrypter returns a BlockMode which encrypts in cipher block chaining
+// mode, using the given Block. The length of iv must be the same as the
+// Block's block size. This always returns the generic non-asm decrypter for use in
+// fuzz testing.
+func newCBCGenericDecrypter(b Block, iv []byte) BlockMode {
+ if len(iv) != b.BlockSize() {
+ panic("cipher.NewCBCDecrypter: IV length must equal block size")
+ }
+ return (*cbcDecrypter)(newCBC(b, iv))
+}
+
+func (x *cbcDecrypter) BlockSize() int { return x.blockSize }
+
+func (x *cbcDecrypter) CryptBlocks(dst, src []byte) {
+ if len(src)%x.blockSize != 0 {
+ panic("crypto/cipher: input not full blocks")
+ }
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if alias.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+ if len(src) == 0 {
+ return
+ }
+
+ // For each block, we need to xor the decrypted data with the previous block's ciphertext (the iv).
+ // To avoid making a copy each time, we loop over the blocks BACKWARDS.
+ end := len(src)
+ start := end - x.blockSize
+ prev := start - x.blockSize
+
+ // Copy the last block of ciphertext in preparation as the new iv.
+ copy(x.tmp, src[start:end])
+
+ // Loop over all but the first block.
+ for start > 0 {
+ x.b.Decrypt(dst[start:end], src[start:end])
+ subtle.XORBytes(dst[start:end], dst[start:end], src[prev:start])
+
+ end = start
+ start = prev
+ prev -= x.blockSize
+ }
+
+ // The first block is special because it uses the saved iv.
+ x.b.Decrypt(dst[start:end], src[start:end])
+ subtle.XORBytes(dst[start:end], dst[start:end], x.iv)
+
+ // Set the new iv to the first block we copied earlier.
+ x.iv, x.tmp = x.tmp, x.iv
+}
+
+func (x *cbcDecrypter) SetIV(iv []byte) {
+ if len(iv) != len(x.iv) {
+ panic("cipher: incorrect length IV")
+ }
+ copy(x.iv, iv)
+}
diff --git a/src/crypto/cipher/cbc_aes_test.go b/src/crypto/cipher/cbc_aes_test.go
new file mode 100644
index 0000000..bf9e7ad
--- /dev/null
+++ b/src/crypto/cipher/cbc_aes_test.go
@@ -0,0 +1,104 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CBC AES test vectors.
+
+// See U.S. National Institute of Standards and Technology (NIST)
+// Special Publication 800-38A, ``Recommendation for Block Cipher
+// Modes of Operation,'' 2001 Edition, pp. 24-29.
+
+package cipher_test
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "testing"
+)
+
+var cbcAESTests = []struct {
+ name string
+ key []byte
+ iv []byte
+ in []byte
+ out []byte
+}{
+ // NIST SP 800-38A pp 27-29
+ {
+ "CBC-AES128",
+ commonKey128,
+ commonIV,
+ commonInput,
+ []byte{
+ 0x76, 0x49, 0xab, 0xac, 0x81, 0x19, 0xb2, 0x46, 0xce, 0xe9, 0x8e, 0x9b, 0x12, 0xe9, 0x19, 0x7d,
+ 0x50, 0x86, 0xcb, 0x9b, 0x50, 0x72, 0x19, 0xee, 0x95, 0xdb, 0x11, 0x3a, 0x91, 0x76, 0x78, 0xb2,
+ 0x73, 0xbe, 0xd6, 0xb8, 0xe3, 0xc1, 0x74, 0x3b, 0x71, 0x16, 0xe6, 0x9e, 0x22, 0x22, 0x95, 0x16,
+ 0x3f, 0xf1, 0xca, 0xa1, 0x68, 0x1f, 0xac, 0x09, 0x12, 0x0e, 0xca, 0x30, 0x75, 0x86, 0xe1, 0xa7,
+ },
+ },
+ {
+ "CBC-AES192",
+ commonKey192,
+ commonIV,
+ commonInput,
+ []byte{
+ 0x4f, 0x02, 0x1d, 0xb2, 0x43, 0xbc, 0x63, 0x3d, 0x71, 0x78, 0x18, 0x3a, 0x9f, 0xa0, 0x71, 0xe8,
+ 0xb4, 0xd9, 0xad, 0xa9, 0xad, 0x7d, 0xed, 0xf4, 0xe5, 0xe7, 0x38, 0x76, 0x3f, 0x69, 0x14, 0x5a,
+ 0x57, 0x1b, 0x24, 0x20, 0x12, 0xfb, 0x7a, 0xe0, 0x7f, 0xa9, 0xba, 0xac, 0x3d, 0xf1, 0x02, 0xe0,
+ 0x08, 0xb0, 0xe2, 0x79, 0x88, 0x59, 0x88, 0x81, 0xd9, 0x20, 0xa9, 0xe6, 0x4f, 0x56, 0x15, 0xcd,
+ },
+ },
+ {
+ "CBC-AES256",
+ commonKey256,
+ commonIV,
+ commonInput,
+ []byte{
+ 0xf5, 0x8c, 0x4c, 0x04, 0xd6, 0xe5, 0xf1, 0xba, 0x77, 0x9e, 0xab, 0xfb, 0x5f, 0x7b, 0xfb, 0xd6,
+ 0x9c, 0xfc, 0x4e, 0x96, 0x7e, 0xdb, 0x80, 0x8d, 0x67, 0x9f, 0x77, 0x7b, 0xc6, 0x70, 0x2c, 0x7d,
+ 0x39, 0xf2, 0x33, 0x69, 0xa9, 0xd9, 0xba, 0xcf, 0xa5, 0x30, 0xe2, 0x63, 0x04, 0x23, 0x14, 0x61,
+ 0xb2, 0xeb, 0x05, 0xe2, 0xc3, 0x9b, 0xe9, 0xfc, 0xda, 0x6c, 0x19, 0x07, 0x8c, 0x6a, 0x9d, 0x1b,
+ },
+ },
+}
+
+func TestCBCEncrypterAES(t *testing.T) {
+ for _, test := range cbcAESTests {
+ c, err := aes.NewCipher(test.key)
+ if err != nil {
+ t.Errorf("%s: NewCipher(%d bytes) = %s", test.name, len(test.key), err)
+ continue
+ }
+
+ encrypter := cipher.NewCBCEncrypter(c, test.iv)
+
+ data := make([]byte, len(test.in))
+ copy(data, test.in)
+
+ encrypter.CryptBlocks(data, data)
+ if !bytes.Equal(test.out, data) {
+ t.Errorf("%s: CBCEncrypter\nhave %x\nwant %x", test.name, data, test.out)
+ }
+ }
+}
+
+func TestCBCDecrypterAES(t *testing.T) {
+ for _, test := range cbcAESTests {
+ c, err := aes.NewCipher(test.key)
+ if err != nil {
+ t.Errorf("%s: NewCipher(%d bytes) = %s", test.name, len(test.key), err)
+ continue
+ }
+
+ decrypter := cipher.NewCBCDecrypter(c, test.iv)
+
+ data := make([]byte, len(test.out))
+ copy(data, test.out)
+
+ decrypter.CryptBlocks(data, data)
+ if !bytes.Equal(test.in, data) {
+ t.Errorf("%s: CBCDecrypter\nhave %x\nwant %x", test.name, data, test.in)
+ }
+ }
+}
diff --git a/src/crypto/cipher/cfb.go b/src/crypto/cipher/cfb.go
new file mode 100644
index 0000000..aae3575
--- /dev/null
+++ b/src/crypto/cipher/cfb.go
@@ -0,0 +1,83 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CFB (Cipher Feedback) Mode.
+
+package cipher
+
+import (
+ "crypto/internal/alias"
+ "crypto/subtle"
+)
+
+type cfb struct {
+ b Block
+ next []byte
+ out []byte
+ outUsed int
+
+ decrypt bool
+}
+
+func (x *cfb) XORKeyStream(dst, src []byte) {
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if alias.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+ for len(src) > 0 {
+ if x.outUsed == len(x.out) {
+ x.b.Encrypt(x.out, x.next)
+ x.outUsed = 0
+ }
+
+ if x.decrypt {
+ // We can precompute a larger segment of the
+ // keystream on decryption. This will allow
+ // larger batches for xor, and we should be
+ // able to match CTR/OFB performance.
+ copy(x.next[x.outUsed:], src)
+ }
+ n := subtle.XORBytes(dst, src, x.out[x.outUsed:])
+ if !x.decrypt {
+ copy(x.next[x.outUsed:], dst)
+ }
+ dst = dst[n:]
+ src = src[n:]
+ x.outUsed += n
+ }
+}
+
+// NewCFBEncrypter returns a Stream which encrypts with cipher feedback mode,
+// using the given Block. The iv must be the same length as the Block's block
+// size.
+func NewCFBEncrypter(block Block, iv []byte) Stream {
+ return newCFB(block, iv, false)
+}
+
+// NewCFBDecrypter returns a Stream which decrypts with cipher feedback mode,
+// using the given Block. The iv must be the same length as the Block's block
+// size.
+func NewCFBDecrypter(block Block, iv []byte) Stream {
+ return newCFB(block, iv, true)
+}
+
+func newCFB(block Block, iv []byte, decrypt bool) Stream {
+ blockSize := block.BlockSize()
+ if len(iv) != blockSize {
+ // stack trace will indicate whether it was de or encryption
+ panic("cipher.newCFB: IV length must equal block size")
+ }
+ x := &cfb{
+ b: block,
+ out: make([]byte, blockSize),
+ next: make([]byte, blockSize),
+ outUsed: blockSize,
+ decrypt: decrypt,
+ }
+ copy(x.next, iv)
+
+ return x
+}
diff --git a/src/crypto/cipher/cfb_test.go b/src/crypto/cipher/cfb_test.go
new file mode 100644
index 0000000..72f62e6
--- /dev/null
+++ b/src/crypto/cipher/cfb_test.go
@@ -0,0 +1,113 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher_test
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/rand"
+ "encoding/hex"
+ "testing"
+)
+
+// cfbTests contains the test vectors from
+// https://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf, section
+// F.3.13.
+var cfbTests = []struct {
+ key, iv, plaintext, ciphertext string
+}{
+ {
+ "2b7e151628aed2a6abf7158809cf4f3c",
+ "000102030405060708090a0b0c0d0e0f",
+ "6bc1bee22e409f96e93d7e117393172a",
+ "3b3fd92eb72dad20333449f8e83cfb4a",
+ },
+ {
+ "2b7e151628aed2a6abf7158809cf4f3c",
+ "3B3FD92EB72DAD20333449F8E83CFB4A",
+ "ae2d8a571e03ac9c9eb76fac45af8e51",
+ "c8a64537a0b3a93fcde3cdad9f1ce58b",
+ },
+ {
+ "2b7e151628aed2a6abf7158809cf4f3c",
+ "C8A64537A0B3A93FCDE3CDAD9F1CE58B",
+ "30c81c46a35ce411e5fbc1191a0a52ef",
+ "26751f67a3cbb140b1808cf187a4f4df",
+ },
+ {
+ "2b7e151628aed2a6abf7158809cf4f3c",
+ "26751F67A3CBB140B1808CF187A4F4DF",
+ "f69f2445df4f9b17ad2b417be66c3710",
+ "c04b05357c5d1c0eeac4c66f9ff7f2e6",
+ },
+}
+
+func TestCFBVectors(t *testing.T) {
+ for i, test := range cfbTests {
+ key, err := hex.DecodeString(test.key)
+ if err != nil {
+ t.Fatal(err)
+ }
+ iv, err := hex.DecodeString(test.iv)
+ if err != nil {
+ t.Fatal(err)
+ }
+ plaintext, err := hex.DecodeString(test.plaintext)
+ if err != nil {
+ t.Fatal(err)
+ }
+ expected, err := hex.DecodeString(test.ciphertext)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ ciphertext := make([]byte, len(plaintext))
+ cfb := cipher.NewCFBEncrypter(block, iv)
+ cfb.XORKeyStream(ciphertext, plaintext)
+
+ if !bytes.Equal(ciphertext, expected) {
+ t.Errorf("#%d: wrong output: got %x, expected %x", i, ciphertext, expected)
+ }
+
+ cfbdec := cipher.NewCFBDecrypter(block, iv)
+ plaintextCopy := make([]byte, len(ciphertext))
+ cfbdec.XORKeyStream(plaintextCopy, ciphertext)
+
+ if !bytes.Equal(plaintextCopy, plaintext) {
+ t.Errorf("#%d: wrong plaintext: got %x, expected %x", i, plaintextCopy, plaintext)
+ }
+ }
+}
+
+func TestCFBInverse(t *testing.T) {
+ block, err := aes.NewCipher(commonKey128)
+ if err != nil {
+ t.Error(err)
+ return
+ }
+
+ plaintext := []byte("this is the plaintext. this is the plaintext.")
+ iv := make([]byte, block.BlockSize())
+ rand.Reader.Read(iv)
+ cfb := cipher.NewCFBEncrypter(block, iv)
+ ciphertext := make([]byte, len(plaintext))
+ copy(ciphertext, plaintext)
+ cfb.XORKeyStream(ciphertext, ciphertext)
+
+ cfbdec := cipher.NewCFBDecrypter(block, iv)
+ plaintextCopy := make([]byte, len(plaintext))
+ copy(plaintextCopy, ciphertext)
+ cfbdec.XORKeyStream(plaintextCopy, plaintextCopy)
+
+ if !bytes.Equal(plaintextCopy, plaintext) {
+ t.Errorf("got: %x, want: %x", plaintextCopy, plaintext)
+ }
+}
diff --git a/src/crypto/cipher/cipher.go b/src/crypto/cipher/cipher.go
new file mode 100644
index 0000000..df6f596
--- /dev/null
+++ b/src/crypto/cipher/cipher.go
@@ -0,0 +1,61 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package cipher implements standard block cipher modes that can be wrapped
+// around low-level block cipher implementations.
+// See https://csrc.nist.gov/groups/ST/toolkit/BCM/current_modes.html
+// and NIST Special Publication 800-38A.
+package cipher
+
+// A Block represents an implementation of block cipher
+// using a given key. It provides the capability to encrypt
+// or decrypt individual blocks. The mode implementations
+// extend that capability to streams of blocks.
+type Block interface {
+ // BlockSize returns the cipher's block size.
+ BlockSize() int
+
+ // Encrypt encrypts the first block in src into dst.
+ // Dst and src must overlap entirely or not at all.
+ Encrypt(dst, src []byte)
+
+ // Decrypt decrypts the first block in src into dst.
+ // Dst and src must overlap entirely or not at all.
+ Decrypt(dst, src []byte)
+}
+
+// A Stream represents a stream cipher.
+type Stream interface {
+ // XORKeyStream XORs each byte in the given slice with a byte from the
+ // cipher's key stream. Dst and src must overlap entirely or not at all.
+ //
+ // If len(dst) < len(src), XORKeyStream should panic. It is acceptable
+ // to pass a dst bigger than src, and in that case, XORKeyStream will
+ // only update dst[:len(src)] and will not touch the rest of dst.
+ //
+ // Multiple calls to XORKeyStream behave as if the concatenation of
+ // the src buffers was passed in a single run. That is, Stream
+ // maintains state and does not reset at each XORKeyStream call.
+ XORKeyStream(dst, src []byte)
+}
+
+// A BlockMode represents a block cipher running in a block-based mode (CBC,
+// ECB etc).
+type BlockMode interface {
+ // BlockSize returns the mode's block size.
+ BlockSize() int
+
+ // CryptBlocks encrypts or decrypts a number of blocks. The length of
+ // src must be a multiple of the block size. Dst and src must overlap
+ // entirely or not at all.
+ //
+ // If len(dst) < len(src), CryptBlocks should panic. It is acceptable
+ // to pass a dst bigger than src, and in that case, CryptBlocks will
+ // only update dst[:len(src)] and will not touch the rest of dst.
+ //
+ // Multiple calls to CryptBlocks behave as if the concatenation of
+ // the src buffers was passed in a single run. That is, BlockMode
+ // maintains state and does not reset at each CryptBlocks call.
+ CryptBlocks(dst, src []byte)
+}
diff --git a/src/crypto/cipher/cipher_test.go b/src/crypto/cipher/cipher_test.go
new file mode 100644
index 0000000..4d7cd6b
--- /dev/null
+++ b/src/crypto/cipher/cipher_test.go
@@ -0,0 +1,90 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher_test
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/des"
+ "testing"
+)
+
+func TestCryptBlocks(t *testing.T) {
+ buf := make([]byte, 16)
+ block, _ := aes.NewCipher(buf)
+
+ mode := cipher.NewCBCDecrypter(block, buf)
+ mustPanic(t, "crypto/cipher: input not full blocks", func() { mode.CryptBlocks(buf, buf[:3]) })
+ mustPanic(t, "crypto/cipher: output smaller than input", func() { mode.CryptBlocks(buf[:3], buf) })
+
+ mode = cipher.NewCBCEncrypter(block, buf)
+ mustPanic(t, "crypto/cipher: input not full blocks", func() { mode.CryptBlocks(buf, buf[:3]) })
+ mustPanic(t, "crypto/cipher: output smaller than input", func() { mode.CryptBlocks(buf[:3], buf) })
+}
+
+func mustPanic(t *testing.T, msg string, f func()) {
+ defer func() {
+ err := recover()
+ if err == nil {
+ t.Errorf("function did not panic, wanted %q", msg)
+ } else if err != msg {
+ t.Errorf("got panic %v, wanted %q", err, msg)
+ }
+ }()
+ f()
+}
+
+func TestEmptyPlaintext(t *testing.T) {
+ var key [16]byte
+ a, err := aes.NewCipher(key[:16])
+ if err != nil {
+ t.Fatal(err)
+ }
+ d, err := des.NewCipher(key[:8])
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ s := 16
+ pt := make([]byte, s)
+ ct := make([]byte, s)
+ for i := 0; i < 16; i++ {
+ pt[i], ct[i] = byte(i), byte(i)
+ }
+
+ assertEqual := func(name string, got, want []byte) {
+ if !bytes.Equal(got, want) {
+ t.Fatalf("%s: got %v, want %v", name, got, want)
+ }
+ }
+
+ for _, b := range []cipher.Block{a, d} {
+ iv := make([]byte, b.BlockSize())
+ cbce := cipher.NewCBCEncrypter(b, iv)
+ cbce.CryptBlocks(ct, pt[:0])
+ assertEqual("CBC encrypt", ct, pt)
+
+ cbcd := cipher.NewCBCDecrypter(b, iv)
+ cbcd.CryptBlocks(ct, pt[:0])
+ assertEqual("CBC decrypt", ct, pt)
+
+ cfbe := cipher.NewCFBEncrypter(b, iv)
+ cfbe.XORKeyStream(ct, pt[:0])
+ assertEqual("CFB encrypt", ct, pt)
+
+ cfbd := cipher.NewCFBDecrypter(b, iv)
+ cfbd.XORKeyStream(ct, pt[:0])
+ assertEqual("CFB decrypt", ct, pt)
+
+ ctr := cipher.NewCTR(b, iv)
+ ctr.XORKeyStream(ct, pt[:0])
+ assertEqual("CTR", ct, pt)
+
+ ofb := cipher.NewOFB(b, iv)
+ ofb.XORKeyStream(ct, pt[:0])
+ assertEqual("OFB", ct, pt)
+ }
+}
diff --git a/src/crypto/cipher/common_test.go b/src/crypto/cipher/common_test.go
new file mode 100644
index 0000000..c75c919
--- /dev/null
+++ b/src/crypto/cipher/common_test.go
@@ -0,0 +1,28 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher_test
+
+// Common values for tests.
+
+var commonInput = []byte{
+ 0x6b, 0xc1, 0xbe, 0xe2, 0x2e, 0x40, 0x9f, 0x96, 0xe9, 0x3d, 0x7e, 0x11, 0x73, 0x93, 0x17, 0x2a,
+ 0xae, 0x2d, 0x8a, 0x57, 0x1e, 0x03, 0xac, 0x9c, 0x9e, 0xb7, 0x6f, 0xac, 0x45, 0xaf, 0x8e, 0x51,
+ 0x30, 0xc8, 0x1c, 0x46, 0xa3, 0x5c, 0xe4, 0x11, 0xe5, 0xfb, 0xc1, 0x19, 0x1a, 0x0a, 0x52, 0xef,
+ 0xf6, 0x9f, 0x24, 0x45, 0xdf, 0x4f, 0x9b, 0x17, 0xad, 0x2b, 0x41, 0x7b, 0xe6, 0x6c, 0x37, 0x10,
+}
+
+var commonKey128 = []byte{0x2b, 0x7e, 0x15, 0x16, 0x28, 0xae, 0xd2, 0xa6, 0xab, 0xf7, 0x15, 0x88, 0x09, 0xcf, 0x4f, 0x3c}
+
+var commonKey192 = []byte{
+ 0x8e, 0x73, 0xb0, 0xf7, 0xda, 0x0e, 0x64, 0x52, 0xc8, 0x10, 0xf3, 0x2b, 0x80, 0x90, 0x79, 0xe5,
+ 0x62, 0xf8, 0xea, 0xd2, 0x52, 0x2c, 0x6b, 0x7b,
+}
+
+var commonKey256 = []byte{
+ 0x60, 0x3d, 0xeb, 0x10, 0x15, 0xca, 0x71, 0xbe, 0x2b, 0x73, 0xae, 0xf0, 0x85, 0x7d, 0x77, 0x81,
+ 0x1f, 0x35, 0x2c, 0x07, 0x3b, 0x61, 0x08, 0xd7, 0x2d, 0x98, 0x10, 0xa3, 0x09, 0x14, 0xdf, 0xf4,
+}
+
+var commonIV = []byte{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f}
diff --git a/src/crypto/cipher/ctr.go b/src/crypto/cipher/ctr.go
new file mode 100644
index 0000000..3ac0ff7
--- /dev/null
+++ b/src/crypto/cipher/ctr.go
@@ -0,0 +1,95 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Counter (CTR) mode.
+
+// CTR converts a block cipher into a stream cipher by
+// repeatedly encrypting an incrementing counter and
+// xoring the resulting stream of data with the input.
+
+// See NIST SP 800-38A, pp 13-15
+
+package cipher
+
+import (
+ "bytes"
+ "crypto/internal/alias"
+ "crypto/subtle"
+)
+
+type ctr struct {
+ b Block
+ ctr []byte
+ out []byte
+ outUsed int
+}
+
+const streamBufferSize = 512
+
+// ctrAble is an interface implemented by ciphers that have a specific optimized
+// implementation of CTR, like crypto/aes. NewCTR will check for this interface
+// and return the specific Stream if found.
+type ctrAble interface {
+ NewCTR(iv []byte) Stream
+}
+
+// NewCTR returns a Stream which encrypts/decrypts using the given Block in
+// counter mode. The length of iv must be the same as the Block's block size.
+func NewCTR(block Block, iv []byte) Stream {
+ if ctr, ok := block.(ctrAble); ok {
+ return ctr.NewCTR(iv)
+ }
+ if len(iv) != block.BlockSize() {
+ panic("cipher.NewCTR: IV length must equal block size")
+ }
+ bufSize := streamBufferSize
+ if bufSize < block.BlockSize() {
+ bufSize = block.BlockSize()
+ }
+ return &ctr{
+ b: block,
+ ctr: bytes.Clone(iv),
+ out: make([]byte, 0, bufSize),
+ outUsed: 0,
+ }
+}
+
+func (x *ctr) refill() {
+ remain := len(x.out) - x.outUsed
+ copy(x.out, x.out[x.outUsed:])
+ x.out = x.out[:cap(x.out)]
+ bs := x.b.BlockSize()
+ for remain <= len(x.out)-bs {
+ x.b.Encrypt(x.out[remain:], x.ctr)
+ remain += bs
+
+ // Increment counter
+ for i := len(x.ctr) - 1; i >= 0; i-- {
+ x.ctr[i]++
+ if x.ctr[i] != 0 {
+ break
+ }
+ }
+ }
+ x.out = x.out[:remain]
+ x.outUsed = 0
+}
+
+func (x *ctr) XORKeyStream(dst, src []byte) {
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if alias.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+ for len(src) > 0 {
+ if x.outUsed >= len(x.out)-x.b.BlockSize() {
+ x.refill()
+ }
+ n := subtle.XORBytes(dst, src, x.out[x.outUsed:])
+ dst = dst[n:]
+ src = src[n:]
+ x.outUsed += n
+ }
+}
diff --git a/src/crypto/cipher/ctr_aes_test.go b/src/crypto/cipher/ctr_aes_test.go
new file mode 100644
index 0000000..d019ae0
--- /dev/null
+++ b/src/crypto/cipher/ctr_aes_test.go
@@ -0,0 +1,102 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// CTR AES test vectors.
+
+// See U.S. National Institute of Standards and Technology (NIST)
+// Special Publication 800-38A, ``Recommendation for Block Cipher
+// Modes of Operation,'' 2001 Edition, pp. 55-58.
+
+package cipher_test
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "testing"
+)
+
+var commonCounter = []byte{0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff}
+
+var ctrAESTests = []struct {
+ name string
+ key []byte
+ iv []byte
+ in []byte
+ out []byte
+}{
+ // NIST SP 800-38A pp 55-58
+ {
+ "CTR-AES128",
+ commonKey128,
+ commonCounter,
+ commonInput,
+ []byte{
+ 0x87, 0x4d, 0x61, 0x91, 0xb6, 0x20, 0xe3, 0x26, 0x1b, 0xef, 0x68, 0x64, 0x99, 0x0d, 0xb6, 0xce,
+ 0x98, 0x06, 0xf6, 0x6b, 0x79, 0x70, 0xfd, 0xff, 0x86, 0x17, 0x18, 0x7b, 0xb9, 0xff, 0xfd, 0xff,
+ 0x5a, 0xe4, 0xdf, 0x3e, 0xdb, 0xd5, 0xd3, 0x5e, 0x5b, 0x4f, 0x09, 0x02, 0x0d, 0xb0, 0x3e, 0xab,
+ 0x1e, 0x03, 0x1d, 0xda, 0x2f, 0xbe, 0x03, 0xd1, 0x79, 0x21, 0x70, 0xa0, 0xf3, 0x00, 0x9c, 0xee,
+ },
+ },
+ {
+ "CTR-AES192",
+ commonKey192,
+ commonCounter,
+ commonInput,
+ []byte{
+ 0x1a, 0xbc, 0x93, 0x24, 0x17, 0x52, 0x1c, 0xa2, 0x4f, 0x2b, 0x04, 0x59, 0xfe, 0x7e, 0x6e, 0x0b,
+ 0x09, 0x03, 0x39, 0xec, 0x0a, 0xa6, 0xfa, 0xef, 0xd5, 0xcc, 0xc2, 0xc6, 0xf4, 0xce, 0x8e, 0x94,
+ 0x1e, 0x36, 0xb2, 0x6b, 0xd1, 0xeb, 0xc6, 0x70, 0xd1, 0xbd, 0x1d, 0x66, 0x56, 0x20, 0xab, 0xf7,
+ 0x4f, 0x78, 0xa7, 0xf6, 0xd2, 0x98, 0x09, 0x58, 0x5a, 0x97, 0xda, 0xec, 0x58, 0xc6, 0xb0, 0x50,
+ },
+ },
+ {
+ "CTR-AES256",
+ commonKey256,
+ commonCounter,
+ commonInput,
+ []byte{
+ 0x60, 0x1e, 0xc3, 0x13, 0x77, 0x57, 0x89, 0xa5, 0xb7, 0xa7, 0xf5, 0x04, 0xbb, 0xf3, 0xd2, 0x28,
+ 0xf4, 0x43, 0xe3, 0xca, 0x4d, 0x62, 0xb5, 0x9a, 0xca, 0x84, 0xe9, 0x90, 0xca, 0xca, 0xf5, 0xc5,
+ 0x2b, 0x09, 0x30, 0xda, 0xa2, 0x3d, 0xe9, 0x4c, 0xe8, 0x70, 0x17, 0xba, 0x2d, 0x84, 0x98, 0x8d,
+ 0xdf, 0xc9, 0xc5, 0x8d, 0xb6, 0x7a, 0xad, 0xa6, 0x13, 0xc2, 0xdd, 0x08, 0x45, 0x79, 0x41, 0xa6,
+ },
+ },
+}
+
+func TestCTR_AES(t *testing.T) {
+ for _, tt := range ctrAESTests {
+ test := tt.name
+
+ c, err := aes.NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+ continue
+ }
+
+ for j := 0; j <= 5; j += 5 {
+ in := tt.in[0 : len(tt.in)-j]
+ ctr := cipher.NewCTR(c, tt.iv)
+ encrypted := make([]byte, len(in))
+ ctr.XORKeyStream(encrypted, in)
+ if out := tt.out[0:len(in)]; !bytes.Equal(out, encrypted) {
+ t.Errorf("%s/%d: CTR\ninpt %x\nhave %x\nwant %x", test, len(in), in, encrypted, out)
+ }
+ }
+
+ for j := 0; j <= 7; j += 7 {
+ in := tt.out[0 : len(tt.out)-j]
+ ctr := cipher.NewCTR(c, tt.iv)
+ plain := make([]byte, len(in))
+ ctr.XORKeyStream(plain, in)
+ if out := tt.in[0:len(in)]; !bytes.Equal(out, plain) {
+ t.Errorf("%s/%d: CTRReader\nhave %x\nwant %x", test, len(out), plain, out)
+ }
+ }
+
+ if t.Failed() {
+ break
+ }
+ }
+}
diff --git a/src/crypto/cipher/ctr_test.go b/src/crypto/cipher/ctr_test.go
new file mode 100644
index 0000000..e5cce57
--- /dev/null
+++ b/src/crypto/cipher/ctr_test.go
@@ -0,0 +1,55 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher_test
+
+import (
+ "bytes"
+ "crypto/cipher"
+ "testing"
+)
+
+type noopBlock int
+
+func (b noopBlock) BlockSize() int { return int(b) }
+func (noopBlock) Encrypt(dst, src []byte) { copy(dst, src) }
+func (noopBlock) Decrypt(dst, src []byte) { copy(dst, src) }
+
+func inc(b []byte) {
+ for i := len(b) - 1; i >= 0; i++ {
+ b[i]++
+ if b[i] != 0 {
+ break
+ }
+ }
+}
+
+func xor(a, b []byte) {
+ for i := range a {
+ a[i] ^= b[i]
+ }
+}
+
+func TestCTR(t *testing.T) {
+ for size := 64; size <= 1024; size *= 2 {
+ iv := make([]byte, size)
+ ctr := cipher.NewCTR(noopBlock(size), iv)
+ src := make([]byte, 1024)
+ for i := range src {
+ src[i] = 0xff
+ }
+ want := make([]byte, 1024)
+ copy(want, src)
+ counter := make([]byte, size)
+ for i := 1; i < len(want)/size; i++ {
+ inc(counter)
+ xor(want[i*size:(i+1)*size], counter)
+ }
+ dst := make([]byte, 1024)
+ ctr.XORKeyStream(dst, src)
+ if !bytes.Equal(dst, want) {
+ t.Errorf("for size %d\nhave %x\nwant %x", size, dst, want)
+ }
+ }
+}
diff --git a/src/crypto/cipher/example_test.go b/src/crypto/cipher/example_test.go
new file mode 100644
index 0000000..9c32d6a
--- /dev/null
+++ b/src/crypto/cipher/example_test.go
@@ -0,0 +1,363 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher_test
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/rand"
+ "encoding/hex"
+ "fmt"
+ "io"
+ "os"
+)
+
+func ExampleNewGCM_encrypt() {
+ // Load your secret key from a safe place and reuse it across multiple
+ // Seal/Open calls. (Obviously don't use this example key for anything
+ // real.) If you want to convert a passphrase to a key, use a suitable
+ // package like bcrypt or scrypt.
+ // When decoded the key should be 16 bytes (AES-128) or 32 (AES-256).
+ key, _ := hex.DecodeString("6368616e676520746869732070617373776f726420746f206120736563726574")
+ plaintext := []byte("exampleplaintext")
+
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ panic(err.Error())
+ }
+
+ // Never use more than 2^32 random nonces with a given key because of the risk of a repeat.
+ nonce := make([]byte, 12)
+ if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
+ panic(err.Error())
+ }
+
+ aesgcm, err := cipher.NewGCM(block)
+ if err != nil {
+ panic(err.Error())
+ }
+
+ ciphertext := aesgcm.Seal(nil, nonce, plaintext, nil)
+ fmt.Printf("%x\n", ciphertext)
+}
+
+func ExampleNewGCM_decrypt() {
+ // Load your secret key from a safe place and reuse it across multiple
+ // Seal/Open calls. (Obviously don't use this example key for anything
+ // real.) If you want to convert a passphrase to a key, use a suitable
+ // package like bcrypt or scrypt.
+ // When decoded the key should be 16 bytes (AES-128) or 32 (AES-256).
+ key, _ := hex.DecodeString("6368616e676520746869732070617373776f726420746f206120736563726574")
+ ciphertext, _ := hex.DecodeString("c3aaa29f002ca75870806e44086700f62ce4d43e902b3888e23ceff797a7a471")
+ nonce, _ := hex.DecodeString("64a9433eae7ccceee2fc0eda")
+
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ panic(err.Error())
+ }
+
+ aesgcm, err := cipher.NewGCM(block)
+ if err != nil {
+ panic(err.Error())
+ }
+
+ plaintext, err := aesgcm.Open(nil, nonce, ciphertext, nil)
+ if err != nil {
+ panic(err.Error())
+ }
+
+ fmt.Printf("%s\n", plaintext)
+ // Output: exampleplaintext
+}
+
+func ExampleNewCBCDecrypter() {
+ // Load your secret key from a safe place and reuse it across multiple
+ // NewCipher calls. (Obviously don't use this example key for anything
+ // real.) If you want to convert a passphrase to a key, use a suitable
+ // package like bcrypt or scrypt.
+ key, _ := hex.DecodeString("6368616e676520746869732070617373")
+ ciphertext, _ := hex.DecodeString("73c86d43a9d700a253a96c85b0f6b03ac9792e0e757f869cca306bd3cba1c62b")
+
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ panic(err)
+ }
+
+ // The IV needs to be unique, but not secure. Therefore it's common to
+ // include it at the beginning of the ciphertext.
+ if len(ciphertext) < aes.BlockSize {
+ panic("ciphertext too short")
+ }
+ iv := ciphertext[:aes.BlockSize]
+ ciphertext = ciphertext[aes.BlockSize:]
+
+ // CBC mode always works in whole blocks.
+ if len(ciphertext)%aes.BlockSize != 0 {
+ panic("ciphertext is not a multiple of the block size")
+ }
+
+ mode := cipher.NewCBCDecrypter(block, iv)
+
+ // CryptBlocks can work in-place if the two arguments are the same.
+ mode.CryptBlocks(ciphertext, ciphertext)
+
+ // If the original plaintext lengths are not a multiple of the block
+ // size, padding would have to be added when encrypting, which would be
+ // removed at this point. For an example, see
+ // https://tools.ietf.org/html/rfc5246#section-6.2.3.2. However, it's
+ // critical to note that ciphertexts must be authenticated (i.e. by
+ // using crypto/hmac) before being decrypted in order to avoid creating
+ // a padding oracle.
+
+ fmt.Printf("%s\n", ciphertext)
+ // Output: exampleplaintext
+}
+
+func ExampleNewCBCEncrypter() {
+ // Load your secret key from a safe place and reuse it across multiple
+ // NewCipher calls. (Obviously don't use this example key for anything
+ // real.) If you want to convert a passphrase to a key, use a suitable
+ // package like bcrypt or scrypt.
+ key, _ := hex.DecodeString("6368616e676520746869732070617373")
+ plaintext := []byte("exampleplaintext")
+
+ // CBC mode works on blocks so plaintexts may need to be padded to the
+ // next whole block. For an example of such padding, see
+ // https://tools.ietf.org/html/rfc5246#section-6.2.3.2. Here we'll
+ // assume that the plaintext is already of the correct length.
+ if len(plaintext)%aes.BlockSize != 0 {
+ panic("plaintext is not a multiple of the block size")
+ }
+
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ panic(err)
+ }
+
+ // The IV needs to be unique, but not secure. Therefore it's common to
+ // include it at the beginning of the ciphertext.
+ ciphertext := make([]byte, aes.BlockSize+len(plaintext))
+ iv := ciphertext[:aes.BlockSize]
+ if _, err := io.ReadFull(rand.Reader, iv); err != nil {
+ panic(err)
+ }
+
+ mode := cipher.NewCBCEncrypter(block, iv)
+ mode.CryptBlocks(ciphertext[aes.BlockSize:], plaintext)
+
+ // It's important to remember that ciphertexts must be authenticated
+ // (i.e. by using crypto/hmac) as well as being encrypted in order to
+ // be secure.
+
+ fmt.Printf("%x\n", ciphertext)
+}
+
+func ExampleNewCFBDecrypter() {
+ // Load your secret key from a safe place and reuse it across multiple
+ // NewCipher calls. (Obviously don't use this example key for anything
+ // real.) If you want to convert a passphrase to a key, use a suitable
+ // package like bcrypt or scrypt.
+ key, _ := hex.DecodeString("6368616e676520746869732070617373")
+ ciphertext, _ := hex.DecodeString("7dd015f06bec7f1b8f6559dad89f4131da62261786845100056b353194ad")
+
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ panic(err)
+ }
+
+ // The IV needs to be unique, but not secure. Therefore it's common to
+ // include it at the beginning of the ciphertext.
+ if len(ciphertext) < aes.BlockSize {
+ panic("ciphertext too short")
+ }
+ iv := ciphertext[:aes.BlockSize]
+ ciphertext = ciphertext[aes.BlockSize:]
+
+ stream := cipher.NewCFBDecrypter(block, iv)
+
+ // XORKeyStream can work in-place if the two arguments are the same.
+ stream.XORKeyStream(ciphertext, ciphertext)
+ fmt.Printf("%s", ciphertext)
+ // Output: some plaintext
+}
+
+func ExampleNewCFBEncrypter() {
+ // Load your secret key from a safe place and reuse it across multiple
+ // NewCipher calls. (Obviously don't use this example key for anything
+ // real.) If you want to convert a passphrase to a key, use a suitable
+ // package like bcrypt or scrypt.
+ key, _ := hex.DecodeString("6368616e676520746869732070617373")
+ plaintext := []byte("some plaintext")
+
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ panic(err)
+ }
+
+ // The IV needs to be unique, but not secure. Therefore it's common to
+ // include it at the beginning of the ciphertext.
+ ciphertext := make([]byte, aes.BlockSize+len(plaintext))
+ iv := ciphertext[:aes.BlockSize]
+ if _, err := io.ReadFull(rand.Reader, iv); err != nil {
+ panic(err)
+ }
+
+ stream := cipher.NewCFBEncrypter(block, iv)
+ stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
+
+ // It's important to remember that ciphertexts must be authenticated
+ // (i.e. by using crypto/hmac) as well as being encrypted in order to
+ // be secure.
+ fmt.Printf("%x\n", ciphertext)
+}
+
+func ExampleNewCTR() {
+ // Load your secret key from a safe place and reuse it across multiple
+ // NewCipher calls. (Obviously don't use this example key for anything
+ // real.) If you want to convert a passphrase to a key, use a suitable
+ // package like bcrypt or scrypt.
+ key, _ := hex.DecodeString("6368616e676520746869732070617373")
+ plaintext := []byte("some plaintext")
+
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ panic(err)
+ }
+
+ // The IV needs to be unique, but not secure. Therefore it's common to
+ // include it at the beginning of the ciphertext.
+ ciphertext := make([]byte, aes.BlockSize+len(plaintext))
+ iv := ciphertext[:aes.BlockSize]
+ if _, err := io.ReadFull(rand.Reader, iv); err != nil {
+ panic(err)
+ }
+
+ stream := cipher.NewCTR(block, iv)
+ stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
+
+ // It's important to remember that ciphertexts must be authenticated
+ // (i.e. by using crypto/hmac) as well as being encrypted in order to
+ // be secure.
+
+ // CTR mode is the same for both encryption and decryption, so we can
+ // also decrypt that ciphertext with NewCTR.
+
+ plaintext2 := make([]byte, len(plaintext))
+ stream = cipher.NewCTR(block, iv)
+ stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:])
+
+ fmt.Printf("%s\n", plaintext2)
+ // Output: some plaintext
+}
+
+func ExampleNewOFB() {
+ // Load your secret key from a safe place and reuse it across multiple
+ // NewCipher calls. (Obviously don't use this example key for anything
+ // real.) If you want to convert a passphrase to a key, use a suitable
+ // package like bcrypt or scrypt.
+ key, _ := hex.DecodeString("6368616e676520746869732070617373")
+ plaintext := []byte("some plaintext")
+
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ panic(err)
+ }
+
+ // The IV needs to be unique, but not secure. Therefore it's common to
+ // include it at the beginning of the ciphertext.
+ ciphertext := make([]byte, aes.BlockSize+len(plaintext))
+ iv := ciphertext[:aes.BlockSize]
+ if _, err := io.ReadFull(rand.Reader, iv); err != nil {
+ panic(err)
+ }
+
+ stream := cipher.NewOFB(block, iv)
+ stream.XORKeyStream(ciphertext[aes.BlockSize:], plaintext)
+
+ // It's important to remember that ciphertexts must be authenticated
+ // (i.e. by using crypto/hmac) as well as being encrypted in order to
+ // be secure.
+
+ // OFB mode is the same for both encryption and decryption, so we can
+ // also decrypt that ciphertext with NewOFB.
+
+ plaintext2 := make([]byte, len(plaintext))
+ stream = cipher.NewOFB(block, iv)
+ stream.XORKeyStream(plaintext2, ciphertext[aes.BlockSize:])
+
+ fmt.Printf("%s\n", plaintext2)
+ // Output: some plaintext
+}
+
+func ExampleStreamReader() {
+ // Load your secret key from a safe place and reuse it across multiple
+ // NewCipher calls. (Obviously don't use this example key for anything
+ // real.) If you want to convert a passphrase to a key, use a suitable
+ // package like bcrypt or scrypt.
+ key, _ := hex.DecodeString("6368616e676520746869732070617373")
+
+ encrypted, _ := hex.DecodeString("cf0495cc6f75dafc23948538e79904a9")
+ bReader := bytes.NewReader(encrypted)
+
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ panic(err)
+ }
+
+ // If the key is unique for each ciphertext, then it's ok to use a zero
+ // IV.
+ var iv [aes.BlockSize]byte
+ stream := cipher.NewOFB(block, iv[:])
+
+ reader := &cipher.StreamReader{S: stream, R: bReader}
+ // Copy the input to the output stream, decrypting as we go.
+ if _, err := io.Copy(os.Stdout, reader); err != nil {
+ panic(err)
+ }
+
+ // Note that this example is simplistic in that it omits any
+ // authentication of the encrypted data. If you were actually to use
+ // StreamReader in this manner, an attacker could flip arbitrary bits in
+ // the output.
+
+ // Output: some secret text
+}
+
+func ExampleStreamWriter() {
+ // Load your secret key from a safe place and reuse it across multiple
+ // NewCipher calls. (Obviously don't use this example key for anything
+ // real.) If you want to convert a passphrase to a key, use a suitable
+ // package like bcrypt or scrypt.
+ key, _ := hex.DecodeString("6368616e676520746869732070617373")
+
+ bReader := bytes.NewReader([]byte("some secret text"))
+
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ panic(err)
+ }
+
+ // If the key is unique for each ciphertext, then it's ok to use a zero
+ // IV.
+ var iv [aes.BlockSize]byte
+ stream := cipher.NewOFB(block, iv[:])
+
+ var out bytes.Buffer
+
+ writer := &cipher.StreamWriter{S: stream, W: &out}
+ // Copy the input to the output buffer, encrypting as we go.
+ if _, err := io.Copy(writer, bReader); err != nil {
+ panic(err)
+ }
+
+ // Note that this example is simplistic in that it omits any
+ // authentication of the encrypted data. If you were actually to use
+ // StreamReader in this manner, an attacker could flip arbitrary bits in
+ // the decrypted result.
+
+ fmt.Printf("%x\n", out.Bytes())
+ // Output: cf0495cc6f75dafc23948538e79904a9
+}
diff --git a/src/crypto/cipher/export_test.go b/src/crypto/cipher/export_test.go
new file mode 100644
index 0000000..5ecd67b
--- /dev/null
+++ b/src/crypto/cipher/export_test.go
@@ -0,0 +1,9 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher
+
+// Export internal functions for testing.
+var NewCBCGenericEncrypter = newCBCGenericEncrypter
+var NewCBCGenericDecrypter = newCBCGenericDecrypter
diff --git a/src/crypto/cipher/fuzz_test.go b/src/crypto/cipher/fuzz_test.go
new file mode 100644
index 0000000..ffceeef
--- /dev/null
+++ b/src/crypto/cipher/fuzz_test.go
@@ -0,0 +1,103 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build ppc64le
+
+package cipher_test
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/rand"
+ "testing"
+ "time"
+)
+
+var cbcAESFuzzTests = []struct {
+ name string
+ key []byte
+}{
+ {
+ "CBC-AES128",
+ commonKey128,
+ },
+ {
+ "CBC-AES192",
+ commonKey192,
+ },
+ {
+ "CBC-AES256",
+ commonKey256,
+ },
+}
+
+var timeout *time.Timer
+
+const datalen = 1024
+
+func TestFuzz(t *testing.T) {
+
+ for _, ft := range cbcAESFuzzTests {
+ c, _ := aes.NewCipher(ft.key)
+
+ cbcAsm := cipher.NewCBCEncrypter(c, commonIV)
+ cbcGeneric := cipher.NewCBCGenericEncrypter(c, commonIV)
+
+ if testing.Short() {
+ timeout = time.NewTimer(10 * time.Millisecond)
+ } else {
+ timeout = time.NewTimer(2 * time.Second)
+ }
+
+ indata := make([]byte, datalen)
+ outgeneric := make([]byte, datalen)
+ outdata := make([]byte, datalen)
+
+ fuzzencrypt:
+ for {
+ select {
+ case <-timeout.C:
+ break fuzzencrypt
+ default:
+ }
+
+ rand.Read(indata[:])
+
+ cbcGeneric.CryptBlocks(indata, outgeneric)
+ cbcAsm.CryptBlocks(indata, outdata)
+
+ if !bytes.Equal(outdata, outgeneric) {
+ t.Fatalf("AES-CBC encryption does not match reference result: %x and %x, please report this error to security@golang.org", outdata, outgeneric)
+ }
+ }
+
+ cbcAsm = cipher.NewCBCDecrypter(c, commonIV)
+ cbcGeneric = cipher.NewCBCGenericDecrypter(c, commonIV)
+
+ if testing.Short() {
+ timeout = time.NewTimer(10 * time.Millisecond)
+ } else {
+ timeout = time.NewTimer(2 * time.Second)
+ }
+
+ fuzzdecrypt:
+ for {
+ select {
+ case <-timeout.C:
+ break fuzzdecrypt
+ default:
+ }
+
+ rand.Read(indata[:])
+
+ cbcGeneric.CryptBlocks(indata, outgeneric)
+ cbcAsm.CryptBlocks(indata, outdata)
+
+ if !bytes.Equal(outdata, outgeneric) {
+ t.Fatalf("AES-CBC decryption does not match reference result: %x and %x, please report this error to security@golang.org", outdata, outgeneric)
+ }
+ }
+ }
+}
diff --git a/src/crypto/cipher/gcm.go b/src/crypto/cipher/gcm.go
new file mode 100644
index 0000000..477d26a
--- /dev/null
+++ b/src/crypto/cipher/gcm.go
@@ -0,0 +1,427 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher
+
+import (
+ "crypto/internal/alias"
+ "crypto/subtle"
+ "encoding/binary"
+ "errors"
+)
+
+// AEAD is a cipher mode providing authenticated encryption with associated
+// data. For a description of the methodology, see
+// https://en.wikipedia.org/wiki/Authenticated_encryption.
+type AEAD interface {
+ // NonceSize returns the size of the nonce that must be passed to Seal
+ // and Open.
+ NonceSize() int
+
+ // Overhead returns the maximum difference between the lengths of a
+ // plaintext and its ciphertext.
+ Overhead() int
+
+ // Seal encrypts and authenticates plaintext, authenticates the
+ // additional data and appends the result to dst, returning the updated
+ // slice. The nonce must be NonceSize() bytes long and unique for all
+ // time, for a given key.
+ //
+ // To reuse plaintext's storage for the encrypted output, use plaintext[:0]
+ // as dst. Otherwise, the remaining capacity of dst must not overlap plaintext.
+ Seal(dst, nonce, plaintext, additionalData []byte) []byte
+
+ // Open decrypts and authenticates ciphertext, authenticates the
+ // additional data and, if successful, appends the resulting plaintext
+ // to dst, returning the updated slice. The nonce must be NonceSize()
+ // bytes long and both it and the additional data must match the
+ // value passed to Seal.
+ //
+ // To reuse ciphertext's storage for the decrypted output, use ciphertext[:0]
+ // as dst. Otherwise, the remaining capacity of dst must not overlap plaintext.
+ //
+ // Even if the function fails, the contents of dst, up to its capacity,
+ // may be overwritten.
+ Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error)
+}
+
+// gcmAble is an interface implemented by ciphers that have a specific optimized
+// implementation of GCM, like crypto/aes. NewGCM will check for this interface
+// and return the specific AEAD if found.
+type gcmAble interface {
+ NewGCM(nonceSize, tagSize int) (AEAD, error)
+}
+
+// gcmFieldElement represents a value in GF(2¹²⁸). In order to reflect the GCM
+// standard and make binary.BigEndian suitable for marshaling these values, the
+// bits are stored in big endian order. For example:
+//
+// the coefficient of x⁰ can be obtained by v.low >> 63.
+// the coefficient of x⁶³ can be obtained by v.low & 1.
+// the coefficient of x⁶⁴ can be obtained by v.high >> 63.
+// the coefficient of x¹²⁷ can be obtained by v.high & 1.
+type gcmFieldElement struct {
+ low, high uint64
+}
+
+// gcm represents a Galois Counter Mode with a specific key. See
+// https://csrc.nist.gov/groups/ST/toolkit/BCM/documents/proposedmodes/gcm/gcm-revised-spec.pdf
+type gcm struct {
+ cipher Block
+ nonceSize int
+ tagSize int
+ // productTable contains the first sixteen powers of the key, H.
+ // However, they are in bit reversed order. See NewGCMWithNonceSize.
+ productTable [16]gcmFieldElement
+}
+
+// NewGCM returns the given 128-bit, block cipher wrapped in Galois Counter Mode
+// with the standard nonce length.
+//
+// In general, the GHASH operation performed by this implementation of GCM is not constant-time.
+// An exception is when the underlying Block was created by aes.NewCipher
+// on systems with hardware support for AES. See the crypto/aes package documentation for details.
+func NewGCM(cipher Block) (AEAD, error) {
+ return newGCMWithNonceAndTagSize(cipher, gcmStandardNonceSize, gcmTagSize)
+}
+
+// NewGCMWithNonceSize returns the given 128-bit, block cipher wrapped in Galois
+// Counter Mode, which accepts nonces of the given length. The length must not
+// be zero.
+//
+// Only use this function if you require compatibility with an existing
+// cryptosystem that uses non-standard nonce lengths. All other users should use
+// NewGCM, which is faster and more resistant to misuse.
+func NewGCMWithNonceSize(cipher Block, size int) (AEAD, error) {
+ return newGCMWithNonceAndTagSize(cipher, size, gcmTagSize)
+}
+
+// NewGCMWithTagSize returns the given 128-bit, block cipher wrapped in Galois
+// Counter Mode, which generates tags with the given length.
+//
+// Tag sizes between 12 and 16 bytes are allowed.
+//
+// Only use this function if you require compatibility with an existing
+// cryptosystem that uses non-standard tag lengths. All other users should use
+// NewGCM, which is more resistant to misuse.
+func NewGCMWithTagSize(cipher Block, tagSize int) (AEAD, error) {
+ return newGCMWithNonceAndTagSize(cipher, gcmStandardNonceSize, tagSize)
+}
+
+func newGCMWithNonceAndTagSize(cipher Block, nonceSize, tagSize int) (AEAD, error) {
+ if tagSize < gcmMinimumTagSize || tagSize > gcmBlockSize {
+ return nil, errors.New("cipher: incorrect tag size given to GCM")
+ }
+
+ if nonceSize <= 0 {
+ return nil, errors.New("cipher: the nonce can't have zero length, or the security of the key will be immediately compromised")
+ }
+
+ if cipher, ok := cipher.(gcmAble); ok {
+ return cipher.NewGCM(nonceSize, tagSize)
+ }
+
+ if cipher.BlockSize() != gcmBlockSize {
+ return nil, errors.New("cipher: NewGCM requires 128-bit block cipher")
+ }
+
+ var key [gcmBlockSize]byte
+ cipher.Encrypt(key[:], key[:])
+
+ g := &gcm{cipher: cipher, nonceSize: nonceSize, tagSize: tagSize}
+
+ // We precompute 16 multiples of |key|. However, when we do lookups
+ // into this table we'll be using bits from a field element and
+ // therefore the bits will be in the reverse order. So normally one
+ // would expect, say, 4*key to be in index 4 of the table but due to
+ // this bit ordering it will actually be in index 0010 (base 2) = 2.
+ x := gcmFieldElement{
+ binary.BigEndian.Uint64(key[:8]),
+ binary.BigEndian.Uint64(key[8:]),
+ }
+ g.productTable[reverseBits(1)] = x
+
+ for i := 2; i < 16; i += 2 {
+ g.productTable[reverseBits(i)] = gcmDouble(&g.productTable[reverseBits(i/2)])
+ g.productTable[reverseBits(i+1)] = gcmAdd(&g.productTable[reverseBits(i)], &x)
+ }
+
+ return g, nil
+}
+
+const (
+ gcmBlockSize = 16
+ gcmTagSize = 16
+ gcmMinimumTagSize = 12 // NIST SP 800-38D recommends tags with 12 or more bytes.
+ gcmStandardNonceSize = 12
+)
+
+func (g *gcm) NonceSize() int {
+ return g.nonceSize
+}
+
+func (g *gcm) Overhead() int {
+ return g.tagSize
+}
+
+func (g *gcm) Seal(dst, nonce, plaintext, data []byte) []byte {
+ if len(nonce) != g.nonceSize {
+ panic("crypto/cipher: incorrect nonce length given to GCM")
+ }
+ if uint64(len(plaintext)) > ((1<<32)-2)*uint64(g.cipher.BlockSize()) {
+ panic("crypto/cipher: message too large for GCM")
+ }
+
+ ret, out := sliceForAppend(dst, len(plaintext)+g.tagSize)
+ if alias.InexactOverlap(out, plaintext) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+
+ var counter, tagMask [gcmBlockSize]byte
+ g.deriveCounter(&counter, nonce)
+
+ g.cipher.Encrypt(tagMask[:], counter[:])
+ gcmInc32(&counter)
+
+ g.counterCrypt(out, plaintext, &counter)
+
+ var tag [gcmTagSize]byte
+ g.auth(tag[:], out[:len(plaintext)], data, &tagMask)
+ copy(out[len(plaintext):], tag[:])
+
+ return ret
+}
+
+var errOpen = errors.New("cipher: message authentication failed")
+
+func (g *gcm) Open(dst, nonce, ciphertext, data []byte) ([]byte, error) {
+ if len(nonce) != g.nonceSize {
+ panic("crypto/cipher: incorrect nonce length given to GCM")
+ }
+ // Sanity check to prevent the authentication from always succeeding if an implementation
+ // leaves tagSize uninitialized, for example.
+ if g.tagSize < gcmMinimumTagSize {
+ panic("crypto/cipher: incorrect GCM tag size")
+ }
+
+ if len(ciphertext) < g.tagSize {
+ return nil, errOpen
+ }
+ if uint64(len(ciphertext)) > ((1<<32)-2)*uint64(g.cipher.BlockSize())+uint64(g.tagSize) {
+ return nil, errOpen
+ }
+
+ tag := ciphertext[len(ciphertext)-g.tagSize:]
+ ciphertext = ciphertext[:len(ciphertext)-g.tagSize]
+
+ var counter, tagMask [gcmBlockSize]byte
+ g.deriveCounter(&counter, nonce)
+
+ g.cipher.Encrypt(tagMask[:], counter[:])
+ gcmInc32(&counter)
+
+ var expectedTag [gcmTagSize]byte
+ g.auth(expectedTag[:], ciphertext, data, &tagMask)
+
+ ret, out := sliceForAppend(dst, len(ciphertext))
+ if alias.InexactOverlap(out, ciphertext) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+
+ if subtle.ConstantTimeCompare(expectedTag[:g.tagSize], tag) != 1 {
+ // The AESNI code decrypts and authenticates concurrently, and
+ // so overwrites dst in the event of a tag mismatch. That
+ // behavior is mimicked here in order to be consistent across
+ // platforms.
+ for i := range out {
+ out[i] = 0
+ }
+ return nil, errOpen
+ }
+
+ g.counterCrypt(out, ciphertext, &counter)
+
+ return ret, nil
+}
+
+// reverseBits reverses the order of the bits of 4-bit number in i.
+func reverseBits(i int) int {
+ i = ((i << 2) & 0xc) | ((i >> 2) & 0x3)
+ i = ((i << 1) & 0xa) | ((i >> 1) & 0x5)
+ return i
+}
+
+// gcmAdd adds two elements of GF(2¹²⁸) and returns the sum.
+func gcmAdd(x, y *gcmFieldElement) gcmFieldElement {
+ // Addition in a characteristic 2 field is just XOR.
+ return gcmFieldElement{x.low ^ y.low, x.high ^ y.high}
+}
+
+// gcmDouble returns the result of doubling an element of GF(2¹²⁸).
+func gcmDouble(x *gcmFieldElement) (double gcmFieldElement) {
+ msbSet := x.high&1 == 1
+
+ // Because of the bit-ordering, doubling is actually a right shift.
+ double.high = x.high >> 1
+ double.high |= x.low << 63
+ double.low = x.low >> 1
+
+ // If the most-significant bit was set before shifting then it,
+ // conceptually, becomes a term of x^128. This is greater than the
+ // irreducible polynomial so the result has to be reduced. The
+ // irreducible polynomial is 1+x+x^2+x^7+x^128. We can subtract that to
+ // eliminate the term at x^128 which also means subtracting the other
+ // four terms. In characteristic 2 fields, subtraction == addition ==
+ // XOR.
+ if msbSet {
+ double.low ^= 0xe100000000000000
+ }
+
+ return
+}
+
+var gcmReductionTable = []uint16{
+ 0x0000, 0x1c20, 0x3840, 0x2460, 0x7080, 0x6ca0, 0x48c0, 0x54e0,
+ 0xe100, 0xfd20, 0xd940, 0xc560, 0x9180, 0x8da0, 0xa9c0, 0xb5e0,
+}
+
+// mul sets y to y*H, where H is the GCM key, fixed during NewGCMWithNonceSize.
+func (g *gcm) mul(y *gcmFieldElement) {
+ var z gcmFieldElement
+
+ for i := 0; i < 2; i++ {
+ word := y.high
+ if i == 1 {
+ word = y.low
+ }
+
+ // Multiplication works by multiplying z by 16 and adding in
+ // one of the precomputed multiples of H.
+ for j := 0; j < 64; j += 4 {
+ msw := z.high & 0xf
+ z.high >>= 4
+ z.high |= z.low << 60
+ z.low >>= 4
+ z.low ^= uint64(gcmReductionTable[msw]) << 48
+
+ // the values in |table| are ordered for
+ // little-endian bit positions. See the comment
+ // in NewGCMWithNonceSize.
+ t := &g.productTable[word&0xf]
+
+ z.low ^= t.low
+ z.high ^= t.high
+ word >>= 4
+ }
+ }
+
+ *y = z
+}
+
+// updateBlocks extends y with more polynomial terms from blocks, based on
+// Horner's rule. There must be a multiple of gcmBlockSize bytes in blocks.
+func (g *gcm) updateBlocks(y *gcmFieldElement, blocks []byte) {
+ for len(blocks) > 0 {
+ y.low ^= binary.BigEndian.Uint64(blocks)
+ y.high ^= binary.BigEndian.Uint64(blocks[8:])
+ g.mul(y)
+ blocks = blocks[gcmBlockSize:]
+ }
+}
+
+// update extends y with more polynomial terms from data. If data is not a
+// multiple of gcmBlockSize bytes long then the remainder is zero padded.
+func (g *gcm) update(y *gcmFieldElement, data []byte) {
+ fullBlocks := (len(data) >> 4) << 4
+ g.updateBlocks(y, data[:fullBlocks])
+
+ if len(data) != fullBlocks {
+ var partialBlock [gcmBlockSize]byte
+ copy(partialBlock[:], data[fullBlocks:])
+ g.updateBlocks(y, partialBlock[:])
+ }
+}
+
+// gcmInc32 treats the final four bytes of counterBlock as a big-endian value
+// and increments it.
+func gcmInc32(counterBlock *[16]byte) {
+ ctr := counterBlock[len(counterBlock)-4:]
+ binary.BigEndian.PutUint32(ctr, binary.BigEndian.Uint32(ctr)+1)
+}
+
+// sliceForAppend takes a slice and a requested number of bytes. It returns a
+// slice with the contents of the given slice followed by that many bytes and a
+// second slice that aliases into it and contains only the extra bytes. If the
+// original slice has sufficient capacity then no allocation is performed.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+ if total := len(in) + n; cap(in) >= total {
+ head = in[:total]
+ } else {
+ head = make([]byte, total)
+ copy(head, in)
+ }
+ tail = head[len(in):]
+ return
+}
+
+// counterCrypt crypts in to out using g.cipher in counter mode.
+func (g *gcm) counterCrypt(out, in []byte, counter *[gcmBlockSize]byte) {
+ var mask [gcmBlockSize]byte
+
+ for len(in) >= gcmBlockSize {
+ g.cipher.Encrypt(mask[:], counter[:])
+ gcmInc32(counter)
+
+ subtle.XORBytes(out, in, mask[:])
+ out = out[gcmBlockSize:]
+ in = in[gcmBlockSize:]
+ }
+
+ if len(in) > 0 {
+ g.cipher.Encrypt(mask[:], counter[:])
+ gcmInc32(counter)
+ subtle.XORBytes(out, in, mask[:])
+ }
+}
+
+// deriveCounter computes the initial GCM counter state from the given nonce.
+// See NIST SP 800-38D, section 7.1. This assumes that counter is filled with
+// zeros on entry.
+func (g *gcm) deriveCounter(counter *[gcmBlockSize]byte, nonce []byte) {
+ // GCM has two modes of operation with respect to the initial counter
+ // state: a "fast path" for 96-bit (12-byte) nonces, and a "slow path"
+ // for nonces of other lengths. For a 96-bit nonce, the nonce, along
+ // with a four-byte big-endian counter starting at one, is used
+ // directly as the starting counter. For other nonce sizes, the counter
+ // is computed by passing it through the GHASH function.
+ if len(nonce) == gcmStandardNonceSize {
+ copy(counter[:], nonce)
+ counter[gcmBlockSize-1] = 1
+ } else {
+ var y gcmFieldElement
+ g.update(&y, nonce)
+ y.high ^= uint64(len(nonce)) * 8
+ g.mul(&y)
+ binary.BigEndian.PutUint64(counter[:8], y.low)
+ binary.BigEndian.PutUint64(counter[8:], y.high)
+ }
+}
+
+// auth calculates GHASH(ciphertext, additionalData), masks the result with
+// tagMask and writes the result to out.
+func (g *gcm) auth(out, ciphertext, additionalData []byte, tagMask *[gcmTagSize]byte) {
+ var y gcmFieldElement
+ g.update(&y, additionalData)
+ g.update(&y, ciphertext)
+
+ y.low ^= uint64(len(additionalData)) * 8
+ y.high ^= uint64(len(ciphertext)) * 8
+
+ g.mul(&y)
+
+ binary.BigEndian.PutUint64(out, y.low)
+ binary.BigEndian.PutUint64(out[8:], y.high)
+
+ subtle.XORBytes(out, out, tagMask[:])
+}
diff --git a/src/crypto/cipher/gcm_test.go b/src/crypto/cipher/gcm_test.go
new file mode 100644
index 0000000..0d53e47
--- /dev/null
+++ b/src/crypto/cipher/gcm_test.go
@@ -0,0 +1,511 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher_test
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/rand"
+ "encoding/hex"
+ "errors"
+ "io"
+ "reflect"
+ "testing"
+)
+
+var aesGCMTests = []struct {
+ key, nonce, plaintext, ad, result string
+}{
+ {
+ "11754cd72aec309bf52f7687212e8957",
+ "3c819d9a9bed087615030b65",
+ "",
+ "",
+ "250327c674aaf477aef2675748cf6971",
+ },
+ {
+ "ca47248ac0b6f8372a97ac43508308ed",
+ "ffd2b598feabc9019262d2be",
+ "",
+ "",
+ "60d20404af527d248d893ae495707d1a",
+ },
+ {
+ "fbe3467cc254f81be8e78d765a2e6333",
+ "c6697351ff4aec29cdbaabf2",
+ "",
+ "67",
+ "3659cdc25288bf499ac736c03bfc1159",
+ },
+ {
+ "8a7f9d80d08ad0bd5a20fb689c88f9fc",
+ "88b7b27d800937fda4f47301",
+ "",
+ "50edd0503e0d7b8c91608eb5a1",
+ "ed6f65322a4740011f91d2aae22dd44e",
+ },
+ {
+ "051758e95ed4abb2cdc69bb454110e82",
+ "c99a66320db73158a35a255d",
+ "",
+ "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339f",
+ "6ce77f1a5616c505b6aec09420234036",
+ },
+ {
+ "77be63708971c4e240d1cb79e8d77feb",
+ "e0e00f19fed7ba0136a797f3",
+ "",
+ "7a43ec1d9c0a5a78a0b16533a6213cab",
+ "209fcc8d3675ed938e9c7166709dd946",
+ },
+ {
+ "7680c5d3ca6154758e510f4d25b98820",
+ "f8f105f9c3df4965780321f8",
+ "",
+ "c94c410194c765e3dcc7964379758ed3",
+ "94dca8edfcf90bb74b153c8d48a17930",
+ },
+ {
+ "7fddb57453c241d03efbed3ac44e371c",
+ "ee283a3fc75575e33efd4887",
+ "d5de42b461646c255c87bd2962d3b9a2",
+ "",
+ "2ccda4a5415cb91e135c2a0f78c9b2fdb36d1df9b9d5e596f83e8b7f52971cb3",
+ },
+ {
+ "ab72c77b97cb5fe9a382d9fe81ffdbed",
+ "54cc7dc2c37ec006bcc6d1da",
+ "007c5e5b3e59df24a7c355584fc1518d",
+ "",
+ "0e1bde206a07a9c2c1b65300f8c649972b4401346697138c7a4891ee59867d0c",
+ },
+ {
+ "fe47fcce5fc32665d2ae399e4eec72ba",
+ "5adb9609dbaeb58cbd6e7275",
+ "7c0e88c88899a779228465074797cd4c2e1498d259b54390b85e3eef1c02df60e743f1b840382c4bccaf3bafb4ca8429bea063",
+ "88319d6e1d3ffa5f987199166c8a9b56c2aeba5a",
+ "98f4826f05a265e6dd2be82db241c0fbbbf9ffb1c173aa83964b7cf5393043736365253ddbc5db8778371495da76d269e5db3e291ef1982e4defedaa2249f898556b47",
+ },
+ {
+ "ec0c2ba17aa95cd6afffe949da9cc3a8",
+ "296bce5b50b7d66096d627ef",
+ "b85b3753535b825cbe5f632c0b843c741351f18aa484281aebec2f45bb9eea2d79d987b764b9611f6c0f8641843d5d58f3a242",
+ "f8d00f05d22bf68599bcdeb131292ad6e2df5d14",
+ "a7443d31c26bdf2a1c945e29ee4bd344a99cfaf3aa71f8b3f191f83c2adfc7a07162995506fde6309ffc19e716eddf1a828c5a890147971946b627c40016da1ecf3e77",
+ },
+ {
+ "2c1f21cf0f6fb3661943155c3e3d8492",
+ "23cb5ff362e22426984d1907",
+ "42f758836986954db44bf37c6ef5e4ac0adaf38f27252a1b82d02ea949c8a1a2dbc0d68b5615ba7c1220ff6510e259f06655d8",
+ "5d3624879d35e46849953e45a32a624d6a6c536ed9857c613b572b0333e701557a713e3f010ecdf9a6bd6c9e3e44b065208645aff4aabee611b391528514170084ccf587177f4488f33cfb5e979e42b6e1cfc0a60238982a7aec",
+ "81824f0e0d523db30d3da369fdc0d60894c7a0a20646dd015073ad2732bd989b14a222b6ad57af43e1895df9dca2a5344a62cc57a3ee28136e94c74838997ae9823f3a",
+ },
+ {
+ "d9f7d2411091f947b4d6f1e2d1f0fb2e",
+ "e1934f5db57cc983e6b180e7",
+ "73ed042327f70fe9c572a61545eda8b2a0c6e1d6c291ef19248e973aee6c312012f490c2c6f6166f4a59431e182663fcaea05a",
+ "0a8a18a7150e940c3d87b38e73baee9a5c049ee21795663e264b694a949822b639092d0e67015e86363583fcf0ca645af9f43375f05fdb4ce84f411dcbca73c2220dea03a20115d2e51398344b16bee1ed7c499b353d6c597af8",
+ "aaadbd5c92e9151ce3db7210b8714126b73e43436d242677afa50384f2149b831f1d573c7891c2a91fbc48db29967ec9542b2321b51ca862cb637cdd03b99a0f93b134",
+ },
+ {
+ "fe9bb47deb3a61e423c2231841cfd1fb",
+ "4d328eb776f500a2f7fb47aa",
+ "f1cc3818e421876bb6b8bbd6c9",
+ "",
+ "b88c5c1977b35b517b0aeae96743fd4727fe5cdb4b5b42818dea7ef8c9",
+ },
+ {
+ "6703df3701a7f54911ca72e24dca046a",
+ "12823ab601c350ea4bc2488c",
+ "793cd125b0b84a043e3ac67717",
+ "",
+ "b2051c80014f42f08735a7b0cd38e6bcd29962e5f2c13626b85a877101",
+ },
+ // These cases test non-standard nonce sizes.
+ {
+ "1672c3537afa82004c6b8a46f6f0d026",
+ "05",
+ "",
+ "",
+ "8e2ad721f9455f74d8b53d3141f27e8e",
+ },
+ {
+ "9a4fea86a621a91ab371e492457796c0",
+ "75",
+ "ca6131faf0ff210e4e693d6c31c109fc5b6f54224eb120f37de31dc59ec669b6",
+ "4f6e2585c161f05a9ae1f2f894e9f0ab52b45d0f",
+ "5698c0a384241d30004290aac56bb3ece6fe8eacc5c4be98954deb9c3ff6aebf5d50e1af100509e1fba2a5e8a0af9670",
+ },
+ {
+ "d0f1f4defa1e8c08b4b26d576392027c",
+ "42b4f01eb9f5a1ea5b1eb73b0fb0baed54f387ecaa0393c7d7dffc6af50146ecc021abf7eb9038d4303d91f8d741a11743166c0860208bcc02c6258fd9511a2fa626f96d60b72fcff773af4e88e7a923506e4916ecbd814651e9f445adef4ad6a6b6c7290cc13b956130eef5b837c939fcac0cbbcc9656cd75b13823ee5acdac",
+ "",
+ "",
+ "7ab49b57ddf5f62c427950111c5c4f0d",
+ },
+ {
+ "4a0c00a3d284dea9d4bf8b8dde86685e",
+ "f8cbe82588e784bcacbe092cd9089b51e01527297f635bf294b3aa787d91057ef23869789698ac960707857f163ecb242135a228ad93964f5dc4a4d7f88fd7b3b07dd0a5b37f9768fb05a523639f108c34c661498a56879e501a2321c8a4a94d7e1b89db255ac1f685e185263368e99735ebe62a7f2931b47282be8eb165e4d7",
+ "6d4bf87640a6a48a50d28797b7",
+ "8d8c7ffc55086d539b5a8f0d1232654c",
+ "0d803ec309482f35b8e6226f2b56303239298e06b281c2d51aaba3c125",
+ },
+ {
+ "0e18a844ac5bf38e4cd72d9b0942e506",
+ "0870d4b28a2954489a0abcd5",
+ "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b3",
+ "05eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe2f0e49e4f321549fd824ea9",
+ "cace28f4976afd72e3c5128167eb788fbf6634dda0a2f53148d00f6fa557f5e9e8f736c12e450894af56cb67f7d99e1027258c8571bd91ee3b7360e0d508aa1f382411a16115f9c05251cc326d4016f62e0eb8151c048465b0c6c8ff12558d43310e18b2cb1889eec91557ce21ba05955cf4c1d4847aadfb1b0a83f3a3b82b7efa62a5f03c5d6eda381a85dd78dbc55c",
+ },
+ {
+ "1f6c3a3bc0542aabba4ef8f6c7169e73",
+ "f3584606472b260e0dd2ebb2",
+ "67c6697351ff4aec29cdbaabf2fbe3467cc254f81be8e78d765a2e63339fc99a66320db73158a35a255d051758e95ed4abb2cdc69bb454110e827441213ddc8770e93ea141e1fc673e017e97eadc6b968f385c2aecb03bfb32af3c54ec18db5c021afe43fbfaaa3afb29d1e6053c7c9475d8be6189f95cbba8990f95b1ebf1b305eff700e9a13ae5ca0bcbd0484764bd1f231ea81c7b64c514735ac55e4b79633b706424119e09dcaad4acf21b10af3b33cde3504847155cbb6f2219ba9b7df50be11a1c7f23f829f8a41b13b5ca4ee8983238e0794d3d34bc5f4e77facb6c05ac86212baa1a55a2be70b5733b045cd33694b3afe2f0e49e4f321549fd824ea90870d4b28a2954489a0abcd50e18a844ac5bf38e4cd72d9b0942e506c433afcda3847f2dadd47647de321cec4ac430f62023856cfbb20704f4ec0bb920ba86c33e05f1ecd96733b79950a3e314d3d934f75ea0f210a8f6059401beb4bc4478fa4969e623d01ada696a7e4c7e5125b34884533a94fb319990325744ee9bbce9e525cf08f5e9e25e5360aad2b2d085fa54d835e8d466826498d9a8877565705a8a3f62802944de7ca5894e5759d351adac869580ec17e485f18c0c66f17cc07cbb22fce466da610b63af62bc83b4692f3affaf271693ac071fb86d11342d8def4f89d4b66335c1c7e4248367d8ed9612ec453902d8e50af89d7709d1a596c1f41f",
+ "95aa82ca6c49ae90cd1668baac7aa6f2b4a8ca99b2c2372acb08cf61c9c3805e6e0328da4cd76a19edd2d3994c798b0022569ad418d1fee4d9cd45a391c601ffc92ad91501432fee150287617c13629e69fc7281cd7165a63eab49cf714bce3a75a74f76ea7e64ff81eb61fdfec39b67bf0de98c7e4e32bdf97c8c6ac75ba43c02f4b2ed7216ecf3014df000108b67cf99505b179f8ed4980a6103d1bca70dbe9bbfab0ed59801d6e5f2d6f67d3ec5168e212e2daf02c6b963c98a1f7097de0c56891a2b211b01070dd8fd8b16c2a1a4e3cfd292d2984b3561d555d16c33ddc2bcf7edde13efe520c7e2abdda44d81881c531aeeeb66244c3b791ea8acfb6a68",
+ "55864065117e07650ca650a0f0d9ef4b02aee7c58928462fddb49045bf85355b4653fa26158210a7f3ef5b3ca48612e8b7adf5c025c1b821960af770d935df1c9a1dd25077d6b1c7f937b2e20ce981b07980880214698f3fad72fa370b3b7da257ce1d0cf352bc5304fada3e0f8927bd4e5c1abbffa563bdedcb567daa64faaed748cb361732200ba3506836a3c1c82aafa14c76dc07f6c4277ff2c61325f91fdbd6c1883e745fcaadd5a6d692eeaa5ad56eead6a9d74a595d22757ed89532a4b8831e2b9e2315baea70a9b95d228f09d491a5ed5ab7076766703457e3159bbb9b17b329525669863153079448c68cd2f200c0be9d43061a60639cb59d50993d276c05caaa565db8ce633b2673e4012bebbca02b1a64d779d04066f3e949ece173825885ec816468c819a8129007cc05d8785c48077d09eb1abcba14508dde85a6f16a744bc95faef24888d53a8020515ab20307efaecbdf143a26563c67989bceedc2d6d2bb9699bb6c615d93767e4158c1124e3b6c723aaa47796e59a60d3696cd85adfae9a62f2c02c22009f80ed494bdc587f31dd892c253b5c6d6b7db078fa72d23474ee54f8144d6561182d71c862941dbc0b2cb37a4d4b23cbad5637e6be901cc73f16d5aec39c60dddee631511e57b47520b61ae1892d2d1bd2b486e30faec892f171b6de98d96108016fac805604761f8e74742b3bb7dc8a290a46bf697c3e4446e6e65832cbae7cf1aaad1",
+ },
+ {
+ "0795d80bc7f40f4d41c280271a2e4f7f",
+ "ff824c906594aff365d3cb1f",
+ "1ad4e74d127f935beee57cff920665babe7ce56227377afe570ba786193ded3412d4812453157f42fafc418c02a746c1232c234a639d49baa8f041c12e2ef540027764568ce49886e0d913e28059a3a485c6eee96337a30b28e4cd5612c2961539fa6bc5de034cbedc5fa15db844013e0bef276e27ca7a4faf47a5c1093bd643354108144454d221b3737e6cb87faac36ed131959babe44af2890cfcc4e23ffa24470e689ce0894f5407bb0c8665cff536008ad2ac6f1c9ef8289abd0bd9b72f21c597bda5210cf928c805af2dd4a464d52e36819d521f967bba5386930ab5b4cf4c71746d7e6e964673457348e9d71d170d9eb560bd4bdb779e610ba816bf776231ebd0af5966f5cdab6815944032ab4dd060ad8dab880549e910f1ffcf6862005432afad",
+ "98a47a430d8fd74dc1829a91e3481f8ed024d8ba34c9b903321b04864db333e558ae28653dffb2",
+ "3b8f91443480e647473a0a0b03d571c622b7e70e4309a02c9bb7980053010d865e6aec161354dc9f481b2cd5213e09432b57ec4e58fbd0a8549dd15c8c4e74a6529f75fad0ce5a9e20e2beeb2f91eb638bf88999968de438d2f1cedbfb0a1c81f9e8e7362c738e0fddd963692a4f4df9276b7f040979ce874cf6fa3de26da0713784bdb25e4efcb840554ef5b38b5fe8380549a496bd8e423a7456df6f4ae78a07ebe2276a8e22fc2243ec4f78abe0c99c733fd67c8c492699fa5ee2289cdd0a8d469bf883520ee74efb854bfadc7366a49ee65ca4e894e3335e2b672618d362eee12a577dd8dc2ba55c49c1fc3ad68180e9b112d0234d4aa28f5661f1e036450ca6f18be0166676bd80f8a4890c6ddea306fabb7ff3cb2860aa32a827e3a312912a2dfa70f6bc1c07de238448f2d751bd0cf15bf7",
+ },
+ {
+ "e2e001a36c60d2bf40d69ff5b2b1161ea218db263be16a4e",
+ "84230643130d05425826641e",
+ "adb034f3f4a7ca45e2993812d113a9821d50df151af978bccc6d3bc113e15bc0918fb385377dca1916022ce816d56a332649484043c0fc0f2d37d040182b00a9bbb42ef231f80b48fb3730110d9a4433e38c73264c703579a705b9c031b969ec6d98de9f90e9e78b21179c2eb1e061946cd4bbb844f031ecf6eaac27a4151311adf1b03eda97c9fbae66295f468af4b35faf6ba39f9d8f95873bbc2b51cf3dfec0ed3c9b850696336cc093b24a8765a936d14dd56edc6bf518272169f75e67b74ba452d0aae90416a997c8f31e2e9d54ffea296dc69462debc8347b3e1af6a2d53bdfdfda601134f98db42b609df0a08c9347590c8d86e845bb6373d65a26ab85f67b50569c85401a396b8ad76c2b53ff62bcfbf033e435ef47b9b591d05117c6dc681d68e",
+ "d5d7316b8fdee152942148bff007c22e4b2022c6bc7be3c18c5f2e52e004e0b5dc12206bf002bd",
+ "f2c39423ee630dfe961da81909159dba018ce09b1073a12a477108316af5b7a31f86be6a0548b572d604bd115ea737dde899e0bd7f7ac9b23e38910dc457551ecc15c814a9f46d8432a1a36097dc1afe2712d1ba0838fa88cb55d9f65a2e9bece0dbf8999562503989041a2c87d7eb80ef649769d2f4978ce5cf9664f2bd0849646aa81cb976e45e1ade2f17a8126219e917aadbb4bae5e2c4b3f57bbc7f13fcc807df7842d9727a1b389e0b749e5191482adacabd812627c6eae2c7a30caf0844ad2a22e08f39edddf0ae10413e47db433dfe3febbb5a5cec9ade21fbba1e548247579395880b747669a8eb7e2ec0c1bff7fed2defdb92b07a14edf07b1bde29c31ab052ff1214e6b5ebbefcb8f21b5d6f8f6e07ee57ad6e14d4e142cb3f51bb465ab3a28a2a12f01b7514ad0463f2bde0d71d221",
+ },
+ {
+ "5394e890d37ba55ec9d5f327f15680f6a63ef5279c79331643ad0af6d2623525",
+ "815e840b7aca7af3b324583f",
+ "8e63067cd15359f796b43c68f093f55fdf3589fc5f2fdfad5f9d156668a617f7091d73da71cdd207810e6f71a165d0809a597df9885ca6e8f9bb4e616166586b83cc45f49917fc1a256b8bc7d05c476ab5c4633e20092619c4747b26dad3915e9fd65238ee4e5213badeda8a3a22f5efe6582d0762532026c89b4ca26fdd000eb45347a2a199b55b7790e6b1b2dba19833ce9f9522c0bcea5b088ccae68dd99ae0203c81b9f1dd3181c3e2339e83ccd1526b67742b235e872bea5111772aab574ae7d904d9b6355a79178e179b5ae8edc54f61f172bf789ea9c9af21f45b783e4251421b077776808f04972a5e801723cf781442378ce0e0568f014aea7a882dcbcb48d342be53d1c2ebfb206b12443a8a587cc1e55ca23beca385d61d0d03e9d84cbc1b0a",
+ "0feccdfae8ed65fa31a0858a1c466f79e8aa658c2f3ba93c3f92158b4e30955e1c62580450beff",
+ "b69a7e17bb5af688883274550a4ded0d1aff49a0b18343f4b382f745c163f7f714c9206a32a1ff012427e19431951edd0a755e5f491b0eedfd7df68bbc6085dd2888607a2f998c3e881eb1694109250db28291e71f4ad344a125624fb92e16ea9815047cd1111cabfdc9cb8c3b4b0f40aa91d31774009781231400789ed545404af6c3f76d07ddc984a7bd8f52728159782832e298cc4d529be96d17be898efd83e44dc7b0e2efc645849fd2bba61fef0ae7be0dcab233cc4e2b7ba4e887de9c64b97f2a1818aa54371a8d629dae37975f7784e5e3cc77055ed6e975b1e5f55e6bbacdc9f295ce4ada2c16113cd5b323cf78b7dde39f4a87aa8c141a31174e3584ccbd380cf5ec6d1dba539928b084fa9683e9c0953acf47cc3ac384a2c38914f1da01fb2cfd78905c2b58d36b2574b9df15535d82",
+ },
+ // These cases test non-standard tag sizes.
+ {
+ "89c54b0d3bc3c397d5039058c220685f",
+ "bc7f45c00868758d62d4bb4d",
+ "582670b0baf5540a3775b6615605bd05",
+ "48d16cda0337105a50e2ed76fd18e114",
+ "fc2d4c4eee2209ddbba6663c02765e6955e783b00156f5da0446e2970b877f",
+ },
+ {
+ "bad6049678bf75c9087b3e3ae7e72c13",
+ "a0a017b83a67d8f1b883e561",
+ "a1be93012f05a1958440f74a5311f4a1",
+ "f7c27b51d5367161dc2ff1e9e3edc6f2",
+ "36f032f7e3dc3275ca22aedcdc68436b99a2227f8bb69d45ea5d8842cd08",
+ },
+ {
+ "66a3c722ccf9709525650973ecc100a9",
+ "1621d42d3a6d42a2d2bf9494",
+ "61fa9dbbed2190fbc2ffabf5d2ea4ff8",
+ "d7a9b6523b8827068a6354a6d166c6b9",
+ "fef3b20f40e08a49637cc82f4c89b8603fd5c0132acfab97b5fff651c4",
+ },
+ {
+ "562ae8aadb8d23e0f271a99a7d1bd4d1",
+ "f7a5e2399413b89b6ad31aff",
+ "bbdc3504d803682aa08a773cde5f231a",
+ "2b9680b886b3efb7c6354b38c63b5373",
+ "e2b7e5ed5ff27fc8664148f5a628a46dcbf2015184fffb82f2651c36",
+ },
+ {
+ "11754cd72aec309bf52f7687212e8957",
+ "",
+ "",
+ "",
+ "250327c674aaf477aef2675748cf6971",
+ },
+}
+
+func TestAESGCM(t *testing.T) {
+ for i, test := range aesGCMTests {
+ key, _ := hex.DecodeString(test.key)
+ aes, err := aes.NewCipher(key)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ nonce, _ := hex.DecodeString(test.nonce)
+ plaintext, _ := hex.DecodeString(test.plaintext)
+ ad, _ := hex.DecodeString(test.ad)
+ tagSize := (len(test.result) - len(test.plaintext)) / 2
+
+ var aesgcm cipher.AEAD
+ switch {
+ // Handle non-standard tag sizes
+ case tagSize != 16:
+ aesgcm, err = cipher.NewGCMWithTagSize(aes, tagSize)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Handle 0 nonce size (expect error and continue)
+ case len(nonce) == 0:
+ aesgcm, err = cipher.NewGCMWithNonceSize(aes, 0)
+ if err == nil {
+ t.Fatal("expected error for zero nonce size")
+ }
+ continue
+
+ // Handle non-standard nonce sizes
+ case len(nonce) != 12:
+ aesgcm, err = cipher.NewGCMWithNonceSize(aes, len(nonce))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ default:
+ aesgcm, err = cipher.NewGCM(aes)
+ if err != nil {
+ t.Fatal(err)
+ }
+ }
+
+ ct := aesgcm.Seal(nil, nonce, plaintext, ad)
+ if ctHex := hex.EncodeToString(ct); ctHex != test.result {
+ t.Errorf("#%d: got %s, want %s", i, ctHex, test.result)
+ continue
+ }
+
+ plaintext2, err := aesgcm.Open(nil, nonce, ct, ad)
+ if err != nil {
+ t.Errorf("#%d: Open failed", i)
+ continue
+ }
+
+ if !bytes.Equal(plaintext, plaintext2) {
+ t.Errorf("#%d: plaintext's don't match: got %x vs %x", i, plaintext2, plaintext)
+ continue
+ }
+
+ if len(ad) > 0 {
+ ad[0] ^= 0x80
+ if _, err := aesgcm.Open(nil, nonce, ct, ad); err == nil {
+ t.Errorf("#%d: Open was successful after altering additional data", i)
+ }
+ ad[0] ^= 0x80
+ }
+
+ nonce[0] ^= 0x80
+ if _, err := aesgcm.Open(nil, nonce, ct, ad); err == nil {
+ t.Errorf("#%d: Open was successful after altering nonce", i)
+ }
+ nonce[0] ^= 0x80
+
+ ct[0] ^= 0x80
+ if _, err := aesgcm.Open(nil, nonce, ct, ad); err == nil {
+ t.Errorf("#%d: Open was successful after altering ciphertext", i)
+ }
+ ct[0] ^= 0x80
+ }
+}
+
+func TestGCMInvalidTagSize(t *testing.T) {
+ key, _ := hex.DecodeString("ab72c77b97cb5fe9a382d9fe81ffdbed")
+
+ aes, _ := aes.NewCipher(key)
+
+ for _, tagSize := range []int{0, 1, aes.BlockSize() + 1} {
+ aesgcm, err := cipher.NewGCMWithTagSize(aes, tagSize)
+ if aesgcm != nil || err == nil {
+ t.Fatalf("NewGCMWithNonceAndTagSize was successful with an invalid %d-byte tag size", tagSize)
+ }
+ }
+}
+
+func TestTagFailureOverwrite(t *testing.T) {
+ // The AESNI GCM code decrypts and authenticates concurrently and so
+ // overwrites the output buffer before checking the authentication tag.
+ // In order to be consistent across platforms, all implementations
+ // should do this and this test checks that.
+
+ key, _ := hex.DecodeString("ab72c77b97cb5fe9a382d9fe81ffdbed")
+ nonce, _ := hex.DecodeString("54cc7dc2c37ec006bcc6d1db")
+ ciphertext, _ := hex.DecodeString("0e1bde206a07a9c2c1b65300f8c649972b4401346697138c7a4891ee59867d0c")
+
+ aes, _ := aes.NewCipher(key)
+ aesgcm, _ := cipher.NewGCM(aes)
+
+ dst := make([]byte, len(ciphertext)-16)
+ for i := range dst {
+ dst[i] = 42
+ }
+
+ result, err := aesgcm.Open(dst[:0], nonce, ciphertext, nil)
+ if err == nil {
+ t.Fatal("Bad Open still resulted in nil error.")
+ }
+
+ if result != nil {
+ t.Fatal("Failed Open returned non-nil result.")
+ }
+
+ for i := range dst {
+ if dst[i] != 0 {
+ t.Fatal("Failed Open didn't zero dst buffer")
+ }
+ }
+}
+
+func TestGCMCounterWrap(t *testing.T) {
+ // Test that the last 32-bits of the counter wrap correctly.
+ tests := []struct {
+ nonce, tag string
+ }{
+ {"0fa72e25", "37e1948cdfff09fbde0c40ad99fee4a7"}, // counter: 7eb59e4d961dad0dfdd75aaffffffff0
+ {"afe05cc1", "438f3aa9fee5e54903b1927bca26bbdf"}, // counter: 75d492a7e6e6bfc979ad3a8ffffffff4
+ {"9ffecbef", "7b88ca424df9703e9e8611071ec7e16e"}, // counter: c8bb108b0ecdc71747b9d57ffffffff5
+ {"ffc3e5b3", "38d49c86e0abe853ac250e66da54c01a"}, // counter: 706414d2de9b36ab3b900a9ffffffff6
+ {"cfdd729d", "e08402eaac36a1a402e09b1bd56500e8"}, // counter: cd0b96fe36b04e750584e56ffffffff7
+ {"010ae3d486", "5405bb490b1f95d01e2ba735687154bc"}, // counter: e36c18e69406c49722808104fffffff8
+ {"01b1107a9d", "939a585f342e01e17844627492d44dbf"}, // counter: e6d56eaf9127912b6d62c6dcffffffff
+ }
+ key, err := aes.NewCipher(make([]byte, 16))
+ if err != nil {
+ t.Fatal(err)
+ }
+ plaintext := make([]byte, 16*17+1)
+ for i, test := range tests {
+ nonce, _ := hex.DecodeString(test.nonce)
+ want, _ := hex.DecodeString(test.tag)
+ aead, err := cipher.NewGCMWithNonceSize(key, len(nonce))
+ if err != nil {
+ t.Fatal(err)
+ }
+ got := aead.Seal(nil, nonce, plaintext, nil)
+ if !bytes.Equal(got[len(plaintext):], want) {
+ t.Errorf("test[%v]: got: %x, want: %x", i, got[len(plaintext):], want)
+ }
+ _, err = aead.Open(nil, nonce, got, nil)
+ if err != nil {
+ t.Errorf("test[%v]: authentication failed", i)
+ }
+ }
+}
+
+var _ cipher.Block = (*wrapper)(nil)
+
+type wrapper struct {
+ block cipher.Block
+}
+
+func (w *wrapper) BlockSize() int { return w.block.BlockSize() }
+func (w *wrapper) Encrypt(dst, src []byte) { w.block.Encrypt(dst, src) }
+func (w *wrapper) Decrypt(dst, src []byte) { w.block.Decrypt(dst, src) }
+
+// wrap wraps the Block interface so that it does not fulfill
+// any optimizing interfaces such as gcmAble.
+func wrap(b cipher.Block) cipher.Block {
+ return &wrapper{b}
+}
+
+func TestGCMAsm(t *testing.T) {
+ // Create a new pair of AEADs, one using the assembly implementation
+ // and one using the generic Go implementation.
+ newAESGCM := func(key []byte) (asm, generic cipher.AEAD, err error) {
+ block, err := aes.NewCipher(key[:])
+ if err != nil {
+ return nil, nil, err
+ }
+ asm, err = cipher.NewGCM(block)
+ if err != nil {
+ return nil, nil, err
+ }
+ generic, err = cipher.NewGCM(wrap(block))
+ if err != nil {
+ return nil, nil, err
+ }
+ return asm, generic, nil
+ }
+
+ // check for assembly implementation
+ var key [16]byte
+ asm, generic, err := newAESGCM(key[:])
+ if err != nil {
+ t.Fatal(err)
+ }
+ if reflect.TypeOf(asm) == reflect.TypeOf(generic) {
+ t.Skipf("no assembly implementation of GCM")
+ }
+
+ // generate permutations
+ type pair struct{ align, length int }
+ lengths := []int{0, 156, 8192, 8193, 8208}
+ keySizes := []int{16, 24, 32}
+ alignments := []int{0, 1, 2, 3}
+ if testing.Short() {
+ keySizes = []int{16}
+ alignments = []int{1}
+ }
+ perms := make([]pair, 0)
+ for _, l := range lengths {
+ for _, a := range alignments {
+ if a != 0 && l == 0 {
+ continue
+ }
+ perms = append(perms, pair{align: a, length: l})
+ }
+ }
+
+ // run test for all permutations
+ test := func(ks int, pt, ad []byte) error {
+ key := make([]byte, ks)
+ if _, err := io.ReadFull(rand.Reader, key); err != nil {
+ return err
+ }
+ asm, generic, err := newAESGCM(key)
+ if err != nil {
+ return err
+ }
+ if _, err := io.ReadFull(rand.Reader, pt); err != nil {
+ return err
+ }
+ if _, err := io.ReadFull(rand.Reader, ad); err != nil {
+ return err
+ }
+ nonce := make([]byte, 12)
+ if _, err := io.ReadFull(rand.Reader, nonce); err != nil {
+ return err
+ }
+ want := generic.Seal(nil, nonce, pt, ad)
+ got := asm.Seal(nil, nonce, pt, ad)
+ if !bytes.Equal(want, got) {
+ return errors.New("incorrect Seal output")
+ }
+ got, err = asm.Open(nil, nonce, want, ad)
+ if err != nil {
+ return errors.New("authentication failed")
+ }
+ if !bytes.Equal(pt, got) {
+ return errors.New("incorrect Open output")
+ }
+ return nil
+ }
+ for _, a := range perms {
+ ad := make([]byte, a.align+a.length)
+ ad = ad[a.align:]
+ for _, p := range perms {
+ pt := make([]byte, p.align+p.length)
+ pt = pt[p.align:]
+ for _, ks := range keySizes {
+ if err := test(ks, pt, ad); err != nil {
+ t.Error(err)
+ t.Errorf(" key size: %v", ks)
+ t.Errorf(" plaintext alignment: %v", p.align)
+ t.Errorf(" plaintext length: %v", p.length)
+ t.Errorf(" additionalData alignment: %v", a.align)
+ t.Fatalf(" additionalData length: %v", a.length)
+ }
+ }
+ }
+ }
+}
diff --git a/src/crypto/cipher/io.go b/src/crypto/cipher/io.go
new file mode 100644
index 0000000..0974ac7
--- /dev/null
+++ b/src/crypto/cipher/io.go
@@ -0,0 +1,53 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package cipher
+
+import "io"
+
+// The Stream* objects are so simple that all their members are public. Users
+// can create them themselves.
+
+// StreamReader wraps a Stream into an io.Reader. It calls XORKeyStream
+// to process each slice of data which passes through.
+type StreamReader struct {
+ S Stream
+ R io.Reader
+}
+
+func (r StreamReader) Read(dst []byte) (n int, err error) {
+ n, err = r.R.Read(dst)
+ r.S.XORKeyStream(dst[:n], dst[:n])
+ return
+}
+
+// StreamWriter wraps a Stream into an io.Writer. It calls XORKeyStream
+// to process each slice of data which passes through. If any Write call
+// returns short then the StreamWriter is out of sync and must be discarded.
+// A StreamWriter has no internal buffering; Close does not need
+// to be called to flush write data.
+type StreamWriter struct {
+ S Stream
+ W io.Writer
+ Err error // unused
+}
+
+func (w StreamWriter) Write(src []byte) (n int, err error) {
+ c := make([]byte, len(src))
+ w.S.XORKeyStream(c, src)
+ n, err = w.W.Write(c)
+ if n != len(src) && err == nil { // should never happen
+ err = io.ErrShortWrite
+ }
+ return
+}
+
+// Close closes the underlying Writer and returns its Close return value, if the Writer
+// is also an io.Closer. Otherwise it returns nil.
+func (w StreamWriter) Close() error {
+ if c, ok := w.W.(io.Closer); ok {
+ return c.Close()
+ }
+ return nil
+}
diff --git a/src/crypto/cipher/ofb.go b/src/crypto/cipher/ofb.go
new file mode 100644
index 0000000..1195fdd
--- /dev/null
+++ b/src/crypto/cipher/ofb.go
@@ -0,0 +1,77 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// OFB (Output Feedback) Mode.
+
+package cipher
+
+import (
+ "crypto/internal/alias"
+ "crypto/subtle"
+)
+
+type ofb struct {
+ b Block
+ cipher []byte
+ out []byte
+ outUsed int
+}
+
+// NewOFB returns a Stream that encrypts or decrypts using the block cipher b
+// in output feedback mode. The initialization vector iv's length must be equal
+// to b's block size.
+func NewOFB(b Block, iv []byte) Stream {
+ blockSize := b.BlockSize()
+ if len(iv) != blockSize {
+ panic("cipher.NewOFB: IV length must equal block size")
+ }
+ bufSize := streamBufferSize
+ if bufSize < blockSize {
+ bufSize = blockSize
+ }
+ x := &ofb{
+ b: b,
+ cipher: make([]byte, blockSize),
+ out: make([]byte, 0, bufSize),
+ outUsed: 0,
+ }
+
+ copy(x.cipher, iv)
+ return x
+}
+
+func (x *ofb) refill() {
+ bs := x.b.BlockSize()
+ remain := len(x.out) - x.outUsed
+ if remain > x.outUsed {
+ return
+ }
+ copy(x.out, x.out[x.outUsed:])
+ x.out = x.out[:cap(x.out)]
+ for remain < len(x.out)-bs {
+ x.b.Encrypt(x.cipher, x.cipher)
+ copy(x.out[remain:], x.cipher)
+ remain += bs
+ }
+ x.out = x.out[:remain]
+ x.outUsed = 0
+}
+
+func (x *ofb) XORKeyStream(dst, src []byte) {
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if alias.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+ for len(src) > 0 {
+ if x.outUsed >= len(x.out)-x.b.BlockSize() {
+ x.refill()
+ }
+ n := subtle.XORBytes(dst, src, x.out[x.outUsed:])
+ dst = dst[n:]
+ src = src[n:]
+ x.outUsed += n
+ }
+}
diff --git a/src/crypto/cipher/ofb_test.go b/src/crypto/cipher/ofb_test.go
new file mode 100644
index 0000000..8d3c5d3
--- /dev/null
+++ b/src/crypto/cipher/ofb_test.go
@@ -0,0 +1,102 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// OFB AES test vectors.
+
+// See U.S. National Institute of Standards and Technology (NIST)
+// Special Publication 800-38A, ``Recommendation for Block Cipher
+// Modes of Operation,'' 2001 Edition, pp. 52-55.
+
+package cipher_test
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "testing"
+)
+
+type ofbTest struct {
+ name string
+ key []byte
+ iv []byte
+ in []byte
+ out []byte
+}
+
+var ofbTests = []ofbTest{
+ // NIST SP 800-38A pp 52-55
+ {
+ "OFB-AES128",
+ commonKey128,
+ commonIV,
+ commonInput,
+ []byte{
+ 0x3b, 0x3f, 0xd9, 0x2e, 0xb7, 0x2d, 0xad, 0x20, 0x33, 0x34, 0x49, 0xf8, 0xe8, 0x3c, 0xfb, 0x4a,
+ 0x77, 0x89, 0x50, 0x8d, 0x16, 0x91, 0x8f, 0x03, 0xf5, 0x3c, 0x52, 0xda, 0xc5, 0x4e, 0xd8, 0x25,
+ 0x97, 0x40, 0x05, 0x1e, 0x9c, 0x5f, 0xec, 0xf6, 0x43, 0x44, 0xf7, 0xa8, 0x22, 0x60, 0xed, 0xcc,
+ 0x30, 0x4c, 0x65, 0x28, 0xf6, 0x59, 0xc7, 0x78, 0x66, 0xa5, 0x10, 0xd9, 0xc1, 0xd6, 0xae, 0x5e,
+ },
+ },
+ {
+ "OFB-AES192",
+ commonKey192,
+ commonIV,
+ commonInput,
+ []byte{
+ 0xcd, 0xc8, 0x0d, 0x6f, 0xdd, 0xf1, 0x8c, 0xab, 0x34, 0xc2, 0x59, 0x09, 0xc9, 0x9a, 0x41, 0x74,
+ 0xfc, 0xc2, 0x8b, 0x8d, 0x4c, 0x63, 0x83, 0x7c, 0x09, 0xe8, 0x17, 0x00, 0xc1, 0x10, 0x04, 0x01,
+ 0x8d, 0x9a, 0x9a, 0xea, 0xc0, 0xf6, 0x59, 0x6f, 0x55, 0x9c, 0x6d, 0x4d, 0xaf, 0x59, 0xa5, 0xf2,
+ 0x6d, 0x9f, 0x20, 0x08, 0x57, 0xca, 0x6c, 0x3e, 0x9c, 0xac, 0x52, 0x4b, 0xd9, 0xac, 0xc9, 0x2a,
+ },
+ },
+ {
+ "OFB-AES256",
+ commonKey256,
+ commonIV,
+ commonInput,
+ []byte{
+ 0xdc, 0x7e, 0x84, 0xbf, 0xda, 0x79, 0x16, 0x4b, 0x7e, 0xcd, 0x84, 0x86, 0x98, 0x5d, 0x38, 0x60,
+ 0x4f, 0xeb, 0xdc, 0x67, 0x40, 0xd2, 0x0b, 0x3a, 0xc8, 0x8f, 0x6a, 0xd8, 0x2a, 0x4f, 0xb0, 0x8d,
+ 0x71, 0xab, 0x47, 0xa0, 0x86, 0xe8, 0x6e, 0xed, 0xf3, 0x9d, 0x1c, 0x5b, 0xba, 0x97, 0xc4, 0x08,
+ 0x01, 0x26, 0x14, 0x1d, 0x67, 0xf3, 0x7b, 0xe8, 0x53, 0x8f, 0x5a, 0x8b, 0xe7, 0x40, 0xe4, 0x84,
+ },
+ },
+}
+
+func TestOFB(t *testing.T) {
+ for _, tt := range ofbTests {
+ test := tt.name
+
+ c, err := aes.NewCipher(tt.key)
+ if err != nil {
+ t.Errorf("%s: NewCipher(%d bytes) = %s", test, len(tt.key), err)
+ continue
+ }
+
+ for j := 0; j <= 5; j += 5 {
+ plaintext := tt.in[0 : len(tt.in)-j]
+ ofb := cipher.NewOFB(c, tt.iv)
+ ciphertext := make([]byte, len(plaintext))
+ ofb.XORKeyStream(ciphertext, plaintext)
+ if !bytes.Equal(ciphertext, tt.out[:len(plaintext)]) {
+ t.Errorf("%s/%d: encrypting\ninput % x\nhave % x\nwant % x", test, len(plaintext), plaintext, ciphertext, tt.out)
+ }
+ }
+
+ for j := 0; j <= 5; j += 5 {
+ ciphertext := tt.out[0 : len(tt.in)-j]
+ ofb := cipher.NewOFB(c, tt.iv)
+ plaintext := make([]byte, len(ciphertext))
+ ofb.XORKeyStream(plaintext, ciphertext)
+ if !bytes.Equal(plaintext, tt.in[:len(ciphertext)]) {
+ t.Errorf("%s/%d: decrypting\nhave % x\nwant % x", test, len(ciphertext), plaintext, tt.in)
+ }
+ }
+
+ if t.Failed() {
+ break
+ }
+ }
+}
diff --git a/src/crypto/crypto.go b/src/crypto/crypto.go
new file mode 100644
index 0000000..10a1cd8
--- /dev/null
+++ b/src/crypto/crypto.go
@@ -0,0 +1,223 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package crypto collects common cryptographic constants.
+package crypto
+
+import (
+ "hash"
+ "io"
+ "strconv"
+)
+
+// Hash identifies a cryptographic hash function that is implemented in another
+// package.
+type Hash uint
+
+// HashFunc simply returns the value of h so that Hash implements SignerOpts.
+func (h Hash) HashFunc() Hash {
+ return h
+}
+
+func (h Hash) String() string {
+ switch h {
+ case MD4:
+ return "MD4"
+ case MD5:
+ return "MD5"
+ case SHA1:
+ return "SHA-1"
+ case SHA224:
+ return "SHA-224"
+ case SHA256:
+ return "SHA-256"
+ case SHA384:
+ return "SHA-384"
+ case SHA512:
+ return "SHA-512"
+ case MD5SHA1:
+ return "MD5+SHA1"
+ case RIPEMD160:
+ return "RIPEMD-160"
+ case SHA3_224:
+ return "SHA3-224"
+ case SHA3_256:
+ return "SHA3-256"
+ case SHA3_384:
+ return "SHA3-384"
+ case SHA3_512:
+ return "SHA3-512"
+ case SHA512_224:
+ return "SHA-512/224"
+ case SHA512_256:
+ return "SHA-512/256"
+ case BLAKE2s_256:
+ return "BLAKE2s-256"
+ case BLAKE2b_256:
+ return "BLAKE2b-256"
+ case BLAKE2b_384:
+ return "BLAKE2b-384"
+ case BLAKE2b_512:
+ return "BLAKE2b-512"
+ default:
+ return "unknown hash value " + strconv.Itoa(int(h))
+ }
+}
+
+const (
+ MD4 Hash = 1 + iota // import golang.org/x/crypto/md4
+ MD5 // import crypto/md5
+ SHA1 // import crypto/sha1
+ SHA224 // import crypto/sha256
+ SHA256 // import crypto/sha256
+ SHA384 // import crypto/sha512
+ SHA512 // import crypto/sha512
+ MD5SHA1 // no implementation; MD5+SHA1 used for TLS RSA
+ RIPEMD160 // import golang.org/x/crypto/ripemd160
+ SHA3_224 // import golang.org/x/crypto/sha3
+ SHA3_256 // import golang.org/x/crypto/sha3
+ SHA3_384 // import golang.org/x/crypto/sha3
+ SHA3_512 // import golang.org/x/crypto/sha3
+ SHA512_224 // import crypto/sha512
+ SHA512_256 // import crypto/sha512
+ BLAKE2s_256 // import golang.org/x/crypto/blake2s
+ BLAKE2b_256 // import golang.org/x/crypto/blake2b
+ BLAKE2b_384 // import golang.org/x/crypto/blake2b
+ BLAKE2b_512 // import golang.org/x/crypto/blake2b
+ maxHash
+)
+
+var digestSizes = []uint8{
+ MD4: 16,
+ MD5: 16,
+ SHA1: 20,
+ SHA224: 28,
+ SHA256: 32,
+ SHA384: 48,
+ SHA512: 64,
+ SHA512_224: 28,
+ SHA512_256: 32,
+ SHA3_224: 28,
+ SHA3_256: 32,
+ SHA3_384: 48,
+ SHA3_512: 64,
+ MD5SHA1: 36,
+ RIPEMD160: 20,
+ BLAKE2s_256: 32,
+ BLAKE2b_256: 32,
+ BLAKE2b_384: 48,
+ BLAKE2b_512: 64,
+}
+
+// Size returns the length, in bytes, of a digest resulting from the given hash
+// function. It doesn't require that the hash function in question be linked
+// into the program.
+func (h Hash) Size() int {
+ if h > 0 && h < maxHash {
+ return int(digestSizes[h])
+ }
+ panic("crypto: Size of unknown hash function")
+}
+
+var hashes = make([]func() hash.Hash, maxHash)
+
+// New returns a new hash.Hash calculating the given hash function. New panics
+// if the hash function is not linked into the binary.
+func (h Hash) New() hash.Hash {
+ if h > 0 && h < maxHash {
+ f := hashes[h]
+ if f != nil {
+ return f()
+ }
+ }
+ panic("crypto: requested hash function #" + strconv.Itoa(int(h)) + " is unavailable")
+}
+
+// Available reports whether the given hash function is linked into the binary.
+func (h Hash) Available() bool {
+ return h < maxHash && hashes[h] != nil
+}
+
+// RegisterHash registers a function that returns a new instance of the given
+// hash function. This is intended to be called from the init function in
+// packages that implement hash functions.
+func RegisterHash(h Hash, f func() hash.Hash) {
+ if h >= maxHash {
+ panic("crypto: RegisterHash of unknown hash function")
+ }
+ hashes[h] = f
+}
+
+// PublicKey represents a public key using an unspecified algorithm.
+//
+// Although this type is an empty interface for backwards compatibility reasons,
+// all public key types in the standard library implement the following interface
+//
+// interface{
+// Equal(x crypto.PublicKey) bool
+// }
+//
+// which can be used for increased type safety within applications.
+type PublicKey any
+
+// PrivateKey represents a private key using an unspecified algorithm.
+//
+// Although this type is an empty interface for backwards compatibility reasons,
+// all private key types in the standard library implement the following interface
+//
+// interface{
+// Public() crypto.PublicKey
+// Equal(x crypto.PrivateKey) bool
+// }
+//
+// as well as purpose-specific interfaces such as Signer and Decrypter, which
+// can be used for increased type safety within applications.
+type PrivateKey any
+
+// Signer is an interface for an opaque private key that can be used for
+// signing operations. For example, an RSA key kept in a hardware module.
+type Signer interface {
+ // Public returns the public key corresponding to the opaque,
+ // private key.
+ Public() PublicKey
+
+ // Sign signs digest with the private key, possibly using entropy from
+ // rand. For an RSA key, the resulting signature should be either a
+ // PKCS #1 v1.5 or PSS signature (as indicated by opts). For an (EC)DSA
+ // key, it should be a DER-serialised, ASN.1 signature structure.
+ //
+ // Hash implements the SignerOpts interface and, in most cases, one can
+ // simply pass in the hash function used as opts. Sign may also attempt
+ // to type assert opts to other types in order to obtain algorithm
+ // specific values. See the documentation in each package for details.
+ //
+ // Note that when a signature of a hash of a larger message is needed,
+ // the caller is responsible for hashing the larger message and passing
+ // the hash (as digest) and the hash function (as opts) to Sign.
+ Sign(rand io.Reader, digest []byte, opts SignerOpts) (signature []byte, err error)
+}
+
+// SignerOpts contains options for signing with a Signer.
+type SignerOpts interface {
+ // HashFunc returns an identifier for the hash function used to produce
+ // the message passed to Signer.Sign, or else zero to indicate that no
+ // hashing was done.
+ HashFunc() Hash
+}
+
+// Decrypter is an interface for an opaque private key that can be used for
+// asymmetric decryption operations. An example would be an RSA key
+// kept in a hardware module.
+type Decrypter interface {
+ // Public returns the public key corresponding to the opaque,
+ // private key.
+ Public() PublicKey
+
+ // Decrypt decrypts msg. The opts argument should be appropriate for
+ // the primitive used. See the documentation in each implementation for
+ // details.
+ Decrypt(rand io.Reader, msg []byte, opts DecrypterOpts) (plaintext []byte, err error)
+}
+
+type DecrypterOpts any
diff --git a/src/crypto/des/block.go b/src/crypto/des/block.go
new file mode 100644
index 0000000..e029976
--- /dev/null
+++ b/src/crypto/des/block.go
@@ -0,0 +1,259 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package des
+
+import (
+ "encoding/binary"
+ "sync"
+)
+
+func cryptBlock(subkeys []uint64, dst, src []byte, decrypt bool) {
+ b := binary.BigEndian.Uint64(src)
+ b = permuteInitialBlock(b)
+ left, right := uint32(b>>32), uint32(b)
+
+ left = (left << 1) | (left >> 31)
+ right = (right << 1) | (right >> 31)
+
+ if decrypt {
+ for i := 0; i < 8; i++ {
+ left, right = feistel(left, right, subkeys[15-2*i], subkeys[15-(2*i+1)])
+ }
+ } else {
+ for i := 0; i < 8; i++ {
+ left, right = feistel(left, right, subkeys[2*i], subkeys[2*i+1])
+ }
+ }
+
+ left = (left << 31) | (left >> 1)
+ right = (right << 31) | (right >> 1)
+
+ // switch left & right and perform final permutation
+ preOutput := (uint64(right) << 32) | uint64(left)
+ binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput))
+}
+
+// Encrypt one block from src into dst, using the subkeys.
+func encryptBlock(subkeys []uint64, dst, src []byte) {
+ cryptBlock(subkeys, dst, src, false)
+}
+
+// Decrypt one block from src into dst, using the subkeys.
+func decryptBlock(subkeys []uint64, dst, src []byte) {
+ cryptBlock(subkeys, dst, src, true)
+}
+
+// DES Feistel function. feistelBox must be initialized via
+// feistelBoxOnce.Do(initFeistelBox) first.
+func feistel(l, r uint32, k0, k1 uint64) (lout, rout uint32) {
+ var t uint32
+
+ t = r ^ uint32(k0>>32)
+ l ^= feistelBox[7][t&0x3f] ^
+ feistelBox[5][(t>>8)&0x3f] ^
+ feistelBox[3][(t>>16)&0x3f] ^
+ feistelBox[1][(t>>24)&0x3f]
+
+ t = ((r << 28) | (r >> 4)) ^ uint32(k0)
+ l ^= feistelBox[6][(t)&0x3f] ^
+ feistelBox[4][(t>>8)&0x3f] ^
+ feistelBox[2][(t>>16)&0x3f] ^
+ feistelBox[0][(t>>24)&0x3f]
+
+ t = l ^ uint32(k1>>32)
+ r ^= feistelBox[7][t&0x3f] ^
+ feistelBox[5][(t>>8)&0x3f] ^
+ feistelBox[3][(t>>16)&0x3f] ^
+ feistelBox[1][(t>>24)&0x3f]
+
+ t = ((l << 28) | (l >> 4)) ^ uint32(k1)
+ r ^= feistelBox[6][(t)&0x3f] ^
+ feistelBox[4][(t>>8)&0x3f] ^
+ feistelBox[2][(t>>16)&0x3f] ^
+ feistelBox[0][(t>>24)&0x3f]
+
+ return l, r
+}
+
+// feistelBox[s][16*i+j] contains the output of permutationFunction
+// for sBoxes[s][i][j] << 4*(7-s)
+var feistelBox [8][64]uint32
+
+var feistelBoxOnce sync.Once
+
+// general purpose function to perform DES block permutations.
+func permuteBlock(src uint64, permutation []uint8) (block uint64) {
+ for position, n := range permutation {
+ bit := (src >> n) & 1
+ block |= bit << uint((len(permutation)-1)-position)
+ }
+ return
+}
+
+func initFeistelBox() {
+ for s := range sBoxes {
+ for i := 0; i < 4; i++ {
+ for j := 0; j < 16; j++ {
+ f := uint64(sBoxes[s][i][j]) << (4 * (7 - uint(s)))
+ f = permuteBlock(f, permutationFunction[:])
+
+ // Row is determined by the 1st and 6th bit.
+ // Column is the middle four bits.
+ row := uint8(((i & 2) << 4) | i&1)
+ col := uint8(j << 1)
+ t := row | col
+
+ // The rotation was performed in the feistel rounds, being factored out and now mixed into the feistelBox.
+ f = (f << 1) | (f >> 31)
+
+ feistelBox[s][t] = uint32(f)
+ }
+ }
+ }
+}
+
+// permuteInitialBlock is equivalent to the permutation defined
+// by initialPermutation.
+func permuteInitialBlock(block uint64) uint64 {
+ // block = b7 b6 b5 b4 b3 b2 b1 b0 (8 bytes)
+ b1 := block >> 48
+ b2 := block << 48
+ block ^= b1 ^ b2 ^ b1<<48 ^ b2>>48
+
+ // block = b1 b0 b5 b4 b3 b2 b7 b6
+ b1 = block >> 32 & 0xff00ff
+ b2 = (block & 0xff00ff00)
+ block ^= b1<<32 ^ b2 ^ b1<<8 ^ b2<<24 // exchange b0 b4 with b3 b7
+
+ // block is now b1 b3 b5 b7 b0 b2 b4 b6, the permutation:
+ // ... 8
+ // ... 24
+ // ... 40
+ // ... 56
+ // 7 6 5 4 3 2 1 0
+ // 23 22 21 20 19 18 17 16
+ // ... 32
+ // ... 48
+
+ // exchange 4,5,6,7 with 32,33,34,35 etc.
+ b1 = block & 0x0f0f00000f0f0000
+ b2 = block & 0x0000f0f00000f0f0
+ block ^= b1 ^ b2 ^ b1>>12 ^ b2<<12
+
+ // block is the permutation:
+ //
+ // [+8] [+40]
+ //
+ // 7 6 5 4
+ // 23 22 21 20
+ // 3 2 1 0
+ // 19 18 17 16 [+32]
+
+ // exchange 0,1,4,5 with 18,19,22,23
+ b1 = block & 0x3300330033003300
+ b2 = block & 0x00cc00cc00cc00cc
+ block ^= b1 ^ b2 ^ b1>>6 ^ b2<<6
+
+ // block is the permutation:
+ // 15 14
+ // 13 12
+ // 11 10
+ // 9 8
+ // 7 6
+ // 5 4
+ // 3 2
+ // 1 0 [+16] [+32] [+64]
+
+ // exchange 0,2,4,6 with 9,11,13,15:
+ b1 = block & 0xaaaaaaaa55555555
+ block ^= b1 ^ b1>>33 ^ b1<<33
+
+ // block is the permutation:
+ // 6 14 22 30 38 46 54 62
+ // 4 12 20 28 36 44 52 60
+ // 2 10 18 26 34 42 50 58
+ // 0 8 16 24 32 40 48 56
+ // 7 15 23 31 39 47 55 63
+ // 5 13 21 29 37 45 53 61
+ // 3 11 19 27 35 43 51 59
+ // 1 9 17 25 33 41 49 57
+ return block
+}
+
+// permuteFinalBlock is equivalent to the permutation defined
+// by finalPermutation.
+func permuteFinalBlock(block uint64) uint64 {
+ // Perform the same bit exchanges as permuteInitialBlock
+ // but in reverse order.
+ b1 := block & 0xaaaaaaaa55555555
+ block ^= b1 ^ b1>>33 ^ b1<<33
+
+ b1 = block & 0x3300330033003300
+ b2 := block & 0x00cc00cc00cc00cc
+ block ^= b1 ^ b2 ^ b1>>6 ^ b2<<6
+
+ b1 = block & 0x0f0f00000f0f0000
+ b2 = block & 0x0000f0f00000f0f0
+ block ^= b1 ^ b2 ^ b1>>12 ^ b2<<12
+
+ b1 = block >> 32 & 0xff00ff
+ b2 = (block & 0xff00ff00)
+ block ^= b1<<32 ^ b2 ^ b1<<8 ^ b2<<24
+
+ b1 = block >> 48
+ b2 = block << 48
+ block ^= b1 ^ b2 ^ b1<<48 ^ b2>>48
+ return block
+}
+
+// creates 16 28-bit blocks rotated according
+// to the rotation schedule.
+func ksRotate(in uint32) (out []uint32) {
+ out = make([]uint32, 16)
+ last := in
+ for i := 0; i < 16; i++ {
+ // 28-bit circular left shift
+ left := (last << (4 + ksRotations[i])) >> 4
+ right := (last << 4) >> (32 - ksRotations[i])
+ out[i] = left | right
+ last = out[i]
+ }
+ return
+}
+
+// creates 16 56-bit subkeys from the original key.
+func (c *desCipher) generateSubkeys(keyBytes []byte) {
+ feistelBoxOnce.Do(initFeistelBox)
+
+ // apply PC1 permutation to key
+ key := binary.BigEndian.Uint64(keyBytes)
+ permutedKey := permuteBlock(key, permutedChoice1[:])
+
+ // rotate halves of permuted key according to the rotation schedule
+ leftRotations := ksRotate(uint32(permutedKey >> 28))
+ rightRotations := ksRotate(uint32(permutedKey<<4) >> 4)
+
+ // generate subkeys
+ for i := 0; i < 16; i++ {
+ // combine halves to form 56-bit input to PC2
+ pc2Input := uint64(leftRotations[i])<<28 | uint64(rightRotations[i])
+ // apply PC2 permutation to 7 byte input
+ c.subkeys[i] = unpack(permuteBlock(pc2Input, permutedChoice2[:]))
+ }
+}
+
+// Expand 48-bit input to 64-bit, with each 6-bit block padded by extra two bits at the top.
+// By doing so, we can have the input blocks (four bits each), and the key blocks (six bits each) well-aligned without
+// extra shifts/rotations for alignments.
+func unpack(x uint64) uint64 {
+ return ((x>>(6*1))&0xff)<<(8*0) |
+ ((x>>(6*3))&0xff)<<(8*1) |
+ ((x>>(6*5))&0xff)<<(8*2) |
+ ((x>>(6*7))&0xff)<<(8*3) |
+ ((x>>(6*0))&0xff)<<(8*4) |
+ ((x>>(6*2))&0xff)<<(8*5) |
+ ((x>>(6*4))&0xff)<<(8*6) |
+ ((x>>(6*6))&0xff)<<(8*7)
+}
diff --git a/src/crypto/des/cipher.go b/src/crypto/des/cipher.go
new file mode 100644
index 0000000..ece764f
--- /dev/null
+++ b/src/crypto/des/cipher.go
@@ -0,0 +1,155 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package des
+
+import (
+ "crypto/cipher"
+ "crypto/internal/alias"
+ "encoding/binary"
+ "strconv"
+)
+
+// The DES block size in bytes.
+const BlockSize = 8
+
+type KeySizeError int
+
+func (k KeySizeError) Error() string {
+ return "crypto/des: invalid key size " + strconv.Itoa(int(k))
+}
+
+// desCipher is an instance of DES encryption.
+type desCipher struct {
+ subkeys [16]uint64
+}
+
+// NewCipher creates and returns a new cipher.Block.
+func NewCipher(key []byte) (cipher.Block, error) {
+ if len(key) != 8 {
+ return nil, KeySizeError(len(key))
+ }
+
+ c := new(desCipher)
+ c.generateSubkeys(key)
+ return c, nil
+}
+
+func (c *desCipher) BlockSize() int { return BlockSize }
+
+func (c *desCipher) Encrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/des: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/des: output not full block")
+ }
+ if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/des: invalid buffer overlap")
+ }
+ encryptBlock(c.subkeys[:], dst, src)
+}
+
+func (c *desCipher) Decrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/des: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/des: output not full block")
+ }
+ if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/des: invalid buffer overlap")
+ }
+ decryptBlock(c.subkeys[:], dst, src)
+}
+
+// A tripleDESCipher is an instance of TripleDES encryption.
+type tripleDESCipher struct {
+ cipher1, cipher2, cipher3 desCipher
+}
+
+// NewTripleDESCipher creates and returns a new cipher.Block.
+func NewTripleDESCipher(key []byte) (cipher.Block, error) {
+ if len(key) != 24 {
+ return nil, KeySizeError(len(key))
+ }
+
+ c := new(tripleDESCipher)
+ c.cipher1.generateSubkeys(key[:8])
+ c.cipher2.generateSubkeys(key[8:16])
+ c.cipher3.generateSubkeys(key[16:])
+ return c, nil
+}
+
+func (c *tripleDESCipher) BlockSize() int { return BlockSize }
+
+func (c *tripleDESCipher) Encrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/des: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/des: output not full block")
+ }
+ if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/des: invalid buffer overlap")
+ }
+
+ b := binary.BigEndian.Uint64(src)
+ b = permuteInitialBlock(b)
+ left, right := uint32(b>>32), uint32(b)
+
+ left = (left << 1) | (left >> 31)
+ right = (right << 1) | (right >> 31)
+
+ for i := 0; i < 8; i++ {
+ left, right = feistel(left, right, c.cipher1.subkeys[2*i], c.cipher1.subkeys[2*i+1])
+ }
+ for i := 0; i < 8; i++ {
+ right, left = feistel(right, left, c.cipher2.subkeys[15-2*i], c.cipher2.subkeys[15-(2*i+1)])
+ }
+ for i := 0; i < 8; i++ {
+ left, right = feistel(left, right, c.cipher3.subkeys[2*i], c.cipher3.subkeys[2*i+1])
+ }
+
+ left = (left << 31) | (left >> 1)
+ right = (right << 31) | (right >> 1)
+
+ preOutput := (uint64(right) << 32) | uint64(left)
+ binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput))
+}
+
+func (c *tripleDESCipher) Decrypt(dst, src []byte) {
+ if len(src) < BlockSize {
+ panic("crypto/des: input not full block")
+ }
+ if len(dst) < BlockSize {
+ panic("crypto/des: output not full block")
+ }
+ if alias.InexactOverlap(dst[:BlockSize], src[:BlockSize]) {
+ panic("crypto/des: invalid buffer overlap")
+ }
+
+ b := binary.BigEndian.Uint64(src)
+ b = permuteInitialBlock(b)
+ left, right := uint32(b>>32), uint32(b)
+
+ left = (left << 1) | (left >> 31)
+ right = (right << 1) | (right >> 31)
+
+ for i := 0; i < 8; i++ {
+ left, right = feistel(left, right, c.cipher3.subkeys[15-2*i], c.cipher3.subkeys[15-(2*i+1)])
+ }
+ for i := 0; i < 8; i++ {
+ right, left = feistel(right, left, c.cipher2.subkeys[2*i], c.cipher2.subkeys[2*i+1])
+ }
+ for i := 0; i < 8; i++ {
+ left, right = feistel(left, right, c.cipher1.subkeys[15-2*i], c.cipher1.subkeys[15-(2*i+1)])
+ }
+
+ left = (left << 31) | (left >> 1)
+ right = (right << 31) | (right >> 1)
+
+ preOutput := (uint64(right) << 32) | uint64(left)
+ binary.BigEndian.PutUint64(dst, permuteFinalBlock(preOutput))
+}
diff --git a/src/crypto/des/const.go b/src/crypto/des/const.go
new file mode 100644
index 0000000..a20879d
--- /dev/null
+++ b/src/crypto/des/const.go
@@ -0,0 +1,142 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package des implements the Data Encryption Standard (DES) and the
+// Triple Data Encryption Algorithm (TDEA) as defined
+// in U.S. Federal Information Processing Standards Publication 46-3.
+//
+// DES is cryptographically broken and should not be used for secure
+// applications.
+package des
+
+// Used to perform an initial permutation of a 64-bit input block.
+var initialPermutation = [64]byte{
+ 6, 14, 22, 30, 38, 46, 54, 62,
+ 4, 12, 20, 28, 36, 44, 52, 60,
+ 2, 10, 18, 26, 34, 42, 50, 58,
+ 0, 8, 16, 24, 32, 40, 48, 56,
+ 7, 15, 23, 31, 39, 47, 55, 63,
+ 5, 13, 21, 29, 37, 45, 53, 61,
+ 3, 11, 19, 27, 35, 43, 51, 59,
+ 1, 9, 17, 25, 33, 41, 49, 57,
+}
+
+// Used to perform a final permutation of a 4-bit preoutput block. This is the
+// inverse of initialPermutation
+var finalPermutation = [64]byte{
+ 24, 56, 16, 48, 8, 40, 0, 32,
+ 25, 57, 17, 49, 9, 41, 1, 33,
+ 26, 58, 18, 50, 10, 42, 2, 34,
+ 27, 59, 19, 51, 11, 43, 3, 35,
+ 28, 60, 20, 52, 12, 44, 4, 36,
+ 29, 61, 21, 53, 13, 45, 5, 37,
+ 30, 62, 22, 54, 14, 46, 6, 38,
+ 31, 63, 23, 55, 15, 47, 7, 39,
+}
+
+// Used to expand an input block of 32 bits, producing an output block of 48
+// bits.
+var expansionFunction = [48]byte{
+ 0, 31, 30, 29, 28, 27, 28, 27,
+ 26, 25, 24, 23, 24, 23, 22, 21,
+ 20, 19, 20, 19, 18, 17, 16, 15,
+ 16, 15, 14, 13, 12, 11, 12, 11,
+ 10, 9, 8, 7, 8, 7, 6, 5,
+ 4, 3, 4, 3, 2, 1, 0, 31,
+}
+
+// Yields a 32-bit output from a 32-bit input
+var permutationFunction = [32]byte{
+ 16, 25, 12, 11, 3, 20, 4, 15,
+ 31, 17, 9, 6, 27, 14, 1, 22,
+ 30, 24, 8, 18, 0, 5, 29, 23,
+ 13, 19, 2, 26, 10, 21, 28, 7,
+}
+
+// Used in the key schedule to select 56 bits
+// from a 64-bit input.
+var permutedChoice1 = [56]byte{
+ 7, 15, 23, 31, 39, 47, 55, 63,
+ 6, 14, 22, 30, 38, 46, 54, 62,
+ 5, 13, 21, 29, 37, 45, 53, 61,
+ 4, 12, 20, 28, 1, 9, 17, 25,
+ 33, 41, 49, 57, 2, 10, 18, 26,
+ 34, 42, 50, 58, 3, 11, 19, 27,
+ 35, 43, 51, 59, 36, 44, 52, 60,
+}
+
+// Used in the key schedule to produce each subkey by selecting 48 bits from
+// the 56-bit input
+var permutedChoice2 = [48]byte{
+ 42, 39, 45, 32, 55, 51, 53, 28,
+ 41, 50, 35, 46, 33, 37, 44, 52,
+ 30, 48, 40, 49, 29, 36, 43, 54,
+ 15, 4, 25, 19, 9, 1, 26, 16,
+ 5, 11, 23, 8, 12, 7, 17, 0,
+ 22, 3, 10, 14, 6, 20, 27, 24,
+}
+
+// 8 S-boxes composed of 4 rows and 16 columns
+// Used in the DES cipher function
+var sBoxes = [8][4][16]uint8{
+ // S-box 1
+ {
+ {14, 4, 13, 1, 2, 15, 11, 8, 3, 10, 6, 12, 5, 9, 0, 7},
+ {0, 15, 7, 4, 14, 2, 13, 1, 10, 6, 12, 11, 9, 5, 3, 8},
+ {4, 1, 14, 8, 13, 6, 2, 11, 15, 12, 9, 7, 3, 10, 5, 0},
+ {15, 12, 8, 2, 4, 9, 1, 7, 5, 11, 3, 14, 10, 0, 6, 13},
+ },
+ // S-box 2
+ {
+ {15, 1, 8, 14, 6, 11, 3, 4, 9, 7, 2, 13, 12, 0, 5, 10},
+ {3, 13, 4, 7, 15, 2, 8, 14, 12, 0, 1, 10, 6, 9, 11, 5},
+ {0, 14, 7, 11, 10, 4, 13, 1, 5, 8, 12, 6, 9, 3, 2, 15},
+ {13, 8, 10, 1, 3, 15, 4, 2, 11, 6, 7, 12, 0, 5, 14, 9},
+ },
+ // S-box 3
+ {
+ {10, 0, 9, 14, 6, 3, 15, 5, 1, 13, 12, 7, 11, 4, 2, 8},
+ {13, 7, 0, 9, 3, 4, 6, 10, 2, 8, 5, 14, 12, 11, 15, 1},
+ {13, 6, 4, 9, 8, 15, 3, 0, 11, 1, 2, 12, 5, 10, 14, 7},
+ {1, 10, 13, 0, 6, 9, 8, 7, 4, 15, 14, 3, 11, 5, 2, 12},
+ },
+ // S-box 4
+ {
+ {7, 13, 14, 3, 0, 6, 9, 10, 1, 2, 8, 5, 11, 12, 4, 15},
+ {13, 8, 11, 5, 6, 15, 0, 3, 4, 7, 2, 12, 1, 10, 14, 9},
+ {10, 6, 9, 0, 12, 11, 7, 13, 15, 1, 3, 14, 5, 2, 8, 4},
+ {3, 15, 0, 6, 10, 1, 13, 8, 9, 4, 5, 11, 12, 7, 2, 14},
+ },
+ // S-box 5
+ {
+ {2, 12, 4, 1, 7, 10, 11, 6, 8, 5, 3, 15, 13, 0, 14, 9},
+ {14, 11, 2, 12, 4, 7, 13, 1, 5, 0, 15, 10, 3, 9, 8, 6},
+ {4, 2, 1, 11, 10, 13, 7, 8, 15, 9, 12, 5, 6, 3, 0, 14},
+ {11, 8, 12, 7, 1, 14, 2, 13, 6, 15, 0, 9, 10, 4, 5, 3},
+ },
+ // S-box 6
+ {
+ {12, 1, 10, 15, 9, 2, 6, 8, 0, 13, 3, 4, 14, 7, 5, 11},
+ {10, 15, 4, 2, 7, 12, 9, 5, 6, 1, 13, 14, 0, 11, 3, 8},
+ {9, 14, 15, 5, 2, 8, 12, 3, 7, 0, 4, 10, 1, 13, 11, 6},
+ {4, 3, 2, 12, 9, 5, 15, 10, 11, 14, 1, 7, 6, 0, 8, 13},
+ },
+ // S-box 7
+ {
+ {4, 11, 2, 14, 15, 0, 8, 13, 3, 12, 9, 7, 5, 10, 6, 1},
+ {13, 0, 11, 7, 4, 9, 1, 10, 14, 3, 5, 12, 2, 15, 8, 6},
+ {1, 4, 11, 13, 12, 3, 7, 14, 10, 15, 6, 8, 0, 5, 9, 2},
+ {6, 11, 13, 8, 1, 4, 10, 7, 9, 5, 0, 15, 14, 2, 3, 12},
+ },
+ // S-box 8
+ {
+ {13, 2, 8, 4, 6, 15, 11, 1, 10, 9, 3, 14, 5, 0, 12, 7},
+ {1, 15, 13, 8, 10, 3, 7, 4, 12, 5, 6, 11, 0, 14, 9, 2},
+ {7, 11, 4, 1, 9, 12, 14, 2, 0, 6, 10, 13, 15, 3, 5, 8},
+ {2, 1, 14, 7, 4, 10, 8, 13, 15, 12, 9, 0, 3, 5, 6, 11},
+ },
+}
+
+// Size of left rotation per round in each half of the key schedule
+var ksRotations = [16]uint8{1, 1, 2, 2, 2, 2, 2, 2, 1, 2, 2, 2, 2, 2, 2, 1}
diff --git a/src/crypto/des/des_test.go b/src/crypto/des/des_test.go
new file mode 100644
index 0000000..690a49f
--- /dev/null
+++ b/src/crypto/des/des_test.go
@@ -0,0 +1,1583 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package des
+
+import (
+ "bytes"
+ "testing"
+)
+
+type CryptTest struct {
+ key []byte
+ in []byte
+ out []byte
+}
+
+// some custom tests for DES
+var encryptDESTests = []CryptTest{
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x8c, 0xa6, 0x4d, 0xe9, 0xc1, 0xb1, 0x23, 0xa7}},
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0x35, 0x55, 0x50, 0xb2, 0x15, 0x0e, 0x24, 0x51}},
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0x61, 0x7b, 0x3a, 0x0c, 0xe8, 0xf0, 0x71, 0x00}},
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0x92, 0x31, 0xf2, 0x36, 0xff, 0x9a, 0xa9, 0x5c}},
+ {
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xca, 0xaa, 0xaf, 0x4d, 0xea, 0xf1, 0xdb, 0xae}},
+ {
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0x73, 0x59, 0xb2, 0x16, 0x3e, 0x4e, 0xdc, 0x58}},
+ {
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0x6d, 0xce, 0x0d, 0xc9, 0x00, 0x65, 0x56, 0xa3}},
+ {
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0x9e, 0x84, 0xc5, 0xf3, 0x17, 0x0f, 0x8e, 0xff}},
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xd5, 0xd4, 0x4f, 0xf7, 0x20, 0x68, 0x3d, 0x0d}},
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0x59, 0x73, 0x23, 0x56, 0xf3, 0x6f, 0xde, 0x06}},
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0x56, 0xcc, 0x09, 0xe7, 0xcf, 0xdc, 0x4c, 0xef}},
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0x12, 0xc6, 0x26, 0xaf, 0x05, 0x8b, 0x43, 0x3b}},
+ {
+ []byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xa6, 0x8c, 0xdc, 0xa9, 0x0c, 0x90, 0x21, 0xf9}},
+ {
+ []byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0x2a, 0x2b, 0xb0, 0x08, 0xdf, 0x97, 0xc2, 0xf2}},
+ {
+ []byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0xed, 0x39, 0xd9, 0x50, 0xfa, 0x74, 0xbc, 0xc4}},
+ {
+ []byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10},
+ []byte{0xa9, 0x33, 0xf6, 0x18, 0x30, 0x23, 0xb3, 0x10}},
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11},
+ []byte{0x17, 0x66, 0x8d, 0xfc, 0x72, 0x92, 0x53, 0x2d}},
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ []byte{0xb4, 0xfd, 0x23, 0x16, 0x47, 0xa5, 0xbe, 0xc0}},
+ {
+ []byte{0x0e, 0x32, 0x92, 0x32, 0xea, 0x6d, 0x0d, 0x73},
+ []byte{0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87, 0x87},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}},
+ {
+ []byte{0x73, 0x65, 0x63, 0x52, 0x33, 0x74, 0x24, 0x3b}, // "secR3t$;"
+ []byte{0x61, 0x20, 0x74, 0x65, 0x73, 0x74, 0x31, 0x32}, // "a test12"
+ []byte{0x37, 0x0d, 0xee, 0x2c, 0x1f, 0xb4, 0xf7, 0xa5}},
+ {
+ []byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68}, // "abcdefgh"
+ []byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68}, // "abcdefgh"
+ []byte{0x2a, 0x8d, 0x69, 0xde, 0x9d, 0x5f, 0xdf, 0xf9}},
+ {
+ []byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68}, // "abcdefgh"
+ []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}, // "12345678"
+ []byte{0x21, 0xc6, 0x0d, 0xa5, 0x34, 0x24, 0x8b, 0xce}},
+ {
+ []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}, // "12345678"
+ []byte{0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68}, // "abcdefgh"
+ []byte{0x94, 0xd4, 0x43, 0x6b, 0xc3, 0xb5, 0xb6, 0x93}},
+ {
+ []byte{0x1f, 0x79, 0x90, 0x5f, 0x88, 0x01, 0xc8, 0x88}, // random
+ []byte{0xc7, 0x46, 0x18, 0x73, 0xaf, 0x48, 0x5f, 0xb3}, // random
+ []byte{0xb0, 0x93, 0x50, 0x88, 0xf9, 0x92, 0x44, 0x6a}},
+ {
+ []byte{0xe6, 0xf4, 0xf2, 0xdb, 0x31, 0x42, 0x53, 0x01}, // random
+ []byte{0xff, 0x3d, 0x25, 0x50, 0x12, 0xe3, 0x4a, 0xc5}, // random
+ []byte{0x86, 0x08, 0xd3, 0xd1, 0x6c, 0x2f, 0xd2, 0x55}},
+ {
+ []byte{0x69, 0xc1, 0x9d, 0xc1, 0x15, 0xc5, 0xfb, 0x2b}, // random
+ []byte{0x1a, 0x22, 0x5c, 0xaf, 0x1f, 0x1d, 0xa3, 0xf9}, // random
+ []byte{0x64, 0xba, 0x31, 0x67, 0x56, 0x91, 0x1e, 0xa7}},
+ {
+ []byte{0x6e, 0x5e, 0xe2, 0x47, 0xc4, 0xbf, 0xf6, 0x51}, // random
+ []byte{0x11, 0xc9, 0x57, 0xff, 0x66, 0x89, 0x0e, 0xf0}, // random
+ []byte{0x94, 0xc5, 0x35, 0xb2, 0xc5, 0x8b, 0x39, 0x72}},
+}
+
+var weakKeyTests = []CryptTest{
+ {
+ []byte{0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ []byte{0x55, 0x74, 0xc0, 0xbd, 0x7c, 0xdf, 0xf7, 0x39}, // random
+ nil},
+ {
+ []byte{0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe, 0xfe},
+ []byte{0xe8, 0xe1, 0xa7, 0xc1, 0xde, 0x11, 0x89, 0xaa}, // random
+ nil},
+ {
+ []byte{0xe0, 0xe0, 0xe0, 0xe0, 0xf1, 0xf1, 0xf1, 0xf1},
+ []byte{0x50, 0x6a, 0x4b, 0x94, 0x3b, 0xed, 0x7d, 0xdc}, // random
+ nil},
+ {
+ []byte{0x1f, 0x1f, 0x1f, 0x1f, 0x0e, 0x0e, 0x0e, 0x0e},
+ []byte{0x88, 0x81, 0x56, 0x38, 0xec, 0x3b, 0x1c, 0x97}, // random
+ nil},
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x17, 0xa0, 0x83, 0x62, 0x32, 0xfe, 0x9a, 0x0b}, // random
+ nil},
+ {
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0xca, 0x8f, 0xca, 0x1f, 0x50, 0xc5, 0x7b, 0x49}, // random
+ nil},
+ {
+ []byte{0xe1, 0xe1, 0xe1, 0xe1, 0xf0, 0xf0, 0xf0, 0xf0},
+ []byte{0xb1, 0xea, 0xad, 0x7d, 0xe7, 0xc3, 0x7a, 0x43}, // random
+ nil},
+ {
+ []byte{0x1e, 0x1e, 0x1e, 0x1e, 0x0f, 0x0f, 0x0f, 0x0f},
+ []byte{0xae, 0x74, 0x7d, 0x6f, 0xef, 0x16, 0xbb, 0x81}, // random
+ nil},
+}
+
+var semiWeakKeyTests = []CryptTest{
+ // key and out contain the semi-weak key pair
+ {
+ []byte{0x01, 0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e},
+ []byte{0x12, 0xfa, 0x31, 0x16, 0xf9, 0xc5, 0x0a, 0xe4}, // random
+ []byte{0x1f, 0x01, 0x1f, 0x01, 0x0e, 0x01, 0x0e, 0x01}},
+ {
+ []byte{0x01, 0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1},
+ []byte{0xb0, 0x4c, 0x7a, 0xee, 0xd2, 0xe5, 0x4d, 0xb7}, // random
+ []byte{0xe0, 0x01, 0xe0, 0x01, 0xf1, 0x01, 0xf1, 0x01}},
+ {
+ []byte{0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe},
+ []byte{0xa4, 0x81, 0xcd, 0xb1, 0x64, 0x6f, 0xd3, 0xbc}, // random
+ []byte{0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01, 0xfe, 0x01}},
+ {
+ []byte{0x1f, 0xe0, 0x1f, 0xe0, 0x0e, 0xf1, 0x0e, 0xf1},
+ []byte{0xee, 0x27, 0xdd, 0x88, 0x4c, 0x22, 0xcd, 0xce}, // random
+ []byte{0xe0, 0x1f, 0xe0, 0x1f, 0xf1, 0x0e, 0xf1, 0x0e}},
+ {
+ []byte{0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e, 0xfe},
+ []byte{0x19, 0x3d, 0xcf, 0x97, 0x70, 0xfb, 0xab, 0xe1}, // random
+ []byte{0xfe, 0x1f, 0xfe, 0x1f, 0xfe, 0x0e, 0xfe, 0x0e}},
+ {
+ []byte{0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1, 0xfe},
+ []byte{0x7c, 0x82, 0x69, 0xe4, 0x1e, 0x86, 0x99, 0xd7}, // random
+ []byte{0xfe, 0xe0, 0xfe, 0xe0, 0xfe, 0xf1, 0xfe, 0xf1}},
+}
+
+// some custom tests for TripleDES
+var encryptTripleDESTests = []CryptTest{
+ {
+ []byte{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x92, 0x95, 0xb5, 0x9b, 0xb3, 0x84, 0x73, 0x6e}},
+ {
+ []byte{
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0xc1, 0x97, 0xf5, 0x58, 0x74, 0x8a, 0x20, 0xe7}},
+ {
+ []byte{
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x3e, 0x68, 0x0a, 0xa7, 0x8b, 0x75, 0xdf, 0x18}},
+ {
+ []byte{
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ []byte{0x6d, 0x6a, 0x4a, 0x64, 0x4c, 0x7b, 0x8c, 0x91}},
+ {
+ []byte{ // "abcdefgh12345678ABCDEFGH"
+ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
+ []byte{0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x30}, // "00000000"
+ []byte{0xe4, 0x61, 0xb7, 0x59, 0x68, 0x8b, 0xff, 0x66}},
+ {
+ []byte{ // "abcdefgh12345678ABCDEFGH"
+ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
+ []byte{0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38}, // "12345678"
+ []byte{0xdb, 0xd0, 0x92, 0xde, 0xf8, 0x34, 0xff, 0x58}},
+ {
+ []byte{ // "abcdefgh12345678ABCDEFGH"
+ 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68,
+ 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38,
+ 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48},
+ []byte{0xf0, 0xc5, 0x82, 0x22, 0xd3, 0xe6, 0x12, 0xd2}, // random
+ []byte{0xba, 0xe4, 0x41, 0xb1, 0x3c, 0x37, 0x4d, 0xf4}},
+ {
+ []byte{ // random
+ 0xd3, 0x7d, 0x45, 0xee, 0x22, 0xe9, 0xcf, 0x52,
+ 0xf4, 0x65, 0xa2, 0x4f, 0x70, 0xd1, 0x81, 0x8a,
+ 0x3d, 0xbe, 0x2f, 0x39, 0xc7, 0x71, 0xd2, 0xe9},
+ []byte{0x49, 0x53, 0xc3, 0xe9, 0x78, 0xdf, 0x9f, 0xaf}, // random
+ []byte{0x53, 0x40, 0x51, 0x24, 0xd8, 0x3c, 0xf9, 0x88}},
+ {
+ []byte{ // random
+ 0xcb, 0x10, 0x7d, 0xda, 0x7e, 0x96, 0x57, 0x0a,
+ 0xe8, 0xeb, 0xe8, 0x07, 0x8e, 0x87, 0xd3, 0x57,
+ 0xb2, 0x61, 0x12, 0xb8, 0x2a, 0x90, 0xb7, 0x2f},
+ []byte{0xa3, 0xc2, 0x60, 0xb1, 0x0b, 0xb7, 0x28, 0x6e}, // random
+ []byte{0x56, 0x73, 0x7d, 0xfb, 0xb5, 0xa1, 0xc3, 0xde}},
+}
+
+// NIST Special Publication 800-20, Appendix A
+// Key for use with Table A.1 tests
+var tableA1Key = []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+}
+
+// Table A.1 Resulting Ciphertext from the Variable Plaintext Known Answer Test
+var tableA1Tests = []CryptTest{
+ {nil, // 0
+ []byte{0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x95, 0xf8, 0xa5, 0xe5, 0xdd, 0x31, 0xd9, 0x00}},
+ {nil, // 1
+ []byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xdd, 0x7f, 0x12, 0x1c, 0xa5, 0x01, 0x56, 0x19}},
+ {nil, // 2
+ []byte{0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x2e, 0x86, 0x53, 0x10, 0x4f, 0x38, 0x34, 0xea}},
+ {nil, // 3
+ []byte{0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x4b, 0xd3, 0x88, 0xff, 0x6c, 0xd8, 0x1d, 0x4f}},
+ {nil, // 4
+ []byte{0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x20, 0xb9, 0xe7, 0x67, 0xb2, 0xfb, 0x14, 0x56}},
+ {nil, // 5
+ []byte{0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x55, 0x57, 0x93, 0x80, 0xd7, 0x71, 0x38, 0xef}},
+ {nil, // 6
+ []byte{0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x6c, 0xc5, 0xde, 0xfa, 0xaf, 0x04, 0x51, 0x2f}},
+ {nil, // 7
+ []byte{0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x0d, 0x9f, 0x27, 0x9b, 0xa5, 0xd8, 0x72, 0x60}},
+ {nil, // 8
+ []byte{0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xd9, 0x03, 0x1b, 0x02, 0x71, 0xbd, 0x5a, 0x0a}},
+ {nil, // 9
+ []byte{0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x42, 0x42, 0x50, 0xb3, 0x7c, 0x3d, 0xd9, 0x51}},
+ {nil, // 10
+ []byte{0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xb8, 0x06, 0x1b, 0x7e, 0xcd, 0x9a, 0x21, 0xe5}},
+ {nil, // 11
+ []byte{0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xf1, 0x5d, 0x0f, 0x28, 0x6b, 0x65, 0xbd, 0x28}},
+ {nil, // 12
+ []byte{0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xad, 0xd0, 0xcc, 0x8d, 0x6e, 0x5d, 0xeb, 0xa1}},
+ {nil, // 13
+ []byte{0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xe6, 0xd5, 0xf8, 0x27, 0x52, 0xad, 0x63, 0xd1}},
+ {nil, // 14
+ []byte{0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xec, 0xbf, 0xe3, 0xbd, 0x3f, 0x59, 0x1a, 0x5e}},
+ {nil, // 15
+ []byte{0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xf3, 0x56, 0x83, 0x43, 0x79, 0xd1, 0x65, 0xcd}},
+ {nil, // 16
+ []byte{0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x2b, 0x9f, 0x98, 0x2f, 0x20, 0x03, 0x7f, 0xa9}},
+ {nil, // 17
+ []byte{0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x88, 0x9d, 0xe0, 0x68, 0xa1, 0x6f, 0x0b, 0xe6}},
+ {nil, // 18
+ []byte{0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xe1, 0x9e, 0x27, 0x5d, 0x84, 0x6a, 0x12, 0x98}},
+ {nil, // 19
+ []byte{0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x32, 0x9a, 0x8e, 0xd5, 0x23, 0xd7, 0x1a, 0xec}},
+ {nil, // 20
+ []byte{0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xe7, 0xfc, 0xe2, 0x25, 0x57, 0xd2, 0x3c, 0x97}},
+ {nil, // 21
+ []byte{0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x12, 0xa9, 0xf5, 0x81, 0x7f, 0xf2, 0xd6, 0x5d}},
+ {nil, // 22
+ []byte{0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xa4, 0x84, 0xc3, 0xad, 0x38, 0xdc, 0x9c, 0x19}},
+ {nil, // 23
+ []byte{0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xfb, 0xe0, 0x0a, 0x8a, 0x1e, 0xf8, 0xad, 0x72}},
+ {nil, // 24
+ []byte{0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x75, 0x0d, 0x07, 0x94, 0x07, 0x52, 0x13, 0x63}},
+ {nil, // 25
+ []byte{0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x64, 0xfe, 0xed, 0x9c, 0x72, 0x4c, 0x2f, 0xaf}},
+ {nil, // 26
+ []byte{0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xf0, 0x2b, 0x26, 0x3b, 0x32, 0x8e, 0x2b, 0x60}},
+ {nil, // 27
+ []byte{0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00, 0x00},
+ []byte{0x9d, 0x64, 0x55, 0x5a, 0x9a, 0x10, 0xb8, 0x52}},
+ {nil, // 28
+ []byte{0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xd1, 0x06, 0xff, 0x0b, 0xed, 0x52, 0x55, 0xd7}},
+ {nil, // 29
+ []byte{0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xe1, 0x65, 0x2c, 0x6b, 0x13, 0x8c, 0x64, 0xa5}},
+ {nil, // 30
+ []byte{0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xe4, 0x28, 0x58, 0x11, 0x86, 0xec, 0x8f, 0x46}},
+ {nil, // 31
+ []byte{0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xae, 0xb5, 0xf5, 0xed, 0xe2, 0x2d, 0x1a, 0x36}},
+ {nil, // 32
+ []byte{0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00},
+ []byte{0xe9, 0x43, 0xd7, 0x56, 0x8a, 0xec, 0x0c, 0x5c}},
+ {nil, // 33
+ []byte{0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00, 0x00},
+ []byte{0xdf, 0x98, 0xc8, 0x27, 0x6f, 0x54, 0xb0, 0x4b}},
+ {nil, // 34
+ []byte{0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00},
+ []byte{0xb1, 0x60, 0xe4, 0x68, 0x0f, 0x6c, 0x69, 0x6f}},
+ {nil, // 35
+ []byte{0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x00},
+ []byte{0xfa, 0x07, 0x52, 0xb0, 0x7d, 0x9c, 0x4a, 0xb8}},
+ {nil, // 36
+ []byte{0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00, 0x00},
+ []byte{0xca, 0x3a, 0x2b, 0x03, 0x6d, 0xbc, 0x85, 0x02}},
+ {nil, // 37
+ []byte{0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00},
+ []byte{0x5e, 0x09, 0x05, 0x51, 0x7b, 0xb5, 0x9b, 0xcf}},
+ {nil, // 38
+ []byte{0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00, 0x00},
+ []byte{0x81, 0x4e, 0xeb, 0x3b, 0x91, 0xd9, 0x07, 0x26}},
+ {nil, // 39
+ []byte{0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00},
+ []byte{0x4d, 0x49, 0xdb, 0x15, 0x32, 0x91, 0x9c, 0x9f}},
+ {nil, // 40
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00},
+ []byte{0x25, 0xeb, 0x5f, 0xc3, 0xf8, 0xcf, 0x06, 0x21}},
+ {nil, // 41
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00, 0x00},
+ []byte{0xab, 0x6a, 0x20, 0xc0, 0x62, 0x0d, 0x1c, 0x6f}},
+ {nil, // 42
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00},
+ []byte{0x79, 0xe9, 0x0d, 0xbc, 0x98, 0xf9, 0x2c, 0xca}},
+ {nil, // 43
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00},
+ []byte{0x86, 0x6e, 0xce, 0xdd, 0x80, 0x72, 0xbb, 0x0e}},
+ {nil, // 44
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00, 0x00},
+ []byte{0x8b, 0x54, 0x53, 0x6f, 0x2f, 0x3e, 0x64, 0xa8}},
+ {nil, // 45
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00, 0x00},
+ []byte{0xea, 0x51, 0xd3, 0x97, 0x55, 0x95, 0xb8, 0x6b}},
+ {nil, // 46
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00, 0x00},
+ []byte{0xca, 0xff, 0xc6, 0xac, 0x45, 0x42, 0xde, 0x31}},
+ {nil, // 47
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00},
+ []byte{0x8d, 0xd4, 0x5a, 0x2d, 0xdf, 0x90, 0x79, 0x6c}},
+ {nil, // 48
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00},
+ []byte{0x10, 0x29, 0xd5, 0x5e, 0x88, 0x0e, 0xc2, 0xd0}},
+ {nil, // 49
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40, 0x00},
+ []byte{0x5d, 0x86, 0xcb, 0x23, 0x63, 0x9d, 0xbe, 0xa9}},
+ {nil, // 50
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x00},
+ []byte{0x1d, 0x1c, 0xa8, 0x53, 0xae, 0x7c, 0x0c, 0x5f}},
+ {nil, // 51
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00},
+ []byte{0xce, 0x33, 0x23, 0x29, 0x24, 0x8f, 0x32, 0x28}},
+ {nil, // 52
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08, 0x00},
+ []byte{0x84, 0x05, 0xd1, 0xab, 0xe2, 0x4f, 0xb9, 0x42}},
+ {nil, // 53
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04, 0x00},
+ []byte{0xe6, 0x43, 0xd7, 0x80, 0x90, 0xca, 0x42, 0x07}},
+ {nil, // 54
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02, 0x00},
+ []byte{0x48, 0x22, 0x1b, 0x99, 0x37, 0x74, 0x8a, 0x23}},
+ {nil, // 55
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00},
+ []byte{0xdd, 0x7c, 0x0b, 0xbd, 0x61, 0xfa, 0xfd, 0x54}},
+ {nil, // 56
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80},
+ []byte{0x2f, 0xbc, 0x29, 0x1a, 0x57, 0x0d, 0xb5, 0xc4}},
+ {nil, // 57
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x40},
+ []byte{0xe0, 0x7c, 0x30, 0xd7, 0xe4, 0xe2, 0x6e, 0x12}},
+ {nil, // 58
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20},
+ []byte{0x09, 0x53, 0xe2, 0x25, 0x8e, 0x8e, 0x90, 0xa1}},
+ {nil, // 59
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10},
+ []byte{0x5b, 0x71, 0x1b, 0xc4, 0xce, 0xeb, 0xf2, 0xee}},
+ {nil, // 60
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08},
+ []byte{0xcc, 0x08, 0x3f, 0x1e, 0x6d, 0x9e, 0x85, 0xf6}},
+ {nil, // 61
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x04},
+ []byte{0xd2, 0xfd, 0x88, 0x67, 0xd5, 0x0d, 0x2d, 0xfe}},
+ {nil, // 62
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
+ []byte{0x06, 0xe7, 0xea, 0x22, 0xce, 0x92, 0x70, 0x8f}},
+ {nil, // 63
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+ []byte{0x16, 0x6b, 0x40, 0xb4, 0x4a, 0xba, 0x4b, 0xd6}},
+}
+
+// Plaintext for use with Table A.2 tests
+var tableA2Plaintext = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+
+// Table A.2 Resulting Ciphertext from the Variable Key Known Answer Test
+var tableA2Tests = []CryptTest{
+ { // 0
+ []byte{
+ 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x95, 0xa8, 0xd7, 0x28, 0x13, 0xda, 0xa9, 0x4d}},
+ { // 1
+ []byte{
+ 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x0e, 0xec, 0x14, 0x87, 0xdd, 0x8c, 0x26, 0xd5}},
+ { // 2
+ []byte{
+ 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x7a, 0xd1, 0x6f, 0xfb, 0x79, 0xc4, 0x59, 0x26}},
+ { // 3
+ []byte{
+ 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xd3, 0x74, 0x62, 0x94, 0xca, 0x6a, 0x6c, 0xf3}},
+ { // 4
+ []byte{
+ 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x80, 0x9f, 0x5f, 0x87, 0x3c, 0x1f, 0xd7, 0x61}},
+ { // 5
+ []byte{
+ 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xc0, 0x2f, 0xaf, 0xfe, 0xc9, 0x89, 0xd1, 0xfc}},
+ { // 6
+ []byte{
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x46, 0x15, 0xaa, 0x1d, 0x33, 0xe7, 0x2f, 0x10}},
+ { // 7
+ []byte{
+ 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x20, 0x55, 0x12, 0x33, 0x50, 0xc0, 0x08, 0x58}},
+ { // 8
+ []byte{
+ 0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xdf, 0x3b, 0x99, 0xd6, 0x57, 0x73, 0x97, 0xc8}},
+ { // 9
+ []byte{
+ 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x31, 0xfe, 0x17, 0x36, 0x9b, 0x52, 0x88, 0xc9}},
+ { // 10
+ []byte{
+ 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xdf, 0xdd, 0x3c, 0xc6, 0x4d, 0xae, 0x16, 0x42}},
+ { // 11
+ []byte{
+ 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x17, 0x8c, 0x83, 0xce, 0x2b, 0x39, 0x9d, 0x94}},
+ { // 12
+ []byte{
+ 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x50, 0xf6, 0x36, 0x32, 0x4a, 0x9b, 0x7f, 0x80}},
+ { // 13
+ []byte{
+ 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xa8, 0x46, 0x8e, 0xe3, 0xbc, 0x18, 0xf0, 0x6d}},
+ { // 14
+ []byte{
+ 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xa2, 0xdc, 0x9e, 0x92, 0xfd, 0x3c, 0xde, 0x92}},
+ { // 15
+ []byte{
+ 0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xca, 0xc0, 0x9f, 0x79, 0x7d, 0x03, 0x12, 0x87}},
+ { // 16
+ []byte{
+ 0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x90, 0xba, 0x68, 0x0b, 0x22, 0xae, 0xb5, 0x25}},
+ { // 17
+ []byte{
+ 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xce, 0x7a, 0x24, 0xf3, 0x50, 0xe2, 0x80, 0xb6}},
+ { // 18
+ []byte{
+ 0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x88, 0x2b, 0xff, 0x0a, 0xa0, 0x1a, 0x0b, 0x87}},
+ { // 19
+ []byte{
+ 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x25, 0x61, 0x02, 0x88, 0x92, 0x45, 0x11, 0xc2}},
+ { // 20
+ []byte{
+ 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xc7, 0x15, 0x16, 0xc2, 0x9c, 0x75, 0xd1, 0x70}},
+ { // 21
+ []byte{
+ 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x51, 0x99, 0xc2, 0x9a, 0x52, 0xc9, 0xf0, 0x59}},
+ { // 22
+ []byte{
+ 0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xc2, 0x2f, 0x0a, 0x29, 0x4a, 0x71, 0xf2, 0x9f}},
+ { // 23
+ []byte{
+ 0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xee, 0x37, 0x14, 0x83, 0x71, 0x4c, 0x02, 0xea}},
+ { // 24
+ []byte{
+ 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xa8, 0x1f, 0xbd, 0x44, 0x8f, 0x9e, 0x52, 0x2f}},
+ { // 25
+ []byte{
+ 0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x4f, 0x64, 0x4c, 0x92, 0xe1, 0x92, 0xdf, 0xed}},
+ { // 26
+ []byte{
+ 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x1a, 0xfa, 0x9a, 0x66, 0xa6, 0xdf, 0x92, 0xae}},
+ { // 27
+ []byte{
+ 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xb3, 0xc1, 0xcc, 0x71, 0x5c, 0xb8, 0x79, 0xd8}},
+ { // 28
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x19, 0xd0, 0x32, 0xe6, 0x4a, 0xb0, 0xbd, 0x8b}},
+ { // 29
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x3c, 0xfa, 0xa7, 0xa7, 0xdc, 0x87, 0x20, 0xdc}},
+ { // 30
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0xb7, 0x26, 0x5f, 0x7f, 0x44, 0x7a, 0xc6, 0xf3}},
+ { // 31
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x9d, 0xb7, 0x3b, 0x3c, 0x0d, 0x16, 0x3f, 0x54}},
+ { // 32
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x81, 0x81, 0xb6, 0x5b, 0xab, 0xf4, 0xa9, 0x75}},
+ { // 33
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x93, 0xc9, 0xb6, 0x40, 0x42, 0xea, 0xa2, 0x40}},
+ { // 34
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01, 0x01},
+ nil,
+ []byte{0x55, 0x70, 0x53, 0x08, 0x29, 0x70, 0x55, 0x92}},
+ { // 35
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01, 0x01},
+ nil,
+ []byte{0x86, 0x38, 0x80, 0x9e, 0x87, 0x87, 0x87, 0xa0}},
+ { // 36
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01, 0x01},
+ nil,
+ []byte{0x41, 0xb9, 0xa7, 0x9a, 0xf7, 0x9a, 0xc2, 0x08}},
+ { // 37
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01, 0x01},
+ nil,
+ []byte{0x7a, 0x9b, 0xe4, 0x2f, 0x20, 0x09, 0xa8, 0x92}},
+ { // 38
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01, 0x01},
+ nil,
+ []byte{0x29, 0x03, 0x8d, 0x56, 0xba, 0x6d, 0x27, 0x45}},
+ { // 39
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01, 0x01},
+ nil,
+ []byte{0x54, 0x95, 0xc6, 0xab, 0xf1, 0xe5, 0xdf, 0x51}},
+ { // 40
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01},
+ nil,
+ []byte{0xae, 0x13, 0xdb, 0xd5, 0x61, 0x48, 0x89, 0x33}},
+ { // 41
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01, 0x01},
+ nil,
+ []byte{0x02, 0x4d, 0x1f, 0xfa, 0x89, 0x04, 0xe3, 0x89}},
+ { // 42
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80, 0x01},
+ nil,
+ []byte{0xd1, 0x39, 0x97, 0x12, 0xf9, 0x9b, 0xf0, 0x2e}},
+ { // 43
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40, 0x01},
+ nil,
+ []byte{0x14, 0xc1, 0xd7, 0xc1, 0xcf, 0xfe, 0xc7, 0x9e}},
+ { // 44
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20, 0x01},
+ nil,
+ []byte{0x1d, 0xe5, 0x27, 0x9d, 0xae, 0x3b, 0xed, 0x6f}},
+ { // 45
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10, 0x01},
+ nil,
+ []byte{0xe9, 0x41, 0xa3, 0x3f, 0x85, 0x50, 0x13, 0x03}},
+ { // 46
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08, 0x01},
+ nil,
+ []byte{0xda, 0x99, 0xdb, 0xbc, 0x9a, 0x03, 0xf3, 0x79}},
+ { // 47
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04, 0x01},
+ nil,
+ []byte{0xb7, 0xfc, 0x92, 0xf9, 0x1d, 0x8e, 0x92, 0xe9}},
+ { // 48
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02, 0x01},
+ nil,
+ []byte{0xae, 0x8e, 0x5c, 0xaa, 0x3c, 0xa0, 0x4e, 0x85}},
+ { // 49
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x80},
+ nil,
+ []byte{0x9c, 0xc6, 0x2d, 0xf4, 0x3b, 0x6e, 0xed, 0x74}},
+ { // 50
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x40},
+ nil,
+ []byte{0xd8, 0x63, 0xdb, 0xb5, 0xc5, 0x9a, 0x91, 0xa0}},
+ { // 50
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x20},
+ nil,
+ []byte{0xa1, 0xab, 0x21, 0x90, 0x54, 0x5b, 0x91, 0xd7}},
+ { // 52
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x10},
+ nil,
+ []byte{0x08, 0x75, 0x04, 0x1e, 0x64, 0xc5, 0x70, 0xf7}},
+ { // 53
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x08},
+ nil,
+ []byte{0x5a, 0x59, 0x45, 0x28, 0xbe, 0xbe, 0xf1, 0xcc}},
+ { // 54
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x04},
+ nil,
+ []byte{0xfc, 0xdb, 0x32, 0x91, 0xde, 0x21, 0xf0, 0xc0}},
+ { // 55
+ []byte{
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02,
+ 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x01, 0x02},
+ nil,
+ []byte{0x86, 0x9e, 0xfd, 0x7f, 0x9f, 0x26, 0x5a, 0x09}},
+}
+
+// Plaintext for use with Table A.3 tests
+var tableA3Plaintext = []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}
+
+// Table A.3 Values To Be Used for the Permutation Operation Known Answer Test
+var tableA3Tests = []CryptTest{
+ { // 0
+ []byte{
+ 0x10, 0x46, 0x91, 0x34, 0x89, 0x98, 0x01, 0x31,
+ 0x10, 0x46, 0x91, 0x34, 0x89, 0x98, 0x01, 0x31,
+ 0x10, 0x46, 0x91, 0x34, 0x89, 0x98, 0x01, 0x31,
+ },
+ nil,
+ []byte{0x88, 0xd5, 0x5e, 0x54, 0xf5, 0x4c, 0x97, 0xb4}},
+ { // 1
+ []byte{
+ 0x10, 0x07, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
+ 0x10, 0x07, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
+ 0x10, 0x07, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
+ },
+ nil,
+ []byte{0x0c, 0x0c, 0xc0, 0x0c, 0x83, 0xea, 0x48, 0xfd}},
+ { // 2
+ []byte{
+ 0x10, 0x07, 0x10, 0x34, 0xc8, 0x98, 0x01, 0x20,
+ 0x10, 0x07, 0x10, 0x34, 0xc8, 0x98, 0x01, 0x20,
+ 0x10, 0x07, 0x10, 0x34, 0xc8, 0x98, 0x01, 0x20,
+ },
+ nil,
+ []byte{0x83, 0xbc, 0x8e, 0xf3, 0xa6, 0x57, 0x01, 0x83}},
+ { // 3
+ []byte{
+ 0x10, 0x46, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
+ 0x10, 0x46, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
+ 0x10, 0x46, 0x10, 0x34, 0x89, 0x98, 0x80, 0x20,
+ },
+ nil,
+ []byte{0xdf, 0x72, 0x5d, 0xca, 0xd9, 0x4e, 0xa2, 0xe9}},
+ { // 4
+ []byte{
+ 0x10, 0x86, 0x91, 0x15, 0x19, 0x19, 0x01, 0x01,
+ 0x10, 0x86, 0x91, 0x15, 0x19, 0x19, 0x01, 0x01,
+ 0x10, 0x86, 0x91, 0x15, 0x19, 0x19, 0x01, 0x01,
+ },
+ nil,
+ []byte{0xe6, 0x52, 0xb5, 0x3b, 0x55, 0x0b, 0xe8, 0xb0}},
+ { // 5
+ []byte{
+ 0x10, 0x86, 0x91, 0x15, 0x19, 0x58, 0x01, 0x01,
+ 0x10, 0x86, 0x91, 0x15, 0x19, 0x58, 0x01, 0x01,
+ 0x10, 0x86, 0x91, 0x15, 0x19, 0x58, 0x01, 0x01,
+ },
+ nil,
+ []byte{0xaf, 0x52, 0x71, 0x20, 0xc4, 0x85, 0xcb, 0xb0}},
+ { // 6
+ []byte{
+ 0x51, 0x07, 0xb0, 0x15, 0x19, 0x58, 0x01, 0x01,
+ 0x51, 0x07, 0xb0, 0x15, 0x19, 0x58, 0x01, 0x01,
+ 0x51, 0x07, 0xb0, 0x15, 0x19, 0x58, 0x01, 0x01,
+ },
+ nil,
+ []byte{0x0f, 0x04, 0xce, 0x39, 0x3d, 0xb9, 0x26, 0xd5}},
+ { // 7
+ []byte{
+ 0x10, 0x07, 0xb0, 0x15, 0x19, 0x19, 0x01, 0x01,
+ 0x10, 0x07, 0xb0, 0x15, 0x19, 0x19, 0x01, 0x01,
+ 0x10, 0x07, 0xb0, 0x15, 0x19, 0x19, 0x01, 0x01,
+ },
+ nil,
+ []byte{0xc9, 0xf0, 0x0f, 0xfc, 0x74, 0x07, 0x90, 0x67}},
+ { // 8
+ []byte{
+ 0x31, 0x07, 0x91, 0x54, 0x98, 0x08, 0x01, 0x01,
+ 0x31, 0x07, 0x91, 0x54, 0x98, 0x08, 0x01, 0x01,
+ 0x31, 0x07, 0x91, 0x54, 0x98, 0x08, 0x01, 0x01,
+ },
+ nil,
+ []byte{0x7c, 0xfd, 0x82, 0xa5, 0x93, 0x25, 0x2b, 0x4e}},
+ { // 9
+ []byte{
+ 0x31, 0x07, 0x91, 0x94, 0x98, 0x08, 0x01, 0x01,
+ 0x31, 0x07, 0x91, 0x94, 0x98, 0x08, 0x01, 0x01,
+ 0x31, 0x07, 0x91, 0x94, 0x98, 0x08, 0x01, 0x01,
+ },
+ nil,
+ []byte{0xcb, 0x49, 0xa2, 0xf9, 0xe9, 0x13, 0x63, 0xe3}},
+ { // 10
+ []byte{
+ 0x10, 0x07, 0x91, 0x15, 0xb9, 0x08, 0x01, 0x40,
+ 0x10, 0x07, 0x91, 0x15, 0xb9, 0x08, 0x01, 0x40,
+ 0x10, 0x07, 0x91, 0x15, 0xb9, 0x08, 0x01, 0x40,
+ },
+ nil,
+ []byte{0x00, 0xb5, 0x88, 0xbe, 0x70, 0xd2, 0x3f, 0x56}},
+ { // 11
+ []byte{
+ 0x31, 0x07, 0x91, 0x15, 0x98, 0x08, 0x01, 0x40,
+ 0x31, 0x07, 0x91, 0x15, 0x98, 0x08, 0x01, 0x40,
+ 0x31, 0x07, 0x91, 0x15, 0x98, 0x08, 0x01, 0x40,
+ },
+ nil,
+ []byte{0x40, 0x6a, 0x9a, 0x6a, 0xb4, 0x33, 0x99, 0xae}},
+ { // 12
+ []byte{
+ 0x10, 0x07, 0xd0, 0x15, 0x89, 0x98, 0x01, 0x01,
+ 0x10, 0x07, 0xd0, 0x15, 0x89, 0x98, 0x01, 0x01,
+ 0x10, 0x07, 0xd0, 0x15, 0x89, 0x98, 0x01, 0x01,
+ },
+ nil,
+ []byte{0x6c, 0xb7, 0x73, 0x61, 0x1d, 0xca, 0x9a, 0xda}},
+ { // 13
+ []byte{
+ 0x91, 0x07, 0x91, 0x15, 0x89, 0x98, 0x01, 0x01,
+ 0x91, 0x07, 0x91, 0x15, 0x89, 0x98, 0x01, 0x01,
+ 0x91, 0x07, 0x91, 0x15, 0x89, 0x98, 0x01, 0x01,
+ },
+ nil,
+ []byte{0x67, 0xfd, 0x21, 0xc1, 0x7d, 0xbb, 0x5d, 0x70}},
+ { // 14
+ []byte{
+ 0x91, 0x07, 0xd0, 0x15, 0x89, 0x19, 0x01, 0x01,
+ 0x91, 0x07, 0xd0, 0x15, 0x89, 0x19, 0x01, 0x01,
+ 0x91, 0x07, 0xd0, 0x15, 0x89, 0x19, 0x01, 0x01,
+ },
+ nil,
+ []byte{0x95, 0x92, 0xcb, 0x41, 0x10, 0x43, 0x07, 0x87}},
+ { // 15
+ []byte{
+ 0x10, 0x07, 0xd0, 0x15, 0x98, 0x98, 0x01, 0x20,
+ 0x10, 0x07, 0xd0, 0x15, 0x98, 0x98, 0x01, 0x20,
+ 0x10, 0x07, 0xd0, 0x15, 0x98, 0x98, 0x01, 0x20,
+ },
+ nil,
+ []byte{0xa6, 0xb7, 0xff, 0x68, 0xa3, 0x18, 0xdd, 0xd3}},
+ { // 16
+ []byte{
+ 0x10, 0x07, 0x94, 0x04, 0x98, 0x19, 0x01, 0x01,
+ 0x10, 0x07, 0x94, 0x04, 0x98, 0x19, 0x01, 0x01,
+ 0x10, 0x07, 0x94, 0x04, 0x98, 0x19, 0x01, 0x01,
+ },
+ nil,
+ []byte{0x4d, 0x10, 0x21, 0x96, 0xc9, 0x14, 0xca, 0x16}},
+ { // 17
+ []byte{
+ 0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x04, 0x01,
+ 0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x04, 0x01,
+ 0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x04, 0x01,
+ },
+ nil,
+ []byte{0x2d, 0xfa, 0x9f, 0x45, 0x73, 0x59, 0x49, 0x65}},
+ { // 18
+ []byte{
+ 0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x01, 0x01,
+ 0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x01, 0x01,
+ 0x01, 0x07, 0x91, 0x04, 0x91, 0x19, 0x01, 0x01,
+ },
+ nil,
+ []byte{0xb4, 0x66, 0x04, 0x81, 0x6c, 0x0e, 0x07, 0x74}},
+ { // 19
+ []byte{
+ 0x01, 0x07, 0x94, 0x04, 0x91, 0x19, 0x04, 0x01,
+ 0x01, 0x07, 0x94, 0x04, 0x91, 0x19, 0x04, 0x01,
+ 0x01, 0x07, 0x94, 0x04, 0x91, 0x19, 0x04, 0x01,
+ },
+ nil,
+ []byte{0x6e, 0x7e, 0x62, 0x21, 0xa4, 0xf3, 0x4e, 0x87}},
+ { // 20
+ []byte{
+ 0x19, 0x07, 0x92, 0x10, 0x98, 0x1a, 0x01, 0x01,
+ 0x19, 0x07, 0x92, 0x10, 0x98, 0x1a, 0x01, 0x01,
+ 0x19, 0x07, 0x92, 0x10, 0x98, 0x1a, 0x01, 0x01,
+ },
+ nil,
+ []byte{0xaa, 0x85, 0xe7, 0x46, 0x43, 0x23, 0x31, 0x99}},
+ { // 21
+ []byte{
+ 0x10, 0x07, 0x91, 0x19, 0x98, 0x19, 0x08, 0x01,
+ 0x10, 0x07, 0x91, 0x19, 0x98, 0x19, 0x08, 0x01,
+ 0x10, 0x07, 0x91, 0x19, 0x98, 0x19, 0x08, 0x01,
+ },
+ nil,
+ []byte{0x2e, 0x5a, 0x19, 0xdb, 0x4d, 0x19, 0x62, 0xd6}},
+ { // 22
+ []byte{
+ 0x10, 0x07, 0x91, 0x19, 0x98, 0x1a, 0x08, 0x01,
+ 0x10, 0x07, 0x91, 0x19, 0x98, 0x1a, 0x08, 0x01,
+ 0x10, 0x07, 0x91, 0x19, 0x98, 0x1a, 0x08, 0x01,
+ },
+ nil,
+ []byte{0x23, 0xa8, 0x66, 0xa8, 0x09, 0xd3, 0x08, 0x94}},
+ { // 23
+ []byte{
+ 0x10, 0x07, 0x92, 0x10, 0x98, 0x19, 0x01, 0x01,
+ 0x10, 0x07, 0x92, 0x10, 0x98, 0x19, 0x01, 0x01,
+ 0x10, 0x07, 0x92, 0x10, 0x98, 0x19, 0x01, 0x01,
+ },
+ nil,
+ []byte{0xd8, 0x12, 0xd9, 0x61, 0xf0, 0x17, 0xd3, 0x20}},
+ { // 24
+ []byte{
+ 0x10, 0x07, 0x91, 0x15, 0x98, 0x19, 0x01, 0x0b,
+ 0x10, 0x07, 0x91, 0x15, 0x98, 0x19, 0x01, 0x0b,
+ 0x10, 0x07, 0x91, 0x15, 0x98, 0x19, 0x01, 0x0b,
+ },
+ nil,
+ []byte{0x05, 0x56, 0x05, 0x81, 0x6e, 0x58, 0x60, 0x8f}},
+ { // 25
+ []byte{
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x01,
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x01,
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x01,
+ },
+ nil,
+ []byte{0xab, 0xd8, 0x8e, 0x8b, 0x1b, 0x77, 0x16, 0xf1}},
+ { // 26
+ []byte{
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x02,
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x02,
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x02,
+ },
+ nil,
+ []byte{0x53, 0x7a, 0xc9, 0x5b, 0xe6, 0x9d, 0xa1, 0xe1}},
+ { // 27
+ []byte{
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x08,
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x08,
+ 0x10, 0x04, 0x80, 0x15, 0x98, 0x19, 0x01, 0x08,
+ },
+ nil,
+ []byte{0xae, 0xd0, 0xf6, 0xae, 0x3c, 0x25, 0xcd, 0xd8}},
+ { // 28
+ []byte{
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x01, 0x04,
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x01, 0x04,
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x01, 0x04,
+ },
+ nil,
+ []byte{0xb3, 0xe3, 0x5a, 0x5e, 0xe5, 0x3e, 0x7b, 0x8d}},
+ { // 29
+ []byte{
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x19, 0x01, 0x04,
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x19, 0x01, 0x04,
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x19, 0x01, 0x04,
+ },
+ nil,
+ []byte{0x61, 0xc7, 0x9c, 0x71, 0x92, 0x1a, 0x2e, 0xf8}},
+ { // 30
+ []byte{
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x02, 0x01,
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x02, 0x01,
+ 0x10, 0x02, 0x91, 0x15, 0x98, 0x10, 0x02, 0x01,
+ },
+ nil,
+ []byte{0xe2, 0xf5, 0x72, 0x8f, 0x09, 0x95, 0x01, 0x3c}},
+ { // 31
+ []byte{
+ 0x10, 0x02, 0x91, 0x16, 0x98, 0x10, 0x01, 0x01,
+ 0x10, 0x02, 0x91, 0x16, 0x98, 0x10, 0x01, 0x01,
+ 0x10, 0x02, 0x91, 0x16, 0x98, 0x10, 0x01, 0x01,
+ },
+ nil,
+ []byte{0x1a, 0xea, 0xc3, 0x9a, 0x61, 0xf0, 0xa4, 0x64}},
+}
+
+// Table A.4 Values To Be Used for the Substitution Table Known Answer Test
+var tableA4Tests = []CryptTest{
+ { // 0
+ []byte{
+ 0x7c, 0xa1, 0x10, 0x45, 0x4a, 0x1a, 0x6e, 0x57,
+ 0x7c, 0xa1, 0x10, 0x45, 0x4a, 0x1a, 0x6e, 0x57,
+ 0x7c, 0xa1, 0x10, 0x45, 0x4a, 0x1a, 0x6e, 0x57},
+ []byte{0x01, 0xa1, 0xd6, 0xd0, 0x39, 0x77, 0x67, 0x42},
+ []byte{0x69, 0x0f, 0x5b, 0x0d, 0x9a, 0x26, 0x93, 0x9b}},
+ { // 1
+ []byte{
+ 0x01, 0x31, 0xd9, 0x61, 0x9d, 0xc1, 0x37, 0x6e,
+ 0x01, 0x31, 0xd9, 0x61, 0x9d, 0xc1, 0x37, 0x6e,
+ 0x01, 0x31, 0xd9, 0x61, 0x9d, 0xc1, 0x37, 0x6e},
+ []byte{0x5c, 0xd5, 0x4c, 0xa8, 0x3d, 0xef, 0x57, 0xda},
+ []byte{0x7a, 0x38, 0x9d, 0x10, 0x35, 0x4b, 0xd2, 0x71}},
+ { // 2
+ []byte{
+ 0x07, 0xa1, 0x13, 0x3e, 0x4a, 0x0b, 0x26, 0x86,
+ 0x07, 0xa1, 0x13, 0x3e, 0x4a, 0x0b, 0x26, 0x86,
+ 0x07, 0xa1, 0x13, 0x3e, 0x4a, 0x0b, 0x26, 0x86},
+ []byte{0x02, 0x48, 0xd4, 0x38, 0x06, 0xf6, 0x71, 0x72},
+ []byte{0x86, 0x8e, 0xbb, 0x51, 0xca, 0xb4, 0x59, 0x9a}},
+ { // 3
+ []byte{
+ 0x38, 0x49, 0x67, 0x4c, 0x26, 0x02, 0x31, 0x9e,
+ 0x38, 0x49, 0x67, 0x4c, 0x26, 0x02, 0x31, 0x9e,
+ 0x38, 0x49, 0x67, 0x4c, 0x26, 0x02, 0x31, 0x9e},
+ []byte{0x51, 0x45, 0x4b, 0x58, 0x2d, 0xdf, 0x44, 0x0a},
+ []byte{0x71, 0x78, 0x87, 0x6e, 0x01, 0xf1, 0x9b, 0x2a}},
+ { // 4
+ []byte{
+ 0x04, 0xb9, 0x15, 0xba, 0x43, 0xfe, 0xb5, 0xb6,
+ 0x04, 0xb9, 0x15, 0xba, 0x43, 0xfe, 0xb5, 0xb6,
+ 0x04, 0xb9, 0x15, 0xba, 0x43, 0xfe, 0xb5, 0xb6},
+ []byte{0x42, 0xfd, 0x44, 0x30, 0x59, 0x57, 0x7f, 0xa2},
+ []byte{0xaf, 0x37, 0xfb, 0x42, 0x1f, 0x8c, 0x40, 0x95}},
+ { // 5
+ []byte{
+ 0x01, 0x13, 0xb9, 0x70, 0xfd, 0x34, 0xf2, 0xce,
+ 0x01, 0x13, 0xb9, 0x70, 0xfd, 0x34, 0xf2, 0xce,
+ 0x01, 0x13, 0xb9, 0x70, 0xfd, 0x34, 0xf2, 0xce},
+ []byte{0x05, 0x9b, 0x5e, 0x08, 0x51, 0xcf, 0x14, 0x3a},
+ []byte{0x86, 0xa5, 0x60, 0xf1, 0x0e, 0xc6, 0xd8, 0x5b}},
+ { // 6
+ []byte{
+ 0x01, 0x70, 0xf1, 0x75, 0x46, 0x8f, 0xb5, 0xe6,
+ 0x01, 0x70, 0xf1, 0x75, 0x46, 0x8f, 0xb5, 0xe6,
+ 0x01, 0x70, 0xf1, 0x75, 0x46, 0x8f, 0xb5, 0xe6},
+ []byte{0x07, 0x56, 0xd8, 0xe0, 0x77, 0x47, 0x61, 0xd2},
+ []byte{0x0c, 0xd3, 0xda, 0x02, 0x00, 0x21, 0xdc, 0x09}},
+ { // 7
+ []byte{
+ 0x43, 0x29, 0x7f, 0xad, 0x38, 0xe3, 0x73, 0xfe,
+ 0x43, 0x29, 0x7f, 0xad, 0x38, 0xe3, 0x73, 0xfe,
+ 0x43, 0x29, 0x7f, 0xad, 0x38, 0xe3, 0x73, 0xfe},
+ []byte{0x76, 0x25, 0x14, 0xb8, 0x29, 0xbf, 0x48, 0x6a},
+ []byte{0xea, 0x67, 0x6b, 0x2c, 0xb7, 0xdb, 0x2b, 0x7a}},
+ { // 8
+ []byte{
+ 0x07, 0xa7, 0x13, 0x70, 0x45, 0xda, 0x2a, 0x16,
+ 0x07, 0xa7, 0x13, 0x70, 0x45, 0xda, 0x2a, 0x16,
+ 0x07, 0xa7, 0x13, 0x70, 0x45, 0xda, 0x2a, 0x16},
+ []byte{0x3b, 0xdd, 0x11, 0x90, 0x49, 0x37, 0x28, 0x02},
+ []byte{0xdf, 0xd6, 0x4a, 0x81, 0x5c, 0xaf, 0x1a, 0x0f}},
+ { // 9
+ []byte{
+ 0x04, 0x68, 0x91, 0x04, 0xc2, 0xfd, 0x3b, 0x2f,
+ 0x04, 0x68, 0x91, 0x04, 0xc2, 0xfd, 0x3b, 0x2f,
+ 0x04, 0x68, 0x91, 0x04, 0xc2, 0xfd, 0x3b, 0x2f},
+ []byte{0x26, 0x95, 0x5f, 0x68, 0x35, 0xaf, 0x60, 0x9a},
+ []byte{0x5c, 0x51, 0x3c, 0x9c, 0x48, 0x86, 0xc0, 0x88}},
+ { // 10
+ []byte{
+ 0x37, 0xd0, 0x6b, 0xb5, 0x16, 0xcb, 0x75, 0x46,
+ 0x37, 0xd0, 0x6b, 0xb5, 0x16, 0xcb, 0x75, 0x46,
+ 0x37, 0xd0, 0x6b, 0xb5, 0x16, 0xcb, 0x75, 0x46},
+ []byte{0x16, 0x4d, 0x5e, 0x40, 0x4f, 0x27, 0x52, 0x32},
+ []byte{0x0a, 0x2a, 0xee, 0xae, 0x3f, 0xf4, 0xab, 0x77}},
+ { // 11
+ []byte{
+ 0x1f, 0x08, 0x26, 0x0d, 0x1a, 0xc2, 0x46, 0x5e,
+ 0x1f, 0x08, 0x26, 0x0d, 0x1a, 0xc2, 0x46, 0x5e,
+ 0x1f, 0x08, 0x26, 0x0d, 0x1a, 0xc2, 0x46, 0x5e},
+ []byte{0x6b, 0x05, 0x6e, 0x18, 0x75, 0x9f, 0x5c, 0xca},
+ []byte{0xef, 0x1b, 0xf0, 0x3e, 0x5d, 0xfa, 0x57, 0x5a}},
+ { // 12
+ []byte{
+ 0x58, 0x40, 0x23, 0x64, 0x1a, 0xba, 0x61, 0x76,
+ 0x58, 0x40, 0x23, 0x64, 0x1a, 0xba, 0x61, 0x76,
+ 0x58, 0x40, 0x23, 0x64, 0x1a, 0xba, 0x61, 0x76},
+ []byte{0x00, 0x4b, 0xd6, 0xef, 0x09, 0x17, 0x60, 0x62},
+ []byte{0x88, 0xbf, 0x0d, 0xb6, 0xd7, 0x0d, 0xee, 0x56}},
+ { // 13
+ []byte{
+ 0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xb0, 0x07,
+ 0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xb0, 0x07,
+ 0x02, 0x58, 0x16, 0x16, 0x46, 0x29, 0xb0, 0x07},
+ []byte{0x48, 0x0d, 0x39, 0x00, 0x6e, 0xe7, 0x62, 0xf2},
+ []byte{0xa1, 0xf9, 0x91, 0x55, 0x41, 0x02, 0x0b, 0x56}},
+ { // 14
+ []byte{
+ 0x49, 0x79, 0x3e, 0xbc, 0x79, 0xb3, 0x25, 0x8f,
+ 0x49, 0x79, 0x3e, 0xbc, 0x79, 0xb3, 0x25, 0x8f,
+ 0x49, 0x79, 0x3e, 0xbc, 0x79, 0xb3, 0x25, 0x8f},
+ []byte{0x43, 0x75, 0x40, 0xc8, 0x69, 0x8f, 0x3c, 0xfa},
+ []byte{0x6f, 0xbf, 0x1c, 0xaf, 0xcf, 0xfd, 0x05, 0x56}},
+ { // 15
+ []byte{
+ 0x4f, 0xb0, 0x5e, 0x15, 0x15, 0xab, 0x73, 0xa7,
+ 0x4f, 0xb0, 0x5e, 0x15, 0x15, 0xab, 0x73, 0xa7,
+ 0x4f, 0xb0, 0x5e, 0x15, 0x15, 0xab, 0x73, 0xa7},
+ []byte{0x07, 0x2d, 0x43, 0xa0, 0x77, 0x07, 0x52, 0x92},
+ []byte{0x2f, 0x22, 0xe4, 0x9b, 0xab, 0x7c, 0xa1, 0xac}},
+ { // 16
+ []byte{
+ 0x49, 0xe9, 0x5d, 0x6d, 0x4c, 0xa2, 0x29, 0xbf,
+ 0x49, 0xe9, 0x5d, 0x6d, 0x4c, 0xa2, 0x29, 0xbf,
+ 0x49, 0xe9, 0x5d, 0x6d, 0x4c, 0xa2, 0x29, 0xbf},
+ []byte{0x02, 0xfe, 0x55, 0x77, 0x81, 0x17, 0xf1, 0x2a},
+ []byte{0x5a, 0x6b, 0x61, 0x2c, 0xc2, 0x6c, 0xce, 0x4a}},
+ { // 17
+ []byte{
+ 0x01, 0x83, 0x10, 0xdc, 0x40, 0x9b, 0x26, 0xd6,
+ 0x01, 0x83, 0x10, 0xdc, 0x40, 0x9b, 0x26, 0xd6,
+ 0x01, 0x83, 0x10, 0xdc, 0x40, 0x9b, 0x26, 0xd6},
+ []byte{0x1d, 0x9d, 0x5c, 0x50, 0x18, 0xf7, 0x28, 0xc2},
+ []byte{0x5f, 0x4c, 0x03, 0x8e, 0xd1, 0x2b, 0x2e, 0x41}},
+ { // 18
+ []byte{
+ 0x1c, 0x58, 0x7f, 0x1c, 0x13, 0x92, 0x4f, 0xef,
+ 0x1c, 0x58, 0x7f, 0x1c, 0x13, 0x92, 0x4f, 0xef,
+ 0x1c, 0x58, 0x7f, 0x1c, 0x13, 0x92, 0x4f, 0xef},
+ []byte{0x30, 0x55, 0x32, 0x28, 0x6d, 0x6f, 0x29, 0x5a},
+ []byte{0x63, 0xfa, 0xc0, 0xd0, 0x34, 0xd9, 0xf7, 0x93}},
+}
+
+func newCipher(key []byte) *desCipher {
+ c, err := NewCipher(key)
+ if err != nil {
+ panic("NewCipher failed: " + err.Error())
+ }
+ return c.(*desCipher)
+}
+
+// Use the known weak keys to test DES implementation
+func TestWeakKeys(t *testing.T) {
+ for i, tt := range weakKeyTests {
+ var encrypt = func(in []byte) (out []byte) {
+ c := newCipher(tt.key)
+ out = make([]byte, len(in))
+ encryptBlock(c.subkeys[:], out, in)
+ return
+ }
+
+ // Encrypting twice with a DES weak
+ // key should reproduce the original input
+ result := encrypt(tt.in)
+ result = encrypt(result)
+
+ if !bytes.Equal(result, tt.in) {
+ t.Errorf("#%d: result: %x want: %x", i, result, tt.in)
+ }
+ }
+}
+
+// Use the known semi-weak key pairs to test DES implementation
+func TestSemiWeakKeyPairs(t *testing.T) {
+ for i, tt := range semiWeakKeyTests {
+ var encrypt = func(key, in []byte) (out []byte) {
+ c := newCipher(key)
+ out = make([]byte, len(in))
+ encryptBlock(c.subkeys[:], out, in)
+ return
+ }
+
+ // Encrypting with one member of the semi-weak pair
+ // and then encrypting the result with the other member
+ // should reproduce the original input.
+ result := encrypt(tt.key, tt.in)
+ result = encrypt(tt.out, result)
+
+ if !bytes.Equal(result, tt.in) {
+ t.Errorf("#%d: result: %x want: %x", i, result, tt.in)
+ }
+ }
+}
+
+func TestDESEncryptBlock(t *testing.T) {
+ for i, tt := range encryptDESTests {
+ c := newCipher(tt.key)
+ out := make([]byte, len(tt.in))
+ encryptBlock(c.subkeys[:], out, tt.in)
+
+ if !bytes.Equal(out, tt.out) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
+ }
+ }
+}
+
+func TestDESDecryptBlock(t *testing.T) {
+ for i, tt := range encryptDESTests {
+ c := newCipher(tt.key)
+ plain := make([]byte, len(tt.in))
+ decryptBlock(c.subkeys[:], plain, tt.out)
+
+ if !bytes.Equal(plain, tt.in) {
+ t.Errorf("#%d: result: %x want: %x", i, plain, tt.in)
+ }
+ }
+}
+
+func TestEncryptTripleDES(t *testing.T) {
+ for i, tt := range encryptTripleDESTests {
+ c, _ := NewTripleDESCipher(tt.key)
+ out := make([]byte, len(tt.in))
+ c.Encrypt(out, tt.in)
+
+ if !bytes.Equal(out, tt.out) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
+ }
+ }
+}
+
+func TestDecryptTripleDES(t *testing.T) {
+ for i, tt := range encryptTripleDESTests {
+ c, _ := NewTripleDESCipher(tt.key)
+
+ plain := make([]byte, len(tt.in))
+ c.Decrypt(plain, tt.out)
+
+ if !bytes.Equal(plain, tt.in) {
+ t.Errorf("#%d: result: %x want: %x", i, plain, tt.in)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+func TestVariablePlaintextKnownAnswer(t *testing.T) {
+ for i, tt := range tableA1Tests {
+ c, _ := NewTripleDESCipher(tableA1Key)
+
+ out := make([]byte, len(tt.in))
+ c.Encrypt(out, tt.in)
+
+ if !bytes.Equal(out, tt.out) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+func TestVariableCiphertextKnownAnswer(t *testing.T) {
+ for i, tt := range tableA1Tests {
+ c, _ := NewTripleDESCipher(tableA1Key)
+
+ plain := make([]byte, len(tt.out))
+ c.Decrypt(plain, tt.out)
+
+ if !bytes.Equal(plain, tt.in) {
+ t.Errorf("#%d: result: %x want: %x", i, plain, tt.in)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+// Encrypting the Table A.1 ciphertext with the
+// 0x01... key produces the original plaintext
+func TestInversePermutationKnownAnswer(t *testing.T) {
+ for i, tt := range tableA1Tests {
+ c, _ := NewTripleDESCipher(tableA1Key)
+
+ plain := make([]byte, len(tt.in))
+ c.Encrypt(plain, tt.out)
+
+ if !bytes.Equal(plain, tt.in) {
+ t.Errorf("#%d: result: %x want: %x", i, plain, tt.in)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+// Decrypting the Table A.1 plaintext with the
+// 0x01... key produces the corresponding ciphertext
+func TestInitialPermutationKnownAnswer(t *testing.T) {
+ for i, tt := range tableA1Tests {
+ c, _ := NewTripleDESCipher(tableA1Key)
+
+ out := make([]byte, len(tt.in))
+ c.Decrypt(out, tt.in)
+
+ if !bytes.Equal(out, tt.out) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+func TestVariableKeyKnownAnswerEncrypt(t *testing.T) {
+ for i, tt := range tableA2Tests {
+ c, _ := NewTripleDESCipher(tt.key)
+
+ out := make([]byte, len(tableA2Plaintext))
+ c.Encrypt(out, tableA2Plaintext)
+
+ if !bytes.Equal(out, tt.out) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+func TestVariableKeyKnownAnswerDecrypt(t *testing.T) {
+ for i, tt := range tableA2Tests {
+ c, _ := NewTripleDESCipher(tt.key)
+
+ out := make([]byte, len(tt.out))
+ c.Decrypt(out, tt.out)
+
+ if !bytes.Equal(out, tableA2Plaintext) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tableA2Plaintext)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+func TestPermutationOperationKnownAnswerEncrypt(t *testing.T) {
+ for i, tt := range tableA3Tests {
+ c, _ := NewTripleDESCipher(tt.key)
+
+ out := make([]byte, len(tableA3Plaintext))
+ c.Encrypt(out, tableA3Plaintext)
+
+ if !bytes.Equal(out, tt.out) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+func TestPermutationOperationKnownAnswerDecrypt(t *testing.T) {
+ for i, tt := range tableA3Tests {
+ c, _ := NewTripleDESCipher(tt.key)
+
+ out := make([]byte, len(tt.out))
+ c.Decrypt(out, tt.out)
+
+ if !bytes.Equal(out, tableA3Plaintext) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tableA3Plaintext)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+func TestSubstitutionTableKnownAnswerEncrypt(t *testing.T) {
+ for i, tt := range tableA4Tests {
+ c, _ := NewTripleDESCipher(tt.key)
+
+ out := make([]byte, len(tt.in))
+ c.Encrypt(out, tt.in)
+
+ if !bytes.Equal(out, tt.out) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tt.out)
+ }
+ }
+}
+
+// Defined in Pub 800-20
+func TestSubstitutionTableKnownAnswerDecrypt(t *testing.T) {
+ for i, tt := range tableA4Tests {
+ c, _ := NewTripleDESCipher(tt.key)
+
+ out := make([]byte, len(tt.out))
+ c.Decrypt(out, tt.out)
+
+ if !bytes.Equal(out, tt.in) {
+ t.Errorf("#%d: result: %x want: %x", i, out, tt.in)
+ }
+ }
+}
+
+func TestInitialPermute(t *testing.T) {
+ for i := uint(0); i < 64; i++ {
+ bit := uint64(1) << i
+ got := permuteInitialBlock(bit)
+ want := uint64(1) << finalPermutation[63-i]
+ if got != want {
+ t.Errorf("permute(%x) = %x, want %x", bit, got, want)
+ }
+ }
+}
+
+func TestFinalPermute(t *testing.T) {
+ for i := uint(0); i < 64; i++ {
+ bit := uint64(1) << i
+ got := permuteFinalBlock(bit)
+ want := uint64(1) << initialPermutation[63-i]
+ if got != want {
+ t.Errorf("permute(%x) = %x, want %x", bit, got, want)
+ }
+ }
+}
+
+func BenchmarkEncrypt(b *testing.B) {
+ tt := encryptDESTests[0]
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ b.Fatal("NewCipher:", err)
+ }
+ out := make([]byte, len(tt.in))
+ b.SetBytes(int64(len(out)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ c.Encrypt(out, tt.in)
+ }
+}
+
+func BenchmarkDecrypt(b *testing.B) {
+ tt := encryptDESTests[0]
+ c, err := NewCipher(tt.key)
+ if err != nil {
+ b.Fatal("NewCipher:", err)
+ }
+ out := make([]byte, len(tt.out))
+ b.SetBytes(int64(len(out)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ c.Decrypt(out, tt.out)
+ }
+}
+
+func BenchmarkTDESEncrypt(b *testing.B) {
+ tt := encryptTripleDESTests[0]
+ c, err := NewTripleDESCipher(tt.key)
+ if err != nil {
+ b.Fatal("NewCipher:", err)
+ }
+ out := make([]byte, len(tt.in))
+ b.SetBytes(int64(len(out)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ c.Encrypt(out, tt.in)
+ }
+}
+
+func BenchmarkTDESDecrypt(b *testing.B) {
+ tt := encryptTripleDESTests[0]
+ c, err := NewTripleDESCipher(tt.key)
+ if err != nil {
+ b.Fatal("NewCipher:", err)
+ }
+ out := make([]byte, len(tt.out))
+ b.SetBytes(int64(len(out)))
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ c.Decrypt(out, tt.out)
+ }
+}
diff --git a/src/crypto/des/example_test.go b/src/crypto/des/example_test.go
new file mode 100644
index 0000000..336b593
--- /dev/null
+++ b/src/crypto/des/example_test.go
@@ -0,0 +1,25 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package des_test
+
+import "crypto/des"
+
+func ExampleNewTripleDESCipher() {
+ // NewTripleDESCipher can also be used when EDE2 is required by
+ // duplicating the first 8 bytes of the 16-byte key.
+ ede2Key := []byte("example key 1234")
+
+ var tripleDESKey []byte
+ tripleDESKey = append(tripleDESKey, ede2Key[:16]...)
+ tripleDESKey = append(tripleDESKey, ede2Key[:8]...)
+
+ _, err := des.NewTripleDESCipher(tripleDESKey)
+ if err != nil {
+ panic(err)
+ }
+
+ // See crypto/cipher for how to use a cipher.Block for encryption and
+ // decryption.
+}
diff --git a/src/crypto/dsa/dsa.go b/src/crypto/dsa/dsa.go
new file mode 100644
index 0000000..a833599
--- /dev/null
+++ b/src/crypto/dsa/dsa.go
@@ -0,0 +1,309 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package dsa implements the Digital Signature Algorithm, as defined in FIPS 186-3.
+//
+// The DSA operations in this package are not implemented using constant-time algorithms.
+//
+// Deprecated: DSA is a legacy algorithm, and modern alternatives such as
+// Ed25519 (implemented by package crypto/ed25519) should be used instead. Keys
+// with 1024-bit moduli (L1024N160 parameters) are cryptographically weak, while
+// bigger keys are not widely supported. Note that FIPS 186-5 no longer approves
+// DSA for signature generation.
+package dsa
+
+import (
+ "errors"
+ "io"
+ "math/big"
+
+ "crypto/internal/randutil"
+)
+
+// Parameters represents the domain parameters for a key. These parameters can
+// be shared across many keys. The bit length of Q must be a multiple of 8.
+type Parameters struct {
+ P, Q, G *big.Int
+}
+
+// PublicKey represents a DSA public key.
+type PublicKey struct {
+ Parameters
+ Y *big.Int
+}
+
+// PrivateKey represents a DSA private key.
+type PrivateKey struct {
+ PublicKey
+ X *big.Int
+}
+
+// ErrInvalidPublicKey results when a public key is not usable by this code.
+// FIPS is quite strict about the format of DSA keys, but other code may be
+// less so. Thus, when using keys which may have been generated by other code,
+// this error must be handled.
+var ErrInvalidPublicKey = errors.New("crypto/dsa: invalid public key")
+
+// ParameterSizes is an enumeration of the acceptable bit lengths of the primes
+// in a set of DSA parameters. See FIPS 186-3, section 4.2.
+type ParameterSizes int
+
+const (
+ L1024N160 ParameterSizes = iota
+ L2048N224
+ L2048N256
+ L3072N256
+)
+
+// numMRTests is the number of Miller-Rabin primality tests that we perform. We
+// pick the largest recommended number from table C.1 of FIPS 186-3.
+const numMRTests = 64
+
+// GenerateParameters puts a random, valid set of DSA parameters into params.
+// This function can take many seconds, even on fast machines.
+func GenerateParameters(params *Parameters, rand io.Reader, sizes ParameterSizes) error {
+ // This function doesn't follow FIPS 186-3 exactly in that it doesn't
+ // use a verification seed to generate the primes. The verification
+ // seed doesn't appear to be exported or used by other code and
+ // omitting it makes the code cleaner.
+
+ var L, N int
+ switch sizes {
+ case L1024N160:
+ L = 1024
+ N = 160
+ case L2048N224:
+ L = 2048
+ N = 224
+ case L2048N256:
+ L = 2048
+ N = 256
+ case L3072N256:
+ L = 3072
+ N = 256
+ default:
+ return errors.New("crypto/dsa: invalid ParameterSizes")
+ }
+
+ qBytes := make([]byte, N/8)
+ pBytes := make([]byte, L/8)
+
+ q := new(big.Int)
+ p := new(big.Int)
+ rem := new(big.Int)
+ one := new(big.Int)
+ one.SetInt64(1)
+
+GeneratePrimes:
+ for {
+ if _, err := io.ReadFull(rand, qBytes); err != nil {
+ return err
+ }
+
+ qBytes[len(qBytes)-1] |= 1
+ qBytes[0] |= 0x80
+ q.SetBytes(qBytes)
+
+ if !q.ProbablyPrime(numMRTests) {
+ continue
+ }
+
+ for i := 0; i < 4*L; i++ {
+ if _, err := io.ReadFull(rand, pBytes); err != nil {
+ return err
+ }
+
+ pBytes[len(pBytes)-1] |= 1
+ pBytes[0] |= 0x80
+
+ p.SetBytes(pBytes)
+ rem.Mod(p, q)
+ rem.Sub(rem, one)
+ p.Sub(p, rem)
+ if p.BitLen() < L {
+ continue
+ }
+
+ if !p.ProbablyPrime(numMRTests) {
+ continue
+ }
+
+ params.P = p
+ params.Q = q
+ break GeneratePrimes
+ }
+ }
+
+ h := new(big.Int)
+ h.SetInt64(2)
+ g := new(big.Int)
+
+ pm1 := new(big.Int).Sub(p, one)
+ e := new(big.Int).Div(pm1, q)
+
+ for {
+ g.Exp(h, e, p)
+ if g.Cmp(one) == 0 {
+ h.Add(h, one)
+ continue
+ }
+
+ params.G = g
+ return nil
+ }
+}
+
+// GenerateKey generates a public&private key pair. The Parameters of the
+// PrivateKey must already be valid (see GenerateParameters).
+func GenerateKey(priv *PrivateKey, rand io.Reader) error {
+ if priv.P == nil || priv.Q == nil || priv.G == nil {
+ return errors.New("crypto/dsa: parameters not set up before generating key")
+ }
+
+ x := new(big.Int)
+ xBytes := make([]byte, priv.Q.BitLen()/8)
+
+ for {
+ _, err := io.ReadFull(rand, xBytes)
+ if err != nil {
+ return err
+ }
+ x.SetBytes(xBytes)
+ if x.Sign() != 0 && x.Cmp(priv.Q) < 0 {
+ break
+ }
+ }
+
+ priv.X = x
+ priv.Y = new(big.Int)
+ priv.Y.Exp(priv.G, x, priv.P)
+ return nil
+}
+
+// fermatInverse calculates the inverse of k in GF(P) using Fermat's method.
+// This has better constant-time properties than Euclid's method (implemented
+// in math/big.Int.ModInverse) although math/big itself isn't strictly
+// constant-time so it's not perfect.
+func fermatInverse(k, P *big.Int) *big.Int {
+ two := big.NewInt(2)
+ pMinus2 := new(big.Int).Sub(P, two)
+ return new(big.Int).Exp(k, pMinus2, P)
+}
+
+// Sign signs an arbitrary length hash (which should be the result of hashing a
+// larger message) using the private key, priv. It returns the signature as a
+// pair of integers. The security of the private key depends on the entropy of
+// rand.
+//
+// Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated
+// to the byte-length of the subgroup. This function does not perform that
+// truncation itself.
+//
+// Be aware that calling Sign with an attacker-controlled PrivateKey may
+// require an arbitrary amount of CPU.
+func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
+ randutil.MaybeReadByte(rand)
+
+ // FIPS 186-3, section 4.6
+
+ n := priv.Q.BitLen()
+ if priv.Q.Sign() <= 0 || priv.P.Sign() <= 0 || priv.G.Sign() <= 0 || priv.X.Sign() <= 0 || n%8 != 0 {
+ err = ErrInvalidPublicKey
+ return
+ }
+ n >>= 3
+
+ var attempts int
+ for attempts = 10; attempts > 0; attempts-- {
+ k := new(big.Int)
+ buf := make([]byte, n)
+ for {
+ _, err = io.ReadFull(rand, buf)
+ if err != nil {
+ return
+ }
+ k.SetBytes(buf)
+ // priv.Q must be >= 128 because the test above
+ // requires it to be > 0 and that
+ // ceil(log_2(Q)) mod 8 = 0
+ // Thus this loop will quickly terminate.
+ if k.Sign() > 0 && k.Cmp(priv.Q) < 0 {
+ break
+ }
+ }
+
+ kInv := fermatInverse(k, priv.Q)
+
+ r = new(big.Int).Exp(priv.G, k, priv.P)
+ r.Mod(r, priv.Q)
+
+ if r.Sign() == 0 {
+ continue
+ }
+
+ z := k.SetBytes(hash)
+
+ s = new(big.Int).Mul(priv.X, r)
+ s.Add(s, z)
+ s.Mod(s, priv.Q)
+ s.Mul(s, kInv)
+ s.Mod(s, priv.Q)
+
+ if s.Sign() != 0 {
+ break
+ }
+ }
+
+ // Only degenerate private keys will require more than a handful of
+ // attempts.
+ if attempts == 0 {
+ return nil, nil, ErrInvalidPublicKey
+ }
+
+ return
+}
+
+// Verify verifies the signature in r, s of hash using the public key, pub. It
+// reports whether the signature is valid.
+//
+// Note that FIPS 186-3 section 4.6 specifies that the hash should be truncated
+// to the byte-length of the subgroup. This function does not perform that
+// truncation itself.
+func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
+ // FIPS 186-3, section 4.7
+
+ if pub.P.Sign() == 0 {
+ return false
+ }
+
+ if r.Sign() < 1 || r.Cmp(pub.Q) >= 0 {
+ return false
+ }
+ if s.Sign() < 1 || s.Cmp(pub.Q) >= 0 {
+ return false
+ }
+
+ w := new(big.Int).ModInverse(s, pub.Q)
+ if w == nil {
+ return false
+ }
+
+ n := pub.Q.BitLen()
+ if n%8 != 0 {
+ return false
+ }
+ z := new(big.Int).SetBytes(hash)
+
+ u1 := new(big.Int).Mul(z, w)
+ u1.Mod(u1, pub.Q)
+ u2 := w.Mul(r, w)
+ u2.Mod(u2, pub.Q)
+ v := u1.Exp(pub.G, u1, pub.P)
+ u2.Exp(pub.Y, u2, pub.P)
+ v.Mul(v, u2)
+ v.Mod(v, pub.P)
+ v.Mod(v, pub.Q)
+
+ return v.Cmp(r) == 0
+}
diff --git a/src/crypto/dsa/dsa_test.go b/src/crypto/dsa/dsa_test.go
new file mode 100644
index 0000000..28ac00e
--- /dev/null
+++ b/src/crypto/dsa/dsa_test.go
@@ -0,0 +1,143 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package dsa
+
+import (
+ "crypto/rand"
+ "math/big"
+ "testing"
+)
+
+func testSignAndVerify(t *testing.T, i int, priv *PrivateKey) {
+ hashed := []byte("testing")
+ r, s, err := Sign(rand.Reader, priv, hashed)
+ if err != nil {
+ t.Errorf("%d: error signing: %s", i, err)
+ return
+ }
+
+ if !Verify(&priv.PublicKey, hashed, r, s) {
+ t.Errorf("%d: Verify failed", i)
+ }
+}
+
+func testParameterGeneration(t *testing.T, sizes ParameterSizes, L, N int) {
+ var priv PrivateKey
+ params := &priv.Parameters
+
+ err := GenerateParameters(params, rand.Reader, sizes)
+ if err != nil {
+ t.Errorf("%d: %s", int(sizes), err)
+ return
+ }
+
+ if params.P.BitLen() != L {
+ t.Errorf("%d: params.BitLen got:%d want:%d", int(sizes), params.P.BitLen(), L)
+ }
+
+ if params.Q.BitLen() != N {
+ t.Errorf("%d: q.BitLen got:%d want:%d", int(sizes), params.Q.BitLen(), L)
+ }
+
+ one := new(big.Int)
+ one.SetInt64(1)
+ pm1 := new(big.Int).Sub(params.P, one)
+ quo, rem := new(big.Int).DivMod(pm1, params.Q, new(big.Int))
+ if rem.Sign() != 0 {
+ t.Errorf("%d: p-1 mod q != 0", int(sizes))
+ }
+ x := new(big.Int).Exp(params.G, quo, params.P)
+ if x.Cmp(one) == 0 {
+ t.Errorf("%d: invalid generator", int(sizes))
+ }
+
+ err = GenerateKey(&priv, rand.Reader)
+ if err != nil {
+ t.Errorf("error generating key: %s", err)
+ return
+ }
+
+ testSignAndVerify(t, int(sizes), &priv)
+}
+
+func TestParameterGeneration(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping parameter generation test in short mode")
+ }
+
+ testParameterGeneration(t, L1024N160, 1024, 160)
+ testParameterGeneration(t, L2048N224, 2048, 224)
+ testParameterGeneration(t, L2048N256, 2048, 256)
+ testParameterGeneration(t, L3072N256, 3072, 256)
+}
+
+func fromHex(s string) *big.Int {
+ result, ok := new(big.Int).SetString(s, 16)
+ if !ok {
+ panic(s)
+ }
+ return result
+}
+
+func TestSignAndVerify(t *testing.T) {
+ priv := PrivateKey{
+ PublicKey: PublicKey{
+ Parameters: Parameters{
+ P: fromHex("A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF"),
+ Q: fromHex("E1D3391245933D68A0714ED34BBCB7A1F422B9C1"),
+ G: fromHex("634364FC25248933D01D1993ECABD0657CC0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B95DA4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF89D3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA"),
+ },
+ Y: fromHex("32969E5780CFE1C849A1C276D7AEB4F38A23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72568944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB694AB1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2"),
+ },
+ X: fromHex("5078D4D29795CBE76D3AACFE48C9AF0BCDBEE91A"),
+ }
+
+ testSignAndVerify(t, 0, &priv)
+}
+
+func TestSignAndVerifyWithBadPublicKey(t *testing.T) {
+ pub := PublicKey{
+ Parameters: Parameters{
+ P: fromHex("A9B5B793FB4785793D246BAE77E8FF63CA52F442DA763C440259919FE1BC1D6065A9350637A04F75A2F039401D49F08E066C4D275A5A65DA5684BC563C14289D7AB8A67163BFBF79D85972619AD2CFF55AB0EE77A9002B0EF96293BDD0F42685EBB2C66C327079F6C98000FBCB79AACDE1BC6F9D5C7B1A97E3D9D54ED7951FEF"),
+ Q: fromHex("FA"),
+ G: fromHex("634364FC25248933D01D1993ECABD0657CC0CB2CEED7ED2E3E8AECDFCDC4A25C3B15E9E3B163ACA2984B5539181F3EFF1A5E8903D71D5B95DA4F27202B77D2C44B430BB53741A8D59A8F86887525C9F2A6A5980A195EAA7F2FF910064301DEF89D3AA213E1FAC7768D89365318E370AF54A112EFBA9246D9158386BA1B4EEFDA"),
+ },
+ Y: fromHex("32969E5780CFE1C849A1C276D7AEB4F38A23B591739AA2FE197349AEEBD31366AEE5EB7E6C6DDB7C57D02432B30DB5AA66D9884299FAA72568944E4EEDC92EA3FBC6F39F53412FBCC563208F7C15B737AC8910DBC2D9C9B8C001E72FDC40EB694AB1F06A5A2DBD18D9E36C66F31F566742F11EC0A52E9F7B89355C02FB5D32D2"),
+ }
+
+ if Verify(&pub, []byte("testing"), fromHex("2"), fromHex("4")) {
+ t.Errorf("Verify unexpected success with non-existent mod inverse of Q")
+ }
+}
+
+func TestSigningWithDegenerateKeys(t *testing.T) {
+ // Signing with degenerate private keys should not cause an infinite
+ // loop.
+ badKeys := []struct {
+ p, q, g, y, x string
+ }{
+ {"00", "01", "00", "00", "00"},
+ {"01", "ff", "00", "00", "00"},
+ }
+
+ for i, test := range badKeys {
+ priv := PrivateKey{
+ PublicKey: PublicKey{
+ Parameters: Parameters{
+ P: fromHex(test.p),
+ Q: fromHex(test.q),
+ G: fromHex(test.g),
+ },
+ Y: fromHex(test.y),
+ },
+ X: fromHex(test.x),
+ }
+
+ hashed := []byte("testing")
+ if _, _, err := Sign(rand.Reader, &priv, hashed); err == nil {
+ t.Errorf("#%d: unexpected success", i)
+ }
+ }
+}
diff --git a/src/crypto/ecdh/ecdh.go b/src/crypto/ecdh/ecdh.go
new file mode 100644
index 0000000..7442055
--- /dev/null
+++ b/src/crypto/ecdh/ecdh.go
@@ -0,0 +1,184 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ecdh implements Elliptic Curve Diffie-Hellman over
+// NIST curves and Curve25519.
+package ecdh
+
+import (
+ "crypto"
+ "crypto/internal/boring"
+ "crypto/subtle"
+ "errors"
+ "io"
+ "sync"
+)
+
+type Curve interface {
+ // GenerateKey generates a new PrivateKey from rand.
+ GenerateKey(rand io.Reader) (*PrivateKey, error)
+
+ // NewPrivateKey checks that key is valid and returns a PrivateKey.
+ //
+ // For NIST curves, this follows SEC 1, Version 2.0, Section 2.3.6, which
+ // amounts to decoding the bytes as a fixed length big endian integer and
+ // checking that the result is lower than the order of the curve. The zero
+ // private key is also rejected, as the encoding of the corresponding public
+ // key would be irregular.
+ //
+ // For X25519, this only checks the scalar length.
+ NewPrivateKey(key []byte) (*PrivateKey, error)
+
+ // NewPublicKey checks that key is valid and returns a PublicKey.
+ //
+ // For NIST curves, this decodes an uncompressed point according to SEC 1,
+ // Version 2.0, Section 2.3.4. Compressed encodings and the point at
+ // infinity are rejected.
+ //
+ // For X25519, this only checks the u-coordinate length. Adversarially
+ // selected public keys can cause ECDH to return an error.
+ NewPublicKey(key []byte) (*PublicKey, error)
+
+ // ecdh performs a ECDH exchange and returns the shared secret. It's exposed
+ // as the PrivateKey.ECDH method.
+ //
+ // The private method also allow us to expand the ECDH interface with more
+ // methods in the future without breaking backwards compatibility.
+ ecdh(local *PrivateKey, remote *PublicKey) ([]byte, error)
+
+ // privateKeyToPublicKey converts a PrivateKey to a PublicKey. It's exposed
+ // as the PrivateKey.PublicKey method.
+ //
+ // This method always succeeds: for X25519, the zero key can't be
+ // constructed due to clamping; for NIST curves, it is rejected by
+ // NewPrivateKey.
+ privateKeyToPublicKey(*PrivateKey) *PublicKey
+}
+
+// PublicKey is an ECDH public key, usually a peer's ECDH share sent over the wire.
+//
+// These keys can be parsed with [crypto/x509.ParsePKIXPublicKey] and encoded
+// with [crypto/x509.MarshalPKIXPublicKey]. For NIST curves, they then need to
+// be converted with [crypto/ecdsa.PublicKey.ECDH] after parsing.
+type PublicKey struct {
+ curve Curve
+ publicKey []byte
+ boring *boring.PublicKeyECDH
+}
+
+// Bytes returns a copy of the encoding of the public key.
+func (k *PublicKey) Bytes() []byte {
+ // Copy the public key to a fixed size buffer that can get allocated on the
+ // caller's stack after inlining.
+ var buf [133]byte
+ return append(buf[:0], k.publicKey...)
+}
+
+// Equal returns whether x represents the same public key as k.
+//
+// Note that there can be equivalent public keys with different encodings which
+// would return false from this check but behave the same way as inputs to ECDH.
+//
+// This check is performed in constant time as long as the key types and their
+// curve match.
+func (k *PublicKey) Equal(x crypto.PublicKey) bool {
+ xx, ok := x.(*PublicKey)
+ if !ok {
+ return false
+ }
+ return k.curve == xx.curve &&
+ subtle.ConstantTimeCompare(k.publicKey, xx.publicKey) == 1
+}
+
+func (k *PublicKey) Curve() Curve {
+ return k.curve
+}
+
+// PrivateKey is an ECDH private key, usually kept secret.
+//
+// These keys can be parsed with [crypto/x509.ParsePKCS8PrivateKey] and encoded
+// with [crypto/x509.MarshalPKCS8PrivateKey]. For NIST curves, they then need to
+// be converted with [crypto/ecdsa.PrivateKey.ECDH] after parsing.
+type PrivateKey struct {
+ curve Curve
+ privateKey []byte
+ boring *boring.PrivateKeyECDH
+ // publicKey is set under publicKeyOnce, to allow loading private keys with
+ // NewPrivateKey without having to perform a scalar multiplication.
+ publicKey *PublicKey
+ publicKeyOnce sync.Once
+}
+
+// ECDH performs a ECDH exchange and returns the shared secret. The PrivateKey
+// and PublicKey must use the same curve.
+//
+// For NIST curves, this performs ECDH as specified in SEC 1, Version 2.0,
+// Section 3.3.1, and returns the x-coordinate encoded according to SEC 1,
+// Version 2.0, Section 2.3.5. The result is never the point at infinity.
+//
+// For X25519, this performs ECDH as specified in RFC 7748, Section 6.1. If
+// the result is the all-zero value, ECDH returns an error.
+func (k *PrivateKey) ECDH(remote *PublicKey) ([]byte, error) {
+ if k.curve != remote.curve {
+ return nil, errors.New("crypto/ecdh: private key and public key curves do not match")
+ }
+ return k.curve.ecdh(k, remote)
+}
+
+// Bytes returns a copy of the encoding of the private key.
+func (k *PrivateKey) Bytes() []byte {
+ // Copy the private key to a fixed size buffer that can get allocated on the
+ // caller's stack after inlining.
+ var buf [66]byte
+ return append(buf[:0], k.privateKey...)
+}
+
+// Equal returns whether x represents the same private key as k.
+//
+// Note that there can be equivalent private keys with different encodings which
+// would return false from this check but behave the same way as inputs to ECDH.
+//
+// This check is performed in constant time as long as the key types and their
+// curve match.
+func (k *PrivateKey) Equal(x crypto.PrivateKey) bool {
+ xx, ok := x.(*PrivateKey)
+ if !ok {
+ return false
+ }
+ return k.curve == xx.curve &&
+ subtle.ConstantTimeCompare(k.privateKey, xx.privateKey) == 1
+}
+
+func (k *PrivateKey) Curve() Curve {
+ return k.curve
+}
+
+func (k *PrivateKey) PublicKey() *PublicKey {
+ k.publicKeyOnce.Do(func() {
+ if k.boring != nil {
+ // Because we already checked in NewPrivateKey that the key is valid,
+ // there should not be any possible errors from BoringCrypto,
+ // so we turn the error into a panic.
+ // (We can't return it anyhow.)
+ kpub, err := k.boring.PublicKey()
+ if err != nil {
+ panic("boringcrypto: " + err.Error())
+ }
+ k.publicKey = &PublicKey{
+ curve: k.curve,
+ publicKey: kpub.Bytes(),
+ boring: kpub,
+ }
+ } else {
+ k.publicKey = k.curve.privateKeyToPublicKey(k)
+ }
+ })
+ return k.publicKey
+}
+
+// Public implements the implicit interface of all standard library private
+// keys. See the docs of crypto.PrivateKey.
+func (k *PrivateKey) Public() crypto.PublicKey {
+ return k.PublicKey()
+}
diff --git a/src/crypto/ecdh/ecdh_test.go b/src/crypto/ecdh/ecdh_test.go
new file mode 100644
index 0000000..10da95a
--- /dev/null
+++ b/src/crypto/ecdh/ecdh_test.go
@@ -0,0 +1,525 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ecdh_test
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/cipher"
+ "crypto/ecdh"
+ "crypto/rand"
+ "crypto/sha256"
+ "encoding/hex"
+ "fmt"
+ "internal/testenv"
+ "io"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "regexp"
+ "strings"
+ "testing"
+
+ "golang.org/x/crypto/chacha20"
+)
+
+// Check that PublicKey and PrivateKey implement the interfaces documented in
+// crypto.PublicKey and crypto.PrivateKey.
+var _ interface {
+ Equal(x crypto.PublicKey) bool
+} = &ecdh.PublicKey{}
+var _ interface {
+ Public() crypto.PublicKey
+ Equal(x crypto.PrivateKey) bool
+} = &ecdh.PrivateKey{}
+
+func TestECDH(t *testing.T) {
+ testAllCurves(t, func(t *testing.T, curve ecdh.Curve) {
+ aliceKey, err := curve.GenerateKey(rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ bobKey, err := curve.GenerateKey(rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ alicePubKey, err := curve.NewPublicKey(aliceKey.PublicKey().Bytes())
+ if err != nil {
+ t.Error(err)
+ }
+ if !bytes.Equal(aliceKey.PublicKey().Bytes(), alicePubKey.Bytes()) {
+ t.Error("encoded and decoded public keys are different")
+ }
+ if !aliceKey.PublicKey().Equal(alicePubKey) {
+ t.Error("encoded and decoded public keys are different")
+ }
+
+ alicePrivKey, err := curve.NewPrivateKey(aliceKey.Bytes())
+ if err != nil {
+ t.Error(err)
+ }
+ if !bytes.Equal(aliceKey.Bytes(), alicePrivKey.Bytes()) {
+ t.Error("encoded and decoded private keys are different")
+ }
+ if !aliceKey.Equal(alicePrivKey) {
+ t.Error("encoded and decoded private keys are different")
+ }
+
+ bobSecret, err := bobKey.ECDH(aliceKey.PublicKey())
+ if err != nil {
+ t.Fatal(err)
+ }
+ aliceSecret, err := aliceKey.ECDH(bobKey.PublicKey())
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !bytes.Equal(bobSecret, aliceSecret) {
+ t.Error("two ECDH computations came out different")
+ }
+ })
+}
+
+type countingReader struct {
+ r io.Reader
+ n int
+}
+
+func (r *countingReader) Read(p []byte) (int, error) {
+ n, err := r.r.Read(p)
+ r.n += n
+ return n, err
+}
+
+func TestGenerateKey(t *testing.T) {
+ testAllCurves(t, func(t *testing.T, curve ecdh.Curve) {
+ r := &countingReader{r: rand.Reader}
+ k, err := curve.GenerateKey(r)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // GenerateKey does rejection sampling. If the masking works correctly,
+ // the probability of a rejection is 1-ord(G)/2^ceil(log2(ord(G))),
+ // which for all curves is small enough (at most 2^-32, for P-256) that
+ // a bit flip is more likely to make this test fail than bad luck.
+ // Account for the extra MaybeReadByte byte, too.
+ if got, expected := r.n, len(k.Bytes())+1; got > expected {
+ t.Errorf("expected GenerateKey to consume at most %v bytes, got %v", expected, got)
+ }
+ })
+}
+
+var vectors = map[ecdh.Curve]struct {
+ PrivateKey, PublicKey string
+ PeerPublicKey string
+ SharedSecret string
+}{
+ // NIST vectors from CAVS 14.1, ECC CDH Primitive (SP800-56A).
+ ecdh.P256(): {
+ PrivateKey: "7d7dc5f71eb29ddaf80d6214632eeae03d9058af1fb6d22ed80badb62bc1a534",
+ PublicKey: "04ead218590119e8876b29146ff89ca61770c4edbbf97d38ce385ed281d8a6b230" +
+ "28af61281fd35e2fa7002523acc85a429cb06ee6648325389f59edfce1405141",
+ PeerPublicKey: "04700c48f77f56584c5cc632ca65640db91b6bacce3a4df6b42ce7cc838833d287" +
+ "db71e509e3fd9b060ddb20ba5c51dcc5948d46fbf640dfe0441782cab85fa4ac",
+ SharedSecret: "46fc62106420ff012e54a434fbdd2d25ccc5852060561e68040dd7778997bd7b",
+ },
+ ecdh.P384(): {
+ PrivateKey: "3cc3122a68f0d95027ad38c067916ba0eb8c38894d22e1b15618b6818a661774ad463b205da88cf699ab4d43c9cf98a1",
+ PublicKey: "049803807f2f6d2fd966cdd0290bd410c0190352fbec7ff6247de1302df86f25d34fe4a97bef60cff548355c015dbb3e5f" +
+ "ba26ca69ec2f5b5d9dad20cc9da711383a9dbe34ea3fa5a2af75b46502629ad54dd8b7d73a8abb06a3a3be47d650cc99",
+ PeerPublicKey: "04a7c76b970c3b5fe8b05d2838ae04ab47697b9eaf52e764592efda27fe7513272734466b400091adbf2d68c58e0c50066" +
+ "ac68f19f2e1cb879aed43a9969b91a0839c4c38a49749b661efedf243451915ed0905a32b060992b468c64766fc8437a",
+ SharedSecret: "5f9d29dc5e31a163060356213669c8ce132e22f57c9a04f40ba7fcead493b457e5621e766c40a2e3d4d6a04b25e533f1",
+ },
+ // For some reason all field elements in the test vector (both scalars and
+ // base field elements), but not the shared secret output, have two extra
+ // leading zero bytes (which in big-endian are irrelevant). Removed here.
+ ecdh.P521(): {
+ PrivateKey: "017eecc07ab4b329068fba65e56a1f8890aa935e57134ae0ffcce802735151f4eac6564f6ee9974c5e6887a1fefee5743ae2241bfeb95d5ce31ddcb6f9edb4d6fc47",
+ PublicKey: "0400602f9d0cf9e526b29e22381c203c48a886c2b0673033366314f1ffbcba240ba42f4ef38a76174635f91e6b4ed34275eb01c8467d05ca80315bf1a7bbd945f550a5" +
+ "01b7c85f26f5d4b2d7355cf6b02117659943762b6d1db5ab4f1dbc44ce7b2946eb6c7de342962893fd387d1b73d7a8672d1f236961170b7eb3579953ee5cdc88cd2d",
+ PeerPublicKey: "0400685a48e86c79f0f0875f7bc18d25eb5fc8c0b07e5da4f4370f3a9490340854334b1e1b87fa395464c60626124a4e70d0f785601d37c09870ebf176666877a2046d" +
+ "01ba52c56fc8776d9e8f5db4f0cc27636d0b741bbe05400697942e80b739884a83bde99e0f6716939e632bc8986fa18dccd443a348b6c3e522497955a4f3c302f676",
+ SharedSecret: "005fc70477c3e63bc3954bd0df3ea0d1f41ee21746ed95fc5e1fdf90930d5e136672d72cc770742d1711c3c3a4c334a0ad9759436a4d3c5bf6e74b9578fac148c831",
+ },
+ // X25519 test vector from RFC 7748, Section 6.1.
+ ecdh.X25519(): {
+ PrivateKey: "77076d0a7318a57d3c16c17251b26645df4c2f87ebc0992ab177fba51db92c2a",
+ PublicKey: "8520f0098930a754748b7ddcb43ef75a0dbf3a0d26381af4eba4a98eaa9b4e6a",
+ PeerPublicKey: "de9edb7d7b7dc1b4d35b61c2ece435373f8343c85b78674dadfc7e146f882b4f",
+ SharedSecret: "4a5d9d5ba4ce2de1728e3bf480350f25e07e21c947d19e3376f09b3c1e161742",
+ },
+}
+
+func TestVectors(t *testing.T) {
+ testAllCurves(t, func(t *testing.T, curve ecdh.Curve) {
+ v := vectors[curve]
+ key, err := curve.NewPrivateKey(hexDecode(t, v.PrivateKey))
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(key.PublicKey().Bytes(), hexDecode(t, v.PublicKey)) {
+ t.Error("public key derived from the private key does not match")
+ }
+ peer, err := curve.NewPublicKey(hexDecode(t, v.PeerPublicKey))
+ if err != nil {
+ t.Fatal(err)
+ }
+ secret, err := key.ECDH(peer)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(secret, hexDecode(t, v.SharedSecret)) {
+ t.Errorf("shared secret does not match: %x %x %s %x", secret, sha256.Sum256(secret), v.SharedSecret,
+ sha256.Sum256(hexDecode(t, v.SharedSecret)))
+ }
+ })
+}
+
+func hexDecode(t *testing.T, s string) []byte {
+ b, err := hex.DecodeString(s)
+ if err != nil {
+ t.Fatal("invalid hex string:", s)
+ }
+ return b
+}
+
+func TestString(t *testing.T) {
+ testAllCurves(t, func(t *testing.T, curve ecdh.Curve) {
+ s := fmt.Sprintf("%s", curve)
+ if s[:1] != "P" && s[:1] != "X" {
+ t.Errorf("unexpected Curve string encoding: %q", s)
+ }
+ })
+}
+
+func TestX25519Failure(t *testing.T) {
+ identity := hexDecode(t, "0000000000000000000000000000000000000000000000000000000000000000")
+ lowOrderPoint := hexDecode(t, "e0eb7a7c3b41b8ae1656e3faf19fc46ada098deb9c32b1fd866205165f49b800")
+ randomScalar := make([]byte, 32)
+ rand.Read(randomScalar)
+
+ t.Run("identity point", func(t *testing.T) { testX25519Failure(t, randomScalar, identity) })
+ t.Run("low order point", func(t *testing.T) { testX25519Failure(t, randomScalar, lowOrderPoint) })
+}
+
+func testX25519Failure(t *testing.T, private, public []byte) {
+ priv, err := ecdh.X25519().NewPrivateKey(private)
+ if err != nil {
+ t.Fatal(err)
+ }
+ pub, err := ecdh.X25519().NewPublicKey(public)
+ if err != nil {
+ t.Fatal(err)
+ }
+ secret, err := priv.ECDH(pub)
+ if err == nil {
+ t.Error("expected ECDH error")
+ }
+ if secret != nil {
+ t.Errorf("unexpected ECDH output: %x", secret)
+ }
+}
+
+var invalidPrivateKeys = map[ecdh.Curve][]string{
+ ecdh.P256(): {
+ // Bad lengths.
+ "",
+ "01",
+ "01010101010101010101010101010101010101010101010101010101010101",
+ "000101010101010101010101010101010101010101010101010101010101010101",
+ strings.Repeat("01", 200),
+ // Zero.
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ // Order of the curve and above.
+ "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632551",
+ "ffffffff00000000ffffffffffffffffbce6faada7179e84f3b9cac2fc632552",
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ },
+ ecdh.P384(): {
+ // Bad lengths.
+ "",
+ "01",
+ "0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101",
+ "00010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101",
+ strings.Repeat("01", 200),
+ // Zero.
+ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ // Order of the curve and above.
+ "ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52973",
+ "ffffffffffffffffffffffffffffffffffffffffffffffffc7634d81f4372ddf581a0db248b0a77aecec196accc52974",
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ },
+ ecdh.P521(): {
+ // Bad lengths.
+ "",
+ "01",
+ "0101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101",
+ "00010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101010101",
+ strings.Repeat("01", 200),
+ // Zero.
+ "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ // Order of the curve and above.
+ "01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409",
+ "01fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e9138640a",
+ "11fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffa51868783bf2f966b7fcc0148f709a5d03bb5c9b8899c47aebb6fb71e91386409",
+ "03fffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff4a30d0f077e5f2cd6ff980291ee134ba0776b937113388f5d76df6e3d2270c812",
+ },
+ ecdh.X25519(): {
+ // X25519 only rejects bad lengths.
+ "",
+ "01",
+ "01010101010101010101010101010101010101010101010101010101010101",
+ "000101010101010101010101010101010101010101010101010101010101010101",
+ strings.Repeat("01", 200),
+ },
+}
+
+func TestNewPrivateKey(t *testing.T) {
+ testAllCurves(t, func(t *testing.T, curve ecdh.Curve) {
+ for _, input := range invalidPrivateKeys[curve] {
+ k, err := curve.NewPrivateKey(hexDecode(t, input))
+ if err == nil {
+ t.Errorf("unexpectedly accepted %q", input)
+ } else if k != nil {
+ t.Error("PrivateKey was not nil on error")
+ } else if strings.Contains(err.Error(), "boringcrypto") {
+ t.Errorf("boringcrypto error leaked out: %v", err)
+ }
+ }
+ })
+}
+
+var invalidPublicKeys = map[ecdh.Curve][]string{
+ ecdh.P256(): {
+ // Bad lengths.
+ "",
+ "04",
+ strings.Repeat("04", 200),
+ // Infinity.
+ "00",
+ // Compressed encodings.
+ "036b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296",
+ "02e2534a3532d08fbba02dde659ee62bd0031fe2db785596ef509302446b030852",
+ // Points not on the curve.
+ "046b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c2964fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f6",
+ "0400000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ },
+ ecdh.P384(): {
+ // Bad lengths.
+ "",
+ "04",
+ strings.Repeat("04", 200),
+ // Infinity.
+ "00",
+ // Compressed encodings.
+ "03aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab7",
+ "0208d999057ba3d2d969260045c55b97f089025959a6f434d651d207d19fb96e9e4fe0e86ebe0e64f85b96a9c75295df61",
+ // Points not on the curve.
+ "04aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741e082542a385502f25dbf55296c3a545e3872760ab73617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da3113b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e60",
+ "04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ },
+ ecdh.P521(): {
+ // Bad lengths.
+ "",
+ "04",
+ strings.Repeat("04", 200),
+ // Infinity.
+ "00",
+ // Compressed encodings.
+ "030035b5df64ae2ac204c354b483487c9070cdc61c891c5ff39afc06c5d55541d3ceac8659e24afe3d0750e8b88e9f078af066a1d5025b08e5a5e2fbc87412871902f3",
+ "0200c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66",
+ // Points not on the curve.
+ "0400c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f828af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf97e7e31c2e5bd66011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088be94769fd16651",
+ "04000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000",
+ },
+ ecdh.X25519(): {},
+}
+
+func TestNewPublicKey(t *testing.T) {
+ testAllCurves(t, func(t *testing.T, curve ecdh.Curve) {
+ for _, input := range invalidPublicKeys[curve] {
+ k, err := curve.NewPublicKey(hexDecode(t, input))
+ if err == nil {
+ t.Errorf("unexpectedly accepted %q", input)
+ } else if k != nil {
+ t.Error("PublicKey was not nil on error")
+ } else if strings.Contains(err.Error(), "boringcrypto") {
+ t.Errorf("boringcrypto error leaked out: %v", err)
+ }
+ }
+ })
+}
+
+func testAllCurves(t *testing.T, f func(t *testing.T, curve ecdh.Curve)) {
+ t.Run("P256", func(t *testing.T) { f(t, ecdh.P256()) })
+ t.Run("P384", func(t *testing.T) { f(t, ecdh.P384()) })
+ t.Run("P521", func(t *testing.T) { f(t, ecdh.P521()) })
+ t.Run("X25519", func(t *testing.T) { f(t, ecdh.X25519()) })
+}
+
+func BenchmarkECDH(b *testing.B) {
+ benchmarkAllCurves(b, func(b *testing.B, curve ecdh.Curve) {
+ c, err := chacha20.NewUnauthenticatedCipher(make([]byte, 32), make([]byte, 12))
+ if err != nil {
+ b.Fatal(err)
+ }
+ rand := cipher.StreamReader{
+ S: c, R: zeroReader,
+ }
+
+ peerKey, err := curve.GenerateKey(rand)
+ if err != nil {
+ b.Fatal(err)
+ }
+ peerShare := peerKey.PublicKey().Bytes()
+ b.ResetTimer()
+ b.ReportAllocs()
+
+ var allocationsSink byte
+
+ for i := 0; i < b.N; i++ {
+ key, err := curve.GenerateKey(rand)
+ if err != nil {
+ b.Fatal(err)
+ }
+ share := key.PublicKey().Bytes()
+ peerPubKey, err := curve.NewPublicKey(peerShare)
+ if err != nil {
+ b.Fatal(err)
+ }
+ secret, err := key.ECDH(peerPubKey)
+ if err != nil {
+ b.Fatal(err)
+ }
+ allocationsSink ^= secret[0] ^ share[0]
+ }
+ })
+}
+
+func benchmarkAllCurves(b *testing.B, f func(b *testing.B, curve ecdh.Curve)) {
+ b.Run("P256", func(b *testing.B) { f(b, ecdh.P256()) })
+ b.Run("P384", func(b *testing.B) { f(b, ecdh.P384()) })
+ b.Run("P521", func(b *testing.B) { f(b, ecdh.P521()) })
+ b.Run("X25519", func(b *testing.B) { f(b, ecdh.X25519()) })
+}
+
+type zr struct{}
+
+// Read replaces the contents of dst with zeros. It is safe for concurrent use.
+func (zr) Read(dst []byte) (n int, err error) {
+ for i := range dst {
+ dst[i] = 0
+ }
+ return len(dst), nil
+}
+
+var zeroReader = zr{}
+
+const linkerTestProgram = `
+package main
+import "crypto/ecdh"
+import "crypto/rand"
+func main() {
+ curve := ecdh.P384()
+ key, err := curve.GenerateKey(rand.Reader)
+ if err != nil { panic(err) }
+ _, err = curve.NewPublicKey(key.PublicKey().Bytes())
+ if err != nil { panic(err) }
+ _, err = curve.NewPrivateKey(key.Bytes())
+ if err != nil { panic(err) }
+ _, err = key.ECDH(key.PublicKey())
+ if err != nil { panic(err) }
+ println("OK")
+}
+`
+
+// TestLinker ensures that using one curve does not bring all other
+// implementations into the binary. This also guarantees that govulncheck can
+// avoid warning about a curve-specific vulnerability if that curve is not used.
+func TestLinker(t *testing.T) {
+ if testing.Short() {
+ t.Skip("test requires running 'go build'")
+ }
+ testenv.MustHaveGoBuild(t)
+
+ dir := t.TempDir()
+ hello := filepath.Join(dir, "hello.go")
+ err := os.WriteFile(hello, []byte(linkerTestProgram), 0664)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ run := func(args ...string) string {
+ cmd := exec.Command(args[0], args[1:]...)
+ cmd.Dir = dir
+ out, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("%v: %v\n%s", args, err, string(out))
+ }
+ return string(out)
+ }
+
+ goBin := testenv.GoToolPath(t)
+ run(goBin, "build", "-o", "hello.exe", "hello.go")
+ if out := run("./hello.exe"); out != "OK\n" {
+ t.Error("unexpected output:", out)
+ }
+
+ // List all text symbols under crypto/... and make sure there are some for
+ // P384, but none for the other curves.
+ var consistent bool
+ nm := run(goBin, "tool", "nm", "hello.exe")
+ for _, match := range regexp.MustCompile(`(?m)T (crypto/.*)$`).FindAllStringSubmatch(nm, -1) {
+ symbol := strings.ToLower(match[1])
+ if strings.Contains(symbol, "p384") {
+ consistent = true
+ }
+ if strings.Contains(symbol, "p224") || strings.Contains(symbol, "p256") || strings.Contains(symbol, "p521") {
+ t.Errorf("unexpected symbol in program using only ecdh.P384: %s", match[1])
+ }
+ }
+ if !consistent {
+ t.Error("no P384 symbols found in program using ecdh.P384, test is broken")
+ }
+}
+
+func TestMismatchedCurves(t *testing.T) {
+ curves := []struct {
+ name string
+ curve ecdh.Curve
+ }{
+ {"P256", ecdh.P256()},
+ {"P384", ecdh.P384()},
+ {"P521", ecdh.P521()},
+ {"X25519", ecdh.X25519()},
+ }
+
+ for _, privCurve := range curves {
+ priv, err := privCurve.curve.GenerateKey(rand.Reader)
+ if err != nil {
+ t.Fatalf("failed to generate test key: %s", err)
+ }
+
+ for _, pubCurve := range curves {
+ if privCurve == pubCurve {
+ continue
+ }
+ t.Run(fmt.Sprintf("%s/%s", privCurve.name, pubCurve.name), func(t *testing.T) {
+ pub, err := pubCurve.curve.GenerateKey(rand.Reader)
+ if err != nil {
+ t.Fatalf("failed to generate test key: %s", err)
+ }
+ expected := "crypto/ecdh: private key and public key curves do not match"
+ _, err = priv.ECDH(pub.PublicKey())
+ if err.Error() != expected {
+ t.Fatalf("unexpected error: want %q, got %q", expected, err)
+ }
+ })
+ }
+ }
+}
diff --git a/src/crypto/ecdh/nist.go b/src/crypto/ecdh/nist.go
new file mode 100644
index 0000000..01354fa
--- /dev/null
+++ b/src/crypto/ecdh/nist.go
@@ -0,0 +1,275 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ecdh
+
+import (
+ "crypto/internal/boring"
+ "crypto/internal/nistec"
+ "crypto/internal/randutil"
+ "encoding/binary"
+ "errors"
+ "io"
+ "math/bits"
+)
+
+type nistCurve[Point nistPoint[Point]] struct {
+ name string
+ newPoint func() Point
+ scalarOrder []byte
+}
+
+// nistPoint is a generic constraint for the nistec Point types.
+type nistPoint[T any] interface {
+ Bytes() []byte
+ BytesX() ([]byte, error)
+ SetBytes([]byte) (T, error)
+ ScalarMult(T, []byte) (T, error)
+ ScalarBaseMult([]byte) (T, error)
+}
+
+func (c *nistCurve[Point]) String() string {
+ return c.name
+}
+
+var errInvalidPrivateKey = errors.New("crypto/ecdh: invalid private key")
+
+func (c *nistCurve[Point]) GenerateKey(rand io.Reader) (*PrivateKey, error) {
+ if boring.Enabled && rand == boring.RandReader {
+ key, bytes, err := boring.GenerateKeyECDH(c.name)
+ if err != nil {
+ return nil, err
+ }
+ return newBoringPrivateKey(c, key, bytes)
+ }
+
+ key := make([]byte, len(c.scalarOrder))
+ randutil.MaybeReadByte(rand)
+ for {
+ if _, err := io.ReadFull(rand, key); err != nil {
+ return nil, err
+ }
+
+ // Mask off any excess bits if the size of the underlying field is not a
+ // whole number of bytes, which is only the case for P-521. We use a
+ // pointer to the scalarOrder field because comparing generic and
+ // instantiated types is not supported.
+ if &c.scalarOrder[0] == &p521Order[0] {
+ key[0] &= 0b0000_0001
+ }
+
+ // In tests, rand will return all zeros and NewPrivateKey will reject
+ // the zero key as it generates the identity as a public key. This also
+ // makes this function consistent with crypto/elliptic.GenerateKey.
+ key[1] ^= 0x42
+
+ k, err := c.NewPrivateKey(key)
+ if err == errInvalidPrivateKey {
+ continue
+ }
+ return k, err
+ }
+}
+
+func (c *nistCurve[Point]) NewPrivateKey(key []byte) (*PrivateKey, error) {
+ if len(key) != len(c.scalarOrder) {
+ return nil, errors.New("crypto/ecdh: invalid private key size")
+ }
+ if isZero(key) || !isLess(key, c.scalarOrder) {
+ return nil, errInvalidPrivateKey
+ }
+ if boring.Enabled {
+ bk, err := boring.NewPrivateKeyECDH(c.name, key)
+ if err != nil {
+ return nil, err
+ }
+ return newBoringPrivateKey(c, bk, key)
+ }
+ k := &PrivateKey{
+ curve: c,
+ privateKey: append([]byte{}, key...),
+ }
+ return k, nil
+}
+
+func newBoringPrivateKey(c Curve, bk *boring.PrivateKeyECDH, privateKey []byte) (*PrivateKey, error) {
+ k := &PrivateKey{
+ curve: c,
+ boring: bk,
+ privateKey: append([]byte(nil), privateKey...),
+ }
+ return k, nil
+}
+
+func (c *nistCurve[Point]) privateKeyToPublicKey(key *PrivateKey) *PublicKey {
+ boring.Unreachable()
+ if key.curve != c {
+ panic("crypto/ecdh: internal error: converting the wrong key type")
+ }
+ p, err := c.newPoint().ScalarBaseMult(key.privateKey)
+ if err != nil {
+ // This is unreachable because the only error condition of
+ // ScalarBaseMult is if the input is not the right size.
+ panic("crypto/ecdh: internal error: nistec ScalarBaseMult failed for a fixed-size input")
+ }
+ publicKey := p.Bytes()
+ if len(publicKey) == 1 {
+ // The encoding of the identity is a single 0x00 byte. This is
+ // unreachable because the only scalar that generates the identity is
+ // zero, which is rejected by NewPrivateKey.
+ panic("crypto/ecdh: internal error: nistec ScalarBaseMult returned the identity")
+ }
+ return &PublicKey{
+ curve: key.curve,
+ publicKey: publicKey,
+ }
+}
+
+// isZero returns whether a is all zeroes in constant time.
+func isZero(a []byte) bool {
+ var acc byte
+ for _, b := range a {
+ acc |= b
+ }
+ return acc == 0
+}
+
+// isLess returns whether a < b, where a and b are big-endian buffers of the
+// same length and shorter than 72 bytes.
+func isLess(a, b []byte) bool {
+ if len(a) != len(b) {
+ panic("crypto/ecdh: internal error: mismatched isLess inputs")
+ }
+
+ // Copy the values into a fixed-size preallocated little-endian buffer.
+ // 72 bytes is enough for every scalar in this package, and having a fixed
+ // size lets us avoid heap allocations.
+ if len(a) > 72 {
+ panic("crypto/ecdh: internal error: isLess input too large")
+ }
+ bufA, bufB := make([]byte, 72), make([]byte, 72)
+ for i := range a {
+ bufA[i], bufB[i] = a[len(a)-i-1], b[len(b)-i-1]
+ }
+
+ // Perform a subtraction with borrow.
+ var borrow uint64
+ for i := 0; i < len(bufA); i += 8 {
+ limbA, limbB := binary.LittleEndian.Uint64(bufA[i:]), binary.LittleEndian.Uint64(bufB[i:])
+ _, borrow = bits.Sub64(limbA, limbB, borrow)
+ }
+
+ // If there is a borrow at the end of the operation, then a < b.
+ return borrow == 1
+}
+
+func (c *nistCurve[Point]) NewPublicKey(key []byte) (*PublicKey, error) {
+ // Reject the point at infinity and compressed encodings.
+ if len(key) == 0 || key[0] != 4 {
+ return nil, errors.New("crypto/ecdh: invalid public key")
+ }
+ k := &PublicKey{
+ curve: c,
+ publicKey: append([]byte{}, key...),
+ }
+ if boring.Enabled {
+ bk, err := boring.NewPublicKeyECDH(c.name, k.publicKey)
+ if err != nil {
+ return nil, err
+ }
+ k.boring = bk
+ } else {
+ // SetBytes also checks that the point is on the curve.
+ if _, err := c.newPoint().SetBytes(key); err != nil {
+ return nil, err
+ }
+ }
+ return k, nil
+}
+
+func (c *nistCurve[Point]) ecdh(local *PrivateKey, remote *PublicKey) ([]byte, error) {
+ // Note that this function can't return an error, as NewPublicKey rejects
+ // invalid points and the point at infinity, and NewPrivateKey rejects
+ // invalid scalars and the zero value. BytesX returns an error for the point
+ // at infinity, but in a prime order group such as the NIST curves that can
+ // only be the result of a scalar multiplication if one of the inputs is the
+ // zero scalar or the point at infinity.
+
+ if boring.Enabled {
+ return boring.ECDH(local.boring, remote.boring)
+ }
+
+ boring.Unreachable()
+ p, err := c.newPoint().SetBytes(remote.publicKey)
+ if err != nil {
+ return nil, err
+ }
+ if _, err := p.ScalarMult(p, local.privateKey); err != nil {
+ return nil, err
+ }
+ return p.BytesX()
+}
+
+// P256 returns a Curve which implements NIST P-256 (FIPS 186-3, section D.2.3),
+// also known as secp256r1 or prime256v1.
+//
+// Multiple invocations of this function will return the same value, which can
+// be used for equality checks and switch statements.
+func P256() Curve { return p256 }
+
+var p256 = &nistCurve[*nistec.P256Point]{
+ name: "P-256",
+ newPoint: nistec.NewP256Point,
+ scalarOrder: p256Order,
+}
+
+var p256Order = []byte{
+ 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}
+
+// P384 returns a Curve which implements NIST P-384 (FIPS 186-3, section D.2.4),
+// also known as secp384r1.
+//
+// Multiple invocations of this function will return the same value, which can
+// be used for equality checks and switch statements.
+func P384() Curve { return p384 }
+
+var p384 = &nistCurve[*nistec.P384Point]{
+ name: "P-384",
+ newPoint: nistec.NewP384Point,
+ scalarOrder: p384Order,
+}
+
+var p384Order = []byte{
+ 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}
+
+// P521 returns a Curve which implements NIST P-521 (FIPS 186-3, section D.2.5),
+// also known as secp521r1.
+//
+// Multiple invocations of this function will return the same value, which can
+// be used for equality checks and switch statements.
+func P521() Curve { return p521 }
+
+var p521 = &nistCurve[*nistec.P521Point]{
+ name: "P-521",
+ newPoint: nistec.NewP521Point,
+ scalarOrder: p521Order,
+}
+
+var p521Order = []byte{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}
diff --git a/src/crypto/ecdh/x25519.go b/src/crypto/ecdh/x25519.go
new file mode 100644
index 0000000..dbc3ea9
--- /dev/null
+++ b/src/crypto/ecdh/x25519.go
@@ -0,0 +1,136 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ecdh
+
+import (
+ "crypto/internal/edwards25519/field"
+ "crypto/internal/randutil"
+ "errors"
+ "io"
+)
+
+var (
+ x25519PublicKeySize = 32
+ x25519PrivateKeySize = 32
+ x25519SharedSecretSize = 32
+)
+
+// X25519 returns a Curve which implements the X25519 function over Curve25519
+// (RFC 7748, Section 5).
+//
+// Multiple invocations of this function will return the same value, so it can
+// be used for equality checks and switch statements.
+func X25519() Curve { return x25519 }
+
+var x25519 = &x25519Curve{}
+
+type x25519Curve struct{}
+
+func (c *x25519Curve) String() string {
+ return "X25519"
+}
+
+func (c *x25519Curve) GenerateKey(rand io.Reader) (*PrivateKey, error) {
+ key := make([]byte, x25519PrivateKeySize)
+ randutil.MaybeReadByte(rand)
+ if _, err := io.ReadFull(rand, key); err != nil {
+ return nil, err
+ }
+ return c.NewPrivateKey(key)
+}
+
+func (c *x25519Curve) NewPrivateKey(key []byte) (*PrivateKey, error) {
+ if len(key) != x25519PrivateKeySize {
+ return nil, errors.New("crypto/ecdh: invalid private key size")
+ }
+ return &PrivateKey{
+ curve: c,
+ privateKey: append([]byte{}, key...),
+ }, nil
+}
+
+func (c *x25519Curve) privateKeyToPublicKey(key *PrivateKey) *PublicKey {
+ if key.curve != c {
+ panic("crypto/ecdh: internal error: converting the wrong key type")
+ }
+ k := &PublicKey{
+ curve: key.curve,
+ publicKey: make([]byte, x25519PublicKeySize),
+ }
+ x25519Basepoint := [32]byte{9}
+ x25519ScalarMult(k.publicKey, key.privateKey, x25519Basepoint[:])
+ return k
+}
+
+func (c *x25519Curve) NewPublicKey(key []byte) (*PublicKey, error) {
+ if len(key) != x25519PublicKeySize {
+ return nil, errors.New("crypto/ecdh: invalid public key")
+ }
+ return &PublicKey{
+ curve: c,
+ publicKey: append([]byte{}, key...),
+ }, nil
+}
+
+func (c *x25519Curve) ecdh(local *PrivateKey, remote *PublicKey) ([]byte, error) {
+ out := make([]byte, x25519SharedSecretSize)
+ x25519ScalarMult(out, local.privateKey, remote.publicKey)
+ if isZero(out) {
+ return nil, errors.New("crypto/ecdh: bad X25519 remote ECDH input: low order point")
+ }
+ return out, nil
+}
+
+func x25519ScalarMult(dst, scalar, point []byte) {
+ var e [32]byte
+
+ copy(e[:], scalar[:])
+ e[0] &= 248
+ e[31] &= 127
+ e[31] |= 64
+
+ var x1, x2, z2, x3, z3, tmp0, tmp1 field.Element
+ x1.SetBytes(point[:])
+ x2.One()
+ x3.Set(&x1)
+ z3.One()
+
+ swap := 0
+ for pos := 254; pos >= 0; pos-- {
+ b := e[pos/8] >> uint(pos&7)
+ b &= 1
+ swap ^= int(b)
+ x2.Swap(&x3, swap)
+ z2.Swap(&z3, swap)
+ swap = int(b)
+
+ tmp0.Subtract(&x3, &z3)
+ tmp1.Subtract(&x2, &z2)
+ x2.Add(&x2, &z2)
+ z2.Add(&x3, &z3)
+ z3.Multiply(&tmp0, &x2)
+ z2.Multiply(&z2, &tmp1)
+ tmp0.Square(&tmp1)
+ tmp1.Square(&x2)
+ x3.Add(&z3, &z2)
+ z2.Subtract(&z3, &z2)
+ x2.Multiply(&tmp1, &tmp0)
+ tmp1.Subtract(&tmp1, &tmp0)
+ z2.Square(&z2)
+
+ z3.Mult32(&tmp1, 121666)
+ x3.Square(&x3)
+ tmp0.Add(&tmp0, &z3)
+ z3.Multiply(&x1, &z2)
+ z2.Multiply(&tmp1, &tmp0)
+ }
+
+ x2.Swap(&x3, swap)
+ z2.Swap(&z3, swap)
+
+ z2.Invert(&z2)
+ x2.Multiply(&x2, &z2)
+ copy(dst[:], x2.Bytes())
+}
diff --git a/src/crypto/ecdsa/boring.go b/src/crypto/ecdsa/boring.go
new file mode 100644
index 0000000..275c60b
--- /dev/null
+++ b/src/crypto/ecdsa/boring.go
@@ -0,0 +1,106 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto
+
+package ecdsa
+
+import (
+ "crypto/internal/boring"
+ "crypto/internal/boring/bbig"
+ "crypto/internal/boring/bcache"
+ "math/big"
+)
+
+// Cached conversions from Go PublicKey/PrivateKey to BoringCrypto.
+//
+// The first operation on a PublicKey or PrivateKey makes a parallel
+// BoringCrypto key and saves it in pubCache or privCache.
+//
+// We could just assume that once used in a Sign or Verify operation,
+// a particular key is never again modified, but that has not been a
+// stated assumption before. Just in case there is any existing code that
+// does modify the key between operations, we save the original values
+// alongside the cached BoringCrypto key and check that the real key
+// still matches before using the cached key. The theory is that the real
+// operations are significantly more expensive than the comparison.
+
+var pubCache bcache.Cache[PublicKey, boringPub]
+var privCache bcache.Cache[PrivateKey, boringPriv]
+
+func init() {
+ pubCache.Register()
+ privCache.Register()
+}
+
+type boringPub struct {
+ key *boring.PublicKeyECDSA
+ orig PublicKey
+}
+
+func boringPublicKey(pub *PublicKey) (*boring.PublicKeyECDSA, error) {
+ b := pubCache.Get(pub)
+ if b != nil && publicKeyEqual(&b.orig, pub) {
+ return b.key, nil
+ }
+
+ b = new(boringPub)
+ b.orig = copyPublicKey(pub)
+ key, err := boring.NewPublicKeyECDSA(b.orig.Curve.Params().Name, bbig.Enc(b.orig.X), bbig.Enc(b.orig.Y))
+ if err != nil {
+ return nil, err
+ }
+ b.key = key
+ pubCache.Put(pub, b)
+ return key, nil
+}
+
+type boringPriv struct {
+ key *boring.PrivateKeyECDSA
+ orig PrivateKey
+}
+
+func boringPrivateKey(priv *PrivateKey) (*boring.PrivateKeyECDSA, error) {
+ b := privCache.Get(priv)
+ if b != nil && privateKeyEqual(&b.orig, priv) {
+ return b.key, nil
+ }
+
+ b = new(boringPriv)
+ b.orig = copyPrivateKey(priv)
+ key, err := boring.NewPrivateKeyECDSA(b.orig.Curve.Params().Name, bbig.Enc(b.orig.X), bbig.Enc(b.orig.Y), bbig.Enc(b.orig.D))
+ if err != nil {
+ return nil, err
+ }
+ b.key = key
+ privCache.Put(priv, b)
+ return key, nil
+}
+
+func publicKeyEqual(k1, k2 *PublicKey) bool {
+ return k1.X != nil &&
+ k1.Curve.Params() == k2.Curve.Params() &&
+ k1.X.Cmp(k2.X) == 0 &&
+ k1.Y.Cmp(k2.Y) == 0
+}
+
+func privateKeyEqual(k1, k2 *PrivateKey) bool {
+ return publicKeyEqual(&k1.PublicKey, &k2.PublicKey) &&
+ k1.D.Cmp(k2.D) == 0
+}
+
+func copyPublicKey(k *PublicKey) PublicKey {
+ return PublicKey{
+ Curve: k.Curve,
+ X: new(big.Int).Set(k.X),
+ Y: new(big.Int).Set(k.Y),
+ }
+}
+
+func copyPrivateKey(k *PrivateKey) PrivateKey {
+ return PrivateKey{
+ PublicKey: copyPublicKey(&k.PublicKey),
+ D: new(big.Int).Set(k.D),
+ }
+}
diff --git a/src/crypto/ecdsa/ecdsa.go b/src/crypto/ecdsa/ecdsa.go
new file mode 100644
index 0000000..03a9a72
--- /dev/null
+++ b/src/crypto/ecdsa/ecdsa.go
@@ -0,0 +1,660 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ecdsa implements the Elliptic Curve Digital Signature Algorithm, as
+// defined in FIPS 186-4 and SEC 1, Version 2.0.
+//
+// Signatures generated by this package are not deterministic, but entropy is
+// mixed with the private key and the message, achieving the same level of
+// security in case of randomness source failure.
+package ecdsa
+
+// [FIPS 186-4] references ANSI X9.62-2005 for the bulk of the ECDSA algorithm.
+// That standard is not freely available, which is a problem in an open source
+// implementation, because not only the implementer, but also any maintainer,
+// contributor, reviewer, auditor, and learner needs access to it. Instead, this
+// package references and follows the equivalent [SEC 1, Version 2.0].
+//
+// [FIPS 186-4]: https://nvlpubs.nist.gov/nistpubs/FIPS/NIST.FIPS.186-4.pdf
+// [SEC 1, Version 2.0]: https://www.secg.org/sec1-v2.pdf
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/ecdh"
+ "crypto/elliptic"
+ "crypto/internal/bigmod"
+ "crypto/internal/boring"
+ "crypto/internal/boring/bbig"
+ "crypto/internal/nistec"
+ "crypto/internal/randutil"
+ "crypto/sha512"
+ "crypto/subtle"
+ "errors"
+ "io"
+ "math/big"
+ "sync"
+
+ "golang.org/x/crypto/cryptobyte"
+ "golang.org/x/crypto/cryptobyte/asn1"
+)
+
+// PublicKey represents an ECDSA public key.
+type PublicKey struct {
+ elliptic.Curve
+ X, Y *big.Int
+}
+
+// Any methods implemented on PublicKey might need to also be implemented on
+// PrivateKey, as the latter embeds the former and will expose its methods.
+
+// ECDH returns k as a [ecdh.PublicKey]. It returns an error if the key is
+// invalid according to the definition of [ecdh.Curve.NewPublicKey], or if the
+// Curve is not supported by crypto/ecdh.
+func (k *PublicKey) ECDH() (*ecdh.PublicKey, error) {
+ c := curveToECDH(k.Curve)
+ if c == nil {
+ return nil, errors.New("ecdsa: unsupported curve by crypto/ecdh")
+ }
+ if !k.Curve.IsOnCurve(k.X, k.Y) {
+ return nil, errors.New("ecdsa: invalid public key")
+ }
+ return c.NewPublicKey(elliptic.Marshal(k.Curve, k.X, k.Y))
+}
+
+// Equal reports whether pub and x have the same value.
+//
+// Two keys are only considered to have the same value if they have the same Curve value.
+// Note that for example elliptic.P256() and elliptic.P256().Params() are different
+// values, as the latter is a generic not constant time implementation.
+func (pub *PublicKey) Equal(x crypto.PublicKey) bool {
+ xx, ok := x.(*PublicKey)
+ if !ok {
+ return false
+ }
+ return bigIntEqual(pub.X, xx.X) && bigIntEqual(pub.Y, xx.Y) &&
+ // Standard library Curve implementations are singletons, so this check
+ // will work for those. Other Curves might be equivalent even if not
+ // singletons, but there is no definitive way to check for that, and
+ // better to err on the side of safety.
+ pub.Curve == xx.Curve
+}
+
+// PrivateKey represents an ECDSA private key.
+type PrivateKey struct {
+ PublicKey
+ D *big.Int
+}
+
+// ECDH returns k as a [ecdh.PrivateKey]. It returns an error if the key is
+// invalid according to the definition of [ecdh.Curve.NewPrivateKey], or if the
+// Curve is not supported by crypto/ecdh.
+func (k *PrivateKey) ECDH() (*ecdh.PrivateKey, error) {
+ c := curveToECDH(k.Curve)
+ if c == nil {
+ return nil, errors.New("ecdsa: unsupported curve by crypto/ecdh")
+ }
+ size := (k.Curve.Params().N.BitLen() + 7) / 8
+ if k.D.BitLen() > size*8 {
+ return nil, errors.New("ecdsa: invalid private key")
+ }
+ return c.NewPrivateKey(k.D.FillBytes(make([]byte, size)))
+}
+
+func curveToECDH(c elliptic.Curve) ecdh.Curve {
+ switch c {
+ case elliptic.P256():
+ return ecdh.P256()
+ case elliptic.P384():
+ return ecdh.P384()
+ case elliptic.P521():
+ return ecdh.P521()
+ default:
+ return nil
+ }
+}
+
+// Public returns the public key corresponding to priv.
+func (priv *PrivateKey) Public() crypto.PublicKey {
+ return &priv.PublicKey
+}
+
+// Equal reports whether priv and x have the same value.
+//
+// See PublicKey.Equal for details on how Curve is compared.
+func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool {
+ xx, ok := x.(*PrivateKey)
+ if !ok {
+ return false
+ }
+ return priv.PublicKey.Equal(&xx.PublicKey) && bigIntEqual(priv.D, xx.D)
+}
+
+// bigIntEqual reports whether a and b are equal leaking only their bit length
+// through timing side-channels.
+func bigIntEqual(a, b *big.Int) bool {
+ return subtle.ConstantTimeCompare(a.Bytes(), b.Bytes()) == 1
+}
+
+// Sign signs digest with priv, reading randomness from rand. The opts argument
+// is not currently used but, in keeping with the crypto.Signer interface,
+// should be the hash function used to digest the message.
+//
+// This method implements crypto.Signer, which is an interface to support keys
+// where the private part is kept in, for example, a hardware module. Common
+// uses can use the SignASN1 function in this package directly.
+func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
+ return SignASN1(rand, priv, digest)
+}
+
+// GenerateKey generates a public and private key pair.
+func GenerateKey(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
+ randutil.MaybeReadByte(rand)
+
+ if boring.Enabled && rand == boring.RandReader {
+ x, y, d, err := boring.GenerateKeyECDSA(c.Params().Name)
+ if err != nil {
+ return nil, err
+ }
+ return &PrivateKey{PublicKey: PublicKey{Curve: c, X: bbig.Dec(x), Y: bbig.Dec(y)}, D: bbig.Dec(d)}, nil
+ }
+ boring.UnreachableExceptTests()
+
+ switch c.Params() {
+ case elliptic.P224().Params():
+ return generateNISTEC(p224(), rand)
+ case elliptic.P256().Params():
+ return generateNISTEC(p256(), rand)
+ case elliptic.P384().Params():
+ return generateNISTEC(p384(), rand)
+ case elliptic.P521().Params():
+ return generateNISTEC(p521(), rand)
+ default:
+ return generateLegacy(c, rand)
+ }
+}
+
+func generateNISTEC[Point nistPoint[Point]](c *nistCurve[Point], rand io.Reader) (*PrivateKey, error) {
+ k, Q, err := randomPoint(c, rand)
+ if err != nil {
+ return nil, err
+ }
+
+ priv := new(PrivateKey)
+ priv.PublicKey.Curve = c.curve
+ priv.D = new(big.Int).SetBytes(k.Bytes(c.N))
+ priv.PublicKey.X, priv.PublicKey.Y, err = c.pointToAffine(Q)
+ if err != nil {
+ return nil, err
+ }
+ return priv, nil
+}
+
+// randomPoint returns a random scalar and the corresponding point using the
+// procedure given in FIPS 186-4, Appendix B.5.2 (rejection sampling).
+func randomPoint[Point nistPoint[Point]](c *nistCurve[Point], rand io.Reader) (k *bigmod.Nat, p Point, err error) {
+ k = bigmod.NewNat()
+ for {
+ b := make([]byte, c.N.Size())
+ if _, err = io.ReadFull(rand, b); err != nil {
+ return
+ }
+
+ // Mask off any excess bits to increase the chance of hitting a value in
+ // (0, N). These are the most dangerous lines in the package and maybe in
+ // the library: a single bit of bias in the selection of nonces would likely
+ // lead to key recovery, but no tests would fail. Look but DO NOT TOUCH.
+ if excess := len(b)*8 - c.N.BitLen(); excess > 0 {
+ // Just to be safe, assert that this only happens for the one curve that
+ // doesn't have a round number of bits.
+ if excess != 0 && c.curve.Params().Name != "P-521" {
+ panic("ecdsa: internal error: unexpectedly masking off bits")
+ }
+ b[0] >>= excess
+ }
+
+ // FIPS 186-4 makes us check k <= N - 2 and then add one.
+ // Checking 0 < k <= N - 1 is strictly equivalent.
+ // None of this matters anyway because the chance of selecting
+ // zero is cryptographically negligible.
+ if _, err = k.SetBytes(b, c.N); err == nil && k.IsZero() == 0 {
+ break
+ }
+
+ if testingOnlyRejectionSamplingLooped != nil {
+ testingOnlyRejectionSamplingLooped()
+ }
+ }
+
+ p, err = c.newPoint().ScalarBaseMult(k.Bytes(c.N))
+ return
+}
+
+// testingOnlyRejectionSamplingLooped is called when rejection sampling in
+// randomPoint rejects a candidate for being higher than the modulus.
+var testingOnlyRejectionSamplingLooped func()
+
+// errNoAsm is returned by signAsm and verifyAsm when the assembly
+// implementation is not available.
+var errNoAsm = errors.New("no assembly implementation available")
+
+// SignASN1 signs a hash (which should be the result of hashing a larger message)
+// using the private key, priv. If the hash is longer than the bit-length of the
+// private key's curve order, the hash will be truncated to that length. It
+// returns the ASN.1 encoded signature.
+func SignASN1(rand io.Reader, priv *PrivateKey, hash []byte) ([]byte, error) {
+ randutil.MaybeReadByte(rand)
+
+ if boring.Enabled && rand == boring.RandReader {
+ b, err := boringPrivateKey(priv)
+ if err != nil {
+ return nil, err
+ }
+ return boring.SignMarshalECDSA(b, hash)
+ }
+ boring.UnreachableExceptTests()
+
+ csprng, err := mixedCSPRNG(rand, priv, hash)
+ if err != nil {
+ return nil, err
+ }
+
+ if sig, err := signAsm(priv, csprng, hash); err != errNoAsm {
+ return sig, err
+ }
+
+ switch priv.Curve.Params() {
+ case elliptic.P224().Params():
+ return signNISTEC(p224(), priv, csprng, hash)
+ case elliptic.P256().Params():
+ return signNISTEC(p256(), priv, csprng, hash)
+ case elliptic.P384().Params():
+ return signNISTEC(p384(), priv, csprng, hash)
+ case elliptic.P521().Params():
+ return signNISTEC(p521(), priv, csprng, hash)
+ default:
+ return signLegacy(priv, csprng, hash)
+ }
+}
+
+func signNISTEC[Point nistPoint[Point]](c *nistCurve[Point], priv *PrivateKey, csprng io.Reader, hash []byte) (sig []byte, err error) {
+ // SEC 1, Version 2.0, Section 4.1.3
+
+ k, R, err := randomPoint(c, csprng)
+ if err != nil {
+ return nil, err
+ }
+
+ // kInv = k⁻¹
+ kInv := bigmod.NewNat()
+ inverse(c, kInv, k)
+
+ Rx, err := R.BytesX()
+ if err != nil {
+ return nil, err
+ }
+ r, err := bigmod.NewNat().SetOverflowingBytes(Rx, c.N)
+ if err != nil {
+ return nil, err
+ }
+
+ // The spec wants us to retry here, but the chance of hitting this condition
+ // on a large prime-order group like the NIST curves we support is
+ // cryptographically negligible. If we hit it, something is awfully wrong.
+ if r.IsZero() == 1 {
+ return nil, errors.New("ecdsa: internal error: r is zero")
+ }
+
+ e := bigmod.NewNat()
+ hashToNat(c, e, hash)
+
+ s, err := bigmod.NewNat().SetBytes(priv.D.Bytes(), c.N)
+ if err != nil {
+ return nil, err
+ }
+ s.Mul(r, c.N)
+ s.Add(e, c.N)
+ s.Mul(kInv, c.N)
+
+ // Again, the chance of this happening is cryptographically negligible.
+ if s.IsZero() == 1 {
+ return nil, errors.New("ecdsa: internal error: s is zero")
+ }
+
+ return encodeSignature(r.Bytes(c.N), s.Bytes(c.N))
+}
+
+func encodeSignature(r, s []byte) ([]byte, error) {
+ var b cryptobyte.Builder
+ b.AddASN1(asn1.SEQUENCE, func(b *cryptobyte.Builder) {
+ addASN1IntBytes(b, r)
+ addASN1IntBytes(b, s)
+ })
+ return b.Bytes()
+}
+
+// addASN1IntBytes encodes in ASN.1 a positive integer represented as
+// a big-endian byte slice with zero or more leading zeroes.
+func addASN1IntBytes(b *cryptobyte.Builder, bytes []byte) {
+ for len(bytes) > 0 && bytes[0] == 0 {
+ bytes = bytes[1:]
+ }
+ if len(bytes) == 0 {
+ b.SetError(errors.New("invalid integer"))
+ return
+ }
+ b.AddASN1(asn1.INTEGER, func(c *cryptobyte.Builder) {
+ if bytes[0]&0x80 != 0 {
+ c.AddUint8(0)
+ }
+ c.AddBytes(bytes)
+ })
+}
+
+// inverse sets kInv to the inverse of k modulo the order of the curve.
+func inverse[Point nistPoint[Point]](c *nistCurve[Point], kInv, k *bigmod.Nat) {
+ if c.curve.Params().Name == "P-256" {
+ kBytes, err := nistec.P256OrdInverse(k.Bytes(c.N))
+ // Some platforms don't implement P256OrdInverse, and always return an error.
+ if err == nil {
+ _, err := kInv.SetBytes(kBytes, c.N)
+ if err != nil {
+ panic("ecdsa: internal error: P256OrdInverse produced an invalid value")
+ }
+ return
+ }
+ }
+
+ // Calculate the inverse of s in GF(N) using Fermat's method
+ // (exponentiation modulo P - 2, per Euler's theorem)
+ kInv.Exp(k, c.nMinus2, c.N)
+}
+
+// hashToNat sets e to the left-most bits of hash, according to
+// SEC 1, Section 4.1.3, point 5 and Section 4.1.4, point 3.
+func hashToNat[Point nistPoint[Point]](c *nistCurve[Point], e *bigmod.Nat, hash []byte) {
+ // ECDSA asks us to take the left-most log2(N) bits of hash, and use them as
+ // an integer modulo N. This is the absolute worst of all worlds: we still
+ // have to reduce, because the result might still overflow N, but to take
+ // the left-most bits for P-521 we have to do a right shift.
+ if size := c.N.Size(); len(hash) >= size {
+ hash = hash[:size]
+ if excess := len(hash)*8 - c.N.BitLen(); excess > 0 {
+ hash = bytes.Clone(hash)
+ for i := len(hash) - 1; i >= 0; i-- {
+ hash[i] >>= excess
+ if i > 0 {
+ hash[i] |= hash[i-1] << (8 - excess)
+ }
+ }
+ }
+ }
+ _, err := e.SetOverflowingBytes(hash, c.N)
+ if err != nil {
+ panic("ecdsa: internal error: truncated hash is too long")
+ }
+}
+
+// mixedCSPRNG returns a CSPRNG that mixes entropy from rand with the message
+// and the private key, to protect the key in case rand fails. This is
+// equivalent in security to RFC 6979 deterministic nonce generation, but still
+// produces randomized signatures.
+func mixedCSPRNG(rand io.Reader, priv *PrivateKey, hash []byte) (io.Reader, error) {
+ // This implementation derives the nonce from an AES-CTR CSPRNG keyed by:
+ //
+ // SHA2-512(priv.D || entropy || hash)[:32]
+ //
+ // The CSPRNG key is indifferentiable from a random oracle as shown in
+ // [Coron], the AES-CTR stream is indifferentiable from a random oracle
+ // under standard cryptographic assumptions (see [Larsson] for examples).
+ //
+ // [Coron]: https://cs.nyu.edu/~dodis/ps/merkle.pdf
+ // [Larsson]: https://web.archive.org/web/20040719170906/https://www.nada.kth.se/kurser/kth/2D1441/semteo03/lecturenotes/assump.pdf
+
+ // Get 256 bits of entropy from rand.
+ entropy := make([]byte, 32)
+ if _, err := io.ReadFull(rand, entropy); err != nil {
+ return nil, err
+ }
+
+ // Initialize an SHA-512 hash context; digest...
+ md := sha512.New()
+ md.Write(priv.D.Bytes()) // the private key,
+ md.Write(entropy) // the entropy,
+ md.Write(hash) // and the input hash;
+ key := md.Sum(nil)[:32] // and compute ChopMD-256(SHA-512),
+ // which is an indifferentiable MAC.
+
+ // Create an AES-CTR instance to use as a CSPRNG.
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ return nil, err
+ }
+
+ // Create a CSPRNG that xors a stream of zeros with
+ // the output of the AES-CTR instance.
+ const aesIV = "IV for ECDSA CTR"
+ return &cipher.StreamReader{
+ R: zeroReader,
+ S: cipher.NewCTR(block, []byte(aesIV)),
+ }, nil
+}
+
+type zr struct{}
+
+var zeroReader = zr{}
+
+// Read replaces the contents of dst with zeros. It is safe for concurrent use.
+func (zr) Read(dst []byte) (n int, err error) {
+ for i := range dst {
+ dst[i] = 0
+ }
+ return len(dst), nil
+}
+
+// VerifyASN1 verifies the ASN.1 encoded signature, sig, of hash using the
+// public key, pub. Its return value records whether the signature is valid.
+func VerifyASN1(pub *PublicKey, hash, sig []byte) bool {
+ if boring.Enabled {
+ key, err := boringPublicKey(pub)
+ if err != nil {
+ return false
+ }
+ return boring.VerifyECDSA(key, hash, sig)
+ }
+ boring.UnreachableExceptTests()
+
+ if err := verifyAsm(pub, hash, sig); err != errNoAsm {
+ return err == nil
+ }
+
+ switch pub.Curve.Params() {
+ case elliptic.P224().Params():
+ return verifyNISTEC(p224(), pub, hash, sig)
+ case elliptic.P256().Params():
+ return verifyNISTEC(p256(), pub, hash, sig)
+ case elliptic.P384().Params():
+ return verifyNISTEC(p384(), pub, hash, sig)
+ case elliptic.P521().Params():
+ return verifyNISTEC(p521(), pub, hash, sig)
+ default:
+ return verifyLegacy(pub, hash, sig)
+ }
+}
+
+func verifyNISTEC[Point nistPoint[Point]](c *nistCurve[Point], pub *PublicKey, hash, sig []byte) bool {
+ rBytes, sBytes, err := parseSignature(sig)
+ if err != nil {
+ return false
+ }
+
+ Q, err := c.pointFromAffine(pub.X, pub.Y)
+ if err != nil {
+ return false
+ }
+
+ // SEC 1, Version 2.0, Section 4.1.4
+
+ r, err := bigmod.NewNat().SetBytes(rBytes, c.N)
+ if err != nil || r.IsZero() == 1 {
+ return false
+ }
+ s, err := bigmod.NewNat().SetBytes(sBytes, c.N)
+ if err != nil || s.IsZero() == 1 {
+ return false
+ }
+
+ e := bigmod.NewNat()
+ hashToNat(c, e, hash)
+
+ // w = s⁻¹
+ w := bigmod.NewNat()
+ inverse(c, w, s)
+
+ // p₁ = [e * s⁻¹]G
+ p1, err := c.newPoint().ScalarBaseMult(e.Mul(w, c.N).Bytes(c.N))
+ if err != nil {
+ return false
+ }
+ // p₂ = [r * s⁻¹]Q
+ p2, err := Q.ScalarMult(Q, w.Mul(r, c.N).Bytes(c.N))
+ if err != nil {
+ return false
+ }
+ // BytesX returns an error for the point at infinity.
+ Rx, err := p1.Add(p1, p2).BytesX()
+ if err != nil {
+ return false
+ }
+
+ v, err := bigmod.NewNat().SetOverflowingBytes(Rx, c.N)
+ if err != nil {
+ return false
+ }
+
+ return v.Equal(r) == 1
+}
+
+func parseSignature(sig []byte) (r, s []byte, err error) {
+ var inner cryptobyte.String
+ input := cryptobyte.String(sig)
+ if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
+ !input.Empty() ||
+ !inner.ReadASN1Integer(&r) ||
+ !inner.ReadASN1Integer(&s) ||
+ !inner.Empty() {
+ return nil, nil, errors.New("invalid ASN.1")
+ }
+ return r, s, nil
+}
+
+type nistCurve[Point nistPoint[Point]] struct {
+ newPoint func() Point
+ curve elliptic.Curve
+ N *bigmod.Modulus
+ nMinus2 []byte
+}
+
+// nistPoint is a generic constraint for the nistec Point types.
+type nistPoint[T any] interface {
+ Bytes() []byte
+ BytesX() ([]byte, error)
+ SetBytes([]byte) (T, error)
+ Add(T, T) T
+ ScalarMult(T, []byte) (T, error)
+ ScalarBaseMult([]byte) (T, error)
+}
+
+// pointFromAffine is used to convert the PublicKey to a nistec Point.
+func (curve *nistCurve[Point]) pointFromAffine(x, y *big.Int) (p Point, err error) {
+ bitSize := curve.curve.Params().BitSize
+ // Reject values that would not get correctly encoded.
+ if x.Sign() < 0 || y.Sign() < 0 {
+ return p, errors.New("negative coordinate")
+ }
+ if x.BitLen() > bitSize || y.BitLen() > bitSize {
+ return p, errors.New("overflowing coordinate")
+ }
+ // Encode the coordinates and let SetBytes reject invalid points.
+ byteLen := (bitSize + 7) / 8
+ buf := make([]byte, 1+2*byteLen)
+ buf[0] = 4 // uncompressed point
+ x.FillBytes(buf[1 : 1+byteLen])
+ y.FillBytes(buf[1+byteLen : 1+2*byteLen])
+ return curve.newPoint().SetBytes(buf)
+}
+
+// pointToAffine is used to convert a nistec Point to a PublicKey.
+func (curve *nistCurve[Point]) pointToAffine(p Point) (x, y *big.Int, err error) {
+ out := p.Bytes()
+ if len(out) == 1 && out[0] == 0 {
+ // This is the encoding of the point at infinity.
+ return nil, nil, errors.New("ecdsa: public key point is the infinity")
+ }
+ byteLen := (curve.curve.Params().BitSize + 7) / 8
+ x = new(big.Int).SetBytes(out[1 : 1+byteLen])
+ y = new(big.Int).SetBytes(out[1+byteLen:])
+ return x, y, nil
+}
+
+var p224Once sync.Once
+var _p224 *nistCurve[*nistec.P224Point]
+
+func p224() *nistCurve[*nistec.P224Point] {
+ p224Once.Do(func() {
+ _p224 = &nistCurve[*nistec.P224Point]{
+ newPoint: func() *nistec.P224Point { return nistec.NewP224Point() },
+ }
+ precomputeParams(_p224, elliptic.P224())
+ })
+ return _p224
+}
+
+var p256Once sync.Once
+var _p256 *nistCurve[*nistec.P256Point]
+
+func p256() *nistCurve[*nistec.P256Point] {
+ p256Once.Do(func() {
+ _p256 = &nistCurve[*nistec.P256Point]{
+ newPoint: func() *nistec.P256Point { return nistec.NewP256Point() },
+ }
+ precomputeParams(_p256, elliptic.P256())
+ })
+ return _p256
+}
+
+var p384Once sync.Once
+var _p384 *nistCurve[*nistec.P384Point]
+
+func p384() *nistCurve[*nistec.P384Point] {
+ p384Once.Do(func() {
+ _p384 = &nistCurve[*nistec.P384Point]{
+ newPoint: func() *nistec.P384Point { return nistec.NewP384Point() },
+ }
+ precomputeParams(_p384, elliptic.P384())
+ })
+ return _p384
+}
+
+var p521Once sync.Once
+var _p521 *nistCurve[*nistec.P521Point]
+
+func p521() *nistCurve[*nistec.P521Point] {
+ p521Once.Do(func() {
+ _p521 = &nistCurve[*nistec.P521Point]{
+ newPoint: func() *nistec.P521Point { return nistec.NewP521Point() },
+ }
+ precomputeParams(_p521, elliptic.P521())
+ })
+ return _p521
+}
+
+func precomputeParams[Point nistPoint[Point]](c *nistCurve[Point], curve elliptic.Curve) {
+ params := curve.Params()
+ c.curve = curve
+ c.N = bigmod.NewModulusFromBig(params.N)
+ c.nMinus2 = new(big.Int).Sub(params.N, big.NewInt(2)).Bytes()
+}
diff --git a/src/crypto/ecdsa/ecdsa_legacy.go b/src/crypto/ecdsa/ecdsa_legacy.go
new file mode 100644
index 0000000..12a40e4
--- /dev/null
+++ b/src/crypto/ecdsa/ecdsa_legacy.go
@@ -0,0 +1,188 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ecdsa
+
+import (
+ "crypto/elliptic"
+ "errors"
+ "io"
+ "math/big"
+
+ "golang.org/x/crypto/cryptobyte"
+ "golang.org/x/crypto/cryptobyte/asn1"
+)
+
+// This file contains a math/big implementation of ECDSA that is only used for
+// deprecated custom curves.
+
+func generateLegacy(c elliptic.Curve, rand io.Reader) (*PrivateKey, error) {
+ k, err := randFieldElement(c, rand)
+ if err != nil {
+ return nil, err
+ }
+
+ priv := new(PrivateKey)
+ priv.PublicKey.Curve = c
+ priv.D = k
+ priv.PublicKey.X, priv.PublicKey.Y = c.ScalarBaseMult(k.Bytes())
+ return priv, nil
+}
+
+// hashToInt converts a hash value to an integer. Per FIPS 186-4, Section 6.4,
+// we use the left-most bits of the hash to match the bit-length of the order of
+// the curve. This also performs Step 5 of SEC 1, Version 2.0, Section 4.1.3.
+func hashToInt(hash []byte, c elliptic.Curve) *big.Int {
+ orderBits := c.Params().N.BitLen()
+ orderBytes := (orderBits + 7) / 8
+ if len(hash) > orderBytes {
+ hash = hash[:orderBytes]
+ }
+
+ ret := new(big.Int).SetBytes(hash)
+ excess := len(hash)*8 - orderBits
+ if excess > 0 {
+ ret.Rsh(ret, uint(excess))
+ }
+ return ret
+}
+
+var errZeroParam = errors.New("zero parameter")
+
+// Sign signs a hash (which should be the result of hashing a larger message)
+// using the private key, priv. If the hash is longer than the bit-length of the
+// private key's curve order, the hash will be truncated to that length. It
+// returns the signature as a pair of integers. Most applications should use
+// SignASN1 instead of dealing directly with r, s.
+func Sign(rand io.Reader, priv *PrivateKey, hash []byte) (r, s *big.Int, err error) {
+ sig, err := SignASN1(rand, priv, hash)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ r, s = new(big.Int), new(big.Int)
+ var inner cryptobyte.String
+ input := cryptobyte.String(sig)
+ if !input.ReadASN1(&inner, asn1.SEQUENCE) ||
+ !input.Empty() ||
+ !inner.ReadASN1Integer(r) ||
+ !inner.ReadASN1Integer(s) ||
+ !inner.Empty() {
+ return nil, nil, errors.New("invalid ASN.1 from SignASN1")
+ }
+ return r, s, nil
+}
+
+func signLegacy(priv *PrivateKey, csprng io.Reader, hash []byte) (sig []byte, err error) {
+ c := priv.Curve
+
+ // SEC 1, Version 2.0, Section 4.1.3
+ N := c.Params().N
+ if N.Sign() == 0 {
+ return nil, errZeroParam
+ }
+ var k, kInv, r, s *big.Int
+ for {
+ for {
+ k, err = randFieldElement(c, csprng)
+ if err != nil {
+ return nil, err
+ }
+
+ kInv = new(big.Int).ModInverse(k, N)
+
+ r, _ = c.ScalarBaseMult(k.Bytes())
+ r.Mod(r, N)
+ if r.Sign() != 0 {
+ break
+ }
+ }
+
+ e := hashToInt(hash, c)
+ s = new(big.Int).Mul(priv.D, r)
+ s.Add(s, e)
+ s.Mul(s, kInv)
+ s.Mod(s, N) // N != 0
+ if s.Sign() != 0 {
+ break
+ }
+ }
+
+ return encodeSignature(r.Bytes(), s.Bytes())
+}
+
+// Verify verifies the signature in r, s of hash using the public key, pub. Its
+// return value records whether the signature is valid. Most applications should
+// use VerifyASN1 instead of dealing directly with r, s.
+func Verify(pub *PublicKey, hash []byte, r, s *big.Int) bool {
+ if r.Sign() <= 0 || s.Sign() <= 0 {
+ return false
+ }
+ sig, err := encodeSignature(r.Bytes(), s.Bytes())
+ if err != nil {
+ return false
+ }
+ return VerifyASN1(pub, hash, sig)
+}
+
+func verifyLegacy(pub *PublicKey, hash []byte, sig []byte) bool {
+ rBytes, sBytes, err := parseSignature(sig)
+ if err != nil {
+ return false
+ }
+ r, s := new(big.Int).SetBytes(rBytes), new(big.Int).SetBytes(sBytes)
+
+ c := pub.Curve
+ N := c.Params().N
+
+ if r.Sign() <= 0 || s.Sign() <= 0 {
+ return false
+ }
+ if r.Cmp(N) >= 0 || s.Cmp(N) >= 0 {
+ return false
+ }
+
+ // SEC 1, Version 2.0, Section 4.1.4
+ e := hashToInt(hash, c)
+ w := new(big.Int).ModInverse(s, N)
+
+ u1 := e.Mul(e, w)
+ u1.Mod(u1, N)
+ u2 := w.Mul(r, w)
+ u2.Mod(u2, N)
+
+ x1, y1 := c.ScalarBaseMult(u1.Bytes())
+ x2, y2 := c.ScalarMult(pub.X, pub.Y, u2.Bytes())
+ x, y := c.Add(x1, y1, x2, y2)
+
+ if x.Sign() == 0 && y.Sign() == 0 {
+ return false
+ }
+ x.Mod(x, N)
+ return x.Cmp(r) == 0
+}
+
+var one = new(big.Int).SetInt64(1)
+
+// randFieldElement returns a random element of the order of the given
+// curve using the procedure given in FIPS 186-4, Appendix B.5.2.
+func randFieldElement(c elliptic.Curve, rand io.Reader) (k *big.Int, err error) {
+ // See randomPoint for notes on the algorithm. This has to match, or s390x
+ // signatures will come out different from other architectures, which will
+ // break TLS recorded tests.
+ for {
+ N := c.Params().N
+ b := make([]byte, (N.BitLen()+7)/8)
+ if _, err = io.ReadFull(rand, b); err != nil {
+ return
+ }
+ if excess := len(b)*8 - N.BitLen(); excess > 0 {
+ b[0] >>= excess
+ }
+ k = new(big.Int).SetBytes(b)
+ if k.Sign() != 0 && k.Cmp(N) < 0 {
+ return
+ }
+ }
+}
diff --git a/src/crypto/ecdsa/ecdsa_noasm.go b/src/crypto/ecdsa/ecdsa_noasm.go
new file mode 100644
index 0000000..a72aa4b
--- /dev/null
+++ b/src/crypto/ecdsa/ecdsa_noasm.go
@@ -0,0 +1,17 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !s390x
+
+package ecdsa
+
+import "io"
+
+func verifyAsm(pub *PublicKey, hash []byte, sig []byte) error {
+ return errNoAsm
+}
+
+func signAsm(priv *PrivateKey, csprng io.Reader, hash []byte) (sig []byte, err error) {
+ return nil, errNoAsm
+}
diff --git a/src/crypto/ecdsa/ecdsa_s390x.go b/src/crypto/ecdsa/ecdsa_s390x.go
new file mode 100644
index 0000000..49f645a
--- /dev/null
+++ b/src/crypto/ecdsa/ecdsa_s390x.go
@@ -0,0 +1,177 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ecdsa
+
+import (
+ "crypto/elliptic"
+ "errors"
+ "internal/cpu"
+ "io"
+ "math/big"
+)
+
+// kdsa invokes the "compute digital signature authentication"
+// instruction with the given function code and 4096 byte
+// parameter block.
+//
+// The return value corresponds to the condition code set by the
+// instruction. Interrupted invocations are handled by the
+// function.
+//
+//go:noescape
+func kdsa(fc uint64, params *[4096]byte) (errn uint64)
+
+// testingDisableKDSA forces the generic fallback path. It must only be set in tests.
+var testingDisableKDSA bool
+
+// canUseKDSA checks if KDSA instruction is available, and if it is, it checks
+// the name of the curve to see if it matches the curves supported(P-256, P-384, P-521).
+// Then, based on the curve name, a function code and a block size will be assigned.
+// If KDSA instruction is not available or if the curve is not supported, canUseKDSA
+// will set ok to false.
+func canUseKDSA(c elliptic.Curve) (functionCode uint64, blockSize int, ok bool) {
+ if testingDisableKDSA {
+ return 0, 0, false
+ }
+ if !cpu.S390X.HasECDSA {
+ return 0, 0, false
+ }
+ switch c.Params().Name {
+ case "P-256":
+ return 1, 32, true
+ case "P-384":
+ return 2, 48, true
+ case "P-521":
+ return 3, 80, true
+ }
+ return 0, 0, false // A mismatch
+}
+
+func hashToBytes(dst, hash []byte, c elliptic.Curve) {
+ l := len(dst)
+ if n := c.Params().N.BitLen(); n == l*8 {
+ // allocation free path for curves with a length that is a whole number of bytes
+ if len(hash) >= l {
+ // truncate hash
+ copy(dst, hash[:l])
+ return
+ }
+ // pad hash with leading zeros
+ p := l - len(hash)
+ for i := 0; i < p; i++ {
+ dst[i] = 0
+ }
+ copy(dst[p:], hash)
+ return
+ }
+ // TODO(mundaym): avoid hashToInt call here
+ hashToInt(hash, c).FillBytes(dst)
+}
+
+func signAsm(priv *PrivateKey, csprng io.Reader, hash []byte) (sig []byte, err error) {
+ c := priv.Curve
+ functionCode, blockSize, ok := canUseKDSA(c)
+ if !ok {
+ return nil, errNoAsm
+ }
+ for {
+ var k *big.Int
+ k, err = randFieldElement(c, csprng)
+ if err != nil {
+ return nil, err
+ }
+
+ // The parameter block looks like the following for sign.
+ // +---------------------+
+ // | Signature(R) |
+ // +---------------------+
+ // | Signature(S) |
+ // +---------------------+
+ // | Hashed Message |
+ // +---------------------+
+ // | Private Key |
+ // +---------------------+
+ // | Random Number |
+ // +---------------------+
+ // | |
+ // | ... |
+ // | |
+ // +---------------------+
+ // The common components(signatureR, signatureS, hashedMessage, privateKey and
+ // random number) each takes block size of bytes. The block size is different for
+ // different curves and is set by canUseKDSA function.
+ var params [4096]byte
+
+ // Copy content into the parameter block. In the sign case,
+ // we copy hashed message, private key and random number into
+ // the parameter block.
+ hashToBytes(params[2*blockSize:3*blockSize], hash, c)
+ priv.D.FillBytes(params[3*blockSize : 4*blockSize])
+ k.FillBytes(params[4*blockSize : 5*blockSize])
+ // Convert verify function code into a sign function code by adding 8.
+ // We also need to set the 'deterministic' bit in the function code, by
+ // adding 128, in order to stop the instruction using its own random number
+ // generator in addition to the random number we supply.
+ switch kdsa(functionCode+136, &params) {
+ case 0: // success
+ return encodeSignature(params[:blockSize], params[blockSize:2*blockSize])
+ case 1: // error
+ return nil, errZeroParam
+ case 2: // retry
+ continue
+ }
+ panic("unreachable")
+ }
+}
+
+func verifyAsm(pub *PublicKey, hash []byte, sig []byte) error {
+ c := pub.Curve
+ functionCode, blockSize, ok := canUseKDSA(c)
+ if !ok {
+ return errNoAsm
+ }
+
+ r, s, err := parseSignature(sig)
+ if err != nil {
+ return err
+ }
+ if len(r) > blockSize || len(s) > blockSize {
+ return errors.New("invalid signature")
+ }
+
+ // The parameter block looks like the following for verify:
+ // +---------------------+
+ // | Signature(R) |
+ // +---------------------+
+ // | Signature(S) |
+ // +---------------------+
+ // | Hashed Message |
+ // +---------------------+
+ // | Public Key X |
+ // +---------------------+
+ // | Public Key Y |
+ // +---------------------+
+ // | |
+ // | ... |
+ // | |
+ // +---------------------+
+ // The common components(signatureR, signatureS, hashed message, public key X,
+ // and public key Y) each takes block size of bytes. The block size is different for
+ // different curves and is set by canUseKDSA function.
+ var params [4096]byte
+
+ // Copy content into the parameter block. In the verify case,
+ // we copy signature (r), signature(s), hashed message, public key x component,
+ // and public key y component into the parameter block.
+ copy(params[0*blockSize+blockSize-len(r):], r)
+ copy(params[1*blockSize+blockSize-len(s):], s)
+ hashToBytes(params[2*blockSize:3*blockSize], hash, c)
+ pub.X.FillBytes(params[3*blockSize : 4*blockSize])
+ pub.Y.FillBytes(params[4*blockSize : 5*blockSize])
+ if kdsa(functionCode, &params) != 0 {
+ return errors.New("invalid signature")
+ }
+ return nil
+}
diff --git a/src/crypto/ecdsa/ecdsa_s390x.s b/src/crypto/ecdsa/ecdsa_s390x.s
new file mode 100644
index 0000000..ba5b3bf
--- /dev/null
+++ b/src/crypto/ecdsa/ecdsa_s390x.s
@@ -0,0 +1,28 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// func kdsa(fc uint64, params *[4096]byte) (errn uint64)
+TEXT ·kdsa(SB), NOSPLIT|NOFRAME, $0-24
+ MOVD fc+0(FP), R0 // function code
+ MOVD params+8(FP), R1 // address parameter block
+
+loop:
+ WORD $0xB93A0008 // compute digital signature authentication
+ BVS loop // branch back if interrupted
+ BGT retry // signing unsuccessful, but retry with new CSPRN
+ BLT error // condition code of 1 indicates a failure
+
+success:
+ MOVD $0, errn+16(FP) // return 0 - sign/verify was successful
+ RET
+
+error:
+ MOVD $1, errn+16(FP) // return 1 - sign/verify failed
+ RET
+
+retry:
+ MOVD $2, errn+16(FP) // return 2 - sign/verify was unsuccessful -- if sign, retry with new RN
+ RET
diff --git a/src/crypto/ecdsa/ecdsa_s390x_test.go b/src/crypto/ecdsa/ecdsa_s390x_test.go
new file mode 100644
index 0000000..fd1dc7c
--- /dev/null
+++ b/src/crypto/ecdsa/ecdsa_s390x_test.go
@@ -0,0 +1,32 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build s390x
+
+package ecdsa
+
+import (
+ "crypto/elliptic"
+ "testing"
+)
+
+func TestNoAsm(t *testing.T) {
+ testingDisableKDSA = true
+ defer func() { testingDisableKDSA = false }()
+
+ curves := [...]elliptic.Curve{
+ elliptic.P256(),
+ elliptic.P384(),
+ elliptic.P521(),
+ }
+
+ for _, curve := range curves {
+ name := curve.Params().Name
+ t.Run(name, func(t *testing.T) { testKeyGeneration(t, curve) })
+ t.Run(name, func(t *testing.T) { testSignAndVerify(t, curve) })
+ t.Run(name, func(t *testing.T) { testNonceSafety(t, curve) })
+ t.Run(name, func(t *testing.T) { testINDCCA(t, curve) })
+ t.Run(name, func(t *testing.T) { testNegativeInputs(t, curve) })
+ }
+}
diff --git a/src/crypto/ecdsa/ecdsa_test.go b/src/crypto/ecdsa/ecdsa_test.go
new file mode 100644
index 0000000..08a0903
--- /dev/null
+++ b/src/crypto/ecdsa/ecdsa_test.go
@@ -0,0 +1,589 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ecdsa
+
+import (
+ "bufio"
+ "bytes"
+ "compress/bzip2"
+ "crypto/elliptic"
+ "crypto/internal/bigmod"
+ "crypto/rand"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/sha512"
+ "encoding/hex"
+ "hash"
+ "io"
+ "math/big"
+ "os"
+ "strings"
+ "testing"
+)
+
+func testAllCurves(t *testing.T, f func(*testing.T, elliptic.Curve)) {
+ tests := []struct {
+ name string
+ curve elliptic.Curve
+ }{
+ {"P256", elliptic.P256()},
+ {"P224", elliptic.P224()},
+ {"P384", elliptic.P384()},
+ {"P521", elliptic.P521()},
+ {"P256/Generic", genericParamsForCurve(elliptic.P256())},
+ }
+ if testing.Short() {
+ tests = tests[:1]
+ }
+ for _, test := range tests {
+ curve := test.curve
+ t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
+ f(t, curve)
+ })
+ }
+}
+
+// genericParamsForCurve returns the dereferenced CurveParams for
+// the specified curve. This is used to avoid the logic for
+// upgrading a curve to its specific implementation, forcing
+// usage of the generic implementation.
+func genericParamsForCurve(c elliptic.Curve) *elliptic.CurveParams {
+ d := *(c.Params())
+ return &d
+}
+
+func TestKeyGeneration(t *testing.T) {
+ testAllCurves(t, testKeyGeneration)
+}
+
+func testKeyGeneration(t *testing.T, c elliptic.Curve) {
+ priv, err := GenerateKey(c, rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !c.IsOnCurve(priv.PublicKey.X, priv.PublicKey.Y) {
+ t.Errorf("public key invalid: %s", err)
+ }
+}
+
+func TestSignAndVerify(t *testing.T) {
+ testAllCurves(t, testSignAndVerify)
+}
+
+func testSignAndVerify(t *testing.T, c elliptic.Curve) {
+ priv, _ := GenerateKey(c, rand.Reader)
+
+ hashed := []byte("testing")
+ r, s, err := Sign(rand.Reader, priv, hashed)
+ if err != nil {
+ t.Errorf("error signing: %s", err)
+ return
+ }
+
+ if !Verify(&priv.PublicKey, hashed, r, s) {
+ t.Errorf("Verify failed")
+ }
+
+ hashed[0] ^= 0xff
+ if Verify(&priv.PublicKey, hashed, r, s) {
+ t.Errorf("Verify always works!")
+ }
+}
+
+func TestSignAndVerifyASN1(t *testing.T) {
+ testAllCurves(t, testSignAndVerifyASN1)
+}
+
+func testSignAndVerifyASN1(t *testing.T, c elliptic.Curve) {
+ priv, _ := GenerateKey(c, rand.Reader)
+
+ hashed := []byte("testing")
+ sig, err := SignASN1(rand.Reader, priv, hashed)
+ if err != nil {
+ t.Errorf("error signing: %s", err)
+ return
+ }
+
+ if !VerifyASN1(&priv.PublicKey, hashed, sig) {
+ t.Errorf("VerifyASN1 failed")
+ }
+
+ hashed[0] ^= 0xff
+ if VerifyASN1(&priv.PublicKey, hashed, sig) {
+ t.Errorf("VerifyASN1 always works!")
+ }
+}
+
+func TestNonceSafety(t *testing.T) {
+ testAllCurves(t, testNonceSafety)
+}
+
+func testNonceSafety(t *testing.T, c elliptic.Curve) {
+ priv, _ := GenerateKey(c, rand.Reader)
+
+ hashed := []byte("testing")
+ r0, s0, err := Sign(zeroReader, priv, hashed)
+ if err != nil {
+ t.Errorf("error signing: %s", err)
+ return
+ }
+
+ hashed = []byte("testing...")
+ r1, s1, err := Sign(zeroReader, priv, hashed)
+ if err != nil {
+ t.Errorf("error signing: %s", err)
+ return
+ }
+
+ if s0.Cmp(s1) == 0 {
+ // This should never happen.
+ t.Errorf("the signatures on two different messages were the same")
+ }
+
+ if r0.Cmp(r1) == 0 {
+ t.Errorf("the nonce used for two different messages was the same")
+ }
+}
+
+func TestINDCCA(t *testing.T) {
+ testAllCurves(t, testINDCCA)
+}
+
+func testINDCCA(t *testing.T, c elliptic.Curve) {
+ priv, _ := GenerateKey(c, rand.Reader)
+
+ hashed := []byte("testing")
+ r0, s0, err := Sign(rand.Reader, priv, hashed)
+ if err != nil {
+ t.Errorf("error signing: %s", err)
+ return
+ }
+
+ r1, s1, err := Sign(rand.Reader, priv, hashed)
+ if err != nil {
+ t.Errorf("error signing: %s", err)
+ return
+ }
+
+ if s0.Cmp(s1) == 0 {
+ t.Errorf("two signatures of the same message produced the same result")
+ }
+
+ if r0.Cmp(r1) == 0 {
+ t.Errorf("two signatures of the same message produced the same nonce")
+ }
+}
+
+func fromHex(s string) *big.Int {
+ r, ok := new(big.Int).SetString(s, 16)
+ if !ok {
+ panic("bad hex")
+ }
+ return r
+}
+
+func TestVectors(t *testing.T) {
+ // This test runs the full set of NIST test vectors from
+ // https://csrc.nist.gov/groups/STM/cavp/documents/dss/186-3ecdsatestvectors.zip
+ //
+ // The SigVer.rsp file has been edited to remove test vectors for
+ // unsupported algorithms and has been compressed.
+
+ if testing.Short() {
+ return
+ }
+
+ f, err := os.Open("testdata/SigVer.rsp.bz2")
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ buf := bufio.NewReader(bzip2.NewReader(f))
+
+ lineNo := 1
+ var h hash.Hash
+ var msg []byte
+ var hashed []byte
+ var r, s *big.Int
+ pub := new(PublicKey)
+
+ for {
+ line, err := buf.ReadString('\n')
+ if len(line) == 0 {
+ if err == io.EOF {
+ break
+ }
+ t.Fatalf("error reading from input: %s", err)
+ }
+ lineNo++
+ // Need to remove \r\n from the end of the line.
+ if !strings.HasSuffix(line, "\r\n") {
+ t.Fatalf("bad line ending (expected \\r\\n) on line %d", lineNo)
+ }
+ line = line[:len(line)-2]
+
+ if len(line) == 0 || line[0] == '#' {
+ continue
+ }
+
+ if line[0] == '[' {
+ line = line[1 : len(line)-1]
+ curve, hash, _ := strings.Cut(line, ",")
+
+ switch curve {
+ case "P-224":
+ pub.Curve = elliptic.P224()
+ case "P-256":
+ pub.Curve = elliptic.P256()
+ case "P-384":
+ pub.Curve = elliptic.P384()
+ case "P-521":
+ pub.Curve = elliptic.P521()
+ default:
+ pub.Curve = nil
+ }
+
+ switch hash {
+ case "SHA-1":
+ h = sha1.New()
+ case "SHA-224":
+ h = sha256.New224()
+ case "SHA-256":
+ h = sha256.New()
+ case "SHA-384":
+ h = sha512.New384()
+ case "SHA-512":
+ h = sha512.New()
+ default:
+ h = nil
+ }
+
+ continue
+ }
+
+ if h == nil || pub.Curve == nil {
+ continue
+ }
+
+ switch {
+ case strings.HasPrefix(line, "Msg = "):
+ if msg, err = hex.DecodeString(line[6:]); err != nil {
+ t.Fatalf("failed to decode message on line %d: %s", lineNo, err)
+ }
+ case strings.HasPrefix(line, "Qx = "):
+ pub.X = fromHex(line[5:])
+ case strings.HasPrefix(line, "Qy = "):
+ pub.Y = fromHex(line[5:])
+ case strings.HasPrefix(line, "R = "):
+ r = fromHex(line[4:])
+ case strings.HasPrefix(line, "S = "):
+ s = fromHex(line[4:])
+ case strings.HasPrefix(line, "Result = "):
+ expected := line[9] == 'P'
+ h.Reset()
+ h.Write(msg)
+ hashed := h.Sum(hashed[:0])
+ if Verify(pub, hashed, r, s) != expected {
+ t.Fatalf("incorrect result on line %d", lineNo)
+ }
+ default:
+ t.Fatalf("unknown variable on line %d: %s", lineNo, line)
+ }
+ }
+}
+
+func TestNegativeInputs(t *testing.T) {
+ testAllCurves(t, testNegativeInputs)
+}
+
+func testNegativeInputs(t *testing.T, curve elliptic.Curve) {
+ key, err := GenerateKey(curve, rand.Reader)
+ if err != nil {
+ t.Errorf("failed to generate key")
+ }
+
+ var hash [32]byte
+ r := new(big.Int).SetInt64(1)
+ r.Lsh(r, 550 /* larger than any supported curve */)
+ r.Neg(r)
+
+ if Verify(&key.PublicKey, hash[:], r, r) {
+ t.Errorf("bogus signature accepted")
+ }
+}
+
+func TestZeroHashSignature(t *testing.T) {
+ testAllCurves(t, testZeroHashSignature)
+}
+
+func testZeroHashSignature(t *testing.T, curve elliptic.Curve) {
+ zeroHash := make([]byte, 64)
+
+ privKey, err := GenerateKey(curve, rand.Reader)
+ if err != nil {
+ panic(err)
+ }
+
+ // Sign a hash consisting of all zeros.
+ r, s, err := Sign(rand.Reader, privKey, zeroHash)
+ if err != nil {
+ panic(err)
+ }
+
+ // Confirm that it can be verified.
+ if !Verify(&privKey.PublicKey, zeroHash, r, s) {
+ t.Errorf("zero hash signature verify failed for %T", curve)
+ }
+}
+
+func TestRandomPoint(t *testing.T) {
+ t.Run("P-224", func(t *testing.T) { testRandomPoint(t, p224()) })
+ t.Run("P-256", func(t *testing.T) { testRandomPoint(t, p256()) })
+ t.Run("P-384", func(t *testing.T) { testRandomPoint(t, p384()) })
+ t.Run("P-521", func(t *testing.T) { testRandomPoint(t, p521()) })
+}
+
+func testRandomPoint[Point nistPoint[Point]](t *testing.T, c *nistCurve[Point]) {
+ t.Cleanup(func() { testingOnlyRejectionSamplingLooped = nil })
+ var loopCount int
+ testingOnlyRejectionSamplingLooped = func() { loopCount++ }
+
+ // A sequence of all ones will generate 2^N-1, which should be rejected.
+ // (Unless, for example, we are masking too many bits.)
+ r := io.MultiReader(bytes.NewReader(bytes.Repeat([]byte{0xff}, 100)), rand.Reader)
+ if k, p, err := randomPoint(c, r); err != nil {
+ t.Fatal(err)
+ } else if k.IsZero() == 1 {
+ t.Error("k is zero")
+ } else if p.Bytes()[0] != 4 {
+ t.Error("p is infinity")
+ }
+ if loopCount == 0 {
+ t.Error("overflow was not rejected")
+ }
+ loopCount = 0
+
+ // A sequence of all zeroes will generate zero, which should be rejected.
+ r = io.MultiReader(bytes.NewReader(bytes.Repeat([]byte{0}, 100)), rand.Reader)
+ if k, p, err := randomPoint(c, r); err != nil {
+ t.Fatal(err)
+ } else if k.IsZero() == 1 {
+ t.Error("k is zero")
+ } else if p.Bytes()[0] != 4 {
+ t.Error("p is infinity")
+ }
+ if loopCount == 0 {
+ t.Error("zero was not rejected")
+ }
+ loopCount = 0
+
+ // P-256 has a 2⁻³² chance or randomly hitting a rejection. For P-224 it's
+ // 2⁻¹¹², for P-384 it's 2⁻¹⁹⁴, and for P-521 it's 2⁻²⁶², so if we hit in
+ // tests, something is horribly wrong. (For example, we are masking the
+ // wrong bits.)
+ if c.curve == elliptic.P256() {
+ return
+ }
+ if k, p, err := randomPoint(c, rand.Reader); err != nil {
+ t.Fatal(err)
+ } else if k.IsZero() == 1 {
+ t.Error("k is zero")
+ } else if p.Bytes()[0] != 4 {
+ t.Error("p is infinity")
+ }
+ if loopCount > 0 {
+ t.Error("unexpected rejection")
+ }
+}
+
+func TestHashToNat(t *testing.T) {
+ t.Run("P-224", func(t *testing.T) { testHashToNat(t, p224()) })
+ t.Run("P-256", func(t *testing.T) { testHashToNat(t, p256()) })
+ t.Run("P-384", func(t *testing.T) { testHashToNat(t, p384()) })
+ t.Run("P-521", func(t *testing.T) { testHashToNat(t, p521()) })
+}
+
+func testHashToNat[Point nistPoint[Point]](t *testing.T, c *nistCurve[Point]) {
+ for l := 0; l < 600; l++ {
+ h := bytes.Repeat([]byte{0xff}, l)
+ hashToNat(c, bigmod.NewNat(), h)
+ }
+}
+
+func TestZeroSignature(t *testing.T) {
+ testAllCurves(t, testZeroSignature)
+}
+
+func testZeroSignature(t *testing.T, curve elliptic.Curve) {
+ privKey, err := GenerateKey(curve, rand.Reader)
+ if err != nil {
+ panic(err)
+ }
+
+ if Verify(&privKey.PublicKey, make([]byte, 64), big.NewInt(0), big.NewInt(0)) {
+ t.Errorf("Verify with r,s=0 succeeded: %T", curve)
+ }
+}
+
+func TestNegtativeSignature(t *testing.T) {
+ testAllCurves(t, testNegativeSignature)
+}
+
+func testNegativeSignature(t *testing.T, curve elliptic.Curve) {
+ zeroHash := make([]byte, 64)
+
+ privKey, err := GenerateKey(curve, rand.Reader)
+ if err != nil {
+ panic(err)
+ }
+ r, s, err := Sign(rand.Reader, privKey, zeroHash)
+ if err != nil {
+ panic(err)
+ }
+
+ r = r.Neg(r)
+ if Verify(&privKey.PublicKey, zeroHash, r, s) {
+ t.Errorf("Verify with r=-r succeeded: %T", curve)
+ }
+}
+
+func TestRPlusNSignature(t *testing.T) {
+ testAllCurves(t, testRPlusNSignature)
+}
+
+func testRPlusNSignature(t *testing.T, curve elliptic.Curve) {
+ zeroHash := make([]byte, 64)
+
+ privKey, err := GenerateKey(curve, rand.Reader)
+ if err != nil {
+ panic(err)
+ }
+ r, s, err := Sign(rand.Reader, privKey, zeroHash)
+ if err != nil {
+ panic(err)
+ }
+
+ r = r.Add(r, curve.Params().N)
+ if Verify(&privKey.PublicKey, zeroHash, r, s) {
+ t.Errorf("Verify with r=r+n succeeded: %T", curve)
+ }
+}
+
+func TestRMinusNSignature(t *testing.T) {
+ testAllCurves(t, testRMinusNSignature)
+}
+
+func testRMinusNSignature(t *testing.T, curve elliptic.Curve) {
+ zeroHash := make([]byte, 64)
+
+ privKey, err := GenerateKey(curve, rand.Reader)
+ if err != nil {
+ panic(err)
+ }
+ r, s, err := Sign(rand.Reader, privKey, zeroHash)
+ if err != nil {
+ panic(err)
+ }
+
+ r = r.Sub(r, curve.Params().N)
+ if Verify(&privKey.PublicKey, zeroHash, r, s) {
+ t.Errorf("Verify with r=r-n succeeded: %T", curve)
+ }
+}
+
+func randomPointForCurve(curve elliptic.Curve, rand io.Reader) error {
+ switch curve.Params() {
+ case elliptic.P224().Params():
+ _, _, err := randomPoint(p224(), rand)
+ return err
+ case elliptic.P256().Params():
+ _, _, err := randomPoint(p256(), rand)
+ return err
+ case elliptic.P384().Params():
+ _, _, err := randomPoint(p384(), rand)
+ return err
+ case elliptic.P521().Params():
+ _, _, err := randomPoint(p521(), rand)
+ return err
+ default:
+ panic("unknown curve")
+ }
+}
+
+func benchmarkAllCurves(b *testing.B, f func(*testing.B, elliptic.Curve)) {
+ tests := []struct {
+ name string
+ curve elliptic.Curve
+ }{
+ {"P256", elliptic.P256()},
+ {"P384", elliptic.P384()},
+ {"P521", elliptic.P521()},
+ }
+ for _, test := range tests {
+ curve := test.curve
+ b.Run(test.name, func(b *testing.B) {
+ f(b, curve)
+ })
+ }
+}
+
+func BenchmarkSign(b *testing.B) {
+ benchmarkAllCurves(b, func(b *testing.B, curve elliptic.Curve) {
+ r := bufio.NewReaderSize(rand.Reader, 1<<15)
+ priv, err := GenerateKey(curve, r)
+ if err != nil {
+ b.Fatal(err)
+ }
+ hashed := []byte("testing")
+
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ sig, err := SignASN1(r, priv, hashed)
+ if err != nil {
+ b.Fatal(err)
+ }
+ // Prevent the compiler from optimizing out the operation.
+ hashed[0] = sig[0]
+ }
+ })
+}
+
+func BenchmarkVerify(b *testing.B) {
+ benchmarkAllCurves(b, func(b *testing.B, curve elliptic.Curve) {
+ r := bufio.NewReaderSize(rand.Reader, 1<<15)
+ priv, err := GenerateKey(curve, r)
+ if err != nil {
+ b.Fatal(err)
+ }
+ hashed := []byte("testing")
+ sig, err := SignASN1(r, priv, hashed)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ if !VerifyASN1(&priv.PublicKey, hashed, sig) {
+ b.Fatal("verify failed")
+ }
+ }
+ })
+}
+
+func BenchmarkGenerateKey(b *testing.B) {
+ benchmarkAllCurves(b, func(b *testing.B, curve elliptic.Curve) {
+ r := bufio.NewReaderSize(rand.Reader, 1<<15)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ if _, err := GenerateKey(curve, r); err != nil {
+ b.Fatal(err)
+ }
+ }
+ })
+}
diff --git a/src/crypto/ecdsa/equal_test.go b/src/crypto/ecdsa/equal_test.go
new file mode 100644
index 0000000..53ac850
--- /dev/null
+++ b/src/crypto/ecdsa/equal_test.go
@@ -0,0 +1,75 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ecdsa_test
+
+import (
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/x509"
+ "testing"
+)
+
+func testEqual(t *testing.T, c elliptic.Curve) {
+ private, _ := ecdsa.GenerateKey(c, rand.Reader)
+ public := &private.PublicKey
+
+ if !public.Equal(public) {
+ t.Errorf("public key is not equal to itself: %v", public)
+ }
+ if !public.Equal(crypto.Signer(private).Public().(*ecdsa.PublicKey)) {
+ t.Errorf("private.Public() is not Equal to public: %q", public)
+ }
+ if !private.Equal(private) {
+ t.Errorf("private key is not equal to itself: %v", private)
+ }
+
+ enc, err := x509.MarshalPKCS8PrivateKey(private)
+ if err != nil {
+ t.Fatal(err)
+ }
+ decoded, err := x509.ParsePKCS8PrivateKey(enc)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !public.Equal(decoded.(crypto.Signer).Public()) {
+ t.Errorf("public key is not equal to itself after decoding: %v", public)
+ }
+ if !private.Equal(decoded) {
+ t.Errorf("private key is not equal to itself after decoding: %v", private)
+ }
+
+ other, _ := ecdsa.GenerateKey(c, rand.Reader)
+ if public.Equal(other.Public()) {
+ t.Errorf("different public keys are Equal")
+ }
+ if private.Equal(other) {
+ t.Errorf("different private keys are Equal")
+ }
+
+ // Ensure that keys with the same coordinates but on different curves
+ // aren't considered Equal.
+ differentCurve := &ecdsa.PublicKey{}
+ *differentCurve = *public // make a copy of the public key
+ if differentCurve.Curve == elliptic.P256() {
+ differentCurve.Curve = elliptic.P224()
+ } else {
+ differentCurve.Curve = elliptic.P256()
+ }
+ if public.Equal(differentCurve) {
+ t.Errorf("public keys with different curves are Equal")
+ }
+}
+
+func TestEqual(t *testing.T) {
+ t.Run("P224", func(t *testing.T) { testEqual(t, elliptic.P224()) })
+ if testing.Short() {
+ return
+ }
+ t.Run("P256", func(t *testing.T) { testEqual(t, elliptic.P256()) })
+ t.Run("P384", func(t *testing.T) { testEqual(t, elliptic.P384()) })
+ t.Run("P521", func(t *testing.T) { testEqual(t, elliptic.P521()) })
+}
diff --git a/src/crypto/ecdsa/example_test.go b/src/crypto/ecdsa/example_test.go
new file mode 100644
index 0000000..652c165
--- /dev/null
+++ b/src/crypto/ecdsa/example_test.go
@@ -0,0 +1,32 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ecdsa_test
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/sha256"
+ "fmt"
+)
+
+func Example() {
+ privateKey, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ panic(err)
+ }
+
+ msg := "hello, world"
+ hash := sha256.Sum256([]byte(msg))
+
+ sig, err := ecdsa.SignASN1(rand.Reader, privateKey, hash[:])
+ if err != nil {
+ panic(err)
+ }
+ fmt.Printf("signature: %x\n", sig)
+
+ valid := ecdsa.VerifyASN1(&privateKey.PublicKey, hash[:], sig)
+ fmt.Println("signature verified:", valid)
+}
diff --git a/src/crypto/ecdsa/notboring.go b/src/crypto/ecdsa/notboring.go
new file mode 100644
index 0000000..039bd82
--- /dev/null
+++ b/src/crypto/ecdsa/notboring.go
@@ -0,0 +1,16 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !boringcrypto
+
+package ecdsa
+
+import "crypto/internal/boring"
+
+func boringPublicKey(*PublicKey) (*boring.PublicKeyECDSA, error) {
+ panic("boringcrypto: not available")
+}
+func boringPrivateKey(*PrivateKey) (*boring.PrivateKeyECDSA, error) {
+ panic("boringcrypto: not available")
+}
diff --git a/src/crypto/ecdsa/testdata/SigVer.rsp.bz2 b/src/crypto/ecdsa/testdata/SigVer.rsp.bz2
new file mode 100644
index 0000000..09fe2b4
--- /dev/null
+++ b/src/crypto/ecdsa/testdata/SigVer.rsp.bz2
Binary files differ
diff --git a/src/crypto/ed25519/ed25519.go b/src/crypto/ed25519/ed25519.go
new file mode 100644
index 0000000..a45d056
--- /dev/null
+++ b/src/crypto/ed25519/ed25519.go
@@ -0,0 +1,337 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package ed25519 implements the Ed25519 signature algorithm. See
+// https://ed25519.cr.yp.to/.
+//
+// These functions are also compatible with the “Ed25519” function defined in
+// RFC 8032. However, unlike RFC 8032's formulation, this package's private key
+// representation includes a public key suffix to make multiple signing
+// operations with the same key more efficient. This package refers to the RFC
+// 8032 private key as the “seed”.
+package ed25519
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/internal/edwards25519"
+ cryptorand "crypto/rand"
+ "crypto/sha512"
+ "errors"
+ "io"
+ "strconv"
+)
+
+const (
+ // PublicKeySize is the size, in bytes, of public keys as used in this package.
+ PublicKeySize = 32
+ // PrivateKeySize is the size, in bytes, of private keys as used in this package.
+ PrivateKeySize = 64
+ // SignatureSize is the size, in bytes, of signatures generated and verified by this package.
+ SignatureSize = 64
+ // SeedSize is the size, in bytes, of private key seeds. These are the private key representations used by RFC 8032.
+ SeedSize = 32
+)
+
+// PublicKey is the type of Ed25519 public keys.
+type PublicKey []byte
+
+// Any methods implemented on PublicKey might need to also be implemented on
+// PrivateKey, as the latter embeds the former and will expose its methods.
+
+// Equal reports whether pub and x have the same value.
+func (pub PublicKey) Equal(x crypto.PublicKey) bool {
+ xx, ok := x.(PublicKey)
+ if !ok {
+ return false
+ }
+ return bytes.Equal(pub, xx)
+}
+
+// PrivateKey is the type of Ed25519 private keys. It implements [crypto.Signer].
+type PrivateKey []byte
+
+// Public returns the [PublicKey] corresponding to priv.
+func (priv PrivateKey) Public() crypto.PublicKey {
+ publicKey := make([]byte, PublicKeySize)
+ copy(publicKey, priv[32:])
+ return PublicKey(publicKey)
+}
+
+// Equal reports whether priv and x have the same value.
+func (priv PrivateKey) Equal(x crypto.PrivateKey) bool {
+ xx, ok := x.(PrivateKey)
+ if !ok {
+ return false
+ }
+ return bytes.Equal(priv, xx)
+}
+
+// Seed returns the private key seed corresponding to priv. It is provided for
+// interoperability with RFC 8032. RFC 8032's private keys correspond to seeds
+// in this package.
+func (priv PrivateKey) Seed() []byte {
+ return bytes.Clone(priv[:SeedSize])
+}
+
+// Sign signs the given message with priv. rand is ignored.
+//
+// If opts.HashFunc() is [crypto.SHA512], the pre-hashed variant Ed25519ph is used
+// and message is expected to be a SHA-512 hash, otherwise opts.HashFunc() must
+// be [crypto.Hash](0) and the message must not be hashed, as Ed25519 performs two
+// passes over messages to be signed.
+//
+// A value of type [Options] can be used as opts, or crypto.Hash(0) or
+// crypto.SHA512 directly to select plain Ed25519 or Ed25519ph, respectively.
+func (priv PrivateKey) Sign(rand io.Reader, message []byte, opts crypto.SignerOpts) (signature []byte, err error) {
+ hash := opts.HashFunc()
+ context := ""
+ if opts, ok := opts.(*Options); ok {
+ context = opts.Context
+ }
+ if l := len(context); l > 255 {
+ return nil, errors.New("ed25519: bad Ed25519ph context length: " + strconv.Itoa(l))
+ }
+ switch {
+ case hash == crypto.SHA512: // Ed25519ph
+ if l := len(message); l != sha512.Size {
+ return nil, errors.New("ed25519: bad Ed25519ph message hash length: " + strconv.Itoa(l))
+ }
+ signature := make([]byte, SignatureSize)
+ sign(signature, priv, message, domPrefixPh, context)
+ return signature, nil
+ case hash == crypto.Hash(0) && context != "": // Ed25519ctx
+ signature := make([]byte, SignatureSize)
+ sign(signature, priv, message, domPrefixCtx, context)
+ return signature, nil
+ case hash == crypto.Hash(0): // Ed25519
+ return Sign(priv, message), nil
+ default:
+ return nil, errors.New("ed25519: expected opts.HashFunc() zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)")
+ }
+}
+
+// Options can be used with [PrivateKey.Sign] or [VerifyWithOptions]
+// to select Ed25519 variants.
+type Options struct {
+ // Hash can be zero for regular Ed25519, or crypto.SHA512 for Ed25519ph.
+ Hash crypto.Hash
+
+ // Context, if not empty, selects Ed25519ctx or provides the context string
+ // for Ed25519ph. It can be at most 255 bytes in length.
+ Context string
+}
+
+// HashFunc returns o.Hash.
+func (o *Options) HashFunc() crypto.Hash { return o.Hash }
+
+// GenerateKey generates a public/private key pair using entropy from rand.
+// If rand is nil, [crypto/rand.Reader] will be used.
+func GenerateKey(rand io.Reader) (PublicKey, PrivateKey, error) {
+ if rand == nil {
+ rand = cryptorand.Reader
+ }
+
+ seed := make([]byte, SeedSize)
+ if _, err := io.ReadFull(rand, seed); err != nil {
+ return nil, nil, err
+ }
+
+ privateKey := NewKeyFromSeed(seed)
+ publicKey := make([]byte, PublicKeySize)
+ copy(publicKey, privateKey[32:])
+
+ return publicKey, privateKey, nil
+}
+
+// NewKeyFromSeed calculates a private key from a seed. It will panic if
+// len(seed) is not [SeedSize]. This function is provided for interoperability
+// with RFC 8032. RFC 8032's private keys correspond to seeds in this
+// package.
+func NewKeyFromSeed(seed []byte) PrivateKey {
+ // Outline the function body so that the returned key can be stack-allocated.
+ privateKey := make([]byte, PrivateKeySize)
+ newKeyFromSeed(privateKey, seed)
+ return privateKey
+}
+
+func newKeyFromSeed(privateKey, seed []byte) {
+ if l := len(seed); l != SeedSize {
+ panic("ed25519: bad seed length: " + strconv.Itoa(l))
+ }
+
+ h := sha512.Sum512(seed)
+ s, err := edwards25519.NewScalar().SetBytesWithClamping(h[:32])
+ if err != nil {
+ panic("ed25519: internal error: setting scalar failed")
+ }
+ A := (&edwards25519.Point{}).ScalarBaseMult(s)
+
+ publicKey := A.Bytes()
+
+ copy(privateKey, seed)
+ copy(privateKey[32:], publicKey)
+}
+
+// Sign signs the message with privateKey and returns a signature. It will
+// panic if len(privateKey) is not [PrivateKeySize].
+func Sign(privateKey PrivateKey, message []byte) []byte {
+ // Outline the function body so that the returned signature can be
+ // stack-allocated.
+ signature := make([]byte, SignatureSize)
+ sign(signature, privateKey, message, domPrefixPure, "")
+ return signature
+}
+
+// Domain separation prefixes used to disambiguate Ed25519/Ed25519ph/Ed25519ctx.
+// See RFC 8032, Section 2 and Section 5.1.
+const (
+ // domPrefixPure is empty for pure Ed25519.
+ domPrefixPure = ""
+ // domPrefixPh is dom2(phflag=1) for Ed25519ph. It must be followed by the
+ // uint8-length prefixed context.
+ domPrefixPh = "SigEd25519 no Ed25519 collisions\x01"
+ // domPrefixCtx is dom2(phflag=0) for Ed25519ctx. It must be followed by the
+ // uint8-length prefixed context.
+ domPrefixCtx = "SigEd25519 no Ed25519 collisions\x00"
+)
+
+func sign(signature, privateKey, message []byte, domPrefix, context string) {
+ if l := len(privateKey); l != PrivateKeySize {
+ panic("ed25519: bad private key length: " + strconv.Itoa(l))
+ }
+ seed, publicKey := privateKey[:SeedSize], privateKey[SeedSize:]
+
+ h := sha512.Sum512(seed)
+ s, err := edwards25519.NewScalar().SetBytesWithClamping(h[:32])
+ if err != nil {
+ panic("ed25519: internal error: setting scalar failed")
+ }
+ prefix := h[32:]
+
+ mh := sha512.New()
+ if domPrefix != domPrefixPure {
+ mh.Write([]byte(domPrefix))
+ mh.Write([]byte{byte(len(context))})
+ mh.Write([]byte(context))
+ }
+ mh.Write(prefix)
+ mh.Write(message)
+ messageDigest := make([]byte, 0, sha512.Size)
+ messageDigest = mh.Sum(messageDigest)
+ r, err := edwards25519.NewScalar().SetUniformBytes(messageDigest)
+ if err != nil {
+ panic("ed25519: internal error: setting scalar failed")
+ }
+
+ R := (&edwards25519.Point{}).ScalarBaseMult(r)
+
+ kh := sha512.New()
+ if domPrefix != domPrefixPure {
+ kh.Write([]byte(domPrefix))
+ kh.Write([]byte{byte(len(context))})
+ kh.Write([]byte(context))
+ }
+ kh.Write(R.Bytes())
+ kh.Write(publicKey)
+ kh.Write(message)
+ hramDigest := make([]byte, 0, sha512.Size)
+ hramDigest = kh.Sum(hramDigest)
+ k, err := edwards25519.NewScalar().SetUniformBytes(hramDigest)
+ if err != nil {
+ panic("ed25519: internal error: setting scalar failed")
+ }
+
+ S := edwards25519.NewScalar().MultiplyAdd(k, s, r)
+
+ copy(signature[:32], R.Bytes())
+ copy(signature[32:], S.Bytes())
+}
+
+// Verify reports whether sig is a valid signature of message by publicKey. It
+// will panic if len(publicKey) is not [PublicKeySize].
+func Verify(publicKey PublicKey, message, sig []byte) bool {
+ return verify(publicKey, message, sig, domPrefixPure, "")
+}
+
+// VerifyWithOptions reports whether sig is a valid signature of message by
+// publicKey. A valid signature is indicated by returning a nil error. It will
+// panic if len(publicKey) is not [PublicKeySize].
+//
+// If opts.Hash is [crypto.SHA512], the pre-hashed variant Ed25519ph is used and
+// message is expected to be a SHA-512 hash, otherwise opts.Hash must be
+// [crypto.Hash](0) and the message must not be hashed, as Ed25519 performs two
+// passes over messages to be signed.
+func VerifyWithOptions(publicKey PublicKey, message, sig []byte, opts *Options) error {
+ switch {
+ case opts.Hash == crypto.SHA512: // Ed25519ph
+ if l := len(message); l != sha512.Size {
+ return errors.New("ed25519: bad Ed25519ph message hash length: " + strconv.Itoa(l))
+ }
+ if l := len(opts.Context); l > 255 {
+ return errors.New("ed25519: bad Ed25519ph context length: " + strconv.Itoa(l))
+ }
+ if !verify(publicKey, message, sig, domPrefixPh, opts.Context) {
+ return errors.New("ed25519: invalid signature")
+ }
+ return nil
+ case opts.Hash == crypto.Hash(0) && opts.Context != "": // Ed25519ctx
+ if l := len(opts.Context); l > 255 {
+ return errors.New("ed25519: bad Ed25519ctx context length: " + strconv.Itoa(l))
+ }
+ if !verify(publicKey, message, sig, domPrefixCtx, opts.Context) {
+ return errors.New("ed25519: invalid signature")
+ }
+ return nil
+ case opts.Hash == crypto.Hash(0): // Ed25519
+ if !verify(publicKey, message, sig, domPrefixPure, "") {
+ return errors.New("ed25519: invalid signature")
+ }
+ return nil
+ default:
+ return errors.New("ed25519: expected opts.Hash zero (unhashed message, for standard Ed25519) or SHA-512 (for Ed25519ph)")
+ }
+}
+
+func verify(publicKey PublicKey, message, sig []byte, domPrefix, context string) bool {
+ if l := len(publicKey); l != PublicKeySize {
+ panic("ed25519: bad public key length: " + strconv.Itoa(l))
+ }
+
+ if len(sig) != SignatureSize || sig[63]&224 != 0 {
+ return false
+ }
+
+ A, err := (&edwards25519.Point{}).SetBytes(publicKey)
+ if err != nil {
+ return false
+ }
+
+ kh := sha512.New()
+ if domPrefix != domPrefixPure {
+ kh.Write([]byte(domPrefix))
+ kh.Write([]byte{byte(len(context))})
+ kh.Write([]byte(context))
+ }
+ kh.Write(sig[:32])
+ kh.Write(publicKey)
+ kh.Write(message)
+ hramDigest := make([]byte, 0, sha512.Size)
+ hramDigest = kh.Sum(hramDigest)
+ k, err := edwards25519.NewScalar().SetUniformBytes(hramDigest)
+ if err != nil {
+ panic("ed25519: internal error: setting scalar failed")
+ }
+
+ S, err := edwards25519.NewScalar().SetCanonicalBytes(sig[32:])
+ if err != nil {
+ return false
+ }
+
+ // [S]B = R + [k]A --> [k](-A) + [S]B = R
+ minusA := (&edwards25519.Point{}).Negate(A)
+ R := (&edwards25519.Point{}).VarTimeDoubleScalarBaseMult(k, minusA, S)
+
+ return bytes.Equal(sig[:32], R.Bytes())
+}
diff --git a/src/crypto/ed25519/ed25519_test.go b/src/crypto/ed25519/ed25519_test.go
new file mode 100644
index 0000000..47c8698
--- /dev/null
+++ b/src/crypto/ed25519/ed25519_test.go
@@ -0,0 +1,384 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ed25519
+
+import (
+ "bufio"
+ "bytes"
+ "compress/gzip"
+ "crypto"
+ "crypto/internal/boring"
+ "crypto/rand"
+ "crypto/sha512"
+ "encoding/hex"
+ "internal/testenv"
+ "log"
+ "os"
+ "strings"
+ "testing"
+)
+
+func Example_ed25519ctx() {
+ pub, priv, err := GenerateKey(nil)
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ msg := []byte("The quick brown fox jumps over the lazy dog")
+
+ sig, err := priv.Sign(nil, msg, &Options{
+ Context: "Example_ed25519ctx",
+ })
+ if err != nil {
+ log.Fatal(err)
+ }
+
+ if err := VerifyWithOptions(pub, msg, sig, &Options{
+ Context: "Example_ed25519ctx",
+ }); err != nil {
+ log.Fatal("invalid signature")
+ }
+}
+
+type zeroReader struct{}
+
+func (zeroReader) Read(buf []byte) (int, error) {
+ for i := range buf {
+ buf[i] = 0
+ }
+ return len(buf), nil
+}
+
+func TestSignVerify(t *testing.T) {
+ var zero zeroReader
+ public, private, _ := GenerateKey(zero)
+
+ message := []byte("test message")
+ sig := Sign(private, message)
+ if !Verify(public, message, sig) {
+ t.Errorf("valid signature rejected")
+ }
+
+ wrongMessage := []byte("wrong message")
+ if Verify(public, wrongMessage, sig) {
+ t.Errorf("signature of different message accepted")
+ }
+}
+
+func TestSignVerifyHashed(t *testing.T) {
+ // From RFC 8032, Section 7.3
+ key, _ := hex.DecodeString("833fe62409237b9d62ec77587520911e9a759cec1d19755b7da901b96dca3d42ec172b93ad5e563bf4932c70e1245034c35467ef2efd4d64ebf819683467e2bf")
+ expectedSig, _ := hex.DecodeString("98a70222f0b8121aa9d30f813d683f809e462b469c7ff87639499bb94e6dae4131f85042463c2a355a2003d062adf5aaa10b8c61e636062aaad11c2a26083406")
+ message, _ := hex.DecodeString("616263")
+
+ private := PrivateKey(key)
+ public := private.Public().(PublicKey)
+ hash := sha512.Sum512(message)
+ sig, err := private.Sign(nil, hash[:], crypto.SHA512)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(sig, expectedSig) {
+ t.Error("signature doesn't match test vector")
+ }
+ sig, err = private.Sign(nil, hash[:], &Options{Hash: crypto.SHA512})
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(sig, expectedSig) {
+ t.Error("signature doesn't match test vector")
+ }
+ if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512}); err != nil {
+ t.Errorf("valid signature rejected: %v", err)
+ }
+
+ if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA256}); err == nil {
+ t.Errorf("expected error for wrong hash")
+ }
+
+ wrongHash := sha512.Sum512([]byte("wrong message"))
+ if VerifyWithOptions(public, wrongHash[:], sig, &Options{Hash: crypto.SHA512}) == nil {
+ t.Errorf("signature of different message accepted")
+ }
+
+ sig[0] ^= 0xff
+ if VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512}) == nil {
+ t.Errorf("invalid signature accepted")
+ }
+ sig[0] ^= 0xff
+ sig[SignatureSize-1] ^= 0xff
+ if VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512}) == nil {
+ t.Errorf("invalid signature accepted")
+ }
+
+ // The RFC provides no test vectors for Ed25519ph with context, so just sign
+ // and verify something.
+ sig, err = private.Sign(nil, hash[:], &Options{Hash: crypto.SHA512, Context: "123"})
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512, Context: "123"}); err != nil {
+ t.Errorf("valid signature rejected: %v", err)
+ }
+ if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA512, Context: "321"}); err == nil {
+ t.Errorf("expected error for wrong context")
+ }
+ if err := VerifyWithOptions(public, hash[:], sig, &Options{Hash: crypto.SHA256, Context: "123"}); err == nil {
+ t.Errorf("expected error for wrong hash")
+ }
+}
+
+func TestSignVerifyContext(t *testing.T) {
+ // From RFC 8032, Section 7.2
+ key, _ := hex.DecodeString("0305334e381af78f141cb666f6199f57bc3495335a256a95bd2a55bf546663f6dfc9425e4f968f7f0c29f0259cf5f9aed6851c2bb4ad8bfb860cfee0ab248292")
+ expectedSig, _ := hex.DecodeString("55a4cc2f70a54e04288c5f4cd1e45a7bb520b36292911876cada7323198dd87a8b36950b95130022907a7fb7c4e9b2d5f6cca685a587b4b21f4b888e4e7edb0d")
+ message, _ := hex.DecodeString("f726936d19c800494e3fdaff20b276a8")
+ context := "foo"
+
+ private := PrivateKey(key)
+ public := private.Public().(PublicKey)
+ sig, err := private.Sign(nil, message, &Options{Context: context})
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(sig, expectedSig) {
+ t.Error("signature doesn't match test vector")
+ }
+ if err := VerifyWithOptions(public, message, sig, &Options{Context: context}); err != nil {
+ t.Errorf("valid signature rejected: %v", err)
+ }
+
+ if VerifyWithOptions(public, []byte("bar"), sig, &Options{Context: context}) == nil {
+ t.Errorf("signature of different message accepted")
+ }
+ if VerifyWithOptions(public, message, sig, &Options{Context: "bar"}) == nil {
+ t.Errorf("signature with different context accepted")
+ }
+
+ sig[0] ^= 0xff
+ if VerifyWithOptions(public, message, sig, &Options{Context: context}) == nil {
+ t.Errorf("invalid signature accepted")
+ }
+ sig[0] ^= 0xff
+ sig[SignatureSize-1] ^= 0xff
+ if VerifyWithOptions(public, message, sig, &Options{Context: context}) == nil {
+ t.Errorf("invalid signature accepted")
+ }
+}
+
+func TestCryptoSigner(t *testing.T) {
+ var zero zeroReader
+ public, private, _ := GenerateKey(zero)
+
+ signer := crypto.Signer(private)
+
+ publicInterface := signer.Public()
+ public2, ok := publicInterface.(PublicKey)
+ if !ok {
+ t.Fatalf("expected PublicKey from Public() but got %T", publicInterface)
+ }
+
+ if !bytes.Equal(public, public2) {
+ t.Errorf("public keys do not match: original:%x vs Public():%x", public, public2)
+ }
+
+ message := []byte("message")
+ var noHash crypto.Hash
+ signature, err := signer.Sign(zero, message, noHash)
+ if err != nil {
+ t.Fatalf("error from Sign(): %s", err)
+ }
+
+ signature2, err := signer.Sign(zero, message, &Options{Hash: noHash})
+ if err != nil {
+ t.Fatalf("error from Sign(): %s", err)
+ }
+ if !bytes.Equal(signature, signature2) {
+ t.Errorf("signatures keys do not match")
+ }
+
+ if !Verify(public, message, signature) {
+ t.Errorf("Verify failed on signature from Sign()")
+ }
+}
+
+func TestEqual(t *testing.T) {
+ public, private, _ := GenerateKey(rand.Reader)
+
+ if !public.Equal(public) {
+ t.Errorf("public key is not equal to itself: %q", public)
+ }
+ if !public.Equal(crypto.Signer(private).Public()) {
+ t.Errorf("private.Public() is not Equal to public: %q", public)
+ }
+ if !private.Equal(private) {
+ t.Errorf("private key is not equal to itself: %q", private)
+ }
+
+ otherPub, otherPriv, _ := GenerateKey(rand.Reader)
+ if public.Equal(otherPub) {
+ t.Errorf("different public keys are Equal")
+ }
+ if private.Equal(otherPriv) {
+ t.Errorf("different private keys are Equal")
+ }
+}
+
+func TestGolden(t *testing.T) {
+ // sign.input.gz is a selection of test cases from
+ // https://ed25519.cr.yp.to/python/sign.input
+ testDataZ, err := os.Open("testdata/sign.input.gz")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer testDataZ.Close()
+ testData, err := gzip.NewReader(testDataZ)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer testData.Close()
+
+ scanner := bufio.NewScanner(testData)
+ lineNo := 0
+
+ for scanner.Scan() {
+ lineNo++
+
+ line := scanner.Text()
+ parts := strings.Split(line, ":")
+ if len(parts) != 5 {
+ t.Fatalf("bad number of parts on line %d", lineNo)
+ }
+
+ privBytes, _ := hex.DecodeString(parts[0])
+ pubKey, _ := hex.DecodeString(parts[1])
+ msg, _ := hex.DecodeString(parts[2])
+ sig, _ := hex.DecodeString(parts[3])
+ // The signatures in the test vectors also include the message
+ // at the end, but we just want R and S.
+ sig = sig[:SignatureSize]
+
+ if l := len(pubKey); l != PublicKeySize {
+ t.Fatalf("bad public key length on line %d: got %d bytes", lineNo, l)
+ }
+
+ var priv [PrivateKeySize]byte
+ copy(priv[:], privBytes)
+ copy(priv[32:], pubKey)
+
+ sig2 := Sign(priv[:], msg)
+ if !bytes.Equal(sig, sig2[:]) {
+ t.Errorf("different signature result on line %d: %x vs %x", lineNo, sig, sig2)
+ }
+
+ if !Verify(pubKey, msg, sig2) {
+ t.Errorf("signature failed to verify on line %d", lineNo)
+ }
+
+ priv2 := NewKeyFromSeed(priv[:32])
+ if !bytes.Equal(priv[:], priv2) {
+ t.Errorf("recreating key pair gave different private key on line %d: %x vs %x", lineNo, priv[:], priv2)
+ }
+
+ if pubKey2 := priv2.Public().(PublicKey); !bytes.Equal(pubKey, pubKey2) {
+ t.Errorf("recreating key pair gave different public key on line %d: %x vs %x", lineNo, pubKey, pubKey2)
+ }
+
+ if seed := priv2.Seed(); !bytes.Equal(priv[:32], seed) {
+ t.Errorf("recreating key pair gave different seed on line %d: %x vs %x", lineNo, priv[:32], seed)
+ }
+ }
+
+ if err := scanner.Err(); err != nil {
+ t.Fatalf("error reading test data: %s", err)
+ }
+}
+
+func TestMalleability(t *testing.T) {
+ // https://tools.ietf.org/html/rfc8032#section-5.1.7 adds an additional test
+ // that s be in [0, order). This prevents someone from adding a multiple of
+ // order to s and obtaining a second valid signature for the same message.
+ msg := []byte{0x54, 0x65, 0x73, 0x74}
+ sig := []byte{
+ 0x7c, 0x38, 0xe0, 0x26, 0xf2, 0x9e, 0x14, 0xaa, 0xbd, 0x05, 0x9a,
+ 0x0f, 0x2d, 0xb8, 0xb0, 0xcd, 0x78, 0x30, 0x40, 0x60, 0x9a, 0x8b,
+ 0xe6, 0x84, 0xdb, 0x12, 0xf8, 0x2a, 0x27, 0x77, 0x4a, 0xb0, 0x67,
+ 0x65, 0x4b, 0xce, 0x38, 0x32, 0xc2, 0xd7, 0x6f, 0x8f, 0x6f, 0x5d,
+ 0xaf, 0xc0, 0x8d, 0x93, 0x39, 0xd4, 0xee, 0xf6, 0x76, 0x57, 0x33,
+ 0x36, 0xa5, 0xc5, 0x1e, 0xb6, 0xf9, 0x46, 0xb3, 0x1d,
+ }
+ publicKey := []byte{
+ 0x7d, 0x4d, 0x0e, 0x7f, 0x61, 0x53, 0xa6, 0x9b, 0x62, 0x42, 0xb5,
+ 0x22, 0xab, 0xbe, 0xe6, 0x85, 0xfd, 0xa4, 0x42, 0x0f, 0x88, 0x34,
+ 0xb1, 0x08, 0xc3, 0xbd, 0xae, 0x36, 0x9e, 0xf5, 0x49, 0xfa,
+ }
+
+ if Verify(publicKey, msg, sig) {
+ t.Fatal("non-canonical signature accepted")
+ }
+}
+
+func TestAllocations(t *testing.T) {
+ if boring.Enabled {
+ t.Skip("skipping allocations test with BoringCrypto")
+ }
+ testenv.SkipIfOptimizationOff(t)
+
+ if allocs := testing.AllocsPerRun(100, func() {
+ seed := make([]byte, SeedSize)
+ message := []byte("Hello, world!")
+ priv := NewKeyFromSeed(seed)
+ pub := priv.Public().(PublicKey)
+ signature := Sign(priv, message)
+ if !Verify(pub, message, signature) {
+ t.Fatal("signature didn't verify")
+ }
+ }); allocs > 0 {
+ t.Errorf("expected zero allocations, got %0.1f", allocs)
+ }
+}
+
+func BenchmarkKeyGeneration(b *testing.B) {
+ var zero zeroReader
+ for i := 0; i < b.N; i++ {
+ if _, _, err := GenerateKey(zero); err != nil {
+ b.Fatal(err)
+ }
+ }
+}
+
+func BenchmarkNewKeyFromSeed(b *testing.B) {
+ seed := make([]byte, SeedSize)
+ for i := 0; i < b.N; i++ {
+ _ = NewKeyFromSeed(seed)
+ }
+}
+
+func BenchmarkSigning(b *testing.B) {
+ var zero zeroReader
+ _, priv, err := GenerateKey(zero)
+ if err != nil {
+ b.Fatal(err)
+ }
+ message := []byte("Hello, world!")
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ Sign(priv, message)
+ }
+}
+
+func BenchmarkVerification(b *testing.B) {
+ var zero zeroReader
+ pub, priv, err := GenerateKey(zero)
+ if err != nil {
+ b.Fatal(err)
+ }
+ message := []byte("Hello, world!")
+ signature := Sign(priv, message)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ Verify(pub, message, signature)
+ }
+}
diff --git a/src/crypto/ed25519/ed25519vectors_test.go b/src/crypto/ed25519/ed25519vectors_test.go
new file mode 100644
index 0000000..f933f28
--- /dev/null
+++ b/src/crypto/ed25519/ed25519vectors_test.go
@@ -0,0 +1,120 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package ed25519_test
+
+import (
+ "crypto/ed25519"
+ "encoding/hex"
+ "encoding/json"
+ "internal/testenv"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "testing"
+)
+
+// TestEd25519Vectors runs a very large set of test vectors that exercise all
+// combinations of low-order points, low-order components, and non-canonical
+// encodings. These vectors lock in unspecified and spec-divergent behaviors in
+// edge cases that are not security relevant in most contexts, but that can
+// cause issues in consensus applications if changed.
+//
+// Our behavior matches the "classic" unwritten verification rules of the
+// "ref10" reference implementation.
+//
+// Note that although we test for these edge cases, they are not covered by the
+// Go 1 Compatibility Promise. Applications that need stable verification rules
+// should use github.com/hdevalence/ed25519consensus.
+//
+// See https://hdevalence.ca/blog/2020-10-04-its-25519am for more details.
+func TestEd25519Vectors(t *testing.T) {
+ jsonVectors := downloadEd25519Vectors(t)
+ var vectors []struct {
+ A, R, S, M string
+ Flags []string
+ }
+ if err := json.Unmarshal(jsonVectors, &vectors); err != nil {
+ t.Fatal(err)
+ }
+ for i, v := range vectors {
+ expectedToVerify := true
+ for _, f := range v.Flags {
+ switch f {
+ // We use the simplified verification formula that doesn't multiply
+ // by the cofactor, so any low order residue will cause the
+ // signature not to verify.
+ //
+ // This is allowed, but not required, by RFC 8032.
+ case "LowOrderResidue":
+ expectedToVerify = false
+ // Our point decoding allows non-canonical encodings (in violation
+ // of RFC 8032) but R is not decoded: instead, R is recomputed and
+ // compared bytewise against the canonical encoding.
+ case "NonCanonicalR":
+ expectedToVerify = false
+ }
+ }
+
+ publicKey := decodeHex(t, v.A)
+ signature := append(decodeHex(t, v.R), decodeHex(t, v.S)...)
+ message := []byte(v.M)
+
+ didVerify := ed25519.Verify(publicKey, message, signature)
+ if didVerify && !expectedToVerify {
+ t.Errorf("#%d: vector with flags %s unexpectedly verified", i, v.Flags)
+ }
+ if !didVerify && expectedToVerify {
+ t.Errorf("#%d: vector with flags %s unexpectedly rejected", i, v.Flags)
+ }
+ }
+}
+
+func downloadEd25519Vectors(t *testing.T) []byte {
+ testenv.MustHaveExternalNetwork(t)
+
+ // Create a temp dir and modcache subdir.
+ d := t.TempDir()
+ // Create a spot for the modcache.
+ modcache := filepath.Join(d, "modcache")
+ if err := os.Mkdir(modcache, 0777); err != nil {
+ t.Fatal(err)
+ }
+
+ t.Setenv("GO111MODULE", "on")
+ t.Setenv("GOMODCACHE", modcache)
+
+ // Download the JSON test file from the GOPROXY with `go mod download`,
+ // pinning the version so test and module caching works as expected.
+ goTool := testenv.GoToolPath(t)
+ path := "filippo.io/mostly-harmless/ed25519vectors@v0.0.0-20210322192420-30a2d7243a94"
+ cmd := exec.Command(goTool, "mod", "download", "-modcacherw", "-json", path)
+ // TODO: enable the sumdb once the TryBots proxy supports it.
+ cmd.Env = append(os.Environ(), "GONOSUMDB=*")
+ output, err := cmd.Output()
+ if err != nil {
+ t.Fatalf("failed to run `go mod download -json %s`, output: %s", path, output)
+ }
+ var dm struct {
+ Dir string // absolute path to cached source root directory
+ }
+ if err := json.Unmarshal(output, &dm); err != nil {
+ t.Fatal(err)
+ }
+
+ jsonVectors, err := os.ReadFile(filepath.Join(dm.Dir, "ed25519vectors.json"))
+ if err != nil {
+ t.Fatalf("failed to read ed25519vectors.json: %v", err)
+ }
+ return jsonVectors
+}
+
+func decodeHex(t *testing.T, s string) []byte {
+ t.Helper()
+ b, err := hex.DecodeString(s)
+ if err != nil {
+ t.Errorf("invalid hex: %v", err)
+ }
+ return b
+}
diff --git a/src/crypto/ed25519/testdata/sign.input.gz b/src/crypto/ed25519/testdata/sign.input.gz
new file mode 100644
index 0000000..e6dc728
--- /dev/null
+++ b/src/crypto/ed25519/testdata/sign.input.gz
Binary files differ
diff --git a/src/crypto/elliptic/elliptic.go b/src/crypto/elliptic/elliptic.go
new file mode 100644
index 0000000..6b07f5b
--- /dev/null
+++ b/src/crypto/elliptic/elliptic.go
@@ -0,0 +1,275 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package elliptic implements the standard NIST P-224, P-256, P-384, and P-521
+// elliptic curves over prime fields.
+//
+// The P224(), P256(), P384() and P521() values are necessary to use the crypto/ecdsa package.
+// Most other uses should migrate to the more efficient and safer crypto/ecdh package.
+package elliptic
+
+import (
+ "io"
+ "math/big"
+ "sync"
+)
+
+// A Curve represents a short-form Weierstrass curve with a=-3.
+//
+// The behavior of Add, Double, and ScalarMult when the input is not a point on
+// the curve is undefined.
+//
+// Note that the conventional point at infinity (0, 0) is not considered on the
+// curve, although it can be returned by Add, Double, ScalarMult, or
+// ScalarBaseMult (but not the Unmarshal or UnmarshalCompressed functions).
+type Curve interface {
+ // Params returns the parameters for the curve.
+ Params() *CurveParams
+
+ // IsOnCurve reports whether the given (x,y) lies on the curve.
+ //
+ // Note: this is a low-level unsafe API. For ECDH, use the crypto/ecdh
+ // package. The NewPublicKey methods of NIST curves in crypto/ecdh accept
+ // the same encoding as the Unmarshal function, and perform on-curve checks.
+ IsOnCurve(x, y *big.Int) bool
+
+ // Add returns the sum of (x1,y1) and (x2,y2).
+ //
+ // Note: this is a low-level unsafe API.
+ Add(x1, y1, x2, y2 *big.Int) (x, y *big.Int)
+
+ // Double returns 2*(x,y).
+ //
+ // Note: this is a low-level unsafe API.
+ Double(x1, y1 *big.Int) (x, y *big.Int)
+
+ // ScalarMult returns k*(x,y) where k is an integer in big-endian form.
+ //
+ // Note: this is a low-level unsafe API. For ECDH, use the crypto/ecdh
+ // package. Most uses of ScalarMult can be replaced by a call to the ECDH
+ // methods of NIST curves in crypto/ecdh.
+ ScalarMult(x1, y1 *big.Int, k []byte) (x, y *big.Int)
+
+ // ScalarBaseMult returns k*G, where G is the base point of the group
+ // and k is an integer in big-endian form.
+ //
+ // Note: this is a low-level unsafe API. For ECDH, use the crypto/ecdh
+ // package. Most uses of ScalarBaseMult can be replaced by a call to the
+ // PrivateKey.PublicKey method in crypto/ecdh.
+ ScalarBaseMult(k []byte) (x, y *big.Int)
+}
+
+var mask = []byte{0xff, 0x1, 0x3, 0x7, 0xf, 0x1f, 0x3f, 0x7f}
+
+// GenerateKey returns a public/private key pair. The private key is
+// generated using the given reader, which must return random data.
+//
+// Note: for ECDH, use the GenerateKey methods of the crypto/ecdh package;
+// for ECDSA, use the GenerateKey function of the crypto/ecdsa package.
+func GenerateKey(curve Curve, rand io.Reader) (priv []byte, x, y *big.Int, err error) {
+ N := curve.Params().N
+ bitSize := N.BitLen()
+ byteLen := (bitSize + 7) / 8
+ priv = make([]byte, byteLen)
+
+ for x == nil {
+ _, err = io.ReadFull(rand, priv)
+ if err != nil {
+ return
+ }
+ // We have to mask off any excess bits in the case that the size of the
+ // underlying field is not a whole number of bytes.
+ priv[0] &= mask[bitSize%8]
+ // This is because, in tests, rand will return all zeros and we don't
+ // want to get the point at infinity and loop forever.
+ priv[1] ^= 0x42
+
+ // If the scalar is out of range, sample another random number.
+ if new(big.Int).SetBytes(priv).Cmp(N) >= 0 {
+ continue
+ }
+
+ x, y = curve.ScalarBaseMult(priv)
+ }
+ return
+}
+
+// Marshal converts a point on the curve into the uncompressed form specified in
+// SEC 1, Version 2.0, Section 2.3.3. If the point is not on the curve (or is
+// the conventional point at infinity), the behavior is undefined.
+//
+// Note: for ECDH, use the crypto/ecdh package. This function returns an
+// encoding equivalent to that of PublicKey.Bytes in crypto/ecdh.
+func Marshal(curve Curve, x, y *big.Int) []byte {
+ panicIfNotOnCurve(curve, x, y)
+
+ byteLen := (curve.Params().BitSize + 7) / 8
+
+ ret := make([]byte, 1+2*byteLen)
+ ret[0] = 4 // uncompressed point
+
+ x.FillBytes(ret[1 : 1+byteLen])
+ y.FillBytes(ret[1+byteLen : 1+2*byteLen])
+
+ return ret
+}
+
+// MarshalCompressed converts a point on the curve into the compressed form
+// specified in SEC 1, Version 2.0, Section 2.3.3. If the point is not on the
+// curve (or is the conventional point at infinity), the behavior is undefined.
+func MarshalCompressed(curve Curve, x, y *big.Int) []byte {
+ panicIfNotOnCurve(curve, x, y)
+ byteLen := (curve.Params().BitSize + 7) / 8
+ compressed := make([]byte, 1+byteLen)
+ compressed[0] = byte(y.Bit(0)) | 2
+ x.FillBytes(compressed[1:])
+ return compressed
+}
+
+// unmarshaler is implemented by curves with their own constant-time Unmarshal.
+//
+// There isn't an equivalent interface for Marshal/MarshalCompressed because
+// that doesn't involve any mathematical operations, only FillBytes and Bit.
+type unmarshaler interface {
+ Unmarshal([]byte) (x, y *big.Int)
+ UnmarshalCompressed([]byte) (x, y *big.Int)
+}
+
+// Assert that the known curves implement unmarshaler.
+var _ = []unmarshaler{p224, p256, p384, p521}
+
+// Unmarshal converts a point, serialized by Marshal, into an x, y pair. It is
+// an error if the point is not in uncompressed form, is not on the curve, or is
+// the point at infinity. On error, x = nil.
+//
+// Note: for ECDH, use the crypto/ecdh package. This function accepts an
+// encoding equivalent to that of the NewPublicKey methods in crypto/ecdh.
+func Unmarshal(curve Curve, data []byte) (x, y *big.Int) {
+ if c, ok := curve.(unmarshaler); ok {
+ return c.Unmarshal(data)
+ }
+
+ byteLen := (curve.Params().BitSize + 7) / 8
+ if len(data) != 1+2*byteLen {
+ return nil, nil
+ }
+ if data[0] != 4 { // uncompressed form
+ return nil, nil
+ }
+ p := curve.Params().P
+ x = new(big.Int).SetBytes(data[1 : 1+byteLen])
+ y = new(big.Int).SetBytes(data[1+byteLen:])
+ if x.Cmp(p) >= 0 || y.Cmp(p) >= 0 {
+ return nil, nil
+ }
+ if !curve.IsOnCurve(x, y) {
+ return nil, nil
+ }
+ return
+}
+
+// UnmarshalCompressed converts a point, serialized by MarshalCompressed, into
+// an x, y pair. It is an error if the point is not in compressed form, is not
+// on the curve, or is the point at infinity. On error, x = nil.
+func UnmarshalCompressed(curve Curve, data []byte) (x, y *big.Int) {
+ if c, ok := curve.(unmarshaler); ok {
+ return c.UnmarshalCompressed(data)
+ }
+
+ byteLen := (curve.Params().BitSize + 7) / 8
+ if len(data) != 1+byteLen {
+ return nil, nil
+ }
+ if data[0] != 2 && data[0] != 3 { // compressed form
+ return nil, nil
+ }
+ p := curve.Params().P
+ x = new(big.Int).SetBytes(data[1:])
+ if x.Cmp(p) >= 0 {
+ return nil, nil
+ }
+ // y² = x³ - 3x + b
+ y = curve.Params().polynomial(x)
+ y = y.ModSqrt(y, p)
+ if y == nil {
+ return nil, nil
+ }
+ if byte(y.Bit(0)) != data[0]&1 {
+ y.Neg(y).Mod(y, p)
+ }
+ if !curve.IsOnCurve(x, y) {
+ return nil, nil
+ }
+ return
+}
+
+func panicIfNotOnCurve(curve Curve, x, y *big.Int) {
+ // (0, 0) is the point at infinity by convention. It's ok to operate on it,
+ // although IsOnCurve is documented to return false for it. See Issue 37294.
+ if x.Sign() == 0 && y.Sign() == 0 {
+ return
+ }
+
+ if !curve.IsOnCurve(x, y) {
+ panic("crypto/elliptic: attempted operation on invalid point")
+ }
+}
+
+var initonce sync.Once
+
+func initAll() {
+ initP224()
+ initP256()
+ initP384()
+ initP521()
+}
+
+// P224 returns a Curve which implements NIST P-224 (FIPS 186-3, section D.2.2),
+// also known as secp224r1. The CurveParams.Name of this Curve is "P-224".
+//
+// Multiple invocations of this function will return the same value, so it can
+// be used for equality checks and switch statements.
+//
+// The cryptographic operations are implemented using constant-time algorithms.
+func P224() Curve {
+ initonce.Do(initAll)
+ return p224
+}
+
+// P256 returns a Curve which implements NIST P-256 (FIPS 186-3, section D.2.3),
+// also known as secp256r1 or prime256v1. The CurveParams.Name of this Curve is
+// "P-256".
+//
+// Multiple invocations of this function will return the same value, so it can
+// be used for equality checks and switch statements.
+//
+// The cryptographic operations are implemented using constant-time algorithms.
+func P256() Curve {
+ initonce.Do(initAll)
+ return p256
+}
+
+// P384 returns a Curve which implements NIST P-384 (FIPS 186-3, section D.2.4),
+// also known as secp384r1. The CurveParams.Name of this Curve is "P-384".
+//
+// Multiple invocations of this function will return the same value, so it can
+// be used for equality checks and switch statements.
+//
+// The cryptographic operations are implemented using constant-time algorithms.
+func P384() Curve {
+ initonce.Do(initAll)
+ return p384
+}
+
+// P521 returns a Curve which implements NIST P-521 (FIPS 186-3, section D.2.5),
+// also known as secp521r1. The CurveParams.Name of this Curve is "P-521".
+//
+// Multiple invocations of this function will return the same value, so it can
+// be used for equality checks and switch statements.
+//
+// The cryptographic operations are implemented using constant-time algorithms.
+func P521() Curve {
+ initonce.Do(initAll)
+ return p521
+}
diff --git a/src/crypto/elliptic/elliptic_test.go b/src/crypto/elliptic/elliptic_test.go
new file mode 100644
index 0000000..34d70f6
--- /dev/null
+++ b/src/crypto/elliptic/elliptic_test.go
@@ -0,0 +1,405 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package elliptic
+
+import (
+ "bytes"
+ "crypto/rand"
+ "encoding/hex"
+ "math/big"
+ "testing"
+)
+
+// genericParamsForCurve returns the dereferenced CurveParams for
+// the specified curve. This is used to avoid the logic for
+// upgrading a curve to its specific implementation, forcing
+// usage of the generic implementation.
+func genericParamsForCurve(c Curve) *CurveParams {
+ d := *(c.Params())
+ return &d
+}
+
+func testAllCurves(t *testing.T, f func(*testing.T, Curve)) {
+ tests := []struct {
+ name string
+ curve Curve
+ }{
+ {"P256", P256()},
+ {"P256/Params", genericParamsForCurve(P256())},
+ {"P224", P224()},
+ {"P224/Params", genericParamsForCurve(P224())},
+ {"P384", P384()},
+ {"P384/Params", genericParamsForCurve(P384())},
+ {"P521", P521()},
+ {"P521/Params", genericParamsForCurve(P521())},
+ }
+ if testing.Short() {
+ tests = tests[:1]
+ }
+ for _, test := range tests {
+ curve := test.curve
+ t.Run(test.name, func(t *testing.T) {
+ t.Parallel()
+ f(t, curve)
+ })
+ }
+}
+
+func TestOnCurve(t *testing.T) {
+ testAllCurves(t, func(t *testing.T, curve Curve) {
+ if !curve.IsOnCurve(curve.Params().Gx, curve.Params().Gy) {
+ t.Error("basepoint is not on the curve")
+ }
+ })
+}
+
+func TestOffCurve(t *testing.T) {
+ testAllCurves(t, func(t *testing.T, curve Curve) {
+ x, y := new(big.Int).SetInt64(1), new(big.Int).SetInt64(1)
+ if curve.IsOnCurve(x, y) {
+ t.Errorf("point off curve is claimed to be on the curve")
+ }
+
+ byteLen := (curve.Params().BitSize + 7) / 8
+ b := make([]byte, 1+2*byteLen)
+ b[0] = 4 // uncompressed point
+ x.FillBytes(b[1 : 1+byteLen])
+ y.FillBytes(b[1+byteLen : 1+2*byteLen])
+
+ x1, y1 := Unmarshal(curve, b)
+ if x1 != nil || y1 != nil {
+ t.Errorf("unmarshaling a point not on the curve succeeded")
+ }
+ })
+}
+
+func TestInfinity(t *testing.T) {
+ testAllCurves(t, testInfinity)
+}
+
+func isInfinity(x, y *big.Int) bool {
+ return x.Sign() == 0 && y.Sign() == 0
+}
+
+func testInfinity(t *testing.T, curve Curve) {
+ x0, y0 := new(big.Int), new(big.Int)
+ xG, yG := curve.Params().Gx, curve.Params().Gy
+
+ if !isInfinity(curve.ScalarMult(xG, yG, curve.Params().N.Bytes())) {
+ t.Errorf("x^q != ∞")
+ }
+ if !isInfinity(curve.ScalarMult(xG, yG, []byte{0})) {
+ t.Errorf("x^0 != ∞")
+ }
+
+ if !isInfinity(curve.ScalarMult(x0, y0, []byte{1, 2, 3})) {
+ t.Errorf("∞^k != ∞")
+ }
+ if !isInfinity(curve.ScalarMult(x0, y0, []byte{0})) {
+ t.Errorf("∞^0 != ∞")
+ }
+
+ if !isInfinity(curve.ScalarBaseMult(curve.Params().N.Bytes())) {
+ t.Errorf("b^q != ∞")
+ }
+ if !isInfinity(curve.ScalarBaseMult([]byte{0})) {
+ t.Errorf("b^0 != ∞")
+ }
+
+ if !isInfinity(curve.Double(x0, y0)) {
+ t.Errorf("2∞ != ∞")
+ }
+ // There is no other point of order two on the NIST curves (as they have
+ // cofactor one), so Double can't otherwise return the point at infinity.
+
+ nMinusOne := new(big.Int).Sub(curve.Params().N, big.NewInt(1))
+ x, y := curve.ScalarMult(xG, yG, nMinusOne.Bytes())
+ x, y = curve.Add(x, y, xG, yG)
+ if !isInfinity(x, y) {
+ t.Errorf("x^(q-1) + x != ∞")
+ }
+ x, y = curve.Add(xG, yG, x0, y0)
+ if x.Cmp(xG) != 0 || y.Cmp(yG) != 0 {
+ t.Errorf("x+∞ != x")
+ }
+ x, y = curve.Add(x0, y0, xG, yG)
+ if x.Cmp(xG) != 0 || y.Cmp(yG) != 0 {
+ t.Errorf("∞+x != x")
+ }
+
+ if curve.IsOnCurve(x0, y0) {
+ t.Errorf("IsOnCurve(∞) == true")
+ }
+
+ if xx, yy := Unmarshal(curve, Marshal(curve, x0, y0)); xx != nil || yy != nil {
+ t.Errorf("Unmarshal(Marshal(∞)) did not return an error")
+ }
+ // We don't test UnmarshalCompressed(MarshalCompressed(∞)) because there are
+ // two valid points with x = 0.
+ if xx, yy := Unmarshal(curve, []byte{0x00}); xx != nil || yy != nil {
+ t.Errorf("Unmarshal(∞) did not return an error")
+ }
+ byteLen := (curve.Params().BitSize + 7) / 8
+ buf := make([]byte, byteLen*2+1)
+ buf[0] = 4 // Uncompressed format.
+ if xx, yy := Unmarshal(curve, buf); xx != nil || yy != nil {
+ t.Errorf("Unmarshal((0,0)) did not return an error")
+ }
+}
+
+func TestMarshal(t *testing.T) {
+ testAllCurves(t, func(t *testing.T, curve Curve) {
+ _, x, y, err := GenerateKey(curve, rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ serialized := Marshal(curve, x, y)
+ xx, yy := Unmarshal(curve, serialized)
+ if xx == nil {
+ t.Fatal("failed to unmarshal")
+ }
+ if xx.Cmp(x) != 0 || yy.Cmp(y) != 0 {
+ t.Fatal("unmarshal returned different values")
+ }
+ })
+}
+
+func TestUnmarshalToLargeCoordinates(t *testing.T) {
+ // See https://golang.org/issues/20482.
+ testAllCurves(t, testUnmarshalToLargeCoordinates)
+}
+
+func testUnmarshalToLargeCoordinates(t *testing.T, curve Curve) {
+ p := curve.Params().P
+ byteLen := (p.BitLen() + 7) / 8
+
+ // Set x to be greater than curve's parameter P – specifically, to P+5.
+ // Set y to mod_sqrt(x^3 - 3x + B)) so that (x mod P = 5 , y) is on the
+ // curve.
+ x := new(big.Int).Add(p, big.NewInt(5))
+ y := curve.Params().polynomial(x)
+ y.ModSqrt(y, p)
+
+ invalid := make([]byte, byteLen*2+1)
+ invalid[0] = 4 // uncompressed encoding
+ x.FillBytes(invalid[1 : 1+byteLen])
+ y.FillBytes(invalid[1+byteLen:])
+
+ if X, Y := Unmarshal(curve, invalid); X != nil || Y != nil {
+ t.Errorf("Unmarshal accepts invalid X coordinate")
+ }
+
+ if curve == p256 {
+ // This is a point on the curve with a small y value, small enough that
+ // we can add p and still be within 32 bytes.
+ x, _ = new(big.Int).SetString("31931927535157963707678568152204072984517581467226068221761862915403492091210", 10)
+ y, _ = new(big.Int).SetString("5208467867388784005506817585327037698770365050895731383201516607147", 10)
+ y.Add(y, p)
+
+ if p.Cmp(y) > 0 || y.BitLen() != 256 {
+ t.Fatal("y not within expected range")
+ }
+
+ // marshal
+ x.FillBytes(invalid[1 : 1+byteLen])
+ y.FillBytes(invalid[1+byteLen:])
+
+ if X, Y := Unmarshal(curve, invalid); X != nil || Y != nil {
+ t.Errorf("Unmarshal accepts invalid Y coordinate")
+ }
+ }
+}
+
+// TestInvalidCoordinates tests big.Int values that are not valid field elements
+// (negative or bigger than P). They are expected to return false from
+// IsOnCurve, all other behavior is undefined.
+func TestInvalidCoordinates(t *testing.T) {
+ testAllCurves(t, testInvalidCoordinates)
+}
+
+func testInvalidCoordinates(t *testing.T, curve Curve) {
+ checkIsOnCurveFalse := func(name string, x, y *big.Int) {
+ if curve.IsOnCurve(x, y) {
+ t.Errorf("IsOnCurve(%s) unexpectedly returned true", name)
+ }
+ }
+
+ p := curve.Params().P
+ _, x, y, _ := GenerateKey(curve, rand.Reader)
+ xx, yy := new(big.Int), new(big.Int)
+
+ // Check if the sign is getting dropped.
+ xx.Neg(x)
+ checkIsOnCurveFalse("-x, y", xx, y)
+ yy.Neg(y)
+ checkIsOnCurveFalse("x, -y", x, yy)
+
+ // Check if negative values are reduced modulo P.
+ xx.Sub(x, p)
+ checkIsOnCurveFalse("x-P, y", xx, y)
+ yy.Sub(y, p)
+ checkIsOnCurveFalse("x, y-P", x, yy)
+
+ // Check if positive values are reduced modulo P.
+ xx.Add(x, p)
+ checkIsOnCurveFalse("x+P, y", xx, y)
+ yy.Add(y, p)
+ checkIsOnCurveFalse("x, y+P", x, yy)
+
+ // Check if the overflow is dropped.
+ xx.Add(x, new(big.Int).Lsh(big.NewInt(1), 535))
+ checkIsOnCurveFalse("x+2⁵³⁵, y", xx, y)
+ yy.Add(y, new(big.Int).Lsh(big.NewInt(1), 535))
+ checkIsOnCurveFalse("x, y+2⁵³⁵", x, yy)
+
+ // Check if P is treated like zero (if possible).
+ // y^2 = x^3 - 3x + B
+ // y = mod_sqrt(x^3 - 3x + B)
+ // y = mod_sqrt(B) if x = 0
+ // If there is no modsqrt, there is no point with x = 0, can't test x = P.
+ if yy := new(big.Int).ModSqrt(curve.Params().B, p); yy != nil {
+ if !curve.IsOnCurve(big.NewInt(0), yy) {
+ t.Fatal("(0, mod_sqrt(B)) is not on the curve?")
+ }
+ checkIsOnCurveFalse("P, y", p, yy)
+ }
+}
+
+func TestMarshalCompressed(t *testing.T) {
+ t.Run("P-256/03", func(t *testing.T) {
+ data, _ := hex.DecodeString("031e3987d9f9ea9d7dd7155a56a86b2009e1e0ab332f962d10d8beb6406ab1ad79")
+ x, _ := new(big.Int).SetString("13671033352574878777044637384712060483119675368076128232297328793087057702265", 10)
+ y, _ := new(big.Int).SetString("66200849279091436748794323380043701364391950689352563629885086590854940586447", 10)
+ testMarshalCompressed(t, P256(), x, y, data)
+ })
+ t.Run("P-256/02", func(t *testing.T) {
+ data, _ := hex.DecodeString("021e3987d9f9ea9d7dd7155a56a86b2009e1e0ab332f962d10d8beb6406ab1ad79")
+ x, _ := new(big.Int).SetString("13671033352574878777044637384712060483119675368076128232297328793087057702265", 10)
+ y, _ := new(big.Int).SetString("49591239931264812013903123569363872165694192725937750565648544718012157267504", 10)
+ testMarshalCompressed(t, P256(), x, y, data)
+ })
+
+ t.Run("Invalid", func(t *testing.T) {
+ data, _ := hex.DecodeString("02fd4bf61763b46581fd9174d623516cf3c81edd40e29ffa2777fb6cb0ae3ce535")
+ X, Y := UnmarshalCompressed(P256(), data)
+ if X != nil || Y != nil {
+ t.Error("expected an error for invalid encoding")
+ }
+ })
+
+ if testing.Short() {
+ t.Skip("skipping other curves on short test")
+ }
+
+ testAllCurves(t, func(t *testing.T, curve Curve) {
+ _, x, y, err := GenerateKey(curve, rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ testMarshalCompressed(t, curve, x, y, nil)
+ })
+
+}
+
+func testMarshalCompressed(t *testing.T, curve Curve, x, y *big.Int, want []byte) {
+ if !curve.IsOnCurve(x, y) {
+ t.Fatal("invalid test point")
+ }
+ got := MarshalCompressed(curve, x, y)
+ if want != nil && !bytes.Equal(got, want) {
+ t.Errorf("got unexpected MarshalCompressed result: got %x, want %x", got, want)
+ }
+
+ X, Y := UnmarshalCompressed(curve, got)
+ if X == nil || Y == nil {
+ t.Fatalf("UnmarshalCompressed failed unexpectedly")
+ }
+
+ if !curve.IsOnCurve(X, Y) {
+ t.Error("UnmarshalCompressed returned a point not on the curve")
+ }
+ if X.Cmp(x) != 0 || Y.Cmp(y) != 0 {
+ t.Errorf("point did not round-trip correctly: got (%v, %v), want (%v, %v)", X, Y, x, y)
+ }
+}
+
+func TestLargeIsOnCurve(t *testing.T) {
+ testAllCurves(t, func(t *testing.T, curve Curve) {
+ large := big.NewInt(1)
+ large.Lsh(large, 1000)
+ if curve.IsOnCurve(large, large) {
+ t.Errorf("(2^1000, 2^1000) is reported on the curve")
+ }
+ })
+}
+
+func benchmarkAllCurves(b *testing.B, f func(*testing.B, Curve)) {
+ tests := []struct {
+ name string
+ curve Curve
+ }{
+ {"P256", P256()},
+ {"P224", P224()},
+ {"P384", P384()},
+ {"P521", P521()},
+ }
+ for _, test := range tests {
+ curve := test.curve
+ b.Run(test.name, func(b *testing.B) {
+ f(b, curve)
+ })
+ }
+}
+
+func BenchmarkScalarBaseMult(b *testing.B) {
+ benchmarkAllCurves(b, func(b *testing.B, curve Curve) {
+ priv, _, _, _ := GenerateKey(curve, rand.Reader)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ x, _ := curve.ScalarBaseMult(priv)
+ // Prevent the compiler from optimizing out the operation.
+ priv[0] ^= byte(x.Bits()[0])
+ }
+ })
+}
+
+func BenchmarkScalarMult(b *testing.B) {
+ benchmarkAllCurves(b, func(b *testing.B, curve Curve) {
+ _, x, y, _ := GenerateKey(curve, rand.Reader)
+ priv, _, _, _ := GenerateKey(curve, rand.Reader)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ x, y = curve.ScalarMult(x, y, priv)
+ }
+ })
+}
+
+func BenchmarkMarshalUnmarshal(b *testing.B) {
+ benchmarkAllCurves(b, func(b *testing.B, curve Curve) {
+ _, x, y, _ := GenerateKey(curve, rand.Reader)
+ b.Run("Uncompressed", func(b *testing.B) {
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ buf := Marshal(curve, x, y)
+ xx, yy := Unmarshal(curve, buf)
+ if xx.Cmp(x) != 0 || yy.Cmp(y) != 0 {
+ b.Error("Unmarshal output different from Marshal input")
+ }
+ }
+ })
+ b.Run("Compressed", func(b *testing.B) {
+ b.ReportAllocs()
+ for i := 0; i < b.N; i++ {
+ buf := MarshalCompressed(curve, x, y)
+ xx, yy := UnmarshalCompressed(curve, buf)
+ if xx.Cmp(x) != 0 || yy.Cmp(y) != 0 {
+ b.Error("Unmarshal output different from Marshal input")
+ }
+ }
+ })
+ })
+}
diff --git a/src/crypto/elliptic/nistec.go b/src/crypto/elliptic/nistec.go
new file mode 100644
index 0000000..d906c57
--- /dev/null
+++ b/src/crypto/elliptic/nistec.go
@@ -0,0 +1,294 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package elliptic
+
+import (
+ "crypto/internal/nistec"
+ "errors"
+ "math/big"
+)
+
+var p224 = &nistCurve[*nistec.P224Point]{
+ newPoint: nistec.NewP224Point,
+}
+
+func initP224() {
+ p224.params = &CurveParams{
+ Name: "P-224",
+ BitSize: 224,
+ // FIPS 186-4, section D.1.2.2
+ P: bigFromDecimal("26959946667150639794667015087019630673557916260026308143510066298881"),
+ N: bigFromDecimal("26959946667150639794667015087019625940457807714424391721682722368061"),
+ B: bigFromHex("b4050a850c04b3abf54132565044b0b7d7bfd8ba270b39432355ffb4"),
+ Gx: bigFromHex("b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21"),
+ Gy: bigFromHex("bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34"),
+ }
+}
+
+type p256Curve struct {
+ nistCurve[*nistec.P256Point]
+}
+
+var p256 = &p256Curve{nistCurve[*nistec.P256Point]{
+ newPoint: nistec.NewP256Point,
+}}
+
+func initP256() {
+ p256.params = &CurveParams{
+ Name: "P-256",
+ BitSize: 256,
+ // FIPS 186-4, section D.1.2.3
+ P: bigFromDecimal("115792089210356248762697446949407573530086143415290314195533631308867097853951"),
+ N: bigFromDecimal("115792089210356248762697446949407573529996955224135760342422259061068512044369"),
+ B: bigFromHex("5ac635d8aa3a93e7b3ebbd55769886bc651d06b0cc53b0f63bce3c3e27d2604b"),
+ Gx: bigFromHex("6b17d1f2e12c4247f8bce6e563a440f277037d812deb33a0f4a13945d898c296"),
+ Gy: bigFromHex("4fe342e2fe1a7f9b8ee7eb4a7c0f9e162bce33576b315ececbb6406837bf51f5"),
+ }
+}
+
+var p384 = &nistCurve[*nistec.P384Point]{
+ newPoint: nistec.NewP384Point,
+}
+
+func initP384() {
+ p384.params = &CurveParams{
+ Name: "P-384",
+ BitSize: 384,
+ // FIPS 186-4, section D.1.2.4
+ P: bigFromDecimal("394020061963944792122790401001436138050797392704654" +
+ "46667948293404245721771496870329047266088258938001861606973112319"),
+ N: bigFromDecimal("394020061963944792122790401001436138050797392704654" +
+ "46667946905279627659399113263569398956308152294913554433653942643"),
+ B: bigFromHex("b3312fa7e23ee7e4988e056be3f82d19181d9c6efe8141120314088" +
+ "f5013875ac656398d8a2ed19d2a85c8edd3ec2aef"),
+ Gx: bigFromHex("aa87ca22be8b05378eb1c71ef320ad746e1d3b628ba79b9859f741" +
+ "e082542a385502f25dbf55296c3a545e3872760ab7"),
+ Gy: bigFromHex("3617de4a96262c6f5d9e98bf9292dc29f8f41dbd289a147ce9da31" +
+ "13b5f0b8c00a60b1ce1d7e819d7a431d7c90ea0e5f"),
+ }
+}
+
+var p521 = &nistCurve[*nistec.P521Point]{
+ newPoint: nistec.NewP521Point,
+}
+
+func initP521() {
+ p521.params = &CurveParams{
+ Name: "P-521",
+ BitSize: 521,
+ // FIPS 186-4, section D.1.2.5
+ P: bigFromDecimal("68647976601306097149819007990813932172694353001433" +
+ "0540939446345918554318339765605212255964066145455497729631139148" +
+ "0858037121987999716643812574028291115057151"),
+ N: bigFromDecimal("68647976601306097149819007990813932172694353001433" +
+ "0540939446345918554318339765539424505774633321719753296399637136" +
+ "3321113864768612440380340372808892707005449"),
+ B: bigFromHex("0051953eb9618e1c9a1f929a21a0b68540eea2da725b99b315f3b8" +
+ "b489918ef109e156193951ec7e937b1652c0bd3bb1bf073573df883d2c34f1ef" +
+ "451fd46b503f00"),
+ Gx: bigFromHex("00c6858e06b70404e9cd9e3ecb662395b4429c648139053fb521f8" +
+ "28af606b4d3dbaa14b5e77efe75928fe1dc127a2ffa8de3348b3c1856a429bf9" +
+ "7e7e31c2e5bd66"),
+ Gy: bigFromHex("011839296a789a3bc0045c8a5fb42c7d1bd998f54449579b446817" +
+ "afbd17273e662c97ee72995ef42640c550b9013fad0761353c7086a272c24088" +
+ "be94769fd16650"),
+ }
+}
+
+// nistCurve is a Curve implementation based on a nistec Point.
+//
+// It's a wrapper that exposes the big.Int-based Curve interface and encodes the
+// legacy idiosyncrasies it requires, such as invalid and infinity point
+// handling.
+//
+// To interact with the nistec package, points are encoded into and decoded from
+// properly formatted byte slices. All big.Int use is limited to this package.
+// Encoding and decoding is 1/1000th of the runtime of a scalar multiplication,
+// so the overhead is acceptable.
+type nistCurve[Point nistPoint[Point]] struct {
+ newPoint func() Point
+ params *CurveParams
+}
+
+// nistPoint is a generic constraint for the nistec Point types.
+type nistPoint[T any] interface {
+ Bytes() []byte
+ SetBytes([]byte) (T, error)
+ Add(T, T) T
+ Double(T) T
+ ScalarMult(T, []byte) (T, error)
+ ScalarBaseMult([]byte) (T, error)
+}
+
+func (curve *nistCurve[Point]) Params() *CurveParams {
+ return curve.params
+}
+
+func (curve *nistCurve[Point]) IsOnCurve(x, y *big.Int) bool {
+ // IsOnCurve is documented to reject (0, 0), the conventional point at
+ // infinity, which however is accepted by pointFromAffine.
+ if x.Sign() == 0 && y.Sign() == 0 {
+ return false
+ }
+ _, err := curve.pointFromAffine(x, y)
+ return err == nil
+}
+
+func (curve *nistCurve[Point]) pointFromAffine(x, y *big.Int) (p Point, err error) {
+ // (0, 0) is by convention the point at infinity, which can't be represented
+ // in affine coordinates. See Issue 37294.
+ if x.Sign() == 0 && y.Sign() == 0 {
+ return curve.newPoint(), nil
+ }
+ // Reject values that would not get correctly encoded.
+ if x.Sign() < 0 || y.Sign() < 0 {
+ return p, errors.New("negative coordinate")
+ }
+ if x.BitLen() > curve.params.BitSize || y.BitLen() > curve.params.BitSize {
+ return p, errors.New("overflowing coordinate")
+ }
+ // Encode the coordinates and let SetBytes reject invalid points.
+ byteLen := (curve.params.BitSize + 7) / 8
+ buf := make([]byte, 1+2*byteLen)
+ buf[0] = 4 // uncompressed point
+ x.FillBytes(buf[1 : 1+byteLen])
+ y.FillBytes(buf[1+byteLen : 1+2*byteLen])
+ return curve.newPoint().SetBytes(buf)
+}
+
+func (curve *nistCurve[Point]) pointToAffine(p Point) (x, y *big.Int) {
+ out := p.Bytes()
+ if len(out) == 1 && out[0] == 0 {
+ // This is the encoding of the point at infinity, which the affine
+ // coordinates API represents as (0, 0) by convention.
+ return new(big.Int), new(big.Int)
+ }
+ byteLen := (curve.params.BitSize + 7) / 8
+ x = new(big.Int).SetBytes(out[1 : 1+byteLen])
+ y = new(big.Int).SetBytes(out[1+byteLen:])
+ return x, y
+}
+
+func (curve *nistCurve[Point]) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
+ p1, err := curve.pointFromAffine(x1, y1)
+ if err != nil {
+ panic("crypto/elliptic: Add was called on an invalid point")
+ }
+ p2, err := curve.pointFromAffine(x2, y2)
+ if err != nil {
+ panic("crypto/elliptic: Add was called on an invalid point")
+ }
+ return curve.pointToAffine(p1.Add(p1, p2))
+}
+
+func (curve *nistCurve[Point]) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
+ p, err := curve.pointFromAffine(x1, y1)
+ if err != nil {
+ panic("crypto/elliptic: Double was called on an invalid point")
+ }
+ return curve.pointToAffine(p.Double(p))
+}
+
+// normalizeScalar brings the scalar within the byte size of the order of the
+// curve, as expected by the nistec scalar multiplication functions.
+func (curve *nistCurve[Point]) normalizeScalar(scalar []byte) []byte {
+ byteSize := (curve.params.N.BitLen() + 7) / 8
+ if len(scalar) == byteSize {
+ return scalar
+ }
+ s := new(big.Int).SetBytes(scalar)
+ if len(scalar) > byteSize {
+ s.Mod(s, curve.params.N)
+ }
+ out := make([]byte, byteSize)
+ return s.FillBytes(out)
+}
+
+func (curve *nistCurve[Point]) ScalarMult(Bx, By *big.Int, scalar []byte) (*big.Int, *big.Int) {
+ p, err := curve.pointFromAffine(Bx, By)
+ if err != nil {
+ panic("crypto/elliptic: ScalarMult was called on an invalid point")
+ }
+ scalar = curve.normalizeScalar(scalar)
+ p, err = p.ScalarMult(p, scalar)
+ if err != nil {
+ panic("crypto/elliptic: nistec rejected normalized scalar")
+ }
+ return curve.pointToAffine(p)
+}
+
+func (curve *nistCurve[Point]) ScalarBaseMult(scalar []byte) (*big.Int, *big.Int) {
+ scalar = curve.normalizeScalar(scalar)
+ p, err := curve.newPoint().ScalarBaseMult(scalar)
+ if err != nil {
+ panic("crypto/elliptic: nistec rejected normalized scalar")
+ }
+ return curve.pointToAffine(p)
+}
+
+// CombinedMult returns [s1]G + [s2]P where G is the generator. It's used
+// through an interface upgrade in crypto/ecdsa.
+func (curve *nistCurve[Point]) CombinedMult(Px, Py *big.Int, s1, s2 []byte) (x, y *big.Int) {
+ s1 = curve.normalizeScalar(s1)
+ q, err := curve.newPoint().ScalarBaseMult(s1)
+ if err != nil {
+ panic("crypto/elliptic: nistec rejected normalized scalar")
+ }
+ p, err := curve.pointFromAffine(Px, Py)
+ if err != nil {
+ panic("crypto/elliptic: CombinedMult was called on an invalid point")
+ }
+ s2 = curve.normalizeScalar(s2)
+ p, err = p.ScalarMult(p, s2)
+ if err != nil {
+ panic("crypto/elliptic: nistec rejected normalized scalar")
+ }
+ return curve.pointToAffine(p.Add(p, q))
+}
+
+func (curve *nistCurve[Point]) Unmarshal(data []byte) (x, y *big.Int) {
+ if len(data) == 0 || data[0] != 4 {
+ return nil, nil
+ }
+ // Use SetBytes to check that data encodes a valid point.
+ _, err := curve.newPoint().SetBytes(data)
+ if err != nil {
+ return nil, nil
+ }
+ // We don't use pointToAffine because it involves an expensive field
+ // inversion to convert from Jacobian to affine coordinates, which we
+ // already have.
+ byteLen := (curve.params.BitSize + 7) / 8
+ x = new(big.Int).SetBytes(data[1 : 1+byteLen])
+ y = new(big.Int).SetBytes(data[1+byteLen:])
+ return x, y
+}
+
+func (curve *nistCurve[Point]) UnmarshalCompressed(data []byte) (x, y *big.Int) {
+ if len(data) == 0 || (data[0] != 2 && data[0] != 3) {
+ return nil, nil
+ }
+ p, err := curve.newPoint().SetBytes(data)
+ if err != nil {
+ return nil, nil
+ }
+ return curve.pointToAffine(p)
+}
+
+func bigFromDecimal(s string) *big.Int {
+ b, ok := new(big.Int).SetString(s, 10)
+ if !ok {
+ panic("crypto/elliptic: internal error: invalid encoding")
+ }
+ return b
+}
+
+func bigFromHex(s string) *big.Int {
+ b, ok := new(big.Int).SetString(s, 16)
+ if !ok {
+ panic("crypto/elliptic: internal error: invalid encoding")
+ }
+ return b
+}
diff --git a/src/crypto/elliptic/nistec_p256.go b/src/crypto/elliptic/nistec_p256.go
new file mode 100644
index 0000000..304f8f2
--- /dev/null
+++ b/src/crypto/elliptic/nistec_p256.go
@@ -0,0 +1,29 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build amd64 || arm64
+
+package elliptic
+
+import (
+ "crypto/internal/nistec"
+ "math/big"
+)
+
+func (c p256Curve) Inverse(k *big.Int) *big.Int {
+ if k.Sign() < 0 {
+ // This should never happen.
+ k = new(big.Int).Neg(k)
+ }
+ if k.Cmp(c.params.N) >= 0 {
+ // This should never happen.
+ k = new(big.Int).Mod(k, c.params.N)
+ }
+ scalar := k.FillBytes(make([]byte, 32))
+ inverse, err := nistec.P256OrdInverse(scalar)
+ if err != nil {
+ panic("crypto/elliptic: nistec rejected normalized scalar")
+ }
+ return new(big.Int).SetBytes(inverse)
+}
diff --git a/src/crypto/elliptic/p224_test.go b/src/crypto/elliptic/p224_test.go
new file mode 100644
index 0000000..7971f63
--- /dev/null
+++ b/src/crypto/elliptic/p224_test.go
@@ -0,0 +1,325 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package elliptic
+
+import (
+ "encoding/hex"
+ "fmt"
+ "math/big"
+ "testing"
+)
+
+type baseMultTest struct {
+ k string
+ x, y string
+}
+
+var p224BaseMultTests = []baseMultTest{
+ {
+ "1",
+ "b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
+ "bd376388b5f723fb4c22dfe6cd4375a05a07476444d5819985007e34",
+ },
+ {
+ "2",
+ "706a46dc76dcb76798e60e6d89474788d16dc18032d268fd1a704fa6",
+ "1c2b76a7bc25e7702a704fa986892849fca629487acf3709d2e4e8bb",
+ },
+ {
+ "3",
+ "df1b1d66a551d0d31eff822558b9d2cc75c2180279fe0d08fd896d04",
+ "a3f7f03cadd0be444c0aa56830130ddf77d317344e1af3591981a925",
+ },
+ {
+ "4",
+ "ae99feebb5d26945b54892092a8aee02912930fa41cd114e40447301",
+ "482580a0ec5bc47e88bc8c378632cd196cb3fa058a7114eb03054c9",
+ },
+ {
+ "5",
+ "31c49ae75bce7807cdff22055d94ee9021fedbb5ab51c57526f011aa",
+ "27e8bff1745635ec5ba0c9f1c2ede15414c6507d29ffe37e790a079b",
+ },
+ {
+ "6",
+ "1f2483f82572251fca975fea40db821df8ad82a3c002ee6c57112408",
+ "89faf0ccb750d99b553c574fad7ecfb0438586eb3952af5b4b153c7e",
+ },
+ {
+ "7",
+ "db2f6be630e246a5cf7d99b85194b123d487e2d466b94b24a03c3e28",
+ "f3a30085497f2f611ee2517b163ef8c53b715d18bb4e4808d02b963",
+ },
+ {
+ "8",
+ "858e6f9cc6c12c31f5df124aa77767b05c8bc021bd683d2b55571550",
+ "46dcd3ea5c43898c5c5fc4fdac7db39c2f02ebee4e3541d1e78047a",
+ },
+ {
+ "9",
+ "2fdcccfee720a77ef6cb3bfbb447f9383117e3daa4a07e36ed15f78d",
+ "371732e4f41bf4f7883035e6a79fcedc0e196eb07b48171697517463",
+ },
+ {
+ "10",
+ "aea9e17a306517eb89152aa7096d2c381ec813c51aa880e7bee2c0fd",
+ "39bb30eab337e0a521b6cba1abe4b2b3a3e524c14a3fe3eb116b655f",
+ },
+ {
+ "11",
+ "ef53b6294aca431f0f3c22dc82eb9050324f1d88d377e716448e507c",
+ "20b510004092e96636cfb7e32efded8265c266dfb754fa6d6491a6da",
+ },
+ {
+ "12",
+ "6e31ee1dc137f81b056752e4deab1443a481033e9b4c93a3044f4f7a",
+ "207dddf0385bfdeab6e9acda8da06b3bbef224a93ab1e9e036109d13",
+ },
+ {
+ "13",
+ "34e8e17a430e43289793c383fac9774247b40e9ebd3366981fcfaeca",
+ "252819f71c7fb7fbcb159be337d37d3336d7feb963724fdfb0ecb767",
+ },
+ {
+ "14",
+ "a53640c83dc208603ded83e4ecf758f24c357d7cf48088b2ce01e9fa",
+ "d5814cd724199c4a5b974a43685fbf5b8bac69459c9469bc8f23ccaf",
+ },
+ {
+ "15",
+ "baa4d8635511a7d288aebeedd12ce529ff102c91f97f867e21916bf9",
+ "979a5f4759f80f4fb4ec2e34f5566d595680a11735e7b61046127989",
+ },
+ {
+ "16",
+ "b6ec4fe1777382404ef679997ba8d1cc5cd8e85349259f590c4c66d",
+ "3399d464345906b11b00e363ef429221f2ec720d2f665d7dead5b482",
+ },
+ {
+ "17",
+ "b8357c3a6ceef288310e17b8bfeff9200846ca8c1942497c484403bc",
+ "ff149efa6606a6bd20ef7d1b06bd92f6904639dce5174db6cc554a26",
+ },
+ {
+ "18",
+ "c9ff61b040874c0568479216824a15eab1a838a797d189746226e4cc",
+ "ea98d60e5ffc9b8fcf999fab1df7e7ef7084f20ddb61bb045a6ce002",
+ },
+ {
+ "19",
+ "a1e81c04f30ce201c7c9ace785ed44cc33b455a022f2acdbc6cae83c",
+ "dcf1f6c3db09c70acc25391d492fe25b4a180babd6cea356c04719cd",
+ },
+ {
+ "20",
+ "fcc7f2b45df1cd5a3c0c0731ca47a8af75cfb0347e8354eefe782455",
+ "d5d7110274cba7cdee90e1a8b0d394c376a5573db6be0bf2747f530",
+ },
+ {
+ "112233445566778899",
+ "61f077c6f62ed802dad7c2f38f5c67f2cc453601e61bd076bb46179e",
+ "2272f9e9f5933e70388ee652513443b5e289dd135dcc0d0299b225e4",
+ },
+ {
+ "112233445566778899112233445566778899",
+ "29895f0af496bfc62b6ef8d8a65c88c613949b03668aab4f0429e35",
+ "3ea6e53f9a841f2019ec24bde1a75677aa9b5902e61081c01064de93",
+ },
+ {
+ "6950511619965839450988900688150712778015737983940691968051900319680",
+ "ab689930bcae4a4aa5f5cb085e823e8ae30fd365eb1da4aba9cf0379",
+ "3345a121bbd233548af0d210654eb40bab788a03666419be6fbd34e7",
+ },
+ {
+ "13479972933410060327035789020509431695094902435494295338570602119423",
+ "bdb6a8817c1f89da1c2f3dd8e97feb4494f2ed302a4ce2bc7f5f4025",
+ "4c7020d57c00411889462d77a5438bb4e97d177700bf7243a07f1680",
+ },
+ {
+ "13479971751745682581351455311314208093898607229429740618390390702079",
+ "d58b61aa41c32dd5eba462647dba75c5d67c83606c0af2bd928446a9",
+ "d24ba6a837be0460dd107ae77725696d211446c5609b4595976b16bd",
+ },
+ {
+ "13479972931865328106486971546324465392952975980343228160962702868479",
+ "dc9fa77978a005510980e929a1485f63716df695d7a0c18bb518df03",
+ "ede2b016f2ddffc2a8c015b134928275ce09e5661b7ab14ce0d1d403",
+ },
+ {
+ "11795773708834916026404142434151065506931607341523388140225443265536",
+ "499d8b2829cfb879c901f7d85d357045edab55028824d0f05ba279ba",
+ "bf929537b06e4015919639d94f57838fa33fc3d952598dcdbb44d638",
+ },
+ {
+ "784254593043826236572847595991346435467177662189391577090",
+ "8246c999137186632c5f9eddf3b1b0e1764c5e8bd0e0d8a554b9cb77",
+ "e80ed8660bc1cb17ac7d845be40a7a022d3306f116ae9f81fea65947",
+ },
+ {
+ "13479767645505654746623887797783387853576174193480695826442858012671",
+ "6670c20afcceaea672c97f75e2e9dd5c8460e54bb38538ebb4bd30eb",
+ "f280d8008d07a4caf54271f993527d46ff3ff46fd1190a3f1faa4f74",
+ },
+ {
+ "205688069665150753842126177372015544874550518966168735589597183",
+ "eca934247425cfd949b795cb5ce1eff401550386e28d1a4c5a8eb",
+ "d4c01040dba19628931bc8855370317c722cbd9ca6156985f1c2e9ce",
+ },
+ {
+ "13479966930919337728895168462090683249159702977113823384618282123295",
+ "ef353bf5c73cd551b96d596fbc9a67f16d61dd9fe56af19de1fba9cd",
+ "21771b9cdce3e8430c09b3838be70b48c21e15bc09ee1f2d7945b91f",
+ },
+ {
+ "50210731791415612487756441341851895584393717453129007497216",
+ "4036052a3091eb481046ad3289c95d3ac905ca0023de2c03ecd451cf",
+ "d768165a38a2b96f812586a9d59d4136035d9c853a5bf2e1c86a4993",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368041",
+ "fcc7f2b45df1cd5a3c0c0731ca47a8af75cfb0347e8354eefe782455",
+ "f2a28eefd8b345832116f1e574f2c6b2c895aa8c24941f40d8b80ad1",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368042",
+ "a1e81c04f30ce201c7c9ace785ed44cc33b455a022f2acdbc6cae83c",
+ "230e093c24f638f533dac6e2b6d01da3b5e7f45429315ca93fb8e634",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368043",
+ "c9ff61b040874c0568479216824a15eab1a838a797d189746226e4cc",
+ "156729f1a003647030666054e208180f8f7b0df2249e44fba5931fff",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368044",
+ "b8357c3a6ceef288310e17b8bfeff9200846ca8c1942497c484403bc",
+ "eb610599f95942df1082e4f9426d086fb9c6231ae8b24933aab5db",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368045",
+ "b6ec4fe1777382404ef679997ba8d1cc5cd8e85349259f590c4c66d",
+ "cc662b9bcba6f94ee4ff1c9c10bd6ddd0d138df2d099a282152a4b7f",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368046",
+ "baa4d8635511a7d288aebeedd12ce529ff102c91f97f867e21916bf9",
+ "6865a0b8a607f0b04b13d1cb0aa992a5a97f5ee8ca1849efb9ed8678",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368047",
+ "a53640c83dc208603ded83e4ecf758f24c357d7cf48088b2ce01e9fa",
+ "2a7eb328dbe663b5a468b5bc97a040a3745396ba636b964370dc3352",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368048",
+ "34e8e17a430e43289793c383fac9774247b40e9ebd3366981fcfaeca",
+ "dad7e608e380480434ea641cc82c82cbc92801469c8db0204f13489a",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368049",
+ "6e31ee1dc137f81b056752e4deab1443a481033e9b4c93a3044f4f7a",
+ "df82220fc7a4021549165325725f94c3410ddb56c54e161fc9ef62ee",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368050",
+ "ef53b6294aca431f0f3c22dc82eb9050324f1d88d377e716448e507c",
+ "df4aefffbf6d1699c930481cd102127c9a3d992048ab05929b6e5927",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368051",
+ "aea9e17a306517eb89152aa7096d2c381ec813c51aa880e7bee2c0fd",
+ "c644cf154cc81f5ade49345e541b4d4b5c1adb3eb5c01c14ee949aa2",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368052",
+ "2fdcccfee720a77ef6cb3bfbb447f9383117e3daa4a07e36ed15f78d",
+ "c8e8cd1b0be40b0877cfca1958603122f1e6914f84b7e8e968ae8b9e",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368053",
+ "858e6f9cc6c12c31f5df124aa77767b05c8bc021bd683d2b55571550",
+ "fb9232c15a3bc7673a3a03b0253824c53d0fd1411b1cabe2e187fb87",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368054",
+ "db2f6be630e246a5cf7d99b85194b123d487e2d466b94b24a03c3e28",
+ "f0c5cff7ab680d09ee11dae84e9c1072ac48ea2e744b1b7f72fd469e",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368055",
+ "1f2483f82572251fca975fea40db821df8ad82a3c002ee6c57112408",
+ "76050f3348af2664aac3a8b05281304ebc7a7914c6ad50a4b4eac383",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368056",
+ "31c49ae75bce7807cdff22055d94ee9021fedbb5ab51c57526f011aa",
+ "d817400e8ba9ca13a45f360e3d121eaaeb39af82d6001c8186f5f866",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368057",
+ "ae99feebb5d26945b54892092a8aee02912930fa41cd114e40447301",
+ "fb7da7f5f13a43b81774373c879cd32d6934c05fa758eeb14fcfab38",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368058",
+ "df1b1d66a551d0d31eff822558b9d2cc75c2180279fe0d08fd896d04",
+ "5c080fc3522f41bbb3f55a97cfecf21f882ce8cbb1e50ca6e67e56dc",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368059",
+ "706a46dc76dcb76798e60e6d89474788d16dc18032d268fd1a704fa6",
+ "e3d4895843da188fd58fb0567976d7b50359d6b78530c8f62d1b1746",
+ },
+ {
+ "26959946667150639794667015087019625940457807714424391721682722368060",
+ "b70e0cbd6bb4bf7f321390b94a03c1d356c21122343280d6115c1d21",
+ "42c89c774a08dc04b3dd201932bc8a5ea5f8b89bbb2a7e667aff81cd",
+ },
+}
+
+func TestP224BaseMult(t *testing.T) {
+ p224 := P224()
+ for i, e := range p224BaseMultTests {
+ k, ok := new(big.Int).SetString(e.k, 10)
+ if !ok {
+ t.Errorf("%d: bad value for k: %s", i, e.k)
+ }
+ x, y := p224.ScalarBaseMult(k.Bytes())
+ if fmt.Sprintf("%x", x) != e.x || fmt.Sprintf("%x", y) != e.y {
+ t.Errorf("%d: bad output for k=%s: got (%x, %x), want (%s, %s)", i, e.k, x, y, e.x, e.y)
+ }
+ if testing.Short() && i > 5 {
+ break
+ }
+ }
+}
+
+func TestP224GenericBaseMult(t *testing.T) {
+ // We use the P224 CurveParams directly in order to test the generic implementation.
+ p224 := genericParamsForCurve(P224())
+ for i, e := range p224BaseMultTests {
+ k, ok := new(big.Int).SetString(e.k, 10)
+ if !ok {
+ t.Errorf("%d: bad value for k: %s", i, e.k)
+ }
+ x, y := p224.ScalarBaseMult(k.Bytes())
+ if fmt.Sprintf("%x", x) != e.x || fmt.Sprintf("%x", y) != e.y {
+ t.Errorf("%d: bad output for k=%s: got (%x, %x), want (%s, %s)", i, e.k, x, y, e.x, e.y)
+ }
+ if testing.Short() && i > 5 {
+ break
+ }
+ }
+}
+
+func TestP224Overflow(t *testing.T) {
+ // This tests for a specific bug in the P224 implementation.
+ p224 := P224()
+ pointData, _ := hex.DecodeString("049B535B45FB0A2072398A6831834624C7E32CCFD5A4B933BCEAF77F1DD945E08BBE5178F5EDF5E733388F196D2A631D2E075BB16CBFEEA15B")
+ x, y := Unmarshal(p224, pointData)
+ if !p224.IsOnCurve(x, y) {
+ t.Error("P224 failed to validate a correct point")
+ }
+}
diff --git a/src/crypto/elliptic/p256_test.go b/src/crypto/elliptic/p256_test.go
new file mode 100644
index 0000000..a607766
--- /dev/null
+++ b/src/crypto/elliptic/p256_test.go
@@ -0,0 +1,152 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package elliptic
+
+import (
+ "math/big"
+ "testing"
+)
+
+type scalarMultTest struct {
+ k string
+ xIn, yIn string
+ xOut, yOut string
+}
+
+var p256MultTests = []scalarMultTest{
+ {
+ "2a265f8bcbdcaf94d58519141e578124cb40d64a501fba9c11847b28965bc737",
+ "023819813ac969847059028ea88a1f30dfbcde03fc791d3a252c6b41211882ea",
+ "f93e4ae433cc12cf2a43fc0ef26400c0e125508224cdb649380f25479148a4ad",
+ "4d4de80f1534850d261075997e3049321a0864082d24a917863366c0724f5ae3",
+ "a22d2b7f7818a3563e0f7a76c9bf0921ac55e06e2e4d11795b233824b1db8cc0",
+ },
+ {
+ "313f72ff9fe811bf573176231b286a3bdb6f1b14e05c40146590727a71c3bccd",
+ "cc11887b2d66cbae8f4d306627192522932146b42f01d3c6f92bd5c8ba739b06",
+ "a2f08a029cd06b46183085bae9248b0ed15b70280c7ef13a457f5af382426031",
+ "831c3f6b5f762d2f461901577af41354ac5f228c2591f84f8a6e51e2e3f17991",
+ "93f90934cd0ef2c698cc471c60a93524e87ab31ca2412252337f364513e43684",
+ },
+}
+
+func TestP256BaseMult(t *testing.T) {
+ p256 := P256()
+ p256Generic := genericParamsForCurve(p256)
+
+ scalars := make([]*big.Int, 0, len(p224BaseMultTests)+1)
+ for _, e := range p224BaseMultTests {
+ k, _ := new(big.Int).SetString(e.k, 10)
+ scalars = append(scalars, k)
+ }
+ k := new(big.Int).SetInt64(1)
+ k.Lsh(k, 500)
+ scalars = append(scalars, k)
+
+ for i, k := range scalars {
+ x, y := p256.ScalarBaseMult(k.Bytes())
+ x2, y2 := p256Generic.ScalarBaseMult(k.Bytes())
+ if x.Cmp(x2) != 0 || y.Cmp(y2) != 0 {
+ t.Errorf("#%d: got (%x, %x), want (%x, %x)", i, x, y, x2, y2)
+ }
+
+ if testing.Short() && i > 5 {
+ break
+ }
+ }
+}
+
+func TestP256Mult(t *testing.T) {
+ p256 := P256()
+ for i, e := range p256MultTests {
+ x, _ := new(big.Int).SetString(e.xIn, 16)
+ y, _ := new(big.Int).SetString(e.yIn, 16)
+ k, _ := new(big.Int).SetString(e.k, 16)
+ expectedX, _ := new(big.Int).SetString(e.xOut, 16)
+ expectedY, _ := new(big.Int).SetString(e.yOut, 16)
+
+ xx, yy := p256.ScalarMult(x, y, k.Bytes())
+ if xx.Cmp(expectedX) != 0 || yy.Cmp(expectedY) != 0 {
+ t.Errorf("#%d: got (%x, %x), want (%x, %x)", i, xx, yy, expectedX, expectedY)
+ }
+ }
+}
+
+type synthCombinedMult struct {
+ Curve
+}
+
+func (s synthCombinedMult) CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int) {
+ x1, y1 := s.ScalarBaseMult(baseScalar)
+ x2, y2 := s.ScalarMult(bigX, bigY, scalar)
+ return s.Add(x1, y1, x2, y2)
+}
+
+func TestP256CombinedMult(t *testing.T) {
+ type combinedMult interface {
+ Curve
+ CombinedMult(bigX, bigY *big.Int, baseScalar, scalar []byte) (x, y *big.Int)
+ }
+
+ p256, ok := P256().(combinedMult)
+ if !ok {
+ p256 = &synthCombinedMult{P256()}
+ }
+
+ gx := p256.Params().Gx
+ gy := p256.Params().Gy
+
+ zero := make([]byte, 32)
+ one := make([]byte, 32)
+ one[31] = 1
+ two := make([]byte, 32)
+ two[31] = 2
+
+ // 0×G + 0×G = ∞
+ x, y := p256.CombinedMult(gx, gy, zero, zero)
+ if x.Sign() != 0 || y.Sign() != 0 {
+ t.Errorf("0×G + 0×G = (%d, %d), should be ∞", x, y)
+ }
+
+ // 1×G + 0×G = G
+ x, y = p256.CombinedMult(gx, gy, one, zero)
+ if x.Cmp(gx) != 0 || y.Cmp(gy) != 0 {
+ t.Errorf("1×G + 0×G = (%d, %d), should be (%d, %d)", x, y, gx, gy)
+ }
+
+ // 0×G + 1×G = G
+ x, y = p256.CombinedMult(gx, gy, zero, one)
+ if x.Cmp(gx) != 0 || y.Cmp(gy) != 0 {
+ t.Errorf("0×G + 1×G = (%d, %d), should be (%d, %d)", x, y, gx, gy)
+ }
+
+ // 1×G + 1×G = 2×G
+ x, y = p256.CombinedMult(gx, gy, one, one)
+ ggx, ggy := p256.ScalarBaseMult(two)
+ if x.Cmp(ggx) != 0 || y.Cmp(ggy) != 0 {
+ t.Errorf("1×G + 1×G = (%d, %d), should be (%d, %d)", x, y, ggx, ggy)
+ }
+
+ minusOne := new(big.Int).Sub(p256.Params().N, big.NewInt(1))
+ // 1×G + (-1)×G = ∞
+ x, y = p256.CombinedMult(gx, gy, one, minusOne.Bytes())
+ if x.Sign() != 0 || y.Sign() != 0 {
+ t.Errorf("1×G + (-1)×G = (%d, %d), should be ∞", x, y)
+ }
+}
+
+func TestIssue52075(t *testing.T) {
+ Gx, Gy := P256().Params().Gx, P256().Params().Gy
+ scalar := make([]byte, 33)
+ scalar[32] = 1
+ x, y := P256().ScalarBaseMult(scalar)
+ if x.Cmp(Gx) != 0 || y.Cmp(Gy) != 0 {
+ t.Errorf("unexpected output (%v,%v)", x, y)
+ }
+ x, y = P256().ScalarMult(Gx, Gy, scalar)
+ if x.Cmp(Gx) != 0 || y.Cmp(Gy) != 0 {
+ t.Errorf("unexpected output (%v,%v)", x, y)
+ }
+}
diff --git a/src/crypto/elliptic/params.go b/src/crypto/elliptic/params.go
new file mode 100644
index 0000000..c4e9784
--- /dev/null
+++ b/src/crypto/elliptic/params.go
@@ -0,0 +1,333 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package elliptic
+
+import "math/big"
+
+// CurveParams contains the parameters of an elliptic curve and also provides
+// a generic, non-constant time implementation of Curve.
+//
+// Note: Custom curves (those not returned by P224(), P256(), P384(), and P521())
+// are not guaranteed to provide any security property.
+type CurveParams struct {
+ P *big.Int // the order of the underlying field
+ N *big.Int // the order of the base point
+ B *big.Int // the constant of the curve equation
+ Gx, Gy *big.Int // (x,y) of the base point
+ BitSize int // the size of the underlying field
+ Name string // the canonical name of the curve
+}
+
+func (curve *CurveParams) Params() *CurveParams {
+ return curve
+}
+
+// CurveParams operates, internally, on Jacobian coordinates. For a given
+// (x, y) position on the curve, the Jacobian coordinates are (x1, y1, z1)
+// where x = x1/z1² and y = y1/z1³. The greatest speedups come when the whole
+// calculation can be performed within the transform (as in ScalarMult and
+// ScalarBaseMult). But even for Add and Double, it's faster to apply and
+// reverse the transform than to operate in affine coordinates.
+
+// polynomial returns x³ - 3x + b.
+func (curve *CurveParams) polynomial(x *big.Int) *big.Int {
+ x3 := new(big.Int).Mul(x, x)
+ x3.Mul(x3, x)
+
+ threeX := new(big.Int).Lsh(x, 1)
+ threeX.Add(threeX, x)
+
+ x3.Sub(x3, threeX)
+ x3.Add(x3, curve.B)
+ x3.Mod(x3, curve.P)
+
+ return x3
+}
+
+// IsOnCurve implements Curve.IsOnCurve.
+//
+// Note: the CurveParams methods are not guaranteed to
+// provide any security property. For ECDH, use the crypto/ecdh package.
+// For ECDSA, use the crypto/ecdsa package with a Curve value returned directly
+// from P224(), P256(), P384(), or P521().
+func (curve *CurveParams) IsOnCurve(x, y *big.Int) bool {
+ // If there is a dedicated constant-time implementation for this curve operation,
+ // use that instead of the generic one.
+ if specific, ok := matchesSpecificCurve(curve); ok {
+ return specific.IsOnCurve(x, y)
+ }
+
+ if x.Sign() < 0 || x.Cmp(curve.P) >= 0 ||
+ y.Sign() < 0 || y.Cmp(curve.P) >= 0 {
+ return false
+ }
+
+ // y² = x³ - 3x + b
+ y2 := new(big.Int).Mul(y, y)
+ y2.Mod(y2, curve.P)
+
+ return curve.polynomial(x).Cmp(y2) == 0
+}
+
+// zForAffine returns a Jacobian Z value for the affine point (x, y). If x and
+// y are zero, it assumes that they represent the point at infinity because (0,
+// 0) is not on the any of the curves handled here.
+func zForAffine(x, y *big.Int) *big.Int {
+ z := new(big.Int)
+ if x.Sign() != 0 || y.Sign() != 0 {
+ z.SetInt64(1)
+ }
+ return z
+}
+
+// affineFromJacobian reverses the Jacobian transform. See the comment at the
+// top of the file. If the point is ∞ it returns 0, 0.
+func (curve *CurveParams) affineFromJacobian(x, y, z *big.Int) (xOut, yOut *big.Int) {
+ if z.Sign() == 0 {
+ return new(big.Int), new(big.Int)
+ }
+
+ zinv := new(big.Int).ModInverse(z, curve.P)
+ zinvsq := new(big.Int).Mul(zinv, zinv)
+
+ xOut = new(big.Int).Mul(x, zinvsq)
+ xOut.Mod(xOut, curve.P)
+ zinvsq.Mul(zinvsq, zinv)
+ yOut = new(big.Int).Mul(y, zinvsq)
+ yOut.Mod(yOut, curve.P)
+ return
+}
+
+// Add implements Curve.Add.
+//
+// Note: the CurveParams methods are not guaranteed to
+// provide any security property. For ECDH, use the crypto/ecdh package.
+// For ECDSA, use the crypto/ecdsa package with a Curve value returned directly
+// from P224(), P256(), P384(), or P521().
+func (curve *CurveParams) Add(x1, y1, x2, y2 *big.Int) (*big.Int, *big.Int) {
+ // If there is a dedicated constant-time implementation for this curve operation,
+ // use that instead of the generic one.
+ if specific, ok := matchesSpecificCurve(curve); ok {
+ return specific.Add(x1, y1, x2, y2)
+ }
+ panicIfNotOnCurve(curve, x1, y1)
+ panicIfNotOnCurve(curve, x2, y2)
+
+ z1 := zForAffine(x1, y1)
+ z2 := zForAffine(x2, y2)
+ return curve.affineFromJacobian(curve.addJacobian(x1, y1, z1, x2, y2, z2))
+}
+
+// addJacobian takes two points in Jacobian coordinates, (x1, y1, z1) and
+// (x2, y2, z2) and returns their sum, also in Jacobian form.
+func (curve *CurveParams) addJacobian(x1, y1, z1, x2, y2, z2 *big.Int) (*big.Int, *big.Int, *big.Int) {
+ // See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
+ x3, y3, z3 := new(big.Int), new(big.Int), new(big.Int)
+ if z1.Sign() == 0 {
+ x3.Set(x2)
+ y3.Set(y2)
+ z3.Set(z2)
+ return x3, y3, z3
+ }
+ if z2.Sign() == 0 {
+ x3.Set(x1)
+ y3.Set(y1)
+ z3.Set(z1)
+ return x3, y3, z3
+ }
+
+ z1z1 := new(big.Int).Mul(z1, z1)
+ z1z1.Mod(z1z1, curve.P)
+ z2z2 := new(big.Int).Mul(z2, z2)
+ z2z2.Mod(z2z2, curve.P)
+
+ u1 := new(big.Int).Mul(x1, z2z2)
+ u1.Mod(u1, curve.P)
+ u2 := new(big.Int).Mul(x2, z1z1)
+ u2.Mod(u2, curve.P)
+ h := new(big.Int).Sub(u2, u1)
+ xEqual := h.Sign() == 0
+ if h.Sign() == -1 {
+ h.Add(h, curve.P)
+ }
+ i := new(big.Int).Lsh(h, 1)
+ i.Mul(i, i)
+ j := new(big.Int).Mul(h, i)
+
+ s1 := new(big.Int).Mul(y1, z2)
+ s1.Mul(s1, z2z2)
+ s1.Mod(s1, curve.P)
+ s2 := new(big.Int).Mul(y2, z1)
+ s2.Mul(s2, z1z1)
+ s2.Mod(s2, curve.P)
+ r := new(big.Int).Sub(s2, s1)
+ if r.Sign() == -1 {
+ r.Add(r, curve.P)
+ }
+ yEqual := r.Sign() == 0
+ if xEqual && yEqual {
+ return curve.doubleJacobian(x1, y1, z1)
+ }
+ r.Lsh(r, 1)
+ v := new(big.Int).Mul(u1, i)
+
+ x3.Set(r)
+ x3.Mul(x3, x3)
+ x3.Sub(x3, j)
+ x3.Sub(x3, v)
+ x3.Sub(x3, v)
+ x3.Mod(x3, curve.P)
+
+ y3.Set(r)
+ v.Sub(v, x3)
+ y3.Mul(y3, v)
+ s1.Mul(s1, j)
+ s1.Lsh(s1, 1)
+ y3.Sub(y3, s1)
+ y3.Mod(y3, curve.P)
+
+ z3.Add(z1, z2)
+ z3.Mul(z3, z3)
+ z3.Sub(z3, z1z1)
+ z3.Sub(z3, z2z2)
+ z3.Mul(z3, h)
+ z3.Mod(z3, curve.P)
+
+ return x3, y3, z3
+}
+
+// Double implements Curve.Double.
+//
+// Note: the CurveParams methods are not guaranteed to
+// provide any security property. For ECDH, use the crypto/ecdh package.
+// For ECDSA, use the crypto/ecdsa package with a Curve value returned directly
+// from P224(), P256(), P384(), or P521().
+func (curve *CurveParams) Double(x1, y1 *big.Int) (*big.Int, *big.Int) {
+ // If there is a dedicated constant-time implementation for this curve operation,
+ // use that instead of the generic one.
+ if specific, ok := matchesSpecificCurve(curve); ok {
+ return specific.Double(x1, y1)
+ }
+ panicIfNotOnCurve(curve, x1, y1)
+
+ z1 := zForAffine(x1, y1)
+ return curve.affineFromJacobian(curve.doubleJacobian(x1, y1, z1))
+}
+
+// doubleJacobian takes a point in Jacobian coordinates, (x, y, z), and
+// returns its double, also in Jacobian form.
+func (curve *CurveParams) doubleJacobian(x, y, z *big.Int) (*big.Int, *big.Int, *big.Int) {
+ // See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2001-b
+ delta := new(big.Int).Mul(z, z)
+ delta.Mod(delta, curve.P)
+ gamma := new(big.Int).Mul(y, y)
+ gamma.Mod(gamma, curve.P)
+ alpha := new(big.Int).Sub(x, delta)
+ if alpha.Sign() == -1 {
+ alpha.Add(alpha, curve.P)
+ }
+ alpha2 := new(big.Int).Add(x, delta)
+ alpha.Mul(alpha, alpha2)
+ alpha2.Set(alpha)
+ alpha.Lsh(alpha, 1)
+ alpha.Add(alpha, alpha2)
+
+ beta := alpha2.Mul(x, gamma)
+
+ x3 := new(big.Int).Mul(alpha, alpha)
+ beta8 := new(big.Int).Lsh(beta, 3)
+ beta8.Mod(beta8, curve.P)
+ x3.Sub(x3, beta8)
+ if x3.Sign() == -1 {
+ x3.Add(x3, curve.P)
+ }
+ x3.Mod(x3, curve.P)
+
+ z3 := new(big.Int).Add(y, z)
+ z3.Mul(z3, z3)
+ z3.Sub(z3, gamma)
+ if z3.Sign() == -1 {
+ z3.Add(z3, curve.P)
+ }
+ z3.Sub(z3, delta)
+ if z3.Sign() == -1 {
+ z3.Add(z3, curve.P)
+ }
+ z3.Mod(z3, curve.P)
+
+ beta.Lsh(beta, 2)
+ beta.Sub(beta, x3)
+ if beta.Sign() == -1 {
+ beta.Add(beta, curve.P)
+ }
+ y3 := alpha.Mul(alpha, beta)
+
+ gamma.Mul(gamma, gamma)
+ gamma.Lsh(gamma, 3)
+ gamma.Mod(gamma, curve.P)
+
+ y3.Sub(y3, gamma)
+ if y3.Sign() == -1 {
+ y3.Add(y3, curve.P)
+ }
+ y3.Mod(y3, curve.P)
+
+ return x3, y3, z3
+}
+
+// ScalarMult implements Curve.ScalarMult.
+//
+// Note: the CurveParams methods are not guaranteed to
+// provide any security property. For ECDH, use the crypto/ecdh package.
+// For ECDSA, use the crypto/ecdsa package with a Curve value returned directly
+// from P224(), P256(), P384(), or P521().
+func (curve *CurveParams) ScalarMult(Bx, By *big.Int, k []byte) (*big.Int, *big.Int) {
+ // If there is a dedicated constant-time implementation for this curve operation,
+ // use that instead of the generic one.
+ if specific, ok := matchesSpecificCurve(curve); ok {
+ return specific.ScalarMult(Bx, By, k)
+ }
+ panicIfNotOnCurve(curve, Bx, By)
+
+ Bz := new(big.Int).SetInt64(1)
+ x, y, z := new(big.Int), new(big.Int), new(big.Int)
+
+ for _, byte := range k {
+ for bitNum := 0; bitNum < 8; bitNum++ {
+ x, y, z = curve.doubleJacobian(x, y, z)
+ if byte&0x80 == 0x80 {
+ x, y, z = curve.addJacobian(Bx, By, Bz, x, y, z)
+ }
+ byte <<= 1
+ }
+ }
+
+ return curve.affineFromJacobian(x, y, z)
+}
+
+// ScalarBaseMult implements Curve.ScalarBaseMult.
+//
+// Note: the CurveParams methods are not guaranteed to
+// provide any security property. For ECDH, use the crypto/ecdh package.
+// For ECDSA, use the crypto/ecdsa package with a Curve value returned directly
+// from P224(), P256(), P384(), or P521().
+func (curve *CurveParams) ScalarBaseMult(k []byte) (*big.Int, *big.Int) {
+ // If there is a dedicated constant-time implementation for this curve operation,
+ // use that instead of the generic one.
+ if specific, ok := matchesSpecificCurve(curve); ok {
+ return specific.ScalarBaseMult(k)
+ }
+
+ return curve.ScalarMult(curve.Gx, curve.Gy, k)
+}
+
+func matchesSpecificCurve(params *CurveParams) (Curve, bool) {
+ for _, c := range []Curve{p224, p256, p384, p521} {
+ if params == c.Params() {
+ return c, true
+ }
+ }
+ return nil, false
+}
diff --git a/src/crypto/hmac/hmac.go b/src/crypto/hmac/hmac.go
new file mode 100644
index 0000000..ed3ebc0
--- /dev/null
+++ b/src/crypto/hmac/hmac.go
@@ -0,0 +1,180 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+/*
+Package hmac implements the Keyed-Hash Message Authentication Code (HMAC) as
+defined in U.S. Federal Information Processing Standards Publication 198.
+An HMAC is a cryptographic hash that uses a key to sign a message.
+The receiver verifies the hash by recomputing it using the same key.
+
+Receivers should be careful to use Equal to compare MACs in order to avoid
+timing side-channels:
+
+ // ValidMAC reports whether messageMAC is a valid HMAC tag for message.
+ func ValidMAC(message, messageMAC, key []byte) bool {
+ mac := hmac.New(sha256.New, key)
+ mac.Write(message)
+ expectedMAC := mac.Sum(nil)
+ return hmac.Equal(messageMAC, expectedMAC)
+ }
+*/
+package hmac
+
+import (
+ "crypto/internal/boring"
+ "crypto/subtle"
+ "hash"
+)
+
+// FIPS 198-1:
+// https://csrc.nist.gov/publications/fips/fips198-1/FIPS-198-1_final.pdf
+
+// key is zero padded to the block size of the hash function
+// ipad = 0x36 byte repeated for key length
+// opad = 0x5c byte repeated for key length
+// hmac = H([key ^ opad] H([key ^ ipad] text))
+
+// Marshalable is the combination of encoding.BinaryMarshaler and
+// encoding.BinaryUnmarshaler. Their method definitions are repeated here to
+// avoid a dependency on the encoding package.
+type marshalable interface {
+ MarshalBinary() ([]byte, error)
+ UnmarshalBinary([]byte) error
+}
+
+type hmac struct {
+ opad, ipad []byte
+ outer, inner hash.Hash
+
+ // If marshaled is true, then opad and ipad do not contain a padded
+ // copy of the key, but rather the marshaled state of outer/inner after
+ // opad/ipad has been fed into it.
+ marshaled bool
+}
+
+func (h *hmac) Sum(in []byte) []byte {
+ origLen := len(in)
+ in = h.inner.Sum(in)
+
+ if h.marshaled {
+ if err := h.outer.(marshalable).UnmarshalBinary(h.opad); err != nil {
+ panic(err)
+ }
+ } else {
+ h.outer.Reset()
+ h.outer.Write(h.opad)
+ }
+ h.outer.Write(in[origLen:])
+ return h.outer.Sum(in[:origLen])
+}
+
+func (h *hmac) Write(p []byte) (n int, err error) {
+ return h.inner.Write(p)
+}
+
+func (h *hmac) Size() int { return h.outer.Size() }
+func (h *hmac) BlockSize() int { return h.inner.BlockSize() }
+
+func (h *hmac) Reset() {
+ if h.marshaled {
+ if err := h.inner.(marshalable).UnmarshalBinary(h.ipad); err != nil {
+ panic(err)
+ }
+ return
+ }
+
+ h.inner.Reset()
+ h.inner.Write(h.ipad)
+
+ // If the underlying hash is marshalable, we can save some time by
+ // saving a copy of the hash state now, and restoring it on future
+ // calls to Reset and Sum instead of writing ipad/opad every time.
+ //
+ // If either hash is unmarshalable for whatever reason,
+ // it's safe to bail out here.
+ marshalableInner, innerOK := h.inner.(marshalable)
+ if !innerOK {
+ return
+ }
+ marshalableOuter, outerOK := h.outer.(marshalable)
+ if !outerOK {
+ return
+ }
+
+ imarshal, err := marshalableInner.MarshalBinary()
+ if err != nil {
+ return
+ }
+
+ h.outer.Reset()
+ h.outer.Write(h.opad)
+ omarshal, err := marshalableOuter.MarshalBinary()
+ if err != nil {
+ return
+ }
+
+ // Marshaling succeeded; save the marshaled state for later
+ h.ipad = imarshal
+ h.opad = omarshal
+ h.marshaled = true
+}
+
+// New returns a new HMAC hash using the given hash.Hash type and key.
+// New functions like sha256.New from crypto/sha256 can be used as h.
+// h must return a new Hash every time it is called.
+// Note that unlike other hash implementations in the standard library,
+// the returned Hash does not implement encoding.BinaryMarshaler
+// or encoding.BinaryUnmarshaler.
+func New(h func() hash.Hash, key []byte) hash.Hash {
+ if boring.Enabled {
+ hm := boring.NewHMAC(h, key)
+ if hm != nil {
+ return hm
+ }
+ // BoringCrypto did not recognize h, so fall through to standard Go code.
+ }
+ hm := new(hmac)
+ hm.outer = h()
+ hm.inner = h()
+ unique := true
+ func() {
+ defer func() {
+ // The comparison might panic if the underlying types are not comparable.
+ _ = recover()
+ }()
+ if hm.outer == hm.inner {
+ unique = false
+ }
+ }()
+ if !unique {
+ panic("crypto/hmac: hash generation function does not produce unique values")
+ }
+ blocksize := hm.inner.BlockSize()
+ hm.ipad = make([]byte, blocksize)
+ hm.opad = make([]byte, blocksize)
+ if len(key) > blocksize {
+ // If key is too big, hash it.
+ hm.outer.Write(key)
+ key = hm.outer.Sum(nil)
+ }
+ copy(hm.ipad, key)
+ copy(hm.opad, key)
+ for i := range hm.ipad {
+ hm.ipad[i] ^= 0x36
+ }
+ for i := range hm.opad {
+ hm.opad[i] ^= 0x5c
+ }
+ hm.inner.Write(hm.ipad)
+
+ return hm
+}
+
+// Equal compares two MACs for equality without leaking timing information.
+func Equal(mac1, mac2 []byte) bool {
+ // We don't have to be constant time if the lengths of the MACs are
+ // different as that suggests that a completely different hash function
+ // was used.
+ return subtle.ConstantTimeCompare(mac1, mac2) == 1
+}
diff --git a/src/crypto/hmac/hmac_test.go b/src/crypto/hmac/hmac_test.go
new file mode 100644
index 0000000..55415ab
--- /dev/null
+++ b/src/crypto/hmac/hmac_test.go
@@ -0,0 +1,695 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package hmac
+
+import (
+ "bytes"
+ "crypto/internal/boring"
+ "crypto/md5"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/sha512"
+ "fmt"
+ "hash"
+ "testing"
+)
+
+type hmacTest struct {
+ hash func() hash.Hash
+ key []byte
+ in []byte
+ out string
+ size int
+ blocksize int
+}
+
+var hmacTests = []hmacTest{
+ // Tests from US FIPS 198
+ // https://csrc.nist.gov/publications/fips/fips198/fips-198a.pdf
+ {
+ sha1.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ []byte("Sample #1"),
+ "4f4ca3d5d68ba7cc0a1208c9c61e9c5da0403c0a",
+ sha1.Size,
+ sha1.BlockSize,
+ },
+ {
+ sha1.New,
+ []byte{
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43,
+ },
+ []byte("Sample #2"),
+ "0922d3405faa3d194f82a45830737d5cc6c75d24",
+ sha1.Size,
+ sha1.BlockSize,
+ },
+ {
+ sha1.New,
+ []byte{
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3,
+ },
+ []byte("Sample #3"),
+ "bcf41eab8bb2d802f3d05caf7cb092ecf8d1a3aa",
+ sha1.Size,
+ sha1.BlockSize,
+ },
+
+ // Test from Plan 9.
+ {
+ md5.New,
+ []byte("Jefe"),
+ []byte("what do ya want for nothing?"),
+ "750c783e6ab0b503eaa86e310a5db738",
+ md5.Size,
+ md5.BlockSize,
+ },
+
+ // Tests from RFC 4231
+ {
+ sha256.New,
+ []byte{
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b,
+ 0x0b, 0x0b, 0x0b, 0x0b,
+ },
+ []byte("Hi There"),
+ "b0344c61d8db38535ca8afceaf0bf12b881dc200c9833da726e9376c2e32cff7",
+ sha256.Size,
+ sha256.BlockSize,
+ },
+ {
+ sha256.New,
+ []byte("Jefe"),
+ []byte("what do ya want for nothing?"),
+ "5bdcc146bf60754e6a042426089575c75a003f089d2739839dec58b964ec3843",
+ sha256.Size,
+ sha256.BlockSize,
+ },
+ {
+ sha256.New,
+ []byte{
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa,
+ },
+ []byte{
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd, 0xdd,
+ 0xdd, 0xdd,
+ },
+ "773ea91e36800e46854db8ebd09181a72959098b3ef8c122d9635514ced565fe",
+ sha256.Size,
+ sha256.BlockSize,
+ },
+ {
+ sha256.New,
+ []byte{
+ 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08,
+ 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10,
+ 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18,
+ 0x19,
+ },
+ []byte{
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd, 0xcd,
+ 0xcd, 0xcd,
+ },
+ "82558a389a443c0ea4cc819899f2083a85f0faa3e578f8077a2e3ff46729665b",
+ sha256.Size,
+ sha256.BlockSize,
+ },
+ {
+ sha256.New,
+ []byte{
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa,
+ },
+ []byte("Test Using Larger Than Block-Size Key - Hash Key First"),
+ "60e431591ee0b67f0d8a26aacbf5b77f8e0bc6213728c5140546040f0ee37f54",
+ sha256.Size,
+ sha256.BlockSize,
+ },
+ {
+ sha256.New,
+ []byte{
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa,
+ 0xaa, 0xaa, 0xaa,
+ },
+ []byte("This is a test using a larger than block-size key " +
+ "and a larger than block-size data. The key needs to " +
+ "be hashed before being used by the HMAC algorithm."),
+ "9b09ffa71b942fcb27635fbcd5b0e944bfdc63644f0713938a7f51535c3a35e2",
+ sha256.Size,
+ sha256.BlockSize,
+ },
+
+ // Tests from https://csrc.nist.gov/groups/ST/toolkit/examples.html
+ // (truncated tag tests are left out)
+ {
+ sha1.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "5fd596ee78d5553c8ff4e72d266dfd192366da29",
+ sha1.Size,
+ sha1.BlockSize,
+ },
+ {
+ sha1.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13,
+ },
+ []byte("Sample message for keylen<blocklen"),
+ "4c99ff0cb1b31bd33f8431dbaf4d17fcd356a807",
+ sha1.Size,
+ sha1.BlockSize,
+ },
+ {
+ sha1.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "2d51b2f7750e410584662e38f133435f4c4fd42a",
+ sha1.Size,
+ sha1.BlockSize,
+ },
+ {
+ sha256.New224,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "c7405e3ae058e8cd30b08b4140248581ed174cb34e1224bcc1efc81b",
+ sha256.Size224,
+ sha256.BlockSize,
+ },
+ {
+ sha256.New224,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b,
+ },
+ []byte("Sample message for keylen<blocklen"),
+ "e3d249a8cfb67ef8b7a169e9a0a599714a2cecba65999a51beb8fbbe",
+ sha256.Size224,
+ sha256.BlockSize,
+ },
+ {
+ sha256.New224,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "91c52509e5af8531601ae6230099d90bef88aaefb961f4080abc014d",
+ sha256.Size224,
+ sha256.BlockSize,
+ },
+ {
+ sha256.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "8bb9a1db9806f20df7f77b82138c7914d174d59e13dc4d0169c9057b133e1d62",
+ sha256.Size,
+ sha256.BlockSize,
+ },
+ {
+ sha256.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ },
+ []byte("Sample message for keylen<blocklen"),
+ "a28cf43130ee696a98f14a37678b56bcfcbdd9e5cf69717fecf5480f0ebdf790",
+ sha256.Size,
+ sha256.BlockSize,
+ },
+ {
+ sha256.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "bdccb6c72ddeadb500ae768386cb38cc41c63dbb0878ddb9c7a38a431b78378d",
+ sha256.Size,
+ sha256.BlockSize,
+ },
+ {
+ sha512.New384,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "63c5daa5e651847ca897c95814ab830bededc7d25e83eef9195cd45857a37f448947858f5af50cc2b1b730ddf29671a9",
+ sha512.Size384,
+ sha512.BlockSize,
+ },
+ {
+ sha512.New384,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ },
+ []byte("Sample message for keylen<blocklen"),
+ "6eb242bdbb582ca17bebfa481b1e23211464d2b7f8c20b9ff2201637b93646af5ae9ac316e98db45d9cae773675eeed0",
+ sha512.Size384,
+ sha512.BlockSize,
+ },
+ {
+ sha512.New384,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "5b664436df69b0ca22551231a3f0a3d5b4f97991713cfa84bff4d0792eff96c27dccbbb6f79b65d548b40e8564cef594",
+ sha512.Size384,
+ sha512.BlockSize,
+ },
+ {
+ sha512.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "fc25e240658ca785b7a811a8d3f7b4ca" +
+ "48cfa26a8a366bf2cd1f836b05fcb024bd36853081811d6c" +
+ "ea4216ebad79da1cfcb95ea4586b8a0ce356596a55fb1347",
+ sha512.Size,
+ sha512.BlockSize,
+ },
+ {
+ sha512.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ },
+ []byte("Sample message for keylen<blocklen"),
+ "fd44c18bda0bb0a6ce0e82b031bf2818" +
+ "f6539bd56ec00bdc10a8a2d730b3634de2545d639b0f2cf7" +
+ "10d0692c72a1896f1f211c2b922d1a96c392e07e7ea9fedc",
+ sha512.Size,
+ sha512.BlockSize,
+ },
+ {
+ sha512.New,
+ []byte{
+ 0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07,
+ 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f,
+ 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17,
+ 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f,
+ 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27,
+ 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f,
+ 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37,
+ 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f,
+ 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47,
+ 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f,
+ 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57,
+ 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f,
+ 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67,
+ 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f,
+ 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77,
+ 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f,
+ 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87,
+ 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f,
+ 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97,
+ 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f,
+ 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7,
+ 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf,
+ 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7,
+ 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf,
+ 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7,
+ },
+ []byte("Sample message for keylen=blocklen"),
+ "d93ec8d2de1ad2a9957cb9b83f14e76a" +
+ "d6b5e0cce285079a127d3b14bccb7aa7286d4ac0d4ce6421" +
+ "5f2bc9e6870b33d97438be4aaa20cda5c5a912b48b8e27f3",
+ sha512.Size,
+ sha512.BlockSize,
+ },
+ // HMAC without key is dumb but should probably not fail.
+ {
+ sha1.New,
+ []byte{},
+ []byte("message"),
+ "d5d1ed05121417247616cfc8378f360a39da7cfa",
+ sha1.Size,
+ sha1.BlockSize,
+ },
+ {
+ sha256.New,
+ []byte{},
+ []byte("message"),
+ "eb08c1f56d5ddee07f7bdf80468083da06b64cf4fac64fe3a90883df5feacae4",
+ sha256.Size,
+ sha256.BlockSize,
+ },
+ {
+ sha512.New,
+ []byte{},
+ []byte("message"),
+ "08fce52f6395d59c2a3fb8abb281d74ad6f112b9a9c787bcea290d94dadbc82b2ca3e5e12bf2277c7fedbb0154d5493e41bb7459f63c8e39554ea3651b812492",
+ sha512.Size,
+ sha512.BlockSize,
+ },
+}
+
+func TestHMAC(t *testing.T) {
+ for i, tt := range hmacTests {
+ h := New(tt.hash, tt.key)
+ if s := h.Size(); s != tt.size {
+ t.Errorf("Size: got %v, want %v", s, tt.size)
+ }
+ if b := h.BlockSize(); b != tt.blocksize {
+ t.Errorf("BlockSize: got %v, want %v", b, tt.blocksize)
+ }
+ for j := 0; j < 4; j++ {
+ n, err := h.Write(tt.in)
+ if n != len(tt.in) || err != nil {
+ t.Errorf("test %d.%d: Write(%d) = %d, %v", i, j, len(tt.in), n, err)
+ continue
+ }
+
+ // Repetitive Sum() calls should return the same value
+ for k := 0; k < 2; k++ {
+ sum := fmt.Sprintf("%x", h.Sum(nil))
+ if sum != tt.out {
+ t.Errorf("test %d.%d.%d: have %s want %s\n", i, j, k, sum, tt.out)
+ }
+ }
+
+ // Second iteration: make sure reset works.
+ h.Reset()
+
+ // Third and fourth iteration: make sure hmac works on
+ // hashes without MarshalBinary/UnmarshalBinary
+ if j == 1 {
+ h = New(func() hash.Hash { return justHash{tt.hash()} }, tt.key)
+ }
+ }
+ }
+}
+
+func TestNonUniqueHash(t *testing.T) {
+ if boring.Enabled {
+ t.Skip("hash.Hash provided by boringcrypto are not comparable")
+ }
+ sha := sha256.New()
+ defer func() {
+ err := recover()
+ if err == nil {
+ t.Error("expected panic when calling New with a non-unique hash generation function")
+ }
+ }()
+ New(func() hash.Hash { return sha }, []byte("bytes"))
+}
+
+// justHash implements just the hash.Hash methods and nothing else
+type justHash struct {
+ hash.Hash
+}
+
+func TestEqual(t *testing.T) {
+ a := []byte("test")
+ b := []byte("test1")
+ c := []byte("test2")
+
+ if !Equal(b, b) {
+ t.Error("Equal failed with equal arguments")
+ }
+ if Equal(a, b) {
+ t.Error("Equal accepted a prefix of the second argument")
+ }
+ if Equal(b, a) {
+ t.Error("Equal accepted a prefix of the first argument")
+ }
+ if Equal(b, c) {
+ t.Error("Equal accepted unequal slices")
+ }
+}
+
+func TestWriteAfterSum(t *testing.T) {
+ h := New(sha1.New, nil)
+ h.Write([]byte("hello"))
+ sumHello := h.Sum(nil)
+
+ h = New(sha1.New, nil)
+ h.Write([]byte("hello world"))
+ sumHelloWorld := h.Sum(nil)
+
+ // Test that Sum has no effect on future Sum or Write operations.
+ // This is a bit unusual as far as usage, but it's allowed
+ // by the definition of Go hash.Hash, and some clients expect it to work.
+ h = New(sha1.New, nil)
+ h.Write([]byte("hello"))
+ if sum := h.Sum(nil); !bytes.Equal(sum, sumHello) {
+ t.Fatalf("1st Sum after hello = %x, want %x", sum, sumHello)
+ }
+ if sum := h.Sum(nil); !bytes.Equal(sum, sumHello) {
+ t.Fatalf("2nd Sum after hello = %x, want %x", sum, sumHello)
+ }
+
+ h.Write([]byte(" world"))
+ if sum := h.Sum(nil); !bytes.Equal(sum, sumHelloWorld) {
+ t.Fatalf("1st Sum after hello world = %x, want %x", sum, sumHelloWorld)
+ }
+ if sum := h.Sum(nil); !bytes.Equal(sum, sumHelloWorld) {
+ t.Fatalf("2nd Sum after hello world = %x, want %x", sum, sumHelloWorld)
+ }
+
+ h.Reset()
+ h.Write([]byte("hello"))
+ if sum := h.Sum(nil); !bytes.Equal(sum, sumHello) {
+ t.Fatalf("Sum after Reset + hello = %x, want %x", sum, sumHello)
+ }
+}
+
+func BenchmarkHMACSHA256_1K(b *testing.B) {
+ key := make([]byte, 32)
+ buf := make([]byte, 1024)
+ h := New(sha256.New, key)
+ b.SetBytes(int64(len(buf)))
+ for i := 0; i < b.N; i++ {
+ h.Write(buf)
+ mac := h.Sum(nil)
+ h.Reset()
+ buf[0] = mac[0]
+ }
+}
+
+func BenchmarkHMACSHA256_32(b *testing.B) {
+ key := make([]byte, 32)
+ buf := make([]byte, 32)
+ h := New(sha256.New, key)
+ b.SetBytes(int64(len(buf)))
+ for i := 0; i < b.N; i++ {
+ h.Write(buf)
+ mac := h.Sum(nil)
+ h.Reset()
+ buf[0] = mac[0]
+ }
+}
+
+func BenchmarkNewWriteSum(b *testing.B) {
+ buf := make([]byte, 32)
+ b.SetBytes(int64(len(buf)))
+ for i := 0; i < b.N; i++ {
+ h := New(sha256.New, make([]byte, 32))
+ h.Write(buf)
+ mac := h.Sum(nil)
+ buf[0] = mac[0]
+ }
+}
diff --git a/src/crypto/internal/alias/alias.go b/src/crypto/internal/alias/alias.go
new file mode 100644
index 0000000..936cc25
--- /dev/null
+++ b/src/crypto/internal/alias/alias.go
@@ -0,0 +1,30 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package alias implements memory alaising tests.
+// This code also exists as golang.org/x/crypto/internal/alias.
+package alias
+
+import "unsafe"
+
+// AnyOverlap reports whether x and y share memory at any (not necessarily
+// corresponding) index. The memory beyond the slice length is ignored.
+func AnyOverlap(x, y []byte) bool {
+ return len(x) > 0 && len(y) > 0 &&
+ uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
+ uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
+}
+
+// InexactOverlap reports whether x and y share memory at any non-corresponding
+// index. The memory beyond the slice length is ignored. Note that x and y can
+// have different lengths and still not have any inexact overlap.
+//
+// InexactOverlap can be used to implement the requirements of the crypto/cipher
+// AEAD, Block, BlockMode and Stream interfaces.
+func InexactOverlap(x, y []byte) bool {
+ if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
+ return false
+ }
+ return AnyOverlap(x, y)
+}
diff --git a/src/crypto/internal/alias/alias_test.go b/src/crypto/internal/alias/alias_test.go
new file mode 100644
index 0000000..a68fb33
--- /dev/null
+++ b/src/crypto/internal/alias/alias_test.go
@@ -0,0 +1,46 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package alias
+
+import "testing"
+
+var a, b [100]byte
+
+var aliasingTests = []struct {
+ x, y []byte
+ anyOverlap, inexactOverlap bool
+}{
+ {a[:], b[:], false, false},
+ {a[:], b[:0], false, false},
+ {a[:], b[:50], false, false},
+ {a[40:50], a[50:60], false, false},
+ {a[40:50], a[60:70], false, false},
+ {a[:51], a[50:], true, true},
+ {a[:], a[:], true, false},
+ {a[:50], a[:60], true, false},
+ {a[:], nil, false, false},
+ {nil, nil, false, false},
+ {a[:], a[:0], false, false},
+ {a[:10], a[:10:20], true, false},
+ {a[:10], a[5:10:20], true, true},
+}
+
+func testAliasing(t *testing.T, i int, x, y []byte, anyOverlap, inexactOverlap bool) {
+ any := AnyOverlap(x, y)
+ if any != anyOverlap {
+ t.Errorf("%d: wrong AnyOverlap result, expected %v, got %v", i, anyOverlap, any)
+ }
+ inexact := InexactOverlap(x, y)
+ if inexact != inexactOverlap {
+ t.Errorf("%d: wrong InexactOverlap result, expected %v, got %v", i, inexactOverlap, any)
+ }
+}
+
+func TestAliasing(t *testing.T) {
+ for i, tt := range aliasingTests {
+ testAliasing(t, i, tt.x, tt.y, tt.anyOverlap, tt.inexactOverlap)
+ testAliasing(t, i, tt.y, tt.x, tt.anyOverlap, tt.inexactOverlap)
+ }
+}
diff --git a/src/crypto/internal/bigmod/_asm/go.mod b/src/crypto/internal/bigmod/_asm/go.mod
new file mode 100644
index 0000000..1ce2b5e
--- /dev/null
+++ b/src/crypto/internal/bigmod/_asm/go.mod
@@ -0,0 +1,12 @@
+module asm
+
+go 1.19
+
+require github.com/mmcloughlin/avo v0.4.0
+
+require (
+ golang.org/x/mod v0.4.2 // indirect
+ golang.org/x/sys v0.0.0-20211030160813-b3129d9d1021 // indirect
+ golang.org/x/tools v0.1.7 // indirect
+ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
+)
diff --git a/src/crypto/internal/bigmod/_asm/go.sum b/src/crypto/internal/bigmod/_asm/go.sum
new file mode 100644
index 0000000..b4b5914
--- /dev/null
+++ b/src/crypto/internal/bigmod/_asm/go.sum
@@ -0,0 +1,32 @@
+github.com/mmcloughlin/avo v0.4.0 h1:jeHDRktVD+578ULxWpQHkilor6pkdLF7u7EiTzDbfcU=
+github.com/mmcloughlin/avo v0.4.0/go.mod h1:RW9BfYA3TgO9uCdNrKU2h6J8cPD8ZLznvfgHAeszb1s=
+github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211030160813-b3129d9d1021 h1:giLT+HuUP/gXYrG2Plg9WTjj4qhfgaW424ZIFog3rlk=
+golang.org/x/sys v0.0.0-20211030160813-b3129d9d1021/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
+golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
diff --git a/src/crypto/internal/bigmod/_asm/nat_amd64_asm.go b/src/crypto/internal/bigmod/_asm/nat_amd64_asm.go
new file mode 100644
index 0000000..5690f04
--- /dev/null
+++ b/src/crypto/internal/bigmod/_asm/nat_amd64_asm.go
@@ -0,0 +1,131 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ . "github.com/mmcloughlin/avo/build"
+ . "github.com/mmcloughlin/avo/operand"
+ . "github.com/mmcloughlin/avo/reg"
+)
+
+//go:generate go run . -out ../nat_amd64.s -stubs ../nat_amd64.go -pkg bigmod
+
+func main() {
+ Package("crypto/internal/bigmod")
+ ConstraintExpr("amd64,gc,!purego")
+
+ Implement("montgomeryLoop")
+ Pragma("noescape")
+
+ size := Load(Param("d").Len(), GP64())
+ d := Mem{Base: Load(Param("d").Base(), GP64())}
+ b := Mem{Base: Load(Param("b").Base(), GP64())}
+ m := Mem{Base: Load(Param("m").Base(), GP64())}
+ m0inv := Load(Param("m0inv"), GP64())
+
+ overflow := zero()
+ i := zero()
+ Label("outerLoop")
+
+ ai := Load(Param("a").Base(), GP64())
+ MOVQ(Mem{Base: ai}.Idx(i, 8), ai)
+
+ z := uint128{GP64(), GP64()}
+ mul64(z, b, ai)
+ add64(z, d)
+ f := GP64()
+ MOVQ(m0inv, f)
+ IMULQ(z.lo, f)
+ _MASK(f)
+ addMul64(z, m, f)
+ carry := shiftBy63(z)
+
+ j := zero()
+ INCQ(j)
+ JMP(LabelRef("innerLoopCondition"))
+ Label("innerLoop")
+
+ // z = d[j] + a[i] * b[j] + f * m[j] + carry
+ z = uint128{GP64(), GP64()}
+ mul64(z, b.Idx(j, 8), ai)
+ addMul64(z, m.Idx(j, 8), f)
+ add64(z, d.Idx(j, 8))
+ add64(z, carry)
+ // d[j-1] = z_lo & _MASK
+ storeMasked(z.lo, d.Idx(j, 8).Offset(-8))
+ // carry = z_hi<<1 | z_lo>>_W
+ MOVQ(shiftBy63(z), carry)
+
+ INCQ(j)
+ Label("innerLoopCondition")
+ CMPQ(size, j)
+ JGT(LabelRef("innerLoop"))
+
+ ADDQ(carry, overflow)
+ storeMasked(overflow, d.Idx(size, 8).Offset(-8))
+ SHRQ(Imm(63), overflow)
+
+ INCQ(i)
+ CMPQ(size, i)
+ JGT(LabelRef("outerLoop"))
+
+ Store(overflow, ReturnIndex(0))
+ RET()
+ Generate()
+}
+
+// zero zeroes a new register and returns it.
+func zero() Register {
+ r := GP64()
+ XORQ(r, r)
+ return r
+}
+
+// _MASK masks out the top bit of r.
+func _MASK(r Register) {
+ BTRQ(Imm(63), r)
+}
+
+type uint128 struct {
+ hi, lo GPVirtual
+}
+
+// storeMasked stores _MASK(src) in dst. It doesn't modify src.
+func storeMasked(src, dst Op) {
+ out := GP64()
+ MOVQ(src, out)
+ _MASK(out)
+ MOVQ(out, dst)
+}
+
+// shiftBy63 returns z >> 63. It reuses z.lo.
+func shiftBy63(z uint128) Register {
+ SHRQ(Imm(63), z.hi, z.lo)
+ result := z.lo
+ z.hi, z.lo = nil, nil
+ return result
+}
+
+// add64 sets r to r + a.
+func add64(r uint128, a Op) {
+ ADDQ(a, r.lo)
+ ADCQ(Imm(0), r.hi)
+}
+
+// mul64 sets r to a * b.
+func mul64(r uint128, a, b Op) {
+ MOVQ(a, RAX)
+ MULQ(b) // RDX, RAX = RAX * b
+ MOVQ(RAX, r.lo)
+ MOVQ(RDX, r.hi)
+}
+
+// addMul64 sets r to r + a * b.
+func addMul64(r uint128, a, b Op) {
+ MOVQ(a, RAX)
+ MULQ(b) // RDX, RAX = RAX * b
+ ADDQ(RAX, r.lo)
+ ADCQ(RDX, r.hi)
+}
diff --git a/src/crypto/internal/bigmod/nat.go b/src/crypto/internal/bigmod/nat.go
new file mode 100644
index 0000000..804316f
--- /dev/null
+++ b/src/crypto/internal/bigmod/nat.go
@@ -0,0 +1,703 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bigmod
+
+import (
+ "errors"
+ "math/big"
+ "math/bits"
+)
+
+const (
+ // _W is the number of bits we use for our limbs.
+ _W = bits.UintSize - 1
+ // _MASK selects _W bits from a full machine word.
+ _MASK = (1 << _W) - 1
+)
+
+// choice represents a constant-time boolean. The value of choice is always
+// either 1 or 0. We use an int instead of bool in order to make decisions in
+// constant time by turning it into a mask.
+type choice uint
+
+func not(c choice) choice { return 1 ^ c }
+
+const yes = choice(1)
+const no = choice(0)
+
+// ctSelect returns x if on == 1, and y if on == 0. The execution time of this
+// function does not depend on its inputs. If on is any value besides 1 or 0,
+// the result is undefined.
+func ctSelect(on choice, x, y uint) uint {
+ // When on == 1, mask is 0b111..., otherwise mask is 0b000...
+ mask := -uint(on)
+ // When mask is all zeros, we just have y, otherwise, y cancels with itself.
+ return y ^ (mask & (y ^ x))
+}
+
+// ctEq returns 1 if x == y, and 0 otherwise. The execution time of this
+// function does not depend on its inputs.
+func ctEq(x, y uint) choice {
+ // If x != y, then either x - y or y - x will generate a carry.
+ _, c1 := bits.Sub(x, y, 0)
+ _, c2 := bits.Sub(y, x, 0)
+ return not(choice(c1 | c2))
+}
+
+// ctGeq returns 1 if x >= y, and 0 otherwise. The execution time of this
+// function does not depend on its inputs.
+func ctGeq(x, y uint) choice {
+ // If x < y, then x - y generates a carry.
+ _, carry := bits.Sub(x, y, 0)
+ return not(choice(carry))
+}
+
+// Nat represents an arbitrary natural number
+//
+// Each Nat has an announced length, which is the number of limbs it has stored.
+// Operations on this number are allowed to leak this length, but will not leak
+// any information about the values contained in those limbs.
+type Nat struct {
+ // limbs is a little-endian representation in base 2^W with
+ // W = bits.UintSize - 1. The top bit is always unset between operations.
+ //
+ // The top bit is left unset to optimize Montgomery multiplication, in the
+ // inner loop of exponentiation. Using fully saturated limbs would leave us
+ // working with 129-bit numbers on 64-bit platforms, wasting a lot of space,
+ // and thus time.
+ limbs []uint
+}
+
+// preallocTarget is the size in bits of the numbers used to implement the most
+// common and most performant RSA key size. It's also enough to cover some of
+// the operations of key sizes up to 4096.
+const preallocTarget = 2048
+const preallocLimbs = (preallocTarget + _W - 1) / _W
+
+// NewNat returns a new nat with a size of zero, just like new(Nat), but with
+// the preallocated capacity to hold a number of up to preallocTarget bits.
+// NewNat inlines, so the allocation can live on the stack.
+func NewNat() *Nat {
+ limbs := make([]uint, 0, preallocLimbs)
+ return &Nat{limbs}
+}
+
+// expand expands x to n limbs, leaving its value unchanged.
+func (x *Nat) expand(n int) *Nat {
+ if len(x.limbs) > n {
+ panic("bigmod: internal error: shrinking nat")
+ }
+ if cap(x.limbs) < n {
+ newLimbs := make([]uint, n)
+ copy(newLimbs, x.limbs)
+ x.limbs = newLimbs
+ return x
+ }
+ extraLimbs := x.limbs[len(x.limbs):n]
+ for i := range extraLimbs {
+ extraLimbs[i] = 0
+ }
+ x.limbs = x.limbs[:n]
+ return x
+}
+
+// reset returns a zero nat of n limbs, reusing x's storage if n <= cap(x.limbs).
+func (x *Nat) reset(n int) *Nat {
+ if cap(x.limbs) < n {
+ x.limbs = make([]uint, n)
+ return x
+ }
+ for i := range x.limbs {
+ x.limbs[i] = 0
+ }
+ x.limbs = x.limbs[:n]
+ return x
+}
+
+// set assigns x = y, optionally resizing x to the appropriate size.
+func (x *Nat) set(y *Nat) *Nat {
+ x.reset(len(y.limbs))
+ copy(x.limbs, y.limbs)
+ return x
+}
+
+// setBig assigns x = n, optionally resizing n to the appropriate size.
+//
+// The announced length of x is set based on the actual bit size of the input,
+// ignoring leading zeroes.
+func (x *Nat) setBig(n *big.Int) *Nat {
+ requiredLimbs := (n.BitLen() + _W - 1) / _W
+ x.reset(requiredLimbs)
+
+ outI := 0
+ shift := 0
+ limbs := n.Bits()
+ for i := range limbs {
+ xi := uint(limbs[i])
+ x.limbs[outI] |= (xi << shift) & _MASK
+ outI++
+ if outI == requiredLimbs {
+ return x
+ }
+ x.limbs[outI] = xi >> (_W - shift)
+ shift++ // this assumes bits.UintSize - _W = 1
+ if shift == _W {
+ shift = 0
+ outI++
+ }
+ }
+ return x
+}
+
+// Bytes returns x as a zero-extended big-endian byte slice. The size of the
+// slice will match the size of m.
+//
+// x must have the same size as m and it must be reduced modulo m.
+func (x *Nat) Bytes(m *Modulus) []byte {
+ bytes := make([]byte, m.Size())
+ shift := 0
+ outI := len(bytes) - 1
+ for _, limb := range x.limbs {
+ remainingBits := _W
+ for remainingBits >= 8 {
+ bytes[outI] |= byte(limb) << shift
+ consumed := 8 - shift
+ limb >>= consumed
+ remainingBits -= consumed
+ shift = 0
+ outI--
+ if outI < 0 {
+ return bytes
+ }
+ }
+ bytes[outI] = byte(limb)
+ shift = remainingBits
+ }
+ return bytes
+}
+
+// SetBytes assigns x = b, where b is a slice of big-endian bytes.
+// SetBytes returns an error if b >= m.
+//
+// The output will be resized to the size of m and overwritten.
+func (x *Nat) SetBytes(b []byte, m *Modulus) (*Nat, error) {
+ if err := x.setBytes(b, m); err != nil {
+ return nil, err
+ }
+ if x.cmpGeq(m.nat) == yes {
+ return nil, errors.New("input overflows the modulus")
+ }
+ return x, nil
+}
+
+// SetOverflowingBytes assigns x = b, where b is a slice of big-endian bytes. SetOverflowingBytes
+// returns an error if b has a longer bit length than m, but reduces overflowing
+// values up to 2^⌈log2(m)⌉ - 1.
+//
+// The output will be resized to the size of m and overwritten.
+func (x *Nat) SetOverflowingBytes(b []byte, m *Modulus) (*Nat, error) {
+ if err := x.setBytes(b, m); err != nil {
+ return nil, err
+ }
+ leading := _W - bitLen(x.limbs[len(x.limbs)-1])
+ if leading < m.leading {
+ return nil, errors.New("input overflows the modulus")
+ }
+ x.sub(x.cmpGeq(m.nat), m.nat)
+ return x, nil
+}
+
+func (x *Nat) setBytes(b []byte, m *Modulus) error {
+ outI := 0
+ shift := 0
+ x.resetFor(m)
+ for i := len(b) - 1; i >= 0; i-- {
+ bi := b[i]
+ x.limbs[outI] |= uint(bi) << shift
+ shift += 8
+ if shift >= _W {
+ shift -= _W
+ x.limbs[outI] &= _MASK
+ overflow := bi >> (8 - shift)
+ outI++
+ if outI >= len(x.limbs) {
+ if overflow > 0 || i > 0 {
+ return errors.New("input overflows the modulus")
+ }
+ break
+ }
+ x.limbs[outI] = uint(overflow)
+ }
+ }
+ return nil
+}
+
+// Equal returns 1 if x == y, and 0 otherwise.
+//
+// Both operands must have the same announced length.
+func (x *Nat) Equal(y *Nat) choice {
+ // Eliminate bounds checks in the loop.
+ size := len(x.limbs)
+ xLimbs := x.limbs[:size]
+ yLimbs := y.limbs[:size]
+
+ equal := yes
+ for i := 0; i < size; i++ {
+ equal &= ctEq(xLimbs[i], yLimbs[i])
+ }
+ return equal
+}
+
+// IsZero returns 1 if x == 0, and 0 otherwise.
+func (x *Nat) IsZero() choice {
+ // Eliminate bounds checks in the loop.
+ size := len(x.limbs)
+ xLimbs := x.limbs[:size]
+
+ zero := yes
+ for i := 0; i < size; i++ {
+ zero &= ctEq(xLimbs[i], 0)
+ }
+ return zero
+}
+
+// cmpGeq returns 1 if x >= y, and 0 otherwise.
+//
+// Both operands must have the same announced length.
+func (x *Nat) cmpGeq(y *Nat) choice {
+ // Eliminate bounds checks in the loop.
+ size := len(x.limbs)
+ xLimbs := x.limbs[:size]
+ yLimbs := y.limbs[:size]
+
+ var c uint
+ for i := 0; i < size; i++ {
+ c = (xLimbs[i] - yLimbs[i] - c) >> _W
+ }
+ // If there was a carry, then subtracting y underflowed, so
+ // x is not greater than or equal to y.
+ return not(choice(c))
+}
+
+// assign sets x <- y if on == 1, and does nothing otherwise.
+//
+// Both operands must have the same announced length.
+func (x *Nat) assign(on choice, y *Nat) *Nat {
+ // Eliminate bounds checks in the loop.
+ size := len(x.limbs)
+ xLimbs := x.limbs[:size]
+ yLimbs := y.limbs[:size]
+
+ for i := 0; i < size; i++ {
+ xLimbs[i] = ctSelect(on, yLimbs[i], xLimbs[i])
+ }
+ return x
+}
+
+// add computes x += y if on == 1, and does nothing otherwise. It returns the
+// carry of the addition regardless of on.
+//
+// Both operands must have the same announced length.
+func (x *Nat) add(on choice, y *Nat) (c uint) {
+ // Eliminate bounds checks in the loop.
+ size := len(x.limbs)
+ xLimbs := x.limbs[:size]
+ yLimbs := y.limbs[:size]
+
+ for i := 0; i < size; i++ {
+ res := xLimbs[i] + yLimbs[i] + c
+ xLimbs[i] = ctSelect(on, res&_MASK, xLimbs[i])
+ c = res >> _W
+ }
+ return
+}
+
+// sub computes x -= y if on == 1, and does nothing otherwise. It returns the
+// borrow of the subtraction regardless of on.
+//
+// Both operands must have the same announced length.
+func (x *Nat) sub(on choice, y *Nat) (c uint) {
+ // Eliminate bounds checks in the loop.
+ size := len(x.limbs)
+ xLimbs := x.limbs[:size]
+ yLimbs := y.limbs[:size]
+
+ for i := 0; i < size; i++ {
+ res := xLimbs[i] - yLimbs[i] - c
+ xLimbs[i] = ctSelect(on, res&_MASK, xLimbs[i])
+ c = res >> _W
+ }
+ return
+}
+
+// Modulus is used for modular arithmetic, precomputing relevant constants.
+//
+// Moduli are assumed to be odd numbers. Moduli can also leak the exact
+// number of bits needed to store their value, and are stored without padding.
+//
+// Their actual value is still kept secret.
+type Modulus struct {
+ // The underlying natural number for this modulus.
+ //
+ // This will be stored without any padding, and shouldn't alias with any
+ // other natural number being used.
+ nat *Nat
+ leading int // number of leading zeros in the modulus
+ m0inv uint // -nat.limbs[0]⁻¹ mod _W
+ rr *Nat // R*R for montgomeryRepresentation
+}
+
+// rr returns R*R with R = 2^(_W * n) and n = len(m.nat.limbs).
+func rr(m *Modulus) *Nat {
+ rr := NewNat().ExpandFor(m)
+ // R*R is 2^(2 * _W * n). We can safely get 2^(_W * (n - 1)) by setting the
+ // most significant limb to 1. We then get to R*R by shifting left by _W
+ // n + 1 times.
+ n := len(rr.limbs)
+ rr.limbs[n-1] = 1
+ for i := n - 1; i < 2*n; i++ {
+ rr.shiftIn(0, m) // x = x * 2^_W mod m
+ }
+ return rr
+}
+
+// minusInverseModW computes -x⁻¹ mod _W with x odd.
+//
+// This operation is used to precompute a constant involved in Montgomery
+// multiplication.
+func minusInverseModW(x uint) uint {
+ // Every iteration of this loop doubles the least-significant bits of
+ // correct inverse in y. The first three bits are already correct (1⁻¹ = 1,
+ // 3⁻¹ = 3, 5⁻¹ = 5, and 7⁻¹ = 7 mod 8), so doubling five times is enough
+ // for 61 bits (and wastes only one iteration for 31 bits).
+ //
+ // See https://crypto.stackexchange.com/a/47496.
+ y := x
+ for i := 0; i < 5; i++ {
+ y = y * (2 - x*y)
+ }
+ return (1 << _W) - (y & _MASK)
+}
+
+// NewModulusFromBig creates a new Modulus from a [big.Int].
+//
+// The Int must be odd. The number of significant bits must be leakable.
+func NewModulusFromBig(n *big.Int) *Modulus {
+ m := &Modulus{}
+ m.nat = NewNat().setBig(n)
+ m.leading = _W - bitLen(m.nat.limbs[len(m.nat.limbs)-1])
+ m.m0inv = minusInverseModW(m.nat.limbs[0])
+ m.rr = rr(m)
+ return m
+}
+
+// bitLen is a version of bits.Len that only leaks the bit length of n, but not
+// its value. bits.Len and bits.LeadingZeros use a lookup table for the
+// low-order bits on some architectures.
+func bitLen(n uint) int {
+ var len int
+ // We assume, here and elsewhere, that comparison to zero is constant time
+ // with respect to different non-zero values.
+ for n != 0 {
+ len++
+ n >>= 1
+ }
+ return len
+}
+
+// Size returns the size of m in bytes.
+func (m *Modulus) Size() int {
+ return (m.BitLen() + 7) / 8
+}
+
+// BitLen returns the size of m in bits.
+func (m *Modulus) BitLen() int {
+ return len(m.nat.limbs)*_W - int(m.leading)
+}
+
+// Nat returns m as a Nat. The return value must not be written to.
+func (m *Modulus) Nat() *Nat {
+ return m.nat
+}
+
+// shiftIn calculates x = x << _W + y mod m.
+//
+// This assumes that x is already reduced mod m, and that y < 2^_W.
+func (x *Nat) shiftIn(y uint, m *Modulus) *Nat {
+ d := NewNat().resetFor(m)
+
+ // Eliminate bounds checks in the loop.
+ size := len(m.nat.limbs)
+ xLimbs := x.limbs[:size]
+ dLimbs := d.limbs[:size]
+ mLimbs := m.nat.limbs[:size]
+
+ // Each iteration of this loop computes x = 2x + b mod m, where b is a bit
+ // from y. Effectively, it left-shifts x and adds y one bit at a time,
+ // reducing it every time.
+ //
+ // To do the reduction, each iteration computes both 2x + b and 2x + b - m.
+ // The next iteration (and finally the return line) will use either result
+ // based on whether the subtraction underflowed.
+ needSubtraction := no
+ for i := _W - 1; i >= 0; i-- {
+ carry := (y >> i) & 1
+ var borrow uint
+ for i := 0; i < size; i++ {
+ l := ctSelect(needSubtraction, dLimbs[i], xLimbs[i])
+
+ res := l<<1 + carry
+ xLimbs[i] = res & _MASK
+ carry = res >> _W
+
+ res = xLimbs[i] - mLimbs[i] - borrow
+ dLimbs[i] = res & _MASK
+ borrow = res >> _W
+ }
+ // See Add for how carry (aka overflow), borrow (aka underflow), and
+ // needSubtraction relate.
+ needSubtraction = ctEq(carry, borrow)
+ }
+ return x.assign(needSubtraction, d)
+}
+
+// Mod calculates out = x mod m.
+//
+// This works regardless how large the value of x is.
+//
+// The output will be resized to the size of m and overwritten.
+func (out *Nat) Mod(x *Nat, m *Modulus) *Nat {
+ out.resetFor(m)
+ // Working our way from the most significant to the least significant limb,
+ // we can insert each limb at the least significant position, shifting all
+ // previous limbs left by _W. This way each limb will get shifted by the
+ // correct number of bits. We can insert at least N - 1 limbs without
+ // overflowing m. After that, we need to reduce every time we shift.
+ i := len(x.limbs) - 1
+ // For the first N - 1 limbs we can skip the actual shifting and position
+ // them at the shifted position, which starts at min(N - 2, i).
+ start := len(m.nat.limbs) - 2
+ if i < start {
+ start = i
+ }
+ for j := start; j >= 0; j-- {
+ out.limbs[j] = x.limbs[i]
+ i--
+ }
+ // We shift in the remaining limbs, reducing modulo m each time.
+ for i >= 0 {
+ out.shiftIn(x.limbs[i], m)
+ i--
+ }
+ return out
+}
+
+// ExpandFor ensures out has the right size to work with operations modulo m.
+//
+// The announced size of out must be smaller than or equal to that of m.
+func (out *Nat) ExpandFor(m *Modulus) *Nat {
+ return out.expand(len(m.nat.limbs))
+}
+
+// resetFor ensures out has the right size to work with operations modulo m.
+//
+// out is zeroed and may start at any size.
+func (out *Nat) resetFor(m *Modulus) *Nat {
+ return out.reset(len(m.nat.limbs))
+}
+
+// Sub computes x = x - y mod m.
+//
+// The length of both operands must be the same as the modulus. Both operands
+// must already be reduced modulo m.
+func (x *Nat) Sub(y *Nat, m *Modulus) *Nat {
+ underflow := x.sub(yes, y)
+ // If the subtraction underflowed, add m.
+ x.add(choice(underflow), m.nat)
+ return x
+}
+
+// Add computes x = x + y mod m.
+//
+// The length of both operands must be the same as the modulus. Both operands
+// must already be reduced modulo m.
+func (x *Nat) Add(y *Nat, m *Modulus) *Nat {
+ overflow := x.add(yes, y)
+ underflow := not(x.cmpGeq(m.nat)) // x < m
+
+ // Three cases are possible:
+ //
+ // - overflow = 0, underflow = 0
+ //
+ // In this case, addition fits in our limbs, but we can still subtract away
+ // m without an underflow, so we need to perform the subtraction to reduce
+ // our result.
+ //
+ // - overflow = 0, underflow = 1
+ //
+ // The addition fits in our limbs, but we can't subtract m without
+ // underflowing. The result is already reduced.
+ //
+ // - overflow = 1, underflow = 1
+ //
+ // The addition does not fit in our limbs, and the subtraction's borrow
+ // would cancel out with the addition's carry. We need to subtract m to
+ // reduce our result.
+ //
+ // The overflow = 1, underflow = 0 case is not possible, because y is at
+ // most m - 1, and if adding m - 1 overflows, then subtracting m must
+ // necessarily underflow.
+ needSubtraction := ctEq(overflow, uint(underflow))
+
+ x.sub(needSubtraction, m.nat)
+ return x
+}
+
+// montgomeryRepresentation calculates x = x * R mod m, with R = 2^(_W * n) and
+// n = len(m.nat.limbs).
+//
+// Faster Montgomery multiplication replaces standard modular multiplication for
+// numbers in this representation.
+//
+// This assumes that x is already reduced mod m.
+func (x *Nat) montgomeryRepresentation(m *Modulus) *Nat {
+ // A Montgomery multiplication (which computes a * b / R) by R * R works out
+ // to a multiplication by R, which takes the value out of the Montgomery domain.
+ return x.montgomeryMul(NewNat().set(x), m.rr, m)
+}
+
+// montgomeryReduction calculates x = x / R mod m, with R = 2^(_W * n) and
+// n = len(m.nat.limbs).
+//
+// This assumes that x is already reduced mod m.
+func (x *Nat) montgomeryReduction(m *Modulus) *Nat {
+ // By Montgomery multiplying with 1 not in Montgomery representation, we
+ // convert out back from Montgomery representation, because it works out to
+ // dividing by R.
+ t0 := NewNat().set(x)
+ t1 := NewNat().ExpandFor(m)
+ t1.limbs[0] = 1
+ return x.montgomeryMul(t0, t1, m)
+}
+
+// montgomeryMul calculates d = a * b / R mod m, with R = 2^(_W * n) and
+// n = len(m.nat.limbs), using the Montgomery Multiplication technique.
+//
+// All inputs should be the same length, not aliasing d, and already
+// reduced modulo m. d will be resized to the size of m and overwritten.
+func (d *Nat) montgomeryMul(a *Nat, b *Nat, m *Modulus) *Nat {
+ d.resetFor(m)
+ if len(a.limbs) != len(m.nat.limbs) || len(b.limbs) != len(m.nat.limbs) {
+ panic("bigmod: invalid montgomeryMul input")
+ }
+
+ // See https://bearssl.org/bigint.html#montgomery-reduction-and-multiplication
+ // for a description of the algorithm implemented mostly in montgomeryLoop.
+ // See Add for how overflow, underflow, and needSubtraction relate.
+ overflow := montgomeryLoop(d.limbs, a.limbs, b.limbs, m.nat.limbs, m.m0inv)
+ underflow := not(d.cmpGeq(m.nat)) // d < m
+ needSubtraction := ctEq(overflow, uint(underflow))
+ d.sub(needSubtraction, m.nat)
+
+ return d
+}
+
+func montgomeryLoopGeneric(d, a, b, m []uint, m0inv uint) (overflow uint) {
+ // Eliminate bounds checks in the loop.
+ size := len(d)
+ a = a[:size]
+ b = b[:size]
+ m = m[:size]
+
+ for _, ai := range a {
+ // This is an unrolled iteration of the loop below with j = 0.
+ hi, lo := bits.Mul(ai, b[0])
+ z_lo, c := bits.Add(d[0], lo, 0)
+ f := (z_lo * m0inv) & _MASK // (d[0] + a[i] * b[0]) * m0inv
+ z_hi, _ := bits.Add(0, hi, c)
+ hi, lo = bits.Mul(f, m[0])
+ z_lo, c = bits.Add(z_lo, lo, 0)
+ z_hi, _ = bits.Add(z_hi, hi, c)
+ carry := z_hi<<1 | z_lo>>_W
+
+ for j := 1; j < size; j++ {
+ // z = d[j] + a[i] * b[j] + f * m[j] + carry <= 2^(2W+1) - 2^(W+1) + 2^W
+ hi, lo := bits.Mul(ai, b[j])
+ z_lo, c := bits.Add(d[j], lo, 0)
+ z_hi, _ := bits.Add(0, hi, c)
+ hi, lo = bits.Mul(f, m[j])
+ z_lo, c = bits.Add(z_lo, lo, 0)
+ z_hi, _ = bits.Add(z_hi, hi, c)
+ z_lo, c = bits.Add(z_lo, carry, 0)
+ z_hi, _ = bits.Add(z_hi, 0, c)
+ d[j-1] = z_lo & _MASK
+ carry = z_hi<<1 | z_lo>>_W // carry <= 2^(W+1) - 2
+ }
+
+ z := overflow + carry // z <= 2^(W+1) - 1
+ d[size-1] = z & _MASK
+ overflow = z >> _W // overflow <= 1
+ }
+ return
+}
+
+// Mul calculates x *= y mod m.
+//
+// x and y must already be reduced modulo m, they must share its announced
+// length, and they may not alias.
+func (x *Nat) Mul(y *Nat, m *Modulus) *Nat {
+ // A Montgomery multiplication by a value out of the Montgomery domain
+ // takes the result out of Montgomery representation.
+ xR := NewNat().set(x).montgomeryRepresentation(m) // xR = x * R mod m
+ return x.montgomeryMul(xR, y, m) // x = xR * y / R mod m
+}
+
+// Exp calculates out = x^e mod m.
+//
+// The exponent e is represented in big-endian order. The output will be resized
+// to the size of m and overwritten. x must already be reduced modulo m.
+func (out *Nat) Exp(x *Nat, e []byte, m *Modulus) *Nat {
+ // We use a 4 bit window. For our RSA workload, 4 bit windows are faster
+ // than 2 bit windows, but use an extra 12 nats worth of scratch space.
+ // Using bit sizes that don't divide 8 are more complex to implement.
+
+ table := [(1 << 4) - 1]*Nat{ // table[i] = x ^ (i+1)
+ // newNat calls are unrolled so they are allocated on the stack.
+ NewNat(), NewNat(), NewNat(), NewNat(), NewNat(),
+ NewNat(), NewNat(), NewNat(), NewNat(), NewNat(),
+ NewNat(), NewNat(), NewNat(), NewNat(), NewNat(),
+ }
+ table[0].set(x).montgomeryRepresentation(m)
+ for i := 1; i < len(table); i++ {
+ table[i].montgomeryMul(table[i-1], table[0], m)
+ }
+
+ out.resetFor(m)
+ out.limbs[0] = 1
+ out.montgomeryRepresentation(m)
+ t0 := NewNat().ExpandFor(m)
+ t1 := NewNat().ExpandFor(m)
+ for _, b := range e {
+ for _, j := range []int{4, 0} {
+ // Square four times.
+ t1.montgomeryMul(out, out, m)
+ out.montgomeryMul(t1, t1, m)
+ t1.montgomeryMul(out, out, m)
+ out.montgomeryMul(t1, t1, m)
+
+ // Select x^k in constant time from the table.
+ k := uint((b >> j) & 0b1111)
+ for i := range table {
+ t0.assign(ctEq(k, uint(i+1)), table[i])
+ }
+
+ // Multiply by x^k, discarding the result if k = 0.
+ t1.montgomeryMul(out, t0, m)
+ out.assign(not(ctEq(k, 0)), t1)
+ }
+ }
+
+ return out.montgomeryReduction(m)
+}
diff --git a/src/crypto/internal/bigmod/nat_amd64.go b/src/crypto/internal/bigmod/nat_amd64.go
new file mode 100644
index 0000000..e947782
--- /dev/null
+++ b/src/crypto/internal/bigmod/nat_amd64.go
@@ -0,0 +1,8 @@
+// Code generated by command: go run nat_amd64_asm.go -out ../nat_amd64.s -stubs ../nat_amd64.go -pkg bigmod. DO NOT EDIT.
+
+//go:build amd64 && gc && !purego
+
+package bigmod
+
+//go:noescape
+func montgomeryLoop(d []uint, a []uint, b []uint, m []uint, m0inv uint) uint
diff --git a/src/crypto/internal/bigmod/nat_amd64.s b/src/crypto/internal/bigmod/nat_amd64.s
new file mode 100644
index 0000000..12b7629
--- /dev/null
+++ b/src/crypto/internal/bigmod/nat_amd64.s
@@ -0,0 +1,68 @@
+// Code generated by command: go run nat_amd64_asm.go -out ../nat_amd64.s -stubs ../nat_amd64.go -pkg bigmod. DO NOT EDIT.
+
+//go:build amd64 && gc && !purego
+
+// func montgomeryLoop(d []uint, a []uint, b []uint, m []uint, m0inv uint) uint
+TEXT ·montgomeryLoop(SB), $8-112
+ MOVQ d_len+8(FP), CX
+ MOVQ d_base+0(FP), BX
+ MOVQ b_base+48(FP), SI
+ MOVQ m_base+72(FP), DI
+ MOVQ m0inv+96(FP), R8
+ XORQ R9, R9
+ XORQ R10, R10
+
+outerLoop:
+ MOVQ a_base+24(FP), R11
+ MOVQ (R11)(R10*8), R11
+ MOVQ (SI), AX
+ MULQ R11
+ MOVQ AX, R13
+ MOVQ DX, R12
+ ADDQ (BX), R13
+ ADCQ $0x00, R12
+ MOVQ R8, R14
+ IMULQ R13, R14
+ BTRQ $0x3f, R14
+ MOVQ (DI), AX
+ MULQ R14
+ ADDQ AX, R13
+ ADCQ DX, R12
+ SHRQ $0x3f, R12, R13
+ XORQ R12, R12
+ INCQ R12
+ JMP innerLoopCondition
+
+innerLoop:
+ MOVQ (SI)(R12*8), AX
+ MULQ R11
+ MOVQ AX, BP
+ MOVQ DX, R15
+ MOVQ (DI)(R12*8), AX
+ MULQ R14
+ ADDQ AX, BP
+ ADCQ DX, R15
+ ADDQ (BX)(R12*8), BP
+ ADCQ $0x00, R15
+ ADDQ R13, BP
+ ADCQ $0x00, R15
+ MOVQ BP, AX
+ BTRQ $0x3f, AX
+ MOVQ AX, -8(BX)(R12*8)
+ SHRQ $0x3f, R15, BP
+ MOVQ BP, R13
+ INCQ R12
+
+innerLoopCondition:
+ CMPQ CX, R12
+ JGT innerLoop
+ ADDQ R13, R9
+ MOVQ R9, AX
+ BTRQ $0x3f, AX
+ MOVQ AX, -8(BX)(CX*8)
+ SHRQ $0x3f, R9
+ INCQ R10
+ CMPQ CX, R10
+ JGT outerLoop
+ MOVQ R9, ret+104(FP)
+ RET
diff --git a/src/crypto/internal/bigmod/nat_noasm.go b/src/crypto/internal/bigmod/nat_noasm.go
new file mode 100644
index 0000000..870b445
--- /dev/null
+++ b/src/crypto/internal/bigmod/nat_noasm.go
@@ -0,0 +1,11 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !amd64 || !gc || purego
+
+package bigmod
+
+func montgomeryLoop(d, a, b, m []uint, m0inv uint) uint {
+ return montgomeryLoopGeneric(d, a, b, m, m0inv)
+}
diff --git a/src/crypto/internal/bigmod/nat_test.go b/src/crypto/internal/bigmod/nat_test.go
new file mode 100644
index 0000000..6431d25
--- /dev/null
+++ b/src/crypto/internal/bigmod/nat_test.go
@@ -0,0 +1,412 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bigmod
+
+import (
+ "math/big"
+ "math/bits"
+ "math/rand"
+ "reflect"
+ "testing"
+ "testing/quick"
+)
+
+// Generate generates an even nat. It's used by testing/quick to produce random
+// *nat values for quick.Check invocations.
+func (*Nat) Generate(r *rand.Rand, size int) reflect.Value {
+ limbs := make([]uint, size)
+ for i := 0; i < size; i++ {
+ limbs[i] = uint(r.Uint64()) & ((1 << _W) - 2)
+ }
+ return reflect.ValueOf(&Nat{limbs})
+}
+
+func testModAddCommutative(a *Nat, b *Nat) bool {
+ m := maxModulus(uint(len(a.limbs)))
+ aPlusB := new(Nat).set(a)
+ aPlusB.Add(b, m)
+ bPlusA := new(Nat).set(b)
+ bPlusA.Add(a, m)
+ return aPlusB.Equal(bPlusA) == 1
+}
+
+func TestModAddCommutative(t *testing.T) {
+ err := quick.Check(testModAddCommutative, &quick.Config{})
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func testModSubThenAddIdentity(a *Nat, b *Nat) bool {
+ m := maxModulus(uint(len(a.limbs)))
+ original := new(Nat).set(a)
+ a.Sub(b, m)
+ a.Add(b, m)
+ return a.Equal(original) == 1
+}
+
+func TestModSubThenAddIdentity(t *testing.T) {
+ err := quick.Check(testModSubThenAddIdentity, &quick.Config{})
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func testMontgomeryRoundtrip(a *Nat) bool {
+ one := &Nat{make([]uint, len(a.limbs))}
+ one.limbs[0] = 1
+ aPlusOne := new(big.Int).SetBytes(natBytes(a))
+ aPlusOne.Add(aPlusOne, big.NewInt(1))
+ m := NewModulusFromBig(aPlusOne)
+ monty := new(Nat).set(a)
+ monty.montgomeryRepresentation(m)
+ aAgain := new(Nat).set(monty)
+ aAgain.montgomeryMul(monty, one, m)
+ return a.Equal(aAgain) == 1
+}
+
+func TestMontgomeryRoundtrip(t *testing.T) {
+ err := quick.Check(testMontgomeryRoundtrip, &quick.Config{})
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestShiftIn(t *testing.T) {
+ if bits.UintSize != 64 {
+ t.Skip("examples are only valid in 64 bit")
+ }
+ examples := []struct {
+ m, x, expected []byte
+ y uint64
+ }{{
+ m: []byte{13},
+ x: []byte{0},
+ y: 0x7FFF_FFFF_FFFF_FFFF,
+ expected: []byte{7},
+ }, {
+ m: []byte{13},
+ x: []byte{7},
+ y: 0x7FFF_FFFF_FFFF_FFFF,
+ expected: []byte{11},
+ }, {
+ m: []byte{0x06, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d},
+ x: make([]byte, 9),
+ y: 0x7FFF_FFFF_FFFF_FFFF,
+ expected: []byte{0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ }, {
+ m: []byte{0x06, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d},
+ x: []byte{0x00, 0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ y: 0,
+ expected: []byte{0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x08},
+ }}
+
+ for i, tt := range examples {
+ m := modulusFromBytes(tt.m)
+ got := natFromBytes(tt.x).ExpandFor(m).shiftIn(uint(tt.y), m)
+ if got.Equal(natFromBytes(tt.expected).ExpandFor(m)) != 1 {
+ t.Errorf("%d: got %x, expected %x", i, got, tt.expected)
+ }
+ }
+}
+
+func TestModulusAndNatSizes(t *testing.T) {
+ // These are 126 bit (2 * _W on 64-bit architectures) values, serialized as
+ // 128 bits worth of bytes. If leading zeroes are stripped, they fit in two
+ // limbs, if they are not, they fit in three. This can be a problem because
+ // modulus strips leading zeroes and nat does not.
+ m := modulusFromBytes([]byte{
+ 0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff})
+ xb := []byte{0x3f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe}
+ natFromBytes(xb).ExpandFor(m) // must not panic for shrinking
+ NewNat().SetBytes(xb, m)
+}
+
+func TestSetBytes(t *testing.T) {
+ tests := []struct {
+ m, b []byte
+ fail bool
+ }{{
+ m: []byte{0xff, 0xff},
+ b: []byte{0x00, 0x01},
+ }, {
+ m: []byte{0xff, 0xff},
+ b: []byte{0xff, 0xff},
+ fail: true,
+ }, {
+ m: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ b: []byte{0x00, 0x01},
+ }, {
+ m: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ b: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe},
+ }, {
+ m: []byte{0xff, 0xff},
+ b: []byte{0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ fail: true,
+ }, {
+ m: []byte{0xff, 0xff},
+ b: []byte{0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ fail: true,
+ }, {
+ m: []byte{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ b: []byte{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe},
+ }, {
+ m: []byte{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ b: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe},
+ fail: true,
+ }, {
+ m: []byte{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ b: []byte{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ fail: true,
+ }, {
+ m: []byte{0x7f, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ b: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfe},
+ fail: true,
+ }, {
+ m: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xfd},
+ b: []byte{0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff},
+ fail: true,
+ }}
+
+ for i, tt := range tests {
+ m := modulusFromBytes(tt.m)
+ got, err := NewNat().SetBytes(tt.b, m)
+ if err != nil {
+ if !tt.fail {
+ t.Errorf("%d: unexpected error: %v", i, err)
+ }
+ continue
+ }
+ if err == nil && tt.fail {
+ t.Errorf("%d: unexpected success", i)
+ continue
+ }
+ if expected := natFromBytes(tt.b).ExpandFor(m); got.Equal(expected) != yes {
+ t.Errorf("%d: got %x, expected %x", i, got, expected)
+ }
+ }
+
+ f := func(xBytes []byte) bool {
+ m := maxModulus(uint(len(xBytes)*8/_W + 1))
+ got, err := NewNat().SetBytes(xBytes, m)
+ if err != nil {
+ return false
+ }
+ return got.Equal(natFromBytes(xBytes).ExpandFor(m)) == yes
+ }
+
+ err := quick.Check(f, &quick.Config{})
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func TestExpand(t *testing.T) {
+ sliced := []uint{1, 2, 3, 4}
+ examples := []struct {
+ in []uint
+ n int
+ out []uint
+ }{{
+ []uint{1, 2},
+ 4,
+ []uint{1, 2, 0, 0},
+ }, {
+ sliced[:2],
+ 4,
+ []uint{1, 2, 0, 0},
+ }, {
+ []uint{1, 2},
+ 2,
+ []uint{1, 2},
+ }}
+
+ for i, tt := range examples {
+ got := (&Nat{tt.in}).expand(tt.n)
+ if len(got.limbs) != len(tt.out) || got.Equal(&Nat{tt.out}) != 1 {
+ t.Errorf("%d: got %x, expected %x", i, got, tt.out)
+ }
+ }
+}
+
+func TestMod(t *testing.T) {
+ m := modulusFromBytes([]byte{0x06, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0d})
+ x := natFromBytes([]byte{0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01})
+ out := new(Nat)
+ out.Mod(x, m)
+ expected := natFromBytes([]byte{0x04, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x09})
+ if out.Equal(expected) != 1 {
+ t.Errorf("%+v != %+v", out, expected)
+ }
+}
+
+func TestModSub(t *testing.T) {
+ m := modulusFromBytes([]byte{13})
+ x := &Nat{[]uint{6}}
+ y := &Nat{[]uint{7}}
+ x.Sub(y, m)
+ expected := &Nat{[]uint{12}}
+ if x.Equal(expected) != 1 {
+ t.Errorf("%+v != %+v", x, expected)
+ }
+ x.Sub(y, m)
+ expected = &Nat{[]uint{5}}
+ if x.Equal(expected) != 1 {
+ t.Errorf("%+v != %+v", x, expected)
+ }
+}
+
+func TestModAdd(t *testing.T) {
+ m := modulusFromBytes([]byte{13})
+ x := &Nat{[]uint{6}}
+ y := &Nat{[]uint{7}}
+ x.Add(y, m)
+ expected := &Nat{[]uint{0}}
+ if x.Equal(expected) != 1 {
+ t.Errorf("%+v != %+v", x, expected)
+ }
+ x.Add(y, m)
+ expected = &Nat{[]uint{7}}
+ if x.Equal(expected) != 1 {
+ t.Errorf("%+v != %+v", x, expected)
+ }
+}
+
+func TestExp(t *testing.T) {
+ m := modulusFromBytes([]byte{13})
+ x := &Nat{[]uint{3}}
+ out := &Nat{[]uint{0}}
+ out.Exp(x, []byte{12}, m)
+ expected := &Nat{[]uint{1}}
+ if out.Equal(expected) != 1 {
+ t.Errorf("%+v != %+v", out, expected)
+ }
+}
+
+func natBytes(n *Nat) []byte {
+ return n.Bytes(maxModulus(uint(len(n.limbs))))
+}
+
+func natFromBytes(b []byte) *Nat {
+ bb := new(big.Int).SetBytes(b)
+ return NewNat().setBig(bb)
+}
+
+func modulusFromBytes(b []byte) *Modulus {
+ bb := new(big.Int).SetBytes(b)
+ return NewModulusFromBig(bb)
+}
+
+// maxModulus returns the biggest modulus that can fit in n limbs.
+func maxModulus(n uint) *Modulus {
+ m := big.NewInt(1)
+ m.Lsh(m, n*_W)
+ m.Sub(m, big.NewInt(1))
+ return NewModulusFromBig(m)
+}
+
+func makeBenchmarkModulus() *Modulus {
+ return maxModulus(32)
+}
+
+func makeBenchmarkValue() *Nat {
+ x := make([]uint, 32)
+ for i := 0; i < 32; i++ {
+ x[i] = _MASK - 1
+ }
+ return &Nat{limbs: x}
+}
+
+func makeBenchmarkExponent() []byte {
+ e := make([]byte, 256)
+ for i := 0; i < 32; i++ {
+ e[i] = 0xFF
+ }
+ return e
+}
+
+func BenchmarkModAdd(b *testing.B) {
+ x := makeBenchmarkValue()
+ y := makeBenchmarkValue()
+ m := makeBenchmarkModulus()
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ x.Add(y, m)
+ }
+}
+
+func BenchmarkModSub(b *testing.B) {
+ x := makeBenchmarkValue()
+ y := makeBenchmarkValue()
+ m := makeBenchmarkModulus()
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ x.Sub(y, m)
+ }
+}
+
+func BenchmarkMontgomeryRepr(b *testing.B) {
+ x := makeBenchmarkValue()
+ m := makeBenchmarkModulus()
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ x.montgomeryRepresentation(m)
+ }
+}
+
+func BenchmarkMontgomeryMul(b *testing.B) {
+ x := makeBenchmarkValue()
+ y := makeBenchmarkValue()
+ out := makeBenchmarkValue()
+ m := makeBenchmarkModulus()
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ out.montgomeryMul(x, y, m)
+ }
+}
+
+func BenchmarkModMul(b *testing.B) {
+ x := makeBenchmarkValue()
+ y := makeBenchmarkValue()
+ m := makeBenchmarkModulus()
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ x.Mul(y, m)
+ }
+}
+
+func BenchmarkExpBig(b *testing.B) {
+ out := new(big.Int)
+ exponentBytes := makeBenchmarkExponent()
+ x := new(big.Int).SetBytes(exponentBytes)
+ e := new(big.Int).SetBytes(exponentBytes)
+ n := new(big.Int).SetBytes(exponentBytes)
+ one := new(big.Int).SetUint64(1)
+ n.Add(n, one)
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ out.Exp(x, e, n)
+ }
+}
+
+func BenchmarkExp(b *testing.B) {
+ x := makeBenchmarkValue()
+ e := makeBenchmarkExponent()
+ out := makeBenchmarkValue()
+ m := makeBenchmarkModulus()
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ out.Exp(x, e, m)
+ }
+}
diff --git a/src/crypto/internal/boring/Dockerfile b/src/crypto/internal/boring/Dockerfile
new file mode 100644
index 0000000..58eb028
--- /dev/null
+++ b/src/crypto/internal/boring/Dockerfile
@@ -0,0 +1,63 @@
+# Copyright 2020 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Run this using build.sh.
+
+ARG ubuntu=ubuntu
+FROM $ubuntu:focal
+
+RUN mkdir /boring
+WORKDIR /boring
+
+ENV LANG=C
+ENV LANGUAGE=
+
+# Following NIST submission draft dated July 3, 2021.
+# This corresponds to boringssl.googlesource.com/boringssl tag fips-20210429.
+ENV ClangV=12
+RUN apt-get update && \
+ apt-get install --no-install-recommends -y cmake xz-utils wget unzip ca-certificates clang-$ClangV python
+
+# Download, validate, unpack, build, and install Ninja.
+ENV NinjaV=1.10.2
+ENV NinjaH=ce35865411f0490368a8fc383f29071de6690cbadc27704734978221f25e2bed
+RUN \
+ wget https://github.com/ninja-build/ninja/archive/refs/tags/v$NinjaV.tar.gz && \
+ echo "$NinjaH v$NinjaV.tar.gz" >sha && sha256sum -c sha && \
+ tar -xzf v$NinjaV.tar.gz && \
+ rm v$NinjaV.tar.gz && \
+ cd ninja-$NinjaV && \
+ CC=clang-$ClangV CXX=clang++-$ClangV ./configure.py --bootstrap && \
+ mv ninja /usr/local/bin/
+
+# Download, validate, unpack, and install Go.
+ARG GOARCH
+ENV GoV=1.16.5
+ENV GoHamd64=b12c23023b68de22f74c0524f10b753e7b08b1504cb7e417eccebdd3fae49061
+ENV GoHarm64=d5446b46ef6f36fdffa852f73dfbbe78c1ddf010b99fa4964944b9ae8b4d6799
+RUN \
+ eval GoH=\${GoH$GOARCH} && \
+ wget https://golang.org/dl/go$GoV.linux-$GOARCH.tar.gz && \
+ echo "$GoH go$GoV.linux-$GOARCH.tar.gz" >sha && sha256sum -c sha && \
+ tar -C /usr/local -xzf go$GoV.linux-$GOARCH.tar.gz && \
+ rm go$GoV.linux-$GOARCH.tar.gz && \
+ ln -s /usr/local/go/bin/go /usr/local/bin/
+
+# Download, validate, and unpack BoringCrypto.
+ENV BoringV=853ca1ea1168dff08011e5d42d94609cc0ca2e27
+ENV BoringH=a4d069ccef6f3c7bc0c68de82b91414f05cb817494cd1ab483dcf3368883c7c2
+RUN \
+ wget https://commondatastorage.googleapis.com/chromium-boringssl-fips/boringssl-$BoringV.tar.xz && \
+ echo "$BoringH boringssl-$BoringV.tar.xz" >sha && sha256sum -c sha && \
+ tar xJf boringssl-$BoringV.tar.xz
+
+# Build BoringCrypto.
+ADD build-boring.sh /boring/build-boring.sh
+RUN /boring/build-boring.sh
+
+# Build Go BoringCrypto syso.
+# build.sh copies it back out of the Docker image.
+ADD goboringcrypto.h /boring/godriver/goboringcrypto.h
+ADD build-goboring.sh /boring/build-goboring.sh
+RUN /boring/build-goboring.sh
diff --git a/src/crypto/internal/boring/LICENSE b/src/crypto/internal/boring/LICENSE
new file mode 100644
index 0000000..38990bd
--- /dev/null
+++ b/src/crypto/internal/boring/LICENSE
@@ -0,0 +1,202 @@
+The Go source code and supporting files in this directory
+are covered by the usual Go license (see ../../../../LICENSE).
+
+When building with GOEXPERIMENT=boringcrypto, the following applies.
+
+The goboringcrypto_linux_amd64.syso object file is built
+from BoringSSL source code by build/build.sh and is covered
+by the BoringSSL license reproduced below and also at
+https://boringssl.googlesource.com/boringssl/+/fips-20190808/LICENSE.
+
+BoringSSL is a fork of OpenSSL. As such, large parts of it fall under OpenSSL
+licensing. Files that are completely new have a Google copyright and an ISC
+license. This license is reproduced at the bottom of this file.
+
+Contributors to BoringSSL are required to follow the CLA rules for Chromium:
+https://cla.developers.google.com/clas
+
+Some files from Intel are under yet another license, which is also included
+underneath.
+
+The OpenSSL toolkit stays under a dual license, i.e. both the conditions of the
+OpenSSL License and the original SSLeay license apply to the toolkit. See below
+for the actual license texts. Actually both licenses are BSD-style Open Source
+licenses. In case of any license issues related to OpenSSL please contact
+openssl-core@openssl.org.
+
+The following are Google-internal bug numbers where explicit permission from
+some authors is recorded for use of their work. (This is purely for our own
+record keeping.)
+ 27287199
+ 27287880
+ 27287883
+
+ OpenSSL License
+ ---------------
+
+/* ====================================================================
+ * Copyright (c) 1998-2011 The OpenSSL Project. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in
+ * the documentation and/or other materials provided with the
+ * distribution.
+ *
+ * 3. All advertising materials mentioning features or use of this
+ * software must display the following acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit. (http://www.openssl.org/)"
+ *
+ * 4. The names "OpenSSL Toolkit" and "OpenSSL Project" must not be used to
+ * endorse or promote products derived from this software without
+ * prior written permission. For written permission, please contact
+ * openssl-core@openssl.org.
+ *
+ * 5. Products derived from this software may not be called "OpenSSL"
+ * nor may "OpenSSL" appear in their names without prior written
+ * permission of the OpenSSL Project.
+ *
+ * 6. Redistributions of any form whatsoever must retain the following
+ * acknowledgment:
+ * "This product includes software developed by the OpenSSL Project
+ * for use in the OpenSSL Toolkit (http://www.openssl.org/)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE OpenSSL PROJECT ``AS IS'' AND ANY
+ * EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE OpenSSL PROJECT OR
+ * ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+ * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+ * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+ * OF THE POSSIBILITY OF SUCH DAMAGE.
+ * ====================================================================
+ *
+ * This product includes cryptographic software written by Eric Young
+ * (eay@cryptsoft.com). This product includes software written by Tim
+ * Hudson (tjh@cryptsoft.com).
+ *
+ */
+
+ Original SSLeay License
+ -----------------------
+
+/* Copyright (C) 1995-1998 Eric Young (eay@cryptsoft.com)
+ * All rights reserved.
+ *
+ * This package is an SSL implementation written
+ * by Eric Young (eay@cryptsoft.com).
+ * The implementation was written so as to conform with Netscapes SSL.
+ *
+ * This library is free for commercial and non-commercial use as long as
+ * the following conditions are aheared to. The following conditions
+ * apply to all code found in this distribution, be it the RC4, RSA,
+ * lhash, DES, etc., code; not just the SSL code. The SSL documentation
+ * included with this distribution is covered by the same copyright terms
+ * except that the holder is Tim Hudson (tjh@cryptsoft.com).
+ *
+ * Copyright remains Eric Young's, and as such any Copyright notices in
+ * the code are not to be removed.
+ * If this package is used in a product, Eric Young should be given attribution
+ * as the author of the parts of the library used.
+ * This can be in the form of a textual message at program startup or
+ * in documentation (online or textual) provided with the package.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. All advertising materials mentioning features or use of this software
+ * must display the following acknowledgement:
+ * "This product includes cryptographic software written by
+ * Eric Young (eay@cryptsoft.com)"
+ * The word 'cryptographic' can be left out if the rouines from the library
+ * being used are not cryptographic related :-).
+ * 4. If you include any Windows specific code (or a derivative thereof) from
+ * the apps directory (application code) you must include an acknowledgement:
+ * "This product includes software written by Tim Hudson (tjh@cryptsoft.com)"
+ *
+ * THIS SOFTWARE IS PROVIDED BY ERIC YOUNG ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ *
+ * The licence and distribution terms for any publically available version or
+ * derivative of this code cannot be changed. i.e. this code cannot simply be
+ * copied and put under another distribution licence
+ * [including the GNU Public Licence.]
+ */
+
+
+ISC license used for completely new code in BoringSSL:
+
+/* Copyright (c) 2015, Google Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. */
+
+
+Some files from Intel carry the following license:
+
+# Copyright (c) 2012, Intel Corporation
+#
+# All rights reserved.
+#
+# Redistribution and use in source and binary forms, with or without
+# modification, are permitted provided that the following conditions are
+# met:
+#
+# * Redistributions of source code must retain the above copyright
+# notice, this list of conditions and the following disclaimer.
+#
+# * Redistributions in binary form must reproduce the above copyright
+# notice, this list of conditions and the following disclaimer in the
+# documentation and/or other materials provided with the
+# distribution.
+#
+# * Neither the name of the Intel Corporation nor the names of its
+# contributors may be used to endorse or promote products derived from
+# this software without specific prior written permission.
+#
+#
+# THIS SOFTWARE IS PROVIDED BY INTEL CORPORATION ""AS IS"" AND ANY
+# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL INTEL CORPORATION OR
+# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
diff --git a/src/crypto/internal/boring/README.md b/src/crypto/internal/boring/README.md
new file mode 100644
index 0000000..ec02786
--- /dev/null
+++ b/src/crypto/internal/boring/README.md
@@ -0,0 +1,39 @@
+We have been working inside Google on a fork of Go that uses
+BoringCrypto (the core of [BoringSSL](https://boringssl.googlesource.com/boringssl/))
+for various crypto primitives, in furtherance of some work related to FIPS 140.
+We have heard that some external users of Go would be
+interested in this code as well, so we have published this code
+here in the main Go repository behind the setting GOEXPERIMENT=boringcrypto.
+
+Use of GOEXPERIMENT=boringcrypto outside Google is _unsupported_.
+This mode is not part of the [Go 1 compatibility rules](https://go.dev/doc/go1compat),
+and it may change incompatibly or break in other ways at any time.
+
+To be clear, we are not making any statements or representations about
+the suitability of this code in relation to the FIPS 140 standard.
+Interested users will have to evaluate for themselves whether the code
+is useful for their own purposes.
+
+---
+
+This directory holds the core of the BoringCrypto implementation
+as well as the build scripts for the module itself: syso/*.syso.
+
+syso/goboringcrypto_linux_amd64.syso is built with:
+
+ GOARCH=amd64 ./build.sh
+
+syso/goboringcrypto_linux_arm64.syso is built with:
+
+ GOARCH=arm64 ./build.sh
+
+Both run on an x86 Debian Linux system using Docker.
+For the arm64 build to run on an x86 system, you need
+
+ apt-get install qemu-user-static qemu-binfmt-support
+
+to allow the x86 kernel to run arm64 binaries via QEMU.
+
+See build.sh for more details about the build.
+
+
diff --git a/src/crypto/internal/boring/aes.go b/src/crypto/internal/boring/aes.go
new file mode 100644
index 0000000..6fae1d5
--- /dev/null
+++ b/src/crypto/internal/boring/aes.go
@@ -0,0 +1,385 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto && linux && (amd64 || arm64) && !android && !cmd_go_bootstrap && !msan
+
+package boring
+
+/*
+
+#include "goboringcrypto.h"
+
+// These wrappers allocate out_len on the C stack, and check that it matches the expected
+// value, to avoid having to pass a pointer from Go, which would escape to the heap.
+
+int EVP_AEAD_CTX_seal_wrapper(const GO_EVP_AEAD_CTX *ctx, uint8_t *out,
+ size_t exp_out_len,
+ const uint8_t *nonce, size_t nonce_len,
+ const uint8_t *in, size_t in_len,
+ const uint8_t *ad, size_t ad_len) {
+ size_t out_len;
+ int ok = _goboringcrypto_EVP_AEAD_CTX_seal(ctx, out, &out_len, exp_out_len,
+ nonce, nonce_len, in, in_len, ad, ad_len);
+ if (out_len != exp_out_len) {
+ return 0;
+ }
+ return ok;
+};
+
+int EVP_AEAD_CTX_open_wrapper(const GO_EVP_AEAD_CTX *ctx, uint8_t *out,
+ size_t exp_out_len,
+ const uint8_t *nonce, size_t nonce_len,
+ const uint8_t *in, size_t in_len,
+ const uint8_t *ad, size_t ad_len) {
+ size_t out_len;
+ int ok = _goboringcrypto_EVP_AEAD_CTX_open(ctx, out, &out_len, exp_out_len,
+ nonce, nonce_len, in, in_len, ad, ad_len);
+ if (out_len != exp_out_len) {
+ return 0;
+ }
+ return ok;
+};
+
+*/
+import "C"
+import (
+ "bytes"
+ "crypto/cipher"
+ "errors"
+ "runtime"
+ "strconv"
+ "unsafe"
+)
+
+type aesKeySizeError int
+
+func (k aesKeySizeError) Error() string {
+ return "crypto/aes: invalid key size " + strconv.Itoa(int(k))
+}
+
+const aesBlockSize = 16
+
+type aesCipher struct {
+ key []byte
+ enc C.GO_AES_KEY
+ dec C.GO_AES_KEY
+}
+
+type extraModes interface {
+ // Copied out of crypto/aes/modes.go.
+ NewCBCEncrypter(iv []byte) cipher.BlockMode
+ NewCBCDecrypter(iv []byte) cipher.BlockMode
+ NewCTR(iv []byte) cipher.Stream
+ NewGCM(nonceSize, tagSize int) (cipher.AEAD, error)
+}
+
+var _ extraModes = (*aesCipher)(nil)
+
+func NewAESCipher(key []byte) (cipher.Block, error) {
+ c := &aesCipher{key: bytes.Clone(key)}
+ // Note: 0 is success, contradicting the usual BoringCrypto convention.
+ if C._goboringcrypto_AES_set_decrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.dec) != 0 ||
+ C._goboringcrypto_AES_set_encrypt_key((*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.uint(8*len(c.key)), &c.enc) != 0 {
+ return nil, aesKeySizeError(len(key))
+ }
+ return c, nil
+}
+
+func (c *aesCipher) BlockSize() int { return aesBlockSize }
+
+func (c *aesCipher) Encrypt(dst, src []byte) {
+ if inexactOverlap(dst, src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+ if len(src) < aesBlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < aesBlockSize {
+ panic("crypto/aes: output not full block")
+ }
+ C._goboringcrypto_AES_encrypt(
+ (*C.uint8_t)(unsafe.Pointer(&src[0])),
+ (*C.uint8_t)(unsafe.Pointer(&dst[0])),
+ &c.enc)
+}
+
+func (c *aesCipher) Decrypt(dst, src []byte) {
+ if inexactOverlap(dst, src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+ if len(src) < aesBlockSize {
+ panic("crypto/aes: input not full block")
+ }
+ if len(dst) < aesBlockSize {
+ panic("crypto/aes: output not full block")
+ }
+ C._goboringcrypto_AES_decrypt(
+ (*C.uint8_t)(unsafe.Pointer(&src[0])),
+ (*C.uint8_t)(unsafe.Pointer(&dst[0])),
+ &c.dec)
+}
+
+type aesCBC struct {
+ key *C.GO_AES_KEY
+ mode C.int
+ iv [aesBlockSize]byte
+}
+
+func (x *aesCBC) BlockSize() int { return aesBlockSize }
+
+func (x *aesCBC) CryptBlocks(dst, src []byte) {
+ if inexactOverlap(dst, src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+ if len(src)%aesBlockSize != 0 {
+ panic("crypto/cipher: input not full blocks")
+ }
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if len(src) > 0 {
+ C._goboringcrypto_AES_cbc_encrypt(
+ (*C.uint8_t)(unsafe.Pointer(&src[0])),
+ (*C.uint8_t)(unsafe.Pointer(&dst[0])),
+ C.size_t(len(src)), x.key,
+ (*C.uint8_t)(unsafe.Pointer(&x.iv[0])), x.mode)
+ }
+}
+
+func (x *aesCBC) SetIV(iv []byte) {
+ if len(iv) != aesBlockSize {
+ panic("cipher: incorrect length IV")
+ }
+ copy(x.iv[:], iv)
+}
+
+func (c *aesCipher) NewCBCEncrypter(iv []byte) cipher.BlockMode {
+ x := &aesCBC{key: &c.enc, mode: C.GO_AES_ENCRYPT}
+ copy(x.iv[:], iv)
+ return x
+}
+
+func (c *aesCipher) NewCBCDecrypter(iv []byte) cipher.BlockMode {
+ x := &aesCBC{key: &c.dec, mode: C.GO_AES_DECRYPT}
+ copy(x.iv[:], iv)
+ return x
+}
+
+type aesCTR struct {
+ key *C.GO_AES_KEY
+ iv [aesBlockSize]byte
+ num C.uint
+ ecount_buf [16]C.uint8_t
+}
+
+func (x *aesCTR) XORKeyStream(dst, src []byte) {
+ if inexactOverlap(dst, src) {
+ panic("crypto/cipher: invalid buffer overlap")
+ }
+ if len(dst) < len(src) {
+ panic("crypto/cipher: output smaller than input")
+ }
+ if len(src) == 0 {
+ return
+ }
+ C._goboringcrypto_AES_ctr128_encrypt(
+ (*C.uint8_t)(unsafe.Pointer(&src[0])),
+ (*C.uint8_t)(unsafe.Pointer(&dst[0])),
+ C.size_t(len(src)), x.key, (*C.uint8_t)(unsafe.Pointer(&x.iv[0])),
+ &x.ecount_buf[0], &x.num)
+}
+
+func (c *aesCipher) NewCTR(iv []byte) cipher.Stream {
+ x := &aesCTR{key: &c.enc}
+ copy(x.iv[:], iv)
+ return x
+}
+
+type aesGCM struct {
+ ctx C.GO_EVP_AEAD_CTX
+ aead *C.GO_EVP_AEAD
+}
+
+const (
+ gcmBlockSize = 16
+ gcmTagSize = 16
+ gcmStandardNonceSize = 12
+)
+
+type aesNonceSizeError int
+
+func (n aesNonceSizeError) Error() string {
+ return "crypto/aes: invalid GCM nonce size " + strconv.Itoa(int(n))
+}
+
+type noGCM struct {
+ cipher.Block
+}
+
+func (c *aesCipher) NewGCM(nonceSize, tagSize int) (cipher.AEAD, error) {
+ if nonceSize != gcmStandardNonceSize && tagSize != gcmTagSize {
+ return nil, errors.New("crypto/aes: GCM tag and nonce sizes can't be non-standard at the same time")
+ }
+ // Fall back to standard library for GCM with non-standard nonce or tag size.
+ if nonceSize != gcmStandardNonceSize {
+ return cipher.NewGCMWithNonceSize(&noGCM{c}, nonceSize)
+ }
+ if tagSize != gcmTagSize {
+ return cipher.NewGCMWithTagSize(&noGCM{c}, tagSize)
+ }
+ return c.newGCM(false)
+}
+
+func NewGCMTLS(c cipher.Block) (cipher.AEAD, error) {
+ return c.(*aesCipher).newGCM(true)
+}
+
+func (c *aesCipher) newGCM(tls bool) (cipher.AEAD, error) {
+ var aead *C.GO_EVP_AEAD
+ switch len(c.key) * 8 {
+ case 128:
+ if tls {
+ aead = C._goboringcrypto_EVP_aead_aes_128_gcm_tls12()
+ } else {
+ aead = C._goboringcrypto_EVP_aead_aes_128_gcm()
+ }
+ case 256:
+ if tls {
+ aead = C._goboringcrypto_EVP_aead_aes_256_gcm_tls12()
+ } else {
+ aead = C._goboringcrypto_EVP_aead_aes_256_gcm()
+ }
+ default:
+ // Fall back to standard library for GCM with non-standard key size.
+ return cipher.NewGCMWithNonceSize(&noGCM{c}, gcmStandardNonceSize)
+ }
+
+ g := &aesGCM{aead: aead}
+ if C._goboringcrypto_EVP_AEAD_CTX_init(&g.ctx, aead, (*C.uint8_t)(unsafe.Pointer(&c.key[0])), C.size_t(len(c.key)), C.GO_EVP_AEAD_DEFAULT_TAG_LENGTH, nil) == 0 {
+ return nil, fail("EVP_AEAD_CTX_init")
+ }
+ // Note: Because of the finalizer, any time g.ctx is passed to cgo,
+ // that call must be followed by a call to runtime.KeepAlive(g),
+ // to make sure g is not collected (and finalized) before the cgo
+ // call returns.
+ runtime.SetFinalizer(g, (*aesGCM).finalize)
+ if g.NonceSize() != gcmStandardNonceSize {
+ panic("boringcrypto: internal confusion about nonce size")
+ }
+ if g.Overhead() != gcmTagSize {
+ panic("boringcrypto: internal confusion about tag size")
+ }
+
+ return g, nil
+}
+
+func (g *aesGCM) finalize() {
+ C._goboringcrypto_EVP_AEAD_CTX_cleanup(&g.ctx)
+}
+
+func (g *aesGCM) NonceSize() int {
+ return int(C._goboringcrypto_EVP_AEAD_nonce_length(g.aead))
+}
+
+func (g *aesGCM) Overhead() int {
+ return int(C._goboringcrypto_EVP_AEAD_max_overhead(g.aead))
+}
+
+// base returns the address of the underlying array in b,
+// being careful not to panic when b has zero length.
+func base(b []byte) *C.uint8_t {
+ if len(b) == 0 {
+ return nil
+ }
+ return (*C.uint8_t)(unsafe.Pointer(&b[0]))
+}
+
+func (g *aesGCM) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
+ if len(nonce) != gcmStandardNonceSize {
+ panic("cipher: incorrect nonce length given to GCM")
+ }
+ if uint64(len(plaintext)) > ((1<<32)-2)*aesBlockSize || len(plaintext)+gcmTagSize < len(plaintext) {
+ panic("cipher: message too large for GCM")
+ }
+ if len(dst)+len(plaintext)+gcmTagSize < len(dst) {
+ panic("cipher: message too large for buffer")
+ }
+
+ // Make room in dst to append plaintext+overhead.
+ n := len(dst)
+ for cap(dst) < n+len(plaintext)+gcmTagSize {
+ dst = append(dst[:cap(dst)], 0)
+ }
+ dst = dst[:n+len(plaintext)+gcmTagSize]
+
+ // Check delayed until now to make sure len(dst) is accurate.
+ if inexactOverlap(dst[n:], plaintext) {
+ panic("cipher: invalid buffer overlap")
+ }
+
+ outLen := C.size_t(len(plaintext) + gcmTagSize)
+ ok := C.EVP_AEAD_CTX_seal_wrapper(
+ &g.ctx,
+ (*C.uint8_t)(unsafe.Pointer(&dst[n])), outLen,
+ base(nonce), C.size_t(len(nonce)),
+ base(plaintext), C.size_t(len(plaintext)),
+ base(additionalData), C.size_t(len(additionalData)))
+ runtime.KeepAlive(g)
+ if ok == 0 {
+ panic(fail("EVP_AEAD_CTX_seal"))
+ }
+ return dst[:n+int(outLen)]
+}
+
+var errOpen = errors.New("cipher: message authentication failed")
+
+func (g *aesGCM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ if len(nonce) != gcmStandardNonceSize {
+ panic("cipher: incorrect nonce length given to GCM")
+ }
+ if len(ciphertext) < gcmTagSize {
+ return nil, errOpen
+ }
+ if uint64(len(ciphertext)) > ((1<<32)-2)*aesBlockSize+gcmTagSize {
+ return nil, errOpen
+ }
+
+ // Make room in dst to append ciphertext without tag.
+ n := len(dst)
+ for cap(dst) < n+len(ciphertext)-gcmTagSize {
+ dst = append(dst[:cap(dst)], 0)
+ }
+ dst = dst[:n+len(ciphertext)-gcmTagSize]
+
+ // Check delayed until now to make sure len(dst) is accurate.
+ if inexactOverlap(dst[n:], ciphertext) {
+ panic("cipher: invalid buffer overlap")
+ }
+
+ outLen := C.size_t(len(ciphertext) - gcmTagSize)
+ ok := C.EVP_AEAD_CTX_open_wrapper(
+ &g.ctx,
+ base(dst[n:]), outLen,
+ base(nonce), C.size_t(len(nonce)),
+ base(ciphertext), C.size_t(len(ciphertext)),
+ base(additionalData), C.size_t(len(additionalData)))
+ runtime.KeepAlive(g)
+ if ok == 0 {
+ return nil, errOpen
+ }
+ return dst[:n+int(outLen)], nil
+}
+
+func anyOverlap(x, y []byte) bool {
+ return len(x) > 0 && len(y) > 0 &&
+ uintptr(unsafe.Pointer(&x[0])) <= uintptr(unsafe.Pointer(&y[len(y)-1])) &&
+ uintptr(unsafe.Pointer(&y[0])) <= uintptr(unsafe.Pointer(&x[len(x)-1]))
+}
+
+func inexactOverlap(x, y []byte) bool {
+ if len(x) == 0 || len(y) == 0 || &x[0] == &y[0] {
+ return false
+ }
+ return anyOverlap(x, y)
+}
diff --git a/src/crypto/internal/boring/bbig/big.go b/src/crypto/internal/boring/bbig/big.go
new file mode 100644
index 0000000..5ce4697
--- /dev/null
+++ b/src/crypto/internal/boring/bbig/big.go
@@ -0,0 +1,33 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bbig
+
+import (
+ "crypto/internal/boring"
+ "math/big"
+ "unsafe"
+)
+
+func Enc(b *big.Int) boring.BigInt {
+ if b == nil {
+ return nil
+ }
+ x := b.Bits()
+ if len(x) == 0 {
+ return boring.BigInt{}
+ }
+ return unsafe.Slice((*uint)(&x[0]), len(x))
+}
+
+func Dec(b boring.BigInt) *big.Int {
+ if b == nil {
+ return nil
+ }
+ if len(b) == 0 {
+ return new(big.Int)
+ }
+ x := unsafe.Slice((*big.Word)(&b[0]), len(b))
+ return new(big.Int).SetBits(x)
+}
diff --git a/src/crypto/internal/boring/bcache/cache.go b/src/crypto/internal/boring/bcache/cache.go
new file mode 100644
index 0000000..7934d03
--- /dev/null
+++ b/src/crypto/internal/boring/bcache/cache.go
@@ -0,0 +1,140 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package bcache implements a GC-friendly cache (see [Cache]) for BoringCrypto.
+package bcache
+
+import (
+ "sync/atomic"
+ "unsafe"
+)
+
+// A Cache is a GC-friendly concurrent map from unsafe.Pointer to
+// unsafe.Pointer. It is meant to be used for maintaining shadow
+// BoringCrypto state associated with certain allocated structs, in
+// particular public and private RSA and ECDSA keys.
+//
+// The cache is GC-friendly in the sense that the keys do not
+// indefinitely prevent the garbage collector from collecting them.
+// Instead, at the start of each GC, the cache is cleared entirely. That
+// is, the cache is lossy, and the loss happens at the start of each GC.
+// This means that clients need to be able to cope with cache entries
+// disappearing, but it also means that clients don't need to worry about
+// cache entries keeping the keys from being collected.
+type Cache[K, V any] struct {
+ // The runtime atomically stores nil to ptable at the start of each GC.
+ ptable atomic.Pointer[cacheTable[K, V]]
+}
+
+type cacheTable[K, V any] [cacheSize]atomic.Pointer[cacheEntry[K, V]]
+
+// A cacheEntry is a single entry in the linked list for a given hash table entry.
+type cacheEntry[K, V any] struct {
+ k *K // immutable once created
+ v atomic.Pointer[V] // read and written atomically to allow updates
+ next *cacheEntry[K, V] // immutable once linked into table
+}
+
+func registerCache(unsafe.Pointer) // provided by runtime
+
+// Register registers the cache with the runtime,
+// so that c.ptable can be cleared at the start of each GC.
+// Register must be called during package initialization.
+func (c *Cache[K, V]) Register() {
+ registerCache(unsafe.Pointer(&c.ptable))
+}
+
+// cacheSize is the number of entries in the hash table.
+// The hash is the pointer value mod cacheSize, a prime.
+// Collisions are resolved by maintaining a linked list in each hash slot.
+const cacheSize = 1021
+
+// table returns a pointer to the current cache hash table,
+// coping with the possibility of the GC clearing it out from under us.
+func (c *Cache[K, V]) table() *cacheTable[K, V] {
+ for {
+ p := c.ptable.Load()
+ if p == nil {
+ p = new(cacheTable[K, V])
+ if !c.ptable.CompareAndSwap(nil, p) {
+ continue
+ }
+ }
+ return p
+ }
+}
+
+// Clear clears the cache.
+// The runtime does this automatically at each garbage collection;
+// this method is exposed only for testing.
+func (c *Cache[K, V]) Clear() {
+ // The runtime does this at the start of every garbage collection
+ // (itself, not by calling this function).
+ c.ptable.Store(nil)
+}
+
+// Get returns the cached value associated with v,
+// which is either the value v corresponding to the most recent call to Put(k, v)
+// or nil if that cache entry has been dropped.
+func (c *Cache[K, V]) Get(k *K) *V {
+ head := &c.table()[uintptr(unsafe.Pointer(k))%cacheSize]
+ e := head.Load()
+ for ; e != nil; e = e.next {
+ if e.k == k {
+ return e.v.Load()
+ }
+ }
+ return nil
+}
+
+// Put sets the cached value associated with k to v.
+func (c *Cache[K, V]) Put(k *K, v *V) {
+ head := &c.table()[uintptr(unsafe.Pointer(k))%cacheSize]
+
+ // Strategy is to walk the linked list at head,
+ // same as in Get, to look for existing entry.
+ // If we find one, we update v atomically in place.
+ // If not, then we race to replace the start = *head
+ // we observed with a new k, v entry.
+ // If we win that race, we're done.
+ // Otherwise, we try the whole thing again,
+ // with two optimizations:
+ //
+ // 1. We track in noK the start of the section of
+ // the list that we've confirmed has no entry for k.
+ // The next time down the list, we can stop at noK,
+ // because new entries are inserted at the front of the list.
+ // This guarantees we never traverse an entry
+ // multiple times.
+ //
+ // 2. We only allocate the entry to be added once,
+ // saving it in add for the next attempt.
+ var add, noK *cacheEntry[K, V]
+ n := 0
+ for {
+ e := head.Load()
+ start := e
+ for ; e != nil && e != noK; e = e.next {
+ if e.k == k {
+ e.v.Store(v)
+ return
+ }
+ n++
+ }
+ if add == nil {
+ add = &cacheEntry[K, V]{k: k}
+ add.v.Store(v)
+ }
+ add.next = start
+ if n >= 1000 {
+ // If an individual list gets too long, which shouldn't happen,
+ // throw it away to avoid quadratic lookup behavior.
+ add.next = nil
+ }
+ if head.CompareAndSwap(start, add) {
+ return
+ }
+ noK = start
+ }
+}
diff --git a/src/crypto/internal/boring/bcache/cache_test.go b/src/crypto/internal/boring/bcache/cache_test.go
new file mode 100644
index 0000000..19458a1
--- /dev/null
+++ b/src/crypto/internal/boring/bcache/cache_test.go
@@ -0,0 +1,122 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package bcache
+
+import (
+ "fmt"
+ "runtime"
+ "sync"
+ "sync/atomic"
+ "testing"
+)
+
+var registeredCache Cache[int, int32]
+
+func init() {
+ registeredCache.Register()
+}
+
+var seq atomic.Uint32
+
+func next[T int | int32]() *T {
+ x := new(T)
+ *x = T(seq.Add(1))
+ return x
+}
+
+func str[T int | int32](x *T) string {
+ if x == nil {
+ return "nil"
+ }
+ return fmt.Sprint(*x)
+}
+
+func TestCache(t *testing.T) {
+ // Use unregistered cache for functionality tests,
+ // to keep the runtime from clearing behind our backs.
+ c := new(Cache[int, int32])
+
+ // Create many entries.
+ m := make(map[*int]*int32)
+ for i := 0; i < 10000; i++ {
+ k := next[int]()
+ v := next[int32]()
+ m[k] = v
+ c.Put(k, v)
+ }
+
+ // Overwrite a random 20% of those.
+ n := 0
+ for k := range m {
+ v := next[int32]()
+ m[k] = v
+ c.Put(k, v)
+ if n++; n >= 2000 {
+ break
+ }
+ }
+
+ // Check results.
+ for k, v := range m {
+ if cv := c.Get(k); cv != v {
+ t.Fatalf("c.Get(%v) = %v, want %v", str(k), str(cv), str(v))
+ }
+ }
+
+ c.Clear()
+ for k := range m {
+ if cv := c.Get(k); cv != nil {
+ t.Fatalf("after GC, c.Get(%v) = %v, want nil", str(k), str(cv))
+ }
+ }
+
+ // Check that registered cache is cleared at GC.
+ c = &registeredCache
+ for k, v := range m {
+ c.Put(k, v)
+ }
+ runtime.GC()
+ for k := range m {
+ if cv := c.Get(k); cv != nil {
+ t.Fatalf("after Clear, c.Get(%v) = %v, want nil", str(k), str(cv))
+ }
+ }
+
+ // Check that cache works for concurrent access.
+ // Lists are discarded if they reach 1000 entries,
+ // and there are cacheSize list heads, so we should be
+ // able to do 100 * cacheSize entries with no problem at all.
+ c = new(Cache[int, int32])
+ var barrier, wg sync.WaitGroup
+ const N = 100
+ barrier.Add(N)
+ wg.Add(N)
+ var lost int32
+ for i := 0; i < N; i++ {
+ go func() {
+ defer wg.Done()
+
+ m := make(map[*int]*int32)
+ for j := 0; j < cacheSize; j++ {
+ k, v := next[int](), next[int32]()
+ m[k] = v
+ c.Put(k, v)
+ }
+ barrier.Done()
+ barrier.Wait()
+
+ for k, v := range m {
+ if cv := c.Get(k); cv != v {
+ t.Errorf("c.Get(%v) = %v, want %v", str(k), str(cv), str(v))
+ atomic.AddInt32(&lost, +1)
+ }
+ }
+ }()
+ }
+ wg.Wait()
+ if lost != 0 {
+ t.Errorf("lost %d entries", lost)
+ }
+}
diff --git a/src/crypto/internal/boring/bcache/stub.s b/src/crypto/internal/boring/bcache/stub.s
new file mode 100644
index 0000000..59f2dee
--- /dev/null
+++ b/src/crypto/internal/boring/bcache/stub.s
@@ -0,0 +1,6 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file is here to silence an error about registerCache not having a body.
+// (The body is provided by package runtime.)
diff --git a/src/crypto/internal/boring/boring.go b/src/crypto/internal/boring/boring.go
new file mode 100644
index 0000000..102380a
--- /dev/null
+++ b/src/crypto/internal/boring/boring.go
@@ -0,0 +1,126 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto && linux && (amd64 || arm64) && !android && !cmd_go_bootstrap && !msan
+
+package boring
+
+/*
+// goboringcrypto_linux_amd64.syso references pthread functions.
+#cgo LDFLAGS: "-pthread"
+
+#include "goboringcrypto.h"
+*/
+import "C"
+import (
+ "crypto/internal/boring/sig"
+ _ "crypto/internal/boring/syso"
+ "math/bits"
+ "unsafe"
+)
+
+const available = true
+
+func init() {
+ C._goboringcrypto_BORINGSSL_bcm_power_on_self_test()
+ if C._goboringcrypto_FIPS_mode() != 1 {
+ panic("boringcrypto: not in FIPS mode")
+ }
+ sig.BoringCrypto()
+}
+
+// Unreachable marks code that should be unreachable
+// when BoringCrypto is in use. It panics.
+func Unreachable() {
+ panic("boringcrypto: invalid code execution")
+}
+
+// provided by runtime to avoid os import.
+func runtime_arg0() string
+
+func hasSuffix(s, t string) bool {
+ return len(s) > len(t) && s[len(s)-len(t):] == t
+}
+
+// UnreachableExceptTests marks code that should be unreachable
+// when BoringCrypto is in use. It panics.
+func UnreachableExceptTests() {
+ name := runtime_arg0()
+ // If BoringCrypto ran on Windows we'd need to allow _test.exe and .test.exe as well.
+ if !hasSuffix(name, "_test") && !hasSuffix(name, ".test") {
+ println("boringcrypto: unexpected code execution in", name)
+ panic("boringcrypto: invalid code execution")
+ }
+}
+
+type fail string
+
+func (e fail) Error() string { return "boringcrypto: " + string(e) + " failed" }
+
+func wbase(b BigInt) *C.uint8_t {
+ if len(b) == 0 {
+ return nil
+ }
+ return (*C.uint8_t)(unsafe.Pointer(&b[0]))
+}
+
+const wordBytes = bits.UintSize / 8
+
+func bigToBN(x BigInt) *C.GO_BIGNUM {
+ return C._goboringcrypto_BN_le2bn(wbase(x), C.size_t(len(x)*wordBytes), nil)
+}
+
+func bytesToBN(x []byte) *C.GO_BIGNUM {
+ return C._goboringcrypto_BN_bin2bn((*C.uint8_t)(&x[0]), C.size_t(len(x)), nil)
+}
+
+func bnToBig(bn *C.GO_BIGNUM) BigInt {
+ x := make(BigInt, (C._goboringcrypto_BN_num_bytes(bn)+wordBytes-1)/wordBytes)
+ if C._goboringcrypto_BN_bn2le_padded(wbase(x), C.size_t(len(x)*wordBytes), bn) == 0 {
+ panic("boringcrypto: bignum conversion failed")
+ }
+ return x
+}
+
+func bigToBn(bnp **C.GO_BIGNUM, b BigInt) bool {
+ if *bnp != nil {
+ C._goboringcrypto_BN_free(*bnp)
+ *bnp = nil
+ }
+ if b == nil {
+ return true
+ }
+ bn := bigToBN(b)
+ if bn == nil {
+ return false
+ }
+ *bnp = bn
+ return true
+}
+
+// noescape hides a pointer from escape analysis. noescape is
+// the identity function but escape analysis doesn't think the
+// output depends on the input. noescape is inlined and currently
+// compiles down to zero instructions.
+// USE CAREFULLY!
+//
+//go:nosplit
+func noescape(p unsafe.Pointer) unsafe.Pointer {
+ x := uintptr(p)
+ return unsafe.Pointer(x ^ 0)
+}
+
+var zero byte
+
+// addr converts p to its base addr, including a noescape along the way.
+// If p is nil, addr returns a non-nil pointer, so that the result can always
+// be dereferenced.
+//
+//go:nosplit
+func addr(p []byte) *byte {
+ if len(p) == 0 {
+ return &zero
+ }
+ return (*byte)(noescape(unsafe.Pointer(&p[0])))
+}
diff --git a/src/crypto/internal/boring/boring_test.go b/src/crypto/internal/boring/boring_test.go
new file mode 100644
index 0000000..83bbbd3
--- /dev/null
+++ b/src/crypto/internal/boring/boring_test.go
@@ -0,0 +1,34 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Most functionality in this package is tested by replacing existing code
+// and inheriting that code's tests.
+
+package boring
+
+import "testing"
+
+// Test that func init does not panic.
+func TestInit(t *testing.T) {}
+
+// Test that Unreachable panics.
+func TestUnreachable(t *testing.T) {
+ defer func() {
+ if Enabled {
+ if err := recover(); err == nil {
+ t.Fatal("expected Unreachable to panic")
+ }
+ } else {
+ if err := recover(); err != nil {
+ t.Fatalf("expected Unreachable to be a no-op")
+ }
+ }
+ }()
+ Unreachable()
+}
+
+// Test that UnreachableExceptTests does not panic (this is a test).
+func TestUnreachableExceptTests(t *testing.T) {
+ UnreachableExceptTests()
+}
diff --git a/src/crypto/internal/boring/build-boring.sh b/src/crypto/internal/boring/build-boring.sh
new file mode 100755
index 0000000..db49852
--- /dev/null
+++ b/src/crypto/internal/boring/build-boring.sh
@@ -0,0 +1,44 @@
+#!/bin/bash
+# Copyright 2020 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Do not run directly; run build.sh, which runs this in Docker.
+# This script builds boringssl, which has already been unpacked in /boring/boringssl.
+
+set -e
+id
+date
+cd /boring
+
+# Go requires -fPIC for linux/amd64 cgo builds.
+# Setting -fPIC only affects the compilation of the non-module code in libcrypto.a,
+# because the FIPS module itself is already built with -fPIC.
+echo '#!/bin/bash
+exec clang-'$ClangV' -DGOBORING -fPIC "$@"
+' >/usr/local/bin/clang
+echo '#!/bin/bash
+exec clang++-'$ClangV' -DGOBORING -fPIC "$@"
+' >/usr/local/bin/clang++
+chmod +x /usr/local/bin/clang /usr/local/bin/clang++
+
+# The BoringSSL tests use Go, and cgo would look for gcc.
+export CGO_ENABLED=0
+
+# Modify the support code crypto/mem.c (outside the FIPS module)
+# to not try to use weak symbols, because they don't work with some
+# Go toolchain / clang toolchain combinations.
+perl -p -i -e 's/defined.*ELF.*defined.*GNUC.*/$0 \&\& !defined(GOBORING)/' boringssl/crypto/mem.c
+
+# Verbatim instructions from BoringCrypto build docs.
+printf "set(CMAKE_C_COMPILER \"clang\")\nset(CMAKE_CXX_COMPILER \"clang++\")\n" >${HOME}/toolchain
+cd boringssl
+mkdir build && cd build && cmake -GNinja -DCMAKE_TOOLCHAIN_FILE=${HOME}/toolchain -DFIPS=1 -DCMAKE_BUILD_TYPE=Release ..
+ninja
+./crypto/crypto_test
+cd ../..
+
+if [ "$(./boringssl/build/tool/bssl isfips)" != 1 ]; then
+ echo "NOT FIPS"
+ exit 2
+fi
diff --git a/src/crypto/internal/boring/build-goboring.sh b/src/crypto/internal/boring/build-goboring.sh
new file mode 100755
index 0000000..4938b5e
--- /dev/null
+++ b/src/crypto/internal/boring/build-goboring.sh
@@ -0,0 +1,237 @@
+#!/bin/bash
+# Copyright 2020 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# Do not run directly; run build.sh, which runs this in Docker.
+# This script builds goboringcrypto's syso, after boringssl has been built.
+
+export TERM=dumb
+
+set -e
+set -x
+id
+date
+export LANG=C
+unset LANGUAGE
+
+case $(uname -m) in
+x86_64) export GOARCH=amd64 ;;
+aarch64) export GOARCH=arm64 ;;
+*)
+ echo 'unknown uname -m:' $(uname -m) >&2
+ exit 2
+esac
+
+export CGO_ENABLED=0
+
+# Build and run test C++ program to make sure goboringcrypto.h matches openssl/*.h.
+# Also collect list of checked symbols in syms.txt
+set -e
+cd /boring/godriver
+cat >goboringcrypto.cc <<'EOF'
+#include <cassert>
+#include "goboringcrypto0.h"
+#include "goboringcrypto1.h"
+#define check_size(t) if(sizeof(t) != sizeof(GO_ ## t)) {printf("sizeof(" #t ")=%d, but sizeof(GO_" #t ")=%d\n", (int)sizeof(t), (int)sizeof(GO_ ## t)); ret=1;}
+#define check_func(f) { auto x = f; x = _goboringcrypto_ ## f ; }
+#define check_value(n, v) if(n != v) {printf(#n "=%d, but goboringcrypto.h defines it as %d\n", (int)n, (int)v); ret=1;}
+int main() {
+int ret = 0;
+#include "goboringcrypto.x"
+return ret;
+}
+EOF
+
+cat >boringx.awk <<'EOF'
+BEGIN {
+ exitcode = 0
+}
+
+# Ignore comments, #includes, blank lines.
+/^\/\// || /^#/ || NF == 0 { next }
+
+# Ignore unchecked declarations.
+/\/\*unchecked/ { next }
+
+# Check enum values.
+!enum && ($1 == "enum" || $2 == "enum") && $NF == "{" {
+ enum = 1
+ next
+}
+enum && $1 == "};" {
+ enum = 0
+ next
+}
+enum && /^}.*;$/ {
+ enum = 0
+ next
+}
+enum && NF == 3 && $2 == "=" {
+ name = $1
+ sub(/^GO_/, "", name)
+ val = $3
+ sub(/,$/, "", val)
+ print "check_value(" name ", " val ")" > "goboringcrypto.x"
+ next
+}
+enum {
+ print FILENAME ":" NR ": unexpected line in enum: " $0 > "/dev/stderr"
+ exitcode = 1
+ next
+}
+
+# Check struct sizes.
+/^typedef struct / && $NF ~ /^GO_/ {
+ name = $NF
+ sub(/^GO_/, "", name)
+ sub(/;$/, "", name)
+ print "check_size(" name ")" > "goboringcrypto.x"
+ next
+}
+
+# Check function prototypes.
+/^(const )?[^ ]+ \**_goboringcrypto_.*\(/ {
+ name = $2
+ if($1 == "const")
+ name = $3
+ sub(/^\**_goboringcrypto_/, "", name)
+ sub(/\(.*/, "", name)
+ print "check_func(" name ")" > "goboringcrypto.x"
+ print name > "syms.txt"
+ next
+}
+
+{
+ print FILENAME ":" NR ": unexpected line: " $0 > "/dev/stderr"
+ exitcode = 1
+}
+
+END {
+ exit exitcode
+}
+EOF
+
+cat >boringh.awk <<'EOF'
+/^\/\/ #include/ {sub(/\/\//, ""); print > "goboringcrypto0.h"; next}
+/typedef struct|enum ([a-z_]+ )?{|^[ \t]/ {print >"goboringcrypto1.h";next}
+{gsub(/GO_/, ""); gsub(/enum go_/, "enum "); gsub(/go_point_conv/, "point_conv"); print >"goboringcrypto1.h"}
+EOF
+
+awk -f boringx.awk goboringcrypto.h # writes goboringcrypto.x
+awk -f boringh.awk goboringcrypto.h # writes goboringcrypto[01].h
+
+ls -l ../boringssl/include
+clang++ -std=c++11 -fPIC -I../boringssl/include -O2 -o a.out goboringcrypto.cc
+./a.out || exit 2
+
+# clang implements u128 % u128 -> u128 by calling __umodti3,
+# which is in libgcc. To make the result self-contained even if linking
+# against a different compiler version, link our own __umodti3 into the syso.
+# This one is specialized so it only expects divisors below 2^64,
+# which is all BoringCrypto uses. (Otherwise it will seg fault.)
+cat >umod-amd64.s <<'EOF'
+# tu_int __umodti3(tu_int x, tu_int y)
+# x is rsi:rdi, y is rcx:rdx, return result is rdx:rax.
+.globl __umodti3
+__umodti3:
+ # specialized to u128 % u64, so verify that
+ test %rcx,%rcx
+ jne 1f
+
+ # save divisor
+ movq %rdx, %r8
+
+ # reduce top 64 bits mod divisor
+ movq %rsi, %rax
+ xorl %edx, %edx
+ divq %r8
+
+ # reduce full 128-bit mod divisor
+ # quotient fits in 64 bits because top 64 bits have been reduced < divisor.
+ # (even though we only care about the remainder, divq also computes
+ # the quotient, and it will trap if the quotient is too large.)
+ movq %rdi, %rax
+ divq %r8
+
+ # expand remainder to 128 for return
+ movq %rdx, %rax
+ xorl %edx, %edx
+ ret
+
+1:
+ # crash - only want 64-bit divisor
+ xorl %ecx, %ecx
+ movl %ecx, 0(%ecx)
+ jmp 1b
+
+.section .note.GNU-stack,"",@progbits
+EOF
+
+cat >umod-arm64.c <<'EOF'
+typedef unsigned int u128 __attribute__((mode(TI)));
+
+static u128 div(u128 x, u128 y, u128 *rp) {
+ int n = 0;
+ while((y>>(128-1)) != 1 && y < x) {
+ y<<=1;
+ n++;
+ }
+ u128 q = 0;
+ for(;; n--, y>>=1, q<<=1) {
+ if(x>=y) {
+ x -= y;
+ q |= 1;
+ }
+ if(n == 0)
+ break;
+ }
+ if(rp)
+ *rp = x;
+ return q;
+}
+
+u128 __umodti3(u128 x, u128 y) {
+ u128 r;
+ div(x, y, &r);
+ return r;
+}
+
+u128 __udivti3(u128 x, u128 y) {
+ return div(x, y, 0);
+}
+EOF
+
+extra=""
+case $GOARCH in
+amd64)
+ cp umod-amd64.s umod.s
+ clang -c -o umod.o umod.s
+ extra=umod.o
+ ;;
+arm64)
+ cp umod-arm64.c umod.c
+ clang -c -o umod.o umod.c
+ extra=umod.o
+ ;;
+esac
+
+# Prepare copy of libcrypto.a with only the checked functions renamed and exported.
+# All other symbols are left alone and hidden.
+echo BORINGSSL_bcm_power_on_self_test >>syms.txt
+awk '{print "_goboringcrypto_" $0 }' syms.txt >globals.txt
+awk '{print $0 " _goboringcrypto_" $0 }' syms.txt >renames.txt
+objcopy --globalize-symbol=BORINGSSL_bcm_power_on_self_test \
+ ../boringssl/build/crypto/libcrypto.a libcrypto.a
+
+# Link together bcm.o and libcrypto.a into a single object.
+ld -r -nostdlib --whole-archive -o goboringcrypto.o libcrypto.a $extra
+
+echo __umodti3 _goboringcrypto___umodti3 >>renames.txt
+echo __udivti3 _goboringcrypto___udivti3 >>renames.txt
+objcopy --remove-section=.llvm_addrsig goboringcrypto.o goboringcrypto1.o # b/179161016
+objcopy --redefine-syms=renames.txt goboringcrypto1.o goboringcrypto2.o
+objcopy --keep-global-symbols=globals.txt --strip-unneeded goboringcrypto2.o goboringcrypto_linux_$GOARCH.syso
+
+# Done!
+ls -l goboringcrypto_linux_$GOARCH.syso
diff --git a/src/crypto/internal/boring/build.sh b/src/crypto/internal/boring/build.sh
new file mode 100755
index 0000000..ec960d7
--- /dev/null
+++ b/src/crypto/internal/boring/build.sh
@@ -0,0 +1,46 @@
+#!/bin/bash
+# Copyright 2022 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+# This shell script uses Docker to run build-boring.sh and build-goboring.sh,
+# which build goboringcrypto_linux_$GOARCH.syso according to the Security Policy.
+# Currently, amd64 and arm64 are permitted.
+
+set -e
+set -o pipefail
+
+GOARCH=${GOARCH:-$(go env GOARCH)}
+echo "# Building goboringcrypto_linux_$GOARCH.syso. Set GOARCH to override." >&2
+
+if ! which docker >/dev/null; then
+ echo "# Docker not found. Inside Google, see go/installdocker." >&2
+ exit 1
+fi
+
+platform=""
+buildargs=""
+case "$GOARCH" in
+amd64)
+ ;;
+arm64)
+ if ! docker run --rm -t arm64v8/ubuntu:focal uname -m >/dev/null 2>&1; then
+ echo "# Docker cannot run arm64 binaries. Try:"
+ echo " sudo apt-get install qemu binfmt-support qemu-user-static"
+ echo " docker run --rm --privileged multiarch/qemu-user-static --reset -p yes"
+ echo " docker run --rm -t arm64v8/ubuntu:focal uname -m"
+ exit 1
+ fi
+ platform="--platform linux/arm64/v8"
+ buildargs="--build-arg ubuntu=arm64v8/ubuntu"
+ ;;
+*)
+ echo unknown GOARCH $GOARCH >&2
+ exit 2
+esac
+
+docker build $platform $buildargs --build-arg GOARCH=$GOARCH -t goboring:$GOARCH .
+id=$(docker create $platform goboring:$GOARCH)
+docker cp $id:/boring/godriver/goboringcrypto_linux_$GOARCH.syso ./syso
+docker rm $id
+ls -l ./syso/goboringcrypto_linux_$GOARCH.syso
diff --git a/src/crypto/internal/boring/div_test.c b/src/crypto/internal/boring/div_test.c
new file mode 100644
index 0000000..f909cc9
--- /dev/null
+++ b/src/crypto/internal/boring/div_test.c
@@ -0,0 +1,83 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file is a self-contained test for a copy of
+// the division algorithm in build-goboring.sh,
+// to verify that is correct. The real algorithm uses u128
+// but this copy uses u32 for easier testing.
+// s/32/128/g should be the only difference between the two.
+//
+// This is the dumbest possible division algorithm,
+// but any crypto code that depends on the speed of
+// division is equally dumb.
+
+//go:build ignore
+
+#include <stdio.h>
+#include <stdint.h>
+
+#define nelem(x) (sizeof(x)/sizeof((x)[0]))
+
+typedef uint32_t u32;
+
+static u32 div(u32 x, u32 y, u32 *rp) {
+ int n = 0;
+ while((y>>(32-1)) != 1 && y < x) {
+ y<<=1;
+ n++;
+ }
+ u32 q = 0;
+ for(;; n--, y>>=1, q<<=1) {
+ if(x>=y) {
+ x -= y;
+ q |= 1;
+ }
+ if(n == 0)
+ break;
+ }
+ if(rp)
+ *rp = x;
+ return q;
+}
+
+u32 tests[] = {
+ 0,
+ 1,
+ 2,
+ 3,
+ 4,
+ 5,
+ 6,
+ 7,
+ 8,
+ 9,
+ 10,
+ 11,
+ 31,
+ 0xFFF,
+ 0x1000,
+ 0x1001,
+ 0xF0F0F0,
+ 0xFFFFFF,
+ 0x1000000,
+ 0xF0F0F0F0,
+ 0xFFFFFFFF,
+};
+
+int
+main(void)
+{
+ for(int i=0; i<nelem(tests); i++)
+ for(int j=0; j<nelem(tests); j++) {
+ u32 n = tests[i];
+ u32 d = tests[j];
+ if(d == 0)
+ continue;
+ u32 r;
+ u32 q = div(n, d, &r);
+ if(q != n/d || r != n%d)
+ printf("div(%x, %x) = %x, %x, want %x, %x\n", n, d, q, r, n/d, n%d);
+ }
+ return 0;
+}
diff --git a/src/crypto/internal/boring/doc.go b/src/crypto/internal/boring/doc.go
new file mode 100644
index 0000000..6060fe5
--- /dev/null
+++ b/src/crypto/internal/boring/doc.go
@@ -0,0 +1,19 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package boring provides access to BoringCrypto implementation functions.
+// Check the constant Enabled to find out whether BoringCrypto is available.
+// If BoringCrypto is not available, the functions in this package all panic.
+package boring
+
+// Enabled reports whether BoringCrypto is available.
+// When enabled is false, all functions in this package panic.
+//
+// BoringCrypto is only available on linux/amd64 systems.
+const Enabled = available
+
+// A BigInt is the raw words from a BigInt.
+// This definition allows us to avoid importing math/big.
+// Conversion between BigInt and *big.Int is in crypto/internal/boring/bbig.
+type BigInt []uint
diff --git a/src/crypto/internal/boring/ecdh.go b/src/crypto/internal/boring/ecdh.go
new file mode 100644
index 0000000..8f46d81
--- /dev/null
+++ b/src/crypto/internal/boring/ecdh.go
@@ -0,0 +1,224 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto && linux && (amd64 || arm64) && !android && !cmd_go_bootstrap && !msan
+
+package boring
+
+// #include "goboringcrypto.h"
+import "C"
+import (
+ "errors"
+ "runtime"
+ "unsafe"
+)
+
+type PublicKeyECDH struct {
+ curve string
+ key *C.GO_EC_POINT
+ group *C.GO_EC_GROUP
+ bytes []byte
+}
+
+func (k *PublicKeyECDH) finalize() {
+ C._goboringcrypto_EC_POINT_free(k.key)
+}
+
+type PrivateKeyECDH struct {
+ curve string
+ key *C.GO_EC_KEY
+}
+
+func (k *PrivateKeyECDH) finalize() {
+ C._goboringcrypto_EC_KEY_free(k.key)
+}
+
+func NewPublicKeyECDH(curve string, bytes []byte) (*PublicKeyECDH, error) {
+ if len(bytes) < 1 {
+ return nil, errors.New("NewPublicKeyECDH: missing key")
+ }
+
+ nid, err := curveNID(curve)
+ if err != nil {
+ return nil, err
+ }
+
+ group := C._goboringcrypto_EC_GROUP_new_by_curve_name(nid)
+ if group == nil {
+ return nil, fail("EC_GROUP_new_by_curve_name")
+ }
+ defer C._goboringcrypto_EC_GROUP_free(group)
+ key := C._goboringcrypto_EC_POINT_new(group)
+ if key == nil {
+ return nil, fail("EC_POINT_new")
+ }
+ ok := C._goboringcrypto_EC_POINT_oct2point(group, key, (*C.uint8_t)(unsafe.Pointer(&bytes[0])), C.size_t(len(bytes)), nil) != 0
+ if !ok {
+ C._goboringcrypto_EC_POINT_free(key)
+ return nil, errors.New("point not on curve")
+ }
+
+ k := &PublicKeyECDH{curve, key, group, append([]byte(nil), bytes...)}
+ // Note: Because of the finalizer, any time k.key is passed to cgo,
+ // that call must be followed by a call to runtime.KeepAlive(k),
+ // to make sure k is not collected (and finalized) before the cgo
+ // call returns.
+ runtime.SetFinalizer(k, (*PublicKeyECDH).finalize)
+ return k, nil
+}
+
+func (k *PublicKeyECDH) Bytes() []byte { return k.bytes }
+
+func NewPrivateKeyECDH(curve string, bytes []byte) (*PrivateKeyECDH, error) {
+ nid, err := curveNID(curve)
+ if err != nil {
+ return nil, err
+ }
+ key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid)
+ if key == nil {
+ return nil, fail("EC_KEY_new_by_curve_name")
+ }
+ b := bytesToBN(bytes)
+ ok := b != nil && C._goboringcrypto_EC_KEY_set_private_key(key, b) != 0
+ if b != nil {
+ C._goboringcrypto_BN_free(b)
+ }
+ if !ok {
+ C._goboringcrypto_EC_KEY_free(key)
+ return nil, fail("EC_KEY_set_private_key")
+ }
+ k := &PrivateKeyECDH{curve, key}
+ // Note: Same as in NewPublicKeyECDH regarding finalizer and KeepAlive.
+ runtime.SetFinalizer(k, (*PrivateKeyECDH).finalize)
+ return k, nil
+}
+
+func (k *PrivateKeyECDH) PublicKey() (*PublicKeyECDH, error) {
+ defer runtime.KeepAlive(k)
+
+ group := C._goboringcrypto_EC_KEY_get0_group(k.key)
+ if group == nil {
+ return nil, fail("EC_KEY_get0_group")
+ }
+ kbig := C._goboringcrypto_EC_KEY_get0_private_key(k.key)
+ if kbig == nil {
+ return nil, fail("EC_KEY_get0_private_key")
+ }
+ pt := C._goboringcrypto_EC_POINT_new(group)
+ if pt == nil {
+ return nil, fail("EC_POINT_new")
+ }
+ if C._goboringcrypto_EC_POINT_mul(group, pt, kbig, nil, nil, nil) == 0 {
+ C._goboringcrypto_EC_POINT_free(pt)
+ return nil, fail("EC_POINT_mul")
+ }
+ bytes, err := pointBytesECDH(k.curve, group, pt)
+ if err != nil {
+ C._goboringcrypto_EC_POINT_free(pt)
+ return nil, err
+ }
+ pub := &PublicKeyECDH{k.curve, pt, group, bytes}
+ // Note: Same as in NewPublicKeyECDH regarding finalizer and KeepAlive.
+ runtime.SetFinalizer(pub, (*PublicKeyECDH).finalize)
+ return pub, nil
+}
+
+func pointBytesECDH(curve string, group *C.GO_EC_GROUP, pt *C.GO_EC_POINT) ([]byte, error) {
+ out := make([]byte, 1+2*curveSize(curve))
+ n := C._goboringcrypto_EC_POINT_point2oct(group, pt, C.GO_POINT_CONVERSION_UNCOMPRESSED, (*C.uint8_t)(unsafe.Pointer(&out[0])), C.size_t(len(out)), nil)
+ if int(n) != len(out) {
+ return nil, fail("EC_POINT_point2oct")
+ }
+ return out, nil
+}
+
+func ECDH(priv *PrivateKeyECDH, pub *PublicKeyECDH) ([]byte, error) {
+ group := C._goboringcrypto_EC_KEY_get0_group(priv.key)
+ if group == nil {
+ return nil, fail("EC_KEY_get0_group")
+ }
+ privBig := C._goboringcrypto_EC_KEY_get0_private_key(priv.key)
+ if privBig == nil {
+ return nil, fail("EC_KEY_get0_private_key")
+ }
+ pt := C._goboringcrypto_EC_POINT_new(group)
+ if pt == nil {
+ return nil, fail("EC_POINT_new")
+ }
+ defer C._goboringcrypto_EC_POINT_free(pt)
+ if C._goboringcrypto_EC_POINT_mul(group, pt, nil, pub.key, privBig, nil) == 0 {
+ return nil, fail("EC_POINT_mul")
+ }
+ out, err := xCoordBytesECDH(priv.curve, group, pt)
+ if err != nil {
+ return nil, err
+ }
+ return out, nil
+}
+
+func xCoordBytesECDH(curve string, group *C.GO_EC_GROUP, pt *C.GO_EC_POINT) ([]byte, error) {
+ big := C._goboringcrypto_BN_new()
+ defer C._goboringcrypto_BN_free(big)
+ if C._goboringcrypto_EC_POINT_get_affine_coordinates_GFp(group, pt, big, nil, nil) == 0 {
+ return nil, fail("EC_POINT_get_affine_coordinates_GFp")
+ }
+ return bigBytesECDH(curve, big)
+}
+
+func bigBytesECDH(curve string, big *C.GO_BIGNUM) ([]byte, error) {
+ out := make([]byte, curveSize(curve))
+ if C._goboringcrypto_BN_bn2bin_padded((*C.uint8_t)(&out[0]), C.size_t(len(out)), big) == 0 {
+ return nil, fail("BN_bn2bin_padded")
+ }
+ return out, nil
+}
+
+func curveSize(curve string) int {
+ switch curve {
+ default:
+ panic("crypto/internal/boring: unknown curve " + curve)
+ case "P-256":
+ return 256 / 8
+ case "P-384":
+ return 384 / 8
+ case "P-521":
+ return (521 + 7) / 8
+ }
+}
+
+func GenerateKeyECDH(curve string) (*PrivateKeyECDH, []byte, error) {
+ nid, err := curveNID(curve)
+ if err != nil {
+ return nil, nil, err
+ }
+ key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid)
+ if key == nil {
+ return nil, nil, fail("EC_KEY_new_by_curve_name")
+ }
+ if C._goboringcrypto_EC_KEY_generate_key_fips(key) == 0 {
+ C._goboringcrypto_EC_KEY_free(key)
+ return nil, nil, fail("EC_KEY_generate_key_fips")
+ }
+
+ group := C._goboringcrypto_EC_KEY_get0_group(key)
+ if group == nil {
+ C._goboringcrypto_EC_KEY_free(key)
+ return nil, nil, fail("EC_KEY_get0_group")
+ }
+ b := C._goboringcrypto_EC_KEY_get0_private_key(key)
+ if b == nil {
+ C._goboringcrypto_EC_KEY_free(key)
+ return nil, nil, fail("EC_KEY_get0_private_key")
+ }
+ bytes, err := bigBytesECDH(curve, b)
+ if err != nil {
+ C._goboringcrypto_EC_KEY_free(key)
+ return nil, nil, err
+ }
+
+ k := &PrivateKeyECDH{curve, key}
+ // Note: Same as in NewPublicKeyECDH regarding finalizer and KeepAlive.
+ runtime.SetFinalizer(k, (*PrivateKeyECDH).finalize)
+ return k, bytes, nil
+}
diff --git a/src/crypto/internal/boring/ecdsa.go b/src/crypto/internal/boring/ecdsa.go
new file mode 100644
index 0000000..e15f368
--- /dev/null
+++ b/src/crypto/internal/boring/ecdsa.go
@@ -0,0 +1,172 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto && linux && (amd64 || arm64) && !android && !cmd_go_bootstrap && !msan
+
+package boring
+
+// #include "goboringcrypto.h"
+import "C"
+import (
+ "errors"
+ "runtime"
+)
+
+type ecdsaSignature struct {
+ R, S BigInt
+}
+
+type PrivateKeyECDSA struct {
+ key *C.GO_EC_KEY
+}
+
+func (k *PrivateKeyECDSA) finalize() {
+ C._goboringcrypto_EC_KEY_free(k.key)
+}
+
+type PublicKeyECDSA struct {
+ key *C.GO_EC_KEY
+}
+
+func (k *PublicKeyECDSA) finalize() {
+ C._goboringcrypto_EC_KEY_free(k.key)
+}
+
+var errUnknownCurve = errors.New("boringcrypto: unknown elliptic curve")
+
+func curveNID(curve string) (C.int, error) {
+ switch curve {
+ case "P-224":
+ return C.GO_NID_secp224r1, nil
+ case "P-256":
+ return C.GO_NID_X9_62_prime256v1, nil
+ case "P-384":
+ return C.GO_NID_secp384r1, nil
+ case "P-521":
+ return C.GO_NID_secp521r1, nil
+ }
+ return 0, errUnknownCurve
+}
+
+func NewPublicKeyECDSA(curve string, X, Y BigInt) (*PublicKeyECDSA, error) {
+ key, err := newECKey(curve, X, Y)
+ if err != nil {
+ return nil, err
+ }
+ k := &PublicKeyECDSA{key}
+ // Note: Because of the finalizer, any time k.key is passed to cgo,
+ // that call must be followed by a call to runtime.KeepAlive(k),
+ // to make sure k is not collected (and finalized) before the cgo
+ // call returns.
+ runtime.SetFinalizer(k, (*PublicKeyECDSA).finalize)
+ return k, nil
+}
+
+func newECKey(curve string, X, Y BigInt) (*C.GO_EC_KEY, error) {
+ nid, err := curveNID(curve)
+ if err != nil {
+ return nil, err
+ }
+ key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid)
+ if key == nil {
+ return nil, fail("EC_KEY_new_by_curve_name")
+ }
+ group := C._goboringcrypto_EC_KEY_get0_group(key)
+ pt := C._goboringcrypto_EC_POINT_new(group)
+ if pt == nil {
+ C._goboringcrypto_EC_KEY_free(key)
+ return nil, fail("EC_POINT_new")
+ }
+ bx := bigToBN(X)
+ by := bigToBN(Y)
+ ok := bx != nil && by != nil && C._goboringcrypto_EC_POINT_set_affine_coordinates_GFp(group, pt, bx, by, nil) != 0 &&
+ C._goboringcrypto_EC_KEY_set_public_key(key, pt) != 0
+ if bx != nil {
+ C._goboringcrypto_BN_free(bx)
+ }
+ if by != nil {
+ C._goboringcrypto_BN_free(by)
+ }
+ C._goboringcrypto_EC_POINT_free(pt)
+ if !ok {
+ C._goboringcrypto_EC_KEY_free(key)
+ return nil, fail("EC_POINT_set_affine_coordinates_GFp")
+ }
+ return key, nil
+}
+
+func NewPrivateKeyECDSA(curve string, X, Y BigInt, D BigInt) (*PrivateKeyECDSA, error) {
+ key, err := newECKey(curve, X, Y)
+ if err != nil {
+ return nil, err
+ }
+ bd := bigToBN(D)
+ ok := bd != nil && C._goboringcrypto_EC_KEY_set_private_key(key, bd) != 0
+ if bd != nil {
+ C._goboringcrypto_BN_free(bd)
+ }
+ if !ok {
+ C._goboringcrypto_EC_KEY_free(key)
+ return nil, fail("EC_KEY_set_private_key")
+ }
+ k := &PrivateKeyECDSA{key}
+ // Note: Because of the finalizer, any time k.key is passed to cgo,
+ // that call must be followed by a call to runtime.KeepAlive(k),
+ // to make sure k is not collected (and finalized) before the cgo
+ // call returns.
+ runtime.SetFinalizer(k, (*PrivateKeyECDSA).finalize)
+ return k, nil
+}
+
+func SignMarshalECDSA(priv *PrivateKeyECDSA, hash []byte) ([]byte, error) {
+ size := C._goboringcrypto_ECDSA_size(priv.key)
+ sig := make([]byte, size)
+ var sigLen C.uint
+ if C._goboringcrypto_ECDSA_sign(0, base(hash), C.size_t(len(hash)), base(sig), &sigLen, priv.key) == 0 {
+ return nil, fail("ECDSA_sign")
+ }
+ runtime.KeepAlive(priv)
+ return sig[:sigLen], nil
+}
+
+func VerifyECDSA(pub *PublicKeyECDSA, hash []byte, sig []byte) bool {
+ ok := C._goboringcrypto_ECDSA_verify(0, base(hash), C.size_t(len(hash)), base(sig), C.size_t(len(sig)), pub.key) != 0
+ runtime.KeepAlive(pub)
+ return ok
+}
+
+func GenerateKeyECDSA(curve string) (X, Y, D BigInt, err error) {
+ nid, err := curveNID(curve)
+ if err != nil {
+ return nil, nil, nil, err
+ }
+ key := C._goboringcrypto_EC_KEY_new_by_curve_name(nid)
+ if key == nil {
+ return nil, nil, nil, fail("EC_KEY_new_by_curve_name")
+ }
+ defer C._goboringcrypto_EC_KEY_free(key)
+ if C._goboringcrypto_EC_KEY_generate_key_fips(key) == 0 {
+ return nil, nil, nil, fail("EC_KEY_generate_key_fips")
+ }
+ group := C._goboringcrypto_EC_KEY_get0_group(key)
+ pt := C._goboringcrypto_EC_KEY_get0_public_key(key)
+ bd := C._goboringcrypto_EC_KEY_get0_private_key(key)
+ if pt == nil || bd == nil {
+ return nil, nil, nil, fail("EC_KEY_get0_private_key")
+ }
+ bx := C._goboringcrypto_BN_new()
+ if bx == nil {
+ return nil, nil, nil, fail("BN_new")
+ }
+ defer C._goboringcrypto_BN_free(bx)
+ by := C._goboringcrypto_BN_new()
+ if by == nil {
+ return nil, nil, nil, fail("BN_new")
+ }
+ defer C._goboringcrypto_BN_free(by)
+ if C._goboringcrypto_EC_POINT_get_affine_coordinates_GFp(group, pt, bx, by, nil) == 0 {
+ return nil, nil, nil, fail("EC_POINT_get_affine_coordinates_GFp")
+ }
+ return bnToBig(bx), bnToBig(by), bnToBig(bd), nil
+}
diff --git a/src/crypto/internal/boring/fipstls/stub.s b/src/crypto/internal/boring/fipstls/stub.s
new file mode 100644
index 0000000..f2e5a50
--- /dev/null
+++ b/src/crypto/internal/boring/fipstls/stub.s
@@ -0,0 +1,12 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto
+
+// runtime_arg0 is declared in tls.go without a body.
+// It's provided by package runtime,
+// but the go command doesn't know that.
+// Having this assembly file keeps the go command
+// from complaining about the missing body
+// (because the implementation might be here).
diff --git a/src/crypto/internal/boring/fipstls/tls.go b/src/crypto/internal/boring/fipstls/tls.go
new file mode 100644
index 0000000..3bf1471
--- /dev/null
+++ b/src/crypto/internal/boring/fipstls/tls.go
@@ -0,0 +1,52 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto
+
+// Package fipstls allows control over whether crypto/tls requires FIPS-approved settings.
+// This package only exists with GOEXPERIMENT=boringcrypto, but the effects are independent
+// of the use of BoringCrypto.
+package fipstls
+
+import "sync/atomic"
+
+var required atomic.Bool
+
+// Force forces crypto/tls to restrict TLS configurations to FIPS-approved settings.
+// By design, this call is impossible to undo (except in tests).
+//
+// Note that this call has an effect even in programs using
+// standard crypto (that is, even when Enabled = false).
+func Force() {
+ required.Store(true)
+}
+
+// Abandon allows non-FIPS-approved settings.
+// If called from a non-test binary, it panics.
+func Abandon() {
+ // Note: Not using boring.UnreachableExceptTests because we want
+ // this test to happen even when boring.Enabled = false.
+ name := runtime_arg0()
+ // Allow _test for Go command, .test for Bazel,
+ // NaClMain for NaCl (where all binaries run as NaClMain),
+ // and empty string for Windows (where runtime_arg0 can't easily find the name).
+ // Since this is an internal package, testing that this isn't used on the
+ // other operating systems should suffice to catch any mistakes.
+ if !hasSuffix(name, "_test") && !hasSuffix(name, ".test") && name != "NaClMain" && name != "" {
+ panic("fipstls: invalid use of Abandon in " + name)
+ }
+ required.Store(false)
+}
+
+// provided by runtime
+func runtime_arg0() string
+
+func hasSuffix(s, t string) bool {
+ return len(s) > len(t) && s[len(s)-len(t):] == t
+}
+
+// Required reports whether FIPS-approved settings are required.
+func Required() bool {
+ return required.Load()
+}
diff --git a/src/crypto/internal/boring/goboringcrypto.h b/src/crypto/internal/boring/goboringcrypto.h
new file mode 100644
index 0000000..2b11049
--- /dev/null
+++ b/src/crypto/internal/boring/goboringcrypto.h
@@ -0,0 +1,255 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This header file describes the BoringCrypto ABI as built for use in Go.
+// The BoringCrypto build for Go (which generates goboringcrypto_*.syso)
+// takes the standard libcrypto.a from BoringCrypto and adds the prefix
+// _goboringcrypto_ to every symbol, to avoid possible conflicts with
+// code wrapping a different BoringCrypto or OpenSSL.
+//
+// To make this header standalone (so that building Go does not require
+// having a full set of BoringCrypto headers), the struct details are not here.
+// Instead, while building the syso, we compile and run a C++ program
+// that checks that the sizes match. The program also checks (during compilation)
+// that all the function prototypes match the BoringCrypto equivalents.
+// The generation of the checking program depends on the declaration
+// forms used below (one line for most, multiline for enums).
+
+#include <stdlib.h> // size_t
+#include <stdint.h> // uint8_t
+
+// This symbol is hidden in BoringCrypto and marked as a constructor,
+// but cmd/link's internal linking mode doesn't handle constructors.
+// Until it does, we've exported the symbol and can call it explicitly.
+// (If using external linking mode, it will therefore be called twice,
+// once explicitly and once as a constructor, but that's OK.)
+/*unchecked*/ void _goboringcrypto_BORINGSSL_bcm_power_on_self_test(void);
+
+// #include <openssl/crypto.h>
+int _goboringcrypto_FIPS_mode(void);
+void* _goboringcrypto_OPENSSL_malloc(size_t);
+
+// #include <openssl/rand.h>
+int _goboringcrypto_RAND_bytes(uint8_t*, size_t);
+
+// #include <openssl/nid.h>
+enum {
+ GO_NID_md5_sha1 = 114,
+
+ GO_NID_secp224r1 = 713,
+ GO_NID_X9_62_prime256v1 = 415,
+ GO_NID_secp384r1 = 715,
+ GO_NID_secp521r1 = 716,
+
+ GO_NID_sha224 = 675,
+ GO_NID_sha256 = 672,
+ GO_NID_sha384 = 673,
+ GO_NID_sha512 = 674,
+};
+
+// #include <openssl/sha.h>
+typedef struct GO_SHA_CTX { char data[96]; } GO_SHA_CTX;
+int _goboringcrypto_SHA1_Init(GO_SHA_CTX*);
+int _goboringcrypto_SHA1_Update(GO_SHA_CTX*, const void*, size_t);
+int _goboringcrypto_SHA1_Final(uint8_t*, GO_SHA_CTX*);
+
+typedef struct GO_SHA256_CTX { char data[48+64]; } GO_SHA256_CTX;
+int _goboringcrypto_SHA224_Init(GO_SHA256_CTX*);
+int _goboringcrypto_SHA224_Update(GO_SHA256_CTX*, const void*, size_t);
+int _goboringcrypto_SHA224_Final(uint8_t*, GO_SHA256_CTX*);
+int _goboringcrypto_SHA256_Init(GO_SHA256_CTX*);
+int _goboringcrypto_SHA256_Update(GO_SHA256_CTX*, const void*, size_t);
+int _goboringcrypto_SHA256_Final(uint8_t*, GO_SHA256_CTX*);
+
+typedef struct GO_SHA512_CTX { char data[88+128]; } GO_SHA512_CTX;
+int _goboringcrypto_SHA384_Init(GO_SHA512_CTX*);
+int _goboringcrypto_SHA384_Update(GO_SHA512_CTX*, const void*, size_t);
+int _goboringcrypto_SHA384_Final(uint8_t*, GO_SHA512_CTX*);
+int _goboringcrypto_SHA512_Init(GO_SHA512_CTX*);
+int _goboringcrypto_SHA512_Update(GO_SHA512_CTX*, const void*, size_t);
+int _goboringcrypto_SHA512_Final(uint8_t*, GO_SHA512_CTX*);
+
+// #include <openssl/digest.h>
+/*unchecked (opaque)*/ typedef struct GO_EVP_MD { char data[1]; } GO_EVP_MD;
+const GO_EVP_MD* _goboringcrypto_EVP_md4(void);
+const GO_EVP_MD* _goboringcrypto_EVP_md5(void);
+const GO_EVP_MD* _goboringcrypto_EVP_md5_sha1(void);
+const GO_EVP_MD* _goboringcrypto_EVP_sha1(void);
+const GO_EVP_MD* _goboringcrypto_EVP_sha224(void);
+const GO_EVP_MD* _goboringcrypto_EVP_sha256(void);
+const GO_EVP_MD* _goboringcrypto_EVP_sha384(void);
+const GO_EVP_MD* _goboringcrypto_EVP_sha512(void);
+int _goboringcrypto_EVP_MD_type(const GO_EVP_MD*);
+size_t _goboringcrypto_EVP_MD_size(const GO_EVP_MD*);
+
+// #include <openssl/hmac.h>
+typedef struct GO_HMAC_CTX { char data[104]; } GO_HMAC_CTX;
+void _goboringcrypto_HMAC_CTX_init(GO_HMAC_CTX*);
+void _goboringcrypto_HMAC_CTX_cleanup(GO_HMAC_CTX*);
+int _goboringcrypto_HMAC_Init(GO_HMAC_CTX*, const void*, int, const GO_EVP_MD*);
+int _goboringcrypto_HMAC_Update(GO_HMAC_CTX*, const uint8_t*, size_t);
+int _goboringcrypto_HMAC_Final(GO_HMAC_CTX*, uint8_t*, unsigned int*);
+size_t _goboringcrypto_HMAC_size(const GO_HMAC_CTX*);
+int _goboringcrypto_HMAC_CTX_copy_ex(GO_HMAC_CTX *dest, const GO_HMAC_CTX *src);
+
+// #include <openssl/aes.h>
+typedef struct GO_AES_KEY { char data[244]; } GO_AES_KEY;
+int _goboringcrypto_AES_set_encrypt_key(const uint8_t*, unsigned int, GO_AES_KEY*);
+int _goboringcrypto_AES_set_decrypt_key(const uint8_t*, unsigned int, GO_AES_KEY*);
+void _goboringcrypto_AES_encrypt(const uint8_t*, uint8_t*, const GO_AES_KEY*);
+void _goboringcrypto_AES_decrypt(const uint8_t*, uint8_t*, const GO_AES_KEY*);
+void _goboringcrypto_AES_ctr128_encrypt(const uint8_t*, uint8_t*, size_t, const GO_AES_KEY*, uint8_t*, uint8_t*, unsigned int*);
+enum {
+ GO_AES_ENCRYPT = 1,
+ GO_AES_DECRYPT = 0
+};
+void _goboringcrypto_AES_cbc_encrypt(const uint8_t*, uint8_t*, size_t, const GO_AES_KEY*, uint8_t*, const int);
+
+// #include <openssl/aead.h>
+/*unchecked (opaque)*/ typedef struct GO_EVP_AEAD { char data[1]; } GO_EVP_AEAD;
+/*unchecked (opaque)*/ typedef struct GO_ENGINE { char data[1]; } GO_ENGINE;
+const GO_EVP_AEAD* _goboringcrypto_EVP_aead_aes_128_gcm(void);
+const GO_EVP_AEAD* _goboringcrypto_EVP_aead_aes_256_gcm(void);
+enum {
+ GO_EVP_AEAD_DEFAULT_TAG_LENGTH = 0
+};
+size_t _goboringcrypto_EVP_AEAD_key_length(const GO_EVP_AEAD*);
+size_t _goboringcrypto_EVP_AEAD_nonce_length(const GO_EVP_AEAD*);
+size_t _goboringcrypto_EVP_AEAD_max_overhead(const GO_EVP_AEAD*);
+size_t _goboringcrypto_EVP_AEAD_max_tag_len(const GO_EVP_AEAD*);
+typedef struct GO_EVP_AEAD_CTX { char data[600]; } GO_EVP_AEAD_CTX;
+void _goboringcrypto_EVP_AEAD_CTX_zero(GO_EVP_AEAD_CTX*);
+int _goboringcrypto_EVP_AEAD_CTX_init(GO_EVP_AEAD_CTX*, const GO_EVP_AEAD*, const uint8_t*, size_t, size_t, GO_ENGINE*);
+void _goboringcrypto_EVP_AEAD_CTX_cleanup(GO_EVP_AEAD_CTX*);
+int _goboringcrypto_EVP_AEAD_CTX_seal(const GO_EVP_AEAD_CTX*, uint8_t*, size_t*, size_t, const uint8_t*, size_t, const uint8_t*, size_t, const uint8_t*, size_t);
+int _goboringcrypto_EVP_AEAD_CTX_open(const GO_EVP_AEAD_CTX*, uint8_t*, size_t*, size_t, const uint8_t*, size_t, const uint8_t*, size_t, const uint8_t*, size_t);
+const GO_EVP_AEAD* _goboringcrypto_EVP_aead_aes_128_gcm_tls12(void);
+const GO_EVP_AEAD* _goboringcrypto_EVP_aead_aes_256_gcm_tls12(void);
+enum go_evp_aead_direction_t {
+ go_evp_aead_open = 0,
+ go_evp_aead_seal = 1
+};
+int _goboringcrypto_EVP_AEAD_CTX_init_with_direction(GO_EVP_AEAD_CTX*, const GO_EVP_AEAD*, const uint8_t*, size_t, size_t, enum go_evp_aead_direction_t);
+
+// #include <openssl/bn.h>
+/*unchecked (opaque)*/ typedef struct GO_BN_CTX { char data[1]; } GO_BN_CTX;
+typedef struct GO_BIGNUM { char data[24]; } GO_BIGNUM;
+GO_BIGNUM* _goboringcrypto_BN_new(void);
+void _goboringcrypto_BN_free(GO_BIGNUM*);
+unsigned _goboringcrypto_BN_num_bits(const GO_BIGNUM*);
+unsigned _goboringcrypto_BN_num_bytes(const GO_BIGNUM*);
+int _goboringcrypto_BN_is_negative(const GO_BIGNUM*);
+GO_BIGNUM* _goboringcrypto_BN_bin2bn(const uint8_t*, size_t, GO_BIGNUM*);
+GO_BIGNUM* _goboringcrypto_BN_le2bn(const uint8_t*, size_t, GO_BIGNUM*);
+size_t _goboringcrypto_BN_bn2bin(const GO_BIGNUM*, uint8_t*);
+int _goboringcrypto_BN_bn2le_padded(uint8_t*, size_t, const GO_BIGNUM*);
+int _goboringcrypto_BN_bn2bin_padded(uint8_t*, size_t, const GO_BIGNUM*);
+
+// #include <openssl/ec.h>
+/*unchecked (opaque)*/ typedef struct GO_EC_GROUP { char data[1]; } GO_EC_GROUP;
+GO_EC_GROUP* _goboringcrypto_EC_GROUP_new_by_curve_name(int);
+void _goboringcrypto_EC_GROUP_free(GO_EC_GROUP*);
+
+/*unchecked (opaque)*/ typedef struct GO_EC_POINT { char data[1]; } GO_EC_POINT;
+GO_EC_POINT* _goboringcrypto_EC_POINT_new(const GO_EC_GROUP*);
+int _goboringcrypto_EC_POINT_mul(const GO_EC_GROUP*, GO_EC_POINT*, const GO_BIGNUM*, const GO_EC_POINT*, const GO_BIGNUM*, GO_BN_CTX*);
+void _goboringcrypto_EC_POINT_free(GO_EC_POINT*);
+int _goboringcrypto_EC_POINT_get_affine_coordinates_GFp(const GO_EC_GROUP*, const GO_EC_POINT*, GO_BIGNUM*, GO_BIGNUM*, GO_BN_CTX*);
+int _goboringcrypto_EC_POINT_set_affine_coordinates_GFp(const GO_EC_GROUP*, GO_EC_POINT*, const GO_BIGNUM*, const GO_BIGNUM*, GO_BN_CTX*);
+int _goboringcrypto_EC_POINT_oct2point(const GO_EC_GROUP*, GO_EC_POINT*, const uint8_t*, size_t, GO_BN_CTX*);
+GO_EC_POINT* _goboringcrypto_EC_POINT_dup(const GO_EC_POINT*, const GO_EC_GROUP*);
+int _goboringcrypto_EC_POINT_is_on_curve(const GO_EC_GROUP*, const GO_EC_POINT*, GO_BN_CTX*);
+#ifndef OPENSSL_HEADER_EC_H
+typedef enum {
+ GO_POINT_CONVERSION_COMPRESSED = 2,
+ GO_POINT_CONVERSION_UNCOMPRESSED = 4,
+ GO_POINT_CONVERSION_HYBRID = 6,
+} go_point_conversion_form_t;
+#endif
+size_t _goboringcrypto_EC_POINT_point2oct(const GO_EC_GROUP*, const GO_EC_POINT*, go_point_conversion_form_t, uint8_t*, size_t, GO_BN_CTX*);
+
+// #include <openssl/ec_key.h>
+/*unchecked (opaque)*/ typedef struct GO_EC_KEY { char data[1]; } GO_EC_KEY;
+GO_EC_KEY* _goboringcrypto_EC_KEY_new(void);
+GO_EC_KEY* _goboringcrypto_EC_KEY_new_by_curve_name(int);
+void _goboringcrypto_EC_KEY_free(GO_EC_KEY*);
+const GO_EC_GROUP* _goboringcrypto_EC_KEY_get0_group(const GO_EC_KEY*);
+int _goboringcrypto_EC_KEY_generate_key_fips(GO_EC_KEY*);
+int _goboringcrypto_EC_KEY_set_private_key(GO_EC_KEY*, const GO_BIGNUM*);
+int _goboringcrypto_EC_KEY_set_public_key(GO_EC_KEY*, const GO_EC_POINT*);
+int _goboringcrypto_EC_KEY_is_opaque(const GO_EC_KEY*);
+const GO_BIGNUM* _goboringcrypto_EC_KEY_get0_private_key(const GO_EC_KEY*);
+const GO_EC_POINT* _goboringcrypto_EC_KEY_get0_public_key(const GO_EC_KEY*);
+// TODO: EC_KEY_check_fips?
+
+// #include <openssl/ecdh.h>
+int _goboringcrypto_ECDH_compute_key_fips(uint8_t*, size_t, const GO_EC_POINT*, const GO_EC_KEY*);
+
+// #include <openssl/ecdsa.h>
+typedef struct GO_ECDSA_SIG { char data[16]; } GO_ECDSA_SIG;
+GO_ECDSA_SIG* _goboringcrypto_ECDSA_SIG_new(void);
+void _goboringcrypto_ECDSA_SIG_free(GO_ECDSA_SIG*);
+GO_ECDSA_SIG* _goboringcrypto_ECDSA_do_sign(const uint8_t*, size_t, const GO_EC_KEY*);
+int _goboringcrypto_ECDSA_do_verify(const uint8_t*, size_t, const GO_ECDSA_SIG*, const GO_EC_KEY*);
+int _goboringcrypto_ECDSA_sign(int, const uint8_t*, size_t, uint8_t*, unsigned int*, const GO_EC_KEY*);
+size_t _goboringcrypto_ECDSA_size(const GO_EC_KEY*);
+int _goboringcrypto_ECDSA_verify(int, const uint8_t*, size_t, const uint8_t*, size_t, const GO_EC_KEY*);
+
+// #include <openssl/rsa.h>
+
+// Note: order of struct fields here is unchecked.
+typedef struct GO_RSA { void *meth; GO_BIGNUM *n, *e, *d, *p, *q, *dmp1, *dmq1, *iqmp; char data[168]; } GO_RSA;
+/*unchecked (opaque)*/ typedef struct GO_BN_GENCB { char data[1]; } GO_BN_GENCB;
+GO_RSA* _goboringcrypto_RSA_new(void);
+void _goboringcrypto_RSA_free(GO_RSA*);
+void _goboringcrypto_RSA_get0_key(const GO_RSA*, const GO_BIGNUM **n, const GO_BIGNUM **e, const GO_BIGNUM **d);
+void _goboringcrypto_RSA_get0_factors(const GO_RSA*, const GO_BIGNUM **p, const GO_BIGNUM **q);
+void _goboringcrypto_RSA_get0_crt_params(const GO_RSA*, const GO_BIGNUM **dmp1, const GO_BIGNUM **dmp2, const GO_BIGNUM **iqmp);
+int _goboringcrypto_RSA_generate_key_ex(GO_RSA*, int, const GO_BIGNUM*, GO_BN_GENCB*);
+int _goboringcrypto_RSA_generate_key_fips(GO_RSA*, int, GO_BN_GENCB*);
+enum {
+ GO_RSA_PKCS1_PADDING = 1,
+ GO_RSA_NO_PADDING = 3,
+ GO_RSA_PKCS1_OAEP_PADDING = 4,
+ GO_RSA_PKCS1_PSS_PADDING = 6,
+};
+int _goboringcrypto_RSA_encrypt(GO_RSA*, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding);
+int _goboringcrypto_RSA_decrypt(GO_RSA*, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding);
+int _goboringcrypto_RSA_sign(int hash_nid, const uint8_t* in, unsigned int in_len, uint8_t *out, unsigned int *out_len, GO_RSA*);
+int _goboringcrypto_RSA_sign_pss_mgf1(GO_RSA*, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, const GO_EVP_MD *md, const GO_EVP_MD *mgf1_md, int salt_len);
+int _goboringcrypto_RSA_sign_raw(GO_RSA*, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding);
+int _goboringcrypto_RSA_verify(int hash_nid, const uint8_t *msg, size_t msg_len, const uint8_t *sig, size_t sig_len, GO_RSA*);
+int _goboringcrypto_RSA_verify_pss_mgf1(GO_RSA*, const uint8_t *msg, size_t msg_len, const GO_EVP_MD *md, const GO_EVP_MD *mgf1_md, int salt_len, const uint8_t *sig, size_t sig_len);
+int _goboringcrypto_RSA_verify_raw(GO_RSA*, size_t *out_len, uint8_t *out, size_t max_out, const uint8_t *in, size_t in_len, int padding);
+unsigned _goboringcrypto_RSA_size(const GO_RSA*);
+int _goboringcrypto_RSA_is_opaque(const GO_RSA*);
+int _goboringcrypto_RSA_check_key(const GO_RSA*);
+int _goboringcrypto_RSA_check_fips(GO_RSA*);
+GO_RSA* _goboringcrypto_RSA_public_key_from_bytes(const uint8_t*, size_t);
+GO_RSA* _goboringcrypto_RSA_private_key_from_bytes(const uint8_t*, size_t);
+int _goboringcrypto_RSA_public_key_to_bytes(uint8_t**, size_t*, const GO_RSA*);
+int _goboringcrypto_RSA_private_key_to_bytes(uint8_t**, size_t*, const GO_RSA*);
+
+// #include <openssl/evp.h>
+/*unchecked (opaque)*/ typedef struct GO_EVP_PKEY { char data[1]; } GO_EVP_PKEY;
+GO_EVP_PKEY* _goboringcrypto_EVP_PKEY_new(void);
+void _goboringcrypto_EVP_PKEY_free(GO_EVP_PKEY*);
+int _goboringcrypto_EVP_PKEY_set1_RSA(GO_EVP_PKEY*, GO_RSA*);
+
+/*unchecked (opaque)*/ typedef struct GO_EVP_PKEY_CTX { char data[1]; } GO_EVP_PKEY_CTX;
+
+GO_EVP_PKEY_CTX* _goboringcrypto_EVP_PKEY_CTX_new(GO_EVP_PKEY*, GO_ENGINE*);
+void _goboringcrypto_EVP_PKEY_CTX_free(GO_EVP_PKEY_CTX*);
+int _goboringcrypto_EVP_PKEY_CTX_set0_rsa_oaep_label(GO_EVP_PKEY_CTX*, uint8_t*, size_t);
+int _goboringcrypto_EVP_PKEY_CTX_set_rsa_oaep_md(GO_EVP_PKEY_CTX*, const GO_EVP_MD*);
+int _goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(GO_EVP_PKEY_CTX*, int padding);
+int _goboringcrypto_EVP_PKEY_decrypt(GO_EVP_PKEY_CTX*, uint8_t*, size_t*, const uint8_t*, size_t);
+int _goboringcrypto_EVP_PKEY_encrypt(GO_EVP_PKEY_CTX*, uint8_t*, size_t*, const uint8_t*, size_t);
+int _goboringcrypto_EVP_PKEY_decrypt_init(GO_EVP_PKEY_CTX*);
+int _goboringcrypto_EVP_PKEY_encrypt_init(GO_EVP_PKEY_CTX*);
+int _goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(GO_EVP_PKEY_CTX*, const GO_EVP_MD*);
+int _goboringcrypto_EVP_PKEY_CTX_set_rsa_pss_saltlen(GO_EVP_PKEY_CTX*, int);
+int _goboringcrypto_EVP_PKEY_sign_init(GO_EVP_PKEY_CTX*);
+int _goboringcrypto_EVP_PKEY_verify_init(GO_EVP_PKEY_CTX*);
+int _goboringcrypto_EVP_PKEY_sign(GO_EVP_PKEY_CTX*, uint8_t*, size_t*, const uint8_t*, size_t);
diff --git a/src/crypto/internal/boring/hmac.go b/src/crypto/internal/boring/hmac.go
new file mode 100644
index 0000000..6241a65
--- /dev/null
+++ b/src/crypto/internal/boring/hmac.go
@@ -0,0 +1,153 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto && linux && (amd64 || arm64) && !android && !cmd_go_bootstrap && !msan
+
+package boring
+
+// #include "goboringcrypto.h"
+import "C"
+import (
+ "bytes"
+ "crypto"
+ "hash"
+ "runtime"
+ "unsafe"
+)
+
+// hashToMD converts a hash.Hash implementation from this package
+// to a BoringCrypto *C.GO_EVP_MD.
+func hashToMD(h hash.Hash) *C.GO_EVP_MD {
+ switch h.(type) {
+ case *sha1Hash:
+ return C._goboringcrypto_EVP_sha1()
+ case *sha224Hash:
+ return C._goboringcrypto_EVP_sha224()
+ case *sha256Hash:
+ return C._goboringcrypto_EVP_sha256()
+ case *sha384Hash:
+ return C._goboringcrypto_EVP_sha384()
+ case *sha512Hash:
+ return C._goboringcrypto_EVP_sha512()
+ }
+ return nil
+}
+
+// cryptoHashToMD converts a crypto.Hash
+// to a BoringCrypto *C.GO_EVP_MD.
+func cryptoHashToMD(ch crypto.Hash) *C.GO_EVP_MD {
+ switch ch {
+ case crypto.MD5:
+ return C._goboringcrypto_EVP_md5()
+ case crypto.MD5SHA1:
+ return C._goboringcrypto_EVP_md5_sha1()
+ case crypto.SHA1:
+ return C._goboringcrypto_EVP_sha1()
+ case crypto.SHA224:
+ return C._goboringcrypto_EVP_sha224()
+ case crypto.SHA256:
+ return C._goboringcrypto_EVP_sha256()
+ case crypto.SHA384:
+ return C._goboringcrypto_EVP_sha384()
+ case crypto.SHA512:
+ return C._goboringcrypto_EVP_sha512()
+ }
+ return nil
+}
+
+// NewHMAC returns a new HMAC using BoringCrypto.
+// The function h must return a hash implemented by
+// BoringCrypto (for example, h could be boring.NewSHA256).
+// If h is not recognized, NewHMAC returns nil.
+func NewHMAC(h func() hash.Hash, key []byte) hash.Hash {
+ ch := h()
+ md := hashToMD(ch)
+ if md == nil {
+ return nil
+ }
+
+ // Note: Could hash down long keys here using EVP_Digest.
+ hkey := bytes.Clone(key)
+ hmac := &boringHMAC{
+ md: md,
+ size: ch.Size(),
+ blockSize: ch.BlockSize(),
+ key: hkey,
+ }
+ hmac.Reset()
+ return hmac
+}
+
+type boringHMAC struct {
+ md *C.GO_EVP_MD
+ ctx C.GO_HMAC_CTX
+ ctx2 C.GO_HMAC_CTX
+ size int
+ blockSize int
+ key []byte
+ sum []byte
+ needCleanup bool
+}
+
+func (h *boringHMAC) Reset() {
+ if h.needCleanup {
+ C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx)
+ } else {
+ h.needCleanup = true
+ // Note: Because of the finalizer, any time h.ctx is passed to cgo,
+ // that call must be followed by a call to runtime.KeepAlive(h),
+ // to make sure h is not collected (and finalized) before the cgo
+ // call returns.
+ runtime.SetFinalizer(h, (*boringHMAC).finalize)
+ }
+ C._goboringcrypto_HMAC_CTX_init(&h.ctx)
+
+ if C._goboringcrypto_HMAC_Init(&h.ctx, unsafe.Pointer(base(h.key)), C.int(len(h.key)), h.md) == 0 {
+ panic("boringcrypto: HMAC_Init failed")
+ }
+ if int(C._goboringcrypto_HMAC_size(&h.ctx)) != h.size {
+ println("boringcrypto: HMAC size:", C._goboringcrypto_HMAC_size(&h.ctx), "!=", h.size)
+ panic("boringcrypto: HMAC size mismatch")
+ }
+ runtime.KeepAlive(h) // Next line will keep h alive too; just making doubly sure.
+ h.sum = nil
+}
+
+func (h *boringHMAC) finalize() {
+ C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx)
+}
+
+func (h *boringHMAC) Write(p []byte) (int, error) {
+ if len(p) > 0 {
+ C._goboringcrypto_HMAC_Update(&h.ctx, (*C.uint8_t)(unsafe.Pointer(&p[0])), C.size_t(len(p)))
+ }
+ runtime.KeepAlive(h)
+ return len(p), nil
+}
+
+func (h *boringHMAC) Size() int {
+ return h.size
+}
+
+func (h *boringHMAC) BlockSize() int {
+ return h.blockSize
+}
+
+func (h *boringHMAC) Sum(in []byte) []byte {
+ if h.sum == nil {
+ size := h.Size()
+ h.sum = make([]byte, size)
+ }
+ // Make copy of context because Go hash.Hash mandates
+ // that Sum has no effect on the underlying stream.
+ // In particular it is OK to Sum, then Write more, then Sum again,
+ // and the second Sum acts as if the first didn't happen.
+ C._goboringcrypto_HMAC_CTX_init(&h.ctx2)
+ if C._goboringcrypto_HMAC_CTX_copy_ex(&h.ctx2, &h.ctx) == 0 {
+ panic("boringcrypto: HMAC_CTX_copy_ex failed")
+ }
+ C._goboringcrypto_HMAC_Final(&h.ctx2, (*C.uint8_t)(unsafe.Pointer(&h.sum[0])), nil)
+ C._goboringcrypto_HMAC_CTX_cleanup(&h.ctx2)
+ return append(in, h.sum...)
+}
diff --git a/src/crypto/internal/boring/notboring.go b/src/crypto/internal/boring/notboring.go
new file mode 100644
index 0000000..1c5e4c7
--- /dev/null
+++ b/src/crypto/internal/boring/notboring.go
@@ -0,0 +1,122 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !(boringcrypto && linux && (amd64 || arm64) && !android && !cmd_go_bootstrap && !msan && cgo)
+
+package boring
+
+import (
+ "crypto"
+ "crypto/cipher"
+ "crypto/internal/boring/sig"
+ "hash"
+)
+
+const available = false
+
+// Unreachable marks code that should be unreachable
+// when BoringCrypto is in use. It is a no-op without BoringCrypto.
+func Unreachable() {
+ // Code that's unreachable when using BoringCrypto
+ // is exactly the code we want to detect for reporting
+ // standard Go crypto.
+ sig.StandardCrypto()
+}
+
+// UnreachableExceptTests marks code that should be unreachable
+// when BoringCrypto is in use. It is a no-op without BoringCrypto.
+func UnreachableExceptTests() {}
+
+type randReader int
+
+func (randReader) Read(b []byte) (int, error) { panic("boringcrypto: not available") }
+
+const RandReader = randReader(0)
+
+func NewSHA1() hash.Hash { panic("boringcrypto: not available") }
+func NewSHA224() hash.Hash { panic("boringcrypto: not available") }
+func NewSHA256() hash.Hash { panic("boringcrypto: not available") }
+func NewSHA384() hash.Hash { panic("boringcrypto: not available") }
+func NewSHA512() hash.Hash { panic("boringcrypto: not available") }
+
+func SHA1([]byte) [20]byte { panic("boringcrypto: not available") }
+func SHA224([]byte) [28]byte { panic("boringcrypto: not available") }
+func SHA256([]byte) [32]byte { panic("boringcrypto: not available") }
+func SHA384([]byte) [48]byte { panic("boringcrypto: not available") }
+func SHA512([]byte) [64]byte { panic("boringcrypto: not available") }
+
+func NewHMAC(h func() hash.Hash, key []byte) hash.Hash { panic("boringcrypto: not available") }
+
+func NewAESCipher(key []byte) (cipher.Block, error) { panic("boringcrypto: not available") }
+func NewGCMTLS(cipher.Block) (cipher.AEAD, error) { panic("boringcrypto: not available") }
+
+type PublicKeyECDSA struct{ _ int }
+type PrivateKeyECDSA struct{ _ int }
+
+func GenerateKeyECDSA(curve string) (X, Y, D BigInt, err error) {
+ panic("boringcrypto: not available")
+}
+func NewPrivateKeyECDSA(curve string, X, Y, D BigInt) (*PrivateKeyECDSA, error) {
+ panic("boringcrypto: not available")
+}
+func NewPublicKeyECDSA(curve string, X, Y BigInt) (*PublicKeyECDSA, error) {
+ panic("boringcrypto: not available")
+}
+func SignMarshalECDSA(priv *PrivateKeyECDSA, hash []byte) ([]byte, error) {
+ panic("boringcrypto: not available")
+}
+func VerifyECDSA(pub *PublicKeyECDSA, hash []byte, sig []byte) bool {
+ panic("boringcrypto: not available")
+}
+
+type PublicKeyRSA struct{ _ int }
+type PrivateKeyRSA struct{ _ int }
+
+func DecryptRSAOAEP(h, mgfHash hash.Hash, priv *PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) {
+ panic("boringcrypto: not available")
+}
+func DecryptRSAPKCS1(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) {
+ panic("boringcrypto: not available")
+}
+func DecryptRSANoPadding(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) {
+ panic("boringcrypto: not available")
+}
+func EncryptRSAOAEP(h, mgfHash hash.Hash, pub *PublicKeyRSA, msg, label []byte) ([]byte, error) {
+ panic("boringcrypto: not available")
+}
+func EncryptRSAPKCS1(pub *PublicKeyRSA, msg []byte) ([]byte, error) {
+ panic("boringcrypto: not available")
+}
+func EncryptRSANoPadding(pub *PublicKeyRSA, msg []byte) ([]byte, error) {
+ panic("boringcrypto: not available")
+}
+func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv BigInt, err error) {
+ panic("boringcrypto: not available")
+}
+func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv BigInt) (*PrivateKeyRSA, error) {
+ panic("boringcrypto: not available")
+}
+func NewPublicKeyRSA(N, E BigInt) (*PublicKeyRSA, error) { panic("boringcrypto: not available") }
+func SignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) {
+ panic("boringcrypto: not available")
+}
+func SignRSAPSS(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) {
+ panic("boringcrypto: not available")
+}
+func VerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error {
+ panic("boringcrypto: not available")
+}
+func VerifyRSAPSS(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error {
+ panic("boringcrypto: not available")
+}
+
+type PublicKeyECDH struct{}
+type PrivateKeyECDH struct{}
+
+func ECDH(*PrivateKeyECDH, *PublicKeyECDH) ([]byte, error) { panic("boringcrypto: not available") }
+func GenerateKeyECDH(string) (*PrivateKeyECDH, []byte, error) { panic("boringcrypto: not available") }
+func NewPrivateKeyECDH(string, []byte) (*PrivateKeyECDH, error) { panic("boringcrypto: not available") }
+func NewPublicKeyECDH(string, []byte) (*PublicKeyECDH, error) { panic("boringcrypto: not available") }
+func (*PublicKeyECDH) Bytes() []byte { panic("boringcrypto: not available") }
+func (*PrivateKeyECDH) PublicKey() (*PublicKeyECDH, error) { panic("boringcrypto: not available") }
diff --git a/src/crypto/internal/boring/rand.go b/src/crypto/internal/boring/rand.go
new file mode 100644
index 0000000..7639c01
--- /dev/null
+++ b/src/crypto/internal/boring/rand.go
@@ -0,0 +1,24 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto && linux && (amd64 || arm64) && !android && !cmd_go_bootstrap && !msan
+
+package boring
+
+// #include "goboringcrypto.h"
+import "C"
+import "unsafe"
+
+type randReader int
+
+func (randReader) Read(b []byte) (int, error) {
+ // Note: RAND_bytes should never fail; the return value exists only for historical reasons.
+ // We check it even so.
+ if len(b) > 0 && C._goboringcrypto_RAND_bytes((*C.uint8_t)(unsafe.Pointer(&b[0])), C.size_t(len(b))) == 0 {
+ return 0, fail("RAND_bytes")
+ }
+ return len(b), nil
+}
+
+const RandReader = randReader(0)
diff --git a/src/crypto/internal/boring/rsa.go b/src/crypto/internal/boring/rsa.go
new file mode 100644
index 0000000..fa693ea
--- /dev/null
+++ b/src/crypto/internal/boring/rsa.go
@@ -0,0 +1,379 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto && linux && (amd64 || arm64) && !android && !cmd_go_bootstrap && !msan
+
+package boring
+
+// #include "goboringcrypto.h"
+import "C"
+import (
+ "crypto"
+ "crypto/subtle"
+ "errors"
+ "hash"
+ "runtime"
+ "strconv"
+ "unsafe"
+)
+
+func GenerateKeyRSA(bits int) (N, E, D, P, Q, Dp, Dq, Qinv BigInt, err error) {
+ bad := func(e error) (N, E, D, P, Q, Dp, Dq, Qinv BigInt, err error) {
+ return nil, nil, nil, nil, nil, nil, nil, nil, e
+ }
+
+ key := C._goboringcrypto_RSA_new()
+ if key == nil {
+ return bad(fail("RSA_new"))
+ }
+ defer C._goboringcrypto_RSA_free(key)
+
+ if C._goboringcrypto_RSA_generate_key_fips(key, C.int(bits), nil) == 0 {
+ return bad(fail("RSA_generate_key_fips"))
+ }
+
+ var n, e, d, p, q, dp, dq, qinv *C.GO_BIGNUM
+ C._goboringcrypto_RSA_get0_key(key, &n, &e, &d)
+ C._goboringcrypto_RSA_get0_factors(key, &p, &q)
+ C._goboringcrypto_RSA_get0_crt_params(key, &dp, &dq, &qinv)
+ return bnToBig(n), bnToBig(e), bnToBig(d), bnToBig(p), bnToBig(q), bnToBig(dp), bnToBig(dq), bnToBig(qinv), nil
+}
+
+type PublicKeyRSA struct {
+ // _key MUST NOT be accessed directly. Instead, use the withKey method.
+ _key *C.GO_RSA
+}
+
+func NewPublicKeyRSA(N, E BigInt) (*PublicKeyRSA, error) {
+ key := C._goboringcrypto_RSA_new()
+ if key == nil {
+ return nil, fail("RSA_new")
+ }
+ if !bigToBn(&key.n, N) ||
+ !bigToBn(&key.e, E) {
+ return nil, fail("BN_bin2bn")
+ }
+ k := &PublicKeyRSA{_key: key}
+ runtime.SetFinalizer(k, (*PublicKeyRSA).finalize)
+ return k, nil
+}
+
+func (k *PublicKeyRSA) finalize() {
+ C._goboringcrypto_RSA_free(k._key)
+}
+
+func (k *PublicKeyRSA) withKey(f func(*C.GO_RSA) C.int) C.int {
+ // Because of the finalizer, any time _key is passed to cgo, that call must
+ // be followed by a call to runtime.KeepAlive, to make sure k is not
+ // collected (and finalized) before the cgo call returns.
+ defer runtime.KeepAlive(k)
+ return f(k._key)
+}
+
+type PrivateKeyRSA struct {
+ // _key MUST NOT be accessed directly. Instead, use the withKey method.
+ _key *C.GO_RSA
+}
+
+func NewPrivateKeyRSA(N, E, D, P, Q, Dp, Dq, Qinv BigInt) (*PrivateKeyRSA, error) {
+ key := C._goboringcrypto_RSA_new()
+ if key == nil {
+ return nil, fail("RSA_new")
+ }
+ if !bigToBn(&key.n, N) ||
+ !bigToBn(&key.e, E) ||
+ !bigToBn(&key.d, D) ||
+ !bigToBn(&key.p, P) ||
+ !bigToBn(&key.q, Q) ||
+ !bigToBn(&key.dmp1, Dp) ||
+ !bigToBn(&key.dmq1, Dq) ||
+ !bigToBn(&key.iqmp, Qinv) {
+ return nil, fail("BN_bin2bn")
+ }
+ k := &PrivateKeyRSA{_key: key}
+ runtime.SetFinalizer(k, (*PrivateKeyRSA).finalize)
+ return k, nil
+}
+
+func (k *PrivateKeyRSA) finalize() {
+ C._goboringcrypto_RSA_free(k._key)
+}
+
+func (k *PrivateKeyRSA) withKey(f func(*C.GO_RSA) C.int) C.int {
+ // Because of the finalizer, any time _key is passed to cgo, that call must
+ // be followed by a call to runtime.KeepAlive, to make sure k is not
+ // collected (and finalized) before the cgo call returns.
+ defer runtime.KeepAlive(k)
+ return f(k._key)
+}
+
+func setupRSA(withKey func(func(*C.GO_RSA) C.int) C.int,
+ padding C.int, h, mgfHash hash.Hash, label []byte, saltLen int, ch crypto.Hash,
+ init func(*C.GO_EVP_PKEY_CTX) C.int) (pkey *C.GO_EVP_PKEY, ctx *C.GO_EVP_PKEY_CTX, err error) {
+ defer func() {
+ if err != nil {
+ if pkey != nil {
+ C._goboringcrypto_EVP_PKEY_free(pkey)
+ pkey = nil
+ }
+ if ctx != nil {
+ C._goboringcrypto_EVP_PKEY_CTX_free(ctx)
+ ctx = nil
+ }
+ }
+ }()
+
+ pkey = C._goboringcrypto_EVP_PKEY_new()
+ if pkey == nil {
+ return nil, nil, fail("EVP_PKEY_new")
+ }
+ if withKey(func(key *C.GO_RSA) C.int {
+ return C._goboringcrypto_EVP_PKEY_set1_RSA(pkey, key)
+ }) == 0 {
+ return nil, nil, fail("EVP_PKEY_set1_RSA")
+ }
+ ctx = C._goboringcrypto_EVP_PKEY_CTX_new(pkey, nil)
+ if ctx == nil {
+ return nil, nil, fail("EVP_PKEY_CTX_new")
+ }
+ if init(ctx) == 0 {
+ return nil, nil, fail("EVP_PKEY_operation_init")
+ }
+ if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_padding(ctx, padding) == 0 {
+ return nil, nil, fail("EVP_PKEY_CTX_set_rsa_padding")
+ }
+ if padding == C.GO_RSA_PKCS1_OAEP_PADDING {
+ md := hashToMD(h)
+ if md == nil {
+ return nil, nil, errors.New("crypto/rsa: unsupported hash function")
+ }
+ mgfMD := hashToMD(mgfHash)
+ if mgfMD == nil {
+ return nil, nil, errors.New("crypto/rsa: unsupported hash function")
+ }
+ if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_oaep_md(ctx, md) == 0 {
+ return nil, nil, fail("EVP_PKEY_set_rsa_oaep_md")
+ }
+ if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, mgfMD) == 0 {
+ return nil, nil, fail("EVP_PKEY_set_rsa_mgf1_md")
+ }
+ // ctx takes ownership of label, so malloc a copy for BoringCrypto to free.
+ clabel := (*C.uint8_t)(C._goboringcrypto_OPENSSL_malloc(C.size_t(len(label))))
+ if clabel == nil {
+ return nil, nil, fail("OPENSSL_malloc")
+ }
+ copy((*[1 << 30]byte)(unsafe.Pointer(clabel))[:len(label)], label)
+ if C._goboringcrypto_EVP_PKEY_CTX_set0_rsa_oaep_label(ctx, clabel, C.size_t(len(label))) == 0 {
+ return nil, nil, fail("EVP_PKEY_CTX_set0_rsa_oaep_label")
+ }
+ }
+ if padding == C.GO_RSA_PKCS1_PSS_PADDING {
+ if saltLen != 0 {
+ if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_pss_saltlen(ctx, C.int(saltLen)) == 0 {
+ return nil, nil, fail("EVP_PKEY_set_rsa_pss_saltlen")
+ }
+ }
+ md := cryptoHashToMD(ch)
+ if md == nil {
+ return nil, nil, errors.New("crypto/rsa: unsupported hash function")
+ }
+ if C._goboringcrypto_EVP_PKEY_CTX_set_rsa_mgf1_md(ctx, md) == 0 {
+ return nil, nil, fail("EVP_PKEY_set_rsa_mgf1_md")
+ }
+ }
+
+ return pkey, ctx, nil
+}
+
+func cryptRSA(withKey func(func(*C.GO_RSA) C.int) C.int,
+ padding C.int, h, mgfHash hash.Hash, label []byte, saltLen int, ch crypto.Hash,
+ init func(*C.GO_EVP_PKEY_CTX) C.int,
+ crypt func(*C.GO_EVP_PKEY_CTX, *C.uint8_t, *C.size_t, *C.uint8_t, C.size_t) C.int,
+ in []byte) ([]byte, error) {
+
+ pkey, ctx, err := setupRSA(withKey, padding, h, mgfHash, label, saltLen, ch, init)
+ if err != nil {
+ return nil, err
+ }
+ defer C._goboringcrypto_EVP_PKEY_free(pkey)
+ defer C._goboringcrypto_EVP_PKEY_CTX_free(ctx)
+
+ var outLen C.size_t
+ if crypt(ctx, nil, &outLen, base(in), C.size_t(len(in))) == 0 {
+ return nil, fail("EVP_PKEY_decrypt/encrypt")
+ }
+ out := make([]byte, outLen)
+ if crypt(ctx, base(out), &outLen, base(in), C.size_t(len(in))) == 0 {
+ return nil, fail("EVP_PKEY_decrypt/encrypt")
+ }
+ return out[:outLen], nil
+}
+
+func DecryptRSAOAEP(h, mgfHash hash.Hash, priv *PrivateKeyRSA, ciphertext, label []byte) ([]byte, error) {
+ return cryptRSA(priv.withKey, C.GO_RSA_PKCS1_OAEP_PADDING, h, mgfHash, label, 0, 0, decryptInit, decrypt, ciphertext)
+}
+
+func EncryptRSAOAEP(h, mgfHash hash.Hash, pub *PublicKeyRSA, msg, label []byte) ([]byte, error) {
+ return cryptRSA(pub.withKey, C.GO_RSA_PKCS1_OAEP_PADDING, h, mgfHash, label, 0, 0, encryptInit, encrypt, msg)
+}
+
+func DecryptRSAPKCS1(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) {
+ return cryptRSA(priv.withKey, C.GO_RSA_PKCS1_PADDING, nil, nil, nil, 0, 0, decryptInit, decrypt, ciphertext)
+}
+
+func EncryptRSAPKCS1(pub *PublicKeyRSA, msg []byte) ([]byte, error) {
+ return cryptRSA(pub.withKey, C.GO_RSA_PKCS1_PADDING, nil, nil, nil, 0, 0, encryptInit, encrypt, msg)
+}
+
+func DecryptRSANoPadding(priv *PrivateKeyRSA, ciphertext []byte) ([]byte, error) {
+ return cryptRSA(priv.withKey, C.GO_RSA_NO_PADDING, nil, nil, nil, 0, 0, decryptInit, decrypt, ciphertext)
+}
+
+func EncryptRSANoPadding(pub *PublicKeyRSA, msg []byte) ([]byte, error) {
+ return cryptRSA(pub.withKey, C.GO_RSA_NO_PADDING, nil, nil, nil, 0, 0, encryptInit, encrypt, msg)
+}
+
+// These dumb wrappers work around the fact that cgo functions cannot be used as values directly.
+
+func decryptInit(ctx *C.GO_EVP_PKEY_CTX) C.int {
+ return C._goboringcrypto_EVP_PKEY_decrypt_init(ctx)
+}
+
+func decrypt(ctx *C.GO_EVP_PKEY_CTX, out *C.uint8_t, outLen *C.size_t, in *C.uint8_t, inLen C.size_t) C.int {
+ return C._goboringcrypto_EVP_PKEY_decrypt(ctx, out, outLen, in, inLen)
+}
+
+func encryptInit(ctx *C.GO_EVP_PKEY_CTX) C.int {
+ return C._goboringcrypto_EVP_PKEY_encrypt_init(ctx)
+}
+
+func encrypt(ctx *C.GO_EVP_PKEY_CTX, out *C.uint8_t, outLen *C.size_t, in *C.uint8_t, inLen C.size_t) C.int {
+ return C._goboringcrypto_EVP_PKEY_encrypt(ctx, out, outLen, in, inLen)
+}
+
+var invalidSaltLenErr = errors.New("crypto/rsa: PSSOptions.SaltLength cannot be negative")
+
+func SignRSAPSS(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte, saltLen int) ([]byte, error) {
+ md := cryptoHashToMD(h)
+ if md == nil {
+ return nil, errors.New("crypto/rsa: unsupported hash function")
+ }
+
+ // A salt length of -2 is valid in BoringSSL, but not in crypto/rsa, so reject
+ // it, and lengths < -2, before we convert to the BoringSSL sentinel values.
+ if saltLen <= -2 {
+ return nil, invalidSaltLenErr
+ }
+
+ // BoringSSL uses sentinel salt length values like we do, but the values don't
+ // fully match what we use. We both use -1 for salt length equal to hash length,
+ // but BoringSSL uses -2 to mean maximal size where we use 0. In the latter
+ // case convert to the BoringSSL version.
+ if saltLen == 0 {
+ saltLen = -2
+ }
+
+ var out []byte
+ var outLen C.size_t
+ if priv.withKey(func(key *C.GO_RSA) C.int {
+ out = make([]byte, C._goboringcrypto_RSA_size(key))
+ return C._goboringcrypto_RSA_sign_pss_mgf1(key, &outLen, base(out), C.size_t(len(out)),
+ base(hashed), C.size_t(len(hashed)), md, nil, C.int(saltLen))
+ }) == 0 {
+ return nil, fail("RSA_sign_pss_mgf1")
+ }
+
+ return out[:outLen], nil
+}
+
+func VerifyRSAPSS(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte, saltLen int) error {
+ md := cryptoHashToMD(h)
+ if md == nil {
+ return errors.New("crypto/rsa: unsupported hash function")
+ }
+
+ // A salt length of -2 is valid in BoringSSL, but not in crypto/rsa, so reject
+ // it, and lengths < -2, before we convert to the BoringSSL sentinel values.
+ if saltLen <= -2 {
+ return invalidSaltLenErr
+ }
+
+ // BoringSSL uses sentinel salt length values like we do, but the values don't
+ // fully match what we use. We both use -1 for salt length equal to hash length,
+ // but BoringSSL uses -2 to mean maximal size where we use 0. In the latter
+ // case convert to the BoringSSL version.
+ if saltLen == 0 {
+ saltLen = -2
+ }
+
+ if pub.withKey(func(key *C.GO_RSA) C.int {
+ return C._goboringcrypto_RSA_verify_pss_mgf1(key, base(hashed), C.size_t(len(hashed)),
+ md, nil, C.int(saltLen), base(sig), C.size_t(len(sig)))
+ }) == 0 {
+ return fail("RSA_verify_pss_mgf1")
+ }
+ return nil
+}
+
+func SignRSAPKCS1v15(priv *PrivateKeyRSA, h crypto.Hash, hashed []byte) ([]byte, error) {
+ if h == 0 {
+ // No hashing.
+ var out []byte
+ var outLen C.size_t
+ if priv.withKey(func(key *C.GO_RSA) C.int {
+ out = make([]byte, C._goboringcrypto_RSA_size(key))
+ return C._goboringcrypto_RSA_sign_raw(key, &outLen, base(out), C.size_t(len(out)),
+ base(hashed), C.size_t(len(hashed)), C.GO_RSA_PKCS1_PADDING)
+ }) == 0 {
+ return nil, fail("RSA_sign_raw")
+ }
+ return out[:outLen], nil
+ }
+
+ md := cryptoHashToMD(h)
+ if md == nil {
+ return nil, errors.New("crypto/rsa: unsupported hash function: " + strconv.Itoa(int(h)))
+ }
+ nid := C._goboringcrypto_EVP_MD_type(md)
+ var out []byte
+ var outLen C.uint
+ if priv.withKey(func(key *C.GO_RSA) C.int {
+ out = make([]byte, C._goboringcrypto_RSA_size(key))
+ return C._goboringcrypto_RSA_sign(nid, base(hashed), C.uint(len(hashed)),
+ base(out), &outLen, key)
+ }) == 0 {
+ return nil, fail("RSA_sign")
+ }
+ return out[:outLen], nil
+}
+
+func VerifyRSAPKCS1v15(pub *PublicKeyRSA, h crypto.Hash, hashed, sig []byte) error {
+ if h == 0 {
+ var out []byte
+ var outLen C.size_t
+ if pub.withKey(func(key *C.GO_RSA) C.int {
+ out = make([]byte, C._goboringcrypto_RSA_size(key))
+ return C._goboringcrypto_RSA_verify_raw(key, &outLen, base(out),
+ C.size_t(len(out)), base(sig), C.size_t(len(sig)), C.GO_RSA_PKCS1_PADDING)
+ }) == 0 {
+ return fail("RSA_verify")
+ }
+ if subtle.ConstantTimeCompare(hashed, out[:outLen]) != 1 {
+ return fail("RSA_verify")
+ }
+ return nil
+ }
+ md := cryptoHashToMD(h)
+ if md == nil {
+ return errors.New("crypto/rsa: unsupported hash function")
+ }
+ nid := C._goboringcrypto_EVP_MD_type(md)
+ if pub.withKey(func(key *C.GO_RSA) C.int {
+ return C._goboringcrypto_RSA_verify(nid, base(hashed), C.size_t(len(hashed)),
+ base(sig), C.size_t(len(sig)), key)
+ }) == 0 {
+ return fail("RSA_verify")
+ }
+ return nil
+}
diff --git a/src/crypto/internal/boring/sha.go b/src/crypto/internal/boring/sha.go
new file mode 100644
index 0000000..cf82f3f
--- /dev/null
+++ b/src/crypto/internal/boring/sha.go
@@ -0,0 +1,599 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto && linux && (amd64 || arm64) && !android && !cmd_go_bootstrap && !msan
+
+package boring
+
+/*
+#include "goboringcrypto.h"
+
+int
+_goboringcrypto_gosha1(void *p, size_t n, void *out)
+{
+ GO_SHA_CTX ctx;
+ _goboringcrypto_SHA1_Init(&ctx);
+ return _goboringcrypto_SHA1_Update(&ctx, p, n) &&
+ _goboringcrypto_SHA1_Final(out, &ctx);
+}
+
+int
+_goboringcrypto_gosha224(void *p, size_t n, void *out)
+{
+ GO_SHA256_CTX ctx;
+ _goboringcrypto_SHA224_Init(&ctx);
+ return _goboringcrypto_SHA224_Update(&ctx, p, n) &&
+ _goboringcrypto_SHA224_Final(out, &ctx);
+}
+
+int
+_goboringcrypto_gosha256(void *p, size_t n, void *out)
+{
+ GO_SHA256_CTX ctx;
+ _goboringcrypto_SHA256_Init(&ctx);
+ return _goboringcrypto_SHA256_Update(&ctx, p, n) &&
+ _goboringcrypto_SHA256_Final(out, &ctx);
+}
+
+int
+_goboringcrypto_gosha384(void *p, size_t n, void *out)
+{
+ GO_SHA512_CTX ctx;
+ _goboringcrypto_SHA384_Init(&ctx);
+ return _goboringcrypto_SHA384_Update(&ctx, p, n) &&
+ _goboringcrypto_SHA384_Final(out, &ctx);
+}
+
+int
+_goboringcrypto_gosha512(void *p, size_t n, void *out)
+{
+ GO_SHA512_CTX ctx;
+ _goboringcrypto_SHA512_Init(&ctx);
+ return _goboringcrypto_SHA512_Update(&ctx, p, n) &&
+ _goboringcrypto_SHA512_Final(out, &ctx);
+}
+
+*/
+import "C"
+import (
+ "errors"
+ "hash"
+ "unsafe"
+)
+
+// NOTE: The cgo calls in this file are arranged to avoid marking the parameters as escaping.
+// To do that, we call noescape (including via addr).
+// We must also make sure that the data pointer arguments have the form unsafe.Pointer(&...)
+// so that cgo does not annotate them with cgoCheckPointer calls. If it did that, it might look
+// beyond the byte slice and find Go pointers in unprocessed parts of a larger allocation.
+// To do both of these simultaneously, the idiom is unsafe.Pointer(&*addr(p)),
+// where addr returns the base pointer of p, substituting a non-nil pointer for nil,
+// and applying a noescape along the way.
+// This is all to preserve compatibility with the allocation behavior of the non-boring implementations.
+
+func SHA1(p []byte) (sum [20]byte) {
+ if C._goboringcrypto_gosha1(unsafe.Pointer(&*addr(p)), C.size_t(len(p)), unsafe.Pointer(&*addr(sum[:]))) == 0 {
+ panic("boringcrypto: SHA1 failed")
+ }
+ return
+}
+
+func SHA224(p []byte) (sum [28]byte) {
+ if C._goboringcrypto_gosha224(unsafe.Pointer(&*addr(p)), C.size_t(len(p)), unsafe.Pointer(&*addr(sum[:]))) == 0 {
+ panic("boringcrypto: SHA224 failed")
+ }
+ return
+}
+
+func SHA256(p []byte) (sum [32]byte) {
+ if C._goboringcrypto_gosha256(unsafe.Pointer(&*addr(p)), C.size_t(len(p)), unsafe.Pointer(&*addr(sum[:]))) == 0 {
+ panic("boringcrypto: SHA256 failed")
+ }
+ return
+}
+
+func SHA384(p []byte) (sum [48]byte) {
+ if C._goboringcrypto_gosha384(unsafe.Pointer(&*addr(p)), C.size_t(len(p)), unsafe.Pointer(&*addr(sum[:]))) == 0 {
+ panic("boringcrypto: SHA384 failed")
+ }
+ return
+}
+
+func SHA512(p []byte) (sum [64]byte) {
+ if C._goboringcrypto_gosha512(unsafe.Pointer(&*addr(p)), C.size_t(len(p)), unsafe.Pointer(&*addr(sum[:]))) == 0 {
+ panic("boringcrypto: SHA512 failed")
+ }
+ return
+}
+
+// NewSHA1 returns a new SHA1 hash.
+func NewSHA1() hash.Hash {
+ h := new(sha1Hash)
+ h.Reset()
+ return h
+}
+
+type sha1Hash struct {
+ ctx C.GO_SHA_CTX
+ out [20]byte
+}
+
+type sha1Ctx struct {
+ h [5]uint32
+ nl, nh uint32
+ x [64]byte
+ nx uint32
+}
+
+func (h *sha1Hash) noescapeCtx() *C.GO_SHA_CTX {
+ return (*C.GO_SHA_CTX)(noescape(unsafe.Pointer(&h.ctx)))
+}
+
+func (h *sha1Hash) Reset() {
+ C._goboringcrypto_SHA1_Init(h.noescapeCtx())
+}
+
+func (h *sha1Hash) Size() int { return 20 }
+func (h *sha1Hash) BlockSize() int { return 64 }
+func (h *sha1Hash) Sum(dst []byte) []byte { return h.sum(dst) }
+
+func (h *sha1Hash) Write(p []byte) (int, error) {
+ if len(p) > 0 && C._goboringcrypto_SHA1_Update(h.noescapeCtx(), unsafe.Pointer(&*addr(p)), C.size_t(len(p))) == 0 {
+ panic("boringcrypto: SHA1_Update failed")
+ }
+ return len(p), nil
+}
+
+func (h0 *sha1Hash) sum(dst []byte) []byte {
+ h := *h0 // make copy so future Write+Sum is valid
+ if C._goboringcrypto_SHA1_Final((*C.uint8_t)(noescape(unsafe.Pointer(&h.out[0]))), h.noescapeCtx()) == 0 {
+ panic("boringcrypto: SHA1_Final failed")
+ }
+ return append(dst, h.out[:]...)
+}
+
+const (
+ sha1Magic = "sha\x01"
+ sha1MarshaledSize = len(sha1Magic) + 5*4 + 64 + 8
+)
+
+func (h *sha1Hash) MarshalBinary() ([]byte, error) {
+ d := (*sha1Ctx)(unsafe.Pointer(&h.ctx))
+ b := make([]byte, 0, sha1MarshaledSize)
+ b = append(b, sha1Magic...)
+ b = appendUint32(b, d.h[0])
+ b = appendUint32(b, d.h[1])
+ b = appendUint32(b, d.h[2])
+ b = appendUint32(b, d.h[3])
+ b = appendUint32(b, d.h[4])
+ b = append(b, d.x[:d.nx]...)
+ b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
+ b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29)
+ return b, nil
+}
+
+func (h *sha1Hash) UnmarshalBinary(b []byte) error {
+ if len(b) < len(sha1Magic) || string(b[:len(sha1Magic)]) != sha1Magic {
+ return errors.New("crypto/sha1: invalid hash state identifier")
+ }
+ if len(b) != sha1MarshaledSize {
+ return errors.New("crypto/sha1: invalid hash state size")
+ }
+ d := (*sha1Ctx)(unsafe.Pointer(&h.ctx))
+ b = b[len(sha1Magic):]
+ b, d.h[0] = consumeUint32(b)
+ b, d.h[1] = consumeUint32(b)
+ b, d.h[2] = consumeUint32(b)
+ b, d.h[3] = consumeUint32(b)
+ b, d.h[4] = consumeUint32(b)
+ b = b[copy(d.x[:], b):]
+ b, n := consumeUint64(b)
+ d.nl = uint32(n << 3)
+ d.nh = uint32(n >> 29)
+ d.nx = uint32(n) % 64
+ return nil
+}
+
+// NewSHA224 returns a new SHA224 hash.
+func NewSHA224() hash.Hash {
+ h := new(sha224Hash)
+ h.Reset()
+ return h
+}
+
+type sha224Hash struct {
+ ctx C.GO_SHA256_CTX
+ out [224 / 8]byte
+}
+
+func (h *sha224Hash) noescapeCtx() *C.GO_SHA256_CTX {
+ return (*C.GO_SHA256_CTX)(noescape(unsafe.Pointer(&h.ctx)))
+}
+
+func (h *sha224Hash) Reset() {
+ C._goboringcrypto_SHA224_Init(h.noescapeCtx())
+}
+func (h *sha224Hash) Size() int { return 224 / 8 }
+func (h *sha224Hash) BlockSize() int { return 64 }
+func (h *sha224Hash) Sum(dst []byte) []byte { return h.sum(dst) }
+
+func (h *sha224Hash) Write(p []byte) (int, error) {
+ if len(p) > 0 && C._goboringcrypto_SHA224_Update(h.noescapeCtx(), unsafe.Pointer(&*addr(p)), C.size_t(len(p))) == 0 {
+ panic("boringcrypto: SHA224_Update failed")
+ }
+ return len(p), nil
+}
+
+func (h0 *sha224Hash) sum(dst []byte) []byte {
+ h := *h0 // make copy so future Write+Sum is valid
+ if C._goboringcrypto_SHA224_Final((*C.uint8_t)(noescape(unsafe.Pointer(&h.out[0]))), h.noescapeCtx()) == 0 {
+ panic("boringcrypto: SHA224_Final failed")
+ }
+ return append(dst, h.out[:]...)
+}
+
+// NewSHA256 returns a new SHA256 hash.
+func NewSHA256() hash.Hash {
+ h := new(sha256Hash)
+ h.Reset()
+ return h
+}
+
+type sha256Hash struct {
+ ctx C.GO_SHA256_CTX
+ out [256 / 8]byte
+}
+
+func (h *sha256Hash) noescapeCtx() *C.GO_SHA256_CTX {
+ return (*C.GO_SHA256_CTX)(noescape(unsafe.Pointer(&h.ctx)))
+}
+
+func (h *sha256Hash) Reset() {
+ C._goboringcrypto_SHA256_Init(h.noescapeCtx())
+}
+func (h *sha256Hash) Size() int { return 256 / 8 }
+func (h *sha256Hash) BlockSize() int { return 64 }
+func (h *sha256Hash) Sum(dst []byte) []byte { return h.sum(dst) }
+
+func (h *sha256Hash) Write(p []byte) (int, error) {
+ if len(p) > 0 && C._goboringcrypto_SHA256_Update(h.noescapeCtx(), unsafe.Pointer(&*addr(p)), C.size_t(len(p))) == 0 {
+ panic("boringcrypto: SHA256_Update failed")
+ }
+ return len(p), nil
+}
+
+func (h0 *sha256Hash) sum(dst []byte) []byte {
+ h := *h0 // make copy so future Write+Sum is valid
+ if C._goboringcrypto_SHA256_Final((*C.uint8_t)(noescape(unsafe.Pointer(&h.out[0]))), h.noescapeCtx()) == 0 {
+ panic("boringcrypto: SHA256_Final failed")
+ }
+ return append(dst, h.out[:]...)
+}
+
+const (
+ magic224 = "sha\x02"
+ magic256 = "sha\x03"
+ marshaledSize256 = len(magic256) + 8*4 + 64 + 8
+)
+
+type sha256Ctx struct {
+ h [8]uint32
+ nl, nh uint32
+ x [64]byte
+ nx uint32
+}
+
+func (h *sha224Hash) MarshalBinary() ([]byte, error) {
+ d := (*sha256Ctx)(unsafe.Pointer(&h.ctx))
+ b := make([]byte, 0, marshaledSize256)
+ b = append(b, magic224...)
+ b = appendUint32(b, d.h[0])
+ b = appendUint32(b, d.h[1])
+ b = appendUint32(b, d.h[2])
+ b = appendUint32(b, d.h[3])
+ b = appendUint32(b, d.h[4])
+ b = appendUint32(b, d.h[5])
+ b = appendUint32(b, d.h[6])
+ b = appendUint32(b, d.h[7])
+ b = append(b, d.x[:d.nx]...)
+ b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
+ b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29)
+ return b, nil
+}
+
+func (h *sha256Hash) MarshalBinary() ([]byte, error) {
+ d := (*sha256Ctx)(unsafe.Pointer(&h.ctx))
+ b := make([]byte, 0, marshaledSize256)
+ b = append(b, magic256...)
+ b = appendUint32(b, d.h[0])
+ b = appendUint32(b, d.h[1])
+ b = appendUint32(b, d.h[2])
+ b = appendUint32(b, d.h[3])
+ b = appendUint32(b, d.h[4])
+ b = appendUint32(b, d.h[5])
+ b = appendUint32(b, d.h[6])
+ b = appendUint32(b, d.h[7])
+ b = append(b, d.x[:d.nx]...)
+ b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
+ b = appendUint64(b, uint64(d.nl)>>3|uint64(d.nh)<<29)
+ return b, nil
+}
+
+func (h *sha224Hash) UnmarshalBinary(b []byte) error {
+ if len(b) < len(magic224) || string(b[:len(magic224)]) != magic224 {
+ return errors.New("crypto/sha256: invalid hash state identifier")
+ }
+ if len(b) != marshaledSize256 {
+ return errors.New("crypto/sha256: invalid hash state size")
+ }
+ d := (*sha256Ctx)(unsafe.Pointer(&h.ctx))
+ b = b[len(magic224):]
+ b, d.h[0] = consumeUint32(b)
+ b, d.h[1] = consumeUint32(b)
+ b, d.h[2] = consumeUint32(b)
+ b, d.h[3] = consumeUint32(b)
+ b, d.h[4] = consumeUint32(b)
+ b, d.h[5] = consumeUint32(b)
+ b, d.h[6] = consumeUint32(b)
+ b, d.h[7] = consumeUint32(b)
+ b = b[copy(d.x[:], b):]
+ b, n := consumeUint64(b)
+ d.nl = uint32(n << 3)
+ d.nh = uint32(n >> 29)
+ d.nx = uint32(n) % 64
+ return nil
+}
+
+func (h *sha256Hash) UnmarshalBinary(b []byte) error {
+ if len(b) < len(magic256) || string(b[:len(magic256)]) != magic256 {
+ return errors.New("crypto/sha256: invalid hash state identifier")
+ }
+ if len(b) != marshaledSize256 {
+ return errors.New("crypto/sha256: invalid hash state size")
+ }
+ d := (*sha256Ctx)(unsafe.Pointer(&h.ctx))
+ b = b[len(magic256):]
+ b, d.h[0] = consumeUint32(b)
+ b, d.h[1] = consumeUint32(b)
+ b, d.h[2] = consumeUint32(b)
+ b, d.h[3] = consumeUint32(b)
+ b, d.h[4] = consumeUint32(b)
+ b, d.h[5] = consumeUint32(b)
+ b, d.h[6] = consumeUint32(b)
+ b, d.h[7] = consumeUint32(b)
+ b = b[copy(d.x[:], b):]
+ b, n := consumeUint64(b)
+ d.nl = uint32(n << 3)
+ d.nh = uint32(n >> 29)
+ d.nx = uint32(n) % 64
+ return nil
+}
+
+// NewSHA384 returns a new SHA384 hash.
+func NewSHA384() hash.Hash {
+ h := new(sha384Hash)
+ h.Reset()
+ return h
+}
+
+type sha384Hash struct {
+ ctx C.GO_SHA512_CTX
+ out [384 / 8]byte
+}
+
+func (h *sha384Hash) noescapeCtx() *C.GO_SHA512_CTX {
+ return (*C.GO_SHA512_CTX)(noescape(unsafe.Pointer(&h.ctx)))
+}
+
+func (h *sha384Hash) Reset() {
+ C._goboringcrypto_SHA384_Init(h.noescapeCtx())
+}
+func (h *sha384Hash) Size() int { return 384 / 8 }
+func (h *sha384Hash) BlockSize() int { return 128 }
+func (h *sha384Hash) Sum(dst []byte) []byte { return h.sum(dst) }
+
+func (h *sha384Hash) Write(p []byte) (int, error) {
+ if len(p) > 0 && C._goboringcrypto_SHA384_Update(h.noescapeCtx(), unsafe.Pointer(&*addr(p)), C.size_t(len(p))) == 0 {
+ panic("boringcrypto: SHA384_Update failed")
+ }
+ return len(p), nil
+}
+
+func (h0 *sha384Hash) sum(dst []byte) []byte {
+ h := *h0 // make copy so future Write+Sum is valid
+ if C._goboringcrypto_SHA384_Final((*C.uint8_t)(noescape(unsafe.Pointer(&h.out[0]))), h.noescapeCtx()) == 0 {
+ panic("boringcrypto: SHA384_Final failed")
+ }
+ return append(dst, h.out[:]...)
+}
+
+// NewSHA512 returns a new SHA512 hash.
+func NewSHA512() hash.Hash {
+ h := new(sha512Hash)
+ h.Reset()
+ return h
+}
+
+type sha512Hash struct {
+ ctx C.GO_SHA512_CTX
+ out [512 / 8]byte
+}
+
+func (h *sha512Hash) noescapeCtx() *C.GO_SHA512_CTX {
+ return (*C.GO_SHA512_CTX)(noescape(unsafe.Pointer(&h.ctx)))
+}
+
+func (h *sha512Hash) Reset() {
+ C._goboringcrypto_SHA512_Init(h.noescapeCtx())
+}
+func (h *sha512Hash) Size() int { return 512 / 8 }
+func (h *sha512Hash) BlockSize() int { return 128 }
+func (h *sha512Hash) Sum(dst []byte) []byte { return h.sum(dst) }
+
+func (h *sha512Hash) Write(p []byte) (int, error) {
+ if len(p) > 0 && C._goboringcrypto_SHA512_Update(h.noescapeCtx(), unsafe.Pointer(&*addr(p)), C.size_t(len(p))) == 0 {
+ panic("boringcrypto: SHA512_Update failed")
+ }
+ return len(p), nil
+}
+
+func (h0 *sha512Hash) sum(dst []byte) []byte {
+ h := *h0 // make copy so future Write+Sum is valid
+ if C._goboringcrypto_SHA512_Final((*C.uint8_t)(noescape(unsafe.Pointer(&h.out[0]))), h.noescapeCtx()) == 0 {
+ panic("boringcrypto: SHA512_Final failed")
+ }
+ return append(dst, h.out[:]...)
+}
+
+type sha512Ctx struct {
+ h [8]uint64
+ nl, nh uint64
+ x [128]byte
+ nx uint32
+}
+
+const (
+ magic384 = "sha\x04"
+ magic512_224 = "sha\x05"
+ magic512_256 = "sha\x06"
+ magic512 = "sha\x07"
+ marshaledSize512 = len(magic512) + 8*8 + 128 + 8
+)
+
+func (h *sha384Hash) MarshalBinary() ([]byte, error) {
+ d := (*sha512Ctx)(unsafe.Pointer(&h.ctx))
+ b := make([]byte, 0, marshaledSize512)
+ b = append(b, magic384...)
+ b = appendUint64(b, d.h[0])
+ b = appendUint64(b, d.h[1])
+ b = appendUint64(b, d.h[2])
+ b = appendUint64(b, d.h[3])
+ b = appendUint64(b, d.h[4])
+ b = appendUint64(b, d.h[5])
+ b = appendUint64(b, d.h[6])
+ b = appendUint64(b, d.h[7])
+ b = append(b, d.x[:d.nx]...)
+ b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
+ b = appendUint64(b, d.nl>>3|d.nh<<61)
+ return b, nil
+}
+
+func (h *sha512Hash) MarshalBinary() ([]byte, error) {
+ d := (*sha512Ctx)(unsafe.Pointer(&h.ctx))
+ b := make([]byte, 0, marshaledSize512)
+ b = append(b, magic512...)
+ b = appendUint64(b, d.h[0])
+ b = appendUint64(b, d.h[1])
+ b = appendUint64(b, d.h[2])
+ b = appendUint64(b, d.h[3])
+ b = appendUint64(b, d.h[4])
+ b = appendUint64(b, d.h[5])
+ b = appendUint64(b, d.h[6])
+ b = appendUint64(b, d.h[7])
+ b = append(b, d.x[:d.nx]...)
+ b = b[:len(b)+len(d.x)-int(d.nx)] // already zero
+ b = appendUint64(b, d.nl>>3|d.nh<<61)
+ return b, nil
+}
+
+func (h *sha384Hash) UnmarshalBinary(b []byte) error {
+ if len(b) < len(magic512) {
+ return errors.New("crypto/sha512: invalid hash state identifier")
+ }
+ if string(b[:len(magic384)]) != magic384 {
+ return errors.New("crypto/sha512: invalid hash state identifier")
+ }
+ if len(b) != marshaledSize512 {
+ return errors.New("crypto/sha512: invalid hash state size")
+ }
+ d := (*sha512Ctx)(unsafe.Pointer(&h.ctx))
+ b = b[len(magic512):]
+ b, d.h[0] = consumeUint64(b)
+ b, d.h[1] = consumeUint64(b)
+ b, d.h[2] = consumeUint64(b)
+ b, d.h[3] = consumeUint64(b)
+ b, d.h[4] = consumeUint64(b)
+ b, d.h[5] = consumeUint64(b)
+ b, d.h[6] = consumeUint64(b)
+ b, d.h[7] = consumeUint64(b)
+ b = b[copy(d.x[:], b):]
+ b, n := consumeUint64(b)
+ d.nl = n << 3
+ d.nh = n >> 61
+ d.nx = uint32(n) % 128
+ return nil
+}
+
+func (h *sha512Hash) UnmarshalBinary(b []byte) error {
+ if len(b) < len(magic512) {
+ return errors.New("crypto/sha512: invalid hash state identifier")
+ }
+ if string(b[:len(magic512)]) != magic512 {
+ return errors.New("crypto/sha512: invalid hash state identifier")
+ }
+ if len(b) != marshaledSize512 {
+ return errors.New("crypto/sha512: invalid hash state size")
+ }
+ d := (*sha512Ctx)(unsafe.Pointer(&h.ctx))
+ b = b[len(magic512):]
+ b, d.h[0] = consumeUint64(b)
+ b, d.h[1] = consumeUint64(b)
+ b, d.h[2] = consumeUint64(b)
+ b, d.h[3] = consumeUint64(b)
+ b, d.h[4] = consumeUint64(b)
+ b, d.h[5] = consumeUint64(b)
+ b, d.h[6] = consumeUint64(b)
+ b, d.h[7] = consumeUint64(b)
+ b = b[copy(d.x[:], b):]
+ b, n := consumeUint64(b)
+ d.nl = n << 3
+ d.nh = n >> 61
+ d.nx = uint32(n) % 128
+ return nil
+}
+
+func appendUint64(b []byte, x uint64) []byte {
+ var a [8]byte
+ putUint64(a[:], x)
+ return append(b, a[:]...)
+}
+
+func appendUint32(b []byte, x uint32) []byte {
+ var a [4]byte
+ putUint32(a[:], x)
+ return append(b, a[:]...)
+}
+
+func consumeUint64(b []byte) ([]byte, uint64) {
+ _ = b[7]
+ x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+ uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+ return b[8:], x
+}
+
+func consumeUint32(b []byte) ([]byte, uint32) {
+ _ = b[3]
+ x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+ return b[4:], x
+}
+
+func putUint64(x []byte, s uint64) {
+ _ = x[7]
+ x[0] = byte(s >> 56)
+ x[1] = byte(s >> 48)
+ x[2] = byte(s >> 40)
+ x[3] = byte(s >> 32)
+ x[4] = byte(s >> 24)
+ x[5] = byte(s >> 16)
+ x[6] = byte(s >> 8)
+ x[7] = byte(s)
+}
+
+func putUint32(x []byte, s uint32) {
+ _ = x[3]
+ x[0] = byte(s >> 24)
+ x[1] = byte(s >> 16)
+ x[2] = byte(s >> 8)
+ x[3] = byte(s)
+}
diff --git a/src/crypto/internal/boring/sig/sig.go b/src/crypto/internal/boring/sig/sig.go
new file mode 100644
index 0000000..716c03c
--- /dev/null
+++ b/src/crypto/internal/boring/sig/sig.go
@@ -0,0 +1,17 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sig holds “code signatures” that can be called
+// and will result in certain code sequences being linked into
+// the final binary. The functions themselves are no-ops.
+package sig
+
+// BoringCrypto indicates that the BoringCrypto module is present.
+func BoringCrypto()
+
+// FIPSOnly indicates that package crypto/tls/fipsonly is present.
+func FIPSOnly()
+
+// StandardCrypto indicates that standard Go crypto is present.
+func StandardCrypto()
diff --git a/src/crypto/internal/boring/sig/sig_amd64.s b/src/crypto/internal/boring/sig/sig_amd64.s
new file mode 100644
index 0000000..64e3462
--- /dev/null
+++ b/src/crypto/internal/boring/sig/sig_amd64.s
@@ -0,0 +1,54 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// These functions are no-ops, but you can search for their implementations
+// to find out whether they are linked into a particular binary.
+//
+// Each function consists of a two-byte jump over the next 29-bytes,
+// then a 5-byte indicator sequence unlikely to occur in real x86 instructions,
+// then a randomly-chosen 24-byte sequence, and finally a return instruction
+// (the target of the jump).
+//
+// These sequences are known to rsc.io/goversion.
+
+#define START \
+ BYTE $0xEB; BYTE $0x1D; BYTE $0xF4; BYTE $0x48; BYTE $0xF4; BYTE $0x4B; BYTE $0xF4
+
+#define END \
+ BYTE $0xC3
+
+// BoringCrypto indicates that BoringCrypto (in particular, its func init) is present.
+TEXT ·BoringCrypto(SB),NOSPLIT,$0
+ START
+ BYTE $0xB3; BYTE $0x32; BYTE $0xF5; BYTE $0x28;
+ BYTE $0x13; BYTE $0xA3; BYTE $0xB4; BYTE $0x50;
+ BYTE $0xD4; BYTE $0x41; BYTE $0xCC; BYTE $0x24;
+ BYTE $0x85; BYTE $0xF0; BYTE $0x01; BYTE $0x45;
+ BYTE $0x4E; BYTE $0x92; BYTE $0x10; BYTE $0x1B;
+ BYTE $0x1D; BYTE $0x2F; BYTE $0x19; BYTE $0x50;
+ END
+
+// StandardCrypto indicates that standard Go crypto is present.
+TEXT ·StandardCrypto(SB),NOSPLIT,$0
+ START
+ BYTE $0xba; BYTE $0xee; BYTE $0x4d; BYTE $0xfa;
+ BYTE $0x98; BYTE $0x51; BYTE $0xca; BYTE $0x56;
+ BYTE $0xa9; BYTE $0x11; BYTE $0x45; BYTE $0xe8;
+ BYTE $0x3e; BYTE $0x99; BYTE $0xc5; BYTE $0x9c;
+ BYTE $0xf9; BYTE $0x11; BYTE $0xcb; BYTE $0x8e;
+ BYTE $0x80; BYTE $0xda; BYTE $0xf1; BYTE $0x2f;
+ END
+
+// FIPSOnly indicates that crypto/tls/fipsonly is present.
+TEXT ·FIPSOnly(SB),NOSPLIT,$0
+ START
+ BYTE $0x36; BYTE $0x3C; BYTE $0xB9; BYTE $0xCE;
+ BYTE $0x9D; BYTE $0x68; BYTE $0x04; BYTE $0x7D;
+ BYTE $0x31; BYTE $0xF2; BYTE $0x8D; BYTE $0x32;
+ BYTE $0x5D; BYTE $0x5C; BYTE $0xA5; BYTE $0x87;
+ BYTE $0x3F; BYTE $0x5D; BYTE $0x80; BYTE $0xCA;
+ BYTE $0xF6; BYTE $0xD6; BYTE $0x15; BYTE $0x1B;
+ END
diff --git a/src/crypto/internal/boring/sig/sig_other.s b/src/crypto/internal/boring/sig/sig_other.s
new file mode 100644
index 0000000..2bbb1df
--- /dev/null
+++ b/src/crypto/internal/boring/sig/sig_other.s
@@ -0,0 +1,20 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// These functions are no-ops.
+// On amd64 they have recognizable implementations, so that you can
+// search a particular binary to see if they are present.
+// On other platforms (those using this source file), they don't.
+
+//go:build !amd64
+// +build !amd64
+
+TEXT ·BoringCrypto(SB),$0
+ RET
+
+TEXT ·FIPSOnly(SB),$0
+ RET
+
+TEXT ·StandardCrypto(SB),$0
+ RET
diff --git a/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso b/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso
new file mode 100644
index 0000000..6cea789
--- /dev/null
+++ b/src/crypto/internal/boring/syso/goboringcrypto_linux_amd64.syso
Binary files differ
diff --git a/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso b/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso
new file mode 100644
index 0000000..9659aa1
--- /dev/null
+++ b/src/crypto/internal/boring/syso/goboringcrypto_linux_arm64.syso
Binary files differ
diff --git a/src/crypto/internal/boring/syso/syso.go b/src/crypto/internal/boring/syso/syso.go
new file mode 100644
index 0000000..b338754
--- /dev/null
+++ b/src/crypto/internal/boring/syso/syso.go
@@ -0,0 +1,9 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto
+
+// This package only exists with GOEXPERIMENT=boringcrypto.
+// It provides the actual syso file.
+package syso
diff --git a/src/crypto/internal/edwards25519/doc.go b/src/crypto/internal/edwards25519/doc.go
new file mode 100644
index 0000000..8cba6fe
--- /dev/null
+++ b/src/crypto/internal/edwards25519/doc.go
@@ -0,0 +1,22 @@
+// Copyright (c) 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package edwards25519 implements group logic for the twisted Edwards curve
+//
+// -x^2 + y^2 = 1 + -(121665/121666)*x^2*y^2
+//
+// This is better known as the Edwards curve equivalent to Curve25519, and is
+// the curve used by the Ed25519 signature scheme.
+//
+// Most users don't need this package, and should instead use crypto/ed25519 for
+// signatures, golang.org/x/crypto/curve25519 for Diffie-Hellman, or
+// github.com/gtank/ristretto255 for prime order group logic.
+//
+// However, developers who do need to interact with low-level edwards25519
+// operations can use filippo.io/edwards25519, an extended version of this
+// package repackaged as an importable module.
+//
+// (Note that filippo.io/edwards25519 and github.com/gtank/ristretto255 are not
+// maintained by the Go team and are not covered by the Go 1 Compatibility Promise.)
+package edwards25519
diff --git a/src/crypto/internal/edwards25519/edwards25519.go b/src/crypto/internal/edwards25519/edwards25519.go
new file mode 100644
index 0000000..71e9c09
--- /dev/null
+++ b/src/crypto/internal/edwards25519/edwards25519.go
@@ -0,0 +1,426 @@
+// Copyright (c) 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+import (
+ "crypto/internal/edwards25519/field"
+ "errors"
+)
+
+// Point types.
+
+type projP1xP1 struct {
+ X, Y, Z, T field.Element
+}
+
+type projP2 struct {
+ X, Y, Z field.Element
+}
+
+// Point represents a point on the edwards25519 curve.
+//
+// This type works similarly to math/big.Int, and all arguments and receivers
+// are allowed to alias.
+//
+// The zero value is NOT valid, and it may be used only as a receiver.
+type Point struct {
+ // The point is internally represented in extended coordinates (X, Y, Z, T)
+ // where x = X/Z, y = Y/Z, and xy = T/Z per https://eprint.iacr.org/2008/522.
+ x, y, z, t field.Element
+
+ // Make the type not comparable (i.e. used with == or as a map key), as
+ // equivalent points can be represented by different Go values.
+ _ incomparable
+}
+
+type incomparable [0]func()
+
+func checkInitialized(points ...*Point) {
+ for _, p := range points {
+ if p.x == (field.Element{}) && p.y == (field.Element{}) {
+ panic("edwards25519: use of uninitialized Point")
+ }
+ }
+}
+
+type projCached struct {
+ YplusX, YminusX, Z, T2d field.Element
+}
+
+type affineCached struct {
+ YplusX, YminusX, T2d field.Element
+}
+
+// Constructors.
+
+func (v *projP2) Zero() *projP2 {
+ v.X.Zero()
+ v.Y.One()
+ v.Z.One()
+ return v
+}
+
+// identity is the point at infinity.
+var identity, _ = new(Point).SetBytes([]byte{
+ 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
+
+// NewIdentityPoint returns a new Point set to the identity.
+func NewIdentityPoint() *Point {
+ return new(Point).Set(identity)
+}
+
+// generator is the canonical curve basepoint. See TestGenerator for the
+// correspondence of this encoding with the values in RFC 8032.
+var generator, _ = new(Point).SetBytes([]byte{
+ 0x58, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66,
+ 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66, 0x66})
+
+// NewGeneratorPoint returns a new Point set to the canonical generator.
+func NewGeneratorPoint() *Point {
+ return new(Point).Set(generator)
+}
+
+func (v *projCached) Zero() *projCached {
+ v.YplusX.One()
+ v.YminusX.One()
+ v.Z.One()
+ v.T2d.Zero()
+ return v
+}
+
+func (v *affineCached) Zero() *affineCached {
+ v.YplusX.One()
+ v.YminusX.One()
+ v.T2d.Zero()
+ return v
+}
+
+// Assignments.
+
+// Set sets v = u, and returns v.
+func (v *Point) Set(u *Point) *Point {
+ *v = *u
+ return v
+}
+
+// Encoding.
+
+// Bytes returns the canonical 32-byte encoding of v, according to RFC 8032,
+// Section 5.1.2.
+func (v *Point) Bytes() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var buf [32]byte
+ return v.bytes(&buf)
+}
+
+func (v *Point) bytes(buf *[32]byte) []byte {
+ checkInitialized(v)
+
+ var zInv, x, y field.Element
+ zInv.Invert(&v.z) // zInv = 1 / Z
+ x.Multiply(&v.x, &zInv) // x = X / Z
+ y.Multiply(&v.y, &zInv) // y = Y / Z
+
+ out := copyFieldElement(buf, &y)
+ out[31] |= byte(x.IsNegative() << 7)
+ return out
+}
+
+var feOne = new(field.Element).One()
+
+// SetBytes sets v = x, where x is a 32-byte encoding of v. If x does not
+// represent a valid point on the curve, SetBytes returns nil and an error and
+// the receiver is unchanged. Otherwise, SetBytes returns v.
+//
+// Note that SetBytes accepts all non-canonical encodings of valid points.
+// That is, it follows decoding rules that match most implementations in
+// the ecosystem rather than RFC 8032.
+func (v *Point) SetBytes(x []byte) (*Point, error) {
+ // Specifically, the non-canonical encodings that are accepted are
+ // 1) the ones where the field element is not reduced (see the
+ // (*field.Element).SetBytes docs) and
+ // 2) the ones where the x-coordinate is zero and the sign bit is set.
+ //
+ // Read more at https://hdevalence.ca/blog/2020-10-04-its-25519am,
+ // specifically the "Canonical A, R" section.
+
+ y, err := new(field.Element).SetBytes(x)
+ if err != nil {
+ return nil, errors.New("edwards25519: invalid point encoding length")
+ }
+
+ // -x² + y² = 1 + dx²y²
+ // x² + dx²y² = x²(dy² + 1) = y² - 1
+ // x² = (y² - 1) / (dy² + 1)
+
+ // u = y² - 1
+ y2 := new(field.Element).Square(y)
+ u := new(field.Element).Subtract(y2, feOne)
+
+ // v = dy² + 1
+ vv := new(field.Element).Multiply(y2, d)
+ vv = vv.Add(vv, feOne)
+
+ // x = +√(u/v)
+ xx, wasSquare := new(field.Element).SqrtRatio(u, vv)
+ if wasSquare == 0 {
+ return nil, errors.New("edwards25519: invalid point encoding")
+ }
+
+ // Select the negative square root if the sign bit is set.
+ xxNeg := new(field.Element).Negate(xx)
+ xx = xx.Select(xxNeg, xx, int(x[31]>>7))
+
+ v.x.Set(xx)
+ v.y.Set(y)
+ v.z.One()
+ v.t.Multiply(xx, y) // xy = T / Z
+
+ return v, nil
+}
+
+func copyFieldElement(buf *[32]byte, v *field.Element) []byte {
+ copy(buf[:], v.Bytes())
+ return buf[:]
+}
+
+// Conversions.
+
+func (v *projP2) FromP1xP1(p *projP1xP1) *projP2 {
+ v.X.Multiply(&p.X, &p.T)
+ v.Y.Multiply(&p.Y, &p.Z)
+ v.Z.Multiply(&p.Z, &p.T)
+ return v
+}
+
+func (v *projP2) FromP3(p *Point) *projP2 {
+ v.X.Set(&p.x)
+ v.Y.Set(&p.y)
+ v.Z.Set(&p.z)
+ return v
+}
+
+func (v *Point) fromP1xP1(p *projP1xP1) *Point {
+ v.x.Multiply(&p.X, &p.T)
+ v.y.Multiply(&p.Y, &p.Z)
+ v.z.Multiply(&p.Z, &p.T)
+ v.t.Multiply(&p.X, &p.Y)
+ return v
+}
+
+func (v *Point) fromP2(p *projP2) *Point {
+ v.x.Multiply(&p.X, &p.Z)
+ v.y.Multiply(&p.Y, &p.Z)
+ v.z.Square(&p.Z)
+ v.t.Multiply(&p.X, &p.Y)
+ return v
+}
+
+// d is a constant in the curve equation.
+var d, _ = new(field.Element).SetBytes([]byte{
+ 0xa3, 0x78, 0x59, 0x13, 0xca, 0x4d, 0xeb, 0x75,
+ 0xab, 0xd8, 0x41, 0x41, 0x4d, 0x0a, 0x70, 0x00,
+ 0x98, 0xe8, 0x79, 0x77, 0x79, 0x40, 0xc7, 0x8c,
+ 0x73, 0xfe, 0x6f, 0x2b, 0xee, 0x6c, 0x03, 0x52})
+var d2 = new(field.Element).Add(d, d)
+
+func (v *projCached) FromP3(p *Point) *projCached {
+ v.YplusX.Add(&p.y, &p.x)
+ v.YminusX.Subtract(&p.y, &p.x)
+ v.Z.Set(&p.z)
+ v.T2d.Multiply(&p.t, d2)
+ return v
+}
+
+func (v *affineCached) FromP3(p *Point) *affineCached {
+ v.YplusX.Add(&p.y, &p.x)
+ v.YminusX.Subtract(&p.y, &p.x)
+ v.T2d.Multiply(&p.t, d2)
+
+ var invZ field.Element
+ invZ.Invert(&p.z)
+ v.YplusX.Multiply(&v.YplusX, &invZ)
+ v.YminusX.Multiply(&v.YminusX, &invZ)
+ v.T2d.Multiply(&v.T2d, &invZ)
+ return v
+}
+
+// (Re)addition and subtraction.
+
+// Add sets v = p + q, and returns v.
+func (v *Point) Add(p, q *Point) *Point {
+ checkInitialized(p, q)
+ qCached := new(projCached).FromP3(q)
+ result := new(projP1xP1).Add(p, qCached)
+ return v.fromP1xP1(result)
+}
+
+// Subtract sets v = p - q, and returns v.
+func (v *Point) Subtract(p, q *Point) *Point {
+ checkInitialized(p, q)
+ qCached := new(projCached).FromP3(q)
+ result := new(projP1xP1).Sub(p, qCached)
+ return v.fromP1xP1(result)
+}
+
+func (v *projP1xP1) Add(p *Point, q *projCached) *projP1xP1 {
+ var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element
+
+ YplusX.Add(&p.y, &p.x)
+ YminusX.Subtract(&p.y, &p.x)
+
+ PP.Multiply(&YplusX, &q.YplusX)
+ MM.Multiply(&YminusX, &q.YminusX)
+ TT2d.Multiply(&p.t, &q.T2d)
+ ZZ2.Multiply(&p.z, &q.Z)
+
+ ZZ2.Add(&ZZ2, &ZZ2)
+
+ v.X.Subtract(&PP, &MM)
+ v.Y.Add(&PP, &MM)
+ v.Z.Add(&ZZ2, &TT2d)
+ v.T.Subtract(&ZZ2, &TT2d)
+ return v
+}
+
+func (v *projP1xP1) Sub(p *Point, q *projCached) *projP1xP1 {
+ var YplusX, YminusX, PP, MM, TT2d, ZZ2 field.Element
+
+ YplusX.Add(&p.y, &p.x)
+ YminusX.Subtract(&p.y, &p.x)
+
+ PP.Multiply(&YplusX, &q.YminusX) // flipped sign
+ MM.Multiply(&YminusX, &q.YplusX) // flipped sign
+ TT2d.Multiply(&p.t, &q.T2d)
+ ZZ2.Multiply(&p.z, &q.Z)
+
+ ZZ2.Add(&ZZ2, &ZZ2)
+
+ v.X.Subtract(&PP, &MM)
+ v.Y.Add(&PP, &MM)
+ v.Z.Subtract(&ZZ2, &TT2d) // flipped sign
+ v.T.Add(&ZZ2, &TT2d) // flipped sign
+ return v
+}
+
+func (v *projP1xP1) AddAffine(p *Point, q *affineCached) *projP1xP1 {
+ var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element
+
+ YplusX.Add(&p.y, &p.x)
+ YminusX.Subtract(&p.y, &p.x)
+
+ PP.Multiply(&YplusX, &q.YplusX)
+ MM.Multiply(&YminusX, &q.YminusX)
+ TT2d.Multiply(&p.t, &q.T2d)
+
+ Z2.Add(&p.z, &p.z)
+
+ v.X.Subtract(&PP, &MM)
+ v.Y.Add(&PP, &MM)
+ v.Z.Add(&Z2, &TT2d)
+ v.T.Subtract(&Z2, &TT2d)
+ return v
+}
+
+func (v *projP1xP1) SubAffine(p *Point, q *affineCached) *projP1xP1 {
+ var YplusX, YminusX, PP, MM, TT2d, Z2 field.Element
+
+ YplusX.Add(&p.y, &p.x)
+ YminusX.Subtract(&p.y, &p.x)
+
+ PP.Multiply(&YplusX, &q.YminusX) // flipped sign
+ MM.Multiply(&YminusX, &q.YplusX) // flipped sign
+ TT2d.Multiply(&p.t, &q.T2d)
+
+ Z2.Add(&p.z, &p.z)
+
+ v.X.Subtract(&PP, &MM)
+ v.Y.Add(&PP, &MM)
+ v.Z.Subtract(&Z2, &TT2d) // flipped sign
+ v.T.Add(&Z2, &TT2d) // flipped sign
+ return v
+}
+
+// Doubling.
+
+func (v *projP1xP1) Double(p *projP2) *projP1xP1 {
+ var XX, YY, ZZ2, XplusYsq field.Element
+
+ XX.Square(&p.X)
+ YY.Square(&p.Y)
+ ZZ2.Square(&p.Z)
+ ZZ2.Add(&ZZ2, &ZZ2)
+ XplusYsq.Add(&p.X, &p.Y)
+ XplusYsq.Square(&XplusYsq)
+
+ v.Y.Add(&YY, &XX)
+ v.Z.Subtract(&YY, &XX)
+
+ v.X.Subtract(&XplusYsq, &v.Y)
+ v.T.Subtract(&ZZ2, &v.Z)
+ return v
+}
+
+// Negation.
+
+// Negate sets v = -p, and returns v.
+func (v *Point) Negate(p *Point) *Point {
+ checkInitialized(p)
+ v.x.Negate(&p.x)
+ v.y.Set(&p.y)
+ v.z.Set(&p.z)
+ v.t.Negate(&p.t)
+ return v
+}
+
+// Equal returns 1 if v is equivalent to u, and 0 otherwise.
+func (v *Point) Equal(u *Point) int {
+ checkInitialized(v, u)
+
+ var t1, t2, t3, t4 field.Element
+ t1.Multiply(&v.x, &u.z)
+ t2.Multiply(&u.x, &v.z)
+ t3.Multiply(&v.y, &u.z)
+ t4.Multiply(&u.y, &v.z)
+
+ return t1.Equal(&t2) & t3.Equal(&t4)
+}
+
+// Constant-time operations
+
+// Select sets v to a if cond == 1 and to b if cond == 0.
+func (v *projCached) Select(a, b *projCached, cond int) *projCached {
+ v.YplusX.Select(&a.YplusX, &b.YplusX, cond)
+ v.YminusX.Select(&a.YminusX, &b.YminusX, cond)
+ v.Z.Select(&a.Z, &b.Z, cond)
+ v.T2d.Select(&a.T2d, &b.T2d, cond)
+ return v
+}
+
+// Select sets v to a if cond == 1 and to b if cond == 0.
+func (v *affineCached) Select(a, b *affineCached, cond int) *affineCached {
+ v.YplusX.Select(&a.YplusX, &b.YplusX, cond)
+ v.YminusX.Select(&a.YminusX, &b.YminusX, cond)
+ v.T2d.Select(&a.T2d, &b.T2d, cond)
+ return v
+}
+
+// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0.
+func (v *projCached) CondNeg(cond int) *projCached {
+ v.YplusX.Swap(&v.YminusX, cond)
+ v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond)
+ return v
+}
+
+// CondNeg negates v if cond == 1 and leaves it unchanged if cond == 0.
+func (v *affineCached) CondNeg(cond int) *affineCached {
+ v.YplusX.Swap(&v.YminusX, cond)
+ v.T2d.Select(new(field.Element).Negate(&v.T2d), &v.T2d, cond)
+ return v
+}
diff --git a/src/crypto/internal/edwards25519/edwards25519_test.go b/src/crypto/internal/edwards25519/edwards25519_test.go
new file mode 100644
index 0000000..307ae26
--- /dev/null
+++ b/src/crypto/internal/edwards25519/edwards25519_test.go
@@ -0,0 +1,313 @@
+// Copyright (c) 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+import (
+ "crypto/internal/edwards25519/field"
+ "encoding/hex"
+ "internal/testenv"
+ "reflect"
+ "testing"
+)
+
+var B = NewGeneratorPoint()
+var I = NewIdentityPoint()
+
+func checkOnCurve(t *testing.T, points ...*Point) {
+ t.Helper()
+ for i, p := range points {
+ var XX, YY, ZZ, ZZZZ field.Element
+ XX.Square(&p.x)
+ YY.Square(&p.y)
+ ZZ.Square(&p.z)
+ ZZZZ.Square(&ZZ)
+ // -x² + y² = 1 + dx²y²
+ // -(X/Z)² + (Y/Z)² = 1 + d(X/Z)²(Y/Z)²
+ // (-X² + Y²)/Z² = 1 + (dX²Y²)/Z⁴
+ // (-X² + Y²)*Z² = Z⁴ + dX²Y²
+ var lhs, rhs field.Element
+ lhs.Subtract(&YY, &XX).Multiply(&lhs, &ZZ)
+ rhs.Multiply(d, &XX).Multiply(&rhs, &YY).Add(&rhs, &ZZZZ)
+ if lhs.Equal(&rhs) != 1 {
+ t.Errorf("X, Y, and Z do not specify a point on the curve\nX = %v\nY = %v\nZ = %v", p.x, p.y, p.z)
+ }
+ // xy = T/Z
+ lhs.Multiply(&p.x, &p.y)
+ rhs.Multiply(&p.z, &p.t)
+ if lhs.Equal(&rhs) != 1 {
+ t.Errorf("point %d is not valid\nX = %v\nY = %v\nZ = %v", i, p.x, p.y, p.z)
+ }
+ }
+}
+
+func TestGenerator(t *testing.T) {
+ // These are the coordinates of B from RFC 8032, Section 5.1, converted to
+ // little endian hex.
+ x := "1ad5258f602d56c9b2a7259560c72c695cdcd6fd31e2a4c0fe536ecdd3366921"
+ y := "5866666666666666666666666666666666666666666666666666666666666666"
+ if got := hex.EncodeToString(B.x.Bytes()); got != x {
+ t.Errorf("wrong B.x: got %s, expected %s", got, x)
+ }
+ if got := hex.EncodeToString(B.y.Bytes()); got != y {
+ t.Errorf("wrong B.y: got %s, expected %s", got, y)
+ }
+ if B.z.Equal(feOne) != 1 {
+ t.Errorf("wrong B.z: got %v, expected 1", B.z)
+ }
+ // Check that t is correct.
+ checkOnCurve(t, B)
+}
+
+func TestAddSubNegOnBasePoint(t *testing.T) {
+ checkLhs, checkRhs := &Point{}, &Point{}
+
+ checkLhs.Add(B, B)
+ tmpP2 := new(projP2).FromP3(B)
+ tmpP1xP1 := new(projP1xP1).Double(tmpP2)
+ checkRhs.fromP1xP1(tmpP1xP1)
+ if checkLhs.Equal(checkRhs) != 1 {
+ t.Error("B + B != [2]B")
+ }
+ checkOnCurve(t, checkLhs, checkRhs)
+
+ checkLhs.Subtract(B, B)
+ Bneg := new(Point).Negate(B)
+ checkRhs.Add(B, Bneg)
+ if checkLhs.Equal(checkRhs) != 1 {
+ t.Error("B - B != B + (-B)")
+ }
+ if I.Equal(checkLhs) != 1 {
+ t.Error("B - B != 0")
+ }
+ if I.Equal(checkRhs) != 1 {
+ t.Error("B + (-B) != 0")
+ }
+ checkOnCurve(t, checkLhs, checkRhs, Bneg)
+}
+
+func TestComparable(t *testing.T) {
+ if reflect.TypeOf(Point{}).Comparable() {
+ t.Error("Point is unexpectedly comparable")
+ }
+}
+
+func TestInvalidEncodings(t *testing.T) {
+ // An invalid point, that also happens to have y > p.
+ invalid := "efffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f"
+ p := NewGeneratorPoint()
+ if out, err := p.SetBytes(decodeHex(invalid)); err == nil {
+ t.Error("expected error for invalid point")
+ } else if out != nil {
+ t.Error("SetBytes did not return nil on an invalid encoding")
+ } else if p.Equal(B) != 1 {
+ t.Error("the Point was modified while decoding an invalid encoding")
+ }
+ checkOnCurve(t, p)
+}
+
+func TestNonCanonicalPoints(t *testing.T) {
+ type test struct {
+ name string
+ encoding, canonical string
+ }
+ tests := []test{
+ // Points with x = 0 and the sign bit set. With x = 0 the curve equation
+ // gives y² = 1, so y = ±1. 1 has two valid encodings.
+ {
+ "y=1,sign-",
+ "0100000000000000000000000000000000000000000000000000000000000080",
+ "0100000000000000000000000000000000000000000000000000000000000000",
+ },
+ {
+ "y=p+1,sign-",
+ "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0100000000000000000000000000000000000000000000000000000000000000",
+ },
+ {
+ "y=p-1,sign-",
+ "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "ecffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
+ },
+
+ // Non-canonical y encodings with values 2²⁵⁵-19 (p) to 2²⁵⁵-1 (p+18).
+ {
+ "y=p,sign+",
+ "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ },
+ {
+ "y=p,sign-",
+ "edffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0000000000000000000000000000000000000000000000000000000000000080",
+ },
+ {
+ "y=p+1,sign+",
+ "eeffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
+ "0100000000000000000000000000000000000000000000000000000000000000",
+ },
+ // "y=p+1,sign-" is already tested above.
+ // p+2 is not a valid y-coordinate.
+ {
+ "y=p+3,sign+",
+ "f0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
+ "0300000000000000000000000000000000000000000000000000000000000000",
+ },
+ {
+ "y=p+3,sign-",
+ "f0ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0300000000000000000000000000000000000000000000000000000000000080",
+ },
+ {
+ "y=p+4,sign+",
+ "f1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
+ "0400000000000000000000000000000000000000000000000000000000000000",
+ },
+ {
+ "y=p+4,sign-",
+ "f1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0400000000000000000000000000000000000000000000000000000000000080",
+ },
+ {
+ "y=p+5,sign+",
+ "f2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
+ "0500000000000000000000000000000000000000000000000000000000000000",
+ },
+ {
+ "y=p+5,sign-",
+ "f2ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0500000000000000000000000000000000000000000000000000000000000080",
+ },
+ {
+ "y=p+6,sign+",
+ "f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
+ "0600000000000000000000000000000000000000000000000000000000000000",
+ },
+ {
+ "y=p+6,sign-",
+ "f3ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0600000000000000000000000000000000000000000000000000000000000080",
+ },
+ // p+7 is not a valid y-coordinate.
+ // p+8 is not a valid y-coordinate.
+ {
+ "y=p+9,sign+",
+ "f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
+ "0900000000000000000000000000000000000000000000000000000000000000",
+ },
+ {
+ "y=p+9,sign-",
+ "f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0900000000000000000000000000000000000000000000000000000000000080",
+ },
+ {
+ "y=p+10,sign+",
+ "f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
+ "0a00000000000000000000000000000000000000000000000000000000000000",
+ },
+ {
+ "y=p+10,sign-",
+ "f7ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0a00000000000000000000000000000000000000000000000000000000000080",
+ },
+ // p+11 is not a valid y-coordinate.
+ // p+12 is not a valid y-coordinate.
+ // p+13 is not a valid y-coordinate.
+ {
+ "y=p+14,sign+",
+ "fbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
+ "0e00000000000000000000000000000000000000000000000000000000000000",
+ },
+ {
+ "y=p+14,sign-",
+ "fbffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0e00000000000000000000000000000000000000000000000000000000000080",
+ },
+ {
+ "y=p+15,sign+",
+ "fcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
+ "0f00000000000000000000000000000000000000000000000000000000000000",
+ },
+ {
+ "y=p+15,sign-",
+ "fcffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "0f00000000000000000000000000000000000000000000000000000000000080",
+ },
+ {
+ "y=p+16,sign+",
+ "fdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
+ "1000000000000000000000000000000000000000000000000000000000000000",
+ },
+ {
+ "y=p+16,sign-",
+ "fdffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "1000000000000000000000000000000000000000000000000000000000000080",
+ },
+ // p+17 is not a valid y-coordinate.
+ {
+ "y=p+18,sign+",
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff7f",
+ "1200000000000000000000000000000000000000000000000000000000000000",
+ },
+ {
+ "y=p+18,sign-",
+ "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff",
+ "1200000000000000000000000000000000000000000000000000000000000080",
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ p1, err := new(Point).SetBytes(decodeHex(tt.encoding))
+ if err != nil {
+ t.Fatalf("error decoding non-canonical point: %v", err)
+ }
+ p2, err := new(Point).SetBytes(decodeHex(tt.canonical))
+ if err != nil {
+ t.Fatalf("error decoding canonical point: %v", err)
+ }
+ if p1.Equal(p2) != 1 {
+ t.Errorf("equivalent points are not equal: %v, %v", p1, p2)
+ }
+ if encoding := hex.EncodeToString(p1.Bytes()); encoding != tt.canonical {
+ t.Errorf("re-encoding does not match canonical; got %q, expected %q", encoding, tt.canonical)
+ }
+ checkOnCurve(t, p1, p2)
+ })
+ }
+}
+
+var testAllocationsSink byte
+
+func TestAllocations(t *testing.T) {
+ testenv.SkipIfOptimizationOff(t)
+
+ if allocs := testing.AllocsPerRun(100, func() {
+ p := NewIdentityPoint()
+ p.Add(p, NewGeneratorPoint())
+ s := NewScalar()
+ testAllocationsSink ^= s.Bytes()[0]
+ testAllocationsSink ^= p.Bytes()[0]
+ }); allocs > 0 {
+ t.Errorf("expected zero allocations, got %0.1v", allocs)
+ }
+}
+
+func decodeHex(s string) []byte {
+ b, err := hex.DecodeString(s)
+ if err != nil {
+ panic(err)
+ }
+ return b
+}
+
+func BenchmarkEncodingDecoding(b *testing.B) {
+ p := new(Point).Set(dalekScalarBasepoint)
+ for i := 0; i < b.N; i++ {
+ buf := p.Bytes()
+ _, err := p.SetBytes(buf)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+}
diff --git a/src/crypto/internal/edwards25519/field/_asm/fe_amd64_asm.go b/src/crypto/internal/edwards25519/field/_asm/fe_amd64_asm.go
new file mode 100644
index 0000000..411399c
--- /dev/null
+++ b/src/crypto/internal/edwards25519/field/_asm/fe_amd64_asm.go
@@ -0,0 +1,294 @@
+// Copyright (c) 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package main
+
+import (
+ "fmt"
+
+ . "github.com/mmcloughlin/avo/build"
+ . "github.com/mmcloughlin/avo/gotypes"
+ . "github.com/mmcloughlin/avo/operand"
+ . "github.com/mmcloughlin/avo/reg"
+)
+
+//go:generate go run . -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field
+
+func main() {
+ Package("crypto/internal/edwards25519/field")
+ ConstraintExpr("amd64,gc,!purego")
+ feMul()
+ feSquare()
+ Generate()
+}
+
+type namedComponent struct {
+ Component
+ name string
+}
+
+func (c namedComponent) String() string { return c.name }
+
+type uint128 struct {
+ name string
+ hi, lo GPVirtual
+}
+
+func (c uint128) String() string { return c.name }
+
+func feSquare() {
+ TEXT("feSquare", NOSPLIT, "func(out, a *Element)")
+ Doc("feSquare sets out = a * a. It works like feSquareGeneric.")
+ Pragma("noescape")
+
+ a := Dereference(Param("a"))
+ l0 := namedComponent{a.Field("l0"), "l0"}
+ l1 := namedComponent{a.Field("l1"), "l1"}
+ l2 := namedComponent{a.Field("l2"), "l2"}
+ l3 := namedComponent{a.Field("l3"), "l3"}
+ l4 := namedComponent{a.Field("l4"), "l4"}
+
+ // r0 = l0×l0 + 19×2×(l1×l4 + l2×l3)
+ r0 := uint128{"r0", GP64(), GP64()}
+ mul64(r0, 1, l0, l0)
+ addMul64(r0, 38, l1, l4)
+ addMul64(r0, 38, l2, l3)
+
+ // r1 = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3
+ r1 := uint128{"r1", GP64(), GP64()}
+ mul64(r1, 2, l0, l1)
+ addMul64(r1, 38, l2, l4)
+ addMul64(r1, 19, l3, l3)
+
+ // r2 = = 2×l0×l2 + l1×l1 + 19×2×l3×l4
+ r2 := uint128{"r2", GP64(), GP64()}
+ mul64(r2, 2, l0, l2)
+ addMul64(r2, 1, l1, l1)
+ addMul64(r2, 38, l3, l4)
+
+ // r3 = = 2×l0×l3 + 2×l1×l2 + 19×l4×l4
+ r3 := uint128{"r3", GP64(), GP64()}
+ mul64(r3, 2, l0, l3)
+ addMul64(r3, 2, l1, l2)
+ addMul64(r3, 19, l4, l4)
+
+ // r4 = = 2×l0×l4 + 2×l1×l3 + l2×l2
+ r4 := uint128{"r4", GP64(), GP64()}
+ mul64(r4, 2, l0, l4)
+ addMul64(r4, 2, l1, l3)
+ addMul64(r4, 1, l2, l2)
+
+ Comment("First reduction chain")
+ maskLow51Bits := GP64()
+ MOVQ(Imm((1<<51)-1), maskLow51Bits)
+ c0, r0lo := shiftRightBy51(&r0)
+ c1, r1lo := shiftRightBy51(&r1)
+ c2, r2lo := shiftRightBy51(&r2)
+ c3, r3lo := shiftRightBy51(&r3)
+ c4, r4lo := shiftRightBy51(&r4)
+ maskAndAdd(r0lo, maskLow51Bits, c4, 19)
+ maskAndAdd(r1lo, maskLow51Bits, c0, 1)
+ maskAndAdd(r2lo, maskLow51Bits, c1, 1)
+ maskAndAdd(r3lo, maskLow51Bits, c2, 1)
+ maskAndAdd(r4lo, maskLow51Bits, c3, 1)
+
+ Comment("Second reduction chain (carryPropagate)")
+ // c0 = r0 >> 51
+ MOVQ(r0lo, c0)
+ SHRQ(Imm(51), c0)
+ // c1 = r1 >> 51
+ MOVQ(r1lo, c1)
+ SHRQ(Imm(51), c1)
+ // c2 = r2 >> 51
+ MOVQ(r2lo, c2)
+ SHRQ(Imm(51), c2)
+ // c3 = r3 >> 51
+ MOVQ(r3lo, c3)
+ SHRQ(Imm(51), c3)
+ // c4 = r4 >> 51
+ MOVQ(r4lo, c4)
+ SHRQ(Imm(51), c4)
+ maskAndAdd(r0lo, maskLow51Bits, c4, 19)
+ maskAndAdd(r1lo, maskLow51Bits, c0, 1)
+ maskAndAdd(r2lo, maskLow51Bits, c1, 1)
+ maskAndAdd(r3lo, maskLow51Bits, c2, 1)
+ maskAndAdd(r4lo, maskLow51Bits, c3, 1)
+
+ Comment("Store output")
+ out := Dereference(Param("out"))
+ Store(r0lo, out.Field("l0"))
+ Store(r1lo, out.Field("l1"))
+ Store(r2lo, out.Field("l2"))
+ Store(r3lo, out.Field("l3"))
+ Store(r4lo, out.Field("l4"))
+
+ RET()
+}
+
+func feMul() {
+ TEXT("feMul", NOSPLIT, "func(out, a, b *Element)")
+ Doc("feMul sets out = a * b. It works like feMulGeneric.")
+ Pragma("noescape")
+
+ a := Dereference(Param("a"))
+ a0 := namedComponent{a.Field("l0"), "a0"}
+ a1 := namedComponent{a.Field("l1"), "a1"}
+ a2 := namedComponent{a.Field("l2"), "a2"}
+ a3 := namedComponent{a.Field("l3"), "a3"}
+ a4 := namedComponent{a.Field("l4"), "a4"}
+
+ b := Dereference(Param("b"))
+ b0 := namedComponent{b.Field("l0"), "b0"}
+ b1 := namedComponent{b.Field("l1"), "b1"}
+ b2 := namedComponent{b.Field("l2"), "b2"}
+ b3 := namedComponent{b.Field("l3"), "b3"}
+ b4 := namedComponent{b.Field("l4"), "b4"}
+
+ // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
+ r0 := uint128{"r0", GP64(), GP64()}
+ mul64(r0, 1, a0, b0)
+ addMul64(r0, 19, a1, b4)
+ addMul64(r0, 19, a2, b3)
+ addMul64(r0, 19, a3, b2)
+ addMul64(r0, 19, a4, b1)
+
+ // r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2)
+ r1 := uint128{"r1", GP64(), GP64()}
+ mul64(r1, 1, a0, b1)
+ addMul64(r1, 1, a1, b0)
+ addMul64(r1, 19, a2, b4)
+ addMul64(r1, 19, a3, b3)
+ addMul64(r1, 19, a4, b2)
+
+ // r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3)
+ r2 := uint128{"r2", GP64(), GP64()}
+ mul64(r2, 1, a0, b2)
+ addMul64(r2, 1, a1, b1)
+ addMul64(r2, 1, a2, b0)
+ addMul64(r2, 19, a3, b4)
+ addMul64(r2, 19, a4, b3)
+
+ // r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4
+ r3 := uint128{"r3", GP64(), GP64()}
+ mul64(r3, 1, a0, b3)
+ addMul64(r3, 1, a1, b2)
+ addMul64(r3, 1, a2, b1)
+ addMul64(r3, 1, a3, b0)
+ addMul64(r3, 19, a4, b4)
+
+ // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
+ r4 := uint128{"r4", GP64(), GP64()}
+ mul64(r4, 1, a0, b4)
+ addMul64(r4, 1, a1, b3)
+ addMul64(r4, 1, a2, b2)
+ addMul64(r4, 1, a3, b1)
+ addMul64(r4, 1, a4, b0)
+
+ Comment("First reduction chain")
+ maskLow51Bits := GP64()
+ MOVQ(Imm((1<<51)-1), maskLow51Bits)
+ c0, r0lo := shiftRightBy51(&r0)
+ c1, r1lo := shiftRightBy51(&r1)
+ c2, r2lo := shiftRightBy51(&r2)
+ c3, r3lo := shiftRightBy51(&r3)
+ c4, r4lo := shiftRightBy51(&r4)
+ maskAndAdd(r0lo, maskLow51Bits, c4, 19)
+ maskAndAdd(r1lo, maskLow51Bits, c0, 1)
+ maskAndAdd(r2lo, maskLow51Bits, c1, 1)
+ maskAndAdd(r3lo, maskLow51Bits, c2, 1)
+ maskAndAdd(r4lo, maskLow51Bits, c3, 1)
+
+ Comment("Second reduction chain (carryPropagate)")
+ // c0 = r0 >> 51
+ MOVQ(r0lo, c0)
+ SHRQ(Imm(51), c0)
+ // c1 = r1 >> 51
+ MOVQ(r1lo, c1)
+ SHRQ(Imm(51), c1)
+ // c2 = r2 >> 51
+ MOVQ(r2lo, c2)
+ SHRQ(Imm(51), c2)
+ // c3 = r3 >> 51
+ MOVQ(r3lo, c3)
+ SHRQ(Imm(51), c3)
+ // c4 = r4 >> 51
+ MOVQ(r4lo, c4)
+ SHRQ(Imm(51), c4)
+ maskAndAdd(r0lo, maskLow51Bits, c4, 19)
+ maskAndAdd(r1lo, maskLow51Bits, c0, 1)
+ maskAndAdd(r2lo, maskLow51Bits, c1, 1)
+ maskAndAdd(r3lo, maskLow51Bits, c2, 1)
+ maskAndAdd(r4lo, maskLow51Bits, c3, 1)
+
+ Comment("Store output")
+ out := Dereference(Param("out"))
+ Store(r0lo, out.Field("l0"))
+ Store(r1lo, out.Field("l1"))
+ Store(r2lo, out.Field("l2"))
+ Store(r3lo, out.Field("l3"))
+ Store(r4lo, out.Field("l4"))
+
+ RET()
+}
+
+// mul64 sets r to i * aX * bX.
+func mul64(r uint128, i int, aX, bX namedComponent) {
+ switch i {
+ case 1:
+ Comment(fmt.Sprintf("%s = %s×%s", r, aX, bX))
+ Load(aX, RAX)
+ case 2:
+ Comment(fmt.Sprintf("%s = 2×%s×%s", r, aX, bX))
+ Load(aX, RAX)
+ SHLQ(Imm(1), RAX)
+ default:
+ panic("unsupported i value")
+ }
+ MULQ(mustAddr(bX)) // RDX, RAX = RAX * bX
+ MOVQ(RAX, r.lo)
+ MOVQ(RDX, r.hi)
+}
+
+// addMul64 sets r to r + i * aX * bX.
+func addMul64(r uint128, i uint64, aX, bX namedComponent) {
+ switch i {
+ case 1:
+ Comment(fmt.Sprintf("%s += %s×%s", r, aX, bX))
+ Load(aX, RAX)
+ default:
+ Comment(fmt.Sprintf("%s += %d×%s×%s", r, i, aX, bX))
+ IMUL3Q(Imm(i), Load(aX, GP64()), RAX)
+ }
+ MULQ(mustAddr(bX)) // RDX, RAX = RAX * bX
+ ADDQ(RAX, r.lo)
+ ADCQ(RDX, r.hi)
+}
+
+// shiftRightBy51 returns r >> 51 and r.lo.
+//
+// After this function is called, the uint128 may not be used anymore.
+func shiftRightBy51(r *uint128) (out, lo GPVirtual) {
+ out = r.hi
+ lo = r.lo
+ SHLQ(Imm(64-51), r.lo, r.hi)
+ r.lo, r.hi = nil, nil // make sure the uint128 is unusable
+ return
+}
+
+// maskAndAdd sets r = r&mask + c*i.
+func maskAndAdd(r, mask, c GPVirtual, i uint64) {
+ ANDQ(mask, r)
+ if i != 1 {
+ IMUL3Q(Imm(i), c, c)
+ }
+ ADDQ(c, r)
+}
+
+func mustAddr(c Component) Op {
+ b, err := c.Resolve()
+ if err != nil {
+ panic(err)
+ }
+ return b.Addr
+}
diff --git a/src/crypto/internal/edwards25519/field/_asm/go.mod b/src/crypto/internal/edwards25519/field/_asm/go.mod
new file mode 100644
index 0000000..1ce2b5e
--- /dev/null
+++ b/src/crypto/internal/edwards25519/field/_asm/go.mod
@@ -0,0 +1,12 @@
+module asm
+
+go 1.19
+
+require github.com/mmcloughlin/avo v0.4.0
+
+require (
+ golang.org/x/mod v0.4.2 // indirect
+ golang.org/x/sys v0.0.0-20211030160813-b3129d9d1021 // indirect
+ golang.org/x/tools v0.1.7 // indirect
+ golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect
+)
diff --git a/src/crypto/internal/edwards25519/field/_asm/go.sum b/src/crypto/internal/edwards25519/field/_asm/go.sum
new file mode 100644
index 0000000..b4b5914
--- /dev/null
+++ b/src/crypto/internal/edwards25519/field/_asm/go.sum
@@ -0,0 +1,32 @@
+github.com/mmcloughlin/avo v0.4.0 h1:jeHDRktVD+578ULxWpQHkilor6pkdLF7u7EiTzDbfcU=
+github.com/mmcloughlin/avo v0.4.0/go.mod h1:RW9BfYA3TgO9uCdNrKU2h6J8cPD8ZLznvfgHAeszb1s=
+github.com/yuin/goldmark v1.4.0/go.mod h1:mwnBkeHKe2W/ZEtQ+71ViKU8L12m81fl3OWwC1Zlc8k=
+golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
+golang.org/x/crypto v0.0.0-20190308221718-c2843e01d9a2/go.mod h1:djNgcEr1/C05ACkg1iLfiJU5Ep61QUkGW8qpdssI0+w=
+golang.org/x/crypto v0.0.0-20191011191535-87dc89f01550/go.mod h1:yigFU9vqHzYiE8UmvKecakEJjdnWj3jj499lnFckfCI=
+golang.org/x/mod v0.4.2 h1:Gz96sIWK3OalVv/I/qNygP42zyoKp3xptRVCWRFEBvo=
+golang.org/x/mod v0.4.2/go.mod h1:s0Qsj1ACt9ePp/hMypM3fl4fZqREWJwdYDEqhRiZZUA=
+golang.org/x/net v0.0.0-20190404232315-eb5bcb51f2a3/go.mod h1:t9HGtf8HONx5eT2rtn7q6eTqICYqUVnKs3thJo3Qplg=
+golang.org/x/net v0.0.0-20190620200207-3b0461eec859/go.mod h1:z5CRVTTTmAJ677TzLLGU+0bjPO0LkuOLi4/5GtJWs/s=
+golang.org/x/net v0.0.0-20210805182204-aaa1db679c0d/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
+golang.org/x/sync v0.0.0-20190423024810-112230192c58/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
+golang.org/x/sys v0.0.0-20190215142949-d0b11bdaac8a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
+golang.org/x/sys v0.0.0-20190412213103-97732733099d/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
+golang.org/x/sys v0.0.0-20210809222454-d867a43fc93e/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/sys v0.0.0-20211030160813-b3129d9d1021 h1:giLT+HuUP/gXYrG2Plg9WTjj4qhfgaW424ZIFog3rlk=
+golang.org/x/sys v0.0.0-20211030160813-b3129d9d1021/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
+golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
+golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
+golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
+golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
+golang.org/x/tools v0.0.0-20191119224855-298f0cb1881e/go.mod h1:b+2E5dAYhXwXZwtnZ6UAqBI28+e2cm9otk0dWdXHAEo=
+golang.org/x/tools v0.1.7 h1:6j8CgantCy3yc8JGBqkDLMKWqZ0RDU2g1HVgacojGWQ=
+golang.org/x/tools v0.1.7/go.mod h1:LGqMHiF4EqQNHR1JncWGqT5BVaXmza+X+BDGol+dOxo=
+golang.org/x/xerrors v0.0.0-20190717185122-a985d3407aa7/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20191011141410-1b5146add898/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE=
+golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
+rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=
diff --git a/src/crypto/internal/edwards25519/field/fe.go b/src/crypto/internal/edwards25519/field/fe.go
new file mode 100644
index 0000000..5518ef2
--- /dev/null
+++ b/src/crypto/internal/edwards25519/field/fe.go
@@ -0,0 +1,420 @@
+// Copyright (c) 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package field implements fast arithmetic modulo 2^255-19.
+package field
+
+import (
+ "crypto/subtle"
+ "encoding/binary"
+ "errors"
+ "math/bits"
+)
+
+// Element represents an element of the field GF(2^255-19). Note that this
+// is not a cryptographically secure group, and should only be used to interact
+// with edwards25519.Point coordinates.
+//
+// This type works similarly to math/big.Int, and all arguments and receivers
+// are allowed to alias.
+//
+// The zero value is a valid zero element.
+type Element struct {
+ // An element t represents the integer
+ // t.l0 + t.l1*2^51 + t.l2*2^102 + t.l3*2^153 + t.l4*2^204
+ //
+ // Between operations, all limbs are expected to be lower than 2^52.
+ l0 uint64
+ l1 uint64
+ l2 uint64
+ l3 uint64
+ l4 uint64
+}
+
+const maskLow51Bits uint64 = (1 << 51) - 1
+
+var feZero = &Element{0, 0, 0, 0, 0}
+
+// Zero sets v = 0, and returns v.
+func (v *Element) Zero() *Element {
+ *v = *feZero
+ return v
+}
+
+var feOne = &Element{1, 0, 0, 0, 0}
+
+// One sets v = 1, and returns v.
+func (v *Element) One() *Element {
+ *v = *feOne
+ return v
+}
+
+// reduce reduces v modulo 2^255 - 19 and returns it.
+func (v *Element) reduce() *Element {
+ v.carryPropagate()
+
+ // After the light reduction we now have a field element representation
+ // v < 2^255 + 2^13 * 19, but need v < 2^255 - 19.
+
+ // If v >= 2^255 - 19, then v + 19 >= 2^255, which would overflow 2^255 - 1,
+ // generating a carry. That is, c will be 0 if v < 2^255 - 19, and 1 otherwise.
+ c := (v.l0 + 19) >> 51
+ c = (v.l1 + c) >> 51
+ c = (v.l2 + c) >> 51
+ c = (v.l3 + c) >> 51
+ c = (v.l4 + c) >> 51
+
+ // If v < 2^255 - 19 and c = 0, this will be a no-op. Otherwise, it's
+ // effectively applying the reduction identity to the carry.
+ v.l0 += 19 * c
+
+ v.l1 += v.l0 >> 51
+ v.l0 = v.l0 & maskLow51Bits
+ v.l2 += v.l1 >> 51
+ v.l1 = v.l1 & maskLow51Bits
+ v.l3 += v.l2 >> 51
+ v.l2 = v.l2 & maskLow51Bits
+ v.l4 += v.l3 >> 51
+ v.l3 = v.l3 & maskLow51Bits
+ // no additional carry
+ v.l4 = v.l4 & maskLow51Bits
+
+ return v
+}
+
+// Add sets v = a + b, and returns v.
+func (v *Element) Add(a, b *Element) *Element {
+ v.l0 = a.l0 + b.l0
+ v.l1 = a.l1 + b.l1
+ v.l2 = a.l2 + b.l2
+ v.l3 = a.l3 + b.l3
+ v.l4 = a.l4 + b.l4
+ // Using the generic implementation here is actually faster than the
+ // assembly. Probably because the body of this function is so simple that
+ // the compiler can figure out better optimizations by inlining the carry
+ // propagation.
+ return v.carryPropagateGeneric()
+}
+
+// Subtract sets v = a - b, and returns v.
+func (v *Element) Subtract(a, b *Element) *Element {
+ // We first add 2 * p, to guarantee the subtraction won't underflow, and
+ // then subtract b (which can be up to 2^255 + 2^13 * 19).
+ v.l0 = (a.l0 + 0xFFFFFFFFFFFDA) - b.l0
+ v.l1 = (a.l1 + 0xFFFFFFFFFFFFE) - b.l1
+ v.l2 = (a.l2 + 0xFFFFFFFFFFFFE) - b.l2
+ v.l3 = (a.l3 + 0xFFFFFFFFFFFFE) - b.l3
+ v.l4 = (a.l4 + 0xFFFFFFFFFFFFE) - b.l4
+ return v.carryPropagate()
+}
+
+// Negate sets v = -a, and returns v.
+func (v *Element) Negate(a *Element) *Element {
+ return v.Subtract(feZero, a)
+}
+
+// Invert sets v = 1/z mod p, and returns v.
+//
+// If z == 0, Invert returns v = 0.
+func (v *Element) Invert(z *Element) *Element {
+ // Inversion is implemented as exponentiation with exponent p − 2. It uses the
+ // same sequence of 255 squarings and 11 multiplications as [Curve25519].
+ var z2, z9, z11, z2_5_0, z2_10_0, z2_20_0, z2_50_0, z2_100_0, t Element
+
+ z2.Square(z) // 2
+ t.Square(&z2) // 4
+ t.Square(&t) // 8
+ z9.Multiply(&t, z) // 9
+ z11.Multiply(&z9, &z2) // 11
+ t.Square(&z11) // 22
+ z2_5_0.Multiply(&t, &z9) // 31 = 2^5 - 2^0
+
+ t.Square(&z2_5_0) // 2^6 - 2^1
+ for i := 0; i < 4; i++ {
+ t.Square(&t) // 2^10 - 2^5
+ }
+ z2_10_0.Multiply(&t, &z2_5_0) // 2^10 - 2^0
+
+ t.Square(&z2_10_0) // 2^11 - 2^1
+ for i := 0; i < 9; i++ {
+ t.Square(&t) // 2^20 - 2^10
+ }
+ z2_20_0.Multiply(&t, &z2_10_0) // 2^20 - 2^0
+
+ t.Square(&z2_20_0) // 2^21 - 2^1
+ for i := 0; i < 19; i++ {
+ t.Square(&t) // 2^40 - 2^20
+ }
+ t.Multiply(&t, &z2_20_0) // 2^40 - 2^0
+
+ t.Square(&t) // 2^41 - 2^1
+ for i := 0; i < 9; i++ {
+ t.Square(&t) // 2^50 - 2^10
+ }
+ z2_50_0.Multiply(&t, &z2_10_0) // 2^50 - 2^0
+
+ t.Square(&z2_50_0) // 2^51 - 2^1
+ for i := 0; i < 49; i++ {
+ t.Square(&t) // 2^100 - 2^50
+ }
+ z2_100_0.Multiply(&t, &z2_50_0) // 2^100 - 2^0
+
+ t.Square(&z2_100_0) // 2^101 - 2^1
+ for i := 0; i < 99; i++ {
+ t.Square(&t) // 2^200 - 2^100
+ }
+ t.Multiply(&t, &z2_100_0) // 2^200 - 2^0
+
+ t.Square(&t) // 2^201 - 2^1
+ for i := 0; i < 49; i++ {
+ t.Square(&t) // 2^250 - 2^50
+ }
+ t.Multiply(&t, &z2_50_0) // 2^250 - 2^0
+
+ t.Square(&t) // 2^251 - 2^1
+ t.Square(&t) // 2^252 - 2^2
+ t.Square(&t) // 2^253 - 2^3
+ t.Square(&t) // 2^254 - 2^4
+ t.Square(&t) // 2^255 - 2^5
+
+ return v.Multiply(&t, &z11) // 2^255 - 21
+}
+
+// Set sets v = a, and returns v.
+func (v *Element) Set(a *Element) *Element {
+ *v = *a
+ return v
+}
+
+// SetBytes sets v to x, where x is a 32-byte little-endian encoding. If x is
+// not of the right length, SetBytes returns nil and an error, and the
+// receiver is unchanged.
+//
+// Consistent with RFC 7748, the most significant bit (the high bit of the
+// last byte) is ignored, and non-canonical values (2^255-19 through 2^255-1)
+// are accepted. Note that this is laxer than specified by RFC 8032, but
+// consistent with most Ed25519 implementations.
+func (v *Element) SetBytes(x []byte) (*Element, error) {
+ if len(x) != 32 {
+ return nil, errors.New("edwards25519: invalid field element input size")
+ }
+
+ // Bits 0:51 (bytes 0:8, bits 0:64, shift 0, mask 51).
+ v.l0 = binary.LittleEndian.Uint64(x[0:8])
+ v.l0 &= maskLow51Bits
+ // Bits 51:102 (bytes 6:14, bits 48:112, shift 3, mask 51).
+ v.l1 = binary.LittleEndian.Uint64(x[6:14]) >> 3
+ v.l1 &= maskLow51Bits
+ // Bits 102:153 (bytes 12:20, bits 96:160, shift 6, mask 51).
+ v.l2 = binary.LittleEndian.Uint64(x[12:20]) >> 6
+ v.l2 &= maskLow51Bits
+ // Bits 153:204 (bytes 19:27, bits 152:216, shift 1, mask 51).
+ v.l3 = binary.LittleEndian.Uint64(x[19:27]) >> 1
+ v.l3 &= maskLow51Bits
+ // Bits 204:255 (bytes 24:32, bits 192:256, shift 12, mask 51).
+ // Note: not bytes 25:33, shift 4, to avoid overread.
+ v.l4 = binary.LittleEndian.Uint64(x[24:32]) >> 12
+ v.l4 &= maskLow51Bits
+
+ return v, nil
+}
+
+// Bytes returns the canonical 32-byte little-endian encoding of v.
+func (v *Element) Bytes() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [32]byte
+ return v.bytes(&out)
+}
+
+func (v *Element) bytes(out *[32]byte) []byte {
+ t := *v
+ t.reduce()
+
+ var buf [8]byte
+ for i, l := range [5]uint64{t.l0, t.l1, t.l2, t.l3, t.l4} {
+ bitsOffset := i * 51
+ binary.LittleEndian.PutUint64(buf[:], l<<uint(bitsOffset%8))
+ for i, bb := range buf {
+ off := bitsOffset/8 + i
+ if off >= len(out) {
+ break
+ }
+ out[off] |= bb
+ }
+ }
+
+ return out[:]
+}
+
+// Equal returns 1 if v and u are equal, and 0 otherwise.
+func (v *Element) Equal(u *Element) int {
+ sa, sv := u.Bytes(), v.Bytes()
+ return subtle.ConstantTimeCompare(sa, sv)
+}
+
+// mask64Bits returns 0xffffffff if cond is 1, and 0 otherwise.
+func mask64Bits(cond int) uint64 { return ^(uint64(cond) - 1) }
+
+// Select sets v to a if cond == 1, and to b if cond == 0.
+func (v *Element) Select(a, b *Element, cond int) *Element {
+ m := mask64Bits(cond)
+ v.l0 = (m & a.l0) | (^m & b.l0)
+ v.l1 = (m & a.l1) | (^m & b.l1)
+ v.l2 = (m & a.l2) | (^m & b.l2)
+ v.l3 = (m & a.l3) | (^m & b.l3)
+ v.l4 = (m & a.l4) | (^m & b.l4)
+ return v
+}
+
+// Swap swaps v and u if cond == 1 or leaves them unchanged if cond == 0, and returns v.
+func (v *Element) Swap(u *Element, cond int) {
+ m := mask64Bits(cond)
+ t := m & (v.l0 ^ u.l0)
+ v.l0 ^= t
+ u.l0 ^= t
+ t = m & (v.l1 ^ u.l1)
+ v.l1 ^= t
+ u.l1 ^= t
+ t = m & (v.l2 ^ u.l2)
+ v.l2 ^= t
+ u.l2 ^= t
+ t = m & (v.l3 ^ u.l3)
+ v.l3 ^= t
+ u.l3 ^= t
+ t = m & (v.l4 ^ u.l4)
+ v.l4 ^= t
+ u.l4 ^= t
+}
+
+// IsNegative returns 1 if v is negative, and 0 otherwise.
+func (v *Element) IsNegative() int {
+ return int(v.Bytes()[0] & 1)
+}
+
+// Absolute sets v to |u|, and returns v.
+func (v *Element) Absolute(u *Element) *Element {
+ return v.Select(new(Element).Negate(u), u, u.IsNegative())
+}
+
+// Multiply sets v = x * y, and returns v.
+func (v *Element) Multiply(x, y *Element) *Element {
+ feMul(v, x, y)
+ return v
+}
+
+// Square sets v = x * x, and returns v.
+func (v *Element) Square(x *Element) *Element {
+ feSquare(v, x)
+ return v
+}
+
+// Mult32 sets v = x * y, and returns v.
+func (v *Element) Mult32(x *Element, y uint32) *Element {
+ x0lo, x0hi := mul51(x.l0, y)
+ x1lo, x1hi := mul51(x.l1, y)
+ x2lo, x2hi := mul51(x.l2, y)
+ x3lo, x3hi := mul51(x.l3, y)
+ x4lo, x4hi := mul51(x.l4, y)
+ v.l0 = x0lo + 19*x4hi // carried over per the reduction identity
+ v.l1 = x1lo + x0hi
+ v.l2 = x2lo + x1hi
+ v.l3 = x3lo + x2hi
+ v.l4 = x4lo + x3hi
+ // The hi portions are going to be only 32 bits, plus any previous excess,
+ // so we can skip the carry propagation.
+ return v
+}
+
+// mul51 returns lo + hi * 2⁵¹ = a * b.
+func mul51(a uint64, b uint32) (lo uint64, hi uint64) {
+ mh, ml := bits.Mul64(a, uint64(b))
+ lo = ml & maskLow51Bits
+ hi = (mh << 13) | (ml >> 51)
+ return
+}
+
+// Pow22523 set v = x^((p-5)/8), and returns v. (p-5)/8 is 2^252-3.
+func (v *Element) Pow22523(x *Element) *Element {
+ var t0, t1, t2 Element
+
+ t0.Square(x) // x^2
+ t1.Square(&t0) // x^4
+ t1.Square(&t1) // x^8
+ t1.Multiply(x, &t1) // x^9
+ t0.Multiply(&t0, &t1) // x^11
+ t0.Square(&t0) // x^22
+ t0.Multiply(&t1, &t0) // x^31
+ t1.Square(&t0) // x^62
+ for i := 1; i < 5; i++ { // x^992
+ t1.Square(&t1)
+ }
+ t0.Multiply(&t1, &t0) // x^1023 -> 1023 = 2^10 - 1
+ t1.Square(&t0) // 2^11 - 2
+ for i := 1; i < 10; i++ { // 2^20 - 2^10
+ t1.Square(&t1)
+ }
+ t1.Multiply(&t1, &t0) // 2^20 - 1
+ t2.Square(&t1) // 2^21 - 2
+ for i := 1; i < 20; i++ { // 2^40 - 2^20
+ t2.Square(&t2)
+ }
+ t1.Multiply(&t2, &t1) // 2^40 - 1
+ t1.Square(&t1) // 2^41 - 2
+ for i := 1; i < 10; i++ { // 2^50 - 2^10
+ t1.Square(&t1)
+ }
+ t0.Multiply(&t1, &t0) // 2^50 - 1
+ t1.Square(&t0) // 2^51 - 2
+ for i := 1; i < 50; i++ { // 2^100 - 2^50
+ t1.Square(&t1)
+ }
+ t1.Multiply(&t1, &t0) // 2^100 - 1
+ t2.Square(&t1) // 2^101 - 2
+ for i := 1; i < 100; i++ { // 2^200 - 2^100
+ t2.Square(&t2)
+ }
+ t1.Multiply(&t2, &t1) // 2^200 - 1
+ t1.Square(&t1) // 2^201 - 2
+ for i := 1; i < 50; i++ { // 2^250 - 2^50
+ t1.Square(&t1)
+ }
+ t0.Multiply(&t1, &t0) // 2^250 - 1
+ t0.Square(&t0) // 2^251 - 2
+ t0.Square(&t0) // 2^252 - 4
+ return v.Multiply(&t0, x) // 2^252 - 3 -> x^(2^252-3)
+}
+
+// sqrtM1 is 2^((p-1)/4), which squared is equal to -1 by Euler's Criterion.
+var sqrtM1 = &Element{1718705420411056, 234908883556509,
+ 2233514472574048, 2117202627021982, 765476049583133}
+
+// SqrtRatio sets r to the non-negative square root of the ratio of u and v.
+//
+// If u/v is square, SqrtRatio returns r and 1. If u/v is not square, SqrtRatio
+// sets r according to Section 4.3 of draft-irtf-cfrg-ristretto255-decaf448-00,
+// and returns r and 0.
+func (r *Element) SqrtRatio(u, v *Element) (R *Element, wasSquare int) {
+ t0 := new(Element)
+
+ // r = (u * v3) * (u * v7)^((p-5)/8)
+ v2 := new(Element).Square(v)
+ uv3 := new(Element).Multiply(u, t0.Multiply(v2, v))
+ uv7 := new(Element).Multiply(uv3, t0.Square(v2))
+ rr := new(Element).Multiply(uv3, t0.Pow22523(uv7))
+
+ check := new(Element).Multiply(v, t0.Square(rr)) // check = v * r^2
+
+ uNeg := new(Element).Negate(u)
+ correctSignSqrt := check.Equal(u)
+ flippedSignSqrt := check.Equal(uNeg)
+ flippedSignSqrtI := check.Equal(t0.Multiply(uNeg, sqrtM1))
+
+ rPrime := new(Element).Multiply(rr, sqrtM1) // r_prime = SQRT_M1 * r
+ // r = CT_SELECT(r_prime IF flipped_sign_sqrt | flipped_sign_sqrt_i ELSE r)
+ rr.Select(rPrime, rr, flippedSignSqrt|flippedSignSqrtI)
+
+ r.Absolute(rr) // Choose the nonnegative square root.
+ return r, correctSignSqrt | flippedSignSqrt
+}
diff --git a/src/crypto/internal/edwards25519/field/fe_alias_test.go b/src/crypto/internal/edwards25519/field/fe_alias_test.go
new file mode 100644
index 0000000..bf1efdc
--- /dev/null
+++ b/src/crypto/internal/edwards25519/field/fe_alias_test.go
@@ -0,0 +1,140 @@
+// Copyright (c) 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package field
+
+import (
+ "testing"
+ "testing/quick"
+)
+
+func checkAliasingOneArg(f func(v, x *Element) *Element) func(v, x Element) bool {
+ return func(v, x Element) bool {
+ x1, v1 := x, x
+
+ // Calculate a reference f(x) without aliasing.
+ if out := f(&v, &x); out != &v && isInBounds(out) {
+ return false
+ }
+
+ // Test aliasing the argument and the receiver.
+ if out := f(&v1, &v1); out != &v1 || v1 != v {
+ return false
+ }
+
+ // Ensure the arguments was not modified.
+ return x == x1
+ }
+}
+
+func checkAliasingTwoArgs(f func(v, x, y *Element) *Element) func(v, x, y Element) bool {
+ return func(v, x, y Element) bool {
+ x1, y1, v1 := x, y, Element{}
+
+ // Calculate a reference f(x, y) without aliasing.
+ if out := f(&v, &x, &y); out != &v && isInBounds(out) {
+ return false
+ }
+
+ // Test aliasing the first argument and the receiver.
+ v1 = x
+ if out := f(&v1, &v1, &y); out != &v1 || v1 != v {
+ return false
+ }
+ // Test aliasing the second argument and the receiver.
+ v1 = y
+ if out := f(&v1, &x, &v1); out != &v1 || v1 != v {
+ return false
+ }
+
+ // Calculate a reference f(x, x) without aliasing.
+ if out := f(&v, &x, &x); out != &v {
+ return false
+ }
+
+ // Test aliasing the first argument and the receiver.
+ v1 = x
+ if out := f(&v1, &v1, &x); out != &v1 || v1 != v {
+ return false
+ }
+ // Test aliasing the second argument and the receiver.
+ v1 = x
+ if out := f(&v1, &x, &v1); out != &v1 || v1 != v {
+ return false
+ }
+ // Test aliasing both arguments and the receiver.
+ v1 = x
+ if out := f(&v1, &v1, &v1); out != &v1 || v1 != v {
+ return false
+ }
+
+ // Ensure the arguments were not modified.
+ return x == x1 && y == y1
+ }
+}
+
+// TestAliasing checks that receivers and arguments can alias each other without
+// leading to incorrect results. That is, it ensures that it's safe to write
+//
+// v.Invert(v)
+//
+// or
+//
+// v.Add(v, v)
+//
+// without any of the inputs getting clobbered by the output being written.
+func TestAliasing(t *testing.T) {
+ type target struct {
+ name string
+ oneArgF func(v, x *Element) *Element
+ twoArgsF func(v, x, y *Element) *Element
+ }
+ for _, tt := range []target{
+ {name: "Absolute", oneArgF: (*Element).Absolute},
+ {name: "Invert", oneArgF: (*Element).Invert},
+ {name: "Negate", oneArgF: (*Element).Negate},
+ {name: "Set", oneArgF: (*Element).Set},
+ {name: "Square", oneArgF: (*Element).Square},
+ {name: "Pow22523", oneArgF: (*Element).Pow22523},
+ {
+ name: "Mult32",
+ oneArgF: func(v, x *Element) *Element {
+ return v.Mult32(x, 0xffffffff)
+ },
+ },
+ {name: "Multiply", twoArgsF: (*Element).Multiply},
+ {name: "Add", twoArgsF: (*Element).Add},
+ {name: "Subtract", twoArgsF: (*Element).Subtract},
+ {
+ name: "SqrtRatio",
+ twoArgsF: func(v, x, y *Element) *Element {
+ r, _ := v.SqrtRatio(x, y)
+ return r
+ },
+ },
+ {
+ name: "Select0",
+ twoArgsF: func(v, x, y *Element) *Element {
+ return v.Select(x, y, 0)
+ },
+ },
+ {
+ name: "Select1",
+ twoArgsF: func(v, x, y *Element) *Element {
+ return v.Select(x, y, 1)
+ },
+ },
+ } {
+ var err error
+ switch {
+ case tt.oneArgF != nil:
+ err = quick.Check(checkAliasingOneArg(tt.oneArgF), &quick.Config{MaxCountScale: 1 << 8})
+ case tt.twoArgsF != nil:
+ err = quick.Check(checkAliasingTwoArgs(tt.twoArgsF), &quick.Config{MaxCountScale: 1 << 8})
+ }
+ if err != nil {
+ t.Errorf("%v: %v", tt.name, err)
+ }
+ }
+}
diff --git a/src/crypto/internal/edwards25519/field/fe_amd64.go b/src/crypto/internal/edwards25519/field/fe_amd64.go
new file mode 100644
index 0000000..70c5416
--- /dev/null
+++ b/src/crypto/internal/edwards25519/field/fe_amd64.go
@@ -0,0 +1,15 @@
+// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
+
+//go:build amd64 && gc && !purego
+
+package field
+
+// feMul sets out = a * b. It works like feMulGeneric.
+//
+//go:noescape
+func feMul(out *Element, a *Element, b *Element)
+
+// feSquare sets out = a * a. It works like feSquareGeneric.
+//
+//go:noescape
+func feSquare(out *Element, a *Element)
diff --git a/src/crypto/internal/edwards25519/field/fe_amd64.s b/src/crypto/internal/edwards25519/field/fe_amd64.s
new file mode 100644
index 0000000..60817ac
--- /dev/null
+++ b/src/crypto/internal/edwards25519/field/fe_amd64.s
@@ -0,0 +1,378 @@
+// Code generated by command: go run fe_amd64_asm.go -out ../fe_amd64.s -stubs ../fe_amd64.go -pkg field. DO NOT EDIT.
+
+//go:build amd64 && gc && !purego
+
+#include "textflag.h"
+
+// func feMul(out *Element, a *Element, b *Element)
+TEXT ·feMul(SB), NOSPLIT, $0-24
+ MOVQ a+8(FP), CX
+ MOVQ b+16(FP), BX
+
+ // r0 = a0×b0
+ MOVQ (CX), AX
+ MULQ (BX)
+ MOVQ AX, DI
+ MOVQ DX, SI
+
+ // r0 += 19×a1×b4
+ MOVQ 8(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 32(BX)
+ ADDQ AX, DI
+ ADCQ DX, SI
+
+ // r0 += 19×a2×b3
+ MOVQ 16(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 24(BX)
+ ADDQ AX, DI
+ ADCQ DX, SI
+
+ // r0 += 19×a3×b2
+ MOVQ 24(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 16(BX)
+ ADDQ AX, DI
+ ADCQ DX, SI
+
+ // r0 += 19×a4×b1
+ MOVQ 32(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 8(BX)
+ ADDQ AX, DI
+ ADCQ DX, SI
+
+ // r1 = a0×b1
+ MOVQ (CX), AX
+ MULQ 8(BX)
+ MOVQ AX, R9
+ MOVQ DX, R8
+
+ // r1 += a1×b0
+ MOVQ 8(CX), AX
+ MULQ (BX)
+ ADDQ AX, R9
+ ADCQ DX, R8
+
+ // r1 += 19×a2×b4
+ MOVQ 16(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 32(BX)
+ ADDQ AX, R9
+ ADCQ DX, R8
+
+ // r1 += 19×a3×b3
+ MOVQ 24(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 24(BX)
+ ADDQ AX, R9
+ ADCQ DX, R8
+
+ // r1 += 19×a4×b2
+ MOVQ 32(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 16(BX)
+ ADDQ AX, R9
+ ADCQ DX, R8
+
+ // r2 = a0×b2
+ MOVQ (CX), AX
+ MULQ 16(BX)
+ MOVQ AX, R11
+ MOVQ DX, R10
+
+ // r2 += a1×b1
+ MOVQ 8(CX), AX
+ MULQ 8(BX)
+ ADDQ AX, R11
+ ADCQ DX, R10
+
+ // r2 += a2×b0
+ MOVQ 16(CX), AX
+ MULQ (BX)
+ ADDQ AX, R11
+ ADCQ DX, R10
+
+ // r2 += 19×a3×b4
+ MOVQ 24(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 32(BX)
+ ADDQ AX, R11
+ ADCQ DX, R10
+
+ // r2 += 19×a4×b3
+ MOVQ 32(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 24(BX)
+ ADDQ AX, R11
+ ADCQ DX, R10
+
+ // r3 = a0×b3
+ MOVQ (CX), AX
+ MULQ 24(BX)
+ MOVQ AX, R13
+ MOVQ DX, R12
+
+ // r3 += a1×b2
+ MOVQ 8(CX), AX
+ MULQ 16(BX)
+ ADDQ AX, R13
+ ADCQ DX, R12
+
+ // r3 += a2×b1
+ MOVQ 16(CX), AX
+ MULQ 8(BX)
+ ADDQ AX, R13
+ ADCQ DX, R12
+
+ // r3 += a3×b0
+ MOVQ 24(CX), AX
+ MULQ (BX)
+ ADDQ AX, R13
+ ADCQ DX, R12
+
+ // r3 += 19×a4×b4
+ MOVQ 32(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 32(BX)
+ ADDQ AX, R13
+ ADCQ DX, R12
+
+ // r4 = a0×b4
+ MOVQ (CX), AX
+ MULQ 32(BX)
+ MOVQ AX, R15
+ MOVQ DX, R14
+
+ // r4 += a1×b3
+ MOVQ 8(CX), AX
+ MULQ 24(BX)
+ ADDQ AX, R15
+ ADCQ DX, R14
+
+ // r4 += a2×b2
+ MOVQ 16(CX), AX
+ MULQ 16(BX)
+ ADDQ AX, R15
+ ADCQ DX, R14
+
+ // r4 += a3×b1
+ MOVQ 24(CX), AX
+ MULQ 8(BX)
+ ADDQ AX, R15
+ ADCQ DX, R14
+
+ // r4 += a4×b0
+ MOVQ 32(CX), AX
+ MULQ (BX)
+ ADDQ AX, R15
+ ADCQ DX, R14
+
+ // First reduction chain
+ MOVQ $0x0007ffffffffffff, AX
+ SHLQ $0x0d, DI, SI
+ SHLQ $0x0d, R9, R8
+ SHLQ $0x0d, R11, R10
+ SHLQ $0x0d, R13, R12
+ SHLQ $0x0d, R15, R14
+ ANDQ AX, DI
+ IMUL3Q $0x13, R14, R14
+ ADDQ R14, DI
+ ANDQ AX, R9
+ ADDQ SI, R9
+ ANDQ AX, R11
+ ADDQ R8, R11
+ ANDQ AX, R13
+ ADDQ R10, R13
+ ANDQ AX, R15
+ ADDQ R12, R15
+
+ // Second reduction chain (carryPropagate)
+ MOVQ DI, SI
+ SHRQ $0x33, SI
+ MOVQ R9, R8
+ SHRQ $0x33, R8
+ MOVQ R11, R10
+ SHRQ $0x33, R10
+ MOVQ R13, R12
+ SHRQ $0x33, R12
+ MOVQ R15, R14
+ SHRQ $0x33, R14
+ ANDQ AX, DI
+ IMUL3Q $0x13, R14, R14
+ ADDQ R14, DI
+ ANDQ AX, R9
+ ADDQ SI, R9
+ ANDQ AX, R11
+ ADDQ R8, R11
+ ANDQ AX, R13
+ ADDQ R10, R13
+ ANDQ AX, R15
+ ADDQ R12, R15
+
+ // Store output
+ MOVQ out+0(FP), AX
+ MOVQ DI, (AX)
+ MOVQ R9, 8(AX)
+ MOVQ R11, 16(AX)
+ MOVQ R13, 24(AX)
+ MOVQ R15, 32(AX)
+ RET
+
+// func feSquare(out *Element, a *Element)
+TEXT ·feSquare(SB), NOSPLIT, $0-16
+ MOVQ a+8(FP), CX
+
+ // r0 = l0×l0
+ MOVQ (CX), AX
+ MULQ (CX)
+ MOVQ AX, SI
+ MOVQ DX, BX
+
+ // r0 += 38×l1×l4
+ MOVQ 8(CX), AX
+ IMUL3Q $0x26, AX, AX
+ MULQ 32(CX)
+ ADDQ AX, SI
+ ADCQ DX, BX
+
+ // r0 += 38×l2×l3
+ MOVQ 16(CX), AX
+ IMUL3Q $0x26, AX, AX
+ MULQ 24(CX)
+ ADDQ AX, SI
+ ADCQ DX, BX
+
+ // r1 = 2×l0×l1
+ MOVQ (CX), AX
+ SHLQ $0x01, AX
+ MULQ 8(CX)
+ MOVQ AX, R8
+ MOVQ DX, DI
+
+ // r1 += 38×l2×l4
+ MOVQ 16(CX), AX
+ IMUL3Q $0x26, AX, AX
+ MULQ 32(CX)
+ ADDQ AX, R8
+ ADCQ DX, DI
+
+ // r1 += 19×l3×l3
+ MOVQ 24(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 24(CX)
+ ADDQ AX, R8
+ ADCQ DX, DI
+
+ // r2 = 2×l0×l2
+ MOVQ (CX), AX
+ SHLQ $0x01, AX
+ MULQ 16(CX)
+ MOVQ AX, R10
+ MOVQ DX, R9
+
+ // r2 += l1×l1
+ MOVQ 8(CX), AX
+ MULQ 8(CX)
+ ADDQ AX, R10
+ ADCQ DX, R9
+
+ // r2 += 38×l3×l4
+ MOVQ 24(CX), AX
+ IMUL3Q $0x26, AX, AX
+ MULQ 32(CX)
+ ADDQ AX, R10
+ ADCQ DX, R9
+
+ // r3 = 2×l0×l3
+ MOVQ (CX), AX
+ SHLQ $0x01, AX
+ MULQ 24(CX)
+ MOVQ AX, R12
+ MOVQ DX, R11
+
+ // r3 += 2×l1×l2
+ MOVQ 8(CX), AX
+ IMUL3Q $0x02, AX, AX
+ MULQ 16(CX)
+ ADDQ AX, R12
+ ADCQ DX, R11
+
+ // r3 += 19×l4×l4
+ MOVQ 32(CX), AX
+ IMUL3Q $0x13, AX, AX
+ MULQ 32(CX)
+ ADDQ AX, R12
+ ADCQ DX, R11
+
+ // r4 = 2×l0×l4
+ MOVQ (CX), AX
+ SHLQ $0x01, AX
+ MULQ 32(CX)
+ MOVQ AX, R14
+ MOVQ DX, R13
+
+ // r4 += 2×l1×l3
+ MOVQ 8(CX), AX
+ IMUL3Q $0x02, AX, AX
+ MULQ 24(CX)
+ ADDQ AX, R14
+ ADCQ DX, R13
+
+ // r4 += l2×l2
+ MOVQ 16(CX), AX
+ MULQ 16(CX)
+ ADDQ AX, R14
+ ADCQ DX, R13
+
+ // First reduction chain
+ MOVQ $0x0007ffffffffffff, AX
+ SHLQ $0x0d, SI, BX
+ SHLQ $0x0d, R8, DI
+ SHLQ $0x0d, R10, R9
+ SHLQ $0x0d, R12, R11
+ SHLQ $0x0d, R14, R13
+ ANDQ AX, SI
+ IMUL3Q $0x13, R13, R13
+ ADDQ R13, SI
+ ANDQ AX, R8
+ ADDQ BX, R8
+ ANDQ AX, R10
+ ADDQ DI, R10
+ ANDQ AX, R12
+ ADDQ R9, R12
+ ANDQ AX, R14
+ ADDQ R11, R14
+
+ // Second reduction chain (carryPropagate)
+ MOVQ SI, BX
+ SHRQ $0x33, BX
+ MOVQ R8, DI
+ SHRQ $0x33, DI
+ MOVQ R10, R9
+ SHRQ $0x33, R9
+ MOVQ R12, R11
+ SHRQ $0x33, R11
+ MOVQ R14, R13
+ SHRQ $0x33, R13
+ ANDQ AX, SI
+ IMUL3Q $0x13, R13, R13
+ ADDQ R13, SI
+ ANDQ AX, R8
+ ADDQ BX, R8
+ ANDQ AX, R10
+ ADDQ DI, R10
+ ANDQ AX, R12
+ ADDQ R9, R12
+ ANDQ AX, R14
+ ADDQ R11, R14
+
+ // Store output
+ MOVQ out+0(FP), AX
+ MOVQ SI, (AX)
+ MOVQ R8, 8(AX)
+ MOVQ R10, 16(AX)
+ MOVQ R12, 24(AX)
+ MOVQ R14, 32(AX)
+ RET
diff --git a/src/crypto/internal/edwards25519/field/fe_amd64_noasm.go b/src/crypto/internal/edwards25519/field/fe_amd64_noasm.go
new file mode 100644
index 0000000..9da280d
--- /dev/null
+++ b/src/crypto/internal/edwards25519/field/fe_amd64_noasm.go
@@ -0,0 +1,11 @@
+// Copyright (c) 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !amd64 || !gc || purego
+
+package field
+
+func feMul(v, x, y *Element) { feMulGeneric(v, x, y) }
+
+func feSquare(v, x *Element) { feSquareGeneric(v, x) }
diff --git a/src/crypto/internal/edwards25519/field/fe_arm64.go b/src/crypto/internal/edwards25519/field/fe_arm64.go
new file mode 100644
index 0000000..075fe9b
--- /dev/null
+++ b/src/crypto/internal/edwards25519/field/fe_arm64.go
@@ -0,0 +1,15 @@
+// Copyright (c) 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build arm64 && gc && !purego
+
+package field
+
+//go:noescape
+func carryPropagate(v *Element)
+
+func (v *Element) carryPropagate() *Element {
+ carryPropagate(v)
+ return v
+}
diff --git a/src/crypto/internal/edwards25519/field/fe_arm64.s b/src/crypto/internal/edwards25519/field/fe_arm64.s
new file mode 100644
index 0000000..751ab2a
--- /dev/null
+++ b/src/crypto/internal/edwards25519/field/fe_arm64.s
@@ -0,0 +1,42 @@
+// Copyright (c) 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// +build arm64,gc,!purego
+
+#include "textflag.h"
+
+// carryPropagate works exactly like carryPropagateGeneric and uses the
+// same AND, ADD, and LSR+MADD instructions emitted by the compiler, but
+// avoids loading R0-R4 twice and uses LDP and STP.
+//
+// See https://golang.org/issues/43145 for the main compiler issue.
+//
+// func carryPropagate(v *Element)
+TEXT ·carryPropagate(SB),NOFRAME|NOSPLIT,$0-8
+ MOVD v+0(FP), R20
+
+ LDP 0(R20), (R0, R1)
+ LDP 16(R20), (R2, R3)
+ MOVD 32(R20), R4
+
+ AND $0x7ffffffffffff, R0, R10
+ AND $0x7ffffffffffff, R1, R11
+ AND $0x7ffffffffffff, R2, R12
+ AND $0x7ffffffffffff, R3, R13
+ AND $0x7ffffffffffff, R4, R14
+
+ ADD R0>>51, R11, R11
+ ADD R1>>51, R12, R12
+ ADD R2>>51, R13, R13
+ ADD R3>>51, R14, R14
+ // R4>>51 * 19 + R10 -> R10
+ LSR $51, R4, R21
+ MOVD $19, R22
+ MADD R22, R10, R21, R10
+
+ STP (R10, R11), 0(R20)
+ STP (R12, R13), 16(R20)
+ MOVD R14, 32(R20)
+
+ RET
diff --git a/src/crypto/internal/edwards25519/field/fe_arm64_noasm.go b/src/crypto/internal/edwards25519/field/fe_arm64_noasm.go
new file mode 100644
index 0000000..fc029ac
--- /dev/null
+++ b/src/crypto/internal/edwards25519/field/fe_arm64_noasm.go
@@ -0,0 +1,11 @@
+// Copyright (c) 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !arm64 || !gc || purego
+
+package field
+
+func (v *Element) carryPropagate() *Element {
+ return v.carryPropagateGeneric()
+}
diff --git a/src/crypto/internal/edwards25519/field/fe_bench_test.go b/src/crypto/internal/edwards25519/field/fe_bench_test.go
new file mode 100644
index 0000000..84fdf05
--- /dev/null
+++ b/src/crypto/internal/edwards25519/field/fe_bench_test.go
@@ -0,0 +1,49 @@
+// Copyright (c) 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package field
+
+import "testing"
+
+func BenchmarkAdd(b *testing.B) {
+ x := new(Element).One()
+ y := new(Element).Add(x, x)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ x.Add(x, y)
+ }
+}
+
+func BenchmarkMultiply(b *testing.B) {
+ x := new(Element).One()
+ y := new(Element).Add(x, x)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ x.Multiply(x, y)
+ }
+}
+
+func BenchmarkSquare(b *testing.B) {
+ x := new(Element).Add(feOne, feOne)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ x.Square(x)
+ }
+}
+
+func BenchmarkInvert(b *testing.B) {
+ x := new(Element).Add(feOne, feOne)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ x.Invert(x)
+ }
+}
+
+func BenchmarkMult32(b *testing.B) {
+ x := new(Element).One()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ x.Mult32(x, 0xaa42aa42)
+ }
+}
diff --git a/src/crypto/internal/edwards25519/field/fe_generic.go b/src/crypto/internal/edwards25519/field/fe_generic.go
new file mode 100644
index 0000000..d6667b2
--- /dev/null
+++ b/src/crypto/internal/edwards25519/field/fe_generic.go
@@ -0,0 +1,266 @@
+// Copyright (c) 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package field
+
+import "math/bits"
+
+// uint128 holds a 128-bit number as two 64-bit limbs, for use with the
+// bits.Mul64 and bits.Add64 intrinsics.
+type uint128 struct {
+ lo, hi uint64
+}
+
+// mul64 returns a * b.
+func mul64(a, b uint64) uint128 {
+ hi, lo := bits.Mul64(a, b)
+ return uint128{lo, hi}
+}
+
+// addMul64 returns v + a * b.
+func addMul64(v uint128, a, b uint64) uint128 {
+ hi, lo := bits.Mul64(a, b)
+ lo, c := bits.Add64(lo, v.lo, 0)
+ hi, _ = bits.Add64(hi, v.hi, c)
+ return uint128{lo, hi}
+}
+
+// shiftRightBy51 returns a >> 51. a is assumed to be at most 115 bits.
+func shiftRightBy51(a uint128) uint64 {
+ return (a.hi << (64 - 51)) | (a.lo >> 51)
+}
+
+func feMulGeneric(v, a, b *Element) {
+ a0 := a.l0
+ a1 := a.l1
+ a2 := a.l2
+ a3 := a.l3
+ a4 := a.l4
+
+ b0 := b.l0
+ b1 := b.l1
+ b2 := b.l2
+ b3 := b.l3
+ b4 := b.l4
+
+ // Limb multiplication works like pen-and-paper columnar multiplication, but
+ // with 51-bit limbs instead of digits.
+ //
+ // a4 a3 a2 a1 a0 x
+ // b4 b3 b2 b1 b0 =
+ // ------------------------
+ // a4b0 a3b0 a2b0 a1b0 a0b0 +
+ // a4b1 a3b1 a2b1 a1b1 a0b1 +
+ // a4b2 a3b2 a2b2 a1b2 a0b2 +
+ // a4b3 a3b3 a2b3 a1b3 a0b3 +
+ // a4b4 a3b4 a2b4 a1b4 a0b4 =
+ // ----------------------------------------------
+ // r8 r7 r6 r5 r4 r3 r2 r1 r0
+ //
+ // We can then use the reduction identity (a * 2²⁵⁵ + b = a * 19 + b) to
+ // reduce the limbs that would overflow 255 bits. r5 * 2²⁵⁵ becomes 19 * r5,
+ // r6 * 2³⁰⁶ becomes 19 * r6 * 2⁵¹, etc.
+ //
+ // Reduction can be carried out simultaneously to multiplication. For
+ // example, we do not compute r5: whenever the result of a multiplication
+ // belongs to r5, like a1b4, we multiply it by 19 and add the result to r0.
+ //
+ // a4b0 a3b0 a2b0 a1b0 a0b0 +
+ // a3b1 a2b1 a1b1 a0b1 19×a4b1 +
+ // a2b2 a1b2 a0b2 19×a4b2 19×a3b2 +
+ // a1b3 a0b3 19×a4b3 19×a3b3 19×a2b3 +
+ // a0b4 19×a4b4 19×a3b4 19×a2b4 19×a1b4 =
+ // --------------------------------------
+ // r4 r3 r2 r1 r0
+ //
+ // Finally we add up the columns into wide, overlapping limbs.
+
+ a1_19 := a1 * 19
+ a2_19 := a2 * 19
+ a3_19 := a3 * 19
+ a4_19 := a4 * 19
+
+ // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
+ r0 := mul64(a0, b0)
+ r0 = addMul64(r0, a1_19, b4)
+ r0 = addMul64(r0, a2_19, b3)
+ r0 = addMul64(r0, a3_19, b2)
+ r0 = addMul64(r0, a4_19, b1)
+
+ // r1 = a0×b1 + a1×b0 + 19×(a2×b4 + a3×b3 + a4×b2)
+ r1 := mul64(a0, b1)
+ r1 = addMul64(r1, a1, b0)
+ r1 = addMul64(r1, a2_19, b4)
+ r1 = addMul64(r1, a3_19, b3)
+ r1 = addMul64(r1, a4_19, b2)
+
+ // r2 = a0×b2 + a1×b1 + a2×b0 + 19×(a3×b4 + a4×b3)
+ r2 := mul64(a0, b2)
+ r2 = addMul64(r2, a1, b1)
+ r2 = addMul64(r2, a2, b0)
+ r2 = addMul64(r2, a3_19, b4)
+ r2 = addMul64(r2, a4_19, b3)
+
+ // r3 = a0×b3 + a1×b2 + a2×b1 + a3×b0 + 19×a4×b4
+ r3 := mul64(a0, b3)
+ r3 = addMul64(r3, a1, b2)
+ r3 = addMul64(r3, a2, b1)
+ r3 = addMul64(r3, a3, b0)
+ r3 = addMul64(r3, a4_19, b4)
+
+ // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
+ r4 := mul64(a0, b4)
+ r4 = addMul64(r4, a1, b3)
+ r4 = addMul64(r4, a2, b2)
+ r4 = addMul64(r4, a3, b1)
+ r4 = addMul64(r4, a4, b0)
+
+ // After the multiplication, we need to reduce (carry) the five coefficients
+ // to obtain a result with limbs that are at most slightly larger than 2⁵¹,
+ // to respect the Element invariant.
+ //
+ // Overall, the reduction works the same as carryPropagate, except with
+ // wider inputs: we take the carry for each coefficient by shifting it right
+ // by 51, and add it to the limb above it. The top carry is multiplied by 19
+ // according to the reduction identity and added to the lowest limb.
+ //
+ // The largest coefficient (r0) will be at most 111 bits, which guarantees
+ // that all carries are at most 111 - 51 = 60 bits, which fits in a uint64.
+ //
+ // r0 = a0×b0 + 19×(a1×b4 + a2×b3 + a3×b2 + a4×b1)
+ // r0 < 2⁵²×2⁵² + 19×(2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵² + 2⁵²×2⁵²)
+ // r0 < (1 + 19 × 4) × 2⁵² × 2⁵²
+ // r0 < 2⁷ × 2⁵² × 2⁵²
+ // r0 < 2¹¹¹
+ //
+ // Moreover, the top coefficient (r4) is at most 107 bits, so c4 is at most
+ // 56 bits, and c4 * 19 is at most 61 bits, which again fits in a uint64 and
+ // allows us to easily apply the reduction identity.
+ //
+ // r4 = a0×b4 + a1×b3 + a2×b2 + a3×b1 + a4×b0
+ // r4 < 5 × 2⁵² × 2⁵²
+ // r4 < 2¹⁰⁷
+ //
+
+ c0 := shiftRightBy51(r0)
+ c1 := shiftRightBy51(r1)
+ c2 := shiftRightBy51(r2)
+ c3 := shiftRightBy51(r3)
+ c4 := shiftRightBy51(r4)
+
+ rr0 := r0.lo&maskLow51Bits + c4*19
+ rr1 := r1.lo&maskLow51Bits + c0
+ rr2 := r2.lo&maskLow51Bits + c1
+ rr3 := r3.lo&maskLow51Bits + c2
+ rr4 := r4.lo&maskLow51Bits + c3
+
+ // Now all coefficients fit into 64-bit registers but are still too large to
+ // be passed around as a Element. We therefore do one last carry chain,
+ // where the carries will be small enough to fit in the wiggle room above 2⁵¹.
+ *v = Element{rr0, rr1, rr2, rr3, rr4}
+ v.carryPropagate()
+}
+
+func feSquareGeneric(v, a *Element) {
+ l0 := a.l0
+ l1 := a.l1
+ l2 := a.l2
+ l3 := a.l3
+ l4 := a.l4
+
+ // Squaring works precisely like multiplication above, but thanks to its
+ // symmetry we get to group a few terms together.
+ //
+ // l4 l3 l2 l1 l0 x
+ // l4 l3 l2 l1 l0 =
+ // ------------------------
+ // l4l0 l3l0 l2l0 l1l0 l0l0 +
+ // l4l1 l3l1 l2l1 l1l1 l0l1 +
+ // l4l2 l3l2 l2l2 l1l2 l0l2 +
+ // l4l3 l3l3 l2l3 l1l3 l0l3 +
+ // l4l4 l3l4 l2l4 l1l4 l0l4 =
+ // ----------------------------------------------
+ // r8 r7 r6 r5 r4 r3 r2 r1 r0
+ //
+ // l4l0 l3l0 l2l0 l1l0 l0l0 +
+ // l3l1 l2l1 l1l1 l0l1 19×l4l1 +
+ // l2l2 l1l2 l0l2 19×l4l2 19×l3l2 +
+ // l1l3 l0l3 19×l4l3 19×l3l3 19×l2l3 +
+ // l0l4 19×l4l4 19×l3l4 19×l2l4 19×l1l4 =
+ // --------------------------------------
+ // r4 r3 r2 r1 r0
+ //
+ // With precomputed 2×, 19×, and 2×19× terms, we can compute each limb with
+ // only three Mul64 and four Add64, instead of five and eight.
+
+ l0_2 := l0 * 2
+ l1_2 := l1 * 2
+
+ l1_38 := l1 * 38
+ l2_38 := l2 * 38
+ l3_38 := l3 * 38
+
+ l3_19 := l3 * 19
+ l4_19 := l4 * 19
+
+ // r0 = l0×l0 + 19×(l1×l4 + l2×l3 + l3×l2 + l4×l1) = l0×l0 + 19×2×(l1×l4 + l2×l3)
+ r0 := mul64(l0, l0)
+ r0 = addMul64(r0, l1_38, l4)
+ r0 = addMul64(r0, l2_38, l3)
+
+ // r1 = l0×l1 + l1×l0 + 19×(l2×l4 + l3×l3 + l4×l2) = 2×l0×l1 + 19×2×l2×l4 + 19×l3×l3
+ r1 := mul64(l0_2, l1)
+ r1 = addMul64(r1, l2_38, l4)
+ r1 = addMul64(r1, l3_19, l3)
+
+ // r2 = l0×l2 + l1×l1 + l2×l0 + 19×(l3×l4 + l4×l3) = 2×l0×l2 + l1×l1 + 19×2×l3×l4
+ r2 := mul64(l0_2, l2)
+ r2 = addMul64(r2, l1, l1)
+ r2 = addMul64(r2, l3_38, l4)
+
+ // r3 = l0×l3 + l1×l2 + l2×l1 + l3×l0 + 19×l4×l4 = 2×l0×l3 + 2×l1×l2 + 19×l4×l4
+ r3 := mul64(l0_2, l3)
+ r3 = addMul64(r3, l1_2, l2)
+ r3 = addMul64(r3, l4_19, l4)
+
+ // r4 = l0×l4 + l1×l3 + l2×l2 + l3×l1 + l4×l0 = 2×l0×l4 + 2×l1×l3 + l2×l2
+ r4 := mul64(l0_2, l4)
+ r4 = addMul64(r4, l1_2, l3)
+ r4 = addMul64(r4, l2, l2)
+
+ c0 := shiftRightBy51(r0)
+ c1 := shiftRightBy51(r1)
+ c2 := shiftRightBy51(r2)
+ c3 := shiftRightBy51(r3)
+ c4 := shiftRightBy51(r4)
+
+ rr0 := r0.lo&maskLow51Bits + c4*19
+ rr1 := r1.lo&maskLow51Bits + c0
+ rr2 := r2.lo&maskLow51Bits + c1
+ rr3 := r3.lo&maskLow51Bits + c2
+ rr4 := r4.lo&maskLow51Bits + c3
+
+ *v = Element{rr0, rr1, rr2, rr3, rr4}
+ v.carryPropagate()
+}
+
+// carryPropagate brings the limbs below 52 bits by applying the reduction
+// identity (a * 2²⁵⁵ + b = a * 19 + b) to the l4 carry.
+func (v *Element) carryPropagateGeneric() *Element {
+ c0 := v.l0 >> 51
+ c1 := v.l1 >> 51
+ c2 := v.l2 >> 51
+ c3 := v.l3 >> 51
+ c4 := v.l4 >> 51
+
+ // c4 is at most 64 - 51 = 13 bits, so c4*19 is at most 18 bits, and
+ // the final l0 will be at most 52 bits. Similarly for the rest.
+ v.l0 = v.l0&maskLow51Bits + c4*19
+ v.l1 = v.l1&maskLow51Bits + c0
+ v.l2 = v.l2&maskLow51Bits + c1
+ v.l3 = v.l3&maskLow51Bits + c2
+ v.l4 = v.l4&maskLow51Bits + c3
+
+ return v
+}
diff --git a/src/crypto/internal/edwards25519/field/fe_test.go b/src/crypto/internal/edwards25519/field/fe_test.go
new file mode 100644
index 0000000..945a024
--- /dev/null
+++ b/src/crypto/internal/edwards25519/field/fe_test.go
@@ -0,0 +1,560 @@
+// Copyright (c) 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package field
+
+import (
+ "bytes"
+ "crypto/rand"
+ "encoding/hex"
+ "io"
+ "math/big"
+ "math/bits"
+ mathrand "math/rand"
+ "reflect"
+ "testing"
+ "testing/quick"
+)
+
+func (v Element) String() string {
+ return hex.EncodeToString(v.Bytes())
+}
+
+// quickCheckConfig1024 will make each quickcheck test run (1024 * -quickchecks)
+// times. The default value of -quickchecks is 100.
+var quickCheckConfig1024 = &quick.Config{MaxCountScale: 1 << 10}
+
+func generateFieldElement(rand *mathrand.Rand) Element {
+ const maskLow52Bits = (1 << 52) - 1
+ return Element{
+ rand.Uint64() & maskLow52Bits,
+ rand.Uint64() & maskLow52Bits,
+ rand.Uint64() & maskLow52Bits,
+ rand.Uint64() & maskLow52Bits,
+ rand.Uint64() & maskLow52Bits,
+ }
+}
+
+// weirdLimbs can be combined to generate a range of edge-case field elements.
+// 0 and -1 are intentionally more weighted, as they combine well.
+var (
+ weirdLimbs51 = []uint64{
+ 0, 0, 0, 0,
+ 1,
+ 19 - 1,
+ 19,
+ 0x2aaaaaaaaaaaa,
+ 0x5555555555555,
+ (1 << 51) - 20,
+ (1 << 51) - 19,
+ (1 << 51) - 1, (1 << 51) - 1,
+ (1 << 51) - 1, (1 << 51) - 1,
+ }
+ weirdLimbs52 = []uint64{
+ 0, 0, 0, 0, 0, 0,
+ 1,
+ 19 - 1,
+ 19,
+ 0x2aaaaaaaaaaaa,
+ 0x5555555555555,
+ (1 << 51) - 20,
+ (1 << 51) - 19,
+ (1 << 51) - 1, (1 << 51) - 1,
+ (1 << 51) - 1, (1 << 51) - 1,
+ (1 << 51) - 1, (1 << 51) - 1,
+ 1 << 51,
+ (1 << 51) + 1,
+ (1 << 52) - 19,
+ (1 << 52) - 1,
+ }
+)
+
+func generateWeirdFieldElement(rand *mathrand.Rand) Element {
+ return Element{
+ weirdLimbs52[rand.Intn(len(weirdLimbs52))],
+ weirdLimbs51[rand.Intn(len(weirdLimbs51))],
+ weirdLimbs51[rand.Intn(len(weirdLimbs51))],
+ weirdLimbs51[rand.Intn(len(weirdLimbs51))],
+ weirdLimbs51[rand.Intn(len(weirdLimbs51))],
+ }
+}
+
+func (Element) Generate(rand *mathrand.Rand, size int) reflect.Value {
+ if rand.Intn(2) == 0 {
+ return reflect.ValueOf(generateWeirdFieldElement(rand))
+ }
+ return reflect.ValueOf(generateFieldElement(rand))
+}
+
+// isInBounds returns whether the element is within the expected bit size bounds
+// after a light reduction.
+func isInBounds(x *Element) bool {
+ return bits.Len64(x.l0) <= 52 &&
+ bits.Len64(x.l1) <= 52 &&
+ bits.Len64(x.l2) <= 52 &&
+ bits.Len64(x.l3) <= 52 &&
+ bits.Len64(x.l4) <= 52
+}
+
+func TestMultiplyDistributesOverAdd(t *testing.T) {
+ multiplyDistributesOverAdd := func(x, y, z Element) bool {
+ // Compute t1 = (x+y)*z
+ t1 := new(Element)
+ t1.Add(&x, &y)
+ t1.Multiply(t1, &z)
+
+ // Compute t2 = x*z + y*z
+ t2 := new(Element)
+ t3 := new(Element)
+ t2.Multiply(&x, &z)
+ t3.Multiply(&y, &z)
+ t2.Add(t2, t3)
+
+ return t1.Equal(t2) == 1 && isInBounds(t1) && isInBounds(t2)
+ }
+
+ if err := quick.Check(multiplyDistributesOverAdd, quickCheckConfig1024); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestMul64to128(t *testing.T) {
+ a := uint64(5)
+ b := uint64(5)
+ r := mul64(a, b)
+ if r.lo != 0x19 || r.hi != 0 {
+ t.Errorf("lo-range wide mult failed, got %d + %d*(2**64)", r.lo, r.hi)
+ }
+
+ a = uint64(18014398509481983) // 2^54 - 1
+ b = uint64(18014398509481983) // 2^54 - 1
+ r = mul64(a, b)
+ if r.lo != 0xff80000000000001 || r.hi != 0xfffffffffff {
+ t.Errorf("hi-range wide mult failed, got %d + %d*(2**64)", r.lo, r.hi)
+ }
+
+ a = uint64(1125899906842661)
+ b = uint64(2097155)
+ r = mul64(a, b)
+ r = addMul64(r, a, b)
+ r = addMul64(r, a, b)
+ r = addMul64(r, a, b)
+ r = addMul64(r, a, b)
+ if r.lo != 16888498990613035 || r.hi != 640 {
+ t.Errorf("wrong answer: %d + %d*(2**64)", r.lo, r.hi)
+ }
+}
+
+func TestSetBytesRoundTrip(t *testing.T) {
+ f1 := func(in [32]byte, fe Element) bool {
+ fe.SetBytes(in[:])
+
+ // Mask the most significant bit as it's ignored by SetBytes. (Now
+ // instead of earlier so we check the masking in SetBytes is working.)
+ in[len(in)-1] &= (1 << 7) - 1
+
+ return bytes.Equal(in[:], fe.Bytes()) && isInBounds(&fe)
+ }
+ if err := quick.Check(f1, nil); err != nil {
+ t.Errorf("failed bytes->FE->bytes round-trip: %v", err)
+ }
+
+ f2 := func(fe, r Element) bool {
+ r.SetBytes(fe.Bytes())
+
+ // Intentionally not using Equal not to go through Bytes again.
+ // Calling reduce because both Generate and SetBytes can produce
+ // non-canonical representations.
+ fe.reduce()
+ r.reduce()
+ return fe == r
+ }
+ if err := quick.Check(f2, nil); err != nil {
+ t.Errorf("failed FE->bytes->FE round-trip: %v", err)
+ }
+
+ // Check some fixed vectors from dalek
+ type feRTTest struct {
+ fe Element
+ b []byte
+ }
+ var tests = []feRTTest{
+ {
+ fe: Element{358744748052810, 1691584618240980, 977650209285361, 1429865912637724, 560044844278676},
+ b: []byte{74, 209, 69, 197, 70, 70, 161, 222, 56, 226, 229, 19, 112, 60, 25, 92, 187, 74, 222, 56, 50, 153, 51, 233, 40, 74, 57, 6, 160, 185, 213, 31},
+ },
+ {
+ fe: Element{84926274344903, 473620666599931, 365590438845504, 1028470286882429, 2146499180330972},
+ b: []byte{199, 23, 106, 112, 61, 77, 216, 79, 186, 60, 11, 118, 13, 16, 103, 15, 42, 32, 83, 250, 44, 57, 204, 198, 78, 199, 253, 119, 146, 172, 3, 122},
+ },
+ }
+
+ for _, tt := range tests {
+ b := tt.fe.Bytes()
+ fe, _ := new(Element).SetBytes(tt.b)
+ if !bytes.Equal(b, tt.b) || fe.Equal(&tt.fe) != 1 {
+ t.Errorf("Failed fixed roundtrip: %v", tt)
+ }
+ }
+}
+
+func swapEndianness(buf []byte) []byte {
+ for i := 0; i < len(buf)/2; i++ {
+ buf[i], buf[len(buf)-i-1] = buf[len(buf)-i-1], buf[i]
+ }
+ return buf
+}
+
+func TestBytesBigEquivalence(t *testing.T) {
+ f1 := func(in [32]byte, fe, fe1 Element) bool {
+ fe.SetBytes(in[:])
+
+ in[len(in)-1] &= (1 << 7) - 1 // mask the most significant bit
+ b := new(big.Int).SetBytes(swapEndianness(in[:]))
+ fe1.fromBig(b)
+
+ if fe != fe1 {
+ return false
+ }
+
+ buf := make([]byte, 32)
+ buf = swapEndianness(fe1.toBig().FillBytes(buf))
+
+ return bytes.Equal(fe.Bytes(), buf) && isInBounds(&fe) && isInBounds(&fe1)
+ }
+ if err := quick.Check(f1, nil); err != nil {
+ t.Error(err)
+ }
+}
+
+// fromBig sets v = n, and returns v. The bit length of n must not exceed 256.
+func (v *Element) fromBig(n *big.Int) *Element {
+ if n.BitLen() > 32*8 {
+ panic("edwards25519: invalid field element input size")
+ }
+
+ buf := make([]byte, 0, 32)
+ for _, word := range n.Bits() {
+ for i := 0; i < bits.UintSize; i += 8 {
+ if len(buf) >= cap(buf) {
+ break
+ }
+ buf = append(buf, byte(word))
+ word >>= 8
+ }
+ }
+
+ v.SetBytes(buf[:32])
+ return v
+}
+
+func (v *Element) fromDecimal(s string) *Element {
+ n, ok := new(big.Int).SetString(s, 10)
+ if !ok {
+ panic("not a valid decimal: " + s)
+ }
+ return v.fromBig(n)
+}
+
+// toBig returns v as a big.Int.
+func (v *Element) toBig() *big.Int {
+ buf := v.Bytes()
+
+ words := make([]big.Word, 32*8/bits.UintSize)
+ for n := range words {
+ for i := 0; i < bits.UintSize; i += 8 {
+ if len(buf) == 0 {
+ break
+ }
+ words[n] |= big.Word(buf[0]) << big.Word(i)
+ buf = buf[1:]
+ }
+ }
+
+ return new(big.Int).SetBits(words)
+}
+
+func TestDecimalConstants(t *testing.T) {
+ sqrtM1String := "19681161376707505956807079304988542015446066515923890162744021073123829784752"
+ if exp := new(Element).fromDecimal(sqrtM1String); sqrtM1.Equal(exp) != 1 {
+ t.Errorf("sqrtM1 is %v, expected %v", sqrtM1, exp)
+ }
+ // d is in the parent package, and we don't want to expose d or fromDecimal.
+ // dString := "37095705934669439343138083508754565189542113879843219016388785533085940283555"
+ // if exp := new(Element).fromDecimal(dString); d.Equal(exp) != 1 {
+ // t.Errorf("d is %v, expected %v", d, exp)
+ // }
+}
+
+func TestSetBytesRoundTripEdgeCases(t *testing.T) {
+ // TODO: values close to 0, close to 2^255-19, between 2^255-19 and 2^255-1,
+ // and between 2^255 and 2^256-1. Test both the documented SetBytes
+ // behavior, and that Bytes reduces them.
+}
+
+// Tests self-consistency between Multiply and Square.
+func TestConsistency(t *testing.T) {
+ var x Element
+ var x2, x2sq Element
+
+ x = Element{1, 1, 1, 1, 1}
+ x2.Multiply(&x, &x)
+ x2sq.Square(&x)
+
+ if x2 != x2sq {
+ t.Fatalf("all ones failed\nmul: %x\nsqr: %x\n", x2, x2sq)
+ }
+
+ var bytes [32]byte
+
+ _, err := io.ReadFull(rand.Reader, bytes[:])
+ if err != nil {
+ t.Fatal(err)
+ }
+ x.SetBytes(bytes[:])
+
+ x2.Multiply(&x, &x)
+ x2sq.Square(&x)
+
+ if x2 != x2sq {
+ t.Fatalf("all ones failed\nmul: %x\nsqr: %x\n", x2, x2sq)
+ }
+}
+
+func TestEqual(t *testing.T) {
+ x := Element{1, 1, 1, 1, 1}
+ y := Element{5, 4, 3, 2, 1}
+
+ eq := x.Equal(&x)
+ if eq != 1 {
+ t.Errorf("wrong about equality")
+ }
+
+ eq = x.Equal(&y)
+ if eq != 0 {
+ t.Errorf("wrong about inequality")
+ }
+}
+
+func TestInvert(t *testing.T) {
+ x := Element{1, 1, 1, 1, 1}
+ one := Element{1, 0, 0, 0, 0}
+ var xinv, r Element
+
+ xinv.Invert(&x)
+ r.Multiply(&x, &xinv)
+ r.reduce()
+
+ if one != r {
+ t.Errorf("inversion identity failed, got: %x", r)
+ }
+
+ var bytes [32]byte
+
+ _, err := io.ReadFull(rand.Reader, bytes[:])
+ if err != nil {
+ t.Fatal(err)
+ }
+ x.SetBytes(bytes[:])
+
+ xinv.Invert(&x)
+ r.Multiply(&x, &xinv)
+ r.reduce()
+
+ if one != r {
+ t.Errorf("random inversion identity failed, got: %x for field element %x", r, x)
+ }
+
+ zero := Element{}
+ x.Set(&zero)
+ if xx := xinv.Invert(&x); xx != &xinv {
+ t.Errorf("inverting zero did not return the receiver")
+ } else if xinv.Equal(&zero) != 1 {
+ t.Errorf("inverting zero did not return zero")
+ }
+}
+
+func TestSelectSwap(t *testing.T) {
+ a := Element{358744748052810, 1691584618240980, 977650209285361, 1429865912637724, 560044844278676}
+ b := Element{84926274344903, 473620666599931, 365590438845504, 1028470286882429, 2146499180330972}
+
+ var c, d Element
+
+ c.Select(&a, &b, 1)
+ d.Select(&a, &b, 0)
+
+ if c.Equal(&a) != 1 || d.Equal(&b) != 1 {
+ t.Errorf("Select failed")
+ }
+
+ c.Swap(&d, 0)
+
+ if c.Equal(&a) != 1 || d.Equal(&b) != 1 {
+ t.Errorf("Swap failed")
+ }
+
+ c.Swap(&d, 1)
+
+ if c.Equal(&b) != 1 || d.Equal(&a) != 1 {
+ t.Errorf("Swap failed")
+ }
+}
+
+func TestMult32(t *testing.T) {
+ mult32EquivalentToMul := func(x Element, y uint32) bool {
+ t1 := new(Element)
+ for i := 0; i < 100; i++ {
+ t1.Mult32(&x, y)
+ }
+
+ ty := new(Element)
+ ty.l0 = uint64(y)
+
+ t2 := new(Element)
+ for i := 0; i < 100; i++ {
+ t2.Multiply(&x, ty)
+ }
+
+ return t1.Equal(t2) == 1 && isInBounds(t1) && isInBounds(t2)
+ }
+
+ if err := quick.Check(mult32EquivalentToMul, quickCheckConfig1024); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestSqrtRatio(t *testing.T) {
+ // From draft-irtf-cfrg-ristretto255-decaf448-00, Appendix A.4.
+ type test struct {
+ u, v string
+ wasSquare int
+ r string
+ }
+ var tests = []test{
+ // If u is 0, the function is defined to return (0, TRUE), even if v
+ // is zero. Note that where used in this package, the denominator v
+ // is never zero.
+ {
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ 1, "0000000000000000000000000000000000000000000000000000000000000000",
+ },
+ // 0/1 == 0²
+ {
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ "0100000000000000000000000000000000000000000000000000000000000000",
+ 1, "0000000000000000000000000000000000000000000000000000000000000000",
+ },
+ // If u is non-zero and v is zero, defined to return (0, FALSE).
+ {
+ "0100000000000000000000000000000000000000000000000000000000000000",
+ "0000000000000000000000000000000000000000000000000000000000000000",
+ 0, "0000000000000000000000000000000000000000000000000000000000000000",
+ },
+ // 2/1 is not square in this field.
+ {
+ "0200000000000000000000000000000000000000000000000000000000000000",
+ "0100000000000000000000000000000000000000000000000000000000000000",
+ 0, "3c5ff1b5d8e4113b871bd052f9e7bcd0582804c266ffb2d4f4203eb07fdb7c54",
+ },
+ // 4/1 == 2²
+ {
+ "0400000000000000000000000000000000000000000000000000000000000000",
+ "0100000000000000000000000000000000000000000000000000000000000000",
+ 1, "0200000000000000000000000000000000000000000000000000000000000000",
+ },
+ // 1/4 == (2⁻¹)² == (2^(p-2))² per Euler's theorem
+ {
+ "0100000000000000000000000000000000000000000000000000000000000000",
+ "0400000000000000000000000000000000000000000000000000000000000000",
+ 1, "f6ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff3f",
+ },
+ }
+
+ for i, tt := range tests {
+ u, _ := new(Element).SetBytes(decodeHex(tt.u))
+ v, _ := new(Element).SetBytes(decodeHex(tt.v))
+ want, _ := new(Element).SetBytes(decodeHex(tt.r))
+ got, wasSquare := new(Element).SqrtRatio(u, v)
+ if got.Equal(want) == 0 || wasSquare != tt.wasSquare {
+ t.Errorf("%d: got (%v, %v), want (%v, %v)", i, got, wasSquare, want, tt.wasSquare)
+ }
+ }
+}
+
+func TestCarryPropagate(t *testing.T) {
+ asmLikeGeneric := func(a [5]uint64) bool {
+ t1 := &Element{a[0], a[1], a[2], a[3], a[4]}
+ t2 := &Element{a[0], a[1], a[2], a[3], a[4]}
+
+ t1.carryPropagate()
+ t2.carryPropagateGeneric()
+
+ if *t1 != *t2 {
+ t.Logf("got: %#v,\nexpected: %#v", t1, t2)
+ }
+
+ return *t1 == *t2 && isInBounds(t2)
+ }
+
+ if err := quick.Check(asmLikeGeneric, quickCheckConfig1024); err != nil {
+ t.Error(err)
+ }
+
+ if !asmLikeGeneric([5]uint64{0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff}) {
+ t.Errorf("failed for {0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff, 0xffffffffffffffff}")
+ }
+}
+
+func TestFeSquare(t *testing.T) {
+ asmLikeGeneric := func(a Element) bool {
+ t1 := a
+ t2 := a
+
+ feSquareGeneric(&t1, &t1)
+ feSquare(&t2, &t2)
+
+ if t1 != t2 {
+ t.Logf("got: %#v,\nexpected: %#v", t1, t2)
+ }
+
+ return t1 == t2 && isInBounds(&t2)
+ }
+
+ if err := quick.Check(asmLikeGeneric, quickCheckConfig1024); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestFeMul(t *testing.T) {
+ asmLikeGeneric := func(a, b Element) bool {
+ a1 := a
+ a2 := a
+ b1 := b
+ b2 := b
+
+ feMulGeneric(&a1, &a1, &b1)
+ feMul(&a2, &a2, &b2)
+
+ if a1 != a2 || b1 != b2 {
+ t.Logf("got: %#v,\nexpected: %#v", a1, a2)
+ t.Logf("got: %#v,\nexpected: %#v", b1, b2)
+ }
+
+ return a1 == a2 && isInBounds(&a2) &&
+ b1 == b2 && isInBounds(&b2)
+ }
+
+ if err := quick.Check(asmLikeGeneric, quickCheckConfig1024); err != nil {
+ t.Error(err)
+ }
+}
+
+func decodeHex(s string) []byte {
+ b, err := hex.DecodeString(s)
+ if err != nil {
+ panic(err)
+ }
+ return b
+}
diff --git a/src/crypto/internal/edwards25519/scalar.go b/src/crypto/internal/edwards25519/scalar.go
new file mode 100644
index 0000000..d34ecea
--- /dev/null
+++ b/src/crypto/internal/edwards25519/scalar.go
@@ -0,0 +1,343 @@
+// Copyright (c) 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+import (
+ "encoding/binary"
+ "errors"
+)
+
+// A Scalar is an integer modulo
+//
+// l = 2^252 + 27742317777372353535851937790883648493
+//
+// which is the prime order of the edwards25519 group.
+//
+// This type works similarly to math/big.Int, and all arguments and
+// receivers are allowed to alias.
+//
+// The zero value is a valid zero element.
+type Scalar struct {
+ // s is the scalar in the Montgomery domain, in the format of the
+ // fiat-crypto implementation.
+ s fiatScalarMontgomeryDomainFieldElement
+}
+
+// The field implementation in scalar_fiat.go is generated by the fiat-crypto
+// project (https://github.com/mit-plv/fiat-crypto) at version v0.0.9 (23d2dbc)
+// from a formally verified model.
+//
+// fiat-crypto code comes under the following license.
+//
+// Copyright (c) 2015-2020 The fiat-crypto Authors. All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions are
+// met:
+//
+// 1. Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS"
+// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+// THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design,
+// Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+// LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+// NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+//
+
+// NewScalar returns a new zero Scalar.
+func NewScalar() *Scalar {
+ return &Scalar{}
+}
+
+// MultiplyAdd sets s = x * y + z mod l, and returns s. It is equivalent to
+// using Multiply and then Add.
+func (s *Scalar) MultiplyAdd(x, y, z *Scalar) *Scalar {
+ // Make a copy of z in case it aliases s.
+ zCopy := new(Scalar).Set(z)
+ return s.Multiply(x, y).Add(s, zCopy)
+}
+
+// Add sets s = x + y mod l, and returns s.
+func (s *Scalar) Add(x, y *Scalar) *Scalar {
+ // s = 1 * x + y mod l
+ fiatScalarAdd(&s.s, &x.s, &y.s)
+ return s
+}
+
+// Subtract sets s = x - y mod l, and returns s.
+func (s *Scalar) Subtract(x, y *Scalar) *Scalar {
+ // s = -1 * y + x mod l
+ fiatScalarSub(&s.s, &x.s, &y.s)
+ return s
+}
+
+// Negate sets s = -x mod l, and returns s.
+func (s *Scalar) Negate(x *Scalar) *Scalar {
+ // s = -1 * x + 0 mod l
+ fiatScalarOpp(&s.s, &x.s)
+ return s
+}
+
+// Multiply sets s = x * y mod l, and returns s.
+func (s *Scalar) Multiply(x, y *Scalar) *Scalar {
+ // s = x * y + 0 mod l
+ fiatScalarMul(&s.s, &x.s, &y.s)
+ return s
+}
+
+// Set sets s = x, and returns s.
+func (s *Scalar) Set(x *Scalar) *Scalar {
+ *s = *x
+ return s
+}
+
+// SetUniformBytes sets s = x mod l, where x is a 64-byte little-endian integer.
+// If x is not of the right length, SetUniformBytes returns nil and an error,
+// and the receiver is unchanged.
+//
+// SetUniformBytes can be used to set s to an uniformly distributed value given
+// 64 uniformly distributed random bytes.
+func (s *Scalar) SetUniformBytes(x []byte) (*Scalar, error) {
+ if len(x) != 64 {
+ return nil, errors.New("edwards25519: invalid SetUniformBytes input length")
+ }
+
+ // We have a value x of 512 bits, but our fiatScalarFromBytes function
+ // expects an input lower than l, which is a little over 252 bits.
+ //
+ // Instead of writing a reduction function that operates on wider inputs, we
+ // can interpret x as the sum of three shorter values a, b, and c.
+ //
+ // x = a + b * 2^168 + c * 2^336 mod l
+ //
+ // We then precompute 2^168 and 2^336 modulo l, and perform the reduction
+ // with two multiplications and two additions.
+
+ s.setShortBytes(x[:21])
+ t := new(Scalar).setShortBytes(x[21:42])
+ s.Add(s, t.Multiply(t, scalarTwo168))
+ t.setShortBytes(x[42:])
+ s.Add(s, t.Multiply(t, scalarTwo336))
+
+ return s, nil
+}
+
+// scalarTwo168 and scalarTwo336 are 2^168 and 2^336 modulo l, encoded as a
+// fiatScalarMontgomeryDomainFieldElement, which is a little-endian 4-limb value
+// in the 2^256 Montgomery domain.
+var scalarTwo168 = &Scalar{s: [4]uint64{0x5b8ab432eac74798, 0x38afddd6de59d5d7,
+ 0xa2c131b399411b7c, 0x6329a7ed9ce5a30}}
+var scalarTwo336 = &Scalar{s: [4]uint64{0xbd3d108e2b35ecc5, 0x5c3a3718bdf9c90b,
+ 0x63aa97a331b4f2ee, 0x3d217f5be65cb5c}}
+
+// setShortBytes sets s = x mod l, where x is a little-endian integer shorter
+// than 32 bytes.
+func (s *Scalar) setShortBytes(x []byte) *Scalar {
+ if len(x) >= 32 {
+ panic("edwards25519: internal error: setShortBytes called with a long string")
+ }
+ var buf [32]byte
+ copy(buf[:], x)
+ fiatScalarFromBytes((*[4]uint64)(&s.s), &buf)
+ fiatScalarToMontgomery(&s.s, (*fiatScalarNonMontgomeryDomainFieldElement)(&s.s))
+ return s
+}
+
+// SetCanonicalBytes sets s = x, where x is a 32-byte little-endian encoding of
+// s, and returns s. If x is not a canonical encoding of s, SetCanonicalBytes
+// returns nil and an error, and the receiver is unchanged.
+func (s *Scalar) SetCanonicalBytes(x []byte) (*Scalar, error) {
+ if len(x) != 32 {
+ return nil, errors.New("invalid scalar length")
+ }
+ if !isReduced(x) {
+ return nil, errors.New("invalid scalar encoding")
+ }
+
+ fiatScalarFromBytes((*[4]uint64)(&s.s), (*[32]byte)(x))
+ fiatScalarToMontgomery(&s.s, (*fiatScalarNonMontgomeryDomainFieldElement)(&s.s))
+
+ return s, nil
+}
+
+// scalarMinusOneBytes is l - 1 in little endian.
+var scalarMinusOneBytes = [32]byte{236, 211, 245, 92, 26, 99, 18, 88, 214, 156, 247, 162, 222, 249, 222, 20, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 16}
+
+// isReduced returns whether the given scalar in 32-byte little endian encoded
+// form is reduced modulo l.
+func isReduced(s []byte) bool {
+ if len(s) != 32 {
+ return false
+ }
+
+ for i := len(s) - 1; i >= 0; i-- {
+ switch {
+ case s[i] > scalarMinusOneBytes[i]:
+ return false
+ case s[i] < scalarMinusOneBytes[i]:
+ return true
+ }
+ }
+ return true
+}
+
+// SetBytesWithClamping applies the buffer pruning described in RFC 8032,
+// Section 5.1.5 (also known as clamping) and sets s to the result. The input
+// must be 32 bytes, and it is not modified. If x is not of the right length,
+// SetBytesWithClamping returns nil and an error, and the receiver is unchanged.
+//
+// Note that since Scalar values are always reduced modulo the prime order of
+// the curve, the resulting value will not preserve any of the cofactor-clearing
+// properties that clamping is meant to provide. It will however work as
+// expected as long as it is applied to points on the prime order subgroup, like
+// in Ed25519. In fact, it is lost to history why RFC 8032 adopted the
+// irrelevant RFC 7748 clamping, but it is now required for compatibility.
+func (s *Scalar) SetBytesWithClamping(x []byte) (*Scalar, error) {
+ // The description above omits the purpose of the high bits of the clamping
+ // for brevity, but those are also lost to reductions, and are also
+ // irrelevant to edwards25519 as they protect against a specific
+ // implementation bug that was once observed in a generic Montgomery ladder.
+ if len(x) != 32 {
+ return nil, errors.New("edwards25519: invalid SetBytesWithClamping input length")
+ }
+
+ // We need to use the wide reduction from SetUniformBytes, since clamping
+ // sets the 2^254 bit, making the value higher than the order.
+ var wideBytes [64]byte
+ copy(wideBytes[:], x[:])
+ wideBytes[0] &= 248
+ wideBytes[31] &= 63
+ wideBytes[31] |= 64
+ return s.SetUniformBytes(wideBytes[:])
+}
+
+// Bytes returns the canonical 32-byte little-endian encoding of s.
+func (s *Scalar) Bytes() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var encoded [32]byte
+ return s.bytes(&encoded)
+}
+
+func (s *Scalar) bytes(out *[32]byte) []byte {
+ var ss fiatScalarNonMontgomeryDomainFieldElement
+ fiatScalarFromMontgomery(&ss, &s.s)
+ fiatScalarToBytes(out, (*[4]uint64)(&ss))
+ return out[:]
+}
+
+// Equal returns 1 if s and t are equal, and 0 otherwise.
+func (s *Scalar) Equal(t *Scalar) int {
+ var diff fiatScalarMontgomeryDomainFieldElement
+ fiatScalarSub(&diff, &s.s, &t.s)
+ var nonzero uint64
+ fiatScalarNonzero(&nonzero, (*[4]uint64)(&diff))
+ nonzero |= nonzero >> 32
+ nonzero |= nonzero >> 16
+ nonzero |= nonzero >> 8
+ nonzero |= nonzero >> 4
+ nonzero |= nonzero >> 2
+ nonzero |= nonzero >> 1
+ return int(^nonzero) & 1
+}
+
+// nonAdjacentForm computes a width-w non-adjacent form for this scalar.
+//
+// w must be between 2 and 8, or nonAdjacentForm will panic.
+func (s *Scalar) nonAdjacentForm(w uint) [256]int8 {
+ // This implementation is adapted from the one
+ // in curve25519-dalek and is documented there:
+ // https://github.com/dalek-cryptography/curve25519-dalek/blob/f630041af28e9a405255f98a8a93adca18e4315b/src/scalar.rs#L800-L871
+ b := s.Bytes()
+ if b[31] > 127 {
+ panic("scalar has high bit set illegally")
+ }
+ if w < 2 {
+ panic("w must be at least 2 by the definition of NAF")
+ } else if w > 8 {
+ panic("NAF digits must fit in int8")
+ }
+
+ var naf [256]int8
+ var digits [5]uint64
+
+ for i := 0; i < 4; i++ {
+ digits[i] = binary.LittleEndian.Uint64(b[i*8:])
+ }
+
+ width := uint64(1 << w)
+ windowMask := uint64(width - 1)
+
+ pos := uint(0)
+ carry := uint64(0)
+ for pos < 256 {
+ indexU64 := pos / 64
+ indexBit := pos % 64
+ var bitBuf uint64
+ if indexBit < 64-w {
+ // This window's bits are contained in a single u64
+ bitBuf = digits[indexU64] >> indexBit
+ } else {
+ // Combine the current 64 bits with bits from the next 64
+ bitBuf = (digits[indexU64] >> indexBit) | (digits[1+indexU64] << (64 - indexBit))
+ }
+
+ // Add carry into the current window
+ window := carry + (bitBuf & windowMask)
+
+ if window&1 == 0 {
+ // If the window value is even, preserve the carry and continue.
+ // Why is the carry preserved?
+ // If carry == 0 and window & 1 == 0,
+ // then the next carry should be 0
+ // If carry == 1 and window & 1 == 0,
+ // then bit_buf & 1 == 1 so the next carry should be 1
+ pos += 1
+ continue
+ }
+
+ if window < width/2 {
+ carry = 0
+ naf[pos] = int8(window)
+ } else {
+ carry = 1
+ naf[pos] = int8(window) - int8(width)
+ }
+
+ pos += w
+ }
+ return naf
+}
+
+func (s *Scalar) signedRadix16() [64]int8 {
+ b := s.Bytes()
+ if b[31] > 127 {
+ panic("scalar has high bit set illegally")
+ }
+
+ var digits [64]int8
+
+ // Compute unsigned radix-16 digits:
+ for i := 0; i < 32; i++ {
+ digits[2*i] = int8(b[i] & 15)
+ digits[2*i+1] = int8((b[i] >> 4) & 15)
+ }
+
+ // Recenter coefficients:
+ for i := 0; i < 63; i++ {
+ carry := (digits[i] + 8) >> 4
+ digits[i] -= carry << 4
+ digits[i+1] += carry
+ }
+
+ return digits
+}
diff --git a/src/crypto/internal/edwards25519/scalar_alias_test.go b/src/crypto/internal/edwards25519/scalar_alias_test.go
new file mode 100644
index 0000000..4d83441
--- /dev/null
+++ b/src/crypto/internal/edwards25519/scalar_alias_test.go
@@ -0,0 +1,108 @@
+// Copyright (c) 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+import (
+ "testing"
+ "testing/quick"
+)
+
+func TestScalarAliasing(t *testing.T) {
+ checkAliasingOneArg := func(f func(v, x *Scalar) *Scalar, v, x Scalar) bool {
+ x1, v1 := x, x
+
+ // Calculate a reference f(x) without aliasing.
+ if out := f(&v, &x); out != &v || !isReduced(out.Bytes()) {
+ return false
+ }
+
+ // Test aliasing the argument and the receiver.
+ if out := f(&v1, &v1); out != &v1 || v1 != v || !isReduced(out.Bytes()) {
+ return false
+ }
+
+ // Ensure the arguments was not modified.
+ return x == x1
+ }
+
+ checkAliasingTwoArgs := func(f func(v, x, y *Scalar) *Scalar, v, x, y Scalar) bool {
+ x1, y1, v1 := x, y, Scalar{}
+
+ // Calculate a reference f(x, y) without aliasing.
+ if out := f(&v, &x, &y); out != &v || !isReduced(out.Bytes()) {
+ return false
+ }
+
+ // Test aliasing the first argument and the receiver.
+ v1 = x
+ if out := f(&v1, &v1, &y); out != &v1 || v1 != v || !isReduced(out.Bytes()) {
+ return false
+ }
+ // Test aliasing the second argument and the receiver.
+ v1 = y
+ if out := f(&v1, &x, &v1); out != &v1 || v1 != v || !isReduced(out.Bytes()) {
+ return false
+ }
+
+ // Calculate a reference f(x, x) without aliasing.
+ if out := f(&v, &x, &x); out != &v || !isReduced(out.Bytes()) {
+ return false
+ }
+
+ // Test aliasing the first argument and the receiver.
+ v1 = x
+ if out := f(&v1, &v1, &x); out != &v1 || v1 != v || !isReduced(out.Bytes()) {
+ return false
+ }
+ // Test aliasing the second argument and the receiver.
+ v1 = x
+ if out := f(&v1, &x, &v1); out != &v1 || v1 != v || !isReduced(out.Bytes()) {
+ return false
+ }
+ // Test aliasing both arguments and the receiver.
+ v1 = x
+ if out := f(&v1, &v1, &v1); out != &v1 || v1 != v || !isReduced(out.Bytes()) {
+ return false
+ }
+
+ // Ensure the arguments were not modified.
+ return x == x1 && y == y1
+ }
+
+ for name, f := range map[string]interface{}{
+ "Negate": func(v, x Scalar) bool {
+ return checkAliasingOneArg((*Scalar).Negate, v, x)
+ },
+ "Multiply": func(v, x, y Scalar) bool {
+ return checkAliasingTwoArgs((*Scalar).Multiply, v, x, y)
+ },
+ "Add": func(v, x, y Scalar) bool {
+ return checkAliasingTwoArgs((*Scalar).Add, v, x, y)
+ },
+ "Subtract": func(v, x, y Scalar) bool {
+ return checkAliasingTwoArgs((*Scalar).Subtract, v, x, y)
+ },
+ "MultiplyAdd1": func(v, x, y, fixed Scalar) bool {
+ return checkAliasingTwoArgs(func(v, x, y *Scalar) *Scalar {
+ return v.MultiplyAdd(&fixed, x, y)
+ }, v, x, y)
+ },
+ "MultiplyAdd2": func(v, x, y, fixed Scalar) bool {
+ return checkAliasingTwoArgs(func(v, x, y *Scalar) *Scalar {
+ return v.MultiplyAdd(x, &fixed, y)
+ }, v, x, y)
+ },
+ "MultiplyAdd3": func(v, x, y, fixed Scalar) bool {
+ return checkAliasingTwoArgs(func(v, x, y *Scalar) *Scalar {
+ return v.MultiplyAdd(x, y, &fixed)
+ }, v, x, y)
+ },
+ } {
+ err := quick.Check(f, &quick.Config{MaxCountScale: 1 << 5})
+ if err != nil {
+ t.Errorf("%v: %v", name, err)
+ }
+ }
+}
diff --git a/src/crypto/internal/edwards25519/scalar_fiat.go b/src/crypto/internal/edwards25519/scalar_fiat.go
new file mode 100644
index 0000000..2e5782b
--- /dev/null
+++ b/src/crypto/internal/edwards25519/scalar_fiat.go
@@ -0,0 +1,1147 @@
+// Code generated by Fiat Cryptography. DO NOT EDIT.
+//
+// Autogenerated: word_by_word_montgomery --lang Go --cmovznz-by-mul --relax-primitive-carry-to-bitwidth 32,64 --public-function-case camelCase --public-type-case camelCase --private-function-case camelCase --private-type-case camelCase --doc-text-before-function-name '' --doc-newline-before-package-declaration --doc-prepend-header 'Code generated by Fiat Cryptography. DO NOT EDIT.' --package-name edwards25519 Scalar 64 '2^252 + 27742317777372353535851937790883648493' mul add sub opp nonzero from_montgomery to_montgomery to_bytes from_bytes
+//
+// curve description: Scalar
+//
+// machine_wordsize = 64 (from "64")
+//
+// requested operations: mul, add, sub, opp, nonzero, from_montgomery, to_montgomery, to_bytes, from_bytes
+//
+// m = 0x1000000000000000000000000000000014def9dea2f79cd65812631a5cf5d3ed (from "2^252 + 27742317777372353535851937790883648493")
+//
+//
+//
+// NOTE: In addition to the bounds specified above each function, all
+//
+// functions synthesized for this Montgomery arithmetic require the
+//
+// input to be strictly less than the prime modulus (m), and also
+//
+// require the input to be in the unique saturated representation.
+//
+// All functions also ensure that these two properties are true of
+//
+// return values.
+//
+//
+//
+// Computed values:
+//
+// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192)
+//
+// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248)
+//
+// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in
+//
+// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256
+
+package edwards25519
+
+import "math/bits"
+
+type fiatScalarUint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927
+type fiatScalarInt1 int64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927
+
+// The type fiatScalarMontgomeryDomainFieldElement is a field element in the Montgomery domain.
+//
+// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+type fiatScalarMontgomeryDomainFieldElement [4]uint64
+
+// The type fiatScalarNonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain.
+//
+// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+type fiatScalarNonMontgomeryDomainFieldElement [4]uint64
+
+// fiatScalarCmovznzU64 is a single-word conditional move.
+//
+// Postconditions:
+//
+// out1 = (if arg1 = 0 then arg2 else arg3)
+//
+// Input Bounds:
+//
+// arg1: [0x0 ~> 0x1]
+// arg2: [0x0 ~> 0xffffffffffffffff]
+// arg3: [0x0 ~> 0xffffffffffffffff]
+//
+// Output Bounds:
+//
+// out1: [0x0 ~> 0xffffffffffffffff]
+func fiatScalarCmovznzU64(out1 *uint64, arg1 fiatScalarUint1, arg2 uint64, arg3 uint64) {
+ x1 := (uint64(arg1) * 0xffffffffffffffff)
+ x2 := ((x1 & arg3) | ((^x1) & arg2))
+ *out1 = x2
+}
+
+// fiatScalarMul multiplies two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func fiatScalarMul(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement, arg2 *fiatScalarMontgomeryDomainFieldElement) {
+ x1 := arg1[1]
+ x2 := arg1[2]
+ x3 := arg1[3]
+ x4 := arg1[0]
+ var x5 uint64
+ var x6 uint64
+ x6, x5 = bits.Mul64(x4, arg2[3])
+ var x7 uint64
+ var x8 uint64
+ x8, x7 = bits.Mul64(x4, arg2[2])
+ var x9 uint64
+ var x10 uint64
+ x10, x9 = bits.Mul64(x4, arg2[1])
+ var x11 uint64
+ var x12 uint64
+ x12, x11 = bits.Mul64(x4, arg2[0])
+ var x13 uint64
+ var x14 uint64
+ x13, x14 = bits.Add64(x12, x9, uint64(0x0))
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Add64(x10, x7, uint64(fiatScalarUint1(x14)))
+ var x17 uint64
+ var x18 uint64
+ x17, x18 = bits.Add64(x8, x5, uint64(fiatScalarUint1(x16)))
+ x19 := (uint64(fiatScalarUint1(x18)) + x6)
+ var x20 uint64
+ _, x20 = bits.Mul64(x11, 0xd2b51da312547e1b)
+ var x22 uint64
+ var x23 uint64
+ x23, x22 = bits.Mul64(x20, 0x1000000000000000)
+ var x24 uint64
+ var x25 uint64
+ x25, x24 = bits.Mul64(x20, 0x14def9dea2f79cd6)
+ var x26 uint64
+ var x27 uint64
+ x27, x26 = bits.Mul64(x20, 0x5812631a5cf5d3ed)
+ var x28 uint64
+ var x29 uint64
+ x28, x29 = bits.Add64(x27, x24, uint64(0x0))
+ x30 := (uint64(fiatScalarUint1(x29)) + x25)
+ var x32 uint64
+ _, x32 = bits.Add64(x11, x26, uint64(0x0))
+ var x33 uint64
+ var x34 uint64
+ x33, x34 = bits.Add64(x13, x28, uint64(fiatScalarUint1(x32)))
+ var x35 uint64
+ var x36 uint64
+ x35, x36 = bits.Add64(x15, x30, uint64(fiatScalarUint1(x34)))
+ var x37 uint64
+ var x38 uint64
+ x37, x38 = bits.Add64(x17, x22, uint64(fiatScalarUint1(x36)))
+ var x39 uint64
+ var x40 uint64
+ x39, x40 = bits.Add64(x19, x23, uint64(fiatScalarUint1(x38)))
+ var x41 uint64
+ var x42 uint64
+ x42, x41 = bits.Mul64(x1, arg2[3])
+ var x43 uint64
+ var x44 uint64
+ x44, x43 = bits.Mul64(x1, arg2[2])
+ var x45 uint64
+ var x46 uint64
+ x46, x45 = bits.Mul64(x1, arg2[1])
+ var x47 uint64
+ var x48 uint64
+ x48, x47 = bits.Mul64(x1, arg2[0])
+ var x49 uint64
+ var x50 uint64
+ x49, x50 = bits.Add64(x48, x45, uint64(0x0))
+ var x51 uint64
+ var x52 uint64
+ x51, x52 = bits.Add64(x46, x43, uint64(fiatScalarUint1(x50)))
+ var x53 uint64
+ var x54 uint64
+ x53, x54 = bits.Add64(x44, x41, uint64(fiatScalarUint1(x52)))
+ x55 := (uint64(fiatScalarUint1(x54)) + x42)
+ var x56 uint64
+ var x57 uint64
+ x56, x57 = bits.Add64(x33, x47, uint64(0x0))
+ var x58 uint64
+ var x59 uint64
+ x58, x59 = bits.Add64(x35, x49, uint64(fiatScalarUint1(x57)))
+ var x60 uint64
+ var x61 uint64
+ x60, x61 = bits.Add64(x37, x51, uint64(fiatScalarUint1(x59)))
+ var x62 uint64
+ var x63 uint64
+ x62, x63 = bits.Add64(x39, x53, uint64(fiatScalarUint1(x61)))
+ var x64 uint64
+ var x65 uint64
+ x64, x65 = bits.Add64(uint64(fiatScalarUint1(x40)), x55, uint64(fiatScalarUint1(x63)))
+ var x66 uint64
+ _, x66 = bits.Mul64(x56, 0xd2b51da312547e1b)
+ var x68 uint64
+ var x69 uint64
+ x69, x68 = bits.Mul64(x66, 0x1000000000000000)
+ var x70 uint64
+ var x71 uint64
+ x71, x70 = bits.Mul64(x66, 0x14def9dea2f79cd6)
+ var x72 uint64
+ var x73 uint64
+ x73, x72 = bits.Mul64(x66, 0x5812631a5cf5d3ed)
+ var x74 uint64
+ var x75 uint64
+ x74, x75 = bits.Add64(x73, x70, uint64(0x0))
+ x76 := (uint64(fiatScalarUint1(x75)) + x71)
+ var x78 uint64
+ _, x78 = bits.Add64(x56, x72, uint64(0x0))
+ var x79 uint64
+ var x80 uint64
+ x79, x80 = bits.Add64(x58, x74, uint64(fiatScalarUint1(x78)))
+ var x81 uint64
+ var x82 uint64
+ x81, x82 = bits.Add64(x60, x76, uint64(fiatScalarUint1(x80)))
+ var x83 uint64
+ var x84 uint64
+ x83, x84 = bits.Add64(x62, x68, uint64(fiatScalarUint1(x82)))
+ var x85 uint64
+ var x86 uint64
+ x85, x86 = bits.Add64(x64, x69, uint64(fiatScalarUint1(x84)))
+ x87 := (uint64(fiatScalarUint1(x86)) + uint64(fiatScalarUint1(x65)))
+ var x88 uint64
+ var x89 uint64
+ x89, x88 = bits.Mul64(x2, arg2[3])
+ var x90 uint64
+ var x91 uint64
+ x91, x90 = bits.Mul64(x2, arg2[2])
+ var x92 uint64
+ var x93 uint64
+ x93, x92 = bits.Mul64(x2, arg2[1])
+ var x94 uint64
+ var x95 uint64
+ x95, x94 = bits.Mul64(x2, arg2[0])
+ var x96 uint64
+ var x97 uint64
+ x96, x97 = bits.Add64(x95, x92, uint64(0x0))
+ var x98 uint64
+ var x99 uint64
+ x98, x99 = bits.Add64(x93, x90, uint64(fiatScalarUint1(x97)))
+ var x100 uint64
+ var x101 uint64
+ x100, x101 = bits.Add64(x91, x88, uint64(fiatScalarUint1(x99)))
+ x102 := (uint64(fiatScalarUint1(x101)) + x89)
+ var x103 uint64
+ var x104 uint64
+ x103, x104 = bits.Add64(x79, x94, uint64(0x0))
+ var x105 uint64
+ var x106 uint64
+ x105, x106 = bits.Add64(x81, x96, uint64(fiatScalarUint1(x104)))
+ var x107 uint64
+ var x108 uint64
+ x107, x108 = bits.Add64(x83, x98, uint64(fiatScalarUint1(x106)))
+ var x109 uint64
+ var x110 uint64
+ x109, x110 = bits.Add64(x85, x100, uint64(fiatScalarUint1(x108)))
+ var x111 uint64
+ var x112 uint64
+ x111, x112 = bits.Add64(x87, x102, uint64(fiatScalarUint1(x110)))
+ var x113 uint64
+ _, x113 = bits.Mul64(x103, 0xd2b51da312547e1b)
+ var x115 uint64
+ var x116 uint64
+ x116, x115 = bits.Mul64(x113, 0x1000000000000000)
+ var x117 uint64
+ var x118 uint64
+ x118, x117 = bits.Mul64(x113, 0x14def9dea2f79cd6)
+ var x119 uint64
+ var x120 uint64
+ x120, x119 = bits.Mul64(x113, 0x5812631a5cf5d3ed)
+ var x121 uint64
+ var x122 uint64
+ x121, x122 = bits.Add64(x120, x117, uint64(0x0))
+ x123 := (uint64(fiatScalarUint1(x122)) + x118)
+ var x125 uint64
+ _, x125 = bits.Add64(x103, x119, uint64(0x0))
+ var x126 uint64
+ var x127 uint64
+ x126, x127 = bits.Add64(x105, x121, uint64(fiatScalarUint1(x125)))
+ var x128 uint64
+ var x129 uint64
+ x128, x129 = bits.Add64(x107, x123, uint64(fiatScalarUint1(x127)))
+ var x130 uint64
+ var x131 uint64
+ x130, x131 = bits.Add64(x109, x115, uint64(fiatScalarUint1(x129)))
+ var x132 uint64
+ var x133 uint64
+ x132, x133 = bits.Add64(x111, x116, uint64(fiatScalarUint1(x131)))
+ x134 := (uint64(fiatScalarUint1(x133)) + uint64(fiatScalarUint1(x112)))
+ var x135 uint64
+ var x136 uint64
+ x136, x135 = bits.Mul64(x3, arg2[3])
+ var x137 uint64
+ var x138 uint64
+ x138, x137 = bits.Mul64(x3, arg2[2])
+ var x139 uint64
+ var x140 uint64
+ x140, x139 = bits.Mul64(x3, arg2[1])
+ var x141 uint64
+ var x142 uint64
+ x142, x141 = bits.Mul64(x3, arg2[0])
+ var x143 uint64
+ var x144 uint64
+ x143, x144 = bits.Add64(x142, x139, uint64(0x0))
+ var x145 uint64
+ var x146 uint64
+ x145, x146 = bits.Add64(x140, x137, uint64(fiatScalarUint1(x144)))
+ var x147 uint64
+ var x148 uint64
+ x147, x148 = bits.Add64(x138, x135, uint64(fiatScalarUint1(x146)))
+ x149 := (uint64(fiatScalarUint1(x148)) + x136)
+ var x150 uint64
+ var x151 uint64
+ x150, x151 = bits.Add64(x126, x141, uint64(0x0))
+ var x152 uint64
+ var x153 uint64
+ x152, x153 = bits.Add64(x128, x143, uint64(fiatScalarUint1(x151)))
+ var x154 uint64
+ var x155 uint64
+ x154, x155 = bits.Add64(x130, x145, uint64(fiatScalarUint1(x153)))
+ var x156 uint64
+ var x157 uint64
+ x156, x157 = bits.Add64(x132, x147, uint64(fiatScalarUint1(x155)))
+ var x158 uint64
+ var x159 uint64
+ x158, x159 = bits.Add64(x134, x149, uint64(fiatScalarUint1(x157)))
+ var x160 uint64
+ _, x160 = bits.Mul64(x150, 0xd2b51da312547e1b)
+ var x162 uint64
+ var x163 uint64
+ x163, x162 = bits.Mul64(x160, 0x1000000000000000)
+ var x164 uint64
+ var x165 uint64
+ x165, x164 = bits.Mul64(x160, 0x14def9dea2f79cd6)
+ var x166 uint64
+ var x167 uint64
+ x167, x166 = bits.Mul64(x160, 0x5812631a5cf5d3ed)
+ var x168 uint64
+ var x169 uint64
+ x168, x169 = bits.Add64(x167, x164, uint64(0x0))
+ x170 := (uint64(fiatScalarUint1(x169)) + x165)
+ var x172 uint64
+ _, x172 = bits.Add64(x150, x166, uint64(0x0))
+ var x173 uint64
+ var x174 uint64
+ x173, x174 = bits.Add64(x152, x168, uint64(fiatScalarUint1(x172)))
+ var x175 uint64
+ var x176 uint64
+ x175, x176 = bits.Add64(x154, x170, uint64(fiatScalarUint1(x174)))
+ var x177 uint64
+ var x178 uint64
+ x177, x178 = bits.Add64(x156, x162, uint64(fiatScalarUint1(x176)))
+ var x179 uint64
+ var x180 uint64
+ x179, x180 = bits.Add64(x158, x163, uint64(fiatScalarUint1(x178)))
+ x181 := (uint64(fiatScalarUint1(x180)) + uint64(fiatScalarUint1(x159)))
+ var x182 uint64
+ var x183 uint64
+ x182, x183 = bits.Sub64(x173, 0x5812631a5cf5d3ed, uint64(0x0))
+ var x184 uint64
+ var x185 uint64
+ x184, x185 = bits.Sub64(x175, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x183)))
+ var x186 uint64
+ var x187 uint64
+ x186, x187 = bits.Sub64(x177, uint64(0x0), uint64(fiatScalarUint1(x185)))
+ var x188 uint64
+ var x189 uint64
+ x188, x189 = bits.Sub64(x179, 0x1000000000000000, uint64(fiatScalarUint1(x187)))
+ var x191 uint64
+ _, x191 = bits.Sub64(x181, uint64(0x0), uint64(fiatScalarUint1(x189)))
+ var x192 uint64
+ fiatScalarCmovznzU64(&x192, fiatScalarUint1(x191), x182, x173)
+ var x193 uint64
+ fiatScalarCmovznzU64(&x193, fiatScalarUint1(x191), x184, x175)
+ var x194 uint64
+ fiatScalarCmovznzU64(&x194, fiatScalarUint1(x191), x186, x177)
+ var x195 uint64
+ fiatScalarCmovznzU64(&x195, fiatScalarUint1(x191), x188, x179)
+ out1[0] = x192
+ out1[1] = x193
+ out1[2] = x194
+ out1[3] = x195
+}
+
+// fiatScalarAdd adds two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func fiatScalarAdd(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement, arg2 *fiatScalarMontgomeryDomainFieldElement) {
+ var x1 uint64
+ var x2 uint64
+ x1, x2 = bits.Add64(arg1[0], arg2[0], uint64(0x0))
+ var x3 uint64
+ var x4 uint64
+ x3, x4 = bits.Add64(arg1[1], arg2[1], uint64(fiatScalarUint1(x2)))
+ var x5 uint64
+ var x6 uint64
+ x5, x6 = bits.Add64(arg1[2], arg2[2], uint64(fiatScalarUint1(x4)))
+ var x7 uint64
+ var x8 uint64
+ x7, x8 = bits.Add64(arg1[3], arg2[3], uint64(fiatScalarUint1(x6)))
+ var x9 uint64
+ var x10 uint64
+ x9, x10 = bits.Sub64(x1, 0x5812631a5cf5d3ed, uint64(0x0))
+ var x11 uint64
+ var x12 uint64
+ x11, x12 = bits.Sub64(x3, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x10)))
+ var x13 uint64
+ var x14 uint64
+ x13, x14 = bits.Sub64(x5, uint64(0x0), uint64(fiatScalarUint1(x12)))
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Sub64(x7, 0x1000000000000000, uint64(fiatScalarUint1(x14)))
+ var x18 uint64
+ _, x18 = bits.Sub64(uint64(fiatScalarUint1(x8)), uint64(0x0), uint64(fiatScalarUint1(x16)))
+ var x19 uint64
+ fiatScalarCmovznzU64(&x19, fiatScalarUint1(x18), x9, x1)
+ var x20 uint64
+ fiatScalarCmovznzU64(&x20, fiatScalarUint1(x18), x11, x3)
+ var x21 uint64
+ fiatScalarCmovznzU64(&x21, fiatScalarUint1(x18), x13, x5)
+ var x22 uint64
+ fiatScalarCmovznzU64(&x22, fiatScalarUint1(x18), x15, x7)
+ out1[0] = x19
+ out1[1] = x20
+ out1[2] = x21
+ out1[3] = x22
+}
+
+// fiatScalarSub subtracts two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func fiatScalarSub(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement, arg2 *fiatScalarMontgomeryDomainFieldElement) {
+ var x1 uint64
+ var x2 uint64
+ x1, x2 = bits.Sub64(arg1[0], arg2[0], uint64(0x0))
+ var x3 uint64
+ var x4 uint64
+ x3, x4 = bits.Sub64(arg1[1], arg2[1], uint64(fiatScalarUint1(x2)))
+ var x5 uint64
+ var x6 uint64
+ x5, x6 = bits.Sub64(arg1[2], arg2[2], uint64(fiatScalarUint1(x4)))
+ var x7 uint64
+ var x8 uint64
+ x7, x8 = bits.Sub64(arg1[3], arg2[3], uint64(fiatScalarUint1(x6)))
+ var x9 uint64
+ fiatScalarCmovznzU64(&x9, fiatScalarUint1(x8), uint64(0x0), 0xffffffffffffffff)
+ var x10 uint64
+ var x11 uint64
+ x10, x11 = bits.Add64(x1, (x9 & 0x5812631a5cf5d3ed), uint64(0x0))
+ var x12 uint64
+ var x13 uint64
+ x12, x13 = bits.Add64(x3, (x9 & 0x14def9dea2f79cd6), uint64(fiatScalarUint1(x11)))
+ var x14 uint64
+ var x15 uint64
+ x14, x15 = bits.Add64(x5, uint64(0x0), uint64(fiatScalarUint1(x13)))
+ var x16 uint64
+ x16, _ = bits.Add64(x7, (x9 & 0x1000000000000000), uint64(fiatScalarUint1(x15)))
+ out1[0] = x10
+ out1[1] = x12
+ out1[2] = x14
+ out1[3] = x16
+}
+
+// fiatScalarOpp negates a field element in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = -eval (from_montgomery arg1) mod m
+// 0 ≤ eval out1 < m
+func fiatScalarOpp(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement) {
+ var x1 uint64
+ var x2 uint64
+ x1, x2 = bits.Sub64(uint64(0x0), arg1[0], uint64(0x0))
+ var x3 uint64
+ var x4 uint64
+ x3, x4 = bits.Sub64(uint64(0x0), arg1[1], uint64(fiatScalarUint1(x2)))
+ var x5 uint64
+ var x6 uint64
+ x5, x6 = bits.Sub64(uint64(0x0), arg1[2], uint64(fiatScalarUint1(x4)))
+ var x7 uint64
+ var x8 uint64
+ x7, x8 = bits.Sub64(uint64(0x0), arg1[3], uint64(fiatScalarUint1(x6)))
+ var x9 uint64
+ fiatScalarCmovznzU64(&x9, fiatScalarUint1(x8), uint64(0x0), 0xffffffffffffffff)
+ var x10 uint64
+ var x11 uint64
+ x10, x11 = bits.Add64(x1, (x9 & 0x5812631a5cf5d3ed), uint64(0x0))
+ var x12 uint64
+ var x13 uint64
+ x12, x13 = bits.Add64(x3, (x9 & 0x14def9dea2f79cd6), uint64(fiatScalarUint1(x11)))
+ var x14 uint64
+ var x15 uint64
+ x14, x15 = bits.Add64(x5, uint64(0x0), uint64(fiatScalarUint1(x13)))
+ var x16 uint64
+ x16, _ = bits.Add64(x7, (x9 & 0x1000000000000000), uint64(fiatScalarUint1(x15)))
+ out1[0] = x10
+ out1[1] = x12
+ out1[2] = x14
+ out1[3] = x16
+}
+
+// fiatScalarNonzero outputs a single non-zero word if the input is non-zero and zero otherwise.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// out1 = 0 ↔ eval (from_montgomery arg1) mod m = 0
+//
+// Input Bounds:
+//
+// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+//
+// Output Bounds:
+//
+// out1: [0x0 ~> 0xffffffffffffffff]
+func fiatScalarNonzero(out1 *uint64, arg1 *[4]uint64) {
+ x1 := (arg1[0] | (arg1[1] | (arg1[2] | arg1[3])))
+ *out1 = x1
+}
+
+// fiatScalarFromMontgomery translates a field element out of the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m
+// 0 ≤ eval out1 < m
+func fiatScalarFromMontgomery(out1 *fiatScalarNonMontgomeryDomainFieldElement, arg1 *fiatScalarMontgomeryDomainFieldElement) {
+ x1 := arg1[0]
+ var x2 uint64
+ _, x2 = bits.Mul64(x1, 0xd2b51da312547e1b)
+ var x4 uint64
+ var x5 uint64
+ x5, x4 = bits.Mul64(x2, 0x1000000000000000)
+ var x6 uint64
+ var x7 uint64
+ x7, x6 = bits.Mul64(x2, 0x14def9dea2f79cd6)
+ var x8 uint64
+ var x9 uint64
+ x9, x8 = bits.Mul64(x2, 0x5812631a5cf5d3ed)
+ var x10 uint64
+ var x11 uint64
+ x10, x11 = bits.Add64(x9, x6, uint64(0x0))
+ var x13 uint64
+ _, x13 = bits.Add64(x1, x8, uint64(0x0))
+ var x14 uint64
+ var x15 uint64
+ x14, x15 = bits.Add64(uint64(0x0), x10, uint64(fiatScalarUint1(x13)))
+ var x16 uint64
+ var x17 uint64
+ x16, x17 = bits.Add64(x14, arg1[1], uint64(0x0))
+ var x18 uint64
+ _, x18 = bits.Mul64(x16, 0xd2b51da312547e1b)
+ var x20 uint64
+ var x21 uint64
+ x21, x20 = bits.Mul64(x18, 0x1000000000000000)
+ var x22 uint64
+ var x23 uint64
+ x23, x22 = bits.Mul64(x18, 0x14def9dea2f79cd6)
+ var x24 uint64
+ var x25 uint64
+ x25, x24 = bits.Mul64(x18, 0x5812631a5cf5d3ed)
+ var x26 uint64
+ var x27 uint64
+ x26, x27 = bits.Add64(x25, x22, uint64(0x0))
+ var x29 uint64
+ _, x29 = bits.Add64(x16, x24, uint64(0x0))
+ var x30 uint64
+ var x31 uint64
+ x30, x31 = bits.Add64((uint64(fiatScalarUint1(x17)) + (uint64(fiatScalarUint1(x15)) + (uint64(fiatScalarUint1(x11)) + x7))), x26, uint64(fiatScalarUint1(x29)))
+ var x32 uint64
+ var x33 uint64
+ x32, x33 = bits.Add64(x4, (uint64(fiatScalarUint1(x27)) + x23), uint64(fiatScalarUint1(x31)))
+ var x34 uint64
+ var x35 uint64
+ x34, x35 = bits.Add64(x5, x20, uint64(fiatScalarUint1(x33)))
+ var x36 uint64
+ var x37 uint64
+ x36, x37 = bits.Add64(x30, arg1[2], uint64(0x0))
+ var x38 uint64
+ var x39 uint64
+ x38, x39 = bits.Add64(x32, uint64(0x0), uint64(fiatScalarUint1(x37)))
+ var x40 uint64
+ var x41 uint64
+ x40, x41 = bits.Add64(x34, uint64(0x0), uint64(fiatScalarUint1(x39)))
+ var x42 uint64
+ _, x42 = bits.Mul64(x36, 0xd2b51da312547e1b)
+ var x44 uint64
+ var x45 uint64
+ x45, x44 = bits.Mul64(x42, 0x1000000000000000)
+ var x46 uint64
+ var x47 uint64
+ x47, x46 = bits.Mul64(x42, 0x14def9dea2f79cd6)
+ var x48 uint64
+ var x49 uint64
+ x49, x48 = bits.Mul64(x42, 0x5812631a5cf5d3ed)
+ var x50 uint64
+ var x51 uint64
+ x50, x51 = bits.Add64(x49, x46, uint64(0x0))
+ var x53 uint64
+ _, x53 = bits.Add64(x36, x48, uint64(0x0))
+ var x54 uint64
+ var x55 uint64
+ x54, x55 = bits.Add64(x38, x50, uint64(fiatScalarUint1(x53)))
+ var x56 uint64
+ var x57 uint64
+ x56, x57 = bits.Add64(x40, (uint64(fiatScalarUint1(x51)) + x47), uint64(fiatScalarUint1(x55)))
+ var x58 uint64
+ var x59 uint64
+ x58, x59 = bits.Add64((uint64(fiatScalarUint1(x41)) + (uint64(fiatScalarUint1(x35)) + x21)), x44, uint64(fiatScalarUint1(x57)))
+ var x60 uint64
+ var x61 uint64
+ x60, x61 = bits.Add64(x54, arg1[3], uint64(0x0))
+ var x62 uint64
+ var x63 uint64
+ x62, x63 = bits.Add64(x56, uint64(0x0), uint64(fiatScalarUint1(x61)))
+ var x64 uint64
+ var x65 uint64
+ x64, x65 = bits.Add64(x58, uint64(0x0), uint64(fiatScalarUint1(x63)))
+ var x66 uint64
+ _, x66 = bits.Mul64(x60, 0xd2b51da312547e1b)
+ var x68 uint64
+ var x69 uint64
+ x69, x68 = bits.Mul64(x66, 0x1000000000000000)
+ var x70 uint64
+ var x71 uint64
+ x71, x70 = bits.Mul64(x66, 0x14def9dea2f79cd6)
+ var x72 uint64
+ var x73 uint64
+ x73, x72 = bits.Mul64(x66, 0x5812631a5cf5d3ed)
+ var x74 uint64
+ var x75 uint64
+ x74, x75 = bits.Add64(x73, x70, uint64(0x0))
+ var x77 uint64
+ _, x77 = bits.Add64(x60, x72, uint64(0x0))
+ var x78 uint64
+ var x79 uint64
+ x78, x79 = bits.Add64(x62, x74, uint64(fiatScalarUint1(x77)))
+ var x80 uint64
+ var x81 uint64
+ x80, x81 = bits.Add64(x64, (uint64(fiatScalarUint1(x75)) + x71), uint64(fiatScalarUint1(x79)))
+ var x82 uint64
+ var x83 uint64
+ x82, x83 = bits.Add64((uint64(fiatScalarUint1(x65)) + (uint64(fiatScalarUint1(x59)) + x45)), x68, uint64(fiatScalarUint1(x81)))
+ x84 := (uint64(fiatScalarUint1(x83)) + x69)
+ var x85 uint64
+ var x86 uint64
+ x85, x86 = bits.Sub64(x78, 0x5812631a5cf5d3ed, uint64(0x0))
+ var x87 uint64
+ var x88 uint64
+ x87, x88 = bits.Sub64(x80, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x86)))
+ var x89 uint64
+ var x90 uint64
+ x89, x90 = bits.Sub64(x82, uint64(0x0), uint64(fiatScalarUint1(x88)))
+ var x91 uint64
+ var x92 uint64
+ x91, x92 = bits.Sub64(x84, 0x1000000000000000, uint64(fiatScalarUint1(x90)))
+ var x94 uint64
+ _, x94 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(fiatScalarUint1(x92)))
+ var x95 uint64
+ fiatScalarCmovznzU64(&x95, fiatScalarUint1(x94), x85, x78)
+ var x96 uint64
+ fiatScalarCmovznzU64(&x96, fiatScalarUint1(x94), x87, x80)
+ var x97 uint64
+ fiatScalarCmovznzU64(&x97, fiatScalarUint1(x94), x89, x82)
+ var x98 uint64
+ fiatScalarCmovznzU64(&x98, fiatScalarUint1(x94), x91, x84)
+ out1[0] = x95
+ out1[1] = x96
+ out1[2] = x97
+ out1[3] = x98
+}
+
+// fiatScalarToMontgomery translates a field element into the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = eval arg1 mod m
+// 0 ≤ eval out1 < m
+func fiatScalarToMontgomery(out1 *fiatScalarMontgomeryDomainFieldElement, arg1 *fiatScalarNonMontgomeryDomainFieldElement) {
+ x1 := arg1[1]
+ x2 := arg1[2]
+ x3 := arg1[3]
+ x4 := arg1[0]
+ var x5 uint64
+ var x6 uint64
+ x6, x5 = bits.Mul64(x4, 0x399411b7c309a3d)
+ var x7 uint64
+ var x8 uint64
+ x8, x7 = bits.Mul64(x4, 0xceec73d217f5be65)
+ var x9 uint64
+ var x10 uint64
+ x10, x9 = bits.Mul64(x4, 0xd00e1ba768859347)
+ var x11 uint64
+ var x12 uint64
+ x12, x11 = bits.Mul64(x4, 0xa40611e3449c0f01)
+ var x13 uint64
+ var x14 uint64
+ x13, x14 = bits.Add64(x12, x9, uint64(0x0))
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Add64(x10, x7, uint64(fiatScalarUint1(x14)))
+ var x17 uint64
+ var x18 uint64
+ x17, x18 = bits.Add64(x8, x5, uint64(fiatScalarUint1(x16)))
+ var x19 uint64
+ _, x19 = bits.Mul64(x11, 0xd2b51da312547e1b)
+ var x21 uint64
+ var x22 uint64
+ x22, x21 = bits.Mul64(x19, 0x1000000000000000)
+ var x23 uint64
+ var x24 uint64
+ x24, x23 = bits.Mul64(x19, 0x14def9dea2f79cd6)
+ var x25 uint64
+ var x26 uint64
+ x26, x25 = bits.Mul64(x19, 0x5812631a5cf5d3ed)
+ var x27 uint64
+ var x28 uint64
+ x27, x28 = bits.Add64(x26, x23, uint64(0x0))
+ var x30 uint64
+ _, x30 = bits.Add64(x11, x25, uint64(0x0))
+ var x31 uint64
+ var x32 uint64
+ x31, x32 = bits.Add64(x13, x27, uint64(fiatScalarUint1(x30)))
+ var x33 uint64
+ var x34 uint64
+ x33, x34 = bits.Add64(x15, (uint64(fiatScalarUint1(x28)) + x24), uint64(fiatScalarUint1(x32)))
+ var x35 uint64
+ var x36 uint64
+ x35, x36 = bits.Add64(x17, x21, uint64(fiatScalarUint1(x34)))
+ var x37 uint64
+ var x38 uint64
+ x38, x37 = bits.Mul64(x1, 0x399411b7c309a3d)
+ var x39 uint64
+ var x40 uint64
+ x40, x39 = bits.Mul64(x1, 0xceec73d217f5be65)
+ var x41 uint64
+ var x42 uint64
+ x42, x41 = bits.Mul64(x1, 0xd00e1ba768859347)
+ var x43 uint64
+ var x44 uint64
+ x44, x43 = bits.Mul64(x1, 0xa40611e3449c0f01)
+ var x45 uint64
+ var x46 uint64
+ x45, x46 = bits.Add64(x44, x41, uint64(0x0))
+ var x47 uint64
+ var x48 uint64
+ x47, x48 = bits.Add64(x42, x39, uint64(fiatScalarUint1(x46)))
+ var x49 uint64
+ var x50 uint64
+ x49, x50 = bits.Add64(x40, x37, uint64(fiatScalarUint1(x48)))
+ var x51 uint64
+ var x52 uint64
+ x51, x52 = bits.Add64(x31, x43, uint64(0x0))
+ var x53 uint64
+ var x54 uint64
+ x53, x54 = bits.Add64(x33, x45, uint64(fiatScalarUint1(x52)))
+ var x55 uint64
+ var x56 uint64
+ x55, x56 = bits.Add64(x35, x47, uint64(fiatScalarUint1(x54)))
+ var x57 uint64
+ var x58 uint64
+ x57, x58 = bits.Add64(((uint64(fiatScalarUint1(x36)) + (uint64(fiatScalarUint1(x18)) + x6)) + x22), x49, uint64(fiatScalarUint1(x56)))
+ var x59 uint64
+ _, x59 = bits.Mul64(x51, 0xd2b51da312547e1b)
+ var x61 uint64
+ var x62 uint64
+ x62, x61 = bits.Mul64(x59, 0x1000000000000000)
+ var x63 uint64
+ var x64 uint64
+ x64, x63 = bits.Mul64(x59, 0x14def9dea2f79cd6)
+ var x65 uint64
+ var x66 uint64
+ x66, x65 = bits.Mul64(x59, 0x5812631a5cf5d3ed)
+ var x67 uint64
+ var x68 uint64
+ x67, x68 = bits.Add64(x66, x63, uint64(0x0))
+ var x70 uint64
+ _, x70 = bits.Add64(x51, x65, uint64(0x0))
+ var x71 uint64
+ var x72 uint64
+ x71, x72 = bits.Add64(x53, x67, uint64(fiatScalarUint1(x70)))
+ var x73 uint64
+ var x74 uint64
+ x73, x74 = bits.Add64(x55, (uint64(fiatScalarUint1(x68)) + x64), uint64(fiatScalarUint1(x72)))
+ var x75 uint64
+ var x76 uint64
+ x75, x76 = bits.Add64(x57, x61, uint64(fiatScalarUint1(x74)))
+ var x77 uint64
+ var x78 uint64
+ x78, x77 = bits.Mul64(x2, 0x399411b7c309a3d)
+ var x79 uint64
+ var x80 uint64
+ x80, x79 = bits.Mul64(x2, 0xceec73d217f5be65)
+ var x81 uint64
+ var x82 uint64
+ x82, x81 = bits.Mul64(x2, 0xd00e1ba768859347)
+ var x83 uint64
+ var x84 uint64
+ x84, x83 = bits.Mul64(x2, 0xa40611e3449c0f01)
+ var x85 uint64
+ var x86 uint64
+ x85, x86 = bits.Add64(x84, x81, uint64(0x0))
+ var x87 uint64
+ var x88 uint64
+ x87, x88 = bits.Add64(x82, x79, uint64(fiatScalarUint1(x86)))
+ var x89 uint64
+ var x90 uint64
+ x89, x90 = bits.Add64(x80, x77, uint64(fiatScalarUint1(x88)))
+ var x91 uint64
+ var x92 uint64
+ x91, x92 = bits.Add64(x71, x83, uint64(0x0))
+ var x93 uint64
+ var x94 uint64
+ x93, x94 = bits.Add64(x73, x85, uint64(fiatScalarUint1(x92)))
+ var x95 uint64
+ var x96 uint64
+ x95, x96 = bits.Add64(x75, x87, uint64(fiatScalarUint1(x94)))
+ var x97 uint64
+ var x98 uint64
+ x97, x98 = bits.Add64(((uint64(fiatScalarUint1(x76)) + (uint64(fiatScalarUint1(x58)) + (uint64(fiatScalarUint1(x50)) + x38))) + x62), x89, uint64(fiatScalarUint1(x96)))
+ var x99 uint64
+ _, x99 = bits.Mul64(x91, 0xd2b51da312547e1b)
+ var x101 uint64
+ var x102 uint64
+ x102, x101 = bits.Mul64(x99, 0x1000000000000000)
+ var x103 uint64
+ var x104 uint64
+ x104, x103 = bits.Mul64(x99, 0x14def9dea2f79cd6)
+ var x105 uint64
+ var x106 uint64
+ x106, x105 = bits.Mul64(x99, 0x5812631a5cf5d3ed)
+ var x107 uint64
+ var x108 uint64
+ x107, x108 = bits.Add64(x106, x103, uint64(0x0))
+ var x110 uint64
+ _, x110 = bits.Add64(x91, x105, uint64(0x0))
+ var x111 uint64
+ var x112 uint64
+ x111, x112 = bits.Add64(x93, x107, uint64(fiatScalarUint1(x110)))
+ var x113 uint64
+ var x114 uint64
+ x113, x114 = bits.Add64(x95, (uint64(fiatScalarUint1(x108)) + x104), uint64(fiatScalarUint1(x112)))
+ var x115 uint64
+ var x116 uint64
+ x115, x116 = bits.Add64(x97, x101, uint64(fiatScalarUint1(x114)))
+ var x117 uint64
+ var x118 uint64
+ x118, x117 = bits.Mul64(x3, 0x399411b7c309a3d)
+ var x119 uint64
+ var x120 uint64
+ x120, x119 = bits.Mul64(x3, 0xceec73d217f5be65)
+ var x121 uint64
+ var x122 uint64
+ x122, x121 = bits.Mul64(x3, 0xd00e1ba768859347)
+ var x123 uint64
+ var x124 uint64
+ x124, x123 = bits.Mul64(x3, 0xa40611e3449c0f01)
+ var x125 uint64
+ var x126 uint64
+ x125, x126 = bits.Add64(x124, x121, uint64(0x0))
+ var x127 uint64
+ var x128 uint64
+ x127, x128 = bits.Add64(x122, x119, uint64(fiatScalarUint1(x126)))
+ var x129 uint64
+ var x130 uint64
+ x129, x130 = bits.Add64(x120, x117, uint64(fiatScalarUint1(x128)))
+ var x131 uint64
+ var x132 uint64
+ x131, x132 = bits.Add64(x111, x123, uint64(0x0))
+ var x133 uint64
+ var x134 uint64
+ x133, x134 = bits.Add64(x113, x125, uint64(fiatScalarUint1(x132)))
+ var x135 uint64
+ var x136 uint64
+ x135, x136 = bits.Add64(x115, x127, uint64(fiatScalarUint1(x134)))
+ var x137 uint64
+ var x138 uint64
+ x137, x138 = bits.Add64(((uint64(fiatScalarUint1(x116)) + (uint64(fiatScalarUint1(x98)) + (uint64(fiatScalarUint1(x90)) + x78))) + x102), x129, uint64(fiatScalarUint1(x136)))
+ var x139 uint64
+ _, x139 = bits.Mul64(x131, 0xd2b51da312547e1b)
+ var x141 uint64
+ var x142 uint64
+ x142, x141 = bits.Mul64(x139, 0x1000000000000000)
+ var x143 uint64
+ var x144 uint64
+ x144, x143 = bits.Mul64(x139, 0x14def9dea2f79cd6)
+ var x145 uint64
+ var x146 uint64
+ x146, x145 = bits.Mul64(x139, 0x5812631a5cf5d3ed)
+ var x147 uint64
+ var x148 uint64
+ x147, x148 = bits.Add64(x146, x143, uint64(0x0))
+ var x150 uint64
+ _, x150 = bits.Add64(x131, x145, uint64(0x0))
+ var x151 uint64
+ var x152 uint64
+ x151, x152 = bits.Add64(x133, x147, uint64(fiatScalarUint1(x150)))
+ var x153 uint64
+ var x154 uint64
+ x153, x154 = bits.Add64(x135, (uint64(fiatScalarUint1(x148)) + x144), uint64(fiatScalarUint1(x152)))
+ var x155 uint64
+ var x156 uint64
+ x155, x156 = bits.Add64(x137, x141, uint64(fiatScalarUint1(x154)))
+ x157 := ((uint64(fiatScalarUint1(x156)) + (uint64(fiatScalarUint1(x138)) + (uint64(fiatScalarUint1(x130)) + x118))) + x142)
+ var x158 uint64
+ var x159 uint64
+ x158, x159 = bits.Sub64(x151, 0x5812631a5cf5d3ed, uint64(0x0))
+ var x160 uint64
+ var x161 uint64
+ x160, x161 = bits.Sub64(x153, 0x14def9dea2f79cd6, uint64(fiatScalarUint1(x159)))
+ var x162 uint64
+ var x163 uint64
+ x162, x163 = bits.Sub64(x155, uint64(0x0), uint64(fiatScalarUint1(x161)))
+ var x164 uint64
+ var x165 uint64
+ x164, x165 = bits.Sub64(x157, 0x1000000000000000, uint64(fiatScalarUint1(x163)))
+ var x167 uint64
+ _, x167 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(fiatScalarUint1(x165)))
+ var x168 uint64
+ fiatScalarCmovznzU64(&x168, fiatScalarUint1(x167), x158, x151)
+ var x169 uint64
+ fiatScalarCmovznzU64(&x169, fiatScalarUint1(x167), x160, x153)
+ var x170 uint64
+ fiatScalarCmovznzU64(&x170, fiatScalarUint1(x167), x162, x155)
+ var x171 uint64
+ fiatScalarCmovznzU64(&x171, fiatScalarUint1(x167), x164, x157)
+ out1[0] = x168
+ out1[1] = x169
+ out1[2] = x170
+ out1[3] = x171
+}
+
+// fiatScalarToBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..31]
+//
+// Input Bounds:
+//
+// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0x1fffffffffffffff]]
+//
+// Output Bounds:
+//
+// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x1f]]
+func fiatScalarToBytes(out1 *[32]uint8, arg1 *[4]uint64) {
+ x1 := arg1[3]
+ x2 := arg1[2]
+ x3 := arg1[1]
+ x4 := arg1[0]
+ x5 := (uint8(x4) & 0xff)
+ x6 := (x4 >> 8)
+ x7 := (uint8(x6) & 0xff)
+ x8 := (x6 >> 8)
+ x9 := (uint8(x8) & 0xff)
+ x10 := (x8 >> 8)
+ x11 := (uint8(x10) & 0xff)
+ x12 := (x10 >> 8)
+ x13 := (uint8(x12) & 0xff)
+ x14 := (x12 >> 8)
+ x15 := (uint8(x14) & 0xff)
+ x16 := (x14 >> 8)
+ x17 := (uint8(x16) & 0xff)
+ x18 := uint8((x16 >> 8))
+ x19 := (uint8(x3) & 0xff)
+ x20 := (x3 >> 8)
+ x21 := (uint8(x20) & 0xff)
+ x22 := (x20 >> 8)
+ x23 := (uint8(x22) & 0xff)
+ x24 := (x22 >> 8)
+ x25 := (uint8(x24) & 0xff)
+ x26 := (x24 >> 8)
+ x27 := (uint8(x26) & 0xff)
+ x28 := (x26 >> 8)
+ x29 := (uint8(x28) & 0xff)
+ x30 := (x28 >> 8)
+ x31 := (uint8(x30) & 0xff)
+ x32 := uint8((x30 >> 8))
+ x33 := (uint8(x2) & 0xff)
+ x34 := (x2 >> 8)
+ x35 := (uint8(x34) & 0xff)
+ x36 := (x34 >> 8)
+ x37 := (uint8(x36) & 0xff)
+ x38 := (x36 >> 8)
+ x39 := (uint8(x38) & 0xff)
+ x40 := (x38 >> 8)
+ x41 := (uint8(x40) & 0xff)
+ x42 := (x40 >> 8)
+ x43 := (uint8(x42) & 0xff)
+ x44 := (x42 >> 8)
+ x45 := (uint8(x44) & 0xff)
+ x46 := uint8((x44 >> 8))
+ x47 := (uint8(x1) & 0xff)
+ x48 := (x1 >> 8)
+ x49 := (uint8(x48) & 0xff)
+ x50 := (x48 >> 8)
+ x51 := (uint8(x50) & 0xff)
+ x52 := (x50 >> 8)
+ x53 := (uint8(x52) & 0xff)
+ x54 := (x52 >> 8)
+ x55 := (uint8(x54) & 0xff)
+ x56 := (x54 >> 8)
+ x57 := (uint8(x56) & 0xff)
+ x58 := (x56 >> 8)
+ x59 := (uint8(x58) & 0xff)
+ x60 := uint8((x58 >> 8))
+ out1[0] = x5
+ out1[1] = x7
+ out1[2] = x9
+ out1[3] = x11
+ out1[4] = x13
+ out1[5] = x15
+ out1[6] = x17
+ out1[7] = x18
+ out1[8] = x19
+ out1[9] = x21
+ out1[10] = x23
+ out1[11] = x25
+ out1[12] = x27
+ out1[13] = x29
+ out1[14] = x31
+ out1[15] = x32
+ out1[16] = x33
+ out1[17] = x35
+ out1[18] = x37
+ out1[19] = x39
+ out1[20] = x41
+ out1[21] = x43
+ out1[22] = x45
+ out1[23] = x46
+ out1[24] = x47
+ out1[25] = x49
+ out1[26] = x51
+ out1[27] = x53
+ out1[28] = x55
+ out1[29] = x57
+ out1[30] = x59
+ out1[31] = x60
+}
+
+// fiatScalarFromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order.
+//
+// Preconditions:
+//
+// 0 ≤ bytes_eval arg1 < m
+//
+// Postconditions:
+//
+// eval out1 mod m = bytes_eval arg1 mod m
+// 0 ≤ eval out1 < m
+//
+// Input Bounds:
+//
+// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x1f]]
+//
+// Output Bounds:
+//
+// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0x1fffffffffffffff]]
+func fiatScalarFromBytes(out1 *[4]uint64, arg1 *[32]uint8) {
+ x1 := (uint64(arg1[31]) << 56)
+ x2 := (uint64(arg1[30]) << 48)
+ x3 := (uint64(arg1[29]) << 40)
+ x4 := (uint64(arg1[28]) << 32)
+ x5 := (uint64(arg1[27]) << 24)
+ x6 := (uint64(arg1[26]) << 16)
+ x7 := (uint64(arg1[25]) << 8)
+ x8 := arg1[24]
+ x9 := (uint64(arg1[23]) << 56)
+ x10 := (uint64(arg1[22]) << 48)
+ x11 := (uint64(arg1[21]) << 40)
+ x12 := (uint64(arg1[20]) << 32)
+ x13 := (uint64(arg1[19]) << 24)
+ x14 := (uint64(arg1[18]) << 16)
+ x15 := (uint64(arg1[17]) << 8)
+ x16 := arg1[16]
+ x17 := (uint64(arg1[15]) << 56)
+ x18 := (uint64(arg1[14]) << 48)
+ x19 := (uint64(arg1[13]) << 40)
+ x20 := (uint64(arg1[12]) << 32)
+ x21 := (uint64(arg1[11]) << 24)
+ x22 := (uint64(arg1[10]) << 16)
+ x23 := (uint64(arg1[9]) << 8)
+ x24 := arg1[8]
+ x25 := (uint64(arg1[7]) << 56)
+ x26 := (uint64(arg1[6]) << 48)
+ x27 := (uint64(arg1[5]) << 40)
+ x28 := (uint64(arg1[4]) << 32)
+ x29 := (uint64(arg1[3]) << 24)
+ x30 := (uint64(arg1[2]) << 16)
+ x31 := (uint64(arg1[1]) << 8)
+ x32 := arg1[0]
+ x33 := (x31 + uint64(x32))
+ x34 := (x30 + x33)
+ x35 := (x29 + x34)
+ x36 := (x28 + x35)
+ x37 := (x27 + x36)
+ x38 := (x26 + x37)
+ x39 := (x25 + x38)
+ x40 := (x23 + uint64(x24))
+ x41 := (x22 + x40)
+ x42 := (x21 + x41)
+ x43 := (x20 + x42)
+ x44 := (x19 + x43)
+ x45 := (x18 + x44)
+ x46 := (x17 + x45)
+ x47 := (x15 + uint64(x16))
+ x48 := (x14 + x47)
+ x49 := (x13 + x48)
+ x50 := (x12 + x49)
+ x51 := (x11 + x50)
+ x52 := (x10 + x51)
+ x53 := (x9 + x52)
+ x54 := (x7 + uint64(x8))
+ x55 := (x6 + x54)
+ x56 := (x5 + x55)
+ x57 := (x4 + x56)
+ x58 := (x3 + x57)
+ x59 := (x2 + x58)
+ x60 := (x1 + x59)
+ out1[0] = x39
+ out1[1] = x46
+ out1[2] = x53
+ out1[3] = x60
+}
diff --git a/src/crypto/internal/edwards25519/scalar_test.go b/src/crypto/internal/edwards25519/scalar_test.go
new file mode 100644
index 0000000..67bcdaf
--- /dev/null
+++ b/src/crypto/internal/edwards25519/scalar_test.go
@@ -0,0 +1,249 @@
+// Copyright (c) 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+import (
+ "bytes"
+ "encoding/hex"
+ "math/big"
+ mathrand "math/rand"
+ "reflect"
+ "testing"
+ "testing/quick"
+)
+
+var scOneBytes = [32]byte{1}
+var scOne, _ = new(Scalar).SetCanonicalBytes(scOneBytes[:])
+var scMinusOne, _ = new(Scalar).SetCanonicalBytes(scalarMinusOneBytes[:])
+
+// Generate returns a valid (reduced modulo l) Scalar with a distribution
+// weighted towards high, low, and edge values.
+func (Scalar) Generate(rand *mathrand.Rand, size int) reflect.Value {
+ var s [32]byte
+ diceRoll := rand.Intn(100)
+ switch {
+ case diceRoll == 0:
+ case diceRoll == 1:
+ s = scOneBytes
+ case diceRoll == 2:
+ s = scalarMinusOneBytes
+ case diceRoll < 5:
+ // Generate a low scalar in [0, 2^125).
+ rand.Read(s[:16])
+ s[15] &= (1 << 5) - 1
+ case diceRoll < 10:
+ // Generate a high scalar in [2^252, 2^252 + 2^124).
+ s[31] = 1 << 4
+ rand.Read(s[:16])
+ s[15] &= (1 << 4) - 1
+ default:
+ // Generate a valid scalar in [0, l) by returning [0, 2^252) which has a
+ // negligibly different distribution (the former has a 2^-127.6 chance
+ // of being out of the latter range).
+ rand.Read(s[:])
+ s[31] &= (1 << 4) - 1
+ }
+
+ val := Scalar{}
+ fiatScalarFromBytes((*[4]uint64)(&val.s), &s)
+ fiatScalarToMontgomery(&val.s, (*fiatScalarNonMontgomeryDomainFieldElement)(&val.s))
+
+ return reflect.ValueOf(val)
+}
+
+// quickCheckConfig1024 will make each quickcheck test run (1024 * -quickchecks)
+// times. The default value of -quickchecks is 100.
+var quickCheckConfig1024 = &quick.Config{MaxCountScale: 1 << 10}
+
+func TestScalarGenerate(t *testing.T) {
+ f := func(sc Scalar) bool {
+ return isReduced(sc.Bytes())
+ }
+ if err := quick.Check(f, quickCheckConfig1024); err != nil {
+ t.Errorf("generated unreduced scalar: %v", err)
+ }
+}
+
+func TestScalarSetCanonicalBytes(t *testing.T) {
+ f1 := func(in [32]byte, sc Scalar) bool {
+ // Mask out top 4 bits to guarantee value falls in [0, l).
+ in[len(in)-1] &= (1 << 4) - 1
+ if _, err := sc.SetCanonicalBytes(in[:]); err != nil {
+ return false
+ }
+ repr := sc.Bytes()
+ return bytes.Equal(in[:], repr) && isReduced(repr)
+ }
+ if err := quick.Check(f1, quickCheckConfig1024); err != nil {
+ t.Errorf("failed bytes->scalar->bytes round-trip: %v", err)
+ }
+
+ f2 := func(sc1, sc2 Scalar) bool {
+ if _, err := sc2.SetCanonicalBytes(sc1.Bytes()); err != nil {
+ return false
+ }
+ return sc1 == sc2
+ }
+ if err := quick.Check(f2, quickCheckConfig1024); err != nil {
+ t.Errorf("failed scalar->bytes->scalar round-trip: %v", err)
+ }
+
+ b := scalarMinusOneBytes
+ b[31] += 1
+ s := scOne
+ if out, err := s.SetCanonicalBytes(b[:]); err == nil {
+ t.Errorf("SetCanonicalBytes worked on a non-canonical value")
+ } else if s != scOne {
+ t.Errorf("SetCanonicalBytes modified its receiver")
+ } else if out != nil {
+ t.Errorf("SetCanonicalBytes did not return nil with an error")
+ }
+}
+
+func TestScalarSetUniformBytes(t *testing.T) {
+ mod, _ := new(big.Int).SetString("27742317777372353535851937790883648493", 10)
+ mod.Add(mod, new(big.Int).Lsh(big.NewInt(1), 252))
+ f := func(in [64]byte, sc Scalar) bool {
+ sc.SetUniformBytes(in[:])
+ repr := sc.Bytes()
+ if !isReduced(repr) {
+ return false
+ }
+ scBig := bigIntFromLittleEndianBytes(repr[:])
+ inBig := bigIntFromLittleEndianBytes(in[:])
+ return inBig.Mod(inBig, mod).Cmp(scBig) == 0
+ }
+ if err := quick.Check(f, quickCheckConfig1024); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestScalarSetBytesWithClamping(t *testing.T) {
+ // Generated with libsodium.js 1.0.18 crypto_scalarmult_ed25519_base.
+
+ random := "633d368491364dc9cd4c1bf891b1d59460face1644813240a313e61f2c88216e"
+ s, _ := new(Scalar).SetBytesWithClamping(decodeHex(random))
+ p := new(Point).ScalarBaseMult(s)
+ want := "1d87a9026fd0126a5736fe1628c95dd419172b5b618457e041c9c861b2494a94"
+ if got := hex.EncodeToString(p.Bytes()); got != want {
+ t.Errorf("random: got %q, want %q", got, want)
+ }
+
+ zero := "0000000000000000000000000000000000000000000000000000000000000000"
+ s, _ = new(Scalar).SetBytesWithClamping(decodeHex(zero))
+ p = new(Point).ScalarBaseMult(s)
+ want = "693e47972caf527c7883ad1b39822f026f47db2ab0e1919955b8993aa04411d1"
+ if got := hex.EncodeToString(p.Bytes()); got != want {
+ t.Errorf("zero: got %q, want %q", got, want)
+ }
+
+ one := "ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff"
+ s, _ = new(Scalar).SetBytesWithClamping(decodeHex(one))
+ p = new(Point).ScalarBaseMult(s)
+ want = "12e9a68b73fd5aacdbcaf3e88c46fea6ebedb1aa84eed1842f07f8edab65e3a7"
+ if got := hex.EncodeToString(p.Bytes()); got != want {
+ t.Errorf("one: got %q, want %q", got, want)
+ }
+}
+
+func bigIntFromLittleEndianBytes(b []byte) *big.Int {
+ bb := make([]byte, len(b))
+ for i := range b {
+ bb[i] = b[len(b)-i-1]
+ }
+ return new(big.Int).SetBytes(bb)
+}
+
+func TestScalarMultiplyDistributesOverAdd(t *testing.T) {
+ multiplyDistributesOverAdd := func(x, y, z Scalar) bool {
+ // Compute t1 = (x+y)*z
+ var t1 Scalar
+ t1.Add(&x, &y)
+ t1.Multiply(&t1, &z)
+
+ // Compute t2 = x*z + y*z
+ var t2 Scalar
+ var t3 Scalar
+ t2.Multiply(&x, &z)
+ t3.Multiply(&y, &z)
+ t2.Add(&t2, &t3)
+
+ reprT1, reprT2 := t1.Bytes(), t2.Bytes()
+
+ return t1 == t2 && isReduced(reprT1) && isReduced(reprT2)
+ }
+
+ if err := quick.Check(multiplyDistributesOverAdd, quickCheckConfig1024); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestScalarAddLikeSubNeg(t *testing.T) {
+ addLikeSubNeg := func(x, y Scalar) bool {
+ // Compute t1 = x - y
+ var t1 Scalar
+ t1.Subtract(&x, &y)
+
+ // Compute t2 = -y + x
+ var t2 Scalar
+ t2.Negate(&y)
+ t2.Add(&t2, &x)
+
+ return t1 == t2 && isReduced(t1.Bytes())
+ }
+
+ if err := quick.Check(addLikeSubNeg, quickCheckConfig1024); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestScalarNonAdjacentForm(t *testing.T) {
+ s, _ := (&Scalar{}).SetCanonicalBytes([]byte{
+ 0x1a, 0x0e, 0x97, 0x8a, 0x90, 0xf6, 0x62, 0x2d,
+ 0x37, 0x47, 0x02, 0x3f, 0x8a, 0xd8, 0x26, 0x4d,
+ 0xa7, 0x58, 0xaa, 0x1b, 0x88, 0xe0, 0x40, 0xd1,
+ 0x58, 0x9e, 0x7b, 0x7f, 0x23, 0x76, 0xef, 0x09,
+ })
+
+ expectedNaf := [256]int8{
+ 0, 13, 0, 0, 0, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, -9, 0, 0, 0, 0, -11, 0, 0, 0, 0, 3, 0, 0, 0, 0, 1,
+ 0, 0, 0, 0, 9, 0, 0, 0, 0, -5, 0, 0, 0, 0, 0, 0, 3, 0, 0, 0, 0, 11, 0, 0, 0, 0, 11, 0, 0, 0, 0, 0,
+ -9, 0, 0, 0, 0, 0, -3, 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 9, 0,
+ 0, 0, 0, -15, 0, 0, 0, 0, -7, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 13, 0, 0, 0, 0, 0, -3, 0,
+ 0, 0, 0, -11, 0, 0, 0, 0, -7, 0, 0, 0, 0, -13, 0, 0, 0, 0, 11, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, 1, 0, 0,
+ 0, 0, 0, -15, 0, 0, 0, 0, 1, 0, 0, 0, 0, 7, 0, 0, 0, 0, 0, 0, 0, 0, 5, 0, 0, 0, 0, 0, 13, 0, 0, 0,
+ 0, 0, 0, 11, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, -9, 0, 0, 0, 0, 0, 0, 0, -1, 0, 0, 0, 0, 0, 0, 0, 7,
+ 0, 0, 0, 0, 0, -15, 0, 0, 0, 0, 0, 15, 0, 0, 0, 0, 15, 0, 0, 0, 0, 15, 0, 0, 0, 0, 0, 1, 0, 0, 0, 0,
+ }
+
+ sNaf := s.nonAdjacentForm(5)
+
+ for i := 0; i < 256; i++ {
+ if expectedNaf[i] != sNaf[i] {
+ t.Errorf("Wrong digit at position %d, got %d, expected %d", i, sNaf[i], expectedNaf[i])
+ }
+ }
+}
+
+type notZeroScalar Scalar
+
+func (notZeroScalar) Generate(rand *mathrand.Rand, size int) reflect.Value {
+ var s Scalar
+ var isNonZero uint64
+ for isNonZero == 0 {
+ s = Scalar{}.Generate(rand, size).Interface().(Scalar)
+ fiatScalarNonzero(&isNonZero, (*[4]uint64)(&s.s))
+ }
+ return reflect.ValueOf(notZeroScalar(s))
+}
+
+func TestScalarEqual(t *testing.T) {
+ if scOne.Equal(scMinusOne) == 1 {
+ t.Errorf("scOne.Equal(&scMinusOne) is true")
+ }
+ if scMinusOne.Equal(scMinusOne) == 0 {
+ t.Errorf("scMinusOne.Equal(&scMinusOne) is false")
+ }
+}
diff --git a/src/crypto/internal/edwards25519/scalarmult.go b/src/crypto/internal/edwards25519/scalarmult.go
new file mode 100644
index 0000000..f7ca3ce
--- /dev/null
+++ b/src/crypto/internal/edwards25519/scalarmult.go
@@ -0,0 +1,214 @@
+// Copyright (c) 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+import "sync"
+
+// basepointTable is a set of 32 affineLookupTables, where table i is generated
+// from 256i * basepoint. It is precomputed the first time it's used.
+func basepointTable() *[32]affineLookupTable {
+ basepointTablePrecomp.initOnce.Do(func() {
+ p := NewGeneratorPoint()
+ for i := 0; i < 32; i++ {
+ basepointTablePrecomp.table[i].FromP3(p)
+ for j := 0; j < 8; j++ {
+ p.Add(p, p)
+ }
+ }
+ })
+ return &basepointTablePrecomp.table
+}
+
+var basepointTablePrecomp struct {
+ table [32]affineLookupTable
+ initOnce sync.Once
+}
+
+// ScalarBaseMult sets v = x * B, where B is the canonical generator, and
+// returns v.
+//
+// The scalar multiplication is done in constant time.
+func (v *Point) ScalarBaseMult(x *Scalar) *Point {
+ basepointTable := basepointTable()
+
+ // Write x = sum(x_i * 16^i) so x*B = sum( B*x_i*16^i )
+ // as described in the Ed25519 paper
+ //
+ // Group even and odd coefficients
+ // x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
+ // + x_1*16^1*B + x_3*16^3*B + ... + x_63*16^63*B
+ // x*B = x_0*16^0*B + x_2*16^2*B + ... + x_62*16^62*B
+ // + 16*( x_1*16^0*B + x_3*16^2*B + ... + x_63*16^62*B)
+ //
+ // We use a lookup table for each i to get x_i*16^(2*i)*B
+ // and do four doublings to multiply by 16.
+ digits := x.signedRadix16()
+
+ multiple := &affineCached{}
+ tmp1 := &projP1xP1{}
+ tmp2 := &projP2{}
+
+ // Accumulate the odd components first
+ v.Set(NewIdentityPoint())
+ for i := 1; i < 64; i += 2 {
+ basepointTable[i/2].SelectInto(multiple, digits[i])
+ tmp1.AddAffine(v, multiple)
+ v.fromP1xP1(tmp1)
+ }
+
+ // Multiply by 16
+ tmp2.FromP3(v) // tmp2 = v in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 2*v in P1xP1 coords
+ tmp2.FromP1xP1(tmp1) // tmp2 = 2*v in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 4*v in P1xP1 coords
+ tmp2.FromP1xP1(tmp1) // tmp2 = 4*v in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 8*v in P1xP1 coords
+ tmp2.FromP1xP1(tmp1) // tmp2 = 8*v in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 16*v in P1xP1 coords
+ v.fromP1xP1(tmp1) // now v = 16*(odd components)
+
+ // Accumulate the even components
+ for i := 0; i < 64; i += 2 {
+ basepointTable[i/2].SelectInto(multiple, digits[i])
+ tmp1.AddAffine(v, multiple)
+ v.fromP1xP1(tmp1)
+ }
+
+ return v
+}
+
+// ScalarMult sets v = x * q, and returns v.
+//
+// The scalar multiplication is done in constant time.
+func (v *Point) ScalarMult(x *Scalar, q *Point) *Point {
+ checkInitialized(q)
+
+ var table projLookupTable
+ table.FromP3(q)
+
+ // Write x = sum(x_i * 16^i)
+ // so x*Q = sum( Q*x_i*16^i )
+ // = Q*x_0 + 16*(Q*x_1 + 16*( ... + Q*x_63) ... )
+ // <------compute inside out---------
+ //
+ // We use the lookup table to get the x_i*Q values
+ // and do four doublings to compute 16*Q
+ digits := x.signedRadix16()
+
+ // Unwrap first loop iteration to save computing 16*identity
+ multiple := &projCached{}
+ tmp1 := &projP1xP1{}
+ tmp2 := &projP2{}
+ table.SelectInto(multiple, digits[63])
+
+ v.Set(NewIdentityPoint())
+ tmp1.Add(v, multiple) // tmp1 = x_63*Q in P1xP1 coords
+ for i := 62; i >= 0; i-- {
+ tmp2.FromP1xP1(tmp1) // tmp2 = (prev) in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 2*(prev) in P1xP1 coords
+ tmp2.FromP1xP1(tmp1) // tmp2 = 2*(prev) in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 4*(prev) in P1xP1 coords
+ tmp2.FromP1xP1(tmp1) // tmp2 = 4*(prev) in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 8*(prev) in P1xP1 coords
+ tmp2.FromP1xP1(tmp1) // tmp2 = 8*(prev) in P2 coords
+ tmp1.Double(tmp2) // tmp1 = 16*(prev) in P1xP1 coords
+ v.fromP1xP1(tmp1) // v = 16*(prev) in P3 coords
+ table.SelectInto(multiple, digits[i])
+ tmp1.Add(v, multiple) // tmp1 = x_i*Q + 16*(prev) in P1xP1 coords
+ }
+ v.fromP1xP1(tmp1)
+ return v
+}
+
+// basepointNafTable is the nafLookupTable8 for the basepoint.
+// It is precomputed the first time it's used.
+func basepointNafTable() *nafLookupTable8 {
+ basepointNafTablePrecomp.initOnce.Do(func() {
+ basepointNafTablePrecomp.table.FromP3(NewGeneratorPoint())
+ })
+ return &basepointNafTablePrecomp.table
+}
+
+var basepointNafTablePrecomp struct {
+ table nafLookupTable8
+ initOnce sync.Once
+}
+
+// VarTimeDoubleScalarBaseMult sets v = a * A + b * B, where B is the canonical
+// generator, and returns v.
+//
+// Execution time depends on the inputs.
+func (v *Point) VarTimeDoubleScalarBaseMult(a *Scalar, A *Point, b *Scalar) *Point {
+ checkInitialized(A)
+
+ // Similarly to the single variable-base approach, we compute
+ // digits and use them with a lookup table. However, because
+ // we are allowed to do variable-time operations, we don't
+ // need constant-time lookups or constant-time digit
+ // computations.
+ //
+ // So we use a non-adjacent form of some width w instead of
+ // radix 16. This is like a binary representation (one digit
+ // for each binary place) but we allow the digits to grow in
+ // magnitude up to 2^{w-1} so that the nonzero digits are as
+ // sparse as possible. Intuitively, this "condenses" the
+ // "mass" of the scalar onto sparse coefficients (meaning
+ // fewer additions).
+
+ basepointNafTable := basepointNafTable()
+ var aTable nafLookupTable5
+ aTable.FromP3(A)
+ // Because the basepoint is fixed, we can use a wider NAF
+ // corresponding to a bigger table.
+ aNaf := a.nonAdjacentForm(5)
+ bNaf := b.nonAdjacentForm(8)
+
+ // Find the first nonzero coefficient.
+ i := 255
+ for j := i; j >= 0; j-- {
+ if aNaf[j] != 0 || bNaf[j] != 0 {
+ break
+ }
+ }
+
+ multA := &projCached{}
+ multB := &affineCached{}
+ tmp1 := &projP1xP1{}
+ tmp2 := &projP2{}
+ tmp2.Zero()
+
+ // Move from high to low bits, doubling the accumulator
+ // at each iteration and checking whether there is a nonzero
+ // coefficient to look up a multiple of.
+ for ; i >= 0; i-- {
+ tmp1.Double(tmp2)
+
+ // Only update v if we have a nonzero coeff to add in.
+ if aNaf[i] > 0 {
+ v.fromP1xP1(tmp1)
+ aTable.SelectInto(multA, aNaf[i])
+ tmp1.Add(v, multA)
+ } else if aNaf[i] < 0 {
+ v.fromP1xP1(tmp1)
+ aTable.SelectInto(multA, -aNaf[i])
+ tmp1.Sub(v, multA)
+ }
+
+ if bNaf[i] > 0 {
+ v.fromP1xP1(tmp1)
+ basepointNafTable.SelectInto(multB, bNaf[i])
+ tmp1.AddAffine(v, multB)
+ } else if bNaf[i] < 0 {
+ v.fromP1xP1(tmp1)
+ basepointNafTable.SelectInto(multB, -bNaf[i])
+ tmp1.SubAffine(v, multB)
+ }
+
+ tmp2.FromP1xP1(tmp1)
+ }
+
+ v.fromP2(tmp2)
+ return v
+}
diff --git a/src/crypto/internal/edwards25519/scalarmult_test.go b/src/crypto/internal/edwards25519/scalarmult_test.go
new file mode 100644
index 0000000..6c92ab3
--- /dev/null
+++ b/src/crypto/internal/edwards25519/scalarmult_test.go
@@ -0,0 +1,209 @@
+// Copyright (c) 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+import (
+ "testing"
+ "testing/quick"
+)
+
+var (
+ // quickCheckConfig32 will make each quickcheck test run (32 * -quickchecks)
+ // times. The default value of -quickchecks is 100.
+ quickCheckConfig32 = &quick.Config{MaxCountScale: 1 << 5}
+
+ // a random scalar generated using dalek.
+ dalekScalar, _ = (&Scalar{}).SetCanonicalBytes([]byte{219, 106, 114, 9, 174, 249, 155, 89, 69, 203, 201, 93, 92, 116, 234, 187, 78, 115, 103, 172, 182, 98, 62, 103, 187, 136, 13, 100, 248, 110, 12, 4})
+ // the above, times the edwards25519 basepoint.
+ dalekScalarBasepoint, _ = new(Point).SetBytes([]byte{0xf4, 0xef, 0x7c, 0xa, 0x34, 0x55, 0x7b, 0x9f, 0x72, 0x3b, 0xb6, 0x1e, 0xf9, 0x46, 0x9, 0x91, 0x1c, 0xb9, 0xc0, 0x6c, 0x17, 0x28, 0x2d, 0x8b, 0x43, 0x2b, 0x5, 0x18, 0x6a, 0x54, 0x3e, 0x48})
+)
+
+func TestScalarMultSmallScalars(t *testing.T) {
+ var z Scalar
+ var p Point
+ p.ScalarMult(&z, B)
+ if I.Equal(&p) != 1 {
+ t.Error("0*B != 0")
+ }
+ checkOnCurve(t, &p)
+
+ scEight, _ := (&Scalar{}).SetCanonicalBytes([]byte{1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0})
+ p.ScalarMult(scEight, B)
+ if B.Equal(&p) != 1 {
+ t.Error("1*B != 1")
+ }
+ checkOnCurve(t, &p)
+}
+
+func TestScalarMultVsDalek(t *testing.T) {
+ var p Point
+ p.ScalarMult(dalekScalar, B)
+ if dalekScalarBasepoint.Equal(&p) != 1 {
+ t.Error("Scalar mul does not match dalek")
+ }
+ checkOnCurve(t, &p)
+}
+
+func TestBaseMultVsDalek(t *testing.T) {
+ var p Point
+ p.ScalarBaseMult(dalekScalar)
+ if dalekScalarBasepoint.Equal(&p) != 1 {
+ t.Error("Scalar mul does not match dalek")
+ }
+ checkOnCurve(t, &p)
+}
+
+func TestVarTimeDoubleBaseMultVsDalek(t *testing.T) {
+ var p Point
+ var z Scalar
+ p.VarTimeDoubleScalarBaseMult(dalekScalar, B, &z)
+ if dalekScalarBasepoint.Equal(&p) != 1 {
+ t.Error("VarTimeDoubleScalarBaseMult fails with b=0")
+ }
+ checkOnCurve(t, &p)
+ p.VarTimeDoubleScalarBaseMult(&z, B, dalekScalar)
+ if dalekScalarBasepoint.Equal(&p) != 1 {
+ t.Error("VarTimeDoubleScalarBaseMult fails with a=0")
+ }
+ checkOnCurve(t, &p)
+}
+
+func TestScalarMultDistributesOverAdd(t *testing.T) {
+ scalarMultDistributesOverAdd := func(x, y Scalar) bool {
+ var z Scalar
+ z.Add(&x, &y)
+ var p, q, r, check Point
+ p.ScalarMult(&x, B)
+ q.ScalarMult(&y, B)
+ r.ScalarMult(&z, B)
+ check.Add(&p, &q)
+ checkOnCurve(t, &p, &q, &r, &check)
+ return check.Equal(&r) == 1
+ }
+
+ if err := quick.Check(scalarMultDistributesOverAdd, quickCheckConfig32); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestScalarMultNonIdentityPoint(t *testing.T) {
+ // Check whether p.ScalarMult and q.ScalaBaseMult give the same,
+ // when p and q are originally set to the base point.
+
+ scalarMultNonIdentityPoint := func(x Scalar) bool {
+ var p, q Point
+ p.Set(B)
+ q.Set(B)
+
+ p.ScalarMult(&x, B)
+ q.ScalarBaseMult(&x)
+
+ checkOnCurve(t, &p, &q)
+
+ return p.Equal(&q) == 1
+ }
+
+ if err := quick.Check(scalarMultNonIdentityPoint, quickCheckConfig32); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestBasepointTableGeneration(t *testing.T) {
+ // The basepoint table is 32 affineLookupTables,
+ // corresponding to (16^2i)*B for table i.
+ basepointTable := basepointTable()
+
+ tmp1 := &projP1xP1{}
+ tmp2 := &projP2{}
+ tmp3 := &Point{}
+ tmp3.Set(B)
+ table := make([]affineLookupTable, 32)
+ for i := 0; i < 32; i++ {
+ // Build the table
+ table[i].FromP3(tmp3)
+ // Assert equality with the hardcoded one
+ if table[i] != basepointTable[i] {
+ t.Errorf("Basepoint table %d does not match", i)
+ }
+
+ // Set p = (16^2)*p = 256*p = 2^8*p
+ tmp2.FromP3(tmp3)
+ for j := 0; j < 7; j++ {
+ tmp1.Double(tmp2)
+ tmp2.FromP1xP1(tmp1)
+ }
+ tmp1.Double(tmp2)
+ tmp3.fromP1xP1(tmp1)
+ checkOnCurve(t, tmp3)
+ }
+}
+
+func TestScalarMultMatchesBaseMult(t *testing.T) {
+ scalarMultMatchesBaseMult := func(x Scalar) bool {
+ var p, q Point
+ p.ScalarMult(&x, B)
+ q.ScalarBaseMult(&x)
+ checkOnCurve(t, &p, &q)
+ return p.Equal(&q) == 1
+ }
+
+ if err := quick.Check(scalarMultMatchesBaseMult, quickCheckConfig32); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestBasepointNafTableGeneration(t *testing.T) {
+ var table nafLookupTable8
+ table.FromP3(B)
+
+ if table != *basepointNafTable() {
+ t.Error("BasepointNafTable does not match")
+ }
+}
+
+func TestVarTimeDoubleBaseMultMatchesBaseMult(t *testing.T) {
+ varTimeDoubleBaseMultMatchesBaseMult := func(x, y Scalar) bool {
+ var p, q1, q2, check Point
+
+ p.VarTimeDoubleScalarBaseMult(&x, B, &y)
+
+ q1.ScalarBaseMult(&x)
+ q2.ScalarBaseMult(&y)
+ check.Add(&q1, &q2)
+
+ checkOnCurve(t, &p, &check, &q1, &q2)
+ return p.Equal(&check) == 1
+ }
+
+ if err := quick.Check(varTimeDoubleBaseMultMatchesBaseMult, quickCheckConfig32); err != nil {
+ t.Error(err)
+ }
+}
+
+// Benchmarks.
+
+func BenchmarkScalarBaseMult(b *testing.B) {
+ var p Point
+
+ for i := 0; i < b.N; i++ {
+ p.ScalarBaseMult(dalekScalar)
+ }
+}
+
+func BenchmarkScalarMult(b *testing.B) {
+ var p Point
+
+ for i := 0; i < b.N; i++ {
+ p.ScalarMult(dalekScalar, B)
+ }
+}
+
+func BenchmarkVarTimeDoubleScalarBaseMult(b *testing.B) {
+ var p Point
+
+ for i := 0; i < b.N; i++ {
+ p.VarTimeDoubleScalarBaseMult(dalekScalar, B, dalekScalar)
+ }
+}
diff --git a/src/crypto/internal/edwards25519/tables.go b/src/crypto/internal/edwards25519/tables.go
new file mode 100644
index 0000000..83234bb
--- /dev/null
+++ b/src/crypto/internal/edwards25519/tables.go
@@ -0,0 +1,129 @@
+// Copyright (c) 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+import (
+ "crypto/subtle"
+)
+
+// A dynamic lookup table for variable-base, constant-time scalar muls.
+type projLookupTable struct {
+ points [8]projCached
+}
+
+// A precomputed lookup table for fixed-base, constant-time scalar muls.
+type affineLookupTable struct {
+ points [8]affineCached
+}
+
+// A dynamic lookup table for variable-base, variable-time scalar muls.
+type nafLookupTable5 struct {
+ points [8]projCached
+}
+
+// A precomputed lookup table for fixed-base, variable-time scalar muls.
+type nafLookupTable8 struct {
+ points [64]affineCached
+}
+
+// Constructors.
+
+// Builds a lookup table at runtime. Fast.
+func (v *projLookupTable) FromP3(q *Point) {
+ // Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
+ // This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
+ v.points[0].FromP3(q)
+ tmpP3 := Point{}
+ tmpP1xP1 := projP1xP1{}
+ for i := 0; i < 7; i++ {
+ // Compute (i+1)*Q as Q + i*Q and convert to a projCached
+ // This is needlessly complicated because the API has explicit
+ // receivers instead of creating stack objects and relying on RVO
+ v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(q, &v.points[i])))
+ }
+}
+
+// This is not optimised for speed; fixed-base tables should be precomputed.
+func (v *affineLookupTable) FromP3(q *Point) {
+ // Goal: v.points[i] = (i+1)*Q, i.e., Q, 2Q, ..., 8Q
+ // This allows lookup of -8Q, ..., -Q, 0, Q, ..., 8Q
+ v.points[0].FromP3(q)
+ tmpP3 := Point{}
+ tmpP1xP1 := projP1xP1{}
+ for i := 0; i < 7; i++ {
+ // Compute (i+1)*Q as Q + i*Q and convert to affineCached
+ v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(q, &v.points[i])))
+ }
+}
+
+// Builds a lookup table at runtime. Fast.
+func (v *nafLookupTable5) FromP3(q *Point) {
+ // Goal: v.points[i] = (2*i+1)*Q, i.e., Q, 3Q, 5Q, ..., 15Q
+ // This allows lookup of -15Q, ..., -3Q, -Q, 0, Q, 3Q, ..., 15Q
+ v.points[0].FromP3(q)
+ q2 := Point{}
+ q2.Add(q, q)
+ tmpP3 := Point{}
+ tmpP1xP1 := projP1xP1{}
+ for i := 0; i < 7; i++ {
+ v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.Add(&q2, &v.points[i])))
+ }
+}
+
+// This is not optimised for speed; fixed-base tables should be precomputed.
+func (v *nafLookupTable8) FromP3(q *Point) {
+ v.points[0].FromP3(q)
+ q2 := Point{}
+ q2.Add(q, q)
+ tmpP3 := Point{}
+ tmpP1xP1 := projP1xP1{}
+ for i := 0; i < 63; i++ {
+ v.points[i+1].FromP3(tmpP3.fromP1xP1(tmpP1xP1.AddAffine(&q2, &v.points[i])))
+ }
+}
+
+// Selectors.
+
+// Set dest to x*Q, where -8 <= x <= 8, in constant time.
+func (v *projLookupTable) SelectInto(dest *projCached, x int8) {
+ // Compute xabs = |x|
+ xmask := x >> 7
+ xabs := uint8((x + xmask) ^ xmask)
+
+ dest.Zero()
+ for j := 1; j <= 8; j++ {
+ // Set dest = j*Q if |x| = j
+ cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
+ dest.Select(&v.points[j-1], dest, cond)
+ }
+ // Now dest = |x|*Q, conditionally negate to get x*Q
+ dest.CondNeg(int(xmask & 1))
+}
+
+// Set dest to x*Q, where -8 <= x <= 8, in constant time.
+func (v *affineLookupTable) SelectInto(dest *affineCached, x int8) {
+ // Compute xabs = |x|
+ xmask := x >> 7
+ xabs := uint8((x + xmask) ^ xmask)
+
+ dest.Zero()
+ for j := 1; j <= 8; j++ {
+ // Set dest = j*Q if |x| = j
+ cond := subtle.ConstantTimeByteEq(xabs, uint8(j))
+ dest.Select(&v.points[j-1], dest, cond)
+ }
+ // Now dest = |x|*Q, conditionally negate to get x*Q
+ dest.CondNeg(int(xmask & 1))
+}
+
+// Given odd x with 0 < x < 2^4, return x*Q (in variable time).
+func (v *nafLookupTable5) SelectInto(dest *projCached, x int8) {
+ *dest = v.points[x/2]
+}
+
+// Given odd x with 0 < x < 2^7, return x*Q (in variable time).
+func (v *nafLookupTable8) SelectInto(dest *affineCached, x int8) {
+ *dest = v.points[x/2]
+}
diff --git a/src/crypto/internal/edwards25519/tables_test.go b/src/crypto/internal/edwards25519/tables_test.go
new file mode 100644
index 0000000..b5d161a
--- /dev/null
+++ b/src/crypto/internal/edwards25519/tables_test.go
@@ -0,0 +1,119 @@
+// Copyright (c) 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package edwards25519
+
+import (
+ "testing"
+)
+
+func TestProjLookupTable(t *testing.T) {
+ var table projLookupTable
+ table.FromP3(B)
+
+ var tmp1, tmp2, tmp3 projCached
+ table.SelectInto(&tmp1, 6)
+ table.SelectInto(&tmp2, -2)
+ table.SelectInto(&tmp3, -4)
+ // Expect T1 + T2 + T3 = identity
+
+ var accP1xP1 projP1xP1
+ accP3 := NewIdentityPoint()
+
+ accP1xP1.Add(accP3, &tmp1)
+ accP3.fromP1xP1(&accP1xP1)
+ accP1xP1.Add(accP3, &tmp2)
+ accP3.fromP1xP1(&accP1xP1)
+ accP1xP1.Add(accP3, &tmp3)
+ accP3.fromP1xP1(&accP1xP1)
+
+ if accP3.Equal(I) != 1 {
+ t.Errorf("Consistency check on ProjLookupTable.SelectInto failed! %x %x %x", tmp1, tmp2, tmp3)
+ }
+}
+
+func TestAffineLookupTable(t *testing.T) {
+ var table affineLookupTable
+ table.FromP3(B)
+
+ var tmp1, tmp2, tmp3 affineCached
+ table.SelectInto(&tmp1, 3)
+ table.SelectInto(&tmp2, -7)
+ table.SelectInto(&tmp3, 4)
+ // Expect T1 + T2 + T3 = identity
+
+ var accP1xP1 projP1xP1
+ accP3 := NewIdentityPoint()
+
+ accP1xP1.AddAffine(accP3, &tmp1)
+ accP3.fromP1xP1(&accP1xP1)
+ accP1xP1.AddAffine(accP3, &tmp2)
+ accP3.fromP1xP1(&accP1xP1)
+ accP1xP1.AddAffine(accP3, &tmp3)
+ accP3.fromP1xP1(&accP1xP1)
+
+ if accP3.Equal(I) != 1 {
+ t.Errorf("Consistency check on ProjLookupTable.SelectInto failed! %x %x %x", tmp1, tmp2, tmp3)
+ }
+}
+
+func TestNafLookupTable5(t *testing.T) {
+ var table nafLookupTable5
+ table.FromP3(B)
+
+ var tmp1, tmp2, tmp3, tmp4 projCached
+ table.SelectInto(&tmp1, 9)
+ table.SelectInto(&tmp2, 11)
+ table.SelectInto(&tmp3, 7)
+ table.SelectInto(&tmp4, 13)
+ // Expect T1 + T2 = T3 + T4
+
+ var accP1xP1 projP1xP1
+ lhs := NewIdentityPoint()
+ rhs := NewIdentityPoint()
+
+ accP1xP1.Add(lhs, &tmp1)
+ lhs.fromP1xP1(&accP1xP1)
+ accP1xP1.Add(lhs, &tmp2)
+ lhs.fromP1xP1(&accP1xP1)
+
+ accP1xP1.Add(rhs, &tmp3)
+ rhs.fromP1xP1(&accP1xP1)
+ accP1xP1.Add(rhs, &tmp4)
+ rhs.fromP1xP1(&accP1xP1)
+
+ if lhs.Equal(rhs) != 1 {
+ t.Errorf("Consistency check on nafLookupTable5 failed")
+ }
+}
+
+func TestNafLookupTable8(t *testing.T) {
+ var table nafLookupTable8
+ table.FromP3(B)
+
+ var tmp1, tmp2, tmp3, tmp4 affineCached
+ table.SelectInto(&tmp1, 49)
+ table.SelectInto(&tmp2, 11)
+ table.SelectInto(&tmp3, 35)
+ table.SelectInto(&tmp4, 25)
+ // Expect T1 + T2 = T3 + T4
+
+ var accP1xP1 projP1xP1
+ lhs := NewIdentityPoint()
+ rhs := NewIdentityPoint()
+
+ accP1xP1.AddAffine(lhs, &tmp1)
+ lhs.fromP1xP1(&accP1xP1)
+ accP1xP1.AddAffine(lhs, &tmp2)
+ lhs.fromP1xP1(&accP1xP1)
+
+ accP1xP1.AddAffine(rhs, &tmp3)
+ rhs.fromP1xP1(&accP1xP1)
+ accP1xP1.AddAffine(rhs, &tmp4)
+ rhs.fromP1xP1(&accP1xP1)
+
+ if lhs.Equal(rhs) != 1 {
+ t.Errorf("Consistency check on nafLookupTable8 failed")
+ }
+}
diff --git a/src/crypto/internal/nistec/fiat/Dockerfile b/src/crypto/internal/nistec/fiat/Dockerfile
new file mode 100644
index 0000000..2877e0b
--- /dev/null
+++ b/src/crypto/internal/nistec/fiat/Dockerfile
@@ -0,0 +1,12 @@
+# Copyright 2021 The Go Authors. All rights reserved.
+# Use of this source code is governed by a BSD-style
+# license that can be found in the LICENSE file.
+
+FROM coqorg/coq:8.13.2
+
+RUN git clone https://github.com/mit-plv/fiat-crypto && cd fiat-crypto && \
+ git checkout 23d2dbc4ab897d14bde4404f70cd6991635f9c01 && \
+ git submodule update --init --recursive
+RUN cd fiat-crypto && eval $(opam env) && make -j4 standalone-ocaml SKIP_BEDROCK2=1
+
+ENV PATH /home/coq/fiat-crypto/src/ExtractionOCaml:$PATH
diff --git a/src/crypto/internal/nistec/fiat/README b/src/crypto/internal/nistec/fiat/README
new file mode 100644
index 0000000..916ebc1
--- /dev/null
+++ b/src/crypto/internal/nistec/fiat/README
@@ -0,0 +1,34 @@
+The code in this package was autogenerated by the fiat-crypto project
+at version v0.0.9 from a formally verified model, and by the addchain
+project at a recent tip version.
+
+ docker build -t fiat-crypto:v0.0.9 .
+ go install github.com/mmcloughlin/addchain/cmd/addchain@v0.3.1-0.20211027081849-6a7d3decbe08
+ ../../../../../bin/go run generate.go
+
+fiat-crypto code comes under the following license.
+
+ Copyright (c) 2015-2020 The fiat-crypto Authors. All rights reserved.
+
+ Redistribution and use in source and binary forms, with or without
+ modification, are permitted provided that the following conditions are
+ met:
+
+ 1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+
+ THIS SOFTWARE IS PROVIDED BY the fiat-crypto authors "AS IS"
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
+ THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
+ PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL Berkeley Software Design,
+ Inc. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
+ EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
+ PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
+ PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
+ NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
+ SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The authors are listed at
+
+ https://github.com/mit-plv/fiat-crypto/blob/master/AUTHORS
diff --git a/src/crypto/internal/nistec/fiat/fiat_test.go b/src/crypto/internal/nistec/fiat/fiat_test.go
new file mode 100644
index 0000000..dee9f68
--- /dev/null
+++ b/src/crypto/internal/nistec/fiat/fiat_test.go
@@ -0,0 +1,64 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package fiat_test
+
+import (
+ "crypto/internal/nistec/fiat"
+ "testing"
+)
+
+func BenchmarkMul(b *testing.B) {
+ b.Run("P224", func(b *testing.B) {
+ v := new(fiat.P224Element).One()
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ v.Mul(v, v)
+ }
+ })
+ b.Run("P384", func(b *testing.B) {
+ v := new(fiat.P384Element).One()
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ v.Mul(v, v)
+ }
+ })
+ b.Run("P521", func(b *testing.B) {
+ v := new(fiat.P521Element).One()
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ v.Mul(v, v)
+ }
+ })
+}
+
+func BenchmarkSquare(b *testing.B) {
+ b.Run("P224", func(b *testing.B) {
+ v := new(fiat.P224Element).One()
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ v.Square(v)
+ }
+ })
+ b.Run("P384", func(b *testing.B) {
+ v := new(fiat.P384Element).One()
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ v.Square(v)
+ }
+ })
+ b.Run("P521", func(b *testing.B) {
+ v := new(fiat.P521Element).One()
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ v.Square(v)
+ }
+ })
+}
diff --git a/src/crypto/internal/nistec/fiat/generate.go b/src/crypto/internal/nistec/fiat/generate.go
new file mode 100644
index 0000000..db57021
--- /dev/null
+++ b/src/crypto/internal/nistec/fiat/generate.go
@@ -0,0 +1,330 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build ignore
+
+package main
+
+import (
+ "bytes"
+ "go/format"
+ "io"
+ "log"
+ "os"
+ "os/exec"
+ "text/template"
+)
+
+var curves = []struct {
+ Element string
+ Prime string
+ Prefix string
+ FiatType string
+ BytesLen int
+}{
+ {
+ Element: "P224Element",
+ Prime: "2^224 - 2^96 + 1",
+ Prefix: "p224",
+ FiatType: "[4]uint64",
+ BytesLen: 28,
+ },
+ // The P-256 fiat implementation is used only on 32-bit architectures, but
+ // the uint32 fiat code is for some reason slower than the uint64 one. That
+ // suggests there is a wide margin for improvement.
+ {
+ Element: "P256Element",
+ Prime: "2^256 - 2^224 + 2^192 + 2^96 - 1",
+ Prefix: "p256",
+ FiatType: "[4]uint64",
+ BytesLen: 32,
+ },
+ {
+ Element: "P384Element",
+ Prime: "2^384 - 2^128 - 2^96 + 2^32 - 1",
+ Prefix: "p384",
+ FiatType: "[6]uint64",
+ BytesLen: 48,
+ },
+ // Note that unsaturated_solinas would be about 2x faster than
+ // word_by_word_montgomery for P-521, but this curve is used rarely enough
+ // that it's not worth carrying unsaturated_solinas support for it.
+ {
+ Element: "P521Element",
+ Prime: "2^521 - 1",
+ Prefix: "p521",
+ FiatType: "[9]uint64",
+ BytesLen: 66,
+ },
+}
+
+func main() {
+ t := template.Must(template.New("montgomery").Parse(tmplWrapper))
+
+ tmplAddchainFile, err := os.CreateTemp("", "addchain-template")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer os.Remove(tmplAddchainFile.Name())
+ if _, err := io.WriteString(tmplAddchainFile, tmplAddchain); err != nil {
+ log.Fatal(err)
+ }
+ if err := tmplAddchainFile.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ for _, c := range curves {
+ log.Printf("Generating %s.go...", c.Prefix)
+ f, err := os.Create(c.Prefix + ".go")
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := t.Execute(f, c); err != nil {
+ log.Fatal(err)
+ }
+ if err := f.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ log.Printf("Generating %s_fiat64.go...", c.Prefix)
+ cmd := exec.Command("docker", "run", "--rm", "--entrypoint", "word_by_word_montgomery",
+ "fiat-crypto:v0.0.9", "--lang", "Go", "--no-wide-int", "--cmovznz-by-mul",
+ "--relax-primitive-carry-to-bitwidth", "32,64", "--internal-static",
+ "--public-function-case", "camelCase", "--public-type-case", "camelCase",
+ "--private-function-case", "camelCase", "--private-type-case", "camelCase",
+ "--doc-text-before-function-name", "", "--doc-newline-before-package-declaration",
+ "--doc-prepend-header", "Code generated by Fiat Cryptography. DO NOT EDIT.",
+ "--package-name", "fiat", "--no-prefix-fiat", c.Prefix, "64", c.Prime,
+ "mul", "square", "add", "sub", "one", "from_montgomery", "to_montgomery",
+ "selectznz", "to_bytes", "from_bytes")
+ cmd.Stderr = os.Stderr
+ out, err := cmd.Output()
+ if err != nil {
+ log.Fatal(err)
+ }
+ out, err = format.Source(out)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := os.WriteFile(c.Prefix+"_fiat64.go", out, 0644); err != nil {
+ log.Fatal(err)
+ }
+
+ log.Printf("Generating %s_invert.go...", c.Prefix)
+ f, err = os.CreateTemp("", "addchain-"+c.Prefix)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer os.Remove(f.Name())
+ cmd = exec.Command("addchain", "search", c.Prime+" - 2")
+ cmd.Stderr = os.Stderr
+ cmd.Stdout = f
+ if err := cmd.Run(); err != nil {
+ log.Fatal(err)
+ }
+ if err := f.Close(); err != nil {
+ log.Fatal(err)
+ }
+ cmd = exec.Command("addchain", "gen", "-tmpl", tmplAddchainFile.Name(), f.Name())
+ cmd.Stderr = os.Stderr
+ out, err = cmd.Output()
+ if err != nil {
+ log.Fatal(err)
+ }
+ out = bytes.Replace(out, []byte("Element"), []byte(c.Element), -1)
+ out, err = format.Source(out)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if err := os.WriteFile(c.Prefix+"_invert.go", out, 0644); err != nil {
+ log.Fatal(err)
+ }
+ }
+}
+
+const tmplWrapper = `// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by generate.go. DO NOT EDIT.
+
+package fiat
+
+import (
+ "crypto/subtle"
+ "errors"
+)
+
+// {{ .Element }} is an integer modulo {{ .Prime }}.
+//
+// The zero value is a valid zero element.
+type {{ .Element }} struct {
+ // Values are represented internally always in the Montgomery domain, and
+ // converted in Bytes and SetBytes.
+ x {{ .Prefix }}MontgomeryDomainFieldElement
+}
+
+const {{ .Prefix }}ElementLen = {{ .BytesLen }}
+
+type {{ .Prefix }}UntypedFieldElement = {{ .FiatType }}
+
+// One sets e = 1, and returns e.
+func (e *{{ .Element }}) One() *{{ .Element }} {
+ {{ .Prefix }}SetOne(&e.x)
+ return e
+}
+
+// Equal returns 1 if e == t, and zero otherwise.
+func (e *{{ .Element }}) Equal(t *{{ .Element }}) int {
+ eBytes := e.Bytes()
+ tBytes := t.Bytes()
+ return subtle.ConstantTimeCompare(eBytes, tBytes)
+}
+
+// IsZero returns 1 if e == 0, and zero otherwise.
+func (e *{{ .Element }}) IsZero() int {
+ zero := make([]byte, {{ .Prefix }}ElementLen)
+ eBytes := e.Bytes()
+ return subtle.ConstantTimeCompare(eBytes, zero)
+}
+
+// Set sets e = t, and returns e.
+func (e *{{ .Element }}) Set(t *{{ .Element }}) *{{ .Element }} {
+ e.x = t.x
+ return e
+}
+
+// Bytes returns the {{ .BytesLen }}-byte big-endian encoding of e.
+func (e *{{ .Element }}) Bytes() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [{{ .Prefix }}ElementLen]byte
+ return e.bytes(&out)
+}
+
+func (e *{{ .Element }}) bytes(out *[{{ .Prefix }}ElementLen]byte) []byte {
+ var tmp {{ .Prefix }}NonMontgomeryDomainFieldElement
+ {{ .Prefix }}FromMontgomery(&tmp, &e.x)
+ {{ .Prefix }}ToBytes(out, (*{{ .Prefix }}UntypedFieldElement)(&tmp))
+ {{ .Prefix }}InvertEndianness(out[:])
+ return out[:]
+}
+
+// SetBytes sets e = v, where v is a big-endian {{ .BytesLen }}-byte encoding, and returns e.
+// If v is not {{ .BytesLen }} bytes or it encodes a value higher than {{ .Prime }},
+// SetBytes returns nil and an error, and e is unchanged.
+func (e *{{ .Element }}) SetBytes(v []byte) (*{{ .Element }}, error) {
+ if len(v) != {{ .Prefix }}ElementLen {
+ return nil, errors.New("invalid {{ .Element }} encoding")
+ }
+
+ // Check for non-canonical encodings (p + k, 2p + k, etc.) by comparing to
+ // the encoding of -1 mod p, so p - 1, the highest canonical encoding.
+ var minusOneEncoding = new({{ .Element }}).Sub(
+ new({{ .Element }}), new({{ .Element }}).One()).Bytes()
+ for i := range v {
+ if v[i] < minusOneEncoding[i] {
+ break
+ }
+ if v[i] > minusOneEncoding[i] {
+ return nil, errors.New("invalid {{ .Element }} encoding")
+ }
+ }
+
+ var in [{{ .Prefix }}ElementLen]byte
+ copy(in[:], v)
+ {{ .Prefix }}InvertEndianness(in[:])
+ var tmp {{ .Prefix }}NonMontgomeryDomainFieldElement
+ {{ .Prefix }}FromBytes((*{{ .Prefix }}UntypedFieldElement)(&tmp), &in)
+ {{ .Prefix }}ToMontgomery(&e.x, &tmp)
+ return e, nil
+}
+
+// Add sets e = t1 + t2, and returns e.
+func (e *{{ .Element }}) Add(t1, t2 *{{ .Element }}) *{{ .Element }} {
+ {{ .Prefix }}Add(&e.x, &t1.x, &t2.x)
+ return e
+}
+
+// Sub sets e = t1 - t2, and returns e.
+func (e *{{ .Element }}) Sub(t1, t2 *{{ .Element }}) *{{ .Element }} {
+ {{ .Prefix }}Sub(&e.x, &t1.x, &t2.x)
+ return e
+}
+
+// Mul sets e = t1 * t2, and returns e.
+func (e *{{ .Element }}) Mul(t1, t2 *{{ .Element }}) *{{ .Element }} {
+ {{ .Prefix }}Mul(&e.x, &t1.x, &t2.x)
+ return e
+}
+
+// Square sets e = t * t, and returns e.
+func (e *{{ .Element }}) Square(t *{{ .Element }}) *{{ .Element }} {
+ {{ .Prefix }}Square(&e.x, &t.x)
+ return e
+}
+
+// Select sets v to a if cond == 1, and to b if cond == 0.
+func (v *{{ .Element }}) Select(a, b *{{ .Element }}, cond int) *{{ .Element }} {
+ {{ .Prefix }}Selectznz((*{{ .Prefix }}UntypedFieldElement)(&v.x), {{ .Prefix }}Uint1(cond),
+ (*{{ .Prefix }}UntypedFieldElement)(&b.x), (*{{ .Prefix }}UntypedFieldElement)(&a.x))
+ return v
+}
+
+func {{ .Prefix }}InvertEndianness(v []byte) {
+ for i := 0; i < len(v)/2; i++ {
+ v[i], v[len(v)-1-i] = v[len(v)-1-i], v[i]
+ }
+}
+`
+
+const tmplAddchain = `// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by {{ .Meta.Name }}. DO NOT EDIT.
+
+package fiat
+
+// Invert sets e = 1/x, and returns e.
+//
+// If x == 0, Invert returns e = 0.
+func (e *Element) Invert(x *Element) *Element {
+ // Inversion is implemented as exponentiation with exponent p − 2.
+ // The sequence of {{ .Ops.Adds }} multiplications and {{ .Ops.Doubles }} squarings is derived from the
+ // following addition chain generated with {{ .Meta.Module }} {{ .Meta.ReleaseTag }}.
+ //
+ {{- range lines (format .Script) }}
+ // {{ . }}
+ {{- end }}
+ //
+
+ var z = new(Element).Set(e)
+ {{- range .Program.Temporaries }}
+ var {{ . }} = new(Element)
+ {{- end }}
+ {{ range $i := .Program.Instructions -}}
+ {{- with add $i.Op }}
+ {{ $i.Output }}.Mul({{ .X }}, {{ .Y }})
+ {{- end -}}
+
+ {{- with double $i.Op }}
+ {{ $i.Output }}.Square({{ .X }})
+ {{- end -}}
+
+ {{- with shift $i.Op -}}
+ {{- $first := 0 -}}
+ {{- if ne $i.Output.Identifier .X.Identifier }}
+ {{ $i.Output }}.Square({{ .X }})
+ {{- $first = 1 -}}
+ {{- end }}
+ for s := {{ $first }}; s < {{ .S }}; s++ {
+ {{ $i.Output }}.Square({{ $i.Output }})
+ }
+ {{- end -}}
+ {{- end }}
+
+ return e.Set(z)
+}
+`
diff --git a/src/crypto/internal/nistec/fiat/p224.go b/src/crypto/internal/nistec/fiat/p224.go
new file mode 100644
index 0000000..e1a78db
--- /dev/null
+++ b/src/crypto/internal/nistec/fiat/p224.go
@@ -0,0 +1,134 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by generate.go. DO NOT EDIT.
+
+package fiat
+
+import (
+ "crypto/subtle"
+ "errors"
+)
+
+// P224Element is an integer modulo 2^224 - 2^96 + 1.
+//
+// The zero value is a valid zero element.
+type P224Element struct {
+ // Values are represented internally always in the Montgomery domain, and
+ // converted in Bytes and SetBytes.
+ x p224MontgomeryDomainFieldElement
+}
+
+const p224ElementLen = 28
+
+type p224UntypedFieldElement = [4]uint64
+
+// One sets e = 1, and returns e.
+func (e *P224Element) One() *P224Element {
+ p224SetOne(&e.x)
+ return e
+}
+
+// Equal returns 1 if e == t, and zero otherwise.
+func (e *P224Element) Equal(t *P224Element) int {
+ eBytes := e.Bytes()
+ tBytes := t.Bytes()
+ return subtle.ConstantTimeCompare(eBytes, tBytes)
+}
+
+// IsZero returns 1 if e == 0, and zero otherwise.
+func (e *P224Element) IsZero() int {
+ zero := make([]byte, p224ElementLen)
+ eBytes := e.Bytes()
+ return subtle.ConstantTimeCompare(eBytes, zero)
+}
+
+// Set sets e = t, and returns e.
+func (e *P224Element) Set(t *P224Element) *P224Element {
+ e.x = t.x
+ return e
+}
+
+// Bytes returns the 28-byte big-endian encoding of e.
+func (e *P224Element) Bytes() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [p224ElementLen]byte
+ return e.bytes(&out)
+}
+
+func (e *P224Element) bytes(out *[p224ElementLen]byte) []byte {
+ var tmp p224NonMontgomeryDomainFieldElement
+ p224FromMontgomery(&tmp, &e.x)
+ p224ToBytes(out, (*p224UntypedFieldElement)(&tmp))
+ p224InvertEndianness(out[:])
+ return out[:]
+}
+
+// SetBytes sets e = v, where v is a big-endian 28-byte encoding, and returns e.
+// If v is not 28 bytes or it encodes a value higher than 2^224 - 2^96 + 1,
+// SetBytes returns nil and an error, and e is unchanged.
+func (e *P224Element) SetBytes(v []byte) (*P224Element, error) {
+ if len(v) != p224ElementLen {
+ return nil, errors.New("invalid P224Element encoding")
+ }
+
+ // Check for non-canonical encodings (p + k, 2p + k, etc.) by comparing to
+ // the encoding of -1 mod p, so p - 1, the highest canonical encoding.
+ var minusOneEncoding = new(P224Element).Sub(
+ new(P224Element), new(P224Element).One()).Bytes()
+ for i := range v {
+ if v[i] < minusOneEncoding[i] {
+ break
+ }
+ if v[i] > minusOneEncoding[i] {
+ return nil, errors.New("invalid P224Element encoding")
+ }
+ }
+
+ var in [p224ElementLen]byte
+ copy(in[:], v)
+ p224InvertEndianness(in[:])
+ var tmp p224NonMontgomeryDomainFieldElement
+ p224FromBytes((*p224UntypedFieldElement)(&tmp), &in)
+ p224ToMontgomery(&e.x, &tmp)
+ return e, nil
+}
+
+// Add sets e = t1 + t2, and returns e.
+func (e *P224Element) Add(t1, t2 *P224Element) *P224Element {
+ p224Add(&e.x, &t1.x, &t2.x)
+ return e
+}
+
+// Sub sets e = t1 - t2, and returns e.
+func (e *P224Element) Sub(t1, t2 *P224Element) *P224Element {
+ p224Sub(&e.x, &t1.x, &t2.x)
+ return e
+}
+
+// Mul sets e = t1 * t2, and returns e.
+func (e *P224Element) Mul(t1, t2 *P224Element) *P224Element {
+ p224Mul(&e.x, &t1.x, &t2.x)
+ return e
+}
+
+// Square sets e = t * t, and returns e.
+func (e *P224Element) Square(t *P224Element) *P224Element {
+ p224Square(&e.x, &t.x)
+ return e
+}
+
+// Select sets v to a if cond == 1, and to b if cond == 0.
+func (v *P224Element) Select(a, b *P224Element, cond int) *P224Element {
+ p224Selectznz((*p224UntypedFieldElement)(&v.x), p224Uint1(cond),
+ (*p224UntypedFieldElement)(&b.x), (*p224UntypedFieldElement)(&a.x))
+ return v
+}
+
+func p224InvertEndianness(v []byte) {
+ for i := 0; i < len(v)/2; i++ {
+ v[i], v[len(v)-1-i] = v[len(v)-1-i], v[i]
+ }
+}
diff --git a/src/crypto/internal/nistec/fiat/p224_fiat64.go b/src/crypto/internal/nistec/fiat/p224_fiat64.go
new file mode 100644
index 0000000..9337bfe
--- /dev/null
+++ b/src/crypto/internal/nistec/fiat/p224_fiat64.go
@@ -0,0 +1,1461 @@
+// Code generated by Fiat Cryptography. DO NOT EDIT.
+//
+// Autogenerated: word_by_word_montgomery --lang Go --no-wide-int --cmovznz-by-mul --relax-primitive-carry-to-bitwidth 32,64 --internal-static --public-function-case camelCase --public-type-case camelCase --private-function-case camelCase --private-type-case camelCase --doc-text-before-function-name '' --doc-newline-before-package-declaration --doc-prepend-header 'Code generated by Fiat Cryptography. DO NOT EDIT.' --package-name fiat --no-prefix-fiat p224 64 '2^224 - 2^96 + 1' mul square add sub one from_montgomery to_montgomery selectznz to_bytes from_bytes
+//
+// curve description: p224
+//
+// machine_wordsize = 64 (from "64")
+//
+// requested operations: mul, square, add, sub, one, from_montgomery, to_montgomery, selectznz, to_bytes, from_bytes
+//
+// m = 0xffffffffffffffffffffffffffffffff000000000000000000000001 (from "2^224 - 2^96 + 1")
+//
+//
+//
+// NOTE: In addition to the bounds specified above each function, all
+//
+// functions synthesized for this Montgomery arithmetic require the
+//
+// input to be strictly less than the prime modulus (m), and also
+//
+// require the input to be in the unique saturated representation.
+//
+// All functions also ensure that these two properties are true of
+//
+// return values.
+//
+//
+//
+// Computed values:
+//
+// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192)
+//
+// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216)
+//
+// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in
+//
+// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256
+
+package fiat
+
+import "math/bits"
+
+type p224Uint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927
+type p224Int1 int64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927
+
+// The type p224MontgomeryDomainFieldElement is a field element in the Montgomery domain.
+//
+// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+type p224MontgomeryDomainFieldElement [4]uint64
+
+// The type p224NonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain.
+//
+// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+type p224NonMontgomeryDomainFieldElement [4]uint64
+
+// p224CmovznzU64 is a single-word conditional move.
+//
+// Postconditions:
+//
+// out1 = (if arg1 = 0 then arg2 else arg3)
+//
+// Input Bounds:
+//
+// arg1: [0x0 ~> 0x1]
+// arg2: [0x0 ~> 0xffffffffffffffff]
+// arg3: [0x0 ~> 0xffffffffffffffff]
+//
+// Output Bounds:
+//
+// out1: [0x0 ~> 0xffffffffffffffff]
+func p224CmovznzU64(out1 *uint64, arg1 p224Uint1, arg2 uint64, arg3 uint64) {
+ x1 := (uint64(arg1) * 0xffffffffffffffff)
+ x2 := ((x1 & arg3) | ((^x1) & arg2))
+ *out1 = x2
+}
+
+// p224Mul multiplies two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func p224Mul(out1 *p224MontgomeryDomainFieldElement, arg1 *p224MontgomeryDomainFieldElement, arg2 *p224MontgomeryDomainFieldElement) {
+ x1 := arg1[1]
+ x2 := arg1[2]
+ x3 := arg1[3]
+ x4 := arg1[0]
+ var x5 uint64
+ var x6 uint64
+ x6, x5 = bits.Mul64(x4, arg2[3])
+ var x7 uint64
+ var x8 uint64
+ x8, x7 = bits.Mul64(x4, arg2[2])
+ var x9 uint64
+ var x10 uint64
+ x10, x9 = bits.Mul64(x4, arg2[1])
+ var x11 uint64
+ var x12 uint64
+ x12, x11 = bits.Mul64(x4, arg2[0])
+ var x13 uint64
+ var x14 uint64
+ x13, x14 = bits.Add64(x12, x9, uint64(0x0))
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Add64(x10, x7, uint64(p224Uint1(x14)))
+ var x17 uint64
+ var x18 uint64
+ x17, x18 = bits.Add64(x8, x5, uint64(p224Uint1(x16)))
+ x19 := (uint64(p224Uint1(x18)) + x6)
+ var x20 uint64
+ _, x20 = bits.Mul64(x11, 0xffffffffffffffff)
+ var x22 uint64
+ var x23 uint64
+ x23, x22 = bits.Mul64(x20, 0xffffffff)
+ var x24 uint64
+ var x25 uint64
+ x25, x24 = bits.Mul64(x20, 0xffffffffffffffff)
+ var x26 uint64
+ var x27 uint64
+ x27, x26 = bits.Mul64(x20, 0xffffffff00000000)
+ var x28 uint64
+ var x29 uint64
+ x28, x29 = bits.Add64(x27, x24, uint64(0x0))
+ var x30 uint64
+ var x31 uint64
+ x30, x31 = bits.Add64(x25, x22, uint64(p224Uint1(x29)))
+ x32 := (uint64(p224Uint1(x31)) + x23)
+ var x34 uint64
+ _, x34 = bits.Add64(x11, x20, uint64(0x0))
+ var x35 uint64
+ var x36 uint64
+ x35, x36 = bits.Add64(x13, x26, uint64(p224Uint1(x34)))
+ var x37 uint64
+ var x38 uint64
+ x37, x38 = bits.Add64(x15, x28, uint64(p224Uint1(x36)))
+ var x39 uint64
+ var x40 uint64
+ x39, x40 = bits.Add64(x17, x30, uint64(p224Uint1(x38)))
+ var x41 uint64
+ var x42 uint64
+ x41, x42 = bits.Add64(x19, x32, uint64(p224Uint1(x40)))
+ var x43 uint64
+ var x44 uint64
+ x44, x43 = bits.Mul64(x1, arg2[3])
+ var x45 uint64
+ var x46 uint64
+ x46, x45 = bits.Mul64(x1, arg2[2])
+ var x47 uint64
+ var x48 uint64
+ x48, x47 = bits.Mul64(x1, arg2[1])
+ var x49 uint64
+ var x50 uint64
+ x50, x49 = bits.Mul64(x1, arg2[0])
+ var x51 uint64
+ var x52 uint64
+ x51, x52 = bits.Add64(x50, x47, uint64(0x0))
+ var x53 uint64
+ var x54 uint64
+ x53, x54 = bits.Add64(x48, x45, uint64(p224Uint1(x52)))
+ var x55 uint64
+ var x56 uint64
+ x55, x56 = bits.Add64(x46, x43, uint64(p224Uint1(x54)))
+ x57 := (uint64(p224Uint1(x56)) + x44)
+ var x58 uint64
+ var x59 uint64
+ x58, x59 = bits.Add64(x35, x49, uint64(0x0))
+ var x60 uint64
+ var x61 uint64
+ x60, x61 = bits.Add64(x37, x51, uint64(p224Uint1(x59)))
+ var x62 uint64
+ var x63 uint64
+ x62, x63 = bits.Add64(x39, x53, uint64(p224Uint1(x61)))
+ var x64 uint64
+ var x65 uint64
+ x64, x65 = bits.Add64(x41, x55, uint64(p224Uint1(x63)))
+ var x66 uint64
+ var x67 uint64
+ x66, x67 = bits.Add64(uint64(p224Uint1(x42)), x57, uint64(p224Uint1(x65)))
+ var x68 uint64
+ _, x68 = bits.Mul64(x58, 0xffffffffffffffff)
+ var x70 uint64
+ var x71 uint64
+ x71, x70 = bits.Mul64(x68, 0xffffffff)
+ var x72 uint64
+ var x73 uint64
+ x73, x72 = bits.Mul64(x68, 0xffffffffffffffff)
+ var x74 uint64
+ var x75 uint64
+ x75, x74 = bits.Mul64(x68, 0xffffffff00000000)
+ var x76 uint64
+ var x77 uint64
+ x76, x77 = bits.Add64(x75, x72, uint64(0x0))
+ var x78 uint64
+ var x79 uint64
+ x78, x79 = bits.Add64(x73, x70, uint64(p224Uint1(x77)))
+ x80 := (uint64(p224Uint1(x79)) + x71)
+ var x82 uint64
+ _, x82 = bits.Add64(x58, x68, uint64(0x0))
+ var x83 uint64
+ var x84 uint64
+ x83, x84 = bits.Add64(x60, x74, uint64(p224Uint1(x82)))
+ var x85 uint64
+ var x86 uint64
+ x85, x86 = bits.Add64(x62, x76, uint64(p224Uint1(x84)))
+ var x87 uint64
+ var x88 uint64
+ x87, x88 = bits.Add64(x64, x78, uint64(p224Uint1(x86)))
+ var x89 uint64
+ var x90 uint64
+ x89, x90 = bits.Add64(x66, x80, uint64(p224Uint1(x88)))
+ x91 := (uint64(p224Uint1(x90)) + uint64(p224Uint1(x67)))
+ var x92 uint64
+ var x93 uint64
+ x93, x92 = bits.Mul64(x2, arg2[3])
+ var x94 uint64
+ var x95 uint64
+ x95, x94 = bits.Mul64(x2, arg2[2])
+ var x96 uint64
+ var x97 uint64
+ x97, x96 = bits.Mul64(x2, arg2[1])
+ var x98 uint64
+ var x99 uint64
+ x99, x98 = bits.Mul64(x2, arg2[0])
+ var x100 uint64
+ var x101 uint64
+ x100, x101 = bits.Add64(x99, x96, uint64(0x0))
+ var x102 uint64
+ var x103 uint64
+ x102, x103 = bits.Add64(x97, x94, uint64(p224Uint1(x101)))
+ var x104 uint64
+ var x105 uint64
+ x104, x105 = bits.Add64(x95, x92, uint64(p224Uint1(x103)))
+ x106 := (uint64(p224Uint1(x105)) + x93)
+ var x107 uint64
+ var x108 uint64
+ x107, x108 = bits.Add64(x83, x98, uint64(0x0))
+ var x109 uint64
+ var x110 uint64
+ x109, x110 = bits.Add64(x85, x100, uint64(p224Uint1(x108)))
+ var x111 uint64
+ var x112 uint64
+ x111, x112 = bits.Add64(x87, x102, uint64(p224Uint1(x110)))
+ var x113 uint64
+ var x114 uint64
+ x113, x114 = bits.Add64(x89, x104, uint64(p224Uint1(x112)))
+ var x115 uint64
+ var x116 uint64
+ x115, x116 = bits.Add64(x91, x106, uint64(p224Uint1(x114)))
+ var x117 uint64
+ _, x117 = bits.Mul64(x107, 0xffffffffffffffff)
+ var x119 uint64
+ var x120 uint64
+ x120, x119 = bits.Mul64(x117, 0xffffffff)
+ var x121 uint64
+ var x122 uint64
+ x122, x121 = bits.Mul64(x117, 0xffffffffffffffff)
+ var x123 uint64
+ var x124 uint64
+ x124, x123 = bits.Mul64(x117, 0xffffffff00000000)
+ var x125 uint64
+ var x126 uint64
+ x125, x126 = bits.Add64(x124, x121, uint64(0x0))
+ var x127 uint64
+ var x128 uint64
+ x127, x128 = bits.Add64(x122, x119, uint64(p224Uint1(x126)))
+ x129 := (uint64(p224Uint1(x128)) + x120)
+ var x131 uint64
+ _, x131 = bits.Add64(x107, x117, uint64(0x0))
+ var x132 uint64
+ var x133 uint64
+ x132, x133 = bits.Add64(x109, x123, uint64(p224Uint1(x131)))
+ var x134 uint64
+ var x135 uint64
+ x134, x135 = bits.Add64(x111, x125, uint64(p224Uint1(x133)))
+ var x136 uint64
+ var x137 uint64
+ x136, x137 = bits.Add64(x113, x127, uint64(p224Uint1(x135)))
+ var x138 uint64
+ var x139 uint64
+ x138, x139 = bits.Add64(x115, x129, uint64(p224Uint1(x137)))
+ x140 := (uint64(p224Uint1(x139)) + uint64(p224Uint1(x116)))
+ var x141 uint64
+ var x142 uint64
+ x142, x141 = bits.Mul64(x3, arg2[3])
+ var x143 uint64
+ var x144 uint64
+ x144, x143 = bits.Mul64(x3, arg2[2])
+ var x145 uint64
+ var x146 uint64
+ x146, x145 = bits.Mul64(x3, arg2[1])
+ var x147 uint64
+ var x148 uint64
+ x148, x147 = bits.Mul64(x3, arg2[0])
+ var x149 uint64
+ var x150 uint64
+ x149, x150 = bits.Add64(x148, x145, uint64(0x0))
+ var x151 uint64
+ var x152 uint64
+ x151, x152 = bits.Add64(x146, x143, uint64(p224Uint1(x150)))
+ var x153 uint64
+ var x154 uint64
+ x153, x154 = bits.Add64(x144, x141, uint64(p224Uint1(x152)))
+ x155 := (uint64(p224Uint1(x154)) + x142)
+ var x156 uint64
+ var x157 uint64
+ x156, x157 = bits.Add64(x132, x147, uint64(0x0))
+ var x158 uint64
+ var x159 uint64
+ x158, x159 = bits.Add64(x134, x149, uint64(p224Uint1(x157)))
+ var x160 uint64
+ var x161 uint64
+ x160, x161 = bits.Add64(x136, x151, uint64(p224Uint1(x159)))
+ var x162 uint64
+ var x163 uint64
+ x162, x163 = bits.Add64(x138, x153, uint64(p224Uint1(x161)))
+ var x164 uint64
+ var x165 uint64
+ x164, x165 = bits.Add64(x140, x155, uint64(p224Uint1(x163)))
+ var x166 uint64
+ _, x166 = bits.Mul64(x156, 0xffffffffffffffff)
+ var x168 uint64
+ var x169 uint64
+ x169, x168 = bits.Mul64(x166, 0xffffffff)
+ var x170 uint64
+ var x171 uint64
+ x171, x170 = bits.Mul64(x166, 0xffffffffffffffff)
+ var x172 uint64
+ var x173 uint64
+ x173, x172 = bits.Mul64(x166, 0xffffffff00000000)
+ var x174 uint64
+ var x175 uint64
+ x174, x175 = bits.Add64(x173, x170, uint64(0x0))
+ var x176 uint64
+ var x177 uint64
+ x176, x177 = bits.Add64(x171, x168, uint64(p224Uint1(x175)))
+ x178 := (uint64(p224Uint1(x177)) + x169)
+ var x180 uint64
+ _, x180 = bits.Add64(x156, x166, uint64(0x0))
+ var x181 uint64
+ var x182 uint64
+ x181, x182 = bits.Add64(x158, x172, uint64(p224Uint1(x180)))
+ var x183 uint64
+ var x184 uint64
+ x183, x184 = bits.Add64(x160, x174, uint64(p224Uint1(x182)))
+ var x185 uint64
+ var x186 uint64
+ x185, x186 = bits.Add64(x162, x176, uint64(p224Uint1(x184)))
+ var x187 uint64
+ var x188 uint64
+ x187, x188 = bits.Add64(x164, x178, uint64(p224Uint1(x186)))
+ x189 := (uint64(p224Uint1(x188)) + uint64(p224Uint1(x165)))
+ var x190 uint64
+ var x191 uint64
+ x190, x191 = bits.Sub64(x181, uint64(0x1), uint64(0x0))
+ var x192 uint64
+ var x193 uint64
+ x192, x193 = bits.Sub64(x183, 0xffffffff00000000, uint64(p224Uint1(x191)))
+ var x194 uint64
+ var x195 uint64
+ x194, x195 = bits.Sub64(x185, 0xffffffffffffffff, uint64(p224Uint1(x193)))
+ var x196 uint64
+ var x197 uint64
+ x196, x197 = bits.Sub64(x187, 0xffffffff, uint64(p224Uint1(x195)))
+ var x199 uint64
+ _, x199 = bits.Sub64(x189, uint64(0x0), uint64(p224Uint1(x197)))
+ var x200 uint64
+ p224CmovznzU64(&x200, p224Uint1(x199), x190, x181)
+ var x201 uint64
+ p224CmovznzU64(&x201, p224Uint1(x199), x192, x183)
+ var x202 uint64
+ p224CmovznzU64(&x202, p224Uint1(x199), x194, x185)
+ var x203 uint64
+ p224CmovznzU64(&x203, p224Uint1(x199), x196, x187)
+ out1[0] = x200
+ out1[1] = x201
+ out1[2] = x202
+ out1[3] = x203
+}
+
+// p224Square squares a field element in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m
+// 0 ≤ eval out1 < m
+func p224Square(out1 *p224MontgomeryDomainFieldElement, arg1 *p224MontgomeryDomainFieldElement) {
+ x1 := arg1[1]
+ x2 := arg1[2]
+ x3 := arg1[3]
+ x4 := arg1[0]
+ var x5 uint64
+ var x6 uint64
+ x6, x5 = bits.Mul64(x4, arg1[3])
+ var x7 uint64
+ var x8 uint64
+ x8, x7 = bits.Mul64(x4, arg1[2])
+ var x9 uint64
+ var x10 uint64
+ x10, x9 = bits.Mul64(x4, arg1[1])
+ var x11 uint64
+ var x12 uint64
+ x12, x11 = bits.Mul64(x4, arg1[0])
+ var x13 uint64
+ var x14 uint64
+ x13, x14 = bits.Add64(x12, x9, uint64(0x0))
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Add64(x10, x7, uint64(p224Uint1(x14)))
+ var x17 uint64
+ var x18 uint64
+ x17, x18 = bits.Add64(x8, x5, uint64(p224Uint1(x16)))
+ x19 := (uint64(p224Uint1(x18)) + x6)
+ var x20 uint64
+ _, x20 = bits.Mul64(x11, 0xffffffffffffffff)
+ var x22 uint64
+ var x23 uint64
+ x23, x22 = bits.Mul64(x20, 0xffffffff)
+ var x24 uint64
+ var x25 uint64
+ x25, x24 = bits.Mul64(x20, 0xffffffffffffffff)
+ var x26 uint64
+ var x27 uint64
+ x27, x26 = bits.Mul64(x20, 0xffffffff00000000)
+ var x28 uint64
+ var x29 uint64
+ x28, x29 = bits.Add64(x27, x24, uint64(0x0))
+ var x30 uint64
+ var x31 uint64
+ x30, x31 = bits.Add64(x25, x22, uint64(p224Uint1(x29)))
+ x32 := (uint64(p224Uint1(x31)) + x23)
+ var x34 uint64
+ _, x34 = bits.Add64(x11, x20, uint64(0x0))
+ var x35 uint64
+ var x36 uint64
+ x35, x36 = bits.Add64(x13, x26, uint64(p224Uint1(x34)))
+ var x37 uint64
+ var x38 uint64
+ x37, x38 = bits.Add64(x15, x28, uint64(p224Uint1(x36)))
+ var x39 uint64
+ var x40 uint64
+ x39, x40 = bits.Add64(x17, x30, uint64(p224Uint1(x38)))
+ var x41 uint64
+ var x42 uint64
+ x41, x42 = bits.Add64(x19, x32, uint64(p224Uint1(x40)))
+ var x43 uint64
+ var x44 uint64
+ x44, x43 = bits.Mul64(x1, arg1[3])
+ var x45 uint64
+ var x46 uint64
+ x46, x45 = bits.Mul64(x1, arg1[2])
+ var x47 uint64
+ var x48 uint64
+ x48, x47 = bits.Mul64(x1, arg1[1])
+ var x49 uint64
+ var x50 uint64
+ x50, x49 = bits.Mul64(x1, arg1[0])
+ var x51 uint64
+ var x52 uint64
+ x51, x52 = bits.Add64(x50, x47, uint64(0x0))
+ var x53 uint64
+ var x54 uint64
+ x53, x54 = bits.Add64(x48, x45, uint64(p224Uint1(x52)))
+ var x55 uint64
+ var x56 uint64
+ x55, x56 = bits.Add64(x46, x43, uint64(p224Uint1(x54)))
+ x57 := (uint64(p224Uint1(x56)) + x44)
+ var x58 uint64
+ var x59 uint64
+ x58, x59 = bits.Add64(x35, x49, uint64(0x0))
+ var x60 uint64
+ var x61 uint64
+ x60, x61 = bits.Add64(x37, x51, uint64(p224Uint1(x59)))
+ var x62 uint64
+ var x63 uint64
+ x62, x63 = bits.Add64(x39, x53, uint64(p224Uint1(x61)))
+ var x64 uint64
+ var x65 uint64
+ x64, x65 = bits.Add64(x41, x55, uint64(p224Uint1(x63)))
+ var x66 uint64
+ var x67 uint64
+ x66, x67 = bits.Add64(uint64(p224Uint1(x42)), x57, uint64(p224Uint1(x65)))
+ var x68 uint64
+ _, x68 = bits.Mul64(x58, 0xffffffffffffffff)
+ var x70 uint64
+ var x71 uint64
+ x71, x70 = bits.Mul64(x68, 0xffffffff)
+ var x72 uint64
+ var x73 uint64
+ x73, x72 = bits.Mul64(x68, 0xffffffffffffffff)
+ var x74 uint64
+ var x75 uint64
+ x75, x74 = bits.Mul64(x68, 0xffffffff00000000)
+ var x76 uint64
+ var x77 uint64
+ x76, x77 = bits.Add64(x75, x72, uint64(0x0))
+ var x78 uint64
+ var x79 uint64
+ x78, x79 = bits.Add64(x73, x70, uint64(p224Uint1(x77)))
+ x80 := (uint64(p224Uint1(x79)) + x71)
+ var x82 uint64
+ _, x82 = bits.Add64(x58, x68, uint64(0x0))
+ var x83 uint64
+ var x84 uint64
+ x83, x84 = bits.Add64(x60, x74, uint64(p224Uint1(x82)))
+ var x85 uint64
+ var x86 uint64
+ x85, x86 = bits.Add64(x62, x76, uint64(p224Uint1(x84)))
+ var x87 uint64
+ var x88 uint64
+ x87, x88 = bits.Add64(x64, x78, uint64(p224Uint1(x86)))
+ var x89 uint64
+ var x90 uint64
+ x89, x90 = bits.Add64(x66, x80, uint64(p224Uint1(x88)))
+ x91 := (uint64(p224Uint1(x90)) + uint64(p224Uint1(x67)))
+ var x92 uint64
+ var x93 uint64
+ x93, x92 = bits.Mul64(x2, arg1[3])
+ var x94 uint64
+ var x95 uint64
+ x95, x94 = bits.Mul64(x2, arg1[2])
+ var x96 uint64
+ var x97 uint64
+ x97, x96 = bits.Mul64(x2, arg1[1])
+ var x98 uint64
+ var x99 uint64
+ x99, x98 = bits.Mul64(x2, arg1[0])
+ var x100 uint64
+ var x101 uint64
+ x100, x101 = bits.Add64(x99, x96, uint64(0x0))
+ var x102 uint64
+ var x103 uint64
+ x102, x103 = bits.Add64(x97, x94, uint64(p224Uint1(x101)))
+ var x104 uint64
+ var x105 uint64
+ x104, x105 = bits.Add64(x95, x92, uint64(p224Uint1(x103)))
+ x106 := (uint64(p224Uint1(x105)) + x93)
+ var x107 uint64
+ var x108 uint64
+ x107, x108 = bits.Add64(x83, x98, uint64(0x0))
+ var x109 uint64
+ var x110 uint64
+ x109, x110 = bits.Add64(x85, x100, uint64(p224Uint1(x108)))
+ var x111 uint64
+ var x112 uint64
+ x111, x112 = bits.Add64(x87, x102, uint64(p224Uint1(x110)))
+ var x113 uint64
+ var x114 uint64
+ x113, x114 = bits.Add64(x89, x104, uint64(p224Uint1(x112)))
+ var x115 uint64
+ var x116 uint64
+ x115, x116 = bits.Add64(x91, x106, uint64(p224Uint1(x114)))
+ var x117 uint64
+ _, x117 = bits.Mul64(x107, 0xffffffffffffffff)
+ var x119 uint64
+ var x120 uint64
+ x120, x119 = bits.Mul64(x117, 0xffffffff)
+ var x121 uint64
+ var x122 uint64
+ x122, x121 = bits.Mul64(x117, 0xffffffffffffffff)
+ var x123 uint64
+ var x124 uint64
+ x124, x123 = bits.Mul64(x117, 0xffffffff00000000)
+ var x125 uint64
+ var x126 uint64
+ x125, x126 = bits.Add64(x124, x121, uint64(0x0))
+ var x127 uint64
+ var x128 uint64
+ x127, x128 = bits.Add64(x122, x119, uint64(p224Uint1(x126)))
+ x129 := (uint64(p224Uint1(x128)) + x120)
+ var x131 uint64
+ _, x131 = bits.Add64(x107, x117, uint64(0x0))
+ var x132 uint64
+ var x133 uint64
+ x132, x133 = bits.Add64(x109, x123, uint64(p224Uint1(x131)))
+ var x134 uint64
+ var x135 uint64
+ x134, x135 = bits.Add64(x111, x125, uint64(p224Uint1(x133)))
+ var x136 uint64
+ var x137 uint64
+ x136, x137 = bits.Add64(x113, x127, uint64(p224Uint1(x135)))
+ var x138 uint64
+ var x139 uint64
+ x138, x139 = bits.Add64(x115, x129, uint64(p224Uint1(x137)))
+ x140 := (uint64(p224Uint1(x139)) + uint64(p224Uint1(x116)))
+ var x141 uint64
+ var x142 uint64
+ x142, x141 = bits.Mul64(x3, arg1[3])
+ var x143 uint64
+ var x144 uint64
+ x144, x143 = bits.Mul64(x3, arg1[2])
+ var x145 uint64
+ var x146 uint64
+ x146, x145 = bits.Mul64(x3, arg1[1])
+ var x147 uint64
+ var x148 uint64
+ x148, x147 = bits.Mul64(x3, arg1[0])
+ var x149 uint64
+ var x150 uint64
+ x149, x150 = bits.Add64(x148, x145, uint64(0x0))
+ var x151 uint64
+ var x152 uint64
+ x151, x152 = bits.Add64(x146, x143, uint64(p224Uint1(x150)))
+ var x153 uint64
+ var x154 uint64
+ x153, x154 = bits.Add64(x144, x141, uint64(p224Uint1(x152)))
+ x155 := (uint64(p224Uint1(x154)) + x142)
+ var x156 uint64
+ var x157 uint64
+ x156, x157 = bits.Add64(x132, x147, uint64(0x0))
+ var x158 uint64
+ var x159 uint64
+ x158, x159 = bits.Add64(x134, x149, uint64(p224Uint1(x157)))
+ var x160 uint64
+ var x161 uint64
+ x160, x161 = bits.Add64(x136, x151, uint64(p224Uint1(x159)))
+ var x162 uint64
+ var x163 uint64
+ x162, x163 = bits.Add64(x138, x153, uint64(p224Uint1(x161)))
+ var x164 uint64
+ var x165 uint64
+ x164, x165 = bits.Add64(x140, x155, uint64(p224Uint1(x163)))
+ var x166 uint64
+ _, x166 = bits.Mul64(x156, 0xffffffffffffffff)
+ var x168 uint64
+ var x169 uint64
+ x169, x168 = bits.Mul64(x166, 0xffffffff)
+ var x170 uint64
+ var x171 uint64
+ x171, x170 = bits.Mul64(x166, 0xffffffffffffffff)
+ var x172 uint64
+ var x173 uint64
+ x173, x172 = bits.Mul64(x166, 0xffffffff00000000)
+ var x174 uint64
+ var x175 uint64
+ x174, x175 = bits.Add64(x173, x170, uint64(0x0))
+ var x176 uint64
+ var x177 uint64
+ x176, x177 = bits.Add64(x171, x168, uint64(p224Uint1(x175)))
+ x178 := (uint64(p224Uint1(x177)) + x169)
+ var x180 uint64
+ _, x180 = bits.Add64(x156, x166, uint64(0x0))
+ var x181 uint64
+ var x182 uint64
+ x181, x182 = bits.Add64(x158, x172, uint64(p224Uint1(x180)))
+ var x183 uint64
+ var x184 uint64
+ x183, x184 = bits.Add64(x160, x174, uint64(p224Uint1(x182)))
+ var x185 uint64
+ var x186 uint64
+ x185, x186 = bits.Add64(x162, x176, uint64(p224Uint1(x184)))
+ var x187 uint64
+ var x188 uint64
+ x187, x188 = bits.Add64(x164, x178, uint64(p224Uint1(x186)))
+ x189 := (uint64(p224Uint1(x188)) + uint64(p224Uint1(x165)))
+ var x190 uint64
+ var x191 uint64
+ x190, x191 = bits.Sub64(x181, uint64(0x1), uint64(0x0))
+ var x192 uint64
+ var x193 uint64
+ x192, x193 = bits.Sub64(x183, 0xffffffff00000000, uint64(p224Uint1(x191)))
+ var x194 uint64
+ var x195 uint64
+ x194, x195 = bits.Sub64(x185, 0xffffffffffffffff, uint64(p224Uint1(x193)))
+ var x196 uint64
+ var x197 uint64
+ x196, x197 = bits.Sub64(x187, 0xffffffff, uint64(p224Uint1(x195)))
+ var x199 uint64
+ _, x199 = bits.Sub64(x189, uint64(0x0), uint64(p224Uint1(x197)))
+ var x200 uint64
+ p224CmovznzU64(&x200, p224Uint1(x199), x190, x181)
+ var x201 uint64
+ p224CmovznzU64(&x201, p224Uint1(x199), x192, x183)
+ var x202 uint64
+ p224CmovznzU64(&x202, p224Uint1(x199), x194, x185)
+ var x203 uint64
+ p224CmovznzU64(&x203, p224Uint1(x199), x196, x187)
+ out1[0] = x200
+ out1[1] = x201
+ out1[2] = x202
+ out1[3] = x203
+}
+
+// p224Add adds two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func p224Add(out1 *p224MontgomeryDomainFieldElement, arg1 *p224MontgomeryDomainFieldElement, arg2 *p224MontgomeryDomainFieldElement) {
+ var x1 uint64
+ var x2 uint64
+ x1, x2 = bits.Add64(arg1[0], arg2[0], uint64(0x0))
+ var x3 uint64
+ var x4 uint64
+ x3, x4 = bits.Add64(arg1[1], arg2[1], uint64(p224Uint1(x2)))
+ var x5 uint64
+ var x6 uint64
+ x5, x6 = bits.Add64(arg1[2], arg2[2], uint64(p224Uint1(x4)))
+ var x7 uint64
+ var x8 uint64
+ x7, x8 = bits.Add64(arg1[3], arg2[3], uint64(p224Uint1(x6)))
+ var x9 uint64
+ var x10 uint64
+ x9, x10 = bits.Sub64(x1, uint64(0x1), uint64(0x0))
+ var x11 uint64
+ var x12 uint64
+ x11, x12 = bits.Sub64(x3, 0xffffffff00000000, uint64(p224Uint1(x10)))
+ var x13 uint64
+ var x14 uint64
+ x13, x14 = bits.Sub64(x5, 0xffffffffffffffff, uint64(p224Uint1(x12)))
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Sub64(x7, 0xffffffff, uint64(p224Uint1(x14)))
+ var x18 uint64
+ _, x18 = bits.Sub64(uint64(p224Uint1(x8)), uint64(0x0), uint64(p224Uint1(x16)))
+ var x19 uint64
+ p224CmovznzU64(&x19, p224Uint1(x18), x9, x1)
+ var x20 uint64
+ p224CmovznzU64(&x20, p224Uint1(x18), x11, x3)
+ var x21 uint64
+ p224CmovznzU64(&x21, p224Uint1(x18), x13, x5)
+ var x22 uint64
+ p224CmovznzU64(&x22, p224Uint1(x18), x15, x7)
+ out1[0] = x19
+ out1[1] = x20
+ out1[2] = x21
+ out1[3] = x22
+}
+
+// p224Sub subtracts two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func p224Sub(out1 *p224MontgomeryDomainFieldElement, arg1 *p224MontgomeryDomainFieldElement, arg2 *p224MontgomeryDomainFieldElement) {
+ var x1 uint64
+ var x2 uint64
+ x1, x2 = bits.Sub64(arg1[0], arg2[0], uint64(0x0))
+ var x3 uint64
+ var x4 uint64
+ x3, x4 = bits.Sub64(arg1[1], arg2[1], uint64(p224Uint1(x2)))
+ var x5 uint64
+ var x6 uint64
+ x5, x6 = bits.Sub64(arg1[2], arg2[2], uint64(p224Uint1(x4)))
+ var x7 uint64
+ var x8 uint64
+ x7, x8 = bits.Sub64(arg1[3], arg2[3], uint64(p224Uint1(x6)))
+ var x9 uint64
+ p224CmovznzU64(&x9, p224Uint1(x8), uint64(0x0), 0xffffffffffffffff)
+ var x10 uint64
+ var x11 uint64
+ x10, x11 = bits.Add64(x1, uint64((p224Uint1(x9) & 0x1)), uint64(0x0))
+ var x12 uint64
+ var x13 uint64
+ x12, x13 = bits.Add64(x3, (x9 & 0xffffffff00000000), uint64(p224Uint1(x11)))
+ var x14 uint64
+ var x15 uint64
+ x14, x15 = bits.Add64(x5, x9, uint64(p224Uint1(x13)))
+ var x16 uint64
+ x16, _ = bits.Add64(x7, (x9 & 0xffffffff), uint64(p224Uint1(x15)))
+ out1[0] = x10
+ out1[1] = x12
+ out1[2] = x14
+ out1[3] = x16
+}
+
+// p224SetOne returns the field element one in the Montgomery domain.
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = 1 mod m
+// 0 ≤ eval out1 < m
+func p224SetOne(out1 *p224MontgomeryDomainFieldElement) {
+ out1[0] = 0xffffffff00000000
+ out1[1] = 0xffffffffffffffff
+ out1[2] = uint64(0x0)
+ out1[3] = uint64(0x0)
+}
+
+// p224FromMontgomery translates a field element out of the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m
+// 0 ≤ eval out1 < m
+func p224FromMontgomery(out1 *p224NonMontgomeryDomainFieldElement, arg1 *p224MontgomeryDomainFieldElement) {
+ x1 := arg1[0]
+ var x2 uint64
+ _, x2 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x4 uint64
+ var x5 uint64
+ x5, x4 = bits.Mul64(x2, 0xffffffff)
+ var x6 uint64
+ var x7 uint64
+ x7, x6 = bits.Mul64(x2, 0xffffffffffffffff)
+ var x8 uint64
+ var x9 uint64
+ x9, x8 = bits.Mul64(x2, 0xffffffff00000000)
+ var x10 uint64
+ var x11 uint64
+ x10, x11 = bits.Add64(x9, x6, uint64(0x0))
+ var x12 uint64
+ var x13 uint64
+ x12, x13 = bits.Add64(x7, x4, uint64(p224Uint1(x11)))
+ var x15 uint64
+ _, x15 = bits.Add64(x1, x2, uint64(0x0))
+ var x16 uint64
+ var x17 uint64
+ x16, x17 = bits.Add64(uint64(0x0), x8, uint64(p224Uint1(x15)))
+ var x18 uint64
+ var x19 uint64
+ x18, x19 = bits.Add64(uint64(0x0), x10, uint64(p224Uint1(x17)))
+ var x20 uint64
+ var x21 uint64
+ x20, x21 = bits.Add64(uint64(0x0), x12, uint64(p224Uint1(x19)))
+ var x22 uint64
+ var x23 uint64
+ x22, x23 = bits.Add64(x16, arg1[1], uint64(0x0))
+ var x24 uint64
+ var x25 uint64
+ x24, x25 = bits.Add64(x18, uint64(0x0), uint64(p224Uint1(x23)))
+ var x26 uint64
+ var x27 uint64
+ x26, x27 = bits.Add64(x20, uint64(0x0), uint64(p224Uint1(x25)))
+ var x28 uint64
+ _, x28 = bits.Mul64(x22, 0xffffffffffffffff)
+ var x30 uint64
+ var x31 uint64
+ x31, x30 = bits.Mul64(x28, 0xffffffff)
+ var x32 uint64
+ var x33 uint64
+ x33, x32 = bits.Mul64(x28, 0xffffffffffffffff)
+ var x34 uint64
+ var x35 uint64
+ x35, x34 = bits.Mul64(x28, 0xffffffff00000000)
+ var x36 uint64
+ var x37 uint64
+ x36, x37 = bits.Add64(x35, x32, uint64(0x0))
+ var x38 uint64
+ var x39 uint64
+ x38, x39 = bits.Add64(x33, x30, uint64(p224Uint1(x37)))
+ var x41 uint64
+ _, x41 = bits.Add64(x22, x28, uint64(0x0))
+ var x42 uint64
+ var x43 uint64
+ x42, x43 = bits.Add64(x24, x34, uint64(p224Uint1(x41)))
+ var x44 uint64
+ var x45 uint64
+ x44, x45 = bits.Add64(x26, x36, uint64(p224Uint1(x43)))
+ var x46 uint64
+ var x47 uint64
+ x46, x47 = bits.Add64((uint64(p224Uint1(x27)) + (uint64(p224Uint1(x21)) + (uint64(p224Uint1(x13)) + x5))), x38, uint64(p224Uint1(x45)))
+ var x48 uint64
+ var x49 uint64
+ x48, x49 = bits.Add64(x42, arg1[2], uint64(0x0))
+ var x50 uint64
+ var x51 uint64
+ x50, x51 = bits.Add64(x44, uint64(0x0), uint64(p224Uint1(x49)))
+ var x52 uint64
+ var x53 uint64
+ x52, x53 = bits.Add64(x46, uint64(0x0), uint64(p224Uint1(x51)))
+ var x54 uint64
+ _, x54 = bits.Mul64(x48, 0xffffffffffffffff)
+ var x56 uint64
+ var x57 uint64
+ x57, x56 = bits.Mul64(x54, 0xffffffff)
+ var x58 uint64
+ var x59 uint64
+ x59, x58 = bits.Mul64(x54, 0xffffffffffffffff)
+ var x60 uint64
+ var x61 uint64
+ x61, x60 = bits.Mul64(x54, 0xffffffff00000000)
+ var x62 uint64
+ var x63 uint64
+ x62, x63 = bits.Add64(x61, x58, uint64(0x0))
+ var x64 uint64
+ var x65 uint64
+ x64, x65 = bits.Add64(x59, x56, uint64(p224Uint1(x63)))
+ var x67 uint64
+ _, x67 = bits.Add64(x48, x54, uint64(0x0))
+ var x68 uint64
+ var x69 uint64
+ x68, x69 = bits.Add64(x50, x60, uint64(p224Uint1(x67)))
+ var x70 uint64
+ var x71 uint64
+ x70, x71 = bits.Add64(x52, x62, uint64(p224Uint1(x69)))
+ var x72 uint64
+ var x73 uint64
+ x72, x73 = bits.Add64((uint64(p224Uint1(x53)) + (uint64(p224Uint1(x47)) + (uint64(p224Uint1(x39)) + x31))), x64, uint64(p224Uint1(x71)))
+ var x74 uint64
+ var x75 uint64
+ x74, x75 = bits.Add64(x68, arg1[3], uint64(0x0))
+ var x76 uint64
+ var x77 uint64
+ x76, x77 = bits.Add64(x70, uint64(0x0), uint64(p224Uint1(x75)))
+ var x78 uint64
+ var x79 uint64
+ x78, x79 = bits.Add64(x72, uint64(0x0), uint64(p224Uint1(x77)))
+ var x80 uint64
+ _, x80 = bits.Mul64(x74, 0xffffffffffffffff)
+ var x82 uint64
+ var x83 uint64
+ x83, x82 = bits.Mul64(x80, 0xffffffff)
+ var x84 uint64
+ var x85 uint64
+ x85, x84 = bits.Mul64(x80, 0xffffffffffffffff)
+ var x86 uint64
+ var x87 uint64
+ x87, x86 = bits.Mul64(x80, 0xffffffff00000000)
+ var x88 uint64
+ var x89 uint64
+ x88, x89 = bits.Add64(x87, x84, uint64(0x0))
+ var x90 uint64
+ var x91 uint64
+ x90, x91 = bits.Add64(x85, x82, uint64(p224Uint1(x89)))
+ var x93 uint64
+ _, x93 = bits.Add64(x74, x80, uint64(0x0))
+ var x94 uint64
+ var x95 uint64
+ x94, x95 = bits.Add64(x76, x86, uint64(p224Uint1(x93)))
+ var x96 uint64
+ var x97 uint64
+ x96, x97 = bits.Add64(x78, x88, uint64(p224Uint1(x95)))
+ var x98 uint64
+ var x99 uint64
+ x98, x99 = bits.Add64((uint64(p224Uint1(x79)) + (uint64(p224Uint1(x73)) + (uint64(p224Uint1(x65)) + x57))), x90, uint64(p224Uint1(x97)))
+ x100 := (uint64(p224Uint1(x99)) + (uint64(p224Uint1(x91)) + x83))
+ var x101 uint64
+ var x102 uint64
+ x101, x102 = bits.Sub64(x94, uint64(0x1), uint64(0x0))
+ var x103 uint64
+ var x104 uint64
+ x103, x104 = bits.Sub64(x96, 0xffffffff00000000, uint64(p224Uint1(x102)))
+ var x105 uint64
+ var x106 uint64
+ x105, x106 = bits.Sub64(x98, 0xffffffffffffffff, uint64(p224Uint1(x104)))
+ var x107 uint64
+ var x108 uint64
+ x107, x108 = bits.Sub64(x100, 0xffffffff, uint64(p224Uint1(x106)))
+ var x110 uint64
+ _, x110 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(p224Uint1(x108)))
+ var x111 uint64
+ p224CmovznzU64(&x111, p224Uint1(x110), x101, x94)
+ var x112 uint64
+ p224CmovznzU64(&x112, p224Uint1(x110), x103, x96)
+ var x113 uint64
+ p224CmovznzU64(&x113, p224Uint1(x110), x105, x98)
+ var x114 uint64
+ p224CmovznzU64(&x114, p224Uint1(x110), x107, x100)
+ out1[0] = x111
+ out1[1] = x112
+ out1[2] = x113
+ out1[3] = x114
+}
+
+// p224ToMontgomery translates a field element into the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = eval arg1 mod m
+// 0 ≤ eval out1 < m
+func p224ToMontgomery(out1 *p224MontgomeryDomainFieldElement, arg1 *p224NonMontgomeryDomainFieldElement) {
+ x1 := arg1[1]
+ x2 := arg1[2]
+ x3 := arg1[3]
+ x4 := arg1[0]
+ var x5 uint64
+ var x6 uint64
+ x6, x5 = bits.Mul64(x4, 0xffffffff)
+ var x7 uint64
+ var x8 uint64
+ x8, x7 = bits.Mul64(x4, 0xfffffffe00000000)
+ var x9 uint64
+ var x10 uint64
+ x10, x9 = bits.Mul64(x4, 0xffffffff00000000)
+ var x11 uint64
+ var x12 uint64
+ x12, x11 = bits.Mul64(x4, 0xffffffff00000001)
+ var x13 uint64
+ var x14 uint64
+ x13, x14 = bits.Add64(x12, x9, uint64(0x0))
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Add64(x10, x7, uint64(p224Uint1(x14)))
+ var x17 uint64
+ var x18 uint64
+ x17, x18 = bits.Add64(x8, x5, uint64(p224Uint1(x16)))
+ var x19 uint64
+ _, x19 = bits.Mul64(x11, 0xffffffffffffffff)
+ var x21 uint64
+ var x22 uint64
+ x22, x21 = bits.Mul64(x19, 0xffffffff)
+ var x23 uint64
+ var x24 uint64
+ x24, x23 = bits.Mul64(x19, 0xffffffffffffffff)
+ var x25 uint64
+ var x26 uint64
+ x26, x25 = bits.Mul64(x19, 0xffffffff00000000)
+ var x27 uint64
+ var x28 uint64
+ x27, x28 = bits.Add64(x26, x23, uint64(0x0))
+ var x29 uint64
+ var x30 uint64
+ x29, x30 = bits.Add64(x24, x21, uint64(p224Uint1(x28)))
+ var x32 uint64
+ _, x32 = bits.Add64(x11, x19, uint64(0x0))
+ var x33 uint64
+ var x34 uint64
+ x33, x34 = bits.Add64(x13, x25, uint64(p224Uint1(x32)))
+ var x35 uint64
+ var x36 uint64
+ x35, x36 = bits.Add64(x15, x27, uint64(p224Uint1(x34)))
+ var x37 uint64
+ var x38 uint64
+ x37, x38 = bits.Add64(x17, x29, uint64(p224Uint1(x36)))
+ var x39 uint64
+ var x40 uint64
+ x40, x39 = bits.Mul64(x1, 0xffffffff)
+ var x41 uint64
+ var x42 uint64
+ x42, x41 = bits.Mul64(x1, 0xfffffffe00000000)
+ var x43 uint64
+ var x44 uint64
+ x44, x43 = bits.Mul64(x1, 0xffffffff00000000)
+ var x45 uint64
+ var x46 uint64
+ x46, x45 = bits.Mul64(x1, 0xffffffff00000001)
+ var x47 uint64
+ var x48 uint64
+ x47, x48 = bits.Add64(x46, x43, uint64(0x0))
+ var x49 uint64
+ var x50 uint64
+ x49, x50 = bits.Add64(x44, x41, uint64(p224Uint1(x48)))
+ var x51 uint64
+ var x52 uint64
+ x51, x52 = bits.Add64(x42, x39, uint64(p224Uint1(x50)))
+ var x53 uint64
+ var x54 uint64
+ x53, x54 = bits.Add64(x33, x45, uint64(0x0))
+ var x55 uint64
+ var x56 uint64
+ x55, x56 = bits.Add64(x35, x47, uint64(p224Uint1(x54)))
+ var x57 uint64
+ var x58 uint64
+ x57, x58 = bits.Add64(x37, x49, uint64(p224Uint1(x56)))
+ var x59 uint64
+ var x60 uint64
+ x59, x60 = bits.Add64(((uint64(p224Uint1(x38)) + (uint64(p224Uint1(x18)) + x6)) + (uint64(p224Uint1(x30)) + x22)), x51, uint64(p224Uint1(x58)))
+ var x61 uint64
+ _, x61 = bits.Mul64(x53, 0xffffffffffffffff)
+ var x63 uint64
+ var x64 uint64
+ x64, x63 = bits.Mul64(x61, 0xffffffff)
+ var x65 uint64
+ var x66 uint64
+ x66, x65 = bits.Mul64(x61, 0xffffffffffffffff)
+ var x67 uint64
+ var x68 uint64
+ x68, x67 = bits.Mul64(x61, 0xffffffff00000000)
+ var x69 uint64
+ var x70 uint64
+ x69, x70 = bits.Add64(x68, x65, uint64(0x0))
+ var x71 uint64
+ var x72 uint64
+ x71, x72 = bits.Add64(x66, x63, uint64(p224Uint1(x70)))
+ var x74 uint64
+ _, x74 = bits.Add64(x53, x61, uint64(0x0))
+ var x75 uint64
+ var x76 uint64
+ x75, x76 = bits.Add64(x55, x67, uint64(p224Uint1(x74)))
+ var x77 uint64
+ var x78 uint64
+ x77, x78 = bits.Add64(x57, x69, uint64(p224Uint1(x76)))
+ var x79 uint64
+ var x80 uint64
+ x79, x80 = bits.Add64(x59, x71, uint64(p224Uint1(x78)))
+ var x81 uint64
+ var x82 uint64
+ x82, x81 = bits.Mul64(x2, 0xffffffff)
+ var x83 uint64
+ var x84 uint64
+ x84, x83 = bits.Mul64(x2, 0xfffffffe00000000)
+ var x85 uint64
+ var x86 uint64
+ x86, x85 = bits.Mul64(x2, 0xffffffff00000000)
+ var x87 uint64
+ var x88 uint64
+ x88, x87 = bits.Mul64(x2, 0xffffffff00000001)
+ var x89 uint64
+ var x90 uint64
+ x89, x90 = bits.Add64(x88, x85, uint64(0x0))
+ var x91 uint64
+ var x92 uint64
+ x91, x92 = bits.Add64(x86, x83, uint64(p224Uint1(x90)))
+ var x93 uint64
+ var x94 uint64
+ x93, x94 = bits.Add64(x84, x81, uint64(p224Uint1(x92)))
+ var x95 uint64
+ var x96 uint64
+ x95, x96 = bits.Add64(x75, x87, uint64(0x0))
+ var x97 uint64
+ var x98 uint64
+ x97, x98 = bits.Add64(x77, x89, uint64(p224Uint1(x96)))
+ var x99 uint64
+ var x100 uint64
+ x99, x100 = bits.Add64(x79, x91, uint64(p224Uint1(x98)))
+ var x101 uint64
+ var x102 uint64
+ x101, x102 = bits.Add64(((uint64(p224Uint1(x80)) + (uint64(p224Uint1(x60)) + (uint64(p224Uint1(x52)) + x40))) + (uint64(p224Uint1(x72)) + x64)), x93, uint64(p224Uint1(x100)))
+ var x103 uint64
+ _, x103 = bits.Mul64(x95, 0xffffffffffffffff)
+ var x105 uint64
+ var x106 uint64
+ x106, x105 = bits.Mul64(x103, 0xffffffff)
+ var x107 uint64
+ var x108 uint64
+ x108, x107 = bits.Mul64(x103, 0xffffffffffffffff)
+ var x109 uint64
+ var x110 uint64
+ x110, x109 = bits.Mul64(x103, 0xffffffff00000000)
+ var x111 uint64
+ var x112 uint64
+ x111, x112 = bits.Add64(x110, x107, uint64(0x0))
+ var x113 uint64
+ var x114 uint64
+ x113, x114 = bits.Add64(x108, x105, uint64(p224Uint1(x112)))
+ var x116 uint64
+ _, x116 = bits.Add64(x95, x103, uint64(0x0))
+ var x117 uint64
+ var x118 uint64
+ x117, x118 = bits.Add64(x97, x109, uint64(p224Uint1(x116)))
+ var x119 uint64
+ var x120 uint64
+ x119, x120 = bits.Add64(x99, x111, uint64(p224Uint1(x118)))
+ var x121 uint64
+ var x122 uint64
+ x121, x122 = bits.Add64(x101, x113, uint64(p224Uint1(x120)))
+ var x123 uint64
+ var x124 uint64
+ x124, x123 = bits.Mul64(x3, 0xffffffff)
+ var x125 uint64
+ var x126 uint64
+ x126, x125 = bits.Mul64(x3, 0xfffffffe00000000)
+ var x127 uint64
+ var x128 uint64
+ x128, x127 = bits.Mul64(x3, 0xffffffff00000000)
+ var x129 uint64
+ var x130 uint64
+ x130, x129 = bits.Mul64(x3, 0xffffffff00000001)
+ var x131 uint64
+ var x132 uint64
+ x131, x132 = bits.Add64(x130, x127, uint64(0x0))
+ var x133 uint64
+ var x134 uint64
+ x133, x134 = bits.Add64(x128, x125, uint64(p224Uint1(x132)))
+ var x135 uint64
+ var x136 uint64
+ x135, x136 = bits.Add64(x126, x123, uint64(p224Uint1(x134)))
+ var x137 uint64
+ var x138 uint64
+ x137, x138 = bits.Add64(x117, x129, uint64(0x0))
+ var x139 uint64
+ var x140 uint64
+ x139, x140 = bits.Add64(x119, x131, uint64(p224Uint1(x138)))
+ var x141 uint64
+ var x142 uint64
+ x141, x142 = bits.Add64(x121, x133, uint64(p224Uint1(x140)))
+ var x143 uint64
+ var x144 uint64
+ x143, x144 = bits.Add64(((uint64(p224Uint1(x122)) + (uint64(p224Uint1(x102)) + (uint64(p224Uint1(x94)) + x82))) + (uint64(p224Uint1(x114)) + x106)), x135, uint64(p224Uint1(x142)))
+ var x145 uint64
+ _, x145 = bits.Mul64(x137, 0xffffffffffffffff)
+ var x147 uint64
+ var x148 uint64
+ x148, x147 = bits.Mul64(x145, 0xffffffff)
+ var x149 uint64
+ var x150 uint64
+ x150, x149 = bits.Mul64(x145, 0xffffffffffffffff)
+ var x151 uint64
+ var x152 uint64
+ x152, x151 = bits.Mul64(x145, 0xffffffff00000000)
+ var x153 uint64
+ var x154 uint64
+ x153, x154 = bits.Add64(x152, x149, uint64(0x0))
+ var x155 uint64
+ var x156 uint64
+ x155, x156 = bits.Add64(x150, x147, uint64(p224Uint1(x154)))
+ var x158 uint64
+ _, x158 = bits.Add64(x137, x145, uint64(0x0))
+ var x159 uint64
+ var x160 uint64
+ x159, x160 = bits.Add64(x139, x151, uint64(p224Uint1(x158)))
+ var x161 uint64
+ var x162 uint64
+ x161, x162 = bits.Add64(x141, x153, uint64(p224Uint1(x160)))
+ var x163 uint64
+ var x164 uint64
+ x163, x164 = bits.Add64(x143, x155, uint64(p224Uint1(x162)))
+ x165 := ((uint64(p224Uint1(x164)) + (uint64(p224Uint1(x144)) + (uint64(p224Uint1(x136)) + x124))) + (uint64(p224Uint1(x156)) + x148))
+ var x166 uint64
+ var x167 uint64
+ x166, x167 = bits.Sub64(x159, uint64(0x1), uint64(0x0))
+ var x168 uint64
+ var x169 uint64
+ x168, x169 = bits.Sub64(x161, 0xffffffff00000000, uint64(p224Uint1(x167)))
+ var x170 uint64
+ var x171 uint64
+ x170, x171 = bits.Sub64(x163, 0xffffffffffffffff, uint64(p224Uint1(x169)))
+ var x172 uint64
+ var x173 uint64
+ x172, x173 = bits.Sub64(x165, 0xffffffff, uint64(p224Uint1(x171)))
+ var x175 uint64
+ _, x175 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(p224Uint1(x173)))
+ var x176 uint64
+ p224CmovznzU64(&x176, p224Uint1(x175), x166, x159)
+ var x177 uint64
+ p224CmovznzU64(&x177, p224Uint1(x175), x168, x161)
+ var x178 uint64
+ p224CmovznzU64(&x178, p224Uint1(x175), x170, x163)
+ var x179 uint64
+ p224CmovznzU64(&x179, p224Uint1(x175), x172, x165)
+ out1[0] = x176
+ out1[1] = x177
+ out1[2] = x178
+ out1[3] = x179
+}
+
+// p224Selectznz is a multi-limb conditional select.
+//
+// Postconditions:
+//
+// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3)
+//
+// Input Bounds:
+//
+// arg1: [0x0 ~> 0x1]
+// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+//
+// Output Bounds:
+//
+// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+func p224Selectznz(out1 *[4]uint64, arg1 p224Uint1, arg2 *[4]uint64, arg3 *[4]uint64) {
+ var x1 uint64
+ p224CmovznzU64(&x1, arg1, arg2[0], arg3[0])
+ var x2 uint64
+ p224CmovznzU64(&x2, arg1, arg2[1], arg3[1])
+ var x3 uint64
+ p224CmovznzU64(&x3, arg1, arg2[2], arg3[2])
+ var x4 uint64
+ p224CmovznzU64(&x4, arg1, arg2[3], arg3[3])
+ out1[0] = x1
+ out1[1] = x2
+ out1[2] = x3
+ out1[3] = x4
+}
+
+// p224ToBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..27]
+//
+// Input Bounds:
+//
+// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffff]]
+//
+// Output Bounds:
+//
+// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]]
+func p224ToBytes(out1 *[28]uint8, arg1 *[4]uint64) {
+ x1 := arg1[3]
+ x2 := arg1[2]
+ x3 := arg1[1]
+ x4 := arg1[0]
+ x5 := (uint8(x4) & 0xff)
+ x6 := (x4 >> 8)
+ x7 := (uint8(x6) & 0xff)
+ x8 := (x6 >> 8)
+ x9 := (uint8(x8) & 0xff)
+ x10 := (x8 >> 8)
+ x11 := (uint8(x10) & 0xff)
+ x12 := (x10 >> 8)
+ x13 := (uint8(x12) & 0xff)
+ x14 := (x12 >> 8)
+ x15 := (uint8(x14) & 0xff)
+ x16 := (x14 >> 8)
+ x17 := (uint8(x16) & 0xff)
+ x18 := uint8((x16 >> 8))
+ x19 := (uint8(x3) & 0xff)
+ x20 := (x3 >> 8)
+ x21 := (uint8(x20) & 0xff)
+ x22 := (x20 >> 8)
+ x23 := (uint8(x22) & 0xff)
+ x24 := (x22 >> 8)
+ x25 := (uint8(x24) & 0xff)
+ x26 := (x24 >> 8)
+ x27 := (uint8(x26) & 0xff)
+ x28 := (x26 >> 8)
+ x29 := (uint8(x28) & 0xff)
+ x30 := (x28 >> 8)
+ x31 := (uint8(x30) & 0xff)
+ x32 := uint8((x30 >> 8))
+ x33 := (uint8(x2) & 0xff)
+ x34 := (x2 >> 8)
+ x35 := (uint8(x34) & 0xff)
+ x36 := (x34 >> 8)
+ x37 := (uint8(x36) & 0xff)
+ x38 := (x36 >> 8)
+ x39 := (uint8(x38) & 0xff)
+ x40 := (x38 >> 8)
+ x41 := (uint8(x40) & 0xff)
+ x42 := (x40 >> 8)
+ x43 := (uint8(x42) & 0xff)
+ x44 := (x42 >> 8)
+ x45 := (uint8(x44) & 0xff)
+ x46 := uint8((x44 >> 8))
+ x47 := (uint8(x1) & 0xff)
+ x48 := (x1 >> 8)
+ x49 := (uint8(x48) & 0xff)
+ x50 := (x48 >> 8)
+ x51 := (uint8(x50) & 0xff)
+ x52 := uint8((x50 >> 8))
+ out1[0] = x5
+ out1[1] = x7
+ out1[2] = x9
+ out1[3] = x11
+ out1[4] = x13
+ out1[5] = x15
+ out1[6] = x17
+ out1[7] = x18
+ out1[8] = x19
+ out1[9] = x21
+ out1[10] = x23
+ out1[11] = x25
+ out1[12] = x27
+ out1[13] = x29
+ out1[14] = x31
+ out1[15] = x32
+ out1[16] = x33
+ out1[17] = x35
+ out1[18] = x37
+ out1[19] = x39
+ out1[20] = x41
+ out1[21] = x43
+ out1[22] = x45
+ out1[23] = x46
+ out1[24] = x47
+ out1[25] = x49
+ out1[26] = x51
+ out1[27] = x52
+}
+
+// p224FromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order.
+//
+// Preconditions:
+//
+// 0 ≤ bytes_eval arg1 < m
+//
+// Postconditions:
+//
+// eval out1 mod m = bytes_eval arg1 mod m
+// 0 ≤ eval out1 < m
+//
+// Input Bounds:
+//
+// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]]
+//
+// Output Bounds:
+//
+// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffff]]
+func p224FromBytes(out1 *[4]uint64, arg1 *[28]uint8) {
+ x1 := (uint64(arg1[27]) << 24)
+ x2 := (uint64(arg1[26]) << 16)
+ x3 := (uint64(arg1[25]) << 8)
+ x4 := arg1[24]
+ x5 := (uint64(arg1[23]) << 56)
+ x6 := (uint64(arg1[22]) << 48)
+ x7 := (uint64(arg1[21]) << 40)
+ x8 := (uint64(arg1[20]) << 32)
+ x9 := (uint64(arg1[19]) << 24)
+ x10 := (uint64(arg1[18]) << 16)
+ x11 := (uint64(arg1[17]) << 8)
+ x12 := arg1[16]
+ x13 := (uint64(arg1[15]) << 56)
+ x14 := (uint64(arg1[14]) << 48)
+ x15 := (uint64(arg1[13]) << 40)
+ x16 := (uint64(arg1[12]) << 32)
+ x17 := (uint64(arg1[11]) << 24)
+ x18 := (uint64(arg1[10]) << 16)
+ x19 := (uint64(arg1[9]) << 8)
+ x20 := arg1[8]
+ x21 := (uint64(arg1[7]) << 56)
+ x22 := (uint64(arg1[6]) << 48)
+ x23 := (uint64(arg1[5]) << 40)
+ x24 := (uint64(arg1[4]) << 32)
+ x25 := (uint64(arg1[3]) << 24)
+ x26 := (uint64(arg1[2]) << 16)
+ x27 := (uint64(arg1[1]) << 8)
+ x28 := arg1[0]
+ x29 := (x27 + uint64(x28))
+ x30 := (x26 + x29)
+ x31 := (x25 + x30)
+ x32 := (x24 + x31)
+ x33 := (x23 + x32)
+ x34 := (x22 + x33)
+ x35 := (x21 + x34)
+ x36 := (x19 + uint64(x20))
+ x37 := (x18 + x36)
+ x38 := (x17 + x37)
+ x39 := (x16 + x38)
+ x40 := (x15 + x39)
+ x41 := (x14 + x40)
+ x42 := (x13 + x41)
+ x43 := (x11 + uint64(x12))
+ x44 := (x10 + x43)
+ x45 := (x9 + x44)
+ x46 := (x8 + x45)
+ x47 := (x7 + x46)
+ x48 := (x6 + x47)
+ x49 := (x5 + x48)
+ x50 := (x3 + uint64(x4))
+ x51 := (x2 + x50)
+ x52 := (x1 + x51)
+ out1[0] = x35
+ out1[1] = x42
+ out1[2] = x49
+ out1[3] = x52
+}
diff --git a/src/crypto/internal/nistec/fiat/p224_invert.go b/src/crypto/internal/nistec/fiat/p224_invert.go
new file mode 100644
index 0000000..3cf5286
--- /dev/null
+++ b/src/crypto/internal/nistec/fiat/p224_invert.go
@@ -0,0 +1,87 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by addchain. DO NOT EDIT.
+
+package fiat
+
+// Invert sets e = 1/x, and returns e.
+//
+// If x == 0, Invert returns e = 0.
+func (e *P224Element) Invert(x *P224Element) *P224Element {
+ // Inversion is implemented as exponentiation with exponent p − 2.
+ // The sequence of 11 multiplications and 223 squarings is derived from the
+ // following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
+ //
+ // _10 = 2*1
+ // _11 = 1 + _10
+ // _110 = 2*_11
+ // _111 = 1 + _110
+ // _111000 = _111 << 3
+ // _111111 = _111 + _111000
+ // x12 = _111111 << 6 + _111111
+ // x14 = x12 << 2 + _11
+ // x17 = x14 << 3 + _111
+ // x31 = x17 << 14 + x14
+ // x48 = x31 << 17 + x17
+ // x96 = x48 << 48 + x48
+ // x127 = x96 << 31 + x31
+ // return x127 << 97 + x96
+ //
+
+ var z = new(P224Element).Set(e)
+ var t0 = new(P224Element)
+ var t1 = new(P224Element)
+ var t2 = new(P224Element)
+
+ z.Square(x)
+ t0.Mul(x, z)
+ z.Square(t0)
+ z.Mul(x, z)
+ t1.Square(z)
+ for s := 1; s < 3; s++ {
+ t1.Square(t1)
+ }
+ t1.Mul(z, t1)
+ t2.Square(t1)
+ for s := 1; s < 6; s++ {
+ t2.Square(t2)
+ }
+ t1.Mul(t1, t2)
+ for s := 0; s < 2; s++ {
+ t1.Square(t1)
+ }
+ t0.Mul(t0, t1)
+ t1.Square(t0)
+ for s := 1; s < 3; s++ {
+ t1.Square(t1)
+ }
+ z.Mul(z, t1)
+ t1.Square(z)
+ for s := 1; s < 14; s++ {
+ t1.Square(t1)
+ }
+ t0.Mul(t0, t1)
+ t1.Square(t0)
+ for s := 1; s < 17; s++ {
+ t1.Square(t1)
+ }
+ z.Mul(z, t1)
+ t1.Square(z)
+ for s := 1; s < 48; s++ {
+ t1.Square(t1)
+ }
+ z.Mul(z, t1)
+ t1.Square(z)
+ for s := 1; s < 31; s++ {
+ t1.Square(t1)
+ }
+ t0.Mul(t0, t1)
+ for s := 0; s < 97; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+
+ return e.Set(z)
+}
diff --git a/src/crypto/internal/nistec/fiat/p256.go b/src/crypto/internal/nistec/fiat/p256.go
new file mode 100644
index 0000000..7705904
--- /dev/null
+++ b/src/crypto/internal/nistec/fiat/p256.go
@@ -0,0 +1,134 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by generate.go. DO NOT EDIT.
+
+package fiat
+
+import (
+ "crypto/subtle"
+ "errors"
+)
+
+// P256Element is an integer modulo 2^256 - 2^224 + 2^192 + 2^96 - 1.
+//
+// The zero value is a valid zero element.
+type P256Element struct {
+ // Values are represented internally always in the Montgomery domain, and
+ // converted in Bytes and SetBytes.
+ x p256MontgomeryDomainFieldElement
+}
+
+const p256ElementLen = 32
+
+type p256UntypedFieldElement = [4]uint64
+
+// One sets e = 1, and returns e.
+func (e *P256Element) One() *P256Element {
+ p256SetOne(&e.x)
+ return e
+}
+
+// Equal returns 1 if e == t, and zero otherwise.
+func (e *P256Element) Equal(t *P256Element) int {
+ eBytes := e.Bytes()
+ tBytes := t.Bytes()
+ return subtle.ConstantTimeCompare(eBytes, tBytes)
+}
+
+// IsZero returns 1 if e == 0, and zero otherwise.
+func (e *P256Element) IsZero() int {
+ zero := make([]byte, p256ElementLen)
+ eBytes := e.Bytes()
+ return subtle.ConstantTimeCompare(eBytes, zero)
+}
+
+// Set sets e = t, and returns e.
+func (e *P256Element) Set(t *P256Element) *P256Element {
+ e.x = t.x
+ return e
+}
+
+// Bytes returns the 32-byte big-endian encoding of e.
+func (e *P256Element) Bytes() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [p256ElementLen]byte
+ return e.bytes(&out)
+}
+
+func (e *P256Element) bytes(out *[p256ElementLen]byte) []byte {
+ var tmp p256NonMontgomeryDomainFieldElement
+ p256FromMontgomery(&tmp, &e.x)
+ p256ToBytes(out, (*p256UntypedFieldElement)(&tmp))
+ p256InvertEndianness(out[:])
+ return out[:]
+}
+
+// SetBytes sets e = v, where v is a big-endian 32-byte encoding, and returns e.
+// If v is not 32 bytes or it encodes a value higher than 2^256 - 2^224 + 2^192 + 2^96 - 1,
+// SetBytes returns nil and an error, and e is unchanged.
+func (e *P256Element) SetBytes(v []byte) (*P256Element, error) {
+ if len(v) != p256ElementLen {
+ return nil, errors.New("invalid P256Element encoding")
+ }
+
+ // Check for non-canonical encodings (p + k, 2p + k, etc.) by comparing to
+ // the encoding of -1 mod p, so p - 1, the highest canonical encoding.
+ var minusOneEncoding = new(P256Element).Sub(
+ new(P256Element), new(P256Element).One()).Bytes()
+ for i := range v {
+ if v[i] < minusOneEncoding[i] {
+ break
+ }
+ if v[i] > minusOneEncoding[i] {
+ return nil, errors.New("invalid P256Element encoding")
+ }
+ }
+
+ var in [p256ElementLen]byte
+ copy(in[:], v)
+ p256InvertEndianness(in[:])
+ var tmp p256NonMontgomeryDomainFieldElement
+ p256FromBytes((*p256UntypedFieldElement)(&tmp), &in)
+ p256ToMontgomery(&e.x, &tmp)
+ return e, nil
+}
+
+// Add sets e = t1 + t2, and returns e.
+func (e *P256Element) Add(t1, t2 *P256Element) *P256Element {
+ p256Add(&e.x, &t1.x, &t2.x)
+ return e
+}
+
+// Sub sets e = t1 - t2, and returns e.
+func (e *P256Element) Sub(t1, t2 *P256Element) *P256Element {
+ p256Sub(&e.x, &t1.x, &t2.x)
+ return e
+}
+
+// Mul sets e = t1 * t2, and returns e.
+func (e *P256Element) Mul(t1, t2 *P256Element) *P256Element {
+ p256Mul(&e.x, &t1.x, &t2.x)
+ return e
+}
+
+// Square sets e = t * t, and returns e.
+func (e *P256Element) Square(t *P256Element) *P256Element {
+ p256Square(&e.x, &t.x)
+ return e
+}
+
+// Select sets v to a if cond == 1, and to b if cond == 0.
+func (v *P256Element) Select(a, b *P256Element, cond int) *P256Element {
+ p256Selectznz((*p256UntypedFieldElement)(&v.x), p256Uint1(cond),
+ (*p256UntypedFieldElement)(&b.x), (*p256UntypedFieldElement)(&a.x))
+ return v
+}
+
+func p256InvertEndianness(v []byte) {
+ for i := 0; i < len(v)/2; i++ {
+ v[i], v[len(v)-1-i] = v[len(v)-1-i], v[i]
+ }
+}
diff --git a/src/crypto/internal/nistec/fiat/p256_fiat64.go b/src/crypto/internal/nistec/fiat/p256_fiat64.go
new file mode 100644
index 0000000..75352d5
--- /dev/null
+++ b/src/crypto/internal/nistec/fiat/p256_fiat64.go
@@ -0,0 +1,1400 @@
+// Code generated by Fiat Cryptography. DO NOT EDIT.
+//
+// Autogenerated: word_by_word_montgomery --lang Go --no-wide-int --cmovznz-by-mul --relax-primitive-carry-to-bitwidth 32,64 --internal-static --public-function-case camelCase --public-type-case camelCase --private-function-case camelCase --private-type-case camelCase --doc-text-before-function-name '' --doc-newline-before-package-declaration --doc-prepend-header 'Code generated by Fiat Cryptography. DO NOT EDIT.' --package-name fiat --no-prefix-fiat p256 64 '2^256 - 2^224 + 2^192 + 2^96 - 1' mul square add sub one from_montgomery to_montgomery selectznz to_bytes from_bytes
+//
+// curve description: p256
+//
+// machine_wordsize = 64 (from "64")
+//
+// requested operations: mul, square, add, sub, one, from_montgomery, to_montgomery, selectznz, to_bytes, from_bytes
+//
+// m = 0xffffffff00000001000000000000000000000000ffffffffffffffffffffffff (from "2^256 - 2^224 + 2^192 + 2^96 - 1")
+//
+//
+//
+// NOTE: In addition to the bounds specified above each function, all
+//
+// functions synthesized for this Montgomery arithmetic require the
+//
+// input to be strictly less than the prime modulus (m), and also
+//
+// require the input to be in the unique saturated representation.
+//
+// All functions also ensure that these two properties are true of
+//
+// return values.
+//
+//
+//
+// Computed values:
+//
+// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192)
+//
+// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248)
+//
+// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) in
+//
+// if x1 & (2^256-1) < 2^255 then x1 & (2^256-1) else (x1 & (2^256-1)) - 2^256
+
+package fiat
+
+import "math/bits"
+
+type p256Uint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927
+type p256Int1 int64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927
+
+// The type p256MontgomeryDomainFieldElement is a field element in the Montgomery domain.
+//
+// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+type p256MontgomeryDomainFieldElement [4]uint64
+
+// The type p256NonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain.
+//
+// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+type p256NonMontgomeryDomainFieldElement [4]uint64
+
+// p256CmovznzU64 is a single-word conditional move.
+//
+// Postconditions:
+//
+// out1 = (if arg1 = 0 then arg2 else arg3)
+//
+// Input Bounds:
+//
+// arg1: [0x0 ~> 0x1]
+// arg2: [0x0 ~> 0xffffffffffffffff]
+// arg3: [0x0 ~> 0xffffffffffffffff]
+//
+// Output Bounds:
+//
+// out1: [0x0 ~> 0xffffffffffffffff]
+func p256CmovznzU64(out1 *uint64, arg1 p256Uint1, arg2 uint64, arg3 uint64) {
+ x1 := (uint64(arg1) * 0xffffffffffffffff)
+ x2 := ((x1 & arg3) | ((^x1) & arg2))
+ *out1 = x2
+}
+
+// p256Mul multiplies two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func p256Mul(out1 *p256MontgomeryDomainFieldElement, arg1 *p256MontgomeryDomainFieldElement, arg2 *p256MontgomeryDomainFieldElement) {
+ x1 := arg1[1]
+ x2 := arg1[2]
+ x3 := arg1[3]
+ x4 := arg1[0]
+ var x5 uint64
+ var x6 uint64
+ x6, x5 = bits.Mul64(x4, arg2[3])
+ var x7 uint64
+ var x8 uint64
+ x8, x7 = bits.Mul64(x4, arg2[2])
+ var x9 uint64
+ var x10 uint64
+ x10, x9 = bits.Mul64(x4, arg2[1])
+ var x11 uint64
+ var x12 uint64
+ x12, x11 = bits.Mul64(x4, arg2[0])
+ var x13 uint64
+ var x14 uint64
+ x13, x14 = bits.Add64(x12, x9, uint64(0x0))
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Add64(x10, x7, uint64(p256Uint1(x14)))
+ var x17 uint64
+ var x18 uint64
+ x17, x18 = bits.Add64(x8, x5, uint64(p256Uint1(x16)))
+ x19 := (uint64(p256Uint1(x18)) + x6)
+ var x20 uint64
+ var x21 uint64
+ x21, x20 = bits.Mul64(x11, 0xffffffff00000001)
+ var x22 uint64
+ var x23 uint64
+ x23, x22 = bits.Mul64(x11, 0xffffffff)
+ var x24 uint64
+ var x25 uint64
+ x25, x24 = bits.Mul64(x11, 0xffffffffffffffff)
+ var x26 uint64
+ var x27 uint64
+ x26, x27 = bits.Add64(x25, x22, uint64(0x0))
+ x28 := (uint64(p256Uint1(x27)) + x23)
+ var x30 uint64
+ _, x30 = bits.Add64(x11, x24, uint64(0x0))
+ var x31 uint64
+ var x32 uint64
+ x31, x32 = bits.Add64(x13, x26, uint64(p256Uint1(x30)))
+ var x33 uint64
+ var x34 uint64
+ x33, x34 = bits.Add64(x15, x28, uint64(p256Uint1(x32)))
+ var x35 uint64
+ var x36 uint64
+ x35, x36 = bits.Add64(x17, x20, uint64(p256Uint1(x34)))
+ var x37 uint64
+ var x38 uint64
+ x37, x38 = bits.Add64(x19, x21, uint64(p256Uint1(x36)))
+ var x39 uint64
+ var x40 uint64
+ x40, x39 = bits.Mul64(x1, arg2[3])
+ var x41 uint64
+ var x42 uint64
+ x42, x41 = bits.Mul64(x1, arg2[2])
+ var x43 uint64
+ var x44 uint64
+ x44, x43 = bits.Mul64(x1, arg2[1])
+ var x45 uint64
+ var x46 uint64
+ x46, x45 = bits.Mul64(x1, arg2[0])
+ var x47 uint64
+ var x48 uint64
+ x47, x48 = bits.Add64(x46, x43, uint64(0x0))
+ var x49 uint64
+ var x50 uint64
+ x49, x50 = bits.Add64(x44, x41, uint64(p256Uint1(x48)))
+ var x51 uint64
+ var x52 uint64
+ x51, x52 = bits.Add64(x42, x39, uint64(p256Uint1(x50)))
+ x53 := (uint64(p256Uint1(x52)) + x40)
+ var x54 uint64
+ var x55 uint64
+ x54, x55 = bits.Add64(x31, x45, uint64(0x0))
+ var x56 uint64
+ var x57 uint64
+ x56, x57 = bits.Add64(x33, x47, uint64(p256Uint1(x55)))
+ var x58 uint64
+ var x59 uint64
+ x58, x59 = bits.Add64(x35, x49, uint64(p256Uint1(x57)))
+ var x60 uint64
+ var x61 uint64
+ x60, x61 = bits.Add64(x37, x51, uint64(p256Uint1(x59)))
+ var x62 uint64
+ var x63 uint64
+ x62, x63 = bits.Add64(uint64(p256Uint1(x38)), x53, uint64(p256Uint1(x61)))
+ var x64 uint64
+ var x65 uint64
+ x65, x64 = bits.Mul64(x54, 0xffffffff00000001)
+ var x66 uint64
+ var x67 uint64
+ x67, x66 = bits.Mul64(x54, 0xffffffff)
+ var x68 uint64
+ var x69 uint64
+ x69, x68 = bits.Mul64(x54, 0xffffffffffffffff)
+ var x70 uint64
+ var x71 uint64
+ x70, x71 = bits.Add64(x69, x66, uint64(0x0))
+ x72 := (uint64(p256Uint1(x71)) + x67)
+ var x74 uint64
+ _, x74 = bits.Add64(x54, x68, uint64(0x0))
+ var x75 uint64
+ var x76 uint64
+ x75, x76 = bits.Add64(x56, x70, uint64(p256Uint1(x74)))
+ var x77 uint64
+ var x78 uint64
+ x77, x78 = bits.Add64(x58, x72, uint64(p256Uint1(x76)))
+ var x79 uint64
+ var x80 uint64
+ x79, x80 = bits.Add64(x60, x64, uint64(p256Uint1(x78)))
+ var x81 uint64
+ var x82 uint64
+ x81, x82 = bits.Add64(x62, x65, uint64(p256Uint1(x80)))
+ x83 := (uint64(p256Uint1(x82)) + uint64(p256Uint1(x63)))
+ var x84 uint64
+ var x85 uint64
+ x85, x84 = bits.Mul64(x2, arg2[3])
+ var x86 uint64
+ var x87 uint64
+ x87, x86 = bits.Mul64(x2, arg2[2])
+ var x88 uint64
+ var x89 uint64
+ x89, x88 = bits.Mul64(x2, arg2[1])
+ var x90 uint64
+ var x91 uint64
+ x91, x90 = bits.Mul64(x2, arg2[0])
+ var x92 uint64
+ var x93 uint64
+ x92, x93 = bits.Add64(x91, x88, uint64(0x0))
+ var x94 uint64
+ var x95 uint64
+ x94, x95 = bits.Add64(x89, x86, uint64(p256Uint1(x93)))
+ var x96 uint64
+ var x97 uint64
+ x96, x97 = bits.Add64(x87, x84, uint64(p256Uint1(x95)))
+ x98 := (uint64(p256Uint1(x97)) + x85)
+ var x99 uint64
+ var x100 uint64
+ x99, x100 = bits.Add64(x75, x90, uint64(0x0))
+ var x101 uint64
+ var x102 uint64
+ x101, x102 = bits.Add64(x77, x92, uint64(p256Uint1(x100)))
+ var x103 uint64
+ var x104 uint64
+ x103, x104 = bits.Add64(x79, x94, uint64(p256Uint1(x102)))
+ var x105 uint64
+ var x106 uint64
+ x105, x106 = bits.Add64(x81, x96, uint64(p256Uint1(x104)))
+ var x107 uint64
+ var x108 uint64
+ x107, x108 = bits.Add64(x83, x98, uint64(p256Uint1(x106)))
+ var x109 uint64
+ var x110 uint64
+ x110, x109 = bits.Mul64(x99, 0xffffffff00000001)
+ var x111 uint64
+ var x112 uint64
+ x112, x111 = bits.Mul64(x99, 0xffffffff)
+ var x113 uint64
+ var x114 uint64
+ x114, x113 = bits.Mul64(x99, 0xffffffffffffffff)
+ var x115 uint64
+ var x116 uint64
+ x115, x116 = bits.Add64(x114, x111, uint64(0x0))
+ x117 := (uint64(p256Uint1(x116)) + x112)
+ var x119 uint64
+ _, x119 = bits.Add64(x99, x113, uint64(0x0))
+ var x120 uint64
+ var x121 uint64
+ x120, x121 = bits.Add64(x101, x115, uint64(p256Uint1(x119)))
+ var x122 uint64
+ var x123 uint64
+ x122, x123 = bits.Add64(x103, x117, uint64(p256Uint1(x121)))
+ var x124 uint64
+ var x125 uint64
+ x124, x125 = bits.Add64(x105, x109, uint64(p256Uint1(x123)))
+ var x126 uint64
+ var x127 uint64
+ x126, x127 = bits.Add64(x107, x110, uint64(p256Uint1(x125)))
+ x128 := (uint64(p256Uint1(x127)) + uint64(p256Uint1(x108)))
+ var x129 uint64
+ var x130 uint64
+ x130, x129 = bits.Mul64(x3, arg2[3])
+ var x131 uint64
+ var x132 uint64
+ x132, x131 = bits.Mul64(x3, arg2[2])
+ var x133 uint64
+ var x134 uint64
+ x134, x133 = bits.Mul64(x3, arg2[1])
+ var x135 uint64
+ var x136 uint64
+ x136, x135 = bits.Mul64(x3, arg2[0])
+ var x137 uint64
+ var x138 uint64
+ x137, x138 = bits.Add64(x136, x133, uint64(0x0))
+ var x139 uint64
+ var x140 uint64
+ x139, x140 = bits.Add64(x134, x131, uint64(p256Uint1(x138)))
+ var x141 uint64
+ var x142 uint64
+ x141, x142 = bits.Add64(x132, x129, uint64(p256Uint1(x140)))
+ x143 := (uint64(p256Uint1(x142)) + x130)
+ var x144 uint64
+ var x145 uint64
+ x144, x145 = bits.Add64(x120, x135, uint64(0x0))
+ var x146 uint64
+ var x147 uint64
+ x146, x147 = bits.Add64(x122, x137, uint64(p256Uint1(x145)))
+ var x148 uint64
+ var x149 uint64
+ x148, x149 = bits.Add64(x124, x139, uint64(p256Uint1(x147)))
+ var x150 uint64
+ var x151 uint64
+ x150, x151 = bits.Add64(x126, x141, uint64(p256Uint1(x149)))
+ var x152 uint64
+ var x153 uint64
+ x152, x153 = bits.Add64(x128, x143, uint64(p256Uint1(x151)))
+ var x154 uint64
+ var x155 uint64
+ x155, x154 = bits.Mul64(x144, 0xffffffff00000001)
+ var x156 uint64
+ var x157 uint64
+ x157, x156 = bits.Mul64(x144, 0xffffffff)
+ var x158 uint64
+ var x159 uint64
+ x159, x158 = bits.Mul64(x144, 0xffffffffffffffff)
+ var x160 uint64
+ var x161 uint64
+ x160, x161 = bits.Add64(x159, x156, uint64(0x0))
+ x162 := (uint64(p256Uint1(x161)) + x157)
+ var x164 uint64
+ _, x164 = bits.Add64(x144, x158, uint64(0x0))
+ var x165 uint64
+ var x166 uint64
+ x165, x166 = bits.Add64(x146, x160, uint64(p256Uint1(x164)))
+ var x167 uint64
+ var x168 uint64
+ x167, x168 = bits.Add64(x148, x162, uint64(p256Uint1(x166)))
+ var x169 uint64
+ var x170 uint64
+ x169, x170 = bits.Add64(x150, x154, uint64(p256Uint1(x168)))
+ var x171 uint64
+ var x172 uint64
+ x171, x172 = bits.Add64(x152, x155, uint64(p256Uint1(x170)))
+ x173 := (uint64(p256Uint1(x172)) + uint64(p256Uint1(x153)))
+ var x174 uint64
+ var x175 uint64
+ x174, x175 = bits.Sub64(x165, 0xffffffffffffffff, uint64(0x0))
+ var x176 uint64
+ var x177 uint64
+ x176, x177 = bits.Sub64(x167, 0xffffffff, uint64(p256Uint1(x175)))
+ var x178 uint64
+ var x179 uint64
+ x178, x179 = bits.Sub64(x169, uint64(0x0), uint64(p256Uint1(x177)))
+ var x180 uint64
+ var x181 uint64
+ x180, x181 = bits.Sub64(x171, 0xffffffff00000001, uint64(p256Uint1(x179)))
+ var x183 uint64
+ _, x183 = bits.Sub64(x173, uint64(0x0), uint64(p256Uint1(x181)))
+ var x184 uint64
+ p256CmovznzU64(&x184, p256Uint1(x183), x174, x165)
+ var x185 uint64
+ p256CmovznzU64(&x185, p256Uint1(x183), x176, x167)
+ var x186 uint64
+ p256CmovznzU64(&x186, p256Uint1(x183), x178, x169)
+ var x187 uint64
+ p256CmovznzU64(&x187, p256Uint1(x183), x180, x171)
+ out1[0] = x184
+ out1[1] = x185
+ out1[2] = x186
+ out1[3] = x187
+}
+
+// p256Square squares a field element in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m
+// 0 ≤ eval out1 < m
+func p256Square(out1 *p256MontgomeryDomainFieldElement, arg1 *p256MontgomeryDomainFieldElement) {
+ x1 := arg1[1]
+ x2 := arg1[2]
+ x3 := arg1[3]
+ x4 := arg1[0]
+ var x5 uint64
+ var x6 uint64
+ x6, x5 = bits.Mul64(x4, arg1[3])
+ var x7 uint64
+ var x8 uint64
+ x8, x7 = bits.Mul64(x4, arg1[2])
+ var x9 uint64
+ var x10 uint64
+ x10, x9 = bits.Mul64(x4, arg1[1])
+ var x11 uint64
+ var x12 uint64
+ x12, x11 = bits.Mul64(x4, arg1[0])
+ var x13 uint64
+ var x14 uint64
+ x13, x14 = bits.Add64(x12, x9, uint64(0x0))
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Add64(x10, x7, uint64(p256Uint1(x14)))
+ var x17 uint64
+ var x18 uint64
+ x17, x18 = bits.Add64(x8, x5, uint64(p256Uint1(x16)))
+ x19 := (uint64(p256Uint1(x18)) + x6)
+ var x20 uint64
+ var x21 uint64
+ x21, x20 = bits.Mul64(x11, 0xffffffff00000001)
+ var x22 uint64
+ var x23 uint64
+ x23, x22 = bits.Mul64(x11, 0xffffffff)
+ var x24 uint64
+ var x25 uint64
+ x25, x24 = bits.Mul64(x11, 0xffffffffffffffff)
+ var x26 uint64
+ var x27 uint64
+ x26, x27 = bits.Add64(x25, x22, uint64(0x0))
+ x28 := (uint64(p256Uint1(x27)) + x23)
+ var x30 uint64
+ _, x30 = bits.Add64(x11, x24, uint64(0x0))
+ var x31 uint64
+ var x32 uint64
+ x31, x32 = bits.Add64(x13, x26, uint64(p256Uint1(x30)))
+ var x33 uint64
+ var x34 uint64
+ x33, x34 = bits.Add64(x15, x28, uint64(p256Uint1(x32)))
+ var x35 uint64
+ var x36 uint64
+ x35, x36 = bits.Add64(x17, x20, uint64(p256Uint1(x34)))
+ var x37 uint64
+ var x38 uint64
+ x37, x38 = bits.Add64(x19, x21, uint64(p256Uint1(x36)))
+ var x39 uint64
+ var x40 uint64
+ x40, x39 = bits.Mul64(x1, arg1[3])
+ var x41 uint64
+ var x42 uint64
+ x42, x41 = bits.Mul64(x1, arg1[2])
+ var x43 uint64
+ var x44 uint64
+ x44, x43 = bits.Mul64(x1, arg1[1])
+ var x45 uint64
+ var x46 uint64
+ x46, x45 = bits.Mul64(x1, arg1[0])
+ var x47 uint64
+ var x48 uint64
+ x47, x48 = bits.Add64(x46, x43, uint64(0x0))
+ var x49 uint64
+ var x50 uint64
+ x49, x50 = bits.Add64(x44, x41, uint64(p256Uint1(x48)))
+ var x51 uint64
+ var x52 uint64
+ x51, x52 = bits.Add64(x42, x39, uint64(p256Uint1(x50)))
+ x53 := (uint64(p256Uint1(x52)) + x40)
+ var x54 uint64
+ var x55 uint64
+ x54, x55 = bits.Add64(x31, x45, uint64(0x0))
+ var x56 uint64
+ var x57 uint64
+ x56, x57 = bits.Add64(x33, x47, uint64(p256Uint1(x55)))
+ var x58 uint64
+ var x59 uint64
+ x58, x59 = bits.Add64(x35, x49, uint64(p256Uint1(x57)))
+ var x60 uint64
+ var x61 uint64
+ x60, x61 = bits.Add64(x37, x51, uint64(p256Uint1(x59)))
+ var x62 uint64
+ var x63 uint64
+ x62, x63 = bits.Add64(uint64(p256Uint1(x38)), x53, uint64(p256Uint1(x61)))
+ var x64 uint64
+ var x65 uint64
+ x65, x64 = bits.Mul64(x54, 0xffffffff00000001)
+ var x66 uint64
+ var x67 uint64
+ x67, x66 = bits.Mul64(x54, 0xffffffff)
+ var x68 uint64
+ var x69 uint64
+ x69, x68 = bits.Mul64(x54, 0xffffffffffffffff)
+ var x70 uint64
+ var x71 uint64
+ x70, x71 = bits.Add64(x69, x66, uint64(0x0))
+ x72 := (uint64(p256Uint1(x71)) + x67)
+ var x74 uint64
+ _, x74 = bits.Add64(x54, x68, uint64(0x0))
+ var x75 uint64
+ var x76 uint64
+ x75, x76 = bits.Add64(x56, x70, uint64(p256Uint1(x74)))
+ var x77 uint64
+ var x78 uint64
+ x77, x78 = bits.Add64(x58, x72, uint64(p256Uint1(x76)))
+ var x79 uint64
+ var x80 uint64
+ x79, x80 = bits.Add64(x60, x64, uint64(p256Uint1(x78)))
+ var x81 uint64
+ var x82 uint64
+ x81, x82 = bits.Add64(x62, x65, uint64(p256Uint1(x80)))
+ x83 := (uint64(p256Uint1(x82)) + uint64(p256Uint1(x63)))
+ var x84 uint64
+ var x85 uint64
+ x85, x84 = bits.Mul64(x2, arg1[3])
+ var x86 uint64
+ var x87 uint64
+ x87, x86 = bits.Mul64(x2, arg1[2])
+ var x88 uint64
+ var x89 uint64
+ x89, x88 = bits.Mul64(x2, arg1[1])
+ var x90 uint64
+ var x91 uint64
+ x91, x90 = bits.Mul64(x2, arg1[0])
+ var x92 uint64
+ var x93 uint64
+ x92, x93 = bits.Add64(x91, x88, uint64(0x0))
+ var x94 uint64
+ var x95 uint64
+ x94, x95 = bits.Add64(x89, x86, uint64(p256Uint1(x93)))
+ var x96 uint64
+ var x97 uint64
+ x96, x97 = bits.Add64(x87, x84, uint64(p256Uint1(x95)))
+ x98 := (uint64(p256Uint1(x97)) + x85)
+ var x99 uint64
+ var x100 uint64
+ x99, x100 = bits.Add64(x75, x90, uint64(0x0))
+ var x101 uint64
+ var x102 uint64
+ x101, x102 = bits.Add64(x77, x92, uint64(p256Uint1(x100)))
+ var x103 uint64
+ var x104 uint64
+ x103, x104 = bits.Add64(x79, x94, uint64(p256Uint1(x102)))
+ var x105 uint64
+ var x106 uint64
+ x105, x106 = bits.Add64(x81, x96, uint64(p256Uint1(x104)))
+ var x107 uint64
+ var x108 uint64
+ x107, x108 = bits.Add64(x83, x98, uint64(p256Uint1(x106)))
+ var x109 uint64
+ var x110 uint64
+ x110, x109 = bits.Mul64(x99, 0xffffffff00000001)
+ var x111 uint64
+ var x112 uint64
+ x112, x111 = bits.Mul64(x99, 0xffffffff)
+ var x113 uint64
+ var x114 uint64
+ x114, x113 = bits.Mul64(x99, 0xffffffffffffffff)
+ var x115 uint64
+ var x116 uint64
+ x115, x116 = bits.Add64(x114, x111, uint64(0x0))
+ x117 := (uint64(p256Uint1(x116)) + x112)
+ var x119 uint64
+ _, x119 = bits.Add64(x99, x113, uint64(0x0))
+ var x120 uint64
+ var x121 uint64
+ x120, x121 = bits.Add64(x101, x115, uint64(p256Uint1(x119)))
+ var x122 uint64
+ var x123 uint64
+ x122, x123 = bits.Add64(x103, x117, uint64(p256Uint1(x121)))
+ var x124 uint64
+ var x125 uint64
+ x124, x125 = bits.Add64(x105, x109, uint64(p256Uint1(x123)))
+ var x126 uint64
+ var x127 uint64
+ x126, x127 = bits.Add64(x107, x110, uint64(p256Uint1(x125)))
+ x128 := (uint64(p256Uint1(x127)) + uint64(p256Uint1(x108)))
+ var x129 uint64
+ var x130 uint64
+ x130, x129 = bits.Mul64(x3, arg1[3])
+ var x131 uint64
+ var x132 uint64
+ x132, x131 = bits.Mul64(x3, arg1[2])
+ var x133 uint64
+ var x134 uint64
+ x134, x133 = bits.Mul64(x3, arg1[1])
+ var x135 uint64
+ var x136 uint64
+ x136, x135 = bits.Mul64(x3, arg1[0])
+ var x137 uint64
+ var x138 uint64
+ x137, x138 = bits.Add64(x136, x133, uint64(0x0))
+ var x139 uint64
+ var x140 uint64
+ x139, x140 = bits.Add64(x134, x131, uint64(p256Uint1(x138)))
+ var x141 uint64
+ var x142 uint64
+ x141, x142 = bits.Add64(x132, x129, uint64(p256Uint1(x140)))
+ x143 := (uint64(p256Uint1(x142)) + x130)
+ var x144 uint64
+ var x145 uint64
+ x144, x145 = bits.Add64(x120, x135, uint64(0x0))
+ var x146 uint64
+ var x147 uint64
+ x146, x147 = bits.Add64(x122, x137, uint64(p256Uint1(x145)))
+ var x148 uint64
+ var x149 uint64
+ x148, x149 = bits.Add64(x124, x139, uint64(p256Uint1(x147)))
+ var x150 uint64
+ var x151 uint64
+ x150, x151 = bits.Add64(x126, x141, uint64(p256Uint1(x149)))
+ var x152 uint64
+ var x153 uint64
+ x152, x153 = bits.Add64(x128, x143, uint64(p256Uint1(x151)))
+ var x154 uint64
+ var x155 uint64
+ x155, x154 = bits.Mul64(x144, 0xffffffff00000001)
+ var x156 uint64
+ var x157 uint64
+ x157, x156 = bits.Mul64(x144, 0xffffffff)
+ var x158 uint64
+ var x159 uint64
+ x159, x158 = bits.Mul64(x144, 0xffffffffffffffff)
+ var x160 uint64
+ var x161 uint64
+ x160, x161 = bits.Add64(x159, x156, uint64(0x0))
+ x162 := (uint64(p256Uint1(x161)) + x157)
+ var x164 uint64
+ _, x164 = bits.Add64(x144, x158, uint64(0x0))
+ var x165 uint64
+ var x166 uint64
+ x165, x166 = bits.Add64(x146, x160, uint64(p256Uint1(x164)))
+ var x167 uint64
+ var x168 uint64
+ x167, x168 = bits.Add64(x148, x162, uint64(p256Uint1(x166)))
+ var x169 uint64
+ var x170 uint64
+ x169, x170 = bits.Add64(x150, x154, uint64(p256Uint1(x168)))
+ var x171 uint64
+ var x172 uint64
+ x171, x172 = bits.Add64(x152, x155, uint64(p256Uint1(x170)))
+ x173 := (uint64(p256Uint1(x172)) + uint64(p256Uint1(x153)))
+ var x174 uint64
+ var x175 uint64
+ x174, x175 = bits.Sub64(x165, 0xffffffffffffffff, uint64(0x0))
+ var x176 uint64
+ var x177 uint64
+ x176, x177 = bits.Sub64(x167, 0xffffffff, uint64(p256Uint1(x175)))
+ var x178 uint64
+ var x179 uint64
+ x178, x179 = bits.Sub64(x169, uint64(0x0), uint64(p256Uint1(x177)))
+ var x180 uint64
+ var x181 uint64
+ x180, x181 = bits.Sub64(x171, 0xffffffff00000001, uint64(p256Uint1(x179)))
+ var x183 uint64
+ _, x183 = bits.Sub64(x173, uint64(0x0), uint64(p256Uint1(x181)))
+ var x184 uint64
+ p256CmovznzU64(&x184, p256Uint1(x183), x174, x165)
+ var x185 uint64
+ p256CmovznzU64(&x185, p256Uint1(x183), x176, x167)
+ var x186 uint64
+ p256CmovznzU64(&x186, p256Uint1(x183), x178, x169)
+ var x187 uint64
+ p256CmovznzU64(&x187, p256Uint1(x183), x180, x171)
+ out1[0] = x184
+ out1[1] = x185
+ out1[2] = x186
+ out1[3] = x187
+}
+
+// p256Add adds two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func p256Add(out1 *p256MontgomeryDomainFieldElement, arg1 *p256MontgomeryDomainFieldElement, arg2 *p256MontgomeryDomainFieldElement) {
+ var x1 uint64
+ var x2 uint64
+ x1, x2 = bits.Add64(arg1[0], arg2[0], uint64(0x0))
+ var x3 uint64
+ var x4 uint64
+ x3, x4 = bits.Add64(arg1[1], arg2[1], uint64(p256Uint1(x2)))
+ var x5 uint64
+ var x6 uint64
+ x5, x6 = bits.Add64(arg1[2], arg2[2], uint64(p256Uint1(x4)))
+ var x7 uint64
+ var x8 uint64
+ x7, x8 = bits.Add64(arg1[3], arg2[3], uint64(p256Uint1(x6)))
+ var x9 uint64
+ var x10 uint64
+ x9, x10 = bits.Sub64(x1, 0xffffffffffffffff, uint64(0x0))
+ var x11 uint64
+ var x12 uint64
+ x11, x12 = bits.Sub64(x3, 0xffffffff, uint64(p256Uint1(x10)))
+ var x13 uint64
+ var x14 uint64
+ x13, x14 = bits.Sub64(x5, uint64(0x0), uint64(p256Uint1(x12)))
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Sub64(x7, 0xffffffff00000001, uint64(p256Uint1(x14)))
+ var x18 uint64
+ _, x18 = bits.Sub64(uint64(p256Uint1(x8)), uint64(0x0), uint64(p256Uint1(x16)))
+ var x19 uint64
+ p256CmovznzU64(&x19, p256Uint1(x18), x9, x1)
+ var x20 uint64
+ p256CmovznzU64(&x20, p256Uint1(x18), x11, x3)
+ var x21 uint64
+ p256CmovznzU64(&x21, p256Uint1(x18), x13, x5)
+ var x22 uint64
+ p256CmovznzU64(&x22, p256Uint1(x18), x15, x7)
+ out1[0] = x19
+ out1[1] = x20
+ out1[2] = x21
+ out1[3] = x22
+}
+
+// p256Sub subtracts two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func p256Sub(out1 *p256MontgomeryDomainFieldElement, arg1 *p256MontgomeryDomainFieldElement, arg2 *p256MontgomeryDomainFieldElement) {
+ var x1 uint64
+ var x2 uint64
+ x1, x2 = bits.Sub64(arg1[0], arg2[0], uint64(0x0))
+ var x3 uint64
+ var x4 uint64
+ x3, x4 = bits.Sub64(arg1[1], arg2[1], uint64(p256Uint1(x2)))
+ var x5 uint64
+ var x6 uint64
+ x5, x6 = bits.Sub64(arg1[2], arg2[2], uint64(p256Uint1(x4)))
+ var x7 uint64
+ var x8 uint64
+ x7, x8 = bits.Sub64(arg1[3], arg2[3], uint64(p256Uint1(x6)))
+ var x9 uint64
+ p256CmovznzU64(&x9, p256Uint1(x8), uint64(0x0), 0xffffffffffffffff)
+ var x10 uint64
+ var x11 uint64
+ x10, x11 = bits.Add64(x1, x9, uint64(0x0))
+ var x12 uint64
+ var x13 uint64
+ x12, x13 = bits.Add64(x3, (x9 & 0xffffffff), uint64(p256Uint1(x11)))
+ var x14 uint64
+ var x15 uint64
+ x14, x15 = bits.Add64(x5, uint64(0x0), uint64(p256Uint1(x13)))
+ var x16 uint64
+ x16, _ = bits.Add64(x7, (x9 & 0xffffffff00000001), uint64(p256Uint1(x15)))
+ out1[0] = x10
+ out1[1] = x12
+ out1[2] = x14
+ out1[3] = x16
+}
+
+// p256SetOne returns the field element one in the Montgomery domain.
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = 1 mod m
+// 0 ≤ eval out1 < m
+func p256SetOne(out1 *p256MontgomeryDomainFieldElement) {
+ out1[0] = uint64(0x1)
+ out1[1] = 0xffffffff00000000
+ out1[2] = 0xffffffffffffffff
+ out1[3] = 0xfffffffe
+}
+
+// p256FromMontgomery translates a field element out of the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^4) mod m
+// 0 ≤ eval out1 < m
+func p256FromMontgomery(out1 *p256NonMontgomeryDomainFieldElement, arg1 *p256MontgomeryDomainFieldElement) {
+ x1 := arg1[0]
+ var x2 uint64
+ var x3 uint64
+ x3, x2 = bits.Mul64(x1, 0xffffffff00000001)
+ var x4 uint64
+ var x5 uint64
+ x5, x4 = bits.Mul64(x1, 0xffffffff)
+ var x6 uint64
+ var x7 uint64
+ x7, x6 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x8 uint64
+ var x9 uint64
+ x8, x9 = bits.Add64(x7, x4, uint64(0x0))
+ var x11 uint64
+ _, x11 = bits.Add64(x1, x6, uint64(0x0))
+ var x12 uint64
+ var x13 uint64
+ x12, x13 = bits.Add64(uint64(0x0), x8, uint64(p256Uint1(x11)))
+ var x14 uint64
+ var x15 uint64
+ x14, x15 = bits.Add64(x12, arg1[1], uint64(0x0))
+ var x16 uint64
+ var x17 uint64
+ x17, x16 = bits.Mul64(x14, 0xffffffff00000001)
+ var x18 uint64
+ var x19 uint64
+ x19, x18 = bits.Mul64(x14, 0xffffffff)
+ var x20 uint64
+ var x21 uint64
+ x21, x20 = bits.Mul64(x14, 0xffffffffffffffff)
+ var x22 uint64
+ var x23 uint64
+ x22, x23 = bits.Add64(x21, x18, uint64(0x0))
+ var x25 uint64
+ _, x25 = bits.Add64(x14, x20, uint64(0x0))
+ var x26 uint64
+ var x27 uint64
+ x26, x27 = bits.Add64((uint64(p256Uint1(x15)) + (uint64(p256Uint1(x13)) + (uint64(p256Uint1(x9)) + x5))), x22, uint64(p256Uint1(x25)))
+ var x28 uint64
+ var x29 uint64
+ x28, x29 = bits.Add64(x2, (uint64(p256Uint1(x23)) + x19), uint64(p256Uint1(x27)))
+ var x30 uint64
+ var x31 uint64
+ x30, x31 = bits.Add64(x3, x16, uint64(p256Uint1(x29)))
+ var x32 uint64
+ var x33 uint64
+ x32, x33 = bits.Add64(x26, arg1[2], uint64(0x0))
+ var x34 uint64
+ var x35 uint64
+ x34, x35 = bits.Add64(x28, uint64(0x0), uint64(p256Uint1(x33)))
+ var x36 uint64
+ var x37 uint64
+ x36, x37 = bits.Add64(x30, uint64(0x0), uint64(p256Uint1(x35)))
+ var x38 uint64
+ var x39 uint64
+ x39, x38 = bits.Mul64(x32, 0xffffffff00000001)
+ var x40 uint64
+ var x41 uint64
+ x41, x40 = bits.Mul64(x32, 0xffffffff)
+ var x42 uint64
+ var x43 uint64
+ x43, x42 = bits.Mul64(x32, 0xffffffffffffffff)
+ var x44 uint64
+ var x45 uint64
+ x44, x45 = bits.Add64(x43, x40, uint64(0x0))
+ var x47 uint64
+ _, x47 = bits.Add64(x32, x42, uint64(0x0))
+ var x48 uint64
+ var x49 uint64
+ x48, x49 = bits.Add64(x34, x44, uint64(p256Uint1(x47)))
+ var x50 uint64
+ var x51 uint64
+ x50, x51 = bits.Add64(x36, (uint64(p256Uint1(x45)) + x41), uint64(p256Uint1(x49)))
+ var x52 uint64
+ var x53 uint64
+ x52, x53 = bits.Add64((uint64(p256Uint1(x37)) + (uint64(p256Uint1(x31)) + x17)), x38, uint64(p256Uint1(x51)))
+ var x54 uint64
+ var x55 uint64
+ x54, x55 = bits.Add64(x48, arg1[3], uint64(0x0))
+ var x56 uint64
+ var x57 uint64
+ x56, x57 = bits.Add64(x50, uint64(0x0), uint64(p256Uint1(x55)))
+ var x58 uint64
+ var x59 uint64
+ x58, x59 = bits.Add64(x52, uint64(0x0), uint64(p256Uint1(x57)))
+ var x60 uint64
+ var x61 uint64
+ x61, x60 = bits.Mul64(x54, 0xffffffff00000001)
+ var x62 uint64
+ var x63 uint64
+ x63, x62 = bits.Mul64(x54, 0xffffffff)
+ var x64 uint64
+ var x65 uint64
+ x65, x64 = bits.Mul64(x54, 0xffffffffffffffff)
+ var x66 uint64
+ var x67 uint64
+ x66, x67 = bits.Add64(x65, x62, uint64(0x0))
+ var x69 uint64
+ _, x69 = bits.Add64(x54, x64, uint64(0x0))
+ var x70 uint64
+ var x71 uint64
+ x70, x71 = bits.Add64(x56, x66, uint64(p256Uint1(x69)))
+ var x72 uint64
+ var x73 uint64
+ x72, x73 = bits.Add64(x58, (uint64(p256Uint1(x67)) + x63), uint64(p256Uint1(x71)))
+ var x74 uint64
+ var x75 uint64
+ x74, x75 = bits.Add64((uint64(p256Uint1(x59)) + (uint64(p256Uint1(x53)) + x39)), x60, uint64(p256Uint1(x73)))
+ x76 := (uint64(p256Uint1(x75)) + x61)
+ var x77 uint64
+ var x78 uint64
+ x77, x78 = bits.Sub64(x70, 0xffffffffffffffff, uint64(0x0))
+ var x79 uint64
+ var x80 uint64
+ x79, x80 = bits.Sub64(x72, 0xffffffff, uint64(p256Uint1(x78)))
+ var x81 uint64
+ var x82 uint64
+ x81, x82 = bits.Sub64(x74, uint64(0x0), uint64(p256Uint1(x80)))
+ var x83 uint64
+ var x84 uint64
+ x83, x84 = bits.Sub64(x76, 0xffffffff00000001, uint64(p256Uint1(x82)))
+ var x86 uint64
+ _, x86 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(p256Uint1(x84)))
+ var x87 uint64
+ p256CmovznzU64(&x87, p256Uint1(x86), x77, x70)
+ var x88 uint64
+ p256CmovznzU64(&x88, p256Uint1(x86), x79, x72)
+ var x89 uint64
+ p256CmovznzU64(&x89, p256Uint1(x86), x81, x74)
+ var x90 uint64
+ p256CmovznzU64(&x90, p256Uint1(x86), x83, x76)
+ out1[0] = x87
+ out1[1] = x88
+ out1[2] = x89
+ out1[3] = x90
+}
+
+// p256ToMontgomery translates a field element into the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = eval arg1 mod m
+// 0 ≤ eval out1 < m
+func p256ToMontgomery(out1 *p256MontgomeryDomainFieldElement, arg1 *p256NonMontgomeryDomainFieldElement) {
+ x1 := arg1[1]
+ x2 := arg1[2]
+ x3 := arg1[3]
+ x4 := arg1[0]
+ var x5 uint64
+ var x6 uint64
+ x6, x5 = bits.Mul64(x4, 0x4fffffffd)
+ var x7 uint64
+ var x8 uint64
+ x8, x7 = bits.Mul64(x4, 0xfffffffffffffffe)
+ var x9 uint64
+ var x10 uint64
+ x10, x9 = bits.Mul64(x4, 0xfffffffbffffffff)
+ var x11 uint64
+ var x12 uint64
+ x12, x11 = bits.Mul64(x4, 0x3)
+ var x13 uint64
+ var x14 uint64
+ x13, x14 = bits.Add64(x12, x9, uint64(0x0))
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Add64(x10, x7, uint64(p256Uint1(x14)))
+ var x17 uint64
+ var x18 uint64
+ x17, x18 = bits.Add64(x8, x5, uint64(p256Uint1(x16)))
+ var x19 uint64
+ var x20 uint64
+ x20, x19 = bits.Mul64(x11, 0xffffffff00000001)
+ var x21 uint64
+ var x22 uint64
+ x22, x21 = bits.Mul64(x11, 0xffffffff)
+ var x23 uint64
+ var x24 uint64
+ x24, x23 = bits.Mul64(x11, 0xffffffffffffffff)
+ var x25 uint64
+ var x26 uint64
+ x25, x26 = bits.Add64(x24, x21, uint64(0x0))
+ var x28 uint64
+ _, x28 = bits.Add64(x11, x23, uint64(0x0))
+ var x29 uint64
+ var x30 uint64
+ x29, x30 = bits.Add64(x13, x25, uint64(p256Uint1(x28)))
+ var x31 uint64
+ var x32 uint64
+ x31, x32 = bits.Add64(x15, (uint64(p256Uint1(x26)) + x22), uint64(p256Uint1(x30)))
+ var x33 uint64
+ var x34 uint64
+ x33, x34 = bits.Add64(x17, x19, uint64(p256Uint1(x32)))
+ var x35 uint64
+ var x36 uint64
+ x35, x36 = bits.Add64((uint64(p256Uint1(x18)) + x6), x20, uint64(p256Uint1(x34)))
+ var x37 uint64
+ var x38 uint64
+ x38, x37 = bits.Mul64(x1, 0x4fffffffd)
+ var x39 uint64
+ var x40 uint64
+ x40, x39 = bits.Mul64(x1, 0xfffffffffffffffe)
+ var x41 uint64
+ var x42 uint64
+ x42, x41 = bits.Mul64(x1, 0xfffffffbffffffff)
+ var x43 uint64
+ var x44 uint64
+ x44, x43 = bits.Mul64(x1, 0x3)
+ var x45 uint64
+ var x46 uint64
+ x45, x46 = bits.Add64(x44, x41, uint64(0x0))
+ var x47 uint64
+ var x48 uint64
+ x47, x48 = bits.Add64(x42, x39, uint64(p256Uint1(x46)))
+ var x49 uint64
+ var x50 uint64
+ x49, x50 = bits.Add64(x40, x37, uint64(p256Uint1(x48)))
+ var x51 uint64
+ var x52 uint64
+ x51, x52 = bits.Add64(x29, x43, uint64(0x0))
+ var x53 uint64
+ var x54 uint64
+ x53, x54 = bits.Add64(x31, x45, uint64(p256Uint1(x52)))
+ var x55 uint64
+ var x56 uint64
+ x55, x56 = bits.Add64(x33, x47, uint64(p256Uint1(x54)))
+ var x57 uint64
+ var x58 uint64
+ x57, x58 = bits.Add64(x35, x49, uint64(p256Uint1(x56)))
+ var x59 uint64
+ var x60 uint64
+ x60, x59 = bits.Mul64(x51, 0xffffffff00000001)
+ var x61 uint64
+ var x62 uint64
+ x62, x61 = bits.Mul64(x51, 0xffffffff)
+ var x63 uint64
+ var x64 uint64
+ x64, x63 = bits.Mul64(x51, 0xffffffffffffffff)
+ var x65 uint64
+ var x66 uint64
+ x65, x66 = bits.Add64(x64, x61, uint64(0x0))
+ var x68 uint64
+ _, x68 = bits.Add64(x51, x63, uint64(0x0))
+ var x69 uint64
+ var x70 uint64
+ x69, x70 = bits.Add64(x53, x65, uint64(p256Uint1(x68)))
+ var x71 uint64
+ var x72 uint64
+ x71, x72 = bits.Add64(x55, (uint64(p256Uint1(x66)) + x62), uint64(p256Uint1(x70)))
+ var x73 uint64
+ var x74 uint64
+ x73, x74 = bits.Add64(x57, x59, uint64(p256Uint1(x72)))
+ var x75 uint64
+ var x76 uint64
+ x75, x76 = bits.Add64(((uint64(p256Uint1(x58)) + uint64(p256Uint1(x36))) + (uint64(p256Uint1(x50)) + x38)), x60, uint64(p256Uint1(x74)))
+ var x77 uint64
+ var x78 uint64
+ x78, x77 = bits.Mul64(x2, 0x4fffffffd)
+ var x79 uint64
+ var x80 uint64
+ x80, x79 = bits.Mul64(x2, 0xfffffffffffffffe)
+ var x81 uint64
+ var x82 uint64
+ x82, x81 = bits.Mul64(x2, 0xfffffffbffffffff)
+ var x83 uint64
+ var x84 uint64
+ x84, x83 = bits.Mul64(x2, 0x3)
+ var x85 uint64
+ var x86 uint64
+ x85, x86 = bits.Add64(x84, x81, uint64(0x0))
+ var x87 uint64
+ var x88 uint64
+ x87, x88 = bits.Add64(x82, x79, uint64(p256Uint1(x86)))
+ var x89 uint64
+ var x90 uint64
+ x89, x90 = bits.Add64(x80, x77, uint64(p256Uint1(x88)))
+ var x91 uint64
+ var x92 uint64
+ x91, x92 = bits.Add64(x69, x83, uint64(0x0))
+ var x93 uint64
+ var x94 uint64
+ x93, x94 = bits.Add64(x71, x85, uint64(p256Uint1(x92)))
+ var x95 uint64
+ var x96 uint64
+ x95, x96 = bits.Add64(x73, x87, uint64(p256Uint1(x94)))
+ var x97 uint64
+ var x98 uint64
+ x97, x98 = bits.Add64(x75, x89, uint64(p256Uint1(x96)))
+ var x99 uint64
+ var x100 uint64
+ x100, x99 = bits.Mul64(x91, 0xffffffff00000001)
+ var x101 uint64
+ var x102 uint64
+ x102, x101 = bits.Mul64(x91, 0xffffffff)
+ var x103 uint64
+ var x104 uint64
+ x104, x103 = bits.Mul64(x91, 0xffffffffffffffff)
+ var x105 uint64
+ var x106 uint64
+ x105, x106 = bits.Add64(x104, x101, uint64(0x0))
+ var x108 uint64
+ _, x108 = bits.Add64(x91, x103, uint64(0x0))
+ var x109 uint64
+ var x110 uint64
+ x109, x110 = bits.Add64(x93, x105, uint64(p256Uint1(x108)))
+ var x111 uint64
+ var x112 uint64
+ x111, x112 = bits.Add64(x95, (uint64(p256Uint1(x106)) + x102), uint64(p256Uint1(x110)))
+ var x113 uint64
+ var x114 uint64
+ x113, x114 = bits.Add64(x97, x99, uint64(p256Uint1(x112)))
+ var x115 uint64
+ var x116 uint64
+ x115, x116 = bits.Add64(((uint64(p256Uint1(x98)) + uint64(p256Uint1(x76))) + (uint64(p256Uint1(x90)) + x78)), x100, uint64(p256Uint1(x114)))
+ var x117 uint64
+ var x118 uint64
+ x118, x117 = bits.Mul64(x3, 0x4fffffffd)
+ var x119 uint64
+ var x120 uint64
+ x120, x119 = bits.Mul64(x3, 0xfffffffffffffffe)
+ var x121 uint64
+ var x122 uint64
+ x122, x121 = bits.Mul64(x3, 0xfffffffbffffffff)
+ var x123 uint64
+ var x124 uint64
+ x124, x123 = bits.Mul64(x3, 0x3)
+ var x125 uint64
+ var x126 uint64
+ x125, x126 = bits.Add64(x124, x121, uint64(0x0))
+ var x127 uint64
+ var x128 uint64
+ x127, x128 = bits.Add64(x122, x119, uint64(p256Uint1(x126)))
+ var x129 uint64
+ var x130 uint64
+ x129, x130 = bits.Add64(x120, x117, uint64(p256Uint1(x128)))
+ var x131 uint64
+ var x132 uint64
+ x131, x132 = bits.Add64(x109, x123, uint64(0x0))
+ var x133 uint64
+ var x134 uint64
+ x133, x134 = bits.Add64(x111, x125, uint64(p256Uint1(x132)))
+ var x135 uint64
+ var x136 uint64
+ x135, x136 = bits.Add64(x113, x127, uint64(p256Uint1(x134)))
+ var x137 uint64
+ var x138 uint64
+ x137, x138 = bits.Add64(x115, x129, uint64(p256Uint1(x136)))
+ var x139 uint64
+ var x140 uint64
+ x140, x139 = bits.Mul64(x131, 0xffffffff00000001)
+ var x141 uint64
+ var x142 uint64
+ x142, x141 = bits.Mul64(x131, 0xffffffff)
+ var x143 uint64
+ var x144 uint64
+ x144, x143 = bits.Mul64(x131, 0xffffffffffffffff)
+ var x145 uint64
+ var x146 uint64
+ x145, x146 = bits.Add64(x144, x141, uint64(0x0))
+ var x148 uint64
+ _, x148 = bits.Add64(x131, x143, uint64(0x0))
+ var x149 uint64
+ var x150 uint64
+ x149, x150 = bits.Add64(x133, x145, uint64(p256Uint1(x148)))
+ var x151 uint64
+ var x152 uint64
+ x151, x152 = bits.Add64(x135, (uint64(p256Uint1(x146)) + x142), uint64(p256Uint1(x150)))
+ var x153 uint64
+ var x154 uint64
+ x153, x154 = bits.Add64(x137, x139, uint64(p256Uint1(x152)))
+ var x155 uint64
+ var x156 uint64
+ x155, x156 = bits.Add64(((uint64(p256Uint1(x138)) + uint64(p256Uint1(x116))) + (uint64(p256Uint1(x130)) + x118)), x140, uint64(p256Uint1(x154)))
+ var x157 uint64
+ var x158 uint64
+ x157, x158 = bits.Sub64(x149, 0xffffffffffffffff, uint64(0x0))
+ var x159 uint64
+ var x160 uint64
+ x159, x160 = bits.Sub64(x151, 0xffffffff, uint64(p256Uint1(x158)))
+ var x161 uint64
+ var x162 uint64
+ x161, x162 = bits.Sub64(x153, uint64(0x0), uint64(p256Uint1(x160)))
+ var x163 uint64
+ var x164 uint64
+ x163, x164 = bits.Sub64(x155, 0xffffffff00000001, uint64(p256Uint1(x162)))
+ var x166 uint64
+ _, x166 = bits.Sub64(uint64(p256Uint1(x156)), uint64(0x0), uint64(p256Uint1(x164)))
+ var x167 uint64
+ p256CmovznzU64(&x167, p256Uint1(x166), x157, x149)
+ var x168 uint64
+ p256CmovznzU64(&x168, p256Uint1(x166), x159, x151)
+ var x169 uint64
+ p256CmovznzU64(&x169, p256Uint1(x166), x161, x153)
+ var x170 uint64
+ p256CmovznzU64(&x170, p256Uint1(x166), x163, x155)
+ out1[0] = x167
+ out1[1] = x168
+ out1[2] = x169
+ out1[3] = x170
+}
+
+// p256Selectznz is a multi-limb conditional select.
+//
+// Postconditions:
+//
+// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3)
+//
+// Input Bounds:
+//
+// arg1: [0x0 ~> 0x1]
+// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+//
+// Output Bounds:
+//
+// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+func p256Selectznz(out1 *[4]uint64, arg1 p256Uint1, arg2 *[4]uint64, arg3 *[4]uint64) {
+ var x1 uint64
+ p256CmovznzU64(&x1, arg1, arg2[0], arg3[0])
+ var x2 uint64
+ p256CmovznzU64(&x2, arg1, arg2[1], arg3[1])
+ var x3 uint64
+ p256CmovznzU64(&x3, arg1, arg2[2], arg3[2])
+ var x4 uint64
+ p256CmovznzU64(&x4, arg1, arg2[3], arg3[3])
+ out1[0] = x1
+ out1[1] = x2
+ out1[2] = x3
+ out1[3] = x4
+}
+
+// p256ToBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..31]
+//
+// Input Bounds:
+//
+// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+//
+// Output Bounds:
+//
+// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]]
+func p256ToBytes(out1 *[32]uint8, arg1 *[4]uint64) {
+ x1 := arg1[3]
+ x2 := arg1[2]
+ x3 := arg1[1]
+ x4 := arg1[0]
+ x5 := (uint8(x4) & 0xff)
+ x6 := (x4 >> 8)
+ x7 := (uint8(x6) & 0xff)
+ x8 := (x6 >> 8)
+ x9 := (uint8(x8) & 0xff)
+ x10 := (x8 >> 8)
+ x11 := (uint8(x10) & 0xff)
+ x12 := (x10 >> 8)
+ x13 := (uint8(x12) & 0xff)
+ x14 := (x12 >> 8)
+ x15 := (uint8(x14) & 0xff)
+ x16 := (x14 >> 8)
+ x17 := (uint8(x16) & 0xff)
+ x18 := uint8((x16 >> 8))
+ x19 := (uint8(x3) & 0xff)
+ x20 := (x3 >> 8)
+ x21 := (uint8(x20) & 0xff)
+ x22 := (x20 >> 8)
+ x23 := (uint8(x22) & 0xff)
+ x24 := (x22 >> 8)
+ x25 := (uint8(x24) & 0xff)
+ x26 := (x24 >> 8)
+ x27 := (uint8(x26) & 0xff)
+ x28 := (x26 >> 8)
+ x29 := (uint8(x28) & 0xff)
+ x30 := (x28 >> 8)
+ x31 := (uint8(x30) & 0xff)
+ x32 := uint8((x30 >> 8))
+ x33 := (uint8(x2) & 0xff)
+ x34 := (x2 >> 8)
+ x35 := (uint8(x34) & 0xff)
+ x36 := (x34 >> 8)
+ x37 := (uint8(x36) & 0xff)
+ x38 := (x36 >> 8)
+ x39 := (uint8(x38) & 0xff)
+ x40 := (x38 >> 8)
+ x41 := (uint8(x40) & 0xff)
+ x42 := (x40 >> 8)
+ x43 := (uint8(x42) & 0xff)
+ x44 := (x42 >> 8)
+ x45 := (uint8(x44) & 0xff)
+ x46 := uint8((x44 >> 8))
+ x47 := (uint8(x1) & 0xff)
+ x48 := (x1 >> 8)
+ x49 := (uint8(x48) & 0xff)
+ x50 := (x48 >> 8)
+ x51 := (uint8(x50) & 0xff)
+ x52 := (x50 >> 8)
+ x53 := (uint8(x52) & 0xff)
+ x54 := (x52 >> 8)
+ x55 := (uint8(x54) & 0xff)
+ x56 := (x54 >> 8)
+ x57 := (uint8(x56) & 0xff)
+ x58 := (x56 >> 8)
+ x59 := (uint8(x58) & 0xff)
+ x60 := uint8((x58 >> 8))
+ out1[0] = x5
+ out1[1] = x7
+ out1[2] = x9
+ out1[3] = x11
+ out1[4] = x13
+ out1[5] = x15
+ out1[6] = x17
+ out1[7] = x18
+ out1[8] = x19
+ out1[9] = x21
+ out1[10] = x23
+ out1[11] = x25
+ out1[12] = x27
+ out1[13] = x29
+ out1[14] = x31
+ out1[15] = x32
+ out1[16] = x33
+ out1[17] = x35
+ out1[18] = x37
+ out1[19] = x39
+ out1[20] = x41
+ out1[21] = x43
+ out1[22] = x45
+ out1[23] = x46
+ out1[24] = x47
+ out1[25] = x49
+ out1[26] = x51
+ out1[27] = x53
+ out1[28] = x55
+ out1[29] = x57
+ out1[30] = x59
+ out1[31] = x60
+}
+
+// p256FromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order.
+//
+// Preconditions:
+//
+// 0 ≤ bytes_eval arg1 < m
+//
+// Postconditions:
+//
+// eval out1 mod m = bytes_eval arg1 mod m
+// 0 ≤ eval out1 < m
+//
+// Input Bounds:
+//
+// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]]
+//
+// Output Bounds:
+//
+// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+func p256FromBytes(out1 *[4]uint64, arg1 *[32]uint8) {
+ x1 := (uint64(arg1[31]) << 56)
+ x2 := (uint64(arg1[30]) << 48)
+ x3 := (uint64(arg1[29]) << 40)
+ x4 := (uint64(arg1[28]) << 32)
+ x5 := (uint64(arg1[27]) << 24)
+ x6 := (uint64(arg1[26]) << 16)
+ x7 := (uint64(arg1[25]) << 8)
+ x8 := arg1[24]
+ x9 := (uint64(arg1[23]) << 56)
+ x10 := (uint64(arg1[22]) << 48)
+ x11 := (uint64(arg1[21]) << 40)
+ x12 := (uint64(arg1[20]) << 32)
+ x13 := (uint64(arg1[19]) << 24)
+ x14 := (uint64(arg1[18]) << 16)
+ x15 := (uint64(arg1[17]) << 8)
+ x16 := arg1[16]
+ x17 := (uint64(arg1[15]) << 56)
+ x18 := (uint64(arg1[14]) << 48)
+ x19 := (uint64(arg1[13]) << 40)
+ x20 := (uint64(arg1[12]) << 32)
+ x21 := (uint64(arg1[11]) << 24)
+ x22 := (uint64(arg1[10]) << 16)
+ x23 := (uint64(arg1[9]) << 8)
+ x24 := arg1[8]
+ x25 := (uint64(arg1[7]) << 56)
+ x26 := (uint64(arg1[6]) << 48)
+ x27 := (uint64(arg1[5]) << 40)
+ x28 := (uint64(arg1[4]) << 32)
+ x29 := (uint64(arg1[3]) << 24)
+ x30 := (uint64(arg1[2]) << 16)
+ x31 := (uint64(arg1[1]) << 8)
+ x32 := arg1[0]
+ x33 := (x31 + uint64(x32))
+ x34 := (x30 + x33)
+ x35 := (x29 + x34)
+ x36 := (x28 + x35)
+ x37 := (x27 + x36)
+ x38 := (x26 + x37)
+ x39 := (x25 + x38)
+ x40 := (x23 + uint64(x24))
+ x41 := (x22 + x40)
+ x42 := (x21 + x41)
+ x43 := (x20 + x42)
+ x44 := (x19 + x43)
+ x45 := (x18 + x44)
+ x46 := (x17 + x45)
+ x47 := (x15 + uint64(x16))
+ x48 := (x14 + x47)
+ x49 := (x13 + x48)
+ x50 := (x12 + x49)
+ x51 := (x11 + x50)
+ x52 := (x10 + x51)
+ x53 := (x9 + x52)
+ x54 := (x7 + uint64(x8))
+ x55 := (x6 + x54)
+ x56 := (x5 + x55)
+ x57 := (x4 + x56)
+ x58 := (x3 + x57)
+ x59 := (x2 + x58)
+ x60 := (x1 + x59)
+ out1[0] = x39
+ out1[1] = x46
+ out1[2] = x53
+ out1[3] = x60
+}
diff --git a/src/crypto/internal/nistec/fiat/p256_invert.go b/src/crypto/internal/nistec/fiat/p256_invert.go
new file mode 100644
index 0000000..d0101e1
--- /dev/null
+++ b/src/crypto/internal/nistec/fiat/p256_invert.go
@@ -0,0 +1,84 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by addchain. DO NOT EDIT.
+
+package fiat
+
+// Invert sets e = 1/x, and returns e.
+//
+// If x == 0, Invert returns e = 0.
+func (e *P256Element) Invert(x *P256Element) *P256Element {
+ // Inversion is implemented as exponentiation with exponent p − 2.
+ // The sequence of 12 multiplications and 255 squarings is derived from the
+ // following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
+ //
+ // _10 = 2*1
+ // _11 = 1 + _10
+ // _110 = 2*_11
+ // _111 = 1 + _110
+ // _111000 = _111 << 3
+ // _111111 = _111 + _111000
+ // x12 = _111111 << 6 + _111111
+ // x15 = x12 << 3 + _111
+ // x16 = 2*x15 + 1
+ // x32 = x16 << 16 + x16
+ // i53 = x32 << 15
+ // x47 = x15 + i53
+ // i263 = ((i53 << 17 + 1) << 143 + x47) << 47
+ // return (x47 + i263) << 2 + 1
+ //
+
+ var z = new(P256Element).Set(e)
+ var t0 = new(P256Element)
+ var t1 = new(P256Element)
+
+ z.Square(x)
+ z.Mul(x, z)
+ z.Square(z)
+ z.Mul(x, z)
+ t0.Square(z)
+ for s := 1; s < 3; s++ {
+ t0.Square(t0)
+ }
+ t0.Mul(z, t0)
+ t1.Square(t0)
+ for s := 1; s < 6; s++ {
+ t1.Square(t1)
+ }
+ t0.Mul(t0, t1)
+ for s := 0; s < 3; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ t0.Square(z)
+ t0.Mul(x, t0)
+ t1.Square(t0)
+ for s := 1; s < 16; s++ {
+ t1.Square(t1)
+ }
+ t0.Mul(t0, t1)
+ for s := 0; s < 15; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ for s := 0; s < 17; s++ {
+ t0.Square(t0)
+ }
+ t0.Mul(x, t0)
+ for s := 0; s < 143; s++ {
+ t0.Square(t0)
+ }
+ t0.Mul(z, t0)
+ for s := 0; s < 47; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ for s := 0; s < 2; s++ {
+ z.Square(z)
+ }
+ z.Mul(x, z)
+
+ return e.Set(z)
+}
diff --git a/src/crypto/internal/nistec/fiat/p384.go b/src/crypto/internal/nistec/fiat/p384.go
new file mode 100644
index 0000000..aed0c01
--- /dev/null
+++ b/src/crypto/internal/nistec/fiat/p384.go
@@ -0,0 +1,134 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by generate.go. DO NOT EDIT.
+
+package fiat
+
+import (
+ "crypto/subtle"
+ "errors"
+)
+
+// P384Element is an integer modulo 2^384 - 2^128 - 2^96 + 2^32 - 1.
+//
+// The zero value is a valid zero element.
+type P384Element struct {
+ // Values are represented internally always in the Montgomery domain, and
+ // converted in Bytes and SetBytes.
+ x p384MontgomeryDomainFieldElement
+}
+
+const p384ElementLen = 48
+
+type p384UntypedFieldElement = [6]uint64
+
+// One sets e = 1, and returns e.
+func (e *P384Element) One() *P384Element {
+ p384SetOne(&e.x)
+ return e
+}
+
+// Equal returns 1 if e == t, and zero otherwise.
+func (e *P384Element) Equal(t *P384Element) int {
+ eBytes := e.Bytes()
+ tBytes := t.Bytes()
+ return subtle.ConstantTimeCompare(eBytes, tBytes)
+}
+
+// IsZero returns 1 if e == 0, and zero otherwise.
+func (e *P384Element) IsZero() int {
+ zero := make([]byte, p384ElementLen)
+ eBytes := e.Bytes()
+ return subtle.ConstantTimeCompare(eBytes, zero)
+}
+
+// Set sets e = t, and returns e.
+func (e *P384Element) Set(t *P384Element) *P384Element {
+ e.x = t.x
+ return e
+}
+
+// Bytes returns the 48-byte big-endian encoding of e.
+func (e *P384Element) Bytes() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [p384ElementLen]byte
+ return e.bytes(&out)
+}
+
+func (e *P384Element) bytes(out *[p384ElementLen]byte) []byte {
+ var tmp p384NonMontgomeryDomainFieldElement
+ p384FromMontgomery(&tmp, &e.x)
+ p384ToBytes(out, (*p384UntypedFieldElement)(&tmp))
+ p384InvertEndianness(out[:])
+ return out[:]
+}
+
+// SetBytes sets e = v, where v is a big-endian 48-byte encoding, and returns e.
+// If v is not 48 bytes or it encodes a value higher than 2^384 - 2^128 - 2^96 + 2^32 - 1,
+// SetBytes returns nil and an error, and e is unchanged.
+func (e *P384Element) SetBytes(v []byte) (*P384Element, error) {
+ if len(v) != p384ElementLen {
+ return nil, errors.New("invalid P384Element encoding")
+ }
+
+ // Check for non-canonical encodings (p + k, 2p + k, etc.) by comparing to
+ // the encoding of -1 mod p, so p - 1, the highest canonical encoding.
+ var minusOneEncoding = new(P384Element).Sub(
+ new(P384Element), new(P384Element).One()).Bytes()
+ for i := range v {
+ if v[i] < minusOneEncoding[i] {
+ break
+ }
+ if v[i] > minusOneEncoding[i] {
+ return nil, errors.New("invalid P384Element encoding")
+ }
+ }
+
+ var in [p384ElementLen]byte
+ copy(in[:], v)
+ p384InvertEndianness(in[:])
+ var tmp p384NonMontgomeryDomainFieldElement
+ p384FromBytes((*p384UntypedFieldElement)(&tmp), &in)
+ p384ToMontgomery(&e.x, &tmp)
+ return e, nil
+}
+
+// Add sets e = t1 + t2, and returns e.
+func (e *P384Element) Add(t1, t2 *P384Element) *P384Element {
+ p384Add(&e.x, &t1.x, &t2.x)
+ return e
+}
+
+// Sub sets e = t1 - t2, and returns e.
+func (e *P384Element) Sub(t1, t2 *P384Element) *P384Element {
+ p384Sub(&e.x, &t1.x, &t2.x)
+ return e
+}
+
+// Mul sets e = t1 * t2, and returns e.
+func (e *P384Element) Mul(t1, t2 *P384Element) *P384Element {
+ p384Mul(&e.x, &t1.x, &t2.x)
+ return e
+}
+
+// Square sets e = t * t, and returns e.
+func (e *P384Element) Square(t *P384Element) *P384Element {
+ p384Square(&e.x, &t.x)
+ return e
+}
+
+// Select sets v to a if cond == 1, and to b if cond == 0.
+func (v *P384Element) Select(a, b *P384Element, cond int) *P384Element {
+ p384Selectznz((*p384UntypedFieldElement)(&v.x), p384Uint1(cond),
+ (*p384UntypedFieldElement)(&b.x), (*p384UntypedFieldElement)(&a.x))
+ return v
+}
+
+func p384InvertEndianness(v []byte) {
+ for i := 0; i < len(v)/2; i++ {
+ v[i], v[len(v)-1-i] = v[len(v)-1-i], v[i]
+ }
+}
diff --git a/src/crypto/internal/nistec/fiat/p384_fiat64.go b/src/crypto/internal/nistec/fiat/p384_fiat64.go
new file mode 100644
index 0000000..979eadd
--- /dev/null
+++ b/src/crypto/internal/nistec/fiat/p384_fiat64.go
@@ -0,0 +1,3036 @@
+// Code generated by Fiat Cryptography. DO NOT EDIT.
+//
+// Autogenerated: word_by_word_montgomery --lang Go --no-wide-int --cmovznz-by-mul --relax-primitive-carry-to-bitwidth 32,64 --internal-static --public-function-case camelCase --public-type-case camelCase --private-function-case camelCase --private-type-case camelCase --doc-text-before-function-name '' --doc-newline-before-package-declaration --doc-prepend-header 'Code generated by Fiat Cryptography. DO NOT EDIT.' --package-name fiat --no-prefix-fiat p384 64 '2^384 - 2^128 - 2^96 + 2^32 - 1' mul square add sub one from_montgomery to_montgomery selectznz to_bytes from_bytes
+//
+// curve description: p384
+//
+// machine_wordsize = 64 (from "64")
+//
+// requested operations: mul, square, add, sub, one, from_montgomery, to_montgomery, selectznz, to_bytes, from_bytes
+//
+// m = 0xfffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffeffffffff0000000000000000ffffffff (from "2^384 - 2^128 - 2^96 + 2^32 - 1")
+//
+//
+//
+// NOTE: In addition to the bounds specified above each function, all
+//
+// functions synthesized for this Montgomery arithmetic require the
+//
+// input to be strictly less than the prime modulus (m), and also
+//
+// require the input to be in the unique saturated representation.
+//
+// All functions also ensure that these two properties are true of
+//
+// return values.
+//
+//
+//
+// Computed values:
+//
+// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) + (z[4] << 256) + (z[5] << 0x140)
+//
+// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248) + (z[32] << 256) + (z[33] << 0x108) + (z[34] << 0x110) + (z[35] << 0x118) + (z[36] << 0x120) + (z[37] << 0x128) + (z[38] << 0x130) + (z[39] << 0x138) + (z[40] << 0x140) + (z[41] << 0x148) + (z[42] << 0x150) + (z[43] << 0x158) + (z[44] << 0x160) + (z[45] << 0x168) + (z[46] << 0x170) + (z[47] << 0x178)
+//
+// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) + (z[4] << 256) + (z[5] << 0x140) in
+//
+// if x1 & (2^384-1) < 2^383 then x1 & (2^384-1) else (x1 & (2^384-1)) - 2^384
+
+package fiat
+
+import "math/bits"
+
+type p384Uint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927
+type p384Int1 int64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927
+
+// The type p384MontgomeryDomainFieldElement is a field element in the Montgomery domain.
+//
+// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+type p384MontgomeryDomainFieldElement [6]uint64
+
+// The type p384NonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain.
+//
+// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+type p384NonMontgomeryDomainFieldElement [6]uint64
+
+// p384CmovznzU64 is a single-word conditional move.
+//
+// Postconditions:
+//
+// out1 = (if arg1 = 0 then arg2 else arg3)
+//
+// Input Bounds:
+//
+// arg1: [0x0 ~> 0x1]
+// arg2: [0x0 ~> 0xffffffffffffffff]
+// arg3: [0x0 ~> 0xffffffffffffffff]
+//
+// Output Bounds:
+//
+// out1: [0x0 ~> 0xffffffffffffffff]
+func p384CmovznzU64(out1 *uint64, arg1 p384Uint1, arg2 uint64, arg3 uint64) {
+ x1 := (uint64(arg1) * 0xffffffffffffffff)
+ x2 := ((x1 & arg3) | ((^x1) & arg2))
+ *out1 = x2
+}
+
+// p384Mul multiplies two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func p384Mul(out1 *p384MontgomeryDomainFieldElement, arg1 *p384MontgomeryDomainFieldElement, arg2 *p384MontgomeryDomainFieldElement) {
+ x1 := arg1[1]
+ x2 := arg1[2]
+ x3 := arg1[3]
+ x4 := arg1[4]
+ x5 := arg1[5]
+ x6 := arg1[0]
+ var x7 uint64
+ var x8 uint64
+ x8, x7 = bits.Mul64(x6, arg2[5])
+ var x9 uint64
+ var x10 uint64
+ x10, x9 = bits.Mul64(x6, arg2[4])
+ var x11 uint64
+ var x12 uint64
+ x12, x11 = bits.Mul64(x6, arg2[3])
+ var x13 uint64
+ var x14 uint64
+ x14, x13 = bits.Mul64(x6, arg2[2])
+ var x15 uint64
+ var x16 uint64
+ x16, x15 = bits.Mul64(x6, arg2[1])
+ var x17 uint64
+ var x18 uint64
+ x18, x17 = bits.Mul64(x6, arg2[0])
+ var x19 uint64
+ var x20 uint64
+ x19, x20 = bits.Add64(x18, x15, uint64(0x0))
+ var x21 uint64
+ var x22 uint64
+ x21, x22 = bits.Add64(x16, x13, uint64(p384Uint1(x20)))
+ var x23 uint64
+ var x24 uint64
+ x23, x24 = bits.Add64(x14, x11, uint64(p384Uint1(x22)))
+ var x25 uint64
+ var x26 uint64
+ x25, x26 = bits.Add64(x12, x9, uint64(p384Uint1(x24)))
+ var x27 uint64
+ var x28 uint64
+ x27, x28 = bits.Add64(x10, x7, uint64(p384Uint1(x26)))
+ x29 := (uint64(p384Uint1(x28)) + x8)
+ var x30 uint64
+ _, x30 = bits.Mul64(x17, 0x100000001)
+ var x32 uint64
+ var x33 uint64
+ x33, x32 = bits.Mul64(x30, 0xffffffffffffffff)
+ var x34 uint64
+ var x35 uint64
+ x35, x34 = bits.Mul64(x30, 0xffffffffffffffff)
+ var x36 uint64
+ var x37 uint64
+ x37, x36 = bits.Mul64(x30, 0xffffffffffffffff)
+ var x38 uint64
+ var x39 uint64
+ x39, x38 = bits.Mul64(x30, 0xfffffffffffffffe)
+ var x40 uint64
+ var x41 uint64
+ x41, x40 = bits.Mul64(x30, 0xffffffff00000000)
+ var x42 uint64
+ var x43 uint64
+ x43, x42 = bits.Mul64(x30, 0xffffffff)
+ var x44 uint64
+ var x45 uint64
+ x44, x45 = bits.Add64(x43, x40, uint64(0x0))
+ var x46 uint64
+ var x47 uint64
+ x46, x47 = bits.Add64(x41, x38, uint64(p384Uint1(x45)))
+ var x48 uint64
+ var x49 uint64
+ x48, x49 = bits.Add64(x39, x36, uint64(p384Uint1(x47)))
+ var x50 uint64
+ var x51 uint64
+ x50, x51 = bits.Add64(x37, x34, uint64(p384Uint1(x49)))
+ var x52 uint64
+ var x53 uint64
+ x52, x53 = bits.Add64(x35, x32, uint64(p384Uint1(x51)))
+ x54 := (uint64(p384Uint1(x53)) + x33)
+ var x56 uint64
+ _, x56 = bits.Add64(x17, x42, uint64(0x0))
+ var x57 uint64
+ var x58 uint64
+ x57, x58 = bits.Add64(x19, x44, uint64(p384Uint1(x56)))
+ var x59 uint64
+ var x60 uint64
+ x59, x60 = bits.Add64(x21, x46, uint64(p384Uint1(x58)))
+ var x61 uint64
+ var x62 uint64
+ x61, x62 = bits.Add64(x23, x48, uint64(p384Uint1(x60)))
+ var x63 uint64
+ var x64 uint64
+ x63, x64 = bits.Add64(x25, x50, uint64(p384Uint1(x62)))
+ var x65 uint64
+ var x66 uint64
+ x65, x66 = bits.Add64(x27, x52, uint64(p384Uint1(x64)))
+ var x67 uint64
+ var x68 uint64
+ x67, x68 = bits.Add64(x29, x54, uint64(p384Uint1(x66)))
+ var x69 uint64
+ var x70 uint64
+ x70, x69 = bits.Mul64(x1, arg2[5])
+ var x71 uint64
+ var x72 uint64
+ x72, x71 = bits.Mul64(x1, arg2[4])
+ var x73 uint64
+ var x74 uint64
+ x74, x73 = bits.Mul64(x1, arg2[3])
+ var x75 uint64
+ var x76 uint64
+ x76, x75 = bits.Mul64(x1, arg2[2])
+ var x77 uint64
+ var x78 uint64
+ x78, x77 = bits.Mul64(x1, arg2[1])
+ var x79 uint64
+ var x80 uint64
+ x80, x79 = bits.Mul64(x1, arg2[0])
+ var x81 uint64
+ var x82 uint64
+ x81, x82 = bits.Add64(x80, x77, uint64(0x0))
+ var x83 uint64
+ var x84 uint64
+ x83, x84 = bits.Add64(x78, x75, uint64(p384Uint1(x82)))
+ var x85 uint64
+ var x86 uint64
+ x85, x86 = bits.Add64(x76, x73, uint64(p384Uint1(x84)))
+ var x87 uint64
+ var x88 uint64
+ x87, x88 = bits.Add64(x74, x71, uint64(p384Uint1(x86)))
+ var x89 uint64
+ var x90 uint64
+ x89, x90 = bits.Add64(x72, x69, uint64(p384Uint1(x88)))
+ x91 := (uint64(p384Uint1(x90)) + x70)
+ var x92 uint64
+ var x93 uint64
+ x92, x93 = bits.Add64(x57, x79, uint64(0x0))
+ var x94 uint64
+ var x95 uint64
+ x94, x95 = bits.Add64(x59, x81, uint64(p384Uint1(x93)))
+ var x96 uint64
+ var x97 uint64
+ x96, x97 = bits.Add64(x61, x83, uint64(p384Uint1(x95)))
+ var x98 uint64
+ var x99 uint64
+ x98, x99 = bits.Add64(x63, x85, uint64(p384Uint1(x97)))
+ var x100 uint64
+ var x101 uint64
+ x100, x101 = bits.Add64(x65, x87, uint64(p384Uint1(x99)))
+ var x102 uint64
+ var x103 uint64
+ x102, x103 = bits.Add64(x67, x89, uint64(p384Uint1(x101)))
+ var x104 uint64
+ var x105 uint64
+ x104, x105 = bits.Add64(uint64(p384Uint1(x68)), x91, uint64(p384Uint1(x103)))
+ var x106 uint64
+ _, x106 = bits.Mul64(x92, 0x100000001)
+ var x108 uint64
+ var x109 uint64
+ x109, x108 = bits.Mul64(x106, 0xffffffffffffffff)
+ var x110 uint64
+ var x111 uint64
+ x111, x110 = bits.Mul64(x106, 0xffffffffffffffff)
+ var x112 uint64
+ var x113 uint64
+ x113, x112 = bits.Mul64(x106, 0xffffffffffffffff)
+ var x114 uint64
+ var x115 uint64
+ x115, x114 = bits.Mul64(x106, 0xfffffffffffffffe)
+ var x116 uint64
+ var x117 uint64
+ x117, x116 = bits.Mul64(x106, 0xffffffff00000000)
+ var x118 uint64
+ var x119 uint64
+ x119, x118 = bits.Mul64(x106, 0xffffffff)
+ var x120 uint64
+ var x121 uint64
+ x120, x121 = bits.Add64(x119, x116, uint64(0x0))
+ var x122 uint64
+ var x123 uint64
+ x122, x123 = bits.Add64(x117, x114, uint64(p384Uint1(x121)))
+ var x124 uint64
+ var x125 uint64
+ x124, x125 = bits.Add64(x115, x112, uint64(p384Uint1(x123)))
+ var x126 uint64
+ var x127 uint64
+ x126, x127 = bits.Add64(x113, x110, uint64(p384Uint1(x125)))
+ var x128 uint64
+ var x129 uint64
+ x128, x129 = bits.Add64(x111, x108, uint64(p384Uint1(x127)))
+ x130 := (uint64(p384Uint1(x129)) + x109)
+ var x132 uint64
+ _, x132 = bits.Add64(x92, x118, uint64(0x0))
+ var x133 uint64
+ var x134 uint64
+ x133, x134 = bits.Add64(x94, x120, uint64(p384Uint1(x132)))
+ var x135 uint64
+ var x136 uint64
+ x135, x136 = bits.Add64(x96, x122, uint64(p384Uint1(x134)))
+ var x137 uint64
+ var x138 uint64
+ x137, x138 = bits.Add64(x98, x124, uint64(p384Uint1(x136)))
+ var x139 uint64
+ var x140 uint64
+ x139, x140 = bits.Add64(x100, x126, uint64(p384Uint1(x138)))
+ var x141 uint64
+ var x142 uint64
+ x141, x142 = bits.Add64(x102, x128, uint64(p384Uint1(x140)))
+ var x143 uint64
+ var x144 uint64
+ x143, x144 = bits.Add64(x104, x130, uint64(p384Uint1(x142)))
+ x145 := (uint64(p384Uint1(x144)) + uint64(p384Uint1(x105)))
+ var x146 uint64
+ var x147 uint64
+ x147, x146 = bits.Mul64(x2, arg2[5])
+ var x148 uint64
+ var x149 uint64
+ x149, x148 = bits.Mul64(x2, arg2[4])
+ var x150 uint64
+ var x151 uint64
+ x151, x150 = bits.Mul64(x2, arg2[3])
+ var x152 uint64
+ var x153 uint64
+ x153, x152 = bits.Mul64(x2, arg2[2])
+ var x154 uint64
+ var x155 uint64
+ x155, x154 = bits.Mul64(x2, arg2[1])
+ var x156 uint64
+ var x157 uint64
+ x157, x156 = bits.Mul64(x2, arg2[0])
+ var x158 uint64
+ var x159 uint64
+ x158, x159 = bits.Add64(x157, x154, uint64(0x0))
+ var x160 uint64
+ var x161 uint64
+ x160, x161 = bits.Add64(x155, x152, uint64(p384Uint1(x159)))
+ var x162 uint64
+ var x163 uint64
+ x162, x163 = bits.Add64(x153, x150, uint64(p384Uint1(x161)))
+ var x164 uint64
+ var x165 uint64
+ x164, x165 = bits.Add64(x151, x148, uint64(p384Uint1(x163)))
+ var x166 uint64
+ var x167 uint64
+ x166, x167 = bits.Add64(x149, x146, uint64(p384Uint1(x165)))
+ x168 := (uint64(p384Uint1(x167)) + x147)
+ var x169 uint64
+ var x170 uint64
+ x169, x170 = bits.Add64(x133, x156, uint64(0x0))
+ var x171 uint64
+ var x172 uint64
+ x171, x172 = bits.Add64(x135, x158, uint64(p384Uint1(x170)))
+ var x173 uint64
+ var x174 uint64
+ x173, x174 = bits.Add64(x137, x160, uint64(p384Uint1(x172)))
+ var x175 uint64
+ var x176 uint64
+ x175, x176 = bits.Add64(x139, x162, uint64(p384Uint1(x174)))
+ var x177 uint64
+ var x178 uint64
+ x177, x178 = bits.Add64(x141, x164, uint64(p384Uint1(x176)))
+ var x179 uint64
+ var x180 uint64
+ x179, x180 = bits.Add64(x143, x166, uint64(p384Uint1(x178)))
+ var x181 uint64
+ var x182 uint64
+ x181, x182 = bits.Add64(x145, x168, uint64(p384Uint1(x180)))
+ var x183 uint64
+ _, x183 = bits.Mul64(x169, 0x100000001)
+ var x185 uint64
+ var x186 uint64
+ x186, x185 = bits.Mul64(x183, 0xffffffffffffffff)
+ var x187 uint64
+ var x188 uint64
+ x188, x187 = bits.Mul64(x183, 0xffffffffffffffff)
+ var x189 uint64
+ var x190 uint64
+ x190, x189 = bits.Mul64(x183, 0xffffffffffffffff)
+ var x191 uint64
+ var x192 uint64
+ x192, x191 = bits.Mul64(x183, 0xfffffffffffffffe)
+ var x193 uint64
+ var x194 uint64
+ x194, x193 = bits.Mul64(x183, 0xffffffff00000000)
+ var x195 uint64
+ var x196 uint64
+ x196, x195 = bits.Mul64(x183, 0xffffffff)
+ var x197 uint64
+ var x198 uint64
+ x197, x198 = bits.Add64(x196, x193, uint64(0x0))
+ var x199 uint64
+ var x200 uint64
+ x199, x200 = bits.Add64(x194, x191, uint64(p384Uint1(x198)))
+ var x201 uint64
+ var x202 uint64
+ x201, x202 = bits.Add64(x192, x189, uint64(p384Uint1(x200)))
+ var x203 uint64
+ var x204 uint64
+ x203, x204 = bits.Add64(x190, x187, uint64(p384Uint1(x202)))
+ var x205 uint64
+ var x206 uint64
+ x205, x206 = bits.Add64(x188, x185, uint64(p384Uint1(x204)))
+ x207 := (uint64(p384Uint1(x206)) + x186)
+ var x209 uint64
+ _, x209 = bits.Add64(x169, x195, uint64(0x0))
+ var x210 uint64
+ var x211 uint64
+ x210, x211 = bits.Add64(x171, x197, uint64(p384Uint1(x209)))
+ var x212 uint64
+ var x213 uint64
+ x212, x213 = bits.Add64(x173, x199, uint64(p384Uint1(x211)))
+ var x214 uint64
+ var x215 uint64
+ x214, x215 = bits.Add64(x175, x201, uint64(p384Uint1(x213)))
+ var x216 uint64
+ var x217 uint64
+ x216, x217 = bits.Add64(x177, x203, uint64(p384Uint1(x215)))
+ var x218 uint64
+ var x219 uint64
+ x218, x219 = bits.Add64(x179, x205, uint64(p384Uint1(x217)))
+ var x220 uint64
+ var x221 uint64
+ x220, x221 = bits.Add64(x181, x207, uint64(p384Uint1(x219)))
+ x222 := (uint64(p384Uint1(x221)) + uint64(p384Uint1(x182)))
+ var x223 uint64
+ var x224 uint64
+ x224, x223 = bits.Mul64(x3, arg2[5])
+ var x225 uint64
+ var x226 uint64
+ x226, x225 = bits.Mul64(x3, arg2[4])
+ var x227 uint64
+ var x228 uint64
+ x228, x227 = bits.Mul64(x3, arg2[3])
+ var x229 uint64
+ var x230 uint64
+ x230, x229 = bits.Mul64(x3, arg2[2])
+ var x231 uint64
+ var x232 uint64
+ x232, x231 = bits.Mul64(x3, arg2[1])
+ var x233 uint64
+ var x234 uint64
+ x234, x233 = bits.Mul64(x3, arg2[0])
+ var x235 uint64
+ var x236 uint64
+ x235, x236 = bits.Add64(x234, x231, uint64(0x0))
+ var x237 uint64
+ var x238 uint64
+ x237, x238 = bits.Add64(x232, x229, uint64(p384Uint1(x236)))
+ var x239 uint64
+ var x240 uint64
+ x239, x240 = bits.Add64(x230, x227, uint64(p384Uint1(x238)))
+ var x241 uint64
+ var x242 uint64
+ x241, x242 = bits.Add64(x228, x225, uint64(p384Uint1(x240)))
+ var x243 uint64
+ var x244 uint64
+ x243, x244 = bits.Add64(x226, x223, uint64(p384Uint1(x242)))
+ x245 := (uint64(p384Uint1(x244)) + x224)
+ var x246 uint64
+ var x247 uint64
+ x246, x247 = bits.Add64(x210, x233, uint64(0x0))
+ var x248 uint64
+ var x249 uint64
+ x248, x249 = bits.Add64(x212, x235, uint64(p384Uint1(x247)))
+ var x250 uint64
+ var x251 uint64
+ x250, x251 = bits.Add64(x214, x237, uint64(p384Uint1(x249)))
+ var x252 uint64
+ var x253 uint64
+ x252, x253 = bits.Add64(x216, x239, uint64(p384Uint1(x251)))
+ var x254 uint64
+ var x255 uint64
+ x254, x255 = bits.Add64(x218, x241, uint64(p384Uint1(x253)))
+ var x256 uint64
+ var x257 uint64
+ x256, x257 = bits.Add64(x220, x243, uint64(p384Uint1(x255)))
+ var x258 uint64
+ var x259 uint64
+ x258, x259 = bits.Add64(x222, x245, uint64(p384Uint1(x257)))
+ var x260 uint64
+ _, x260 = bits.Mul64(x246, 0x100000001)
+ var x262 uint64
+ var x263 uint64
+ x263, x262 = bits.Mul64(x260, 0xffffffffffffffff)
+ var x264 uint64
+ var x265 uint64
+ x265, x264 = bits.Mul64(x260, 0xffffffffffffffff)
+ var x266 uint64
+ var x267 uint64
+ x267, x266 = bits.Mul64(x260, 0xffffffffffffffff)
+ var x268 uint64
+ var x269 uint64
+ x269, x268 = bits.Mul64(x260, 0xfffffffffffffffe)
+ var x270 uint64
+ var x271 uint64
+ x271, x270 = bits.Mul64(x260, 0xffffffff00000000)
+ var x272 uint64
+ var x273 uint64
+ x273, x272 = bits.Mul64(x260, 0xffffffff)
+ var x274 uint64
+ var x275 uint64
+ x274, x275 = bits.Add64(x273, x270, uint64(0x0))
+ var x276 uint64
+ var x277 uint64
+ x276, x277 = bits.Add64(x271, x268, uint64(p384Uint1(x275)))
+ var x278 uint64
+ var x279 uint64
+ x278, x279 = bits.Add64(x269, x266, uint64(p384Uint1(x277)))
+ var x280 uint64
+ var x281 uint64
+ x280, x281 = bits.Add64(x267, x264, uint64(p384Uint1(x279)))
+ var x282 uint64
+ var x283 uint64
+ x282, x283 = bits.Add64(x265, x262, uint64(p384Uint1(x281)))
+ x284 := (uint64(p384Uint1(x283)) + x263)
+ var x286 uint64
+ _, x286 = bits.Add64(x246, x272, uint64(0x0))
+ var x287 uint64
+ var x288 uint64
+ x287, x288 = bits.Add64(x248, x274, uint64(p384Uint1(x286)))
+ var x289 uint64
+ var x290 uint64
+ x289, x290 = bits.Add64(x250, x276, uint64(p384Uint1(x288)))
+ var x291 uint64
+ var x292 uint64
+ x291, x292 = bits.Add64(x252, x278, uint64(p384Uint1(x290)))
+ var x293 uint64
+ var x294 uint64
+ x293, x294 = bits.Add64(x254, x280, uint64(p384Uint1(x292)))
+ var x295 uint64
+ var x296 uint64
+ x295, x296 = bits.Add64(x256, x282, uint64(p384Uint1(x294)))
+ var x297 uint64
+ var x298 uint64
+ x297, x298 = bits.Add64(x258, x284, uint64(p384Uint1(x296)))
+ x299 := (uint64(p384Uint1(x298)) + uint64(p384Uint1(x259)))
+ var x300 uint64
+ var x301 uint64
+ x301, x300 = bits.Mul64(x4, arg2[5])
+ var x302 uint64
+ var x303 uint64
+ x303, x302 = bits.Mul64(x4, arg2[4])
+ var x304 uint64
+ var x305 uint64
+ x305, x304 = bits.Mul64(x4, arg2[3])
+ var x306 uint64
+ var x307 uint64
+ x307, x306 = bits.Mul64(x4, arg2[2])
+ var x308 uint64
+ var x309 uint64
+ x309, x308 = bits.Mul64(x4, arg2[1])
+ var x310 uint64
+ var x311 uint64
+ x311, x310 = bits.Mul64(x4, arg2[0])
+ var x312 uint64
+ var x313 uint64
+ x312, x313 = bits.Add64(x311, x308, uint64(0x0))
+ var x314 uint64
+ var x315 uint64
+ x314, x315 = bits.Add64(x309, x306, uint64(p384Uint1(x313)))
+ var x316 uint64
+ var x317 uint64
+ x316, x317 = bits.Add64(x307, x304, uint64(p384Uint1(x315)))
+ var x318 uint64
+ var x319 uint64
+ x318, x319 = bits.Add64(x305, x302, uint64(p384Uint1(x317)))
+ var x320 uint64
+ var x321 uint64
+ x320, x321 = bits.Add64(x303, x300, uint64(p384Uint1(x319)))
+ x322 := (uint64(p384Uint1(x321)) + x301)
+ var x323 uint64
+ var x324 uint64
+ x323, x324 = bits.Add64(x287, x310, uint64(0x0))
+ var x325 uint64
+ var x326 uint64
+ x325, x326 = bits.Add64(x289, x312, uint64(p384Uint1(x324)))
+ var x327 uint64
+ var x328 uint64
+ x327, x328 = bits.Add64(x291, x314, uint64(p384Uint1(x326)))
+ var x329 uint64
+ var x330 uint64
+ x329, x330 = bits.Add64(x293, x316, uint64(p384Uint1(x328)))
+ var x331 uint64
+ var x332 uint64
+ x331, x332 = bits.Add64(x295, x318, uint64(p384Uint1(x330)))
+ var x333 uint64
+ var x334 uint64
+ x333, x334 = bits.Add64(x297, x320, uint64(p384Uint1(x332)))
+ var x335 uint64
+ var x336 uint64
+ x335, x336 = bits.Add64(x299, x322, uint64(p384Uint1(x334)))
+ var x337 uint64
+ _, x337 = bits.Mul64(x323, 0x100000001)
+ var x339 uint64
+ var x340 uint64
+ x340, x339 = bits.Mul64(x337, 0xffffffffffffffff)
+ var x341 uint64
+ var x342 uint64
+ x342, x341 = bits.Mul64(x337, 0xffffffffffffffff)
+ var x343 uint64
+ var x344 uint64
+ x344, x343 = bits.Mul64(x337, 0xffffffffffffffff)
+ var x345 uint64
+ var x346 uint64
+ x346, x345 = bits.Mul64(x337, 0xfffffffffffffffe)
+ var x347 uint64
+ var x348 uint64
+ x348, x347 = bits.Mul64(x337, 0xffffffff00000000)
+ var x349 uint64
+ var x350 uint64
+ x350, x349 = bits.Mul64(x337, 0xffffffff)
+ var x351 uint64
+ var x352 uint64
+ x351, x352 = bits.Add64(x350, x347, uint64(0x0))
+ var x353 uint64
+ var x354 uint64
+ x353, x354 = bits.Add64(x348, x345, uint64(p384Uint1(x352)))
+ var x355 uint64
+ var x356 uint64
+ x355, x356 = bits.Add64(x346, x343, uint64(p384Uint1(x354)))
+ var x357 uint64
+ var x358 uint64
+ x357, x358 = bits.Add64(x344, x341, uint64(p384Uint1(x356)))
+ var x359 uint64
+ var x360 uint64
+ x359, x360 = bits.Add64(x342, x339, uint64(p384Uint1(x358)))
+ x361 := (uint64(p384Uint1(x360)) + x340)
+ var x363 uint64
+ _, x363 = bits.Add64(x323, x349, uint64(0x0))
+ var x364 uint64
+ var x365 uint64
+ x364, x365 = bits.Add64(x325, x351, uint64(p384Uint1(x363)))
+ var x366 uint64
+ var x367 uint64
+ x366, x367 = bits.Add64(x327, x353, uint64(p384Uint1(x365)))
+ var x368 uint64
+ var x369 uint64
+ x368, x369 = bits.Add64(x329, x355, uint64(p384Uint1(x367)))
+ var x370 uint64
+ var x371 uint64
+ x370, x371 = bits.Add64(x331, x357, uint64(p384Uint1(x369)))
+ var x372 uint64
+ var x373 uint64
+ x372, x373 = bits.Add64(x333, x359, uint64(p384Uint1(x371)))
+ var x374 uint64
+ var x375 uint64
+ x374, x375 = bits.Add64(x335, x361, uint64(p384Uint1(x373)))
+ x376 := (uint64(p384Uint1(x375)) + uint64(p384Uint1(x336)))
+ var x377 uint64
+ var x378 uint64
+ x378, x377 = bits.Mul64(x5, arg2[5])
+ var x379 uint64
+ var x380 uint64
+ x380, x379 = bits.Mul64(x5, arg2[4])
+ var x381 uint64
+ var x382 uint64
+ x382, x381 = bits.Mul64(x5, arg2[3])
+ var x383 uint64
+ var x384 uint64
+ x384, x383 = bits.Mul64(x5, arg2[2])
+ var x385 uint64
+ var x386 uint64
+ x386, x385 = bits.Mul64(x5, arg2[1])
+ var x387 uint64
+ var x388 uint64
+ x388, x387 = bits.Mul64(x5, arg2[0])
+ var x389 uint64
+ var x390 uint64
+ x389, x390 = bits.Add64(x388, x385, uint64(0x0))
+ var x391 uint64
+ var x392 uint64
+ x391, x392 = bits.Add64(x386, x383, uint64(p384Uint1(x390)))
+ var x393 uint64
+ var x394 uint64
+ x393, x394 = bits.Add64(x384, x381, uint64(p384Uint1(x392)))
+ var x395 uint64
+ var x396 uint64
+ x395, x396 = bits.Add64(x382, x379, uint64(p384Uint1(x394)))
+ var x397 uint64
+ var x398 uint64
+ x397, x398 = bits.Add64(x380, x377, uint64(p384Uint1(x396)))
+ x399 := (uint64(p384Uint1(x398)) + x378)
+ var x400 uint64
+ var x401 uint64
+ x400, x401 = bits.Add64(x364, x387, uint64(0x0))
+ var x402 uint64
+ var x403 uint64
+ x402, x403 = bits.Add64(x366, x389, uint64(p384Uint1(x401)))
+ var x404 uint64
+ var x405 uint64
+ x404, x405 = bits.Add64(x368, x391, uint64(p384Uint1(x403)))
+ var x406 uint64
+ var x407 uint64
+ x406, x407 = bits.Add64(x370, x393, uint64(p384Uint1(x405)))
+ var x408 uint64
+ var x409 uint64
+ x408, x409 = bits.Add64(x372, x395, uint64(p384Uint1(x407)))
+ var x410 uint64
+ var x411 uint64
+ x410, x411 = bits.Add64(x374, x397, uint64(p384Uint1(x409)))
+ var x412 uint64
+ var x413 uint64
+ x412, x413 = bits.Add64(x376, x399, uint64(p384Uint1(x411)))
+ var x414 uint64
+ _, x414 = bits.Mul64(x400, 0x100000001)
+ var x416 uint64
+ var x417 uint64
+ x417, x416 = bits.Mul64(x414, 0xffffffffffffffff)
+ var x418 uint64
+ var x419 uint64
+ x419, x418 = bits.Mul64(x414, 0xffffffffffffffff)
+ var x420 uint64
+ var x421 uint64
+ x421, x420 = bits.Mul64(x414, 0xffffffffffffffff)
+ var x422 uint64
+ var x423 uint64
+ x423, x422 = bits.Mul64(x414, 0xfffffffffffffffe)
+ var x424 uint64
+ var x425 uint64
+ x425, x424 = bits.Mul64(x414, 0xffffffff00000000)
+ var x426 uint64
+ var x427 uint64
+ x427, x426 = bits.Mul64(x414, 0xffffffff)
+ var x428 uint64
+ var x429 uint64
+ x428, x429 = bits.Add64(x427, x424, uint64(0x0))
+ var x430 uint64
+ var x431 uint64
+ x430, x431 = bits.Add64(x425, x422, uint64(p384Uint1(x429)))
+ var x432 uint64
+ var x433 uint64
+ x432, x433 = bits.Add64(x423, x420, uint64(p384Uint1(x431)))
+ var x434 uint64
+ var x435 uint64
+ x434, x435 = bits.Add64(x421, x418, uint64(p384Uint1(x433)))
+ var x436 uint64
+ var x437 uint64
+ x436, x437 = bits.Add64(x419, x416, uint64(p384Uint1(x435)))
+ x438 := (uint64(p384Uint1(x437)) + x417)
+ var x440 uint64
+ _, x440 = bits.Add64(x400, x426, uint64(0x0))
+ var x441 uint64
+ var x442 uint64
+ x441, x442 = bits.Add64(x402, x428, uint64(p384Uint1(x440)))
+ var x443 uint64
+ var x444 uint64
+ x443, x444 = bits.Add64(x404, x430, uint64(p384Uint1(x442)))
+ var x445 uint64
+ var x446 uint64
+ x445, x446 = bits.Add64(x406, x432, uint64(p384Uint1(x444)))
+ var x447 uint64
+ var x448 uint64
+ x447, x448 = bits.Add64(x408, x434, uint64(p384Uint1(x446)))
+ var x449 uint64
+ var x450 uint64
+ x449, x450 = bits.Add64(x410, x436, uint64(p384Uint1(x448)))
+ var x451 uint64
+ var x452 uint64
+ x451, x452 = bits.Add64(x412, x438, uint64(p384Uint1(x450)))
+ x453 := (uint64(p384Uint1(x452)) + uint64(p384Uint1(x413)))
+ var x454 uint64
+ var x455 uint64
+ x454, x455 = bits.Sub64(x441, 0xffffffff, uint64(0x0))
+ var x456 uint64
+ var x457 uint64
+ x456, x457 = bits.Sub64(x443, 0xffffffff00000000, uint64(p384Uint1(x455)))
+ var x458 uint64
+ var x459 uint64
+ x458, x459 = bits.Sub64(x445, 0xfffffffffffffffe, uint64(p384Uint1(x457)))
+ var x460 uint64
+ var x461 uint64
+ x460, x461 = bits.Sub64(x447, 0xffffffffffffffff, uint64(p384Uint1(x459)))
+ var x462 uint64
+ var x463 uint64
+ x462, x463 = bits.Sub64(x449, 0xffffffffffffffff, uint64(p384Uint1(x461)))
+ var x464 uint64
+ var x465 uint64
+ x464, x465 = bits.Sub64(x451, 0xffffffffffffffff, uint64(p384Uint1(x463)))
+ var x467 uint64
+ _, x467 = bits.Sub64(x453, uint64(0x0), uint64(p384Uint1(x465)))
+ var x468 uint64
+ p384CmovznzU64(&x468, p384Uint1(x467), x454, x441)
+ var x469 uint64
+ p384CmovznzU64(&x469, p384Uint1(x467), x456, x443)
+ var x470 uint64
+ p384CmovznzU64(&x470, p384Uint1(x467), x458, x445)
+ var x471 uint64
+ p384CmovznzU64(&x471, p384Uint1(x467), x460, x447)
+ var x472 uint64
+ p384CmovznzU64(&x472, p384Uint1(x467), x462, x449)
+ var x473 uint64
+ p384CmovznzU64(&x473, p384Uint1(x467), x464, x451)
+ out1[0] = x468
+ out1[1] = x469
+ out1[2] = x470
+ out1[3] = x471
+ out1[4] = x472
+ out1[5] = x473
+}
+
+// p384Square squares a field element in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m
+// 0 ≤ eval out1 < m
+func p384Square(out1 *p384MontgomeryDomainFieldElement, arg1 *p384MontgomeryDomainFieldElement) {
+ x1 := arg1[1]
+ x2 := arg1[2]
+ x3 := arg1[3]
+ x4 := arg1[4]
+ x5 := arg1[5]
+ x6 := arg1[0]
+ var x7 uint64
+ var x8 uint64
+ x8, x7 = bits.Mul64(x6, arg1[5])
+ var x9 uint64
+ var x10 uint64
+ x10, x9 = bits.Mul64(x6, arg1[4])
+ var x11 uint64
+ var x12 uint64
+ x12, x11 = bits.Mul64(x6, arg1[3])
+ var x13 uint64
+ var x14 uint64
+ x14, x13 = bits.Mul64(x6, arg1[2])
+ var x15 uint64
+ var x16 uint64
+ x16, x15 = bits.Mul64(x6, arg1[1])
+ var x17 uint64
+ var x18 uint64
+ x18, x17 = bits.Mul64(x6, arg1[0])
+ var x19 uint64
+ var x20 uint64
+ x19, x20 = bits.Add64(x18, x15, uint64(0x0))
+ var x21 uint64
+ var x22 uint64
+ x21, x22 = bits.Add64(x16, x13, uint64(p384Uint1(x20)))
+ var x23 uint64
+ var x24 uint64
+ x23, x24 = bits.Add64(x14, x11, uint64(p384Uint1(x22)))
+ var x25 uint64
+ var x26 uint64
+ x25, x26 = bits.Add64(x12, x9, uint64(p384Uint1(x24)))
+ var x27 uint64
+ var x28 uint64
+ x27, x28 = bits.Add64(x10, x7, uint64(p384Uint1(x26)))
+ x29 := (uint64(p384Uint1(x28)) + x8)
+ var x30 uint64
+ _, x30 = bits.Mul64(x17, 0x100000001)
+ var x32 uint64
+ var x33 uint64
+ x33, x32 = bits.Mul64(x30, 0xffffffffffffffff)
+ var x34 uint64
+ var x35 uint64
+ x35, x34 = bits.Mul64(x30, 0xffffffffffffffff)
+ var x36 uint64
+ var x37 uint64
+ x37, x36 = bits.Mul64(x30, 0xffffffffffffffff)
+ var x38 uint64
+ var x39 uint64
+ x39, x38 = bits.Mul64(x30, 0xfffffffffffffffe)
+ var x40 uint64
+ var x41 uint64
+ x41, x40 = bits.Mul64(x30, 0xffffffff00000000)
+ var x42 uint64
+ var x43 uint64
+ x43, x42 = bits.Mul64(x30, 0xffffffff)
+ var x44 uint64
+ var x45 uint64
+ x44, x45 = bits.Add64(x43, x40, uint64(0x0))
+ var x46 uint64
+ var x47 uint64
+ x46, x47 = bits.Add64(x41, x38, uint64(p384Uint1(x45)))
+ var x48 uint64
+ var x49 uint64
+ x48, x49 = bits.Add64(x39, x36, uint64(p384Uint1(x47)))
+ var x50 uint64
+ var x51 uint64
+ x50, x51 = bits.Add64(x37, x34, uint64(p384Uint1(x49)))
+ var x52 uint64
+ var x53 uint64
+ x52, x53 = bits.Add64(x35, x32, uint64(p384Uint1(x51)))
+ x54 := (uint64(p384Uint1(x53)) + x33)
+ var x56 uint64
+ _, x56 = bits.Add64(x17, x42, uint64(0x0))
+ var x57 uint64
+ var x58 uint64
+ x57, x58 = bits.Add64(x19, x44, uint64(p384Uint1(x56)))
+ var x59 uint64
+ var x60 uint64
+ x59, x60 = bits.Add64(x21, x46, uint64(p384Uint1(x58)))
+ var x61 uint64
+ var x62 uint64
+ x61, x62 = bits.Add64(x23, x48, uint64(p384Uint1(x60)))
+ var x63 uint64
+ var x64 uint64
+ x63, x64 = bits.Add64(x25, x50, uint64(p384Uint1(x62)))
+ var x65 uint64
+ var x66 uint64
+ x65, x66 = bits.Add64(x27, x52, uint64(p384Uint1(x64)))
+ var x67 uint64
+ var x68 uint64
+ x67, x68 = bits.Add64(x29, x54, uint64(p384Uint1(x66)))
+ var x69 uint64
+ var x70 uint64
+ x70, x69 = bits.Mul64(x1, arg1[5])
+ var x71 uint64
+ var x72 uint64
+ x72, x71 = bits.Mul64(x1, arg1[4])
+ var x73 uint64
+ var x74 uint64
+ x74, x73 = bits.Mul64(x1, arg1[3])
+ var x75 uint64
+ var x76 uint64
+ x76, x75 = bits.Mul64(x1, arg1[2])
+ var x77 uint64
+ var x78 uint64
+ x78, x77 = bits.Mul64(x1, arg1[1])
+ var x79 uint64
+ var x80 uint64
+ x80, x79 = bits.Mul64(x1, arg1[0])
+ var x81 uint64
+ var x82 uint64
+ x81, x82 = bits.Add64(x80, x77, uint64(0x0))
+ var x83 uint64
+ var x84 uint64
+ x83, x84 = bits.Add64(x78, x75, uint64(p384Uint1(x82)))
+ var x85 uint64
+ var x86 uint64
+ x85, x86 = bits.Add64(x76, x73, uint64(p384Uint1(x84)))
+ var x87 uint64
+ var x88 uint64
+ x87, x88 = bits.Add64(x74, x71, uint64(p384Uint1(x86)))
+ var x89 uint64
+ var x90 uint64
+ x89, x90 = bits.Add64(x72, x69, uint64(p384Uint1(x88)))
+ x91 := (uint64(p384Uint1(x90)) + x70)
+ var x92 uint64
+ var x93 uint64
+ x92, x93 = bits.Add64(x57, x79, uint64(0x0))
+ var x94 uint64
+ var x95 uint64
+ x94, x95 = bits.Add64(x59, x81, uint64(p384Uint1(x93)))
+ var x96 uint64
+ var x97 uint64
+ x96, x97 = bits.Add64(x61, x83, uint64(p384Uint1(x95)))
+ var x98 uint64
+ var x99 uint64
+ x98, x99 = bits.Add64(x63, x85, uint64(p384Uint1(x97)))
+ var x100 uint64
+ var x101 uint64
+ x100, x101 = bits.Add64(x65, x87, uint64(p384Uint1(x99)))
+ var x102 uint64
+ var x103 uint64
+ x102, x103 = bits.Add64(x67, x89, uint64(p384Uint1(x101)))
+ var x104 uint64
+ var x105 uint64
+ x104, x105 = bits.Add64(uint64(p384Uint1(x68)), x91, uint64(p384Uint1(x103)))
+ var x106 uint64
+ _, x106 = bits.Mul64(x92, 0x100000001)
+ var x108 uint64
+ var x109 uint64
+ x109, x108 = bits.Mul64(x106, 0xffffffffffffffff)
+ var x110 uint64
+ var x111 uint64
+ x111, x110 = bits.Mul64(x106, 0xffffffffffffffff)
+ var x112 uint64
+ var x113 uint64
+ x113, x112 = bits.Mul64(x106, 0xffffffffffffffff)
+ var x114 uint64
+ var x115 uint64
+ x115, x114 = bits.Mul64(x106, 0xfffffffffffffffe)
+ var x116 uint64
+ var x117 uint64
+ x117, x116 = bits.Mul64(x106, 0xffffffff00000000)
+ var x118 uint64
+ var x119 uint64
+ x119, x118 = bits.Mul64(x106, 0xffffffff)
+ var x120 uint64
+ var x121 uint64
+ x120, x121 = bits.Add64(x119, x116, uint64(0x0))
+ var x122 uint64
+ var x123 uint64
+ x122, x123 = bits.Add64(x117, x114, uint64(p384Uint1(x121)))
+ var x124 uint64
+ var x125 uint64
+ x124, x125 = bits.Add64(x115, x112, uint64(p384Uint1(x123)))
+ var x126 uint64
+ var x127 uint64
+ x126, x127 = bits.Add64(x113, x110, uint64(p384Uint1(x125)))
+ var x128 uint64
+ var x129 uint64
+ x128, x129 = bits.Add64(x111, x108, uint64(p384Uint1(x127)))
+ x130 := (uint64(p384Uint1(x129)) + x109)
+ var x132 uint64
+ _, x132 = bits.Add64(x92, x118, uint64(0x0))
+ var x133 uint64
+ var x134 uint64
+ x133, x134 = bits.Add64(x94, x120, uint64(p384Uint1(x132)))
+ var x135 uint64
+ var x136 uint64
+ x135, x136 = bits.Add64(x96, x122, uint64(p384Uint1(x134)))
+ var x137 uint64
+ var x138 uint64
+ x137, x138 = bits.Add64(x98, x124, uint64(p384Uint1(x136)))
+ var x139 uint64
+ var x140 uint64
+ x139, x140 = bits.Add64(x100, x126, uint64(p384Uint1(x138)))
+ var x141 uint64
+ var x142 uint64
+ x141, x142 = bits.Add64(x102, x128, uint64(p384Uint1(x140)))
+ var x143 uint64
+ var x144 uint64
+ x143, x144 = bits.Add64(x104, x130, uint64(p384Uint1(x142)))
+ x145 := (uint64(p384Uint1(x144)) + uint64(p384Uint1(x105)))
+ var x146 uint64
+ var x147 uint64
+ x147, x146 = bits.Mul64(x2, arg1[5])
+ var x148 uint64
+ var x149 uint64
+ x149, x148 = bits.Mul64(x2, arg1[4])
+ var x150 uint64
+ var x151 uint64
+ x151, x150 = bits.Mul64(x2, arg1[3])
+ var x152 uint64
+ var x153 uint64
+ x153, x152 = bits.Mul64(x2, arg1[2])
+ var x154 uint64
+ var x155 uint64
+ x155, x154 = bits.Mul64(x2, arg1[1])
+ var x156 uint64
+ var x157 uint64
+ x157, x156 = bits.Mul64(x2, arg1[0])
+ var x158 uint64
+ var x159 uint64
+ x158, x159 = bits.Add64(x157, x154, uint64(0x0))
+ var x160 uint64
+ var x161 uint64
+ x160, x161 = bits.Add64(x155, x152, uint64(p384Uint1(x159)))
+ var x162 uint64
+ var x163 uint64
+ x162, x163 = bits.Add64(x153, x150, uint64(p384Uint1(x161)))
+ var x164 uint64
+ var x165 uint64
+ x164, x165 = bits.Add64(x151, x148, uint64(p384Uint1(x163)))
+ var x166 uint64
+ var x167 uint64
+ x166, x167 = bits.Add64(x149, x146, uint64(p384Uint1(x165)))
+ x168 := (uint64(p384Uint1(x167)) + x147)
+ var x169 uint64
+ var x170 uint64
+ x169, x170 = bits.Add64(x133, x156, uint64(0x0))
+ var x171 uint64
+ var x172 uint64
+ x171, x172 = bits.Add64(x135, x158, uint64(p384Uint1(x170)))
+ var x173 uint64
+ var x174 uint64
+ x173, x174 = bits.Add64(x137, x160, uint64(p384Uint1(x172)))
+ var x175 uint64
+ var x176 uint64
+ x175, x176 = bits.Add64(x139, x162, uint64(p384Uint1(x174)))
+ var x177 uint64
+ var x178 uint64
+ x177, x178 = bits.Add64(x141, x164, uint64(p384Uint1(x176)))
+ var x179 uint64
+ var x180 uint64
+ x179, x180 = bits.Add64(x143, x166, uint64(p384Uint1(x178)))
+ var x181 uint64
+ var x182 uint64
+ x181, x182 = bits.Add64(x145, x168, uint64(p384Uint1(x180)))
+ var x183 uint64
+ _, x183 = bits.Mul64(x169, 0x100000001)
+ var x185 uint64
+ var x186 uint64
+ x186, x185 = bits.Mul64(x183, 0xffffffffffffffff)
+ var x187 uint64
+ var x188 uint64
+ x188, x187 = bits.Mul64(x183, 0xffffffffffffffff)
+ var x189 uint64
+ var x190 uint64
+ x190, x189 = bits.Mul64(x183, 0xffffffffffffffff)
+ var x191 uint64
+ var x192 uint64
+ x192, x191 = bits.Mul64(x183, 0xfffffffffffffffe)
+ var x193 uint64
+ var x194 uint64
+ x194, x193 = bits.Mul64(x183, 0xffffffff00000000)
+ var x195 uint64
+ var x196 uint64
+ x196, x195 = bits.Mul64(x183, 0xffffffff)
+ var x197 uint64
+ var x198 uint64
+ x197, x198 = bits.Add64(x196, x193, uint64(0x0))
+ var x199 uint64
+ var x200 uint64
+ x199, x200 = bits.Add64(x194, x191, uint64(p384Uint1(x198)))
+ var x201 uint64
+ var x202 uint64
+ x201, x202 = bits.Add64(x192, x189, uint64(p384Uint1(x200)))
+ var x203 uint64
+ var x204 uint64
+ x203, x204 = bits.Add64(x190, x187, uint64(p384Uint1(x202)))
+ var x205 uint64
+ var x206 uint64
+ x205, x206 = bits.Add64(x188, x185, uint64(p384Uint1(x204)))
+ x207 := (uint64(p384Uint1(x206)) + x186)
+ var x209 uint64
+ _, x209 = bits.Add64(x169, x195, uint64(0x0))
+ var x210 uint64
+ var x211 uint64
+ x210, x211 = bits.Add64(x171, x197, uint64(p384Uint1(x209)))
+ var x212 uint64
+ var x213 uint64
+ x212, x213 = bits.Add64(x173, x199, uint64(p384Uint1(x211)))
+ var x214 uint64
+ var x215 uint64
+ x214, x215 = bits.Add64(x175, x201, uint64(p384Uint1(x213)))
+ var x216 uint64
+ var x217 uint64
+ x216, x217 = bits.Add64(x177, x203, uint64(p384Uint1(x215)))
+ var x218 uint64
+ var x219 uint64
+ x218, x219 = bits.Add64(x179, x205, uint64(p384Uint1(x217)))
+ var x220 uint64
+ var x221 uint64
+ x220, x221 = bits.Add64(x181, x207, uint64(p384Uint1(x219)))
+ x222 := (uint64(p384Uint1(x221)) + uint64(p384Uint1(x182)))
+ var x223 uint64
+ var x224 uint64
+ x224, x223 = bits.Mul64(x3, arg1[5])
+ var x225 uint64
+ var x226 uint64
+ x226, x225 = bits.Mul64(x3, arg1[4])
+ var x227 uint64
+ var x228 uint64
+ x228, x227 = bits.Mul64(x3, arg1[3])
+ var x229 uint64
+ var x230 uint64
+ x230, x229 = bits.Mul64(x3, arg1[2])
+ var x231 uint64
+ var x232 uint64
+ x232, x231 = bits.Mul64(x3, arg1[1])
+ var x233 uint64
+ var x234 uint64
+ x234, x233 = bits.Mul64(x3, arg1[0])
+ var x235 uint64
+ var x236 uint64
+ x235, x236 = bits.Add64(x234, x231, uint64(0x0))
+ var x237 uint64
+ var x238 uint64
+ x237, x238 = bits.Add64(x232, x229, uint64(p384Uint1(x236)))
+ var x239 uint64
+ var x240 uint64
+ x239, x240 = bits.Add64(x230, x227, uint64(p384Uint1(x238)))
+ var x241 uint64
+ var x242 uint64
+ x241, x242 = bits.Add64(x228, x225, uint64(p384Uint1(x240)))
+ var x243 uint64
+ var x244 uint64
+ x243, x244 = bits.Add64(x226, x223, uint64(p384Uint1(x242)))
+ x245 := (uint64(p384Uint1(x244)) + x224)
+ var x246 uint64
+ var x247 uint64
+ x246, x247 = bits.Add64(x210, x233, uint64(0x0))
+ var x248 uint64
+ var x249 uint64
+ x248, x249 = bits.Add64(x212, x235, uint64(p384Uint1(x247)))
+ var x250 uint64
+ var x251 uint64
+ x250, x251 = bits.Add64(x214, x237, uint64(p384Uint1(x249)))
+ var x252 uint64
+ var x253 uint64
+ x252, x253 = bits.Add64(x216, x239, uint64(p384Uint1(x251)))
+ var x254 uint64
+ var x255 uint64
+ x254, x255 = bits.Add64(x218, x241, uint64(p384Uint1(x253)))
+ var x256 uint64
+ var x257 uint64
+ x256, x257 = bits.Add64(x220, x243, uint64(p384Uint1(x255)))
+ var x258 uint64
+ var x259 uint64
+ x258, x259 = bits.Add64(x222, x245, uint64(p384Uint1(x257)))
+ var x260 uint64
+ _, x260 = bits.Mul64(x246, 0x100000001)
+ var x262 uint64
+ var x263 uint64
+ x263, x262 = bits.Mul64(x260, 0xffffffffffffffff)
+ var x264 uint64
+ var x265 uint64
+ x265, x264 = bits.Mul64(x260, 0xffffffffffffffff)
+ var x266 uint64
+ var x267 uint64
+ x267, x266 = bits.Mul64(x260, 0xffffffffffffffff)
+ var x268 uint64
+ var x269 uint64
+ x269, x268 = bits.Mul64(x260, 0xfffffffffffffffe)
+ var x270 uint64
+ var x271 uint64
+ x271, x270 = bits.Mul64(x260, 0xffffffff00000000)
+ var x272 uint64
+ var x273 uint64
+ x273, x272 = bits.Mul64(x260, 0xffffffff)
+ var x274 uint64
+ var x275 uint64
+ x274, x275 = bits.Add64(x273, x270, uint64(0x0))
+ var x276 uint64
+ var x277 uint64
+ x276, x277 = bits.Add64(x271, x268, uint64(p384Uint1(x275)))
+ var x278 uint64
+ var x279 uint64
+ x278, x279 = bits.Add64(x269, x266, uint64(p384Uint1(x277)))
+ var x280 uint64
+ var x281 uint64
+ x280, x281 = bits.Add64(x267, x264, uint64(p384Uint1(x279)))
+ var x282 uint64
+ var x283 uint64
+ x282, x283 = bits.Add64(x265, x262, uint64(p384Uint1(x281)))
+ x284 := (uint64(p384Uint1(x283)) + x263)
+ var x286 uint64
+ _, x286 = bits.Add64(x246, x272, uint64(0x0))
+ var x287 uint64
+ var x288 uint64
+ x287, x288 = bits.Add64(x248, x274, uint64(p384Uint1(x286)))
+ var x289 uint64
+ var x290 uint64
+ x289, x290 = bits.Add64(x250, x276, uint64(p384Uint1(x288)))
+ var x291 uint64
+ var x292 uint64
+ x291, x292 = bits.Add64(x252, x278, uint64(p384Uint1(x290)))
+ var x293 uint64
+ var x294 uint64
+ x293, x294 = bits.Add64(x254, x280, uint64(p384Uint1(x292)))
+ var x295 uint64
+ var x296 uint64
+ x295, x296 = bits.Add64(x256, x282, uint64(p384Uint1(x294)))
+ var x297 uint64
+ var x298 uint64
+ x297, x298 = bits.Add64(x258, x284, uint64(p384Uint1(x296)))
+ x299 := (uint64(p384Uint1(x298)) + uint64(p384Uint1(x259)))
+ var x300 uint64
+ var x301 uint64
+ x301, x300 = bits.Mul64(x4, arg1[5])
+ var x302 uint64
+ var x303 uint64
+ x303, x302 = bits.Mul64(x4, arg1[4])
+ var x304 uint64
+ var x305 uint64
+ x305, x304 = bits.Mul64(x4, arg1[3])
+ var x306 uint64
+ var x307 uint64
+ x307, x306 = bits.Mul64(x4, arg1[2])
+ var x308 uint64
+ var x309 uint64
+ x309, x308 = bits.Mul64(x4, arg1[1])
+ var x310 uint64
+ var x311 uint64
+ x311, x310 = bits.Mul64(x4, arg1[0])
+ var x312 uint64
+ var x313 uint64
+ x312, x313 = bits.Add64(x311, x308, uint64(0x0))
+ var x314 uint64
+ var x315 uint64
+ x314, x315 = bits.Add64(x309, x306, uint64(p384Uint1(x313)))
+ var x316 uint64
+ var x317 uint64
+ x316, x317 = bits.Add64(x307, x304, uint64(p384Uint1(x315)))
+ var x318 uint64
+ var x319 uint64
+ x318, x319 = bits.Add64(x305, x302, uint64(p384Uint1(x317)))
+ var x320 uint64
+ var x321 uint64
+ x320, x321 = bits.Add64(x303, x300, uint64(p384Uint1(x319)))
+ x322 := (uint64(p384Uint1(x321)) + x301)
+ var x323 uint64
+ var x324 uint64
+ x323, x324 = bits.Add64(x287, x310, uint64(0x0))
+ var x325 uint64
+ var x326 uint64
+ x325, x326 = bits.Add64(x289, x312, uint64(p384Uint1(x324)))
+ var x327 uint64
+ var x328 uint64
+ x327, x328 = bits.Add64(x291, x314, uint64(p384Uint1(x326)))
+ var x329 uint64
+ var x330 uint64
+ x329, x330 = bits.Add64(x293, x316, uint64(p384Uint1(x328)))
+ var x331 uint64
+ var x332 uint64
+ x331, x332 = bits.Add64(x295, x318, uint64(p384Uint1(x330)))
+ var x333 uint64
+ var x334 uint64
+ x333, x334 = bits.Add64(x297, x320, uint64(p384Uint1(x332)))
+ var x335 uint64
+ var x336 uint64
+ x335, x336 = bits.Add64(x299, x322, uint64(p384Uint1(x334)))
+ var x337 uint64
+ _, x337 = bits.Mul64(x323, 0x100000001)
+ var x339 uint64
+ var x340 uint64
+ x340, x339 = bits.Mul64(x337, 0xffffffffffffffff)
+ var x341 uint64
+ var x342 uint64
+ x342, x341 = bits.Mul64(x337, 0xffffffffffffffff)
+ var x343 uint64
+ var x344 uint64
+ x344, x343 = bits.Mul64(x337, 0xffffffffffffffff)
+ var x345 uint64
+ var x346 uint64
+ x346, x345 = bits.Mul64(x337, 0xfffffffffffffffe)
+ var x347 uint64
+ var x348 uint64
+ x348, x347 = bits.Mul64(x337, 0xffffffff00000000)
+ var x349 uint64
+ var x350 uint64
+ x350, x349 = bits.Mul64(x337, 0xffffffff)
+ var x351 uint64
+ var x352 uint64
+ x351, x352 = bits.Add64(x350, x347, uint64(0x0))
+ var x353 uint64
+ var x354 uint64
+ x353, x354 = bits.Add64(x348, x345, uint64(p384Uint1(x352)))
+ var x355 uint64
+ var x356 uint64
+ x355, x356 = bits.Add64(x346, x343, uint64(p384Uint1(x354)))
+ var x357 uint64
+ var x358 uint64
+ x357, x358 = bits.Add64(x344, x341, uint64(p384Uint1(x356)))
+ var x359 uint64
+ var x360 uint64
+ x359, x360 = bits.Add64(x342, x339, uint64(p384Uint1(x358)))
+ x361 := (uint64(p384Uint1(x360)) + x340)
+ var x363 uint64
+ _, x363 = bits.Add64(x323, x349, uint64(0x0))
+ var x364 uint64
+ var x365 uint64
+ x364, x365 = bits.Add64(x325, x351, uint64(p384Uint1(x363)))
+ var x366 uint64
+ var x367 uint64
+ x366, x367 = bits.Add64(x327, x353, uint64(p384Uint1(x365)))
+ var x368 uint64
+ var x369 uint64
+ x368, x369 = bits.Add64(x329, x355, uint64(p384Uint1(x367)))
+ var x370 uint64
+ var x371 uint64
+ x370, x371 = bits.Add64(x331, x357, uint64(p384Uint1(x369)))
+ var x372 uint64
+ var x373 uint64
+ x372, x373 = bits.Add64(x333, x359, uint64(p384Uint1(x371)))
+ var x374 uint64
+ var x375 uint64
+ x374, x375 = bits.Add64(x335, x361, uint64(p384Uint1(x373)))
+ x376 := (uint64(p384Uint1(x375)) + uint64(p384Uint1(x336)))
+ var x377 uint64
+ var x378 uint64
+ x378, x377 = bits.Mul64(x5, arg1[5])
+ var x379 uint64
+ var x380 uint64
+ x380, x379 = bits.Mul64(x5, arg1[4])
+ var x381 uint64
+ var x382 uint64
+ x382, x381 = bits.Mul64(x5, arg1[3])
+ var x383 uint64
+ var x384 uint64
+ x384, x383 = bits.Mul64(x5, arg1[2])
+ var x385 uint64
+ var x386 uint64
+ x386, x385 = bits.Mul64(x5, arg1[1])
+ var x387 uint64
+ var x388 uint64
+ x388, x387 = bits.Mul64(x5, arg1[0])
+ var x389 uint64
+ var x390 uint64
+ x389, x390 = bits.Add64(x388, x385, uint64(0x0))
+ var x391 uint64
+ var x392 uint64
+ x391, x392 = bits.Add64(x386, x383, uint64(p384Uint1(x390)))
+ var x393 uint64
+ var x394 uint64
+ x393, x394 = bits.Add64(x384, x381, uint64(p384Uint1(x392)))
+ var x395 uint64
+ var x396 uint64
+ x395, x396 = bits.Add64(x382, x379, uint64(p384Uint1(x394)))
+ var x397 uint64
+ var x398 uint64
+ x397, x398 = bits.Add64(x380, x377, uint64(p384Uint1(x396)))
+ x399 := (uint64(p384Uint1(x398)) + x378)
+ var x400 uint64
+ var x401 uint64
+ x400, x401 = bits.Add64(x364, x387, uint64(0x0))
+ var x402 uint64
+ var x403 uint64
+ x402, x403 = bits.Add64(x366, x389, uint64(p384Uint1(x401)))
+ var x404 uint64
+ var x405 uint64
+ x404, x405 = bits.Add64(x368, x391, uint64(p384Uint1(x403)))
+ var x406 uint64
+ var x407 uint64
+ x406, x407 = bits.Add64(x370, x393, uint64(p384Uint1(x405)))
+ var x408 uint64
+ var x409 uint64
+ x408, x409 = bits.Add64(x372, x395, uint64(p384Uint1(x407)))
+ var x410 uint64
+ var x411 uint64
+ x410, x411 = bits.Add64(x374, x397, uint64(p384Uint1(x409)))
+ var x412 uint64
+ var x413 uint64
+ x412, x413 = bits.Add64(x376, x399, uint64(p384Uint1(x411)))
+ var x414 uint64
+ _, x414 = bits.Mul64(x400, 0x100000001)
+ var x416 uint64
+ var x417 uint64
+ x417, x416 = bits.Mul64(x414, 0xffffffffffffffff)
+ var x418 uint64
+ var x419 uint64
+ x419, x418 = bits.Mul64(x414, 0xffffffffffffffff)
+ var x420 uint64
+ var x421 uint64
+ x421, x420 = bits.Mul64(x414, 0xffffffffffffffff)
+ var x422 uint64
+ var x423 uint64
+ x423, x422 = bits.Mul64(x414, 0xfffffffffffffffe)
+ var x424 uint64
+ var x425 uint64
+ x425, x424 = bits.Mul64(x414, 0xffffffff00000000)
+ var x426 uint64
+ var x427 uint64
+ x427, x426 = bits.Mul64(x414, 0xffffffff)
+ var x428 uint64
+ var x429 uint64
+ x428, x429 = bits.Add64(x427, x424, uint64(0x0))
+ var x430 uint64
+ var x431 uint64
+ x430, x431 = bits.Add64(x425, x422, uint64(p384Uint1(x429)))
+ var x432 uint64
+ var x433 uint64
+ x432, x433 = bits.Add64(x423, x420, uint64(p384Uint1(x431)))
+ var x434 uint64
+ var x435 uint64
+ x434, x435 = bits.Add64(x421, x418, uint64(p384Uint1(x433)))
+ var x436 uint64
+ var x437 uint64
+ x436, x437 = bits.Add64(x419, x416, uint64(p384Uint1(x435)))
+ x438 := (uint64(p384Uint1(x437)) + x417)
+ var x440 uint64
+ _, x440 = bits.Add64(x400, x426, uint64(0x0))
+ var x441 uint64
+ var x442 uint64
+ x441, x442 = bits.Add64(x402, x428, uint64(p384Uint1(x440)))
+ var x443 uint64
+ var x444 uint64
+ x443, x444 = bits.Add64(x404, x430, uint64(p384Uint1(x442)))
+ var x445 uint64
+ var x446 uint64
+ x445, x446 = bits.Add64(x406, x432, uint64(p384Uint1(x444)))
+ var x447 uint64
+ var x448 uint64
+ x447, x448 = bits.Add64(x408, x434, uint64(p384Uint1(x446)))
+ var x449 uint64
+ var x450 uint64
+ x449, x450 = bits.Add64(x410, x436, uint64(p384Uint1(x448)))
+ var x451 uint64
+ var x452 uint64
+ x451, x452 = bits.Add64(x412, x438, uint64(p384Uint1(x450)))
+ x453 := (uint64(p384Uint1(x452)) + uint64(p384Uint1(x413)))
+ var x454 uint64
+ var x455 uint64
+ x454, x455 = bits.Sub64(x441, 0xffffffff, uint64(0x0))
+ var x456 uint64
+ var x457 uint64
+ x456, x457 = bits.Sub64(x443, 0xffffffff00000000, uint64(p384Uint1(x455)))
+ var x458 uint64
+ var x459 uint64
+ x458, x459 = bits.Sub64(x445, 0xfffffffffffffffe, uint64(p384Uint1(x457)))
+ var x460 uint64
+ var x461 uint64
+ x460, x461 = bits.Sub64(x447, 0xffffffffffffffff, uint64(p384Uint1(x459)))
+ var x462 uint64
+ var x463 uint64
+ x462, x463 = bits.Sub64(x449, 0xffffffffffffffff, uint64(p384Uint1(x461)))
+ var x464 uint64
+ var x465 uint64
+ x464, x465 = bits.Sub64(x451, 0xffffffffffffffff, uint64(p384Uint1(x463)))
+ var x467 uint64
+ _, x467 = bits.Sub64(x453, uint64(0x0), uint64(p384Uint1(x465)))
+ var x468 uint64
+ p384CmovznzU64(&x468, p384Uint1(x467), x454, x441)
+ var x469 uint64
+ p384CmovznzU64(&x469, p384Uint1(x467), x456, x443)
+ var x470 uint64
+ p384CmovznzU64(&x470, p384Uint1(x467), x458, x445)
+ var x471 uint64
+ p384CmovznzU64(&x471, p384Uint1(x467), x460, x447)
+ var x472 uint64
+ p384CmovznzU64(&x472, p384Uint1(x467), x462, x449)
+ var x473 uint64
+ p384CmovznzU64(&x473, p384Uint1(x467), x464, x451)
+ out1[0] = x468
+ out1[1] = x469
+ out1[2] = x470
+ out1[3] = x471
+ out1[4] = x472
+ out1[5] = x473
+}
+
+// p384Add adds two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func p384Add(out1 *p384MontgomeryDomainFieldElement, arg1 *p384MontgomeryDomainFieldElement, arg2 *p384MontgomeryDomainFieldElement) {
+ var x1 uint64
+ var x2 uint64
+ x1, x2 = bits.Add64(arg1[0], arg2[0], uint64(0x0))
+ var x3 uint64
+ var x4 uint64
+ x3, x4 = bits.Add64(arg1[1], arg2[1], uint64(p384Uint1(x2)))
+ var x5 uint64
+ var x6 uint64
+ x5, x6 = bits.Add64(arg1[2], arg2[2], uint64(p384Uint1(x4)))
+ var x7 uint64
+ var x8 uint64
+ x7, x8 = bits.Add64(arg1[3], arg2[3], uint64(p384Uint1(x6)))
+ var x9 uint64
+ var x10 uint64
+ x9, x10 = bits.Add64(arg1[4], arg2[4], uint64(p384Uint1(x8)))
+ var x11 uint64
+ var x12 uint64
+ x11, x12 = bits.Add64(arg1[5], arg2[5], uint64(p384Uint1(x10)))
+ var x13 uint64
+ var x14 uint64
+ x13, x14 = bits.Sub64(x1, 0xffffffff, uint64(0x0))
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Sub64(x3, 0xffffffff00000000, uint64(p384Uint1(x14)))
+ var x17 uint64
+ var x18 uint64
+ x17, x18 = bits.Sub64(x5, 0xfffffffffffffffe, uint64(p384Uint1(x16)))
+ var x19 uint64
+ var x20 uint64
+ x19, x20 = bits.Sub64(x7, 0xffffffffffffffff, uint64(p384Uint1(x18)))
+ var x21 uint64
+ var x22 uint64
+ x21, x22 = bits.Sub64(x9, 0xffffffffffffffff, uint64(p384Uint1(x20)))
+ var x23 uint64
+ var x24 uint64
+ x23, x24 = bits.Sub64(x11, 0xffffffffffffffff, uint64(p384Uint1(x22)))
+ var x26 uint64
+ _, x26 = bits.Sub64(uint64(p384Uint1(x12)), uint64(0x0), uint64(p384Uint1(x24)))
+ var x27 uint64
+ p384CmovznzU64(&x27, p384Uint1(x26), x13, x1)
+ var x28 uint64
+ p384CmovznzU64(&x28, p384Uint1(x26), x15, x3)
+ var x29 uint64
+ p384CmovznzU64(&x29, p384Uint1(x26), x17, x5)
+ var x30 uint64
+ p384CmovznzU64(&x30, p384Uint1(x26), x19, x7)
+ var x31 uint64
+ p384CmovznzU64(&x31, p384Uint1(x26), x21, x9)
+ var x32 uint64
+ p384CmovznzU64(&x32, p384Uint1(x26), x23, x11)
+ out1[0] = x27
+ out1[1] = x28
+ out1[2] = x29
+ out1[3] = x30
+ out1[4] = x31
+ out1[5] = x32
+}
+
+// p384Sub subtracts two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func p384Sub(out1 *p384MontgomeryDomainFieldElement, arg1 *p384MontgomeryDomainFieldElement, arg2 *p384MontgomeryDomainFieldElement) {
+ var x1 uint64
+ var x2 uint64
+ x1, x2 = bits.Sub64(arg1[0], arg2[0], uint64(0x0))
+ var x3 uint64
+ var x4 uint64
+ x3, x4 = bits.Sub64(arg1[1], arg2[1], uint64(p384Uint1(x2)))
+ var x5 uint64
+ var x6 uint64
+ x5, x6 = bits.Sub64(arg1[2], arg2[2], uint64(p384Uint1(x4)))
+ var x7 uint64
+ var x8 uint64
+ x7, x8 = bits.Sub64(arg1[3], arg2[3], uint64(p384Uint1(x6)))
+ var x9 uint64
+ var x10 uint64
+ x9, x10 = bits.Sub64(arg1[4], arg2[4], uint64(p384Uint1(x8)))
+ var x11 uint64
+ var x12 uint64
+ x11, x12 = bits.Sub64(arg1[5], arg2[5], uint64(p384Uint1(x10)))
+ var x13 uint64
+ p384CmovznzU64(&x13, p384Uint1(x12), uint64(0x0), 0xffffffffffffffff)
+ var x14 uint64
+ var x15 uint64
+ x14, x15 = bits.Add64(x1, (x13 & 0xffffffff), uint64(0x0))
+ var x16 uint64
+ var x17 uint64
+ x16, x17 = bits.Add64(x3, (x13 & 0xffffffff00000000), uint64(p384Uint1(x15)))
+ var x18 uint64
+ var x19 uint64
+ x18, x19 = bits.Add64(x5, (x13 & 0xfffffffffffffffe), uint64(p384Uint1(x17)))
+ var x20 uint64
+ var x21 uint64
+ x20, x21 = bits.Add64(x7, x13, uint64(p384Uint1(x19)))
+ var x22 uint64
+ var x23 uint64
+ x22, x23 = bits.Add64(x9, x13, uint64(p384Uint1(x21)))
+ var x24 uint64
+ x24, _ = bits.Add64(x11, x13, uint64(p384Uint1(x23)))
+ out1[0] = x14
+ out1[1] = x16
+ out1[2] = x18
+ out1[3] = x20
+ out1[4] = x22
+ out1[5] = x24
+}
+
+// p384SetOne returns the field element one in the Montgomery domain.
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = 1 mod m
+// 0 ≤ eval out1 < m
+func p384SetOne(out1 *p384MontgomeryDomainFieldElement) {
+ out1[0] = 0xffffffff00000001
+ out1[1] = 0xffffffff
+ out1[2] = uint64(0x1)
+ out1[3] = uint64(0x0)
+ out1[4] = uint64(0x0)
+ out1[5] = uint64(0x0)
+}
+
+// p384FromMontgomery translates a field element out of the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^6) mod m
+// 0 ≤ eval out1 < m
+func p384FromMontgomery(out1 *p384NonMontgomeryDomainFieldElement, arg1 *p384MontgomeryDomainFieldElement) {
+ x1 := arg1[0]
+ var x2 uint64
+ _, x2 = bits.Mul64(x1, 0x100000001)
+ var x4 uint64
+ var x5 uint64
+ x5, x4 = bits.Mul64(x2, 0xffffffffffffffff)
+ var x6 uint64
+ var x7 uint64
+ x7, x6 = bits.Mul64(x2, 0xffffffffffffffff)
+ var x8 uint64
+ var x9 uint64
+ x9, x8 = bits.Mul64(x2, 0xffffffffffffffff)
+ var x10 uint64
+ var x11 uint64
+ x11, x10 = bits.Mul64(x2, 0xfffffffffffffffe)
+ var x12 uint64
+ var x13 uint64
+ x13, x12 = bits.Mul64(x2, 0xffffffff00000000)
+ var x14 uint64
+ var x15 uint64
+ x15, x14 = bits.Mul64(x2, 0xffffffff)
+ var x16 uint64
+ var x17 uint64
+ x16, x17 = bits.Add64(x15, x12, uint64(0x0))
+ var x18 uint64
+ var x19 uint64
+ x18, x19 = bits.Add64(x13, x10, uint64(p384Uint1(x17)))
+ var x20 uint64
+ var x21 uint64
+ x20, x21 = bits.Add64(x11, x8, uint64(p384Uint1(x19)))
+ var x22 uint64
+ var x23 uint64
+ x22, x23 = bits.Add64(x9, x6, uint64(p384Uint1(x21)))
+ var x24 uint64
+ var x25 uint64
+ x24, x25 = bits.Add64(x7, x4, uint64(p384Uint1(x23)))
+ var x27 uint64
+ _, x27 = bits.Add64(x1, x14, uint64(0x0))
+ var x28 uint64
+ var x29 uint64
+ x28, x29 = bits.Add64(uint64(0x0), x16, uint64(p384Uint1(x27)))
+ var x30 uint64
+ var x31 uint64
+ x30, x31 = bits.Add64(uint64(0x0), x18, uint64(p384Uint1(x29)))
+ var x32 uint64
+ var x33 uint64
+ x32, x33 = bits.Add64(uint64(0x0), x20, uint64(p384Uint1(x31)))
+ var x34 uint64
+ var x35 uint64
+ x34, x35 = bits.Add64(uint64(0x0), x22, uint64(p384Uint1(x33)))
+ var x36 uint64
+ var x37 uint64
+ x36, x37 = bits.Add64(uint64(0x0), x24, uint64(p384Uint1(x35)))
+ var x38 uint64
+ var x39 uint64
+ x38, x39 = bits.Add64(uint64(0x0), (uint64(p384Uint1(x25)) + x5), uint64(p384Uint1(x37)))
+ var x40 uint64
+ var x41 uint64
+ x40, x41 = bits.Add64(x28, arg1[1], uint64(0x0))
+ var x42 uint64
+ var x43 uint64
+ x42, x43 = bits.Add64(x30, uint64(0x0), uint64(p384Uint1(x41)))
+ var x44 uint64
+ var x45 uint64
+ x44, x45 = bits.Add64(x32, uint64(0x0), uint64(p384Uint1(x43)))
+ var x46 uint64
+ var x47 uint64
+ x46, x47 = bits.Add64(x34, uint64(0x0), uint64(p384Uint1(x45)))
+ var x48 uint64
+ var x49 uint64
+ x48, x49 = bits.Add64(x36, uint64(0x0), uint64(p384Uint1(x47)))
+ var x50 uint64
+ var x51 uint64
+ x50, x51 = bits.Add64(x38, uint64(0x0), uint64(p384Uint1(x49)))
+ var x52 uint64
+ _, x52 = bits.Mul64(x40, 0x100000001)
+ var x54 uint64
+ var x55 uint64
+ x55, x54 = bits.Mul64(x52, 0xffffffffffffffff)
+ var x56 uint64
+ var x57 uint64
+ x57, x56 = bits.Mul64(x52, 0xffffffffffffffff)
+ var x58 uint64
+ var x59 uint64
+ x59, x58 = bits.Mul64(x52, 0xffffffffffffffff)
+ var x60 uint64
+ var x61 uint64
+ x61, x60 = bits.Mul64(x52, 0xfffffffffffffffe)
+ var x62 uint64
+ var x63 uint64
+ x63, x62 = bits.Mul64(x52, 0xffffffff00000000)
+ var x64 uint64
+ var x65 uint64
+ x65, x64 = bits.Mul64(x52, 0xffffffff)
+ var x66 uint64
+ var x67 uint64
+ x66, x67 = bits.Add64(x65, x62, uint64(0x0))
+ var x68 uint64
+ var x69 uint64
+ x68, x69 = bits.Add64(x63, x60, uint64(p384Uint1(x67)))
+ var x70 uint64
+ var x71 uint64
+ x70, x71 = bits.Add64(x61, x58, uint64(p384Uint1(x69)))
+ var x72 uint64
+ var x73 uint64
+ x72, x73 = bits.Add64(x59, x56, uint64(p384Uint1(x71)))
+ var x74 uint64
+ var x75 uint64
+ x74, x75 = bits.Add64(x57, x54, uint64(p384Uint1(x73)))
+ var x77 uint64
+ _, x77 = bits.Add64(x40, x64, uint64(0x0))
+ var x78 uint64
+ var x79 uint64
+ x78, x79 = bits.Add64(x42, x66, uint64(p384Uint1(x77)))
+ var x80 uint64
+ var x81 uint64
+ x80, x81 = bits.Add64(x44, x68, uint64(p384Uint1(x79)))
+ var x82 uint64
+ var x83 uint64
+ x82, x83 = bits.Add64(x46, x70, uint64(p384Uint1(x81)))
+ var x84 uint64
+ var x85 uint64
+ x84, x85 = bits.Add64(x48, x72, uint64(p384Uint1(x83)))
+ var x86 uint64
+ var x87 uint64
+ x86, x87 = bits.Add64(x50, x74, uint64(p384Uint1(x85)))
+ var x88 uint64
+ var x89 uint64
+ x88, x89 = bits.Add64((uint64(p384Uint1(x51)) + uint64(p384Uint1(x39))), (uint64(p384Uint1(x75)) + x55), uint64(p384Uint1(x87)))
+ var x90 uint64
+ var x91 uint64
+ x90, x91 = bits.Add64(x78, arg1[2], uint64(0x0))
+ var x92 uint64
+ var x93 uint64
+ x92, x93 = bits.Add64(x80, uint64(0x0), uint64(p384Uint1(x91)))
+ var x94 uint64
+ var x95 uint64
+ x94, x95 = bits.Add64(x82, uint64(0x0), uint64(p384Uint1(x93)))
+ var x96 uint64
+ var x97 uint64
+ x96, x97 = bits.Add64(x84, uint64(0x0), uint64(p384Uint1(x95)))
+ var x98 uint64
+ var x99 uint64
+ x98, x99 = bits.Add64(x86, uint64(0x0), uint64(p384Uint1(x97)))
+ var x100 uint64
+ var x101 uint64
+ x100, x101 = bits.Add64(x88, uint64(0x0), uint64(p384Uint1(x99)))
+ var x102 uint64
+ _, x102 = bits.Mul64(x90, 0x100000001)
+ var x104 uint64
+ var x105 uint64
+ x105, x104 = bits.Mul64(x102, 0xffffffffffffffff)
+ var x106 uint64
+ var x107 uint64
+ x107, x106 = bits.Mul64(x102, 0xffffffffffffffff)
+ var x108 uint64
+ var x109 uint64
+ x109, x108 = bits.Mul64(x102, 0xffffffffffffffff)
+ var x110 uint64
+ var x111 uint64
+ x111, x110 = bits.Mul64(x102, 0xfffffffffffffffe)
+ var x112 uint64
+ var x113 uint64
+ x113, x112 = bits.Mul64(x102, 0xffffffff00000000)
+ var x114 uint64
+ var x115 uint64
+ x115, x114 = bits.Mul64(x102, 0xffffffff)
+ var x116 uint64
+ var x117 uint64
+ x116, x117 = bits.Add64(x115, x112, uint64(0x0))
+ var x118 uint64
+ var x119 uint64
+ x118, x119 = bits.Add64(x113, x110, uint64(p384Uint1(x117)))
+ var x120 uint64
+ var x121 uint64
+ x120, x121 = bits.Add64(x111, x108, uint64(p384Uint1(x119)))
+ var x122 uint64
+ var x123 uint64
+ x122, x123 = bits.Add64(x109, x106, uint64(p384Uint1(x121)))
+ var x124 uint64
+ var x125 uint64
+ x124, x125 = bits.Add64(x107, x104, uint64(p384Uint1(x123)))
+ var x127 uint64
+ _, x127 = bits.Add64(x90, x114, uint64(0x0))
+ var x128 uint64
+ var x129 uint64
+ x128, x129 = bits.Add64(x92, x116, uint64(p384Uint1(x127)))
+ var x130 uint64
+ var x131 uint64
+ x130, x131 = bits.Add64(x94, x118, uint64(p384Uint1(x129)))
+ var x132 uint64
+ var x133 uint64
+ x132, x133 = bits.Add64(x96, x120, uint64(p384Uint1(x131)))
+ var x134 uint64
+ var x135 uint64
+ x134, x135 = bits.Add64(x98, x122, uint64(p384Uint1(x133)))
+ var x136 uint64
+ var x137 uint64
+ x136, x137 = bits.Add64(x100, x124, uint64(p384Uint1(x135)))
+ var x138 uint64
+ var x139 uint64
+ x138, x139 = bits.Add64((uint64(p384Uint1(x101)) + uint64(p384Uint1(x89))), (uint64(p384Uint1(x125)) + x105), uint64(p384Uint1(x137)))
+ var x140 uint64
+ var x141 uint64
+ x140, x141 = bits.Add64(x128, arg1[3], uint64(0x0))
+ var x142 uint64
+ var x143 uint64
+ x142, x143 = bits.Add64(x130, uint64(0x0), uint64(p384Uint1(x141)))
+ var x144 uint64
+ var x145 uint64
+ x144, x145 = bits.Add64(x132, uint64(0x0), uint64(p384Uint1(x143)))
+ var x146 uint64
+ var x147 uint64
+ x146, x147 = bits.Add64(x134, uint64(0x0), uint64(p384Uint1(x145)))
+ var x148 uint64
+ var x149 uint64
+ x148, x149 = bits.Add64(x136, uint64(0x0), uint64(p384Uint1(x147)))
+ var x150 uint64
+ var x151 uint64
+ x150, x151 = bits.Add64(x138, uint64(0x0), uint64(p384Uint1(x149)))
+ var x152 uint64
+ _, x152 = bits.Mul64(x140, 0x100000001)
+ var x154 uint64
+ var x155 uint64
+ x155, x154 = bits.Mul64(x152, 0xffffffffffffffff)
+ var x156 uint64
+ var x157 uint64
+ x157, x156 = bits.Mul64(x152, 0xffffffffffffffff)
+ var x158 uint64
+ var x159 uint64
+ x159, x158 = bits.Mul64(x152, 0xffffffffffffffff)
+ var x160 uint64
+ var x161 uint64
+ x161, x160 = bits.Mul64(x152, 0xfffffffffffffffe)
+ var x162 uint64
+ var x163 uint64
+ x163, x162 = bits.Mul64(x152, 0xffffffff00000000)
+ var x164 uint64
+ var x165 uint64
+ x165, x164 = bits.Mul64(x152, 0xffffffff)
+ var x166 uint64
+ var x167 uint64
+ x166, x167 = bits.Add64(x165, x162, uint64(0x0))
+ var x168 uint64
+ var x169 uint64
+ x168, x169 = bits.Add64(x163, x160, uint64(p384Uint1(x167)))
+ var x170 uint64
+ var x171 uint64
+ x170, x171 = bits.Add64(x161, x158, uint64(p384Uint1(x169)))
+ var x172 uint64
+ var x173 uint64
+ x172, x173 = bits.Add64(x159, x156, uint64(p384Uint1(x171)))
+ var x174 uint64
+ var x175 uint64
+ x174, x175 = bits.Add64(x157, x154, uint64(p384Uint1(x173)))
+ var x177 uint64
+ _, x177 = bits.Add64(x140, x164, uint64(0x0))
+ var x178 uint64
+ var x179 uint64
+ x178, x179 = bits.Add64(x142, x166, uint64(p384Uint1(x177)))
+ var x180 uint64
+ var x181 uint64
+ x180, x181 = bits.Add64(x144, x168, uint64(p384Uint1(x179)))
+ var x182 uint64
+ var x183 uint64
+ x182, x183 = bits.Add64(x146, x170, uint64(p384Uint1(x181)))
+ var x184 uint64
+ var x185 uint64
+ x184, x185 = bits.Add64(x148, x172, uint64(p384Uint1(x183)))
+ var x186 uint64
+ var x187 uint64
+ x186, x187 = bits.Add64(x150, x174, uint64(p384Uint1(x185)))
+ var x188 uint64
+ var x189 uint64
+ x188, x189 = bits.Add64((uint64(p384Uint1(x151)) + uint64(p384Uint1(x139))), (uint64(p384Uint1(x175)) + x155), uint64(p384Uint1(x187)))
+ var x190 uint64
+ var x191 uint64
+ x190, x191 = bits.Add64(x178, arg1[4], uint64(0x0))
+ var x192 uint64
+ var x193 uint64
+ x192, x193 = bits.Add64(x180, uint64(0x0), uint64(p384Uint1(x191)))
+ var x194 uint64
+ var x195 uint64
+ x194, x195 = bits.Add64(x182, uint64(0x0), uint64(p384Uint1(x193)))
+ var x196 uint64
+ var x197 uint64
+ x196, x197 = bits.Add64(x184, uint64(0x0), uint64(p384Uint1(x195)))
+ var x198 uint64
+ var x199 uint64
+ x198, x199 = bits.Add64(x186, uint64(0x0), uint64(p384Uint1(x197)))
+ var x200 uint64
+ var x201 uint64
+ x200, x201 = bits.Add64(x188, uint64(0x0), uint64(p384Uint1(x199)))
+ var x202 uint64
+ _, x202 = bits.Mul64(x190, 0x100000001)
+ var x204 uint64
+ var x205 uint64
+ x205, x204 = bits.Mul64(x202, 0xffffffffffffffff)
+ var x206 uint64
+ var x207 uint64
+ x207, x206 = bits.Mul64(x202, 0xffffffffffffffff)
+ var x208 uint64
+ var x209 uint64
+ x209, x208 = bits.Mul64(x202, 0xffffffffffffffff)
+ var x210 uint64
+ var x211 uint64
+ x211, x210 = bits.Mul64(x202, 0xfffffffffffffffe)
+ var x212 uint64
+ var x213 uint64
+ x213, x212 = bits.Mul64(x202, 0xffffffff00000000)
+ var x214 uint64
+ var x215 uint64
+ x215, x214 = bits.Mul64(x202, 0xffffffff)
+ var x216 uint64
+ var x217 uint64
+ x216, x217 = bits.Add64(x215, x212, uint64(0x0))
+ var x218 uint64
+ var x219 uint64
+ x218, x219 = bits.Add64(x213, x210, uint64(p384Uint1(x217)))
+ var x220 uint64
+ var x221 uint64
+ x220, x221 = bits.Add64(x211, x208, uint64(p384Uint1(x219)))
+ var x222 uint64
+ var x223 uint64
+ x222, x223 = bits.Add64(x209, x206, uint64(p384Uint1(x221)))
+ var x224 uint64
+ var x225 uint64
+ x224, x225 = bits.Add64(x207, x204, uint64(p384Uint1(x223)))
+ var x227 uint64
+ _, x227 = bits.Add64(x190, x214, uint64(0x0))
+ var x228 uint64
+ var x229 uint64
+ x228, x229 = bits.Add64(x192, x216, uint64(p384Uint1(x227)))
+ var x230 uint64
+ var x231 uint64
+ x230, x231 = bits.Add64(x194, x218, uint64(p384Uint1(x229)))
+ var x232 uint64
+ var x233 uint64
+ x232, x233 = bits.Add64(x196, x220, uint64(p384Uint1(x231)))
+ var x234 uint64
+ var x235 uint64
+ x234, x235 = bits.Add64(x198, x222, uint64(p384Uint1(x233)))
+ var x236 uint64
+ var x237 uint64
+ x236, x237 = bits.Add64(x200, x224, uint64(p384Uint1(x235)))
+ var x238 uint64
+ var x239 uint64
+ x238, x239 = bits.Add64((uint64(p384Uint1(x201)) + uint64(p384Uint1(x189))), (uint64(p384Uint1(x225)) + x205), uint64(p384Uint1(x237)))
+ var x240 uint64
+ var x241 uint64
+ x240, x241 = bits.Add64(x228, arg1[5], uint64(0x0))
+ var x242 uint64
+ var x243 uint64
+ x242, x243 = bits.Add64(x230, uint64(0x0), uint64(p384Uint1(x241)))
+ var x244 uint64
+ var x245 uint64
+ x244, x245 = bits.Add64(x232, uint64(0x0), uint64(p384Uint1(x243)))
+ var x246 uint64
+ var x247 uint64
+ x246, x247 = bits.Add64(x234, uint64(0x0), uint64(p384Uint1(x245)))
+ var x248 uint64
+ var x249 uint64
+ x248, x249 = bits.Add64(x236, uint64(0x0), uint64(p384Uint1(x247)))
+ var x250 uint64
+ var x251 uint64
+ x250, x251 = bits.Add64(x238, uint64(0x0), uint64(p384Uint1(x249)))
+ var x252 uint64
+ _, x252 = bits.Mul64(x240, 0x100000001)
+ var x254 uint64
+ var x255 uint64
+ x255, x254 = bits.Mul64(x252, 0xffffffffffffffff)
+ var x256 uint64
+ var x257 uint64
+ x257, x256 = bits.Mul64(x252, 0xffffffffffffffff)
+ var x258 uint64
+ var x259 uint64
+ x259, x258 = bits.Mul64(x252, 0xffffffffffffffff)
+ var x260 uint64
+ var x261 uint64
+ x261, x260 = bits.Mul64(x252, 0xfffffffffffffffe)
+ var x262 uint64
+ var x263 uint64
+ x263, x262 = bits.Mul64(x252, 0xffffffff00000000)
+ var x264 uint64
+ var x265 uint64
+ x265, x264 = bits.Mul64(x252, 0xffffffff)
+ var x266 uint64
+ var x267 uint64
+ x266, x267 = bits.Add64(x265, x262, uint64(0x0))
+ var x268 uint64
+ var x269 uint64
+ x268, x269 = bits.Add64(x263, x260, uint64(p384Uint1(x267)))
+ var x270 uint64
+ var x271 uint64
+ x270, x271 = bits.Add64(x261, x258, uint64(p384Uint1(x269)))
+ var x272 uint64
+ var x273 uint64
+ x272, x273 = bits.Add64(x259, x256, uint64(p384Uint1(x271)))
+ var x274 uint64
+ var x275 uint64
+ x274, x275 = bits.Add64(x257, x254, uint64(p384Uint1(x273)))
+ var x277 uint64
+ _, x277 = bits.Add64(x240, x264, uint64(0x0))
+ var x278 uint64
+ var x279 uint64
+ x278, x279 = bits.Add64(x242, x266, uint64(p384Uint1(x277)))
+ var x280 uint64
+ var x281 uint64
+ x280, x281 = bits.Add64(x244, x268, uint64(p384Uint1(x279)))
+ var x282 uint64
+ var x283 uint64
+ x282, x283 = bits.Add64(x246, x270, uint64(p384Uint1(x281)))
+ var x284 uint64
+ var x285 uint64
+ x284, x285 = bits.Add64(x248, x272, uint64(p384Uint1(x283)))
+ var x286 uint64
+ var x287 uint64
+ x286, x287 = bits.Add64(x250, x274, uint64(p384Uint1(x285)))
+ var x288 uint64
+ var x289 uint64
+ x288, x289 = bits.Add64((uint64(p384Uint1(x251)) + uint64(p384Uint1(x239))), (uint64(p384Uint1(x275)) + x255), uint64(p384Uint1(x287)))
+ var x290 uint64
+ var x291 uint64
+ x290, x291 = bits.Sub64(x278, 0xffffffff, uint64(0x0))
+ var x292 uint64
+ var x293 uint64
+ x292, x293 = bits.Sub64(x280, 0xffffffff00000000, uint64(p384Uint1(x291)))
+ var x294 uint64
+ var x295 uint64
+ x294, x295 = bits.Sub64(x282, 0xfffffffffffffffe, uint64(p384Uint1(x293)))
+ var x296 uint64
+ var x297 uint64
+ x296, x297 = bits.Sub64(x284, 0xffffffffffffffff, uint64(p384Uint1(x295)))
+ var x298 uint64
+ var x299 uint64
+ x298, x299 = bits.Sub64(x286, 0xffffffffffffffff, uint64(p384Uint1(x297)))
+ var x300 uint64
+ var x301 uint64
+ x300, x301 = bits.Sub64(x288, 0xffffffffffffffff, uint64(p384Uint1(x299)))
+ var x303 uint64
+ _, x303 = bits.Sub64(uint64(p384Uint1(x289)), uint64(0x0), uint64(p384Uint1(x301)))
+ var x304 uint64
+ p384CmovznzU64(&x304, p384Uint1(x303), x290, x278)
+ var x305 uint64
+ p384CmovznzU64(&x305, p384Uint1(x303), x292, x280)
+ var x306 uint64
+ p384CmovznzU64(&x306, p384Uint1(x303), x294, x282)
+ var x307 uint64
+ p384CmovznzU64(&x307, p384Uint1(x303), x296, x284)
+ var x308 uint64
+ p384CmovznzU64(&x308, p384Uint1(x303), x298, x286)
+ var x309 uint64
+ p384CmovznzU64(&x309, p384Uint1(x303), x300, x288)
+ out1[0] = x304
+ out1[1] = x305
+ out1[2] = x306
+ out1[3] = x307
+ out1[4] = x308
+ out1[5] = x309
+}
+
+// p384ToMontgomery translates a field element into the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = eval arg1 mod m
+// 0 ≤ eval out1 < m
+func p384ToMontgomery(out1 *p384MontgomeryDomainFieldElement, arg1 *p384NonMontgomeryDomainFieldElement) {
+ x1 := arg1[1]
+ x2 := arg1[2]
+ x3 := arg1[3]
+ x4 := arg1[4]
+ x5 := arg1[5]
+ x6 := arg1[0]
+ var x7 uint64
+ var x8 uint64
+ x8, x7 = bits.Mul64(x6, 0x200000000)
+ var x9 uint64
+ var x10 uint64
+ x10, x9 = bits.Mul64(x6, 0xfffffffe00000000)
+ var x11 uint64
+ var x12 uint64
+ x12, x11 = bits.Mul64(x6, 0x200000000)
+ var x13 uint64
+ var x14 uint64
+ x14, x13 = bits.Mul64(x6, 0xfffffffe00000001)
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Add64(x14, x11, uint64(0x0))
+ var x17 uint64
+ var x18 uint64
+ x17, x18 = bits.Add64(x12, x9, uint64(p384Uint1(x16)))
+ var x19 uint64
+ var x20 uint64
+ x19, x20 = bits.Add64(x10, x7, uint64(p384Uint1(x18)))
+ var x21 uint64
+ var x22 uint64
+ x21, x22 = bits.Add64(x8, x6, uint64(p384Uint1(x20)))
+ var x23 uint64
+ _, x23 = bits.Mul64(x13, 0x100000001)
+ var x25 uint64
+ var x26 uint64
+ x26, x25 = bits.Mul64(x23, 0xffffffffffffffff)
+ var x27 uint64
+ var x28 uint64
+ x28, x27 = bits.Mul64(x23, 0xffffffffffffffff)
+ var x29 uint64
+ var x30 uint64
+ x30, x29 = bits.Mul64(x23, 0xffffffffffffffff)
+ var x31 uint64
+ var x32 uint64
+ x32, x31 = bits.Mul64(x23, 0xfffffffffffffffe)
+ var x33 uint64
+ var x34 uint64
+ x34, x33 = bits.Mul64(x23, 0xffffffff00000000)
+ var x35 uint64
+ var x36 uint64
+ x36, x35 = bits.Mul64(x23, 0xffffffff)
+ var x37 uint64
+ var x38 uint64
+ x37, x38 = bits.Add64(x36, x33, uint64(0x0))
+ var x39 uint64
+ var x40 uint64
+ x39, x40 = bits.Add64(x34, x31, uint64(p384Uint1(x38)))
+ var x41 uint64
+ var x42 uint64
+ x41, x42 = bits.Add64(x32, x29, uint64(p384Uint1(x40)))
+ var x43 uint64
+ var x44 uint64
+ x43, x44 = bits.Add64(x30, x27, uint64(p384Uint1(x42)))
+ var x45 uint64
+ var x46 uint64
+ x45, x46 = bits.Add64(x28, x25, uint64(p384Uint1(x44)))
+ var x48 uint64
+ _, x48 = bits.Add64(x13, x35, uint64(0x0))
+ var x49 uint64
+ var x50 uint64
+ x49, x50 = bits.Add64(x15, x37, uint64(p384Uint1(x48)))
+ var x51 uint64
+ var x52 uint64
+ x51, x52 = bits.Add64(x17, x39, uint64(p384Uint1(x50)))
+ var x53 uint64
+ var x54 uint64
+ x53, x54 = bits.Add64(x19, x41, uint64(p384Uint1(x52)))
+ var x55 uint64
+ var x56 uint64
+ x55, x56 = bits.Add64(x21, x43, uint64(p384Uint1(x54)))
+ var x57 uint64
+ var x58 uint64
+ x57, x58 = bits.Add64(uint64(p384Uint1(x22)), x45, uint64(p384Uint1(x56)))
+ var x59 uint64
+ var x60 uint64
+ x59, x60 = bits.Add64(uint64(0x0), (uint64(p384Uint1(x46)) + x26), uint64(p384Uint1(x58)))
+ var x61 uint64
+ var x62 uint64
+ x62, x61 = bits.Mul64(x1, 0x200000000)
+ var x63 uint64
+ var x64 uint64
+ x64, x63 = bits.Mul64(x1, 0xfffffffe00000000)
+ var x65 uint64
+ var x66 uint64
+ x66, x65 = bits.Mul64(x1, 0x200000000)
+ var x67 uint64
+ var x68 uint64
+ x68, x67 = bits.Mul64(x1, 0xfffffffe00000001)
+ var x69 uint64
+ var x70 uint64
+ x69, x70 = bits.Add64(x68, x65, uint64(0x0))
+ var x71 uint64
+ var x72 uint64
+ x71, x72 = bits.Add64(x66, x63, uint64(p384Uint1(x70)))
+ var x73 uint64
+ var x74 uint64
+ x73, x74 = bits.Add64(x64, x61, uint64(p384Uint1(x72)))
+ var x75 uint64
+ var x76 uint64
+ x75, x76 = bits.Add64(x62, x1, uint64(p384Uint1(x74)))
+ var x77 uint64
+ var x78 uint64
+ x77, x78 = bits.Add64(x49, x67, uint64(0x0))
+ var x79 uint64
+ var x80 uint64
+ x79, x80 = bits.Add64(x51, x69, uint64(p384Uint1(x78)))
+ var x81 uint64
+ var x82 uint64
+ x81, x82 = bits.Add64(x53, x71, uint64(p384Uint1(x80)))
+ var x83 uint64
+ var x84 uint64
+ x83, x84 = bits.Add64(x55, x73, uint64(p384Uint1(x82)))
+ var x85 uint64
+ var x86 uint64
+ x85, x86 = bits.Add64(x57, x75, uint64(p384Uint1(x84)))
+ var x87 uint64
+ var x88 uint64
+ x87, x88 = bits.Add64(x59, uint64(p384Uint1(x76)), uint64(p384Uint1(x86)))
+ var x89 uint64
+ _, x89 = bits.Mul64(x77, 0x100000001)
+ var x91 uint64
+ var x92 uint64
+ x92, x91 = bits.Mul64(x89, 0xffffffffffffffff)
+ var x93 uint64
+ var x94 uint64
+ x94, x93 = bits.Mul64(x89, 0xffffffffffffffff)
+ var x95 uint64
+ var x96 uint64
+ x96, x95 = bits.Mul64(x89, 0xffffffffffffffff)
+ var x97 uint64
+ var x98 uint64
+ x98, x97 = bits.Mul64(x89, 0xfffffffffffffffe)
+ var x99 uint64
+ var x100 uint64
+ x100, x99 = bits.Mul64(x89, 0xffffffff00000000)
+ var x101 uint64
+ var x102 uint64
+ x102, x101 = bits.Mul64(x89, 0xffffffff)
+ var x103 uint64
+ var x104 uint64
+ x103, x104 = bits.Add64(x102, x99, uint64(0x0))
+ var x105 uint64
+ var x106 uint64
+ x105, x106 = bits.Add64(x100, x97, uint64(p384Uint1(x104)))
+ var x107 uint64
+ var x108 uint64
+ x107, x108 = bits.Add64(x98, x95, uint64(p384Uint1(x106)))
+ var x109 uint64
+ var x110 uint64
+ x109, x110 = bits.Add64(x96, x93, uint64(p384Uint1(x108)))
+ var x111 uint64
+ var x112 uint64
+ x111, x112 = bits.Add64(x94, x91, uint64(p384Uint1(x110)))
+ var x114 uint64
+ _, x114 = bits.Add64(x77, x101, uint64(0x0))
+ var x115 uint64
+ var x116 uint64
+ x115, x116 = bits.Add64(x79, x103, uint64(p384Uint1(x114)))
+ var x117 uint64
+ var x118 uint64
+ x117, x118 = bits.Add64(x81, x105, uint64(p384Uint1(x116)))
+ var x119 uint64
+ var x120 uint64
+ x119, x120 = bits.Add64(x83, x107, uint64(p384Uint1(x118)))
+ var x121 uint64
+ var x122 uint64
+ x121, x122 = bits.Add64(x85, x109, uint64(p384Uint1(x120)))
+ var x123 uint64
+ var x124 uint64
+ x123, x124 = bits.Add64(x87, x111, uint64(p384Uint1(x122)))
+ var x125 uint64
+ var x126 uint64
+ x125, x126 = bits.Add64((uint64(p384Uint1(x88)) + uint64(p384Uint1(x60))), (uint64(p384Uint1(x112)) + x92), uint64(p384Uint1(x124)))
+ var x127 uint64
+ var x128 uint64
+ x128, x127 = bits.Mul64(x2, 0x200000000)
+ var x129 uint64
+ var x130 uint64
+ x130, x129 = bits.Mul64(x2, 0xfffffffe00000000)
+ var x131 uint64
+ var x132 uint64
+ x132, x131 = bits.Mul64(x2, 0x200000000)
+ var x133 uint64
+ var x134 uint64
+ x134, x133 = bits.Mul64(x2, 0xfffffffe00000001)
+ var x135 uint64
+ var x136 uint64
+ x135, x136 = bits.Add64(x134, x131, uint64(0x0))
+ var x137 uint64
+ var x138 uint64
+ x137, x138 = bits.Add64(x132, x129, uint64(p384Uint1(x136)))
+ var x139 uint64
+ var x140 uint64
+ x139, x140 = bits.Add64(x130, x127, uint64(p384Uint1(x138)))
+ var x141 uint64
+ var x142 uint64
+ x141, x142 = bits.Add64(x128, x2, uint64(p384Uint1(x140)))
+ var x143 uint64
+ var x144 uint64
+ x143, x144 = bits.Add64(x115, x133, uint64(0x0))
+ var x145 uint64
+ var x146 uint64
+ x145, x146 = bits.Add64(x117, x135, uint64(p384Uint1(x144)))
+ var x147 uint64
+ var x148 uint64
+ x147, x148 = bits.Add64(x119, x137, uint64(p384Uint1(x146)))
+ var x149 uint64
+ var x150 uint64
+ x149, x150 = bits.Add64(x121, x139, uint64(p384Uint1(x148)))
+ var x151 uint64
+ var x152 uint64
+ x151, x152 = bits.Add64(x123, x141, uint64(p384Uint1(x150)))
+ var x153 uint64
+ var x154 uint64
+ x153, x154 = bits.Add64(x125, uint64(p384Uint1(x142)), uint64(p384Uint1(x152)))
+ var x155 uint64
+ _, x155 = bits.Mul64(x143, 0x100000001)
+ var x157 uint64
+ var x158 uint64
+ x158, x157 = bits.Mul64(x155, 0xffffffffffffffff)
+ var x159 uint64
+ var x160 uint64
+ x160, x159 = bits.Mul64(x155, 0xffffffffffffffff)
+ var x161 uint64
+ var x162 uint64
+ x162, x161 = bits.Mul64(x155, 0xffffffffffffffff)
+ var x163 uint64
+ var x164 uint64
+ x164, x163 = bits.Mul64(x155, 0xfffffffffffffffe)
+ var x165 uint64
+ var x166 uint64
+ x166, x165 = bits.Mul64(x155, 0xffffffff00000000)
+ var x167 uint64
+ var x168 uint64
+ x168, x167 = bits.Mul64(x155, 0xffffffff)
+ var x169 uint64
+ var x170 uint64
+ x169, x170 = bits.Add64(x168, x165, uint64(0x0))
+ var x171 uint64
+ var x172 uint64
+ x171, x172 = bits.Add64(x166, x163, uint64(p384Uint1(x170)))
+ var x173 uint64
+ var x174 uint64
+ x173, x174 = bits.Add64(x164, x161, uint64(p384Uint1(x172)))
+ var x175 uint64
+ var x176 uint64
+ x175, x176 = bits.Add64(x162, x159, uint64(p384Uint1(x174)))
+ var x177 uint64
+ var x178 uint64
+ x177, x178 = bits.Add64(x160, x157, uint64(p384Uint1(x176)))
+ var x180 uint64
+ _, x180 = bits.Add64(x143, x167, uint64(0x0))
+ var x181 uint64
+ var x182 uint64
+ x181, x182 = bits.Add64(x145, x169, uint64(p384Uint1(x180)))
+ var x183 uint64
+ var x184 uint64
+ x183, x184 = bits.Add64(x147, x171, uint64(p384Uint1(x182)))
+ var x185 uint64
+ var x186 uint64
+ x185, x186 = bits.Add64(x149, x173, uint64(p384Uint1(x184)))
+ var x187 uint64
+ var x188 uint64
+ x187, x188 = bits.Add64(x151, x175, uint64(p384Uint1(x186)))
+ var x189 uint64
+ var x190 uint64
+ x189, x190 = bits.Add64(x153, x177, uint64(p384Uint1(x188)))
+ var x191 uint64
+ var x192 uint64
+ x191, x192 = bits.Add64((uint64(p384Uint1(x154)) + uint64(p384Uint1(x126))), (uint64(p384Uint1(x178)) + x158), uint64(p384Uint1(x190)))
+ var x193 uint64
+ var x194 uint64
+ x194, x193 = bits.Mul64(x3, 0x200000000)
+ var x195 uint64
+ var x196 uint64
+ x196, x195 = bits.Mul64(x3, 0xfffffffe00000000)
+ var x197 uint64
+ var x198 uint64
+ x198, x197 = bits.Mul64(x3, 0x200000000)
+ var x199 uint64
+ var x200 uint64
+ x200, x199 = bits.Mul64(x3, 0xfffffffe00000001)
+ var x201 uint64
+ var x202 uint64
+ x201, x202 = bits.Add64(x200, x197, uint64(0x0))
+ var x203 uint64
+ var x204 uint64
+ x203, x204 = bits.Add64(x198, x195, uint64(p384Uint1(x202)))
+ var x205 uint64
+ var x206 uint64
+ x205, x206 = bits.Add64(x196, x193, uint64(p384Uint1(x204)))
+ var x207 uint64
+ var x208 uint64
+ x207, x208 = bits.Add64(x194, x3, uint64(p384Uint1(x206)))
+ var x209 uint64
+ var x210 uint64
+ x209, x210 = bits.Add64(x181, x199, uint64(0x0))
+ var x211 uint64
+ var x212 uint64
+ x211, x212 = bits.Add64(x183, x201, uint64(p384Uint1(x210)))
+ var x213 uint64
+ var x214 uint64
+ x213, x214 = bits.Add64(x185, x203, uint64(p384Uint1(x212)))
+ var x215 uint64
+ var x216 uint64
+ x215, x216 = bits.Add64(x187, x205, uint64(p384Uint1(x214)))
+ var x217 uint64
+ var x218 uint64
+ x217, x218 = bits.Add64(x189, x207, uint64(p384Uint1(x216)))
+ var x219 uint64
+ var x220 uint64
+ x219, x220 = bits.Add64(x191, uint64(p384Uint1(x208)), uint64(p384Uint1(x218)))
+ var x221 uint64
+ _, x221 = bits.Mul64(x209, 0x100000001)
+ var x223 uint64
+ var x224 uint64
+ x224, x223 = bits.Mul64(x221, 0xffffffffffffffff)
+ var x225 uint64
+ var x226 uint64
+ x226, x225 = bits.Mul64(x221, 0xffffffffffffffff)
+ var x227 uint64
+ var x228 uint64
+ x228, x227 = bits.Mul64(x221, 0xffffffffffffffff)
+ var x229 uint64
+ var x230 uint64
+ x230, x229 = bits.Mul64(x221, 0xfffffffffffffffe)
+ var x231 uint64
+ var x232 uint64
+ x232, x231 = bits.Mul64(x221, 0xffffffff00000000)
+ var x233 uint64
+ var x234 uint64
+ x234, x233 = bits.Mul64(x221, 0xffffffff)
+ var x235 uint64
+ var x236 uint64
+ x235, x236 = bits.Add64(x234, x231, uint64(0x0))
+ var x237 uint64
+ var x238 uint64
+ x237, x238 = bits.Add64(x232, x229, uint64(p384Uint1(x236)))
+ var x239 uint64
+ var x240 uint64
+ x239, x240 = bits.Add64(x230, x227, uint64(p384Uint1(x238)))
+ var x241 uint64
+ var x242 uint64
+ x241, x242 = bits.Add64(x228, x225, uint64(p384Uint1(x240)))
+ var x243 uint64
+ var x244 uint64
+ x243, x244 = bits.Add64(x226, x223, uint64(p384Uint1(x242)))
+ var x246 uint64
+ _, x246 = bits.Add64(x209, x233, uint64(0x0))
+ var x247 uint64
+ var x248 uint64
+ x247, x248 = bits.Add64(x211, x235, uint64(p384Uint1(x246)))
+ var x249 uint64
+ var x250 uint64
+ x249, x250 = bits.Add64(x213, x237, uint64(p384Uint1(x248)))
+ var x251 uint64
+ var x252 uint64
+ x251, x252 = bits.Add64(x215, x239, uint64(p384Uint1(x250)))
+ var x253 uint64
+ var x254 uint64
+ x253, x254 = bits.Add64(x217, x241, uint64(p384Uint1(x252)))
+ var x255 uint64
+ var x256 uint64
+ x255, x256 = bits.Add64(x219, x243, uint64(p384Uint1(x254)))
+ var x257 uint64
+ var x258 uint64
+ x257, x258 = bits.Add64((uint64(p384Uint1(x220)) + uint64(p384Uint1(x192))), (uint64(p384Uint1(x244)) + x224), uint64(p384Uint1(x256)))
+ var x259 uint64
+ var x260 uint64
+ x260, x259 = bits.Mul64(x4, 0x200000000)
+ var x261 uint64
+ var x262 uint64
+ x262, x261 = bits.Mul64(x4, 0xfffffffe00000000)
+ var x263 uint64
+ var x264 uint64
+ x264, x263 = bits.Mul64(x4, 0x200000000)
+ var x265 uint64
+ var x266 uint64
+ x266, x265 = bits.Mul64(x4, 0xfffffffe00000001)
+ var x267 uint64
+ var x268 uint64
+ x267, x268 = bits.Add64(x266, x263, uint64(0x0))
+ var x269 uint64
+ var x270 uint64
+ x269, x270 = bits.Add64(x264, x261, uint64(p384Uint1(x268)))
+ var x271 uint64
+ var x272 uint64
+ x271, x272 = bits.Add64(x262, x259, uint64(p384Uint1(x270)))
+ var x273 uint64
+ var x274 uint64
+ x273, x274 = bits.Add64(x260, x4, uint64(p384Uint1(x272)))
+ var x275 uint64
+ var x276 uint64
+ x275, x276 = bits.Add64(x247, x265, uint64(0x0))
+ var x277 uint64
+ var x278 uint64
+ x277, x278 = bits.Add64(x249, x267, uint64(p384Uint1(x276)))
+ var x279 uint64
+ var x280 uint64
+ x279, x280 = bits.Add64(x251, x269, uint64(p384Uint1(x278)))
+ var x281 uint64
+ var x282 uint64
+ x281, x282 = bits.Add64(x253, x271, uint64(p384Uint1(x280)))
+ var x283 uint64
+ var x284 uint64
+ x283, x284 = bits.Add64(x255, x273, uint64(p384Uint1(x282)))
+ var x285 uint64
+ var x286 uint64
+ x285, x286 = bits.Add64(x257, uint64(p384Uint1(x274)), uint64(p384Uint1(x284)))
+ var x287 uint64
+ _, x287 = bits.Mul64(x275, 0x100000001)
+ var x289 uint64
+ var x290 uint64
+ x290, x289 = bits.Mul64(x287, 0xffffffffffffffff)
+ var x291 uint64
+ var x292 uint64
+ x292, x291 = bits.Mul64(x287, 0xffffffffffffffff)
+ var x293 uint64
+ var x294 uint64
+ x294, x293 = bits.Mul64(x287, 0xffffffffffffffff)
+ var x295 uint64
+ var x296 uint64
+ x296, x295 = bits.Mul64(x287, 0xfffffffffffffffe)
+ var x297 uint64
+ var x298 uint64
+ x298, x297 = bits.Mul64(x287, 0xffffffff00000000)
+ var x299 uint64
+ var x300 uint64
+ x300, x299 = bits.Mul64(x287, 0xffffffff)
+ var x301 uint64
+ var x302 uint64
+ x301, x302 = bits.Add64(x300, x297, uint64(0x0))
+ var x303 uint64
+ var x304 uint64
+ x303, x304 = bits.Add64(x298, x295, uint64(p384Uint1(x302)))
+ var x305 uint64
+ var x306 uint64
+ x305, x306 = bits.Add64(x296, x293, uint64(p384Uint1(x304)))
+ var x307 uint64
+ var x308 uint64
+ x307, x308 = bits.Add64(x294, x291, uint64(p384Uint1(x306)))
+ var x309 uint64
+ var x310 uint64
+ x309, x310 = bits.Add64(x292, x289, uint64(p384Uint1(x308)))
+ var x312 uint64
+ _, x312 = bits.Add64(x275, x299, uint64(0x0))
+ var x313 uint64
+ var x314 uint64
+ x313, x314 = bits.Add64(x277, x301, uint64(p384Uint1(x312)))
+ var x315 uint64
+ var x316 uint64
+ x315, x316 = bits.Add64(x279, x303, uint64(p384Uint1(x314)))
+ var x317 uint64
+ var x318 uint64
+ x317, x318 = bits.Add64(x281, x305, uint64(p384Uint1(x316)))
+ var x319 uint64
+ var x320 uint64
+ x319, x320 = bits.Add64(x283, x307, uint64(p384Uint1(x318)))
+ var x321 uint64
+ var x322 uint64
+ x321, x322 = bits.Add64(x285, x309, uint64(p384Uint1(x320)))
+ var x323 uint64
+ var x324 uint64
+ x323, x324 = bits.Add64((uint64(p384Uint1(x286)) + uint64(p384Uint1(x258))), (uint64(p384Uint1(x310)) + x290), uint64(p384Uint1(x322)))
+ var x325 uint64
+ var x326 uint64
+ x326, x325 = bits.Mul64(x5, 0x200000000)
+ var x327 uint64
+ var x328 uint64
+ x328, x327 = bits.Mul64(x5, 0xfffffffe00000000)
+ var x329 uint64
+ var x330 uint64
+ x330, x329 = bits.Mul64(x5, 0x200000000)
+ var x331 uint64
+ var x332 uint64
+ x332, x331 = bits.Mul64(x5, 0xfffffffe00000001)
+ var x333 uint64
+ var x334 uint64
+ x333, x334 = bits.Add64(x332, x329, uint64(0x0))
+ var x335 uint64
+ var x336 uint64
+ x335, x336 = bits.Add64(x330, x327, uint64(p384Uint1(x334)))
+ var x337 uint64
+ var x338 uint64
+ x337, x338 = bits.Add64(x328, x325, uint64(p384Uint1(x336)))
+ var x339 uint64
+ var x340 uint64
+ x339, x340 = bits.Add64(x326, x5, uint64(p384Uint1(x338)))
+ var x341 uint64
+ var x342 uint64
+ x341, x342 = bits.Add64(x313, x331, uint64(0x0))
+ var x343 uint64
+ var x344 uint64
+ x343, x344 = bits.Add64(x315, x333, uint64(p384Uint1(x342)))
+ var x345 uint64
+ var x346 uint64
+ x345, x346 = bits.Add64(x317, x335, uint64(p384Uint1(x344)))
+ var x347 uint64
+ var x348 uint64
+ x347, x348 = bits.Add64(x319, x337, uint64(p384Uint1(x346)))
+ var x349 uint64
+ var x350 uint64
+ x349, x350 = bits.Add64(x321, x339, uint64(p384Uint1(x348)))
+ var x351 uint64
+ var x352 uint64
+ x351, x352 = bits.Add64(x323, uint64(p384Uint1(x340)), uint64(p384Uint1(x350)))
+ var x353 uint64
+ _, x353 = bits.Mul64(x341, 0x100000001)
+ var x355 uint64
+ var x356 uint64
+ x356, x355 = bits.Mul64(x353, 0xffffffffffffffff)
+ var x357 uint64
+ var x358 uint64
+ x358, x357 = bits.Mul64(x353, 0xffffffffffffffff)
+ var x359 uint64
+ var x360 uint64
+ x360, x359 = bits.Mul64(x353, 0xffffffffffffffff)
+ var x361 uint64
+ var x362 uint64
+ x362, x361 = bits.Mul64(x353, 0xfffffffffffffffe)
+ var x363 uint64
+ var x364 uint64
+ x364, x363 = bits.Mul64(x353, 0xffffffff00000000)
+ var x365 uint64
+ var x366 uint64
+ x366, x365 = bits.Mul64(x353, 0xffffffff)
+ var x367 uint64
+ var x368 uint64
+ x367, x368 = bits.Add64(x366, x363, uint64(0x0))
+ var x369 uint64
+ var x370 uint64
+ x369, x370 = bits.Add64(x364, x361, uint64(p384Uint1(x368)))
+ var x371 uint64
+ var x372 uint64
+ x371, x372 = bits.Add64(x362, x359, uint64(p384Uint1(x370)))
+ var x373 uint64
+ var x374 uint64
+ x373, x374 = bits.Add64(x360, x357, uint64(p384Uint1(x372)))
+ var x375 uint64
+ var x376 uint64
+ x375, x376 = bits.Add64(x358, x355, uint64(p384Uint1(x374)))
+ var x378 uint64
+ _, x378 = bits.Add64(x341, x365, uint64(0x0))
+ var x379 uint64
+ var x380 uint64
+ x379, x380 = bits.Add64(x343, x367, uint64(p384Uint1(x378)))
+ var x381 uint64
+ var x382 uint64
+ x381, x382 = bits.Add64(x345, x369, uint64(p384Uint1(x380)))
+ var x383 uint64
+ var x384 uint64
+ x383, x384 = bits.Add64(x347, x371, uint64(p384Uint1(x382)))
+ var x385 uint64
+ var x386 uint64
+ x385, x386 = bits.Add64(x349, x373, uint64(p384Uint1(x384)))
+ var x387 uint64
+ var x388 uint64
+ x387, x388 = bits.Add64(x351, x375, uint64(p384Uint1(x386)))
+ var x389 uint64
+ var x390 uint64
+ x389, x390 = bits.Add64((uint64(p384Uint1(x352)) + uint64(p384Uint1(x324))), (uint64(p384Uint1(x376)) + x356), uint64(p384Uint1(x388)))
+ var x391 uint64
+ var x392 uint64
+ x391, x392 = bits.Sub64(x379, 0xffffffff, uint64(0x0))
+ var x393 uint64
+ var x394 uint64
+ x393, x394 = bits.Sub64(x381, 0xffffffff00000000, uint64(p384Uint1(x392)))
+ var x395 uint64
+ var x396 uint64
+ x395, x396 = bits.Sub64(x383, 0xfffffffffffffffe, uint64(p384Uint1(x394)))
+ var x397 uint64
+ var x398 uint64
+ x397, x398 = bits.Sub64(x385, 0xffffffffffffffff, uint64(p384Uint1(x396)))
+ var x399 uint64
+ var x400 uint64
+ x399, x400 = bits.Sub64(x387, 0xffffffffffffffff, uint64(p384Uint1(x398)))
+ var x401 uint64
+ var x402 uint64
+ x401, x402 = bits.Sub64(x389, 0xffffffffffffffff, uint64(p384Uint1(x400)))
+ var x404 uint64
+ _, x404 = bits.Sub64(uint64(p384Uint1(x390)), uint64(0x0), uint64(p384Uint1(x402)))
+ var x405 uint64
+ p384CmovznzU64(&x405, p384Uint1(x404), x391, x379)
+ var x406 uint64
+ p384CmovznzU64(&x406, p384Uint1(x404), x393, x381)
+ var x407 uint64
+ p384CmovznzU64(&x407, p384Uint1(x404), x395, x383)
+ var x408 uint64
+ p384CmovznzU64(&x408, p384Uint1(x404), x397, x385)
+ var x409 uint64
+ p384CmovznzU64(&x409, p384Uint1(x404), x399, x387)
+ var x410 uint64
+ p384CmovznzU64(&x410, p384Uint1(x404), x401, x389)
+ out1[0] = x405
+ out1[1] = x406
+ out1[2] = x407
+ out1[3] = x408
+ out1[4] = x409
+ out1[5] = x410
+}
+
+// p384Selectznz is a multi-limb conditional select.
+//
+// Postconditions:
+//
+// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3)
+//
+// Input Bounds:
+//
+// arg1: [0x0 ~> 0x1]
+// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+//
+// Output Bounds:
+//
+// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+func p384Selectznz(out1 *[6]uint64, arg1 p384Uint1, arg2 *[6]uint64, arg3 *[6]uint64) {
+ var x1 uint64
+ p384CmovznzU64(&x1, arg1, arg2[0], arg3[0])
+ var x2 uint64
+ p384CmovznzU64(&x2, arg1, arg2[1], arg3[1])
+ var x3 uint64
+ p384CmovznzU64(&x3, arg1, arg2[2], arg3[2])
+ var x4 uint64
+ p384CmovznzU64(&x4, arg1, arg2[3], arg3[3])
+ var x5 uint64
+ p384CmovznzU64(&x5, arg1, arg2[4], arg3[4])
+ var x6 uint64
+ p384CmovznzU64(&x6, arg1, arg2[5], arg3[5])
+ out1[0] = x1
+ out1[1] = x2
+ out1[2] = x3
+ out1[3] = x4
+ out1[4] = x5
+ out1[5] = x6
+}
+
+// p384ToBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..47]
+//
+// Input Bounds:
+//
+// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+//
+// Output Bounds:
+//
+// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]]
+func p384ToBytes(out1 *[48]uint8, arg1 *[6]uint64) {
+ x1 := arg1[5]
+ x2 := arg1[4]
+ x3 := arg1[3]
+ x4 := arg1[2]
+ x5 := arg1[1]
+ x6 := arg1[0]
+ x7 := (uint8(x6) & 0xff)
+ x8 := (x6 >> 8)
+ x9 := (uint8(x8) & 0xff)
+ x10 := (x8 >> 8)
+ x11 := (uint8(x10) & 0xff)
+ x12 := (x10 >> 8)
+ x13 := (uint8(x12) & 0xff)
+ x14 := (x12 >> 8)
+ x15 := (uint8(x14) & 0xff)
+ x16 := (x14 >> 8)
+ x17 := (uint8(x16) & 0xff)
+ x18 := (x16 >> 8)
+ x19 := (uint8(x18) & 0xff)
+ x20 := uint8((x18 >> 8))
+ x21 := (uint8(x5) & 0xff)
+ x22 := (x5 >> 8)
+ x23 := (uint8(x22) & 0xff)
+ x24 := (x22 >> 8)
+ x25 := (uint8(x24) & 0xff)
+ x26 := (x24 >> 8)
+ x27 := (uint8(x26) & 0xff)
+ x28 := (x26 >> 8)
+ x29 := (uint8(x28) & 0xff)
+ x30 := (x28 >> 8)
+ x31 := (uint8(x30) & 0xff)
+ x32 := (x30 >> 8)
+ x33 := (uint8(x32) & 0xff)
+ x34 := uint8((x32 >> 8))
+ x35 := (uint8(x4) & 0xff)
+ x36 := (x4 >> 8)
+ x37 := (uint8(x36) & 0xff)
+ x38 := (x36 >> 8)
+ x39 := (uint8(x38) & 0xff)
+ x40 := (x38 >> 8)
+ x41 := (uint8(x40) & 0xff)
+ x42 := (x40 >> 8)
+ x43 := (uint8(x42) & 0xff)
+ x44 := (x42 >> 8)
+ x45 := (uint8(x44) & 0xff)
+ x46 := (x44 >> 8)
+ x47 := (uint8(x46) & 0xff)
+ x48 := uint8((x46 >> 8))
+ x49 := (uint8(x3) & 0xff)
+ x50 := (x3 >> 8)
+ x51 := (uint8(x50) & 0xff)
+ x52 := (x50 >> 8)
+ x53 := (uint8(x52) & 0xff)
+ x54 := (x52 >> 8)
+ x55 := (uint8(x54) & 0xff)
+ x56 := (x54 >> 8)
+ x57 := (uint8(x56) & 0xff)
+ x58 := (x56 >> 8)
+ x59 := (uint8(x58) & 0xff)
+ x60 := (x58 >> 8)
+ x61 := (uint8(x60) & 0xff)
+ x62 := uint8((x60 >> 8))
+ x63 := (uint8(x2) & 0xff)
+ x64 := (x2 >> 8)
+ x65 := (uint8(x64) & 0xff)
+ x66 := (x64 >> 8)
+ x67 := (uint8(x66) & 0xff)
+ x68 := (x66 >> 8)
+ x69 := (uint8(x68) & 0xff)
+ x70 := (x68 >> 8)
+ x71 := (uint8(x70) & 0xff)
+ x72 := (x70 >> 8)
+ x73 := (uint8(x72) & 0xff)
+ x74 := (x72 >> 8)
+ x75 := (uint8(x74) & 0xff)
+ x76 := uint8((x74 >> 8))
+ x77 := (uint8(x1) & 0xff)
+ x78 := (x1 >> 8)
+ x79 := (uint8(x78) & 0xff)
+ x80 := (x78 >> 8)
+ x81 := (uint8(x80) & 0xff)
+ x82 := (x80 >> 8)
+ x83 := (uint8(x82) & 0xff)
+ x84 := (x82 >> 8)
+ x85 := (uint8(x84) & 0xff)
+ x86 := (x84 >> 8)
+ x87 := (uint8(x86) & 0xff)
+ x88 := (x86 >> 8)
+ x89 := (uint8(x88) & 0xff)
+ x90 := uint8((x88 >> 8))
+ out1[0] = x7
+ out1[1] = x9
+ out1[2] = x11
+ out1[3] = x13
+ out1[4] = x15
+ out1[5] = x17
+ out1[6] = x19
+ out1[7] = x20
+ out1[8] = x21
+ out1[9] = x23
+ out1[10] = x25
+ out1[11] = x27
+ out1[12] = x29
+ out1[13] = x31
+ out1[14] = x33
+ out1[15] = x34
+ out1[16] = x35
+ out1[17] = x37
+ out1[18] = x39
+ out1[19] = x41
+ out1[20] = x43
+ out1[21] = x45
+ out1[22] = x47
+ out1[23] = x48
+ out1[24] = x49
+ out1[25] = x51
+ out1[26] = x53
+ out1[27] = x55
+ out1[28] = x57
+ out1[29] = x59
+ out1[30] = x61
+ out1[31] = x62
+ out1[32] = x63
+ out1[33] = x65
+ out1[34] = x67
+ out1[35] = x69
+ out1[36] = x71
+ out1[37] = x73
+ out1[38] = x75
+ out1[39] = x76
+ out1[40] = x77
+ out1[41] = x79
+ out1[42] = x81
+ out1[43] = x83
+ out1[44] = x85
+ out1[45] = x87
+ out1[46] = x89
+ out1[47] = x90
+}
+
+// p384FromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order.
+//
+// Preconditions:
+//
+// 0 ≤ bytes_eval arg1 < m
+//
+// Postconditions:
+//
+// eval out1 mod m = bytes_eval arg1 mod m
+// 0 ≤ eval out1 < m
+//
+// Input Bounds:
+//
+// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff]]
+//
+// Output Bounds:
+//
+// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+func p384FromBytes(out1 *[6]uint64, arg1 *[48]uint8) {
+ x1 := (uint64(arg1[47]) << 56)
+ x2 := (uint64(arg1[46]) << 48)
+ x3 := (uint64(arg1[45]) << 40)
+ x4 := (uint64(arg1[44]) << 32)
+ x5 := (uint64(arg1[43]) << 24)
+ x6 := (uint64(arg1[42]) << 16)
+ x7 := (uint64(arg1[41]) << 8)
+ x8 := arg1[40]
+ x9 := (uint64(arg1[39]) << 56)
+ x10 := (uint64(arg1[38]) << 48)
+ x11 := (uint64(arg1[37]) << 40)
+ x12 := (uint64(arg1[36]) << 32)
+ x13 := (uint64(arg1[35]) << 24)
+ x14 := (uint64(arg1[34]) << 16)
+ x15 := (uint64(arg1[33]) << 8)
+ x16 := arg1[32]
+ x17 := (uint64(arg1[31]) << 56)
+ x18 := (uint64(arg1[30]) << 48)
+ x19 := (uint64(arg1[29]) << 40)
+ x20 := (uint64(arg1[28]) << 32)
+ x21 := (uint64(arg1[27]) << 24)
+ x22 := (uint64(arg1[26]) << 16)
+ x23 := (uint64(arg1[25]) << 8)
+ x24 := arg1[24]
+ x25 := (uint64(arg1[23]) << 56)
+ x26 := (uint64(arg1[22]) << 48)
+ x27 := (uint64(arg1[21]) << 40)
+ x28 := (uint64(arg1[20]) << 32)
+ x29 := (uint64(arg1[19]) << 24)
+ x30 := (uint64(arg1[18]) << 16)
+ x31 := (uint64(arg1[17]) << 8)
+ x32 := arg1[16]
+ x33 := (uint64(arg1[15]) << 56)
+ x34 := (uint64(arg1[14]) << 48)
+ x35 := (uint64(arg1[13]) << 40)
+ x36 := (uint64(arg1[12]) << 32)
+ x37 := (uint64(arg1[11]) << 24)
+ x38 := (uint64(arg1[10]) << 16)
+ x39 := (uint64(arg1[9]) << 8)
+ x40 := arg1[8]
+ x41 := (uint64(arg1[7]) << 56)
+ x42 := (uint64(arg1[6]) << 48)
+ x43 := (uint64(arg1[5]) << 40)
+ x44 := (uint64(arg1[4]) << 32)
+ x45 := (uint64(arg1[3]) << 24)
+ x46 := (uint64(arg1[2]) << 16)
+ x47 := (uint64(arg1[1]) << 8)
+ x48 := arg1[0]
+ x49 := (x47 + uint64(x48))
+ x50 := (x46 + x49)
+ x51 := (x45 + x50)
+ x52 := (x44 + x51)
+ x53 := (x43 + x52)
+ x54 := (x42 + x53)
+ x55 := (x41 + x54)
+ x56 := (x39 + uint64(x40))
+ x57 := (x38 + x56)
+ x58 := (x37 + x57)
+ x59 := (x36 + x58)
+ x60 := (x35 + x59)
+ x61 := (x34 + x60)
+ x62 := (x33 + x61)
+ x63 := (x31 + uint64(x32))
+ x64 := (x30 + x63)
+ x65 := (x29 + x64)
+ x66 := (x28 + x65)
+ x67 := (x27 + x66)
+ x68 := (x26 + x67)
+ x69 := (x25 + x68)
+ x70 := (x23 + uint64(x24))
+ x71 := (x22 + x70)
+ x72 := (x21 + x71)
+ x73 := (x20 + x72)
+ x74 := (x19 + x73)
+ x75 := (x18 + x74)
+ x76 := (x17 + x75)
+ x77 := (x15 + uint64(x16))
+ x78 := (x14 + x77)
+ x79 := (x13 + x78)
+ x80 := (x12 + x79)
+ x81 := (x11 + x80)
+ x82 := (x10 + x81)
+ x83 := (x9 + x82)
+ x84 := (x7 + uint64(x8))
+ x85 := (x6 + x84)
+ x86 := (x5 + x85)
+ x87 := (x4 + x86)
+ x88 := (x3 + x87)
+ x89 := (x2 + x88)
+ x90 := (x1 + x89)
+ out1[0] = x55
+ out1[1] = x62
+ out1[2] = x69
+ out1[3] = x76
+ out1[4] = x83
+ out1[5] = x90
+}
diff --git a/src/crypto/internal/nistec/fiat/p384_invert.go b/src/crypto/internal/nistec/fiat/p384_invert.go
new file mode 100644
index 0000000..31591ac
--- /dev/null
+++ b/src/crypto/internal/nistec/fiat/p384_invert.go
@@ -0,0 +1,102 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by addchain. DO NOT EDIT.
+
+package fiat
+
+// Invert sets e = 1/x, and returns e.
+//
+// If x == 0, Invert returns e = 0.
+func (e *P384Element) Invert(x *P384Element) *P384Element {
+ // Inversion is implemented as exponentiation with exponent p − 2.
+ // The sequence of 15 multiplications and 383 squarings is derived from the
+ // following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
+ //
+ // _10 = 2*1
+ // _11 = 1 + _10
+ // _110 = 2*_11
+ // _111 = 1 + _110
+ // _111000 = _111 << 3
+ // _111111 = _111 + _111000
+ // x12 = _111111 << 6 + _111111
+ // x24 = x12 << 12 + x12
+ // x30 = x24 << 6 + _111111
+ // x31 = 2*x30 + 1
+ // x32 = 2*x31 + 1
+ // x63 = x32 << 31 + x31
+ // x126 = x63 << 63 + x63
+ // x252 = x126 << 126 + x126
+ // x255 = x252 << 3 + _111
+ // i397 = ((x255 << 33 + x32) << 94 + x30) << 2
+ // return 1 + i397
+ //
+
+ var z = new(P384Element).Set(e)
+ var t0 = new(P384Element)
+ var t1 = new(P384Element)
+ var t2 = new(P384Element)
+ var t3 = new(P384Element)
+
+ z.Square(x)
+ z.Mul(x, z)
+ z.Square(z)
+ t1.Mul(x, z)
+ z.Square(t1)
+ for s := 1; s < 3; s++ {
+ z.Square(z)
+ }
+ z.Mul(t1, z)
+ t0.Square(z)
+ for s := 1; s < 6; s++ {
+ t0.Square(t0)
+ }
+ t0.Mul(z, t0)
+ t2.Square(t0)
+ for s := 1; s < 12; s++ {
+ t2.Square(t2)
+ }
+ t0.Mul(t0, t2)
+ for s := 0; s < 6; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ t0.Square(z)
+ t2.Mul(x, t0)
+ t0.Square(t2)
+ t0.Mul(x, t0)
+ t3.Square(t0)
+ for s := 1; s < 31; s++ {
+ t3.Square(t3)
+ }
+ t2.Mul(t2, t3)
+ t3.Square(t2)
+ for s := 1; s < 63; s++ {
+ t3.Square(t3)
+ }
+ t2.Mul(t2, t3)
+ t3.Square(t2)
+ for s := 1; s < 126; s++ {
+ t3.Square(t3)
+ }
+ t2.Mul(t2, t3)
+ for s := 0; s < 3; s++ {
+ t2.Square(t2)
+ }
+ t1.Mul(t1, t2)
+ for s := 0; s < 33; s++ {
+ t1.Square(t1)
+ }
+ t0.Mul(t0, t1)
+ for s := 0; s < 94; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ for s := 0; s < 2; s++ {
+ z.Square(z)
+ }
+ z.Mul(x, z)
+
+ return e.Set(z)
+}
diff --git a/src/crypto/internal/nistec/fiat/p521.go b/src/crypto/internal/nistec/fiat/p521.go
new file mode 100644
index 0000000..43ac7d0
--- /dev/null
+++ b/src/crypto/internal/nistec/fiat/p521.go
@@ -0,0 +1,134 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by generate.go. DO NOT EDIT.
+
+package fiat
+
+import (
+ "crypto/subtle"
+ "errors"
+)
+
+// P521Element is an integer modulo 2^521 - 1.
+//
+// The zero value is a valid zero element.
+type P521Element struct {
+ // Values are represented internally always in the Montgomery domain, and
+ // converted in Bytes and SetBytes.
+ x p521MontgomeryDomainFieldElement
+}
+
+const p521ElementLen = 66
+
+type p521UntypedFieldElement = [9]uint64
+
+// One sets e = 1, and returns e.
+func (e *P521Element) One() *P521Element {
+ p521SetOne(&e.x)
+ return e
+}
+
+// Equal returns 1 if e == t, and zero otherwise.
+func (e *P521Element) Equal(t *P521Element) int {
+ eBytes := e.Bytes()
+ tBytes := t.Bytes()
+ return subtle.ConstantTimeCompare(eBytes, tBytes)
+}
+
+// IsZero returns 1 if e == 0, and zero otherwise.
+func (e *P521Element) IsZero() int {
+ zero := make([]byte, p521ElementLen)
+ eBytes := e.Bytes()
+ return subtle.ConstantTimeCompare(eBytes, zero)
+}
+
+// Set sets e = t, and returns e.
+func (e *P521Element) Set(t *P521Element) *P521Element {
+ e.x = t.x
+ return e
+}
+
+// Bytes returns the 66-byte big-endian encoding of e.
+func (e *P521Element) Bytes() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [p521ElementLen]byte
+ return e.bytes(&out)
+}
+
+func (e *P521Element) bytes(out *[p521ElementLen]byte) []byte {
+ var tmp p521NonMontgomeryDomainFieldElement
+ p521FromMontgomery(&tmp, &e.x)
+ p521ToBytes(out, (*p521UntypedFieldElement)(&tmp))
+ p521InvertEndianness(out[:])
+ return out[:]
+}
+
+// SetBytes sets e = v, where v is a big-endian 66-byte encoding, and returns e.
+// If v is not 66 bytes or it encodes a value higher than 2^521 - 1,
+// SetBytes returns nil and an error, and e is unchanged.
+func (e *P521Element) SetBytes(v []byte) (*P521Element, error) {
+ if len(v) != p521ElementLen {
+ return nil, errors.New("invalid P521Element encoding")
+ }
+
+ // Check for non-canonical encodings (p + k, 2p + k, etc.) by comparing to
+ // the encoding of -1 mod p, so p - 1, the highest canonical encoding.
+ var minusOneEncoding = new(P521Element).Sub(
+ new(P521Element), new(P521Element).One()).Bytes()
+ for i := range v {
+ if v[i] < minusOneEncoding[i] {
+ break
+ }
+ if v[i] > minusOneEncoding[i] {
+ return nil, errors.New("invalid P521Element encoding")
+ }
+ }
+
+ var in [p521ElementLen]byte
+ copy(in[:], v)
+ p521InvertEndianness(in[:])
+ var tmp p521NonMontgomeryDomainFieldElement
+ p521FromBytes((*p521UntypedFieldElement)(&tmp), &in)
+ p521ToMontgomery(&e.x, &tmp)
+ return e, nil
+}
+
+// Add sets e = t1 + t2, and returns e.
+func (e *P521Element) Add(t1, t2 *P521Element) *P521Element {
+ p521Add(&e.x, &t1.x, &t2.x)
+ return e
+}
+
+// Sub sets e = t1 - t2, and returns e.
+func (e *P521Element) Sub(t1, t2 *P521Element) *P521Element {
+ p521Sub(&e.x, &t1.x, &t2.x)
+ return e
+}
+
+// Mul sets e = t1 * t2, and returns e.
+func (e *P521Element) Mul(t1, t2 *P521Element) *P521Element {
+ p521Mul(&e.x, &t1.x, &t2.x)
+ return e
+}
+
+// Square sets e = t * t, and returns e.
+func (e *P521Element) Square(t *P521Element) *P521Element {
+ p521Square(&e.x, &t.x)
+ return e
+}
+
+// Select sets v to a if cond == 1, and to b if cond == 0.
+func (v *P521Element) Select(a, b *P521Element, cond int) *P521Element {
+ p521Selectznz((*p521UntypedFieldElement)(&v.x), p521Uint1(cond),
+ (*p521UntypedFieldElement)(&b.x), (*p521UntypedFieldElement)(&a.x))
+ return v
+}
+
+func p521InvertEndianness(v []byte) {
+ for i := 0; i < len(v)/2; i++ {
+ v[i], v[len(v)-1-i] = v[len(v)-1-i], v[i]
+ }
+}
diff --git a/src/crypto/internal/nistec/fiat/p521_fiat64.go b/src/crypto/internal/nistec/fiat/p521_fiat64.go
new file mode 100644
index 0000000..87a359e
--- /dev/null
+++ b/src/crypto/internal/nistec/fiat/p521_fiat64.go
@@ -0,0 +1,5541 @@
+// Code generated by Fiat Cryptography. DO NOT EDIT.
+//
+// Autogenerated: word_by_word_montgomery --lang Go --no-wide-int --cmovznz-by-mul --relax-primitive-carry-to-bitwidth 32,64 --internal-static --public-function-case camelCase --public-type-case camelCase --private-function-case camelCase --private-type-case camelCase --doc-text-before-function-name '' --doc-newline-before-package-declaration --doc-prepend-header 'Code generated by Fiat Cryptography. DO NOT EDIT.' --package-name fiat --no-prefix-fiat p521 64 '2^521 - 1' mul square add sub one from_montgomery to_montgomery selectznz to_bytes from_bytes
+//
+// curve description: p521
+//
+// machine_wordsize = 64 (from "64")
+//
+// requested operations: mul, square, add, sub, one, from_montgomery, to_montgomery, selectznz, to_bytes, from_bytes
+//
+// m = 0x1ffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffffff (from "2^521 - 1")
+//
+//
+//
+// NOTE: In addition to the bounds specified above each function, all
+//
+// functions synthesized for this Montgomery arithmetic require the
+//
+// input to be strictly less than the prime modulus (m), and also
+//
+// require the input to be in the unique saturated representation.
+//
+// All functions also ensure that these two properties are true of
+//
+// return values.
+//
+//
+//
+// Computed values:
+//
+// eval z = z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) + (z[4] << 256) + (z[5] << 0x140) + (z[6] << 0x180) + (z[7] << 0x1c0) + (z[8] << 2^9)
+//
+// bytes_eval z = z[0] + (z[1] << 8) + (z[2] << 16) + (z[3] << 24) + (z[4] << 32) + (z[5] << 40) + (z[6] << 48) + (z[7] << 56) + (z[8] << 64) + (z[9] << 72) + (z[10] << 80) + (z[11] << 88) + (z[12] << 96) + (z[13] << 104) + (z[14] << 112) + (z[15] << 120) + (z[16] << 128) + (z[17] << 136) + (z[18] << 144) + (z[19] << 152) + (z[20] << 160) + (z[21] << 168) + (z[22] << 176) + (z[23] << 184) + (z[24] << 192) + (z[25] << 200) + (z[26] << 208) + (z[27] << 216) + (z[28] << 224) + (z[29] << 232) + (z[30] << 240) + (z[31] << 248) + (z[32] << 256) + (z[33] << 0x108) + (z[34] << 0x110) + (z[35] << 0x118) + (z[36] << 0x120) + (z[37] << 0x128) + (z[38] << 0x130) + (z[39] << 0x138) + (z[40] << 0x140) + (z[41] << 0x148) + (z[42] << 0x150) + (z[43] << 0x158) + (z[44] << 0x160) + (z[45] << 0x168) + (z[46] << 0x170) + (z[47] << 0x178) + (z[48] << 0x180) + (z[49] << 0x188) + (z[50] << 0x190) + (z[51] << 0x198) + (z[52] << 0x1a0) + (z[53] << 0x1a8) + (z[54] << 0x1b0) + (z[55] << 0x1b8) + (z[56] << 0x1c0) + (z[57] << 0x1c8) + (z[58] << 0x1d0) + (z[59] << 0x1d8) + (z[60] << 0x1e0) + (z[61] << 0x1e8) + (z[62] << 0x1f0) + (z[63] << 0x1f8) + (z[64] << 2^9) + (z[65] << 0x208)
+//
+// twos_complement_eval z = let x1 := z[0] + (z[1] << 64) + (z[2] << 128) + (z[3] << 192) + (z[4] << 256) + (z[5] << 0x140) + (z[6] << 0x180) + (z[7] << 0x1c0) + (z[8] << 2^9) in
+//
+// if x1 & (2^576-1) < 2^575 then x1 & (2^576-1) else (x1 & (2^576-1)) - 2^576
+
+package fiat
+
+import "math/bits"
+
+type p521Uint1 uint64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927
+type p521Int1 int64 // We use uint64 instead of a more narrow type for performance reasons; see https://github.com/mit-plv/fiat-crypto/pull/1006#issuecomment-892625927
+
+// The type p521MontgomeryDomainFieldElement is a field element in the Montgomery domain.
+//
+// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+type p521MontgomeryDomainFieldElement [9]uint64
+
+// The type p521NonMontgomeryDomainFieldElement is a field element NOT in the Montgomery domain.
+//
+// Bounds: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+type p521NonMontgomeryDomainFieldElement [9]uint64
+
+// p521CmovznzU64 is a single-word conditional move.
+//
+// Postconditions:
+//
+// out1 = (if arg1 = 0 then arg2 else arg3)
+//
+// Input Bounds:
+//
+// arg1: [0x0 ~> 0x1]
+// arg2: [0x0 ~> 0xffffffffffffffff]
+// arg3: [0x0 ~> 0xffffffffffffffff]
+//
+// Output Bounds:
+//
+// out1: [0x0 ~> 0xffffffffffffffff]
+func p521CmovznzU64(out1 *uint64, arg1 p521Uint1, arg2 uint64, arg3 uint64) {
+ x1 := (uint64(arg1) * 0xffffffffffffffff)
+ x2 := ((x1 & arg3) | ((^x1) & arg2))
+ *out1 = x2
+}
+
+// p521Mul multiplies two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func p521Mul(out1 *p521MontgomeryDomainFieldElement, arg1 *p521MontgomeryDomainFieldElement, arg2 *p521MontgomeryDomainFieldElement) {
+ x1 := arg1[1]
+ x2 := arg1[2]
+ x3 := arg1[3]
+ x4 := arg1[4]
+ x5 := arg1[5]
+ x6 := arg1[6]
+ x7 := arg1[7]
+ x8 := arg1[8]
+ x9 := arg1[0]
+ var x10 uint64
+ var x11 uint64
+ x11, x10 = bits.Mul64(x9, arg2[8])
+ var x12 uint64
+ var x13 uint64
+ x13, x12 = bits.Mul64(x9, arg2[7])
+ var x14 uint64
+ var x15 uint64
+ x15, x14 = bits.Mul64(x9, arg2[6])
+ var x16 uint64
+ var x17 uint64
+ x17, x16 = bits.Mul64(x9, arg2[5])
+ var x18 uint64
+ var x19 uint64
+ x19, x18 = bits.Mul64(x9, arg2[4])
+ var x20 uint64
+ var x21 uint64
+ x21, x20 = bits.Mul64(x9, arg2[3])
+ var x22 uint64
+ var x23 uint64
+ x23, x22 = bits.Mul64(x9, arg2[2])
+ var x24 uint64
+ var x25 uint64
+ x25, x24 = bits.Mul64(x9, arg2[1])
+ var x26 uint64
+ var x27 uint64
+ x27, x26 = bits.Mul64(x9, arg2[0])
+ var x28 uint64
+ var x29 uint64
+ x28, x29 = bits.Add64(x27, x24, uint64(0x0))
+ var x30 uint64
+ var x31 uint64
+ x30, x31 = bits.Add64(x25, x22, uint64(p521Uint1(x29)))
+ var x32 uint64
+ var x33 uint64
+ x32, x33 = bits.Add64(x23, x20, uint64(p521Uint1(x31)))
+ var x34 uint64
+ var x35 uint64
+ x34, x35 = bits.Add64(x21, x18, uint64(p521Uint1(x33)))
+ var x36 uint64
+ var x37 uint64
+ x36, x37 = bits.Add64(x19, x16, uint64(p521Uint1(x35)))
+ var x38 uint64
+ var x39 uint64
+ x38, x39 = bits.Add64(x17, x14, uint64(p521Uint1(x37)))
+ var x40 uint64
+ var x41 uint64
+ x40, x41 = bits.Add64(x15, x12, uint64(p521Uint1(x39)))
+ var x42 uint64
+ var x43 uint64
+ x42, x43 = bits.Add64(x13, x10, uint64(p521Uint1(x41)))
+ x44 := (uint64(p521Uint1(x43)) + x11)
+ var x45 uint64
+ var x46 uint64
+ x46, x45 = bits.Mul64(x26, 0x1ff)
+ var x47 uint64
+ var x48 uint64
+ x48, x47 = bits.Mul64(x26, 0xffffffffffffffff)
+ var x49 uint64
+ var x50 uint64
+ x50, x49 = bits.Mul64(x26, 0xffffffffffffffff)
+ var x51 uint64
+ var x52 uint64
+ x52, x51 = bits.Mul64(x26, 0xffffffffffffffff)
+ var x53 uint64
+ var x54 uint64
+ x54, x53 = bits.Mul64(x26, 0xffffffffffffffff)
+ var x55 uint64
+ var x56 uint64
+ x56, x55 = bits.Mul64(x26, 0xffffffffffffffff)
+ var x57 uint64
+ var x58 uint64
+ x58, x57 = bits.Mul64(x26, 0xffffffffffffffff)
+ var x59 uint64
+ var x60 uint64
+ x60, x59 = bits.Mul64(x26, 0xffffffffffffffff)
+ var x61 uint64
+ var x62 uint64
+ x62, x61 = bits.Mul64(x26, 0xffffffffffffffff)
+ var x63 uint64
+ var x64 uint64
+ x63, x64 = bits.Add64(x62, x59, uint64(0x0))
+ var x65 uint64
+ var x66 uint64
+ x65, x66 = bits.Add64(x60, x57, uint64(p521Uint1(x64)))
+ var x67 uint64
+ var x68 uint64
+ x67, x68 = bits.Add64(x58, x55, uint64(p521Uint1(x66)))
+ var x69 uint64
+ var x70 uint64
+ x69, x70 = bits.Add64(x56, x53, uint64(p521Uint1(x68)))
+ var x71 uint64
+ var x72 uint64
+ x71, x72 = bits.Add64(x54, x51, uint64(p521Uint1(x70)))
+ var x73 uint64
+ var x74 uint64
+ x73, x74 = bits.Add64(x52, x49, uint64(p521Uint1(x72)))
+ var x75 uint64
+ var x76 uint64
+ x75, x76 = bits.Add64(x50, x47, uint64(p521Uint1(x74)))
+ var x77 uint64
+ var x78 uint64
+ x77, x78 = bits.Add64(x48, x45, uint64(p521Uint1(x76)))
+ x79 := (uint64(p521Uint1(x78)) + x46)
+ var x81 uint64
+ _, x81 = bits.Add64(x26, x61, uint64(0x0))
+ var x82 uint64
+ var x83 uint64
+ x82, x83 = bits.Add64(x28, x63, uint64(p521Uint1(x81)))
+ var x84 uint64
+ var x85 uint64
+ x84, x85 = bits.Add64(x30, x65, uint64(p521Uint1(x83)))
+ var x86 uint64
+ var x87 uint64
+ x86, x87 = bits.Add64(x32, x67, uint64(p521Uint1(x85)))
+ var x88 uint64
+ var x89 uint64
+ x88, x89 = bits.Add64(x34, x69, uint64(p521Uint1(x87)))
+ var x90 uint64
+ var x91 uint64
+ x90, x91 = bits.Add64(x36, x71, uint64(p521Uint1(x89)))
+ var x92 uint64
+ var x93 uint64
+ x92, x93 = bits.Add64(x38, x73, uint64(p521Uint1(x91)))
+ var x94 uint64
+ var x95 uint64
+ x94, x95 = bits.Add64(x40, x75, uint64(p521Uint1(x93)))
+ var x96 uint64
+ var x97 uint64
+ x96, x97 = bits.Add64(x42, x77, uint64(p521Uint1(x95)))
+ var x98 uint64
+ var x99 uint64
+ x98, x99 = bits.Add64(x44, x79, uint64(p521Uint1(x97)))
+ var x100 uint64
+ var x101 uint64
+ x101, x100 = bits.Mul64(x1, arg2[8])
+ var x102 uint64
+ var x103 uint64
+ x103, x102 = bits.Mul64(x1, arg2[7])
+ var x104 uint64
+ var x105 uint64
+ x105, x104 = bits.Mul64(x1, arg2[6])
+ var x106 uint64
+ var x107 uint64
+ x107, x106 = bits.Mul64(x1, arg2[5])
+ var x108 uint64
+ var x109 uint64
+ x109, x108 = bits.Mul64(x1, arg2[4])
+ var x110 uint64
+ var x111 uint64
+ x111, x110 = bits.Mul64(x1, arg2[3])
+ var x112 uint64
+ var x113 uint64
+ x113, x112 = bits.Mul64(x1, arg2[2])
+ var x114 uint64
+ var x115 uint64
+ x115, x114 = bits.Mul64(x1, arg2[1])
+ var x116 uint64
+ var x117 uint64
+ x117, x116 = bits.Mul64(x1, arg2[0])
+ var x118 uint64
+ var x119 uint64
+ x118, x119 = bits.Add64(x117, x114, uint64(0x0))
+ var x120 uint64
+ var x121 uint64
+ x120, x121 = bits.Add64(x115, x112, uint64(p521Uint1(x119)))
+ var x122 uint64
+ var x123 uint64
+ x122, x123 = bits.Add64(x113, x110, uint64(p521Uint1(x121)))
+ var x124 uint64
+ var x125 uint64
+ x124, x125 = bits.Add64(x111, x108, uint64(p521Uint1(x123)))
+ var x126 uint64
+ var x127 uint64
+ x126, x127 = bits.Add64(x109, x106, uint64(p521Uint1(x125)))
+ var x128 uint64
+ var x129 uint64
+ x128, x129 = bits.Add64(x107, x104, uint64(p521Uint1(x127)))
+ var x130 uint64
+ var x131 uint64
+ x130, x131 = bits.Add64(x105, x102, uint64(p521Uint1(x129)))
+ var x132 uint64
+ var x133 uint64
+ x132, x133 = bits.Add64(x103, x100, uint64(p521Uint1(x131)))
+ x134 := (uint64(p521Uint1(x133)) + x101)
+ var x135 uint64
+ var x136 uint64
+ x135, x136 = bits.Add64(x82, x116, uint64(0x0))
+ var x137 uint64
+ var x138 uint64
+ x137, x138 = bits.Add64(x84, x118, uint64(p521Uint1(x136)))
+ var x139 uint64
+ var x140 uint64
+ x139, x140 = bits.Add64(x86, x120, uint64(p521Uint1(x138)))
+ var x141 uint64
+ var x142 uint64
+ x141, x142 = bits.Add64(x88, x122, uint64(p521Uint1(x140)))
+ var x143 uint64
+ var x144 uint64
+ x143, x144 = bits.Add64(x90, x124, uint64(p521Uint1(x142)))
+ var x145 uint64
+ var x146 uint64
+ x145, x146 = bits.Add64(x92, x126, uint64(p521Uint1(x144)))
+ var x147 uint64
+ var x148 uint64
+ x147, x148 = bits.Add64(x94, x128, uint64(p521Uint1(x146)))
+ var x149 uint64
+ var x150 uint64
+ x149, x150 = bits.Add64(x96, x130, uint64(p521Uint1(x148)))
+ var x151 uint64
+ var x152 uint64
+ x151, x152 = bits.Add64(x98, x132, uint64(p521Uint1(x150)))
+ var x153 uint64
+ var x154 uint64
+ x153, x154 = bits.Add64(uint64(p521Uint1(x99)), x134, uint64(p521Uint1(x152)))
+ var x155 uint64
+ var x156 uint64
+ x156, x155 = bits.Mul64(x135, 0x1ff)
+ var x157 uint64
+ var x158 uint64
+ x158, x157 = bits.Mul64(x135, 0xffffffffffffffff)
+ var x159 uint64
+ var x160 uint64
+ x160, x159 = bits.Mul64(x135, 0xffffffffffffffff)
+ var x161 uint64
+ var x162 uint64
+ x162, x161 = bits.Mul64(x135, 0xffffffffffffffff)
+ var x163 uint64
+ var x164 uint64
+ x164, x163 = bits.Mul64(x135, 0xffffffffffffffff)
+ var x165 uint64
+ var x166 uint64
+ x166, x165 = bits.Mul64(x135, 0xffffffffffffffff)
+ var x167 uint64
+ var x168 uint64
+ x168, x167 = bits.Mul64(x135, 0xffffffffffffffff)
+ var x169 uint64
+ var x170 uint64
+ x170, x169 = bits.Mul64(x135, 0xffffffffffffffff)
+ var x171 uint64
+ var x172 uint64
+ x172, x171 = bits.Mul64(x135, 0xffffffffffffffff)
+ var x173 uint64
+ var x174 uint64
+ x173, x174 = bits.Add64(x172, x169, uint64(0x0))
+ var x175 uint64
+ var x176 uint64
+ x175, x176 = bits.Add64(x170, x167, uint64(p521Uint1(x174)))
+ var x177 uint64
+ var x178 uint64
+ x177, x178 = bits.Add64(x168, x165, uint64(p521Uint1(x176)))
+ var x179 uint64
+ var x180 uint64
+ x179, x180 = bits.Add64(x166, x163, uint64(p521Uint1(x178)))
+ var x181 uint64
+ var x182 uint64
+ x181, x182 = bits.Add64(x164, x161, uint64(p521Uint1(x180)))
+ var x183 uint64
+ var x184 uint64
+ x183, x184 = bits.Add64(x162, x159, uint64(p521Uint1(x182)))
+ var x185 uint64
+ var x186 uint64
+ x185, x186 = bits.Add64(x160, x157, uint64(p521Uint1(x184)))
+ var x187 uint64
+ var x188 uint64
+ x187, x188 = bits.Add64(x158, x155, uint64(p521Uint1(x186)))
+ x189 := (uint64(p521Uint1(x188)) + x156)
+ var x191 uint64
+ _, x191 = bits.Add64(x135, x171, uint64(0x0))
+ var x192 uint64
+ var x193 uint64
+ x192, x193 = bits.Add64(x137, x173, uint64(p521Uint1(x191)))
+ var x194 uint64
+ var x195 uint64
+ x194, x195 = bits.Add64(x139, x175, uint64(p521Uint1(x193)))
+ var x196 uint64
+ var x197 uint64
+ x196, x197 = bits.Add64(x141, x177, uint64(p521Uint1(x195)))
+ var x198 uint64
+ var x199 uint64
+ x198, x199 = bits.Add64(x143, x179, uint64(p521Uint1(x197)))
+ var x200 uint64
+ var x201 uint64
+ x200, x201 = bits.Add64(x145, x181, uint64(p521Uint1(x199)))
+ var x202 uint64
+ var x203 uint64
+ x202, x203 = bits.Add64(x147, x183, uint64(p521Uint1(x201)))
+ var x204 uint64
+ var x205 uint64
+ x204, x205 = bits.Add64(x149, x185, uint64(p521Uint1(x203)))
+ var x206 uint64
+ var x207 uint64
+ x206, x207 = bits.Add64(x151, x187, uint64(p521Uint1(x205)))
+ var x208 uint64
+ var x209 uint64
+ x208, x209 = bits.Add64(x153, x189, uint64(p521Uint1(x207)))
+ x210 := (uint64(p521Uint1(x209)) + uint64(p521Uint1(x154)))
+ var x211 uint64
+ var x212 uint64
+ x212, x211 = bits.Mul64(x2, arg2[8])
+ var x213 uint64
+ var x214 uint64
+ x214, x213 = bits.Mul64(x2, arg2[7])
+ var x215 uint64
+ var x216 uint64
+ x216, x215 = bits.Mul64(x2, arg2[6])
+ var x217 uint64
+ var x218 uint64
+ x218, x217 = bits.Mul64(x2, arg2[5])
+ var x219 uint64
+ var x220 uint64
+ x220, x219 = bits.Mul64(x2, arg2[4])
+ var x221 uint64
+ var x222 uint64
+ x222, x221 = bits.Mul64(x2, arg2[3])
+ var x223 uint64
+ var x224 uint64
+ x224, x223 = bits.Mul64(x2, arg2[2])
+ var x225 uint64
+ var x226 uint64
+ x226, x225 = bits.Mul64(x2, arg2[1])
+ var x227 uint64
+ var x228 uint64
+ x228, x227 = bits.Mul64(x2, arg2[0])
+ var x229 uint64
+ var x230 uint64
+ x229, x230 = bits.Add64(x228, x225, uint64(0x0))
+ var x231 uint64
+ var x232 uint64
+ x231, x232 = bits.Add64(x226, x223, uint64(p521Uint1(x230)))
+ var x233 uint64
+ var x234 uint64
+ x233, x234 = bits.Add64(x224, x221, uint64(p521Uint1(x232)))
+ var x235 uint64
+ var x236 uint64
+ x235, x236 = bits.Add64(x222, x219, uint64(p521Uint1(x234)))
+ var x237 uint64
+ var x238 uint64
+ x237, x238 = bits.Add64(x220, x217, uint64(p521Uint1(x236)))
+ var x239 uint64
+ var x240 uint64
+ x239, x240 = bits.Add64(x218, x215, uint64(p521Uint1(x238)))
+ var x241 uint64
+ var x242 uint64
+ x241, x242 = bits.Add64(x216, x213, uint64(p521Uint1(x240)))
+ var x243 uint64
+ var x244 uint64
+ x243, x244 = bits.Add64(x214, x211, uint64(p521Uint1(x242)))
+ x245 := (uint64(p521Uint1(x244)) + x212)
+ var x246 uint64
+ var x247 uint64
+ x246, x247 = bits.Add64(x192, x227, uint64(0x0))
+ var x248 uint64
+ var x249 uint64
+ x248, x249 = bits.Add64(x194, x229, uint64(p521Uint1(x247)))
+ var x250 uint64
+ var x251 uint64
+ x250, x251 = bits.Add64(x196, x231, uint64(p521Uint1(x249)))
+ var x252 uint64
+ var x253 uint64
+ x252, x253 = bits.Add64(x198, x233, uint64(p521Uint1(x251)))
+ var x254 uint64
+ var x255 uint64
+ x254, x255 = bits.Add64(x200, x235, uint64(p521Uint1(x253)))
+ var x256 uint64
+ var x257 uint64
+ x256, x257 = bits.Add64(x202, x237, uint64(p521Uint1(x255)))
+ var x258 uint64
+ var x259 uint64
+ x258, x259 = bits.Add64(x204, x239, uint64(p521Uint1(x257)))
+ var x260 uint64
+ var x261 uint64
+ x260, x261 = bits.Add64(x206, x241, uint64(p521Uint1(x259)))
+ var x262 uint64
+ var x263 uint64
+ x262, x263 = bits.Add64(x208, x243, uint64(p521Uint1(x261)))
+ var x264 uint64
+ var x265 uint64
+ x264, x265 = bits.Add64(x210, x245, uint64(p521Uint1(x263)))
+ var x266 uint64
+ var x267 uint64
+ x267, x266 = bits.Mul64(x246, 0x1ff)
+ var x268 uint64
+ var x269 uint64
+ x269, x268 = bits.Mul64(x246, 0xffffffffffffffff)
+ var x270 uint64
+ var x271 uint64
+ x271, x270 = bits.Mul64(x246, 0xffffffffffffffff)
+ var x272 uint64
+ var x273 uint64
+ x273, x272 = bits.Mul64(x246, 0xffffffffffffffff)
+ var x274 uint64
+ var x275 uint64
+ x275, x274 = bits.Mul64(x246, 0xffffffffffffffff)
+ var x276 uint64
+ var x277 uint64
+ x277, x276 = bits.Mul64(x246, 0xffffffffffffffff)
+ var x278 uint64
+ var x279 uint64
+ x279, x278 = bits.Mul64(x246, 0xffffffffffffffff)
+ var x280 uint64
+ var x281 uint64
+ x281, x280 = bits.Mul64(x246, 0xffffffffffffffff)
+ var x282 uint64
+ var x283 uint64
+ x283, x282 = bits.Mul64(x246, 0xffffffffffffffff)
+ var x284 uint64
+ var x285 uint64
+ x284, x285 = bits.Add64(x283, x280, uint64(0x0))
+ var x286 uint64
+ var x287 uint64
+ x286, x287 = bits.Add64(x281, x278, uint64(p521Uint1(x285)))
+ var x288 uint64
+ var x289 uint64
+ x288, x289 = bits.Add64(x279, x276, uint64(p521Uint1(x287)))
+ var x290 uint64
+ var x291 uint64
+ x290, x291 = bits.Add64(x277, x274, uint64(p521Uint1(x289)))
+ var x292 uint64
+ var x293 uint64
+ x292, x293 = bits.Add64(x275, x272, uint64(p521Uint1(x291)))
+ var x294 uint64
+ var x295 uint64
+ x294, x295 = bits.Add64(x273, x270, uint64(p521Uint1(x293)))
+ var x296 uint64
+ var x297 uint64
+ x296, x297 = bits.Add64(x271, x268, uint64(p521Uint1(x295)))
+ var x298 uint64
+ var x299 uint64
+ x298, x299 = bits.Add64(x269, x266, uint64(p521Uint1(x297)))
+ x300 := (uint64(p521Uint1(x299)) + x267)
+ var x302 uint64
+ _, x302 = bits.Add64(x246, x282, uint64(0x0))
+ var x303 uint64
+ var x304 uint64
+ x303, x304 = bits.Add64(x248, x284, uint64(p521Uint1(x302)))
+ var x305 uint64
+ var x306 uint64
+ x305, x306 = bits.Add64(x250, x286, uint64(p521Uint1(x304)))
+ var x307 uint64
+ var x308 uint64
+ x307, x308 = bits.Add64(x252, x288, uint64(p521Uint1(x306)))
+ var x309 uint64
+ var x310 uint64
+ x309, x310 = bits.Add64(x254, x290, uint64(p521Uint1(x308)))
+ var x311 uint64
+ var x312 uint64
+ x311, x312 = bits.Add64(x256, x292, uint64(p521Uint1(x310)))
+ var x313 uint64
+ var x314 uint64
+ x313, x314 = bits.Add64(x258, x294, uint64(p521Uint1(x312)))
+ var x315 uint64
+ var x316 uint64
+ x315, x316 = bits.Add64(x260, x296, uint64(p521Uint1(x314)))
+ var x317 uint64
+ var x318 uint64
+ x317, x318 = bits.Add64(x262, x298, uint64(p521Uint1(x316)))
+ var x319 uint64
+ var x320 uint64
+ x319, x320 = bits.Add64(x264, x300, uint64(p521Uint1(x318)))
+ x321 := (uint64(p521Uint1(x320)) + uint64(p521Uint1(x265)))
+ var x322 uint64
+ var x323 uint64
+ x323, x322 = bits.Mul64(x3, arg2[8])
+ var x324 uint64
+ var x325 uint64
+ x325, x324 = bits.Mul64(x3, arg2[7])
+ var x326 uint64
+ var x327 uint64
+ x327, x326 = bits.Mul64(x3, arg2[6])
+ var x328 uint64
+ var x329 uint64
+ x329, x328 = bits.Mul64(x3, arg2[5])
+ var x330 uint64
+ var x331 uint64
+ x331, x330 = bits.Mul64(x3, arg2[4])
+ var x332 uint64
+ var x333 uint64
+ x333, x332 = bits.Mul64(x3, arg2[3])
+ var x334 uint64
+ var x335 uint64
+ x335, x334 = bits.Mul64(x3, arg2[2])
+ var x336 uint64
+ var x337 uint64
+ x337, x336 = bits.Mul64(x3, arg2[1])
+ var x338 uint64
+ var x339 uint64
+ x339, x338 = bits.Mul64(x3, arg2[0])
+ var x340 uint64
+ var x341 uint64
+ x340, x341 = bits.Add64(x339, x336, uint64(0x0))
+ var x342 uint64
+ var x343 uint64
+ x342, x343 = bits.Add64(x337, x334, uint64(p521Uint1(x341)))
+ var x344 uint64
+ var x345 uint64
+ x344, x345 = bits.Add64(x335, x332, uint64(p521Uint1(x343)))
+ var x346 uint64
+ var x347 uint64
+ x346, x347 = bits.Add64(x333, x330, uint64(p521Uint1(x345)))
+ var x348 uint64
+ var x349 uint64
+ x348, x349 = bits.Add64(x331, x328, uint64(p521Uint1(x347)))
+ var x350 uint64
+ var x351 uint64
+ x350, x351 = bits.Add64(x329, x326, uint64(p521Uint1(x349)))
+ var x352 uint64
+ var x353 uint64
+ x352, x353 = bits.Add64(x327, x324, uint64(p521Uint1(x351)))
+ var x354 uint64
+ var x355 uint64
+ x354, x355 = bits.Add64(x325, x322, uint64(p521Uint1(x353)))
+ x356 := (uint64(p521Uint1(x355)) + x323)
+ var x357 uint64
+ var x358 uint64
+ x357, x358 = bits.Add64(x303, x338, uint64(0x0))
+ var x359 uint64
+ var x360 uint64
+ x359, x360 = bits.Add64(x305, x340, uint64(p521Uint1(x358)))
+ var x361 uint64
+ var x362 uint64
+ x361, x362 = bits.Add64(x307, x342, uint64(p521Uint1(x360)))
+ var x363 uint64
+ var x364 uint64
+ x363, x364 = bits.Add64(x309, x344, uint64(p521Uint1(x362)))
+ var x365 uint64
+ var x366 uint64
+ x365, x366 = bits.Add64(x311, x346, uint64(p521Uint1(x364)))
+ var x367 uint64
+ var x368 uint64
+ x367, x368 = bits.Add64(x313, x348, uint64(p521Uint1(x366)))
+ var x369 uint64
+ var x370 uint64
+ x369, x370 = bits.Add64(x315, x350, uint64(p521Uint1(x368)))
+ var x371 uint64
+ var x372 uint64
+ x371, x372 = bits.Add64(x317, x352, uint64(p521Uint1(x370)))
+ var x373 uint64
+ var x374 uint64
+ x373, x374 = bits.Add64(x319, x354, uint64(p521Uint1(x372)))
+ var x375 uint64
+ var x376 uint64
+ x375, x376 = bits.Add64(x321, x356, uint64(p521Uint1(x374)))
+ var x377 uint64
+ var x378 uint64
+ x378, x377 = bits.Mul64(x357, 0x1ff)
+ var x379 uint64
+ var x380 uint64
+ x380, x379 = bits.Mul64(x357, 0xffffffffffffffff)
+ var x381 uint64
+ var x382 uint64
+ x382, x381 = bits.Mul64(x357, 0xffffffffffffffff)
+ var x383 uint64
+ var x384 uint64
+ x384, x383 = bits.Mul64(x357, 0xffffffffffffffff)
+ var x385 uint64
+ var x386 uint64
+ x386, x385 = bits.Mul64(x357, 0xffffffffffffffff)
+ var x387 uint64
+ var x388 uint64
+ x388, x387 = bits.Mul64(x357, 0xffffffffffffffff)
+ var x389 uint64
+ var x390 uint64
+ x390, x389 = bits.Mul64(x357, 0xffffffffffffffff)
+ var x391 uint64
+ var x392 uint64
+ x392, x391 = bits.Mul64(x357, 0xffffffffffffffff)
+ var x393 uint64
+ var x394 uint64
+ x394, x393 = bits.Mul64(x357, 0xffffffffffffffff)
+ var x395 uint64
+ var x396 uint64
+ x395, x396 = bits.Add64(x394, x391, uint64(0x0))
+ var x397 uint64
+ var x398 uint64
+ x397, x398 = bits.Add64(x392, x389, uint64(p521Uint1(x396)))
+ var x399 uint64
+ var x400 uint64
+ x399, x400 = bits.Add64(x390, x387, uint64(p521Uint1(x398)))
+ var x401 uint64
+ var x402 uint64
+ x401, x402 = bits.Add64(x388, x385, uint64(p521Uint1(x400)))
+ var x403 uint64
+ var x404 uint64
+ x403, x404 = bits.Add64(x386, x383, uint64(p521Uint1(x402)))
+ var x405 uint64
+ var x406 uint64
+ x405, x406 = bits.Add64(x384, x381, uint64(p521Uint1(x404)))
+ var x407 uint64
+ var x408 uint64
+ x407, x408 = bits.Add64(x382, x379, uint64(p521Uint1(x406)))
+ var x409 uint64
+ var x410 uint64
+ x409, x410 = bits.Add64(x380, x377, uint64(p521Uint1(x408)))
+ x411 := (uint64(p521Uint1(x410)) + x378)
+ var x413 uint64
+ _, x413 = bits.Add64(x357, x393, uint64(0x0))
+ var x414 uint64
+ var x415 uint64
+ x414, x415 = bits.Add64(x359, x395, uint64(p521Uint1(x413)))
+ var x416 uint64
+ var x417 uint64
+ x416, x417 = bits.Add64(x361, x397, uint64(p521Uint1(x415)))
+ var x418 uint64
+ var x419 uint64
+ x418, x419 = bits.Add64(x363, x399, uint64(p521Uint1(x417)))
+ var x420 uint64
+ var x421 uint64
+ x420, x421 = bits.Add64(x365, x401, uint64(p521Uint1(x419)))
+ var x422 uint64
+ var x423 uint64
+ x422, x423 = bits.Add64(x367, x403, uint64(p521Uint1(x421)))
+ var x424 uint64
+ var x425 uint64
+ x424, x425 = bits.Add64(x369, x405, uint64(p521Uint1(x423)))
+ var x426 uint64
+ var x427 uint64
+ x426, x427 = bits.Add64(x371, x407, uint64(p521Uint1(x425)))
+ var x428 uint64
+ var x429 uint64
+ x428, x429 = bits.Add64(x373, x409, uint64(p521Uint1(x427)))
+ var x430 uint64
+ var x431 uint64
+ x430, x431 = bits.Add64(x375, x411, uint64(p521Uint1(x429)))
+ x432 := (uint64(p521Uint1(x431)) + uint64(p521Uint1(x376)))
+ var x433 uint64
+ var x434 uint64
+ x434, x433 = bits.Mul64(x4, arg2[8])
+ var x435 uint64
+ var x436 uint64
+ x436, x435 = bits.Mul64(x4, arg2[7])
+ var x437 uint64
+ var x438 uint64
+ x438, x437 = bits.Mul64(x4, arg2[6])
+ var x439 uint64
+ var x440 uint64
+ x440, x439 = bits.Mul64(x4, arg2[5])
+ var x441 uint64
+ var x442 uint64
+ x442, x441 = bits.Mul64(x4, arg2[4])
+ var x443 uint64
+ var x444 uint64
+ x444, x443 = bits.Mul64(x4, arg2[3])
+ var x445 uint64
+ var x446 uint64
+ x446, x445 = bits.Mul64(x4, arg2[2])
+ var x447 uint64
+ var x448 uint64
+ x448, x447 = bits.Mul64(x4, arg2[1])
+ var x449 uint64
+ var x450 uint64
+ x450, x449 = bits.Mul64(x4, arg2[0])
+ var x451 uint64
+ var x452 uint64
+ x451, x452 = bits.Add64(x450, x447, uint64(0x0))
+ var x453 uint64
+ var x454 uint64
+ x453, x454 = bits.Add64(x448, x445, uint64(p521Uint1(x452)))
+ var x455 uint64
+ var x456 uint64
+ x455, x456 = bits.Add64(x446, x443, uint64(p521Uint1(x454)))
+ var x457 uint64
+ var x458 uint64
+ x457, x458 = bits.Add64(x444, x441, uint64(p521Uint1(x456)))
+ var x459 uint64
+ var x460 uint64
+ x459, x460 = bits.Add64(x442, x439, uint64(p521Uint1(x458)))
+ var x461 uint64
+ var x462 uint64
+ x461, x462 = bits.Add64(x440, x437, uint64(p521Uint1(x460)))
+ var x463 uint64
+ var x464 uint64
+ x463, x464 = bits.Add64(x438, x435, uint64(p521Uint1(x462)))
+ var x465 uint64
+ var x466 uint64
+ x465, x466 = bits.Add64(x436, x433, uint64(p521Uint1(x464)))
+ x467 := (uint64(p521Uint1(x466)) + x434)
+ var x468 uint64
+ var x469 uint64
+ x468, x469 = bits.Add64(x414, x449, uint64(0x0))
+ var x470 uint64
+ var x471 uint64
+ x470, x471 = bits.Add64(x416, x451, uint64(p521Uint1(x469)))
+ var x472 uint64
+ var x473 uint64
+ x472, x473 = bits.Add64(x418, x453, uint64(p521Uint1(x471)))
+ var x474 uint64
+ var x475 uint64
+ x474, x475 = bits.Add64(x420, x455, uint64(p521Uint1(x473)))
+ var x476 uint64
+ var x477 uint64
+ x476, x477 = bits.Add64(x422, x457, uint64(p521Uint1(x475)))
+ var x478 uint64
+ var x479 uint64
+ x478, x479 = bits.Add64(x424, x459, uint64(p521Uint1(x477)))
+ var x480 uint64
+ var x481 uint64
+ x480, x481 = bits.Add64(x426, x461, uint64(p521Uint1(x479)))
+ var x482 uint64
+ var x483 uint64
+ x482, x483 = bits.Add64(x428, x463, uint64(p521Uint1(x481)))
+ var x484 uint64
+ var x485 uint64
+ x484, x485 = bits.Add64(x430, x465, uint64(p521Uint1(x483)))
+ var x486 uint64
+ var x487 uint64
+ x486, x487 = bits.Add64(x432, x467, uint64(p521Uint1(x485)))
+ var x488 uint64
+ var x489 uint64
+ x489, x488 = bits.Mul64(x468, 0x1ff)
+ var x490 uint64
+ var x491 uint64
+ x491, x490 = bits.Mul64(x468, 0xffffffffffffffff)
+ var x492 uint64
+ var x493 uint64
+ x493, x492 = bits.Mul64(x468, 0xffffffffffffffff)
+ var x494 uint64
+ var x495 uint64
+ x495, x494 = bits.Mul64(x468, 0xffffffffffffffff)
+ var x496 uint64
+ var x497 uint64
+ x497, x496 = bits.Mul64(x468, 0xffffffffffffffff)
+ var x498 uint64
+ var x499 uint64
+ x499, x498 = bits.Mul64(x468, 0xffffffffffffffff)
+ var x500 uint64
+ var x501 uint64
+ x501, x500 = bits.Mul64(x468, 0xffffffffffffffff)
+ var x502 uint64
+ var x503 uint64
+ x503, x502 = bits.Mul64(x468, 0xffffffffffffffff)
+ var x504 uint64
+ var x505 uint64
+ x505, x504 = bits.Mul64(x468, 0xffffffffffffffff)
+ var x506 uint64
+ var x507 uint64
+ x506, x507 = bits.Add64(x505, x502, uint64(0x0))
+ var x508 uint64
+ var x509 uint64
+ x508, x509 = bits.Add64(x503, x500, uint64(p521Uint1(x507)))
+ var x510 uint64
+ var x511 uint64
+ x510, x511 = bits.Add64(x501, x498, uint64(p521Uint1(x509)))
+ var x512 uint64
+ var x513 uint64
+ x512, x513 = bits.Add64(x499, x496, uint64(p521Uint1(x511)))
+ var x514 uint64
+ var x515 uint64
+ x514, x515 = bits.Add64(x497, x494, uint64(p521Uint1(x513)))
+ var x516 uint64
+ var x517 uint64
+ x516, x517 = bits.Add64(x495, x492, uint64(p521Uint1(x515)))
+ var x518 uint64
+ var x519 uint64
+ x518, x519 = bits.Add64(x493, x490, uint64(p521Uint1(x517)))
+ var x520 uint64
+ var x521 uint64
+ x520, x521 = bits.Add64(x491, x488, uint64(p521Uint1(x519)))
+ x522 := (uint64(p521Uint1(x521)) + x489)
+ var x524 uint64
+ _, x524 = bits.Add64(x468, x504, uint64(0x0))
+ var x525 uint64
+ var x526 uint64
+ x525, x526 = bits.Add64(x470, x506, uint64(p521Uint1(x524)))
+ var x527 uint64
+ var x528 uint64
+ x527, x528 = bits.Add64(x472, x508, uint64(p521Uint1(x526)))
+ var x529 uint64
+ var x530 uint64
+ x529, x530 = bits.Add64(x474, x510, uint64(p521Uint1(x528)))
+ var x531 uint64
+ var x532 uint64
+ x531, x532 = bits.Add64(x476, x512, uint64(p521Uint1(x530)))
+ var x533 uint64
+ var x534 uint64
+ x533, x534 = bits.Add64(x478, x514, uint64(p521Uint1(x532)))
+ var x535 uint64
+ var x536 uint64
+ x535, x536 = bits.Add64(x480, x516, uint64(p521Uint1(x534)))
+ var x537 uint64
+ var x538 uint64
+ x537, x538 = bits.Add64(x482, x518, uint64(p521Uint1(x536)))
+ var x539 uint64
+ var x540 uint64
+ x539, x540 = bits.Add64(x484, x520, uint64(p521Uint1(x538)))
+ var x541 uint64
+ var x542 uint64
+ x541, x542 = bits.Add64(x486, x522, uint64(p521Uint1(x540)))
+ x543 := (uint64(p521Uint1(x542)) + uint64(p521Uint1(x487)))
+ var x544 uint64
+ var x545 uint64
+ x545, x544 = bits.Mul64(x5, arg2[8])
+ var x546 uint64
+ var x547 uint64
+ x547, x546 = bits.Mul64(x5, arg2[7])
+ var x548 uint64
+ var x549 uint64
+ x549, x548 = bits.Mul64(x5, arg2[6])
+ var x550 uint64
+ var x551 uint64
+ x551, x550 = bits.Mul64(x5, arg2[5])
+ var x552 uint64
+ var x553 uint64
+ x553, x552 = bits.Mul64(x5, arg2[4])
+ var x554 uint64
+ var x555 uint64
+ x555, x554 = bits.Mul64(x5, arg2[3])
+ var x556 uint64
+ var x557 uint64
+ x557, x556 = bits.Mul64(x5, arg2[2])
+ var x558 uint64
+ var x559 uint64
+ x559, x558 = bits.Mul64(x5, arg2[1])
+ var x560 uint64
+ var x561 uint64
+ x561, x560 = bits.Mul64(x5, arg2[0])
+ var x562 uint64
+ var x563 uint64
+ x562, x563 = bits.Add64(x561, x558, uint64(0x0))
+ var x564 uint64
+ var x565 uint64
+ x564, x565 = bits.Add64(x559, x556, uint64(p521Uint1(x563)))
+ var x566 uint64
+ var x567 uint64
+ x566, x567 = bits.Add64(x557, x554, uint64(p521Uint1(x565)))
+ var x568 uint64
+ var x569 uint64
+ x568, x569 = bits.Add64(x555, x552, uint64(p521Uint1(x567)))
+ var x570 uint64
+ var x571 uint64
+ x570, x571 = bits.Add64(x553, x550, uint64(p521Uint1(x569)))
+ var x572 uint64
+ var x573 uint64
+ x572, x573 = bits.Add64(x551, x548, uint64(p521Uint1(x571)))
+ var x574 uint64
+ var x575 uint64
+ x574, x575 = bits.Add64(x549, x546, uint64(p521Uint1(x573)))
+ var x576 uint64
+ var x577 uint64
+ x576, x577 = bits.Add64(x547, x544, uint64(p521Uint1(x575)))
+ x578 := (uint64(p521Uint1(x577)) + x545)
+ var x579 uint64
+ var x580 uint64
+ x579, x580 = bits.Add64(x525, x560, uint64(0x0))
+ var x581 uint64
+ var x582 uint64
+ x581, x582 = bits.Add64(x527, x562, uint64(p521Uint1(x580)))
+ var x583 uint64
+ var x584 uint64
+ x583, x584 = bits.Add64(x529, x564, uint64(p521Uint1(x582)))
+ var x585 uint64
+ var x586 uint64
+ x585, x586 = bits.Add64(x531, x566, uint64(p521Uint1(x584)))
+ var x587 uint64
+ var x588 uint64
+ x587, x588 = bits.Add64(x533, x568, uint64(p521Uint1(x586)))
+ var x589 uint64
+ var x590 uint64
+ x589, x590 = bits.Add64(x535, x570, uint64(p521Uint1(x588)))
+ var x591 uint64
+ var x592 uint64
+ x591, x592 = bits.Add64(x537, x572, uint64(p521Uint1(x590)))
+ var x593 uint64
+ var x594 uint64
+ x593, x594 = bits.Add64(x539, x574, uint64(p521Uint1(x592)))
+ var x595 uint64
+ var x596 uint64
+ x595, x596 = bits.Add64(x541, x576, uint64(p521Uint1(x594)))
+ var x597 uint64
+ var x598 uint64
+ x597, x598 = bits.Add64(x543, x578, uint64(p521Uint1(x596)))
+ var x599 uint64
+ var x600 uint64
+ x600, x599 = bits.Mul64(x579, 0x1ff)
+ var x601 uint64
+ var x602 uint64
+ x602, x601 = bits.Mul64(x579, 0xffffffffffffffff)
+ var x603 uint64
+ var x604 uint64
+ x604, x603 = bits.Mul64(x579, 0xffffffffffffffff)
+ var x605 uint64
+ var x606 uint64
+ x606, x605 = bits.Mul64(x579, 0xffffffffffffffff)
+ var x607 uint64
+ var x608 uint64
+ x608, x607 = bits.Mul64(x579, 0xffffffffffffffff)
+ var x609 uint64
+ var x610 uint64
+ x610, x609 = bits.Mul64(x579, 0xffffffffffffffff)
+ var x611 uint64
+ var x612 uint64
+ x612, x611 = bits.Mul64(x579, 0xffffffffffffffff)
+ var x613 uint64
+ var x614 uint64
+ x614, x613 = bits.Mul64(x579, 0xffffffffffffffff)
+ var x615 uint64
+ var x616 uint64
+ x616, x615 = bits.Mul64(x579, 0xffffffffffffffff)
+ var x617 uint64
+ var x618 uint64
+ x617, x618 = bits.Add64(x616, x613, uint64(0x0))
+ var x619 uint64
+ var x620 uint64
+ x619, x620 = bits.Add64(x614, x611, uint64(p521Uint1(x618)))
+ var x621 uint64
+ var x622 uint64
+ x621, x622 = bits.Add64(x612, x609, uint64(p521Uint1(x620)))
+ var x623 uint64
+ var x624 uint64
+ x623, x624 = bits.Add64(x610, x607, uint64(p521Uint1(x622)))
+ var x625 uint64
+ var x626 uint64
+ x625, x626 = bits.Add64(x608, x605, uint64(p521Uint1(x624)))
+ var x627 uint64
+ var x628 uint64
+ x627, x628 = bits.Add64(x606, x603, uint64(p521Uint1(x626)))
+ var x629 uint64
+ var x630 uint64
+ x629, x630 = bits.Add64(x604, x601, uint64(p521Uint1(x628)))
+ var x631 uint64
+ var x632 uint64
+ x631, x632 = bits.Add64(x602, x599, uint64(p521Uint1(x630)))
+ x633 := (uint64(p521Uint1(x632)) + x600)
+ var x635 uint64
+ _, x635 = bits.Add64(x579, x615, uint64(0x0))
+ var x636 uint64
+ var x637 uint64
+ x636, x637 = bits.Add64(x581, x617, uint64(p521Uint1(x635)))
+ var x638 uint64
+ var x639 uint64
+ x638, x639 = bits.Add64(x583, x619, uint64(p521Uint1(x637)))
+ var x640 uint64
+ var x641 uint64
+ x640, x641 = bits.Add64(x585, x621, uint64(p521Uint1(x639)))
+ var x642 uint64
+ var x643 uint64
+ x642, x643 = bits.Add64(x587, x623, uint64(p521Uint1(x641)))
+ var x644 uint64
+ var x645 uint64
+ x644, x645 = bits.Add64(x589, x625, uint64(p521Uint1(x643)))
+ var x646 uint64
+ var x647 uint64
+ x646, x647 = bits.Add64(x591, x627, uint64(p521Uint1(x645)))
+ var x648 uint64
+ var x649 uint64
+ x648, x649 = bits.Add64(x593, x629, uint64(p521Uint1(x647)))
+ var x650 uint64
+ var x651 uint64
+ x650, x651 = bits.Add64(x595, x631, uint64(p521Uint1(x649)))
+ var x652 uint64
+ var x653 uint64
+ x652, x653 = bits.Add64(x597, x633, uint64(p521Uint1(x651)))
+ x654 := (uint64(p521Uint1(x653)) + uint64(p521Uint1(x598)))
+ var x655 uint64
+ var x656 uint64
+ x656, x655 = bits.Mul64(x6, arg2[8])
+ var x657 uint64
+ var x658 uint64
+ x658, x657 = bits.Mul64(x6, arg2[7])
+ var x659 uint64
+ var x660 uint64
+ x660, x659 = bits.Mul64(x6, arg2[6])
+ var x661 uint64
+ var x662 uint64
+ x662, x661 = bits.Mul64(x6, arg2[5])
+ var x663 uint64
+ var x664 uint64
+ x664, x663 = bits.Mul64(x6, arg2[4])
+ var x665 uint64
+ var x666 uint64
+ x666, x665 = bits.Mul64(x6, arg2[3])
+ var x667 uint64
+ var x668 uint64
+ x668, x667 = bits.Mul64(x6, arg2[2])
+ var x669 uint64
+ var x670 uint64
+ x670, x669 = bits.Mul64(x6, arg2[1])
+ var x671 uint64
+ var x672 uint64
+ x672, x671 = bits.Mul64(x6, arg2[0])
+ var x673 uint64
+ var x674 uint64
+ x673, x674 = bits.Add64(x672, x669, uint64(0x0))
+ var x675 uint64
+ var x676 uint64
+ x675, x676 = bits.Add64(x670, x667, uint64(p521Uint1(x674)))
+ var x677 uint64
+ var x678 uint64
+ x677, x678 = bits.Add64(x668, x665, uint64(p521Uint1(x676)))
+ var x679 uint64
+ var x680 uint64
+ x679, x680 = bits.Add64(x666, x663, uint64(p521Uint1(x678)))
+ var x681 uint64
+ var x682 uint64
+ x681, x682 = bits.Add64(x664, x661, uint64(p521Uint1(x680)))
+ var x683 uint64
+ var x684 uint64
+ x683, x684 = bits.Add64(x662, x659, uint64(p521Uint1(x682)))
+ var x685 uint64
+ var x686 uint64
+ x685, x686 = bits.Add64(x660, x657, uint64(p521Uint1(x684)))
+ var x687 uint64
+ var x688 uint64
+ x687, x688 = bits.Add64(x658, x655, uint64(p521Uint1(x686)))
+ x689 := (uint64(p521Uint1(x688)) + x656)
+ var x690 uint64
+ var x691 uint64
+ x690, x691 = bits.Add64(x636, x671, uint64(0x0))
+ var x692 uint64
+ var x693 uint64
+ x692, x693 = bits.Add64(x638, x673, uint64(p521Uint1(x691)))
+ var x694 uint64
+ var x695 uint64
+ x694, x695 = bits.Add64(x640, x675, uint64(p521Uint1(x693)))
+ var x696 uint64
+ var x697 uint64
+ x696, x697 = bits.Add64(x642, x677, uint64(p521Uint1(x695)))
+ var x698 uint64
+ var x699 uint64
+ x698, x699 = bits.Add64(x644, x679, uint64(p521Uint1(x697)))
+ var x700 uint64
+ var x701 uint64
+ x700, x701 = bits.Add64(x646, x681, uint64(p521Uint1(x699)))
+ var x702 uint64
+ var x703 uint64
+ x702, x703 = bits.Add64(x648, x683, uint64(p521Uint1(x701)))
+ var x704 uint64
+ var x705 uint64
+ x704, x705 = bits.Add64(x650, x685, uint64(p521Uint1(x703)))
+ var x706 uint64
+ var x707 uint64
+ x706, x707 = bits.Add64(x652, x687, uint64(p521Uint1(x705)))
+ var x708 uint64
+ var x709 uint64
+ x708, x709 = bits.Add64(x654, x689, uint64(p521Uint1(x707)))
+ var x710 uint64
+ var x711 uint64
+ x711, x710 = bits.Mul64(x690, 0x1ff)
+ var x712 uint64
+ var x713 uint64
+ x713, x712 = bits.Mul64(x690, 0xffffffffffffffff)
+ var x714 uint64
+ var x715 uint64
+ x715, x714 = bits.Mul64(x690, 0xffffffffffffffff)
+ var x716 uint64
+ var x717 uint64
+ x717, x716 = bits.Mul64(x690, 0xffffffffffffffff)
+ var x718 uint64
+ var x719 uint64
+ x719, x718 = bits.Mul64(x690, 0xffffffffffffffff)
+ var x720 uint64
+ var x721 uint64
+ x721, x720 = bits.Mul64(x690, 0xffffffffffffffff)
+ var x722 uint64
+ var x723 uint64
+ x723, x722 = bits.Mul64(x690, 0xffffffffffffffff)
+ var x724 uint64
+ var x725 uint64
+ x725, x724 = bits.Mul64(x690, 0xffffffffffffffff)
+ var x726 uint64
+ var x727 uint64
+ x727, x726 = bits.Mul64(x690, 0xffffffffffffffff)
+ var x728 uint64
+ var x729 uint64
+ x728, x729 = bits.Add64(x727, x724, uint64(0x0))
+ var x730 uint64
+ var x731 uint64
+ x730, x731 = bits.Add64(x725, x722, uint64(p521Uint1(x729)))
+ var x732 uint64
+ var x733 uint64
+ x732, x733 = bits.Add64(x723, x720, uint64(p521Uint1(x731)))
+ var x734 uint64
+ var x735 uint64
+ x734, x735 = bits.Add64(x721, x718, uint64(p521Uint1(x733)))
+ var x736 uint64
+ var x737 uint64
+ x736, x737 = bits.Add64(x719, x716, uint64(p521Uint1(x735)))
+ var x738 uint64
+ var x739 uint64
+ x738, x739 = bits.Add64(x717, x714, uint64(p521Uint1(x737)))
+ var x740 uint64
+ var x741 uint64
+ x740, x741 = bits.Add64(x715, x712, uint64(p521Uint1(x739)))
+ var x742 uint64
+ var x743 uint64
+ x742, x743 = bits.Add64(x713, x710, uint64(p521Uint1(x741)))
+ x744 := (uint64(p521Uint1(x743)) + x711)
+ var x746 uint64
+ _, x746 = bits.Add64(x690, x726, uint64(0x0))
+ var x747 uint64
+ var x748 uint64
+ x747, x748 = bits.Add64(x692, x728, uint64(p521Uint1(x746)))
+ var x749 uint64
+ var x750 uint64
+ x749, x750 = bits.Add64(x694, x730, uint64(p521Uint1(x748)))
+ var x751 uint64
+ var x752 uint64
+ x751, x752 = bits.Add64(x696, x732, uint64(p521Uint1(x750)))
+ var x753 uint64
+ var x754 uint64
+ x753, x754 = bits.Add64(x698, x734, uint64(p521Uint1(x752)))
+ var x755 uint64
+ var x756 uint64
+ x755, x756 = bits.Add64(x700, x736, uint64(p521Uint1(x754)))
+ var x757 uint64
+ var x758 uint64
+ x757, x758 = bits.Add64(x702, x738, uint64(p521Uint1(x756)))
+ var x759 uint64
+ var x760 uint64
+ x759, x760 = bits.Add64(x704, x740, uint64(p521Uint1(x758)))
+ var x761 uint64
+ var x762 uint64
+ x761, x762 = bits.Add64(x706, x742, uint64(p521Uint1(x760)))
+ var x763 uint64
+ var x764 uint64
+ x763, x764 = bits.Add64(x708, x744, uint64(p521Uint1(x762)))
+ x765 := (uint64(p521Uint1(x764)) + uint64(p521Uint1(x709)))
+ var x766 uint64
+ var x767 uint64
+ x767, x766 = bits.Mul64(x7, arg2[8])
+ var x768 uint64
+ var x769 uint64
+ x769, x768 = bits.Mul64(x7, arg2[7])
+ var x770 uint64
+ var x771 uint64
+ x771, x770 = bits.Mul64(x7, arg2[6])
+ var x772 uint64
+ var x773 uint64
+ x773, x772 = bits.Mul64(x7, arg2[5])
+ var x774 uint64
+ var x775 uint64
+ x775, x774 = bits.Mul64(x7, arg2[4])
+ var x776 uint64
+ var x777 uint64
+ x777, x776 = bits.Mul64(x7, arg2[3])
+ var x778 uint64
+ var x779 uint64
+ x779, x778 = bits.Mul64(x7, arg2[2])
+ var x780 uint64
+ var x781 uint64
+ x781, x780 = bits.Mul64(x7, arg2[1])
+ var x782 uint64
+ var x783 uint64
+ x783, x782 = bits.Mul64(x7, arg2[0])
+ var x784 uint64
+ var x785 uint64
+ x784, x785 = bits.Add64(x783, x780, uint64(0x0))
+ var x786 uint64
+ var x787 uint64
+ x786, x787 = bits.Add64(x781, x778, uint64(p521Uint1(x785)))
+ var x788 uint64
+ var x789 uint64
+ x788, x789 = bits.Add64(x779, x776, uint64(p521Uint1(x787)))
+ var x790 uint64
+ var x791 uint64
+ x790, x791 = bits.Add64(x777, x774, uint64(p521Uint1(x789)))
+ var x792 uint64
+ var x793 uint64
+ x792, x793 = bits.Add64(x775, x772, uint64(p521Uint1(x791)))
+ var x794 uint64
+ var x795 uint64
+ x794, x795 = bits.Add64(x773, x770, uint64(p521Uint1(x793)))
+ var x796 uint64
+ var x797 uint64
+ x796, x797 = bits.Add64(x771, x768, uint64(p521Uint1(x795)))
+ var x798 uint64
+ var x799 uint64
+ x798, x799 = bits.Add64(x769, x766, uint64(p521Uint1(x797)))
+ x800 := (uint64(p521Uint1(x799)) + x767)
+ var x801 uint64
+ var x802 uint64
+ x801, x802 = bits.Add64(x747, x782, uint64(0x0))
+ var x803 uint64
+ var x804 uint64
+ x803, x804 = bits.Add64(x749, x784, uint64(p521Uint1(x802)))
+ var x805 uint64
+ var x806 uint64
+ x805, x806 = bits.Add64(x751, x786, uint64(p521Uint1(x804)))
+ var x807 uint64
+ var x808 uint64
+ x807, x808 = bits.Add64(x753, x788, uint64(p521Uint1(x806)))
+ var x809 uint64
+ var x810 uint64
+ x809, x810 = bits.Add64(x755, x790, uint64(p521Uint1(x808)))
+ var x811 uint64
+ var x812 uint64
+ x811, x812 = bits.Add64(x757, x792, uint64(p521Uint1(x810)))
+ var x813 uint64
+ var x814 uint64
+ x813, x814 = bits.Add64(x759, x794, uint64(p521Uint1(x812)))
+ var x815 uint64
+ var x816 uint64
+ x815, x816 = bits.Add64(x761, x796, uint64(p521Uint1(x814)))
+ var x817 uint64
+ var x818 uint64
+ x817, x818 = bits.Add64(x763, x798, uint64(p521Uint1(x816)))
+ var x819 uint64
+ var x820 uint64
+ x819, x820 = bits.Add64(x765, x800, uint64(p521Uint1(x818)))
+ var x821 uint64
+ var x822 uint64
+ x822, x821 = bits.Mul64(x801, 0x1ff)
+ var x823 uint64
+ var x824 uint64
+ x824, x823 = bits.Mul64(x801, 0xffffffffffffffff)
+ var x825 uint64
+ var x826 uint64
+ x826, x825 = bits.Mul64(x801, 0xffffffffffffffff)
+ var x827 uint64
+ var x828 uint64
+ x828, x827 = bits.Mul64(x801, 0xffffffffffffffff)
+ var x829 uint64
+ var x830 uint64
+ x830, x829 = bits.Mul64(x801, 0xffffffffffffffff)
+ var x831 uint64
+ var x832 uint64
+ x832, x831 = bits.Mul64(x801, 0xffffffffffffffff)
+ var x833 uint64
+ var x834 uint64
+ x834, x833 = bits.Mul64(x801, 0xffffffffffffffff)
+ var x835 uint64
+ var x836 uint64
+ x836, x835 = bits.Mul64(x801, 0xffffffffffffffff)
+ var x837 uint64
+ var x838 uint64
+ x838, x837 = bits.Mul64(x801, 0xffffffffffffffff)
+ var x839 uint64
+ var x840 uint64
+ x839, x840 = bits.Add64(x838, x835, uint64(0x0))
+ var x841 uint64
+ var x842 uint64
+ x841, x842 = bits.Add64(x836, x833, uint64(p521Uint1(x840)))
+ var x843 uint64
+ var x844 uint64
+ x843, x844 = bits.Add64(x834, x831, uint64(p521Uint1(x842)))
+ var x845 uint64
+ var x846 uint64
+ x845, x846 = bits.Add64(x832, x829, uint64(p521Uint1(x844)))
+ var x847 uint64
+ var x848 uint64
+ x847, x848 = bits.Add64(x830, x827, uint64(p521Uint1(x846)))
+ var x849 uint64
+ var x850 uint64
+ x849, x850 = bits.Add64(x828, x825, uint64(p521Uint1(x848)))
+ var x851 uint64
+ var x852 uint64
+ x851, x852 = bits.Add64(x826, x823, uint64(p521Uint1(x850)))
+ var x853 uint64
+ var x854 uint64
+ x853, x854 = bits.Add64(x824, x821, uint64(p521Uint1(x852)))
+ x855 := (uint64(p521Uint1(x854)) + x822)
+ var x857 uint64
+ _, x857 = bits.Add64(x801, x837, uint64(0x0))
+ var x858 uint64
+ var x859 uint64
+ x858, x859 = bits.Add64(x803, x839, uint64(p521Uint1(x857)))
+ var x860 uint64
+ var x861 uint64
+ x860, x861 = bits.Add64(x805, x841, uint64(p521Uint1(x859)))
+ var x862 uint64
+ var x863 uint64
+ x862, x863 = bits.Add64(x807, x843, uint64(p521Uint1(x861)))
+ var x864 uint64
+ var x865 uint64
+ x864, x865 = bits.Add64(x809, x845, uint64(p521Uint1(x863)))
+ var x866 uint64
+ var x867 uint64
+ x866, x867 = bits.Add64(x811, x847, uint64(p521Uint1(x865)))
+ var x868 uint64
+ var x869 uint64
+ x868, x869 = bits.Add64(x813, x849, uint64(p521Uint1(x867)))
+ var x870 uint64
+ var x871 uint64
+ x870, x871 = bits.Add64(x815, x851, uint64(p521Uint1(x869)))
+ var x872 uint64
+ var x873 uint64
+ x872, x873 = bits.Add64(x817, x853, uint64(p521Uint1(x871)))
+ var x874 uint64
+ var x875 uint64
+ x874, x875 = bits.Add64(x819, x855, uint64(p521Uint1(x873)))
+ x876 := (uint64(p521Uint1(x875)) + uint64(p521Uint1(x820)))
+ var x877 uint64
+ var x878 uint64
+ x878, x877 = bits.Mul64(x8, arg2[8])
+ var x879 uint64
+ var x880 uint64
+ x880, x879 = bits.Mul64(x8, arg2[7])
+ var x881 uint64
+ var x882 uint64
+ x882, x881 = bits.Mul64(x8, arg2[6])
+ var x883 uint64
+ var x884 uint64
+ x884, x883 = bits.Mul64(x8, arg2[5])
+ var x885 uint64
+ var x886 uint64
+ x886, x885 = bits.Mul64(x8, arg2[4])
+ var x887 uint64
+ var x888 uint64
+ x888, x887 = bits.Mul64(x8, arg2[3])
+ var x889 uint64
+ var x890 uint64
+ x890, x889 = bits.Mul64(x8, arg2[2])
+ var x891 uint64
+ var x892 uint64
+ x892, x891 = bits.Mul64(x8, arg2[1])
+ var x893 uint64
+ var x894 uint64
+ x894, x893 = bits.Mul64(x8, arg2[0])
+ var x895 uint64
+ var x896 uint64
+ x895, x896 = bits.Add64(x894, x891, uint64(0x0))
+ var x897 uint64
+ var x898 uint64
+ x897, x898 = bits.Add64(x892, x889, uint64(p521Uint1(x896)))
+ var x899 uint64
+ var x900 uint64
+ x899, x900 = bits.Add64(x890, x887, uint64(p521Uint1(x898)))
+ var x901 uint64
+ var x902 uint64
+ x901, x902 = bits.Add64(x888, x885, uint64(p521Uint1(x900)))
+ var x903 uint64
+ var x904 uint64
+ x903, x904 = bits.Add64(x886, x883, uint64(p521Uint1(x902)))
+ var x905 uint64
+ var x906 uint64
+ x905, x906 = bits.Add64(x884, x881, uint64(p521Uint1(x904)))
+ var x907 uint64
+ var x908 uint64
+ x907, x908 = bits.Add64(x882, x879, uint64(p521Uint1(x906)))
+ var x909 uint64
+ var x910 uint64
+ x909, x910 = bits.Add64(x880, x877, uint64(p521Uint1(x908)))
+ x911 := (uint64(p521Uint1(x910)) + x878)
+ var x912 uint64
+ var x913 uint64
+ x912, x913 = bits.Add64(x858, x893, uint64(0x0))
+ var x914 uint64
+ var x915 uint64
+ x914, x915 = bits.Add64(x860, x895, uint64(p521Uint1(x913)))
+ var x916 uint64
+ var x917 uint64
+ x916, x917 = bits.Add64(x862, x897, uint64(p521Uint1(x915)))
+ var x918 uint64
+ var x919 uint64
+ x918, x919 = bits.Add64(x864, x899, uint64(p521Uint1(x917)))
+ var x920 uint64
+ var x921 uint64
+ x920, x921 = bits.Add64(x866, x901, uint64(p521Uint1(x919)))
+ var x922 uint64
+ var x923 uint64
+ x922, x923 = bits.Add64(x868, x903, uint64(p521Uint1(x921)))
+ var x924 uint64
+ var x925 uint64
+ x924, x925 = bits.Add64(x870, x905, uint64(p521Uint1(x923)))
+ var x926 uint64
+ var x927 uint64
+ x926, x927 = bits.Add64(x872, x907, uint64(p521Uint1(x925)))
+ var x928 uint64
+ var x929 uint64
+ x928, x929 = bits.Add64(x874, x909, uint64(p521Uint1(x927)))
+ var x930 uint64
+ var x931 uint64
+ x930, x931 = bits.Add64(x876, x911, uint64(p521Uint1(x929)))
+ var x932 uint64
+ var x933 uint64
+ x933, x932 = bits.Mul64(x912, 0x1ff)
+ var x934 uint64
+ var x935 uint64
+ x935, x934 = bits.Mul64(x912, 0xffffffffffffffff)
+ var x936 uint64
+ var x937 uint64
+ x937, x936 = bits.Mul64(x912, 0xffffffffffffffff)
+ var x938 uint64
+ var x939 uint64
+ x939, x938 = bits.Mul64(x912, 0xffffffffffffffff)
+ var x940 uint64
+ var x941 uint64
+ x941, x940 = bits.Mul64(x912, 0xffffffffffffffff)
+ var x942 uint64
+ var x943 uint64
+ x943, x942 = bits.Mul64(x912, 0xffffffffffffffff)
+ var x944 uint64
+ var x945 uint64
+ x945, x944 = bits.Mul64(x912, 0xffffffffffffffff)
+ var x946 uint64
+ var x947 uint64
+ x947, x946 = bits.Mul64(x912, 0xffffffffffffffff)
+ var x948 uint64
+ var x949 uint64
+ x949, x948 = bits.Mul64(x912, 0xffffffffffffffff)
+ var x950 uint64
+ var x951 uint64
+ x950, x951 = bits.Add64(x949, x946, uint64(0x0))
+ var x952 uint64
+ var x953 uint64
+ x952, x953 = bits.Add64(x947, x944, uint64(p521Uint1(x951)))
+ var x954 uint64
+ var x955 uint64
+ x954, x955 = bits.Add64(x945, x942, uint64(p521Uint1(x953)))
+ var x956 uint64
+ var x957 uint64
+ x956, x957 = bits.Add64(x943, x940, uint64(p521Uint1(x955)))
+ var x958 uint64
+ var x959 uint64
+ x958, x959 = bits.Add64(x941, x938, uint64(p521Uint1(x957)))
+ var x960 uint64
+ var x961 uint64
+ x960, x961 = bits.Add64(x939, x936, uint64(p521Uint1(x959)))
+ var x962 uint64
+ var x963 uint64
+ x962, x963 = bits.Add64(x937, x934, uint64(p521Uint1(x961)))
+ var x964 uint64
+ var x965 uint64
+ x964, x965 = bits.Add64(x935, x932, uint64(p521Uint1(x963)))
+ x966 := (uint64(p521Uint1(x965)) + x933)
+ var x968 uint64
+ _, x968 = bits.Add64(x912, x948, uint64(0x0))
+ var x969 uint64
+ var x970 uint64
+ x969, x970 = bits.Add64(x914, x950, uint64(p521Uint1(x968)))
+ var x971 uint64
+ var x972 uint64
+ x971, x972 = bits.Add64(x916, x952, uint64(p521Uint1(x970)))
+ var x973 uint64
+ var x974 uint64
+ x973, x974 = bits.Add64(x918, x954, uint64(p521Uint1(x972)))
+ var x975 uint64
+ var x976 uint64
+ x975, x976 = bits.Add64(x920, x956, uint64(p521Uint1(x974)))
+ var x977 uint64
+ var x978 uint64
+ x977, x978 = bits.Add64(x922, x958, uint64(p521Uint1(x976)))
+ var x979 uint64
+ var x980 uint64
+ x979, x980 = bits.Add64(x924, x960, uint64(p521Uint1(x978)))
+ var x981 uint64
+ var x982 uint64
+ x981, x982 = bits.Add64(x926, x962, uint64(p521Uint1(x980)))
+ var x983 uint64
+ var x984 uint64
+ x983, x984 = bits.Add64(x928, x964, uint64(p521Uint1(x982)))
+ var x985 uint64
+ var x986 uint64
+ x985, x986 = bits.Add64(x930, x966, uint64(p521Uint1(x984)))
+ x987 := (uint64(p521Uint1(x986)) + uint64(p521Uint1(x931)))
+ var x988 uint64
+ var x989 uint64
+ x988, x989 = bits.Sub64(x969, 0xffffffffffffffff, uint64(0x0))
+ var x990 uint64
+ var x991 uint64
+ x990, x991 = bits.Sub64(x971, 0xffffffffffffffff, uint64(p521Uint1(x989)))
+ var x992 uint64
+ var x993 uint64
+ x992, x993 = bits.Sub64(x973, 0xffffffffffffffff, uint64(p521Uint1(x991)))
+ var x994 uint64
+ var x995 uint64
+ x994, x995 = bits.Sub64(x975, 0xffffffffffffffff, uint64(p521Uint1(x993)))
+ var x996 uint64
+ var x997 uint64
+ x996, x997 = bits.Sub64(x977, 0xffffffffffffffff, uint64(p521Uint1(x995)))
+ var x998 uint64
+ var x999 uint64
+ x998, x999 = bits.Sub64(x979, 0xffffffffffffffff, uint64(p521Uint1(x997)))
+ var x1000 uint64
+ var x1001 uint64
+ x1000, x1001 = bits.Sub64(x981, 0xffffffffffffffff, uint64(p521Uint1(x999)))
+ var x1002 uint64
+ var x1003 uint64
+ x1002, x1003 = bits.Sub64(x983, 0xffffffffffffffff, uint64(p521Uint1(x1001)))
+ var x1004 uint64
+ var x1005 uint64
+ x1004, x1005 = bits.Sub64(x985, 0x1ff, uint64(p521Uint1(x1003)))
+ var x1007 uint64
+ _, x1007 = bits.Sub64(x987, uint64(0x0), uint64(p521Uint1(x1005)))
+ var x1008 uint64
+ p521CmovznzU64(&x1008, p521Uint1(x1007), x988, x969)
+ var x1009 uint64
+ p521CmovznzU64(&x1009, p521Uint1(x1007), x990, x971)
+ var x1010 uint64
+ p521CmovznzU64(&x1010, p521Uint1(x1007), x992, x973)
+ var x1011 uint64
+ p521CmovznzU64(&x1011, p521Uint1(x1007), x994, x975)
+ var x1012 uint64
+ p521CmovznzU64(&x1012, p521Uint1(x1007), x996, x977)
+ var x1013 uint64
+ p521CmovznzU64(&x1013, p521Uint1(x1007), x998, x979)
+ var x1014 uint64
+ p521CmovznzU64(&x1014, p521Uint1(x1007), x1000, x981)
+ var x1015 uint64
+ p521CmovznzU64(&x1015, p521Uint1(x1007), x1002, x983)
+ var x1016 uint64
+ p521CmovznzU64(&x1016, p521Uint1(x1007), x1004, x985)
+ out1[0] = x1008
+ out1[1] = x1009
+ out1[2] = x1010
+ out1[3] = x1011
+ out1[4] = x1012
+ out1[5] = x1013
+ out1[6] = x1014
+ out1[7] = x1015
+ out1[8] = x1016
+}
+
+// p521Square squares a field element in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) * eval (from_montgomery arg1)) mod m
+// 0 ≤ eval out1 < m
+func p521Square(out1 *p521MontgomeryDomainFieldElement, arg1 *p521MontgomeryDomainFieldElement) {
+ x1 := arg1[1]
+ x2 := arg1[2]
+ x3 := arg1[3]
+ x4 := arg1[4]
+ x5 := arg1[5]
+ x6 := arg1[6]
+ x7 := arg1[7]
+ x8 := arg1[8]
+ x9 := arg1[0]
+ var x10 uint64
+ var x11 uint64
+ x11, x10 = bits.Mul64(x9, arg1[8])
+ var x12 uint64
+ var x13 uint64
+ x13, x12 = bits.Mul64(x9, arg1[7])
+ var x14 uint64
+ var x15 uint64
+ x15, x14 = bits.Mul64(x9, arg1[6])
+ var x16 uint64
+ var x17 uint64
+ x17, x16 = bits.Mul64(x9, arg1[5])
+ var x18 uint64
+ var x19 uint64
+ x19, x18 = bits.Mul64(x9, arg1[4])
+ var x20 uint64
+ var x21 uint64
+ x21, x20 = bits.Mul64(x9, arg1[3])
+ var x22 uint64
+ var x23 uint64
+ x23, x22 = bits.Mul64(x9, arg1[2])
+ var x24 uint64
+ var x25 uint64
+ x25, x24 = bits.Mul64(x9, arg1[1])
+ var x26 uint64
+ var x27 uint64
+ x27, x26 = bits.Mul64(x9, arg1[0])
+ var x28 uint64
+ var x29 uint64
+ x28, x29 = bits.Add64(x27, x24, uint64(0x0))
+ var x30 uint64
+ var x31 uint64
+ x30, x31 = bits.Add64(x25, x22, uint64(p521Uint1(x29)))
+ var x32 uint64
+ var x33 uint64
+ x32, x33 = bits.Add64(x23, x20, uint64(p521Uint1(x31)))
+ var x34 uint64
+ var x35 uint64
+ x34, x35 = bits.Add64(x21, x18, uint64(p521Uint1(x33)))
+ var x36 uint64
+ var x37 uint64
+ x36, x37 = bits.Add64(x19, x16, uint64(p521Uint1(x35)))
+ var x38 uint64
+ var x39 uint64
+ x38, x39 = bits.Add64(x17, x14, uint64(p521Uint1(x37)))
+ var x40 uint64
+ var x41 uint64
+ x40, x41 = bits.Add64(x15, x12, uint64(p521Uint1(x39)))
+ var x42 uint64
+ var x43 uint64
+ x42, x43 = bits.Add64(x13, x10, uint64(p521Uint1(x41)))
+ x44 := (uint64(p521Uint1(x43)) + x11)
+ var x45 uint64
+ var x46 uint64
+ x46, x45 = bits.Mul64(x26, 0x1ff)
+ var x47 uint64
+ var x48 uint64
+ x48, x47 = bits.Mul64(x26, 0xffffffffffffffff)
+ var x49 uint64
+ var x50 uint64
+ x50, x49 = bits.Mul64(x26, 0xffffffffffffffff)
+ var x51 uint64
+ var x52 uint64
+ x52, x51 = bits.Mul64(x26, 0xffffffffffffffff)
+ var x53 uint64
+ var x54 uint64
+ x54, x53 = bits.Mul64(x26, 0xffffffffffffffff)
+ var x55 uint64
+ var x56 uint64
+ x56, x55 = bits.Mul64(x26, 0xffffffffffffffff)
+ var x57 uint64
+ var x58 uint64
+ x58, x57 = bits.Mul64(x26, 0xffffffffffffffff)
+ var x59 uint64
+ var x60 uint64
+ x60, x59 = bits.Mul64(x26, 0xffffffffffffffff)
+ var x61 uint64
+ var x62 uint64
+ x62, x61 = bits.Mul64(x26, 0xffffffffffffffff)
+ var x63 uint64
+ var x64 uint64
+ x63, x64 = bits.Add64(x62, x59, uint64(0x0))
+ var x65 uint64
+ var x66 uint64
+ x65, x66 = bits.Add64(x60, x57, uint64(p521Uint1(x64)))
+ var x67 uint64
+ var x68 uint64
+ x67, x68 = bits.Add64(x58, x55, uint64(p521Uint1(x66)))
+ var x69 uint64
+ var x70 uint64
+ x69, x70 = bits.Add64(x56, x53, uint64(p521Uint1(x68)))
+ var x71 uint64
+ var x72 uint64
+ x71, x72 = bits.Add64(x54, x51, uint64(p521Uint1(x70)))
+ var x73 uint64
+ var x74 uint64
+ x73, x74 = bits.Add64(x52, x49, uint64(p521Uint1(x72)))
+ var x75 uint64
+ var x76 uint64
+ x75, x76 = bits.Add64(x50, x47, uint64(p521Uint1(x74)))
+ var x77 uint64
+ var x78 uint64
+ x77, x78 = bits.Add64(x48, x45, uint64(p521Uint1(x76)))
+ x79 := (uint64(p521Uint1(x78)) + x46)
+ var x81 uint64
+ _, x81 = bits.Add64(x26, x61, uint64(0x0))
+ var x82 uint64
+ var x83 uint64
+ x82, x83 = bits.Add64(x28, x63, uint64(p521Uint1(x81)))
+ var x84 uint64
+ var x85 uint64
+ x84, x85 = bits.Add64(x30, x65, uint64(p521Uint1(x83)))
+ var x86 uint64
+ var x87 uint64
+ x86, x87 = bits.Add64(x32, x67, uint64(p521Uint1(x85)))
+ var x88 uint64
+ var x89 uint64
+ x88, x89 = bits.Add64(x34, x69, uint64(p521Uint1(x87)))
+ var x90 uint64
+ var x91 uint64
+ x90, x91 = bits.Add64(x36, x71, uint64(p521Uint1(x89)))
+ var x92 uint64
+ var x93 uint64
+ x92, x93 = bits.Add64(x38, x73, uint64(p521Uint1(x91)))
+ var x94 uint64
+ var x95 uint64
+ x94, x95 = bits.Add64(x40, x75, uint64(p521Uint1(x93)))
+ var x96 uint64
+ var x97 uint64
+ x96, x97 = bits.Add64(x42, x77, uint64(p521Uint1(x95)))
+ var x98 uint64
+ var x99 uint64
+ x98, x99 = bits.Add64(x44, x79, uint64(p521Uint1(x97)))
+ var x100 uint64
+ var x101 uint64
+ x101, x100 = bits.Mul64(x1, arg1[8])
+ var x102 uint64
+ var x103 uint64
+ x103, x102 = bits.Mul64(x1, arg1[7])
+ var x104 uint64
+ var x105 uint64
+ x105, x104 = bits.Mul64(x1, arg1[6])
+ var x106 uint64
+ var x107 uint64
+ x107, x106 = bits.Mul64(x1, arg1[5])
+ var x108 uint64
+ var x109 uint64
+ x109, x108 = bits.Mul64(x1, arg1[4])
+ var x110 uint64
+ var x111 uint64
+ x111, x110 = bits.Mul64(x1, arg1[3])
+ var x112 uint64
+ var x113 uint64
+ x113, x112 = bits.Mul64(x1, arg1[2])
+ var x114 uint64
+ var x115 uint64
+ x115, x114 = bits.Mul64(x1, arg1[1])
+ var x116 uint64
+ var x117 uint64
+ x117, x116 = bits.Mul64(x1, arg1[0])
+ var x118 uint64
+ var x119 uint64
+ x118, x119 = bits.Add64(x117, x114, uint64(0x0))
+ var x120 uint64
+ var x121 uint64
+ x120, x121 = bits.Add64(x115, x112, uint64(p521Uint1(x119)))
+ var x122 uint64
+ var x123 uint64
+ x122, x123 = bits.Add64(x113, x110, uint64(p521Uint1(x121)))
+ var x124 uint64
+ var x125 uint64
+ x124, x125 = bits.Add64(x111, x108, uint64(p521Uint1(x123)))
+ var x126 uint64
+ var x127 uint64
+ x126, x127 = bits.Add64(x109, x106, uint64(p521Uint1(x125)))
+ var x128 uint64
+ var x129 uint64
+ x128, x129 = bits.Add64(x107, x104, uint64(p521Uint1(x127)))
+ var x130 uint64
+ var x131 uint64
+ x130, x131 = bits.Add64(x105, x102, uint64(p521Uint1(x129)))
+ var x132 uint64
+ var x133 uint64
+ x132, x133 = bits.Add64(x103, x100, uint64(p521Uint1(x131)))
+ x134 := (uint64(p521Uint1(x133)) + x101)
+ var x135 uint64
+ var x136 uint64
+ x135, x136 = bits.Add64(x82, x116, uint64(0x0))
+ var x137 uint64
+ var x138 uint64
+ x137, x138 = bits.Add64(x84, x118, uint64(p521Uint1(x136)))
+ var x139 uint64
+ var x140 uint64
+ x139, x140 = bits.Add64(x86, x120, uint64(p521Uint1(x138)))
+ var x141 uint64
+ var x142 uint64
+ x141, x142 = bits.Add64(x88, x122, uint64(p521Uint1(x140)))
+ var x143 uint64
+ var x144 uint64
+ x143, x144 = bits.Add64(x90, x124, uint64(p521Uint1(x142)))
+ var x145 uint64
+ var x146 uint64
+ x145, x146 = bits.Add64(x92, x126, uint64(p521Uint1(x144)))
+ var x147 uint64
+ var x148 uint64
+ x147, x148 = bits.Add64(x94, x128, uint64(p521Uint1(x146)))
+ var x149 uint64
+ var x150 uint64
+ x149, x150 = bits.Add64(x96, x130, uint64(p521Uint1(x148)))
+ var x151 uint64
+ var x152 uint64
+ x151, x152 = bits.Add64(x98, x132, uint64(p521Uint1(x150)))
+ var x153 uint64
+ var x154 uint64
+ x153, x154 = bits.Add64(uint64(p521Uint1(x99)), x134, uint64(p521Uint1(x152)))
+ var x155 uint64
+ var x156 uint64
+ x156, x155 = bits.Mul64(x135, 0x1ff)
+ var x157 uint64
+ var x158 uint64
+ x158, x157 = bits.Mul64(x135, 0xffffffffffffffff)
+ var x159 uint64
+ var x160 uint64
+ x160, x159 = bits.Mul64(x135, 0xffffffffffffffff)
+ var x161 uint64
+ var x162 uint64
+ x162, x161 = bits.Mul64(x135, 0xffffffffffffffff)
+ var x163 uint64
+ var x164 uint64
+ x164, x163 = bits.Mul64(x135, 0xffffffffffffffff)
+ var x165 uint64
+ var x166 uint64
+ x166, x165 = bits.Mul64(x135, 0xffffffffffffffff)
+ var x167 uint64
+ var x168 uint64
+ x168, x167 = bits.Mul64(x135, 0xffffffffffffffff)
+ var x169 uint64
+ var x170 uint64
+ x170, x169 = bits.Mul64(x135, 0xffffffffffffffff)
+ var x171 uint64
+ var x172 uint64
+ x172, x171 = bits.Mul64(x135, 0xffffffffffffffff)
+ var x173 uint64
+ var x174 uint64
+ x173, x174 = bits.Add64(x172, x169, uint64(0x0))
+ var x175 uint64
+ var x176 uint64
+ x175, x176 = bits.Add64(x170, x167, uint64(p521Uint1(x174)))
+ var x177 uint64
+ var x178 uint64
+ x177, x178 = bits.Add64(x168, x165, uint64(p521Uint1(x176)))
+ var x179 uint64
+ var x180 uint64
+ x179, x180 = bits.Add64(x166, x163, uint64(p521Uint1(x178)))
+ var x181 uint64
+ var x182 uint64
+ x181, x182 = bits.Add64(x164, x161, uint64(p521Uint1(x180)))
+ var x183 uint64
+ var x184 uint64
+ x183, x184 = bits.Add64(x162, x159, uint64(p521Uint1(x182)))
+ var x185 uint64
+ var x186 uint64
+ x185, x186 = bits.Add64(x160, x157, uint64(p521Uint1(x184)))
+ var x187 uint64
+ var x188 uint64
+ x187, x188 = bits.Add64(x158, x155, uint64(p521Uint1(x186)))
+ x189 := (uint64(p521Uint1(x188)) + x156)
+ var x191 uint64
+ _, x191 = bits.Add64(x135, x171, uint64(0x0))
+ var x192 uint64
+ var x193 uint64
+ x192, x193 = bits.Add64(x137, x173, uint64(p521Uint1(x191)))
+ var x194 uint64
+ var x195 uint64
+ x194, x195 = bits.Add64(x139, x175, uint64(p521Uint1(x193)))
+ var x196 uint64
+ var x197 uint64
+ x196, x197 = bits.Add64(x141, x177, uint64(p521Uint1(x195)))
+ var x198 uint64
+ var x199 uint64
+ x198, x199 = bits.Add64(x143, x179, uint64(p521Uint1(x197)))
+ var x200 uint64
+ var x201 uint64
+ x200, x201 = bits.Add64(x145, x181, uint64(p521Uint1(x199)))
+ var x202 uint64
+ var x203 uint64
+ x202, x203 = bits.Add64(x147, x183, uint64(p521Uint1(x201)))
+ var x204 uint64
+ var x205 uint64
+ x204, x205 = bits.Add64(x149, x185, uint64(p521Uint1(x203)))
+ var x206 uint64
+ var x207 uint64
+ x206, x207 = bits.Add64(x151, x187, uint64(p521Uint1(x205)))
+ var x208 uint64
+ var x209 uint64
+ x208, x209 = bits.Add64(x153, x189, uint64(p521Uint1(x207)))
+ x210 := (uint64(p521Uint1(x209)) + uint64(p521Uint1(x154)))
+ var x211 uint64
+ var x212 uint64
+ x212, x211 = bits.Mul64(x2, arg1[8])
+ var x213 uint64
+ var x214 uint64
+ x214, x213 = bits.Mul64(x2, arg1[7])
+ var x215 uint64
+ var x216 uint64
+ x216, x215 = bits.Mul64(x2, arg1[6])
+ var x217 uint64
+ var x218 uint64
+ x218, x217 = bits.Mul64(x2, arg1[5])
+ var x219 uint64
+ var x220 uint64
+ x220, x219 = bits.Mul64(x2, arg1[4])
+ var x221 uint64
+ var x222 uint64
+ x222, x221 = bits.Mul64(x2, arg1[3])
+ var x223 uint64
+ var x224 uint64
+ x224, x223 = bits.Mul64(x2, arg1[2])
+ var x225 uint64
+ var x226 uint64
+ x226, x225 = bits.Mul64(x2, arg1[1])
+ var x227 uint64
+ var x228 uint64
+ x228, x227 = bits.Mul64(x2, arg1[0])
+ var x229 uint64
+ var x230 uint64
+ x229, x230 = bits.Add64(x228, x225, uint64(0x0))
+ var x231 uint64
+ var x232 uint64
+ x231, x232 = bits.Add64(x226, x223, uint64(p521Uint1(x230)))
+ var x233 uint64
+ var x234 uint64
+ x233, x234 = bits.Add64(x224, x221, uint64(p521Uint1(x232)))
+ var x235 uint64
+ var x236 uint64
+ x235, x236 = bits.Add64(x222, x219, uint64(p521Uint1(x234)))
+ var x237 uint64
+ var x238 uint64
+ x237, x238 = bits.Add64(x220, x217, uint64(p521Uint1(x236)))
+ var x239 uint64
+ var x240 uint64
+ x239, x240 = bits.Add64(x218, x215, uint64(p521Uint1(x238)))
+ var x241 uint64
+ var x242 uint64
+ x241, x242 = bits.Add64(x216, x213, uint64(p521Uint1(x240)))
+ var x243 uint64
+ var x244 uint64
+ x243, x244 = bits.Add64(x214, x211, uint64(p521Uint1(x242)))
+ x245 := (uint64(p521Uint1(x244)) + x212)
+ var x246 uint64
+ var x247 uint64
+ x246, x247 = bits.Add64(x192, x227, uint64(0x0))
+ var x248 uint64
+ var x249 uint64
+ x248, x249 = bits.Add64(x194, x229, uint64(p521Uint1(x247)))
+ var x250 uint64
+ var x251 uint64
+ x250, x251 = bits.Add64(x196, x231, uint64(p521Uint1(x249)))
+ var x252 uint64
+ var x253 uint64
+ x252, x253 = bits.Add64(x198, x233, uint64(p521Uint1(x251)))
+ var x254 uint64
+ var x255 uint64
+ x254, x255 = bits.Add64(x200, x235, uint64(p521Uint1(x253)))
+ var x256 uint64
+ var x257 uint64
+ x256, x257 = bits.Add64(x202, x237, uint64(p521Uint1(x255)))
+ var x258 uint64
+ var x259 uint64
+ x258, x259 = bits.Add64(x204, x239, uint64(p521Uint1(x257)))
+ var x260 uint64
+ var x261 uint64
+ x260, x261 = bits.Add64(x206, x241, uint64(p521Uint1(x259)))
+ var x262 uint64
+ var x263 uint64
+ x262, x263 = bits.Add64(x208, x243, uint64(p521Uint1(x261)))
+ var x264 uint64
+ var x265 uint64
+ x264, x265 = bits.Add64(x210, x245, uint64(p521Uint1(x263)))
+ var x266 uint64
+ var x267 uint64
+ x267, x266 = bits.Mul64(x246, 0x1ff)
+ var x268 uint64
+ var x269 uint64
+ x269, x268 = bits.Mul64(x246, 0xffffffffffffffff)
+ var x270 uint64
+ var x271 uint64
+ x271, x270 = bits.Mul64(x246, 0xffffffffffffffff)
+ var x272 uint64
+ var x273 uint64
+ x273, x272 = bits.Mul64(x246, 0xffffffffffffffff)
+ var x274 uint64
+ var x275 uint64
+ x275, x274 = bits.Mul64(x246, 0xffffffffffffffff)
+ var x276 uint64
+ var x277 uint64
+ x277, x276 = bits.Mul64(x246, 0xffffffffffffffff)
+ var x278 uint64
+ var x279 uint64
+ x279, x278 = bits.Mul64(x246, 0xffffffffffffffff)
+ var x280 uint64
+ var x281 uint64
+ x281, x280 = bits.Mul64(x246, 0xffffffffffffffff)
+ var x282 uint64
+ var x283 uint64
+ x283, x282 = bits.Mul64(x246, 0xffffffffffffffff)
+ var x284 uint64
+ var x285 uint64
+ x284, x285 = bits.Add64(x283, x280, uint64(0x0))
+ var x286 uint64
+ var x287 uint64
+ x286, x287 = bits.Add64(x281, x278, uint64(p521Uint1(x285)))
+ var x288 uint64
+ var x289 uint64
+ x288, x289 = bits.Add64(x279, x276, uint64(p521Uint1(x287)))
+ var x290 uint64
+ var x291 uint64
+ x290, x291 = bits.Add64(x277, x274, uint64(p521Uint1(x289)))
+ var x292 uint64
+ var x293 uint64
+ x292, x293 = bits.Add64(x275, x272, uint64(p521Uint1(x291)))
+ var x294 uint64
+ var x295 uint64
+ x294, x295 = bits.Add64(x273, x270, uint64(p521Uint1(x293)))
+ var x296 uint64
+ var x297 uint64
+ x296, x297 = bits.Add64(x271, x268, uint64(p521Uint1(x295)))
+ var x298 uint64
+ var x299 uint64
+ x298, x299 = bits.Add64(x269, x266, uint64(p521Uint1(x297)))
+ x300 := (uint64(p521Uint1(x299)) + x267)
+ var x302 uint64
+ _, x302 = bits.Add64(x246, x282, uint64(0x0))
+ var x303 uint64
+ var x304 uint64
+ x303, x304 = bits.Add64(x248, x284, uint64(p521Uint1(x302)))
+ var x305 uint64
+ var x306 uint64
+ x305, x306 = bits.Add64(x250, x286, uint64(p521Uint1(x304)))
+ var x307 uint64
+ var x308 uint64
+ x307, x308 = bits.Add64(x252, x288, uint64(p521Uint1(x306)))
+ var x309 uint64
+ var x310 uint64
+ x309, x310 = bits.Add64(x254, x290, uint64(p521Uint1(x308)))
+ var x311 uint64
+ var x312 uint64
+ x311, x312 = bits.Add64(x256, x292, uint64(p521Uint1(x310)))
+ var x313 uint64
+ var x314 uint64
+ x313, x314 = bits.Add64(x258, x294, uint64(p521Uint1(x312)))
+ var x315 uint64
+ var x316 uint64
+ x315, x316 = bits.Add64(x260, x296, uint64(p521Uint1(x314)))
+ var x317 uint64
+ var x318 uint64
+ x317, x318 = bits.Add64(x262, x298, uint64(p521Uint1(x316)))
+ var x319 uint64
+ var x320 uint64
+ x319, x320 = bits.Add64(x264, x300, uint64(p521Uint1(x318)))
+ x321 := (uint64(p521Uint1(x320)) + uint64(p521Uint1(x265)))
+ var x322 uint64
+ var x323 uint64
+ x323, x322 = bits.Mul64(x3, arg1[8])
+ var x324 uint64
+ var x325 uint64
+ x325, x324 = bits.Mul64(x3, arg1[7])
+ var x326 uint64
+ var x327 uint64
+ x327, x326 = bits.Mul64(x3, arg1[6])
+ var x328 uint64
+ var x329 uint64
+ x329, x328 = bits.Mul64(x3, arg1[5])
+ var x330 uint64
+ var x331 uint64
+ x331, x330 = bits.Mul64(x3, arg1[4])
+ var x332 uint64
+ var x333 uint64
+ x333, x332 = bits.Mul64(x3, arg1[3])
+ var x334 uint64
+ var x335 uint64
+ x335, x334 = bits.Mul64(x3, arg1[2])
+ var x336 uint64
+ var x337 uint64
+ x337, x336 = bits.Mul64(x3, arg1[1])
+ var x338 uint64
+ var x339 uint64
+ x339, x338 = bits.Mul64(x3, arg1[0])
+ var x340 uint64
+ var x341 uint64
+ x340, x341 = bits.Add64(x339, x336, uint64(0x0))
+ var x342 uint64
+ var x343 uint64
+ x342, x343 = bits.Add64(x337, x334, uint64(p521Uint1(x341)))
+ var x344 uint64
+ var x345 uint64
+ x344, x345 = bits.Add64(x335, x332, uint64(p521Uint1(x343)))
+ var x346 uint64
+ var x347 uint64
+ x346, x347 = bits.Add64(x333, x330, uint64(p521Uint1(x345)))
+ var x348 uint64
+ var x349 uint64
+ x348, x349 = bits.Add64(x331, x328, uint64(p521Uint1(x347)))
+ var x350 uint64
+ var x351 uint64
+ x350, x351 = bits.Add64(x329, x326, uint64(p521Uint1(x349)))
+ var x352 uint64
+ var x353 uint64
+ x352, x353 = bits.Add64(x327, x324, uint64(p521Uint1(x351)))
+ var x354 uint64
+ var x355 uint64
+ x354, x355 = bits.Add64(x325, x322, uint64(p521Uint1(x353)))
+ x356 := (uint64(p521Uint1(x355)) + x323)
+ var x357 uint64
+ var x358 uint64
+ x357, x358 = bits.Add64(x303, x338, uint64(0x0))
+ var x359 uint64
+ var x360 uint64
+ x359, x360 = bits.Add64(x305, x340, uint64(p521Uint1(x358)))
+ var x361 uint64
+ var x362 uint64
+ x361, x362 = bits.Add64(x307, x342, uint64(p521Uint1(x360)))
+ var x363 uint64
+ var x364 uint64
+ x363, x364 = bits.Add64(x309, x344, uint64(p521Uint1(x362)))
+ var x365 uint64
+ var x366 uint64
+ x365, x366 = bits.Add64(x311, x346, uint64(p521Uint1(x364)))
+ var x367 uint64
+ var x368 uint64
+ x367, x368 = bits.Add64(x313, x348, uint64(p521Uint1(x366)))
+ var x369 uint64
+ var x370 uint64
+ x369, x370 = bits.Add64(x315, x350, uint64(p521Uint1(x368)))
+ var x371 uint64
+ var x372 uint64
+ x371, x372 = bits.Add64(x317, x352, uint64(p521Uint1(x370)))
+ var x373 uint64
+ var x374 uint64
+ x373, x374 = bits.Add64(x319, x354, uint64(p521Uint1(x372)))
+ var x375 uint64
+ var x376 uint64
+ x375, x376 = bits.Add64(x321, x356, uint64(p521Uint1(x374)))
+ var x377 uint64
+ var x378 uint64
+ x378, x377 = bits.Mul64(x357, 0x1ff)
+ var x379 uint64
+ var x380 uint64
+ x380, x379 = bits.Mul64(x357, 0xffffffffffffffff)
+ var x381 uint64
+ var x382 uint64
+ x382, x381 = bits.Mul64(x357, 0xffffffffffffffff)
+ var x383 uint64
+ var x384 uint64
+ x384, x383 = bits.Mul64(x357, 0xffffffffffffffff)
+ var x385 uint64
+ var x386 uint64
+ x386, x385 = bits.Mul64(x357, 0xffffffffffffffff)
+ var x387 uint64
+ var x388 uint64
+ x388, x387 = bits.Mul64(x357, 0xffffffffffffffff)
+ var x389 uint64
+ var x390 uint64
+ x390, x389 = bits.Mul64(x357, 0xffffffffffffffff)
+ var x391 uint64
+ var x392 uint64
+ x392, x391 = bits.Mul64(x357, 0xffffffffffffffff)
+ var x393 uint64
+ var x394 uint64
+ x394, x393 = bits.Mul64(x357, 0xffffffffffffffff)
+ var x395 uint64
+ var x396 uint64
+ x395, x396 = bits.Add64(x394, x391, uint64(0x0))
+ var x397 uint64
+ var x398 uint64
+ x397, x398 = bits.Add64(x392, x389, uint64(p521Uint1(x396)))
+ var x399 uint64
+ var x400 uint64
+ x399, x400 = bits.Add64(x390, x387, uint64(p521Uint1(x398)))
+ var x401 uint64
+ var x402 uint64
+ x401, x402 = bits.Add64(x388, x385, uint64(p521Uint1(x400)))
+ var x403 uint64
+ var x404 uint64
+ x403, x404 = bits.Add64(x386, x383, uint64(p521Uint1(x402)))
+ var x405 uint64
+ var x406 uint64
+ x405, x406 = bits.Add64(x384, x381, uint64(p521Uint1(x404)))
+ var x407 uint64
+ var x408 uint64
+ x407, x408 = bits.Add64(x382, x379, uint64(p521Uint1(x406)))
+ var x409 uint64
+ var x410 uint64
+ x409, x410 = bits.Add64(x380, x377, uint64(p521Uint1(x408)))
+ x411 := (uint64(p521Uint1(x410)) + x378)
+ var x413 uint64
+ _, x413 = bits.Add64(x357, x393, uint64(0x0))
+ var x414 uint64
+ var x415 uint64
+ x414, x415 = bits.Add64(x359, x395, uint64(p521Uint1(x413)))
+ var x416 uint64
+ var x417 uint64
+ x416, x417 = bits.Add64(x361, x397, uint64(p521Uint1(x415)))
+ var x418 uint64
+ var x419 uint64
+ x418, x419 = bits.Add64(x363, x399, uint64(p521Uint1(x417)))
+ var x420 uint64
+ var x421 uint64
+ x420, x421 = bits.Add64(x365, x401, uint64(p521Uint1(x419)))
+ var x422 uint64
+ var x423 uint64
+ x422, x423 = bits.Add64(x367, x403, uint64(p521Uint1(x421)))
+ var x424 uint64
+ var x425 uint64
+ x424, x425 = bits.Add64(x369, x405, uint64(p521Uint1(x423)))
+ var x426 uint64
+ var x427 uint64
+ x426, x427 = bits.Add64(x371, x407, uint64(p521Uint1(x425)))
+ var x428 uint64
+ var x429 uint64
+ x428, x429 = bits.Add64(x373, x409, uint64(p521Uint1(x427)))
+ var x430 uint64
+ var x431 uint64
+ x430, x431 = bits.Add64(x375, x411, uint64(p521Uint1(x429)))
+ x432 := (uint64(p521Uint1(x431)) + uint64(p521Uint1(x376)))
+ var x433 uint64
+ var x434 uint64
+ x434, x433 = bits.Mul64(x4, arg1[8])
+ var x435 uint64
+ var x436 uint64
+ x436, x435 = bits.Mul64(x4, arg1[7])
+ var x437 uint64
+ var x438 uint64
+ x438, x437 = bits.Mul64(x4, arg1[6])
+ var x439 uint64
+ var x440 uint64
+ x440, x439 = bits.Mul64(x4, arg1[5])
+ var x441 uint64
+ var x442 uint64
+ x442, x441 = bits.Mul64(x4, arg1[4])
+ var x443 uint64
+ var x444 uint64
+ x444, x443 = bits.Mul64(x4, arg1[3])
+ var x445 uint64
+ var x446 uint64
+ x446, x445 = bits.Mul64(x4, arg1[2])
+ var x447 uint64
+ var x448 uint64
+ x448, x447 = bits.Mul64(x4, arg1[1])
+ var x449 uint64
+ var x450 uint64
+ x450, x449 = bits.Mul64(x4, arg1[0])
+ var x451 uint64
+ var x452 uint64
+ x451, x452 = bits.Add64(x450, x447, uint64(0x0))
+ var x453 uint64
+ var x454 uint64
+ x453, x454 = bits.Add64(x448, x445, uint64(p521Uint1(x452)))
+ var x455 uint64
+ var x456 uint64
+ x455, x456 = bits.Add64(x446, x443, uint64(p521Uint1(x454)))
+ var x457 uint64
+ var x458 uint64
+ x457, x458 = bits.Add64(x444, x441, uint64(p521Uint1(x456)))
+ var x459 uint64
+ var x460 uint64
+ x459, x460 = bits.Add64(x442, x439, uint64(p521Uint1(x458)))
+ var x461 uint64
+ var x462 uint64
+ x461, x462 = bits.Add64(x440, x437, uint64(p521Uint1(x460)))
+ var x463 uint64
+ var x464 uint64
+ x463, x464 = bits.Add64(x438, x435, uint64(p521Uint1(x462)))
+ var x465 uint64
+ var x466 uint64
+ x465, x466 = bits.Add64(x436, x433, uint64(p521Uint1(x464)))
+ x467 := (uint64(p521Uint1(x466)) + x434)
+ var x468 uint64
+ var x469 uint64
+ x468, x469 = bits.Add64(x414, x449, uint64(0x0))
+ var x470 uint64
+ var x471 uint64
+ x470, x471 = bits.Add64(x416, x451, uint64(p521Uint1(x469)))
+ var x472 uint64
+ var x473 uint64
+ x472, x473 = bits.Add64(x418, x453, uint64(p521Uint1(x471)))
+ var x474 uint64
+ var x475 uint64
+ x474, x475 = bits.Add64(x420, x455, uint64(p521Uint1(x473)))
+ var x476 uint64
+ var x477 uint64
+ x476, x477 = bits.Add64(x422, x457, uint64(p521Uint1(x475)))
+ var x478 uint64
+ var x479 uint64
+ x478, x479 = bits.Add64(x424, x459, uint64(p521Uint1(x477)))
+ var x480 uint64
+ var x481 uint64
+ x480, x481 = bits.Add64(x426, x461, uint64(p521Uint1(x479)))
+ var x482 uint64
+ var x483 uint64
+ x482, x483 = bits.Add64(x428, x463, uint64(p521Uint1(x481)))
+ var x484 uint64
+ var x485 uint64
+ x484, x485 = bits.Add64(x430, x465, uint64(p521Uint1(x483)))
+ var x486 uint64
+ var x487 uint64
+ x486, x487 = bits.Add64(x432, x467, uint64(p521Uint1(x485)))
+ var x488 uint64
+ var x489 uint64
+ x489, x488 = bits.Mul64(x468, 0x1ff)
+ var x490 uint64
+ var x491 uint64
+ x491, x490 = bits.Mul64(x468, 0xffffffffffffffff)
+ var x492 uint64
+ var x493 uint64
+ x493, x492 = bits.Mul64(x468, 0xffffffffffffffff)
+ var x494 uint64
+ var x495 uint64
+ x495, x494 = bits.Mul64(x468, 0xffffffffffffffff)
+ var x496 uint64
+ var x497 uint64
+ x497, x496 = bits.Mul64(x468, 0xffffffffffffffff)
+ var x498 uint64
+ var x499 uint64
+ x499, x498 = bits.Mul64(x468, 0xffffffffffffffff)
+ var x500 uint64
+ var x501 uint64
+ x501, x500 = bits.Mul64(x468, 0xffffffffffffffff)
+ var x502 uint64
+ var x503 uint64
+ x503, x502 = bits.Mul64(x468, 0xffffffffffffffff)
+ var x504 uint64
+ var x505 uint64
+ x505, x504 = bits.Mul64(x468, 0xffffffffffffffff)
+ var x506 uint64
+ var x507 uint64
+ x506, x507 = bits.Add64(x505, x502, uint64(0x0))
+ var x508 uint64
+ var x509 uint64
+ x508, x509 = bits.Add64(x503, x500, uint64(p521Uint1(x507)))
+ var x510 uint64
+ var x511 uint64
+ x510, x511 = bits.Add64(x501, x498, uint64(p521Uint1(x509)))
+ var x512 uint64
+ var x513 uint64
+ x512, x513 = bits.Add64(x499, x496, uint64(p521Uint1(x511)))
+ var x514 uint64
+ var x515 uint64
+ x514, x515 = bits.Add64(x497, x494, uint64(p521Uint1(x513)))
+ var x516 uint64
+ var x517 uint64
+ x516, x517 = bits.Add64(x495, x492, uint64(p521Uint1(x515)))
+ var x518 uint64
+ var x519 uint64
+ x518, x519 = bits.Add64(x493, x490, uint64(p521Uint1(x517)))
+ var x520 uint64
+ var x521 uint64
+ x520, x521 = bits.Add64(x491, x488, uint64(p521Uint1(x519)))
+ x522 := (uint64(p521Uint1(x521)) + x489)
+ var x524 uint64
+ _, x524 = bits.Add64(x468, x504, uint64(0x0))
+ var x525 uint64
+ var x526 uint64
+ x525, x526 = bits.Add64(x470, x506, uint64(p521Uint1(x524)))
+ var x527 uint64
+ var x528 uint64
+ x527, x528 = bits.Add64(x472, x508, uint64(p521Uint1(x526)))
+ var x529 uint64
+ var x530 uint64
+ x529, x530 = bits.Add64(x474, x510, uint64(p521Uint1(x528)))
+ var x531 uint64
+ var x532 uint64
+ x531, x532 = bits.Add64(x476, x512, uint64(p521Uint1(x530)))
+ var x533 uint64
+ var x534 uint64
+ x533, x534 = bits.Add64(x478, x514, uint64(p521Uint1(x532)))
+ var x535 uint64
+ var x536 uint64
+ x535, x536 = bits.Add64(x480, x516, uint64(p521Uint1(x534)))
+ var x537 uint64
+ var x538 uint64
+ x537, x538 = bits.Add64(x482, x518, uint64(p521Uint1(x536)))
+ var x539 uint64
+ var x540 uint64
+ x539, x540 = bits.Add64(x484, x520, uint64(p521Uint1(x538)))
+ var x541 uint64
+ var x542 uint64
+ x541, x542 = bits.Add64(x486, x522, uint64(p521Uint1(x540)))
+ x543 := (uint64(p521Uint1(x542)) + uint64(p521Uint1(x487)))
+ var x544 uint64
+ var x545 uint64
+ x545, x544 = bits.Mul64(x5, arg1[8])
+ var x546 uint64
+ var x547 uint64
+ x547, x546 = bits.Mul64(x5, arg1[7])
+ var x548 uint64
+ var x549 uint64
+ x549, x548 = bits.Mul64(x5, arg1[6])
+ var x550 uint64
+ var x551 uint64
+ x551, x550 = bits.Mul64(x5, arg1[5])
+ var x552 uint64
+ var x553 uint64
+ x553, x552 = bits.Mul64(x5, arg1[4])
+ var x554 uint64
+ var x555 uint64
+ x555, x554 = bits.Mul64(x5, arg1[3])
+ var x556 uint64
+ var x557 uint64
+ x557, x556 = bits.Mul64(x5, arg1[2])
+ var x558 uint64
+ var x559 uint64
+ x559, x558 = bits.Mul64(x5, arg1[1])
+ var x560 uint64
+ var x561 uint64
+ x561, x560 = bits.Mul64(x5, arg1[0])
+ var x562 uint64
+ var x563 uint64
+ x562, x563 = bits.Add64(x561, x558, uint64(0x0))
+ var x564 uint64
+ var x565 uint64
+ x564, x565 = bits.Add64(x559, x556, uint64(p521Uint1(x563)))
+ var x566 uint64
+ var x567 uint64
+ x566, x567 = bits.Add64(x557, x554, uint64(p521Uint1(x565)))
+ var x568 uint64
+ var x569 uint64
+ x568, x569 = bits.Add64(x555, x552, uint64(p521Uint1(x567)))
+ var x570 uint64
+ var x571 uint64
+ x570, x571 = bits.Add64(x553, x550, uint64(p521Uint1(x569)))
+ var x572 uint64
+ var x573 uint64
+ x572, x573 = bits.Add64(x551, x548, uint64(p521Uint1(x571)))
+ var x574 uint64
+ var x575 uint64
+ x574, x575 = bits.Add64(x549, x546, uint64(p521Uint1(x573)))
+ var x576 uint64
+ var x577 uint64
+ x576, x577 = bits.Add64(x547, x544, uint64(p521Uint1(x575)))
+ x578 := (uint64(p521Uint1(x577)) + x545)
+ var x579 uint64
+ var x580 uint64
+ x579, x580 = bits.Add64(x525, x560, uint64(0x0))
+ var x581 uint64
+ var x582 uint64
+ x581, x582 = bits.Add64(x527, x562, uint64(p521Uint1(x580)))
+ var x583 uint64
+ var x584 uint64
+ x583, x584 = bits.Add64(x529, x564, uint64(p521Uint1(x582)))
+ var x585 uint64
+ var x586 uint64
+ x585, x586 = bits.Add64(x531, x566, uint64(p521Uint1(x584)))
+ var x587 uint64
+ var x588 uint64
+ x587, x588 = bits.Add64(x533, x568, uint64(p521Uint1(x586)))
+ var x589 uint64
+ var x590 uint64
+ x589, x590 = bits.Add64(x535, x570, uint64(p521Uint1(x588)))
+ var x591 uint64
+ var x592 uint64
+ x591, x592 = bits.Add64(x537, x572, uint64(p521Uint1(x590)))
+ var x593 uint64
+ var x594 uint64
+ x593, x594 = bits.Add64(x539, x574, uint64(p521Uint1(x592)))
+ var x595 uint64
+ var x596 uint64
+ x595, x596 = bits.Add64(x541, x576, uint64(p521Uint1(x594)))
+ var x597 uint64
+ var x598 uint64
+ x597, x598 = bits.Add64(x543, x578, uint64(p521Uint1(x596)))
+ var x599 uint64
+ var x600 uint64
+ x600, x599 = bits.Mul64(x579, 0x1ff)
+ var x601 uint64
+ var x602 uint64
+ x602, x601 = bits.Mul64(x579, 0xffffffffffffffff)
+ var x603 uint64
+ var x604 uint64
+ x604, x603 = bits.Mul64(x579, 0xffffffffffffffff)
+ var x605 uint64
+ var x606 uint64
+ x606, x605 = bits.Mul64(x579, 0xffffffffffffffff)
+ var x607 uint64
+ var x608 uint64
+ x608, x607 = bits.Mul64(x579, 0xffffffffffffffff)
+ var x609 uint64
+ var x610 uint64
+ x610, x609 = bits.Mul64(x579, 0xffffffffffffffff)
+ var x611 uint64
+ var x612 uint64
+ x612, x611 = bits.Mul64(x579, 0xffffffffffffffff)
+ var x613 uint64
+ var x614 uint64
+ x614, x613 = bits.Mul64(x579, 0xffffffffffffffff)
+ var x615 uint64
+ var x616 uint64
+ x616, x615 = bits.Mul64(x579, 0xffffffffffffffff)
+ var x617 uint64
+ var x618 uint64
+ x617, x618 = bits.Add64(x616, x613, uint64(0x0))
+ var x619 uint64
+ var x620 uint64
+ x619, x620 = bits.Add64(x614, x611, uint64(p521Uint1(x618)))
+ var x621 uint64
+ var x622 uint64
+ x621, x622 = bits.Add64(x612, x609, uint64(p521Uint1(x620)))
+ var x623 uint64
+ var x624 uint64
+ x623, x624 = bits.Add64(x610, x607, uint64(p521Uint1(x622)))
+ var x625 uint64
+ var x626 uint64
+ x625, x626 = bits.Add64(x608, x605, uint64(p521Uint1(x624)))
+ var x627 uint64
+ var x628 uint64
+ x627, x628 = bits.Add64(x606, x603, uint64(p521Uint1(x626)))
+ var x629 uint64
+ var x630 uint64
+ x629, x630 = bits.Add64(x604, x601, uint64(p521Uint1(x628)))
+ var x631 uint64
+ var x632 uint64
+ x631, x632 = bits.Add64(x602, x599, uint64(p521Uint1(x630)))
+ x633 := (uint64(p521Uint1(x632)) + x600)
+ var x635 uint64
+ _, x635 = bits.Add64(x579, x615, uint64(0x0))
+ var x636 uint64
+ var x637 uint64
+ x636, x637 = bits.Add64(x581, x617, uint64(p521Uint1(x635)))
+ var x638 uint64
+ var x639 uint64
+ x638, x639 = bits.Add64(x583, x619, uint64(p521Uint1(x637)))
+ var x640 uint64
+ var x641 uint64
+ x640, x641 = bits.Add64(x585, x621, uint64(p521Uint1(x639)))
+ var x642 uint64
+ var x643 uint64
+ x642, x643 = bits.Add64(x587, x623, uint64(p521Uint1(x641)))
+ var x644 uint64
+ var x645 uint64
+ x644, x645 = bits.Add64(x589, x625, uint64(p521Uint1(x643)))
+ var x646 uint64
+ var x647 uint64
+ x646, x647 = bits.Add64(x591, x627, uint64(p521Uint1(x645)))
+ var x648 uint64
+ var x649 uint64
+ x648, x649 = bits.Add64(x593, x629, uint64(p521Uint1(x647)))
+ var x650 uint64
+ var x651 uint64
+ x650, x651 = bits.Add64(x595, x631, uint64(p521Uint1(x649)))
+ var x652 uint64
+ var x653 uint64
+ x652, x653 = bits.Add64(x597, x633, uint64(p521Uint1(x651)))
+ x654 := (uint64(p521Uint1(x653)) + uint64(p521Uint1(x598)))
+ var x655 uint64
+ var x656 uint64
+ x656, x655 = bits.Mul64(x6, arg1[8])
+ var x657 uint64
+ var x658 uint64
+ x658, x657 = bits.Mul64(x6, arg1[7])
+ var x659 uint64
+ var x660 uint64
+ x660, x659 = bits.Mul64(x6, arg1[6])
+ var x661 uint64
+ var x662 uint64
+ x662, x661 = bits.Mul64(x6, arg1[5])
+ var x663 uint64
+ var x664 uint64
+ x664, x663 = bits.Mul64(x6, arg1[4])
+ var x665 uint64
+ var x666 uint64
+ x666, x665 = bits.Mul64(x6, arg1[3])
+ var x667 uint64
+ var x668 uint64
+ x668, x667 = bits.Mul64(x6, arg1[2])
+ var x669 uint64
+ var x670 uint64
+ x670, x669 = bits.Mul64(x6, arg1[1])
+ var x671 uint64
+ var x672 uint64
+ x672, x671 = bits.Mul64(x6, arg1[0])
+ var x673 uint64
+ var x674 uint64
+ x673, x674 = bits.Add64(x672, x669, uint64(0x0))
+ var x675 uint64
+ var x676 uint64
+ x675, x676 = bits.Add64(x670, x667, uint64(p521Uint1(x674)))
+ var x677 uint64
+ var x678 uint64
+ x677, x678 = bits.Add64(x668, x665, uint64(p521Uint1(x676)))
+ var x679 uint64
+ var x680 uint64
+ x679, x680 = bits.Add64(x666, x663, uint64(p521Uint1(x678)))
+ var x681 uint64
+ var x682 uint64
+ x681, x682 = bits.Add64(x664, x661, uint64(p521Uint1(x680)))
+ var x683 uint64
+ var x684 uint64
+ x683, x684 = bits.Add64(x662, x659, uint64(p521Uint1(x682)))
+ var x685 uint64
+ var x686 uint64
+ x685, x686 = bits.Add64(x660, x657, uint64(p521Uint1(x684)))
+ var x687 uint64
+ var x688 uint64
+ x687, x688 = bits.Add64(x658, x655, uint64(p521Uint1(x686)))
+ x689 := (uint64(p521Uint1(x688)) + x656)
+ var x690 uint64
+ var x691 uint64
+ x690, x691 = bits.Add64(x636, x671, uint64(0x0))
+ var x692 uint64
+ var x693 uint64
+ x692, x693 = bits.Add64(x638, x673, uint64(p521Uint1(x691)))
+ var x694 uint64
+ var x695 uint64
+ x694, x695 = bits.Add64(x640, x675, uint64(p521Uint1(x693)))
+ var x696 uint64
+ var x697 uint64
+ x696, x697 = bits.Add64(x642, x677, uint64(p521Uint1(x695)))
+ var x698 uint64
+ var x699 uint64
+ x698, x699 = bits.Add64(x644, x679, uint64(p521Uint1(x697)))
+ var x700 uint64
+ var x701 uint64
+ x700, x701 = bits.Add64(x646, x681, uint64(p521Uint1(x699)))
+ var x702 uint64
+ var x703 uint64
+ x702, x703 = bits.Add64(x648, x683, uint64(p521Uint1(x701)))
+ var x704 uint64
+ var x705 uint64
+ x704, x705 = bits.Add64(x650, x685, uint64(p521Uint1(x703)))
+ var x706 uint64
+ var x707 uint64
+ x706, x707 = bits.Add64(x652, x687, uint64(p521Uint1(x705)))
+ var x708 uint64
+ var x709 uint64
+ x708, x709 = bits.Add64(x654, x689, uint64(p521Uint1(x707)))
+ var x710 uint64
+ var x711 uint64
+ x711, x710 = bits.Mul64(x690, 0x1ff)
+ var x712 uint64
+ var x713 uint64
+ x713, x712 = bits.Mul64(x690, 0xffffffffffffffff)
+ var x714 uint64
+ var x715 uint64
+ x715, x714 = bits.Mul64(x690, 0xffffffffffffffff)
+ var x716 uint64
+ var x717 uint64
+ x717, x716 = bits.Mul64(x690, 0xffffffffffffffff)
+ var x718 uint64
+ var x719 uint64
+ x719, x718 = bits.Mul64(x690, 0xffffffffffffffff)
+ var x720 uint64
+ var x721 uint64
+ x721, x720 = bits.Mul64(x690, 0xffffffffffffffff)
+ var x722 uint64
+ var x723 uint64
+ x723, x722 = bits.Mul64(x690, 0xffffffffffffffff)
+ var x724 uint64
+ var x725 uint64
+ x725, x724 = bits.Mul64(x690, 0xffffffffffffffff)
+ var x726 uint64
+ var x727 uint64
+ x727, x726 = bits.Mul64(x690, 0xffffffffffffffff)
+ var x728 uint64
+ var x729 uint64
+ x728, x729 = bits.Add64(x727, x724, uint64(0x0))
+ var x730 uint64
+ var x731 uint64
+ x730, x731 = bits.Add64(x725, x722, uint64(p521Uint1(x729)))
+ var x732 uint64
+ var x733 uint64
+ x732, x733 = bits.Add64(x723, x720, uint64(p521Uint1(x731)))
+ var x734 uint64
+ var x735 uint64
+ x734, x735 = bits.Add64(x721, x718, uint64(p521Uint1(x733)))
+ var x736 uint64
+ var x737 uint64
+ x736, x737 = bits.Add64(x719, x716, uint64(p521Uint1(x735)))
+ var x738 uint64
+ var x739 uint64
+ x738, x739 = bits.Add64(x717, x714, uint64(p521Uint1(x737)))
+ var x740 uint64
+ var x741 uint64
+ x740, x741 = bits.Add64(x715, x712, uint64(p521Uint1(x739)))
+ var x742 uint64
+ var x743 uint64
+ x742, x743 = bits.Add64(x713, x710, uint64(p521Uint1(x741)))
+ x744 := (uint64(p521Uint1(x743)) + x711)
+ var x746 uint64
+ _, x746 = bits.Add64(x690, x726, uint64(0x0))
+ var x747 uint64
+ var x748 uint64
+ x747, x748 = bits.Add64(x692, x728, uint64(p521Uint1(x746)))
+ var x749 uint64
+ var x750 uint64
+ x749, x750 = bits.Add64(x694, x730, uint64(p521Uint1(x748)))
+ var x751 uint64
+ var x752 uint64
+ x751, x752 = bits.Add64(x696, x732, uint64(p521Uint1(x750)))
+ var x753 uint64
+ var x754 uint64
+ x753, x754 = bits.Add64(x698, x734, uint64(p521Uint1(x752)))
+ var x755 uint64
+ var x756 uint64
+ x755, x756 = bits.Add64(x700, x736, uint64(p521Uint1(x754)))
+ var x757 uint64
+ var x758 uint64
+ x757, x758 = bits.Add64(x702, x738, uint64(p521Uint1(x756)))
+ var x759 uint64
+ var x760 uint64
+ x759, x760 = bits.Add64(x704, x740, uint64(p521Uint1(x758)))
+ var x761 uint64
+ var x762 uint64
+ x761, x762 = bits.Add64(x706, x742, uint64(p521Uint1(x760)))
+ var x763 uint64
+ var x764 uint64
+ x763, x764 = bits.Add64(x708, x744, uint64(p521Uint1(x762)))
+ x765 := (uint64(p521Uint1(x764)) + uint64(p521Uint1(x709)))
+ var x766 uint64
+ var x767 uint64
+ x767, x766 = bits.Mul64(x7, arg1[8])
+ var x768 uint64
+ var x769 uint64
+ x769, x768 = bits.Mul64(x7, arg1[7])
+ var x770 uint64
+ var x771 uint64
+ x771, x770 = bits.Mul64(x7, arg1[6])
+ var x772 uint64
+ var x773 uint64
+ x773, x772 = bits.Mul64(x7, arg1[5])
+ var x774 uint64
+ var x775 uint64
+ x775, x774 = bits.Mul64(x7, arg1[4])
+ var x776 uint64
+ var x777 uint64
+ x777, x776 = bits.Mul64(x7, arg1[3])
+ var x778 uint64
+ var x779 uint64
+ x779, x778 = bits.Mul64(x7, arg1[2])
+ var x780 uint64
+ var x781 uint64
+ x781, x780 = bits.Mul64(x7, arg1[1])
+ var x782 uint64
+ var x783 uint64
+ x783, x782 = bits.Mul64(x7, arg1[0])
+ var x784 uint64
+ var x785 uint64
+ x784, x785 = bits.Add64(x783, x780, uint64(0x0))
+ var x786 uint64
+ var x787 uint64
+ x786, x787 = bits.Add64(x781, x778, uint64(p521Uint1(x785)))
+ var x788 uint64
+ var x789 uint64
+ x788, x789 = bits.Add64(x779, x776, uint64(p521Uint1(x787)))
+ var x790 uint64
+ var x791 uint64
+ x790, x791 = bits.Add64(x777, x774, uint64(p521Uint1(x789)))
+ var x792 uint64
+ var x793 uint64
+ x792, x793 = bits.Add64(x775, x772, uint64(p521Uint1(x791)))
+ var x794 uint64
+ var x795 uint64
+ x794, x795 = bits.Add64(x773, x770, uint64(p521Uint1(x793)))
+ var x796 uint64
+ var x797 uint64
+ x796, x797 = bits.Add64(x771, x768, uint64(p521Uint1(x795)))
+ var x798 uint64
+ var x799 uint64
+ x798, x799 = bits.Add64(x769, x766, uint64(p521Uint1(x797)))
+ x800 := (uint64(p521Uint1(x799)) + x767)
+ var x801 uint64
+ var x802 uint64
+ x801, x802 = bits.Add64(x747, x782, uint64(0x0))
+ var x803 uint64
+ var x804 uint64
+ x803, x804 = bits.Add64(x749, x784, uint64(p521Uint1(x802)))
+ var x805 uint64
+ var x806 uint64
+ x805, x806 = bits.Add64(x751, x786, uint64(p521Uint1(x804)))
+ var x807 uint64
+ var x808 uint64
+ x807, x808 = bits.Add64(x753, x788, uint64(p521Uint1(x806)))
+ var x809 uint64
+ var x810 uint64
+ x809, x810 = bits.Add64(x755, x790, uint64(p521Uint1(x808)))
+ var x811 uint64
+ var x812 uint64
+ x811, x812 = bits.Add64(x757, x792, uint64(p521Uint1(x810)))
+ var x813 uint64
+ var x814 uint64
+ x813, x814 = bits.Add64(x759, x794, uint64(p521Uint1(x812)))
+ var x815 uint64
+ var x816 uint64
+ x815, x816 = bits.Add64(x761, x796, uint64(p521Uint1(x814)))
+ var x817 uint64
+ var x818 uint64
+ x817, x818 = bits.Add64(x763, x798, uint64(p521Uint1(x816)))
+ var x819 uint64
+ var x820 uint64
+ x819, x820 = bits.Add64(x765, x800, uint64(p521Uint1(x818)))
+ var x821 uint64
+ var x822 uint64
+ x822, x821 = bits.Mul64(x801, 0x1ff)
+ var x823 uint64
+ var x824 uint64
+ x824, x823 = bits.Mul64(x801, 0xffffffffffffffff)
+ var x825 uint64
+ var x826 uint64
+ x826, x825 = bits.Mul64(x801, 0xffffffffffffffff)
+ var x827 uint64
+ var x828 uint64
+ x828, x827 = bits.Mul64(x801, 0xffffffffffffffff)
+ var x829 uint64
+ var x830 uint64
+ x830, x829 = bits.Mul64(x801, 0xffffffffffffffff)
+ var x831 uint64
+ var x832 uint64
+ x832, x831 = bits.Mul64(x801, 0xffffffffffffffff)
+ var x833 uint64
+ var x834 uint64
+ x834, x833 = bits.Mul64(x801, 0xffffffffffffffff)
+ var x835 uint64
+ var x836 uint64
+ x836, x835 = bits.Mul64(x801, 0xffffffffffffffff)
+ var x837 uint64
+ var x838 uint64
+ x838, x837 = bits.Mul64(x801, 0xffffffffffffffff)
+ var x839 uint64
+ var x840 uint64
+ x839, x840 = bits.Add64(x838, x835, uint64(0x0))
+ var x841 uint64
+ var x842 uint64
+ x841, x842 = bits.Add64(x836, x833, uint64(p521Uint1(x840)))
+ var x843 uint64
+ var x844 uint64
+ x843, x844 = bits.Add64(x834, x831, uint64(p521Uint1(x842)))
+ var x845 uint64
+ var x846 uint64
+ x845, x846 = bits.Add64(x832, x829, uint64(p521Uint1(x844)))
+ var x847 uint64
+ var x848 uint64
+ x847, x848 = bits.Add64(x830, x827, uint64(p521Uint1(x846)))
+ var x849 uint64
+ var x850 uint64
+ x849, x850 = bits.Add64(x828, x825, uint64(p521Uint1(x848)))
+ var x851 uint64
+ var x852 uint64
+ x851, x852 = bits.Add64(x826, x823, uint64(p521Uint1(x850)))
+ var x853 uint64
+ var x854 uint64
+ x853, x854 = bits.Add64(x824, x821, uint64(p521Uint1(x852)))
+ x855 := (uint64(p521Uint1(x854)) + x822)
+ var x857 uint64
+ _, x857 = bits.Add64(x801, x837, uint64(0x0))
+ var x858 uint64
+ var x859 uint64
+ x858, x859 = bits.Add64(x803, x839, uint64(p521Uint1(x857)))
+ var x860 uint64
+ var x861 uint64
+ x860, x861 = bits.Add64(x805, x841, uint64(p521Uint1(x859)))
+ var x862 uint64
+ var x863 uint64
+ x862, x863 = bits.Add64(x807, x843, uint64(p521Uint1(x861)))
+ var x864 uint64
+ var x865 uint64
+ x864, x865 = bits.Add64(x809, x845, uint64(p521Uint1(x863)))
+ var x866 uint64
+ var x867 uint64
+ x866, x867 = bits.Add64(x811, x847, uint64(p521Uint1(x865)))
+ var x868 uint64
+ var x869 uint64
+ x868, x869 = bits.Add64(x813, x849, uint64(p521Uint1(x867)))
+ var x870 uint64
+ var x871 uint64
+ x870, x871 = bits.Add64(x815, x851, uint64(p521Uint1(x869)))
+ var x872 uint64
+ var x873 uint64
+ x872, x873 = bits.Add64(x817, x853, uint64(p521Uint1(x871)))
+ var x874 uint64
+ var x875 uint64
+ x874, x875 = bits.Add64(x819, x855, uint64(p521Uint1(x873)))
+ x876 := (uint64(p521Uint1(x875)) + uint64(p521Uint1(x820)))
+ var x877 uint64
+ var x878 uint64
+ x878, x877 = bits.Mul64(x8, arg1[8])
+ var x879 uint64
+ var x880 uint64
+ x880, x879 = bits.Mul64(x8, arg1[7])
+ var x881 uint64
+ var x882 uint64
+ x882, x881 = bits.Mul64(x8, arg1[6])
+ var x883 uint64
+ var x884 uint64
+ x884, x883 = bits.Mul64(x8, arg1[5])
+ var x885 uint64
+ var x886 uint64
+ x886, x885 = bits.Mul64(x8, arg1[4])
+ var x887 uint64
+ var x888 uint64
+ x888, x887 = bits.Mul64(x8, arg1[3])
+ var x889 uint64
+ var x890 uint64
+ x890, x889 = bits.Mul64(x8, arg1[2])
+ var x891 uint64
+ var x892 uint64
+ x892, x891 = bits.Mul64(x8, arg1[1])
+ var x893 uint64
+ var x894 uint64
+ x894, x893 = bits.Mul64(x8, arg1[0])
+ var x895 uint64
+ var x896 uint64
+ x895, x896 = bits.Add64(x894, x891, uint64(0x0))
+ var x897 uint64
+ var x898 uint64
+ x897, x898 = bits.Add64(x892, x889, uint64(p521Uint1(x896)))
+ var x899 uint64
+ var x900 uint64
+ x899, x900 = bits.Add64(x890, x887, uint64(p521Uint1(x898)))
+ var x901 uint64
+ var x902 uint64
+ x901, x902 = bits.Add64(x888, x885, uint64(p521Uint1(x900)))
+ var x903 uint64
+ var x904 uint64
+ x903, x904 = bits.Add64(x886, x883, uint64(p521Uint1(x902)))
+ var x905 uint64
+ var x906 uint64
+ x905, x906 = bits.Add64(x884, x881, uint64(p521Uint1(x904)))
+ var x907 uint64
+ var x908 uint64
+ x907, x908 = bits.Add64(x882, x879, uint64(p521Uint1(x906)))
+ var x909 uint64
+ var x910 uint64
+ x909, x910 = bits.Add64(x880, x877, uint64(p521Uint1(x908)))
+ x911 := (uint64(p521Uint1(x910)) + x878)
+ var x912 uint64
+ var x913 uint64
+ x912, x913 = bits.Add64(x858, x893, uint64(0x0))
+ var x914 uint64
+ var x915 uint64
+ x914, x915 = bits.Add64(x860, x895, uint64(p521Uint1(x913)))
+ var x916 uint64
+ var x917 uint64
+ x916, x917 = bits.Add64(x862, x897, uint64(p521Uint1(x915)))
+ var x918 uint64
+ var x919 uint64
+ x918, x919 = bits.Add64(x864, x899, uint64(p521Uint1(x917)))
+ var x920 uint64
+ var x921 uint64
+ x920, x921 = bits.Add64(x866, x901, uint64(p521Uint1(x919)))
+ var x922 uint64
+ var x923 uint64
+ x922, x923 = bits.Add64(x868, x903, uint64(p521Uint1(x921)))
+ var x924 uint64
+ var x925 uint64
+ x924, x925 = bits.Add64(x870, x905, uint64(p521Uint1(x923)))
+ var x926 uint64
+ var x927 uint64
+ x926, x927 = bits.Add64(x872, x907, uint64(p521Uint1(x925)))
+ var x928 uint64
+ var x929 uint64
+ x928, x929 = bits.Add64(x874, x909, uint64(p521Uint1(x927)))
+ var x930 uint64
+ var x931 uint64
+ x930, x931 = bits.Add64(x876, x911, uint64(p521Uint1(x929)))
+ var x932 uint64
+ var x933 uint64
+ x933, x932 = bits.Mul64(x912, 0x1ff)
+ var x934 uint64
+ var x935 uint64
+ x935, x934 = bits.Mul64(x912, 0xffffffffffffffff)
+ var x936 uint64
+ var x937 uint64
+ x937, x936 = bits.Mul64(x912, 0xffffffffffffffff)
+ var x938 uint64
+ var x939 uint64
+ x939, x938 = bits.Mul64(x912, 0xffffffffffffffff)
+ var x940 uint64
+ var x941 uint64
+ x941, x940 = bits.Mul64(x912, 0xffffffffffffffff)
+ var x942 uint64
+ var x943 uint64
+ x943, x942 = bits.Mul64(x912, 0xffffffffffffffff)
+ var x944 uint64
+ var x945 uint64
+ x945, x944 = bits.Mul64(x912, 0xffffffffffffffff)
+ var x946 uint64
+ var x947 uint64
+ x947, x946 = bits.Mul64(x912, 0xffffffffffffffff)
+ var x948 uint64
+ var x949 uint64
+ x949, x948 = bits.Mul64(x912, 0xffffffffffffffff)
+ var x950 uint64
+ var x951 uint64
+ x950, x951 = bits.Add64(x949, x946, uint64(0x0))
+ var x952 uint64
+ var x953 uint64
+ x952, x953 = bits.Add64(x947, x944, uint64(p521Uint1(x951)))
+ var x954 uint64
+ var x955 uint64
+ x954, x955 = bits.Add64(x945, x942, uint64(p521Uint1(x953)))
+ var x956 uint64
+ var x957 uint64
+ x956, x957 = bits.Add64(x943, x940, uint64(p521Uint1(x955)))
+ var x958 uint64
+ var x959 uint64
+ x958, x959 = bits.Add64(x941, x938, uint64(p521Uint1(x957)))
+ var x960 uint64
+ var x961 uint64
+ x960, x961 = bits.Add64(x939, x936, uint64(p521Uint1(x959)))
+ var x962 uint64
+ var x963 uint64
+ x962, x963 = bits.Add64(x937, x934, uint64(p521Uint1(x961)))
+ var x964 uint64
+ var x965 uint64
+ x964, x965 = bits.Add64(x935, x932, uint64(p521Uint1(x963)))
+ x966 := (uint64(p521Uint1(x965)) + x933)
+ var x968 uint64
+ _, x968 = bits.Add64(x912, x948, uint64(0x0))
+ var x969 uint64
+ var x970 uint64
+ x969, x970 = bits.Add64(x914, x950, uint64(p521Uint1(x968)))
+ var x971 uint64
+ var x972 uint64
+ x971, x972 = bits.Add64(x916, x952, uint64(p521Uint1(x970)))
+ var x973 uint64
+ var x974 uint64
+ x973, x974 = bits.Add64(x918, x954, uint64(p521Uint1(x972)))
+ var x975 uint64
+ var x976 uint64
+ x975, x976 = bits.Add64(x920, x956, uint64(p521Uint1(x974)))
+ var x977 uint64
+ var x978 uint64
+ x977, x978 = bits.Add64(x922, x958, uint64(p521Uint1(x976)))
+ var x979 uint64
+ var x980 uint64
+ x979, x980 = bits.Add64(x924, x960, uint64(p521Uint1(x978)))
+ var x981 uint64
+ var x982 uint64
+ x981, x982 = bits.Add64(x926, x962, uint64(p521Uint1(x980)))
+ var x983 uint64
+ var x984 uint64
+ x983, x984 = bits.Add64(x928, x964, uint64(p521Uint1(x982)))
+ var x985 uint64
+ var x986 uint64
+ x985, x986 = bits.Add64(x930, x966, uint64(p521Uint1(x984)))
+ x987 := (uint64(p521Uint1(x986)) + uint64(p521Uint1(x931)))
+ var x988 uint64
+ var x989 uint64
+ x988, x989 = bits.Sub64(x969, 0xffffffffffffffff, uint64(0x0))
+ var x990 uint64
+ var x991 uint64
+ x990, x991 = bits.Sub64(x971, 0xffffffffffffffff, uint64(p521Uint1(x989)))
+ var x992 uint64
+ var x993 uint64
+ x992, x993 = bits.Sub64(x973, 0xffffffffffffffff, uint64(p521Uint1(x991)))
+ var x994 uint64
+ var x995 uint64
+ x994, x995 = bits.Sub64(x975, 0xffffffffffffffff, uint64(p521Uint1(x993)))
+ var x996 uint64
+ var x997 uint64
+ x996, x997 = bits.Sub64(x977, 0xffffffffffffffff, uint64(p521Uint1(x995)))
+ var x998 uint64
+ var x999 uint64
+ x998, x999 = bits.Sub64(x979, 0xffffffffffffffff, uint64(p521Uint1(x997)))
+ var x1000 uint64
+ var x1001 uint64
+ x1000, x1001 = bits.Sub64(x981, 0xffffffffffffffff, uint64(p521Uint1(x999)))
+ var x1002 uint64
+ var x1003 uint64
+ x1002, x1003 = bits.Sub64(x983, 0xffffffffffffffff, uint64(p521Uint1(x1001)))
+ var x1004 uint64
+ var x1005 uint64
+ x1004, x1005 = bits.Sub64(x985, 0x1ff, uint64(p521Uint1(x1003)))
+ var x1007 uint64
+ _, x1007 = bits.Sub64(x987, uint64(0x0), uint64(p521Uint1(x1005)))
+ var x1008 uint64
+ p521CmovznzU64(&x1008, p521Uint1(x1007), x988, x969)
+ var x1009 uint64
+ p521CmovznzU64(&x1009, p521Uint1(x1007), x990, x971)
+ var x1010 uint64
+ p521CmovznzU64(&x1010, p521Uint1(x1007), x992, x973)
+ var x1011 uint64
+ p521CmovznzU64(&x1011, p521Uint1(x1007), x994, x975)
+ var x1012 uint64
+ p521CmovznzU64(&x1012, p521Uint1(x1007), x996, x977)
+ var x1013 uint64
+ p521CmovznzU64(&x1013, p521Uint1(x1007), x998, x979)
+ var x1014 uint64
+ p521CmovznzU64(&x1014, p521Uint1(x1007), x1000, x981)
+ var x1015 uint64
+ p521CmovznzU64(&x1015, p521Uint1(x1007), x1002, x983)
+ var x1016 uint64
+ p521CmovznzU64(&x1016, p521Uint1(x1007), x1004, x985)
+ out1[0] = x1008
+ out1[1] = x1009
+ out1[2] = x1010
+ out1[3] = x1011
+ out1[4] = x1012
+ out1[5] = x1013
+ out1[6] = x1014
+ out1[7] = x1015
+ out1[8] = x1016
+}
+
+// p521Add adds two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) + eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func p521Add(out1 *p521MontgomeryDomainFieldElement, arg1 *p521MontgomeryDomainFieldElement, arg2 *p521MontgomeryDomainFieldElement) {
+ var x1 uint64
+ var x2 uint64
+ x1, x2 = bits.Add64(arg1[0], arg2[0], uint64(0x0))
+ var x3 uint64
+ var x4 uint64
+ x3, x4 = bits.Add64(arg1[1], arg2[1], uint64(p521Uint1(x2)))
+ var x5 uint64
+ var x6 uint64
+ x5, x6 = bits.Add64(arg1[2], arg2[2], uint64(p521Uint1(x4)))
+ var x7 uint64
+ var x8 uint64
+ x7, x8 = bits.Add64(arg1[3], arg2[3], uint64(p521Uint1(x6)))
+ var x9 uint64
+ var x10 uint64
+ x9, x10 = bits.Add64(arg1[4], arg2[4], uint64(p521Uint1(x8)))
+ var x11 uint64
+ var x12 uint64
+ x11, x12 = bits.Add64(arg1[5], arg2[5], uint64(p521Uint1(x10)))
+ var x13 uint64
+ var x14 uint64
+ x13, x14 = bits.Add64(arg1[6], arg2[6], uint64(p521Uint1(x12)))
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Add64(arg1[7], arg2[7], uint64(p521Uint1(x14)))
+ var x17 uint64
+ var x18 uint64
+ x17, x18 = bits.Add64(arg1[8], arg2[8], uint64(p521Uint1(x16)))
+ var x19 uint64
+ var x20 uint64
+ x19, x20 = bits.Sub64(x1, 0xffffffffffffffff, uint64(0x0))
+ var x21 uint64
+ var x22 uint64
+ x21, x22 = bits.Sub64(x3, 0xffffffffffffffff, uint64(p521Uint1(x20)))
+ var x23 uint64
+ var x24 uint64
+ x23, x24 = bits.Sub64(x5, 0xffffffffffffffff, uint64(p521Uint1(x22)))
+ var x25 uint64
+ var x26 uint64
+ x25, x26 = bits.Sub64(x7, 0xffffffffffffffff, uint64(p521Uint1(x24)))
+ var x27 uint64
+ var x28 uint64
+ x27, x28 = bits.Sub64(x9, 0xffffffffffffffff, uint64(p521Uint1(x26)))
+ var x29 uint64
+ var x30 uint64
+ x29, x30 = bits.Sub64(x11, 0xffffffffffffffff, uint64(p521Uint1(x28)))
+ var x31 uint64
+ var x32 uint64
+ x31, x32 = bits.Sub64(x13, 0xffffffffffffffff, uint64(p521Uint1(x30)))
+ var x33 uint64
+ var x34 uint64
+ x33, x34 = bits.Sub64(x15, 0xffffffffffffffff, uint64(p521Uint1(x32)))
+ var x35 uint64
+ var x36 uint64
+ x35, x36 = bits.Sub64(x17, 0x1ff, uint64(p521Uint1(x34)))
+ var x38 uint64
+ _, x38 = bits.Sub64(uint64(p521Uint1(x18)), uint64(0x0), uint64(p521Uint1(x36)))
+ var x39 uint64
+ p521CmovznzU64(&x39, p521Uint1(x38), x19, x1)
+ var x40 uint64
+ p521CmovznzU64(&x40, p521Uint1(x38), x21, x3)
+ var x41 uint64
+ p521CmovznzU64(&x41, p521Uint1(x38), x23, x5)
+ var x42 uint64
+ p521CmovznzU64(&x42, p521Uint1(x38), x25, x7)
+ var x43 uint64
+ p521CmovznzU64(&x43, p521Uint1(x38), x27, x9)
+ var x44 uint64
+ p521CmovznzU64(&x44, p521Uint1(x38), x29, x11)
+ var x45 uint64
+ p521CmovznzU64(&x45, p521Uint1(x38), x31, x13)
+ var x46 uint64
+ p521CmovznzU64(&x46, p521Uint1(x38), x33, x15)
+ var x47 uint64
+ p521CmovznzU64(&x47, p521Uint1(x38), x35, x17)
+ out1[0] = x39
+ out1[1] = x40
+ out1[2] = x41
+ out1[3] = x42
+ out1[4] = x43
+ out1[5] = x44
+ out1[6] = x45
+ out1[7] = x46
+ out1[8] = x47
+}
+
+// p521Sub subtracts two field elements in the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+// 0 ≤ eval arg2 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = (eval (from_montgomery arg1) - eval (from_montgomery arg2)) mod m
+// 0 ≤ eval out1 < m
+func p521Sub(out1 *p521MontgomeryDomainFieldElement, arg1 *p521MontgomeryDomainFieldElement, arg2 *p521MontgomeryDomainFieldElement) {
+ var x1 uint64
+ var x2 uint64
+ x1, x2 = bits.Sub64(arg1[0], arg2[0], uint64(0x0))
+ var x3 uint64
+ var x4 uint64
+ x3, x4 = bits.Sub64(arg1[1], arg2[1], uint64(p521Uint1(x2)))
+ var x5 uint64
+ var x6 uint64
+ x5, x6 = bits.Sub64(arg1[2], arg2[2], uint64(p521Uint1(x4)))
+ var x7 uint64
+ var x8 uint64
+ x7, x8 = bits.Sub64(arg1[3], arg2[3], uint64(p521Uint1(x6)))
+ var x9 uint64
+ var x10 uint64
+ x9, x10 = bits.Sub64(arg1[4], arg2[4], uint64(p521Uint1(x8)))
+ var x11 uint64
+ var x12 uint64
+ x11, x12 = bits.Sub64(arg1[5], arg2[5], uint64(p521Uint1(x10)))
+ var x13 uint64
+ var x14 uint64
+ x13, x14 = bits.Sub64(arg1[6], arg2[6], uint64(p521Uint1(x12)))
+ var x15 uint64
+ var x16 uint64
+ x15, x16 = bits.Sub64(arg1[7], arg2[7], uint64(p521Uint1(x14)))
+ var x17 uint64
+ var x18 uint64
+ x17, x18 = bits.Sub64(arg1[8], arg2[8], uint64(p521Uint1(x16)))
+ var x19 uint64
+ p521CmovznzU64(&x19, p521Uint1(x18), uint64(0x0), 0xffffffffffffffff)
+ var x20 uint64
+ var x21 uint64
+ x20, x21 = bits.Add64(x1, x19, uint64(0x0))
+ var x22 uint64
+ var x23 uint64
+ x22, x23 = bits.Add64(x3, x19, uint64(p521Uint1(x21)))
+ var x24 uint64
+ var x25 uint64
+ x24, x25 = bits.Add64(x5, x19, uint64(p521Uint1(x23)))
+ var x26 uint64
+ var x27 uint64
+ x26, x27 = bits.Add64(x7, x19, uint64(p521Uint1(x25)))
+ var x28 uint64
+ var x29 uint64
+ x28, x29 = bits.Add64(x9, x19, uint64(p521Uint1(x27)))
+ var x30 uint64
+ var x31 uint64
+ x30, x31 = bits.Add64(x11, x19, uint64(p521Uint1(x29)))
+ var x32 uint64
+ var x33 uint64
+ x32, x33 = bits.Add64(x13, x19, uint64(p521Uint1(x31)))
+ var x34 uint64
+ var x35 uint64
+ x34, x35 = bits.Add64(x15, x19, uint64(p521Uint1(x33)))
+ var x36 uint64
+ x36, _ = bits.Add64(x17, (x19 & 0x1ff), uint64(p521Uint1(x35)))
+ out1[0] = x20
+ out1[1] = x22
+ out1[2] = x24
+ out1[3] = x26
+ out1[4] = x28
+ out1[5] = x30
+ out1[6] = x32
+ out1[7] = x34
+ out1[8] = x36
+}
+
+// p521SetOne returns the field element one in the Montgomery domain.
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = 1 mod m
+// 0 ≤ eval out1 < m
+func p521SetOne(out1 *p521MontgomeryDomainFieldElement) {
+ out1[0] = 0x80000000000000
+ out1[1] = uint64(0x0)
+ out1[2] = uint64(0x0)
+ out1[3] = uint64(0x0)
+ out1[4] = uint64(0x0)
+ out1[5] = uint64(0x0)
+ out1[6] = uint64(0x0)
+ out1[7] = uint64(0x0)
+ out1[8] = uint64(0x0)
+}
+
+// p521FromMontgomery translates a field element out of the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval out1 mod m = (eval arg1 * ((2^64)⁻¹ mod m)^9) mod m
+// 0 ≤ eval out1 < m
+func p521FromMontgomery(out1 *p521NonMontgomeryDomainFieldElement, arg1 *p521MontgomeryDomainFieldElement) {
+ x1 := arg1[0]
+ var x2 uint64
+ var x3 uint64
+ x3, x2 = bits.Mul64(x1, 0x1ff)
+ var x4 uint64
+ var x5 uint64
+ x5, x4 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x6 uint64
+ var x7 uint64
+ x7, x6 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x8 uint64
+ var x9 uint64
+ x9, x8 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x10 uint64
+ var x11 uint64
+ x11, x10 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x12 uint64
+ var x13 uint64
+ x13, x12 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x14 uint64
+ var x15 uint64
+ x15, x14 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x16 uint64
+ var x17 uint64
+ x17, x16 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x18 uint64
+ var x19 uint64
+ x19, x18 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x20 uint64
+ var x21 uint64
+ x20, x21 = bits.Add64(x19, x16, uint64(0x0))
+ var x22 uint64
+ var x23 uint64
+ x22, x23 = bits.Add64(x17, x14, uint64(p521Uint1(x21)))
+ var x24 uint64
+ var x25 uint64
+ x24, x25 = bits.Add64(x15, x12, uint64(p521Uint1(x23)))
+ var x26 uint64
+ var x27 uint64
+ x26, x27 = bits.Add64(x13, x10, uint64(p521Uint1(x25)))
+ var x28 uint64
+ var x29 uint64
+ x28, x29 = bits.Add64(x11, x8, uint64(p521Uint1(x27)))
+ var x30 uint64
+ var x31 uint64
+ x30, x31 = bits.Add64(x9, x6, uint64(p521Uint1(x29)))
+ var x32 uint64
+ var x33 uint64
+ x32, x33 = bits.Add64(x7, x4, uint64(p521Uint1(x31)))
+ var x34 uint64
+ var x35 uint64
+ x34, x35 = bits.Add64(x5, x2, uint64(p521Uint1(x33)))
+ var x37 uint64
+ _, x37 = bits.Add64(x1, x18, uint64(0x0))
+ var x38 uint64
+ var x39 uint64
+ x38, x39 = bits.Add64(uint64(0x0), x20, uint64(p521Uint1(x37)))
+ var x40 uint64
+ var x41 uint64
+ x40, x41 = bits.Add64(uint64(0x0), x22, uint64(p521Uint1(x39)))
+ var x42 uint64
+ var x43 uint64
+ x42, x43 = bits.Add64(uint64(0x0), x24, uint64(p521Uint1(x41)))
+ var x44 uint64
+ var x45 uint64
+ x44, x45 = bits.Add64(uint64(0x0), x26, uint64(p521Uint1(x43)))
+ var x46 uint64
+ var x47 uint64
+ x46, x47 = bits.Add64(uint64(0x0), x28, uint64(p521Uint1(x45)))
+ var x48 uint64
+ var x49 uint64
+ x48, x49 = bits.Add64(uint64(0x0), x30, uint64(p521Uint1(x47)))
+ var x50 uint64
+ var x51 uint64
+ x50, x51 = bits.Add64(uint64(0x0), x32, uint64(p521Uint1(x49)))
+ var x52 uint64
+ var x53 uint64
+ x52, x53 = bits.Add64(uint64(0x0), x34, uint64(p521Uint1(x51)))
+ var x54 uint64
+ var x55 uint64
+ x54, x55 = bits.Add64(x38, arg1[1], uint64(0x0))
+ var x56 uint64
+ var x57 uint64
+ x56, x57 = bits.Add64(x40, uint64(0x0), uint64(p521Uint1(x55)))
+ var x58 uint64
+ var x59 uint64
+ x58, x59 = bits.Add64(x42, uint64(0x0), uint64(p521Uint1(x57)))
+ var x60 uint64
+ var x61 uint64
+ x60, x61 = bits.Add64(x44, uint64(0x0), uint64(p521Uint1(x59)))
+ var x62 uint64
+ var x63 uint64
+ x62, x63 = bits.Add64(x46, uint64(0x0), uint64(p521Uint1(x61)))
+ var x64 uint64
+ var x65 uint64
+ x64, x65 = bits.Add64(x48, uint64(0x0), uint64(p521Uint1(x63)))
+ var x66 uint64
+ var x67 uint64
+ x66, x67 = bits.Add64(x50, uint64(0x0), uint64(p521Uint1(x65)))
+ var x68 uint64
+ var x69 uint64
+ x68, x69 = bits.Add64(x52, uint64(0x0), uint64(p521Uint1(x67)))
+ var x70 uint64
+ var x71 uint64
+ x71, x70 = bits.Mul64(x54, 0x1ff)
+ var x72 uint64
+ var x73 uint64
+ x73, x72 = bits.Mul64(x54, 0xffffffffffffffff)
+ var x74 uint64
+ var x75 uint64
+ x75, x74 = bits.Mul64(x54, 0xffffffffffffffff)
+ var x76 uint64
+ var x77 uint64
+ x77, x76 = bits.Mul64(x54, 0xffffffffffffffff)
+ var x78 uint64
+ var x79 uint64
+ x79, x78 = bits.Mul64(x54, 0xffffffffffffffff)
+ var x80 uint64
+ var x81 uint64
+ x81, x80 = bits.Mul64(x54, 0xffffffffffffffff)
+ var x82 uint64
+ var x83 uint64
+ x83, x82 = bits.Mul64(x54, 0xffffffffffffffff)
+ var x84 uint64
+ var x85 uint64
+ x85, x84 = bits.Mul64(x54, 0xffffffffffffffff)
+ var x86 uint64
+ var x87 uint64
+ x87, x86 = bits.Mul64(x54, 0xffffffffffffffff)
+ var x88 uint64
+ var x89 uint64
+ x88, x89 = bits.Add64(x87, x84, uint64(0x0))
+ var x90 uint64
+ var x91 uint64
+ x90, x91 = bits.Add64(x85, x82, uint64(p521Uint1(x89)))
+ var x92 uint64
+ var x93 uint64
+ x92, x93 = bits.Add64(x83, x80, uint64(p521Uint1(x91)))
+ var x94 uint64
+ var x95 uint64
+ x94, x95 = bits.Add64(x81, x78, uint64(p521Uint1(x93)))
+ var x96 uint64
+ var x97 uint64
+ x96, x97 = bits.Add64(x79, x76, uint64(p521Uint1(x95)))
+ var x98 uint64
+ var x99 uint64
+ x98, x99 = bits.Add64(x77, x74, uint64(p521Uint1(x97)))
+ var x100 uint64
+ var x101 uint64
+ x100, x101 = bits.Add64(x75, x72, uint64(p521Uint1(x99)))
+ var x102 uint64
+ var x103 uint64
+ x102, x103 = bits.Add64(x73, x70, uint64(p521Uint1(x101)))
+ var x105 uint64
+ _, x105 = bits.Add64(x54, x86, uint64(0x0))
+ var x106 uint64
+ var x107 uint64
+ x106, x107 = bits.Add64(x56, x88, uint64(p521Uint1(x105)))
+ var x108 uint64
+ var x109 uint64
+ x108, x109 = bits.Add64(x58, x90, uint64(p521Uint1(x107)))
+ var x110 uint64
+ var x111 uint64
+ x110, x111 = bits.Add64(x60, x92, uint64(p521Uint1(x109)))
+ var x112 uint64
+ var x113 uint64
+ x112, x113 = bits.Add64(x62, x94, uint64(p521Uint1(x111)))
+ var x114 uint64
+ var x115 uint64
+ x114, x115 = bits.Add64(x64, x96, uint64(p521Uint1(x113)))
+ var x116 uint64
+ var x117 uint64
+ x116, x117 = bits.Add64(x66, x98, uint64(p521Uint1(x115)))
+ var x118 uint64
+ var x119 uint64
+ x118, x119 = bits.Add64(x68, x100, uint64(p521Uint1(x117)))
+ var x120 uint64
+ var x121 uint64
+ x120, x121 = bits.Add64((uint64(p521Uint1(x69)) + (uint64(p521Uint1(x53)) + (uint64(p521Uint1(x35)) + x3))), x102, uint64(p521Uint1(x119)))
+ var x122 uint64
+ var x123 uint64
+ x122, x123 = bits.Add64(x106, arg1[2], uint64(0x0))
+ var x124 uint64
+ var x125 uint64
+ x124, x125 = bits.Add64(x108, uint64(0x0), uint64(p521Uint1(x123)))
+ var x126 uint64
+ var x127 uint64
+ x126, x127 = bits.Add64(x110, uint64(0x0), uint64(p521Uint1(x125)))
+ var x128 uint64
+ var x129 uint64
+ x128, x129 = bits.Add64(x112, uint64(0x0), uint64(p521Uint1(x127)))
+ var x130 uint64
+ var x131 uint64
+ x130, x131 = bits.Add64(x114, uint64(0x0), uint64(p521Uint1(x129)))
+ var x132 uint64
+ var x133 uint64
+ x132, x133 = bits.Add64(x116, uint64(0x0), uint64(p521Uint1(x131)))
+ var x134 uint64
+ var x135 uint64
+ x134, x135 = bits.Add64(x118, uint64(0x0), uint64(p521Uint1(x133)))
+ var x136 uint64
+ var x137 uint64
+ x136, x137 = bits.Add64(x120, uint64(0x0), uint64(p521Uint1(x135)))
+ var x138 uint64
+ var x139 uint64
+ x139, x138 = bits.Mul64(x122, 0x1ff)
+ var x140 uint64
+ var x141 uint64
+ x141, x140 = bits.Mul64(x122, 0xffffffffffffffff)
+ var x142 uint64
+ var x143 uint64
+ x143, x142 = bits.Mul64(x122, 0xffffffffffffffff)
+ var x144 uint64
+ var x145 uint64
+ x145, x144 = bits.Mul64(x122, 0xffffffffffffffff)
+ var x146 uint64
+ var x147 uint64
+ x147, x146 = bits.Mul64(x122, 0xffffffffffffffff)
+ var x148 uint64
+ var x149 uint64
+ x149, x148 = bits.Mul64(x122, 0xffffffffffffffff)
+ var x150 uint64
+ var x151 uint64
+ x151, x150 = bits.Mul64(x122, 0xffffffffffffffff)
+ var x152 uint64
+ var x153 uint64
+ x153, x152 = bits.Mul64(x122, 0xffffffffffffffff)
+ var x154 uint64
+ var x155 uint64
+ x155, x154 = bits.Mul64(x122, 0xffffffffffffffff)
+ var x156 uint64
+ var x157 uint64
+ x156, x157 = bits.Add64(x155, x152, uint64(0x0))
+ var x158 uint64
+ var x159 uint64
+ x158, x159 = bits.Add64(x153, x150, uint64(p521Uint1(x157)))
+ var x160 uint64
+ var x161 uint64
+ x160, x161 = bits.Add64(x151, x148, uint64(p521Uint1(x159)))
+ var x162 uint64
+ var x163 uint64
+ x162, x163 = bits.Add64(x149, x146, uint64(p521Uint1(x161)))
+ var x164 uint64
+ var x165 uint64
+ x164, x165 = bits.Add64(x147, x144, uint64(p521Uint1(x163)))
+ var x166 uint64
+ var x167 uint64
+ x166, x167 = bits.Add64(x145, x142, uint64(p521Uint1(x165)))
+ var x168 uint64
+ var x169 uint64
+ x168, x169 = bits.Add64(x143, x140, uint64(p521Uint1(x167)))
+ var x170 uint64
+ var x171 uint64
+ x170, x171 = bits.Add64(x141, x138, uint64(p521Uint1(x169)))
+ var x173 uint64
+ _, x173 = bits.Add64(x122, x154, uint64(0x0))
+ var x174 uint64
+ var x175 uint64
+ x174, x175 = bits.Add64(x124, x156, uint64(p521Uint1(x173)))
+ var x176 uint64
+ var x177 uint64
+ x176, x177 = bits.Add64(x126, x158, uint64(p521Uint1(x175)))
+ var x178 uint64
+ var x179 uint64
+ x178, x179 = bits.Add64(x128, x160, uint64(p521Uint1(x177)))
+ var x180 uint64
+ var x181 uint64
+ x180, x181 = bits.Add64(x130, x162, uint64(p521Uint1(x179)))
+ var x182 uint64
+ var x183 uint64
+ x182, x183 = bits.Add64(x132, x164, uint64(p521Uint1(x181)))
+ var x184 uint64
+ var x185 uint64
+ x184, x185 = bits.Add64(x134, x166, uint64(p521Uint1(x183)))
+ var x186 uint64
+ var x187 uint64
+ x186, x187 = bits.Add64(x136, x168, uint64(p521Uint1(x185)))
+ var x188 uint64
+ var x189 uint64
+ x188, x189 = bits.Add64((uint64(p521Uint1(x137)) + (uint64(p521Uint1(x121)) + (uint64(p521Uint1(x103)) + x71))), x170, uint64(p521Uint1(x187)))
+ var x190 uint64
+ var x191 uint64
+ x190, x191 = bits.Add64(x174, arg1[3], uint64(0x0))
+ var x192 uint64
+ var x193 uint64
+ x192, x193 = bits.Add64(x176, uint64(0x0), uint64(p521Uint1(x191)))
+ var x194 uint64
+ var x195 uint64
+ x194, x195 = bits.Add64(x178, uint64(0x0), uint64(p521Uint1(x193)))
+ var x196 uint64
+ var x197 uint64
+ x196, x197 = bits.Add64(x180, uint64(0x0), uint64(p521Uint1(x195)))
+ var x198 uint64
+ var x199 uint64
+ x198, x199 = bits.Add64(x182, uint64(0x0), uint64(p521Uint1(x197)))
+ var x200 uint64
+ var x201 uint64
+ x200, x201 = bits.Add64(x184, uint64(0x0), uint64(p521Uint1(x199)))
+ var x202 uint64
+ var x203 uint64
+ x202, x203 = bits.Add64(x186, uint64(0x0), uint64(p521Uint1(x201)))
+ var x204 uint64
+ var x205 uint64
+ x204, x205 = bits.Add64(x188, uint64(0x0), uint64(p521Uint1(x203)))
+ var x206 uint64
+ var x207 uint64
+ x207, x206 = bits.Mul64(x190, 0x1ff)
+ var x208 uint64
+ var x209 uint64
+ x209, x208 = bits.Mul64(x190, 0xffffffffffffffff)
+ var x210 uint64
+ var x211 uint64
+ x211, x210 = bits.Mul64(x190, 0xffffffffffffffff)
+ var x212 uint64
+ var x213 uint64
+ x213, x212 = bits.Mul64(x190, 0xffffffffffffffff)
+ var x214 uint64
+ var x215 uint64
+ x215, x214 = bits.Mul64(x190, 0xffffffffffffffff)
+ var x216 uint64
+ var x217 uint64
+ x217, x216 = bits.Mul64(x190, 0xffffffffffffffff)
+ var x218 uint64
+ var x219 uint64
+ x219, x218 = bits.Mul64(x190, 0xffffffffffffffff)
+ var x220 uint64
+ var x221 uint64
+ x221, x220 = bits.Mul64(x190, 0xffffffffffffffff)
+ var x222 uint64
+ var x223 uint64
+ x223, x222 = bits.Mul64(x190, 0xffffffffffffffff)
+ var x224 uint64
+ var x225 uint64
+ x224, x225 = bits.Add64(x223, x220, uint64(0x0))
+ var x226 uint64
+ var x227 uint64
+ x226, x227 = bits.Add64(x221, x218, uint64(p521Uint1(x225)))
+ var x228 uint64
+ var x229 uint64
+ x228, x229 = bits.Add64(x219, x216, uint64(p521Uint1(x227)))
+ var x230 uint64
+ var x231 uint64
+ x230, x231 = bits.Add64(x217, x214, uint64(p521Uint1(x229)))
+ var x232 uint64
+ var x233 uint64
+ x232, x233 = bits.Add64(x215, x212, uint64(p521Uint1(x231)))
+ var x234 uint64
+ var x235 uint64
+ x234, x235 = bits.Add64(x213, x210, uint64(p521Uint1(x233)))
+ var x236 uint64
+ var x237 uint64
+ x236, x237 = bits.Add64(x211, x208, uint64(p521Uint1(x235)))
+ var x238 uint64
+ var x239 uint64
+ x238, x239 = bits.Add64(x209, x206, uint64(p521Uint1(x237)))
+ var x241 uint64
+ _, x241 = bits.Add64(x190, x222, uint64(0x0))
+ var x242 uint64
+ var x243 uint64
+ x242, x243 = bits.Add64(x192, x224, uint64(p521Uint1(x241)))
+ var x244 uint64
+ var x245 uint64
+ x244, x245 = bits.Add64(x194, x226, uint64(p521Uint1(x243)))
+ var x246 uint64
+ var x247 uint64
+ x246, x247 = bits.Add64(x196, x228, uint64(p521Uint1(x245)))
+ var x248 uint64
+ var x249 uint64
+ x248, x249 = bits.Add64(x198, x230, uint64(p521Uint1(x247)))
+ var x250 uint64
+ var x251 uint64
+ x250, x251 = bits.Add64(x200, x232, uint64(p521Uint1(x249)))
+ var x252 uint64
+ var x253 uint64
+ x252, x253 = bits.Add64(x202, x234, uint64(p521Uint1(x251)))
+ var x254 uint64
+ var x255 uint64
+ x254, x255 = bits.Add64(x204, x236, uint64(p521Uint1(x253)))
+ var x256 uint64
+ var x257 uint64
+ x256, x257 = bits.Add64((uint64(p521Uint1(x205)) + (uint64(p521Uint1(x189)) + (uint64(p521Uint1(x171)) + x139))), x238, uint64(p521Uint1(x255)))
+ var x258 uint64
+ var x259 uint64
+ x258, x259 = bits.Add64(x242, arg1[4], uint64(0x0))
+ var x260 uint64
+ var x261 uint64
+ x260, x261 = bits.Add64(x244, uint64(0x0), uint64(p521Uint1(x259)))
+ var x262 uint64
+ var x263 uint64
+ x262, x263 = bits.Add64(x246, uint64(0x0), uint64(p521Uint1(x261)))
+ var x264 uint64
+ var x265 uint64
+ x264, x265 = bits.Add64(x248, uint64(0x0), uint64(p521Uint1(x263)))
+ var x266 uint64
+ var x267 uint64
+ x266, x267 = bits.Add64(x250, uint64(0x0), uint64(p521Uint1(x265)))
+ var x268 uint64
+ var x269 uint64
+ x268, x269 = bits.Add64(x252, uint64(0x0), uint64(p521Uint1(x267)))
+ var x270 uint64
+ var x271 uint64
+ x270, x271 = bits.Add64(x254, uint64(0x0), uint64(p521Uint1(x269)))
+ var x272 uint64
+ var x273 uint64
+ x272, x273 = bits.Add64(x256, uint64(0x0), uint64(p521Uint1(x271)))
+ var x274 uint64
+ var x275 uint64
+ x275, x274 = bits.Mul64(x258, 0x1ff)
+ var x276 uint64
+ var x277 uint64
+ x277, x276 = bits.Mul64(x258, 0xffffffffffffffff)
+ var x278 uint64
+ var x279 uint64
+ x279, x278 = bits.Mul64(x258, 0xffffffffffffffff)
+ var x280 uint64
+ var x281 uint64
+ x281, x280 = bits.Mul64(x258, 0xffffffffffffffff)
+ var x282 uint64
+ var x283 uint64
+ x283, x282 = bits.Mul64(x258, 0xffffffffffffffff)
+ var x284 uint64
+ var x285 uint64
+ x285, x284 = bits.Mul64(x258, 0xffffffffffffffff)
+ var x286 uint64
+ var x287 uint64
+ x287, x286 = bits.Mul64(x258, 0xffffffffffffffff)
+ var x288 uint64
+ var x289 uint64
+ x289, x288 = bits.Mul64(x258, 0xffffffffffffffff)
+ var x290 uint64
+ var x291 uint64
+ x291, x290 = bits.Mul64(x258, 0xffffffffffffffff)
+ var x292 uint64
+ var x293 uint64
+ x292, x293 = bits.Add64(x291, x288, uint64(0x0))
+ var x294 uint64
+ var x295 uint64
+ x294, x295 = bits.Add64(x289, x286, uint64(p521Uint1(x293)))
+ var x296 uint64
+ var x297 uint64
+ x296, x297 = bits.Add64(x287, x284, uint64(p521Uint1(x295)))
+ var x298 uint64
+ var x299 uint64
+ x298, x299 = bits.Add64(x285, x282, uint64(p521Uint1(x297)))
+ var x300 uint64
+ var x301 uint64
+ x300, x301 = bits.Add64(x283, x280, uint64(p521Uint1(x299)))
+ var x302 uint64
+ var x303 uint64
+ x302, x303 = bits.Add64(x281, x278, uint64(p521Uint1(x301)))
+ var x304 uint64
+ var x305 uint64
+ x304, x305 = bits.Add64(x279, x276, uint64(p521Uint1(x303)))
+ var x306 uint64
+ var x307 uint64
+ x306, x307 = bits.Add64(x277, x274, uint64(p521Uint1(x305)))
+ var x309 uint64
+ _, x309 = bits.Add64(x258, x290, uint64(0x0))
+ var x310 uint64
+ var x311 uint64
+ x310, x311 = bits.Add64(x260, x292, uint64(p521Uint1(x309)))
+ var x312 uint64
+ var x313 uint64
+ x312, x313 = bits.Add64(x262, x294, uint64(p521Uint1(x311)))
+ var x314 uint64
+ var x315 uint64
+ x314, x315 = bits.Add64(x264, x296, uint64(p521Uint1(x313)))
+ var x316 uint64
+ var x317 uint64
+ x316, x317 = bits.Add64(x266, x298, uint64(p521Uint1(x315)))
+ var x318 uint64
+ var x319 uint64
+ x318, x319 = bits.Add64(x268, x300, uint64(p521Uint1(x317)))
+ var x320 uint64
+ var x321 uint64
+ x320, x321 = bits.Add64(x270, x302, uint64(p521Uint1(x319)))
+ var x322 uint64
+ var x323 uint64
+ x322, x323 = bits.Add64(x272, x304, uint64(p521Uint1(x321)))
+ var x324 uint64
+ var x325 uint64
+ x324, x325 = bits.Add64((uint64(p521Uint1(x273)) + (uint64(p521Uint1(x257)) + (uint64(p521Uint1(x239)) + x207))), x306, uint64(p521Uint1(x323)))
+ var x326 uint64
+ var x327 uint64
+ x326, x327 = bits.Add64(x310, arg1[5], uint64(0x0))
+ var x328 uint64
+ var x329 uint64
+ x328, x329 = bits.Add64(x312, uint64(0x0), uint64(p521Uint1(x327)))
+ var x330 uint64
+ var x331 uint64
+ x330, x331 = bits.Add64(x314, uint64(0x0), uint64(p521Uint1(x329)))
+ var x332 uint64
+ var x333 uint64
+ x332, x333 = bits.Add64(x316, uint64(0x0), uint64(p521Uint1(x331)))
+ var x334 uint64
+ var x335 uint64
+ x334, x335 = bits.Add64(x318, uint64(0x0), uint64(p521Uint1(x333)))
+ var x336 uint64
+ var x337 uint64
+ x336, x337 = bits.Add64(x320, uint64(0x0), uint64(p521Uint1(x335)))
+ var x338 uint64
+ var x339 uint64
+ x338, x339 = bits.Add64(x322, uint64(0x0), uint64(p521Uint1(x337)))
+ var x340 uint64
+ var x341 uint64
+ x340, x341 = bits.Add64(x324, uint64(0x0), uint64(p521Uint1(x339)))
+ var x342 uint64
+ var x343 uint64
+ x343, x342 = bits.Mul64(x326, 0x1ff)
+ var x344 uint64
+ var x345 uint64
+ x345, x344 = bits.Mul64(x326, 0xffffffffffffffff)
+ var x346 uint64
+ var x347 uint64
+ x347, x346 = bits.Mul64(x326, 0xffffffffffffffff)
+ var x348 uint64
+ var x349 uint64
+ x349, x348 = bits.Mul64(x326, 0xffffffffffffffff)
+ var x350 uint64
+ var x351 uint64
+ x351, x350 = bits.Mul64(x326, 0xffffffffffffffff)
+ var x352 uint64
+ var x353 uint64
+ x353, x352 = bits.Mul64(x326, 0xffffffffffffffff)
+ var x354 uint64
+ var x355 uint64
+ x355, x354 = bits.Mul64(x326, 0xffffffffffffffff)
+ var x356 uint64
+ var x357 uint64
+ x357, x356 = bits.Mul64(x326, 0xffffffffffffffff)
+ var x358 uint64
+ var x359 uint64
+ x359, x358 = bits.Mul64(x326, 0xffffffffffffffff)
+ var x360 uint64
+ var x361 uint64
+ x360, x361 = bits.Add64(x359, x356, uint64(0x0))
+ var x362 uint64
+ var x363 uint64
+ x362, x363 = bits.Add64(x357, x354, uint64(p521Uint1(x361)))
+ var x364 uint64
+ var x365 uint64
+ x364, x365 = bits.Add64(x355, x352, uint64(p521Uint1(x363)))
+ var x366 uint64
+ var x367 uint64
+ x366, x367 = bits.Add64(x353, x350, uint64(p521Uint1(x365)))
+ var x368 uint64
+ var x369 uint64
+ x368, x369 = bits.Add64(x351, x348, uint64(p521Uint1(x367)))
+ var x370 uint64
+ var x371 uint64
+ x370, x371 = bits.Add64(x349, x346, uint64(p521Uint1(x369)))
+ var x372 uint64
+ var x373 uint64
+ x372, x373 = bits.Add64(x347, x344, uint64(p521Uint1(x371)))
+ var x374 uint64
+ var x375 uint64
+ x374, x375 = bits.Add64(x345, x342, uint64(p521Uint1(x373)))
+ var x377 uint64
+ _, x377 = bits.Add64(x326, x358, uint64(0x0))
+ var x378 uint64
+ var x379 uint64
+ x378, x379 = bits.Add64(x328, x360, uint64(p521Uint1(x377)))
+ var x380 uint64
+ var x381 uint64
+ x380, x381 = bits.Add64(x330, x362, uint64(p521Uint1(x379)))
+ var x382 uint64
+ var x383 uint64
+ x382, x383 = bits.Add64(x332, x364, uint64(p521Uint1(x381)))
+ var x384 uint64
+ var x385 uint64
+ x384, x385 = bits.Add64(x334, x366, uint64(p521Uint1(x383)))
+ var x386 uint64
+ var x387 uint64
+ x386, x387 = bits.Add64(x336, x368, uint64(p521Uint1(x385)))
+ var x388 uint64
+ var x389 uint64
+ x388, x389 = bits.Add64(x338, x370, uint64(p521Uint1(x387)))
+ var x390 uint64
+ var x391 uint64
+ x390, x391 = bits.Add64(x340, x372, uint64(p521Uint1(x389)))
+ var x392 uint64
+ var x393 uint64
+ x392, x393 = bits.Add64((uint64(p521Uint1(x341)) + (uint64(p521Uint1(x325)) + (uint64(p521Uint1(x307)) + x275))), x374, uint64(p521Uint1(x391)))
+ var x394 uint64
+ var x395 uint64
+ x394, x395 = bits.Add64(x378, arg1[6], uint64(0x0))
+ var x396 uint64
+ var x397 uint64
+ x396, x397 = bits.Add64(x380, uint64(0x0), uint64(p521Uint1(x395)))
+ var x398 uint64
+ var x399 uint64
+ x398, x399 = bits.Add64(x382, uint64(0x0), uint64(p521Uint1(x397)))
+ var x400 uint64
+ var x401 uint64
+ x400, x401 = bits.Add64(x384, uint64(0x0), uint64(p521Uint1(x399)))
+ var x402 uint64
+ var x403 uint64
+ x402, x403 = bits.Add64(x386, uint64(0x0), uint64(p521Uint1(x401)))
+ var x404 uint64
+ var x405 uint64
+ x404, x405 = bits.Add64(x388, uint64(0x0), uint64(p521Uint1(x403)))
+ var x406 uint64
+ var x407 uint64
+ x406, x407 = bits.Add64(x390, uint64(0x0), uint64(p521Uint1(x405)))
+ var x408 uint64
+ var x409 uint64
+ x408, x409 = bits.Add64(x392, uint64(0x0), uint64(p521Uint1(x407)))
+ var x410 uint64
+ var x411 uint64
+ x411, x410 = bits.Mul64(x394, 0x1ff)
+ var x412 uint64
+ var x413 uint64
+ x413, x412 = bits.Mul64(x394, 0xffffffffffffffff)
+ var x414 uint64
+ var x415 uint64
+ x415, x414 = bits.Mul64(x394, 0xffffffffffffffff)
+ var x416 uint64
+ var x417 uint64
+ x417, x416 = bits.Mul64(x394, 0xffffffffffffffff)
+ var x418 uint64
+ var x419 uint64
+ x419, x418 = bits.Mul64(x394, 0xffffffffffffffff)
+ var x420 uint64
+ var x421 uint64
+ x421, x420 = bits.Mul64(x394, 0xffffffffffffffff)
+ var x422 uint64
+ var x423 uint64
+ x423, x422 = bits.Mul64(x394, 0xffffffffffffffff)
+ var x424 uint64
+ var x425 uint64
+ x425, x424 = bits.Mul64(x394, 0xffffffffffffffff)
+ var x426 uint64
+ var x427 uint64
+ x427, x426 = bits.Mul64(x394, 0xffffffffffffffff)
+ var x428 uint64
+ var x429 uint64
+ x428, x429 = bits.Add64(x427, x424, uint64(0x0))
+ var x430 uint64
+ var x431 uint64
+ x430, x431 = bits.Add64(x425, x422, uint64(p521Uint1(x429)))
+ var x432 uint64
+ var x433 uint64
+ x432, x433 = bits.Add64(x423, x420, uint64(p521Uint1(x431)))
+ var x434 uint64
+ var x435 uint64
+ x434, x435 = bits.Add64(x421, x418, uint64(p521Uint1(x433)))
+ var x436 uint64
+ var x437 uint64
+ x436, x437 = bits.Add64(x419, x416, uint64(p521Uint1(x435)))
+ var x438 uint64
+ var x439 uint64
+ x438, x439 = bits.Add64(x417, x414, uint64(p521Uint1(x437)))
+ var x440 uint64
+ var x441 uint64
+ x440, x441 = bits.Add64(x415, x412, uint64(p521Uint1(x439)))
+ var x442 uint64
+ var x443 uint64
+ x442, x443 = bits.Add64(x413, x410, uint64(p521Uint1(x441)))
+ var x445 uint64
+ _, x445 = bits.Add64(x394, x426, uint64(0x0))
+ var x446 uint64
+ var x447 uint64
+ x446, x447 = bits.Add64(x396, x428, uint64(p521Uint1(x445)))
+ var x448 uint64
+ var x449 uint64
+ x448, x449 = bits.Add64(x398, x430, uint64(p521Uint1(x447)))
+ var x450 uint64
+ var x451 uint64
+ x450, x451 = bits.Add64(x400, x432, uint64(p521Uint1(x449)))
+ var x452 uint64
+ var x453 uint64
+ x452, x453 = bits.Add64(x402, x434, uint64(p521Uint1(x451)))
+ var x454 uint64
+ var x455 uint64
+ x454, x455 = bits.Add64(x404, x436, uint64(p521Uint1(x453)))
+ var x456 uint64
+ var x457 uint64
+ x456, x457 = bits.Add64(x406, x438, uint64(p521Uint1(x455)))
+ var x458 uint64
+ var x459 uint64
+ x458, x459 = bits.Add64(x408, x440, uint64(p521Uint1(x457)))
+ var x460 uint64
+ var x461 uint64
+ x460, x461 = bits.Add64((uint64(p521Uint1(x409)) + (uint64(p521Uint1(x393)) + (uint64(p521Uint1(x375)) + x343))), x442, uint64(p521Uint1(x459)))
+ var x462 uint64
+ var x463 uint64
+ x462, x463 = bits.Add64(x446, arg1[7], uint64(0x0))
+ var x464 uint64
+ var x465 uint64
+ x464, x465 = bits.Add64(x448, uint64(0x0), uint64(p521Uint1(x463)))
+ var x466 uint64
+ var x467 uint64
+ x466, x467 = bits.Add64(x450, uint64(0x0), uint64(p521Uint1(x465)))
+ var x468 uint64
+ var x469 uint64
+ x468, x469 = bits.Add64(x452, uint64(0x0), uint64(p521Uint1(x467)))
+ var x470 uint64
+ var x471 uint64
+ x470, x471 = bits.Add64(x454, uint64(0x0), uint64(p521Uint1(x469)))
+ var x472 uint64
+ var x473 uint64
+ x472, x473 = bits.Add64(x456, uint64(0x0), uint64(p521Uint1(x471)))
+ var x474 uint64
+ var x475 uint64
+ x474, x475 = bits.Add64(x458, uint64(0x0), uint64(p521Uint1(x473)))
+ var x476 uint64
+ var x477 uint64
+ x476, x477 = bits.Add64(x460, uint64(0x0), uint64(p521Uint1(x475)))
+ var x478 uint64
+ var x479 uint64
+ x479, x478 = bits.Mul64(x462, 0x1ff)
+ var x480 uint64
+ var x481 uint64
+ x481, x480 = bits.Mul64(x462, 0xffffffffffffffff)
+ var x482 uint64
+ var x483 uint64
+ x483, x482 = bits.Mul64(x462, 0xffffffffffffffff)
+ var x484 uint64
+ var x485 uint64
+ x485, x484 = bits.Mul64(x462, 0xffffffffffffffff)
+ var x486 uint64
+ var x487 uint64
+ x487, x486 = bits.Mul64(x462, 0xffffffffffffffff)
+ var x488 uint64
+ var x489 uint64
+ x489, x488 = bits.Mul64(x462, 0xffffffffffffffff)
+ var x490 uint64
+ var x491 uint64
+ x491, x490 = bits.Mul64(x462, 0xffffffffffffffff)
+ var x492 uint64
+ var x493 uint64
+ x493, x492 = bits.Mul64(x462, 0xffffffffffffffff)
+ var x494 uint64
+ var x495 uint64
+ x495, x494 = bits.Mul64(x462, 0xffffffffffffffff)
+ var x496 uint64
+ var x497 uint64
+ x496, x497 = bits.Add64(x495, x492, uint64(0x0))
+ var x498 uint64
+ var x499 uint64
+ x498, x499 = bits.Add64(x493, x490, uint64(p521Uint1(x497)))
+ var x500 uint64
+ var x501 uint64
+ x500, x501 = bits.Add64(x491, x488, uint64(p521Uint1(x499)))
+ var x502 uint64
+ var x503 uint64
+ x502, x503 = bits.Add64(x489, x486, uint64(p521Uint1(x501)))
+ var x504 uint64
+ var x505 uint64
+ x504, x505 = bits.Add64(x487, x484, uint64(p521Uint1(x503)))
+ var x506 uint64
+ var x507 uint64
+ x506, x507 = bits.Add64(x485, x482, uint64(p521Uint1(x505)))
+ var x508 uint64
+ var x509 uint64
+ x508, x509 = bits.Add64(x483, x480, uint64(p521Uint1(x507)))
+ var x510 uint64
+ var x511 uint64
+ x510, x511 = bits.Add64(x481, x478, uint64(p521Uint1(x509)))
+ var x513 uint64
+ _, x513 = bits.Add64(x462, x494, uint64(0x0))
+ var x514 uint64
+ var x515 uint64
+ x514, x515 = bits.Add64(x464, x496, uint64(p521Uint1(x513)))
+ var x516 uint64
+ var x517 uint64
+ x516, x517 = bits.Add64(x466, x498, uint64(p521Uint1(x515)))
+ var x518 uint64
+ var x519 uint64
+ x518, x519 = bits.Add64(x468, x500, uint64(p521Uint1(x517)))
+ var x520 uint64
+ var x521 uint64
+ x520, x521 = bits.Add64(x470, x502, uint64(p521Uint1(x519)))
+ var x522 uint64
+ var x523 uint64
+ x522, x523 = bits.Add64(x472, x504, uint64(p521Uint1(x521)))
+ var x524 uint64
+ var x525 uint64
+ x524, x525 = bits.Add64(x474, x506, uint64(p521Uint1(x523)))
+ var x526 uint64
+ var x527 uint64
+ x526, x527 = bits.Add64(x476, x508, uint64(p521Uint1(x525)))
+ var x528 uint64
+ var x529 uint64
+ x528, x529 = bits.Add64((uint64(p521Uint1(x477)) + (uint64(p521Uint1(x461)) + (uint64(p521Uint1(x443)) + x411))), x510, uint64(p521Uint1(x527)))
+ var x530 uint64
+ var x531 uint64
+ x530, x531 = bits.Add64(x514, arg1[8], uint64(0x0))
+ var x532 uint64
+ var x533 uint64
+ x532, x533 = bits.Add64(x516, uint64(0x0), uint64(p521Uint1(x531)))
+ var x534 uint64
+ var x535 uint64
+ x534, x535 = bits.Add64(x518, uint64(0x0), uint64(p521Uint1(x533)))
+ var x536 uint64
+ var x537 uint64
+ x536, x537 = bits.Add64(x520, uint64(0x0), uint64(p521Uint1(x535)))
+ var x538 uint64
+ var x539 uint64
+ x538, x539 = bits.Add64(x522, uint64(0x0), uint64(p521Uint1(x537)))
+ var x540 uint64
+ var x541 uint64
+ x540, x541 = bits.Add64(x524, uint64(0x0), uint64(p521Uint1(x539)))
+ var x542 uint64
+ var x543 uint64
+ x542, x543 = bits.Add64(x526, uint64(0x0), uint64(p521Uint1(x541)))
+ var x544 uint64
+ var x545 uint64
+ x544, x545 = bits.Add64(x528, uint64(0x0), uint64(p521Uint1(x543)))
+ var x546 uint64
+ var x547 uint64
+ x547, x546 = bits.Mul64(x530, 0x1ff)
+ var x548 uint64
+ var x549 uint64
+ x549, x548 = bits.Mul64(x530, 0xffffffffffffffff)
+ var x550 uint64
+ var x551 uint64
+ x551, x550 = bits.Mul64(x530, 0xffffffffffffffff)
+ var x552 uint64
+ var x553 uint64
+ x553, x552 = bits.Mul64(x530, 0xffffffffffffffff)
+ var x554 uint64
+ var x555 uint64
+ x555, x554 = bits.Mul64(x530, 0xffffffffffffffff)
+ var x556 uint64
+ var x557 uint64
+ x557, x556 = bits.Mul64(x530, 0xffffffffffffffff)
+ var x558 uint64
+ var x559 uint64
+ x559, x558 = bits.Mul64(x530, 0xffffffffffffffff)
+ var x560 uint64
+ var x561 uint64
+ x561, x560 = bits.Mul64(x530, 0xffffffffffffffff)
+ var x562 uint64
+ var x563 uint64
+ x563, x562 = bits.Mul64(x530, 0xffffffffffffffff)
+ var x564 uint64
+ var x565 uint64
+ x564, x565 = bits.Add64(x563, x560, uint64(0x0))
+ var x566 uint64
+ var x567 uint64
+ x566, x567 = bits.Add64(x561, x558, uint64(p521Uint1(x565)))
+ var x568 uint64
+ var x569 uint64
+ x568, x569 = bits.Add64(x559, x556, uint64(p521Uint1(x567)))
+ var x570 uint64
+ var x571 uint64
+ x570, x571 = bits.Add64(x557, x554, uint64(p521Uint1(x569)))
+ var x572 uint64
+ var x573 uint64
+ x572, x573 = bits.Add64(x555, x552, uint64(p521Uint1(x571)))
+ var x574 uint64
+ var x575 uint64
+ x574, x575 = bits.Add64(x553, x550, uint64(p521Uint1(x573)))
+ var x576 uint64
+ var x577 uint64
+ x576, x577 = bits.Add64(x551, x548, uint64(p521Uint1(x575)))
+ var x578 uint64
+ var x579 uint64
+ x578, x579 = bits.Add64(x549, x546, uint64(p521Uint1(x577)))
+ var x581 uint64
+ _, x581 = bits.Add64(x530, x562, uint64(0x0))
+ var x582 uint64
+ var x583 uint64
+ x582, x583 = bits.Add64(x532, x564, uint64(p521Uint1(x581)))
+ var x584 uint64
+ var x585 uint64
+ x584, x585 = bits.Add64(x534, x566, uint64(p521Uint1(x583)))
+ var x586 uint64
+ var x587 uint64
+ x586, x587 = bits.Add64(x536, x568, uint64(p521Uint1(x585)))
+ var x588 uint64
+ var x589 uint64
+ x588, x589 = bits.Add64(x538, x570, uint64(p521Uint1(x587)))
+ var x590 uint64
+ var x591 uint64
+ x590, x591 = bits.Add64(x540, x572, uint64(p521Uint1(x589)))
+ var x592 uint64
+ var x593 uint64
+ x592, x593 = bits.Add64(x542, x574, uint64(p521Uint1(x591)))
+ var x594 uint64
+ var x595 uint64
+ x594, x595 = bits.Add64(x544, x576, uint64(p521Uint1(x593)))
+ var x596 uint64
+ var x597 uint64
+ x596, x597 = bits.Add64((uint64(p521Uint1(x545)) + (uint64(p521Uint1(x529)) + (uint64(p521Uint1(x511)) + x479))), x578, uint64(p521Uint1(x595)))
+ x598 := (uint64(p521Uint1(x597)) + (uint64(p521Uint1(x579)) + x547))
+ var x599 uint64
+ var x600 uint64
+ x599, x600 = bits.Sub64(x582, 0xffffffffffffffff, uint64(0x0))
+ var x601 uint64
+ var x602 uint64
+ x601, x602 = bits.Sub64(x584, 0xffffffffffffffff, uint64(p521Uint1(x600)))
+ var x603 uint64
+ var x604 uint64
+ x603, x604 = bits.Sub64(x586, 0xffffffffffffffff, uint64(p521Uint1(x602)))
+ var x605 uint64
+ var x606 uint64
+ x605, x606 = bits.Sub64(x588, 0xffffffffffffffff, uint64(p521Uint1(x604)))
+ var x607 uint64
+ var x608 uint64
+ x607, x608 = bits.Sub64(x590, 0xffffffffffffffff, uint64(p521Uint1(x606)))
+ var x609 uint64
+ var x610 uint64
+ x609, x610 = bits.Sub64(x592, 0xffffffffffffffff, uint64(p521Uint1(x608)))
+ var x611 uint64
+ var x612 uint64
+ x611, x612 = bits.Sub64(x594, 0xffffffffffffffff, uint64(p521Uint1(x610)))
+ var x613 uint64
+ var x614 uint64
+ x613, x614 = bits.Sub64(x596, 0xffffffffffffffff, uint64(p521Uint1(x612)))
+ var x615 uint64
+ var x616 uint64
+ x615, x616 = bits.Sub64(x598, 0x1ff, uint64(p521Uint1(x614)))
+ var x618 uint64
+ _, x618 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(p521Uint1(x616)))
+ var x619 uint64
+ p521CmovznzU64(&x619, p521Uint1(x618), x599, x582)
+ var x620 uint64
+ p521CmovznzU64(&x620, p521Uint1(x618), x601, x584)
+ var x621 uint64
+ p521CmovznzU64(&x621, p521Uint1(x618), x603, x586)
+ var x622 uint64
+ p521CmovznzU64(&x622, p521Uint1(x618), x605, x588)
+ var x623 uint64
+ p521CmovznzU64(&x623, p521Uint1(x618), x607, x590)
+ var x624 uint64
+ p521CmovznzU64(&x624, p521Uint1(x618), x609, x592)
+ var x625 uint64
+ p521CmovznzU64(&x625, p521Uint1(x618), x611, x594)
+ var x626 uint64
+ p521CmovznzU64(&x626, p521Uint1(x618), x613, x596)
+ var x627 uint64
+ p521CmovznzU64(&x627, p521Uint1(x618), x615, x598)
+ out1[0] = x619
+ out1[1] = x620
+ out1[2] = x621
+ out1[3] = x622
+ out1[4] = x623
+ out1[5] = x624
+ out1[6] = x625
+ out1[7] = x626
+ out1[8] = x627
+}
+
+// p521ToMontgomery translates a field element into the Montgomery domain.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// eval (from_montgomery out1) mod m = eval arg1 mod m
+// 0 ≤ eval out1 < m
+func p521ToMontgomery(out1 *p521MontgomeryDomainFieldElement, arg1 *p521NonMontgomeryDomainFieldElement) {
+ var x1 uint64
+ var x2 uint64
+ x2, x1 = bits.Mul64(arg1[0], 0x400000000000)
+ var x3 uint64
+ var x4 uint64
+ x4, x3 = bits.Mul64(arg1[1], 0x400000000000)
+ var x5 uint64
+ var x6 uint64
+ x5, x6 = bits.Add64(x2, x3, uint64(0x0))
+ var x7 uint64
+ var x8 uint64
+ x8, x7 = bits.Mul64(x1, 0x1ff)
+ var x9 uint64
+ var x10 uint64
+ x10, x9 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x11 uint64
+ var x12 uint64
+ x12, x11 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x13 uint64
+ var x14 uint64
+ x14, x13 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x15 uint64
+ var x16 uint64
+ x16, x15 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x17 uint64
+ var x18 uint64
+ x18, x17 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x19 uint64
+ var x20 uint64
+ x20, x19 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x21 uint64
+ var x22 uint64
+ x22, x21 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x23 uint64
+ var x24 uint64
+ x24, x23 = bits.Mul64(x1, 0xffffffffffffffff)
+ var x25 uint64
+ var x26 uint64
+ x25, x26 = bits.Add64(x24, x21, uint64(0x0))
+ var x27 uint64
+ var x28 uint64
+ x27, x28 = bits.Add64(x22, x19, uint64(p521Uint1(x26)))
+ var x29 uint64
+ var x30 uint64
+ x29, x30 = bits.Add64(x20, x17, uint64(p521Uint1(x28)))
+ var x31 uint64
+ var x32 uint64
+ x31, x32 = bits.Add64(x18, x15, uint64(p521Uint1(x30)))
+ var x33 uint64
+ var x34 uint64
+ x33, x34 = bits.Add64(x16, x13, uint64(p521Uint1(x32)))
+ var x35 uint64
+ var x36 uint64
+ x35, x36 = bits.Add64(x14, x11, uint64(p521Uint1(x34)))
+ var x37 uint64
+ var x38 uint64
+ x37, x38 = bits.Add64(x12, x9, uint64(p521Uint1(x36)))
+ var x39 uint64
+ var x40 uint64
+ x39, x40 = bits.Add64(x10, x7, uint64(p521Uint1(x38)))
+ var x42 uint64
+ _, x42 = bits.Add64(x1, x23, uint64(0x0))
+ var x43 uint64
+ var x44 uint64
+ x43, x44 = bits.Add64(x5, x25, uint64(p521Uint1(x42)))
+ var x45 uint64
+ var x46 uint64
+ x45, x46 = bits.Add64((uint64(p521Uint1(x6)) + x4), x27, uint64(p521Uint1(x44)))
+ var x47 uint64
+ var x48 uint64
+ x47, x48 = bits.Add64(uint64(0x0), x29, uint64(p521Uint1(x46)))
+ var x49 uint64
+ var x50 uint64
+ x49, x50 = bits.Add64(uint64(0x0), x31, uint64(p521Uint1(x48)))
+ var x51 uint64
+ var x52 uint64
+ x51, x52 = bits.Add64(uint64(0x0), x33, uint64(p521Uint1(x50)))
+ var x53 uint64
+ var x54 uint64
+ x53, x54 = bits.Add64(uint64(0x0), x35, uint64(p521Uint1(x52)))
+ var x55 uint64
+ var x56 uint64
+ x55, x56 = bits.Add64(uint64(0x0), x37, uint64(p521Uint1(x54)))
+ var x57 uint64
+ var x58 uint64
+ x57, x58 = bits.Add64(uint64(0x0), x39, uint64(p521Uint1(x56)))
+ var x59 uint64
+ var x60 uint64
+ x60, x59 = bits.Mul64(arg1[2], 0x400000000000)
+ var x61 uint64
+ var x62 uint64
+ x61, x62 = bits.Add64(x45, x59, uint64(0x0))
+ var x63 uint64
+ var x64 uint64
+ x63, x64 = bits.Add64(x47, x60, uint64(p521Uint1(x62)))
+ var x65 uint64
+ var x66 uint64
+ x65, x66 = bits.Add64(x49, uint64(0x0), uint64(p521Uint1(x64)))
+ var x67 uint64
+ var x68 uint64
+ x67, x68 = bits.Add64(x51, uint64(0x0), uint64(p521Uint1(x66)))
+ var x69 uint64
+ var x70 uint64
+ x69, x70 = bits.Add64(x53, uint64(0x0), uint64(p521Uint1(x68)))
+ var x71 uint64
+ var x72 uint64
+ x71, x72 = bits.Add64(x55, uint64(0x0), uint64(p521Uint1(x70)))
+ var x73 uint64
+ var x74 uint64
+ x73, x74 = bits.Add64(x57, uint64(0x0), uint64(p521Uint1(x72)))
+ var x75 uint64
+ var x76 uint64
+ x76, x75 = bits.Mul64(x43, 0x1ff)
+ var x77 uint64
+ var x78 uint64
+ x78, x77 = bits.Mul64(x43, 0xffffffffffffffff)
+ var x79 uint64
+ var x80 uint64
+ x80, x79 = bits.Mul64(x43, 0xffffffffffffffff)
+ var x81 uint64
+ var x82 uint64
+ x82, x81 = bits.Mul64(x43, 0xffffffffffffffff)
+ var x83 uint64
+ var x84 uint64
+ x84, x83 = bits.Mul64(x43, 0xffffffffffffffff)
+ var x85 uint64
+ var x86 uint64
+ x86, x85 = bits.Mul64(x43, 0xffffffffffffffff)
+ var x87 uint64
+ var x88 uint64
+ x88, x87 = bits.Mul64(x43, 0xffffffffffffffff)
+ var x89 uint64
+ var x90 uint64
+ x90, x89 = bits.Mul64(x43, 0xffffffffffffffff)
+ var x91 uint64
+ var x92 uint64
+ x92, x91 = bits.Mul64(x43, 0xffffffffffffffff)
+ var x93 uint64
+ var x94 uint64
+ x93, x94 = bits.Add64(x92, x89, uint64(0x0))
+ var x95 uint64
+ var x96 uint64
+ x95, x96 = bits.Add64(x90, x87, uint64(p521Uint1(x94)))
+ var x97 uint64
+ var x98 uint64
+ x97, x98 = bits.Add64(x88, x85, uint64(p521Uint1(x96)))
+ var x99 uint64
+ var x100 uint64
+ x99, x100 = bits.Add64(x86, x83, uint64(p521Uint1(x98)))
+ var x101 uint64
+ var x102 uint64
+ x101, x102 = bits.Add64(x84, x81, uint64(p521Uint1(x100)))
+ var x103 uint64
+ var x104 uint64
+ x103, x104 = bits.Add64(x82, x79, uint64(p521Uint1(x102)))
+ var x105 uint64
+ var x106 uint64
+ x105, x106 = bits.Add64(x80, x77, uint64(p521Uint1(x104)))
+ var x107 uint64
+ var x108 uint64
+ x107, x108 = bits.Add64(x78, x75, uint64(p521Uint1(x106)))
+ var x110 uint64
+ _, x110 = bits.Add64(x43, x91, uint64(0x0))
+ var x111 uint64
+ var x112 uint64
+ x111, x112 = bits.Add64(x61, x93, uint64(p521Uint1(x110)))
+ var x113 uint64
+ var x114 uint64
+ x113, x114 = bits.Add64(x63, x95, uint64(p521Uint1(x112)))
+ var x115 uint64
+ var x116 uint64
+ x115, x116 = bits.Add64(x65, x97, uint64(p521Uint1(x114)))
+ var x117 uint64
+ var x118 uint64
+ x117, x118 = bits.Add64(x67, x99, uint64(p521Uint1(x116)))
+ var x119 uint64
+ var x120 uint64
+ x119, x120 = bits.Add64(x69, x101, uint64(p521Uint1(x118)))
+ var x121 uint64
+ var x122 uint64
+ x121, x122 = bits.Add64(x71, x103, uint64(p521Uint1(x120)))
+ var x123 uint64
+ var x124 uint64
+ x123, x124 = bits.Add64(x73, x105, uint64(p521Uint1(x122)))
+ var x125 uint64
+ var x126 uint64
+ x125, x126 = bits.Add64((uint64(p521Uint1(x74)) + (uint64(p521Uint1(x58)) + (uint64(p521Uint1(x40)) + x8))), x107, uint64(p521Uint1(x124)))
+ var x127 uint64
+ var x128 uint64
+ x128, x127 = bits.Mul64(arg1[3], 0x400000000000)
+ var x129 uint64
+ var x130 uint64
+ x129, x130 = bits.Add64(x113, x127, uint64(0x0))
+ var x131 uint64
+ var x132 uint64
+ x131, x132 = bits.Add64(x115, x128, uint64(p521Uint1(x130)))
+ var x133 uint64
+ var x134 uint64
+ x133, x134 = bits.Add64(x117, uint64(0x0), uint64(p521Uint1(x132)))
+ var x135 uint64
+ var x136 uint64
+ x135, x136 = bits.Add64(x119, uint64(0x0), uint64(p521Uint1(x134)))
+ var x137 uint64
+ var x138 uint64
+ x137, x138 = bits.Add64(x121, uint64(0x0), uint64(p521Uint1(x136)))
+ var x139 uint64
+ var x140 uint64
+ x139, x140 = bits.Add64(x123, uint64(0x0), uint64(p521Uint1(x138)))
+ var x141 uint64
+ var x142 uint64
+ x141, x142 = bits.Add64(x125, uint64(0x0), uint64(p521Uint1(x140)))
+ var x143 uint64
+ var x144 uint64
+ x144, x143 = bits.Mul64(x111, 0x1ff)
+ var x145 uint64
+ var x146 uint64
+ x146, x145 = bits.Mul64(x111, 0xffffffffffffffff)
+ var x147 uint64
+ var x148 uint64
+ x148, x147 = bits.Mul64(x111, 0xffffffffffffffff)
+ var x149 uint64
+ var x150 uint64
+ x150, x149 = bits.Mul64(x111, 0xffffffffffffffff)
+ var x151 uint64
+ var x152 uint64
+ x152, x151 = bits.Mul64(x111, 0xffffffffffffffff)
+ var x153 uint64
+ var x154 uint64
+ x154, x153 = bits.Mul64(x111, 0xffffffffffffffff)
+ var x155 uint64
+ var x156 uint64
+ x156, x155 = bits.Mul64(x111, 0xffffffffffffffff)
+ var x157 uint64
+ var x158 uint64
+ x158, x157 = bits.Mul64(x111, 0xffffffffffffffff)
+ var x159 uint64
+ var x160 uint64
+ x160, x159 = bits.Mul64(x111, 0xffffffffffffffff)
+ var x161 uint64
+ var x162 uint64
+ x161, x162 = bits.Add64(x160, x157, uint64(0x0))
+ var x163 uint64
+ var x164 uint64
+ x163, x164 = bits.Add64(x158, x155, uint64(p521Uint1(x162)))
+ var x165 uint64
+ var x166 uint64
+ x165, x166 = bits.Add64(x156, x153, uint64(p521Uint1(x164)))
+ var x167 uint64
+ var x168 uint64
+ x167, x168 = bits.Add64(x154, x151, uint64(p521Uint1(x166)))
+ var x169 uint64
+ var x170 uint64
+ x169, x170 = bits.Add64(x152, x149, uint64(p521Uint1(x168)))
+ var x171 uint64
+ var x172 uint64
+ x171, x172 = bits.Add64(x150, x147, uint64(p521Uint1(x170)))
+ var x173 uint64
+ var x174 uint64
+ x173, x174 = bits.Add64(x148, x145, uint64(p521Uint1(x172)))
+ var x175 uint64
+ var x176 uint64
+ x175, x176 = bits.Add64(x146, x143, uint64(p521Uint1(x174)))
+ var x178 uint64
+ _, x178 = bits.Add64(x111, x159, uint64(0x0))
+ var x179 uint64
+ var x180 uint64
+ x179, x180 = bits.Add64(x129, x161, uint64(p521Uint1(x178)))
+ var x181 uint64
+ var x182 uint64
+ x181, x182 = bits.Add64(x131, x163, uint64(p521Uint1(x180)))
+ var x183 uint64
+ var x184 uint64
+ x183, x184 = bits.Add64(x133, x165, uint64(p521Uint1(x182)))
+ var x185 uint64
+ var x186 uint64
+ x185, x186 = bits.Add64(x135, x167, uint64(p521Uint1(x184)))
+ var x187 uint64
+ var x188 uint64
+ x187, x188 = bits.Add64(x137, x169, uint64(p521Uint1(x186)))
+ var x189 uint64
+ var x190 uint64
+ x189, x190 = bits.Add64(x139, x171, uint64(p521Uint1(x188)))
+ var x191 uint64
+ var x192 uint64
+ x191, x192 = bits.Add64(x141, x173, uint64(p521Uint1(x190)))
+ var x193 uint64
+ var x194 uint64
+ x193, x194 = bits.Add64((uint64(p521Uint1(x142)) + (uint64(p521Uint1(x126)) + (uint64(p521Uint1(x108)) + x76))), x175, uint64(p521Uint1(x192)))
+ var x195 uint64
+ var x196 uint64
+ x196, x195 = bits.Mul64(arg1[4], 0x400000000000)
+ var x197 uint64
+ var x198 uint64
+ x197, x198 = bits.Add64(x181, x195, uint64(0x0))
+ var x199 uint64
+ var x200 uint64
+ x199, x200 = bits.Add64(x183, x196, uint64(p521Uint1(x198)))
+ var x201 uint64
+ var x202 uint64
+ x201, x202 = bits.Add64(x185, uint64(0x0), uint64(p521Uint1(x200)))
+ var x203 uint64
+ var x204 uint64
+ x203, x204 = bits.Add64(x187, uint64(0x0), uint64(p521Uint1(x202)))
+ var x205 uint64
+ var x206 uint64
+ x205, x206 = bits.Add64(x189, uint64(0x0), uint64(p521Uint1(x204)))
+ var x207 uint64
+ var x208 uint64
+ x207, x208 = bits.Add64(x191, uint64(0x0), uint64(p521Uint1(x206)))
+ var x209 uint64
+ var x210 uint64
+ x209, x210 = bits.Add64(x193, uint64(0x0), uint64(p521Uint1(x208)))
+ var x211 uint64
+ var x212 uint64
+ x212, x211 = bits.Mul64(x179, 0x1ff)
+ var x213 uint64
+ var x214 uint64
+ x214, x213 = bits.Mul64(x179, 0xffffffffffffffff)
+ var x215 uint64
+ var x216 uint64
+ x216, x215 = bits.Mul64(x179, 0xffffffffffffffff)
+ var x217 uint64
+ var x218 uint64
+ x218, x217 = bits.Mul64(x179, 0xffffffffffffffff)
+ var x219 uint64
+ var x220 uint64
+ x220, x219 = bits.Mul64(x179, 0xffffffffffffffff)
+ var x221 uint64
+ var x222 uint64
+ x222, x221 = bits.Mul64(x179, 0xffffffffffffffff)
+ var x223 uint64
+ var x224 uint64
+ x224, x223 = bits.Mul64(x179, 0xffffffffffffffff)
+ var x225 uint64
+ var x226 uint64
+ x226, x225 = bits.Mul64(x179, 0xffffffffffffffff)
+ var x227 uint64
+ var x228 uint64
+ x228, x227 = bits.Mul64(x179, 0xffffffffffffffff)
+ var x229 uint64
+ var x230 uint64
+ x229, x230 = bits.Add64(x228, x225, uint64(0x0))
+ var x231 uint64
+ var x232 uint64
+ x231, x232 = bits.Add64(x226, x223, uint64(p521Uint1(x230)))
+ var x233 uint64
+ var x234 uint64
+ x233, x234 = bits.Add64(x224, x221, uint64(p521Uint1(x232)))
+ var x235 uint64
+ var x236 uint64
+ x235, x236 = bits.Add64(x222, x219, uint64(p521Uint1(x234)))
+ var x237 uint64
+ var x238 uint64
+ x237, x238 = bits.Add64(x220, x217, uint64(p521Uint1(x236)))
+ var x239 uint64
+ var x240 uint64
+ x239, x240 = bits.Add64(x218, x215, uint64(p521Uint1(x238)))
+ var x241 uint64
+ var x242 uint64
+ x241, x242 = bits.Add64(x216, x213, uint64(p521Uint1(x240)))
+ var x243 uint64
+ var x244 uint64
+ x243, x244 = bits.Add64(x214, x211, uint64(p521Uint1(x242)))
+ var x246 uint64
+ _, x246 = bits.Add64(x179, x227, uint64(0x0))
+ var x247 uint64
+ var x248 uint64
+ x247, x248 = bits.Add64(x197, x229, uint64(p521Uint1(x246)))
+ var x249 uint64
+ var x250 uint64
+ x249, x250 = bits.Add64(x199, x231, uint64(p521Uint1(x248)))
+ var x251 uint64
+ var x252 uint64
+ x251, x252 = bits.Add64(x201, x233, uint64(p521Uint1(x250)))
+ var x253 uint64
+ var x254 uint64
+ x253, x254 = bits.Add64(x203, x235, uint64(p521Uint1(x252)))
+ var x255 uint64
+ var x256 uint64
+ x255, x256 = bits.Add64(x205, x237, uint64(p521Uint1(x254)))
+ var x257 uint64
+ var x258 uint64
+ x257, x258 = bits.Add64(x207, x239, uint64(p521Uint1(x256)))
+ var x259 uint64
+ var x260 uint64
+ x259, x260 = bits.Add64(x209, x241, uint64(p521Uint1(x258)))
+ var x261 uint64
+ var x262 uint64
+ x261, x262 = bits.Add64((uint64(p521Uint1(x210)) + (uint64(p521Uint1(x194)) + (uint64(p521Uint1(x176)) + x144))), x243, uint64(p521Uint1(x260)))
+ var x263 uint64
+ var x264 uint64
+ x264, x263 = bits.Mul64(arg1[5], 0x400000000000)
+ var x265 uint64
+ var x266 uint64
+ x265, x266 = bits.Add64(x249, x263, uint64(0x0))
+ var x267 uint64
+ var x268 uint64
+ x267, x268 = bits.Add64(x251, x264, uint64(p521Uint1(x266)))
+ var x269 uint64
+ var x270 uint64
+ x269, x270 = bits.Add64(x253, uint64(0x0), uint64(p521Uint1(x268)))
+ var x271 uint64
+ var x272 uint64
+ x271, x272 = bits.Add64(x255, uint64(0x0), uint64(p521Uint1(x270)))
+ var x273 uint64
+ var x274 uint64
+ x273, x274 = bits.Add64(x257, uint64(0x0), uint64(p521Uint1(x272)))
+ var x275 uint64
+ var x276 uint64
+ x275, x276 = bits.Add64(x259, uint64(0x0), uint64(p521Uint1(x274)))
+ var x277 uint64
+ var x278 uint64
+ x277, x278 = bits.Add64(x261, uint64(0x0), uint64(p521Uint1(x276)))
+ var x279 uint64
+ var x280 uint64
+ x280, x279 = bits.Mul64(x247, 0x1ff)
+ var x281 uint64
+ var x282 uint64
+ x282, x281 = bits.Mul64(x247, 0xffffffffffffffff)
+ var x283 uint64
+ var x284 uint64
+ x284, x283 = bits.Mul64(x247, 0xffffffffffffffff)
+ var x285 uint64
+ var x286 uint64
+ x286, x285 = bits.Mul64(x247, 0xffffffffffffffff)
+ var x287 uint64
+ var x288 uint64
+ x288, x287 = bits.Mul64(x247, 0xffffffffffffffff)
+ var x289 uint64
+ var x290 uint64
+ x290, x289 = bits.Mul64(x247, 0xffffffffffffffff)
+ var x291 uint64
+ var x292 uint64
+ x292, x291 = bits.Mul64(x247, 0xffffffffffffffff)
+ var x293 uint64
+ var x294 uint64
+ x294, x293 = bits.Mul64(x247, 0xffffffffffffffff)
+ var x295 uint64
+ var x296 uint64
+ x296, x295 = bits.Mul64(x247, 0xffffffffffffffff)
+ var x297 uint64
+ var x298 uint64
+ x297, x298 = bits.Add64(x296, x293, uint64(0x0))
+ var x299 uint64
+ var x300 uint64
+ x299, x300 = bits.Add64(x294, x291, uint64(p521Uint1(x298)))
+ var x301 uint64
+ var x302 uint64
+ x301, x302 = bits.Add64(x292, x289, uint64(p521Uint1(x300)))
+ var x303 uint64
+ var x304 uint64
+ x303, x304 = bits.Add64(x290, x287, uint64(p521Uint1(x302)))
+ var x305 uint64
+ var x306 uint64
+ x305, x306 = bits.Add64(x288, x285, uint64(p521Uint1(x304)))
+ var x307 uint64
+ var x308 uint64
+ x307, x308 = bits.Add64(x286, x283, uint64(p521Uint1(x306)))
+ var x309 uint64
+ var x310 uint64
+ x309, x310 = bits.Add64(x284, x281, uint64(p521Uint1(x308)))
+ var x311 uint64
+ var x312 uint64
+ x311, x312 = bits.Add64(x282, x279, uint64(p521Uint1(x310)))
+ var x314 uint64
+ _, x314 = bits.Add64(x247, x295, uint64(0x0))
+ var x315 uint64
+ var x316 uint64
+ x315, x316 = bits.Add64(x265, x297, uint64(p521Uint1(x314)))
+ var x317 uint64
+ var x318 uint64
+ x317, x318 = bits.Add64(x267, x299, uint64(p521Uint1(x316)))
+ var x319 uint64
+ var x320 uint64
+ x319, x320 = bits.Add64(x269, x301, uint64(p521Uint1(x318)))
+ var x321 uint64
+ var x322 uint64
+ x321, x322 = bits.Add64(x271, x303, uint64(p521Uint1(x320)))
+ var x323 uint64
+ var x324 uint64
+ x323, x324 = bits.Add64(x273, x305, uint64(p521Uint1(x322)))
+ var x325 uint64
+ var x326 uint64
+ x325, x326 = bits.Add64(x275, x307, uint64(p521Uint1(x324)))
+ var x327 uint64
+ var x328 uint64
+ x327, x328 = bits.Add64(x277, x309, uint64(p521Uint1(x326)))
+ var x329 uint64
+ var x330 uint64
+ x329, x330 = bits.Add64((uint64(p521Uint1(x278)) + (uint64(p521Uint1(x262)) + (uint64(p521Uint1(x244)) + x212))), x311, uint64(p521Uint1(x328)))
+ var x331 uint64
+ var x332 uint64
+ x332, x331 = bits.Mul64(arg1[6], 0x400000000000)
+ var x333 uint64
+ var x334 uint64
+ x333, x334 = bits.Add64(x317, x331, uint64(0x0))
+ var x335 uint64
+ var x336 uint64
+ x335, x336 = bits.Add64(x319, x332, uint64(p521Uint1(x334)))
+ var x337 uint64
+ var x338 uint64
+ x337, x338 = bits.Add64(x321, uint64(0x0), uint64(p521Uint1(x336)))
+ var x339 uint64
+ var x340 uint64
+ x339, x340 = bits.Add64(x323, uint64(0x0), uint64(p521Uint1(x338)))
+ var x341 uint64
+ var x342 uint64
+ x341, x342 = bits.Add64(x325, uint64(0x0), uint64(p521Uint1(x340)))
+ var x343 uint64
+ var x344 uint64
+ x343, x344 = bits.Add64(x327, uint64(0x0), uint64(p521Uint1(x342)))
+ var x345 uint64
+ var x346 uint64
+ x345, x346 = bits.Add64(x329, uint64(0x0), uint64(p521Uint1(x344)))
+ var x347 uint64
+ var x348 uint64
+ x348, x347 = bits.Mul64(x315, 0x1ff)
+ var x349 uint64
+ var x350 uint64
+ x350, x349 = bits.Mul64(x315, 0xffffffffffffffff)
+ var x351 uint64
+ var x352 uint64
+ x352, x351 = bits.Mul64(x315, 0xffffffffffffffff)
+ var x353 uint64
+ var x354 uint64
+ x354, x353 = bits.Mul64(x315, 0xffffffffffffffff)
+ var x355 uint64
+ var x356 uint64
+ x356, x355 = bits.Mul64(x315, 0xffffffffffffffff)
+ var x357 uint64
+ var x358 uint64
+ x358, x357 = bits.Mul64(x315, 0xffffffffffffffff)
+ var x359 uint64
+ var x360 uint64
+ x360, x359 = bits.Mul64(x315, 0xffffffffffffffff)
+ var x361 uint64
+ var x362 uint64
+ x362, x361 = bits.Mul64(x315, 0xffffffffffffffff)
+ var x363 uint64
+ var x364 uint64
+ x364, x363 = bits.Mul64(x315, 0xffffffffffffffff)
+ var x365 uint64
+ var x366 uint64
+ x365, x366 = bits.Add64(x364, x361, uint64(0x0))
+ var x367 uint64
+ var x368 uint64
+ x367, x368 = bits.Add64(x362, x359, uint64(p521Uint1(x366)))
+ var x369 uint64
+ var x370 uint64
+ x369, x370 = bits.Add64(x360, x357, uint64(p521Uint1(x368)))
+ var x371 uint64
+ var x372 uint64
+ x371, x372 = bits.Add64(x358, x355, uint64(p521Uint1(x370)))
+ var x373 uint64
+ var x374 uint64
+ x373, x374 = bits.Add64(x356, x353, uint64(p521Uint1(x372)))
+ var x375 uint64
+ var x376 uint64
+ x375, x376 = bits.Add64(x354, x351, uint64(p521Uint1(x374)))
+ var x377 uint64
+ var x378 uint64
+ x377, x378 = bits.Add64(x352, x349, uint64(p521Uint1(x376)))
+ var x379 uint64
+ var x380 uint64
+ x379, x380 = bits.Add64(x350, x347, uint64(p521Uint1(x378)))
+ var x382 uint64
+ _, x382 = bits.Add64(x315, x363, uint64(0x0))
+ var x383 uint64
+ var x384 uint64
+ x383, x384 = bits.Add64(x333, x365, uint64(p521Uint1(x382)))
+ var x385 uint64
+ var x386 uint64
+ x385, x386 = bits.Add64(x335, x367, uint64(p521Uint1(x384)))
+ var x387 uint64
+ var x388 uint64
+ x387, x388 = bits.Add64(x337, x369, uint64(p521Uint1(x386)))
+ var x389 uint64
+ var x390 uint64
+ x389, x390 = bits.Add64(x339, x371, uint64(p521Uint1(x388)))
+ var x391 uint64
+ var x392 uint64
+ x391, x392 = bits.Add64(x341, x373, uint64(p521Uint1(x390)))
+ var x393 uint64
+ var x394 uint64
+ x393, x394 = bits.Add64(x343, x375, uint64(p521Uint1(x392)))
+ var x395 uint64
+ var x396 uint64
+ x395, x396 = bits.Add64(x345, x377, uint64(p521Uint1(x394)))
+ var x397 uint64
+ var x398 uint64
+ x397, x398 = bits.Add64((uint64(p521Uint1(x346)) + (uint64(p521Uint1(x330)) + (uint64(p521Uint1(x312)) + x280))), x379, uint64(p521Uint1(x396)))
+ var x399 uint64
+ var x400 uint64
+ x400, x399 = bits.Mul64(arg1[7], 0x400000000000)
+ var x401 uint64
+ var x402 uint64
+ x401, x402 = bits.Add64(x385, x399, uint64(0x0))
+ var x403 uint64
+ var x404 uint64
+ x403, x404 = bits.Add64(x387, x400, uint64(p521Uint1(x402)))
+ var x405 uint64
+ var x406 uint64
+ x405, x406 = bits.Add64(x389, uint64(0x0), uint64(p521Uint1(x404)))
+ var x407 uint64
+ var x408 uint64
+ x407, x408 = bits.Add64(x391, uint64(0x0), uint64(p521Uint1(x406)))
+ var x409 uint64
+ var x410 uint64
+ x409, x410 = bits.Add64(x393, uint64(0x0), uint64(p521Uint1(x408)))
+ var x411 uint64
+ var x412 uint64
+ x411, x412 = bits.Add64(x395, uint64(0x0), uint64(p521Uint1(x410)))
+ var x413 uint64
+ var x414 uint64
+ x413, x414 = bits.Add64(x397, uint64(0x0), uint64(p521Uint1(x412)))
+ var x415 uint64
+ var x416 uint64
+ x416, x415 = bits.Mul64(x383, 0x1ff)
+ var x417 uint64
+ var x418 uint64
+ x418, x417 = bits.Mul64(x383, 0xffffffffffffffff)
+ var x419 uint64
+ var x420 uint64
+ x420, x419 = bits.Mul64(x383, 0xffffffffffffffff)
+ var x421 uint64
+ var x422 uint64
+ x422, x421 = bits.Mul64(x383, 0xffffffffffffffff)
+ var x423 uint64
+ var x424 uint64
+ x424, x423 = bits.Mul64(x383, 0xffffffffffffffff)
+ var x425 uint64
+ var x426 uint64
+ x426, x425 = bits.Mul64(x383, 0xffffffffffffffff)
+ var x427 uint64
+ var x428 uint64
+ x428, x427 = bits.Mul64(x383, 0xffffffffffffffff)
+ var x429 uint64
+ var x430 uint64
+ x430, x429 = bits.Mul64(x383, 0xffffffffffffffff)
+ var x431 uint64
+ var x432 uint64
+ x432, x431 = bits.Mul64(x383, 0xffffffffffffffff)
+ var x433 uint64
+ var x434 uint64
+ x433, x434 = bits.Add64(x432, x429, uint64(0x0))
+ var x435 uint64
+ var x436 uint64
+ x435, x436 = bits.Add64(x430, x427, uint64(p521Uint1(x434)))
+ var x437 uint64
+ var x438 uint64
+ x437, x438 = bits.Add64(x428, x425, uint64(p521Uint1(x436)))
+ var x439 uint64
+ var x440 uint64
+ x439, x440 = bits.Add64(x426, x423, uint64(p521Uint1(x438)))
+ var x441 uint64
+ var x442 uint64
+ x441, x442 = bits.Add64(x424, x421, uint64(p521Uint1(x440)))
+ var x443 uint64
+ var x444 uint64
+ x443, x444 = bits.Add64(x422, x419, uint64(p521Uint1(x442)))
+ var x445 uint64
+ var x446 uint64
+ x445, x446 = bits.Add64(x420, x417, uint64(p521Uint1(x444)))
+ var x447 uint64
+ var x448 uint64
+ x447, x448 = bits.Add64(x418, x415, uint64(p521Uint1(x446)))
+ var x450 uint64
+ _, x450 = bits.Add64(x383, x431, uint64(0x0))
+ var x451 uint64
+ var x452 uint64
+ x451, x452 = bits.Add64(x401, x433, uint64(p521Uint1(x450)))
+ var x453 uint64
+ var x454 uint64
+ x453, x454 = bits.Add64(x403, x435, uint64(p521Uint1(x452)))
+ var x455 uint64
+ var x456 uint64
+ x455, x456 = bits.Add64(x405, x437, uint64(p521Uint1(x454)))
+ var x457 uint64
+ var x458 uint64
+ x457, x458 = bits.Add64(x407, x439, uint64(p521Uint1(x456)))
+ var x459 uint64
+ var x460 uint64
+ x459, x460 = bits.Add64(x409, x441, uint64(p521Uint1(x458)))
+ var x461 uint64
+ var x462 uint64
+ x461, x462 = bits.Add64(x411, x443, uint64(p521Uint1(x460)))
+ var x463 uint64
+ var x464 uint64
+ x463, x464 = bits.Add64(x413, x445, uint64(p521Uint1(x462)))
+ var x465 uint64
+ var x466 uint64
+ x465, x466 = bits.Add64((uint64(p521Uint1(x414)) + (uint64(p521Uint1(x398)) + (uint64(p521Uint1(x380)) + x348))), x447, uint64(p521Uint1(x464)))
+ var x467 uint64
+ var x468 uint64
+ x468, x467 = bits.Mul64(arg1[8], 0x400000000000)
+ var x469 uint64
+ var x470 uint64
+ x469, x470 = bits.Add64(x453, x467, uint64(0x0))
+ var x471 uint64
+ var x472 uint64
+ x471, x472 = bits.Add64(x455, x468, uint64(p521Uint1(x470)))
+ var x473 uint64
+ var x474 uint64
+ x473, x474 = bits.Add64(x457, uint64(0x0), uint64(p521Uint1(x472)))
+ var x475 uint64
+ var x476 uint64
+ x475, x476 = bits.Add64(x459, uint64(0x0), uint64(p521Uint1(x474)))
+ var x477 uint64
+ var x478 uint64
+ x477, x478 = bits.Add64(x461, uint64(0x0), uint64(p521Uint1(x476)))
+ var x479 uint64
+ var x480 uint64
+ x479, x480 = bits.Add64(x463, uint64(0x0), uint64(p521Uint1(x478)))
+ var x481 uint64
+ var x482 uint64
+ x481, x482 = bits.Add64(x465, uint64(0x0), uint64(p521Uint1(x480)))
+ var x483 uint64
+ var x484 uint64
+ x484, x483 = bits.Mul64(x451, 0x1ff)
+ var x485 uint64
+ var x486 uint64
+ x486, x485 = bits.Mul64(x451, 0xffffffffffffffff)
+ var x487 uint64
+ var x488 uint64
+ x488, x487 = bits.Mul64(x451, 0xffffffffffffffff)
+ var x489 uint64
+ var x490 uint64
+ x490, x489 = bits.Mul64(x451, 0xffffffffffffffff)
+ var x491 uint64
+ var x492 uint64
+ x492, x491 = bits.Mul64(x451, 0xffffffffffffffff)
+ var x493 uint64
+ var x494 uint64
+ x494, x493 = bits.Mul64(x451, 0xffffffffffffffff)
+ var x495 uint64
+ var x496 uint64
+ x496, x495 = bits.Mul64(x451, 0xffffffffffffffff)
+ var x497 uint64
+ var x498 uint64
+ x498, x497 = bits.Mul64(x451, 0xffffffffffffffff)
+ var x499 uint64
+ var x500 uint64
+ x500, x499 = bits.Mul64(x451, 0xffffffffffffffff)
+ var x501 uint64
+ var x502 uint64
+ x501, x502 = bits.Add64(x500, x497, uint64(0x0))
+ var x503 uint64
+ var x504 uint64
+ x503, x504 = bits.Add64(x498, x495, uint64(p521Uint1(x502)))
+ var x505 uint64
+ var x506 uint64
+ x505, x506 = bits.Add64(x496, x493, uint64(p521Uint1(x504)))
+ var x507 uint64
+ var x508 uint64
+ x507, x508 = bits.Add64(x494, x491, uint64(p521Uint1(x506)))
+ var x509 uint64
+ var x510 uint64
+ x509, x510 = bits.Add64(x492, x489, uint64(p521Uint1(x508)))
+ var x511 uint64
+ var x512 uint64
+ x511, x512 = bits.Add64(x490, x487, uint64(p521Uint1(x510)))
+ var x513 uint64
+ var x514 uint64
+ x513, x514 = bits.Add64(x488, x485, uint64(p521Uint1(x512)))
+ var x515 uint64
+ var x516 uint64
+ x515, x516 = bits.Add64(x486, x483, uint64(p521Uint1(x514)))
+ var x518 uint64
+ _, x518 = bits.Add64(x451, x499, uint64(0x0))
+ var x519 uint64
+ var x520 uint64
+ x519, x520 = bits.Add64(x469, x501, uint64(p521Uint1(x518)))
+ var x521 uint64
+ var x522 uint64
+ x521, x522 = bits.Add64(x471, x503, uint64(p521Uint1(x520)))
+ var x523 uint64
+ var x524 uint64
+ x523, x524 = bits.Add64(x473, x505, uint64(p521Uint1(x522)))
+ var x525 uint64
+ var x526 uint64
+ x525, x526 = bits.Add64(x475, x507, uint64(p521Uint1(x524)))
+ var x527 uint64
+ var x528 uint64
+ x527, x528 = bits.Add64(x477, x509, uint64(p521Uint1(x526)))
+ var x529 uint64
+ var x530 uint64
+ x529, x530 = bits.Add64(x479, x511, uint64(p521Uint1(x528)))
+ var x531 uint64
+ var x532 uint64
+ x531, x532 = bits.Add64(x481, x513, uint64(p521Uint1(x530)))
+ var x533 uint64
+ var x534 uint64
+ x533, x534 = bits.Add64((uint64(p521Uint1(x482)) + (uint64(p521Uint1(x466)) + (uint64(p521Uint1(x448)) + x416))), x515, uint64(p521Uint1(x532)))
+ x535 := (uint64(p521Uint1(x534)) + (uint64(p521Uint1(x516)) + x484))
+ var x536 uint64
+ var x537 uint64
+ x536, x537 = bits.Sub64(x519, 0xffffffffffffffff, uint64(0x0))
+ var x538 uint64
+ var x539 uint64
+ x538, x539 = bits.Sub64(x521, 0xffffffffffffffff, uint64(p521Uint1(x537)))
+ var x540 uint64
+ var x541 uint64
+ x540, x541 = bits.Sub64(x523, 0xffffffffffffffff, uint64(p521Uint1(x539)))
+ var x542 uint64
+ var x543 uint64
+ x542, x543 = bits.Sub64(x525, 0xffffffffffffffff, uint64(p521Uint1(x541)))
+ var x544 uint64
+ var x545 uint64
+ x544, x545 = bits.Sub64(x527, 0xffffffffffffffff, uint64(p521Uint1(x543)))
+ var x546 uint64
+ var x547 uint64
+ x546, x547 = bits.Sub64(x529, 0xffffffffffffffff, uint64(p521Uint1(x545)))
+ var x548 uint64
+ var x549 uint64
+ x548, x549 = bits.Sub64(x531, 0xffffffffffffffff, uint64(p521Uint1(x547)))
+ var x550 uint64
+ var x551 uint64
+ x550, x551 = bits.Sub64(x533, 0xffffffffffffffff, uint64(p521Uint1(x549)))
+ var x552 uint64
+ var x553 uint64
+ x552, x553 = bits.Sub64(x535, 0x1ff, uint64(p521Uint1(x551)))
+ var x555 uint64
+ _, x555 = bits.Sub64(uint64(0x0), uint64(0x0), uint64(p521Uint1(x553)))
+ var x556 uint64
+ p521CmovznzU64(&x556, p521Uint1(x555), x536, x519)
+ var x557 uint64
+ p521CmovznzU64(&x557, p521Uint1(x555), x538, x521)
+ var x558 uint64
+ p521CmovznzU64(&x558, p521Uint1(x555), x540, x523)
+ var x559 uint64
+ p521CmovznzU64(&x559, p521Uint1(x555), x542, x525)
+ var x560 uint64
+ p521CmovznzU64(&x560, p521Uint1(x555), x544, x527)
+ var x561 uint64
+ p521CmovznzU64(&x561, p521Uint1(x555), x546, x529)
+ var x562 uint64
+ p521CmovznzU64(&x562, p521Uint1(x555), x548, x531)
+ var x563 uint64
+ p521CmovznzU64(&x563, p521Uint1(x555), x550, x533)
+ var x564 uint64
+ p521CmovznzU64(&x564, p521Uint1(x555), x552, x535)
+ out1[0] = x556
+ out1[1] = x557
+ out1[2] = x558
+ out1[3] = x559
+ out1[4] = x560
+ out1[5] = x561
+ out1[6] = x562
+ out1[7] = x563
+ out1[8] = x564
+}
+
+// p521Selectznz is a multi-limb conditional select.
+//
+// Postconditions:
+//
+// eval out1 = (if arg1 = 0 then eval arg2 else eval arg3)
+//
+// Input Bounds:
+//
+// arg1: [0x0 ~> 0x1]
+// arg2: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+// arg3: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+//
+// Output Bounds:
+//
+// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff]]
+func p521Selectznz(out1 *[9]uint64, arg1 p521Uint1, arg2 *[9]uint64, arg3 *[9]uint64) {
+ var x1 uint64
+ p521CmovznzU64(&x1, arg1, arg2[0], arg3[0])
+ var x2 uint64
+ p521CmovznzU64(&x2, arg1, arg2[1], arg3[1])
+ var x3 uint64
+ p521CmovznzU64(&x3, arg1, arg2[2], arg3[2])
+ var x4 uint64
+ p521CmovznzU64(&x4, arg1, arg2[3], arg3[3])
+ var x5 uint64
+ p521CmovznzU64(&x5, arg1, arg2[4], arg3[4])
+ var x6 uint64
+ p521CmovznzU64(&x6, arg1, arg2[5], arg3[5])
+ var x7 uint64
+ p521CmovznzU64(&x7, arg1, arg2[6], arg3[6])
+ var x8 uint64
+ p521CmovznzU64(&x8, arg1, arg2[7], arg3[7])
+ var x9 uint64
+ p521CmovznzU64(&x9, arg1, arg2[8], arg3[8])
+ out1[0] = x1
+ out1[1] = x2
+ out1[2] = x3
+ out1[3] = x4
+ out1[4] = x5
+ out1[5] = x6
+ out1[6] = x7
+ out1[7] = x8
+ out1[8] = x9
+}
+
+// p521ToBytes serializes a field element NOT in the Montgomery domain to bytes in little-endian order.
+//
+// Preconditions:
+//
+// 0 ≤ eval arg1 < m
+//
+// Postconditions:
+//
+// out1 = map (λ x, ⌊((eval arg1 mod m) mod 2^(8 * (x + 1))) / 2^(8 * x)⌋) [0..65]
+//
+// Input Bounds:
+//
+// arg1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0x1ff]]
+//
+// Output Bounds:
+//
+// out1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x1]]
+func p521ToBytes(out1 *[66]uint8, arg1 *[9]uint64) {
+ x1 := arg1[8]
+ x2 := arg1[7]
+ x3 := arg1[6]
+ x4 := arg1[5]
+ x5 := arg1[4]
+ x6 := arg1[3]
+ x7 := arg1[2]
+ x8 := arg1[1]
+ x9 := arg1[0]
+ x10 := (uint8(x9) & 0xff)
+ x11 := (x9 >> 8)
+ x12 := (uint8(x11) & 0xff)
+ x13 := (x11 >> 8)
+ x14 := (uint8(x13) & 0xff)
+ x15 := (x13 >> 8)
+ x16 := (uint8(x15) & 0xff)
+ x17 := (x15 >> 8)
+ x18 := (uint8(x17) & 0xff)
+ x19 := (x17 >> 8)
+ x20 := (uint8(x19) & 0xff)
+ x21 := (x19 >> 8)
+ x22 := (uint8(x21) & 0xff)
+ x23 := uint8((x21 >> 8))
+ x24 := (uint8(x8) & 0xff)
+ x25 := (x8 >> 8)
+ x26 := (uint8(x25) & 0xff)
+ x27 := (x25 >> 8)
+ x28 := (uint8(x27) & 0xff)
+ x29 := (x27 >> 8)
+ x30 := (uint8(x29) & 0xff)
+ x31 := (x29 >> 8)
+ x32 := (uint8(x31) & 0xff)
+ x33 := (x31 >> 8)
+ x34 := (uint8(x33) & 0xff)
+ x35 := (x33 >> 8)
+ x36 := (uint8(x35) & 0xff)
+ x37 := uint8((x35 >> 8))
+ x38 := (uint8(x7) & 0xff)
+ x39 := (x7 >> 8)
+ x40 := (uint8(x39) & 0xff)
+ x41 := (x39 >> 8)
+ x42 := (uint8(x41) & 0xff)
+ x43 := (x41 >> 8)
+ x44 := (uint8(x43) & 0xff)
+ x45 := (x43 >> 8)
+ x46 := (uint8(x45) & 0xff)
+ x47 := (x45 >> 8)
+ x48 := (uint8(x47) & 0xff)
+ x49 := (x47 >> 8)
+ x50 := (uint8(x49) & 0xff)
+ x51 := uint8((x49 >> 8))
+ x52 := (uint8(x6) & 0xff)
+ x53 := (x6 >> 8)
+ x54 := (uint8(x53) & 0xff)
+ x55 := (x53 >> 8)
+ x56 := (uint8(x55) & 0xff)
+ x57 := (x55 >> 8)
+ x58 := (uint8(x57) & 0xff)
+ x59 := (x57 >> 8)
+ x60 := (uint8(x59) & 0xff)
+ x61 := (x59 >> 8)
+ x62 := (uint8(x61) & 0xff)
+ x63 := (x61 >> 8)
+ x64 := (uint8(x63) & 0xff)
+ x65 := uint8((x63 >> 8))
+ x66 := (uint8(x5) & 0xff)
+ x67 := (x5 >> 8)
+ x68 := (uint8(x67) & 0xff)
+ x69 := (x67 >> 8)
+ x70 := (uint8(x69) & 0xff)
+ x71 := (x69 >> 8)
+ x72 := (uint8(x71) & 0xff)
+ x73 := (x71 >> 8)
+ x74 := (uint8(x73) & 0xff)
+ x75 := (x73 >> 8)
+ x76 := (uint8(x75) & 0xff)
+ x77 := (x75 >> 8)
+ x78 := (uint8(x77) & 0xff)
+ x79 := uint8((x77 >> 8))
+ x80 := (uint8(x4) & 0xff)
+ x81 := (x4 >> 8)
+ x82 := (uint8(x81) & 0xff)
+ x83 := (x81 >> 8)
+ x84 := (uint8(x83) & 0xff)
+ x85 := (x83 >> 8)
+ x86 := (uint8(x85) & 0xff)
+ x87 := (x85 >> 8)
+ x88 := (uint8(x87) & 0xff)
+ x89 := (x87 >> 8)
+ x90 := (uint8(x89) & 0xff)
+ x91 := (x89 >> 8)
+ x92 := (uint8(x91) & 0xff)
+ x93 := uint8((x91 >> 8))
+ x94 := (uint8(x3) & 0xff)
+ x95 := (x3 >> 8)
+ x96 := (uint8(x95) & 0xff)
+ x97 := (x95 >> 8)
+ x98 := (uint8(x97) & 0xff)
+ x99 := (x97 >> 8)
+ x100 := (uint8(x99) & 0xff)
+ x101 := (x99 >> 8)
+ x102 := (uint8(x101) & 0xff)
+ x103 := (x101 >> 8)
+ x104 := (uint8(x103) & 0xff)
+ x105 := (x103 >> 8)
+ x106 := (uint8(x105) & 0xff)
+ x107 := uint8((x105 >> 8))
+ x108 := (uint8(x2) & 0xff)
+ x109 := (x2 >> 8)
+ x110 := (uint8(x109) & 0xff)
+ x111 := (x109 >> 8)
+ x112 := (uint8(x111) & 0xff)
+ x113 := (x111 >> 8)
+ x114 := (uint8(x113) & 0xff)
+ x115 := (x113 >> 8)
+ x116 := (uint8(x115) & 0xff)
+ x117 := (x115 >> 8)
+ x118 := (uint8(x117) & 0xff)
+ x119 := (x117 >> 8)
+ x120 := (uint8(x119) & 0xff)
+ x121 := uint8((x119 >> 8))
+ x122 := (uint8(x1) & 0xff)
+ x123 := p521Uint1((x1 >> 8))
+ out1[0] = x10
+ out1[1] = x12
+ out1[2] = x14
+ out1[3] = x16
+ out1[4] = x18
+ out1[5] = x20
+ out1[6] = x22
+ out1[7] = x23
+ out1[8] = x24
+ out1[9] = x26
+ out1[10] = x28
+ out1[11] = x30
+ out1[12] = x32
+ out1[13] = x34
+ out1[14] = x36
+ out1[15] = x37
+ out1[16] = x38
+ out1[17] = x40
+ out1[18] = x42
+ out1[19] = x44
+ out1[20] = x46
+ out1[21] = x48
+ out1[22] = x50
+ out1[23] = x51
+ out1[24] = x52
+ out1[25] = x54
+ out1[26] = x56
+ out1[27] = x58
+ out1[28] = x60
+ out1[29] = x62
+ out1[30] = x64
+ out1[31] = x65
+ out1[32] = x66
+ out1[33] = x68
+ out1[34] = x70
+ out1[35] = x72
+ out1[36] = x74
+ out1[37] = x76
+ out1[38] = x78
+ out1[39] = x79
+ out1[40] = x80
+ out1[41] = x82
+ out1[42] = x84
+ out1[43] = x86
+ out1[44] = x88
+ out1[45] = x90
+ out1[46] = x92
+ out1[47] = x93
+ out1[48] = x94
+ out1[49] = x96
+ out1[50] = x98
+ out1[51] = x100
+ out1[52] = x102
+ out1[53] = x104
+ out1[54] = x106
+ out1[55] = x107
+ out1[56] = x108
+ out1[57] = x110
+ out1[58] = x112
+ out1[59] = x114
+ out1[60] = x116
+ out1[61] = x118
+ out1[62] = x120
+ out1[63] = x121
+ out1[64] = x122
+ out1[65] = uint8(x123)
+}
+
+// p521FromBytes deserializes a field element NOT in the Montgomery domain from bytes in little-endian order.
+//
+// Preconditions:
+//
+// 0 ≤ bytes_eval arg1 < m
+//
+// Postconditions:
+//
+// eval out1 mod m = bytes_eval arg1 mod m
+// 0 ≤ eval out1 < m
+//
+// Input Bounds:
+//
+// arg1: [[0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0xff], [0x0 ~> 0x1]]
+//
+// Output Bounds:
+//
+// out1: [[0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0xffffffffffffffff], [0x0 ~> 0x1ff]]
+func p521FromBytes(out1 *[9]uint64, arg1 *[66]uint8) {
+ x1 := (uint64(p521Uint1(arg1[65])) << 8)
+ x2 := arg1[64]
+ x3 := (uint64(arg1[63]) << 56)
+ x4 := (uint64(arg1[62]) << 48)
+ x5 := (uint64(arg1[61]) << 40)
+ x6 := (uint64(arg1[60]) << 32)
+ x7 := (uint64(arg1[59]) << 24)
+ x8 := (uint64(arg1[58]) << 16)
+ x9 := (uint64(arg1[57]) << 8)
+ x10 := arg1[56]
+ x11 := (uint64(arg1[55]) << 56)
+ x12 := (uint64(arg1[54]) << 48)
+ x13 := (uint64(arg1[53]) << 40)
+ x14 := (uint64(arg1[52]) << 32)
+ x15 := (uint64(arg1[51]) << 24)
+ x16 := (uint64(arg1[50]) << 16)
+ x17 := (uint64(arg1[49]) << 8)
+ x18 := arg1[48]
+ x19 := (uint64(arg1[47]) << 56)
+ x20 := (uint64(arg1[46]) << 48)
+ x21 := (uint64(arg1[45]) << 40)
+ x22 := (uint64(arg1[44]) << 32)
+ x23 := (uint64(arg1[43]) << 24)
+ x24 := (uint64(arg1[42]) << 16)
+ x25 := (uint64(arg1[41]) << 8)
+ x26 := arg1[40]
+ x27 := (uint64(arg1[39]) << 56)
+ x28 := (uint64(arg1[38]) << 48)
+ x29 := (uint64(arg1[37]) << 40)
+ x30 := (uint64(arg1[36]) << 32)
+ x31 := (uint64(arg1[35]) << 24)
+ x32 := (uint64(arg1[34]) << 16)
+ x33 := (uint64(arg1[33]) << 8)
+ x34 := arg1[32]
+ x35 := (uint64(arg1[31]) << 56)
+ x36 := (uint64(arg1[30]) << 48)
+ x37 := (uint64(arg1[29]) << 40)
+ x38 := (uint64(arg1[28]) << 32)
+ x39 := (uint64(arg1[27]) << 24)
+ x40 := (uint64(arg1[26]) << 16)
+ x41 := (uint64(arg1[25]) << 8)
+ x42 := arg1[24]
+ x43 := (uint64(arg1[23]) << 56)
+ x44 := (uint64(arg1[22]) << 48)
+ x45 := (uint64(arg1[21]) << 40)
+ x46 := (uint64(arg1[20]) << 32)
+ x47 := (uint64(arg1[19]) << 24)
+ x48 := (uint64(arg1[18]) << 16)
+ x49 := (uint64(arg1[17]) << 8)
+ x50 := arg1[16]
+ x51 := (uint64(arg1[15]) << 56)
+ x52 := (uint64(arg1[14]) << 48)
+ x53 := (uint64(arg1[13]) << 40)
+ x54 := (uint64(arg1[12]) << 32)
+ x55 := (uint64(arg1[11]) << 24)
+ x56 := (uint64(arg1[10]) << 16)
+ x57 := (uint64(arg1[9]) << 8)
+ x58 := arg1[8]
+ x59 := (uint64(arg1[7]) << 56)
+ x60 := (uint64(arg1[6]) << 48)
+ x61 := (uint64(arg1[5]) << 40)
+ x62 := (uint64(arg1[4]) << 32)
+ x63 := (uint64(arg1[3]) << 24)
+ x64 := (uint64(arg1[2]) << 16)
+ x65 := (uint64(arg1[1]) << 8)
+ x66 := arg1[0]
+ x67 := (x65 + uint64(x66))
+ x68 := (x64 + x67)
+ x69 := (x63 + x68)
+ x70 := (x62 + x69)
+ x71 := (x61 + x70)
+ x72 := (x60 + x71)
+ x73 := (x59 + x72)
+ x74 := (x57 + uint64(x58))
+ x75 := (x56 + x74)
+ x76 := (x55 + x75)
+ x77 := (x54 + x76)
+ x78 := (x53 + x77)
+ x79 := (x52 + x78)
+ x80 := (x51 + x79)
+ x81 := (x49 + uint64(x50))
+ x82 := (x48 + x81)
+ x83 := (x47 + x82)
+ x84 := (x46 + x83)
+ x85 := (x45 + x84)
+ x86 := (x44 + x85)
+ x87 := (x43 + x86)
+ x88 := (x41 + uint64(x42))
+ x89 := (x40 + x88)
+ x90 := (x39 + x89)
+ x91 := (x38 + x90)
+ x92 := (x37 + x91)
+ x93 := (x36 + x92)
+ x94 := (x35 + x93)
+ x95 := (x33 + uint64(x34))
+ x96 := (x32 + x95)
+ x97 := (x31 + x96)
+ x98 := (x30 + x97)
+ x99 := (x29 + x98)
+ x100 := (x28 + x99)
+ x101 := (x27 + x100)
+ x102 := (x25 + uint64(x26))
+ x103 := (x24 + x102)
+ x104 := (x23 + x103)
+ x105 := (x22 + x104)
+ x106 := (x21 + x105)
+ x107 := (x20 + x106)
+ x108 := (x19 + x107)
+ x109 := (x17 + uint64(x18))
+ x110 := (x16 + x109)
+ x111 := (x15 + x110)
+ x112 := (x14 + x111)
+ x113 := (x13 + x112)
+ x114 := (x12 + x113)
+ x115 := (x11 + x114)
+ x116 := (x9 + uint64(x10))
+ x117 := (x8 + x116)
+ x118 := (x7 + x117)
+ x119 := (x6 + x118)
+ x120 := (x5 + x119)
+ x121 := (x4 + x120)
+ x122 := (x3 + x121)
+ x123 := (x1 + uint64(x2))
+ out1[0] = x73
+ out1[1] = x80
+ out1[2] = x87
+ out1[3] = x94
+ out1[4] = x101
+ out1[5] = x108
+ out1[6] = x115
+ out1[7] = x122
+ out1[8] = x123
+}
diff --git a/src/crypto/internal/nistec/fiat/p521_invert.go b/src/crypto/internal/nistec/fiat/p521_invert.go
new file mode 100644
index 0000000..16c53e1
--- /dev/null
+++ b/src/crypto/internal/nistec/fiat/p521_invert.go
@@ -0,0 +1,89 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by addchain. DO NOT EDIT.
+
+package fiat
+
+// Invert sets e = 1/x, and returns e.
+//
+// If x == 0, Invert returns e = 0.
+func (e *P521Element) Invert(x *P521Element) *P521Element {
+ // Inversion is implemented as exponentiation with exponent p − 2.
+ // The sequence of 13 multiplications and 520 squarings is derived from the
+ // following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
+ //
+ // _10 = 2*1
+ // _11 = 1 + _10
+ // _1100 = _11 << 2
+ // _1111 = _11 + _1100
+ // _11110000 = _1111 << 4
+ // _11111111 = _1111 + _11110000
+ // x16 = _11111111 << 8 + _11111111
+ // x32 = x16 << 16 + x16
+ // x64 = x32 << 32 + x32
+ // x65 = 2*x64 + 1
+ // x129 = x65 << 64 + x64
+ // x130 = 2*x129 + 1
+ // x259 = x130 << 129 + x129
+ // x260 = 2*x259 + 1
+ // x519 = x260 << 259 + x259
+ // return x519 << 2 + 1
+ //
+
+ var z = new(P521Element).Set(e)
+ var t0 = new(P521Element)
+
+ z.Square(x)
+ z.Mul(x, z)
+ t0.Square(z)
+ for s := 1; s < 2; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ t0.Square(z)
+ for s := 1; s < 4; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ t0.Square(z)
+ for s := 1; s < 8; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ t0.Square(z)
+ for s := 1; s < 16; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ t0.Square(z)
+ for s := 1; s < 32; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ t0.Square(z)
+ t0.Mul(x, t0)
+ for s := 0; s < 64; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ t0.Square(z)
+ t0.Mul(x, t0)
+ for s := 0; s < 129; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ t0.Square(z)
+ t0.Mul(x, t0)
+ for s := 0; s < 259; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ for s := 0; s < 2; s++ {
+ z.Square(z)
+ }
+ z.Mul(x, z)
+
+ return e.Set(z)
+}
diff --git a/src/crypto/internal/nistec/generate.go b/src/crypto/internal/nistec/generate.go
new file mode 100644
index 0000000..0204bc1
--- /dev/null
+++ b/src/crypto/internal/nistec/generate.go
@@ -0,0 +1,639 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build ignore
+
+package main
+
+// Running this generator requires addchain v0.4.0, which can be installed with
+//
+// go install github.com/mmcloughlin/addchain/cmd/addchain@v0.4.0
+//
+
+import (
+ "bytes"
+ "crypto/elliptic"
+ "fmt"
+ "go/format"
+ "io"
+ "log"
+ "math/big"
+ "os"
+ "os/exec"
+ "strings"
+ "text/template"
+)
+
+var curves = []struct {
+ P string
+ Element string
+ Params *elliptic.CurveParams
+ BuildTags string
+}{
+ {
+ P: "P224",
+ Element: "fiat.P224Element",
+ Params: elliptic.P224().Params(),
+ },
+ {
+ P: "P256",
+ Element: "fiat.P256Element",
+ Params: elliptic.P256().Params(),
+ BuildTags: "!amd64 && !arm64 && !ppc64le",
+ },
+ {
+ P: "P384",
+ Element: "fiat.P384Element",
+ Params: elliptic.P384().Params(),
+ },
+ {
+ P: "P521",
+ Element: "fiat.P521Element",
+ Params: elliptic.P521().Params(),
+ },
+}
+
+func main() {
+ t := template.Must(template.New("tmplNISTEC").Parse(tmplNISTEC))
+
+ tmplAddchainFile, err := os.CreateTemp("", "addchain-template")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer os.Remove(tmplAddchainFile.Name())
+ if _, err := io.WriteString(tmplAddchainFile, tmplAddchain); err != nil {
+ log.Fatal(err)
+ }
+ if err := tmplAddchainFile.Close(); err != nil {
+ log.Fatal(err)
+ }
+
+ for _, c := range curves {
+ p := strings.ToLower(c.P)
+ elementLen := (c.Params.BitSize + 7) / 8
+ B := fmt.Sprintf("%#v", c.Params.B.FillBytes(make([]byte, elementLen)))
+ Gx := fmt.Sprintf("%#v", c.Params.Gx.FillBytes(make([]byte, elementLen)))
+ Gy := fmt.Sprintf("%#v", c.Params.Gy.FillBytes(make([]byte, elementLen)))
+
+ log.Printf("Generating %s.go...", p)
+ f, err := os.Create(p + ".go")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+ buf := &bytes.Buffer{}
+ if err := t.Execute(buf, map[string]interface{}{
+ "P": c.P, "p": p, "B": B, "Gx": Gx, "Gy": Gy,
+ "Element": c.Element, "ElementLen": elementLen,
+ "BuildTags": c.BuildTags,
+ }); err != nil {
+ log.Fatal(err)
+ }
+ out, err := format.Source(buf.Bytes())
+ if err != nil {
+ log.Fatal(err)
+ }
+ if _, err := f.Write(out); err != nil {
+ log.Fatal(err)
+ }
+
+ // If p = 3 mod 4, implement modular square root by exponentiation.
+ mod4 := new(big.Int).Mod(c.Params.P, big.NewInt(4))
+ if mod4.Cmp(big.NewInt(3)) != 0 {
+ continue
+ }
+
+ exp := new(big.Int).Add(c.Params.P, big.NewInt(1))
+ exp.Div(exp, big.NewInt(4))
+
+ tmp, err := os.CreateTemp("", "addchain-"+p)
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer os.Remove(tmp.Name())
+ cmd := exec.Command("addchain", "search", fmt.Sprintf("%d", exp))
+ cmd.Stderr = os.Stderr
+ cmd.Stdout = tmp
+ if err := cmd.Run(); err != nil {
+ log.Fatal(err)
+ }
+ if err := tmp.Close(); err != nil {
+ log.Fatal(err)
+ }
+ cmd = exec.Command("addchain", "gen", "-tmpl", tmplAddchainFile.Name(), tmp.Name())
+ cmd.Stderr = os.Stderr
+ out, err = cmd.Output()
+ if err != nil {
+ log.Fatal(err)
+ }
+ out = bytes.Replace(out, []byte("Element"), []byte(c.Element), -1)
+ out = bytes.Replace(out, []byte("sqrtCandidate"), []byte(p+"SqrtCandidate"), -1)
+ out, err = format.Source(out)
+ if err != nil {
+ log.Fatal(err)
+ }
+ if _, err := f.Write(out); err != nil {
+ log.Fatal(err)
+ }
+ }
+}
+
+const tmplNISTEC = `// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by generate.go. DO NOT EDIT.
+
+{{ if .BuildTags }}
+//go:build {{ .BuildTags }}
+{{ end }}
+
+package nistec
+
+import (
+ "crypto/internal/nistec/fiat"
+ "crypto/subtle"
+ "errors"
+ "sync"
+)
+
+// {{.p}}ElementLength is the length of an element of the base or scalar field,
+// which have the same bytes length for all NIST P curves.
+const {{.p}}ElementLength = {{ .ElementLen }}
+
+// {{.P}}Point is a {{.P}} point. The zero value is NOT valid.
+type {{.P}}Point struct {
+ // The point is represented in projective coordinates (X:Y:Z),
+ // where x = X/Z and y = Y/Z.
+ x, y, z *{{.Element}}
+}
+
+// New{{.P}}Point returns a new {{.P}}Point representing the point at infinity point.
+func New{{.P}}Point() *{{.P}}Point {
+ return &{{.P}}Point{
+ x: new({{.Element}}),
+ y: new({{.Element}}).One(),
+ z: new({{.Element}}),
+ }
+}
+
+// SetGenerator sets p to the canonical generator and returns p.
+func (p *{{.P}}Point) SetGenerator() *{{.P}}Point {
+ p.x.SetBytes({{.Gx}})
+ p.y.SetBytes({{.Gy}})
+ p.z.One()
+ return p
+}
+
+// Set sets p = q and returns p.
+func (p *{{.P}}Point) Set(q *{{.P}}Point) *{{.P}}Point {
+ p.x.Set(q.x)
+ p.y.Set(q.y)
+ p.z.Set(q.z)
+ return p
+}
+
+// SetBytes sets p to the compressed, uncompressed, or infinity value encoded in
+// b, as specified in SEC 1, Version 2.0, Section 2.3.4. If the point is not on
+// the curve, it returns nil and an error, and the receiver is unchanged.
+// Otherwise, it returns p.
+func (p *{{.P}}Point) SetBytes(b []byte) (*{{.P}}Point, error) {
+ switch {
+ // Point at infinity.
+ case len(b) == 1 && b[0] == 0:
+ return p.Set(New{{.P}}Point()), nil
+
+ // Uncompressed form.
+ case len(b) == 1+2*{{.p}}ElementLength && b[0] == 4:
+ x, err := new({{.Element}}).SetBytes(b[1 : 1+{{.p}}ElementLength])
+ if err != nil {
+ return nil, err
+ }
+ y, err := new({{.Element}}).SetBytes(b[1+{{.p}}ElementLength:])
+ if err != nil {
+ return nil, err
+ }
+ if err := {{.p}}CheckOnCurve(x, y); err != nil {
+ return nil, err
+ }
+ p.x.Set(x)
+ p.y.Set(y)
+ p.z.One()
+ return p, nil
+
+ // Compressed form.
+ case len(b) == 1+{{.p}}ElementLength && (b[0] == 2 || b[0] == 3):
+ x, err := new({{.Element}}).SetBytes(b[1:])
+ if err != nil {
+ return nil, err
+ }
+
+ // y² = x³ - 3x + b
+ y := {{.p}}Polynomial(new({{.Element}}), x)
+ if !{{.p}}Sqrt(y, y) {
+ return nil, errors.New("invalid {{.P}} compressed point encoding")
+ }
+
+ // Select the positive or negative root, as indicated by the least
+ // significant bit, based on the encoding type byte.
+ otherRoot := new({{.Element}})
+ otherRoot.Sub(otherRoot, y)
+ cond := y.Bytes()[{{.p}}ElementLength-1]&1 ^ b[0]&1
+ y.Select(otherRoot, y, int(cond))
+
+ p.x.Set(x)
+ p.y.Set(y)
+ p.z.One()
+ return p, nil
+
+ default:
+ return nil, errors.New("invalid {{.P}} point encoding")
+ }
+}
+
+
+var _{{.p}}B *{{.Element}}
+var _{{.p}}BOnce sync.Once
+
+func {{.p}}B() *{{.Element}} {
+ _{{.p}}BOnce.Do(func() {
+ _{{.p}}B, _ = new({{.Element}}).SetBytes({{.B}})
+ })
+ return _{{.p}}B
+}
+
+// {{.p}}Polynomial sets y2 to x³ - 3x + b, and returns y2.
+func {{.p}}Polynomial(y2, x *{{.Element}}) *{{.Element}} {
+ y2.Square(x)
+ y2.Mul(y2, x)
+
+ threeX := new({{.Element}}).Add(x, x)
+ threeX.Add(threeX, x)
+ y2.Sub(y2, threeX)
+
+ return y2.Add(y2, {{.p}}B())
+}
+
+func {{.p}}CheckOnCurve(x, y *{{.Element}}) error {
+ // y² = x³ - 3x + b
+ rhs := {{.p}}Polynomial(new({{.Element}}), x)
+ lhs := new({{.Element}}).Square(y)
+ if rhs.Equal(lhs) != 1 {
+ return errors.New("{{.P}} point not on curve")
+ }
+ return nil
+}
+
+// Bytes returns the uncompressed or infinity encoding of p, as specified in
+// SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at
+// infinity is shorter than all other encodings.
+func (p *{{.P}}Point) Bytes() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [1+2*{{.p}}ElementLength]byte
+ return p.bytes(&out)
+}
+
+func (p *{{.P}}Point) bytes(out *[1+2*{{.p}}ElementLength]byte) []byte {
+ if p.z.IsZero() == 1 {
+ return append(out[:0], 0)
+ }
+
+ zinv := new({{.Element}}).Invert(p.z)
+ x := new({{.Element}}).Mul(p.x, zinv)
+ y := new({{.Element}}).Mul(p.y, zinv)
+
+ buf := append(out[:0], 4)
+ buf = append(buf, x.Bytes()...)
+ buf = append(buf, y.Bytes()...)
+ return buf
+}
+
+// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
+// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
+func (p *{{.P}}Point) BytesX() ([]byte, error) {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [{{.p}}ElementLength]byte
+ return p.bytesX(&out)
+}
+
+func (p *{{.P}}Point) bytesX(out *[{{.p}}ElementLength]byte) ([]byte, error) {
+ if p.z.IsZero() == 1 {
+ return nil, errors.New("{{.P}} point is the point at infinity")
+ }
+
+ zinv := new({{.Element}}).Invert(p.z)
+ x := new({{.Element}}).Mul(p.x, zinv)
+
+ return append(out[:0], x.Bytes()...), nil
+}
+
+// BytesCompressed returns the compressed or infinity encoding of p, as
+// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
+// point at infinity is shorter than all other encodings.
+func (p *{{.P}}Point) BytesCompressed() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [1 + {{.p}}ElementLength]byte
+ return p.bytesCompressed(&out)
+}
+
+func (p *{{.P}}Point) bytesCompressed(out *[1 + {{.p}}ElementLength]byte) []byte {
+ if p.z.IsZero() == 1 {
+ return append(out[:0], 0)
+ }
+
+ zinv := new({{.Element}}).Invert(p.z)
+ x := new({{.Element}}).Mul(p.x, zinv)
+ y := new({{.Element}}).Mul(p.y, zinv)
+
+ // Encode the sign of the y coordinate (indicated by the least significant
+ // bit) as the encoding type (2 or 3).
+ buf := append(out[:0], 2)
+ buf[0] |= y.Bytes()[{{.p}}ElementLength-1] & 1
+ buf = append(buf, x.Bytes()...)
+ return buf
+}
+
+// Add sets q = p1 + p2, and returns q. The points may overlap.
+func (q *{{.P}}Point) Add(p1, p2 *{{.P}}Point) *{{.P}}Point {
+ // Complete addition formula for a = -3 from "Complete addition formulas for
+ // prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
+
+ t0 := new({{.Element}}).Mul(p1.x, p2.x) // t0 := X1 * X2
+ t1 := new({{.Element}}).Mul(p1.y, p2.y) // t1 := Y1 * Y2
+ t2 := new({{.Element}}).Mul(p1.z, p2.z) // t2 := Z1 * Z2
+ t3 := new({{.Element}}).Add(p1.x, p1.y) // t3 := X1 + Y1
+ t4 := new({{.Element}}).Add(p2.x, p2.y) // t4 := X2 + Y2
+ t3.Mul(t3, t4) // t3 := t3 * t4
+ t4.Add(t0, t1) // t4 := t0 + t1
+ t3.Sub(t3, t4) // t3 := t3 - t4
+ t4.Add(p1.y, p1.z) // t4 := Y1 + Z1
+ x3 := new({{.Element}}).Add(p2.y, p2.z) // X3 := Y2 + Z2
+ t4.Mul(t4, x3) // t4 := t4 * X3
+ x3.Add(t1, t2) // X3 := t1 + t2
+ t4.Sub(t4, x3) // t4 := t4 - X3
+ x3.Add(p1.x, p1.z) // X3 := X1 + Z1
+ y3 := new({{.Element}}).Add(p2.x, p2.z) // Y3 := X2 + Z2
+ x3.Mul(x3, y3) // X3 := X3 * Y3
+ y3.Add(t0, t2) // Y3 := t0 + t2
+ y3.Sub(x3, y3) // Y3 := X3 - Y3
+ z3 := new({{.Element}}).Mul({{.p}}B(), t2) // Z3 := b * t2
+ x3.Sub(y3, z3) // X3 := Y3 - Z3
+ z3.Add(x3, x3) // Z3 := X3 + X3
+ x3.Add(x3, z3) // X3 := X3 + Z3
+ z3.Sub(t1, x3) // Z3 := t1 - X3
+ x3.Add(t1, x3) // X3 := t1 + X3
+ y3.Mul({{.p}}B(), y3) // Y3 := b * Y3
+ t1.Add(t2, t2) // t1 := t2 + t2
+ t2.Add(t1, t2) // t2 := t1 + t2
+ y3.Sub(y3, t2) // Y3 := Y3 - t2
+ y3.Sub(y3, t0) // Y3 := Y3 - t0
+ t1.Add(y3, y3) // t1 := Y3 + Y3
+ y3.Add(t1, y3) // Y3 := t1 + Y3
+ t1.Add(t0, t0) // t1 := t0 + t0
+ t0.Add(t1, t0) // t0 := t1 + t0
+ t0.Sub(t0, t2) // t0 := t0 - t2
+ t1.Mul(t4, y3) // t1 := t4 * Y3
+ t2.Mul(t0, y3) // t2 := t0 * Y3
+ y3.Mul(x3, z3) // Y3 := X3 * Z3
+ y3.Add(y3, t2) // Y3 := Y3 + t2
+ x3.Mul(t3, x3) // X3 := t3 * X3
+ x3.Sub(x3, t1) // X3 := X3 - t1
+ z3.Mul(t4, z3) // Z3 := t4 * Z3
+ t1.Mul(t3, t0) // t1 := t3 * t0
+ z3.Add(z3, t1) // Z3 := Z3 + t1
+
+ q.x.Set(x3)
+ q.y.Set(y3)
+ q.z.Set(z3)
+ return q
+}
+
+// Double sets q = p + p, and returns q. The points may overlap.
+func (q *{{.P}}Point) Double(p *{{.P}}Point) *{{.P}}Point {
+ // Complete addition formula for a = -3 from "Complete addition formulas for
+ // prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
+
+ t0 := new({{.Element}}).Square(p.x) // t0 := X ^ 2
+ t1 := new({{.Element}}).Square(p.y) // t1 := Y ^ 2
+ t2 := new({{.Element}}).Square(p.z) // t2 := Z ^ 2
+ t3 := new({{.Element}}).Mul(p.x, p.y) // t3 := X * Y
+ t3.Add(t3, t3) // t3 := t3 + t3
+ z3 := new({{.Element}}).Mul(p.x, p.z) // Z3 := X * Z
+ z3.Add(z3, z3) // Z3 := Z3 + Z3
+ y3 := new({{.Element}}).Mul({{.p}}B(), t2) // Y3 := b * t2
+ y3.Sub(y3, z3) // Y3 := Y3 - Z3
+ x3 := new({{.Element}}).Add(y3, y3) // X3 := Y3 + Y3
+ y3.Add(x3, y3) // Y3 := X3 + Y3
+ x3.Sub(t1, y3) // X3 := t1 - Y3
+ y3.Add(t1, y3) // Y3 := t1 + Y3
+ y3.Mul(x3, y3) // Y3 := X3 * Y3
+ x3.Mul(x3, t3) // X3 := X3 * t3
+ t3.Add(t2, t2) // t3 := t2 + t2
+ t2.Add(t2, t3) // t2 := t2 + t3
+ z3.Mul({{.p}}B(), z3) // Z3 := b * Z3
+ z3.Sub(z3, t2) // Z3 := Z3 - t2
+ z3.Sub(z3, t0) // Z3 := Z3 - t0
+ t3.Add(z3, z3) // t3 := Z3 + Z3
+ z3.Add(z3, t3) // Z3 := Z3 + t3
+ t3.Add(t0, t0) // t3 := t0 + t0
+ t0.Add(t3, t0) // t0 := t3 + t0
+ t0.Sub(t0, t2) // t0 := t0 - t2
+ t0.Mul(t0, z3) // t0 := t0 * Z3
+ y3.Add(y3, t0) // Y3 := Y3 + t0
+ t0.Mul(p.y, p.z) // t0 := Y * Z
+ t0.Add(t0, t0) // t0 := t0 + t0
+ z3.Mul(t0, z3) // Z3 := t0 * Z3
+ x3.Sub(x3, z3) // X3 := X3 - Z3
+ z3.Mul(t0, t1) // Z3 := t0 * t1
+ z3.Add(z3, z3) // Z3 := Z3 + Z3
+ z3.Add(z3, z3) // Z3 := Z3 + Z3
+
+ q.x.Set(x3)
+ q.y.Set(y3)
+ q.z.Set(z3)
+ return q
+}
+
+// Select sets q to p1 if cond == 1, and to p2 if cond == 0.
+func (q *{{.P}}Point) Select(p1, p2 *{{.P}}Point, cond int) *{{.P}}Point {
+ q.x.Select(p1.x, p2.x, cond)
+ q.y.Select(p1.y, p2.y, cond)
+ q.z.Select(p1.z, p2.z, cond)
+ return q
+}
+
+// A {{.p}}Table holds the first 15 multiples of a point at offset -1, so [1]P
+// is at table[0], [15]P is at table[14], and [0]P is implicitly the identity
+// point.
+type {{.p}}Table [15]*{{.P}}Point
+
+// Select selects the n-th multiple of the table base point into p. It works in
+// constant time by iterating over every entry of the table. n must be in [0, 15].
+func (table *{{.p}}Table) Select(p *{{.P}}Point, n uint8) {
+ if n >= 16 {
+ panic("nistec: internal error: {{.p}}Table called with out-of-bounds value")
+ }
+ p.Set(New{{.P}}Point())
+ for i := uint8(1); i < 16; i++ {
+ cond := subtle.ConstantTimeByteEq(i, n)
+ p.Select(table[i-1], p, cond)
+ }
+}
+
+// ScalarMult sets p = scalar * q, and returns p.
+func (p *{{.P}}Point) ScalarMult(q *{{.P}}Point, scalar []byte) (*{{.P}}Point, error) {
+ // Compute a {{.p}}Table for the base point q. The explicit New{{.P}}Point
+ // calls get inlined, letting the allocations live on the stack.
+ var table = {{.p}}Table{New{{.P}}Point(), New{{.P}}Point(), New{{.P}}Point(),
+ New{{.P}}Point(), New{{.P}}Point(), New{{.P}}Point(), New{{.P}}Point(),
+ New{{.P}}Point(), New{{.P}}Point(), New{{.P}}Point(), New{{.P}}Point(),
+ New{{.P}}Point(), New{{.P}}Point(), New{{.P}}Point(), New{{.P}}Point()}
+ table[0].Set(q)
+ for i := 1; i < 15; i += 2 {
+ table[i].Double(table[i/2])
+ table[i+1].Add(table[i], q)
+ }
+
+ // Instead of doing the classic double-and-add chain, we do it with a
+ // four-bit window: we double four times, and then add [0-15]P.
+ t := New{{.P}}Point()
+ p.Set(New{{.P}}Point())
+ for i, byte := range scalar {
+ // No need to double on the first iteration, as p is the identity at
+ // this point, and [N]∞ = ∞.
+ if i != 0 {
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+ }
+
+ windowValue := byte >> 4
+ table.Select(t, windowValue)
+ p.Add(p, t)
+
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+
+ windowValue = byte & 0b1111
+ table.Select(t, windowValue)
+ p.Add(p, t)
+ }
+
+ return p, nil
+}
+
+var {{.p}}GeneratorTable *[{{.p}}ElementLength * 2]{{.p}}Table
+var {{.p}}GeneratorTableOnce sync.Once
+
+// generatorTable returns a sequence of {{.p}}Tables. The first table contains
+// multiples of G. Each successive table is the previous table doubled four
+// times.
+func (p *{{.P}}Point) generatorTable() *[{{.p}}ElementLength * 2]{{.p}}Table {
+ {{.p}}GeneratorTableOnce.Do(func() {
+ {{.p}}GeneratorTable = new([{{.p}}ElementLength * 2]{{.p}}Table)
+ base := New{{.P}}Point().SetGenerator()
+ for i := 0; i < {{.p}}ElementLength*2; i++ {
+ {{.p}}GeneratorTable[i][0] = New{{.P}}Point().Set(base)
+ for j := 1; j < 15; j++ {
+ {{.p}}GeneratorTable[i][j] = New{{.P}}Point().Add({{.p}}GeneratorTable[i][j-1], base)
+ }
+ base.Double(base)
+ base.Double(base)
+ base.Double(base)
+ base.Double(base)
+ }
+ })
+ return {{.p}}GeneratorTable
+}
+
+// ScalarBaseMult sets p = scalar * B, where B is the canonical generator, and
+// returns p.
+func (p *{{.P}}Point) ScalarBaseMult(scalar []byte) (*{{.P}}Point, error) {
+ if len(scalar) != {{.p}}ElementLength {
+ return nil, errors.New("invalid scalar length")
+ }
+ tables := p.generatorTable()
+
+ // This is also a scalar multiplication with a four-bit window like in
+ // ScalarMult, but in this case the doublings are precomputed. The value
+ // [windowValue]G added at iteration k would normally get doubled
+ // (totIterations-k)×4 times, but with a larger precomputation we can
+ // instead add [2^((totIterations-k)×4)][windowValue]G and avoid the
+ // doublings between iterations.
+ t := New{{.P}}Point()
+ p.Set(New{{.P}}Point())
+ tableIndex := len(tables) - 1
+ for _, byte := range scalar {
+ windowValue := byte >> 4
+ tables[tableIndex].Select(t, windowValue)
+ p.Add(p, t)
+ tableIndex--
+
+ windowValue = byte & 0b1111
+ tables[tableIndex].Select(t, windowValue)
+ p.Add(p, t)
+ tableIndex--
+ }
+
+ return p, nil
+}
+
+// {{.p}}Sqrt sets e to a square root of x. If x is not a square, {{.p}}Sqrt returns
+// false and e is unchanged. e and x can overlap.
+func {{.p}}Sqrt(e, x *{{ .Element }}) (isSquare bool) {
+ candidate := new({{ .Element }})
+ {{.p}}SqrtCandidate(candidate, x)
+ square := new({{ .Element }}).Square(candidate)
+ if square.Equal(x) != 1 {
+ return false
+ }
+ e.Set(candidate)
+ return true
+}
+`
+
+const tmplAddchain = `
+// sqrtCandidate sets z to a square root candidate for x. z and x must not overlap.
+func sqrtCandidate(z, x *Element) {
+ // Since p = 3 mod 4, exponentiation by (p + 1) / 4 yields a square root candidate.
+ //
+ // The sequence of {{ .Ops.Adds }} multiplications and {{ .Ops.Doubles }} squarings is derived from the
+ // following addition chain generated with {{ .Meta.Module }} {{ .Meta.ReleaseTag }}.
+ //
+ {{- range lines (format .Script) }}
+ // {{ . }}
+ {{- end }}
+ //
+
+ {{- range .Program.Temporaries }}
+ var {{ . }} = new(Element)
+ {{- end }}
+ {{ range $i := .Program.Instructions -}}
+ {{- with add $i.Op }}
+ {{ $i.Output }}.Mul({{ .X }}, {{ .Y }})
+ {{- end -}}
+
+ {{- with double $i.Op }}
+ {{ $i.Output }}.Square({{ .X }})
+ {{- end -}}
+
+ {{- with shift $i.Op -}}
+ {{- $first := 0 -}}
+ {{- if ne $i.Output.Identifier .X.Identifier }}
+ {{ $i.Output }}.Square({{ .X }})
+ {{- $first = 1 -}}
+ {{- end }}
+ for s := {{ $first }}; s < {{ .S }}; s++ {
+ {{ $i.Output }}.Square({{ $i.Output }})
+ }
+ {{- end -}}
+ {{- end }}
+}
+`
diff --git a/src/crypto/internal/nistec/nistec.go b/src/crypto/internal/nistec/nistec.go
new file mode 100644
index 0000000..d898d40
--- /dev/null
+++ b/src/crypto/internal/nistec/nistec.go
@@ -0,0 +1,15 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package nistec implements the NIST P elliptic curves from FIPS 186-4.
+//
+// This package uses fiat-crypto or specialized assembly and Go code for its
+// backend field arithmetic (not math/big) and exposes constant-time, heap
+// allocation-free, byte slice-based safe APIs. Group operations use modern and
+// safe complete addition formulas where possible. The point at infinity is
+// handled and encoded according to SEC 1, Version 2.0, and invalid curve points
+// can't be represented.
+package nistec
+
+//go:generate go run generate.go
diff --git a/src/crypto/internal/nistec/nistec_test.go b/src/crypto/internal/nistec/nistec_test.go
new file mode 100644
index 0000000..9103608
--- /dev/null
+++ b/src/crypto/internal/nistec/nistec_test.go
@@ -0,0 +1,297 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package nistec_test
+
+import (
+ "bytes"
+ "crypto/elliptic"
+ "crypto/internal/nistec"
+ "fmt"
+ "internal/testenv"
+ "math/big"
+ "math/rand"
+ "testing"
+)
+
+func TestAllocations(t *testing.T) {
+ testenv.SkipIfOptimizationOff(t)
+
+ t.Run("P224", func(t *testing.T) {
+ if allocs := testing.AllocsPerRun(100, func() {
+ p := nistec.NewP224Point().SetGenerator()
+ scalar := make([]byte, 28)
+ rand.Read(scalar)
+ p.ScalarBaseMult(scalar)
+ p.ScalarMult(p, scalar)
+ out := p.Bytes()
+ if _, err := nistec.NewP224Point().SetBytes(out); err != nil {
+ t.Fatal(err)
+ }
+ out = p.BytesCompressed()
+ if _, err := p.SetBytes(out); err != nil {
+ t.Fatal(err)
+ }
+ }); allocs > 0 {
+ t.Errorf("expected zero allocations, got %0.1f", allocs)
+ }
+ })
+ t.Run("P256", func(t *testing.T) {
+ if allocs := testing.AllocsPerRun(100, func() {
+ p := nistec.NewP256Point().SetGenerator()
+ scalar := make([]byte, 32)
+ rand.Read(scalar)
+ p.ScalarBaseMult(scalar)
+ p.ScalarMult(p, scalar)
+ out := p.Bytes()
+ if _, err := nistec.NewP256Point().SetBytes(out); err != nil {
+ t.Fatal(err)
+ }
+ out = p.BytesCompressed()
+ if _, err := p.SetBytes(out); err != nil {
+ t.Fatal(err)
+ }
+ }); allocs > 0 {
+ t.Errorf("expected zero allocations, got %0.1f", allocs)
+ }
+ })
+ t.Run("P384", func(t *testing.T) {
+ if allocs := testing.AllocsPerRun(100, func() {
+ p := nistec.NewP384Point().SetGenerator()
+ scalar := make([]byte, 48)
+ rand.Read(scalar)
+ p.ScalarBaseMult(scalar)
+ p.ScalarMult(p, scalar)
+ out := p.Bytes()
+ if _, err := nistec.NewP384Point().SetBytes(out); err != nil {
+ t.Fatal(err)
+ }
+ out = p.BytesCompressed()
+ if _, err := p.SetBytes(out); err != nil {
+ t.Fatal(err)
+ }
+ }); allocs > 0 {
+ t.Errorf("expected zero allocations, got %0.1f", allocs)
+ }
+ })
+ t.Run("P521", func(t *testing.T) {
+ if allocs := testing.AllocsPerRun(100, func() {
+ p := nistec.NewP521Point().SetGenerator()
+ scalar := make([]byte, 66)
+ rand.Read(scalar)
+ p.ScalarBaseMult(scalar)
+ p.ScalarMult(p, scalar)
+ out := p.Bytes()
+ if _, err := nistec.NewP521Point().SetBytes(out); err != nil {
+ t.Fatal(err)
+ }
+ out = p.BytesCompressed()
+ if _, err := p.SetBytes(out); err != nil {
+ t.Fatal(err)
+ }
+ }); allocs > 0 {
+ t.Errorf("expected zero allocations, got %0.1f", allocs)
+ }
+ })
+}
+
+type nistPoint[T any] interface {
+ Bytes() []byte
+ SetGenerator() T
+ SetBytes([]byte) (T, error)
+ Add(T, T) T
+ Double(T) T
+ ScalarMult(T, []byte) (T, error)
+ ScalarBaseMult([]byte) (T, error)
+}
+
+func TestEquivalents(t *testing.T) {
+ t.Run("P224", func(t *testing.T) {
+ testEquivalents(t, nistec.NewP224Point, elliptic.P224())
+ })
+ t.Run("P256", func(t *testing.T) {
+ testEquivalents(t, nistec.NewP256Point, elliptic.P256())
+ })
+ t.Run("P384", func(t *testing.T) {
+ testEquivalents(t, nistec.NewP384Point, elliptic.P384())
+ })
+ t.Run("P521", func(t *testing.T) {
+ testEquivalents(t, nistec.NewP521Point, elliptic.P521())
+ })
+}
+
+func testEquivalents[P nistPoint[P]](t *testing.T, newPoint func() P, c elliptic.Curve) {
+ p := newPoint().SetGenerator()
+
+ elementSize := (c.Params().BitSize + 7) / 8
+ two := make([]byte, elementSize)
+ two[len(two)-1] = 2
+ nPlusTwo := make([]byte, elementSize)
+ new(big.Int).Add(c.Params().N, big.NewInt(2)).FillBytes(nPlusTwo)
+
+ p1 := newPoint().Double(p)
+ p2 := newPoint().Add(p, p)
+ p3, err := newPoint().ScalarMult(p, two)
+ if err != nil {
+ t.Fatal(err)
+ }
+ p4, err := newPoint().ScalarBaseMult(two)
+ if err != nil {
+ t.Fatal(err)
+ }
+ p5, err := newPoint().ScalarMult(p, nPlusTwo)
+ if err != nil {
+ t.Fatal(err)
+ }
+ p6, err := newPoint().ScalarBaseMult(nPlusTwo)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if !bytes.Equal(p1.Bytes(), p2.Bytes()) {
+ t.Error("P+P != 2*P")
+ }
+ if !bytes.Equal(p1.Bytes(), p3.Bytes()) {
+ t.Error("P+P != [2]P")
+ }
+ if !bytes.Equal(p1.Bytes(), p4.Bytes()) {
+ t.Error("G+G != [2]G")
+ }
+ if !bytes.Equal(p1.Bytes(), p5.Bytes()) {
+ t.Error("P+P != [N+2]P")
+ }
+ if !bytes.Equal(p1.Bytes(), p6.Bytes()) {
+ t.Error("G+G != [N+2]G")
+ }
+}
+
+func TestScalarMult(t *testing.T) {
+ t.Run("P224", func(t *testing.T) {
+ testScalarMult(t, nistec.NewP224Point, elliptic.P224())
+ })
+ t.Run("P256", func(t *testing.T) {
+ testScalarMult(t, nistec.NewP256Point, elliptic.P256())
+ })
+ t.Run("P384", func(t *testing.T) {
+ testScalarMult(t, nistec.NewP384Point, elliptic.P384())
+ })
+ t.Run("P521", func(t *testing.T) {
+ testScalarMult(t, nistec.NewP521Point, elliptic.P521())
+ })
+}
+
+func testScalarMult[P nistPoint[P]](t *testing.T, newPoint func() P, c elliptic.Curve) {
+ G := newPoint().SetGenerator()
+ checkScalar := func(t *testing.T, scalar []byte) {
+ p1, err := newPoint().ScalarBaseMult(scalar)
+ fatalIfErr(t, err)
+ p2, err := newPoint().ScalarMult(G, scalar)
+ fatalIfErr(t, err)
+ if !bytes.Equal(p1.Bytes(), p2.Bytes()) {
+ t.Error("[k]G != ScalarBaseMult(k)")
+ }
+
+ d := new(big.Int).SetBytes(scalar)
+ d.Sub(c.Params().N, d)
+ d.Mod(d, c.Params().N)
+ g1, err := newPoint().ScalarBaseMult(d.FillBytes(make([]byte, len(scalar))))
+ fatalIfErr(t, err)
+ g1.Add(g1, p1)
+ if !bytes.Equal(g1.Bytes(), newPoint().Bytes()) {
+ t.Error("[N - k]G + [k]G != ∞")
+ }
+ }
+
+ byteLen := len(c.Params().N.Bytes())
+ bitLen := c.Params().N.BitLen()
+ t.Run("0", func(t *testing.T) { checkScalar(t, make([]byte, byteLen)) })
+ t.Run("1", func(t *testing.T) {
+ checkScalar(t, big.NewInt(1).FillBytes(make([]byte, byteLen)))
+ })
+ t.Run("N-1", func(t *testing.T) {
+ checkScalar(t, new(big.Int).Sub(c.Params().N, big.NewInt(1)).Bytes())
+ })
+ t.Run("N", func(t *testing.T) { checkScalar(t, c.Params().N.Bytes()) })
+ t.Run("N+1", func(t *testing.T) {
+ checkScalar(t, new(big.Int).Add(c.Params().N, big.NewInt(1)).Bytes())
+ })
+ t.Run("all1s", func(t *testing.T) {
+ s := new(big.Int).Lsh(big.NewInt(1), uint(bitLen))
+ s.Sub(s, big.NewInt(1))
+ checkScalar(t, s.Bytes())
+ })
+ if testing.Short() {
+ return
+ }
+ for i := 0; i < bitLen; i++ {
+ t.Run(fmt.Sprintf("1<<%d", i), func(t *testing.T) {
+ s := new(big.Int).Lsh(big.NewInt(1), uint(i))
+ checkScalar(t, s.FillBytes(make([]byte, byteLen)))
+ })
+ }
+ // Test N+1...N+32 since they risk overlapping with precomputed table values
+ // in the final additions.
+ for i := int64(2); i <= 32; i++ {
+ t.Run(fmt.Sprintf("N+%d", i), func(t *testing.T) {
+ checkScalar(t, new(big.Int).Add(c.Params().N, big.NewInt(i)).Bytes())
+ })
+ }
+}
+
+func fatalIfErr(t *testing.T, err error) {
+ t.Helper()
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func BenchmarkScalarMult(b *testing.B) {
+ b.Run("P224", func(b *testing.B) {
+ benchmarkScalarMult(b, nistec.NewP224Point().SetGenerator(), 28)
+ })
+ b.Run("P256", func(b *testing.B) {
+ benchmarkScalarMult(b, nistec.NewP256Point().SetGenerator(), 32)
+ })
+ b.Run("P384", func(b *testing.B) {
+ benchmarkScalarMult(b, nistec.NewP384Point().SetGenerator(), 48)
+ })
+ b.Run("P521", func(b *testing.B) {
+ benchmarkScalarMult(b, nistec.NewP521Point().SetGenerator(), 66)
+ })
+}
+
+func benchmarkScalarMult[P nistPoint[P]](b *testing.B, p P, scalarSize int) {
+ scalar := make([]byte, scalarSize)
+ rand.Read(scalar)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ p.ScalarMult(p, scalar)
+ }
+}
+
+func BenchmarkScalarBaseMult(b *testing.B) {
+ b.Run("P224", func(b *testing.B) {
+ benchmarkScalarBaseMult(b, nistec.NewP224Point().SetGenerator(), 28)
+ })
+ b.Run("P256", func(b *testing.B) {
+ benchmarkScalarBaseMult(b, nistec.NewP256Point().SetGenerator(), 32)
+ })
+ b.Run("P384", func(b *testing.B) {
+ benchmarkScalarBaseMult(b, nistec.NewP384Point().SetGenerator(), 48)
+ })
+ b.Run("P521", func(b *testing.B) {
+ benchmarkScalarBaseMult(b, nistec.NewP521Point().SetGenerator(), 66)
+ })
+}
+
+func benchmarkScalarBaseMult[P nistPoint[P]](b *testing.B, p P, scalarSize int) {
+ scalar := make([]byte, scalarSize)
+ rand.Read(scalar)
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ p.ScalarBaseMult(scalar)
+ }
+}
diff --git a/src/crypto/internal/nistec/p224.go b/src/crypto/internal/nistec/p224.go
new file mode 100644
index 0000000..faa971d
--- /dev/null
+++ b/src/crypto/internal/nistec/p224.go
@@ -0,0 +1,453 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by generate.go. DO NOT EDIT.
+
+package nistec
+
+import (
+ "crypto/internal/nistec/fiat"
+ "crypto/subtle"
+ "errors"
+ "sync"
+)
+
+// p224ElementLength is the length of an element of the base or scalar field,
+// which have the same bytes length for all NIST P curves.
+const p224ElementLength = 28
+
+// P224Point is a P224 point. The zero value is NOT valid.
+type P224Point struct {
+ // The point is represented in projective coordinates (X:Y:Z),
+ // where x = X/Z and y = Y/Z.
+ x, y, z *fiat.P224Element
+}
+
+// NewP224Point returns a new P224Point representing the point at infinity point.
+func NewP224Point() *P224Point {
+ return &P224Point{
+ x: new(fiat.P224Element),
+ y: new(fiat.P224Element).One(),
+ z: new(fiat.P224Element),
+ }
+}
+
+// SetGenerator sets p to the canonical generator and returns p.
+func (p *P224Point) SetGenerator() *P224Point {
+ p.x.SetBytes([]byte{0xb7, 0xe, 0xc, 0xbd, 0x6b, 0xb4, 0xbf, 0x7f, 0x32, 0x13, 0x90, 0xb9, 0x4a, 0x3, 0xc1, 0xd3, 0x56, 0xc2, 0x11, 0x22, 0x34, 0x32, 0x80, 0xd6, 0x11, 0x5c, 0x1d, 0x21})
+ p.y.SetBytes([]byte{0xbd, 0x37, 0x63, 0x88, 0xb5, 0xf7, 0x23, 0xfb, 0x4c, 0x22, 0xdf, 0xe6, 0xcd, 0x43, 0x75, 0xa0, 0x5a, 0x7, 0x47, 0x64, 0x44, 0xd5, 0x81, 0x99, 0x85, 0x0, 0x7e, 0x34})
+ p.z.One()
+ return p
+}
+
+// Set sets p = q and returns p.
+func (p *P224Point) Set(q *P224Point) *P224Point {
+ p.x.Set(q.x)
+ p.y.Set(q.y)
+ p.z.Set(q.z)
+ return p
+}
+
+// SetBytes sets p to the compressed, uncompressed, or infinity value encoded in
+// b, as specified in SEC 1, Version 2.0, Section 2.3.4. If the point is not on
+// the curve, it returns nil and an error, and the receiver is unchanged.
+// Otherwise, it returns p.
+func (p *P224Point) SetBytes(b []byte) (*P224Point, error) {
+ switch {
+ // Point at infinity.
+ case len(b) == 1 && b[0] == 0:
+ return p.Set(NewP224Point()), nil
+
+ // Uncompressed form.
+ case len(b) == 1+2*p224ElementLength && b[0] == 4:
+ x, err := new(fiat.P224Element).SetBytes(b[1 : 1+p224ElementLength])
+ if err != nil {
+ return nil, err
+ }
+ y, err := new(fiat.P224Element).SetBytes(b[1+p224ElementLength:])
+ if err != nil {
+ return nil, err
+ }
+ if err := p224CheckOnCurve(x, y); err != nil {
+ return nil, err
+ }
+ p.x.Set(x)
+ p.y.Set(y)
+ p.z.One()
+ return p, nil
+
+ // Compressed form.
+ case len(b) == 1+p224ElementLength && (b[0] == 2 || b[0] == 3):
+ x, err := new(fiat.P224Element).SetBytes(b[1:])
+ if err != nil {
+ return nil, err
+ }
+
+ // y² = x³ - 3x + b
+ y := p224Polynomial(new(fiat.P224Element), x)
+ if !p224Sqrt(y, y) {
+ return nil, errors.New("invalid P224 compressed point encoding")
+ }
+
+ // Select the positive or negative root, as indicated by the least
+ // significant bit, based on the encoding type byte.
+ otherRoot := new(fiat.P224Element)
+ otherRoot.Sub(otherRoot, y)
+ cond := y.Bytes()[p224ElementLength-1]&1 ^ b[0]&1
+ y.Select(otherRoot, y, int(cond))
+
+ p.x.Set(x)
+ p.y.Set(y)
+ p.z.One()
+ return p, nil
+
+ default:
+ return nil, errors.New("invalid P224 point encoding")
+ }
+}
+
+var _p224B *fiat.P224Element
+var _p224BOnce sync.Once
+
+func p224B() *fiat.P224Element {
+ _p224BOnce.Do(func() {
+ _p224B, _ = new(fiat.P224Element).SetBytes([]byte{0xb4, 0x5, 0xa, 0x85, 0xc, 0x4, 0xb3, 0xab, 0xf5, 0x41, 0x32, 0x56, 0x50, 0x44, 0xb0, 0xb7, 0xd7, 0xbf, 0xd8, 0xba, 0x27, 0xb, 0x39, 0x43, 0x23, 0x55, 0xff, 0xb4})
+ })
+ return _p224B
+}
+
+// p224Polynomial sets y2 to x³ - 3x + b, and returns y2.
+func p224Polynomial(y2, x *fiat.P224Element) *fiat.P224Element {
+ y2.Square(x)
+ y2.Mul(y2, x)
+
+ threeX := new(fiat.P224Element).Add(x, x)
+ threeX.Add(threeX, x)
+ y2.Sub(y2, threeX)
+
+ return y2.Add(y2, p224B())
+}
+
+func p224CheckOnCurve(x, y *fiat.P224Element) error {
+ // y² = x³ - 3x + b
+ rhs := p224Polynomial(new(fiat.P224Element), x)
+ lhs := new(fiat.P224Element).Square(y)
+ if rhs.Equal(lhs) != 1 {
+ return errors.New("P224 point not on curve")
+ }
+ return nil
+}
+
+// Bytes returns the uncompressed or infinity encoding of p, as specified in
+// SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at
+// infinity is shorter than all other encodings.
+func (p *P224Point) Bytes() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [1 + 2*p224ElementLength]byte
+ return p.bytes(&out)
+}
+
+func (p *P224Point) bytes(out *[1 + 2*p224ElementLength]byte) []byte {
+ if p.z.IsZero() == 1 {
+ return append(out[:0], 0)
+ }
+
+ zinv := new(fiat.P224Element).Invert(p.z)
+ x := new(fiat.P224Element).Mul(p.x, zinv)
+ y := new(fiat.P224Element).Mul(p.y, zinv)
+
+ buf := append(out[:0], 4)
+ buf = append(buf, x.Bytes()...)
+ buf = append(buf, y.Bytes()...)
+ return buf
+}
+
+// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
+// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
+func (p *P224Point) BytesX() ([]byte, error) {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [p224ElementLength]byte
+ return p.bytesX(&out)
+}
+
+func (p *P224Point) bytesX(out *[p224ElementLength]byte) ([]byte, error) {
+ if p.z.IsZero() == 1 {
+ return nil, errors.New("P224 point is the point at infinity")
+ }
+
+ zinv := new(fiat.P224Element).Invert(p.z)
+ x := new(fiat.P224Element).Mul(p.x, zinv)
+
+ return append(out[:0], x.Bytes()...), nil
+}
+
+// BytesCompressed returns the compressed or infinity encoding of p, as
+// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
+// point at infinity is shorter than all other encodings.
+func (p *P224Point) BytesCompressed() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [1 + p224ElementLength]byte
+ return p.bytesCompressed(&out)
+}
+
+func (p *P224Point) bytesCompressed(out *[1 + p224ElementLength]byte) []byte {
+ if p.z.IsZero() == 1 {
+ return append(out[:0], 0)
+ }
+
+ zinv := new(fiat.P224Element).Invert(p.z)
+ x := new(fiat.P224Element).Mul(p.x, zinv)
+ y := new(fiat.P224Element).Mul(p.y, zinv)
+
+ // Encode the sign of the y coordinate (indicated by the least significant
+ // bit) as the encoding type (2 or 3).
+ buf := append(out[:0], 2)
+ buf[0] |= y.Bytes()[p224ElementLength-1] & 1
+ buf = append(buf, x.Bytes()...)
+ return buf
+}
+
+// Add sets q = p1 + p2, and returns q. The points may overlap.
+func (q *P224Point) Add(p1, p2 *P224Point) *P224Point {
+ // Complete addition formula for a = -3 from "Complete addition formulas for
+ // prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
+
+ t0 := new(fiat.P224Element).Mul(p1.x, p2.x) // t0 := X1 * X2
+ t1 := new(fiat.P224Element).Mul(p1.y, p2.y) // t1 := Y1 * Y2
+ t2 := new(fiat.P224Element).Mul(p1.z, p2.z) // t2 := Z1 * Z2
+ t3 := new(fiat.P224Element).Add(p1.x, p1.y) // t3 := X1 + Y1
+ t4 := new(fiat.P224Element).Add(p2.x, p2.y) // t4 := X2 + Y2
+ t3.Mul(t3, t4) // t3 := t3 * t4
+ t4.Add(t0, t1) // t4 := t0 + t1
+ t3.Sub(t3, t4) // t3 := t3 - t4
+ t4.Add(p1.y, p1.z) // t4 := Y1 + Z1
+ x3 := new(fiat.P224Element).Add(p2.y, p2.z) // X3 := Y2 + Z2
+ t4.Mul(t4, x3) // t4 := t4 * X3
+ x3.Add(t1, t2) // X3 := t1 + t2
+ t4.Sub(t4, x3) // t4 := t4 - X3
+ x3.Add(p1.x, p1.z) // X3 := X1 + Z1
+ y3 := new(fiat.P224Element).Add(p2.x, p2.z) // Y3 := X2 + Z2
+ x3.Mul(x3, y3) // X3 := X3 * Y3
+ y3.Add(t0, t2) // Y3 := t0 + t2
+ y3.Sub(x3, y3) // Y3 := X3 - Y3
+ z3 := new(fiat.P224Element).Mul(p224B(), t2) // Z3 := b * t2
+ x3.Sub(y3, z3) // X3 := Y3 - Z3
+ z3.Add(x3, x3) // Z3 := X3 + X3
+ x3.Add(x3, z3) // X3 := X3 + Z3
+ z3.Sub(t1, x3) // Z3 := t1 - X3
+ x3.Add(t1, x3) // X3 := t1 + X3
+ y3.Mul(p224B(), y3) // Y3 := b * Y3
+ t1.Add(t2, t2) // t1 := t2 + t2
+ t2.Add(t1, t2) // t2 := t1 + t2
+ y3.Sub(y3, t2) // Y3 := Y3 - t2
+ y3.Sub(y3, t0) // Y3 := Y3 - t0
+ t1.Add(y3, y3) // t1 := Y3 + Y3
+ y3.Add(t1, y3) // Y3 := t1 + Y3
+ t1.Add(t0, t0) // t1 := t0 + t0
+ t0.Add(t1, t0) // t0 := t1 + t0
+ t0.Sub(t0, t2) // t0 := t0 - t2
+ t1.Mul(t4, y3) // t1 := t4 * Y3
+ t2.Mul(t0, y3) // t2 := t0 * Y3
+ y3.Mul(x3, z3) // Y3 := X3 * Z3
+ y3.Add(y3, t2) // Y3 := Y3 + t2
+ x3.Mul(t3, x3) // X3 := t3 * X3
+ x3.Sub(x3, t1) // X3 := X3 - t1
+ z3.Mul(t4, z3) // Z3 := t4 * Z3
+ t1.Mul(t3, t0) // t1 := t3 * t0
+ z3.Add(z3, t1) // Z3 := Z3 + t1
+
+ q.x.Set(x3)
+ q.y.Set(y3)
+ q.z.Set(z3)
+ return q
+}
+
+// Double sets q = p + p, and returns q. The points may overlap.
+func (q *P224Point) Double(p *P224Point) *P224Point {
+ // Complete addition formula for a = -3 from "Complete addition formulas for
+ // prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
+
+ t0 := new(fiat.P224Element).Square(p.x) // t0 := X ^ 2
+ t1 := new(fiat.P224Element).Square(p.y) // t1 := Y ^ 2
+ t2 := new(fiat.P224Element).Square(p.z) // t2 := Z ^ 2
+ t3 := new(fiat.P224Element).Mul(p.x, p.y) // t3 := X * Y
+ t3.Add(t3, t3) // t3 := t3 + t3
+ z3 := new(fiat.P224Element).Mul(p.x, p.z) // Z3 := X * Z
+ z3.Add(z3, z3) // Z3 := Z3 + Z3
+ y3 := new(fiat.P224Element).Mul(p224B(), t2) // Y3 := b * t2
+ y3.Sub(y3, z3) // Y3 := Y3 - Z3
+ x3 := new(fiat.P224Element).Add(y3, y3) // X3 := Y3 + Y3
+ y3.Add(x3, y3) // Y3 := X3 + Y3
+ x3.Sub(t1, y3) // X3 := t1 - Y3
+ y3.Add(t1, y3) // Y3 := t1 + Y3
+ y3.Mul(x3, y3) // Y3 := X3 * Y3
+ x3.Mul(x3, t3) // X3 := X3 * t3
+ t3.Add(t2, t2) // t3 := t2 + t2
+ t2.Add(t2, t3) // t2 := t2 + t3
+ z3.Mul(p224B(), z3) // Z3 := b * Z3
+ z3.Sub(z3, t2) // Z3 := Z3 - t2
+ z3.Sub(z3, t0) // Z3 := Z3 - t0
+ t3.Add(z3, z3) // t3 := Z3 + Z3
+ z3.Add(z3, t3) // Z3 := Z3 + t3
+ t3.Add(t0, t0) // t3 := t0 + t0
+ t0.Add(t3, t0) // t0 := t3 + t0
+ t0.Sub(t0, t2) // t0 := t0 - t2
+ t0.Mul(t0, z3) // t0 := t0 * Z3
+ y3.Add(y3, t0) // Y3 := Y3 + t0
+ t0.Mul(p.y, p.z) // t0 := Y * Z
+ t0.Add(t0, t0) // t0 := t0 + t0
+ z3.Mul(t0, z3) // Z3 := t0 * Z3
+ x3.Sub(x3, z3) // X3 := X3 - Z3
+ z3.Mul(t0, t1) // Z3 := t0 * t1
+ z3.Add(z3, z3) // Z3 := Z3 + Z3
+ z3.Add(z3, z3) // Z3 := Z3 + Z3
+
+ q.x.Set(x3)
+ q.y.Set(y3)
+ q.z.Set(z3)
+ return q
+}
+
+// Select sets q to p1 if cond == 1, and to p2 if cond == 0.
+func (q *P224Point) Select(p1, p2 *P224Point, cond int) *P224Point {
+ q.x.Select(p1.x, p2.x, cond)
+ q.y.Select(p1.y, p2.y, cond)
+ q.z.Select(p1.z, p2.z, cond)
+ return q
+}
+
+// A p224Table holds the first 15 multiples of a point at offset -1, so [1]P
+// is at table[0], [15]P is at table[14], and [0]P is implicitly the identity
+// point.
+type p224Table [15]*P224Point
+
+// Select selects the n-th multiple of the table base point into p. It works in
+// constant time by iterating over every entry of the table. n must be in [0, 15].
+func (table *p224Table) Select(p *P224Point, n uint8) {
+ if n >= 16 {
+ panic("nistec: internal error: p224Table called with out-of-bounds value")
+ }
+ p.Set(NewP224Point())
+ for i := uint8(1); i < 16; i++ {
+ cond := subtle.ConstantTimeByteEq(i, n)
+ p.Select(table[i-1], p, cond)
+ }
+}
+
+// ScalarMult sets p = scalar * q, and returns p.
+func (p *P224Point) ScalarMult(q *P224Point, scalar []byte) (*P224Point, error) {
+ // Compute a p224Table for the base point q. The explicit NewP224Point
+ // calls get inlined, letting the allocations live on the stack.
+ var table = p224Table{NewP224Point(), NewP224Point(), NewP224Point(),
+ NewP224Point(), NewP224Point(), NewP224Point(), NewP224Point(),
+ NewP224Point(), NewP224Point(), NewP224Point(), NewP224Point(),
+ NewP224Point(), NewP224Point(), NewP224Point(), NewP224Point()}
+ table[0].Set(q)
+ for i := 1; i < 15; i += 2 {
+ table[i].Double(table[i/2])
+ table[i+1].Add(table[i], q)
+ }
+
+ // Instead of doing the classic double-and-add chain, we do it with a
+ // four-bit window: we double four times, and then add [0-15]P.
+ t := NewP224Point()
+ p.Set(NewP224Point())
+ for i, byte := range scalar {
+ // No need to double on the first iteration, as p is the identity at
+ // this point, and [N]∞ = ∞.
+ if i != 0 {
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+ }
+
+ windowValue := byte >> 4
+ table.Select(t, windowValue)
+ p.Add(p, t)
+
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+
+ windowValue = byte & 0b1111
+ table.Select(t, windowValue)
+ p.Add(p, t)
+ }
+
+ return p, nil
+}
+
+var p224GeneratorTable *[p224ElementLength * 2]p224Table
+var p224GeneratorTableOnce sync.Once
+
+// generatorTable returns a sequence of p224Tables. The first table contains
+// multiples of G. Each successive table is the previous table doubled four
+// times.
+func (p *P224Point) generatorTable() *[p224ElementLength * 2]p224Table {
+ p224GeneratorTableOnce.Do(func() {
+ p224GeneratorTable = new([p224ElementLength * 2]p224Table)
+ base := NewP224Point().SetGenerator()
+ for i := 0; i < p224ElementLength*2; i++ {
+ p224GeneratorTable[i][0] = NewP224Point().Set(base)
+ for j := 1; j < 15; j++ {
+ p224GeneratorTable[i][j] = NewP224Point().Add(p224GeneratorTable[i][j-1], base)
+ }
+ base.Double(base)
+ base.Double(base)
+ base.Double(base)
+ base.Double(base)
+ }
+ })
+ return p224GeneratorTable
+}
+
+// ScalarBaseMult sets p = scalar * B, where B is the canonical generator, and
+// returns p.
+func (p *P224Point) ScalarBaseMult(scalar []byte) (*P224Point, error) {
+ if len(scalar) != p224ElementLength {
+ return nil, errors.New("invalid scalar length")
+ }
+ tables := p.generatorTable()
+
+ // This is also a scalar multiplication with a four-bit window like in
+ // ScalarMult, but in this case the doublings are precomputed. The value
+ // [windowValue]G added at iteration k would normally get doubled
+ // (totIterations-k)×4 times, but with a larger precomputation we can
+ // instead add [2^((totIterations-k)×4)][windowValue]G and avoid the
+ // doublings between iterations.
+ t := NewP224Point()
+ p.Set(NewP224Point())
+ tableIndex := len(tables) - 1
+ for _, byte := range scalar {
+ windowValue := byte >> 4
+ tables[tableIndex].Select(t, windowValue)
+ p.Add(p, t)
+ tableIndex--
+
+ windowValue = byte & 0b1111
+ tables[tableIndex].Select(t, windowValue)
+ p.Add(p, t)
+ tableIndex--
+ }
+
+ return p, nil
+}
+
+// p224Sqrt sets e to a square root of x. If x is not a square, p224Sqrt returns
+// false and e is unchanged. e and x can overlap.
+func p224Sqrt(e, x *fiat.P224Element) (isSquare bool) {
+ candidate := new(fiat.P224Element)
+ p224SqrtCandidate(candidate, x)
+ square := new(fiat.P224Element).Square(candidate)
+ if square.Equal(x) != 1 {
+ return false
+ }
+ e.Set(candidate)
+ return true
+}
diff --git a/src/crypto/internal/nistec/p224_sqrt.go b/src/crypto/internal/nistec/p224_sqrt.go
new file mode 100644
index 0000000..0c77579
--- /dev/null
+++ b/src/crypto/internal/nistec/p224_sqrt.go
@@ -0,0 +1,132 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package nistec
+
+import (
+ "crypto/internal/nistec/fiat"
+ "sync"
+)
+
+var p224GG *[96]fiat.P224Element
+var p224GGOnce sync.Once
+
+// p224SqrtCandidate sets r to a square root candidate for x. r and x must not overlap.
+func p224SqrtCandidate(r, x *fiat.P224Element) {
+ // Since p = 1 mod 4, we can't use the exponentiation by (p + 1) / 4 like
+ // for the other primes. Instead, implement a variation of Tonelli–Shanks.
+ // The constant-time implementation is adapted from Thomas Pornin's ecGFp5.
+ //
+ // https://github.com/pornin/ecgfp5/blob/82325b965/rust/src/field.rs#L337-L385
+
+ // p = q*2^n + 1 with q odd -> q = 2^128 - 1 and n = 96
+ // g^(2^n) = 1 -> g = 11 ^ q (where 11 is the smallest non-square)
+ // GG[j] = g^(2^j) for j = 0 to n-1
+
+ p224GGOnce.Do(func() {
+ p224GG = new([96]fiat.P224Element)
+ for i := range p224GG {
+ if i == 0 {
+ p224GG[i].SetBytes([]byte{0x6a, 0x0f, 0xec, 0x67,
+ 0x85, 0x98, 0xa7, 0x92, 0x0c, 0x55, 0xb2, 0xd4,
+ 0x0b, 0x2d, 0x6f, 0xfb, 0xbe, 0xa3, 0xd8, 0xce,
+ 0xf3, 0xfb, 0x36, 0x32, 0xdc, 0x69, 0x1b, 0x74})
+ } else {
+ p224GG[i].Square(&p224GG[i-1])
+ }
+ }
+ })
+
+ // r <- x^((q+1)/2) = x^(2^127)
+ // v <- x^q = x^(2^128-1)
+
+ // Compute x^(2^127-1) first.
+ //
+ // The sequence of 10 multiplications and 126 squarings is derived from the
+ // following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
+ //
+ // _10 = 2*1
+ // _11 = 1 + _10
+ // _110 = 2*_11
+ // _111 = 1 + _110
+ // _111000 = _111 << 3
+ // _111111 = _111 + _111000
+ // _1111110 = 2*_111111
+ // _1111111 = 1 + _1111110
+ // x12 = _1111110 << 5 + _111111
+ // x24 = x12 << 12 + x12
+ // i36 = x24 << 7
+ // x31 = _1111111 + i36
+ // x48 = i36 << 17 + x24
+ // x96 = x48 << 48 + x48
+ // return x96 << 31 + x31
+ //
+ var t0 = new(fiat.P224Element)
+ var t1 = new(fiat.P224Element)
+
+ r.Square(x)
+ r.Mul(x, r)
+ r.Square(r)
+ r.Mul(x, r)
+ t0.Square(r)
+ for s := 1; s < 3; s++ {
+ t0.Square(t0)
+ }
+ t0.Mul(r, t0)
+ t1.Square(t0)
+ r.Mul(x, t1)
+ for s := 0; s < 5; s++ {
+ t1.Square(t1)
+ }
+ t0.Mul(t0, t1)
+ t1.Square(t0)
+ for s := 1; s < 12; s++ {
+ t1.Square(t1)
+ }
+ t0.Mul(t0, t1)
+ t1.Square(t0)
+ for s := 1; s < 7; s++ {
+ t1.Square(t1)
+ }
+ r.Mul(r, t1)
+ for s := 0; s < 17; s++ {
+ t1.Square(t1)
+ }
+ t0.Mul(t0, t1)
+ t1.Square(t0)
+ for s := 1; s < 48; s++ {
+ t1.Square(t1)
+ }
+ t0.Mul(t0, t1)
+ for s := 0; s < 31; s++ {
+ t0.Square(t0)
+ }
+ r.Mul(r, t0)
+
+ // v = x^(2^127-1)^2 * x
+ v := new(fiat.P224Element).Square(r)
+ v.Mul(v, x)
+
+ // r = x^(2^127-1) * x
+ r.Mul(r, x)
+
+ // for i = n-1 down to 1:
+ // w = v^(2^(i-1))
+ // if w == -1 then:
+ // v <- v*GG[n-i]
+ // r <- r*GG[n-i-1]
+
+ var p224MinusOne = new(fiat.P224Element).Sub(
+ new(fiat.P224Element), new(fiat.P224Element).One())
+
+ for i := 96 - 1; i >= 1; i-- {
+ w := new(fiat.P224Element).Set(v)
+ for j := 0; j < i-1; j++ {
+ w.Square(w)
+ }
+ cond := w.Equal(p224MinusOne)
+ v.Select(t0.Mul(v, &p224GG[96-i]), v, cond)
+ r.Select(t0.Mul(r, &p224GG[96-i-1]), r, cond)
+ }
+}
diff --git a/src/crypto/internal/nistec/p256.go b/src/crypto/internal/nistec/p256.go
new file mode 100644
index 0000000..3cfa5fb
--- /dev/null
+++ b/src/crypto/internal/nistec/p256.go
@@ -0,0 +1,509 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by generate.go. DO NOT EDIT.
+
+//go:build !amd64 && !arm64 && !ppc64le && !s390x
+
+package nistec
+
+import (
+ "crypto/internal/nistec/fiat"
+ "crypto/subtle"
+ "errors"
+ "sync"
+)
+
+// p256ElementLength is the length of an element of the base or scalar field,
+// which have the same bytes length for all NIST P curves.
+const p256ElementLength = 32
+
+// P256Point is a P256 point. The zero value is NOT valid.
+type P256Point struct {
+ // The point is represented in projective coordinates (X:Y:Z),
+ // where x = X/Z and y = Y/Z.
+ x, y, z *fiat.P256Element
+}
+
+// NewP256Point returns a new P256Point representing the point at infinity point.
+func NewP256Point() *P256Point {
+ return &P256Point{
+ x: new(fiat.P256Element),
+ y: new(fiat.P256Element).One(),
+ z: new(fiat.P256Element),
+ }
+}
+
+// SetGenerator sets p to the canonical generator and returns p.
+func (p *P256Point) SetGenerator() *P256Point {
+ p.x.SetBytes([]byte{0x6b, 0x17, 0xd1, 0xf2, 0xe1, 0x2c, 0x42, 0x47, 0xf8, 0xbc, 0xe6, 0xe5, 0x63, 0xa4, 0x40, 0xf2, 0x77, 0x3, 0x7d, 0x81, 0x2d, 0xeb, 0x33, 0xa0, 0xf4, 0xa1, 0x39, 0x45, 0xd8, 0x98, 0xc2, 0x96})
+ p.y.SetBytes([]byte{0x4f, 0xe3, 0x42, 0xe2, 0xfe, 0x1a, 0x7f, 0x9b, 0x8e, 0xe7, 0xeb, 0x4a, 0x7c, 0xf, 0x9e, 0x16, 0x2b, 0xce, 0x33, 0x57, 0x6b, 0x31, 0x5e, 0xce, 0xcb, 0xb6, 0x40, 0x68, 0x37, 0xbf, 0x51, 0xf5})
+ p.z.One()
+ return p
+}
+
+// Set sets p = q and returns p.
+func (p *P256Point) Set(q *P256Point) *P256Point {
+ p.x.Set(q.x)
+ p.y.Set(q.y)
+ p.z.Set(q.z)
+ return p
+}
+
+// SetBytes sets p to the compressed, uncompressed, or infinity value encoded in
+// b, as specified in SEC 1, Version 2.0, Section 2.3.4. If the point is not on
+// the curve, it returns nil and an error, and the receiver is unchanged.
+// Otherwise, it returns p.
+func (p *P256Point) SetBytes(b []byte) (*P256Point, error) {
+ switch {
+ // Point at infinity.
+ case len(b) == 1 && b[0] == 0:
+ return p.Set(NewP256Point()), nil
+
+ // Uncompressed form.
+ case len(b) == 1+2*p256ElementLength && b[0] == 4:
+ x, err := new(fiat.P256Element).SetBytes(b[1 : 1+p256ElementLength])
+ if err != nil {
+ return nil, err
+ }
+ y, err := new(fiat.P256Element).SetBytes(b[1+p256ElementLength:])
+ if err != nil {
+ return nil, err
+ }
+ if err := p256CheckOnCurve(x, y); err != nil {
+ return nil, err
+ }
+ p.x.Set(x)
+ p.y.Set(y)
+ p.z.One()
+ return p, nil
+
+ // Compressed form.
+ case len(b) == 1+p256ElementLength && (b[0] == 2 || b[0] == 3):
+ x, err := new(fiat.P256Element).SetBytes(b[1:])
+ if err != nil {
+ return nil, err
+ }
+
+ // y² = x³ - 3x + b
+ y := p256Polynomial(new(fiat.P256Element), x)
+ if !p256Sqrt(y, y) {
+ return nil, errors.New("invalid P256 compressed point encoding")
+ }
+
+ // Select the positive or negative root, as indicated by the least
+ // significant bit, based on the encoding type byte.
+ otherRoot := new(fiat.P256Element)
+ otherRoot.Sub(otherRoot, y)
+ cond := y.Bytes()[p256ElementLength-1]&1 ^ b[0]&1
+ y.Select(otherRoot, y, int(cond))
+
+ p.x.Set(x)
+ p.y.Set(y)
+ p.z.One()
+ return p, nil
+
+ default:
+ return nil, errors.New("invalid P256 point encoding")
+ }
+}
+
+var _p256B *fiat.P256Element
+var _p256BOnce sync.Once
+
+func p256B() *fiat.P256Element {
+ _p256BOnce.Do(func() {
+ _p256B, _ = new(fiat.P256Element).SetBytes([]byte{0x5a, 0xc6, 0x35, 0xd8, 0xaa, 0x3a, 0x93, 0xe7, 0xb3, 0xeb, 0xbd, 0x55, 0x76, 0x98, 0x86, 0xbc, 0x65, 0x1d, 0x6, 0xb0, 0xcc, 0x53, 0xb0, 0xf6, 0x3b, 0xce, 0x3c, 0x3e, 0x27, 0xd2, 0x60, 0x4b})
+ })
+ return _p256B
+}
+
+// p256Polynomial sets y2 to x³ - 3x + b, and returns y2.
+func p256Polynomial(y2, x *fiat.P256Element) *fiat.P256Element {
+ y2.Square(x)
+ y2.Mul(y2, x)
+
+ threeX := new(fiat.P256Element).Add(x, x)
+ threeX.Add(threeX, x)
+ y2.Sub(y2, threeX)
+
+ return y2.Add(y2, p256B())
+}
+
+func p256CheckOnCurve(x, y *fiat.P256Element) error {
+ // y² = x³ - 3x + b
+ rhs := p256Polynomial(new(fiat.P256Element), x)
+ lhs := new(fiat.P256Element).Square(y)
+ if rhs.Equal(lhs) != 1 {
+ return errors.New("P256 point not on curve")
+ }
+ return nil
+}
+
+// Bytes returns the uncompressed or infinity encoding of p, as specified in
+// SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at
+// infinity is shorter than all other encodings.
+func (p *P256Point) Bytes() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [1 + 2*p256ElementLength]byte
+ return p.bytes(&out)
+}
+
+func (p *P256Point) bytes(out *[1 + 2*p256ElementLength]byte) []byte {
+ if p.z.IsZero() == 1 {
+ return append(out[:0], 0)
+ }
+
+ zinv := new(fiat.P256Element).Invert(p.z)
+ x := new(fiat.P256Element).Mul(p.x, zinv)
+ y := new(fiat.P256Element).Mul(p.y, zinv)
+
+ buf := append(out[:0], 4)
+ buf = append(buf, x.Bytes()...)
+ buf = append(buf, y.Bytes()...)
+ return buf
+}
+
+// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
+// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
+func (p *P256Point) BytesX() ([]byte, error) {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [p256ElementLength]byte
+ return p.bytesX(&out)
+}
+
+func (p *P256Point) bytesX(out *[p256ElementLength]byte) ([]byte, error) {
+ if p.z.IsZero() == 1 {
+ return nil, errors.New("P256 point is the point at infinity")
+ }
+
+ zinv := new(fiat.P256Element).Invert(p.z)
+ x := new(fiat.P256Element).Mul(p.x, zinv)
+
+ return append(out[:0], x.Bytes()...), nil
+}
+
+// BytesCompressed returns the compressed or infinity encoding of p, as
+// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
+// point at infinity is shorter than all other encodings.
+func (p *P256Point) BytesCompressed() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [1 + p256ElementLength]byte
+ return p.bytesCompressed(&out)
+}
+
+func (p *P256Point) bytesCompressed(out *[1 + p256ElementLength]byte) []byte {
+ if p.z.IsZero() == 1 {
+ return append(out[:0], 0)
+ }
+
+ zinv := new(fiat.P256Element).Invert(p.z)
+ x := new(fiat.P256Element).Mul(p.x, zinv)
+ y := new(fiat.P256Element).Mul(p.y, zinv)
+
+ // Encode the sign of the y coordinate (indicated by the least significant
+ // bit) as the encoding type (2 or 3).
+ buf := append(out[:0], 2)
+ buf[0] |= y.Bytes()[p256ElementLength-1] & 1
+ buf = append(buf, x.Bytes()...)
+ return buf
+}
+
+// Add sets q = p1 + p2, and returns q. The points may overlap.
+func (q *P256Point) Add(p1, p2 *P256Point) *P256Point {
+ // Complete addition formula for a = -3 from "Complete addition formulas for
+ // prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
+
+ t0 := new(fiat.P256Element).Mul(p1.x, p2.x) // t0 := X1 * X2
+ t1 := new(fiat.P256Element).Mul(p1.y, p2.y) // t1 := Y1 * Y2
+ t2 := new(fiat.P256Element).Mul(p1.z, p2.z) // t2 := Z1 * Z2
+ t3 := new(fiat.P256Element).Add(p1.x, p1.y) // t3 := X1 + Y1
+ t4 := new(fiat.P256Element).Add(p2.x, p2.y) // t4 := X2 + Y2
+ t3.Mul(t3, t4) // t3 := t3 * t4
+ t4.Add(t0, t1) // t4 := t0 + t1
+ t3.Sub(t3, t4) // t3 := t3 - t4
+ t4.Add(p1.y, p1.z) // t4 := Y1 + Z1
+ x3 := new(fiat.P256Element).Add(p2.y, p2.z) // X3 := Y2 + Z2
+ t4.Mul(t4, x3) // t4 := t4 * X3
+ x3.Add(t1, t2) // X3 := t1 + t2
+ t4.Sub(t4, x3) // t4 := t4 - X3
+ x3.Add(p1.x, p1.z) // X3 := X1 + Z1
+ y3 := new(fiat.P256Element).Add(p2.x, p2.z) // Y3 := X2 + Z2
+ x3.Mul(x3, y3) // X3 := X3 * Y3
+ y3.Add(t0, t2) // Y3 := t0 + t2
+ y3.Sub(x3, y3) // Y3 := X3 - Y3
+ z3 := new(fiat.P256Element).Mul(p256B(), t2) // Z3 := b * t2
+ x3.Sub(y3, z3) // X3 := Y3 - Z3
+ z3.Add(x3, x3) // Z3 := X3 + X3
+ x3.Add(x3, z3) // X3 := X3 + Z3
+ z3.Sub(t1, x3) // Z3 := t1 - X3
+ x3.Add(t1, x3) // X3 := t1 + X3
+ y3.Mul(p256B(), y3) // Y3 := b * Y3
+ t1.Add(t2, t2) // t1 := t2 + t2
+ t2.Add(t1, t2) // t2 := t1 + t2
+ y3.Sub(y3, t2) // Y3 := Y3 - t2
+ y3.Sub(y3, t0) // Y3 := Y3 - t0
+ t1.Add(y3, y3) // t1 := Y3 + Y3
+ y3.Add(t1, y3) // Y3 := t1 + Y3
+ t1.Add(t0, t0) // t1 := t0 + t0
+ t0.Add(t1, t0) // t0 := t1 + t0
+ t0.Sub(t0, t2) // t0 := t0 - t2
+ t1.Mul(t4, y3) // t1 := t4 * Y3
+ t2.Mul(t0, y3) // t2 := t0 * Y3
+ y3.Mul(x3, z3) // Y3 := X3 * Z3
+ y3.Add(y3, t2) // Y3 := Y3 + t2
+ x3.Mul(t3, x3) // X3 := t3 * X3
+ x3.Sub(x3, t1) // X3 := X3 - t1
+ z3.Mul(t4, z3) // Z3 := t4 * Z3
+ t1.Mul(t3, t0) // t1 := t3 * t0
+ z3.Add(z3, t1) // Z3 := Z3 + t1
+
+ q.x.Set(x3)
+ q.y.Set(y3)
+ q.z.Set(z3)
+ return q
+}
+
+// Double sets q = p + p, and returns q. The points may overlap.
+func (q *P256Point) Double(p *P256Point) *P256Point {
+ // Complete addition formula for a = -3 from "Complete addition formulas for
+ // prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
+
+ t0 := new(fiat.P256Element).Square(p.x) // t0 := X ^ 2
+ t1 := new(fiat.P256Element).Square(p.y) // t1 := Y ^ 2
+ t2 := new(fiat.P256Element).Square(p.z) // t2 := Z ^ 2
+ t3 := new(fiat.P256Element).Mul(p.x, p.y) // t3 := X * Y
+ t3.Add(t3, t3) // t3 := t3 + t3
+ z3 := new(fiat.P256Element).Mul(p.x, p.z) // Z3 := X * Z
+ z3.Add(z3, z3) // Z3 := Z3 + Z3
+ y3 := new(fiat.P256Element).Mul(p256B(), t2) // Y3 := b * t2
+ y3.Sub(y3, z3) // Y3 := Y3 - Z3
+ x3 := new(fiat.P256Element).Add(y3, y3) // X3 := Y3 + Y3
+ y3.Add(x3, y3) // Y3 := X3 + Y3
+ x3.Sub(t1, y3) // X3 := t1 - Y3
+ y3.Add(t1, y3) // Y3 := t1 + Y3
+ y3.Mul(x3, y3) // Y3 := X3 * Y3
+ x3.Mul(x3, t3) // X3 := X3 * t3
+ t3.Add(t2, t2) // t3 := t2 + t2
+ t2.Add(t2, t3) // t2 := t2 + t3
+ z3.Mul(p256B(), z3) // Z3 := b * Z3
+ z3.Sub(z3, t2) // Z3 := Z3 - t2
+ z3.Sub(z3, t0) // Z3 := Z3 - t0
+ t3.Add(z3, z3) // t3 := Z3 + Z3
+ z3.Add(z3, t3) // Z3 := Z3 + t3
+ t3.Add(t0, t0) // t3 := t0 + t0
+ t0.Add(t3, t0) // t0 := t3 + t0
+ t0.Sub(t0, t2) // t0 := t0 - t2
+ t0.Mul(t0, z3) // t0 := t0 * Z3
+ y3.Add(y3, t0) // Y3 := Y3 + t0
+ t0.Mul(p.y, p.z) // t0 := Y * Z
+ t0.Add(t0, t0) // t0 := t0 + t0
+ z3.Mul(t0, z3) // Z3 := t0 * Z3
+ x3.Sub(x3, z3) // X3 := X3 - Z3
+ z3.Mul(t0, t1) // Z3 := t0 * t1
+ z3.Add(z3, z3) // Z3 := Z3 + Z3
+ z3.Add(z3, z3) // Z3 := Z3 + Z3
+
+ q.x.Set(x3)
+ q.y.Set(y3)
+ q.z.Set(z3)
+ return q
+}
+
+// Select sets q to p1 if cond == 1, and to p2 if cond == 0.
+func (q *P256Point) Select(p1, p2 *P256Point, cond int) *P256Point {
+ q.x.Select(p1.x, p2.x, cond)
+ q.y.Select(p1.y, p2.y, cond)
+ q.z.Select(p1.z, p2.z, cond)
+ return q
+}
+
+// A p256Table holds the first 15 multiples of a point at offset -1, so [1]P
+// is at table[0], [15]P is at table[14], and [0]P is implicitly the identity
+// point.
+type p256Table [15]*P256Point
+
+// Select selects the n-th multiple of the table base point into p. It works in
+// constant time by iterating over every entry of the table. n must be in [0, 15].
+func (table *p256Table) Select(p *P256Point, n uint8) {
+ if n >= 16 {
+ panic("nistec: internal error: p256Table called with out-of-bounds value")
+ }
+ p.Set(NewP256Point())
+ for i := uint8(1); i < 16; i++ {
+ cond := subtle.ConstantTimeByteEq(i, n)
+ p.Select(table[i-1], p, cond)
+ }
+}
+
+// ScalarMult sets p = scalar * q, and returns p.
+func (p *P256Point) ScalarMult(q *P256Point, scalar []byte) (*P256Point, error) {
+ // Compute a p256Table for the base point q. The explicit NewP256Point
+ // calls get inlined, letting the allocations live on the stack.
+ var table = p256Table{NewP256Point(), NewP256Point(), NewP256Point(),
+ NewP256Point(), NewP256Point(), NewP256Point(), NewP256Point(),
+ NewP256Point(), NewP256Point(), NewP256Point(), NewP256Point(),
+ NewP256Point(), NewP256Point(), NewP256Point(), NewP256Point()}
+ table[0].Set(q)
+ for i := 1; i < 15; i += 2 {
+ table[i].Double(table[i/2])
+ table[i+1].Add(table[i], q)
+ }
+
+ // Instead of doing the classic double-and-add chain, we do it with a
+ // four-bit window: we double four times, and then add [0-15]P.
+ t := NewP256Point()
+ p.Set(NewP256Point())
+ for i, byte := range scalar {
+ // No need to double on the first iteration, as p is the identity at
+ // this point, and [N]∞ = ∞.
+ if i != 0 {
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+ }
+
+ windowValue := byte >> 4
+ table.Select(t, windowValue)
+ p.Add(p, t)
+
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+
+ windowValue = byte & 0b1111
+ table.Select(t, windowValue)
+ p.Add(p, t)
+ }
+
+ return p, nil
+}
+
+var p256GeneratorTable *[p256ElementLength * 2]p256Table
+var p256GeneratorTableOnce sync.Once
+
+// generatorTable returns a sequence of p256Tables. The first table contains
+// multiples of G. Each successive table is the previous table doubled four
+// times.
+func (p *P256Point) generatorTable() *[p256ElementLength * 2]p256Table {
+ p256GeneratorTableOnce.Do(func() {
+ p256GeneratorTable = new([p256ElementLength * 2]p256Table)
+ base := NewP256Point().SetGenerator()
+ for i := 0; i < p256ElementLength*2; i++ {
+ p256GeneratorTable[i][0] = NewP256Point().Set(base)
+ for j := 1; j < 15; j++ {
+ p256GeneratorTable[i][j] = NewP256Point().Add(p256GeneratorTable[i][j-1], base)
+ }
+ base.Double(base)
+ base.Double(base)
+ base.Double(base)
+ base.Double(base)
+ }
+ })
+ return p256GeneratorTable
+}
+
+// ScalarBaseMult sets p = scalar * B, where B is the canonical generator, and
+// returns p.
+func (p *P256Point) ScalarBaseMult(scalar []byte) (*P256Point, error) {
+ if len(scalar) != p256ElementLength {
+ return nil, errors.New("invalid scalar length")
+ }
+ tables := p.generatorTable()
+
+ // This is also a scalar multiplication with a four-bit window like in
+ // ScalarMult, but in this case the doublings are precomputed. The value
+ // [windowValue]G added at iteration k would normally get doubled
+ // (totIterations-k)×4 times, but with a larger precomputation we can
+ // instead add [2^((totIterations-k)×4)][windowValue]G and avoid the
+ // doublings between iterations.
+ t := NewP256Point()
+ p.Set(NewP256Point())
+ tableIndex := len(tables) - 1
+ for _, byte := range scalar {
+ windowValue := byte >> 4
+ tables[tableIndex].Select(t, windowValue)
+ p.Add(p, t)
+ tableIndex--
+
+ windowValue = byte & 0b1111
+ tables[tableIndex].Select(t, windowValue)
+ p.Add(p, t)
+ tableIndex--
+ }
+
+ return p, nil
+}
+
+// p256Sqrt sets e to a square root of x. If x is not a square, p256Sqrt returns
+// false and e is unchanged. e and x can overlap.
+func p256Sqrt(e, x *fiat.P256Element) (isSquare bool) {
+ candidate := new(fiat.P256Element)
+ p256SqrtCandidate(candidate, x)
+ square := new(fiat.P256Element).Square(candidate)
+ if square.Equal(x) != 1 {
+ return false
+ }
+ e.Set(candidate)
+ return true
+}
+
+// p256SqrtCandidate sets z to a square root candidate for x. z and x must not overlap.
+func p256SqrtCandidate(z, x *fiat.P256Element) {
+ // Since p = 3 mod 4, exponentiation by (p + 1) / 4 yields a square root candidate.
+ //
+ // The sequence of 7 multiplications and 253 squarings is derived from the
+ // following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
+ //
+ // _10 = 2*1
+ // _11 = 1 + _10
+ // _1100 = _11 << 2
+ // _1111 = _11 + _1100
+ // _11110000 = _1111 << 4
+ // _11111111 = _1111 + _11110000
+ // x16 = _11111111 << 8 + _11111111
+ // x32 = x16 << 16 + x16
+ // return ((x32 << 32 + 1) << 96 + 1) << 94
+ //
+ var t0 = new(fiat.P256Element)
+
+ z.Square(x)
+ z.Mul(x, z)
+ t0.Square(z)
+ for s := 1; s < 2; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ t0.Square(z)
+ for s := 1; s < 4; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ t0.Square(z)
+ for s := 1; s < 8; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ t0.Square(z)
+ for s := 1; s < 16; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ for s := 0; s < 32; s++ {
+ z.Square(z)
+ }
+ z.Mul(x, z)
+ for s := 0; s < 96; s++ {
+ z.Square(z)
+ }
+ z.Mul(x, z)
+ for s := 0; s < 94; s++ {
+ z.Square(z)
+ }
+}
diff --git a/src/crypto/internal/nistec/p256_asm.go b/src/crypto/internal/nistec/p256_asm.go
new file mode 100644
index 0000000..99a22b8
--- /dev/null
+++ b/src/crypto/internal/nistec/p256_asm.go
@@ -0,0 +1,744 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains the Go wrapper for the constant-time, 64-bit assembly
+// implementation of P256. The optimizations performed here are described in
+// detail in:
+// S.Gueron and V.Krasnov, "Fast prime field elliptic-curve cryptography with
+// 256-bit primes"
+// https://link.springer.com/article/10.1007%2Fs13389-014-0090-x
+// https://eprint.iacr.org/2013/816.pdf
+
+//go:build amd64 || arm64 || ppc64le || s390x
+
+package nistec
+
+import (
+ _ "embed"
+ "encoding/binary"
+ "errors"
+ "math/bits"
+ "runtime"
+ "unsafe"
+)
+
+// p256Element is a P-256 base field element in [0, P-1] in the Montgomery
+// domain (with R 2²⁵⁶) as four limbs in little-endian order value.
+type p256Element [4]uint64
+
+// p256One is one in the Montgomery domain.
+var p256One = p256Element{0x0000000000000001, 0xffffffff00000000,
+ 0xffffffffffffffff, 0x00000000fffffffe}
+
+var p256Zero = p256Element{}
+
+// p256P is 2²⁵⁶ - 2²²⁴ + 2¹⁹² + 2⁹⁶ - 1 in the Montgomery domain.
+var p256P = p256Element{0xffffffffffffffff, 0x00000000ffffffff,
+ 0x0000000000000000, 0xffffffff00000001}
+
+// P256Point is a P-256 point. The zero value should not be assumed to be valid
+// (although it is in this implementation).
+type P256Point struct {
+ // (X:Y:Z) are Jacobian coordinates where x = X/Z² and y = Y/Z³. The point
+ // at infinity can be represented by any set of coordinates with Z = 0.
+ x, y, z p256Element
+}
+
+// NewP256Point returns a new P256Point representing the point at infinity.
+func NewP256Point() *P256Point {
+ return &P256Point{
+ x: p256One, y: p256One, z: p256Zero,
+ }
+}
+
+// SetGenerator sets p to the canonical generator and returns p.
+func (p *P256Point) SetGenerator() *P256Point {
+ p.x = p256Element{0x79e730d418a9143c, 0x75ba95fc5fedb601,
+ 0x79fb732b77622510, 0x18905f76a53755c6}
+ p.y = p256Element{0xddf25357ce95560a, 0x8b4ab8e4ba19e45c,
+ 0xd2e88688dd21f325, 0x8571ff1825885d85}
+ p.z = p256One
+ return p
+}
+
+// Set sets p = q and returns p.
+func (p *P256Point) Set(q *P256Point) *P256Point {
+ p.x, p.y, p.z = q.x, q.y, q.z
+ return p
+}
+
+const p256ElementLength = 32
+const p256UncompressedLength = 1 + 2*p256ElementLength
+const p256CompressedLength = 1 + p256ElementLength
+
+// SetBytes sets p to the compressed, uncompressed, or infinity value encoded in
+// b, as specified in SEC 1, Version 2.0, Section 2.3.4. If the point is not on
+// the curve, it returns nil and an error, and the receiver is unchanged.
+// Otherwise, it returns p.
+func (p *P256Point) SetBytes(b []byte) (*P256Point, error) {
+ // p256Mul operates in the Montgomery domain with R = 2²⁵⁶ mod p. Thus rr
+ // here is R in the Montgomery domain, or R×R mod p. See comment in
+ // P256OrdInverse about how this is used.
+ rr := p256Element{0x0000000000000003, 0xfffffffbffffffff,
+ 0xfffffffffffffffe, 0x00000004fffffffd}
+
+ switch {
+ // Point at infinity.
+ case len(b) == 1 && b[0] == 0:
+ return p.Set(NewP256Point()), nil
+
+ // Uncompressed form.
+ case len(b) == p256UncompressedLength && b[0] == 4:
+ var r P256Point
+ p256BigToLittle(&r.x, (*[32]byte)(b[1:33]))
+ p256BigToLittle(&r.y, (*[32]byte)(b[33:65]))
+ if p256LessThanP(&r.x) == 0 || p256LessThanP(&r.y) == 0 {
+ return nil, errors.New("invalid P256 element encoding")
+ }
+ p256Mul(&r.x, &r.x, &rr)
+ p256Mul(&r.y, &r.y, &rr)
+ if err := p256CheckOnCurve(&r.x, &r.y); err != nil {
+ return nil, err
+ }
+ r.z = p256One
+ return p.Set(&r), nil
+
+ // Compressed form.
+ case len(b) == p256CompressedLength && (b[0] == 2 || b[0] == 3):
+ var r P256Point
+ p256BigToLittle(&r.x, (*[32]byte)(b[1:33]))
+ if p256LessThanP(&r.x) == 0 {
+ return nil, errors.New("invalid P256 element encoding")
+ }
+ p256Mul(&r.x, &r.x, &rr)
+
+ // y² = x³ - 3x + b
+ p256Polynomial(&r.y, &r.x)
+ if !p256Sqrt(&r.y, &r.y) {
+ return nil, errors.New("invalid P256 compressed point encoding")
+ }
+
+ // Select the positive or negative root, as indicated by the least
+ // significant bit, based on the encoding type byte.
+ yy := new(p256Element)
+ p256FromMont(yy, &r.y)
+ cond := int(yy[0]&1) ^ int(b[0]&1)
+ p256NegCond(&r.y, cond)
+
+ r.z = p256One
+ return p.Set(&r), nil
+
+ default:
+ return nil, errors.New("invalid P256 point encoding")
+ }
+}
+
+// p256Polynomial sets y2 to x³ - 3x + b, and returns y2.
+func p256Polynomial(y2, x *p256Element) *p256Element {
+ x3 := new(p256Element)
+ p256Sqr(x3, x, 1)
+ p256Mul(x3, x3, x)
+
+ threeX := new(p256Element)
+ p256Add(threeX, x, x)
+ p256Add(threeX, threeX, x)
+ p256NegCond(threeX, 1)
+
+ p256B := &p256Element{0xd89cdf6229c4bddf, 0xacf005cd78843090,
+ 0xe5a220abf7212ed6, 0xdc30061d04874834}
+
+ p256Add(x3, x3, threeX)
+ p256Add(x3, x3, p256B)
+
+ *y2 = *x3
+ return y2
+}
+
+func p256CheckOnCurve(x, y *p256Element) error {
+ // y² = x³ - 3x + b
+ rhs := p256Polynomial(new(p256Element), x)
+ lhs := new(p256Element)
+ p256Sqr(lhs, y, 1)
+ if p256Equal(lhs, rhs) != 1 {
+ return errors.New("P256 point not on curve")
+ }
+ return nil
+}
+
+// p256LessThanP returns 1 if x < p, and 0 otherwise. Note that a p256Element is
+// not allowed to be equal to or greater than p, so if this function returns 0
+// then x is invalid.
+func p256LessThanP(x *p256Element) int {
+ var b uint64
+ _, b = bits.Sub64(x[0], p256P[0], b)
+ _, b = bits.Sub64(x[1], p256P[1], b)
+ _, b = bits.Sub64(x[2], p256P[2], b)
+ _, b = bits.Sub64(x[3], p256P[3], b)
+ return int(b)
+}
+
+// p256Add sets res = x + y.
+func p256Add(res, x, y *p256Element) {
+ var c, b uint64
+ t1 := make([]uint64, 4)
+ t1[0], c = bits.Add64(x[0], y[0], 0)
+ t1[1], c = bits.Add64(x[1], y[1], c)
+ t1[2], c = bits.Add64(x[2], y[2], c)
+ t1[3], c = bits.Add64(x[3], y[3], c)
+ t2 := make([]uint64, 4)
+ t2[0], b = bits.Sub64(t1[0], p256P[0], 0)
+ t2[1], b = bits.Sub64(t1[1], p256P[1], b)
+ t2[2], b = bits.Sub64(t1[2], p256P[2], b)
+ t2[3], b = bits.Sub64(t1[3], p256P[3], b)
+ // Three options:
+ // - a+b < p
+ // then c is 0, b is 1, and t1 is correct
+ // - p <= a+b < 2^256
+ // then c is 0, b is 0, and t2 is correct
+ // - 2^256 <= a+b
+ // then c is 1, b is 1, and t2 is correct
+ t2Mask := (c ^ b) - 1
+ res[0] = (t1[0] & ^t2Mask) | (t2[0] & t2Mask)
+ res[1] = (t1[1] & ^t2Mask) | (t2[1] & t2Mask)
+ res[2] = (t1[2] & ^t2Mask) | (t2[2] & t2Mask)
+ res[3] = (t1[3] & ^t2Mask) | (t2[3] & t2Mask)
+}
+
+// p256Sqrt sets e to a square root of x. If x is not a square, p256Sqrt returns
+// false and e is unchanged. e and x can overlap.
+func p256Sqrt(e, x *p256Element) (isSquare bool) {
+ t0, t1 := new(p256Element), new(p256Element)
+
+ // Since p = 3 mod 4, exponentiation by (p + 1) / 4 yields a square root candidate.
+ //
+ // The sequence of 7 multiplications and 253 squarings is derived from the
+ // following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
+ //
+ // _10 = 2*1
+ // _11 = 1 + _10
+ // _1100 = _11 << 2
+ // _1111 = _11 + _1100
+ // _11110000 = _1111 << 4
+ // _11111111 = _1111 + _11110000
+ // x16 = _11111111 << 8 + _11111111
+ // x32 = x16 << 16 + x16
+ // return ((x32 << 32 + 1) << 96 + 1) << 94
+ //
+ p256Sqr(t0, x, 1)
+ p256Mul(t0, x, t0)
+ p256Sqr(t1, t0, 2)
+ p256Mul(t0, t0, t1)
+ p256Sqr(t1, t0, 4)
+ p256Mul(t0, t0, t1)
+ p256Sqr(t1, t0, 8)
+ p256Mul(t0, t0, t1)
+ p256Sqr(t1, t0, 16)
+ p256Mul(t0, t0, t1)
+ p256Sqr(t0, t0, 32)
+ p256Mul(t0, x, t0)
+ p256Sqr(t0, t0, 96)
+ p256Mul(t0, x, t0)
+ p256Sqr(t0, t0, 94)
+
+ p256Sqr(t1, t0, 1)
+ if p256Equal(t1, x) != 1 {
+ return false
+ }
+ *e = *t0
+ return true
+}
+
+// The following assembly functions are implemented in p256_asm_*.s
+
+// Montgomery multiplication. Sets res = in1 * in2 * R⁻¹ mod p.
+//
+//go:noescape
+func p256Mul(res, in1, in2 *p256Element)
+
+// Montgomery square, repeated n times (n >= 1).
+//
+//go:noescape
+func p256Sqr(res, in *p256Element, n int)
+
+// Montgomery multiplication by R⁻¹, or 1 outside the domain.
+// Sets res = in * R⁻¹, bringing res out of the Montgomery domain.
+//
+//go:noescape
+func p256FromMont(res, in *p256Element)
+
+// If cond is not 0, sets val = -val mod p.
+//
+//go:noescape
+func p256NegCond(val *p256Element, cond int)
+
+// If cond is 0, sets res = b, otherwise sets res = a.
+//
+//go:noescape
+func p256MovCond(res, a, b *P256Point, cond int)
+
+//go:noescape
+func p256BigToLittle(res *p256Element, in *[32]byte)
+
+//go:noescape
+func p256LittleToBig(res *[32]byte, in *p256Element)
+
+//go:noescape
+func p256OrdBigToLittle(res *p256OrdElement, in *[32]byte)
+
+//go:noescape
+func p256OrdLittleToBig(res *[32]byte, in *p256OrdElement)
+
+// p256Table is a table of the first 16 multiples of a point. Points are stored
+// at an index offset of -1 so [8]P is at index 7, P is at 0, and [16]P is at 15.
+// [0]P is the point at infinity and it's not stored.
+type p256Table [16]P256Point
+
+// p256Select sets res to the point at index idx in the table.
+// idx must be in [0, 15]. It executes in constant time.
+//
+//go:noescape
+func p256Select(res *P256Point, table *p256Table, idx int)
+
+// p256AffinePoint is a point in affine coordinates (x, y). x and y are still
+// Montgomery domain elements. The point can't be the point at infinity.
+type p256AffinePoint struct {
+ x, y p256Element
+}
+
+// p256AffineTable is a table of the first 32 multiples of a point. Points are
+// stored at an index offset of -1 like in p256Table, and [0]P is not stored.
+type p256AffineTable [32]p256AffinePoint
+
+// p256Precomputed is a series of precomputed multiples of G, the canonical
+// generator. The first p256AffineTable contains multiples of G. The second one
+// multiples of [2⁶]G, the third one of [2¹²]G, and so on, where each successive
+// table is the previous table doubled six times. Six is the width of the
+// sliding window used in p256ScalarMult, and having each table already
+// pre-doubled lets us avoid the doublings between windows entirely. This table
+// MUST NOT be modified, as it aliases into p256PrecomputedEmbed below.
+var p256Precomputed *[43]p256AffineTable
+
+//go:embed p256_asm_table.bin
+var p256PrecomputedEmbed string
+
+func init() {
+ p256PrecomputedPtr := (*unsafe.Pointer)(unsafe.Pointer(&p256PrecomputedEmbed))
+ if runtime.GOARCH == "s390x" {
+ var newTable [43 * 32 * 2 * 4]uint64
+ for i, x := range (*[43 * 32 * 2 * 4][8]byte)(*p256PrecomputedPtr) {
+ newTable[i] = binary.LittleEndian.Uint64(x[:])
+ }
+ newTablePtr := unsafe.Pointer(&newTable)
+ p256PrecomputedPtr = &newTablePtr
+ }
+ p256Precomputed = (*[43]p256AffineTable)(*p256PrecomputedPtr)
+}
+
+// p256SelectAffine sets res to the point at index idx in the table.
+// idx must be in [0, 31]. It executes in constant time.
+//
+//go:noescape
+func p256SelectAffine(res *p256AffinePoint, table *p256AffineTable, idx int)
+
+// Point addition with an affine point and constant time conditions.
+// If zero is 0, sets res = in2. If sel is 0, sets res = in1.
+// If sign is not 0, sets res = in1 + -in2. Otherwise, sets res = in1 + in2
+//
+//go:noescape
+func p256PointAddAffineAsm(res, in1 *P256Point, in2 *p256AffinePoint, sign, sel, zero int)
+
+// Point addition. Sets res = in1 + in2. Returns one if the two input points
+// were equal and zero otherwise. If in1 or in2 are the point at infinity, res
+// and the return value are undefined.
+//
+//go:noescape
+func p256PointAddAsm(res, in1, in2 *P256Point) int
+
+// Point doubling. Sets res = in + in. in can be the point at infinity.
+//
+//go:noescape
+func p256PointDoubleAsm(res, in *P256Point)
+
+// p256OrdElement is a P-256 scalar field element in [0, ord(G)-1] in the
+// Montgomery domain (with R 2²⁵⁶) as four uint64 limbs in little-endian order.
+type p256OrdElement [4]uint64
+
+// p256OrdReduce ensures s is in the range [0, ord(G)-1].
+func p256OrdReduce(s *p256OrdElement) {
+ // Since 2 * ord(G) > 2²⁵⁶, we can just conditionally subtract ord(G),
+ // keeping the result if it doesn't underflow.
+ t0, b := bits.Sub64(s[0], 0xf3b9cac2fc632551, 0)
+ t1, b := bits.Sub64(s[1], 0xbce6faada7179e84, b)
+ t2, b := bits.Sub64(s[2], 0xffffffffffffffff, b)
+ t3, b := bits.Sub64(s[3], 0xffffffff00000000, b)
+ tMask := b - 1 // zero if subtraction underflowed
+ s[0] ^= (t0 ^ s[0]) & tMask
+ s[1] ^= (t1 ^ s[1]) & tMask
+ s[2] ^= (t2 ^ s[2]) & tMask
+ s[3] ^= (t3 ^ s[3]) & tMask
+}
+
+// Add sets q = p1 + p2, and returns q. The points may overlap.
+func (q *P256Point) Add(r1, r2 *P256Point) *P256Point {
+ var sum, double P256Point
+ r1IsInfinity := r1.isInfinity()
+ r2IsInfinity := r2.isInfinity()
+ pointsEqual := p256PointAddAsm(&sum, r1, r2)
+ p256PointDoubleAsm(&double, r1)
+ p256MovCond(&sum, &double, &sum, pointsEqual)
+ p256MovCond(&sum, r1, &sum, r2IsInfinity)
+ p256MovCond(&sum, r2, &sum, r1IsInfinity)
+ return q.Set(&sum)
+}
+
+// Double sets q = p + p, and returns q. The points may overlap.
+func (q *P256Point) Double(p *P256Point) *P256Point {
+ var double P256Point
+ p256PointDoubleAsm(&double, p)
+ return q.Set(&double)
+}
+
+// ScalarBaseMult sets r = scalar * generator, where scalar is a 32-byte big
+// endian value, and returns r. If scalar is not 32 bytes long, ScalarBaseMult
+// returns an error and the receiver is unchanged.
+func (r *P256Point) ScalarBaseMult(scalar []byte) (*P256Point, error) {
+ if len(scalar) != 32 {
+ return nil, errors.New("invalid scalar length")
+ }
+ scalarReversed := new(p256OrdElement)
+ p256OrdBigToLittle(scalarReversed, (*[32]byte)(scalar))
+ p256OrdReduce(scalarReversed)
+
+ r.p256BaseMult(scalarReversed)
+ return r, nil
+}
+
+// ScalarMult sets r = scalar * q, where scalar is a 32-byte big endian value,
+// and returns r. If scalar is not 32 bytes long, ScalarBaseMult returns an
+// error and the receiver is unchanged.
+func (r *P256Point) ScalarMult(q *P256Point, scalar []byte) (*P256Point, error) {
+ if len(scalar) != 32 {
+ return nil, errors.New("invalid scalar length")
+ }
+ scalarReversed := new(p256OrdElement)
+ p256OrdBigToLittle(scalarReversed, (*[32]byte)(scalar))
+ p256OrdReduce(scalarReversed)
+
+ r.Set(q).p256ScalarMult(scalarReversed)
+ return r, nil
+}
+
+// uint64IsZero returns 1 if x is zero and zero otherwise.
+func uint64IsZero(x uint64) int {
+ x = ^x
+ x &= x >> 32
+ x &= x >> 16
+ x &= x >> 8
+ x &= x >> 4
+ x &= x >> 2
+ x &= x >> 1
+ return int(x & 1)
+}
+
+// p256Equal returns 1 if a and b are equal and 0 otherwise.
+func p256Equal(a, b *p256Element) int {
+ var acc uint64
+ for i := range a {
+ acc |= a[i] ^ b[i]
+ }
+ return uint64IsZero(acc)
+}
+
+// isInfinity returns 1 if p is the point at infinity and 0 otherwise.
+func (p *P256Point) isInfinity() int {
+ return p256Equal(&p.z, &p256Zero)
+}
+
+// Bytes returns the uncompressed or infinity encoding of p, as specified in
+// SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at
+// infinity is shorter than all other encodings.
+func (p *P256Point) Bytes() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [p256UncompressedLength]byte
+ return p.bytes(&out)
+}
+
+func (p *P256Point) bytes(out *[p256UncompressedLength]byte) []byte {
+ // The proper representation of the point at infinity is a single zero byte.
+ if p.isInfinity() == 1 {
+ return append(out[:0], 0)
+ }
+
+ x, y := new(p256Element), new(p256Element)
+ p.affineFromMont(x, y)
+
+ out[0] = 4 // Uncompressed form.
+ p256LittleToBig((*[32]byte)(out[1:33]), x)
+ p256LittleToBig((*[32]byte)(out[33:65]), y)
+
+ return out[:]
+}
+
+// affineFromMont sets (x, y) to the affine coordinates of p, converted out of the
+// Montgomery domain.
+func (p *P256Point) affineFromMont(x, y *p256Element) {
+ p256Inverse(y, &p.z)
+ p256Sqr(x, y, 1)
+ p256Mul(y, y, x)
+
+ p256Mul(x, &p.x, x)
+ p256Mul(y, &p.y, y)
+
+ p256FromMont(x, x)
+ p256FromMont(y, y)
+}
+
+// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
+// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
+func (p *P256Point) BytesX() ([]byte, error) {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [p256ElementLength]byte
+ return p.bytesX(&out)
+}
+
+func (p *P256Point) bytesX(out *[p256ElementLength]byte) ([]byte, error) {
+ if p.isInfinity() == 1 {
+ return nil, errors.New("P256 point is the point at infinity")
+ }
+
+ x := new(p256Element)
+ p256Inverse(x, &p.z)
+ p256Sqr(x, x, 1)
+ p256Mul(x, &p.x, x)
+ p256FromMont(x, x)
+ p256LittleToBig((*[32]byte)(out[:]), x)
+
+ return out[:], nil
+}
+
+// BytesCompressed returns the compressed or infinity encoding of p, as
+// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
+// point at infinity is shorter than all other encodings.
+func (p *P256Point) BytesCompressed() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [p256CompressedLength]byte
+ return p.bytesCompressed(&out)
+}
+
+func (p *P256Point) bytesCompressed(out *[p256CompressedLength]byte) []byte {
+ if p.isInfinity() == 1 {
+ return append(out[:0], 0)
+ }
+
+ x, y := new(p256Element), new(p256Element)
+ p.affineFromMont(x, y)
+
+ out[0] = 2 | byte(y[0]&1)
+ p256LittleToBig((*[32]byte)(out[1:33]), x)
+
+ return out[:]
+}
+
+// Select sets q to p1 if cond == 1, and to p2 if cond == 0.
+func (q *P256Point) Select(p1, p2 *P256Point, cond int) *P256Point {
+ p256MovCond(q, p1, p2, cond)
+ return q
+}
+
+// p256Inverse sets out to in⁻¹ mod p. If in is zero, out will be zero.
+func p256Inverse(out, in *p256Element) {
+ // Inversion is calculated through exponentiation by p - 2, per Fermat's
+ // little theorem.
+ //
+ // The sequence of 12 multiplications and 255 squarings is derived from the
+ // following addition chain generated with github.com/mmcloughlin/addchain
+ // v0.4.0.
+ //
+ // _10 = 2*1
+ // _11 = 1 + _10
+ // _110 = 2*_11
+ // _111 = 1 + _110
+ // _111000 = _111 << 3
+ // _111111 = _111 + _111000
+ // x12 = _111111 << 6 + _111111
+ // x15 = x12 << 3 + _111
+ // x16 = 2*x15 + 1
+ // x32 = x16 << 16 + x16
+ // i53 = x32 << 15
+ // x47 = x15 + i53
+ // i263 = ((i53 << 17 + 1) << 143 + x47) << 47
+ // return (x47 + i263) << 2 + 1
+ //
+ var z = new(p256Element)
+ var t0 = new(p256Element)
+ var t1 = new(p256Element)
+
+ p256Sqr(z, in, 1)
+ p256Mul(z, in, z)
+ p256Sqr(z, z, 1)
+ p256Mul(z, in, z)
+ p256Sqr(t0, z, 3)
+ p256Mul(t0, z, t0)
+ p256Sqr(t1, t0, 6)
+ p256Mul(t0, t0, t1)
+ p256Sqr(t0, t0, 3)
+ p256Mul(z, z, t0)
+ p256Sqr(t0, z, 1)
+ p256Mul(t0, in, t0)
+ p256Sqr(t1, t0, 16)
+ p256Mul(t0, t0, t1)
+ p256Sqr(t0, t0, 15)
+ p256Mul(z, z, t0)
+ p256Sqr(t0, t0, 17)
+ p256Mul(t0, in, t0)
+ p256Sqr(t0, t0, 143)
+ p256Mul(t0, z, t0)
+ p256Sqr(t0, t0, 47)
+ p256Mul(z, z, t0)
+ p256Sqr(z, z, 2)
+ p256Mul(out, in, z)
+}
+
+func boothW5(in uint) (int, int) {
+ var s uint = ^((in >> 5) - 1)
+ var d uint = (1 << 6) - in - 1
+ d = (d & s) | (in & (^s))
+ d = (d >> 1) + (d & 1)
+ return int(d), int(s & 1)
+}
+
+func boothW6(in uint) (int, int) {
+ var s uint = ^((in >> 6) - 1)
+ var d uint = (1 << 7) - in - 1
+ d = (d & s) | (in & (^s))
+ d = (d >> 1) + (d & 1)
+ return int(d), int(s & 1)
+}
+
+func (p *P256Point) p256BaseMult(scalar *p256OrdElement) {
+ var t0 p256AffinePoint
+
+ wvalue := (scalar[0] << 1) & 0x7f
+ sel, sign := boothW6(uint(wvalue))
+ p256SelectAffine(&t0, &p256Precomputed[0], sel)
+ p.x, p.y, p.z = t0.x, t0.y, p256One
+ p256NegCond(&p.y, sign)
+
+ index := uint(5)
+ zero := sel
+
+ for i := 1; i < 43; i++ {
+ if index < 192 {
+ wvalue = ((scalar[index/64] >> (index % 64)) + (scalar[index/64+1] << (64 - (index % 64)))) & 0x7f
+ } else {
+ wvalue = (scalar[index/64] >> (index % 64)) & 0x7f
+ }
+ index += 6
+ sel, sign = boothW6(uint(wvalue))
+ p256SelectAffine(&t0, &p256Precomputed[i], sel)
+ p256PointAddAffineAsm(p, p, &t0, sign, sel, zero)
+ zero |= sel
+ }
+
+ // If the whole scalar was zero, set to the point at infinity.
+ p256MovCond(p, p, NewP256Point(), zero)
+}
+
+func (p *P256Point) p256ScalarMult(scalar *p256OrdElement) {
+ // precomp is a table of precomputed points that stores powers of p
+ // from p^1 to p^16.
+ var precomp p256Table
+ var t0, t1, t2, t3 P256Point
+
+ // Prepare the table
+ precomp[0] = *p // 1
+
+ p256PointDoubleAsm(&t0, p)
+ p256PointDoubleAsm(&t1, &t0)
+ p256PointDoubleAsm(&t2, &t1)
+ p256PointDoubleAsm(&t3, &t2)
+ precomp[1] = t0 // 2
+ precomp[3] = t1 // 4
+ precomp[7] = t2 // 8
+ precomp[15] = t3 // 16
+
+ p256PointAddAsm(&t0, &t0, p)
+ p256PointAddAsm(&t1, &t1, p)
+ p256PointAddAsm(&t2, &t2, p)
+ precomp[2] = t0 // 3
+ precomp[4] = t1 // 5
+ precomp[8] = t2 // 9
+
+ p256PointDoubleAsm(&t0, &t0)
+ p256PointDoubleAsm(&t1, &t1)
+ precomp[5] = t0 // 6
+ precomp[9] = t1 // 10
+
+ p256PointAddAsm(&t2, &t0, p)
+ p256PointAddAsm(&t1, &t1, p)
+ precomp[6] = t2 // 7
+ precomp[10] = t1 // 11
+
+ p256PointDoubleAsm(&t0, &t0)
+ p256PointDoubleAsm(&t2, &t2)
+ precomp[11] = t0 // 12
+ precomp[13] = t2 // 14
+
+ p256PointAddAsm(&t0, &t0, p)
+ p256PointAddAsm(&t2, &t2, p)
+ precomp[12] = t0 // 13
+ precomp[14] = t2 // 15
+
+ // Start scanning the window from top bit
+ index := uint(254)
+ var sel, sign int
+
+ wvalue := (scalar[index/64] >> (index % 64)) & 0x3f
+ sel, _ = boothW5(uint(wvalue))
+
+ p256Select(p, &precomp, sel)
+ zero := sel
+
+ for index > 4 {
+ index -= 5
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+
+ if index < 192 {
+ wvalue = ((scalar[index/64] >> (index % 64)) + (scalar[index/64+1] << (64 - (index % 64)))) & 0x3f
+ } else {
+ wvalue = (scalar[index/64] >> (index % 64)) & 0x3f
+ }
+
+ sel, sign = boothW5(uint(wvalue))
+
+ p256Select(&t0, &precomp, sel)
+ p256NegCond(&t0.y, sign)
+ p256PointAddAsm(&t1, p, &t0)
+ p256MovCond(&t1, &t1, p, sel)
+ p256MovCond(p, &t1, &t0, zero)
+ zero |= sel
+ }
+
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+ p256PointDoubleAsm(p, p)
+
+ wvalue = (scalar[0] << 1) & 0x3f
+ sel, sign = boothW5(uint(wvalue))
+
+ p256Select(&t0, &precomp, sel)
+ p256NegCond(&t0.y, sign)
+ p256PointAddAsm(&t1, p, &t0)
+ p256MovCond(&t1, &t1, p, sel)
+ p256MovCond(p, &t1, &t0, zero)
+}
diff --git a/src/crypto/internal/nistec/p256_asm_amd64.s b/src/crypto/internal/nistec/p256_asm_amd64.s
new file mode 100644
index 0000000..84e4cee
--- /dev/null
+++ b/src/crypto/internal/nistec/p256_asm_amd64.s
@@ -0,0 +1,2350 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains constant-time, 64-bit assembly implementation of
+// P256. The optimizations performed here are described in detail in:
+// S.Gueron and V.Krasnov, "Fast prime field elliptic-curve cryptography with
+// 256-bit primes"
+// https://link.springer.com/article/10.1007%2Fs13389-014-0090-x
+// https://eprint.iacr.org/2013/816.pdf
+
+#include "textflag.h"
+
+#define res_ptr DI
+#define x_ptr SI
+#define y_ptr CX
+
+#define acc0 R8
+#define acc1 R9
+#define acc2 R10
+#define acc3 R11
+#define acc4 R12
+#define acc5 R13
+#define t0 R14
+#define t1 R15
+
+DATA p256const0<>+0x00(SB)/8, $0x00000000ffffffff
+DATA p256const1<>+0x00(SB)/8, $0xffffffff00000001
+DATA p256ordK0<>+0x00(SB)/8, $0xccd1c8aaee00bc4f
+DATA p256ord<>+0x00(SB)/8, $0xf3b9cac2fc632551
+DATA p256ord<>+0x08(SB)/8, $0xbce6faada7179e84
+DATA p256ord<>+0x10(SB)/8, $0xffffffffffffffff
+DATA p256ord<>+0x18(SB)/8, $0xffffffff00000000
+DATA p256one<>+0x00(SB)/8, $0x0000000000000001
+DATA p256one<>+0x08(SB)/8, $0xffffffff00000000
+DATA p256one<>+0x10(SB)/8, $0xffffffffffffffff
+DATA p256one<>+0x18(SB)/8, $0x00000000fffffffe
+GLOBL p256const0<>(SB), 8, $8
+GLOBL p256const1<>(SB), 8, $8
+GLOBL p256ordK0<>(SB), 8, $8
+GLOBL p256ord<>(SB), 8, $32
+GLOBL p256one<>(SB), 8, $32
+
+/* ---------------------------------------*/
+// func p256OrdLittleToBig(res *[32]byte, in *p256OrdElement)
+TEXT ·p256OrdLittleToBig(SB),NOSPLIT,$0
+ JMP ·p256BigToLittle(SB)
+/* ---------------------------------------*/
+// func p256OrdBigToLittle(res *p256OrdElement, in *[32]byte)
+TEXT ·p256OrdBigToLittle(SB),NOSPLIT,$0
+ JMP ·p256BigToLittle(SB)
+/* ---------------------------------------*/
+// func p256LittleToBig(res *[32]byte, in *p256Element)
+TEXT ·p256LittleToBig(SB),NOSPLIT,$0
+ JMP ·p256BigToLittle(SB)
+/* ---------------------------------------*/
+// func p256BigToLittle(res *p256Element, in *[32]byte)
+TEXT ·p256BigToLittle(SB),NOSPLIT,$0
+ MOVQ res+0(FP), res_ptr
+ MOVQ in+8(FP), x_ptr
+
+ MOVQ (8*0)(x_ptr), acc0
+ MOVQ (8*1)(x_ptr), acc1
+ MOVQ (8*2)(x_ptr), acc2
+ MOVQ (8*3)(x_ptr), acc3
+
+ BSWAPQ acc0
+ BSWAPQ acc1
+ BSWAPQ acc2
+ BSWAPQ acc3
+
+ MOVQ acc3, (8*0)(res_ptr)
+ MOVQ acc2, (8*1)(res_ptr)
+ MOVQ acc1, (8*2)(res_ptr)
+ MOVQ acc0, (8*3)(res_ptr)
+
+ RET
+/* ---------------------------------------*/
+// func p256MovCond(res, a, b *P256Point, cond int)
+TEXT ·p256MovCond(SB),NOSPLIT,$0
+ MOVQ res+0(FP), res_ptr
+ MOVQ a+8(FP), x_ptr
+ MOVQ b+16(FP), y_ptr
+ MOVQ cond+24(FP), X12
+
+ PXOR X13, X13
+ PSHUFD $0, X12, X12
+ PCMPEQL X13, X12
+
+ MOVOU X12, X0
+ MOVOU (16*0)(x_ptr), X6
+ PANDN X6, X0
+ MOVOU X12, X1
+ MOVOU (16*1)(x_ptr), X7
+ PANDN X7, X1
+ MOVOU X12, X2
+ MOVOU (16*2)(x_ptr), X8
+ PANDN X8, X2
+ MOVOU X12, X3
+ MOVOU (16*3)(x_ptr), X9
+ PANDN X9, X3
+ MOVOU X12, X4
+ MOVOU (16*4)(x_ptr), X10
+ PANDN X10, X4
+ MOVOU X12, X5
+ MOVOU (16*5)(x_ptr), X11
+ PANDN X11, X5
+
+ MOVOU (16*0)(y_ptr), X6
+ MOVOU (16*1)(y_ptr), X7
+ MOVOU (16*2)(y_ptr), X8
+ MOVOU (16*3)(y_ptr), X9
+ MOVOU (16*4)(y_ptr), X10
+ MOVOU (16*5)(y_ptr), X11
+
+ PAND X12, X6
+ PAND X12, X7
+ PAND X12, X8
+ PAND X12, X9
+ PAND X12, X10
+ PAND X12, X11
+
+ PXOR X6, X0
+ PXOR X7, X1
+ PXOR X8, X2
+ PXOR X9, X3
+ PXOR X10, X4
+ PXOR X11, X5
+
+ MOVOU X0, (16*0)(res_ptr)
+ MOVOU X1, (16*1)(res_ptr)
+ MOVOU X2, (16*2)(res_ptr)
+ MOVOU X3, (16*3)(res_ptr)
+ MOVOU X4, (16*4)(res_ptr)
+ MOVOU X5, (16*5)(res_ptr)
+
+ RET
+/* ---------------------------------------*/
+// func p256NegCond(val *p256Element, cond int)
+TEXT ·p256NegCond(SB),NOSPLIT,$0
+ MOVQ val+0(FP), res_ptr
+ MOVQ cond+8(FP), t0
+ // acc = poly
+ MOVQ $-1, acc0
+ MOVQ p256const0<>(SB), acc1
+ MOVQ $0, acc2
+ MOVQ p256const1<>(SB), acc3
+ // Load the original value
+ MOVQ (8*0)(res_ptr), acc5
+ MOVQ (8*1)(res_ptr), x_ptr
+ MOVQ (8*2)(res_ptr), y_ptr
+ MOVQ (8*3)(res_ptr), t1
+ // Speculatively subtract
+ SUBQ acc5, acc0
+ SBBQ x_ptr, acc1
+ SBBQ y_ptr, acc2
+ SBBQ t1, acc3
+ // If condition is 0, keep original value
+ TESTQ t0, t0
+ CMOVQEQ acc5, acc0
+ CMOVQEQ x_ptr, acc1
+ CMOVQEQ y_ptr, acc2
+ CMOVQEQ t1, acc3
+ // Store result
+ MOVQ acc0, (8*0)(res_ptr)
+ MOVQ acc1, (8*1)(res_ptr)
+ MOVQ acc2, (8*2)(res_ptr)
+ MOVQ acc3, (8*3)(res_ptr)
+
+ RET
+/* ---------------------------------------*/
+// func p256Sqr(res, in *p256Element, n int)
+TEXT ·p256Sqr(SB),NOSPLIT,$0
+ MOVQ res+0(FP), res_ptr
+ MOVQ in+8(FP), x_ptr
+ MOVQ n+16(FP), BX
+
+sqrLoop:
+
+ // y[1:] * y[0]
+ MOVQ (8*0)(x_ptr), t0
+
+ MOVQ (8*1)(x_ptr), AX
+ MULQ t0
+ MOVQ AX, acc1
+ MOVQ DX, acc2
+
+ MOVQ (8*2)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc2
+ ADCQ $0, DX
+ MOVQ DX, acc3
+
+ MOVQ (8*3)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc3
+ ADCQ $0, DX
+ MOVQ DX, acc4
+ // y[2:] * y[1]
+ MOVQ (8*1)(x_ptr), t0
+
+ MOVQ (8*2)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc3
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*3)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc4
+ ADCQ $0, DX
+ ADDQ AX, acc4
+ ADCQ $0, DX
+ MOVQ DX, acc5
+ // y[3] * y[2]
+ MOVQ (8*2)(x_ptr), t0
+
+ MOVQ (8*3)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc5
+ ADCQ $0, DX
+ MOVQ DX, y_ptr
+ XORQ t1, t1
+ // *2
+ ADDQ acc1, acc1
+ ADCQ acc2, acc2
+ ADCQ acc3, acc3
+ ADCQ acc4, acc4
+ ADCQ acc5, acc5
+ ADCQ y_ptr, y_ptr
+ ADCQ $0, t1
+ // Missing products
+ MOVQ (8*0)(x_ptr), AX
+ MULQ AX
+ MOVQ AX, acc0
+ MOVQ DX, t0
+
+ MOVQ (8*1)(x_ptr), AX
+ MULQ AX
+ ADDQ t0, acc1
+ ADCQ AX, acc2
+ ADCQ $0, DX
+ MOVQ DX, t0
+
+ MOVQ (8*2)(x_ptr), AX
+ MULQ AX
+ ADDQ t0, acc3
+ ADCQ AX, acc4
+ ADCQ $0, DX
+ MOVQ DX, t0
+
+ MOVQ (8*3)(x_ptr), AX
+ MULQ AX
+ ADDQ t0, acc5
+ ADCQ AX, y_ptr
+ ADCQ DX, t1
+ MOVQ t1, x_ptr
+ // First reduction step
+ MOVQ acc0, AX
+ MOVQ acc0, t1
+ SHLQ $32, acc0
+ MULQ p256const1<>(SB)
+ SHRQ $32, t1
+ ADDQ acc0, acc1
+ ADCQ t1, acc2
+ ADCQ AX, acc3
+ ADCQ $0, DX
+ MOVQ DX, acc0
+ // Second reduction step
+ MOVQ acc1, AX
+ MOVQ acc1, t1
+ SHLQ $32, acc1
+ MULQ p256const1<>(SB)
+ SHRQ $32, t1
+ ADDQ acc1, acc2
+ ADCQ t1, acc3
+ ADCQ AX, acc0
+ ADCQ $0, DX
+ MOVQ DX, acc1
+ // Third reduction step
+ MOVQ acc2, AX
+ MOVQ acc2, t1
+ SHLQ $32, acc2
+ MULQ p256const1<>(SB)
+ SHRQ $32, t1
+ ADDQ acc2, acc3
+ ADCQ t1, acc0
+ ADCQ AX, acc1
+ ADCQ $0, DX
+ MOVQ DX, acc2
+ // Last reduction step
+ XORQ t0, t0
+ MOVQ acc3, AX
+ MOVQ acc3, t1
+ SHLQ $32, acc3
+ MULQ p256const1<>(SB)
+ SHRQ $32, t1
+ ADDQ acc3, acc0
+ ADCQ t1, acc1
+ ADCQ AX, acc2
+ ADCQ $0, DX
+ MOVQ DX, acc3
+ // Add bits [511:256] of the sqr result
+ ADCQ acc4, acc0
+ ADCQ acc5, acc1
+ ADCQ y_ptr, acc2
+ ADCQ x_ptr, acc3
+ ADCQ $0, t0
+
+ MOVQ acc0, acc4
+ MOVQ acc1, acc5
+ MOVQ acc2, y_ptr
+ MOVQ acc3, t1
+ // Subtract p256
+ SUBQ $-1, acc0
+ SBBQ p256const0<>(SB) ,acc1
+ SBBQ $0, acc2
+ SBBQ p256const1<>(SB), acc3
+ SBBQ $0, t0
+
+ CMOVQCS acc4, acc0
+ CMOVQCS acc5, acc1
+ CMOVQCS y_ptr, acc2
+ CMOVQCS t1, acc3
+
+ MOVQ acc0, (8*0)(res_ptr)
+ MOVQ acc1, (8*1)(res_ptr)
+ MOVQ acc2, (8*2)(res_ptr)
+ MOVQ acc3, (8*3)(res_ptr)
+ MOVQ res_ptr, x_ptr
+ DECQ BX
+ JNE sqrLoop
+
+ RET
+/* ---------------------------------------*/
+// func p256Mul(res, in1, in2 *p256Element)
+TEXT ·p256Mul(SB),NOSPLIT,$0
+ MOVQ res+0(FP), res_ptr
+ MOVQ in1+8(FP), x_ptr
+ MOVQ in2+16(FP), y_ptr
+ // x * y[0]
+ MOVQ (8*0)(y_ptr), t0
+
+ MOVQ (8*0)(x_ptr), AX
+ MULQ t0
+ MOVQ AX, acc0
+ MOVQ DX, acc1
+
+ MOVQ (8*1)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc1
+ ADCQ $0, DX
+ MOVQ DX, acc2
+
+ MOVQ (8*2)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc2
+ ADCQ $0, DX
+ MOVQ DX, acc3
+
+ MOVQ (8*3)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc3
+ ADCQ $0, DX
+ MOVQ DX, acc4
+ XORQ acc5, acc5
+ // First reduction step
+ MOVQ acc0, AX
+ MOVQ acc0, t1
+ SHLQ $32, acc0
+ MULQ p256const1<>(SB)
+ SHRQ $32, t1
+ ADDQ acc0, acc1
+ ADCQ t1, acc2
+ ADCQ AX, acc3
+ ADCQ DX, acc4
+ ADCQ $0, acc5
+ XORQ acc0, acc0
+ // x * y[1]
+ MOVQ (8*1)(y_ptr), t0
+
+ MOVQ (8*0)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc1
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*1)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc2
+ ADCQ $0, DX
+ ADDQ AX, acc2
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*2)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc3
+ ADCQ $0, DX
+ ADDQ AX, acc3
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*3)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc4
+ ADCQ $0, DX
+ ADDQ AX, acc4
+ ADCQ DX, acc5
+ ADCQ $0, acc0
+ // Second reduction step
+ MOVQ acc1, AX
+ MOVQ acc1, t1
+ SHLQ $32, acc1
+ MULQ p256const1<>(SB)
+ SHRQ $32, t1
+ ADDQ acc1, acc2
+ ADCQ t1, acc3
+ ADCQ AX, acc4
+ ADCQ DX, acc5
+ ADCQ $0, acc0
+ XORQ acc1, acc1
+ // x * y[2]
+ MOVQ (8*2)(y_ptr), t0
+
+ MOVQ (8*0)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc2
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*1)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc3
+ ADCQ $0, DX
+ ADDQ AX, acc3
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*2)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc4
+ ADCQ $0, DX
+ ADDQ AX, acc4
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*3)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc5
+ ADCQ $0, DX
+ ADDQ AX, acc5
+ ADCQ DX, acc0
+ ADCQ $0, acc1
+ // Third reduction step
+ MOVQ acc2, AX
+ MOVQ acc2, t1
+ SHLQ $32, acc2
+ MULQ p256const1<>(SB)
+ SHRQ $32, t1
+ ADDQ acc2, acc3
+ ADCQ t1, acc4
+ ADCQ AX, acc5
+ ADCQ DX, acc0
+ ADCQ $0, acc1
+ XORQ acc2, acc2
+ // x * y[3]
+ MOVQ (8*3)(y_ptr), t0
+
+ MOVQ (8*0)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc3
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*1)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc4
+ ADCQ $0, DX
+ ADDQ AX, acc4
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*2)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc5
+ ADCQ $0, DX
+ ADDQ AX, acc5
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*3)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc0
+ ADCQ $0, DX
+ ADDQ AX, acc0
+ ADCQ DX, acc1
+ ADCQ $0, acc2
+ // Last reduction step
+ MOVQ acc3, AX
+ MOVQ acc3, t1
+ SHLQ $32, acc3
+ MULQ p256const1<>(SB)
+ SHRQ $32, t1
+ ADDQ acc3, acc4
+ ADCQ t1, acc5
+ ADCQ AX, acc0
+ ADCQ DX, acc1
+ ADCQ $0, acc2
+ // Copy result [255:0]
+ MOVQ acc4, x_ptr
+ MOVQ acc5, acc3
+ MOVQ acc0, t0
+ MOVQ acc1, t1
+ // Subtract p256
+ SUBQ $-1, acc4
+ SBBQ p256const0<>(SB) ,acc5
+ SBBQ $0, acc0
+ SBBQ p256const1<>(SB), acc1
+ SBBQ $0, acc2
+
+ CMOVQCS x_ptr, acc4
+ CMOVQCS acc3, acc5
+ CMOVQCS t0, acc0
+ CMOVQCS t1, acc1
+
+ MOVQ acc4, (8*0)(res_ptr)
+ MOVQ acc5, (8*1)(res_ptr)
+ MOVQ acc0, (8*2)(res_ptr)
+ MOVQ acc1, (8*3)(res_ptr)
+
+ RET
+/* ---------------------------------------*/
+// func p256FromMont(res, in *p256Element)
+TEXT ·p256FromMont(SB),NOSPLIT,$0
+ MOVQ res+0(FP), res_ptr
+ MOVQ in+8(FP), x_ptr
+
+ MOVQ (8*0)(x_ptr), acc0
+ MOVQ (8*1)(x_ptr), acc1
+ MOVQ (8*2)(x_ptr), acc2
+ MOVQ (8*3)(x_ptr), acc3
+ XORQ acc4, acc4
+
+ // Only reduce, no multiplications are needed
+ // First stage
+ MOVQ acc0, AX
+ MOVQ acc0, t1
+ SHLQ $32, acc0
+ MULQ p256const1<>(SB)
+ SHRQ $32, t1
+ ADDQ acc0, acc1
+ ADCQ t1, acc2
+ ADCQ AX, acc3
+ ADCQ DX, acc4
+ XORQ acc5, acc5
+ // Second stage
+ MOVQ acc1, AX
+ MOVQ acc1, t1
+ SHLQ $32, acc1
+ MULQ p256const1<>(SB)
+ SHRQ $32, t1
+ ADDQ acc1, acc2
+ ADCQ t1, acc3
+ ADCQ AX, acc4
+ ADCQ DX, acc5
+ XORQ acc0, acc0
+ // Third stage
+ MOVQ acc2, AX
+ MOVQ acc2, t1
+ SHLQ $32, acc2
+ MULQ p256const1<>(SB)
+ SHRQ $32, t1
+ ADDQ acc2, acc3
+ ADCQ t1, acc4
+ ADCQ AX, acc5
+ ADCQ DX, acc0
+ XORQ acc1, acc1
+ // Last stage
+ MOVQ acc3, AX
+ MOVQ acc3, t1
+ SHLQ $32, acc3
+ MULQ p256const1<>(SB)
+ SHRQ $32, t1
+ ADDQ acc3, acc4
+ ADCQ t1, acc5
+ ADCQ AX, acc0
+ ADCQ DX, acc1
+
+ MOVQ acc4, x_ptr
+ MOVQ acc5, acc3
+ MOVQ acc0, t0
+ MOVQ acc1, t1
+
+ SUBQ $-1, acc4
+ SBBQ p256const0<>(SB), acc5
+ SBBQ $0, acc0
+ SBBQ p256const1<>(SB), acc1
+
+ CMOVQCS x_ptr, acc4
+ CMOVQCS acc3, acc5
+ CMOVQCS t0, acc0
+ CMOVQCS t1, acc1
+
+ MOVQ acc4, (8*0)(res_ptr)
+ MOVQ acc5, (8*1)(res_ptr)
+ MOVQ acc0, (8*2)(res_ptr)
+ MOVQ acc1, (8*3)(res_ptr)
+
+ RET
+/* ---------------------------------------*/
+// func p256Select(res *P256Point, table *p256Table, idx int)
+TEXT ·p256Select(SB),NOSPLIT,$0
+ MOVQ idx+16(FP),AX
+ MOVQ table+8(FP),DI
+ MOVQ res+0(FP),DX
+
+ PXOR X15, X15 // X15 = 0
+ PCMPEQL X14, X14 // X14 = -1
+ PSUBL X14, X15 // X15 = 1
+ MOVL AX, X14
+ PSHUFD $0, X14, X14
+
+ PXOR X0, X0
+ PXOR X1, X1
+ PXOR X2, X2
+ PXOR X3, X3
+ PXOR X4, X4
+ PXOR X5, X5
+ MOVQ $16, AX
+
+ MOVOU X15, X13
+
+loop_select:
+
+ MOVOU X13, X12
+ PADDL X15, X13
+ PCMPEQL X14, X12
+
+ MOVOU (16*0)(DI), X6
+ MOVOU (16*1)(DI), X7
+ MOVOU (16*2)(DI), X8
+ MOVOU (16*3)(DI), X9
+ MOVOU (16*4)(DI), X10
+ MOVOU (16*5)(DI), X11
+ ADDQ $(16*6), DI
+
+ PAND X12, X6
+ PAND X12, X7
+ PAND X12, X8
+ PAND X12, X9
+ PAND X12, X10
+ PAND X12, X11
+
+ PXOR X6, X0
+ PXOR X7, X1
+ PXOR X8, X2
+ PXOR X9, X3
+ PXOR X10, X4
+ PXOR X11, X5
+
+ DECQ AX
+ JNE loop_select
+
+ MOVOU X0, (16*0)(DX)
+ MOVOU X1, (16*1)(DX)
+ MOVOU X2, (16*2)(DX)
+ MOVOU X3, (16*3)(DX)
+ MOVOU X4, (16*4)(DX)
+ MOVOU X5, (16*5)(DX)
+
+ RET
+/* ---------------------------------------*/
+// func p256SelectAffine(res *p256AffinePoint, table *p256AffineTable, idx int)
+TEXT ·p256SelectAffine(SB),NOSPLIT,$0
+ MOVQ idx+16(FP),AX
+ MOVQ table+8(FP),DI
+ MOVQ res+0(FP),DX
+
+ PXOR X15, X15 // X15 = 0
+ PCMPEQL X14, X14 // X14 = -1
+ PSUBL X14, X15 // X15 = 1
+ MOVL AX, X14
+ PSHUFD $0, X14, X14
+
+ PXOR X0, X0
+ PXOR X1, X1
+ PXOR X2, X2
+ PXOR X3, X3
+ MOVQ $16, AX
+
+ MOVOU X15, X13
+
+loop_select_base:
+
+ MOVOU X13, X12
+ PADDL X15, X13
+ PCMPEQL X14, X12
+
+ MOVOU (16*0)(DI), X4
+ MOVOU (16*1)(DI), X5
+ MOVOU (16*2)(DI), X6
+ MOVOU (16*3)(DI), X7
+
+ MOVOU (16*4)(DI), X8
+ MOVOU (16*5)(DI), X9
+ MOVOU (16*6)(DI), X10
+ MOVOU (16*7)(DI), X11
+
+ ADDQ $(16*8), DI
+
+ PAND X12, X4
+ PAND X12, X5
+ PAND X12, X6
+ PAND X12, X7
+
+ MOVOU X13, X12
+ PADDL X15, X13
+ PCMPEQL X14, X12
+
+ PAND X12, X8
+ PAND X12, X9
+ PAND X12, X10
+ PAND X12, X11
+
+ PXOR X4, X0
+ PXOR X5, X1
+ PXOR X6, X2
+ PXOR X7, X3
+
+ PXOR X8, X0
+ PXOR X9, X1
+ PXOR X10, X2
+ PXOR X11, X3
+
+ DECQ AX
+ JNE loop_select_base
+
+ MOVOU X0, (16*0)(DX)
+ MOVOU X1, (16*1)(DX)
+ MOVOU X2, (16*2)(DX)
+ MOVOU X3, (16*3)(DX)
+
+ RET
+/* ---------------------------------------*/
+// func p256OrdMul(res, in1, in2 *p256OrdElement)
+TEXT ·p256OrdMul(SB),NOSPLIT,$0
+ MOVQ res+0(FP), res_ptr
+ MOVQ in1+8(FP), x_ptr
+ MOVQ in2+16(FP), y_ptr
+ // x * y[0]
+ MOVQ (8*0)(y_ptr), t0
+
+ MOVQ (8*0)(x_ptr), AX
+ MULQ t0
+ MOVQ AX, acc0
+ MOVQ DX, acc1
+
+ MOVQ (8*1)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc1
+ ADCQ $0, DX
+ MOVQ DX, acc2
+
+ MOVQ (8*2)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc2
+ ADCQ $0, DX
+ MOVQ DX, acc3
+
+ MOVQ (8*3)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc3
+ ADCQ $0, DX
+ MOVQ DX, acc4
+ XORQ acc5, acc5
+ // First reduction step
+ MOVQ acc0, AX
+ MULQ p256ordK0<>(SB)
+ MOVQ AX, t0
+
+ MOVQ p256ord<>+0x00(SB), AX
+ MULQ t0
+ ADDQ AX, acc0
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ p256ord<>+0x08(SB), AX
+ MULQ t0
+ ADDQ t1, acc1
+ ADCQ $0, DX
+ ADDQ AX, acc1
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ p256ord<>+0x10(SB), AX
+ MULQ t0
+ ADDQ t1, acc2
+ ADCQ $0, DX
+ ADDQ AX, acc2
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ p256ord<>+0x18(SB), AX
+ MULQ t0
+ ADDQ t1, acc3
+ ADCQ $0, DX
+ ADDQ AX, acc3
+ ADCQ DX, acc4
+ ADCQ $0, acc5
+ // x * y[1]
+ MOVQ (8*1)(y_ptr), t0
+
+ MOVQ (8*0)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc1
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*1)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc2
+ ADCQ $0, DX
+ ADDQ AX, acc2
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*2)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc3
+ ADCQ $0, DX
+ ADDQ AX, acc3
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*3)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc4
+ ADCQ $0, DX
+ ADDQ AX, acc4
+ ADCQ DX, acc5
+ ADCQ $0, acc0
+ // Second reduction step
+ MOVQ acc1, AX
+ MULQ p256ordK0<>(SB)
+ MOVQ AX, t0
+
+ MOVQ p256ord<>+0x00(SB), AX
+ MULQ t0
+ ADDQ AX, acc1
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ p256ord<>+0x08(SB), AX
+ MULQ t0
+ ADDQ t1, acc2
+ ADCQ $0, DX
+ ADDQ AX, acc2
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ p256ord<>+0x10(SB), AX
+ MULQ t0
+ ADDQ t1, acc3
+ ADCQ $0, DX
+ ADDQ AX, acc3
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ p256ord<>+0x18(SB), AX
+ MULQ t0
+ ADDQ t1, acc4
+ ADCQ $0, DX
+ ADDQ AX, acc4
+ ADCQ DX, acc5
+ ADCQ $0, acc0
+ // x * y[2]
+ MOVQ (8*2)(y_ptr), t0
+
+ MOVQ (8*0)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc2
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*1)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc3
+ ADCQ $0, DX
+ ADDQ AX, acc3
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*2)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc4
+ ADCQ $0, DX
+ ADDQ AX, acc4
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*3)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc5
+ ADCQ $0, DX
+ ADDQ AX, acc5
+ ADCQ DX, acc0
+ ADCQ $0, acc1
+ // Third reduction step
+ MOVQ acc2, AX
+ MULQ p256ordK0<>(SB)
+ MOVQ AX, t0
+
+ MOVQ p256ord<>+0x00(SB), AX
+ MULQ t0
+ ADDQ AX, acc2
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ p256ord<>+0x08(SB), AX
+ MULQ t0
+ ADDQ t1, acc3
+ ADCQ $0, DX
+ ADDQ AX, acc3
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ p256ord<>+0x10(SB), AX
+ MULQ t0
+ ADDQ t1, acc4
+ ADCQ $0, DX
+ ADDQ AX, acc4
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ p256ord<>+0x18(SB), AX
+ MULQ t0
+ ADDQ t1, acc5
+ ADCQ $0, DX
+ ADDQ AX, acc5
+ ADCQ DX, acc0
+ ADCQ $0, acc1
+ // x * y[3]
+ MOVQ (8*3)(y_ptr), t0
+
+ MOVQ (8*0)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc3
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*1)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc4
+ ADCQ $0, DX
+ ADDQ AX, acc4
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*2)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc5
+ ADCQ $0, DX
+ ADDQ AX, acc5
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*3)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc0
+ ADCQ $0, DX
+ ADDQ AX, acc0
+ ADCQ DX, acc1
+ ADCQ $0, acc2
+ // Last reduction step
+ MOVQ acc3, AX
+ MULQ p256ordK0<>(SB)
+ MOVQ AX, t0
+
+ MOVQ p256ord<>+0x00(SB), AX
+ MULQ t0
+ ADDQ AX, acc3
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ p256ord<>+0x08(SB), AX
+ MULQ t0
+ ADDQ t1, acc4
+ ADCQ $0, DX
+ ADDQ AX, acc4
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ p256ord<>+0x10(SB), AX
+ MULQ t0
+ ADDQ t1, acc5
+ ADCQ $0, DX
+ ADDQ AX, acc5
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ p256ord<>+0x18(SB), AX
+ MULQ t0
+ ADDQ t1, acc0
+ ADCQ $0, DX
+ ADDQ AX, acc0
+ ADCQ DX, acc1
+ ADCQ $0, acc2
+ // Copy result [255:0]
+ MOVQ acc4, x_ptr
+ MOVQ acc5, acc3
+ MOVQ acc0, t0
+ MOVQ acc1, t1
+ // Subtract p256
+ SUBQ p256ord<>+0x00(SB), acc4
+ SBBQ p256ord<>+0x08(SB) ,acc5
+ SBBQ p256ord<>+0x10(SB), acc0
+ SBBQ p256ord<>+0x18(SB), acc1
+ SBBQ $0, acc2
+
+ CMOVQCS x_ptr, acc4
+ CMOVQCS acc3, acc5
+ CMOVQCS t0, acc0
+ CMOVQCS t1, acc1
+
+ MOVQ acc4, (8*0)(res_ptr)
+ MOVQ acc5, (8*1)(res_ptr)
+ MOVQ acc0, (8*2)(res_ptr)
+ MOVQ acc1, (8*3)(res_ptr)
+
+ RET
+/* ---------------------------------------*/
+// func p256OrdSqr(res, in *p256OrdElement, n int)
+TEXT ·p256OrdSqr(SB),NOSPLIT,$0
+ MOVQ res+0(FP), res_ptr
+ MOVQ in+8(FP), x_ptr
+ MOVQ n+16(FP), BX
+
+ordSqrLoop:
+
+ // y[1:] * y[0]
+ MOVQ (8*0)(x_ptr), t0
+
+ MOVQ (8*1)(x_ptr), AX
+ MULQ t0
+ MOVQ AX, acc1
+ MOVQ DX, acc2
+
+ MOVQ (8*2)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc2
+ ADCQ $0, DX
+ MOVQ DX, acc3
+
+ MOVQ (8*3)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc3
+ ADCQ $0, DX
+ MOVQ DX, acc4
+ // y[2:] * y[1]
+ MOVQ (8*1)(x_ptr), t0
+
+ MOVQ (8*2)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc3
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ (8*3)(x_ptr), AX
+ MULQ t0
+ ADDQ t1, acc4
+ ADCQ $0, DX
+ ADDQ AX, acc4
+ ADCQ $0, DX
+ MOVQ DX, acc5
+ // y[3] * y[2]
+ MOVQ (8*2)(x_ptr), t0
+
+ MOVQ (8*3)(x_ptr), AX
+ MULQ t0
+ ADDQ AX, acc5
+ ADCQ $0, DX
+ MOVQ DX, y_ptr
+ XORQ t1, t1
+ // *2
+ ADDQ acc1, acc1
+ ADCQ acc2, acc2
+ ADCQ acc3, acc3
+ ADCQ acc4, acc4
+ ADCQ acc5, acc5
+ ADCQ y_ptr, y_ptr
+ ADCQ $0, t1
+ // Missing products
+ MOVQ (8*0)(x_ptr), AX
+ MULQ AX
+ MOVQ AX, acc0
+ MOVQ DX, t0
+
+ MOVQ (8*1)(x_ptr), AX
+ MULQ AX
+ ADDQ t0, acc1
+ ADCQ AX, acc2
+ ADCQ $0, DX
+ MOVQ DX, t0
+
+ MOVQ (8*2)(x_ptr), AX
+ MULQ AX
+ ADDQ t0, acc3
+ ADCQ AX, acc4
+ ADCQ $0, DX
+ MOVQ DX, t0
+
+ MOVQ (8*3)(x_ptr), AX
+ MULQ AX
+ ADDQ t0, acc5
+ ADCQ AX, y_ptr
+ ADCQ DX, t1
+ MOVQ t1, x_ptr
+ // First reduction step
+ MOVQ acc0, AX
+ MULQ p256ordK0<>(SB)
+ MOVQ AX, t0
+
+ MOVQ p256ord<>+0x00(SB), AX
+ MULQ t0
+ ADDQ AX, acc0
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ p256ord<>+0x08(SB), AX
+ MULQ t0
+ ADDQ t1, acc1
+ ADCQ $0, DX
+ ADDQ AX, acc1
+
+ MOVQ t0, t1
+ ADCQ DX, acc2
+ ADCQ $0, t1
+ SUBQ t0, acc2
+ SBBQ $0, t1
+
+ MOVQ t0, AX
+ MOVQ t0, DX
+ MOVQ t0, acc0
+ SHLQ $32, AX
+ SHRQ $32, DX
+
+ ADDQ t1, acc3
+ ADCQ $0, acc0
+ SUBQ AX, acc3
+ SBBQ DX, acc0
+ // Second reduction step
+ MOVQ acc1, AX
+ MULQ p256ordK0<>(SB)
+ MOVQ AX, t0
+
+ MOVQ p256ord<>+0x00(SB), AX
+ MULQ t0
+ ADDQ AX, acc1
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ p256ord<>+0x08(SB), AX
+ MULQ t0
+ ADDQ t1, acc2
+ ADCQ $0, DX
+ ADDQ AX, acc2
+
+ MOVQ t0, t1
+ ADCQ DX, acc3
+ ADCQ $0, t1
+ SUBQ t0, acc3
+ SBBQ $0, t1
+
+ MOVQ t0, AX
+ MOVQ t0, DX
+ MOVQ t0, acc1
+ SHLQ $32, AX
+ SHRQ $32, DX
+
+ ADDQ t1, acc0
+ ADCQ $0, acc1
+ SUBQ AX, acc0
+ SBBQ DX, acc1
+ // Third reduction step
+ MOVQ acc2, AX
+ MULQ p256ordK0<>(SB)
+ MOVQ AX, t0
+
+ MOVQ p256ord<>+0x00(SB), AX
+ MULQ t0
+ ADDQ AX, acc2
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ p256ord<>+0x08(SB), AX
+ MULQ t0
+ ADDQ t1, acc3
+ ADCQ $0, DX
+ ADDQ AX, acc3
+
+ MOVQ t0, t1
+ ADCQ DX, acc0
+ ADCQ $0, t1
+ SUBQ t0, acc0
+ SBBQ $0, t1
+
+ MOVQ t0, AX
+ MOVQ t0, DX
+ MOVQ t0, acc2
+ SHLQ $32, AX
+ SHRQ $32, DX
+
+ ADDQ t1, acc1
+ ADCQ $0, acc2
+ SUBQ AX, acc1
+ SBBQ DX, acc2
+ // Last reduction step
+ MOVQ acc3, AX
+ MULQ p256ordK0<>(SB)
+ MOVQ AX, t0
+
+ MOVQ p256ord<>+0x00(SB), AX
+ MULQ t0
+ ADDQ AX, acc3
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ p256ord<>+0x08(SB), AX
+ MULQ t0
+ ADDQ t1, acc0
+ ADCQ $0, DX
+ ADDQ AX, acc0
+ ADCQ $0, DX
+ MOVQ DX, t1
+
+ MOVQ t0, t1
+ ADCQ DX, acc1
+ ADCQ $0, t1
+ SUBQ t0, acc1
+ SBBQ $0, t1
+
+ MOVQ t0, AX
+ MOVQ t0, DX
+ MOVQ t0, acc3
+ SHLQ $32, AX
+ SHRQ $32, DX
+
+ ADDQ t1, acc2
+ ADCQ $0, acc3
+ SUBQ AX, acc2
+ SBBQ DX, acc3
+ XORQ t0, t0
+ // Add bits [511:256] of the sqr result
+ ADCQ acc4, acc0
+ ADCQ acc5, acc1
+ ADCQ y_ptr, acc2
+ ADCQ x_ptr, acc3
+ ADCQ $0, t0
+
+ MOVQ acc0, acc4
+ MOVQ acc1, acc5
+ MOVQ acc2, y_ptr
+ MOVQ acc3, t1
+ // Subtract p256
+ SUBQ p256ord<>+0x00(SB), acc0
+ SBBQ p256ord<>+0x08(SB) ,acc1
+ SBBQ p256ord<>+0x10(SB), acc2
+ SBBQ p256ord<>+0x18(SB), acc3
+ SBBQ $0, t0
+
+ CMOVQCS acc4, acc0
+ CMOVQCS acc5, acc1
+ CMOVQCS y_ptr, acc2
+ CMOVQCS t1, acc3
+
+ MOVQ acc0, (8*0)(res_ptr)
+ MOVQ acc1, (8*1)(res_ptr)
+ MOVQ acc2, (8*2)(res_ptr)
+ MOVQ acc3, (8*3)(res_ptr)
+ MOVQ res_ptr, x_ptr
+ DECQ BX
+ JNE ordSqrLoop
+
+ RET
+/* ---------------------------------------*/
+#undef res_ptr
+#undef x_ptr
+#undef y_ptr
+
+#undef acc0
+#undef acc1
+#undef acc2
+#undef acc3
+#undef acc4
+#undef acc5
+#undef t0
+#undef t1
+/* ---------------------------------------*/
+#define mul0 AX
+#define mul1 DX
+#define acc0 BX
+#define acc1 CX
+#define acc2 R8
+#define acc3 R9
+#define acc4 R10
+#define acc5 R11
+#define acc6 R12
+#define acc7 R13
+#define t0 R14
+#define t1 R15
+#define t2 DI
+#define t3 SI
+#define hlp BP
+/* ---------------------------------------*/
+TEXT p256SubInternal(SB),NOSPLIT,$0
+ XORQ mul0, mul0
+ SUBQ t0, acc4
+ SBBQ t1, acc5
+ SBBQ t2, acc6
+ SBBQ t3, acc7
+ SBBQ $0, mul0
+
+ MOVQ acc4, acc0
+ MOVQ acc5, acc1
+ MOVQ acc6, acc2
+ MOVQ acc7, acc3
+
+ ADDQ $-1, acc4
+ ADCQ p256const0<>(SB), acc5
+ ADCQ $0, acc6
+ ADCQ p256const1<>(SB), acc7
+ ANDQ $1, mul0
+
+ CMOVQEQ acc0, acc4
+ CMOVQEQ acc1, acc5
+ CMOVQEQ acc2, acc6
+ CMOVQEQ acc3, acc7
+
+ RET
+/* ---------------------------------------*/
+TEXT p256MulInternal(SB),NOSPLIT,$8
+ MOVQ acc4, mul0
+ MULQ t0
+ MOVQ mul0, acc0
+ MOVQ mul1, acc1
+
+ MOVQ acc4, mul0
+ MULQ t1
+ ADDQ mul0, acc1
+ ADCQ $0, mul1
+ MOVQ mul1, acc2
+
+ MOVQ acc4, mul0
+ MULQ t2
+ ADDQ mul0, acc2
+ ADCQ $0, mul1
+ MOVQ mul1, acc3
+
+ MOVQ acc4, mul0
+ MULQ t3
+ ADDQ mul0, acc3
+ ADCQ $0, mul1
+ MOVQ mul1, acc4
+
+ MOVQ acc5, mul0
+ MULQ t0
+ ADDQ mul0, acc1
+ ADCQ $0, mul1
+ MOVQ mul1, hlp
+
+ MOVQ acc5, mul0
+ MULQ t1
+ ADDQ hlp, acc2
+ ADCQ $0, mul1
+ ADDQ mul0, acc2
+ ADCQ $0, mul1
+ MOVQ mul1, hlp
+
+ MOVQ acc5, mul0
+ MULQ t2
+ ADDQ hlp, acc3
+ ADCQ $0, mul1
+ ADDQ mul0, acc3
+ ADCQ $0, mul1
+ MOVQ mul1, hlp
+
+ MOVQ acc5, mul0
+ MULQ t3
+ ADDQ hlp, acc4
+ ADCQ $0, mul1
+ ADDQ mul0, acc4
+ ADCQ $0, mul1
+ MOVQ mul1, acc5
+
+ MOVQ acc6, mul0
+ MULQ t0
+ ADDQ mul0, acc2
+ ADCQ $0, mul1
+ MOVQ mul1, hlp
+
+ MOVQ acc6, mul0
+ MULQ t1
+ ADDQ hlp, acc3
+ ADCQ $0, mul1
+ ADDQ mul0, acc3
+ ADCQ $0, mul1
+ MOVQ mul1, hlp
+
+ MOVQ acc6, mul0
+ MULQ t2
+ ADDQ hlp, acc4
+ ADCQ $0, mul1
+ ADDQ mul0, acc4
+ ADCQ $0, mul1
+ MOVQ mul1, hlp
+
+ MOVQ acc6, mul0
+ MULQ t3
+ ADDQ hlp, acc5
+ ADCQ $0, mul1
+ ADDQ mul0, acc5
+ ADCQ $0, mul1
+ MOVQ mul1, acc6
+
+ MOVQ acc7, mul0
+ MULQ t0
+ ADDQ mul0, acc3
+ ADCQ $0, mul1
+ MOVQ mul1, hlp
+
+ MOVQ acc7, mul0
+ MULQ t1
+ ADDQ hlp, acc4
+ ADCQ $0, mul1
+ ADDQ mul0, acc4
+ ADCQ $0, mul1
+ MOVQ mul1, hlp
+
+ MOVQ acc7, mul0
+ MULQ t2
+ ADDQ hlp, acc5
+ ADCQ $0, mul1
+ ADDQ mul0, acc5
+ ADCQ $0, mul1
+ MOVQ mul1, hlp
+
+ MOVQ acc7, mul0
+ MULQ t3
+ ADDQ hlp, acc6
+ ADCQ $0, mul1
+ ADDQ mul0, acc6
+ ADCQ $0, mul1
+ MOVQ mul1, acc7
+ // First reduction step
+ MOVQ acc0, mul0
+ MOVQ acc0, hlp
+ SHLQ $32, acc0
+ MULQ p256const1<>(SB)
+ SHRQ $32, hlp
+ ADDQ acc0, acc1
+ ADCQ hlp, acc2
+ ADCQ mul0, acc3
+ ADCQ $0, mul1
+ MOVQ mul1, acc0
+ // Second reduction step
+ MOVQ acc1, mul0
+ MOVQ acc1, hlp
+ SHLQ $32, acc1
+ MULQ p256const1<>(SB)
+ SHRQ $32, hlp
+ ADDQ acc1, acc2
+ ADCQ hlp, acc3
+ ADCQ mul0, acc0
+ ADCQ $0, mul1
+ MOVQ mul1, acc1
+ // Third reduction step
+ MOVQ acc2, mul0
+ MOVQ acc2, hlp
+ SHLQ $32, acc2
+ MULQ p256const1<>(SB)
+ SHRQ $32, hlp
+ ADDQ acc2, acc3
+ ADCQ hlp, acc0
+ ADCQ mul0, acc1
+ ADCQ $0, mul1
+ MOVQ mul1, acc2
+ // Last reduction step
+ MOVQ acc3, mul0
+ MOVQ acc3, hlp
+ SHLQ $32, acc3
+ MULQ p256const1<>(SB)
+ SHRQ $32, hlp
+ ADDQ acc3, acc0
+ ADCQ hlp, acc1
+ ADCQ mul0, acc2
+ ADCQ $0, mul1
+ MOVQ mul1, acc3
+ MOVQ $0, BP
+ // Add bits [511:256] of the result
+ ADCQ acc0, acc4
+ ADCQ acc1, acc5
+ ADCQ acc2, acc6
+ ADCQ acc3, acc7
+ ADCQ $0, hlp
+ // Copy result
+ MOVQ acc4, acc0
+ MOVQ acc5, acc1
+ MOVQ acc6, acc2
+ MOVQ acc7, acc3
+ // Subtract p256
+ SUBQ $-1, acc4
+ SBBQ p256const0<>(SB) ,acc5
+ SBBQ $0, acc6
+ SBBQ p256const1<>(SB), acc7
+ SBBQ $0, hlp
+ // If the result of the subtraction is negative, restore the previous result
+ CMOVQCS acc0, acc4
+ CMOVQCS acc1, acc5
+ CMOVQCS acc2, acc6
+ CMOVQCS acc3, acc7
+
+ RET
+/* ---------------------------------------*/
+TEXT p256SqrInternal(SB),NOSPLIT,$8
+
+ MOVQ acc4, mul0
+ MULQ acc5
+ MOVQ mul0, acc1
+ MOVQ mul1, acc2
+
+ MOVQ acc4, mul0
+ MULQ acc6
+ ADDQ mul0, acc2
+ ADCQ $0, mul1
+ MOVQ mul1, acc3
+
+ MOVQ acc4, mul0
+ MULQ acc7
+ ADDQ mul0, acc3
+ ADCQ $0, mul1
+ MOVQ mul1, t0
+
+ MOVQ acc5, mul0
+ MULQ acc6
+ ADDQ mul0, acc3
+ ADCQ $0, mul1
+ MOVQ mul1, hlp
+
+ MOVQ acc5, mul0
+ MULQ acc7
+ ADDQ hlp, t0
+ ADCQ $0, mul1
+ ADDQ mul0, t0
+ ADCQ $0, mul1
+ MOVQ mul1, t1
+
+ MOVQ acc6, mul0
+ MULQ acc7
+ ADDQ mul0, t1
+ ADCQ $0, mul1
+ MOVQ mul1, t2
+ XORQ t3, t3
+ // *2
+ ADDQ acc1, acc1
+ ADCQ acc2, acc2
+ ADCQ acc3, acc3
+ ADCQ t0, t0
+ ADCQ t1, t1
+ ADCQ t2, t2
+ ADCQ $0, t3
+ // Missing products
+ MOVQ acc4, mul0
+ MULQ mul0
+ MOVQ mul0, acc0
+ MOVQ DX, acc4
+
+ MOVQ acc5, mul0
+ MULQ mul0
+ ADDQ acc4, acc1
+ ADCQ mul0, acc2
+ ADCQ $0, DX
+ MOVQ DX, acc4
+
+ MOVQ acc6, mul0
+ MULQ mul0
+ ADDQ acc4, acc3
+ ADCQ mul0, t0
+ ADCQ $0, DX
+ MOVQ DX, acc4
+
+ MOVQ acc7, mul0
+ MULQ mul0
+ ADDQ acc4, t1
+ ADCQ mul0, t2
+ ADCQ DX, t3
+ // First reduction step
+ MOVQ acc0, mul0
+ MOVQ acc0, hlp
+ SHLQ $32, acc0
+ MULQ p256const1<>(SB)
+ SHRQ $32, hlp
+ ADDQ acc0, acc1
+ ADCQ hlp, acc2
+ ADCQ mul0, acc3
+ ADCQ $0, mul1
+ MOVQ mul1, acc0
+ // Second reduction step
+ MOVQ acc1, mul0
+ MOVQ acc1, hlp
+ SHLQ $32, acc1
+ MULQ p256const1<>(SB)
+ SHRQ $32, hlp
+ ADDQ acc1, acc2
+ ADCQ hlp, acc3
+ ADCQ mul0, acc0
+ ADCQ $0, mul1
+ MOVQ mul1, acc1
+ // Third reduction step
+ MOVQ acc2, mul0
+ MOVQ acc2, hlp
+ SHLQ $32, acc2
+ MULQ p256const1<>(SB)
+ SHRQ $32, hlp
+ ADDQ acc2, acc3
+ ADCQ hlp, acc0
+ ADCQ mul0, acc1
+ ADCQ $0, mul1
+ MOVQ mul1, acc2
+ // Last reduction step
+ MOVQ acc3, mul0
+ MOVQ acc3, hlp
+ SHLQ $32, acc3
+ MULQ p256const1<>(SB)
+ SHRQ $32, hlp
+ ADDQ acc3, acc0
+ ADCQ hlp, acc1
+ ADCQ mul0, acc2
+ ADCQ $0, mul1
+ MOVQ mul1, acc3
+ MOVQ $0, BP
+ // Add bits [511:256] of the result
+ ADCQ acc0, t0
+ ADCQ acc1, t1
+ ADCQ acc2, t2
+ ADCQ acc3, t3
+ ADCQ $0, hlp
+ // Copy result
+ MOVQ t0, acc4
+ MOVQ t1, acc5
+ MOVQ t2, acc6
+ MOVQ t3, acc7
+ // Subtract p256
+ SUBQ $-1, acc4
+ SBBQ p256const0<>(SB) ,acc5
+ SBBQ $0, acc6
+ SBBQ p256const1<>(SB), acc7
+ SBBQ $0, hlp
+ // If the result of the subtraction is negative, restore the previous result
+ CMOVQCS t0, acc4
+ CMOVQCS t1, acc5
+ CMOVQCS t2, acc6
+ CMOVQCS t3, acc7
+
+ RET
+/* ---------------------------------------*/
+#define p256MulBy2Inline\
+ XORQ mul0, mul0;\
+ ADDQ acc4, acc4;\
+ ADCQ acc5, acc5;\
+ ADCQ acc6, acc6;\
+ ADCQ acc7, acc7;\
+ ADCQ $0, mul0;\
+ MOVQ acc4, t0;\
+ MOVQ acc5, t1;\
+ MOVQ acc6, t2;\
+ MOVQ acc7, t3;\
+ SUBQ $-1, t0;\
+ SBBQ p256const0<>(SB), t1;\
+ SBBQ $0, t2;\
+ SBBQ p256const1<>(SB), t3;\
+ SBBQ $0, mul0;\
+ CMOVQCS acc4, t0;\
+ CMOVQCS acc5, t1;\
+ CMOVQCS acc6, t2;\
+ CMOVQCS acc7, t3;
+/* ---------------------------------------*/
+#define p256AddInline \
+ XORQ mul0, mul0;\
+ ADDQ t0, acc4;\
+ ADCQ t1, acc5;\
+ ADCQ t2, acc6;\
+ ADCQ t3, acc7;\
+ ADCQ $0, mul0;\
+ MOVQ acc4, t0;\
+ MOVQ acc5, t1;\
+ MOVQ acc6, t2;\
+ MOVQ acc7, t3;\
+ SUBQ $-1, t0;\
+ SBBQ p256const0<>(SB), t1;\
+ SBBQ $0, t2;\
+ SBBQ p256const1<>(SB), t3;\
+ SBBQ $0, mul0;\
+ CMOVQCS acc4, t0;\
+ CMOVQCS acc5, t1;\
+ CMOVQCS acc6, t2;\
+ CMOVQCS acc7, t3;
+/* ---------------------------------------*/
+#define LDacc(src) MOVQ src(8*0), acc4; MOVQ src(8*1), acc5; MOVQ src(8*2), acc6; MOVQ src(8*3), acc7
+#define LDt(src) MOVQ src(8*0), t0; MOVQ src(8*1), t1; MOVQ src(8*2), t2; MOVQ src(8*3), t3
+#define ST(dst) MOVQ acc4, dst(8*0); MOVQ acc5, dst(8*1); MOVQ acc6, dst(8*2); MOVQ acc7, dst(8*3)
+#define STt(dst) MOVQ t0, dst(8*0); MOVQ t1, dst(8*1); MOVQ t2, dst(8*2); MOVQ t3, dst(8*3)
+#define acc2t MOVQ acc4, t0; MOVQ acc5, t1; MOVQ acc6, t2; MOVQ acc7, t3
+#define t2acc MOVQ t0, acc4; MOVQ t1, acc5; MOVQ t2, acc6; MOVQ t3, acc7
+/* ---------------------------------------*/
+#define x1in(off) (32*0 + off)(SP)
+#define y1in(off) (32*1 + off)(SP)
+#define z1in(off) (32*2 + off)(SP)
+#define x2in(off) (32*3 + off)(SP)
+#define y2in(off) (32*4 + off)(SP)
+#define xout(off) (32*5 + off)(SP)
+#define yout(off) (32*6 + off)(SP)
+#define zout(off) (32*7 + off)(SP)
+#define s2(off) (32*8 + off)(SP)
+#define z1sqr(off) (32*9 + off)(SP)
+#define h(off) (32*10 + off)(SP)
+#define r(off) (32*11 + off)(SP)
+#define hsqr(off) (32*12 + off)(SP)
+#define rsqr(off) (32*13 + off)(SP)
+#define hcub(off) (32*14 + off)(SP)
+#define rptr (32*15)(SP)
+#define sel_save (32*15 + 8)(SP)
+#define zero_save (32*15 + 8 + 4)(SP)
+
+// func p256PointAddAffineAsm(res, in1 *P256Point, in2 *p256AffinePoint, sign, sel, zero int)
+TEXT ·p256PointAddAffineAsm(SB),0,$512-48
+ // Move input to stack in order to free registers
+ MOVQ res+0(FP), AX
+ MOVQ in1+8(FP), BX
+ MOVQ in2+16(FP), CX
+ MOVQ sign+24(FP), DX
+ MOVQ sel+32(FP), t1
+ MOVQ zero+40(FP), t2
+
+ MOVOU (16*0)(BX), X0
+ MOVOU (16*1)(BX), X1
+ MOVOU (16*2)(BX), X2
+ MOVOU (16*3)(BX), X3
+ MOVOU (16*4)(BX), X4
+ MOVOU (16*5)(BX), X5
+
+ MOVOU X0, x1in(16*0)
+ MOVOU X1, x1in(16*1)
+ MOVOU X2, y1in(16*0)
+ MOVOU X3, y1in(16*1)
+ MOVOU X4, z1in(16*0)
+ MOVOU X5, z1in(16*1)
+
+ MOVOU (16*0)(CX), X0
+ MOVOU (16*1)(CX), X1
+
+ MOVOU X0, x2in(16*0)
+ MOVOU X1, x2in(16*1)
+ // Store pointer to result
+ MOVQ mul0, rptr
+ MOVL t1, sel_save
+ MOVL t2, zero_save
+ // Negate y2in based on sign
+ MOVQ (16*2 + 8*0)(CX), acc4
+ MOVQ (16*2 + 8*1)(CX), acc5
+ MOVQ (16*2 + 8*2)(CX), acc6
+ MOVQ (16*2 + 8*3)(CX), acc7
+ MOVQ $-1, acc0
+ MOVQ p256const0<>(SB), acc1
+ MOVQ $0, acc2
+ MOVQ p256const1<>(SB), acc3
+ XORQ mul0, mul0
+ // Speculatively subtract
+ SUBQ acc4, acc0
+ SBBQ acc5, acc1
+ SBBQ acc6, acc2
+ SBBQ acc7, acc3
+ SBBQ $0, mul0
+ MOVQ acc0, t0
+ MOVQ acc1, t1
+ MOVQ acc2, t2
+ MOVQ acc3, t3
+ // Add in case the operand was > p256
+ ADDQ $-1, acc0
+ ADCQ p256const0<>(SB), acc1
+ ADCQ $0, acc2
+ ADCQ p256const1<>(SB), acc3
+ ADCQ $0, mul0
+ CMOVQNE t0, acc0
+ CMOVQNE t1, acc1
+ CMOVQNE t2, acc2
+ CMOVQNE t3, acc3
+ // If condition is 0, keep original value
+ TESTQ DX, DX
+ CMOVQEQ acc4, acc0
+ CMOVQEQ acc5, acc1
+ CMOVQEQ acc6, acc2
+ CMOVQEQ acc7, acc3
+ // Store result
+ MOVQ acc0, y2in(8*0)
+ MOVQ acc1, y2in(8*1)
+ MOVQ acc2, y2in(8*2)
+ MOVQ acc3, y2in(8*3)
+ // Begin point add
+ LDacc (z1in)
+ CALL p256SqrInternal(SB) // z1ˆ2
+ ST (z1sqr)
+
+ LDt (x2in)
+ CALL p256MulInternal(SB) // x2 * z1ˆ2
+
+ LDt (x1in)
+ CALL p256SubInternal(SB) // h = u2 - u1
+ ST (h)
+
+ LDt (z1in)
+ CALL p256MulInternal(SB) // z3 = h * z1
+ ST (zout)
+
+ LDacc (z1sqr)
+ CALL p256MulInternal(SB) // z1ˆ3
+
+ LDt (y2in)
+ CALL p256MulInternal(SB) // s2 = y2 * z1ˆ3
+ ST (s2)
+
+ LDt (y1in)
+ CALL p256SubInternal(SB) // r = s2 - s1
+ ST (r)
+
+ CALL p256SqrInternal(SB) // rsqr = rˆ2
+ ST (rsqr)
+
+ LDacc (h)
+ CALL p256SqrInternal(SB) // hsqr = hˆ2
+ ST (hsqr)
+
+ LDt (h)
+ CALL p256MulInternal(SB) // hcub = hˆ3
+ ST (hcub)
+
+ LDt (y1in)
+ CALL p256MulInternal(SB) // y1 * hˆ3
+ ST (s2)
+
+ LDacc (x1in)
+ LDt (hsqr)
+ CALL p256MulInternal(SB) // u1 * hˆ2
+ ST (h)
+
+ p256MulBy2Inline // u1 * hˆ2 * 2, inline
+ LDacc (rsqr)
+ CALL p256SubInternal(SB) // rˆ2 - u1 * hˆ2 * 2
+
+ LDt (hcub)
+ CALL p256SubInternal(SB)
+ ST (xout)
+
+ MOVQ acc4, t0
+ MOVQ acc5, t1
+ MOVQ acc6, t2
+ MOVQ acc7, t3
+ LDacc (h)
+ CALL p256SubInternal(SB)
+
+ LDt (r)
+ CALL p256MulInternal(SB)
+
+ LDt (s2)
+ CALL p256SubInternal(SB)
+ ST (yout)
+ // Load stored values from stack
+ MOVQ rptr, AX
+ MOVL sel_save, BX
+ MOVL zero_save, CX
+ // The result is not valid if (sel == 0), conditional choose
+ MOVOU xout(16*0), X0
+ MOVOU xout(16*1), X1
+ MOVOU yout(16*0), X2
+ MOVOU yout(16*1), X3
+ MOVOU zout(16*0), X4
+ MOVOU zout(16*1), X5
+
+ MOVL BX, X6
+ MOVL CX, X7
+
+ PXOR X8, X8
+ PCMPEQL X9, X9
+
+ PSHUFD $0, X6, X6
+ PSHUFD $0, X7, X7
+
+ PCMPEQL X8, X6
+ PCMPEQL X8, X7
+
+ MOVOU X6, X15
+ PANDN X9, X15
+
+ MOVOU x1in(16*0), X9
+ MOVOU x1in(16*1), X10
+ MOVOU y1in(16*0), X11
+ MOVOU y1in(16*1), X12
+ MOVOU z1in(16*0), X13
+ MOVOU z1in(16*1), X14
+
+ PAND X15, X0
+ PAND X15, X1
+ PAND X15, X2
+ PAND X15, X3
+ PAND X15, X4
+ PAND X15, X5
+
+ PAND X6, X9
+ PAND X6, X10
+ PAND X6, X11
+ PAND X6, X12
+ PAND X6, X13
+ PAND X6, X14
+
+ PXOR X9, X0
+ PXOR X10, X1
+ PXOR X11, X2
+ PXOR X12, X3
+ PXOR X13, X4
+ PXOR X14, X5
+ // Similarly if zero == 0
+ PCMPEQL X9, X9
+ MOVOU X7, X15
+ PANDN X9, X15
+
+ MOVOU x2in(16*0), X9
+ MOVOU x2in(16*1), X10
+ MOVOU y2in(16*0), X11
+ MOVOU y2in(16*1), X12
+ MOVOU p256one<>+0x00(SB), X13
+ MOVOU p256one<>+0x10(SB), X14
+
+ PAND X15, X0
+ PAND X15, X1
+ PAND X15, X2
+ PAND X15, X3
+ PAND X15, X4
+ PAND X15, X5
+
+ PAND X7, X9
+ PAND X7, X10
+ PAND X7, X11
+ PAND X7, X12
+ PAND X7, X13
+ PAND X7, X14
+
+ PXOR X9, X0
+ PXOR X10, X1
+ PXOR X11, X2
+ PXOR X12, X3
+ PXOR X13, X4
+ PXOR X14, X5
+ // Finally output the result
+ MOVOU X0, (16*0)(AX)
+ MOVOU X1, (16*1)(AX)
+ MOVOU X2, (16*2)(AX)
+ MOVOU X3, (16*3)(AX)
+ MOVOU X4, (16*4)(AX)
+ MOVOU X5, (16*5)(AX)
+ MOVQ $0, rptr
+
+ RET
+#undef x1in
+#undef y1in
+#undef z1in
+#undef x2in
+#undef y2in
+#undef xout
+#undef yout
+#undef zout
+#undef s2
+#undef z1sqr
+#undef h
+#undef r
+#undef hsqr
+#undef rsqr
+#undef hcub
+#undef rptr
+#undef sel_save
+#undef zero_save
+
+// p256IsZero returns 1 in AX if [acc4..acc7] represents zero and zero
+// otherwise. It writes to [acc4..acc7], t0 and t1.
+TEXT p256IsZero(SB),NOSPLIT,$0
+ // AX contains a flag that is set if the input is zero.
+ XORQ AX, AX
+ MOVQ $1, t1
+
+ // Check whether [acc4..acc7] are all zero.
+ MOVQ acc4, t0
+ ORQ acc5, t0
+ ORQ acc6, t0
+ ORQ acc7, t0
+
+ // Set the zero flag if so. (CMOV of a constant to a register doesn't
+ // appear to be supported in Go. Thus t1 = 1.)
+ CMOVQEQ t1, AX
+
+ // XOR [acc4..acc7] with P and compare with zero again.
+ XORQ $-1, acc4
+ XORQ p256const0<>(SB), acc5
+ XORQ p256const1<>(SB), acc7
+ ORQ acc5, acc4
+ ORQ acc6, acc4
+ ORQ acc7, acc4
+
+ // Set the zero flag if so.
+ CMOVQEQ t1, AX
+ RET
+
+/* ---------------------------------------*/
+#define x1in(off) (32*0 + off)(SP)
+#define y1in(off) (32*1 + off)(SP)
+#define z1in(off) (32*2 + off)(SP)
+#define x2in(off) (32*3 + off)(SP)
+#define y2in(off) (32*4 + off)(SP)
+#define z2in(off) (32*5 + off)(SP)
+
+#define xout(off) (32*6 + off)(SP)
+#define yout(off) (32*7 + off)(SP)
+#define zout(off) (32*8 + off)(SP)
+
+#define u1(off) (32*9 + off)(SP)
+#define u2(off) (32*10 + off)(SP)
+#define s1(off) (32*11 + off)(SP)
+#define s2(off) (32*12 + off)(SP)
+#define z1sqr(off) (32*13 + off)(SP)
+#define z2sqr(off) (32*14 + off)(SP)
+#define h(off) (32*15 + off)(SP)
+#define r(off) (32*16 + off)(SP)
+#define hsqr(off) (32*17 + off)(SP)
+#define rsqr(off) (32*18 + off)(SP)
+#define hcub(off) (32*19 + off)(SP)
+#define rptr (32*20)(SP)
+#define points_eq (32*20+8)(SP)
+
+//func p256PointAddAsm(res, in1, in2 *P256Point) int
+TEXT ·p256PointAddAsm(SB),0,$680-32
+ // See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
+ // Move input to stack in order to free registers
+ MOVQ res+0(FP), AX
+ MOVQ in1+8(FP), BX
+ MOVQ in2+16(FP), CX
+
+ MOVOU (16*0)(BX), X0
+ MOVOU (16*1)(BX), X1
+ MOVOU (16*2)(BX), X2
+ MOVOU (16*3)(BX), X3
+ MOVOU (16*4)(BX), X4
+ MOVOU (16*5)(BX), X5
+
+ MOVOU X0, x1in(16*0)
+ MOVOU X1, x1in(16*1)
+ MOVOU X2, y1in(16*0)
+ MOVOU X3, y1in(16*1)
+ MOVOU X4, z1in(16*0)
+ MOVOU X5, z1in(16*1)
+
+ MOVOU (16*0)(CX), X0
+ MOVOU (16*1)(CX), X1
+ MOVOU (16*2)(CX), X2
+ MOVOU (16*3)(CX), X3
+ MOVOU (16*4)(CX), X4
+ MOVOU (16*5)(CX), X5
+
+ MOVOU X0, x2in(16*0)
+ MOVOU X1, x2in(16*1)
+ MOVOU X2, y2in(16*0)
+ MOVOU X3, y2in(16*1)
+ MOVOU X4, z2in(16*0)
+ MOVOU X5, z2in(16*1)
+ // Store pointer to result
+ MOVQ AX, rptr
+ // Begin point add
+ LDacc (z2in)
+ CALL p256SqrInternal(SB) // z2ˆ2
+ ST (z2sqr)
+ LDt (z2in)
+ CALL p256MulInternal(SB) // z2ˆ3
+ LDt (y1in)
+ CALL p256MulInternal(SB) // s1 = z2ˆ3*y1
+ ST (s1)
+
+ LDacc (z1in)
+ CALL p256SqrInternal(SB) // z1ˆ2
+ ST (z1sqr)
+ LDt (z1in)
+ CALL p256MulInternal(SB) // z1ˆ3
+ LDt (y2in)
+ CALL p256MulInternal(SB) // s2 = z1ˆ3*y2
+ ST (s2)
+
+ LDt (s1)
+ CALL p256SubInternal(SB) // r = s2 - s1
+ ST (r)
+ CALL p256IsZero(SB)
+ MOVQ AX, points_eq
+
+ LDacc (z2sqr)
+ LDt (x1in)
+ CALL p256MulInternal(SB) // u1 = x1 * z2ˆ2
+ ST (u1)
+ LDacc (z1sqr)
+ LDt (x2in)
+ CALL p256MulInternal(SB) // u2 = x2 * z1ˆ2
+ ST (u2)
+
+ LDt (u1)
+ CALL p256SubInternal(SB) // h = u2 - u1
+ ST (h)
+ CALL p256IsZero(SB)
+ ANDQ points_eq, AX
+ MOVQ AX, points_eq
+
+ LDacc (r)
+ CALL p256SqrInternal(SB) // rsqr = rˆ2
+ ST (rsqr)
+
+ LDacc (h)
+ CALL p256SqrInternal(SB) // hsqr = hˆ2
+ ST (hsqr)
+
+ LDt (h)
+ CALL p256MulInternal(SB) // hcub = hˆ3
+ ST (hcub)
+
+ LDt (s1)
+ CALL p256MulInternal(SB)
+ ST (s2)
+
+ LDacc (z1in)
+ LDt (z2in)
+ CALL p256MulInternal(SB) // z1 * z2
+ LDt (h)
+ CALL p256MulInternal(SB) // z1 * z2 * h
+ ST (zout)
+
+ LDacc (hsqr)
+ LDt (u1)
+ CALL p256MulInternal(SB) // hˆ2 * u1
+ ST (u2)
+
+ p256MulBy2Inline // u1 * hˆ2 * 2, inline
+ LDacc (rsqr)
+ CALL p256SubInternal(SB) // rˆ2 - u1 * hˆ2 * 2
+
+ LDt (hcub)
+ CALL p256SubInternal(SB)
+ ST (xout)
+
+ MOVQ acc4, t0
+ MOVQ acc5, t1
+ MOVQ acc6, t2
+ MOVQ acc7, t3
+ LDacc (u2)
+ CALL p256SubInternal(SB)
+
+ LDt (r)
+ CALL p256MulInternal(SB)
+
+ LDt (s2)
+ CALL p256SubInternal(SB)
+ ST (yout)
+
+ MOVOU xout(16*0), X0
+ MOVOU xout(16*1), X1
+ MOVOU yout(16*0), X2
+ MOVOU yout(16*1), X3
+ MOVOU zout(16*0), X4
+ MOVOU zout(16*1), X5
+ // Finally output the result
+ MOVQ rptr, AX
+ MOVQ $0, rptr
+ MOVOU X0, (16*0)(AX)
+ MOVOU X1, (16*1)(AX)
+ MOVOU X2, (16*2)(AX)
+ MOVOU X3, (16*3)(AX)
+ MOVOU X4, (16*4)(AX)
+ MOVOU X5, (16*5)(AX)
+
+ MOVQ points_eq, AX
+ MOVQ AX, ret+24(FP)
+
+ RET
+#undef x1in
+#undef y1in
+#undef z1in
+#undef x2in
+#undef y2in
+#undef z2in
+#undef xout
+#undef yout
+#undef zout
+#undef s1
+#undef s2
+#undef u1
+#undef u2
+#undef z1sqr
+#undef z2sqr
+#undef h
+#undef r
+#undef hsqr
+#undef rsqr
+#undef hcub
+#undef rptr
+/* ---------------------------------------*/
+#define x(off) (32*0 + off)(SP)
+#define y(off) (32*1 + off)(SP)
+#define z(off) (32*2 + off)(SP)
+
+#define s(off) (32*3 + off)(SP)
+#define m(off) (32*4 + off)(SP)
+#define zsqr(off) (32*5 + off)(SP)
+#define tmp(off) (32*6 + off)(SP)
+#define rptr (32*7)(SP)
+
+//func p256PointDoubleAsm(res, in *P256Point)
+TEXT ·p256PointDoubleAsm(SB),NOSPLIT,$256-16
+ // Move input to stack in order to free registers
+ MOVQ res+0(FP), AX
+ MOVQ in+8(FP), BX
+
+ MOVOU (16*0)(BX), X0
+ MOVOU (16*1)(BX), X1
+ MOVOU (16*2)(BX), X2
+ MOVOU (16*3)(BX), X3
+ MOVOU (16*4)(BX), X4
+ MOVOU (16*5)(BX), X5
+
+ MOVOU X0, x(16*0)
+ MOVOU X1, x(16*1)
+ MOVOU X2, y(16*0)
+ MOVOU X3, y(16*1)
+ MOVOU X4, z(16*0)
+ MOVOU X5, z(16*1)
+ // Store pointer to result
+ MOVQ AX, rptr
+ // Begin point double
+ LDacc (z)
+ CALL p256SqrInternal(SB)
+ ST (zsqr)
+
+ LDt (x)
+ p256AddInline
+ STt (m)
+
+ LDacc (z)
+ LDt (y)
+ CALL p256MulInternal(SB)
+ p256MulBy2Inline
+ MOVQ rptr, AX
+ // Store z
+ MOVQ t0, (16*4 + 8*0)(AX)
+ MOVQ t1, (16*4 + 8*1)(AX)
+ MOVQ t2, (16*4 + 8*2)(AX)
+ MOVQ t3, (16*4 + 8*3)(AX)
+
+ LDacc (x)
+ LDt (zsqr)
+ CALL p256SubInternal(SB)
+ LDt (m)
+ CALL p256MulInternal(SB)
+ ST (m)
+ // Multiply by 3
+ p256MulBy2Inline
+ LDacc (m)
+ p256AddInline
+ STt (m)
+ ////////////////////////
+ LDacc (y)
+ p256MulBy2Inline
+ t2acc
+ CALL p256SqrInternal(SB)
+ ST (s)
+ CALL p256SqrInternal(SB)
+ // Divide by 2
+ XORQ mul0, mul0
+ MOVQ acc4, t0
+ MOVQ acc5, t1
+ MOVQ acc6, t2
+ MOVQ acc7, t3
+
+ ADDQ $-1, acc4
+ ADCQ p256const0<>(SB), acc5
+ ADCQ $0, acc6
+ ADCQ p256const1<>(SB), acc7
+ ADCQ $0, mul0
+ TESTQ $1, t0
+
+ CMOVQEQ t0, acc4
+ CMOVQEQ t1, acc5
+ CMOVQEQ t2, acc6
+ CMOVQEQ t3, acc7
+ ANDQ t0, mul0
+
+ SHRQ $1, acc5, acc4
+ SHRQ $1, acc6, acc5
+ SHRQ $1, acc7, acc6
+ SHRQ $1, mul0, acc7
+ ST (y)
+ /////////////////////////
+ LDacc (x)
+ LDt (s)
+ CALL p256MulInternal(SB)
+ ST (s)
+ p256MulBy2Inline
+ STt (tmp)
+
+ LDacc (m)
+ CALL p256SqrInternal(SB)
+ LDt (tmp)
+ CALL p256SubInternal(SB)
+
+ MOVQ rptr, AX
+ // Store x
+ MOVQ acc4, (16*0 + 8*0)(AX)
+ MOVQ acc5, (16*0 + 8*1)(AX)
+ MOVQ acc6, (16*0 + 8*2)(AX)
+ MOVQ acc7, (16*0 + 8*3)(AX)
+
+ acc2t
+ LDacc (s)
+ CALL p256SubInternal(SB)
+
+ LDt (m)
+ CALL p256MulInternal(SB)
+
+ LDt (y)
+ CALL p256SubInternal(SB)
+ MOVQ rptr, AX
+ // Store y
+ MOVQ acc4, (16*2 + 8*0)(AX)
+ MOVQ acc5, (16*2 + 8*1)(AX)
+ MOVQ acc6, (16*2 + 8*2)(AX)
+ MOVQ acc7, (16*2 + 8*3)(AX)
+ ///////////////////////
+ MOVQ $0, rptr
+
+ RET
+/* ---------------------------------------*/
diff --git a/src/crypto/internal/nistec/p256_asm_arm64.s b/src/crypto/internal/nistec/p256_asm_arm64.s
new file mode 100644
index 0000000..1ba5df3
--- /dev/null
+++ b/src/crypto/internal/nistec/p256_asm_arm64.s
@@ -0,0 +1,1533 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// This file contains constant-time, 64-bit assembly implementation of
+// P256. The optimizations performed here are described in detail in:
+// S.Gueron and V.Krasnov, "Fast prime field elliptic-curve cryptography with
+// 256-bit primes"
+// http://link.springer.com/article/10.1007%2Fs13389-014-0090-x
+// https://eprint.iacr.org/2013/816.pdf
+
+#include "textflag.h"
+
+#define res_ptr R0
+#define a_ptr R1
+#define b_ptr R2
+
+#define acc0 R3
+#define acc1 R4
+#define acc2 R5
+#define acc3 R6
+
+#define acc4 R7
+#define acc5 R8
+#define acc6 R9
+#define acc7 R10
+#define t0 R11
+#define t1 R12
+#define t2 R13
+#define t3 R14
+#define const0 R15
+#define const1 R16
+
+#define hlp0 R17
+#define hlp1 res_ptr
+
+#define x0 R19
+#define x1 R20
+#define x2 R21
+#define x3 R22
+#define y0 R23
+#define y1 R24
+#define y2 R25
+#define y3 R26
+
+#define const2 t2
+#define const3 t3
+
+DATA p256const0<>+0x00(SB)/8, $0x00000000ffffffff
+DATA p256const1<>+0x00(SB)/8, $0xffffffff00000001
+DATA p256ordK0<>+0x00(SB)/8, $0xccd1c8aaee00bc4f
+DATA p256ord<>+0x00(SB)/8, $0xf3b9cac2fc632551
+DATA p256ord<>+0x08(SB)/8, $0xbce6faada7179e84
+DATA p256ord<>+0x10(SB)/8, $0xffffffffffffffff
+DATA p256ord<>+0x18(SB)/8, $0xffffffff00000000
+DATA p256one<>+0x00(SB)/8, $0x0000000000000001
+DATA p256one<>+0x08(SB)/8, $0xffffffff00000000
+DATA p256one<>+0x10(SB)/8, $0xffffffffffffffff
+DATA p256one<>+0x18(SB)/8, $0x00000000fffffffe
+GLOBL p256const0<>(SB), 8, $8
+GLOBL p256const1<>(SB), 8, $8
+GLOBL p256ordK0<>(SB), 8, $8
+GLOBL p256ord<>(SB), 8, $32
+GLOBL p256one<>(SB), 8, $32
+
+/* ---------------------------------------*/
+// func p256OrdLittleToBig(res *[32]byte, in *p256OrdElement)
+TEXT ·p256OrdLittleToBig(SB),NOSPLIT,$0
+ JMP ·p256BigToLittle(SB)
+/* ---------------------------------------*/
+// func p256OrdBigToLittle(res *p256OrdElement, in *[32]byte)
+TEXT ·p256OrdBigToLittle(SB),NOSPLIT,$0
+ JMP ·p256BigToLittle(SB)
+/* ---------------------------------------*/
+// func p256LittleToBig(res *[32]byte, in *p256Element)
+TEXT ·p256LittleToBig(SB),NOSPLIT,$0
+ JMP ·p256BigToLittle(SB)
+/* ---------------------------------------*/
+// func p256BigToLittle(res *p256Element, in *[32]byte)
+TEXT ·p256BigToLittle(SB),NOSPLIT,$0
+ MOVD res+0(FP), res_ptr
+ MOVD in+8(FP), a_ptr
+
+ LDP 0*16(a_ptr), (acc0, acc1)
+ LDP 1*16(a_ptr), (acc2, acc3)
+
+ REV acc0, acc0
+ REV acc1, acc1
+ REV acc2, acc2
+ REV acc3, acc3
+
+ STP (acc3, acc2), 0*16(res_ptr)
+ STP (acc1, acc0), 1*16(res_ptr)
+ RET
+/* ---------------------------------------*/
+// func p256MovCond(res, a, b *P256Point, cond int)
+// If cond == 0 res=b, else res=a
+TEXT ·p256MovCond(SB),NOSPLIT,$0
+ MOVD res+0(FP), res_ptr
+ MOVD a+8(FP), a_ptr
+ MOVD b+16(FP), b_ptr
+ MOVD cond+24(FP), R3
+
+ CMP $0, R3
+ // Two remarks:
+ // 1) Will want to revisit NEON, when support is better
+ // 2) CSEL might not be constant time on all ARM processors
+ LDP 0*16(a_ptr), (R4, R5)
+ LDP 1*16(a_ptr), (R6, R7)
+ LDP 2*16(a_ptr), (R8, R9)
+ LDP 0*16(b_ptr), (R16, R17)
+ LDP 1*16(b_ptr), (R19, R20)
+ LDP 2*16(b_ptr), (R21, R22)
+ CSEL EQ, R16, R4, R4
+ CSEL EQ, R17, R5, R5
+ CSEL EQ, R19, R6, R6
+ CSEL EQ, R20, R7, R7
+ CSEL EQ, R21, R8, R8
+ CSEL EQ, R22, R9, R9
+ STP (R4, R5), 0*16(res_ptr)
+ STP (R6, R7), 1*16(res_ptr)
+ STP (R8, R9), 2*16(res_ptr)
+
+ LDP 3*16(a_ptr), (R4, R5)
+ LDP 4*16(a_ptr), (R6, R7)
+ LDP 5*16(a_ptr), (R8, R9)
+ LDP 3*16(b_ptr), (R16, R17)
+ LDP 4*16(b_ptr), (R19, R20)
+ LDP 5*16(b_ptr), (R21, R22)
+ CSEL EQ, R16, R4, R4
+ CSEL EQ, R17, R5, R5
+ CSEL EQ, R19, R6, R6
+ CSEL EQ, R20, R7, R7
+ CSEL EQ, R21, R8, R8
+ CSEL EQ, R22, R9, R9
+ STP (R4, R5), 3*16(res_ptr)
+ STP (R6, R7), 4*16(res_ptr)
+ STP (R8, R9), 5*16(res_ptr)
+
+ RET
+/* ---------------------------------------*/
+// func p256NegCond(val *p256Element, cond int)
+TEXT ·p256NegCond(SB),NOSPLIT,$0
+ MOVD val+0(FP), a_ptr
+ MOVD cond+8(FP), hlp0
+ MOVD a_ptr, res_ptr
+ // acc = poly
+ MOVD $-1, acc0
+ MOVD p256const0<>(SB), acc1
+ MOVD $0, acc2
+ MOVD p256const1<>(SB), acc3
+ // Load the original value
+ LDP 0*16(a_ptr), (t0, t1)
+ LDP 1*16(a_ptr), (t2, t3)
+ // Speculatively subtract
+ SUBS t0, acc0
+ SBCS t1, acc1
+ SBCS t2, acc2
+ SBC t3, acc3
+ // If condition is 0, keep original value
+ CMP $0, hlp0
+ CSEL EQ, t0, acc0, acc0
+ CSEL EQ, t1, acc1, acc1
+ CSEL EQ, t2, acc2, acc2
+ CSEL EQ, t3, acc3, acc3
+ // Store result
+ STP (acc0, acc1), 0*16(res_ptr)
+ STP (acc2, acc3), 1*16(res_ptr)
+
+ RET
+/* ---------------------------------------*/
+// func p256Sqr(res, in *p256Element, n int)
+TEXT ·p256Sqr(SB),NOSPLIT,$0
+ MOVD res+0(FP), res_ptr
+ MOVD in+8(FP), a_ptr
+ MOVD n+16(FP), b_ptr
+
+ MOVD p256const0<>(SB), const0
+ MOVD p256const1<>(SB), const1
+
+ LDP 0*16(a_ptr), (x0, x1)
+ LDP 1*16(a_ptr), (x2, x3)
+
+sqrLoop:
+ SUB $1, b_ptr
+ CALL p256SqrInternal<>(SB)
+ MOVD y0, x0
+ MOVD y1, x1
+ MOVD y2, x2
+ MOVD y3, x3
+ CBNZ b_ptr, sqrLoop
+
+ STP (y0, y1), 0*16(res_ptr)
+ STP (y2, y3), 1*16(res_ptr)
+ RET
+/* ---------------------------------------*/
+// func p256Mul(res, in1, in2 *p256Element)
+TEXT ·p256Mul(SB),NOSPLIT,$0
+ MOVD res+0(FP), res_ptr
+ MOVD in1+8(FP), a_ptr
+ MOVD in2+16(FP), b_ptr
+
+ MOVD p256const0<>(SB), const0
+ MOVD p256const1<>(SB), const1
+
+ LDP 0*16(a_ptr), (x0, x1)
+ LDP 1*16(a_ptr), (x2, x3)
+
+ LDP 0*16(b_ptr), (y0, y1)
+ LDP 1*16(b_ptr), (y2, y3)
+
+ CALL p256MulInternal<>(SB)
+
+ STP (y0, y1), 0*16(res_ptr)
+ STP (y2, y3), 1*16(res_ptr)
+ RET
+/* ---------------------------------------*/
+// func p256FromMont(res, in *p256Element)
+TEXT ·p256FromMont(SB),NOSPLIT,$0
+ MOVD res+0(FP), res_ptr
+ MOVD in+8(FP), a_ptr
+
+ MOVD p256const0<>(SB), const0
+ MOVD p256const1<>(SB), const1
+
+ LDP 0*16(a_ptr), (acc0, acc1)
+ LDP 1*16(a_ptr), (acc2, acc3)
+ // Only reduce, no multiplications are needed
+ // First reduction step
+ ADDS acc0<<32, acc1, acc1
+ LSR $32, acc0, t0
+ MUL acc0, const1, t1
+ UMULH acc0, const1, acc0
+ ADCS t0, acc2
+ ADCS t1, acc3
+ ADC $0, acc0
+ // Second reduction step
+ ADDS acc1<<32, acc2, acc2
+ LSR $32, acc1, t0
+ MUL acc1, const1, t1
+ UMULH acc1, const1, acc1
+ ADCS t0, acc3
+ ADCS t1, acc0
+ ADC $0, acc1
+ // Third reduction step
+ ADDS acc2<<32, acc3, acc3
+ LSR $32, acc2, t0
+ MUL acc2, const1, t1
+ UMULH acc2, const1, acc2
+ ADCS t0, acc0
+ ADCS t1, acc1
+ ADC $0, acc2
+ // Last reduction step
+ ADDS acc3<<32, acc0, acc0
+ LSR $32, acc3, t0
+ MUL acc3, const1, t1
+ UMULH acc3, const1, acc3
+ ADCS t0, acc1
+ ADCS t1, acc2
+ ADC $0, acc3
+
+ SUBS $-1, acc0, t0
+ SBCS const0, acc1, t1
+ SBCS $0, acc2, t2
+ SBCS const1, acc3, t3
+
+ CSEL CS, t0, acc0, acc0
+ CSEL CS, t1, acc1, acc1
+ CSEL CS, t2, acc2, acc2
+ CSEL CS, t3, acc3, acc3
+
+ STP (acc0, acc1), 0*16(res_ptr)
+ STP (acc2, acc3), 1*16(res_ptr)
+
+ RET
+/* ---------------------------------------*/
+// func p256Select(res *P256Point, table *p256Table, idx int)
+TEXT ·p256Select(SB),NOSPLIT,$0
+ MOVD idx+16(FP), const0
+ MOVD table+8(FP), b_ptr
+ MOVD res+0(FP), res_ptr
+
+ EOR x0, x0, x0
+ EOR x1, x1, x1
+ EOR x2, x2, x2
+ EOR x3, x3, x3
+ EOR y0, y0, y0
+ EOR y1, y1, y1
+ EOR y2, y2, y2
+ EOR y3, y3, y3
+ EOR t0, t0, t0
+ EOR t1, t1, t1
+ EOR t2, t2, t2
+ EOR t3, t3, t3
+
+ MOVD $0, const1
+
+loop_select:
+ ADD $1, const1
+ CMP const0, const1
+ LDP.P 16(b_ptr), (acc0, acc1)
+ CSEL EQ, acc0, x0, x0
+ CSEL EQ, acc1, x1, x1
+ LDP.P 16(b_ptr), (acc2, acc3)
+ CSEL EQ, acc2, x2, x2
+ CSEL EQ, acc3, x3, x3
+ LDP.P 16(b_ptr), (acc4, acc5)
+ CSEL EQ, acc4, y0, y0
+ CSEL EQ, acc5, y1, y1
+ LDP.P 16(b_ptr), (acc6, acc7)
+ CSEL EQ, acc6, y2, y2
+ CSEL EQ, acc7, y3, y3
+ LDP.P 16(b_ptr), (acc0, acc1)
+ CSEL EQ, acc0, t0, t0
+ CSEL EQ, acc1, t1, t1
+ LDP.P 16(b_ptr), (acc2, acc3)
+ CSEL EQ, acc2, t2, t2
+ CSEL EQ, acc3, t3, t3
+
+ CMP $16, const1
+ BNE loop_select
+
+ STP (x0, x1), 0*16(res_ptr)
+ STP (x2, x3), 1*16(res_ptr)
+ STP (y0, y1), 2*16(res_ptr)
+ STP (y2, y3), 3*16(res_ptr)
+ STP (t0, t1), 4*16(res_ptr)
+ STP (t2, t3), 5*16(res_ptr)
+ RET
+/* ---------------------------------------*/
+// func p256SelectAffine(res *p256AffinePoint, table *p256AffineTable, idx int)
+TEXT ·p256SelectAffine(SB),NOSPLIT,$0
+ MOVD idx+16(FP), t0
+ MOVD table+8(FP), t1
+ MOVD res+0(FP), res_ptr
+
+ EOR x0, x0, x0
+ EOR x1, x1, x1
+ EOR x2, x2, x2
+ EOR x3, x3, x3
+ EOR y0, y0, y0
+ EOR y1, y1, y1
+ EOR y2, y2, y2
+ EOR y3, y3, y3
+
+ MOVD $0, t2
+
+loop_select:
+ ADD $1, t2
+ CMP t0, t2
+ LDP.P 16(t1), (acc0, acc1)
+ CSEL EQ, acc0, x0, x0
+ CSEL EQ, acc1, x1, x1
+ LDP.P 16(t1), (acc2, acc3)
+ CSEL EQ, acc2, x2, x2
+ CSEL EQ, acc3, x3, x3
+ LDP.P 16(t1), (acc4, acc5)
+ CSEL EQ, acc4, y0, y0
+ CSEL EQ, acc5, y1, y1
+ LDP.P 16(t1), (acc6, acc7)
+ CSEL EQ, acc6, y2, y2
+ CSEL EQ, acc7, y3, y3
+
+ CMP $32, t2
+ BNE loop_select
+
+ STP (x0, x1), 0*16(res_ptr)
+ STP (x2, x3), 1*16(res_ptr)
+ STP (y0, y1), 2*16(res_ptr)
+ STP (y2, y3), 3*16(res_ptr)
+ RET
+/* ---------------------------------------*/
+// func p256OrdSqr(res, in *p256OrdElement, n int)
+TEXT ·p256OrdSqr(SB),NOSPLIT,$0
+ MOVD in+8(FP), a_ptr
+ MOVD n+16(FP), b_ptr
+
+ MOVD p256ordK0<>(SB), hlp1
+ LDP p256ord<>+0x00(SB), (const0, const1)
+ LDP p256ord<>+0x10(SB), (const2, const3)
+
+ LDP 0*16(a_ptr), (x0, x1)
+ LDP 1*16(a_ptr), (x2, x3)
+
+ordSqrLoop:
+ SUB $1, b_ptr
+
+ // x[1:] * x[0]
+ MUL x0, x1, acc1
+ UMULH x0, x1, acc2
+
+ MUL x0, x2, t0
+ ADDS t0, acc2, acc2
+ UMULH x0, x2, acc3
+
+ MUL x0, x3, t0
+ ADCS t0, acc3, acc3
+ UMULH x0, x3, acc4
+ ADC $0, acc4, acc4
+ // x[2:] * x[1]
+ MUL x1, x2, t0
+ ADDS t0, acc3
+ UMULH x1, x2, t1
+ ADCS t1, acc4
+ ADC $0, ZR, acc5
+
+ MUL x1, x3, t0
+ ADDS t0, acc4
+ UMULH x1, x3, t1
+ ADC t1, acc5
+ // x[3] * x[2]
+ MUL x2, x3, t0
+ ADDS t0, acc5
+ UMULH x2, x3, acc6
+ ADC $0, acc6
+
+ MOVD $0, acc7
+ // *2
+ ADDS acc1, acc1
+ ADCS acc2, acc2
+ ADCS acc3, acc3
+ ADCS acc4, acc4
+ ADCS acc5, acc5
+ ADCS acc6, acc6
+ ADC $0, acc7
+ // Missing products
+ MUL x0, x0, acc0
+ UMULH x0, x0, t0
+ ADDS t0, acc1, acc1
+
+ MUL x1, x1, t0
+ ADCS t0, acc2, acc2
+ UMULH x1, x1, t1
+ ADCS t1, acc3, acc3
+
+ MUL x2, x2, t0
+ ADCS t0, acc4, acc4
+ UMULH x2, x2, t1
+ ADCS t1, acc5, acc5
+
+ MUL x3, x3, t0
+ ADCS t0, acc6, acc6
+ UMULH x3, x3, t1
+ ADC t1, acc7, acc7
+ // First reduction step
+ MUL acc0, hlp1, hlp0
+
+ MUL const0, hlp1, t0
+ ADDS t0, acc0, acc0
+ UMULH const0, hlp0, t1
+
+ MUL const1, hlp0, t0
+ ADCS t0, acc1, acc1
+ UMULH const1, hlp0, y0
+
+ MUL const2, hlp0, t0
+ ADCS t0, acc2, acc2
+ UMULH const2, hlp0, acc0
+
+ MUL const3, hlp0, t0
+ ADCS t0, acc3, acc3
+
+ UMULH const3, hlp0, hlp0
+ ADC $0, hlp0
+
+ ADDS t1, acc1, acc1
+ ADCS y0, acc2, acc2
+ ADCS acc0, acc3, acc3
+ ADC $0, hlp0, acc0
+ // Second reduction step
+ MUL acc1, hlp1, hlp0
+
+ MUL const0, hlp1, t0
+ ADDS t0, acc1, acc1
+ UMULH const0, hlp0, t1
+
+ MUL const1, hlp0, t0
+ ADCS t0, acc2, acc2
+ UMULH const1, hlp0, y0
+
+ MUL const2, hlp0, t0
+ ADCS t0, acc3, acc3
+ UMULH const2, hlp0, acc1
+
+ MUL const3, hlp0, t0
+ ADCS t0, acc0, acc0
+
+ UMULH const3, hlp0, hlp0
+ ADC $0, hlp0
+
+ ADDS t1, acc2, acc2
+ ADCS y0, acc3, acc3
+ ADCS acc1, acc0, acc0
+ ADC $0, hlp0, acc1
+ // Third reduction step
+ MUL acc2, hlp1, hlp0
+
+ MUL const0, hlp1, t0
+ ADDS t0, acc2, acc2
+ UMULH const0, hlp0, t1
+
+ MUL const1, hlp0, t0
+ ADCS t0, acc3, acc3
+ UMULH const1, hlp0, y0
+
+ MUL const2, hlp0, t0
+ ADCS t0, acc0, acc0
+ UMULH const2, hlp0, acc2
+
+ MUL const3, hlp0, t0
+ ADCS t0, acc1, acc1
+
+ UMULH const3, hlp0, hlp0
+ ADC $0, hlp0
+
+ ADDS t1, acc3, acc3
+ ADCS y0, acc0, acc0
+ ADCS acc2, acc1, acc1
+ ADC $0, hlp0, acc2
+
+ // Last reduction step
+ MUL acc3, hlp1, hlp0
+
+ MUL const0, hlp1, t0
+ ADDS t0, acc3, acc3
+ UMULH const0, hlp0, t1
+
+ MUL const1, hlp0, t0
+ ADCS t0, acc0, acc0
+ UMULH const1, hlp0, y0
+
+ MUL const2, hlp0, t0
+ ADCS t0, acc1, acc1
+ UMULH const2, hlp0, acc3
+
+ MUL const3, hlp0, t0
+ ADCS t0, acc2, acc2
+
+ UMULH const3, hlp0, hlp0
+ ADC $0, acc7
+
+ ADDS t1, acc0, acc0
+ ADCS y0, acc1, acc1
+ ADCS acc3, acc2, acc2
+ ADC $0, hlp0, acc3
+
+ ADDS acc4, acc0, acc0
+ ADCS acc5, acc1, acc1
+ ADCS acc6, acc2, acc2
+ ADCS acc7, acc3, acc3
+ ADC $0, ZR, acc4
+
+ SUBS const0, acc0, y0
+ SBCS const1, acc1, y1
+ SBCS const2, acc2, y2
+ SBCS const3, acc3, y3
+ SBCS $0, acc4, acc4
+
+ CSEL CS, y0, acc0, x0
+ CSEL CS, y1, acc1, x1
+ CSEL CS, y2, acc2, x2
+ CSEL CS, y3, acc3, x3
+
+ CBNZ b_ptr, ordSqrLoop
+
+ MOVD res+0(FP), res_ptr
+ STP (x0, x1), 0*16(res_ptr)
+ STP (x2, x3), 1*16(res_ptr)
+
+ RET
+/* ---------------------------------------*/
+// func p256OrdMul(res, in1, in2 *p256OrdElement)
+TEXT ·p256OrdMul(SB),NOSPLIT,$0
+ MOVD in1+8(FP), a_ptr
+ MOVD in2+16(FP), b_ptr
+
+ MOVD p256ordK0<>(SB), hlp1
+ LDP p256ord<>+0x00(SB), (const0, const1)
+ LDP p256ord<>+0x10(SB), (const2, const3)
+
+ LDP 0*16(a_ptr), (x0, x1)
+ LDP 1*16(a_ptr), (x2, x3)
+ LDP 0*16(b_ptr), (y0, y1)
+ LDP 1*16(b_ptr), (y2, y3)
+
+ // y[0] * x
+ MUL y0, x0, acc0
+ UMULH y0, x0, acc1
+
+ MUL y0, x1, t0
+ ADDS t0, acc1
+ UMULH y0, x1, acc2
+
+ MUL y0, x2, t0
+ ADCS t0, acc2
+ UMULH y0, x2, acc3
+
+ MUL y0, x3, t0
+ ADCS t0, acc3
+ UMULH y0, x3, acc4
+ ADC $0, acc4
+ // First reduction step
+ MUL acc0, hlp1, hlp0
+
+ MUL const0, hlp1, t0
+ ADDS t0, acc0, acc0
+ UMULH const0, hlp0, t1
+
+ MUL const1, hlp0, t0
+ ADCS t0, acc1, acc1
+ UMULH const1, hlp0, y0
+
+ MUL const2, hlp0, t0
+ ADCS t0, acc2, acc2
+ UMULH const2, hlp0, acc0
+
+ MUL const3, hlp0, t0
+ ADCS t0, acc3, acc3
+
+ UMULH const3, hlp0, hlp0
+ ADC $0, acc4
+
+ ADDS t1, acc1, acc1
+ ADCS y0, acc2, acc2
+ ADCS acc0, acc3, acc3
+ ADC $0, hlp0, acc0
+ // y[1] * x
+ MUL y1, x0, t0
+ ADDS t0, acc1
+ UMULH y1, x0, t1
+
+ MUL y1, x1, t0
+ ADCS t0, acc2
+ UMULH y1, x1, hlp0
+
+ MUL y1, x2, t0
+ ADCS t0, acc3
+ UMULH y1, x2, y0
+
+ MUL y1, x3, t0
+ ADCS t0, acc4
+ UMULH y1, x3, y1
+ ADC $0, ZR, acc5
+
+ ADDS t1, acc2
+ ADCS hlp0, acc3
+ ADCS y0, acc4
+ ADC y1, acc5
+ // Second reduction step
+ MUL acc1, hlp1, hlp0
+
+ MUL const0, hlp1, t0
+ ADDS t0, acc1, acc1
+ UMULH const0, hlp0, t1
+
+ MUL const1, hlp0, t0
+ ADCS t0, acc2, acc2
+ UMULH const1, hlp0, y0
+
+ MUL const2, hlp0, t0
+ ADCS t0, acc3, acc3
+ UMULH const2, hlp0, acc1
+
+ MUL const3, hlp0, t0
+ ADCS t0, acc0, acc0
+
+ UMULH const3, hlp0, hlp0
+ ADC $0, acc5
+
+ ADDS t1, acc2, acc2
+ ADCS y0, acc3, acc3
+ ADCS acc1, acc0, acc0
+ ADC $0, hlp0, acc1
+ // y[2] * x
+ MUL y2, x0, t0
+ ADDS t0, acc2
+ UMULH y2, x0, t1
+
+ MUL y2, x1, t0
+ ADCS t0, acc3
+ UMULH y2, x1, hlp0
+
+ MUL y2, x2, t0
+ ADCS t0, acc4
+ UMULH y2, x2, y0
+
+ MUL y2, x3, t0
+ ADCS t0, acc5
+ UMULH y2, x3, y1
+ ADC $0, ZR, acc6
+
+ ADDS t1, acc3
+ ADCS hlp0, acc4
+ ADCS y0, acc5
+ ADC y1, acc6
+ // Third reduction step
+ MUL acc2, hlp1, hlp0
+
+ MUL const0, hlp1, t0
+ ADDS t0, acc2, acc2
+ UMULH const0, hlp0, t1
+
+ MUL const1, hlp0, t0
+ ADCS t0, acc3, acc3
+ UMULH const1, hlp0, y0
+
+ MUL const2, hlp0, t0
+ ADCS t0, acc0, acc0
+ UMULH const2, hlp0, acc2
+
+ MUL const3, hlp0, t0
+ ADCS t0, acc1, acc1
+
+ UMULH const3, hlp0, hlp0
+ ADC $0, acc6
+
+ ADDS t1, acc3, acc3
+ ADCS y0, acc0, acc0
+ ADCS acc2, acc1, acc1
+ ADC $0, hlp0, acc2
+ // y[3] * x
+ MUL y3, x0, t0
+ ADDS t0, acc3
+ UMULH y3, x0, t1
+
+ MUL y3, x1, t0
+ ADCS t0, acc4
+ UMULH y3, x1, hlp0
+
+ MUL y3, x2, t0
+ ADCS t0, acc5
+ UMULH y3, x2, y0
+
+ MUL y3, x3, t0
+ ADCS t0, acc6
+ UMULH y3, x3, y1
+ ADC $0, ZR, acc7
+
+ ADDS t1, acc4
+ ADCS hlp0, acc5
+ ADCS y0, acc6
+ ADC y1, acc7
+ // Last reduction step
+ MUL acc3, hlp1, hlp0
+
+ MUL const0, hlp1, t0
+ ADDS t0, acc3, acc3
+ UMULH const0, hlp0, t1
+
+ MUL const1, hlp0, t0
+ ADCS t0, acc0, acc0
+ UMULH const1, hlp0, y0
+
+ MUL const2, hlp0, t0
+ ADCS t0, acc1, acc1
+ UMULH const2, hlp0, acc3
+
+ MUL const3, hlp0, t0
+ ADCS t0, acc2, acc2
+
+ UMULH const3, hlp0, hlp0
+ ADC $0, acc7
+
+ ADDS t1, acc0, acc0
+ ADCS y0, acc1, acc1
+ ADCS acc3, acc2, acc2
+ ADC $0, hlp0, acc3
+
+ ADDS acc4, acc0, acc0
+ ADCS acc5, acc1, acc1
+ ADCS acc6, acc2, acc2
+ ADCS acc7, acc3, acc3
+ ADC $0, ZR, acc4
+
+ SUBS const0, acc0, t0
+ SBCS const1, acc1, t1
+ SBCS const2, acc2, t2
+ SBCS const3, acc3, t3
+ SBCS $0, acc4, acc4
+
+ CSEL CS, t0, acc0, acc0
+ CSEL CS, t1, acc1, acc1
+ CSEL CS, t2, acc2, acc2
+ CSEL CS, t3, acc3, acc3
+
+ MOVD res+0(FP), res_ptr
+ STP (acc0, acc1), 0*16(res_ptr)
+ STP (acc2, acc3), 1*16(res_ptr)
+
+ RET
+/* ---------------------------------------*/
+TEXT p256SubInternal<>(SB),NOSPLIT,$0
+ SUBS x0, y0, acc0
+ SBCS x1, y1, acc1
+ SBCS x2, y2, acc2
+ SBCS x3, y3, acc3
+ SBC $0, ZR, t0
+
+ ADDS $-1, acc0, acc4
+ ADCS const0, acc1, acc5
+ ADCS $0, acc2, acc6
+ ADC const1, acc3, acc7
+
+ ANDS $1, t0
+ CSEL EQ, acc0, acc4, x0
+ CSEL EQ, acc1, acc5, x1
+ CSEL EQ, acc2, acc6, x2
+ CSEL EQ, acc3, acc7, x3
+
+ RET
+/* ---------------------------------------*/
+TEXT p256SqrInternal<>(SB),NOSPLIT,$0
+ // x[1:] * x[0]
+ MUL x0, x1, acc1
+ UMULH x0, x1, acc2
+
+ MUL x0, x2, t0
+ ADDS t0, acc2, acc2
+ UMULH x0, x2, acc3
+
+ MUL x0, x3, t0
+ ADCS t0, acc3, acc3
+ UMULH x0, x3, acc4
+ ADC $0, acc4, acc4
+ // x[2:] * x[1]
+ MUL x1, x2, t0
+ ADDS t0, acc3
+ UMULH x1, x2, t1
+ ADCS t1, acc4
+ ADC $0, ZR, acc5
+
+ MUL x1, x3, t0
+ ADDS t0, acc4
+ UMULH x1, x3, t1
+ ADC t1, acc5
+ // x[3] * x[2]
+ MUL x2, x3, t0
+ ADDS t0, acc5
+ UMULH x2, x3, acc6
+ ADC $0, acc6
+
+ MOVD $0, acc7
+ // *2
+ ADDS acc1, acc1
+ ADCS acc2, acc2
+ ADCS acc3, acc3
+ ADCS acc4, acc4
+ ADCS acc5, acc5
+ ADCS acc6, acc6
+ ADC $0, acc7
+ // Missing products
+ MUL x0, x0, acc0
+ UMULH x0, x0, t0
+ ADDS t0, acc1, acc1
+
+ MUL x1, x1, t0
+ ADCS t0, acc2, acc2
+ UMULH x1, x1, t1
+ ADCS t1, acc3, acc3
+
+ MUL x2, x2, t0
+ ADCS t0, acc4, acc4
+ UMULH x2, x2, t1
+ ADCS t1, acc5, acc5
+
+ MUL x3, x3, t0
+ ADCS t0, acc6, acc6
+ UMULH x3, x3, t1
+ ADCS t1, acc7, acc7
+ // First reduction step
+ ADDS acc0<<32, acc1, acc1
+ LSR $32, acc0, t0
+ MUL acc0, const1, t1
+ UMULH acc0, const1, acc0
+ ADCS t0, acc2, acc2
+ ADCS t1, acc3, acc3
+ ADC $0, acc0, acc0
+ // Second reduction step
+ ADDS acc1<<32, acc2, acc2
+ LSR $32, acc1, t0
+ MUL acc1, const1, t1
+ UMULH acc1, const1, acc1
+ ADCS t0, acc3, acc3
+ ADCS t1, acc0, acc0
+ ADC $0, acc1, acc1
+ // Third reduction step
+ ADDS acc2<<32, acc3, acc3
+ LSR $32, acc2, t0
+ MUL acc2, const1, t1
+ UMULH acc2, const1, acc2
+ ADCS t0, acc0, acc0
+ ADCS t1, acc1, acc1
+ ADC $0, acc2, acc2
+ // Last reduction step
+ ADDS acc3<<32, acc0, acc0
+ LSR $32, acc3, t0
+ MUL acc3, const1, t1
+ UMULH acc3, const1, acc3
+ ADCS t0, acc1, acc1
+ ADCS t1, acc2, acc2
+ ADC $0, acc3, acc3
+ // Add bits [511:256] of the sqr result
+ ADDS acc4, acc0, acc0
+ ADCS acc5, acc1, acc1
+ ADCS acc6, acc2, acc2
+ ADCS acc7, acc3, acc3
+ ADC $0, ZR, acc4
+
+ SUBS $-1, acc0, t0
+ SBCS const0, acc1, t1
+ SBCS $0, acc2, t2
+ SBCS const1, acc3, t3
+ SBCS $0, acc4, acc4
+
+ CSEL CS, t0, acc0, y0
+ CSEL CS, t1, acc1, y1
+ CSEL CS, t2, acc2, y2
+ CSEL CS, t3, acc3, y3
+ RET
+/* ---------------------------------------*/
+TEXT p256MulInternal<>(SB),NOSPLIT,$0
+ // y[0] * x
+ MUL y0, x0, acc0
+ UMULH y0, x0, acc1
+
+ MUL y0, x1, t0
+ ADDS t0, acc1
+ UMULH y0, x1, acc2
+
+ MUL y0, x2, t0
+ ADCS t0, acc2
+ UMULH y0, x2, acc3
+
+ MUL y0, x3, t0
+ ADCS t0, acc3
+ UMULH y0, x3, acc4
+ ADC $0, acc4
+ // First reduction step
+ ADDS acc0<<32, acc1, acc1
+ LSR $32, acc0, t0
+ MUL acc0, const1, t1
+ UMULH acc0, const1, acc0
+ ADCS t0, acc2
+ ADCS t1, acc3
+ ADC $0, acc0
+ // y[1] * x
+ MUL y1, x0, t0
+ ADDS t0, acc1
+ UMULH y1, x0, t1
+
+ MUL y1, x1, t0
+ ADCS t0, acc2
+ UMULH y1, x1, t2
+
+ MUL y1, x2, t0
+ ADCS t0, acc3
+ UMULH y1, x2, t3
+
+ MUL y1, x3, t0
+ ADCS t0, acc4
+ UMULH y1, x3, hlp0
+ ADC $0, ZR, acc5
+
+ ADDS t1, acc2
+ ADCS t2, acc3
+ ADCS t3, acc4
+ ADC hlp0, acc5
+ // Second reduction step
+ ADDS acc1<<32, acc2, acc2
+ LSR $32, acc1, t0
+ MUL acc1, const1, t1
+ UMULH acc1, const1, acc1
+ ADCS t0, acc3
+ ADCS t1, acc0
+ ADC $0, acc1
+ // y[2] * x
+ MUL y2, x0, t0
+ ADDS t0, acc2
+ UMULH y2, x0, t1
+
+ MUL y2, x1, t0
+ ADCS t0, acc3
+ UMULH y2, x1, t2
+
+ MUL y2, x2, t0
+ ADCS t0, acc4
+ UMULH y2, x2, t3
+
+ MUL y2, x3, t0
+ ADCS t0, acc5
+ UMULH y2, x3, hlp0
+ ADC $0, ZR, acc6
+
+ ADDS t1, acc3
+ ADCS t2, acc4
+ ADCS t3, acc5
+ ADC hlp0, acc6
+ // Third reduction step
+ ADDS acc2<<32, acc3, acc3
+ LSR $32, acc2, t0
+ MUL acc2, const1, t1
+ UMULH acc2, const1, acc2
+ ADCS t0, acc0
+ ADCS t1, acc1
+ ADC $0, acc2
+ // y[3] * x
+ MUL y3, x0, t0
+ ADDS t0, acc3
+ UMULH y3, x0, t1
+
+ MUL y3, x1, t0
+ ADCS t0, acc4
+ UMULH y3, x1, t2
+
+ MUL y3, x2, t0
+ ADCS t0, acc5
+ UMULH y3, x2, t3
+
+ MUL y3, x3, t0
+ ADCS t0, acc6
+ UMULH y3, x3, hlp0
+ ADC $0, ZR, acc7
+
+ ADDS t1, acc4
+ ADCS t2, acc5
+ ADCS t3, acc6
+ ADC hlp0, acc7
+ // Last reduction step
+ ADDS acc3<<32, acc0, acc0
+ LSR $32, acc3, t0
+ MUL acc3, const1, t1
+ UMULH acc3, const1, acc3
+ ADCS t0, acc1
+ ADCS t1, acc2
+ ADC $0, acc3
+ // Add bits [511:256] of the mul result
+ ADDS acc4, acc0, acc0
+ ADCS acc5, acc1, acc1
+ ADCS acc6, acc2, acc2
+ ADCS acc7, acc3, acc3
+ ADC $0, ZR, acc4
+
+ SUBS $-1, acc0, t0
+ SBCS const0, acc1, t1
+ SBCS $0, acc2, t2
+ SBCS const1, acc3, t3
+ SBCS $0, acc4, acc4
+
+ CSEL CS, t0, acc0, y0
+ CSEL CS, t1, acc1, y1
+ CSEL CS, t2, acc2, y2
+ CSEL CS, t3, acc3, y3
+ RET
+/* ---------------------------------------*/
+#define p256MulBy2Inline \
+ ADDS y0, y0, x0; \
+ ADCS y1, y1, x1; \
+ ADCS y2, y2, x2; \
+ ADCS y3, y3, x3; \
+ ADC $0, ZR, hlp0; \
+ SUBS $-1, x0, t0; \
+ SBCS const0, x1, t1;\
+ SBCS $0, x2, t2; \
+ SBCS const1, x3, t3;\
+ SBCS $0, hlp0, hlp0;\
+ CSEL CC, x0, t0, x0;\
+ CSEL CC, x1, t1, x1;\
+ CSEL CC, x2, t2, x2;\
+ CSEL CC, x3, t3, x3;
+/* ---------------------------------------*/
+#define x1in(off) (off)(a_ptr)
+#define y1in(off) (off + 32)(a_ptr)
+#define z1in(off) (off + 64)(a_ptr)
+#define x2in(off) (off)(b_ptr)
+#define z2in(off) (off + 64)(b_ptr)
+#define x3out(off) (off)(res_ptr)
+#define y3out(off) (off + 32)(res_ptr)
+#define z3out(off) (off + 64)(res_ptr)
+#define LDx(src) LDP src(0), (x0, x1); LDP src(16), (x2, x3)
+#define LDy(src) LDP src(0), (y0, y1); LDP src(16), (y2, y3)
+#define STx(src) STP (x0, x1), src(0); STP (x2, x3), src(16)
+#define STy(src) STP (y0, y1), src(0); STP (y2, y3), src(16)
+/* ---------------------------------------*/
+#define y2in(off) (32*0 + 8 + off)(RSP)
+#define s2(off) (32*1 + 8 + off)(RSP)
+#define z1sqr(off) (32*2 + 8 + off)(RSP)
+#define h(off) (32*3 + 8 + off)(RSP)
+#define r(off) (32*4 + 8 + off)(RSP)
+#define hsqr(off) (32*5 + 8 + off)(RSP)
+#define rsqr(off) (32*6 + 8 + off)(RSP)
+#define hcub(off) (32*7 + 8 + off)(RSP)
+
+#define z2sqr(off) (32*8 + 8 + off)(RSP)
+#define s1(off) (32*9 + 8 + off)(RSP)
+#define u1(off) (32*10 + 8 + off)(RSP)
+#define u2(off) (32*11 + 8 + off)(RSP)
+
+// func p256PointAddAffineAsm(res, in1 *P256Point, in2 *p256AffinePoint, sign, sel, zero int)
+TEXT ·p256PointAddAffineAsm(SB),0,$264-48
+ MOVD in1+8(FP), a_ptr
+ MOVD in2+16(FP), b_ptr
+ MOVD sign+24(FP), hlp0
+ MOVD sel+32(FP), hlp1
+ MOVD zero+40(FP), t2
+
+ MOVD $1, t0
+ CMP $0, t2
+ CSEL EQ, ZR, t0, t2
+ CMP $0, hlp1
+ CSEL EQ, ZR, t0, hlp1
+
+ MOVD p256const0<>(SB), const0
+ MOVD p256const1<>(SB), const1
+ EOR t2<<1, hlp1
+
+ // Negate y2in based on sign
+ LDP 2*16(b_ptr), (y0, y1)
+ LDP 3*16(b_ptr), (y2, y3)
+ MOVD $-1, acc0
+
+ SUBS y0, acc0, acc0
+ SBCS y1, const0, acc1
+ SBCS y2, ZR, acc2
+ SBCS y3, const1, acc3
+ SBC $0, ZR, t0
+
+ ADDS $-1, acc0, acc4
+ ADCS const0, acc1, acc5
+ ADCS $0, acc2, acc6
+ ADCS const1, acc3, acc7
+ ADC $0, t0, t0
+
+ CMP $0, t0
+ CSEL EQ, acc4, acc0, acc0
+ CSEL EQ, acc5, acc1, acc1
+ CSEL EQ, acc6, acc2, acc2
+ CSEL EQ, acc7, acc3, acc3
+ // If condition is 0, keep original value
+ CMP $0, hlp0
+ CSEL EQ, y0, acc0, y0
+ CSEL EQ, y1, acc1, y1
+ CSEL EQ, y2, acc2, y2
+ CSEL EQ, y3, acc3, y3
+ // Store result
+ STy(y2in)
+ // Begin point add
+ LDx(z1in)
+ CALL p256SqrInternal<>(SB) // z1ˆ2
+ STy(z1sqr)
+
+ LDx(x2in)
+ CALL p256MulInternal<>(SB) // x2 * z1ˆ2
+
+ LDx(x1in)
+ CALL p256SubInternal<>(SB) // h = u2 - u1
+ STx(h)
+
+ LDy(z1in)
+ CALL p256MulInternal<>(SB) // z3 = h * z1
+
+ LDP 4*16(a_ptr), (acc0, acc1)// iff select[0] == 0, z3 = z1
+ LDP 5*16(a_ptr), (acc2, acc3)
+ ANDS $1, hlp1, ZR
+ CSEL EQ, acc0, y0, y0
+ CSEL EQ, acc1, y1, y1
+ CSEL EQ, acc2, y2, y2
+ CSEL EQ, acc3, y3, y3
+ LDP p256one<>+0x00(SB), (acc0, acc1)
+ LDP p256one<>+0x10(SB), (acc2, acc3)
+ ANDS $2, hlp1, ZR // iff select[1] == 0, z3 = 1
+ CSEL EQ, acc0, y0, y0
+ CSEL EQ, acc1, y1, y1
+ CSEL EQ, acc2, y2, y2
+ CSEL EQ, acc3, y3, y3
+ LDx(z1in)
+ MOVD res+0(FP), t0
+ STP (y0, y1), 4*16(t0)
+ STP (y2, y3), 5*16(t0)
+
+ LDy(z1sqr)
+ CALL p256MulInternal<>(SB) // z1 ^ 3
+
+ LDx(y2in)
+ CALL p256MulInternal<>(SB) // s2 = y2 * z1ˆ3
+ STy(s2)
+
+ LDx(y1in)
+ CALL p256SubInternal<>(SB) // r = s2 - s1
+ STx(r)
+
+ CALL p256SqrInternal<>(SB) // rsqr = rˆ2
+ STy (rsqr)
+
+ LDx(h)
+ CALL p256SqrInternal<>(SB) // hsqr = hˆ2
+ STy(hsqr)
+
+ CALL p256MulInternal<>(SB) // hcub = hˆ3
+ STy(hcub)
+
+ LDx(y1in)
+ CALL p256MulInternal<>(SB) // y1 * hˆ3
+ STy(s2)
+
+ LDP hsqr(0*8), (x0, x1)
+ LDP hsqr(2*8), (x2, x3)
+ LDP 0*16(a_ptr), (y0, y1)
+ LDP 1*16(a_ptr), (y2, y3)
+ CALL p256MulInternal<>(SB) // u1 * hˆ2
+ STP (y0, y1), h(0*8)
+ STP (y2, y3), h(2*8)
+
+ p256MulBy2Inline // u1 * hˆ2 * 2, inline
+
+ LDy(rsqr)
+ CALL p256SubInternal<>(SB) // rˆ2 - u1 * hˆ2 * 2
+
+ MOVD x0, y0
+ MOVD x1, y1
+ MOVD x2, y2
+ MOVD x3, y3
+ LDx(hcub)
+ CALL p256SubInternal<>(SB)
+
+ LDP 0*16(a_ptr), (acc0, acc1)
+ LDP 1*16(a_ptr), (acc2, acc3)
+ ANDS $1, hlp1, ZR // iff select[0] == 0, x3 = x1
+ CSEL EQ, acc0, x0, x0
+ CSEL EQ, acc1, x1, x1
+ CSEL EQ, acc2, x2, x2
+ CSEL EQ, acc3, x3, x3
+ LDP 0*16(b_ptr), (acc0, acc1)
+ LDP 1*16(b_ptr), (acc2, acc3)
+ ANDS $2, hlp1, ZR // iff select[1] == 0, x3 = x2
+ CSEL EQ, acc0, x0, x0
+ CSEL EQ, acc1, x1, x1
+ CSEL EQ, acc2, x2, x2
+ CSEL EQ, acc3, x3, x3
+ MOVD res+0(FP), t0
+ STP (x0, x1), 0*16(t0)
+ STP (x2, x3), 1*16(t0)
+
+ LDP h(0*8), (y0, y1)
+ LDP h(2*8), (y2, y3)
+ CALL p256SubInternal<>(SB)
+
+ LDP r(0*8), (y0, y1)
+ LDP r(2*8), (y2, y3)
+ CALL p256MulInternal<>(SB)
+
+ LDP s2(0*8), (x0, x1)
+ LDP s2(2*8), (x2, x3)
+ CALL p256SubInternal<>(SB)
+ LDP 2*16(a_ptr), (acc0, acc1)
+ LDP 3*16(a_ptr), (acc2, acc3)
+ ANDS $1, hlp1, ZR // iff select[0] == 0, y3 = y1
+ CSEL EQ, acc0, x0, x0
+ CSEL EQ, acc1, x1, x1
+ CSEL EQ, acc2, x2, x2
+ CSEL EQ, acc3, x3, x3
+ LDP y2in(0*8), (acc0, acc1)
+ LDP y2in(2*8), (acc2, acc3)
+ ANDS $2, hlp1, ZR // iff select[1] == 0, y3 = y2
+ CSEL EQ, acc0, x0, x0
+ CSEL EQ, acc1, x1, x1
+ CSEL EQ, acc2, x2, x2
+ CSEL EQ, acc3, x3, x3
+ MOVD res+0(FP), t0
+ STP (x0, x1), 2*16(t0)
+ STP (x2, x3), 3*16(t0)
+
+ RET
+
+#define p256AddInline \
+ ADDS y0, x0, x0; \
+ ADCS y1, x1, x1; \
+ ADCS y2, x2, x2; \
+ ADCS y3, x3, x3; \
+ ADC $0, ZR, hlp0; \
+ SUBS $-1, x0, t0; \
+ SBCS const0, x1, t1;\
+ SBCS $0, x2, t2; \
+ SBCS const1, x3, t3;\
+ SBCS $0, hlp0, hlp0;\
+ CSEL CC, x0, t0, x0;\
+ CSEL CC, x1, t1, x1;\
+ CSEL CC, x2, t2, x2;\
+ CSEL CC, x3, t3, x3;
+
+#define s(off) (32*0 + 8 + off)(RSP)
+#define m(off) (32*1 + 8 + off)(RSP)
+#define zsqr(off) (32*2 + 8 + off)(RSP)
+#define tmp(off) (32*3 + 8 + off)(RSP)
+
+//func p256PointDoubleAsm(res, in *P256Point)
+TEXT ·p256PointDoubleAsm(SB),NOSPLIT,$136-16
+ MOVD res+0(FP), res_ptr
+ MOVD in+8(FP), a_ptr
+
+ MOVD p256const0<>(SB), const0
+ MOVD p256const1<>(SB), const1
+
+ // Begin point double
+ LDP 4*16(a_ptr), (x0, x1)
+ LDP 5*16(a_ptr), (x2, x3)
+ CALL p256SqrInternal<>(SB)
+ STP (y0, y1), zsqr(0*8)
+ STP (y2, y3), zsqr(2*8)
+
+ LDP 0*16(a_ptr), (x0, x1)
+ LDP 1*16(a_ptr), (x2, x3)
+ p256AddInline
+ STx(m)
+
+ LDx(z1in)
+ LDy(y1in)
+ CALL p256MulInternal<>(SB)
+ p256MulBy2Inline
+ STx(z3out)
+
+ LDy(x1in)
+ LDx(zsqr)
+ CALL p256SubInternal<>(SB)
+ LDy(m)
+ CALL p256MulInternal<>(SB)
+
+ // Multiply by 3
+ p256MulBy2Inline
+ p256AddInline
+ STx(m)
+
+ LDy(y1in)
+ p256MulBy2Inline
+ CALL p256SqrInternal<>(SB)
+ STy(s)
+ MOVD y0, x0
+ MOVD y1, x1
+ MOVD y2, x2
+ MOVD y3, x3
+ CALL p256SqrInternal<>(SB)
+
+ // Divide by 2
+ ADDS $-1, y0, t0
+ ADCS const0, y1, t1
+ ADCS $0, y2, t2
+ ADCS const1, y3, t3
+ ADC $0, ZR, hlp0
+
+ ANDS $1, y0, ZR
+ CSEL EQ, y0, t0, t0
+ CSEL EQ, y1, t1, t1
+ CSEL EQ, y2, t2, t2
+ CSEL EQ, y3, t3, t3
+ AND y0, hlp0, hlp0
+
+ EXTR $1, t0, t1, y0
+ EXTR $1, t1, t2, y1
+ EXTR $1, t2, t3, y2
+ EXTR $1, t3, hlp0, y3
+ STy(y3out)
+
+ LDx(x1in)
+ LDy(s)
+ CALL p256MulInternal<>(SB)
+ STy(s)
+ p256MulBy2Inline
+ STx(tmp)
+
+ LDx(m)
+ CALL p256SqrInternal<>(SB)
+ LDx(tmp)
+ CALL p256SubInternal<>(SB)
+
+ STx(x3out)
+
+ LDy(s)
+ CALL p256SubInternal<>(SB)
+
+ LDy(m)
+ CALL p256MulInternal<>(SB)
+
+ LDx(y3out)
+ CALL p256SubInternal<>(SB)
+ STx(y3out)
+ RET
+/* ---------------------------------------*/
+#undef y2in
+#undef x3out
+#undef y3out
+#undef z3out
+#define y2in(off) (off + 32)(b_ptr)
+#define x3out(off) (off)(b_ptr)
+#define y3out(off) (off + 32)(b_ptr)
+#define z3out(off) (off + 64)(b_ptr)
+// func p256PointAddAsm(res, in1, in2 *P256Point) int
+TEXT ·p256PointAddAsm(SB),0,$392-32
+ // See https://hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-2007-bl
+ // Move input to stack in order to free registers
+ MOVD in1+8(FP), a_ptr
+ MOVD in2+16(FP), b_ptr
+
+ MOVD p256const0<>(SB), const0
+ MOVD p256const1<>(SB), const1
+
+ // Begin point add
+ LDx(z2in)
+ CALL p256SqrInternal<>(SB) // z2^2
+ STy(z2sqr)
+
+ CALL p256MulInternal<>(SB) // z2^3
+
+ LDx(y1in)
+ CALL p256MulInternal<>(SB) // s1 = z2ˆ3*y1
+ STy(s1)
+
+ LDx(z1in)
+ CALL p256SqrInternal<>(SB) // z1^2
+ STy(z1sqr)
+
+ CALL p256MulInternal<>(SB) // z1^3
+
+ LDx(y2in)
+ CALL p256MulInternal<>(SB) // s2 = z1ˆ3*y2
+
+ LDx(s1)
+ CALL p256SubInternal<>(SB) // r = s2 - s1
+ STx(r)
+
+ MOVD $1, t2
+ ORR x0, x1, t0 // Check if zero mod p256
+ ORR x2, x3, t1
+ ORR t1, t0, t0
+ CMP $0, t0
+ CSEL EQ, t2, ZR, hlp1
+
+ EOR $-1, x0, t0
+ EOR const0, x1, t1
+ EOR const1, x3, t3
+
+ ORR t0, t1, t0
+ ORR x2, t3, t1
+ ORR t1, t0, t0
+ CMP $0, t0
+ CSEL EQ, t2, hlp1, hlp1
+
+ LDx(z2sqr)
+ LDy(x1in)
+ CALL p256MulInternal<>(SB) // u1 = x1 * z2ˆ2
+ STy(u1)
+
+ LDx(z1sqr)
+ LDy(x2in)
+ CALL p256MulInternal<>(SB) // u2 = x2 * z1ˆ2
+ STy(u2)
+
+ LDx(u1)
+ CALL p256SubInternal<>(SB) // h = u2 - u1
+ STx(h)
+
+ MOVD $1, t2
+ ORR x0, x1, t0 // Check if zero mod p256
+ ORR x2, x3, t1
+ ORR t1, t0, t0
+ CMP $0, t0
+ CSEL EQ, t2, ZR, hlp0
+
+ EOR $-1, x0, t0
+ EOR const0, x1, t1
+ EOR const1, x3, t3
+
+ ORR t0, t1, t0
+ ORR x2, t3, t1
+ ORR t1, t0, t0
+ CMP $0, t0
+ CSEL EQ, t2, hlp0, hlp0
+
+ AND hlp0, hlp1, hlp1
+
+ LDx(r)
+ CALL p256SqrInternal<>(SB) // rsqr = rˆ2
+ STy(rsqr)
+
+ LDx(h)
+ CALL p256SqrInternal<>(SB) // hsqr = hˆ2
+ STy(hsqr)
+
+ LDx(h)
+ CALL p256MulInternal<>(SB) // hcub = hˆ3
+ STy(hcub)
+
+ LDx(s1)
+ CALL p256MulInternal<>(SB)
+ STy(s2)
+
+ LDx(z1in)
+ LDy(z2in)
+ CALL p256MulInternal<>(SB) // z1 * z2
+ LDx(h)
+ CALL p256MulInternal<>(SB) // z1 * z2 * h
+ MOVD res+0(FP), b_ptr
+ STy(z3out)
+
+ LDx(hsqr)
+ LDy(u1)
+ CALL p256MulInternal<>(SB) // hˆ2 * u1
+ STy(u2)
+
+ p256MulBy2Inline // u1 * hˆ2 * 2, inline
+ LDy(rsqr)
+ CALL p256SubInternal<>(SB) // rˆ2 - u1 * hˆ2 * 2
+
+ MOVD x0, y0
+ MOVD x1, y1
+ MOVD x2, y2
+ MOVD x3, y3
+ LDx(hcub)
+ CALL p256SubInternal<>(SB)
+ STx(x3out)
+
+ LDy(u2)
+ CALL p256SubInternal<>(SB)
+
+ LDy(r)
+ CALL p256MulInternal<>(SB)
+
+ LDx(s2)
+ CALL p256SubInternal<>(SB)
+ STx(y3out)
+
+ MOVD hlp1, R0
+ MOVD R0, ret+24(FP)
+
+ RET
diff --git a/src/crypto/internal/nistec/p256_asm_ppc64le.s b/src/crypto/internal/nistec/p256_asm_ppc64le.s
new file mode 100644
index 0000000..0593ef3
--- /dev/null
+++ b/src/crypto/internal/nistec/p256_asm_ppc64le.s
@@ -0,0 +1,2208 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// This is a port of the s390x asm implementation.
+// to ppc64le.
+
+// Some changes were needed due to differences in
+// the Go opcodes and/or available instructions
+// between s390x and ppc64le.
+
+// 1. There were operand order differences in the
+// VSUBUQM, VSUBCUQ, and VSEL instructions.
+
+// 2. ppc64 does not have a multiply high and low
+// like s390x, so those were implemented using
+// macros to compute the equivalent values.
+
+// 3. The LVX, STVX instructions on ppc64 require
+// 16 byte alignment of the data. To avoid that
+// requirement, data is loaded using LXVD2X and
+// STXVD2X with VPERM to reorder bytes correctly.
+
+// I have identified some areas where I believe
+// changes would be needed to make this work for big
+// endian; however additional changes beyond what I
+// have noted are most likely needed to make it work.
+// - The string used with VPERM to swap the byte order
+// for loads and stores.
+// - The constants that are loaded from CPOOL.
+//
+
+// The following constants are defined in an order
+// that is correct for use with LXVD2X/STXVD2X
+// on little endian.
+DATA p256<>+0x00(SB)/8, $0xffffffff00000001 // P256
+DATA p256<>+0x08(SB)/8, $0x0000000000000000 // P256
+DATA p256<>+0x10(SB)/8, $0x00000000ffffffff // P256
+DATA p256<>+0x18(SB)/8, $0xffffffffffffffff // P256
+DATA p256<>+0x20(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256<>+0x28(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256<>+0x30(SB)/8, $0x0000000010111213 // SEL 0 d1 d0 0
+DATA p256<>+0x38(SB)/8, $0x1415161700000000 // SEL 0 d1 d0 0
+DATA p256<>+0x40(SB)/8, $0x18191a1b1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256<>+0x48(SB)/8, $0x18191a1b1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256mul<>+0x00(SB)/8, $0x00000000ffffffff // P256 original
+DATA p256mul<>+0x08(SB)/8, $0xffffffffffffffff // P256
+DATA p256mul<>+0x10(SB)/8, $0xffffffff00000001 // P256 original
+DATA p256mul<>+0x18(SB)/8, $0x0000000000000000 // P256
+DATA p256mul<>+0x20(SB)/8, $0x1c1d1e1f00000000 // SEL d0 0 0 d0
+DATA p256mul<>+0x28(SB)/8, $0x000000001c1d1e1f // SEL d0 0 0 d0
+DATA p256mul<>+0x30(SB)/8, $0x0001020304050607 // SEL d0 0 d1 d0
+DATA p256mul<>+0x38(SB)/8, $0x1c1d1e1f0c0d0e0f // SEL d0 0 d1 d0
+DATA p256mul<>+0x40(SB)/8, $0x040506071c1d1e1f // SEL 0 d1 d0 d1
+DATA p256mul<>+0x48(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL 0 d1 d0 d1
+DATA p256mul<>+0x50(SB)/8, $0x0405060704050607 // SEL 0 0 d1 d0
+DATA p256mul<>+0x58(SB)/8, $0x1c1d1e1f0c0d0e0f // SEL 0 0 d1 d0
+DATA p256mul<>+0x60(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256mul<>+0x68(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256mul<>+0x70(SB)/8, $0x141516170c0d0e0f // SEL 0 d1 d0 0
+DATA p256mul<>+0x78(SB)/8, $0x1c1d1e1f14151617 // SEL 0 d1 d0 0
+DATA p256mul<>+0x80(SB)/8, $0xffffffff00000000 // (1*2^256)%P256
+DATA p256mul<>+0x88(SB)/8, $0x0000000000000001 // (1*2^256)%P256
+DATA p256mul<>+0x90(SB)/8, $0x00000000fffffffe // (1*2^256)%P256
+DATA p256mul<>+0x98(SB)/8, $0xffffffffffffffff // (1*2^256)%P256
+
+// External declarations for constants
+GLOBL p256ord<>(SB), 8, $32
+GLOBL p256<>(SB), 8, $80
+GLOBL p256mul<>(SB), 8, $160
+
+// The following macros are used to implement the ppc64le
+// equivalent function from the corresponding s390x
+// instruction for vector multiply high, low, and add,
+// since there aren't exact equivalent instructions.
+// The corresponding s390x instructions appear in the
+// comments.
+// Implementation for big endian would have to be
+// investigated, I think it would be different.
+//
+//
+// Vector multiply word
+//
+// VMLF x0, x1, out_low
+// VMLHF x0, x1, out_hi
+#define VMULT(x1, x2, out_low, out_hi) \
+ VMULEUW x1, x2, TMP1; \
+ VMULOUW x1, x2, TMP2; \
+ VMRGEW TMP1, TMP2, out_hi; \
+ VMRGOW TMP1, TMP2, out_low
+
+//
+// Vector multiply add word
+//
+// VMALF x0, x1, y, out_low
+// VMALHF x0, x1, y, out_hi
+#define VMULT_ADD(x1, x2, y, one, out_low, out_hi) \
+ VMULEUW y, one, TMP2; \
+ VMULOUW y, one, TMP1; \
+ VMULEUW x1, x2, out_low; \
+ VMULOUW x1, x2, out_hi; \
+ VADDUDM TMP2, out_low, TMP2; \
+ VADDUDM TMP1, out_hi, TMP1; \
+ VMRGOW TMP2, TMP1, out_low; \
+ VMRGEW TMP2, TMP1, out_hi
+
+#define res_ptr R3
+#define a_ptr R4
+
+#undef res_ptr
+#undef a_ptr
+
+#define P1ptr R3
+#define CPOOL R7
+
+#define Y1L V0
+#define Y1H V1
+#define T1L V2
+#define T1H V3
+
+#define PL V30
+#define PH V31
+
+#define CAR1 V6
+// func p256NegCond(val *p256Point, cond int)
+TEXT ·p256NegCond(SB), NOSPLIT, $0-16
+ MOVD val+0(FP), P1ptr
+ MOVD $16, R16
+
+ MOVD cond+8(FP), R6
+ CMP $0, R6
+ BC 12, 2, LR // just return if cond == 0
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+
+ LXVD2X (P1ptr)(R0), Y1L
+ LXVD2X (P1ptr)(R16), Y1H
+
+ XXPERMDI Y1H, Y1H, $2, Y1H
+ XXPERMDI Y1L, Y1L, $2, Y1L
+
+ LXVD2X (CPOOL)(R0), PL
+ LXVD2X (CPOOL)(R16), PH
+
+ VSUBCUQ PL, Y1L, CAR1 // subtract part2 giving carry
+ VSUBUQM PL, Y1L, T1L // subtract part2 giving result
+ VSUBEUQM PH, Y1H, CAR1, T1H // subtract part1 using carry from part2
+
+ XXPERMDI T1H, T1H, $2, T1H
+ XXPERMDI T1L, T1L, $2, T1L
+
+ STXVD2X T1L, (R0+P1ptr)
+ STXVD2X T1H, (R16+P1ptr)
+ RET
+
+#undef P1ptr
+#undef CPOOL
+#undef Y1L
+#undef Y1H
+#undef T1L
+#undef T1H
+#undef PL
+#undef PH
+#undef CAR1
+
+#define P3ptr R3
+#define P1ptr R4
+#define P2ptr R5
+
+#define X1L V0
+#define X1H V1
+#define Y1L V2
+#define Y1H V3
+#define Z1L V4
+#define Z1H V5
+#define X2L V6
+#define X2H V7
+#define Y2L V8
+#define Y2H V9
+#define Z2L V10
+#define Z2H V11
+#define SEL V12
+#define ZER V13
+
+// This function uses LXVD2X and STXVD2X to avoid the
+// data alignment requirement for LVX, STVX. Since
+// this code is just moving bytes and not doing arithmetic,
+// order of the bytes doesn't matter.
+//
+// func p256MovCond(res, a, b *p256Point, cond int)
+TEXT ·p256MovCond(SB), NOSPLIT, $0-32
+ MOVD res+0(FP), P3ptr
+ MOVD a+8(FP), P1ptr
+ MOVD b+16(FP), P2ptr
+ MOVD $16, R16
+ MOVD $32, R17
+ MOVD $48, R18
+ MOVD $56, R21
+ MOVD $64, R19
+ MOVD $80, R20
+ // cond is R1 + 24 (cond offset) + 32
+ LXVDSX (R1)(R21), SEL
+ VSPLTISB $0, ZER
+ // SEL controls whether to store a or b
+ VCMPEQUD SEL, ZER, SEL
+
+ LXVD2X (P1ptr+R0), X1H
+ LXVD2X (P1ptr+R16), X1L
+ LXVD2X (P1ptr+R17), Y1H
+ LXVD2X (P1ptr+R18), Y1L
+ LXVD2X (P1ptr+R19), Z1H
+ LXVD2X (P1ptr+R20), Z1L
+
+ LXVD2X (P2ptr+R0), X2H
+ LXVD2X (P2ptr+R16), X2L
+ LXVD2X (P2ptr+R17), Y2H
+ LXVD2X (P2ptr+R18), Y2L
+ LXVD2X (P2ptr+R19), Z2H
+ LXVD2X (P2ptr+R20), Z2L
+
+ VSEL X1H, X2H, SEL, X1H
+ VSEL X1L, X2L, SEL, X1L
+ VSEL Y1H, Y2H, SEL, Y1H
+ VSEL Y1L, Y2L, SEL, Y1L
+ VSEL Z1H, Z2H, SEL, Z1H
+ VSEL Z1L, Z2L, SEL, Z1L
+
+ STXVD2X X1H, (P3ptr+R0)
+ STXVD2X X1L, (P3ptr+R16)
+ STXVD2X Y1H, (P3ptr+R17)
+ STXVD2X Y1L, (P3ptr+R18)
+ STXVD2X Z1H, (P3ptr+R19)
+ STXVD2X Z1L, (P3ptr+R20)
+
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef P2ptr
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef X2L
+#undef X2H
+#undef Y2L
+#undef Y2H
+#undef Z2L
+#undef Z2H
+#undef SEL
+#undef ZER
+
+#define P3ptr R3
+#define P1ptr R4
+#define COUNT R5
+
+#define X1L V0
+#define X1H V1
+#define Y1L V2
+#define Y1H V3
+#define Z1L V4
+#define Z1H V5
+#define X2L V6
+#define X2H V7
+#define Y2L V8
+#define Y2H V9
+#define Z2L V10
+#define Z2H V11
+
+#define ONE V18
+#define IDX V19
+#define SEL1 V20
+#define SEL2 V21
+// func p256Select(point *p256Point, table *p256Table, idx int)
+TEXT ·p256Select(SB), NOSPLIT, $0-24
+ MOVD res+0(FP), P3ptr
+ MOVD table+8(FP), P1ptr
+ MOVD $16, R16
+ MOVD $32, R17
+ MOVD $48, R18
+ MOVD $64, R19
+ MOVD $80, R20
+
+ LXVDSX (R1)(R18), SEL1 // VLREPG idx+32(FP), SEL1
+ VSPLTB $7, SEL1, IDX // splat byte
+ VSPLTISB $1, ONE // VREPIB $1, ONE
+ VSPLTISB $1, SEL2 // VREPIB $1, SEL2
+ MOVD $17, COUNT
+ MOVD COUNT, CTR // set up ctr
+
+ VSPLTISB $0, X1H // VZERO X1H
+ VSPLTISB $0, X1L // VZERO X1L
+ VSPLTISB $0, Y1H // VZERO Y1H
+ VSPLTISB $0, Y1L // VZERO Y1L
+ VSPLTISB $0, Z1H // VZERO Z1H
+ VSPLTISB $0, Z1L // VZERO Z1L
+
+loop_select:
+
+ // LVXD2X is used here since data alignment doesn't
+ // matter.
+
+ LXVD2X (P1ptr+R0), X2H
+ LXVD2X (P1ptr+R16), X2L
+ LXVD2X (P1ptr+R17), Y2H
+ LXVD2X (P1ptr+R18), Y2L
+ LXVD2X (P1ptr+R19), Z2H
+ LXVD2X (P1ptr+R20), Z2L
+
+ VCMPEQUD SEL2, IDX, SEL1 // VCEQG SEL2, IDX, SEL1 OK
+
+ // This will result in SEL1 being all 0s or 1s, meaning
+ // the result is either X1L or X2L, no individual byte
+ // selection.
+
+ VSEL X1L, X2L, SEL1, X1L
+ VSEL X1H, X2H, SEL1, X1H
+ VSEL Y1L, Y2L, SEL1, Y1L
+ VSEL Y1H, Y2H, SEL1, Y1H
+ VSEL Z1L, Z2L, SEL1, Z1L
+ VSEL Z1H, Z2H, SEL1, Z1H
+
+ // Add 1 to all bytes in SEL2
+ VADDUBM SEL2, ONE, SEL2 // VAB SEL2, ONE, SEL2 OK
+ ADD $96, P1ptr
+ BDNZ loop_select
+
+ // STXVD2X is used here so that alignment doesn't
+ // need to be verified. Since values were loaded
+ // using LXVD2X this is OK.
+ STXVD2X X1H, (P3ptr+R0)
+ STXVD2X X1L, (P3ptr+R16)
+ STXVD2X Y1H, (P3ptr+R17)
+ STXVD2X Y1L, (P3ptr+R18)
+ STXVD2X Z1H, (P3ptr+R19)
+ STXVD2X Z1L, (P3ptr+R20)
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef COUNT
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef X2L
+#undef X2H
+#undef Y2L
+#undef Y2H
+#undef Z2L
+#undef Z2H
+#undef ONE
+#undef IDX
+#undef SEL1
+#undef SEL2
+
+// The following functions all reverse the byte order.
+
+//func p256BigToLittle(res *p256Element, in *[32]byte)
+TEXT ·p256BigToLittle(SB), NOSPLIT, $0-16
+ MOVD res+0(FP), R3
+ MOVD in+8(FP), R4
+ BR p256InternalEndianSwap<>(SB)
+
+//func p256LittleToBig(res *[32]byte, in *p256Element)
+TEXT ·p256LittleToBig(SB), NOSPLIT, $0-16
+ MOVD res+0(FP), R3
+ MOVD in+8(FP), R4
+ BR p256InternalEndianSwap<>(SB)
+
+//func p256OrdBigToLittle(res *p256OrdElement, in *[32]byte)
+TEXT ·p256OrdBigToLittle(SB), NOSPLIT, $0-16
+ MOVD res+0(FP), R3
+ MOVD in+8(FP), R4
+ BR p256InternalEndianSwap<>(SB)
+
+//func p256OrdLittleToBig(res *[32]byte, in *p256OrdElement)
+TEXT ·p256OrdLittleToBig(SB), NOSPLIT, $0-16
+ MOVD res+0(FP), R3
+ MOVD in+8(FP), R4
+ BR p256InternalEndianSwap<>(SB)
+
+TEXT p256InternalEndianSwap<>(SB), NOSPLIT, $0-0
+ // Index registers needed for BR movs
+ MOVD $8, R9
+ MOVD $16, R10
+ MOVD $24, R14
+
+ MOVDBR (R0)(R4), R5
+ MOVDBR (R9)(R4), R6
+ MOVDBR (R10)(R4), R7
+ MOVDBR (R14)(R4), R8
+
+ MOVD R8, 0(R3)
+ MOVD R7, 8(R3)
+ MOVD R6, 16(R3)
+ MOVD R5, 24(R3)
+
+ RET
+
+#define P3ptr R3
+#define P1ptr R4
+#define COUNT R5
+
+#define X1L V0
+#define X1H V1
+#define Y1L V2
+#define Y1H V3
+#define Z1L V4
+#define Z1H V5
+#define X2L V6
+#define X2H V7
+#define Y2L V8
+#define Y2H V9
+#define Z2L V10
+#define Z2H V11
+
+#define ONE V18
+#define IDX V19
+#define SEL1 V20
+#define SEL2 V21
+
+// func p256SelectAffine(res *p256AffinePoint, table *p256AffineTable, idx int)
+TEXT ·p256SelectAffine(SB), NOSPLIT, $0-24
+ MOVD res+0(FP), P3ptr
+ MOVD table+8(FP), P1ptr
+ MOVD $16, R16
+ MOVD $32, R17
+ MOVD $48, R18
+
+ LXVDSX (R1)(R18), SEL1
+ VSPLTB $7, SEL1, IDX // splat byte
+
+ VSPLTISB $1, ONE // Vector with byte 1s
+ VSPLTISB $1, SEL2 // Vector with byte 1s
+ MOVD $64, COUNT
+ MOVD COUNT, CTR // loop count
+
+ VSPLTISB $0, X1H // VZERO X1H
+ VSPLTISB $0, X1L // VZERO X1L
+ VSPLTISB $0, Y1H // VZERO Y1H
+ VSPLTISB $0, Y1L // VZERO Y1L
+
+loop_select:
+ LXVD2X (P1ptr+R0), X2H
+ LXVD2X (P1ptr+R16), X2L
+ LXVD2X (P1ptr+R17), Y2H
+ LXVD2X (P1ptr+R18), Y2L
+
+ VCMPEQUD SEL2, IDX, SEL1 // Compare against idx
+
+ VSEL X1L, X2L, SEL1, X1L // Select if idx matched
+ VSEL X1H, X2H, SEL1, X1H
+ VSEL Y1L, Y2L, SEL1, Y1L
+ VSEL Y1H, Y2H, SEL1, Y1H
+
+ VADDUBM SEL2, ONE, SEL2 // Increment SEL2 bytes by 1
+ ADD $64, P1ptr // Next chunk
+ BDNZ loop_select
+
+ STXVD2X X1H, (P3ptr+R0)
+ STXVD2X X1L, (P3ptr+R16)
+ STXVD2X Y1H, (P3ptr+R17)
+ STXVD2X Y1L, (P3ptr+R18)
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef COUNT
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef X2L
+#undef X2H
+#undef Y2L
+#undef Y2H
+#undef Z2L
+#undef Z2H
+#undef ONE
+#undef IDX
+#undef SEL1
+#undef SEL2
+
+#define res_ptr R3
+#define x_ptr R4
+#define CPOOL R7
+
+#define T0 V0
+#define T1 V1
+#define T2 V2
+#define TT0 V3
+#define TT1 V4
+
+#define ZER V6
+#define SEL1 V7
+#define SEL2 V8
+#define CAR1 V9
+#define CAR2 V10
+#define RED1 V11
+#define RED2 V12
+#define PL V13
+#define PH V14
+
+// func p256FromMont(res, in *p256Element)
+TEXT ·p256FromMont(SB), NOSPLIT, $0-16
+ MOVD res+0(FP), res_ptr
+ MOVD in+8(FP), x_ptr
+
+ MOVD $16, R16
+ MOVD $32, R17
+ MOVD $48, R18
+ MOVD $64, R19
+ MOVD $p256<>+0x00(SB), CPOOL
+
+ VSPLTISB $0, T2 // VZERO T2
+ VSPLTISB $0, ZER // VZERO ZER
+
+ // Constants are defined so that the LXVD2X is correct
+ LXVD2X (CPOOL+R0), PH
+ LXVD2X (CPOOL+R16), PL
+
+ // VPERM byte selections
+ LXVD2X (CPOOL+R18), SEL2
+ LXVD2X (CPOOL+R19), SEL1
+
+ LXVD2X (R16)(x_ptr), T1
+ LXVD2X (R0)(x_ptr), T0
+
+ // Put in true little endian order
+ XXPERMDI T0, T0, $2, T0
+ XXPERMDI T1, T1, $2, T1
+
+ // First round
+ VPERM T1, T0, SEL1, RED2 // d1 d0 d1 d0
+ VPERM ZER, RED2, SEL2, RED1 // 0 d1 d0 0
+ VSUBUQM RED2, RED1, RED2 // VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDOI $8, T1, T0, T0 // VSLDB $8, T1, T0, T0
+ VSLDOI $8, T2, T1, T1 // VSLDB $8, T2, T1, T1
+
+ VADDCUQ T0, RED1, CAR1 // VACCQ T0, RED1, CAR1
+ VADDUQM T0, RED1, T0 // VAQ T0, RED1, T0
+ VADDECUQ T1, RED2, CAR1, CAR2 // VACCCQ T1, RED2, CAR1, CAR2
+ VADDEUQM T1, RED2, CAR1, T1 // VACQ T1, RED2, CAR1, T1
+ VADDUQM T2, CAR2, T2 // VAQ T2, CAR2, T2
+
+ // Second round
+ VPERM T1, T0, SEL1, RED2 // d1 d0 d1 d0
+ VPERM ZER, RED2, SEL2, RED1 // 0 d1 d0 0
+ VSUBUQM RED2, RED1, RED2 // VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDOI $8, T1, T0, T0 // VSLDB $8, T1, T0, T0
+ VSLDOI $8, T2, T1, T1 // VSLDB $8, T2, T1, T1
+
+ VADDCUQ T0, RED1, CAR1 // VACCQ T0, RED1, CAR1
+ VADDUQM T0, RED1, T0 // VAQ T0, RED1, T0
+ VADDECUQ T1, RED2, CAR1, CAR2 // VACCCQ T1, RED2, CAR1, CAR2
+ VADDEUQM T1, RED2, CAR1, T1 // VACQ T1, RED2, CAR1, T1
+ VADDUQM T2, CAR2, T2 // VAQ T2, CAR2, T2
+
+ // Third round
+ VPERM T1, T0, SEL1, RED2 // d1 d0 d1 d0
+ VPERM ZER, RED2, SEL2, RED1 // 0 d1 d0 0
+ VSUBUQM RED2, RED1, RED2 // VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDOI $8, T1, T0, T0 // VSLDB $8, T1, T0, T0
+ VSLDOI $8, T2, T1, T1 // VSLDB $8, T2, T1, T1
+
+ VADDCUQ T0, RED1, CAR1 // VACCQ T0, RED1, CAR1
+ VADDUQM T0, RED1, T0 // VAQ T0, RED1, T0
+ VADDECUQ T1, RED2, CAR1, CAR2 // VACCCQ T1, RED2, CAR1, CAR2
+ VADDEUQM T1, RED2, CAR1, T1 // VACQ T1, RED2, CAR1, T1
+ VADDUQM T2, CAR2, T2 // VAQ T2, CAR2, T2
+
+ // Last round
+ VPERM T1, T0, SEL1, RED2 // d1 d0 d1 d0
+ VPERM ZER, RED2, SEL2, RED1 // 0 d1 d0 0
+ VSUBUQM RED2, RED1, RED2 // VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDOI $8, T1, T0, T0 // VSLDB $8, T1, T0, T0
+ VSLDOI $8, T2, T1, T1 // VSLDB $8, T2, T1, T1
+
+ VADDCUQ T0, RED1, CAR1 // VACCQ T0, RED1, CAR1
+ VADDUQM T0, RED1, T0 // VAQ T0, RED1, T0
+ VADDECUQ T1, RED2, CAR1, CAR2 // VACCCQ T1, RED2, CAR1, CAR2
+ VADDEUQM T1, RED2, CAR1, T1 // VACQ T1, RED2, CAR1, T1
+ VADDUQM T2, CAR2, T2 // VAQ T2, CAR2, T2
+
+ // ---------------------------------------------------
+
+ VSUBCUQ T0, PL, CAR1 // VSCBIQ PL, T0, CAR1
+ VSUBUQM T0, PL, TT0 // VSQ PL, T0, TT0
+ VSUBECUQ T1, PH, CAR1, CAR2 // VSBCBIQ T1, PH, CAR1, CAR2
+ VSUBEUQM T1, PH, CAR1, TT1 // VSBIQ T1, PH, CAR1, TT1
+ VSUBEUQM T2, ZER, CAR2, T2 // VSBIQ T2, ZER, CAR2, T2
+
+ VSEL TT0, T0, T2, T0
+ VSEL TT1, T1, T2, T1
+
+ // Reorder the bytes so STXVD2X can be used.
+ // TT0, TT1 used for VPERM result in case
+ // the caller expects T0, T1 to be good.
+ XXPERMDI T0, T0, $2, TT0
+ XXPERMDI T1, T1, $2, TT1
+
+ STXVD2X TT0, (R0)(res_ptr)
+ STXVD2X TT1, (R16)(res_ptr)
+ RET
+
+#undef res_ptr
+#undef x_ptr
+#undef CPOOL
+#undef T0
+#undef T1
+#undef T2
+#undef TT0
+#undef TT1
+#undef ZER
+#undef SEL1
+#undef SEL2
+#undef CAR1
+#undef CAR2
+#undef RED1
+#undef RED2
+#undef PL
+#undef PH
+
+// ---------------------------------------
+// p256MulInternal
+// V0-V3 V30,V31 - Not Modified
+// V4-V15 V27-V29 - Volatile
+
+#define CPOOL R7
+
+// Parameters
+#define X0 V0 // Not modified
+#define X1 V1 // Not modified
+#define Y0 V2 // Not modified
+#define Y1 V3 // Not modified
+#define T0 V4 // Result
+#define T1 V5 // Result
+#define P0 V30 // Not modified
+#define P1 V31 // Not modified
+
+// Temporaries: lots of reused vector regs
+#define YDIG V6 // Overloaded with CAR2
+#define ADD1H V7 // Overloaded with ADD3H
+#define ADD2H V8 // Overloaded with ADD4H
+#define ADD3 V9 // Overloaded with SEL2,SEL5
+#define ADD4 V10 // Overloaded with SEL3,SEL6
+#define RED1 V11 // Overloaded with CAR2
+#define RED2 V12
+#define RED3 V13 // Overloaded with SEL1
+#define T2 V14
+// Overloaded temporaries
+#define ADD1 V4 // Overloaded with T0
+#define ADD2 V5 // Overloaded with T1
+#define ADD3H V7 // Overloaded with ADD1H
+#define ADD4H V8 // Overloaded with ADD2H
+#define ZER V28 // Overloaded with TMP1
+#define CAR1 V6 // Overloaded with YDIG
+#define CAR2 V11 // Overloaded with RED1
+// Constant Selects
+#define SEL1 V13 // Overloaded with RED3
+#define SEL2 V9 // Overloaded with ADD3,SEL5
+#define SEL3 V10 // Overloaded with ADD4,SEL6
+#define SEL4 V6 // Overloaded with YDIG,CAR1
+#define SEL5 V9 // Overloaded with ADD3,SEL2
+#define SEL6 V10 // Overloaded with ADD4,SEL3
+
+// TMP1, TMP2 used in
+// VMULT macros
+#define TMP1 V13 // Overloaded with RED3
+#define TMP2 V27
+#define ONE V29 // 1s splatted by word
+
+/* *
+ * To follow the flow of bits, for your own sanity a stiff drink, need you shall.
+ * Of a single round, a 'helpful' picture, here is. Meaning, column position has.
+ * With you, SIMD be...
+ *
+ * +--------+--------+
+ * +--------| RED2 | RED1 |
+ * | +--------+--------+
+ * | ---+--------+--------+
+ * | +---- T2| T1 | T0 |--+
+ * | | ---+--------+--------+ |
+ * | | |
+ * | | ======================= |
+ * | | |
+ * | | +--------+--------+<-+
+ * | +-------| ADD2 | ADD1 |--|-----+
+ * | | +--------+--------+ | |
+ * | | +--------+--------+<---+ |
+ * | | | ADD2H | ADD1H |--+ |
+ * | | +--------+--------+ | |
+ * | | +--------+--------+<-+ |
+ * | | | ADD4 | ADD3 |--|-+ |
+ * | | +--------+--------+ | | |
+ * | | +--------+--------+<---+ | |
+ * | | | ADD4H | ADD3H |------|-+ |(+vzero)
+ * | | +--------+--------+ | | V
+ * | | ------------------------ | | +--------+
+ * | | | | | RED3 | [d0 0 0 d0]
+ * | | | | +--------+
+ * | +---->+--------+--------+ | | |
+ * (T2[1w]||ADD2[4w]||ADD1[3w]) +--------| T1 | T0 | | | |
+ * | +--------+--------+ | | |
+ * +---->---+--------+--------+ | | |
+ * T2| T1 | T0 |----+ | |
+ * ---+--------+--------+ | | |
+ * ---+--------+--------+<---+ | |
+ * +--- T2| T1 | T0 |----------+
+ * | ---+--------+--------+ | |
+ * | +--------+--------+<-------------+
+ * | | RED2 | RED1 |-----+ | | [0 d1 d0 d1] [d0 0 d1 d0]
+ * | +--------+--------+ | | |
+ * | +--------+<----------------------+
+ * | | RED3 |--------------+ | [0 0 d1 d0]
+ * | +--------+ | |
+ * +--->+--------+--------+ | |
+ * | T1 | T0 |--------+
+ * +--------+--------+ | |
+ * --------------------------- | |
+ * | |
+ * +--------+--------+<----+ |
+ * | RED2 | RED1 | |
+ * +--------+--------+ |
+ * ---+--------+--------+<-------+
+ * T2| T1 | T0 | (H1P-H1P-H00RRAY!)
+ * ---+--------+--------+
+ *
+ * *Mi obra de arte de siglo XXI @vpaprots
+ *
+ *
+ * First group is special, doesn't get the two inputs:
+ * +--------+--------+<-+
+ * +-------| ADD2 | ADD1 |--|-----+
+ * | +--------+--------+ | |
+ * | +--------+--------+<---+ |
+ * | | ADD2H | ADD1H |--+ |
+ * | +--------+--------+ | |
+ * | +--------+--------+<-+ |
+ * | | ADD4 | ADD3 |--|-+ |
+ * | +--------+--------+ | | |
+ * | +--------+--------+<---+ | |
+ * | | ADD4H | ADD3H |------|-+ |(+vzero)
+ * | +--------+--------+ | | V
+ * | ------------------------ | | +--------+
+ * | | | | RED3 | [d0 0 0 d0]
+ * | | | +--------+
+ * +---->+--------+--------+ | | |
+ * (T2[1w]||ADD2[4w]||ADD1[3w]) | T1 | T0 |----+ | |
+ * +--------+--------+ | | |
+ * ---+--------+--------+<---+ | |
+ * +--- T2| T1 | T0 |----------+
+ * | ---+--------+--------+ | |
+ * | +--------+--------+<-------------+
+ * | | RED2 | RED1 |-----+ | | [0 d1 d0 d1] [d0 0 d1 d0]
+ * | +--------+--------+ | | |
+ * | +--------+<----------------------+
+ * | | RED3 |--------------+ | [0 0 d1 d0]
+ * | +--------+ | |
+ * +--->+--------+--------+ | |
+ * | T1 | T0 |--------+
+ * +--------+--------+ | |
+ * --------------------------- | |
+ * | |
+ * +--------+--------+<----+ |
+ * | RED2 | RED1 | |
+ * +--------+--------+ |
+ * ---+--------+--------+<-------+
+ * T2| T1 | T0 | (H1P-H1P-H00RRAY!)
+ * ---+--------+--------+
+ *
+ * Last 'group' needs to RED2||RED1 shifted less
+ */
+TEXT p256MulInternal<>(SB), NOSPLIT, $0-16
+ // CPOOL loaded from caller
+ MOVD $16, R16
+ MOVD $32, R17
+ MOVD $48, R18
+ MOVD $64, R19
+ MOVD $80, R20
+ MOVD $96, R21
+ MOVD $112, R22
+
+ // ---------------------------------------------------
+
+ VSPLTW $3, Y0, YDIG // VREPF Y0 is input
+
+ // VMLHF X0, YDIG, ADD1H
+ // VMLHF X1, YDIG, ADD2H
+ // VMLF X0, YDIG, ADD1
+ // VMLF X1, YDIG, ADD2
+ //
+ VMULT(X0, YDIG, ADD1, ADD1H)
+ VMULT(X1, YDIG, ADD2, ADD2H)
+
+ VSPLTISW $1, ONE
+ VSPLTW $2, Y0, YDIG // VREPF
+
+ // VMALF X0, YDIG, ADD1H, ADD3
+ // VMALF X1, YDIG, ADD2H, ADD4
+ // VMALHF X0, YDIG, ADD1H, ADD3H // ADD1H Free
+ // VMALHF X1, YDIG, ADD2H, ADD4H // ADD2H Free
+ VMULT_ADD(X0, YDIG, ADD1H, ONE, ADD3, ADD3H)
+ VMULT_ADD(X1, YDIG, ADD2H, ONE, ADD4, ADD4H)
+
+ LXVD2X (R17)(CPOOL), SEL1
+ VSPLTISB $0, ZER // VZERO ZER
+ VPERM ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
+
+ VSLDOI $12, ADD2, ADD1, T0 // ADD1 Free // VSLDB
+ VSLDOI $12, ZER, ADD2, T1 // ADD2 Free // VSLDB
+
+ VADDCUQ T0, ADD3, CAR1 // VACCQ
+ VADDUQM T0, ADD3, T0 // ADD3 Free // VAQ
+ VADDECUQ T1, ADD4, CAR1, T2 // VACCCQ
+ VADDEUQM T1, ADD4, CAR1, T1 // ADD4 Free // VACQ
+
+ LXVD2X (R18)(CPOOL), SEL2
+ LXVD2X (R19)(CPOOL), SEL3
+ LXVD2X (R20)(CPOOL), SEL4
+ VPERM RED3, T0, SEL2, RED1 // [d0 0 d1 d0]
+ VPERM RED3, T0, SEL3, RED2 // [ 0 d1 d0 d1]
+ VPERM RED3, T0, SEL4, RED3 // [ 0 0 d1 d0]
+ VSUBUQM RED2, RED3, RED2 // Guaranteed not to underflow -->? // VSQ
+
+ VSLDOI $12, T1, T0, T0 // VSLDB
+ VSLDOI $12, T2, T1, T1 // VSLDB
+
+ VADDCUQ T0, ADD3H, CAR1 // VACCQ
+ VADDUQM T0, ADD3H, T0 // VAQ
+ VADDECUQ T1, ADD4H, CAR1, T2 // VACCCQ
+ VADDEUQM T1, ADD4H, CAR1, T1 // VACQ
+
+ // ---------------------------------------------------
+
+ VSPLTW $1, Y0, YDIG // VREPF
+
+ // VMALHF X0, YDIG, T0, ADD1H
+ // VMALHF X1, YDIG, T1, ADD2H
+ // VMALF X0, YDIG, T0, ADD1 // T0 Free->ADD1
+ // VMALF X1, YDIG, T1, ADD2 // T1 Free->ADD2
+ VMULT_ADD(X0, YDIG, T0, ONE, ADD1, ADD1H)
+ VMULT_ADD(X1, YDIG, T1, ONE, ADD2, ADD2H)
+
+ VSPLTW $0, Y0, YDIG // VREPF
+
+ // VMALF X0, YDIG, ADD1H, ADD3
+ // VMALF X1, YDIG, ADD2H, ADD4
+ // VMALHF X0, YDIG, ADD1H, ADD3H // ADD1H Free->ADD3H
+ // VMALHF X1, YDIG, ADD2H, ADD4H // ADD2H Free->ADD4H , YDIG Free->ZER
+ VMULT_ADD(X0, YDIG, ADD1H, ONE, ADD3, ADD3H)
+ VMULT_ADD(X1, YDIG, ADD2H, ONE, ADD4, ADD4H)
+
+ VSPLTISB $0, ZER // VZERO ZER
+ LXVD2X (R17)(CPOOL), SEL1
+ VPERM ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
+
+ VSLDOI $12, ADD2, ADD1, T0 // ADD1 Free->T0 // VSLDB
+ VSLDOI $12, T2, ADD2, T1 // ADD2 Free->T1, T2 Free // VSLDB
+
+ VADDCUQ T0, RED1, CAR1 // VACCQ
+ VADDUQM T0, RED1, T0 // VAQ
+ VADDECUQ T1, RED2, CAR1, T2 // VACCCQ
+ VADDEUQM T1, RED2, CAR1, T1 // VACQ
+
+ VADDCUQ T0, ADD3, CAR1 // VACCQ
+ VADDUQM T0, ADD3, T0 // VAQ
+ VADDECUQ T1, ADD4, CAR1, CAR2 // VACCCQ
+ VADDEUQM T1, ADD4, CAR1, T1 // VACQ
+ VADDUQM T2, CAR2, T2 // VAQ
+
+ LXVD2X (R18)(CPOOL), SEL2
+ LXVD2X (R19)(CPOOL), SEL3
+ LXVD2X (R20)(CPOOL), SEL4
+ VPERM RED3, T0, SEL2, RED1 // [d0 0 d1 d0]
+ VPERM RED3, T0, SEL3, RED2 // [ 0 d1 d0 d1]
+ VPERM RED3, T0, SEL4, RED3 // [ 0 0 d1 d0]
+ VSUBUQM RED2, RED3, RED2 // Guaranteed not to underflow // VSQ
+
+ VSLDOI $12, T1, T0, T0 // VSLDB
+ VSLDOI $12, T2, T1, T1 // VSLDB
+
+ VADDCUQ T0, ADD3H, CAR1 // VACCQ
+ VADDUQM T0, ADD3H, T0 // VAQ
+ VADDECUQ T1, ADD4H, CAR1, T2 // VACCCQ
+ VADDEUQM T1, ADD4H, CAR1, T1 // VACQ
+
+ // ---------------------------------------------------
+
+ VSPLTW $3, Y1, YDIG // VREPF
+
+ // VMALHF X0, YDIG, T0, ADD1H
+ // VMALHF X1, YDIG, T1, ADD2H
+ // VMALF X0, YDIG, T0, ADD1
+ // VMALF X1, YDIG, T1, ADD2
+ VMULT_ADD(X0, YDIG, T0, ONE, ADD1, ADD1H)
+ VMULT_ADD(X1, YDIG, T1, ONE, ADD2, ADD2H)
+
+ VSPLTW $2, Y1, YDIG // VREPF
+
+ // VMALF X0, YDIG, ADD1H, ADD3
+ // VMALF X1, YDIG, ADD2H, ADD4
+ // VMALHF X0, YDIG, ADD1H, ADD3H // ADD1H Free
+ // VMALHF X1, YDIG, ADD2H, ADD4H // ADD2H Free
+ VMULT_ADD(X0, YDIG, ADD1H, ONE, ADD3, ADD3H)
+ VMULT_ADD(X1, YDIG, ADD2H, ONE, ADD4, ADD4H)
+
+ LXVD2X (R17)(CPOOL), SEL1
+ VSPLTISB $0, ZER // VZERO ZER
+ LXVD2X (R17)(CPOOL), SEL1
+ VPERM ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
+
+ VSLDOI $12, ADD2, ADD1, T0 // ADD1 Free // VSLDB
+ VSLDOI $12, T2, ADD2, T1 // ADD2 Free // VSLDB
+
+ VADDCUQ T0, RED1, CAR1 // VACCQ
+ VADDUQM T0, RED1, T0 // VAQ
+ VADDECUQ T1, RED2, CAR1, T2 // VACCCQ
+ VADDEUQM T1, RED2, CAR1, T1 // VACQ
+
+ VADDCUQ T0, ADD3, CAR1 // VACCQ
+ VADDUQM T0, ADD3, T0 // VAQ
+ VADDECUQ T1, ADD4, CAR1, CAR2 // VACCCQ
+ VADDEUQM T1, ADD4, CAR1, T1 // VACQ
+ VADDUQM T2, CAR2, T2 // VAQ
+
+ LXVD2X (R18)(CPOOL), SEL2
+ LXVD2X (R19)(CPOOL), SEL3
+ LXVD2X (R20)(CPOOL), SEL4
+ VPERM RED3, T0, SEL2, RED1 // [d0 0 d1 d0]
+ VPERM RED3, T0, SEL3, RED2 // [ 0 d1 d0 d1]
+ VPERM RED3, T0, SEL4, RED3 // [ 0 0 d1 d0]
+ VSUBUQM RED2, RED3, RED2 // Guaranteed not to underflow // VSQ
+
+ VSLDOI $12, T1, T0, T0 // VSLDB
+ VSLDOI $12, T2, T1, T1 // VSLDB
+
+ VADDCUQ T0, ADD3H, CAR1 // VACCQ
+ VADDUQM T0, ADD3H, T0 // VAQ
+ VADDECUQ T1, ADD4H, CAR1, T2 // VACCCQ
+ VADDEUQM T1, ADD4H, CAR1, T1 // VACQ
+
+ // ---------------------------------------------------
+
+ VSPLTW $1, Y1, YDIG // VREPF
+
+ // VMALHF X0, YDIG, T0, ADD1H
+ // VMALHF X1, YDIG, T1, ADD2H
+ // VMALF X0, YDIG, T0, ADD1
+ // VMALF X1, YDIG, T1, ADD2
+ VMULT_ADD(X0, YDIG, T0, ONE, ADD1, ADD1H)
+ VMULT_ADD(X1, YDIG, T1, ONE, ADD2, ADD2H)
+
+ VSPLTW $0, Y1, YDIG // VREPF
+
+ // VMALF X0, YDIG, ADD1H, ADD3
+ // VMALF X1, YDIG, ADD2H, ADD4
+ // VMALHF X0, YDIG, ADD1H, ADD3H
+ // VMALHF X1, YDIG, ADD2H, ADD4H
+ VMULT_ADD(X0, YDIG, ADD1H, ONE, ADD3, ADD3H)
+ VMULT_ADD(X1, YDIG, ADD2H, ONE, ADD4, ADD4H)
+
+ VSPLTISB $0, ZER // VZERO ZER
+ LXVD2X (R17)(CPOOL), SEL1
+ VPERM ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
+
+ VSLDOI $12, ADD2, ADD1, T0 // VSLDB
+ VSLDOI $12, T2, ADD2, T1 // VSLDB
+
+ VADDCUQ T0, RED1, CAR1 // VACCQ
+ VADDUQM T0, RED1, T0 // VAQ
+ VADDECUQ T1, RED2, CAR1, T2 // VACCCQ
+ VADDEUQM T1, RED2, CAR1, T1 // VACQ
+
+ VADDCUQ T0, ADD3, CAR1 // VACCQ
+ VADDUQM T0, ADD3, T0 // VAQ
+ VADDECUQ T1, ADD4, CAR1, CAR2 // VACCCQ
+ VADDEUQM T1, ADD4, CAR1, T1 // VACQ
+ VADDUQM T2, CAR2, T2 // VAQ
+
+ LXVD2X (R21)(CPOOL), SEL5
+ LXVD2X (R22)(CPOOL), SEL6
+ VPERM T0, RED3, SEL5, RED2 // [d1 d0 d1 d0]
+ VPERM T0, RED3, SEL6, RED1 // [ 0 d1 d0 0]
+ VSUBUQM RED2, RED1, RED2 // Guaranteed not to underflow // VSQ
+
+ VSLDOI $12, T1, T0, T0 // VSLDB
+ VSLDOI $12, T2, T1, T1 // VSLDB
+
+ VADDCUQ T0, ADD3H, CAR1 // VACCQ
+ VADDUQM T0, ADD3H, T0 // VAQ
+ VADDECUQ T1, ADD4H, CAR1, T2 // VACCCQ
+ VADDEUQM T1, ADD4H, CAR1, T1 // VACQ
+
+ VADDCUQ T0, RED1, CAR1 // VACCQ
+ VADDUQM T0, RED1, T0 // VAQ
+ VADDECUQ T1, RED2, CAR1, CAR2 // VACCCQ
+ VADDEUQM T1, RED2, CAR1, T1 // VACQ
+ VADDUQM T2, CAR2, T2 // VAQ
+
+ // ---------------------------------------------------
+
+ VSPLTISB $0, RED3 // VZERO RED3
+ VSUBCUQ T0, P0, CAR1 // VSCBIQ
+ VSUBUQM T0, P0, ADD1H // VSQ
+ VSUBECUQ T1, P1, CAR1, CAR2 // VSBCBIQ
+ VSUBEUQM T1, P1, CAR1, ADD2H // VSBIQ
+ VSUBEUQM T2, RED3, CAR2, T2 // VSBIQ
+
+ // what output to use, ADD2H||ADD1H or T1||T0?
+ VSEL ADD1H, T0, T2, T0
+ VSEL ADD2H, T1, T2, T1
+ RET
+
+#undef CPOOL
+
+#undef X0
+#undef X1
+#undef Y0
+#undef Y1
+#undef T0
+#undef T1
+#undef P0
+#undef P1
+
+#undef SEL1
+#undef SEL2
+#undef SEL3
+#undef SEL4
+#undef SEL5
+#undef SEL6
+
+#undef YDIG
+#undef ADD1H
+#undef ADD2H
+#undef ADD3
+#undef ADD4
+#undef RED1
+#undef RED2
+#undef RED3
+#undef T2
+#undef ADD1
+#undef ADD2
+#undef ADD3H
+#undef ADD4H
+#undef ZER
+#undef CAR1
+#undef CAR2
+
+#undef TMP1
+#undef TMP2
+
+#define p256SubInternal(T1, T0, X1, X0, Y1, Y0) \
+ VSPLTISB $0, ZER \ // VZERO
+ VSUBCUQ X0, Y0, CAR1 \
+ VSUBUQM X0, Y0, T0 \
+ VSUBECUQ X1, Y1, CAR1, SEL1 \
+ VSUBEUQM X1, Y1, CAR1, T1 \
+ VSUBUQM ZER, SEL1, SEL1 \ // VSQ
+ \
+ VADDCUQ T0, PL, CAR1 \ // VACCQ
+ VADDUQM T0, PL, TT0 \ // VAQ
+ VADDEUQM T1, PH, CAR1, TT1 \ // VACQ
+ \
+ VSEL TT0, T0, SEL1, T0 \
+ VSEL TT1, T1, SEL1, T1 \
+
+#define p256AddInternal(T1, T0, X1, X0, Y1, Y0) \
+ VADDCUQ X0, Y0, CAR1 \
+ VADDUQM X0, Y0, T0 \
+ VADDECUQ X1, Y1, CAR1, T2 \ // VACCCQ
+ VADDEUQM X1, Y1, CAR1, T1 \
+ \
+ VSPLTISB $0, ZER \
+ VSUBCUQ T0, PL, CAR1 \ // VSCBIQ
+ VSUBUQM T0, PL, TT0 \
+ VSUBECUQ T1, PH, CAR1, CAR2 \ // VSBCBIQ
+ VSUBEUQM T1, PH, CAR1, TT1 \ // VSBIQ
+ VSUBEUQM T2, ZER, CAR2, SEL1 \
+ \
+ VSEL TT0, T0, SEL1, T0 \
+ VSEL TT1, T1, SEL1, T1
+
+#define p256HalfInternal(T1, T0, X1, X0) \
+ VSPLTISB $0, ZER \
+ VSUBEUQM ZER, ZER, X0, SEL1 \
+ \
+ VADDCUQ X0, PL, CAR1 \
+ VADDUQM X0, PL, T0 \
+ VADDECUQ X1, PH, CAR1, T2 \
+ VADDEUQM X1, PH, CAR1, T1 \
+ \
+ VSEL T0, X0, SEL1, T0 \
+ VSEL T1, X1, SEL1, T1 \
+ VSEL T2, ZER, SEL1, T2 \
+ \
+ VSLDOI $15, T2, ZER, TT1 \
+ VSLDOI $15, T1, ZER, TT0 \
+ VSPLTISB $1, SEL1 \
+ VSR T0, SEL1, T0 \ // VSRL
+ VSR T1, SEL1, T1 \
+ VSPLTISB $7, SEL1 \ // VREPIB
+ VSL TT0, SEL1, TT0 \
+ VSL TT1, SEL1, TT1 \
+ VOR T0, TT0, T0 \
+ VOR T1, TT1, T1
+
+#define res_ptr R3
+#define x_ptr R4
+#define y_ptr R5
+#define CPOOL R7
+#define TEMP R8
+#define N R9
+
+// Parameters
+#define X0 V0
+#define X1 V1
+#define Y0 V2
+#define Y1 V3
+#define T0 V4
+#define T1 V5
+
+// Constants
+#define P0 V30
+#define P1 V31
+// func p256MulAsm(res, in1, in2 *p256Element)
+TEXT ·p256Mul(SB), NOSPLIT, $0-24
+ MOVD res+0(FP), res_ptr
+ MOVD in1+8(FP), x_ptr
+ MOVD in2+16(FP), y_ptr
+ MOVD $16, R16
+ MOVD $32, R17
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+
+
+ LXVD2X (R0)(x_ptr), X0
+ LXVD2X (R16)(x_ptr), X1
+
+ XXPERMDI X0, X0, $2, X0
+ XXPERMDI X1, X1, $2, X1
+
+ LXVD2X (R0)(y_ptr), Y0
+ LXVD2X (R16)(y_ptr), Y1
+
+ XXPERMDI Y0, Y0, $2, Y0
+ XXPERMDI Y1, Y1, $2, Y1
+
+ LXVD2X (R16)(CPOOL), P1
+ LXVD2X (R0)(CPOOL), P0
+
+ CALL p256MulInternal<>(SB)
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+
+ XXPERMDI T0, T0, $2, T0
+ XXPERMDI T1, T1, $2, T1
+ STXVD2X T0, (R0)(res_ptr)
+ STXVD2X T1, (R16)(res_ptr)
+ RET
+
+// func p256Sqr(res, in *p256Element, n int)
+TEXT ·p256Sqr(SB), NOSPLIT, $0-24
+ MOVD res+0(FP), res_ptr
+ MOVD in+8(FP), x_ptr
+ MOVD $16, R16
+ MOVD $32, R17
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+
+ LXVD2X (R0)(x_ptr), X0
+ LXVD2X (R16)(x_ptr), X1
+
+ XXPERMDI X0, X0, $2, X0
+ XXPERMDI X1, X1, $2, X1
+
+sqrLoop:
+ // Sqr uses same value for both
+
+ VOR X0, X0, Y0
+ VOR X1, X1, Y1
+
+ LXVD2X (R16)(CPOOL), P1
+ LXVD2X (R0)(CPOOL), P0
+
+ CALL p256MulInternal<>(SB)
+
+ MOVD n+16(FP), N
+ ADD $-1, N
+ CMP $0, N
+ BEQ done
+ MOVD N, n+16(FP) // Save counter to avoid clobber
+ VOR T0, T0, X0
+ VOR T1, T1, X1
+ BR sqrLoop
+
+done:
+ MOVD $p256mul<>+0x00(SB), CPOOL
+
+ XXPERMDI T0, T0, $2, T0
+ XXPERMDI T1, T1, $2, T1
+ STXVD2X T0, (R0)(res_ptr)
+ STXVD2X T1, (R16)(res_ptr)
+ RET
+
+#undef res_ptr
+#undef x_ptr
+#undef y_ptr
+#undef CPOOL
+
+#undef X0
+#undef X1
+#undef Y0
+#undef Y1
+#undef T0
+#undef T1
+#undef P0
+#undef P1
+
+#define P3ptr R3
+#define P1ptr R4
+#define P2ptr R5
+#define CPOOL R7
+
+// Temporaries in REGs
+#define Y2L V15
+#define Y2H V16
+#define T1L V17
+#define T1H V18
+#define T2L V19
+#define T2H V20
+#define T3L V21
+#define T3H V22
+#define T4L V23
+#define T4H V24
+
+// Temps for Sub and Add
+#define TT0 V11
+#define TT1 V12
+#define T2 V13
+
+// p256MulAsm Parameters
+#define X0 V0
+#define X1 V1
+#define Y0 V2
+#define Y1 V3
+#define T0 V4
+#define T1 V5
+
+#define PL V30
+#define PH V31
+
+// Names for zero/sel selects
+#define X1L V0
+#define X1H V1
+#define Y1L V2 // p256MulAsmParmY
+#define Y1H V3 // p256MulAsmParmY
+#define Z1L V4
+#define Z1H V5
+#define X2L V0
+#define X2H V1
+#define Z2L V4
+#define Z2H V5
+#define X3L V17 // T1L
+#define X3H V18 // T1H
+#define Y3L V21 // T3L
+#define Y3H V22 // T3H
+#define Z3L V25
+#define Z3H V26
+
+#define ZER V6
+#define SEL1 V7
+#define CAR1 V8
+#define CAR2 V9
+/* *
+ * Three operand formula:
+ * Source: 2004 Hankerson–Menezes–Vanstone, page 91.
+ * T1 = Z1²
+ * T2 = T1*Z1
+ * T1 = T1*X2
+ * T2 = T2*Y2
+ * T1 = T1-X1
+ * T2 = T2-Y1
+ * Z3 = Z1*T1
+ * T3 = T1²
+ * T4 = T3*T1
+ * T3 = T3*X1
+ * T1 = 2*T3
+ * X3 = T2²
+ * X3 = X3-T1
+ * X3 = X3-T4
+ * T3 = T3-X3
+ * T3 = T3*T2
+ * T4 = T4*Y1
+ * Y3 = T3-T4
+
+ * Three operand formulas, but with MulInternal X,Y used to store temps
+X=Z1; Y=Z1; MUL;T- // T1 = Z1² T1
+X=T ; Y- ; MUL;T2=T // T2 = T1*Z1 T1 T2
+X- ; Y=X2; MUL;T1=T // T1 = T1*X2 T1 T2
+X=T2; Y=Y2; MUL;T- // T2 = T2*Y2 T1 T2
+SUB(T2<T-Y1) // T2 = T2-Y1 T1 T2
+SUB(Y<T1-X1) // T1 = T1-X1 T1 T2
+X=Z1; Y- ; MUL;Z3:=T// Z3 = Z1*T1 T2
+X=Y; Y- ; MUL;X=T // T3 = T1*T1 T2
+X- ; Y- ; MUL;T4=T // T4 = T3*T1 T2 T4
+X- ; Y=X1; MUL;T3=T // T3 = T3*X1 T2 T3 T4
+ADD(T1<T+T) // T1 = T3+T3 T1 T2 T3 T4
+X=T2; Y=T2; MUL;T- // X3 = T2*T2 T1 T2 T3 T4
+SUB(T<T-T1) // X3 = X3-T1 T1 T2 T3 T4
+SUB(T<T-T4) X3:=T // X3 = X3-T4 T2 T3 T4
+SUB(X<T3-T) // T3 = T3-X3 T2 T3 T4
+X- ; Y- ; MUL;T3=T // T3 = T3*T2 T2 T3 T4
+X=T4; Y=Y1; MUL;T- // T4 = T4*Y1 T3 T4
+SUB(T<T3-T) Y3:=T // Y3 = T3-T4 T3 T4
+
+ */
+//
+// V27 is clobbered by p256MulInternal so must be
+// saved in a temp.
+//
+// func p256PointAddAffineAsm(res, in1 *P256Point, in2 *p256AffinePoint, sign, sel, zero int)
+TEXT ·p256PointAddAffineAsm(SB), NOSPLIT, $16-48
+ MOVD res+0(FP), P3ptr
+ MOVD in1+8(FP), P1ptr
+ MOVD in2+16(FP), P2ptr
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+
+ MOVD $16, R16
+ MOVD $32, R17
+ MOVD $48, R18
+ MOVD $64, R19
+ MOVD $80, R20
+ MOVD $96, R21
+ MOVD $112, R22
+ MOVD $128, R23
+ MOVD $144, R24
+ MOVD $160, R25
+ MOVD $104, R26 // offset of sign+24(FP)
+
+ LXVD2X (R16)(CPOOL), PH
+ LXVD2X (R0)(CPOOL), PL
+
+ LXVD2X (R17)(P2ptr), Y2L
+ LXVD2X (R18)(P2ptr), Y2H
+ XXPERMDI Y2H, Y2H, $2, Y2H
+ XXPERMDI Y2L, Y2L, $2, Y2L
+
+ // Equivalent of VLREPG sign+24(FP), SEL1
+ LXVDSX (R1)(R26), SEL1
+ VSPLTISB $0, ZER
+ VCMPEQUD SEL1, ZER, SEL1
+
+ VSUBCUQ PL, Y2L, CAR1
+ VSUBUQM PL, Y2L, T1L
+ VSUBEUQM PH, Y2H, CAR1, T1H
+
+ VSEL T1L, Y2L, SEL1, Y2L
+ VSEL T1H, Y2H, SEL1, Y2H
+
+/* *
+ * Three operand formula:
+ * Source: 2004 Hankerson–Menezes–Vanstone, page 91.
+ */
+ // X=Z1; Y=Z1; MUL; T- // T1 = Z1² T1
+ LXVD2X (R19)(P1ptr), X0 // Z1H
+ LXVD2X (R20)(P1ptr), X1 // Z1L
+ XXPERMDI X0, X0, $2, X0
+ XXPERMDI X1, X1, $2, X1
+ VOR X0, X0, Y0
+ VOR X1, X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // X=T ; Y- ; MUL; T2=T // T2 = T1*Z1 T1 T2
+ VOR T0, T0, X0
+ VOR T1, T1, X1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, T2L
+ VOR T1, T1, T2H
+
+ // X- ; Y=X2; MUL; T1=T // T1 = T1*X2 T1 T2
+ MOVD in2+16(FP), P2ptr
+ LXVD2X (R0)(P2ptr), Y0 // X2H
+ LXVD2X (R16)(P2ptr), Y1 // X2L
+ XXPERMDI Y0, Y0, $2, Y0
+ XXPERMDI Y1, Y1, $2, Y1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, T1L
+ VOR T1, T1, T1H
+
+ // X=T2; Y=Y2; MUL; T- // T2 = T2*Y2 T1 T2
+ VOR T2L, T2L, X0
+ VOR T2H, T2H, X1
+ VOR Y2L, Y2L, Y0
+ VOR Y2H, Y2H, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(T2<T-Y1) // T2 = T2-Y1 T1 T2
+ MOVD in1+8(FP), P1ptr
+ LXVD2X (R17)(P1ptr), Y1L
+ LXVD2X (R18)(P1ptr), Y1H
+ XXPERMDI Y1H, Y1H, $2, Y1H
+ XXPERMDI Y1L, Y1L, $2, Y1L
+ p256SubInternal(T2H,T2L,T1,T0,Y1H,Y1L)
+
+ // SUB(Y<T1-X1) // T1 = T1-X1 T1 T2
+ LXVD2X (R0)(P1ptr), X1L
+ LXVD2X (R16)(P1ptr), X1H
+ XXPERMDI X1H, X1H, $2, X1H
+ XXPERMDI X1L, X1L, $2, X1L
+ p256SubInternal(Y1,Y0,T1H,T1L,X1H,X1L)
+
+ // X=Z1; Y- ; MUL; Z3:=T// Z3 = Z1*T1 T2
+ LXVD2X (R19)(P1ptr), X0 // Z1H
+ LXVD2X (R20)(P1ptr), X1 // Z1L
+ XXPERMDI X0, X0, $2, X0
+ XXPERMDI X1, X1, $2, X1
+ CALL p256MulInternal<>(SB)
+
+ VOR T0, T0, Z3L
+ VOR T1, T1, Z3H
+
+ // X=Y; Y- ; MUL; X=T // T3 = T1*T1 T2
+ VOR Y0, Y0, X0
+ VOR Y1, Y1, X1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, X0
+ VOR T1, T1, X1
+
+ // X- ; Y- ; MUL; T4=T // T4 = T3*T1 T2 T4
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, T4L
+ VOR T1, T1, T4H
+
+ // X- ; Y=X1; MUL; T3=T // T3 = T3*X1 T2 T3 T4
+ MOVD in1+8(FP), P1ptr
+ LXVD2X (R0)(P1ptr), Y0 // X1H
+ LXVD2X (R16)(P1ptr), Y1 // X1L
+ XXPERMDI Y1, Y1, $2, Y1
+ XXPERMDI Y0, Y0, $2, Y0
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, T3L
+ VOR T1, T1, T3H
+
+ // ADD(T1<T+T) // T1 = T3+T3 T1 T2 T3 T4
+ p256AddInternal(T1H,T1L, T1,T0,T1,T0)
+
+ // X=T2; Y=T2; MUL; T- // X3 = T2*T2 T1 T2 T3 T4
+ VOR T2L, T2L, X0
+ VOR T2H, T2H, X1
+ VOR T2L, T2L, Y0
+ VOR T2H, T2H, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(T<T-T1) // X3 = X3-T1 T1 T2 T3 T4 (T1 = X3)
+ p256SubInternal(T1,T0,T1,T0,T1H,T1L)
+
+ // SUB(T<T-T4) X3:=T // X3 = X3-T4 T2 T3 T4
+ p256SubInternal(T1,T0,T1,T0,T4H,T4L)
+ VOR T0, T0, X3L
+ VOR T1, T1, X3H
+
+ // SUB(X<T3-T) // T3 = T3-X3 T2 T3 T4
+ p256SubInternal(X1,X0,T3H,T3L,T1,T0)
+
+ // X- ; Y- ; MUL; T3=T // T3 = T3*T2 T2 T3 T4
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, T3L
+ VOR T1, T1, T3H
+
+ // X=T4; Y=Y1; MUL; T- // T4 = T4*Y1 T3 T4
+ VOR T4L, T4L, X0
+ VOR T4H, T4H, X1
+ MOVD in1+8(FP), P1ptr
+ LXVD2X (R17)(P1ptr), Y0 // Y1H
+ LXVD2X (R18)(P1ptr), Y1 // Y1L
+ XXPERMDI Y0, Y0, $2, Y0
+ XXPERMDI Y1, Y1, $2, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(T<T3-T) Y3:=T // Y3 = T3-T4 T3 T4 (T3 = Y3)
+ p256SubInternal(Y3H,Y3L,T3H,T3L,T1,T0)
+
+ // if (sel == 0) {
+ // copy(P3.x[:], X1)
+ // copy(P3.y[:], Y1)
+ // copy(P3.z[:], Z1)
+ // }
+
+ LXVD2X (R0)(P1ptr), X1L
+ LXVD2X (R16)(P1ptr), X1H
+ XXPERMDI X1H, X1H, $2, X1H
+ XXPERMDI X1L, X1L, $2, X1L
+
+ // Y1 already loaded, left over from addition
+ LXVD2X (R19)(P1ptr), Z1L
+ LXVD2X (R20)(P1ptr), Z1H
+ XXPERMDI Z1H, Z1H, $2, Z1H
+ XXPERMDI Z1L, Z1L, $2, Z1L
+
+ MOVD $112, R26 // Get offset to sel+32
+ LXVDSX (R1)(R26), SEL1
+ VSPLTISB $0, ZER
+ VCMPEQUD SEL1, ZER, SEL1
+
+ VSEL X3L, X1L, SEL1, X3L
+ VSEL X3H, X1H, SEL1, X3H
+ VSEL Y3L, Y1L, SEL1, Y3L
+ VSEL Y3H, Y1H, SEL1, Y3H
+ VSEL Z3L, Z1L, SEL1, Z3L
+ VSEL Z3H, Z1H, SEL1, Z3H
+
+ MOVD in2+16(FP), P2ptr
+ LXVD2X (R0)(P2ptr), X2L
+ LXVD2X (R16)(P2ptr), X2H
+ XXPERMDI X2H, X2H, $2, X2H
+ XXPERMDI X2L, X2L, $2, X2L
+
+ // Y2 already loaded
+ LXVD2X (R23)(CPOOL), Z2L
+ LXVD2X (R24)(CPOOL), Z2H
+
+ MOVD $120, R26 // Get the value from zero+40(FP)
+ LXVDSX (R1)(R26), SEL1
+ VSPLTISB $0, ZER
+ VCMPEQUD SEL1, ZER, SEL1
+
+ VSEL X3L, X2L, SEL1, X3L
+ VSEL X3H, X2H, SEL1, X3H
+ VSEL Y3L, Y2L, SEL1, Y3L
+ VSEL Y3H, Y2H, SEL1, Y3H
+ VSEL Z3L, Z2L, SEL1, Z3L
+ VSEL Z3H, Z2H, SEL1, Z3H
+
+ // Reorder the bytes so they can be stored using STXVD2X.
+ MOVD res+0(FP), P3ptr
+ XXPERMDI X3H, X3H, $2, X3H
+ XXPERMDI X3L, X3L, $2, X3L
+ XXPERMDI Y3H, Y3H, $2, Y3H
+ XXPERMDI Y3L, Y3L, $2, Y3L
+ XXPERMDI Z3H, Z3H, $2, Z3H
+ XXPERMDI Z3L, Z3L, $2, Z3L
+ STXVD2X X3L, (R0)(P3ptr)
+ STXVD2X X3H, (R16)(P3ptr)
+ STXVD2X Y3L, (R17)(P3ptr)
+ STXVD2X Y3H, (R18)(P3ptr)
+ STXVD2X Z3L, (R19)(P3ptr)
+ STXVD2X Z3H, (R20)(P3ptr)
+
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef P2ptr
+#undef CPOOL
+
+#undef Y2L
+#undef Y2H
+#undef T1L
+#undef T1H
+#undef T2L
+#undef T2H
+#undef T3L
+#undef T3H
+#undef T4L
+#undef T4H
+
+#undef TT0
+#undef TT1
+#undef T2
+
+#undef X0
+#undef X1
+#undef Y0
+#undef Y1
+#undef T0
+#undef T1
+
+#undef PL
+#undef PH
+
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef X2L
+#undef X2H
+#undef Z2L
+#undef Z2H
+#undef X3L
+#undef X3H
+#undef Y3L
+#undef Y3H
+#undef Z3L
+#undef Z3H
+
+#undef ZER
+#undef SEL1
+#undef CAR1
+#undef CAR2
+
+// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl
+// http://www.hyperelliptic.org/EFD/g1p/auto-shortw.html
+// http://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective-3.html
+#define P3ptr R3
+#define P1ptr R4
+#define CPOOL R7
+
+// Temporaries in REGs
+#define X3L V15
+#define X3H V16
+#define Y3L V17
+#define Y3H V18
+#define T1L V19
+#define T1H V20
+#define T2L V21
+#define T2H V22
+#define T3L V23
+#define T3H V24
+
+#define X1L V6
+#define X1H V7
+#define Y1L V8
+#define Y1H V9
+#define Z1L V10
+#define Z1H V11
+
+// Temps for Sub and Add
+#define TT0 V11
+#define TT1 V12
+#define T2 V13
+
+// p256MulAsm Parameters
+#define X0 V0
+#define X1 V1
+#define Y0 V2
+#define Y1 V3
+#define T0 V4
+#define T1 V5
+
+#define PL V30
+#define PH V31
+
+#define Z3L V23
+#define Z3H V24
+
+#define ZER V26
+#define SEL1 V27
+#define CAR1 V28
+#define CAR2 V29
+/*
+ * http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2004-hmv
+ * Cost: 4M + 4S + 1*half + 5add + 2*2 + 1*3.
+ * Source: 2004 Hankerson–Menezes–Vanstone, page 91.
+ * A = 3(X₁-Z₁²)×(X₁+Z₁²)
+ * B = 2Y₁
+ * Z₃ = B×Z₁
+ * C = B²
+ * D = C×X₁
+ * X₃ = A²-2D
+ * Y₃ = (D-X₃)×A-C²/2
+ *
+ * Three-operand formula:
+ * T1 = Z1²
+ * T2 = X1-T1
+ * T1 = X1+T1
+ * T2 = T2*T1
+ * T2 = 3*T2
+ * Y3 = 2*Y1
+ * Z3 = Y3*Z1
+ * Y3 = Y3²
+ * T3 = Y3*X1
+ * Y3 = Y3²
+ * Y3 = half*Y3
+ * X3 = T2²
+ * T1 = 2*T3
+ * X3 = X3-T1
+ * T1 = T3-X3
+ * T1 = T1*T2
+ * Y3 = T1-Y3
+ */
+// p256PointDoubleAsm(res, in1 *p256Point)
+TEXT ·p256PointDoubleAsm(SB), NOSPLIT, $0-16
+ MOVD res+0(FP), P3ptr
+ MOVD in+8(FP), P1ptr
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+
+ MOVD $16, R16
+ MOVD $32, R17
+ MOVD $48, R18
+ MOVD $64, R19
+ MOVD $80, R20
+
+ LXVD2X (R16)(CPOOL), PH
+ LXVD2X (R0)(CPOOL), PL
+
+ // X=Z1; Y=Z1; MUL; T- // T1 = Z1²
+ LXVD2X (R19)(P1ptr), X0 // Z1H
+ LXVD2X (R20)(P1ptr), X1 // Z1L
+
+ XXPERMDI X0, X0, $2, X0
+ XXPERMDI X1, X1, $2, X1
+
+ VOR X0, X0, Y0
+ VOR X1, X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(X<X1-T) // T2 = X1-T1
+ LXVD2X (R0)(P1ptr), X1L
+ LXVD2X (R16)(P1ptr), X1H
+ XXPERMDI X1L, X1L, $2, X1L
+ XXPERMDI X1H, X1H, $2, X1H
+
+ p256SubInternal(X1,X0,X1H,X1L,T1,T0)
+
+ // ADD(Y<X1+T) // T1 = X1+T1
+ p256AddInternal(Y1,Y0,X1H,X1L,T1,T0)
+
+ // X- ; Y- ; MUL; T- // T2 = T2*T1
+ CALL p256MulInternal<>(SB)
+
+ // ADD(T2<T+T); ADD(T2<T2+T) // T2 = 3*T2
+ p256AddInternal(T2H,T2L,T1,T0,T1,T0)
+ p256AddInternal(T2H,T2L,T2H,T2L,T1,T0)
+
+ // ADD(X<Y1+Y1) // Y3 = 2*Y1
+ LXVD2X (R17)(P1ptr), Y1L
+ LXVD2X (R18)(P1ptr), Y1H
+ XXPERMDI Y1L, Y1L, $2, Y1L
+ XXPERMDI Y1H, Y1H, $2, Y1H
+
+ p256AddInternal(X1,X0,Y1H,Y1L,Y1H,Y1L)
+
+ // X- ; Y=Z1; MUL; Z3:=T // Z3 = Y3*Z1
+ LXVD2X (R19)(P1ptr), Y0
+ LXVD2X (R20)(P1ptr), Y1
+ XXPERMDI Y0, Y0, $2, Y0
+ XXPERMDI Y1, Y1, $2, Y1
+
+ CALL p256MulInternal<>(SB)
+
+ // Leave T0, T1 as is.
+ XXPERMDI T0, T0, $2, TT0
+ XXPERMDI T1, T1, $2, TT1
+ STXVD2X TT0, (R19)(P3ptr)
+ STXVD2X TT1, (R20)(P3ptr)
+
+ // X- ; Y=X ; MUL; T- // Y3 = Y3²
+ VOR X0, X0, Y0
+ VOR X1, X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // X=T ; Y=X1; MUL; T3=T // T3 = Y3*X1
+ VOR T0, T0, X0
+ VOR T1, T1, X1
+ LXVD2X (R0)(P1ptr), Y0
+ LXVD2X (R16)(P1ptr), Y1
+ XXPERMDI Y0, Y0, $2, Y0
+ XXPERMDI Y1, Y1, $2, Y1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, T3L
+ VOR T1, T1, T3H
+
+ // X- ; Y=X ; MUL; T- // Y3 = Y3²
+ VOR X0, X0, Y0
+ VOR X1, X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // HAL(Y3<T) // Y3 = half*Y3
+ p256HalfInternal(Y3H,Y3L, T1,T0)
+
+ // X=T2; Y=T2; MUL; T- // X3 = T2²
+ VOR T2L, T2L, X0
+ VOR T2H, T2H, X1
+ VOR T2L, T2L, Y0
+ VOR T2H, T2H, Y1
+ CALL p256MulInternal<>(SB)
+
+ // ADD(T1<T3+T3) // T1 = 2*T3
+ p256AddInternal(T1H,T1L,T3H,T3L,T3H,T3L)
+
+ // SUB(X3<T-T1) X3:=X3 // X3 = X3-T1
+ p256SubInternal(X3H,X3L,T1,T0,T1H,T1L)
+
+ XXPERMDI X3L, X3L, $2, TT0
+ XXPERMDI X3H, X3H, $2, TT1
+ STXVD2X TT0, (R0)(P3ptr)
+ STXVD2X TT1, (R16)(P3ptr)
+
+ // SUB(X<T3-X3) // T1 = T3-X3
+ p256SubInternal(X1,X0,T3H,T3L,X3H,X3L)
+
+ // X- ; Y- ; MUL; T- // T1 = T1*T2
+ CALL p256MulInternal<>(SB)
+
+ // SUB(Y3<T-Y3) // Y3 = T1-Y3
+ p256SubInternal(Y3H,Y3L,T1,T0,Y3H,Y3L)
+
+ XXPERMDI Y3L, Y3L, $2, Y3L
+ XXPERMDI Y3H, Y3H, $2, Y3H
+ STXVD2X Y3L, (R17)(P3ptr)
+ STXVD2X Y3H, (R18)(P3ptr)
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef CPOOL
+#undef X3L
+#undef X3H
+#undef Y3L
+#undef Y3H
+#undef T1L
+#undef T1H
+#undef T2L
+#undef T2H
+#undef T3L
+#undef T3H
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef TT0
+#undef TT1
+#undef T2
+#undef X0
+#undef X1
+#undef Y0
+#undef Y1
+#undef T0
+#undef T1
+#undef PL
+#undef PH
+#undef Z3L
+#undef Z3H
+#undef ZER
+#undef SEL1
+#undef CAR1
+#undef CAR2
+
+#define P3ptr R3
+#define P1ptr R4
+#define P2ptr R5
+#define CPOOL R7
+#define TRUE R14
+#define RES1 R9
+#define RES2 R10
+
+// Temporaries in REGs
+#define T1L V16
+#define T1H V17
+#define T2L V18
+#define T2H V19
+#define U1L V20
+#define U1H V21
+#define S1L V22
+#define S1H V23
+#define HL V24
+#define HH V25
+#define RL V26
+#define RH V27
+
+// Temps for Sub and Add
+#define ZER V6
+#define SEL1 V7
+#define CAR1 V8
+#define CAR2 V9
+#define TT0 V11
+#define TT1 V12
+#define T2 V13
+
+// p256MulAsm Parameters
+#define X0 V0
+#define X1 V1
+#define Y0 V2
+#define Y1 V3
+#define T0 V4
+#define T1 V5
+
+#define PL V30
+#define PH V31
+/*
+ * https://choucroutage.com/Papers/SideChannelAttacks/ctrsa-2011-brown.pdf "Software Implementation of the NIST Elliptic Curves Over Prime Fields"
+ *
+ * A = X₁×Z₂²
+ * B = Y₁×Z₂³
+ * C = X₂×Z₁²-A
+ * D = Y₂×Z₁³-B
+ * X₃ = D² - 2A×C² - C³
+ * Y₃ = D×(A×C² - X₃) - B×C³
+ * Z₃ = Z₁×Z₂×C
+ *
+ * Three-operand formula (adopted): http://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2
+ * Temp storage: T1,T2,U1,H,Z3=X3=Y3,S1,R
+ *
+ * T1 = Z1*Z1
+ * T2 = Z2*Z2
+ * U1 = X1*T2
+ * H = X2*T1
+ * H = H-U1
+ * Z3 = Z1*Z2
+ * Z3 = Z3*H << store-out Z3 result reg.. could override Z1, if slices have same backing array
+ *
+ * S1 = Z2*T2
+ * S1 = Y1*S1
+ * R = Z1*T1
+ * R = Y2*R
+ * R = R-S1
+ *
+ * T1 = H*H
+ * T2 = H*T1
+ * U1 = U1*T1
+ *
+ * X3 = R*R
+ * X3 = X3-T2
+ * T1 = 2*U1
+ * X3 = X3-T1 << store-out X3 result reg
+ *
+ * T2 = S1*T2
+ * Y3 = U1-X3
+ * Y3 = R*Y3
+ * Y3 = Y3-T2 << store-out Y3 result reg
+
+ // X=Z1; Y=Z1; MUL; T- // T1 = Z1*Z1
+ // X- ; Y=T ; MUL; R=T // R = Z1*T1
+ // X=X2; Y- ; MUL; H=T // H = X2*T1
+ // X=Z2; Y=Z2; MUL; T- // T2 = Z2*Z2
+ // X- ; Y=T ; MUL; S1=T // S1 = Z2*T2
+ // X=X1; Y- ; MUL; U1=T // U1 = X1*T2
+ // SUB(H<H-T) // H = H-U1
+ // X=Z1; Y=Z2; MUL; T- // Z3 = Z1*Z2
+ // X=T ; Y=H ; MUL; Z3:=T// Z3 = Z3*H << store-out Z3 result reg.. could override Z1, if slices have same backing array
+ // X=Y1; Y=S1; MUL; S1=T // S1 = Y1*S1
+ // X=Y2; Y=R ; MUL; T- // R = Y2*R
+ // SUB(R<T-S1) // R = R-S1
+ // X=H ; Y=H ; MUL; T- // T1 = H*H
+ // X- ; Y=T ; MUL; T2=T // T2 = H*T1
+ // X=U1; Y- ; MUL; U1=T // U1 = U1*T1
+ // X=R ; Y=R ; MUL; T- // X3 = R*R
+ // SUB(T<T-T2) // X3 = X3-T2
+ // ADD(X<U1+U1) // T1 = 2*U1
+ // SUB(T<T-X) X3:=T // X3 = X3-T1 << store-out X3 result reg
+ // SUB(Y<U1-T) // Y3 = U1-X3
+ // X=R ; Y- ; MUL; U1=T // Y3 = R*Y3
+ // X=S1; Y=T2; MUL; T- // T2 = S1*T2
+ // SUB(T<U1-T); Y3:=T // Y3 = Y3-T2 << store-out Y3 result reg
+ */
+// p256PointAddAsm(res, in1, in2 *p256Point)
+TEXT ·p256PointAddAsm(SB), NOSPLIT, $16-32
+ MOVD res+0(FP), P3ptr
+ MOVD in1+8(FP), P1ptr
+ MOVD $p256mul<>+0x00(SB), CPOOL
+ MOVD $16, R16
+ MOVD $32, R17
+ MOVD $48, R18
+ MOVD $64, R19
+ MOVD $80, R20
+
+ LXVD2X (R16)(CPOOL), PH
+ LXVD2X (R0)(CPOOL), PL
+
+ // X=Z1; Y=Z1; MUL; T- // T1 = Z1*Z1
+ LXVD2X (R19)(P1ptr), X0 // Z1L
+ LXVD2X (R20)(P1ptr), X1 // Z1H
+ XXPERMDI X0, X0, $2, X0
+ XXPERMDI X1, X1, $2, X1
+ VOR X0, X0, Y0
+ VOR X1, X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // X- ; Y=T ; MUL; R=T // R = Z1*T1
+ VOR T0, T0, Y0
+ VOR T1, T1, Y1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, RL // SAVE: RL
+ VOR T1, T1, RH // SAVE: RH
+
+ STXVD2X RH, (R1)(R17) // V27 has to be saved
+
+ // X=X2; Y- ; MUL; H=T // H = X2*T1
+ MOVD in2+16(FP), P2ptr
+ LXVD2X (R0)(P2ptr), X0 // X2L
+ LXVD2X (R16)(P2ptr), X1 // X2H
+ XXPERMDI X0, X0, $2, X0
+ XXPERMDI X1, X1, $2, X1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, HL // SAVE: HL
+ VOR T1, T1, HH // SAVE: HH
+
+ // X=Z2; Y=Z2; MUL; T- // T2 = Z2*Z2
+ MOVD in2+16(FP), P2ptr
+ LXVD2X (R19)(P2ptr), X0 // Z2L
+ LXVD2X (R20)(P2ptr), X1 // Z2H
+ XXPERMDI X0, X0, $2, X0
+ XXPERMDI X1, X1, $2, X1
+ VOR X0, X0, Y0
+ VOR X1, X1, Y1
+ CALL p256MulInternal<>(SB)
+
+ // X- ; Y=T ; MUL; S1=T // S1 = Z2*T2
+ VOR T0, T0, Y0
+ VOR T1, T1, Y1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, S1L // SAVE: S1L
+ VOR T1, T1, S1H // SAVE: S1H
+
+ // X=X1; Y- ; MUL; U1=T // U1 = X1*T2
+ MOVD in1+8(FP), P1ptr
+ LXVD2X (R0)(P1ptr), X0 // X1L
+ LXVD2X (R16)(P1ptr), X1 // X1H
+ XXPERMDI X0, X0, $2, X0
+ XXPERMDI X1, X1, $2, X1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, U1L // SAVE: U1L
+ VOR T1, T1, U1H // SAVE: U1H
+
+ // SUB(H<H-T) // H = H-U1
+ p256SubInternal(HH,HL,HH,HL,T1,T0)
+
+ // if H == 0 or H^P == 0 then ret=1 else ret=0
+ // clobbers T1H and T1L
+ MOVD $1, TRUE
+ VSPLTISB $0, ZER
+ VOR HL, HH, T1H
+ VCMPEQUDCC ZER, T1H, T1H
+
+ // 26 = CR6 NE
+ ISEL $26, R0, TRUE, RES1
+ VXOR HL, PL, T1L // SAVE: T1L
+ VXOR HH, PH, T1H // SAVE: T1H
+ VOR T1L, T1H, T1H
+ VCMPEQUDCC ZER, T1H, T1H
+
+ // 26 = CR6 NE
+ ISEL $26, R0, TRUE, RES2
+ OR RES2, RES1, RES1
+ MOVD RES1, ret+24(FP)
+
+ // X=Z1; Y=Z2; MUL; T- // Z3 = Z1*Z2
+ MOVD in1+8(FP), P1ptr
+ MOVD in2+16(FP), P2ptr
+ LXVD2X (R19)(P1ptr), X0 // Z1L
+ LXVD2X (R20)(P1ptr), X1 // Z1H
+ XXPERMDI X0, X0, $2, X0
+ XXPERMDI X1, X1, $2, X1
+ LXVD2X (R19)(P2ptr), Y0 // Z2L
+ LXVD2X (R20)(P2ptr), Y1 // Z2H
+ XXPERMDI Y0, Y0, $2, Y0
+ XXPERMDI Y1, Y1, $2, Y1
+ CALL p256MulInternal<>(SB)
+
+ // X=T ; Y=H ; MUL; Z3:=T// Z3 = Z3*H
+ VOR T0, T0, X0
+ VOR T1, T1, X1
+ VOR HL, HL, Y0
+ VOR HH, HH, Y1
+ CALL p256MulInternal<>(SB)
+ MOVD res+0(FP), P3ptr
+ XXPERMDI T1, T1, $2, TT1
+ XXPERMDI T0, T0, $2, TT0
+ STXVD2X TT0, (R19)(P3ptr)
+ STXVD2X TT1, (R20)(P3ptr)
+
+ // X=Y1; Y=S1; MUL; S1=T // S1 = Y1*S1
+ MOVD in1+8(FP), P1ptr
+ LXVD2X (R17)(P1ptr), X0
+ LXVD2X (R18)(P1ptr), X1
+ XXPERMDI X0, X0, $2, X0
+ XXPERMDI X1, X1, $2, X1
+ VOR S1L, S1L, Y0
+ VOR S1H, S1H, Y1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, S1L
+ VOR T1, T1, S1H
+
+ // X=Y2; Y=R ; MUL; T- // R = Y2*R
+ MOVD in2+16(FP), P2ptr
+ LXVD2X (R17)(P2ptr), X0
+ LXVD2X (R18)(P2ptr), X1
+ XXPERMDI X0, X0, $2, X0
+ XXPERMDI X1, X1, $2, X1
+ VOR RL, RL, Y0
+
+ // VOR RH, RH, Y1 RH was saved above in D2X format
+ LXVD2X (R1)(R17), Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(R<T-S1) // R = T-S1
+ p256SubInternal(RH,RL,T1,T0,S1H,S1L)
+
+ STXVD2X RH, (R1)(R17) // Save RH
+
+ // if R == 0 or R^P == 0 then ret=ret else ret=0
+ // clobbers T1H and T1L
+ // Redo this using ISEL??
+ MOVD $1, TRUE
+ VSPLTISB $0, ZER
+ VOR RL, RH, T1H
+ VCMPEQUDCC ZER, T1H, T1H
+
+ // 24 = CR6 NE
+ ISEL $26, R0, TRUE, RES1
+ VXOR RL, PL, T1L
+ VXOR RH, PH, T1H // SAVE: T1L
+ VOR T1L, T1H, T1H
+ VCMPEQUDCC ZER, T1H, T1H
+
+ // 26 = CR6 NE
+ ISEL $26, R0, TRUE, RES2
+ OR RES2, RES1, RES1
+ MOVD ret+24(FP), RES2
+ AND RES2, RES1, RES1
+ MOVD RES1, ret+24(FP)
+
+ // X=H ; Y=H ; MUL; T- // T1 = H*H
+ VOR HL, HL, X0
+ VOR HH, HH, X1
+ VOR HL, HL, Y0
+ VOR HH, HH, Y1
+ CALL p256MulInternal<>(SB)
+
+ // X- ; Y=T ; MUL; T2=T // T2 = H*T1
+ VOR T0, T0, Y0
+ VOR T1, T1, Y1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, T2L
+ VOR T1, T1, T2H
+
+ // X=U1; Y- ; MUL; U1=T // U1 = U1*T1
+ VOR U1L, U1L, X0
+ VOR U1H, U1H, X1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, U1L
+ VOR T1, T1, U1H
+
+ // X=R ; Y=R ; MUL; T- // X3 = R*R
+ VOR RL, RL, X0
+
+ // VOR RH, RH, X1
+ VOR RL, RL, Y0
+
+ // RH was saved above using STXVD2X
+ LXVD2X (R1)(R17), X1
+ VOR X1, X1, Y1
+
+ // VOR RH, RH, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(T<T-T2) // X3 = X3-T2
+ p256SubInternal(T1,T0,T1,T0,T2H,T2L)
+
+ // ADD(X<U1+U1) // T1 = 2*U1
+ p256AddInternal(X1,X0,U1H,U1L,U1H,U1L)
+
+ // SUB(T<T-X) X3:=T // X3 = X3-T1 << store-out X3 result reg
+ p256SubInternal(T1,T0,T1,T0,X1,X0)
+ MOVD res+0(FP), P3ptr
+ XXPERMDI T1, T1, $2, TT1
+ XXPERMDI T0, T0, $2, TT0
+ STXVD2X TT0, (R0)(P3ptr)
+ STXVD2X TT1, (R16)(P3ptr)
+
+ // SUB(Y<U1-T) // Y3 = U1-X3
+ p256SubInternal(Y1,Y0,U1H,U1L,T1,T0)
+
+ // X=R ; Y- ; MUL; U1=T // Y3 = R*Y3
+ VOR RL, RL, X0
+
+ // VOR RH, RH, X1
+ LXVD2X (R1)(R17), X1
+ CALL p256MulInternal<>(SB)
+ VOR T0, T0, U1L
+ VOR T1, T1, U1H
+
+ // X=S1; Y=T2; MUL; T- // T2 = S1*T2
+ VOR S1L, S1L, X0
+ VOR S1H, S1H, X1
+ VOR T2L, T2L, Y0
+ VOR T2H, T2H, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(T<U1-T); Y3:=T // Y3 = Y3-T2 << store-out Y3 result reg
+ p256SubInternal(T1,T0,U1H,U1L,T1,T0)
+ MOVD res+0(FP), P3ptr
+ XXPERMDI T1, T1, $2, TT1
+ XXPERMDI T0, T0, $2, TT0
+ STXVD2X TT0, (R17)(P3ptr)
+ STXVD2X TT1, (R18)(P3ptr)
+
+ RET
diff --git a/src/crypto/internal/nistec/p256_asm_s390x.s b/src/crypto/internal/nistec/p256_asm_s390x.s
new file mode 100644
index 0000000..8da4f3f
--- /dev/null
+++ b/src/crypto/internal/nistec/p256_asm_s390x.s
@@ -0,0 +1,2418 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+#include "go_asm.h"
+
+DATA p256ordK0<>+0x00(SB)/4, $0xee00bc4f
+DATA p256ord<>+0x00(SB)/8, $0xffffffff00000000
+DATA p256ord<>+0x08(SB)/8, $0xffffffffffffffff
+DATA p256ord<>+0x10(SB)/8, $0xbce6faada7179e84
+DATA p256ord<>+0x18(SB)/8, $0xf3b9cac2fc632551
+DATA p256<>+0x00(SB)/8, $0xffffffff00000001 // P256
+DATA p256<>+0x08(SB)/8, $0x0000000000000000 // P256
+DATA p256<>+0x10(SB)/8, $0x00000000ffffffff // P256
+DATA p256<>+0x18(SB)/8, $0xffffffffffffffff // P256
+DATA p256<>+0x20(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256<>+0x28(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256<>+0x30(SB)/8, $0x0000000010111213 // SEL 0 d1 d0 0
+DATA p256<>+0x38(SB)/8, $0x1415161700000000 // SEL 0 d1 d0 0
+DATA p256<>+0x40(SB)/8, $0x18191a1b1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256<>+0x48(SB)/8, $0x18191a1b1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256<>+0x50(SB)/8, $0x0706050403020100 // LE2BE permute mask
+DATA p256<>+0x58(SB)/8, $0x0f0e0d0c0b0a0908 // LE2BE permute mask
+DATA p256mul<>+0x00(SB)/8, $0xffffffff00000001 // P256
+DATA p256mul<>+0x08(SB)/8, $0x0000000000000000 // P256
+DATA p256mul<>+0x10(SB)/8, $0x00000000ffffffff // P256
+DATA p256mul<>+0x18(SB)/8, $0xffffffffffffffff // P256
+DATA p256mul<>+0x20(SB)/8, $0x1c1d1e1f00000000 // SEL d0 0 0 d0
+DATA p256mul<>+0x28(SB)/8, $0x000000001c1d1e1f // SEL d0 0 0 d0
+DATA p256mul<>+0x30(SB)/8, $0x0001020304050607 // SEL d0 0 d1 d0
+DATA p256mul<>+0x38(SB)/8, $0x1c1d1e1f0c0d0e0f // SEL d0 0 d1 d0
+DATA p256mul<>+0x40(SB)/8, $0x040506071c1d1e1f // SEL 0 d1 d0 d1
+DATA p256mul<>+0x48(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL 0 d1 d0 d1
+DATA p256mul<>+0x50(SB)/8, $0x0405060704050607 // SEL 0 0 d1 d0
+DATA p256mul<>+0x58(SB)/8, $0x1c1d1e1f0c0d0e0f // SEL 0 0 d1 d0
+DATA p256mul<>+0x60(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256mul<>+0x68(SB)/8, $0x0c0d0e0f1c1d1e1f // SEL d1 d0 d1 d0
+DATA p256mul<>+0x70(SB)/8, $0x141516170c0d0e0f // SEL 0 d1 d0 0
+DATA p256mul<>+0x78(SB)/8, $0x1c1d1e1f14151617 // SEL 0 d1 d0 0
+DATA p256mul<>+0x80(SB)/8, $0x00000000fffffffe // (1*2^256)%P256
+DATA p256mul<>+0x88(SB)/8, $0xffffffffffffffff // (1*2^256)%P256
+DATA p256mul<>+0x90(SB)/8, $0xffffffff00000000 // (1*2^256)%P256
+DATA p256mul<>+0x98(SB)/8, $0x0000000000000001 // (1*2^256)%P256
+GLOBL p256ordK0<>(SB), 8, $4
+GLOBL p256ord<>(SB), 8, $32
+GLOBL p256<>(SB), 8, $96
+GLOBL p256mul<>(SB), 8, $160
+
+// func p256OrdLittleToBig(res *[32]byte, in *p256OrdElement)
+TEXT ·p256OrdLittleToBig(SB), NOSPLIT, $0
+ JMP ·p256BigToLittle(SB)
+
+// func p256OrdBigToLittle(res *p256OrdElement, in *[32]byte)
+TEXT ·p256OrdBigToLittle(SB), NOSPLIT, $0
+ JMP ·p256BigToLittle(SB)
+
+// ---------------------------------------
+// func p256LittleToBig(res *[32]byte, in *p256Element)
+TEXT ·p256LittleToBig(SB), NOSPLIT, $0
+ JMP ·p256BigToLittle(SB)
+
+// func p256BigToLittle(res *p256Element, in *[32]byte)
+#define res_ptr R1
+#define in_ptr R2
+#define T1L V2
+#define T1H V3
+
+TEXT ·p256BigToLittle(SB), NOSPLIT, $0
+ MOVD res+0(FP), res_ptr
+ MOVD in+8(FP), in_ptr
+
+ VL 0(in_ptr), T1H
+ VL 16(in_ptr), T1L
+
+ VPDI $0x4, T1L, T1L, T1L
+ VPDI $0x4, T1H, T1H, T1H
+
+ VST T1L, 0(res_ptr)
+ VST T1H, 16(res_ptr)
+ RET
+
+#undef res_ptr
+#undef in_ptr
+#undef T1L
+#undef T1H
+
+// ---------------------------------------
+// iff cond == 1 val <- -val
+// func p256NegCond(val *p256Element, cond int)
+#define P1ptr R1
+#define CPOOL R4
+
+#define Y1L V0
+#define Y1H V1
+#define T1L V2
+#define T1H V3
+
+#define PL V30
+#define PH V31
+
+#define ZER V4
+#define SEL1 V5
+#define CAR1 V6
+TEXT ·p256NegCond(SB), NOSPLIT, $0
+ MOVD val+0(FP), P1ptr
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+ VL 16(CPOOL), PL
+ VL 0(CPOOL), PH
+
+ VL 16(P1ptr), Y1H
+ VPDI $0x4, Y1H, Y1H, Y1H
+ VL 0(P1ptr), Y1L
+ VPDI $0x4, Y1L, Y1L, Y1L
+
+ VLREPG cond+8(FP), SEL1
+ VZERO ZER
+ VCEQG SEL1, ZER, SEL1
+
+ VSCBIQ Y1L, PL, CAR1
+ VSQ Y1L, PL, T1L
+ VSBIQ PH, Y1H, CAR1, T1H
+
+ VSEL Y1L, T1L, SEL1, Y1L
+ VSEL Y1H, T1H, SEL1, Y1H
+
+ VPDI $0x4, Y1H, Y1H, Y1H
+ VST Y1H, 16(P1ptr)
+ VPDI $0x4, Y1L, Y1L, Y1L
+ VST Y1L, 0(P1ptr)
+ RET
+
+#undef P1ptr
+#undef CPOOL
+#undef Y1L
+#undef Y1H
+#undef T1L
+#undef T1H
+#undef PL
+#undef PH
+#undef ZER
+#undef SEL1
+#undef CAR1
+
+// ---------------------------------------
+// if cond == 0 res <- b; else res <- a
+// func p256MovCond(res, a, b *P256Point, cond int)
+#define P3ptr R1
+#define P1ptr R2
+#define P2ptr R3
+
+#define X1L V0
+#define X1H V1
+#define Y1L V2
+#define Y1H V3
+#define Z1L V4
+#define Z1H V5
+#define X2L V6
+#define X2H V7
+#define Y2L V8
+#define Y2H V9
+#define Z2L V10
+#define Z2H V11
+
+#define ZER V18
+#define SEL1 V19
+TEXT ·p256MovCond(SB), NOSPLIT, $0
+ MOVD res+0(FP), P3ptr
+ MOVD a+8(FP), P1ptr
+ MOVD b+16(FP), P2ptr
+ VLREPG cond+24(FP), SEL1
+ VZERO ZER
+ VCEQG SEL1, ZER, SEL1
+
+ VL 0(P1ptr), X1H
+ VL 16(P1ptr), X1L
+ VL 32(P1ptr), Y1H
+ VL 48(P1ptr), Y1L
+ VL 64(P1ptr), Z1H
+ VL 80(P1ptr), Z1L
+
+ VL 0(P2ptr), X2H
+ VL 16(P2ptr), X2L
+ VL 32(P2ptr), Y2H
+ VL 48(P2ptr), Y2L
+ VL 64(P2ptr), Z2H
+ VL 80(P2ptr), Z2L
+
+ VSEL X2L, X1L, SEL1, X1L
+ VSEL X2H, X1H, SEL1, X1H
+ VSEL Y2L, Y1L, SEL1, Y1L
+ VSEL Y2H, Y1H, SEL1, Y1H
+ VSEL Z2L, Z1L, SEL1, Z1L
+ VSEL Z2H, Z1H, SEL1, Z1H
+
+ VST X1H, 0(P3ptr)
+ VST X1L, 16(P3ptr)
+ VST Y1H, 32(P3ptr)
+ VST Y1L, 48(P3ptr)
+ VST Z1H, 64(P3ptr)
+ VST Z1L, 80(P3ptr)
+
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef P2ptr
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef X2L
+#undef X2H
+#undef Y2L
+#undef Y2H
+#undef Z2L
+#undef Z2H
+#undef ZER
+#undef SEL1
+
+// ---------------------------------------
+// Constant time table access
+// Indexed from 1 to 15, with -1 offset
+// (index 0 is implicitly point at infinity)
+// func p256Select(res *P256Point, table *p256Table, idx int)
+#define P3ptr R1
+#define P1ptr R2
+#define COUNT R4
+
+#define X1L V0
+#define X1H V1
+#define Y1L V2
+#define Y1H V3
+#define Z1L V4
+#define Z1H V5
+#define X2L V6
+#define X2H V7
+#define Y2L V8
+#define Y2H V9
+#define Z2L V10
+#define Z2H V11
+
+#define ONE V18
+#define IDX V19
+#define SEL1 V20
+#define SEL2 V21
+TEXT ·p256Select(SB), NOSPLIT, $0
+ MOVD res+0(FP), P3ptr
+ MOVD table+8(FP), P1ptr
+ VLREPB idx+(16+7)(FP), IDX
+ VREPIB $1, ONE
+ VREPIB $1, SEL2
+ MOVD $1, COUNT
+
+ VZERO X1H
+ VZERO X1L
+ VZERO Y1H
+ VZERO Y1L
+ VZERO Z1H
+ VZERO Z1L
+
+loop_select:
+ VL 0(P1ptr), X2H
+ VL 16(P1ptr), X2L
+ VL 32(P1ptr), Y2H
+ VL 48(P1ptr), Y2L
+ VL 64(P1ptr), Z2H
+ VL 80(P1ptr), Z2L
+
+ VCEQG SEL2, IDX, SEL1
+
+ VSEL X2L, X1L, SEL1, X1L
+ VSEL X2H, X1H, SEL1, X1H
+ VSEL Y2L, Y1L, SEL1, Y1L
+ VSEL Y2H, Y1H, SEL1, Y1H
+ VSEL Z2L, Z1L, SEL1, Z1L
+ VSEL Z2H, Z1H, SEL1, Z1H
+
+ VAB SEL2, ONE, SEL2
+ ADDW $1, COUNT
+ ADD $96, P1ptr
+ CMPW COUNT, $17
+ BLT loop_select
+
+ VST X1H, 0(P3ptr)
+ VST X1L, 16(P3ptr)
+ VST Y1H, 32(P3ptr)
+ VST Y1L, 48(P3ptr)
+ VST Z1H, 64(P3ptr)
+ VST Z1L, 80(P3ptr)
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef COUNT
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef X2L
+#undef X2H
+#undef Y2L
+#undef Y2H
+#undef Z2L
+#undef Z2H
+#undef ONE
+#undef IDX
+#undef SEL1
+#undef SEL2
+
+// ---------------------------------------
+
+// func p256FromMont(res, in *p256Element)
+#define res_ptr R1
+#define x_ptr R2
+#define CPOOL R4
+
+#define T0 V0
+#define T1 V1
+#define T2 V2
+#define TT0 V3
+#define TT1 V4
+
+#define ZER V6
+#define SEL1 V7
+#define SEL2 V8
+#define CAR1 V9
+#define CAR2 V10
+#define RED1 V11
+#define RED2 V12
+#define PL V13
+#define PH V14
+
+TEXT ·p256FromMont(SB), NOSPLIT, $0
+ MOVD res+0(FP), res_ptr
+ MOVD in+8(FP), x_ptr
+
+ VZERO T2
+ VZERO ZER
+ MOVD $p256<>+0x00(SB), CPOOL
+ VL 16(CPOOL), PL
+ VL 0(CPOOL), PH
+ VL 48(CPOOL), SEL2
+ VL 64(CPOOL), SEL1
+
+ VL (0*16)(x_ptr), T0
+ VPDI $0x4, T0, T0, T0
+ VL (1*16)(x_ptr), T1
+ VPDI $0x4, T1, T1, T1
+
+ // First round
+ VPERM T1, T0, SEL1, RED2 // d1 d0 d1 d0
+ VPERM ZER, RED2, SEL2, RED1 // 0 d1 d0 0
+ VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDB $8, T1, T0, T0
+ VSLDB $8, T2, T1, T1
+
+ VACCQ T0, RED1, CAR1
+ VAQ T0, RED1, T0
+ VACCCQ T1, RED2, CAR1, CAR2
+ VACQ T1, RED2, CAR1, T1
+ VAQ T2, CAR2, T2
+
+ // Second round
+ VPERM T1, T0, SEL1, RED2 // d1 d0 d1 d0
+ VPERM ZER, RED2, SEL2, RED1 // 0 d1 d0 0
+ VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDB $8, T1, T0, T0
+ VSLDB $8, T2, T1, T1
+
+ VACCQ T0, RED1, CAR1
+ VAQ T0, RED1, T0
+ VACCCQ T1, RED2, CAR1, CAR2
+ VACQ T1, RED2, CAR1, T1
+ VAQ T2, CAR2, T2
+
+ // Third round
+ VPERM T1, T0, SEL1, RED2 // d1 d0 d1 d0
+ VPERM ZER, RED2, SEL2, RED1 // 0 d1 d0 0
+ VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDB $8, T1, T0, T0
+ VSLDB $8, T2, T1, T1
+
+ VACCQ T0, RED1, CAR1
+ VAQ T0, RED1, T0
+ VACCCQ T1, RED2, CAR1, CAR2
+ VACQ T1, RED2, CAR1, T1
+ VAQ T2, CAR2, T2
+
+ // Last round
+ VPERM T1, T0, SEL1, RED2 // d1 d0 d1 d0
+ VPERM ZER, RED2, SEL2, RED1 // 0 d1 d0 0
+ VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDB $8, T1, T0, T0
+ VSLDB $8, T2, T1, T1
+
+ VACCQ T0, RED1, CAR1
+ VAQ T0, RED1, T0
+ VACCCQ T1, RED2, CAR1, CAR2
+ VACQ T1, RED2, CAR1, T1
+ VAQ T2, CAR2, T2
+
+ // ---------------------------------------------------
+
+ VSCBIQ PL, T0, CAR1
+ VSQ PL, T0, TT0
+ VSBCBIQ T1, PH, CAR1, CAR2
+ VSBIQ T1, PH, CAR1, TT1
+ VSBIQ T2, ZER, CAR2, T2
+
+ // what output to use, TT1||TT0 or T1||T0?
+ VSEL T0, TT0, T2, T0
+ VSEL T1, TT1, T2, T1
+
+ VPDI $0x4, T0, T0, TT0
+ VST TT0, (0*16)(res_ptr)
+ VPDI $0x4, T1, T1, TT1
+ VST TT1, (1*16)(res_ptr)
+ RET
+
+#undef res_ptr
+#undef x_ptr
+#undef CPOOL
+#undef T0
+#undef T1
+#undef T2
+#undef TT0
+#undef TT1
+#undef ZER
+#undef SEL1
+#undef SEL2
+#undef CAR1
+#undef CAR2
+#undef RED1
+#undef RED2
+#undef PL
+#undef PH
+
+// Constant time table access
+// Indexed from 1 to 15, with -1 offset
+// (index 0 is implicitly point at infinity)
+// func p256SelectBase(point *p256Point, table []p256Point, idx int)
+// new : func p256SelectAffine(res *p256AffinePoint, table *p256AffineTable, idx int)
+
+#define P3ptr R1
+#define P1ptr R2
+#define COUNT R4
+#define CPOOL R5
+
+#define X1L V0
+#define X1H V1
+#define Y1L V2
+#define Y1H V3
+#define Z1L V4
+#define Z1H V5
+#define X2L V6
+#define X2H V7
+#define Y2L V8
+#define Y2H V9
+#define Z2L V10
+#define Z2H V11
+#define LE2BE V12
+
+#define ONE V18
+#define IDX V19
+#define SEL1 V20
+#define SEL2 V21
+
+TEXT ·p256SelectAffine(SB), NOSPLIT, $0
+ MOVD res+0(FP), P3ptr
+ MOVD table+8(FP), P1ptr
+ MOVD $p256<>+0x00(SB), CPOOL
+ VLREPB idx+(16+7)(FP), IDX
+ VREPIB $1, ONE
+ VREPIB $1, SEL2
+ MOVD $1, COUNT
+ VL 80(CPOOL), LE2BE
+
+ VZERO X1H
+ VZERO X1L
+ VZERO Y1H
+ VZERO Y1L
+
+loop_select:
+ VL 0(P1ptr), X2H
+ VL 16(P1ptr), X2L
+ VL 32(P1ptr), Y2H
+ VL 48(P1ptr), Y2L
+
+ VCEQG SEL2, IDX, SEL1
+
+ VSEL X2L, X1L, SEL1, X1L
+ VSEL X2H, X1H, SEL1, X1H
+ VSEL Y2L, Y1L, SEL1, Y1L
+ VSEL Y2H, Y1H, SEL1, Y1H
+
+ VAB SEL2, ONE, SEL2
+ ADDW $1, COUNT
+ ADD $64, P1ptr
+ CMPW COUNT, $65
+ BLT loop_select
+ VST X1H, 0(P3ptr)
+ VST X1L, 16(P3ptr)
+ VST Y1H, 32(P3ptr)
+ VST Y1L, 48(P3ptr)
+
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef COUNT
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef X2L
+#undef X2H
+#undef Y2L
+#undef Y2H
+#undef Z2L
+#undef Z2H
+#undef ONE
+#undef IDX
+#undef SEL1
+#undef SEL2
+#undef CPOOL
+
+// ---------------------------------------
+
+// func p256OrdMul(res, in1, in2 *p256OrdElement)
+#define res_ptr R1
+#define x_ptr R2
+#define y_ptr R3
+#define X0 V0
+#define X1 V1
+#define Y0 V2
+#define Y1 V3
+#define M0 V4
+#define M1 V5
+#define T0 V6
+#define T1 V7
+#define T2 V8
+#define YDIG V9
+
+#define ADD1 V16
+#define ADD1H V17
+#define ADD2 V18
+#define ADD2H V19
+#define RED1 V20
+#define RED1H V21
+#define RED2 V22
+#define RED2H V23
+#define CAR1 V24
+#define CAR1M V25
+
+#define MK0 V30
+#define K0 V31
+TEXT ·p256OrdMul<>(SB), NOSPLIT, $0
+ MOVD res+0(FP), res_ptr
+ MOVD in1+8(FP), x_ptr
+ MOVD in2+16(FP), y_ptr
+
+ VZERO T2
+ MOVD $p256ordK0<>+0x00(SB), R4
+
+ // VLEF $3, 0(R4), K0
+ WORD $0xE7F40000
+ BYTE $0x38
+ BYTE $0x03
+ MOVD $p256ord<>+0x00(SB), R4
+ VL 16(R4), M0
+ VL 0(R4), M1
+
+ VL (0*16)(x_ptr), X0
+ VPDI $0x4, X0, X0, X0
+ VL (1*16)(x_ptr), X1
+ VPDI $0x4, X1, X1, X1
+ VL (0*16)(y_ptr), Y0
+ VPDI $0x4, Y0, Y0, Y0
+ VL (1*16)(y_ptr), Y1
+ VPDI $0x4, Y1, Y1, Y1
+
+ // ---------------------------------------------------------------------------/
+ VREPF $3, Y0, YDIG
+ VMLF X0, YDIG, ADD1
+ VMLF ADD1, K0, MK0
+ VREPF $3, MK0, MK0
+
+ VMLF X1, YDIG, ADD2
+ VMLHF X0, YDIG, ADD1H
+ VMLHF X1, YDIG, ADD2H
+
+ VMALF M0, MK0, ADD1, RED1
+ VMALHF M0, MK0, ADD1, RED1H
+ VMALF M1, MK0, ADD2, RED2
+ VMALHF M1, MK0, ADD2, RED2H
+
+ VSLDB $12, RED2, RED1, RED1
+ VSLDB $12, T2, RED2, RED2
+
+ VACCQ RED1, ADD1H, CAR1
+ VAQ RED1, ADD1H, T0
+ VACCQ RED1H, T0, CAR1M
+ VAQ RED1H, T0, T0
+
+ // << ready for next MK0
+
+ VACQ RED2, ADD2H, CAR1, T1
+ VACCCQ RED2, ADD2H, CAR1, CAR1
+ VACCCQ RED2H, T1, CAR1M, T2
+ VACQ RED2H, T1, CAR1M, T1
+ VAQ CAR1, T2, T2
+
+ // ---------------------------------------------------
+/* *
+ * ---+--------+--------+
+ * T2| T1 | T0 |
+ * ---+--------+--------+
+ * *(add)*
+ * +--------+--------+
+ * | X1 | X0 |
+ * +--------+--------+
+ * *(mul)*
+ * +--------+--------+
+ * | YDIG | YDIG |
+ * +--------+--------+
+ * *(add)*
+ * +--------+--------+
+ * | M1 | M0 |
+ * +--------+--------+
+ * *(mul)*
+ * +--------+--------+
+ * | MK0 | MK0 |
+ * +--------+--------+
+ *
+ * ---------------------
+ *
+ * +--------+--------+
+ * | ADD2 | ADD1 |
+ * +--------+--------+
+ * +--------+--------+
+ * | ADD2H | ADD1H |
+ * +--------+--------+
+ * +--------+--------+
+ * | RED2 | RED1 |
+ * +--------+--------+
+ * +--------+--------+
+ * | RED2H | RED1H |
+ * +--------+--------+
+ */
+ VREPF $2, Y0, YDIG
+ VMALF X0, YDIG, T0, ADD1
+ VMLF ADD1, K0, MK0
+ VREPF $3, MK0, MK0
+
+ VMALF X1, YDIG, T1, ADD2
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+
+ VMALF M0, MK0, ADD1, RED1
+ VMALHF M0, MK0, ADD1, RED1H
+ VMALF M1, MK0, ADD2, RED2
+ VMALHF M1, MK0, ADD2, RED2H
+
+ VSLDB $12, RED2, RED1, RED1
+ VSLDB $12, T2, RED2, RED2
+
+ VACCQ RED1, ADD1H, CAR1
+ VAQ RED1, ADD1H, T0
+ VACCQ RED1H, T0, CAR1M
+ VAQ RED1H, T0, T0
+
+ // << ready for next MK0
+
+ VACQ RED2, ADD2H, CAR1, T1
+ VACCCQ RED2, ADD2H, CAR1, CAR1
+ VACCCQ RED2H, T1, CAR1M, T2
+ VACQ RED2H, T1, CAR1M, T1
+ VAQ CAR1, T2, T2
+
+ // ---------------------------------------------------
+ VREPF $1, Y0, YDIG
+ VMALF X0, YDIG, T0, ADD1
+ VMLF ADD1, K0, MK0
+ VREPF $3, MK0, MK0
+
+ VMALF X1, YDIG, T1, ADD2
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+
+ VMALF M0, MK0, ADD1, RED1
+ VMALHF M0, MK0, ADD1, RED1H
+ VMALF M1, MK0, ADD2, RED2
+ VMALHF M1, MK0, ADD2, RED2H
+
+ VSLDB $12, RED2, RED1, RED1
+ VSLDB $12, T2, RED2, RED2
+
+ VACCQ RED1, ADD1H, CAR1
+ VAQ RED1, ADD1H, T0
+ VACCQ RED1H, T0, CAR1M
+ VAQ RED1H, T0, T0
+
+ // << ready for next MK0
+
+ VACQ RED2, ADD2H, CAR1, T1
+ VACCCQ RED2, ADD2H, CAR1, CAR1
+ VACCCQ RED2H, T1, CAR1M, T2
+ VACQ RED2H, T1, CAR1M, T1
+ VAQ CAR1, T2, T2
+
+ // ---------------------------------------------------
+ VREPF $0, Y0, YDIG
+ VMALF X0, YDIG, T0, ADD1
+ VMLF ADD1, K0, MK0
+ VREPF $3, MK0, MK0
+
+ VMALF X1, YDIG, T1, ADD2
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+
+ VMALF M0, MK0, ADD1, RED1
+ VMALHF M0, MK0, ADD1, RED1H
+ VMALF M1, MK0, ADD2, RED2
+ VMALHF M1, MK0, ADD2, RED2H
+
+ VSLDB $12, RED2, RED1, RED1
+ VSLDB $12, T2, RED2, RED2
+
+ VACCQ RED1, ADD1H, CAR1
+ VAQ RED1, ADD1H, T0
+ VACCQ RED1H, T0, CAR1M
+ VAQ RED1H, T0, T0
+
+ // << ready for next MK0
+
+ VACQ RED2, ADD2H, CAR1, T1
+ VACCCQ RED2, ADD2H, CAR1, CAR1
+ VACCCQ RED2H, T1, CAR1M, T2
+ VACQ RED2H, T1, CAR1M, T1
+ VAQ CAR1, T2, T2
+
+ // ---------------------------------------------------
+ VREPF $3, Y1, YDIG
+ VMALF X0, YDIG, T0, ADD1
+ VMLF ADD1, K0, MK0
+ VREPF $3, MK0, MK0
+
+ VMALF X1, YDIG, T1, ADD2
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+
+ VMALF M0, MK0, ADD1, RED1
+ VMALHF M0, MK0, ADD1, RED1H
+ VMALF M1, MK0, ADD2, RED2
+ VMALHF M1, MK0, ADD2, RED2H
+
+ VSLDB $12, RED2, RED1, RED1
+ VSLDB $12, T2, RED2, RED2
+
+ VACCQ RED1, ADD1H, CAR1
+ VAQ RED1, ADD1H, T0
+ VACCQ RED1H, T0, CAR1M
+ VAQ RED1H, T0, T0
+
+ // << ready for next MK0
+
+ VACQ RED2, ADD2H, CAR1, T1
+ VACCCQ RED2, ADD2H, CAR1, CAR1
+ VACCCQ RED2H, T1, CAR1M, T2
+ VACQ RED2H, T1, CAR1M, T1
+ VAQ CAR1, T2, T2
+
+ // ---------------------------------------------------
+ VREPF $2, Y1, YDIG
+ VMALF X0, YDIG, T0, ADD1
+ VMLF ADD1, K0, MK0
+ VREPF $3, MK0, MK0
+
+ VMALF X1, YDIG, T1, ADD2
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+
+ VMALF M0, MK0, ADD1, RED1
+ VMALHF M0, MK0, ADD1, RED1H
+ VMALF M1, MK0, ADD2, RED2
+ VMALHF M1, MK0, ADD2, RED2H
+
+ VSLDB $12, RED2, RED1, RED1
+ VSLDB $12, T2, RED2, RED2
+
+ VACCQ RED1, ADD1H, CAR1
+ VAQ RED1, ADD1H, T0
+ VACCQ RED1H, T0, CAR1M
+ VAQ RED1H, T0, T0
+
+ // << ready for next MK0
+
+ VACQ RED2, ADD2H, CAR1, T1
+ VACCCQ RED2, ADD2H, CAR1, CAR1
+ VACCCQ RED2H, T1, CAR1M, T2
+ VACQ RED2H, T1, CAR1M, T1
+ VAQ CAR1, T2, T2
+
+ // ---------------------------------------------------
+ VREPF $1, Y1, YDIG
+ VMALF X0, YDIG, T0, ADD1
+ VMLF ADD1, K0, MK0
+ VREPF $3, MK0, MK0
+
+ VMALF X1, YDIG, T1, ADD2
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+
+ VMALF M0, MK0, ADD1, RED1
+ VMALHF M0, MK0, ADD1, RED1H
+ VMALF M1, MK0, ADD2, RED2
+ VMALHF M1, MK0, ADD2, RED2H
+
+ VSLDB $12, RED2, RED1, RED1
+ VSLDB $12, T2, RED2, RED2
+
+ VACCQ RED1, ADD1H, CAR1
+ VAQ RED1, ADD1H, T0
+ VACCQ RED1H, T0, CAR1M
+ VAQ RED1H, T0, T0
+
+ // << ready for next MK0
+
+ VACQ RED2, ADD2H, CAR1, T1
+ VACCCQ RED2, ADD2H, CAR1, CAR1
+ VACCCQ RED2H, T1, CAR1M, T2
+ VACQ RED2H, T1, CAR1M, T1
+ VAQ CAR1, T2, T2
+
+ // ---------------------------------------------------
+ VREPF $0, Y1, YDIG
+ VMALF X0, YDIG, T0, ADD1
+ VMLF ADD1, K0, MK0
+ VREPF $3, MK0, MK0
+
+ VMALF X1, YDIG, T1, ADD2
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+
+ VMALF M0, MK0, ADD1, RED1
+ VMALHF M0, MK0, ADD1, RED1H
+ VMALF M1, MK0, ADD2, RED2
+ VMALHF M1, MK0, ADD2, RED2H
+
+ VSLDB $12, RED2, RED1, RED1
+ VSLDB $12, T2, RED2, RED2
+
+ VACCQ RED1, ADD1H, CAR1
+ VAQ RED1, ADD1H, T0
+ VACCQ RED1H, T0, CAR1M
+ VAQ RED1H, T0, T0
+
+ // << ready for next MK0
+
+ VACQ RED2, ADD2H, CAR1, T1
+ VACCCQ RED2, ADD2H, CAR1, CAR1
+ VACCCQ RED2H, T1, CAR1M, T2
+ VACQ RED2H, T1, CAR1M, T1
+ VAQ CAR1, T2, T2
+
+ // ---------------------------------------------------
+
+ VZERO RED1
+ VSCBIQ M0, T0, CAR1
+ VSQ M0, T0, ADD1
+ VSBCBIQ T1, M1, CAR1, CAR1M
+ VSBIQ T1, M1, CAR1, ADD2
+ VSBIQ T2, RED1, CAR1M, T2
+
+ // what output to use, ADD2||ADD1 or T1||T0?
+ VSEL T0, ADD1, T2, T0
+ VSEL T1, ADD2, T2, T1
+
+ VPDI $0x4, T0, T0, T0
+ VST T0, (0*16)(res_ptr)
+ VPDI $0x4, T1, T1, T1
+ VST T1, (1*16)(res_ptr)
+ RET
+
+#undef res_ptr
+#undef x_ptr
+#undef y_ptr
+#undef X0
+#undef X1
+#undef Y0
+#undef Y1
+#undef M0
+#undef M1
+#undef T0
+#undef T1
+#undef T2
+#undef YDIG
+
+#undef ADD1
+#undef ADD1H
+#undef ADD2
+#undef ADD2H
+#undef RED1
+#undef RED1H
+#undef RED2
+#undef RED2H
+#undef CAR1
+#undef CAR1M
+
+#undef MK0
+#undef K0
+
+// ---------------------------------------
+// p256MulInternal
+// V0-V3,V30,V31 - Not Modified
+// V4-V15 - Volatile
+
+#define CPOOL R4
+
+// Parameters
+#define X0 V0 // Not modified
+#define X1 V1 // Not modified
+#define Y0 V2 // Not modified
+#define Y1 V3 // Not modified
+#define T0 V4
+#define T1 V5
+#define P0 V30 // Not modified
+#define P1 V31 // Not modified
+
+// Temporaries
+#define YDIG V6 // Overloaded with CAR2, ZER
+#define ADD1H V7 // Overloaded with ADD3H
+#define ADD2H V8 // Overloaded with ADD4H
+#define ADD3 V9 // Overloaded with SEL2,SEL5
+#define ADD4 V10 // Overloaded with SEL3,SEL6
+#define RED1 V11 // Overloaded with CAR2
+#define RED2 V12
+#define RED3 V13 // Overloaded with SEL1
+#define T2 V14
+// Overloaded temporaries
+#define ADD1 V4 // Overloaded with T0
+#define ADD2 V5 // Overloaded with T1
+#define ADD3H V7 // Overloaded with ADD1H
+#define ADD4H V8 // Overloaded with ADD2H
+#define ZER V6 // Overloaded with YDIG, CAR2
+#define CAR1 V6 // Overloaded with YDIG, ZER
+#define CAR2 V11 // Overloaded with RED1
+// Constant Selects
+#define SEL1 V13 // Overloaded with RED3
+#define SEL2 V9 // Overloaded with ADD3,SEL5
+#define SEL3 V10 // Overloaded with ADD4,SEL6
+#define SEL4 V6 // Overloaded with YDIG,CAR2,ZER
+#define SEL5 V9 // Overloaded with ADD3,SEL2
+#define SEL6 V10 // Overloaded with ADD4,SEL3
+
+/* *
+ * To follow the flow of bits, for your own sanity a stiff drink, need you shall.
+ * Of a single round, a 'helpful' picture, here is. Meaning, column position has.
+ * With you, SIMD be...
+ *
+ * +--------+--------+
+ * +--------| RED2 | RED1 |
+ * | +--------+--------+
+ * | ---+--------+--------+
+ * | +---- T2| T1 | T0 |--+
+ * | | ---+--------+--------+ |
+ * | | |
+ * | | ======================= |
+ * | | |
+ * | | +--------+--------+<-+
+ * | +-------| ADD2 | ADD1 |--|-----+
+ * | | +--------+--------+ | |
+ * | | +--------+--------+<---+ |
+ * | | | ADD2H | ADD1H |--+ |
+ * | | +--------+--------+ | |
+ * | | +--------+--------+<-+ |
+ * | | | ADD4 | ADD3 |--|-+ |
+ * | | +--------+--------+ | | |
+ * | | +--------+--------+<---+ | |
+ * | | | ADD4H | ADD3H |------|-+ |(+vzero)
+ * | | +--------+--------+ | | V
+ * | | ------------------------ | | +--------+
+ * | | | | | RED3 | [d0 0 0 d0]
+ * | | | | +--------+
+ * | +---->+--------+--------+ | | |
+ * (T2[1w]||ADD2[4w]||ADD1[3w]) +--------| T1 | T0 | | | |
+ * | +--------+--------+ | | |
+ * +---->---+--------+--------+ | | |
+ * T2| T1 | T0 |----+ | |
+ * ---+--------+--------+ | | |
+ * ---+--------+--------+<---+ | |
+ * +--- T2| T1 | T0 |----------+
+ * | ---+--------+--------+ | |
+ * | +--------+--------+<-------------+
+ * | | RED2 | RED1 |-----+ | | [0 d1 d0 d1] [d0 0 d1 d0]
+ * | +--------+--------+ | | |
+ * | +--------+<----------------------+
+ * | | RED3 |--------------+ | [0 0 d1 d0]
+ * | +--------+ | |
+ * +--->+--------+--------+ | |
+ * | T1 | T0 |--------+
+ * +--------+--------+ | |
+ * --------------------------- | |
+ * | |
+ * +--------+--------+<----+ |
+ * | RED2 | RED1 | |
+ * +--------+--------+ |
+ * ---+--------+--------+<-------+
+ * T2| T1 | T0 | (H1P-H1P-H00RRAY!)
+ * ---+--------+--------+
+ *
+ * *Mi obra de arte de siglo XXI @vpaprots
+ *
+ *
+ * First group is special, doesn't get the two inputs:
+ * +--------+--------+<-+
+ * +-------| ADD2 | ADD1 |--|-----+
+ * | +--------+--------+ | |
+ * | +--------+--------+<---+ |
+ * | | ADD2H | ADD1H |--+ |
+ * | +--------+--------+ | |
+ * | +--------+--------+<-+ |
+ * | | ADD4 | ADD3 |--|-+ |
+ * | +--------+--------+ | | |
+ * | +--------+--------+<---+ | |
+ * | | ADD4H | ADD3H |------|-+ |(+vzero)
+ * | +--------+--------+ | | V
+ * | ------------------------ | | +--------+
+ * | | | | RED3 | [d0 0 0 d0]
+ * | | | +--------+
+ * +---->+--------+--------+ | | |
+ * (T2[1w]||ADD2[4w]||ADD1[3w]) | T1 | T0 |----+ | |
+ * +--------+--------+ | | |
+ * ---+--------+--------+<---+ | |
+ * +--- T2| T1 | T0 |----------+
+ * | ---+--------+--------+ | |
+ * | +--------+--------+<-------------+
+ * | | RED2 | RED1 |-----+ | | [0 d1 d0 d1] [d0 0 d1 d0]
+ * | +--------+--------+ | | |
+ * | +--------+<----------------------+
+ * | | RED3 |--------------+ | [0 0 d1 d0]
+ * | +--------+ | |
+ * +--->+--------+--------+ | |
+ * | T1 | T0 |--------+
+ * +--------+--------+ | |
+ * --------------------------- | |
+ * | |
+ * +--------+--------+<----+ |
+ * | RED2 | RED1 | |
+ * +--------+--------+ |
+ * ---+--------+--------+<-------+
+ * T2| T1 | T0 | (H1P-H1P-H00RRAY!)
+ * ---+--------+--------+
+ *
+ * Last 'group' needs to RED2||RED1 shifted less
+ */
+TEXT p256MulInternal<>(SB), NOSPLIT, $0-0
+ VL 32(CPOOL), SEL1
+ VL 48(CPOOL), SEL2
+ VL 64(CPOOL), SEL3
+ VL 80(CPOOL), SEL4
+
+ // ---------------------------------------------------
+
+ VREPF $3, Y0, YDIG
+ VMLHF X0, YDIG, ADD1H
+ VMLHF X1, YDIG, ADD2H
+ VMLF X0, YDIG, ADD1
+ VMLF X1, YDIG, ADD2
+
+ VREPF $2, Y0, YDIG
+ VMALF X0, YDIG, ADD1H, ADD3
+ VMALF X1, YDIG, ADD2H, ADD4
+ VMALHF X0, YDIG, ADD1H, ADD3H // ADD1H Free
+ VMALHF X1, YDIG, ADD2H, ADD4H // ADD2H Free
+
+ VZERO ZER
+ VL 32(CPOOL), SEL1
+ VPERM ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
+
+ VSLDB $12, ADD2, ADD1, T0 // ADD1 Free
+ VSLDB $12, ZER, ADD2, T1 // ADD2 Free
+
+ VACCQ T0, ADD3, CAR1
+ VAQ T0, ADD3, T0 // ADD3 Free
+ VACCCQ T1, ADD4, CAR1, T2
+ VACQ T1, ADD4, CAR1, T1 // ADD4 Free
+
+ VL 48(CPOOL), SEL2
+ VL 64(CPOOL), SEL3
+ VL 80(CPOOL), SEL4
+ VPERM RED3, T0, SEL2, RED1 // [d0 0 d1 d0]
+ VPERM RED3, T0, SEL3, RED2 // [ 0 d1 d0 d1]
+ VPERM RED3, T0, SEL4, RED3 // [ 0 0 d1 d0]
+ VSQ RED3, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDB $12, T1, T0, T0
+ VSLDB $12, T2, T1, T1
+
+ VACCQ T0, ADD3H, CAR1
+ VAQ T0, ADD3H, T0
+ VACCCQ T1, ADD4H, CAR1, T2
+ VACQ T1, ADD4H, CAR1, T1
+
+ // ---------------------------------------------------
+
+ VREPF $1, Y0, YDIG
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+ VMALF X0, YDIG, T0, ADD1 // T0 Free->ADD1
+ VMALF X1, YDIG, T1, ADD2 // T1 Free->ADD2
+
+ VREPF $0, Y0, YDIG
+ VMALF X0, YDIG, ADD1H, ADD3
+ VMALF X1, YDIG, ADD2H, ADD4
+ VMALHF X0, YDIG, ADD1H, ADD3H // ADD1H Free->ADD3H
+ VMALHF X1, YDIG, ADD2H, ADD4H // ADD2H Free->ADD4H , YDIG Free->ZER
+
+ VZERO ZER
+ VL 32(CPOOL), SEL1
+ VPERM ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
+
+ VSLDB $12, ADD2, ADD1, T0 // ADD1 Free->T0
+ VSLDB $12, T2, ADD2, T1 // ADD2 Free->T1, T2 Free
+
+ VACCQ T0, RED1, CAR1
+ VAQ T0, RED1, T0
+ VACCCQ T1, RED2, CAR1, T2
+ VACQ T1, RED2, CAR1, T1
+
+ VACCQ T0, ADD3, CAR1
+ VAQ T0, ADD3, T0
+ VACCCQ T1, ADD4, CAR1, CAR2
+ VACQ T1, ADD4, CAR1, T1
+ VAQ T2, CAR2, T2
+
+ VL 48(CPOOL), SEL2
+ VL 64(CPOOL), SEL3
+ VL 80(CPOOL), SEL4
+ VPERM RED3, T0, SEL2, RED1 // [d0 0 d1 d0]
+ VPERM RED3, T0, SEL3, RED2 // [ 0 d1 d0 d1]
+ VPERM RED3, T0, SEL4, RED3 // [ 0 0 d1 d0]
+ VSQ RED3, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDB $12, T1, T0, T0
+ VSLDB $12, T2, T1, T1
+
+ VACCQ T0, ADD3H, CAR1
+ VAQ T0, ADD3H, T0
+ VACCCQ T1, ADD4H, CAR1, T2
+ VACQ T1, ADD4H, CAR1, T1
+
+ // ---------------------------------------------------
+
+ VREPF $3, Y1, YDIG
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+ VMALF X0, YDIG, T0, ADD1
+ VMALF X1, YDIG, T1, ADD2
+
+ VREPF $2, Y1, YDIG
+ VMALF X0, YDIG, ADD1H, ADD3
+ VMALF X1, YDIG, ADD2H, ADD4
+ VMALHF X0, YDIG, ADD1H, ADD3H // ADD1H Free
+ VMALHF X1, YDIG, ADD2H, ADD4H // ADD2H Free
+
+ VZERO ZER
+ VL 32(CPOOL), SEL1
+ VPERM ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
+
+ VSLDB $12, ADD2, ADD1, T0 // ADD1 Free
+ VSLDB $12, T2, ADD2, T1 // ADD2 Free
+
+ VACCQ T0, RED1, CAR1
+ VAQ T0, RED1, T0
+ VACCCQ T1, RED2, CAR1, T2
+ VACQ T1, RED2, CAR1, T1
+
+ VACCQ T0, ADD3, CAR1
+ VAQ T0, ADD3, T0
+ VACCCQ T1, ADD4, CAR1, CAR2
+ VACQ T1, ADD4, CAR1, T1
+ VAQ T2, CAR2, T2
+
+ VL 48(CPOOL), SEL2
+ VL 64(CPOOL), SEL3
+ VL 80(CPOOL), SEL4
+ VPERM RED3, T0, SEL2, RED1 // [d0 0 d1 d0]
+ VPERM RED3, T0, SEL3, RED2 // [ 0 d1 d0 d1]
+ VPERM RED3, T0, SEL4, RED3 // [ 0 0 d1 d0]
+ VSQ RED3, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDB $12, T1, T0, T0
+ VSLDB $12, T2, T1, T1
+
+ VACCQ T0, ADD3H, CAR1
+ VAQ T0, ADD3H, T0
+ VACCCQ T1, ADD4H, CAR1, T2
+ VACQ T1, ADD4H, CAR1, T1
+
+ // ---------------------------------------------------
+
+ VREPF $1, Y1, YDIG
+ VMALHF X0, YDIG, T0, ADD1H
+ VMALHF X1, YDIG, T1, ADD2H
+ VMALF X0, YDIG, T0, ADD1
+ VMALF X1, YDIG, T1, ADD2
+
+ VREPF $0, Y1, YDIG
+ VMALF X0, YDIG, ADD1H, ADD3
+ VMALF X1, YDIG, ADD2H, ADD4
+ VMALHF X0, YDIG, ADD1H, ADD3H
+ VMALHF X1, YDIG, ADD2H, ADD4H
+
+ VZERO ZER
+ VL 32(CPOOL), SEL1
+ VPERM ZER, ADD1, SEL1, RED3 // [d0 0 0 d0]
+
+ VSLDB $12, ADD2, ADD1, T0
+ VSLDB $12, T2, ADD2, T1
+
+ VACCQ T0, RED1, CAR1
+ VAQ T0, RED1, T0
+ VACCCQ T1, RED2, CAR1, T2
+ VACQ T1, RED2, CAR1, T1
+
+ VACCQ T0, ADD3, CAR1
+ VAQ T0, ADD3, T0
+ VACCCQ T1, ADD4, CAR1, CAR2
+ VACQ T1, ADD4, CAR1, T1
+ VAQ T2, CAR2, T2
+
+ VL 96(CPOOL), SEL5
+ VL 112(CPOOL), SEL6
+ VPERM T0, RED3, SEL5, RED2 // [d1 d0 d1 d0]
+ VPERM T0, RED3, SEL6, RED1 // [ 0 d1 d0 0]
+ VSQ RED1, RED2, RED2 // Guaranteed not to underflow
+
+ VSLDB $12, T1, T0, T0
+ VSLDB $12, T2, T1, T1
+
+ VACCQ T0, ADD3H, CAR1
+ VAQ T0, ADD3H, T0
+ VACCCQ T1, ADD4H, CAR1, T2
+ VACQ T1, ADD4H, CAR1, T1
+
+ VACCQ T0, RED1, CAR1
+ VAQ T0, RED1, T0
+ VACCCQ T1, RED2, CAR1, CAR2
+ VACQ T1, RED2, CAR1, T1
+ VAQ T2, CAR2, T2
+
+ // ---------------------------------------------------
+
+ VZERO RED3
+ VSCBIQ P0, T0, CAR1
+ VSQ P0, T0, ADD1H
+ VSBCBIQ T1, P1, CAR1, CAR2
+ VSBIQ T1, P1, CAR1, ADD2H
+ VSBIQ T2, RED3, CAR2, T2
+
+ // what output to use, ADD2H||ADD1H or T1||T0?
+ VSEL T0, ADD1H, T2, T0
+ VSEL T1, ADD2H, T2, T1
+ RET
+
+#undef CPOOL
+
+#undef X0
+#undef X1
+#undef Y0
+#undef Y1
+#undef T0
+#undef T1
+#undef P0
+#undef P1
+
+#undef SEL1
+#undef SEL2
+#undef SEL3
+#undef SEL4
+#undef SEL5
+#undef SEL6
+
+#undef YDIG
+#undef ADD1H
+#undef ADD2H
+#undef ADD3
+#undef ADD4
+#undef RED1
+#undef RED2
+#undef RED3
+#undef T2
+#undef ADD1
+#undef ADD2
+#undef ADD3H
+#undef ADD4H
+#undef ZER
+#undef CAR1
+#undef CAR2
+
+// ---------------------------------------
+
+// Parameters
+#define X0 V0
+#define X1 V1
+#define Y0 V2
+#define Y1 V3
+
+TEXT p256SqrInternal<>(SB), NOFRAME|NOSPLIT, $0
+ VLR X0, Y0
+ VLR X1, Y1
+ BR p256MulInternal<>(SB)
+
+#undef X0
+#undef X1
+#undef Y0
+#undef Y1
+
+#define p256SubInternal(T1, T0, X1, X0, Y1, Y0) \
+ VZERO ZER \
+ VSCBIQ Y0, X0, CAR1 \
+ VSQ Y0, X0, T0 \
+ VSBCBIQ X1, Y1, CAR1, SEL1 \
+ VSBIQ X1, Y1, CAR1, T1 \
+ VSQ SEL1, ZER, SEL1 \
+ \
+ VACCQ T0, PL, CAR1 \
+ VAQ T0, PL, TT0 \
+ VACQ T1, PH, CAR1, TT1 \
+ \
+ VSEL T0, TT0, SEL1, T0 \
+ VSEL T1, TT1, SEL1, T1 \
+
+#define p256AddInternal(T1, T0, X1, X0, Y1, Y0) \
+ VACCQ X0, Y0, CAR1 \
+ VAQ X0, Y0, T0 \
+ VACCCQ X1, Y1, CAR1, T2 \
+ VACQ X1, Y1, CAR1, T1 \
+ \
+ VZERO ZER \
+ VSCBIQ PL, T0, CAR1 \
+ VSQ PL, T0, TT0 \
+ VSBCBIQ T1, PH, CAR1, CAR2 \
+ VSBIQ T1, PH, CAR1, TT1 \
+ VSBIQ T2, ZER, CAR2, SEL1 \
+ \
+ VSEL T0, TT0, SEL1, T0 \
+ VSEL T1, TT1, SEL1, T1
+
+#define p256HalfInternal(T1, T0, X1, X0) \
+ VZERO ZER \
+ VSBIQ ZER, ZER, X0, SEL1 \
+ \
+ VACCQ X0, PL, CAR1 \
+ VAQ X0, PL, T0 \
+ VACCCQ X1, PH, CAR1, T2 \
+ VACQ X1, PH, CAR1, T1 \
+ \
+ VSEL X0, T0, SEL1, T0 \
+ VSEL X1, T1, SEL1, T1 \
+ VSEL ZER, T2, SEL1, T2 \
+ \
+ VSLDB $15, T2, ZER, TT1 \
+ VSLDB $15, T1, ZER, TT0 \
+ VREPIB $1, SEL1 \
+ VSRL SEL1, T0, T0 \
+ VSRL SEL1, T1, T1 \
+ VREPIB $7, SEL1 \
+ VSL SEL1, TT0, TT0 \
+ VSL SEL1, TT1, TT1 \
+ VO T0, TT0, T0 \
+ VO T1, TT1, T1
+
+// ---------------------------------------
+// func p256Mul(res, in1, in2 *p256Element)
+#define res_ptr R1
+#define x_ptr R2
+#define y_ptr R3
+#define CPOOL R4
+
+// Parameters
+#define X0 V0
+#define X1 V1
+#define Y0 V2
+#define Y1 V3
+#define T0 V4
+#define T1 V5
+
+// Constants
+#define P0 V30
+#define P1 V31
+TEXT ·p256Mul(SB), NOSPLIT, $0
+ MOVD res+0(FP), res_ptr
+ MOVD in1+8(FP), x_ptr
+ MOVD in2+16(FP), y_ptr
+
+ VL (0*16)(x_ptr), X0
+ VPDI $0x4, X0, X0, X0
+ VL (1*16)(x_ptr), X1
+ VPDI $0x4, X1, X1, X1
+ VL (0*16)(y_ptr), Y0
+ VPDI $0x4, Y0, Y0, Y0
+ VL (1*16)(y_ptr), Y1
+ VPDI $0x4, Y1, Y1, Y1
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+ VL 16(CPOOL), P0
+ VL 0(CPOOL), P1
+
+ CALL p256MulInternal<>(SB)
+
+ VPDI $0x4, T0, T0, T0
+ VST T0, (0*16)(res_ptr)
+ VPDI $0x4, T1, T1, T1
+ VST T1, (1*16)(res_ptr)
+ RET
+
+#undef res_ptr
+#undef x_ptr
+#undef y_ptr
+#undef CPOOL
+
+#undef X0
+#undef X1
+#undef Y0
+#undef Y1
+#undef T0
+#undef T1
+#undef P0
+#undef P1
+
+// ---------------------------------------
+// func p256Sqr(res, in *p256Element, n int)
+#define res_ptr R1
+#define x_ptr R2
+#define y_ptr R3
+#define CPOOL R4
+#define COUNT R5
+#define N R6
+
+// Parameters
+#define X0 V0
+#define X1 V1
+#define T0 V4
+#define T1 V5
+
+// Constants
+#define P0 V30
+#define P1 V31
+TEXT ·p256Sqr(SB), NOSPLIT, $0
+ MOVD res+0(FP), res_ptr
+ MOVD in+8(FP), x_ptr
+
+ VL (0*16)(x_ptr), X0
+ VPDI $0x4, X0, X0, X0
+ VL (1*16)(x_ptr), X1
+ VPDI $0x4, X1, X1, X1
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+ MOVD $0, COUNT
+ MOVD n+16(FP), N
+ VL 16(CPOOL), P0
+ VL 0(CPOOL), P1
+
+loop:
+ CALL p256SqrInternal<>(SB)
+ VLR T0, X0
+ VLR T1, X1
+ ADDW $1, COUNT
+ CMPW COUNT, N
+ BLT loop
+
+ VPDI $0x4, T0, T0, T0
+ VST T0, (0*16)(res_ptr)
+ VPDI $0x4, T1, T1, T1
+ VST T1, (1*16)(res_ptr)
+ RET
+
+#undef res_ptr
+#undef x_ptr
+#undef y_ptr
+#undef CPOOL
+#undef COUNT
+#undef N
+
+#undef X0
+#undef X1
+#undef T0
+#undef T1
+#undef P0
+#undef P1
+
+// Point add with P2 being affine point
+// If sign == 1 -> P2 = -P2
+// If sel == 0 -> P3 = P1
+// if zero == 0 -> P3 = P2
+// func p256PointAddAffineAsm(res, in1 *P256Point, in2 *p256AffinePoint, sign, sel, zero int)
+#define P3ptr R1
+#define P1ptr R2
+#define P2ptr R3
+#define CPOOL R4
+
+// Temporaries in REGs
+#define Y2L V15
+#define Y2H V16
+#define T1L V17
+#define T1H V18
+#define T2L V19
+#define T2H V20
+#define T3L V21
+#define T3H V22
+#define T4L V23
+#define T4H V24
+
+// Temps for Sub and Add
+#define TT0 V11
+#define TT1 V12
+#define T2 V13
+
+// p256MulAsm Parameters
+#define X0 V0
+#define X1 V1
+#define Y0 V2
+#define Y1 V3
+#define T0 V4
+#define T1 V5
+
+#define PL V30
+#define PH V31
+
+// Names for zero/sel selects
+#define X1L V0
+#define X1H V1
+#define Y1L V2 // p256MulAsmParmY
+#define Y1H V3 // p256MulAsmParmY
+#define Z1L V4
+#define Z1H V5
+#define X2L V0
+#define X2H V1
+#define Z2L V4
+#define Z2H V5
+#define X3L V17 // T1L
+#define X3H V18 // T1H
+#define Y3L V21 // T3L
+#define Y3H V22 // T3H
+#define Z3L V28
+#define Z3H V29
+
+#define ZER V6
+#define SEL1 V7
+#define CAR1 V8
+#define CAR2 V9
+/* *
+ * Three operand formula:
+ * Source: 2004 Hankerson–Menezes–Vanstone, page 91.
+ * T1 = Z1²
+ * T2 = T1*Z1
+ * T1 = T1*X2
+ * T2 = T2*Y2
+ * T1 = T1-X1
+ * T2 = T2-Y1
+ * Z3 = Z1*T1
+ * T3 = T1²
+ * T4 = T3*T1
+ * T3 = T3*X1
+ * T1 = 2*T3
+ * X3 = T2²
+ * X3 = X3-T1
+ * X3 = X3-T4
+ * T3 = T3-X3
+ * T3 = T3*T2
+ * T4 = T4*Y1
+ * Y3 = T3-T4
+
+ * Three operand formulas, but with MulInternal X,Y used to store temps
+X=Z1; Y=Z1; MUL;T- // T1 = Z1² T1
+X=T ; Y- ; MUL;T2=T // T2 = T1*Z1 T1 T2
+X- ; Y=X2; MUL;T1=T // T1 = T1*X2 T1 T2
+X=T2; Y=Y2; MUL;T- // T2 = T2*Y2 T1 T2
+SUB(T2<T-Y1) // T2 = T2-Y1 T1 T2
+SUB(Y<T1-X1) // T1 = T1-X1 T1 T2
+X=Z1; Y- ; MUL;Z3:=T// Z3 = Z1*T1 T2
+X=Y; Y- ; MUL;X=T // T3 = T1*T1 T2
+X- ; Y- ; MUL;T4=T // T4 = T3*T1 T2 T4
+X- ; Y=X1; MUL;T3=T // T3 = T3*X1 T2 T3 T4
+ADD(T1<T+T) // T1 = T3+T3 T1 T2 T3 T4
+X=T2; Y=T2; MUL;T- // X3 = T2*T2 T1 T2 T3 T4
+SUB(T<T-T1) // X3 = X3-T1 T1 T2 T3 T4
+SUB(T<T-T4) X3:=T // X3 = X3-T4 T2 T3 T4
+SUB(X<T3-T) // T3 = T3-X3 T2 T3 T4
+X- ; Y- ; MUL;T3=T // T3 = T3*T2 T2 T3 T4
+X=T4; Y=Y1; MUL;T- // T4 = T4*Y1 T3 T4
+SUB(T<T3-T) Y3:=T // Y3 = T3-T4 T3 T4
+
+ */
+TEXT ·p256PointAddAffineAsm(SB), NOSPLIT, $0
+ MOVD res+0(FP), P3ptr
+ MOVD in1+8(FP), P1ptr
+ MOVD in2+16(FP), P2ptr
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+ VL 16(CPOOL), PL
+ VL 0(CPOOL), PH
+
+ // if (sign == 1) {
+ // Y2 = fromBig(new(big.Int).Mod(new(big.Int).Sub(p256.P, new(big.Int).SetBytes(Y2)), p256.P)) // Y2 = P-Y2
+ // }
+
+ VL 48(P2ptr), Y2H
+ VPDI $0x4, Y2H, Y2H, Y2H
+ VL 32(P2ptr), Y2L
+ VPDI $0x4, Y2L, Y2L, Y2L
+
+ VLREPG sign+24(FP), SEL1
+ VZERO ZER
+ VCEQG SEL1, ZER, SEL1
+
+ VSCBIQ Y2L, PL, CAR1
+ VSQ Y2L, PL, T1L
+ VSBIQ PH, Y2H, CAR1, T1H
+
+ VSEL Y2L, T1L, SEL1, Y2L
+ VSEL Y2H, T1H, SEL1, Y2H
+
+/* *
+ * Three operand formula:
+ * Source: 2004 Hankerson–Menezes–Vanstone, page 91.
+ */
+ // X=Z1; Y=Z1; MUL; T- // T1 = Z1² T1
+ VL 80(P1ptr), X1 // Z1H
+ VPDI $0x4, X1, X1, X1
+ VL 64(P1ptr), X0 // Z1L
+ VPDI $0x4, X0, X0, X0
+ VLR X0, Y0
+ VLR X1, Y1
+ CALL p256SqrInternal<>(SB)
+
+ // X=T ; Y- ; MUL; T2=T // T2 = T1*Z1 T1 T2
+ VLR T0, X0
+ VLR T1, X1
+ CALL p256MulInternal<>(SB)
+ VLR T0, T2L
+ VLR T1, T2H
+
+ // X- ; Y=X2; MUL; T1=T // T1 = T1*X2 T1 T2
+ VL 16(P2ptr), Y1 // X2H
+ VPDI $0x4, Y1, Y1, Y1
+ VL 0(P2ptr), Y0 // X2L
+ VPDI $0x4, Y0, Y0, Y0
+ CALL p256MulInternal<>(SB)
+ VLR T0, T1L
+ VLR T1, T1H
+
+ // X=T2; Y=Y2; MUL; T- // T2 = T2*Y2 T1 T2
+ VLR T2L, X0
+ VLR T2H, X1
+ VLR Y2L, Y0
+ VLR Y2H, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(T2<T-Y1) // T2 = T2-Y1 T1 T2
+ VL 48(P1ptr), Y1H
+ VPDI $0x4, Y1H, Y1H, Y1H
+ VL 32(P1ptr), Y1L
+ VPDI $0x4, Y1L, Y1L, Y1L
+ p256SubInternal(T2H,T2L,T1,T0,Y1H,Y1L)
+
+ // SUB(Y<T1-X1) // T1 = T1-X1 T1 T2
+ VL 16(P1ptr), X1H
+ VPDI $0x4, X1H, X1H, X1H
+ VL 0(P1ptr), X1L
+ VPDI $0x4, X1L, X1L, X1L
+ p256SubInternal(Y1,Y0,T1H,T1L,X1H,X1L)
+
+ // X=Z1; Y- ; MUL; Z3:=T// Z3 = Z1*T1 T2
+ VL 80(P1ptr), X1 // Z1H
+ VPDI $0x4, X1, X1, X1
+ VL 64(P1ptr), X0 // Z1L
+ VPDI $0x4, X0, X0, X0
+ CALL p256MulInternal<>(SB)
+
+ // VST T1, 64(P3ptr)
+ // VST T0, 80(P3ptr)
+ VLR T0, Z3L
+ VLR T1, Z3H
+
+ // X=Y; Y- ; MUL; X=T // T3 = T1*T1 T2
+ VLR Y0, X0
+ VLR Y1, X1
+ CALL p256SqrInternal<>(SB)
+ VLR T0, X0
+ VLR T1, X1
+
+ // X- ; Y- ; MUL; T4=T // T4 = T3*T1 T2 T4
+ CALL p256MulInternal<>(SB)
+ VLR T0, T4L
+ VLR T1, T4H
+
+ // X- ; Y=X1; MUL; T3=T // T3 = T3*X1 T2 T3 T4
+ VL 16(P1ptr), Y1 // X1H
+ VPDI $0x4, Y1, Y1, Y1
+ VL 0(P1ptr), Y0 // X1L
+ VPDI $0x4, Y0, Y0, Y0
+ CALL p256MulInternal<>(SB)
+ VLR T0, T3L
+ VLR T1, T3H
+
+ // ADD(T1<T+T) // T1 = T3+T3 T1 T2 T3 T4
+ p256AddInternal(T1H,T1L, T1,T0,T1,T0)
+
+ // X=T2; Y=T2; MUL; T- // X3 = T2*T2 T1 T2 T3 T4
+ VLR T2L, X0
+ VLR T2H, X1
+ VLR T2L, Y0
+ VLR T2H, Y1
+ CALL p256SqrInternal<>(SB)
+
+ // SUB(T<T-T1) // X3 = X3-T1 T1 T2 T3 T4 (T1 = X3)
+ p256SubInternal(T1,T0,T1,T0,T1H,T1L)
+
+ // SUB(T<T-T4) X3:=T // X3 = X3-T4 T2 T3 T4
+ p256SubInternal(T1,T0,T1,T0,T4H,T4L)
+ VLR T0, X3L
+ VLR T1, X3H
+
+ // SUB(X<T3-T) // T3 = T3-X3 T2 T3 T4
+ p256SubInternal(X1,X0,T3H,T3L,T1,T0)
+
+ // X- ; Y- ; MUL; T3=T // T3 = T3*T2 T2 T3 T4
+ CALL p256MulInternal<>(SB)
+ VLR T0, T3L
+ VLR T1, T3H
+
+ // X=T4; Y=Y1; MUL; T- // T4 = T4*Y1 T3 T4
+ VLR T4L, X0
+ VLR T4H, X1
+ VL 48(P1ptr), Y1 // Y1H
+ VPDI $0x4, Y1, Y1, Y1
+ VL 32(P1ptr), Y0 // Y1L
+ VPDI $0x4, Y0, Y0, Y0
+ CALL p256MulInternal<>(SB)
+
+ // SUB(T<T3-T) Y3:=T // Y3 = T3-T4 T3 T4 (T3 = Y3)
+ p256SubInternal(Y3H,Y3L,T3H,T3L,T1,T0)
+
+ // if (sel == 0) {
+ // copy(P3.x[:], X1)
+ // copy(P3.y[:], Y1)
+ // copy(P3.z[:], Z1)
+ // }
+
+ VL 16(P1ptr), X1H
+ VPDI $0x4, X1H, X1H, X1H
+ VL 0(P1ptr), X1L
+ VPDI $0x4, X1L, X1L, X1L
+
+ // Y1 already loaded, left over from addition
+ VL 80(P1ptr), Z1H
+ VPDI $0x4, Z1H, Z1H, Z1H
+ VL 64(P1ptr), Z1L
+ VPDI $0x4, Z1L, Z1L, Z1L
+
+ VLREPG sel+32(FP), SEL1
+ VZERO ZER
+ VCEQG SEL1, ZER, SEL1
+
+ VSEL X1L, X3L, SEL1, X3L
+ VSEL X1H, X3H, SEL1, X3H
+ VSEL Y1L, Y3L, SEL1, Y3L
+ VSEL Y1H, Y3H, SEL1, Y3H
+ VSEL Z1L, Z3L, SEL1, Z3L
+ VSEL Z1H, Z3H, SEL1, Z3H
+
+ // if (zero == 0) {
+ // copy(P3.x[:], X2)
+ // copy(P3.y[:], Y2)
+ // copy(P3.z[:], []byte{0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0xfe, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff,
+ // 0xff, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01}) //(p256.z*2^256)%p
+ // }
+ VL 16(P2ptr), X2H
+ VPDI $0x4, X2H, X2H, X2H
+ VL 0(P2ptr), X2L
+ VPDI $0x4, X2L, X2L, X2L
+
+ // Y2 already loaded
+ VL 128(CPOOL), Z2H
+ VL 144(CPOOL), Z2L
+
+ VLREPG zero+40(FP), SEL1
+ VZERO ZER
+ VCEQG SEL1, ZER, SEL1
+
+ VSEL X2L, X3L, SEL1, X3L
+ VSEL X2H, X3H, SEL1, X3H
+ VSEL Y2L, Y3L, SEL1, Y3L
+ VSEL Y2H, Y3H, SEL1, Y3H
+ VSEL Z2L, Z3L, SEL1, Z3L
+ VSEL Z2H, Z3H, SEL1, Z3H
+
+ // All done, store out the result!!!
+ VPDI $0x4, X3H, X3H, X3H
+ VST X3H, 16(P3ptr)
+ VPDI $0x4, X3L, X3L, X3L
+ VST X3L, 0(P3ptr)
+ VPDI $0x4, Y3H, Y3H, Y3H
+ VST Y3H, 48(P3ptr)
+ VPDI $0x4, Y3L, Y3L, Y3L
+ VST Y3L, 32(P3ptr)
+ VPDI $0x4, Z3H, Z3H, Z3H
+ VST Z3H, 80(P3ptr)
+ VPDI $0x4, Z3L, Z3L, Z3L
+ VST Z3L, 64(P3ptr)
+
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef P2ptr
+#undef CPOOL
+
+#undef Y2L
+#undef Y2H
+#undef T1L
+#undef T1H
+#undef T2L
+#undef T2H
+#undef T3L
+#undef T3H
+#undef T4L
+#undef T4H
+
+#undef TT0
+#undef TT1
+#undef T2
+
+#undef X0
+#undef X1
+#undef Y0
+#undef Y1
+#undef T0
+#undef T1
+
+#undef PL
+#undef PH
+
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef X2L
+#undef X2H
+#undef Z2L
+#undef Z2H
+#undef X3L
+#undef X3H
+#undef Y3L
+#undef Y3H
+#undef Z3L
+#undef Z3H
+
+#undef ZER
+#undef SEL1
+#undef CAR1
+#undef CAR2
+
+// func p256PointDoubleAsm(res, in *P256Point)
+// https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian.html#doubling-dbl-2007-bl
+// https://www.hyperelliptic.org/EFD/g1p/auto-shortw.html
+// https://www.hyperelliptic.org/EFD/g1p/auto-shortw-projective-3.html
+#define P3ptr R1
+#define P1ptr R2
+#define CPOOL R4
+
+// Temporaries in REGs
+#define X3L V15
+#define X3H V16
+#define Y3L V17
+#define Y3H V18
+#define T1L V19
+#define T1H V20
+#define T2L V21
+#define T2H V22
+#define T3L V23
+#define T3H V24
+
+#define X1L V6
+#define X1H V7
+#define Y1L V8
+#define Y1H V9
+#define Z1L V10
+#define Z1H V11
+
+// Temps for Sub and Add
+#define TT0 V11
+#define TT1 V12
+#define T2 V13
+
+// p256MulAsm Parameters
+#define X0 V0
+#define X1 V1
+#define Y0 V2
+#define Y1 V3
+#define T0 V4
+#define T1 V5
+
+#define PL V30
+#define PH V31
+
+#define Z3L V23
+#define Z3H V24
+
+#define ZER V26
+#define SEL1 V27
+#define CAR1 V28
+#define CAR2 V29
+/*
+ * https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#doubling-dbl-2004-hmv
+ * Cost: 4M + 4S + 1*half + 5add + 2*2 + 1*3.
+ * Source: 2004 Hankerson–Menezes–Vanstone, page 91.
+ * A = 3(X₁-Z₁²)×(X₁+Z₁²)
+ * B = 2Y₁
+ * Z₃ = B×Z₁
+ * C = B²
+ * D = C×X₁
+ * X₃ = A²-2D
+ * Y₃ = (D-X₃)×A-C²/2
+ *
+ * Three-operand formula:
+ * T1 = Z1²
+ * T2 = X1-T1
+ * T1 = X1+T1
+ * T2 = T2*T1
+ * T2 = 3*T2
+ * Y3 = 2*Y1
+ * Z3 = Y3*Z1
+ * Y3 = Y3²
+ * T3 = Y3*X1
+ * Y3 = Y3²
+ * Y3 = half*Y3
+ * X3 = T2²
+ * T1 = 2*T3
+ * X3 = X3-T1
+ * T1 = T3-X3
+ * T1 = T1*T2
+ * Y3 = T1-Y3
+ */
+
+TEXT ·p256PointDoubleAsm(SB), NOSPLIT, $0
+ MOVD res+0(FP), P3ptr
+ MOVD in+8(FP), P1ptr
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+ VL 16(CPOOL), PL
+ VL 0(CPOOL), PH
+
+ // X=Z1; Y=Z1; MUL; T- // T1 = Z1²
+ VL 80(P1ptr), X1 // Z1H
+ VPDI $0x4, X1, X1, X1
+ VL 64(P1ptr), X0 // Z1L
+ VPDI $0x4, X0, X0, X0
+ VLR X0, Y0
+ VLR X1, Y1
+ CALL p256SqrInternal<>(SB)
+
+ // SUB(X<X1-T) // T2 = X1-T1
+ VL 16(P1ptr), X1H
+ VPDI $0x4, X1H, X1H, X1H
+ VL 0(P1ptr), X1L
+ VPDI $0x4, X1L, X1L, X1L
+ p256SubInternal(X1,X0,X1H,X1L,T1,T0)
+
+ // ADD(Y<X1+T) // T1 = X1+T1
+ p256AddInternal(Y1,Y0,X1H,X1L,T1,T0)
+
+ // X- ; Y- ; MUL; T- // T2 = T2*T1
+ CALL p256MulInternal<>(SB)
+
+ // ADD(T2<T+T); ADD(T2<T2+T) // T2 = 3*T2
+ p256AddInternal(T2H,T2L,T1,T0,T1,T0)
+ p256AddInternal(T2H,T2L,T2H,T2L,T1,T0)
+
+ // ADD(X<Y1+Y1) // Y3 = 2*Y1
+ VL 48(P1ptr), Y1H
+ VPDI $0x4, Y1H, Y1H, Y1H
+ VL 32(P1ptr), Y1L
+ VPDI $0x4, Y1L, Y1L, Y1L
+ p256AddInternal(X1,X0,Y1H,Y1L,Y1H,Y1L)
+
+ // X- ; Y=Z1; MUL; Z3:=T // Z3 = Y3*Z1
+ VL 80(P1ptr), Y1 // Z1H
+ VPDI $0x4, Y1, Y1, Y1
+ VL 64(P1ptr), Y0 // Z1L
+ VPDI $0x4, Y0, Y0, Y0
+ CALL p256MulInternal<>(SB)
+ VPDI $0x4, T1, T1, TT1
+ VST TT1, 80(P3ptr)
+ VPDI $0x4, T0, T0, TT0
+ VST TT0, 64(P3ptr)
+
+ // X- ; Y=X ; MUL; T- // Y3 = Y3²
+ VLR X0, Y0
+ VLR X1, Y1
+ CALL p256SqrInternal<>(SB)
+
+ // X=T ; Y=X1; MUL; T3=T // T3 = Y3*X1
+ VLR T0, X0
+ VLR T1, X1
+ VL 16(P1ptr), Y1
+ VPDI $0x4, Y1, Y1, Y1
+ VL 0(P1ptr), Y0
+ VPDI $0x4, Y0, Y0, Y0
+ CALL p256MulInternal<>(SB)
+ VLR T0, T3L
+ VLR T1, T3H
+
+ // X- ; Y=X ; MUL; T- // Y3 = Y3²
+ VLR X0, Y0
+ VLR X1, Y1
+ CALL p256SqrInternal<>(SB)
+
+ // HAL(Y3<T) // Y3 = half*Y3
+ p256HalfInternal(Y3H,Y3L, T1,T0)
+
+ // X=T2; Y=T2; MUL; T- // X3 = T2²
+ VLR T2L, X0
+ VLR T2H, X1
+ VLR T2L, Y0
+ VLR T2H, Y1
+ CALL p256SqrInternal<>(SB)
+
+ // ADD(T1<T3+T3) // T1 = 2*T3
+ p256AddInternal(T1H,T1L,T3H,T3L,T3H,T3L)
+
+ // SUB(X3<T-T1) X3:=X3 // X3 = X3-T1
+ p256SubInternal(X3H,X3L,T1,T0,T1H,T1L)
+ VPDI $0x4, X3H, X3H, TT1
+ VST TT1, 16(P3ptr)
+ VPDI $0x4, X3L, X3L, TT0
+ VST TT0, 0(P3ptr)
+
+ // SUB(X<T3-X3) // T1 = T3-X3
+ p256SubInternal(X1,X0,T3H,T3L,X3H,X3L)
+
+ // X- ; Y- ; MUL; T- // T1 = T1*T2
+ CALL p256MulInternal<>(SB)
+
+ // SUB(Y3<T-Y3) // Y3 = T1-Y3
+ p256SubInternal(Y3H,Y3L,T1,T0,Y3H,Y3L)
+
+ VPDI $0x4, Y3H, Y3H, Y3H
+ VST Y3H, 48(P3ptr)
+ VPDI $0x4, Y3L, Y3L, Y3L
+ VST Y3L, 32(P3ptr)
+ RET
+
+#undef P3ptr
+#undef P1ptr
+#undef CPOOL
+#undef X3L
+#undef X3H
+#undef Y3L
+#undef Y3H
+#undef T1L
+#undef T1H
+#undef T2L
+#undef T2H
+#undef T3L
+#undef T3H
+#undef X1L
+#undef X1H
+#undef Y1L
+#undef Y1H
+#undef Z1L
+#undef Z1H
+#undef TT0
+#undef TT1
+#undef T2
+#undef X0
+#undef X1
+#undef Y0
+#undef Y1
+#undef T0
+#undef T1
+#undef PL
+#undef PH
+#undef Z3L
+#undef Z3H
+#undef ZER
+#undef SEL1
+#undef CAR1
+#undef CAR2
+
+// func p256PointAddAsm(res, in1, in2 *P256Point) int
+#define P3ptr R1
+#define P1ptr R2
+#define P2ptr R3
+#define CPOOL R4
+#define ISZERO R5
+#define TRUE R6
+
+// Temporaries in REGs
+#define T1L V16
+#define T1H V17
+#define T2L V18
+#define T2H V19
+#define U1L V20
+#define U1H V21
+#define S1L V22
+#define S1H V23
+#define HL V24
+#define HH V25
+#define RL V26
+#define RH V27
+
+// Temps for Sub and Add
+#define ZER V6
+#define SEL1 V7
+#define CAR1 V8
+#define CAR2 V9
+#define TT0 V11
+#define TT1 V12
+#define T2 V13
+
+// p256MulAsm Parameters
+#define X0 V0
+#define X1 V1
+#define Y0 V2
+#define Y1 V3
+#define T0 V4
+#define T1 V5
+
+#define PL V30
+#define PH V31
+/*
+ * https://delta.cs.cinvestav.mx/~francisco/arith/julio.pdf "Software Implementation of the NIST Elliptic Curves Over Prime Fields"
+ *
+ * A = X₁×Z₂²
+ * B = Y₁×Z₂³
+ * C = X₂×Z₁²-A
+ * D = Y₂×Z₁³-B
+ * X₃ = D² - 2A×C² - C³
+ * Y₃ = D×(A×C² - X₃) - B×C³
+ * Z₃ = Z₁×Z₂×C
+ *
+ * Three-operand formula (adopted): https://www.hyperelliptic.org/EFD/g1p/auto-shortw-jacobian-3.html#addition-add-1998-cmo-2
+ * Temp storage: T1,T2,U1,H,Z3=X3=Y3,S1,R
+ *
+ * T1 = Z1*Z1
+ * T2 = Z2*Z2
+ * U1 = X1*T2
+ * H = X2*T1
+ * H = H-U1
+ * Z3 = Z1*Z2
+ * Z3 = Z3*H << store-out Z3 result reg.. could override Z1, if slices have same backing array
+ *
+ * S1 = Z2*T2
+ * S1 = Y1*S1
+ * R = Z1*T1
+ * R = Y2*R
+ * R = R-S1
+ *
+ * T1 = H*H
+ * T2 = H*T1
+ * U1 = U1*T1
+ *
+ * X3 = R*R
+ * X3 = X3-T2
+ * T1 = 2*U1
+ * X3 = X3-T1 << store-out X3 result reg
+ *
+ * T2 = S1*T2
+ * Y3 = U1-X3
+ * Y3 = R*Y3
+ * Y3 = Y3-T2 << store-out Y3 result reg
+
+ // X=Z1; Y=Z1; MUL; T- // T1 = Z1*Z1
+ // X- ; Y=T ; MUL; R=T // R = Z1*T1
+ // X=X2; Y- ; MUL; H=T // H = X2*T1
+ // X=Z2; Y=Z2; MUL; T- // T2 = Z2*Z2
+ // X- ; Y=T ; MUL; S1=T // S1 = Z2*T2
+ // X=X1; Y- ; MUL; U1=T // U1 = X1*T2
+ // SUB(H<H-T) // H = H-U1
+ // X=Z1; Y=Z2; MUL; T- // Z3 = Z1*Z2
+ // X=T ; Y=H ; MUL; Z3:=T// Z3 = Z3*H << store-out Z3 result reg.. could override Z1, if slices have same backing array
+ // X=Y1; Y=S1; MUL; S1=T // S1 = Y1*S1
+ // X=Y2; Y=R ; MUL; T- // R = Y2*R
+ // SUB(R<T-S1) // R = R-S1
+ // X=H ; Y=H ; MUL; T- // T1 = H*H
+ // X- ; Y=T ; MUL; T2=T // T2 = H*T1
+ // X=U1; Y- ; MUL; U1=T // U1 = U1*T1
+ // X=R ; Y=R ; MUL; T- // X3 = R*R
+ // SUB(T<T-T2) // X3 = X3-T2
+ // ADD(X<U1+U1) // T1 = 2*U1
+ // SUB(T<T-X) X3:=T // X3 = X3-T1 << store-out X3 result reg
+ // SUB(Y<U1-T) // Y3 = U1-X3
+ // X=R ; Y- ; MUL; U1=T // Y3 = R*Y3
+ // X=S1; Y=T2; MUL; T- // T2 = S1*T2
+ // SUB(T<U1-T); Y3:=T // Y3 = Y3-T2 << store-out Y3 result reg
+ */
+TEXT ·p256PointAddAsm(SB), NOSPLIT, $0
+ MOVD res+0(FP), P3ptr
+ MOVD in1+8(FP), P1ptr
+ MOVD in2+16(FP), P2ptr
+
+ MOVD $p256mul<>+0x00(SB), CPOOL
+ VL 16(CPOOL), PL
+ VL 0(CPOOL), PH
+
+ // X=Z1; Y=Z1; MUL; T- // T1 = Z1*Z1
+ VL 80(P1ptr), X1 // Z1H
+ VPDI $0x4, X1, X1, X1
+ VL 64(P1ptr), X0 // Z1L
+ VPDI $0x4, X0, X0, X0
+ VLR X0, Y0
+ VLR X1, Y1
+ CALL p256SqrInternal<>(SB)
+
+ // X- ; Y=T ; MUL; R=T // R = Z1*T1
+ VLR T0, Y0
+ VLR T1, Y1
+ CALL p256MulInternal<>(SB)
+ VLR T0, RL
+ VLR T1, RH
+
+ // X=X2; Y- ; MUL; H=T // H = X2*T1
+ VL 16(P2ptr), X1 // X2H
+ VPDI $0x4, X1, X1, X1
+ VL 0(P2ptr), X0 // X2L
+ VPDI $0x4, X0, X0, X0
+ CALL p256MulInternal<>(SB)
+ VLR T0, HL
+ VLR T1, HH
+
+ // X=Z2; Y=Z2; MUL; T- // T2 = Z2*Z2
+ VL 80(P2ptr), X1 // Z2H
+ VPDI $0x4, X1, X1, X1
+ VL 64(P2ptr), X0 // Z2L
+ VPDI $0x4, X0, X0, X0
+ VLR X0, Y0
+ VLR X1, Y1
+ CALL p256SqrInternal<>(SB)
+
+ // X- ; Y=T ; MUL; S1=T // S1 = Z2*T2
+ VLR T0, Y0
+ VLR T1, Y1
+ CALL p256MulInternal<>(SB)
+ VLR T0, S1L
+ VLR T1, S1H
+
+ // X=X1; Y- ; MUL; U1=T // U1 = X1*T2
+ VL 16(P1ptr), X1 // X1H
+ VPDI $0x4, X1, X1, X1
+ VL 0(P1ptr), X0 // X1L
+ VPDI $0x4, X0, X0, X0
+ CALL p256MulInternal<>(SB)
+ VLR T0, U1L
+ VLR T1, U1H
+
+ // SUB(H<H-T) // H = H-U1
+ p256SubInternal(HH,HL,HH,HL,T1,T0)
+
+ // if H == 0 or H^P == 0 then ret=1 else ret=0
+ // clobbers T1H and T1L
+ MOVD $0, ISZERO
+ MOVD $1, TRUE
+ VZERO ZER
+ VO HL, HH, T1H
+ VCEQGS ZER, T1H, T1H
+ MOVDEQ TRUE, ISZERO
+ VX HL, PL, T1L
+ VX HH, PH, T1H
+ VO T1L, T1H, T1H
+ VCEQGS ZER, T1H, T1H
+ MOVDEQ TRUE, ISZERO
+ MOVD ISZERO, ret+24(FP)
+
+ // X=Z1; Y=Z2; MUL; T- // Z3 = Z1*Z2
+ VL 80(P1ptr), X1 // Z1H
+ VPDI $0x4, X1, X1, X1
+ VL 64(P1ptr), X0 // Z1L
+ VPDI $0x4, X0, X0, X0
+ VL 80(P2ptr), Y1 // Z2H
+ VPDI $0x4, Y1, Y1, Y1
+ VL 64(P2ptr), Y0 // Z2L
+ VPDI $0x4, Y0, Y0, Y0
+ CALL p256MulInternal<>(SB)
+
+ // X=T ; Y=H ; MUL; Z3:=T// Z3 = Z3*H
+ VLR T0, X0
+ VLR T1, X1
+ VLR HL, Y0
+ VLR HH, Y1
+ CALL p256MulInternal<>(SB)
+ VPDI $0x4, T1, T1, TT1
+ VST TT1, 80(P3ptr)
+ VPDI $0x4, T0, T0, TT0
+ VST TT0, 64(P3ptr)
+
+ // X=Y1; Y=S1; MUL; S1=T // S1 = Y1*S1
+ VL 48(P1ptr), X1
+ VPDI $0x4, X1, X1, X1
+ VL 32(P1ptr), X0
+ VPDI $0x4, X0, X0, X0
+ VLR S1L, Y0
+ VLR S1H, Y1
+ CALL p256MulInternal<>(SB)
+ VLR T0, S1L
+ VLR T1, S1H
+
+ // X=Y2; Y=R ; MUL; T- // R = Y2*R
+ VL 48(P2ptr), X1
+ VPDI $0x4, X1, X1, X1
+ VL 32(P2ptr), X0
+ VPDI $0x4, X0, X0, X0
+ VLR RL, Y0
+ VLR RH, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(R<T-S1) // R = T-S1
+ p256SubInternal(RH,RL,T1,T0,S1H,S1L)
+
+ // if R == 0 or R^P == 0 then ret=ret else ret=0
+ // clobbers T1H and T1L
+ MOVD $0, ISZERO
+ MOVD $1, TRUE
+ VZERO ZER
+ VO RL, RH, T1H
+ VCEQGS ZER, T1H, T1H
+ MOVDEQ TRUE, ISZERO
+ VX RL, PL, T1L
+ VX RH, PH, T1H
+ VO T1L, T1H, T1H
+ VCEQGS ZER, T1H, T1H
+ MOVDEQ TRUE, ISZERO
+ AND ret+24(FP), ISZERO
+ MOVD ISZERO, ret+24(FP)
+
+ // X=H ; Y=H ; MUL; T- // T1 = H*H
+ VLR HL, X0
+ VLR HH, X1
+ VLR HL, Y0
+ VLR HH, Y1
+ CALL p256SqrInternal<>(SB)
+
+ // X- ; Y=T ; MUL; T2=T // T2 = H*T1
+ VLR T0, Y0
+ VLR T1, Y1
+ CALL p256MulInternal<>(SB)
+ VLR T0, T2L
+ VLR T1, T2H
+
+ // X=U1; Y- ; MUL; U1=T // U1 = U1*T1
+ VLR U1L, X0
+ VLR U1H, X1
+ CALL p256MulInternal<>(SB)
+ VLR T0, U1L
+ VLR T1, U1H
+
+ // X=R ; Y=R ; MUL; T- // X3 = R*R
+ VLR RL, X0
+ VLR RH, X1
+ VLR RL, Y0
+ VLR RH, Y1
+ CALL p256SqrInternal<>(SB)
+
+ // SUB(T<T-T2) // X3 = X3-T2
+ p256SubInternal(T1,T0,T1,T0,T2H,T2L)
+
+ // ADD(X<U1+U1) // T1 = 2*U1
+ p256AddInternal(X1,X0,U1H,U1L,U1H,U1L)
+
+ // SUB(T<T-X) X3:=T // X3 = X3-T1 << store-out X3 result reg
+ p256SubInternal(T1,T0,T1,T0,X1,X0)
+ VPDI $0x4, T1, T1, TT1
+ VST TT1, 16(P3ptr)
+ VPDI $0x4, T0, T0, TT0
+ VST TT0, 0(P3ptr)
+
+ // SUB(Y<U1-T) // Y3 = U1-X3
+ p256SubInternal(Y1,Y0,U1H,U1L,T1,T0)
+
+ // X=R ; Y- ; MUL; U1=T // Y3 = R*Y3
+ VLR RL, X0
+ VLR RH, X1
+ CALL p256MulInternal<>(SB)
+ VLR T0, U1L
+ VLR T1, U1H
+
+ // X=S1; Y=T2; MUL; T- // T2 = S1*T2
+ VLR S1L, X0
+ VLR S1H, X1
+ VLR T2L, Y0
+ VLR T2H, Y1
+ CALL p256MulInternal<>(SB)
+
+ // SUB(T<U1-T); Y3:=T // Y3 = Y3-T2 << store-out Y3 result reg
+ p256SubInternal(T1,T0,U1H,U1L,T1,T0)
+ VPDI $0x4, T1, T1, T1
+ VST T1, 48(P3ptr)
+ VPDI $0x4, T0, T0, T0
+ VST T0, 32(P3ptr)
+
+ RET
diff --git a/src/crypto/internal/nistec/p256_asm_table.bin b/src/crypto/internal/nistec/p256_asm_table.bin
new file mode 100644
index 0000000..20c527e
--- /dev/null
+++ b/src/crypto/internal/nistec/p256_asm_table.bin
Binary files differ
diff --git a/src/crypto/internal/nistec/p256_asm_table_test.go b/src/crypto/internal/nistec/p256_asm_table_test.go
new file mode 100644
index 0000000..5b7246b
--- /dev/null
+++ b/src/crypto/internal/nistec/p256_asm_table_test.go
@@ -0,0 +1,49 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build amd64 || arm64 || ppc64le || s390x
+
+package nistec
+
+import (
+ "fmt"
+ "testing"
+)
+
+func TestP256PrecomputedTable(t *testing.T) {
+ base := NewP256Point().SetGenerator()
+
+ for i := 0; i < 43; i++ {
+ t.Run(fmt.Sprintf("table[%d]", i), func(t *testing.T) {
+ testP256AffineTable(t, base, &p256Precomputed[i])
+ })
+
+ for k := 0; k < 6; k++ {
+ base.Double(base)
+ }
+ }
+}
+
+func testP256AffineTable(t *testing.T, base *P256Point, table *p256AffineTable) {
+ p := NewP256Point()
+ zInv := new(p256Element)
+ zInvSq := new(p256Element)
+
+ for j := 0; j < 32; j++ {
+ p.Add(p, base)
+
+ // Convert p to affine coordinates.
+ p256Inverse(zInv, &p.z)
+ p256Sqr(zInvSq, zInv, 1)
+ p256Mul(zInv, zInv, zInvSq)
+
+ p256Mul(&p.x, &p.x, zInvSq)
+ p256Mul(&p.y, &p.y, zInv)
+ p.z = p256One
+
+ if p256Equal(&table[j].x, &p.x) != 1 || p256Equal(&table[j].y, &p.y) != 1 {
+ t.Fatalf("incorrect table entry at index %d", j)
+ }
+ }
+}
diff --git a/src/crypto/internal/nistec/p256_ordinv.go b/src/crypto/internal/nistec/p256_ordinv.go
new file mode 100644
index 0000000..1274fb7
--- /dev/null
+++ b/src/crypto/internal/nistec/p256_ordinv.go
@@ -0,0 +1,102 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build amd64 || arm64
+
+package nistec
+
+import "errors"
+
+// Montgomery multiplication modulo org(G). Sets res = in1 * in2 * R⁻¹.
+//
+//go:noescape
+func p256OrdMul(res, in1, in2 *p256OrdElement)
+
+// Montgomery square modulo org(G), repeated n times (n >= 1).
+//
+//go:noescape
+func p256OrdSqr(res, in *p256OrdElement, n int)
+
+func P256OrdInverse(k []byte) ([]byte, error) {
+ if len(k) != 32 {
+ return nil, errors.New("invalid scalar length")
+ }
+
+ x := new(p256OrdElement)
+ p256OrdBigToLittle(x, (*[32]byte)(k))
+ p256OrdReduce(x)
+
+ // Inversion is implemented as exponentiation by n - 2, per Fermat's little theorem.
+ //
+ // The sequence of 38 multiplications and 254 squarings is derived from
+ // https://briansmith.org/ecc-inversion-addition-chains-01#p256_scalar_inversion
+ _1 := new(p256OrdElement)
+ _11 := new(p256OrdElement)
+ _101 := new(p256OrdElement)
+ _111 := new(p256OrdElement)
+ _1111 := new(p256OrdElement)
+ _10101 := new(p256OrdElement)
+ _101111 := new(p256OrdElement)
+ t := new(p256OrdElement)
+
+ // This code operates in the Montgomery domain where R = 2²⁵⁶ mod n and n is
+ // the order of the scalar field. Elements in the Montgomery domain take the
+ // form a×R and p256OrdMul calculates (a × b × R⁻¹) mod n. RR is R in the
+ // domain, or R×R mod n, thus p256OrdMul(x, RR) gives x×R, i.e. converts x
+ // into the Montgomery domain.
+ RR := &p256OrdElement{0x83244c95be79eea2, 0x4699799c49bd6fa6,
+ 0x2845b2392b6bec59, 0x66e12d94f3d95620}
+
+ p256OrdMul(_1, x, RR) // _1
+ p256OrdSqr(x, _1, 1) // _10
+ p256OrdMul(_11, x, _1) // _11
+ p256OrdMul(_101, x, _11) // _101
+ p256OrdMul(_111, x, _101) // _111
+ p256OrdSqr(x, _101, 1) // _1010
+ p256OrdMul(_1111, _101, x) // _1111
+
+ p256OrdSqr(t, x, 1) // _10100
+ p256OrdMul(_10101, t, _1) // _10101
+ p256OrdSqr(x, _10101, 1) // _101010
+ p256OrdMul(_101111, _101, x) // _101111
+ p256OrdMul(x, _10101, x) // _111111 = x6
+ p256OrdSqr(t, x, 2) // _11111100
+ p256OrdMul(t, t, _11) // _11111111 = x8
+ p256OrdSqr(x, t, 8) // _ff00
+ p256OrdMul(x, x, t) // _ffff = x16
+ p256OrdSqr(t, x, 16) // _ffff0000
+ p256OrdMul(t, t, x) // _ffffffff = x32
+
+ p256OrdSqr(x, t, 64)
+ p256OrdMul(x, x, t)
+ p256OrdSqr(x, x, 32)
+ p256OrdMul(x, x, t)
+
+ sqrs := []int{
+ 6, 5, 4, 5, 5,
+ 4, 3, 3, 5, 9,
+ 6, 2, 5, 6, 5,
+ 4, 5, 5, 3, 10,
+ 2, 5, 5, 3, 7, 6}
+ muls := []*p256OrdElement{
+ _101111, _111, _11, _1111, _10101,
+ _101, _101, _101, _111, _101111,
+ _1111, _1, _1, _1111, _111,
+ _111, _111, _101, _11, _101111,
+ _11, _11, _11, _1, _10101, _1111}
+
+ for i, s := range sqrs {
+ p256OrdSqr(x, x, s)
+ p256OrdMul(x, x, muls[i])
+ }
+
+ // Montgomery multiplication by R⁻¹, or 1 outside the domain as R⁻¹×R = 1,
+ // converts a Montgomery value out of the domain.
+ one := &p256OrdElement{1}
+ p256OrdMul(x, x, one)
+
+ var xOut [32]byte
+ p256OrdLittleToBig(&xOut, x)
+ return xOut[:], nil
+}
diff --git a/src/crypto/internal/nistec/p256_ordinv_noasm.go b/src/crypto/internal/nistec/p256_ordinv_noasm.go
new file mode 100644
index 0000000..213875c
--- /dev/null
+++ b/src/crypto/internal/nistec/p256_ordinv_noasm.go
@@ -0,0 +1,13 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !amd64 && !arm64
+
+package nistec
+
+import "errors"
+
+func P256OrdInverse(k []byte) ([]byte, error) {
+ return nil, errors.New("unimplemented")
+}
diff --git a/src/crypto/internal/nistec/p256_ordinv_test.go b/src/crypto/internal/nistec/p256_ordinv_test.go
new file mode 100644
index 0000000..72de6bd
--- /dev/null
+++ b/src/crypto/internal/nistec/p256_ordinv_test.go
@@ -0,0 +1,94 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build amd64 || arm64
+
+package nistec_test
+
+import (
+ "bytes"
+ "crypto/elliptic"
+ "crypto/internal/nistec"
+ "math/big"
+ "testing"
+)
+
+func TestP256OrdInverse(t *testing.T) {
+ N := elliptic.P256().Params().N
+
+ // inv(0) is expected to be 0.
+ zero := make([]byte, 32)
+ out, err := nistec.P256OrdInverse(zero)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(out, zero) {
+ t.Error("unexpected output for inv(0)")
+ }
+
+ // inv(N) is also 0 mod N.
+ input := make([]byte, 32)
+ N.FillBytes(input)
+ out, err = nistec.P256OrdInverse(input)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(out, zero) {
+ t.Error("unexpected output for inv(N)")
+ }
+ if !bytes.Equal(input, N.Bytes()) {
+ t.Error("input was modified")
+ }
+
+ // Check inv(1) and inv(N+1) against math/big
+ exp := new(big.Int).ModInverse(big.NewInt(1), N).FillBytes(make([]byte, 32))
+ big.NewInt(1).FillBytes(input)
+ out, err = nistec.P256OrdInverse(input)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(out, exp) {
+ t.Error("unexpected output for inv(1)")
+ }
+ new(big.Int).Add(N, big.NewInt(1)).FillBytes(input)
+ out, err = nistec.P256OrdInverse(input)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(out, exp) {
+ t.Error("unexpected output for inv(N+1)")
+ }
+
+ // Check inv(20) and inv(N+20) against math/big
+ exp = new(big.Int).ModInverse(big.NewInt(20), N).FillBytes(make([]byte, 32))
+ big.NewInt(20).FillBytes(input)
+ out, err = nistec.P256OrdInverse(input)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(out, exp) {
+ t.Error("unexpected output for inv(20)")
+ }
+ new(big.Int).Add(N, big.NewInt(20)).FillBytes(input)
+ out, err = nistec.P256OrdInverse(input)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(out, exp) {
+ t.Error("unexpected output for inv(N+20)")
+ }
+
+ // Check inv(2^256-1) against math/big
+ bigInput := new(big.Int).Lsh(big.NewInt(1), 256)
+ bigInput.Sub(bigInput, big.NewInt(1))
+ exp = new(big.Int).ModInverse(bigInput, N).FillBytes(make([]byte, 32))
+ bigInput.FillBytes(input)
+ out, err = nistec.P256OrdInverse(input)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(out, exp) {
+ t.Error("unexpected output for inv(2^256-1)")
+ }
+}
diff --git a/src/crypto/internal/nistec/p384.go b/src/crypto/internal/nistec/p384.go
new file mode 100644
index 0000000..b452ec9
--- /dev/null
+++ b/src/crypto/internal/nistec/p384.go
@@ -0,0 +1,540 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by generate.go. DO NOT EDIT.
+
+package nistec
+
+import (
+ "crypto/internal/nistec/fiat"
+ "crypto/subtle"
+ "errors"
+ "sync"
+)
+
+// p384ElementLength is the length of an element of the base or scalar field,
+// which have the same bytes length for all NIST P curves.
+const p384ElementLength = 48
+
+// P384Point is a P384 point. The zero value is NOT valid.
+type P384Point struct {
+ // The point is represented in projective coordinates (X:Y:Z),
+ // where x = X/Z and y = Y/Z.
+ x, y, z *fiat.P384Element
+}
+
+// NewP384Point returns a new P384Point representing the point at infinity point.
+func NewP384Point() *P384Point {
+ return &P384Point{
+ x: new(fiat.P384Element),
+ y: new(fiat.P384Element).One(),
+ z: new(fiat.P384Element),
+ }
+}
+
+// SetGenerator sets p to the canonical generator and returns p.
+func (p *P384Point) SetGenerator() *P384Point {
+ p.x.SetBytes([]byte{0xaa, 0x87, 0xca, 0x22, 0xbe, 0x8b, 0x5, 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, 0x2, 0xf2, 0x5d, 0xbf, 0x55, 0x29, 0x6c, 0x3a, 0x54, 0x5e, 0x38, 0x72, 0x76, 0xa, 0xb7})
+ p.y.SetBytes([]byte{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, 0xa, 0x60, 0xb1, 0xce, 0x1d, 0x7e, 0x81, 0x9d, 0x7a, 0x43, 0x1d, 0x7c, 0x90, 0xea, 0xe, 0x5f})
+ p.z.One()
+ return p
+}
+
+// Set sets p = q and returns p.
+func (p *P384Point) Set(q *P384Point) *P384Point {
+ p.x.Set(q.x)
+ p.y.Set(q.y)
+ p.z.Set(q.z)
+ return p
+}
+
+// SetBytes sets p to the compressed, uncompressed, or infinity value encoded in
+// b, as specified in SEC 1, Version 2.0, Section 2.3.4. If the point is not on
+// the curve, it returns nil and an error, and the receiver is unchanged.
+// Otherwise, it returns p.
+func (p *P384Point) SetBytes(b []byte) (*P384Point, error) {
+ switch {
+ // Point at infinity.
+ case len(b) == 1 && b[0] == 0:
+ return p.Set(NewP384Point()), nil
+
+ // Uncompressed form.
+ case len(b) == 1+2*p384ElementLength && b[0] == 4:
+ x, err := new(fiat.P384Element).SetBytes(b[1 : 1+p384ElementLength])
+ if err != nil {
+ return nil, err
+ }
+ y, err := new(fiat.P384Element).SetBytes(b[1+p384ElementLength:])
+ if err != nil {
+ return nil, err
+ }
+ if err := p384CheckOnCurve(x, y); err != nil {
+ return nil, err
+ }
+ p.x.Set(x)
+ p.y.Set(y)
+ p.z.One()
+ return p, nil
+
+ // Compressed form.
+ case len(b) == 1+p384ElementLength && (b[0] == 2 || b[0] == 3):
+ x, err := new(fiat.P384Element).SetBytes(b[1:])
+ if err != nil {
+ return nil, err
+ }
+
+ // y² = x³ - 3x + b
+ y := p384Polynomial(new(fiat.P384Element), x)
+ if !p384Sqrt(y, y) {
+ return nil, errors.New("invalid P384 compressed point encoding")
+ }
+
+ // Select the positive or negative root, as indicated by the least
+ // significant bit, based on the encoding type byte.
+ otherRoot := new(fiat.P384Element)
+ otherRoot.Sub(otherRoot, y)
+ cond := y.Bytes()[p384ElementLength-1]&1 ^ b[0]&1
+ y.Select(otherRoot, y, int(cond))
+
+ p.x.Set(x)
+ p.y.Set(y)
+ p.z.One()
+ return p, nil
+
+ default:
+ return nil, errors.New("invalid P384 point encoding")
+ }
+}
+
+var _p384B *fiat.P384Element
+var _p384BOnce sync.Once
+
+func p384B() *fiat.P384Element {
+ _p384BOnce.Do(func() {
+ _p384B, _ = new(fiat.P384Element).SetBytes([]byte{0xb3, 0x31, 0x2f, 0xa7, 0xe2, 0x3e, 0xe7, 0xe4, 0x98, 0x8e, 0x5, 0x6b, 0xe3, 0xf8, 0x2d, 0x19, 0x18, 0x1d, 0x9c, 0x6e, 0xfe, 0x81, 0x41, 0x12, 0x3, 0x14, 0x8, 0x8f, 0x50, 0x13, 0x87, 0x5a, 0xc6, 0x56, 0x39, 0x8d, 0x8a, 0x2e, 0xd1, 0x9d, 0x2a, 0x85, 0xc8, 0xed, 0xd3, 0xec, 0x2a, 0xef})
+ })
+ return _p384B
+}
+
+// p384Polynomial sets y2 to x³ - 3x + b, and returns y2.
+func p384Polynomial(y2, x *fiat.P384Element) *fiat.P384Element {
+ y2.Square(x)
+ y2.Mul(y2, x)
+
+ threeX := new(fiat.P384Element).Add(x, x)
+ threeX.Add(threeX, x)
+ y2.Sub(y2, threeX)
+
+ return y2.Add(y2, p384B())
+}
+
+func p384CheckOnCurve(x, y *fiat.P384Element) error {
+ // y² = x³ - 3x + b
+ rhs := p384Polynomial(new(fiat.P384Element), x)
+ lhs := new(fiat.P384Element).Square(y)
+ if rhs.Equal(lhs) != 1 {
+ return errors.New("P384 point not on curve")
+ }
+ return nil
+}
+
+// Bytes returns the uncompressed or infinity encoding of p, as specified in
+// SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at
+// infinity is shorter than all other encodings.
+func (p *P384Point) Bytes() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [1 + 2*p384ElementLength]byte
+ return p.bytes(&out)
+}
+
+func (p *P384Point) bytes(out *[1 + 2*p384ElementLength]byte) []byte {
+ if p.z.IsZero() == 1 {
+ return append(out[:0], 0)
+ }
+
+ zinv := new(fiat.P384Element).Invert(p.z)
+ x := new(fiat.P384Element).Mul(p.x, zinv)
+ y := new(fiat.P384Element).Mul(p.y, zinv)
+
+ buf := append(out[:0], 4)
+ buf = append(buf, x.Bytes()...)
+ buf = append(buf, y.Bytes()...)
+ return buf
+}
+
+// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
+// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
+func (p *P384Point) BytesX() ([]byte, error) {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [p384ElementLength]byte
+ return p.bytesX(&out)
+}
+
+func (p *P384Point) bytesX(out *[p384ElementLength]byte) ([]byte, error) {
+ if p.z.IsZero() == 1 {
+ return nil, errors.New("P384 point is the point at infinity")
+ }
+
+ zinv := new(fiat.P384Element).Invert(p.z)
+ x := new(fiat.P384Element).Mul(p.x, zinv)
+
+ return append(out[:0], x.Bytes()...), nil
+}
+
+// BytesCompressed returns the compressed or infinity encoding of p, as
+// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
+// point at infinity is shorter than all other encodings.
+func (p *P384Point) BytesCompressed() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [1 + p384ElementLength]byte
+ return p.bytesCompressed(&out)
+}
+
+func (p *P384Point) bytesCompressed(out *[1 + p384ElementLength]byte) []byte {
+ if p.z.IsZero() == 1 {
+ return append(out[:0], 0)
+ }
+
+ zinv := new(fiat.P384Element).Invert(p.z)
+ x := new(fiat.P384Element).Mul(p.x, zinv)
+ y := new(fiat.P384Element).Mul(p.y, zinv)
+
+ // Encode the sign of the y coordinate (indicated by the least significant
+ // bit) as the encoding type (2 or 3).
+ buf := append(out[:0], 2)
+ buf[0] |= y.Bytes()[p384ElementLength-1] & 1
+ buf = append(buf, x.Bytes()...)
+ return buf
+}
+
+// Add sets q = p1 + p2, and returns q. The points may overlap.
+func (q *P384Point) Add(p1, p2 *P384Point) *P384Point {
+ // Complete addition formula for a = -3 from "Complete addition formulas for
+ // prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
+
+ t0 := new(fiat.P384Element).Mul(p1.x, p2.x) // t0 := X1 * X2
+ t1 := new(fiat.P384Element).Mul(p1.y, p2.y) // t1 := Y1 * Y2
+ t2 := new(fiat.P384Element).Mul(p1.z, p2.z) // t2 := Z1 * Z2
+ t3 := new(fiat.P384Element).Add(p1.x, p1.y) // t3 := X1 + Y1
+ t4 := new(fiat.P384Element).Add(p2.x, p2.y) // t4 := X2 + Y2
+ t3.Mul(t3, t4) // t3 := t3 * t4
+ t4.Add(t0, t1) // t4 := t0 + t1
+ t3.Sub(t3, t4) // t3 := t3 - t4
+ t4.Add(p1.y, p1.z) // t4 := Y1 + Z1
+ x3 := new(fiat.P384Element).Add(p2.y, p2.z) // X3 := Y2 + Z2
+ t4.Mul(t4, x3) // t4 := t4 * X3
+ x3.Add(t1, t2) // X3 := t1 + t2
+ t4.Sub(t4, x3) // t4 := t4 - X3
+ x3.Add(p1.x, p1.z) // X3 := X1 + Z1
+ y3 := new(fiat.P384Element).Add(p2.x, p2.z) // Y3 := X2 + Z2
+ x3.Mul(x3, y3) // X3 := X3 * Y3
+ y3.Add(t0, t2) // Y3 := t0 + t2
+ y3.Sub(x3, y3) // Y3 := X3 - Y3
+ z3 := new(fiat.P384Element).Mul(p384B(), t2) // Z3 := b * t2
+ x3.Sub(y3, z3) // X3 := Y3 - Z3
+ z3.Add(x3, x3) // Z3 := X3 + X3
+ x3.Add(x3, z3) // X3 := X3 + Z3
+ z3.Sub(t1, x3) // Z3 := t1 - X3
+ x3.Add(t1, x3) // X3 := t1 + X3
+ y3.Mul(p384B(), y3) // Y3 := b * Y3
+ t1.Add(t2, t2) // t1 := t2 + t2
+ t2.Add(t1, t2) // t2 := t1 + t2
+ y3.Sub(y3, t2) // Y3 := Y3 - t2
+ y3.Sub(y3, t0) // Y3 := Y3 - t0
+ t1.Add(y3, y3) // t1 := Y3 + Y3
+ y3.Add(t1, y3) // Y3 := t1 + Y3
+ t1.Add(t0, t0) // t1 := t0 + t0
+ t0.Add(t1, t0) // t0 := t1 + t0
+ t0.Sub(t0, t2) // t0 := t0 - t2
+ t1.Mul(t4, y3) // t1 := t4 * Y3
+ t2.Mul(t0, y3) // t2 := t0 * Y3
+ y3.Mul(x3, z3) // Y3 := X3 * Z3
+ y3.Add(y3, t2) // Y3 := Y3 + t2
+ x3.Mul(t3, x3) // X3 := t3 * X3
+ x3.Sub(x3, t1) // X3 := X3 - t1
+ z3.Mul(t4, z3) // Z3 := t4 * Z3
+ t1.Mul(t3, t0) // t1 := t3 * t0
+ z3.Add(z3, t1) // Z3 := Z3 + t1
+
+ q.x.Set(x3)
+ q.y.Set(y3)
+ q.z.Set(z3)
+ return q
+}
+
+// Double sets q = p + p, and returns q. The points may overlap.
+func (q *P384Point) Double(p *P384Point) *P384Point {
+ // Complete addition formula for a = -3 from "Complete addition formulas for
+ // prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
+
+ t0 := new(fiat.P384Element).Square(p.x) // t0 := X ^ 2
+ t1 := new(fiat.P384Element).Square(p.y) // t1 := Y ^ 2
+ t2 := new(fiat.P384Element).Square(p.z) // t2 := Z ^ 2
+ t3 := new(fiat.P384Element).Mul(p.x, p.y) // t3 := X * Y
+ t3.Add(t3, t3) // t3 := t3 + t3
+ z3 := new(fiat.P384Element).Mul(p.x, p.z) // Z3 := X * Z
+ z3.Add(z3, z3) // Z3 := Z3 + Z3
+ y3 := new(fiat.P384Element).Mul(p384B(), t2) // Y3 := b * t2
+ y3.Sub(y3, z3) // Y3 := Y3 - Z3
+ x3 := new(fiat.P384Element).Add(y3, y3) // X3 := Y3 + Y3
+ y3.Add(x3, y3) // Y3 := X3 + Y3
+ x3.Sub(t1, y3) // X3 := t1 - Y3
+ y3.Add(t1, y3) // Y3 := t1 + Y3
+ y3.Mul(x3, y3) // Y3 := X3 * Y3
+ x3.Mul(x3, t3) // X3 := X3 * t3
+ t3.Add(t2, t2) // t3 := t2 + t2
+ t2.Add(t2, t3) // t2 := t2 + t3
+ z3.Mul(p384B(), z3) // Z3 := b * Z3
+ z3.Sub(z3, t2) // Z3 := Z3 - t2
+ z3.Sub(z3, t0) // Z3 := Z3 - t0
+ t3.Add(z3, z3) // t3 := Z3 + Z3
+ z3.Add(z3, t3) // Z3 := Z3 + t3
+ t3.Add(t0, t0) // t3 := t0 + t0
+ t0.Add(t3, t0) // t0 := t3 + t0
+ t0.Sub(t0, t2) // t0 := t0 - t2
+ t0.Mul(t0, z3) // t0 := t0 * Z3
+ y3.Add(y3, t0) // Y3 := Y3 + t0
+ t0.Mul(p.y, p.z) // t0 := Y * Z
+ t0.Add(t0, t0) // t0 := t0 + t0
+ z3.Mul(t0, z3) // Z3 := t0 * Z3
+ x3.Sub(x3, z3) // X3 := X3 - Z3
+ z3.Mul(t0, t1) // Z3 := t0 * t1
+ z3.Add(z3, z3) // Z3 := Z3 + Z3
+ z3.Add(z3, z3) // Z3 := Z3 + Z3
+
+ q.x.Set(x3)
+ q.y.Set(y3)
+ q.z.Set(z3)
+ return q
+}
+
+// Select sets q to p1 if cond == 1, and to p2 if cond == 0.
+func (q *P384Point) Select(p1, p2 *P384Point, cond int) *P384Point {
+ q.x.Select(p1.x, p2.x, cond)
+ q.y.Select(p1.y, p2.y, cond)
+ q.z.Select(p1.z, p2.z, cond)
+ return q
+}
+
+// A p384Table holds the first 15 multiples of a point at offset -1, so [1]P
+// is at table[0], [15]P is at table[14], and [0]P is implicitly the identity
+// point.
+type p384Table [15]*P384Point
+
+// Select selects the n-th multiple of the table base point into p. It works in
+// constant time by iterating over every entry of the table. n must be in [0, 15].
+func (table *p384Table) Select(p *P384Point, n uint8) {
+ if n >= 16 {
+ panic("nistec: internal error: p384Table called with out-of-bounds value")
+ }
+ p.Set(NewP384Point())
+ for i := uint8(1); i < 16; i++ {
+ cond := subtle.ConstantTimeByteEq(i, n)
+ p.Select(table[i-1], p, cond)
+ }
+}
+
+// ScalarMult sets p = scalar * q, and returns p.
+func (p *P384Point) ScalarMult(q *P384Point, scalar []byte) (*P384Point, error) {
+ // Compute a p384Table for the base point q. The explicit NewP384Point
+ // calls get inlined, letting the allocations live on the stack.
+ var table = p384Table{NewP384Point(), NewP384Point(), NewP384Point(),
+ NewP384Point(), NewP384Point(), NewP384Point(), NewP384Point(),
+ NewP384Point(), NewP384Point(), NewP384Point(), NewP384Point(),
+ NewP384Point(), NewP384Point(), NewP384Point(), NewP384Point()}
+ table[0].Set(q)
+ for i := 1; i < 15; i += 2 {
+ table[i].Double(table[i/2])
+ table[i+1].Add(table[i], q)
+ }
+
+ // Instead of doing the classic double-and-add chain, we do it with a
+ // four-bit window: we double four times, and then add [0-15]P.
+ t := NewP384Point()
+ p.Set(NewP384Point())
+ for i, byte := range scalar {
+ // No need to double on the first iteration, as p is the identity at
+ // this point, and [N]∞ = ∞.
+ if i != 0 {
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+ }
+
+ windowValue := byte >> 4
+ table.Select(t, windowValue)
+ p.Add(p, t)
+
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+
+ windowValue = byte & 0b1111
+ table.Select(t, windowValue)
+ p.Add(p, t)
+ }
+
+ return p, nil
+}
+
+var p384GeneratorTable *[p384ElementLength * 2]p384Table
+var p384GeneratorTableOnce sync.Once
+
+// generatorTable returns a sequence of p384Tables. The first table contains
+// multiples of G. Each successive table is the previous table doubled four
+// times.
+func (p *P384Point) generatorTable() *[p384ElementLength * 2]p384Table {
+ p384GeneratorTableOnce.Do(func() {
+ p384GeneratorTable = new([p384ElementLength * 2]p384Table)
+ base := NewP384Point().SetGenerator()
+ for i := 0; i < p384ElementLength*2; i++ {
+ p384GeneratorTable[i][0] = NewP384Point().Set(base)
+ for j := 1; j < 15; j++ {
+ p384GeneratorTable[i][j] = NewP384Point().Add(p384GeneratorTable[i][j-1], base)
+ }
+ base.Double(base)
+ base.Double(base)
+ base.Double(base)
+ base.Double(base)
+ }
+ })
+ return p384GeneratorTable
+}
+
+// ScalarBaseMult sets p = scalar * B, where B is the canonical generator, and
+// returns p.
+func (p *P384Point) ScalarBaseMult(scalar []byte) (*P384Point, error) {
+ if len(scalar) != p384ElementLength {
+ return nil, errors.New("invalid scalar length")
+ }
+ tables := p.generatorTable()
+
+ // This is also a scalar multiplication with a four-bit window like in
+ // ScalarMult, but in this case the doublings are precomputed. The value
+ // [windowValue]G added at iteration k would normally get doubled
+ // (totIterations-k)×4 times, but with a larger precomputation we can
+ // instead add [2^((totIterations-k)×4)][windowValue]G and avoid the
+ // doublings between iterations.
+ t := NewP384Point()
+ p.Set(NewP384Point())
+ tableIndex := len(tables) - 1
+ for _, byte := range scalar {
+ windowValue := byte >> 4
+ tables[tableIndex].Select(t, windowValue)
+ p.Add(p, t)
+ tableIndex--
+
+ windowValue = byte & 0b1111
+ tables[tableIndex].Select(t, windowValue)
+ p.Add(p, t)
+ tableIndex--
+ }
+
+ return p, nil
+}
+
+// p384Sqrt sets e to a square root of x. If x is not a square, p384Sqrt returns
+// false and e is unchanged. e and x can overlap.
+func p384Sqrt(e, x *fiat.P384Element) (isSquare bool) {
+ candidate := new(fiat.P384Element)
+ p384SqrtCandidate(candidate, x)
+ square := new(fiat.P384Element).Square(candidate)
+ if square.Equal(x) != 1 {
+ return false
+ }
+ e.Set(candidate)
+ return true
+}
+
+// p384SqrtCandidate sets z to a square root candidate for x. z and x must not overlap.
+func p384SqrtCandidate(z, x *fiat.P384Element) {
+ // Since p = 3 mod 4, exponentiation by (p + 1) / 4 yields a square root candidate.
+ //
+ // The sequence of 14 multiplications and 381 squarings is derived from the
+ // following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
+ //
+ // _10 = 2*1
+ // _11 = 1 + _10
+ // _110 = 2*_11
+ // _111 = 1 + _110
+ // _111000 = _111 << 3
+ // _111111 = _111 + _111000
+ // _1111110 = 2*_111111
+ // _1111111 = 1 + _1111110
+ // x12 = _1111110 << 5 + _111111
+ // x24 = x12 << 12 + x12
+ // x31 = x24 << 7 + _1111111
+ // x32 = 2*x31 + 1
+ // x63 = x32 << 31 + x31
+ // x126 = x63 << 63 + x63
+ // x252 = x126 << 126 + x126
+ // x255 = x252 << 3 + _111
+ // return ((x255 << 33 + x32) << 64 + 1) << 30
+ //
+ var t0 = new(fiat.P384Element)
+ var t1 = new(fiat.P384Element)
+ var t2 = new(fiat.P384Element)
+
+ z.Square(x)
+ z.Mul(x, z)
+ z.Square(z)
+ t0.Mul(x, z)
+ z.Square(t0)
+ for s := 1; s < 3; s++ {
+ z.Square(z)
+ }
+ t1.Mul(t0, z)
+ t2.Square(t1)
+ z.Mul(x, t2)
+ for s := 0; s < 5; s++ {
+ t2.Square(t2)
+ }
+ t1.Mul(t1, t2)
+ t2.Square(t1)
+ for s := 1; s < 12; s++ {
+ t2.Square(t2)
+ }
+ t1.Mul(t1, t2)
+ for s := 0; s < 7; s++ {
+ t1.Square(t1)
+ }
+ t1.Mul(z, t1)
+ z.Square(t1)
+ z.Mul(x, z)
+ t2.Square(z)
+ for s := 1; s < 31; s++ {
+ t2.Square(t2)
+ }
+ t1.Mul(t1, t2)
+ t2.Square(t1)
+ for s := 1; s < 63; s++ {
+ t2.Square(t2)
+ }
+ t1.Mul(t1, t2)
+ t2.Square(t1)
+ for s := 1; s < 126; s++ {
+ t2.Square(t2)
+ }
+ t1.Mul(t1, t2)
+ for s := 0; s < 3; s++ {
+ t1.Square(t1)
+ }
+ t0.Mul(t0, t1)
+ for s := 0; s < 33; s++ {
+ t0.Square(t0)
+ }
+ z.Mul(z, t0)
+ for s := 0; s < 64; s++ {
+ z.Square(z)
+ }
+ z.Mul(x, z)
+ for s := 0; s < 30; s++ {
+ z.Square(z)
+ }
+}
diff --git a/src/crypto/internal/nistec/p521.go b/src/crypto/internal/nistec/p521.go
new file mode 100644
index 0000000..a57ad24
--- /dev/null
+++ b/src/crypto/internal/nistec/p521.go
@@ -0,0 +1,469 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by generate.go. DO NOT EDIT.
+
+package nistec
+
+import (
+ "crypto/internal/nistec/fiat"
+ "crypto/subtle"
+ "errors"
+ "sync"
+)
+
+// p521ElementLength is the length of an element of the base or scalar field,
+// which have the same bytes length for all NIST P curves.
+const p521ElementLength = 66
+
+// P521Point is a P521 point. The zero value is NOT valid.
+type P521Point struct {
+ // The point is represented in projective coordinates (X:Y:Z),
+ // where x = X/Z and y = Y/Z.
+ x, y, z *fiat.P521Element
+}
+
+// NewP521Point returns a new P521Point representing the point at infinity point.
+func NewP521Point() *P521Point {
+ return &P521Point{
+ x: new(fiat.P521Element),
+ y: new(fiat.P521Element).One(),
+ z: new(fiat.P521Element),
+ }
+}
+
+// SetGenerator sets p to the canonical generator and returns p.
+func (p *P521Point) SetGenerator() *P521Point {
+ p.x.SetBytes([]byte{0x0, 0xc6, 0x85, 0x8e, 0x6, 0xb7, 0x4, 0x4, 0xe9, 0xcd, 0x9e, 0x3e, 0xcb, 0x66, 0x23, 0x95, 0xb4, 0x42, 0x9c, 0x64, 0x81, 0x39, 0x5, 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})
+ p.y.SetBytes([]byte{0x1, 0x18, 0x39, 0x29, 0x6a, 0x78, 0x9a, 0x3b, 0xc0, 0x4, 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, 0x1, 0x3f, 0xad, 0x7, 0x61, 0x35, 0x3c, 0x70, 0x86, 0xa2, 0x72, 0xc2, 0x40, 0x88, 0xbe, 0x94, 0x76, 0x9f, 0xd1, 0x66, 0x50})
+ p.z.One()
+ return p
+}
+
+// Set sets p = q and returns p.
+func (p *P521Point) Set(q *P521Point) *P521Point {
+ p.x.Set(q.x)
+ p.y.Set(q.y)
+ p.z.Set(q.z)
+ return p
+}
+
+// SetBytes sets p to the compressed, uncompressed, or infinity value encoded in
+// b, as specified in SEC 1, Version 2.0, Section 2.3.4. If the point is not on
+// the curve, it returns nil and an error, and the receiver is unchanged.
+// Otherwise, it returns p.
+func (p *P521Point) SetBytes(b []byte) (*P521Point, error) {
+ switch {
+ // Point at infinity.
+ case len(b) == 1 && b[0] == 0:
+ return p.Set(NewP521Point()), nil
+
+ // Uncompressed form.
+ case len(b) == 1+2*p521ElementLength && b[0] == 4:
+ x, err := new(fiat.P521Element).SetBytes(b[1 : 1+p521ElementLength])
+ if err != nil {
+ return nil, err
+ }
+ y, err := new(fiat.P521Element).SetBytes(b[1+p521ElementLength:])
+ if err != nil {
+ return nil, err
+ }
+ if err := p521CheckOnCurve(x, y); err != nil {
+ return nil, err
+ }
+ p.x.Set(x)
+ p.y.Set(y)
+ p.z.One()
+ return p, nil
+
+ // Compressed form.
+ case len(b) == 1+p521ElementLength && (b[0] == 2 || b[0] == 3):
+ x, err := new(fiat.P521Element).SetBytes(b[1:])
+ if err != nil {
+ return nil, err
+ }
+
+ // y² = x³ - 3x + b
+ y := p521Polynomial(new(fiat.P521Element), x)
+ if !p521Sqrt(y, y) {
+ return nil, errors.New("invalid P521 compressed point encoding")
+ }
+
+ // Select the positive or negative root, as indicated by the least
+ // significant bit, based on the encoding type byte.
+ otherRoot := new(fiat.P521Element)
+ otherRoot.Sub(otherRoot, y)
+ cond := y.Bytes()[p521ElementLength-1]&1 ^ b[0]&1
+ y.Select(otherRoot, y, int(cond))
+
+ p.x.Set(x)
+ p.y.Set(y)
+ p.z.One()
+ return p, nil
+
+ default:
+ return nil, errors.New("invalid P521 point encoding")
+ }
+}
+
+var _p521B *fiat.P521Element
+var _p521BOnce sync.Once
+
+func p521B() *fiat.P521Element {
+ _p521BOnce.Do(func() {
+ _p521B, _ = new(fiat.P521Element).SetBytes([]byte{0x0, 0x51, 0x95, 0x3e, 0xb9, 0x61, 0x8e, 0x1c, 0x9a, 0x1f, 0x92, 0x9a, 0x21, 0xa0, 0xb6, 0x85, 0x40, 0xee, 0xa2, 0xda, 0x72, 0x5b, 0x99, 0xb3, 0x15, 0xf3, 0xb8, 0xb4, 0x89, 0x91, 0x8e, 0xf1, 0x9, 0xe1, 0x56, 0x19, 0x39, 0x51, 0xec, 0x7e, 0x93, 0x7b, 0x16, 0x52, 0xc0, 0xbd, 0x3b, 0xb1, 0xbf, 0x7, 0x35, 0x73, 0xdf, 0x88, 0x3d, 0x2c, 0x34, 0xf1, 0xef, 0x45, 0x1f, 0xd4, 0x6b, 0x50, 0x3f, 0x0})
+ })
+ return _p521B
+}
+
+// p521Polynomial sets y2 to x³ - 3x + b, and returns y2.
+func p521Polynomial(y2, x *fiat.P521Element) *fiat.P521Element {
+ y2.Square(x)
+ y2.Mul(y2, x)
+
+ threeX := new(fiat.P521Element).Add(x, x)
+ threeX.Add(threeX, x)
+ y2.Sub(y2, threeX)
+
+ return y2.Add(y2, p521B())
+}
+
+func p521CheckOnCurve(x, y *fiat.P521Element) error {
+ // y² = x³ - 3x + b
+ rhs := p521Polynomial(new(fiat.P521Element), x)
+ lhs := new(fiat.P521Element).Square(y)
+ if rhs.Equal(lhs) != 1 {
+ return errors.New("P521 point not on curve")
+ }
+ return nil
+}
+
+// Bytes returns the uncompressed or infinity encoding of p, as specified in
+// SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the point at
+// infinity is shorter than all other encodings.
+func (p *P521Point) Bytes() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [1 + 2*p521ElementLength]byte
+ return p.bytes(&out)
+}
+
+func (p *P521Point) bytes(out *[1 + 2*p521ElementLength]byte) []byte {
+ if p.z.IsZero() == 1 {
+ return append(out[:0], 0)
+ }
+
+ zinv := new(fiat.P521Element).Invert(p.z)
+ x := new(fiat.P521Element).Mul(p.x, zinv)
+ y := new(fiat.P521Element).Mul(p.y, zinv)
+
+ buf := append(out[:0], 4)
+ buf = append(buf, x.Bytes()...)
+ buf = append(buf, y.Bytes()...)
+ return buf
+}
+
+// BytesX returns the encoding of the x-coordinate of p, as specified in SEC 1,
+// Version 2.0, Section 2.3.5, or an error if p is the point at infinity.
+func (p *P521Point) BytesX() ([]byte, error) {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [p521ElementLength]byte
+ return p.bytesX(&out)
+}
+
+func (p *P521Point) bytesX(out *[p521ElementLength]byte) ([]byte, error) {
+ if p.z.IsZero() == 1 {
+ return nil, errors.New("P521 point is the point at infinity")
+ }
+
+ zinv := new(fiat.P521Element).Invert(p.z)
+ x := new(fiat.P521Element).Mul(p.x, zinv)
+
+ return append(out[:0], x.Bytes()...), nil
+}
+
+// BytesCompressed returns the compressed or infinity encoding of p, as
+// specified in SEC 1, Version 2.0, Section 2.3.3. Note that the encoding of the
+// point at infinity is shorter than all other encodings.
+func (p *P521Point) BytesCompressed() []byte {
+ // This function is outlined to make the allocations inline in the caller
+ // rather than happen on the heap.
+ var out [1 + p521ElementLength]byte
+ return p.bytesCompressed(&out)
+}
+
+func (p *P521Point) bytesCompressed(out *[1 + p521ElementLength]byte) []byte {
+ if p.z.IsZero() == 1 {
+ return append(out[:0], 0)
+ }
+
+ zinv := new(fiat.P521Element).Invert(p.z)
+ x := new(fiat.P521Element).Mul(p.x, zinv)
+ y := new(fiat.P521Element).Mul(p.y, zinv)
+
+ // Encode the sign of the y coordinate (indicated by the least significant
+ // bit) as the encoding type (2 or 3).
+ buf := append(out[:0], 2)
+ buf[0] |= y.Bytes()[p521ElementLength-1] & 1
+ buf = append(buf, x.Bytes()...)
+ return buf
+}
+
+// Add sets q = p1 + p2, and returns q. The points may overlap.
+func (q *P521Point) Add(p1, p2 *P521Point) *P521Point {
+ // Complete addition formula for a = -3 from "Complete addition formulas for
+ // prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
+
+ t0 := new(fiat.P521Element).Mul(p1.x, p2.x) // t0 := X1 * X2
+ t1 := new(fiat.P521Element).Mul(p1.y, p2.y) // t1 := Y1 * Y2
+ t2 := new(fiat.P521Element).Mul(p1.z, p2.z) // t2 := Z1 * Z2
+ t3 := new(fiat.P521Element).Add(p1.x, p1.y) // t3 := X1 + Y1
+ t4 := new(fiat.P521Element).Add(p2.x, p2.y) // t4 := X2 + Y2
+ t3.Mul(t3, t4) // t3 := t3 * t4
+ t4.Add(t0, t1) // t4 := t0 + t1
+ t3.Sub(t3, t4) // t3 := t3 - t4
+ t4.Add(p1.y, p1.z) // t4 := Y1 + Z1
+ x3 := new(fiat.P521Element).Add(p2.y, p2.z) // X3 := Y2 + Z2
+ t4.Mul(t4, x3) // t4 := t4 * X3
+ x3.Add(t1, t2) // X3 := t1 + t2
+ t4.Sub(t4, x3) // t4 := t4 - X3
+ x3.Add(p1.x, p1.z) // X3 := X1 + Z1
+ y3 := new(fiat.P521Element).Add(p2.x, p2.z) // Y3 := X2 + Z2
+ x3.Mul(x3, y3) // X3 := X3 * Y3
+ y3.Add(t0, t2) // Y3 := t0 + t2
+ y3.Sub(x3, y3) // Y3 := X3 - Y3
+ z3 := new(fiat.P521Element).Mul(p521B(), t2) // Z3 := b * t2
+ x3.Sub(y3, z3) // X3 := Y3 - Z3
+ z3.Add(x3, x3) // Z3 := X3 + X3
+ x3.Add(x3, z3) // X3 := X3 + Z3
+ z3.Sub(t1, x3) // Z3 := t1 - X3
+ x3.Add(t1, x3) // X3 := t1 + X3
+ y3.Mul(p521B(), y3) // Y3 := b * Y3
+ t1.Add(t2, t2) // t1 := t2 + t2
+ t2.Add(t1, t2) // t2 := t1 + t2
+ y3.Sub(y3, t2) // Y3 := Y3 - t2
+ y3.Sub(y3, t0) // Y3 := Y3 - t0
+ t1.Add(y3, y3) // t1 := Y3 + Y3
+ y3.Add(t1, y3) // Y3 := t1 + Y3
+ t1.Add(t0, t0) // t1 := t0 + t0
+ t0.Add(t1, t0) // t0 := t1 + t0
+ t0.Sub(t0, t2) // t0 := t0 - t2
+ t1.Mul(t4, y3) // t1 := t4 * Y3
+ t2.Mul(t0, y3) // t2 := t0 * Y3
+ y3.Mul(x3, z3) // Y3 := X3 * Z3
+ y3.Add(y3, t2) // Y3 := Y3 + t2
+ x3.Mul(t3, x3) // X3 := t3 * X3
+ x3.Sub(x3, t1) // X3 := X3 - t1
+ z3.Mul(t4, z3) // Z3 := t4 * Z3
+ t1.Mul(t3, t0) // t1 := t3 * t0
+ z3.Add(z3, t1) // Z3 := Z3 + t1
+
+ q.x.Set(x3)
+ q.y.Set(y3)
+ q.z.Set(z3)
+ return q
+}
+
+// Double sets q = p + p, and returns q. The points may overlap.
+func (q *P521Point) Double(p *P521Point) *P521Point {
+ // Complete addition formula for a = -3 from "Complete addition formulas for
+ // prime order elliptic curves" (https://eprint.iacr.org/2015/1060), §A.2.
+
+ t0 := new(fiat.P521Element).Square(p.x) // t0 := X ^ 2
+ t1 := new(fiat.P521Element).Square(p.y) // t1 := Y ^ 2
+ t2 := new(fiat.P521Element).Square(p.z) // t2 := Z ^ 2
+ t3 := new(fiat.P521Element).Mul(p.x, p.y) // t3 := X * Y
+ t3.Add(t3, t3) // t3 := t3 + t3
+ z3 := new(fiat.P521Element).Mul(p.x, p.z) // Z3 := X * Z
+ z3.Add(z3, z3) // Z3 := Z3 + Z3
+ y3 := new(fiat.P521Element).Mul(p521B(), t2) // Y3 := b * t2
+ y3.Sub(y3, z3) // Y3 := Y3 - Z3
+ x3 := new(fiat.P521Element).Add(y3, y3) // X3 := Y3 + Y3
+ y3.Add(x3, y3) // Y3 := X3 + Y3
+ x3.Sub(t1, y3) // X3 := t1 - Y3
+ y3.Add(t1, y3) // Y3 := t1 + Y3
+ y3.Mul(x3, y3) // Y3 := X3 * Y3
+ x3.Mul(x3, t3) // X3 := X3 * t3
+ t3.Add(t2, t2) // t3 := t2 + t2
+ t2.Add(t2, t3) // t2 := t2 + t3
+ z3.Mul(p521B(), z3) // Z3 := b * Z3
+ z3.Sub(z3, t2) // Z3 := Z3 - t2
+ z3.Sub(z3, t0) // Z3 := Z3 - t0
+ t3.Add(z3, z3) // t3 := Z3 + Z3
+ z3.Add(z3, t3) // Z3 := Z3 + t3
+ t3.Add(t0, t0) // t3 := t0 + t0
+ t0.Add(t3, t0) // t0 := t3 + t0
+ t0.Sub(t0, t2) // t0 := t0 - t2
+ t0.Mul(t0, z3) // t0 := t0 * Z3
+ y3.Add(y3, t0) // Y3 := Y3 + t0
+ t0.Mul(p.y, p.z) // t0 := Y * Z
+ t0.Add(t0, t0) // t0 := t0 + t0
+ z3.Mul(t0, z3) // Z3 := t0 * Z3
+ x3.Sub(x3, z3) // X3 := X3 - Z3
+ z3.Mul(t0, t1) // Z3 := t0 * t1
+ z3.Add(z3, z3) // Z3 := Z3 + Z3
+ z3.Add(z3, z3) // Z3 := Z3 + Z3
+
+ q.x.Set(x3)
+ q.y.Set(y3)
+ q.z.Set(z3)
+ return q
+}
+
+// Select sets q to p1 if cond == 1, and to p2 if cond == 0.
+func (q *P521Point) Select(p1, p2 *P521Point, cond int) *P521Point {
+ q.x.Select(p1.x, p2.x, cond)
+ q.y.Select(p1.y, p2.y, cond)
+ q.z.Select(p1.z, p2.z, cond)
+ return q
+}
+
+// A p521Table holds the first 15 multiples of a point at offset -1, so [1]P
+// is at table[0], [15]P is at table[14], and [0]P is implicitly the identity
+// point.
+type p521Table [15]*P521Point
+
+// Select selects the n-th multiple of the table base point into p. It works in
+// constant time by iterating over every entry of the table. n must be in [0, 15].
+func (table *p521Table) Select(p *P521Point, n uint8) {
+ if n >= 16 {
+ panic("nistec: internal error: p521Table called with out-of-bounds value")
+ }
+ p.Set(NewP521Point())
+ for i := uint8(1); i < 16; i++ {
+ cond := subtle.ConstantTimeByteEq(i, n)
+ p.Select(table[i-1], p, cond)
+ }
+}
+
+// ScalarMult sets p = scalar * q, and returns p.
+func (p *P521Point) ScalarMult(q *P521Point, scalar []byte) (*P521Point, error) {
+ // Compute a p521Table for the base point q. The explicit NewP521Point
+ // calls get inlined, letting the allocations live on the stack.
+ var table = p521Table{NewP521Point(), NewP521Point(), NewP521Point(),
+ NewP521Point(), NewP521Point(), NewP521Point(), NewP521Point(),
+ NewP521Point(), NewP521Point(), NewP521Point(), NewP521Point(),
+ NewP521Point(), NewP521Point(), NewP521Point(), NewP521Point()}
+ table[0].Set(q)
+ for i := 1; i < 15; i += 2 {
+ table[i].Double(table[i/2])
+ table[i+1].Add(table[i], q)
+ }
+
+ // Instead of doing the classic double-and-add chain, we do it with a
+ // four-bit window: we double four times, and then add [0-15]P.
+ t := NewP521Point()
+ p.Set(NewP521Point())
+ for i, byte := range scalar {
+ // No need to double on the first iteration, as p is the identity at
+ // this point, and [N]∞ = ∞.
+ if i != 0 {
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+ }
+
+ windowValue := byte >> 4
+ table.Select(t, windowValue)
+ p.Add(p, t)
+
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+ p.Double(p)
+
+ windowValue = byte & 0b1111
+ table.Select(t, windowValue)
+ p.Add(p, t)
+ }
+
+ return p, nil
+}
+
+var p521GeneratorTable *[p521ElementLength * 2]p521Table
+var p521GeneratorTableOnce sync.Once
+
+// generatorTable returns a sequence of p521Tables. The first table contains
+// multiples of G. Each successive table is the previous table doubled four
+// times.
+func (p *P521Point) generatorTable() *[p521ElementLength * 2]p521Table {
+ p521GeneratorTableOnce.Do(func() {
+ p521GeneratorTable = new([p521ElementLength * 2]p521Table)
+ base := NewP521Point().SetGenerator()
+ for i := 0; i < p521ElementLength*2; i++ {
+ p521GeneratorTable[i][0] = NewP521Point().Set(base)
+ for j := 1; j < 15; j++ {
+ p521GeneratorTable[i][j] = NewP521Point().Add(p521GeneratorTable[i][j-1], base)
+ }
+ base.Double(base)
+ base.Double(base)
+ base.Double(base)
+ base.Double(base)
+ }
+ })
+ return p521GeneratorTable
+}
+
+// ScalarBaseMult sets p = scalar * B, where B is the canonical generator, and
+// returns p.
+func (p *P521Point) ScalarBaseMult(scalar []byte) (*P521Point, error) {
+ if len(scalar) != p521ElementLength {
+ return nil, errors.New("invalid scalar length")
+ }
+ tables := p.generatorTable()
+
+ // This is also a scalar multiplication with a four-bit window like in
+ // ScalarMult, but in this case the doublings are precomputed. The value
+ // [windowValue]G added at iteration k would normally get doubled
+ // (totIterations-k)×4 times, but with a larger precomputation we can
+ // instead add [2^((totIterations-k)×4)][windowValue]G and avoid the
+ // doublings between iterations.
+ t := NewP521Point()
+ p.Set(NewP521Point())
+ tableIndex := len(tables) - 1
+ for _, byte := range scalar {
+ windowValue := byte >> 4
+ tables[tableIndex].Select(t, windowValue)
+ p.Add(p, t)
+ tableIndex--
+
+ windowValue = byte & 0b1111
+ tables[tableIndex].Select(t, windowValue)
+ p.Add(p, t)
+ tableIndex--
+ }
+
+ return p, nil
+}
+
+// p521Sqrt sets e to a square root of x. If x is not a square, p521Sqrt returns
+// false and e is unchanged. e and x can overlap.
+func p521Sqrt(e, x *fiat.P521Element) (isSquare bool) {
+ candidate := new(fiat.P521Element)
+ p521SqrtCandidate(candidate, x)
+ square := new(fiat.P521Element).Square(candidate)
+ if square.Equal(x) != 1 {
+ return false
+ }
+ e.Set(candidate)
+ return true
+}
+
+// p521SqrtCandidate sets z to a square root candidate for x. z and x must not overlap.
+func p521SqrtCandidate(z, x *fiat.P521Element) {
+ // Since p = 3 mod 4, exponentiation by (p + 1) / 4 yields a square root candidate.
+ //
+ // The sequence of 0 multiplications and 519 squarings is derived from the
+ // following addition chain generated with github.com/mmcloughlin/addchain v0.4.0.
+ //
+ // return 1 << 519
+ //
+
+ z.Square(x)
+ for s := 1; s < 519; s++ {
+ z.Square(z)
+ }
+}
diff --git a/src/crypto/internal/randutil/randutil.go b/src/crypto/internal/randutil/randutil.go
new file mode 100644
index 0000000..84b1295
--- /dev/null
+++ b/src/crypto/internal/randutil/randutil.go
@@ -0,0 +1,38 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package randutil contains internal randomness utilities for various
+// crypto packages.
+package randutil
+
+import (
+ "io"
+ "sync"
+)
+
+var (
+ closedChanOnce sync.Once
+ closedChan chan struct{}
+)
+
+// MaybeReadByte reads a single byte from r with ~50% probability. This is used
+// to ensure that callers do not depend on non-guaranteed behaviour, e.g.
+// assuming that rsa.GenerateKey is deterministic w.r.t. a given random stream.
+//
+// This does not affect tests that pass a stream of fixed bytes as the random
+// source (e.g. a zeroReader).
+func MaybeReadByte(r io.Reader) {
+ closedChanOnce.Do(func() {
+ closedChan = make(chan struct{})
+ close(closedChan)
+ })
+
+ select {
+ case <-closedChan:
+ return
+ case <-closedChan:
+ var buf [1]byte
+ r.Read(buf[:])
+ }
+}
diff --git a/src/crypto/issue21104_test.go b/src/crypto/issue21104_test.go
new file mode 100644
index 0000000..4662088
--- /dev/null
+++ b/src/crypto/issue21104_test.go
@@ -0,0 +1,61 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package crypto_test
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/rc4"
+ "testing"
+)
+
+func TestRC4OutOfBoundsWrite(t *testing.T) {
+ // This cipherText is encrypted "0123456789"
+ cipherText := []byte{238, 41, 187, 114, 151, 2, 107, 13, 178, 63}
+ cipher, err := rc4.NewCipher([]byte{0})
+ if err != nil {
+ panic(err)
+ }
+ test(t, "RC4", cipherText, cipher.XORKeyStream)
+}
+func TestCTROutOfBoundsWrite(t *testing.T) {
+ testBlock(t, "CTR", cipher.NewCTR)
+}
+func TestOFBOutOfBoundsWrite(t *testing.T) {
+ testBlock(t, "OFB", cipher.NewOFB)
+}
+func TestCFBEncryptOutOfBoundsWrite(t *testing.T) {
+ testBlock(t, "CFB Encrypt", cipher.NewCFBEncrypter)
+}
+func TestCFBDecryptOutOfBoundsWrite(t *testing.T) {
+ testBlock(t, "CFB Decrypt", cipher.NewCFBDecrypter)
+}
+func testBlock(t *testing.T, name string, newCipher func(cipher.Block, []byte) cipher.Stream) {
+ // This cipherText is encrypted "0123456789"
+ cipherText := []byte{86, 216, 121, 231, 219, 191, 26, 12, 176, 117}
+ var iv, key [16]byte
+ block, err := aes.NewCipher(key[:])
+ if err != nil {
+ panic(err)
+ }
+ stream := newCipher(block, iv[:])
+ test(t, name, cipherText, stream.XORKeyStream)
+}
+func test(t *testing.T, name string, cipherText []byte, xor func([]byte, []byte)) {
+ want := "abcdefghij"
+ plainText := []byte(want)
+ shorterLen := len(cipherText) / 2
+ defer func() {
+ err := recover()
+ if err == nil {
+ t.Errorf("%v XORKeyStream expected to panic on len(dst) < len(src), but didn't", name)
+ }
+ const plain = "0123456789"
+ if plainText[shorterLen] == plain[shorterLen] {
+ t.Errorf("%v XORKeyStream did out of bounds write, want %v, got %v", name, want, string(plainText))
+ }
+ }()
+ xor(plainText[:shorterLen], cipherText)
+}
diff --git a/src/crypto/md5/example_test.go b/src/crypto/md5/example_test.go
new file mode 100644
index 0000000..af8c1bf
--- /dev/null
+++ b/src/crypto/md5/example_test.go
@@ -0,0 +1,42 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package md5_test
+
+import (
+ "crypto/md5"
+ "fmt"
+ "io"
+ "log"
+ "os"
+)
+
+func ExampleNew() {
+ h := md5.New()
+ io.WriteString(h, "The fog is getting thicker!")
+ io.WriteString(h, "And Leon's getting laaarger!")
+ fmt.Printf("%x", h.Sum(nil))
+ // Output: e2c569be17396eca2a2e3c11578123ed
+}
+
+func ExampleSum() {
+ data := []byte("These pretzels are making me thirsty.")
+ fmt.Printf("%x", md5.Sum(data))
+ // Output: b0804ec967f48520697662a204f5fe72
+}
+
+func ExampleNew_file() {
+ f, err := os.Open("file.txt")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+
+ h := md5.New()
+ if _, err := io.Copy(h, f); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("%x", h.Sum(nil))
+}
diff --git a/src/crypto/md5/gen.go b/src/crypto/md5/gen.go
new file mode 100644
index 0000000..cd2700a
--- /dev/null
+++ b/src/crypto/md5/gen.go
@@ -0,0 +1,259 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build ignore
+
+// This program generates md5block.go
+// Invoke as
+//
+// go run gen.go -output md5block.go
+
+package main
+
+import (
+ "bytes"
+ "flag"
+ "go/format"
+ "log"
+ "os"
+ "strings"
+ "text/template"
+)
+
+var filename = flag.String("output", "md5block.go", "output file name")
+
+func main() {
+ flag.Parse()
+
+ var buf bytes.Buffer
+
+ t := template.Must(template.New("main").Funcs(funcs).Parse(program))
+ if err := t.Execute(&buf, data); err != nil {
+ log.Fatal(err)
+ }
+
+ data, err := format.Source(buf.Bytes())
+ if err != nil {
+ log.Fatal(err)
+ }
+ err = os.WriteFile(*filename, data, 0644)
+ if err != nil {
+ log.Fatal(err)
+ }
+}
+
+type Data struct {
+ a, b, c, d string
+ Shift1 []int
+ Shift2 []int
+ Shift3 []int
+ Shift4 []int
+ Table1 []uint32
+ Table2 []uint32
+ Table3 []uint32
+ Table4 []uint32
+}
+
+var funcs = template.FuncMap{
+ "dup": dup,
+ "relabel": relabel,
+ "rotate": rotate,
+ "idx": idx,
+ "seq": seq,
+}
+
+func dup(count int, x []int) []int {
+ var out []int
+ for i := 0; i < count; i++ {
+ out = append(out, x...)
+ }
+ return out
+}
+
+func relabel(s string) string {
+ return strings.NewReplacer("arg0", data.a, "arg1", data.b, "arg2", data.c, "arg3", data.d).Replace(s)
+}
+
+func rotate() string {
+ data.a, data.b, data.c, data.d = data.d, data.a, data.b, data.c
+ return "" // no output
+}
+
+func idx(round, index int) int {
+ v := 0
+ switch round {
+ case 1:
+ v = index
+ case 2:
+ v = (1 + 5*index) & 15
+ case 3:
+ v = (5 + 3*index) & 15
+ case 4:
+ v = (7 * index) & 15
+ }
+ return v
+}
+
+func seq(i int) []int {
+ s := make([]int, i)
+ for i := range s {
+ s[i] = i
+ }
+ return s
+}
+
+var data = Data{
+ a: "a",
+ b: "b",
+ c: "c",
+ d: "d",
+ Shift1: []int{7, 12, 17, 22},
+ Shift2: []int{5, 9, 14, 20},
+ Shift3: []int{4, 11, 16, 23},
+ Shift4: []int{6, 10, 15, 21},
+
+ // table[i] = int((1<<32) * abs(sin(i+1 radians))).
+ Table1: []uint32{
+ // round 1
+ 0xd76aa478,
+ 0xe8c7b756,
+ 0x242070db,
+ 0xc1bdceee,
+ 0xf57c0faf,
+ 0x4787c62a,
+ 0xa8304613,
+ 0xfd469501,
+ 0x698098d8,
+ 0x8b44f7af,
+ 0xffff5bb1,
+ 0x895cd7be,
+ 0x6b901122,
+ 0xfd987193,
+ 0xa679438e,
+ 0x49b40821,
+ },
+ Table2: []uint32{
+ // round 2
+ 0xf61e2562,
+ 0xc040b340,
+ 0x265e5a51,
+ 0xe9b6c7aa,
+ 0xd62f105d,
+ 0x2441453,
+ 0xd8a1e681,
+ 0xe7d3fbc8,
+ 0x21e1cde6,
+ 0xc33707d6,
+ 0xf4d50d87,
+ 0x455a14ed,
+ 0xa9e3e905,
+ 0xfcefa3f8,
+ 0x676f02d9,
+ 0x8d2a4c8a,
+ },
+ Table3: []uint32{
+ // round3
+ 0xfffa3942,
+ 0x8771f681,
+ 0x6d9d6122,
+ 0xfde5380c,
+ 0xa4beea44,
+ 0x4bdecfa9,
+ 0xf6bb4b60,
+ 0xbebfbc70,
+ 0x289b7ec6,
+ 0xeaa127fa,
+ 0xd4ef3085,
+ 0x4881d05,
+ 0xd9d4d039,
+ 0xe6db99e5,
+ 0x1fa27cf8,
+ 0xc4ac5665,
+ },
+ Table4: []uint32{
+ // round 4
+ 0xf4292244,
+ 0x432aff97,
+ 0xab9423a7,
+ 0xfc93a039,
+ 0x655b59c3,
+ 0x8f0ccc92,
+ 0xffeff47d,
+ 0x85845dd1,
+ 0x6fa87e4f,
+ 0xfe2ce6e0,
+ 0xa3014314,
+ 0x4e0811a1,
+ 0xf7537e82,
+ 0xbd3af235,
+ 0x2ad7d2bb,
+ 0xeb86d391,
+ },
+}
+
+var program = `// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by go run gen.go -output md5block.go; DO NOT EDIT.
+
+package md5
+
+import (
+ "encoding/binary"
+ "math/bits"
+)
+
+func blockGeneric(dig *digest, p []byte) {
+ // load state
+ a, b, c, d := dig.s[0], dig.s[1], dig.s[2], dig.s[3]
+
+ for i := 0; i <= len(p)-BlockSize; i += BlockSize {
+ // eliminate bounds checks on p
+ q := p[i:]
+ q = q[:BlockSize:BlockSize]
+
+ // save current state
+ aa, bb, cc, dd := a, b, c, d
+
+ // load input block
+ {{range $i := seq 16 -}}
+ {{printf "x%x := binary.LittleEndian.Uint32(q[4*%#x:])" $i $i}}
+ {{end}}
+
+ // round 1
+ {{range $i, $s := dup 4 .Shift1 -}}
+ {{printf "arg0 = arg1 + bits.RotateLeft32((((arg2^arg3)&arg1)^arg3)+arg0+x%x+%#08x, %d)" (idx 1 $i) (index $.Table1 $i) $s | relabel}}
+ {{rotate -}}
+ {{end}}
+
+ // round 2
+ {{range $i, $s := dup 4 .Shift2 -}}
+ {{printf "arg0 = arg1 + bits.RotateLeft32((((arg1^arg2)&arg3)^arg2)+arg0+x%x+%#08x, %d)" (idx 2 $i) (index $.Table2 $i) $s | relabel}}
+ {{rotate -}}
+ {{end}}
+
+ // round 3
+ {{range $i, $s := dup 4 .Shift3 -}}
+ {{printf "arg0 = arg1 + bits.RotateLeft32((arg1^arg2^arg3)+arg0+x%x+%#08x, %d)" (idx 3 $i) (index $.Table3 $i) $s | relabel}}
+ {{rotate -}}
+ {{end}}
+
+ // round 4
+ {{range $i, $s := dup 4 .Shift4 -}}
+ {{printf "arg0 = arg1 + bits.RotateLeft32((arg2^(arg1|^arg3))+arg0+x%x+%#08x, %d)" (idx 4 $i) (index $.Table4 $i) $s | relabel}}
+ {{rotate -}}
+ {{end}}
+
+ // add saved state
+ a += aa
+ b += bb
+ c += cc
+ d += dd
+ }
+
+ // save state
+ dig.s[0], dig.s[1], dig.s[2], dig.s[3] = a, b, c, d
+}
+`
diff --git a/src/crypto/md5/md5.go b/src/crypto/md5/md5.go
new file mode 100644
index 0000000..ccee4ea
--- /dev/null
+++ b/src/crypto/md5/md5.go
@@ -0,0 +1,183 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:generate go run gen.go -output md5block.go
+
+// Package md5 implements the MD5 hash algorithm as defined in RFC 1321.
+//
+// MD5 is cryptographically broken and should not be used for secure
+// applications.
+package md5
+
+import (
+ "crypto"
+ "encoding/binary"
+ "errors"
+ "hash"
+)
+
+func init() {
+ crypto.RegisterHash(crypto.MD5, New)
+}
+
+// The size of an MD5 checksum in bytes.
+const Size = 16
+
+// The blocksize of MD5 in bytes.
+const BlockSize = 64
+
+const (
+ init0 = 0x67452301
+ init1 = 0xEFCDAB89
+ init2 = 0x98BADCFE
+ init3 = 0x10325476
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ s [4]uint32
+ x [BlockSize]byte
+ nx int
+ len uint64
+}
+
+func (d *digest) Reset() {
+ d.s[0] = init0
+ d.s[1] = init1
+ d.s[2] = init2
+ d.s[3] = init3
+ d.nx = 0
+ d.len = 0
+}
+
+const (
+ magic = "md5\x01"
+ marshaledSize = len(magic) + 4*4 + BlockSize + 8
+)
+
+func (d *digest) MarshalBinary() ([]byte, error) {
+ b := make([]byte, 0, marshaledSize)
+ b = append(b, magic...)
+ b = binary.BigEndian.AppendUint32(b, d.s[0])
+ b = binary.BigEndian.AppendUint32(b, d.s[1])
+ b = binary.BigEndian.AppendUint32(b, d.s[2])
+ b = binary.BigEndian.AppendUint32(b, d.s[3])
+ b = append(b, d.x[:d.nx]...)
+ b = b[:len(b)+len(d.x)-d.nx] // already zero
+ b = binary.BigEndian.AppendUint64(b, d.len)
+ return b, nil
+}
+
+func (d *digest) UnmarshalBinary(b []byte) error {
+ if len(b) < len(magic) || string(b[:len(magic)]) != magic {
+ return errors.New("crypto/md5: invalid hash state identifier")
+ }
+ if len(b) != marshaledSize {
+ return errors.New("crypto/md5: invalid hash state size")
+ }
+ b = b[len(magic):]
+ b, d.s[0] = consumeUint32(b)
+ b, d.s[1] = consumeUint32(b)
+ b, d.s[2] = consumeUint32(b)
+ b, d.s[3] = consumeUint32(b)
+ b = b[copy(d.x[:], b):]
+ b, d.len = consumeUint64(b)
+ d.nx = int(d.len % BlockSize)
+ return nil
+}
+
+func consumeUint64(b []byte) ([]byte, uint64) {
+ return b[8:], binary.BigEndian.Uint64(b[0:8])
+}
+
+func consumeUint32(b []byte) ([]byte, uint32) {
+ return b[4:], binary.BigEndian.Uint32(b[0:4])
+}
+
+// New returns a new hash.Hash computing the MD5 checksum. The Hash also
+// implements encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to
+// marshal and unmarshal the internal state of the hash.
+func New() hash.Hash {
+ d := new(digest)
+ d.Reset()
+ return d
+}
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) BlockSize() int { return BlockSize }
+
+func (d *digest) Write(p []byte) (nn int, err error) {
+ // Note that we currently call block or blockGeneric
+ // directly (guarded using haveAsm) because this allows
+ // escape analysis to see that p and d don't escape.
+ nn = len(p)
+ d.len += uint64(nn)
+ if d.nx > 0 {
+ n := copy(d.x[d.nx:], p)
+ d.nx += n
+ if d.nx == BlockSize {
+ if haveAsm {
+ block(d, d.x[:])
+ } else {
+ blockGeneric(d, d.x[:])
+ }
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ if len(p) >= BlockSize {
+ n := len(p) &^ (BlockSize - 1)
+ if haveAsm {
+ block(d, p[:n])
+ } else {
+ blockGeneric(d, p[:n])
+ }
+ p = p[n:]
+ }
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d *digest) Sum(in []byte) []byte {
+ // Make a copy of d so that caller can keep writing and summing.
+ d0 := *d
+ hash := d0.checkSum()
+ return append(in, hash[:]...)
+}
+
+func (d *digest) checkSum() [Size]byte {
+ // Append 0x80 to the end of the message and then append zeros
+ // until the length is a multiple of 56 bytes. Finally append
+ // 8 bytes representing the message length in bits.
+ //
+ // 1 byte end marker :: 0-63 padding bytes :: 8 byte length
+ tmp := [1 + 63 + 8]byte{0x80}
+ pad := (55 - d.len) % 64 // calculate number of padding bytes
+ binary.LittleEndian.PutUint64(tmp[1+pad:], d.len<<3) // append length in bits
+ d.Write(tmp[:1+pad+8])
+
+ // The previous write ensures that a whole number of
+ // blocks (i.e. a multiple of 64 bytes) have been hashed.
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ var digest [Size]byte
+ binary.LittleEndian.PutUint32(digest[0:], d.s[0])
+ binary.LittleEndian.PutUint32(digest[4:], d.s[1])
+ binary.LittleEndian.PutUint32(digest[8:], d.s[2])
+ binary.LittleEndian.PutUint32(digest[12:], d.s[3])
+ return digest
+}
+
+// Sum returns the MD5 checksum of the data.
+func Sum(data []byte) [Size]byte {
+ var d digest
+ d.Reset()
+ d.Write(data)
+ return d.checkSum()
+}
diff --git a/src/crypto/md5/md5_test.go b/src/crypto/md5/md5_test.go
new file mode 100644
index 0000000..851e7fb
--- /dev/null
+++ b/src/crypto/md5/md5_test.go
@@ -0,0 +1,294 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package md5
+
+import (
+ "bytes"
+ "crypto/rand"
+ "encoding"
+ "fmt"
+ "hash"
+ "io"
+ "testing"
+ "unsafe"
+)
+
+type md5Test struct {
+ out string
+ in string
+ halfState string // marshaled hash state after first half of in written, used by TestGoldenMarshal
+}
+
+var golden = []md5Test{
+ {"d41d8cd98f00b204e9800998ecf8427e", "", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102Tv\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"},
+ {"0cc175b9c0f1b6a831c399e269772661", "a", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102Tv\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"},
+ {"187ef4436122d1cc2f40dc2b92f0eba0", "ab", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102Tva\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"},
+ {"900150983cd24fb0d6963f7d28e17f72", "abc", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102Tva\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"},
+ {"e2fc714c4727ee9395f324cd2e7f331f", "abcd", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102Tvab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"},
+ {"ab56b4d92b40713acc5af89985d4b786", "abcde", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102Tvab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"},
+ {"e80b5017098950fc58aad83c8c14978e", "abcdef", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102Tvabc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03"},
+ {"7ac66c0f148de9519b8bd264312c4d64", "abcdefg", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102Tvabc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03"},
+ {"e8dc4081b13434b45189a720b77b6818", "abcdefgh", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102Tvabcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04"},
+ {"8aa99b1f439ff71293e95357bac6fd94", "abcdefghi", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102Tvabcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04"},
+ {"a925576942e94b2ef57a066101b48876", "abcdefghij", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102Tvabcde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05"},
+ {"d747fc1719c7eacb84058196cfe56d57", "Discard medicine more than two years old.", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvDiscard medicine mor\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14"},
+ {"bff2dcb37ef3a44ba43ab144768ca837", "He who has a shady past knows that nice guys finish last.", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvHe who has a shady past know\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"},
+ {"0441015ecb54a7342d017ed1bcfdbea5", "I wouldn't marry him with a ten foot pole.", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvI wouldn't marry him \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15"},
+ {"9e3cac8e9e9757a60c3ea391130d3689", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvFree! Free!/A trip/to Mars/f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"},
+ {"a0f04459b031f916a59a35cc482dc039", "The days of the digital watch are numbered. -Tom Stoppard", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvThe days of the digital watch\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d"},
+ {"e7a48e0fe884faf31475d2a04b1362cc", "Nepal premier won't resign.", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvNepal premier\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r"},
+ {"637d2fe925c07c113800509964fb0e06", "For every action there is an equal and opposite government program.", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvFor every action there is an equa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!"},
+ {"834a8d18d5c6562119cf4c7f5086cb71", "His money is twice tainted: 'taint yours and 'taint mine.", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvHis money is twice tainted: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"},
+ {"de3a4d2fd6c73ec2db2abad23b444281", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvThere is no reason for any individual to hav\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,"},
+ {"acf203f997e2cf74ea3aff86985aefaf", "It's a tiny change to the code and not completely disgusting. - Bob Manchek", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvIt's a tiny change to the code and no\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%"},
+ {"e1c1384cb4d2221dfdd7c795a4222c9a", "size: a.out: bad magic", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102Tvsize: a.out\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\f"},
+ {"c90f3ddecc54f34228c063d7525bf644", "The major problem is with sendmail. -Mark Horton", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvThe major problem is wit\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18"},
+ {"cdf7ab6c1fd49bd9933c43f3ea5af185", "Give me a rock, paper and scissors and I will move the world. CCFestoon", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvGive me a rock, paper and scissors a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$"},
+ {"83bc85234942fc883c063cbd7f0ad5d0", "If the enemy is within range, then so are you.", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvIf the enemy is within \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17"},
+ {"277cbe255686b48dd7e8f389394d9299", "It's well we cannot hear the screams/That we create in others' dreams.", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvIt's well we cannot hear the scream\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#"},
+ {"fd3fb0a7ffb8af16603f3d3af98f8e1f", "You remind me of a TV show, but that's all right: I watch it anyway.", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvYou remind me of a TV show, but th\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\""},
+ {"469b13a78ebf297ecda64d4723655154", "C is as portable as Stonehedge!!", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvC is as portable\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10"},
+ {"63eb3a2f466410104731c4b037600110", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvEven if I could be Shakespeare, I think I sh\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,"},
+ {"72c2ed7592debca1c90fc0100f931a2f", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", "md5\x01\xa7\xc9\x18\x9b\xc3E\x18\xf2\x82\xfd\xf3$\x9d_\v\nem\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B"},
+ {"132f7619d33b523b1d9e5bd8e0928355", "How can you write a big system without C++? -Paul Glick", "md5\x01gE#\x01\xefͫ\x89\x98\xba\xdc\xfe\x102TvHow can you write a big syst\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"},
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ s := fmt.Sprintf("%x", Sum([]byte(g.in)))
+ if s != g.out {
+ t.Fatalf("Sum function: md5(%s) = %s want %s", g.in, s, g.out)
+ }
+ c := New()
+ buf := make([]byte, len(g.in)+4)
+ for j := 0; j < 3+4; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else if j == 2 {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum(nil)
+ io.WriteString(c, g.in[len(g.in)/2:])
+ } else if j > 2 {
+ // test unaligned write
+ buf = buf[1:]
+ copy(buf, g.in)
+ c.Write(buf[:len(g.in)])
+ }
+ s := fmt.Sprintf("%x", c.Sum(nil))
+ if s != g.out {
+ t.Fatalf("md5[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+}
+
+func TestGoldenMarshal(t *testing.T) {
+ for _, g := range golden {
+ h := New()
+ h2 := New()
+
+ io.WriteString(h, g.in[:len(g.in)/2])
+
+ state, err := h.(encoding.BinaryMarshaler).MarshalBinary()
+ if err != nil {
+ t.Errorf("could not marshal: %v", err)
+ continue
+ }
+
+ if string(state) != g.halfState {
+ t.Errorf("md5(%q) state = %q, want %q", g.in, state, g.halfState)
+ continue
+ }
+
+ if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err != nil {
+ t.Errorf("could not unmarshal: %v", err)
+ continue
+ }
+
+ io.WriteString(h, g.in[len(g.in)/2:])
+ io.WriteString(h2, g.in[len(g.in)/2:])
+
+ if actual, actual2 := h.Sum(nil), h2.Sum(nil); !bytes.Equal(actual, actual2) {
+ t.Errorf("md5(%q) = 0x%x != marshaled 0x%x", g.in, actual, actual2)
+ }
+ }
+}
+
+func TestLarge(t *testing.T) {
+ const N = 10000
+ ok := "2bb571599a4180e1d542f76904adc3df" // md5sum of "0123456789" * 1000
+ block := make([]byte, 10004)
+ c := New()
+ for offset := 0; offset < 4; offset++ {
+ for i := 0; i < N; i++ {
+ block[offset+i] = '0' + byte(i%10)
+ }
+ for blockSize := 10; blockSize <= N; blockSize *= 10 {
+ blocks := N / blockSize
+ b := block[offset : offset+blockSize]
+ c.Reset()
+ for i := 0; i < blocks; i++ {
+ c.Write(b)
+ }
+ s := fmt.Sprintf("%x", c.Sum(nil))
+ if s != ok {
+ t.Fatalf("md5 TestLarge offset=%d, blockSize=%d = %s want %s", offset, blockSize, s, ok)
+ }
+ }
+ }
+}
+
+// Tests that blockGeneric (pure Go) and block (in assembly for amd64, 386, arm) match.
+func TestBlockGeneric(t *testing.T) {
+ gen, asm := New().(*digest), New().(*digest)
+ buf := make([]byte, BlockSize*20) // arbitrary factor
+ rand.Read(buf)
+ blockGeneric(gen, buf)
+ block(asm, buf)
+ if *gen != *asm {
+ t.Error("block and blockGeneric resulted in different states")
+ }
+}
+
+// Tests for unmarshaling hashes that have hashed a large amount of data
+// The initial hash generation is omitted from the test, because it takes a long time.
+// The test contains some already-generated states, and their expected sums
+// Tests a problem that is outlined in GitHub issue #29541
+// The problem is triggered when an amount of data has been hashed for which
+// the data length has a 1 in the 32nd bit. When casted to int, this changes
+// the sign of the value, and causes the modulus operation to return a
+// different result.
+type unmarshalTest struct {
+ state string
+ sum string
+}
+
+var largeUnmarshalTests = []unmarshalTest{
+ // Data length: 7_102_415_735
+ {
+ state: "md5\x01\xa5\xf7\xf0=\xd6S\x85\xd9M\n}\xc3\u0601\x89\xe7@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuv\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xa7VCw",
+ sum: "cddefcf74ffec709a0b45a6a987564d5",
+ },
+ // Data length: 6_565_544_823
+ {
+ state: "md5\x01{\xda\x1a\xc7\xc9'?\x83EX\xe0\x88q\xfeG\x18@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuv\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x87VCw",
+ sum: "fd9f41874ab240698e7bc9c3ae70c8e4",
+ },
+}
+
+func safeSum(h hash.Hash) (sum []byte, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = fmt.Errorf("sum panic: %v", r)
+ }
+ }()
+
+ return h.Sum(nil), nil
+}
+
+func TestLargeHashes(t *testing.T) {
+ for i, test := range largeUnmarshalTests {
+
+ h := New()
+ if err := h.(encoding.BinaryUnmarshaler).UnmarshalBinary([]byte(test.state)); err != nil {
+ t.Errorf("test %d could not unmarshal: %v", i, err)
+ continue
+ }
+
+ sum, err := safeSum(h)
+ if err != nil {
+ t.Errorf("test %d could not sum: %v", i, err)
+ continue
+ }
+
+ if fmt.Sprintf("%x", sum) != test.sum {
+ t.Errorf("test %d sum mismatch: expect %s got %x", i, test.sum, sum)
+ }
+ }
+}
+
+func TestAllocations(t *testing.T) {
+ in := []byte("hello, world!")
+ out := make([]byte, 0, Size)
+ h := New()
+ n := int(testing.AllocsPerRun(10, func() {
+ h.Reset()
+ h.Write(in)
+ out = h.Sum(out[:0])
+ }))
+ if n > 0 {
+ t.Errorf("allocs = %d, want 0", n)
+ }
+}
+
+var bench = New()
+var buf = make([]byte, 1024*1024*8+1)
+var sum = make([]byte, bench.Size())
+
+func benchmarkSize(b *testing.B, size int, unaligned bool) {
+ b.SetBytes(int64(size))
+ buf := buf
+ if unaligned {
+ if uintptr(unsafe.Pointer(&buf[0]))&(unsafe.Alignof(uint32(0))-1) == 0 {
+ buf = buf[1:]
+ }
+ }
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ bench.Reset()
+ bench.Write(buf[:size])
+ bench.Sum(sum[:0])
+ }
+}
+
+func BenchmarkHash8Bytes(b *testing.B) {
+ benchmarkSize(b, 8, false)
+}
+
+func BenchmarkHash64(b *testing.B) {
+ benchmarkSize(b, 64, false)
+}
+
+func BenchmarkHash128(b *testing.B) {
+ benchmarkSize(b, 128, false)
+}
+
+func BenchmarkHash256(b *testing.B) {
+ benchmarkSize(b, 256, false)
+}
+
+func BenchmarkHash512(b *testing.B) {
+ benchmarkSize(b, 512, false)
+}
+
+func BenchmarkHash1K(b *testing.B) {
+ benchmarkSize(b, 1024, false)
+}
+
+func BenchmarkHash8K(b *testing.B) {
+ benchmarkSize(b, 8192, false)
+}
+
+func BenchmarkHash1M(b *testing.B) {
+ benchmarkSize(b, 1024*1024, false)
+}
+
+func BenchmarkHash8M(b *testing.B) {
+ benchmarkSize(b, 8*1024*1024, false)
+}
+
+func BenchmarkHash8BytesUnaligned(b *testing.B) {
+ benchmarkSize(b, 8, true)
+}
+
+func BenchmarkHash1KUnaligned(b *testing.B) {
+ benchmarkSize(b, 1024, true)
+}
+
+func BenchmarkHash8KUnaligned(b *testing.B) {
+ benchmarkSize(b, 8192, true)
+}
diff --git a/src/crypto/md5/md5block.go b/src/crypto/md5/md5block.go
new file mode 100644
index 0000000..4ff289e
--- /dev/null
+++ b/src/crypto/md5/md5block.go
@@ -0,0 +1,125 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Code generated by go run gen.go -output md5block.go; DO NOT EDIT.
+
+package md5
+
+import (
+ "encoding/binary"
+ "math/bits"
+)
+
+func blockGeneric(dig *digest, p []byte) {
+ // load state
+ a, b, c, d := dig.s[0], dig.s[1], dig.s[2], dig.s[3]
+
+ for i := 0; i <= len(p)-BlockSize; i += BlockSize {
+ // eliminate bounds checks on p
+ q := p[i:]
+ q = q[:BlockSize:BlockSize]
+
+ // save current state
+ aa, bb, cc, dd := a, b, c, d
+
+ // load input block
+ x0 := binary.LittleEndian.Uint32(q[4*0x0:])
+ x1 := binary.LittleEndian.Uint32(q[4*0x1:])
+ x2 := binary.LittleEndian.Uint32(q[4*0x2:])
+ x3 := binary.LittleEndian.Uint32(q[4*0x3:])
+ x4 := binary.LittleEndian.Uint32(q[4*0x4:])
+ x5 := binary.LittleEndian.Uint32(q[4*0x5:])
+ x6 := binary.LittleEndian.Uint32(q[4*0x6:])
+ x7 := binary.LittleEndian.Uint32(q[4*0x7:])
+ x8 := binary.LittleEndian.Uint32(q[4*0x8:])
+ x9 := binary.LittleEndian.Uint32(q[4*0x9:])
+ xa := binary.LittleEndian.Uint32(q[4*0xa:])
+ xb := binary.LittleEndian.Uint32(q[4*0xb:])
+ xc := binary.LittleEndian.Uint32(q[4*0xc:])
+ xd := binary.LittleEndian.Uint32(q[4*0xd:])
+ xe := binary.LittleEndian.Uint32(q[4*0xe:])
+ xf := binary.LittleEndian.Uint32(q[4*0xf:])
+
+ // round 1
+ a = b + bits.RotateLeft32((((c^d)&b)^d)+a+x0+0xd76aa478, 7)
+ d = a + bits.RotateLeft32((((b^c)&a)^c)+d+x1+0xe8c7b756, 12)
+ c = d + bits.RotateLeft32((((a^b)&d)^b)+c+x2+0x242070db, 17)
+ b = c + bits.RotateLeft32((((d^a)&c)^a)+b+x3+0xc1bdceee, 22)
+ a = b + bits.RotateLeft32((((c^d)&b)^d)+a+x4+0xf57c0faf, 7)
+ d = a + bits.RotateLeft32((((b^c)&a)^c)+d+x5+0x4787c62a, 12)
+ c = d + bits.RotateLeft32((((a^b)&d)^b)+c+x6+0xa8304613, 17)
+ b = c + bits.RotateLeft32((((d^a)&c)^a)+b+x7+0xfd469501, 22)
+ a = b + bits.RotateLeft32((((c^d)&b)^d)+a+x8+0x698098d8, 7)
+ d = a + bits.RotateLeft32((((b^c)&a)^c)+d+x9+0x8b44f7af, 12)
+ c = d + bits.RotateLeft32((((a^b)&d)^b)+c+xa+0xffff5bb1, 17)
+ b = c + bits.RotateLeft32((((d^a)&c)^a)+b+xb+0x895cd7be, 22)
+ a = b + bits.RotateLeft32((((c^d)&b)^d)+a+xc+0x6b901122, 7)
+ d = a + bits.RotateLeft32((((b^c)&a)^c)+d+xd+0xfd987193, 12)
+ c = d + bits.RotateLeft32((((a^b)&d)^b)+c+xe+0xa679438e, 17)
+ b = c + bits.RotateLeft32((((d^a)&c)^a)+b+xf+0x49b40821, 22)
+
+ // round 2
+ a = b + bits.RotateLeft32((((b^c)&d)^c)+a+x1+0xf61e2562, 5)
+ d = a + bits.RotateLeft32((((a^b)&c)^b)+d+x6+0xc040b340, 9)
+ c = d + bits.RotateLeft32((((d^a)&b)^a)+c+xb+0x265e5a51, 14)
+ b = c + bits.RotateLeft32((((c^d)&a)^d)+b+x0+0xe9b6c7aa, 20)
+ a = b + bits.RotateLeft32((((b^c)&d)^c)+a+x5+0xd62f105d, 5)
+ d = a + bits.RotateLeft32((((a^b)&c)^b)+d+xa+0x02441453, 9)
+ c = d + bits.RotateLeft32((((d^a)&b)^a)+c+xf+0xd8a1e681, 14)
+ b = c + bits.RotateLeft32((((c^d)&a)^d)+b+x4+0xe7d3fbc8, 20)
+ a = b + bits.RotateLeft32((((b^c)&d)^c)+a+x9+0x21e1cde6, 5)
+ d = a + bits.RotateLeft32((((a^b)&c)^b)+d+xe+0xc33707d6, 9)
+ c = d + bits.RotateLeft32((((d^a)&b)^a)+c+x3+0xf4d50d87, 14)
+ b = c + bits.RotateLeft32((((c^d)&a)^d)+b+x8+0x455a14ed, 20)
+ a = b + bits.RotateLeft32((((b^c)&d)^c)+a+xd+0xa9e3e905, 5)
+ d = a + bits.RotateLeft32((((a^b)&c)^b)+d+x2+0xfcefa3f8, 9)
+ c = d + bits.RotateLeft32((((d^a)&b)^a)+c+x7+0x676f02d9, 14)
+ b = c + bits.RotateLeft32((((c^d)&a)^d)+b+xc+0x8d2a4c8a, 20)
+
+ // round 3
+ a = b + bits.RotateLeft32((b^c^d)+a+x5+0xfffa3942, 4)
+ d = a + bits.RotateLeft32((a^b^c)+d+x8+0x8771f681, 11)
+ c = d + bits.RotateLeft32((d^a^b)+c+xb+0x6d9d6122, 16)
+ b = c + bits.RotateLeft32((c^d^a)+b+xe+0xfde5380c, 23)
+ a = b + bits.RotateLeft32((b^c^d)+a+x1+0xa4beea44, 4)
+ d = a + bits.RotateLeft32((a^b^c)+d+x4+0x4bdecfa9, 11)
+ c = d + bits.RotateLeft32((d^a^b)+c+x7+0xf6bb4b60, 16)
+ b = c + bits.RotateLeft32((c^d^a)+b+xa+0xbebfbc70, 23)
+ a = b + bits.RotateLeft32((b^c^d)+a+xd+0x289b7ec6, 4)
+ d = a + bits.RotateLeft32((a^b^c)+d+x0+0xeaa127fa, 11)
+ c = d + bits.RotateLeft32((d^a^b)+c+x3+0xd4ef3085, 16)
+ b = c + bits.RotateLeft32((c^d^a)+b+x6+0x04881d05, 23)
+ a = b + bits.RotateLeft32((b^c^d)+a+x9+0xd9d4d039, 4)
+ d = a + bits.RotateLeft32((a^b^c)+d+xc+0xe6db99e5, 11)
+ c = d + bits.RotateLeft32((d^a^b)+c+xf+0x1fa27cf8, 16)
+ b = c + bits.RotateLeft32((c^d^a)+b+x2+0xc4ac5665, 23)
+
+ // round 4
+ a = b + bits.RotateLeft32((c^(b|^d))+a+x0+0xf4292244, 6)
+ d = a + bits.RotateLeft32((b^(a|^c))+d+x7+0x432aff97, 10)
+ c = d + bits.RotateLeft32((a^(d|^b))+c+xe+0xab9423a7, 15)
+ b = c + bits.RotateLeft32((d^(c|^a))+b+x5+0xfc93a039, 21)
+ a = b + bits.RotateLeft32((c^(b|^d))+a+xc+0x655b59c3, 6)
+ d = a + bits.RotateLeft32((b^(a|^c))+d+x3+0x8f0ccc92, 10)
+ c = d + bits.RotateLeft32((a^(d|^b))+c+xa+0xffeff47d, 15)
+ b = c + bits.RotateLeft32((d^(c|^a))+b+x1+0x85845dd1, 21)
+ a = b + bits.RotateLeft32((c^(b|^d))+a+x8+0x6fa87e4f, 6)
+ d = a + bits.RotateLeft32((b^(a|^c))+d+xf+0xfe2ce6e0, 10)
+ c = d + bits.RotateLeft32((a^(d|^b))+c+x6+0xa3014314, 15)
+ b = c + bits.RotateLeft32((d^(c|^a))+b+xd+0x4e0811a1, 21)
+ a = b + bits.RotateLeft32((c^(b|^d))+a+x4+0xf7537e82, 6)
+ d = a + bits.RotateLeft32((b^(a|^c))+d+xb+0xbd3af235, 10)
+ c = d + bits.RotateLeft32((a^(d|^b))+c+x2+0x2ad7d2bb, 15)
+ b = c + bits.RotateLeft32((d^(c|^a))+b+x9+0xeb86d391, 21)
+
+ // add saved state
+ a += aa
+ b += bb
+ c += cc
+ d += dd
+ }
+
+ // save state
+ dig.s[0], dig.s[1], dig.s[2], dig.s[3] = a, b, c, d
+}
diff --git a/src/crypto/md5/md5block_386.s b/src/crypto/md5/md5block_386.s
new file mode 100644
index 0000000..30d4209
--- /dev/null
+++ b/src/crypto/md5/md5block_386.s
@@ -0,0 +1,182 @@
+// Original source:
+// http://www.zorinaq.com/papers/md5-amd64.html
+// http://www.zorinaq.com/papers/md5-amd64.tar.bz2
+//
+// Translated from Perl generating GNU assembly into
+// #defines generating 8a assembly, and adjusted for 386,
+// by the Go Authors.
+
+#include "textflag.h"
+
+// MD5 optimized for AMD64.
+//
+// Author: Marc Bevand <bevand_m (at) epita.fr>
+// Licence: I hereby disclaim the copyright on this code and place it
+// in the public domain.
+
+#define ROUND1(a, b, c, d, index, const, shift) \
+ XORL c, BP; \
+ LEAL const(a)(DI*1), a; \
+ ANDL b, BP; \
+ XORL d, BP; \
+ MOVL (index*4)(SI), DI; \
+ ADDL BP, a; \
+ ROLL $shift, a; \
+ MOVL c, BP; \
+ ADDL b, a
+
+#define ROUND2(a, b, c, d, index, const, shift) \
+ LEAL const(a)(DI*1),a; \
+ MOVL d, DI; \
+ ANDL b, DI; \
+ MOVL d, BP; \
+ NOTL BP; \
+ ANDL c, BP; \
+ ORL DI, BP; \
+ MOVL (index*4)(SI),DI; \
+ ADDL BP, a; \
+ ROLL $shift, a; \
+ ADDL b, a
+
+#define ROUND3(a, b, c, d, index, const, shift) \
+ LEAL const(a)(DI*1),a; \
+ MOVL (index*4)(SI),DI; \
+ XORL d, BP; \
+ XORL b, BP; \
+ ADDL BP, a; \
+ ROLL $shift, a; \
+ MOVL b, BP; \
+ ADDL b, a
+
+#define ROUND4(a, b, c, d, index, const, shift) \
+ LEAL const(a)(DI*1),a; \
+ ORL b, BP; \
+ XORL c, BP; \
+ ADDL BP, a; \
+ MOVL (index*4)(SI),DI; \
+ MOVL $0xffffffff, BP; \
+ ROLL $shift, a; \
+ XORL c, BP; \
+ ADDL b, a
+
+TEXT ·block(SB),NOSPLIT,$24-16
+ MOVL dig+0(FP), BP
+ MOVL p+4(FP), SI
+ MOVL p_len+8(FP), DX
+ SHRL $6, DX
+ SHLL $6, DX
+
+ LEAL (SI)(DX*1), DI
+ MOVL (0*4)(BP), AX
+ MOVL (1*4)(BP), BX
+ MOVL (2*4)(BP), CX
+ MOVL (3*4)(BP), DX
+
+ CMPL SI, DI
+ JEQ end
+
+ MOVL DI, 16(SP)
+
+loop:
+ MOVL AX, 0(SP)
+ MOVL BX, 4(SP)
+ MOVL CX, 8(SP)
+ MOVL DX, 12(SP)
+
+ MOVL (0*4)(SI), DI
+ MOVL DX, BP
+
+ ROUND1(AX,BX,CX,DX, 1,0xd76aa478, 7);
+ ROUND1(DX,AX,BX,CX, 2,0xe8c7b756,12);
+ ROUND1(CX,DX,AX,BX, 3,0x242070db,17);
+ ROUND1(BX,CX,DX,AX, 4,0xc1bdceee,22);
+ ROUND1(AX,BX,CX,DX, 5,0xf57c0faf, 7);
+ ROUND1(DX,AX,BX,CX, 6,0x4787c62a,12);
+ ROUND1(CX,DX,AX,BX, 7,0xa8304613,17);
+ ROUND1(BX,CX,DX,AX, 8,0xfd469501,22);
+ ROUND1(AX,BX,CX,DX, 9,0x698098d8, 7);
+ ROUND1(DX,AX,BX,CX,10,0x8b44f7af,12);
+ ROUND1(CX,DX,AX,BX,11,0xffff5bb1,17);
+ ROUND1(BX,CX,DX,AX,12,0x895cd7be,22);
+ ROUND1(AX,BX,CX,DX,13,0x6b901122, 7);
+ ROUND1(DX,AX,BX,CX,14,0xfd987193,12);
+ ROUND1(CX,DX,AX,BX,15,0xa679438e,17);
+ ROUND1(BX,CX,DX,AX, 0,0x49b40821,22);
+
+ MOVL (1*4)(SI), DI
+ MOVL DX, BP
+
+ ROUND2(AX,BX,CX,DX, 6,0xf61e2562, 5);
+ ROUND2(DX,AX,BX,CX,11,0xc040b340, 9);
+ ROUND2(CX,DX,AX,BX, 0,0x265e5a51,14);
+ ROUND2(BX,CX,DX,AX, 5,0xe9b6c7aa,20);
+ ROUND2(AX,BX,CX,DX,10,0xd62f105d, 5);
+ ROUND2(DX,AX,BX,CX,15, 0x2441453, 9);
+ ROUND2(CX,DX,AX,BX, 4,0xd8a1e681,14);
+ ROUND2(BX,CX,DX,AX, 9,0xe7d3fbc8,20);
+ ROUND2(AX,BX,CX,DX,14,0x21e1cde6, 5);
+ ROUND2(DX,AX,BX,CX, 3,0xc33707d6, 9);
+ ROUND2(CX,DX,AX,BX, 8,0xf4d50d87,14);
+ ROUND2(BX,CX,DX,AX,13,0x455a14ed,20);
+ ROUND2(AX,BX,CX,DX, 2,0xa9e3e905, 5);
+ ROUND2(DX,AX,BX,CX, 7,0xfcefa3f8, 9);
+ ROUND2(CX,DX,AX,BX,12,0x676f02d9,14);
+ ROUND2(BX,CX,DX,AX, 0,0x8d2a4c8a,20);
+
+ MOVL (5*4)(SI), DI
+ MOVL CX, BP
+
+ ROUND3(AX,BX,CX,DX, 8,0xfffa3942, 4);
+ ROUND3(DX,AX,BX,CX,11,0x8771f681,11);
+ ROUND3(CX,DX,AX,BX,14,0x6d9d6122,16);
+ ROUND3(BX,CX,DX,AX, 1,0xfde5380c,23);
+ ROUND3(AX,BX,CX,DX, 4,0xa4beea44, 4);
+ ROUND3(DX,AX,BX,CX, 7,0x4bdecfa9,11);
+ ROUND3(CX,DX,AX,BX,10,0xf6bb4b60,16);
+ ROUND3(BX,CX,DX,AX,13,0xbebfbc70,23);
+ ROUND3(AX,BX,CX,DX, 0,0x289b7ec6, 4);
+ ROUND3(DX,AX,BX,CX, 3,0xeaa127fa,11);
+ ROUND3(CX,DX,AX,BX, 6,0xd4ef3085,16);
+ ROUND3(BX,CX,DX,AX, 9, 0x4881d05,23);
+ ROUND3(AX,BX,CX,DX,12,0xd9d4d039, 4);
+ ROUND3(DX,AX,BX,CX,15,0xe6db99e5,11);
+ ROUND3(CX,DX,AX,BX, 2,0x1fa27cf8,16);
+ ROUND3(BX,CX,DX,AX, 0,0xc4ac5665,23);
+
+ MOVL (0*4)(SI), DI
+ MOVL $0xffffffff, BP
+ XORL DX, BP
+
+ ROUND4(AX,BX,CX,DX, 7,0xf4292244, 6);
+ ROUND4(DX,AX,BX,CX,14,0x432aff97,10);
+ ROUND4(CX,DX,AX,BX, 5,0xab9423a7,15);
+ ROUND4(BX,CX,DX,AX,12,0xfc93a039,21);
+ ROUND4(AX,BX,CX,DX, 3,0x655b59c3, 6);
+ ROUND4(DX,AX,BX,CX,10,0x8f0ccc92,10);
+ ROUND4(CX,DX,AX,BX, 1,0xffeff47d,15);
+ ROUND4(BX,CX,DX,AX, 8,0x85845dd1,21);
+ ROUND4(AX,BX,CX,DX,15,0x6fa87e4f, 6);
+ ROUND4(DX,AX,BX,CX, 6,0xfe2ce6e0,10);
+ ROUND4(CX,DX,AX,BX,13,0xa3014314,15);
+ ROUND4(BX,CX,DX,AX, 4,0x4e0811a1,21);
+ ROUND4(AX,BX,CX,DX,11,0xf7537e82, 6);
+ ROUND4(DX,AX,BX,CX, 2,0xbd3af235,10);
+ ROUND4(CX,DX,AX,BX, 9,0x2ad7d2bb,15);
+ ROUND4(BX,CX,DX,AX, 0,0xeb86d391,21);
+
+ ADDL 0(SP), AX
+ ADDL 4(SP), BX
+ ADDL 8(SP), CX
+ ADDL 12(SP), DX
+
+ ADDL $64, SI
+ CMPL SI, 16(SP)
+ JB loop
+
+end:
+ MOVL dig+0(FP), BP
+ MOVL AX, (0*4)(BP)
+ MOVL BX, (1*4)(BP)
+ MOVL CX, (2*4)(BP)
+ MOVL DX, (3*4)(BP)
+ RET
diff --git a/src/crypto/md5/md5block_amd64.s b/src/crypto/md5/md5block_amd64.s
new file mode 100644
index 0000000..7c7d92d
--- /dev/null
+++ b/src/crypto/md5/md5block_amd64.s
@@ -0,0 +1,179 @@
+// Original source:
+// http://www.zorinaq.com/papers/md5-amd64.html
+// http://www.zorinaq.com/papers/md5-amd64.tar.bz2
+//
+// Translated from Perl generating GNU assembly into
+// #defines generating 6a assembly by the Go Authors.
+
+#include "textflag.h"
+
+// MD5 optimized for AMD64.
+//
+// Author: Marc Bevand <bevand_m (at) epita.fr>
+// Licence: I hereby disclaim the copyright on this code and place it
+// in the public domain.
+
+TEXT ·block(SB),NOSPLIT,$8-32
+ MOVQ dig+0(FP), BP
+ MOVQ p+8(FP), SI
+ MOVQ p_len+16(FP), DX
+ SHRQ $6, DX
+ SHLQ $6, DX
+
+ LEAQ (SI)(DX*1), DI
+ MOVL (0*4)(BP), AX
+ MOVL (1*4)(BP), BX
+ MOVL (2*4)(BP), CX
+ MOVL (3*4)(BP), DX
+
+ CMPQ SI, DI
+ JEQ end
+
+loop:
+ MOVL AX, R12
+ MOVL BX, R13
+ MOVL CX, R14
+ MOVL DX, R15
+
+ MOVL (0*4)(SI), R8
+ MOVL DX, R9
+
+#define ROUND1(a, b, c, d, index, const, shift) \
+ XORL c, R9; \
+ LEAL const(a)(R8*1), a; \
+ ANDL b, R9; \
+ XORL d, R9; \
+ MOVL (index*4)(SI), R8; \
+ ADDL R9, a; \
+ ROLL $shift, a; \
+ MOVL c, R9; \
+ ADDL b, a
+
+ ROUND1(AX,BX,CX,DX, 1,0xd76aa478, 7);
+ ROUND1(DX,AX,BX,CX, 2,0xe8c7b756,12);
+ ROUND1(CX,DX,AX,BX, 3,0x242070db,17);
+ ROUND1(BX,CX,DX,AX, 4,0xc1bdceee,22);
+ ROUND1(AX,BX,CX,DX, 5,0xf57c0faf, 7);
+ ROUND1(DX,AX,BX,CX, 6,0x4787c62a,12);
+ ROUND1(CX,DX,AX,BX, 7,0xa8304613,17);
+ ROUND1(BX,CX,DX,AX, 8,0xfd469501,22);
+ ROUND1(AX,BX,CX,DX, 9,0x698098d8, 7);
+ ROUND1(DX,AX,BX,CX,10,0x8b44f7af,12);
+ ROUND1(CX,DX,AX,BX,11,0xffff5bb1,17);
+ ROUND1(BX,CX,DX,AX,12,0x895cd7be,22);
+ ROUND1(AX,BX,CX,DX,13,0x6b901122, 7);
+ ROUND1(DX,AX,BX,CX,14,0xfd987193,12);
+ ROUND1(CX,DX,AX,BX,15,0xa679438e,17);
+ ROUND1(BX,CX,DX,AX, 0,0x49b40821,22);
+
+ MOVL (1*4)(SI), R8
+ MOVL DX, R9
+ MOVL DX, R10
+
+#define ROUND2(a, b, c, d, index, const, shift) \
+ NOTL R9; \
+ LEAL const(a)(R8*1),a; \
+ ANDL b, R10; \
+ ANDL c, R9; \
+ MOVL (index*4)(SI),R8; \
+ ORL R9, R10; \
+ MOVL c, R9; \
+ ADDL R10, a; \
+ MOVL c, R10; \
+ ROLL $shift, a; \
+ ADDL b, a
+
+ ROUND2(AX,BX,CX,DX, 6,0xf61e2562, 5);
+ ROUND2(DX,AX,BX,CX,11,0xc040b340, 9);
+ ROUND2(CX,DX,AX,BX, 0,0x265e5a51,14);
+ ROUND2(BX,CX,DX,AX, 5,0xe9b6c7aa,20);
+ ROUND2(AX,BX,CX,DX,10,0xd62f105d, 5);
+ ROUND2(DX,AX,BX,CX,15, 0x2441453, 9);
+ ROUND2(CX,DX,AX,BX, 4,0xd8a1e681,14);
+ ROUND2(BX,CX,DX,AX, 9,0xe7d3fbc8,20);
+ ROUND2(AX,BX,CX,DX,14,0x21e1cde6, 5);
+ ROUND2(DX,AX,BX,CX, 3,0xc33707d6, 9);
+ ROUND2(CX,DX,AX,BX, 8,0xf4d50d87,14);
+ ROUND2(BX,CX,DX,AX,13,0x455a14ed,20);
+ ROUND2(AX,BX,CX,DX, 2,0xa9e3e905, 5);
+ ROUND2(DX,AX,BX,CX, 7,0xfcefa3f8, 9);
+ ROUND2(CX,DX,AX,BX,12,0x676f02d9,14);
+ ROUND2(BX,CX,DX,AX, 0,0x8d2a4c8a,20);
+
+ MOVL (5*4)(SI), R8
+ MOVL CX, R9
+
+#define ROUND3(a, b, c, d, index, const, shift) \
+ LEAL const(a)(R8*1),a; \
+ MOVL (index*4)(SI),R8; \
+ XORL d, R9; \
+ XORL b, R9; \
+ ADDL R9, a; \
+ ROLL $shift, a; \
+ MOVL b, R9; \
+ ADDL b, a
+
+ ROUND3(AX,BX,CX,DX, 8,0xfffa3942, 4);
+ ROUND3(DX,AX,BX,CX,11,0x8771f681,11);
+ ROUND3(CX,DX,AX,BX,14,0x6d9d6122,16);
+ ROUND3(BX,CX,DX,AX, 1,0xfde5380c,23);
+ ROUND3(AX,BX,CX,DX, 4,0xa4beea44, 4);
+ ROUND3(DX,AX,BX,CX, 7,0x4bdecfa9,11);
+ ROUND3(CX,DX,AX,BX,10,0xf6bb4b60,16);
+ ROUND3(BX,CX,DX,AX,13,0xbebfbc70,23);
+ ROUND3(AX,BX,CX,DX, 0,0x289b7ec6, 4);
+ ROUND3(DX,AX,BX,CX, 3,0xeaa127fa,11);
+ ROUND3(CX,DX,AX,BX, 6,0xd4ef3085,16);
+ ROUND3(BX,CX,DX,AX, 9, 0x4881d05,23);
+ ROUND3(AX,BX,CX,DX,12,0xd9d4d039, 4);
+ ROUND3(DX,AX,BX,CX,15,0xe6db99e5,11);
+ ROUND3(CX,DX,AX,BX, 2,0x1fa27cf8,16);
+ ROUND3(BX,CX,DX,AX, 0,0xc4ac5665,23);
+
+ MOVL (0*4)(SI), R8
+ MOVL $0xffffffff, R9
+ XORL DX, R9
+
+#define ROUND4(a, b, c, d, index, const, shift) \
+ LEAL const(a)(R8*1),a; \
+ ORL b, R9; \
+ XORL c, R9; \
+ ADDL R9, a; \
+ MOVL (index*4)(SI),R8; \
+ MOVL $0xffffffff, R9; \
+ ROLL $shift, a; \
+ XORL c, R9; \
+ ADDL b, a
+
+ ROUND4(AX,BX,CX,DX, 7,0xf4292244, 6);
+ ROUND4(DX,AX,BX,CX,14,0x432aff97,10);
+ ROUND4(CX,DX,AX,BX, 5,0xab9423a7,15);
+ ROUND4(BX,CX,DX,AX,12,0xfc93a039,21);
+ ROUND4(AX,BX,CX,DX, 3,0x655b59c3, 6);
+ ROUND4(DX,AX,BX,CX,10,0x8f0ccc92,10);
+ ROUND4(CX,DX,AX,BX, 1,0xffeff47d,15);
+ ROUND4(BX,CX,DX,AX, 8,0x85845dd1,21);
+ ROUND4(AX,BX,CX,DX,15,0x6fa87e4f, 6);
+ ROUND4(DX,AX,BX,CX, 6,0xfe2ce6e0,10);
+ ROUND4(CX,DX,AX,BX,13,0xa3014314,15);
+ ROUND4(BX,CX,DX,AX, 4,0x4e0811a1,21);
+ ROUND4(AX,BX,CX,DX,11,0xf7537e82, 6);
+ ROUND4(DX,AX,BX,CX, 2,0xbd3af235,10);
+ ROUND4(CX,DX,AX,BX, 9,0x2ad7d2bb,15);
+ ROUND4(BX,CX,DX,AX, 0,0xeb86d391,21);
+
+ ADDL R12, AX
+ ADDL R13, BX
+ ADDL R14, CX
+ ADDL R15, DX
+
+ ADDQ $64, SI
+ CMPQ SI, DI
+ JB loop
+
+end:
+ MOVL AX, (0*4)(BP)
+ MOVL BX, (1*4)(BP)
+ MOVL CX, (2*4)(BP)
+ MOVL DX, (3*4)(BP)
+ RET
diff --git a/src/crypto/md5/md5block_arm.s b/src/crypto/md5/md5block_arm.s
new file mode 100644
index 0000000..54d02b7
--- /dev/null
+++ b/src/crypto/md5/md5block_arm.s
@@ -0,0 +1,299 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// ARM version of md5block.go
+
+#include "textflag.h"
+
+// Register definitions
+#define Rtable R0 // Pointer to MD5 constants table
+#define Rdata R1 // Pointer to data to hash
+#define Ra R2 // MD5 accumulator
+#define Rb R3 // MD5 accumulator
+#define Rc R4 // MD5 accumulator
+#define Rd R5 // MD5 accumulator
+#define Rc0 R6 // MD5 constant
+#define Rc1 R7 // MD5 constant
+#define Rc2 R8 // MD5 constant
+// r9, r10 are forbidden
+// r11 is OK provided you check the assembler that no synthetic instructions use it
+#define Rc3 R11 // MD5 constant
+#define Rt0 R12 // temporary
+#define Rt1 R14 // temporary
+
+// func block(dig *digest, p []byte)
+// 0(FP) is *digest
+// 4(FP) is p.array (struct Slice)
+// 8(FP) is p.len
+//12(FP) is p.cap
+//
+// Stack frame
+#define p_end end-4(SP) // pointer to the end of data
+#define p_data data-8(SP) // current data pointer
+#define buf buffer-(8+4*16)(SP) //16 words temporary buffer
+ // 3 words at 4..12(R13) for called routine parameters
+
+TEXT ·block(SB), NOSPLIT, $84-16
+ MOVW p+4(FP), Rdata // pointer to the data
+ MOVW p_len+8(FP), Rt0 // number of bytes
+ ADD Rdata, Rt0
+ MOVW Rt0, p_end // pointer to end of data
+
+loop:
+ MOVW Rdata, p_data // Save Rdata
+ AND.S $3, Rdata, Rt0 // TST $3, Rdata not working see issue 5921
+ BEQ aligned // aligned detected - skip copy
+
+ // Copy the unaligned source data into the aligned temporary buffer
+ // memmove(to=4(R13), from=8(R13), n=12(R13)) - Corrupts all registers
+ MOVW $buf, Rtable // to
+ MOVW $64, Rc0 // n
+ MOVM.IB [Rtable,Rdata,Rc0], (R13)
+ BL runtime·memmove(SB)
+
+ // Point to the local aligned copy of the data
+ MOVW $buf, Rdata
+
+aligned:
+ // Point to the table of constants
+ // A PC relative add would be cheaper than this
+ MOVW $·table(SB), Rtable
+
+ // Load up initial MD5 accumulator
+ MOVW dig+0(FP), Rc0
+ MOVM.IA (Rc0), [Ra,Rb,Rc,Rd]
+
+// a += (((c^d)&b)^d) + X[index] + const
+// a = a<<shift | a>>(32-shift) + b
+#define ROUND1(Ra, Rb, Rc, Rd, index, shift, Rconst) \
+ EOR Rc, Rd, Rt0 ; \
+ AND Rb, Rt0 ; \
+ EOR Rd, Rt0 ; \
+ MOVW (index<<2)(Rdata), Rt1 ; \
+ ADD Rt1, Rt0 ; \
+ ADD Rconst, Rt0 ; \
+ ADD Rt0, Ra ; \
+ ADD Ra@>(32-shift), Rb, Ra ;
+
+ MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+ ROUND1(Ra, Rb, Rc, Rd, 0, 7, Rc0)
+ ROUND1(Rd, Ra, Rb, Rc, 1, 12, Rc1)
+ ROUND1(Rc, Rd, Ra, Rb, 2, 17, Rc2)
+ ROUND1(Rb, Rc, Rd, Ra, 3, 22, Rc3)
+
+ MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+ ROUND1(Ra, Rb, Rc, Rd, 4, 7, Rc0)
+ ROUND1(Rd, Ra, Rb, Rc, 5, 12, Rc1)
+ ROUND1(Rc, Rd, Ra, Rb, 6, 17, Rc2)
+ ROUND1(Rb, Rc, Rd, Ra, 7, 22, Rc3)
+
+ MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+ ROUND1(Ra, Rb, Rc, Rd, 8, 7, Rc0)
+ ROUND1(Rd, Ra, Rb, Rc, 9, 12, Rc1)
+ ROUND1(Rc, Rd, Ra, Rb, 10, 17, Rc2)
+ ROUND1(Rb, Rc, Rd, Ra, 11, 22, Rc3)
+
+ MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+ ROUND1(Ra, Rb, Rc, Rd, 12, 7, Rc0)
+ ROUND1(Rd, Ra, Rb, Rc, 13, 12, Rc1)
+ ROUND1(Rc, Rd, Ra, Rb, 14, 17, Rc2)
+ ROUND1(Rb, Rc, Rd, Ra, 15, 22, Rc3)
+
+// a += (((b^c)&d)^c) + X[index] + const
+// a = a<<shift | a>>(32-shift) + b
+#define ROUND2(Ra, Rb, Rc, Rd, index, shift, Rconst) \
+ EOR Rb, Rc, Rt0 ; \
+ AND Rd, Rt0 ; \
+ EOR Rc, Rt0 ; \
+ MOVW (index<<2)(Rdata), Rt1 ; \
+ ADD Rt1, Rt0 ; \
+ ADD Rconst, Rt0 ; \
+ ADD Rt0, Ra ; \
+ ADD Ra@>(32-shift), Rb, Ra ;
+
+ MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+ ROUND2(Ra, Rb, Rc, Rd, 1, 5, Rc0)
+ ROUND2(Rd, Ra, Rb, Rc, 6, 9, Rc1)
+ ROUND2(Rc, Rd, Ra, Rb, 11, 14, Rc2)
+ ROUND2(Rb, Rc, Rd, Ra, 0, 20, Rc3)
+
+ MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+ ROUND2(Ra, Rb, Rc, Rd, 5, 5, Rc0)
+ ROUND2(Rd, Ra, Rb, Rc, 10, 9, Rc1)
+ ROUND2(Rc, Rd, Ra, Rb, 15, 14, Rc2)
+ ROUND2(Rb, Rc, Rd, Ra, 4, 20, Rc3)
+
+ MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+ ROUND2(Ra, Rb, Rc, Rd, 9, 5, Rc0)
+ ROUND2(Rd, Ra, Rb, Rc, 14, 9, Rc1)
+ ROUND2(Rc, Rd, Ra, Rb, 3, 14, Rc2)
+ ROUND2(Rb, Rc, Rd, Ra, 8, 20, Rc3)
+
+ MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+ ROUND2(Ra, Rb, Rc, Rd, 13, 5, Rc0)
+ ROUND2(Rd, Ra, Rb, Rc, 2, 9, Rc1)
+ ROUND2(Rc, Rd, Ra, Rb, 7, 14, Rc2)
+ ROUND2(Rb, Rc, Rd, Ra, 12, 20, Rc3)
+
+// a += (b^c^d) + X[index] + const
+// a = a<<shift | a>>(32-shift) + b
+#define ROUND3(Ra, Rb, Rc, Rd, index, shift, Rconst) \
+ EOR Rb, Rc, Rt0 ; \
+ EOR Rd, Rt0 ; \
+ MOVW (index<<2)(Rdata), Rt1 ; \
+ ADD Rt1, Rt0 ; \
+ ADD Rconst, Rt0 ; \
+ ADD Rt0, Ra ; \
+ ADD Ra@>(32-shift), Rb, Ra ;
+
+ MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+ ROUND3(Ra, Rb, Rc, Rd, 5, 4, Rc0)
+ ROUND3(Rd, Ra, Rb, Rc, 8, 11, Rc1)
+ ROUND3(Rc, Rd, Ra, Rb, 11, 16, Rc2)
+ ROUND3(Rb, Rc, Rd, Ra, 14, 23, Rc3)
+
+ MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+ ROUND3(Ra, Rb, Rc, Rd, 1, 4, Rc0)
+ ROUND3(Rd, Ra, Rb, Rc, 4, 11, Rc1)
+ ROUND3(Rc, Rd, Ra, Rb, 7, 16, Rc2)
+ ROUND3(Rb, Rc, Rd, Ra, 10, 23, Rc3)
+
+ MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+ ROUND3(Ra, Rb, Rc, Rd, 13, 4, Rc0)
+ ROUND3(Rd, Ra, Rb, Rc, 0, 11, Rc1)
+ ROUND3(Rc, Rd, Ra, Rb, 3, 16, Rc2)
+ ROUND3(Rb, Rc, Rd, Ra, 6, 23, Rc3)
+
+ MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+ ROUND3(Ra, Rb, Rc, Rd, 9, 4, Rc0)
+ ROUND3(Rd, Ra, Rb, Rc, 12, 11, Rc1)
+ ROUND3(Rc, Rd, Ra, Rb, 15, 16, Rc2)
+ ROUND3(Rb, Rc, Rd, Ra, 2, 23, Rc3)
+
+// a += (c^(b|^d)) + X[index] + const
+// a = a<<shift | a>>(32-shift) + b
+#define ROUND4(Ra, Rb, Rc, Rd, index, shift, Rconst) \
+ MVN Rd, Rt0 ; \
+ ORR Rb, Rt0 ; \
+ EOR Rc, Rt0 ; \
+ MOVW (index<<2)(Rdata), Rt1 ; \
+ ADD Rt1, Rt0 ; \
+ ADD Rconst, Rt0 ; \
+ ADD Rt0, Ra ; \
+ ADD Ra@>(32-shift), Rb, Ra ;
+
+ MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+ ROUND4(Ra, Rb, Rc, Rd, 0, 6, Rc0)
+ ROUND4(Rd, Ra, Rb, Rc, 7, 10, Rc1)
+ ROUND4(Rc, Rd, Ra, Rb, 14, 15, Rc2)
+ ROUND4(Rb, Rc, Rd, Ra, 5, 21, Rc3)
+
+ MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+ ROUND4(Ra, Rb, Rc, Rd, 12, 6, Rc0)
+ ROUND4(Rd, Ra, Rb, Rc, 3, 10, Rc1)
+ ROUND4(Rc, Rd, Ra, Rb, 10, 15, Rc2)
+ ROUND4(Rb, Rc, Rd, Ra, 1, 21, Rc3)
+
+ MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+ ROUND4(Ra, Rb, Rc, Rd, 8, 6, Rc0)
+ ROUND4(Rd, Ra, Rb, Rc, 15, 10, Rc1)
+ ROUND4(Rc, Rd, Ra, Rb, 6, 15, Rc2)
+ ROUND4(Rb, Rc, Rd, Ra, 13, 21, Rc3)
+
+ MOVM.IA.W (Rtable), [Rc0,Rc1,Rc2,Rc3]
+ ROUND4(Ra, Rb, Rc, Rd, 4, 6, Rc0)
+ ROUND4(Rd, Ra, Rb, Rc, 11, 10, Rc1)
+ ROUND4(Rc, Rd, Ra, Rb, 2, 15, Rc2)
+ ROUND4(Rb, Rc, Rd, Ra, 9, 21, Rc3)
+
+ MOVW dig+0(FP), Rt0
+ MOVM.IA (Rt0), [Rc0,Rc1,Rc2,Rc3]
+
+ ADD Rc0, Ra
+ ADD Rc1, Rb
+ ADD Rc2, Rc
+ ADD Rc3, Rd
+
+ MOVM.IA [Ra,Rb,Rc,Rd], (Rt0)
+
+ MOVW p_data, Rdata
+ MOVW p_end, Rt0
+ ADD $64, Rdata
+ CMP Rt0, Rdata
+ BLO loop
+
+ RET
+
+// MD5 constants table
+
+ // Round 1
+ DATA ·table+0x00(SB)/4, $0xd76aa478
+ DATA ·table+0x04(SB)/4, $0xe8c7b756
+ DATA ·table+0x08(SB)/4, $0x242070db
+ DATA ·table+0x0c(SB)/4, $0xc1bdceee
+ DATA ·table+0x10(SB)/4, $0xf57c0faf
+ DATA ·table+0x14(SB)/4, $0x4787c62a
+ DATA ·table+0x18(SB)/4, $0xa8304613
+ DATA ·table+0x1c(SB)/4, $0xfd469501
+ DATA ·table+0x20(SB)/4, $0x698098d8
+ DATA ·table+0x24(SB)/4, $0x8b44f7af
+ DATA ·table+0x28(SB)/4, $0xffff5bb1
+ DATA ·table+0x2c(SB)/4, $0x895cd7be
+ DATA ·table+0x30(SB)/4, $0x6b901122
+ DATA ·table+0x34(SB)/4, $0xfd987193
+ DATA ·table+0x38(SB)/4, $0xa679438e
+ DATA ·table+0x3c(SB)/4, $0x49b40821
+ // Round 2
+ DATA ·table+0x40(SB)/4, $0xf61e2562
+ DATA ·table+0x44(SB)/4, $0xc040b340
+ DATA ·table+0x48(SB)/4, $0x265e5a51
+ DATA ·table+0x4c(SB)/4, $0xe9b6c7aa
+ DATA ·table+0x50(SB)/4, $0xd62f105d
+ DATA ·table+0x54(SB)/4, $0x02441453
+ DATA ·table+0x58(SB)/4, $0xd8a1e681
+ DATA ·table+0x5c(SB)/4, $0xe7d3fbc8
+ DATA ·table+0x60(SB)/4, $0x21e1cde6
+ DATA ·table+0x64(SB)/4, $0xc33707d6
+ DATA ·table+0x68(SB)/4, $0xf4d50d87
+ DATA ·table+0x6c(SB)/4, $0x455a14ed
+ DATA ·table+0x70(SB)/4, $0xa9e3e905
+ DATA ·table+0x74(SB)/4, $0xfcefa3f8
+ DATA ·table+0x78(SB)/4, $0x676f02d9
+ DATA ·table+0x7c(SB)/4, $0x8d2a4c8a
+ // Round 3
+ DATA ·table+0x80(SB)/4, $0xfffa3942
+ DATA ·table+0x84(SB)/4, $0x8771f681
+ DATA ·table+0x88(SB)/4, $0x6d9d6122
+ DATA ·table+0x8c(SB)/4, $0xfde5380c
+ DATA ·table+0x90(SB)/4, $0xa4beea44
+ DATA ·table+0x94(SB)/4, $0x4bdecfa9
+ DATA ·table+0x98(SB)/4, $0xf6bb4b60
+ DATA ·table+0x9c(SB)/4, $0xbebfbc70
+ DATA ·table+0xa0(SB)/4, $0x289b7ec6
+ DATA ·table+0xa4(SB)/4, $0xeaa127fa
+ DATA ·table+0xa8(SB)/4, $0xd4ef3085
+ DATA ·table+0xac(SB)/4, $0x04881d05
+ DATA ·table+0xb0(SB)/4, $0xd9d4d039
+ DATA ·table+0xb4(SB)/4, $0xe6db99e5
+ DATA ·table+0xb8(SB)/4, $0x1fa27cf8
+ DATA ·table+0xbc(SB)/4, $0xc4ac5665
+ // Round 4
+ DATA ·table+0xc0(SB)/4, $0xf4292244
+ DATA ·table+0xc4(SB)/4, $0x432aff97
+ DATA ·table+0xc8(SB)/4, $0xab9423a7
+ DATA ·table+0xcc(SB)/4, $0xfc93a039
+ DATA ·table+0xd0(SB)/4, $0x655b59c3
+ DATA ·table+0xd4(SB)/4, $0x8f0ccc92
+ DATA ·table+0xd8(SB)/4, $0xffeff47d
+ DATA ·table+0xdc(SB)/4, $0x85845dd1
+ DATA ·table+0xe0(SB)/4, $0x6fa87e4f
+ DATA ·table+0xe4(SB)/4, $0xfe2ce6e0
+ DATA ·table+0xe8(SB)/4, $0xa3014314
+ DATA ·table+0xec(SB)/4, $0x4e0811a1
+ DATA ·table+0xf0(SB)/4, $0xf7537e82
+ DATA ·table+0xf4(SB)/4, $0xbd3af235
+ DATA ·table+0xf8(SB)/4, $0x2ad7d2bb
+ DATA ·table+0xfc(SB)/4, $0xeb86d391
+ // Global definition
+ GLOBL ·table(SB),8,$256
diff --git a/src/crypto/md5/md5block_arm64.s b/src/crypto/md5/md5block_arm64.s
new file mode 100644
index 0000000..39b9851
--- /dev/null
+++ b/src/crypto/md5/md5block_arm64.s
@@ -0,0 +1,167 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// ARM64 version of md5block.go
+// derived from crypto/md5/md5block_amd64.s
+
+#include "textflag.h"
+
+TEXT ·block(SB),NOSPLIT,$0-32
+ MOVD dig+0(FP), R0
+ MOVD p+8(FP), R1
+ MOVD p_len+16(FP), R2
+ AND $~63, R2
+ CBZ R2, zero
+
+ ADD R1, R2, R21
+ LDPW (0*8)(R0), (R4, R5)
+ LDPW (1*8)(R0), (R6, R7)
+
+loop:
+ MOVW R4, R12
+ MOVW R5, R13
+ MOVW R6, R14
+ MOVW R7, R15
+
+ MOVW (0*4)(R1), R8
+ MOVW R7, R9
+
+#define ROUND1(a, b, c, d, index, const, shift) \
+ ADDW $const, a; \
+ ADDW R8, a; \
+ MOVW (index*4)(R1), R8; \
+ EORW c, R9; \
+ ANDW b, R9; \
+ EORW d, R9; \
+ ADDW R9, a; \
+ RORW $(32-shift), a; \
+ MOVW c, R9; \
+ ADDW b, a
+
+ ROUND1(R4,R5,R6,R7, 1,0xd76aa478, 7);
+ ROUND1(R7,R4,R5,R6, 2,0xe8c7b756,12);
+ ROUND1(R6,R7,R4,R5, 3,0x242070db,17);
+ ROUND1(R5,R6,R7,R4, 4,0xc1bdceee,22);
+ ROUND1(R4,R5,R6,R7, 5,0xf57c0faf, 7);
+ ROUND1(R7,R4,R5,R6, 6,0x4787c62a,12);
+ ROUND1(R6,R7,R4,R5, 7,0xa8304613,17);
+ ROUND1(R5,R6,R7,R4, 8,0xfd469501,22);
+ ROUND1(R4,R5,R6,R7, 9,0x698098d8, 7);
+ ROUND1(R7,R4,R5,R6,10,0x8b44f7af,12);
+ ROUND1(R6,R7,R4,R5,11,0xffff5bb1,17);
+ ROUND1(R5,R6,R7,R4,12,0x895cd7be,22);
+ ROUND1(R4,R5,R6,R7,13,0x6b901122, 7);
+ ROUND1(R7,R4,R5,R6,14,0xfd987193,12);
+ ROUND1(R6,R7,R4,R5,15,0xa679438e,17);
+ ROUND1(R5,R6,R7,R4, 0,0x49b40821,22);
+
+ MOVW (1*4)(R1), R8
+ MOVW R7, R9
+ MOVW R7, R10
+
+#define ROUND2(a, b, c, d, index, const, shift) \
+ ADDW $const, a; \
+ ADDW R8, a; \
+ MOVW (index*4)(R1), R8; \
+ ANDW b, R10; \
+ BICW R9, c, R9; \
+ ORRW R9, R10; \
+ MOVW c, R9; \
+ ADDW R10, a; \
+ MOVW c, R10; \
+ RORW $(32-shift), a; \
+ ADDW b, a
+
+ ROUND2(R4,R5,R6,R7, 6,0xf61e2562, 5);
+ ROUND2(R7,R4,R5,R6,11,0xc040b340, 9);
+ ROUND2(R6,R7,R4,R5, 0,0x265e5a51,14);
+ ROUND2(R5,R6,R7,R4, 5,0xe9b6c7aa,20);
+ ROUND2(R4,R5,R6,R7,10,0xd62f105d, 5);
+ ROUND2(R7,R4,R5,R6,15, 0x2441453, 9);
+ ROUND2(R6,R7,R4,R5, 4,0xd8a1e681,14);
+ ROUND2(R5,R6,R7,R4, 9,0xe7d3fbc8,20);
+ ROUND2(R4,R5,R6,R7,14,0x21e1cde6, 5);
+ ROUND2(R7,R4,R5,R6, 3,0xc33707d6, 9);
+ ROUND2(R6,R7,R4,R5, 8,0xf4d50d87,14);
+ ROUND2(R5,R6,R7,R4,13,0x455a14ed,20);
+ ROUND2(R4,R5,R6,R7, 2,0xa9e3e905, 5);
+ ROUND2(R7,R4,R5,R6, 7,0xfcefa3f8, 9);
+ ROUND2(R6,R7,R4,R5,12,0x676f02d9,14);
+ ROUND2(R5,R6,R7,R4, 0,0x8d2a4c8a,20);
+
+ MOVW (5*4)(R1), R8
+ MOVW R6, R9
+
+#define ROUND3(a, b, c, d, index, const, shift) \
+ ADDW $const, a; \
+ ADDW R8, a; \
+ MOVW (index*4)(R1), R8; \
+ EORW d, R9; \
+ EORW b, R9; \
+ ADDW R9, a; \
+ RORW $(32-shift), a; \
+ MOVW b, R9; \
+ ADDW b, a
+
+ ROUND3(R4,R5,R6,R7, 8,0xfffa3942, 4);
+ ROUND3(R7,R4,R5,R6,11,0x8771f681,11);
+ ROUND3(R6,R7,R4,R5,14,0x6d9d6122,16);
+ ROUND3(R5,R6,R7,R4, 1,0xfde5380c,23);
+ ROUND3(R4,R5,R6,R7, 4,0xa4beea44, 4);
+ ROUND3(R7,R4,R5,R6, 7,0x4bdecfa9,11);
+ ROUND3(R6,R7,R4,R5,10,0xf6bb4b60,16);
+ ROUND3(R5,R6,R7,R4,13,0xbebfbc70,23);
+ ROUND3(R4,R5,R6,R7, 0,0x289b7ec6, 4);
+ ROUND3(R7,R4,R5,R6, 3,0xeaa127fa,11);
+ ROUND3(R6,R7,R4,R5, 6,0xd4ef3085,16);
+ ROUND3(R5,R6,R7,R4, 9, 0x4881d05,23);
+ ROUND3(R4,R5,R6,R7,12,0xd9d4d039, 4);
+ ROUND3(R7,R4,R5,R6,15,0xe6db99e5,11);
+ ROUND3(R6,R7,R4,R5, 2,0x1fa27cf8,16);
+ ROUND3(R5,R6,R7,R4, 0,0xc4ac5665,23);
+
+ MOVW (0*4)(R1), R8
+ MVNW R7, R9
+
+#define ROUND4(a, b, c, d, index, const, shift) \
+ ADDW $const, a; \
+ ADDW R8, a; \
+ MOVW (index*4)(R1), R8; \
+ ORRW b, R9; \
+ EORW c, R9; \
+ ADDW R9, a; \
+ RORW $(32-shift), a; \
+ MVNW c, R9; \
+ ADDW b, a
+
+ ROUND4(R4,R5,R6,R7, 7,0xf4292244, 6);
+ ROUND4(R7,R4,R5,R6,14,0x432aff97,10);
+ ROUND4(R6,R7,R4,R5, 5,0xab9423a7,15);
+ ROUND4(R5,R6,R7,R4,12,0xfc93a039,21);
+ ROUND4(R4,R5,R6,R7, 3,0x655b59c3, 6);
+ ROUND4(R7,R4,R5,R6,10,0x8f0ccc92,10);
+ ROUND4(R6,R7,R4,R5, 1,0xffeff47d,15);
+ ROUND4(R5,R6,R7,R4, 8,0x85845dd1,21);
+ ROUND4(R4,R5,R6,R7,15,0x6fa87e4f, 6);
+ ROUND4(R7,R4,R5,R6, 6,0xfe2ce6e0,10);
+ ROUND4(R6,R7,R4,R5,13,0xa3014314,15);
+ ROUND4(R5,R6,R7,R4, 4,0x4e0811a1,21);
+ ROUND4(R4,R5,R6,R7,11,0xf7537e82, 6);
+ ROUND4(R7,R4,R5,R6, 2,0xbd3af235,10);
+ ROUND4(R6,R7,R4,R5, 9,0x2ad7d2bb,15);
+ ROUND4(R5,R6,R7,R4, 0,0xeb86d391,21);
+
+ ADDW R12, R4
+ ADDW R13, R5
+ ADDW R14, R6
+ ADDW R15, R7
+
+ ADD $64, R1
+ CMP R1, R21
+ BNE loop
+
+ STPW (R4, R5), (0*8)(R0)
+ STPW (R6, R7), (1*8)(R0)
+zero:
+ RET
diff --git a/src/crypto/md5/md5block_decl.go b/src/crypto/md5/md5block_decl.go
new file mode 100644
index 0000000..6716a0c
--- /dev/null
+++ b/src/crypto/md5/md5block_decl.go
@@ -0,0 +1,13 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build amd64 || 386 || arm || ppc64le || ppc64 || s390x || arm64
+
+package md5
+
+const haveAsm = true
+
+//go:noescape
+
+func block(dig *digest, p []byte)
diff --git a/src/crypto/md5/md5block_generic.go b/src/crypto/md5/md5block_generic.go
new file mode 100644
index 0000000..c929c2b
--- /dev/null
+++ b/src/crypto/md5/md5block_generic.go
@@ -0,0 +1,13 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !amd64 && !386 && !arm && !ppc64le && !ppc64 && !s390x && !arm64
+
+package md5
+
+const haveAsm = false
+
+func block(dig *digest, p []byte) {
+ blockGeneric(dig, p)
+}
diff --git a/src/crypto/md5/md5block_ppc64x.s b/src/crypto/md5/md5block_ppc64x.s
new file mode 100644
index 0000000..69a20e7
--- /dev/null
+++ b/src/crypto/md5/md5block_ppc64x.s
@@ -0,0 +1,212 @@
+// Original source:
+// http://www.zorinaq.com/papers/md5-amd64.html
+// http://www.zorinaq.com/papers/md5-amd64.tar.bz2
+//
+// MD5 optimized for ppc64le using Go's assembler for
+// ppc64le, based on md5block_amd64.s implementation by
+// the Go authors.
+//
+// Author: Marc Bevand <bevand_m (at) epita.fr>
+// Licence: I hereby disclaim the copyright on this code and place it
+// in the public domain.
+
+//go:build ppc64 || ppc64le
+
+#include "textflag.h"
+
+// ENDIAN_MOVE generates the appropriate
+// 4 byte load for big or little endian.
+// The 4 bytes at ptr+off is loaded into dst.
+// The idx reg is only needed for big endian
+// and is clobbered when used.
+#ifdef GOARCH_ppc64le
+#define ENDIAN_MOVE(off, ptr, dst, idx) \
+ MOVWZ off(ptr),dst
+#else
+#define ENDIAN_MOVE(off, ptr, dst, idx) \
+ MOVD $off,idx; \
+ MOVWBR (idx)(ptr), dst
+#endif
+
+#define M00 R18
+#define M01 R19
+#define M02 R20
+#define M03 R24
+#define M04 R25
+#define M05 R26
+#define M06 R27
+#define M07 R28
+#define M08 R29
+#define M09 R21
+#define M10 R11
+#define M11 R8
+#define M12 R7
+#define M13 R12
+#define M14 R23
+#define M15 R10
+
+#define ROUND1(a, b, c, d, index, const, shift) \
+ ADD $const, index, R9; \
+ ADD R9, a; \
+ AND b, c, R9; \
+ ANDN b, d, R31; \
+ OR R9, R31, R9; \
+ ADD R9, a; \
+ ROTLW $shift, a; \
+ ADD b, a;
+
+#define ROUND2(a, b, c, d, index, const, shift) \
+ ADD $const, index, R9; \
+ ADD R9, a; \
+ AND b, d, R31; \
+ ANDN d, c, R9; \
+ OR R9, R31; \
+ ADD R31, a; \
+ ROTLW $shift, a; \
+ ADD b, a;
+
+#define ROUND3(a, b, c, d, index, const, shift) \
+ ADD $const, index, R9; \
+ ADD R9, a; \
+ XOR d, c, R31; \
+ XOR b, R31; \
+ ADD R31, a; \
+ ROTLW $shift, a; \
+ ADD b, a;
+
+#define ROUND4(a, b, c, d, index, const, shift) \
+ ADD $const, index, R9; \
+ ADD R9, a; \
+ ORN d, b, R31; \
+ XOR c, R31; \
+ ADD R31, a; \
+ ROTLW $shift, a; \
+ ADD b, a;
+
+
+TEXT ·block(SB),NOSPLIT,$0-32
+ MOVD dig+0(FP), R10
+ MOVD p+8(FP), R6
+ MOVD p_len+16(FP), R5
+
+ // We assume p_len >= 64
+ SRD $6, R5
+ MOVD R5, CTR
+
+ MOVWZ 0(R10), R22
+ MOVWZ 4(R10), R3
+ MOVWZ 8(R10), R4
+ MOVWZ 12(R10), R5
+
+loop:
+ MOVD R22, R14
+ MOVD R3, R15
+ MOVD R4, R16
+ MOVD R5, R17
+
+ ENDIAN_MOVE( 0,R6,M00,M15)
+ ENDIAN_MOVE( 4,R6,M01,M15)
+ ENDIAN_MOVE( 8,R6,M02,M15)
+ ENDIAN_MOVE(12,R6,M03,M15)
+
+ ROUND1(R22,R3,R4,R5,M00,0xd76aa478, 7);
+ ROUND1(R5,R22,R3,R4,M01,0xe8c7b756,12);
+ ROUND1(R4,R5,R22,R3,M02,0x242070db,17);
+ ROUND1(R3,R4,R5,R22,M03,0xc1bdceee,22);
+
+ ENDIAN_MOVE(16,R6,M04,M15)
+ ENDIAN_MOVE(20,R6,M05,M15)
+ ENDIAN_MOVE(24,R6,M06,M15)
+ ENDIAN_MOVE(28,R6,M07,M15)
+
+ ROUND1(R22,R3,R4,R5,M04,0xf57c0faf, 7);
+ ROUND1(R5,R22,R3,R4,M05,0x4787c62a,12);
+ ROUND1(R4,R5,R22,R3,M06,0xa8304613,17);
+ ROUND1(R3,R4,R5,R22,M07,0xfd469501,22);
+
+ ENDIAN_MOVE(32,R6,M08,M15)
+ ENDIAN_MOVE(36,R6,M09,M15)
+ ENDIAN_MOVE(40,R6,M10,M15)
+ ENDIAN_MOVE(44,R6,M11,M15)
+
+ ROUND1(R22,R3,R4,R5,M08,0x698098d8, 7);
+ ROUND1(R5,R22,R3,R4,M09,0x8b44f7af,12);
+ ROUND1(R4,R5,R22,R3,M10,0xffff5bb1,17);
+ ROUND1(R3,R4,R5,R22,M11,0x895cd7be,22);
+
+ ENDIAN_MOVE(48,R6,M12,M15)
+ ENDIAN_MOVE(52,R6,M13,M15)
+ ENDIAN_MOVE(56,R6,M14,M15)
+ ENDIAN_MOVE(60,R6,M15,M15)
+
+ ROUND1(R22,R3,R4,R5,M12,0x6b901122, 7);
+ ROUND1(R5,R22,R3,R4,M13,0xfd987193,12);
+ ROUND1(R4,R5,R22,R3,M14,0xa679438e,17);
+ ROUND1(R3,R4,R5,R22,M15,0x49b40821,22);
+
+ ROUND2(R22,R3,R4,R5,M01,0xf61e2562, 5);
+ ROUND2(R5,R22,R3,R4,M06,0xc040b340, 9);
+ ROUND2(R4,R5,R22,R3,M11,0x265e5a51,14);
+ ROUND2(R3,R4,R5,R22,M00,0xe9b6c7aa,20);
+ ROUND2(R22,R3,R4,R5,M05,0xd62f105d, 5);
+ ROUND2(R5,R22,R3,R4,M10, 0x2441453, 9);
+ ROUND2(R4,R5,R22,R3,M15,0xd8a1e681,14);
+ ROUND2(R3,R4,R5,R22,M04,0xe7d3fbc8,20);
+ ROUND2(R22,R3,R4,R5,M09,0x21e1cde6, 5);
+ ROUND2(R5,R22,R3,R4,M14,0xc33707d6, 9);
+ ROUND2(R4,R5,R22,R3,M03,0xf4d50d87,14);
+ ROUND2(R3,R4,R5,R22,M08,0x455a14ed,20);
+ ROUND2(R22,R3,R4,R5,M13,0xa9e3e905, 5);
+ ROUND2(R5,R22,R3,R4,M02,0xfcefa3f8, 9);
+ ROUND2(R4,R5,R22,R3,M07,0x676f02d9,14);
+ ROUND2(R3,R4,R5,R22,M12,0x8d2a4c8a,20);
+
+ ROUND3(R22,R3,R4,R5,M05,0xfffa3942, 4);
+ ROUND3(R5,R22,R3,R4,M08,0x8771f681,11);
+ ROUND3(R4,R5,R22,R3,M11,0x6d9d6122,16);
+ ROUND3(R3,R4,R5,R22,M14,0xfde5380c,23);
+ ROUND3(R22,R3,R4,R5,M01,0xa4beea44, 4);
+ ROUND3(R5,R22,R3,R4,M04,0x4bdecfa9,11);
+ ROUND3(R4,R5,R22,R3,M07,0xf6bb4b60,16);
+ ROUND3(R3,R4,R5,R22,M10,0xbebfbc70,23);
+ ROUND3(R22,R3,R4,R5,M13,0x289b7ec6, 4);
+ ROUND3(R5,R22,R3,R4,M00,0xeaa127fa,11);
+ ROUND3(R4,R5,R22,R3,M03,0xd4ef3085,16);
+ ROUND3(R3,R4,R5,R22,M06, 0x4881d05,23);
+ ROUND3(R22,R3,R4,R5,M09,0xd9d4d039, 4);
+ ROUND3(R5,R22,R3,R4,M12,0xe6db99e5,11);
+ ROUND3(R4,R5,R22,R3,M15,0x1fa27cf8,16);
+ ROUND3(R3,R4,R5,R22,M02,0xc4ac5665,23);
+
+ ROUND4(R22,R3,R4,R5,M00,0xf4292244, 6);
+ ROUND4(R5,R22,R3,R4,M07,0x432aff97,10);
+ ROUND4(R4,R5,R22,R3,M14,0xab9423a7,15);
+ ROUND4(R3,R4,R5,R22,M05,0xfc93a039,21);
+ ROUND4(R22,R3,R4,R5,M12,0x655b59c3, 6);
+ ROUND4(R5,R22,R3,R4,M03,0x8f0ccc92,10);
+ ROUND4(R4,R5,R22,R3,M10,0xffeff47d,15);
+ ROUND4(R3,R4,R5,R22,M01,0x85845dd1,21);
+ ROUND4(R22,R3,R4,R5,M08,0x6fa87e4f, 6);
+ ROUND4(R5,R22,R3,R4,M15,0xfe2ce6e0,10);
+ ROUND4(R4,R5,R22,R3,M06,0xa3014314,15);
+ ROUND4(R3,R4,R5,R22,M13,0x4e0811a1,21);
+ ROUND4(R22,R3,R4,R5,M04,0xf7537e82, 6);
+ ROUND4(R5,R22,R3,R4,M11,0xbd3af235,10);
+ ROUND4(R4,R5,R22,R3,M02,0x2ad7d2bb,15);
+ ROUND4(R3,R4,R5,R22,M09,0xeb86d391,21);
+
+ ADD R14, R22
+ ADD R15, R3
+ ADD R16, R4
+ ADD R17, R5
+ ADD $64, R6
+ BC 16, 0, loop // bdnz
+
+end:
+ MOVD dig+0(FP), R10
+ MOVWZ R22, 0(R10)
+ MOVWZ R3, 4(R10)
+ MOVWZ R4, 8(R10)
+ MOVWZ R5, 12(R10)
+
+ RET
diff --git a/src/crypto/md5/md5block_s390x.s b/src/crypto/md5/md5block_s390x.s
new file mode 100644
index 0000000..68f501c
--- /dev/null
+++ b/src/crypto/md5/md5block_s390x.s
@@ -0,0 +1,175 @@
+// Original source:
+// http://www.zorinaq.com/papers/md5-amd64.html
+// http://www.zorinaq.com/papers/md5-amd64.tar.bz2
+//
+// MD5 adapted for s390x using Go's assembler for
+// s390x, based on md5block_amd64.s implementation by
+// the Go authors.
+//
+// Author: Marc Bevand <bevand_m (at) epita.fr>
+// Licence: I hereby disclaim the copyright on this code and place it
+// in the public domain.
+
+#include "textflag.h"
+
+// func block(dig *digest, p []byte)
+TEXT ·block(SB),NOSPLIT,$16-32
+ MOVD dig+0(FP), R1
+ MOVD p+8(FP), R6
+ MOVD p_len+16(FP), R5
+ AND $-64, R5
+ LAY (R6)(R5*1), R7
+
+ LMY 0(R1), R2, R5
+ CMPBEQ R6, R7, end
+
+loop:
+ STMY R2, R5, tmp-16(SP)
+
+ MOVWBR 0(R6), R8
+ MOVWZ R5, R9
+
+#define ROUND1(a, b, c, d, index, const, shift) \
+ XOR c, R9; \
+ ADD $const, a; \
+ ADD R8, a; \
+ MOVWBR (index*4)(R6), R8; \
+ AND b, R9; \
+ XOR d, R9; \
+ ADD R9, a; \
+ RLL $shift, a; \
+ MOVWZ c, R9; \
+ ADD b, a
+
+ ROUND1(R2,R3,R4,R5, 1,0xd76aa478, 7);
+ ROUND1(R5,R2,R3,R4, 2,0xe8c7b756,12);
+ ROUND1(R4,R5,R2,R3, 3,0x242070db,17);
+ ROUND1(R3,R4,R5,R2, 4,0xc1bdceee,22);
+ ROUND1(R2,R3,R4,R5, 5,0xf57c0faf, 7);
+ ROUND1(R5,R2,R3,R4, 6,0x4787c62a,12);
+ ROUND1(R4,R5,R2,R3, 7,0xa8304613,17);
+ ROUND1(R3,R4,R5,R2, 8,0xfd469501,22);
+ ROUND1(R2,R3,R4,R5, 9,0x698098d8, 7);
+ ROUND1(R5,R2,R3,R4,10,0x8b44f7af,12);
+ ROUND1(R4,R5,R2,R3,11,0xffff5bb1,17);
+ ROUND1(R3,R4,R5,R2,12,0x895cd7be,22);
+ ROUND1(R2,R3,R4,R5,13,0x6b901122, 7);
+ ROUND1(R5,R2,R3,R4,14,0xfd987193,12);
+ ROUND1(R4,R5,R2,R3,15,0xa679438e,17);
+ ROUND1(R3,R4,R5,R2, 0,0x49b40821,22);
+
+ MOVWBR (1*4)(R6), R8
+ MOVWZ R5, R9
+ MOVWZ R5, R1
+
+#define ROUND2(a, b, c, d, index, const, shift) \
+ XOR $0xffffffff, R9; \ // NOTW R9
+ ADD $const, a; \
+ ADD R8, a; \
+ MOVWBR (index*4)(R6), R8; \
+ AND b, R1; \
+ AND c, R9; \
+ OR R9, R1; \
+ MOVWZ c, R9; \
+ ADD R1, a; \
+ MOVWZ c, R1; \
+ RLL $shift, a; \
+ ADD b, a
+
+ ROUND2(R2,R3,R4,R5, 6,0xf61e2562, 5);
+ ROUND2(R5,R2,R3,R4,11,0xc040b340, 9);
+ ROUND2(R4,R5,R2,R3, 0,0x265e5a51,14);
+ ROUND2(R3,R4,R5,R2, 5,0xe9b6c7aa,20);
+ ROUND2(R2,R3,R4,R5,10,0xd62f105d, 5);
+ ROUND2(R5,R2,R3,R4,15, 0x2441453, 9);
+ ROUND2(R4,R5,R2,R3, 4,0xd8a1e681,14);
+ ROUND2(R3,R4,R5,R2, 9,0xe7d3fbc8,20);
+ ROUND2(R2,R3,R4,R5,14,0x21e1cde6, 5);
+ ROUND2(R5,R2,R3,R4, 3,0xc33707d6, 9);
+ ROUND2(R4,R5,R2,R3, 8,0xf4d50d87,14);
+ ROUND2(R3,R4,R5,R2,13,0x455a14ed,20);
+ ROUND2(R2,R3,R4,R5, 2,0xa9e3e905, 5);
+ ROUND2(R5,R2,R3,R4, 7,0xfcefa3f8, 9);
+ ROUND2(R4,R5,R2,R3,12,0x676f02d9,14);
+ ROUND2(R3,R4,R5,R2, 0,0x8d2a4c8a,20);
+
+ MOVWBR (5*4)(R6), R8
+ MOVWZ R4, R9
+
+#define ROUND3(a, b, c, d, index, const, shift) \
+ ADD $const, a; \
+ ADD R8, a; \
+ MOVWBR (index*4)(R6), R8; \
+ XOR d, R9; \
+ XOR b, R9; \
+ ADD R9, a; \
+ RLL $shift, a; \
+ MOVWZ b, R9; \
+ ADD b, a
+
+ ROUND3(R2,R3,R4,R5, 8,0xfffa3942, 4);
+ ROUND3(R5,R2,R3,R4,11,0x8771f681,11);
+ ROUND3(R4,R5,R2,R3,14,0x6d9d6122,16);
+ ROUND3(R3,R4,R5,R2, 1,0xfde5380c,23);
+ ROUND3(R2,R3,R4,R5, 4,0xa4beea44, 4);
+ ROUND3(R5,R2,R3,R4, 7,0x4bdecfa9,11);
+ ROUND3(R4,R5,R2,R3,10,0xf6bb4b60,16);
+ ROUND3(R3,R4,R5,R2,13,0xbebfbc70,23);
+ ROUND3(R2,R3,R4,R5, 0,0x289b7ec6, 4);
+ ROUND3(R5,R2,R3,R4, 3,0xeaa127fa,11);
+ ROUND3(R4,R5,R2,R3, 6,0xd4ef3085,16);
+ ROUND3(R3,R4,R5,R2, 9, 0x4881d05,23);
+ ROUND3(R2,R3,R4,R5,12,0xd9d4d039, 4);
+ ROUND3(R5,R2,R3,R4,15,0xe6db99e5,11);
+ ROUND3(R4,R5,R2,R3, 2,0x1fa27cf8,16);
+ ROUND3(R3,R4,R5,R2, 0,0xc4ac5665,23);
+
+ MOVWBR (0*4)(R6), R8
+ MOVWZ $0xffffffff, R9
+ XOR R5, R9
+
+#define ROUND4(a, b, c, d, index, const, shift) \
+ ADD $const, a; \
+ ADD R8, a; \
+ MOVWBR (index*4)(R6), R8; \
+ OR b, R9; \
+ XOR c, R9; \
+ ADD R9, a; \
+ MOVWZ $0xffffffff, R9; \
+ RLL $shift, a; \
+ XOR c, R9; \
+ ADD b, a
+
+ ROUND4(R2,R3,R4,R5, 7,0xf4292244, 6);
+ ROUND4(R5,R2,R3,R4,14,0x432aff97,10);
+ ROUND4(R4,R5,R2,R3, 5,0xab9423a7,15);
+ ROUND4(R3,R4,R5,R2,12,0xfc93a039,21);
+ ROUND4(R2,R3,R4,R5, 3,0x655b59c3, 6);
+ ROUND4(R5,R2,R3,R4,10,0x8f0ccc92,10);
+ ROUND4(R4,R5,R2,R3, 1,0xffeff47d,15);
+ ROUND4(R3,R4,R5,R2, 8,0x85845dd1,21);
+ ROUND4(R2,R3,R4,R5,15,0x6fa87e4f, 6);
+ ROUND4(R5,R2,R3,R4, 6,0xfe2ce6e0,10);
+ ROUND4(R4,R5,R2,R3,13,0xa3014314,15);
+ ROUND4(R3,R4,R5,R2, 4,0x4e0811a1,21);
+ ROUND4(R2,R3,R4,R5,11,0xf7537e82, 6);
+ ROUND4(R5,R2,R3,R4, 2,0xbd3af235,10);
+ ROUND4(R4,R5,R2,R3, 9,0x2ad7d2bb,15);
+ ROUND4(R3,R4,R5,R2, 0,0xeb86d391,21);
+
+ MOVWZ tmp-16(SP), R1
+ ADD R1, R2
+ MOVWZ tmp-12(SP), R1
+ ADD R1, R3
+ MOVWZ tmp-8(SP), R1
+ ADD R1, R4
+ MOVWZ tmp-4(SP), R1
+ ADD R1, R5
+
+ LA 64(R6), R6
+ CMPBLT R6, R7, loop
+
+end:
+ MOVD dig+0(FP), R1
+ STMY R2, R5, 0(R1)
+ RET
diff --git a/src/crypto/rand/example_test.go b/src/crypto/rand/example_test.go
new file mode 100644
index 0000000..ed18647
--- /dev/null
+++ b/src/crypto/rand/example_test.go
@@ -0,0 +1,28 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand_test
+
+import (
+ "bytes"
+ "crypto/rand"
+ "fmt"
+)
+
+// This example reads 10 cryptographically secure pseudorandom numbers from
+// rand.Reader and writes them to a byte slice.
+func ExampleRead() {
+ c := 10
+ b := make([]byte, c)
+ _, err := rand.Read(b)
+ if err != nil {
+ fmt.Println("error:", err)
+ return
+ }
+ // The slice should now contain random bytes instead of only zeroes.
+ fmt.Println(bytes.Equal(b, make([]byte, c)))
+
+ // Output:
+ // false
+}
diff --git a/src/crypto/rand/rand.go b/src/crypto/rand/rand.go
new file mode 100644
index 0000000..af85b96
--- /dev/null
+++ b/src/crypto/rand/rand.go
@@ -0,0 +1,44 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package rand implements a cryptographically secure
+// random number generator.
+package rand
+
+import "io"
+
+// Reader is a global, shared instance of a cryptographically
+// secure random number generator.
+//
+// On Linux, FreeBSD, Dragonfly and Solaris, Reader uses getrandom(2) if
+// available, /dev/urandom otherwise.
+// On OpenBSD and macOS, Reader uses getentropy(2).
+// On other Unix-like systems, Reader reads from /dev/urandom.
+// On Windows systems, Reader uses the RtlGenRandom API.
+// On Wasm, Reader uses the Web Crypto API.
+var Reader io.Reader
+
+// Read is a helper function that calls Reader.Read using io.ReadFull.
+// On return, n == len(b) if and only if err == nil.
+func Read(b []byte) (n int, err error) {
+ return io.ReadFull(Reader, b)
+}
+
+// batched returns a function that calls f to populate a []byte by chunking it
+// into subslices of, at most, readMax bytes.
+func batched(f func([]byte) error, readMax int) func([]byte) error {
+ return func(out []byte) error {
+ for len(out) > 0 {
+ read := len(out)
+ if read > readMax {
+ read = readMax
+ }
+ if err := f(out[:read]); err != nil {
+ return err
+ }
+ out = out[read:]
+ }
+ return nil
+ }
+}
diff --git a/src/crypto/rand/rand_batched_test.go b/src/crypto/rand/rand_batched_test.go
new file mode 100644
index 0000000..02f4893
--- /dev/null
+++ b/src/crypto/rand/rand_batched_test.go
@@ -0,0 +1,75 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build unix
+
+package rand
+
+import (
+ "bytes"
+ "errors"
+ prand "math/rand"
+ "testing"
+)
+
+func TestBatched(t *testing.T) {
+ fillBatched := batched(func(p []byte) error {
+ for i := range p {
+ p[i] = byte(i)
+ }
+ return nil
+ }, 5)
+
+ p := make([]byte, 13)
+ if err := fillBatched(p); err != nil {
+ t.Fatalf("batched function returned error: %s", err)
+ }
+ expected := []byte{0, 1, 2, 3, 4, 0, 1, 2, 3, 4, 0, 1, 2}
+ if !bytes.Equal(expected, p) {
+ t.Errorf("incorrect batch result: got %x, want %x", p, expected)
+ }
+}
+
+func TestBatchedBuffering(t *testing.T) {
+ backingStore := make([]byte, 1<<23)
+ prand.Read(backingStore)
+ backingMarker := backingStore[:]
+ output := make([]byte, len(backingStore))
+ outputMarker := output[:]
+
+ fillBatched := batched(func(p []byte) error {
+ n := copy(p, backingMarker)
+ backingMarker = backingMarker[n:]
+ return nil
+ }, 731)
+
+ for len(outputMarker) > 0 {
+ max := 9200
+ if max > len(outputMarker) {
+ max = len(outputMarker)
+ }
+ howMuch := prand.Intn(max + 1)
+ if err := fillBatched(outputMarker[:howMuch]); err != nil {
+ t.Fatalf("batched function returned error: %s", err)
+ }
+ outputMarker = outputMarker[howMuch:]
+ }
+ if !bytes.Equal(backingStore, output) {
+ t.Error("incorrect batch result")
+ }
+}
+
+func TestBatchedError(t *testing.T) {
+ b := batched(func(p []byte) error { return errors.New("failure") }, 5)
+ if b(make([]byte, 13)) == nil {
+ t.Fatal("batched function should have returned an error")
+ }
+}
+
+func TestBatchedEmpty(t *testing.T) {
+ b := batched(func(p []byte) error { return errors.New("failure") }, 5)
+ if b(make([]byte, 0)) != nil {
+ t.Fatal("empty slice should always return successful")
+ }
+}
diff --git a/src/crypto/rand/rand_getentropy.go b/src/crypto/rand/rand_getentropy.go
new file mode 100644
index 0000000..68f921b
--- /dev/null
+++ b/src/crypto/rand/rand_getentropy.go
@@ -0,0 +1,14 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (darwin && !ios) || openbsd
+
+package rand
+
+import "internal/syscall/unix"
+
+func init() {
+ // getentropy(2) returns a maximum of 256 bytes per call
+ altGetRandom = batched(unix.GetEntropy, 256)
+}
diff --git a/src/crypto/rand/rand_getrandom.go b/src/crypto/rand/rand_getrandom.go
new file mode 100644
index 0000000..478aa5c
--- /dev/null
+++ b/src/crypto/rand/rand_getrandom.go
@@ -0,0 +1,48 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build linux || freebsd || dragonfly || solaris
+
+package rand
+
+import (
+ "internal/syscall/unix"
+ "runtime"
+ "syscall"
+)
+
+func init() {
+ var maxGetRandomRead int
+ switch runtime.GOOS {
+ case "linux", "android":
+ // Per the manpage:
+ // When reading from the urandom source, a maximum of 33554431 bytes
+ // is returned by a single call to getrandom() on systems where int
+ // has a size of 32 bits.
+ maxGetRandomRead = (1 << 25) - 1
+ case "freebsd", "dragonfly", "solaris", "illumos":
+ maxGetRandomRead = 1 << 8
+ default:
+ panic("no maximum specified for GetRandom")
+ }
+ altGetRandom = batched(getRandom, maxGetRandomRead)
+}
+
+// If the kernel is too old to support the getrandom syscall(),
+// unix.GetRandom will immediately return ENOSYS and we will then fall back to
+// reading from /dev/urandom in rand_unix.go. unix.GetRandom caches the ENOSYS
+// result so we only suffer the syscall overhead once in this case.
+// If the kernel supports the getrandom() syscall, unix.GetRandom will block
+// until the kernel has sufficient randomness (as we don't use GRND_NONBLOCK).
+// In this case, unix.GetRandom will not return an error.
+func getRandom(p []byte) error {
+ n, err := unix.GetRandom(p, 0)
+ if err != nil {
+ return err
+ }
+ if n != len(p) {
+ return syscall.EIO
+ }
+ return nil
+}
diff --git a/src/crypto/rand/rand_js.go b/src/crypto/rand/rand_js.go
new file mode 100644
index 0000000..91e69fa
--- /dev/null
+++ b/src/crypto/rand/rand_js.go
@@ -0,0 +1,28 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build js && wasm
+
+package rand
+
+import "syscall/js"
+
+func init() {
+ Reader = &reader{}
+}
+
+var jsCrypto = js.Global().Get("crypto")
+var uint8Array = js.Global().Get("Uint8Array")
+
+// reader implements a pseudorandom generator
+// using JavaScript crypto.getRandomValues method.
+// See https://developer.mozilla.org/en-US/docs/Web/API/Crypto/getRandomValues.
+type reader struct{}
+
+func (r *reader) Read(b []byte) (int, error) {
+ a := uint8Array.New(len(b))
+ jsCrypto.Call("getRandomValues", a)
+ js.CopyBytesToGo(b, a)
+ return len(b), nil
+}
diff --git a/src/crypto/rand/rand_plan9.go b/src/crypto/rand/rand_plan9.go
new file mode 100644
index 0000000..5d0af09
--- /dev/null
+++ b/src/crypto/rand/rand_plan9.go
@@ -0,0 +1,87 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Plan9 cryptographically secure pseudorandom number
+// generator.
+
+package rand
+
+import (
+ "crypto/aes"
+ "encoding/binary"
+ "io"
+ "os"
+ "sync"
+ "time"
+)
+
+const randomDevice = "/dev/random"
+
+func init() {
+ Reader = &reader{}
+}
+
+// reader is a new pseudorandom generator that seeds itself by
+// reading from /dev/random. The Read method on the returned
+// reader always returns the full amount asked for, or else it
+// returns an error. The generator is a fast key erasure RNG.
+type reader struct {
+ mu sync.Mutex
+ seeded sync.Once
+ seedErr error
+ key [32]byte
+}
+
+func (r *reader) Read(b []byte) (n int, err error) {
+ r.seeded.Do(func() {
+ t := time.AfterFunc(time.Minute, func() {
+ println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
+ })
+ defer t.Stop()
+ entropy, err := os.Open(randomDevice)
+ if err != nil {
+ r.seedErr = err
+ return
+ }
+ _, r.seedErr = io.ReadFull(entropy, r.key[:])
+ })
+ if r.seedErr != nil {
+ return 0, r.seedErr
+ }
+
+ r.mu.Lock()
+ blockCipher, err := aes.NewCipher(r.key[:])
+ if err != nil {
+ r.mu.Unlock()
+ return 0, err
+ }
+ var (
+ counter uint64
+ block [aes.BlockSize]byte
+ )
+ inc := func() {
+ counter++
+ if counter == 0 {
+ panic("crypto/rand counter wrapped")
+ }
+ binary.LittleEndian.PutUint64(block[:], counter)
+ }
+ blockCipher.Encrypt(r.key[:aes.BlockSize], block[:])
+ inc()
+ blockCipher.Encrypt(r.key[aes.BlockSize:], block[:])
+ inc()
+ r.mu.Unlock()
+
+ n = len(b)
+ for len(b) >= aes.BlockSize {
+ blockCipher.Encrypt(b[:aes.BlockSize], block[:])
+ inc()
+ b = b[aes.BlockSize:]
+ }
+ if len(b) > 0 {
+ blockCipher.Encrypt(block[:], block[:])
+ copy(b, block[:])
+ }
+ return n, nil
+}
diff --git a/src/crypto/rand/rand_test.go b/src/crypto/rand/rand_test.go
new file mode 100644
index 0000000..e45f58e
--- /dev/null
+++ b/src/crypto/rand/rand_test.go
@@ -0,0 +1,43 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+import (
+ "bytes"
+ "compress/flate"
+ "io"
+ "testing"
+)
+
+func TestRead(t *testing.T) {
+ var n int = 4e6
+ if testing.Short() {
+ n = 1e5
+ }
+ b := make([]byte, n)
+ n, err := io.ReadFull(Reader, b)
+ if n != len(b) || err != nil {
+ t.Fatalf("ReadFull(buf) = %d, %s", n, err)
+ }
+
+ var z bytes.Buffer
+ f, _ := flate.NewWriter(&z, 5)
+ f.Write(b)
+ f.Close()
+ if z.Len() < len(b)*99/100 {
+ t.Fatalf("Compressed %d -> %d", len(b), z.Len())
+ }
+}
+
+func TestReadEmpty(t *testing.T) {
+ n, err := Reader.Read(make([]byte, 0))
+ if n != 0 || err != nil {
+ t.Fatalf("Read(make([]byte, 0)) = %d, %v", n, err)
+ }
+ n, err = Reader.Read(nil)
+ if n != 0 || err != nil {
+ t.Fatalf("Read(nil) = %d, %v", n, err)
+ }
+}
diff --git a/src/crypto/rand/rand_unix.go b/src/crypto/rand/rand_unix.go
new file mode 100644
index 0000000..40fce36
--- /dev/null
+++ b/src/crypto/rand/rand_unix.go
@@ -0,0 +1,87 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build unix
+
+// Unix cryptographically secure pseudorandom number
+// generator.
+
+package rand
+
+import (
+ "crypto/internal/boring"
+ "errors"
+ "io"
+ "os"
+ "sync"
+ "sync/atomic"
+ "syscall"
+ "time"
+)
+
+const urandomDevice = "/dev/urandom"
+
+func init() {
+ if boring.Enabled {
+ Reader = boring.RandReader
+ return
+ }
+ Reader = &reader{}
+}
+
+// A reader satisfies reads by reading from urandomDevice
+type reader struct {
+ f io.Reader
+ mu sync.Mutex
+ used atomic.Uint32 // Atomic: 0 - never used, 1 - used, but f == nil, 2 - used, and f != nil
+}
+
+// altGetRandom if non-nil specifies an OS-specific function to get
+// urandom-style randomness.
+var altGetRandom func([]byte) (err error)
+
+func warnBlocked() {
+ println("crypto/rand: blocked for 60 seconds waiting to read random data from the kernel")
+}
+
+func (r *reader) Read(b []byte) (n int, err error) {
+ boring.Unreachable()
+ if r.used.CompareAndSwap(0, 1) {
+ // First use of randomness. Start timer to warn about
+ // being blocked on entropy not being available.
+ t := time.AfterFunc(time.Minute, warnBlocked)
+ defer t.Stop()
+ }
+ if altGetRandom != nil && altGetRandom(b) == nil {
+ return len(b), nil
+ }
+ if r.used.Load() != 2 {
+ r.mu.Lock()
+ if r.used.Load() != 2 {
+ f, err := os.Open(urandomDevice)
+ if err != nil {
+ r.mu.Unlock()
+ return 0, err
+ }
+ r.f = hideAgainReader{f}
+ r.used.Store(2)
+ }
+ r.mu.Unlock()
+ }
+ return io.ReadFull(r.f, b)
+}
+
+// hideAgainReader masks EAGAIN reads from /dev/urandom.
+// See golang.org/issue/9205
+type hideAgainReader struct {
+ r io.Reader
+}
+
+func (hr hideAgainReader) Read(p []byte) (n int, err error) {
+ n, err = hr.r.Read(p)
+ if errors.Is(err, syscall.EAGAIN) {
+ err = nil
+ }
+ return
+}
diff --git a/src/crypto/rand/rand_windows.go b/src/crypto/rand/rand_windows.go
new file mode 100644
index 0000000..6c0655c
--- /dev/null
+++ b/src/crypto/rand/rand_windows.go
@@ -0,0 +1,26 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Windows cryptographically secure pseudorandom number
+// generator.
+
+package rand
+
+import (
+ "internal/syscall/windows"
+)
+
+func init() { Reader = &rngReader{} }
+
+type rngReader struct{}
+
+func (r *rngReader) Read(b []byte) (n int, err error) {
+ // RtlGenRandom only returns 1<<32-1 bytes at a time. We only read at
+ // most 1<<31-1 bytes at a time so that this works the same on 32-bit
+ // and 64-bit systems.
+ if err := batched(windows.RtlGenRandom, 1<<31-1)(b); err != nil {
+ return 0, err
+ }
+ return len(b), nil
+}
diff --git a/src/crypto/rand/util.go b/src/crypto/rand/util.go
new file mode 100644
index 0000000..11b1a28
--- /dev/null
+++ b/src/crypto/rand/util.go
@@ -0,0 +1,99 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand
+
+import (
+ "crypto/internal/randutil"
+ "errors"
+ "io"
+ "math/big"
+)
+
+// Prime returns a number of the given bit length that is prime with high probability.
+// Prime will return error for any error returned by rand.Read or if bits < 2.
+func Prime(rand io.Reader, bits int) (*big.Int, error) {
+ if bits < 2 {
+ return nil, errors.New("crypto/rand: prime size must be at least 2-bit")
+ }
+
+ randutil.MaybeReadByte(rand)
+
+ b := uint(bits % 8)
+ if b == 0 {
+ b = 8
+ }
+
+ bytes := make([]byte, (bits+7)/8)
+ p := new(big.Int)
+
+ for {
+ if _, err := io.ReadFull(rand, bytes); err != nil {
+ return nil, err
+ }
+
+ // Clear bits in the first byte to make sure the candidate has a size <= bits.
+ bytes[0] &= uint8(int(1<<b) - 1)
+ // Don't let the value be too small, i.e, set the most significant two bits.
+ // Setting the top two bits, rather than just the top bit,
+ // means that when two of these values are multiplied together,
+ // the result isn't ever one bit short.
+ if b >= 2 {
+ bytes[0] |= 3 << (b - 2)
+ } else {
+ // Here b==1, because b cannot be zero.
+ bytes[0] |= 1
+ if len(bytes) > 1 {
+ bytes[1] |= 0x80
+ }
+ }
+ // Make the value odd since an even number this large certainly isn't prime.
+ bytes[len(bytes)-1] |= 1
+
+ p.SetBytes(bytes)
+ if p.ProbablyPrime(20) {
+ return p, nil
+ }
+ }
+}
+
+// Int returns a uniform random value in [0, max). It panics if max <= 0.
+func Int(rand io.Reader, max *big.Int) (n *big.Int, err error) {
+ if max.Sign() <= 0 {
+ panic("crypto/rand: argument to Int is <= 0")
+ }
+ n = new(big.Int)
+ n.Sub(max, n.SetUint64(1))
+ // bitLen is the maximum bit length needed to encode a value < max.
+ bitLen := n.BitLen()
+ if bitLen == 0 {
+ // the only valid result is 0
+ return
+ }
+ // k is the maximum byte length needed to encode a value < max.
+ k := (bitLen + 7) / 8
+ // b is the number of bits in the most significant byte of max-1.
+ b := uint(bitLen % 8)
+ if b == 0 {
+ b = 8
+ }
+
+ bytes := make([]byte, k)
+
+ for {
+ _, err = io.ReadFull(rand, bytes)
+ if err != nil {
+ return nil, err
+ }
+
+ // Clear bits in the first byte to increase the probability
+ // that the candidate is < max.
+ bytes[0] &= uint8(int(1<<b) - 1)
+
+ n.SetBytes(bytes)
+ if n.Cmp(max) < 0 {
+ return
+ }
+ }
+}
diff --git a/src/crypto/rand/util_test.go b/src/crypto/rand/util_test.go
new file mode 100644
index 0000000..9caf8e9
--- /dev/null
+++ b/src/crypto/rand/util_test.go
@@ -0,0 +1,149 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rand_test
+
+import (
+ "bytes"
+ "crypto/rand"
+ "fmt"
+ "io"
+ "math/big"
+ mathrand "math/rand"
+ "testing"
+ "time"
+)
+
+// https://golang.org/issue/6849.
+func TestPrimeSmall(t *testing.T) {
+ for n := 2; n < 10; n++ {
+ p, err := rand.Prime(rand.Reader, n)
+ if err != nil {
+ t.Fatalf("Can't generate %d-bit prime: %v", n, err)
+ }
+ if p.BitLen() != n {
+ t.Fatalf("%v is not %d-bit", p, n)
+ }
+ if !p.ProbablyPrime(32) {
+ t.Fatalf("%v is not prime", p)
+ }
+ }
+}
+
+// Test that passing bits < 2 causes Prime to return nil, error
+func TestPrimeBitsLt2(t *testing.T) {
+ if p, err := rand.Prime(rand.Reader, 1); p != nil || err == nil {
+ t.Errorf("Prime should return nil, error when called with bits < 2")
+ }
+}
+
+func TestPrimeNondeterministic(t *testing.T) {
+ r := mathrand.New(mathrand.NewSource(42))
+ p0, err := rand.Prime(r, 32)
+ if err != nil {
+ t.Fatal(err)
+ }
+ for i := 0; i < 128; i++ {
+ r.Seed(42)
+ p, err := rand.Prime(r, 32)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if p.Cmp(p0) != 0 {
+ return
+ }
+ }
+ t.Error("Prime always generated the same prime given the same input")
+}
+
+func TestInt(t *testing.T) {
+ // start at 128 so the case of (max.BitLen() % 8) == 0 is covered
+ for n := 128; n < 140; n++ {
+ b := new(big.Int).SetInt64(int64(n))
+ if i, err := rand.Int(rand.Reader, b); err != nil {
+ t.Fatalf("Can't generate random value: %v, %v", i, err)
+ }
+ }
+}
+
+type countingReader struct {
+ r io.Reader
+ n int
+}
+
+func (r *countingReader) Read(p []byte) (n int, err error) {
+ n, err = r.r.Read(p)
+ r.n += n
+ return n, err
+}
+
+// Test that Int reads only the necessary number of bytes from the reader for
+// max at each bit length
+func TestIntReads(t *testing.T) {
+ for i := 0; i < 32; i++ {
+ max := int64(1 << uint64(i))
+ t.Run(fmt.Sprintf("max=%d", max), func(t *testing.T) {
+ reader := &countingReader{r: rand.Reader}
+
+ _, err := rand.Int(reader, big.NewInt(max))
+ if err != nil {
+ t.Fatalf("Can't generate random value: %d, %v", max, err)
+ }
+ expected := (i + 7) / 8
+ if reader.n != expected {
+ t.Errorf("Int(reader, %d) should read %d bytes, but it read: %d", max, expected, reader.n)
+ }
+ })
+ }
+}
+
+// Test that Int does not mask out valid return values
+func TestIntMask(t *testing.T) {
+ for max := 1; max <= 256; max++ {
+ t.Run(fmt.Sprintf("max=%d", max), func(t *testing.T) {
+ for i := 0; i < max; i++ {
+ if testing.Short() && i == 0 {
+ i = max - 1
+ }
+ var b bytes.Buffer
+ b.WriteByte(byte(i))
+ n, err := rand.Int(&b, big.NewInt(int64(max)))
+ if err != nil {
+ t.Fatalf("Can't generate random value: %d, %v", max, err)
+ }
+ if n.Int64() != int64(i) {
+ t.Errorf("Int(reader, %d) should have returned value of %d, but it returned: %v", max, i, n)
+ }
+ }
+ })
+ }
+}
+
+func testIntPanics(t *testing.T, b *big.Int) {
+ defer func() {
+ if err := recover(); err == nil {
+ t.Errorf("Int should panic when called with max <= 0: %v", b)
+ }
+ }()
+ rand.Int(rand.Reader, b)
+}
+
+// Test that passing a new big.Int as max causes Int to panic
+func TestIntEmptyMaxPanics(t *testing.T) {
+ b := new(big.Int)
+ testIntPanics(t, b)
+}
+
+// Test that passing a negative value as max causes Int to panic
+func TestIntNegativeMaxPanics(t *testing.T) {
+ b := new(big.Int).SetInt64(int64(-1))
+ testIntPanics(t, b)
+}
+
+func BenchmarkPrime(b *testing.B) {
+ r := mathrand.New(mathrand.NewSource(time.Now().UnixNano()))
+ for i := 0; i < b.N; i++ {
+ rand.Prime(r, 1024)
+ }
+}
diff --git a/src/crypto/rc4/rc4.go b/src/crypto/rc4/rc4.go
new file mode 100644
index 0000000..f08da0e
--- /dev/null
+++ b/src/crypto/rc4/rc4.go
@@ -0,0 +1,80 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package rc4 implements RC4 encryption, as defined in Bruce Schneier's
+// Applied Cryptography.
+//
+// RC4 is cryptographically broken and should not be used for secure
+// applications.
+package rc4
+
+import (
+ "crypto/internal/alias"
+ "strconv"
+)
+
+// A Cipher is an instance of RC4 using a particular key.
+type Cipher struct {
+ s [256]uint32
+ i, j uint8
+}
+
+type KeySizeError int
+
+func (k KeySizeError) Error() string {
+ return "crypto/rc4: invalid key size " + strconv.Itoa(int(k))
+}
+
+// NewCipher creates and returns a new Cipher. The key argument should be the
+// RC4 key, at least 1 byte and at most 256 bytes.
+func NewCipher(key []byte) (*Cipher, error) {
+ k := len(key)
+ if k < 1 || k > 256 {
+ return nil, KeySizeError(k)
+ }
+ var c Cipher
+ for i := 0; i < 256; i++ {
+ c.s[i] = uint32(i)
+ }
+ var j uint8 = 0
+ for i := 0; i < 256; i++ {
+ j += uint8(c.s[i]) + key[i%k]
+ c.s[i], c.s[j] = c.s[j], c.s[i]
+ }
+ return &c, nil
+}
+
+// Reset zeros the key data and makes the Cipher unusable.
+//
+// Deprecated: Reset can't guarantee that the key will be entirely removed from
+// the process's memory.
+func (c *Cipher) Reset() {
+ for i := range c.s {
+ c.s[i] = 0
+ }
+ c.i, c.j = 0, 0
+}
+
+// XORKeyStream sets dst to the result of XORing src with the key stream.
+// Dst and src must overlap entirely or not at all.
+func (c *Cipher) XORKeyStream(dst, src []byte) {
+ if len(src) == 0 {
+ return
+ }
+ if alias.InexactOverlap(dst[:len(src)], src) {
+ panic("crypto/rc4: invalid buffer overlap")
+ }
+ i, j := c.i, c.j
+ _ = dst[len(src)-1]
+ dst = dst[:len(src)] // eliminate bounds check from loop
+ for k, v := range src {
+ i += 1
+ x := c.s[i]
+ j += uint8(x)
+ y := c.s[j]
+ c.s[i], c.s[j] = y, x
+ dst[k] = v ^ uint8(c.s[uint8(x+y)])
+ }
+ c.i, c.j = i, j
+}
diff --git a/src/crypto/rc4/rc4_test.go b/src/crypto/rc4/rc4_test.go
new file mode 100644
index 0000000..e7356aa
--- /dev/null
+++ b/src/crypto/rc4/rc4_test.go
@@ -0,0 +1,162 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rc4
+
+import (
+ "bytes"
+ "fmt"
+ "testing"
+)
+
+type rc4Test struct {
+ key, keystream []byte
+}
+
+var golden = []rc4Test{
+ // Test vectors from the original cypherpunk posting of ARC4:
+ // https://groups.google.com/group/sci.crypt/msg/10a300c9d21afca0?pli=1
+ {
+ []byte{0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef},
+ []byte{0x74, 0x94, 0xc2, 0xe7, 0x10, 0x4b, 0x08, 0x79},
+ },
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{0xde, 0x18, 0x89, 0x41, 0xa3, 0x37, 0x5d, 0x3a},
+ },
+ {
+ []byte{0xef, 0x01, 0x23, 0x45},
+ []byte{0xd6, 0xa1, 0x41, 0xa7, 0xec, 0x3c, 0x38, 0xdf, 0xbd, 0x61},
+ },
+
+ // Test vectors from the Wikipedia page: https://en.wikipedia.org/wiki/RC4
+ {
+ []byte{0x4b, 0x65, 0x79},
+ []byte{0xeb, 0x9f, 0x77, 0x81, 0xb7, 0x34, 0xca, 0x72, 0xa7, 0x19},
+ },
+ {
+ []byte{0x57, 0x69, 0x6b, 0x69},
+ []byte{0x60, 0x44, 0xdb, 0x6d, 0x41, 0xb7},
+ },
+ {
+ []byte{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+ []byte{
+ 0xde, 0x18, 0x89, 0x41, 0xa3, 0x37, 0x5d, 0x3a,
+ 0x8a, 0x06, 0x1e, 0x67, 0x57, 0x6e, 0x92, 0x6d,
+ 0xc7, 0x1a, 0x7f, 0xa3, 0xf0, 0xcc, 0xeb, 0x97,
+ 0x45, 0x2b, 0x4d, 0x32, 0x27, 0x96, 0x5f, 0x9e,
+ 0xa8, 0xcc, 0x75, 0x07, 0x6d, 0x9f, 0xb9, 0xc5,
+ 0x41, 0x7a, 0xa5, 0xcb, 0x30, 0xfc, 0x22, 0x19,
+ 0x8b, 0x34, 0x98, 0x2d, 0xbb, 0x62, 0x9e, 0xc0,
+ 0x4b, 0x4f, 0x8b, 0x05, 0xa0, 0x71, 0x08, 0x50,
+ 0x92, 0xa0, 0xc3, 0x58, 0x4a, 0x48, 0xe4, 0xa3,
+ 0x0a, 0x39, 0x7b, 0x8a, 0xcd, 0x1d, 0x00, 0x9e,
+ 0xc8, 0x7d, 0x68, 0x11, 0xf2, 0x2c, 0xf4, 0x9c,
+ 0xa3, 0xe5, 0x93, 0x54, 0xb9, 0x45, 0x15, 0x35,
+ 0xa2, 0x18, 0x7a, 0x86, 0x42, 0x6c, 0xca, 0x7d,
+ 0x5e, 0x82, 0x3e, 0xba, 0x00, 0x44, 0x12, 0x67,
+ 0x12, 0x57, 0xb8, 0xd8, 0x60, 0xae, 0x4c, 0xbd,
+ 0x4c, 0x49, 0x06, 0xbb, 0xc5, 0x35, 0xef, 0xe1,
+ 0x58, 0x7f, 0x08, 0xdb, 0x33, 0x95, 0x5c, 0xdb,
+ 0xcb, 0xad, 0x9b, 0x10, 0xf5, 0x3f, 0xc4, 0xe5,
+ 0x2c, 0x59, 0x15, 0x65, 0x51, 0x84, 0x87, 0xfe,
+ 0x08, 0x4d, 0x0e, 0x3f, 0x03, 0xde, 0xbc, 0xc9,
+ 0xda, 0x1c, 0xe9, 0x0d, 0x08, 0x5c, 0x2d, 0x8a,
+ 0x19, 0xd8, 0x37, 0x30, 0x86, 0x16, 0x36, 0x92,
+ 0x14, 0x2b, 0xd8, 0xfc, 0x5d, 0x7a, 0x73, 0x49,
+ 0x6a, 0x8e, 0x59, 0xee, 0x7e, 0xcf, 0x6b, 0x94,
+ 0x06, 0x63, 0xf4, 0xa6, 0xbe, 0xe6, 0x5b, 0xd2,
+ 0xc8, 0x5c, 0x46, 0x98, 0x6c, 0x1b, 0xef, 0x34,
+ 0x90, 0xd3, 0x7b, 0x38, 0xda, 0x85, 0xd3, 0x2e,
+ 0x97, 0x39, 0xcb, 0x23, 0x4a, 0x2b, 0xe7, 0x40,
+ },
+ },
+}
+
+func testEncrypt(t *testing.T, desc string, c *Cipher, src, expect []byte) {
+ dst := make([]byte, len(src))
+ c.XORKeyStream(dst, src)
+ for i, v := range dst {
+ if v != expect[i] {
+ t.Fatalf("%s: mismatch at byte %d:\nhave %x\nwant %x", desc, i, dst, expect)
+ }
+ }
+}
+
+func TestGolden(t *testing.T) {
+ for gi, g := range golden {
+ data := make([]byte, len(g.keystream))
+ for i := range data {
+ data[i] = byte(i)
+ }
+
+ expect := make([]byte, len(g.keystream))
+ for i := range expect {
+ expect[i] = byte(i) ^ g.keystream[i]
+ }
+
+ for size := 1; size <= len(g.keystream); size++ {
+ c, err := NewCipher(g.key)
+ if err != nil {
+ t.Fatalf("#%d: NewCipher: %v", gi, err)
+ }
+
+ off := 0
+ for off < len(g.keystream) {
+ n := len(g.keystream) - off
+ if n > size {
+ n = size
+ }
+ desc := fmt.Sprintf("#%d@[%d:%d]", gi, off, off+n)
+ testEncrypt(t, desc, c, data[off:off+n], expect[off:off+n])
+ off += n
+ }
+ }
+ }
+}
+
+func TestBlock(t *testing.T) {
+ c1a, _ := NewCipher(golden[0].key)
+ c1b, _ := NewCipher(golden[1].key)
+ data1 := make([]byte, 1<<20)
+ for i := range data1 {
+ c1a.XORKeyStream(data1[i:i+1], data1[i:i+1])
+ c1b.XORKeyStream(data1[i:i+1], data1[i:i+1])
+ }
+
+ c2a, _ := NewCipher(golden[0].key)
+ c2b, _ := NewCipher(golden[1].key)
+ data2 := make([]byte, 1<<20)
+ c2a.XORKeyStream(data2, data2)
+ c2b.XORKeyStream(data2, data2)
+
+ if !bytes.Equal(data1, data2) {
+ t.Fatalf("bad block")
+ }
+}
+
+func benchmark(b *testing.B, size int64) {
+ buf := make([]byte, size)
+ c, err := NewCipher(golden[0].key)
+ if err != nil {
+ panic(err)
+ }
+ b.SetBytes(size)
+
+ for i := 0; i < b.N; i++ {
+ c.XORKeyStream(buf, buf)
+ }
+}
+
+func BenchmarkRC4_128(b *testing.B) {
+ benchmark(b, 128)
+}
+
+func BenchmarkRC4_1K(b *testing.B) {
+ benchmark(b, 1024)
+}
+
+func BenchmarkRC4_8K(b *testing.B) {
+ benchmark(b, 8096)
+}
diff --git a/src/crypto/rsa/boring.go b/src/crypto/rsa/boring.go
new file mode 100644
index 0000000..b9f9d31
--- /dev/null
+++ b/src/crypto/rsa/boring.go
@@ -0,0 +1,130 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto
+
+package rsa
+
+import (
+ "crypto/internal/boring"
+ "crypto/internal/boring/bbig"
+ "crypto/internal/boring/bcache"
+ "math/big"
+)
+
+// Cached conversions from Go PublicKey/PrivateKey to BoringCrypto.
+//
+// The first operation on a PublicKey or PrivateKey makes a parallel
+// BoringCrypto key and saves it in pubCache or privCache.
+//
+// We could just assume that once used in a sign/verify/encrypt/decrypt operation,
+// a particular key is never again modified, but that has not been a
+// stated assumption before. Just in case there is any existing code that
+// does modify the key between operations, we save the original values
+// alongside the cached BoringCrypto key and check that the real key
+// still matches before using the cached key. The theory is that the real
+// operations are significantly more expensive than the comparison.
+
+type boringPub struct {
+ key *boring.PublicKeyRSA
+ orig PublicKey
+}
+
+var pubCache bcache.Cache[PublicKey, boringPub]
+var privCache bcache.Cache[PrivateKey, boringPriv]
+
+func init() {
+ pubCache.Register()
+ privCache.Register()
+}
+
+func boringPublicKey(pub *PublicKey) (*boring.PublicKeyRSA, error) {
+ b := pubCache.Get(pub)
+ if b != nil && publicKeyEqual(&b.orig, pub) {
+ return b.key, nil
+ }
+
+ b = new(boringPub)
+ b.orig = copyPublicKey(pub)
+ key, err := boring.NewPublicKeyRSA(bbig.Enc(b.orig.N), bbig.Enc(big.NewInt(int64(b.orig.E))))
+ if err != nil {
+ return nil, err
+ }
+ b.key = key
+ pubCache.Put(pub, b)
+ return key, nil
+}
+
+type boringPriv struct {
+ key *boring.PrivateKeyRSA
+ orig PrivateKey
+}
+
+func boringPrivateKey(priv *PrivateKey) (*boring.PrivateKeyRSA, error) {
+ b := privCache.Get(priv)
+ if b != nil && privateKeyEqual(&b.orig, priv) {
+ return b.key, nil
+ }
+
+ b = new(boringPriv)
+ b.orig = copyPrivateKey(priv)
+
+ var N, E, D, P, Q, Dp, Dq, Qinv *big.Int
+ N = b.orig.N
+ E = big.NewInt(int64(b.orig.E))
+ D = b.orig.D
+ if len(b.orig.Primes) == 2 {
+ P = b.orig.Primes[0]
+ Q = b.orig.Primes[1]
+ Dp = b.orig.Precomputed.Dp
+ Dq = b.orig.Precomputed.Dq
+ Qinv = b.orig.Precomputed.Qinv
+ }
+ key, err := boring.NewPrivateKeyRSA(bbig.Enc(N), bbig.Enc(E), bbig.Enc(D), bbig.Enc(P), bbig.Enc(Q), bbig.Enc(Dp), bbig.Enc(Dq), bbig.Enc(Qinv))
+ if err != nil {
+ return nil, err
+ }
+ b.key = key
+ privCache.Put(priv, b)
+ return key, nil
+}
+
+func publicKeyEqual(k1, k2 *PublicKey) bool {
+ return k1.N != nil &&
+ k1.N.Cmp(k2.N) == 0 &&
+ k1.E == k2.E
+}
+
+func copyPublicKey(k *PublicKey) PublicKey {
+ return PublicKey{
+ N: new(big.Int).Set(k.N),
+ E: k.E,
+ }
+}
+
+func privateKeyEqual(k1, k2 *PrivateKey) bool {
+ return publicKeyEqual(&k1.PublicKey, &k2.PublicKey) &&
+ k1.D.Cmp(k2.D) == 0
+}
+
+func copyPrivateKey(k *PrivateKey) PrivateKey {
+ dst := PrivateKey{
+ PublicKey: copyPublicKey(&k.PublicKey),
+ D: new(big.Int).Set(k.D),
+ }
+ dst.Primes = make([]*big.Int, len(k.Primes))
+ for i, p := range k.Primes {
+ dst.Primes[i] = new(big.Int).Set(p)
+ }
+ if x := k.Precomputed.Dp; x != nil {
+ dst.Precomputed.Dp = new(big.Int).Set(x)
+ }
+ if x := k.Precomputed.Dq; x != nil {
+ dst.Precomputed.Dq = new(big.Int).Set(x)
+ }
+ if x := k.Precomputed.Qinv; x != nil {
+ dst.Precomputed.Qinv = new(big.Int).Set(x)
+ }
+ return dst
+}
diff --git a/src/crypto/rsa/boring_test.go b/src/crypto/rsa/boring_test.go
new file mode 100644
index 0000000..2234d07
--- /dev/null
+++ b/src/crypto/rsa/boring_test.go
@@ -0,0 +1,148 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto
+
+// Note: Can run these tests against the non-BoringCrypto
+// version of the code by using "CGO_ENABLED=0 go test".
+
+package rsa
+
+import (
+ "crypto"
+ "crypto/rand"
+ "encoding/asn1"
+ "encoding/hex"
+ "math/big"
+ "runtime"
+ "runtime/debug"
+ "sync"
+ "testing"
+)
+
+func TestBoringASN1Marshal(t *testing.T) {
+ k, err := GenerateKey(rand.Reader, 128)
+ if err != nil {
+ t.Fatal(err)
+ }
+ _, err = asn1.Marshal(k.PublicKey)
+ if err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestBoringVerify(t *testing.T) {
+ // Check that signatures that lack leading zeroes don't verify.
+ key := &PublicKey{
+ N: bigFromHex("c4fdf7b40a5477f206e6ee278eaef888ca73bf9128a9eef9f2f1ddb8b7b71a4c07cfa241f028a04edb405e4d916c61d6beabc333813dc7b484d2b3c52ee233c6a79b1eea4e9cc51596ba9cd5ac5aeb9df62d86ea051055b79d03f8a4fa9f38386f5bd17529138f3325d46801514ea9047977e0829ed728e68636802796801be1"),
+ E: 65537,
+ }
+
+ hash := fromHex("019c5571724fb5d0e47a4260c940e9803ba05a44")
+ paddedHash := fromHex("3021300906052b0e03021a05000414019c5571724fb5d0e47a4260c940e9803ba05a44")
+
+ // signature is one byte shorter than key.N.
+ sig := fromHex("5edfbeb6a73e7225ad3cc52724e2872e04260d7daf0d693c170d8c4b243b8767bc7785763533febc62ec2600c30603c433c095453ede59ff2fcabeb84ce32e0ed9d5cf15ffcbc816202b64370d4d77c1e9077d74e94a16fb4fa2e5bec23a56d7a73cf275f91691ae1801a976fcde09e981a2f6327ac27ea1fecf3185df0d56")
+
+ err := VerifyPKCS1v15(key, 0, paddedHash, sig)
+ if err == nil {
+ t.Errorf("raw: expected verification error")
+ }
+
+ err = VerifyPKCS1v15(key, crypto.SHA1, hash, sig)
+ if err == nil {
+ t.Errorf("sha1: expected verification error")
+ }
+}
+
+func BenchmarkBoringVerify(b *testing.B) {
+ // Check that signatures that lack leading zeroes don't verify.
+ key := &PublicKey{
+ N: bigFromHex("c4fdf7b40a5477f206e6ee278eaef888ca73bf9128a9eef9f2f1ddb8b7b71a4c07cfa241f028a04edb405e4d916c61d6beabc333813dc7b484d2b3c52ee233c6a79b1eea4e9cc51596ba9cd5ac5aeb9df62d86ea051055b79d03f8a4fa9f38386f5bd17529138f3325d46801514ea9047977e0829ed728e68636802796801be1"),
+ E: 65537,
+ }
+
+ hash := fromHex("019c5571724fb5d0e47a4260c940e9803ba05a44")
+
+ // signature is one byte shorter than key.N.
+ sig := fromHex("5edfbeb6a73e7225ad3cc52724e2872e04260d7daf0d693c170d8c4b243b8767bc7785763533febc62ec2600c30603c433c095453ede59ff2fcabeb84ce32e0ed9d5cf15ffcbc816202b64370d4d77c1e9077d74e94a16fb4fa2e5bec23a56d7a73cf275f91691ae1801a976fcde09e981a2f6327ac27ea1fecf3185df0d56")
+
+ b.ReportAllocs()
+
+ for i := 0; i < b.N; i++ {
+ err := VerifyPKCS1v15(key, crypto.SHA1, hash, sig)
+ if err == nil {
+ b.Fatalf("sha1: expected verification error")
+ }
+ }
+}
+
+func TestBoringGenerateKey(t *testing.T) {
+ k, err := GenerateKey(rand.Reader, 2048) // 2048 is smallest size BoringCrypto might kick in for
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Non-Boring GenerateKey always sets CRTValues to a non-nil (possibly empty) slice.
+ if k.Precomputed.CRTValues == nil {
+ t.Fatalf("GenerateKey: Precomputed.CRTValues = nil")
+ }
+}
+
+func TestBoringFinalizers(t *testing.T) {
+ if runtime.GOOS == "nacl" || runtime.GOOS == "js" {
+ // Times out on nacl and js/wasm (without BoringCrypto)
+ // but not clear why - probably consuming rand.Reader too quickly
+ // and being throttled. Also doesn't really matter.
+ t.Skipf("skipping on %s/%s", runtime.GOOS, runtime.GOARCH)
+ }
+
+ k, err := GenerateKey(rand.Reader, 2048)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Run test with GOGC=10, to make bug more likely.
+ // Without the KeepAlives, the loop usually dies after
+ // about 30 iterations.
+ defer debug.SetGCPercent(debug.SetGCPercent(10))
+ for n := 0; n < 200; n++ {
+ // Clear the underlying BoringCrypto object cache.
+ privCache.Clear()
+
+ // Race to create the underlying BoringCrypto object.
+ // The ones that lose the race are prime candidates for
+ // being GC'ed too early if the finalizers are not being
+ // used correctly.
+ var wg sync.WaitGroup
+ for i := 0; i < 10; i++ {
+ wg.Add(1)
+ go func() {
+ defer wg.Done()
+ sum := make([]byte, 32)
+ _, err := SignPKCS1v15(rand.Reader, k, crypto.SHA256, sum)
+ if err != nil {
+ panic(err) // usually caused by memory corruption, so hard stop
+ }
+ }()
+ }
+ wg.Wait()
+ }
+}
+
+func bigFromHex(hex string) *big.Int {
+ n, ok := new(big.Int).SetString(hex, 16)
+ if !ok {
+ panic("bad hex: " + hex)
+ }
+ return n
+}
+
+func fromHex(hexStr string) []byte {
+ s, err := hex.DecodeString(hexStr)
+ if err != nil {
+ panic(err)
+ }
+ return s
+}
diff --git a/src/crypto/rsa/equal_test.go b/src/crypto/rsa/equal_test.go
new file mode 100644
index 0000000..90f4bf9
--- /dev/null
+++ b/src/crypto/rsa/equal_test.go
@@ -0,0 +1,51 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rsa_test
+
+import (
+ "crypto"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/x509"
+ "testing"
+)
+
+func TestEqual(t *testing.T) {
+ private, _ := rsa.GenerateKey(rand.Reader, 512)
+ public := &private.PublicKey
+
+ if !public.Equal(public) {
+ t.Errorf("public key is not equal to itself: %v", public)
+ }
+ if !public.Equal(crypto.Signer(private).Public().(*rsa.PublicKey)) {
+ t.Errorf("private.Public() is not Equal to public: %q", public)
+ }
+ if !private.Equal(private) {
+ t.Errorf("private key is not equal to itself: %v", private)
+ }
+
+ enc, err := x509.MarshalPKCS8PrivateKey(private)
+ if err != nil {
+ t.Fatal(err)
+ }
+ decoded, err := x509.ParsePKCS8PrivateKey(enc)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !public.Equal(decoded.(crypto.Signer).Public()) {
+ t.Errorf("public key is not equal to itself after decoding: %v", public)
+ }
+ if !private.Equal(decoded) {
+ t.Errorf("private key is not equal to itself after decoding: %v", private)
+ }
+
+ other, _ := rsa.GenerateKey(rand.Reader, 512)
+ if public.Equal(other.Public()) {
+ t.Errorf("different public keys are Equal")
+ }
+ if private.Equal(other) {
+ t.Errorf("different private keys are Equal")
+ }
+}
diff --git a/src/crypto/rsa/example_test.go b/src/crypto/rsa/example_test.go
new file mode 100644
index 0000000..d07ee7d
--- /dev/null
+++ b/src/crypto/rsa/example_test.go
@@ -0,0 +1,157 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rsa_test
+
+import (
+ "crypto"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/sha256"
+ "encoding/hex"
+ "fmt"
+ "os"
+)
+
+// RSA is able to encrypt only a very limited amount of data. In order
+// to encrypt reasonable amounts of data a hybrid scheme is commonly
+// used: RSA is used to encrypt a key for a symmetric primitive like
+// AES-GCM.
+//
+// Before encrypting, data is “padded” by embedding it in a known
+// structure. This is done for a number of reasons, but the most
+// obvious is to ensure that the value is large enough that the
+// exponentiation is larger than the modulus. (Otherwise it could be
+// decrypted with a square-root.)
+//
+// In these designs, when using PKCS #1 v1.5, it's vitally important to
+// avoid disclosing whether the received RSA message was well-formed
+// (that is, whether the result of decrypting is a correctly padded
+// message) because this leaks secret information.
+// DecryptPKCS1v15SessionKey is designed for this situation and copies
+// the decrypted, symmetric key (if well-formed) in constant-time over
+// a buffer that contains a random key. Thus, if the RSA result isn't
+// well-formed, the implementation uses a random key in constant time.
+func ExampleDecryptPKCS1v15SessionKey() {
+ // The hybrid scheme should use at least a 16-byte symmetric key. Here
+ // we read the random key that will be used if the RSA decryption isn't
+ // well-formed.
+ key := make([]byte, 32)
+ if _, err := rand.Read(key); err != nil {
+ panic("RNG failure")
+ }
+
+ rsaCiphertext, _ := hex.DecodeString("aabbccddeeff")
+
+ if err := rsa.DecryptPKCS1v15SessionKey(nil, rsaPrivateKey, rsaCiphertext, key); err != nil {
+ // Any errors that result will be “public” – meaning that they
+ // can be determined without any secret information. (For
+ // instance, if the length of key is impossible given the RSA
+ // public key.)
+ fmt.Fprintf(os.Stderr, "Error from RSA decryption: %s\n", err)
+ return
+ }
+
+ // Given the resulting key, a symmetric scheme can be used to decrypt a
+ // larger ciphertext.
+ block, err := aes.NewCipher(key)
+ if err != nil {
+ panic("aes.NewCipher failed: " + err.Error())
+ }
+
+ // Since the key is random, using a fixed nonce is acceptable as the
+ // (key, nonce) pair will still be unique, as required.
+ var zeroNonce [12]byte
+ aead, err := cipher.NewGCM(block)
+ if err != nil {
+ panic("cipher.NewGCM failed: " + err.Error())
+ }
+ ciphertext, _ := hex.DecodeString("00112233445566")
+ plaintext, err := aead.Open(nil, zeroNonce[:], ciphertext, nil)
+ if err != nil {
+ // The RSA ciphertext was badly formed; the decryption will
+ // fail here because the AES-GCM key will be incorrect.
+ fmt.Fprintf(os.Stderr, "Error decrypting: %s\n", err)
+ return
+ }
+
+ fmt.Printf("Plaintext: %s\n", string(plaintext))
+}
+
+func ExampleSignPKCS1v15() {
+ message := []byte("message to be signed")
+
+ // Only small messages can be signed directly; thus the hash of a
+ // message, rather than the message itself, is signed. This requires
+ // that the hash function be collision resistant. SHA-256 is the
+ // least-strong hash function that should be used for this at the time
+ // of writing (2016).
+ hashed := sha256.Sum256(message)
+
+ signature, err := rsa.SignPKCS1v15(nil, rsaPrivateKey, crypto.SHA256, hashed[:])
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error from signing: %s\n", err)
+ return
+ }
+
+ fmt.Printf("Signature: %x\n", signature)
+}
+
+func ExampleVerifyPKCS1v15() {
+ message := []byte("message to be signed")
+ signature, _ := hex.DecodeString("ad2766728615cc7a746cc553916380ca7bfa4f8983b990913bc69eb0556539a350ff0f8fe65ddfd3ebe91fe1c299c2fac135bc8c61e26be44ee259f2f80c1530")
+
+ // Only small messages can be signed directly; thus the hash of a
+ // message, rather than the message itself, is signed. This requires
+ // that the hash function be collision resistant. SHA-256 is the
+ // least-strong hash function that should be used for this at the time
+ // of writing (2016).
+ hashed := sha256.Sum256(message)
+
+ err := rsa.VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.SHA256, hashed[:], signature)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error from verification: %s\n", err)
+ return
+ }
+
+ // signature is a valid signature of message from the public key.
+}
+
+func ExampleEncryptOAEP() {
+ secretMessage := []byte("send reinforcements, we're going to advance")
+ label := []byte("orders")
+
+ // crypto/rand.Reader is a good source of entropy for randomizing the
+ // encryption function.
+ rng := rand.Reader
+
+ ciphertext, err := rsa.EncryptOAEP(sha256.New(), rng, &test2048Key.PublicKey, secretMessage, label)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error from encryption: %s\n", err)
+ return
+ }
+
+ // Since encryption is a randomized function, ciphertext will be
+ // different each time.
+ fmt.Printf("Ciphertext: %x\n", ciphertext)
+}
+
+func ExampleDecryptOAEP() {
+ ciphertext, _ := hex.DecodeString("4d1ee10e8f286390258c51a5e80802844c3e6358ad6690b7285218a7c7ed7fc3a4c7b950fbd04d4b0239cc060dcc7065ca6f84c1756deb71ca5685cadbb82be025e16449b905c568a19c088a1abfad54bf7ecc67a7df39943ec511091a34c0f2348d04e058fcff4d55644de3cd1d580791d4524b92f3e91695582e6e340a1c50b6c6d78e80b4e42c5b4d45e479b492de42bbd39cc642ebb80226bb5200020d501b24a37bcc2ec7f34e596b4fd6b063de4858dbf5a4e3dd18e262eda0ec2d19dbd8e890d672b63d368768360b20c0b6b8592a438fa275e5fa7f60bef0dd39673fd3989cc54d2cb80c08fcd19dacbc265ee1c6014616b0e04ea0328c2a04e73460")
+ label := []byte("orders")
+
+ plaintext, err := rsa.DecryptOAEP(sha256.New(), nil, test2048Key, ciphertext, label)
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Error from decryption: %s\n", err)
+ return
+ }
+
+ fmt.Printf("Plaintext: %s\n", string(plaintext))
+
+ // Remember that encryption only provides confidentiality. The
+ // ciphertext should be signed before authenticity is assumed and, even
+ // then, consider that messages might be reordered.
+}
diff --git a/src/crypto/rsa/notboring.go b/src/crypto/rsa/notboring.go
new file mode 100644
index 0000000..2abc043
--- /dev/null
+++ b/src/crypto/rsa/notboring.go
@@ -0,0 +1,16 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !boringcrypto
+
+package rsa
+
+import "crypto/internal/boring"
+
+func boringPublicKey(*PublicKey) (*boring.PublicKeyRSA, error) {
+ panic("boringcrypto: not available")
+}
+func boringPrivateKey(*PrivateKey) (*boring.PrivateKeyRSA, error) {
+ panic("boringcrypto: not available")
+}
diff --git a/src/crypto/rsa/pkcs1v15.go b/src/crypto/rsa/pkcs1v15.go
new file mode 100644
index 0000000..e51b9d2
--- /dev/null
+++ b/src/crypto/rsa/pkcs1v15.go
@@ -0,0 +1,375 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rsa
+
+import (
+ "crypto"
+ "crypto/internal/boring"
+ "crypto/internal/randutil"
+ "crypto/subtle"
+ "errors"
+ "io"
+)
+
+// This file implements encryption and decryption using PKCS #1 v1.5 padding.
+
+// PKCS1v15DecryptOptions is for passing options to PKCS #1 v1.5 decryption using
+// the crypto.Decrypter interface.
+type PKCS1v15DecryptOptions struct {
+ // SessionKeyLen is the length of the session key that is being
+ // decrypted. If not zero, then a padding error during decryption will
+ // cause a random plaintext of this length to be returned rather than
+ // an error. These alternatives happen in constant time.
+ SessionKeyLen int
+}
+
+// EncryptPKCS1v15 encrypts the given message with RSA and the padding
+// scheme from PKCS #1 v1.5. The message must be no longer than the
+// length of the public modulus minus 11 bytes.
+//
+// The random parameter is used as a source of entropy to ensure that
+// encrypting the same message twice doesn't result in the same
+// ciphertext.
+//
+// WARNING: use of this function to encrypt plaintexts other than
+// session keys is dangerous. Use RSA OAEP in new protocols.
+func EncryptPKCS1v15(random io.Reader, pub *PublicKey, msg []byte) ([]byte, error) {
+ randutil.MaybeReadByte(random)
+
+ if err := checkPub(pub); err != nil {
+ return nil, err
+ }
+ k := pub.Size()
+ if len(msg) > k-11 {
+ return nil, ErrMessageTooLong
+ }
+
+ if boring.Enabled && random == boring.RandReader {
+ bkey, err := boringPublicKey(pub)
+ if err != nil {
+ return nil, err
+ }
+ return boring.EncryptRSAPKCS1(bkey, msg)
+ }
+ boring.UnreachableExceptTests()
+
+ // EM = 0x00 || 0x02 || PS || 0x00 || M
+ em := make([]byte, k)
+ em[1] = 2
+ ps, mm := em[2:len(em)-len(msg)-1], em[len(em)-len(msg):]
+ err := nonZeroRandomBytes(ps, random)
+ if err != nil {
+ return nil, err
+ }
+ em[len(em)-len(msg)-1] = 0
+ copy(mm, msg)
+
+ if boring.Enabled {
+ var bkey *boring.PublicKeyRSA
+ bkey, err = boringPublicKey(pub)
+ if err != nil {
+ return nil, err
+ }
+ return boring.EncryptRSANoPadding(bkey, em)
+ }
+
+ return encrypt(pub, em)
+}
+
+// DecryptPKCS1v15 decrypts a plaintext using RSA and the padding scheme from PKCS #1 v1.5.
+// The random parameter is legacy and ignored, and it can be as nil.
+//
+// Note that whether this function returns an error or not discloses secret
+// information. If an attacker can cause this function to run repeatedly and
+// learn whether each instance returned an error then they can decrypt and
+// forge signatures as if they had the private key. See
+// DecryptPKCS1v15SessionKey for a way of solving this problem.
+func DecryptPKCS1v15(random io.Reader, priv *PrivateKey, ciphertext []byte) ([]byte, error) {
+ if err := checkPub(&priv.PublicKey); err != nil {
+ return nil, err
+ }
+
+ if boring.Enabled {
+ bkey, err := boringPrivateKey(priv)
+ if err != nil {
+ return nil, err
+ }
+ out, err := boring.DecryptRSAPKCS1(bkey, ciphertext)
+ if err != nil {
+ return nil, ErrDecryption
+ }
+ return out, nil
+ }
+
+ valid, out, index, err := decryptPKCS1v15(priv, ciphertext)
+ if err != nil {
+ return nil, err
+ }
+ if valid == 0 {
+ return nil, ErrDecryption
+ }
+ return out[index:], nil
+}
+
+// DecryptPKCS1v15SessionKey decrypts a session key using RSA and the padding scheme from PKCS #1 v1.5.
+// The random parameter is legacy and ignored, and it can be as nil.
+// It returns an error if the ciphertext is the wrong length or if the
+// ciphertext is greater than the public modulus. Otherwise, no error is
+// returned. If the padding is valid, the resulting plaintext message is copied
+// into key. Otherwise, key is unchanged. These alternatives occur in constant
+// time. It is intended that the user of this function generate a random
+// session key beforehand and continue the protocol with the resulting value.
+// This will remove any possibility that an attacker can learn any information
+// about the plaintext.
+// See “Chosen Ciphertext Attacks Against Protocols Based on the RSA
+// Encryption Standard PKCS #1”, Daniel Bleichenbacher, Advances in Cryptology
+// (Crypto '98).
+//
+// Note that if the session key is too small then it may be possible for an
+// attacker to brute-force it. If they can do that then they can learn whether
+// a random value was used (because it'll be different for the same ciphertext)
+// and thus whether the padding was correct. This defeats the point of this
+// function. Using at least a 16-byte key will protect against this attack.
+func DecryptPKCS1v15SessionKey(random io.Reader, priv *PrivateKey, ciphertext []byte, key []byte) error {
+ if err := checkPub(&priv.PublicKey); err != nil {
+ return err
+ }
+ k := priv.Size()
+ if k-(len(key)+3+8) < 0 {
+ return ErrDecryption
+ }
+
+ valid, em, index, err := decryptPKCS1v15(priv, ciphertext)
+ if err != nil {
+ return err
+ }
+
+ if len(em) != k {
+ // This should be impossible because decryptPKCS1v15 always
+ // returns the full slice.
+ return ErrDecryption
+ }
+
+ valid &= subtle.ConstantTimeEq(int32(len(em)-index), int32(len(key)))
+ subtle.ConstantTimeCopy(valid, key, em[len(em)-len(key):])
+ return nil
+}
+
+// decryptPKCS1v15 decrypts ciphertext using priv. It returns one or zero in
+// valid that indicates whether the plaintext was correctly structured.
+// In either case, the plaintext is returned in em so that it may be read
+// independently of whether it was valid in order to maintain constant memory
+// access patterns. If the plaintext was valid then index contains the index of
+// the original message in em, to allow constant time padding removal.
+func decryptPKCS1v15(priv *PrivateKey, ciphertext []byte) (valid int, em []byte, index int, err error) {
+ k := priv.Size()
+ if k < 11 {
+ err = ErrDecryption
+ return
+ }
+
+ if boring.Enabled {
+ var bkey *boring.PrivateKeyRSA
+ bkey, err = boringPrivateKey(priv)
+ if err != nil {
+ return
+ }
+ em, err = boring.DecryptRSANoPadding(bkey, ciphertext)
+ if err != nil {
+ return
+ }
+ } else {
+ em, err = decrypt(priv, ciphertext, noCheck)
+ if err != nil {
+ return
+ }
+ }
+
+ firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0)
+ secondByteIsTwo := subtle.ConstantTimeByteEq(em[1], 2)
+
+ // The remainder of the plaintext must be a string of non-zero random
+ // octets, followed by a 0, followed by the message.
+ // lookingForIndex: 1 iff we are still looking for the zero.
+ // index: the offset of the first zero byte.
+ lookingForIndex := 1
+
+ for i := 2; i < len(em); i++ {
+ equals0 := subtle.ConstantTimeByteEq(em[i], 0)
+ index = subtle.ConstantTimeSelect(lookingForIndex&equals0, i, index)
+ lookingForIndex = subtle.ConstantTimeSelect(equals0, 0, lookingForIndex)
+ }
+
+ // The PS padding must be at least 8 bytes long, and it starts two
+ // bytes into em.
+ validPS := subtle.ConstantTimeLessOrEq(2+8, index)
+
+ valid = firstByteIsZero & secondByteIsTwo & (^lookingForIndex & 1) & validPS
+ index = subtle.ConstantTimeSelect(valid, index+1, 0)
+ return valid, em, index, nil
+}
+
+// nonZeroRandomBytes fills the given slice with non-zero random octets.
+func nonZeroRandomBytes(s []byte, random io.Reader) (err error) {
+ _, err = io.ReadFull(random, s)
+ if err != nil {
+ return
+ }
+
+ for i := 0; i < len(s); i++ {
+ for s[i] == 0 {
+ _, err = io.ReadFull(random, s[i:i+1])
+ if err != nil {
+ return
+ }
+ // In tests, the PRNG may return all zeros so we do
+ // this to break the loop.
+ s[i] ^= 0x42
+ }
+ }
+
+ return
+}
+
+// These are ASN1 DER structures:
+//
+// DigestInfo ::= SEQUENCE {
+// digestAlgorithm AlgorithmIdentifier,
+// digest OCTET STRING
+// }
+//
+// For performance, we don't use the generic ASN1 encoder. Rather, we
+// precompute a prefix of the digest value that makes a valid ASN1 DER string
+// with the correct contents.
+var hashPrefixes = map[crypto.Hash][]byte{
+ crypto.MD5: {0x30, 0x20, 0x30, 0x0c, 0x06, 0x08, 0x2a, 0x86, 0x48, 0x86, 0xf7, 0x0d, 0x02, 0x05, 0x05, 0x00, 0x04, 0x10},
+ crypto.SHA1: {0x30, 0x21, 0x30, 0x09, 0x06, 0x05, 0x2b, 0x0e, 0x03, 0x02, 0x1a, 0x05, 0x00, 0x04, 0x14},
+ crypto.SHA224: {0x30, 0x2d, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x04, 0x05, 0x00, 0x04, 0x1c},
+ crypto.SHA256: {0x30, 0x31, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x01, 0x05, 0x00, 0x04, 0x20},
+ crypto.SHA384: {0x30, 0x41, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x02, 0x05, 0x00, 0x04, 0x30},
+ crypto.SHA512: {0x30, 0x51, 0x30, 0x0d, 0x06, 0x09, 0x60, 0x86, 0x48, 0x01, 0x65, 0x03, 0x04, 0x02, 0x03, 0x05, 0x00, 0x04, 0x40},
+ crypto.MD5SHA1: {}, // A special TLS case which doesn't use an ASN1 prefix.
+ crypto.RIPEMD160: {0x30, 0x20, 0x30, 0x08, 0x06, 0x06, 0x28, 0xcf, 0x06, 0x03, 0x00, 0x31, 0x04, 0x14},
+}
+
+// SignPKCS1v15 calculates the signature of hashed using
+// RSASSA-PKCS1-V1_5-SIGN from RSA PKCS #1 v1.5. Note that hashed must
+// be the result of hashing the input message using the given hash
+// function. If hash is zero, hashed is signed directly. This isn't
+// advisable except for interoperability.
+//
+// The random parameter is legacy and ignored, and it can be as nil.
+//
+// This function is deterministic. Thus, if the set of possible
+// messages is small, an attacker may be able to build a map from
+// messages to signatures and identify the signed messages. As ever,
+// signatures provide authenticity, not confidentiality.
+func SignPKCS1v15(random io.Reader, priv *PrivateKey, hash crypto.Hash, hashed []byte) ([]byte, error) {
+ hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
+ if err != nil {
+ return nil, err
+ }
+
+ tLen := len(prefix) + hashLen
+ k := priv.Size()
+ if k < tLen+11 {
+ return nil, ErrMessageTooLong
+ }
+
+ if boring.Enabled {
+ bkey, err := boringPrivateKey(priv)
+ if err != nil {
+ return nil, err
+ }
+ return boring.SignRSAPKCS1v15(bkey, hash, hashed)
+ }
+
+ // EM = 0x00 || 0x01 || PS || 0x00 || T
+ em := make([]byte, k)
+ em[1] = 1
+ for i := 2; i < k-tLen-1; i++ {
+ em[i] = 0xff
+ }
+ copy(em[k-tLen:k-hashLen], prefix)
+ copy(em[k-hashLen:k], hashed)
+
+ return decrypt(priv, em, withCheck)
+}
+
+// VerifyPKCS1v15 verifies an RSA PKCS #1 v1.5 signature.
+// hashed is the result of hashing the input message using the given hash
+// function and sig is the signature. A valid signature is indicated by
+// returning a nil error. If hash is zero then hashed is used directly. This
+// isn't advisable except for interoperability.
+func VerifyPKCS1v15(pub *PublicKey, hash crypto.Hash, hashed []byte, sig []byte) error {
+ if boring.Enabled {
+ bkey, err := boringPublicKey(pub)
+ if err != nil {
+ return err
+ }
+ if err := boring.VerifyRSAPKCS1v15(bkey, hash, hashed, sig); err != nil {
+ return ErrVerification
+ }
+ return nil
+ }
+
+ hashLen, prefix, err := pkcs1v15HashInfo(hash, len(hashed))
+ if err != nil {
+ return err
+ }
+
+ tLen := len(prefix) + hashLen
+ k := pub.Size()
+ if k < tLen+11 {
+ return ErrVerification
+ }
+
+ // RFC 8017 Section 8.2.2: If the length of the signature S is not k
+ // octets (where k is the length in octets of the RSA modulus n), output
+ // "invalid signature" and stop.
+ if k != len(sig) {
+ return ErrVerification
+ }
+
+ em, err := encrypt(pub, sig)
+ if err != nil {
+ return ErrVerification
+ }
+ // EM = 0x00 || 0x01 || PS || 0x00 || T
+
+ ok := subtle.ConstantTimeByteEq(em[0], 0)
+ ok &= subtle.ConstantTimeByteEq(em[1], 1)
+ ok &= subtle.ConstantTimeCompare(em[k-hashLen:k], hashed)
+ ok &= subtle.ConstantTimeCompare(em[k-tLen:k-hashLen], prefix)
+ ok &= subtle.ConstantTimeByteEq(em[k-tLen-1], 0)
+
+ for i := 2; i < k-tLen-1; i++ {
+ ok &= subtle.ConstantTimeByteEq(em[i], 0xff)
+ }
+
+ if ok != 1 {
+ return ErrVerification
+ }
+
+ return nil
+}
+
+func pkcs1v15HashInfo(hash crypto.Hash, inLen int) (hashLen int, prefix []byte, err error) {
+ // Special case: crypto.Hash(0) is used to indicate that the data is
+ // signed directly.
+ if hash == 0 {
+ return inLen, nil, nil
+ }
+
+ hashLen = hash.Size()
+ if inLen != hashLen {
+ return 0, nil, errors.New("crypto/rsa: input must be hashed message")
+ }
+ prefix, ok := hashPrefixes[hash]
+ if !ok {
+ return 0, nil, errors.New("crypto/rsa: unsupported hash function")
+ }
+ return
+}
diff --git a/src/crypto/rsa/pkcs1v15_test.go b/src/crypto/rsa/pkcs1v15_test.go
new file mode 100644
index 0000000..dfa1edd
--- /dev/null
+++ b/src/crypto/rsa/pkcs1v15_test.go
@@ -0,0 +1,315 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rsa_test
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/rand"
+ . "crypto/rsa"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/x509"
+ "encoding/base64"
+ "encoding/hex"
+ "encoding/pem"
+ "io"
+ "testing"
+ "testing/quick"
+)
+
+func decodeBase64(in string) []byte {
+ out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
+ n, err := base64.StdEncoding.Decode(out, []byte(in))
+ if err != nil {
+ return nil
+ }
+ return out[0:n]
+}
+
+type DecryptPKCS1v15Test struct {
+ in, out string
+}
+
+// These test vectors were generated with `openssl rsautl -pkcs -encrypt`
+var decryptPKCS1v15Tests = []DecryptPKCS1v15Test{
+ {
+ "gIcUIoVkD6ATMBk/u/nlCZCCWRKdkfjCgFdo35VpRXLduiKXhNz1XupLLzTXAybEq15juc+EgY5o0DHv/nt3yg==",
+ "x",
+ },
+ {
+ "Y7TOCSqofGhkRb+jaVRLzK8xw2cSo1IVES19utzv6hwvx+M8kFsoWQm5DzBeJCZTCVDPkTpavUuEbgp8hnUGDw==",
+ "testing.",
+ },
+ {
+ "arReP9DJtEVyV2Dg3dDp4c/PSk1O6lxkoJ8HcFupoRorBZG+7+1fDAwT1olNddFnQMjmkb8vxwmNMoTAT/BFjQ==",
+ "testing.\n",
+ },
+ {
+ "WtaBXIoGC54+vH0NH0CHHE+dRDOsMc/6BrfFu2lEqcKL9+uDuWaf+Xj9mrbQCjjZcpQuX733zyok/jsnqe/Ftw==",
+ "01234567890123456789012345678901234567890123456789012",
+ },
+}
+
+func TestDecryptPKCS1v15(t *testing.T) {
+ decryptionFuncs := []func([]byte) ([]byte, error){
+ func(ciphertext []byte) (plaintext []byte, err error) {
+ return DecryptPKCS1v15(nil, rsaPrivateKey, ciphertext)
+ },
+ func(ciphertext []byte) (plaintext []byte, err error) {
+ return rsaPrivateKey.Decrypt(nil, ciphertext, nil)
+ },
+ }
+
+ for _, decryptFunc := range decryptionFuncs {
+ for i, test := range decryptPKCS1v15Tests {
+ out, err := decryptFunc(decodeBase64(test.in))
+ if err != nil {
+ t.Errorf("#%d error decrypting: %v", i, err)
+ }
+ want := []byte(test.out)
+ if !bytes.Equal(out, want) {
+ t.Errorf("#%d got:%#v want:%#v", i, out, want)
+ }
+ }
+ }
+}
+
+func TestEncryptPKCS1v15(t *testing.T) {
+ random := rand.Reader
+ k := (rsaPrivateKey.N.BitLen() + 7) / 8
+
+ tryEncryptDecrypt := func(in []byte, blind bool) bool {
+ if len(in) > k-11 {
+ in = in[0 : k-11]
+ }
+
+ ciphertext, err := EncryptPKCS1v15(random, &rsaPrivateKey.PublicKey, in)
+ if err != nil {
+ t.Errorf("error encrypting: %s", err)
+ return false
+ }
+
+ var rand io.Reader
+ if !blind {
+ rand = nil
+ } else {
+ rand = random
+ }
+ plaintext, err := DecryptPKCS1v15(rand, rsaPrivateKey, ciphertext)
+ if err != nil {
+ t.Errorf("error decrypting: %s", err)
+ return false
+ }
+
+ if !bytes.Equal(plaintext, in) {
+ t.Errorf("output mismatch: %#v %#v", plaintext, in)
+ return false
+ }
+ return true
+ }
+
+ config := new(quick.Config)
+ if testing.Short() {
+ config.MaxCount = 10
+ }
+ quick.Check(tryEncryptDecrypt, config)
+}
+
+// These test vectors were generated with `openssl rsautl -pkcs -encrypt`
+var decryptPKCS1v15SessionKeyTests = []DecryptPKCS1v15Test{
+ {
+ "e6ukkae6Gykq0fKzYwULpZehX+UPXYzMoB5mHQUDEiclRbOTqas4Y0E6nwns1BBpdvEJcilhl5zsox/6DtGsYg==",
+ "1234",
+ },
+ {
+ "Dtis4uk/q/LQGGqGk97P59K03hkCIVFMEFZRgVWOAAhxgYpCRG0MX2adptt92l67IqMki6iVQyyt0TtX3IdtEw==",
+ "FAIL",
+ },
+ {
+ "LIyFyCYCptPxrvTxpol8F3M7ZivlMsf53zs0vHRAv+rDIh2YsHS69ePMoPMe3TkOMZ3NupiL3takPxIs1sK+dw==",
+ "abcd",
+ },
+ {
+ "bafnobel46bKy76JzqU/RIVOH0uAYvzUtauKmIidKgM0sMlvobYVAVQPeUQ/oTGjbIZ1v/6Gyi5AO4DtHruGdw==",
+ "FAIL",
+ },
+}
+
+func TestEncryptPKCS1v15SessionKey(t *testing.T) {
+ for i, test := range decryptPKCS1v15SessionKeyTests {
+ key := []byte("FAIL")
+ err := DecryptPKCS1v15SessionKey(nil, rsaPrivateKey, decodeBase64(test.in), key)
+ if err != nil {
+ t.Errorf("#%d error decrypting", i)
+ }
+ want := []byte(test.out)
+ if !bytes.Equal(key, want) {
+ t.Errorf("#%d got:%#v want:%#v", i, key, want)
+ }
+ }
+}
+
+func TestEncryptPKCS1v15DecrypterSessionKey(t *testing.T) {
+ for i, test := range decryptPKCS1v15SessionKeyTests {
+ plaintext, err := rsaPrivateKey.Decrypt(rand.Reader, decodeBase64(test.in), &PKCS1v15DecryptOptions{SessionKeyLen: 4})
+ if err != nil {
+ t.Fatalf("#%d: error decrypting: %s", i, err)
+ }
+ if len(plaintext) != 4 {
+ t.Fatalf("#%d: incorrect length plaintext: got %d, want 4", i, len(plaintext))
+ }
+
+ if test.out != "FAIL" && !bytes.Equal(plaintext, []byte(test.out)) {
+ t.Errorf("#%d: incorrect plaintext: got %x, want %x", i, plaintext, test.out)
+ }
+ }
+}
+
+func TestNonZeroRandomBytes(t *testing.T) {
+ random := rand.Reader
+
+ b := make([]byte, 512)
+ err := NonZeroRandomBytes(b, random)
+ if err != nil {
+ t.Errorf("returned error: %s", err)
+ }
+ for _, b := range b {
+ if b == 0 {
+ t.Errorf("Zero octet found")
+ return
+ }
+ }
+}
+
+type signPKCS1v15Test struct {
+ in, out string
+}
+
+// These vectors have been tested with
+//
+// `openssl rsautl -verify -inkey pk -in signature | hexdump -C`
+var signPKCS1v15Tests = []signPKCS1v15Test{
+ {"Test.\n", "a4f3fa6ea93bcdd0c57be020c1193ecbfd6f200a3d95c409769b029578fa0e336ad9a347600e40d3ae823b8c7e6bad88cc07c1d54c3a1523cbbb6d58efc362ae"},
+}
+
+func TestSignPKCS1v15(t *testing.T) {
+ for i, test := range signPKCS1v15Tests {
+ h := sha1.New()
+ h.Write([]byte(test.in))
+ digest := h.Sum(nil)
+
+ s, err := SignPKCS1v15(nil, rsaPrivateKey, crypto.SHA1, digest)
+ if err != nil {
+ t.Errorf("#%d %s", i, err)
+ }
+
+ expected, _ := hex.DecodeString(test.out)
+ if !bytes.Equal(s, expected) {
+ t.Errorf("#%d got: %x want: %x", i, s, expected)
+ }
+ }
+}
+
+func TestVerifyPKCS1v15(t *testing.T) {
+ for i, test := range signPKCS1v15Tests {
+ h := sha1.New()
+ h.Write([]byte(test.in))
+ digest := h.Sum(nil)
+
+ sig, _ := hex.DecodeString(test.out)
+
+ err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.SHA1, digest, sig)
+ if err != nil {
+ t.Errorf("#%d %s", i, err)
+ }
+ }
+}
+
+func TestOverlongMessagePKCS1v15(t *testing.T) {
+ ciphertext := decodeBase64("fjOVdirUzFoLlukv80dBllMLjXythIf22feqPrNo0YoIjzyzyoMFiLjAc/Y4krkeZ11XFThIrEvw\nkRiZcCq5ng==")
+ _, err := DecryptPKCS1v15(nil, rsaPrivateKey, ciphertext)
+ if err == nil {
+ t.Error("RSA decrypted a message that was too long.")
+ }
+}
+
+func TestUnpaddedSignature(t *testing.T) {
+ msg := []byte("Thu Dec 19 18:06:16 EST 2013\n")
+ // This base64 value was generated with:
+ // % echo Thu Dec 19 18:06:16 EST 2013 > /tmp/msg
+ // % openssl rsautl -sign -inkey key -out /tmp/sig -in /tmp/msg
+ //
+ // Where "key" contains the RSA private key given at the bottom of this
+ // file.
+ expectedSig := decodeBase64("pX4DR8azytjdQ1rtUiC040FjkepuQut5q2ZFX1pTjBrOVKNjgsCDyiJDGZTCNoh9qpXYbhl7iEym30BWWwuiZg==")
+
+ sig, err := SignPKCS1v15(nil, rsaPrivateKey, crypto.Hash(0), msg)
+ if err != nil {
+ t.Fatalf("SignPKCS1v15 failed: %s", err)
+ }
+ if !bytes.Equal(sig, expectedSig) {
+ t.Fatalf("signature is not expected value: got %x, want %x", sig, expectedSig)
+ }
+ if err := VerifyPKCS1v15(&rsaPrivateKey.PublicKey, crypto.Hash(0), msg, sig); err != nil {
+ t.Fatalf("signature failed to verify: %s", err)
+ }
+}
+
+func TestShortSessionKey(t *testing.T) {
+ // This tests that attempting to decrypt a session key where the
+ // ciphertext is too small doesn't run outside the array bounds.
+ ciphertext, err := EncryptPKCS1v15(rand.Reader, &rsaPrivateKey.PublicKey, []byte{1})
+ if err != nil {
+ t.Fatalf("Failed to encrypt short message: %s", err)
+ }
+
+ var key [32]byte
+ if err := DecryptPKCS1v15SessionKey(nil, rsaPrivateKey, ciphertext, key[:]); err != nil {
+ t.Fatalf("Failed to decrypt short message: %s", err)
+ }
+
+ for _, v := range key {
+ if v != 0 {
+ t.Fatal("key was modified when ciphertext was invalid")
+ }
+ }
+}
+
+var rsaPrivateKey = parseKey(testingKey(`-----BEGIN RSA TESTING KEY-----
+MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
+fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
+/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
+RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
+EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
+IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
+tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
+-----END RSA TESTING KEY-----`))
+
+func parsePublicKey(s string) *PublicKey {
+ p, _ := pem.Decode([]byte(s))
+ k, err := x509.ParsePKCS1PublicKey(p.Bytes)
+ if err != nil {
+ panic(err)
+ }
+ return k
+}
+
+func TestShortPKCS1v15Signature(t *testing.T) {
+ pub := parsePublicKey(`-----BEGIN RSA PUBLIC KEY-----
+MEgCQQCd9BVzo775lkohasxjnefF1nCMcNoibqIWEVDe/K7M2GSoO4zlSQB+gkix
+O3AnTcdHB51iaZpWfxPSnew8yfulAgMBAAE=
+-----END RSA PUBLIC KEY-----`)
+ sig, err := hex.DecodeString("193a310d0dcf64094c6e3a00c8219b80ded70535473acff72c08e1222974bb24a93a535b1dc4c59fc0e65775df7ba2007dd20e9193f4c4025a18a7070aee93")
+ if err != nil {
+ t.Fatalf("failed to decode signature: %s", err)
+ }
+
+ h := sha256.Sum256([]byte("hello"))
+ err = VerifyPKCS1v15(pub, crypto.SHA256, h[:], sig)
+ if err == nil {
+ t.Fatal("VerifyPKCS1v15 accepted a truncated signature")
+ }
+}
diff --git a/src/crypto/rsa/pss.go b/src/crypto/rsa/pss.go
new file mode 100644
index 0000000..f7d23b5
--- /dev/null
+++ b/src/crypto/rsa/pss.go
@@ -0,0 +1,372 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rsa
+
+// This file implements the RSASSA-PSS signature scheme according to RFC 8017.
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/internal/boring"
+ "errors"
+ "hash"
+ "io"
+)
+
+// Per RFC 8017, Section 9.1
+//
+// EM = MGF1 xor DB || H( 8*0x00 || mHash || salt ) || 0xbc
+//
+// where
+//
+// DB = PS || 0x01 || salt
+//
+// and PS can be empty so
+//
+// emLen = dbLen + hLen + 1 = psLen + sLen + hLen + 2
+//
+
+func emsaPSSEncode(mHash []byte, emBits int, salt []byte, hash hash.Hash) ([]byte, error) {
+ // See RFC 8017, Section 9.1.1.
+
+ hLen := hash.Size()
+ sLen := len(salt)
+ emLen := (emBits + 7) / 8
+
+ // 1. If the length of M is greater than the input limitation for the
+ // hash function (2^61 - 1 octets for SHA-1), output "message too
+ // long" and stop.
+ //
+ // 2. Let mHash = Hash(M), an octet string of length hLen.
+
+ if len(mHash) != hLen {
+ return nil, errors.New("crypto/rsa: input must be hashed with given hash")
+ }
+
+ // 3. If emLen < hLen + sLen + 2, output "encoding error" and stop.
+
+ if emLen < hLen+sLen+2 {
+ return nil, ErrMessageTooLong
+ }
+
+ em := make([]byte, emLen)
+ psLen := emLen - sLen - hLen - 2
+ db := em[:psLen+1+sLen]
+ h := em[psLen+1+sLen : emLen-1]
+
+ // 4. Generate a random octet string salt of length sLen; if sLen = 0,
+ // then salt is the empty string.
+ //
+ // 5. Let
+ // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt;
+ //
+ // M' is an octet string of length 8 + hLen + sLen with eight
+ // initial zero octets.
+ //
+ // 6. Let H = Hash(M'), an octet string of length hLen.
+
+ var prefix [8]byte
+
+ hash.Write(prefix[:])
+ hash.Write(mHash)
+ hash.Write(salt)
+
+ h = hash.Sum(h[:0])
+ hash.Reset()
+
+ // 7. Generate an octet string PS consisting of emLen - sLen - hLen - 2
+ // zero octets. The length of PS may be 0.
+ //
+ // 8. Let DB = PS || 0x01 || salt; DB is an octet string of length
+ // emLen - hLen - 1.
+
+ db[psLen] = 0x01
+ copy(db[psLen+1:], salt)
+
+ // 9. Let dbMask = MGF(H, emLen - hLen - 1).
+ //
+ // 10. Let maskedDB = DB \xor dbMask.
+
+ mgf1XOR(db, hash, h)
+
+ // 11. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in
+ // maskedDB to zero.
+
+ db[0] &= 0xff >> (8*emLen - emBits)
+
+ // 12. Let EM = maskedDB || H || 0xbc.
+ em[emLen-1] = 0xbc
+
+ // 13. Output EM.
+ return em, nil
+}
+
+func emsaPSSVerify(mHash, em []byte, emBits, sLen int, hash hash.Hash) error {
+ // See RFC 8017, Section 9.1.2.
+
+ hLen := hash.Size()
+ if sLen == PSSSaltLengthEqualsHash {
+ sLen = hLen
+ }
+ emLen := (emBits + 7) / 8
+ if emLen != len(em) {
+ return errors.New("rsa: internal error: inconsistent length")
+ }
+
+ // 1. If the length of M is greater than the input limitation for the
+ // hash function (2^61 - 1 octets for SHA-1), output "inconsistent"
+ // and stop.
+ //
+ // 2. Let mHash = Hash(M), an octet string of length hLen.
+ if hLen != len(mHash) {
+ return ErrVerification
+ }
+
+ // 3. If emLen < hLen + sLen + 2, output "inconsistent" and stop.
+ if emLen < hLen+sLen+2 {
+ return ErrVerification
+ }
+
+ // 4. If the rightmost octet of EM does not have hexadecimal value
+ // 0xbc, output "inconsistent" and stop.
+ if em[emLen-1] != 0xbc {
+ return ErrVerification
+ }
+
+ // 5. Let maskedDB be the leftmost emLen - hLen - 1 octets of EM, and
+ // let H be the next hLen octets.
+ db := em[:emLen-hLen-1]
+ h := em[emLen-hLen-1 : emLen-1]
+
+ // 6. If the leftmost 8 * emLen - emBits bits of the leftmost octet in
+ // maskedDB are not all equal to zero, output "inconsistent" and
+ // stop.
+ var bitMask byte = 0xff >> (8*emLen - emBits)
+ if em[0] & ^bitMask != 0 {
+ return ErrVerification
+ }
+
+ // 7. Let dbMask = MGF(H, emLen - hLen - 1).
+ //
+ // 8. Let DB = maskedDB \xor dbMask.
+ mgf1XOR(db, hash, h)
+
+ // 9. Set the leftmost 8 * emLen - emBits bits of the leftmost octet in DB
+ // to zero.
+ db[0] &= bitMask
+
+ // If we don't know the salt length, look for the 0x01 delimiter.
+ if sLen == PSSSaltLengthAuto {
+ psLen := bytes.IndexByte(db, 0x01)
+ if psLen < 0 {
+ return ErrVerification
+ }
+ sLen = len(db) - psLen - 1
+ }
+
+ // 10. If the emLen - hLen - sLen - 2 leftmost octets of DB are not zero
+ // or if the octet at position emLen - hLen - sLen - 1 (the leftmost
+ // position is "position 1") does not have hexadecimal value 0x01,
+ // output "inconsistent" and stop.
+ psLen := emLen - hLen - sLen - 2
+ for _, e := range db[:psLen] {
+ if e != 0x00 {
+ return ErrVerification
+ }
+ }
+ if db[psLen] != 0x01 {
+ return ErrVerification
+ }
+
+ // 11. Let salt be the last sLen octets of DB.
+ salt := db[len(db)-sLen:]
+
+ // 12. Let
+ // M' = (0x)00 00 00 00 00 00 00 00 || mHash || salt ;
+ // M' is an octet string of length 8 + hLen + sLen with eight
+ // initial zero octets.
+ //
+ // 13. Let H' = Hash(M'), an octet string of length hLen.
+ var prefix [8]byte
+ hash.Write(prefix[:])
+ hash.Write(mHash)
+ hash.Write(salt)
+
+ h0 := hash.Sum(nil)
+
+ // 14. If H = H', output "consistent." Otherwise, output "inconsistent."
+ if !bytes.Equal(h0, h) { // TODO: constant time?
+ return ErrVerification
+ }
+ return nil
+}
+
+// signPSSWithSalt calculates the signature of hashed using PSS with specified salt.
+// Note that hashed must be the result of hashing the input message using the
+// given hash function. salt is a random sequence of bytes whose length will be
+// later used to verify the signature.
+func signPSSWithSalt(priv *PrivateKey, hash crypto.Hash, hashed, salt []byte) ([]byte, error) {
+ emBits := priv.N.BitLen() - 1
+ em, err := emsaPSSEncode(hashed, emBits, salt, hash.New())
+ if err != nil {
+ return nil, err
+ }
+
+ if boring.Enabled {
+ bkey, err := boringPrivateKey(priv)
+ if err != nil {
+ return nil, err
+ }
+ // Note: BoringCrypto always does decrypt "withCheck".
+ // (It's not just decrypt.)
+ s, err := boring.DecryptRSANoPadding(bkey, em)
+ if err != nil {
+ return nil, err
+ }
+ return s, nil
+ }
+
+ // RFC 8017: "Note that the octet length of EM will be one less than k if
+ // modBits - 1 is divisible by 8 and equal to k otherwise, where k is the
+ // length in octets of the RSA modulus n." 🙄
+ //
+ // This is extremely annoying, as all other encrypt and decrypt inputs are
+ // always the exact same size as the modulus. Since it only happens for
+ // weird modulus sizes, fix it by padding inefficiently.
+ if emLen, k := len(em), priv.Size(); emLen < k {
+ emNew := make([]byte, k)
+ copy(emNew[k-emLen:], em)
+ em = emNew
+ }
+
+ return decrypt(priv, em, withCheck)
+}
+
+const (
+ // PSSSaltLengthAuto causes the salt in a PSS signature to be as large
+ // as possible when signing, and to be auto-detected when verifying.
+ PSSSaltLengthAuto = 0
+ // PSSSaltLengthEqualsHash causes the salt length to equal the length
+ // of the hash used in the signature.
+ PSSSaltLengthEqualsHash = -1
+)
+
+// PSSOptions contains options for creating and verifying PSS signatures.
+type PSSOptions struct {
+ // SaltLength controls the length of the salt used in the PSS signature. It
+ // can either be a positive number of bytes, or one of the special
+ // PSSSaltLength constants.
+ SaltLength int
+
+ // Hash is the hash function used to generate the message digest. If not
+ // zero, it overrides the hash function passed to SignPSS. It's required
+ // when using PrivateKey.Sign.
+ Hash crypto.Hash
+}
+
+// HashFunc returns opts.Hash so that PSSOptions implements crypto.SignerOpts.
+func (opts *PSSOptions) HashFunc() crypto.Hash {
+ return opts.Hash
+}
+
+func (opts *PSSOptions) saltLength() int {
+ if opts == nil {
+ return PSSSaltLengthAuto
+ }
+ return opts.SaltLength
+}
+
+var invalidSaltLenErr = errors.New("crypto/rsa: PSSOptions.SaltLength cannot be negative")
+
+// SignPSS calculates the signature of digest using PSS.
+//
+// digest must be the result of hashing the input message using the given hash
+// function. The opts argument may be nil, in which case sensible defaults are
+// used. If opts.Hash is set, it overrides hash.
+func SignPSS(rand io.Reader, priv *PrivateKey, hash crypto.Hash, digest []byte, opts *PSSOptions) ([]byte, error) {
+ if boring.Enabled && rand == boring.RandReader {
+ bkey, err := boringPrivateKey(priv)
+ if err != nil {
+ return nil, err
+ }
+ return boring.SignRSAPSS(bkey, hash, digest, opts.saltLength())
+ }
+ boring.UnreachableExceptTests()
+
+ if opts != nil && opts.Hash != 0 {
+ hash = opts.Hash
+ }
+
+ saltLength := opts.saltLength()
+ switch saltLength {
+ case PSSSaltLengthAuto:
+ saltLength = (priv.N.BitLen()-1+7)/8 - 2 - hash.Size()
+ if saltLength < 0 {
+ return nil, ErrMessageTooLong
+ }
+ case PSSSaltLengthEqualsHash:
+ saltLength = hash.Size()
+ default:
+ // If we get here saltLength is either > 0 or < -1, in the
+ // latter case we fail out.
+ if saltLength <= 0 {
+ return nil, invalidSaltLenErr
+ }
+ }
+ salt := make([]byte, saltLength)
+ if _, err := io.ReadFull(rand, salt); err != nil {
+ return nil, err
+ }
+ return signPSSWithSalt(priv, hash, digest, salt)
+}
+
+// VerifyPSS verifies a PSS signature.
+//
+// A valid signature is indicated by returning a nil error. digest must be the
+// result of hashing the input message using the given hash function. The opts
+// argument may be nil, in which case sensible defaults are used. opts.Hash is
+// ignored.
+func VerifyPSS(pub *PublicKey, hash crypto.Hash, digest []byte, sig []byte, opts *PSSOptions) error {
+ if boring.Enabled {
+ bkey, err := boringPublicKey(pub)
+ if err != nil {
+ return err
+ }
+ if err := boring.VerifyRSAPSS(bkey, hash, digest, sig, opts.saltLength()); err != nil {
+ return ErrVerification
+ }
+ return nil
+ }
+ if len(sig) != pub.Size() {
+ return ErrVerification
+ }
+ // Salt length must be either one of the special constants (-1 or 0)
+ // or otherwise positive. If it is < PSSSaltLengthEqualsHash (-1)
+ // we return an error.
+ if opts.saltLength() < PSSSaltLengthEqualsHash {
+ return invalidSaltLenErr
+ }
+
+ emBits := pub.N.BitLen() - 1
+ emLen := (emBits + 7) / 8
+ em, err := encrypt(pub, sig)
+ if err != nil {
+ return ErrVerification
+ }
+
+ // Like in signPSSWithSalt, deal with mismatches between emLen and the size
+ // of the modulus. The spec would have us wire emLen into the encoding
+ // function, but we'd rather always encode to the size of the modulus and
+ // then strip leading zeroes if necessary. This only happens for weird
+ // modulus sizes anyway.
+ for len(em) > emLen && len(em) > 0 {
+ if em[0] != 0 {
+ return ErrVerification
+ }
+ em = em[1:]
+ }
+
+ return emsaPSSVerify(digest, em, emBits, opts.saltLength(), hash.New())
+}
diff --git a/src/crypto/rsa/pss_test.go b/src/crypto/rsa/pss_test.go
new file mode 100644
index 0000000..cf03e3c
--- /dev/null
+++ b/src/crypto/rsa/pss_test.go
@@ -0,0 +1,308 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rsa_test
+
+import (
+ "bufio"
+ "bytes"
+ "compress/bzip2"
+ "crypto"
+ "crypto/rand"
+ . "crypto/rsa"
+ "crypto/sha1"
+ "crypto/sha256"
+ "encoding/hex"
+ "math/big"
+ "os"
+ "strconv"
+ "strings"
+ "testing"
+)
+
+func TestEMSAPSS(t *testing.T) {
+ // Test vector in file pss-int.txt from: ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip
+ msg := []byte{
+ 0x85, 0x9e, 0xef, 0x2f, 0xd7, 0x8a, 0xca, 0x00, 0x30, 0x8b,
+ 0xdc, 0x47, 0x11, 0x93, 0xbf, 0x55, 0xbf, 0x9d, 0x78, 0xdb,
+ 0x8f, 0x8a, 0x67, 0x2b, 0x48, 0x46, 0x34, 0xf3, 0xc9, 0xc2,
+ 0x6e, 0x64, 0x78, 0xae, 0x10, 0x26, 0x0f, 0xe0, 0xdd, 0x8c,
+ 0x08, 0x2e, 0x53, 0xa5, 0x29, 0x3a, 0xf2, 0x17, 0x3c, 0xd5,
+ 0x0c, 0x6d, 0x5d, 0x35, 0x4f, 0xeb, 0xf7, 0x8b, 0x26, 0x02,
+ 0x1c, 0x25, 0xc0, 0x27, 0x12, 0xe7, 0x8c, 0xd4, 0x69, 0x4c,
+ 0x9f, 0x46, 0x97, 0x77, 0xe4, 0x51, 0xe7, 0xf8, 0xe9, 0xe0,
+ 0x4c, 0xd3, 0x73, 0x9c, 0x6b, 0xbf, 0xed, 0xae, 0x48, 0x7f,
+ 0xb5, 0x56, 0x44, 0xe9, 0xca, 0x74, 0xff, 0x77, 0xa5, 0x3c,
+ 0xb7, 0x29, 0x80, 0x2f, 0x6e, 0xd4, 0xa5, 0xff, 0xa8, 0xba,
+ 0x15, 0x98, 0x90, 0xfc,
+ }
+ salt := []byte{
+ 0xe3, 0xb5, 0xd5, 0xd0, 0x02, 0xc1, 0xbc, 0xe5, 0x0c, 0x2b,
+ 0x65, 0xef, 0x88, 0xa1, 0x88, 0xd8, 0x3b, 0xce, 0x7e, 0x61,
+ }
+ expected := []byte{
+ 0x66, 0xe4, 0x67, 0x2e, 0x83, 0x6a, 0xd1, 0x21, 0xba, 0x24,
+ 0x4b, 0xed, 0x65, 0x76, 0xb8, 0x67, 0xd9, 0xa4, 0x47, 0xc2,
+ 0x8a, 0x6e, 0x66, 0xa5, 0xb8, 0x7d, 0xee, 0x7f, 0xbc, 0x7e,
+ 0x65, 0xaf, 0x50, 0x57, 0xf8, 0x6f, 0xae, 0x89, 0x84, 0xd9,
+ 0xba, 0x7f, 0x96, 0x9a, 0xd6, 0xfe, 0x02, 0xa4, 0xd7, 0x5f,
+ 0x74, 0x45, 0xfe, 0xfd, 0xd8, 0x5b, 0x6d, 0x3a, 0x47, 0x7c,
+ 0x28, 0xd2, 0x4b, 0xa1, 0xe3, 0x75, 0x6f, 0x79, 0x2d, 0xd1,
+ 0xdc, 0xe8, 0xca, 0x94, 0x44, 0x0e, 0xcb, 0x52, 0x79, 0xec,
+ 0xd3, 0x18, 0x3a, 0x31, 0x1f, 0xc8, 0x96, 0xda, 0x1c, 0xb3,
+ 0x93, 0x11, 0xaf, 0x37, 0xea, 0x4a, 0x75, 0xe2, 0x4b, 0xdb,
+ 0xfd, 0x5c, 0x1d, 0xa0, 0xde, 0x7c, 0xec, 0xdf, 0x1a, 0x89,
+ 0x6f, 0x9d, 0x8b, 0xc8, 0x16, 0xd9, 0x7c, 0xd7, 0xa2, 0xc4,
+ 0x3b, 0xad, 0x54, 0x6f, 0xbe, 0x8c, 0xfe, 0xbc,
+ }
+
+ hash := sha1.New()
+ hash.Write(msg)
+ hashed := hash.Sum(nil)
+
+ encoded, err := EMSAPSSEncode(hashed, 1023, salt, sha1.New())
+ if err != nil {
+ t.Errorf("Error from emsaPSSEncode: %s\n", err)
+ }
+ if !bytes.Equal(encoded, expected) {
+ t.Errorf("Bad encoding. got %x, want %x", encoded, expected)
+ }
+
+ if err = EMSAPSSVerify(hashed, encoded, 1023, len(salt), sha1.New()); err != nil {
+ t.Errorf("Bad verification: %s", err)
+ }
+}
+
+// TestPSSGolden tests all the test vectors in pss-vect.txt from
+// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-1/pkcs-1v2-1-vec.zip
+func TestPSSGolden(t *testing.T) {
+ inFile, err := os.Open("testdata/pss-vect.txt.bz2")
+ if err != nil {
+ t.Fatalf("Failed to open input file: %s", err)
+ }
+ defer inFile.Close()
+
+ // The pss-vect.txt file contains RSA keys and then a series of
+ // signatures. A goroutine is used to preprocess the input by merging
+ // lines, removing spaces in hex values and identifying the start of
+ // new keys and signature blocks.
+ const newKeyMarker = "START NEW KEY"
+ const newSignatureMarker = "START NEW SIGNATURE"
+
+ values := make(chan string)
+
+ go func() {
+ defer close(values)
+ scanner := bufio.NewScanner(bzip2.NewReader(inFile))
+ var partialValue string
+ lastWasValue := true
+
+ for scanner.Scan() {
+ line := scanner.Text()
+ switch {
+ case len(line) == 0:
+ if len(partialValue) > 0 {
+ values <- strings.ReplaceAll(partialValue, " ", "")
+ partialValue = ""
+ lastWasValue = true
+ }
+ continue
+ case strings.HasPrefix(line, "# ======") && lastWasValue:
+ values <- newKeyMarker
+ lastWasValue = false
+ case strings.HasPrefix(line, "# ------") && lastWasValue:
+ values <- newSignatureMarker
+ lastWasValue = false
+ case strings.HasPrefix(line, "#"):
+ continue
+ default:
+ partialValue += line
+ }
+ }
+ if err := scanner.Err(); err != nil {
+ panic(err)
+ }
+ }()
+
+ var key *PublicKey
+ var hashed []byte
+ hash := crypto.SHA1
+ h := hash.New()
+ opts := &PSSOptions{
+ SaltLength: PSSSaltLengthEqualsHash,
+ }
+
+ for marker := range values {
+ switch marker {
+ case newKeyMarker:
+ key = new(PublicKey)
+ nHex, ok := <-values
+ if !ok {
+ continue
+ }
+ key.N = bigFromHex(nHex)
+ key.E = intFromHex(<-values)
+ // We don't care for d, p, q, dP, dQ or qInv.
+ for i := 0; i < 6; i++ {
+ <-values
+ }
+ case newSignatureMarker:
+ msg := fromHex(<-values)
+ <-values // skip salt
+ sig := fromHex(<-values)
+
+ h.Reset()
+ h.Write(msg)
+ hashed = h.Sum(hashed[:0])
+
+ if err := VerifyPSS(key, hash, hashed, sig, opts); err != nil {
+ t.Error(err)
+ }
+ default:
+ t.Fatalf("unknown marker: " + marker)
+ }
+ }
+}
+
+// TestPSSOpenSSL ensures that we can verify a PSS signature from OpenSSL with
+// the default options. OpenSSL sets the salt length to be maximal.
+func TestPSSOpenSSL(t *testing.T) {
+ hash := crypto.SHA256
+ h := hash.New()
+ h.Write([]byte("testing"))
+ hashed := h.Sum(nil)
+
+ // Generated with `echo -n testing | openssl dgst -sign key.pem -sigopt rsa_padding_mode:pss -sha256 > sig`
+ sig := []byte{
+ 0x95, 0x59, 0x6f, 0xd3, 0x10, 0xa2, 0xe7, 0xa2, 0x92, 0x9d,
+ 0x4a, 0x07, 0x2e, 0x2b, 0x27, 0xcc, 0x06, 0xc2, 0x87, 0x2c,
+ 0x52, 0xf0, 0x4a, 0xcc, 0x05, 0x94, 0xf2, 0xc3, 0x2e, 0x20,
+ 0xd7, 0x3e, 0x66, 0x62, 0xb5, 0x95, 0x2b, 0xa3, 0x93, 0x9a,
+ 0x66, 0x64, 0x25, 0xe0, 0x74, 0x66, 0x8c, 0x3e, 0x92, 0xeb,
+ 0xc6, 0xe6, 0xc0, 0x44, 0xf3, 0xb4, 0xb4, 0x2e, 0x8c, 0x66,
+ 0x0a, 0x37, 0x9c, 0x69,
+ }
+
+ if err := VerifyPSS(&rsaPrivateKey.PublicKey, hash, hashed, sig, nil); err != nil {
+ t.Error(err)
+ }
+}
+
+func TestPSSNilOpts(t *testing.T) {
+ hash := crypto.SHA256
+ h := hash.New()
+ h.Write([]byte("testing"))
+ hashed := h.Sum(nil)
+
+ SignPSS(rand.Reader, rsaPrivateKey, hash, hashed, nil)
+}
+
+func TestPSSSigning(t *testing.T) {
+ var saltLengthCombinations = []struct {
+ signSaltLength, verifySaltLength int
+ good bool
+ }{
+ {PSSSaltLengthAuto, PSSSaltLengthAuto, true},
+ {PSSSaltLengthEqualsHash, PSSSaltLengthAuto, true},
+ {PSSSaltLengthEqualsHash, PSSSaltLengthEqualsHash, true},
+ {PSSSaltLengthEqualsHash, 8, false},
+ {PSSSaltLengthAuto, PSSSaltLengthEqualsHash, false},
+ {8, 8, true},
+ {PSSSaltLengthAuto, 42, true},
+ {PSSSaltLengthAuto, 20, false},
+ {PSSSaltLengthAuto, -2, false},
+ }
+
+ hash := crypto.SHA1
+ h := hash.New()
+ h.Write([]byte("testing"))
+ hashed := h.Sum(nil)
+ var opts PSSOptions
+
+ for i, test := range saltLengthCombinations {
+ opts.SaltLength = test.signSaltLength
+ sig, err := SignPSS(rand.Reader, rsaPrivateKey, hash, hashed, &opts)
+ if err != nil {
+ t.Errorf("#%d: error while signing: %s", i, err)
+ continue
+ }
+
+ opts.SaltLength = test.verifySaltLength
+ err = VerifyPSS(&rsaPrivateKey.PublicKey, hash, hashed, sig, &opts)
+ if (err == nil) != test.good {
+ t.Errorf("#%d: bad result, wanted: %t, got: %s", i, test.good, err)
+ }
+ }
+}
+
+func TestPSS513(t *testing.T) {
+ // See Issue 42741, and separately, RFC 8017: "Note that the octet length of
+ // EM will be one less than k if modBits - 1 is divisible by 8 and equal to
+ // k otherwise, where k is the length in octets of the RSA modulus n."
+ key, err := GenerateKey(rand.Reader, 513)
+ if err != nil {
+ t.Fatal(err)
+ }
+ digest := sha256.Sum256([]byte("message"))
+ signature, err := key.Sign(rand.Reader, digest[:], &PSSOptions{
+ SaltLength: PSSSaltLengthAuto,
+ Hash: crypto.SHA256,
+ })
+ if err != nil {
+ t.Fatal(err)
+ }
+ err = VerifyPSS(&key.PublicKey, crypto.SHA256, digest[:], signature, nil)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func bigFromHex(hex string) *big.Int {
+ n, ok := new(big.Int).SetString(hex, 16)
+ if !ok {
+ panic("bad hex: " + hex)
+ }
+ return n
+}
+
+func intFromHex(hex string) int {
+ i, err := strconv.ParseInt(hex, 16, 32)
+ if err != nil {
+ panic(err)
+ }
+ return int(i)
+}
+
+func fromHex(hexStr string) []byte {
+ s, err := hex.DecodeString(hexStr)
+ if err != nil {
+ panic(err)
+ }
+ return s
+}
+
+func TestInvalidPSSSaltLength(t *testing.T) {
+ key, err := GenerateKey(rand.Reader, 245)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ digest := sha256.Sum256([]byte("message"))
+ // We don't check the exact error matches, because crypto/rsa and crypto/internal/boring
+ // return two different error variables, which have the same content but are not equal.
+ if _, err := SignPSS(rand.Reader, key, crypto.SHA256, digest[:], &PSSOptions{
+ SaltLength: -2,
+ Hash: crypto.SHA256,
+ }); err.Error() != InvalidSaltLenErr.Error() {
+ t.Fatalf("SignPSS unexpected error: got %v, want %v", err, InvalidSaltLenErr)
+ }
+
+ // We don't check the specific error here, because crypto/rsa and crypto/internal/boring
+ // return different errors, so we just check that _an error_ was returned.
+ if err := VerifyPSS(&key.PublicKey, crypto.SHA256, []byte{1, 2, 3}, make([]byte, 31), &PSSOptions{
+ SaltLength: -2,
+ }); err == nil {
+ t.Fatal("VerifyPSS unexpected success")
+ }
+}
diff --git a/src/crypto/rsa/rsa.go b/src/crypto/rsa/rsa.go
new file mode 100644
index 0000000..63bc8da
--- /dev/null
+++ b/src/crypto/rsa/rsa.go
@@ -0,0 +1,737 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package rsa implements RSA encryption as specified in PKCS #1 and RFC 8017.
+//
+// RSA is a single, fundamental operation that is used in this package to
+// implement either public-key encryption or public-key signatures.
+//
+// The original specification for encryption and signatures with RSA is PKCS #1
+// and the terms "RSA encryption" and "RSA signatures" by default refer to
+// PKCS #1 version 1.5. However, that specification has flaws and new designs
+// should use version 2, usually called by just OAEP and PSS, where
+// possible.
+//
+// Two sets of interfaces are included in this package. When a more abstract
+// interface isn't necessary, there are functions for encrypting/decrypting
+// with v1.5/OAEP and signing/verifying with v1.5/PSS. If one needs to abstract
+// over the public key primitive, the PrivateKey type implements the
+// Decrypter and Signer interfaces from the crypto package.
+//
+// Operations in this package are implemented using constant-time algorithms,
+// except for [GenerateKey], [PrivateKey.Precompute], and [PrivateKey.Validate].
+// Every other operation only leaks the bit size of the involved values, which
+// all depend on the selected key size.
+package rsa
+
+import (
+ "crypto"
+ "crypto/internal/bigmod"
+ "crypto/internal/boring"
+ "crypto/internal/boring/bbig"
+ "crypto/internal/randutil"
+ "crypto/rand"
+ "crypto/subtle"
+ "encoding/binary"
+ "errors"
+ "hash"
+ "io"
+ "math"
+ "math/big"
+)
+
+var bigOne = big.NewInt(1)
+
+// A PublicKey represents the public part of an RSA key.
+type PublicKey struct {
+ N *big.Int // modulus
+ E int // public exponent
+}
+
+// Any methods implemented on PublicKey might need to also be implemented on
+// PrivateKey, as the latter embeds the former and will expose its methods.
+
+// Size returns the modulus size in bytes. Raw signatures and ciphertexts
+// for or by this public key will have the same size.
+func (pub *PublicKey) Size() int {
+ return (pub.N.BitLen() + 7) / 8
+}
+
+// Equal reports whether pub and x have the same value.
+func (pub *PublicKey) Equal(x crypto.PublicKey) bool {
+ xx, ok := x.(*PublicKey)
+ if !ok {
+ return false
+ }
+ return pub.N.Cmp(xx.N) == 0 && pub.E == xx.E
+}
+
+// OAEPOptions is an interface for passing options to OAEP decryption using the
+// crypto.Decrypter interface.
+type OAEPOptions struct {
+ // Hash is the hash function that will be used when generating the mask.
+ Hash crypto.Hash
+
+ // MGFHash is the hash function used for MGF1.
+ // If zero, Hash is used instead.
+ MGFHash crypto.Hash
+
+ // Label is an arbitrary byte string that must be equal to the value
+ // used when encrypting.
+ Label []byte
+}
+
+var (
+ errPublicModulus = errors.New("crypto/rsa: missing public modulus")
+ errPublicExponentSmall = errors.New("crypto/rsa: public exponent too small")
+ errPublicExponentLarge = errors.New("crypto/rsa: public exponent too large")
+)
+
+// checkPub sanity checks the public key before we use it.
+// We require pub.E to fit into a 32-bit integer so that we
+// do not have different behavior depending on whether
+// int is 32 or 64 bits. See also
+// https://www.imperialviolet.org/2012/03/16/rsae.html.
+func checkPub(pub *PublicKey) error {
+ if pub.N == nil {
+ return errPublicModulus
+ }
+ if pub.E < 2 {
+ return errPublicExponentSmall
+ }
+ if pub.E > 1<<31-1 {
+ return errPublicExponentLarge
+ }
+ return nil
+}
+
+// A PrivateKey represents an RSA key
+type PrivateKey struct {
+ PublicKey // public part.
+ D *big.Int // private exponent
+ Primes []*big.Int // prime factors of N, has >= 2 elements.
+
+ // Precomputed contains precomputed values that speed up RSA operations,
+ // if available. It must be generated by calling PrivateKey.Precompute and
+ // must not be modified.
+ Precomputed PrecomputedValues
+}
+
+// Public returns the public key corresponding to priv.
+func (priv *PrivateKey) Public() crypto.PublicKey {
+ return &priv.PublicKey
+}
+
+// Equal reports whether priv and x have equivalent values. It ignores
+// Precomputed values.
+func (priv *PrivateKey) Equal(x crypto.PrivateKey) bool {
+ xx, ok := x.(*PrivateKey)
+ if !ok {
+ return false
+ }
+ if !priv.PublicKey.Equal(&xx.PublicKey) || priv.D.Cmp(xx.D) != 0 {
+ return false
+ }
+ if len(priv.Primes) != len(xx.Primes) {
+ return false
+ }
+ for i := range priv.Primes {
+ if priv.Primes[i].Cmp(xx.Primes[i]) != 0 {
+ return false
+ }
+ }
+ return true
+}
+
+// Sign signs digest with priv, reading randomness from rand. If opts is a
+// *PSSOptions then the PSS algorithm will be used, otherwise PKCS #1 v1.5 will
+// be used. digest must be the result of hashing the input message using
+// opts.HashFunc().
+//
+// This method implements crypto.Signer, which is an interface to support keys
+// where the private part is kept in, for example, a hardware module. Common
+// uses should use the Sign* functions in this package directly.
+func (priv *PrivateKey) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) ([]byte, error) {
+ if pssOpts, ok := opts.(*PSSOptions); ok {
+ return SignPSS(rand, priv, pssOpts.Hash, digest, pssOpts)
+ }
+
+ return SignPKCS1v15(rand, priv, opts.HashFunc(), digest)
+}
+
+// Decrypt decrypts ciphertext with priv. If opts is nil or of type
+// *PKCS1v15DecryptOptions then PKCS #1 v1.5 decryption is performed. Otherwise
+// opts must have type *OAEPOptions and OAEP decryption is done.
+func (priv *PrivateKey) Decrypt(rand io.Reader, ciphertext []byte, opts crypto.DecrypterOpts) (plaintext []byte, err error) {
+ if opts == nil {
+ return DecryptPKCS1v15(rand, priv, ciphertext)
+ }
+
+ switch opts := opts.(type) {
+ case *OAEPOptions:
+ if opts.MGFHash == 0 {
+ return decryptOAEP(opts.Hash.New(), opts.Hash.New(), rand, priv, ciphertext, opts.Label)
+ } else {
+ return decryptOAEP(opts.Hash.New(), opts.MGFHash.New(), rand, priv, ciphertext, opts.Label)
+ }
+
+ case *PKCS1v15DecryptOptions:
+ if l := opts.SessionKeyLen; l > 0 {
+ plaintext = make([]byte, l)
+ if _, err := io.ReadFull(rand, plaintext); err != nil {
+ return nil, err
+ }
+ if err := DecryptPKCS1v15SessionKey(rand, priv, ciphertext, plaintext); err != nil {
+ return nil, err
+ }
+ return plaintext, nil
+ } else {
+ return DecryptPKCS1v15(rand, priv, ciphertext)
+ }
+
+ default:
+ return nil, errors.New("crypto/rsa: invalid options for Decrypt")
+ }
+}
+
+type PrecomputedValues struct {
+ Dp, Dq *big.Int // D mod (P-1) (or mod Q-1)
+ Qinv *big.Int // Q^-1 mod P
+
+ // CRTValues is used for the 3rd and subsequent primes. Due to a
+ // historical accident, the CRT for the first two primes is handled
+ // differently in PKCS #1 and interoperability is sufficiently
+ // important that we mirror this.
+ //
+ // Note: these values are still filled in by Precompute for
+ // backwards compatibility but are not used. Multi-prime RSA is very rare,
+ // and is implemented by this package without CRT optimizations to limit
+ // complexity.
+ CRTValues []CRTValue
+
+ n, p, q *bigmod.Modulus // moduli for CRT with Montgomery precomputed constants
+}
+
+// CRTValue contains the precomputed Chinese remainder theorem values.
+type CRTValue struct {
+ Exp *big.Int // D mod (prime-1).
+ Coeff *big.Int // R·Coeff ≡ 1 mod Prime.
+ R *big.Int // product of primes prior to this (inc p and q).
+}
+
+// Validate performs basic sanity checks on the key.
+// It returns nil if the key is valid, or else an error describing a problem.
+func (priv *PrivateKey) Validate() error {
+ if err := checkPub(&priv.PublicKey); err != nil {
+ return err
+ }
+
+ // Check that Πprimes == n.
+ modulus := new(big.Int).Set(bigOne)
+ for _, prime := range priv.Primes {
+ // Any primes ≤ 1 will cause divide-by-zero panics later.
+ if prime.Cmp(bigOne) <= 0 {
+ return errors.New("crypto/rsa: invalid prime value")
+ }
+ modulus.Mul(modulus, prime)
+ }
+ if modulus.Cmp(priv.N) != 0 {
+ return errors.New("crypto/rsa: invalid modulus")
+ }
+
+ // Check that de ≡ 1 mod p-1, for each prime.
+ // This implies that e is coprime to each p-1 as e has a multiplicative
+ // inverse. Therefore e is coprime to lcm(p-1,q-1,r-1,...) =
+ // exponent(ℤ/nℤ). It also implies that a^de ≡ a mod p as a^(p-1) ≡ 1
+ // mod p. Thus a^de ≡ a mod n for all a coprime to n, as required.
+ congruence := new(big.Int)
+ de := new(big.Int).SetInt64(int64(priv.E))
+ de.Mul(de, priv.D)
+ for _, prime := range priv.Primes {
+ pminus1 := new(big.Int).Sub(prime, bigOne)
+ congruence.Mod(de, pminus1)
+ if congruence.Cmp(bigOne) != 0 {
+ return errors.New("crypto/rsa: invalid exponents")
+ }
+ }
+ return nil
+}
+
+// GenerateKey generates an RSA keypair of the given bit size using the
+// random source random (for example, crypto/rand.Reader).
+func GenerateKey(random io.Reader, bits int) (*PrivateKey, error) {
+ return GenerateMultiPrimeKey(random, 2, bits)
+}
+
+// GenerateMultiPrimeKey generates a multi-prime RSA keypair of the given bit
+// size and the given random source.
+//
+// Table 1 in "[On the Security of Multi-prime RSA]" suggests maximum numbers of
+// primes for a given bit size.
+//
+// Although the public keys are compatible (actually, indistinguishable) from
+// the 2-prime case, the private keys are not. Thus it may not be possible to
+// export multi-prime private keys in certain formats or to subsequently import
+// them into other code.
+//
+// This package does not implement CRT optimizations for multi-prime RSA, so the
+// keys with more than two primes will have worse performance.
+//
+// Note: The use of this function with a number of primes different from
+// two is not recommended for the above security, compatibility, and performance
+// reasons. Use GenerateKey instead.
+//
+// [On the Security of Multi-prime RSA]: http://www.cacr.math.uwaterloo.ca/techreports/2006/cacr2006-16.pdf
+func GenerateMultiPrimeKey(random io.Reader, nprimes int, bits int) (*PrivateKey, error) {
+ randutil.MaybeReadByte(random)
+
+ if boring.Enabled && random == boring.RandReader && nprimes == 2 &&
+ (bits == 2048 || bits == 3072 || bits == 4096) {
+ bN, bE, bD, bP, bQ, bDp, bDq, bQinv, err := boring.GenerateKeyRSA(bits)
+ if err != nil {
+ return nil, err
+ }
+ N := bbig.Dec(bN)
+ E := bbig.Dec(bE)
+ D := bbig.Dec(bD)
+ P := bbig.Dec(bP)
+ Q := bbig.Dec(bQ)
+ Dp := bbig.Dec(bDp)
+ Dq := bbig.Dec(bDq)
+ Qinv := bbig.Dec(bQinv)
+ e64 := E.Int64()
+ if !E.IsInt64() || int64(int(e64)) != e64 {
+ return nil, errors.New("crypto/rsa: generated key exponent too large")
+ }
+ key := &PrivateKey{
+ PublicKey: PublicKey{
+ N: N,
+ E: int(e64),
+ },
+ D: D,
+ Primes: []*big.Int{P, Q},
+ Precomputed: PrecomputedValues{
+ Dp: Dp,
+ Dq: Dq,
+ Qinv: Qinv,
+ CRTValues: make([]CRTValue, 0), // non-nil, to match Precompute
+ n: bigmod.NewModulusFromBig(N),
+ p: bigmod.NewModulusFromBig(P),
+ q: bigmod.NewModulusFromBig(Q),
+ },
+ }
+ return key, nil
+ }
+
+ priv := new(PrivateKey)
+ priv.E = 65537
+
+ if nprimes < 2 {
+ return nil, errors.New("crypto/rsa: GenerateMultiPrimeKey: nprimes must be >= 2")
+ }
+
+ if bits < 64 {
+ primeLimit := float64(uint64(1) << uint(bits/nprimes))
+ // pi approximates the number of primes less than primeLimit
+ pi := primeLimit / (math.Log(primeLimit) - 1)
+ // Generated primes start with 11 (in binary) so we can only
+ // use a quarter of them.
+ pi /= 4
+ // Use a factor of two to ensure that key generation terminates
+ // in a reasonable amount of time.
+ pi /= 2
+ if pi <= float64(nprimes) {
+ return nil, errors.New("crypto/rsa: too few primes of given length to generate an RSA key")
+ }
+ }
+
+ primes := make([]*big.Int, nprimes)
+
+NextSetOfPrimes:
+ for {
+ todo := bits
+ // crypto/rand should set the top two bits in each prime.
+ // Thus each prime has the form
+ // p_i = 2^bitlen(p_i) × 0.11... (in base 2).
+ // And the product is:
+ // P = 2^todo × α
+ // where α is the product of nprimes numbers of the form 0.11...
+ //
+ // If α < 1/2 (which can happen for nprimes > 2), we need to
+ // shift todo to compensate for lost bits: the mean value of 0.11...
+ // is 7/8, so todo + shift - nprimes * log2(7/8) ~= bits - 1/2
+ // will give good results.
+ if nprimes >= 7 {
+ todo += (nprimes - 2) / 5
+ }
+ for i := 0; i < nprimes; i++ {
+ var err error
+ primes[i], err = rand.Prime(random, todo/(nprimes-i))
+ if err != nil {
+ return nil, err
+ }
+ todo -= primes[i].BitLen()
+ }
+
+ // Make sure that primes is pairwise unequal.
+ for i, prime := range primes {
+ for j := 0; j < i; j++ {
+ if prime.Cmp(primes[j]) == 0 {
+ continue NextSetOfPrimes
+ }
+ }
+ }
+
+ n := new(big.Int).Set(bigOne)
+ totient := new(big.Int).Set(bigOne)
+ pminus1 := new(big.Int)
+ for _, prime := range primes {
+ n.Mul(n, prime)
+ pminus1.Sub(prime, bigOne)
+ totient.Mul(totient, pminus1)
+ }
+ if n.BitLen() != bits {
+ // This should never happen for nprimes == 2 because
+ // crypto/rand should set the top two bits in each prime.
+ // For nprimes > 2 we hope it does not happen often.
+ continue NextSetOfPrimes
+ }
+
+ priv.D = new(big.Int)
+ e := big.NewInt(int64(priv.E))
+ ok := priv.D.ModInverse(e, totient)
+
+ if ok != nil {
+ priv.Primes = primes
+ priv.N = n
+ break
+ }
+ }
+
+ priv.Precompute()
+ return priv, nil
+}
+
+// incCounter increments a four byte, big-endian counter.
+func incCounter(c *[4]byte) {
+ if c[3]++; c[3] != 0 {
+ return
+ }
+ if c[2]++; c[2] != 0 {
+ return
+ }
+ if c[1]++; c[1] != 0 {
+ return
+ }
+ c[0]++
+}
+
+// mgf1XOR XORs the bytes in out with a mask generated using the MGF1 function
+// specified in PKCS #1 v2.1.
+func mgf1XOR(out []byte, hash hash.Hash, seed []byte) {
+ var counter [4]byte
+ var digest []byte
+
+ done := 0
+ for done < len(out) {
+ hash.Write(seed)
+ hash.Write(counter[0:4])
+ digest = hash.Sum(digest[:0])
+ hash.Reset()
+
+ for i := 0; i < len(digest) && done < len(out); i++ {
+ out[done] ^= digest[i]
+ done++
+ }
+ incCounter(&counter)
+ }
+}
+
+// ErrMessageTooLong is returned when attempting to encrypt or sign a message
+// which is too large for the size of the key. When using SignPSS, this can also
+// be returned if the size of the salt is too large.
+var ErrMessageTooLong = errors.New("crypto/rsa: message too long for RSA key size")
+
+func encrypt(pub *PublicKey, plaintext []byte) ([]byte, error) {
+ boring.Unreachable()
+
+ N := bigmod.NewModulusFromBig(pub.N)
+ m, err := bigmod.NewNat().SetBytes(plaintext, N)
+ if err != nil {
+ return nil, err
+ }
+ e := intToBytes(pub.E)
+
+ return bigmod.NewNat().Exp(m, e, N).Bytes(N), nil
+}
+
+// intToBytes returns i as a big-endian slice of bytes with no leading zeroes,
+// leaking only the bit size of i through timing side-channels.
+func intToBytes(i int) []byte {
+ b := make([]byte, 8)
+ binary.BigEndian.PutUint64(b, uint64(i))
+ for len(b) > 1 && b[0] == 0 {
+ b = b[1:]
+ }
+ return b
+}
+
+// EncryptOAEP encrypts the given message with RSA-OAEP.
+//
+// OAEP is parameterised by a hash function that is used as a random oracle.
+// Encryption and decryption of a given message must use the same hash function
+// and sha256.New() is a reasonable choice.
+//
+// The random parameter is used as a source of entropy to ensure that
+// encrypting the same message twice doesn't result in the same ciphertext.
+//
+// The label parameter may contain arbitrary data that will not be encrypted,
+// but which gives important context to the message. For example, if a given
+// public key is used to encrypt two types of messages then distinct label
+// values could be used to ensure that a ciphertext for one purpose cannot be
+// used for another by an attacker. If not required it can be empty.
+//
+// The message must be no longer than the length of the public modulus minus
+// twice the hash length, minus a further 2.
+func EncryptOAEP(hash hash.Hash, random io.Reader, pub *PublicKey, msg []byte, label []byte) ([]byte, error) {
+ if err := checkPub(pub); err != nil {
+ return nil, err
+ }
+ hash.Reset()
+ k := pub.Size()
+ if len(msg) > k-2*hash.Size()-2 {
+ return nil, ErrMessageTooLong
+ }
+
+ if boring.Enabled && random == boring.RandReader {
+ bkey, err := boringPublicKey(pub)
+ if err != nil {
+ return nil, err
+ }
+ return boring.EncryptRSAOAEP(hash, hash, bkey, msg, label)
+ }
+ boring.UnreachableExceptTests()
+
+ hash.Write(label)
+ lHash := hash.Sum(nil)
+ hash.Reset()
+
+ em := make([]byte, k)
+ seed := em[1 : 1+hash.Size()]
+ db := em[1+hash.Size():]
+
+ copy(db[0:hash.Size()], lHash)
+ db[len(db)-len(msg)-1] = 1
+ copy(db[len(db)-len(msg):], msg)
+
+ _, err := io.ReadFull(random, seed)
+ if err != nil {
+ return nil, err
+ }
+
+ mgf1XOR(db, hash, seed)
+ mgf1XOR(seed, hash, db)
+
+ if boring.Enabled {
+ var bkey *boring.PublicKeyRSA
+ bkey, err = boringPublicKey(pub)
+ if err != nil {
+ return nil, err
+ }
+ return boring.EncryptRSANoPadding(bkey, em)
+ }
+
+ return encrypt(pub, em)
+}
+
+// ErrDecryption represents a failure to decrypt a message.
+// It is deliberately vague to avoid adaptive attacks.
+var ErrDecryption = errors.New("crypto/rsa: decryption error")
+
+// ErrVerification represents a failure to verify a signature.
+// It is deliberately vague to avoid adaptive attacks.
+var ErrVerification = errors.New("crypto/rsa: verification error")
+
+// Precompute performs some calculations that speed up private key operations
+// in the future.
+func (priv *PrivateKey) Precompute() {
+ if priv.Precomputed.n == nil && len(priv.Primes) == 2 {
+ priv.Precomputed.n = bigmod.NewModulusFromBig(priv.N)
+ priv.Precomputed.p = bigmod.NewModulusFromBig(priv.Primes[0])
+ priv.Precomputed.q = bigmod.NewModulusFromBig(priv.Primes[1])
+ }
+
+ // Fill in the backwards-compatibility *big.Int values.
+ if priv.Precomputed.Dp != nil {
+ return
+ }
+
+ priv.Precomputed.Dp = new(big.Int).Sub(priv.Primes[0], bigOne)
+ priv.Precomputed.Dp.Mod(priv.D, priv.Precomputed.Dp)
+
+ priv.Precomputed.Dq = new(big.Int).Sub(priv.Primes[1], bigOne)
+ priv.Precomputed.Dq.Mod(priv.D, priv.Precomputed.Dq)
+
+ priv.Precomputed.Qinv = new(big.Int).ModInverse(priv.Primes[1], priv.Primes[0])
+
+ r := new(big.Int).Mul(priv.Primes[0], priv.Primes[1])
+ priv.Precomputed.CRTValues = make([]CRTValue, len(priv.Primes)-2)
+ for i := 2; i < len(priv.Primes); i++ {
+ prime := priv.Primes[i]
+ values := &priv.Precomputed.CRTValues[i-2]
+
+ values.Exp = new(big.Int).Sub(prime, bigOne)
+ values.Exp.Mod(priv.D, values.Exp)
+
+ values.R = new(big.Int).Set(r)
+ values.Coeff = new(big.Int).ModInverse(r, prime)
+
+ r.Mul(r, prime)
+ }
+}
+
+const withCheck = true
+const noCheck = false
+
+// decrypt performs an RSA decryption of ciphertext into out. If check is true,
+// m^e is calculated and compared with ciphertext, in order to defend against
+// errors in the CRT computation.
+func decrypt(priv *PrivateKey, ciphertext []byte, check bool) ([]byte, error) {
+ if len(priv.Primes) <= 2 {
+ boring.Unreachable()
+ }
+
+ var (
+ err error
+ m, c *bigmod.Nat
+ N *bigmod.Modulus
+ t0 = bigmod.NewNat()
+ )
+ if priv.Precomputed.n == nil {
+ N = bigmod.NewModulusFromBig(priv.N)
+ c, err = bigmod.NewNat().SetBytes(ciphertext, N)
+ if err != nil {
+ return nil, ErrDecryption
+ }
+ m = bigmod.NewNat().Exp(c, priv.D.Bytes(), N)
+ } else {
+ N = priv.Precomputed.n
+ P, Q := priv.Precomputed.p, priv.Precomputed.q
+ Qinv, err := bigmod.NewNat().SetBytes(priv.Precomputed.Qinv.Bytes(), P)
+ if err != nil {
+ return nil, ErrDecryption
+ }
+ c, err = bigmod.NewNat().SetBytes(ciphertext, N)
+ if err != nil {
+ return nil, ErrDecryption
+ }
+
+ // m = c ^ Dp mod p
+ m = bigmod.NewNat().Exp(t0.Mod(c, P), priv.Precomputed.Dp.Bytes(), P)
+ // m2 = c ^ Dq mod q
+ m2 := bigmod.NewNat().Exp(t0.Mod(c, Q), priv.Precomputed.Dq.Bytes(), Q)
+ // m = m - m2 mod p
+ m.Sub(t0.Mod(m2, P), P)
+ // m = m * Qinv mod p
+ m.Mul(Qinv, P)
+ // m = m * q mod N
+ m.ExpandFor(N).Mul(t0.Mod(Q.Nat(), N), N)
+ // m = m + m2 mod N
+ m.Add(m2.ExpandFor(N), N)
+ }
+
+ if check {
+ c1 := bigmod.NewNat().Exp(m, intToBytes(priv.E), N)
+ if c1.Equal(c) != 1 {
+ return nil, ErrDecryption
+ }
+ }
+
+ return m.Bytes(N), nil
+}
+
+// DecryptOAEP decrypts ciphertext using RSA-OAEP.
+//
+// OAEP is parameterised by a hash function that is used as a random oracle.
+// Encryption and decryption of a given message must use the same hash function
+// and sha256.New() is a reasonable choice.
+//
+// The random parameter is legacy and ignored, and it can be as nil.
+//
+// The label parameter must match the value given when encrypting. See
+// EncryptOAEP for details.
+func DecryptOAEP(hash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) ([]byte, error) {
+ return decryptOAEP(hash, hash, random, priv, ciphertext, label)
+}
+
+func decryptOAEP(hash, mgfHash hash.Hash, random io.Reader, priv *PrivateKey, ciphertext []byte, label []byte) ([]byte, error) {
+ if err := checkPub(&priv.PublicKey); err != nil {
+ return nil, err
+ }
+ k := priv.Size()
+ if len(ciphertext) > k ||
+ k < hash.Size()*2+2 {
+ return nil, ErrDecryption
+ }
+
+ if boring.Enabled {
+ bkey, err := boringPrivateKey(priv)
+ if err != nil {
+ return nil, err
+ }
+ out, err := boring.DecryptRSAOAEP(hash, mgfHash, bkey, ciphertext, label)
+ if err != nil {
+ return nil, ErrDecryption
+ }
+ return out, nil
+ }
+
+ em, err := decrypt(priv, ciphertext, noCheck)
+ if err != nil {
+ return nil, err
+ }
+
+ hash.Write(label)
+ lHash := hash.Sum(nil)
+ hash.Reset()
+
+ firstByteIsZero := subtle.ConstantTimeByteEq(em[0], 0)
+
+ seed := em[1 : hash.Size()+1]
+ db := em[hash.Size()+1:]
+
+ mgf1XOR(seed, mgfHash, db)
+ mgf1XOR(db, mgfHash, seed)
+
+ lHash2 := db[0:hash.Size()]
+
+ // We have to validate the plaintext in constant time in order to avoid
+ // attacks like: J. Manger. A Chosen Ciphertext Attack on RSA Optimal
+ // Asymmetric Encryption Padding (OAEP) as Standardized in PKCS #1
+ // v2.0. In J. Kilian, editor, Advances in Cryptology.
+ lHash2Good := subtle.ConstantTimeCompare(lHash, lHash2)
+
+ // The remainder of the plaintext must be zero or more 0x00, followed
+ // by 0x01, followed by the message.
+ // lookingForIndex: 1 iff we are still looking for the 0x01
+ // index: the offset of the first 0x01 byte
+ // invalid: 1 iff we saw a non-zero byte before the 0x01.
+ var lookingForIndex, index, invalid int
+ lookingForIndex = 1
+ rest := db[hash.Size():]
+
+ for i := 0; i < len(rest); i++ {
+ equals0 := subtle.ConstantTimeByteEq(rest[i], 0)
+ equals1 := subtle.ConstantTimeByteEq(rest[i], 1)
+ index = subtle.ConstantTimeSelect(lookingForIndex&equals1, i, index)
+ lookingForIndex = subtle.ConstantTimeSelect(equals1, 0, lookingForIndex)
+ invalid = subtle.ConstantTimeSelect(lookingForIndex&^equals0, 1, invalid)
+ }
+
+ if firstByteIsZero&lHash2Good&^invalid&^lookingForIndex != 1 {
+ return nil, ErrDecryption
+ }
+
+ return rest[index+1:], nil
+}
diff --git a/src/crypto/rsa/rsa_export_test.go b/src/crypto/rsa/rsa_export_test.go
new file mode 100644
index 0000000..70406de
--- /dev/null
+++ b/src/crypto/rsa/rsa_export_test.go
@@ -0,0 +1,10 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rsa
+
+var NonZeroRandomBytes = nonZeroRandomBytes
+var EMSAPSSEncode = emsaPSSEncode
+var EMSAPSSVerify = emsaPSSVerify
+var InvalidSaltLenErr = invalidSaltLenErr
diff --git a/src/crypto/rsa/rsa_test.go b/src/crypto/rsa/rsa_test.go
new file mode 100644
index 0000000..3278a7f
--- /dev/null
+++ b/src/crypto/rsa/rsa_test.go
@@ -0,0 +1,882 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package rsa_test
+
+import (
+ "bufio"
+ "bytes"
+ "crypto"
+ "crypto/internal/boring"
+ "crypto/rand"
+ . "crypto/rsa"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/x509"
+ "encoding/pem"
+ "flag"
+ "fmt"
+ "internal/testenv"
+ "math/big"
+ "strings"
+ "testing"
+)
+
+func TestKeyGeneration(t *testing.T) {
+ for _, size := range []int{128, 1024, 2048, 3072} {
+ priv, err := GenerateKey(rand.Reader, size)
+ if err != nil {
+ t.Errorf("GenerateKey(%d): %v", size, err)
+ }
+ if bits := priv.N.BitLen(); bits != size {
+ t.Errorf("key too short (%d vs %d)", bits, size)
+ }
+ testKeyBasics(t, priv)
+ if testing.Short() {
+ break
+ }
+ }
+}
+
+func Test3PrimeKeyGeneration(t *testing.T) {
+ size := 768
+ if testing.Short() {
+ size = 256
+ }
+
+ priv, err := GenerateMultiPrimeKey(rand.Reader, 3, size)
+ if err != nil {
+ t.Errorf("failed to generate key")
+ }
+ testKeyBasics(t, priv)
+}
+
+func Test4PrimeKeyGeneration(t *testing.T) {
+ size := 768
+ if testing.Short() {
+ size = 256
+ }
+
+ priv, err := GenerateMultiPrimeKey(rand.Reader, 4, size)
+ if err != nil {
+ t.Errorf("failed to generate key")
+ }
+ testKeyBasics(t, priv)
+}
+
+func TestNPrimeKeyGeneration(t *testing.T) {
+ primeSize := 64
+ maxN := 24
+ if testing.Short() {
+ primeSize = 16
+ maxN = 16
+ }
+ // Test that generation of N-prime keys works for N > 4.
+ for n := 5; n < maxN; n++ {
+ priv, err := GenerateMultiPrimeKey(rand.Reader, n, 64+n*primeSize)
+ if err == nil {
+ testKeyBasics(t, priv)
+ } else {
+ t.Errorf("failed to generate %d-prime key", n)
+ }
+ }
+}
+
+func TestImpossibleKeyGeneration(t *testing.T) {
+ // This test ensures that trying to generate toy RSA keys doesn't enter
+ // an infinite loop.
+ for i := 0; i < 32; i++ {
+ GenerateKey(rand.Reader, i)
+ GenerateMultiPrimeKey(rand.Reader, 3, i)
+ GenerateMultiPrimeKey(rand.Reader, 4, i)
+ GenerateMultiPrimeKey(rand.Reader, 5, i)
+ }
+}
+
+func TestGnuTLSKey(t *testing.T) {
+ // This is a key generated by `certtool --generate-privkey --bits 128`.
+ // It's such that de ≢ 1 mod φ(n), but is congruent mod the order of
+ // the group.
+ priv := parseKey(testingKey(`-----BEGIN RSA TESTING KEY-----
+MGECAQACEQDar8EuoZuSosYtE9SeXSyPAgMBAAECEBf7XDET8e6jjTcfO7y/sykC
+CQDozXjCjkBzLQIJAPB6MqNbZaQrAghbZTdQoko5LQIIUp9ZiKDdYjMCCCCpqzmX
+d8Y7
+-----END RSA TESTING KEY-----`))
+ testKeyBasics(t, priv)
+}
+
+func testKeyBasics(t *testing.T, priv *PrivateKey) {
+ if err := priv.Validate(); err != nil {
+ t.Errorf("Validate() failed: %s", err)
+ }
+ if priv.D.Cmp(priv.N) > 0 {
+ t.Errorf("private exponent too large")
+ }
+
+ msg := []byte("hi!")
+ enc, err := EncryptPKCS1v15(rand.Reader, &priv.PublicKey, msg)
+ if err != nil {
+ t.Errorf("EncryptPKCS1v15: %v", err)
+ return
+ }
+
+ dec, err := DecryptPKCS1v15(nil, priv, enc)
+ if err != nil {
+ t.Errorf("DecryptPKCS1v15: %v", err)
+ return
+ }
+ if !bytes.Equal(dec, msg) {
+ t.Errorf("got:%x want:%x (%+v)", dec, msg, priv)
+ }
+}
+
+func TestAllocations(t *testing.T) {
+ if boring.Enabled {
+ t.Skip("skipping allocations test with BoringCrypto")
+ }
+ testenv.SkipIfOptimizationOff(t)
+
+ m := []byte("Hello Gophers")
+ c, err := EncryptPKCS1v15(rand.Reader, &test2048Key.PublicKey, m)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if allocs := testing.AllocsPerRun(100, func() {
+ p, err := DecryptPKCS1v15(nil, test2048Key, c)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !bytes.Equal(p, m) {
+ t.Fatalf("unexpected output: %q", p)
+ }
+ }); allocs > 10 {
+ t.Errorf("expected less than 10 allocations, got %0.1f", allocs)
+ }
+}
+
+var allFlag = flag.Bool("all", false, "test all key sizes up to 2048")
+
+func TestEverything(t *testing.T) {
+ min := 32
+ max := 560 // any smaller than this and not all tests will run
+ if testing.Short() {
+ min = max
+ }
+ if *allFlag {
+ max = 2048
+ }
+ for size := min; size <= max; size++ {
+ size := size
+ t.Run(fmt.Sprintf("%d", size), func(t *testing.T) {
+ t.Parallel()
+ priv, err := GenerateKey(rand.Reader, size)
+ if err != nil {
+ t.Errorf("GenerateKey(%d): %v", size, err)
+ }
+ if bits := priv.N.BitLen(); bits != size {
+ t.Errorf("key too short (%d vs %d)", bits, size)
+ }
+ testEverything(t, priv)
+ })
+ }
+}
+
+func testEverything(t *testing.T, priv *PrivateKey) {
+ if err := priv.Validate(); err != nil {
+ t.Errorf("Validate() failed: %s", err)
+ }
+
+ msg := []byte("test")
+ enc, err := EncryptPKCS1v15(rand.Reader, &priv.PublicKey, msg)
+ if err == ErrMessageTooLong {
+ t.Log("key too small for EncryptPKCS1v15")
+ } else if err != nil {
+ t.Errorf("EncryptPKCS1v15: %v", err)
+ }
+ if err == nil {
+ dec, err := DecryptPKCS1v15(nil, priv, enc)
+ if err != nil {
+ t.Errorf("DecryptPKCS1v15: %v", err)
+ }
+ err = DecryptPKCS1v15SessionKey(nil, priv, enc, make([]byte, 4))
+ if err != nil {
+ t.Errorf("DecryptPKCS1v15SessionKey: %v", err)
+ }
+ if !bytes.Equal(dec, msg) {
+ t.Errorf("got:%x want:%x (%+v)", dec, msg, priv)
+ }
+ }
+
+ label := []byte("label")
+ enc, err = EncryptOAEP(sha256.New(), rand.Reader, &priv.PublicKey, msg, label)
+ if err == ErrMessageTooLong {
+ t.Log("key too small for EncryptOAEP")
+ } else if err != nil {
+ t.Errorf("EncryptOAEP: %v", err)
+ }
+ if err == nil {
+ dec, err := DecryptOAEP(sha256.New(), nil, priv, enc, label)
+ if err != nil {
+ t.Errorf("DecryptOAEP: %v", err)
+ }
+ if !bytes.Equal(dec, msg) {
+ t.Errorf("got:%x want:%x (%+v)", dec, msg, priv)
+ }
+ }
+
+ hash := sha256.Sum256(msg)
+ sig, err := SignPKCS1v15(nil, priv, crypto.SHA256, hash[:])
+ if err == ErrMessageTooLong {
+ t.Log("key too small for SignPKCS1v15")
+ } else if err != nil {
+ t.Errorf("SignPKCS1v15: %v", err)
+ }
+ if err == nil {
+ err = VerifyPKCS1v15(&priv.PublicKey, crypto.SHA256, hash[:], sig)
+ if err != nil {
+ t.Errorf("VerifyPKCS1v15: %v", err)
+ }
+ sig[1] ^= 0x80
+ err = VerifyPKCS1v15(&priv.PublicKey, crypto.SHA256, hash[:], sig)
+ if err == nil {
+ t.Errorf("VerifyPKCS1v15 success for tampered signature")
+ }
+ sig[1] ^= 0x80
+ hash[1] ^= 0x80
+ err = VerifyPKCS1v15(&priv.PublicKey, crypto.SHA256, hash[:], sig)
+ if err == nil {
+ t.Errorf("VerifyPKCS1v15 success for tampered message")
+ }
+ hash[1] ^= 0x80
+ }
+
+ opts := &PSSOptions{SaltLength: PSSSaltLengthAuto}
+ sig, err = SignPSS(rand.Reader, priv, crypto.SHA256, hash[:], opts)
+ if err == ErrMessageTooLong {
+ t.Log("key too small for SignPSS with PSSSaltLengthAuto")
+ } else if err != nil {
+ t.Errorf("SignPSS: %v", err)
+ }
+ if err == nil {
+ err = VerifyPSS(&priv.PublicKey, crypto.SHA256, hash[:], sig, opts)
+ if err != nil {
+ t.Errorf("VerifyPSS: %v", err)
+ }
+ sig[1] ^= 0x80
+ err = VerifyPSS(&priv.PublicKey, crypto.SHA256, hash[:], sig, opts)
+ if err == nil {
+ t.Errorf("VerifyPSS success for tampered signature")
+ }
+ sig[1] ^= 0x80
+ hash[1] ^= 0x80
+ err = VerifyPSS(&priv.PublicKey, crypto.SHA256, hash[:], sig, opts)
+ if err == nil {
+ t.Errorf("VerifyPSS success for tampered message")
+ }
+ hash[1] ^= 0x80
+ }
+
+ opts.SaltLength = PSSSaltLengthEqualsHash
+ sig, err = SignPSS(rand.Reader, priv, crypto.SHA256, hash[:], opts)
+ if err == ErrMessageTooLong {
+ t.Log("key too small for SignPSS with PSSSaltLengthEqualsHash")
+ } else if err != nil {
+ t.Errorf("SignPSS: %v", err)
+ }
+ if err == nil {
+ err = VerifyPSS(&priv.PublicKey, crypto.SHA256, hash[:], sig, opts)
+ if err != nil {
+ t.Errorf("VerifyPSS: %v", err)
+ }
+ sig[1] ^= 0x80
+ err = VerifyPSS(&priv.PublicKey, crypto.SHA256, hash[:], sig, opts)
+ if err == nil {
+ t.Errorf("VerifyPSS success for tampered signature")
+ }
+ sig[1] ^= 0x80
+ hash[1] ^= 0x80
+ err = VerifyPSS(&priv.PublicKey, crypto.SHA256, hash[:], sig, opts)
+ if err == nil {
+ t.Errorf("VerifyPSS success for tampered message")
+ }
+ hash[1] ^= 0x80
+ }
+
+ // Check that an input bigger than the modulus is handled correctly,
+ // whether it is longer than the byte size of the modulus or not.
+ c := bytes.Repeat([]byte{0xff}, priv.Size())
+ err = VerifyPSS(&priv.PublicKey, crypto.SHA256, hash[:], c, opts)
+ if err == nil {
+ t.Errorf("VerifyPSS accepted a large signature")
+ }
+ _, err = DecryptPKCS1v15(nil, priv, c)
+ if err == nil {
+ t.Errorf("DecryptPKCS1v15 accepted a large ciphertext")
+ }
+ c = append(c, 0xff)
+ err = VerifyPSS(&priv.PublicKey, crypto.SHA256, hash[:], c, opts)
+ if err == nil {
+ t.Errorf("VerifyPSS accepted a long signature")
+ }
+ _, err = DecryptPKCS1v15(nil, priv, c)
+ if err == nil {
+ t.Errorf("DecryptPKCS1v15 accepted a long ciphertext")
+ }
+}
+
+func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") }
+
+func parseKey(s string) *PrivateKey {
+ p, _ := pem.Decode([]byte(s))
+ k, err := x509.ParsePKCS1PrivateKey(p.Bytes)
+ if err != nil {
+ panic(err)
+ }
+ return k
+}
+
+var test2048Key = parseKey(testingKey(`-----BEGIN RSA TESTING KEY-----
+MIIEnwIBAAKCAQBxY8hCshkKiXCUKydkrtQtQSRke28w4JotocDiVqou4k55DEDJ
+akvWbXXDcakV4HA8R2tOGgbxvTjFo8EK470w9O9ipapPUSrRRaBsSOlkaaIs6OYh
+4FLwZpqMNBVVEtguVUR/C34Y2pS9kRrHs6q+cGhDZolkWT7nGy5eSEvPDHg0EBq1
+1hu6HmPmI3r0BInONqJg2rcK3U++wk1lnbD3ysCZsKOqRUms3n/IWKeTqXXmz2XK
+J2t0NSXwiDmA9q0Gm+w0bXh3lzhtUP4MlzS+lnx9hK5bjzSbCUB5RXwMDG/uNMQq
+C4MmA4BPceSfMyAIFjdRLGy/K7gbb2viOYRtAgEDAoIBAEuX2tchZgcGSw1yGkMf
+OB4rbZhSSiCVvB5r1ew5xsnsNFCy1ducMo7zo9ehG2Pq9X2E8jQRWfZ+JdkX1gdC
+fiCjSkHDxt+LceDZFZ2F8O2bwXNF7sFAN0rvEbLNY44MkB7jgv9c/rs8YykLZy/N
+HH71mteZsO2Q1JoSHumFh99cwWHFhLxYh64qFeeH6Gqx6AM2YVBWHgs7OuKOvc8y
+zUbf8xftPht1kMwwDR1XySiEYtBtn74JflK3DcT8oxOuCZBuX6sMJHKbVP41zDj+
+FJZBmpAvNfCEYJUr1Hg+DpMLqLUg+D6v5vpliburbk9LxcKFZyyZ9QVe7GoqMLBu
+eGsCgYEAummUj4MMKWJC2mv5rj/dt2pj2/B2HtP2RLypai4et1/Ru9nNk8cjMLzC
+qXz6/RLuJ7/eD7asFS3y7EqxKxEmW0G8tTHjnzR/3wnpVipuWnwCDGU032HJVd13
+LMe51GH97qLzuDZjMCz+VlbCNdSslMgWWK0XmRnN7Yqxvh6ao2kCgYEAm7fTRBhF
+JtKcaJ7d8BQb9l8BNHfjayYOMq5CxoCyxa2pGBv/Mrnxv73Twp9Z/MP0ue5M5nZt
+GMovpP5cGdJLQ2w5p4H3opcuWeYW9Yyru2EyCEAI/hD/Td3QVP0ukc19BDuPl5Wg
+eIFs218uiVOU4pw3w+Et5B1PZ/F+ZLr5LGUCgYB8RmMKV11w7CyRnVEe1T56Ru09
+Svlp4qQt0xucHr8k6ovSkTO32hd10yxw/fyot0lv1T61JHK4yUydhyDHYMQ81n3O
+IUJqIv/qBpuOxvQ8UqwIQ3iU69uOk6TIhSaNlqlJwffQJEIgHf7kOdbOjchjMA7l
+yLpmETPzscvUFGcXmwKBgGfP4i1lg283EvBp6Uq4EqQ/ViL6l5zECXce1y8Ady5z
+xhASqiHRS9UpN9cU5qiCoyae3e75nhCGym3+6BE23Nede8UBT8G6HuaZZKOzHSeW
+IVrVW1QLVN6T4DioybaI/gLSX7pjwFBWSJI/dFuNDexoJS1AyUK+NO/2VEMnUMhD
+AoGAOsdn3Prnh/mjC95vraHCLap0bRBSexMdx77ImHgtFUUcSaT8DJHs+NZw1RdM
+SZA0J+zVQ8q7B11jIgz5hMz+chedwoRjTL7a8VRTKHFmmBH0zlEuV7L79w6HkRCQ
+VRg10GUN6heGLv0aOHbPdobcuVDH4sgOqpT1QnOuce34sQs=
+-----END RSA TESTING KEY-----`))
+
+var test3072Key = parseKey(testingKey(`-----BEGIN RSA TESTING KEY-----
+MIIG5AIBAAKCAYEAuvg7HHdVlr2kKZzRw9xs/uZqR6JK21izBdg8D52YPqEdMIhG
+BSuOrejT6HiDaJcyCkeNxj7E2dKWacIV4UytlPvDnSL9dQduytl31YQ01J5i20r3
+Kp1etZDEDltly1eVKcbdQTsr26oSQCojYYiYOj+q8w/rzH3WSEuMs04TMwxCR0CC
+nStVsNWw5zL45n26mxDgDdPK/i3OJTinTvPUDysB/V0c8tRaQ8U6YesmgSYGIMe0
+bx5l9k1RJbISGIipmS1IVdNAHSnxqJTUG+9k8SHzp5bvqPeiuVLMZeEdqPHwkNHW
+37LNO28nN+B0xhc4wvEFvggrMf58oO3oy16AzBsWDKSOQnsagc4gQtrJ4N4WOibT
+/LJB76RLoNyJ+Ov7Ue8ngqR3r3EM8I9AAkj2+3fo+DxcLuE9qOVnrHYFRqq+EYQe
+lKSg3Z0EHb7XF35xXeAFbpEXSVuidBRm+emgLkZ2n313hz6jUg3FdE3vLMYHvxly
+ROzgsz0cNOAH3jnXAgMBAAECggGBAILJqe/buk9cET3aqRGtW8FjRO0fJeYSQgjQ
+nhL+VsVYxqZwbSqosYIN4E46HxJG0YZHT3Fh7ynAGd+ZGN0lWjdhdhCxrUL0FBhp
+z13YwWwJ73UfF48DzoCL59lzLd30Qi+bIKLE1YUvjty7nUxY1MPKTbcBaBz/2alw
+z9eNwfhvlt1ozvVKnwK4OKtCCMKTKLnYMCL8CH+NYyq+Wqrr/Wcu2pF1VQ64ZPwL
+Ny/P4nttMdQ0Xo9sYD7PDvije+0VivsoT8ZatLt06fCwxEIue2uucIQjXCgO8Igm
+pZwBEWDfy+NHtTKrFpyKf357S8veDwdU14GjviY8JFH8Bg8PBn3i38635m0o7xMG
+pRlQi5x1zbHy4riOEjyjCIRVCKwKT5HEYNK5Uu3aQnlOV7CzxBLNp5lyioAIGOBC
+RKJabN5vbUqJjxaQ39tA29DtfA3+r30aMO+QzOl5hrjJV7A7ueV3dbjp+fDV0LPq
+QrJ68IvHPi3hfqVlP1UM2s4T69kcYQKBwQDoj+rZVb3Aq0JZ8LraR3nA1yFw4NfA
+SZ/Ne36rIySiy5z+qY9p6WRNLGLrusSIfmbmvStswAliIdh1cZTAUsIF5+kQvBQg
+VlxJW/nY5hTktIDOZPDaI77jid1iZLID3VXEm6dXY/Hv7DiUORudXAHoy6HZm2Jt
+kSkIplSeSfASqidj9Bv7V27ttCcMLu0ImdX4JyWoXkVuzBuxKAgiemtLS5IPN8tw
+m/o2lMaP8/sCMpXrlo2VS3TMsfJyRI/JGoMCgcEAzdAH1TKNeQ3ghzRdlw5NAs31
+VbcYzjz8HRkNhOsQCs++1ib7H2MZ3HPLpAa3mBJ+VfXO479G23yI7f2zpiUzRuVY
+cTMHw5Ln7FXfBro5eu/ruyNzKiWPElP8VK814HI5u5XqUU05BsQbe6AjSGHoU6P6
+PfSDzaw8hGW78GcZu4/EkZp/0TXW+1HUGgU+ObgmG+PnyIMHIt99i7qrOVbNmG9n
+uNwGwmfFzNqAtVLbLcVyBV5TR+Ze3ZAwjnVaH5MdAoHBAOg5ncd8KMjVuqHZEpyY
+tulraQcwXgCzBBHJ+YimxRSSwahCZOTbm768TeMaUtoBbnuF9nDXqgcFyQItct5B
+RWFkXITLakWINwtB/tEpnz9pRx3SCfeprhnENv7jkibtw5FZ5NYNBTAQ78aC6CJQ
+F9AAVxPWZ4kFZLYwcVrGdiYNJtxWjAKFIk3WkQ9HZIYsJ09ut9nSmP60bgqO8OCM
+4csEIUt06X7/IfGSylxAwytEnBPt+F9WQ8GLB5A3CmVERQKBwGmBR0Knk5aG4p7s
+3T1ee2QAqM+z+Odgo+1WtnN4/NROAwpNGVbRuqQkSDRhrSQr9s+iHtjpaS2C/b7i
+24FEeLDTSS9edZBwcqvYqWgNdwHqk/FvDs6ASoOewi+3UespIydihqf+6kjppx0M
+zomAh1S5LsMr4ZVBwhQtAtcOQ0a/QIlTpkpdS0OygwSDw45bNE3/2wYTBUl/QCCt
+JLFUKjkGgylkwaJPCDsnl+tb+jfQi87st8yX7/GsxPeCeRzOkQKBwGPcu2OgZfsl
+dMHz0LwKOEattrkDujpIoNxyTrBN4fX0RdhTgfRrqsEkrH/4XG5VTtc7K7sBgx7f
+IwP1uUAx5v16QDA1Z+oFBXwmI7atdKRM34kl1Q0i60z83ahgA/9bAsSpcA23LtM4
+u2PRX3YNXb9kUcSbod2tVfXyiu7wl6NlsYw5PeF8A8m7QicaeXR6t8NB02XqQ4k+
+BoyV2DVuoxSZKOMti0piQIIacSZWEbgyslwNxW99JRVfA2xKJGjUqA==
+-----END RSA TESTING KEY-----`))
+
+var test4096Key = parseKey(testingKey(`-----BEGIN RSA TESTING KEY-----
+MIIJKQIBAAKCAgEAwTmi+2MLTSm6GbsKksOHCMdIRsPwLlPtJQiMEjnKq4YEPSaC
+HXWQTza0KL/PySjhgw3Go5pC7epXlA9o1I+rbx4J3AwxC+xUUJqs3U0AETtzC1JD
+r3+/aP5KJzXp7IQXe1twEyHbQDCy3XUFhB0tZpIuAx82VSzMv4c6h6KPaES24ljd
+OxJJLPTYVECG2NbYBeKZPxyGNIkHn6/6rJDxnlICvLVBMrPaxsvN04ck55SRIglw
+MWmxpPTRFkMFERY7b2C33BuVICB8tXccvNwgtrNOmaWd6yjESZOYMyJQLi0QHMan
+ObuZw2PeUR+9gAE3R8/ji/i1VLYeVfC6TKzhziq5NKeBXzjSGOS7XyjvxrzypUco
+HiAUyVGKtouRFyOe4gr4xxZpljIEoN4TsBWSbM8GH6n5uFmEKvFnBR5KDRCwFfvI
+JudWm/oWptzQUyqRvzNtv4OgU9YVnx/fY3hyaD5ZnVZjUZzAjo3o8WSwmuTbZbJ1
+gX3pDRPw3g0naBm6rMEWPV4YR93be/mBERxWua6IrPPptRh9WYAJP4bkwk9V0F8U
+Ydk1URLeETAyFScNgukcKzpNw+OeCze2Blvrenf9goHefIpMzv4/ulEr7/v80ESq
+qd9CAwpz7cRe5+g18v5rFTEHESTCCq+rOFI5L59UX4VvE7CGOzcPLLZjlcMCAwEA
+AQKCAgB3/09UR0IxfYRxjlMWqg8mSHx+VhjG7KANq60xdGqE8wmW4F9V5DjmuNZR
+qC1mg9jpBpkh6R8/mZUiAh/cQgz5SPJekcOz3+TM2gIYvUUZbo4XrdMTHobEsYdj
+qnvHwpDCrxp/BzueNaAfIBl43pXfaVDh53RamSPeniCfMzlUS7g4AXACy2xeWwAt
+8pTL/UDTBtKc+x3talwts6A9oxYqeEvy3a3Lyx5G7zK39unYV896D9p5FWaZRuDC
+roRrBB+NH8ePDiIifYp1N6/FKf+29swNZ2kXLY4ZE2wl9V1OD/Y9qLEZjYQEb/UU
+9F0/LYIjOtvZhW83WJKmVIWeMI9Z4UooOztJJK0XOqSDsXVaEMgrF9D4E8BnKdWp
+ddM5E0nNXpLEV/SsoUyAMjArjImf8HjmJA45Px+BBGxdIv5PCyvUUD2R/6WbHOdh
+glH49I4SpVKGICV+qhLdSZkjWaItECwbsw5CeXrcOPjVCrNGOOKI8FdQN7S9JRiN
+Th6pTL1ezDUOx2Sq1M/h++ucd7akzsxm6my3leNYHxxyX7/PnQgUDyoXwQ1azAtB
+8PmMe7JAxuMjwFJJXn1Sgoq0ml0RkRkrj18+UMiz32qX8OtN+x44LkC7TnMNXqiA
+ohmzYy4WJRc3LyyTMWGrH00Zckc8oBvjf/rWy5X1nWz+DcuQIQKCAQEA6x92d8A9
+WR4qeHRY6zfHaaza8Z9vFUUUwebPxDy82Q6znu6nXNB/Q+OuhGohqcODUC8dj2qv
+7AyKdukzZzPTNSWNoSnr3c3nGpOzXxFntGOMFB83nmeoYGJEo3RertQO8QG2Dkis
+Ix9uKU6u2m5ijnH5cqHs2OcRbl2b+6mkRvPY2YxI0EqSXnMa1jpjeCKpZDW89iLU
+rm7x6vqyffqVaTt4PHj47p5QIUj8cRkVtAvUuIzM/R2g/epiytTo4iRM28rVLRnK
+28BtTtXZBT6Xy4UWX0fLSOUm2Hr1jiUJIc+Adb2h+zh69MBtBG6JRBiK7zwx7HxE
+c6sFzNvfMei99QKCAQEA0mHNpqmHuHb+wNdAEiKz4hCnYyuLDy+lZp/uQRkiODqV
+eUxAHRK1OP8yt45ZBxyaLcuRvAgK/ETg/QlYWUuAXvUWVGq9Ycv3WrpjUL0DHvuo
+rBfWTSiTNWH9sbDoCapiJMDe28ELBXVp1dCKuei/EReRHYg/vJn+GdPaZL60rlQg
+qCMou3jOXw94/Y05QcJQNkoLmVEEEwkbwrfXWvjShRbKNsv5kJydgPRfnsu5JSue
+Ydkx/Io4+4xz6vjfDDjgFFfvOJJjouFkYGWIDuT5JViIVBVK1F3XrkzOYUjoBzo7
+xDJkZrgNyNIpWXdzwfb8WTCJAOTHMk9DSB4lkk651wKCAQBKMTtovjidjm9IYy5L
+yuYZ6nmMFQswYwQRy4t0GNZeh80WMaiOGRyPh6DiF7tXnmIpQzTItJmemrZ2n0+h
+GTFka90tJdVPwFFUiZboQM3Alkj1cIRUb9Ep2Nhf27Ck6jVsx2VzTGtFCf3w+ush
+8gMXf89+5KmgKAnQEanO19EGspuSyjmPwHg/ZYLqZrJMjmN1Q5/E62jBQjEEPOdl
+6VSMSD/AlUu3wCz409cUuR2oGrOdKJDmrhrHBNb3ugdilKHMGUz7VlA015umbMR2
+azHq/qv4lOcIsYZ4eRRTLkybZqbagGREqaXi5XWBGIAoBLaSlyQJw4y2ExlZc2gS
+j6ahAoIBAQCwzdsL1mumHfMI050X4Kw2L3LNCBoMwCkL7xpHAT1d7fYSg39aL4+3
+f9j6pBmzvVjhZbRrRoMc8TH31XO3T5lptCV4+l+AIe8WA5BVmRNXZX2ia0IBhDj6
+4whW3eqTvOpQIvrnyfteMgeo1mLPzIdOcPTW0dtmwC/pOr7Obergmvj69NlVfDhL
+cXBn/diBqDDK/z1yMsDu0nfPE7tby8L4cGeu14s7+jLv3e/CP0mwsFChwOueZfdv
+h+EfNtoUpnPDBQeZDoXHrA40aP+ILOwpc5bWuzIw+VC6PfgvkBrXgBwcTZFNNh73
+h4+Sja3t84it1/k7lAjIAg70O8mthJXvAoIBAQDUUqWxqQN76gY2CPuXrwIvWvfP
+Z9U2Lv5ZTmY75L20CWRY0os0hAF68vCwxLpfeUMUTSokwa5L/l1gHwA2Zqm1977W
+9wV2Iiyqmkz9u3fu5YNOlezSoffOvAf/GUvSQ9HJ/VGqFdy2bC6NE81HRxojxeeY
+7ZmNlJrcsupyWmpUTpAd4cRVaCjcZQRoj+uIYCbgtV6/RD5VXHcPTd9wR7pjZPv7
+239qVdVU4ahkSZP6ikeN/wOEegWS0i/cKSgYmLBpWFGze3EKvHdEzurqPNCr5zo2
+jd7HGMtCpvqFx/7wUl09ac/kHeY+Ob2KduWinSPm5+jI6dPohnGx/wBEVCWh
+-----END RSA TESTING KEY-----`))
+
+func BenchmarkDecryptPKCS1v15(b *testing.B) {
+ b.Run("2048", func(b *testing.B) { benchmarkDecryptPKCS1v15(b, test2048Key) })
+ b.Run("3072", func(b *testing.B) { benchmarkDecryptPKCS1v15(b, test3072Key) })
+ b.Run("4096", func(b *testing.B) { benchmarkDecryptPKCS1v15(b, test4096Key) })
+}
+
+func benchmarkDecryptPKCS1v15(b *testing.B, k *PrivateKey) {
+ r := bufio.NewReaderSize(rand.Reader, 1<<15)
+
+ m := []byte("Hello Gophers")
+ c, err := EncryptPKCS1v15(r, &k.PublicKey, m)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ b.ResetTimer()
+ var sink byte
+ for i := 0; i < b.N; i++ {
+ p, err := DecryptPKCS1v15(r, k, c)
+ if err != nil {
+ b.Fatal(err)
+ }
+ if !bytes.Equal(p, m) {
+ b.Fatalf("unexpected output: %q", p)
+ }
+ sink ^= p[0]
+ }
+}
+
+func BenchmarkEncryptPKCS1v15(b *testing.B) {
+ b.Run("2048", func(b *testing.B) {
+ r := bufio.NewReaderSize(rand.Reader, 1<<15)
+ m := []byte("Hello Gophers")
+
+ var sink byte
+ for i := 0; i < b.N; i++ {
+ c, err := EncryptPKCS1v15(r, &test2048Key.PublicKey, m)
+ if err != nil {
+ b.Fatal(err)
+ }
+ sink ^= c[0]
+ }
+ })
+}
+
+func BenchmarkDecryptOAEP(b *testing.B) {
+ b.Run("2048", func(b *testing.B) {
+ r := bufio.NewReaderSize(rand.Reader, 1<<15)
+
+ m := []byte("Hello Gophers")
+ c, err := EncryptOAEP(sha256.New(), r, &test2048Key.PublicKey, m, nil)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ b.ResetTimer()
+ var sink byte
+ for i := 0; i < b.N; i++ {
+ p, err := DecryptOAEP(sha256.New(), r, test2048Key, c, nil)
+ if err != nil {
+ b.Fatal(err)
+ }
+ if !bytes.Equal(p, m) {
+ b.Fatalf("unexpected output: %q", p)
+ }
+ sink ^= p[0]
+ }
+ })
+}
+
+func BenchmarkEncryptOAEP(b *testing.B) {
+ b.Run("2048", func(b *testing.B) {
+ r := bufio.NewReaderSize(rand.Reader, 1<<15)
+ m := []byte("Hello Gophers")
+
+ var sink byte
+ for i := 0; i < b.N; i++ {
+ c, err := EncryptOAEP(sha256.New(), r, &test2048Key.PublicKey, m, nil)
+ if err != nil {
+ b.Fatal(err)
+ }
+ sink ^= c[0]
+ }
+ })
+}
+
+func BenchmarkSignPKCS1v15(b *testing.B) {
+ b.Run("2048", func(b *testing.B) {
+ hashed := sha256.Sum256([]byte("testing"))
+
+ var sink byte
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ s, err := SignPKCS1v15(rand.Reader, test2048Key, crypto.SHA256, hashed[:])
+ if err != nil {
+ b.Fatal(err)
+ }
+ sink ^= s[0]
+ }
+ })
+}
+
+func BenchmarkVerifyPKCS1v15(b *testing.B) {
+ b.Run("2048", func(b *testing.B) {
+ hashed := sha256.Sum256([]byte("testing"))
+ s, err := SignPKCS1v15(rand.Reader, test2048Key, crypto.SHA256, hashed[:])
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ err := VerifyPKCS1v15(&test2048Key.PublicKey, crypto.SHA256, hashed[:], s)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+ })
+}
+
+func BenchmarkSignPSS(b *testing.B) {
+ b.Run("2048", func(b *testing.B) {
+ hashed := sha256.Sum256([]byte("testing"))
+
+ var sink byte
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ s, err := SignPSS(rand.Reader, test2048Key, crypto.SHA256, hashed[:], nil)
+ if err != nil {
+ b.Fatal(err)
+ }
+ sink ^= s[0]
+ }
+ })
+}
+
+func BenchmarkVerifyPSS(b *testing.B) {
+ b.Run("2048", func(b *testing.B) {
+ hashed := sha256.Sum256([]byte("testing"))
+ s, err := SignPSS(rand.Reader, test2048Key, crypto.SHA256, hashed[:], nil)
+ if err != nil {
+ b.Fatal(err)
+ }
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ err := VerifyPSS(&test2048Key.PublicKey, crypto.SHA256, hashed[:], s, nil)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+ })
+}
+
+type testEncryptOAEPMessage struct {
+ in []byte
+ seed []byte
+ out []byte
+}
+
+type testEncryptOAEPStruct struct {
+ modulus string
+ e int
+ d string
+ msgs []testEncryptOAEPMessage
+}
+
+func TestEncryptOAEP(t *testing.T) {
+ sha1 := sha1.New()
+ n := new(big.Int)
+ for i, test := range testEncryptOAEPData {
+ n.SetString(test.modulus, 16)
+ public := PublicKey{N: n, E: test.e}
+
+ for j, message := range test.msgs {
+ randomSource := bytes.NewReader(message.seed)
+ out, err := EncryptOAEP(sha1, randomSource, &public, message.in, nil)
+ if err != nil {
+ t.Errorf("#%d,%d error: %s", i, j, err)
+ }
+ if !bytes.Equal(out, message.out) {
+ t.Errorf("#%d,%d bad result: %x (want %x)", i, j, out, message.out)
+ }
+ }
+ }
+}
+
+func TestDecryptOAEP(t *testing.T) {
+ random := rand.Reader
+
+ sha1 := sha1.New()
+ n := new(big.Int)
+ d := new(big.Int)
+ for i, test := range testEncryptOAEPData {
+ n.SetString(test.modulus, 16)
+ d.SetString(test.d, 16)
+ private := new(PrivateKey)
+ private.PublicKey = PublicKey{N: n, E: test.e}
+ private.D = d
+
+ for j, message := range test.msgs {
+ out, err := DecryptOAEP(sha1, nil, private, message.out, nil)
+ if err != nil {
+ t.Errorf("#%d,%d error: %s", i, j, err)
+ } else if !bytes.Equal(out, message.in) {
+ t.Errorf("#%d,%d bad result: %#v (want %#v)", i, j, out, message.in)
+ }
+
+ // Decrypt with blinding.
+ out, err = DecryptOAEP(sha1, random, private, message.out, nil)
+ if err != nil {
+ t.Errorf("#%d,%d (blind) error: %s", i, j, err)
+ } else if !bytes.Equal(out, message.in) {
+ t.Errorf("#%d,%d (blind) bad result: %#v (want %#v)", i, j, out, message.in)
+ }
+ }
+ if testing.Short() {
+ break
+ }
+ }
+}
+
+func Test2DecryptOAEP(t *testing.T) {
+ random := rand.Reader
+
+ msg := []byte{0xed, 0x36, 0x90, 0x8d, 0xbe, 0xfc, 0x35, 0x40, 0x70, 0x4f, 0xf5, 0x9d, 0x6e, 0xc2, 0xeb, 0xf5, 0x27, 0xae, 0x65, 0xb0, 0x59, 0x29, 0x45, 0x25, 0x8c, 0xc1, 0x91, 0x22}
+ in := []byte{0x72, 0x26, 0x84, 0xc9, 0xcf, 0xd6, 0xa8, 0x96, 0x04, 0x3e, 0x34, 0x07, 0x2c, 0x4f, 0xe6, 0x52, 0xbe, 0x46, 0x3c, 0xcf, 0x79, 0x21, 0x09, 0x64, 0xe7, 0x33, 0x66, 0x9b, 0xf8, 0x14, 0x22, 0x43, 0xfe, 0x8e, 0x52, 0x8b, 0xe0, 0x5f, 0x98, 0xef, 0x54, 0xac, 0x6b, 0xc6, 0x26, 0xac, 0x5b, 0x1b, 0x4b, 0x7d, 0x2e, 0xd7, 0x69, 0x28, 0x5a, 0x2f, 0x4a, 0x95, 0x89, 0x6c, 0xc7, 0x53, 0x95, 0xc7, 0xd2, 0x89, 0x04, 0x6f, 0x94, 0x74, 0x9b, 0x09, 0x0d, 0xf4, 0x61, 0x2e, 0xab, 0x48, 0x57, 0x4a, 0xbf, 0x95, 0xcb, 0xff, 0x15, 0xe2, 0xa0, 0x66, 0x58, 0xf7, 0x46, 0xf8, 0xc7, 0x0b, 0xb5, 0x1e, 0xa7, 0xba, 0x36, 0xce, 0xdd, 0x36, 0x41, 0x98, 0x6e, 0x10, 0xf9, 0x3b, 0x70, 0xbb, 0xa1, 0xda, 0x00, 0x40, 0xd5, 0xa5, 0x3f, 0x87, 0x64, 0x32, 0x7c, 0xbc, 0x50, 0x52, 0x0e, 0x4f, 0x21, 0xbd}
+
+ n := new(big.Int)
+ d := new(big.Int)
+ n.SetString(testEncryptOAEPData[0].modulus, 16)
+ d.SetString(testEncryptOAEPData[0].d, 16)
+ priv := new(PrivateKey)
+ priv.PublicKey = PublicKey{N: n, E: testEncryptOAEPData[0].e}
+ priv.D = d
+ sha1 := crypto.SHA1
+ sha256 := crypto.SHA256
+
+ out, err := priv.Decrypt(random, in, &OAEPOptions{MGFHash: sha1, Hash: sha256})
+
+ if err != nil {
+ t.Errorf("error: %s", err)
+ } else if !bytes.Equal(out, msg) {
+ t.Errorf("bad result %#v (want %#v)", out, msg)
+ }
+}
+
+func TestEncryptDecryptOAEP(t *testing.T) {
+ sha256 := sha256.New()
+ n := new(big.Int)
+ d := new(big.Int)
+ for i, test := range testEncryptOAEPData {
+ n.SetString(test.modulus, 16)
+ d.SetString(test.d, 16)
+ priv := new(PrivateKey)
+ priv.PublicKey = PublicKey{N: n, E: test.e}
+ priv.D = d
+
+ for j, message := range test.msgs {
+ label := []byte(fmt.Sprintf("hi#%d", j))
+ enc, err := EncryptOAEP(sha256, rand.Reader, &priv.PublicKey, message.in, label)
+ if err != nil {
+ t.Errorf("#%d,%d: EncryptOAEP: %v", i, j, err)
+ continue
+ }
+ dec, err := DecryptOAEP(sha256, rand.Reader, priv, enc, label)
+ if err != nil {
+ t.Errorf("#%d,%d: DecryptOAEP: %v", i, j, err)
+ continue
+ }
+ if !bytes.Equal(dec, message.in) {
+ t.Errorf("#%d,%d: round trip %q -> %q", i, j, message.in, dec)
+ }
+ }
+ }
+}
+
+// testEncryptOAEPData contains a subset of the vectors from RSA's "Test vectors for RSA-OAEP".
+var testEncryptOAEPData = []testEncryptOAEPStruct{
+ // Key 1
+ {"a8b3b284af8eb50b387034a860f146c4919f318763cd6c5598c8ae4811a1e0abc4c7e0b082d693a5e7fced675cf4668512772c0cbc64a742c6c630f533c8cc72f62ae833c40bf25842e984bb78bdbf97c0107d55bdb662f5c4e0fab9845cb5148ef7392dd3aaff93ae1e6b667bb3d4247616d4f5ba10d4cfd226de88d39f16fb",
+ 65537,
+ "53339cfdb79fc8466a655c7316aca85c55fd8f6dd898fdaf119517ef4f52e8fd8e258df93fee180fa0e4ab29693cd83b152a553d4ac4d1812b8b9fa5af0e7f55fe7304df41570926f3311f15c4d65a732c483116ee3d3d2d0af3549ad9bf7cbfb78ad884f84d5beb04724dc7369b31def37d0cf539e9cfcdd3de653729ead5d1",
+ []testEncryptOAEPMessage{
+ // Example 1.1
+ {
+ []byte{0x66, 0x28, 0x19, 0x4e, 0x12, 0x07, 0x3d, 0xb0,
+ 0x3b, 0xa9, 0x4c, 0xda, 0x9e, 0xf9, 0x53, 0x23, 0x97,
+ 0xd5, 0x0d, 0xba, 0x79, 0xb9, 0x87, 0x00, 0x4a, 0xfe,
+ 0xfe, 0x34,
+ },
+ []byte{0x18, 0xb7, 0x76, 0xea, 0x21, 0x06, 0x9d, 0x69,
+ 0x77, 0x6a, 0x33, 0xe9, 0x6b, 0xad, 0x48, 0xe1, 0xdd,
+ 0xa0, 0xa5, 0xef,
+ },
+ []byte{0x35, 0x4f, 0xe6, 0x7b, 0x4a, 0x12, 0x6d, 0x5d,
+ 0x35, 0xfe, 0x36, 0xc7, 0x77, 0x79, 0x1a, 0x3f, 0x7b,
+ 0xa1, 0x3d, 0xef, 0x48, 0x4e, 0x2d, 0x39, 0x08, 0xaf,
+ 0xf7, 0x22, 0xfa, 0xd4, 0x68, 0xfb, 0x21, 0x69, 0x6d,
+ 0xe9, 0x5d, 0x0b, 0xe9, 0x11, 0xc2, 0xd3, 0x17, 0x4f,
+ 0x8a, 0xfc, 0xc2, 0x01, 0x03, 0x5f, 0x7b, 0x6d, 0x8e,
+ 0x69, 0x40, 0x2d, 0xe5, 0x45, 0x16, 0x18, 0xc2, 0x1a,
+ 0x53, 0x5f, 0xa9, 0xd7, 0xbf, 0xc5, 0xb8, 0xdd, 0x9f,
+ 0xc2, 0x43, 0xf8, 0xcf, 0x92, 0x7d, 0xb3, 0x13, 0x22,
+ 0xd6, 0xe8, 0x81, 0xea, 0xa9, 0x1a, 0x99, 0x61, 0x70,
+ 0xe6, 0x57, 0xa0, 0x5a, 0x26, 0x64, 0x26, 0xd9, 0x8c,
+ 0x88, 0x00, 0x3f, 0x84, 0x77, 0xc1, 0x22, 0x70, 0x94,
+ 0xa0, 0xd9, 0xfa, 0x1e, 0x8c, 0x40, 0x24, 0x30, 0x9c,
+ 0xe1, 0xec, 0xcc, 0xb5, 0x21, 0x00, 0x35, 0xd4, 0x7a,
+ 0xc7, 0x2e, 0x8a,
+ },
+ },
+ // Example 1.2
+ {
+ []byte{0x75, 0x0c, 0x40, 0x47, 0xf5, 0x47, 0xe8, 0xe4,
+ 0x14, 0x11, 0x85, 0x65, 0x23, 0x29, 0x8a, 0xc9, 0xba,
+ 0xe2, 0x45, 0xef, 0xaf, 0x13, 0x97, 0xfb, 0xe5, 0x6f,
+ 0x9d, 0xd5,
+ },
+ []byte{0x0c, 0xc7, 0x42, 0xce, 0x4a, 0x9b, 0x7f, 0x32,
+ 0xf9, 0x51, 0xbc, 0xb2, 0x51, 0xef, 0xd9, 0x25, 0xfe,
+ 0x4f, 0xe3, 0x5f,
+ },
+ []byte{0x64, 0x0d, 0xb1, 0xac, 0xc5, 0x8e, 0x05, 0x68,
+ 0xfe, 0x54, 0x07, 0xe5, 0xf9, 0xb7, 0x01, 0xdf, 0xf8,
+ 0xc3, 0xc9, 0x1e, 0x71, 0x6c, 0x53, 0x6f, 0xc7, 0xfc,
+ 0xec, 0x6c, 0xb5, 0xb7, 0x1c, 0x11, 0x65, 0x98, 0x8d,
+ 0x4a, 0x27, 0x9e, 0x15, 0x77, 0xd7, 0x30, 0xfc, 0x7a,
+ 0x29, 0x93, 0x2e, 0x3f, 0x00, 0xc8, 0x15, 0x15, 0x23,
+ 0x6d, 0x8d, 0x8e, 0x31, 0x01, 0x7a, 0x7a, 0x09, 0xdf,
+ 0x43, 0x52, 0xd9, 0x04, 0xcd, 0xeb, 0x79, 0xaa, 0x58,
+ 0x3a, 0xdc, 0xc3, 0x1e, 0xa6, 0x98, 0xa4, 0xc0, 0x52,
+ 0x83, 0xda, 0xba, 0x90, 0x89, 0xbe, 0x54, 0x91, 0xf6,
+ 0x7c, 0x1a, 0x4e, 0xe4, 0x8d, 0xc7, 0x4b, 0xbb, 0xe6,
+ 0x64, 0x3a, 0xef, 0x84, 0x66, 0x79, 0xb4, 0xcb, 0x39,
+ 0x5a, 0x35, 0x2d, 0x5e, 0xd1, 0x15, 0x91, 0x2d, 0xf6,
+ 0x96, 0xff, 0xe0, 0x70, 0x29, 0x32, 0x94, 0x6d, 0x71,
+ 0x49, 0x2b, 0x44,
+ },
+ },
+ // Example 1.3
+ {
+ []byte{0xd9, 0x4a, 0xe0, 0x83, 0x2e, 0x64, 0x45, 0xce,
+ 0x42, 0x33, 0x1c, 0xb0, 0x6d, 0x53, 0x1a, 0x82, 0xb1,
+ 0xdb, 0x4b, 0xaa, 0xd3, 0x0f, 0x74, 0x6d, 0xc9, 0x16,
+ 0xdf, 0x24, 0xd4, 0xe3, 0xc2, 0x45, 0x1f, 0xff, 0x59,
+ 0xa6, 0x42, 0x3e, 0xb0, 0xe1, 0xd0, 0x2d, 0x4f, 0xe6,
+ 0x46, 0xcf, 0x69, 0x9d, 0xfd, 0x81, 0x8c, 0x6e, 0x97,
+ 0xb0, 0x51,
+ },
+ []byte{0x25, 0x14, 0xdf, 0x46, 0x95, 0x75, 0x5a, 0x67,
+ 0xb2, 0x88, 0xea, 0xf4, 0x90, 0x5c, 0x36, 0xee, 0xc6,
+ 0x6f, 0xd2, 0xfd,
+ },
+ []byte{0x42, 0x37, 0x36, 0xed, 0x03, 0x5f, 0x60, 0x26,
+ 0xaf, 0x27, 0x6c, 0x35, 0xc0, 0xb3, 0x74, 0x1b, 0x36,
+ 0x5e, 0x5f, 0x76, 0xca, 0x09, 0x1b, 0x4e, 0x8c, 0x29,
+ 0xe2, 0xf0, 0xbe, 0xfe, 0xe6, 0x03, 0x59, 0x5a, 0xa8,
+ 0x32, 0x2d, 0x60, 0x2d, 0x2e, 0x62, 0x5e, 0x95, 0xeb,
+ 0x81, 0xb2, 0xf1, 0xc9, 0x72, 0x4e, 0x82, 0x2e, 0xca,
+ 0x76, 0xdb, 0x86, 0x18, 0xcf, 0x09, 0xc5, 0x34, 0x35,
+ 0x03, 0xa4, 0x36, 0x08, 0x35, 0xb5, 0x90, 0x3b, 0xc6,
+ 0x37, 0xe3, 0x87, 0x9f, 0xb0, 0x5e, 0x0e, 0xf3, 0x26,
+ 0x85, 0xd5, 0xae, 0xc5, 0x06, 0x7c, 0xd7, 0xcc, 0x96,
+ 0xfe, 0x4b, 0x26, 0x70, 0xb6, 0xea, 0xc3, 0x06, 0x6b,
+ 0x1f, 0xcf, 0x56, 0x86, 0xb6, 0x85, 0x89, 0xaa, 0xfb,
+ 0x7d, 0x62, 0x9b, 0x02, 0xd8, 0xf8, 0x62, 0x5c, 0xa3,
+ 0x83, 0x36, 0x24, 0xd4, 0x80, 0x0f, 0xb0, 0x81, 0xb1,
+ 0xcf, 0x94, 0xeb,
+ },
+ },
+ },
+ },
+ // Key 10
+ {"ae45ed5601cec6b8cc05f803935c674ddbe0d75c4c09fd7951fc6b0caec313a8df39970c518bffba5ed68f3f0d7f22a4029d413f1ae07e4ebe9e4177ce23e7f5404b569e4ee1bdcf3c1fb03ef113802d4f855eb9b5134b5a7c8085adcae6fa2fa1417ec3763be171b0c62b760ede23c12ad92b980884c641f5a8fac26bdad4a03381a22fe1b754885094c82506d4019a535a286afeb271bb9ba592de18dcf600c2aeeae56e02f7cf79fc14cf3bdc7cd84febbbf950ca90304b2219a7aa063aefa2c3c1980e560cd64afe779585b6107657b957857efde6010988ab7de417fc88d8f384c4e6e72c3f943e0c31c0c4a5cc36f879d8a3ac9d7d59860eaada6b83bb",
+ 65537,
+ "056b04216fe5f354ac77250a4b6b0c8525a85c59b0bd80c56450a22d5f438e596a333aa875e291dd43f48cb88b9d5fc0d499f9fcd1c397f9afc070cd9e398c8d19e61db7c7410a6b2675dfbf5d345b804d201add502d5ce2dfcb091ce9997bbebe57306f383e4d588103f036f7e85d1934d152a323e4a8db451d6f4a5b1b0f102cc150e02feee2b88dea4ad4c1baccb24d84072d14e1d24a6771f7408ee30564fb86d4393a34bcf0b788501d193303f13a2284b001f0f649eaf79328d4ac5c430ab4414920a9460ed1b7bc40ec653e876d09abc509ae45b525190116a0c26101848298509c1c3bf3a483e7274054e15e97075036e989f60932807b5257751e79",
+ []testEncryptOAEPMessage{
+ // Example 10.1
+ {
+ []byte{0x8b, 0xba, 0x6b, 0xf8, 0x2a, 0x6c, 0x0f, 0x86,
+ 0xd5, 0xf1, 0x75, 0x6e, 0x97, 0x95, 0x68, 0x70, 0xb0,
+ 0x89, 0x53, 0xb0, 0x6b, 0x4e, 0xb2, 0x05, 0xbc, 0x16,
+ 0x94, 0xee,
+ },
+ []byte{0x47, 0xe1, 0xab, 0x71, 0x19, 0xfe, 0xe5, 0x6c,
+ 0x95, 0xee, 0x5e, 0xaa, 0xd8, 0x6f, 0x40, 0xd0, 0xaa,
+ 0x63, 0xbd, 0x33,
+ },
+ []byte{0x53, 0xea, 0x5d, 0xc0, 0x8c, 0xd2, 0x60, 0xfb,
+ 0x3b, 0x85, 0x85, 0x67, 0x28, 0x7f, 0xa9, 0x15, 0x52,
+ 0xc3, 0x0b, 0x2f, 0xeb, 0xfb, 0xa2, 0x13, 0xf0, 0xae,
+ 0x87, 0x70, 0x2d, 0x06, 0x8d, 0x19, 0xba, 0xb0, 0x7f,
+ 0xe5, 0x74, 0x52, 0x3d, 0xfb, 0x42, 0x13, 0x9d, 0x68,
+ 0xc3, 0xc5, 0xaf, 0xee, 0xe0, 0xbf, 0xe4, 0xcb, 0x79,
+ 0x69, 0xcb, 0xf3, 0x82, 0xb8, 0x04, 0xd6, 0xe6, 0x13,
+ 0x96, 0x14, 0x4e, 0x2d, 0x0e, 0x60, 0x74, 0x1f, 0x89,
+ 0x93, 0xc3, 0x01, 0x4b, 0x58, 0xb9, 0xb1, 0x95, 0x7a,
+ 0x8b, 0xab, 0xcd, 0x23, 0xaf, 0x85, 0x4f, 0x4c, 0x35,
+ 0x6f, 0xb1, 0x66, 0x2a, 0xa7, 0x2b, 0xfc, 0xc7, 0xe5,
+ 0x86, 0x55, 0x9d, 0xc4, 0x28, 0x0d, 0x16, 0x0c, 0x12,
+ 0x67, 0x85, 0xa7, 0x23, 0xeb, 0xee, 0xbe, 0xff, 0x71,
+ 0xf1, 0x15, 0x94, 0x44, 0x0a, 0xae, 0xf8, 0x7d, 0x10,
+ 0x79, 0x3a, 0x87, 0x74, 0xa2, 0x39, 0xd4, 0xa0, 0x4c,
+ 0x87, 0xfe, 0x14, 0x67, 0xb9, 0xda, 0xf8, 0x52, 0x08,
+ 0xec, 0x6c, 0x72, 0x55, 0x79, 0x4a, 0x96, 0xcc, 0x29,
+ 0x14, 0x2f, 0x9a, 0x8b, 0xd4, 0x18, 0xe3, 0xc1, 0xfd,
+ 0x67, 0x34, 0x4b, 0x0c, 0xd0, 0x82, 0x9d, 0xf3, 0xb2,
+ 0xbe, 0xc6, 0x02, 0x53, 0x19, 0x62, 0x93, 0xc6, 0xb3,
+ 0x4d, 0x3f, 0x75, 0xd3, 0x2f, 0x21, 0x3d, 0xd4, 0x5c,
+ 0x62, 0x73, 0xd5, 0x05, 0xad, 0xf4, 0xcc, 0xed, 0x10,
+ 0x57, 0xcb, 0x75, 0x8f, 0xc2, 0x6a, 0xee, 0xfa, 0x44,
+ 0x12, 0x55, 0xed, 0x4e, 0x64, 0xc1, 0x99, 0xee, 0x07,
+ 0x5e, 0x7f, 0x16, 0x64, 0x61, 0x82, 0xfd, 0xb4, 0x64,
+ 0x73, 0x9b, 0x68, 0xab, 0x5d, 0xaf, 0xf0, 0xe6, 0x3e,
+ 0x95, 0x52, 0x01, 0x68, 0x24, 0xf0, 0x54, 0xbf, 0x4d,
+ 0x3c, 0x8c, 0x90, 0xa9, 0x7b, 0xb6, 0xb6, 0x55, 0x32,
+ 0x84, 0xeb, 0x42, 0x9f, 0xcc,
+ },
+ },
+ },
+ },
+}
diff --git a/src/crypto/rsa/testdata/pss-vect.txt.bz2 b/src/crypto/rsa/testdata/pss-vect.txt.bz2
new file mode 100644
index 0000000..ad3da1a
--- /dev/null
+++ b/src/crypto/rsa/testdata/pss-vect.txt.bz2
Binary files differ
diff --git a/src/crypto/sha1/boring.go b/src/crypto/sha1/boring.go
new file mode 100644
index 0000000..b5786d1
--- /dev/null
+++ b/src/crypto/sha1/boring.go
@@ -0,0 +1,25 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Extra indirection here so that when building go_bootstrap
+// cmd/internal/boring is not even imported, so that we don't
+// have to maintain changes to cmd/dist's deps graph.
+
+//go:build !cmd_go_bootstrap && cgo
+// +build !cmd_go_bootstrap,cgo
+
+package sha1
+
+import (
+ "crypto/internal/boring"
+ "hash"
+)
+
+const boringEnabled = boring.Enabled
+
+func boringNewSHA1() hash.Hash { return boring.NewSHA1() }
+
+func boringUnreachable() { boring.Unreachable() }
+
+func boringSHA1(p []byte) [20]byte { return boring.SHA1(p) }
diff --git a/src/crypto/sha1/example_test.go b/src/crypto/sha1/example_test.go
new file mode 100644
index 0000000..499055c
--- /dev/null
+++ b/src/crypto/sha1/example_test.go
@@ -0,0 +1,42 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha1_test
+
+import (
+ "crypto/sha1"
+ "fmt"
+ "io"
+ "log"
+ "os"
+)
+
+func ExampleNew() {
+ h := sha1.New()
+ io.WriteString(h, "His money is twice tainted:")
+ io.WriteString(h, " 'taint yours and 'taint mine.")
+ fmt.Printf("% x", h.Sum(nil))
+ // Output: 59 7f 6a 54 00 10 f9 4c 15 d7 18 06 a9 9a 2c 87 10 e7 47 bd
+}
+
+func ExampleSum() {
+ data := []byte("This page intentionally left blank.")
+ fmt.Printf("% x", sha1.Sum(data))
+ // Output: af 06 49 23 bb f2 30 15 96 aa c4 c2 73 ba 32 17 8e bc 4a 96
+}
+
+func ExampleNew_file() {
+ f, err := os.Open("file.txt")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+
+ h := sha1.New()
+ if _, err := io.Copy(h, f); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("% x", h.Sum(nil))
+}
diff --git a/src/crypto/sha1/fallback_test.go b/src/crypto/sha1/fallback_test.go
new file mode 100644
index 0000000..45d1f57
--- /dev/null
+++ b/src/crypto/sha1/fallback_test.go
@@ -0,0 +1,34 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build s390x
+
+package sha1
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+// Tests the fallback code path in case the optimized asm
+// implementation cannot be used.
+// See also TestBlockGeneric.
+func TestGenericPath(t *testing.T) {
+ if useAsm == false {
+ t.Skipf("assembly implementation unavailable")
+ }
+ useAsm = false
+ defer func() { useAsm = true }()
+ c := New()
+ in := "ΑΒΓΔΕϜΖΗΘΙΚΛΜΝΞΟΠϺϘΡΣΤΥΦΧΨΩ"
+ gold := "0f58c2bb130f8182375f325c18342215255387e5"
+ if _, err := io.WriteString(c, in); err != nil {
+ t.Fatalf("could not write to c: %v", err)
+ }
+ out := fmt.Sprintf("%x", c.Sum(nil))
+ if out != gold {
+ t.Fatalf("mismatch: got %s, wanted %s", out, gold)
+ }
+}
diff --git a/src/crypto/sha1/issue15617_test.go b/src/crypto/sha1/issue15617_test.go
new file mode 100644
index 0000000..116c78f
--- /dev/null
+++ b/src/crypto/sha1/issue15617_test.go
@@ -0,0 +1,27 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build amd64 && (linux || darwin)
+
+package sha1_test
+
+import (
+ "crypto/sha1"
+ "syscall"
+ "testing"
+)
+
+func TestOutOfBoundsRead(t *testing.T) {
+ const pageSize = 4 << 10
+ data, err := syscall.Mmap(0, 0, 2*pageSize, syscall.PROT_READ|syscall.PROT_WRITE, syscall.MAP_ANON|syscall.MAP_PRIVATE)
+ if err != nil {
+ panic(err)
+ }
+ if err := syscall.Mprotect(data[pageSize:], syscall.PROT_NONE); err != nil {
+ panic(err)
+ }
+ for i := 0; i < pageSize; i++ {
+ sha1.Sum(data[pageSize-i : pageSize])
+ }
+}
diff --git a/src/crypto/sha1/notboring.go b/src/crypto/sha1/notboring.go
new file mode 100644
index 0000000..42ef879
--- /dev/null
+++ b/src/crypto/sha1/notboring.go
@@ -0,0 +1,20 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build cmd_go_bootstrap || !cgo
+// +build cmd_go_bootstrap !cgo
+
+package sha1
+
+import (
+ "hash"
+)
+
+const boringEnabled = false
+
+func boringNewSHA1() hash.Hash { panic("boringcrypto: not available") }
+
+func boringUnreachable() {}
+
+func boringSHA1([]byte) [20]byte { panic("boringcrypto: not available") }
diff --git a/src/crypto/sha1/sha1.go b/src/crypto/sha1/sha1.go
new file mode 100644
index 0000000..43ab72a
--- /dev/null
+++ b/src/crypto/sha1/sha1.go
@@ -0,0 +1,264 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sha1 implements the SHA-1 hash algorithm as defined in RFC 3174.
+//
+// SHA-1 is cryptographically broken and should not be used for secure
+// applications.
+package sha1
+
+import (
+ "crypto"
+ "encoding/binary"
+ "errors"
+ "hash"
+)
+
+func init() {
+ crypto.RegisterHash(crypto.SHA1, New)
+}
+
+// The size of a SHA-1 checksum in bytes.
+const Size = 20
+
+// The blocksize of SHA-1 in bytes.
+const BlockSize = 64
+
+const (
+ chunk = 64
+ init0 = 0x67452301
+ init1 = 0xEFCDAB89
+ init2 = 0x98BADCFE
+ init3 = 0x10325476
+ init4 = 0xC3D2E1F0
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ h [5]uint32
+ x [chunk]byte
+ nx int
+ len uint64
+}
+
+const (
+ magic = "sha\x01"
+ marshaledSize = len(magic) + 5*4 + chunk + 8
+)
+
+func (d *digest) MarshalBinary() ([]byte, error) {
+ b := make([]byte, 0, marshaledSize)
+ b = append(b, magic...)
+ b = binary.BigEndian.AppendUint32(b, d.h[0])
+ b = binary.BigEndian.AppendUint32(b, d.h[1])
+ b = binary.BigEndian.AppendUint32(b, d.h[2])
+ b = binary.BigEndian.AppendUint32(b, d.h[3])
+ b = binary.BigEndian.AppendUint32(b, d.h[4])
+ b = append(b, d.x[:d.nx]...)
+ b = b[:len(b)+len(d.x)-d.nx] // already zero
+ b = binary.BigEndian.AppendUint64(b, d.len)
+ return b, nil
+}
+
+func (d *digest) UnmarshalBinary(b []byte) error {
+ if len(b) < len(magic) || string(b[:len(magic)]) != magic {
+ return errors.New("crypto/sha1: invalid hash state identifier")
+ }
+ if len(b) != marshaledSize {
+ return errors.New("crypto/sha1: invalid hash state size")
+ }
+ b = b[len(magic):]
+ b, d.h[0] = consumeUint32(b)
+ b, d.h[1] = consumeUint32(b)
+ b, d.h[2] = consumeUint32(b)
+ b, d.h[3] = consumeUint32(b)
+ b, d.h[4] = consumeUint32(b)
+ b = b[copy(d.x[:], b):]
+ b, d.len = consumeUint64(b)
+ d.nx = int(d.len % chunk)
+ return nil
+}
+
+func consumeUint64(b []byte) ([]byte, uint64) {
+ _ = b[7]
+ x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+ uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+ return b[8:], x
+}
+
+func consumeUint32(b []byte) ([]byte, uint32) {
+ _ = b[3]
+ x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+ return b[4:], x
+}
+
+func (d *digest) Reset() {
+ d.h[0] = init0
+ d.h[1] = init1
+ d.h[2] = init2
+ d.h[3] = init3
+ d.h[4] = init4
+ d.nx = 0
+ d.len = 0
+}
+
+// New returns a new hash.Hash computing the SHA1 checksum. The Hash also
+// implements encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to
+// marshal and unmarshal the internal state of the hash.
+func New() hash.Hash {
+ if boringEnabled {
+ return boringNewSHA1()
+ }
+ d := new(digest)
+ d.Reset()
+ return d
+}
+
+func (d *digest) Size() int { return Size }
+
+func (d *digest) BlockSize() int { return BlockSize }
+
+func (d *digest) Write(p []byte) (nn int, err error) {
+ boringUnreachable()
+ nn = len(p)
+ d.len += uint64(nn)
+ if d.nx > 0 {
+ n := copy(d.x[d.nx:], p)
+ d.nx += n
+ if d.nx == chunk {
+ block(d, d.x[:])
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ if len(p) >= chunk {
+ n := len(p) &^ (chunk - 1)
+ block(d, p[:n])
+ p = p[n:]
+ }
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d *digest) Sum(in []byte) []byte {
+ boringUnreachable()
+ // Make a copy of d so that caller can keep writing and summing.
+ d0 := *d
+ hash := d0.checkSum()
+ return append(in, hash[:]...)
+}
+
+func (d *digest) checkSum() [Size]byte {
+ len := d.len
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ var tmp [64 + 8]byte // padding + length buffer
+ tmp[0] = 0x80
+ var t uint64
+ if len%64 < 56 {
+ t = 56 - len%64
+ } else {
+ t = 64 + 56 - len%64
+ }
+
+ // Length in bits.
+ len <<= 3
+ padlen := tmp[:t+8]
+ binary.BigEndian.PutUint64(padlen[t:], len)
+ d.Write(padlen)
+
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ var digest [Size]byte
+
+ binary.BigEndian.PutUint32(digest[0:], d.h[0])
+ binary.BigEndian.PutUint32(digest[4:], d.h[1])
+ binary.BigEndian.PutUint32(digest[8:], d.h[2])
+ binary.BigEndian.PutUint32(digest[12:], d.h[3])
+ binary.BigEndian.PutUint32(digest[16:], d.h[4])
+
+ return digest
+}
+
+// ConstantTimeSum computes the same result of Sum() but in constant time
+func (d *digest) ConstantTimeSum(in []byte) []byte {
+ d0 := *d
+ hash := d0.constSum()
+ return append(in, hash[:]...)
+}
+
+func (d *digest) constSum() [Size]byte {
+ var length [8]byte
+ l := d.len << 3
+ for i := uint(0); i < 8; i++ {
+ length[i] = byte(l >> (56 - 8*i))
+ }
+
+ nx := byte(d.nx)
+ t := nx - 56 // if nx < 56 then the MSB of t is one
+ mask1b := byte(int8(t) >> 7) // mask1b is 0xFF iff one block is enough
+
+ separator := byte(0x80) // gets reset to 0x00 once used
+ for i := byte(0); i < chunk; i++ {
+ mask := byte(int8(i-nx) >> 7) // 0x00 after the end of data
+
+ // if we reached the end of the data, replace with 0x80 or 0x00
+ d.x[i] = (^mask & separator) | (mask & d.x[i])
+
+ // zero the separator once used
+ separator &= mask
+
+ if i >= 56 {
+ // we might have to write the length here if all fit in one block
+ d.x[i] |= mask1b & length[i-56]
+ }
+ }
+
+ // compress, and only keep the digest if all fit in one block
+ block(d, d.x[:])
+
+ var digest [Size]byte
+ for i, s := range d.h {
+ digest[i*4] = mask1b & byte(s>>24)
+ digest[i*4+1] = mask1b & byte(s>>16)
+ digest[i*4+2] = mask1b & byte(s>>8)
+ digest[i*4+3] = mask1b & byte(s)
+ }
+
+ for i := byte(0); i < chunk; i++ {
+ // second block, it's always past the end of data, might start with 0x80
+ if i < 56 {
+ d.x[i] = separator
+ separator = 0
+ } else {
+ d.x[i] = length[i-56]
+ }
+ }
+
+ // compress, and only keep the digest if we actually needed the second block
+ block(d, d.x[:])
+
+ for i, s := range d.h {
+ digest[i*4] |= ^mask1b & byte(s>>24)
+ digest[i*4+1] |= ^mask1b & byte(s>>16)
+ digest[i*4+2] |= ^mask1b & byte(s>>8)
+ digest[i*4+3] |= ^mask1b & byte(s)
+ }
+
+ return digest
+}
+
+// Sum returns the SHA-1 checksum of the data.
+func Sum(data []byte) [Size]byte {
+ if boringEnabled {
+ return boringSHA1(data)
+ }
+ var d digest
+ d.Reset()
+ d.Write(data)
+ return d.checkSum()
+}
diff --git a/src/crypto/sha1/sha1_test.go b/src/crypto/sha1/sha1_test.go
new file mode 100644
index 0000000..85ed126
--- /dev/null
+++ b/src/crypto/sha1/sha1_test.go
@@ -0,0 +1,274 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA-1 hash algorithm. See RFC 3174.
+
+package sha1
+
+import (
+ "bytes"
+ "crypto/internal/boring"
+ "crypto/rand"
+ "encoding"
+ "fmt"
+ "hash"
+ "io"
+ "testing"
+)
+
+type sha1Test struct {
+ out string
+ in string
+ halfState string // marshaled hash state after first half of in written, used by TestGoldenMarshal
+}
+
+var golden = []sha1Test{
+ {"76245dbf96f661bd221046197ab8b9f063f11bad", "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa\n", "sha\x01\v\xa0)I\xdeq(8h\x9ev\xe5\x88[\xf8\x81\x17\xba4Daaaaaaaaaaaaaaaaaaaaaa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x96"},
+ {"da39a3ee5e6b4b0d3255bfef95601890afd80709", "", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"},
+ {"86f7e437faa5a7fce15d1ddcb9eaeaea377667b8", "a", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"},
+ {"da23614e02469a0d7c7bd1bdab5c9c474b1904dc", "ab", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"},
+ {"a9993e364706816aba3e25717850c26c9cd0d89d", "abc", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"},
+ {"81fe8bfe87576c3ecb22426f8e57847382917acf", "abcd", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"},
+ {"03de6c570bfe24bfc328ccd7ca46b76eadaf4334", "abcde", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"},
+ {"1f8ac10f23c5b5bc1167bda84b833e5c057a77d2", "abcdef", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03"},
+ {"2fb5e13419fc89246865e7a324f476ec624e8740", "abcdefg", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03"},
+ {"425af12a0743502b322e93a015bcf868e324d56a", "abcdefgh", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04"},
+ {"c63b19f1e4c8b5f76b25c49b8b87f57d8e4872a1", "abcdefghi", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04"},
+ {"d68c19a0a345b7eab78d5e11e991c026ec60db63", "abcdefghij", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0abcde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05"},
+ {"ebf81ddcbe5bf13aaabdc4d65354fdf2044f38a7", "Discard medicine more than two years old.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0Discard medicine mor\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14"},
+ {"e5dea09392dd886ca63531aaa00571dc07554bb6", "He who has a shady past knows that nice guys finish last.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0He who has a shady past know\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"},
+ {"45988f7234467b94e3e9494434c96ee3609d8f8f", "I wouldn't marry him with a ten foot pole.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0I wouldn't marry him \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15"},
+ {"55dee037eb7460d5a692d1ce11330b260e40c988", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0Free! Free!/A trip/to Mars/f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"},
+ {"b7bc5fb91080c7de6b582ea281f8a396d7c0aee8", "The days of the digital watch are numbered. -Tom Stoppard", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0The days of the digital watch\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d"},
+ {"c3aed9358f7c77f523afe86135f06b95b3999797", "Nepal premier won't resign.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0Nepal premier\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r"},
+ {"6e29d302bf6e3a5e4305ff318d983197d6906bb9", "For every action there is an equal and opposite government program.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0For every action there is an equa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!"},
+ {"597f6a540010f94c15d71806a99a2c8710e747bd", "His money is twice tainted: 'taint yours and 'taint mine.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0His money is twice tainted: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"},
+ {"6859733b2590a8a091cecf50086febc5ceef1e80", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0There is no reason for any individual to hav\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,"},
+ {"514b2630ec089b8aee18795fc0cf1f4860cdacad", "It's a tiny change to the code and not completely disgusting. - Bob Manchek", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0It's a tiny change to the code and no\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%"},
+ {"c5ca0d4a7b6676fc7aa72caa41cc3d5df567ed69", "size: a.out: bad magic", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0size: a.out\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\f"},
+ {"74c51fa9a04eadc8c1bbeaa7fc442f834b90a00a", "The major problem is with sendmail. -Mark Horton", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0The major problem is wit\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18"},
+ {"0b4c4ce5f52c3ad2821852a8dc00217fa18b8b66", "Give me a rock, paper and scissors and I will move the world. CCFestoon", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0Give me a rock, paper and scissors a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$"},
+ {"3ae7937dd790315beb0f48330e8642237c61550a", "If the enemy is within range, then so are you.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0If the enemy is within \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17"},
+ {"410a2b296df92b9a47412b13281df8f830a9f44b", "It's well we cannot hear the screams/That we create in others' dreams.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0It's well we cannot hear the scream\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#"},
+ {"841e7c85ca1adcddbdd0187f1289acb5c642f7f5", "You remind me of a TV show, but that's all right: I watch it anyway.", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0You remind me of a TV show, but th\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\""},
+ {"163173b825d03b952601376b25212df66763e1db", "C is as portable as Stonehedge!!", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0C is as portable\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10"},
+ {"32b0377f2687eb88e22106f133c586ab314d5279", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0Even if I could be Shakespeare, I think I sh\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,"},
+ {"0885aaf99b569542fd165fa44e322718f4a984e0", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", "sha\x01x}\xf4\r\xeb\xf2\x10\x87\xe8[\xb2JA$D\xb7\u063ax8em\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B"},
+ {"6627d6904d71420b0bf3886ab629623538689f45", "How can you write a big system without C++? -Paul Glick", "sha\x01gE#\x01\xef\u036b\x89\x98\xba\xdc\xfe\x102Tv\xc3\xd2\xe1\xf0How can you write a big syst\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"},
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ s := fmt.Sprintf("%x", Sum([]byte(g.in)))
+ if s != g.out {
+ t.Fatalf("Sum function: sha1(%s) = %s want %s", g.in, s, g.out)
+ }
+ c := New()
+ for j := 0; j < 4; j++ {
+ var sum []byte
+ switch j {
+ case 0, 1:
+ io.WriteString(c, g.in)
+ sum = c.Sum(nil)
+ case 2:
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum(nil)
+ io.WriteString(c, g.in[len(g.in)/2:])
+ sum = c.Sum(nil)
+ case 3:
+ if boring.Enabled {
+ continue
+ }
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.(*digest).ConstantTimeSum(nil)
+ io.WriteString(c, g.in[len(g.in)/2:])
+ sum = c.(*digest).ConstantTimeSum(nil)
+ }
+ s := fmt.Sprintf("%x", sum)
+ if s != g.out {
+ t.Fatalf("sha1[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+}
+
+func TestGoldenMarshal(t *testing.T) {
+ h := New()
+ h2 := New()
+ for _, g := range golden {
+ h.Reset()
+ h2.Reset()
+
+ io.WriteString(h, g.in[:len(g.in)/2])
+
+ state, err := h.(encoding.BinaryMarshaler).MarshalBinary()
+ if err != nil {
+ t.Errorf("could not marshal: %v", err)
+ continue
+ }
+
+ if string(state) != g.halfState {
+ t.Errorf("sha1(%q) state = %+q, want %+q", g.in, state, g.halfState)
+ continue
+ }
+
+ if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err != nil {
+ t.Errorf("could not unmarshal: %v", err)
+ continue
+ }
+
+ io.WriteString(h, g.in[len(g.in)/2:])
+ io.WriteString(h2, g.in[len(g.in)/2:])
+
+ if actual, actual2 := h.Sum(nil), h2.Sum(nil); !bytes.Equal(actual, actual2) {
+ t.Errorf("sha1(%q) = 0x%x != marshaled 0x%x", g.in, actual, actual2)
+ }
+ }
+}
+
+func TestSize(t *testing.T) {
+ c := New()
+ if got := c.Size(); got != Size {
+ t.Errorf("Size = %d; want %d", got, Size)
+ }
+}
+
+func TestBlockSize(t *testing.T) {
+ c := New()
+ if got := c.BlockSize(); got != BlockSize {
+ t.Errorf("BlockSize = %d; want %d", got, BlockSize)
+ }
+}
+
+// Tests that blockGeneric (pure Go) and block (in assembly for some architectures) match.
+func TestBlockGeneric(t *testing.T) {
+ if boring.Enabled {
+ t.Skip("BoringCrypto doesn't expose digest")
+ }
+ for i := 1; i < 30; i++ { // arbitrary factor
+ gen, asm := New().(*digest), New().(*digest)
+ buf := make([]byte, BlockSize*i)
+ rand.Read(buf)
+ blockGeneric(gen, buf)
+ block(asm, buf)
+ if *gen != *asm {
+ t.Errorf("For %#v block and blockGeneric resulted in different states", buf)
+ }
+ }
+}
+
+// Tests for unmarshaling hashes that have hashed a large amount of data
+// The initial hash generation is omitted from the test, because it takes a long time.
+// The test contains some already-generated states, and their expected sums
+// Tests a problem that is outlined in GitHub issue #29543
+// The problem is triggered when an amount of data has been hashed for which
+// the data length has a 1 in the 32nd bit. When casted to int, this changes
+// the sign of the value, and causes the modulus operation to return a
+// different result.
+type unmarshalTest struct {
+ state string
+ sum string
+}
+
+var largeUnmarshalTests = []unmarshalTest{
+ // Data length: 7_102_415_735
+ {
+ state: "sha\x01\x13\xbc\xfe\x83\x8c\xbd\xdfP\x1f\xd8ڿ<\x9eji8t\xe1\xa5@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuv\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xa7VCw",
+ sum: "bc6245c9959cc33e1c2592e5c9ea9b5d0431246c",
+ },
+ // Data length: 6_565_544_823
+ {
+ state: "sha\x01m;\x16\xa6R\xbe@\xa9nĈ\xf9S\x03\x00B\xc2\xdcv\xcf@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuv\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x87VCw",
+ sum: "8f2d1c0e4271768f35feb918bfe21ea1387a2072",
+ },
+}
+
+func safeSum(h hash.Hash) (sum []byte, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = fmt.Errorf("sum panic: %v", r)
+ }
+ }()
+
+ return h.Sum(nil), nil
+}
+
+func TestLargeHashes(t *testing.T) {
+ for i, test := range largeUnmarshalTests {
+
+ h := New()
+ if err := h.(encoding.BinaryUnmarshaler).UnmarshalBinary([]byte(test.state)); err != nil {
+ t.Errorf("test %d could not unmarshal: %v", i, err)
+ continue
+ }
+
+ sum, err := safeSum(h)
+ if err != nil {
+ t.Errorf("test %d could not sum: %v", i, err)
+ continue
+ }
+
+ if fmt.Sprintf("%x", sum) != test.sum {
+ t.Errorf("test %d sum mismatch: expect %s got %x", i, test.sum, sum)
+ }
+ }
+}
+
+func TestAllocations(t *testing.T) {
+ if boring.Enabled {
+ t.Skip("BoringCrypto doesn't allocate the same way as stdlib")
+ }
+ in := []byte("hello, world!")
+ out := make([]byte, 0, Size)
+ h := New()
+ n := int(testing.AllocsPerRun(10, func() {
+ h.Reset()
+ h.Write(in)
+ out = h.Sum(out[:0])
+ }))
+ if n > 0 {
+ t.Errorf("allocs = %d, want 0", n)
+ }
+}
+
+var bench = New()
+var buf = make([]byte, 8192)
+
+func benchmarkSize(b *testing.B, size int) {
+ sum := make([]byte, bench.Size())
+ b.Run("New", func(b *testing.B) {
+ b.ReportAllocs()
+ b.SetBytes(int64(size))
+ for i := 0; i < b.N; i++ {
+ bench.Reset()
+ bench.Write(buf[:size])
+ bench.Sum(sum[:0])
+ }
+ })
+ b.Run("Sum", func(b *testing.B) {
+ b.ReportAllocs()
+ b.SetBytes(int64(size))
+ for i := 0; i < b.N; i++ {
+ Sum(buf[:size])
+ }
+ })
+}
+
+func BenchmarkHash8Bytes(b *testing.B) {
+ benchmarkSize(b, 8)
+}
+
+func BenchmarkHash320Bytes(b *testing.B) {
+ benchmarkSize(b, 320)
+}
+
+func BenchmarkHash1K(b *testing.B) {
+ benchmarkSize(b, 1024)
+}
+
+func BenchmarkHash8K(b *testing.B) {
+ benchmarkSize(b, 8192)
+}
diff --git a/src/crypto/sha1/sha1block.go b/src/crypto/sha1/sha1block.go
new file mode 100644
index 0000000..321d343
--- /dev/null
+++ b/src/crypto/sha1/sha1block.go
@@ -0,0 +1,83 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha1
+
+import (
+ "math/bits"
+)
+
+const (
+ _K0 = 0x5A827999
+ _K1 = 0x6ED9EBA1
+ _K2 = 0x8F1BBCDC
+ _K3 = 0xCA62C1D6
+)
+
+// blockGeneric is a portable, pure Go version of the SHA-1 block step.
+// It's used by sha1block_generic.go and tests.
+func blockGeneric(dig *digest, p []byte) {
+ var w [16]uint32
+
+ h0, h1, h2, h3, h4 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4]
+ for len(p) >= chunk {
+ // Can interlace the computation of w with the
+ // rounds below if needed for speed.
+ for i := 0; i < 16; i++ {
+ j := i * 4
+ w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3])
+ }
+
+ a, b, c, d, e := h0, h1, h2, h3, h4
+
+ // Each of the four 20-iteration rounds
+ // differs only in the computation of f and
+ // the choice of K (_K0, _K1, etc).
+ i := 0
+ for ; i < 16; i++ {
+ f := b&c | (^b)&d
+ t := bits.RotateLeft32(a, 5) + f + e + w[i&0xf] + _K0
+ a, b, c, d, e = t, a, bits.RotateLeft32(b, 30), c, d
+ }
+ for ; i < 20; i++ {
+ tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
+ w[i&0xf] = tmp<<1 | tmp>>(32-1)
+
+ f := b&c | (^b)&d
+ t := bits.RotateLeft32(a, 5) + f + e + w[i&0xf] + _K0
+ a, b, c, d, e = t, a, bits.RotateLeft32(b, 30), c, d
+ }
+ for ; i < 40; i++ {
+ tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
+ w[i&0xf] = tmp<<1 | tmp>>(32-1)
+ f := b ^ c ^ d
+ t := bits.RotateLeft32(a, 5) + f + e + w[i&0xf] + _K1
+ a, b, c, d, e = t, a, bits.RotateLeft32(b, 30), c, d
+ }
+ for ; i < 60; i++ {
+ tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
+ w[i&0xf] = tmp<<1 | tmp>>(32-1)
+ f := ((b | c) & d) | (b & c)
+ t := bits.RotateLeft32(a, 5) + f + e + w[i&0xf] + _K2
+ a, b, c, d, e = t, a, bits.RotateLeft32(b, 30), c, d
+ }
+ for ; i < 80; i++ {
+ tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
+ w[i&0xf] = tmp<<1 | tmp>>(32-1)
+ f := b ^ c ^ d
+ t := bits.RotateLeft32(a, 5) + f + e + w[i&0xf] + _K3
+ a, b, c, d, e = t, a, bits.RotateLeft32(b, 30), c, d
+ }
+
+ h0 += a
+ h1 += b
+ h2 += c
+ h3 += d
+ h4 += e
+
+ p = p[chunk:]
+ }
+
+ dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4] = h0, h1, h2, h3, h4
+}
diff --git a/src/crypto/sha1/sha1block_386.s b/src/crypto/sha1/sha1block_386.s
new file mode 100644
index 0000000..34d023d
--- /dev/null
+++ b/src/crypto/sha1/sha1block_386.s
@@ -0,0 +1,233 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// SHA-1 block routine. See sha1block.go for Go equivalent.
+//
+// There are 80 rounds of 4 types:
+// - rounds 0-15 are type 1 and load data (ROUND1 macro).
+// - rounds 16-19 are type 1 and do not load data (ROUND1x macro).
+// - rounds 20-39 are type 2 and do not load data (ROUND2 macro).
+// - rounds 40-59 are type 3 and do not load data (ROUND3 macro).
+// - rounds 60-79 are type 4 and do not load data (ROUND4 macro).
+//
+// Each round loads or shuffles the data, then computes a per-round
+// function of b, c, d, and then mixes the result into and rotates the
+// five registers a, b, c, d, e holding the intermediate results.
+//
+// The register rotation is implemented by rotating the arguments to
+// the round macros instead of by explicit move instructions.
+
+// Like sha1block_amd64.s, but we keep the data and limit pointers on the stack.
+// To free up the word pointer (R10 on amd64, DI here), we add it to e during
+// LOAD/SHUFFLE instead of during MIX.
+//
+// The stack holds the intermediate word array - 16 uint32s - at 0(SP) up to 64(SP).
+// The saved a, b, c, d, e (R11 through R15 on amd64) are at 64(SP) up to 84(SP).
+// The saved limit pointer (DI on amd64) is at 84(SP).
+// The saved data pointer (SI on amd64) is at 88(SP).
+
+#define LOAD(index, e) \
+ MOVL 88(SP), SI; \
+ MOVL (index*4)(SI), DI; \
+ BSWAPL DI; \
+ MOVL DI, (index*4)(SP); \
+ ADDL DI, e
+
+#define SHUFFLE(index, e) \
+ MOVL (((index)&0xf)*4)(SP), DI; \
+ XORL (((index-3)&0xf)*4)(SP), DI; \
+ XORL (((index-8)&0xf)*4)(SP), DI; \
+ XORL (((index-14)&0xf)*4)(SP), DI; \
+ ROLL $1, DI; \
+ MOVL DI, (((index)&0xf)*4)(SP); \
+ ADDL DI, e
+
+#define FUNC1(a, b, c, d, e) \
+ MOVL d, DI; \
+ XORL c, DI; \
+ ANDL b, DI; \
+ XORL d, DI
+
+#define FUNC2(a, b, c, d, e) \
+ MOVL b, DI; \
+ XORL c, DI; \
+ XORL d, DI
+
+#define FUNC3(a, b, c, d, e) \
+ MOVL b, SI; \
+ ORL c, SI; \
+ ANDL d, SI; \
+ MOVL b, DI; \
+ ANDL c, DI; \
+ ORL SI, DI
+
+#define FUNC4 FUNC2
+
+#define MIX(a, b, c, d, e, const) \
+ ROLL $30, b; \
+ ADDL DI, e; \
+ MOVL a, SI; \
+ ROLL $5, SI; \
+ LEAL const(e)(SI*1), e
+
+#define ROUND1(a, b, c, d, e, index) \
+ LOAD(index, e); \
+ FUNC1(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND1x(a, b, c, d, e, index) \
+ SHUFFLE(index, e); \
+ FUNC1(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND2(a, b, c, d, e, index) \
+ SHUFFLE(index, e); \
+ FUNC2(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x6ED9EBA1)
+
+#define ROUND3(a, b, c, d, e, index) \
+ SHUFFLE(index, e); \
+ FUNC3(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x8F1BBCDC)
+
+#define ROUND4(a, b, c, d, e, index) \
+ SHUFFLE(index, e); \
+ FUNC4(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0xCA62C1D6)
+
+// func block(dig *digest, p []byte)
+TEXT ·block(SB),NOSPLIT,$92-16
+ MOVL dig+0(FP), BP
+ MOVL p+4(FP), SI
+ MOVL p_len+8(FP), DX
+ SHRL $6, DX
+ SHLL $6, DX
+
+ LEAL (SI)(DX*1), DI
+ MOVL (0*4)(BP), AX
+ MOVL (1*4)(BP), BX
+ MOVL (2*4)(BP), CX
+ MOVL (3*4)(BP), DX
+ MOVL (4*4)(BP), BP
+
+ CMPL SI, DI
+ JEQ end
+
+ MOVL DI, 84(SP)
+
+loop:
+ MOVL SI, 88(SP)
+
+ MOVL AX, 64(SP)
+ MOVL BX, 68(SP)
+ MOVL CX, 72(SP)
+ MOVL DX, 76(SP)
+ MOVL BP, 80(SP)
+
+ ROUND1(AX, BX, CX, DX, BP, 0)
+ ROUND1(BP, AX, BX, CX, DX, 1)
+ ROUND1(DX, BP, AX, BX, CX, 2)
+ ROUND1(CX, DX, BP, AX, BX, 3)
+ ROUND1(BX, CX, DX, BP, AX, 4)
+ ROUND1(AX, BX, CX, DX, BP, 5)
+ ROUND1(BP, AX, BX, CX, DX, 6)
+ ROUND1(DX, BP, AX, BX, CX, 7)
+ ROUND1(CX, DX, BP, AX, BX, 8)
+ ROUND1(BX, CX, DX, BP, AX, 9)
+ ROUND1(AX, BX, CX, DX, BP, 10)
+ ROUND1(BP, AX, BX, CX, DX, 11)
+ ROUND1(DX, BP, AX, BX, CX, 12)
+ ROUND1(CX, DX, BP, AX, BX, 13)
+ ROUND1(BX, CX, DX, BP, AX, 14)
+ ROUND1(AX, BX, CX, DX, BP, 15)
+
+ ROUND1x(BP, AX, BX, CX, DX, 16)
+ ROUND1x(DX, BP, AX, BX, CX, 17)
+ ROUND1x(CX, DX, BP, AX, BX, 18)
+ ROUND1x(BX, CX, DX, BP, AX, 19)
+
+ ROUND2(AX, BX, CX, DX, BP, 20)
+ ROUND2(BP, AX, BX, CX, DX, 21)
+ ROUND2(DX, BP, AX, BX, CX, 22)
+ ROUND2(CX, DX, BP, AX, BX, 23)
+ ROUND2(BX, CX, DX, BP, AX, 24)
+ ROUND2(AX, BX, CX, DX, BP, 25)
+ ROUND2(BP, AX, BX, CX, DX, 26)
+ ROUND2(DX, BP, AX, BX, CX, 27)
+ ROUND2(CX, DX, BP, AX, BX, 28)
+ ROUND2(BX, CX, DX, BP, AX, 29)
+ ROUND2(AX, BX, CX, DX, BP, 30)
+ ROUND2(BP, AX, BX, CX, DX, 31)
+ ROUND2(DX, BP, AX, BX, CX, 32)
+ ROUND2(CX, DX, BP, AX, BX, 33)
+ ROUND2(BX, CX, DX, BP, AX, 34)
+ ROUND2(AX, BX, CX, DX, BP, 35)
+ ROUND2(BP, AX, BX, CX, DX, 36)
+ ROUND2(DX, BP, AX, BX, CX, 37)
+ ROUND2(CX, DX, BP, AX, BX, 38)
+ ROUND2(BX, CX, DX, BP, AX, 39)
+
+ ROUND3(AX, BX, CX, DX, BP, 40)
+ ROUND3(BP, AX, BX, CX, DX, 41)
+ ROUND3(DX, BP, AX, BX, CX, 42)
+ ROUND3(CX, DX, BP, AX, BX, 43)
+ ROUND3(BX, CX, DX, BP, AX, 44)
+ ROUND3(AX, BX, CX, DX, BP, 45)
+ ROUND3(BP, AX, BX, CX, DX, 46)
+ ROUND3(DX, BP, AX, BX, CX, 47)
+ ROUND3(CX, DX, BP, AX, BX, 48)
+ ROUND3(BX, CX, DX, BP, AX, 49)
+ ROUND3(AX, BX, CX, DX, BP, 50)
+ ROUND3(BP, AX, BX, CX, DX, 51)
+ ROUND3(DX, BP, AX, BX, CX, 52)
+ ROUND3(CX, DX, BP, AX, BX, 53)
+ ROUND3(BX, CX, DX, BP, AX, 54)
+ ROUND3(AX, BX, CX, DX, BP, 55)
+ ROUND3(BP, AX, BX, CX, DX, 56)
+ ROUND3(DX, BP, AX, BX, CX, 57)
+ ROUND3(CX, DX, BP, AX, BX, 58)
+ ROUND3(BX, CX, DX, BP, AX, 59)
+
+ ROUND4(AX, BX, CX, DX, BP, 60)
+ ROUND4(BP, AX, BX, CX, DX, 61)
+ ROUND4(DX, BP, AX, BX, CX, 62)
+ ROUND4(CX, DX, BP, AX, BX, 63)
+ ROUND4(BX, CX, DX, BP, AX, 64)
+ ROUND4(AX, BX, CX, DX, BP, 65)
+ ROUND4(BP, AX, BX, CX, DX, 66)
+ ROUND4(DX, BP, AX, BX, CX, 67)
+ ROUND4(CX, DX, BP, AX, BX, 68)
+ ROUND4(BX, CX, DX, BP, AX, 69)
+ ROUND4(AX, BX, CX, DX, BP, 70)
+ ROUND4(BP, AX, BX, CX, DX, 71)
+ ROUND4(DX, BP, AX, BX, CX, 72)
+ ROUND4(CX, DX, BP, AX, BX, 73)
+ ROUND4(BX, CX, DX, BP, AX, 74)
+ ROUND4(AX, BX, CX, DX, BP, 75)
+ ROUND4(BP, AX, BX, CX, DX, 76)
+ ROUND4(DX, BP, AX, BX, CX, 77)
+ ROUND4(CX, DX, BP, AX, BX, 78)
+ ROUND4(BX, CX, DX, BP, AX, 79)
+
+ ADDL 64(SP), AX
+ ADDL 68(SP), BX
+ ADDL 72(SP), CX
+ ADDL 76(SP), DX
+ ADDL 80(SP), BP
+
+ MOVL 88(SP), SI
+ ADDL $64, SI
+ CMPL SI, 84(SP)
+ JB loop
+
+end:
+ MOVL dig+0(FP), DI
+ MOVL AX, (0*4)(DI)
+ MOVL BX, (1*4)(DI)
+ MOVL CX, (2*4)(DI)
+ MOVL DX, (3*4)(DI)
+ MOVL BP, (4*4)(DI)
+ RET
diff --git a/src/crypto/sha1/sha1block_amd64.go b/src/crypto/sha1/sha1block_amd64.go
new file mode 100644
index 0000000..039813d
--- /dev/null
+++ b/src/crypto/sha1/sha1block_amd64.go
@@ -0,0 +1,34 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha1
+
+import "internal/cpu"
+
+//go:noescape
+func blockAVX2(dig *digest, p []byte)
+
+//go:noescape
+func blockAMD64(dig *digest, p []byte)
+
+var useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI1 && cpu.X86.HasBMI2
+
+func block(dig *digest, p []byte) {
+ if useAVX2 && len(p) >= 256 {
+ // blockAVX2 calculates sha1 for 2 block per iteration
+ // it also interleaves precalculation for next block.
+ // So it may read up-to 192 bytes past end of p
+ // We may add checks inside blockAVX2, but this will
+ // just turn it into a copy of blockAMD64,
+ // so call it directly, instead.
+ safeLen := len(p) - 128
+ if safeLen%128 != 0 {
+ safeLen -= 64
+ }
+ blockAVX2(dig, p[:safeLen])
+ blockAMD64(dig, p[safeLen:])
+ } else {
+ blockAMD64(dig, p)
+ }
+}
diff --git a/src/crypto/sha1/sha1block_amd64.s b/src/crypto/sha1/sha1block_amd64.s
new file mode 100644
index 0000000..42f03fb
--- /dev/null
+++ b/src/crypto/sha1/sha1block_amd64.s
@@ -0,0 +1,1500 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// AVX2 version by Intel, same algorithm as code in Linux kernel:
+// https://github.com/torvalds/linux/blob/master/arch/x86/crypto/sha1_avx2_x86_64_asm.S
+// Authors:
+// Ilya Albrekht <ilya.albrekht@intel.com>
+// Maxim Locktyukhin <maxim.locktyukhin@intel.com>
+// Ronen Zohar <ronen.zohar@intel.com>
+// Chandramouli Narayanan <mouli@linux.intel.com>
+
+
+#include "textflag.h"
+
+// SHA-1 block routine. See sha1block.go for Go equivalent.
+//
+// There are 80 rounds of 4 types:
+// - rounds 0-15 are type 1 and load data (ROUND1 macro).
+// - rounds 16-19 are type 1 and do not load data (ROUND1x macro).
+// - rounds 20-39 are type 2 and do not load data (ROUND2 macro).
+// - rounds 40-59 are type 3 and do not load data (ROUND3 macro).
+// - rounds 60-79 are type 4 and do not load data (ROUND4 macro).
+//
+// Each round loads or shuffles the data, then computes a per-round
+// function of b, c, d, and then mixes the result into and rotates the
+// five registers a, b, c, d, e holding the intermediate results.
+//
+// The register rotation is implemented by rotating the arguments to
+// the round macros instead of by explicit move instructions.
+
+#define LOAD(index) \
+ MOVL (index*4)(SI), R10; \
+ BSWAPL R10; \
+ MOVL R10, (index*4)(SP)
+
+#define SHUFFLE(index) \
+ MOVL (((index)&0xf)*4)(SP), R10; \
+ XORL (((index-3)&0xf)*4)(SP), R10; \
+ XORL (((index-8)&0xf)*4)(SP), R10; \
+ XORL (((index-14)&0xf)*4)(SP), R10; \
+ ROLL $1, R10; \
+ MOVL R10, (((index)&0xf)*4)(SP)
+
+#define FUNC1(a, b, c, d, e) \
+ MOVL d, R9; \
+ XORL c, R9; \
+ ANDL b, R9; \
+ XORL d, R9
+
+#define FUNC2(a, b, c, d, e) \
+ MOVL b, R9; \
+ XORL c, R9; \
+ XORL d, R9
+
+#define FUNC3(a, b, c, d, e) \
+ MOVL b, R8; \
+ ORL c, R8; \
+ ANDL d, R8; \
+ MOVL b, R9; \
+ ANDL c, R9; \
+ ORL R8, R9
+
+#define FUNC4 FUNC2
+
+#define MIX(a, b, c, d, e, const) \
+ ROLL $30, b; \
+ ADDL R9, e; \
+ MOVL a, R8; \
+ ROLL $5, R8; \
+ LEAL const(e)(R10*1), e; \
+ ADDL R8, e
+
+#define ROUND1(a, b, c, d, e, index) \
+ LOAD(index); \
+ FUNC1(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND1x(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC1(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x5A827999)
+
+#define ROUND2(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC2(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x6ED9EBA1)
+
+#define ROUND3(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC3(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0x8F1BBCDC)
+
+#define ROUND4(a, b, c, d, e, index) \
+ SHUFFLE(index); \
+ FUNC4(a, b, c, d, e); \
+ MIX(a, b, c, d, e, 0xCA62C1D6)
+
+TEXT ·blockAMD64(SB),NOSPLIT,$64-32
+ MOVQ dig+0(FP), BP
+ MOVQ p_base+8(FP), SI
+ MOVQ p_len+16(FP), DX
+ SHRQ $6, DX
+ SHLQ $6, DX
+
+ LEAQ (SI)(DX*1), DI
+ MOVL (0*4)(BP), AX
+ MOVL (1*4)(BP), BX
+ MOVL (2*4)(BP), CX
+ MOVL (3*4)(BP), DX
+ MOVL (4*4)(BP), BP
+
+ CMPQ SI, DI
+ JEQ end
+
+loop:
+ MOVL AX, R11
+ MOVL BX, R12
+ MOVL CX, R13
+ MOVL DX, R14
+ MOVL BP, R15
+
+ ROUND1(AX, BX, CX, DX, BP, 0)
+ ROUND1(BP, AX, BX, CX, DX, 1)
+ ROUND1(DX, BP, AX, BX, CX, 2)
+ ROUND1(CX, DX, BP, AX, BX, 3)
+ ROUND1(BX, CX, DX, BP, AX, 4)
+ ROUND1(AX, BX, CX, DX, BP, 5)
+ ROUND1(BP, AX, BX, CX, DX, 6)
+ ROUND1(DX, BP, AX, BX, CX, 7)
+ ROUND1(CX, DX, BP, AX, BX, 8)
+ ROUND1(BX, CX, DX, BP, AX, 9)
+ ROUND1(AX, BX, CX, DX, BP, 10)
+ ROUND1(BP, AX, BX, CX, DX, 11)
+ ROUND1(DX, BP, AX, BX, CX, 12)
+ ROUND1(CX, DX, BP, AX, BX, 13)
+ ROUND1(BX, CX, DX, BP, AX, 14)
+ ROUND1(AX, BX, CX, DX, BP, 15)
+
+ ROUND1x(BP, AX, BX, CX, DX, 16)
+ ROUND1x(DX, BP, AX, BX, CX, 17)
+ ROUND1x(CX, DX, BP, AX, BX, 18)
+ ROUND1x(BX, CX, DX, BP, AX, 19)
+
+ ROUND2(AX, BX, CX, DX, BP, 20)
+ ROUND2(BP, AX, BX, CX, DX, 21)
+ ROUND2(DX, BP, AX, BX, CX, 22)
+ ROUND2(CX, DX, BP, AX, BX, 23)
+ ROUND2(BX, CX, DX, BP, AX, 24)
+ ROUND2(AX, BX, CX, DX, BP, 25)
+ ROUND2(BP, AX, BX, CX, DX, 26)
+ ROUND2(DX, BP, AX, BX, CX, 27)
+ ROUND2(CX, DX, BP, AX, BX, 28)
+ ROUND2(BX, CX, DX, BP, AX, 29)
+ ROUND2(AX, BX, CX, DX, BP, 30)
+ ROUND2(BP, AX, BX, CX, DX, 31)
+ ROUND2(DX, BP, AX, BX, CX, 32)
+ ROUND2(CX, DX, BP, AX, BX, 33)
+ ROUND2(BX, CX, DX, BP, AX, 34)
+ ROUND2(AX, BX, CX, DX, BP, 35)
+ ROUND2(BP, AX, BX, CX, DX, 36)
+ ROUND2(DX, BP, AX, BX, CX, 37)
+ ROUND2(CX, DX, BP, AX, BX, 38)
+ ROUND2(BX, CX, DX, BP, AX, 39)
+
+ ROUND3(AX, BX, CX, DX, BP, 40)
+ ROUND3(BP, AX, BX, CX, DX, 41)
+ ROUND3(DX, BP, AX, BX, CX, 42)
+ ROUND3(CX, DX, BP, AX, BX, 43)
+ ROUND3(BX, CX, DX, BP, AX, 44)
+ ROUND3(AX, BX, CX, DX, BP, 45)
+ ROUND3(BP, AX, BX, CX, DX, 46)
+ ROUND3(DX, BP, AX, BX, CX, 47)
+ ROUND3(CX, DX, BP, AX, BX, 48)
+ ROUND3(BX, CX, DX, BP, AX, 49)
+ ROUND3(AX, BX, CX, DX, BP, 50)
+ ROUND3(BP, AX, BX, CX, DX, 51)
+ ROUND3(DX, BP, AX, BX, CX, 52)
+ ROUND3(CX, DX, BP, AX, BX, 53)
+ ROUND3(BX, CX, DX, BP, AX, 54)
+ ROUND3(AX, BX, CX, DX, BP, 55)
+ ROUND3(BP, AX, BX, CX, DX, 56)
+ ROUND3(DX, BP, AX, BX, CX, 57)
+ ROUND3(CX, DX, BP, AX, BX, 58)
+ ROUND3(BX, CX, DX, BP, AX, 59)
+
+ ROUND4(AX, BX, CX, DX, BP, 60)
+ ROUND4(BP, AX, BX, CX, DX, 61)
+ ROUND4(DX, BP, AX, BX, CX, 62)
+ ROUND4(CX, DX, BP, AX, BX, 63)
+ ROUND4(BX, CX, DX, BP, AX, 64)
+ ROUND4(AX, BX, CX, DX, BP, 65)
+ ROUND4(BP, AX, BX, CX, DX, 66)
+ ROUND4(DX, BP, AX, BX, CX, 67)
+ ROUND4(CX, DX, BP, AX, BX, 68)
+ ROUND4(BX, CX, DX, BP, AX, 69)
+ ROUND4(AX, BX, CX, DX, BP, 70)
+ ROUND4(BP, AX, BX, CX, DX, 71)
+ ROUND4(DX, BP, AX, BX, CX, 72)
+ ROUND4(CX, DX, BP, AX, BX, 73)
+ ROUND4(BX, CX, DX, BP, AX, 74)
+ ROUND4(AX, BX, CX, DX, BP, 75)
+ ROUND4(BP, AX, BX, CX, DX, 76)
+ ROUND4(DX, BP, AX, BX, CX, 77)
+ ROUND4(CX, DX, BP, AX, BX, 78)
+ ROUND4(BX, CX, DX, BP, AX, 79)
+
+ ADDL R11, AX
+ ADDL R12, BX
+ ADDL R13, CX
+ ADDL R14, DX
+ ADDL R15, BP
+
+ ADDQ $64, SI
+ CMPQ SI, DI
+ JB loop
+
+end:
+ MOVQ dig+0(FP), DI
+ MOVL AX, (0*4)(DI)
+ MOVL BX, (1*4)(DI)
+ MOVL CX, (2*4)(DI)
+ MOVL DX, (3*4)(DI)
+ MOVL BP, (4*4)(DI)
+ RET
+
+
+// This is the implementation using AVX2, BMI1 and BMI2. It is based on:
+// "SHA-1 implementation with Intel(R) AVX2 instruction set extensions"
+// From http://software.intel.com/en-us/articles
+// (look for improving-the-performance-of-the-secure-hash-algorithm-1)
+// This implementation is 2x unrolled, and interleaves vector instructions,
+// used to precompute W, with scalar computation of current round
+// for optimal scheduling.
+
+// Trivial helper macros.
+#define UPDATE_HASH(A,TB,C,D,E) \
+ ADDL (R9), A \
+ MOVL A, (R9) \
+ ADDL 4(R9), TB \
+ MOVL TB, 4(R9) \
+ ADDL 8(R9), C \
+ MOVL C, 8(R9) \
+ ADDL 12(R9), D \
+ MOVL D, 12(R9) \
+ ADDL 16(R9), E \
+ MOVL E, 16(R9)
+
+
+
+// Helper macros for PRECALC, which does precomputations
+#define PRECALC_0(OFFSET) \
+ VMOVDQU OFFSET(R10),X0
+
+#define PRECALC_1(OFFSET) \
+ VINSERTI128 $1, OFFSET(R13), Y0, Y0
+
+#define PRECALC_2(YREG) \
+ VPSHUFB Y10, Y0, YREG
+
+#define PRECALC_4(YREG,K_OFFSET) \
+ VPADDD K_OFFSET(R8), YREG, Y0
+
+#define PRECALC_7(OFFSET) \
+ VMOVDQU Y0, (OFFSET*2)(R14)
+
+
+// Message scheduling pre-compute for rounds 0-15
+// R13 is a pointer to even 64-byte block
+// R10 is a pointer to odd 64-byte block
+// R14 is a pointer to temp buffer
+// X0 is used as temp register
+// YREG is clobbered as part of computation
+// OFFSET chooses 16 byte chunk within a block
+// R8 is a pointer to constants block
+// K_OFFSET chooses K constants relevant to this round
+// X10 holds swap mask
+#define PRECALC_00_15(OFFSET,YREG) \
+ PRECALC_0(OFFSET) \
+ PRECALC_1(OFFSET) \
+ PRECALC_2(YREG) \
+ PRECALC_4(YREG,0x0) \
+ PRECALC_7(OFFSET)
+
+
+// Helper macros for PRECALC_16_31
+#define PRECALC_16(REG_SUB_16,REG_SUB_12,REG_SUB_4,REG) \
+ VPALIGNR $8, REG_SUB_16, REG_SUB_12, REG \ // w[i-14]
+ VPSRLDQ $4, REG_SUB_4, Y0 // w[i-3]
+
+#define PRECALC_17(REG_SUB_16,REG_SUB_8,REG) \
+ VPXOR REG_SUB_8, REG, REG \
+ VPXOR REG_SUB_16, Y0, Y0
+
+#define PRECALC_18(REG) \
+ VPXOR Y0, REG, REG \
+ VPSLLDQ $12, REG, Y9
+
+#define PRECALC_19(REG) \
+ VPSLLD $1, REG, Y0 \
+ VPSRLD $31, REG, REG
+
+#define PRECALC_20(REG) \
+ VPOR REG, Y0, Y0 \
+ VPSLLD $2, Y9, REG
+
+#define PRECALC_21(REG) \
+ VPSRLD $30, Y9, Y9 \
+ VPXOR REG, Y0, Y0
+
+#define PRECALC_23(REG,K_OFFSET,OFFSET) \
+ VPXOR Y9, Y0, REG \
+ VPADDD K_OFFSET(R8), REG, Y0 \
+ VMOVDQU Y0, (OFFSET)(R14)
+
+// Message scheduling pre-compute for rounds 16-31
+// calculating last 32 w[i] values in 8 XMM registers
+// pre-calculate K+w[i] values and store to mem
+// for later load by ALU add instruction.
+// "brute force" vectorization for rounds 16-31 only
+// due to w[i]->w[i-3] dependency.
+// clobbers 5 input ymm registers REG_SUB*
+// uses X0 and X9 as temp registers
+// As always, R8 is a pointer to constants block
+// and R14 is a pointer to temp buffer
+#define PRECALC_16_31(REG,REG_SUB_4,REG_SUB_8,REG_SUB_12,REG_SUB_16,K_OFFSET,OFFSET) \
+ PRECALC_16(REG_SUB_16,REG_SUB_12,REG_SUB_4,REG) \
+ PRECALC_17(REG_SUB_16,REG_SUB_8,REG) \
+ PRECALC_18(REG) \
+ PRECALC_19(REG) \
+ PRECALC_20(REG) \
+ PRECALC_21(REG) \
+ PRECALC_23(REG,K_OFFSET,OFFSET)
+
+
+// Helper macros for PRECALC_32_79
+#define PRECALC_32(REG_SUB_8,REG_SUB_4) \
+ VPALIGNR $8, REG_SUB_8, REG_SUB_4, Y0
+
+#define PRECALC_33(REG_SUB_28,REG) \
+ VPXOR REG_SUB_28, REG, REG
+
+#define PRECALC_34(REG_SUB_16) \
+ VPXOR REG_SUB_16, Y0, Y0
+
+#define PRECALC_35(REG) \
+ VPXOR Y0, REG, REG
+
+#define PRECALC_36(REG) \
+ VPSLLD $2, REG, Y0
+
+#define PRECALC_37(REG) \
+ VPSRLD $30, REG, REG \
+ VPOR REG, Y0, REG
+
+#define PRECALC_39(REG,K_OFFSET,OFFSET) \
+ VPADDD K_OFFSET(R8), REG, Y0 \
+ VMOVDQU Y0, (OFFSET)(R14)
+
+// Message scheduling pre-compute for rounds 32-79
+// In SHA-1 specification we have:
+// w[i] = (w[i-3] ^ w[i-8] ^ w[i-14] ^ w[i-16]) rol 1
+// Which is the same as:
+// w[i] = (w[i-6] ^ w[i-16] ^ w[i-28] ^ w[i-32]) rol 2
+// This allows for more efficient vectorization,
+// since w[i]->w[i-3] dependency is broken
+#define PRECALC_32_79(REG,REG_SUB_4,REG_SUB_8,REG_SUB_16,REG_SUB_28,K_OFFSET,OFFSET) \
+ PRECALC_32(REG_SUB_8,REG_SUB_4) \
+ PRECALC_33(REG_SUB_28,REG) \
+ PRECALC_34(REG_SUB_16) \
+ PRECALC_35(REG) \
+ PRECALC_36(REG) \
+ PRECALC_37(REG) \
+ PRECALC_39(REG,K_OFFSET,OFFSET)
+
+#define PRECALC \
+ PRECALC_00_15(0,Y15) \
+ PRECALC_00_15(0x10,Y14) \
+ PRECALC_00_15(0x20,Y13) \
+ PRECALC_00_15(0x30,Y12) \
+ PRECALC_16_31(Y8,Y12,Y13,Y14,Y15,0,0x80) \
+ PRECALC_16_31(Y7,Y8,Y12,Y13,Y14,0x20,0xa0) \
+ PRECALC_16_31(Y5,Y7,Y8,Y12,Y13,0x20,0xc0) \
+ PRECALC_16_31(Y3,Y5,Y7,Y8,Y12,0x20,0xe0) \
+ PRECALC_32_79(Y15,Y3,Y5,Y8,Y14,0x20,0x100) \
+ PRECALC_32_79(Y14,Y15,Y3,Y7,Y13,0x20,0x120) \
+ PRECALC_32_79(Y13,Y14,Y15,Y5,Y12,0x40,0x140) \
+ PRECALC_32_79(Y12,Y13,Y14,Y3,Y8,0x40,0x160) \
+ PRECALC_32_79(Y8,Y12,Y13,Y15,Y7,0x40,0x180) \
+ PRECALC_32_79(Y7,Y8,Y12,Y14,Y5,0x40,0x1a0) \
+ PRECALC_32_79(Y5,Y7,Y8,Y13,Y3,0x40,0x1c0) \
+ PRECALC_32_79(Y3,Y5,Y7,Y12,Y15,0x60,0x1e0) \
+ PRECALC_32_79(Y15,Y3,Y5,Y8,Y14,0x60,0x200) \
+ PRECALC_32_79(Y14,Y15,Y3,Y7,Y13,0x60,0x220) \
+ PRECALC_32_79(Y13,Y14,Y15,Y5,Y12,0x60,0x240) \
+ PRECALC_32_79(Y12,Y13,Y14,Y3,Y8,0x60,0x260)
+
+// Macros calculating individual rounds have general form
+// CALC_ROUND_PRE + PRECALC_ROUND + CALC_ROUND_POST
+// CALC_ROUND_{PRE,POST} macros follow
+
+#define CALC_F1_PRE(OFFSET,REG_A,REG_B,REG_C,REG_E) \
+ ADDL OFFSET(R15),REG_E \
+ ANDNL REG_C,REG_A,BP \
+ LEAL (REG_E)(REG_B*1), REG_E \ // Add F from the previous round
+ RORXL $0x1b, REG_A, R12 \
+ RORXL $2, REG_A, REG_B // for next round
+
+// Calculate F for the next round
+#define CALC_F1_POST(REG_A,REG_B,REG_E) \
+ ANDL REG_B,REG_A \ // b&c
+ XORL BP, REG_A \ // F1 = (b&c) ^ (~b&d)
+ LEAL (REG_E)(R12*1), REG_E // E += A >>> 5
+
+
+// Registers are cyclically rotated DX -> AX -> DI -> SI -> BX -> CX
+#define CALC_0 \
+ MOVL SI, BX \ // Precalculating first round
+ RORXL $2, SI, SI \
+ ANDNL AX, BX, BP \
+ ANDL DI, BX \
+ XORL BP, BX \
+ CALC_F1_PRE(0x0,CX,BX,DI,DX) \
+ PRECALC_0(0x80) \
+ CALC_F1_POST(CX,SI,DX)
+
+#define CALC_1 \
+ CALC_F1_PRE(0x4,DX,CX,SI,AX) \
+ PRECALC_1(0x80) \
+ CALC_F1_POST(DX,BX,AX)
+
+#define CALC_2 \
+ CALC_F1_PRE(0x8,AX,DX,BX,DI) \
+ PRECALC_2(Y15) \
+ CALC_F1_POST(AX,CX,DI)
+
+#define CALC_3 \
+ CALC_F1_PRE(0xc,DI,AX,CX,SI) \
+ CALC_F1_POST(DI,DX,SI)
+
+#define CALC_4 \
+ CALC_F1_PRE(0x20,SI,DI,DX,BX) \
+ PRECALC_4(Y15,0x0) \
+ CALC_F1_POST(SI,AX,BX)
+
+#define CALC_5 \
+ CALC_F1_PRE(0x24,BX,SI,AX,CX) \
+ CALC_F1_POST(BX,DI,CX)
+
+#define CALC_6 \
+ CALC_F1_PRE(0x28,CX,BX,DI,DX) \
+ CALC_F1_POST(CX,SI,DX)
+
+#define CALC_7 \
+ CALC_F1_PRE(0x2c,DX,CX,SI,AX) \
+ PRECALC_7(0x0) \
+ CALC_F1_POST(DX,BX,AX)
+
+#define CALC_8 \
+ CALC_F1_PRE(0x40,AX,DX,BX,DI) \
+ PRECALC_0(0x90) \
+ CALC_F1_POST(AX,CX,DI)
+
+#define CALC_9 \
+ CALC_F1_PRE(0x44,DI,AX,CX,SI) \
+ PRECALC_1(0x90) \
+ CALC_F1_POST(DI,DX,SI)
+
+#define CALC_10 \
+ CALC_F1_PRE(0x48,SI,DI,DX,BX) \
+ PRECALC_2(Y14) \
+ CALC_F1_POST(SI,AX,BX)
+
+#define CALC_11 \
+ CALC_F1_PRE(0x4c,BX,SI,AX,CX) \
+ CALC_F1_POST(BX,DI,CX)
+
+#define CALC_12 \
+ CALC_F1_PRE(0x60,CX,BX,DI,DX) \
+ PRECALC_4(Y14,0x0) \
+ CALC_F1_POST(CX,SI,DX)
+
+#define CALC_13 \
+ CALC_F1_PRE(0x64,DX,CX,SI,AX) \
+ CALC_F1_POST(DX,BX,AX)
+
+#define CALC_14 \
+ CALC_F1_PRE(0x68,AX,DX,BX,DI) \
+ CALC_F1_POST(AX,CX,DI)
+
+#define CALC_15 \
+ CALC_F1_PRE(0x6c,DI,AX,CX,SI) \
+ PRECALC_7(0x10) \
+ CALC_F1_POST(DI,DX,SI)
+
+#define CALC_16 \
+ CALC_F1_PRE(0x80,SI,DI,DX,BX) \
+ PRECALC_0(0xa0) \
+ CALC_F1_POST(SI,AX,BX)
+
+#define CALC_17 \
+ CALC_F1_PRE(0x84,BX,SI,AX,CX) \
+ PRECALC_1(0xa0) \
+ CALC_F1_POST(BX,DI,CX)
+
+#define CALC_18 \
+ CALC_F1_PRE(0x88,CX,BX,DI,DX) \
+ PRECALC_2(Y13) \
+ CALC_F1_POST(CX,SI,DX)
+
+
+#define CALC_F2_PRE(OFFSET,REG_A,REG_B,REG_E) \
+ ADDL OFFSET(R15),REG_E \
+ LEAL (REG_E)(REG_B*1), REG_E \ // Add F from the previous round
+ RORXL $0x1b, REG_A, R12 \
+ RORXL $2, REG_A, REG_B // for next round
+
+#define CALC_F2_POST(REG_A,REG_B,REG_C,REG_E) \
+ XORL REG_B, REG_A \
+ ADDL R12, REG_E \
+ XORL REG_C, REG_A
+
+#define CALC_19 \
+ CALC_F2_PRE(0x8c,DX,CX,AX) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_20 \
+ CALC_F2_PRE(0xa0,AX,DX,DI) \
+ PRECALC_4(Y13,0x0) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_21 \
+ CALC_F2_PRE(0xa4,DI,AX,SI) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_22 \
+ CALC_F2_PRE(0xa8,SI,DI,BX) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_23 \
+ CALC_F2_PRE(0xac,BX,SI,CX) \
+ PRECALC_7(0x20) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_24 \
+ CALC_F2_PRE(0xc0,CX,BX,DX) \
+ PRECALC_0(0xb0) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_25 \
+ CALC_F2_PRE(0xc4,DX,CX,AX) \
+ PRECALC_1(0xb0) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_26 \
+ CALC_F2_PRE(0xc8,AX,DX,DI) \
+ PRECALC_2(Y12) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_27 \
+ CALC_F2_PRE(0xcc,DI,AX,SI) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_28 \
+ CALC_F2_PRE(0xe0,SI,DI,BX) \
+ PRECALC_4(Y12,0x0) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_29 \
+ CALC_F2_PRE(0xe4,BX,SI,CX) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_30 \
+ CALC_F2_PRE(0xe8,CX,BX,DX) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_31 \
+ CALC_F2_PRE(0xec,DX,CX,AX) \
+ PRECALC_7(0x30) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_32 \
+ CALC_F2_PRE(0x100,AX,DX,DI) \
+ PRECALC_16(Y15,Y14,Y12,Y8) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_33 \
+ CALC_F2_PRE(0x104,DI,AX,SI) \
+ PRECALC_17(Y15,Y13,Y8) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_34 \
+ CALC_F2_PRE(0x108,SI,DI,BX) \
+ PRECALC_18(Y8) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_35 \
+ CALC_F2_PRE(0x10c,BX,SI,CX) \
+ PRECALC_19(Y8) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_36 \
+ CALC_F2_PRE(0x120,CX,BX,DX) \
+ PRECALC_20(Y8) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_37 \
+ CALC_F2_PRE(0x124,DX,CX,AX) \
+ PRECALC_21(Y8) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_38 \
+ CALC_F2_PRE(0x128,AX,DX,DI) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+
+#define CALC_F3_PRE(OFFSET,REG_E) \
+ ADDL OFFSET(R15),REG_E
+
+#define CALC_F3_POST(REG_A,REG_B,REG_C,REG_E,REG_TB) \
+ LEAL (REG_E)(REG_TB*1), REG_E \ // Add F from the previous round
+ MOVL REG_B, BP \
+ ORL REG_A, BP \
+ RORXL $0x1b, REG_A, R12 \
+ RORXL $2, REG_A, REG_TB \
+ ANDL REG_C, BP \ // Calculate F for the next round
+ ANDL REG_B, REG_A \
+ ORL BP, REG_A \
+ ADDL R12, REG_E
+
+#define CALC_39 \
+ CALC_F3_PRE(0x12c,SI) \
+ PRECALC_23(Y8,0x0,0x80) \
+ CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_40 \
+ CALC_F3_PRE(0x140,BX) \
+ PRECALC_16(Y14,Y13,Y8,Y7) \
+ CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_41 \
+ CALC_F3_PRE(0x144,CX) \
+ PRECALC_17(Y14,Y12,Y7) \
+ CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_42 \
+ CALC_F3_PRE(0x148,DX) \
+ PRECALC_18(Y7) \
+ CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_43 \
+ CALC_F3_PRE(0x14c,AX) \
+ PRECALC_19(Y7) \
+ CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_44 \
+ CALC_F3_PRE(0x160,DI) \
+ PRECALC_20(Y7) \
+ CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_45 \
+ CALC_F3_PRE(0x164,SI) \
+ PRECALC_21(Y7) \
+ CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_46 \
+ CALC_F3_PRE(0x168,BX) \
+ CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_47 \
+ CALC_F3_PRE(0x16c,CX) \
+ VPXOR Y9, Y0, Y7 \
+ VPADDD 0x20(R8), Y7, Y0 \
+ VMOVDQU Y0, 0xa0(R14) \
+ CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_48 \
+ CALC_F3_PRE(0x180,DX) \
+ PRECALC_16(Y13,Y12,Y7,Y5) \
+ CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_49 \
+ CALC_F3_PRE(0x184,AX) \
+ PRECALC_17(Y13,Y8,Y5) \
+ CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_50 \
+ CALC_F3_PRE(0x188,DI) \
+ PRECALC_18(Y5) \
+ CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_51 \
+ CALC_F3_PRE(0x18c,SI) \
+ PRECALC_19(Y5) \
+ CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_52 \
+ CALC_F3_PRE(0x1a0,BX) \
+ PRECALC_20(Y5) \
+ CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_53 \
+ CALC_F3_PRE(0x1a4,CX) \
+ PRECALC_21(Y5) \
+ CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_54 \
+ CALC_F3_PRE(0x1a8,DX) \
+ CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_55 \
+ CALC_F3_PRE(0x1ac,AX) \
+ PRECALC_23(Y5,0x20,0xc0) \
+ CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_56 \
+ CALC_F3_PRE(0x1c0,DI) \
+ PRECALC_16(Y12,Y8,Y5,Y3) \
+ CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_57 \
+ CALC_F3_PRE(0x1c4,SI) \
+ PRECALC_17(Y12,Y7,Y3) \
+ CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_58 \
+ CALC_F3_PRE(0x1c8,BX) \
+ PRECALC_18(Y3) \
+ CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_59 \
+ CALC_F2_PRE(0x1cc,BX,SI,CX) \
+ PRECALC_19(Y3) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_60 \
+ CALC_F2_PRE(0x1e0,CX,BX,DX) \
+ PRECALC_20(Y3) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_61 \
+ CALC_F2_PRE(0x1e4,DX,CX,AX) \
+ PRECALC_21(Y3) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_62 \
+ CALC_F2_PRE(0x1e8,AX,DX,DI) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_63 \
+ CALC_F2_PRE(0x1ec,DI,AX,SI) \
+ PRECALC_23(Y3,0x20,0xe0) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_64 \
+ CALC_F2_PRE(0x200,SI,DI,BX) \
+ PRECALC_32(Y5,Y3) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_65 \
+ CALC_F2_PRE(0x204,BX,SI,CX) \
+ PRECALC_33(Y14,Y15) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_66 \
+ CALC_F2_PRE(0x208,CX,BX,DX) \
+ PRECALC_34(Y8) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_67 \
+ CALC_F2_PRE(0x20c,DX,CX,AX) \
+ PRECALC_35(Y15) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_68 \
+ CALC_F2_PRE(0x220,AX,DX,DI) \
+ PRECALC_36(Y15) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_69 \
+ CALC_F2_PRE(0x224,DI,AX,SI) \
+ PRECALC_37(Y15) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_70 \
+ CALC_F2_PRE(0x228,SI,DI,BX) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_71 \
+ CALC_F2_PRE(0x22c,BX,SI,CX) \
+ PRECALC_39(Y15,0x20,0x100) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_72 \
+ CALC_F2_PRE(0x240,CX,BX,DX) \
+ PRECALC_32(Y3,Y15) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_73 \
+ CALC_F2_PRE(0x244,DX,CX,AX) \
+ PRECALC_33(Y13,Y14) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_74 \
+ CALC_F2_PRE(0x248,AX,DX,DI) \
+ PRECALC_34(Y7) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_75 \
+ CALC_F2_PRE(0x24c,DI,AX,SI) \
+ PRECALC_35(Y14) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_76 \
+ CALC_F2_PRE(0x260,SI,DI,BX) \
+ PRECALC_36(Y14) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_77 \
+ CALC_F2_PRE(0x264,BX,SI,CX) \
+ PRECALC_37(Y14) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_78 \
+ CALC_F2_PRE(0x268,CX,BX,DX) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_79 \
+ ADDL 0x26c(R15), AX \
+ LEAL (AX)(CX*1), AX \
+ RORXL $0x1b, DX, R12 \
+ PRECALC_39(Y14,0x20,0x120) \
+ ADDL R12, AX
+
+// Similar to CALC_0
+#define CALC_80 \
+ MOVL CX, DX \
+ RORXL $2, CX, CX \
+ ANDNL SI, DX, BP \
+ ANDL BX, DX \
+ XORL BP, DX \
+ CALC_F1_PRE(0x10,AX,DX,BX,DI) \
+ PRECALC_32(Y15,Y14) \
+ CALC_F1_POST(AX,CX,DI)
+
+#define CALC_81 \
+ CALC_F1_PRE(0x14,DI,AX,CX,SI) \
+ PRECALC_33(Y12,Y13) \
+ CALC_F1_POST(DI,DX,SI)
+
+#define CALC_82 \
+ CALC_F1_PRE(0x18,SI,DI,DX,BX) \
+ PRECALC_34(Y5) \
+ CALC_F1_POST(SI,AX,BX)
+
+#define CALC_83 \
+ CALC_F1_PRE(0x1c,BX,SI,AX,CX) \
+ PRECALC_35(Y13) \
+ CALC_F1_POST(BX,DI,CX)
+
+#define CALC_84 \
+ CALC_F1_PRE(0x30,CX,BX,DI,DX) \
+ PRECALC_36(Y13) \
+ CALC_F1_POST(CX,SI,DX)
+
+#define CALC_85 \
+ CALC_F1_PRE(0x34,DX,CX,SI,AX) \
+ PRECALC_37(Y13) \
+ CALC_F1_POST(DX,BX,AX)
+
+#define CALC_86 \
+ CALC_F1_PRE(0x38,AX,DX,BX,DI) \
+ CALC_F1_POST(AX,CX,DI)
+
+#define CALC_87 \
+ CALC_F1_PRE(0x3c,DI,AX,CX,SI) \
+ PRECALC_39(Y13,0x40,0x140) \
+ CALC_F1_POST(DI,DX,SI)
+
+#define CALC_88 \
+ CALC_F1_PRE(0x50,SI,DI,DX,BX) \
+ PRECALC_32(Y14,Y13) \
+ CALC_F1_POST(SI,AX,BX)
+
+#define CALC_89 \
+ CALC_F1_PRE(0x54,BX,SI,AX,CX) \
+ PRECALC_33(Y8,Y12) \
+ CALC_F1_POST(BX,DI,CX)
+
+#define CALC_90 \
+ CALC_F1_PRE(0x58,CX,BX,DI,DX) \
+ PRECALC_34(Y3) \
+ CALC_F1_POST(CX,SI,DX)
+
+#define CALC_91 \
+ CALC_F1_PRE(0x5c,DX,CX,SI,AX) \
+ PRECALC_35(Y12) \
+ CALC_F1_POST(DX,BX,AX)
+
+#define CALC_92 \
+ CALC_F1_PRE(0x70,AX,DX,BX,DI) \
+ PRECALC_36(Y12) \
+ CALC_F1_POST(AX,CX,DI)
+
+#define CALC_93 \
+ CALC_F1_PRE(0x74,DI,AX,CX,SI) \
+ PRECALC_37(Y12) \
+ CALC_F1_POST(DI,DX,SI)
+
+#define CALC_94 \
+ CALC_F1_PRE(0x78,SI,DI,DX,BX) \
+ CALC_F1_POST(SI,AX,BX)
+
+#define CALC_95 \
+ CALC_F1_PRE(0x7c,BX,SI,AX,CX) \
+ PRECALC_39(Y12,0x40,0x160) \
+ CALC_F1_POST(BX,DI,CX)
+
+#define CALC_96 \
+ CALC_F1_PRE(0x90,CX,BX,DI,DX) \
+ PRECALC_32(Y13,Y12) \
+ CALC_F1_POST(CX,SI,DX)
+
+#define CALC_97 \
+ CALC_F1_PRE(0x94,DX,CX,SI,AX) \
+ PRECALC_33(Y7,Y8) \
+ CALC_F1_POST(DX,BX,AX)
+
+#define CALC_98 \
+ CALC_F1_PRE(0x98,AX,DX,BX,DI) \
+ PRECALC_34(Y15) \
+ CALC_F1_POST(AX,CX,DI)
+
+#define CALC_99 \
+ CALC_F2_PRE(0x9c,DI,AX,SI) \
+ PRECALC_35(Y8) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_100 \
+ CALC_F2_PRE(0xb0,SI,DI,BX) \
+ PRECALC_36(Y8) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_101 \
+ CALC_F2_PRE(0xb4,BX,SI,CX) \
+ PRECALC_37(Y8) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_102 \
+ CALC_F2_PRE(0xb8,CX,BX,DX) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_103 \
+ CALC_F2_PRE(0xbc,DX,CX,AX) \
+ PRECALC_39(Y8,0x40,0x180) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_104 \
+ CALC_F2_PRE(0xd0,AX,DX,DI) \
+ PRECALC_32(Y12,Y8) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_105 \
+ CALC_F2_PRE(0xd4,DI,AX,SI) \
+ PRECALC_33(Y5,Y7) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_106 \
+ CALC_F2_PRE(0xd8,SI,DI,BX) \
+ PRECALC_34(Y14) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_107 \
+ CALC_F2_PRE(0xdc,BX,SI,CX) \
+ PRECALC_35(Y7) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_108 \
+ CALC_F2_PRE(0xf0,CX,BX,DX) \
+ PRECALC_36(Y7) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_109 \
+ CALC_F2_PRE(0xf4,DX,CX,AX) \
+ PRECALC_37(Y7) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_110 \
+ CALC_F2_PRE(0xf8,AX,DX,DI) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_111 \
+ CALC_F2_PRE(0xfc,DI,AX,SI) \
+ PRECALC_39(Y7,0x40,0x1a0) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_112 \
+ CALC_F2_PRE(0x110,SI,DI,BX) \
+ PRECALC_32(Y8,Y7) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_113 \
+ CALC_F2_PRE(0x114,BX,SI,CX) \
+ PRECALC_33(Y3,Y5) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_114 \
+ CALC_F2_PRE(0x118,CX,BX,DX) \
+ PRECALC_34(Y13) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_115 \
+ CALC_F2_PRE(0x11c,DX,CX,AX) \
+ PRECALC_35(Y5) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_116 \
+ CALC_F2_PRE(0x130,AX,DX,DI) \
+ PRECALC_36(Y5) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_117 \
+ CALC_F2_PRE(0x134,DI,AX,SI) \
+ PRECALC_37(Y5) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_118 \
+ CALC_F2_PRE(0x138,SI,DI,BX) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_119 \
+ CALC_F3_PRE(0x13c,CX) \
+ PRECALC_39(Y5,0x40,0x1c0) \
+ CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_120 \
+ CALC_F3_PRE(0x150,DX) \
+ PRECALC_32(Y7,Y5) \
+ CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_121 \
+ CALC_F3_PRE(0x154,AX) \
+ PRECALC_33(Y15,Y3) \
+ CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_122 \
+ CALC_F3_PRE(0x158,DI) \
+ PRECALC_34(Y12) \
+ CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_123 \
+ CALC_F3_PRE(0x15c,SI) \
+ PRECALC_35(Y3) \
+ CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_124 \
+ CALC_F3_PRE(0x170,BX) \
+ PRECALC_36(Y3) \
+ CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_125 \
+ CALC_F3_PRE(0x174,CX) \
+ PRECALC_37(Y3) \
+ CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_126 \
+ CALC_F3_PRE(0x178,DX) \
+ CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_127 \
+ CALC_F3_PRE(0x17c,AX) \
+ PRECALC_39(Y3,0x60,0x1e0) \
+ CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_128 \
+ CALC_F3_PRE(0x190,DI) \
+ PRECALC_32(Y5,Y3) \
+ CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_129 \
+ CALC_F3_PRE(0x194,SI) \
+ PRECALC_33(Y14,Y15) \
+ CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_130 \
+ CALC_F3_PRE(0x198,BX) \
+ PRECALC_34(Y8) \
+ CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_131 \
+ CALC_F3_PRE(0x19c,CX) \
+ PRECALC_35(Y15) \
+ CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_132 \
+ CALC_F3_PRE(0x1b0,DX) \
+ PRECALC_36(Y15) \
+ CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_133 \
+ CALC_F3_PRE(0x1b4,AX) \
+ PRECALC_37(Y15) \
+ CALC_F3_POST(DX,BX,SI,AX,CX)
+
+#define CALC_134 \
+ CALC_F3_PRE(0x1b8,DI) \
+ CALC_F3_POST(AX,CX,BX,DI,DX)
+
+#define CALC_135 \
+ CALC_F3_PRE(0x1bc,SI) \
+ PRECALC_39(Y15,0x60,0x200) \
+ CALC_F3_POST(DI,DX,CX,SI,AX)
+
+#define CALC_136 \
+ CALC_F3_PRE(0x1d0,BX) \
+ PRECALC_32(Y3,Y15) \
+ CALC_F3_POST(SI,AX,DX,BX,DI)
+
+#define CALC_137 \
+ CALC_F3_PRE(0x1d4,CX) \
+ PRECALC_33(Y13,Y14) \
+ CALC_F3_POST(BX,DI,AX,CX,SI)
+
+#define CALC_138 \
+ CALC_F3_PRE(0x1d8,DX) \
+ PRECALC_34(Y7) \
+ CALC_F3_POST(CX,SI,DI,DX,BX)
+
+#define CALC_139 \
+ CALC_F2_PRE(0x1dc,DX,CX,AX) \
+ PRECALC_35(Y14) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_140 \
+ CALC_F2_PRE(0x1f0,AX,DX,DI) \
+ PRECALC_36(Y14) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_141 \
+ CALC_F2_PRE(0x1f4,DI,AX,SI) \
+ PRECALC_37(Y14) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_142 \
+ CALC_F2_PRE(0x1f8,SI,DI,BX) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_143 \
+ CALC_F2_PRE(0x1fc,BX,SI,CX) \
+ PRECALC_39(Y14,0x60,0x220) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_144 \
+ CALC_F2_PRE(0x210,CX,BX,DX) \
+ PRECALC_32(Y15,Y14) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_145 \
+ CALC_F2_PRE(0x214,DX,CX,AX) \
+ PRECALC_33(Y12,Y13) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_146 \
+ CALC_F2_PRE(0x218,AX,DX,DI) \
+ PRECALC_34(Y5) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_147 \
+ CALC_F2_PRE(0x21c,DI,AX,SI) \
+ PRECALC_35(Y13) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_148 \
+ CALC_F2_PRE(0x230,SI,DI,BX) \
+ PRECALC_36(Y13) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_149 \
+ CALC_F2_PRE(0x234,BX,SI,CX) \
+ PRECALC_37(Y13) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_150 \
+ CALC_F2_PRE(0x238,CX,BX,DX) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_151 \
+ CALC_F2_PRE(0x23c,DX,CX,AX) \
+ PRECALC_39(Y13,0x60,0x240) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_152 \
+ CALC_F2_PRE(0x250,AX,DX,DI) \
+ PRECALC_32(Y14,Y13) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_153 \
+ CALC_F2_PRE(0x254,DI,AX,SI) \
+ PRECALC_33(Y8,Y12) \
+ CALC_F2_POST(DI,DX,CX,SI)
+
+#define CALC_154 \
+ CALC_F2_PRE(0x258,SI,DI,BX) \
+ PRECALC_34(Y3) \
+ CALC_F2_POST(SI,AX,DX,BX)
+
+#define CALC_155 \
+ CALC_F2_PRE(0x25c,BX,SI,CX) \
+ PRECALC_35(Y12) \
+ CALC_F2_POST(BX,DI,AX,CX)
+
+#define CALC_156 \
+ CALC_F2_PRE(0x270,CX,BX,DX) \
+ PRECALC_36(Y12) \
+ CALC_F2_POST(CX,SI,DI,DX)
+
+#define CALC_157 \
+ CALC_F2_PRE(0x274,DX,CX,AX) \
+ PRECALC_37(Y12) \
+ CALC_F2_POST(DX,BX,SI,AX)
+
+#define CALC_158 \
+ CALC_F2_PRE(0x278,AX,DX,DI) \
+ CALC_F2_POST(AX,CX,BX,DI)
+
+#define CALC_159 \
+ ADDL 0x27c(R15),SI \
+ LEAL (SI)(AX*1), SI \
+ RORXL $0x1b, DI, R12 \
+ PRECALC_39(Y12,0x60,0x260) \
+ ADDL R12, SI
+
+
+
+#define CALC \
+ MOVL (R9), CX \
+ MOVL 4(R9), SI \
+ MOVL 8(R9), DI \
+ MOVL 12(R9), AX \
+ MOVL 16(R9), DX \
+ MOVQ SP, R14 \
+ LEAQ (2*4*80+32)(SP), R15 \
+ PRECALC \ // Precalc WK for first 2 blocks
+ XCHGQ R15, R14 \
+loop: \ // this loops is unrolled
+ CMPQ R10, R8 \ // we use R8 value (set below) as a signal of a last block
+ JNE begin \
+ VZEROUPPER \
+ RET \
+begin: \
+ CALC_0 \
+ CALC_1 \
+ CALC_2 \
+ CALC_3 \
+ CALC_4 \
+ CALC_5 \
+ CALC_6 \
+ CALC_7 \
+ CALC_8 \
+ CALC_9 \
+ CALC_10 \
+ CALC_11 \
+ CALC_12 \
+ CALC_13 \
+ CALC_14 \
+ CALC_15 \
+ CALC_16 \
+ CALC_17 \
+ CALC_18 \
+ CALC_19 \
+ CALC_20 \
+ CALC_21 \
+ CALC_22 \
+ CALC_23 \
+ CALC_24 \
+ CALC_25 \
+ CALC_26 \
+ CALC_27 \
+ CALC_28 \
+ CALC_29 \
+ CALC_30 \
+ CALC_31 \
+ CALC_32 \
+ CALC_33 \
+ CALC_34 \
+ CALC_35 \
+ CALC_36 \
+ CALC_37 \
+ CALC_38 \
+ CALC_39 \
+ CALC_40 \
+ CALC_41 \
+ CALC_42 \
+ CALC_43 \
+ CALC_44 \
+ CALC_45 \
+ CALC_46 \
+ CALC_47 \
+ CALC_48 \
+ CALC_49 \
+ CALC_50 \
+ CALC_51 \
+ CALC_52 \
+ CALC_53 \
+ CALC_54 \
+ CALC_55 \
+ CALC_56 \
+ CALC_57 \
+ CALC_58 \
+ CALC_59 \
+ ADDQ $128, R10 \ // move to next even-64-byte block
+ CMPQ R10, R11 \ // is current block the last one?
+ CMOVQCC R8, R10 \ // signal the last iteration smartly
+ CALC_60 \
+ CALC_61 \
+ CALC_62 \
+ CALC_63 \
+ CALC_64 \
+ CALC_65 \
+ CALC_66 \
+ CALC_67 \
+ CALC_68 \
+ CALC_69 \
+ CALC_70 \
+ CALC_71 \
+ CALC_72 \
+ CALC_73 \
+ CALC_74 \
+ CALC_75 \
+ CALC_76 \
+ CALC_77 \
+ CALC_78 \
+ CALC_79 \
+ UPDATE_HASH(AX,DX,BX,SI,DI) \
+ CMPQ R10, R8 \ // is current block the last one?
+ JE loop\
+ MOVL DX, CX \
+ CALC_80 \
+ CALC_81 \
+ CALC_82 \
+ CALC_83 \
+ CALC_84 \
+ CALC_85 \
+ CALC_86 \
+ CALC_87 \
+ CALC_88 \
+ CALC_89 \
+ CALC_90 \
+ CALC_91 \
+ CALC_92 \
+ CALC_93 \
+ CALC_94 \
+ CALC_95 \
+ CALC_96 \
+ CALC_97 \
+ CALC_98 \
+ CALC_99 \
+ CALC_100 \
+ CALC_101 \
+ CALC_102 \
+ CALC_103 \
+ CALC_104 \
+ CALC_105 \
+ CALC_106 \
+ CALC_107 \
+ CALC_108 \
+ CALC_109 \
+ CALC_110 \
+ CALC_111 \
+ CALC_112 \
+ CALC_113 \
+ CALC_114 \
+ CALC_115 \
+ CALC_116 \
+ CALC_117 \
+ CALC_118 \
+ CALC_119 \
+ CALC_120 \
+ CALC_121 \
+ CALC_122 \
+ CALC_123 \
+ CALC_124 \
+ CALC_125 \
+ CALC_126 \
+ CALC_127 \
+ CALC_128 \
+ CALC_129 \
+ CALC_130 \
+ CALC_131 \
+ CALC_132 \
+ CALC_133 \
+ CALC_134 \
+ CALC_135 \
+ CALC_136 \
+ CALC_137 \
+ CALC_138 \
+ CALC_139 \
+ ADDQ $128, R13 \ //move to next even-64-byte block
+ CMPQ R13, R11 \ //is current block the last one?
+ CMOVQCC R8, R10 \
+ CALC_140 \
+ CALC_141 \
+ CALC_142 \
+ CALC_143 \
+ CALC_144 \
+ CALC_145 \
+ CALC_146 \
+ CALC_147 \
+ CALC_148 \
+ CALC_149 \
+ CALC_150 \
+ CALC_151 \
+ CALC_152 \
+ CALC_153 \
+ CALC_154 \
+ CALC_155 \
+ CALC_156 \
+ CALC_157 \
+ CALC_158 \
+ CALC_159 \
+ UPDATE_HASH(SI,DI,DX,CX,BX) \
+ MOVL SI, R12 \ //Reset state for AVX2 reg permutation
+ MOVL DI, SI \
+ MOVL DX, DI \
+ MOVL BX, DX \
+ MOVL CX, AX \
+ MOVL R12, CX \
+ XCHGQ R15, R14 \
+ JMP loop
+
+
+
+TEXT ·blockAVX2(SB),$1408-32
+
+ MOVQ dig+0(FP), DI
+ MOVQ p_base+8(FP), SI
+ MOVQ p_len+16(FP), DX
+ SHRQ $6, DX
+ SHLQ $6, DX
+
+ MOVQ $K_XMM_AR<>(SB), R8
+
+ MOVQ DI, R9
+ MOVQ SI, R10
+ LEAQ 64(SI), R13
+
+ ADDQ SI, DX
+ ADDQ $64, DX
+ MOVQ DX, R11
+
+ CMPQ R13, R11
+ CMOVQCC R8, R13
+
+ VMOVDQU BSWAP_SHUFB_CTL<>(SB), Y10
+
+ CALC // RET is inside macros
+
+DATA K_XMM_AR<>+0x00(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x04(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x08(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x0c(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x10(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x14(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x18(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x1c(SB)/4,$0x5a827999
+DATA K_XMM_AR<>+0x20(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x24(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x28(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x2c(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x30(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x34(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x38(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x3c(SB)/4,$0x6ed9eba1
+DATA K_XMM_AR<>+0x40(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x44(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x48(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x4c(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x50(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x54(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x58(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x5c(SB)/4,$0x8f1bbcdc
+DATA K_XMM_AR<>+0x60(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x64(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x68(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x6c(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x70(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x74(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x78(SB)/4,$0xca62c1d6
+DATA K_XMM_AR<>+0x7c(SB)/4,$0xca62c1d6
+GLOBL K_XMM_AR<>(SB),RODATA,$128
+
+DATA BSWAP_SHUFB_CTL<>+0x00(SB)/4,$0x00010203
+DATA BSWAP_SHUFB_CTL<>+0x04(SB)/4,$0x04050607
+DATA BSWAP_SHUFB_CTL<>+0x08(SB)/4,$0x08090a0b
+DATA BSWAP_SHUFB_CTL<>+0x0c(SB)/4,$0x0c0d0e0f
+DATA BSWAP_SHUFB_CTL<>+0x10(SB)/4,$0x00010203
+DATA BSWAP_SHUFB_CTL<>+0x14(SB)/4,$0x04050607
+DATA BSWAP_SHUFB_CTL<>+0x18(SB)/4,$0x08090a0b
+DATA BSWAP_SHUFB_CTL<>+0x1c(SB)/4,$0x0c0d0e0f
+GLOBL BSWAP_SHUFB_CTL<>(SB),RODATA,$32
diff --git a/src/crypto/sha1/sha1block_arm.s b/src/crypto/sha1/sha1block_arm.s
new file mode 100644
index 0000000..2236533
--- /dev/null
+++ b/src/crypto/sha1/sha1block_arm.s
@@ -0,0 +1,217 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+//
+// ARM version of md5block.go
+
+#include "textflag.h"
+
+// SHA-1 block routine. See sha1block.go for Go equivalent.
+//
+// There are 80 rounds of 4 types:
+// - rounds 0-15 are type 1 and load data (ROUND1 macro).
+// - rounds 16-19 are type 1 and do not load data (ROUND1x macro).
+// - rounds 20-39 are type 2 and do not load data (ROUND2 macro).
+// - rounds 40-59 are type 3 and do not load data (ROUND3 macro).
+// - rounds 60-79 are type 4 and do not load data (ROUND4 macro).
+//
+// Each round loads or shuffles the data, then computes a per-round
+// function of b, c, d, and then mixes the result into and rotates the
+// five registers a, b, c, d, e holding the intermediate results.
+//
+// The register rotation is implemented by rotating the arguments to
+// the round macros instead of by explicit move instructions.
+
+// Register definitions
+#define Rdata R0 // Pointer to incoming data
+#define Rconst R1 // Current constant for SHA round
+#define Ra R2 // SHA-1 accumulator
+#define Rb R3 // SHA-1 accumulator
+#define Rc R4 // SHA-1 accumulator
+#define Rd R5 // SHA-1 accumulator
+#define Re R6 // SHA-1 accumulator
+#define Rt0 R7 // Temporary
+#define Rt1 R8 // Temporary
+// r9, r10 are forbidden
+// r11 is OK provided you check the assembler that no synthetic instructions use it
+#define Rt2 R11 // Temporary
+#define Rctr R12 // loop counter
+#define Rw R14 // point to w buffer
+
+// func block(dig *digest, p []byte)
+// 0(FP) is *digest
+// 4(FP) is p.array (struct Slice)
+// 8(FP) is p.len
+//12(FP) is p.cap
+//
+// Stack frame
+#define p_end end-4(SP) // pointer to the end of data
+#define p_data data-8(SP) // current data pointer (unused?)
+#define w_buf buf-(8+4*80)(SP) //80 words temporary buffer w uint32[80]
+#define saved abcde-(8+4*80+4*5)(SP) // saved sha1 registers a,b,c,d,e - these must be last (unused?)
+// Total size +4 for saved LR is 352
+
+ // w[i] = p[j]<<24 | p[j+1]<<16 | p[j+2]<<8 | p[j+3]
+ // e += w[i]
+#define LOAD(Re) \
+ MOVBU 2(Rdata), Rt0 ; \
+ MOVBU 3(Rdata), Rt1 ; \
+ MOVBU 1(Rdata), Rt2 ; \
+ ORR Rt0<<8, Rt1, Rt0 ; \
+ MOVBU.P 4(Rdata), Rt1 ; \
+ ORR Rt2<<16, Rt0, Rt0 ; \
+ ORR Rt1<<24, Rt0, Rt0 ; \
+ MOVW.P Rt0, 4(Rw) ; \
+ ADD Rt0, Re, Re
+
+ // tmp := w[(i-3)&0xf] ^ w[(i-8)&0xf] ^ w[(i-14)&0xf] ^ w[(i)&0xf]
+ // w[i&0xf] = tmp<<1 | tmp>>(32-1)
+ // e += w[i&0xf]
+#define SHUFFLE(Re) \
+ MOVW (-16*4)(Rw), Rt0 ; \
+ MOVW (-14*4)(Rw), Rt1 ; \
+ MOVW (-8*4)(Rw), Rt2 ; \
+ EOR Rt0, Rt1, Rt0 ; \
+ MOVW (-3*4)(Rw), Rt1 ; \
+ EOR Rt2, Rt0, Rt0 ; \
+ EOR Rt0, Rt1, Rt0 ; \
+ MOVW Rt0@>(32-1), Rt0 ; \
+ MOVW.P Rt0, 4(Rw) ; \
+ ADD Rt0, Re, Re
+
+ // t1 = (b & c) | ((~b) & d)
+#define FUNC1(Ra, Rb, Rc, Rd, Re) \
+ MVN Rb, Rt1 ; \
+ AND Rb, Rc, Rt0 ; \
+ AND Rd, Rt1, Rt1 ; \
+ ORR Rt0, Rt1, Rt1
+
+ // t1 = b ^ c ^ d
+#define FUNC2(Ra, Rb, Rc, Rd, Re) \
+ EOR Rb, Rc, Rt1 ; \
+ EOR Rd, Rt1, Rt1
+
+ // t1 = (b & c) | (b & d) | (c & d) =
+ // t1 = (b & c) | ((b | c) & d)
+#define FUNC3(Ra, Rb, Rc, Rd, Re) \
+ ORR Rb, Rc, Rt0 ; \
+ AND Rb, Rc, Rt1 ; \
+ AND Rd, Rt0, Rt0 ; \
+ ORR Rt0, Rt1, Rt1
+
+#define FUNC4 FUNC2
+
+ // a5 := a<<5 | a>>(32-5)
+ // b = b<<30 | b>>(32-30)
+ // e = a5 + t1 + e + const
+#define MIX(Ra, Rb, Rc, Rd, Re) \
+ ADD Rt1, Re, Re ; \
+ MOVW Rb@>(32-30), Rb ; \
+ ADD Ra@>(32-5), Re, Re ; \
+ ADD Rconst, Re, Re
+
+#define ROUND1(Ra, Rb, Rc, Rd, Re) \
+ LOAD(Re) ; \
+ FUNC1(Ra, Rb, Rc, Rd, Re) ; \
+ MIX(Ra, Rb, Rc, Rd, Re)
+
+#define ROUND1x(Ra, Rb, Rc, Rd, Re) \
+ SHUFFLE(Re) ; \
+ FUNC1(Ra, Rb, Rc, Rd, Re) ; \
+ MIX(Ra, Rb, Rc, Rd, Re)
+
+#define ROUND2(Ra, Rb, Rc, Rd, Re) \
+ SHUFFLE(Re) ; \
+ FUNC2(Ra, Rb, Rc, Rd, Re) ; \
+ MIX(Ra, Rb, Rc, Rd, Re)
+
+#define ROUND3(Ra, Rb, Rc, Rd, Re) \
+ SHUFFLE(Re) ; \
+ FUNC3(Ra, Rb, Rc, Rd, Re) ; \
+ MIX(Ra, Rb, Rc, Rd, Re)
+
+#define ROUND4(Ra, Rb, Rc, Rd, Re) \
+ SHUFFLE(Re) ; \
+ FUNC4(Ra, Rb, Rc, Rd, Re) ; \
+ MIX(Ra, Rb, Rc, Rd, Re)
+
+
+// func block(dig *digest, p []byte)
+TEXT ·block(SB), 0, $352-16
+ MOVW p+4(FP), Rdata // pointer to the data
+ MOVW p_len+8(FP), Rt0 // number of bytes
+ ADD Rdata, Rt0
+ MOVW Rt0, p_end // pointer to end of data
+
+ // Load up initial SHA-1 accumulator
+ MOVW dig+0(FP), Rt0
+ MOVM.IA (Rt0), [Ra,Rb,Rc,Rd,Re]
+
+loop:
+ // Save registers at SP+4 onwards
+ MOVM.IB [Ra,Rb,Rc,Rd,Re], (R13)
+
+ MOVW $w_buf, Rw
+ MOVW $0x5A827999, Rconst
+ MOVW $3, Rctr
+loop1: ROUND1(Ra, Rb, Rc, Rd, Re)
+ ROUND1(Re, Ra, Rb, Rc, Rd)
+ ROUND1(Rd, Re, Ra, Rb, Rc)
+ ROUND1(Rc, Rd, Re, Ra, Rb)
+ ROUND1(Rb, Rc, Rd, Re, Ra)
+ SUB.S $1, Rctr
+ BNE loop1
+
+ ROUND1(Ra, Rb, Rc, Rd, Re)
+ ROUND1x(Re, Ra, Rb, Rc, Rd)
+ ROUND1x(Rd, Re, Ra, Rb, Rc)
+ ROUND1x(Rc, Rd, Re, Ra, Rb)
+ ROUND1x(Rb, Rc, Rd, Re, Ra)
+
+ MOVW $0x6ED9EBA1, Rconst
+ MOVW $4, Rctr
+loop2: ROUND2(Ra, Rb, Rc, Rd, Re)
+ ROUND2(Re, Ra, Rb, Rc, Rd)
+ ROUND2(Rd, Re, Ra, Rb, Rc)
+ ROUND2(Rc, Rd, Re, Ra, Rb)
+ ROUND2(Rb, Rc, Rd, Re, Ra)
+ SUB.S $1, Rctr
+ BNE loop2
+
+ MOVW $0x8F1BBCDC, Rconst
+ MOVW $4, Rctr
+loop3: ROUND3(Ra, Rb, Rc, Rd, Re)
+ ROUND3(Re, Ra, Rb, Rc, Rd)
+ ROUND3(Rd, Re, Ra, Rb, Rc)
+ ROUND3(Rc, Rd, Re, Ra, Rb)
+ ROUND3(Rb, Rc, Rd, Re, Ra)
+ SUB.S $1, Rctr
+ BNE loop3
+
+ MOVW $0xCA62C1D6, Rconst
+ MOVW $4, Rctr
+loop4: ROUND4(Ra, Rb, Rc, Rd, Re)
+ ROUND4(Re, Ra, Rb, Rc, Rd)
+ ROUND4(Rd, Re, Ra, Rb, Rc)
+ ROUND4(Rc, Rd, Re, Ra, Rb)
+ ROUND4(Rb, Rc, Rd, Re, Ra)
+ SUB.S $1, Rctr
+ BNE loop4
+
+ // Accumulate - restoring registers from SP+4
+ MOVM.IB (R13), [Rt0,Rt1,Rt2,Rctr,Rw]
+ ADD Rt0, Ra
+ ADD Rt1, Rb
+ ADD Rt2, Rc
+ ADD Rctr, Rd
+ ADD Rw, Re
+
+ MOVW p_end, Rt0
+ CMP Rt0, Rdata
+ BLO loop
+
+ // Save final SHA-1 accumulator
+ MOVW dig+0(FP), Rt0
+ MOVM.IA [Ra,Rb,Rc,Rd,Re], (Rt0)
+
+ RET
diff --git a/src/crypto/sha1/sha1block_arm64.go b/src/crypto/sha1/sha1block_arm64.go
new file mode 100644
index 0000000..08d3df0
--- /dev/null
+++ b/src/crypto/sha1/sha1block_arm64.go
@@ -0,0 +1,26 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha1
+
+import "internal/cpu"
+
+var k = []uint32{
+ 0x5A827999,
+ 0x6ED9EBA1,
+ 0x8F1BBCDC,
+ 0xCA62C1D6,
+}
+
+//go:noescape
+func sha1block(h []uint32, p []byte, k []uint32)
+
+func block(dig *digest, p []byte) {
+ if !cpu.ARM64.HasSHA1 {
+ blockGeneric(dig, p)
+ } else {
+ h := dig.h[:]
+ sha1block(h, p, k)
+ }
+}
diff --git a/src/crypto/sha1/sha1block_arm64.s b/src/crypto/sha1/sha1block_arm64.s
new file mode 100644
index 0000000..d568384
--- /dev/null
+++ b/src/crypto/sha1/sha1block_arm64.s
@@ -0,0 +1,152 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+#define HASHUPDATECHOOSE \
+ SHA1C V16.S4, V1, V2 \
+ SHA1H V3, V1 \
+ VMOV V2.B16, V3.B16
+
+#define HASHUPDATEPARITY \
+ SHA1P V16.S4, V1, V2 \
+ SHA1H V3, V1 \
+ VMOV V2.B16, V3.B16
+
+#define HASHUPDATEMAJ \
+ SHA1M V16.S4, V1, V2 \
+ SHA1H V3, V1 \
+ VMOV V2.B16, V3.B16
+
+// func sha1block(h []uint32, p []byte, k []uint32)
+TEXT ·sha1block(SB),NOSPLIT,$0
+ MOVD h_base+0(FP), R0 // hash value first address
+ MOVD p_base+24(FP), R1 // message first address
+ MOVD k_base+48(FP), R2 // k constants first address
+ MOVD p_len+32(FP), R3 // message length
+ VLD1.P 16(R0), [V0.S4]
+ FMOVS (R0), F20
+ SUB $16, R0, R0
+
+blockloop:
+
+ VLD1.P 16(R1), [V4.B16] // load message
+ VLD1.P 16(R1), [V5.B16]
+ VLD1.P 16(R1), [V6.B16]
+ VLD1.P 16(R1), [V7.B16]
+ VLD1 (R2), [V19.S4] // load constant k0-k79
+ VMOV V0.B16, V2.B16
+ VMOV V20.S[0], V1
+ VMOV V2.B16, V3.B16
+ VDUP V19.S[0], V17.S4
+ VREV32 V4.B16, V4.B16 // prepare for using message in Byte format
+ VREV32 V5.B16, V5.B16
+ VREV32 V6.B16, V6.B16
+ VREV32 V7.B16, V7.B16
+
+
+ VDUP V19.S[1], V18.S4
+ VADD V17.S4, V4.S4, V16.S4
+ SHA1SU0 V6.S4, V5.S4, V4.S4
+ HASHUPDATECHOOSE
+ SHA1SU1 V7.S4, V4.S4
+
+ VADD V17.S4, V5.S4, V16.S4
+ SHA1SU0 V7.S4, V6.S4, V5.S4
+ HASHUPDATECHOOSE
+ SHA1SU1 V4.S4, V5.S4
+ VADD V17.S4, V6.S4, V16.S4
+ SHA1SU0 V4.S4, V7.S4, V6.S4
+ HASHUPDATECHOOSE
+ SHA1SU1 V5.S4, V6.S4
+
+ VADD V17.S4, V7.S4, V16.S4
+ SHA1SU0 V5.S4, V4.S4, V7.S4
+ HASHUPDATECHOOSE
+ SHA1SU1 V6.S4, V7.S4
+
+ VADD V17.S4, V4.S4, V16.S4
+ SHA1SU0 V6.S4, V5.S4, V4.S4
+ HASHUPDATECHOOSE
+ SHA1SU1 V7.S4, V4.S4
+
+ VDUP V19.S[2], V17.S4
+ VADD V18.S4, V5.S4, V16.S4
+ SHA1SU0 V7.S4, V6.S4, V5.S4
+ HASHUPDATEPARITY
+ SHA1SU1 V4.S4, V5.S4
+
+ VADD V18.S4, V6.S4, V16.S4
+ SHA1SU0 V4.S4, V7.S4, V6.S4
+ HASHUPDATEPARITY
+ SHA1SU1 V5.S4, V6.S4
+
+ VADD V18.S4, V7.S4, V16.S4
+ SHA1SU0 V5.S4, V4.S4, V7.S4
+ HASHUPDATEPARITY
+ SHA1SU1 V6.S4, V7.S4
+
+ VADD V18.S4, V4.S4, V16.S4
+ SHA1SU0 V6.S4, V5.S4, V4.S4
+ HASHUPDATEPARITY
+ SHA1SU1 V7.S4, V4.S4
+
+ VADD V18.S4, V5.S4, V16.S4
+ SHA1SU0 V7.S4, V6.S4, V5.S4
+ HASHUPDATEPARITY
+ SHA1SU1 V4.S4, V5.S4
+
+ VDUP V19.S[3], V18.S4
+ VADD V17.S4, V6.S4, V16.S4
+ SHA1SU0 V4.S4, V7.S4, V6.S4
+ HASHUPDATEMAJ
+ SHA1SU1 V5.S4, V6.S4
+
+ VADD V17.S4, V7.S4, V16.S4
+ SHA1SU0 V5.S4, V4.S4, V7.S4
+ HASHUPDATEMAJ
+ SHA1SU1 V6.S4, V7.S4
+
+ VADD V17.S4, V4.S4, V16.S4
+ SHA1SU0 V6.S4, V5.S4, V4.S4
+ HASHUPDATEMAJ
+ SHA1SU1 V7.S4, V4.S4
+
+ VADD V17.S4, V5.S4, V16.S4
+ SHA1SU0 V7.S4, V6.S4, V5.S4
+ HASHUPDATEMAJ
+ SHA1SU1 V4.S4, V5.S4
+
+ VADD V17.S4, V6.S4, V16.S4
+ SHA1SU0 V4.S4, V7.S4, V6.S4
+ HASHUPDATEMAJ
+ SHA1SU1 V5.S4, V6.S4
+
+ VADD V18.S4, V7.S4, V16.S4
+ SHA1SU0 V5.S4, V4.S4, V7.S4
+ HASHUPDATEPARITY
+ SHA1SU1 V6.S4, V7.S4
+
+ VADD V18.S4, V4.S4, V16.S4
+ HASHUPDATEPARITY
+
+ VADD V18.S4, V5.S4, V16.S4
+ HASHUPDATEPARITY
+
+ VADD V18.S4, V6.S4, V16.S4
+ HASHUPDATEPARITY
+
+ VADD V18.S4, V7.S4, V16.S4
+ HASHUPDATEPARITY
+
+ SUB $64, R3, R3 // message length - 64bytes, then compare with 64bytes
+ VADD V2.S4, V0.S4, V0.S4
+ VADD V1.S4, V20.S4, V20.S4
+ CBNZ R3, blockloop
+
+sha1ret:
+
+ VST1.P [V0.S4], 16(R0) // store hash value H(dcba)
+ FMOVS F20, (R0) // store hash value H(e)
+ RET
diff --git a/src/crypto/sha1/sha1block_decl.go b/src/crypto/sha1/sha1block_decl.go
new file mode 100644
index 0000000..518a4b6
--- /dev/null
+++ b/src/crypto/sha1/sha1block_decl.go
@@ -0,0 +1,11 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build arm || 386 || s390x
+
+package sha1
+
+//go:noescape
+
+func block(dig *digest, p []byte)
diff --git a/src/crypto/sha1/sha1block_generic.go b/src/crypto/sha1/sha1block_generic.go
new file mode 100644
index 0000000..ba35155
--- /dev/null
+++ b/src/crypto/sha1/sha1block_generic.go
@@ -0,0 +1,11 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !amd64 && !386 && !arm && !s390x && !arm64
+
+package sha1
+
+func block(dig *digest, p []byte) {
+ blockGeneric(dig, p)
+}
diff --git a/src/crypto/sha1/sha1block_s390x.go b/src/crypto/sha1/sha1block_s390x.go
new file mode 100644
index 0000000..446bf5d
--- /dev/null
+++ b/src/crypto/sha1/sha1block_s390x.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha1
+
+import "internal/cpu"
+
+var useAsm = cpu.S390X.HasSHA1
diff --git a/src/crypto/sha1/sha1block_s390x.s b/src/crypto/sha1/sha1block_s390x.s
new file mode 100644
index 0000000..6ba6883
--- /dev/null
+++ b/src/crypto/sha1/sha1block_s390x.s
@@ -0,0 +1,20 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// func block(dig *digest, p []byte)
+TEXT ·block(SB), NOSPLIT|NOFRAME, $0-32
+ MOVBZ ·useAsm(SB), R4
+ LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
+ MOVBZ $1, R0 // SHA-1 function code
+ CMPBEQ R4, $0, generic
+
+loop:
+ WORD $0xB93E0002 // KIMD R2
+ BVS loop // continue if interrupted
+ RET
+
+generic:
+ BR ·blockGeneric(SB)
diff --git a/src/crypto/sha256/example_test.go b/src/crypto/sha256/example_test.go
new file mode 100644
index 0000000..7d73120
--- /dev/null
+++ b/src/crypto/sha256/example_test.go
@@ -0,0 +1,41 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha256_test
+
+import (
+ "crypto/sha256"
+ "fmt"
+ "io"
+ "log"
+ "os"
+)
+
+func ExampleSum256() {
+ sum := sha256.Sum256([]byte("hello world\n"))
+ fmt.Printf("%x", sum)
+ // Output: a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447
+}
+
+func ExampleNew() {
+ h := sha256.New()
+ h.Write([]byte("hello world\n"))
+ fmt.Printf("%x", h.Sum(nil))
+ // Output: a948904f2f0f479b8f8197694b30184b0d2ed1c1cd2a1ec0fb85d299a192a447
+}
+
+func ExampleNew_file() {
+ f, err := os.Open("file.txt")
+ if err != nil {
+ log.Fatal(err)
+ }
+ defer f.Close()
+
+ h := sha256.New()
+ if _, err := io.Copy(h, f); err != nil {
+ log.Fatal(err)
+ }
+
+ fmt.Printf("%x", h.Sum(nil))
+}
diff --git a/src/crypto/sha256/fallback_test.go b/src/crypto/sha256/fallback_test.go
new file mode 100644
index 0000000..3f561aa
--- /dev/null
+++ b/src/crypto/sha256/fallback_test.go
@@ -0,0 +1,35 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build s390x
+
+package sha256
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+// Tests the fallback code path in case the optimized asm
+// implementation cannot be used.
+// See also TestBlockGeneric.
+func TestGenericPath(t *testing.T) {
+ if useAsm == false {
+ t.Skipf("assembly implementation unavailable")
+ }
+ useAsm = false
+ defer func() { useAsm = true }()
+ c := New()
+ in := "ΑΒΓΔΕϜΖΗΘΙΚΛΜΝΞΟΠϺϘΡΣΤΥΦΧΨΩ"
+ gold := "e93d84ec2b22383123be9f713697fb25" +
+ "338c86e2f7d8d1ddc2d89d332dd9d76c"
+ if _, err := io.WriteString(c, in); err != nil {
+ t.Fatalf("could not write to c: %v", err)
+ }
+ out := fmt.Sprintf("%x", c.Sum(nil))
+ if out != gold {
+ t.Fatalf("mismatch: got %s, wanted %s", out, gold)
+ }
+}
diff --git a/src/crypto/sha256/sha256.go b/src/crypto/sha256/sha256.go
new file mode 100644
index 0000000..2deafbc
--- /dev/null
+++ b/src/crypto/sha256/sha256.go
@@ -0,0 +1,275 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sha256 implements the SHA224 and SHA256 hash algorithms as defined
+// in FIPS 180-4.
+package sha256
+
+import (
+ "crypto"
+ "crypto/internal/boring"
+ "encoding/binary"
+ "errors"
+ "hash"
+)
+
+func init() {
+ crypto.RegisterHash(crypto.SHA224, New224)
+ crypto.RegisterHash(crypto.SHA256, New)
+}
+
+// The size of a SHA256 checksum in bytes.
+const Size = 32
+
+// The size of a SHA224 checksum in bytes.
+const Size224 = 28
+
+// The blocksize of SHA256 and SHA224 in bytes.
+const BlockSize = 64
+
+const (
+ chunk = 64
+ init0 = 0x6A09E667
+ init1 = 0xBB67AE85
+ init2 = 0x3C6EF372
+ init3 = 0xA54FF53A
+ init4 = 0x510E527F
+ init5 = 0x9B05688C
+ init6 = 0x1F83D9AB
+ init7 = 0x5BE0CD19
+ init0_224 = 0xC1059ED8
+ init1_224 = 0x367CD507
+ init2_224 = 0x3070DD17
+ init3_224 = 0xF70E5939
+ init4_224 = 0xFFC00B31
+ init5_224 = 0x68581511
+ init6_224 = 0x64F98FA7
+ init7_224 = 0xBEFA4FA4
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ h [8]uint32
+ x [chunk]byte
+ nx int
+ len uint64
+ is224 bool // mark if this digest is SHA-224
+}
+
+const (
+ magic224 = "sha\x02"
+ magic256 = "sha\x03"
+ marshaledSize = len(magic256) + 8*4 + chunk + 8
+)
+
+func (d *digest) MarshalBinary() ([]byte, error) {
+ b := make([]byte, 0, marshaledSize)
+ if d.is224 {
+ b = append(b, magic224...)
+ } else {
+ b = append(b, magic256...)
+ }
+ b = binary.BigEndian.AppendUint32(b, d.h[0])
+ b = binary.BigEndian.AppendUint32(b, d.h[1])
+ b = binary.BigEndian.AppendUint32(b, d.h[2])
+ b = binary.BigEndian.AppendUint32(b, d.h[3])
+ b = binary.BigEndian.AppendUint32(b, d.h[4])
+ b = binary.BigEndian.AppendUint32(b, d.h[5])
+ b = binary.BigEndian.AppendUint32(b, d.h[6])
+ b = binary.BigEndian.AppendUint32(b, d.h[7])
+ b = append(b, d.x[:d.nx]...)
+ b = b[:len(b)+len(d.x)-d.nx] // already zero
+ b = binary.BigEndian.AppendUint64(b, d.len)
+ return b, nil
+}
+
+func (d *digest) UnmarshalBinary(b []byte) error {
+ if len(b) < len(magic224) || (d.is224 && string(b[:len(magic224)]) != magic224) || (!d.is224 && string(b[:len(magic256)]) != magic256) {
+ return errors.New("crypto/sha256: invalid hash state identifier")
+ }
+ if len(b) != marshaledSize {
+ return errors.New("crypto/sha256: invalid hash state size")
+ }
+ b = b[len(magic224):]
+ b, d.h[0] = consumeUint32(b)
+ b, d.h[1] = consumeUint32(b)
+ b, d.h[2] = consumeUint32(b)
+ b, d.h[3] = consumeUint32(b)
+ b, d.h[4] = consumeUint32(b)
+ b, d.h[5] = consumeUint32(b)
+ b, d.h[6] = consumeUint32(b)
+ b, d.h[7] = consumeUint32(b)
+ b = b[copy(d.x[:], b):]
+ b, d.len = consumeUint64(b)
+ d.nx = int(d.len % chunk)
+ return nil
+}
+
+func consumeUint64(b []byte) ([]byte, uint64) {
+ _ = b[7]
+ x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+ uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+ return b[8:], x
+}
+
+func consumeUint32(b []byte) ([]byte, uint32) {
+ _ = b[3]
+ x := uint32(b[3]) | uint32(b[2])<<8 | uint32(b[1])<<16 | uint32(b[0])<<24
+ return b[4:], x
+}
+
+func (d *digest) Reset() {
+ if !d.is224 {
+ d.h[0] = init0
+ d.h[1] = init1
+ d.h[2] = init2
+ d.h[3] = init3
+ d.h[4] = init4
+ d.h[5] = init5
+ d.h[6] = init6
+ d.h[7] = init7
+ } else {
+ d.h[0] = init0_224
+ d.h[1] = init1_224
+ d.h[2] = init2_224
+ d.h[3] = init3_224
+ d.h[4] = init4_224
+ d.h[5] = init5_224
+ d.h[6] = init6_224
+ d.h[7] = init7_224
+ }
+ d.nx = 0
+ d.len = 0
+}
+
+// New returns a new hash.Hash computing the SHA256 checksum. The Hash
+// also implements encoding.BinaryMarshaler and
+// encoding.BinaryUnmarshaler to marshal and unmarshal the internal
+// state of the hash.
+func New() hash.Hash {
+ if boring.Enabled {
+ return boring.NewSHA256()
+ }
+ d := new(digest)
+ d.Reset()
+ return d
+}
+
+// New224 returns a new hash.Hash computing the SHA224 checksum.
+func New224() hash.Hash {
+ if boring.Enabled {
+ return boring.NewSHA224()
+ }
+ d := new(digest)
+ d.is224 = true
+ d.Reset()
+ return d
+}
+
+func (d *digest) Size() int {
+ if !d.is224 {
+ return Size
+ }
+ return Size224
+}
+
+func (d *digest) BlockSize() int { return BlockSize }
+
+func (d *digest) Write(p []byte) (nn int, err error) {
+ boring.Unreachable()
+ nn = len(p)
+ d.len += uint64(nn)
+ if d.nx > 0 {
+ n := copy(d.x[d.nx:], p)
+ d.nx += n
+ if d.nx == chunk {
+ block(d, d.x[:])
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ if len(p) >= chunk {
+ n := len(p) &^ (chunk - 1)
+ block(d, p[:n])
+ p = p[n:]
+ }
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d *digest) Sum(in []byte) []byte {
+ boring.Unreachable()
+ // Make a copy of d so that caller can keep writing and summing.
+ d0 := *d
+ hash := d0.checkSum()
+ if d0.is224 {
+ return append(in, hash[:Size224]...)
+ }
+ return append(in, hash[:]...)
+}
+
+func (d *digest) checkSum() [Size]byte {
+ len := d.len
+ // Padding. Add a 1 bit and 0 bits until 56 bytes mod 64.
+ var tmp [64 + 8]byte // padding + length buffer
+ tmp[0] = 0x80
+ var t uint64
+ if len%64 < 56 {
+ t = 56 - len%64
+ } else {
+ t = 64 + 56 - len%64
+ }
+
+ // Length in bits.
+ len <<= 3
+ padlen := tmp[:t+8]
+ binary.BigEndian.PutUint64(padlen[t+0:], len)
+ d.Write(padlen)
+
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ var digest [Size]byte
+
+ binary.BigEndian.PutUint32(digest[0:], d.h[0])
+ binary.BigEndian.PutUint32(digest[4:], d.h[1])
+ binary.BigEndian.PutUint32(digest[8:], d.h[2])
+ binary.BigEndian.PutUint32(digest[12:], d.h[3])
+ binary.BigEndian.PutUint32(digest[16:], d.h[4])
+ binary.BigEndian.PutUint32(digest[20:], d.h[5])
+ binary.BigEndian.PutUint32(digest[24:], d.h[6])
+ if !d.is224 {
+ binary.BigEndian.PutUint32(digest[28:], d.h[7])
+ }
+
+ return digest
+}
+
+// Sum256 returns the SHA256 checksum of the data.
+func Sum256(data []byte) [Size]byte {
+ if boring.Enabled {
+ return boring.SHA256(data)
+ }
+ var d digest
+ d.Reset()
+ d.Write(data)
+ return d.checkSum()
+}
+
+// Sum224 returns the SHA224 checksum of the data.
+func Sum224(data []byte) [Size224]byte {
+ if boring.Enabled {
+ return boring.SHA224(data)
+ }
+ var d digest
+ d.is224 = true
+ d.Reset()
+ d.Write(data)
+ sum := d.checkSum()
+ ap := (*[Size224]byte)(sum[:])
+ return *ap
+}
diff --git a/src/crypto/sha256/sha256_test.go b/src/crypto/sha256/sha256_test.go
new file mode 100644
index 0000000..7304678
--- /dev/null
+++ b/src/crypto/sha256/sha256_test.go
@@ -0,0 +1,368 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA256 hash algorithm. See FIPS 180-2.
+
+package sha256
+
+import (
+ "bytes"
+ "crypto/internal/boring"
+ "crypto/rand"
+ "encoding"
+ "fmt"
+ "hash"
+ "io"
+ "testing"
+)
+
+type sha256Test struct {
+ out string
+ in string
+ halfState string // marshaled hash state after first half of in written, used by TestGoldenMarshal
+}
+
+var golden = []sha256Test{
+ {"e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855", "", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"},
+ {"ca978112ca1bbdcafac231b39a23dc4da786eff8147c4e72b9807785afee48bb", "a", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"},
+ {"fb8e20fc2e4c3f248c60c39bd652f3c1347298bb977b8b4d5903b85055620603", "ab", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"},
+ {"ba7816bf8f01cfea414140de5dae2223b00361a396177a9cb410ff61f20015ad", "abc", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"},
+ {"88d4266fd4e6338d13b845fcf289579d209c897823b9217da3e161936f031589", "abcd", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"},
+ {"36bbe50ed96841d10443bcb670d6554f0a34b761be67ec9c4a8ad2c0c44ca42c", "abcde", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"},
+ {"bef57ec7f53a6d40beb640a780a639c83bc29ac8a9816f1fc6c5c6dcd93c4721", "abcdef", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03"},
+ {"7d1a54127b222502f5b79b5fb0803061152a44f92b37e23c6527baf665d4da9a", "abcdefg", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03"},
+ {"9c56cc51b374c3ba189210d5b6d4bf57790d351c96c47c02190ecf1e430635ab", "abcdefgh", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04"},
+ {"19cc02f26df43cc571bc9ed7b0c4d29224a3ec229529221725ef76d021c8326f", "abcdefghi", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04"},
+ {"72399361da6a7754fec986dca5b7cbaf1c810a28ded4abaf56b2106d06cb78b0", "abcdefghij", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19abcde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05"},
+ {"a144061c271f152da4d151034508fed1c138b8c976339de229c3bb6d4bbb4fce", "Discard medicine more than two years old.", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19Discard medicine mor\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14"},
+ {"6dae5caa713a10ad04b46028bf6dad68837c581616a1589a265a11288d4bb5c4", "He who has a shady past knows that nice guys finish last.", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19He who has a shady past know\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"},
+ {"ae7a702a9509039ddbf29f0765e70d0001177914b86459284dab8b348c2dce3f", "I wouldn't marry him with a ten foot pole.", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19I wouldn't marry him \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15"},
+ {"6748450b01c568586715291dfa3ee018da07d36bb7ea6f180c1af6270215c64f", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19Free! Free!/A trip/to Mars/f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"},
+ {"14b82014ad2b11f661b5ae6a99b75105c2ffac278cd071cd6c05832793635774", "The days of the digital watch are numbered. -Tom Stoppard", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19The days of the digital watch\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d"},
+ {"7102cfd76e2e324889eece5d6c41921b1e142a4ac5a2692be78803097f6a48d8", "Nepal premier won't resign.", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19Nepal premier\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r"},
+ {"23b1018cd81db1d67983c5f7417c44da9deb582459e378d7a068552ea649dc9f", "For every action there is an equal and opposite government program.", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19For every action there is an equa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!"},
+ {"8001f190dfb527261c4cfcab70c98e8097a7a1922129bc4096950e57c7999a5a", "His money is twice tainted: 'taint yours and 'taint mine.", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19His money is twice tainted: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"},
+ {"8c87deb65505c3993eb24b7a150c4155e82eee6960cf0c3a8114ff736d69cad5", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19There is no reason for any individual to hav\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,"},
+ {"bfb0a67a19cdec3646498b2e0f751bddc41bba4b7f30081b0b932aad214d16d7", "It's a tiny change to the code and not completely disgusting. - Bob Manchek", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19It's a tiny change to the code and no\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%"},
+ {"7f9a0b9bf56332e19f5a0ec1ad9c1425a153da1c624868fda44561d6b74daf36", "size: a.out: bad magic", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19size: a.out\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\f"},
+ {"b13f81b8aad9e3666879af19886140904f7f429ef083286195982a7588858cfc", "The major problem is with sendmail. -Mark Horton", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19The major problem is wit\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18"},
+ {"b26c38d61519e894480c70c8374ea35aa0ad05b2ae3d6674eec5f52a69305ed4", "Give me a rock, paper and scissors and I will move the world. CCFestoon", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19Give me a rock, paper and scissors a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$"},
+ {"049d5e26d4f10222cd841a119e38bd8d2e0d1129728688449575d4ff42b842c1", "If the enemy is within range, then so are you.", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19If the enemy is within \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17"},
+ {"0e116838e3cc1c1a14cd045397e29b4d087aa11b0853fc69ec82e90330d60949", "It's well we cannot hear the screams/That we create in others' dreams.", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19It's well we cannot hear the scream\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#"},
+ {"4f7d8eb5bcf11de2a56b971021a444aa4eafd6ecd0f307b5109e4e776cd0fe46", "You remind me of a TV show, but that's all right: I watch it anyway.", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19You remind me of a TV show, but th\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\""},
+ {"61c0cc4c4bd8406d5120b3fb4ebc31ce87667c162f29468b3c779675a85aebce", "C is as portable as Stonehedge!!", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19C is as portable\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10"},
+ {"1fb2eb3688093c4a3f80cd87a5547e2ce940a4f923243a79a2a1e242220693ac", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19Even if I could be Shakespeare, I think I sh\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,"},
+ {"395585ce30617b62c80b93e8208ce866d4edc811a177fdb4b82d3911d8696423", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", "sha\x03\x93\x14\xc8z\x87\x0e\vo\xf1E\x0f\xa4V\xb2a\x00\x87\xb5ǔ\xfc\xeaV\u009eg\xbc\x17\xb1\x85њem\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B"},
+ {"4f9b189a13d030838269dce846b16a1ce9ce81fe63e65de2f636863336a98fe6", "How can you write a big system without C++? -Paul Glick", "sha\x03j\t\xe6g\xbbg\xae\x85<n\xf3r\xa5O\xf5:Q\x0eR\u007f\x9b\x05h\x8c\x1f\x83٫[\xe0\xcd\x19How can you write a big syst\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"},
+}
+
+var golden224 = []sha256Test{
+ {"d14a028c2a3a2bc9476102bb288234c415a2b01f828ea62ac5b3e42f", "", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"},
+ {"abd37534c7d9a2efb9465de931cd7055ffdb8879563ae98078d6d6d5", "a", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00"},
+ {"db3cda86d4429a1d39c148989566b38f7bda0156296bd364ba2f878b", "ab", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"},
+ {"23097d223405d8228642a477bda255b32aadbce4bda0b3f7e36c9da7", "abc", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01"},
+ {"a76654d8e3550e9a2d67a0eeb6c67b220e5885eddd3fde135806e601", "abcd", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"},
+ {"bdd03d560993e675516ba5a50638b6531ac2ac3d5847c61916cfced6", "abcde", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02"},
+ {"7043631cb415556a275a4ebecb802c74ee9f6153908e1792a90b6a98", "abcdef", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03"},
+ {"d1884e711701ad81abe0c77a3b0ea12e19ba9af64077286c72fc602d", "abcdefg", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03"},
+ {"17eb7d40f0356f8598e89eafad5f6c759b1f822975d9c9b737c8a517", "abcdefgh", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04"},
+ {"aeb35915346c584db820d2de7af3929ffafef9222a9bcb26516c7334", "abcdefghi", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04"},
+ {"d35e1e5af29ddb0d7e154357df4ad9842afee527c689ee547f753188", "abcdefghij", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4abcde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05"},
+ {"19297f1cef7ddc8a7e947f5c5a341e10f7245045e425db67043988d7", "Discard medicine more than two years old.", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4Discard medicine mor\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14"},
+ {"0f10c2eb436251f777fbbd125e260d36aecf180411726c7c885f599a", "He who has a shady past knows that nice guys finish last.", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4He who has a shady past know\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"},
+ {"4d1842104919f314cad8a3cd20b3cba7e8ed3e7abed62b57441358f6", "I wouldn't marry him with a ten foot pole.", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4I wouldn't marry him \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15"},
+ {"a8ba85c6fe0c48fbffc72bbb2f03fcdbc87ae2dc7a56804d1590fb3b", "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4Free! Free!/A trip/to Mars/f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"},
+ {"5543fbab26e67e8885b1a852d567d1cb8b9bfe42e0899584c50449a9", "The days of the digital watch are numbered. -Tom Stoppard", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4The days of the digital watch\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d"},
+ {"65ca107390f5da9efa05d28e57b221657edc7e43a9a18fb15b053ddb", "Nepal premier won't resign.", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4Nepal premier\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r"},
+ {"84953962be366305a9cc9b5cd16ed019edc37ac96c0deb3e12cca116", "For every action there is an equal and opposite government program.", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4For every action there is an equa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!"},
+ {"35a189ce987151dfd00b3577583cc6a74b9869eecf894459cb52038d", "His money is twice tainted: 'taint yours and 'taint mine.", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4His money is twice tainted: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"},
+ {"2fc333713983edfd4ef2c0da6fb6d6415afb94987c91e4069eb063e6", "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4There is no reason for any individual to hav\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,"},
+ {"cbe32d38d577a1b355960a4bc3c659c2dc4670859a19777a875842c4", "It's a tiny change to the code and not completely disgusting. - Bob Manchek", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4It's a tiny change to the code and no\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%"},
+ {"a2dc118ce959e027576413a7b440c875cdc8d40df9141d6ef78a57e1", "size: a.out: bad magic", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4size: a.out\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\f"},
+ {"d10787e24052bcff26dc484787a54ed819e4e4511c54890ee977bf81", "The major problem is with sendmail. -Mark Horton", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4The major problem is wit\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18"},
+ {"62efcf16ab8a893acdf2f348aaf06b63039ff1bf55508c830532c9fb", "Give me a rock, paper and scissors and I will move the world. CCFestoon", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4Give me a rock, paper and scissors a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$"},
+ {"3e9b7e4613c59f58665104c5fa86c272db5d3a2ff30df5bb194a5c99", "If the enemy is within range, then so are you.", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4If the enemy is within \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17"},
+ {"5999c208b8bdf6d471bb7c359ac5b829e73a8211dff686143a4e7f18", "It's well we cannot hear the screams/That we create in others' dreams.", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4It's well we cannot hear the scream\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#"},
+ {"3b2d67ff54eabc4ef737b14edf87c64280ef582bcdf2a6d56908b405", "You remind me of a TV show, but that's all right: I watch it anyway.", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4You remind me of a TV show, but th\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\""},
+ {"d0733595d20e4d3d6b5c565a445814d1bbb2fd08b9a3b8ffb97930c6", "C is as portable as Stonehedge!!", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4C is as portable\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10"},
+ {"43fb8aeed8a833175c9295c1165415f98c866ef08a4922959d673507", "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4Even if I could be Shakespeare, I think I sh\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,"},
+ {"ec18e66e93afc4fb1604bc2baedbfd20b44c43d76e65c0996d7851c6", "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule", "sha\x02\xea\xc9\xc2e\xddH\x0f\\.\xeb\xc4G\xda\xea\xd5TX\x17\xca3l\xfaV\x9d\x9d\x056\x85&1\rDem\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B"},
+ {"86ed2eaa9c75ba98396e5c9fb2f679ecf0ea2ed1e0ee9ceecb4a9332", "How can you write a big system without C++? -Paul Glick", "sha\x02\xc1\x05\x9e\xd86|\xd5\a0p\xdd\x17\xf7\x0eY9\xff\xc0\v1hX\x15\x11d\xf9\x8f\xa7\xbe\xfaO\xa4How can you write a big syst\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c"},
+}
+
+func TestGolden(t *testing.T) {
+ for i := 0; i < len(golden); i++ {
+ g := golden[i]
+ s := fmt.Sprintf("%x", Sum256([]byte(g.in)))
+ if s != g.out {
+ t.Fatalf("Sum256 function: sha256(%s) = %s want %s", g.in, s, g.out)
+ }
+ c := New()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum(nil)
+ io.WriteString(c, g.in[len(g.in)/2:])
+ }
+ s := fmt.Sprintf("%x", c.Sum(nil))
+ if s != g.out {
+ t.Fatalf("sha256[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+ for i := 0; i < len(golden224); i++ {
+ g := golden224[i]
+ s := fmt.Sprintf("%x", Sum224([]byte(g.in)))
+ if s != g.out {
+ t.Fatalf("Sum224 function: sha224(%s) = %s want %s", g.in, s, g.out)
+ }
+ c := New224()
+ for j := 0; j < 3; j++ {
+ if j < 2 {
+ io.WriteString(c, g.in)
+ } else {
+ io.WriteString(c, g.in[0:len(g.in)/2])
+ c.Sum(nil)
+ io.WriteString(c, g.in[len(g.in)/2:])
+ }
+ s := fmt.Sprintf("%x", c.Sum(nil))
+ if s != g.out {
+ t.Fatalf("sha224[%d](%s) = %s want %s", j, g.in, s, g.out)
+ }
+ c.Reset()
+ }
+ }
+}
+
+func TestGoldenMarshal(t *testing.T) {
+ tests := []struct {
+ name string
+ newHash func() hash.Hash
+ gold []sha256Test
+ }{
+ {"256", New, golden},
+ {"224", New224, golden224},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ for _, g := range tt.gold {
+ h := tt.newHash()
+ h2 := tt.newHash()
+
+ io.WriteString(h, g.in[:len(g.in)/2])
+
+ state, err := h.(encoding.BinaryMarshaler).MarshalBinary()
+ if err != nil {
+ t.Errorf("could not marshal: %v", err)
+ continue
+ }
+
+ if string(state) != g.halfState {
+ t.Errorf("sha%s(%q) state = %q, want %q", tt.name, g.in, state, g.halfState)
+ continue
+ }
+
+ if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err != nil {
+ t.Errorf("could not unmarshal: %v", err)
+ continue
+ }
+
+ io.WriteString(h, g.in[len(g.in)/2:])
+ io.WriteString(h2, g.in[len(g.in)/2:])
+
+ if actual, actual2 := h.Sum(nil), h2.Sum(nil); !bytes.Equal(actual, actual2) {
+ t.Errorf("sha%s(%q) = 0x%x != marshaled 0x%x", tt.name, g.in, actual, actual2)
+ }
+ }
+ })
+ }
+}
+
+func TestMarshalTypeMismatch(t *testing.T) {
+ h1 := New()
+ h2 := New224()
+
+ state1, err := h1.(encoding.BinaryMarshaler).MarshalBinary()
+ if err != nil {
+ t.Errorf("could not marshal: %v", err)
+ }
+
+ if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state1); err == nil {
+ t.Errorf("no error when one was expected")
+ }
+}
+
+func TestSize(t *testing.T) {
+ c := New()
+ if got := c.Size(); got != Size {
+ t.Errorf("Size = %d; want %d", got, Size)
+ }
+ c = New224()
+ if got := c.Size(); got != Size224 {
+ t.Errorf("New224.Size = %d; want %d", got, Size224)
+ }
+}
+
+func TestBlockSize(t *testing.T) {
+ c := New()
+ if got := c.BlockSize(); got != BlockSize {
+ t.Errorf("BlockSize = %d want %d", got, BlockSize)
+ }
+}
+
+// Tests that blockGeneric (pure Go) and block (in assembly for some architectures) match.
+func TestBlockGeneric(t *testing.T) {
+ if boring.Enabled {
+ t.Skip("BoringCrypto doesn't expose digest")
+ }
+ gen, asm := New().(*digest), New().(*digest)
+ buf := make([]byte, BlockSize*20) // arbitrary factor
+ rand.Read(buf)
+ blockGeneric(gen, buf)
+ block(asm, buf)
+ if *gen != *asm {
+ t.Error("block and blockGeneric resulted in different states")
+ }
+}
+
+// Tests for unmarshaling hashes that have hashed a large amount of data
+// The initial hash generation is omitted from the test, because it takes a long time.
+// The test contains some already-generated states, and their expected sums
+// Tests a problem that is outlined in GitHub issue #29517
+// The problem is triggered when an amount of data has been hashed for which
+// the data length has a 1 in the 32nd bit. When casted to int, this changes
+// the sign of the value, and causes the modulus operation to return a
+// different result.
+type unmarshalTest struct {
+ state string
+ sum string
+}
+
+var largeUnmarshalTests = []unmarshalTest{
+ // Data length: 7_115_087_207
+ {
+ state: "sha\x03yX\xaf\xb7\x04*\x8f\xaa\x9bx\xc5#\x1f\xeb\x94\xfdz1\xaf\xfbk֗\n\xc93\xcf\x02\v.\xa5\xe4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xa8\x17\x9dg",
+ sum: "f5e06371f0c115e9968455c8e48a318aba548b9f15676fa41de123f7d1c99c55",
+ },
+
+ // Data length: 7_070_038_086
+ {
+ state: "sha\x03$\x933u\nV\v\xe2\xf7:0!ʳ\xa4\x13\xd3 6\xdcBB\xb5\x19\xcd=\xc1h\xee=\xb4\x9c@ABCDE\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xa5h8F",
+ sum: "a280b08df5eba060fcd0eb3d29320bbc038afb95781661f91bbfd0a6fc9fdd6e",
+ },
+
+ // Data length: 6_464_878_887
+ {
+ state: "sha\x03\x9f\x12\x87G\xf2\xdf<\x82\xa0\x11/*W\x02&IKWlh\x03\x95\xb1\xab\f\n\xf6Ze\xf9\x1d\x1b\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x81V9'",
+ sum: "d2fffb762f105ab71e2d70069346c44c38c4fe183aad8cfcf5a76397c0457806",
+ },
+}
+
+func safeSum(h hash.Hash) (sum []byte, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = fmt.Errorf("sum panic: %v", r)
+ }
+ }()
+
+ return h.Sum(nil), nil
+}
+func TestLargeHashes(t *testing.T) {
+ for i, test := range largeUnmarshalTests {
+
+ h := New()
+ if err := h.(encoding.BinaryUnmarshaler).UnmarshalBinary([]byte(test.state)); err != nil {
+ t.Errorf("test %d could not unmarshal: %v", i, err)
+ continue
+ }
+
+ sum, err := safeSum(h)
+ if err != nil {
+ t.Errorf("test %d could not sum: %v", i, err)
+ continue
+ }
+
+ if fmt.Sprintf("%x", sum) != test.sum {
+ t.Errorf("test %d sum mismatch: expect %s got %x", i, test.sum, sum)
+ }
+ }
+}
+
+func TestAllocations(t *testing.T) {
+ if boring.Enabled {
+ t.Skip("BoringCrypto doesn't allocate the same way as stdlib")
+ }
+ in := []byte("hello, world!")
+ out := make([]byte, 0, Size)
+ h := New()
+ n := int(testing.AllocsPerRun(10, func() {
+ h.Reset()
+ h.Write(in)
+ out = h.Sum(out[:0])
+ }))
+ if n > 0 {
+ t.Errorf("allocs = %d, want 0", n)
+ }
+}
+
+type cgoData struct {
+ Data [16]byte
+ Ptr *cgoData
+}
+
+func TestCgo(t *testing.T) {
+ // Test that Write does not cause cgo to scan the entire cgoData struct for pointers.
+ // The scan (if any) should be limited to the [16]byte.
+ d := new(cgoData)
+ d.Ptr = d
+ h := New()
+ h.Write(d.Data[:])
+ h.Sum(nil)
+}
+
+var bench = New()
+var buf = make([]byte, 8192)
+
+func benchmarkSize(b *testing.B, size int) {
+ sum := make([]byte, bench.Size())
+ b.Run("New", func(b *testing.B) {
+ b.ReportAllocs()
+ b.SetBytes(int64(size))
+ for i := 0; i < b.N; i++ {
+ bench.Reset()
+ bench.Write(buf[:size])
+ bench.Sum(sum[:0])
+ }
+ })
+ b.Run("Sum224", func(b *testing.B) {
+ b.ReportAllocs()
+ b.SetBytes(int64(size))
+ for i := 0; i < b.N; i++ {
+ Sum224(buf[:size])
+ }
+ })
+ b.Run("Sum256", func(b *testing.B) {
+ b.ReportAllocs()
+ b.SetBytes(int64(size))
+ for i := 0; i < b.N; i++ {
+ Sum256(buf[:size])
+ }
+ })
+}
+
+func BenchmarkHash8Bytes(b *testing.B) {
+ benchmarkSize(b, 8)
+}
+
+func BenchmarkHash1K(b *testing.B) {
+ benchmarkSize(b, 1024)
+}
+
+func BenchmarkHash8K(b *testing.B) {
+ benchmarkSize(b, 8192)
+}
diff --git a/src/crypto/sha256/sha256block.go b/src/crypto/sha256/sha256block.go
new file mode 100644
index 0000000..bd2f9da
--- /dev/null
+++ b/src/crypto/sha256/sha256block.go
@@ -0,0 +1,128 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA256 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package sha256
+
+import "math/bits"
+
+var _K = []uint32{
+ 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,
+}
+
+func blockGeneric(dig *digest, p []byte) {
+ var w [64]uint32
+ h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
+ for len(p) >= chunk {
+ // Can interlace the computation of w with the
+ // rounds below if needed for speed.
+ for i := 0; i < 16; i++ {
+ j := i * 4
+ w[i] = uint32(p[j])<<24 | uint32(p[j+1])<<16 | uint32(p[j+2])<<8 | uint32(p[j+3])
+ }
+ for i := 16; i < 64; i++ {
+ v1 := w[i-2]
+ t1 := (bits.RotateLeft32(v1, -17)) ^ (bits.RotateLeft32(v1, -19)) ^ (v1 >> 10)
+ v2 := w[i-15]
+ t2 := (bits.RotateLeft32(v2, -7)) ^ (bits.RotateLeft32(v2, -18)) ^ (v2 >> 3)
+ w[i] = t1 + w[i-7] + t2 + w[i-16]
+ }
+
+ a, b, c, d, e, f, g, h := h0, h1, h2, h3, h4, h5, h6, h7
+
+ for i := 0; i < 64; i++ {
+ t1 := h + ((bits.RotateLeft32(e, -6)) ^ (bits.RotateLeft32(e, -11)) ^ (bits.RotateLeft32(e, -25))) + ((e & f) ^ (^e & g)) + _K[i] + w[i]
+
+ t2 := ((bits.RotateLeft32(a, -2)) ^ (bits.RotateLeft32(a, -13)) ^ (bits.RotateLeft32(a, -22))) + ((a & b) ^ (a & c) ^ (b & c))
+
+ h = g
+ g = f
+ f = e
+ e = d + t1
+ d = c
+ c = b
+ b = a
+ a = t1 + t2
+ }
+
+ h0 += a
+ h1 += b
+ h2 += c
+ h3 += d
+ h4 += e
+ h5 += f
+ h6 += g
+ h7 += h
+
+ p = p[chunk:]
+ }
+
+ dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7
+}
diff --git a/src/crypto/sha256/sha256block_386.s b/src/crypto/sha256/sha256block_386.s
new file mode 100644
index 0000000..086a0ab
--- /dev/null
+++ b/src/crypto/sha256/sha256block_386.s
@@ -0,0 +1,283 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA256 block routine. See sha256block.go for Go equivalent.
+//
+// The algorithm is detailed in FIPS 180-4:
+//
+// https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+//
+// Wt = Mt; for 0 <= t <= 15
+// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+//
+// a = H0
+// b = H1
+// c = H2
+// d = H3
+// e = H4
+// f = H5
+// g = H6
+// h = H7
+//
+// for t = 0 to 63 {
+// T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt
+// T2 = BIGSIGMA0(a) + Maj(a,b,c)
+// h = g
+// g = f
+// f = e
+// e = d + T1
+// d = c
+// c = b
+// b = a
+// a = T1 + T2
+// }
+//
+// H0 = a + H0
+// H1 = b + H1
+// H2 = c + H2
+// H3 = d + H3
+// H4 = e + H4
+// H5 = f + H5
+// H6 = g + H6
+// H7 = h + H7
+
+// Wt = Mt; for 0 <= t <= 15
+#define MSGSCHEDULE0(index) \
+ MOVL (index*4)(SI), AX; \
+ BSWAPL AX; \
+ MOVL AX, (index*4)(BP)
+
+// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+// SIGMA0(x) = ROTR(7,x) XOR ROTR(18,x) XOR SHR(3,x)
+// SIGMA1(x) = ROTR(17,x) XOR ROTR(19,x) XOR SHR(10,x)
+#define MSGSCHEDULE1(index) \
+ MOVL ((index-2)*4)(BP), AX; \
+ MOVL AX, CX; \
+ RORL $17, AX; \
+ MOVL CX, DX; \
+ RORL $19, CX; \
+ SHRL $10, DX; \
+ MOVL ((index-15)*4)(BP), BX; \
+ XORL CX, AX; \
+ MOVL BX, CX; \
+ XORL DX, AX; \
+ RORL $7, BX; \
+ MOVL CX, DX; \
+ SHRL $3, DX; \
+ RORL $18, CX; \
+ ADDL ((index-7)*4)(BP), AX; \
+ XORL CX, BX; \
+ XORL DX, BX; \
+ ADDL ((index-16)*4)(BP), BX; \
+ ADDL BX, AX; \
+ MOVL AX, ((index)*4)(BP)
+
+// Calculate T1 in AX - uses AX, BX, CX and DX registers.
+// Wt is passed in AX.
+// T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt
+// BIGSIGMA1(x) = ROTR(6,x) XOR ROTR(11,x) XOR ROTR(25,x)
+// Ch(x, y, z) = (x AND y) XOR (NOT x AND z)
+#define SHA256T1(const, e, f, g, h) \
+ MOVL (h*4)(DI), BX; \
+ ADDL AX, BX; \
+ MOVL (e*4)(DI), AX; \
+ ADDL $const, BX; \
+ MOVL (e*4)(DI), CX; \
+ RORL $6, AX; \
+ MOVL (e*4)(DI), DX; \
+ RORL $11, CX; \
+ XORL CX, AX; \
+ MOVL (e*4)(DI), CX; \
+ RORL $25, DX; \
+ ANDL (f*4)(DI), CX; \
+ XORL AX, DX; \
+ MOVL (e*4)(DI), AX; \
+ NOTL AX; \
+ ADDL DX, BX; \
+ ANDL (g*4)(DI), AX; \
+ XORL CX, AX; \
+ ADDL BX, AX
+
+// Calculate T2 in BX - uses AX, BX, CX and DX registers.
+// T2 = BIGSIGMA0(a) + Maj(a, b, c)
+// BIGSIGMA0(x) = ROTR(2,x) XOR ROTR(13,x) XOR ROTR(22,x)
+// Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
+#define SHA256T2(a, b, c) \
+ MOVL (a*4)(DI), AX; \
+ MOVL (c*4)(DI), BX; \
+ RORL $2, AX; \
+ MOVL (a*4)(DI), DX; \
+ ANDL (b*4)(DI), BX; \
+ RORL $13, DX; \
+ MOVL (a*4)(DI), CX; \
+ ANDL (c*4)(DI), CX; \
+ XORL DX, AX; \
+ XORL CX, BX; \
+ MOVL (a*4)(DI), DX; \
+ MOVL (b*4)(DI), CX; \
+ RORL $22, DX; \
+ ANDL (a*4)(DI), CX; \
+ XORL CX, BX; \
+ XORL DX, AX; \
+ ADDL AX, BX
+
+// Calculate T1 and T2, then e = d + T1 and a = T1 + T2.
+// The values for e and a are stored in d and h, ready for rotation.
+#define SHA256ROUND(index, const, a, b, c, d, e, f, g, h) \
+ SHA256T1(const, e, f, g, h); \
+ MOVL AX, 292(SP); \
+ SHA256T2(a, b, c); \
+ MOVL 292(SP), AX; \
+ ADDL AX, BX; \
+ ADDL AX, (d*4)(DI); \
+ MOVL BX, (h*4)(DI)
+
+#define SHA256ROUND0(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE0(index); \
+ SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
+
+#define SHA256ROUND1(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE1(index); \
+ SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
+
+TEXT ·block(SB),0,$296-16
+ MOVL p_base+4(FP), SI
+ MOVL p_len+8(FP), DX
+ SHRL $6, DX
+ SHLL $6, DX
+
+ LEAL (SI)(DX*1), DI
+ MOVL DI, 288(SP)
+ CMPL SI, DI
+ JEQ end
+
+ LEAL 256(SP), DI // variables
+
+ MOVL dig+0(FP), BP
+ MOVL (0*4)(BP), AX // a = H0
+ MOVL AX, (0*4)(DI)
+ MOVL (1*4)(BP), BX // b = H1
+ MOVL BX, (1*4)(DI)
+ MOVL (2*4)(BP), CX // c = H2
+ MOVL CX, (2*4)(DI)
+ MOVL (3*4)(BP), DX // d = H3
+ MOVL DX, (3*4)(DI)
+ MOVL (4*4)(BP), AX // e = H4
+ MOVL AX, (4*4)(DI)
+ MOVL (5*4)(BP), BX // f = H5
+ MOVL BX, (5*4)(DI)
+ MOVL (6*4)(BP), CX // g = H6
+ MOVL CX, (6*4)(DI)
+ MOVL (7*4)(BP), DX // h = H7
+ MOVL DX, (7*4)(DI)
+
+loop:
+ MOVL SP, BP // message schedule
+
+ SHA256ROUND0(0, 0x428a2f98, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND0(1, 0x71374491, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND0(2, 0xb5c0fbcf, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND0(3, 0xe9b5dba5, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND0(4, 0x3956c25b, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND0(5, 0x59f111f1, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND0(6, 0x923f82a4, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND0(7, 0xab1c5ed5, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND0(8, 0xd807aa98, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND0(9, 0x12835b01, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND0(10, 0x243185be, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND0(11, 0x550c7dc3, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND0(12, 0x72be5d74, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND0(13, 0x80deb1fe, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND0(14, 0x9bdc06a7, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND0(15, 0xc19bf174, 1, 2, 3, 4, 5, 6, 7, 0)
+
+ SHA256ROUND1(16, 0xe49b69c1, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(17, 0xefbe4786, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(18, 0x0fc19dc6, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(19, 0x240ca1cc, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(20, 0x2de92c6f, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(21, 0x4a7484aa, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(22, 0x5cb0a9dc, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(23, 0x76f988da, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND1(24, 0x983e5152, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(25, 0xa831c66d, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(26, 0xb00327c8, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(27, 0xbf597fc7, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(28, 0xc6e00bf3, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(29, 0xd5a79147, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(30, 0x06ca6351, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(31, 0x14292967, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND1(32, 0x27b70a85, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(33, 0x2e1b2138, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(34, 0x4d2c6dfc, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(35, 0x53380d13, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(36, 0x650a7354, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(37, 0x766a0abb, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(38, 0x81c2c92e, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(39, 0x92722c85, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND1(40, 0xa2bfe8a1, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(41, 0xa81a664b, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(42, 0xc24b8b70, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(43, 0xc76c51a3, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(44, 0xd192e819, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(45, 0xd6990624, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(46, 0xf40e3585, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(47, 0x106aa070, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND1(48, 0x19a4c116, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(49, 0x1e376c08, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(50, 0x2748774c, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(51, 0x34b0bcb5, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(52, 0x391c0cb3, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(53, 0x4ed8aa4a, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(54, 0x5b9cca4f, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(55, 0x682e6ff3, 1, 2, 3, 4, 5, 6, 7, 0)
+ SHA256ROUND1(56, 0x748f82ee, 0, 1, 2, 3, 4, 5, 6, 7)
+ SHA256ROUND1(57, 0x78a5636f, 7, 0, 1, 2, 3, 4, 5, 6)
+ SHA256ROUND1(58, 0x84c87814, 6, 7, 0, 1, 2, 3, 4, 5)
+ SHA256ROUND1(59, 0x8cc70208, 5, 6, 7, 0, 1, 2, 3, 4)
+ SHA256ROUND1(60, 0x90befffa, 4, 5, 6, 7, 0, 1, 2, 3)
+ SHA256ROUND1(61, 0xa4506ceb, 3, 4, 5, 6, 7, 0, 1, 2)
+ SHA256ROUND1(62, 0xbef9a3f7, 2, 3, 4, 5, 6, 7, 0, 1)
+ SHA256ROUND1(63, 0xc67178f2, 1, 2, 3, 4, 5, 6, 7, 0)
+
+ MOVL dig+0(FP), BP
+ MOVL (0*4)(BP), AX // H0 = a + H0
+ ADDL (0*4)(DI), AX
+ MOVL AX, (0*4)(DI)
+ MOVL AX, (0*4)(BP)
+ MOVL (1*4)(BP), BX // H1 = b + H1
+ ADDL (1*4)(DI), BX
+ MOVL BX, (1*4)(DI)
+ MOVL BX, (1*4)(BP)
+ MOVL (2*4)(BP), CX // H2 = c + H2
+ ADDL (2*4)(DI), CX
+ MOVL CX, (2*4)(DI)
+ MOVL CX, (2*4)(BP)
+ MOVL (3*4)(BP), DX // H3 = d + H3
+ ADDL (3*4)(DI), DX
+ MOVL DX, (3*4)(DI)
+ MOVL DX, (3*4)(BP)
+ MOVL (4*4)(BP), AX // H4 = e + H4
+ ADDL (4*4)(DI), AX
+ MOVL AX, (4*4)(DI)
+ MOVL AX, (4*4)(BP)
+ MOVL (5*4)(BP), BX // H5 = f + H5
+ ADDL (5*4)(DI), BX
+ MOVL BX, (5*4)(DI)
+ MOVL BX, (5*4)(BP)
+ MOVL (6*4)(BP), CX // H6 = g + H6
+ ADDL (6*4)(DI), CX
+ MOVL CX, (6*4)(DI)
+ MOVL CX, (6*4)(BP)
+ MOVL (7*4)(BP), DX // H7 = h + H7
+ ADDL (7*4)(DI), DX
+ MOVL DX, (7*4)(DI)
+ MOVL DX, (7*4)(BP)
+
+ ADDL $64, SI
+ CMPL SI, 288(SP)
+ JB loop
+
+end:
+ RET
diff --git a/src/crypto/sha256/sha256block_amd64.go b/src/crypto/sha256/sha256block_amd64.go
new file mode 100644
index 0000000..27464e2
--- /dev/null
+++ b/src/crypto/sha256/sha256block_amd64.go
@@ -0,0 +1,9 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha256
+
+import "internal/cpu"
+
+var useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI2
diff --git a/src/crypto/sha256/sha256block_amd64.s b/src/crypto/sha256/sha256block_amd64.s
new file mode 100644
index 0000000..f6af47c
--- /dev/null
+++ b/src/crypto/sha256/sha256block_amd64.s
@@ -0,0 +1,1031 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// SHA256 block routine. See sha256block.go for Go equivalent.
+//
+// The algorithm is detailed in FIPS 180-4:
+//
+// https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+
+// The avx2-version is described in an Intel White-Paper:
+// "Fast SHA-256 Implementations on Intel Architecture Processors"
+// To find it, surf to http://www.intel.com/p/en_US/embedded
+// and search for that title.
+// AVX2 version by Intel, same algorithm as code in Linux kernel:
+// https://github.com/torvalds/linux/blob/master/arch/x86/crypto/sha256-avx2-asm.S
+// by
+// James Guilford <james.guilford@intel.com>
+// Kirk Yap <kirk.s.yap@intel.com>
+// Tim Chen <tim.c.chen@linux.intel.com>
+
+// Wt = Mt; for 0 <= t <= 15
+// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+//
+// a = H0
+// b = H1
+// c = H2
+// d = H3
+// e = H4
+// f = H5
+// g = H6
+// h = H7
+//
+// for t = 0 to 63 {
+// T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt
+// T2 = BIGSIGMA0(a) + Maj(a,b,c)
+// h = g
+// g = f
+// f = e
+// e = d + T1
+// d = c
+// c = b
+// b = a
+// a = T1 + T2
+// }
+//
+// H0 = a + H0
+// H1 = b + H1
+// H2 = c + H2
+// H3 = d + H3
+// H4 = e + H4
+// H5 = f + H5
+// H6 = g + H6
+// H7 = h + H7
+
+// Wt = Mt; for 0 <= t <= 15
+#define MSGSCHEDULE0(index) \
+ MOVL (index*4)(SI), AX; \
+ BSWAPL AX; \
+ MOVL AX, (index*4)(BP)
+
+// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+// SIGMA0(x) = ROTR(7,x) XOR ROTR(18,x) XOR SHR(3,x)
+// SIGMA1(x) = ROTR(17,x) XOR ROTR(19,x) XOR SHR(10,x)
+#define MSGSCHEDULE1(index) \
+ MOVL ((index-2)*4)(BP), AX; \
+ MOVL AX, CX; \
+ RORL $17, AX; \
+ MOVL CX, DX; \
+ RORL $19, CX; \
+ SHRL $10, DX; \
+ MOVL ((index-15)*4)(BP), BX; \
+ XORL CX, AX; \
+ MOVL BX, CX; \
+ XORL DX, AX; \
+ RORL $7, BX; \
+ MOVL CX, DX; \
+ SHRL $3, DX; \
+ RORL $18, CX; \
+ ADDL ((index-7)*4)(BP), AX; \
+ XORL CX, BX; \
+ XORL DX, BX; \
+ ADDL ((index-16)*4)(BP), BX; \
+ ADDL BX, AX; \
+ MOVL AX, ((index)*4)(BP)
+
+// Calculate T1 in AX - uses AX, CX and DX registers.
+// h is also used as an accumulator. Wt is passed in AX.
+// T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt
+// BIGSIGMA1(x) = ROTR(6,x) XOR ROTR(11,x) XOR ROTR(25,x)
+// Ch(x, y, z) = (x AND y) XOR (NOT x AND z)
+#define SHA256T1(const, e, f, g, h) \
+ ADDL AX, h; \
+ MOVL e, AX; \
+ ADDL $const, h; \
+ MOVL e, CX; \
+ RORL $6, AX; \
+ MOVL e, DX; \
+ RORL $11, CX; \
+ XORL CX, AX; \
+ MOVL e, CX; \
+ RORL $25, DX; \
+ ANDL f, CX; \
+ XORL AX, DX; \
+ MOVL e, AX; \
+ NOTL AX; \
+ ADDL DX, h; \
+ ANDL g, AX; \
+ XORL CX, AX; \
+ ADDL h, AX
+
+// Calculate T2 in BX - uses BX, CX, DX and DI registers.
+// T2 = BIGSIGMA0(a) + Maj(a, b, c)
+// BIGSIGMA0(x) = ROTR(2,x) XOR ROTR(13,x) XOR ROTR(22,x)
+// Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
+#define SHA256T2(a, b, c) \
+ MOVL a, DI; \
+ MOVL c, BX; \
+ RORL $2, DI; \
+ MOVL a, DX; \
+ ANDL b, BX; \
+ RORL $13, DX; \
+ MOVL a, CX; \
+ ANDL c, CX; \
+ XORL DX, DI; \
+ XORL CX, BX; \
+ MOVL a, DX; \
+ MOVL b, CX; \
+ RORL $22, DX; \
+ ANDL a, CX; \
+ XORL CX, BX; \
+ XORL DX, DI; \
+ ADDL DI, BX
+
+// Calculate T1 and T2, then e = d + T1 and a = T1 + T2.
+// The values for e and a are stored in d and h, ready for rotation.
+#define SHA256ROUND(index, const, a, b, c, d, e, f, g, h) \
+ SHA256T1(const, e, f, g, h); \
+ SHA256T2(a, b, c); \
+ MOVL BX, h; \
+ ADDL AX, d; \
+ ADDL AX, h
+
+#define SHA256ROUND0(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE0(index); \
+ SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
+
+#define SHA256ROUND1(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE1(index); \
+ SHA256ROUND(index, const, a, b, c, d, e, f, g, h)
+
+
+// Definitions for AVX2 version
+
+// addm (mem), reg
+// Add reg to mem using reg-mem add and store
+#define addm(P1, P2) \
+ ADDL P2, P1; \
+ MOVL P1, P2
+
+#define XDWORD0 Y4
+#define XDWORD1 Y5
+#define XDWORD2 Y6
+#define XDWORD3 Y7
+
+#define XWORD0 X4
+#define XWORD1 X5
+#define XWORD2 X6
+#define XWORD3 X7
+
+#define XTMP0 Y0
+#define XTMP1 Y1
+#define XTMP2 Y2
+#define XTMP3 Y3
+#define XTMP4 Y8
+#define XTMP5 Y11
+
+#define XFER Y9
+
+#define BYTE_FLIP_MASK Y13 // mask to convert LE -> BE
+#define X_BYTE_FLIP_MASK X13
+
+#define NUM_BYTES DX
+#define INP DI
+
+#define CTX SI // Beginning of digest in memory (a, b, c, ... , h)
+
+#define a AX
+#define b BX
+#define c CX
+#define d R8
+#define e DX
+#define f R9
+#define g R10
+#define h R11
+
+#define old_h R11
+
+#define TBL BP
+
+#define SRND SI // SRND is same register as CTX
+
+#define T1 R12
+
+#define y0 R13
+#define y1 R14
+#define y2 R15
+#define y3 DI
+
+// Offsets
+#define XFER_SIZE 2*64*4
+#define INP_END_SIZE 8
+#define INP_SIZE 8
+
+#define _XFER 0
+#define _INP_END _XFER + XFER_SIZE
+#define _INP _INP_END + INP_END_SIZE
+#define STACK_SIZE _INP + INP_SIZE
+
+#define ROUND_AND_SCHED_N_0(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \
+ ; \ // ############################# RND N + 0 ############################//
+ MOVL a, y3; \ // y3 = a // MAJA
+ RORXL $25, e, y0; \ // y0 = e >> 25 // S1A
+ RORXL $11, e, y1; \ // y1 = e >> 11 // S1B
+ ; \
+ ADDL (disp + 0*4)(SP)(SRND*1), h; \ // h = k + w + h // disp = k + w
+ ORL c, y3; \ // y3 = a|c // MAJA
+ VPALIGNR $4, XDWORD2, XDWORD3, XTMP0; \ // XTMP0 = W[-7]
+ MOVL f, y2; \ // y2 = f // CH
+ RORXL $13, a, T1; \ // T1 = a >> 13 // S0B
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1
+ XORL g, y2; \ // y2 = f^g // CH
+ VPADDD XDWORD0, XTMP0, XTMP0; \ // XTMP0 = W[-7] + W[-16] // y1 = (e >> 6) // S1
+ RORXL $6, e, y1; \ // y1 = (e >> 6) // S1
+ ; \
+ ANDL e, y2; \ // y2 = (f^g)&e // CH
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1
+ RORXL $22, a, y1; \ // y1 = a >> 22 // S0A
+ ADDL h, d; \ // d = k + w + h + d // --
+ ; \
+ ANDL b, y3; \ // y3 = (a|c)&b // MAJA
+ VPALIGNR $4, XDWORD0, XDWORD1, XTMP1; \ // XTMP1 = W[-15]
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0
+ RORXL $2, a, T1; \ // T1 = (a >> 2) // S0
+ ; \
+ XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH
+ VPSRLD $7, XTMP1, XTMP2; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0
+ MOVL a, T1; \ // T1 = a // MAJB
+ ANDL c, T1; \ // T1 = a&c // MAJB
+ ; \
+ ADDL y0, y2; \ // y2 = S1 + CH // --
+ VPSLLD $(32-7), XTMP1, XTMP3; \
+ ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ
+ ADDL y1, h; \ // h = k + w + h + S0 // --
+ ; \
+ ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // --
+ VPOR XTMP2, XTMP3, XTMP3; \ // XTMP3 = W[-15] ror 7
+ ; \
+ VPSRLD $18, XTMP1, XTMP2; \
+ ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+ ADDL y3, h // h = t1 + S0 + MAJ // --
+
+#define ROUND_AND_SCHED_N_1(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \
+ ; \ // ################################### RND N + 1 ############################
+ ; \
+ MOVL a, y3; \ // y3 = a // MAJA
+ RORXL $25, e, y0; \ // y0 = e >> 25 // S1A
+ RORXL $11, e, y1; \ // y1 = e >> 11 // S1B
+ ADDL (disp + 1*4)(SP)(SRND*1), h; \ // h = k + w + h // --
+ ORL c, y3; \ // y3 = a|c // MAJA
+ ; \
+ VPSRLD $3, XTMP1, XTMP4; \ // XTMP4 = W[-15] >> 3
+ MOVL f, y2; \ // y2 = f // CH
+ RORXL $13, a, T1; \ // T1 = a >> 13 // S0B
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1
+ XORL g, y2; \ // y2 = f^g // CH
+ ; \
+ RORXL $6, e, y1; \ // y1 = (e >> 6) // S1
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1
+ RORXL $22, a, y1; \ // y1 = a >> 22 // S0A
+ ANDL e, y2; \ // y2 = (f^g)&e // CH
+ ADDL h, d; \ // d = k + w + h + d // --
+ ; \
+ VPSLLD $(32-18), XTMP1, XTMP1; \
+ ANDL b, y3; \ // y3 = (a|c)&b // MAJA
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0
+ ; \
+ VPXOR XTMP1, XTMP3, XTMP3; \
+ RORXL $2, a, T1; \ // T1 = (a >> 2) // S0
+ XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH
+ ; \
+ VPXOR XTMP2, XTMP3, XTMP3; \ // XTMP3 = W[-15] ror 7 ^ W[-15] ror 18
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0
+ MOVL a, T1; \ // T1 = a // MAJB
+ ANDL c, T1; \ // T1 = a&c // MAJB
+ ADDL y0, y2; \ // y2 = S1 + CH // --
+ ; \
+ VPXOR XTMP4, XTMP3, XTMP1; \ // XTMP1 = s0
+ VPSHUFD $0xFA, XDWORD3, XTMP2; \ // XTMP2 = W[-2] {BBAA}
+ ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ
+ ADDL y1, h; \ // h = k + w + h + S0 // --
+ ; \
+ VPADDD XTMP1, XTMP0, XTMP0; \ // XTMP0 = W[-16] + W[-7] + s0
+ ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // --
+ ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+ ADDL y3, h; \ // h = t1 + S0 + MAJ // --
+ ; \
+ VPSRLD $10, XTMP2, XTMP4 // XTMP4 = W[-2] >> 10 {BBAA}
+
+#define ROUND_AND_SCHED_N_2(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \
+ ; \ // ################################### RND N + 2 ############################
+ ; \
+ MOVL a, y3; \ // y3 = a // MAJA
+ RORXL $25, e, y0; \ // y0 = e >> 25 // S1A
+ ADDL (disp + 2*4)(SP)(SRND*1), h; \ // h = k + w + h // --
+ ; \
+ VPSRLQ $19, XTMP2, XTMP3; \ // XTMP3 = W[-2] ror 19 {xBxA}
+ RORXL $11, e, y1; \ // y1 = e >> 11 // S1B
+ ORL c, y3; \ // y3 = a|c // MAJA
+ MOVL f, y2; \ // y2 = f // CH
+ XORL g, y2; \ // y2 = f^g // CH
+ ; \
+ RORXL $13, a, T1; \ // T1 = a >> 13 // S0B
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1
+ VPSRLQ $17, XTMP2, XTMP2; \ // XTMP2 = W[-2] ror 17 {xBxA}
+ ANDL e, y2; \ // y2 = (f^g)&e // CH
+ ; \
+ RORXL $6, e, y1; \ // y1 = (e >> 6) // S1
+ VPXOR XTMP3, XTMP2, XTMP2; \
+ ADDL h, d; \ // d = k + w + h + d // --
+ ANDL b, y3; \ // y3 = (a|c)&b // MAJA
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1
+ RORXL $22, a, y1; \ // y1 = a >> 22 // S0A
+ VPXOR XTMP2, XTMP4, XTMP4; \ // XTMP4 = s1 {xBxA}
+ XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH
+ ; \
+ VPSHUFB shuff_00BA<>(SB), XTMP4, XTMP4;\ // XTMP4 = s1 {00BA}
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0
+ RORXL $2, a, T1; \ // T1 = (a >> 2) // S0
+ VPADDD XTMP4, XTMP0, XTMP0; \ // XTMP0 = {..., ..., W[1], W[0]}
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0
+ MOVL a, T1; \ // T1 = a // MAJB
+ ANDL c, T1; \ // T1 = a&c // MAJB
+ ADDL y0, y2; \ // y2 = S1 + CH // --
+ VPSHUFD $80, XTMP0, XTMP2; \ // XTMP2 = W[-2] {DDCC}
+ ; \
+ ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ
+ ADDL y1, h; \ // h = k + w + h + S0 // --
+ ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // --
+ ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+ ; \
+ ADDL y3, h // h = t1 + S0 + MAJ // --
+
+#define ROUND_AND_SCHED_N_3(disp, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3) \
+ ; \ // ################################### RND N + 3 ############################
+ ; \
+ MOVL a, y3; \ // y3 = a // MAJA
+ RORXL $25, e, y0; \ // y0 = e >> 25 // S1A
+ RORXL $11, e, y1; \ // y1 = e >> 11 // S1B
+ ADDL (disp + 3*4)(SP)(SRND*1), h; \ // h = k + w + h // --
+ ORL c, y3; \ // y3 = a|c // MAJA
+ ; \
+ VPSRLD $10, XTMP2, XTMP5; \ // XTMP5 = W[-2] >> 10 {DDCC}
+ MOVL f, y2; \ // y2 = f // CH
+ RORXL $13, a, T1; \ // T1 = a >> 13 // S0B
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1
+ XORL g, y2; \ // y2 = f^g // CH
+ ; \
+ VPSRLQ $19, XTMP2, XTMP3; \ // XTMP3 = W[-2] ror 19 {xDxC}
+ RORXL $6, e, y1; \ // y1 = (e >> 6) // S1
+ ANDL e, y2; \ // y2 = (f^g)&e // CH
+ ADDL h, d; \ // d = k + w + h + d // --
+ ANDL b, y3; \ // y3 = (a|c)&b // MAJA
+ ; \
+ VPSRLQ $17, XTMP2, XTMP2; \ // XTMP2 = W[-2] ror 17 {xDxC}
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1
+ XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH
+ ; \
+ VPXOR XTMP3, XTMP2, XTMP2; \
+ RORXL $22, a, y1; \ // y1 = a >> 22 // S0A
+ ADDL y0, y2; \ // y2 = S1 + CH // --
+ ; \
+ VPXOR XTMP2, XTMP5, XTMP5; \ // XTMP5 = s1 {xDxC}
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0
+ ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // --
+ ; \
+ RORXL $2, a, T1; \ // T1 = (a >> 2) // S0
+ ; \
+ VPSHUFB shuff_DC00<>(SB), XTMP5, XTMP5;\ // XTMP5 = s1 {DC00}
+ ; \
+ VPADDD XTMP0, XTMP5, XDWORD0; \ // XDWORD0 = {W[3], W[2], W[1], W[0]}
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0
+ MOVL a, T1; \ // T1 = a // MAJB
+ ANDL c, T1; \ // T1 = a&c // MAJB
+ ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ
+ ; \
+ ADDL y1, h; \ // h = k + w + h + S0 // --
+ ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+ ADDL y3, h // h = t1 + S0 + MAJ // --
+
+#define DO_ROUND_N_0(disp, a, b, c, d, e, f, g, h, old_h) \
+ ; \ // ################################### RND N + 0 ###########################
+ MOVL f, y2; \ // y2 = f // CH
+ RORXL $25, e, y0; \ // y0 = e >> 25 // S1A
+ RORXL $11, e, y1; \ // y1 = e >> 11 // S1B
+ XORL g, y2; \ // y2 = f^g // CH
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1
+ RORXL $6, e, y1; \ // y1 = (e >> 6) // S1
+ ANDL e, y2; \ // y2 = (f^g)&e // CH
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1
+ RORXL $13, a, T1; \ // T1 = a >> 13 // S0B
+ XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH
+ RORXL $22, a, y1; \ // y1 = a >> 22 // S0A
+ MOVL a, y3; \ // y3 = a // MAJA
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0
+ RORXL $2, a, T1; \ // T1 = (a >> 2) // S0
+ ADDL (disp + 0*4)(SP)(SRND*1), h; \ // h = k + w + h // --
+ ORL c, y3; \ // y3 = a|c // MAJA
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0
+ MOVL a, T1; \ // T1 = a // MAJB
+ ANDL b, y3; \ // y3 = (a|c)&b // MAJA
+ ANDL c, T1; \ // T1 = a&c // MAJB
+ ADDL y0, y2; \ // y2 = S1 + CH // --
+ ; \
+ ADDL h, d; \ // d = k + w + h + d // --
+ ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ
+ ADDL y1, h; \ // h = k + w + h + S0 // --
+ ADDL y2, d // d = k + w + h + d + S1 + CH = d + t1 // --
+
+#define DO_ROUND_N_1(disp, a, b, c, d, e, f, g, h, old_h) \
+ ; \ // ################################### RND N + 1 ###########################
+ ADDL y2, old_h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0 // --
+ MOVL f, y2; \ // y2 = f // CH
+ RORXL $25, e, y0; \ // y0 = e >> 25 // S1A
+ RORXL $11, e, y1; \ // y1 = e >> 11 // S1B
+ XORL g, y2; \ // y2 = f^g // CH
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1
+ RORXL $6, e, y1; \ // y1 = (e >> 6) // S1
+ ANDL e, y2; \ // y2 = (f^g)&e // CH
+ ADDL y3, old_h; \ // h = t1 + S0 + MAJ // --
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1
+ RORXL $13, a, T1; \ // T1 = a >> 13 // S0B
+ XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH
+ RORXL $22, a, y1; \ // y1 = a >> 22 // S0A
+ MOVL a, y3; \ // y3 = a // MAJA
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0
+ RORXL $2, a, T1; \ // T1 = (a >> 2) // S0
+ ADDL (disp + 1*4)(SP)(SRND*1), h; \ // h = k + w + h // --
+ ORL c, y3; \ // y3 = a|c // MAJA
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0
+ MOVL a, T1; \ // T1 = a // MAJB
+ ANDL b, y3; \ // y3 = (a|c)&b // MAJA
+ ANDL c, T1; \ // T1 = a&c // MAJB
+ ADDL y0, y2; \ // y2 = S1 + CH // --
+ ; \
+ ADDL h, d; \ // d = k + w + h + d // --
+ ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ
+ ADDL y1, h; \ // h = k + w + h + S0 // --
+ ; \
+ ADDL y2, d // d = k + w + h + d + S1 + CH = d + t1 // --
+
+#define DO_ROUND_N_2(disp, a, b, c, d, e, f, g, h, old_h) \
+ ; \ // ################################### RND N + 2 ##############################
+ ADDL y2, old_h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+ MOVL f, y2; \ // y2 = f // CH
+ RORXL $25, e, y0; \ // y0 = e >> 25 // S1A
+ RORXL $11, e, y1; \ // y1 = e >> 11 // S1B
+ XORL g, y2; \ // y2 = f^g // CH
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1
+ RORXL $6, e, y1; \ // y1 = (e >> 6) // S1
+ ANDL e, y2; \ // y2 = (f^g)&e // CH
+ ADDL y3, old_h; \ // h = t1 + S0 + MAJ // --
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1
+ RORXL $13, a, T1; \ // T1 = a >> 13 // S0B
+ XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH
+ RORXL $22, a, y1; \ // y1 = a >> 22 // S0A
+ MOVL a, y3; \ // y3 = a // MAJA
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0
+ RORXL $2, a, T1; \ // T1 = (a >> 2) // S0
+ ADDL (disp + 2*4)(SP)(SRND*1), h; \ // h = k + w + h // --
+ ORL c, y3; \ // y3 = a|c // MAJA
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0
+ MOVL a, T1; \ // T1 = a // MAJB
+ ANDL b, y3; \ // y3 = (a|c)&b // MAJA
+ ANDL c, T1; \ // T1 = a&c // MAJB
+ ADDL y0, y2; \ // y2 = S1 + CH // --
+ ; \
+ ADDL h, d; \ // d = k + w + h + d // --
+ ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ
+ ADDL y1, h; \ // h = k + w + h + S0 // --
+ ; \
+ ADDL y2, d // d = k + w + h + d + S1 + CH = d + t1 // --
+
+#define DO_ROUND_N_3(disp, a, b, c, d, e, f, g, h, old_h) \
+ ; \ // ################################### RND N + 3 ###########################
+ ADDL y2, old_h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+ MOVL f, y2; \ // y2 = f // CH
+ RORXL $25, e, y0; \ // y0 = e >> 25 // S1A
+ RORXL $11, e, y1; \ // y1 = e >> 11 // S1B
+ XORL g, y2; \ // y2 = f^g // CH
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) // S1
+ RORXL $6, e, y1; \ // y1 = (e >> 6) // S1
+ ANDL e, y2; \ // y2 = (f^g)&e // CH
+ ADDL y3, old_h; \ // h = t1 + S0 + MAJ // --
+ ; \
+ XORL y1, y0; \ // y0 = (e>>25) ^ (e>>11) ^ (e>>6) // S1
+ RORXL $13, a, T1; \ // T1 = a >> 13 // S0B
+ XORL g, y2; \ // y2 = CH = ((f^g)&e)^g // CH
+ RORXL $22, a, y1; \ // y1 = a >> 22 // S0A
+ MOVL a, y3; \ // y3 = a // MAJA
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) // S0
+ RORXL $2, a, T1; \ // T1 = (a >> 2) // S0
+ ADDL (disp + 3*4)(SP)(SRND*1), h; \ // h = k + w + h // --
+ ORL c, y3; \ // y3 = a|c // MAJA
+ ; \
+ XORL T1, y1; \ // y1 = (a>>22) ^ (a>>13) ^ (a>>2) // S0
+ MOVL a, T1; \ // T1 = a // MAJB
+ ANDL b, y3; \ // y3 = (a|c)&b // MAJA
+ ANDL c, T1; \ // T1 = a&c // MAJB
+ ADDL y0, y2; \ // y2 = S1 + CH // --
+ ; \
+ ADDL h, d; \ // d = k + w + h + d // --
+ ORL T1, y3; \ // y3 = MAJ = (a|c)&b)|(a&c) // MAJ
+ ADDL y1, h; \ // h = k + w + h + S0 // --
+ ; \
+ ADDL y2, d; \ // d = k + w + h + d + S1 + CH = d + t1 // --
+ ; \
+ ADDL y2, h; \ // h = k + w + h + S0 + S1 + CH = t1 + S0// --
+ ; \
+ ADDL y3, h // h = t1 + S0 + MAJ // --
+
+TEXT ·block(SB), 0, $536-32
+ CMPB ·useAVX2(SB), $1
+ JE avx2
+
+ MOVQ p_base+8(FP), SI
+ MOVQ p_len+16(FP), DX
+ SHRQ $6, DX
+ SHLQ $6, DX
+
+ LEAQ (SI)(DX*1), DI
+ MOVQ DI, 256(SP)
+ CMPQ SI, DI
+ JEQ end
+
+ MOVQ dig+0(FP), BP
+ MOVL (0*4)(BP), R8 // a = H0
+ MOVL (1*4)(BP), R9 // b = H1
+ MOVL (2*4)(BP), R10 // c = H2
+ MOVL (3*4)(BP), R11 // d = H3
+ MOVL (4*4)(BP), R12 // e = H4
+ MOVL (5*4)(BP), R13 // f = H5
+ MOVL (6*4)(BP), R14 // g = H6
+ MOVL (7*4)(BP), R15 // h = H7
+
+loop:
+ MOVQ SP, BP
+
+ SHA256ROUND0(0, 0x428a2f98, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND0(1, 0x71374491, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND0(2, 0xb5c0fbcf, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND0(3, 0xe9b5dba5, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND0(4, 0x3956c25b, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND0(5, 0x59f111f1, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND0(6, 0x923f82a4, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND0(7, 0xab1c5ed5, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND0(8, 0xd807aa98, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND0(9, 0x12835b01, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND0(10, 0x243185be, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND0(11, 0x550c7dc3, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND0(12, 0x72be5d74, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND0(13, 0x80deb1fe, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND0(14, 0x9bdc06a7, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND0(15, 0xc19bf174, R9, R10, R11, R12, R13, R14, R15, R8)
+
+ SHA256ROUND1(16, 0xe49b69c1, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(17, 0xefbe4786, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(18, 0x0fc19dc6, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(19, 0x240ca1cc, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(20, 0x2de92c6f, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(21, 0x4a7484aa, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(22, 0x5cb0a9dc, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(23, 0x76f988da, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND1(24, 0x983e5152, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(25, 0xa831c66d, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(26, 0xb00327c8, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(27, 0xbf597fc7, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(28, 0xc6e00bf3, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(29, 0xd5a79147, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(30, 0x06ca6351, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(31, 0x14292967, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND1(32, 0x27b70a85, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(33, 0x2e1b2138, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(34, 0x4d2c6dfc, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(35, 0x53380d13, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(36, 0x650a7354, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(37, 0x766a0abb, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(38, 0x81c2c92e, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(39, 0x92722c85, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND1(40, 0xa2bfe8a1, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(41, 0xa81a664b, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(42, 0xc24b8b70, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(43, 0xc76c51a3, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(44, 0xd192e819, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(45, 0xd6990624, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(46, 0xf40e3585, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(47, 0x106aa070, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND1(48, 0x19a4c116, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(49, 0x1e376c08, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(50, 0x2748774c, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(51, 0x34b0bcb5, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(52, 0x391c0cb3, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(53, 0x4ed8aa4a, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(54, 0x5b9cca4f, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(55, 0x682e6ff3, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA256ROUND1(56, 0x748f82ee, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA256ROUND1(57, 0x78a5636f, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA256ROUND1(58, 0x84c87814, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA256ROUND1(59, 0x8cc70208, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA256ROUND1(60, 0x90befffa, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA256ROUND1(61, 0xa4506ceb, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA256ROUND1(62, 0xbef9a3f7, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA256ROUND1(63, 0xc67178f2, R9, R10, R11, R12, R13, R14, R15, R8)
+
+ MOVQ dig+0(FP), BP
+ ADDL (0*4)(BP), R8 // H0 = a + H0
+ MOVL R8, (0*4)(BP)
+ ADDL (1*4)(BP), R9 // H1 = b + H1
+ MOVL R9, (1*4)(BP)
+ ADDL (2*4)(BP), R10 // H2 = c + H2
+ MOVL R10, (2*4)(BP)
+ ADDL (3*4)(BP), R11 // H3 = d + H3
+ MOVL R11, (3*4)(BP)
+ ADDL (4*4)(BP), R12 // H4 = e + H4
+ MOVL R12, (4*4)(BP)
+ ADDL (5*4)(BP), R13 // H5 = f + H5
+ MOVL R13, (5*4)(BP)
+ ADDL (6*4)(BP), R14 // H6 = g + H6
+ MOVL R14, (6*4)(BP)
+ ADDL (7*4)(BP), R15 // H7 = h + H7
+ MOVL R15, (7*4)(BP)
+
+ ADDQ $64, SI
+ CMPQ SI, 256(SP)
+ JB loop
+
+end:
+ RET
+
+avx2:
+ MOVQ dig+0(FP), CTX // d.h[8]
+ MOVQ p_base+8(FP), INP
+ MOVQ p_len+16(FP), NUM_BYTES
+
+ LEAQ -64(INP)(NUM_BYTES*1), NUM_BYTES // Pointer to the last block
+ MOVQ NUM_BYTES, _INP_END(SP)
+
+ CMPQ NUM_BYTES, INP
+ JE avx2_only_one_block
+
+ // Load initial digest
+ MOVL 0(CTX), a // a = H0
+ MOVL 4(CTX), b // b = H1
+ MOVL 8(CTX), c // c = H2
+ MOVL 12(CTX), d // d = H3
+ MOVL 16(CTX), e // e = H4
+ MOVL 20(CTX), f // f = H5
+ MOVL 24(CTX), g // g = H6
+ MOVL 28(CTX), h // h = H7
+
+avx2_loop0: // at each iteration works with one block (512 bit)
+
+ VMOVDQU (0*32)(INP), XTMP0
+ VMOVDQU (1*32)(INP), XTMP1
+ VMOVDQU (2*32)(INP), XTMP2
+ VMOVDQU (3*32)(INP), XTMP3
+
+ VMOVDQU flip_mask<>(SB), BYTE_FLIP_MASK
+
+ // Apply Byte Flip Mask: LE -> BE
+ VPSHUFB BYTE_FLIP_MASK, XTMP0, XTMP0
+ VPSHUFB BYTE_FLIP_MASK, XTMP1, XTMP1
+ VPSHUFB BYTE_FLIP_MASK, XTMP2, XTMP2
+ VPSHUFB BYTE_FLIP_MASK, XTMP3, XTMP3
+
+ // Transpose data into high/low parts
+ VPERM2I128 $0x20, XTMP2, XTMP0, XDWORD0 // w3, w2, w1, w0
+ VPERM2I128 $0x31, XTMP2, XTMP0, XDWORD1 // w7, w6, w5, w4
+ VPERM2I128 $0x20, XTMP3, XTMP1, XDWORD2 // w11, w10, w9, w8
+ VPERM2I128 $0x31, XTMP3, XTMP1, XDWORD3 // w15, w14, w13, w12
+
+ MOVQ $K256<>(SB), TBL // Loading address of table with round-specific constants
+
+avx2_last_block_enter:
+ ADDQ $64, INP
+ MOVQ INP, _INP(SP)
+ XORQ SRND, SRND
+
+avx2_loop1: // for w0 - w47
+ // Do 4 rounds and scheduling
+ VPADDD 0*32(TBL)(SRND*1), XDWORD0, XFER
+ VMOVDQU XFER, (_XFER + 0*32)(SP)(SRND*1)
+ ROUND_AND_SCHED_N_0(_XFER + 0*32, a, b, c, d, e, f, g, h, XDWORD0, XDWORD1, XDWORD2, XDWORD3)
+ ROUND_AND_SCHED_N_1(_XFER + 0*32, h, a, b, c, d, e, f, g, XDWORD0, XDWORD1, XDWORD2, XDWORD3)
+ ROUND_AND_SCHED_N_2(_XFER + 0*32, g, h, a, b, c, d, e, f, XDWORD0, XDWORD1, XDWORD2, XDWORD3)
+ ROUND_AND_SCHED_N_3(_XFER + 0*32, f, g, h, a, b, c, d, e, XDWORD0, XDWORD1, XDWORD2, XDWORD3)
+
+ // Do 4 rounds and scheduling
+ VPADDD 1*32(TBL)(SRND*1), XDWORD1, XFER
+ VMOVDQU XFER, (_XFER + 1*32)(SP)(SRND*1)
+ ROUND_AND_SCHED_N_0(_XFER + 1*32, e, f, g, h, a, b, c, d, XDWORD1, XDWORD2, XDWORD3, XDWORD0)
+ ROUND_AND_SCHED_N_1(_XFER + 1*32, d, e, f, g, h, a, b, c, XDWORD1, XDWORD2, XDWORD3, XDWORD0)
+ ROUND_AND_SCHED_N_2(_XFER + 1*32, c, d, e, f, g, h, a, b, XDWORD1, XDWORD2, XDWORD3, XDWORD0)
+ ROUND_AND_SCHED_N_3(_XFER + 1*32, b, c, d, e, f, g, h, a, XDWORD1, XDWORD2, XDWORD3, XDWORD0)
+
+ // Do 4 rounds and scheduling
+ VPADDD 2*32(TBL)(SRND*1), XDWORD2, XFER
+ VMOVDQU XFER, (_XFER + 2*32)(SP)(SRND*1)
+ ROUND_AND_SCHED_N_0(_XFER + 2*32, a, b, c, d, e, f, g, h, XDWORD2, XDWORD3, XDWORD0, XDWORD1)
+ ROUND_AND_SCHED_N_1(_XFER + 2*32, h, a, b, c, d, e, f, g, XDWORD2, XDWORD3, XDWORD0, XDWORD1)
+ ROUND_AND_SCHED_N_2(_XFER + 2*32, g, h, a, b, c, d, e, f, XDWORD2, XDWORD3, XDWORD0, XDWORD1)
+ ROUND_AND_SCHED_N_3(_XFER + 2*32, f, g, h, a, b, c, d, e, XDWORD2, XDWORD3, XDWORD0, XDWORD1)
+
+ // Do 4 rounds and scheduling
+ VPADDD 3*32(TBL)(SRND*1), XDWORD3, XFER
+ VMOVDQU XFER, (_XFER + 3*32)(SP)(SRND*1)
+ ROUND_AND_SCHED_N_0(_XFER + 3*32, e, f, g, h, a, b, c, d, XDWORD3, XDWORD0, XDWORD1, XDWORD2)
+ ROUND_AND_SCHED_N_1(_XFER + 3*32, d, e, f, g, h, a, b, c, XDWORD3, XDWORD0, XDWORD1, XDWORD2)
+ ROUND_AND_SCHED_N_2(_XFER + 3*32, c, d, e, f, g, h, a, b, XDWORD3, XDWORD0, XDWORD1, XDWORD2)
+ ROUND_AND_SCHED_N_3(_XFER + 3*32, b, c, d, e, f, g, h, a, XDWORD3, XDWORD0, XDWORD1, XDWORD2)
+
+ ADDQ $4*32, SRND
+ CMPQ SRND, $3*4*32
+ JB avx2_loop1
+
+avx2_loop2:
+ // w48 - w63 processed with no scheduling (last 16 rounds)
+ VPADDD 0*32(TBL)(SRND*1), XDWORD0, XFER
+ VMOVDQU XFER, (_XFER + 0*32)(SP)(SRND*1)
+ DO_ROUND_N_0(_XFER + 0*32, a, b, c, d, e, f, g, h, h)
+ DO_ROUND_N_1(_XFER + 0*32, h, a, b, c, d, e, f, g, h)
+ DO_ROUND_N_2(_XFER + 0*32, g, h, a, b, c, d, e, f, g)
+ DO_ROUND_N_3(_XFER + 0*32, f, g, h, a, b, c, d, e, f)
+
+ VPADDD 1*32(TBL)(SRND*1), XDWORD1, XFER
+ VMOVDQU XFER, (_XFER + 1*32)(SP)(SRND*1)
+ DO_ROUND_N_0(_XFER + 1*32, e, f, g, h, a, b, c, d, e)
+ DO_ROUND_N_1(_XFER + 1*32, d, e, f, g, h, a, b, c, d)
+ DO_ROUND_N_2(_XFER + 1*32, c, d, e, f, g, h, a, b, c)
+ DO_ROUND_N_3(_XFER + 1*32, b, c, d, e, f, g, h, a, b)
+
+ ADDQ $2*32, SRND
+
+ VMOVDQU XDWORD2, XDWORD0
+ VMOVDQU XDWORD3, XDWORD1
+
+ CMPQ SRND, $4*4*32
+ JB avx2_loop2
+
+ MOVQ dig+0(FP), CTX // d.h[8]
+ MOVQ _INP(SP), INP
+
+ addm( 0(CTX), a)
+ addm( 4(CTX), b)
+ addm( 8(CTX), c)
+ addm( 12(CTX), d)
+ addm( 16(CTX), e)
+ addm( 20(CTX), f)
+ addm( 24(CTX), g)
+ addm( 28(CTX), h)
+
+ CMPQ _INP_END(SP), INP
+ JB done_hash
+
+ XORQ SRND, SRND
+
+avx2_loop3: // Do second block using previously scheduled results
+ DO_ROUND_N_0(_XFER + 0*32 + 16, a, b, c, d, e, f, g, h, a)
+ DO_ROUND_N_1(_XFER + 0*32 + 16, h, a, b, c, d, e, f, g, h)
+ DO_ROUND_N_2(_XFER + 0*32 + 16, g, h, a, b, c, d, e, f, g)
+ DO_ROUND_N_3(_XFER + 0*32 + 16, f, g, h, a, b, c, d, e, f)
+
+ DO_ROUND_N_0(_XFER + 1*32 + 16, e, f, g, h, a, b, c, d, e)
+ DO_ROUND_N_1(_XFER + 1*32 + 16, d, e, f, g, h, a, b, c, d)
+ DO_ROUND_N_2(_XFER + 1*32 + 16, c, d, e, f, g, h, a, b, c)
+ DO_ROUND_N_3(_XFER + 1*32 + 16, b, c, d, e, f, g, h, a, b)
+
+ ADDQ $2*32, SRND
+ CMPQ SRND, $4*4*32
+ JB avx2_loop3
+
+ MOVQ dig+0(FP), CTX // d.h[8]
+ MOVQ _INP(SP), INP
+ ADDQ $64, INP
+
+ addm( 0(CTX), a)
+ addm( 4(CTX), b)
+ addm( 8(CTX), c)
+ addm( 12(CTX), d)
+ addm( 16(CTX), e)
+ addm( 20(CTX), f)
+ addm( 24(CTX), g)
+ addm( 28(CTX), h)
+
+ CMPQ _INP_END(SP), INP
+ JA avx2_loop0
+ JB done_hash
+
+avx2_do_last_block:
+
+ VMOVDQU 0(INP), XWORD0
+ VMOVDQU 16(INP), XWORD1
+ VMOVDQU 32(INP), XWORD2
+ VMOVDQU 48(INP), XWORD3
+
+ VMOVDQU flip_mask<>(SB), BYTE_FLIP_MASK
+
+ VPSHUFB X_BYTE_FLIP_MASK, XWORD0, XWORD0
+ VPSHUFB X_BYTE_FLIP_MASK, XWORD1, XWORD1
+ VPSHUFB X_BYTE_FLIP_MASK, XWORD2, XWORD2
+ VPSHUFB X_BYTE_FLIP_MASK, XWORD3, XWORD3
+
+ MOVQ $K256<>(SB), TBL
+
+ JMP avx2_last_block_enter
+
+avx2_only_one_block:
+ // Load initial digest
+ MOVL 0(CTX), a // a = H0
+ MOVL 4(CTX), b // b = H1
+ MOVL 8(CTX), c // c = H2
+ MOVL 12(CTX), d // d = H3
+ MOVL 16(CTX), e // e = H4
+ MOVL 20(CTX), f // f = H5
+ MOVL 24(CTX), g // g = H6
+ MOVL 28(CTX), h // h = H7
+
+ JMP avx2_do_last_block
+
+done_hash:
+ VZEROUPPER
+ RET
+
+// shuffle byte order from LE to BE
+DATA flip_mask<>+0x00(SB)/8, $0x0405060700010203
+DATA flip_mask<>+0x08(SB)/8, $0x0c0d0e0f08090a0b
+DATA flip_mask<>+0x10(SB)/8, $0x0405060700010203
+DATA flip_mask<>+0x18(SB)/8, $0x0c0d0e0f08090a0b
+GLOBL flip_mask<>(SB), 8, $32
+
+// shuffle xBxA -> 00BA
+DATA shuff_00BA<>+0x00(SB)/8, $0x0b0a090803020100
+DATA shuff_00BA<>+0x08(SB)/8, $0xFFFFFFFFFFFFFFFF
+DATA shuff_00BA<>+0x10(SB)/8, $0x0b0a090803020100
+DATA shuff_00BA<>+0x18(SB)/8, $0xFFFFFFFFFFFFFFFF
+GLOBL shuff_00BA<>(SB), 8, $32
+
+// shuffle xDxC -> DC00
+DATA shuff_DC00<>+0x00(SB)/8, $0xFFFFFFFFFFFFFFFF
+DATA shuff_DC00<>+0x08(SB)/8, $0x0b0a090803020100
+DATA shuff_DC00<>+0x10(SB)/8, $0xFFFFFFFFFFFFFFFF
+DATA shuff_DC00<>+0x18(SB)/8, $0x0b0a090803020100
+GLOBL shuff_DC00<>(SB), 8, $32
+
+// Round specific constants
+DATA K256<>+0x00(SB)/4, $0x428a2f98 // k1
+DATA K256<>+0x04(SB)/4, $0x71374491 // k2
+DATA K256<>+0x08(SB)/4, $0xb5c0fbcf // k3
+DATA K256<>+0x0c(SB)/4, $0xe9b5dba5 // k4
+DATA K256<>+0x10(SB)/4, $0x428a2f98 // k1
+DATA K256<>+0x14(SB)/4, $0x71374491 // k2
+DATA K256<>+0x18(SB)/4, $0xb5c0fbcf // k3
+DATA K256<>+0x1c(SB)/4, $0xe9b5dba5 // k4
+
+DATA K256<>+0x20(SB)/4, $0x3956c25b // k5 - k8
+DATA K256<>+0x24(SB)/4, $0x59f111f1
+DATA K256<>+0x28(SB)/4, $0x923f82a4
+DATA K256<>+0x2c(SB)/4, $0xab1c5ed5
+DATA K256<>+0x30(SB)/4, $0x3956c25b
+DATA K256<>+0x34(SB)/4, $0x59f111f1
+DATA K256<>+0x38(SB)/4, $0x923f82a4
+DATA K256<>+0x3c(SB)/4, $0xab1c5ed5
+
+DATA K256<>+0x40(SB)/4, $0xd807aa98 // k9 - k12
+DATA K256<>+0x44(SB)/4, $0x12835b01
+DATA K256<>+0x48(SB)/4, $0x243185be
+DATA K256<>+0x4c(SB)/4, $0x550c7dc3
+DATA K256<>+0x50(SB)/4, $0xd807aa98
+DATA K256<>+0x54(SB)/4, $0x12835b01
+DATA K256<>+0x58(SB)/4, $0x243185be
+DATA K256<>+0x5c(SB)/4, $0x550c7dc3
+
+DATA K256<>+0x60(SB)/4, $0x72be5d74 // k13 - k16
+DATA K256<>+0x64(SB)/4, $0x80deb1fe
+DATA K256<>+0x68(SB)/4, $0x9bdc06a7
+DATA K256<>+0x6c(SB)/4, $0xc19bf174
+DATA K256<>+0x70(SB)/4, $0x72be5d74
+DATA K256<>+0x74(SB)/4, $0x80deb1fe
+DATA K256<>+0x78(SB)/4, $0x9bdc06a7
+DATA K256<>+0x7c(SB)/4, $0xc19bf174
+
+DATA K256<>+0x80(SB)/4, $0xe49b69c1 // k17 - k20
+DATA K256<>+0x84(SB)/4, $0xefbe4786
+DATA K256<>+0x88(SB)/4, $0x0fc19dc6
+DATA K256<>+0x8c(SB)/4, $0x240ca1cc
+DATA K256<>+0x90(SB)/4, $0xe49b69c1
+DATA K256<>+0x94(SB)/4, $0xefbe4786
+DATA K256<>+0x98(SB)/4, $0x0fc19dc6
+DATA K256<>+0x9c(SB)/4, $0x240ca1cc
+
+DATA K256<>+0xa0(SB)/4, $0x2de92c6f // k21 - k24
+DATA K256<>+0xa4(SB)/4, $0x4a7484aa
+DATA K256<>+0xa8(SB)/4, $0x5cb0a9dc
+DATA K256<>+0xac(SB)/4, $0x76f988da
+DATA K256<>+0xb0(SB)/4, $0x2de92c6f
+DATA K256<>+0xb4(SB)/4, $0x4a7484aa
+DATA K256<>+0xb8(SB)/4, $0x5cb0a9dc
+DATA K256<>+0xbc(SB)/4, $0x76f988da
+
+DATA K256<>+0xc0(SB)/4, $0x983e5152 // k25 - k28
+DATA K256<>+0xc4(SB)/4, $0xa831c66d
+DATA K256<>+0xc8(SB)/4, $0xb00327c8
+DATA K256<>+0xcc(SB)/4, $0xbf597fc7
+DATA K256<>+0xd0(SB)/4, $0x983e5152
+DATA K256<>+0xd4(SB)/4, $0xa831c66d
+DATA K256<>+0xd8(SB)/4, $0xb00327c8
+DATA K256<>+0xdc(SB)/4, $0xbf597fc7
+
+DATA K256<>+0xe0(SB)/4, $0xc6e00bf3 // k29 - k32
+DATA K256<>+0xe4(SB)/4, $0xd5a79147
+DATA K256<>+0xe8(SB)/4, $0x06ca6351
+DATA K256<>+0xec(SB)/4, $0x14292967
+DATA K256<>+0xf0(SB)/4, $0xc6e00bf3
+DATA K256<>+0xf4(SB)/4, $0xd5a79147
+DATA K256<>+0xf8(SB)/4, $0x06ca6351
+DATA K256<>+0xfc(SB)/4, $0x14292967
+
+DATA K256<>+0x100(SB)/4, $0x27b70a85
+DATA K256<>+0x104(SB)/4, $0x2e1b2138
+DATA K256<>+0x108(SB)/4, $0x4d2c6dfc
+DATA K256<>+0x10c(SB)/4, $0x53380d13
+DATA K256<>+0x110(SB)/4, $0x27b70a85
+DATA K256<>+0x114(SB)/4, $0x2e1b2138
+DATA K256<>+0x118(SB)/4, $0x4d2c6dfc
+DATA K256<>+0x11c(SB)/4, $0x53380d13
+
+DATA K256<>+0x120(SB)/4, $0x650a7354
+DATA K256<>+0x124(SB)/4, $0x766a0abb
+DATA K256<>+0x128(SB)/4, $0x81c2c92e
+DATA K256<>+0x12c(SB)/4, $0x92722c85
+DATA K256<>+0x130(SB)/4, $0x650a7354
+DATA K256<>+0x134(SB)/4, $0x766a0abb
+DATA K256<>+0x138(SB)/4, $0x81c2c92e
+DATA K256<>+0x13c(SB)/4, $0x92722c85
+
+DATA K256<>+0x140(SB)/4, $0xa2bfe8a1
+DATA K256<>+0x144(SB)/4, $0xa81a664b
+DATA K256<>+0x148(SB)/4, $0xc24b8b70
+DATA K256<>+0x14c(SB)/4, $0xc76c51a3
+DATA K256<>+0x150(SB)/4, $0xa2bfe8a1
+DATA K256<>+0x154(SB)/4, $0xa81a664b
+DATA K256<>+0x158(SB)/4, $0xc24b8b70
+DATA K256<>+0x15c(SB)/4, $0xc76c51a3
+
+DATA K256<>+0x160(SB)/4, $0xd192e819
+DATA K256<>+0x164(SB)/4, $0xd6990624
+DATA K256<>+0x168(SB)/4, $0xf40e3585
+DATA K256<>+0x16c(SB)/4, $0x106aa070
+DATA K256<>+0x170(SB)/4, $0xd192e819
+DATA K256<>+0x174(SB)/4, $0xd6990624
+DATA K256<>+0x178(SB)/4, $0xf40e3585
+DATA K256<>+0x17c(SB)/4, $0x106aa070
+
+DATA K256<>+0x180(SB)/4, $0x19a4c116
+DATA K256<>+0x184(SB)/4, $0x1e376c08
+DATA K256<>+0x188(SB)/4, $0x2748774c
+DATA K256<>+0x18c(SB)/4, $0x34b0bcb5
+DATA K256<>+0x190(SB)/4, $0x19a4c116
+DATA K256<>+0x194(SB)/4, $0x1e376c08
+DATA K256<>+0x198(SB)/4, $0x2748774c
+DATA K256<>+0x19c(SB)/4, $0x34b0bcb5
+
+DATA K256<>+0x1a0(SB)/4, $0x391c0cb3
+DATA K256<>+0x1a4(SB)/4, $0x4ed8aa4a
+DATA K256<>+0x1a8(SB)/4, $0x5b9cca4f
+DATA K256<>+0x1ac(SB)/4, $0x682e6ff3
+DATA K256<>+0x1b0(SB)/4, $0x391c0cb3
+DATA K256<>+0x1b4(SB)/4, $0x4ed8aa4a
+DATA K256<>+0x1b8(SB)/4, $0x5b9cca4f
+DATA K256<>+0x1bc(SB)/4, $0x682e6ff3
+
+DATA K256<>+0x1c0(SB)/4, $0x748f82ee
+DATA K256<>+0x1c4(SB)/4, $0x78a5636f
+DATA K256<>+0x1c8(SB)/4, $0x84c87814
+DATA K256<>+0x1cc(SB)/4, $0x8cc70208
+DATA K256<>+0x1d0(SB)/4, $0x748f82ee
+DATA K256<>+0x1d4(SB)/4, $0x78a5636f
+DATA K256<>+0x1d8(SB)/4, $0x84c87814
+DATA K256<>+0x1dc(SB)/4, $0x8cc70208
+
+DATA K256<>+0x1e0(SB)/4, $0x90befffa
+DATA K256<>+0x1e4(SB)/4, $0xa4506ceb
+DATA K256<>+0x1e8(SB)/4, $0xbef9a3f7
+DATA K256<>+0x1ec(SB)/4, $0xc67178f2
+DATA K256<>+0x1f0(SB)/4, $0x90befffa
+DATA K256<>+0x1f4(SB)/4, $0xa4506ceb
+DATA K256<>+0x1f8(SB)/4, $0xbef9a3f7
+DATA K256<>+0x1fc(SB)/4, $0xc67178f2
+
+GLOBL K256<>(SB), (NOPTR + RODATA), $512
diff --git a/src/crypto/sha256/sha256block_arm64.go b/src/crypto/sha256/sha256block_arm64.go
new file mode 100644
index 0000000..e5da566
--- /dev/null
+++ b/src/crypto/sha256/sha256block_arm64.go
@@ -0,0 +1,21 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha256
+
+import "internal/cpu"
+
+var k = _K
+
+//go:noescape
+func sha256block(h []uint32, p []byte, k []uint32)
+
+func block(dig *digest, p []byte) {
+ if !cpu.ARM64.HasSHA2 {
+ blockGeneric(dig, p)
+ } else {
+ h := dig.h[:]
+ sha256block(h, p, k)
+ }
+}
diff --git a/src/crypto/sha256/sha256block_arm64.s b/src/crypto/sha256/sha256block_arm64.s
new file mode 100644
index 0000000..d5c1eb0
--- /dev/null
+++ b/src/crypto/sha256/sha256block_arm64.s
@@ -0,0 +1,119 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+#define HASHUPDATE \
+ SHA256H V9.S4, V3, V2 \
+ SHA256H2 V9.S4, V8, V3 \
+ VMOV V2.B16, V8.B16
+
+// func sha256block(h []uint32, p []byte, k []uint32)
+TEXT ·sha256block(SB),NOSPLIT,$0
+ MOVD h_base+0(FP), R0 // Hash value first address
+ MOVD p_base+24(FP), R1 // message first address
+ MOVD k_base+48(FP), R2 // k constants first address
+ MOVD p_len+32(FP), R3 // message length
+ VLD1 (R0), [V0.S4, V1.S4] // load h(a,b,c,d,e,f,g,h)
+ VLD1.P 64(R2), [V16.S4, V17.S4, V18.S4, V19.S4]
+ VLD1.P 64(R2), [V20.S4, V21.S4, V22.S4, V23.S4]
+ VLD1.P 64(R2), [V24.S4, V25.S4, V26.S4, V27.S4]
+ VLD1 (R2), [V28.S4, V29.S4, V30.S4, V31.S4] //load 64*4bytes K constant(K0-K63)
+
+blockloop:
+
+ VLD1.P 16(R1), [V4.B16] // load 16bytes message
+ VLD1.P 16(R1), [V5.B16] // load 16bytes message
+ VLD1.P 16(R1), [V6.B16] // load 16bytes message
+ VLD1.P 16(R1), [V7.B16] // load 16bytes message
+ VMOV V0.B16, V2.B16 // backup: VO h(dcba)
+ VMOV V1.B16, V3.B16 // backup: V1 h(hgfe)
+ VMOV V2.B16, V8.B16
+ VREV32 V4.B16, V4.B16 // prepare for using message in Byte format
+ VREV32 V5.B16, V5.B16
+ VREV32 V6.B16, V6.B16
+ VREV32 V7.B16, V7.B16
+
+ VADD V16.S4, V4.S4, V9.S4 // V18(W0+K0...W3+K3)
+ SHA256SU0 V5.S4, V4.S4 // V4: (su0(W1)+W0,...,su0(W4)+W3)
+ HASHUPDATE // H4
+
+ VADD V17.S4, V5.S4, V9.S4 // V18(W4+K4...W7+K7)
+ SHA256SU0 V6.S4, V5.S4 // V5: (su0(W5)+W4,...,su0(W8)+W7)
+ SHA256SU1 V7.S4, V6.S4, V4.S4 // V4: W16-W19
+ HASHUPDATE // H8
+
+ VADD V18.S4, V6.S4, V9.S4 // V18(W8+K8...W11+K11)
+ SHA256SU0 V7.S4, V6.S4 // V6: (su0(W9)+W8,...,su0(W12)+W11)
+ SHA256SU1 V4.S4, V7.S4, V5.S4 // V5: W20-W23
+ HASHUPDATE // H12
+
+ VADD V19.S4, V7.S4, V9.S4 // V18(W12+K12...W15+K15)
+ SHA256SU0 V4.S4, V7.S4 // V7: (su0(W13)+W12,...,su0(W16)+W15)
+ SHA256SU1 V5.S4, V4.S4, V6.S4 // V6: W24-W27
+ HASHUPDATE // H16
+
+ VADD V20.S4, V4.S4, V9.S4 // V18(W16+K16...W19+K19)
+ SHA256SU0 V5.S4, V4.S4 // V4: (su0(W17)+W16,...,su0(W20)+W19)
+ SHA256SU1 V6.S4, V5.S4, V7.S4 // V7: W28-W31
+ HASHUPDATE // H20
+
+ VADD V21.S4, V5.S4, V9.S4 // V18(W20+K20...W23+K23)
+ SHA256SU0 V6.S4, V5.S4 // V5: (su0(W21)+W20,...,su0(W24)+W23)
+ SHA256SU1 V7.S4, V6.S4, V4.S4 // V4: W32-W35
+ HASHUPDATE // H24
+
+ VADD V22.S4, V6.S4, V9.S4 // V18(W24+K24...W27+K27)
+ SHA256SU0 V7.S4, V6.S4 // V6: (su0(W25)+W24,...,su0(W28)+W27)
+ SHA256SU1 V4.S4, V7.S4, V5.S4 // V5: W36-W39
+ HASHUPDATE // H28
+
+ VADD V23.S4, V7.S4, V9.S4 // V18(W28+K28...W31+K31)
+ SHA256SU0 V4.S4, V7.S4 // V7: (su0(W29)+W28,...,su0(W32)+W31)
+ SHA256SU1 V5.S4, V4.S4, V6.S4 // V6: W40-W43
+ HASHUPDATE // H32
+
+ VADD V24.S4, V4.S4, V9.S4 // V18(W32+K32...W35+K35)
+ SHA256SU0 V5.S4, V4.S4 // V4: (su0(W33)+W32,...,su0(W36)+W35)
+ SHA256SU1 V6.S4, V5.S4, V7.S4 // V7: W44-W47
+ HASHUPDATE // H36
+
+ VADD V25.S4, V5.S4, V9.S4 // V18(W36+K36...W39+K39)
+ SHA256SU0 V6.S4, V5.S4 // V5: (su0(W37)+W36,...,su0(W40)+W39)
+ SHA256SU1 V7.S4, V6.S4, V4.S4 // V4: W48-W51
+ HASHUPDATE // H40
+
+ VADD V26.S4, V6.S4, V9.S4 // V18(W40+K40...W43+K43)
+ SHA256SU0 V7.S4, V6.S4 // V6: (su0(W41)+W40,...,su0(W44)+W43)
+ SHA256SU1 V4.S4, V7.S4, V5.S4 // V5: W52-W55
+ HASHUPDATE // H44
+
+ VADD V27.S4, V7.S4, V9.S4 // V18(W44+K44...W47+K47)
+ SHA256SU0 V4.S4, V7.S4 // V7: (su0(W45)+W44,...,su0(W48)+W47)
+ SHA256SU1 V5.S4, V4.S4, V6.S4 // V6: W56-W59
+ HASHUPDATE // H48
+
+ VADD V28.S4, V4.S4, V9.S4 // V18(W48+K48,...,W51+K51)
+ HASHUPDATE // H52
+ SHA256SU1 V6.S4, V5.S4, V7.S4 // V7: W60-W63
+
+ VADD V29.S4, V5.S4, V9.S4 // V18(W52+K52,...,W55+K55)
+ HASHUPDATE // H56
+
+ VADD V30.S4, V6.S4, V9.S4 // V18(W59+K59,...,W59+K59)
+ HASHUPDATE // H60
+
+ VADD V31.S4, V7.S4, V9.S4 // V18(W60+K60,...,W63+K63)
+ HASHUPDATE // H64
+
+ SUB $64, R3, R3 // message length - 64bytes, then compare with 64bytes
+ VADD V2.S4, V0.S4, V0.S4
+ VADD V3.S4, V1.S4, V1.S4
+ CBNZ R3, blockloop
+
+sha256ret:
+
+ VST1 [V0.S4, V1.S4], (R0) // store hash value H
+ RET
+
diff --git a/src/crypto/sha256/sha256block_decl.go b/src/crypto/sha256/sha256block_decl.go
new file mode 100644
index 0000000..18ba1c0
--- /dev/null
+++ b/src/crypto/sha256/sha256block_decl.go
@@ -0,0 +1,11 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build 386 || amd64 || s390x || ppc64le || ppc64
+
+package sha256
+
+//go:noescape
+
+func block(dig *digest, p []byte)
diff --git a/src/crypto/sha256/sha256block_generic.go b/src/crypto/sha256/sha256block_generic.go
new file mode 100644
index 0000000..fd098be
--- /dev/null
+++ b/src/crypto/sha256/sha256block_generic.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !amd64 && !386 && !s390x && !ppc64le && !ppc64 && !arm64
+
+package sha256
+
+func block(dig *digest, p []byte) {
+ blockGeneric(dig, p)
+}
diff --git a/src/crypto/sha256/sha256block_ppc64x.s b/src/crypto/sha256/sha256block_ppc64x.s
new file mode 100644
index 0000000..b229ef6
--- /dev/null
+++ b/src/crypto/sha256/sha256block_ppc64x.s
@@ -0,0 +1,453 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build ppc64 || ppc64le
+
+// Based on CRYPTOGAMS code with the following comment:
+// # ====================================================================
+// # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+// # project. The module is, however, dual licensed under OpenSSL and
+// # CRYPTOGAMS licenses depending on where you obtain it. For further
+// # details see http://www.openssl.org/~appro/cryptogams/.
+// # ====================================================================
+
+#include "textflag.h"
+
+// SHA256 block routine. See sha256block.go for Go equivalent.
+//
+// The algorithm is detailed in FIPS 180-4:
+//
+// https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+//
+// Wt = Mt; for 0 <= t <= 15
+// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 63
+//
+// a = H0
+// b = H1
+// c = H2
+// d = H3
+// e = H4
+// f = H5
+// g = H6
+// h = H7
+//
+// for t = 0 to 63 {
+// T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt
+// T2 = BIGSIGMA0(a) + Maj(a,b,c)
+// h = g
+// g = f
+// f = e
+// e = d + T1
+// d = c
+// c = b
+// b = a
+// a = T1 + T2
+// }
+//
+// H0 = a + H0
+// H1 = b + H1
+// H2 = c + H2
+// H3 = d + H3
+// H4 = e + H4
+// H5 = f + H5
+// H6 = g + H6
+// H7 = h + H7
+
+#define CTX R3
+#define INP R4
+#define END R5
+#define TBL R6 // Pointer into kcon table
+#define LEN R9
+#define TEMP R12
+
+#define TBL_STRT R7 // Pointer to start of kcon table.
+
+#define R_x000 R0
+#define R_x010 R8
+#define R_x020 R10
+#define R_x030 R11
+#define R_x040 R14
+#define R_x050 R15
+#define R_x060 R16
+#define R_x070 R17
+#define R_x080 R18
+#define R_x090 R19
+#define R_x0a0 R20
+#define R_x0b0 R21
+#define R_x0c0 R22
+#define R_x0d0 R23
+#define R_x0e0 R24
+#define R_x0f0 R25
+#define R_x100 R26
+#define R_x110 R27
+
+
+// V0-V7 are A-H
+// V8-V23 are used for the message schedule
+#define KI V24
+#define FUNC V25
+#define S0 V26
+#define S1 V27
+#define s0 V28
+#define s1 V29
+#define LEMASK V31 // Permutation control register for little endian
+
+// 4 copies of each Kt, to fill all 4 words of a vector register
+DATA ·kcon+0x000(SB)/8, $0x428a2f98428a2f98
+DATA ·kcon+0x008(SB)/8, $0x428a2f98428a2f98
+DATA ·kcon+0x010(SB)/8, $0x7137449171374491
+DATA ·kcon+0x018(SB)/8, $0x7137449171374491
+DATA ·kcon+0x020(SB)/8, $0xb5c0fbcfb5c0fbcf
+DATA ·kcon+0x028(SB)/8, $0xb5c0fbcfb5c0fbcf
+DATA ·kcon+0x030(SB)/8, $0xe9b5dba5e9b5dba5
+DATA ·kcon+0x038(SB)/8, $0xe9b5dba5e9b5dba5
+DATA ·kcon+0x040(SB)/8, $0x3956c25b3956c25b
+DATA ·kcon+0x048(SB)/8, $0x3956c25b3956c25b
+DATA ·kcon+0x050(SB)/8, $0x59f111f159f111f1
+DATA ·kcon+0x058(SB)/8, $0x59f111f159f111f1
+DATA ·kcon+0x060(SB)/8, $0x923f82a4923f82a4
+DATA ·kcon+0x068(SB)/8, $0x923f82a4923f82a4
+DATA ·kcon+0x070(SB)/8, $0xab1c5ed5ab1c5ed5
+DATA ·kcon+0x078(SB)/8, $0xab1c5ed5ab1c5ed5
+DATA ·kcon+0x080(SB)/8, $0xd807aa98d807aa98
+DATA ·kcon+0x088(SB)/8, $0xd807aa98d807aa98
+DATA ·kcon+0x090(SB)/8, $0x12835b0112835b01
+DATA ·kcon+0x098(SB)/8, $0x12835b0112835b01
+DATA ·kcon+0x0A0(SB)/8, $0x243185be243185be
+DATA ·kcon+0x0A8(SB)/8, $0x243185be243185be
+DATA ·kcon+0x0B0(SB)/8, $0x550c7dc3550c7dc3
+DATA ·kcon+0x0B8(SB)/8, $0x550c7dc3550c7dc3
+DATA ·kcon+0x0C0(SB)/8, $0x72be5d7472be5d74
+DATA ·kcon+0x0C8(SB)/8, $0x72be5d7472be5d74
+DATA ·kcon+0x0D0(SB)/8, $0x80deb1fe80deb1fe
+DATA ·kcon+0x0D8(SB)/8, $0x80deb1fe80deb1fe
+DATA ·kcon+0x0E0(SB)/8, $0x9bdc06a79bdc06a7
+DATA ·kcon+0x0E8(SB)/8, $0x9bdc06a79bdc06a7
+DATA ·kcon+0x0F0(SB)/8, $0xc19bf174c19bf174
+DATA ·kcon+0x0F8(SB)/8, $0xc19bf174c19bf174
+DATA ·kcon+0x100(SB)/8, $0xe49b69c1e49b69c1
+DATA ·kcon+0x108(SB)/8, $0xe49b69c1e49b69c1
+DATA ·kcon+0x110(SB)/8, $0xefbe4786efbe4786
+DATA ·kcon+0x118(SB)/8, $0xefbe4786efbe4786
+DATA ·kcon+0x120(SB)/8, $0x0fc19dc60fc19dc6
+DATA ·kcon+0x128(SB)/8, $0x0fc19dc60fc19dc6
+DATA ·kcon+0x130(SB)/8, $0x240ca1cc240ca1cc
+DATA ·kcon+0x138(SB)/8, $0x240ca1cc240ca1cc
+DATA ·kcon+0x140(SB)/8, $0x2de92c6f2de92c6f
+DATA ·kcon+0x148(SB)/8, $0x2de92c6f2de92c6f
+DATA ·kcon+0x150(SB)/8, $0x4a7484aa4a7484aa
+DATA ·kcon+0x158(SB)/8, $0x4a7484aa4a7484aa
+DATA ·kcon+0x160(SB)/8, $0x5cb0a9dc5cb0a9dc
+DATA ·kcon+0x168(SB)/8, $0x5cb0a9dc5cb0a9dc
+DATA ·kcon+0x170(SB)/8, $0x76f988da76f988da
+DATA ·kcon+0x178(SB)/8, $0x76f988da76f988da
+DATA ·kcon+0x180(SB)/8, $0x983e5152983e5152
+DATA ·kcon+0x188(SB)/8, $0x983e5152983e5152
+DATA ·kcon+0x190(SB)/8, $0xa831c66da831c66d
+DATA ·kcon+0x198(SB)/8, $0xa831c66da831c66d
+DATA ·kcon+0x1A0(SB)/8, $0xb00327c8b00327c8
+DATA ·kcon+0x1A8(SB)/8, $0xb00327c8b00327c8
+DATA ·kcon+0x1B0(SB)/8, $0xbf597fc7bf597fc7
+DATA ·kcon+0x1B8(SB)/8, $0xbf597fc7bf597fc7
+DATA ·kcon+0x1C0(SB)/8, $0xc6e00bf3c6e00bf3
+DATA ·kcon+0x1C8(SB)/8, $0xc6e00bf3c6e00bf3
+DATA ·kcon+0x1D0(SB)/8, $0xd5a79147d5a79147
+DATA ·kcon+0x1D8(SB)/8, $0xd5a79147d5a79147
+DATA ·kcon+0x1E0(SB)/8, $0x06ca635106ca6351
+DATA ·kcon+0x1E8(SB)/8, $0x06ca635106ca6351
+DATA ·kcon+0x1F0(SB)/8, $0x1429296714292967
+DATA ·kcon+0x1F8(SB)/8, $0x1429296714292967
+DATA ·kcon+0x200(SB)/8, $0x27b70a8527b70a85
+DATA ·kcon+0x208(SB)/8, $0x27b70a8527b70a85
+DATA ·kcon+0x210(SB)/8, $0x2e1b21382e1b2138
+DATA ·kcon+0x218(SB)/8, $0x2e1b21382e1b2138
+DATA ·kcon+0x220(SB)/8, $0x4d2c6dfc4d2c6dfc
+DATA ·kcon+0x228(SB)/8, $0x4d2c6dfc4d2c6dfc
+DATA ·kcon+0x230(SB)/8, $0x53380d1353380d13
+DATA ·kcon+0x238(SB)/8, $0x53380d1353380d13
+DATA ·kcon+0x240(SB)/8, $0x650a7354650a7354
+DATA ·kcon+0x248(SB)/8, $0x650a7354650a7354
+DATA ·kcon+0x250(SB)/8, $0x766a0abb766a0abb
+DATA ·kcon+0x258(SB)/8, $0x766a0abb766a0abb
+DATA ·kcon+0x260(SB)/8, $0x81c2c92e81c2c92e
+DATA ·kcon+0x268(SB)/8, $0x81c2c92e81c2c92e
+DATA ·kcon+0x270(SB)/8, $0x92722c8592722c85
+DATA ·kcon+0x278(SB)/8, $0x92722c8592722c85
+DATA ·kcon+0x280(SB)/8, $0xa2bfe8a1a2bfe8a1
+DATA ·kcon+0x288(SB)/8, $0xa2bfe8a1a2bfe8a1
+DATA ·kcon+0x290(SB)/8, $0xa81a664ba81a664b
+DATA ·kcon+0x298(SB)/8, $0xa81a664ba81a664b
+DATA ·kcon+0x2A0(SB)/8, $0xc24b8b70c24b8b70
+DATA ·kcon+0x2A8(SB)/8, $0xc24b8b70c24b8b70
+DATA ·kcon+0x2B0(SB)/8, $0xc76c51a3c76c51a3
+DATA ·kcon+0x2B8(SB)/8, $0xc76c51a3c76c51a3
+DATA ·kcon+0x2C0(SB)/8, $0xd192e819d192e819
+DATA ·kcon+0x2C8(SB)/8, $0xd192e819d192e819
+DATA ·kcon+0x2D0(SB)/8, $0xd6990624d6990624
+DATA ·kcon+0x2D8(SB)/8, $0xd6990624d6990624
+DATA ·kcon+0x2E0(SB)/8, $0xf40e3585f40e3585
+DATA ·kcon+0x2E8(SB)/8, $0xf40e3585f40e3585
+DATA ·kcon+0x2F0(SB)/8, $0x106aa070106aa070
+DATA ·kcon+0x2F8(SB)/8, $0x106aa070106aa070
+DATA ·kcon+0x300(SB)/8, $0x19a4c11619a4c116
+DATA ·kcon+0x308(SB)/8, $0x19a4c11619a4c116
+DATA ·kcon+0x310(SB)/8, $0x1e376c081e376c08
+DATA ·kcon+0x318(SB)/8, $0x1e376c081e376c08
+DATA ·kcon+0x320(SB)/8, $0x2748774c2748774c
+DATA ·kcon+0x328(SB)/8, $0x2748774c2748774c
+DATA ·kcon+0x330(SB)/8, $0x34b0bcb534b0bcb5
+DATA ·kcon+0x338(SB)/8, $0x34b0bcb534b0bcb5
+DATA ·kcon+0x340(SB)/8, $0x391c0cb3391c0cb3
+DATA ·kcon+0x348(SB)/8, $0x391c0cb3391c0cb3
+DATA ·kcon+0x350(SB)/8, $0x4ed8aa4a4ed8aa4a
+DATA ·kcon+0x358(SB)/8, $0x4ed8aa4a4ed8aa4a
+DATA ·kcon+0x360(SB)/8, $0x5b9cca4f5b9cca4f
+DATA ·kcon+0x368(SB)/8, $0x5b9cca4f5b9cca4f
+DATA ·kcon+0x370(SB)/8, $0x682e6ff3682e6ff3
+DATA ·kcon+0x378(SB)/8, $0x682e6ff3682e6ff3
+DATA ·kcon+0x380(SB)/8, $0x748f82ee748f82ee
+DATA ·kcon+0x388(SB)/8, $0x748f82ee748f82ee
+DATA ·kcon+0x390(SB)/8, $0x78a5636f78a5636f
+DATA ·kcon+0x398(SB)/8, $0x78a5636f78a5636f
+DATA ·kcon+0x3A0(SB)/8, $0x84c8781484c87814
+DATA ·kcon+0x3A8(SB)/8, $0x84c8781484c87814
+DATA ·kcon+0x3B0(SB)/8, $0x8cc702088cc70208
+DATA ·kcon+0x3B8(SB)/8, $0x8cc702088cc70208
+DATA ·kcon+0x3C0(SB)/8, $0x90befffa90befffa
+DATA ·kcon+0x3C8(SB)/8, $0x90befffa90befffa
+DATA ·kcon+0x3D0(SB)/8, $0xa4506ceba4506ceb
+DATA ·kcon+0x3D8(SB)/8, $0xa4506ceba4506ceb
+DATA ·kcon+0x3E0(SB)/8, $0xbef9a3f7bef9a3f7
+DATA ·kcon+0x3E8(SB)/8, $0xbef9a3f7bef9a3f7
+DATA ·kcon+0x3F0(SB)/8, $0xc67178f2c67178f2
+DATA ·kcon+0x3F8(SB)/8, $0xc67178f2c67178f2
+DATA ·kcon+0x400(SB)/8, $0x0000000000000000
+DATA ·kcon+0x408(SB)/8, $0x0000000000000000
+
+#ifdef GOARCH_ppc64le
+DATA ·kcon+0x410(SB)/8, $0x1011121310111213 // permutation control vectors
+DATA ·kcon+0x418(SB)/8, $0x1011121300010203
+DATA ·kcon+0x420(SB)/8, $0x1011121310111213
+DATA ·kcon+0x428(SB)/8, $0x0405060700010203
+DATA ·kcon+0x430(SB)/8, $0x1011121308090a0b
+DATA ·kcon+0x438(SB)/8, $0x0405060700010203
+#else
+DATA ·kcon+0x410(SB)/8, $0x1011121300010203
+DATA ·kcon+0x418(SB)/8, $0x1011121310111213 // permutation control vectors
+DATA ·kcon+0x420(SB)/8, $0x0405060700010203
+DATA ·kcon+0x428(SB)/8, $0x1011121310111213
+DATA ·kcon+0x430(SB)/8, $0x0001020304050607
+DATA ·kcon+0x438(SB)/8, $0x08090a0b10111213
+#endif
+
+GLOBL ·kcon(SB), RODATA, $1088
+
+#define SHA256ROUND0(a, b, c, d, e, f, g, h, xi, idx) \
+ VSEL g, f, e, FUNC; \
+ VSHASIGMAW $15, e, $1, S1; \
+ VADDUWM xi, h, h; \
+ VSHASIGMAW $0, a, $1, S0; \
+ VADDUWM FUNC, h, h; \
+ VXOR b, a, FUNC; \
+ VADDUWM S1, h, h; \
+ VSEL b, c, FUNC, FUNC; \
+ VADDUWM KI, g, g; \
+ VADDUWM h, d, d; \
+ VADDUWM FUNC, S0, S0; \
+ LVX (TBL)(idx), KI; \
+ VADDUWM S0, h, h
+
+#define SHA256ROUND1(a, b, c, d, e, f, g, h, xi, xj, xj_1, xj_9, xj_14, idx) \
+ VSHASIGMAW $0, xj_1, $0, s0; \
+ VSEL g, f, e, FUNC; \
+ VSHASIGMAW $15, e, $1, S1; \
+ VADDUWM xi, h, h; \
+ VSHASIGMAW $0, a, $1, S0; \
+ VSHASIGMAW $15, xj_14, $0, s1; \
+ VADDUWM FUNC, h, h; \
+ VXOR b, a, FUNC; \
+ VADDUWM xj_9, xj, xj; \
+ VADDUWM S1, h, h; \
+ VSEL b, c, FUNC, FUNC; \
+ VADDUWM KI, g, g; \
+ VADDUWM h, d, d; \
+ VADDUWM FUNC, S0, S0; \
+ VADDUWM s0, xj, xj; \
+ LVX (TBL)(idx), KI; \
+ VADDUWM S0, h, h; \
+ VADDUWM s1, xj, xj
+
+#ifdef GOARCH_ppc64le
+#define VPERMLE(va,vb,vc,vt) VPERM va, vb, vc, vt
+#else
+#define VPERMLE(va,vb,vc,vt)
+#endif
+
+// func block(dig *digest, p []byte)
+TEXT ·block(SB),0,$0-32
+ MOVD dig+0(FP), CTX
+ MOVD p_base+8(FP), INP
+ MOVD p_len+16(FP), LEN
+
+ SRD $6, LEN
+ SLD $6, LEN
+ ADD INP, LEN, END
+
+ CMP INP, END
+ BEQ end
+
+ MOVD $·kcon(SB), TBL_STRT
+ MOVD $0x10, R_x010
+
+#ifdef GOARCH_ppc64le
+ MOVWZ $8, TEMP
+ LVSL (TEMP)(R0), LEMASK
+ VSPLTISB $0x0F, KI
+ VXOR KI, LEMASK, LEMASK
+#endif
+
+ LXVW4X (CTX)(R_x000), V0
+ LXVW4X (CTX)(R_x010), V4
+
+ // unpack the input values into vector registers
+ VSLDOI $4, V0, V0, V1
+ VSLDOI $8, V0, V0, V2
+ VSLDOI $12, V0, V0, V3
+ VSLDOI $4, V4, V4, V5
+ VSLDOI $8, V4, V4, V6
+ VSLDOI $12, V4, V4, V7
+
+ MOVD $0x020, R_x020
+ MOVD $0x030, R_x030
+ MOVD $0x040, R_x040
+ MOVD $0x050, R_x050
+ MOVD $0x060, R_x060
+ MOVD $0x070, R_x070
+ MOVD $0x080, R_x080
+ MOVD $0x090, R_x090
+ MOVD $0x0a0, R_x0a0
+ MOVD $0x0b0, R_x0b0
+ MOVD $0x0c0, R_x0c0
+ MOVD $0x0d0, R_x0d0
+ MOVD $0x0e0, R_x0e0
+ MOVD $0x0f0, R_x0f0
+ MOVD $0x100, R_x100
+ MOVD $0x110, R_x110
+
+loop:
+ MOVD TBL_STRT, TBL
+ LVX (TBL)(R_x000), KI
+
+ LXVD2X (INP)(R_x000), V8 // load v8 in advance
+
+ // Offload to VSR24-31 (aka FPR24-31)
+ XXLOR V0, V0, VS24
+ XXLOR V1, V1, VS25
+ XXLOR V2, V2, VS26
+ XXLOR V3, V3, VS27
+ XXLOR V4, V4, VS28
+ XXLOR V5, V5, VS29
+ XXLOR V6, V6, VS30
+ XXLOR V7, V7, VS31
+
+ VADDUWM KI, V7, V7 // h+K[i]
+ LVX (TBL)(R_x010), KI
+
+ VPERMLE(V8, V8, LEMASK, V8)
+ SHA256ROUND0(V0, V1, V2, V3, V4, V5, V6, V7, V8, R_x020)
+ VSLDOI $4, V8, V8, V9
+ SHA256ROUND0(V7, V0, V1, V2, V3, V4, V5, V6, V9, R_x030)
+ VSLDOI $4, V9, V9, V10
+ SHA256ROUND0(V6, V7, V0, V1, V2, V3, V4, V5, V10, R_x040)
+ LXVD2X (INP)(R_x010), V12 // load v12 in advance
+ VSLDOI $4, V10, V10, V11
+ SHA256ROUND0(V5, V6, V7, V0, V1, V2, V3, V4, V11, R_x050)
+ VPERMLE(V12, V12, LEMASK, V12)
+ SHA256ROUND0(V4, V5, V6, V7, V0, V1, V2, V3, V12, R_x060)
+ VSLDOI $4, V12, V12, V13
+ SHA256ROUND0(V3, V4, V5, V6, V7, V0, V1, V2, V13, R_x070)
+ VSLDOI $4, V13, V13, V14
+ SHA256ROUND0(V2, V3, V4, V5, V6, V7, V0, V1, V14, R_x080)
+ LXVD2X (INP)(R_x020), V16 // load v16 in advance
+ VSLDOI $4, V14, V14, V15
+ SHA256ROUND0(V1, V2, V3, V4, V5, V6, V7, V0, V15, R_x090)
+ VPERMLE(V16, V16, LEMASK, V16)
+ SHA256ROUND0(V0, V1, V2, V3, V4, V5, V6, V7, V16, R_x0a0)
+ VSLDOI $4, V16, V16, V17
+ SHA256ROUND0(V7, V0, V1, V2, V3, V4, V5, V6, V17, R_x0b0)
+ VSLDOI $4, V17, V17, V18
+ SHA256ROUND0(V6, V7, V0, V1, V2, V3, V4, V5, V18, R_x0c0)
+ VSLDOI $4, V18, V18, V19
+ LXVD2X (INP)(R_x030), V20 // load v20 in advance
+ SHA256ROUND0(V5, V6, V7, V0, V1, V2, V3, V4, V19, R_x0d0)
+ VPERMLE(V20, V20, LEMASK, V20)
+ SHA256ROUND0(V4, V5, V6, V7, V0, V1, V2, V3, V20, R_x0e0)
+ VSLDOI $4, V20, V20, V21
+ SHA256ROUND0(V3, V4, V5, V6, V7, V0, V1, V2, V21, R_x0f0)
+ VSLDOI $4, V21, V21, V22
+ SHA256ROUND0(V2, V3, V4, V5, V6, V7, V0, V1, V22, R_x100)
+ VSLDOI $4, V22, V22, V23
+ SHA256ROUND1(V1, V2, V3, V4, V5, V6, V7, V0, V23, V8, V9, V17, V22, R_x110)
+
+ MOVD $3, TEMP
+ MOVD TEMP, CTR
+ ADD $0x120, TBL
+ ADD $0x40, INP
+
+L16_xx:
+ SHA256ROUND1(V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V18, V23, R_x000)
+ SHA256ROUND1(V7, V0, V1, V2, V3, V4, V5, V6, V9, V10, V11, V19, V8, R_x010)
+ SHA256ROUND1(V6, V7, V0, V1, V2, V3, V4, V5, V10, V11, V12, V20, V9, R_x020)
+ SHA256ROUND1(V5, V6, V7, V0, V1, V2, V3, V4, V11, V12, V13, V21, V10, R_x030)
+ SHA256ROUND1(V4, V5, V6, V7, V0, V1, V2, V3, V12, V13, V14, V22, V11, R_x040)
+ SHA256ROUND1(V3, V4, V5, V6, V7, V0, V1, V2, V13, V14, V15, V23, V12, R_x050)
+ SHA256ROUND1(V2, V3, V4, V5, V6, V7, V0, V1, V14, V15, V16, V8, V13, R_x060)
+ SHA256ROUND1(V1, V2, V3, V4, V5, V6, V7, V0, V15, V16, V17, V9, V14, R_x070)
+ SHA256ROUND1(V0, V1, V2, V3, V4, V5, V6, V7, V16, V17, V18, V10, V15, R_x080)
+ SHA256ROUND1(V7, V0, V1, V2, V3, V4, V5, V6, V17, V18, V19, V11, V16, R_x090)
+ SHA256ROUND1(V6, V7, V0, V1, V2, V3, V4, V5, V18, V19, V20, V12, V17, R_x0a0)
+ SHA256ROUND1(V5, V6, V7, V0, V1, V2, V3, V4, V19, V20, V21, V13, V18, R_x0b0)
+ SHA256ROUND1(V4, V5, V6, V7, V0, V1, V2, V3, V20, V21, V22, V14, V19, R_x0c0)
+ SHA256ROUND1(V3, V4, V5, V6, V7, V0, V1, V2, V21, V22, V23, V15, V20, R_x0d0)
+ SHA256ROUND1(V2, V3, V4, V5, V6, V7, V0, V1, V22, V23, V8, V16, V21, R_x0e0)
+ SHA256ROUND1(V1, V2, V3, V4, V5, V6, V7, V0, V23, V8, V9, V17, V22, R_x0f0)
+ ADD $0x100, TBL
+
+ BDNZ L16_xx
+
+ XXLOR VS24, VS24, V10
+
+ XXLOR VS25, VS25, V11
+ VADDUWM V10, V0, V0
+ XXLOR VS26, VS26, V12
+ VADDUWM V11, V1, V1
+ XXLOR VS27, VS27, V13
+ VADDUWM V12, V2, V2
+ XXLOR VS28, VS28, V14
+ VADDUWM V13, V3, V3
+ XXLOR VS29, VS29, V15
+ VADDUWM V14, V4, V4
+ XXLOR VS30, VS30, V16
+ VADDUWM V15, V5, V5
+ XXLOR VS31, VS31, V17
+ VADDUWM V16, V6, V6
+ VADDUWM V17, V7, V7
+
+ CMPU INP, END
+ BLT loop
+
+ LVX (TBL)(R_x000), V8
+ VPERM V0, V1, KI, V0
+ LVX (TBL)(R_x010), V9
+ VPERM V4, V5, KI, V4
+ VPERM V0, V2, V8, V0
+ VPERM V4, V6, V8, V4
+ VPERM V0, V3, V9, V0
+ VPERM V4, V7, V9, V4
+ STXVD2X V0, (CTX+R_x000)
+ STXVD2X V4, (CTX+R_x010)
+
+end:
+ RET
+
diff --git a/src/crypto/sha256/sha256block_s390x.go b/src/crypto/sha256/sha256block_s390x.go
new file mode 100644
index 0000000..1a376c5
--- /dev/null
+++ b/src/crypto/sha256/sha256block_s390x.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha256
+
+import "internal/cpu"
+
+var useAsm = cpu.S390X.HasSHA256
diff --git a/src/crypto/sha256/sha256block_s390x.s b/src/crypto/sha256/sha256block_s390x.s
new file mode 100644
index 0000000..81b1b38
--- /dev/null
+++ b/src/crypto/sha256/sha256block_s390x.s
@@ -0,0 +1,20 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// func block(dig *digest, p []byte)
+TEXT ·block(SB), NOSPLIT|NOFRAME, $0-32
+ MOVBZ ·useAsm(SB), R4
+ LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
+ MOVBZ $2, R0 // SHA-256 function code
+ CMPBEQ R4, $0, generic
+
+loop:
+ WORD $0xB93E0002 // KIMD R2
+ BVS loop // continue if interrupted
+ RET
+
+generic:
+ BR ·blockGeneric(SB)
diff --git a/src/crypto/sha512/fallback_test.go b/src/crypto/sha512/fallback_test.go
new file mode 100644
index 0000000..db5b13c
--- /dev/null
+++ b/src/crypto/sha512/fallback_test.go
@@ -0,0 +1,37 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build s390x
+
+package sha512
+
+import (
+ "fmt"
+ "io"
+ "testing"
+)
+
+// Tests the fallback code path in case the optimized asm
+// implementation cannot be used.
+// See also TestBlockGeneric.
+func TestGenericPath(t *testing.T) {
+ if useAsm == false {
+ t.Skipf("assembly implementation unavailable")
+ }
+ useAsm = false
+ defer func() { useAsm = true }()
+ c := New()
+ in := "ΑΒΓΔΕϜΖΗΘΙΚΛΜΝΞΟΠϺϘΡΣΤΥΦΧΨΩ"
+ gold := "6922e319366d677f34c504af31bfcb29" +
+ "e531c125ecd08679362bffbd6b6ebfb9" +
+ "0dcc27dfc1f3d3b16a16c0763cf43b91" +
+ "40bbf9bbb7233724e9a0c6655b185d76"
+ if _, err := io.WriteString(c, in); err != nil {
+ t.Fatalf("could not write to c: %v", err)
+ }
+ out := fmt.Sprintf("%x", c.Sum(nil))
+ if out != gold {
+ t.Fatalf("mismatch: got %s, wanted %s", out, gold)
+ }
+}
diff --git a/src/crypto/sha512/sha512.go b/src/crypto/sha512/sha512.go
new file mode 100644
index 0000000..9ae1b3a
--- /dev/null
+++ b/src/crypto/sha512/sha512.go
@@ -0,0 +1,384 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package sha512 implements the SHA-384, SHA-512, SHA-512/224, and SHA-512/256
+// hash algorithms as defined in FIPS 180-4.
+//
+// All the hash.Hash implementations returned by this package also
+// implement encoding.BinaryMarshaler and encoding.BinaryUnmarshaler to
+// marshal and unmarshal the internal state of the hash.
+package sha512
+
+import (
+ "crypto"
+ "crypto/internal/boring"
+ "encoding/binary"
+ "errors"
+ "hash"
+)
+
+func init() {
+ crypto.RegisterHash(crypto.SHA384, New384)
+ crypto.RegisterHash(crypto.SHA512, New)
+ crypto.RegisterHash(crypto.SHA512_224, New512_224)
+ crypto.RegisterHash(crypto.SHA512_256, New512_256)
+}
+
+const (
+ // Size is the size, in bytes, of a SHA-512 checksum.
+ Size = 64
+
+ // Size224 is the size, in bytes, of a SHA-512/224 checksum.
+ Size224 = 28
+
+ // Size256 is the size, in bytes, of a SHA-512/256 checksum.
+ Size256 = 32
+
+ // Size384 is the size, in bytes, of a SHA-384 checksum.
+ Size384 = 48
+
+ // BlockSize is the block size, in bytes, of the SHA-512/224,
+ // SHA-512/256, SHA-384 and SHA-512 hash functions.
+ BlockSize = 128
+)
+
+const (
+ chunk = 128
+ init0 = 0x6a09e667f3bcc908
+ init1 = 0xbb67ae8584caa73b
+ init2 = 0x3c6ef372fe94f82b
+ init3 = 0xa54ff53a5f1d36f1
+ init4 = 0x510e527fade682d1
+ init5 = 0x9b05688c2b3e6c1f
+ init6 = 0x1f83d9abfb41bd6b
+ init7 = 0x5be0cd19137e2179
+ init0_224 = 0x8c3d37c819544da2
+ init1_224 = 0x73e1996689dcd4d6
+ init2_224 = 0x1dfab7ae32ff9c82
+ init3_224 = 0x679dd514582f9fcf
+ init4_224 = 0x0f6d2b697bd44da8
+ init5_224 = 0x77e36f7304c48942
+ init6_224 = 0x3f9d85a86a1d36c8
+ init7_224 = 0x1112e6ad91d692a1
+ init0_256 = 0x22312194fc2bf72c
+ init1_256 = 0x9f555fa3c84c64c2
+ init2_256 = 0x2393b86b6f53b151
+ init3_256 = 0x963877195940eabd
+ init4_256 = 0x96283ee2a88effe3
+ init5_256 = 0xbe5e1e2553863992
+ init6_256 = 0x2b0199fc2c85b8aa
+ init7_256 = 0x0eb72ddc81c52ca2
+ init0_384 = 0xcbbb9d5dc1059ed8
+ init1_384 = 0x629a292a367cd507
+ init2_384 = 0x9159015a3070dd17
+ init3_384 = 0x152fecd8f70e5939
+ init4_384 = 0x67332667ffc00b31
+ init5_384 = 0x8eb44a8768581511
+ init6_384 = 0xdb0c2e0d64f98fa7
+ init7_384 = 0x47b5481dbefa4fa4
+)
+
+// digest represents the partial evaluation of a checksum.
+type digest struct {
+ h [8]uint64
+ x [chunk]byte
+ nx int
+ len uint64
+ function crypto.Hash
+}
+
+func (d *digest) Reset() {
+ switch d.function {
+ case crypto.SHA384:
+ d.h[0] = init0_384
+ d.h[1] = init1_384
+ d.h[2] = init2_384
+ d.h[3] = init3_384
+ d.h[4] = init4_384
+ d.h[5] = init5_384
+ d.h[6] = init6_384
+ d.h[7] = init7_384
+ case crypto.SHA512_224:
+ d.h[0] = init0_224
+ d.h[1] = init1_224
+ d.h[2] = init2_224
+ d.h[3] = init3_224
+ d.h[4] = init4_224
+ d.h[5] = init5_224
+ d.h[6] = init6_224
+ d.h[7] = init7_224
+ case crypto.SHA512_256:
+ d.h[0] = init0_256
+ d.h[1] = init1_256
+ d.h[2] = init2_256
+ d.h[3] = init3_256
+ d.h[4] = init4_256
+ d.h[5] = init5_256
+ d.h[6] = init6_256
+ d.h[7] = init7_256
+ default:
+ d.h[0] = init0
+ d.h[1] = init1
+ d.h[2] = init2
+ d.h[3] = init3
+ d.h[4] = init4
+ d.h[5] = init5
+ d.h[6] = init6
+ d.h[7] = init7
+ }
+ d.nx = 0
+ d.len = 0
+}
+
+const (
+ magic384 = "sha\x04"
+ magic512_224 = "sha\x05"
+ magic512_256 = "sha\x06"
+ magic512 = "sha\x07"
+ marshaledSize = len(magic512) + 8*8 + chunk + 8
+)
+
+func (d *digest) MarshalBinary() ([]byte, error) {
+ b := make([]byte, 0, marshaledSize)
+ switch d.function {
+ case crypto.SHA384:
+ b = append(b, magic384...)
+ case crypto.SHA512_224:
+ b = append(b, magic512_224...)
+ case crypto.SHA512_256:
+ b = append(b, magic512_256...)
+ case crypto.SHA512:
+ b = append(b, magic512...)
+ default:
+ return nil, errors.New("crypto/sha512: invalid hash function")
+ }
+ b = binary.BigEndian.AppendUint64(b, d.h[0])
+ b = binary.BigEndian.AppendUint64(b, d.h[1])
+ b = binary.BigEndian.AppendUint64(b, d.h[2])
+ b = binary.BigEndian.AppendUint64(b, d.h[3])
+ b = binary.BigEndian.AppendUint64(b, d.h[4])
+ b = binary.BigEndian.AppendUint64(b, d.h[5])
+ b = binary.BigEndian.AppendUint64(b, d.h[6])
+ b = binary.BigEndian.AppendUint64(b, d.h[7])
+ b = append(b, d.x[:d.nx]...)
+ b = b[:len(b)+len(d.x)-d.nx] // already zero
+ b = binary.BigEndian.AppendUint64(b, d.len)
+ return b, nil
+}
+
+func (d *digest) UnmarshalBinary(b []byte) error {
+ if len(b) < len(magic512) {
+ return errors.New("crypto/sha512: invalid hash state identifier")
+ }
+ switch {
+ case d.function == crypto.SHA384 && string(b[:len(magic384)]) == magic384:
+ case d.function == crypto.SHA512_224 && string(b[:len(magic512_224)]) == magic512_224:
+ case d.function == crypto.SHA512_256 && string(b[:len(magic512_256)]) == magic512_256:
+ case d.function == crypto.SHA512 && string(b[:len(magic512)]) == magic512:
+ default:
+ return errors.New("crypto/sha512: invalid hash state identifier")
+ }
+ if len(b) != marshaledSize {
+ return errors.New("crypto/sha512: invalid hash state size")
+ }
+ b = b[len(magic512):]
+ b, d.h[0] = consumeUint64(b)
+ b, d.h[1] = consumeUint64(b)
+ b, d.h[2] = consumeUint64(b)
+ b, d.h[3] = consumeUint64(b)
+ b, d.h[4] = consumeUint64(b)
+ b, d.h[5] = consumeUint64(b)
+ b, d.h[6] = consumeUint64(b)
+ b, d.h[7] = consumeUint64(b)
+ b = b[copy(d.x[:], b):]
+ b, d.len = consumeUint64(b)
+ d.nx = int(d.len % chunk)
+ return nil
+}
+
+func consumeUint64(b []byte) ([]byte, uint64) {
+ _ = b[7]
+ x := uint64(b[7]) | uint64(b[6])<<8 | uint64(b[5])<<16 | uint64(b[4])<<24 |
+ uint64(b[3])<<32 | uint64(b[2])<<40 | uint64(b[1])<<48 | uint64(b[0])<<56
+ return b[8:], x
+}
+
+// New returns a new hash.Hash computing the SHA-512 checksum.
+func New() hash.Hash {
+ if boring.Enabled {
+ return boring.NewSHA512()
+ }
+ d := &digest{function: crypto.SHA512}
+ d.Reset()
+ return d
+}
+
+// New512_224 returns a new hash.Hash computing the SHA-512/224 checksum.
+func New512_224() hash.Hash {
+ d := &digest{function: crypto.SHA512_224}
+ d.Reset()
+ return d
+}
+
+// New512_256 returns a new hash.Hash computing the SHA-512/256 checksum.
+func New512_256() hash.Hash {
+ d := &digest{function: crypto.SHA512_256}
+ d.Reset()
+ return d
+}
+
+// New384 returns a new hash.Hash computing the SHA-384 checksum.
+func New384() hash.Hash {
+ if boring.Enabled {
+ return boring.NewSHA384()
+ }
+ d := &digest{function: crypto.SHA384}
+ d.Reset()
+ return d
+}
+
+func (d *digest) Size() int {
+ switch d.function {
+ case crypto.SHA512_224:
+ return Size224
+ case crypto.SHA512_256:
+ return Size256
+ case crypto.SHA384:
+ return Size384
+ default:
+ return Size
+ }
+}
+
+func (d *digest) BlockSize() int { return BlockSize }
+
+func (d *digest) Write(p []byte) (nn int, err error) {
+ if d.function != crypto.SHA512_224 && d.function != crypto.SHA512_256 {
+ boring.Unreachable()
+ }
+ nn = len(p)
+ d.len += uint64(nn)
+ if d.nx > 0 {
+ n := copy(d.x[d.nx:], p)
+ d.nx += n
+ if d.nx == chunk {
+ block(d, d.x[:])
+ d.nx = 0
+ }
+ p = p[n:]
+ }
+ if len(p) >= chunk {
+ n := len(p) &^ (chunk - 1)
+ block(d, p[:n])
+ p = p[n:]
+ }
+ if len(p) > 0 {
+ d.nx = copy(d.x[:], p)
+ }
+ return
+}
+
+func (d *digest) Sum(in []byte) []byte {
+ if d.function != crypto.SHA512_224 && d.function != crypto.SHA512_256 {
+ boring.Unreachable()
+ }
+ // Make a copy of d so that caller can keep writing and summing.
+ d0 := new(digest)
+ *d0 = *d
+ hash := d0.checkSum()
+ switch d0.function {
+ case crypto.SHA384:
+ return append(in, hash[:Size384]...)
+ case crypto.SHA512_224:
+ return append(in, hash[:Size224]...)
+ case crypto.SHA512_256:
+ return append(in, hash[:Size256]...)
+ default:
+ return append(in, hash[:]...)
+ }
+}
+
+func (d *digest) checkSum() [Size]byte {
+ // Padding. Add a 1 bit and 0 bits until 112 bytes mod 128.
+ len := d.len
+ var tmp [128 + 16]byte // padding + length buffer
+ tmp[0] = 0x80
+ var t uint64
+ if len%128 < 112 {
+ t = 112 - len%128
+ } else {
+ t = 128 + 112 - len%128
+ }
+
+ // Length in bits.
+ len <<= 3
+ padlen := tmp[:t+16]
+ // Upper 64 bits are always zero, because len variable has type uint64,
+ // and tmp is already zeroed at that index, so we can skip updating it.
+ // binary.BigEndian.PutUint64(padlen[t+0:], 0)
+ binary.BigEndian.PutUint64(padlen[t+8:], len)
+ d.Write(padlen)
+
+ if d.nx != 0 {
+ panic("d.nx != 0")
+ }
+
+ var digest [Size]byte
+ binary.BigEndian.PutUint64(digest[0:], d.h[0])
+ binary.BigEndian.PutUint64(digest[8:], d.h[1])
+ binary.BigEndian.PutUint64(digest[16:], d.h[2])
+ binary.BigEndian.PutUint64(digest[24:], d.h[3])
+ binary.BigEndian.PutUint64(digest[32:], d.h[4])
+ binary.BigEndian.PutUint64(digest[40:], d.h[5])
+ if d.function != crypto.SHA384 {
+ binary.BigEndian.PutUint64(digest[48:], d.h[6])
+ binary.BigEndian.PutUint64(digest[56:], d.h[7])
+ }
+
+ return digest
+}
+
+// Sum512 returns the SHA512 checksum of the data.
+func Sum512(data []byte) [Size]byte {
+ if boring.Enabled {
+ return boring.SHA512(data)
+ }
+ d := digest{function: crypto.SHA512}
+ d.Reset()
+ d.Write(data)
+ return d.checkSum()
+}
+
+// Sum384 returns the SHA384 checksum of the data.
+func Sum384(data []byte) [Size384]byte {
+ if boring.Enabled {
+ return boring.SHA384(data)
+ }
+ d := digest{function: crypto.SHA384}
+ d.Reset()
+ d.Write(data)
+ sum := d.checkSum()
+ ap := (*[Size384]byte)(sum[:])
+ return *ap
+}
+
+// Sum512_224 returns the Sum512/224 checksum of the data.
+func Sum512_224(data []byte) [Size224]byte {
+ d := digest{function: crypto.SHA512_224}
+ d.Reset()
+ d.Write(data)
+ sum := d.checkSum()
+ ap := (*[Size224]byte)(sum[:])
+ return *ap
+}
+
+// Sum512_256 returns the Sum512/256 checksum of the data.
+func Sum512_256(data []byte) [Size256]byte {
+ d := digest{function: crypto.SHA512_256}
+ d.Reset()
+ d.Write(data)
+ sum := d.checkSum()
+ ap := (*[Size256]byte)(sum[:])
+ return *ap
+}
diff --git a/src/crypto/sha512/sha512_test.go b/src/crypto/sha512/sha512_test.go
new file mode 100644
index 0000000..921cdbb
--- /dev/null
+++ b/src/crypto/sha512/sha512_test.go
@@ -0,0 +1,952 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA512 hash algorithm. See FIPS 180-4.
+
+package sha512
+
+import (
+ "bytes"
+ "crypto/internal/boring"
+ "crypto/rand"
+ "encoding"
+ "encoding/hex"
+ "fmt"
+ "hash"
+ "io"
+ "testing"
+)
+
+type sha512Test struct {
+ out string
+ in string
+ halfState string // marshaled hash state after first half of in written, used by TestGoldenMarshal
+}
+
+var golden224 = []sha512Test{
+ {
+ "6ed0dd02806fa89e25de060c19d3ac86cabb87d6a0ddd05c333b84f4",
+ "",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ },
+ {
+ "d5cdb9ccc769a5121d4175f2bfdd13d6310e0d3d361ea75d82108327",
+ "a",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ },
+ {
+ "b35878d07bfedf39fc638af08547eb5d1072d8546319f247b442fbf5",
+ "ab",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
+ },
+ {
+ "4634270f707b6a54daae7530460842e20e37ed265ceee9a43e8924aa",
+ "abc",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
+ },
+ {
+ "0c9f157ab030fb06e957c14e3938dc5908962e5dd7b66f04a36fc534",
+ "abcd",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02",
+ },
+ {
+ "880e79bb0a1d2c9b7528d851edb6b8342c58c831de98123b432a4515",
+ "abcde",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02",
+ },
+ {
+ "236c829cfea4fd6d4de61ad15fcf34dca62342adaf9f2001c16f29b8",
+ "abcdef",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03",
+ },
+ {
+ "4767af672b3ed107f25018dc22d6fa4b07d156e13b720971e2c4f6bf",
+ "abcdefg",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03",
+ },
+ {
+ "792e25e0ae286d123a38950007e037d3122e76c4ee201668c385edab",
+ "abcdefgh",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04",
+ },
+ {
+ "56b275d36127dc070cda4019baf2ce2579a25d8c67fa2bc9be61b539",
+ "abcdefghi",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04",
+ },
+ {
+ "f809423cbb25e81a2a64aecee2cd5fdc7d91d5db583901fbf1db3116",
+ "abcdefghij",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1abcde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05",
+ },
+ {
+ "4c46e10b5b72204e509c3c06072cea970bc020cd45a61a0acdfa97ac",
+ "Discard medicine more than two years old.",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1Discard medicine mor\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14",
+ },
+ {
+ "cb0cef13c1848d91a6d02637c7c520de1914ad4a7aea824671cc328e",
+ "He who has a shady past knows that nice guys finish last.",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1He who has a shady past know\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c",
+ },
+ {
+ "6c7bd0f3a6544ea698006c2ea583a85f80ea2913590a186db8bb2f1b",
+ "I wouldn't marry him with a ten foot pole.",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1I wouldn't marry him \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15",
+ },
+ {
+ "981323be3eca6ccfa598e58dd74ed8cb05d5f7f6653b7604b684f904",
+ "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1Free! Free!/A trip/to Mars/f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c",
+ },
+ {
+ "e6fbf82df5138bf361e826903cadf0612cb2986649ba47a57e1bca99",
+ "The days of the digital watch are numbered. -Tom Stoppard",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1The days of the digital watch\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d",
+ },
+ {
+ "6ec2cb2ecafc1a9bddaf4caf57344d853e6ded398927d5694fd7714f",
+ "Nepal premier won't resign.",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1Nepal premier\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r",
+ },
+ {
+ "7f62f36e716e0badaf4a4658da9d09bea26357a1bc6aeb8cf7c3ae35",
+ "For every action there is an equal and opposite government program.",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1For every action there is an equa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!",
+ },
+ {
+ "45adffcb86a05ee4d91263a6115dda011b805d442c60836963cb8378",
+ "His money is twice tainted: 'taint yours and 'taint mine.",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1His money is twice tainted: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c",
+ },
+ {
+ "51cb518f1f68daa901a3075a0a5e1acc755b4e5c82cb47687537f880",
+ "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1There is no reason for any individual to hav\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,",
+ },
+ {
+ "3b59c5e64b0da7bfc18d7017bf458d90f2c83601ff1afc6263ac0993",
+ "It's a tiny change to the code and not completely disgusting. - Bob Manchek",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1It's a tiny change to the code and no\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%",
+ },
+ {
+ "6a9525c0fac0f91b489bc4f0f539b9ec4a156a4e98bc15b655c2c881",
+ "size: a.out: bad magic",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1size: a.out\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\f",
+ },
+ {
+ "a1b2b2905b1527d682049c6a76e35c7d8c72551abfe7833ac1be595f",
+ "The major problem is with sendmail. -Mark Horton",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1The major problem is wit\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18",
+ },
+ {
+ "76cf045c76a5f2e3d64d56c3cdba6a25479334611bc375460526f8c1",
+ "Give me a rock, paper and scissors and I will move the world. CCFestoon",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1Give me a rock, paper and scissors a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$",
+ },
+ {
+ "4473671daeecfdb6f6c5bc06b26374aa5e497cc37119fe14144c430c",
+ "If the enemy is within range, then so are you.",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1If the enemy is within \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17",
+ },
+ {
+ "6accb6394758523fcd453d47d37ebd10868957a0a9e81c796736abf8",
+ "It's well we cannot hear the screams/That we create in others' dreams.",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1It's well we cannot hear the scream\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#",
+ },
+ {
+ "6f173f4b6eac7f2a73eaa0833c4563752df2c869dc00b7d30219e12e",
+ "You remind me of a TV show, but that's all right: I watch it anyway.",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1You remind me of a TV show, but th\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\"",
+ },
+ {
+ "db05bf4d0f73325208755f4af96cfac6cb3db5dbfc323d675d68f938",
+ "C is as portable as Stonehedge!!",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1C is as portable\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10",
+ },
+ {
+ "05ffa71bb02e855de1aaee1777b3bdbaf7507646f19c4c6aa29933d0",
+ "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1Even if I could be Shakespeare, I think I sh\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,",
+ },
+ {
+ "3ad3c89e15b91e6273534c5d18adadbb528e7b840b288f64e81b8c6d",
+ "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1The fugacity of a constituent in a mixture of gases at a given tem\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B",
+ },
+ {
+ "e3763669d1b760c1be7bfcb6625f92300a8430419d1dbad57ec9f53c",
+ "How can you write a big system without C++? -Paul Glick",
+ "sha\x05\x8c=7\xc8\x19TM\xa2s\xe1\x99f\x89\xdc\xd4\xd6\x1d\xfa\xb7\xae2\xff\x9c\x82g\x9d\xd5\x14X/\x9f\xcf\x0fm+i{\xd4M\xa8w\xe3os\x04ĉB?\x9d\x85\xa8j\x1d6\xc8\x11\x12歑֒\xa1How can you write a big syst\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c",
+ },
+}
+
+var golden256 = []sha512Test{
+ {
+ "c672b8d1ef56ed28ab87c3622c5114069bdd3ad7b8f9737498d0c01ecef0967a",
+ "",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ },
+ {
+ "455e518824bc0601f9fb858ff5c37d417d67c2f8e0df2babe4808858aea830f8",
+ "a",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ },
+ {
+ "22d4d37ec6370571af7109fb12eae79673d5f7c83e6e677083faa3cfac3b2c14",
+ "ab",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
+ },
+ {
+ "53048e2681941ef99b2e29b76b4c7dabe4c2d0c634fc6d46e0e2f13107e7af23",
+ "abc",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
+ },
+ {
+ "d2891c7978be0e24948f37caa415b87cb5cbe2b26b7bad9dc6391b8a6f6ddcc9",
+ "abcd",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02",
+ },
+ {
+ "de8322b46e78b67d4431997070703e9764e03a1237b896fd8b379ed4576e8363",
+ "abcde",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02",
+ },
+ {
+ "e4fdcb11d1ac14e698743acd8805174cea5ddc0d312e3e47f6372032571bad84",
+ "abcdef",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03",
+ },
+ {
+ "a8117f680bdceb5d1443617cbdae9255f6900075422326a972fdd2f65ba9bee3",
+ "abcdefg",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03",
+ },
+ {
+ "a29b9645d2a02a8b582888d044199787220e316bf2e89d1422d3df26bf545bbe",
+ "abcdefgh",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04",
+ },
+ {
+ "b955095330f9c8188d11884ec1679dc44c9c5b25ff9bda700416df9cdd39188f",
+ "abcdefghi",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04",
+ },
+ {
+ "550762913d51eefbcd1a55068fcfc9b154fd11c1078b996df0d926ea59d2a68d",
+ "abcdefghij",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2abcde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05",
+ },
+ {
+ "690c8ad3916cefd3ad29226d9875965e3ee9ec0d4482eacc248f2ff4aa0d8e5b",
+ "Discard medicine more than two years old.",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2Discard medicine mor\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14",
+ },
+ {
+ "25938ca49f7ef1178ce81620842b65e576245fcaed86026a36b516b80bb86b3b",
+ "He who has a shady past knows that nice guys finish last.",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2He who has a shady past know\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c",
+ },
+ {
+ "698e420c3a7038e53d8e73f4be2b02e03b93464ac1a61ebe69f557079921ef65",
+ "I wouldn't marry him with a ten foot pole.",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2I wouldn't marry him \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15",
+ },
+ {
+ "839b414d7e3900ee243aa3d1f9b6955720e64041f5ab9bedd3eb0a08da5a2ca8",
+ "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2Free! Free!/A trip/to Mars/f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c",
+ },
+ {
+ "5625ecb9d284e54c00b257b67a8cacb25a78db2845c60ef2d29e43c84f236e8e",
+ "The days of the digital watch are numbered. -Tom Stoppard",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2The days of the digital watch\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d",
+ },
+ {
+ "9b81d06bca2f985e6ad3249096ff3c0f2a9ec5bb16ef530d738d19d81e7806f2",
+ "Nepal premier won't resign.",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2Nepal premier\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r",
+ },
+ {
+ "08241df8d91edfcd68bb1a1dada6e0ae1475a5c6e7b8f12d8e24ca43a38240a9",
+ "For every action there is an equal and opposite government program.",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2For every action there is an equa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!",
+ },
+ {
+ "4ff74d9213a8117745f5d37b5353a774ec81c5dfe65c4c8986a56fc01f2c551e",
+ "His money is twice tainted: 'taint yours and 'taint mine.",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2His money is twice tainted: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c",
+ },
+ {
+ "b5baf747c307f98849ec881cf0d48605ae4edd386372aea9b26e71db517e650b",
+ "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2There is no reason for any individual to hav\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,",
+ },
+ {
+ "7eef0538ebd7ecf18611d23b0e1cd26a74d65b929a2e374197dc66e755ca4944",
+ "It's a tiny change to the code and not completely disgusting. - Bob Manchek",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2It's a tiny change to the code and no\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%",
+ },
+ {
+ "d05600964f83f55323104aadab434f32391c029718a7690d08ddb2d7e8708443",
+ "size: a.out: bad magic",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2size: a.out\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\f",
+ },
+ {
+ "53ed5f9b5c0b674ac0f3425d9f9a5d462655b07cc90f5d0f692eec093884a607",
+ "The major problem is with sendmail. -Mark Horton",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2The major problem is wit\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18",
+ },
+ {
+ "5a0147685a44eea2435dbd582724efca7637acd9c428e5e1a05115bc3bc2a0e0",
+ "Give me a rock, paper and scissors and I will move the world. CCFestoon",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2Give me a rock, paper and scissors a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$",
+ },
+ {
+ "1152c9b27a99dbf4057d21438f4e63dd0cd0977d5ff12317c64d3b97fcac875a",
+ "If the enemy is within range, then so are you.",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2If the enemy is within \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17",
+ },
+ {
+ "105e890f5d5cf1748d9a7b4cdaf58b69855779deebc2097747c2210a17b2cb51",
+ "It's well we cannot hear the screams/That we create in others' dreams.",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2It's well we cannot hear the scream\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#",
+ },
+ {
+ "74644ead770da1434365cd912656fe1aca2056d3039d39f10eb1151bddb32cf3",
+ "You remind me of a TV show, but that's all right: I watch it anyway.",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2You remind me of a TV show, but th\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\"",
+ },
+ {
+ "50a234625de5587581883dad9ef399460928032a5ea6bd005d7dc7b68d8cc3d6",
+ "C is as portable as Stonehedge!!",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2C is as portable\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10",
+ },
+ {
+ "a7a3846005f8a9935a0a2d43e7fd56d95132a9a3609bf3296ef80b8218acffa0",
+ "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2Even if I could be Shakespeare, I think I sh\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,",
+ },
+ {
+ "688ff03e367680757aa9906cb1e2ad218c51f4526dc0426ea229a5ba9d002c69",
+ "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2The fugacity of a constituent in a mixture of gases at a given tem\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B",
+ },
+ {
+ "3fa46d52094b01021cff5af9a438982b887a5793f624c0a6644149b6b7c3f485",
+ "How can you write a big system without C++? -Paul Glick",
+ "sha\x06\"1!\x94\xfc+\xf7,\x9fU_\xa3\xc8Ld\xc2#\x93\xb8koS\xb1Q\x968w\x19Y@꽖(>⨎\xff\xe3\xbe^\x1e%S\x869\x92+\x01\x99\xfc,\x85\xb8\xaa\x0e\xb7-܁\xc5,\xa2How can you write a big syst\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c",
+ },
+}
+
+var golden384 = []sha512Test{
+ {
+ "38b060a751ac96384cd9327eb1b1e36a21fdb71114be07434c0cc7bf63f6e1da274edebfe76f65fbd51ad2f14898b95b",
+ "",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ },
+ {
+ "54a59b9f22b0b80880d8427e548b7c23abd873486e1f035dce9cd697e85175033caa88e6d57bc35efae0b5afd3145f31",
+ "a",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ },
+ {
+ "c7be03ba5bcaa384727076db0018e99248e1a6e8bd1b9ef58a9ec9dd4eeebb3f48b836201221175befa74ddc3d35afdd",
+ "ab",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
+ },
+ {
+ "cb00753f45a35e8bb5a03d699ac65007272c32ab0eded1631a8b605a43ff5bed8086072ba1e7cc2358baeca134c825a7",
+ "abc",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
+ },
+ {
+ "1165b3406ff0b52a3d24721f785462ca2276c9f454a116c2b2ba20171a7905ea5a026682eb659c4d5f115c363aa3c79b",
+ "abcd",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02",
+ },
+ {
+ "4c525cbeac729eaf4b4665815bc5db0c84fe6300068a727cf74e2813521565abc0ec57a37ee4d8be89d097c0d2ad52f0",
+ "abcde",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4ab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02",
+ },
+ {
+ "c6a4c65b227e7387b9c3e839d44869c4cfca3ef583dea64117859b808c1e3d8ae689e1e314eeef52a6ffe22681aa11f5",
+ "abcdef",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03",
+ },
+ {
+ "9f11fc131123f844c1226f429b6a0a6af0525d9f40f056c7fc16cdf1b06bda08e302554417a59fa7dcf6247421959d22",
+ "abcdefg",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4abc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03",
+ },
+ {
+ "9000cd7cada59d1d2eb82912f7f24e5e69cc5517f68283b005fa27c285b61e05edf1ad1a8a9bded6fd29eb87d75ad806",
+ "abcdefgh",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04",
+ },
+ {
+ "ef54915b60cf062b8dd0c29ae3cad69abe6310de63ac081f46ef019c5c90897caefd79b796cfa81139788a260ded52df",
+ "abcdefghi",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4abcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04",
+ },
+ {
+ "a12070030a02d86b0ddacd0d3a5b598344513d0a051e7355053e556a0055489c1555399b03342845c4adde2dc44ff66c",
+ "abcdefghij",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4abcde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05",
+ },
+ {
+ "86f58ec2d74d1b7f8eb0c2ff0967316699639e8d4eb129de54bdf34c96cdbabe200d052149f2dd787f43571ba74670d4",
+ "Discard medicine more than two years old.",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4Discard medicine mor\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14",
+ },
+ {
+ "ae4a2b639ca9bfa04b1855d5a05fe7f230994f790891c6979103e2605f660c4c1262a48142dcbeb57a1914ba5f7c3fa7",
+ "He who has a shady past knows that nice guys finish last.",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4He who has a shady past know\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c",
+ },
+ {
+ "40ae213df6436eca952aa6841886fcdb82908ef1576a99c8f49bb9dd5023169f7c53035abdda0b54c302f4974e2105e7",
+ "I wouldn't marry him with a ten foot pole.",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4I wouldn't marry him \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15",
+ },
+ {
+ "e7cf8b873c9bc950f06259aa54309f349cefa72c00d597aebf903e6519a50011dfe355afff064a10701c705693848df9",
+ "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4Free! Free!/A trip/to Mars/f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c",
+ },
+ {
+ "c3d4f0f4047181c7d39d34703365f7bf70207183caf2c2f6145f04da895ef69124d9cdeb635da636c3a474e61024e29b",
+ "The days of the digital watch are numbered. -Tom Stoppard",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4The days of the digital watch\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d",
+ },
+ {
+ "a097aab567e167d5cf93676ed73252a69f9687cb3179bb2d27c9878119e94bf7b7c4b58dc90582edfaf66e11388ed714",
+ "Nepal premier won't resign.",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4Nepal premier\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r",
+ },
+ {
+ "5026ca45c41fc64712eb65065da92f6467541c78f8966d3fe2c8e3fb769a3ec14215f819654b47bd64f7f0eac17184f3",
+ "For every action there is an equal and opposite government program.",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4For every action there is an equa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!",
+ },
+ {
+ "ac1cc0f5ac8d5f5514a7b738ac322b7fb52a161b449c3672e9b6a6ad1a5e4b26b001cf3bad24c56598676ca17d4b445a",
+ "His money is twice tainted: 'taint yours and 'taint mine.",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4His money is twice tainted: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c",
+ },
+ {
+ "722d10c5de371ec0c8c4b5247ac8a5f1d240d68c73f8da13d8b25f0166d6f309bf9561979a111a0049405771d201941a",
+ "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4There is no reason for any individual to hav\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,",
+ },
+ {
+ "dc2d3ea18bfa10549c63bf2b75b39b5167a80c12aff0e05443168ea87ff149fb0eda5e0bd234eb5d48c7d02ffc5807f1",
+ "It's a tiny change to the code and not completely disgusting. - Bob Manchek",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4It's a tiny change to the code and no\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%",
+ },
+ {
+ "1d67c969e2a945ae5346d2139760261504d4ba164c522443afe19ef3e29b152a4c52445489cfc9d7215e5a450e8e1e4e",
+ "size: a.out: bad magic",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4size: a.out\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\f",
+ },
+ {
+ "5ff8e075e465646e7b73ef36d812c6e9f7d60fa6ea0e533e5569b4f73cde53cdd2cc787f33540af57cca3fe467d32fe0",
+ "The major problem is with sendmail. -Mark Horton",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4The major problem is wit\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18",
+ },
+ {
+ "5bd0a997a67c9ae1979a894eb0cde403dde003c9b6f2c03cf21925c42ff4e1176e6df1ca005381612ef18457b9b7ec3b",
+ "Give me a rock, paper and scissors and I will move the world. CCFestoon",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4Give me a rock, paper and scissors a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$",
+ },
+ {
+ "1eee6da33e7e54fc5be52ae23b94b16ba4d2a947ae4505c6a3edfc7401151ea5205ac01b669b56f27d8ef7f175ed7762",
+ "If the enemy is within range, then so are you.",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4If the enemy is within \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17",
+ },
+ {
+ "76b06e9dea66bfbb1a96029426dc0dfd7830bd297eb447ff5358d94a87cd00c88b59df2493fef56ecbb5231073892ea9",
+ "It's well we cannot hear the screams/That we create in others' dreams.",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4It's well we cannot hear the scream\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#",
+ },
+ {
+ "12acaf21452cff586143e3f5db0bfdf7802c057e1adf2a619031c4e1b0ccc4208cf6cef8fe722bbaa2fb46a30d9135d8",
+ "You remind me of a TV show, but that's all right: I watch it anyway.",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4You remind me of a TV show, but th\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\"",
+ },
+ {
+ "0fc23d7f4183efd186f0bc4fc5db867e026e2146b06cb3d52f4bdbd57d1740122caa853b41868b197b2ac759db39df88",
+ "C is as portable as Stonehedge!!",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4C is as portable\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10",
+ },
+ {
+ "bc805578a7f85d34a86a32976e1c34fe65cf815186fbef76f46ef99cda10723f971f3f1464d488243f5e29db7488598d",
+ "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4Even if I could be Shakespeare, I think I sh\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,",
+ },
+ {
+ "b23918399a12ebf4431559eec3813eaf7412e875fd7464f16d581e473330842d2e96c6be49a7ce3f9bb0b8bc0fcbe0fe",
+ "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4The fugacity of a constituent in a mixture of gases at a given tem\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B",
+ },
+ {
+ "1764b700eb1ead52a2fc33cc28975c2180f1b8faa5038d94cffa8d78154aab16e91dd787e7b0303948ebed62561542c8",
+ "How can you write a big system without C++? -Paul Glick",
+ "sha\x04˻\x9d]\xc1\x05\x9e\xd8b\x9a)*6|\xd5\a\x91Y\x01Z0p\xdd\x17\x15/\xec\xd8\xf7\x0eY9g3&g\xff\xc0\v1\x8e\xb4J\x87hX\x15\x11\xdb\f.\rd\xf9\x8f\xa7G\xb5H\x1d\xbe\xfaO\xa4How can you write a big syst\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c",
+ },
+}
+
+var golden512 = []sha512Test{
+ {
+ "cf83e1357eefb8bdf1542850d66d8007d620e4050b5715dc83f4a921d36ce9ce47d0d13c5d85f2b0ff8318d2877eec2f63b931bd47417a81a538327af927da3e",
+ "",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!y\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ },
+ {
+ "1f40fc92da241694750979ee6cf582f2d5d7d28e18335de05abc54d0560e0f5302860c652bf08d560252aa5e74210546f369fbbbce8c12cfc7957b2652fe9a75",
+ "a",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!y\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00",
+ },
+ {
+ "2d408a0717ec188158278a796c689044361dc6fdde28d6f04973b80896e1823975cdbf12eb63f9e0591328ee235d80e9b5bf1aa6a44f4617ff3caf6400eb172d",
+ "ab",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!ya\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
+ },
+ {
+ "ddaf35a193617abacc417349ae20413112e6fa4e89a97ea20a9eeee64b55d39a2192992a274fc1a836ba3c23a3feebbd454d4423643ce80e2a9ac94fa54ca49f",
+ "abc",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!ya\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01",
+ },
+ {
+ "d8022f2060ad6efd297ab73dcc5355c9b214054b0d1776a136a669d26a7d3b14f73aa0d0ebff19ee333368f0164b6419a96da49e3e481753e7e96b716bdccb6f",
+ "abcd",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02",
+ },
+ {
+ "878ae65a92e86cac011a570d4c30a7eaec442b85ce8eca0c2952b5e3cc0628c2e79d889ad4d5c7c626986d452dd86374b6ffaa7cd8b67665bef2289a5c70b0a1",
+ "abcde",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yab\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x02",
+ },
+ {
+ "e32ef19623e8ed9d267f657a81944b3d07adbb768518068e88435745564e8d4150a0a703be2a7d88b61e3d390c2bb97e2d4c311fdc69d6b1267f05f59aa920e7",
+ "abcdef",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yabc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03",
+ },
+ {
+ "d716a4188569b68ab1b6dfac178e570114cdf0ea3a1cc0e31486c3e41241bc6a76424e8c37ab26f096fc85ef9886c8cb634187f4fddff645fb099f1ff54c6b8c",
+ "abcdefg",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yabc\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x03",
+ },
+ {
+ "a3a8c81bc97c2560010d7389bc88aac974a104e0e2381220c6e084c4dccd1d2d17d4f86db31c2a851dc80e6681d74733c55dcd03dd96f6062cdda12a291ae6ce",
+ "abcdefgh",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yabcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04",
+ },
+ {
+ "f22d51d25292ca1d0f68f69aedc7897019308cc9db46efb75a03dd494fc7f126c010e8ade6a00a0c1a5f1b75d81e0ed5a93ce98dc9b833db7839247b1d9c24fe",
+ "abcdefghi",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yabcd\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x04",
+ },
+ {
+ "ef6b97321f34b1fea2169a7db9e1960b471aa13302a988087357c520be957ca119c3ba68e6b4982c019ec89de3865ccf6a3cda1fe11e59f98d99f1502c8b9745",
+ "abcdefghij",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yabcde\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x05",
+ },
+ {
+ "2210d99af9c8bdecda1b4beff822136753d8342505ddce37f1314e2cdbb488c6016bdaa9bd2ffa513dd5de2e4b50f031393d8ab61f773b0e0130d7381e0f8a1d",
+ "Discard medicine more than two years old.",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yDiscard medicine mor\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x14",
+ },
+ {
+ "a687a8985b4d8d0a24f115fe272255c6afaf3909225838546159c1ed685c211a203796ae8ecc4c81a5b6315919b3a64f10713da07e341fcdbb08541bf03066ce",
+ "He who has a shady past knows that nice guys finish last.",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yHe who has a shady past know\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c",
+ },
+ {
+ "8ddb0392e818b7d585ab22769a50df660d9f6d559cca3afc5691b8ca91b8451374e42bcdabd64589ed7c91d85f626596228a5c8572677eb98bc6b624befb7af8",
+ "I wouldn't marry him with a ten foot pole.",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yI wouldn't marry him \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x15",
+ },
+ {
+ "26ed8f6ca7f8d44b6a8a54ae39640fa8ad5c673f70ee9ce074ba4ef0d483eea00bab2f61d8695d6b34df9c6c48ae36246362200ed820448bdc03a720366a87c6",
+ "Free! Free!/A trip/to Mars/for 900/empty jars/Burma Shave",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yFree! Free!/A trip/to Mars/f\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c",
+ },
+ {
+ "e5a14bf044be69615aade89afcf1ab0389d5fc302a884d403579d1386a2400c089b0dbb387ed0f463f9ee342f8244d5a38cfbc0e819da9529fbff78368c9a982",
+ "The days of the digital watch are numbered. -Tom Stoppard",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yThe days of the digital watch\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1d",
+ },
+ {
+ "420a1faa48919e14651bed45725abe0f7a58e0f099424c4e5a49194946e38b46c1f8034b18ef169b2e31050d1648e0b982386595f7df47da4b6fd18e55333015",
+ "Nepal premier won't resign.",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yNepal premier\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\r",
+ },
+ {
+ "d926a863beadb20134db07683535c72007b0e695045876254f341ddcccde132a908c5af57baa6a6a9c63e6649bba0c213dc05fadcf9abccea09f23dcfb637fbe",
+ "For every action there is an equal and opposite government program.",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yFor every action there is an equa\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00!",
+ },
+ {
+ "9a98dd9bb67d0da7bf83da5313dff4fd60a4bac0094f1b05633690ffa7f6d61de9a1d4f8617937d560833a9aaa9ccafe3fd24db418d0e728833545cadd3ad92d",
+ "His money is twice tainted: 'taint yours and 'taint mine.",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yHis money is twice tainted: \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c",
+ },
+ {
+ "d7fde2d2351efade52f4211d3746a0780a26eec3df9b2ed575368a8a1c09ec452402293a8ea4eceb5a4f60064ea29b13cdd86918cd7a4faf366160b009804107",
+ "There is no reason for any individual to have a computer in their home. -Ken Olsen, 1977",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yThere is no reason for any individual to hav\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,",
+ },
+ {
+ "b0f35ffa2697359c33a56f5c0cf715c7aeed96da9905ca2698acadb08fbc9e669bf566b6bd5d61a3e86dc22999bcc9f2224e33d1d4f32a228cf9d0349e2db518",
+ "It's a tiny change to the code and not completely disgusting. - Bob Manchek",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yIt's a tiny change to the code and no\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00%",
+ },
+ {
+ "3d2e5f91778c9e66f7e061293aaa8a8fc742dd3b2e4f483772464b1144189b49273e610e5cccd7a81a19ca1fa70f16b10f1a100a4d8c1372336be8484c64b311",
+ "size: a.out: bad magic",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!ysize: a.out\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\f",
+ },
+ {
+ "b2f68ff58ac015efb1c94c908b0d8c2bf06f491e4de8e6302c49016f7f8a33eac3e959856c7fddbc464de618701338a4b46f76dbfaf9a1e5262b5f40639771c7",
+ "The major problem is with sendmail. -Mark Horton",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yThe major problem is wit\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x18",
+ },
+ {
+ "d8c92db5fdf52cf8215e4df3b4909d29203ff4d00e9ad0b64a6a4e04dec5e74f62e7c35c7fb881bd5de95442123df8f57a489b0ae616bd326f84d10021121c57",
+ "Give me a rock, paper and scissors and I will move the world. CCFestoon",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yGive me a rock, paper and scissors a\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00$",
+ },
+ {
+ "19a9f8dc0a233e464e8566ad3ca9b91e459a7b8c4780985b015776e1bf239a19bc233d0556343e2b0a9bc220900b4ebf4f8bdf89ff8efeaf79602d6849e6f72e",
+ "If the enemy is within range, then so are you.",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yIf the enemy is within \x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x17",
+ },
+ {
+ "00b4c41f307bde87301cdc5b5ab1ae9a592e8ecbb2021dd7bc4b34e2ace60741cc362560bec566ba35178595a91932b8d5357e2c9cec92d393b0fa7831852476",
+ "It's well we cannot hear the screams/That we create in others' dreams.",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yIt's well we cannot hear the scream\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00#",
+ },
+ {
+ "91eccc3d5375fd026e4d6787874b1dce201cecd8a27dbded5065728cb2d09c58a3d467bb1faf353bf7ba567e005245d5321b55bc344f7c07b91cb6f26c959be7",
+ "You remind me of a TV show, but that's all right: I watch it anyway.",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yYou remind me of a TV show, but th\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\"",
+ },
+ {
+ "fabbbe22180f1f137cfdc9556d2570e775d1ae02a597ded43a72a40f9b485d500043b7be128fb9fcd982b83159a0d99aa855a9e7cc4240c00dc01a9bdf8218d7",
+ "C is as portable as Stonehedge!!",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yC is as portable\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x10",
+ },
+ {
+ "2ecdec235c1fa4fc2a154d8fba1dddb8a72a1ad73838b51d792331d143f8b96a9f6fcb0f34d7caa351fe6d88771c4f105040e0392f06e0621689d33b2f3ba92e",
+ "Even if I could be Shakespeare, I think I should still choose to be Faraday. - A. Huxley",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yEven if I could be Shakespeare, I think I sh\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00,",
+ },
+ {
+ "7ad681f6f96f82f7abfa7ecc0334e8fa16d3dc1cdc45b60b7af43fe4075d2357c0c1d60e98350f1afb1f2fe7a4d7cd2ad55b88e458e06b73c40b437331f5dab4",
+ "The fugacity of a constituent in a mixture of gases at a given temperature is proportional to its mole fraction. Lewis-Randall Rule",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yThe fugacity of a constituent in a mixture of gases at a given tem\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00B",
+ },
+ {
+ "833f9248ab4a3b9e5131f745fda1ffd2dd435b30e965957e78291c7ab73605fd1912b0794e5c233ab0a12d205a39778d19b83515d6a47003f19cdee51d98c7e0",
+ "How can you write a big system without C++? -Paul Glick",
+ "sha\aj\t\xe6g\xf3\xbc\xc9\b\xbbg\xae\x85\x84ʧ;<n\xf3r\xfe\x94\xf8+\xa5O\xf5:_\x1d6\xf1Q\x0eR\u007f\xad\xe6\x82ћ\x05h\x8c+>l\x1f\x1f\x83٫\xfbA\xbdk[\xe0\xcd\x19\x13~!yHow can you write a big syst\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x1c",
+ },
+}
+
+func testHash(t *testing.T, name, in, outHex string, oneShotResult []byte, digestFunc hash.Hash) {
+ if calculated := hex.EncodeToString(oneShotResult); calculated != outHex {
+ t.Errorf("one-shot result for %s(%q) = %q, but expected %q", name, in, calculated, outHex)
+ return
+ }
+
+ for pass := 0; pass < 3; pass++ {
+ if pass < 2 {
+ io.WriteString(digestFunc, in)
+ } else {
+ io.WriteString(digestFunc, in[:len(in)/2])
+ digestFunc.Sum(nil)
+ io.WriteString(digestFunc, in[len(in)/2:])
+ }
+
+ if calculated := hex.EncodeToString(digestFunc.Sum(nil)); calculated != outHex {
+ t.Errorf("%s(%q) = %q (in pass #%d), but expected %q", name, in, calculated, pass, outHex)
+ }
+ digestFunc.Reset()
+ }
+}
+
+func TestGolden(t *testing.T) {
+ tests := []struct {
+ name string
+ oneShotHash func(in []byte) []byte
+ digest hash.Hash
+ golden []sha512Test
+ }{
+ {
+ "SHA512/224",
+ func(in []byte) []byte { a := Sum512_224(in); return a[:] },
+ New512_224(),
+ golden224,
+ },
+ {
+ "SHA512/256",
+ func(in []byte) []byte { a := Sum512_256(in); return a[:] },
+ New512_256(),
+ golden256,
+ },
+ {
+ "SHA384",
+ func(in []byte) []byte { a := Sum384(in); return a[:] },
+ New384(),
+ golden384,
+ },
+ {
+ "SHA512",
+ func(in []byte) []byte { a := Sum512(in); return a[:] },
+ New(),
+ golden512,
+ },
+ }
+ for _, tt := range tests {
+ for _, test := range tt.golden {
+ in := []byte(test.in)
+ testHash(t, tt.name, test.in, test.out, tt.oneShotHash(in), tt.digest)
+ }
+ }
+}
+
+func TestGoldenMarshal(t *testing.T) {
+ tests := []struct {
+ name string
+ newHash func() hash.Hash
+ golden []sha512Test
+ }{
+ {"512/224", New512_224, golden224},
+ {"512/256", New512_256, golden256},
+ {"384", New384, golden384},
+ {"512", New, golden512},
+ }
+
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ for _, test := range tt.golden {
+ h := tt.newHash()
+ h2 := tt.newHash()
+
+ io.WriteString(h, test.in[:len(test.in)/2])
+
+ state, err := h.(encoding.BinaryMarshaler).MarshalBinary()
+ if err != nil {
+ t.Errorf("could not marshal: %v", err)
+ return
+ }
+
+ if string(state) != test.halfState {
+ t.Errorf("New%s(%q) state = %q, want %q", tt.name, test.in, state, test.halfState)
+ continue
+ }
+
+ if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err != nil {
+ t.Errorf("could not unmarshal: %v", err)
+ return
+ }
+
+ io.WriteString(h, test.in[len(test.in)/2:])
+ io.WriteString(h2, test.in[len(test.in)/2:])
+
+ if actual, actual2 := h.Sum(nil), h2.Sum(nil); !bytes.Equal(actual, actual2) {
+ t.Errorf("New%s(%q) = 0x%x != marshaled 0x%x", tt.name, test.in, actual, actual2)
+ }
+ }
+ })
+ }
+}
+
+func TestMarshalMismatch(t *testing.T) {
+ h := []func() hash.Hash{
+ New,
+ New384,
+ New512_224,
+ New512_256,
+ }
+
+ for i, fn1 := range h {
+ for j, fn2 := range h {
+ if i == j {
+ continue
+ }
+
+ h1 := fn1()
+ h2 := fn2()
+
+ state, err := h1.(encoding.BinaryMarshaler).MarshalBinary()
+ if err != nil {
+ t.Errorf("i=%d: could not marshal: %v", i, err)
+ continue
+ }
+
+ if err := h2.(encoding.BinaryUnmarshaler).UnmarshalBinary(state); err == nil {
+ t.Errorf("i=%d, j=%d: got no error, expected one: %v", i, j, err)
+ }
+ }
+ }
+}
+
+func TestSize(t *testing.T) {
+ c := New()
+ if got := c.Size(); got != Size {
+ t.Errorf("Size = %d; want %d", got, Size)
+ }
+ c = New384()
+ if got := c.Size(); got != Size384 {
+ t.Errorf("New384.Size = %d; want %d", got, Size384)
+ }
+ c = New512_224()
+ if got := c.Size(); got != Size224 {
+ t.Errorf("New512224.Size = %d; want %d", got, Size224)
+ }
+ c = New512_256()
+ if got := c.Size(); got != Size256 {
+ t.Errorf("New512256.Size = %d; want %d", got, Size256)
+ }
+}
+
+func TestBlockSize(t *testing.T) {
+ c := New()
+ if got := c.BlockSize(); got != BlockSize {
+ t.Errorf("BlockSize = %d; want %d", got, BlockSize)
+ }
+}
+
+// Tests that blockGeneric (pure Go) and block (in assembly for some architectures) match.
+func TestBlockGeneric(t *testing.T) {
+ if boring.Enabled {
+ t.Skip("BoringCrypto doesn't expose digest")
+ }
+ gen, asm := New().(*digest), New().(*digest)
+ buf := make([]byte, BlockSize*20) // arbitrary factor
+ rand.Read(buf)
+ blockGeneric(gen, buf)
+ block(asm, buf)
+ if *gen != *asm {
+ t.Error("block and blockGeneric resulted in different states")
+ }
+}
+
+// Tests for unmarshaling hashes that have hashed a large amount of data
+// The initial hash generation is omitted from the test, because it takes a long time.
+// The test contains some already-generated states, and their expected sums
+// Tests a problem that is outlined in GitHub issue #29541
+// The problem is triggered when an amount of data has been hashed for which
+// the data length has a 1 in the 32nd bit. When casted to int, this changes
+// the sign of the value, and causes the modulus operation to return a
+// different result.
+type unmarshalTest struct {
+ state string
+ sum string
+}
+
+var largeUnmarshalTests = []unmarshalTest{
+ // Data length: 6_565_544_823
+ {
+ state: "sha\aηe\x0f\x0f\xe1r]#\aoJ!.{5B\xe4\x140\x91\xdd\x00a\xe1\xb3E&\xb9\xbb\aJ\x9f^\x9f\x03ͺD\x96H\x80\xb0X\x9d\xdeʸ\f\xf7:\xd5\xe6'\xb9\x93f\xddA\xf0~\xe1\x02\x14\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuv\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\x87VCw",
+ sum: "12d612357a1dbc74a28883dff79b83e7d2b881ae40d7a67fd7305490bc8a641cd1ce9ece598192080d6e9ac7e75d5988567a58a9812991299eb99a04ecb69523",
+ },
+ {
+ state: "sha\a2\xd2\xdc\xf5\xd7\xe2\xf9\x97\xaa\xe7}Fϱ\xbc\x8e\xbf\x12h\x83Z\xa1\xc7\xf5p>bfS T\xea\xee\x1e\xa6Z\x9c\xa4ڶ\u0086\bn\xe47\x8fsGs3\xe0\xda\\\x9dqZ\xa5\xf6\xd0kM\xa1\xf2\x00\x01\x02\x03\x04\x05\x06\a\b\t\n\v\f\r\x0e\x0f\x10\x11\x12\x13\x14\x15\x16\x17\x18\x19\x1a\x1b\x1c\x1d\x1e\x1f !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuv\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x01\xa7VCw",
+ sum: "94a04b9a901254cd94ca0313557e4be3ab1ca86e920c1f3efdc22d361e9ae12be66bc6d6dc5db79a0a4aa6eca6f293c1e9095bbae127ae405f6c325478343299",
+ },
+}
+
+func safeSum(h hash.Hash) (sum []byte, err error) {
+ defer func() {
+ if r := recover(); r != nil {
+ err = fmt.Errorf("sum panic: %v", r)
+ }
+ }()
+
+ return h.Sum(nil), nil
+}
+
+func TestLargeHashes(t *testing.T) {
+ for i, test := range largeUnmarshalTests {
+
+ h := New()
+ if err := h.(encoding.BinaryUnmarshaler).UnmarshalBinary([]byte(test.state)); err != nil {
+ t.Errorf("test %d could not unmarshal: %v", i, err)
+ continue
+ }
+
+ sum, err := safeSum(h)
+ if err != nil {
+ t.Errorf("test %d could not sum: %v", i, err)
+ continue
+ }
+
+ if fmt.Sprintf("%x", sum) != test.sum {
+ t.Errorf("test %d sum mismatch: expect %s got %x", i, test.sum, sum)
+ }
+ }
+}
+
+func TestAllocations(t *testing.T) {
+ if boring.Enabled {
+ t.Skip("BoringCrypto doesn't allocate the same way as stdlib")
+ }
+ in := []byte("hello, world!")
+ out := make([]byte, 0, Size)
+ h := New()
+ n := int(testing.AllocsPerRun(10, func() {
+ h.Reset()
+ h.Write(in)
+ out = h.Sum(out[:0])
+ }))
+ if n > 0 {
+ t.Errorf("allocs = %d, want 0", n)
+ }
+}
+
+var bench = New()
+var buf = make([]byte, 8192)
+
+func benchmarkSize(b *testing.B, size int) {
+ sum := make([]byte, bench.Size())
+ b.Run("New", func(b *testing.B) {
+ b.ReportAllocs()
+ b.SetBytes(int64(size))
+ for i := 0; i < b.N; i++ {
+ bench.Reset()
+ bench.Write(buf[:size])
+ bench.Sum(sum[:0])
+ }
+ })
+ b.Run("Sum384", func(b *testing.B) {
+ b.ReportAllocs()
+ b.SetBytes(int64(size))
+ for i := 0; i < b.N; i++ {
+ Sum384(buf[:size])
+ }
+ })
+ b.Run("Sum512", func(b *testing.B) {
+ b.ReportAllocs()
+ b.SetBytes(int64(size))
+ for i := 0; i < b.N; i++ {
+ Sum512(buf[:size])
+ }
+ })
+}
+
+func BenchmarkHash8Bytes(b *testing.B) {
+ benchmarkSize(b, 8)
+}
+
+func BenchmarkHash1K(b *testing.B) {
+ benchmarkSize(b, 1024)
+}
+
+func BenchmarkHash8K(b *testing.B) {
+ benchmarkSize(b, 8192)
+}
diff --git a/src/crypto/sha512/sha512block.go b/src/crypto/sha512/sha512block.go
new file mode 100644
index 0000000..81569c5
--- /dev/null
+++ b/src/crypto/sha512/sha512block.go
@@ -0,0 +1,144 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// SHA512 block step.
+// In its own file so that a faster assembly or C version
+// can be substituted easily.
+
+package sha512
+
+import "math/bits"
+
+var _K = []uint64{
+ 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,
+}
+
+func blockGeneric(dig *digest, p []byte) {
+ var w [80]uint64
+ h0, h1, h2, h3, h4, h5, h6, h7 := dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7]
+ for len(p) >= chunk {
+ for i := 0; i < 16; i++ {
+ j := i * 8
+ w[i] = uint64(p[j])<<56 | uint64(p[j+1])<<48 | uint64(p[j+2])<<40 | uint64(p[j+3])<<32 |
+ uint64(p[j+4])<<24 | uint64(p[j+5])<<16 | uint64(p[j+6])<<8 | uint64(p[j+7])
+ }
+ for i := 16; i < 80; i++ {
+ v1 := w[i-2]
+ t1 := bits.RotateLeft64(v1, -19) ^ bits.RotateLeft64(v1, -61) ^ (v1 >> 6)
+ v2 := w[i-15]
+ t2 := bits.RotateLeft64(v2, -1) ^ bits.RotateLeft64(v2, -8) ^ (v2 >> 7)
+
+ w[i] = t1 + w[i-7] + t2 + w[i-16]
+ }
+
+ a, b, c, d, e, f, g, h := h0, h1, h2, h3, h4, h5, h6, h7
+
+ for i := 0; i < 80; i++ {
+ t1 := h + (bits.RotateLeft64(e, -14) ^ bits.RotateLeft64(e, -18) ^ bits.RotateLeft64(e, -41)) + ((e & f) ^ (^e & g)) + _K[i] + w[i]
+
+ t2 := (bits.RotateLeft64(a, -28) ^ bits.RotateLeft64(a, -34) ^ bits.RotateLeft64(a, -39)) + ((a & b) ^ (a & c) ^ (b & c))
+
+ h = g
+ g = f
+ f = e
+ e = d + t1
+ d = c
+ c = b
+ b = a
+ a = t1 + t2
+ }
+
+ h0 += a
+ h1 += b
+ h2 += c
+ h3 += d
+ h4 += e
+ h5 += f
+ h6 += g
+ h7 += h
+
+ p = p[chunk:]
+ }
+
+ dig.h[0], dig.h[1], dig.h[2], dig.h[3], dig.h[4], dig.h[5], dig.h[6], dig.h[7] = h0, h1, h2, h3, h4, h5, h6, h7
+}
diff --git a/src/crypto/sha512/sha512block_amd64.go b/src/crypto/sha512/sha512block_amd64.go
new file mode 100644
index 0000000..8da3e14
--- /dev/null
+++ b/src/crypto/sha512/sha512block_amd64.go
@@ -0,0 +1,25 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build amd64
+
+package sha512
+
+import "internal/cpu"
+
+//go:noescape
+func blockAVX2(dig *digest, p []byte)
+
+//go:noescape
+func blockAMD64(dig *digest, p []byte)
+
+var useAVX2 = cpu.X86.HasAVX2 && cpu.X86.HasBMI1 && cpu.X86.HasBMI2
+
+func block(dig *digest, p []byte) {
+ if useAVX2 {
+ blockAVX2(dig, p)
+ } else {
+ blockAMD64(dig, p)
+ }
+}
diff --git a/src/crypto/sha512/sha512block_amd64.s b/src/crypto/sha512/sha512block_amd64.s
new file mode 100644
index 0000000..0fa0df2
--- /dev/null
+++ b/src/crypto/sha512/sha512block_amd64.s
@@ -0,0 +1,1468 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// SHA512 block routine. See sha512block.go for Go equivalent.
+//
+// The algorithm is detailed in FIPS 180-4:
+//
+// https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+//
+// Wt = Mt; for 0 <= t <= 15
+// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79
+//
+// a = H0
+// b = H1
+// c = H2
+// d = H3
+// e = H4
+// f = H5
+// g = H6
+// h = H7
+//
+// for t = 0 to 79 {
+// T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt
+// T2 = BIGSIGMA0(a) + Maj(a,b,c)
+// h = g
+// g = f
+// f = e
+// e = d + T1
+// d = c
+// c = b
+// b = a
+// a = T1 + T2
+// }
+//
+// H0 = a + H0
+// H1 = b + H1
+// H2 = c + H2
+// H3 = d + H3
+// H4 = e + H4
+// H5 = f + H5
+// H6 = g + H6
+// H7 = h + H7
+
+// Wt = Mt; for 0 <= t <= 15
+#define MSGSCHEDULE0(index) \
+ MOVQ (index*8)(SI), AX; \
+ BSWAPQ AX; \
+ MOVQ AX, (index*8)(BP)
+
+// Wt = SIGMA1(Wt-2) + Wt-7 + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79
+// SIGMA0(x) = ROTR(1,x) XOR ROTR(8,x) XOR SHR(7,x)
+// SIGMA1(x) = ROTR(19,x) XOR ROTR(61,x) XOR SHR(6,x)
+#define MSGSCHEDULE1(index) \
+ MOVQ ((index-2)*8)(BP), AX; \
+ MOVQ AX, CX; \
+ RORQ $19, AX; \
+ MOVQ CX, DX; \
+ RORQ $61, CX; \
+ SHRQ $6, DX; \
+ MOVQ ((index-15)*8)(BP), BX; \
+ XORQ CX, AX; \
+ MOVQ BX, CX; \
+ XORQ DX, AX; \
+ RORQ $1, BX; \
+ MOVQ CX, DX; \
+ SHRQ $7, DX; \
+ RORQ $8, CX; \
+ ADDQ ((index-7)*8)(BP), AX; \
+ XORQ CX, BX; \
+ XORQ DX, BX; \
+ ADDQ ((index-16)*8)(BP), BX; \
+ ADDQ BX, AX; \
+ MOVQ AX, ((index)*8)(BP)
+
+// Calculate T1 in AX - uses AX, CX and DX registers.
+// h is also used as an accumulator. Wt is passed in AX.
+// T1 = h + BIGSIGMA1(e) + Ch(e, f, g) + Kt + Wt
+// BIGSIGMA1(x) = ROTR(14,x) XOR ROTR(18,x) XOR ROTR(41,x)
+// Ch(x, y, z) = (x AND y) XOR (NOT x AND z)
+#define SHA512T1(const, e, f, g, h) \
+ MOVQ $const, DX; \
+ ADDQ AX, h; \
+ MOVQ e, AX; \
+ ADDQ DX, h; \
+ MOVQ e, CX; \
+ RORQ $14, AX; \
+ MOVQ e, DX; \
+ RORQ $18, CX; \
+ XORQ CX, AX; \
+ MOVQ e, CX; \
+ RORQ $41, DX; \
+ ANDQ f, CX; \
+ XORQ AX, DX; \
+ MOVQ e, AX; \
+ NOTQ AX; \
+ ADDQ DX, h; \
+ ANDQ g, AX; \
+ XORQ CX, AX; \
+ ADDQ h, AX
+
+// Calculate T2 in BX - uses BX, CX, DX and DI registers.
+// T2 = BIGSIGMA0(a) + Maj(a, b, c)
+// BIGSIGMA0(x) = ROTR(28,x) XOR ROTR(34,x) XOR ROTR(39,x)
+// Maj(x, y, z) = (x AND y) XOR (x AND z) XOR (y AND z)
+#define SHA512T2(a, b, c) \
+ MOVQ a, DI; \
+ MOVQ c, BX; \
+ RORQ $28, DI; \
+ MOVQ a, DX; \
+ ANDQ b, BX; \
+ RORQ $34, DX; \
+ MOVQ a, CX; \
+ ANDQ c, CX; \
+ XORQ DX, DI; \
+ XORQ CX, BX; \
+ MOVQ a, DX; \
+ MOVQ b, CX; \
+ RORQ $39, DX; \
+ ANDQ a, CX; \
+ XORQ CX, BX; \
+ XORQ DX, DI; \
+ ADDQ DI, BX
+
+// Calculate T1 and T2, then e = d + T1 and a = T1 + T2.
+// The values for e and a are stored in d and h, ready for rotation.
+#define SHA512ROUND(index, const, a, b, c, d, e, f, g, h) \
+ SHA512T1(const, e, f, g, h); \
+ SHA512T2(a, b, c); \
+ MOVQ BX, h; \
+ ADDQ AX, d; \
+ ADDQ AX, h
+
+#define SHA512ROUND0(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE0(index); \
+ SHA512ROUND(index, const, a, b, c, d, e, f, g, h)
+
+#define SHA512ROUND1(index, const, a, b, c, d, e, f, g, h) \
+ MSGSCHEDULE1(index); \
+ SHA512ROUND(index, const, a, b, c, d, e, f, g, h)
+
+TEXT ·blockAMD64(SB),0,$648-32
+ MOVQ p_base+8(FP), SI
+ MOVQ p_len+16(FP), DX
+ SHRQ $7, DX
+ SHLQ $7, DX
+
+ LEAQ (SI)(DX*1), DI
+ MOVQ DI, 640(SP)
+ CMPQ SI, DI
+ JEQ end
+
+ MOVQ dig+0(FP), BP
+ MOVQ (0*8)(BP), R8 // a = H0
+ MOVQ (1*8)(BP), R9 // b = H1
+ MOVQ (2*8)(BP), R10 // c = H2
+ MOVQ (3*8)(BP), R11 // d = H3
+ MOVQ (4*8)(BP), R12 // e = H4
+ MOVQ (5*8)(BP), R13 // f = H5
+ MOVQ (6*8)(BP), R14 // g = H6
+ MOVQ (7*8)(BP), R15 // h = H7
+
+loop:
+ MOVQ SP, BP // message schedule
+
+ SHA512ROUND0(0, 0x428a2f98d728ae22, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND0(1, 0x7137449123ef65cd, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND0(2, 0xb5c0fbcfec4d3b2f, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND0(3, 0xe9b5dba58189dbbc, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND0(4, 0x3956c25bf348b538, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND0(5, 0x59f111f1b605d019, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND0(6, 0x923f82a4af194f9b, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND0(7, 0xab1c5ed5da6d8118, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND0(8, 0xd807aa98a3030242, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND0(9, 0x12835b0145706fbe, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND0(10, 0x243185be4ee4b28c, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND0(11, 0x550c7dc3d5ffb4e2, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND0(12, 0x72be5d74f27b896f, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND0(13, 0x80deb1fe3b1696b1, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND0(14, 0x9bdc06a725c71235, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND0(15, 0xc19bf174cf692694, R9, R10, R11, R12, R13, R14, R15, R8)
+
+ SHA512ROUND1(16, 0xe49b69c19ef14ad2, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(17, 0xefbe4786384f25e3, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(18, 0x0fc19dc68b8cd5b5, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(19, 0x240ca1cc77ac9c65, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(20, 0x2de92c6f592b0275, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(21, 0x4a7484aa6ea6e483, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(22, 0x5cb0a9dcbd41fbd4, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(23, 0x76f988da831153b5, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(24, 0x983e5152ee66dfab, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(25, 0xa831c66d2db43210, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(26, 0xb00327c898fb213f, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(27, 0xbf597fc7beef0ee4, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(28, 0xc6e00bf33da88fc2, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(29, 0xd5a79147930aa725, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(30, 0x06ca6351e003826f, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(31, 0x142929670a0e6e70, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(32, 0x27b70a8546d22ffc, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(33, 0x2e1b21385c26c926, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(34, 0x4d2c6dfc5ac42aed, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(35, 0x53380d139d95b3df, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(36, 0x650a73548baf63de, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(37, 0x766a0abb3c77b2a8, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(38, 0x81c2c92e47edaee6, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(39, 0x92722c851482353b, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(40, 0xa2bfe8a14cf10364, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(41, 0xa81a664bbc423001, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(42, 0xc24b8b70d0f89791, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(43, 0xc76c51a30654be30, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(44, 0xd192e819d6ef5218, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(45, 0xd69906245565a910, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(46, 0xf40e35855771202a, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(47, 0x106aa07032bbd1b8, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(48, 0x19a4c116b8d2d0c8, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(49, 0x1e376c085141ab53, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(50, 0x2748774cdf8eeb99, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(51, 0x34b0bcb5e19b48a8, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(52, 0x391c0cb3c5c95a63, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(53, 0x4ed8aa4ae3418acb, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(54, 0x5b9cca4f7763e373, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(55, 0x682e6ff3d6b2b8a3, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(56, 0x748f82ee5defb2fc, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(57, 0x78a5636f43172f60, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(58, 0x84c87814a1f0ab72, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(59, 0x8cc702081a6439ec, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(60, 0x90befffa23631e28, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(61, 0xa4506cebde82bde9, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(62, 0xbef9a3f7b2c67915, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(63, 0xc67178f2e372532b, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(64, 0xca273eceea26619c, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(65, 0xd186b8c721c0c207, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(66, 0xeada7dd6cde0eb1e, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(67, 0xf57d4f7fee6ed178, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(68, 0x06f067aa72176fba, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(69, 0x0a637dc5a2c898a6, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(70, 0x113f9804bef90dae, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(71, 0x1b710b35131c471b, R9, R10, R11, R12, R13, R14, R15, R8)
+ SHA512ROUND1(72, 0x28db77f523047d84, R8, R9, R10, R11, R12, R13, R14, R15)
+ SHA512ROUND1(73, 0x32caab7b40c72493, R15, R8, R9, R10, R11, R12, R13, R14)
+ SHA512ROUND1(74, 0x3c9ebe0a15c9bebc, R14, R15, R8, R9, R10, R11, R12, R13)
+ SHA512ROUND1(75, 0x431d67c49c100d4c, R13, R14, R15, R8, R9, R10, R11, R12)
+ SHA512ROUND1(76, 0x4cc5d4becb3e42b6, R12, R13, R14, R15, R8, R9, R10, R11)
+ SHA512ROUND1(77, 0x597f299cfc657e2a, R11, R12, R13, R14, R15, R8, R9, R10)
+ SHA512ROUND1(78, 0x5fcb6fab3ad6faec, R10, R11, R12, R13, R14, R15, R8, R9)
+ SHA512ROUND1(79, 0x6c44198c4a475817, R9, R10, R11, R12, R13, R14, R15, R8)
+
+ MOVQ dig+0(FP), BP
+ ADDQ (0*8)(BP), R8 // H0 = a + H0
+ MOVQ R8, (0*8)(BP)
+ ADDQ (1*8)(BP), R9 // H1 = b + H1
+ MOVQ R9, (1*8)(BP)
+ ADDQ (2*8)(BP), R10 // H2 = c + H2
+ MOVQ R10, (2*8)(BP)
+ ADDQ (3*8)(BP), R11 // H3 = d + H3
+ MOVQ R11, (3*8)(BP)
+ ADDQ (4*8)(BP), R12 // H4 = e + H4
+ MOVQ R12, (4*8)(BP)
+ ADDQ (5*8)(BP), R13 // H5 = f + H5
+ MOVQ R13, (5*8)(BP)
+ ADDQ (6*8)(BP), R14 // H6 = g + H6
+ MOVQ R14, (6*8)(BP)
+ ADDQ (7*8)(BP), R15 // H7 = h + H7
+ MOVQ R15, (7*8)(BP)
+
+ ADDQ $128, SI
+ CMPQ SI, 640(SP)
+ JB loop
+
+end:
+ RET
+
+// Version below is based on "Fast SHA512 Implementations on Intel
+// Architecture Processors" White-paper
+// https://www.intel.com/content/dam/www/public/us/en/documents/white-papers/fast-sha512-implementations-ia-processors-paper.pdf
+// AVX2 version by Intel, same algorithm in Linux kernel:
+// https://github.com/torvalds/linux/blob/master/arch/x86/crypto/sha512-avx2-asm.S
+
+// James Guilford <james.guilford@intel.com>
+// Kirk Yap <kirk.s.yap@intel.com>
+// Tim Chen <tim.c.chen@linux.intel.com>
+// David Cote <david.m.cote@intel.com>
+// Aleksey Sidorov <aleksey.sidorov@intel.com>
+
+#define YFER_SIZE (4*8)
+#define SRND_SIZE (1*8)
+#define INP_SIZE (1*8)
+
+#define frame_YFER (0)
+#define frame_SRND (frame_YFER + YFER_SIZE)
+#define frame_INP (frame_SRND + SRND_SIZE)
+#define frame_INPEND (frame_INP + INP_SIZE)
+
+#define addm(p1, p2) \
+ ADDQ p1, p2; \
+ MOVQ p2, p1
+
+#define COPY_YMM_AND_BSWAP(p1, p2, p3) \
+ VMOVDQU p2, p1; \
+ VPSHUFB p3, p1, p1
+
+#define MY_VPALIGNR(YDST, YSRC1, YSRC2, RVAL) \
+ VPERM2F128 $0x3, YSRC2, YSRC1, YDST; \
+ VPALIGNR $RVAL, YSRC2, YDST, YDST
+
+DATA PSHUFFLE_BYTE_FLIP_MASK<>+0x00(SB)/8, $0x0001020304050607
+DATA PSHUFFLE_BYTE_FLIP_MASK<>+0x08(SB)/8, $0x08090a0b0c0d0e0f
+DATA PSHUFFLE_BYTE_FLIP_MASK<>+0x10(SB)/8, $0x1011121314151617
+DATA PSHUFFLE_BYTE_FLIP_MASK<>+0x18(SB)/8, $0x18191a1b1c1d1e1f
+
+GLOBL PSHUFFLE_BYTE_FLIP_MASK<>(SB), (NOPTR+RODATA), $32
+
+DATA MASK_YMM_LO<>+0x00(SB)/8, $0x0000000000000000
+DATA MASK_YMM_LO<>+0x08(SB)/8, $0x0000000000000000
+DATA MASK_YMM_LO<>+0x10(SB)/8, $0xFFFFFFFFFFFFFFFF
+DATA MASK_YMM_LO<>+0x18(SB)/8, $0xFFFFFFFFFFFFFFFF
+
+GLOBL MASK_YMM_LO<>(SB), (NOPTR+RODATA), $32
+
+TEXT ·blockAVX2(SB), NOSPLIT, $56-32
+ MOVQ dig+0(FP), SI
+ MOVQ p_base+8(FP), DI
+ MOVQ p_len+16(FP), DX
+
+ SHRQ $7, DX
+ SHLQ $7, DX
+
+ JZ done_hash
+ ADDQ DI, DX
+ MOVQ DX, frame_INPEND(SP)
+
+ MOVQ (0*8)(SI), AX
+ MOVQ (1*8)(SI), BX
+ MOVQ (2*8)(SI), CX
+ MOVQ (3*8)(SI), R8
+ MOVQ (4*8)(SI), DX
+ MOVQ (5*8)(SI), R9
+ MOVQ (6*8)(SI), R10
+ MOVQ (7*8)(SI), R11
+
+ VMOVDQU PSHUFFLE_BYTE_FLIP_MASK<>(SB), Y9
+
+loop0:
+ MOVQ ·_K+0(SB), BP
+
+ // byte swap first 16 dwords
+ COPY_YMM_AND_BSWAP(Y4, (0*32)(DI), Y9)
+ COPY_YMM_AND_BSWAP(Y5, (1*32)(DI), Y9)
+ COPY_YMM_AND_BSWAP(Y6, (2*32)(DI), Y9)
+ COPY_YMM_AND_BSWAP(Y7, (3*32)(DI), Y9)
+
+ MOVQ DI, frame_INP(SP)
+
+ // schedule 64 input dwords, by doing 12 rounds of 4 each
+ MOVQ $4, frame_SRND(SP)
+
+loop1:
+ VPADDQ (BP), Y4, Y0
+ VMOVDQU Y0, frame_YFER(SP)
+
+ MY_VPALIGNR(Y0, Y7, Y6, 8)
+
+ VPADDQ Y4, Y0, Y0
+
+ MY_VPALIGNR(Y1, Y5, Y4, 8)
+
+ VPSRLQ $1, Y1, Y2
+ VPSLLQ $(64-1), Y1, Y3
+ VPOR Y2, Y3, Y3
+
+ VPSRLQ $7, Y1, Y8
+
+ MOVQ AX, DI
+ RORXQ $41, DX, R13
+ RORXQ $18, DX, R14
+ ADDQ frame_YFER(SP), R11
+ ORQ CX, DI
+ MOVQ R9, R15
+ RORXQ $34, AX, R12
+
+ XORQ R14, R13
+ XORQ R10, R15
+ RORXQ $14, DX, R14
+
+ ANDQ DX, R15
+ XORQ R14, R13
+ RORXQ $39, AX, R14
+ ADDQ R11, R8
+
+ ANDQ BX, DI
+ XORQ R12, R14
+ RORXQ $28, AX, R12
+
+ XORQ R10, R15
+ XORQ R12, R14
+ MOVQ AX, R12
+ ANDQ CX, R12
+
+ ADDQ R13, R15
+ ORQ R12, DI
+ ADDQ R14, R11
+
+ ADDQ R15, R8
+
+ ADDQ R15, R11
+ ADDQ DI, R11
+
+ VPSRLQ $8, Y1, Y2
+ VPSLLQ $(64-8), Y1, Y1
+ VPOR Y2, Y1, Y1
+
+ VPXOR Y8, Y3, Y3
+ VPXOR Y1, Y3, Y1
+
+ VPADDQ Y1, Y0, Y0
+
+ VPERM2F128 $0x0, Y0, Y0, Y4
+
+ VPAND MASK_YMM_LO<>(SB), Y0, Y0
+
+ VPERM2F128 $0x11, Y7, Y7, Y2
+ VPSRLQ $6, Y2, Y8
+
+ MOVQ R11, DI
+ RORXQ $41, R8, R13
+ RORXQ $18, R8, R14
+ ADDQ 1*8+frame_YFER(SP), R10
+ ORQ BX, DI
+
+ MOVQ DX, R15
+ RORXQ $34, R11, R12
+ XORQ R14, R13
+ XORQ R9, R15
+
+ RORXQ $14, R8, R14
+ XORQ R14, R13
+ RORXQ $39, R11, R14
+ ANDQ R8, R15
+ ADDQ R10, CX
+
+ ANDQ AX, DI
+ XORQ R12, R14
+
+ RORXQ $28, R11, R12
+ XORQ R9, R15
+
+ XORQ R12, R14
+ MOVQ R11, R12
+ ANDQ BX, R12
+ ADDQ R13, R15
+
+ ORQ R12, DI
+ ADDQ R14, R10
+
+ ADDQ R15, CX
+ ADDQ R15, R10
+ ADDQ DI, R10
+
+ VPSRLQ $19, Y2, Y3
+ VPSLLQ $(64-19), Y2, Y1
+ VPOR Y1, Y3, Y3
+ VPXOR Y3, Y8, Y8
+ VPSRLQ $61, Y2, Y3
+ VPSLLQ $(64-61), Y2, Y1
+ VPOR Y1, Y3, Y3
+ VPXOR Y3, Y8, Y8
+
+ VPADDQ Y8, Y4, Y4
+
+ VPSRLQ $6, Y4, Y8
+
+ MOVQ R10, DI
+ RORXQ $41, CX, R13
+ ADDQ 2*8+frame_YFER(SP), R9
+
+ RORXQ $18, CX, R14
+ ORQ AX, DI
+ MOVQ R8, R15
+ XORQ DX, R15
+
+ RORXQ $34, R10, R12
+ XORQ R14, R13
+ ANDQ CX, R15
+
+ RORXQ $14, CX, R14
+ ADDQ R9, BX
+ ANDQ R11, DI
+
+ XORQ R14, R13
+ RORXQ $39, R10, R14
+ XORQ DX, R15
+
+ XORQ R12, R14
+ RORXQ $28, R10, R12
+
+ XORQ R12, R14
+ MOVQ R10, R12
+ ANDQ AX, R12
+ ADDQ R13, R15
+
+ ORQ R12, DI
+ ADDQ R14, R9
+ ADDQ R15, BX
+ ADDQ R15, R9
+
+ ADDQ DI, R9
+
+ VPSRLQ $19, Y4, Y3
+ VPSLLQ $(64-19), Y4, Y1
+ VPOR Y1, Y3, Y3
+ VPXOR Y3, Y8, Y8
+ VPSRLQ $61, Y4, Y3
+ VPSLLQ $(64-61), Y4, Y1
+ VPOR Y1, Y3, Y3
+ VPXOR Y3, Y8, Y8
+
+ VPADDQ Y8, Y0, Y2
+
+ VPBLENDD $0xF0, Y2, Y4, Y4
+
+ MOVQ R9, DI
+ RORXQ $41, BX, R13
+ RORXQ $18, BX, R14
+ ADDQ 3*8+frame_YFER(SP), DX
+ ORQ R11, DI
+
+ MOVQ CX, R15
+ RORXQ $34, R9, R12
+ XORQ R14, R13
+ XORQ R8, R15
+
+ RORXQ $14, BX, R14
+ ANDQ BX, R15
+ ADDQ DX, AX
+ ANDQ R10, DI
+
+ XORQ R14, R13
+ XORQ R8, R15
+
+ RORXQ $39, R9, R14
+ ADDQ R13, R15
+
+ XORQ R12, R14
+ ADDQ R15, AX
+
+ RORXQ $28, R9, R12
+
+ XORQ R12, R14
+ MOVQ R9, R12
+ ANDQ R11, R12
+ ORQ R12, DI
+
+ ADDQ R14, DX
+ ADDQ R15, DX
+ ADDQ DI, DX
+
+ VPADDQ 1*32(BP), Y5, Y0
+ VMOVDQU Y0, frame_YFER(SP)
+
+ MY_VPALIGNR(Y0, Y4, Y7, 8)
+
+ VPADDQ Y5, Y0, Y0
+
+ MY_VPALIGNR(Y1, Y6, Y5, 8)
+
+ VPSRLQ $1, Y1, Y2
+ VPSLLQ $(64-1), Y1, Y3
+ VPOR Y2, Y3, Y3
+
+ VPSRLQ $7, Y1, Y8
+
+ MOVQ DX, DI
+ RORXQ $41, AX, R13
+ RORXQ $18, AX, R14
+ ADDQ frame_YFER(SP), R8
+ ORQ R10, DI
+ MOVQ BX, R15
+ RORXQ $34, DX, R12
+
+ XORQ R14, R13
+ XORQ CX, R15
+ RORXQ $14, AX, R14
+
+ ANDQ AX, R15
+ XORQ R14, R13
+ RORXQ $39, DX, R14
+ ADDQ R8, R11
+
+ ANDQ R9, DI
+ XORQ R12, R14
+ RORXQ $28, DX, R12
+
+ XORQ CX, R15
+ XORQ R12, R14
+ MOVQ DX, R12
+ ANDQ R10, R12
+
+ ADDQ R13, R15
+ ORQ R12, DI
+ ADDQ R14, R8
+
+ ADDQ R15, R11
+
+ ADDQ R15, R8
+ ADDQ DI, R8
+
+ VPSRLQ $8, Y1, Y2
+ VPSLLQ $(64-8), Y1, Y1
+ VPOR Y2, Y1, Y1
+
+ VPXOR Y8, Y3, Y3
+ VPXOR Y1, Y3, Y1
+
+ VPADDQ Y1, Y0, Y0
+
+ VPERM2F128 $0x0, Y0, Y0, Y5
+
+ VPAND MASK_YMM_LO<>(SB), Y0, Y0
+
+ VPERM2F128 $0x11, Y4, Y4, Y2
+ VPSRLQ $6, Y2, Y8
+
+ MOVQ R8, DI
+ RORXQ $41, R11, R13
+ RORXQ $18, R11, R14
+ ADDQ 1*8+frame_YFER(SP), CX
+ ORQ R9, DI
+
+ MOVQ AX, R15
+ RORXQ $34, R8, R12
+ XORQ R14, R13
+ XORQ BX, R15
+
+ RORXQ $14, R11, R14
+ XORQ R14, R13
+ RORXQ $39, R8, R14
+ ANDQ R11, R15
+ ADDQ CX, R10
+
+ ANDQ DX, DI
+ XORQ R12, R14
+
+ RORXQ $28, R8, R12
+ XORQ BX, R15
+
+ XORQ R12, R14
+ MOVQ R8, R12
+ ANDQ R9, R12
+ ADDQ R13, R15
+
+ ORQ R12, DI
+ ADDQ R14, CX
+
+ ADDQ R15, R10
+ ADDQ R15, CX
+ ADDQ DI, CX
+
+ VPSRLQ $19, Y2, Y3
+ VPSLLQ $(64-19), Y2, Y1
+ VPOR Y1, Y3, Y3
+ VPXOR Y3, Y8, Y8
+ VPSRLQ $61, Y2, Y3
+ VPSLLQ $(64-61), Y2, Y1
+ VPOR Y1, Y3, Y3
+ VPXOR Y3, Y8, Y8
+
+ VPADDQ Y8, Y5, Y5
+
+ VPSRLQ $6, Y5, Y8
+
+ MOVQ CX, DI
+ RORXQ $41, R10, R13
+ ADDQ 2*8+frame_YFER(SP), BX
+
+ RORXQ $18, R10, R14
+ ORQ DX, DI
+ MOVQ R11, R15
+ XORQ AX, R15
+
+ RORXQ $34, CX, R12
+ XORQ R14, R13
+ ANDQ R10, R15
+
+ RORXQ $14, R10, R14
+ ADDQ BX, R9
+ ANDQ R8, DI
+
+ XORQ R14, R13
+ RORXQ $39, CX, R14
+ XORQ AX, R15
+
+ XORQ R12, R14
+ RORXQ $28, CX, R12
+
+ XORQ R12, R14
+ MOVQ CX, R12
+ ANDQ DX, R12
+ ADDQ R13, R15
+
+ ORQ R12, DI
+ ADDQ R14, BX
+ ADDQ R15, R9
+ ADDQ R15, BX
+
+ ADDQ DI, BX
+
+ VPSRLQ $19, Y5, Y3
+ VPSLLQ $(64-19), Y5, Y1
+ VPOR Y1, Y3, Y3
+ VPXOR Y3, Y8, Y8
+ VPSRLQ $61, Y5, Y3
+ VPSLLQ $(64-61), Y5, Y1
+ VPOR Y1, Y3, Y3
+ VPXOR Y3, Y8, Y8
+
+ VPADDQ Y8, Y0, Y2
+
+ VPBLENDD $0xF0, Y2, Y5, Y5
+
+ MOVQ BX, DI
+ RORXQ $41, R9, R13
+ RORXQ $18, R9, R14
+ ADDQ 3*8+frame_YFER(SP), AX
+ ORQ R8, DI
+
+ MOVQ R10, R15
+ RORXQ $34, BX, R12
+ XORQ R14, R13
+ XORQ R11, R15
+
+ RORXQ $14, R9, R14
+ ANDQ R9, R15
+ ADDQ AX, DX
+ ANDQ CX, DI
+
+ XORQ R14, R13
+ XORQ R11, R15
+
+ RORXQ $39, BX, R14
+ ADDQ R13, R15
+
+ XORQ R12, R14
+ ADDQ R15, DX
+
+ RORXQ $28, BX, R12
+
+ XORQ R12, R14
+ MOVQ BX, R12
+ ANDQ R8, R12
+ ORQ R12, DI
+
+ ADDQ R14, AX
+ ADDQ R15, AX
+ ADDQ DI, AX
+
+ VPADDQ 2*32(BP), Y6, Y0
+ VMOVDQU Y0, frame_YFER(SP)
+
+ MY_VPALIGNR(Y0, Y5, Y4, 8)
+
+ VPADDQ Y6, Y0, Y0
+
+ MY_VPALIGNR(Y1, Y7, Y6, 8)
+
+ VPSRLQ $1, Y1, Y2
+ VPSLLQ $(64-1), Y1, Y3
+ VPOR Y2, Y3, Y3
+
+ VPSRLQ $7, Y1, Y8
+
+ MOVQ AX, DI
+ RORXQ $41, DX, R13
+ RORXQ $18, DX, R14
+ ADDQ frame_YFER(SP), R11
+ ORQ CX, DI
+ MOVQ R9, R15
+ RORXQ $34, AX, R12
+
+ XORQ R14, R13
+ XORQ R10, R15
+ RORXQ $14, DX, R14
+
+ ANDQ DX, R15
+ XORQ R14, R13
+ RORXQ $39, AX, R14
+ ADDQ R11, R8
+
+ ANDQ BX, DI
+ XORQ R12, R14
+ RORXQ $28, AX, R12
+
+ XORQ R10, R15
+ XORQ R12, R14
+ MOVQ AX, R12
+ ANDQ CX, R12
+
+ ADDQ R13, R15
+ ORQ R12, DI
+ ADDQ R14, R11
+
+ ADDQ R15, R8
+
+ ADDQ R15, R11
+ ADDQ DI, R11
+
+ VPSRLQ $8, Y1, Y2
+ VPSLLQ $(64-8), Y1, Y1
+ VPOR Y2, Y1, Y1
+
+ VPXOR Y8, Y3, Y3
+ VPXOR Y1, Y3, Y1
+
+ VPADDQ Y1, Y0, Y0
+
+ VPERM2F128 $0x0, Y0, Y0, Y6
+
+ VPAND MASK_YMM_LO<>(SB), Y0, Y0
+
+ VPERM2F128 $0x11, Y5, Y5, Y2
+ VPSRLQ $6, Y2, Y8
+
+ MOVQ R11, DI
+ RORXQ $41, R8, R13
+ RORXQ $18, R8, R14
+ ADDQ 1*8+frame_YFER(SP), R10
+ ORQ BX, DI
+
+ MOVQ DX, R15
+ RORXQ $34, R11, R12
+ XORQ R14, R13
+ XORQ R9, R15
+
+ RORXQ $14, R8, R14
+ XORQ R14, R13
+ RORXQ $39, R11, R14
+ ANDQ R8, R15
+ ADDQ R10, CX
+
+ ANDQ AX, DI
+ XORQ R12, R14
+
+ RORXQ $28, R11, R12
+ XORQ R9, R15
+
+ XORQ R12, R14
+ MOVQ R11, R12
+ ANDQ BX, R12
+ ADDQ R13, R15
+
+ ORQ R12, DI
+ ADDQ R14, R10
+
+ ADDQ R15, CX
+ ADDQ R15, R10
+ ADDQ DI, R10
+
+ VPSRLQ $19, Y2, Y3
+ VPSLLQ $(64-19), Y2, Y1
+ VPOR Y1, Y3, Y3
+ VPXOR Y3, Y8, Y8
+ VPSRLQ $61, Y2, Y3
+ VPSLLQ $(64-61), Y2, Y1
+ VPOR Y1, Y3, Y3
+ VPXOR Y3, Y8, Y8
+
+ VPADDQ Y8, Y6, Y6
+
+ VPSRLQ $6, Y6, Y8
+
+ MOVQ R10, DI
+ RORXQ $41, CX, R13
+ ADDQ 2*8+frame_YFER(SP), R9
+
+ RORXQ $18, CX, R14
+ ORQ AX, DI
+ MOVQ R8, R15
+ XORQ DX, R15
+
+ RORXQ $34, R10, R12
+ XORQ R14, R13
+ ANDQ CX, R15
+
+ RORXQ $14, CX, R14
+ ADDQ R9, BX
+ ANDQ R11, DI
+
+ XORQ R14, R13
+ RORXQ $39, R10, R14
+ XORQ DX, R15
+
+ XORQ R12, R14
+ RORXQ $28, R10, R12
+
+ XORQ R12, R14
+ MOVQ R10, R12
+ ANDQ AX, R12
+ ADDQ R13, R15
+
+ ORQ R12, DI
+ ADDQ R14, R9
+ ADDQ R15, BX
+ ADDQ R15, R9
+
+ ADDQ DI, R9
+
+ VPSRLQ $19, Y6, Y3
+ VPSLLQ $(64-19), Y6, Y1
+ VPOR Y1, Y3, Y3
+ VPXOR Y3, Y8, Y8
+ VPSRLQ $61, Y6, Y3
+ VPSLLQ $(64-61), Y6, Y1
+ VPOR Y1, Y3, Y3
+ VPXOR Y3, Y8, Y8
+
+ VPADDQ Y8, Y0, Y2
+
+ VPBLENDD $0xF0, Y2, Y6, Y6
+
+ MOVQ R9, DI
+ RORXQ $41, BX, R13
+ RORXQ $18, BX, R14
+ ADDQ 3*8+frame_YFER(SP), DX
+ ORQ R11, DI
+
+ MOVQ CX, R15
+ RORXQ $34, R9, R12
+ XORQ R14, R13
+ XORQ R8, R15
+
+ RORXQ $14, BX, R14
+ ANDQ BX, R15
+ ADDQ DX, AX
+ ANDQ R10, DI
+
+ XORQ R14, R13
+ XORQ R8, R15
+
+ RORXQ $39, R9, R14
+ ADDQ R13, R15
+
+ XORQ R12, R14
+ ADDQ R15, AX
+
+ RORXQ $28, R9, R12
+
+ XORQ R12, R14
+ MOVQ R9, R12
+ ANDQ R11, R12
+ ORQ R12, DI
+
+ ADDQ R14, DX
+ ADDQ R15, DX
+ ADDQ DI, DX
+
+ VPADDQ 3*32(BP), Y7, Y0
+ VMOVDQU Y0, frame_YFER(SP)
+ ADDQ $(4*32), BP
+
+ MY_VPALIGNR(Y0, Y6, Y5, 8)
+
+ VPADDQ Y7, Y0, Y0
+
+ MY_VPALIGNR(Y1, Y4, Y7, 8)
+
+ VPSRLQ $1, Y1, Y2
+ VPSLLQ $(64-1), Y1, Y3
+ VPOR Y2, Y3, Y3
+
+ VPSRLQ $7, Y1, Y8
+
+ MOVQ DX, DI
+ RORXQ $41, AX, R13
+ RORXQ $18, AX, R14
+ ADDQ frame_YFER(SP), R8
+ ORQ R10, DI
+ MOVQ BX, R15
+ RORXQ $34, DX, R12
+
+ XORQ R14, R13
+ XORQ CX, R15
+ RORXQ $14, AX, R14
+
+ ANDQ AX, R15
+ XORQ R14, R13
+ RORXQ $39, DX, R14
+ ADDQ R8, R11
+
+ ANDQ R9, DI
+ XORQ R12, R14
+ RORXQ $28, DX, R12
+
+ XORQ CX, R15
+ XORQ R12, R14
+ MOVQ DX, R12
+ ANDQ R10, R12
+
+ ADDQ R13, R15
+ ORQ R12, DI
+ ADDQ R14, R8
+
+ ADDQ R15, R11
+
+ ADDQ R15, R8
+ ADDQ DI, R8
+
+ VPSRLQ $8, Y1, Y2
+ VPSLLQ $(64-8), Y1, Y1
+ VPOR Y2, Y1, Y1
+
+ VPXOR Y8, Y3, Y3
+ VPXOR Y1, Y3, Y1
+
+ VPADDQ Y1, Y0, Y0
+
+ VPERM2F128 $0x0, Y0, Y0, Y7
+
+ VPAND MASK_YMM_LO<>(SB), Y0, Y0
+
+ VPERM2F128 $0x11, Y6, Y6, Y2
+ VPSRLQ $6, Y2, Y8
+
+ MOVQ R8, DI
+ RORXQ $41, R11, R13
+ RORXQ $18, R11, R14
+ ADDQ 1*8+frame_YFER(SP), CX
+ ORQ R9, DI
+
+ MOVQ AX, R15
+ RORXQ $34, R8, R12
+ XORQ R14, R13
+ XORQ BX, R15
+
+ RORXQ $14, R11, R14
+ XORQ R14, R13
+ RORXQ $39, R8, R14
+ ANDQ R11, R15
+ ADDQ CX, R10
+
+ ANDQ DX, DI
+ XORQ R12, R14
+
+ RORXQ $28, R8, R12
+ XORQ BX, R15
+
+ XORQ R12, R14
+ MOVQ R8, R12
+ ANDQ R9, R12
+ ADDQ R13, R15
+
+ ORQ R12, DI
+ ADDQ R14, CX
+
+ ADDQ R15, R10
+ ADDQ R15, CX
+ ADDQ DI, CX
+
+ VPSRLQ $19, Y2, Y3
+ VPSLLQ $(64-19), Y2, Y1
+ VPOR Y1, Y3, Y3
+ VPXOR Y3, Y8, Y8
+ VPSRLQ $61, Y2, Y3
+ VPSLLQ $(64-61), Y2, Y1
+ VPOR Y1, Y3, Y3
+ VPXOR Y3, Y8, Y8
+
+ VPADDQ Y8, Y7, Y7
+
+ VPSRLQ $6, Y7, Y8
+
+ MOVQ CX, DI
+ RORXQ $41, R10, R13
+ ADDQ 2*8+frame_YFER(SP), BX
+
+ RORXQ $18, R10, R14
+ ORQ DX, DI
+ MOVQ R11, R15
+ XORQ AX, R15
+
+ RORXQ $34, CX, R12
+ XORQ R14, R13
+ ANDQ R10, R15
+
+ RORXQ $14, R10, R14
+ ADDQ BX, R9
+ ANDQ R8, DI
+
+ XORQ R14, R13
+ RORXQ $39, CX, R14
+ XORQ AX, R15
+
+ XORQ R12, R14
+ RORXQ $28, CX, R12
+
+ XORQ R12, R14
+ MOVQ CX, R12
+ ANDQ DX, R12
+ ADDQ R13, R15
+
+ ORQ R12, DI
+ ADDQ R14, BX
+ ADDQ R15, R9
+ ADDQ R15, BX
+
+ ADDQ DI, BX
+
+ VPSRLQ $19, Y7, Y3
+ VPSLLQ $(64-19), Y7, Y1
+ VPOR Y1, Y3, Y3
+ VPXOR Y3, Y8, Y8
+ VPSRLQ $61, Y7, Y3
+ VPSLLQ $(64-61), Y7, Y1
+ VPOR Y1, Y3, Y3
+ VPXOR Y3, Y8, Y8
+
+ VPADDQ Y8, Y0, Y2
+
+ VPBLENDD $0xF0, Y2, Y7, Y7
+
+ MOVQ BX, DI
+ RORXQ $41, R9, R13
+ RORXQ $18, R9, R14
+ ADDQ 3*8+frame_YFER(SP), AX
+ ORQ R8, DI
+
+ MOVQ R10, R15
+ RORXQ $34, BX, R12
+ XORQ R14, R13
+ XORQ R11, R15
+
+ RORXQ $14, R9, R14
+ ANDQ R9, R15
+ ADDQ AX, DX
+ ANDQ CX, DI
+
+ XORQ R14, R13
+ XORQ R11, R15
+
+ RORXQ $39, BX, R14
+ ADDQ R13, R15
+
+ XORQ R12, R14
+ ADDQ R15, DX
+
+ RORXQ $28, BX, R12
+
+ XORQ R12, R14
+ MOVQ BX, R12
+ ANDQ R8, R12
+ ORQ R12, DI
+
+ ADDQ R14, AX
+ ADDQ R15, AX
+ ADDQ DI, AX
+
+ SUBQ $1, frame_SRND(SP)
+ JNE loop1
+
+ MOVQ $2, frame_SRND(SP)
+
+loop2:
+ VPADDQ (BP), Y4, Y0
+ VMOVDQU Y0, frame_YFER(SP)
+
+ MOVQ R9, R15
+ RORXQ $41, DX, R13
+ RORXQ $18, DX, R14
+ XORQ R10, R15
+
+ XORQ R14, R13
+ RORXQ $14, DX, R14
+ ANDQ DX, R15
+
+ XORQ R14, R13
+ RORXQ $34, AX, R12
+ XORQ R10, R15
+ RORXQ $39, AX, R14
+ MOVQ AX, DI
+
+ XORQ R12, R14
+ RORXQ $28, AX, R12
+ ADDQ frame_YFER(SP), R11
+ ORQ CX, DI
+
+ XORQ R12, R14
+ MOVQ AX, R12
+ ANDQ BX, DI
+ ANDQ CX, R12
+ ADDQ R13, R15
+
+ ADDQ R11, R8
+ ORQ R12, DI
+ ADDQ R14, R11
+
+ ADDQ R15, R8
+
+ ADDQ R15, R11
+ MOVQ DX, R15
+ RORXQ $41, R8, R13
+ RORXQ $18, R8, R14
+ XORQ R9, R15
+
+ XORQ R14, R13
+ RORXQ $14, R8, R14
+ ANDQ R8, R15
+ ADDQ DI, R11
+
+ XORQ R14, R13
+ RORXQ $34, R11, R12
+ XORQ R9, R15
+ RORXQ $39, R11, R14
+ MOVQ R11, DI
+
+ XORQ R12, R14
+ RORXQ $28, R11, R12
+ ADDQ 8*1+frame_YFER(SP), R10
+ ORQ BX, DI
+
+ XORQ R12, R14
+ MOVQ R11, R12
+ ANDQ AX, DI
+ ANDQ BX, R12
+ ADDQ R13, R15
+
+ ADDQ R10, CX
+ ORQ R12, DI
+ ADDQ R14, R10
+
+ ADDQ R15, CX
+
+ ADDQ R15, R10
+ MOVQ R8, R15
+ RORXQ $41, CX, R13
+ RORXQ $18, CX, R14
+ XORQ DX, R15
+
+ XORQ R14, R13
+ RORXQ $14, CX, R14
+ ANDQ CX, R15
+ ADDQ DI, R10
+
+ XORQ R14, R13
+ RORXQ $34, R10, R12
+ XORQ DX, R15
+ RORXQ $39, R10, R14
+ MOVQ R10, DI
+
+ XORQ R12, R14
+ RORXQ $28, R10, R12
+ ADDQ 8*2+frame_YFER(SP), R9
+ ORQ AX, DI
+
+ XORQ R12, R14
+ MOVQ R10, R12
+ ANDQ R11, DI
+ ANDQ AX, R12
+ ADDQ R13, R15
+
+ ADDQ R9, BX
+ ORQ R12, DI
+ ADDQ R14, R9
+
+ ADDQ R15, BX
+
+ ADDQ R15, R9
+ MOVQ CX, R15
+ RORXQ $41, BX, R13
+ RORXQ $18, BX, R14
+ XORQ R8, R15
+
+ XORQ R14, R13
+ RORXQ $14, BX, R14
+ ANDQ BX, R15
+ ADDQ DI, R9
+
+ XORQ R14, R13
+ RORXQ $34, R9, R12
+ XORQ R8, R15
+ RORXQ $39, R9, R14
+ MOVQ R9, DI
+
+ XORQ R12, R14
+ RORXQ $28, R9, R12
+ ADDQ 8*3+frame_YFER(SP), DX
+ ORQ R11, DI
+
+ XORQ R12, R14
+ MOVQ R9, R12
+ ANDQ R10, DI
+ ANDQ R11, R12
+ ADDQ R13, R15
+
+ ADDQ DX, AX
+ ORQ R12, DI
+ ADDQ R14, DX
+
+ ADDQ R15, AX
+
+ ADDQ R15, DX
+
+ ADDQ DI, DX
+
+ VPADDQ 1*32(BP), Y5, Y0
+ VMOVDQU Y0, frame_YFER(SP)
+ ADDQ $(2*32), BP
+
+ MOVQ BX, R15
+ RORXQ $41, AX, R13
+ RORXQ $18, AX, R14
+ XORQ CX, R15
+
+ XORQ R14, R13
+ RORXQ $14, AX, R14
+ ANDQ AX, R15
+
+ XORQ R14, R13
+ RORXQ $34, DX, R12
+ XORQ CX, R15
+ RORXQ $39, DX, R14
+ MOVQ DX, DI
+
+ XORQ R12, R14
+ RORXQ $28, DX, R12
+ ADDQ frame_YFER(SP), R8
+ ORQ R10, DI
+
+ XORQ R12, R14
+ MOVQ DX, R12
+ ANDQ R9, DI
+ ANDQ R10, R12
+ ADDQ R13, R15
+
+ ADDQ R8, R11
+ ORQ R12, DI
+ ADDQ R14, R8
+
+ ADDQ R15, R11
+
+ ADDQ R15, R8
+ MOVQ AX, R15
+ RORXQ $41, R11, R13
+ RORXQ $18, R11, R14
+ XORQ BX, R15
+
+ XORQ R14, R13
+ RORXQ $14, R11, R14
+ ANDQ R11, R15
+ ADDQ DI, R8
+
+ XORQ R14, R13
+ RORXQ $34, R8, R12
+ XORQ BX, R15
+ RORXQ $39, R8, R14
+ MOVQ R8, DI
+
+ XORQ R12, R14
+ RORXQ $28, R8, R12
+ ADDQ 8*1+frame_YFER(SP), CX
+ ORQ R9, DI
+
+ XORQ R12, R14
+ MOVQ R8, R12
+ ANDQ DX, DI
+ ANDQ R9, R12
+ ADDQ R13, R15
+
+ ADDQ CX, R10
+ ORQ R12, DI
+ ADDQ R14, CX
+
+ ADDQ R15, R10
+
+ ADDQ R15, CX
+ MOVQ R11, R15
+ RORXQ $41, R10, R13
+ RORXQ $18, R10, R14
+ XORQ AX, R15
+
+ XORQ R14, R13
+ RORXQ $14, R10, R14
+ ANDQ R10, R15
+ ADDQ DI, CX
+
+ XORQ R14, R13
+ RORXQ $34, CX, R12
+ XORQ AX, R15
+ RORXQ $39, CX, R14
+ MOVQ CX, DI
+
+ XORQ R12, R14
+ RORXQ $28, CX, R12
+ ADDQ 8*2+frame_YFER(SP), BX
+ ORQ DX, DI
+
+ XORQ R12, R14
+ MOVQ CX, R12
+ ANDQ R8, DI
+ ANDQ DX, R12
+ ADDQ R13, R15
+
+ ADDQ BX, R9
+ ORQ R12, DI
+ ADDQ R14, BX
+
+ ADDQ R15, R9
+
+ ADDQ R15, BX
+ MOVQ R10, R15
+ RORXQ $41, R9, R13
+ RORXQ $18, R9, R14
+ XORQ R11, R15
+
+ XORQ R14, R13
+ RORXQ $14, R9, R14
+ ANDQ R9, R15
+ ADDQ DI, BX
+
+ XORQ R14, R13
+ RORXQ $34, BX, R12
+ XORQ R11, R15
+ RORXQ $39, BX, R14
+ MOVQ BX, DI
+
+ XORQ R12, R14
+ RORXQ $28, BX, R12
+ ADDQ 8*3+frame_YFER(SP), AX
+ ORQ R8, DI
+
+ XORQ R12, R14
+ MOVQ BX, R12
+ ANDQ CX, DI
+ ANDQ R8, R12
+ ADDQ R13, R15
+
+ ADDQ AX, DX
+ ORQ R12, DI
+ ADDQ R14, AX
+
+ ADDQ R15, DX
+
+ ADDQ R15, AX
+
+ ADDQ DI, AX
+
+ VMOVDQU Y6, Y4
+ VMOVDQU Y7, Y5
+
+ SUBQ $1, frame_SRND(SP)
+ JNE loop2
+
+ addm(8*0(SI),AX)
+ addm(8*1(SI),BX)
+ addm(8*2(SI),CX)
+ addm(8*3(SI),R8)
+ addm(8*4(SI),DX)
+ addm(8*5(SI),R9)
+ addm(8*6(SI),R10)
+ addm(8*7(SI),R11)
+
+ MOVQ frame_INP(SP), DI
+ ADDQ $128, DI
+ CMPQ DI, frame_INPEND(SP)
+ JNE loop0
+
+done_hash:
+ VZEROUPPER
+ RET
diff --git a/src/crypto/sha512/sha512block_arm64.go b/src/crypto/sha512/sha512block_arm64.go
new file mode 100644
index 0000000..243eb5c
--- /dev/null
+++ b/src/crypto/sha512/sha512block_arm64.go
@@ -0,0 +1,18 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha512
+
+import "internal/cpu"
+
+func block(dig *digest, p []byte) {
+ if cpu.ARM64.HasSHA512 {
+ blockAsm(dig, p)
+ return
+ }
+ blockGeneric(dig, p)
+}
+
+//go:noescape
+func blockAsm(dig *digest, p []byte)
diff --git a/src/crypto/sha512/sha512block_arm64.s b/src/crypto/sha512/sha512block_arm64.s
new file mode 100644
index 0000000..dfc35d6
--- /dev/null
+++ b/src/crypto/sha512/sha512block_arm64.s
@@ -0,0 +1,135 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Based on the Linux Kernel with the following comment:
+// Algorithm based on https://git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git/commit/?id=fb87127bcefc17efab757606e1b1e333fd614dd0
+// Originally written by Ard Biesheuvel <ard.biesheuvel@linaro.org>
+
+#include "textflag.h"
+
+#define SHA512TRANS(i0, i1, i2, i3, i4, rc0, in0) \
+ VADD in0.D2, rc0.D2, V5.D2 \
+ VEXT $8, i3.B16, i2.B16, V6.B16 \
+ VEXT $8, V5.B16, V5.B16, V5.B16 \
+ VEXT $8, i2.B16, i1.B16, V7.B16 \
+ VADD V5.D2, i3.D2, i3.D2 \
+
+#define SHA512ROUND(i0, i1, i2, i3, i4, rc0, rc1, in0, in1, in2, in3, in4) \
+ VLD1.P 16(R4), [rc1.D2] \
+ SHA512TRANS(i0, i1, i2, i3, i4, rc0, in0) \
+ VEXT $8, in4.B16, in3.B16, V5.B16 \
+ SHA512SU0 in1.D2, in0.D2 \
+ SHA512H V7.D2, V6, i3 \
+ SHA512SU1 V5.D2, in2.D2, in0.D2 \
+ VADD i3.D2, i1.D2, i4.D2 \
+ SHA512H2 i0.D2, i1, i3
+
+#define SHA512ROUND_NO_UPDATE(i0, i1, i2, i3, i4, rc0, rc1, in0) \
+ VLD1.P 16(R4), [rc1.D2] \
+ SHA512TRANS(i0, i1, i2, i3, i4, rc0, in0) \
+ SHA512H V7.D2, V6, i3 \
+ VADD i3.D2, i1.D2, i4.D2 \
+ SHA512H2 i0.D2, i1, i3
+
+#define SHA512ROUND_LAST(i0, i1, i2, i3, i4, rc0, in0) \
+ SHA512TRANS(i0, i1, i2, i3, i4, rc0, in0) \
+ SHA512H V7.D2, V6, i3 \
+ VADD i3.D2, i1.D2, i4.D2 \
+ SHA512H2 i0.D2, i1, i3
+
+// func blockAsm(dig *digest, p []byte)
+TEXT ·blockAsm(SB),NOSPLIT,$0
+ MOVD dig+0(FP), R0
+ MOVD p_base+8(FP), R1
+ MOVD p_len+16(FP), R2
+ MOVD ·_K+0(SB), R3
+
+ // long enough to prefetch
+ PRFM (R3), PLDL3KEEP
+ // load digest
+ VLD1 (R0), [V8.D2, V9.D2, V10.D2, V11.D2]
+loop:
+ // load digest in V0-V3 keeping original in V8-V11
+ VMOV V8.B16, V0.B16
+ VMOV V9.B16, V1.B16
+ VMOV V10.B16, V2.B16
+ VMOV V11.B16, V3.B16
+
+ // load message data in V12-V19
+ VLD1.P 64(R1), [V12.D2, V13.D2, V14.D2, V15.D2]
+ VLD1.P 64(R1), [V16.D2, V17.D2, V18.D2, V19.D2]
+
+ // convert message into big endian format
+ VREV64 V12.B16, V12.B16
+ VREV64 V13.B16, V13.B16
+ VREV64 V14.B16, V14.B16
+ VREV64 V15.B16, V15.B16
+ VREV64 V16.B16, V16.B16
+ VREV64 V17.B16, V17.B16
+ VREV64 V18.B16, V18.B16
+ VREV64 V19.B16, V19.B16
+
+ MOVD R3, R4
+ // load first 4 round consts in V20-V23
+ VLD1.P 64(R4), [V20.D2, V21.D2, V22.D2, V23.D2]
+
+ SHA512ROUND(V0, V1, V2, V3, V4, V20, V24, V12, V13, V19, V16, V17)
+ SHA512ROUND(V3, V0, V4, V2, V1, V21, V25, V13, V14, V12, V17, V18)
+ SHA512ROUND(V2, V3, V1, V4, V0, V22, V26, V14, V15, V13, V18, V19)
+ SHA512ROUND(V4, V2, V0, V1, V3, V23, V27, V15, V16, V14, V19, V12)
+ SHA512ROUND(V1, V4, V3, V0, V2, V24, V28, V16, V17, V15, V12, V13)
+
+ SHA512ROUND(V0, V1, V2, V3, V4, V25, V29, V17, V18, V16, V13, V14)
+ SHA512ROUND(V3, V0, V4, V2, V1, V26, V30, V18, V19, V17, V14, V15)
+ SHA512ROUND(V2, V3, V1, V4, V0, V27, V31, V19, V12, V18, V15, V16)
+ SHA512ROUND(V4, V2, V0, V1, V3, V28, V24, V12, V13, V19, V16, V17)
+ SHA512ROUND(V1, V4, V3, V0, V2, V29, V25, V13, V14, V12, V17, V18)
+
+ SHA512ROUND(V0, V1, V2, V3, V4, V30, V26, V14, V15, V13, V18, V19)
+ SHA512ROUND(V3, V0, V4, V2, V1, V31, V27, V15, V16, V14, V19, V12)
+ SHA512ROUND(V2, V3, V1, V4, V0, V24, V28, V16, V17, V15, V12, V13)
+ SHA512ROUND(V4, V2, V0, V1, V3, V25, V29, V17, V18, V16, V13, V14)
+ SHA512ROUND(V1, V4, V3, V0, V2, V26, V30, V18, V19, V17, V14, V15)
+
+ SHA512ROUND(V0, V1, V2, V3, V4, V27, V31, V19, V12, V18, V15, V16)
+ SHA512ROUND(V3, V0, V4, V2, V1, V28, V24, V12, V13, V19, V16, V17)
+ SHA512ROUND(V2, V3, V1, V4, V0, V29, V25, V13, V14, V12, V17, V18)
+ SHA512ROUND(V4, V2, V0, V1, V3, V30, V26, V14, V15, V13, V18, V19)
+ SHA512ROUND(V1, V4, V3, V0, V2, V31, V27, V15, V16, V14, V19, V12)
+
+ SHA512ROUND(V0, V1, V2, V3, V4, V24, V28, V16, V17, V15, V12, V13)
+ SHA512ROUND(V3, V0, V4, V2, V1, V25, V29, V17, V18, V16, V13, V14)
+ SHA512ROUND(V2, V3, V1, V4, V0, V26, V30, V18, V19, V17, V14, V15)
+ SHA512ROUND(V4, V2, V0, V1, V3, V27, V31, V19, V12, V18, V15, V16)
+ SHA512ROUND(V1, V4, V3, V0, V2, V28, V24, V12, V13, V19, V16, V17)
+
+ SHA512ROUND(V0, V1, V2, V3, V4, V29, V25, V13, V14, V12, V17, V18)
+ SHA512ROUND(V3, V0, V4, V2, V1, V30, V26, V14, V15, V13, V18, V19)
+ SHA512ROUND(V2, V3, V1, V4, V0, V31, V27, V15, V16, V14, V19, V12)
+ SHA512ROUND(V4, V2, V0, V1, V3, V24, V28, V16, V17, V15, V12, V13)
+ SHA512ROUND(V1, V4, V3, V0, V2, V25, V29, V17, V18, V16, V13, V14)
+
+ SHA512ROUND(V0, V1, V2, V3, V4, V26, V30, V18, V19, V17, V14, V15)
+ SHA512ROUND(V3, V0, V4, V2, V1, V27, V31, V19, V12, V18, V15, V16)
+
+ SHA512ROUND_NO_UPDATE(V2, V3, V1, V4, V0, V28, V24, V12)
+ SHA512ROUND_NO_UPDATE(V4, V2, V0, V1, V3, V29, V25, V13)
+ SHA512ROUND_NO_UPDATE(V1, V4, V3, V0, V2, V30, V26, V14)
+ SHA512ROUND_NO_UPDATE(V0, V1, V2, V3, V4, V31, V27, V15)
+
+ SHA512ROUND_LAST(V3, V0, V4, V2, V1, V24, V16)
+ SHA512ROUND_LAST(V2, V3, V1, V4, V0, V25, V17)
+ SHA512ROUND_LAST(V4, V2, V0, V1, V3, V26, V18)
+ SHA512ROUND_LAST(V1, V4, V3, V0, V2, V27, V19)
+
+ // add result to digest
+ VADD V0.D2, V8.D2, V8.D2
+ VADD V1.D2, V9.D2, V9.D2
+ VADD V2.D2, V10.D2, V10.D2
+ VADD V3.D2, V11.D2, V11.D2
+ SUB $128, R2
+ CBNZ R2, loop
+
+ VST1 [V8.D2, V9.D2, V10.D2, V11.D2], (R0)
+ RET
diff --git a/src/crypto/sha512/sha512block_decl.go b/src/crypto/sha512/sha512block_decl.go
new file mode 100644
index 0000000..52278ae
--- /dev/null
+++ b/src/crypto/sha512/sha512block_decl.go
@@ -0,0 +1,11 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build s390x || ppc64le || ppc64
+
+package sha512
+
+//go:noescape
+
+func block(dig *digest, p []byte)
diff --git a/src/crypto/sha512/sha512block_generic.go b/src/crypto/sha512/sha512block_generic.go
new file mode 100644
index 0000000..02ecc2c
--- /dev/null
+++ b/src/crypto/sha512/sha512block_generic.go
@@ -0,0 +1,11 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !amd64 && !arm64 && !s390x && !ppc64le && !ppc64
+
+package sha512
+
+func block(dig *digest, p []byte) {
+ blockGeneric(dig, p)
+}
diff --git a/src/crypto/sha512/sha512block_ppc64x.s b/src/crypto/sha512/sha512block_ppc64x.s
new file mode 100644
index 0000000..968183d
--- /dev/null
+++ b/src/crypto/sha512/sha512block_ppc64x.s
@@ -0,0 +1,465 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Based on CRYPTOGAMS code with the following comment:
+// # ====================================================================
+// # Written by Andy Polyakov <appro@openssl.org> for the OpenSSL
+// # project. The module is, however, dual licensed under OpenSSL and
+// # CRYPTOGAMS licenses depending on where you obtain it. For further
+// # details see http://www.openssl.org/~appro/cryptogams/.
+// # ====================================================================
+
+//go:build ppc64 || ppc64le
+
+#include "textflag.h"
+
+// SHA512 block routine. See sha512block.go for Go equivalent.
+//
+// The algorithm is detailed in FIPS 180-4:
+//
+// https://csrc.nist.gov/publications/fips/fips180-4/fips-180-4.pdf
+//
+// Wt = Mt; for 0 <= t <= 15
+// Wt = SIGMA1(Wt-2) + SIGMA0(Wt-15) + Wt-16; for 16 <= t <= 79
+//
+// a = H0
+// b = H1
+// c = H2
+// d = H3
+// e = H4
+// f = H5
+// g = H6
+// h = H7
+//
+// for t = 0 to 79 {
+// T1 = h + BIGSIGMA1(e) + Ch(e,f,g) + Kt + Wt
+// T2 = BIGSIGMA0(a) + Maj(a,b,c)
+// h = g
+// g = f
+// f = e
+// e = d + T1
+// d = c
+// c = b
+// b = a
+// a = T1 + T2
+// }
+//
+// H0 = a + H0
+// H1 = b + H1
+// H2 = c + H2
+// H3 = d + H3
+// H4 = e + H4
+// H5 = f + H5
+// H6 = g + H6
+// H7 = h + H7
+
+#define CTX R3
+#define INP R4
+#define END R5
+#define TBL R6
+#define IDX R7
+#define CNT R8
+#define LEN R9
+#define OFFLOAD R11
+#define TEMP R12
+
+#define HEX00 R0
+#define HEX10 R10
+#define HEX20 R25
+#define HEX30 R26
+
+// V0-V7 are A-H
+// V8-V23 are used for the message schedule
+#define KI V24
+#define FUNC V25
+#define S0 V26
+#define S1 V27
+#define s0 V28
+#define s1 V29
+#define LEMASK V31 // Permutation control register for little endian
+
+// VPERM is needed on LE to switch the bytes
+
+#ifdef GOARCH_ppc64le
+#define VPERMLE(va,vb,vc,vt) VPERM va, vb, vc, vt
+#else
+#define VPERMLE(va,vb,vc,vt)
+#endif
+
+// 2 copies of each Kt, to fill both doublewords of a vector register
+DATA ·kcon+0x000(SB)/8, $0x428a2f98d728ae22
+DATA ·kcon+0x008(SB)/8, $0x428a2f98d728ae22
+DATA ·kcon+0x010(SB)/8, $0x7137449123ef65cd
+DATA ·kcon+0x018(SB)/8, $0x7137449123ef65cd
+DATA ·kcon+0x020(SB)/8, $0xb5c0fbcfec4d3b2f
+DATA ·kcon+0x028(SB)/8, $0xb5c0fbcfec4d3b2f
+DATA ·kcon+0x030(SB)/8, $0xe9b5dba58189dbbc
+DATA ·kcon+0x038(SB)/8, $0xe9b5dba58189dbbc
+DATA ·kcon+0x040(SB)/8, $0x3956c25bf348b538
+DATA ·kcon+0x048(SB)/8, $0x3956c25bf348b538
+DATA ·kcon+0x050(SB)/8, $0x59f111f1b605d019
+DATA ·kcon+0x058(SB)/8, $0x59f111f1b605d019
+DATA ·kcon+0x060(SB)/8, $0x923f82a4af194f9b
+DATA ·kcon+0x068(SB)/8, $0x923f82a4af194f9b
+DATA ·kcon+0x070(SB)/8, $0xab1c5ed5da6d8118
+DATA ·kcon+0x078(SB)/8, $0xab1c5ed5da6d8118
+DATA ·kcon+0x080(SB)/8, $0xd807aa98a3030242
+DATA ·kcon+0x088(SB)/8, $0xd807aa98a3030242
+DATA ·kcon+0x090(SB)/8, $0x12835b0145706fbe
+DATA ·kcon+0x098(SB)/8, $0x12835b0145706fbe
+DATA ·kcon+0x0A0(SB)/8, $0x243185be4ee4b28c
+DATA ·kcon+0x0A8(SB)/8, $0x243185be4ee4b28c
+DATA ·kcon+0x0B0(SB)/8, $0x550c7dc3d5ffb4e2
+DATA ·kcon+0x0B8(SB)/8, $0x550c7dc3d5ffb4e2
+DATA ·kcon+0x0C0(SB)/8, $0x72be5d74f27b896f
+DATA ·kcon+0x0C8(SB)/8, $0x72be5d74f27b896f
+DATA ·kcon+0x0D0(SB)/8, $0x80deb1fe3b1696b1
+DATA ·kcon+0x0D8(SB)/8, $0x80deb1fe3b1696b1
+DATA ·kcon+0x0E0(SB)/8, $0x9bdc06a725c71235
+DATA ·kcon+0x0E8(SB)/8, $0x9bdc06a725c71235
+DATA ·kcon+0x0F0(SB)/8, $0xc19bf174cf692694
+DATA ·kcon+0x0F8(SB)/8, $0xc19bf174cf692694
+DATA ·kcon+0x100(SB)/8, $0xe49b69c19ef14ad2
+DATA ·kcon+0x108(SB)/8, $0xe49b69c19ef14ad2
+DATA ·kcon+0x110(SB)/8, $0xefbe4786384f25e3
+DATA ·kcon+0x118(SB)/8, $0xefbe4786384f25e3
+DATA ·kcon+0x120(SB)/8, $0x0fc19dc68b8cd5b5
+DATA ·kcon+0x128(SB)/8, $0x0fc19dc68b8cd5b5
+DATA ·kcon+0x130(SB)/8, $0x240ca1cc77ac9c65
+DATA ·kcon+0x138(SB)/8, $0x240ca1cc77ac9c65
+DATA ·kcon+0x140(SB)/8, $0x2de92c6f592b0275
+DATA ·kcon+0x148(SB)/8, $0x2de92c6f592b0275
+DATA ·kcon+0x150(SB)/8, $0x4a7484aa6ea6e483
+DATA ·kcon+0x158(SB)/8, $0x4a7484aa6ea6e483
+DATA ·kcon+0x160(SB)/8, $0x5cb0a9dcbd41fbd4
+DATA ·kcon+0x168(SB)/8, $0x5cb0a9dcbd41fbd4
+DATA ·kcon+0x170(SB)/8, $0x76f988da831153b5
+DATA ·kcon+0x178(SB)/8, $0x76f988da831153b5
+DATA ·kcon+0x180(SB)/8, $0x983e5152ee66dfab
+DATA ·kcon+0x188(SB)/8, $0x983e5152ee66dfab
+DATA ·kcon+0x190(SB)/8, $0xa831c66d2db43210
+DATA ·kcon+0x198(SB)/8, $0xa831c66d2db43210
+DATA ·kcon+0x1A0(SB)/8, $0xb00327c898fb213f
+DATA ·kcon+0x1A8(SB)/8, $0xb00327c898fb213f
+DATA ·kcon+0x1B0(SB)/8, $0xbf597fc7beef0ee4
+DATA ·kcon+0x1B8(SB)/8, $0xbf597fc7beef0ee4
+DATA ·kcon+0x1C0(SB)/8, $0xc6e00bf33da88fc2
+DATA ·kcon+0x1C8(SB)/8, $0xc6e00bf33da88fc2
+DATA ·kcon+0x1D0(SB)/8, $0xd5a79147930aa725
+DATA ·kcon+0x1D8(SB)/8, $0xd5a79147930aa725
+DATA ·kcon+0x1E0(SB)/8, $0x06ca6351e003826f
+DATA ·kcon+0x1E8(SB)/8, $0x06ca6351e003826f
+DATA ·kcon+0x1F0(SB)/8, $0x142929670a0e6e70
+DATA ·kcon+0x1F8(SB)/8, $0x142929670a0e6e70
+DATA ·kcon+0x200(SB)/8, $0x27b70a8546d22ffc
+DATA ·kcon+0x208(SB)/8, $0x27b70a8546d22ffc
+DATA ·kcon+0x210(SB)/8, $0x2e1b21385c26c926
+DATA ·kcon+0x218(SB)/8, $0x2e1b21385c26c926
+DATA ·kcon+0x220(SB)/8, $0x4d2c6dfc5ac42aed
+DATA ·kcon+0x228(SB)/8, $0x4d2c6dfc5ac42aed
+DATA ·kcon+0x230(SB)/8, $0x53380d139d95b3df
+DATA ·kcon+0x238(SB)/8, $0x53380d139d95b3df
+DATA ·kcon+0x240(SB)/8, $0x650a73548baf63de
+DATA ·kcon+0x248(SB)/8, $0x650a73548baf63de
+DATA ·kcon+0x250(SB)/8, $0x766a0abb3c77b2a8
+DATA ·kcon+0x258(SB)/8, $0x766a0abb3c77b2a8
+DATA ·kcon+0x260(SB)/8, $0x81c2c92e47edaee6
+DATA ·kcon+0x268(SB)/8, $0x81c2c92e47edaee6
+DATA ·kcon+0x270(SB)/8, $0x92722c851482353b
+DATA ·kcon+0x278(SB)/8, $0x92722c851482353b
+DATA ·kcon+0x280(SB)/8, $0xa2bfe8a14cf10364
+DATA ·kcon+0x288(SB)/8, $0xa2bfe8a14cf10364
+DATA ·kcon+0x290(SB)/8, $0xa81a664bbc423001
+DATA ·kcon+0x298(SB)/8, $0xa81a664bbc423001
+DATA ·kcon+0x2A0(SB)/8, $0xc24b8b70d0f89791
+DATA ·kcon+0x2A8(SB)/8, $0xc24b8b70d0f89791
+DATA ·kcon+0x2B0(SB)/8, $0xc76c51a30654be30
+DATA ·kcon+0x2B8(SB)/8, $0xc76c51a30654be30
+DATA ·kcon+0x2C0(SB)/8, $0xd192e819d6ef5218
+DATA ·kcon+0x2C8(SB)/8, $0xd192e819d6ef5218
+DATA ·kcon+0x2D0(SB)/8, $0xd69906245565a910
+DATA ·kcon+0x2D8(SB)/8, $0xd69906245565a910
+DATA ·kcon+0x2E0(SB)/8, $0xf40e35855771202a
+DATA ·kcon+0x2E8(SB)/8, $0xf40e35855771202a
+DATA ·kcon+0x2F0(SB)/8, $0x106aa07032bbd1b8
+DATA ·kcon+0x2F8(SB)/8, $0x106aa07032bbd1b8
+DATA ·kcon+0x300(SB)/8, $0x19a4c116b8d2d0c8
+DATA ·kcon+0x308(SB)/8, $0x19a4c116b8d2d0c8
+DATA ·kcon+0x310(SB)/8, $0x1e376c085141ab53
+DATA ·kcon+0x318(SB)/8, $0x1e376c085141ab53
+DATA ·kcon+0x320(SB)/8, $0x2748774cdf8eeb99
+DATA ·kcon+0x328(SB)/8, $0x2748774cdf8eeb99
+DATA ·kcon+0x330(SB)/8, $0x34b0bcb5e19b48a8
+DATA ·kcon+0x338(SB)/8, $0x34b0bcb5e19b48a8
+DATA ·kcon+0x340(SB)/8, $0x391c0cb3c5c95a63
+DATA ·kcon+0x348(SB)/8, $0x391c0cb3c5c95a63
+DATA ·kcon+0x350(SB)/8, $0x4ed8aa4ae3418acb
+DATA ·kcon+0x358(SB)/8, $0x4ed8aa4ae3418acb
+DATA ·kcon+0x360(SB)/8, $0x5b9cca4f7763e373
+DATA ·kcon+0x368(SB)/8, $0x5b9cca4f7763e373
+DATA ·kcon+0x370(SB)/8, $0x682e6ff3d6b2b8a3
+DATA ·kcon+0x378(SB)/8, $0x682e6ff3d6b2b8a3
+DATA ·kcon+0x380(SB)/8, $0x748f82ee5defb2fc
+DATA ·kcon+0x388(SB)/8, $0x748f82ee5defb2fc
+DATA ·kcon+0x390(SB)/8, $0x78a5636f43172f60
+DATA ·kcon+0x398(SB)/8, $0x78a5636f43172f60
+DATA ·kcon+0x3A0(SB)/8, $0x84c87814a1f0ab72
+DATA ·kcon+0x3A8(SB)/8, $0x84c87814a1f0ab72
+DATA ·kcon+0x3B0(SB)/8, $0x8cc702081a6439ec
+DATA ·kcon+0x3B8(SB)/8, $0x8cc702081a6439ec
+DATA ·kcon+0x3C0(SB)/8, $0x90befffa23631e28
+DATA ·kcon+0x3C8(SB)/8, $0x90befffa23631e28
+DATA ·kcon+0x3D0(SB)/8, $0xa4506cebde82bde9
+DATA ·kcon+0x3D8(SB)/8, $0xa4506cebde82bde9
+DATA ·kcon+0x3E0(SB)/8, $0xbef9a3f7b2c67915
+DATA ·kcon+0x3E8(SB)/8, $0xbef9a3f7b2c67915
+DATA ·kcon+0x3F0(SB)/8, $0xc67178f2e372532b
+DATA ·kcon+0x3F8(SB)/8, $0xc67178f2e372532b
+DATA ·kcon+0x400(SB)/8, $0xca273eceea26619c
+DATA ·kcon+0x408(SB)/8, $0xca273eceea26619c
+DATA ·kcon+0x410(SB)/8, $0xd186b8c721c0c207
+DATA ·kcon+0x418(SB)/8, $0xd186b8c721c0c207
+DATA ·kcon+0x420(SB)/8, $0xeada7dd6cde0eb1e
+DATA ·kcon+0x428(SB)/8, $0xeada7dd6cde0eb1e
+DATA ·kcon+0x430(SB)/8, $0xf57d4f7fee6ed178
+DATA ·kcon+0x438(SB)/8, $0xf57d4f7fee6ed178
+DATA ·kcon+0x440(SB)/8, $0x06f067aa72176fba
+DATA ·kcon+0x448(SB)/8, $0x06f067aa72176fba
+DATA ·kcon+0x450(SB)/8, $0x0a637dc5a2c898a6
+DATA ·kcon+0x458(SB)/8, $0x0a637dc5a2c898a6
+DATA ·kcon+0x460(SB)/8, $0x113f9804bef90dae
+DATA ·kcon+0x468(SB)/8, $0x113f9804bef90dae
+DATA ·kcon+0x470(SB)/8, $0x1b710b35131c471b
+DATA ·kcon+0x478(SB)/8, $0x1b710b35131c471b
+DATA ·kcon+0x480(SB)/8, $0x28db77f523047d84
+DATA ·kcon+0x488(SB)/8, $0x28db77f523047d84
+DATA ·kcon+0x490(SB)/8, $0x32caab7b40c72493
+DATA ·kcon+0x498(SB)/8, $0x32caab7b40c72493
+DATA ·kcon+0x4A0(SB)/8, $0x3c9ebe0a15c9bebc
+DATA ·kcon+0x4A8(SB)/8, $0x3c9ebe0a15c9bebc
+DATA ·kcon+0x4B0(SB)/8, $0x431d67c49c100d4c
+DATA ·kcon+0x4B8(SB)/8, $0x431d67c49c100d4c
+DATA ·kcon+0x4C0(SB)/8, $0x4cc5d4becb3e42b6
+DATA ·kcon+0x4C8(SB)/8, $0x4cc5d4becb3e42b6
+DATA ·kcon+0x4D0(SB)/8, $0x597f299cfc657e2a
+DATA ·kcon+0x4D8(SB)/8, $0x597f299cfc657e2a
+DATA ·kcon+0x4E0(SB)/8, $0x5fcb6fab3ad6faec
+DATA ·kcon+0x4E8(SB)/8, $0x5fcb6fab3ad6faec
+DATA ·kcon+0x4F0(SB)/8, $0x6c44198c4a475817
+DATA ·kcon+0x4F8(SB)/8, $0x6c44198c4a475817
+DATA ·kcon+0x500(SB)/8, $0x0000000000000000
+DATA ·kcon+0x508(SB)/8, $0x0000000000000000
+DATA ·kcon+0x510(SB)/8, $0x1011121314151617
+DATA ·kcon+0x518(SB)/8, $0x0001020304050607
+GLOBL ·kcon(SB), RODATA, $1312
+
+#define SHA512ROUND0(a, b, c, d, e, f, g, h, xi) \
+ VSEL g, f, e, FUNC; \
+ VSHASIGMAD $15, e, $1, S1; \
+ VADDUDM xi, h, h; \
+ VSHASIGMAD $0, a, $1, S0; \
+ VADDUDM FUNC, h, h; \
+ VXOR b, a, FUNC; \
+ VADDUDM S1, h, h; \
+ VSEL b, c, FUNC, FUNC; \
+ VADDUDM KI, g, g; \
+ VADDUDM h, d, d; \
+ VADDUDM FUNC, S0, S0; \
+ LVX (TBL)(IDX), KI; \
+ ADD $16, IDX; \
+ VADDUDM S0, h, h
+
+#define SHA512ROUND1(a, b, c, d, e, f, g, h, xi, xj, xj_1, xj_9, xj_14) \
+ VSHASIGMAD $0, xj_1, $0, s0; \
+ VSEL g, f, e, FUNC; \
+ VSHASIGMAD $15, e, $1, S1; \
+ VADDUDM xi, h, h; \
+ VSHASIGMAD $0, a, $1, S0; \
+ VSHASIGMAD $15, xj_14, $0, s1; \
+ VADDUDM FUNC, h, h; \
+ VXOR b, a, FUNC; \
+ VADDUDM xj_9, xj, xj; \
+ VADDUDM S1, h, h; \
+ VSEL b, c, FUNC, FUNC; \
+ VADDUDM KI, g, g; \
+ VADDUDM h, d, d; \
+ VADDUDM FUNC, S0, S0; \
+ VADDUDM s0, xj, xj; \
+ LVX (TBL)(IDX), KI; \
+ ADD $16, IDX; \
+ VADDUDM S0, h, h; \
+ VADDUDM s1, xj, xj
+
+// func block(dig *digest, p []byte)
+TEXT ·block(SB),0,$0-32
+ MOVD dig+0(FP), CTX
+ MOVD p_base+8(FP), INP
+ MOVD p_len+16(FP), LEN
+
+ SRD $6, LEN
+ SLD $6, LEN
+
+ ADD INP, LEN, END
+
+ CMP INP, END
+ BEQ end
+
+ MOVD $·kcon(SB), TBL
+ MOVD R1, OFFLOAD
+
+ MOVD R0, CNT
+ MOVWZ $0x10, HEX10
+ MOVWZ $0x20, HEX20
+ MOVWZ $0x30, HEX30
+
+// Generate the mask used with VPERM for LE
+
+#ifdef GOARCH_ppc64le
+ MOVWZ $8, IDX
+ LVSL (IDX)(R0), LEMASK
+ VSPLTISB $0x0F, KI
+ VXOR KI, LEMASK, LEMASK
+#endif
+
+ LXVD2X (CTX)(HEX00), VS32 // v0 = vs32
+ LXVD2X (CTX)(HEX10), VS34 // v2 = vs34
+ LXVD2X (CTX)(HEX20), VS36 // v4 = vs36
+ // unpack the input values into vector registers
+ VSLDOI $8, V0, V0, V1
+ LXVD2X (CTX)(HEX30), VS38 // v6 = vs38
+ VSLDOI $8, V2, V2, V3
+ VSLDOI $8, V4, V4, V5
+ VSLDOI $8, V6, V6, V7
+
+loop:
+ LVX (TBL)(HEX00), KI
+ MOVWZ $16, IDX
+
+ LXVD2X (INP)(R0), VS40 // load v8 (=vs40) in advance
+ ADD $16, INP
+
+ // Copy V0-V7 to VS24-VS31
+
+ XXLOR V0, V0, VS24
+ XXLOR V1, V1, VS25
+ XXLOR V2, V2, VS26
+ XXLOR V3, V3, VS27
+ XXLOR V4, V4, VS28
+ XXLOR V5, V5, VS29
+ XXLOR V6, V6, VS30
+ XXLOR V7, V7, VS31
+
+ VADDUDM KI, V7, V7 // h+K[i]
+ LVX (TBL)(IDX), KI
+ ADD $16, IDX
+
+ VPERMLE(V8,V8,LEMASK,V8)
+ SHA512ROUND0(V0, V1, V2, V3, V4, V5, V6, V7, V8)
+ LXVD2X (INP)(R0), VS42 // load v10 (=vs42) in advance
+ ADD $16, INP, INP
+ VSLDOI $8, V8, V8, V9
+ SHA512ROUND0(V7, V0, V1, V2, V3, V4, V5, V6, V9)
+ VPERMLE(V10,V10,LEMASK,V10)
+ SHA512ROUND0(V6, V7, V0, V1, V2, V3, V4, V5, V10)
+ LXVD2X (INP)(R0), VS44 // load v12 (=vs44) in advance
+ ADD $16, INP, INP
+ VSLDOI $8, V10, V10, V11
+ SHA512ROUND0(V5, V6, V7, V0, V1, V2, V3, V4, V11)
+ VPERMLE(V12,V12,LEMASK,V12)
+ SHA512ROUND0(V4, V5, V6, V7, V0, V1, V2, V3, V12)
+ LXVD2X (INP)(R0), VS46 // load v14 (=vs46) in advance
+ ADD $16, INP, INP
+ VSLDOI $8, V12, V12, V13
+ SHA512ROUND0(V3, V4, V5, V6, V7, V0, V1, V2, V13)
+ VPERMLE(V14,V14,LEMASK,V14)
+ SHA512ROUND0(V2, V3, V4, V5, V6, V7, V0, V1, V14)
+ LXVD2X (INP)(R0), VS48 // load v16 (=vs48) in advance
+ ADD $16, INP, INP
+ VSLDOI $8, V14, V14, V15
+ SHA512ROUND0(V1, V2, V3, V4, V5, V6, V7, V0, V15)
+ VPERMLE(V16,V16,LEMASK,V16)
+ SHA512ROUND0(V0, V1, V2, V3, V4, V5, V6, V7, V16)
+ LXVD2X (INP)(R0), VS50 // load v18 (=vs50) in advance
+ ADD $16, INP, INP
+ VSLDOI $8, V16, V16, V17
+ SHA512ROUND0(V7, V0, V1, V2, V3, V4, V5, V6, V17)
+ VPERMLE(V18,V18,LEMASK,V18)
+ SHA512ROUND0(V6, V7, V0, V1, V2, V3, V4, V5, V18)
+ LXVD2X (INP)(R0), VS52 // load v20 (=vs52) in advance
+ ADD $16, INP, INP
+ VSLDOI $8, V18, V18, V19
+ SHA512ROUND0(V5, V6, V7, V0, V1, V2, V3, V4, V19)
+ VPERMLE(V20,V20,LEMASK,V20)
+ SHA512ROUND0(V4, V5, V6, V7, V0, V1, V2, V3, V20)
+ LXVD2X (INP)(R0), VS54 // load v22 (=vs54) in advance
+ ADD $16, INP, INP
+ VSLDOI $8, V20, V20, V21
+ SHA512ROUND0(V3, V4, V5, V6, V7, V0, V1, V2, V21)
+ VPERMLE(V22,V22,LEMASK,V22)
+ SHA512ROUND0(V2, V3, V4, V5, V6, V7, V0, V1, V22)
+ VSLDOI $8, V22, V22, V23
+ SHA512ROUND1(V1, V2, V3, V4, V5, V6, V7, V0, V23, V8, V9, V17, V22)
+
+ MOVWZ $4, TEMP
+ MOVWZ TEMP, CTR
+
+L16_xx:
+ SHA512ROUND1(V0, V1, V2, V3, V4, V5, V6, V7, V8, V9, V10, V18, V23)
+ SHA512ROUND1(V7, V0, V1, V2, V3, V4, V5, V6, V9, V10, V11, V19, V8)
+ SHA512ROUND1(V6, V7, V0, V1, V2, V3, V4, V5, V10, V11, V12, V20, V9)
+ SHA512ROUND1(V5, V6, V7, V0, V1, V2, V3, V4, V11, V12, V13, V21, V10)
+ SHA512ROUND1(V4, V5, V6, V7, V0, V1, V2, V3, V12, V13, V14, V22, V11)
+ SHA512ROUND1(V3, V4, V5, V6, V7, V0, V1, V2, V13, V14, V15, V23, V12)
+ SHA512ROUND1(V2, V3, V4, V5, V6, V7, V0, V1, V14, V15, V16, V8, V13)
+ SHA512ROUND1(V1, V2, V3, V4, V5, V6, V7, V0, V15, V16, V17, V9, V14)
+ SHA512ROUND1(V0, V1, V2, V3, V4, V5, V6, V7, V16, V17, V18, V10, V15)
+ SHA512ROUND1(V7, V0, V1, V2, V3, V4, V5, V6, V17, V18, V19, V11, V16)
+ SHA512ROUND1(V6, V7, V0, V1, V2, V3, V4, V5, V18, V19, V20, V12, V17)
+ SHA512ROUND1(V5, V6, V7, V0, V1, V2, V3, V4, V19, V20, V21, V13, V18)
+ SHA512ROUND1(V4, V5, V6, V7, V0, V1, V2, V3, V20, V21, V22, V14, V19)
+ SHA512ROUND1(V3, V4, V5, V6, V7, V0, V1, V2, V21, V22, V23, V15, V20)
+ SHA512ROUND1(V2, V3, V4, V5, V6, V7, V0, V1, V22, V23, V8, V16, V21)
+ SHA512ROUND1(V1, V2, V3, V4, V5, V6, V7, V0, V23, V8, V9, V17, V22)
+
+ BC 0x10, 0, L16_xx // bdnz
+
+ XXLOR VS24, VS24, V10
+ XXLOR VS25, VS25, V11
+ XXLOR VS26, VS26, V12
+ XXLOR VS27, VS27, V13
+ XXLOR VS28, VS28, V14
+ XXLOR VS29, VS29, V15
+ XXLOR VS30, VS30, V16
+ XXLOR VS31, VS31, V17
+ VADDUDM V10, V0, V0
+ VADDUDM V11, V1, V1
+ VADDUDM V12, V2, V2
+ VADDUDM V13, V3, V3
+ VADDUDM V14, V4, V4
+ VADDUDM V15, V5, V5
+ VADDUDM V16, V6, V6
+ VADDUDM V17, V7, V7
+
+ CMPU INP, END
+ BLT loop
+
+#ifdef GOARCH_ppc64le
+ VPERM V0, V1, KI, V0
+ VPERM V2, V3, KI, V2
+ VPERM V4, V5, KI, V4
+ VPERM V6, V7, KI, V6
+#else
+ VPERM V1, V0, KI, V0
+ VPERM V3, V2, KI, V2
+ VPERM V5, V4, KI, V4
+ VPERM V7, V6, KI, V6
+#endif
+ STXVD2X VS32, (CTX+HEX00) // v0 = vs32
+ STXVD2X VS34, (CTX+HEX10) // v2 = vs34
+ STXVD2X VS36, (CTX+HEX20) // v4 = vs36
+ STXVD2X VS38, (CTX+HEX30) // v6 = vs38
+
+end:
+ RET
+
diff --git a/src/crypto/sha512/sha512block_s390x.go b/src/crypto/sha512/sha512block_s390x.go
new file mode 100644
index 0000000..7df29fd
--- /dev/null
+++ b/src/crypto/sha512/sha512block_s390x.go
@@ -0,0 +1,9 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package sha512
+
+import "internal/cpu"
+
+var useAsm = cpu.S390X.HasSHA512
diff --git a/src/crypto/sha512/sha512block_s390x.s b/src/crypto/sha512/sha512block_s390x.s
new file mode 100644
index 0000000..f221bd1
--- /dev/null
+++ b/src/crypto/sha512/sha512block_s390x.s
@@ -0,0 +1,20 @@
+// Copyright 2016 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+#include "textflag.h"
+
+// func block(dig *digest, p []byte)
+TEXT ·block(SB), NOSPLIT|NOFRAME, $0-32
+ MOVBZ ·useAsm(SB), R4
+ LMG dig+0(FP), R1, R3 // R2 = &p[0], R3 = len(p)
+ MOVBZ $3, R0 // SHA-512 function code
+ CMPBEQ R4, $0, generic
+
+loop:
+ WORD $0xB93E0002 // KIMD R2
+ BVS loop // continue if interrupted
+ RET
+
+generic:
+ BR ·blockGeneric(SB)
diff --git a/src/crypto/subtle/constant_time.go b/src/crypto/subtle/constant_time.go
new file mode 100644
index 0000000..4e0527f
--- /dev/null
+++ b/src/crypto/subtle/constant_time.go
@@ -0,0 +1,62 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package subtle implements functions that are often useful in cryptographic
+// code but require careful thought to use correctly.
+package subtle
+
+// ConstantTimeCompare returns 1 if the two slices, x and y, have equal contents
+// and 0 otherwise. The time taken is a function of the length of the slices and
+// is independent of the contents. If the lengths of x and y do not match it
+// returns 0 immediately.
+func ConstantTimeCompare(x, y []byte) int {
+ if len(x) != len(y) {
+ return 0
+ }
+
+ var v byte
+
+ for i := 0; i < len(x); i++ {
+ v |= x[i] ^ y[i]
+ }
+
+ return ConstantTimeByteEq(v, 0)
+}
+
+// ConstantTimeSelect returns x if v == 1 and y if v == 0.
+// Its behavior is undefined if v takes any other value.
+func ConstantTimeSelect(v, x, y int) int { return ^(v-1)&x | (v-1)&y }
+
+// ConstantTimeByteEq returns 1 if x == y and 0 otherwise.
+func ConstantTimeByteEq(x, y uint8) int {
+ return int((uint32(x^y) - 1) >> 31)
+}
+
+// ConstantTimeEq returns 1 if x == y and 0 otherwise.
+func ConstantTimeEq(x, y int32) int {
+ return int((uint64(uint32(x^y)) - 1) >> 63)
+}
+
+// ConstantTimeCopy copies the contents of y into x (a slice of equal length)
+// if v == 1. If v == 0, x is left unchanged. Its behavior is undefined if v
+// takes any other value.
+func ConstantTimeCopy(v int, x, y []byte) {
+ if len(x) != len(y) {
+ panic("subtle: slices have different lengths")
+ }
+
+ xmask := byte(v - 1)
+ ymask := byte(^(v - 1))
+ for i := 0; i < len(x); i++ {
+ x[i] = x[i]&xmask | y[i]&ymask
+ }
+}
+
+// ConstantTimeLessOrEq returns 1 if x <= y and 0 otherwise.
+// Its behavior is undefined if x or y are negative or > 2**31 - 1.
+func ConstantTimeLessOrEq(x, y int) int {
+ x32 := int32(x)
+ y32 := int32(y)
+ return int(((x32 - y32 - 1) >> 31) & 1)
+}
diff --git a/src/crypto/subtle/constant_time_test.go b/src/crypto/subtle/constant_time_test.go
new file mode 100644
index 0000000..033301a
--- /dev/null
+++ b/src/crypto/subtle/constant_time_test.go
@@ -0,0 +1,159 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package subtle
+
+import (
+ "testing"
+ "testing/quick"
+)
+
+type TestConstantTimeCompareStruct struct {
+ a, b []byte
+ out int
+}
+
+var testConstantTimeCompareData = []TestConstantTimeCompareStruct{
+ {[]byte{}, []byte{}, 1},
+ {[]byte{0x11}, []byte{0x11}, 1},
+ {[]byte{0x12}, []byte{0x11}, 0},
+ {[]byte{0x11}, []byte{0x11, 0x12}, 0},
+ {[]byte{0x11, 0x12}, []byte{0x11}, 0},
+}
+
+func TestConstantTimeCompare(t *testing.T) {
+ for i, test := range testConstantTimeCompareData {
+ if r := ConstantTimeCompare(test.a, test.b); r != test.out {
+ t.Errorf("#%d bad result (got %x, want %x)", i, r, test.out)
+ }
+ }
+}
+
+type TestConstantTimeByteEqStruct struct {
+ a, b uint8
+ out int
+}
+
+var testConstandTimeByteEqData = []TestConstantTimeByteEqStruct{
+ {0, 0, 1},
+ {0, 1, 0},
+ {1, 0, 0},
+ {0xff, 0xff, 1},
+ {0xff, 0xfe, 0},
+}
+
+func byteEq(a, b uint8) int {
+ if a == b {
+ return 1
+ }
+ return 0
+}
+
+func TestConstantTimeByteEq(t *testing.T) {
+ for i, test := range testConstandTimeByteEqData {
+ if r := ConstantTimeByteEq(test.a, test.b); r != test.out {
+ t.Errorf("#%d bad result (got %x, want %x)", i, r, test.out)
+ }
+ }
+ err := quick.CheckEqual(ConstantTimeByteEq, byteEq, nil)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func eq(a, b int32) int {
+ if a == b {
+ return 1
+ }
+ return 0
+}
+
+func TestConstantTimeEq(t *testing.T) {
+ err := quick.CheckEqual(ConstantTimeEq, eq, nil)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+func makeCopy(v int, x, y []byte) []byte {
+ if len(x) > len(y) {
+ x = x[0:len(y)]
+ } else {
+ y = y[0:len(x)]
+ }
+ if v == 1 {
+ copy(x, y)
+ }
+ return x
+}
+
+func constantTimeCopyWrapper(v int, x, y []byte) []byte {
+ if len(x) > len(y) {
+ x = x[0:len(y)]
+ } else {
+ y = y[0:len(x)]
+ }
+ v &= 1
+ ConstantTimeCopy(v, x, y)
+ return x
+}
+
+func TestConstantTimeCopy(t *testing.T) {
+ err := quick.CheckEqual(constantTimeCopyWrapper, makeCopy, nil)
+ if err != nil {
+ t.Error(err)
+ }
+}
+
+var lessOrEqTests = []struct {
+ x, y, result int
+}{
+ {0, 0, 1},
+ {1, 0, 0},
+ {0, 1, 1},
+ {10, 20, 1},
+ {20, 10, 0},
+ {10, 10, 1},
+}
+
+func TestConstantTimeLessOrEq(t *testing.T) {
+ for i, test := range lessOrEqTests {
+ result := ConstantTimeLessOrEq(test.x, test.y)
+ if result != test.result {
+ t.Errorf("#%d: %d <= %d gave %d, expected %d", i, test.x, test.y, result, test.result)
+ }
+ }
+}
+
+var benchmarkGlobal uint8
+
+func BenchmarkConstantTimeByteEq(b *testing.B) {
+ var x, y uint8
+
+ for i := 0; i < b.N; i++ {
+ x, y = uint8(ConstantTimeByteEq(x, y)), x
+ }
+
+ benchmarkGlobal = x
+}
+
+func BenchmarkConstantTimeEq(b *testing.B) {
+ var x, y int
+
+ for i := 0; i < b.N; i++ {
+ x, y = ConstantTimeEq(int32(x), int32(y)), x
+ }
+
+ benchmarkGlobal = uint8(x)
+}
+
+func BenchmarkConstantTimeLessOrEq(b *testing.B) {
+ var x, y int
+
+ for i := 0; i < b.N; i++ {
+ x, y = ConstantTimeLessOrEq(x, y), x
+ }
+
+ benchmarkGlobal = uint8(x)
+}
diff --git a/src/crypto/subtle/xor.go b/src/crypto/subtle/xor.go
new file mode 100644
index 0000000..a8805ac
--- /dev/null
+++ b/src/crypto/subtle/xor.go
@@ -0,0 +1,24 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package subtle
+
+// XORBytes sets dst[i] = x[i] ^ y[i] for all i < n = min(len(x), len(y)),
+// returning n, the number of bytes written to dst.
+// If dst does not have length at least n,
+// XORBytes panics without writing anything to dst.
+func XORBytes(dst, x, y []byte) int {
+ n := len(x)
+ if len(y) < n {
+ n = len(y)
+ }
+ if n == 0 {
+ return 0
+ }
+ if n > len(dst) {
+ panic("subtle.XORBytes: dst too short")
+ }
+ xorBytes(&dst[0], &x[0], &y[0], n) // arch-specific
+ return n
+}
diff --git a/src/crypto/subtle/xor_amd64.go b/src/crypto/subtle/xor_amd64.go
new file mode 100644
index 0000000..3bb2f08
--- /dev/null
+++ b/src/crypto/subtle/xor_amd64.go
@@ -0,0 +1,10 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !purego
+
+package subtle
+
+//go:noescape
+func xorBytes(dst, a, b *byte, n int)
diff --git a/src/crypto/subtle/xor_amd64.s b/src/crypto/subtle/xor_amd64.s
new file mode 100644
index 0000000..8b04b58
--- /dev/null
+++ b/src/crypto/subtle/xor_amd64.s
@@ -0,0 +1,56 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !purego
+
+#include "textflag.h"
+
+// func xorBytes(dst, a, b *byte, n int)
+TEXT ·xorBytes(SB), NOSPLIT, $0
+ MOVQ dst+0(FP), BX
+ MOVQ a+8(FP), SI
+ MOVQ b+16(FP), CX
+ MOVQ n+24(FP), DX
+ TESTQ $15, DX // AND 15 & len, if not zero jump to not_aligned.
+ JNZ not_aligned
+
+aligned:
+ MOVQ $0, AX // position in slices
+
+loop16b:
+ MOVOU (SI)(AX*1), X0 // XOR 16byte forwards.
+ MOVOU (CX)(AX*1), X1
+ PXOR X1, X0
+ MOVOU X0, (BX)(AX*1)
+ ADDQ $16, AX
+ CMPQ DX, AX
+ JNE loop16b
+ RET
+
+loop_1b:
+ SUBQ $1, DX // XOR 1byte backwards.
+ MOVB (SI)(DX*1), DI
+ MOVB (CX)(DX*1), AX
+ XORB AX, DI
+ MOVB DI, (BX)(DX*1)
+ TESTQ $7, DX // AND 7 & len, if not zero jump to loop_1b.
+ JNZ loop_1b
+ CMPQ DX, $0 // if len is 0, ret.
+ JE ret
+ TESTQ $15, DX // AND 15 & len, if zero jump to aligned.
+ JZ aligned
+
+not_aligned:
+ TESTQ $7, DX // AND $7 & len, if not zero jump to loop_1b.
+ JNE loop_1b
+ SUBQ $8, DX // XOR 8bytes backwards.
+ MOVQ (SI)(DX*1), DI
+ MOVQ (CX)(DX*1), AX
+ XORQ AX, DI
+ MOVQ DI, (BX)(DX*1)
+ CMPQ DX, $16 // if len is greater or equal 16 here, it must be aligned.
+ JGE aligned
+
+ret:
+ RET
diff --git a/src/crypto/subtle/xor_arm64.go b/src/crypto/subtle/xor_arm64.go
new file mode 100644
index 0000000..65bab4c
--- /dev/null
+++ b/src/crypto/subtle/xor_arm64.go
@@ -0,0 +1,10 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !purego
+
+package subtle
+
+//go:noescape
+func xorBytes(dst, a, b *byte, n int)
diff --git a/src/crypto/subtle/xor_arm64.s b/src/crypto/subtle/xor_arm64.s
new file mode 100644
index 0000000..7632164
--- /dev/null
+++ b/src/crypto/subtle/xor_arm64.s
@@ -0,0 +1,69 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !purego
+
+#include "textflag.h"
+
+// func xorBytes(dst, a, b *byte, n int)
+TEXT ·xorBytes(SB), NOSPLIT|NOFRAME, $0
+ MOVD dst+0(FP), R0
+ MOVD a+8(FP), R1
+ MOVD b+16(FP), R2
+ MOVD n+24(FP), R3
+ CMP $64, R3
+ BLT tail
+loop_64:
+ VLD1.P 64(R1), [V0.B16, V1.B16, V2.B16, V3.B16]
+ VLD1.P 64(R2), [V4.B16, V5.B16, V6.B16, V7.B16]
+ VEOR V0.B16, V4.B16, V4.B16
+ VEOR V1.B16, V5.B16, V5.B16
+ VEOR V2.B16, V6.B16, V6.B16
+ VEOR V3.B16, V7.B16, V7.B16
+ VST1.P [V4.B16, V5.B16, V6.B16, V7.B16], 64(R0)
+ SUBS $64, R3
+ CMP $64, R3
+ BGE loop_64
+tail:
+ // quick end
+ CBZ R3, end
+ TBZ $5, R3, less_than32
+ VLD1.P 32(R1), [V0.B16, V1.B16]
+ VLD1.P 32(R2), [V2.B16, V3.B16]
+ VEOR V0.B16, V2.B16, V2.B16
+ VEOR V1.B16, V3.B16, V3.B16
+ VST1.P [V2.B16, V3.B16], 32(R0)
+less_than32:
+ TBZ $4, R3, less_than16
+ LDP.P 16(R1), (R11, R12)
+ LDP.P 16(R2), (R13, R14)
+ EOR R11, R13, R13
+ EOR R12, R14, R14
+ STP.P (R13, R14), 16(R0)
+less_than16:
+ TBZ $3, R3, less_than8
+ MOVD.P 8(R1), R11
+ MOVD.P 8(R2), R12
+ EOR R11, R12, R12
+ MOVD.P R12, 8(R0)
+less_than8:
+ TBZ $2, R3, less_than4
+ MOVWU.P 4(R1), R13
+ MOVWU.P 4(R2), R14
+ EORW R13, R14, R14
+ MOVWU.P R14, 4(R0)
+less_than4:
+ TBZ $1, R3, less_than2
+ MOVHU.P 2(R1), R15
+ MOVHU.P 2(R2), R16
+ EORW R15, R16, R16
+ MOVHU.P R16, 2(R0)
+less_than2:
+ TBZ $0, R3, end
+ MOVBU (R1), R17
+ MOVBU (R2), R19
+ EORW R17, R19, R19
+ MOVBU R19, (R0)
+end:
+ RET
diff --git a/src/crypto/subtle/xor_generic.go b/src/crypto/subtle/xor_generic.go
new file mode 100644
index 0000000..7dc89e3
--- /dev/null
+++ b/src/crypto/subtle/xor_generic.go
@@ -0,0 +1,64 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (!amd64 && !arm64 && !ppc64 && !ppc64le) || purego
+
+package subtle
+
+import (
+ "runtime"
+ "unsafe"
+)
+
+const wordSize = unsafe.Sizeof(uintptr(0))
+
+const supportsUnaligned = runtime.GOARCH == "386" ||
+ runtime.GOARCH == "amd64" ||
+ runtime.GOARCH == "ppc64" ||
+ runtime.GOARCH == "ppc64le" ||
+ runtime.GOARCH == "s390x"
+
+func xorBytes(dstb, xb, yb *byte, n int) {
+ // xorBytes assembly is written using pointers and n. Back to slices.
+ dst := unsafe.Slice(dstb, n)
+ x := unsafe.Slice(xb, n)
+ y := unsafe.Slice(yb, n)
+
+ if supportsUnaligned || aligned(dstb, xb, yb) {
+ xorLoop(words(dst), words(x), words(y))
+ if uintptr(n)%wordSize == 0 {
+ return
+ }
+ done := n &^ int(wordSize-1)
+ dst = dst[done:]
+ x = x[done:]
+ y = y[done:]
+ }
+ xorLoop(dst, x, y)
+}
+
+// aligned reports whether dst, x, and y are all word-aligned pointers.
+func aligned(dst, x, y *byte) bool {
+ return (uintptr(unsafe.Pointer(dst))|uintptr(unsafe.Pointer(x))|uintptr(unsafe.Pointer(y)))&(wordSize-1) == 0
+}
+
+// words returns a []uintptr pointing at the same data as x,
+// with any trailing partial word removed.
+func words(x []byte) []uintptr {
+ n := uintptr(len(x)) / wordSize
+ if n == 0 {
+ // Avoid creating a *uintptr that refers to data smaller than a uintptr;
+ // see issue 59334.
+ return nil
+ }
+ return unsafe.Slice((*uintptr)(unsafe.Pointer(&x[0])), n)
+}
+
+func xorLoop[T byte | uintptr](dst, x, y []T) {
+ x = x[:len(dst)] // remove bounds check in loop
+ y = y[:len(dst)] // remove bounds check in loop
+ for i := range dst {
+ dst[i] = x[i] ^ y[i]
+ }
+}
diff --git a/src/crypto/subtle/xor_ppc64x.go b/src/crypto/subtle/xor_ppc64x.go
new file mode 100644
index 0000000..760463c
--- /dev/null
+++ b/src/crypto/subtle/xor_ppc64x.go
@@ -0,0 +1,10 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (ppc64 || ppc64le) && !purego
+
+package subtle
+
+//go:noescape
+func xorBytes(dst, a, b *byte, n int)
diff --git a/src/crypto/subtle/xor_ppc64x.s b/src/crypto/subtle/xor_ppc64x.s
new file mode 100644
index 0000000..72bb80d
--- /dev/null
+++ b/src/crypto/subtle/xor_ppc64x.s
@@ -0,0 +1,87 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build (ppc64 || ppc64le) && !purego
+
+#include "textflag.h"
+
+// func xorBytes(dst, a, b *byte, n int)
+TEXT ·xorBytes(SB), NOSPLIT, $0
+ MOVD dst+0(FP), R3 // R3 = dst
+ MOVD a+8(FP), R4 // R4 = a
+ MOVD b+16(FP), R5 // R5 = b
+ MOVD n+24(FP), R6 // R6 = n
+
+ CMPU R6, $32, CR7 // Check if n ≥ 32 bytes
+ MOVD R0, R8 // R8 = index
+ CMPU R6, $8, CR6 // Check if 8 ≤ n < 32 bytes
+ BLT CR6, small // Smaller than 8
+ BLT CR7, xor16 // Case for 16 ≤ n < 32 bytes
+
+ // Case for n ≥ 32 bytes
+preloop32:
+ SRD $5, R6, R7 // Setup loop counter
+ MOVD R7, CTR
+ MOVD $16, R10
+ ANDCC $31, R6, R9 // Check for tailing bytes for later
+loop32:
+ LXVD2X (R4)(R8), VS32 // VS32 = a[i,...,i+15]
+ LXVD2X (R4)(R10), VS34
+ LXVD2X (R5)(R8), VS33 // VS33 = b[i,...,i+15]
+ LXVD2X (R5)(R10), VS35
+ XXLXOR VS32, VS33, VS32 // VS34 = a[] ^ b[]
+ XXLXOR VS34, VS35, VS34
+ STXVD2X VS32, (R3)(R8) // Store to dst
+ STXVD2X VS34, (R3)(R10)
+ ADD $32, R8 // Update index
+ ADD $32, R10
+ BC 16, 0, loop32 // bdnz loop16
+
+ BEQ CR0, done
+
+ MOVD R9, R6
+ CMP R6, $8
+ BLT small
+xor16:
+ CMP R6, $16
+ BLT xor8
+ LXVD2X (R4)(R8), VS32
+ LXVD2X (R5)(R8), VS33
+ XXLXOR VS32, VS33, VS32
+ STXVD2X VS32, (R3)(R8)
+ ADD $16, R8
+ ADD $-16, R6
+ CMP R6, $8
+ BLT small
+xor8:
+ // Case for 8 ≤ n < 16 bytes
+ MOVD (R4)(R8), R14 // R14 = a[i,...,i+7]
+ MOVD (R5)(R8), R15 // R15 = b[i,...,i+7]
+ XOR R14, R15, R16 // R16 = a[] ^ b[]
+ SUB $8, R6 // n = n - 8
+ MOVD R16, (R3)(R8) // Store to dst
+ ADD $8, R8
+
+ // Check if we're finished
+ CMP R6, R0
+ BGT small
+ RET
+
+ // Case for n < 8 bytes and tailing bytes from the
+ // previous cases.
+small:
+ CMP R6, R0
+ BEQ done
+ MOVD R6, CTR // Setup loop counter
+
+loop:
+ MOVBZ (R4)(R8), R14 // R14 = a[i]
+ MOVBZ (R5)(R8), R15 // R15 = b[i]
+ XOR R14, R15, R16 // R16 = a[i] ^ b[i]
+ MOVB R16, (R3)(R8) // Store to dst
+ ADD $1, R8
+ BC 16, 0, loop // bdnz loop
+
+done:
+ RET
diff --git a/src/crypto/subtle/xor_test.go b/src/crypto/subtle/xor_test.go
new file mode 100644
index 0000000..7d89b83
--- /dev/null
+++ b/src/crypto/subtle/xor_test.go
@@ -0,0 +1,106 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package subtle_test
+
+import (
+ "bytes"
+ "crypto/rand"
+ . "crypto/subtle"
+ "fmt"
+ "io"
+ "testing"
+)
+
+func TestXORBytes(t *testing.T) {
+ for n := 1; n <= 1024; n++ {
+ if n > 16 && testing.Short() {
+ n += n >> 3
+ }
+ for alignP := 0; alignP < 8; alignP++ {
+ for alignQ := 0; alignQ < 8; alignQ++ {
+ for alignD := 0; alignD < 8; alignD++ {
+ p := make([]byte, alignP+n, alignP+n+10)[alignP:]
+ q := make([]byte, alignQ+n, alignQ+n+10)[alignQ:]
+ if n&1 != 0 {
+ p = p[:n]
+ } else {
+ q = q[:n]
+ }
+ if _, err := io.ReadFull(rand.Reader, p); err != nil {
+ t.Fatal(err)
+ }
+ if _, err := io.ReadFull(rand.Reader, q); err != nil {
+ t.Fatal(err)
+ }
+
+ d := make([]byte, alignD+n, alignD+n+10)
+ for i := range d {
+ d[i] = 0xdd
+ }
+ want := make([]byte, len(d), cap(d))
+ copy(want[:cap(want)], d[:cap(d)])
+ for i := 0; i < n; i++ {
+ want[alignD+i] = p[i] ^ q[i]
+ }
+
+ if XORBytes(d[alignD:], p, q); !bytes.Equal(d, want) {
+ t.Fatalf("n=%d alignP=%d alignQ=%d alignD=%d:\n\tp = %x\n\tq = %x\n\td = %x\n\twant %x\n", n, alignP, alignQ, alignD, p, q, d, want)
+ }
+ }
+ }
+ }
+ }
+}
+
+func TestXorBytesPanic(t *testing.T) {
+ mustPanic(t, "subtle.XORBytes: dst too short", func() {
+ XORBytes(nil, make([]byte, 1), make([]byte, 1))
+ })
+ mustPanic(t, "subtle.XORBytes: dst too short", func() {
+ XORBytes(make([]byte, 1), make([]byte, 2), make([]byte, 3))
+ })
+}
+
+func min(a, b []byte) int {
+ n := len(a)
+ if len(b) < n {
+ n = len(b)
+ }
+ return n
+}
+
+func BenchmarkXORBytes(b *testing.B) {
+ dst := make([]byte, 1<<15)
+ data0 := make([]byte, 1<<15)
+ data1 := make([]byte, 1<<15)
+ sizes := []int64{1 << 3, 1 << 7, 1 << 11, 1 << 15}
+ for _, size := range sizes {
+ b.Run(fmt.Sprintf("%dBytes", size), func(b *testing.B) {
+ s0 := data0[:size]
+ s1 := data1[:size]
+ b.SetBytes(int64(size))
+ for i := 0; i < b.N; i++ {
+ XORBytes(dst, s0, s1)
+ }
+ })
+ }
+}
+
+func mustPanic(t *testing.T, expected string, f func()) {
+ t.Helper()
+ defer func() {
+ switch msg := recover().(type) {
+ case nil:
+ t.Errorf("expected panic(%q), but did not panic", expected)
+ case string:
+ if msg != expected {
+ t.Errorf("expected panic(%q), but got panic(%q)", expected, msg)
+ }
+ default:
+ t.Errorf("expected panic(%q), but got panic(%T%v)", expected, msg, msg)
+ }
+ }()
+ f()
+}
diff --git a/src/crypto/tls/alert.go b/src/crypto/tls/alert.go
new file mode 100644
index 0000000..4790b73
--- /dev/null
+++ b/src/crypto/tls/alert.go
@@ -0,0 +1,99 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import "strconv"
+
+type alert uint8
+
+const (
+ // alert level
+ alertLevelWarning = 1
+ alertLevelError = 2
+)
+
+const (
+ alertCloseNotify alert = 0
+ alertUnexpectedMessage alert = 10
+ alertBadRecordMAC alert = 20
+ alertDecryptionFailed alert = 21
+ alertRecordOverflow alert = 22
+ alertDecompressionFailure alert = 30
+ alertHandshakeFailure alert = 40
+ alertBadCertificate alert = 42
+ alertUnsupportedCertificate alert = 43
+ alertCertificateRevoked alert = 44
+ alertCertificateExpired alert = 45
+ alertCertificateUnknown alert = 46
+ alertIllegalParameter alert = 47
+ alertUnknownCA alert = 48
+ alertAccessDenied alert = 49
+ alertDecodeError alert = 50
+ alertDecryptError alert = 51
+ alertExportRestriction alert = 60
+ alertProtocolVersion alert = 70
+ alertInsufficientSecurity alert = 71
+ alertInternalError alert = 80
+ alertInappropriateFallback alert = 86
+ alertUserCanceled alert = 90
+ alertNoRenegotiation alert = 100
+ alertMissingExtension alert = 109
+ alertUnsupportedExtension alert = 110
+ alertCertificateUnobtainable alert = 111
+ alertUnrecognizedName alert = 112
+ alertBadCertificateStatusResponse alert = 113
+ alertBadCertificateHashValue alert = 114
+ alertUnknownPSKIdentity alert = 115
+ alertCertificateRequired alert = 116
+ alertNoApplicationProtocol alert = 120
+)
+
+var alertText = map[alert]string{
+ alertCloseNotify: "close notify",
+ alertUnexpectedMessage: "unexpected message",
+ alertBadRecordMAC: "bad record MAC",
+ alertDecryptionFailed: "decryption failed",
+ alertRecordOverflow: "record overflow",
+ alertDecompressionFailure: "decompression failure",
+ alertHandshakeFailure: "handshake failure",
+ alertBadCertificate: "bad certificate",
+ alertUnsupportedCertificate: "unsupported certificate",
+ alertCertificateRevoked: "revoked certificate",
+ alertCertificateExpired: "expired certificate",
+ alertCertificateUnknown: "unknown certificate",
+ alertIllegalParameter: "illegal parameter",
+ alertUnknownCA: "unknown certificate authority",
+ alertAccessDenied: "access denied",
+ alertDecodeError: "error decoding message",
+ alertDecryptError: "error decrypting message",
+ alertExportRestriction: "export restriction",
+ alertProtocolVersion: "protocol version not supported",
+ alertInsufficientSecurity: "insufficient security level",
+ alertInternalError: "internal error",
+ alertInappropriateFallback: "inappropriate fallback",
+ alertUserCanceled: "user canceled",
+ alertNoRenegotiation: "no renegotiation",
+ alertMissingExtension: "missing extension",
+ alertUnsupportedExtension: "unsupported extension",
+ alertCertificateUnobtainable: "certificate unobtainable",
+ alertUnrecognizedName: "unrecognized name",
+ alertBadCertificateStatusResponse: "bad certificate status response",
+ alertBadCertificateHashValue: "bad certificate hash value",
+ alertUnknownPSKIdentity: "unknown PSK identity",
+ alertCertificateRequired: "certificate required",
+ alertNoApplicationProtocol: "no application protocol",
+}
+
+func (e alert) String() string {
+ s, ok := alertText[e]
+ if ok {
+ return "tls: " + s
+ }
+ return "tls: alert(" + strconv.Itoa(int(e)) + ")"
+}
+
+func (e alert) Error() string {
+ return e.String()
+}
diff --git a/src/crypto/tls/auth.go b/src/crypto/tls/auth.go
new file mode 100644
index 0000000..7c5675c
--- /dev/null
+++ b/src/crypto/tls/auth.go
@@ -0,0 +1,293 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/elliptic"
+ "crypto/rsa"
+ "errors"
+ "fmt"
+ "hash"
+ "io"
+)
+
+// verifyHandshakeSignature verifies a signature against pre-hashed
+// (if required) handshake contents.
+func verifyHandshakeSignature(sigType uint8, pubkey crypto.PublicKey, hashFunc crypto.Hash, signed, sig []byte) error {
+ switch sigType {
+ case signatureECDSA:
+ pubKey, ok := pubkey.(*ecdsa.PublicKey)
+ if !ok {
+ return fmt.Errorf("expected an ECDSA public key, got %T", pubkey)
+ }
+ if !ecdsa.VerifyASN1(pubKey, signed, sig) {
+ return errors.New("ECDSA verification failure")
+ }
+ case signatureEd25519:
+ pubKey, ok := pubkey.(ed25519.PublicKey)
+ if !ok {
+ return fmt.Errorf("expected an Ed25519 public key, got %T", pubkey)
+ }
+ if !ed25519.Verify(pubKey, signed, sig) {
+ return errors.New("Ed25519 verification failure")
+ }
+ case signaturePKCS1v15:
+ pubKey, ok := pubkey.(*rsa.PublicKey)
+ if !ok {
+ return fmt.Errorf("expected an RSA public key, got %T", pubkey)
+ }
+ if err := rsa.VerifyPKCS1v15(pubKey, hashFunc, signed, sig); err != nil {
+ return err
+ }
+ case signatureRSAPSS:
+ pubKey, ok := pubkey.(*rsa.PublicKey)
+ if !ok {
+ return fmt.Errorf("expected an RSA public key, got %T", pubkey)
+ }
+ signOpts := &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}
+ if err := rsa.VerifyPSS(pubKey, hashFunc, signed, sig, signOpts); err != nil {
+ return err
+ }
+ default:
+ return errors.New("internal error: unknown signature type")
+ }
+ return nil
+}
+
+const (
+ serverSignatureContext = "TLS 1.3, server CertificateVerify\x00"
+ clientSignatureContext = "TLS 1.3, client CertificateVerify\x00"
+)
+
+var signaturePadding = []byte{
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+ 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20, 0x20,
+}
+
+// signedMessage returns the pre-hashed (if necessary) message to be signed by
+// certificate keys in TLS 1.3. See RFC 8446, Section 4.4.3.
+func signedMessage(sigHash crypto.Hash, context string, transcript hash.Hash) []byte {
+ if sigHash == directSigning {
+ b := &bytes.Buffer{}
+ b.Write(signaturePadding)
+ io.WriteString(b, context)
+ b.Write(transcript.Sum(nil))
+ return b.Bytes()
+ }
+ h := sigHash.New()
+ h.Write(signaturePadding)
+ io.WriteString(h, context)
+ h.Write(transcript.Sum(nil))
+ return h.Sum(nil)
+}
+
+// typeAndHashFromSignatureScheme returns the corresponding signature type and
+// crypto.Hash for a given TLS SignatureScheme.
+func typeAndHashFromSignatureScheme(signatureAlgorithm SignatureScheme) (sigType uint8, hash crypto.Hash, err error) {
+ switch signatureAlgorithm {
+ case PKCS1WithSHA1, PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512:
+ sigType = signaturePKCS1v15
+ case PSSWithSHA256, PSSWithSHA384, PSSWithSHA512:
+ sigType = signatureRSAPSS
+ case ECDSAWithSHA1, ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512:
+ sigType = signatureECDSA
+ case Ed25519:
+ sigType = signatureEd25519
+ default:
+ return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm)
+ }
+ switch signatureAlgorithm {
+ case PKCS1WithSHA1, ECDSAWithSHA1:
+ hash = crypto.SHA1
+ case PKCS1WithSHA256, PSSWithSHA256, ECDSAWithP256AndSHA256:
+ hash = crypto.SHA256
+ case PKCS1WithSHA384, PSSWithSHA384, ECDSAWithP384AndSHA384:
+ hash = crypto.SHA384
+ case PKCS1WithSHA512, PSSWithSHA512, ECDSAWithP521AndSHA512:
+ hash = crypto.SHA512
+ case Ed25519:
+ hash = directSigning
+ default:
+ return 0, 0, fmt.Errorf("unsupported signature algorithm: %v", signatureAlgorithm)
+ }
+ return sigType, hash, nil
+}
+
+// legacyTypeAndHashFromPublicKey returns the fixed signature type and crypto.Hash for
+// a given public key used with TLS 1.0 and 1.1, before the introduction of
+// signature algorithm negotiation.
+func legacyTypeAndHashFromPublicKey(pub crypto.PublicKey) (sigType uint8, hash crypto.Hash, err error) {
+ switch pub.(type) {
+ case *rsa.PublicKey:
+ return signaturePKCS1v15, crypto.MD5SHA1, nil
+ case *ecdsa.PublicKey:
+ return signatureECDSA, crypto.SHA1, nil
+ case ed25519.PublicKey:
+ // RFC 8422 specifies support for Ed25519 in TLS 1.0 and 1.1,
+ // but it requires holding on to a handshake transcript to do a
+ // full signature, and not even OpenSSL bothers with the
+ // complexity, so we can't even test it properly.
+ return 0, 0, fmt.Errorf("tls: Ed25519 public keys are not supported before TLS 1.2")
+ default:
+ return 0, 0, fmt.Errorf("tls: unsupported public key: %T", pub)
+ }
+}
+
+var rsaSignatureSchemes = []struct {
+ scheme SignatureScheme
+ minModulusBytes int
+ maxVersion uint16
+}{
+ // RSA-PSS is used with PSSSaltLengthEqualsHash, and requires
+ // emLen >= hLen + sLen + 2
+ {PSSWithSHA256, crypto.SHA256.Size()*2 + 2, VersionTLS13},
+ {PSSWithSHA384, crypto.SHA384.Size()*2 + 2, VersionTLS13},
+ {PSSWithSHA512, crypto.SHA512.Size()*2 + 2, VersionTLS13},
+ // PKCS #1 v1.5 uses prefixes from hashPrefixes in crypto/rsa, and requires
+ // emLen >= len(prefix) + hLen + 11
+ // TLS 1.3 dropped support for PKCS #1 v1.5 in favor of RSA-PSS.
+ {PKCS1WithSHA256, 19 + crypto.SHA256.Size() + 11, VersionTLS12},
+ {PKCS1WithSHA384, 19 + crypto.SHA384.Size() + 11, VersionTLS12},
+ {PKCS1WithSHA512, 19 + crypto.SHA512.Size() + 11, VersionTLS12},
+ {PKCS1WithSHA1, 15 + crypto.SHA1.Size() + 11, VersionTLS12},
+}
+
+// signatureSchemesForCertificate returns the list of supported SignatureSchemes
+// for a given certificate, based on the public key and the protocol version,
+// and optionally filtered by its explicit SupportedSignatureAlgorithms.
+//
+// This function must be kept in sync with supportedSignatureAlgorithms.
+// FIPS filtering is applied in the caller, selectSignatureScheme.
+func signatureSchemesForCertificate(version uint16, cert *Certificate) []SignatureScheme {
+ priv, ok := cert.PrivateKey.(crypto.Signer)
+ if !ok {
+ return nil
+ }
+
+ var sigAlgs []SignatureScheme
+ switch pub := priv.Public().(type) {
+ case *ecdsa.PublicKey:
+ if version != VersionTLS13 {
+ // In TLS 1.2 and earlier, ECDSA algorithms are not
+ // constrained to a single curve.
+ sigAlgs = []SignatureScheme{
+ ECDSAWithP256AndSHA256,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithP521AndSHA512,
+ ECDSAWithSHA1,
+ }
+ break
+ }
+ switch pub.Curve {
+ case elliptic.P256():
+ sigAlgs = []SignatureScheme{ECDSAWithP256AndSHA256}
+ case elliptic.P384():
+ sigAlgs = []SignatureScheme{ECDSAWithP384AndSHA384}
+ case elliptic.P521():
+ sigAlgs = []SignatureScheme{ECDSAWithP521AndSHA512}
+ default:
+ return nil
+ }
+ case *rsa.PublicKey:
+ size := pub.Size()
+ sigAlgs = make([]SignatureScheme, 0, len(rsaSignatureSchemes))
+ for _, candidate := range rsaSignatureSchemes {
+ if size >= candidate.minModulusBytes && version <= candidate.maxVersion {
+ sigAlgs = append(sigAlgs, candidate.scheme)
+ }
+ }
+ case ed25519.PublicKey:
+ sigAlgs = []SignatureScheme{Ed25519}
+ default:
+ return nil
+ }
+
+ if cert.SupportedSignatureAlgorithms != nil {
+ var filteredSigAlgs []SignatureScheme
+ for _, sigAlg := range sigAlgs {
+ if isSupportedSignatureAlgorithm(sigAlg, cert.SupportedSignatureAlgorithms) {
+ filteredSigAlgs = append(filteredSigAlgs, sigAlg)
+ }
+ }
+ return filteredSigAlgs
+ }
+ return sigAlgs
+}
+
+// selectSignatureScheme picks a SignatureScheme from the peer's preference list
+// that works with the selected certificate. It's only called for protocol
+// versions that support signature algorithms, so TLS 1.2 and 1.3.
+func selectSignatureScheme(vers uint16, c *Certificate, peerAlgs []SignatureScheme) (SignatureScheme, error) {
+ supportedAlgs := signatureSchemesForCertificate(vers, c)
+ if len(supportedAlgs) == 0 {
+ return 0, unsupportedCertificateError(c)
+ }
+ if len(peerAlgs) == 0 && vers == VersionTLS12 {
+ // For TLS 1.2, if the client didn't send signature_algorithms then we
+ // can assume that it supports SHA1. See RFC 5246, Section 7.4.1.4.1.
+ peerAlgs = []SignatureScheme{PKCS1WithSHA1, ECDSAWithSHA1}
+ }
+ // Pick signature scheme in the peer's preference order, as our
+ // preference order is not configurable.
+ for _, preferredAlg := range peerAlgs {
+ if needFIPS() && !isSupportedSignatureAlgorithm(preferredAlg, fipsSupportedSignatureAlgorithms) {
+ continue
+ }
+ if isSupportedSignatureAlgorithm(preferredAlg, supportedAlgs) {
+ return preferredAlg, nil
+ }
+ }
+ return 0, errors.New("tls: peer doesn't support any of the certificate's signature algorithms")
+}
+
+// unsupportedCertificateError returns a helpful error for certificates with
+// an unsupported private key.
+func unsupportedCertificateError(cert *Certificate) error {
+ switch cert.PrivateKey.(type) {
+ case rsa.PrivateKey, ecdsa.PrivateKey:
+ return fmt.Errorf("tls: unsupported certificate: private key is %T, expected *%T",
+ cert.PrivateKey, cert.PrivateKey)
+ case *ed25519.PrivateKey:
+ return fmt.Errorf("tls: unsupported certificate: private key is *ed25519.PrivateKey, expected ed25519.PrivateKey")
+ }
+
+ signer, ok := cert.PrivateKey.(crypto.Signer)
+ if !ok {
+ return fmt.Errorf("tls: certificate private key (%T) does not implement crypto.Signer",
+ cert.PrivateKey)
+ }
+
+ switch pub := signer.Public().(type) {
+ case *ecdsa.PublicKey:
+ switch pub.Curve {
+ case elliptic.P256():
+ case elliptic.P384():
+ case elliptic.P521():
+ default:
+ return fmt.Errorf("tls: unsupported certificate curve (%s)", pub.Curve.Params().Name)
+ }
+ case *rsa.PublicKey:
+ return fmt.Errorf("tls: certificate RSA key size too small for supported signature algorithms")
+ case ed25519.PublicKey:
+ default:
+ return fmt.Errorf("tls: unsupported certificate key (%T)", pub)
+ }
+
+ if cert.SupportedSignatureAlgorithms != nil {
+ return fmt.Errorf("tls: peer doesn't support the certificate custom signature algorithms")
+ }
+
+ return fmt.Errorf("tls: internal error: unsupported key (%T)", cert.PrivateKey)
+}
diff --git a/src/crypto/tls/auth_test.go b/src/crypto/tls/auth_test.go
new file mode 100644
index 0000000..c23d93f
--- /dev/null
+++ b/src/crypto/tls/auth_test.go
@@ -0,0 +1,168 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "crypto"
+ "testing"
+)
+
+func TestSignatureSelection(t *testing.T) {
+ rsaCert := &Certificate{
+ Certificate: [][]byte{testRSACertificate},
+ PrivateKey: testRSAPrivateKey,
+ }
+ pkcs1Cert := &Certificate{
+ Certificate: [][]byte{testRSACertificate},
+ PrivateKey: testRSAPrivateKey,
+ SupportedSignatureAlgorithms: []SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256},
+ }
+ ecdsaCert := &Certificate{
+ Certificate: [][]byte{testP256Certificate},
+ PrivateKey: testP256PrivateKey,
+ }
+ ed25519Cert := &Certificate{
+ Certificate: [][]byte{testEd25519Certificate},
+ PrivateKey: testEd25519PrivateKey,
+ }
+
+ tests := []struct {
+ cert *Certificate
+ peerSigAlgs []SignatureScheme
+ tlsVersion uint16
+
+ expectedSigAlg SignatureScheme
+ expectedSigType uint8
+ expectedHash crypto.Hash
+ }{
+ {rsaCert, []SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256}, VersionTLS12, PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1},
+ {rsaCert, []SignatureScheme{PKCS1WithSHA512, PKCS1WithSHA1}, VersionTLS12, PKCS1WithSHA512, signaturePKCS1v15, crypto.SHA512},
+ {rsaCert, []SignatureScheme{PSSWithSHA256, PKCS1WithSHA256}, VersionTLS12, PSSWithSHA256, signatureRSAPSS, crypto.SHA256},
+ {pkcs1Cert, []SignatureScheme{PSSWithSHA256, PKCS1WithSHA256}, VersionTLS12, PKCS1WithSHA256, signaturePKCS1v15, crypto.SHA256},
+ {rsaCert, []SignatureScheme{PSSWithSHA384, PKCS1WithSHA1}, VersionTLS13, PSSWithSHA384, signatureRSAPSS, crypto.SHA384},
+ {ecdsaCert, []SignatureScheme{ECDSAWithSHA1}, VersionTLS12, ECDSAWithSHA1, signatureECDSA, crypto.SHA1},
+ {ecdsaCert, []SignatureScheme{ECDSAWithP256AndSHA256}, VersionTLS12, ECDSAWithP256AndSHA256, signatureECDSA, crypto.SHA256},
+ {ecdsaCert, []SignatureScheme{ECDSAWithP256AndSHA256}, VersionTLS13, ECDSAWithP256AndSHA256, signatureECDSA, crypto.SHA256},
+ {ed25519Cert, []SignatureScheme{Ed25519}, VersionTLS12, Ed25519, signatureEd25519, directSigning},
+ {ed25519Cert, []SignatureScheme{Ed25519}, VersionTLS13, Ed25519, signatureEd25519, directSigning},
+
+ // TLS 1.2 without signature_algorithms extension
+ {rsaCert, nil, VersionTLS12, PKCS1WithSHA1, signaturePKCS1v15, crypto.SHA1},
+ {ecdsaCert, nil, VersionTLS12, ECDSAWithSHA1, signatureECDSA, crypto.SHA1},
+
+ // TLS 1.2 does not restrict the ECDSA curve (our ecdsaCert is P-256)
+ {ecdsaCert, []SignatureScheme{ECDSAWithP384AndSHA384}, VersionTLS12, ECDSAWithP384AndSHA384, signatureECDSA, crypto.SHA384},
+ }
+
+ for testNo, test := range tests {
+ sigAlg, err := selectSignatureScheme(test.tlsVersion, test.cert, test.peerSigAlgs)
+ if err != nil {
+ t.Errorf("test[%d]: unexpected selectSignatureScheme error: %v", testNo, err)
+ }
+ if test.expectedSigAlg != sigAlg {
+ t.Errorf("test[%d]: expected signature scheme %v, got %v", testNo, test.expectedSigAlg, sigAlg)
+ }
+ sigType, hashFunc, err := typeAndHashFromSignatureScheme(sigAlg)
+ if err != nil {
+ t.Errorf("test[%d]: unexpected typeAndHashFromSignatureScheme error: %v", testNo, err)
+ }
+ if test.expectedSigType != sigType {
+ t.Errorf("test[%d]: expected signature algorithm %#x, got %#x", testNo, test.expectedSigType, sigType)
+ }
+ if test.expectedHash != hashFunc {
+ t.Errorf("test[%d]: expected hash function %#x, got %#x", testNo, test.expectedHash, hashFunc)
+ }
+ }
+
+ brokenCert := &Certificate{
+ Certificate: [][]byte{testRSACertificate},
+ PrivateKey: testRSAPrivateKey,
+ SupportedSignatureAlgorithms: []SignatureScheme{Ed25519},
+ }
+
+ badTests := []struct {
+ cert *Certificate
+ peerSigAlgs []SignatureScheme
+ tlsVersion uint16
+ }{
+ {rsaCert, []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithSHA1}, VersionTLS12},
+ {ecdsaCert, []SignatureScheme{PKCS1WithSHA256, PKCS1WithSHA1}, VersionTLS12},
+ {rsaCert, []SignatureScheme{0}, VersionTLS12},
+ {ed25519Cert, []SignatureScheme{ECDSAWithP256AndSHA256, ECDSAWithSHA1}, VersionTLS12},
+ {ecdsaCert, []SignatureScheme{Ed25519}, VersionTLS12},
+ {brokenCert, []SignatureScheme{Ed25519}, VersionTLS12},
+ {brokenCert, []SignatureScheme{PKCS1WithSHA256}, VersionTLS12},
+ // RFC 5246, Section 7.4.1.4.1, says to only consider {sha1,ecdsa} as
+ // default when the extension is missing, and RFC 8422 does not update
+ // it. Anyway, if a stack supports Ed25519 it better support sigalgs.
+ {ed25519Cert, nil, VersionTLS12},
+ // TLS 1.3 has no default signature_algorithms.
+ {rsaCert, nil, VersionTLS13},
+ {ecdsaCert, nil, VersionTLS13},
+ {ed25519Cert, nil, VersionTLS13},
+ // Wrong curve, which TLS 1.3 checks
+ {ecdsaCert, []SignatureScheme{ECDSAWithP384AndSHA384}, VersionTLS13},
+ // TLS 1.3 does not support PKCS1v1.5 or SHA-1.
+ {rsaCert, []SignatureScheme{PKCS1WithSHA256}, VersionTLS13},
+ {pkcs1Cert, []SignatureScheme{PSSWithSHA256, PKCS1WithSHA256}, VersionTLS13},
+ {ecdsaCert, []SignatureScheme{ECDSAWithSHA1}, VersionTLS13},
+ // The key can be too small for the hash.
+ {rsaCert, []SignatureScheme{PSSWithSHA512}, VersionTLS12},
+ }
+
+ for testNo, test := range badTests {
+ sigAlg, err := selectSignatureScheme(test.tlsVersion, test.cert, test.peerSigAlgs)
+ if err == nil {
+ t.Errorf("test[%d]: unexpected success, got %v", testNo, sigAlg)
+ }
+ }
+}
+
+func TestLegacyTypeAndHash(t *testing.T) {
+ sigType, hashFunc, err := legacyTypeAndHashFromPublicKey(testRSAPrivateKey.Public())
+ if err != nil {
+ t.Errorf("RSA: unexpected error: %v", err)
+ }
+ if expectedSigType := signaturePKCS1v15; expectedSigType != sigType {
+ t.Errorf("RSA: expected signature type %#x, got %#x", expectedSigType, sigType)
+ }
+ if expectedHashFunc := crypto.MD5SHA1; expectedHashFunc != hashFunc {
+ t.Errorf("RSA: expected hash %#x, got %#x", expectedHashFunc, hashFunc)
+ }
+
+ sigType, hashFunc, err = legacyTypeAndHashFromPublicKey(testECDSAPrivateKey.Public())
+ if err != nil {
+ t.Errorf("ECDSA: unexpected error: %v", err)
+ }
+ if expectedSigType := signatureECDSA; expectedSigType != sigType {
+ t.Errorf("ECDSA: expected signature type %#x, got %#x", expectedSigType, sigType)
+ }
+ if expectedHashFunc := crypto.SHA1; expectedHashFunc != hashFunc {
+ t.Errorf("ECDSA: expected hash %#x, got %#x", expectedHashFunc, hashFunc)
+ }
+
+ // Ed25519 is not supported by TLS 1.0 and 1.1.
+ _, _, err = legacyTypeAndHashFromPublicKey(testEd25519PrivateKey.Public())
+ if err == nil {
+ t.Errorf("Ed25519: unexpected success")
+ }
+}
+
+// TestSupportedSignatureAlgorithms checks that all supportedSignatureAlgorithms
+// have valid type and hash information.
+func TestSupportedSignatureAlgorithms(t *testing.T) {
+ for _, sigAlg := range supportedSignatureAlgorithms() {
+ sigType, hash, err := typeAndHashFromSignatureScheme(sigAlg)
+ if err != nil {
+ t.Errorf("%v: unexpected error: %v", sigAlg, err)
+ }
+ if sigType == 0 {
+ t.Errorf("%v: missing signature type", sigAlg)
+ }
+ if hash == 0 && sigAlg != Ed25519 {
+ t.Errorf("%v: missing hash", sigAlg)
+ }
+ }
+}
diff --git a/src/crypto/tls/boring.go b/src/crypto/tls/boring.go
new file mode 100644
index 0000000..1827f76
--- /dev/null
+++ b/src/crypto/tls/boring.go
@@ -0,0 +1,98 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto
+
+package tls
+
+import (
+ "crypto/internal/boring/fipstls"
+)
+
+// needFIPS returns fipstls.Required(); it avoids a new import in common.go.
+func needFIPS() bool {
+ return fipstls.Required()
+}
+
+// fipsMinVersion replaces c.minVersion in FIPS-only mode.
+func fipsMinVersion(c *Config) uint16 {
+ // FIPS requires TLS 1.2.
+ return VersionTLS12
+}
+
+// fipsMaxVersion replaces c.maxVersion in FIPS-only mode.
+func fipsMaxVersion(c *Config) uint16 {
+ // FIPS requires TLS 1.2.
+ return VersionTLS12
+}
+
+// default defaultFIPSCurvePreferences is the FIPS-allowed curves,
+// in preference order (most preferable first).
+var defaultFIPSCurvePreferences = []CurveID{CurveP256, CurveP384, CurveP521}
+
+// fipsCurvePreferences replaces c.curvePreferences in FIPS-only mode.
+func fipsCurvePreferences(c *Config) []CurveID {
+ if c == nil || len(c.CurvePreferences) == 0 {
+ return defaultFIPSCurvePreferences
+ }
+ var list []CurveID
+ for _, id := range c.CurvePreferences {
+ for _, allowed := range defaultFIPSCurvePreferences {
+ if id == allowed {
+ list = append(list, id)
+ break
+ }
+ }
+ }
+ return list
+}
+
+// defaultCipherSuitesFIPS are the FIPS-allowed cipher suites.
+var defaultCipherSuitesFIPS = []uint16{
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+}
+
+// fipsCipherSuites replaces c.cipherSuites in FIPS-only mode.
+func fipsCipherSuites(c *Config) []uint16 {
+ if c == nil || c.CipherSuites == nil {
+ return defaultCipherSuitesFIPS
+ }
+ list := make([]uint16, 0, len(defaultCipherSuitesFIPS))
+ for _, id := range c.CipherSuites {
+ for _, allowed := range defaultCipherSuitesFIPS {
+ if id == allowed {
+ list = append(list, id)
+ break
+ }
+ }
+ }
+ return list
+}
+
+// fipsSupportedSignatureAlgorithms currently are a subset of
+// defaultSupportedSignatureAlgorithms without Ed25519 and SHA-1.
+var fipsSupportedSignatureAlgorithms = []SignatureScheme{
+ PSSWithSHA256,
+ PSSWithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA256,
+ ECDSAWithP256AndSHA256,
+ PKCS1WithSHA384,
+ ECDSAWithP384AndSHA384,
+ PKCS1WithSHA512,
+ ECDSAWithP521AndSHA512,
+}
+
+// supportedSignatureAlgorithms returns the supported signature algorithms.
+func supportedSignatureAlgorithms() []SignatureScheme {
+ if !needFIPS() {
+ return defaultSupportedSignatureAlgorithms
+ }
+ return fipsSupportedSignatureAlgorithms
+}
diff --git a/src/crypto/tls/boring_test.go b/src/crypto/tls/boring_test.go
new file mode 100644
index 0000000..ba68f35
--- /dev/null
+++ b/src/crypto/tls/boring_test.go
@@ -0,0 +1,617 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto
+
+package tls
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/internal/boring/fipstls"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "fmt"
+ "internal/obscuretestdata"
+ "math/big"
+ "net"
+ "runtime"
+ "strings"
+ "testing"
+ "time"
+)
+
+func TestBoringServerProtocolVersion(t *testing.T) {
+ test := func(name string, v uint16, msg string) {
+ t.Run(name, func(t *testing.T) {
+ serverConfig := testConfig.Clone()
+ serverConfig.MinVersion = VersionSSL30
+ clientHello := &clientHelloMsg{
+ vers: v,
+ random: make([]byte, 32),
+ cipherSuites: allCipherSuites(),
+ compressionMethods: []uint8{compressionNone},
+ supportedVersions: []uint16{v},
+ }
+ testClientHelloFailure(t, serverConfig, clientHello, msg)
+ })
+ }
+
+ test("VersionTLS10", VersionTLS10, "")
+ test("VersionTLS11", VersionTLS11, "")
+ test("VersionTLS12", VersionTLS12, "")
+ test("VersionTLS13", VersionTLS13, "")
+
+ fipstls.Force()
+ defer fipstls.Abandon()
+ test("VersionSSL30", VersionSSL30, "client offered only unsupported versions")
+ test("VersionTLS10", VersionTLS10, "client offered only unsupported versions")
+ test("VersionTLS11", VersionTLS11, "client offered only unsupported versions")
+ test("VersionTLS12", VersionTLS12, "")
+ test("VersionTLS13", VersionTLS13, "client offered only unsupported versions")
+}
+
+func isBoringVersion(v uint16) bool {
+ return v == VersionTLS12
+}
+
+func isBoringCipherSuite(id uint16) bool {
+ switch id {
+ case TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384:
+ return true
+ }
+ return false
+}
+
+func isBoringCurve(id CurveID) bool {
+ switch id {
+ case CurveP256, CurveP384, CurveP521:
+ return true
+ }
+ return false
+}
+
+func isECDSA(id uint16) bool {
+ for _, suite := range cipherSuites {
+ if suite.id == id {
+ return suite.flags&suiteECSign == suiteECSign
+ }
+ }
+ panic(fmt.Sprintf("unknown cipher suite %#x", id))
+}
+
+func isBoringSignatureScheme(alg SignatureScheme) bool {
+ switch alg {
+ default:
+ return false
+ case PKCS1WithSHA256,
+ ECDSAWithP256AndSHA256,
+ PKCS1WithSHA384,
+ ECDSAWithP384AndSHA384,
+ PKCS1WithSHA512,
+ ECDSAWithP521AndSHA512,
+ PSSWithSHA256,
+ PSSWithSHA384,
+ PSSWithSHA512:
+ // ok
+ }
+ return true
+}
+
+func TestBoringServerCipherSuites(t *testing.T) {
+ serverConfig := testConfig.Clone()
+ serverConfig.CipherSuites = allCipherSuites()
+ serverConfig.Certificates = make([]Certificate, 1)
+
+ for _, id := range allCipherSuites() {
+ if isECDSA(id) {
+ serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+ serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
+ } else {
+ serverConfig.Certificates[0].Certificate = [][]byte{testRSACertificate}
+ serverConfig.Certificates[0].PrivateKey = testRSAPrivateKey
+ }
+ serverConfig.BuildNameToCertificate()
+ t.Run(fmt.Sprintf("suite=%#x", id), func(t *testing.T) {
+ clientHello := &clientHelloMsg{
+ vers: VersionTLS12,
+ random: make([]byte, 32),
+ cipherSuites: []uint16{id},
+ compressionMethods: []uint8{compressionNone},
+ supportedCurves: defaultCurvePreferences,
+ supportedPoints: []uint8{pointFormatUncompressed},
+ }
+
+ testClientHello(t, serverConfig, clientHello)
+ t.Run("fipstls", func(t *testing.T) {
+ fipstls.Force()
+ defer fipstls.Abandon()
+ msg := ""
+ if !isBoringCipherSuite(id) {
+ msg = "no cipher suite supported by both client and server"
+ }
+ testClientHelloFailure(t, serverConfig, clientHello, msg)
+ })
+ })
+ }
+}
+
+func TestBoringServerCurves(t *testing.T) {
+ serverConfig := testConfig.Clone()
+ serverConfig.Certificates = make([]Certificate, 1)
+ serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+ serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
+ serverConfig.BuildNameToCertificate()
+
+ for _, curveid := range defaultCurvePreferences {
+ t.Run(fmt.Sprintf("curve=%d", curveid), func(t *testing.T) {
+ clientHello := &clientHelloMsg{
+ vers: VersionTLS12,
+ random: make([]byte, 32),
+ cipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ compressionMethods: []uint8{compressionNone},
+ supportedCurves: []CurveID{curveid},
+ supportedPoints: []uint8{pointFormatUncompressed},
+ }
+
+ testClientHello(t, serverConfig, clientHello)
+
+ // With fipstls forced, bad curves should be rejected.
+ t.Run("fipstls", func(t *testing.T) {
+ fipstls.Force()
+ defer fipstls.Abandon()
+ msg := ""
+ if !isBoringCurve(curveid) {
+ msg = "no cipher suite supported by both client and server"
+ }
+ testClientHelloFailure(t, serverConfig, clientHello, msg)
+ })
+ })
+ }
+}
+
+func boringHandshake(t *testing.T, clientConfig, serverConfig *Config) (clientErr, serverErr error) {
+ c, s := localPipe(t)
+ client := Client(c, clientConfig)
+ server := Server(s, serverConfig)
+ done := make(chan error, 1)
+ go func() {
+ done <- client.Handshake()
+ c.Close()
+ }()
+ serverErr = server.Handshake()
+ s.Close()
+ clientErr = <-done
+ return
+}
+
+func TestBoringServerSignatureAndHash(t *testing.T) {
+ defer func() {
+ testingOnlyForceClientHelloSignatureAlgorithms = nil
+ }()
+
+ for _, sigHash := range defaultSupportedSignatureAlgorithms {
+ t.Run(fmt.Sprintf("%#x", sigHash), func(t *testing.T) {
+ serverConfig := testConfig.Clone()
+ serverConfig.Certificates = make([]Certificate, 1)
+
+ testingOnlyForceClientHelloSignatureAlgorithms = []SignatureScheme{sigHash}
+
+ sigType, _, _ := typeAndHashFromSignatureScheme(sigHash)
+ switch sigType {
+ case signaturePKCS1v15, signatureRSAPSS:
+ serverConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
+ serverConfig.Certificates[0].Certificate = [][]byte{testRSA2048Certificate}
+ serverConfig.Certificates[0].PrivateKey = testRSA2048PrivateKey
+ case signatureEd25519:
+ serverConfig.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}
+ serverConfig.Certificates[0].Certificate = [][]byte{testEd25519Certificate}
+ serverConfig.Certificates[0].PrivateKey = testEd25519PrivateKey
+ case signatureECDSA:
+ serverConfig.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256}
+ serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+ serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
+ }
+ serverConfig.BuildNameToCertificate()
+ // PKCS#1 v1.5 signature algorithms can't be used standalone in TLS
+ // 1.3, and the ECDSA ones bind to the curve used.
+ serverConfig.MaxVersion = VersionTLS12
+
+ clientErr, serverErr := boringHandshake(t, testConfig, serverConfig)
+ if clientErr != nil {
+ t.Fatalf("expected handshake with %#x to succeed; client error: %v; server error: %v", sigHash, clientErr, serverErr)
+ }
+
+ // With fipstls forced, bad curves should be rejected.
+ t.Run("fipstls", func(t *testing.T) {
+ fipstls.Force()
+ defer fipstls.Abandon()
+ clientErr, _ := boringHandshake(t, testConfig, serverConfig)
+ if isBoringSignatureScheme(sigHash) {
+ if clientErr != nil {
+ t.Fatalf("expected handshake with %#x to succeed; err=%v", sigHash, clientErr)
+ }
+ } else {
+ if clientErr == nil {
+ t.Fatalf("expected handshake with %#x to fail, but it succeeded", sigHash)
+ }
+ }
+ })
+ })
+ }
+}
+
+func TestBoringClientHello(t *testing.T) {
+ // Test that no matter what we put in the client config,
+ // the client does not offer non-FIPS configurations.
+ fipstls.Force()
+ defer fipstls.Abandon()
+
+ c, s := net.Pipe()
+ defer c.Close()
+ defer s.Close()
+
+ clientConfig := testConfig.Clone()
+ // All sorts of traps for the client to avoid.
+ clientConfig.MinVersion = VersionSSL30
+ clientConfig.MaxVersion = VersionTLS13
+ clientConfig.CipherSuites = allCipherSuites()
+ clientConfig.CurvePreferences = defaultCurvePreferences
+
+ go Client(c, clientConfig).Handshake()
+ srv := Server(s, testConfig)
+ msg, err := srv.readHandshake(nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ hello, ok := msg.(*clientHelloMsg)
+ if !ok {
+ t.Fatalf("unexpected message type %T", msg)
+ }
+
+ if !isBoringVersion(hello.vers) {
+ t.Errorf("client vers=%#x, want %#x (TLS 1.2)", hello.vers, VersionTLS12)
+ }
+ for _, v := range hello.supportedVersions {
+ if !isBoringVersion(v) {
+ t.Errorf("client offered disallowed version %#x", v)
+ }
+ }
+ for _, id := range hello.cipherSuites {
+ if !isBoringCipherSuite(id) {
+ t.Errorf("client offered disallowed suite %#x", id)
+ }
+ }
+ for _, id := range hello.supportedCurves {
+ if !isBoringCurve(id) {
+ t.Errorf("client offered disallowed curve %d", id)
+ }
+ }
+ for _, sigHash := range hello.supportedSignatureAlgorithms {
+ if !isBoringSignatureScheme(sigHash) {
+ t.Errorf("client offered disallowed signature-and-hash %v", sigHash)
+ }
+ }
+}
+
+func TestBoringCertAlgs(t *testing.T) {
+ // NaCl, arm and wasm time out generating keys. Nothing in this test is architecture-specific, so just don't bother on those.
+ if runtime.GOOS == "nacl" || runtime.GOARCH == "arm" || runtime.GOOS == "js" {
+ t.Skipf("skipping on %s/%s because key generation takes too long", runtime.GOOS, runtime.GOARCH)
+ }
+
+ // Set up some roots, intermediate CAs, and leaf certs with various algorithms.
+ // X_Y is X signed by Y.
+ R1 := boringCert(t, "R1", boringRSAKey(t, 2048), nil, boringCertCA|boringCertFIPSOK)
+ R2 := boringCert(t, "R2", boringRSAKey(t, 512), nil, boringCertCA)
+
+ M1_R1 := boringCert(t, "M1_R1", boringECDSAKey(t, elliptic.P256()), R1, boringCertCA|boringCertFIPSOK)
+ M2_R1 := boringCert(t, "M2_R1", boringECDSAKey(t, elliptic.P224()), R1, boringCertCA)
+
+ I_R1 := boringCert(t, "I_R1", boringRSAKey(t, 3072), R1, boringCertCA|boringCertFIPSOK)
+ I_R2 := boringCert(t, "I_R2", I_R1.key, R2, boringCertCA|boringCertFIPSOK)
+ I_M1 := boringCert(t, "I_M1", I_R1.key, M1_R1, boringCertCA|boringCertFIPSOK)
+ I_M2 := boringCert(t, "I_M2", I_R1.key, M2_R1, boringCertCA|boringCertFIPSOK)
+
+ L1_I := boringCert(t, "L1_I", boringECDSAKey(t, elliptic.P384()), I_R1, boringCertLeaf|boringCertFIPSOK)
+ L2_I := boringCert(t, "L2_I", boringRSAKey(t, 1024), I_R1, boringCertLeaf)
+
+ // client verifying server cert
+ testServerCert := func(t *testing.T, desc string, pool *x509.CertPool, key interface{}, list [][]byte, ok bool) {
+ clientConfig := testConfig.Clone()
+ clientConfig.RootCAs = pool
+ clientConfig.InsecureSkipVerify = false
+ clientConfig.ServerName = "example.com"
+
+ serverConfig := testConfig.Clone()
+ serverConfig.Certificates = []Certificate{{Certificate: list, PrivateKey: key}}
+ serverConfig.BuildNameToCertificate()
+
+ clientErr, _ := boringHandshake(t, clientConfig, serverConfig)
+
+ if (clientErr == nil) == ok {
+ if ok {
+ t.Logf("%s: accept", desc)
+ } else {
+ t.Logf("%s: reject", desc)
+ }
+ } else {
+ if ok {
+ t.Errorf("%s: BAD reject (%v)", desc, clientErr)
+ } else {
+ t.Errorf("%s: BAD accept", desc)
+ }
+ }
+ }
+
+ // server verifying client cert
+ testClientCert := func(t *testing.T, desc string, pool *x509.CertPool, key interface{}, list [][]byte, ok bool) {
+ clientConfig := testConfig.Clone()
+ clientConfig.ServerName = "example.com"
+ clientConfig.Certificates = []Certificate{{Certificate: list, PrivateKey: key}}
+
+ serverConfig := testConfig.Clone()
+ serverConfig.ClientCAs = pool
+ serverConfig.ClientAuth = RequireAndVerifyClientCert
+
+ _, serverErr := boringHandshake(t, clientConfig, serverConfig)
+
+ if (serverErr == nil) == ok {
+ if ok {
+ t.Logf("%s: accept", desc)
+ } else {
+ t.Logf("%s: reject", desc)
+ }
+ } else {
+ if ok {
+ t.Errorf("%s: BAD reject (%v)", desc, serverErr)
+ } else {
+ t.Errorf("%s: BAD accept", desc)
+ }
+ }
+ }
+
+ // Run simple basic test with known answers before proceeding to
+ // exhaustive test with computed answers.
+ r1pool := x509.NewCertPool()
+ r1pool.AddCert(R1.cert)
+ testServerCert(t, "basic", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true)
+ testClientCert(t, "basic (client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, true)
+ fipstls.Force()
+ testServerCert(t, "basic (fips)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false)
+ testClientCert(t, "basic (fips, client cert)", r1pool, L2_I.key, [][]byte{L2_I.der, I_R1.der}, false)
+ fipstls.Abandon()
+
+ if t.Failed() {
+ t.Fatal("basic test failed, skipping exhaustive test")
+ }
+
+ if testing.Short() {
+ t.Logf("basic test passed; skipping exhaustive test in -short mode")
+ return
+ }
+
+ for l := 1; l <= 2; l++ {
+ leaf := L1_I
+ if l == 2 {
+ leaf = L2_I
+ }
+ for i := 0; i < 64; i++ {
+ reachable := map[string]bool{leaf.parentOrg: true}
+ reachableFIPS := map[string]bool{leaf.parentOrg: leaf.fipsOK}
+ list := [][]byte{leaf.der}
+ listName := leaf.name
+ addList := func(cond int, c *boringCertificate) {
+ if cond != 0 {
+ list = append(list, c.der)
+ listName += "," + c.name
+ if reachable[c.org] {
+ reachable[c.parentOrg] = true
+ }
+ if reachableFIPS[c.org] && c.fipsOK {
+ reachableFIPS[c.parentOrg] = true
+ }
+ }
+ }
+ addList(i&1, I_R1)
+ addList(i&2, I_R2)
+ addList(i&4, I_M1)
+ addList(i&8, I_M2)
+ addList(i&16, M1_R1)
+ addList(i&32, M2_R1)
+
+ for r := 1; r <= 3; r++ {
+ pool := x509.NewCertPool()
+ rootName := ","
+ shouldVerify := false
+ shouldVerifyFIPS := false
+ addRoot := func(cond int, c *boringCertificate) {
+ if cond != 0 {
+ rootName += "," + c.name
+ pool.AddCert(c.cert)
+ if reachable[c.org] {
+ shouldVerify = true
+ }
+ if reachableFIPS[c.org] && c.fipsOK {
+ shouldVerifyFIPS = true
+ }
+ }
+ }
+ addRoot(r&1, R1)
+ addRoot(r&2, R2)
+ rootName = rootName[1:] // strip leading comma
+ testServerCert(t, listName+"->"+rootName[1:], pool, leaf.key, list, shouldVerify)
+ testClientCert(t, listName+"->"+rootName[1:]+"(client cert)", pool, leaf.key, list, shouldVerify)
+ fipstls.Force()
+ testServerCert(t, listName+"->"+rootName[1:]+" (fips)", pool, leaf.key, list, shouldVerifyFIPS)
+ testClientCert(t, listName+"->"+rootName[1:]+" (fips, client cert)", pool, leaf.key, list, shouldVerifyFIPS)
+ fipstls.Abandon()
+ }
+ }
+ }
+}
+
+const (
+ boringCertCA = iota
+ boringCertLeaf
+ boringCertFIPSOK = 0x80
+)
+
+func boringRSAKey(t *testing.T, size int) *rsa.PrivateKey {
+ k, err := rsa.GenerateKey(rand.Reader, size)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return k
+}
+
+func boringECDSAKey(t *testing.T, curve elliptic.Curve) *ecdsa.PrivateKey {
+ k, err := ecdsa.GenerateKey(curve, rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return k
+}
+
+type boringCertificate struct {
+ name string
+ org string
+ parentOrg string
+ der []byte
+ cert *x509.Certificate
+ key interface{}
+ fipsOK bool
+}
+
+func boringCert(t *testing.T, name string, key interface{}, parent *boringCertificate, mode int) *boringCertificate {
+ org := name
+ parentOrg := ""
+ if i := strings.Index(org, "_"); i >= 0 {
+ org = org[:i]
+ parentOrg = name[i+1:]
+ }
+ tmpl := &x509.Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
+ Organization: []string{org},
+ },
+ NotBefore: time.Unix(0, 0),
+ NotAfter: time.Unix(0, 0),
+
+ KeyUsage: x509.KeyUsageKeyEncipherment | x509.KeyUsageDigitalSignature,
+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth, x509.ExtKeyUsageClientAuth},
+ BasicConstraintsValid: true,
+ }
+ if mode&^boringCertFIPSOK == boringCertLeaf {
+ tmpl.DNSNames = []string{"example.com"}
+ } else {
+ tmpl.IsCA = true
+ tmpl.KeyUsage |= x509.KeyUsageCertSign
+ }
+
+ var pcert *x509.Certificate
+ var pkey interface{}
+ if parent != nil {
+ pcert = parent.cert
+ pkey = parent.key
+ } else {
+ pcert = tmpl
+ pkey = key
+ }
+
+ var pub interface{}
+ switch k := key.(type) {
+ case *rsa.PrivateKey:
+ pub = &k.PublicKey
+ case *ecdsa.PrivateKey:
+ pub = &k.PublicKey
+ default:
+ t.Fatalf("invalid key %T", key)
+ }
+
+ der, err := x509.CreateCertificate(rand.Reader, tmpl, pcert, pub, pkey)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cert, err := x509.ParseCertificate(der)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ fipsOK := mode&boringCertFIPSOK != 0
+ return &boringCertificate{name, org, parentOrg, der, cert, key, fipsOK}
+}
+
+// A self-signed test certificate with an RSA key of size 2048, for testing
+// RSA-PSS with SHA512. SAN of example.golang.
+var (
+ testRSA2048Certificate []byte
+ testRSA2048PrivateKey *rsa.PrivateKey
+)
+
+func init() {
+ block, _ := pem.Decode(obscuretestdata.Rot13([]byte(`
+-----ORTVA PREGVSVPNGR-----
+ZVVP/mPPNrrtNjVONtVENYUUK/xu4+4mZH9QnemORpDjQDLWXbMVuipANDRYODNj
+RwRDZN4TN1HRPuZUDJAgMFOQomNrSj0kZGNkZQRkAGN0ZQInSj0lZQRlZwxkAGN0
+ZQInZOVkRQNBOtAIONbGO0SwoJHtD28jttRvZN0TPFdTFVo3QDRONDHNN4VOQjNj
+ttRXNbVONDPs8sx0A6vrPOK4VBIVsXvgg4xTpBDYrvzPsfwddUplfZVITRgSFZ6R
+4Nl141s/7VdqJ0HgVdAo4CKuEBVQ7lQkE284kY6KoPhi/g5uC3HpruLp3uzYvlIq
+ZxMDvMJgsHHWs/1dBgZ+buAt59YEJc4q+6vK0yn1WY3RjPVpxxAwW9uDoS7Co2PF
++RF9Lb55XNnc8XBoycpE8ZOFA38odajwsDqPKiBRBwnz2UHkXmRSK5ZN+sN0zr4P
+vbPpPEYJXy+TbA9S8sNOsbM+G+2rny4QYhB95eKE8FeBVIOu3KSBe/EIuwgKpAIS
+MXpiQg6q68I6wNXNLXz5ayw9TCcq4i+eNtZONNTwHQOBZN4TN1HqQjRO/jDRNjVS
+bQNGOtAIUFHRQQNXOtteOtRSODpQNGNZOtAIUEZONs8RNwNNZOxTN1HqRDDFZOPP
+QzI4LJ1joTHhM29fLJ5aZN0TPFdTFVo3QDROPjHNN4VONDPBbLfIpSPOuobdr3JU
+qP6I7KKKRPzawu01e8u80li0AE379aFQ3pj2Z+UXinKlfJdey5uwTIXj0igjQ81e
+I4WmQh7VsVbt5z8+DAP+7YdQMfm88iQXBefblFIBzHPtzPXSKrj+YN+rB/vDRWGe
+7rafqqBrKWRc27Rq5iJ+xzJJ3Dztyp2Tjl8jSeZQVdaeaBmON4bPaQRtgKWg0mbt
+aEjosRZNJv1nDEl5qG9XN3FC9zb5FrGSFmTTUvR4f4tUHr7wifNSS2dtgQ6+jU6f
+m9o6fukaP7t5VyOXuV7FIO/Hdg2lqW+xU1LowZpVd6ANZ5rAZXtMhWe3+mjfFtju
+TAnR
+-----RAQ PREGVSVPNGR-----`)))
+ testRSA2048Certificate = block.Bytes
+
+ block, _ = pem.Decode(obscuretestdata.Rot13([]byte(`
+-----ORTVA EFN CEVINGR XRL-----
+ZVVRcNVONNXPNDRNa/U5AQrbattI+PQyFUlbeorWOaQxP3bcta7V6du3ZeQPSEuY
+EHwBuBNZgrAK/+lXaIgSYFXwJ+Q14HGvN+8t8HqiBZF+y2jee/7rLG91UUbJUA4M
+v4fyKGWTHVzIeK1SPK/9nweGCdVGLBsF0IdrUshby9WJgFF9kZNvUWWQLlsLHTkr
+m29txiuRiJXBrFtTdsPwz5nKRsQNHwq/T6c8V30UDy7muQb2cgu1ZFfkOI+GNCaj
+AWahNbdNaNxF1vcsudQsEsUjNK6Tsx/gazcrNl7wirn10sRdmvSDLq1kGd/0ILL7
+I3QIEJFaYj7rariSrbjPtTPchM5L/Ew6KrY/djVQNDNONbVONDPAcZMvsq/it42u
+UqPiYhMnLF0E7FhaSycbKRfygTqYSfac0VsbWM/htSDOFNVVsYjZhzH6bKN1m7Hi
+98nVLI61QrCeGPQIQSOfUoAzC8WNb8JgohfRojq5mlbO7YLT2+pyxWxyJR73XdHd
+ezV+HWrlFpy2Tva7MGkOKm1JCOx9IjpajxrnKctNFVOJ23suRPZ9taLRRjnOrm5G
+6Zr8q1gUgLDi7ifXr7eb9j9/UXeEKrwdLXX1YkxusSevlI+z8YMWMa2aKBn6T3tS
+Ao8Dx1Hx5CHORAOzlZSWuG4Z/hhFd4LgZeeB2tv8D+sCuhTmp5FfuLXEOc0J4C5e
+zgIPgRSENbTONZRAOVSYeI2+UfTw0kLSnfXbi/DCr6UFGE1Uu2VMBAc+bX4bfmJR
+wOG4IpaVGzcy6gP1Jl4TpekwAtXVSMNw+1k1YHHYqbeKxhT8le0gNuT9mAlsJfFl
+CeFbiP0HIome8Wkkyn+xDIkRDDdJDkCyRIhY8xKnVQN6Ylg1Uchn2YiCNbTONADM
+p6Yd2G7+OkYkAqv2z8xMmrw5xtmOc/KqIfoSJEyroVK2XeSUfeUmG9CHx3QR1iMX
+Z6cmGg94aDuJFxQtPnj1FbuRyW3USVSjphfS1FWNp3cDrcq8ht6VLqycQZYgOw/C
+/5C6OIHgtb05R4+V/G3vLngztyDkGgyM0ExFI2yyNbTONYBKxXSK7nuCis0JxfQu
+hGshSBGCbbjtDT0RctJ0jEqPkrt/WYvp3yFQ0tfggDI2JfErpelJpknryEt10EzB
+38OobtzunS4kitfFihwBsvMGR8bX1G43Z+6AXfVyZY3LVYocH/9nWkCJl0f2QdQe
+pDWuMeyx+cmwON7Oas/HEqjkNbTNXE/PAj14Q+zeY3LYoovPKvlqdkIjki5cqMqm
+8guv3GApfJP4vTHEqpIdosHvaICqWvKr/Xnp3JTPrEWnSItoXNBkYgv1EO5ZxVut
+Q8rlhcOdx4J1Y1txekdfqw4GSykxjZljwy2R2F4LlD8COg6I04QbIEMfVXmdm+CS
+HvbaCd0PtLOPLKidvbWuCrjxBd/L5jeQOrMJ1SDX5DQ9J5Z8/5mkq4eqiWgwuoWc
+bBegiZqey6hcl9Um4OWQ3SKjISvCSR7wdrAdv0S21ivYkOCZZQ3HBQS6YY5RlYvE
+9I4kIZF8XKkit7ekfhdmZCfpIvnJHY6JAIOufQ2+92qUkFKmm5RWXD==
+-----RAQ EFN CEVINGR XRL-----`)))
+ var err error
+ testRSA2048PrivateKey, err = x509.ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ panic(err)
+ }
+}
diff --git a/src/crypto/tls/cache.go b/src/crypto/tls/cache.go
new file mode 100644
index 0000000..fc8f2c0
--- /dev/null
+++ b/src/crypto/tls/cache.go
@@ -0,0 +1,95 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "crypto/x509"
+ "runtime"
+ "sync"
+ "sync/atomic"
+)
+
+type cacheEntry struct {
+ refs atomic.Int64
+ cert *x509.Certificate
+}
+
+// certCache implements an intern table for reference counted x509.Certificates,
+// implemented in a similar fashion to BoringSSL's CRYPTO_BUFFER_POOL. This
+// allows for a single x509.Certificate to be kept in memory and referenced from
+// multiple Conns. Returned references should not be mutated by callers. Certificates
+// are still safe to use after they are removed from the cache.
+//
+// Certificates are returned wrapped in a activeCert struct that should be held by
+// the caller. When references to the activeCert are freed, the number of references
+// to the certificate in the cache is decremented. Once the number of references
+// reaches zero, the entry is evicted from the cache.
+//
+// The main difference between this implementation and CRYPTO_BUFFER_POOL is that
+// CRYPTO_BUFFER_POOL is a more generic structure which supports blobs of data,
+// rather than specific structures. Since we only care about x509.Certificates,
+// certCache is implemented as a specific cache, rather than a generic one.
+//
+// See https://boringssl.googlesource.com/boringssl/+/master/include/openssl/pool.h
+// and https://boringssl.googlesource.com/boringssl/+/master/crypto/pool/pool.c
+// for the BoringSSL reference.
+type certCache struct {
+ sync.Map
+}
+
+var clientCertCache = new(certCache)
+
+// activeCert is a handle to a certificate held in the cache. Once there are
+// no alive activeCerts for a given certificate, the certificate is removed
+// from the cache by a finalizer.
+type activeCert struct {
+ cert *x509.Certificate
+}
+
+// active increments the number of references to the entry, wraps the
+// certificate in the entry in a activeCert, and sets the finalizer.
+//
+// Note that there is a race between active and the finalizer set on the
+// returned activeCert, triggered if active is called after the ref count is
+// decremented such that refs may be > 0 when evict is called. We consider this
+// safe, since the caller holding an activeCert for an entry that is no longer
+// in the cache is fine, with the only side effect being the memory overhead of
+// there being more than one distinct reference to a certificate alive at once.
+func (cc *certCache) active(e *cacheEntry) *activeCert {
+ e.refs.Add(1)
+ a := &activeCert{e.cert}
+ runtime.SetFinalizer(a, func(_ *activeCert) {
+ if e.refs.Add(-1) == 0 {
+ cc.evict(e)
+ }
+ })
+ return a
+}
+
+// evict removes a cacheEntry from the cache.
+func (cc *certCache) evict(e *cacheEntry) {
+ cc.Delete(string(e.cert.Raw))
+}
+
+// newCert returns a x509.Certificate parsed from der. If there is already a copy
+// of the certificate in the cache, a reference to the existing certificate will
+// be returned. Otherwise, a fresh certificate will be added to the cache, and
+// the reference returned. The returned reference should not be mutated.
+func (cc *certCache) newCert(der []byte) (*activeCert, error) {
+ if entry, ok := cc.Load(string(der)); ok {
+ return cc.active(entry.(*cacheEntry)), nil
+ }
+
+ cert, err := x509.ParseCertificate(der)
+ if err != nil {
+ return nil, err
+ }
+
+ entry := &cacheEntry{cert: cert}
+ if entry, loaded := cc.LoadOrStore(string(der), entry); loaded {
+ return cc.active(entry.(*cacheEntry)), nil
+ }
+ return cc.active(entry), nil
+}
diff --git a/src/crypto/tls/cache_test.go b/src/crypto/tls/cache_test.go
new file mode 100644
index 0000000..2846734
--- /dev/null
+++ b/src/crypto/tls/cache_test.go
@@ -0,0 +1,117 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "encoding/pem"
+ "fmt"
+ "runtime"
+ "testing"
+ "time"
+)
+
+func TestCertCache(t *testing.T) {
+ cc := certCache{}
+ p, _ := pem.Decode([]byte(rsaCertPEM))
+ if p == nil {
+ t.Fatal("Failed to decode certificate")
+ }
+
+ certA, err := cc.newCert(p.Bytes)
+ if err != nil {
+ t.Fatalf("newCert failed: %s", err)
+ }
+ certB, err := cc.newCert(p.Bytes)
+ if err != nil {
+ t.Fatalf("newCert failed: %s", err)
+ }
+ if certA.cert != certB.cert {
+ t.Fatal("newCert returned a unique reference for a duplicate certificate")
+ }
+
+ if entry, ok := cc.Load(string(p.Bytes)); !ok {
+ t.Fatal("cache does not contain expected entry")
+ } else {
+ if refs := entry.(*cacheEntry).refs.Load(); refs != 2 {
+ t.Fatalf("unexpected number of references: got %d, want 2", refs)
+ }
+ }
+
+ timeoutRefCheck := func(t *testing.T, key string, count int64) {
+ t.Helper()
+ c := time.After(4 * time.Second)
+ for {
+ select {
+ case <-c:
+ t.Fatal("timed out waiting for expected ref count")
+ default:
+ e, ok := cc.Load(key)
+ if !ok && count != 0 {
+ t.Fatal("cache does not contain expected key")
+ } else if count == 0 && !ok {
+ return
+ }
+
+ if e.(*cacheEntry).refs.Load() == count {
+ return
+ }
+ }
+ }
+ }
+
+ // Keep certA alive until at least now, so that we can
+ // purposefully nil it and force the finalizer to be
+ // called.
+ runtime.KeepAlive(certA)
+ certA = nil
+ runtime.GC()
+
+ timeoutRefCheck(t, string(p.Bytes), 1)
+
+ // Keep certB alive until at least now, so that we can
+ // purposefully nil it and force the finalizer to be
+ // called.
+ runtime.KeepAlive(certB)
+ certB = nil
+ runtime.GC()
+
+ timeoutRefCheck(t, string(p.Bytes), 0)
+}
+
+func BenchmarkCertCache(b *testing.B) {
+ p, _ := pem.Decode([]byte(rsaCertPEM))
+ if p == nil {
+ b.Fatal("Failed to decode certificate")
+ }
+
+ cc := certCache{}
+ b.ReportAllocs()
+ b.ResetTimer()
+ // We expect that calling newCert additional times after
+ // the initial call should not cause additional allocations.
+ for extra := 0; extra < 4; extra++ {
+ b.Run(fmt.Sprint(extra), func(b *testing.B) {
+ actives := make([]*activeCert, extra+1)
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ var err error
+ actives[0], err = cc.newCert(p.Bytes)
+ if err != nil {
+ b.Fatal(err)
+ }
+ for j := 0; j < extra; j++ {
+ actives[j+1], err = cc.newCert(p.Bytes)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+ for j := 0; j < extra+1; j++ {
+ actives[j] = nil
+ }
+ runtime.GC()
+ }
+ })
+ }
+}
diff --git a/src/crypto/tls/cipher_suites.go b/src/crypto/tls/cipher_suites.go
new file mode 100644
index 0000000..04e6dfe
--- /dev/null
+++ b/src/crypto/tls/cipher_suites.go
@@ -0,0 +1,702 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "crypto"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/des"
+ "crypto/hmac"
+ "crypto/internal/boring"
+ "crypto/rc4"
+ "crypto/sha1"
+ "crypto/sha256"
+ "fmt"
+ "hash"
+ "internal/cpu"
+ "runtime"
+
+ "golang.org/x/crypto/chacha20poly1305"
+)
+
+// CipherSuite is a TLS cipher suite. Note that most functions in this package
+// accept and expose cipher suite IDs instead of this type.
+type CipherSuite struct {
+ ID uint16
+ Name string
+
+ // Supported versions is the list of TLS protocol versions that can
+ // negotiate this cipher suite.
+ SupportedVersions []uint16
+
+ // Insecure is true if the cipher suite has known security issues
+ // due to its primitives, design, or implementation.
+ Insecure bool
+}
+
+var (
+ supportedUpToTLS12 = []uint16{VersionTLS10, VersionTLS11, VersionTLS12}
+ supportedOnlyTLS12 = []uint16{VersionTLS12}
+ supportedOnlyTLS13 = []uint16{VersionTLS13}
+)
+
+// CipherSuites returns a list of cipher suites currently implemented by this
+// package, excluding those with security issues, which are returned by
+// InsecureCipherSuites.
+//
+// The list is sorted by ID. Note that the default cipher suites selected by
+// this package might depend on logic that can't be captured by a static list,
+// and might not match those returned by this function.
+func CipherSuites() []*CipherSuite {
+ return []*CipherSuite{
+ {TLS_RSA_WITH_AES_128_CBC_SHA, "TLS_RSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false},
+ {TLS_RSA_WITH_AES_256_CBC_SHA, "TLS_RSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false},
+ {TLS_RSA_WITH_AES_128_GCM_SHA256, "TLS_RSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false},
+ {TLS_RSA_WITH_AES_256_GCM_SHA384, "TLS_RSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false},
+
+ {TLS_AES_128_GCM_SHA256, "TLS_AES_128_GCM_SHA256", supportedOnlyTLS13, false},
+ {TLS_AES_256_GCM_SHA384, "TLS_AES_256_GCM_SHA384", supportedOnlyTLS13, false},
+ {TLS_CHACHA20_POLY1305_SHA256, "TLS_CHACHA20_POLY1305_SHA256", supportedOnlyTLS13, false},
+
+ {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false},
+ {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false},
+ {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA", supportedUpToTLS12, false},
+ {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, "TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA", supportedUpToTLS12, false},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false},
+ {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false},
+ {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256", supportedOnlyTLS12, false},
+ {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, "TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384", supportedOnlyTLS12, false},
+ {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256, "TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256", supportedOnlyTLS12, false},
+ {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256, "TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256", supportedOnlyTLS12, false},
+ }
+}
+
+// InsecureCipherSuites returns a list of cipher suites currently implemented by
+// this package and which have security issues.
+//
+// Most applications should not use the cipher suites in this list, and should
+// only use those returned by CipherSuites.
+func InsecureCipherSuites() []*CipherSuite {
+ // This list includes RC4, CBC_SHA256, and 3DES cipher suites. See
+ // cipherSuitesPreferenceOrder for details.
+ return []*CipherSuite{
+ {TLS_RSA_WITH_RC4_128_SHA, "TLS_RSA_WITH_RC4_128_SHA", supportedUpToTLS12, true},
+ {TLS_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_RSA_WITH_3DES_EDE_CBC_SHA", supportedUpToTLS12, true},
+ {TLS_RSA_WITH_AES_128_CBC_SHA256, "TLS_RSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true},
+ {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, "TLS_ECDHE_ECDSA_WITH_RC4_128_SHA", supportedUpToTLS12, true},
+ {TLS_ECDHE_RSA_WITH_RC4_128_SHA, "TLS_ECDHE_RSA_WITH_RC4_128_SHA", supportedUpToTLS12, true},
+ {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, "TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA", supportedUpToTLS12, true},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true},
+ {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, "TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256", supportedOnlyTLS12, true},
+ }
+}
+
+// CipherSuiteName returns the standard name for the passed cipher suite ID
+// (e.g. "TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256"), or a fallback representation
+// of the ID value if the cipher suite is not implemented by this package.
+func CipherSuiteName(id uint16) string {
+ for _, c := range CipherSuites() {
+ if c.ID == id {
+ return c.Name
+ }
+ }
+ for _, c := range InsecureCipherSuites() {
+ if c.ID == id {
+ return c.Name
+ }
+ }
+ return fmt.Sprintf("0x%04X", id)
+}
+
+const (
+ // suiteECDHE indicates that the cipher suite involves elliptic curve
+ // Diffie-Hellman. This means that it should only be selected when the
+ // client indicates that it supports ECC with a curve and point format
+ // that we're happy with.
+ suiteECDHE = 1 << iota
+ // suiteECSign indicates that the cipher suite involves an ECDSA or
+ // EdDSA signature and therefore may only be selected when the server's
+ // certificate is ECDSA or EdDSA. If this is not set then the cipher suite
+ // is RSA based.
+ suiteECSign
+ // suiteTLS12 indicates that the cipher suite should only be advertised
+ // and accepted when using TLS 1.2.
+ suiteTLS12
+ // suiteSHA384 indicates that the cipher suite uses SHA384 as the
+ // handshake hash.
+ suiteSHA384
+)
+
+// A cipherSuite is a TLS 1.0–1.2 cipher suite, and defines the key exchange
+// mechanism, as well as the cipher+MAC pair or the AEAD.
+type cipherSuite struct {
+ id uint16
+ // the lengths, in bytes, of the key material needed for each component.
+ keyLen int
+ macLen int
+ ivLen int
+ ka func(version uint16) keyAgreement
+ // flags is a bitmask of the suite* values, above.
+ flags int
+ cipher func(key, iv []byte, isRead bool) any
+ mac func(key []byte) hash.Hash
+ aead func(key, fixedNonce []byte) aead
+}
+
+var cipherSuites = []*cipherSuite{ // TODO: replace with a map, since the order doesn't matter.
+ {TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
+ {TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, 32, 0, 12, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadChaCha20Poly1305},
+ {TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12, nil, nil, aeadAESGCM},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, nil, nil, aeadAESGCM},
+ {TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheRSAKA, suiteECDHE | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+ {TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+ {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheRSAKA, suiteECDHE | suiteTLS12, cipherAES, macSHA256, nil},
+ {TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, ecdheECDSAKA, suiteECDHE | suiteECSign | suiteTLS12, cipherAES, macSHA256, nil},
+ {TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, 16, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherAES, macSHA1, nil},
+ {TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheRSAKA, suiteECDHE, cipherAES, macSHA1, nil},
+ {TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, 32, 20, 16, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherAES, macSHA1, nil},
+ {TLS_RSA_WITH_AES_128_GCM_SHA256, 16, 0, 4, rsaKA, suiteTLS12, nil, nil, aeadAESGCM},
+ {TLS_RSA_WITH_AES_256_GCM_SHA384, 32, 0, 4, rsaKA, suiteTLS12 | suiteSHA384, nil, nil, aeadAESGCM},
+ {TLS_RSA_WITH_AES_128_CBC_SHA256, 16, 32, 16, rsaKA, suiteTLS12, cipherAES, macSHA256, nil},
+ {TLS_RSA_WITH_AES_128_CBC_SHA, 16, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
+ {TLS_RSA_WITH_AES_256_CBC_SHA, 32, 20, 16, rsaKA, 0, cipherAES, macSHA1, nil},
+ {TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, ecdheRSAKA, suiteECDHE, cipher3DES, macSHA1, nil},
+ {TLS_RSA_WITH_3DES_EDE_CBC_SHA, 24, 20, 8, rsaKA, 0, cipher3DES, macSHA1, nil},
+ {TLS_RSA_WITH_RC4_128_SHA, 16, 20, 0, rsaKA, 0, cipherRC4, macSHA1, nil},
+ {TLS_ECDHE_RSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheRSAKA, suiteECDHE, cipherRC4, macSHA1, nil},
+ {TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, 16, 20, 0, ecdheECDSAKA, suiteECDHE | suiteECSign, cipherRC4, macSHA1, nil},
+}
+
+// selectCipherSuite returns the first TLS 1.0–1.2 cipher suite from ids which
+// is also in supportedIDs and passes the ok filter.
+func selectCipherSuite(ids, supportedIDs []uint16, ok func(*cipherSuite) bool) *cipherSuite {
+ for _, id := range ids {
+ candidate := cipherSuiteByID(id)
+ if candidate == nil || !ok(candidate) {
+ continue
+ }
+
+ for _, suppID := range supportedIDs {
+ if id == suppID {
+ return candidate
+ }
+ }
+ }
+ return nil
+}
+
+// A cipherSuiteTLS13 defines only the pair of the AEAD algorithm and hash
+// algorithm to be used with HKDF. See RFC 8446, Appendix B.4.
+type cipherSuiteTLS13 struct {
+ id uint16
+ keyLen int
+ aead func(key, fixedNonce []byte) aead
+ hash crypto.Hash
+}
+
+var cipherSuitesTLS13 = []*cipherSuiteTLS13{ // TODO: replace with a map.
+ {TLS_AES_128_GCM_SHA256, 16, aeadAESGCMTLS13, crypto.SHA256},
+ {TLS_CHACHA20_POLY1305_SHA256, 32, aeadChaCha20Poly1305, crypto.SHA256},
+ {TLS_AES_256_GCM_SHA384, 32, aeadAESGCMTLS13, crypto.SHA384},
+}
+
+// cipherSuitesPreferenceOrder is the order in which we'll select (on the
+// server) or advertise (on the client) TLS 1.0–1.2 cipher suites.
+//
+// Cipher suites are filtered but not reordered based on the application and
+// peer's preferences, meaning we'll never select a suite lower in this list if
+// any higher one is available. This makes it more defensible to keep weaker
+// cipher suites enabled, especially on the server side where we get the last
+// word, since there are no known downgrade attacks on cipher suites selection.
+//
+// The list is sorted by applying the following priority rules, stopping at the
+// first (most important) applicable one:
+//
+// - Anything else comes before RC4
+//
+// RC4 has practically exploitable biases. See https://www.rc4nomore.com.
+//
+// - Anything else comes before CBC_SHA256
+//
+// SHA-256 variants of the CBC ciphersuites don't implement any Lucky13
+// countermeasures. See http://www.isg.rhul.ac.uk/tls/Lucky13.html and
+// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.
+//
+// - Anything else comes before 3DES
+//
+// 3DES has 64-bit blocks, which makes it fundamentally susceptible to
+// birthday attacks. See https://sweet32.info.
+//
+// - ECDHE comes before anything else
+//
+// Once we got the broken stuff out of the way, the most important
+// property a cipher suite can have is forward secrecy. We don't
+// implement FFDHE, so that means ECDHE.
+//
+// - AEADs come before CBC ciphers
+//
+// Even with Lucky13 countermeasures, MAC-then-Encrypt CBC cipher suites
+// are fundamentally fragile, and suffered from an endless sequence of
+// padding oracle attacks. See https://eprint.iacr.org/2015/1129,
+// https://www.imperialviolet.org/2014/12/08/poodleagain.html, and
+// https://blog.cloudflare.com/yet-another-padding-oracle-in-openssl-cbc-ciphersuites/.
+//
+// - AES comes before ChaCha20
+//
+// When AES hardware is available, AES-128-GCM and AES-256-GCM are faster
+// than ChaCha20Poly1305.
+//
+// When AES hardware is not available, AES-128-GCM is one or more of: much
+// slower, way more complex, and less safe (because not constant time)
+// than ChaCha20Poly1305.
+//
+// We use this list if we think both peers have AES hardware, and
+// cipherSuitesPreferenceOrderNoAES otherwise.
+//
+// - AES-128 comes before AES-256
+//
+// The only potential advantages of AES-256 are better multi-target
+// margins, and hypothetical post-quantum properties. Neither apply to
+// TLS, and AES-256 is slower due to its four extra rounds (which don't
+// contribute to the advantages above).
+//
+// - ECDSA comes before RSA
+//
+// The relative order of ECDSA and RSA cipher suites doesn't matter,
+// as they depend on the certificate. Pick one to get a stable order.
+var cipherSuitesPreferenceOrder = []uint16{
+ // AEADs w/ ECDHE
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+
+ // CBC w/ ECDHE
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+
+ // AEADs w/o ECDHE
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+
+ // CBC w/o ECDHE
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+
+ // 3DES
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+
+ // CBC_SHA256
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_RSA_WITH_AES_128_CBC_SHA256,
+
+ // RC4
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ TLS_RSA_WITH_RC4_128_SHA,
+}
+
+var cipherSuitesPreferenceOrderNoAES = []uint16{
+ // ChaCha20Poly1305
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+
+ // AES-GCM w/ ECDHE
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384, TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+
+ // The rest of cipherSuitesPreferenceOrder.
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA, TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ TLS_RSA_WITH_RC4_128_SHA,
+}
+
+// disabledCipherSuites are not used unless explicitly listed in
+// Config.CipherSuites. They MUST be at the end of cipherSuitesPreferenceOrder.
+var disabledCipherSuites = []uint16{
+ // CBC_SHA256
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256, TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_RSA_WITH_AES_128_CBC_SHA256,
+
+ // RC4
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ TLS_RSA_WITH_RC4_128_SHA,
+}
+
+var (
+ defaultCipherSuitesLen = len(cipherSuitesPreferenceOrder) - len(disabledCipherSuites)
+ defaultCipherSuites = cipherSuitesPreferenceOrder[:defaultCipherSuitesLen]
+)
+
+// defaultCipherSuitesTLS13 is also the preference order, since there are no
+// disabled by default TLS 1.3 cipher suites. The same AES vs ChaCha20 logic as
+// cipherSuitesPreferenceOrder applies.
+var defaultCipherSuitesTLS13 = []uint16{
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+ TLS_CHACHA20_POLY1305_SHA256,
+}
+
+var defaultCipherSuitesTLS13NoAES = []uint16{
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_AES_128_GCM_SHA256,
+ TLS_AES_256_GCM_SHA384,
+}
+
+var (
+ hasGCMAsmAMD64 = cpu.X86.HasAES && cpu.X86.HasPCLMULQDQ
+ hasGCMAsmARM64 = cpu.ARM64.HasAES && cpu.ARM64.HasPMULL
+ // Keep in sync with crypto/aes/cipher_s390x.go.
+ hasGCMAsmS390X = cpu.S390X.HasAES && cpu.S390X.HasAESCBC && cpu.S390X.HasAESCTR &&
+ (cpu.S390X.HasGHASH || cpu.S390X.HasAESGCM)
+
+ hasAESGCMHardwareSupport = runtime.GOARCH == "amd64" && hasGCMAsmAMD64 ||
+ runtime.GOARCH == "arm64" && hasGCMAsmARM64 ||
+ runtime.GOARCH == "s390x" && hasGCMAsmS390X
+)
+
+var aesgcmCiphers = map[uint16]bool{
+ // TLS 1.2
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256: true,
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384: true,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256: true,
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384: true,
+ // TLS 1.3
+ TLS_AES_128_GCM_SHA256: true,
+ TLS_AES_256_GCM_SHA384: true,
+}
+
+var nonAESGCMAEADCiphers = map[uint16]bool{
+ // TLS 1.2
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305: true,
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305: true,
+ // TLS 1.3
+ TLS_CHACHA20_POLY1305_SHA256: true,
+}
+
+// aesgcmPreferred returns whether the first known cipher in the preference list
+// is an AES-GCM cipher, implying the peer has hardware support for it.
+func aesgcmPreferred(ciphers []uint16) bool {
+ for _, cID := range ciphers {
+ if c := cipherSuiteByID(cID); c != nil {
+ return aesgcmCiphers[cID]
+ }
+ if c := cipherSuiteTLS13ByID(cID); c != nil {
+ return aesgcmCiphers[cID]
+ }
+ }
+ return false
+}
+
+func cipherRC4(key, iv []byte, isRead bool) any {
+ cipher, _ := rc4.NewCipher(key)
+ return cipher
+}
+
+func cipher3DES(key, iv []byte, isRead bool) any {
+ block, _ := des.NewTripleDESCipher(key)
+ if isRead {
+ return cipher.NewCBCDecrypter(block, iv)
+ }
+ return cipher.NewCBCEncrypter(block, iv)
+}
+
+func cipherAES(key, iv []byte, isRead bool) any {
+ block, _ := aes.NewCipher(key)
+ if isRead {
+ return cipher.NewCBCDecrypter(block, iv)
+ }
+ return cipher.NewCBCEncrypter(block, iv)
+}
+
+// macSHA1 returns a SHA-1 based constant time MAC.
+func macSHA1(key []byte) hash.Hash {
+ h := sha1.New
+ // The BoringCrypto SHA1 does not have a constant-time
+ // checksum function, so don't try to use it.
+ if !boring.Enabled {
+ h = newConstantTimeHash(h)
+ }
+ return hmac.New(h, key)
+}
+
+// macSHA256 returns a SHA-256 based MAC. This is only supported in TLS 1.2 and
+// is currently only used in disabled-by-default cipher suites.
+func macSHA256(key []byte) hash.Hash {
+ return hmac.New(sha256.New, key)
+}
+
+type aead interface {
+ cipher.AEAD
+
+ // explicitNonceLen returns the number of bytes of explicit nonce
+ // included in each record. This is eight for older AEADs and
+ // zero for modern ones.
+ explicitNonceLen() int
+}
+
+const (
+ aeadNonceLength = 12
+ noncePrefixLength = 4
+)
+
+// prefixNonceAEAD wraps an AEAD and prefixes a fixed portion of the nonce to
+// each call.
+type prefixNonceAEAD struct {
+ // nonce contains the fixed part of the nonce in the first four bytes.
+ nonce [aeadNonceLength]byte
+ aead cipher.AEAD
+}
+
+func (f *prefixNonceAEAD) NonceSize() int { return aeadNonceLength - noncePrefixLength }
+func (f *prefixNonceAEAD) Overhead() int { return f.aead.Overhead() }
+func (f *prefixNonceAEAD) explicitNonceLen() int { return f.NonceSize() }
+
+func (f *prefixNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
+ copy(f.nonce[4:], nonce)
+ return f.aead.Seal(out, f.nonce[:], plaintext, additionalData)
+}
+
+func (f *prefixNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ copy(f.nonce[4:], nonce)
+ return f.aead.Open(out, f.nonce[:], ciphertext, additionalData)
+}
+
+// xorNonceAEAD wraps an AEAD by XORing in a fixed pattern to the nonce
+// before each call.
+type xorNonceAEAD struct {
+ nonceMask [aeadNonceLength]byte
+ aead cipher.AEAD
+}
+
+func (f *xorNonceAEAD) NonceSize() int { return 8 } // 64-bit sequence number
+func (f *xorNonceAEAD) Overhead() int { return f.aead.Overhead() }
+func (f *xorNonceAEAD) explicitNonceLen() int { return 0 }
+
+func (f *xorNonceAEAD) Seal(out, nonce, plaintext, additionalData []byte) []byte {
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+ result := f.aead.Seal(out, f.nonceMask[:], plaintext, additionalData)
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+
+ return result
+}
+
+func (f *xorNonceAEAD) Open(out, nonce, ciphertext, additionalData []byte) ([]byte, error) {
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+ result, err := f.aead.Open(out, f.nonceMask[:], ciphertext, additionalData)
+ for i, b := range nonce {
+ f.nonceMask[4+i] ^= b
+ }
+
+ return result, err
+}
+
+func aeadAESGCM(key, noncePrefix []byte) aead {
+ if len(noncePrefix) != noncePrefixLength {
+ panic("tls: internal error: wrong nonce length")
+ }
+ aes, err := aes.NewCipher(key)
+ if err != nil {
+ panic(err)
+ }
+ var aead cipher.AEAD
+ if boring.Enabled {
+ aead, err = boring.NewGCMTLS(aes)
+ } else {
+ boring.Unreachable()
+ aead, err = cipher.NewGCM(aes)
+ }
+ if err != nil {
+ panic(err)
+ }
+
+ ret := &prefixNonceAEAD{aead: aead}
+ copy(ret.nonce[:], noncePrefix)
+ return ret
+}
+
+func aeadAESGCMTLS13(key, nonceMask []byte) aead {
+ if len(nonceMask) != aeadNonceLength {
+ panic("tls: internal error: wrong nonce length")
+ }
+ aes, err := aes.NewCipher(key)
+ if err != nil {
+ panic(err)
+ }
+ aead, err := cipher.NewGCM(aes)
+ if err != nil {
+ panic(err)
+ }
+
+ ret := &xorNonceAEAD{aead: aead}
+ copy(ret.nonceMask[:], nonceMask)
+ return ret
+}
+
+func aeadChaCha20Poly1305(key, nonceMask []byte) aead {
+ if len(nonceMask) != aeadNonceLength {
+ panic("tls: internal error: wrong nonce length")
+ }
+ aead, err := chacha20poly1305.New(key)
+ if err != nil {
+ panic(err)
+ }
+
+ ret := &xorNonceAEAD{aead: aead}
+ copy(ret.nonceMask[:], nonceMask)
+ return ret
+}
+
+type constantTimeHash interface {
+ hash.Hash
+ ConstantTimeSum(b []byte) []byte
+}
+
+// cthWrapper wraps any hash.Hash that implements ConstantTimeSum, and replaces
+// with that all calls to Sum. It's used to obtain a ConstantTimeSum-based HMAC.
+type cthWrapper struct {
+ h constantTimeHash
+}
+
+func (c *cthWrapper) Size() int { return c.h.Size() }
+func (c *cthWrapper) BlockSize() int { return c.h.BlockSize() }
+func (c *cthWrapper) Reset() { c.h.Reset() }
+func (c *cthWrapper) Write(p []byte) (int, error) { return c.h.Write(p) }
+func (c *cthWrapper) Sum(b []byte) []byte { return c.h.ConstantTimeSum(b) }
+
+func newConstantTimeHash(h func() hash.Hash) func() hash.Hash {
+ boring.Unreachable()
+ return func() hash.Hash {
+ return &cthWrapper{h().(constantTimeHash)}
+ }
+}
+
+// tls10MAC implements the TLS 1.0 MAC function. RFC 2246, Section 6.2.3.
+func tls10MAC(h hash.Hash, out, seq, header, data, extra []byte) []byte {
+ h.Reset()
+ h.Write(seq)
+ h.Write(header)
+ h.Write(data)
+ res := h.Sum(out)
+ if extra != nil {
+ h.Write(extra)
+ }
+ return res
+}
+
+func rsaKA(version uint16) keyAgreement {
+ return rsaKeyAgreement{}
+}
+
+func ecdheECDSAKA(version uint16) keyAgreement {
+ return &ecdheKeyAgreement{
+ isRSA: false,
+ version: version,
+ }
+}
+
+func ecdheRSAKA(version uint16) keyAgreement {
+ return &ecdheKeyAgreement{
+ isRSA: true,
+ version: version,
+ }
+}
+
+// mutualCipherSuite returns a cipherSuite given a list of supported
+// ciphersuites and the id requested by the peer.
+func mutualCipherSuite(have []uint16, want uint16) *cipherSuite {
+ for _, id := range have {
+ if id == want {
+ return cipherSuiteByID(id)
+ }
+ }
+ return nil
+}
+
+func cipherSuiteByID(id uint16) *cipherSuite {
+ for _, cipherSuite := range cipherSuites {
+ if cipherSuite.id == id {
+ return cipherSuite
+ }
+ }
+ return nil
+}
+
+func mutualCipherSuiteTLS13(have []uint16, want uint16) *cipherSuiteTLS13 {
+ for _, id := range have {
+ if id == want {
+ return cipherSuiteTLS13ByID(id)
+ }
+ }
+ return nil
+}
+
+func cipherSuiteTLS13ByID(id uint16) *cipherSuiteTLS13 {
+ for _, cipherSuite := range cipherSuitesTLS13 {
+ if cipherSuite.id == id {
+ return cipherSuite
+ }
+ }
+ return nil
+}
+
+// A list of cipher suite IDs that are, or have been, implemented by this
+// package.
+//
+// See https://www.iana.org/assignments/tls-parameters/tls-parameters.xml
+const (
+ // TLS 1.0 - 1.2 cipher suites.
+ TLS_RSA_WITH_RC4_128_SHA uint16 = 0x0005
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0x000a
+ TLS_RSA_WITH_AES_128_CBC_SHA uint16 = 0x002f
+ TLS_RSA_WITH_AES_256_CBC_SHA uint16 = 0x0035
+ TLS_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0x003c
+ TLS_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0x009c
+ TLS_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0x009d
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA uint16 = 0xc007
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA uint16 = 0xc009
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA uint16 = 0xc00a
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA uint16 = 0xc011
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA uint16 = 0xc012
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA uint16 = 0xc013
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA uint16 = 0xc014
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc023
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256 uint16 = 0xc027
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02f
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256 uint16 = 0xc02b
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc030
+ TLS_ECDHE_ECDSA_WITH_AES_256_GCM_SHA384 uint16 = 0xc02c
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcca8
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256 uint16 = 0xcca9
+
+ // TLS 1.3 cipher suites.
+ TLS_AES_128_GCM_SHA256 uint16 = 0x1301
+ TLS_AES_256_GCM_SHA384 uint16 = 0x1302
+ TLS_CHACHA20_POLY1305_SHA256 uint16 = 0x1303
+
+ // TLS_FALLBACK_SCSV isn't a standard cipher suite but an indicator
+ // that the client is doing version fallback. See RFC 7507.
+ TLS_FALLBACK_SCSV uint16 = 0x5600
+
+ // Legacy names for the corresponding cipher suites with the correct _SHA256
+ // suffix, retained for backward compatibility.
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305 = TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256
+ TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305 = TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305_SHA256
+)
diff --git a/src/crypto/tls/common.go b/src/crypto/tls/common.go
new file mode 100644
index 0000000..5394d64
--- /dev/null
+++ b/src/crypto/tls/common.go
@@ -0,0 +1,1510 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "bytes"
+ "container/list"
+ "context"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/sha512"
+ "crypto/x509"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "strings"
+ "sync"
+ "time"
+)
+
+const (
+ VersionTLS10 = 0x0301
+ VersionTLS11 = 0x0302
+ VersionTLS12 = 0x0303
+ VersionTLS13 = 0x0304
+
+ // Deprecated: SSLv3 is cryptographically broken, and is no longer
+ // supported by this package. See golang.org/issue/32716.
+ VersionSSL30 = 0x0300
+)
+
+const (
+ maxPlaintext = 16384 // maximum plaintext payload length
+ maxCiphertext = 16384 + 2048 // maximum ciphertext payload length
+ maxCiphertextTLS13 = 16384 + 256 // maximum ciphertext length in TLS 1.3
+ recordHeaderLen = 5 // record header length
+ maxHandshake = 65536 // maximum handshake we support (protocol max is 16 MB)
+ maxUselessRecords = 16 // maximum number of consecutive non-advancing records
+)
+
+// TLS record types.
+type recordType uint8
+
+const (
+ recordTypeChangeCipherSpec recordType = 20
+ recordTypeAlert recordType = 21
+ recordTypeHandshake recordType = 22
+ recordTypeApplicationData recordType = 23
+)
+
+// TLS handshake message types.
+const (
+ typeHelloRequest uint8 = 0
+ typeClientHello uint8 = 1
+ typeServerHello uint8 = 2
+ typeNewSessionTicket uint8 = 4
+ typeEndOfEarlyData uint8 = 5
+ typeEncryptedExtensions uint8 = 8
+ typeCertificate uint8 = 11
+ typeServerKeyExchange uint8 = 12
+ typeCertificateRequest uint8 = 13
+ typeServerHelloDone uint8 = 14
+ typeCertificateVerify uint8 = 15
+ typeClientKeyExchange uint8 = 16
+ typeFinished uint8 = 20
+ typeCertificateStatus uint8 = 22
+ typeKeyUpdate uint8 = 24
+ typeNextProtocol uint8 = 67 // Not IANA assigned
+ typeMessageHash uint8 = 254 // synthetic message
+)
+
+// TLS compression types.
+const (
+ compressionNone uint8 = 0
+)
+
+// TLS extension numbers
+const (
+ extensionServerName uint16 = 0
+ extensionStatusRequest uint16 = 5
+ extensionSupportedCurves uint16 = 10 // supported_groups in TLS 1.3, see RFC 8446, Section 4.2.7
+ extensionSupportedPoints uint16 = 11
+ extensionSignatureAlgorithms uint16 = 13
+ extensionALPN uint16 = 16
+ extensionSCT uint16 = 18
+ extensionSessionTicket uint16 = 35
+ extensionPreSharedKey uint16 = 41
+ extensionEarlyData uint16 = 42
+ extensionSupportedVersions uint16 = 43
+ extensionCookie uint16 = 44
+ extensionPSKModes uint16 = 45
+ extensionCertificateAuthorities uint16 = 47
+ extensionSignatureAlgorithmsCert uint16 = 50
+ extensionKeyShare uint16 = 51
+ extensionRenegotiationInfo uint16 = 0xff01
+)
+
+// TLS signaling cipher suite values
+const (
+ scsvRenegotiation uint16 = 0x00ff
+)
+
+// CurveID is the type of a TLS identifier for an elliptic curve. See
+// https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-8.
+//
+// In TLS 1.3, this type is called NamedGroup, but at this time this library
+// only supports Elliptic Curve based groups. See RFC 8446, Section 4.2.7.
+type CurveID uint16
+
+const (
+ CurveP256 CurveID = 23
+ CurveP384 CurveID = 24
+ CurveP521 CurveID = 25
+ X25519 CurveID = 29
+)
+
+// TLS 1.3 Key Share. See RFC 8446, Section 4.2.8.
+type keyShare struct {
+ group CurveID
+ data []byte
+}
+
+// TLS 1.3 PSK Key Exchange Modes. See RFC 8446, Section 4.2.9.
+const (
+ pskModePlain uint8 = 0
+ pskModeDHE uint8 = 1
+)
+
+// TLS 1.3 PSK Identity. Can be a Session Ticket, or a reference to a saved
+// session. See RFC 8446, Section 4.2.11.
+type pskIdentity struct {
+ label []byte
+ obfuscatedTicketAge uint32
+}
+
+// TLS Elliptic Curve Point Formats
+// https://www.iana.org/assignments/tls-parameters/tls-parameters.xml#tls-parameters-9
+const (
+ pointFormatUncompressed uint8 = 0
+)
+
+// TLS CertificateStatusType (RFC 3546)
+const (
+ statusTypeOCSP uint8 = 1
+)
+
+// Certificate types (for certificateRequestMsg)
+const (
+ certTypeRSASign = 1
+ certTypeECDSASign = 64 // ECDSA or EdDSA keys, see RFC 8422, Section 3.
+)
+
+// Signature algorithms (for internal signaling use). Starting at 225 to avoid overlap with
+// TLS 1.2 codepoints (RFC 5246, Appendix A.4.1), with which these have nothing to do.
+const (
+ signaturePKCS1v15 uint8 = iota + 225
+ signatureRSAPSS
+ signatureECDSA
+ signatureEd25519
+)
+
+// directSigning is a standard Hash value that signals that no pre-hashing
+// should be performed, and that the input should be signed directly. It is the
+// hash function associated with the Ed25519 signature scheme.
+var directSigning crypto.Hash = 0
+
+// defaultSupportedSignatureAlgorithms contains the signature and hash algorithms that
+// the code advertises as supported in a TLS 1.2+ ClientHello and in a TLS 1.2+
+// CertificateRequest. The two fields are merged to match with TLS 1.3.
+// Note that in TLS 1.2, the ECDSA algorithms are not constrained to P-256, etc.
+var defaultSupportedSignatureAlgorithms = []SignatureScheme{
+ PSSWithSHA256,
+ ECDSAWithP256AndSHA256,
+ Ed25519,
+ PSSWithSHA384,
+ PSSWithSHA512,
+ PKCS1WithSHA256,
+ PKCS1WithSHA384,
+ PKCS1WithSHA512,
+ ECDSAWithP384AndSHA384,
+ ECDSAWithP521AndSHA512,
+ PKCS1WithSHA1,
+ ECDSAWithSHA1,
+}
+
+// helloRetryRequestRandom is set as the Random value of a ServerHello
+// to signal that the message is actually a HelloRetryRequest.
+var helloRetryRequestRandom = []byte{ // See RFC 8446, Section 4.1.3.
+ 0xCF, 0x21, 0xAD, 0x74, 0xE5, 0x9A, 0x61, 0x11,
+ 0xBE, 0x1D, 0x8C, 0x02, 0x1E, 0x65, 0xB8, 0x91,
+ 0xC2, 0xA2, 0x11, 0x16, 0x7A, 0xBB, 0x8C, 0x5E,
+ 0x07, 0x9E, 0x09, 0xE2, 0xC8, 0xA8, 0x33, 0x9C,
+}
+
+const (
+ // downgradeCanaryTLS12 or downgradeCanaryTLS11 is embedded in the server
+ // random as a downgrade protection if the server would be capable of
+ // negotiating a higher version. See RFC 8446, Section 4.1.3.
+ downgradeCanaryTLS12 = "DOWNGRD\x01"
+ downgradeCanaryTLS11 = "DOWNGRD\x00"
+)
+
+// testingOnlyForceDowngradeCanary is set in tests to force the server side to
+// include downgrade canaries even if it's using its highers supported version.
+var testingOnlyForceDowngradeCanary bool
+
+// ConnectionState records basic TLS details about the connection.
+type ConnectionState struct {
+ // Version is the TLS version used by the connection (e.g. VersionTLS12).
+ Version uint16
+
+ // HandshakeComplete is true if the handshake has concluded.
+ HandshakeComplete bool
+
+ // DidResume is true if this connection was successfully resumed from a
+ // previous session with a session ticket or similar mechanism.
+ DidResume bool
+
+ // CipherSuite is the cipher suite negotiated for the connection (e.g.
+ // TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256, TLS_AES_128_GCM_SHA256).
+ CipherSuite uint16
+
+ // NegotiatedProtocol is the application protocol negotiated with ALPN.
+ NegotiatedProtocol string
+
+ // NegotiatedProtocolIsMutual used to indicate a mutual NPN negotiation.
+ //
+ // Deprecated: this value is always true.
+ NegotiatedProtocolIsMutual bool
+
+ // ServerName is the value of the Server Name Indication extension sent by
+ // the client. It's available both on the server and on the client side.
+ ServerName string
+
+ // PeerCertificates are the parsed certificates sent by the peer, in the
+ // order in which they were sent. The first element is the leaf certificate
+ // that the connection is verified against.
+ //
+ // On the client side, it can't be empty. On the server side, it can be
+ // empty if Config.ClientAuth is not RequireAnyClientCert or
+ // RequireAndVerifyClientCert.
+ //
+ // PeerCertificates and its contents should not be modified.
+ PeerCertificates []*x509.Certificate
+
+ // VerifiedChains is a list of one or more chains where the first element is
+ // PeerCertificates[0] and the last element is from Config.RootCAs (on the
+ // client side) or Config.ClientCAs (on the server side).
+ //
+ // On the client side, it's set if Config.InsecureSkipVerify is false. On
+ // the server side, it's set if Config.ClientAuth is VerifyClientCertIfGiven
+ // (and the peer provided a certificate) or RequireAndVerifyClientCert.
+ //
+ // VerifiedChains and its contents should not be modified.
+ VerifiedChains [][]*x509.Certificate
+
+ // SignedCertificateTimestamps is a list of SCTs provided by the peer
+ // through the TLS handshake for the leaf certificate, if any.
+ SignedCertificateTimestamps [][]byte
+
+ // OCSPResponse is a stapled Online Certificate Status Protocol (OCSP)
+ // response provided by the peer for the leaf certificate, if any.
+ OCSPResponse []byte
+
+ // TLSUnique contains the "tls-unique" channel binding value (see RFC 5929,
+ // Section 3). This value will be nil for TLS 1.3 connections and for all
+ // resumed connections.
+ //
+ // Deprecated: there are conditions in which this value might not be unique
+ // to a connection. See the Security Considerations sections of RFC 5705 and
+ // RFC 7627, and https://mitls.org/pages/attacks/3SHAKE#channelbindings.
+ TLSUnique []byte
+
+ // ekm is a closure exposed via ExportKeyingMaterial.
+ ekm func(label string, context []byte, length int) ([]byte, error)
+}
+
+// ExportKeyingMaterial returns length bytes of exported key material in a new
+// slice as defined in RFC 5705. If context is nil, it is not used as part of
+// the seed. If the connection was set to allow renegotiation via
+// Config.Renegotiation, this function will return an error.
+func (cs *ConnectionState) ExportKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
+ return cs.ekm(label, context, length)
+}
+
+// ClientAuthType declares the policy the server will follow for
+// TLS Client Authentication.
+type ClientAuthType int
+
+const (
+ // NoClientCert indicates that no client certificate should be requested
+ // during the handshake, and if any certificates are sent they will not
+ // be verified.
+ NoClientCert ClientAuthType = iota
+ // RequestClientCert indicates that a client certificate should be requested
+ // during the handshake, but does not require that the client send any
+ // certificates.
+ RequestClientCert
+ // RequireAnyClientCert indicates that a client certificate should be requested
+ // during the handshake, and that at least one certificate is required to be
+ // sent by the client, but that certificate is not required to be valid.
+ RequireAnyClientCert
+ // VerifyClientCertIfGiven indicates that a client certificate should be requested
+ // during the handshake, but does not require that the client sends a
+ // certificate. If the client does send a certificate it is required to be
+ // valid.
+ VerifyClientCertIfGiven
+ // RequireAndVerifyClientCert indicates that a client certificate should be requested
+ // during the handshake, and that at least one valid certificate is required
+ // to be sent by the client.
+ RequireAndVerifyClientCert
+)
+
+// requiresClientCert reports whether the ClientAuthType requires a client
+// certificate to be provided.
+func requiresClientCert(c ClientAuthType) bool {
+ switch c {
+ case RequireAnyClientCert, RequireAndVerifyClientCert:
+ return true
+ default:
+ return false
+ }
+}
+
+// ClientSessionState contains the state needed by clients to resume TLS
+// sessions.
+type ClientSessionState struct {
+ sessionTicket []uint8 // Encrypted ticket used for session resumption with server
+ vers uint16 // TLS version negotiated for the session
+ cipherSuite uint16 // Ciphersuite negotiated for the session
+ masterSecret []byte // Full handshake MasterSecret, or TLS 1.3 resumption_master_secret
+ serverCertificates []*x509.Certificate // Certificate chain presented by the server
+ verifiedChains [][]*x509.Certificate // Certificate chains we built for verification
+ receivedAt time.Time // When the session ticket was received from the server
+ ocspResponse []byte // Stapled OCSP response presented by the server
+ scts [][]byte // SCTs presented by the server
+
+ // TLS 1.3 fields.
+ nonce []byte // Ticket nonce sent by the server, to derive PSK
+ useBy time.Time // Expiration of the ticket lifetime as set by the server
+ ageAdd uint32 // Random obfuscation factor for sending the ticket age
+}
+
+// ClientSessionCache is a cache of ClientSessionState objects that can be used
+// by a client to resume a TLS session with a given server. ClientSessionCache
+// implementations should expect to be called concurrently from different
+// goroutines. Up to TLS 1.2, only ticket-based resumption is supported, not
+// SessionID-based resumption. In TLS 1.3 they were merged into PSK modes, which
+// are supported via this interface.
+type ClientSessionCache interface {
+ // Get searches for a ClientSessionState associated with the given key.
+ // On return, ok is true if one was found.
+ Get(sessionKey string) (session *ClientSessionState, ok bool)
+
+ // Put adds the ClientSessionState to the cache with the given key. It might
+ // get called multiple times in a connection if a TLS 1.3 server provides
+ // more than one session ticket. If called with a nil *ClientSessionState,
+ // it should remove the cache entry.
+ Put(sessionKey string, cs *ClientSessionState)
+}
+
+//go:generate stringer -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go
+
+// SignatureScheme identifies a signature algorithm supported by TLS. See
+// RFC 8446, Section 4.2.3.
+type SignatureScheme uint16
+
+const (
+ // RSASSA-PKCS1-v1_5 algorithms.
+ PKCS1WithSHA256 SignatureScheme = 0x0401
+ PKCS1WithSHA384 SignatureScheme = 0x0501
+ PKCS1WithSHA512 SignatureScheme = 0x0601
+
+ // RSASSA-PSS algorithms with public key OID rsaEncryption.
+ PSSWithSHA256 SignatureScheme = 0x0804
+ PSSWithSHA384 SignatureScheme = 0x0805
+ PSSWithSHA512 SignatureScheme = 0x0806
+
+ // ECDSA algorithms. Only constrained to a specific curve in TLS 1.3.
+ ECDSAWithP256AndSHA256 SignatureScheme = 0x0403
+ ECDSAWithP384AndSHA384 SignatureScheme = 0x0503
+ ECDSAWithP521AndSHA512 SignatureScheme = 0x0603
+
+ // EdDSA algorithms.
+ Ed25519 SignatureScheme = 0x0807
+
+ // Legacy signature and hash algorithms for TLS 1.2.
+ PKCS1WithSHA1 SignatureScheme = 0x0201
+ ECDSAWithSHA1 SignatureScheme = 0x0203
+)
+
+// ClientHelloInfo contains information from a ClientHello message in order to
+// guide application logic in the GetCertificate and GetConfigForClient callbacks.
+type ClientHelloInfo struct {
+ // CipherSuites lists the CipherSuites supported by the client (e.g.
+ // TLS_AES_128_GCM_SHA256, TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256).
+ CipherSuites []uint16
+
+ // ServerName indicates the name of the server requested by the client
+ // in order to support virtual hosting. ServerName is only set if the
+ // client is using SNI (see RFC 4366, Section 3.1).
+ ServerName string
+
+ // SupportedCurves lists the elliptic curves supported by the client.
+ // SupportedCurves is set only if the Supported Elliptic Curves
+ // Extension is being used (see RFC 4492, Section 5.1.1).
+ SupportedCurves []CurveID
+
+ // SupportedPoints lists the point formats supported by the client.
+ // SupportedPoints is set only if the Supported Point Formats Extension
+ // is being used (see RFC 4492, Section 5.1.2).
+ SupportedPoints []uint8
+
+ // SignatureSchemes lists the signature and hash schemes that the client
+ // is willing to verify. SignatureSchemes is set only if the Signature
+ // Algorithms Extension is being used (see RFC 5246, Section 7.4.1.4.1).
+ SignatureSchemes []SignatureScheme
+
+ // SupportedProtos lists the application protocols supported by the client.
+ // SupportedProtos is set only if the Application-Layer Protocol
+ // Negotiation Extension is being used (see RFC 7301, Section 3.1).
+ //
+ // Servers can select a protocol by setting Config.NextProtos in a
+ // GetConfigForClient return value.
+ SupportedProtos []string
+
+ // SupportedVersions lists the TLS versions supported by the client.
+ // For TLS versions less than 1.3, this is extrapolated from the max
+ // version advertised by the client, so values other than the greatest
+ // might be rejected if used.
+ SupportedVersions []uint16
+
+ // Conn is the underlying net.Conn for the connection. Do not read
+ // from, or write to, this connection; that will cause the TLS
+ // connection to fail.
+ Conn net.Conn
+
+ // config is embedded by the GetCertificate or GetConfigForClient caller,
+ // for use with SupportsCertificate.
+ config *Config
+
+ // ctx is the context of the handshake that is in progress.
+ ctx context.Context
+}
+
+// Context returns the context of the handshake that is in progress.
+// This context is a child of the context passed to HandshakeContext,
+// if any, and is canceled when the handshake concludes.
+func (c *ClientHelloInfo) Context() context.Context {
+ return c.ctx
+}
+
+// CertificateRequestInfo contains information from a server's
+// CertificateRequest message, which is used to demand a certificate and proof
+// of control from a client.
+type CertificateRequestInfo struct {
+ // AcceptableCAs contains zero or more, DER-encoded, X.501
+ // Distinguished Names. These are the names of root or intermediate CAs
+ // that the server wishes the returned certificate to be signed by. An
+ // empty slice indicates that the server has no preference.
+ AcceptableCAs [][]byte
+
+ // SignatureSchemes lists the signature schemes that the server is
+ // willing to verify.
+ SignatureSchemes []SignatureScheme
+
+ // Version is the TLS version that was negotiated for this connection.
+ Version uint16
+
+ // ctx is the context of the handshake that is in progress.
+ ctx context.Context
+}
+
+// Context returns the context of the handshake that is in progress.
+// This context is a child of the context passed to HandshakeContext,
+// if any, and is canceled when the handshake concludes.
+func (c *CertificateRequestInfo) Context() context.Context {
+ return c.ctx
+}
+
+// RenegotiationSupport enumerates the different levels of support for TLS
+// renegotiation. TLS renegotiation is the act of performing subsequent
+// handshakes on a connection after the first. This significantly complicates
+// the state machine and has been the source of numerous, subtle security
+// issues. Initiating a renegotiation is not supported, but support for
+// accepting renegotiation requests may be enabled.
+//
+// Even when enabled, the server may not change its identity between handshakes
+// (i.e. the leaf certificate must be the same). Additionally, concurrent
+// handshake and application data flow is not permitted so renegotiation can
+// only be used with protocols that synchronise with the renegotiation, such as
+// HTTPS.
+//
+// Renegotiation is not defined in TLS 1.3.
+type RenegotiationSupport int
+
+const (
+ // RenegotiateNever disables renegotiation.
+ RenegotiateNever RenegotiationSupport = iota
+
+ // RenegotiateOnceAsClient allows a remote server to request
+ // renegotiation once per connection.
+ RenegotiateOnceAsClient
+
+ // RenegotiateFreelyAsClient allows a remote server to repeatedly
+ // request renegotiation.
+ RenegotiateFreelyAsClient
+)
+
+// A Config structure is used to configure a TLS client or server.
+// After one has been passed to a TLS function it must not be
+// modified. A Config may be reused; the tls package will also not
+// modify it.
+type Config struct {
+ // Rand provides the source of entropy for nonces and RSA blinding.
+ // If Rand is nil, TLS uses the cryptographic random reader in package
+ // crypto/rand.
+ // The Reader must be safe for use by multiple goroutines.
+ Rand io.Reader
+
+ // Time returns the current time as the number of seconds since the epoch.
+ // If Time is nil, TLS uses time.Now.
+ Time func() time.Time
+
+ // Certificates contains one or more certificate chains to present to the
+ // other side of the connection. The first certificate compatible with the
+ // peer's requirements is selected automatically.
+ //
+ // Server configurations must set one of Certificates, GetCertificate or
+ // GetConfigForClient. Clients doing client-authentication may set either
+ // Certificates or GetClientCertificate.
+ //
+ // Note: if there are multiple Certificates, and they don't have the
+ // optional field Leaf set, certificate selection will incur a significant
+ // per-handshake performance cost.
+ Certificates []Certificate
+
+ // NameToCertificate maps from a certificate name to an element of
+ // Certificates. Note that a certificate name can be of the form
+ // '*.example.com' and so doesn't have to be a domain name as such.
+ //
+ // Deprecated: NameToCertificate only allows associating a single
+ // certificate with a given name. Leave this field nil to let the library
+ // select the first compatible chain from Certificates.
+ NameToCertificate map[string]*Certificate
+
+ // GetCertificate returns a Certificate based on the given
+ // ClientHelloInfo. It will only be called if the client supplies SNI
+ // information or if Certificates is empty.
+ //
+ // If GetCertificate is nil or returns nil, then the certificate is
+ // retrieved from NameToCertificate. If NameToCertificate is nil, the
+ // best element of Certificates will be used.
+ //
+ // Once a Certificate is returned it should not be modified.
+ GetCertificate func(*ClientHelloInfo) (*Certificate, error)
+
+ // GetClientCertificate, if not nil, is called when a server requests a
+ // certificate from a client. If set, the contents of Certificates will
+ // be ignored.
+ //
+ // If GetClientCertificate returns an error, the handshake will be
+ // aborted and that error will be returned. Otherwise
+ // GetClientCertificate must return a non-nil Certificate. If
+ // Certificate.Certificate is empty then no certificate will be sent to
+ // the server. If this is unacceptable to the server then it may abort
+ // the handshake.
+ //
+ // GetClientCertificate may be called multiple times for the same
+ // connection if renegotiation occurs or if TLS 1.3 is in use.
+ //
+ // Once a Certificate is returned it should not be modified.
+ GetClientCertificate func(*CertificateRequestInfo) (*Certificate, error)
+
+ // GetConfigForClient, if not nil, is called after a ClientHello is
+ // received from a client. It may return a non-nil Config in order to
+ // change the Config that will be used to handle this connection. If
+ // the returned Config is nil, the original Config will be used. The
+ // Config returned by this callback may not be subsequently modified.
+ //
+ // If GetConfigForClient is nil, the Config passed to Server() will be
+ // used for all connections.
+ //
+ // If SessionTicketKey was explicitly set on the returned Config, or if
+ // SetSessionTicketKeys was called on the returned Config, those keys will
+ // be used. Otherwise, the original Config keys will be used (and possibly
+ // rotated if they are automatically managed).
+ GetConfigForClient func(*ClientHelloInfo) (*Config, error)
+
+ // VerifyPeerCertificate, if not nil, is called after normal
+ // certificate verification by either a TLS client or server. It
+ // receives the raw ASN.1 certificates provided by the peer and also
+ // any verified chains that normal processing found. If it returns a
+ // non-nil error, the handshake is aborted and that error results.
+ //
+ // If normal verification fails then the handshake will abort before
+ // considering this callback. If normal verification is disabled by
+ // setting InsecureSkipVerify, or (for a server) when ClientAuth is
+ // RequestClientCert or RequireAnyClientCert, then this callback will
+ // be considered but the verifiedChains argument will always be nil.
+ //
+ // verifiedChains and its contents should not be modified.
+ VerifyPeerCertificate func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error
+
+ // VerifyConnection, if not nil, is called after normal certificate
+ // verification and after VerifyPeerCertificate by either a TLS client
+ // or server. If it returns a non-nil error, the handshake is aborted
+ // and that error results.
+ //
+ // If normal verification fails then the handshake will abort before
+ // considering this callback. This callback will run for all connections
+ // regardless of InsecureSkipVerify or ClientAuth settings.
+ VerifyConnection func(ConnectionState) error
+
+ // RootCAs defines the set of root certificate authorities
+ // that clients use when verifying server certificates.
+ // If RootCAs is nil, TLS uses the host's root CA set.
+ RootCAs *x509.CertPool
+
+ // NextProtos is a list of supported application level protocols, in
+ // order of preference. If both peers support ALPN, the selected
+ // protocol will be one from this list, and the connection will fail
+ // if there is no mutually supported protocol. If NextProtos is empty
+ // or the peer doesn't support ALPN, the connection will succeed and
+ // ConnectionState.NegotiatedProtocol will be empty.
+ NextProtos []string
+
+ // ServerName is used to verify the hostname on the returned
+ // certificates unless InsecureSkipVerify is given. It is also included
+ // in the client's handshake to support virtual hosting unless it is
+ // an IP address.
+ ServerName string
+
+ // ClientAuth determines the server's policy for
+ // TLS Client Authentication. The default is NoClientCert.
+ ClientAuth ClientAuthType
+
+ // ClientCAs defines the set of root certificate authorities
+ // that servers use if required to verify a client certificate
+ // by the policy in ClientAuth.
+ ClientCAs *x509.CertPool
+
+ // InsecureSkipVerify controls whether a client verifies the server's
+ // certificate chain and host name. If InsecureSkipVerify is true, crypto/tls
+ // accepts any certificate presented by the server and any host name in that
+ // certificate. In this mode, TLS is susceptible to machine-in-the-middle
+ // attacks unless custom verification is used. This should be used only for
+ // testing or in combination with VerifyConnection or VerifyPeerCertificate.
+ InsecureSkipVerify bool
+
+ // CipherSuites is a list of enabled TLS 1.0–1.2 cipher suites. The order of
+ // the list is ignored. Note that TLS 1.3 ciphersuites are not configurable.
+ //
+ // If CipherSuites is nil, a safe default list is used. The default cipher
+ // suites might change over time.
+ CipherSuites []uint16
+
+ // PreferServerCipherSuites is a legacy field and has no effect.
+ //
+ // It used to control whether the server would follow the client's or the
+ // server's preference. Servers now select the best mutually supported
+ // cipher suite based on logic that takes into account inferred client
+ // hardware, server hardware, and security.
+ //
+ // Deprecated: PreferServerCipherSuites is ignored.
+ PreferServerCipherSuites bool
+
+ // SessionTicketsDisabled may be set to true to disable session ticket and
+ // PSK (resumption) support. Note that on clients, session ticket support is
+ // also disabled if ClientSessionCache is nil.
+ SessionTicketsDisabled bool
+
+ // SessionTicketKey is used by TLS servers to provide session resumption.
+ // See RFC 5077 and the PSK mode of RFC 8446. If zero, it will be filled
+ // with random data before the first server handshake.
+ //
+ // Deprecated: if this field is left at zero, session ticket keys will be
+ // automatically rotated every day and dropped after seven days. For
+ // customizing the rotation schedule or synchronizing servers that are
+ // terminating connections for the same host, use SetSessionTicketKeys.
+ SessionTicketKey [32]byte
+
+ // ClientSessionCache is a cache of ClientSessionState entries for TLS
+ // session resumption. It is only used by clients.
+ ClientSessionCache ClientSessionCache
+
+ // MinVersion contains the minimum TLS version that is acceptable.
+ //
+ // By default, TLS 1.2 is currently used as the minimum when acting as a
+ // client, and TLS 1.0 when acting as a server. TLS 1.0 is the minimum
+ // supported by this package, both as a client and as a server.
+ //
+ // The client-side default can temporarily be reverted to TLS 1.0 by
+ // including the value "x509sha1=1" in the GODEBUG environment variable.
+ // Note that this option will be removed in Go 1.19 (but it will still be
+ // possible to set this field to VersionTLS10 explicitly).
+ MinVersion uint16
+
+ // MaxVersion contains the maximum TLS version that is acceptable.
+ //
+ // By default, the maximum version supported by this package is used,
+ // which is currently TLS 1.3.
+ MaxVersion uint16
+
+ // CurvePreferences contains the elliptic curves that will be used in
+ // an ECDHE handshake, in preference order. If empty, the default will
+ // be used. The client will use the first preference as the type for
+ // its key share in TLS 1.3. This may change in the future.
+ CurvePreferences []CurveID
+
+ // DynamicRecordSizingDisabled disables adaptive sizing of TLS records.
+ // When true, the largest possible TLS record size is always used. When
+ // false, the size of TLS records may be adjusted in an attempt to
+ // improve latency.
+ DynamicRecordSizingDisabled bool
+
+ // Renegotiation controls what types of renegotiation are supported.
+ // The default, none, is correct for the vast majority of applications.
+ Renegotiation RenegotiationSupport
+
+ // KeyLogWriter optionally specifies a destination for TLS master secrets
+ // in NSS key log format that can be used to allow external programs
+ // such as Wireshark to decrypt TLS connections.
+ // See https://developer.mozilla.org/en-US/docs/Mozilla/Projects/NSS/Key_Log_Format.
+ // Use of KeyLogWriter compromises security and should only be
+ // used for debugging.
+ KeyLogWriter io.Writer
+
+ // mutex protects sessionTicketKeys and autoSessionTicketKeys.
+ mutex sync.RWMutex
+ // sessionTicketKeys contains zero or more ticket keys. If set, it means
+ // the keys were set with SessionTicketKey or SetSessionTicketKeys. The
+ // first key is used for new tickets and any subsequent keys can be used to
+ // decrypt old tickets. The slice contents are not protected by the mutex
+ // and are immutable.
+ sessionTicketKeys []ticketKey
+ // autoSessionTicketKeys is like sessionTicketKeys but is owned by the
+ // auto-rotation logic. See Config.ticketKeys.
+ autoSessionTicketKeys []ticketKey
+}
+
+const (
+ // ticketKeyNameLen is the number of bytes of identifier that is prepended to
+ // an encrypted session ticket in order to identify the key used to encrypt it.
+ ticketKeyNameLen = 16
+
+ // ticketKeyLifetime is how long a ticket key remains valid and can be used to
+ // resume a client connection.
+ ticketKeyLifetime = 7 * 24 * time.Hour // 7 days
+
+ // ticketKeyRotation is how often the server should rotate the session ticket key
+ // that is used for new tickets.
+ ticketKeyRotation = 24 * time.Hour
+)
+
+// ticketKey is the internal representation of a session ticket key.
+type ticketKey struct {
+ // keyName is an opaque byte string that serves to identify the session
+ // ticket key. It's exposed as plaintext in every session ticket.
+ keyName [ticketKeyNameLen]byte
+ aesKey [16]byte
+ hmacKey [16]byte
+ // created is the time at which this ticket key was created. See Config.ticketKeys.
+ created time.Time
+}
+
+// ticketKeyFromBytes converts from the external representation of a session
+// ticket key to a ticketKey. Externally, session ticket keys are 32 random
+// bytes and this function expands that into sufficient name and key material.
+func (c *Config) ticketKeyFromBytes(b [32]byte) (key ticketKey) {
+ hashed := sha512.Sum512(b[:])
+ copy(key.keyName[:], hashed[:ticketKeyNameLen])
+ copy(key.aesKey[:], hashed[ticketKeyNameLen:ticketKeyNameLen+16])
+ copy(key.hmacKey[:], hashed[ticketKeyNameLen+16:ticketKeyNameLen+32])
+ key.created = c.time()
+ return key
+}
+
+// maxSessionTicketLifetime is the maximum allowed lifetime of a TLS 1.3 session
+// ticket, and the lifetime we set for tickets we send.
+const maxSessionTicketLifetime = 7 * 24 * time.Hour
+
+// Clone returns a shallow clone of c or nil if c is nil. It is safe to clone a Config that is
+// being used concurrently by a TLS client or server.
+func (c *Config) Clone() *Config {
+ if c == nil {
+ return nil
+ }
+ c.mutex.RLock()
+ defer c.mutex.RUnlock()
+ return &Config{
+ Rand: c.Rand,
+ Time: c.Time,
+ Certificates: c.Certificates,
+ NameToCertificate: c.NameToCertificate,
+ GetCertificate: c.GetCertificate,
+ GetClientCertificate: c.GetClientCertificate,
+ GetConfigForClient: c.GetConfigForClient,
+ VerifyPeerCertificate: c.VerifyPeerCertificate,
+ VerifyConnection: c.VerifyConnection,
+ RootCAs: c.RootCAs,
+ NextProtos: c.NextProtos,
+ ServerName: c.ServerName,
+ ClientAuth: c.ClientAuth,
+ ClientCAs: c.ClientCAs,
+ InsecureSkipVerify: c.InsecureSkipVerify,
+ CipherSuites: c.CipherSuites,
+ PreferServerCipherSuites: c.PreferServerCipherSuites,
+ SessionTicketsDisabled: c.SessionTicketsDisabled,
+ SessionTicketKey: c.SessionTicketKey,
+ ClientSessionCache: c.ClientSessionCache,
+ MinVersion: c.MinVersion,
+ MaxVersion: c.MaxVersion,
+ CurvePreferences: c.CurvePreferences,
+ DynamicRecordSizingDisabled: c.DynamicRecordSizingDisabled,
+ Renegotiation: c.Renegotiation,
+ KeyLogWriter: c.KeyLogWriter,
+ sessionTicketKeys: c.sessionTicketKeys,
+ autoSessionTicketKeys: c.autoSessionTicketKeys,
+ }
+}
+
+// deprecatedSessionTicketKey is set as the prefix of SessionTicketKey if it was
+// randomized for backwards compatibility but is not in use.
+var deprecatedSessionTicketKey = []byte("DEPRECATED")
+
+// initLegacySessionTicketKeyRLocked ensures the legacy SessionTicketKey field is
+// randomized if empty, and that sessionTicketKeys is populated from it otherwise.
+func (c *Config) initLegacySessionTicketKeyRLocked() {
+ // Don't write if SessionTicketKey is already defined as our deprecated string,
+ // or if it is defined by the user but sessionTicketKeys is already set.
+ if c.SessionTicketKey != [32]byte{} &&
+ (bytes.HasPrefix(c.SessionTicketKey[:], deprecatedSessionTicketKey) || len(c.sessionTicketKeys) > 0) {
+ return
+ }
+
+ // We need to write some data, so get an exclusive lock and re-check any conditions.
+ c.mutex.RUnlock()
+ defer c.mutex.RLock()
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+ if c.SessionTicketKey == [32]byte{} {
+ if _, err := io.ReadFull(c.rand(), c.SessionTicketKey[:]); err != nil {
+ panic(fmt.Sprintf("tls: unable to generate random session ticket key: %v", err))
+ }
+ // Write the deprecated prefix at the beginning so we know we created
+ // it. This key with the DEPRECATED prefix isn't used as an actual
+ // session ticket key, and is only randomized in case the application
+ // reuses it for some reason.
+ copy(c.SessionTicketKey[:], deprecatedSessionTicketKey)
+ } else if !bytes.HasPrefix(c.SessionTicketKey[:], deprecatedSessionTicketKey) && len(c.sessionTicketKeys) == 0 {
+ c.sessionTicketKeys = []ticketKey{c.ticketKeyFromBytes(c.SessionTicketKey)}
+ }
+
+}
+
+// ticketKeys returns the ticketKeys for this connection.
+// If configForClient has explicitly set keys, those will
+// be returned. Otherwise, the keys on c will be used and
+// may be rotated if auto-managed.
+// During rotation, any expired session ticket keys are deleted from
+// c.sessionTicketKeys. If the session ticket key that is currently
+// encrypting tickets (ie. the first ticketKey in c.sessionTicketKeys)
+// is not fresh, then a new session ticket key will be
+// created and prepended to c.sessionTicketKeys.
+func (c *Config) ticketKeys(configForClient *Config) []ticketKey {
+ // If the ConfigForClient callback returned a Config with explicitly set
+ // keys, use those, otherwise just use the original Config.
+ if configForClient != nil {
+ configForClient.mutex.RLock()
+ if configForClient.SessionTicketsDisabled {
+ return nil
+ }
+ configForClient.initLegacySessionTicketKeyRLocked()
+ if len(configForClient.sessionTicketKeys) != 0 {
+ ret := configForClient.sessionTicketKeys
+ configForClient.mutex.RUnlock()
+ return ret
+ }
+ configForClient.mutex.RUnlock()
+ }
+
+ c.mutex.RLock()
+ defer c.mutex.RUnlock()
+ if c.SessionTicketsDisabled {
+ return nil
+ }
+ c.initLegacySessionTicketKeyRLocked()
+ if len(c.sessionTicketKeys) != 0 {
+ return c.sessionTicketKeys
+ }
+ // Fast path for the common case where the key is fresh enough.
+ if len(c.autoSessionTicketKeys) > 0 && c.time().Sub(c.autoSessionTicketKeys[0].created) < ticketKeyRotation {
+ return c.autoSessionTicketKeys
+ }
+
+ // autoSessionTicketKeys are managed by auto-rotation.
+ c.mutex.RUnlock()
+ defer c.mutex.RLock()
+ c.mutex.Lock()
+ defer c.mutex.Unlock()
+ // Re-check the condition in case it changed since obtaining the new lock.
+ if len(c.autoSessionTicketKeys) == 0 || c.time().Sub(c.autoSessionTicketKeys[0].created) >= ticketKeyRotation {
+ var newKey [32]byte
+ if _, err := io.ReadFull(c.rand(), newKey[:]); err != nil {
+ panic(fmt.Sprintf("unable to generate random session ticket key: %v", err))
+ }
+ valid := make([]ticketKey, 0, len(c.autoSessionTicketKeys)+1)
+ valid = append(valid, c.ticketKeyFromBytes(newKey))
+ for _, k := range c.autoSessionTicketKeys {
+ // While rotating the current key, also remove any expired ones.
+ if c.time().Sub(k.created) < ticketKeyLifetime {
+ valid = append(valid, k)
+ }
+ }
+ c.autoSessionTicketKeys = valid
+ }
+ return c.autoSessionTicketKeys
+}
+
+// SetSessionTicketKeys updates the session ticket keys for a server.
+//
+// The first key will be used when creating new tickets, while all keys can be
+// used for decrypting tickets. It is safe to call this function while the
+// server is running in order to rotate the session ticket keys. The function
+// will panic if keys is empty.
+//
+// Calling this function will turn off automatic session ticket key rotation.
+//
+// If multiple servers are terminating connections for the same host they should
+// all have the same session ticket keys. If the session ticket keys leaks,
+// previously recorded and future TLS connections using those keys might be
+// compromised.
+func (c *Config) SetSessionTicketKeys(keys [][32]byte) {
+ if len(keys) == 0 {
+ panic("tls: keys must have at least one key")
+ }
+
+ newKeys := make([]ticketKey, len(keys))
+ for i, bytes := range keys {
+ newKeys[i] = c.ticketKeyFromBytes(bytes)
+ }
+
+ c.mutex.Lock()
+ c.sessionTicketKeys = newKeys
+ c.mutex.Unlock()
+}
+
+func (c *Config) rand() io.Reader {
+ r := c.Rand
+ if r == nil {
+ return rand.Reader
+ }
+ return r
+}
+
+func (c *Config) time() time.Time {
+ t := c.Time
+ if t == nil {
+ t = time.Now
+ }
+ return t()
+}
+
+func (c *Config) cipherSuites() []uint16 {
+ if needFIPS() {
+ return fipsCipherSuites(c)
+ }
+ if c.CipherSuites != nil {
+ return c.CipherSuites
+ }
+ return defaultCipherSuites
+}
+
+var supportedVersions = []uint16{
+ VersionTLS13,
+ VersionTLS12,
+ VersionTLS11,
+ VersionTLS10,
+}
+
+// roleClient and roleServer are meant to call supportedVersions and parents
+// with more readability at the callsite.
+const roleClient = true
+const roleServer = false
+
+func (c *Config) supportedVersions(isClient bool) []uint16 {
+ versions := make([]uint16, 0, len(supportedVersions))
+ for _, v := range supportedVersions {
+ if needFIPS() && (v < fipsMinVersion(c) || v > fipsMaxVersion(c)) {
+ continue
+ }
+ if (c == nil || c.MinVersion == 0) &&
+ isClient && v < VersionTLS12 {
+ continue
+ }
+ if c != nil && c.MinVersion != 0 && v < c.MinVersion {
+ continue
+ }
+ if c != nil && c.MaxVersion != 0 && v > c.MaxVersion {
+ continue
+ }
+ versions = append(versions, v)
+ }
+ return versions
+}
+
+func (c *Config) maxSupportedVersion(isClient bool) uint16 {
+ supportedVersions := c.supportedVersions(isClient)
+ if len(supportedVersions) == 0 {
+ return 0
+ }
+ return supportedVersions[0]
+}
+
+// supportedVersionsFromMax returns a list of supported versions derived from a
+// legacy maximum version value. Note that only versions supported by this
+// library are returned. Any newer peer will use supportedVersions anyway.
+func supportedVersionsFromMax(maxVersion uint16) []uint16 {
+ versions := make([]uint16, 0, len(supportedVersions))
+ for _, v := range supportedVersions {
+ if v > maxVersion {
+ continue
+ }
+ versions = append(versions, v)
+ }
+ return versions
+}
+
+var defaultCurvePreferences = []CurveID{X25519, CurveP256, CurveP384, CurveP521}
+
+func (c *Config) curvePreferences() []CurveID {
+ if needFIPS() {
+ return fipsCurvePreferences(c)
+ }
+ if c == nil || len(c.CurvePreferences) == 0 {
+ return defaultCurvePreferences
+ }
+ return c.CurvePreferences
+}
+
+func (c *Config) supportsCurve(curve CurveID) bool {
+ for _, cc := range c.curvePreferences() {
+ if cc == curve {
+ return true
+ }
+ }
+ return false
+}
+
+// mutualVersion returns the protocol version to use given the advertised
+// versions of the peer. Priority is given to the peer preference order.
+func (c *Config) mutualVersion(isClient bool, peerVersions []uint16) (uint16, bool) {
+ supportedVersions := c.supportedVersions(isClient)
+ for _, peerVersion := range peerVersions {
+ for _, v := range supportedVersions {
+ if v == peerVersion {
+ return v, true
+ }
+ }
+ }
+ return 0, false
+}
+
+var errNoCertificates = errors.New("tls: no certificates configured")
+
+// getCertificate returns the best certificate for the given ClientHelloInfo,
+// defaulting to the first element of c.Certificates.
+func (c *Config) getCertificate(clientHello *ClientHelloInfo) (*Certificate, error) {
+ if c.GetCertificate != nil &&
+ (len(c.Certificates) == 0 || len(clientHello.ServerName) > 0) {
+ cert, err := c.GetCertificate(clientHello)
+ if cert != nil || err != nil {
+ return cert, err
+ }
+ }
+
+ if len(c.Certificates) == 0 {
+ return nil, errNoCertificates
+ }
+
+ if len(c.Certificates) == 1 {
+ // There's only one choice, so no point doing any work.
+ return &c.Certificates[0], nil
+ }
+
+ if c.NameToCertificate != nil {
+ name := strings.ToLower(clientHello.ServerName)
+ if cert, ok := c.NameToCertificate[name]; ok {
+ return cert, nil
+ }
+ if len(name) > 0 {
+ labels := strings.Split(name, ".")
+ labels[0] = "*"
+ wildcardName := strings.Join(labels, ".")
+ if cert, ok := c.NameToCertificate[wildcardName]; ok {
+ return cert, nil
+ }
+ }
+ }
+
+ for _, cert := range c.Certificates {
+ if err := clientHello.SupportsCertificate(&cert); err == nil {
+ return &cert, nil
+ }
+ }
+
+ // If nothing matches, return the first certificate.
+ return &c.Certificates[0], nil
+}
+
+// SupportsCertificate returns nil if the provided certificate is supported by
+// the client that sent the ClientHello. Otherwise, it returns an error
+// describing the reason for the incompatibility.
+//
+// If this ClientHelloInfo was passed to a GetConfigForClient or GetCertificate
+// callback, this method will take into account the associated Config. Note that
+// if GetConfigForClient returns a different Config, the change can't be
+// accounted for by this method.
+//
+// This function will call x509.ParseCertificate unless c.Leaf is set, which can
+// incur a significant performance cost.
+func (chi *ClientHelloInfo) SupportsCertificate(c *Certificate) error {
+ // Note we don't currently support certificate_authorities nor
+ // signature_algorithms_cert, and don't check the algorithms of the
+ // signatures on the chain (which anyway are a SHOULD, see RFC 8446,
+ // Section 4.4.2.2).
+
+ config := chi.config
+ if config == nil {
+ config = &Config{}
+ }
+ vers, ok := config.mutualVersion(roleServer, chi.SupportedVersions)
+ if !ok {
+ return errors.New("no mutually supported protocol versions")
+ }
+
+ // If the client specified the name they are trying to connect to, the
+ // certificate needs to be valid for it.
+ if chi.ServerName != "" {
+ x509Cert, err := c.leaf()
+ if err != nil {
+ return fmt.Errorf("failed to parse certificate: %w", err)
+ }
+ if err := x509Cert.VerifyHostname(chi.ServerName); err != nil {
+ return fmt.Errorf("certificate is not valid for requested server name: %w", err)
+ }
+ }
+
+ // supportsRSAFallback returns nil if the certificate and connection support
+ // the static RSA key exchange, and unsupported otherwise. The logic for
+ // supporting static RSA is completely disjoint from the logic for
+ // supporting signed key exchanges, so we just check it as a fallback.
+ supportsRSAFallback := func(unsupported error) error {
+ // TLS 1.3 dropped support for the static RSA key exchange.
+ if vers == VersionTLS13 {
+ return unsupported
+ }
+ // The static RSA key exchange works by decrypting a challenge with the
+ // RSA private key, not by signing, so check the PrivateKey implements
+ // crypto.Decrypter, like *rsa.PrivateKey does.
+ if priv, ok := c.PrivateKey.(crypto.Decrypter); ok {
+ if _, ok := priv.Public().(*rsa.PublicKey); !ok {
+ return unsupported
+ }
+ } else {
+ return unsupported
+ }
+ // Finally, there needs to be a mutual cipher suite that uses the static
+ // RSA key exchange instead of ECDHE.
+ rsaCipherSuite := selectCipherSuite(chi.CipherSuites, config.cipherSuites(), func(c *cipherSuite) bool {
+ if c.flags&suiteECDHE != 0 {
+ return false
+ }
+ if vers < VersionTLS12 && c.flags&suiteTLS12 != 0 {
+ return false
+ }
+ return true
+ })
+ if rsaCipherSuite == nil {
+ return unsupported
+ }
+ return nil
+ }
+
+ // If the client sent the signature_algorithms extension, ensure it supports
+ // schemes we can use with this certificate and TLS version.
+ if len(chi.SignatureSchemes) > 0 {
+ if _, err := selectSignatureScheme(vers, c, chi.SignatureSchemes); err != nil {
+ return supportsRSAFallback(err)
+ }
+ }
+
+ // In TLS 1.3 we are done because supported_groups is only relevant to the
+ // ECDHE computation, point format negotiation is removed, cipher suites are
+ // only relevant to the AEAD choice, and static RSA does not exist.
+ if vers == VersionTLS13 {
+ return nil
+ }
+
+ // The only signed key exchange we support is ECDHE.
+ if !supportsECDHE(config, chi.SupportedCurves, chi.SupportedPoints) {
+ return supportsRSAFallback(errors.New("client doesn't support ECDHE, can only use legacy RSA key exchange"))
+ }
+
+ var ecdsaCipherSuite bool
+ if priv, ok := c.PrivateKey.(crypto.Signer); ok {
+ switch pub := priv.Public().(type) {
+ case *ecdsa.PublicKey:
+ var curve CurveID
+ switch pub.Curve {
+ case elliptic.P256():
+ curve = CurveP256
+ case elliptic.P384():
+ curve = CurveP384
+ case elliptic.P521():
+ curve = CurveP521
+ default:
+ return supportsRSAFallback(unsupportedCertificateError(c))
+ }
+ var curveOk bool
+ for _, c := range chi.SupportedCurves {
+ if c == curve && config.supportsCurve(c) {
+ curveOk = true
+ break
+ }
+ }
+ if !curveOk {
+ return errors.New("client doesn't support certificate curve")
+ }
+ ecdsaCipherSuite = true
+ case ed25519.PublicKey:
+ if vers < VersionTLS12 || len(chi.SignatureSchemes) == 0 {
+ return errors.New("connection doesn't support Ed25519")
+ }
+ ecdsaCipherSuite = true
+ case *rsa.PublicKey:
+ default:
+ return supportsRSAFallback(unsupportedCertificateError(c))
+ }
+ } else {
+ return supportsRSAFallback(unsupportedCertificateError(c))
+ }
+
+ // Make sure that there is a mutually supported cipher suite that works with
+ // this certificate. Cipher suite selection will then apply the logic in
+ // reverse to pick it. See also serverHandshakeState.cipherSuiteOk.
+ cipherSuite := selectCipherSuite(chi.CipherSuites, config.cipherSuites(), func(c *cipherSuite) bool {
+ if c.flags&suiteECDHE == 0 {
+ return false
+ }
+ if c.flags&suiteECSign != 0 {
+ if !ecdsaCipherSuite {
+ return false
+ }
+ } else {
+ if ecdsaCipherSuite {
+ return false
+ }
+ }
+ if vers < VersionTLS12 && c.flags&suiteTLS12 != 0 {
+ return false
+ }
+ return true
+ })
+ if cipherSuite == nil {
+ return supportsRSAFallback(errors.New("client doesn't support any cipher suites compatible with the certificate"))
+ }
+
+ return nil
+}
+
+// SupportsCertificate returns nil if the provided certificate is supported by
+// the server that sent the CertificateRequest. Otherwise, it returns an error
+// describing the reason for the incompatibility.
+func (cri *CertificateRequestInfo) SupportsCertificate(c *Certificate) error {
+ if _, err := selectSignatureScheme(cri.Version, c, cri.SignatureSchemes); err != nil {
+ return err
+ }
+
+ if len(cri.AcceptableCAs) == 0 {
+ return nil
+ }
+
+ for j, cert := range c.Certificate {
+ x509Cert := c.Leaf
+ // Parse the certificate if this isn't the leaf node, or if
+ // chain.Leaf was nil.
+ if j != 0 || x509Cert == nil {
+ var err error
+ if x509Cert, err = x509.ParseCertificate(cert); err != nil {
+ return fmt.Errorf("failed to parse certificate #%d in the chain: %w", j, err)
+ }
+ }
+
+ for _, ca := range cri.AcceptableCAs {
+ if bytes.Equal(x509Cert.RawIssuer, ca) {
+ return nil
+ }
+ }
+ }
+ return errors.New("chain is not signed by an acceptable CA")
+}
+
+// BuildNameToCertificate parses c.Certificates and builds c.NameToCertificate
+// from the CommonName and SubjectAlternateName fields of each of the leaf
+// certificates.
+//
+// Deprecated: NameToCertificate only allows associating a single certificate
+// with a given name. Leave that field nil to let the library select the first
+// compatible chain from Certificates.
+func (c *Config) BuildNameToCertificate() {
+ c.NameToCertificate = make(map[string]*Certificate)
+ for i := range c.Certificates {
+ cert := &c.Certificates[i]
+ x509Cert, err := cert.leaf()
+ if err != nil {
+ continue
+ }
+ // If SANs are *not* present, some clients will consider the certificate
+ // valid for the name in the Common Name.
+ if x509Cert.Subject.CommonName != "" && len(x509Cert.DNSNames) == 0 {
+ c.NameToCertificate[x509Cert.Subject.CommonName] = cert
+ }
+ for _, san := range x509Cert.DNSNames {
+ c.NameToCertificate[san] = cert
+ }
+ }
+}
+
+const (
+ keyLogLabelTLS12 = "CLIENT_RANDOM"
+ keyLogLabelClientHandshake = "CLIENT_HANDSHAKE_TRAFFIC_SECRET"
+ keyLogLabelServerHandshake = "SERVER_HANDSHAKE_TRAFFIC_SECRET"
+ keyLogLabelClientTraffic = "CLIENT_TRAFFIC_SECRET_0"
+ keyLogLabelServerTraffic = "SERVER_TRAFFIC_SECRET_0"
+)
+
+func (c *Config) writeKeyLog(label string, clientRandom, secret []byte) error {
+ if c.KeyLogWriter == nil {
+ return nil
+ }
+
+ logLine := fmt.Appendf(nil, "%s %x %x\n", label, clientRandom, secret)
+
+ writerMutex.Lock()
+ _, err := c.KeyLogWriter.Write(logLine)
+ writerMutex.Unlock()
+
+ return err
+}
+
+// writerMutex protects all KeyLogWriters globally. It is rarely enabled,
+// and is only for debugging, so a global mutex saves space.
+var writerMutex sync.Mutex
+
+// A Certificate is a chain of one or more certificates, leaf first.
+type Certificate struct {
+ Certificate [][]byte
+ // PrivateKey contains the private key corresponding to the public key in
+ // Leaf. This must implement crypto.Signer with an RSA, ECDSA or Ed25519 PublicKey.
+ // For a server up to TLS 1.2, it can also implement crypto.Decrypter with
+ // an RSA PublicKey.
+ PrivateKey crypto.PrivateKey
+ // SupportedSignatureAlgorithms is an optional list restricting what
+ // signature algorithms the PrivateKey can be used for.
+ SupportedSignatureAlgorithms []SignatureScheme
+ // OCSPStaple contains an optional OCSP response which will be served
+ // to clients that request it.
+ OCSPStaple []byte
+ // SignedCertificateTimestamps contains an optional list of Signed
+ // Certificate Timestamps which will be served to clients that request it.
+ SignedCertificateTimestamps [][]byte
+ // Leaf is the parsed form of the leaf certificate, which may be initialized
+ // using x509.ParseCertificate to reduce per-handshake processing. If nil,
+ // the leaf certificate will be parsed as needed.
+ Leaf *x509.Certificate
+}
+
+// leaf returns the parsed leaf certificate, either from c.Leaf or by parsing
+// the corresponding c.Certificate[0].
+func (c *Certificate) leaf() (*x509.Certificate, error) {
+ if c.Leaf != nil {
+ return c.Leaf, nil
+ }
+ return x509.ParseCertificate(c.Certificate[0])
+}
+
+type handshakeMessage interface {
+ marshal() ([]byte, error)
+ unmarshal([]byte) bool
+}
+
+// lruSessionCache is a ClientSessionCache implementation that uses an LRU
+// caching strategy.
+type lruSessionCache struct {
+ sync.Mutex
+
+ m map[string]*list.Element
+ q *list.List
+ capacity int
+}
+
+type lruSessionCacheEntry struct {
+ sessionKey string
+ state *ClientSessionState
+}
+
+// NewLRUClientSessionCache returns a ClientSessionCache with the given
+// capacity that uses an LRU strategy. If capacity is < 1, a default capacity
+// is used instead.
+func NewLRUClientSessionCache(capacity int) ClientSessionCache {
+ const defaultSessionCacheCapacity = 64
+
+ if capacity < 1 {
+ capacity = defaultSessionCacheCapacity
+ }
+ return &lruSessionCache{
+ m: make(map[string]*list.Element),
+ q: list.New(),
+ capacity: capacity,
+ }
+}
+
+// Put adds the provided (sessionKey, cs) pair to the cache. If cs is nil, the entry
+// corresponding to sessionKey is removed from the cache instead.
+func (c *lruSessionCache) Put(sessionKey string, cs *ClientSessionState) {
+ c.Lock()
+ defer c.Unlock()
+
+ if elem, ok := c.m[sessionKey]; ok {
+ if cs == nil {
+ c.q.Remove(elem)
+ delete(c.m, sessionKey)
+ } else {
+ entry := elem.Value.(*lruSessionCacheEntry)
+ entry.state = cs
+ c.q.MoveToFront(elem)
+ }
+ return
+ }
+
+ if c.q.Len() < c.capacity {
+ entry := &lruSessionCacheEntry{sessionKey, cs}
+ c.m[sessionKey] = c.q.PushFront(entry)
+ return
+ }
+
+ elem := c.q.Back()
+ entry := elem.Value.(*lruSessionCacheEntry)
+ delete(c.m, entry.sessionKey)
+ entry.sessionKey = sessionKey
+ entry.state = cs
+ c.q.MoveToFront(elem)
+ c.m[sessionKey] = elem
+}
+
+// Get returns the ClientSessionState value associated with a given key. It
+// returns (nil, false) if no value is found.
+func (c *lruSessionCache) Get(sessionKey string) (*ClientSessionState, bool) {
+ c.Lock()
+ defer c.Unlock()
+
+ if elem, ok := c.m[sessionKey]; ok {
+ c.q.MoveToFront(elem)
+ return elem.Value.(*lruSessionCacheEntry).state, true
+ }
+ return nil, false
+}
+
+var emptyConfig Config
+
+func defaultConfig() *Config {
+ return &emptyConfig
+}
+
+func unexpectedMessageError(wanted, got any) error {
+ return fmt.Errorf("tls: received unexpected handshake message of type %T when waiting for %T", got, wanted)
+}
+
+func isSupportedSignatureAlgorithm(sigAlg SignatureScheme, supportedSignatureAlgorithms []SignatureScheme) bool {
+ for _, s := range supportedSignatureAlgorithms {
+ if s == sigAlg {
+ return true
+ }
+ }
+ return false
+}
+
+// CertificateVerificationError is returned when certificate verification fails during the handshake.
+type CertificateVerificationError struct {
+ // UnverifiedCertificates and its contents should not be modified.
+ UnverifiedCertificates []*x509.Certificate
+ Err error
+}
+
+func (e *CertificateVerificationError) Error() string {
+ return fmt.Sprintf("tls: failed to verify certificate: %s", e.Err)
+}
+
+func (e *CertificateVerificationError) Unwrap() error {
+ return e.Err
+}
diff --git a/src/crypto/tls/common_string.go b/src/crypto/tls/common_string.go
new file mode 100644
index 0000000..2381088
--- /dev/null
+++ b/src/crypto/tls/common_string.go
@@ -0,0 +1,116 @@
+// Code generated by "stringer -type=SignatureScheme,CurveID,ClientAuthType -output=common_string.go"; DO NOT EDIT.
+
+package tls
+
+import "strconv"
+
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[PKCS1WithSHA256-1025]
+ _ = x[PKCS1WithSHA384-1281]
+ _ = x[PKCS1WithSHA512-1537]
+ _ = x[PSSWithSHA256-2052]
+ _ = x[PSSWithSHA384-2053]
+ _ = x[PSSWithSHA512-2054]
+ _ = x[ECDSAWithP256AndSHA256-1027]
+ _ = x[ECDSAWithP384AndSHA384-1283]
+ _ = x[ECDSAWithP521AndSHA512-1539]
+ _ = x[Ed25519-2055]
+ _ = x[PKCS1WithSHA1-513]
+ _ = x[ECDSAWithSHA1-515]
+}
+
+const (
+ _SignatureScheme_name_0 = "PKCS1WithSHA1"
+ _SignatureScheme_name_1 = "ECDSAWithSHA1"
+ _SignatureScheme_name_2 = "PKCS1WithSHA256"
+ _SignatureScheme_name_3 = "ECDSAWithP256AndSHA256"
+ _SignatureScheme_name_4 = "PKCS1WithSHA384"
+ _SignatureScheme_name_5 = "ECDSAWithP384AndSHA384"
+ _SignatureScheme_name_6 = "PKCS1WithSHA512"
+ _SignatureScheme_name_7 = "ECDSAWithP521AndSHA512"
+ _SignatureScheme_name_8 = "PSSWithSHA256PSSWithSHA384PSSWithSHA512Ed25519"
+)
+
+var (
+ _SignatureScheme_index_8 = [...]uint8{0, 13, 26, 39, 46}
+)
+
+func (i SignatureScheme) String() string {
+ switch {
+ case i == 513:
+ return _SignatureScheme_name_0
+ case i == 515:
+ return _SignatureScheme_name_1
+ case i == 1025:
+ return _SignatureScheme_name_2
+ case i == 1027:
+ return _SignatureScheme_name_3
+ case i == 1281:
+ return _SignatureScheme_name_4
+ case i == 1283:
+ return _SignatureScheme_name_5
+ case i == 1537:
+ return _SignatureScheme_name_6
+ case i == 1539:
+ return _SignatureScheme_name_7
+ case 2052 <= i && i <= 2055:
+ i -= 2052
+ return _SignatureScheme_name_8[_SignatureScheme_index_8[i]:_SignatureScheme_index_8[i+1]]
+ default:
+ return "SignatureScheme(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+}
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[CurveP256-23]
+ _ = x[CurveP384-24]
+ _ = x[CurveP521-25]
+ _ = x[X25519-29]
+}
+
+const (
+ _CurveID_name_0 = "CurveP256CurveP384CurveP521"
+ _CurveID_name_1 = "X25519"
+)
+
+var (
+ _CurveID_index_0 = [...]uint8{0, 9, 18, 27}
+)
+
+func (i CurveID) String() string {
+ switch {
+ case 23 <= i && i <= 25:
+ i -= 23
+ return _CurveID_name_0[_CurveID_index_0[i]:_CurveID_index_0[i+1]]
+ case i == 29:
+ return _CurveID_name_1
+ default:
+ return "CurveID(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+}
+func _() {
+ // An "invalid array index" compiler error signifies that the constant values have changed.
+ // Re-run the stringer command to generate them again.
+ var x [1]struct{}
+ _ = x[NoClientCert-0]
+ _ = x[RequestClientCert-1]
+ _ = x[RequireAnyClientCert-2]
+ _ = x[VerifyClientCertIfGiven-3]
+ _ = x[RequireAndVerifyClientCert-4]
+}
+
+const _ClientAuthType_name = "NoClientCertRequestClientCertRequireAnyClientCertVerifyClientCertIfGivenRequireAndVerifyClientCert"
+
+var _ClientAuthType_index = [...]uint8{0, 12, 29, 49, 72, 98}
+
+func (i ClientAuthType) String() string {
+ if i < 0 || i >= ClientAuthType(len(_ClientAuthType_index)-1) {
+ return "ClientAuthType(" + strconv.FormatInt(int64(i), 10) + ")"
+ }
+ return _ClientAuthType_name[_ClientAuthType_index[i]:_ClientAuthType_index[i+1]]
+}
diff --git a/src/crypto/tls/conn.go b/src/crypto/tls/conn.go
new file mode 100644
index 0000000..f50b511
--- /dev/null
+++ b/src/crypto/tls/conn.go
@@ -0,0 +1,1575 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// TLS low level connection and record layer
+
+package tls
+
+import (
+ "bytes"
+ "context"
+ "crypto/cipher"
+ "crypto/subtle"
+ "crypto/x509"
+ "errors"
+ "fmt"
+ "hash"
+ "io"
+ "net"
+ "sync"
+ "sync/atomic"
+ "time"
+)
+
+// A Conn represents a secured connection.
+// It implements the net.Conn interface.
+type Conn struct {
+ // constant
+ conn net.Conn
+ isClient bool
+ handshakeFn func(context.Context) error // (*Conn).clientHandshake or serverHandshake
+
+ // isHandshakeComplete is true if the connection is currently transferring
+ // application data (i.e. is not currently processing a handshake).
+ // isHandshakeComplete is true implies handshakeErr == nil.
+ isHandshakeComplete atomic.Bool
+ // constant after handshake; protected by handshakeMutex
+ handshakeMutex sync.Mutex
+ handshakeErr error // error resulting from handshake
+ vers uint16 // TLS version
+ haveVers bool // version has been negotiated
+ config *Config // configuration passed to constructor
+ // handshakes counts the number of handshakes performed on the
+ // connection so far. If renegotiation is disabled then this is either
+ // zero or one.
+ handshakes int
+ didResume bool // whether this connection was a session resumption
+ cipherSuite uint16
+ ocspResponse []byte // stapled OCSP response
+ scts [][]byte // signed certificate timestamps from server
+ peerCertificates []*x509.Certificate
+ // activeCertHandles contains the cache handles to certificates in
+ // peerCertificates that are used to track active references.
+ activeCertHandles []*activeCert
+ // verifiedChains contains the certificate chains that we built, as
+ // opposed to the ones presented by the server.
+ verifiedChains [][]*x509.Certificate
+ // serverName contains the server name indicated by the client, if any.
+ serverName string
+ // secureRenegotiation is true if the server echoed the secure
+ // renegotiation extension. (This is meaningless as a server because
+ // renegotiation is not supported in that case.)
+ secureRenegotiation bool
+ // ekm is a closure for exporting keying material.
+ ekm func(label string, context []byte, length int) ([]byte, error)
+ // resumptionSecret is the resumption_master_secret for handling
+ // NewSessionTicket messages. nil if config.SessionTicketsDisabled.
+ resumptionSecret []byte
+
+ // ticketKeys is the set of active session ticket keys for this
+ // connection. The first one is used to encrypt new tickets and
+ // all are tried to decrypt tickets.
+ ticketKeys []ticketKey
+
+ // clientFinishedIsFirst is true if the client sent the first Finished
+ // message during the most recent handshake. This is recorded because
+ // the first transmitted Finished message is the tls-unique
+ // channel-binding value.
+ clientFinishedIsFirst bool
+
+ // closeNotifyErr is any error from sending the alertCloseNotify record.
+ closeNotifyErr error
+ // closeNotifySent is true if the Conn attempted to send an
+ // alertCloseNotify record.
+ closeNotifySent bool
+
+ // clientFinished and serverFinished contain the Finished message sent
+ // by the client or server in the most recent handshake. This is
+ // retained to support the renegotiation extension and tls-unique
+ // channel-binding.
+ clientFinished [12]byte
+ serverFinished [12]byte
+
+ // clientProtocol is the negotiated ALPN protocol.
+ clientProtocol string
+
+ // input/output
+ in, out halfConn
+ rawInput bytes.Buffer // raw input, starting with a record header
+ input bytes.Reader // application data waiting to be read, from rawInput.Next
+ hand bytes.Buffer // handshake data waiting to be read
+ buffering bool // whether records are buffered in sendBuf
+ sendBuf []byte // a buffer of records waiting to be sent
+
+ // bytesSent counts the bytes of application data sent.
+ // packetsSent counts packets.
+ bytesSent int64
+ packetsSent int64
+
+ // retryCount counts the number of consecutive non-advancing records
+ // received by Conn.readRecord. That is, records that neither advance the
+ // handshake, nor deliver application data. Protected by in.Mutex.
+ retryCount int
+
+ // activeCall indicates whether Close has been call in the low bit.
+ // the rest of the bits are the number of goroutines in Conn.Write.
+ activeCall atomic.Int32
+
+ tmp [16]byte
+}
+
+// Access to net.Conn methods.
+// Cannot just embed net.Conn because that would
+// export the struct field too.
+
+// LocalAddr returns the local network address.
+func (c *Conn) LocalAddr() net.Addr {
+ return c.conn.LocalAddr()
+}
+
+// RemoteAddr returns the remote network address.
+func (c *Conn) RemoteAddr() net.Addr {
+ return c.conn.RemoteAddr()
+}
+
+// SetDeadline sets the read and write deadlines associated with the connection.
+// A zero value for t means Read and Write will not time out.
+// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
+func (c *Conn) SetDeadline(t time.Time) error {
+ return c.conn.SetDeadline(t)
+}
+
+// SetReadDeadline sets the read deadline on the underlying connection.
+// A zero value for t means Read will not time out.
+func (c *Conn) SetReadDeadline(t time.Time) error {
+ return c.conn.SetReadDeadline(t)
+}
+
+// SetWriteDeadline sets the write deadline on the underlying connection.
+// A zero value for t means Write will not time out.
+// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
+func (c *Conn) SetWriteDeadline(t time.Time) error {
+ return c.conn.SetWriteDeadline(t)
+}
+
+// NetConn returns the underlying connection that is wrapped by c.
+// Note that writing to or reading from this connection directly will corrupt the
+// TLS session.
+func (c *Conn) NetConn() net.Conn {
+ return c.conn
+}
+
+// A halfConn represents one direction of the record layer
+// connection, either sending or receiving.
+type halfConn struct {
+ sync.Mutex
+
+ err error // first permanent error
+ version uint16 // protocol version
+ cipher any // cipher algorithm
+ mac hash.Hash
+ seq [8]byte // 64-bit sequence number
+
+ scratchBuf [13]byte // to avoid allocs; interface method args escape
+
+ nextCipher any // next encryption state
+ nextMac hash.Hash // next MAC algorithm
+
+ trafficSecret []byte // current TLS 1.3 traffic secret
+}
+
+type permanentError struct {
+ err net.Error
+}
+
+func (e *permanentError) Error() string { return e.err.Error() }
+func (e *permanentError) Unwrap() error { return e.err }
+func (e *permanentError) Timeout() bool { return e.err.Timeout() }
+func (e *permanentError) Temporary() bool { return false }
+
+func (hc *halfConn) setErrorLocked(err error) error {
+ if e, ok := err.(net.Error); ok {
+ hc.err = &permanentError{err: e}
+ } else {
+ hc.err = err
+ }
+ return hc.err
+}
+
+// prepareCipherSpec sets the encryption and MAC states
+// that a subsequent changeCipherSpec will use.
+func (hc *halfConn) prepareCipherSpec(version uint16, cipher any, mac hash.Hash) {
+ hc.version = version
+ hc.nextCipher = cipher
+ hc.nextMac = mac
+}
+
+// changeCipherSpec changes the encryption and MAC states
+// to the ones previously passed to prepareCipherSpec.
+func (hc *halfConn) changeCipherSpec() error {
+ if hc.nextCipher == nil || hc.version == VersionTLS13 {
+ return alertInternalError
+ }
+ hc.cipher = hc.nextCipher
+ hc.mac = hc.nextMac
+ hc.nextCipher = nil
+ hc.nextMac = nil
+ for i := range hc.seq {
+ hc.seq[i] = 0
+ }
+ return nil
+}
+
+func (hc *halfConn) setTrafficSecret(suite *cipherSuiteTLS13, secret []byte) {
+ hc.trafficSecret = secret
+ key, iv := suite.trafficKey(secret)
+ hc.cipher = suite.aead(key, iv)
+ for i := range hc.seq {
+ hc.seq[i] = 0
+ }
+}
+
+// incSeq increments the sequence number.
+func (hc *halfConn) incSeq() {
+ for i := 7; i >= 0; i-- {
+ hc.seq[i]++
+ if hc.seq[i] != 0 {
+ return
+ }
+ }
+
+ // Not allowed to let sequence number wrap.
+ // Instead, must renegotiate before it does.
+ // Not likely enough to bother.
+ panic("TLS: sequence number wraparound")
+}
+
+// explicitNonceLen returns the number of bytes of explicit nonce or IV included
+// in each record. Explicit nonces are present only in CBC modes after TLS 1.0
+// and in certain AEAD modes in TLS 1.2.
+func (hc *halfConn) explicitNonceLen() int {
+ if hc.cipher == nil {
+ return 0
+ }
+
+ switch c := hc.cipher.(type) {
+ case cipher.Stream:
+ return 0
+ case aead:
+ return c.explicitNonceLen()
+ case cbcMode:
+ // TLS 1.1 introduced a per-record explicit IV to fix the BEAST attack.
+ if hc.version >= VersionTLS11 {
+ return c.BlockSize()
+ }
+ return 0
+ default:
+ panic("unknown cipher type")
+ }
+}
+
+// extractPadding returns, in constant time, the length of the padding to remove
+// from the end of payload. It also returns a byte which is equal to 255 if the
+// padding was valid and 0 otherwise. See RFC 2246, Section 6.2.3.2.
+func extractPadding(payload []byte) (toRemove int, good byte) {
+ if len(payload) < 1 {
+ return 0, 0
+ }
+
+ paddingLen := payload[len(payload)-1]
+ t := uint(len(payload)-1) - uint(paddingLen)
+ // if len(payload) >= (paddingLen - 1) then the MSB of t is zero
+ good = byte(int32(^t) >> 31)
+
+ // The maximum possible padding length plus the actual length field
+ toCheck := 256
+ // The length of the padded data is public, so we can use an if here
+ if toCheck > len(payload) {
+ toCheck = len(payload)
+ }
+
+ for i := 0; i < toCheck; i++ {
+ t := uint(paddingLen) - uint(i)
+ // if i <= paddingLen then the MSB of t is zero
+ mask := byte(int32(^t) >> 31)
+ b := payload[len(payload)-1-i]
+ good &^= mask&paddingLen ^ mask&b
+ }
+
+ // We AND together the bits of good and replicate the result across
+ // all the bits.
+ good &= good << 4
+ good &= good << 2
+ good &= good << 1
+ good = uint8(int8(good) >> 7)
+
+ // Zero the padding length on error. This ensures any unchecked bytes
+ // are included in the MAC. Otherwise, an attacker that could
+ // distinguish MAC failures from padding failures could mount an attack
+ // similar to POODLE in SSL 3.0: given a good ciphertext that uses a
+ // full block's worth of padding, replace the final block with another
+ // block. If the MAC check passed but the padding check failed, the
+ // last byte of that block decrypted to the block size.
+ //
+ // See also macAndPaddingGood logic below.
+ paddingLen &= good
+
+ toRemove = int(paddingLen) + 1
+ return
+}
+
+func roundUp(a, b int) int {
+ return a + (b-a%b)%b
+}
+
+// cbcMode is an interface for block ciphers using cipher block chaining.
+type cbcMode interface {
+ cipher.BlockMode
+ SetIV([]byte)
+}
+
+// decrypt authenticates and decrypts the record if protection is active at
+// this stage. The returned plaintext might overlap with the input.
+func (hc *halfConn) decrypt(record []byte) ([]byte, recordType, error) {
+ var plaintext []byte
+ typ := recordType(record[0])
+ payload := record[recordHeaderLen:]
+
+ // In TLS 1.3, change_cipher_spec messages are to be ignored without being
+ // decrypted. See RFC 8446, Appendix D.4.
+ if hc.version == VersionTLS13 && typ == recordTypeChangeCipherSpec {
+ return payload, typ, nil
+ }
+
+ paddingGood := byte(255)
+ paddingLen := 0
+
+ explicitNonceLen := hc.explicitNonceLen()
+
+ if hc.cipher != nil {
+ switch c := hc.cipher.(type) {
+ case cipher.Stream:
+ c.XORKeyStream(payload, payload)
+ case aead:
+ if len(payload) < explicitNonceLen {
+ return nil, 0, alertBadRecordMAC
+ }
+ nonce := payload[:explicitNonceLen]
+ if len(nonce) == 0 {
+ nonce = hc.seq[:]
+ }
+ payload = payload[explicitNonceLen:]
+
+ var additionalData []byte
+ if hc.version == VersionTLS13 {
+ additionalData = record[:recordHeaderLen]
+ } else {
+ additionalData = append(hc.scratchBuf[:0], hc.seq[:]...)
+ additionalData = append(additionalData, record[:3]...)
+ n := len(payload) - c.Overhead()
+ additionalData = append(additionalData, byte(n>>8), byte(n))
+ }
+
+ var err error
+ plaintext, err = c.Open(payload[:0], nonce, payload, additionalData)
+ if err != nil {
+ return nil, 0, alertBadRecordMAC
+ }
+ case cbcMode:
+ blockSize := c.BlockSize()
+ minPayload := explicitNonceLen + roundUp(hc.mac.Size()+1, blockSize)
+ if len(payload)%blockSize != 0 || len(payload) < minPayload {
+ return nil, 0, alertBadRecordMAC
+ }
+
+ if explicitNonceLen > 0 {
+ c.SetIV(payload[:explicitNonceLen])
+ payload = payload[explicitNonceLen:]
+ }
+ c.CryptBlocks(payload, payload)
+
+ // In a limited attempt to protect against CBC padding oracles like
+ // Lucky13, the data past paddingLen (which is secret) is passed to
+ // the MAC function as extra data, to be fed into the HMAC after
+ // computing the digest. This makes the MAC roughly constant time as
+ // long as the digest computation is constant time and does not
+ // affect the subsequent write, modulo cache effects.
+ paddingLen, paddingGood = extractPadding(payload)
+ default:
+ panic("unknown cipher type")
+ }
+
+ if hc.version == VersionTLS13 {
+ if typ != recordTypeApplicationData {
+ return nil, 0, alertUnexpectedMessage
+ }
+ if len(plaintext) > maxPlaintext+1 {
+ return nil, 0, alertRecordOverflow
+ }
+ // Remove padding and find the ContentType scanning from the end.
+ for i := len(plaintext) - 1; i >= 0; i-- {
+ if plaintext[i] != 0 {
+ typ = recordType(plaintext[i])
+ plaintext = plaintext[:i]
+ break
+ }
+ if i == 0 {
+ return nil, 0, alertUnexpectedMessage
+ }
+ }
+ }
+ } else {
+ plaintext = payload
+ }
+
+ if hc.mac != nil {
+ macSize := hc.mac.Size()
+ if len(payload) < macSize {
+ return nil, 0, alertBadRecordMAC
+ }
+
+ n := len(payload) - macSize - paddingLen
+ n = subtle.ConstantTimeSelect(int(uint32(n)>>31), 0, n) // if n < 0 { n = 0 }
+ record[3] = byte(n >> 8)
+ record[4] = byte(n)
+ remoteMAC := payload[n : n+macSize]
+ localMAC := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload[:n], payload[n+macSize:])
+
+ // This is equivalent to checking the MACs and paddingGood
+ // separately, but in constant-time to prevent distinguishing
+ // padding failures from MAC failures. Depending on what value
+ // of paddingLen was returned on bad padding, distinguishing
+ // bad MAC from bad padding can lead to an attack.
+ //
+ // See also the logic at the end of extractPadding.
+ macAndPaddingGood := subtle.ConstantTimeCompare(localMAC, remoteMAC) & int(paddingGood)
+ if macAndPaddingGood != 1 {
+ return nil, 0, alertBadRecordMAC
+ }
+
+ plaintext = payload[:n]
+ }
+
+ hc.incSeq()
+ return plaintext, typ, nil
+}
+
+// sliceForAppend extends the input slice by n bytes. head is the full extended
+// slice, while tail is the appended part. If the original slice has sufficient
+// capacity no allocation is performed.
+func sliceForAppend(in []byte, n int) (head, tail []byte) {
+ if total := len(in) + n; cap(in) >= total {
+ head = in[:total]
+ } else {
+ head = make([]byte, total)
+ copy(head, in)
+ }
+ tail = head[len(in):]
+ return
+}
+
+// encrypt encrypts payload, adding the appropriate nonce and/or MAC, and
+// appends it to record, which must already contain the record header.
+func (hc *halfConn) encrypt(record, payload []byte, rand io.Reader) ([]byte, error) {
+ if hc.cipher == nil {
+ return append(record, payload...), nil
+ }
+
+ var explicitNonce []byte
+ if explicitNonceLen := hc.explicitNonceLen(); explicitNonceLen > 0 {
+ record, explicitNonce = sliceForAppend(record, explicitNonceLen)
+ if _, isCBC := hc.cipher.(cbcMode); !isCBC && explicitNonceLen < 16 {
+ // The AES-GCM construction in TLS has an explicit nonce so that the
+ // nonce can be random. However, the nonce is only 8 bytes which is
+ // too small for a secure, random nonce. Therefore we use the
+ // sequence number as the nonce. The 3DES-CBC construction also has
+ // an 8 bytes nonce but its nonces must be unpredictable (see RFC
+ // 5246, Appendix F.3), forcing us to use randomness. That's not
+ // 3DES' biggest problem anyway because the birthday bound on block
+ // collision is reached first due to its similarly small block size
+ // (see the Sweet32 attack).
+ copy(explicitNonce, hc.seq[:])
+ } else {
+ if _, err := io.ReadFull(rand, explicitNonce); err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ var dst []byte
+ switch c := hc.cipher.(type) {
+ case cipher.Stream:
+ mac := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload, nil)
+ record, dst = sliceForAppend(record, len(payload)+len(mac))
+ c.XORKeyStream(dst[:len(payload)], payload)
+ c.XORKeyStream(dst[len(payload):], mac)
+ case aead:
+ nonce := explicitNonce
+ if len(nonce) == 0 {
+ nonce = hc.seq[:]
+ }
+
+ if hc.version == VersionTLS13 {
+ record = append(record, payload...)
+
+ // Encrypt the actual ContentType and replace the plaintext one.
+ record = append(record, record[0])
+ record[0] = byte(recordTypeApplicationData)
+
+ n := len(payload) + 1 + c.Overhead()
+ record[3] = byte(n >> 8)
+ record[4] = byte(n)
+
+ record = c.Seal(record[:recordHeaderLen],
+ nonce, record[recordHeaderLen:], record[:recordHeaderLen])
+ } else {
+ additionalData := append(hc.scratchBuf[:0], hc.seq[:]...)
+ additionalData = append(additionalData, record[:recordHeaderLen]...)
+ record = c.Seal(record, nonce, payload, additionalData)
+ }
+ case cbcMode:
+ mac := tls10MAC(hc.mac, hc.scratchBuf[:0], hc.seq[:], record[:recordHeaderLen], payload, nil)
+ blockSize := c.BlockSize()
+ plaintextLen := len(payload) + len(mac)
+ paddingLen := blockSize - plaintextLen%blockSize
+ record, dst = sliceForAppend(record, plaintextLen+paddingLen)
+ copy(dst, payload)
+ copy(dst[len(payload):], mac)
+ for i := plaintextLen; i < len(dst); i++ {
+ dst[i] = byte(paddingLen - 1)
+ }
+ if len(explicitNonce) > 0 {
+ c.SetIV(explicitNonce)
+ }
+ c.CryptBlocks(dst, dst)
+ default:
+ panic("unknown cipher type")
+ }
+
+ // Update length to include nonce, MAC and any block padding needed.
+ n := len(record) - recordHeaderLen
+ record[3] = byte(n >> 8)
+ record[4] = byte(n)
+ hc.incSeq()
+
+ return record, nil
+}
+
+// RecordHeaderError is returned when a TLS record header is invalid.
+type RecordHeaderError struct {
+ // Msg contains a human readable string that describes the error.
+ Msg string
+ // RecordHeader contains the five bytes of TLS record header that
+ // triggered the error.
+ RecordHeader [5]byte
+ // Conn provides the underlying net.Conn in the case that a client
+ // sent an initial handshake that didn't look like TLS.
+ // It is nil if there's already been a handshake or a TLS alert has
+ // been written to the connection.
+ Conn net.Conn
+}
+
+func (e RecordHeaderError) Error() string { return "tls: " + e.Msg }
+
+func (c *Conn) newRecordHeaderError(conn net.Conn, msg string) (err RecordHeaderError) {
+ err.Msg = msg
+ err.Conn = conn
+ copy(err.RecordHeader[:], c.rawInput.Bytes())
+ return err
+}
+
+func (c *Conn) readRecord() error {
+ return c.readRecordOrCCS(false)
+}
+
+func (c *Conn) readChangeCipherSpec() error {
+ return c.readRecordOrCCS(true)
+}
+
+// readRecordOrCCS reads one or more TLS records from the connection and
+// updates the record layer state. Some invariants:
+// - c.in must be locked
+// - c.input must be empty
+//
+// During the handshake one and only one of the following will happen:
+// - c.hand grows
+// - c.in.changeCipherSpec is called
+// - an error is returned
+//
+// After the handshake one and only one of the following will happen:
+// - c.hand grows
+// - c.input is set
+// - an error is returned
+func (c *Conn) readRecordOrCCS(expectChangeCipherSpec bool) error {
+ if c.in.err != nil {
+ return c.in.err
+ }
+ handshakeComplete := c.isHandshakeComplete.Load()
+
+ // This function modifies c.rawInput, which owns the c.input memory.
+ if c.input.Len() != 0 {
+ return c.in.setErrorLocked(errors.New("tls: internal error: attempted to read record with pending application data"))
+ }
+ c.input.Reset(nil)
+
+ // Read header, payload.
+ if err := c.readFromUntil(c.conn, recordHeaderLen); err != nil {
+ // RFC 8446, Section 6.1 suggests that EOF without an alertCloseNotify
+ // is an error, but popular web sites seem to do this, so we accept it
+ // if and only if at the record boundary.
+ if err == io.ErrUnexpectedEOF && c.rawInput.Len() == 0 {
+ err = io.EOF
+ }
+ if e, ok := err.(net.Error); !ok || !e.Temporary() {
+ c.in.setErrorLocked(err)
+ }
+ return err
+ }
+ hdr := c.rawInput.Bytes()[:recordHeaderLen]
+ typ := recordType(hdr[0])
+
+ // No valid TLS record has a type of 0x80, however SSLv2 handshakes
+ // start with a uint16 length where the MSB is set and the first record
+ // is always < 256 bytes long. Therefore typ == 0x80 strongly suggests
+ // an SSLv2 client.
+ if !handshakeComplete && typ == 0x80 {
+ c.sendAlert(alertProtocolVersion)
+ return c.in.setErrorLocked(c.newRecordHeaderError(nil, "unsupported SSLv2 handshake received"))
+ }
+
+ vers := uint16(hdr[1])<<8 | uint16(hdr[2])
+ n := int(hdr[3])<<8 | int(hdr[4])
+ if c.haveVers && c.vers != VersionTLS13 && vers != c.vers {
+ c.sendAlert(alertProtocolVersion)
+ msg := fmt.Sprintf("received record with version %x when expecting version %x", vers, c.vers)
+ return c.in.setErrorLocked(c.newRecordHeaderError(nil, msg))
+ }
+ if !c.haveVers {
+ // First message, be extra suspicious: this might not be a TLS
+ // client. Bail out before reading a full 'body', if possible.
+ // The current max version is 3.3 so if the version is >= 16.0,
+ // it's probably not real.
+ if (typ != recordTypeAlert && typ != recordTypeHandshake) || vers >= 0x1000 {
+ return c.in.setErrorLocked(c.newRecordHeaderError(c.conn, "first record does not look like a TLS handshake"))
+ }
+ }
+ if c.vers == VersionTLS13 && n > maxCiphertextTLS13 || n > maxCiphertext {
+ c.sendAlert(alertRecordOverflow)
+ msg := fmt.Sprintf("oversized record received with length %d", n)
+ return c.in.setErrorLocked(c.newRecordHeaderError(nil, msg))
+ }
+ if err := c.readFromUntil(c.conn, recordHeaderLen+n); err != nil {
+ if e, ok := err.(net.Error); !ok || !e.Temporary() {
+ c.in.setErrorLocked(err)
+ }
+ return err
+ }
+
+ // Process message.
+ record := c.rawInput.Next(recordHeaderLen + n)
+ data, typ, err := c.in.decrypt(record)
+ if err != nil {
+ return c.in.setErrorLocked(c.sendAlert(err.(alert)))
+ }
+ if len(data) > maxPlaintext {
+ return c.in.setErrorLocked(c.sendAlert(alertRecordOverflow))
+ }
+
+ // Application Data messages are always protected.
+ if c.in.cipher == nil && typ == recordTypeApplicationData {
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+
+ if typ != recordTypeAlert && typ != recordTypeChangeCipherSpec && len(data) > 0 {
+ // This is a state-advancing message: reset the retry count.
+ c.retryCount = 0
+ }
+
+ // Handshake messages MUST NOT be interleaved with other record types in TLS 1.3.
+ if c.vers == VersionTLS13 && typ != recordTypeHandshake && c.hand.Len() > 0 {
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+
+ switch typ {
+ default:
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+
+ case recordTypeAlert:
+ if len(data) != 2 {
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+ if alert(data[1]) == alertCloseNotify {
+ return c.in.setErrorLocked(io.EOF)
+ }
+ if c.vers == VersionTLS13 {
+ return c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])})
+ }
+ switch data[0] {
+ case alertLevelWarning:
+ // Drop the record on the floor and retry.
+ return c.retryReadRecord(expectChangeCipherSpec)
+ case alertLevelError:
+ return c.in.setErrorLocked(&net.OpError{Op: "remote error", Err: alert(data[1])})
+ default:
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+
+ case recordTypeChangeCipherSpec:
+ if len(data) != 1 || data[0] != 1 {
+ return c.in.setErrorLocked(c.sendAlert(alertDecodeError))
+ }
+ // Handshake messages are not allowed to fragment across the CCS.
+ if c.hand.Len() > 0 {
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+ // In TLS 1.3, change_cipher_spec records are ignored until the
+ // Finished. See RFC 8446, Appendix D.4. Note that according to Section
+ // 5, a server can send a ChangeCipherSpec before its ServerHello, when
+ // c.vers is still unset. That's not useful though and suspicious if the
+ // server then selects a lower protocol version, so don't allow that.
+ if c.vers == VersionTLS13 {
+ return c.retryReadRecord(expectChangeCipherSpec)
+ }
+ if !expectChangeCipherSpec {
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+ if err := c.in.changeCipherSpec(); err != nil {
+ return c.in.setErrorLocked(c.sendAlert(err.(alert)))
+ }
+
+ case recordTypeApplicationData:
+ if !handshakeComplete || expectChangeCipherSpec {
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+ // Some OpenSSL servers send empty records in order to randomize the
+ // CBC IV. Ignore a limited number of empty records.
+ if len(data) == 0 {
+ return c.retryReadRecord(expectChangeCipherSpec)
+ }
+ // Note that data is owned by c.rawInput, following the Next call above,
+ // to avoid copying the plaintext. This is safe because c.rawInput is
+ // not read from or written to until c.input is drained.
+ c.input.Reset(data)
+
+ case recordTypeHandshake:
+ if len(data) == 0 || expectChangeCipherSpec {
+ return c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+ c.hand.Write(data)
+ }
+
+ return nil
+}
+
+// retryReadRecord recurs into readRecordOrCCS to drop a non-advancing record, like
+// a warning alert, empty application_data, or a change_cipher_spec in TLS 1.3.
+func (c *Conn) retryReadRecord(expectChangeCipherSpec bool) error {
+ c.retryCount++
+ if c.retryCount > maxUselessRecords {
+ c.sendAlert(alertUnexpectedMessage)
+ return c.in.setErrorLocked(errors.New("tls: too many ignored records"))
+ }
+ return c.readRecordOrCCS(expectChangeCipherSpec)
+}
+
+// atLeastReader reads from R, stopping with EOF once at least N bytes have been
+// read. It is different from an io.LimitedReader in that it doesn't cut short
+// the last Read call, and in that it considers an early EOF an error.
+type atLeastReader struct {
+ R io.Reader
+ N int64
+}
+
+func (r *atLeastReader) Read(p []byte) (int, error) {
+ if r.N <= 0 {
+ return 0, io.EOF
+ }
+ n, err := r.R.Read(p)
+ r.N -= int64(n) // won't underflow unless len(p) >= n > 9223372036854775809
+ if r.N > 0 && err == io.EOF {
+ return n, io.ErrUnexpectedEOF
+ }
+ if r.N <= 0 && err == nil {
+ return n, io.EOF
+ }
+ return n, err
+}
+
+// readFromUntil reads from r into c.rawInput until c.rawInput contains
+// at least n bytes or else returns an error.
+func (c *Conn) readFromUntil(r io.Reader, n int) error {
+ if c.rawInput.Len() >= n {
+ return nil
+ }
+ needs := n - c.rawInput.Len()
+ // There might be extra input waiting on the wire. Make a best effort
+ // attempt to fetch it so that it can be used in (*Conn).Read to
+ // "predict" closeNotify alerts.
+ c.rawInput.Grow(needs + bytes.MinRead)
+ _, err := c.rawInput.ReadFrom(&atLeastReader{r, int64(needs)})
+ return err
+}
+
+// sendAlert sends a TLS alert message.
+func (c *Conn) sendAlertLocked(err alert) error {
+ switch err {
+ case alertNoRenegotiation, alertCloseNotify:
+ c.tmp[0] = alertLevelWarning
+ default:
+ c.tmp[0] = alertLevelError
+ }
+ c.tmp[1] = byte(err)
+
+ _, writeErr := c.writeRecordLocked(recordTypeAlert, c.tmp[0:2])
+ if err == alertCloseNotify {
+ // closeNotify is a special case in that it isn't an error.
+ return writeErr
+ }
+
+ return c.out.setErrorLocked(&net.OpError{Op: "local error", Err: err})
+}
+
+// sendAlert sends a TLS alert message.
+func (c *Conn) sendAlert(err alert) error {
+ c.out.Lock()
+ defer c.out.Unlock()
+ return c.sendAlertLocked(err)
+}
+
+const (
+ // tcpMSSEstimate is a conservative estimate of the TCP maximum segment
+ // size (MSS). A constant is used, rather than querying the kernel for
+ // the actual MSS, to avoid complexity. The value here is the IPv6
+ // minimum MTU (1280 bytes) minus the overhead of an IPv6 header (40
+ // bytes) and a TCP header with timestamps (32 bytes).
+ tcpMSSEstimate = 1208
+
+ // recordSizeBoostThreshold is the number of bytes of application data
+ // sent after which the TLS record size will be increased to the
+ // maximum.
+ recordSizeBoostThreshold = 128 * 1024
+)
+
+// maxPayloadSizeForWrite returns the maximum TLS payload size to use for the
+// next application data record. There is the following trade-off:
+//
+// - For latency-sensitive applications, such as web browsing, each TLS
+// record should fit in one TCP segment.
+// - For throughput-sensitive applications, such as large file transfers,
+// larger TLS records better amortize framing and encryption overheads.
+//
+// A simple heuristic that works well in practice is to use small records for
+// the first 1MB of data, then use larger records for subsequent data, and
+// reset back to smaller records after the connection becomes idle. See "High
+// Performance Web Networking", Chapter 4, or:
+// https://www.igvita.com/2013/10/24/optimizing-tls-record-size-and-buffering-latency/
+//
+// In the interests of simplicity and determinism, this code does not attempt
+// to reset the record size once the connection is idle, however.
+func (c *Conn) maxPayloadSizeForWrite(typ recordType) int {
+ if c.config.DynamicRecordSizingDisabled || typ != recordTypeApplicationData {
+ return maxPlaintext
+ }
+
+ if c.bytesSent >= recordSizeBoostThreshold {
+ return maxPlaintext
+ }
+
+ // Subtract TLS overheads to get the maximum payload size.
+ payloadBytes := tcpMSSEstimate - recordHeaderLen - c.out.explicitNonceLen()
+ if c.out.cipher != nil {
+ switch ciph := c.out.cipher.(type) {
+ case cipher.Stream:
+ payloadBytes -= c.out.mac.Size()
+ case cipher.AEAD:
+ payloadBytes -= ciph.Overhead()
+ case cbcMode:
+ blockSize := ciph.BlockSize()
+ // The payload must fit in a multiple of blockSize, with
+ // room for at least one padding byte.
+ payloadBytes = (payloadBytes & ^(blockSize - 1)) - 1
+ // The MAC is appended before padding so affects the
+ // payload size directly.
+ payloadBytes -= c.out.mac.Size()
+ default:
+ panic("unknown cipher type")
+ }
+ }
+ if c.vers == VersionTLS13 {
+ payloadBytes-- // encrypted ContentType
+ }
+
+ // Allow packet growth in arithmetic progression up to max.
+ pkt := c.packetsSent
+ c.packetsSent++
+ if pkt > 1000 {
+ return maxPlaintext // avoid overflow in multiply below
+ }
+
+ n := payloadBytes * int(pkt+1)
+ if n > maxPlaintext {
+ n = maxPlaintext
+ }
+ return n
+}
+
+func (c *Conn) write(data []byte) (int, error) {
+ if c.buffering {
+ c.sendBuf = append(c.sendBuf, data...)
+ return len(data), nil
+ }
+
+ n, err := c.conn.Write(data)
+ c.bytesSent += int64(n)
+ return n, err
+}
+
+func (c *Conn) flush() (int, error) {
+ if len(c.sendBuf) == 0 {
+ return 0, nil
+ }
+
+ n, err := c.conn.Write(c.sendBuf)
+ c.bytesSent += int64(n)
+ c.sendBuf = nil
+ c.buffering = false
+ return n, err
+}
+
+// outBufPool pools the record-sized scratch buffers used by writeRecordLocked.
+var outBufPool = sync.Pool{
+ New: func() any {
+ return new([]byte)
+ },
+}
+
+// writeRecordLocked writes a TLS record with the given type and payload to the
+// connection and updates the record layer state.
+func (c *Conn) writeRecordLocked(typ recordType, data []byte) (int, error) {
+ outBufPtr := outBufPool.Get().(*[]byte)
+ outBuf := *outBufPtr
+ defer func() {
+ // You might be tempted to simplify this by just passing &outBuf to Put,
+ // but that would make the local copy of the outBuf slice header escape
+ // to the heap, causing an allocation. Instead, we keep around the
+ // pointer to the slice header returned by Get, which is already on the
+ // heap, and overwrite and return that.
+ *outBufPtr = outBuf
+ outBufPool.Put(outBufPtr)
+ }()
+
+ var n int
+ for len(data) > 0 {
+ m := len(data)
+ if maxPayload := c.maxPayloadSizeForWrite(typ); m > maxPayload {
+ m = maxPayload
+ }
+
+ _, outBuf = sliceForAppend(outBuf[:0], recordHeaderLen)
+ outBuf[0] = byte(typ)
+ vers := c.vers
+ if vers == 0 {
+ // Some TLS servers fail if the record version is
+ // greater than TLS 1.0 for the initial ClientHello.
+ vers = VersionTLS10
+ } else if vers == VersionTLS13 {
+ // TLS 1.3 froze the record layer version to 1.2.
+ // See RFC 8446, Section 5.1.
+ vers = VersionTLS12
+ }
+ outBuf[1] = byte(vers >> 8)
+ outBuf[2] = byte(vers)
+ outBuf[3] = byte(m >> 8)
+ outBuf[4] = byte(m)
+
+ var err error
+ outBuf, err = c.out.encrypt(outBuf, data[:m], c.config.rand())
+ if err != nil {
+ return n, err
+ }
+ if _, err := c.write(outBuf); err != nil {
+ return n, err
+ }
+ n += m
+ data = data[m:]
+ }
+
+ if typ == recordTypeChangeCipherSpec && c.vers != VersionTLS13 {
+ if err := c.out.changeCipherSpec(); err != nil {
+ return n, c.sendAlertLocked(err.(alert))
+ }
+ }
+
+ return n, nil
+}
+
+// writeHandshakeRecord writes a handshake message to the connection and updates
+// the record layer state. If transcript is non-nil the marshalled message is
+// written to it.
+func (c *Conn) writeHandshakeRecord(msg handshakeMessage, transcript transcriptHash) (int, error) {
+ c.out.Lock()
+ defer c.out.Unlock()
+
+ data, err := msg.marshal()
+ if err != nil {
+ return 0, err
+ }
+ if transcript != nil {
+ transcript.Write(data)
+ }
+
+ return c.writeRecordLocked(recordTypeHandshake, data)
+}
+
+// writeChangeCipherRecord writes a ChangeCipherSpec message to the connection and
+// updates the record layer state.
+func (c *Conn) writeChangeCipherRecord() error {
+ c.out.Lock()
+ defer c.out.Unlock()
+ _, err := c.writeRecordLocked(recordTypeChangeCipherSpec, []byte{1})
+ return err
+}
+
+// readHandshake reads the next handshake message from
+// the record layer. If transcript is non-nil, the message
+// is written to the passed transcriptHash.
+func (c *Conn) readHandshake(transcript transcriptHash) (any, error) {
+ for c.hand.Len() < 4 {
+ if err := c.readRecord(); err != nil {
+ return nil, err
+ }
+ }
+
+ data := c.hand.Bytes()
+ n := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+ if n > maxHandshake {
+ c.sendAlertLocked(alertInternalError)
+ return nil, c.in.setErrorLocked(fmt.Errorf("tls: handshake message of length %d bytes exceeds maximum of %d bytes", n, maxHandshake))
+ }
+ for c.hand.Len() < 4+n {
+ if err := c.readRecord(); err != nil {
+ return nil, err
+ }
+ }
+ data = c.hand.Next(4 + n)
+ var m handshakeMessage
+ switch data[0] {
+ case typeHelloRequest:
+ m = new(helloRequestMsg)
+ case typeClientHello:
+ m = new(clientHelloMsg)
+ case typeServerHello:
+ m = new(serverHelloMsg)
+ case typeNewSessionTicket:
+ if c.vers == VersionTLS13 {
+ m = new(newSessionTicketMsgTLS13)
+ } else {
+ m = new(newSessionTicketMsg)
+ }
+ case typeCertificate:
+ if c.vers == VersionTLS13 {
+ m = new(certificateMsgTLS13)
+ } else {
+ m = new(certificateMsg)
+ }
+ case typeCertificateRequest:
+ if c.vers == VersionTLS13 {
+ m = new(certificateRequestMsgTLS13)
+ } else {
+ m = &certificateRequestMsg{
+ hasSignatureAlgorithm: c.vers >= VersionTLS12,
+ }
+ }
+ case typeCertificateStatus:
+ m = new(certificateStatusMsg)
+ case typeServerKeyExchange:
+ m = new(serverKeyExchangeMsg)
+ case typeServerHelloDone:
+ m = new(serverHelloDoneMsg)
+ case typeClientKeyExchange:
+ m = new(clientKeyExchangeMsg)
+ case typeCertificateVerify:
+ m = &certificateVerifyMsg{
+ hasSignatureAlgorithm: c.vers >= VersionTLS12,
+ }
+ case typeFinished:
+ m = new(finishedMsg)
+ case typeEncryptedExtensions:
+ m = new(encryptedExtensionsMsg)
+ case typeEndOfEarlyData:
+ m = new(endOfEarlyDataMsg)
+ case typeKeyUpdate:
+ m = new(keyUpdateMsg)
+ default:
+ return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+
+ // The handshake message unmarshalers
+ // expect to be able to keep references to data,
+ // so pass in a fresh copy that won't be overwritten.
+ data = append([]byte(nil), data...)
+
+ if !m.unmarshal(data) {
+ return nil, c.in.setErrorLocked(c.sendAlert(alertUnexpectedMessage))
+ }
+
+ if transcript != nil {
+ transcript.Write(data)
+ }
+
+ return m, nil
+}
+
+var (
+ errShutdown = errors.New("tls: protocol is shutdown")
+)
+
+// Write writes data to the connection.
+//
+// As Write calls Handshake, in order to prevent indefinite blocking a deadline
+// must be set for both Read and Write before Write is called when the handshake
+// has not yet completed. See SetDeadline, SetReadDeadline, and
+// SetWriteDeadline.
+func (c *Conn) Write(b []byte) (int, error) {
+ // interlock with Close below
+ for {
+ x := c.activeCall.Load()
+ if x&1 != 0 {
+ return 0, net.ErrClosed
+ }
+ if c.activeCall.CompareAndSwap(x, x+2) {
+ break
+ }
+ }
+ defer c.activeCall.Add(-2)
+
+ if err := c.Handshake(); err != nil {
+ return 0, err
+ }
+
+ c.out.Lock()
+ defer c.out.Unlock()
+
+ if err := c.out.err; err != nil {
+ return 0, err
+ }
+
+ if !c.isHandshakeComplete.Load() {
+ return 0, alertInternalError
+ }
+
+ if c.closeNotifySent {
+ return 0, errShutdown
+ }
+
+ // TLS 1.0 is susceptible to a chosen-plaintext
+ // attack when using block mode ciphers due to predictable IVs.
+ // This can be prevented by splitting each Application Data
+ // record into two records, effectively randomizing the IV.
+ //
+ // https://www.openssl.org/~bodo/tls-cbc.txt
+ // https://bugzilla.mozilla.org/show_bug.cgi?id=665814
+ // https://www.imperialviolet.org/2012/01/15/beastfollowup.html
+
+ var m int
+ if len(b) > 1 && c.vers == VersionTLS10 {
+ if _, ok := c.out.cipher.(cipher.BlockMode); ok {
+ n, err := c.writeRecordLocked(recordTypeApplicationData, b[:1])
+ if err != nil {
+ return n, c.out.setErrorLocked(err)
+ }
+ m, b = 1, b[1:]
+ }
+ }
+
+ n, err := c.writeRecordLocked(recordTypeApplicationData, b)
+ return n + m, c.out.setErrorLocked(err)
+}
+
+// handleRenegotiation processes a HelloRequest handshake message.
+func (c *Conn) handleRenegotiation() error {
+ if c.vers == VersionTLS13 {
+ return errors.New("tls: internal error: unexpected renegotiation")
+ }
+
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ helloReq, ok := msg.(*helloRequestMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(helloReq, msg)
+ }
+
+ if !c.isClient {
+ return c.sendAlert(alertNoRenegotiation)
+ }
+
+ switch c.config.Renegotiation {
+ case RenegotiateNever:
+ return c.sendAlert(alertNoRenegotiation)
+ case RenegotiateOnceAsClient:
+ if c.handshakes > 1 {
+ return c.sendAlert(alertNoRenegotiation)
+ }
+ case RenegotiateFreelyAsClient:
+ // Ok.
+ default:
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: unknown Renegotiation value")
+ }
+
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ c.isHandshakeComplete.Store(false)
+ if c.handshakeErr = c.clientHandshake(context.Background()); c.handshakeErr == nil {
+ c.handshakes++
+ }
+ return c.handshakeErr
+}
+
+// handlePostHandshakeMessage processes a handshake message arrived after the
+// handshake is complete. Up to TLS 1.2, it indicates the start of a renegotiation.
+func (c *Conn) handlePostHandshakeMessage() error {
+ if c.vers != VersionTLS13 {
+ return c.handleRenegotiation()
+ }
+
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ c.retryCount++
+ if c.retryCount > maxUselessRecords {
+ c.sendAlert(alertUnexpectedMessage)
+ return c.in.setErrorLocked(errors.New("tls: too many non-advancing records"))
+ }
+
+ switch msg := msg.(type) {
+ case *newSessionTicketMsgTLS13:
+ return c.handleNewSessionTicket(msg)
+ case *keyUpdateMsg:
+ return c.handleKeyUpdate(msg)
+ default:
+ c.sendAlert(alertUnexpectedMessage)
+ return fmt.Errorf("tls: received unexpected handshake message of type %T", msg)
+ }
+}
+
+func (c *Conn) handleKeyUpdate(keyUpdate *keyUpdateMsg) error {
+ cipherSuite := cipherSuiteTLS13ByID(c.cipherSuite)
+ if cipherSuite == nil {
+ return c.in.setErrorLocked(c.sendAlert(alertInternalError))
+ }
+
+ newSecret := cipherSuite.nextTrafficSecret(c.in.trafficSecret)
+ c.in.setTrafficSecret(cipherSuite, newSecret)
+
+ if keyUpdate.updateRequested {
+ c.out.Lock()
+ defer c.out.Unlock()
+
+ msg := &keyUpdateMsg{}
+ msgBytes, err := msg.marshal()
+ if err != nil {
+ return err
+ }
+ _, err = c.writeRecordLocked(recordTypeHandshake, msgBytes)
+ if err != nil {
+ // Surface the error at the next write.
+ c.out.setErrorLocked(err)
+ return nil
+ }
+
+ newSecret := cipherSuite.nextTrafficSecret(c.out.trafficSecret)
+ c.out.setTrafficSecret(cipherSuite, newSecret)
+ }
+
+ return nil
+}
+
+// Read reads data from the connection.
+//
+// As Read calls Handshake, in order to prevent indefinite blocking a deadline
+// must be set for both Read and Write before Read is called when the handshake
+// has not yet completed. See SetDeadline, SetReadDeadline, and
+// SetWriteDeadline.
+func (c *Conn) Read(b []byte) (int, error) {
+ if err := c.Handshake(); err != nil {
+ return 0, err
+ }
+ if len(b) == 0 {
+ // Put this after Handshake, in case people were calling
+ // Read(nil) for the side effect of the Handshake.
+ return 0, nil
+ }
+
+ c.in.Lock()
+ defer c.in.Unlock()
+
+ for c.input.Len() == 0 {
+ if err := c.readRecord(); err != nil {
+ return 0, err
+ }
+ for c.hand.Len() > 0 {
+ if err := c.handlePostHandshakeMessage(); err != nil {
+ return 0, err
+ }
+ }
+ }
+
+ n, _ := c.input.Read(b)
+
+ // If a close-notify alert is waiting, read it so that we can return (n,
+ // EOF) instead of (n, nil), to signal to the HTTP response reading
+ // goroutine that the connection is now closed. This eliminates a race
+ // where the HTTP response reading goroutine would otherwise not observe
+ // the EOF until its next read, by which time a client goroutine might
+ // have already tried to reuse the HTTP connection for a new request.
+ // See https://golang.org/cl/76400046 and https://golang.org/issue/3514
+ if n != 0 && c.input.Len() == 0 && c.rawInput.Len() > 0 &&
+ recordType(c.rawInput.Bytes()[0]) == recordTypeAlert {
+ if err := c.readRecord(); err != nil {
+ return n, err // will be io.EOF on closeNotify
+ }
+ }
+
+ return n, nil
+}
+
+// Close closes the connection.
+func (c *Conn) Close() error {
+ // Interlock with Conn.Write above.
+ var x int32
+ for {
+ x = c.activeCall.Load()
+ if x&1 != 0 {
+ return net.ErrClosed
+ }
+ if c.activeCall.CompareAndSwap(x, x|1) {
+ break
+ }
+ }
+ if x != 0 {
+ // io.Writer and io.Closer should not be used concurrently.
+ // If Close is called while a Write is currently in-flight,
+ // interpret that as a sign that this Close is really just
+ // being used to break the Write and/or clean up resources and
+ // avoid sending the alertCloseNotify, which may block
+ // waiting on handshakeMutex or the c.out mutex.
+ return c.conn.Close()
+ }
+
+ var alertErr error
+ if c.isHandshakeComplete.Load() {
+ if err := c.closeNotify(); err != nil {
+ alertErr = fmt.Errorf("tls: failed to send closeNotify alert (but connection was closed anyway): %w", err)
+ }
+ }
+
+ if err := c.conn.Close(); err != nil {
+ return err
+ }
+ return alertErr
+}
+
+var errEarlyCloseWrite = errors.New("tls: CloseWrite called before handshake complete")
+
+// CloseWrite shuts down the writing side of the connection. It should only be
+// called once the handshake has completed and does not call CloseWrite on the
+// underlying connection. Most callers should just use Close.
+func (c *Conn) CloseWrite() error {
+ if !c.isHandshakeComplete.Load() {
+ return errEarlyCloseWrite
+ }
+
+ return c.closeNotify()
+}
+
+func (c *Conn) closeNotify() error {
+ c.out.Lock()
+ defer c.out.Unlock()
+
+ if !c.closeNotifySent {
+ // Set a Write Deadline to prevent possibly blocking forever.
+ c.SetWriteDeadline(time.Now().Add(time.Second * 5))
+ c.closeNotifyErr = c.sendAlertLocked(alertCloseNotify)
+ c.closeNotifySent = true
+ // Any subsequent writes will fail.
+ c.SetWriteDeadline(time.Now())
+ }
+ return c.closeNotifyErr
+}
+
+// Handshake runs the client or server handshake
+// protocol if it has not yet been run.
+//
+// Most uses of this package need not call Handshake explicitly: the
+// first Read or Write will call it automatically.
+//
+// For control over canceling or setting a timeout on a handshake, use
+// HandshakeContext or the Dialer's DialContext method instead.
+//
+// In order to avoid denial of service attacks, the maximum RSA key size allowed
+// in certificates sent by either the TLS server or client is limited to 8192
+// bits. This limit can be overridden by setting tlsmaxrsasize in the GODEBUG
+// environment variable (e.g. GODEBUG=tlsmaxrsasize=4096).
+func (c *Conn) Handshake() error {
+ return c.HandshakeContext(context.Background())
+}
+
+// HandshakeContext runs the client or server handshake
+// protocol if it has not yet been run.
+//
+// The provided Context must be non-nil. If the context is canceled before
+// the handshake is complete, the handshake is interrupted and an error is returned.
+// Once the handshake has completed, cancellation of the context will not affect the
+// connection.
+//
+// Most uses of this package need not call HandshakeContext explicitly: the
+// first Read or Write will call it automatically.
+func (c *Conn) HandshakeContext(ctx context.Context) error {
+ // Delegate to unexported method for named return
+ // without confusing documented signature.
+ return c.handshakeContext(ctx)
+}
+
+func (c *Conn) handshakeContext(ctx context.Context) (ret error) {
+ // Fast sync/atomic-based exit if there is no handshake in flight and the
+ // last one succeeded without an error. Avoids the expensive context setup
+ // and mutex for most Read and Write calls.
+ if c.isHandshakeComplete.Load() {
+ return nil
+ }
+
+ handshakeCtx, cancel := context.WithCancel(ctx)
+ // Note: defer this before starting the "interrupter" goroutine
+ // so that we can tell the difference between the input being canceled and
+ // this cancellation. In the former case, we need to close the connection.
+ defer cancel()
+
+ // Start the "interrupter" goroutine, if this context might be canceled.
+ // (The background context cannot).
+ //
+ // The interrupter goroutine waits for the input context to be done and
+ // closes the connection if this happens before the function returns.
+ if ctx.Done() != nil {
+ done := make(chan struct{})
+ interruptRes := make(chan error, 1)
+ defer func() {
+ close(done)
+ if ctxErr := <-interruptRes; ctxErr != nil {
+ // Return context error to user.
+ ret = ctxErr
+ }
+ }()
+ go func() {
+ select {
+ case <-handshakeCtx.Done():
+ // Close the connection, discarding the error
+ _ = c.conn.Close()
+ interruptRes <- handshakeCtx.Err()
+ case <-done:
+ interruptRes <- nil
+ }
+ }()
+ }
+
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ if err := c.handshakeErr; err != nil {
+ return err
+ }
+ if c.isHandshakeComplete.Load() {
+ return nil
+ }
+
+ c.in.Lock()
+ defer c.in.Unlock()
+
+ c.handshakeErr = c.handshakeFn(handshakeCtx)
+ if c.handshakeErr == nil {
+ c.handshakes++
+ } else {
+ // If an error occurred during the handshake try to flush the
+ // alert that might be left in the buffer.
+ c.flush()
+ }
+
+ if c.handshakeErr == nil && !c.isHandshakeComplete.Load() {
+ c.handshakeErr = errors.New("tls: internal error: handshake should have had a result")
+ }
+ if c.handshakeErr != nil && c.isHandshakeComplete.Load() {
+ panic("tls: internal error: handshake returned an error but is marked successful")
+ }
+
+ return c.handshakeErr
+}
+
+// ConnectionState returns basic TLS details about the connection.
+func (c *Conn) ConnectionState() ConnectionState {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+ return c.connectionStateLocked()
+}
+
+func (c *Conn) connectionStateLocked() ConnectionState {
+ var state ConnectionState
+ state.HandshakeComplete = c.isHandshakeComplete.Load()
+ state.Version = c.vers
+ state.NegotiatedProtocol = c.clientProtocol
+ state.DidResume = c.didResume
+ state.NegotiatedProtocolIsMutual = true
+ state.ServerName = c.serverName
+ state.CipherSuite = c.cipherSuite
+ state.PeerCertificates = c.peerCertificates
+ state.VerifiedChains = c.verifiedChains
+ state.SignedCertificateTimestamps = c.scts
+ state.OCSPResponse = c.ocspResponse
+ if !c.didResume && c.vers != VersionTLS13 {
+ if c.clientFinishedIsFirst {
+ state.TLSUnique = c.clientFinished[:]
+ } else {
+ state.TLSUnique = c.serverFinished[:]
+ }
+ }
+ if c.config.Renegotiation != RenegotiateNever {
+ state.ekm = noExportedKeyingMaterial
+ } else {
+ state.ekm = c.ekm
+ }
+ return state
+}
+
+// OCSPResponse returns the stapled OCSP response from the TLS server, if
+// any. (Only valid for client connections.)
+func (c *Conn) OCSPResponse() []byte {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+
+ return c.ocspResponse
+}
+
+// VerifyHostname checks that the peer certificate chain is valid for
+// connecting to host. If so, it returns nil; if not, it returns an error
+// describing the problem.
+func (c *Conn) VerifyHostname(host string) error {
+ c.handshakeMutex.Lock()
+ defer c.handshakeMutex.Unlock()
+ if !c.isClient {
+ return errors.New("tls: VerifyHostname called on TLS server connection")
+ }
+ if !c.isHandshakeComplete.Load() {
+ return errors.New("tls: handshake has not yet been performed")
+ }
+ if len(c.verifiedChains) == 0 {
+ return errors.New("tls: handshake did not verify certificate chain")
+ }
+ return c.peerCertificates[0].VerifyHostname(host)
+}
diff --git a/src/crypto/tls/conn_test.go b/src/crypto/tls/conn_test.go
new file mode 100644
index 0000000..78935b1
--- /dev/null
+++ b/src/crypto/tls/conn_test.go
@@ -0,0 +1,287 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "bytes"
+ "io"
+ "net"
+ "testing"
+)
+
+func TestRoundUp(t *testing.T) {
+ if roundUp(0, 16) != 0 ||
+ roundUp(1, 16) != 16 ||
+ roundUp(15, 16) != 16 ||
+ roundUp(16, 16) != 16 ||
+ roundUp(17, 16) != 32 {
+ t.Error("roundUp broken")
+ }
+}
+
+// will be initialized with {0, 255, 255, ..., 255}
+var padding255Bad = [256]byte{}
+
+// will be initialized with {255, 255, 255, ..., 255}
+var padding255Good = [256]byte{255}
+
+var paddingTests = []struct {
+ in []byte
+ good bool
+ expectedLen int
+}{
+ {[]byte{1, 2, 3, 4, 0}, true, 4},
+ {[]byte{1, 2, 3, 4, 0, 1}, false, 0},
+ {[]byte{1, 2, 3, 4, 99, 99}, false, 0},
+ {[]byte{1, 2, 3, 4, 1, 1}, true, 4},
+ {[]byte{1, 2, 3, 2, 2, 2}, true, 3},
+ {[]byte{1, 2, 3, 3, 3, 3}, true, 2},
+ {[]byte{1, 2, 3, 4, 3, 3}, false, 0},
+ {[]byte{1, 4, 4, 4, 4, 4}, true, 1},
+ {[]byte{5, 5, 5, 5, 5, 5}, true, 0},
+ {[]byte{6, 6, 6, 6, 6, 6}, false, 0},
+ {padding255Bad[:], false, 0},
+ {padding255Good[:], true, 0},
+}
+
+func TestRemovePadding(t *testing.T) {
+ for i := 1; i < len(padding255Bad); i++ {
+ padding255Bad[i] = 255
+ padding255Good[i] = 255
+ }
+ for i, test := range paddingTests {
+ paddingLen, good := extractPadding(test.in)
+ expectedGood := byte(255)
+ if !test.good {
+ expectedGood = 0
+ }
+ if good != expectedGood {
+ t.Errorf("#%d: wrong validity, want:%d got:%d", i, expectedGood, good)
+ }
+ if good == 255 && len(test.in)-paddingLen != test.expectedLen {
+ t.Errorf("#%d: got %d, want %d", i, len(test.in)-paddingLen, test.expectedLen)
+ }
+ }
+}
+
+var certExampleCom = `308201713082011ba003020102021005a75ddf21014d5f417083b7a010ba2e300d06092a864886f70d01010b050030123110300e060355040a130741636d6520436f301e170d3136303831373231343135335a170d3137303831373231343135335a30123110300e060355040a130741636d6520436f305c300d06092a864886f70d0101010500034b003048024100b37f0fdd67e715bf532046ac34acbd8fdc4dabe2b598588f3f58b1f12e6219a16cbfe54d2b4b665396013589262360b6721efa27d546854f17cc9aeec6751db10203010001a34d304b300e0603551d0f0101ff0404030205a030130603551d25040c300a06082b06010505070301300c0603551d130101ff0402300030160603551d11040f300d820b6578616d706c652e636f6d300d06092a864886f70d01010b050003410059fc487866d3d855503c8e064ca32aac5e9babcece89ec597f8b2b24c17867f4a5d3b4ece06e795bfc5448ccbd2ffca1b3433171ebf3557a4737b020565350a0`
+
+var certWildcardExampleCom = `308201743082011ea003020102021100a7aa6297c9416a4633af8bec2958c607300d06092a864886f70d01010b050030123110300e060355040a130741636d6520436f301e170d3136303831373231343231395a170d3137303831373231343231395a30123110300e060355040a130741636d6520436f305c300d06092a864886f70d0101010500034b003048024100b105afc859a711ee864114e7d2d46c2dcbe392d3506249f6c2285b0eb342cc4bf2d803677c61c0abde443f084745c1a6d62080e5664ef2cc8f50ad8a0ab8870b0203010001a34f304d300e0603551d0f0101ff0404030205a030130603551d25040c300a06082b06010505070301300c0603551d130101ff0402300030180603551d110411300f820d2a2e6578616d706c652e636f6d300d06092a864886f70d01010b0500034100af26088584d266e3f6566360cf862c7fecc441484b098b107439543144a2b93f20781988281e108c6d7656934e56950e1e5f2bcf38796b814ccb729445856c34`
+
+var certFooExampleCom = `308201753082011fa00302010202101bbdb6070b0aeffc49008cde74deef29300d06092a864886f70d01010b050030123110300e060355040a130741636d6520436f301e170d3136303831373231343234345a170d3137303831373231343234345a30123110300e060355040a130741636d6520436f305c300d06092a864886f70d0101010500034b003048024100f00ac69d8ca2829f26216c7b50f1d4bbabad58d447706476cd89a2f3e1859943748aa42c15eedc93ac7c49e40d3b05ed645cb6b81c4efba60d961f44211a54eb0203010001a351304f300e0603551d0f0101ff0404030205a030130603551d25040c300a06082b06010505070301300c0603551d130101ff04023000301a0603551d1104133011820f666f6f2e6578616d706c652e636f6d300d06092a864886f70d01010b0500034100a0957fca6d1e0f1ef4b247348c7a8ca092c29c9c0ecc1898ea6b8065d23af6d922a410dd2335a0ea15edd1394cef9f62c9e876a21e35250a0b4fe1ddceba0f36`
+
+func TestCertificateSelection(t *testing.T) {
+ config := Config{
+ Certificates: []Certificate{
+ {
+ Certificate: [][]byte{fromHex(certExampleCom)},
+ },
+ {
+ Certificate: [][]byte{fromHex(certWildcardExampleCom)},
+ },
+ {
+ Certificate: [][]byte{fromHex(certFooExampleCom)},
+ },
+ },
+ }
+
+ config.BuildNameToCertificate()
+
+ pointerToIndex := func(c *Certificate) int {
+ for i := range config.Certificates {
+ if c == &config.Certificates[i] {
+ return i
+ }
+ }
+ return -1
+ }
+
+ certificateForName := func(name string) *Certificate {
+ clientHello := &ClientHelloInfo{
+ ServerName: name,
+ }
+ if cert, err := config.getCertificate(clientHello); err != nil {
+ t.Errorf("unable to get certificate for name '%s': %s", name, err)
+ return nil
+ } else {
+ return cert
+ }
+ }
+
+ if n := pointerToIndex(certificateForName("example.com")); n != 0 {
+ t.Errorf("example.com returned certificate %d, not 0", n)
+ }
+ if n := pointerToIndex(certificateForName("bar.example.com")); n != 1 {
+ t.Errorf("bar.example.com returned certificate %d, not 1", n)
+ }
+ if n := pointerToIndex(certificateForName("foo.example.com")); n != 2 {
+ t.Errorf("foo.example.com returned certificate %d, not 2", n)
+ }
+ if n := pointerToIndex(certificateForName("foo.bar.example.com")); n != 0 {
+ t.Errorf("foo.bar.example.com returned certificate %d, not 0", n)
+ }
+}
+
+// Run with multiple crypto configs to test the logic for computing TLS record overheads.
+func runDynamicRecordSizingTest(t *testing.T, config *Config) {
+ clientConn, serverConn := localPipe(t)
+
+ serverConfig := config.Clone()
+ serverConfig.DynamicRecordSizingDisabled = false
+ tlsConn := Server(serverConn, serverConfig)
+
+ handshakeDone := make(chan struct{})
+ recordSizesChan := make(chan []int, 1)
+ defer func() { <-recordSizesChan }() // wait for the goroutine to exit
+ go func() {
+ // This goroutine performs a TLS handshake over clientConn and
+ // then reads TLS records until EOF. It writes a slice that
+ // contains all the record sizes to recordSizesChan.
+ defer close(recordSizesChan)
+ defer clientConn.Close()
+
+ tlsConn := Client(clientConn, config)
+ if err := tlsConn.Handshake(); err != nil {
+ t.Errorf("Error from client handshake: %v", err)
+ return
+ }
+ close(handshakeDone)
+
+ var recordHeader [recordHeaderLen]byte
+ var record []byte
+ var recordSizes []int
+
+ for {
+ n, err := io.ReadFull(clientConn, recordHeader[:])
+ if err == io.EOF {
+ break
+ }
+ if err != nil || n != len(recordHeader) {
+ t.Errorf("io.ReadFull = %d, %v", n, err)
+ return
+ }
+
+ length := int(recordHeader[3])<<8 | int(recordHeader[4])
+ if len(record) < length {
+ record = make([]byte, length)
+ }
+
+ n, err = io.ReadFull(clientConn, record[:length])
+ if err != nil || n != length {
+ t.Errorf("io.ReadFull = %d, %v", n, err)
+ return
+ }
+
+ recordSizes = append(recordSizes, recordHeaderLen+length)
+ }
+
+ recordSizesChan <- recordSizes
+ }()
+
+ if err := tlsConn.Handshake(); err != nil {
+ t.Fatalf("Error from server handshake: %s", err)
+ }
+ <-handshakeDone
+
+ // The server writes these plaintexts in order.
+ plaintext := bytes.Join([][]byte{
+ bytes.Repeat([]byte("x"), recordSizeBoostThreshold),
+ bytes.Repeat([]byte("y"), maxPlaintext*2),
+ bytes.Repeat([]byte("z"), maxPlaintext),
+ }, nil)
+
+ if _, err := tlsConn.Write(plaintext); err != nil {
+ t.Fatalf("Error from server write: %s", err)
+ }
+ if err := tlsConn.Close(); err != nil {
+ t.Fatalf("Error from server close: %s", err)
+ }
+
+ recordSizes := <-recordSizesChan
+ if recordSizes == nil {
+ t.Fatalf("Client encountered an error")
+ }
+
+ // Drop the size of the second to last record, which is likely to be
+ // truncated, and the last record, which is a close_notify alert.
+ recordSizes = recordSizes[:len(recordSizes)-2]
+
+ // recordSizes should contain a series of records smaller than
+ // tcpMSSEstimate followed by some larger than maxPlaintext.
+ seenLargeRecord := false
+ for i, size := range recordSizes {
+ if !seenLargeRecord {
+ if size > (i+1)*tcpMSSEstimate {
+ t.Fatalf("Record #%d has size %d, which is too large too soon", i, size)
+ }
+ if size >= maxPlaintext {
+ seenLargeRecord = true
+ }
+ } else if size <= maxPlaintext {
+ t.Fatalf("Record #%d has size %d but should be full sized", i, size)
+ }
+ }
+
+ if !seenLargeRecord {
+ t.Fatalf("No large records observed")
+ }
+}
+
+func TestDynamicRecordSizingWithStreamCipher(t *testing.T) {
+ config := testConfig.Clone()
+ config.MaxVersion = VersionTLS12
+ config.CipherSuites = []uint16{TLS_RSA_WITH_RC4_128_SHA}
+ runDynamicRecordSizingTest(t, config)
+}
+
+func TestDynamicRecordSizingWithCBC(t *testing.T) {
+ config := testConfig.Clone()
+ config.MaxVersion = VersionTLS12
+ config.CipherSuites = []uint16{TLS_RSA_WITH_AES_256_CBC_SHA}
+ runDynamicRecordSizingTest(t, config)
+}
+
+func TestDynamicRecordSizingWithAEAD(t *testing.T) {
+ config := testConfig.Clone()
+ config.MaxVersion = VersionTLS12
+ config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256}
+ runDynamicRecordSizingTest(t, config)
+}
+
+func TestDynamicRecordSizingWithTLSv13(t *testing.T) {
+ config := testConfig.Clone()
+ runDynamicRecordSizingTest(t, config)
+}
+
+// hairpinConn is a net.Conn that makes a “hairpin” call when closed, back into
+// the tls.Conn which is calling it.
+type hairpinConn struct {
+ net.Conn
+ tlsConn *Conn
+}
+
+func (conn *hairpinConn) Close() error {
+ conn.tlsConn.ConnectionState()
+ return nil
+}
+
+func TestHairpinInClose(t *testing.T) {
+ // This tests that the underlying net.Conn can call back into the
+ // tls.Conn when being closed without deadlocking.
+ client, server := localPipe(t)
+ defer server.Close()
+ defer client.Close()
+
+ conn := &hairpinConn{client, nil}
+ tlsConn := Server(conn, &Config{
+ GetCertificate: func(*ClientHelloInfo) (*Certificate, error) {
+ panic("unreachable")
+ },
+ })
+ conn.tlsConn = tlsConn
+
+ // This call should not deadlock.
+ tlsConn.Close()
+}
diff --git a/src/crypto/tls/example_test.go b/src/crypto/tls/example_test.go
new file mode 100644
index 0000000..6389fd7
--- /dev/null
+++ b/src/crypto/tls/example_test.go
@@ -0,0 +1,232 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls_test
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "log"
+ "net/http"
+ "net/http/httptest"
+ "os"
+ "time"
+)
+
+// zeroSource is an io.Reader that returns an unlimited number of zero bytes.
+type zeroSource struct{}
+
+func (zeroSource) Read(b []byte) (n int, err error) {
+ for i := range b {
+ b[i] = 0
+ }
+
+ return len(b), nil
+}
+
+func ExampleDial() {
+ // Connecting with a custom root-certificate set.
+
+ const rootPEM = `
+-- GlobalSign Root R2, valid until Dec 15, 2021
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgILBAAAAAABD4Ym5g0wDQYJKoZIhvcNAQEFBQAwTDEgMB4G
+A1UECxMXR2xvYmFsU2lnbiBSb290IENBIC0gUjIxEzARBgNVBAoTCkdsb2JhbFNp
+Z24xEzARBgNVBAMTCkdsb2JhbFNpZ24wHhcNMDYxMjE1MDgwMDAwWhcNMjExMjE1
+MDgwMDAwWjBMMSAwHgYDVQQLExdHbG9iYWxTaWduIFJvb3QgQ0EgLSBSMjETMBEG
+A1UEChMKR2xvYmFsU2lnbjETMBEGA1UEAxMKR2xvYmFsU2lnbjCCASIwDQYJKoZI
+hvcNAQEBBQADggEPADCCAQoCggEBAKbPJA6+Lm8omUVCxKs+IVSbC9N/hHD6ErPL
+v4dfxn+G07IwXNb9rfF73OX4YJYJkhD10FPe+3t+c4isUoh7SqbKSaZeqKeMWhG8
+eoLrvozps6yWJQeXSpkqBy+0Hne/ig+1AnwblrjFuTosvNYSuetZfeLQBoZfXklq
+tTleiDTsvHgMCJiEbKjNS7SgfQx5TfC4LcshytVsW33hoCmEofnTlEnLJGKRILzd
+C9XZzPnqJworc5HGnRusyMvo4KD0L5CLTfuwNhv2GXqF4G3yYROIXJ/gkwpRl4pa
+zq+r1feqCapgvdzZX99yqWATXgAByUr6P6TqBwMhAo6CygPCm48CAwEAAaOBnDCB
+mTAOBgNVHQ8BAf8EBAMCAQYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUm+IH
+V2ccHsBqBt5ZtJot39wZhi4wNgYDVR0fBC8wLTAroCmgJ4YlaHR0cDovL2NybC5n
+bG9iYWxzaWduLm5ldC9yb290LXIyLmNybDAfBgNVHSMEGDAWgBSb4gdXZxwewGoG
+3lm0mi3f3BmGLjANBgkqhkiG9w0BAQUFAAOCAQEAmYFThxxol4aR7OBKuEQLq4Gs
+J0/WwbgcQ3izDJr86iw8bmEbTUsp9Z8FHSbBuOmDAGJFtqkIk7mpM0sYmsL4h4hO
+291xNBrBVNpGP+DTKqttVCL1OmLNIG+6KYnX3ZHu01yiPqFbQfXf5WRDLenVOavS
+ot+3i9DAgBkcRcAtjOj4LaR0VknFBbVPFd5uRHg5h6h+u/N5GJG79G+dwfCMNYxd
+AfvDbbnvRG15RjF+Cv6pgsH/76tuIMRQyV+dTZsXjAzlAcmgQWpzU/qlULRuJQ/7
+TBj0/VLZjmmx6BEP3ojY+x1J96relc8geMJgEtslQIxq/H5COEBkEveegeGTLg==
+-----END CERTIFICATE-----`
+
+ // First, create the set of root certificates. For this example we only
+ // have one. It's also possible to omit this in order to use the
+ // default root set of the current operating system.
+ roots := x509.NewCertPool()
+ ok := roots.AppendCertsFromPEM([]byte(rootPEM))
+ if !ok {
+ panic("failed to parse root certificate")
+ }
+
+ conn, err := tls.Dial("tcp", "mail.google.com:443", &tls.Config{
+ RootCAs: roots,
+ })
+ if err != nil {
+ panic("failed to connect: " + err.Error())
+ }
+ conn.Close()
+}
+
+func ExampleConfig_keyLogWriter() {
+ // Debugging TLS applications by decrypting a network traffic capture.
+
+ // WARNING: Use of KeyLogWriter compromises security and should only be
+ // used for debugging.
+
+ // Dummy test HTTP server for the example with insecure random so output is
+ // reproducible.
+ server := httptest.NewUnstartedServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {}))
+ server.TLS = &tls.Config{
+ Rand: zeroSource{}, // for example only; don't do this.
+ }
+ server.StartTLS()
+ defer server.Close()
+
+ // Typically the log would go to an open file:
+ // w, err := os.OpenFile("tls-secrets.txt", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
+ w := os.Stdout
+
+ client := &http.Client{
+ Transport: &http.Transport{
+ TLSClientConfig: &tls.Config{
+ KeyLogWriter: w,
+
+ Rand: zeroSource{}, // for reproducible output; don't do this.
+ InsecureSkipVerify: true, // test server certificate is not trusted.
+ },
+ },
+ }
+ resp, err := client.Get(server.URL)
+ if err != nil {
+ log.Fatalf("Failed to get URL: %v", err)
+ }
+ resp.Body.Close()
+
+ // The resulting file can be used with Wireshark to decrypt the TLS
+ // connection by setting (Pre)-Master-Secret log filename in SSL Protocol
+ // preferences.
+}
+
+func ExampleLoadX509KeyPair() {
+ cert, err := tls.LoadX509KeyPair("testdata/example-cert.pem", "testdata/example-key.pem")
+ if err != nil {
+ log.Fatal(err)
+ }
+ cfg := &tls.Config{Certificates: []tls.Certificate{cert}}
+ listener, err := tls.Listen("tcp", ":2000", cfg)
+ if err != nil {
+ log.Fatal(err)
+ }
+ _ = listener
+}
+
+func ExampleX509KeyPair() {
+ certPem := []byte(`-----BEGIN CERTIFICATE-----
+MIIBhTCCASugAwIBAgIQIRi6zePL6mKjOipn+dNuaTAKBggqhkjOPQQDAjASMRAw
+DgYDVQQKEwdBY21lIENvMB4XDTE3MTAyMDE5NDMwNloXDTE4MTAyMDE5NDMwNlow
+EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD0d
+7VNhbWvZLWPuj/RtHFjvtJBEwOkhbN/BnnE8rnZR8+sbwnc/KhCk3FhnpHZnQz7B
+5aETbbIgmuvewdjvSBSjYzBhMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
+BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdEQQiMCCCDmxvY2FsaG9zdDo1
+NDUzgg4xMjcuMC4wLjE6NTQ1MzAKBggqhkjOPQQDAgNIADBFAiEA2zpJEPQyz6/l
+Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc
+6MF9+Yw1Yy0t
+-----END CERTIFICATE-----`)
+ keyPem := []byte(`-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIIrYSSNQFaA2Hwf1duRSxKtLYX5CB04fSeQ6tF1aY/PuoAoGCCqGSM49
+AwEHoUQDQgAEPR3tU2Fta9ktY+6P9G0cWO+0kETA6SFs38GecTyudlHz6xvCdz8q
+EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA==
+-----END EC PRIVATE KEY-----`)
+ cert, err := tls.X509KeyPair(certPem, keyPem)
+ if err != nil {
+ log.Fatal(err)
+ }
+ cfg := &tls.Config{Certificates: []tls.Certificate{cert}}
+ listener, err := tls.Listen("tcp", ":2000", cfg)
+ if err != nil {
+ log.Fatal(err)
+ }
+ _ = listener
+}
+
+func ExampleX509KeyPair_httpServer() {
+ certPem := []byte(`-----BEGIN CERTIFICATE-----
+MIIBhTCCASugAwIBAgIQIRi6zePL6mKjOipn+dNuaTAKBggqhkjOPQQDAjASMRAw
+DgYDVQQKEwdBY21lIENvMB4XDTE3MTAyMDE5NDMwNloXDTE4MTAyMDE5NDMwNlow
+EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD0d
+7VNhbWvZLWPuj/RtHFjvtJBEwOkhbN/BnnE8rnZR8+sbwnc/KhCk3FhnpHZnQz7B
+5aETbbIgmuvewdjvSBSjYzBhMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
+BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdEQQiMCCCDmxvY2FsaG9zdDo1
+NDUzgg4xMjcuMC4wLjE6NTQ1MzAKBggqhkjOPQQDAgNIADBFAiEA2zpJEPQyz6/l
+Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc
+6MF9+Yw1Yy0t
+-----END CERTIFICATE-----`)
+ keyPem := []byte(`-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIIrYSSNQFaA2Hwf1duRSxKtLYX5CB04fSeQ6tF1aY/PuoAoGCCqGSM49
+AwEHoUQDQgAEPR3tU2Fta9ktY+6P9G0cWO+0kETA6SFs38GecTyudlHz6xvCdz8q
+EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA==
+-----END EC PRIVATE KEY-----`)
+ cert, err := tls.X509KeyPair(certPem, keyPem)
+ if err != nil {
+ log.Fatal(err)
+ }
+ cfg := &tls.Config{Certificates: []tls.Certificate{cert}}
+ srv := &http.Server{
+ TLSConfig: cfg,
+ ReadTimeout: time.Minute,
+ WriteTimeout: time.Minute,
+ }
+ log.Fatal(srv.ListenAndServeTLS("", ""))
+}
+
+func ExampleConfig_verifyConnection() {
+ // VerifyConnection can be used to replace and customize connection
+ // verification. This example shows a VerifyConnection implementation that
+ // will be approximately equivalent to what crypto/tls does normally to
+ // verify the peer's certificate.
+
+ // Client side configuration.
+ _ = &tls.Config{
+ // Set InsecureSkipVerify to skip the default validation we are
+ // replacing. This will not disable VerifyConnection.
+ InsecureSkipVerify: true,
+ VerifyConnection: func(cs tls.ConnectionState) error {
+ opts := x509.VerifyOptions{
+ DNSName: cs.ServerName,
+ Intermediates: x509.NewCertPool(),
+ }
+ for _, cert := range cs.PeerCertificates[1:] {
+ opts.Intermediates.AddCert(cert)
+ }
+ _, err := cs.PeerCertificates[0].Verify(opts)
+ return err
+ },
+ }
+
+ // Server side configuration.
+ _ = &tls.Config{
+ // Require client certificates (or VerifyConnection will run anyway and
+ // panic accessing cs.PeerCertificates[0]) but don't verify them with the
+ // default verifier. This will not disable VerifyConnection.
+ ClientAuth: tls.RequireAnyClientCert,
+ VerifyConnection: func(cs tls.ConnectionState) error {
+ opts := x509.VerifyOptions{
+ DNSName: cs.ServerName,
+ Intermediates: x509.NewCertPool(),
+ KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
+ }
+ for _, cert := range cs.PeerCertificates[1:] {
+ opts.Intermediates.AddCert(cert)
+ }
+ _, err := cs.PeerCertificates[0].Verify(opts)
+ return err
+ },
+ }
+
+ // Note that when certificates are not handled by the default verifier
+ // ConnectionState.VerifiedChains will be nil.
+}
diff --git a/src/crypto/tls/fipsonly/fipsonly.go b/src/crypto/tls/fipsonly/fipsonly.go
new file mode 100644
index 0000000..e5e4783
--- /dev/null
+++ b/src/crypto/tls/fipsonly/fipsonly.go
@@ -0,0 +1,29 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto
+
+// Package fipsonly restricts all TLS configuration to FIPS-approved settings.
+//
+// The effect is triggered by importing the package anywhere in a program, as in:
+//
+// import _ "crypto/tls/fipsonly"
+//
+// This package only exists when using Go compiled with GOEXPERIMENT=boringcrypto.
+package fipsonly
+
+// This functionality is provided as a side effect of an import to make
+// it trivial to add to an existing program. It requires only a single line
+// added to an existing source file, or it can be done by adding a whole
+// new source file and not modifying any existing source files.
+
+import (
+ "crypto/internal/boring/fipstls"
+ "crypto/internal/boring/sig"
+)
+
+func init() {
+ fipstls.Force()
+ sig.FIPSOnly()
+}
diff --git a/src/crypto/tls/fipsonly/fipsonly_test.go b/src/crypto/tls/fipsonly/fipsonly_test.go
new file mode 100644
index 0000000..f8485dc
--- /dev/null
+++ b/src/crypto/tls/fipsonly/fipsonly_test.go
@@ -0,0 +1,18 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto
+
+package fipsonly
+
+import (
+ "crypto/internal/boring/fipstls"
+ "testing"
+)
+
+func Test(t *testing.T) {
+ if !fipstls.Required() {
+ t.Fatal("fipstls.Required() = false, must be true")
+ }
+}
diff --git a/src/crypto/tls/generate_cert.go b/src/crypto/tls/generate_cert.go
new file mode 100644
index 0000000..cd4bfc5
--- /dev/null
+++ b/src/crypto/tls/generate_cert.go
@@ -0,0 +1,171 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build ignore
+
+// Generate a self-signed X.509 certificate for a TLS server. Outputs to
+// 'cert.pem' and 'key.pem' and will overwrite existing files.
+
+package main
+
+import (
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "flag"
+ "log"
+ "math/big"
+ "net"
+ "os"
+ "strings"
+ "time"
+)
+
+var (
+ host = flag.String("host", "", "Comma-separated hostnames and IPs to generate a certificate for")
+ validFrom = flag.String("start-date", "", "Creation date formatted as Jan 1 15:04:05 2011")
+ validFor = flag.Duration("duration", 365*24*time.Hour, "Duration that certificate is valid for")
+ isCA = flag.Bool("ca", false, "whether this cert should be its own Certificate Authority")
+ rsaBits = flag.Int("rsa-bits", 2048, "Size of RSA key to generate. Ignored if --ecdsa-curve is set")
+ ecdsaCurve = flag.String("ecdsa-curve", "", "ECDSA curve to use to generate a key. Valid values are P224, P256 (recommended), P384, P521")
+ ed25519Key = flag.Bool("ed25519", false, "Generate an Ed25519 key")
+)
+
+func publicKey(priv any) any {
+ switch k := priv.(type) {
+ case *rsa.PrivateKey:
+ return &k.PublicKey
+ case *ecdsa.PrivateKey:
+ return &k.PublicKey
+ case ed25519.PrivateKey:
+ return k.Public().(ed25519.PublicKey)
+ default:
+ return nil
+ }
+}
+
+func main() {
+ flag.Parse()
+
+ if len(*host) == 0 {
+ log.Fatalf("Missing required --host parameter")
+ }
+
+ var priv any
+ var err error
+ switch *ecdsaCurve {
+ case "":
+ if *ed25519Key {
+ _, priv, err = ed25519.GenerateKey(rand.Reader)
+ } else {
+ priv, err = rsa.GenerateKey(rand.Reader, *rsaBits)
+ }
+ case "P224":
+ priv, err = ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
+ case "P256":
+ priv, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ case "P384":
+ priv, err = ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
+ case "P521":
+ priv, err = ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
+ default:
+ log.Fatalf("Unrecognized elliptic curve: %q", *ecdsaCurve)
+ }
+ if err != nil {
+ log.Fatalf("Failed to generate private key: %v", err)
+ }
+
+ // ECDSA, ED25519 and RSA subject keys should have the DigitalSignature
+ // KeyUsage bits set in the x509.Certificate template
+ keyUsage := x509.KeyUsageDigitalSignature
+ // Only RSA subject keys should have the KeyEncipherment KeyUsage bits set. In
+ // the context of TLS this KeyUsage is particular to RSA key exchange and
+ // authentication.
+ if _, isRSA := priv.(*rsa.PrivateKey); isRSA {
+ keyUsage |= x509.KeyUsageKeyEncipherment
+ }
+
+ var notBefore time.Time
+ if len(*validFrom) == 0 {
+ notBefore = time.Now()
+ } else {
+ notBefore, err = time.Parse("Jan 2 15:04:05 2006", *validFrom)
+ if err != nil {
+ log.Fatalf("Failed to parse creation date: %v", err)
+ }
+ }
+
+ notAfter := notBefore.Add(*validFor)
+
+ serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+ serialNumber, err := rand.Int(rand.Reader, serialNumberLimit)
+ if err != nil {
+ log.Fatalf("Failed to generate serial number: %v", err)
+ }
+
+ template := x509.Certificate{
+ SerialNumber: serialNumber,
+ Subject: pkix.Name{
+ Organization: []string{"Acme Co"},
+ },
+ NotBefore: notBefore,
+ NotAfter: notAfter,
+
+ KeyUsage: keyUsage,
+ ExtKeyUsage: []x509.ExtKeyUsage{x509.ExtKeyUsageServerAuth},
+ BasicConstraintsValid: true,
+ }
+
+ hosts := strings.Split(*host, ",")
+ for _, h := range hosts {
+ if ip := net.ParseIP(h); ip != nil {
+ template.IPAddresses = append(template.IPAddresses, ip)
+ } else {
+ template.DNSNames = append(template.DNSNames, h)
+ }
+ }
+
+ if *isCA {
+ template.IsCA = true
+ template.KeyUsage |= x509.KeyUsageCertSign
+ }
+
+ derBytes, err := x509.CreateCertificate(rand.Reader, &template, &template, publicKey(priv), priv)
+ if err != nil {
+ log.Fatalf("Failed to create certificate: %v", err)
+ }
+
+ certOut, err := os.Create("cert.pem")
+ if err != nil {
+ log.Fatalf("Failed to open cert.pem for writing: %v", err)
+ }
+ if err := pem.Encode(certOut, &pem.Block{Type: "CERTIFICATE", Bytes: derBytes}); err != nil {
+ log.Fatalf("Failed to write data to cert.pem: %v", err)
+ }
+ if err := certOut.Close(); err != nil {
+ log.Fatalf("Error closing cert.pem: %v", err)
+ }
+ log.Print("wrote cert.pem\n")
+
+ keyOut, err := os.OpenFile("key.pem", os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0600)
+ if err != nil {
+ log.Fatalf("Failed to open key.pem for writing: %v", err)
+ }
+ privBytes, err := x509.MarshalPKCS8PrivateKey(priv)
+ if err != nil {
+ log.Fatalf("Unable to marshal private key: %v", err)
+ }
+ if err := pem.Encode(keyOut, &pem.Block{Type: "PRIVATE KEY", Bytes: privBytes}); err != nil {
+ log.Fatalf("Failed to write data to key.pem: %v", err)
+ }
+ if err := keyOut.Close(); err != nil {
+ log.Fatalf("Error closing key.pem: %v", err)
+ }
+ log.Print("wrote key.pem\n")
+}
diff --git a/src/crypto/tls/handshake_client.go b/src/crypto/tls/handshake_client.go
new file mode 100644
index 0000000..0bb6a0a
--- /dev/null
+++ b/src/crypto/tls/handshake_client.go
@@ -0,0 +1,1055 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "bytes"
+ "context"
+ "crypto"
+ "crypto/ecdh"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/rsa"
+ "crypto/subtle"
+ "crypto/x509"
+ "errors"
+ "fmt"
+ "hash"
+ "internal/godebug"
+ "io"
+ "net"
+ "strconv"
+ "strings"
+ "time"
+)
+
+type clientHandshakeState struct {
+ c *Conn
+ ctx context.Context
+ serverHello *serverHelloMsg
+ hello *clientHelloMsg
+ suite *cipherSuite
+ finishedHash finishedHash
+ masterSecret []byte
+ session *ClientSessionState
+}
+
+var testingOnlyForceClientHelloSignatureAlgorithms []SignatureScheme
+
+func (c *Conn) makeClientHello() (*clientHelloMsg, *ecdh.PrivateKey, error) {
+ config := c.config
+ if len(config.ServerName) == 0 && !config.InsecureSkipVerify {
+ return nil, nil, errors.New("tls: either ServerName or InsecureSkipVerify must be specified in the tls.Config")
+ }
+
+ nextProtosLength := 0
+ for _, proto := range config.NextProtos {
+ if l := len(proto); l == 0 || l > 255 {
+ return nil, nil, errors.New("tls: invalid NextProtos value")
+ } else {
+ nextProtosLength += 1 + l
+ }
+ }
+ if nextProtosLength > 0xffff {
+ return nil, nil, errors.New("tls: NextProtos values too large")
+ }
+
+ supportedVersions := config.supportedVersions(roleClient)
+ if len(supportedVersions) == 0 {
+ return nil, nil, errors.New("tls: no supported versions satisfy MinVersion and MaxVersion")
+ }
+
+ clientHelloVersion := config.maxSupportedVersion(roleClient)
+ // The version at the beginning of the ClientHello was capped at TLS 1.2
+ // for compatibility reasons. The supported_versions extension is used
+ // to negotiate versions now. See RFC 8446, Section 4.2.1.
+ if clientHelloVersion > VersionTLS12 {
+ clientHelloVersion = VersionTLS12
+ }
+
+ hello := &clientHelloMsg{
+ vers: clientHelloVersion,
+ compressionMethods: []uint8{compressionNone},
+ random: make([]byte, 32),
+ sessionId: make([]byte, 32),
+ ocspStapling: true,
+ scts: true,
+ serverName: hostnameInSNI(config.ServerName),
+ supportedCurves: config.curvePreferences(),
+ supportedPoints: []uint8{pointFormatUncompressed},
+ secureRenegotiationSupported: true,
+ alpnProtocols: config.NextProtos,
+ supportedVersions: supportedVersions,
+ }
+
+ if c.handshakes > 0 {
+ hello.secureRenegotiation = c.clientFinished[:]
+ }
+
+ preferenceOrder := cipherSuitesPreferenceOrder
+ if !hasAESGCMHardwareSupport {
+ preferenceOrder = cipherSuitesPreferenceOrderNoAES
+ }
+ configCipherSuites := config.cipherSuites()
+ hello.cipherSuites = make([]uint16, 0, len(configCipherSuites))
+
+ for _, suiteId := range preferenceOrder {
+ suite := mutualCipherSuite(configCipherSuites, suiteId)
+ if suite == nil {
+ continue
+ }
+ // Don't advertise TLS 1.2-only cipher suites unless
+ // we're attempting TLS 1.2.
+ if hello.vers < VersionTLS12 && suite.flags&suiteTLS12 != 0 {
+ continue
+ }
+ hello.cipherSuites = append(hello.cipherSuites, suiteId)
+ }
+
+ _, err := io.ReadFull(config.rand(), hello.random)
+ if err != nil {
+ return nil, nil, errors.New("tls: short read from Rand: " + err.Error())
+ }
+
+ // A random session ID is used to detect when the server accepted a ticket
+ // and is resuming a session (see RFC 5077). In TLS 1.3, it's always set as
+ // a compatibility measure (see RFC 8446, Section 4.1.2).
+ if _, err := io.ReadFull(config.rand(), hello.sessionId); err != nil {
+ return nil, nil, errors.New("tls: short read from Rand: " + err.Error())
+ }
+
+ if hello.vers >= VersionTLS12 {
+ hello.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
+ }
+ if testingOnlyForceClientHelloSignatureAlgorithms != nil {
+ hello.supportedSignatureAlgorithms = testingOnlyForceClientHelloSignatureAlgorithms
+ }
+
+ var key *ecdh.PrivateKey
+ if hello.supportedVersions[0] == VersionTLS13 {
+ if hasAESGCMHardwareSupport {
+ hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13...)
+ } else {
+ hello.cipherSuites = append(hello.cipherSuites, defaultCipherSuitesTLS13NoAES...)
+ }
+
+ curveID := config.curvePreferences()[0]
+ if _, ok := curveForCurveID(curveID); !ok {
+ return nil, nil, errors.New("tls: CurvePreferences includes unsupported curve")
+ }
+ key, err = generateECDHEKey(config.rand(), curveID)
+ if err != nil {
+ return nil, nil, err
+ }
+ hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}}
+ }
+
+ return hello, key, nil
+}
+
+func (c *Conn) clientHandshake(ctx context.Context) (err error) {
+ if c.config == nil {
+ c.config = defaultConfig()
+ }
+
+ // This may be a renegotiation handshake, in which case some fields
+ // need to be reset.
+ c.didResume = false
+
+ hello, ecdheKey, err := c.makeClientHello()
+ if err != nil {
+ return err
+ }
+ c.serverName = hello.serverName
+
+ cacheKey, session, earlySecret, binderKey, err := c.loadSession(hello)
+ if err != nil {
+ return err
+ }
+ if cacheKey != "" && session != nil {
+ defer func() {
+ // If we got a handshake failure when resuming a session, throw away
+ // the session ticket. See RFC 5077, Section 3.2.
+ //
+ // RFC 8446 makes no mention of dropping tickets on failure, but it
+ // does require servers to abort on invalid binders, so we need to
+ // delete tickets to recover from a corrupted PSK.
+ if err != nil {
+ c.config.ClientSessionCache.Put(cacheKey, nil)
+ }
+ }()
+ }
+
+ if _, err := c.writeHandshakeRecord(hello, nil); err != nil {
+ return err
+ }
+
+ // serverHelloMsg is not included in the transcript
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ serverHello, ok := msg.(*serverHelloMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(serverHello, msg)
+ }
+
+ if err := c.pickTLSVersion(serverHello); err != nil {
+ return err
+ }
+
+ // If we are negotiating a protocol version that's lower than what we
+ // support, check for the server downgrade canaries.
+ // See RFC 8446, Section 4.1.3.
+ maxVers := c.config.maxSupportedVersion(roleClient)
+ tls12Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS12
+ tls11Downgrade := string(serverHello.random[24:]) == downgradeCanaryTLS11
+ if maxVers == VersionTLS13 && c.vers <= VersionTLS12 && (tls12Downgrade || tls11Downgrade) ||
+ maxVers == VersionTLS12 && c.vers <= VersionTLS11 && tls11Downgrade {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: downgrade attempt detected, possibly due to a MitM attack or a broken middlebox")
+ }
+
+ if c.vers == VersionTLS13 {
+ hs := &clientHandshakeStateTLS13{
+ c: c,
+ ctx: ctx,
+ serverHello: serverHello,
+ hello: hello,
+ ecdheKey: ecdheKey,
+ session: session,
+ earlySecret: earlySecret,
+ binderKey: binderKey,
+ }
+
+ // In TLS 1.3, session tickets are delivered after the handshake.
+ return hs.handshake()
+ }
+
+ hs := &clientHandshakeState{
+ c: c,
+ ctx: ctx,
+ serverHello: serverHello,
+ hello: hello,
+ session: session,
+ }
+
+ if err := hs.handshake(); err != nil {
+ return err
+ }
+
+ // If we had a successful handshake and hs.session is different from
+ // the one already cached - cache a new one.
+ if cacheKey != "" && hs.session != nil && session != hs.session {
+ c.config.ClientSessionCache.Put(cacheKey, hs.session)
+ }
+
+ return nil
+}
+
+func (c *Conn) loadSession(hello *clientHelloMsg) (cacheKey string,
+ session *ClientSessionState, earlySecret, binderKey []byte, err error) {
+ if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil {
+ return "", nil, nil, nil, nil
+ }
+
+ hello.ticketSupported = true
+
+ if hello.supportedVersions[0] == VersionTLS13 {
+ // Require DHE on resumption as it guarantees forward secrecy against
+ // compromise of the session ticket key. See RFC 8446, Section 4.2.9.
+ hello.pskModes = []uint8{pskModeDHE}
+ }
+
+ // Session resumption is not allowed if renegotiating because
+ // renegotiation is primarily used to allow a client to send a client
+ // certificate, which would be skipped if session resumption occurred.
+ if c.handshakes != 0 {
+ return "", nil, nil, nil, nil
+ }
+
+ // Try to resume a previously negotiated TLS session, if available.
+ cacheKey = clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
+ session, ok := c.config.ClientSessionCache.Get(cacheKey)
+ if !ok || session == nil {
+ return cacheKey, nil, nil, nil, nil
+ }
+
+ // Check that version used for the previous session is still valid.
+ versOk := false
+ for _, v := range hello.supportedVersions {
+ if v == session.vers {
+ versOk = true
+ break
+ }
+ }
+ if !versOk {
+ return cacheKey, nil, nil, nil, nil
+ }
+
+ // Check that the cached server certificate is not expired, and that it's
+ // valid for the ServerName. This should be ensured by the cache key, but
+ // protect the application from a faulty ClientSessionCache implementation.
+ if !c.config.InsecureSkipVerify {
+ if len(session.verifiedChains) == 0 {
+ // The original connection had InsecureSkipVerify, while this doesn't.
+ return cacheKey, nil, nil, nil, nil
+ }
+ serverCert := session.serverCertificates[0]
+ if c.config.time().After(serverCert.NotAfter) {
+ // Expired certificate, delete the entry.
+ c.config.ClientSessionCache.Put(cacheKey, nil)
+ return cacheKey, nil, nil, nil, nil
+ }
+ if err := serverCert.VerifyHostname(c.config.ServerName); err != nil {
+ return cacheKey, nil, nil, nil, nil
+ }
+ }
+
+ if session.vers != VersionTLS13 {
+ // In TLS 1.2 the cipher suite must match the resumed session. Ensure we
+ // are still offering it.
+ if mutualCipherSuite(hello.cipherSuites, session.cipherSuite) == nil {
+ return cacheKey, nil, nil, nil, nil
+ }
+
+ hello.sessionTicket = session.sessionTicket
+ return
+ }
+
+ // Check that the session ticket is not expired.
+ if c.config.time().After(session.useBy) {
+ c.config.ClientSessionCache.Put(cacheKey, nil)
+ return cacheKey, nil, nil, nil, nil
+ }
+
+ // In TLS 1.3 the KDF hash must match the resumed session. Ensure we
+ // offer at least one cipher suite with that hash.
+ cipherSuite := cipherSuiteTLS13ByID(session.cipherSuite)
+ if cipherSuite == nil {
+ return cacheKey, nil, nil, nil, nil
+ }
+ cipherSuiteOk := false
+ for _, offeredID := range hello.cipherSuites {
+ offeredSuite := cipherSuiteTLS13ByID(offeredID)
+ if offeredSuite != nil && offeredSuite.hash == cipherSuite.hash {
+ cipherSuiteOk = true
+ break
+ }
+ }
+ if !cipherSuiteOk {
+ return cacheKey, nil, nil, nil, nil
+ }
+
+ // Set the pre_shared_key extension. See RFC 8446, Section 4.2.11.1.
+ ticketAge := uint32(c.config.time().Sub(session.receivedAt) / time.Millisecond)
+ identity := pskIdentity{
+ label: session.sessionTicket,
+ obfuscatedTicketAge: ticketAge + session.ageAdd,
+ }
+ hello.pskIdentities = []pskIdentity{identity}
+ hello.pskBinders = [][]byte{make([]byte, cipherSuite.hash.Size())}
+
+ // Compute the PSK binders. See RFC 8446, Section 4.2.11.2.
+ psk := cipherSuite.expandLabel(session.masterSecret, "resumption",
+ session.nonce, cipherSuite.hash.Size())
+ earlySecret = cipherSuite.extract(psk, nil)
+ binderKey = cipherSuite.deriveSecret(earlySecret, resumptionBinderLabel, nil)
+ transcript := cipherSuite.hash.New()
+ helloBytes, err := hello.marshalWithoutBinders()
+ if err != nil {
+ return "", nil, nil, nil, err
+ }
+ transcript.Write(helloBytes)
+ pskBinders := [][]byte{cipherSuite.finishedHash(binderKey, transcript)}
+ if err := hello.updateBinders(pskBinders); err != nil {
+ return "", nil, nil, nil, err
+ }
+
+ return
+}
+
+func (c *Conn) pickTLSVersion(serverHello *serverHelloMsg) error {
+ peerVersion := serverHello.vers
+ if serverHello.supportedVersion != 0 {
+ peerVersion = serverHello.supportedVersion
+ }
+
+ vers, ok := c.config.mutualVersion(roleClient, []uint16{peerVersion})
+ if !ok {
+ c.sendAlert(alertProtocolVersion)
+ return fmt.Errorf("tls: server selected unsupported protocol version %x", peerVersion)
+ }
+
+ c.vers = vers
+ c.haveVers = true
+ c.in.version = vers
+ c.out.version = vers
+
+ return nil
+}
+
+// Does the handshake, either a full one or resumes old session. Requires hs.c,
+// hs.hello, hs.serverHello, and, optionally, hs.session to be set.
+func (hs *clientHandshakeState) handshake() error {
+ c := hs.c
+
+ isResume, err := hs.processServerHello()
+ if err != nil {
+ return err
+ }
+
+ hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+
+ // No signatures of the handshake are needed in a resumption.
+ // Otherwise, in a full handshake, if we don't have any certificates
+ // configured then we will never send a CertificateVerify message and
+ // thus no signatures are needed in that case either.
+ if isResume || (len(c.config.Certificates) == 0 && c.config.GetClientCertificate == nil) {
+ hs.finishedHash.discardHandshakeBuffer()
+ }
+
+ if err := transcriptMsg(hs.hello, &hs.finishedHash); err != nil {
+ return err
+ }
+ if err := transcriptMsg(hs.serverHello, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ c.buffering = true
+ c.didResume = isResume
+ if isResume {
+ if err := hs.establishKeys(); err != nil {
+ return err
+ }
+ if err := hs.readSessionTicket(); err != nil {
+ return err
+ }
+ if err := hs.readFinished(c.serverFinished[:]); err != nil {
+ return err
+ }
+ c.clientFinishedIsFirst = false
+ // Make sure the connection is still being verified whether or not this
+ // is a resumption. Resumptions currently don't reverify certificates so
+ // they don't call verifyServerCertificate. See Issue 31641.
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+ if err := hs.sendFinished(c.clientFinished[:]); err != nil {
+ return err
+ }
+ if _, err := c.flush(); err != nil {
+ return err
+ }
+ } else {
+ if err := hs.doFullHandshake(); err != nil {
+ return err
+ }
+ if err := hs.establishKeys(); err != nil {
+ return err
+ }
+ if err := hs.sendFinished(c.clientFinished[:]); err != nil {
+ return err
+ }
+ if _, err := c.flush(); err != nil {
+ return err
+ }
+ c.clientFinishedIsFirst = true
+ if err := hs.readSessionTicket(); err != nil {
+ return err
+ }
+ if err := hs.readFinished(c.serverFinished[:]); err != nil {
+ return err
+ }
+ }
+
+ c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random)
+ c.isHandshakeComplete.Store(true)
+
+ return nil
+}
+
+func (hs *clientHandshakeState) pickCipherSuite() error {
+ if hs.suite = mutualCipherSuite(hs.hello.cipherSuites, hs.serverHello.cipherSuite); hs.suite == nil {
+ hs.c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: server chose an unconfigured cipher suite")
+ }
+
+ hs.c.cipherSuite = hs.suite.id
+ return nil
+}
+
+func (hs *clientHandshakeState) doFullHandshake() error {
+ c := hs.c
+
+ msg, err := c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+ certMsg, ok := msg.(*certificateMsg)
+ if !ok || len(certMsg.certificates) == 0 {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
+ }
+
+ msg, err = c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+
+ cs, ok := msg.(*certificateStatusMsg)
+ if ok {
+ // RFC4366 on Certificate Status Request:
+ // The server MAY return a "certificate_status" message.
+
+ if !hs.serverHello.ocspStapling {
+ // If a server returns a "CertificateStatus" message, then the
+ // server MUST have included an extension of type "status_request"
+ // with empty "extension_data" in the extended server hello.
+
+ c.sendAlert(alertUnexpectedMessage)
+ return errors.New("tls: received unexpected CertificateStatus message")
+ }
+
+ c.ocspResponse = cs.response
+
+ msg, err = c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+ }
+
+ if c.handshakes == 0 {
+ // If this is the first handshake on a connection, process and
+ // (optionally) verify the server's certificates.
+ if err := c.verifyServerCertificate(certMsg.certificates); err != nil {
+ return err
+ }
+ } else {
+ // This is a renegotiation handshake. We require that the
+ // server's identity (i.e. leaf certificate) is unchanged and
+ // thus any previous trust decision is still valid.
+ //
+ // See https://mitls.org/pages/attacks/3SHAKE for the
+ // motivation behind this requirement.
+ if !bytes.Equal(c.peerCertificates[0].Raw, certMsg.certificates[0]) {
+ c.sendAlert(alertBadCertificate)
+ return errors.New("tls: server's identity changed during renegotiation")
+ }
+ }
+
+ keyAgreement := hs.suite.ka(c.vers)
+
+ skx, ok := msg.(*serverKeyExchangeMsg)
+ if ok {
+ err = keyAgreement.processServerKeyExchange(c.config, hs.hello, hs.serverHello, c.peerCertificates[0], skx)
+ if err != nil {
+ c.sendAlert(alertUnexpectedMessage)
+ return err
+ }
+
+ msg, err = c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+ }
+
+ var chainToSend *Certificate
+ var certRequested bool
+ certReq, ok := msg.(*certificateRequestMsg)
+ if ok {
+ certRequested = true
+
+ cri := certificateRequestInfoFromMsg(hs.ctx, c.vers, certReq)
+ if chainToSend, err = c.getClientCertificate(cri); err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ msg, err = c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+ }
+
+ shd, ok := msg.(*serverHelloDoneMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(shd, msg)
+ }
+
+ // If the server requested a certificate then we have to send a
+ // Certificate message, even if it's empty because we don't have a
+ // certificate to send.
+ if certRequested {
+ certMsg = new(certificateMsg)
+ certMsg.certificates = chainToSend.Certificate
+ if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil {
+ return err
+ }
+ }
+
+ preMasterSecret, ckx, err := keyAgreement.generateClientKeyExchange(c.config, hs.hello, c.peerCertificates[0])
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ if ckx != nil {
+ if _, err := hs.c.writeHandshakeRecord(ckx, &hs.finishedHash); err != nil {
+ return err
+ }
+ }
+
+ if chainToSend != nil && len(chainToSend.Certificate) > 0 {
+ certVerify := &certificateVerifyMsg{}
+
+ key, ok := chainToSend.PrivateKey.(crypto.Signer)
+ if !ok {
+ c.sendAlert(alertInternalError)
+ return fmt.Errorf("tls: client certificate private key of type %T does not implement crypto.Signer", chainToSend.PrivateKey)
+ }
+
+ var sigType uint8
+ var sigHash crypto.Hash
+ if c.vers >= VersionTLS12 {
+ signatureAlgorithm, err := selectSignatureScheme(c.vers, chainToSend, certReq.supportedSignatureAlgorithms)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return err
+ }
+ sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm)
+ if err != nil {
+ return c.sendAlert(alertInternalError)
+ }
+ certVerify.hasSignatureAlgorithm = true
+ certVerify.signatureAlgorithm = signatureAlgorithm
+ } else {
+ sigType, sigHash, err = legacyTypeAndHashFromPublicKey(key.Public())
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return err
+ }
+ }
+
+ signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash)
+ signOpts := crypto.SignerOpts(sigHash)
+ if sigType == signatureRSAPSS {
+ signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
+ }
+ certVerify.signature, err = key.Sign(c.config.rand(), signed, signOpts)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ if _, err := hs.c.writeHandshakeRecord(certVerify, &hs.finishedHash); err != nil {
+ return err
+ }
+ }
+
+ hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.hello.random, hs.serverHello.random)
+ if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.hello.random, hs.masterSecret); err != nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: failed to write to key log: " + err.Error())
+ }
+
+ hs.finishedHash.discardHandshakeBuffer()
+
+ return nil
+}
+
+func (hs *clientHandshakeState) establishKeys() error {
+ c := hs.c
+
+ clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+ keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.hello.random, hs.serverHello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+ var clientCipher, serverCipher any
+ var clientHash, serverHash hash.Hash
+ if hs.suite.cipher != nil {
+ clientCipher = hs.suite.cipher(clientKey, clientIV, false /* not for reading */)
+ clientHash = hs.suite.mac(clientMAC)
+ serverCipher = hs.suite.cipher(serverKey, serverIV, true /* for reading */)
+ serverHash = hs.suite.mac(serverMAC)
+ } else {
+ clientCipher = hs.suite.aead(clientKey, clientIV)
+ serverCipher = hs.suite.aead(serverKey, serverIV)
+ }
+
+ c.in.prepareCipherSpec(c.vers, serverCipher, serverHash)
+ c.out.prepareCipherSpec(c.vers, clientCipher, clientHash)
+ return nil
+}
+
+func (hs *clientHandshakeState) serverResumedSession() bool {
+ // If the server responded with the same sessionId then it means the
+ // sessionTicket is being used to resume a TLS session.
+ return hs.session != nil && hs.hello.sessionId != nil &&
+ bytes.Equal(hs.serverHello.sessionId, hs.hello.sessionId)
+}
+
+func (hs *clientHandshakeState) processServerHello() (bool, error) {
+ c := hs.c
+
+ if err := hs.pickCipherSuite(); err != nil {
+ return false, err
+ }
+
+ if hs.serverHello.compressionMethod != compressionNone {
+ c.sendAlert(alertUnexpectedMessage)
+ return false, errors.New("tls: server selected unsupported compression format")
+ }
+
+ if c.handshakes == 0 && hs.serverHello.secureRenegotiationSupported {
+ c.secureRenegotiation = true
+ if len(hs.serverHello.secureRenegotiation) != 0 {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: initial handshake had non-empty renegotiation extension")
+ }
+ }
+
+ if c.handshakes > 0 && c.secureRenegotiation {
+ var expectedSecureRenegotiation [24]byte
+ copy(expectedSecureRenegotiation[:], c.clientFinished[:])
+ copy(expectedSecureRenegotiation[12:], c.serverFinished[:])
+ if !bytes.Equal(hs.serverHello.secureRenegotiation, expectedSecureRenegotiation[:]) {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: incorrect renegotiation extension contents")
+ }
+ }
+
+ if err := checkALPN(hs.hello.alpnProtocols, hs.serverHello.alpnProtocol); err != nil {
+ c.sendAlert(alertUnsupportedExtension)
+ return false, err
+ }
+ c.clientProtocol = hs.serverHello.alpnProtocol
+
+ c.scts = hs.serverHello.scts
+
+ if !hs.serverResumedSession() {
+ return false, nil
+ }
+
+ if hs.session.vers != c.vers {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: server resumed a session with a different version")
+ }
+
+ if hs.session.cipherSuite != hs.suite.id {
+ c.sendAlert(alertHandshakeFailure)
+ return false, errors.New("tls: server resumed a session with a different cipher suite")
+ }
+
+ // Restore masterSecret, peerCerts, and ocspResponse from previous state
+ hs.masterSecret = hs.session.masterSecret
+ c.peerCertificates = hs.session.serverCertificates
+ c.verifiedChains = hs.session.verifiedChains
+ c.ocspResponse = hs.session.ocspResponse
+ // Let the ServerHello SCTs override the session SCTs from the original
+ // connection, if any are provided
+ if len(c.scts) == 0 && len(hs.session.scts) != 0 {
+ c.scts = hs.session.scts
+ }
+
+ return true, nil
+}
+
+// checkALPN ensure that the server's choice of ALPN protocol is compatible with
+// the protocols that we advertised in the Client Hello.
+func checkALPN(clientProtos []string, serverProto string) error {
+ if serverProto == "" {
+ return nil
+ }
+ if len(clientProtos) == 0 {
+ return errors.New("tls: server advertised unrequested ALPN extension")
+ }
+ for _, proto := range clientProtos {
+ if proto == serverProto {
+ return nil
+ }
+ }
+ return errors.New("tls: server selected unadvertised ALPN protocol")
+}
+
+func (hs *clientHandshakeState) readFinished(out []byte) error {
+ c := hs.c
+
+ if err := c.readChangeCipherSpec(); err != nil {
+ return err
+ }
+
+ // finishedMsg is included in the transcript, but not until after we
+ // check the client version, since the state before this message was
+ // sent is used during verification.
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+ serverFinished, ok := msg.(*finishedMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(serverFinished, msg)
+ }
+
+ verify := hs.finishedHash.serverSum(hs.masterSecret)
+ if len(verify) != len(serverFinished.verifyData) ||
+ subtle.ConstantTimeCompare(verify, serverFinished.verifyData) != 1 {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: server's Finished message was incorrect")
+ }
+
+ if err := transcriptMsg(serverFinished, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ copy(out, verify)
+ return nil
+}
+
+func (hs *clientHandshakeState) readSessionTicket() error {
+ if !hs.serverHello.ticketSupported {
+ return nil
+ }
+
+ c := hs.c
+ msg, err := c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+ sessionTicketMsg, ok := msg.(*newSessionTicketMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(sessionTicketMsg, msg)
+ }
+
+ hs.session = &ClientSessionState{
+ sessionTicket: sessionTicketMsg.ticket,
+ vers: c.vers,
+ cipherSuite: hs.suite.id,
+ masterSecret: hs.masterSecret,
+ serverCertificates: c.peerCertificates,
+ verifiedChains: c.verifiedChains,
+ receivedAt: c.config.time(),
+ ocspResponse: c.ocspResponse,
+ scts: c.scts,
+ }
+
+ return nil
+}
+
+func (hs *clientHandshakeState) sendFinished(out []byte) error {
+ c := hs.c
+
+ if err := c.writeChangeCipherRecord(); err != nil {
+ return err
+ }
+
+ finished := new(finishedMsg)
+ finished.verifyData = hs.finishedHash.clientSum(hs.masterSecret)
+ if _, err := hs.c.writeHandshakeRecord(finished, &hs.finishedHash); err != nil {
+ return err
+ }
+ copy(out, finished.verifyData)
+ return nil
+}
+
+// defaultMaxRSAKeySize is the maximum RSA key size in bits that we are willing
+// to verify the signatures of during a TLS handshake.
+const defaultMaxRSAKeySize = 8192
+
+var tlsmaxrsasize = godebug.New("tlsmaxrsasize")
+
+func checkKeySize(n int) (max int, ok bool) {
+ if v := tlsmaxrsasize.Value(); v != "" {
+ if max, err := strconv.Atoi(v); err == nil {
+ return max, n <= max
+ }
+ }
+ return defaultMaxRSAKeySize, n <= defaultMaxRSAKeySize
+}
+
+// verifyServerCertificate parses and verifies the provided chain, setting
+// c.verifiedChains and c.peerCertificates or sending the appropriate alert.
+func (c *Conn) verifyServerCertificate(certificates [][]byte) error {
+ activeHandles := make([]*activeCert, len(certificates))
+ certs := make([]*x509.Certificate, len(certificates))
+ for i, asn1Data := range certificates {
+ cert, err := clientCertCache.newCert(asn1Data)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return errors.New("tls: failed to parse certificate from server: " + err.Error())
+ }
+ if cert.cert.PublicKeyAlgorithm == x509.RSA {
+ n := cert.cert.PublicKey.(*rsa.PublicKey).N.BitLen()
+ if max, ok := checkKeySize(n); !ok {
+ c.sendAlert(alertBadCertificate)
+ return fmt.Errorf("tls: server sent certificate containing RSA key larger than %d bits", max)
+ }
+ }
+ activeHandles[i] = cert
+ certs[i] = cert.cert
+ }
+
+ if !c.config.InsecureSkipVerify {
+ opts := x509.VerifyOptions{
+ Roots: c.config.RootCAs,
+ CurrentTime: c.config.time(),
+ DNSName: c.config.ServerName,
+ Intermediates: x509.NewCertPool(),
+ }
+
+ for _, cert := range certs[1:] {
+ opts.Intermediates.AddCert(cert)
+ }
+ var err error
+ c.verifiedChains, err = certs[0].Verify(opts)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err}
+ }
+ }
+
+ switch certs[0].PublicKey.(type) {
+ case *rsa.PublicKey, *ecdsa.PublicKey, ed25519.PublicKey:
+ break
+ default:
+ c.sendAlert(alertUnsupportedCertificate)
+ return fmt.Errorf("tls: server's certificate contains an unsupported type of public key: %T", certs[0].PublicKey)
+ }
+
+ c.activeCertHandles = activeHandles
+ c.peerCertificates = certs
+
+ if c.config.VerifyPeerCertificate != nil {
+ if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
+ return nil
+}
+
+// certificateRequestInfoFromMsg generates a CertificateRequestInfo from a TLS
+// <= 1.2 CertificateRequest, making an effort to fill in missing information.
+func certificateRequestInfoFromMsg(ctx context.Context, vers uint16, certReq *certificateRequestMsg) *CertificateRequestInfo {
+ cri := &CertificateRequestInfo{
+ AcceptableCAs: certReq.certificateAuthorities,
+ Version: vers,
+ ctx: ctx,
+ }
+
+ var rsaAvail, ecAvail bool
+ for _, certType := range certReq.certificateTypes {
+ switch certType {
+ case certTypeRSASign:
+ rsaAvail = true
+ case certTypeECDSASign:
+ ecAvail = true
+ }
+ }
+
+ if !certReq.hasSignatureAlgorithm {
+ // Prior to TLS 1.2, signature schemes did not exist. In this case we
+ // make up a list based on the acceptable certificate types, to help
+ // GetClientCertificate and SupportsCertificate select the right certificate.
+ // The hash part of the SignatureScheme is a lie here, because
+ // TLS 1.0 and 1.1 always use MD5+SHA1 for RSA and SHA1 for ECDSA.
+ switch {
+ case rsaAvail && ecAvail:
+ cri.SignatureSchemes = []SignatureScheme{
+ ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512,
+ PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1,
+ }
+ case rsaAvail:
+ cri.SignatureSchemes = []SignatureScheme{
+ PKCS1WithSHA256, PKCS1WithSHA384, PKCS1WithSHA512, PKCS1WithSHA1,
+ }
+ case ecAvail:
+ cri.SignatureSchemes = []SignatureScheme{
+ ECDSAWithP256AndSHA256, ECDSAWithP384AndSHA384, ECDSAWithP521AndSHA512,
+ }
+ }
+ return cri
+ }
+
+ // Filter the signature schemes based on the certificate types.
+ // See RFC 5246, Section 7.4.4 (where it calls this "somewhat complicated").
+ cri.SignatureSchemes = make([]SignatureScheme, 0, len(certReq.supportedSignatureAlgorithms))
+ for _, sigScheme := range certReq.supportedSignatureAlgorithms {
+ sigType, _, err := typeAndHashFromSignatureScheme(sigScheme)
+ if err != nil {
+ continue
+ }
+ switch sigType {
+ case signatureECDSA, signatureEd25519:
+ if ecAvail {
+ cri.SignatureSchemes = append(cri.SignatureSchemes, sigScheme)
+ }
+ case signatureRSAPSS, signaturePKCS1v15:
+ if rsaAvail {
+ cri.SignatureSchemes = append(cri.SignatureSchemes, sigScheme)
+ }
+ }
+ }
+
+ return cri
+}
+
+func (c *Conn) getClientCertificate(cri *CertificateRequestInfo) (*Certificate, error) {
+ if c.config.GetClientCertificate != nil {
+ return c.config.GetClientCertificate(cri)
+ }
+
+ for _, chain := range c.config.Certificates {
+ if err := cri.SupportsCertificate(&chain); err != nil {
+ continue
+ }
+ return &chain, nil
+ }
+
+ // No acceptable certificate found. Don't send a certificate.
+ return new(Certificate), nil
+}
+
+// clientSessionCacheKey returns a key used to cache sessionTickets that could
+// be used to resume previously negotiated TLS sessions with a server.
+func clientSessionCacheKey(serverAddr net.Addr, config *Config) string {
+ if len(config.ServerName) > 0 {
+ return config.ServerName
+ }
+ return serverAddr.String()
+}
+
+// hostnameInSNI converts name into an appropriate hostname for SNI.
+// Literal IP addresses and absolute FQDNs are not permitted as SNI values.
+// See RFC 6066, Section 3.
+func hostnameInSNI(name string) string {
+ host := name
+ if len(host) > 0 && host[0] == '[' && host[len(host)-1] == ']' {
+ host = host[1 : len(host)-1]
+ }
+ if i := strings.LastIndex(host, "%"); i > 0 {
+ host = host[:i]
+ }
+ if net.ParseIP(host) != nil {
+ return ""
+ }
+ for len(name) > 0 && name[len(name)-1] == '.' {
+ name = name[:len(name)-1]
+ }
+ return name
+}
diff --git a/src/crypto/tls/handshake_client_test.go b/src/crypto/tls/handshake_client_test.go
new file mode 100644
index 0000000..d0afc72
--- /dev/null
+++ b/src/crypto/tls/handshake_client_test.go
@@ -0,0 +1,2721 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "bytes"
+ "context"
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/base64"
+ "encoding/binary"
+ "encoding/pem"
+ "errors"
+ "fmt"
+ "io"
+ "math/big"
+ "net"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "reflect"
+ "runtime"
+ "strconv"
+ "strings"
+ "testing"
+ "time"
+)
+
+// Note: see comment in handshake_test.go for details of how the reference
+// tests work.
+
+// opensslInputEvent enumerates possible inputs that can be sent to an `openssl
+// s_client` process.
+type opensslInputEvent int
+
+const (
+ // opensslRenegotiate causes OpenSSL to request a renegotiation of the
+ // connection.
+ opensslRenegotiate opensslInputEvent = iota
+
+ // opensslSendBanner causes OpenSSL to send the contents of
+ // opensslSentinel on the connection.
+ opensslSendSentinel
+
+ // opensslKeyUpdate causes OpenSSL to send a key update message to the
+ // client and request one back.
+ opensslKeyUpdate
+)
+
+const opensslSentinel = "SENTINEL\n"
+
+type opensslInput chan opensslInputEvent
+
+func (i opensslInput) Read(buf []byte) (n int, err error) {
+ for event := range i {
+ switch event {
+ case opensslRenegotiate:
+ return copy(buf, []byte("R\n")), nil
+ case opensslKeyUpdate:
+ return copy(buf, []byte("K\n")), nil
+ case opensslSendSentinel:
+ return copy(buf, []byte(opensslSentinel)), nil
+ default:
+ panic("unknown event")
+ }
+ }
+
+ return 0, io.EOF
+}
+
+// opensslOutputSink is an io.Writer that receives the stdout and stderr from an
+// `openssl` process and sends a value to handshakeComplete or readKeyUpdate
+// when certain messages are seen.
+type opensslOutputSink struct {
+ handshakeComplete chan struct{}
+ readKeyUpdate chan struct{}
+ all []byte
+ line []byte
+}
+
+func newOpensslOutputSink() *opensslOutputSink {
+ return &opensslOutputSink{make(chan struct{}), make(chan struct{}), nil, nil}
+}
+
+// opensslEndOfHandshake is a message that the “openssl s_server” tool will
+// print when a handshake completes if run with “-state”.
+const opensslEndOfHandshake = "SSL_accept:SSLv3/TLS write finished"
+
+// opensslReadKeyUpdate is a message that the “openssl s_server” tool will
+// print when a KeyUpdate message is received if run with “-state”.
+const opensslReadKeyUpdate = "SSL_accept:TLSv1.3 read client key update"
+
+func (o *opensslOutputSink) Write(data []byte) (n int, err error) {
+ o.line = append(o.line, data...)
+ o.all = append(o.all, data...)
+
+ for {
+ line, next, ok := bytes.Cut(o.line, []byte("\n"))
+ if !ok {
+ break
+ }
+
+ if bytes.Equal([]byte(opensslEndOfHandshake), line) {
+ o.handshakeComplete <- struct{}{}
+ }
+ if bytes.Equal([]byte(opensslReadKeyUpdate), line) {
+ o.readKeyUpdate <- struct{}{}
+ }
+ o.line = next
+ }
+
+ return len(data), nil
+}
+
+func (o *opensslOutputSink) String() string {
+ return string(o.all)
+}
+
+// clientTest represents a test of the TLS client handshake against a reference
+// implementation.
+type clientTest struct {
+ // name is a freeform string identifying the test and the file in which
+ // the expected results will be stored.
+ name string
+ // args, if not empty, contains a series of arguments for the
+ // command to run for the reference server.
+ args []string
+ // config, if not nil, contains a custom Config to use for this test.
+ config *Config
+ // cert, if not empty, contains a DER-encoded certificate for the
+ // reference server.
+ cert []byte
+ // key, if not nil, contains either a *rsa.PrivateKey, ed25519.PrivateKey or
+ // *ecdsa.PrivateKey which is the private key for the reference server.
+ key any
+ // extensions, if not nil, contains a list of extension data to be returned
+ // from the ServerHello. The data should be in standard TLS format with
+ // a 2-byte uint16 type, 2-byte data length, followed by the extension data.
+ extensions [][]byte
+ // validate, if not nil, is a function that will be called with the
+ // ConnectionState of the resulting connection. It returns a non-nil
+ // error if the ConnectionState is unacceptable.
+ validate func(ConnectionState) error
+ // numRenegotiations is the number of times that the connection will be
+ // renegotiated.
+ numRenegotiations int
+ // renegotiationExpectedToFail, if not zero, is the number of the
+ // renegotiation attempt that is expected to fail.
+ renegotiationExpectedToFail int
+ // checkRenegotiationError, if not nil, is called with any error
+ // arising from renegotiation. It can map expected errors to nil to
+ // ignore them.
+ checkRenegotiationError func(renegotiationNum int, err error) error
+ // sendKeyUpdate will cause the server to send a KeyUpdate message.
+ sendKeyUpdate bool
+}
+
+var serverCommand = []string{"openssl", "s_server", "-no_ticket", "-num_tickets", "0"}
+
+// connFromCommand starts the reference server process, connects to it and
+// returns a recordingConn for the connection. The stdin return value is an
+// opensslInput for the stdin of the child process. It must be closed before
+// Waiting for child.
+func (test *clientTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, stdin opensslInput, stdout *opensslOutputSink, err error) {
+ cert := testRSACertificate
+ if len(test.cert) > 0 {
+ cert = test.cert
+ }
+ certPath := tempFile(string(cert))
+ defer os.Remove(certPath)
+
+ var key any = testRSAPrivateKey
+ if test.key != nil {
+ key = test.key
+ }
+ derBytes, err := x509.MarshalPKCS8PrivateKey(key)
+ if err != nil {
+ panic(err)
+ }
+
+ var pemOut bytes.Buffer
+ pem.Encode(&pemOut, &pem.Block{Type: "PRIVATE KEY", Bytes: derBytes})
+
+ keyPath := tempFile(pemOut.String())
+ defer os.Remove(keyPath)
+
+ var command []string
+ command = append(command, serverCommand...)
+ command = append(command, test.args...)
+ command = append(command, "-cert", certPath, "-certform", "DER", "-key", keyPath)
+ // serverPort contains the port that OpenSSL will listen on. OpenSSL
+ // can't take "0" as an argument here so we have to pick a number and
+ // hope that it's not in use on the machine. Since this only occurs
+ // when -update is given and thus when there's a human watching the
+ // test, this isn't too bad.
+ const serverPort = 24323
+ command = append(command, "-accept", strconv.Itoa(serverPort))
+
+ if len(test.extensions) > 0 {
+ var serverInfo bytes.Buffer
+ for _, ext := range test.extensions {
+ pem.Encode(&serverInfo, &pem.Block{
+ Type: fmt.Sprintf("SERVERINFO FOR EXTENSION %d", binary.BigEndian.Uint16(ext)),
+ Bytes: ext,
+ })
+ }
+ serverInfoPath := tempFile(serverInfo.String())
+ defer os.Remove(serverInfoPath)
+ command = append(command, "-serverinfo", serverInfoPath)
+ }
+
+ if test.numRenegotiations > 0 || test.sendKeyUpdate {
+ found := false
+ for _, flag := range command[1:] {
+ if flag == "-state" {
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ panic("-state flag missing to OpenSSL, you need this if testing renegotiation or KeyUpdate")
+ }
+ }
+
+ cmd := exec.Command(command[0], command[1:]...)
+ stdin = opensslInput(make(chan opensslInputEvent))
+ cmd.Stdin = stdin
+ out := newOpensslOutputSink()
+ cmd.Stdout = out
+ cmd.Stderr = out
+ if err := cmd.Start(); err != nil {
+ return nil, nil, nil, nil, err
+ }
+
+ // OpenSSL does print an "ACCEPT" banner, but it does so *before*
+ // opening the listening socket, so we can't use that to wait until it
+ // has started listening. Thus we are forced to poll until we get a
+ // connection.
+ var tcpConn net.Conn
+ for i := uint(0); i < 5; i++ {
+ tcpConn, err = net.DialTCP("tcp", nil, &net.TCPAddr{
+ IP: net.IPv4(127, 0, 0, 1),
+ Port: serverPort,
+ })
+ if err == nil {
+ break
+ }
+ time.Sleep((1 << i) * 5 * time.Millisecond)
+ }
+ if err != nil {
+ close(stdin)
+ cmd.Process.Kill()
+ err = fmt.Errorf("error connecting to the OpenSSL server: %v (%v)\n\n%s", err, cmd.Wait(), out)
+ return nil, nil, nil, nil, err
+ }
+
+ record := &recordingConn{
+ Conn: tcpConn,
+ }
+
+ return record, cmd, stdin, out, nil
+}
+
+func (test *clientTest) dataPath() string {
+ return filepath.Join("testdata", "Client-"+test.name)
+}
+
+func (test *clientTest) loadData() (flows [][]byte, err error) {
+ in, err := os.Open(test.dataPath())
+ if err != nil {
+ return nil, err
+ }
+ defer in.Close()
+ return parseTestData(in)
+}
+
+func (test *clientTest) run(t *testing.T, write bool) {
+ var clientConn, serverConn net.Conn
+ var recordingConn *recordingConn
+ var childProcess *exec.Cmd
+ var stdin opensslInput
+ var stdout *opensslOutputSink
+
+ if write {
+ var err error
+ recordingConn, childProcess, stdin, stdout, err = test.connFromCommand()
+ if err != nil {
+ t.Fatalf("Failed to start subcommand: %s", err)
+ }
+ clientConn = recordingConn
+ defer func() {
+ if t.Failed() {
+ t.Logf("OpenSSL output:\n\n%s", stdout.all)
+ }
+ }()
+ } else {
+ clientConn, serverConn = localPipe(t)
+ }
+
+ doneChan := make(chan bool)
+ defer func() {
+ clientConn.Close()
+ <-doneChan
+ }()
+ go func() {
+ defer close(doneChan)
+
+ config := test.config
+ if config == nil {
+ config = testConfig
+ }
+ client := Client(clientConn, config)
+ defer client.Close()
+
+ if _, err := client.Write([]byte("hello\n")); err != nil {
+ t.Errorf("Client.Write failed: %s", err)
+ return
+ }
+
+ for i := 1; i <= test.numRenegotiations; i++ {
+ // The initial handshake will generate a
+ // handshakeComplete signal which needs to be quashed.
+ if i == 1 && write {
+ <-stdout.handshakeComplete
+ }
+
+ // OpenSSL will try to interleave application data and
+ // a renegotiation if we send both concurrently.
+ // Therefore: ask OpensSSL to start a renegotiation, run
+ // a goroutine to call client.Read and thus process the
+ // renegotiation request, watch for OpenSSL's stdout to
+ // indicate that the handshake is complete and,
+ // finally, have OpenSSL write something to cause
+ // client.Read to complete.
+ if write {
+ stdin <- opensslRenegotiate
+ }
+
+ signalChan := make(chan struct{})
+
+ go func() {
+ defer close(signalChan)
+
+ buf := make([]byte, 256)
+ n, err := client.Read(buf)
+
+ if test.checkRenegotiationError != nil {
+ newErr := test.checkRenegotiationError(i, err)
+ if err != nil && newErr == nil {
+ return
+ }
+ err = newErr
+ }
+
+ if err != nil {
+ t.Errorf("Client.Read failed after renegotiation #%d: %s", i, err)
+ return
+ }
+
+ buf = buf[:n]
+ if !bytes.Equal([]byte(opensslSentinel), buf) {
+ t.Errorf("Client.Read returned %q, but wanted %q", string(buf), opensslSentinel)
+ }
+
+ if expected := i + 1; client.handshakes != expected {
+ t.Errorf("client should have recorded %d handshakes, but believes that %d have occurred", expected, client.handshakes)
+ }
+ }()
+
+ if write && test.renegotiationExpectedToFail != i {
+ <-stdout.handshakeComplete
+ stdin <- opensslSendSentinel
+ }
+ <-signalChan
+ }
+
+ if test.sendKeyUpdate {
+ if write {
+ <-stdout.handshakeComplete
+ stdin <- opensslKeyUpdate
+ }
+
+ doneRead := make(chan struct{})
+
+ go func() {
+ defer close(doneRead)
+
+ buf := make([]byte, 256)
+ n, err := client.Read(buf)
+
+ if err != nil {
+ t.Errorf("Client.Read failed after KeyUpdate: %s", err)
+ return
+ }
+
+ buf = buf[:n]
+ if !bytes.Equal([]byte(opensslSentinel), buf) {
+ t.Errorf("Client.Read returned %q, but wanted %q", string(buf), opensslSentinel)
+ }
+ }()
+
+ if write {
+ // There's no real reason to wait for the client KeyUpdate to
+ // send data with the new server keys, except that s_server
+ // drops writes if they are sent at the wrong time.
+ <-stdout.readKeyUpdate
+ stdin <- opensslSendSentinel
+ }
+ <-doneRead
+
+ if _, err := client.Write([]byte("hello again\n")); err != nil {
+ t.Errorf("Client.Write failed: %s", err)
+ return
+ }
+ }
+
+ if test.validate != nil {
+ if err := test.validate(client.ConnectionState()); err != nil {
+ t.Errorf("validate callback returned error: %s", err)
+ }
+ }
+
+ // If the server sent us an alert after our last flight, give it a
+ // chance to arrive.
+ if write && test.renegotiationExpectedToFail == 0 {
+ if err := peekError(client); err != nil {
+ t.Errorf("final Read returned an error: %s", err)
+ }
+ }
+ }()
+
+ if !write {
+ flows, err := test.loadData()
+ if err != nil {
+ t.Fatalf("%s: failed to load data from %s: %v", test.name, test.dataPath(), err)
+ }
+ for i, b := range flows {
+ if i%2 == 1 {
+ if *fast {
+ serverConn.SetWriteDeadline(time.Now().Add(1 * time.Second))
+ } else {
+ serverConn.SetWriteDeadline(time.Now().Add(1 * time.Minute))
+ }
+ serverConn.Write(b)
+ continue
+ }
+ bb := make([]byte, len(b))
+ if *fast {
+ serverConn.SetReadDeadline(time.Now().Add(1 * time.Second))
+ } else {
+ serverConn.SetReadDeadline(time.Now().Add(1 * time.Minute))
+ }
+ _, err := io.ReadFull(serverConn, bb)
+ if err != nil {
+ t.Fatalf("%s, flow %d: %s", test.name, i+1, err)
+ }
+ if !bytes.Equal(b, bb) {
+ t.Fatalf("%s, flow %d: mismatch on read: got:%x want:%x", test.name, i+1, bb, b)
+ }
+ }
+ }
+
+ <-doneChan
+ if !write {
+ serverConn.Close()
+ }
+
+ if write {
+ path := test.dataPath()
+ out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+ if err != nil {
+ t.Fatalf("Failed to create output file: %s", err)
+ }
+ defer out.Close()
+ recordingConn.Close()
+ close(stdin)
+ childProcess.Process.Kill()
+ childProcess.Wait()
+ if len(recordingConn.flows) < 3 {
+ t.Fatalf("Client connection didn't work")
+ }
+ recordingConn.WriteTo(out)
+ t.Logf("Wrote %s\n", path)
+ }
+}
+
+// peekError does a read with a short timeout to check if the next read would
+// cause an error, for example if there is an alert waiting on the wire.
+func peekError(conn net.Conn) error {
+ conn.SetReadDeadline(time.Now().Add(100 * time.Millisecond))
+ if n, err := conn.Read(make([]byte, 1)); n != 0 {
+ return errors.New("unexpectedly read data")
+ } else if err != nil {
+ if netErr, ok := err.(net.Error); !ok || !netErr.Timeout() {
+ return err
+ }
+ }
+ return nil
+}
+
+func runClientTestForVersion(t *testing.T, template *clientTest, version, option string) {
+ // Make a deep copy of the template before going parallel.
+ test := *template
+ if template.config != nil {
+ test.config = template.config.Clone()
+ }
+ test.name = version + "-" + test.name
+ test.args = append([]string{option}, test.args...)
+
+ runTestAndUpdateIfNeeded(t, version, test.run, false)
+}
+
+func runClientTestTLS10(t *testing.T, template *clientTest) {
+ runClientTestForVersion(t, template, "TLSv10", "-tls1")
+}
+
+func runClientTestTLS11(t *testing.T, template *clientTest) {
+ runClientTestForVersion(t, template, "TLSv11", "-tls1_1")
+}
+
+func runClientTestTLS12(t *testing.T, template *clientTest) {
+ runClientTestForVersion(t, template, "TLSv12", "-tls1_2")
+}
+
+func runClientTestTLS13(t *testing.T, template *clientTest) {
+ runClientTestForVersion(t, template, "TLSv13", "-tls1_3")
+}
+
+func TestHandshakeClientRSARC4(t *testing.T) {
+ test := &clientTest{
+ name: "RSA-RC4",
+ args: []string{"-cipher", "RC4-SHA"},
+ }
+ runClientTestTLS10(t, test)
+ runClientTestTLS11(t, test)
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientRSAAES128GCM(t *testing.T) {
+ test := &clientTest{
+ name: "AES128-GCM-SHA256",
+ args: []string{"-cipher", "AES128-GCM-SHA256"},
+ }
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientRSAAES256GCM(t *testing.T) {
+ test := &clientTest{
+ name: "AES256-GCM-SHA384",
+ args: []string{"-cipher", "AES256-GCM-SHA384"},
+ }
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientECDHERSAAES(t *testing.T) {
+ test := &clientTest{
+ name: "ECDHE-RSA-AES",
+ args: []string{"-cipher", "ECDHE-RSA-AES128-SHA"},
+ }
+ runClientTestTLS10(t, test)
+ runClientTestTLS11(t, test)
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientECDHEECDSAAES(t *testing.T) {
+ test := &clientTest{
+ name: "ECDHE-ECDSA-AES",
+ args: []string{"-cipher", "ECDHE-ECDSA-AES128-SHA"},
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
+ runClientTestTLS10(t, test)
+ runClientTestTLS11(t, test)
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientECDHEECDSAAESGCM(t *testing.T) {
+ test := &clientTest{
+ name: "ECDHE-ECDSA-AES-GCM",
+ args: []string{"-cipher", "ECDHE-ECDSA-AES128-GCM-SHA256"},
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientAES256GCMSHA384(t *testing.T) {
+ test := &clientTest{
+ name: "ECDHE-ECDSA-AES256-GCM-SHA384",
+ args: []string{"-cipher", "ECDHE-ECDSA-AES256-GCM-SHA384"},
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientAES128CBCSHA256(t *testing.T) {
+ test := &clientTest{
+ name: "AES128-SHA256",
+ args: []string{"-cipher", "AES128-SHA256"},
+ }
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientECDHERSAAES128CBCSHA256(t *testing.T) {
+ test := &clientTest{
+ name: "ECDHE-RSA-AES128-SHA256",
+ args: []string{"-cipher", "ECDHE-RSA-AES128-SHA256"},
+ }
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientECDHEECDSAAES128CBCSHA256(t *testing.T) {
+ test := &clientTest{
+ name: "ECDHE-ECDSA-AES128-SHA256",
+ args: []string{"-cipher", "ECDHE-ECDSA-AES128-SHA256"},
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientX25519(t *testing.T) {
+ config := testConfig.Clone()
+ config.CurvePreferences = []CurveID{X25519}
+
+ test := &clientTest{
+ name: "X25519-ECDHE",
+ args: []string{"-cipher", "ECDHE-RSA-AES128-GCM-SHA256", "-curves", "X25519"},
+ config: config,
+ }
+
+ runClientTestTLS12(t, test)
+ runClientTestTLS13(t, test)
+}
+
+func TestHandshakeClientP256(t *testing.T) {
+ config := testConfig.Clone()
+ config.CurvePreferences = []CurveID{CurveP256}
+
+ test := &clientTest{
+ name: "P256-ECDHE",
+ args: []string{"-cipher", "ECDHE-RSA-AES128-GCM-SHA256", "-curves", "P-256"},
+ config: config,
+ }
+
+ runClientTestTLS12(t, test)
+ runClientTestTLS13(t, test)
+}
+
+func TestHandshakeClientHelloRetryRequest(t *testing.T) {
+ config := testConfig.Clone()
+ config.CurvePreferences = []CurveID{X25519, CurveP256}
+
+ test := &clientTest{
+ name: "HelloRetryRequest",
+ args: []string{"-cipher", "ECDHE-RSA-AES128-GCM-SHA256", "-curves", "P-256"},
+ config: config,
+ }
+
+ runClientTestTLS13(t, test)
+}
+
+func TestHandshakeClientECDHERSAChaCha20(t *testing.T) {
+ config := testConfig.Clone()
+ config.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305}
+
+ test := &clientTest{
+ name: "ECDHE-RSA-CHACHA20-POLY1305",
+ args: []string{"-cipher", "ECDHE-RSA-CHACHA20-POLY1305"},
+ config: config,
+ }
+
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientECDHEECDSAChaCha20(t *testing.T) {
+ config := testConfig.Clone()
+ config.CipherSuites = []uint16{TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305}
+
+ test := &clientTest{
+ name: "ECDHE-ECDSA-CHACHA20-POLY1305",
+ args: []string{"-cipher", "ECDHE-ECDSA-CHACHA20-POLY1305"},
+ config: config,
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
+
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientAES128SHA256(t *testing.T) {
+ test := &clientTest{
+ name: "AES128-SHA256",
+ args: []string{"-ciphersuites", "TLS_AES_128_GCM_SHA256"},
+ }
+ runClientTestTLS13(t, test)
+}
+func TestHandshakeClientAES256SHA384(t *testing.T) {
+ test := &clientTest{
+ name: "AES256-SHA384",
+ args: []string{"-ciphersuites", "TLS_AES_256_GCM_SHA384"},
+ }
+ runClientTestTLS13(t, test)
+}
+func TestHandshakeClientCHACHA20SHA256(t *testing.T) {
+ test := &clientTest{
+ name: "CHACHA20-SHA256",
+ args: []string{"-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256"},
+ }
+ runClientTestTLS13(t, test)
+}
+
+func TestHandshakeClientECDSATLS13(t *testing.T) {
+ test := &clientTest{
+ name: "ECDSA",
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
+ runClientTestTLS13(t, test)
+}
+
+func TestHandshakeClientEd25519(t *testing.T) {
+ test := &clientTest{
+ name: "Ed25519",
+ cert: testEd25519Certificate,
+ key: testEd25519PrivateKey,
+ }
+ runClientTestTLS12(t, test)
+ runClientTestTLS13(t, test)
+
+ config := testConfig.Clone()
+ cert, _ := X509KeyPair([]byte(clientEd25519CertificatePEM), []byte(clientEd25519KeyPEM))
+ config.Certificates = []Certificate{cert}
+
+ test = &clientTest{
+ name: "ClientCert-Ed25519",
+ args: []string{"-Verify", "1"},
+ config: config,
+ }
+
+ runClientTestTLS12(t, test)
+ runClientTestTLS13(t, test)
+}
+
+func TestHandshakeClientCertRSA(t *testing.T) {
+ config := testConfig.Clone()
+ cert, _ := X509KeyPair([]byte(clientCertificatePEM), []byte(clientKeyPEM))
+ config.Certificates = []Certificate{cert}
+
+ test := &clientTest{
+ name: "ClientCert-RSA-RSA",
+ args: []string{"-cipher", "AES128", "-Verify", "1"},
+ config: config,
+ }
+
+ runClientTestTLS10(t, test)
+ runClientTestTLS12(t, test)
+
+ test = &clientTest{
+ name: "ClientCert-RSA-ECDSA",
+ args: []string{"-cipher", "ECDHE-ECDSA-AES128-SHA", "-Verify", "1"},
+ config: config,
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
+
+ runClientTestTLS10(t, test)
+ runClientTestTLS12(t, test)
+ runClientTestTLS13(t, test)
+
+ test = &clientTest{
+ name: "ClientCert-RSA-AES256-GCM-SHA384",
+ args: []string{"-cipher", "ECDHE-RSA-AES256-GCM-SHA384", "-Verify", "1"},
+ config: config,
+ cert: testRSACertificate,
+ key: testRSAPrivateKey,
+ }
+
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientCertECDSA(t *testing.T) {
+ config := testConfig.Clone()
+ cert, _ := X509KeyPair([]byte(clientECDSACertificatePEM), []byte(clientECDSAKeyPEM))
+ config.Certificates = []Certificate{cert}
+
+ test := &clientTest{
+ name: "ClientCert-ECDSA-RSA",
+ args: []string{"-cipher", "AES128", "-Verify", "1"},
+ config: config,
+ }
+
+ runClientTestTLS10(t, test)
+ runClientTestTLS12(t, test)
+ runClientTestTLS13(t, test)
+
+ test = &clientTest{
+ name: "ClientCert-ECDSA-ECDSA",
+ args: []string{"-cipher", "ECDHE-ECDSA-AES128-SHA", "-Verify", "1"},
+ config: config,
+ cert: testECDSACertificate,
+ key: testECDSAPrivateKey,
+ }
+
+ runClientTestTLS10(t, test)
+ runClientTestTLS12(t, test)
+}
+
+// TestHandshakeClientCertRSAPSS tests rsa_pss_rsae_sha256 signatures from both
+// client and server certificates. It also serves from both sides a certificate
+// signed itself with RSA-PSS, mostly to check that crypto/x509 chain validation
+// works.
+func TestHandshakeClientCertRSAPSS(t *testing.T) {
+ cert, err := x509.ParseCertificate(testRSAPSSCertificate)
+ if err != nil {
+ panic(err)
+ }
+ rootCAs := x509.NewCertPool()
+ rootCAs.AddCert(cert)
+
+ config := testConfig.Clone()
+ // Use GetClientCertificate to bypass the client certificate selection logic.
+ config.GetClientCertificate = func(*CertificateRequestInfo) (*Certificate, error) {
+ return &Certificate{
+ Certificate: [][]byte{testRSAPSSCertificate},
+ PrivateKey: testRSAPrivateKey,
+ }, nil
+ }
+ config.RootCAs = rootCAs
+
+ test := &clientTest{
+ name: "ClientCert-RSA-RSAPSS",
+ args: []string{"-cipher", "AES128", "-Verify", "1", "-client_sigalgs",
+ "rsa_pss_rsae_sha256", "-sigalgs", "rsa_pss_rsae_sha256"},
+ config: config,
+ cert: testRSAPSSCertificate,
+ key: testRSAPrivateKey,
+ }
+ runClientTestTLS12(t, test)
+ runClientTestTLS13(t, test)
+}
+
+func TestHandshakeClientCertRSAPKCS1v15(t *testing.T) {
+ config := testConfig.Clone()
+ cert, _ := X509KeyPair([]byte(clientCertificatePEM), []byte(clientKeyPEM))
+ config.Certificates = []Certificate{cert}
+
+ test := &clientTest{
+ name: "ClientCert-RSA-RSAPKCS1v15",
+ args: []string{"-cipher", "AES128", "-Verify", "1", "-client_sigalgs",
+ "rsa_pkcs1_sha256", "-sigalgs", "rsa_pkcs1_sha256"},
+ config: config,
+ }
+
+ runClientTestTLS12(t, test)
+}
+
+func TestClientKeyUpdate(t *testing.T) {
+ test := &clientTest{
+ name: "KeyUpdate",
+ args: []string{"-state"},
+ sendKeyUpdate: true,
+ }
+ runClientTestTLS13(t, test)
+}
+
+func TestResumption(t *testing.T) {
+ t.Run("TLSv12", func(t *testing.T) { testResumption(t, VersionTLS12) })
+ t.Run("TLSv13", func(t *testing.T) { testResumption(t, VersionTLS13) })
+}
+
+func testResumption(t *testing.T, version uint16) {
+ if testing.Short() {
+ t.Skip("skipping in -short mode")
+ }
+ serverConfig := &Config{
+ MaxVersion: version,
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+ Certificates: testConfig.Certificates,
+ }
+
+ issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
+ if err != nil {
+ panic(err)
+ }
+
+ rootCAs := x509.NewCertPool()
+ rootCAs.AddCert(issuer)
+
+ clientConfig := &Config{
+ MaxVersion: version,
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ ClientSessionCache: NewLRUClientSessionCache(32),
+ RootCAs: rootCAs,
+ ServerName: "example.golang",
+ }
+
+ testResumeState := func(test string, didResume bool) {
+ _, hs, err := testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("%s: handshake failed: %s", test, err)
+ }
+ if hs.DidResume != didResume {
+ t.Fatalf("%s resumed: %v, expected: %v", test, hs.DidResume, didResume)
+ }
+ if didResume && (hs.PeerCertificates == nil || hs.VerifiedChains == nil) {
+ t.Fatalf("expected non-nil certificates after resumption. Got peerCertificates: %#v, verifiedCertificates: %#v", hs.PeerCertificates, hs.VerifiedChains)
+ }
+ if got, want := hs.ServerName, clientConfig.ServerName; got != want {
+ t.Errorf("%s: server name %s, want %s", test, got, want)
+ }
+ }
+
+ getTicket := func() []byte {
+ return clientConfig.ClientSessionCache.(*lruSessionCache).q.Front().Value.(*lruSessionCacheEntry).state.sessionTicket
+ }
+ deleteTicket := func() {
+ ticketKey := clientConfig.ClientSessionCache.(*lruSessionCache).q.Front().Value.(*lruSessionCacheEntry).sessionKey
+ clientConfig.ClientSessionCache.Put(ticketKey, nil)
+ }
+ corruptTicket := func() {
+ clientConfig.ClientSessionCache.(*lruSessionCache).q.Front().Value.(*lruSessionCacheEntry).state.masterSecret[0] ^= 0xff
+ }
+ randomKey := func() [32]byte {
+ var k [32]byte
+ if _, err := io.ReadFull(serverConfig.rand(), k[:]); err != nil {
+ t.Fatalf("Failed to read new SessionTicketKey: %s", err)
+ }
+ return k
+ }
+
+ testResumeState("Handshake", false)
+ ticket := getTicket()
+ testResumeState("Resume", true)
+ if !bytes.Equal(ticket, getTicket()) && version != VersionTLS13 {
+ t.Fatal("first ticket doesn't match ticket after resumption")
+ }
+ if bytes.Equal(ticket, getTicket()) && version == VersionTLS13 {
+ t.Fatal("ticket didn't change after resumption")
+ }
+
+ // An old session ticket can resume, but the server will provide a ticket encrypted with a fresh key.
+ serverConfig.Time = func() time.Time { return time.Now().Add(24*time.Hour + time.Minute) }
+ testResumeState("ResumeWithOldTicket", true)
+ if bytes.Equal(ticket[:ticketKeyNameLen], getTicket()[:ticketKeyNameLen]) {
+ t.Fatal("old first ticket matches the fresh one")
+ }
+
+ // Now the session tickey key is expired, so a full handshake should occur.
+ serverConfig.Time = func() time.Time { return time.Now().Add(24*8*time.Hour + time.Minute) }
+ testResumeState("ResumeWithExpiredTicket", false)
+ if bytes.Equal(ticket, getTicket()) {
+ t.Fatal("expired first ticket matches the fresh one")
+ }
+
+ serverConfig.Time = func() time.Time { return time.Now() } // reset the time back
+ key1 := randomKey()
+ serverConfig.SetSessionTicketKeys([][32]byte{key1})
+
+ testResumeState("InvalidSessionTicketKey", false)
+ testResumeState("ResumeAfterInvalidSessionTicketKey", true)
+
+ key2 := randomKey()
+ serverConfig.SetSessionTicketKeys([][32]byte{key2, key1})
+ ticket = getTicket()
+ testResumeState("KeyChange", true)
+ if bytes.Equal(ticket, getTicket()) {
+ t.Fatal("new ticket wasn't included while resuming")
+ }
+ testResumeState("KeyChangeFinish", true)
+
+ // Age the session ticket a bit, but not yet expired.
+ serverConfig.Time = func() time.Time { return time.Now().Add(24*time.Hour + time.Minute) }
+ testResumeState("OldSessionTicket", true)
+ ticket = getTicket()
+ // Expire the session ticket, which would force a full handshake.
+ serverConfig.Time = func() time.Time { return time.Now().Add(24*8*time.Hour + time.Minute) }
+ testResumeState("ExpiredSessionTicket", false)
+ if bytes.Equal(ticket, getTicket()) {
+ t.Fatal("new ticket wasn't provided after old ticket expired")
+ }
+
+ // Age the session ticket a bit at a time, but don't expire it.
+ d := 0 * time.Hour
+ for i := 0; i < 13; i++ {
+ d += 12 * time.Hour
+ serverConfig.Time = func() time.Time { return time.Now().Add(d) }
+ testResumeState("OldSessionTicket", true)
+ }
+ // Expire it (now a little more than 7 days) and make sure a full
+ // handshake occurs for TLS 1.2. Resumption should still occur for
+ // TLS 1.3 since the client should be using a fresh ticket sent over
+ // by the server.
+ d += 12 * time.Hour
+ serverConfig.Time = func() time.Time { return time.Now().Add(d) }
+ if version == VersionTLS13 {
+ testResumeState("ExpiredSessionTicket", true)
+ } else {
+ testResumeState("ExpiredSessionTicket", false)
+ }
+ if bytes.Equal(ticket, getTicket()) {
+ t.Fatal("new ticket wasn't provided after old ticket expired")
+ }
+
+ // Reset serverConfig to ensure that calling SetSessionTicketKeys
+ // before the serverConfig is used works.
+ serverConfig = &Config{
+ MaxVersion: version,
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+ Certificates: testConfig.Certificates,
+ }
+ serverConfig.SetSessionTicketKeys([][32]byte{key2})
+
+ testResumeState("FreshConfig", true)
+
+ // In TLS 1.3, cross-cipher suite resumption is allowed as long as the KDF
+ // hash matches. Also, Config.CipherSuites does not apply to TLS 1.3.
+ if version != VersionTLS13 {
+ clientConfig.CipherSuites = []uint16{TLS_ECDHE_RSA_WITH_RC4_128_SHA}
+ testResumeState("DifferentCipherSuite", false)
+ testResumeState("DifferentCipherSuiteRecovers", true)
+ }
+
+ deleteTicket()
+ testResumeState("WithoutSessionTicket", false)
+
+ // In TLS 1.3, HelloRetryRequest is sent after incorrect key share.
+ // See https://www.rfc-editor.org/rfc/rfc8446#page-14.
+ if version == VersionTLS13 {
+ deleteTicket()
+ serverConfig = &Config{
+ // Use a different curve than the client to force a HelloRetryRequest.
+ CurvePreferences: []CurveID{CurveP521, CurveP384, CurveP256},
+ MaxVersion: version,
+ Certificates: testConfig.Certificates,
+ }
+ testResumeState("InitialHandshake", false)
+ testResumeState("WithHelloRetryRequest", true)
+
+ // Reset serverConfig back.
+ serverConfig = &Config{
+ MaxVersion: version,
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_ECDHE_RSA_WITH_RC4_128_SHA},
+ Certificates: testConfig.Certificates,
+ }
+ }
+
+ // Session resumption should work when using client certificates
+ deleteTicket()
+ serverConfig.ClientCAs = rootCAs
+ serverConfig.ClientAuth = RequireAndVerifyClientCert
+ clientConfig.Certificates = serverConfig.Certificates
+ testResumeState("InitialHandshake", false)
+ testResumeState("WithClientCertificates", true)
+ serverConfig.ClientAuth = NoClientCert
+
+ // Tickets should be removed from the session cache on TLS handshake
+ // failure, and the client should recover from a corrupted PSK
+ testResumeState("FetchTicketToCorrupt", false)
+ corruptTicket()
+ _, _, err = testHandshake(t, clientConfig, serverConfig)
+ if err == nil {
+ t.Fatalf("handshake did not fail with a corrupted client secret")
+ }
+ testResumeState("AfterHandshakeFailure", false)
+
+ clientConfig.ClientSessionCache = nil
+ testResumeState("WithoutSessionCache", false)
+}
+
+func TestLRUClientSessionCache(t *testing.T) {
+ // Initialize cache of capacity 4.
+ cache := NewLRUClientSessionCache(4)
+ cs := make([]ClientSessionState, 6)
+ keys := []string{"0", "1", "2", "3", "4", "5", "6"}
+
+ // Add 4 entries to the cache and look them up.
+ for i := 0; i < 4; i++ {
+ cache.Put(keys[i], &cs[i])
+ }
+ for i := 0; i < 4; i++ {
+ if s, ok := cache.Get(keys[i]); !ok || s != &cs[i] {
+ t.Fatalf("session cache failed lookup for added key: %s", keys[i])
+ }
+ }
+
+ // Add 2 more entries to the cache. First 2 should be evicted.
+ for i := 4; i < 6; i++ {
+ cache.Put(keys[i], &cs[i])
+ }
+ for i := 0; i < 2; i++ {
+ if s, ok := cache.Get(keys[i]); ok || s != nil {
+ t.Fatalf("session cache should have evicted key: %s", keys[i])
+ }
+ }
+
+ // Touch entry 2. LRU should evict 3 next.
+ cache.Get(keys[2])
+ cache.Put(keys[0], &cs[0])
+ if s, ok := cache.Get(keys[3]); ok || s != nil {
+ t.Fatalf("session cache should have evicted key 3")
+ }
+
+ // Update entry 0 in place.
+ cache.Put(keys[0], &cs[3])
+ if s, ok := cache.Get(keys[0]); !ok || s != &cs[3] {
+ t.Fatalf("session cache failed update for key 0")
+ }
+
+ // Calling Put with a nil entry deletes the key.
+ cache.Put(keys[0], nil)
+ if _, ok := cache.Get(keys[0]); ok {
+ t.Fatalf("session cache failed to delete key 0")
+ }
+
+ // Delete entry 2. LRU should keep 4 and 5
+ cache.Put(keys[2], nil)
+ if _, ok := cache.Get(keys[2]); ok {
+ t.Fatalf("session cache failed to delete key 4")
+ }
+ for i := 4; i < 6; i++ {
+ if s, ok := cache.Get(keys[i]); !ok || s != &cs[i] {
+ t.Fatalf("session cache should not have deleted key: %s", keys[i])
+ }
+ }
+}
+
+func TestKeyLogTLS12(t *testing.T) {
+ var serverBuf, clientBuf bytes.Buffer
+
+ clientConfig := testConfig.Clone()
+ clientConfig.KeyLogWriter = &clientBuf
+ clientConfig.MaxVersion = VersionTLS12
+
+ serverConfig := testConfig.Clone()
+ serverConfig.KeyLogWriter = &serverBuf
+ serverConfig.MaxVersion = VersionTLS12
+
+ c, s := localPipe(t)
+ done := make(chan bool)
+
+ go func() {
+ defer close(done)
+
+ if err := Server(s, serverConfig).Handshake(); err != nil {
+ t.Errorf("server: %s", err)
+ return
+ }
+ s.Close()
+ }()
+
+ if err := Client(c, clientConfig).Handshake(); err != nil {
+ t.Fatalf("client: %s", err)
+ }
+
+ c.Close()
+ <-done
+
+ checkKeylogLine := func(side, loggedLine string) {
+ if len(loggedLine) == 0 {
+ t.Fatalf("%s: no keylog line was produced", side)
+ }
+ const expectedLen = 13 /* "CLIENT_RANDOM" */ +
+ 1 /* space */ +
+ 32*2 /* hex client nonce */ +
+ 1 /* space */ +
+ 48*2 /* hex master secret */ +
+ 1 /* new line */
+ if len(loggedLine) != expectedLen {
+ t.Fatalf("%s: keylog line has incorrect length (want %d, got %d): %q", side, expectedLen, len(loggedLine), loggedLine)
+ }
+ if !strings.HasPrefix(loggedLine, "CLIENT_RANDOM "+strings.Repeat("0", 64)+" ") {
+ t.Fatalf("%s: keylog line has incorrect structure or nonce: %q", side, loggedLine)
+ }
+ }
+
+ checkKeylogLine("client", clientBuf.String())
+ checkKeylogLine("server", serverBuf.String())
+}
+
+func TestKeyLogTLS13(t *testing.T) {
+ var serverBuf, clientBuf bytes.Buffer
+
+ clientConfig := testConfig.Clone()
+ clientConfig.KeyLogWriter = &clientBuf
+
+ serverConfig := testConfig.Clone()
+ serverConfig.KeyLogWriter = &serverBuf
+
+ c, s := localPipe(t)
+ done := make(chan bool)
+
+ go func() {
+ defer close(done)
+
+ if err := Server(s, serverConfig).Handshake(); err != nil {
+ t.Errorf("server: %s", err)
+ return
+ }
+ s.Close()
+ }()
+
+ if err := Client(c, clientConfig).Handshake(); err != nil {
+ t.Fatalf("client: %s", err)
+ }
+
+ c.Close()
+ <-done
+
+ checkKeylogLines := func(side, loggedLines string) {
+ loggedLines = strings.TrimSpace(loggedLines)
+ lines := strings.Split(loggedLines, "\n")
+ if len(lines) != 4 {
+ t.Errorf("Expected the %s to log 4 lines, got %d", side, len(lines))
+ }
+ }
+
+ checkKeylogLines("client", clientBuf.String())
+ checkKeylogLines("server", serverBuf.String())
+}
+
+func TestHandshakeClientALPNMatch(t *testing.T) {
+ config := testConfig.Clone()
+ config.NextProtos = []string{"proto2", "proto1"}
+
+ test := &clientTest{
+ name: "ALPN",
+ // Note that this needs OpenSSL 1.0.2 because that is the first
+ // version that supports the -alpn flag.
+ args: []string{"-alpn", "proto1,proto2"},
+ config: config,
+ validate: func(state ConnectionState) error {
+ // The server's preferences should override the client.
+ if state.NegotiatedProtocol != "proto1" {
+ return fmt.Errorf("Got protocol %q, wanted proto1", state.NegotiatedProtocol)
+ }
+ return nil
+ },
+ }
+ runClientTestTLS12(t, test)
+ runClientTestTLS13(t, test)
+}
+
+func TestServerSelectingUnconfiguredApplicationProtocol(t *testing.T) {
+ // This checks that the server can't select an application protocol that the
+ // client didn't offer.
+
+ c, s := localPipe(t)
+ errChan := make(chan error, 1)
+
+ go func() {
+ client := Client(c, &Config{
+ ServerName: "foo",
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ NextProtos: []string{"http", "something-else"},
+ })
+ errChan <- client.Handshake()
+ }()
+
+ var header [5]byte
+ if _, err := io.ReadFull(s, header[:]); err != nil {
+ t.Fatal(err)
+ }
+ recordLen := int(header[3])<<8 | int(header[4])
+
+ record := make([]byte, recordLen)
+ if _, err := io.ReadFull(s, record); err != nil {
+ t.Fatal(err)
+ }
+
+ serverHello := &serverHelloMsg{
+ vers: VersionTLS12,
+ random: make([]byte, 32),
+ cipherSuite: TLS_RSA_WITH_AES_128_GCM_SHA256,
+ alpnProtocol: "how-about-this",
+ }
+ serverHelloBytes := mustMarshal(t, serverHello)
+
+ s.Write([]byte{
+ byte(recordTypeHandshake),
+ byte(VersionTLS12 >> 8),
+ byte(VersionTLS12 & 0xff),
+ byte(len(serverHelloBytes) >> 8),
+ byte(len(serverHelloBytes)),
+ })
+ s.Write(serverHelloBytes)
+ s.Close()
+
+ if err := <-errChan; !strings.Contains(err.Error(), "server selected unadvertised ALPN protocol") {
+ t.Fatalf("Expected error about unconfigured cipher suite but got %q", err)
+ }
+}
+
+// sctsBase64 contains data from `openssl s_client -serverinfo 18 -connect ritter.vg:443`
+const sctsBase64 = "ABIBaQFnAHUApLkJkLQYWBSHuxOizGdwCjw1mAT5G9+443fNDsgN3BAAAAFHl5nuFgAABAMARjBEAiAcS4JdlW5nW9sElUv2zvQyPoZ6ejKrGGB03gjaBZFMLwIgc1Qbbn+hsH0RvObzhS+XZhr3iuQQJY8S9G85D9KeGPAAdgBo9pj4H2SCvjqM7rkoHUz8cVFdZ5PURNEKZ6y7T0/7xAAAAUeX4bVwAAAEAwBHMEUCIDIhFDgG2HIuADBkGuLobU5a4dlCHoJLliWJ1SYT05z6AiEAjxIoZFFPRNWMGGIjskOTMwXzQ1Wh2e7NxXE1kd1J0QsAdgDuS723dc5guuFCaR+r4Z5mow9+X7By2IMAxHuJeqj9ywAAAUhcZIqHAAAEAwBHMEUCICmJ1rBT09LpkbzxtUC+Hi7nXLR0J+2PmwLp+sJMuqK+AiEAr0NkUnEVKVhAkccIFpYDqHOlZaBsuEhWWrYpg2RtKp0="
+
+func TestHandshakClientSCTs(t *testing.T) {
+ config := testConfig.Clone()
+
+ scts, err := base64.StdEncoding.DecodeString(sctsBase64)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Note that this needs OpenSSL 1.0.2 because that is the first
+ // version that supports the -serverinfo flag.
+ test := &clientTest{
+ name: "SCT",
+ config: config,
+ extensions: [][]byte{scts},
+ validate: func(state ConnectionState) error {
+ expectedSCTs := [][]byte{
+ scts[8:125],
+ scts[127:245],
+ scts[247:],
+ }
+ if n := len(state.SignedCertificateTimestamps); n != len(expectedSCTs) {
+ return fmt.Errorf("Got %d scts, wanted %d", n, len(expectedSCTs))
+ }
+ for i, expected := range expectedSCTs {
+ if sct := state.SignedCertificateTimestamps[i]; !bytes.Equal(sct, expected) {
+ return fmt.Errorf("SCT #%d contained %x, expected %x", i, sct, expected)
+ }
+ }
+ return nil
+ },
+ }
+ runClientTestTLS12(t, test)
+
+ // TLS 1.3 moved SCTs to the Certificate extensions and -serverinfo only
+ // supports ServerHello extensions.
+}
+
+func TestRenegotiationRejected(t *testing.T) {
+ config := testConfig.Clone()
+ test := &clientTest{
+ name: "RenegotiationRejected",
+ args: []string{"-state"},
+ config: config,
+ numRenegotiations: 1,
+ renegotiationExpectedToFail: 1,
+ checkRenegotiationError: func(renegotiationNum int, err error) error {
+ if err == nil {
+ return errors.New("expected error from renegotiation but got nil")
+ }
+ if !strings.Contains(err.Error(), "no renegotiation") {
+ return fmt.Errorf("expected renegotiation to be rejected but got %q", err)
+ }
+ return nil
+ },
+ }
+ runClientTestTLS12(t, test)
+}
+
+func TestRenegotiateOnce(t *testing.T) {
+ config := testConfig.Clone()
+ config.Renegotiation = RenegotiateOnceAsClient
+
+ test := &clientTest{
+ name: "RenegotiateOnce",
+ args: []string{"-state"},
+ config: config,
+ numRenegotiations: 1,
+ }
+
+ runClientTestTLS12(t, test)
+}
+
+func TestRenegotiateTwice(t *testing.T) {
+ config := testConfig.Clone()
+ config.Renegotiation = RenegotiateFreelyAsClient
+
+ test := &clientTest{
+ name: "RenegotiateTwice",
+ args: []string{"-state"},
+ config: config,
+ numRenegotiations: 2,
+ }
+
+ runClientTestTLS12(t, test)
+}
+
+func TestRenegotiateTwiceRejected(t *testing.T) {
+ config := testConfig.Clone()
+ config.Renegotiation = RenegotiateOnceAsClient
+
+ test := &clientTest{
+ name: "RenegotiateTwiceRejected",
+ args: []string{"-state"},
+ config: config,
+ numRenegotiations: 2,
+ renegotiationExpectedToFail: 2,
+ checkRenegotiationError: func(renegotiationNum int, err error) error {
+ if renegotiationNum == 1 {
+ return err
+ }
+
+ if err == nil {
+ return errors.New("expected error from renegotiation but got nil")
+ }
+ if !strings.Contains(err.Error(), "no renegotiation") {
+ return fmt.Errorf("expected renegotiation to be rejected but got %q", err)
+ }
+ return nil
+ },
+ }
+
+ runClientTestTLS12(t, test)
+}
+
+func TestHandshakeClientExportKeyingMaterial(t *testing.T) {
+ test := &clientTest{
+ name: "ExportKeyingMaterial",
+ config: testConfig.Clone(),
+ validate: func(state ConnectionState) error {
+ if km, err := state.ExportKeyingMaterial("test", nil, 42); err != nil {
+ return fmt.Errorf("ExportKeyingMaterial failed: %v", err)
+ } else if len(km) != 42 {
+ return fmt.Errorf("Got %d bytes from ExportKeyingMaterial, wanted %d", len(km), 42)
+ }
+ return nil
+ },
+ }
+ runClientTestTLS10(t, test)
+ runClientTestTLS12(t, test)
+ runClientTestTLS13(t, test)
+}
+
+var hostnameInSNITests = []struct {
+ in, out string
+}{
+ // Opaque string
+ {"", ""},
+ {"localhost", "localhost"},
+ {"foo, bar, baz and qux", "foo, bar, baz and qux"},
+
+ // DNS hostname
+ {"golang.org", "golang.org"},
+ {"golang.org.", "golang.org"},
+
+ // Literal IPv4 address
+ {"1.2.3.4", ""},
+
+ // Literal IPv6 address
+ {"::1", ""},
+ {"::1%lo0", ""}, // with zone identifier
+ {"[::1]", ""}, // as per RFC 5952 we allow the [] style as IPv6 literal
+ {"[::1%lo0]", ""},
+}
+
+func TestHostnameInSNI(t *testing.T) {
+ for _, tt := range hostnameInSNITests {
+ c, s := localPipe(t)
+
+ go func(host string) {
+ Client(c, &Config{ServerName: host, InsecureSkipVerify: true}).Handshake()
+ }(tt.in)
+
+ var header [5]byte
+ if _, err := io.ReadFull(s, header[:]); err != nil {
+ t.Fatal(err)
+ }
+ recordLen := int(header[3])<<8 | int(header[4])
+
+ record := make([]byte, recordLen)
+ if _, err := io.ReadFull(s, record[:]); err != nil {
+ t.Fatal(err)
+ }
+
+ c.Close()
+ s.Close()
+
+ var m clientHelloMsg
+ if !m.unmarshal(record) {
+ t.Errorf("unmarshaling ClientHello for %q failed", tt.in)
+ continue
+ }
+ if tt.in != tt.out && m.serverName == tt.in {
+ t.Errorf("prohibited %q found in ClientHello: %x", tt.in, record)
+ }
+ if m.serverName != tt.out {
+ t.Errorf("expected %q not found in ClientHello: %x", tt.out, record)
+ }
+ }
+}
+
+func TestServerSelectingUnconfiguredCipherSuite(t *testing.T) {
+ // This checks that the server can't select a cipher suite that the
+ // client didn't offer. See #13174.
+
+ c, s := localPipe(t)
+ errChan := make(chan error, 1)
+
+ go func() {
+ client := Client(c, &Config{
+ ServerName: "foo",
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ })
+ errChan <- client.Handshake()
+ }()
+
+ var header [5]byte
+ if _, err := io.ReadFull(s, header[:]); err != nil {
+ t.Fatal(err)
+ }
+ recordLen := int(header[3])<<8 | int(header[4])
+
+ record := make([]byte, recordLen)
+ if _, err := io.ReadFull(s, record); err != nil {
+ t.Fatal(err)
+ }
+
+ // Create a ServerHello that selects a different cipher suite than the
+ // sole one that the client offered.
+ serverHello := &serverHelloMsg{
+ vers: VersionTLS12,
+ random: make([]byte, 32),
+ cipherSuite: TLS_RSA_WITH_AES_256_GCM_SHA384,
+ }
+ serverHelloBytes := mustMarshal(t, serverHello)
+
+ s.Write([]byte{
+ byte(recordTypeHandshake),
+ byte(VersionTLS12 >> 8),
+ byte(VersionTLS12 & 0xff),
+ byte(len(serverHelloBytes) >> 8),
+ byte(len(serverHelloBytes)),
+ })
+ s.Write(serverHelloBytes)
+ s.Close()
+
+ if err := <-errChan; !strings.Contains(err.Error(), "unconfigured cipher") {
+ t.Fatalf("Expected error about unconfigured cipher suite but got %q", err)
+ }
+}
+
+func TestVerifyConnection(t *testing.T) {
+ t.Run("TLSv12", func(t *testing.T) { testVerifyConnection(t, VersionTLS12) })
+ t.Run("TLSv13", func(t *testing.T) { testVerifyConnection(t, VersionTLS13) })
+}
+
+func testVerifyConnection(t *testing.T, version uint16) {
+ checkFields := func(c ConnectionState, called *int, errorType string) error {
+ if c.Version != version {
+ return fmt.Errorf("%s: got Version %v, want %v", errorType, c.Version, version)
+ }
+ if c.HandshakeComplete {
+ return fmt.Errorf("%s: got HandshakeComplete, want false", errorType)
+ }
+ if c.ServerName != "example.golang" {
+ return fmt.Errorf("%s: got ServerName %s, want %s", errorType, c.ServerName, "example.golang")
+ }
+ if c.NegotiatedProtocol != "protocol1" {
+ return fmt.Errorf("%s: got NegotiatedProtocol %s, want %s", errorType, c.NegotiatedProtocol, "protocol1")
+ }
+ if c.CipherSuite == 0 {
+ return fmt.Errorf("%s: got CipherSuite 0, want non-zero", errorType)
+ }
+ wantDidResume := false
+ if *called == 2 { // if this is the second time, then it should be a resumption
+ wantDidResume = true
+ }
+ if c.DidResume != wantDidResume {
+ return fmt.Errorf("%s: got DidResume %t, want %t", errorType, c.DidResume, wantDidResume)
+ }
+ return nil
+ }
+
+ tests := []struct {
+ name string
+ configureServer func(*Config, *int)
+ configureClient func(*Config, *int)
+ }{
+ {
+ name: "RequireAndVerifyClientCert",
+ configureServer: func(config *Config, called *int) {
+ config.ClientAuth = RequireAndVerifyClientCert
+ config.VerifyConnection = func(c ConnectionState) error {
+ *called++
+ if l := len(c.PeerCertificates); l != 1 {
+ return fmt.Errorf("server: got len(PeerCertificates) = %d, wanted 1", l)
+ }
+ if len(c.VerifiedChains) == 0 {
+ return fmt.Errorf("server: got len(VerifiedChains) = 0, wanted non-zero")
+ }
+ return checkFields(c, called, "server")
+ }
+ },
+ configureClient: func(config *Config, called *int) {
+ config.VerifyConnection = func(c ConnectionState) error {
+ *called++
+ if l := len(c.PeerCertificates); l != 1 {
+ return fmt.Errorf("client: got len(PeerCertificates) = %d, wanted 1", l)
+ }
+ if len(c.VerifiedChains) == 0 {
+ return fmt.Errorf("client: got len(VerifiedChains) = 0, wanted non-zero")
+ }
+ if c.DidResume {
+ return nil
+ // The SCTs and OCSP Response are dropped on resumption.
+ // See http://golang.org/issue/39075.
+ }
+ if len(c.OCSPResponse) == 0 {
+ return fmt.Errorf("client: got len(OCSPResponse) = 0, wanted non-zero")
+ }
+ if len(c.SignedCertificateTimestamps) == 0 {
+ return fmt.Errorf("client: got len(SignedCertificateTimestamps) = 0, wanted non-zero")
+ }
+ return checkFields(c, called, "client")
+ }
+ },
+ },
+ {
+ name: "InsecureSkipVerify",
+ configureServer: func(config *Config, called *int) {
+ config.ClientAuth = RequireAnyClientCert
+ config.InsecureSkipVerify = true
+ config.VerifyConnection = func(c ConnectionState) error {
+ *called++
+ if l := len(c.PeerCertificates); l != 1 {
+ return fmt.Errorf("server: got len(PeerCertificates) = %d, wanted 1", l)
+ }
+ if c.VerifiedChains != nil {
+ return fmt.Errorf("server: got Verified Chains %v, want nil", c.VerifiedChains)
+ }
+ return checkFields(c, called, "server")
+ }
+ },
+ configureClient: func(config *Config, called *int) {
+ config.InsecureSkipVerify = true
+ config.VerifyConnection = func(c ConnectionState) error {
+ *called++
+ if l := len(c.PeerCertificates); l != 1 {
+ return fmt.Errorf("client: got len(PeerCertificates) = %d, wanted 1", l)
+ }
+ if c.VerifiedChains != nil {
+ return fmt.Errorf("server: got Verified Chains %v, want nil", c.VerifiedChains)
+ }
+ if c.DidResume {
+ return nil
+ // The SCTs and OCSP Response are dropped on resumption.
+ // See http://golang.org/issue/39075.
+ }
+ if len(c.OCSPResponse) == 0 {
+ return fmt.Errorf("client: got len(OCSPResponse) = 0, wanted non-zero")
+ }
+ if len(c.SignedCertificateTimestamps) == 0 {
+ return fmt.Errorf("client: got len(SignedCertificateTimestamps) = 0, wanted non-zero")
+ }
+ return checkFields(c, called, "client")
+ }
+ },
+ },
+ {
+ name: "NoClientCert",
+ configureServer: func(config *Config, called *int) {
+ config.ClientAuth = NoClientCert
+ config.VerifyConnection = func(c ConnectionState) error {
+ *called++
+ return checkFields(c, called, "server")
+ }
+ },
+ configureClient: func(config *Config, called *int) {
+ config.VerifyConnection = func(c ConnectionState) error {
+ *called++
+ return checkFields(c, called, "client")
+ }
+ },
+ },
+ {
+ name: "RequestClientCert",
+ configureServer: func(config *Config, called *int) {
+ config.ClientAuth = RequestClientCert
+ config.VerifyConnection = func(c ConnectionState) error {
+ *called++
+ return checkFields(c, called, "server")
+ }
+ },
+ configureClient: func(config *Config, called *int) {
+ config.Certificates = nil // clear the client cert
+ config.VerifyConnection = func(c ConnectionState) error {
+ *called++
+ if l := len(c.PeerCertificates); l != 1 {
+ return fmt.Errorf("client: got len(PeerCertificates) = %d, wanted 1", l)
+ }
+ if len(c.VerifiedChains) == 0 {
+ return fmt.Errorf("client: got len(VerifiedChains) = 0, wanted non-zero")
+ }
+ if c.DidResume {
+ return nil
+ // The SCTs and OCSP Response are dropped on resumption.
+ // See http://golang.org/issue/39075.
+ }
+ if len(c.OCSPResponse) == 0 {
+ return fmt.Errorf("client: got len(OCSPResponse) = 0, wanted non-zero")
+ }
+ if len(c.SignedCertificateTimestamps) == 0 {
+ return fmt.Errorf("client: got len(SignedCertificateTimestamps) = 0, wanted non-zero")
+ }
+ return checkFields(c, called, "client")
+ }
+ },
+ },
+ }
+ for _, test := range tests {
+ issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
+ if err != nil {
+ panic(err)
+ }
+ rootCAs := x509.NewCertPool()
+ rootCAs.AddCert(issuer)
+
+ var serverCalled, clientCalled int
+
+ serverConfig := &Config{
+ MaxVersion: version,
+ Certificates: []Certificate{testConfig.Certificates[0]},
+ ClientCAs: rootCAs,
+ NextProtos: []string{"protocol1"},
+ }
+ serverConfig.Certificates[0].SignedCertificateTimestamps = [][]byte{[]byte("dummy sct 1"), []byte("dummy sct 2")}
+ serverConfig.Certificates[0].OCSPStaple = []byte("dummy ocsp")
+ test.configureServer(serverConfig, &serverCalled)
+
+ clientConfig := &Config{
+ MaxVersion: version,
+ ClientSessionCache: NewLRUClientSessionCache(32),
+ RootCAs: rootCAs,
+ ServerName: "example.golang",
+ Certificates: []Certificate{testConfig.Certificates[0]},
+ NextProtos: []string{"protocol1"},
+ }
+ test.configureClient(clientConfig, &clientCalled)
+
+ testHandshakeState := func(name string, didResume bool) {
+ _, hs, err := testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("%s: handshake failed: %s", name, err)
+ }
+ if hs.DidResume != didResume {
+ t.Errorf("%s: resumed: %v, expected: %v", name, hs.DidResume, didResume)
+ }
+ wantCalled := 1
+ if didResume {
+ wantCalled = 2 // resumption would mean this is the second time it was called in this test
+ }
+ if clientCalled != wantCalled {
+ t.Errorf("%s: expected client VerifyConnection called %d times, did %d times", name, wantCalled, clientCalled)
+ }
+ if serverCalled != wantCalled {
+ t.Errorf("%s: expected server VerifyConnection called %d times, did %d times", name, wantCalled, serverCalled)
+ }
+ }
+ testHandshakeState(fmt.Sprintf("%s-FullHandshake", test.name), false)
+ testHandshakeState(fmt.Sprintf("%s-Resumption", test.name), true)
+ }
+}
+
+func TestVerifyPeerCertificate(t *testing.T) {
+ t.Run("TLSv12", func(t *testing.T) { testVerifyPeerCertificate(t, VersionTLS12) })
+ t.Run("TLSv13", func(t *testing.T) { testVerifyPeerCertificate(t, VersionTLS13) })
+}
+
+func testVerifyPeerCertificate(t *testing.T, version uint16) {
+ issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
+ if err != nil {
+ panic(err)
+ }
+
+ rootCAs := x509.NewCertPool()
+ rootCAs.AddCert(issuer)
+
+ now := func() time.Time { return time.Unix(1476984729, 0) }
+
+ sentinelErr := errors.New("TestVerifyPeerCertificate")
+
+ verifyPeerCertificateCallback := func(called *bool, rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ if l := len(rawCerts); l != 1 {
+ return fmt.Errorf("got len(rawCerts) = %d, wanted 1", l)
+ }
+ if len(validatedChains) == 0 {
+ return errors.New("got len(validatedChains) = 0, wanted non-zero")
+ }
+ *called = true
+ return nil
+ }
+ verifyConnectionCallback := func(called *bool, isClient bool, c ConnectionState) error {
+ if l := len(c.PeerCertificates); l != 1 {
+ return fmt.Errorf("got len(PeerCertificates) = %d, wanted 1", l)
+ }
+ if len(c.VerifiedChains) == 0 {
+ return fmt.Errorf("got len(VerifiedChains) = 0, wanted non-zero")
+ }
+ if isClient && len(c.OCSPResponse) == 0 {
+ return fmt.Errorf("got len(OCSPResponse) = 0, wanted non-zero")
+ }
+ *called = true
+ return nil
+ }
+
+ tests := []struct {
+ configureServer func(*Config, *bool)
+ configureClient func(*Config, *bool)
+ validate func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error)
+ }{
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ return verifyPeerCertificateCallback(called, rawCerts, validatedChains)
+ }
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ return verifyPeerCertificateCallback(called, rawCerts, validatedChains)
+ }
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if clientErr != nil {
+ t.Errorf("test[%d]: client handshake failed: %v", testNo, clientErr)
+ }
+ if serverErr != nil {
+ t.Errorf("test[%d]: server handshake failed: %v", testNo, serverErr)
+ }
+ if !clientCalled {
+ t.Errorf("test[%d]: client did not call callback", testNo)
+ }
+ if !serverCalled {
+ t.Errorf("test[%d]: server did not call callback", testNo)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ return sentinelErr
+ }
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.VerifyPeerCertificate = nil
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if serverErr != sentinelErr {
+ t.Errorf("#%d: got server error %v, wanted sentinelErr", testNo, serverErr)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ return sentinelErr
+ }
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if clientErr != sentinelErr {
+ t.Errorf("#%d: got client error %v, wanted sentinelErr", testNo, clientErr)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = true
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ if l := len(rawCerts); l != 1 {
+ return fmt.Errorf("got len(rawCerts) = %d, wanted 1", l)
+ }
+ // With InsecureSkipVerify set, this
+ // callback should still be called but
+ // validatedChains must be empty.
+ if l := len(validatedChains); l != 0 {
+ return fmt.Errorf("got len(validatedChains) = %d, wanted zero", l)
+ }
+ *called = true
+ return nil
+ }
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if clientErr != nil {
+ t.Errorf("test[%d]: client handshake failed: %v", testNo, clientErr)
+ }
+ if serverErr != nil {
+ t.Errorf("test[%d]: server handshake failed: %v", testNo, serverErr)
+ }
+ if !clientCalled {
+ t.Errorf("test[%d]: client did not call callback", testNo)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyConnection = func(c ConnectionState) error {
+ return verifyConnectionCallback(called, false, c)
+ }
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyConnection = func(c ConnectionState) error {
+ return verifyConnectionCallback(called, true, c)
+ }
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if clientErr != nil {
+ t.Errorf("test[%d]: client handshake failed: %v", testNo, clientErr)
+ }
+ if serverErr != nil {
+ t.Errorf("test[%d]: server handshake failed: %v", testNo, serverErr)
+ }
+ if !clientCalled {
+ t.Errorf("test[%d]: client did not call callback", testNo)
+ }
+ if !serverCalled {
+ t.Errorf("test[%d]: server did not call callback", testNo)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyConnection = func(c ConnectionState) error {
+ return sentinelErr
+ }
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyConnection = nil
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if serverErr != sentinelErr {
+ t.Errorf("#%d: got server error %v, wanted sentinelErr", testNo, serverErr)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyConnection = nil
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyConnection = func(c ConnectionState) error {
+ return sentinelErr
+ }
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if clientErr != sentinelErr {
+ t.Errorf("#%d: got client error %v, wanted sentinelErr", testNo, clientErr)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ return verifyPeerCertificateCallback(called, rawCerts, validatedChains)
+ }
+ config.VerifyConnection = func(c ConnectionState) error {
+ return sentinelErr
+ }
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyPeerCertificate = nil
+ config.VerifyConnection = nil
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if serverErr != sentinelErr {
+ t.Errorf("#%d: got server error %v, wanted sentinelErr", testNo, serverErr)
+ }
+ if !serverCalled {
+ t.Errorf("test[%d]: server did not call callback", testNo)
+ }
+ },
+ },
+ {
+ configureServer: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyPeerCertificate = nil
+ config.VerifyConnection = nil
+ },
+ configureClient: func(config *Config, called *bool) {
+ config.InsecureSkipVerify = false
+ config.VerifyPeerCertificate = func(rawCerts [][]byte, validatedChains [][]*x509.Certificate) error {
+ return verifyPeerCertificateCallback(called, rawCerts, validatedChains)
+ }
+ config.VerifyConnection = func(c ConnectionState) error {
+ return sentinelErr
+ }
+ },
+ validate: func(t *testing.T, testNo int, clientCalled, serverCalled bool, clientErr, serverErr error) {
+ if clientErr != sentinelErr {
+ t.Errorf("#%d: got client error %v, wanted sentinelErr", testNo, clientErr)
+ }
+ if !clientCalled {
+ t.Errorf("test[%d]: client did not call callback", testNo)
+ }
+ },
+ },
+ }
+
+ for i, test := range tests {
+ c, s := localPipe(t)
+ done := make(chan error)
+
+ var clientCalled, serverCalled bool
+
+ go func() {
+ config := testConfig.Clone()
+ config.ServerName = "example.golang"
+ config.ClientAuth = RequireAndVerifyClientCert
+ config.ClientCAs = rootCAs
+ config.Time = now
+ config.MaxVersion = version
+ config.Certificates = make([]Certificate, 1)
+ config.Certificates[0].Certificate = [][]byte{testRSACertificate}
+ config.Certificates[0].PrivateKey = testRSAPrivateKey
+ config.Certificates[0].SignedCertificateTimestamps = [][]byte{[]byte("dummy sct 1"), []byte("dummy sct 2")}
+ config.Certificates[0].OCSPStaple = []byte("dummy ocsp")
+ test.configureServer(config, &serverCalled)
+
+ err = Server(s, config).Handshake()
+ s.Close()
+ done <- err
+ }()
+
+ config := testConfig.Clone()
+ config.ServerName = "example.golang"
+ config.RootCAs = rootCAs
+ config.Time = now
+ config.MaxVersion = version
+ test.configureClient(config, &clientCalled)
+ clientErr := Client(c, config).Handshake()
+ c.Close()
+ serverErr := <-done
+
+ test.validate(t, i, clientCalled, serverCalled, clientErr, serverErr)
+ }
+}
+
+// brokenConn wraps a net.Conn and causes all Writes after a certain number to
+// fail with brokenConnErr.
+type brokenConn struct {
+ net.Conn
+
+ // breakAfter is the number of successful writes that will be allowed
+ // before all subsequent writes fail.
+ breakAfter int
+
+ // numWrites is the number of writes that have been done.
+ numWrites int
+}
+
+// brokenConnErr is the error that brokenConn returns once exhausted.
+var brokenConnErr = errors.New("too many writes to brokenConn")
+
+func (b *brokenConn) Write(data []byte) (int, error) {
+ if b.numWrites >= b.breakAfter {
+ return 0, brokenConnErr
+ }
+
+ b.numWrites++
+ return b.Conn.Write(data)
+}
+
+func TestFailedWrite(t *testing.T) {
+ // Test that a write error during the handshake is returned.
+ for _, breakAfter := range []int{0, 1} {
+ c, s := localPipe(t)
+ done := make(chan bool)
+
+ go func() {
+ Server(s, testConfig).Handshake()
+ s.Close()
+ done <- true
+ }()
+
+ brokenC := &brokenConn{Conn: c, breakAfter: breakAfter}
+ err := Client(brokenC, testConfig).Handshake()
+ if err != brokenConnErr {
+ t.Errorf("#%d: expected error from brokenConn but got %q", breakAfter, err)
+ }
+ brokenC.Close()
+
+ <-done
+ }
+}
+
+// writeCountingConn wraps a net.Conn and counts the number of Write calls.
+type writeCountingConn struct {
+ net.Conn
+
+ // numWrites is the number of writes that have been done.
+ numWrites int
+}
+
+func (wcc *writeCountingConn) Write(data []byte) (int, error) {
+ wcc.numWrites++
+ return wcc.Conn.Write(data)
+}
+
+func TestBuffering(t *testing.T) {
+ t.Run("TLSv12", func(t *testing.T) { testBuffering(t, VersionTLS12) })
+ t.Run("TLSv13", func(t *testing.T) { testBuffering(t, VersionTLS13) })
+}
+
+func testBuffering(t *testing.T, version uint16) {
+ c, s := localPipe(t)
+ done := make(chan bool)
+
+ clientWCC := &writeCountingConn{Conn: c}
+ serverWCC := &writeCountingConn{Conn: s}
+
+ go func() {
+ config := testConfig.Clone()
+ config.MaxVersion = version
+ Server(serverWCC, config).Handshake()
+ serverWCC.Close()
+ done <- true
+ }()
+
+ err := Client(clientWCC, testConfig).Handshake()
+ if err != nil {
+ t.Fatal(err)
+ }
+ clientWCC.Close()
+ <-done
+
+ var expectedClient, expectedServer int
+ if version == VersionTLS13 {
+ expectedClient = 2
+ expectedServer = 1
+ } else {
+ expectedClient = 2
+ expectedServer = 2
+ }
+
+ if n := clientWCC.numWrites; n != expectedClient {
+ t.Errorf("expected client handshake to complete with %d writes, but saw %d", expectedClient, n)
+ }
+
+ if n := serverWCC.numWrites; n != expectedServer {
+ t.Errorf("expected server handshake to complete with %d writes, but saw %d", expectedServer, n)
+ }
+}
+
+func TestAlertFlushing(t *testing.T) {
+ c, s := localPipe(t)
+ done := make(chan bool)
+
+ clientWCC := &writeCountingConn{Conn: c}
+ serverWCC := &writeCountingConn{Conn: s}
+
+ serverConfig := testConfig.Clone()
+
+ // Cause a signature-time error
+ brokenKey := rsa.PrivateKey{PublicKey: testRSAPrivateKey.PublicKey}
+ brokenKey.D = big.NewInt(42)
+ serverConfig.Certificates = []Certificate{{
+ Certificate: [][]byte{testRSACertificate},
+ PrivateKey: &brokenKey,
+ }}
+
+ go func() {
+ Server(serverWCC, serverConfig).Handshake()
+ serverWCC.Close()
+ done <- true
+ }()
+
+ err := Client(clientWCC, testConfig).Handshake()
+ if err == nil {
+ t.Fatal("client unexpectedly returned no error")
+ }
+
+ const expectedError = "remote error: tls: internal error"
+ if e := err.Error(); !strings.Contains(e, expectedError) {
+ t.Fatalf("expected to find %q in error but error was %q", expectedError, e)
+ }
+ clientWCC.Close()
+ <-done
+
+ if n := serverWCC.numWrites; n != 1 {
+ t.Errorf("expected server handshake to complete with one write, but saw %d", n)
+ }
+}
+
+func TestHandshakeRace(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in -short mode")
+ }
+ t.Parallel()
+ // This test races a Read and Write to try and complete a handshake in
+ // order to provide some evidence that there are no races or deadlocks
+ // in the handshake locking.
+ for i := 0; i < 32; i++ {
+ c, s := localPipe(t)
+
+ go func() {
+ server := Server(s, testConfig)
+ if err := server.Handshake(); err != nil {
+ panic(err)
+ }
+
+ var request [1]byte
+ if n, err := server.Read(request[:]); err != nil || n != 1 {
+ panic(err)
+ }
+
+ server.Write(request[:])
+ server.Close()
+ }()
+
+ startWrite := make(chan struct{})
+ startRead := make(chan struct{})
+ readDone := make(chan struct{}, 1)
+
+ client := Client(c, testConfig)
+ go func() {
+ <-startWrite
+ var request [1]byte
+ client.Write(request[:])
+ }()
+
+ go func() {
+ <-startRead
+ var reply [1]byte
+ if _, err := io.ReadFull(client, reply[:]); err != nil {
+ panic(err)
+ }
+ c.Close()
+ readDone <- struct{}{}
+ }()
+
+ if i&1 == 1 {
+ startWrite <- struct{}{}
+ startRead <- struct{}{}
+ } else {
+ startRead <- struct{}{}
+ startWrite <- struct{}{}
+ }
+ <-readDone
+ }
+}
+
+var getClientCertificateTests = []struct {
+ setup func(*Config, *Config)
+ expectedClientError string
+ verify func(*testing.T, int, *ConnectionState)
+}{
+ {
+ func(clientConfig, serverConfig *Config) {
+ // Returning a Certificate with no certificate data
+ // should result in an empty message being sent to the
+ // server.
+ serverConfig.ClientCAs = nil
+ clientConfig.GetClientCertificate = func(cri *CertificateRequestInfo) (*Certificate, error) {
+ if len(cri.SignatureSchemes) == 0 {
+ panic("empty SignatureSchemes")
+ }
+ if len(cri.AcceptableCAs) != 0 {
+ panic("AcceptableCAs should have been empty")
+ }
+ return new(Certificate), nil
+ }
+ },
+ "",
+ func(t *testing.T, testNum int, cs *ConnectionState) {
+ if l := len(cs.PeerCertificates); l != 0 {
+ t.Errorf("#%d: expected no certificates but got %d", testNum, l)
+ }
+ },
+ },
+ {
+ func(clientConfig, serverConfig *Config) {
+ // With TLS 1.1, the SignatureSchemes should be
+ // synthesised from the supported certificate types.
+ clientConfig.MaxVersion = VersionTLS11
+ clientConfig.GetClientCertificate = func(cri *CertificateRequestInfo) (*Certificate, error) {
+ if len(cri.SignatureSchemes) == 0 {
+ panic("empty SignatureSchemes")
+ }
+ return new(Certificate), nil
+ }
+ },
+ "",
+ func(t *testing.T, testNum int, cs *ConnectionState) {
+ if l := len(cs.PeerCertificates); l != 0 {
+ t.Errorf("#%d: expected no certificates but got %d", testNum, l)
+ }
+ },
+ },
+ {
+ func(clientConfig, serverConfig *Config) {
+ // Returning an error should abort the handshake with
+ // that error.
+ clientConfig.GetClientCertificate = func(cri *CertificateRequestInfo) (*Certificate, error) {
+ return nil, errors.New("GetClientCertificate")
+ }
+ },
+ "GetClientCertificate",
+ func(t *testing.T, testNum int, cs *ConnectionState) {
+ },
+ },
+ {
+ func(clientConfig, serverConfig *Config) {
+ clientConfig.GetClientCertificate = func(cri *CertificateRequestInfo) (*Certificate, error) {
+ if len(cri.AcceptableCAs) == 0 {
+ panic("empty AcceptableCAs")
+ }
+ cert := &Certificate{
+ Certificate: [][]byte{testRSACertificate},
+ PrivateKey: testRSAPrivateKey,
+ }
+ return cert, nil
+ }
+ },
+ "",
+ func(t *testing.T, testNum int, cs *ConnectionState) {
+ if len(cs.VerifiedChains) == 0 {
+ t.Errorf("#%d: expected some verified chains, but found none", testNum)
+ }
+ },
+ },
+}
+
+func TestGetClientCertificate(t *testing.T) {
+ t.Run("TLSv12", func(t *testing.T) { testGetClientCertificate(t, VersionTLS12) })
+ t.Run("TLSv13", func(t *testing.T) { testGetClientCertificate(t, VersionTLS13) })
+}
+
+func testGetClientCertificate(t *testing.T, version uint16) {
+ issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
+ if err != nil {
+ panic(err)
+ }
+
+ for i, test := range getClientCertificateTests {
+ serverConfig := testConfig.Clone()
+ serverConfig.ClientAuth = VerifyClientCertIfGiven
+ serverConfig.RootCAs = x509.NewCertPool()
+ serverConfig.RootCAs.AddCert(issuer)
+ serverConfig.ClientCAs = serverConfig.RootCAs
+ serverConfig.Time = func() time.Time { return time.Unix(1476984729, 0) }
+ serverConfig.MaxVersion = version
+
+ clientConfig := testConfig.Clone()
+ clientConfig.MaxVersion = version
+
+ test.setup(clientConfig, serverConfig)
+
+ type serverResult struct {
+ cs ConnectionState
+ err error
+ }
+
+ c, s := localPipe(t)
+ done := make(chan serverResult)
+
+ go func() {
+ defer s.Close()
+ server := Server(s, serverConfig)
+ err := server.Handshake()
+
+ var cs ConnectionState
+ if err == nil {
+ cs = server.ConnectionState()
+ }
+ done <- serverResult{cs, err}
+ }()
+
+ clientErr := Client(c, clientConfig).Handshake()
+ c.Close()
+
+ result := <-done
+
+ if clientErr != nil {
+ if len(test.expectedClientError) == 0 {
+ t.Errorf("#%d: client error: %v", i, clientErr)
+ } else if got := clientErr.Error(); got != test.expectedClientError {
+ t.Errorf("#%d: expected client error %q, but got %q", i, test.expectedClientError, got)
+ } else {
+ test.verify(t, i, &result.cs)
+ }
+ } else if len(test.expectedClientError) > 0 {
+ t.Errorf("#%d: expected client error %q, but got no error", i, test.expectedClientError)
+ } else if err := result.err; err != nil {
+ t.Errorf("#%d: server error: %v", i, err)
+ } else {
+ test.verify(t, i, &result.cs)
+ }
+ }
+}
+
+func TestRSAPSSKeyError(t *testing.T) {
+ // crypto/tls does not support the rsa_pss_pss_* SignatureSchemes. If support for
+ // public keys with OID RSASSA-PSS is added to crypto/x509, they will be misused with
+ // the rsa_pss_rsae_* SignatureSchemes. Assert that RSASSA-PSS certificates don't
+ // parse, or that they don't carry *rsa.PublicKey keys.
+ b, _ := pem.Decode([]byte(`
+-----BEGIN CERTIFICATE-----
+MIIDZTCCAhygAwIBAgIUCF2x0FyTgZG0CC9QTDjGWkB5vgEwPgYJKoZIhvcNAQEK
+MDGgDTALBglghkgBZQMEAgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogQC
+AgDeMBIxEDAOBgNVBAMMB1JTQS1QU1MwHhcNMTgwNjI3MjI0NDM2WhcNMTgwNzI3
+MjI0NDM2WjASMRAwDgYDVQQDDAdSU0EtUFNTMIIBIDALBgkqhkiG9w0BAQoDggEP
+ADCCAQoCggEBANxDm0f76JdI06YzsjB3AmmjIYkwUEGxePlafmIASFjDZl/elD0Z
+/a7xLX468b0qGxLS5al7XCcEprSdsDR6DF5L520+pCbpfLyPOjuOvGmk9KzVX4x5
+b05YXYuXdsQ0Kjxcx2i3jjCday6scIhMJVgBZxTEyMj1thPQM14SHzKCd/m6HmCL
+QmswpH2yMAAcBRWzRpp/vdH5DeOJEB3aelq7094no731mrLUCHRiZ1htq8BDB3ou
+czwqgwspbqZ4dnMXl2MvfySQ5wJUxQwILbiuAKO2lVVPUbFXHE9pgtznNoPvKwQT
+JNcX8ee8WIZc2SEGzofjk3NpjR+2ADB2u3sCAwEAAaNTMFEwHQYDVR0OBBYEFNEz
+AdyJ2f+fU+vSCS6QzohnOnprMB8GA1UdIwQYMBaAFNEzAdyJ2f+fU+vSCS6Qzohn
+OnprMA8GA1UdEwEB/wQFMAMBAf8wPgYJKoZIhvcNAQEKMDGgDTALBglghkgBZQME
+AgGhGjAYBgkqhkiG9w0BAQgwCwYJYIZIAWUDBAIBogQCAgDeA4IBAQCjEdrR5aab
+sZmCwrMeKidXgfkmWvfuLDE+TCbaqDZp7BMWcMQXT9O0UoUT5kqgKj2ARm2pEW0Z
+H3Z1vj3bbds72qcDIJXp+l0fekyLGeCrX/CbgnMZXEP7+/+P416p34ChR1Wz4dU1
+KD3gdsUuTKKeMUog3plxlxQDhRQmiL25ygH1LmjLd6dtIt0GVRGr8lj3euVeprqZ
+bZ3Uq5eLfsn8oPgfC57gpO6yiN+UURRTlK3bgYvLh4VWB3XXk9UaQZ7Mq1tpXjoD
+HYFybkWzibkZp4WRo+Fa28rirH+/wHt0vfeN7UCceURZEx4JaxIIfe4ku7uDRhJi
+RwBA9Xk1KBNF
+-----END CERTIFICATE-----`))
+ if b == nil {
+ t.Fatal("Failed to decode certificate")
+ }
+ cert, err := x509.ParseCertificate(b.Bytes)
+ if err != nil {
+ return
+ }
+ if _, ok := cert.PublicKey.(*rsa.PublicKey); ok {
+ t.Error("A RSASSA-PSS certificate was parsed like a PKCS#1 v1.5 one, and it will be mistakenly used with rsa_pss_rsae_* signature algorithms")
+ }
+}
+
+func TestCloseClientConnectionOnIdleServer(t *testing.T) {
+ clientConn, serverConn := localPipe(t)
+ client := Client(clientConn, testConfig.Clone())
+ go func() {
+ var b [1]byte
+ serverConn.Read(b[:])
+ client.Close()
+ }()
+ client.SetWriteDeadline(time.Now().Add(time.Minute))
+ err := client.Handshake()
+ if err != nil {
+ if err, ok := err.(net.Error); ok && err.Timeout() {
+ t.Errorf("Expected a closed network connection error but got '%s'", err.Error())
+ }
+ } else {
+ t.Errorf("Error expected, but no error returned")
+ }
+}
+
+func testDowngradeCanary(t *testing.T, clientVersion, serverVersion uint16) error {
+ defer func() { testingOnlyForceDowngradeCanary = false }()
+ testingOnlyForceDowngradeCanary = true
+
+ clientConfig := testConfig.Clone()
+ clientConfig.MaxVersion = clientVersion
+ serverConfig := testConfig.Clone()
+ serverConfig.MaxVersion = serverVersion
+ _, _, err := testHandshake(t, clientConfig, serverConfig)
+ return err
+}
+
+func TestDowngradeCanary(t *testing.T) {
+ if err := testDowngradeCanary(t, VersionTLS13, VersionTLS12); err == nil {
+ t.Errorf("downgrade from TLS 1.3 to TLS 1.2 was not detected")
+ }
+ if testing.Short() {
+ t.Skip("skipping the rest of the checks in short mode")
+ }
+ if err := testDowngradeCanary(t, VersionTLS13, VersionTLS11); err == nil {
+ t.Errorf("downgrade from TLS 1.3 to TLS 1.1 was not detected")
+ }
+ if err := testDowngradeCanary(t, VersionTLS13, VersionTLS10); err == nil {
+ t.Errorf("downgrade from TLS 1.3 to TLS 1.0 was not detected")
+ }
+ if err := testDowngradeCanary(t, VersionTLS12, VersionTLS11); err == nil {
+ t.Errorf("downgrade from TLS 1.2 to TLS 1.1 was not detected")
+ }
+ if err := testDowngradeCanary(t, VersionTLS12, VersionTLS10); err == nil {
+ t.Errorf("downgrade from TLS 1.2 to TLS 1.0 was not detected")
+ }
+ if err := testDowngradeCanary(t, VersionTLS13, VersionTLS13); err != nil {
+ t.Errorf("server unexpectedly sent downgrade canary for TLS 1.3")
+ }
+ if err := testDowngradeCanary(t, VersionTLS12, VersionTLS12); err != nil {
+ t.Errorf("client didn't ignore expected TLS 1.2 canary")
+ }
+ if err := testDowngradeCanary(t, VersionTLS11, VersionTLS11); err != nil {
+ t.Errorf("client unexpectedly reacted to a canary in TLS 1.1")
+ }
+ if err := testDowngradeCanary(t, VersionTLS10, VersionTLS10); err != nil {
+ t.Errorf("client unexpectedly reacted to a canary in TLS 1.0")
+ }
+}
+
+func TestResumptionKeepsOCSPAndSCT(t *testing.T) {
+ t.Run("TLSv12", func(t *testing.T) { testResumptionKeepsOCSPAndSCT(t, VersionTLS12) })
+ t.Run("TLSv13", func(t *testing.T) { testResumptionKeepsOCSPAndSCT(t, VersionTLS13) })
+}
+
+func testResumptionKeepsOCSPAndSCT(t *testing.T, ver uint16) {
+ issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
+ if err != nil {
+ t.Fatalf("failed to parse test issuer")
+ }
+ roots := x509.NewCertPool()
+ roots.AddCert(issuer)
+ clientConfig := &Config{
+ MaxVersion: ver,
+ ClientSessionCache: NewLRUClientSessionCache(32),
+ ServerName: "example.golang",
+ RootCAs: roots,
+ }
+ serverConfig := testConfig.Clone()
+ serverConfig.MaxVersion = ver
+ serverConfig.Certificates[0].OCSPStaple = []byte{1, 2, 3}
+ serverConfig.Certificates[0].SignedCertificateTimestamps = [][]byte{{4, 5, 6}}
+
+ _, ccs, err := testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ // after a new session we expect to see OCSPResponse and
+ // SignedCertificateTimestamps populated as usual
+ if !bytes.Equal(ccs.OCSPResponse, serverConfig.Certificates[0].OCSPStaple) {
+ t.Errorf("client ConnectionState contained unexpected OCSPResponse: wanted %v, got %v",
+ serverConfig.Certificates[0].OCSPStaple, ccs.OCSPResponse)
+ }
+ if !reflect.DeepEqual(ccs.SignedCertificateTimestamps, serverConfig.Certificates[0].SignedCertificateTimestamps) {
+ t.Errorf("client ConnectionState contained unexpected SignedCertificateTimestamps: wanted %v, got %v",
+ serverConfig.Certificates[0].SignedCertificateTimestamps, ccs.SignedCertificateTimestamps)
+ }
+
+ // if the server doesn't send any SCTs, repopulate the old SCTs
+ oldSCTs := serverConfig.Certificates[0].SignedCertificateTimestamps
+ serverConfig.Certificates[0].SignedCertificateTimestamps = nil
+ _, ccs, err = testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ if !ccs.DidResume {
+ t.Fatalf("expected session to be resumed")
+ }
+ // after a resumed session we also expect to see OCSPResponse
+ // and SignedCertificateTimestamps populated
+ if !bytes.Equal(ccs.OCSPResponse, serverConfig.Certificates[0].OCSPStaple) {
+ t.Errorf("client ConnectionState contained unexpected OCSPResponse after resumption: wanted %v, got %v",
+ serverConfig.Certificates[0].OCSPStaple, ccs.OCSPResponse)
+ }
+ if !reflect.DeepEqual(ccs.SignedCertificateTimestamps, oldSCTs) {
+ t.Errorf("client ConnectionState contained unexpected SignedCertificateTimestamps after resumption: wanted %v, got %v",
+ oldSCTs, ccs.SignedCertificateTimestamps)
+ }
+
+ // Only test overriding the SCTs for TLS 1.2, since in 1.3
+ // the server won't send the message containing them
+ if ver == VersionTLS13 {
+ return
+ }
+
+ // if the server changes the SCTs it sends, they should override the saved SCTs
+ serverConfig.Certificates[0].SignedCertificateTimestamps = [][]byte{{7, 8, 9}}
+ _, ccs, err = testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ if !ccs.DidResume {
+ t.Fatalf("expected session to be resumed")
+ }
+ if !reflect.DeepEqual(ccs.SignedCertificateTimestamps, serverConfig.Certificates[0].SignedCertificateTimestamps) {
+ t.Errorf("client ConnectionState contained unexpected SignedCertificateTimestamps after resumption: wanted %v, got %v",
+ serverConfig.Certificates[0].SignedCertificateTimestamps, ccs.SignedCertificateTimestamps)
+ }
+}
+
+// TestClientHandshakeContextCancellation tests that canceling
+// the context given to the client side conn.HandshakeContext
+// interrupts the in-progress handshake.
+func TestClientHandshakeContextCancellation(t *testing.T) {
+ c, s := localPipe(t)
+ ctx, cancel := context.WithCancel(context.Background())
+ unblockServer := make(chan struct{})
+ defer close(unblockServer)
+ go func() {
+ cancel()
+ <-unblockServer
+ _ = s.Close()
+ }()
+ cli := Client(c, testConfig)
+ // Initiates client side handshake, which will block until the client hello is read
+ // by the server, unless the cancellation works.
+ err := cli.HandshakeContext(ctx)
+ if err == nil {
+ t.Fatal("Client handshake did not error when the context was canceled")
+ }
+ if err != context.Canceled {
+ t.Errorf("Unexpected client handshake error: %v", err)
+ }
+ if runtime.GOARCH == "wasm" {
+ t.Skip("conn.Close does not error as expected when called multiple times on WASM")
+ }
+ err = cli.Close()
+ if err == nil {
+ t.Error("Client connection was not closed when the context was canceled")
+ }
+}
+
+// discardConn wraps a net.Conn but discards all writes, but reports that they happened.
+type discardConn struct {
+ net.Conn
+}
+
+func (dc *discardConn) Write(data []byte) (int, error) {
+ return len(data), nil
+}
+
+// largeRSAKeyCertPEM contains a 8193 bit RSA key
+const largeRSAKeyCertPEM = `-----BEGIN CERTIFICATE-----
+MIIInjCCBIWgAwIBAgIBAjANBgkqhkiG9w0BAQsFADASMRAwDgYDVQQDEwd0ZXN0
+aW5nMB4XDTIzMDYwNzIxMjMzNloXDTIzMDYwNzIzMjMzNlowEjEQMA4GA1UEAxMH
+dGVzdGluZzCCBCIwDQYJKoZIhvcNAQEBBQADggQPADCCBAoCggQBAWdHsf6Rh2Ca
+n2SQwn4t4OQrOjbLLdGE1pM6TBKKrHUFy62uEL8atNjlcfXIsa4aEu3xNGiqxqur
+ZectlkZbm0FkaaQ1Wr9oikDY3KfjuaXdPdO/XC/h8AKNxlDOylyXwUSK/CuYb+1j
+gy8yF5QFvVfwW/xwTlHmhUeSkVSQPosfQ6yXNNsmMzkd+ZPWLrfq4R+wiNtwYGu0
+WSBcI/M9o8/vrNLnIppoiBJJ13j9CR1ToEAzOFh9wwRWLY10oZhoh1ONN1KQURx4
+qedzvvP2DSjZbUccdvl2rBGvZpzfOiFdm1FCnxB0c72Cqx+GTHXBFf8bsa7KHky9
+sNO1GUanbq17WoDNgwbY6H51bfShqv0CErxatwWox3we4EcAmFHPVTCYL1oWVMGo
+a3Eth91NZj+b/nGhF9lhHKGzXSv9brmLLkfvM1jA6XhNhA7BQ5Vz67lj2j3XfXdh
+t/BU5pBXbL4Ut4mIhT1YnKXAjX2/LF5RHQTE8Vwkx5JAEKZyUEGOReD/B+7GOrLp
+HduMT9vZAc5aR2k9I8qq1zBAzsL69lyQNAPaDYd1BIAjUety9gAYaSQffCgAgpRO
+Gt+DYvxS+7AT/yEd5h74MU2AH7KrAkbXOtlwupiGwhMVTstncDJWXMJqbBhyHPF8
+3UmZH0hbL4PYmzSj9LDWQQXI2tv6vrCpfts3Cqhqxz9vRpgY7t1Wu6l/r+KxYYz3
+1pcGpPvRmPh0DJm7cPTiXqPnZcPt+ulSaSdlxmd19OnvG5awp0fXhxryZVwuiT8G
+VDkhyARrxYrdjlINsZJZbQjO0t8ketXAELJOnbFXXzeCOosyOHkLwsqOO96AVJA8
+45ZVL5m95ClGy0RSrjVIkXsxTAMVG6SPAqKwk6vmTdRGuSPS4rhgckPVDHmccmuq
+dfnT2YkX+wB2/M3oCgU+s30fAHGkbGZ0pCdNbFYFZLiH0iiMbTDl/0L/z7IdK0nH
+GLHVE7apPraKC6xl6rPWsD2iSfrmtIPQa0+rqbIVvKP5JdfJ8J4alI+OxFw/znQe
+V0/Rez0j22Fe119LZFFSXhRv+ZSvcq20xDwh00mzcumPWpYuCVPozA18yIhC9tNn
+ALHndz0tDseIdy9vC71jQWy9iwri3ueN0DekMMF8JGzI1Z6BAFzgyAx3DkHtwHg7
+B7qD0jPG5hJ5+yt323fYgJsuEAYoZ8/jzZ01pkX8bt+UsVN0DGnSGsI2ktnIIk3J
+l+8krjmUy6EaW79nITwoOqaeHOIp8m3UkjEcoKOYrzHRKqRy+A09rY+m/cAQaafW
+4xp0Zv7qZPLwnu0jsqB4jD8Ll9yPB02ndsoV6U5PeHzTkVhPml19jKUAwFfs7TJg
+kXy+/xFhYVUCAwEAATANBgkqhkiG9w0BAQsFAAOCBAIAAQnZY77pMNeypfpba2WK
+aDasT7dk2JqP0eukJCVPTN24Zca+xJNPdzuBATm/8SdZK9lddIbjSnWRsKvTnO2r
+/rYdlPf3jM5uuJtb8+Uwwe1s+gszelGS9G/lzzq+ehWicRIq2PFcs8o3iQMfENiv
+qILJ+xjcrvms5ZPDNahWkfRx3KCg8Q+/at2n5p7XYjMPYiLKHnDC+RE2b1qT20IZ
+FhuK/fTWLmKbfYFNNga6GC4qcaZJ7x0pbm4SDTYp0tkhzcHzwKhidfNB5J2vNz6l
+Ur6wiYwamFTLqcOwWo7rdvI+sSn05WQBv0QZlzFX+OAu0l7WQ7yU+noOxBhjvHds
+14+r9qcQZg2q9kG+evopYZqYXRUNNlZKo9MRBXhfrISulFAc5lRFQIXMXnglvAu+
+Ipz2gomEAOcOPNNVldhKAU94GAMJd/KfN0ZP7gX3YvPzuYU6XDhag5RTohXLm18w
+5AF+ES3DOQ6ixu3DTf0D+6qrDuK+prdX8ivcdTQVNOQ+MIZeGSc6NWWOTaMGJ3lg
+aZIxJUGdo6E7GBGiC1YTjgFKFbHzek1LRTh/LX3vbSudxwaG0HQxwsU9T4DWiMqa
+Fkf2KteLEUA6HrR+0XlAZrhwoqAmrJ+8lCFX3V0gE9lpENfVHlFXDGyx10DpTB28
+DdjnY3F7EPWNzwf9P3oNT69CKW3Bk6VVr3ROOJtDxVu1ioWo3TaXltQ0VOnap2Pu
+sa5wfrpfwBDuAS9JCDg4ttNp2nW3F7tgXC6xPqw5pvGwUppEw9XNrqV8TZrxduuv
+rQ3NyZ7KSzIpmFlD3UwV/fGfz3UQmHS6Ng1evrUID9DjfYNfRqSGIGjDfxGtYD+j
+Z1gLJZuhjJpNtwBkKRtlNtrCWCJK2hidK/foxwD7kwAPo2I9FjpltxCRywZUs07X
+KwXTfBR9v6ij1LV6K58hFS+8ezZyZ05CeVBFkMQdclTOSfuPxlMkQOtjp8QWDj+F
+j/MYziT5KBkHvcbrjdRtUJIAi4N7zCsPZtjik918AK1WBNRVqPbrgq/XSEXMfuvs
+6JbfK0B76vdBDRtJFC1JsvnIrGbUztxXzyQwFLaR/AjVJqpVlysLWzPKWVX6/+SJ
+u1NQOl2E8P6ycyBsuGnO89p0S4F8cMRcI2X1XQsZ7/q0NBrOMaEp5T3SrWo9GiQ3
+o2SBdbs3Y6MBPBtTu977Z/0RO63J3M5i2tjUiDfrFy7+VRLKr7qQ7JibohyB8QaR
+9tedgjn2f+of7PnP/PEl1cCphUZeHM7QKUMPT8dbqwmKtlYY43EHXcvNOT5IBk3X
+9lwJoZk/B2i+ZMRNSP34ztAwtxmasPt6RAWGQpWCn9qmttAHAnMfDqe7F7jVR6rS
+u58=
+-----END CERTIFICATE-----`
+
+func TestHandshakeRSATooBig(t *testing.T) {
+ for _, tc := range []struct {
+ name string
+ godebug string
+ expectedServerErr string
+ expectedClientErr string
+ }{
+ {
+ name: "key too large",
+ expectedServerErr: "tls: server sent certificate containing RSA key larger than 8192 bits",
+ expectedClientErr: "tls: client sent certificate containing RSA key larger than 8192 bits",
+ },
+ {
+ name: "acceptable key (GODEBUG=tlsmaxrsasize=8193)",
+ godebug: "tlsmaxrsasize=8193",
+ },
+ } {
+ t.Run(tc.name, func(t *testing.T) {
+ if tc.godebug != "" {
+ t.Setenv("GODEBUG", tc.godebug)
+ }
+
+ testCert, _ := pem.Decode([]byte(largeRSAKeyCertPEM))
+
+ c := &Conn{conn: &discardConn{}, config: testConfig.Clone()}
+
+ err := c.verifyServerCertificate([][]byte{testCert.Bytes})
+ if tc.expectedServerErr == "" && err != nil {
+ t.Errorf("Conn.verifyServerCertificate unexpected error: %s", err)
+ } else if tc.expectedServerErr != "" && (err == nil || err.Error() != tc.expectedServerErr) {
+ t.Errorf("Conn.verifyServerCertificate unexpected error: want %q, got %q", tc.expectedServerErr, err)
+ }
+
+ err = c.processCertsFromClient(Certificate{Certificate: [][]byte{testCert.Bytes}})
+ if tc.expectedClientErr == "" && err != nil {
+ t.Errorf("Conn.processCertsFromClient unexpected error: %s", err)
+ } else if tc.expectedClientErr != "" && (err == nil || err.Error() != tc.expectedClientErr) {
+ t.Errorf("Conn.processCertsFromClient unexpected error: want %q, got %q", tc.expectedClientErr, err)
+ }
+ })
+ }
+}
diff --git a/src/crypto/tls/handshake_client_tls13.go b/src/crypto/tls/handshake_client_tls13.go
new file mode 100644
index 0000000..4a86610
--- /dev/null
+++ b/src/crypto/tls/handshake_client_tls13.go
@@ -0,0 +1,709 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "bytes"
+ "context"
+ "crypto"
+ "crypto/ecdh"
+ "crypto/hmac"
+ "crypto/rsa"
+ "errors"
+ "hash"
+ "time"
+)
+
+type clientHandshakeStateTLS13 struct {
+ c *Conn
+ ctx context.Context
+ serverHello *serverHelloMsg
+ hello *clientHelloMsg
+ ecdheKey *ecdh.PrivateKey
+
+ session *ClientSessionState
+ earlySecret []byte
+ binderKey []byte
+
+ certReq *certificateRequestMsgTLS13
+ usingPSK bool
+ sentDummyCCS bool
+ suite *cipherSuiteTLS13
+ transcript hash.Hash
+ masterSecret []byte
+ trafficSecret []byte // client_application_traffic_secret_0
+}
+
+// handshake requires hs.c, hs.hello, hs.serverHello, hs.ecdheKey, and,
+// optionally, hs.session, hs.earlySecret and hs.binderKey to be set.
+func (hs *clientHandshakeStateTLS13) handshake() error {
+ c := hs.c
+
+ if needFIPS() {
+ return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode")
+ }
+
+ // The server must not select TLS 1.3 in a renegotiation. See RFC 8446,
+ // sections 4.1.2 and 4.1.3.
+ if c.handshakes > 0 {
+ c.sendAlert(alertProtocolVersion)
+ return errors.New("tls: server selected TLS 1.3 in a renegotiation")
+ }
+
+ // Consistency check on the presence of a keyShare and its parameters.
+ if hs.ecdheKey == nil || len(hs.hello.keyShares) != 1 {
+ return c.sendAlert(alertInternalError)
+ }
+
+ if err := hs.checkServerHelloOrHRR(); err != nil {
+ return err
+ }
+
+ hs.transcript = hs.suite.hash.New()
+
+ if err := transcriptMsg(hs.hello, hs.transcript); err != nil {
+ return err
+ }
+
+ if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) {
+ if err := hs.sendDummyChangeCipherSpec(); err != nil {
+ return err
+ }
+ if err := hs.processHelloRetryRequest(); err != nil {
+ return err
+ }
+ }
+
+ if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
+ return err
+ }
+
+ c.buffering = true
+ if err := hs.processServerHello(); err != nil {
+ return err
+ }
+ if err := hs.sendDummyChangeCipherSpec(); err != nil {
+ return err
+ }
+ if err := hs.establishHandshakeKeys(); err != nil {
+ return err
+ }
+ if err := hs.readServerParameters(); err != nil {
+ return err
+ }
+ if err := hs.readServerCertificate(); err != nil {
+ return err
+ }
+ if err := hs.readServerFinished(); err != nil {
+ return err
+ }
+ if err := hs.sendClientCertificate(); err != nil {
+ return err
+ }
+ if err := hs.sendClientFinished(); err != nil {
+ return err
+ }
+ if _, err := c.flush(); err != nil {
+ return err
+ }
+
+ c.isHandshakeComplete.Store(true)
+
+ return nil
+}
+
+// checkServerHelloOrHRR does validity checks that apply to both ServerHello and
+// HelloRetryRequest messages. It sets hs.suite.
+func (hs *clientHandshakeStateTLS13) checkServerHelloOrHRR() error {
+ c := hs.c
+
+ if hs.serverHello.supportedVersion == 0 {
+ c.sendAlert(alertMissingExtension)
+ return errors.New("tls: server selected TLS 1.3 using the legacy version field")
+ }
+
+ if hs.serverHello.supportedVersion != VersionTLS13 {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server selected an invalid version after a HelloRetryRequest")
+ }
+
+ if hs.serverHello.vers != VersionTLS12 {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server sent an incorrect legacy version")
+ }
+
+ if hs.serverHello.ocspStapling ||
+ hs.serverHello.ticketSupported ||
+ hs.serverHello.secureRenegotiationSupported ||
+ len(hs.serverHello.secureRenegotiation) != 0 ||
+ len(hs.serverHello.alpnProtocol) != 0 ||
+ len(hs.serverHello.scts) != 0 {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: server sent a ServerHello extension forbidden in TLS 1.3")
+ }
+
+ if !bytes.Equal(hs.hello.sessionId, hs.serverHello.sessionId) {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server did not echo the legacy session ID")
+ }
+
+ if hs.serverHello.compressionMethod != compressionNone {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server selected unsupported compression format")
+ }
+
+ selectedSuite := mutualCipherSuiteTLS13(hs.hello.cipherSuites, hs.serverHello.cipherSuite)
+ if hs.suite != nil && selectedSuite != hs.suite {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server changed cipher suite after a HelloRetryRequest")
+ }
+ if selectedSuite == nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server chose an unconfigured cipher suite")
+ }
+ hs.suite = selectedSuite
+ c.cipherSuite = hs.suite.id
+
+ return nil
+}
+
+// sendDummyChangeCipherSpec sends a ChangeCipherSpec record for compatibility
+// with middleboxes that didn't implement TLS correctly. See RFC 8446, Appendix D.4.
+func (hs *clientHandshakeStateTLS13) sendDummyChangeCipherSpec() error {
+ if hs.sentDummyCCS {
+ return nil
+ }
+ hs.sentDummyCCS = true
+
+ return hs.c.writeChangeCipherRecord()
+}
+
+// processHelloRetryRequest handles the HRR in hs.serverHello, modifies and
+// resends hs.hello, and reads the new ServerHello into hs.serverHello.
+func (hs *clientHandshakeStateTLS13) processHelloRetryRequest() error {
+ c := hs.c
+
+ // The first ClientHello gets double-hashed into the transcript upon a
+ // HelloRetryRequest. (The idea is that the server might offload transcript
+ // storage to the client in the cookie.) See RFC 8446, Section 4.4.1.
+ chHash := hs.transcript.Sum(nil)
+ hs.transcript.Reset()
+ hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
+ hs.transcript.Write(chHash)
+ if err := transcriptMsg(hs.serverHello, hs.transcript); err != nil {
+ return err
+ }
+
+ // The only HelloRetryRequest extensions we support are key_share and
+ // cookie, and clients must abort the handshake if the HRR would not result
+ // in any change in the ClientHello.
+ if hs.serverHello.selectedGroup == 0 && hs.serverHello.cookie == nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server sent an unnecessary HelloRetryRequest message")
+ }
+
+ if hs.serverHello.cookie != nil {
+ hs.hello.cookie = hs.serverHello.cookie
+ }
+
+ if hs.serverHello.serverShare.group != 0 {
+ c.sendAlert(alertDecodeError)
+ return errors.New("tls: received malformed key_share extension")
+ }
+
+ // If the server sent a key_share extension selecting a group, ensure it's
+ // a group we advertised but did not send a key share for, and send a key
+ // share for it this time.
+ if curveID := hs.serverHello.selectedGroup; curveID != 0 {
+ curveOK := false
+ for _, id := range hs.hello.supportedCurves {
+ if id == curveID {
+ curveOK = true
+ break
+ }
+ }
+ if !curveOK {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server selected unsupported group")
+ }
+ if sentID, _ := curveIDForCurve(hs.ecdheKey.Curve()); sentID == curveID {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server sent an unnecessary HelloRetryRequest key_share")
+ }
+ if _, ok := curveForCurveID(curveID); !ok {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: CurvePreferences includes unsupported curve")
+ }
+ key, err := generateECDHEKey(c.config.rand(), curveID)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ hs.ecdheKey = key
+ hs.hello.keyShares = []keyShare{{group: curveID, data: key.PublicKey().Bytes()}}
+ }
+
+ hs.hello.raw = nil
+ if len(hs.hello.pskIdentities) > 0 {
+ pskSuite := cipherSuiteTLS13ByID(hs.session.cipherSuite)
+ if pskSuite == nil {
+ return c.sendAlert(alertInternalError)
+ }
+ if pskSuite.hash == hs.suite.hash {
+ // Update binders and obfuscated_ticket_age.
+ ticketAge := uint32(c.config.time().Sub(hs.session.receivedAt) / time.Millisecond)
+ hs.hello.pskIdentities[0].obfuscatedTicketAge = ticketAge + hs.session.ageAdd
+
+ transcript := hs.suite.hash.New()
+ transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
+ transcript.Write(chHash)
+ if err := transcriptMsg(hs.serverHello, transcript); err != nil {
+ return err
+ }
+ helloBytes, err := hs.hello.marshalWithoutBinders()
+ if err != nil {
+ return err
+ }
+ transcript.Write(helloBytes)
+ pskBinders := [][]byte{hs.suite.finishedHash(hs.binderKey, transcript)}
+ if err := hs.hello.updateBinders(pskBinders); err != nil {
+ return err
+ }
+ } else {
+ // Server selected a cipher suite incompatible with the PSK.
+ hs.hello.pskIdentities = nil
+ hs.hello.pskBinders = nil
+ }
+ }
+
+ if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil {
+ return err
+ }
+
+ // serverHelloMsg is not included in the transcript
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ serverHello, ok := msg.(*serverHelloMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(serverHello, msg)
+ }
+ hs.serverHello = serverHello
+
+ if err := hs.checkServerHelloOrHRR(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (hs *clientHandshakeStateTLS13) processServerHello() error {
+ c := hs.c
+
+ if bytes.Equal(hs.serverHello.random, helloRetryRequestRandom) {
+ c.sendAlert(alertUnexpectedMessage)
+ return errors.New("tls: server sent two HelloRetryRequest messages")
+ }
+
+ if len(hs.serverHello.cookie) != 0 {
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: server sent a cookie in a normal ServerHello")
+ }
+
+ if hs.serverHello.selectedGroup != 0 {
+ c.sendAlert(alertDecodeError)
+ return errors.New("tls: malformed key_share extension")
+ }
+
+ if hs.serverHello.serverShare.group == 0 {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server did not send a key share")
+ }
+ if sentID, _ := curveIDForCurve(hs.ecdheKey.Curve()); hs.serverHello.serverShare.group != sentID {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server selected unsupported group")
+ }
+
+ if !hs.serverHello.selectedIdentityPresent {
+ return nil
+ }
+
+ if int(hs.serverHello.selectedIdentity) >= len(hs.hello.pskIdentities) {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server selected an invalid PSK")
+ }
+
+ if len(hs.hello.pskIdentities) != 1 || hs.session == nil {
+ return c.sendAlert(alertInternalError)
+ }
+ pskSuite := cipherSuiteTLS13ByID(hs.session.cipherSuite)
+ if pskSuite == nil {
+ return c.sendAlert(alertInternalError)
+ }
+ if pskSuite.hash != hs.suite.hash {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: server selected an invalid PSK and cipher suite pair")
+ }
+
+ hs.usingPSK = true
+ c.didResume = true
+ c.peerCertificates = hs.session.serverCertificates
+ c.verifiedChains = hs.session.verifiedChains
+ c.ocspResponse = hs.session.ocspResponse
+ c.scts = hs.session.scts
+ return nil
+}
+
+func (hs *clientHandshakeStateTLS13) establishHandshakeKeys() error {
+ c := hs.c
+
+ peerKey, err := hs.ecdheKey.Curve().NewPublicKey(hs.serverHello.serverShare.data)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid server key share")
+ }
+ sharedKey, err := hs.ecdheKey.ECDH(peerKey)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid server key share")
+ }
+
+ earlySecret := hs.earlySecret
+ if !hs.usingPSK {
+ earlySecret = hs.suite.extract(nil, nil)
+ }
+
+ handshakeSecret := hs.suite.extract(sharedKey,
+ hs.suite.deriveSecret(earlySecret, "derived", nil))
+
+ clientSecret := hs.suite.deriveSecret(handshakeSecret,
+ clientHandshakeTrafficLabel, hs.transcript)
+ c.out.setTrafficSecret(hs.suite, clientSecret)
+ serverSecret := hs.suite.deriveSecret(handshakeSecret,
+ serverHandshakeTrafficLabel, hs.transcript)
+ c.in.setTrafficSecret(hs.suite, serverSecret)
+
+ err = c.config.writeKeyLog(keyLogLabelClientHandshake, hs.hello.random, clientSecret)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ err = c.config.writeKeyLog(keyLogLabelServerHandshake, hs.hello.random, serverSecret)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ hs.masterSecret = hs.suite.extract(nil,
+ hs.suite.deriveSecret(handshakeSecret, "derived", nil))
+
+ return nil
+}
+
+func (hs *clientHandshakeStateTLS13) readServerParameters() error {
+ c := hs.c
+
+ msg, err := c.readHandshake(hs.transcript)
+ if err != nil {
+ return err
+ }
+
+ encryptedExtensions, ok := msg.(*encryptedExtensionsMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(encryptedExtensions, msg)
+ }
+
+ if err := checkALPN(hs.hello.alpnProtocols, encryptedExtensions.alpnProtocol); err != nil {
+ c.sendAlert(alertUnsupportedExtension)
+ return err
+ }
+ c.clientProtocol = encryptedExtensions.alpnProtocol
+
+ return nil
+}
+
+func (hs *clientHandshakeStateTLS13) readServerCertificate() error {
+ c := hs.c
+
+ // Either a PSK or a certificate is always used, but not both.
+ // See RFC 8446, Section 4.1.1.
+ if hs.usingPSK {
+ // Make sure the connection is still being verified whether or not this
+ // is a resumption. Resumptions currently don't reverify certificates so
+ // they don't call verifyServerCertificate. See Issue 31641.
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+ return nil
+ }
+
+ msg, err := c.readHandshake(hs.transcript)
+ if err != nil {
+ return err
+ }
+
+ certReq, ok := msg.(*certificateRequestMsgTLS13)
+ if ok {
+ hs.certReq = certReq
+
+ msg, err = c.readHandshake(hs.transcript)
+ if err != nil {
+ return err
+ }
+ }
+
+ certMsg, ok := msg.(*certificateMsgTLS13)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
+ }
+ if len(certMsg.certificate.Certificate) == 0 {
+ c.sendAlert(alertDecodeError)
+ return errors.New("tls: received empty certificates message")
+ }
+
+ c.scts = certMsg.certificate.SignedCertificateTimestamps
+ c.ocspResponse = certMsg.certificate.OCSPStaple
+
+ if err := c.verifyServerCertificate(certMsg.certificate.Certificate); err != nil {
+ return err
+ }
+
+ // certificateVerifyMsg is included in the transcript, but not until
+ // after we verify the handshake signature, since the state before
+ // this message was sent is used.
+ msg, err = c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ certVerify, ok := msg.(*certificateVerifyMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certVerify, msg)
+ }
+
+ // See RFC 8446, Section 4.4.3.
+ if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: certificate used with invalid signature algorithm")
+ }
+ sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
+ if err != nil {
+ return c.sendAlert(alertInternalError)
+ }
+ if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: certificate used with invalid signature algorithm")
+ }
+ signed := signedMessage(sigHash, serverSignatureContext, hs.transcript)
+ if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey,
+ sigHash, signed, certVerify.signature); err != nil {
+ c.sendAlert(alertDecryptError)
+ return errors.New("tls: invalid signature by the server certificate: " + err.Error())
+ }
+
+ if err := transcriptMsg(certVerify, hs.transcript); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (hs *clientHandshakeStateTLS13) readServerFinished() error {
+ c := hs.c
+
+ // finishedMsg is included in the transcript, but not until after we
+ // check the client version, since the state before this message was
+ // sent is used during verification.
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ finished, ok := msg.(*finishedMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(finished, msg)
+ }
+
+ expectedMAC := hs.suite.finishedHash(c.in.trafficSecret, hs.transcript)
+ if !hmac.Equal(expectedMAC, finished.verifyData) {
+ c.sendAlert(alertDecryptError)
+ return errors.New("tls: invalid server finished hash")
+ }
+
+ if err := transcriptMsg(finished, hs.transcript); err != nil {
+ return err
+ }
+
+ // Derive secrets that take context through the server Finished.
+
+ hs.trafficSecret = hs.suite.deriveSecret(hs.masterSecret,
+ clientApplicationTrafficLabel, hs.transcript)
+ serverSecret := hs.suite.deriveSecret(hs.masterSecret,
+ serverApplicationTrafficLabel, hs.transcript)
+ c.in.setTrafficSecret(hs.suite, serverSecret)
+
+ err = c.config.writeKeyLog(keyLogLabelClientTraffic, hs.hello.random, hs.trafficSecret)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ err = c.config.writeKeyLog(keyLogLabelServerTraffic, hs.hello.random, serverSecret)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ c.ekm = hs.suite.exportKeyingMaterial(hs.masterSecret, hs.transcript)
+
+ return nil
+}
+
+func (hs *clientHandshakeStateTLS13) sendClientCertificate() error {
+ c := hs.c
+
+ if hs.certReq == nil {
+ return nil
+ }
+
+ cert, err := c.getClientCertificate(&CertificateRequestInfo{
+ AcceptableCAs: hs.certReq.certificateAuthorities,
+ SignatureSchemes: hs.certReq.supportedSignatureAlgorithms,
+ Version: c.vers,
+ ctx: hs.ctx,
+ })
+ if err != nil {
+ return err
+ }
+
+ certMsg := new(certificateMsgTLS13)
+
+ certMsg.certificate = *cert
+ certMsg.scts = hs.certReq.scts && len(cert.SignedCertificateTimestamps) > 0
+ certMsg.ocspStapling = hs.certReq.ocspStapling && len(cert.OCSPStaple) > 0
+
+ if _, err := hs.c.writeHandshakeRecord(certMsg, hs.transcript); err != nil {
+ return err
+ }
+
+ // If we sent an empty certificate message, skip the CertificateVerify.
+ if len(cert.Certificate) == 0 {
+ return nil
+ }
+
+ certVerifyMsg := new(certificateVerifyMsg)
+ certVerifyMsg.hasSignatureAlgorithm = true
+
+ certVerifyMsg.signatureAlgorithm, err = selectSignatureScheme(c.vers, cert, hs.certReq.supportedSignatureAlgorithms)
+ if err != nil {
+ // getClientCertificate returned a certificate incompatible with the
+ // CertificateRequestInfo supported signature algorithms.
+ c.sendAlert(alertHandshakeFailure)
+ return err
+ }
+
+ sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerifyMsg.signatureAlgorithm)
+ if err != nil {
+ return c.sendAlert(alertInternalError)
+ }
+
+ signed := signedMessage(sigHash, clientSignatureContext, hs.transcript)
+ signOpts := crypto.SignerOpts(sigHash)
+ if sigType == signatureRSAPSS {
+ signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
+ }
+ sig, err := cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), signed, signOpts)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: failed to sign handshake: " + err.Error())
+ }
+ certVerifyMsg.signature = sig
+
+ if _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (hs *clientHandshakeStateTLS13) sendClientFinished() error {
+ c := hs.c
+
+ finished := &finishedMsg{
+ verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript),
+ }
+
+ if _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil {
+ return err
+ }
+
+ c.out.setTrafficSecret(hs.suite, hs.trafficSecret)
+
+ if !c.config.SessionTicketsDisabled && c.config.ClientSessionCache != nil {
+ c.resumptionSecret = hs.suite.deriveSecret(hs.masterSecret,
+ resumptionLabel, hs.transcript)
+ }
+
+ return nil
+}
+
+func (c *Conn) handleNewSessionTicket(msg *newSessionTicketMsgTLS13) error {
+ if !c.isClient {
+ c.sendAlert(alertUnexpectedMessage)
+ return errors.New("tls: received new session ticket from a client")
+ }
+
+ if c.config.SessionTicketsDisabled || c.config.ClientSessionCache == nil {
+ return nil
+ }
+
+ // See RFC 8446, Section 4.6.1.
+ if msg.lifetime == 0 {
+ return nil
+ }
+ lifetime := time.Duration(msg.lifetime) * time.Second
+ if lifetime > maxSessionTicketLifetime {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: received a session ticket with invalid lifetime")
+ }
+
+ cipherSuite := cipherSuiteTLS13ByID(c.cipherSuite)
+ if cipherSuite == nil || c.resumptionSecret == nil {
+ return c.sendAlert(alertInternalError)
+ }
+
+ // Save the resumption_master_secret and nonce instead of deriving the PSK
+ // to do the least amount of work on NewSessionTicket messages before we
+ // know if the ticket will be used. Forward secrecy of resumed connections
+ // is guaranteed by the requirement for pskModeDHE.
+ session := &ClientSessionState{
+ sessionTicket: msg.label,
+ vers: c.vers,
+ cipherSuite: c.cipherSuite,
+ masterSecret: c.resumptionSecret,
+ serverCertificates: c.peerCertificates,
+ verifiedChains: c.verifiedChains,
+ receivedAt: c.config.time(),
+ nonce: msg.nonce,
+ useBy: c.config.time().Add(lifetime),
+ ageAdd: msg.ageAdd,
+ ocspResponse: c.ocspResponse,
+ scts: c.scts,
+ }
+
+ cacheKey := clientSessionCacheKey(c.conn.RemoteAddr(), c.config)
+ c.config.ClientSessionCache.Put(cacheKey, session)
+
+ return nil
+}
diff --git a/src/crypto/tls/handshake_messages.go b/src/crypto/tls/handshake_messages.go
new file mode 100644
index 0000000..695aacf
--- /dev/null
+++ b/src/crypto/tls/handshake_messages.go
@@ -0,0 +1,1852 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "errors"
+ "fmt"
+ "strings"
+
+ "golang.org/x/crypto/cryptobyte"
+)
+
+// The marshalingFunction type is an adapter to allow the use of ordinary
+// functions as cryptobyte.MarshalingValue.
+type marshalingFunction func(b *cryptobyte.Builder) error
+
+func (f marshalingFunction) Marshal(b *cryptobyte.Builder) error {
+ return f(b)
+}
+
+// addBytesWithLength appends a sequence of bytes to the cryptobyte.Builder. If
+// the length of the sequence is not the value specified, it produces an error.
+func addBytesWithLength(b *cryptobyte.Builder, v []byte, n int) {
+ b.AddValue(marshalingFunction(func(b *cryptobyte.Builder) error {
+ if len(v) != n {
+ return fmt.Errorf("invalid value length: expected %d, got %d", n, len(v))
+ }
+ b.AddBytes(v)
+ return nil
+ }))
+}
+
+// addUint64 appends a big-endian, 64-bit value to the cryptobyte.Builder.
+func addUint64(b *cryptobyte.Builder, v uint64) {
+ b.AddUint32(uint32(v >> 32))
+ b.AddUint32(uint32(v))
+}
+
+// readUint64 decodes a big-endian, 64-bit value into out and advances over it.
+// It reports whether the read was successful.
+func readUint64(s *cryptobyte.String, out *uint64) bool {
+ var hi, lo uint32
+ if !s.ReadUint32(&hi) || !s.ReadUint32(&lo) {
+ return false
+ }
+ *out = uint64(hi)<<32 | uint64(lo)
+ return true
+}
+
+// readUint8LengthPrefixed acts like s.ReadUint8LengthPrefixed, but targets a
+// []byte instead of a cryptobyte.String.
+func readUint8LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
+ return s.ReadUint8LengthPrefixed((*cryptobyte.String)(out))
+}
+
+// readUint16LengthPrefixed acts like s.ReadUint16LengthPrefixed, but targets a
+// []byte instead of a cryptobyte.String.
+func readUint16LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
+ return s.ReadUint16LengthPrefixed((*cryptobyte.String)(out))
+}
+
+// readUint24LengthPrefixed acts like s.ReadUint24LengthPrefixed, but targets a
+// []byte instead of a cryptobyte.String.
+func readUint24LengthPrefixed(s *cryptobyte.String, out *[]byte) bool {
+ return s.ReadUint24LengthPrefixed((*cryptobyte.String)(out))
+}
+
+type clientHelloMsg struct {
+ raw []byte
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuites []uint16
+ compressionMethods []uint8
+ serverName string
+ ocspStapling bool
+ supportedCurves []CurveID
+ supportedPoints []uint8
+ ticketSupported bool
+ sessionTicket []uint8
+ supportedSignatureAlgorithms []SignatureScheme
+ supportedSignatureAlgorithmsCert []SignatureScheme
+ secureRenegotiationSupported bool
+ secureRenegotiation []byte
+ alpnProtocols []string
+ scts bool
+ supportedVersions []uint16
+ cookie []byte
+ keyShares []keyShare
+ earlyData bool
+ pskModes []uint8
+ pskIdentities []pskIdentity
+ pskBinders [][]byte
+}
+
+func (m *clientHelloMsg) marshal() ([]byte, error) {
+ if m.raw != nil {
+ return m.raw, nil
+ }
+
+ var exts cryptobyte.Builder
+ if len(m.serverName) > 0 {
+ // RFC 6066, Section 3
+ exts.AddUint16(extensionServerName)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8(0) // name_type = host_name
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes([]byte(m.serverName))
+ })
+ })
+ })
+ }
+ if m.ocspStapling {
+ // RFC 4366, Section 3.6
+ exts.AddUint16(extensionStatusRequest)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8(1) // status_type = ocsp
+ exts.AddUint16(0) // empty responder_id_list
+ exts.AddUint16(0) // empty request_extensions
+ })
+ }
+ if len(m.supportedCurves) > 0 {
+ // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
+ exts.AddUint16(extensionSupportedCurves)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, curve := range m.supportedCurves {
+ exts.AddUint16(uint16(curve))
+ }
+ })
+ })
+ }
+ if len(m.supportedPoints) > 0 {
+ // RFC 4492, Section 5.1.2
+ exts.AddUint16(extensionSupportedPoints)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.supportedPoints)
+ })
+ })
+ }
+ if m.ticketSupported {
+ // RFC 5077, Section 3.2
+ exts.AddUint16(extensionSessionTicket)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.sessionTicket)
+ })
+ }
+ if len(m.supportedSignatureAlgorithms) > 0 {
+ // RFC 5246, Section 7.4.1.4.1
+ exts.AddUint16(extensionSignatureAlgorithms)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, sigAlgo := range m.supportedSignatureAlgorithms {
+ exts.AddUint16(uint16(sigAlgo))
+ }
+ })
+ })
+ }
+ if len(m.supportedSignatureAlgorithmsCert) > 0 {
+ // RFC 8446, Section 4.2.3
+ exts.AddUint16(extensionSignatureAlgorithmsCert)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, sigAlgo := range m.supportedSignatureAlgorithmsCert {
+ exts.AddUint16(uint16(sigAlgo))
+ }
+ })
+ })
+ }
+ if m.secureRenegotiationSupported {
+ // RFC 5746, Section 3.2
+ exts.AddUint16(extensionRenegotiationInfo)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.secureRenegotiation)
+ })
+ })
+ }
+ if len(m.alpnProtocols) > 0 {
+ // RFC 7301, Section 3.1
+ exts.AddUint16(extensionALPN)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, proto := range m.alpnProtocols {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes([]byte(proto))
+ })
+ }
+ })
+ })
+ }
+ if m.scts {
+ // RFC 6962, Section 3.3.1
+ exts.AddUint16(extensionSCT)
+ exts.AddUint16(0) // empty extension_data
+ }
+ if len(m.supportedVersions) > 0 {
+ // RFC 8446, Section 4.2.1
+ exts.AddUint16(extensionSupportedVersions)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, vers := range m.supportedVersions {
+ exts.AddUint16(vers)
+ }
+ })
+ })
+ }
+ if len(m.cookie) > 0 {
+ // RFC 8446, Section 4.2.2
+ exts.AddUint16(extensionCookie)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.cookie)
+ })
+ })
+ }
+ if len(m.keyShares) > 0 {
+ // RFC 8446, Section 4.2.8
+ exts.AddUint16(extensionKeyShare)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, ks := range m.keyShares {
+ exts.AddUint16(uint16(ks.group))
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(ks.data)
+ })
+ }
+ })
+ })
+ }
+ if m.earlyData {
+ // RFC 8446, Section 4.2.10
+ exts.AddUint16(extensionEarlyData)
+ exts.AddUint16(0) // empty extension_data
+ }
+ if len(m.pskModes) > 0 {
+ // RFC 8446, Section 4.2.9
+ exts.AddUint16(extensionPSKModes)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.pskModes)
+ })
+ })
+ }
+ if len(m.pskIdentities) > 0 { // pre_shared_key must be the last extension
+ // RFC 8446, Section 4.2.11
+ exts.AddUint16(extensionPreSharedKey)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, psk := range m.pskIdentities {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(psk.label)
+ })
+ exts.AddUint32(psk.obfuscatedTicketAge)
+ }
+ })
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, binder := range m.pskBinders {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(binder)
+ })
+ }
+ })
+ })
+ }
+ extBytes, err := exts.Bytes()
+ if err != nil {
+ return nil, err
+ }
+
+ var b cryptobyte.Builder
+ b.AddUint8(typeClientHello)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16(m.vers)
+ addBytesWithLength(b, m.random, 32)
+ b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.sessionId)
+ })
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ for _, suite := range m.cipherSuites {
+ b.AddUint16(suite)
+ }
+ })
+ b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.compressionMethods)
+ })
+
+ if len(extBytes) > 0 {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(extBytes)
+ })
+ }
+ })
+
+ m.raw, err = b.Bytes()
+ return m.raw, err
+}
+
+// marshalWithoutBinders returns the ClientHello through the
+// PreSharedKeyExtension.identities field, according to RFC 8446, Section
+// 4.2.11.2. Note that m.pskBinders must be set to slices of the correct length.
+func (m *clientHelloMsg) marshalWithoutBinders() ([]byte, error) {
+ bindersLen := 2 // uint16 length prefix
+ for _, binder := range m.pskBinders {
+ bindersLen += 1 // uint8 length prefix
+ bindersLen += len(binder)
+ }
+
+ fullMessage, err := m.marshal()
+ if err != nil {
+ return nil, err
+ }
+ return fullMessage[:len(fullMessage)-bindersLen], nil
+}
+
+// updateBinders updates the m.pskBinders field, if necessary updating the
+// cached marshaled representation. The supplied binders must have the same
+// length as the current m.pskBinders.
+func (m *clientHelloMsg) updateBinders(pskBinders [][]byte) error {
+ if len(pskBinders) != len(m.pskBinders) {
+ return errors.New("tls: internal error: pskBinders length mismatch")
+ }
+ for i := range m.pskBinders {
+ if len(pskBinders[i]) != len(m.pskBinders[i]) {
+ return errors.New("tls: internal error: pskBinders length mismatch")
+ }
+ }
+ m.pskBinders = pskBinders
+ if m.raw != nil {
+ helloBytes, err := m.marshalWithoutBinders()
+ if err != nil {
+ return err
+ }
+ lenWithoutBinders := len(helloBytes)
+ b := cryptobyte.NewFixedBuilder(m.raw[:lenWithoutBinders])
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ for _, binder := range m.pskBinders {
+ b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(binder)
+ })
+ }
+ })
+ if out, err := b.Bytes(); err != nil || len(out) != len(m.raw) {
+ return errors.New("tls: internal error: failed to update binders")
+ }
+ }
+
+ return nil
+}
+
+func (m *clientHelloMsg) unmarshal(data []byte) bool {
+ *m = clientHelloMsg{raw: data}
+ s := cryptobyte.String(data)
+
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint16(&m.vers) || !s.ReadBytes(&m.random, 32) ||
+ !readUint8LengthPrefixed(&s, &m.sessionId) {
+ return false
+ }
+
+ var cipherSuites cryptobyte.String
+ if !s.ReadUint16LengthPrefixed(&cipherSuites) {
+ return false
+ }
+ m.cipherSuites = []uint16{}
+ m.secureRenegotiationSupported = false
+ for !cipherSuites.Empty() {
+ var suite uint16
+ if !cipherSuites.ReadUint16(&suite) {
+ return false
+ }
+ if suite == scsvRenegotiation {
+ m.secureRenegotiationSupported = true
+ }
+ m.cipherSuites = append(m.cipherSuites, suite)
+ }
+
+ if !readUint8LengthPrefixed(&s, &m.compressionMethods) {
+ return false
+ }
+
+ if s.Empty() {
+ // ClientHello is optionally followed by extension data
+ return true
+ }
+
+ var extensions cryptobyte.String
+ if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
+ return false
+ }
+
+ seenExts := make(map[uint16]bool)
+ for !extensions.Empty() {
+ var extension uint16
+ var extData cryptobyte.String
+ if !extensions.ReadUint16(&extension) ||
+ !extensions.ReadUint16LengthPrefixed(&extData) {
+ return false
+ }
+
+ if seenExts[extension] {
+ return false
+ }
+ seenExts[extension] = true
+
+ switch extension {
+ case extensionServerName:
+ // RFC 6066, Section 3
+ var nameList cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&nameList) || nameList.Empty() {
+ return false
+ }
+ for !nameList.Empty() {
+ var nameType uint8
+ var serverName cryptobyte.String
+ if !nameList.ReadUint8(&nameType) ||
+ !nameList.ReadUint16LengthPrefixed(&serverName) ||
+ serverName.Empty() {
+ return false
+ }
+ if nameType != 0 {
+ continue
+ }
+ if len(m.serverName) != 0 {
+ // Multiple names of the same name_type are prohibited.
+ return false
+ }
+ m.serverName = string(serverName)
+ // An SNI value may not include a trailing dot.
+ if strings.HasSuffix(m.serverName, ".") {
+ return false
+ }
+ }
+ case extensionStatusRequest:
+ // RFC 4366, Section 3.6
+ var statusType uint8
+ var ignored cryptobyte.String
+ if !extData.ReadUint8(&statusType) ||
+ !extData.ReadUint16LengthPrefixed(&ignored) ||
+ !extData.ReadUint16LengthPrefixed(&ignored) {
+ return false
+ }
+ m.ocspStapling = statusType == statusTypeOCSP
+ case extensionSupportedCurves:
+ // RFC 4492, sections 5.1.1 and RFC 8446, Section 4.2.7
+ var curves cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&curves) || curves.Empty() {
+ return false
+ }
+ for !curves.Empty() {
+ var curve uint16
+ if !curves.ReadUint16(&curve) {
+ return false
+ }
+ m.supportedCurves = append(m.supportedCurves, CurveID(curve))
+ }
+ case extensionSupportedPoints:
+ // RFC 4492, Section 5.1.2
+ if !readUint8LengthPrefixed(&extData, &m.supportedPoints) ||
+ len(m.supportedPoints) == 0 {
+ return false
+ }
+ case extensionSessionTicket:
+ // RFC 5077, Section 3.2
+ m.ticketSupported = true
+ extData.ReadBytes(&m.sessionTicket, len(extData))
+ case extensionSignatureAlgorithms:
+ // RFC 5246, Section 7.4.1.4.1
+ var sigAndAlgs cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
+ return false
+ }
+ for !sigAndAlgs.Empty() {
+ var sigAndAlg uint16
+ if !sigAndAlgs.ReadUint16(&sigAndAlg) {
+ return false
+ }
+ m.supportedSignatureAlgorithms = append(
+ m.supportedSignatureAlgorithms, SignatureScheme(sigAndAlg))
+ }
+ case extensionSignatureAlgorithmsCert:
+ // RFC 8446, Section 4.2.3
+ var sigAndAlgs cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
+ return false
+ }
+ for !sigAndAlgs.Empty() {
+ var sigAndAlg uint16
+ if !sigAndAlgs.ReadUint16(&sigAndAlg) {
+ return false
+ }
+ m.supportedSignatureAlgorithmsCert = append(
+ m.supportedSignatureAlgorithmsCert, SignatureScheme(sigAndAlg))
+ }
+ case extensionRenegotiationInfo:
+ // RFC 5746, Section 3.2
+ if !readUint8LengthPrefixed(&extData, &m.secureRenegotiation) {
+ return false
+ }
+ m.secureRenegotiationSupported = true
+ case extensionALPN:
+ // RFC 7301, Section 3.1
+ var protoList cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
+ return false
+ }
+ for !protoList.Empty() {
+ var proto cryptobyte.String
+ if !protoList.ReadUint8LengthPrefixed(&proto) || proto.Empty() {
+ return false
+ }
+ m.alpnProtocols = append(m.alpnProtocols, string(proto))
+ }
+ case extensionSCT:
+ // RFC 6962, Section 3.3.1
+ m.scts = true
+ case extensionSupportedVersions:
+ // RFC 8446, Section 4.2.1
+ var versList cryptobyte.String
+ if !extData.ReadUint8LengthPrefixed(&versList) || versList.Empty() {
+ return false
+ }
+ for !versList.Empty() {
+ var vers uint16
+ if !versList.ReadUint16(&vers) {
+ return false
+ }
+ m.supportedVersions = append(m.supportedVersions, vers)
+ }
+ case extensionCookie:
+ // RFC 8446, Section 4.2.2
+ if !readUint16LengthPrefixed(&extData, &m.cookie) ||
+ len(m.cookie) == 0 {
+ return false
+ }
+ case extensionKeyShare:
+ // RFC 8446, Section 4.2.8
+ var clientShares cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&clientShares) {
+ return false
+ }
+ for !clientShares.Empty() {
+ var ks keyShare
+ if !clientShares.ReadUint16((*uint16)(&ks.group)) ||
+ !readUint16LengthPrefixed(&clientShares, &ks.data) ||
+ len(ks.data) == 0 {
+ return false
+ }
+ m.keyShares = append(m.keyShares, ks)
+ }
+ case extensionEarlyData:
+ // RFC 8446, Section 4.2.10
+ m.earlyData = true
+ case extensionPSKModes:
+ // RFC 8446, Section 4.2.9
+ if !readUint8LengthPrefixed(&extData, &m.pskModes) {
+ return false
+ }
+ case extensionPreSharedKey:
+ // RFC 8446, Section 4.2.11
+ if !extensions.Empty() {
+ return false // pre_shared_key must be the last extension
+ }
+ var identities cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&identities) || identities.Empty() {
+ return false
+ }
+ for !identities.Empty() {
+ var psk pskIdentity
+ if !readUint16LengthPrefixed(&identities, &psk.label) ||
+ !identities.ReadUint32(&psk.obfuscatedTicketAge) ||
+ len(psk.label) == 0 {
+ return false
+ }
+ m.pskIdentities = append(m.pskIdentities, psk)
+ }
+ var binders cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&binders) || binders.Empty() {
+ return false
+ }
+ for !binders.Empty() {
+ var binder []byte
+ if !readUint8LengthPrefixed(&binders, &binder) ||
+ len(binder) == 0 {
+ return false
+ }
+ m.pskBinders = append(m.pskBinders, binder)
+ }
+ default:
+ // Ignore unknown extensions.
+ continue
+ }
+
+ if !extData.Empty() {
+ return false
+ }
+ }
+
+ return true
+}
+
+type serverHelloMsg struct {
+ raw []byte
+ vers uint16
+ random []byte
+ sessionId []byte
+ cipherSuite uint16
+ compressionMethod uint8
+ ocspStapling bool
+ ticketSupported bool
+ secureRenegotiationSupported bool
+ secureRenegotiation []byte
+ alpnProtocol string
+ scts [][]byte
+ supportedVersion uint16
+ serverShare keyShare
+ selectedIdentityPresent bool
+ selectedIdentity uint16
+ supportedPoints []uint8
+
+ // HelloRetryRequest extensions
+ cookie []byte
+ selectedGroup CurveID
+}
+
+func (m *serverHelloMsg) marshal() ([]byte, error) {
+ if m.raw != nil {
+ return m.raw, nil
+ }
+
+ var exts cryptobyte.Builder
+ if m.ocspStapling {
+ exts.AddUint16(extensionStatusRequest)
+ exts.AddUint16(0) // empty extension_data
+ }
+ if m.ticketSupported {
+ exts.AddUint16(extensionSessionTicket)
+ exts.AddUint16(0) // empty extension_data
+ }
+ if m.secureRenegotiationSupported {
+ exts.AddUint16(extensionRenegotiationInfo)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.secureRenegotiation)
+ })
+ })
+ }
+ if len(m.alpnProtocol) > 0 {
+ exts.AddUint16(extensionALPN)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes([]byte(m.alpnProtocol))
+ })
+ })
+ })
+ }
+ if len(m.scts) > 0 {
+ exts.AddUint16(extensionSCT)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ for _, sct := range m.scts {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(sct)
+ })
+ }
+ })
+ })
+ }
+ if m.supportedVersion != 0 {
+ exts.AddUint16(extensionSupportedVersions)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16(m.supportedVersion)
+ })
+ }
+ if m.serverShare.group != 0 {
+ exts.AddUint16(extensionKeyShare)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16(uint16(m.serverShare.group))
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.serverShare.data)
+ })
+ })
+ }
+ if m.selectedIdentityPresent {
+ exts.AddUint16(extensionPreSharedKey)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16(m.selectedIdentity)
+ })
+ }
+
+ if len(m.cookie) > 0 {
+ exts.AddUint16(extensionCookie)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.cookie)
+ })
+ })
+ }
+ if m.selectedGroup != 0 {
+ exts.AddUint16(extensionKeyShare)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint16(uint16(m.selectedGroup))
+ })
+ }
+ if len(m.supportedPoints) > 0 {
+ exts.AddUint16(extensionSupportedPoints)
+ exts.AddUint16LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddUint8LengthPrefixed(func(exts *cryptobyte.Builder) {
+ exts.AddBytes(m.supportedPoints)
+ })
+ })
+ }
+
+ extBytes, err := exts.Bytes()
+ if err != nil {
+ return nil, err
+ }
+
+ var b cryptobyte.Builder
+ b.AddUint8(typeServerHello)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16(m.vers)
+ addBytesWithLength(b, m.random, 32)
+ b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.sessionId)
+ })
+ b.AddUint16(m.cipherSuite)
+ b.AddUint8(m.compressionMethod)
+
+ if len(extBytes) > 0 {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(extBytes)
+ })
+ }
+ })
+
+ m.raw, err = b.Bytes()
+ return m.raw, err
+}
+
+func (m *serverHelloMsg) unmarshal(data []byte) bool {
+ *m = serverHelloMsg{raw: data}
+ s := cryptobyte.String(data)
+
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint16(&m.vers) || !s.ReadBytes(&m.random, 32) ||
+ !readUint8LengthPrefixed(&s, &m.sessionId) ||
+ !s.ReadUint16(&m.cipherSuite) ||
+ !s.ReadUint8(&m.compressionMethod) {
+ return false
+ }
+
+ if s.Empty() {
+ // ServerHello is optionally followed by extension data
+ return true
+ }
+
+ var extensions cryptobyte.String
+ if !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
+ return false
+ }
+
+ seenExts := make(map[uint16]bool)
+ for !extensions.Empty() {
+ var extension uint16
+ var extData cryptobyte.String
+ if !extensions.ReadUint16(&extension) ||
+ !extensions.ReadUint16LengthPrefixed(&extData) {
+ return false
+ }
+
+ if seenExts[extension] {
+ return false
+ }
+ seenExts[extension] = true
+
+ switch extension {
+ case extensionStatusRequest:
+ m.ocspStapling = true
+ case extensionSessionTicket:
+ m.ticketSupported = true
+ case extensionRenegotiationInfo:
+ if !readUint8LengthPrefixed(&extData, &m.secureRenegotiation) {
+ return false
+ }
+ m.secureRenegotiationSupported = true
+ case extensionALPN:
+ var protoList cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
+ return false
+ }
+ var proto cryptobyte.String
+ if !protoList.ReadUint8LengthPrefixed(&proto) ||
+ proto.Empty() || !protoList.Empty() {
+ return false
+ }
+ m.alpnProtocol = string(proto)
+ case extensionSCT:
+ var sctList cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&sctList) || sctList.Empty() {
+ return false
+ }
+ for !sctList.Empty() {
+ var sct []byte
+ if !readUint16LengthPrefixed(&sctList, &sct) ||
+ len(sct) == 0 {
+ return false
+ }
+ m.scts = append(m.scts, sct)
+ }
+ case extensionSupportedVersions:
+ if !extData.ReadUint16(&m.supportedVersion) {
+ return false
+ }
+ case extensionCookie:
+ if !readUint16LengthPrefixed(&extData, &m.cookie) ||
+ len(m.cookie) == 0 {
+ return false
+ }
+ case extensionKeyShare:
+ // This extension has different formats in SH and HRR, accept either
+ // and let the handshake logic decide. See RFC 8446, Section 4.2.8.
+ if len(extData) == 2 {
+ if !extData.ReadUint16((*uint16)(&m.selectedGroup)) {
+ return false
+ }
+ } else {
+ if !extData.ReadUint16((*uint16)(&m.serverShare.group)) ||
+ !readUint16LengthPrefixed(&extData, &m.serverShare.data) {
+ return false
+ }
+ }
+ case extensionPreSharedKey:
+ m.selectedIdentityPresent = true
+ if !extData.ReadUint16(&m.selectedIdentity) {
+ return false
+ }
+ case extensionSupportedPoints:
+ // RFC 4492, Section 5.1.2
+ if !readUint8LengthPrefixed(&extData, &m.supportedPoints) ||
+ len(m.supportedPoints) == 0 {
+ return false
+ }
+ default:
+ // Ignore unknown extensions.
+ continue
+ }
+
+ if !extData.Empty() {
+ return false
+ }
+ }
+
+ return true
+}
+
+type encryptedExtensionsMsg struct {
+ raw []byte
+ alpnProtocol string
+}
+
+func (m *encryptedExtensionsMsg) marshal() ([]byte, error) {
+ if m.raw != nil {
+ return m.raw, nil
+ }
+
+ var b cryptobyte.Builder
+ b.AddUint8(typeEncryptedExtensions)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ if len(m.alpnProtocol) > 0 {
+ b.AddUint16(extensionALPN)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes([]byte(m.alpnProtocol))
+ })
+ })
+ })
+ }
+ })
+ })
+
+ var err error
+ m.raw, err = b.Bytes()
+ return m.raw, err
+}
+
+func (m *encryptedExtensionsMsg) unmarshal(data []byte) bool {
+ *m = encryptedExtensionsMsg{raw: data}
+ s := cryptobyte.String(data)
+
+ var extensions cryptobyte.String
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint16LengthPrefixed(&extensions) || !s.Empty() {
+ return false
+ }
+
+ for !extensions.Empty() {
+ var extension uint16
+ var extData cryptobyte.String
+ if !extensions.ReadUint16(&extension) ||
+ !extensions.ReadUint16LengthPrefixed(&extData) {
+ return false
+ }
+
+ switch extension {
+ case extensionALPN:
+ var protoList cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&protoList) || protoList.Empty() {
+ return false
+ }
+ var proto cryptobyte.String
+ if !protoList.ReadUint8LengthPrefixed(&proto) ||
+ proto.Empty() || !protoList.Empty() {
+ return false
+ }
+ m.alpnProtocol = string(proto)
+ default:
+ // Ignore unknown extensions.
+ continue
+ }
+
+ if !extData.Empty() {
+ return false
+ }
+ }
+
+ return true
+}
+
+type endOfEarlyDataMsg struct{}
+
+func (m *endOfEarlyDataMsg) marshal() ([]byte, error) {
+ x := make([]byte, 4)
+ x[0] = typeEndOfEarlyData
+ return x, nil
+}
+
+func (m *endOfEarlyDataMsg) unmarshal(data []byte) bool {
+ return len(data) == 4
+}
+
+type keyUpdateMsg struct {
+ raw []byte
+ updateRequested bool
+}
+
+func (m *keyUpdateMsg) marshal() ([]byte, error) {
+ if m.raw != nil {
+ return m.raw, nil
+ }
+
+ var b cryptobyte.Builder
+ b.AddUint8(typeKeyUpdate)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ if m.updateRequested {
+ b.AddUint8(1)
+ } else {
+ b.AddUint8(0)
+ }
+ })
+
+ var err error
+ m.raw, err = b.Bytes()
+ return m.raw, err
+}
+
+func (m *keyUpdateMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ s := cryptobyte.String(data)
+
+ var updateRequested uint8
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint8(&updateRequested) || !s.Empty() {
+ return false
+ }
+ switch updateRequested {
+ case 0:
+ m.updateRequested = false
+ case 1:
+ m.updateRequested = true
+ default:
+ return false
+ }
+ return true
+}
+
+type newSessionTicketMsgTLS13 struct {
+ raw []byte
+ lifetime uint32
+ ageAdd uint32
+ nonce []byte
+ label []byte
+ maxEarlyData uint32
+}
+
+func (m *newSessionTicketMsgTLS13) marshal() ([]byte, error) {
+ if m.raw != nil {
+ return m.raw, nil
+ }
+
+ var b cryptobyte.Builder
+ b.AddUint8(typeNewSessionTicket)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint32(m.lifetime)
+ b.AddUint32(m.ageAdd)
+ b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.nonce)
+ })
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.label)
+ })
+
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ if m.maxEarlyData > 0 {
+ b.AddUint16(extensionEarlyData)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint32(m.maxEarlyData)
+ })
+ }
+ })
+ })
+
+ var err error
+ m.raw, err = b.Bytes()
+ return m.raw, err
+}
+
+func (m *newSessionTicketMsgTLS13) unmarshal(data []byte) bool {
+ *m = newSessionTicketMsgTLS13{raw: data}
+ s := cryptobyte.String(data)
+
+ var extensions cryptobyte.String
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint32(&m.lifetime) ||
+ !s.ReadUint32(&m.ageAdd) ||
+ !readUint8LengthPrefixed(&s, &m.nonce) ||
+ !readUint16LengthPrefixed(&s, &m.label) ||
+ !s.ReadUint16LengthPrefixed(&extensions) ||
+ !s.Empty() {
+ return false
+ }
+
+ for !extensions.Empty() {
+ var extension uint16
+ var extData cryptobyte.String
+ if !extensions.ReadUint16(&extension) ||
+ !extensions.ReadUint16LengthPrefixed(&extData) {
+ return false
+ }
+
+ switch extension {
+ case extensionEarlyData:
+ if !extData.ReadUint32(&m.maxEarlyData) {
+ return false
+ }
+ default:
+ // Ignore unknown extensions.
+ continue
+ }
+
+ if !extData.Empty() {
+ return false
+ }
+ }
+
+ return true
+}
+
+type certificateRequestMsgTLS13 struct {
+ raw []byte
+ ocspStapling bool
+ scts bool
+ supportedSignatureAlgorithms []SignatureScheme
+ supportedSignatureAlgorithmsCert []SignatureScheme
+ certificateAuthorities [][]byte
+}
+
+func (m *certificateRequestMsgTLS13) marshal() ([]byte, error) {
+ if m.raw != nil {
+ return m.raw, nil
+ }
+
+ var b cryptobyte.Builder
+ b.AddUint8(typeCertificateRequest)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ // certificate_request_context (SHALL be zero length unless used for
+ // post-handshake authentication)
+ b.AddUint8(0)
+
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ if m.ocspStapling {
+ b.AddUint16(extensionStatusRequest)
+ b.AddUint16(0) // empty extension_data
+ }
+ if m.scts {
+ // RFC 8446, Section 4.4.2.1 makes no mention of
+ // signed_certificate_timestamp in CertificateRequest, but
+ // "Extensions in the Certificate message from the client MUST
+ // correspond to extensions in the CertificateRequest message
+ // from the server." and it appears in the table in Section 4.2.
+ b.AddUint16(extensionSCT)
+ b.AddUint16(0) // empty extension_data
+ }
+ if len(m.supportedSignatureAlgorithms) > 0 {
+ b.AddUint16(extensionSignatureAlgorithms)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ for _, sigAlgo := range m.supportedSignatureAlgorithms {
+ b.AddUint16(uint16(sigAlgo))
+ }
+ })
+ })
+ }
+ if len(m.supportedSignatureAlgorithmsCert) > 0 {
+ b.AddUint16(extensionSignatureAlgorithmsCert)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ for _, sigAlgo := range m.supportedSignatureAlgorithmsCert {
+ b.AddUint16(uint16(sigAlgo))
+ }
+ })
+ })
+ }
+ if len(m.certificateAuthorities) > 0 {
+ b.AddUint16(extensionCertificateAuthorities)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ for _, ca := range m.certificateAuthorities {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(ca)
+ })
+ }
+ })
+ })
+ }
+ })
+ })
+
+ var err error
+ m.raw, err = b.Bytes()
+ return m.raw, err
+}
+
+func (m *certificateRequestMsgTLS13) unmarshal(data []byte) bool {
+ *m = certificateRequestMsgTLS13{raw: data}
+ s := cryptobyte.String(data)
+
+ var context, extensions cryptobyte.String
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint8LengthPrefixed(&context) || !context.Empty() ||
+ !s.ReadUint16LengthPrefixed(&extensions) ||
+ !s.Empty() {
+ return false
+ }
+
+ for !extensions.Empty() {
+ var extension uint16
+ var extData cryptobyte.String
+ if !extensions.ReadUint16(&extension) ||
+ !extensions.ReadUint16LengthPrefixed(&extData) {
+ return false
+ }
+
+ switch extension {
+ case extensionStatusRequest:
+ m.ocspStapling = true
+ case extensionSCT:
+ m.scts = true
+ case extensionSignatureAlgorithms:
+ var sigAndAlgs cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
+ return false
+ }
+ for !sigAndAlgs.Empty() {
+ var sigAndAlg uint16
+ if !sigAndAlgs.ReadUint16(&sigAndAlg) {
+ return false
+ }
+ m.supportedSignatureAlgorithms = append(
+ m.supportedSignatureAlgorithms, SignatureScheme(sigAndAlg))
+ }
+ case extensionSignatureAlgorithmsCert:
+ var sigAndAlgs cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&sigAndAlgs) || sigAndAlgs.Empty() {
+ return false
+ }
+ for !sigAndAlgs.Empty() {
+ var sigAndAlg uint16
+ if !sigAndAlgs.ReadUint16(&sigAndAlg) {
+ return false
+ }
+ m.supportedSignatureAlgorithmsCert = append(
+ m.supportedSignatureAlgorithmsCert, SignatureScheme(sigAndAlg))
+ }
+ case extensionCertificateAuthorities:
+ var auths cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&auths) || auths.Empty() {
+ return false
+ }
+ for !auths.Empty() {
+ var ca []byte
+ if !readUint16LengthPrefixed(&auths, &ca) || len(ca) == 0 {
+ return false
+ }
+ m.certificateAuthorities = append(m.certificateAuthorities, ca)
+ }
+ default:
+ // Ignore unknown extensions.
+ continue
+ }
+
+ if !extData.Empty() {
+ return false
+ }
+ }
+
+ return true
+}
+
+type certificateMsg struct {
+ raw []byte
+ certificates [][]byte
+}
+
+func (m *certificateMsg) marshal() ([]byte, error) {
+ if m.raw != nil {
+ return m.raw, nil
+ }
+
+ var i int
+ for _, slice := range m.certificates {
+ i += len(slice)
+ }
+
+ length := 3 + 3*len(m.certificates) + i
+ x := make([]byte, 4+length)
+ x[0] = typeCertificate
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+
+ certificateOctets := length - 3
+ x[4] = uint8(certificateOctets >> 16)
+ x[5] = uint8(certificateOctets >> 8)
+ x[6] = uint8(certificateOctets)
+
+ y := x[7:]
+ for _, slice := range m.certificates {
+ y[0] = uint8(len(slice) >> 16)
+ y[1] = uint8(len(slice) >> 8)
+ y[2] = uint8(len(slice))
+ copy(y[3:], slice)
+ y = y[3+len(slice):]
+ }
+
+ m.raw = x
+ return m.raw, nil
+}
+
+func (m *certificateMsg) unmarshal(data []byte) bool {
+ if len(data) < 7 {
+ return false
+ }
+
+ m.raw = data
+ certsLen := uint32(data[4])<<16 | uint32(data[5])<<8 | uint32(data[6])
+ if uint32(len(data)) != certsLen+7 {
+ return false
+ }
+
+ numCerts := 0
+ d := data[7:]
+ for certsLen > 0 {
+ if len(d) < 4 {
+ return false
+ }
+ certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
+ if uint32(len(d)) < 3+certLen {
+ return false
+ }
+ d = d[3+certLen:]
+ certsLen -= 3 + certLen
+ numCerts++
+ }
+
+ m.certificates = make([][]byte, numCerts)
+ d = data[7:]
+ for i := 0; i < numCerts; i++ {
+ certLen := uint32(d[0])<<16 | uint32(d[1])<<8 | uint32(d[2])
+ m.certificates[i] = d[3 : 3+certLen]
+ d = d[3+certLen:]
+ }
+
+ return true
+}
+
+type certificateMsgTLS13 struct {
+ raw []byte
+ certificate Certificate
+ ocspStapling bool
+ scts bool
+}
+
+func (m *certificateMsgTLS13) marshal() ([]byte, error) {
+ if m.raw != nil {
+ return m.raw, nil
+ }
+
+ var b cryptobyte.Builder
+ b.AddUint8(typeCertificate)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint8(0) // certificate_request_context
+
+ certificate := m.certificate
+ if !m.ocspStapling {
+ certificate.OCSPStaple = nil
+ }
+ if !m.scts {
+ certificate.SignedCertificateTimestamps = nil
+ }
+ marshalCertificate(b, certificate)
+ })
+
+ var err error
+ m.raw, err = b.Bytes()
+ return m.raw, err
+}
+
+func marshalCertificate(b *cryptobyte.Builder, certificate Certificate) {
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ for i, cert := range certificate.Certificate {
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(cert)
+ })
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ if i > 0 {
+ // This library only supports OCSP and SCT for leaf certificates.
+ return
+ }
+ if certificate.OCSPStaple != nil {
+ b.AddUint16(extensionStatusRequest)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint8(statusTypeOCSP)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(certificate.OCSPStaple)
+ })
+ })
+ }
+ if certificate.SignedCertificateTimestamps != nil {
+ b.AddUint16(extensionSCT)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ for _, sct := range certificate.SignedCertificateTimestamps {
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(sct)
+ })
+ }
+ })
+ })
+ }
+ })
+ }
+ })
+}
+
+func (m *certificateMsgTLS13) unmarshal(data []byte) bool {
+ *m = certificateMsgTLS13{raw: data}
+ s := cryptobyte.String(data)
+
+ var context cryptobyte.String
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint8LengthPrefixed(&context) || !context.Empty() ||
+ !unmarshalCertificate(&s, &m.certificate) ||
+ !s.Empty() {
+ return false
+ }
+
+ m.scts = m.certificate.SignedCertificateTimestamps != nil
+ m.ocspStapling = m.certificate.OCSPStaple != nil
+
+ return true
+}
+
+func unmarshalCertificate(s *cryptobyte.String, certificate *Certificate) bool {
+ var certList cryptobyte.String
+ if !s.ReadUint24LengthPrefixed(&certList) {
+ return false
+ }
+ for !certList.Empty() {
+ var cert []byte
+ var extensions cryptobyte.String
+ if !readUint24LengthPrefixed(&certList, &cert) ||
+ !certList.ReadUint16LengthPrefixed(&extensions) {
+ return false
+ }
+ certificate.Certificate = append(certificate.Certificate, cert)
+ for !extensions.Empty() {
+ var extension uint16
+ var extData cryptobyte.String
+ if !extensions.ReadUint16(&extension) ||
+ !extensions.ReadUint16LengthPrefixed(&extData) {
+ return false
+ }
+ if len(certificate.Certificate) > 1 {
+ // This library only supports OCSP and SCT for leaf certificates.
+ continue
+ }
+
+ switch extension {
+ case extensionStatusRequest:
+ var statusType uint8
+ if !extData.ReadUint8(&statusType) || statusType != statusTypeOCSP ||
+ !readUint24LengthPrefixed(&extData, &certificate.OCSPStaple) ||
+ len(certificate.OCSPStaple) == 0 {
+ return false
+ }
+ case extensionSCT:
+ var sctList cryptobyte.String
+ if !extData.ReadUint16LengthPrefixed(&sctList) || sctList.Empty() {
+ return false
+ }
+ for !sctList.Empty() {
+ var sct []byte
+ if !readUint16LengthPrefixed(&sctList, &sct) ||
+ len(sct) == 0 {
+ return false
+ }
+ certificate.SignedCertificateTimestamps = append(
+ certificate.SignedCertificateTimestamps, sct)
+ }
+ default:
+ // Ignore unknown extensions.
+ continue
+ }
+
+ if !extData.Empty() {
+ return false
+ }
+ }
+ }
+ return true
+}
+
+type serverKeyExchangeMsg struct {
+ raw []byte
+ key []byte
+}
+
+func (m *serverKeyExchangeMsg) marshal() ([]byte, error) {
+ if m.raw != nil {
+ return m.raw, nil
+ }
+ length := len(m.key)
+ x := make([]byte, length+4)
+ x[0] = typeServerKeyExchange
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ copy(x[4:], m.key)
+
+ m.raw = x
+ return x, nil
+}
+
+func (m *serverKeyExchangeMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) < 4 {
+ return false
+ }
+ m.key = data[4:]
+ return true
+}
+
+type certificateStatusMsg struct {
+ raw []byte
+ response []byte
+}
+
+func (m *certificateStatusMsg) marshal() ([]byte, error) {
+ if m.raw != nil {
+ return m.raw, nil
+ }
+
+ var b cryptobyte.Builder
+ b.AddUint8(typeCertificateStatus)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddUint8(statusTypeOCSP)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.response)
+ })
+ })
+
+ var err error
+ m.raw, err = b.Bytes()
+ return m.raw, err
+}
+
+func (m *certificateStatusMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ s := cryptobyte.String(data)
+
+ var statusType uint8
+ if !s.Skip(4) || // message type and uint24 length field
+ !s.ReadUint8(&statusType) || statusType != statusTypeOCSP ||
+ !readUint24LengthPrefixed(&s, &m.response) ||
+ len(m.response) == 0 || !s.Empty() {
+ return false
+ }
+ return true
+}
+
+type serverHelloDoneMsg struct{}
+
+func (m *serverHelloDoneMsg) marshal() ([]byte, error) {
+ x := make([]byte, 4)
+ x[0] = typeServerHelloDone
+ return x, nil
+}
+
+func (m *serverHelloDoneMsg) unmarshal(data []byte) bool {
+ return len(data) == 4
+}
+
+type clientKeyExchangeMsg struct {
+ raw []byte
+ ciphertext []byte
+}
+
+func (m *clientKeyExchangeMsg) marshal() ([]byte, error) {
+ if m.raw != nil {
+ return m.raw, nil
+ }
+ length := len(m.ciphertext)
+ x := make([]byte, length+4)
+ x[0] = typeClientKeyExchange
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ copy(x[4:], m.ciphertext)
+
+ m.raw = x
+ return x, nil
+}
+
+func (m *clientKeyExchangeMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ if len(data) < 4 {
+ return false
+ }
+ l := int(data[1])<<16 | int(data[2])<<8 | int(data[3])
+ if l != len(data)-4 {
+ return false
+ }
+ m.ciphertext = data[4:]
+ return true
+}
+
+type finishedMsg struct {
+ raw []byte
+ verifyData []byte
+}
+
+func (m *finishedMsg) marshal() ([]byte, error) {
+ if m.raw != nil {
+ return m.raw, nil
+ }
+
+ var b cryptobyte.Builder
+ b.AddUint8(typeFinished)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.verifyData)
+ })
+
+ var err error
+ m.raw, err = b.Bytes()
+ return m.raw, err
+}
+
+func (m *finishedMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ s := cryptobyte.String(data)
+ return s.Skip(1) &&
+ readUint24LengthPrefixed(&s, &m.verifyData) &&
+ s.Empty()
+}
+
+type certificateRequestMsg struct {
+ raw []byte
+ // hasSignatureAlgorithm indicates whether this message includes a list of
+ // supported signature algorithms. This change was introduced with TLS 1.2.
+ hasSignatureAlgorithm bool
+
+ certificateTypes []byte
+ supportedSignatureAlgorithms []SignatureScheme
+ certificateAuthorities [][]byte
+}
+
+func (m *certificateRequestMsg) marshal() ([]byte, error) {
+ if m.raw != nil {
+ return m.raw, nil
+ }
+
+ // See RFC 4346, Section 7.4.4.
+ length := 1 + len(m.certificateTypes) + 2
+ casLength := 0
+ for _, ca := range m.certificateAuthorities {
+ casLength += 2 + len(ca)
+ }
+ length += casLength
+
+ if m.hasSignatureAlgorithm {
+ length += 2 + 2*len(m.supportedSignatureAlgorithms)
+ }
+
+ x := make([]byte, 4+length)
+ x[0] = typeCertificateRequest
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+
+ x[4] = uint8(len(m.certificateTypes))
+
+ copy(x[5:], m.certificateTypes)
+ y := x[5+len(m.certificateTypes):]
+
+ if m.hasSignatureAlgorithm {
+ n := len(m.supportedSignatureAlgorithms) * 2
+ y[0] = uint8(n >> 8)
+ y[1] = uint8(n)
+ y = y[2:]
+ for _, sigAlgo := range m.supportedSignatureAlgorithms {
+ y[0] = uint8(sigAlgo >> 8)
+ y[1] = uint8(sigAlgo)
+ y = y[2:]
+ }
+ }
+
+ y[0] = uint8(casLength >> 8)
+ y[1] = uint8(casLength)
+ y = y[2:]
+ for _, ca := range m.certificateAuthorities {
+ y[0] = uint8(len(ca) >> 8)
+ y[1] = uint8(len(ca))
+ y = y[2:]
+ copy(y, ca)
+ y = y[len(ca):]
+ }
+
+ m.raw = x
+ return m.raw, nil
+}
+
+func (m *certificateRequestMsg) unmarshal(data []byte) bool {
+ m.raw = data
+
+ if len(data) < 5 {
+ return false
+ }
+
+ length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+ if uint32(len(data))-4 != length {
+ return false
+ }
+
+ numCertTypes := int(data[4])
+ data = data[5:]
+ if numCertTypes == 0 || len(data) <= numCertTypes {
+ return false
+ }
+
+ m.certificateTypes = make([]byte, numCertTypes)
+ if copy(m.certificateTypes, data) != numCertTypes {
+ return false
+ }
+
+ data = data[numCertTypes:]
+
+ if m.hasSignatureAlgorithm {
+ if len(data) < 2 {
+ return false
+ }
+ sigAndHashLen := uint16(data[0])<<8 | uint16(data[1])
+ data = data[2:]
+ if sigAndHashLen&1 != 0 {
+ return false
+ }
+ if len(data) < int(sigAndHashLen) {
+ return false
+ }
+ numSigAlgos := sigAndHashLen / 2
+ m.supportedSignatureAlgorithms = make([]SignatureScheme, numSigAlgos)
+ for i := range m.supportedSignatureAlgorithms {
+ m.supportedSignatureAlgorithms[i] = SignatureScheme(data[0])<<8 | SignatureScheme(data[1])
+ data = data[2:]
+ }
+ }
+
+ if len(data) < 2 {
+ return false
+ }
+ casLength := uint16(data[0])<<8 | uint16(data[1])
+ data = data[2:]
+ if len(data) < int(casLength) {
+ return false
+ }
+ cas := make([]byte, casLength)
+ copy(cas, data)
+ data = data[casLength:]
+
+ m.certificateAuthorities = nil
+ for len(cas) > 0 {
+ if len(cas) < 2 {
+ return false
+ }
+ caLen := uint16(cas[0])<<8 | uint16(cas[1])
+ cas = cas[2:]
+
+ if len(cas) < int(caLen) {
+ return false
+ }
+
+ m.certificateAuthorities = append(m.certificateAuthorities, cas[:caLen])
+ cas = cas[caLen:]
+ }
+
+ return len(data) == 0
+}
+
+type certificateVerifyMsg struct {
+ raw []byte
+ hasSignatureAlgorithm bool // format change introduced in TLS 1.2
+ signatureAlgorithm SignatureScheme
+ signature []byte
+}
+
+func (m *certificateVerifyMsg) marshal() ([]byte, error) {
+ if m.raw != nil {
+ return m.raw, nil
+ }
+
+ var b cryptobyte.Builder
+ b.AddUint8(typeCertificateVerify)
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ if m.hasSignatureAlgorithm {
+ b.AddUint16(uint16(m.signatureAlgorithm))
+ }
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.signature)
+ })
+ })
+
+ var err error
+ m.raw, err = b.Bytes()
+ return m.raw, err
+}
+
+func (m *certificateVerifyMsg) unmarshal(data []byte) bool {
+ m.raw = data
+ s := cryptobyte.String(data)
+
+ if !s.Skip(4) { // message type and uint24 length field
+ return false
+ }
+ if m.hasSignatureAlgorithm {
+ if !s.ReadUint16((*uint16)(&m.signatureAlgorithm)) {
+ return false
+ }
+ }
+ return readUint16LengthPrefixed(&s, &m.signature) && s.Empty()
+}
+
+type newSessionTicketMsg struct {
+ raw []byte
+ ticket []byte
+}
+
+func (m *newSessionTicketMsg) marshal() ([]byte, error) {
+ if m.raw != nil {
+ return m.raw, nil
+ }
+
+ // See RFC 5077, Section 3.3.
+ ticketLen := len(m.ticket)
+ length := 2 + 4 + ticketLen
+ x := make([]byte, 4+length)
+ x[0] = typeNewSessionTicket
+ x[1] = uint8(length >> 16)
+ x[2] = uint8(length >> 8)
+ x[3] = uint8(length)
+ x[8] = uint8(ticketLen >> 8)
+ x[9] = uint8(ticketLen)
+ copy(x[10:], m.ticket)
+
+ m.raw = x
+
+ return m.raw, nil
+}
+
+func (m *newSessionTicketMsg) unmarshal(data []byte) bool {
+ m.raw = data
+
+ if len(data) < 10 {
+ return false
+ }
+
+ length := uint32(data[1])<<16 | uint32(data[2])<<8 | uint32(data[3])
+ if uint32(len(data))-4 != length {
+ return false
+ }
+
+ ticketLen := int(data[8])<<8 + int(data[9])
+ if len(data)-10 != ticketLen {
+ return false
+ }
+
+ m.ticket = data[10:]
+
+ return true
+}
+
+type helloRequestMsg struct {
+}
+
+func (*helloRequestMsg) marshal() ([]byte, error) {
+ return []byte{typeHelloRequest, 0, 0, 0}, nil
+}
+
+func (*helloRequestMsg) unmarshal(data []byte) bool {
+ return len(data) == 4
+}
+
+type transcriptHash interface {
+ Write([]byte) (int, error)
+}
+
+// transcriptMsg is a helper used to marshal and hash messages which typically
+// are not written to the wire, and as such aren't hashed during Conn.writeRecord.
+func transcriptMsg(msg handshakeMessage, h transcriptHash) error {
+ data, err := msg.marshal()
+ if err != nil {
+ return err
+ }
+ h.Write(data)
+ return nil
+}
diff --git a/src/crypto/tls/handshake_messages_test.go b/src/crypto/tls/handshake_messages_test.go
new file mode 100644
index 0000000..206e2fb
--- /dev/null
+++ b/src/crypto/tls/handshake_messages_test.go
@@ -0,0 +1,495 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "bytes"
+ "encoding/hex"
+ "math/rand"
+ "reflect"
+ "strings"
+ "testing"
+ "testing/quick"
+ "time"
+)
+
+var tests = []any{
+ &clientHelloMsg{},
+ &serverHelloMsg{},
+ &finishedMsg{},
+
+ &certificateMsg{},
+ &certificateRequestMsg{},
+ &certificateVerifyMsg{
+ hasSignatureAlgorithm: true,
+ },
+ &certificateStatusMsg{},
+ &clientKeyExchangeMsg{},
+ &newSessionTicketMsg{},
+ &sessionState{},
+ &sessionStateTLS13{},
+ &encryptedExtensionsMsg{},
+ &endOfEarlyDataMsg{},
+ &keyUpdateMsg{},
+ &newSessionTicketMsgTLS13{},
+ &certificateRequestMsgTLS13{},
+ &certificateMsgTLS13{},
+}
+
+func mustMarshal(t *testing.T, msg handshakeMessage) []byte {
+ t.Helper()
+ b, err := msg.marshal()
+ if err != nil {
+ t.Fatal(err)
+ }
+ return b
+}
+
+func TestMarshalUnmarshal(t *testing.T) {
+ rand := rand.New(rand.NewSource(time.Now().UnixNano()))
+
+ for i, iface := range tests {
+ ty := reflect.ValueOf(iface).Type()
+
+ n := 100
+ if testing.Short() {
+ n = 5
+ }
+ for j := 0; j < n; j++ {
+ v, ok := quick.Value(ty, rand)
+ if !ok {
+ t.Errorf("#%d: failed to create value", i)
+ break
+ }
+
+ m1 := v.Interface().(handshakeMessage)
+ marshaled := mustMarshal(t, m1)
+ m2 := iface.(handshakeMessage)
+ if !m2.unmarshal(marshaled) {
+ t.Errorf("#%d failed to unmarshal %#v %x", i, m1, marshaled)
+ break
+ }
+ m2.marshal() // to fill any marshal cache in the message
+
+ if !reflect.DeepEqual(m1, m2) {
+ t.Errorf("#%d got:%#v want:%#v %x", i, m2, m1, marshaled)
+ break
+ }
+
+ if i >= 3 {
+ // The first three message types (ClientHello,
+ // ServerHello and Finished) are allowed to
+ // have parsable prefixes because the extension
+ // data is optional and the length of the
+ // Finished varies across versions.
+ for j := 0; j < len(marshaled); j++ {
+ if m2.unmarshal(marshaled[0:j]) {
+ t.Errorf("#%d unmarshaled a prefix of length %d of %#v", i, j, m1)
+ break
+ }
+ }
+ }
+ }
+ }
+}
+
+func TestFuzz(t *testing.T) {
+ rand := rand.New(rand.NewSource(0))
+ for _, iface := range tests {
+ m := iface.(handshakeMessage)
+
+ for j := 0; j < 1000; j++ {
+ len := rand.Intn(100)
+ bytes := randomBytes(len, rand)
+ // This just looks for crashes due to bounds errors etc.
+ m.unmarshal(bytes)
+ }
+ }
+}
+
+func randomBytes(n int, rand *rand.Rand) []byte {
+ r := make([]byte, n)
+ if _, err := rand.Read(r); err != nil {
+ panic("rand.Read failed: " + err.Error())
+ }
+ return r
+}
+
+func randomString(n int, rand *rand.Rand) string {
+ b := randomBytes(n, rand)
+ return string(b)
+}
+
+func (*clientHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &clientHelloMsg{}
+ m.vers = uint16(rand.Intn(65536))
+ m.random = randomBytes(32, rand)
+ m.sessionId = randomBytes(rand.Intn(32), rand)
+ m.cipherSuites = make([]uint16, rand.Intn(63)+1)
+ for i := 0; i < len(m.cipherSuites); i++ {
+ cs := uint16(rand.Int31())
+ if cs == scsvRenegotiation {
+ cs += 1
+ }
+ m.cipherSuites[i] = cs
+ }
+ m.compressionMethods = randomBytes(rand.Intn(63)+1, rand)
+ if rand.Intn(10) > 5 {
+ m.serverName = randomString(rand.Intn(255), rand)
+ for strings.HasSuffix(m.serverName, ".") {
+ m.serverName = m.serverName[:len(m.serverName)-1]
+ }
+ }
+ m.ocspStapling = rand.Intn(10) > 5
+ m.supportedPoints = randomBytes(rand.Intn(5)+1, rand)
+ m.supportedCurves = make([]CurveID, rand.Intn(5)+1)
+ for i := range m.supportedCurves {
+ m.supportedCurves[i] = CurveID(rand.Intn(30000) + 1)
+ }
+ if rand.Intn(10) > 5 {
+ m.ticketSupported = true
+ if rand.Intn(10) > 5 {
+ m.sessionTicket = randomBytes(rand.Intn(300), rand)
+ } else {
+ m.sessionTicket = make([]byte, 0)
+ }
+ }
+ if rand.Intn(10) > 5 {
+ m.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
+ }
+ if rand.Intn(10) > 5 {
+ m.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithms()
+ }
+ for i := 0; i < rand.Intn(5); i++ {
+ m.alpnProtocols = append(m.alpnProtocols, randomString(rand.Intn(20)+1, rand))
+ }
+ if rand.Intn(10) > 5 {
+ m.scts = true
+ }
+ if rand.Intn(10) > 5 {
+ m.secureRenegotiationSupported = true
+ m.secureRenegotiation = randomBytes(rand.Intn(50)+1, rand)
+ }
+ for i := 0; i < rand.Intn(5); i++ {
+ m.supportedVersions = append(m.supportedVersions, uint16(rand.Intn(0xffff)+1))
+ }
+ if rand.Intn(10) > 5 {
+ m.cookie = randomBytes(rand.Intn(500)+1, rand)
+ }
+ for i := 0; i < rand.Intn(5); i++ {
+ var ks keyShare
+ ks.group = CurveID(rand.Intn(30000) + 1)
+ ks.data = randomBytes(rand.Intn(200)+1, rand)
+ m.keyShares = append(m.keyShares, ks)
+ }
+ switch rand.Intn(3) {
+ case 1:
+ m.pskModes = []uint8{pskModeDHE}
+ case 2:
+ m.pskModes = []uint8{pskModeDHE, pskModePlain}
+ }
+ for i := 0; i < rand.Intn(5); i++ {
+ var psk pskIdentity
+ psk.obfuscatedTicketAge = uint32(rand.Intn(500000))
+ psk.label = randomBytes(rand.Intn(500)+1, rand)
+ m.pskIdentities = append(m.pskIdentities, psk)
+ m.pskBinders = append(m.pskBinders, randomBytes(rand.Intn(50)+32, rand))
+ }
+ if rand.Intn(10) > 5 {
+ m.earlyData = true
+ }
+
+ return reflect.ValueOf(m)
+}
+
+func (*serverHelloMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &serverHelloMsg{}
+ m.vers = uint16(rand.Intn(65536))
+ m.random = randomBytes(32, rand)
+ m.sessionId = randomBytes(rand.Intn(32), rand)
+ m.cipherSuite = uint16(rand.Int31())
+ m.compressionMethod = uint8(rand.Intn(256))
+ m.supportedPoints = randomBytes(rand.Intn(5)+1, rand)
+
+ if rand.Intn(10) > 5 {
+ m.ocspStapling = true
+ }
+ if rand.Intn(10) > 5 {
+ m.ticketSupported = true
+ }
+ if rand.Intn(10) > 5 {
+ m.alpnProtocol = randomString(rand.Intn(32)+1, rand)
+ }
+
+ for i := 0; i < rand.Intn(4); i++ {
+ m.scts = append(m.scts, randomBytes(rand.Intn(500)+1, rand))
+ }
+
+ if rand.Intn(10) > 5 {
+ m.secureRenegotiationSupported = true
+ m.secureRenegotiation = randomBytes(rand.Intn(50)+1, rand)
+ }
+ if rand.Intn(10) > 5 {
+ m.supportedVersion = uint16(rand.Intn(0xffff) + 1)
+ }
+ if rand.Intn(10) > 5 {
+ m.cookie = randomBytes(rand.Intn(500)+1, rand)
+ }
+ if rand.Intn(10) > 5 {
+ for i := 0; i < rand.Intn(5); i++ {
+ m.serverShare.group = CurveID(rand.Intn(30000) + 1)
+ m.serverShare.data = randomBytes(rand.Intn(200)+1, rand)
+ }
+ } else if rand.Intn(10) > 5 {
+ m.selectedGroup = CurveID(rand.Intn(30000) + 1)
+ }
+ if rand.Intn(10) > 5 {
+ m.selectedIdentityPresent = true
+ m.selectedIdentity = uint16(rand.Intn(0xffff))
+ }
+
+ return reflect.ValueOf(m)
+}
+
+func (*encryptedExtensionsMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &encryptedExtensionsMsg{}
+
+ if rand.Intn(10) > 5 {
+ m.alpnProtocol = randomString(rand.Intn(32)+1, rand)
+ }
+
+ return reflect.ValueOf(m)
+}
+
+func (*certificateMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &certificateMsg{}
+ numCerts := rand.Intn(20)
+ m.certificates = make([][]byte, numCerts)
+ for i := 0; i < numCerts; i++ {
+ m.certificates[i] = randomBytes(rand.Intn(10)+1, rand)
+ }
+ return reflect.ValueOf(m)
+}
+
+func (*certificateRequestMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &certificateRequestMsg{}
+ m.certificateTypes = randomBytes(rand.Intn(5)+1, rand)
+ for i := 0; i < rand.Intn(100); i++ {
+ m.certificateAuthorities = append(m.certificateAuthorities, randomBytes(rand.Intn(15)+1, rand))
+ }
+ return reflect.ValueOf(m)
+}
+
+func (*certificateVerifyMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &certificateVerifyMsg{}
+ m.hasSignatureAlgorithm = true
+ m.signatureAlgorithm = SignatureScheme(rand.Intn(30000))
+ m.signature = randomBytes(rand.Intn(15)+1, rand)
+ return reflect.ValueOf(m)
+}
+
+func (*certificateStatusMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &certificateStatusMsg{}
+ m.response = randomBytes(rand.Intn(10)+1, rand)
+ return reflect.ValueOf(m)
+}
+
+func (*clientKeyExchangeMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &clientKeyExchangeMsg{}
+ m.ciphertext = randomBytes(rand.Intn(1000)+1, rand)
+ return reflect.ValueOf(m)
+}
+
+func (*finishedMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &finishedMsg{}
+ m.verifyData = randomBytes(12, rand)
+ return reflect.ValueOf(m)
+}
+
+func (*newSessionTicketMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &newSessionTicketMsg{}
+ m.ticket = randomBytes(rand.Intn(4), rand)
+ return reflect.ValueOf(m)
+}
+
+func (*sessionState) Generate(rand *rand.Rand, size int) reflect.Value {
+ s := &sessionState{}
+ s.vers = uint16(rand.Intn(10000))
+ s.cipherSuite = uint16(rand.Intn(10000))
+ s.masterSecret = randomBytes(rand.Intn(100)+1, rand)
+ s.createdAt = uint64(rand.Int63())
+ for i := 0; i < rand.Intn(20); i++ {
+ s.certificates = append(s.certificates, randomBytes(rand.Intn(500)+1, rand))
+ }
+ return reflect.ValueOf(s)
+}
+
+func (*sessionStateTLS13) Generate(rand *rand.Rand, size int) reflect.Value {
+ s := &sessionStateTLS13{}
+ s.cipherSuite = uint16(rand.Intn(10000))
+ s.resumptionSecret = randomBytes(rand.Intn(100)+1, rand)
+ s.createdAt = uint64(rand.Int63())
+ for i := 0; i < rand.Intn(2)+1; i++ {
+ s.certificate.Certificate = append(
+ s.certificate.Certificate, randomBytes(rand.Intn(500)+1, rand))
+ }
+ if rand.Intn(10) > 5 {
+ s.certificate.OCSPStaple = randomBytes(rand.Intn(100)+1, rand)
+ }
+ if rand.Intn(10) > 5 {
+ for i := 0; i < rand.Intn(2)+1; i++ {
+ s.certificate.SignedCertificateTimestamps = append(
+ s.certificate.SignedCertificateTimestamps, randomBytes(rand.Intn(500)+1, rand))
+ }
+ }
+ return reflect.ValueOf(s)
+}
+
+func (*endOfEarlyDataMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &endOfEarlyDataMsg{}
+ return reflect.ValueOf(m)
+}
+
+func (*keyUpdateMsg) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &keyUpdateMsg{}
+ m.updateRequested = rand.Intn(10) > 5
+ return reflect.ValueOf(m)
+}
+
+func (*newSessionTicketMsgTLS13) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &newSessionTicketMsgTLS13{}
+ m.lifetime = uint32(rand.Intn(500000))
+ m.ageAdd = uint32(rand.Intn(500000))
+ m.nonce = randomBytes(rand.Intn(100), rand)
+ m.label = randomBytes(rand.Intn(1000), rand)
+ if rand.Intn(10) > 5 {
+ m.maxEarlyData = uint32(rand.Intn(500000))
+ }
+ return reflect.ValueOf(m)
+}
+
+func (*certificateRequestMsgTLS13) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &certificateRequestMsgTLS13{}
+ if rand.Intn(10) > 5 {
+ m.ocspStapling = true
+ }
+ if rand.Intn(10) > 5 {
+ m.scts = true
+ }
+ if rand.Intn(10) > 5 {
+ m.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
+ }
+ if rand.Intn(10) > 5 {
+ m.supportedSignatureAlgorithmsCert = supportedSignatureAlgorithms()
+ }
+ if rand.Intn(10) > 5 {
+ m.certificateAuthorities = make([][]byte, 3)
+ for i := 0; i < 3; i++ {
+ m.certificateAuthorities[i] = randomBytes(rand.Intn(10)+1, rand)
+ }
+ }
+ return reflect.ValueOf(m)
+}
+
+func (*certificateMsgTLS13) Generate(rand *rand.Rand, size int) reflect.Value {
+ m := &certificateMsgTLS13{}
+ for i := 0; i < rand.Intn(2)+1; i++ {
+ m.certificate.Certificate = append(
+ m.certificate.Certificate, randomBytes(rand.Intn(500)+1, rand))
+ }
+ if rand.Intn(10) > 5 {
+ m.ocspStapling = true
+ m.certificate.OCSPStaple = randomBytes(rand.Intn(100)+1, rand)
+ }
+ if rand.Intn(10) > 5 {
+ m.scts = true
+ for i := 0; i < rand.Intn(2)+1; i++ {
+ m.certificate.SignedCertificateTimestamps = append(
+ m.certificate.SignedCertificateTimestamps, randomBytes(rand.Intn(500)+1, rand))
+ }
+ }
+ return reflect.ValueOf(m)
+}
+
+func TestRejectEmptySCTList(t *testing.T) {
+ // RFC 6962, Section 3.3.1 specifies that empty SCT lists are invalid.
+
+ var random [32]byte
+ sct := []byte{0x42, 0x42, 0x42, 0x42}
+ serverHello := &serverHelloMsg{
+ vers: VersionTLS12,
+ random: random[:],
+ scts: [][]byte{sct},
+ }
+ serverHelloBytes := mustMarshal(t, serverHello)
+
+ var serverHelloCopy serverHelloMsg
+ if !serverHelloCopy.unmarshal(serverHelloBytes) {
+ t.Fatal("Failed to unmarshal initial message")
+ }
+
+ // Change serverHelloBytes so that the SCT list is empty
+ i := bytes.Index(serverHelloBytes, sct)
+ if i < 0 {
+ t.Fatal("Cannot find SCT in ServerHello")
+ }
+
+ var serverHelloEmptySCT []byte
+ serverHelloEmptySCT = append(serverHelloEmptySCT, serverHelloBytes[:i-6]...)
+ // Append the extension length and SCT list length for an empty list.
+ serverHelloEmptySCT = append(serverHelloEmptySCT, []byte{0, 2, 0, 0}...)
+ serverHelloEmptySCT = append(serverHelloEmptySCT, serverHelloBytes[i+4:]...)
+
+ // Update the handshake message length.
+ serverHelloEmptySCT[1] = byte((len(serverHelloEmptySCT) - 4) >> 16)
+ serverHelloEmptySCT[2] = byte((len(serverHelloEmptySCT) - 4) >> 8)
+ serverHelloEmptySCT[3] = byte(len(serverHelloEmptySCT) - 4)
+
+ // Update the extensions length
+ serverHelloEmptySCT[42] = byte((len(serverHelloEmptySCT) - 44) >> 8)
+ serverHelloEmptySCT[43] = byte((len(serverHelloEmptySCT) - 44))
+
+ if serverHelloCopy.unmarshal(serverHelloEmptySCT) {
+ t.Fatal("Unmarshaled ServerHello with empty SCT list")
+ }
+}
+
+func TestRejectEmptySCT(t *testing.T) {
+ // Not only must the SCT list be non-empty, but the SCT elements must
+ // not be zero length.
+
+ var random [32]byte
+ serverHello := &serverHelloMsg{
+ vers: VersionTLS12,
+ random: random[:],
+ scts: [][]byte{nil},
+ }
+ serverHelloBytes := mustMarshal(t, serverHello)
+
+ var serverHelloCopy serverHelloMsg
+ if serverHelloCopy.unmarshal(serverHelloBytes) {
+ t.Fatal("Unmarshaled ServerHello with zero-length SCT")
+ }
+}
+
+func TestRejectDuplicateExtensions(t *testing.T) {
+ clientHelloBytes, err := hex.DecodeString("010000440303000000000000000000000000000000000000000000000000000000000000000000000000001c0000000a000800000568656c6c6f0000000a000800000568656c6c6f")
+ if err != nil {
+ t.Fatalf("failed to decode test ClientHello: %s", err)
+ }
+ var clientHelloCopy clientHelloMsg
+ if clientHelloCopy.unmarshal(clientHelloBytes) {
+ t.Error("Unmarshaled ClientHello with duplicate extensions")
+ }
+
+ serverHelloBytes, err := hex.DecodeString("02000030030300000000000000000000000000000000000000000000000000000000000000000000000000080005000000050000")
+ if err != nil {
+ t.Fatalf("failed to decode test ServerHello: %s", err)
+ }
+ var serverHelloCopy serverHelloMsg
+ if serverHelloCopy.unmarshal(serverHelloBytes) {
+ t.Fatal("Unmarshaled ServerHello with duplicate extensions")
+ }
+}
diff --git a/src/crypto/tls/handshake_server.go b/src/crypto/tls/handshake_server.go
new file mode 100644
index 0000000..b6a3c9c
--- /dev/null
+++ b/src/crypto/tls/handshake_server.go
@@ -0,0 +1,897 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "context"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/rsa"
+ "crypto/subtle"
+ "crypto/x509"
+ "errors"
+ "fmt"
+ "hash"
+ "io"
+ "time"
+)
+
+// serverHandshakeState contains details of a server handshake in progress.
+// It's discarded once the handshake has completed.
+type serverHandshakeState struct {
+ c *Conn
+ ctx context.Context
+ clientHello *clientHelloMsg
+ hello *serverHelloMsg
+ suite *cipherSuite
+ ecdheOk bool
+ ecSignOk bool
+ rsaDecryptOk bool
+ rsaSignOk bool
+ sessionState *sessionState
+ finishedHash finishedHash
+ masterSecret []byte
+ cert *Certificate
+}
+
+// serverHandshake performs a TLS handshake as a server.
+func (c *Conn) serverHandshake(ctx context.Context) error {
+ clientHello, err := c.readClientHello(ctx)
+ if err != nil {
+ return err
+ }
+
+ if c.vers == VersionTLS13 {
+ hs := serverHandshakeStateTLS13{
+ c: c,
+ ctx: ctx,
+ clientHello: clientHello,
+ }
+ return hs.handshake()
+ }
+
+ hs := serverHandshakeState{
+ c: c,
+ ctx: ctx,
+ clientHello: clientHello,
+ }
+ return hs.handshake()
+}
+
+func (hs *serverHandshakeState) handshake() error {
+ c := hs.c
+
+ if err := hs.processClientHello(); err != nil {
+ return err
+ }
+
+ // For an overview of TLS handshaking, see RFC 5246, Section 7.3.
+ c.buffering = true
+ if hs.checkForResumption() {
+ // The client has included a session ticket and so we do an abbreviated handshake.
+ c.didResume = true
+ if err := hs.doResumeHandshake(); err != nil {
+ return err
+ }
+ if err := hs.establishKeys(); err != nil {
+ return err
+ }
+ if err := hs.sendSessionTicket(); err != nil {
+ return err
+ }
+ if err := hs.sendFinished(c.serverFinished[:]); err != nil {
+ return err
+ }
+ if _, err := c.flush(); err != nil {
+ return err
+ }
+ c.clientFinishedIsFirst = false
+ if err := hs.readFinished(nil); err != nil {
+ return err
+ }
+ } else {
+ // The client didn't include a session ticket, or it wasn't
+ // valid so we do a full handshake.
+ if err := hs.pickCipherSuite(); err != nil {
+ return err
+ }
+ if err := hs.doFullHandshake(); err != nil {
+ return err
+ }
+ if err := hs.establishKeys(); err != nil {
+ return err
+ }
+ if err := hs.readFinished(c.clientFinished[:]); err != nil {
+ return err
+ }
+ c.clientFinishedIsFirst = true
+ c.buffering = true
+ if err := hs.sendSessionTicket(); err != nil {
+ return err
+ }
+ if err := hs.sendFinished(nil); err != nil {
+ return err
+ }
+ if _, err := c.flush(); err != nil {
+ return err
+ }
+ }
+
+ c.ekm = ekmFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random)
+ c.isHandshakeComplete.Store(true)
+
+ return nil
+}
+
+// readClientHello reads a ClientHello message and selects the protocol version.
+func (c *Conn) readClientHello(ctx context.Context) (*clientHelloMsg, error) {
+ // clientHelloMsg is included in the transcript, but we haven't initialized
+ // it yet. The respective handshake functions will record it themselves.
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return nil, err
+ }
+ clientHello, ok := msg.(*clientHelloMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return nil, unexpectedMessageError(clientHello, msg)
+ }
+
+ var configForClient *Config
+ originalConfig := c.config
+ if c.config.GetConfigForClient != nil {
+ chi := clientHelloInfo(ctx, c, clientHello)
+ if configForClient, err = c.config.GetConfigForClient(chi); err != nil {
+ c.sendAlert(alertInternalError)
+ return nil, err
+ } else if configForClient != nil {
+ c.config = configForClient
+ }
+ }
+ c.ticketKeys = originalConfig.ticketKeys(configForClient)
+
+ clientVersions := clientHello.supportedVersions
+ if len(clientHello.supportedVersions) == 0 {
+ clientVersions = supportedVersionsFromMax(clientHello.vers)
+ }
+ c.vers, ok = c.config.mutualVersion(roleServer, clientVersions)
+ if !ok {
+ c.sendAlert(alertProtocolVersion)
+ return nil, fmt.Errorf("tls: client offered only unsupported versions: %x", clientVersions)
+ }
+ c.haveVers = true
+ c.in.version = c.vers
+ c.out.version = c.vers
+
+ return clientHello, nil
+}
+
+func (hs *serverHandshakeState) processClientHello() error {
+ c := hs.c
+
+ hs.hello = new(serverHelloMsg)
+ hs.hello.vers = c.vers
+
+ foundCompression := false
+ // We only support null compression, so check that the client offered it.
+ for _, compression := range hs.clientHello.compressionMethods {
+ if compression == compressionNone {
+ foundCompression = true
+ break
+ }
+ }
+
+ if !foundCompression {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: client does not support uncompressed connections")
+ }
+
+ hs.hello.random = make([]byte, 32)
+ serverRandom := hs.hello.random
+ // Downgrade protection canaries. See RFC 8446, Section 4.1.3.
+ maxVers := c.config.maxSupportedVersion(roleServer)
+ if maxVers >= VersionTLS12 && c.vers < maxVers || testingOnlyForceDowngradeCanary {
+ if c.vers == VersionTLS12 {
+ copy(serverRandom[24:], downgradeCanaryTLS12)
+ } else {
+ copy(serverRandom[24:], downgradeCanaryTLS11)
+ }
+ serverRandom = serverRandom[:24]
+ }
+ _, err := io.ReadFull(c.config.rand(), serverRandom)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ if len(hs.clientHello.secureRenegotiation) != 0 {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: initial handshake had non-empty renegotiation extension")
+ }
+
+ hs.hello.secureRenegotiationSupported = hs.clientHello.secureRenegotiationSupported
+ hs.hello.compressionMethod = compressionNone
+ if len(hs.clientHello.serverName) > 0 {
+ c.serverName = hs.clientHello.serverName
+ }
+
+ selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols)
+ if err != nil {
+ c.sendAlert(alertNoApplicationProtocol)
+ return err
+ }
+ hs.hello.alpnProtocol = selectedProto
+ c.clientProtocol = selectedProto
+
+ hs.cert, err = c.config.getCertificate(clientHelloInfo(hs.ctx, c, hs.clientHello))
+ if err != nil {
+ if err == errNoCertificates {
+ c.sendAlert(alertUnrecognizedName)
+ } else {
+ c.sendAlert(alertInternalError)
+ }
+ return err
+ }
+ if hs.clientHello.scts {
+ hs.hello.scts = hs.cert.SignedCertificateTimestamps
+ }
+
+ hs.ecdheOk = supportsECDHE(c.config, hs.clientHello.supportedCurves, hs.clientHello.supportedPoints)
+
+ if hs.ecdheOk && len(hs.clientHello.supportedPoints) > 0 {
+ // Although omitting the ec_point_formats extension is permitted, some
+ // old OpenSSL version will refuse to handshake if not present.
+ //
+ // Per RFC 4492, section 5.1.2, implementations MUST support the
+ // uncompressed point format. See golang.org/issue/31943.
+ hs.hello.supportedPoints = []uint8{pointFormatUncompressed}
+ }
+
+ if priv, ok := hs.cert.PrivateKey.(crypto.Signer); ok {
+ switch priv.Public().(type) {
+ case *ecdsa.PublicKey:
+ hs.ecSignOk = true
+ case ed25519.PublicKey:
+ hs.ecSignOk = true
+ case *rsa.PublicKey:
+ hs.rsaSignOk = true
+ default:
+ c.sendAlert(alertInternalError)
+ return fmt.Errorf("tls: unsupported signing key type (%T)", priv.Public())
+ }
+ }
+ if priv, ok := hs.cert.PrivateKey.(crypto.Decrypter); ok {
+ switch priv.Public().(type) {
+ case *rsa.PublicKey:
+ hs.rsaDecryptOk = true
+ default:
+ c.sendAlert(alertInternalError)
+ return fmt.Errorf("tls: unsupported decryption key type (%T)", priv.Public())
+ }
+ }
+
+ return nil
+}
+
+// negotiateALPN picks a shared ALPN protocol that both sides support in server
+// preference order. If ALPN is not configured or the peer doesn't support it,
+// it returns "" and no error.
+func negotiateALPN(serverProtos, clientProtos []string) (string, error) {
+ if len(serverProtos) == 0 || len(clientProtos) == 0 {
+ return "", nil
+ }
+ var http11fallback bool
+ for _, s := range serverProtos {
+ for _, c := range clientProtos {
+ if s == c {
+ return s, nil
+ }
+ if s == "h2" && c == "http/1.1" {
+ http11fallback = true
+ }
+ }
+ }
+ // As a special case, let http/1.1 clients connect to h2 servers as if they
+ // didn't support ALPN. We used not to enforce protocol overlap, so over
+ // time a number of HTTP servers were configured with only "h2", but
+ // expected to accept connections from "http/1.1" clients. See Issue 46310.
+ if http11fallback {
+ return "", nil
+ }
+ return "", fmt.Errorf("tls: client requested unsupported application protocols (%s)", clientProtos)
+}
+
+// supportsECDHE returns whether ECDHE key exchanges can be used with this
+// pre-TLS 1.3 client.
+func supportsECDHE(c *Config, supportedCurves []CurveID, supportedPoints []uint8) bool {
+ supportsCurve := false
+ for _, curve := range supportedCurves {
+ if c.supportsCurve(curve) {
+ supportsCurve = true
+ break
+ }
+ }
+
+ supportsPointFormat := false
+ for _, pointFormat := range supportedPoints {
+ if pointFormat == pointFormatUncompressed {
+ supportsPointFormat = true
+ break
+ }
+ }
+ // Per RFC 8422, Section 5.1.2, if the Supported Point Formats extension is
+ // missing, uncompressed points are supported. If supportedPoints is empty,
+ // the extension must be missing, as an empty extension body is rejected by
+ // the parser. See https://go.dev/issue/49126.
+ if len(supportedPoints) == 0 {
+ supportsPointFormat = true
+ }
+
+ return supportsCurve && supportsPointFormat
+}
+
+func (hs *serverHandshakeState) pickCipherSuite() error {
+ c := hs.c
+
+ preferenceOrder := cipherSuitesPreferenceOrder
+ if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) {
+ preferenceOrder = cipherSuitesPreferenceOrderNoAES
+ }
+
+ configCipherSuites := c.config.cipherSuites()
+ preferenceList := make([]uint16, 0, len(configCipherSuites))
+ for _, suiteID := range preferenceOrder {
+ for _, id := range configCipherSuites {
+ if id == suiteID {
+ preferenceList = append(preferenceList, id)
+ break
+ }
+ }
+ }
+
+ hs.suite = selectCipherSuite(preferenceList, hs.clientHello.cipherSuites, hs.cipherSuiteOk)
+ if hs.suite == nil {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: no cipher suite supported by both client and server")
+ }
+ c.cipherSuite = hs.suite.id
+
+ for _, id := range hs.clientHello.cipherSuites {
+ if id == TLS_FALLBACK_SCSV {
+ // The client is doing a fallback connection. See RFC 7507.
+ if hs.clientHello.vers < c.config.maxSupportedVersion(roleServer) {
+ c.sendAlert(alertInappropriateFallback)
+ return errors.New("tls: client using inappropriate protocol fallback")
+ }
+ break
+ }
+ }
+
+ return nil
+}
+
+func (hs *serverHandshakeState) cipherSuiteOk(c *cipherSuite) bool {
+ if c.flags&suiteECDHE != 0 {
+ if !hs.ecdheOk {
+ return false
+ }
+ if c.flags&suiteECSign != 0 {
+ if !hs.ecSignOk {
+ return false
+ }
+ } else if !hs.rsaSignOk {
+ return false
+ }
+ } else if !hs.rsaDecryptOk {
+ return false
+ }
+ if hs.c.vers < VersionTLS12 && c.flags&suiteTLS12 != 0 {
+ return false
+ }
+ return true
+}
+
+// checkForResumption reports whether we should perform resumption on this connection.
+func (hs *serverHandshakeState) checkForResumption() bool {
+ c := hs.c
+
+ if c.config.SessionTicketsDisabled {
+ return false
+ }
+
+ plaintext, usedOldKey := c.decryptTicket(hs.clientHello.sessionTicket)
+ if plaintext == nil {
+ return false
+ }
+ hs.sessionState = &sessionState{usedOldKey: usedOldKey}
+ ok := hs.sessionState.unmarshal(plaintext)
+ if !ok {
+ return false
+ }
+
+ createdAt := time.Unix(int64(hs.sessionState.createdAt), 0)
+ if c.config.time().Sub(createdAt) > maxSessionTicketLifetime {
+ return false
+ }
+
+ // Never resume a session for a different TLS version.
+ if c.vers != hs.sessionState.vers {
+ return false
+ }
+
+ cipherSuiteOk := false
+ // Check that the client is still offering the ciphersuite in the session.
+ for _, id := range hs.clientHello.cipherSuites {
+ if id == hs.sessionState.cipherSuite {
+ cipherSuiteOk = true
+ break
+ }
+ }
+ if !cipherSuiteOk {
+ return false
+ }
+
+ // Check that we also support the ciphersuite from the session.
+ hs.suite = selectCipherSuite([]uint16{hs.sessionState.cipherSuite},
+ c.config.cipherSuites(), hs.cipherSuiteOk)
+ if hs.suite == nil {
+ return false
+ }
+
+ sessionHasClientCerts := len(hs.sessionState.certificates) != 0
+ needClientCerts := requiresClientCert(c.config.ClientAuth)
+ if needClientCerts && !sessionHasClientCerts {
+ return false
+ }
+ if sessionHasClientCerts && c.config.ClientAuth == NoClientCert {
+ return false
+ }
+
+ return true
+}
+
+func (hs *serverHandshakeState) doResumeHandshake() error {
+ c := hs.c
+
+ hs.hello.cipherSuite = hs.suite.id
+ c.cipherSuite = hs.suite.id
+ // We echo the client's session ID in the ServerHello to let it know
+ // that we're doing a resumption.
+ hs.hello.sessionId = hs.clientHello.sessionId
+ hs.hello.ticketSupported = hs.sessionState.usedOldKey
+ hs.finishedHash = newFinishedHash(c.vers, hs.suite)
+ hs.finishedHash.discardHandshakeBuffer()
+ if err := transcriptMsg(hs.clientHello, &hs.finishedHash); err != nil {
+ return err
+ }
+ if _, err := hs.c.writeHandshakeRecord(hs.hello, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ if err := c.processCertsFromClient(Certificate{
+ Certificate: hs.sessionState.certificates,
+ }); err != nil {
+ return err
+ }
+
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
+ hs.masterSecret = hs.sessionState.masterSecret
+
+ return nil
+}
+
+func (hs *serverHandshakeState) doFullHandshake() error {
+ c := hs.c
+
+ if hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0 {
+ hs.hello.ocspStapling = true
+ }
+
+ hs.hello.ticketSupported = hs.clientHello.ticketSupported && !c.config.SessionTicketsDisabled
+ hs.hello.cipherSuite = hs.suite.id
+
+ hs.finishedHash = newFinishedHash(hs.c.vers, hs.suite)
+ if c.config.ClientAuth == NoClientCert {
+ // No need to keep a full record of the handshake if client
+ // certificates won't be used.
+ hs.finishedHash.discardHandshakeBuffer()
+ }
+ if err := transcriptMsg(hs.clientHello, &hs.finishedHash); err != nil {
+ return err
+ }
+ if _, err := hs.c.writeHandshakeRecord(hs.hello, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ certMsg := new(certificateMsg)
+ certMsg.certificates = hs.cert.Certificate
+ if _, err := hs.c.writeHandshakeRecord(certMsg, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ if hs.hello.ocspStapling {
+ certStatus := new(certificateStatusMsg)
+ certStatus.response = hs.cert.OCSPStaple
+ if _, err := hs.c.writeHandshakeRecord(certStatus, &hs.finishedHash); err != nil {
+ return err
+ }
+ }
+
+ keyAgreement := hs.suite.ka(c.vers)
+ skx, err := keyAgreement.generateServerKeyExchange(c.config, hs.cert, hs.clientHello, hs.hello)
+ if err != nil {
+ c.sendAlert(alertHandshakeFailure)
+ return err
+ }
+ if skx != nil {
+ if _, err := hs.c.writeHandshakeRecord(skx, &hs.finishedHash); err != nil {
+ return err
+ }
+ }
+
+ var certReq *certificateRequestMsg
+ if c.config.ClientAuth >= RequestClientCert {
+ // Request a client certificate
+ certReq = new(certificateRequestMsg)
+ certReq.certificateTypes = []byte{
+ byte(certTypeRSASign),
+ byte(certTypeECDSASign),
+ }
+ if c.vers >= VersionTLS12 {
+ certReq.hasSignatureAlgorithm = true
+ certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
+ }
+
+ // An empty list of certificateAuthorities signals to
+ // the client that it may send any certificate in response
+ // to our request. When we know the CAs we trust, then
+ // we can send them down, so that the client can choose
+ // an appropriate certificate to give to us.
+ if c.config.ClientCAs != nil {
+ certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
+ }
+ if _, err := hs.c.writeHandshakeRecord(certReq, &hs.finishedHash); err != nil {
+ return err
+ }
+ }
+
+ helloDone := new(serverHelloDoneMsg)
+ if _, err := hs.c.writeHandshakeRecord(helloDone, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ if _, err := c.flush(); err != nil {
+ return err
+ }
+
+ var pub crypto.PublicKey // public key for client auth, if any
+
+ msg, err := c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+
+ // If we requested a client certificate, then the client must send a
+ // certificate message, even if it's empty.
+ if c.config.ClientAuth >= RequestClientCert {
+ certMsg, ok := msg.(*certificateMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
+ }
+
+ if err := c.processCertsFromClient(Certificate{
+ Certificate: certMsg.certificates,
+ }); err != nil {
+ return err
+ }
+ if len(certMsg.certificates) != 0 {
+ pub = c.peerCertificates[0].PublicKey
+ }
+
+ msg, err = c.readHandshake(&hs.finishedHash)
+ if err != nil {
+ return err
+ }
+ }
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
+ // Get client key exchange
+ ckx, ok := msg.(*clientKeyExchangeMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(ckx, msg)
+ }
+
+ preMasterSecret, err := keyAgreement.processClientKeyExchange(c.config, hs.cert, ckx, c.vers)
+ if err != nil {
+ c.sendAlert(alertHandshakeFailure)
+ return err
+ }
+ hs.masterSecret = masterFromPreMasterSecret(c.vers, hs.suite, preMasterSecret, hs.clientHello.random, hs.hello.random)
+ if err := c.config.writeKeyLog(keyLogLabelTLS12, hs.clientHello.random, hs.masterSecret); err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ // If we received a client cert in response to our certificate request message,
+ // the client will send us a certificateVerifyMsg immediately after the
+ // clientKeyExchangeMsg. This message is a digest of all preceding
+ // handshake-layer messages that is signed using the private key corresponding
+ // to the client's certificate. This allows us to verify that the client is in
+ // possession of the private key of the certificate.
+ if len(c.peerCertificates) > 0 {
+ // certificateVerifyMsg is included in the transcript, but not until
+ // after we verify the handshake signature, since the state before
+ // this message was sent is used.
+ msg, err = c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+ certVerify, ok := msg.(*certificateVerifyMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certVerify, msg)
+ }
+
+ var sigType uint8
+ var sigHash crypto.Hash
+ if c.vers >= VersionTLS12 {
+ if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, certReq.supportedSignatureAlgorithms) {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: client certificate used with invalid signature algorithm")
+ }
+ sigType, sigHash, err = typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
+ if err != nil {
+ return c.sendAlert(alertInternalError)
+ }
+ } else {
+ sigType, sigHash, err = legacyTypeAndHashFromPublicKey(pub)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return err
+ }
+ }
+
+ signed := hs.finishedHash.hashForClientCertificate(sigType, sigHash)
+ if err := verifyHandshakeSignature(sigType, pub, sigHash, signed, certVerify.signature); err != nil {
+ c.sendAlert(alertDecryptError)
+ return errors.New("tls: invalid signature by the client certificate: " + err.Error())
+ }
+
+ if err := transcriptMsg(certVerify, &hs.finishedHash); err != nil {
+ return err
+ }
+ }
+
+ hs.finishedHash.discardHandshakeBuffer()
+
+ return nil
+}
+
+func (hs *serverHandshakeState) establishKeys() error {
+ c := hs.c
+
+ clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV :=
+ keysFromMasterSecret(c.vers, hs.suite, hs.masterSecret, hs.clientHello.random, hs.hello.random, hs.suite.macLen, hs.suite.keyLen, hs.suite.ivLen)
+
+ var clientCipher, serverCipher any
+ var clientHash, serverHash hash.Hash
+
+ if hs.suite.aead == nil {
+ clientCipher = hs.suite.cipher(clientKey, clientIV, true /* for reading */)
+ clientHash = hs.suite.mac(clientMAC)
+ serverCipher = hs.suite.cipher(serverKey, serverIV, false /* not for reading */)
+ serverHash = hs.suite.mac(serverMAC)
+ } else {
+ clientCipher = hs.suite.aead(clientKey, clientIV)
+ serverCipher = hs.suite.aead(serverKey, serverIV)
+ }
+
+ c.in.prepareCipherSpec(c.vers, clientCipher, clientHash)
+ c.out.prepareCipherSpec(c.vers, serverCipher, serverHash)
+
+ return nil
+}
+
+func (hs *serverHandshakeState) readFinished(out []byte) error {
+ c := hs.c
+
+ if err := c.readChangeCipherSpec(); err != nil {
+ return err
+ }
+
+ // finishedMsg is included in the transcript, but not until after we
+ // check the client version, since the state before this message was
+ // sent is used during verification.
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+ clientFinished, ok := msg.(*finishedMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(clientFinished, msg)
+ }
+
+ verify := hs.finishedHash.clientSum(hs.masterSecret)
+ if len(verify) != len(clientFinished.verifyData) ||
+ subtle.ConstantTimeCompare(verify, clientFinished.verifyData) != 1 {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: client's Finished message is incorrect")
+ }
+
+ if err := transcriptMsg(clientFinished, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ copy(out, verify)
+ return nil
+}
+
+func (hs *serverHandshakeState) sendSessionTicket() error {
+ // ticketSupported is set in a resumption handshake if the
+ // ticket from the client was encrypted with an old session
+ // ticket key and thus a refreshed ticket should be sent.
+ if !hs.hello.ticketSupported {
+ return nil
+ }
+
+ c := hs.c
+ m := new(newSessionTicketMsg)
+
+ createdAt := uint64(c.config.time().Unix())
+ if hs.sessionState != nil {
+ // If this is re-wrapping an old key, then keep
+ // the original time it was created.
+ createdAt = hs.sessionState.createdAt
+ }
+
+ var certsFromClient [][]byte
+ for _, cert := range c.peerCertificates {
+ certsFromClient = append(certsFromClient, cert.Raw)
+ }
+ state := sessionState{
+ vers: c.vers,
+ cipherSuite: hs.suite.id,
+ createdAt: createdAt,
+ masterSecret: hs.masterSecret,
+ certificates: certsFromClient,
+ }
+ stateBytes, err := state.marshal()
+ if err != nil {
+ return err
+ }
+ m.ticket, err = c.encryptTicket(stateBytes)
+ if err != nil {
+ return err
+ }
+
+ if _, err := hs.c.writeHandshakeRecord(m, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (hs *serverHandshakeState) sendFinished(out []byte) error {
+ c := hs.c
+
+ if err := c.writeChangeCipherRecord(); err != nil {
+ return err
+ }
+
+ finished := new(finishedMsg)
+ finished.verifyData = hs.finishedHash.serverSum(hs.masterSecret)
+ if _, err := hs.c.writeHandshakeRecord(finished, &hs.finishedHash); err != nil {
+ return err
+ }
+
+ copy(out, finished.verifyData)
+
+ return nil
+}
+
+// processCertsFromClient takes a chain of client certificates either from a
+// Certificates message or from a sessionState and verifies them. It returns
+// the public key of the leaf certificate.
+func (c *Conn) processCertsFromClient(certificate Certificate) error {
+ certificates := certificate.Certificate
+ certs := make([]*x509.Certificate, len(certificates))
+ var err error
+ for i, asn1Data := range certificates {
+ if certs[i], err = x509.ParseCertificate(asn1Data); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return errors.New("tls: failed to parse client certificate: " + err.Error())
+ }
+ if certs[i].PublicKeyAlgorithm == x509.RSA {
+ n := certs[i].PublicKey.(*rsa.PublicKey).N.BitLen()
+ if max, ok := checkKeySize(n); !ok {
+ c.sendAlert(alertBadCertificate)
+ return fmt.Errorf("tls: client sent certificate containing RSA key larger than %d bits", max)
+ }
+ }
+ }
+
+ if len(certs) == 0 && requiresClientCert(c.config.ClientAuth) {
+ c.sendAlert(alertBadCertificate)
+ return errors.New("tls: client didn't provide a certificate")
+ }
+
+ if c.config.ClientAuth >= VerifyClientCertIfGiven && len(certs) > 0 {
+ opts := x509.VerifyOptions{
+ Roots: c.config.ClientCAs,
+ CurrentTime: c.config.time(),
+ Intermediates: x509.NewCertPool(),
+ KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
+ }
+
+ for _, cert := range certs[1:] {
+ opts.Intermediates.AddCert(cert)
+ }
+
+ chains, err := certs[0].Verify(opts)
+ if err != nil {
+ c.sendAlert(alertBadCertificate)
+ return &CertificateVerificationError{UnverifiedCertificates: certs, Err: err}
+ }
+
+ c.verifiedChains = chains
+ }
+
+ c.peerCertificates = certs
+ c.ocspResponse = certificate.OCSPStaple
+ c.scts = certificate.SignedCertificateTimestamps
+
+ if len(certs) > 0 {
+ switch certs[0].PublicKey.(type) {
+ case *ecdsa.PublicKey, *rsa.PublicKey, ed25519.PublicKey:
+ default:
+ c.sendAlert(alertUnsupportedCertificate)
+ return fmt.Errorf("tls: client certificate contains an unsupported public key of type %T", certs[0].PublicKey)
+ }
+ }
+
+ if c.config.VerifyPeerCertificate != nil {
+ if err := c.config.VerifyPeerCertificate(certificates, c.verifiedChains); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
+ return nil
+}
+
+func clientHelloInfo(ctx context.Context, c *Conn, clientHello *clientHelloMsg) *ClientHelloInfo {
+ supportedVersions := clientHello.supportedVersions
+ if len(clientHello.supportedVersions) == 0 {
+ supportedVersions = supportedVersionsFromMax(clientHello.vers)
+ }
+
+ return &ClientHelloInfo{
+ CipherSuites: clientHello.cipherSuites,
+ ServerName: clientHello.serverName,
+ SupportedCurves: clientHello.supportedCurves,
+ SupportedPoints: clientHello.supportedPoints,
+ SignatureSchemes: clientHello.supportedSignatureAlgorithms,
+ SupportedProtos: clientHello.alpnProtocols,
+ SupportedVersions: supportedVersions,
+ Conn: c.conn,
+ config: c.config,
+ ctx: ctx,
+ }
+}
diff --git a/src/crypto/tls/handshake_server_test.go b/src/crypto/tls/handshake_server_test.go
new file mode 100644
index 0000000..04abdcc
--- /dev/null
+++ b/src/crypto/tls/handshake_server_test.go
@@ -0,0 +1,2047 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "bytes"
+ "context"
+ "crypto"
+ "crypto/ecdh"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/x509"
+ "encoding/pem"
+ "errors"
+ "fmt"
+ "io"
+ "net"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "runtime"
+ "strings"
+ "testing"
+ "time"
+)
+
+func testClientHello(t *testing.T, serverConfig *Config, m handshakeMessage) {
+ testClientHelloFailure(t, serverConfig, m, "")
+}
+
+// testFatal is a hack to prevent the compiler from complaining that there is a
+// call to t.Fatal from a non-test goroutine
+func testFatal(t *testing.T, err error) {
+ t.Helper()
+ t.Fatal(err)
+}
+
+func testClientHelloFailure(t *testing.T, serverConfig *Config, m handshakeMessage, expectedSubStr string) {
+ c, s := localPipe(t)
+ go func() {
+ cli := Client(c, testConfig)
+ if ch, ok := m.(*clientHelloMsg); ok {
+ cli.vers = ch.vers
+ }
+ if _, err := cli.writeHandshakeRecord(m, nil); err != nil {
+ testFatal(t, err)
+ }
+ c.Close()
+ }()
+ ctx := context.Background()
+ conn := Server(s, serverConfig)
+ ch, err := conn.readClientHello(ctx)
+ hs := serverHandshakeState{
+ c: conn,
+ ctx: ctx,
+ clientHello: ch,
+ }
+ if err == nil {
+ err = hs.processClientHello()
+ }
+ if err == nil {
+ err = hs.pickCipherSuite()
+ }
+ s.Close()
+ if len(expectedSubStr) == 0 {
+ if err != nil && err != io.EOF {
+ t.Errorf("Got error: %s; expected to succeed", err)
+ }
+ } else if err == nil || !strings.Contains(err.Error(), expectedSubStr) {
+ t.Errorf("Got error: %v; expected to match substring '%s'", err, expectedSubStr)
+ }
+}
+
+func TestSimpleError(t *testing.T) {
+ testClientHelloFailure(t, testConfig, &serverHelloDoneMsg{}, "unexpected handshake message")
+}
+
+var badProtocolVersions = []uint16{0x0000, 0x0005, 0x0100, 0x0105, 0x0200, 0x0205, VersionSSL30}
+
+func TestRejectBadProtocolVersion(t *testing.T) {
+ config := testConfig.Clone()
+ config.MinVersion = VersionSSL30
+ for _, v := range badProtocolVersions {
+ testClientHelloFailure(t, config, &clientHelloMsg{
+ vers: v,
+ random: make([]byte, 32),
+ }, "unsupported versions")
+ }
+ testClientHelloFailure(t, config, &clientHelloMsg{
+ vers: VersionTLS12,
+ supportedVersions: badProtocolVersions,
+ random: make([]byte, 32),
+ }, "unsupported versions")
+}
+
+func TestNoSuiteOverlap(t *testing.T) {
+ clientHello := &clientHelloMsg{
+ vers: VersionTLS10,
+ random: make([]byte, 32),
+ cipherSuites: []uint16{0xff00},
+ compressionMethods: []uint8{compressionNone},
+ }
+ testClientHelloFailure(t, testConfig, clientHello, "no cipher suite supported by both client and server")
+}
+
+func TestNoCompressionOverlap(t *testing.T) {
+ clientHello := &clientHelloMsg{
+ vers: VersionTLS10,
+ random: make([]byte, 32),
+ cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ compressionMethods: []uint8{0xff},
+ }
+ testClientHelloFailure(t, testConfig, clientHello, "client does not support uncompressed connections")
+}
+
+func TestNoRC4ByDefault(t *testing.T) {
+ clientHello := &clientHelloMsg{
+ vers: VersionTLS10,
+ random: make([]byte, 32),
+ cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ compressionMethods: []uint8{compressionNone},
+ }
+ serverConfig := testConfig.Clone()
+ // Reset the enabled cipher suites to nil in order to test the
+ // defaults.
+ serverConfig.CipherSuites = nil
+ testClientHelloFailure(t, serverConfig, clientHello, "no cipher suite supported by both client and server")
+}
+
+func TestRejectSNIWithTrailingDot(t *testing.T) {
+ testClientHelloFailure(t, testConfig, &clientHelloMsg{
+ vers: VersionTLS12,
+ random: make([]byte, 32),
+ serverName: "foo.com.",
+ }, "unexpected message")
+}
+
+func TestDontSelectECDSAWithRSAKey(t *testing.T) {
+ // Test that, even when both sides support an ECDSA cipher suite, it
+ // won't be selected if the server's private key doesn't support it.
+ clientHello := &clientHelloMsg{
+ vers: VersionTLS10,
+ random: make([]byte, 32),
+ cipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA},
+ compressionMethods: []uint8{compressionNone},
+ supportedCurves: []CurveID{CurveP256},
+ supportedPoints: []uint8{pointFormatUncompressed},
+ }
+ serverConfig := testConfig.Clone()
+ serverConfig.CipherSuites = clientHello.cipherSuites
+ serverConfig.Certificates = make([]Certificate, 1)
+ serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+ serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
+ serverConfig.BuildNameToCertificate()
+ // First test that it *does* work when the server's key is ECDSA.
+ testClientHello(t, serverConfig, clientHello)
+
+ // Now test that switching to an RSA key causes the expected error (and
+ // not an internal error about a signing failure).
+ serverConfig.Certificates = testConfig.Certificates
+ testClientHelloFailure(t, serverConfig, clientHello, "no cipher suite supported by both client and server")
+}
+
+func TestDontSelectRSAWithECDSAKey(t *testing.T) {
+ // Test that, even when both sides support an RSA cipher suite, it
+ // won't be selected if the server's private key doesn't support it.
+ clientHello := &clientHelloMsg{
+ vers: VersionTLS10,
+ random: make([]byte, 32),
+ cipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA},
+ compressionMethods: []uint8{compressionNone},
+ supportedCurves: []CurveID{CurveP256},
+ supportedPoints: []uint8{pointFormatUncompressed},
+ }
+ serverConfig := testConfig.Clone()
+ serverConfig.CipherSuites = clientHello.cipherSuites
+ // First test that it *does* work when the server's key is RSA.
+ testClientHello(t, serverConfig, clientHello)
+
+ // Now test that switching to an ECDSA key causes the expected error
+ // (and not an internal error about a signing failure).
+ serverConfig.Certificates = make([]Certificate, 1)
+ serverConfig.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+ serverConfig.Certificates[0].PrivateKey = testECDSAPrivateKey
+ serverConfig.BuildNameToCertificate()
+ testClientHelloFailure(t, serverConfig, clientHello, "no cipher suite supported by both client and server")
+}
+
+func TestRenegotiationExtension(t *testing.T) {
+ clientHello := &clientHelloMsg{
+ vers: VersionTLS12,
+ compressionMethods: []uint8{compressionNone},
+ random: make([]byte, 32),
+ secureRenegotiationSupported: true,
+ cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ }
+
+ bufChan := make(chan []byte, 1)
+ c, s := localPipe(t)
+
+ go func() {
+ cli := Client(c, testConfig)
+ cli.vers = clientHello.vers
+ if _, err := cli.writeHandshakeRecord(clientHello, nil); err != nil {
+ testFatal(t, err)
+ }
+
+ buf := make([]byte, 1024)
+ n, err := c.Read(buf)
+ if err != nil {
+ t.Errorf("Server read returned error: %s", err)
+ return
+ }
+ c.Close()
+ bufChan <- buf[:n]
+ }()
+
+ Server(s, testConfig).Handshake()
+ buf := <-bufChan
+
+ if len(buf) < 5+4 {
+ t.Fatalf("Server returned short message of length %d", len(buf))
+ }
+ // buf contains a TLS record, with a 5 byte record header and a 4 byte
+ // handshake header. The length of the ServerHello is taken from the
+ // handshake header.
+ serverHelloLen := int(buf[6])<<16 | int(buf[7])<<8 | int(buf[8])
+
+ var serverHello serverHelloMsg
+ // unmarshal expects to be given the handshake header, but
+ // serverHelloLen doesn't include it.
+ if !serverHello.unmarshal(buf[5 : 9+serverHelloLen]) {
+ t.Fatalf("Failed to parse ServerHello")
+ }
+
+ if !serverHello.secureRenegotiationSupported {
+ t.Errorf("Secure renegotiation extension was not echoed.")
+ }
+}
+
+func TestTLS12OnlyCipherSuites(t *testing.T) {
+ // Test that a Server doesn't select a TLS 1.2-only cipher suite when
+ // the client negotiates TLS 1.1.
+ clientHello := &clientHelloMsg{
+ vers: VersionTLS11,
+ random: make([]byte, 32),
+ cipherSuites: []uint16{
+ // The Server, by default, will use the client's
+ // preference order. So the GCM cipher suite
+ // will be selected unless it's excluded because
+ // of the version in this ClientHello.
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_RC4_128_SHA,
+ },
+ compressionMethods: []uint8{compressionNone},
+ supportedCurves: []CurveID{CurveP256, CurveP384, CurveP521},
+ supportedPoints: []uint8{pointFormatUncompressed},
+ }
+
+ c, s := localPipe(t)
+ replyChan := make(chan any)
+ go func() {
+ cli := Client(c, testConfig)
+ cli.vers = clientHello.vers
+ if _, err := cli.writeHandshakeRecord(clientHello, nil); err != nil {
+ testFatal(t, err)
+ }
+ reply, err := cli.readHandshake(nil)
+ c.Close()
+ if err != nil {
+ replyChan <- err
+ } else {
+ replyChan <- reply
+ }
+ }()
+ config := testConfig.Clone()
+ config.CipherSuites = clientHello.cipherSuites
+ Server(s, config).Handshake()
+ s.Close()
+ reply := <-replyChan
+ if err, ok := reply.(error); ok {
+ t.Fatal(err)
+ }
+ serverHello, ok := reply.(*serverHelloMsg)
+ if !ok {
+ t.Fatalf("didn't get ServerHello message in reply. Got %v\n", reply)
+ }
+ if s := serverHello.cipherSuite; s != TLS_RSA_WITH_RC4_128_SHA {
+ t.Fatalf("bad cipher suite from server: %x", s)
+ }
+}
+
+func TestTLSPointFormats(t *testing.T) {
+ // Test that a Server returns the ec_point_format extension when ECC is
+ // negotiated, and not on a RSA handshake or if ec_point_format is missing.
+ tests := []struct {
+ name string
+ cipherSuites []uint16
+ supportedCurves []CurveID
+ supportedPoints []uint8
+ wantSupportedPoints bool
+ }{
+ {"ECC", []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, []CurveID{CurveP256}, []uint8{pointFormatUncompressed}, true},
+ {"ECC without ec_point_format", []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, []CurveID{CurveP256}, nil, false},
+ {"ECC with extra values", []uint16{TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA}, []CurveID{CurveP256}, []uint8{13, 37, pointFormatUncompressed, 42}, true},
+ {"RSA", []uint16{TLS_RSA_WITH_AES_256_GCM_SHA384}, nil, nil, false},
+ {"RSA with ec_point_format", []uint16{TLS_RSA_WITH_AES_256_GCM_SHA384}, nil, []uint8{pointFormatUncompressed}, false},
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ clientHello := &clientHelloMsg{
+ vers: VersionTLS12,
+ random: make([]byte, 32),
+ cipherSuites: tt.cipherSuites,
+ compressionMethods: []uint8{compressionNone},
+ supportedCurves: tt.supportedCurves,
+ supportedPoints: tt.supportedPoints,
+ }
+
+ c, s := localPipe(t)
+ replyChan := make(chan any)
+ go func() {
+ cli := Client(c, testConfig)
+ cli.vers = clientHello.vers
+ if _, err := cli.writeHandshakeRecord(clientHello, nil); err != nil {
+ testFatal(t, err)
+ }
+ reply, err := cli.readHandshake(nil)
+ c.Close()
+ if err != nil {
+ replyChan <- err
+ } else {
+ replyChan <- reply
+ }
+ }()
+ config := testConfig.Clone()
+ config.CipherSuites = clientHello.cipherSuites
+ Server(s, config).Handshake()
+ s.Close()
+ reply := <-replyChan
+ if err, ok := reply.(error); ok {
+ t.Fatal(err)
+ }
+ serverHello, ok := reply.(*serverHelloMsg)
+ if !ok {
+ t.Fatalf("didn't get ServerHello message in reply. Got %v\n", reply)
+ }
+ if tt.wantSupportedPoints {
+ if !bytes.Equal(serverHello.supportedPoints, []uint8{pointFormatUncompressed}) {
+ t.Fatal("incorrect ec_point_format extension from server")
+ }
+ } else {
+ if len(serverHello.supportedPoints) != 0 {
+ t.Fatalf("unexpected ec_point_format extension from server: %v", serverHello.supportedPoints)
+ }
+ }
+ })
+ }
+}
+
+func TestAlertForwarding(t *testing.T) {
+ c, s := localPipe(t)
+ go func() {
+ Client(c, testConfig).sendAlert(alertUnknownCA)
+ c.Close()
+ }()
+
+ err := Server(s, testConfig).Handshake()
+ s.Close()
+ var opErr *net.OpError
+ if !errors.As(err, &opErr) || opErr.Err != error(alertUnknownCA) {
+ t.Errorf("Got error: %s; expected: %s", err, error(alertUnknownCA))
+ }
+}
+
+func TestClose(t *testing.T) {
+ c, s := localPipe(t)
+ go c.Close()
+
+ err := Server(s, testConfig).Handshake()
+ s.Close()
+ if err != io.EOF {
+ t.Errorf("Got error: %s; expected: %s", err, io.EOF)
+ }
+}
+
+func TestVersion(t *testing.T) {
+ serverConfig := &Config{
+ Certificates: testConfig.Certificates,
+ MaxVersion: VersionTLS11,
+ }
+ clientConfig := &Config{
+ InsecureSkipVerify: true,
+ MinVersion: VersionTLS10,
+ }
+ state, _, err := testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ if state.Version != VersionTLS11 {
+ t.Fatalf("incorrect version %x, should be %x", state.Version, VersionTLS11)
+ }
+
+ clientConfig.MinVersion = 0
+ _, _, err = testHandshake(t, clientConfig, serverConfig)
+ if err == nil {
+ t.Fatalf("expected failure to connect with TLS 1.0/1.1")
+ }
+}
+
+func TestCipherSuitePreference(t *testing.T) {
+ serverConfig := &Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA, TLS_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
+ Certificates: testConfig.Certificates,
+ MaxVersion: VersionTLS12,
+ GetConfigForClient: func(chi *ClientHelloInfo) (*Config, error) {
+ if chi.CipherSuites[0] != TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 {
+ t.Error("the advertised order should not depend on Config.CipherSuites")
+ }
+ if len(chi.CipherSuites) != 2+len(defaultCipherSuitesTLS13) {
+ t.Error("the advertised TLS 1.2 suites should be filtered by Config.CipherSuites")
+ }
+ return nil, nil
+ },
+ }
+ clientConfig := &Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256},
+ InsecureSkipVerify: true,
+ }
+ state, _, err := testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ if state.CipherSuite != TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305_SHA256 {
+ t.Error("the preference order should not depend on Config.CipherSuites")
+ }
+}
+
+func TestSCTHandshake(t *testing.T) {
+ t.Run("TLSv12", func(t *testing.T) { testSCTHandshake(t, VersionTLS12) })
+ t.Run("TLSv13", func(t *testing.T) { testSCTHandshake(t, VersionTLS13) })
+}
+
+func testSCTHandshake(t *testing.T, version uint16) {
+ expected := [][]byte{[]byte("certificate"), []byte("transparency")}
+ serverConfig := &Config{
+ Certificates: []Certificate{{
+ Certificate: [][]byte{testRSACertificate},
+ PrivateKey: testRSAPrivateKey,
+ SignedCertificateTimestamps: expected,
+ }},
+ MaxVersion: version,
+ }
+ clientConfig := &Config{
+ InsecureSkipVerify: true,
+ }
+ _, state, err := testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ actual := state.SignedCertificateTimestamps
+ if len(actual) != len(expected) {
+ t.Fatalf("got %d scts, want %d", len(actual), len(expected))
+ }
+ for i, sct := range expected {
+ if !bytes.Equal(sct, actual[i]) {
+ t.Fatalf("SCT #%d was %x, but expected %x", i, actual[i], sct)
+ }
+ }
+}
+
+func TestCrossVersionResume(t *testing.T) {
+ t.Run("TLSv12", func(t *testing.T) { testCrossVersionResume(t, VersionTLS12) })
+ t.Run("TLSv13", func(t *testing.T) { testCrossVersionResume(t, VersionTLS13) })
+}
+
+func testCrossVersionResume(t *testing.T, version uint16) {
+ serverConfig := &Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
+ Certificates: testConfig.Certificates,
+ }
+ clientConfig := &Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_CBC_SHA},
+ InsecureSkipVerify: true,
+ ClientSessionCache: NewLRUClientSessionCache(1),
+ ServerName: "servername",
+ MinVersion: VersionTLS10,
+ }
+
+ // Establish a session at TLS 1.1.
+ clientConfig.MaxVersion = VersionTLS11
+ _, _, err := testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+
+ // The client session cache now contains a TLS 1.1 session.
+ state, _, err := testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ if !state.DidResume {
+ t.Fatalf("handshake did not resume at the same version")
+ }
+
+ // Test that the server will decline to resume at a lower version.
+ clientConfig.MaxVersion = VersionTLS10
+ state, _, err = testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ if state.DidResume {
+ t.Fatalf("handshake resumed at a lower version")
+ }
+
+ // The client session cache now contains a TLS 1.0 session.
+ state, _, err = testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ if !state.DidResume {
+ t.Fatalf("handshake did not resume at the same version")
+ }
+
+ // Test that the server will decline to resume at a higher version.
+ clientConfig.MaxVersion = VersionTLS11
+ state, _, err = testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatalf("handshake failed: %s", err)
+ }
+ if state.DidResume {
+ t.Fatalf("handshake resumed at a higher version")
+ }
+}
+
+// Note: see comment in handshake_test.go for details of how the reference
+// tests work.
+
+// serverTest represents a test of the TLS server handshake against a reference
+// implementation.
+type serverTest struct {
+ // name is a freeform string identifying the test and the file in which
+ // the expected results will be stored.
+ name string
+ // command, if not empty, contains a series of arguments for the
+ // command to run for the reference server.
+ command []string
+ // expectedPeerCerts contains a list of PEM blocks of expected
+ // certificates from the client.
+ expectedPeerCerts []string
+ // config, if not nil, contains a custom Config to use for this test.
+ config *Config
+ // expectHandshakeErrorIncluding, when not empty, contains a string
+ // that must be a substring of the error resulting from the handshake.
+ expectHandshakeErrorIncluding string
+ // validate, if not nil, is a function that will be called with the
+ // ConnectionState of the resulting connection. It returns false if the
+ // ConnectionState is unacceptable.
+ validate func(ConnectionState) error
+ // wait, if true, prevents this subtest from calling t.Parallel.
+ // If false, runServerTest* returns immediately.
+ wait bool
+}
+
+var defaultClientCommand = []string{"openssl", "s_client", "-no_ticket"}
+
+// connFromCommand starts opens a listening socket and starts the reference
+// client to connect to it. It returns a recordingConn that wraps the resulting
+// connection.
+func (test *serverTest) connFromCommand() (conn *recordingConn, child *exec.Cmd, err error) {
+ l, err := net.ListenTCP("tcp", &net.TCPAddr{
+ IP: net.IPv4(127, 0, 0, 1),
+ Port: 0,
+ })
+ if err != nil {
+ return nil, nil, err
+ }
+ defer l.Close()
+
+ port := l.Addr().(*net.TCPAddr).Port
+
+ var command []string
+ command = append(command, test.command...)
+ if len(command) == 0 {
+ command = defaultClientCommand
+ }
+ command = append(command, "-connect")
+ command = append(command, fmt.Sprintf("127.0.0.1:%d", port))
+ cmd := exec.Command(command[0], command[1:]...)
+ cmd.Stdin = nil
+ var output bytes.Buffer
+ cmd.Stdout = &output
+ cmd.Stderr = &output
+ if err := cmd.Start(); err != nil {
+ return nil, nil, err
+ }
+
+ connChan := make(chan any, 1)
+ go func() {
+ tcpConn, err := l.Accept()
+ if err != nil {
+ connChan <- err
+ return
+ }
+ connChan <- tcpConn
+ }()
+
+ var tcpConn net.Conn
+ select {
+ case connOrError := <-connChan:
+ if err, ok := connOrError.(error); ok {
+ return nil, nil, err
+ }
+ tcpConn = connOrError.(net.Conn)
+ case <-time.After(2 * time.Second):
+ return nil, nil, errors.New("timed out waiting for connection from child process")
+ }
+
+ record := &recordingConn{
+ Conn: tcpConn,
+ }
+
+ return record, cmd, nil
+}
+
+func (test *serverTest) dataPath() string {
+ return filepath.Join("testdata", "Server-"+test.name)
+}
+
+func (test *serverTest) loadData() (flows [][]byte, err error) {
+ in, err := os.Open(test.dataPath())
+ if err != nil {
+ return nil, err
+ }
+ defer in.Close()
+ return parseTestData(in)
+}
+
+func (test *serverTest) run(t *testing.T, write bool) {
+ var clientConn, serverConn net.Conn
+ var recordingConn *recordingConn
+ var childProcess *exec.Cmd
+
+ if write {
+ var err error
+ recordingConn, childProcess, err = test.connFromCommand()
+ if err != nil {
+ t.Fatalf("Failed to start subcommand: %s", err)
+ }
+ serverConn = recordingConn
+ defer func() {
+ if t.Failed() {
+ t.Logf("OpenSSL output:\n\n%s", childProcess.Stdout)
+ }
+ }()
+ } else {
+ clientConn, serverConn = localPipe(t)
+ }
+ config := test.config
+ if config == nil {
+ config = testConfig
+ }
+ server := Server(serverConn, config)
+ connStateChan := make(chan ConnectionState, 1)
+ go func() {
+ _, err := server.Write([]byte("hello, world\n"))
+ if len(test.expectHandshakeErrorIncluding) > 0 {
+ if err == nil {
+ t.Errorf("Error expected, but no error returned")
+ } else if s := err.Error(); !strings.Contains(s, test.expectHandshakeErrorIncluding) {
+ t.Errorf("Error expected containing '%s' but got '%s'", test.expectHandshakeErrorIncluding, s)
+ }
+ } else {
+ if err != nil {
+ t.Logf("Error from Server.Write: '%s'", err)
+ }
+ }
+ server.Close()
+ serverConn.Close()
+ connStateChan <- server.ConnectionState()
+ }()
+
+ if !write {
+ flows, err := test.loadData()
+ if err != nil {
+ t.Fatalf("%s: failed to load data from %s", test.name, test.dataPath())
+ }
+ for i, b := range flows {
+ if i%2 == 0 {
+ if *fast {
+ clientConn.SetWriteDeadline(time.Now().Add(1 * time.Second))
+ } else {
+ clientConn.SetWriteDeadline(time.Now().Add(1 * time.Minute))
+ }
+ clientConn.Write(b)
+ continue
+ }
+ bb := make([]byte, len(b))
+ if *fast {
+ clientConn.SetReadDeadline(time.Now().Add(1 * time.Second))
+ } else {
+ clientConn.SetReadDeadline(time.Now().Add(1 * time.Minute))
+ }
+ n, err := io.ReadFull(clientConn, bb)
+ if err != nil {
+ t.Fatalf("%s #%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", test.name, i+1, err, n, len(bb), bb[:n], b)
+ }
+ if !bytes.Equal(b, bb) {
+ t.Fatalf("%s #%d: mismatch on read: got:%x want:%x", test.name, i+1, bb, b)
+ }
+ }
+ clientConn.Close()
+ }
+
+ connState := <-connStateChan
+ peerCerts := connState.PeerCertificates
+ if len(peerCerts) == len(test.expectedPeerCerts) {
+ for i, peerCert := range peerCerts {
+ block, _ := pem.Decode([]byte(test.expectedPeerCerts[i]))
+ if !bytes.Equal(block.Bytes, peerCert.Raw) {
+ t.Fatalf("%s: mismatch on peer cert %d", test.name, i+1)
+ }
+ }
+ } else {
+ t.Fatalf("%s: mismatch on peer list length: %d (wanted) != %d (got)", test.name, len(test.expectedPeerCerts), len(peerCerts))
+ }
+
+ if test.validate != nil {
+ if err := test.validate(connState); err != nil {
+ t.Fatalf("validate callback returned error: %s", err)
+ }
+ }
+
+ if write {
+ path := test.dataPath()
+ out, err := os.OpenFile(path, os.O_WRONLY|os.O_CREATE|os.O_TRUNC, 0644)
+ if err != nil {
+ t.Fatalf("Failed to create output file: %s", err)
+ }
+ defer out.Close()
+ recordingConn.Close()
+ if len(recordingConn.flows) < 3 {
+ if len(test.expectHandshakeErrorIncluding) == 0 {
+ t.Fatalf("Handshake failed")
+ }
+ }
+ recordingConn.WriteTo(out)
+ t.Logf("Wrote %s\n", path)
+ childProcess.Wait()
+ }
+}
+
+func runServerTestForVersion(t *testing.T, template *serverTest, version, option string) {
+ // Make a deep copy of the template before going parallel.
+ test := *template
+ if template.config != nil {
+ test.config = template.config.Clone()
+ }
+ test.name = version + "-" + test.name
+ if len(test.command) == 0 {
+ test.command = defaultClientCommand
+ }
+ test.command = append([]string(nil), test.command...)
+ test.command = append(test.command, option)
+
+ runTestAndUpdateIfNeeded(t, version, test.run, test.wait)
+}
+
+func runServerTestTLS10(t *testing.T, template *serverTest) {
+ runServerTestForVersion(t, template, "TLSv10", "-tls1")
+}
+
+func runServerTestTLS11(t *testing.T, template *serverTest) {
+ runServerTestForVersion(t, template, "TLSv11", "-tls1_1")
+}
+
+func runServerTestTLS12(t *testing.T, template *serverTest) {
+ runServerTestForVersion(t, template, "TLSv12", "-tls1_2")
+}
+
+func runServerTestTLS13(t *testing.T, template *serverTest) {
+ runServerTestForVersion(t, template, "TLSv13", "-tls1_3")
+}
+
+func TestHandshakeServerRSARC4(t *testing.T) {
+ test := &serverTest{
+ name: "RSA-RC4",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "RC4-SHA"},
+ }
+ runServerTestTLS10(t, test)
+ runServerTestTLS11(t, test)
+ runServerTestTLS12(t, test)
+}
+
+func TestHandshakeServerRSA3DES(t *testing.T) {
+ test := &serverTest{
+ name: "RSA-3DES",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "DES-CBC3-SHA"},
+ }
+ runServerTestTLS10(t, test)
+ runServerTestTLS12(t, test)
+}
+
+func TestHandshakeServerRSAAES(t *testing.T) {
+ test := &serverTest{
+ name: "RSA-AES",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA"},
+ }
+ runServerTestTLS10(t, test)
+ runServerTestTLS12(t, test)
+}
+
+func TestHandshakeServerAESGCM(t *testing.T) {
+ test := &serverTest{
+ name: "RSA-AES-GCM",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-AES128-GCM-SHA256"},
+ }
+ runServerTestTLS12(t, test)
+}
+
+func TestHandshakeServerAES256GCMSHA384(t *testing.T) {
+ test := &serverTest{
+ name: "RSA-AES256-GCM-SHA384",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-AES256-GCM-SHA384"},
+ }
+ runServerTestTLS12(t, test)
+}
+
+func TestHandshakeServerAES128SHA256(t *testing.T) {
+ test := &serverTest{
+ name: "AES128-SHA256",
+ command: []string{"openssl", "s_client", "-no_ticket", "-ciphersuites", "TLS_AES_128_GCM_SHA256"},
+ }
+ runServerTestTLS13(t, test)
+}
+func TestHandshakeServerAES256SHA384(t *testing.T) {
+ test := &serverTest{
+ name: "AES256-SHA384",
+ command: []string{"openssl", "s_client", "-no_ticket", "-ciphersuites", "TLS_AES_256_GCM_SHA384"},
+ }
+ runServerTestTLS13(t, test)
+}
+func TestHandshakeServerCHACHA20SHA256(t *testing.T) {
+ test := &serverTest{
+ name: "CHACHA20-SHA256",
+ command: []string{"openssl", "s_client", "-no_ticket", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256"},
+ }
+ runServerTestTLS13(t, test)
+}
+
+func TestHandshakeServerECDHEECDSAAES(t *testing.T) {
+ config := testConfig.Clone()
+ config.Certificates = make([]Certificate, 1)
+ config.Certificates[0].Certificate = [][]byte{testECDSACertificate}
+ config.Certificates[0].PrivateKey = testECDSAPrivateKey
+ config.BuildNameToCertificate()
+
+ test := &serverTest{
+ name: "ECDHE-ECDSA-AES",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-ECDSA-AES256-SHA", "-ciphersuites", "TLS_AES_128_GCM_SHA256"},
+ config: config,
+ }
+ runServerTestTLS10(t, test)
+ runServerTestTLS12(t, test)
+ runServerTestTLS13(t, test)
+}
+
+func TestHandshakeServerX25519(t *testing.T) {
+ config := testConfig.Clone()
+ config.CurvePreferences = []CurveID{X25519}
+
+ test := &serverTest{
+ name: "X25519",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256", "-curves", "X25519"},
+ config: config,
+ }
+ runServerTestTLS12(t, test)
+ runServerTestTLS13(t, test)
+}
+
+func TestHandshakeServerP256(t *testing.T) {
+ config := testConfig.Clone()
+ config.CurvePreferences = []CurveID{CurveP256}
+
+ test := &serverTest{
+ name: "P256",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256", "-curves", "P-256"},
+ config: config,
+ }
+ runServerTestTLS12(t, test)
+ runServerTestTLS13(t, test)
+}
+
+func TestHandshakeServerHelloRetryRequest(t *testing.T) {
+ config := testConfig.Clone()
+ config.CurvePreferences = []CurveID{CurveP256}
+
+ test := &serverTest{
+ name: "HelloRetryRequest",
+ command: []string{"openssl", "s_client", "-no_ticket", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256", "-curves", "X25519:P-256"},
+ config: config,
+ }
+ runServerTestTLS13(t, test)
+}
+
+func TestHandshakeServerALPN(t *testing.T) {
+ config := testConfig.Clone()
+ config.NextProtos = []string{"proto1", "proto2"}
+
+ test := &serverTest{
+ name: "ALPN",
+ // Note that this needs OpenSSL 1.0.2 because that is the first
+ // version that supports the -alpn flag.
+ command: []string{"openssl", "s_client", "-alpn", "proto2,proto1", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256"},
+ config: config,
+ validate: func(state ConnectionState) error {
+ // The server's preferences should override the client.
+ if state.NegotiatedProtocol != "proto1" {
+ return fmt.Errorf("Got protocol %q, wanted proto1", state.NegotiatedProtocol)
+ }
+ return nil
+ },
+ }
+ runServerTestTLS12(t, test)
+ runServerTestTLS13(t, test)
+}
+
+func TestHandshakeServerALPNNoMatch(t *testing.T) {
+ config := testConfig.Clone()
+ config.NextProtos = []string{"proto3"}
+
+ test := &serverTest{
+ name: "ALPN-NoMatch",
+ // Note that this needs OpenSSL 1.0.2 because that is the first
+ // version that supports the -alpn flag.
+ command: []string{"openssl", "s_client", "-alpn", "proto2,proto1", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256"},
+ config: config,
+ expectHandshakeErrorIncluding: "client requested unsupported application protocol",
+ }
+ runServerTestTLS12(t, test)
+ runServerTestTLS13(t, test)
+}
+
+func TestHandshakeServerALPNNotConfigured(t *testing.T) {
+ config := testConfig.Clone()
+ config.NextProtos = nil
+
+ test := &serverTest{
+ name: "ALPN-NotConfigured",
+ // Note that this needs OpenSSL 1.0.2 because that is the first
+ // version that supports the -alpn flag.
+ command: []string{"openssl", "s_client", "-alpn", "proto2,proto1", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256"},
+ config: config,
+ validate: func(state ConnectionState) error {
+ if state.NegotiatedProtocol != "" {
+ return fmt.Errorf("Got protocol %q, wanted nothing", state.NegotiatedProtocol)
+ }
+ return nil
+ },
+ }
+ runServerTestTLS12(t, test)
+ runServerTestTLS13(t, test)
+}
+
+func TestHandshakeServerALPNFallback(t *testing.T) {
+ config := testConfig.Clone()
+ config.NextProtos = []string{"proto1", "h2", "proto2"}
+
+ test := &serverTest{
+ name: "ALPN-Fallback",
+ // Note that this needs OpenSSL 1.0.2 because that is the first
+ // version that supports the -alpn flag.
+ command: []string{"openssl", "s_client", "-alpn", "proto3,http/1.1,proto4", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256"},
+ config: config,
+ validate: func(state ConnectionState) error {
+ if state.NegotiatedProtocol != "" {
+ return fmt.Errorf("Got protocol %q, wanted nothing", state.NegotiatedProtocol)
+ }
+ return nil
+ },
+ }
+ runServerTestTLS12(t, test)
+ runServerTestTLS13(t, test)
+}
+
+// TestHandshakeServerSNI involves a client sending an SNI extension of
+// "snitest.com", which happens to match the CN of testSNICertificate. The test
+// verifies that the server correctly selects that certificate.
+func TestHandshakeServerSNI(t *testing.T) {
+ test := &serverTest{
+ name: "SNI",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
+ }
+ runServerTestTLS12(t, test)
+}
+
+// TestHandshakeServerSNICertForName is similar to TestHandshakeServerSNI, but
+// tests the dynamic GetCertificate method
+func TestHandshakeServerSNIGetCertificate(t *testing.T) {
+ config := testConfig.Clone()
+
+ // Replace the NameToCertificate map with a GetCertificate function
+ nameToCert := config.NameToCertificate
+ config.NameToCertificate = nil
+ config.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
+ cert := nameToCert[clientHello.ServerName]
+ return cert, nil
+ }
+ test := &serverTest{
+ name: "SNI-GetCertificate",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
+ config: config,
+ }
+ runServerTestTLS12(t, test)
+}
+
+// TestHandshakeServerSNICertForNameNotFound is similar to
+// TestHandshakeServerSNICertForName, but tests to make sure that when the
+// GetCertificate method doesn't return a cert, we fall back to what's in
+// the NameToCertificate map.
+func TestHandshakeServerSNIGetCertificateNotFound(t *testing.T) {
+ config := testConfig.Clone()
+
+ config.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
+ return nil, nil
+ }
+ test := &serverTest{
+ name: "SNI-GetCertificateNotFound",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-servername", "snitest.com"},
+ config: config,
+ }
+ runServerTestTLS12(t, test)
+}
+
+// TestHandshakeServerSNICertForNameError tests to make sure that errors in
+// GetCertificate result in a tls alert.
+func TestHandshakeServerSNIGetCertificateError(t *testing.T) {
+ const errMsg = "TestHandshakeServerSNIGetCertificateError error"
+
+ serverConfig := testConfig.Clone()
+ serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
+ return nil, errors.New(errMsg)
+ }
+
+ clientHello := &clientHelloMsg{
+ vers: VersionTLS10,
+ random: make([]byte, 32),
+ cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ compressionMethods: []uint8{compressionNone},
+ serverName: "test",
+ }
+ testClientHelloFailure(t, serverConfig, clientHello, errMsg)
+}
+
+// TestHandshakeServerEmptyCertificates tests that GetCertificates is called in
+// the case that Certificates is empty, even without SNI.
+func TestHandshakeServerEmptyCertificates(t *testing.T) {
+ const errMsg = "TestHandshakeServerEmptyCertificates error"
+
+ serverConfig := testConfig.Clone()
+ serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
+ return nil, errors.New(errMsg)
+ }
+ serverConfig.Certificates = nil
+
+ clientHello := &clientHelloMsg{
+ vers: VersionTLS10,
+ random: make([]byte, 32),
+ cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ compressionMethods: []uint8{compressionNone},
+ }
+ testClientHelloFailure(t, serverConfig, clientHello, errMsg)
+
+ // With an empty Certificates and a nil GetCertificate, the server
+ // should always return a “no certificates” error.
+ serverConfig.GetCertificate = nil
+
+ clientHello = &clientHelloMsg{
+ vers: VersionTLS10,
+ random: make([]byte, 32),
+ cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ compressionMethods: []uint8{compressionNone},
+ }
+ testClientHelloFailure(t, serverConfig, clientHello, "no certificates")
+}
+
+func TestServerResumption(t *testing.T) {
+ sessionFilePath := tempFile("")
+ defer os.Remove(sessionFilePath)
+
+ testIssue := &serverTest{
+ name: "IssueTicket",
+ command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-ciphersuites", "TLS_AES_128_GCM_SHA256", "-sess_out", sessionFilePath},
+ wait: true,
+ }
+ testResume := &serverTest{
+ name: "Resume",
+ command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-ciphersuites", "TLS_AES_128_GCM_SHA256", "-sess_in", sessionFilePath},
+ validate: func(state ConnectionState) error {
+ if !state.DidResume {
+ return errors.New("did not resume")
+ }
+ return nil
+ },
+ }
+
+ runServerTestTLS12(t, testIssue)
+ runServerTestTLS12(t, testResume)
+
+ runServerTestTLS13(t, testIssue)
+ runServerTestTLS13(t, testResume)
+
+ config := testConfig.Clone()
+ config.CurvePreferences = []CurveID{CurveP256}
+
+ testResumeHRR := &serverTest{
+ name: "Resume-HelloRetryRequest",
+ command: []string{"openssl", "s_client", "-curves", "X25519:P-256", "-cipher", "AES128-SHA", "-ciphersuites",
+ "TLS_AES_128_GCM_SHA256", "-sess_in", sessionFilePath},
+ config: config,
+ validate: func(state ConnectionState) error {
+ if !state.DidResume {
+ return errors.New("did not resume")
+ }
+ return nil
+ },
+ }
+
+ runServerTestTLS13(t, testResumeHRR)
+}
+
+func TestServerResumptionDisabled(t *testing.T) {
+ sessionFilePath := tempFile("")
+ defer os.Remove(sessionFilePath)
+
+ config := testConfig.Clone()
+
+ testIssue := &serverTest{
+ name: "IssueTicketPreDisable",
+ command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-ciphersuites", "TLS_AES_128_GCM_SHA256", "-sess_out", sessionFilePath},
+ config: config,
+ wait: true,
+ }
+ testResume := &serverTest{
+ name: "ResumeDisabled",
+ command: []string{"openssl", "s_client", "-cipher", "AES128-SHA", "-ciphersuites", "TLS_AES_128_GCM_SHA256", "-sess_in", sessionFilePath},
+ config: config,
+ validate: func(state ConnectionState) error {
+ if state.DidResume {
+ return errors.New("resumed with SessionTicketsDisabled")
+ }
+ return nil
+ },
+ }
+
+ config.SessionTicketsDisabled = false
+ runServerTestTLS12(t, testIssue)
+ config.SessionTicketsDisabled = true
+ runServerTestTLS12(t, testResume)
+
+ config.SessionTicketsDisabled = false
+ runServerTestTLS13(t, testIssue)
+ config.SessionTicketsDisabled = true
+ runServerTestTLS13(t, testResume)
+}
+
+func TestFallbackSCSV(t *testing.T) {
+ serverConfig := Config{
+ Certificates: testConfig.Certificates,
+ }
+ test := &serverTest{
+ name: "FallbackSCSV",
+ config: &serverConfig,
+ // OpenSSL 1.0.1j is needed for the -fallback_scsv option.
+ command: []string{"openssl", "s_client", "-fallback_scsv"},
+ expectHandshakeErrorIncluding: "inappropriate protocol fallback",
+ }
+ runServerTestTLS11(t, test)
+}
+
+func TestHandshakeServerExportKeyingMaterial(t *testing.T) {
+ test := &serverTest{
+ name: "ExportKeyingMaterial",
+ command: []string{"openssl", "s_client", "-cipher", "ECDHE-RSA-AES256-SHA", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256"},
+ config: testConfig.Clone(),
+ validate: func(state ConnectionState) error {
+ if km, err := state.ExportKeyingMaterial("test", nil, 42); err != nil {
+ return fmt.Errorf("ExportKeyingMaterial failed: %v", err)
+ } else if len(km) != 42 {
+ return fmt.Errorf("Got %d bytes from ExportKeyingMaterial, wanted %d", len(km), 42)
+ }
+ return nil
+ },
+ }
+ runServerTestTLS10(t, test)
+ runServerTestTLS12(t, test)
+ runServerTestTLS13(t, test)
+}
+
+func TestHandshakeServerRSAPKCS1v15(t *testing.T) {
+ test := &serverTest{
+ name: "RSA-RSAPKCS1v15",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-sigalgs", "rsa_pkcs1_sha256"},
+ }
+ runServerTestTLS12(t, test)
+}
+
+func TestHandshakeServerRSAPSS(t *testing.T) {
+ // We send rsa_pss_rsae_sha512 first, as the test key won't fit, and we
+ // verify the server implementation will disregard the client preference in
+ // that case. See Issue 29793.
+ test := &serverTest{
+ name: "RSA-RSAPSS",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-RSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256", "-sigalgs", "rsa_pss_rsae_sha512:rsa_pss_rsae_sha256"},
+ }
+ runServerTestTLS12(t, test)
+ runServerTestTLS13(t, test)
+
+ test = &serverTest{
+ name: "RSA-RSAPSS-TooSmall",
+ command: []string{"openssl", "s_client", "-no_ticket", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256", "-sigalgs", "rsa_pss_rsae_sha512"},
+ expectHandshakeErrorIncluding: "peer doesn't support any of the certificate's signature algorithms",
+ }
+ runServerTestTLS13(t, test)
+}
+
+func TestHandshakeServerEd25519(t *testing.T) {
+ config := testConfig.Clone()
+ config.Certificates = make([]Certificate, 1)
+ config.Certificates[0].Certificate = [][]byte{testEd25519Certificate}
+ config.Certificates[0].PrivateKey = testEd25519PrivateKey
+ config.BuildNameToCertificate()
+
+ test := &serverTest{
+ name: "Ed25519",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "ECDHE-ECDSA-CHACHA20-POLY1305", "-ciphersuites", "TLS_CHACHA20_POLY1305_SHA256"},
+ config: config,
+ }
+ runServerTestTLS12(t, test)
+ runServerTestTLS13(t, test)
+}
+
+func benchmarkHandshakeServer(b *testing.B, version uint16, cipherSuite uint16, curve CurveID, cert []byte, key crypto.PrivateKey) {
+ config := testConfig.Clone()
+ config.CipherSuites = []uint16{cipherSuite}
+ config.CurvePreferences = []CurveID{curve}
+ config.Certificates = make([]Certificate, 1)
+ config.Certificates[0].Certificate = [][]byte{cert}
+ config.Certificates[0].PrivateKey = key
+ config.BuildNameToCertificate()
+
+ clientConn, serverConn := localPipe(b)
+ serverConn = &recordingConn{Conn: serverConn}
+ go func() {
+ config := testConfig.Clone()
+ config.MaxVersion = version
+ config.CurvePreferences = []CurveID{curve}
+ client := Client(clientConn, config)
+ client.Handshake()
+ }()
+ server := Server(serverConn, config)
+ if err := server.Handshake(); err != nil {
+ b.Fatalf("handshake failed: %v", err)
+ }
+ serverConn.Close()
+ flows := serverConn.(*recordingConn).flows
+
+ feeder := make(chan struct{})
+ clientConn, serverConn = localPipe(b)
+
+ go func() {
+ for range feeder {
+ for i, f := range flows {
+ if i%2 == 0 {
+ clientConn.Write(f)
+ continue
+ }
+ ff := make([]byte, len(f))
+ n, err := io.ReadFull(clientConn, ff)
+ if err != nil {
+ b.Errorf("#%d: %s\nRead %d, wanted %d, got %x, wanted %x\n", i+1, err, n, len(ff), ff[:n], f)
+ }
+ if !bytes.Equal(f, ff) {
+ b.Errorf("#%d: mismatch on read: got:%x want:%x", i+1, ff, f)
+ }
+ }
+ }
+ }()
+
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ feeder <- struct{}{}
+ server := Server(serverConn, config)
+ if err := server.Handshake(); err != nil {
+ b.Fatalf("handshake failed: %v", err)
+ }
+ }
+ close(feeder)
+}
+
+func BenchmarkHandshakeServer(b *testing.B) {
+ b.Run("RSA", func(b *testing.B) {
+ benchmarkHandshakeServer(b, VersionTLS12, TLS_RSA_WITH_AES_128_GCM_SHA256,
+ 0, testRSACertificate, testRSAPrivateKey)
+ })
+ b.Run("ECDHE-P256-RSA", func(b *testing.B) {
+ b.Run("TLSv13", func(b *testing.B) {
+ benchmarkHandshakeServer(b, VersionTLS13, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ CurveP256, testRSACertificate, testRSAPrivateKey)
+ })
+ b.Run("TLSv12", func(b *testing.B) {
+ benchmarkHandshakeServer(b, VersionTLS12, TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ CurveP256, testRSACertificate, testRSAPrivateKey)
+ })
+ })
+ b.Run("ECDHE-P256-ECDSA-P256", func(b *testing.B) {
+ b.Run("TLSv13", func(b *testing.B) {
+ benchmarkHandshakeServer(b, VersionTLS13, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ CurveP256, testP256Certificate, testP256PrivateKey)
+ })
+ b.Run("TLSv12", func(b *testing.B) {
+ benchmarkHandshakeServer(b, VersionTLS12, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ CurveP256, testP256Certificate, testP256PrivateKey)
+ })
+ })
+ b.Run("ECDHE-X25519-ECDSA-P256", func(b *testing.B) {
+ b.Run("TLSv13", func(b *testing.B) {
+ benchmarkHandshakeServer(b, VersionTLS13, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ X25519, testP256Certificate, testP256PrivateKey)
+ })
+ b.Run("TLSv12", func(b *testing.B) {
+ benchmarkHandshakeServer(b, VersionTLS12, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ X25519, testP256Certificate, testP256PrivateKey)
+ })
+ })
+ b.Run("ECDHE-P521-ECDSA-P521", func(b *testing.B) {
+ if testECDSAPrivateKey.PublicKey.Curve != elliptic.P521() {
+ b.Fatal("test ECDSA key doesn't use curve P-521")
+ }
+ b.Run("TLSv13", func(b *testing.B) {
+ benchmarkHandshakeServer(b, VersionTLS13, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ CurveP521, testECDSACertificate, testECDSAPrivateKey)
+ })
+ b.Run("TLSv12", func(b *testing.B) {
+ benchmarkHandshakeServer(b, VersionTLS12, TLS_ECDHE_ECDSA_WITH_CHACHA20_POLY1305,
+ CurveP521, testECDSACertificate, testECDSAPrivateKey)
+ })
+ })
+}
+
+func TestClientAuth(t *testing.T) {
+ var certPath, keyPath, ecdsaCertPath, ecdsaKeyPath, ed25519CertPath, ed25519KeyPath string
+
+ if *update {
+ certPath = tempFile(clientCertificatePEM)
+ defer os.Remove(certPath)
+ keyPath = tempFile(clientKeyPEM)
+ defer os.Remove(keyPath)
+ ecdsaCertPath = tempFile(clientECDSACertificatePEM)
+ defer os.Remove(ecdsaCertPath)
+ ecdsaKeyPath = tempFile(clientECDSAKeyPEM)
+ defer os.Remove(ecdsaKeyPath)
+ ed25519CertPath = tempFile(clientEd25519CertificatePEM)
+ defer os.Remove(ed25519CertPath)
+ ed25519KeyPath = tempFile(clientEd25519KeyPEM)
+ defer os.Remove(ed25519KeyPath)
+ } else {
+ t.Parallel()
+ }
+
+ config := testConfig.Clone()
+ config.ClientAuth = RequestClientCert
+
+ test := &serverTest{
+ name: "ClientAuthRequestedNotGiven",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-ciphersuites", "TLS_AES_128_GCM_SHA256"},
+ config: config,
+ }
+ runServerTestTLS12(t, test)
+ runServerTestTLS13(t, test)
+
+ test = &serverTest{
+ name: "ClientAuthRequestedAndGiven",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-ciphersuites", "TLS_AES_128_GCM_SHA256",
+ "-cert", certPath, "-key", keyPath, "-client_sigalgs", "rsa_pss_rsae_sha256"},
+ config: config,
+ expectedPeerCerts: []string{clientCertificatePEM},
+ }
+ runServerTestTLS12(t, test)
+ runServerTestTLS13(t, test)
+
+ test = &serverTest{
+ name: "ClientAuthRequestedAndECDSAGiven",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-ciphersuites", "TLS_AES_128_GCM_SHA256",
+ "-cert", ecdsaCertPath, "-key", ecdsaKeyPath},
+ config: config,
+ expectedPeerCerts: []string{clientECDSACertificatePEM},
+ }
+ runServerTestTLS12(t, test)
+ runServerTestTLS13(t, test)
+
+ test = &serverTest{
+ name: "ClientAuthRequestedAndEd25519Given",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA", "-ciphersuites", "TLS_AES_128_GCM_SHA256",
+ "-cert", ed25519CertPath, "-key", ed25519KeyPath},
+ config: config,
+ expectedPeerCerts: []string{clientEd25519CertificatePEM},
+ }
+ runServerTestTLS12(t, test)
+ runServerTestTLS13(t, test)
+
+ test = &serverTest{
+ name: "ClientAuthRequestedAndPKCS1v15Given",
+ command: []string{"openssl", "s_client", "-no_ticket", "-cipher", "AES128-SHA",
+ "-cert", certPath, "-key", keyPath, "-client_sigalgs", "rsa_pkcs1_sha256"},
+ config: config,
+ expectedPeerCerts: []string{clientCertificatePEM},
+ }
+ runServerTestTLS12(t, test)
+}
+
+func TestSNIGivenOnFailure(t *testing.T) {
+ const expectedServerName = "test.testing"
+
+ clientHello := &clientHelloMsg{
+ vers: VersionTLS10,
+ random: make([]byte, 32),
+ cipherSuites: []uint16{TLS_RSA_WITH_RC4_128_SHA},
+ compressionMethods: []uint8{compressionNone},
+ serverName: expectedServerName,
+ }
+
+ serverConfig := testConfig.Clone()
+ // Erase the server's cipher suites to ensure the handshake fails.
+ serverConfig.CipherSuites = nil
+
+ c, s := localPipe(t)
+ go func() {
+ cli := Client(c, testConfig)
+ cli.vers = clientHello.vers
+ if _, err := cli.writeHandshakeRecord(clientHello, nil); err != nil {
+ testFatal(t, err)
+ }
+ c.Close()
+ }()
+ conn := Server(s, serverConfig)
+ ctx := context.Background()
+ ch, err := conn.readClientHello(ctx)
+ hs := serverHandshakeState{
+ c: conn,
+ ctx: ctx,
+ clientHello: ch,
+ }
+ if err == nil {
+ err = hs.processClientHello()
+ }
+ if err == nil {
+ err = hs.pickCipherSuite()
+ }
+ defer s.Close()
+
+ if err == nil {
+ t.Error("No error reported from server")
+ }
+
+ cs := hs.c.ConnectionState()
+ if cs.HandshakeComplete {
+ t.Error("Handshake registered as complete")
+ }
+
+ if cs.ServerName != expectedServerName {
+ t.Errorf("Expected ServerName of %q, but got %q", expectedServerName, cs.ServerName)
+ }
+}
+
+var getConfigForClientTests = []struct {
+ setup func(config *Config)
+ callback func(clientHello *ClientHelloInfo) (*Config, error)
+ errorSubstring string
+ verify func(config *Config) error
+}{
+ {
+ nil,
+ func(clientHello *ClientHelloInfo) (*Config, error) {
+ return nil, nil
+ },
+ "",
+ nil,
+ },
+ {
+ nil,
+ func(clientHello *ClientHelloInfo) (*Config, error) {
+ return nil, errors.New("should bubble up")
+ },
+ "should bubble up",
+ nil,
+ },
+ {
+ nil,
+ func(clientHello *ClientHelloInfo) (*Config, error) {
+ config := testConfig.Clone()
+ // Setting a maximum version of TLS 1.1 should cause
+ // the handshake to fail, as the client MinVersion is TLS 1.2.
+ config.MaxVersion = VersionTLS11
+ return config, nil
+ },
+ "client offered only unsupported versions",
+ nil,
+ },
+ {
+ func(config *Config) {
+ for i := range config.SessionTicketKey {
+ config.SessionTicketKey[i] = byte(i)
+ }
+ config.sessionTicketKeys = nil
+ },
+ func(clientHello *ClientHelloInfo) (*Config, error) {
+ config := testConfig.Clone()
+ for i := range config.SessionTicketKey {
+ config.SessionTicketKey[i] = 0
+ }
+ config.sessionTicketKeys = nil
+ return config, nil
+ },
+ "",
+ func(config *Config) error {
+ if config.SessionTicketKey == [32]byte{} {
+ return fmt.Errorf("expected SessionTicketKey to be set")
+ }
+ return nil
+ },
+ },
+ {
+ func(config *Config) {
+ var dummyKey [32]byte
+ for i := range dummyKey {
+ dummyKey[i] = byte(i)
+ }
+
+ config.SetSessionTicketKeys([][32]byte{dummyKey})
+ },
+ func(clientHello *ClientHelloInfo) (*Config, error) {
+ config := testConfig.Clone()
+ config.sessionTicketKeys = nil
+ return config, nil
+ },
+ "",
+ func(config *Config) error {
+ if config.SessionTicketKey == [32]byte{} {
+ return fmt.Errorf("expected SessionTicketKey to be set")
+ }
+ return nil
+ },
+ },
+}
+
+func TestGetConfigForClient(t *testing.T) {
+ serverConfig := testConfig.Clone()
+ clientConfig := testConfig.Clone()
+ clientConfig.MinVersion = VersionTLS12
+
+ for i, test := range getConfigForClientTests {
+ if test.setup != nil {
+ test.setup(serverConfig)
+ }
+
+ var configReturned *Config
+ serverConfig.GetConfigForClient = func(clientHello *ClientHelloInfo) (*Config, error) {
+ config, err := test.callback(clientHello)
+ configReturned = config
+ return config, err
+ }
+ c, s := localPipe(t)
+ done := make(chan error)
+
+ go func() {
+ defer s.Close()
+ done <- Server(s, serverConfig).Handshake()
+ }()
+
+ clientErr := Client(c, clientConfig).Handshake()
+ c.Close()
+
+ serverErr := <-done
+
+ if len(test.errorSubstring) == 0 {
+ if serverErr != nil || clientErr != nil {
+ t.Errorf("test[%d]: expected no error but got serverErr: %q, clientErr: %q", i, serverErr, clientErr)
+ }
+ if test.verify != nil {
+ if err := test.verify(configReturned); err != nil {
+ t.Errorf("test[%d]: verify returned error: %v", i, err)
+ }
+ }
+ } else {
+ if serverErr == nil {
+ t.Errorf("test[%d]: expected error containing %q but got no error", i, test.errorSubstring)
+ } else if !strings.Contains(serverErr.Error(), test.errorSubstring) {
+ t.Errorf("test[%d]: expected error to contain %q but it was %q", i, test.errorSubstring, serverErr)
+ }
+ }
+ }
+}
+
+func TestCloseServerConnectionOnIdleClient(t *testing.T) {
+ clientConn, serverConn := localPipe(t)
+ server := Server(serverConn, testConfig.Clone())
+ go func() {
+ clientConn.Write([]byte{'0'})
+ server.Close()
+ }()
+ server.SetReadDeadline(time.Now().Add(time.Minute))
+ err := server.Handshake()
+ if err != nil {
+ if err, ok := err.(net.Error); ok && err.Timeout() {
+ t.Errorf("Expected a closed network connection error but got '%s'", err.Error())
+ }
+ } else {
+ t.Errorf("Error expected, but no error returned")
+ }
+}
+
+func TestCloneHash(t *testing.T) {
+ h1 := crypto.SHA256.New()
+ h1.Write([]byte("test"))
+ s1 := h1.Sum(nil)
+ h2 := cloneHash(h1, crypto.SHA256)
+ s2 := h2.Sum(nil)
+ if !bytes.Equal(s1, s2) {
+ t.Error("cloned hash generated a different sum")
+ }
+}
+
+func expectError(t *testing.T, err error, sub string) {
+ if err == nil {
+ t.Errorf(`expected error %q, got nil`, sub)
+ } else if !strings.Contains(err.Error(), sub) {
+ t.Errorf(`expected error %q, got %q`, sub, err)
+ }
+}
+
+func TestKeyTooSmallForRSAPSS(t *testing.T) {
+ cert, err := X509KeyPair([]byte(`-----BEGIN CERTIFICATE-----
+MIIBcTCCARugAwIBAgIQGjQnkCFlUqaFlt6ixyz/tDANBgkqhkiG9w0BAQsFADAS
+MRAwDgYDVQQKEwdBY21lIENvMB4XDTE5MDExODIzMjMyOFoXDTIwMDExODIzMjMy
+OFowEjEQMA4GA1UEChMHQWNtZSBDbzBcMA0GCSqGSIb3DQEBAQUAA0sAMEgCQQDd
+ez1rFUDwax2HTxbcnFUP9AhcgEGMHVV2nn4VVEWFJB6I8C/Nkx0XyyQlrmFYBzEQ
+nIPhKls4T0hFoLvjJnXpAgMBAAGjTTBLMA4GA1UdDwEB/wQEAwIFoDATBgNVHSUE
+DDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBYGA1UdEQQPMA2CC2V4YW1wbGUu
+Y29tMA0GCSqGSIb3DQEBCwUAA0EAxDuUS+BrrS3c+h+k+fQPOmOScy6yTX9mHw0Q
+KbucGamXYEy0URIwOdO0tQ3LHPc1YGvYSPwkDjkjqECs2Vm/AA==
+-----END CERTIFICATE-----`), []byte(testingKey(`-----BEGIN RSA TESTING KEY-----
+MIIBOgIBAAJBAN17PWsVQPBrHYdPFtycVQ/0CFyAQYwdVXaefhVURYUkHojwL82T
+HRfLJCWuYVgHMRCcg+EqWzhPSEWgu+MmdekCAwEAAQJBALjQYNTdXF4CFBbXwUz/
+yt9QFDYT9B5WT/12jeGAe653gtYS6OOi/+eAkGmzg1GlRnw6fOfn+HYNFDORST7z
+4j0CIQDn2xz9hVWQEu9ee3vecNT3f60huDGTNoRhtqgweQGX0wIhAPSLj1VcRZEz
+nKpbtU22+PbIMSJ+e80fmY9LIPx5N4HTAiAthGSimMR9bloz0EY3GyuUEyqoDgMd
+hXxjuno2WesoJQIgemilbcALXpxsLmZLgcQ2KSmaVr7jb5ECx9R+hYKTw1sCIG4s
+T+E0J8wlH24pgwQHzy7Ko2qLwn1b5PW8ecrlvP1g
+-----END RSA TESTING KEY-----`)))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ clientConn, serverConn := localPipe(t)
+ client := Client(clientConn, testConfig)
+ done := make(chan struct{})
+ go func() {
+ config := testConfig.Clone()
+ config.Certificates = []Certificate{cert}
+ config.MinVersion = VersionTLS13
+ server := Server(serverConn, config)
+ err := server.Handshake()
+ expectError(t, err, "key size too small")
+ close(done)
+ }()
+ err = client.Handshake()
+ expectError(t, err, "handshake failure")
+ <-done
+}
+
+func TestMultipleCertificates(t *testing.T) {
+ clientConfig := testConfig.Clone()
+ clientConfig.CipherSuites = []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256}
+ clientConfig.MaxVersion = VersionTLS12
+
+ serverConfig := testConfig.Clone()
+ serverConfig.Certificates = []Certificate{{
+ Certificate: [][]byte{testECDSACertificate},
+ PrivateKey: testECDSAPrivateKey,
+ }, {
+ Certificate: [][]byte{testRSACertificate},
+ PrivateKey: testRSAPrivateKey,
+ }}
+
+ _, clientState, err := testHandshake(t, clientConfig, serverConfig)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if got := clientState.PeerCertificates[0].PublicKeyAlgorithm; got != x509.RSA {
+ t.Errorf("expected RSA certificate, got %v", got)
+ }
+}
+
+func TestAESCipherReordering(t *testing.T) {
+ currentAESSupport := hasAESGCMHardwareSupport
+ defer func() { hasAESGCMHardwareSupport = currentAESSupport }()
+
+ tests := []struct {
+ name string
+ clientCiphers []uint16
+ serverHasAESGCM bool
+ serverCiphers []uint16
+ expectedCipher uint16
+ }{
+ {
+ name: "server has hardware AES, client doesn't (pick ChaCha)",
+ clientCiphers: []uint16{
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ },
+ serverHasAESGCM: true,
+ expectedCipher: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ },
+ {
+ name: "client prefers AES-GCM, server doesn't have hardware AES (pick ChaCha)",
+ clientCiphers: []uint16{
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ },
+ serverHasAESGCM: false,
+ expectedCipher: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ },
+ {
+ name: "client prefers AES-GCM, server has hardware AES (pick AES-GCM)",
+ clientCiphers: []uint16{
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ },
+ serverHasAESGCM: true,
+ expectedCipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ {
+ name: "client prefers AES-GCM and sends GREASE, server has hardware AES (pick AES-GCM)",
+ clientCiphers: []uint16{
+ 0x0A0A, // GREASE value
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ },
+ serverHasAESGCM: true,
+ expectedCipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ {
+ name: "client prefers AES-GCM and doesn't support ChaCha, server doesn't have hardware AES (pick AES-GCM)",
+ clientCiphers: []uint16{
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ },
+ serverHasAESGCM: false,
+ expectedCipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ {
+ name: "client prefers AES-GCM and AES-CBC over ChaCha, server doesn't have hardware AES (pick ChaCha)",
+ clientCiphers: []uint16{
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ },
+ serverHasAESGCM: false,
+ expectedCipher: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ },
+ {
+ name: "client prefers AES-GCM over ChaCha and sends GREASE, server doesn't have hardware AES (pick ChaCha)",
+ clientCiphers: []uint16{
+ 0x0A0A, // GREASE value
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ },
+ serverHasAESGCM: false,
+ expectedCipher: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ },
+ {
+ name: "client supports multiple AES-GCM, server doesn't have hardware AES and doesn't support ChaCha (AES-GCM)",
+ clientCiphers: []uint16{
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ serverHasAESGCM: false,
+ serverCiphers: []uint16{
+ TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ expectedCipher: TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ },
+ {
+ name: "client prefers AES-GCM, server has hardware but doesn't support AES (pick ChaCha)",
+ clientCiphers: []uint16{
+ TLS_ECDHE_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ },
+ serverHasAESGCM: true,
+ serverCiphers: []uint16{
+ TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ },
+ expectedCipher: TLS_ECDHE_RSA_WITH_CHACHA20_POLY1305,
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ hasAESGCMHardwareSupport = tc.serverHasAESGCM
+ hs := &serverHandshakeState{
+ c: &Conn{
+ config: &Config{
+ CipherSuites: tc.serverCiphers,
+ },
+ vers: VersionTLS12,
+ },
+ clientHello: &clientHelloMsg{
+ cipherSuites: tc.clientCiphers,
+ vers: VersionTLS12,
+ },
+ ecdheOk: true,
+ rsaSignOk: true,
+ rsaDecryptOk: true,
+ }
+
+ err := hs.pickCipherSuite()
+ if err != nil {
+ t.Errorf("pickCipherSuite failed: %s", err)
+ }
+
+ if tc.expectedCipher != hs.suite.id {
+ t.Errorf("unexpected cipher chosen: want %d, got %d", tc.expectedCipher, hs.suite.id)
+ }
+ })
+ }
+}
+
+func TestAESCipherReorderingTLS13(t *testing.T) {
+ currentAESSupport := hasAESGCMHardwareSupport
+ defer func() { hasAESGCMHardwareSupport = currentAESSupport }()
+
+ tests := []struct {
+ name string
+ clientCiphers []uint16
+ serverHasAESGCM bool
+ expectedCipher uint16
+ }{
+ {
+ name: "server has hardware AES, client doesn't (pick ChaCha)",
+ clientCiphers: []uint16{
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_AES_128_GCM_SHA256,
+ },
+ serverHasAESGCM: true,
+ expectedCipher: TLS_CHACHA20_POLY1305_SHA256,
+ },
+ {
+ name: "neither server nor client have hardware AES (pick ChaCha)",
+ clientCiphers: []uint16{
+ TLS_CHACHA20_POLY1305_SHA256,
+ TLS_AES_128_GCM_SHA256,
+ },
+ serverHasAESGCM: false,
+ expectedCipher: TLS_CHACHA20_POLY1305_SHA256,
+ },
+ {
+ name: "client prefers AES, server doesn't have hardware (pick ChaCha)",
+ clientCiphers: []uint16{
+ TLS_AES_128_GCM_SHA256,
+ TLS_CHACHA20_POLY1305_SHA256,
+ },
+ serverHasAESGCM: false,
+ expectedCipher: TLS_CHACHA20_POLY1305_SHA256,
+ },
+ {
+ name: "client prefers AES and sends GREASE, server doesn't have hardware (pick ChaCha)",
+ clientCiphers: []uint16{
+ 0x0A0A, // GREASE value
+ TLS_AES_128_GCM_SHA256,
+ TLS_CHACHA20_POLY1305_SHA256,
+ },
+ serverHasAESGCM: false,
+ expectedCipher: TLS_CHACHA20_POLY1305_SHA256,
+ },
+ {
+ name: "client prefers AES, server has hardware AES (pick AES)",
+ clientCiphers: []uint16{
+ TLS_AES_128_GCM_SHA256,
+ TLS_CHACHA20_POLY1305_SHA256,
+ },
+ serverHasAESGCM: true,
+ expectedCipher: TLS_AES_128_GCM_SHA256,
+ },
+ {
+ name: "client prefers AES and sends GREASE, server has hardware AES (pick AES)",
+ clientCiphers: []uint16{
+ 0x0A0A, // GREASE value
+ TLS_AES_128_GCM_SHA256,
+ TLS_CHACHA20_POLY1305_SHA256,
+ },
+ serverHasAESGCM: true,
+ expectedCipher: TLS_AES_128_GCM_SHA256,
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ hasAESGCMHardwareSupport = tc.serverHasAESGCM
+ pk, _ := ecdh.X25519().GenerateKey(rand.Reader)
+ hs := &serverHandshakeStateTLS13{
+ c: &Conn{
+ config: &Config{},
+ vers: VersionTLS13,
+ },
+ clientHello: &clientHelloMsg{
+ cipherSuites: tc.clientCiphers,
+ supportedVersions: []uint16{VersionTLS13},
+ compressionMethods: []uint8{compressionNone},
+ keyShares: []keyShare{{group: X25519, data: pk.PublicKey().Bytes()}},
+ },
+ }
+
+ err := hs.processClientHello()
+ if err != nil {
+ t.Errorf("pickCipherSuite failed: %s", err)
+ }
+
+ if tc.expectedCipher != hs.suite.id {
+ t.Errorf("unexpected cipher chosen: want %d, got %d", tc.expectedCipher, hs.suite.id)
+ }
+ })
+ }
+}
+
+// TestServerHandshakeContextCancellation tests that canceling
+// the context given to the server side conn.HandshakeContext
+// interrupts the in-progress handshake.
+func TestServerHandshakeContextCancellation(t *testing.T) {
+ c, s := localPipe(t)
+ ctx, cancel := context.WithCancel(context.Background())
+ unblockClient := make(chan struct{})
+ defer close(unblockClient)
+ go func() {
+ cancel()
+ <-unblockClient
+ _ = c.Close()
+ }()
+ conn := Server(s, testConfig)
+ // Initiates server side handshake, which will block until a client hello is read
+ // unless the cancellation works.
+ err := conn.HandshakeContext(ctx)
+ if err == nil {
+ t.Fatal("Server handshake did not error when the context was canceled")
+ }
+ if err != context.Canceled {
+ t.Errorf("Unexpected server handshake error: %v", err)
+ }
+ if runtime.GOARCH == "wasm" {
+ t.Skip("conn.Close does not error as expected when called multiple times on WASM")
+ }
+ err = conn.Close()
+ if err == nil {
+ t.Error("Server connection was not closed when the context was canceled")
+ }
+}
+
+// TestHandshakeContextHierarchy tests whether the contexts
+// available to GetClientCertificate and GetCertificate are
+// derived from the context provided to HandshakeContext, and
+// that those contexts are canceled after HandshakeContext has
+// returned.
+func TestHandshakeContextHierarchy(t *testing.T) {
+ c, s := localPipe(t)
+ clientErr := make(chan error, 1)
+ clientConfig := testConfig.Clone()
+ serverConfig := testConfig.Clone()
+ ctx, cancel := context.WithCancel(context.Background())
+ defer cancel()
+ key := struct{}{}
+ ctx = context.WithValue(ctx, key, true)
+ go func() {
+ defer close(clientErr)
+ defer c.Close()
+ var innerCtx context.Context
+ clientConfig.Certificates = nil
+ clientConfig.GetClientCertificate = func(certificateRequest *CertificateRequestInfo) (*Certificate, error) {
+ if val, ok := certificateRequest.Context().Value(key).(bool); !ok || !val {
+ t.Errorf("GetClientCertificate context was not child of HandshakeContext")
+ }
+ innerCtx = certificateRequest.Context()
+ return &Certificate{
+ Certificate: [][]byte{testRSACertificate},
+ PrivateKey: testRSAPrivateKey,
+ }, nil
+ }
+ cli := Client(c, clientConfig)
+ err := cli.HandshakeContext(ctx)
+ if err != nil {
+ clientErr <- err
+ return
+ }
+ select {
+ case <-innerCtx.Done():
+ default:
+ t.Errorf("GetClientCertificate context was not canceled after HandshakeContext returned.")
+ }
+ }()
+ var innerCtx context.Context
+ serverConfig.Certificates = nil
+ serverConfig.ClientAuth = RequestClientCert
+ serverConfig.GetCertificate = func(clientHello *ClientHelloInfo) (*Certificate, error) {
+ if val, ok := clientHello.Context().Value(key).(bool); !ok || !val {
+ t.Errorf("GetClientCertificate context was not child of HandshakeContext")
+ }
+ innerCtx = clientHello.Context()
+ return &Certificate{
+ Certificate: [][]byte{testRSACertificate},
+ PrivateKey: testRSAPrivateKey,
+ }, nil
+ }
+ conn := Server(s, serverConfig)
+ err := conn.HandshakeContext(ctx)
+ if err != nil {
+ t.Errorf("Unexpected server handshake error: %v", err)
+ }
+ select {
+ case <-innerCtx.Done():
+ default:
+ t.Errorf("GetCertificate context was not canceled after HandshakeContext returned.")
+ }
+ if err := <-clientErr; err != nil {
+ t.Errorf("Unexpected client error: %v", err)
+ }
+}
diff --git a/src/crypto/tls/handshake_server_tls13.go b/src/crypto/tls/handshake_server_tls13.go
new file mode 100644
index 0000000..b7b568c
--- /dev/null
+++ b/src/crypto/tls/handshake_server_tls13.go
@@ -0,0 +1,893 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "bytes"
+ "context"
+ "crypto"
+ "crypto/hmac"
+ "crypto/rsa"
+ "encoding/binary"
+ "errors"
+ "hash"
+ "io"
+ "time"
+)
+
+// maxClientPSKIdentities is the number of client PSK identities the server will
+// attempt to validate. It will ignore the rest not to let cheap ClientHello
+// messages cause too much work in session ticket decryption attempts.
+const maxClientPSKIdentities = 5
+
+type serverHandshakeStateTLS13 struct {
+ c *Conn
+ ctx context.Context
+ clientHello *clientHelloMsg
+ hello *serverHelloMsg
+ sentDummyCCS bool
+ usingPSK bool
+ suite *cipherSuiteTLS13
+ cert *Certificate
+ sigAlg SignatureScheme
+ earlySecret []byte
+ sharedKey []byte
+ handshakeSecret []byte
+ masterSecret []byte
+ trafficSecret []byte // client_application_traffic_secret_0
+ transcript hash.Hash
+ clientFinished []byte
+}
+
+func (hs *serverHandshakeStateTLS13) handshake() error {
+ c := hs.c
+
+ if needFIPS() {
+ return errors.New("tls: internal error: TLS 1.3 reached in FIPS mode")
+ }
+
+ // For an overview of the TLS 1.3 handshake, see RFC 8446, Section 2.
+ if err := hs.processClientHello(); err != nil {
+ return err
+ }
+ if err := hs.checkForResumption(); err != nil {
+ return err
+ }
+ if err := hs.pickCertificate(); err != nil {
+ return err
+ }
+ c.buffering = true
+ if err := hs.sendServerParameters(); err != nil {
+ return err
+ }
+ if err := hs.sendServerCertificate(); err != nil {
+ return err
+ }
+ if err := hs.sendServerFinished(); err != nil {
+ return err
+ }
+ // Note that at this point we could start sending application data without
+ // waiting for the client's second flight, but the application might not
+ // expect the lack of replay protection of the ClientHello parameters.
+ if _, err := c.flush(); err != nil {
+ return err
+ }
+ if err := hs.readClientCertificate(); err != nil {
+ return err
+ }
+ if err := hs.readClientFinished(); err != nil {
+ return err
+ }
+
+ c.isHandshakeComplete.Store(true)
+
+ return nil
+}
+
+func (hs *serverHandshakeStateTLS13) processClientHello() error {
+ c := hs.c
+
+ hs.hello = new(serverHelloMsg)
+
+ // TLS 1.3 froze the ServerHello.legacy_version field, and uses
+ // supported_versions instead. See RFC 8446, sections 4.1.3 and 4.2.1.
+ hs.hello.vers = VersionTLS12
+ hs.hello.supportedVersion = c.vers
+
+ if len(hs.clientHello.supportedVersions) == 0 {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: client used the legacy version field to negotiate TLS 1.3")
+ }
+
+ // Abort if the client is doing a fallback and landing lower than what we
+ // support. See RFC 7507, which however does not specify the interaction
+ // with supported_versions. The only difference is that with
+ // supported_versions a client has a chance to attempt a [TLS 1.2, TLS 1.4]
+ // handshake in case TLS 1.3 is broken but 1.2 is not. Alas, in that case,
+ // it will have to drop the TLS_FALLBACK_SCSV protection if it falls back to
+ // TLS 1.2, because a TLS 1.3 server would abort here. The situation before
+ // supported_versions was not better because there was just no way to do a
+ // TLS 1.4 handshake without risking the server selecting TLS 1.3.
+ for _, id := range hs.clientHello.cipherSuites {
+ if id == TLS_FALLBACK_SCSV {
+ // Use c.vers instead of max(supported_versions) because an attacker
+ // could defeat this by adding an arbitrary high version otherwise.
+ if c.vers < c.config.maxSupportedVersion(roleServer) {
+ c.sendAlert(alertInappropriateFallback)
+ return errors.New("tls: client using inappropriate protocol fallback")
+ }
+ break
+ }
+ }
+
+ if len(hs.clientHello.compressionMethods) != 1 ||
+ hs.clientHello.compressionMethods[0] != compressionNone {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: TLS 1.3 client supports illegal compression methods")
+ }
+
+ hs.hello.random = make([]byte, 32)
+ if _, err := io.ReadFull(c.config.rand(), hs.hello.random); err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ if len(hs.clientHello.secureRenegotiation) != 0 {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: initial handshake had non-empty renegotiation extension")
+ }
+
+ if hs.clientHello.earlyData {
+ // See RFC 8446, Section 4.2.10 for the complicated behavior required
+ // here. The scenario is that a different server at our address offered
+ // to accept early data in the past, which we can't handle. For now, all
+ // 0-RTT enabled session tickets need to expire before a Go server can
+ // replace a server or join a pool. That's the same requirement that
+ // applies to mixing or replacing with any TLS 1.2 server.
+ c.sendAlert(alertUnsupportedExtension)
+ return errors.New("tls: client sent unexpected early data")
+ }
+
+ hs.hello.sessionId = hs.clientHello.sessionId
+ hs.hello.compressionMethod = compressionNone
+
+ preferenceList := defaultCipherSuitesTLS13
+ if !hasAESGCMHardwareSupport || !aesgcmPreferred(hs.clientHello.cipherSuites) {
+ preferenceList = defaultCipherSuitesTLS13NoAES
+ }
+ for _, suiteID := range preferenceList {
+ hs.suite = mutualCipherSuiteTLS13(hs.clientHello.cipherSuites, suiteID)
+ if hs.suite != nil {
+ break
+ }
+ }
+ if hs.suite == nil {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: no cipher suite supported by both client and server")
+ }
+ c.cipherSuite = hs.suite.id
+ hs.hello.cipherSuite = hs.suite.id
+ hs.transcript = hs.suite.hash.New()
+
+ // Pick the ECDHE group in server preference order, but give priority to
+ // groups with a key share, to avoid a HelloRetryRequest round-trip.
+ var selectedGroup CurveID
+ var clientKeyShare *keyShare
+GroupSelection:
+ for _, preferredGroup := range c.config.curvePreferences() {
+ for _, ks := range hs.clientHello.keyShares {
+ if ks.group == preferredGroup {
+ selectedGroup = ks.group
+ clientKeyShare = &ks
+ break GroupSelection
+ }
+ }
+ if selectedGroup != 0 {
+ continue
+ }
+ for _, group := range hs.clientHello.supportedCurves {
+ if group == preferredGroup {
+ selectedGroup = group
+ break
+ }
+ }
+ }
+ if selectedGroup == 0 {
+ c.sendAlert(alertHandshakeFailure)
+ return errors.New("tls: no ECDHE curve supported by both client and server")
+ }
+ if clientKeyShare == nil {
+ if err := hs.doHelloRetryRequest(selectedGroup); err != nil {
+ return err
+ }
+ clientKeyShare = &hs.clientHello.keyShares[0]
+ }
+
+ if _, ok := curveForCurveID(selectedGroup); !ok {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: CurvePreferences includes unsupported curve")
+ }
+ key, err := generateECDHEKey(c.config.rand(), selectedGroup)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ hs.hello.serverShare = keyShare{group: selectedGroup, data: key.PublicKey().Bytes()}
+ peerKey, err := key.Curve().NewPublicKey(clientKeyShare.data)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid client key share")
+ }
+ hs.sharedKey, err = key.ECDH(peerKey)
+ if err != nil {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid client key share")
+ }
+
+ c.serverName = hs.clientHello.serverName
+ return nil
+}
+
+func (hs *serverHandshakeStateTLS13) checkForResumption() error {
+ c := hs.c
+
+ if c.config.SessionTicketsDisabled {
+ return nil
+ }
+
+ modeOK := false
+ for _, mode := range hs.clientHello.pskModes {
+ if mode == pskModeDHE {
+ modeOK = true
+ break
+ }
+ }
+ if !modeOK {
+ return nil
+ }
+
+ if len(hs.clientHello.pskIdentities) != len(hs.clientHello.pskBinders) {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: invalid or missing PSK binders")
+ }
+ if len(hs.clientHello.pskIdentities) == 0 {
+ return nil
+ }
+
+ for i, identity := range hs.clientHello.pskIdentities {
+ if i >= maxClientPSKIdentities {
+ break
+ }
+
+ plaintext, _ := c.decryptTicket(identity.label)
+ if plaintext == nil {
+ continue
+ }
+ sessionState := new(sessionStateTLS13)
+ if ok := sessionState.unmarshal(plaintext); !ok {
+ continue
+ }
+
+ createdAt := time.Unix(int64(sessionState.createdAt), 0)
+ if c.config.time().Sub(createdAt) > maxSessionTicketLifetime {
+ continue
+ }
+
+ // We don't check the obfuscated ticket age because it's affected by
+ // clock skew and it's only a freshness signal useful for shrinking the
+ // window for replay attacks, which don't affect us as we don't do 0-RTT.
+
+ pskSuite := cipherSuiteTLS13ByID(sessionState.cipherSuite)
+ if pskSuite == nil || pskSuite.hash != hs.suite.hash {
+ continue
+ }
+
+ // PSK connections don't re-establish client certificates, but carry
+ // them over in the session ticket. Ensure the presence of client certs
+ // in the ticket is consistent with the configured requirements.
+ sessionHasClientCerts := len(sessionState.certificate.Certificate) != 0
+ needClientCerts := requiresClientCert(c.config.ClientAuth)
+ if needClientCerts && !sessionHasClientCerts {
+ continue
+ }
+ if sessionHasClientCerts && c.config.ClientAuth == NoClientCert {
+ continue
+ }
+
+ psk := hs.suite.expandLabel(sessionState.resumptionSecret, "resumption",
+ nil, hs.suite.hash.Size())
+ hs.earlySecret = hs.suite.extract(psk, nil)
+ binderKey := hs.suite.deriveSecret(hs.earlySecret, resumptionBinderLabel, nil)
+ // Clone the transcript in case a HelloRetryRequest was recorded.
+ transcript := cloneHash(hs.transcript, hs.suite.hash)
+ if transcript == nil {
+ c.sendAlert(alertInternalError)
+ return errors.New("tls: internal error: failed to clone hash")
+ }
+ clientHelloBytes, err := hs.clientHello.marshalWithoutBinders()
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ transcript.Write(clientHelloBytes)
+ pskBinder := hs.suite.finishedHash(binderKey, transcript)
+ if !hmac.Equal(hs.clientHello.pskBinders[i], pskBinder) {
+ c.sendAlert(alertDecryptError)
+ return errors.New("tls: invalid PSK binder")
+ }
+
+ c.didResume = true
+ if err := c.processCertsFromClient(sessionState.certificate); err != nil {
+ return err
+ }
+
+ hs.hello.selectedIdentityPresent = true
+ hs.hello.selectedIdentity = uint16(i)
+ hs.usingPSK = true
+ return nil
+ }
+
+ return nil
+}
+
+// cloneHash uses the encoding.BinaryMarshaler and encoding.BinaryUnmarshaler
+// interfaces implemented by standard library hashes to clone the state of in
+// to a new instance of h. It returns nil if the operation fails.
+func cloneHash(in hash.Hash, h crypto.Hash) hash.Hash {
+ // Recreate the interface to avoid importing encoding.
+ type binaryMarshaler interface {
+ MarshalBinary() (data []byte, err error)
+ UnmarshalBinary(data []byte) error
+ }
+ marshaler, ok := in.(binaryMarshaler)
+ if !ok {
+ return nil
+ }
+ state, err := marshaler.MarshalBinary()
+ if err != nil {
+ return nil
+ }
+ out := h.New()
+ unmarshaler, ok := out.(binaryMarshaler)
+ if !ok {
+ return nil
+ }
+ if err := unmarshaler.UnmarshalBinary(state); err != nil {
+ return nil
+ }
+ return out
+}
+
+func (hs *serverHandshakeStateTLS13) pickCertificate() error {
+ c := hs.c
+
+ // Only one of PSK and certificates are used at a time.
+ if hs.usingPSK {
+ return nil
+ }
+
+ // signature_algorithms is required in TLS 1.3. See RFC 8446, Section 4.2.3.
+ if len(hs.clientHello.supportedSignatureAlgorithms) == 0 {
+ return c.sendAlert(alertMissingExtension)
+ }
+
+ certificate, err := c.config.getCertificate(clientHelloInfo(hs.ctx, c, hs.clientHello))
+ if err != nil {
+ if err == errNoCertificates {
+ c.sendAlert(alertUnrecognizedName)
+ } else {
+ c.sendAlert(alertInternalError)
+ }
+ return err
+ }
+ hs.sigAlg, err = selectSignatureScheme(c.vers, certificate, hs.clientHello.supportedSignatureAlgorithms)
+ if err != nil {
+ // getCertificate returned a certificate that is unsupported or
+ // incompatible with the client's signature algorithms.
+ c.sendAlert(alertHandshakeFailure)
+ return err
+ }
+ hs.cert = certificate
+
+ return nil
+}
+
+// sendDummyChangeCipherSpec sends a ChangeCipherSpec record for compatibility
+// with middleboxes that didn't implement TLS correctly. See RFC 8446, Appendix D.4.
+func (hs *serverHandshakeStateTLS13) sendDummyChangeCipherSpec() error {
+ if hs.sentDummyCCS {
+ return nil
+ }
+ hs.sentDummyCCS = true
+
+ return hs.c.writeChangeCipherRecord()
+}
+
+func (hs *serverHandshakeStateTLS13) doHelloRetryRequest(selectedGroup CurveID) error {
+ c := hs.c
+
+ // The first ClientHello gets double-hashed into the transcript upon a
+ // HelloRetryRequest. See RFC 8446, Section 4.4.1.
+ if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil {
+ return err
+ }
+ chHash := hs.transcript.Sum(nil)
+ hs.transcript.Reset()
+ hs.transcript.Write([]byte{typeMessageHash, 0, 0, uint8(len(chHash))})
+ hs.transcript.Write(chHash)
+
+ helloRetryRequest := &serverHelloMsg{
+ vers: hs.hello.vers,
+ random: helloRetryRequestRandom,
+ sessionId: hs.hello.sessionId,
+ cipherSuite: hs.hello.cipherSuite,
+ compressionMethod: hs.hello.compressionMethod,
+ supportedVersion: hs.hello.supportedVersion,
+ selectedGroup: selectedGroup,
+ }
+
+ if _, err := hs.c.writeHandshakeRecord(helloRetryRequest, hs.transcript); err != nil {
+ return err
+ }
+
+ if err := hs.sendDummyChangeCipherSpec(); err != nil {
+ return err
+ }
+
+ // clientHelloMsg is not included in the transcript.
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ clientHello, ok := msg.(*clientHelloMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(clientHello, msg)
+ }
+
+ if len(clientHello.keyShares) != 1 || clientHello.keyShares[0].group != selectedGroup {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: client sent invalid key share in second ClientHello")
+ }
+
+ if clientHello.earlyData {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: client indicated early data in second ClientHello")
+ }
+
+ if illegalClientHelloChange(clientHello, hs.clientHello) {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: client illegally modified second ClientHello")
+ }
+
+ hs.clientHello = clientHello
+ return nil
+}
+
+// illegalClientHelloChange reports whether the two ClientHello messages are
+// different, with the exception of the changes allowed before and after a
+// HelloRetryRequest. See RFC 8446, Section 4.1.2.
+func illegalClientHelloChange(ch, ch1 *clientHelloMsg) bool {
+ if len(ch.supportedVersions) != len(ch1.supportedVersions) ||
+ len(ch.cipherSuites) != len(ch1.cipherSuites) ||
+ len(ch.supportedCurves) != len(ch1.supportedCurves) ||
+ len(ch.supportedSignatureAlgorithms) != len(ch1.supportedSignatureAlgorithms) ||
+ len(ch.supportedSignatureAlgorithmsCert) != len(ch1.supportedSignatureAlgorithmsCert) ||
+ len(ch.alpnProtocols) != len(ch1.alpnProtocols) {
+ return true
+ }
+ for i := range ch.supportedVersions {
+ if ch.supportedVersions[i] != ch1.supportedVersions[i] {
+ return true
+ }
+ }
+ for i := range ch.cipherSuites {
+ if ch.cipherSuites[i] != ch1.cipherSuites[i] {
+ return true
+ }
+ }
+ for i := range ch.supportedCurves {
+ if ch.supportedCurves[i] != ch1.supportedCurves[i] {
+ return true
+ }
+ }
+ for i := range ch.supportedSignatureAlgorithms {
+ if ch.supportedSignatureAlgorithms[i] != ch1.supportedSignatureAlgorithms[i] {
+ return true
+ }
+ }
+ for i := range ch.supportedSignatureAlgorithmsCert {
+ if ch.supportedSignatureAlgorithmsCert[i] != ch1.supportedSignatureAlgorithmsCert[i] {
+ return true
+ }
+ }
+ for i := range ch.alpnProtocols {
+ if ch.alpnProtocols[i] != ch1.alpnProtocols[i] {
+ return true
+ }
+ }
+ return ch.vers != ch1.vers ||
+ !bytes.Equal(ch.random, ch1.random) ||
+ !bytes.Equal(ch.sessionId, ch1.sessionId) ||
+ !bytes.Equal(ch.compressionMethods, ch1.compressionMethods) ||
+ ch.serverName != ch1.serverName ||
+ ch.ocspStapling != ch1.ocspStapling ||
+ !bytes.Equal(ch.supportedPoints, ch1.supportedPoints) ||
+ ch.ticketSupported != ch1.ticketSupported ||
+ !bytes.Equal(ch.sessionTicket, ch1.sessionTicket) ||
+ ch.secureRenegotiationSupported != ch1.secureRenegotiationSupported ||
+ !bytes.Equal(ch.secureRenegotiation, ch1.secureRenegotiation) ||
+ ch.scts != ch1.scts ||
+ !bytes.Equal(ch.cookie, ch1.cookie) ||
+ !bytes.Equal(ch.pskModes, ch1.pskModes)
+}
+
+func (hs *serverHandshakeStateTLS13) sendServerParameters() error {
+ c := hs.c
+
+ if err := transcriptMsg(hs.clientHello, hs.transcript); err != nil {
+ return err
+ }
+ if _, err := hs.c.writeHandshakeRecord(hs.hello, hs.transcript); err != nil {
+ return err
+ }
+
+ if err := hs.sendDummyChangeCipherSpec(); err != nil {
+ return err
+ }
+
+ earlySecret := hs.earlySecret
+ if earlySecret == nil {
+ earlySecret = hs.suite.extract(nil, nil)
+ }
+ hs.handshakeSecret = hs.suite.extract(hs.sharedKey,
+ hs.suite.deriveSecret(earlySecret, "derived", nil))
+
+ clientSecret := hs.suite.deriveSecret(hs.handshakeSecret,
+ clientHandshakeTrafficLabel, hs.transcript)
+ c.in.setTrafficSecret(hs.suite, clientSecret)
+ serverSecret := hs.suite.deriveSecret(hs.handshakeSecret,
+ serverHandshakeTrafficLabel, hs.transcript)
+ c.out.setTrafficSecret(hs.suite, serverSecret)
+
+ err := c.config.writeKeyLog(keyLogLabelClientHandshake, hs.clientHello.random, clientSecret)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ err = c.config.writeKeyLog(keyLogLabelServerHandshake, hs.clientHello.random, serverSecret)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ encryptedExtensions := new(encryptedExtensionsMsg)
+
+ selectedProto, err := negotiateALPN(c.config.NextProtos, hs.clientHello.alpnProtocols)
+ if err != nil {
+ c.sendAlert(alertNoApplicationProtocol)
+ return err
+ }
+ encryptedExtensions.alpnProtocol = selectedProto
+ c.clientProtocol = selectedProto
+
+ if _, err := hs.c.writeHandshakeRecord(encryptedExtensions, hs.transcript); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (hs *serverHandshakeStateTLS13) requestClientCert() bool {
+ return hs.c.config.ClientAuth >= RequestClientCert && !hs.usingPSK
+}
+
+func (hs *serverHandshakeStateTLS13) sendServerCertificate() error {
+ c := hs.c
+
+ // Only one of PSK and certificates are used at a time.
+ if hs.usingPSK {
+ return nil
+ }
+
+ if hs.requestClientCert() {
+ // Request a client certificate
+ certReq := new(certificateRequestMsgTLS13)
+ certReq.ocspStapling = true
+ certReq.scts = true
+ certReq.supportedSignatureAlgorithms = supportedSignatureAlgorithms()
+ if c.config.ClientCAs != nil {
+ certReq.certificateAuthorities = c.config.ClientCAs.Subjects()
+ }
+
+ if _, err := hs.c.writeHandshakeRecord(certReq, hs.transcript); err != nil {
+ return err
+ }
+ }
+
+ certMsg := new(certificateMsgTLS13)
+
+ certMsg.certificate = *hs.cert
+ certMsg.scts = hs.clientHello.scts && len(hs.cert.SignedCertificateTimestamps) > 0
+ certMsg.ocspStapling = hs.clientHello.ocspStapling && len(hs.cert.OCSPStaple) > 0
+
+ if _, err := hs.c.writeHandshakeRecord(certMsg, hs.transcript); err != nil {
+ return err
+ }
+
+ certVerifyMsg := new(certificateVerifyMsg)
+ certVerifyMsg.hasSignatureAlgorithm = true
+ certVerifyMsg.signatureAlgorithm = hs.sigAlg
+
+ sigType, sigHash, err := typeAndHashFromSignatureScheme(hs.sigAlg)
+ if err != nil {
+ return c.sendAlert(alertInternalError)
+ }
+
+ signed := signedMessage(sigHash, serverSignatureContext, hs.transcript)
+ signOpts := crypto.SignerOpts(sigHash)
+ if sigType == signatureRSAPSS {
+ signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
+ }
+ sig, err := hs.cert.PrivateKey.(crypto.Signer).Sign(c.config.rand(), signed, signOpts)
+ if err != nil {
+ public := hs.cert.PrivateKey.(crypto.Signer).Public()
+ if rsaKey, ok := public.(*rsa.PublicKey); ok && sigType == signatureRSAPSS &&
+ rsaKey.N.BitLen()/8 < sigHash.Size()*2+2 { // key too small for RSA-PSS
+ c.sendAlert(alertHandshakeFailure)
+ } else {
+ c.sendAlert(alertInternalError)
+ }
+ return errors.New("tls: failed to sign handshake: " + err.Error())
+ }
+ certVerifyMsg.signature = sig
+
+ if _, err := hs.c.writeHandshakeRecord(certVerifyMsg, hs.transcript); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (hs *serverHandshakeStateTLS13) sendServerFinished() error {
+ c := hs.c
+
+ finished := &finishedMsg{
+ verifyData: hs.suite.finishedHash(c.out.trafficSecret, hs.transcript),
+ }
+
+ if _, err := hs.c.writeHandshakeRecord(finished, hs.transcript); err != nil {
+ return err
+ }
+
+ // Derive secrets that take context through the server Finished.
+
+ hs.masterSecret = hs.suite.extract(nil,
+ hs.suite.deriveSecret(hs.handshakeSecret, "derived", nil))
+
+ hs.trafficSecret = hs.suite.deriveSecret(hs.masterSecret,
+ clientApplicationTrafficLabel, hs.transcript)
+ serverSecret := hs.suite.deriveSecret(hs.masterSecret,
+ serverApplicationTrafficLabel, hs.transcript)
+ c.out.setTrafficSecret(hs.suite, serverSecret)
+
+ err := c.config.writeKeyLog(keyLogLabelClientTraffic, hs.clientHello.random, hs.trafficSecret)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ err = c.config.writeKeyLog(keyLogLabelServerTraffic, hs.clientHello.random, serverSecret)
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+
+ c.ekm = hs.suite.exportKeyingMaterial(hs.masterSecret, hs.transcript)
+
+ // If we did not request client certificates, at this point we can
+ // precompute the client finished and roll the transcript forward to send
+ // session tickets in our first flight.
+ if !hs.requestClientCert() {
+ if err := hs.sendSessionTickets(); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func (hs *serverHandshakeStateTLS13) shouldSendSessionTickets() bool {
+ if hs.c.config.SessionTicketsDisabled {
+ return false
+ }
+
+ // Don't send tickets the client wouldn't use. See RFC 8446, Section 4.2.9.
+ for _, pskMode := range hs.clientHello.pskModes {
+ if pskMode == pskModeDHE {
+ return true
+ }
+ }
+ return false
+}
+
+func (hs *serverHandshakeStateTLS13) sendSessionTickets() error {
+ c := hs.c
+
+ hs.clientFinished = hs.suite.finishedHash(c.in.trafficSecret, hs.transcript)
+ finishedMsg := &finishedMsg{
+ verifyData: hs.clientFinished,
+ }
+ if err := transcriptMsg(finishedMsg, hs.transcript); err != nil {
+ return err
+ }
+
+ if !hs.shouldSendSessionTickets() {
+ return nil
+ }
+
+ resumptionSecret := hs.suite.deriveSecret(hs.masterSecret,
+ resumptionLabel, hs.transcript)
+
+ m := new(newSessionTicketMsgTLS13)
+
+ var certsFromClient [][]byte
+ for _, cert := range c.peerCertificates {
+ certsFromClient = append(certsFromClient, cert.Raw)
+ }
+ state := sessionStateTLS13{
+ cipherSuite: hs.suite.id,
+ createdAt: uint64(c.config.time().Unix()),
+ resumptionSecret: resumptionSecret,
+ certificate: Certificate{
+ Certificate: certsFromClient,
+ OCSPStaple: c.ocspResponse,
+ SignedCertificateTimestamps: c.scts,
+ },
+ }
+ stateBytes, err := state.marshal()
+ if err != nil {
+ c.sendAlert(alertInternalError)
+ return err
+ }
+ m.label, err = c.encryptTicket(stateBytes)
+ if err != nil {
+ return err
+ }
+ m.lifetime = uint32(maxSessionTicketLifetime / time.Second)
+
+ // ticket_age_add is a random 32-bit value. See RFC 8446, section 4.6.1
+ // The value is not stored anywhere; we never need to check the ticket age
+ // because 0-RTT is not supported.
+ ageAdd := make([]byte, 4)
+ _, err = hs.c.config.rand().Read(ageAdd)
+ if err != nil {
+ return err
+ }
+ m.ageAdd = binary.LittleEndian.Uint32(ageAdd)
+
+ // ticket_nonce, which must be unique per connection, is always left at
+ // zero because we only ever send one ticket per connection.
+
+ if _, err := c.writeHandshakeRecord(m, nil); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (hs *serverHandshakeStateTLS13) readClientCertificate() error {
+ c := hs.c
+
+ if !hs.requestClientCert() {
+ // Make sure the connection is still being verified whether or not
+ // the server requested a client certificate.
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+ return nil
+ }
+
+ // If we requested a client certificate, then the client must send a
+ // certificate message. If it's empty, no CertificateVerify is sent.
+
+ msg, err := c.readHandshake(hs.transcript)
+ if err != nil {
+ return err
+ }
+
+ certMsg, ok := msg.(*certificateMsgTLS13)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certMsg, msg)
+ }
+
+ if err := c.processCertsFromClient(certMsg.certificate); err != nil {
+ return err
+ }
+
+ if c.config.VerifyConnection != nil {
+ if err := c.config.VerifyConnection(c.connectionStateLocked()); err != nil {
+ c.sendAlert(alertBadCertificate)
+ return err
+ }
+ }
+
+ if len(certMsg.certificate.Certificate) != 0 {
+ // certificateVerifyMsg is included in the transcript, but not until
+ // after we verify the handshake signature, since the state before
+ // this message was sent is used.
+ msg, err = c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ certVerify, ok := msg.(*certificateVerifyMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(certVerify, msg)
+ }
+
+ // See RFC 8446, Section 4.4.3.
+ if !isSupportedSignatureAlgorithm(certVerify.signatureAlgorithm, supportedSignatureAlgorithms()) {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: client certificate used with invalid signature algorithm")
+ }
+ sigType, sigHash, err := typeAndHashFromSignatureScheme(certVerify.signatureAlgorithm)
+ if err != nil {
+ return c.sendAlert(alertInternalError)
+ }
+ if sigType == signaturePKCS1v15 || sigHash == crypto.SHA1 {
+ c.sendAlert(alertIllegalParameter)
+ return errors.New("tls: client certificate used with invalid signature algorithm")
+ }
+ signed := signedMessage(sigHash, clientSignatureContext, hs.transcript)
+ if err := verifyHandshakeSignature(sigType, c.peerCertificates[0].PublicKey,
+ sigHash, signed, certVerify.signature); err != nil {
+ c.sendAlert(alertDecryptError)
+ return errors.New("tls: invalid signature by the client certificate: " + err.Error())
+ }
+
+ if err := transcriptMsg(certVerify, hs.transcript); err != nil {
+ return err
+ }
+ }
+
+ // If we waited until the client certificates to send session tickets, we
+ // are ready to do it now.
+ if err := hs.sendSessionTickets(); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (hs *serverHandshakeStateTLS13) readClientFinished() error {
+ c := hs.c
+
+ // finishedMsg is not included in the transcript.
+ msg, err := c.readHandshake(nil)
+ if err != nil {
+ return err
+ }
+
+ finished, ok := msg.(*finishedMsg)
+ if !ok {
+ c.sendAlert(alertUnexpectedMessage)
+ return unexpectedMessageError(finished, msg)
+ }
+
+ if !hmac.Equal(hs.clientFinished, finished.verifyData) {
+ c.sendAlert(alertDecryptError)
+ return errors.New("tls: invalid client finished hash")
+ }
+
+ c.in.setTrafficSecret(hs.suite, hs.trafficSecret)
+
+ return nil
+}
diff --git a/src/crypto/tls/handshake_test.go b/src/crypto/tls/handshake_test.go
new file mode 100644
index 0000000..bacc8b7
--- /dev/null
+++ b/src/crypto/tls/handshake_test.go
@@ -0,0 +1,530 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "bufio"
+ "crypto/ed25519"
+ "crypto/x509"
+ "encoding/hex"
+ "errors"
+ "flag"
+ "fmt"
+ "io"
+ "net"
+ "os"
+ "os/exec"
+ "runtime"
+ "strconv"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+)
+
+// TLS reference tests run a connection against a reference implementation
+// (OpenSSL) of TLS and record the bytes of the resulting connection. The Go
+// code, during a test, is configured with deterministic randomness and so the
+// reference test can be reproduced exactly in the future.
+//
+// In order to save everyone who wishes to run the tests from needing the
+// reference implementation installed, the reference connections are saved in
+// files in the testdata directory. Thus running the tests involves nothing
+// external, but creating and updating them requires the reference
+// implementation.
+//
+// Tests can be updated by running them with the -update flag. This will cause
+// the test files for failing tests to be regenerated. Since the reference
+// implementation will always generate fresh random numbers, large parts of the
+// reference connection will always change.
+
+var (
+ update = flag.Bool("update", false, "update golden files on failure")
+ fast = flag.Bool("fast", false, "impose a quick, possibly flaky timeout on recorded tests")
+ keyFile = flag.String("keylog", "", "destination file for KeyLogWriter")
+)
+
+func runTestAndUpdateIfNeeded(t *testing.T, name string, run func(t *testing.T, update bool), wait bool) {
+ success := t.Run(name, func(t *testing.T) {
+ if !*update && !wait {
+ t.Parallel()
+ }
+ run(t, false)
+ })
+
+ if !success && *update {
+ t.Run(name+"#update", func(t *testing.T) {
+ run(t, true)
+ })
+ }
+}
+
+// checkOpenSSLVersion ensures that the version of OpenSSL looks reasonable
+// before updating the test data.
+func checkOpenSSLVersion() error {
+ if !*update {
+ return nil
+ }
+
+ openssl := exec.Command("openssl", "version")
+ output, err := openssl.CombinedOutput()
+ if err != nil {
+ return err
+ }
+
+ version := string(output)
+ if strings.HasPrefix(version, "OpenSSL 1.1.1") {
+ return nil
+ }
+
+ println("***********************************************")
+ println("")
+ println("You need to build OpenSSL 1.1.1 from source in order")
+ println("to update the test data.")
+ println("")
+ println("Configure it with:")
+ println("./Configure enable-weak-ssl-ciphers no-shared")
+ println("and then add the apps/ directory at the front of your PATH.")
+ println("***********************************************")
+
+ return errors.New("version of OpenSSL does not appear to be suitable for updating test data")
+}
+
+// recordingConn is a net.Conn that records the traffic that passes through it.
+// WriteTo can be used to produce output that can be later be loaded with
+// ParseTestData.
+type recordingConn struct {
+ net.Conn
+ sync.Mutex
+ flows [][]byte
+ reading bool
+}
+
+func (r *recordingConn) Read(b []byte) (n int, err error) {
+ if n, err = r.Conn.Read(b); n == 0 {
+ return
+ }
+ b = b[:n]
+
+ r.Lock()
+ defer r.Unlock()
+
+ if l := len(r.flows); l == 0 || !r.reading {
+ buf := make([]byte, len(b))
+ copy(buf, b)
+ r.flows = append(r.flows, buf)
+ } else {
+ r.flows[l-1] = append(r.flows[l-1], b[:n]...)
+ }
+ r.reading = true
+ return
+}
+
+func (r *recordingConn) Write(b []byte) (n int, err error) {
+ if n, err = r.Conn.Write(b); n == 0 {
+ return
+ }
+ b = b[:n]
+
+ r.Lock()
+ defer r.Unlock()
+
+ if l := len(r.flows); l == 0 || r.reading {
+ buf := make([]byte, len(b))
+ copy(buf, b)
+ r.flows = append(r.flows, buf)
+ } else {
+ r.flows[l-1] = append(r.flows[l-1], b[:n]...)
+ }
+ r.reading = false
+ return
+}
+
+// WriteTo writes Go source code to w that contains the recorded traffic.
+func (r *recordingConn) WriteTo(w io.Writer) (int64, error) {
+ // TLS always starts with a client to server flow.
+ clientToServer := true
+ var written int64
+ for i, flow := range r.flows {
+ source, dest := "client", "server"
+ if !clientToServer {
+ source, dest = dest, source
+ }
+ n, err := fmt.Fprintf(w, ">>> Flow %d (%s to %s)\n", i+1, source, dest)
+ written += int64(n)
+ if err != nil {
+ return written, err
+ }
+ dumper := hex.Dumper(w)
+ n, err = dumper.Write(flow)
+ written += int64(n)
+ if err != nil {
+ return written, err
+ }
+ err = dumper.Close()
+ if err != nil {
+ return written, err
+ }
+ clientToServer = !clientToServer
+ }
+ return written, nil
+}
+
+func parseTestData(r io.Reader) (flows [][]byte, err error) {
+ var currentFlow []byte
+
+ scanner := bufio.NewScanner(r)
+ for scanner.Scan() {
+ line := scanner.Text()
+ // If the line starts with ">>> " then it marks the beginning
+ // of a new flow.
+ if strings.HasPrefix(line, ">>> ") {
+ if len(currentFlow) > 0 || len(flows) > 0 {
+ flows = append(flows, currentFlow)
+ currentFlow = nil
+ }
+ continue
+ }
+
+ // Otherwise the line is a line of hex dump that looks like:
+ // 00000170 fc f5 06 bf (...) |.....X{&?......!|
+ // (Some bytes have been omitted from the middle section.)
+ _, after, ok := strings.Cut(line, " ")
+ if !ok {
+ return nil, errors.New("invalid test data")
+ }
+ line = after
+
+ before, _, ok := strings.Cut(line, "|")
+ if !ok {
+ return nil, errors.New("invalid test data")
+ }
+ line = before
+
+ hexBytes := strings.Fields(line)
+ for _, hexByte := range hexBytes {
+ val, err := strconv.ParseUint(hexByte, 16, 8)
+ if err != nil {
+ return nil, errors.New("invalid hex byte in test data: " + err.Error())
+ }
+ currentFlow = append(currentFlow, byte(val))
+ }
+ }
+
+ if len(currentFlow) > 0 {
+ flows = append(flows, currentFlow)
+ }
+
+ return flows, nil
+}
+
+// tempFile creates a temp file containing contents and returns its path.
+func tempFile(contents string) string {
+ file, err := os.CreateTemp("", "go-tls-test")
+ if err != nil {
+ panic("failed to create temp file: " + err.Error())
+ }
+ path := file.Name()
+ file.WriteString(contents)
+ file.Close()
+ return path
+}
+
+// localListener is set up by TestMain and used by localPipe to create Conn
+// pairs like net.Pipe, but connected by an actual buffered TCP connection.
+var localListener struct {
+ mu sync.Mutex
+ addr net.Addr
+ ch chan net.Conn
+}
+
+const localFlakes = 0 // change to 1 or 2 to exercise localServer/localPipe handling of mismatches
+
+func localServer(l net.Listener) {
+ for n := 0; ; n++ {
+ c, err := l.Accept()
+ if err != nil {
+ return
+ }
+ if localFlakes == 1 && n%2 == 0 {
+ c.Close()
+ continue
+ }
+ localListener.ch <- c
+ }
+}
+
+var isConnRefused = func(err error) bool { return false }
+
+func localPipe(t testing.TB) (net.Conn, net.Conn) {
+ localListener.mu.Lock()
+ defer localListener.mu.Unlock()
+
+ addr := localListener.addr
+
+ var err error
+Dialing:
+ // We expect a rare mismatch, but probably not 5 in a row.
+ for i := 0; i < 5; i++ {
+ tooSlow := time.NewTimer(1 * time.Second)
+ defer tooSlow.Stop()
+ var c1 net.Conn
+ c1, err = net.Dial(addr.Network(), addr.String())
+ if err != nil {
+ if runtime.GOOS == "dragonfly" && (isConnRefused(err) || os.IsTimeout(err)) {
+ // golang.org/issue/29583: Dragonfly sometimes returns a spurious
+ // ECONNREFUSED or ETIMEDOUT.
+ <-tooSlow.C
+ continue
+ }
+ t.Fatalf("localPipe: %v", err)
+ }
+ if localFlakes == 2 && i == 0 {
+ c1.Close()
+ continue
+ }
+ for {
+ select {
+ case <-tooSlow.C:
+ t.Logf("localPipe: timeout waiting for %v", c1.LocalAddr())
+ c1.Close()
+ continue Dialing
+
+ case c2 := <-localListener.ch:
+ if c2.RemoteAddr().String() == c1.LocalAddr().String() {
+ return c1, c2
+ }
+ t.Logf("localPipe: unexpected connection: %v != %v", c2.RemoteAddr(), c1.LocalAddr())
+ c2.Close()
+ }
+ }
+ }
+
+ t.Fatalf("localPipe: failed to connect: %v", err)
+ panic("unreachable")
+}
+
+// zeroSource is an io.Reader that returns an unlimited number of zero bytes.
+type zeroSource struct{}
+
+func (zeroSource) Read(b []byte) (n int, err error) {
+ for i := range b {
+ b[i] = 0
+ }
+
+ return len(b), nil
+}
+
+func allCipherSuites() []uint16 {
+ ids := make([]uint16, len(cipherSuites))
+ for i, suite := range cipherSuites {
+ ids[i] = suite.id
+ }
+
+ return ids
+}
+
+var testConfig *Config
+
+func TestMain(m *testing.M) {
+ flag.Parse()
+ os.Exit(runMain(m))
+}
+
+func runMain(m *testing.M) int {
+ // Cipher suites preferences change based on the architecture. Force them to
+ // the version without AES acceleration for test consistency.
+ hasAESGCMHardwareSupport = false
+
+ // Set up localPipe.
+ l, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ l, err = net.Listen("tcp6", "[::1]:0")
+ }
+ if err != nil {
+ fmt.Fprintf(os.Stderr, "Failed to open local listener: %v", err)
+ os.Exit(1)
+ }
+ localListener.ch = make(chan net.Conn)
+ localListener.addr = l.Addr()
+ defer l.Close()
+ go localServer(l)
+
+ if err := checkOpenSSLVersion(); err != nil {
+ fmt.Fprintf(os.Stderr, "Error: %v", err)
+ os.Exit(1)
+ }
+
+ testConfig = &Config{
+ Time: func() time.Time { return time.Unix(0, 0) },
+ Rand: zeroSource{},
+ Certificates: make([]Certificate, 2),
+ InsecureSkipVerify: true,
+ CipherSuites: allCipherSuites(),
+ MinVersion: VersionTLS10,
+ MaxVersion: VersionTLS13,
+ }
+ testConfig.Certificates[0].Certificate = [][]byte{testRSACertificate}
+ testConfig.Certificates[0].PrivateKey = testRSAPrivateKey
+ testConfig.Certificates[1].Certificate = [][]byte{testSNICertificate}
+ testConfig.Certificates[1].PrivateKey = testRSAPrivateKey
+ testConfig.BuildNameToCertificate()
+ if *keyFile != "" {
+ f, err := os.OpenFile(*keyFile, os.O_APPEND|os.O_CREATE|os.O_WRONLY, 0644)
+ if err != nil {
+ panic("failed to open -keylog file: " + err.Error())
+ }
+ testConfig.KeyLogWriter = f
+ defer f.Close()
+ }
+
+ return m.Run()
+}
+
+func testHandshake(t *testing.T, clientConfig, serverConfig *Config) (serverState, clientState ConnectionState, err error) {
+ const sentinel = "SENTINEL\n"
+ c, s := localPipe(t)
+ errChan := make(chan error)
+ go func() {
+ cli := Client(c, clientConfig)
+ err := cli.Handshake()
+ if err != nil {
+ errChan <- fmt.Errorf("client: %v", err)
+ c.Close()
+ return
+ }
+ defer cli.Close()
+ clientState = cli.ConnectionState()
+ buf, err := io.ReadAll(cli)
+ if err != nil {
+ t.Errorf("failed to call cli.Read: %v", err)
+ }
+ if got := string(buf); got != sentinel {
+ t.Errorf("read %q from TLS connection, but expected %q", got, sentinel)
+ }
+ errChan <- nil
+ }()
+ server := Server(s, serverConfig)
+ err = server.Handshake()
+ if err == nil {
+ serverState = server.ConnectionState()
+ if _, err := io.WriteString(server, sentinel); err != nil {
+ t.Errorf("failed to call server.Write: %v", err)
+ }
+ if err := server.Close(); err != nil {
+ t.Errorf("failed to call server.Close: %v", err)
+ }
+ err = <-errChan
+ } else {
+ s.Close()
+ <-errChan
+ }
+ return
+}
+
+func fromHex(s string) []byte {
+ b, _ := hex.DecodeString(s)
+ return b
+}
+
+var testRSACertificate = fromHex("3082024b308201b4a003020102020900e8f09d3fe25beaa6300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301a310b3009060355040a1302476f310b300906035504031302476f30819f300d06092a864886f70d010101050003818d0030818902818100db467d932e12270648bc062821ab7ec4b6a25dfe1e5245887a3647a5080d92425bc281c0be97799840fb4f6d14fd2b138bc2a52e67d8d4099ed62238b74a0b74732bc234f1d193e596d9747bf3589f6c613cc0b041d4d92b2b2423775b1c3bbd755dce2054cfa163871d1e24c4f31d1a508baab61443ed97a77562f414c852d70203010001a38193308190300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff0402300030190603551d0e041204109f91161f43433e49a6de6db680d79f60301b0603551d230414301280104813494d137e1631bba301d5acab6e7b30190603551d1104123010820e6578616d706c652e676f6c616e67300d06092a864886f70d01010b0500038181009d30cc402b5b50a061cbbae55358e1ed8328a9581aa938a495a1ac315a1a84663d43d32dd90bf297dfd320643892243a00bccf9c7db74020015faad3166109a276fd13c3cce10c5ceeb18782f16c04ed73bbb343778d0c1cf10fa1d8408361c94c722b9daedb4606064df4c1b33ec0d1bd42d4dbfe3d1360845c21d33be9fae7")
+
+var testRSACertificateIssuer = fromHex("3082021930820182a003020102020900ca5e4e811a965964300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f7430819f300d06092a864886f70d010101050003818d0030818902818100d667b378bb22f34143b6cd2008236abefaf2852adf3ab05e01329e2c14834f5105df3f3073f99dab5442d45ee5f8f57b0111c8cb682fbb719a86944eebfffef3406206d898b8c1b1887797c9c5006547bb8f00e694b7a063f10839f269f2c34fff7a1f4b21fbcd6bfdfb13ac792d1d11f277b5c5b48600992203059f2a8f8cc50203010001a35d305b300e0603551d0f0101ff040403020204301d0603551d250416301406082b0601050507030106082b06010505070302300f0603551d130101ff040530030101ff30190603551d0e041204104813494d137e1631bba301d5acab6e7b300d06092a864886f70d01010b050003818100c1154b4bab5266221f293766ae4138899bd4c5e36b13cee670ceeaa4cbdf4f6679017e2fe649765af545749fe4249418a56bd38a04b81e261f5ce86b8d5c65413156a50d12449554748c59a30c515bc36a59d38bddf51173e899820b282e40aa78c806526fd184fb6b4cf186ec728edffa585440d2b3225325f7ab580e87dd76")
+
+// testRSAPSSCertificate has signatureAlgorithm rsassaPss, but subjectPublicKeyInfo
+// algorithm rsaEncryption, for use with the rsa_pss_rsae_* SignatureSchemes.
+// See also TestRSAPSSKeyError. testRSAPSSCertificate is self-signed.
+var testRSAPSSCertificate = fromHex("308202583082018da003020102021100f29926eb87ea8a0db9fcc247347c11b0304106092a864886f70d01010a3034a00f300d06096086480165030402010500a11c301a06092a864886f70d010108300d06096086480165030402010500a20302012030123110300e060355040a130741636d6520436f301e170d3137313132333136313631305a170d3138313132333136313631305a30123110300e060355040a130741636d6520436f30819f300d06092a864886f70d010101050003818d0030818902818100db467d932e12270648bc062821ab7ec4b6a25dfe1e5245887a3647a5080d92425bc281c0be97799840fb4f6d14fd2b138bc2a52e67d8d4099ed62238b74a0b74732bc234f1d193e596d9747bf3589f6c613cc0b041d4d92b2b2423775b1c3bbd755dce2054cfa163871d1e24c4f31d1a508baab61443ed97a77562f414c852d70203010001a3463044300e0603551d0f0101ff0404030205a030130603551d25040c300a06082b06010505070301300c0603551d130101ff04023000300f0603551d110408300687047f000001304106092a864886f70d01010a3034a00f300d06096086480165030402010500a11c301a06092a864886f70d010108300d06096086480165030402010500a20302012003818100cdac4ef2ce5f8d79881042707f7cbf1b5a8a00ef19154b40151771006cd41626e5496d56da0c1a139fd84695593cb67f87765e18aa03ea067522dd78d2a589b8c92364e12838ce346c6e067b51f1a7e6f4b37ffab13f1411896679d18e880e0ba09e302ac067efca460288e9538122692297ad8093d4f7dd701424d7700a46a1")
+
+var testECDSACertificate = fromHex("3082020030820162020900b8bf2d47a0d2ebf4300906072a8648ce3d04013045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c7464301e170d3132313132323135303633325a170d3232313132303135303633325a3045310b3009060355040613024155311330110603550408130a536f6d652d53746174653121301f060355040a1318496e7465726e6574205769646769747320507479204c746430819b301006072a8648ce3d020106052b81040023038186000400c4a1edbe98f90b4873367ec316561122f23d53c33b4d213dcd6b75e6f6b0dc9adf26c1bcb287f072327cb3642f1c90bcea6823107efee325c0483a69e0286dd33700ef0462dd0da09c706283d881d36431aa9e9731bd96b068c09b23de76643f1a5c7fe9120e5858b65f70dd9bd8ead5d7f5d5ccb9b69f30665b669a20e227e5bffe3b300906072a8648ce3d040103818c0030818802420188a24febe245c5487d1bacf5ed989dae4770c05e1bb62fbdf1b64db76140d311a2ceee0b7e927eff769dc33b7ea53fcefa10e259ec472d7cacda4e970e15a06fd00242014dfcbe67139c2d050ebd3fa38c25c13313830d9406bbd4377af6ec7ac9862eddd711697f857c56defb31782be4c7780daecbbe9e4e3624317b6a0f399512078f2a")
+
+var testEd25519Certificate = fromHex("3082012e3081e1a00302010202100f431c425793941de987e4f1ad15005d300506032b657030123110300e060355040a130741636d6520436f301e170d3139303531363231333830315a170d3230303531353231333830315a30123110300e060355040a130741636d6520436f302a300506032b65700321003fe2152ee6e3ef3f4e854a7577a3649eede0bf842ccc92268ffa6f3483aaec8fa34d304b300e0603551d0f0101ff0404030205a030130603551d25040c300a06082b06010505070301300c0603551d130101ff0402300030160603551d11040f300d820b6578616d706c652e636f6d300506032b65700341006344ed9cc4be5324539fd2108d9fe82108909539e50dc155ff2c16b71dfcab7d4dd4e09313d0a942e0b66bfe5d6748d79f50bc6ccd4b03837cf20858cdaccf0c")
+
+var testSNICertificate = fromHex("0441883421114c81480804c430820237308201a0a003020102020900e8f09d3fe25beaa6300d06092a864886f70d01010b0500301f310b3009060355040a1302476f3110300e06035504031307476f20526f6f74301e170d3136303130313030303030305a170d3235303130313030303030305a3023310b3009060355040a1302476f311430120603550403130b736e69746573742e636f6d30819f300d06092a864886f70d010101050003818d0030818902818100db467d932e12270648bc062821ab7ec4b6a25dfe1e5245887a3647a5080d92425bc281c0be97799840fb4f6d14fd2b138bc2a52e67d8d4099ed62238b74a0b74732bc234f1d193e596d9747bf3589f6c613cc0b041d4d92b2b2423775b1c3bbd755dce2054cfa163871d1e24c4f31d1a508baab61443ed97a77562f414c852d70203010001a3773075300e0603551d0f0101ff0404030205a0301d0603551d250416301406082b0601050507030106082b06010505070302300c0603551d130101ff0402300030190603551d0e041204109f91161f43433e49a6de6db680d79f60301b0603551d230414301280104813494d137e1631bba301d5acab6e7b300d06092a864886f70d01010b0500038181007beeecff0230dbb2e7a334af65430b7116e09f327c3bbf918107fc9c66cb497493207ae9b4dbb045cb63d605ec1b5dd485bb69124d68fa298dc776699b47632fd6d73cab57042acb26f083c4087459bc5a3bb3ca4d878d7fe31016b7bc9a627438666566e3389bfaeebe6becc9a0093ceed18d0f9ac79d56f3a73f18188988ed")
+
+var testP256Certificate = fromHex("308201693082010ea00302010202105012dc24e1124ade4f3e153326ff27bf300a06082a8648ce3d04030230123110300e060355040a130741636d6520436f301e170d3137303533313232343934375a170d3138303533313232343934375a30123110300e060355040a130741636d6520436f3059301306072a8648ce3d020106082a8648ce3d03010703420004c02c61c9b16283bbcc14956d886d79b358aa614596975f78cece787146abf74c2d5dc578c0992b4f3c631373479ebf3892efe53d21c4f4f1cc9a11c3536b7f75a3463044300e0603551d0f0101ff0404030205a030130603551d25040c300a06082b06010505070301300c0603551d130101ff04023000300f0603551d1104083006820474657374300a06082a8648ce3d0403020349003046022100963712d6226c7b2bef41512d47e1434131aaca3ba585d666c924df71ac0448b3022100f4d05c725064741aef125f243cdbccaa2a5d485927831f221c43023bd5ae471a")
+
+var testRSAPrivateKey, _ = x509.ParsePKCS1PrivateKey(fromHex("3082025b02010002818100db467d932e12270648bc062821ab7ec4b6a25dfe1e5245887a3647a5080d92425bc281c0be97799840fb4f6d14fd2b138bc2a52e67d8d4099ed62238b74a0b74732bc234f1d193e596d9747bf3589f6c613cc0b041d4d92b2b2423775b1c3bbd755dce2054cfa163871d1e24c4f31d1a508baab61443ed97a77562f414c852d702030100010281800b07fbcf48b50f1388db34b016298b8217f2092a7c9a04f77db6775a3d1279b62ee9951f7e371e9de33f015aea80660760b3951dc589a9f925ed7de13e8f520e1ccbc7498ce78e7fab6d59582c2386cc07ed688212a576ff37833bd5943483b5554d15a0b9b4010ed9bf09f207e7e9805f649240ed6c1256ed75ab7cd56d9671024100fded810da442775f5923debae4ac758390a032a16598d62f059bb2e781a9c2f41bfa015c209f966513fe3bf5a58717cbdb385100de914f88d649b7d15309fa49024100dd10978c623463a1802c52f012cfa72ff5d901f25a2292446552c2568b1840e49a312e127217c2186615aae4fb6602a4f6ebf3f3d160f3b3ad04c592f65ae41f02400c69062ca781841a09de41ed7a6d9f54adc5d693a2c6847949d9e1358555c9ac6a8d9e71653ac77beb2d3abaf7bb1183aa14278956575dbebf525d0482fd72d90240560fe1900ba36dae3022115fd952f2399fb28e2975a1c3e3d0b679660bdcb356cc189d611cfdd6d87cd5aea45aa30a2082e8b51e94c2f3dd5d5c6036a8a615ed0240143993d80ece56f877cb80048335701eb0e608cc0c1ca8c2227b52edf8f1ac99c562f2541b5ce81f0515af1c5b4770dba53383964b4b725ff46fdec3d08907df"))
+
+var testECDSAPrivateKey, _ = x509.ParseECPrivateKey(fromHex("3081dc0201010442019883e909ad0ac9ea3d33f9eae661f1785206970f8ca9a91672f1eedca7a8ef12bd6561bb246dda5df4b4d5e7e3a92649bc5d83a0bf92972e00e62067d0c7bd99d7a00706052b81040023a18189038186000400c4a1edbe98f90b4873367ec316561122f23d53c33b4d213dcd6b75e6f6b0dc9adf26c1bcb287f072327cb3642f1c90bcea6823107efee325c0483a69e0286dd33700ef0462dd0da09c706283d881d36431aa9e9731bd96b068c09b23de76643f1a5c7fe9120e5858b65f70dd9bd8ead5d7f5d5ccb9b69f30665b669a20e227e5bffe3b"))
+
+var testP256PrivateKey, _ = x509.ParseECPrivateKey(fromHex("30770201010420012f3b52bc54c36ba3577ad45034e2e8efe1e6999851284cb848725cfe029991a00a06082a8648ce3d030107a14403420004c02c61c9b16283bbcc14956d886d79b358aa614596975f78cece787146abf74c2d5dc578c0992b4f3c631373479ebf3892efe53d21c4f4f1cc9a11c3536b7f75"))
+
+var testEd25519PrivateKey = ed25519.PrivateKey(fromHex("3a884965e76b3f55e5faf9615458a92354894234de3ec9f684d46d55cebf3dc63fe2152ee6e3ef3f4e854a7577a3649eede0bf842ccc92268ffa6f3483aaec8f"))
+
+const clientCertificatePEM = `
+-----BEGIN CERTIFICATE-----
+MIIB7zCCAVigAwIBAgIQXBnBiWWDVW/cC8m5k5/pvDANBgkqhkiG9w0BAQsFADAS
+MRAwDgYDVQQKEwdBY21lIENvMB4XDTE2MDgxNzIxNTIzMVoXDTE3MDgxNzIxNTIz
+MVowEjEQMA4GA1UEChMHQWNtZSBDbzCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
+gYEAum+qhr3Pv5/y71yUYHhv6BPy0ZZvzdkybiI3zkH5yl0prOEn2mGi7oHLEMff
+NFiVhuk9GeZcJ3NgyI14AvQdpJgJoxlwaTwlYmYqqyIjxXuFOE8uCXMyp70+m63K
+hAfmDzr/d8WdQYUAirab7rCkPy1MTOZCPrtRyN1IVPQMjkcCAwEAAaNGMEQwDgYD
+VR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAw
+DwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOBgQBGq0Si+yhU+Fpn+GKU
+8ZqyGJ7ysd4dfm92lam6512oFmyc9wnTN+RLKzZ8Aa1B0jLYw9KT+RBrjpW5LBeK
+o0RIvFkTgxYEiKSBXCUNmAysEbEoVr4dzWFihAm/1oDGRY2CLLTYg5vbySK3KhIR
+e/oCO8HJ/+rJnahJ05XX1Q7lNQ==
+-----END CERTIFICATE-----`
+
+var clientKeyPEM = testingKey(`
+-----BEGIN RSA TESTING KEY-----
+MIICXQIBAAKBgQC6b6qGvc+/n/LvXJRgeG/oE/LRlm/N2TJuIjfOQfnKXSms4Sfa
+YaLugcsQx980WJWG6T0Z5lwnc2DIjXgC9B2kmAmjGXBpPCViZiqrIiPFe4U4Ty4J
+czKnvT6brcqEB+YPOv93xZ1BhQCKtpvusKQ/LUxM5kI+u1HI3UhU9AyORwIDAQAB
+AoGAEJZ03q4uuMb7b26WSQsOMeDsftdatT747LGgs3pNRkMJvTb/O7/qJjxoG+Mc
+qeSj0TAZXp+PXXc3ikCECAc+R8rVMfWdmp903XgO/qYtmZGCorxAHEmR80SrfMXv
+PJnznLQWc8U9nphQErR+tTESg7xWEzmFcPKwnZd1xg8ERYkCQQDTGtrFczlB2b/Z
+9TjNMqUlMnTLIk/a/rPE2fLLmAYhK5sHnJdvDURaH2mF4nso0EGtENnTsh6LATnY
+dkrxXGm9AkEA4hXHG2q3MnhgK1Z5hjv+Fnqd+8bcbII9WW4flFs15EKoMgS1w/PJ
+zbsySaSy5IVS8XeShmT9+3lrleed4sy+UwJBAJOOAbxhfXP5r4+5R6ql66jES75w
+jUCVJzJA5ORJrn8g64u2eGK28z/LFQbv9wXgCwfc72R468BdawFSLa/m2EECQGbZ
+rWiFla26IVXV0xcD98VWJsTBZMlgPnSOqoMdM1kSEd4fUmlAYI/dFzV1XYSkOmVr
+FhdZnklmpVDeu27P4c0CQQCuCOup0FlJSBpWY1TTfun/KMBkBatMz0VMA3d7FKIU
+csPezl677Yjo8u1r/KzeI6zLg87Z8E6r6ZWNc9wBSZK6
+-----END RSA TESTING KEY-----`)
+
+const clientECDSACertificatePEM = `
+-----BEGIN CERTIFICATE-----
+MIIB/DCCAV4CCQCaMIRsJjXZFzAJBgcqhkjOPQQBMEUxCzAJBgNVBAYTAkFVMRMw
+EQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0
+eSBMdGQwHhcNMTIxMTE0MTMyNTUzWhcNMjIxMTEyMTMyNTUzWjBBMQswCQYDVQQG
+EwJBVTEMMAoGA1UECBMDTlNXMRAwDgYDVQQHEwdQeXJtb250MRIwEAYDVQQDEwlK
+b2VsIFNpbmcwgZswEAYHKoZIzj0CAQYFK4EEACMDgYYABACVjJF1FMBexFe01MNv
+ja5oHt1vzobhfm6ySD6B5U7ixohLZNz1MLvT/2XMW/TdtWo+PtAd3kfDdq0Z9kUs
+jLzYHQFMH3CQRnZIi4+DzEpcj0B22uCJ7B0rxE4wdihBsmKo+1vx+U56jb0JuK7q
+ixgnTy5w/hOWusPTQBbNZU6sER7m8TAJBgcqhkjOPQQBA4GMADCBiAJCAOAUxGBg
+C3JosDJdYUoCdFzCgbkWqD8pyDbHgf9stlvZcPE4O1BIKJTLCRpS8V3ujfK58PDa
+2RU6+b0DeoeiIzXsAkIBo9SKeDUcSpoj0gq+KxAxnZxfvuiRs9oa9V2jI/Umi0Vw
+jWVim34BmT0Y9hCaOGGbLlfk+syxis7iI6CH8OFnUes=
+-----END CERTIFICATE-----`
+
+var clientECDSAKeyPEM = testingKey(`
+-----BEGIN EC PARAMETERS-----
+BgUrgQQAIw==
+-----END EC PARAMETERS-----
+-----BEGIN EC TESTING KEY-----
+MIHcAgEBBEIBkJN9X4IqZIguiEVKMqeBUP5xtRsEv4HJEtOpOGLELwO53SD78Ew8
+k+wLWoqizS3NpQyMtrU8JFdWfj+C57UNkOugBwYFK4EEACOhgYkDgYYABACVjJF1
+FMBexFe01MNvja5oHt1vzobhfm6ySD6B5U7ixohLZNz1MLvT/2XMW/TdtWo+PtAd
+3kfDdq0Z9kUsjLzYHQFMH3CQRnZIi4+DzEpcj0B22uCJ7B0rxE4wdihBsmKo+1vx
++U56jb0JuK7qixgnTy5w/hOWusPTQBbNZU6sER7m8Q==
+-----END EC TESTING KEY-----`)
+
+const clientEd25519CertificatePEM = `
+-----BEGIN CERTIFICATE-----
+MIIBLjCB4aADAgECAhAX0YGTviqMISAQJRXoNCNPMAUGAytlcDASMRAwDgYDVQQK
+EwdBY21lIENvMB4XDTE5MDUxNjIxNTQyNloXDTIwMDUxNTIxNTQyNlowEjEQMA4G
+A1UEChMHQWNtZSBDbzAqMAUGAytlcAMhAAvgtWC14nkwPb7jHuBQsQTIbcd4bGkv
+xRStmmNveRKRo00wSzAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0lBAwwCgYIKwYBBQUH
+AwIwDAYDVR0TAQH/BAIwADAWBgNVHREEDzANggtleGFtcGxlLmNvbTAFBgMrZXAD
+QQD8GRcqlKUx+inILn9boF2KTjRAOdazENwZ/qAicbP1j6FYDc308YUkv+Y9FN/f
+7Q7hF9gRomDQijcjKsJGqjoI
+-----END CERTIFICATE-----`
+
+var clientEd25519KeyPEM = testingKey(`
+-----BEGIN TESTING KEY-----
+MC4CAQAwBQYDK2VwBCIEINifzf07d9qx3d44e0FSbV4mC/xQxT644RRbpgNpin7I
+-----END TESTING KEY-----`)
diff --git a/src/crypto/tls/handshake_unix_test.go b/src/crypto/tls/handshake_unix_test.go
new file mode 100644
index 0000000..86a48f2
--- /dev/null
+++ b/src/crypto/tls/handshake_unix_test.go
@@ -0,0 +1,18 @@
+// Copyright 2019 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build unix
+
+package tls
+
+import (
+ "errors"
+ "syscall"
+)
+
+func init() {
+ isConnRefused = func(err error) bool {
+ return errors.Is(err, syscall.ECONNREFUSED)
+ }
+}
diff --git a/src/crypto/tls/key_agreement.go b/src/crypto/tls/key_agreement.go
new file mode 100644
index 0000000..2c8c5b8
--- /dev/null
+++ b/src/crypto/tls/key_agreement.go
@@ -0,0 +1,366 @@
+// Copyright 2010 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "crypto"
+ "crypto/ecdh"
+ "crypto/md5"
+ "crypto/rsa"
+ "crypto/sha1"
+ "crypto/x509"
+ "errors"
+ "fmt"
+ "io"
+)
+
+// a keyAgreement implements the client and server side of a TLS key agreement
+// protocol by generating and processing key exchange messages.
+type keyAgreement interface {
+ // On the server side, the first two methods are called in order.
+
+ // In the case that the key agreement protocol doesn't use a
+ // ServerKeyExchange message, generateServerKeyExchange can return nil,
+ // nil.
+ generateServerKeyExchange(*Config, *Certificate, *clientHelloMsg, *serverHelloMsg) (*serverKeyExchangeMsg, error)
+ processClientKeyExchange(*Config, *Certificate, *clientKeyExchangeMsg, uint16) ([]byte, error)
+
+ // On the client side, the next two methods are called in order.
+
+ // This method may not be called if the server doesn't send a
+ // ServerKeyExchange message.
+ processServerKeyExchange(*Config, *clientHelloMsg, *serverHelloMsg, *x509.Certificate, *serverKeyExchangeMsg) error
+ generateClientKeyExchange(*Config, *clientHelloMsg, *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error)
+}
+
+var errClientKeyExchange = errors.New("tls: invalid ClientKeyExchange message")
+var errServerKeyExchange = errors.New("tls: invalid ServerKeyExchange message")
+
+// rsaKeyAgreement implements the standard TLS key agreement where the client
+// encrypts the pre-master secret to the server's public key.
+type rsaKeyAgreement struct{}
+
+func (ka rsaKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+ return nil, nil
+}
+
+func (ka rsaKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+ if len(ckx.ciphertext) < 2 {
+ return nil, errClientKeyExchange
+ }
+ ciphertextLen := int(ckx.ciphertext[0])<<8 | int(ckx.ciphertext[1])
+ if ciphertextLen != len(ckx.ciphertext)-2 {
+ return nil, errClientKeyExchange
+ }
+ ciphertext := ckx.ciphertext[2:]
+
+ priv, ok := cert.PrivateKey.(crypto.Decrypter)
+ if !ok {
+ return nil, errors.New("tls: certificate private key does not implement crypto.Decrypter")
+ }
+ // Perform constant time RSA PKCS #1 v1.5 decryption
+ preMasterSecret, err := priv.Decrypt(config.rand(), ciphertext, &rsa.PKCS1v15DecryptOptions{SessionKeyLen: 48})
+ if err != nil {
+ return nil, err
+ }
+ // We don't check the version number in the premaster secret. For one,
+ // by checking it, we would leak information about the validity of the
+ // encrypted pre-master secret. Secondly, it provides only a small
+ // benefit against a downgrade attack and some implementations send the
+ // wrong version anyway. See the discussion at the end of section
+ // 7.4.7.1 of RFC 4346.
+ return preMasterSecret, nil
+}
+
+func (ka rsaKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+ return errors.New("tls: unexpected ServerKeyExchange")
+}
+
+func (ka rsaKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+ preMasterSecret := make([]byte, 48)
+ preMasterSecret[0] = byte(clientHello.vers >> 8)
+ preMasterSecret[1] = byte(clientHello.vers)
+ _, err := io.ReadFull(config.rand(), preMasterSecret[2:])
+ if err != nil {
+ return nil, nil, err
+ }
+
+ rsaKey, ok := cert.PublicKey.(*rsa.PublicKey)
+ if !ok {
+ return nil, nil, errors.New("tls: server certificate contains incorrect key type for selected ciphersuite")
+ }
+ encrypted, err := rsa.EncryptPKCS1v15(config.rand(), rsaKey, preMasterSecret)
+ if err != nil {
+ return nil, nil, err
+ }
+ ckx := new(clientKeyExchangeMsg)
+ ckx.ciphertext = make([]byte, len(encrypted)+2)
+ ckx.ciphertext[0] = byte(len(encrypted) >> 8)
+ ckx.ciphertext[1] = byte(len(encrypted))
+ copy(ckx.ciphertext[2:], encrypted)
+ return preMasterSecret, ckx, nil
+}
+
+// sha1Hash calculates a SHA1 hash over the given byte slices.
+func sha1Hash(slices [][]byte) []byte {
+ hsha1 := sha1.New()
+ for _, slice := range slices {
+ hsha1.Write(slice)
+ }
+ return hsha1.Sum(nil)
+}
+
+// md5SHA1Hash implements TLS 1.0's hybrid hash function which consists of the
+// concatenation of an MD5 and SHA1 hash.
+func md5SHA1Hash(slices [][]byte) []byte {
+ md5sha1 := make([]byte, md5.Size+sha1.Size)
+ hmd5 := md5.New()
+ for _, slice := range slices {
+ hmd5.Write(slice)
+ }
+ copy(md5sha1, hmd5.Sum(nil))
+ copy(md5sha1[md5.Size:], sha1Hash(slices))
+ return md5sha1
+}
+
+// hashForServerKeyExchange hashes the given slices and returns their digest
+// using the given hash function (for >= TLS 1.2) or using a default based on
+// the sigType (for earlier TLS versions). For Ed25519 signatures, which don't
+// do pre-hashing, it returns the concatenation of the slices.
+func hashForServerKeyExchange(sigType uint8, hashFunc crypto.Hash, version uint16, slices ...[]byte) []byte {
+ if sigType == signatureEd25519 {
+ var signed []byte
+ for _, slice := range slices {
+ signed = append(signed, slice...)
+ }
+ return signed
+ }
+ if version >= VersionTLS12 {
+ h := hashFunc.New()
+ for _, slice := range slices {
+ h.Write(slice)
+ }
+ digest := h.Sum(nil)
+ return digest
+ }
+ if sigType == signatureECDSA {
+ return sha1Hash(slices)
+ }
+ return md5SHA1Hash(slices)
+}
+
+// ecdheKeyAgreement implements a TLS key agreement where the server
+// generates an ephemeral EC public/private key pair and signs it. The
+// pre-master secret is then calculated using ECDH. The signature may
+// be ECDSA, Ed25519 or RSA.
+type ecdheKeyAgreement struct {
+ version uint16
+ isRSA bool
+ key *ecdh.PrivateKey
+
+ // ckx and preMasterSecret are generated in processServerKeyExchange
+ // and returned in generateClientKeyExchange.
+ ckx *clientKeyExchangeMsg
+ preMasterSecret []byte
+}
+
+func (ka *ecdheKeyAgreement) generateServerKeyExchange(config *Config, cert *Certificate, clientHello *clientHelloMsg, hello *serverHelloMsg) (*serverKeyExchangeMsg, error) {
+ var curveID CurveID
+ for _, c := range clientHello.supportedCurves {
+ if config.supportsCurve(c) {
+ curveID = c
+ break
+ }
+ }
+
+ if curveID == 0 {
+ return nil, errors.New("tls: no supported elliptic curves offered")
+ }
+ if _, ok := curveForCurveID(curveID); !ok {
+ return nil, errors.New("tls: CurvePreferences includes unsupported curve")
+ }
+
+ key, err := generateECDHEKey(config.rand(), curveID)
+ if err != nil {
+ return nil, err
+ }
+ ka.key = key
+
+ // See RFC 4492, Section 5.4.
+ ecdhePublic := key.PublicKey().Bytes()
+ serverECDHEParams := make([]byte, 1+2+1+len(ecdhePublic))
+ serverECDHEParams[0] = 3 // named curve
+ serverECDHEParams[1] = byte(curveID >> 8)
+ serverECDHEParams[2] = byte(curveID)
+ serverECDHEParams[3] = byte(len(ecdhePublic))
+ copy(serverECDHEParams[4:], ecdhePublic)
+
+ priv, ok := cert.PrivateKey.(crypto.Signer)
+ if !ok {
+ return nil, fmt.Errorf("tls: certificate private key of type %T does not implement crypto.Signer", cert.PrivateKey)
+ }
+
+ var signatureAlgorithm SignatureScheme
+ var sigType uint8
+ var sigHash crypto.Hash
+ if ka.version >= VersionTLS12 {
+ signatureAlgorithm, err = selectSignatureScheme(ka.version, cert, clientHello.supportedSignatureAlgorithms)
+ if err != nil {
+ return nil, err
+ }
+ sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm)
+ if err != nil {
+ return nil, err
+ }
+ } else {
+ sigType, sigHash, err = legacyTypeAndHashFromPublicKey(priv.Public())
+ if err != nil {
+ return nil, err
+ }
+ }
+ if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
+ return nil, errors.New("tls: certificate cannot be used with the selected cipher suite")
+ }
+
+ signed := hashForServerKeyExchange(sigType, sigHash, ka.version, clientHello.random, hello.random, serverECDHEParams)
+
+ signOpts := crypto.SignerOpts(sigHash)
+ if sigType == signatureRSAPSS {
+ signOpts = &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: sigHash}
+ }
+ sig, err := priv.Sign(config.rand(), signed, signOpts)
+ if err != nil {
+ return nil, errors.New("tls: failed to sign ECDHE parameters: " + err.Error())
+ }
+
+ skx := new(serverKeyExchangeMsg)
+ sigAndHashLen := 0
+ if ka.version >= VersionTLS12 {
+ sigAndHashLen = 2
+ }
+ skx.key = make([]byte, len(serverECDHEParams)+sigAndHashLen+2+len(sig))
+ copy(skx.key, serverECDHEParams)
+ k := skx.key[len(serverECDHEParams):]
+ if ka.version >= VersionTLS12 {
+ k[0] = byte(signatureAlgorithm >> 8)
+ k[1] = byte(signatureAlgorithm)
+ k = k[2:]
+ }
+ k[0] = byte(len(sig) >> 8)
+ k[1] = byte(len(sig))
+ copy(k[2:], sig)
+
+ return skx, nil
+}
+
+func (ka *ecdheKeyAgreement) processClientKeyExchange(config *Config, cert *Certificate, ckx *clientKeyExchangeMsg, version uint16) ([]byte, error) {
+ if len(ckx.ciphertext) == 0 || int(ckx.ciphertext[0]) != len(ckx.ciphertext)-1 {
+ return nil, errClientKeyExchange
+ }
+
+ peerKey, err := ka.key.Curve().NewPublicKey(ckx.ciphertext[1:])
+ if err != nil {
+ return nil, errClientKeyExchange
+ }
+ preMasterSecret, err := ka.key.ECDH(peerKey)
+ if err != nil {
+ return nil, errClientKeyExchange
+ }
+
+ return preMasterSecret, nil
+}
+
+func (ka *ecdheKeyAgreement) processServerKeyExchange(config *Config, clientHello *clientHelloMsg, serverHello *serverHelloMsg, cert *x509.Certificate, skx *serverKeyExchangeMsg) error {
+ if len(skx.key) < 4 {
+ return errServerKeyExchange
+ }
+ if skx.key[0] != 3 { // named curve
+ return errors.New("tls: server selected unsupported curve")
+ }
+ curveID := CurveID(skx.key[1])<<8 | CurveID(skx.key[2])
+
+ publicLen := int(skx.key[3])
+ if publicLen+4 > len(skx.key) {
+ return errServerKeyExchange
+ }
+ serverECDHEParams := skx.key[:4+publicLen]
+ publicKey := serverECDHEParams[4:]
+
+ sig := skx.key[4+publicLen:]
+ if len(sig) < 2 {
+ return errServerKeyExchange
+ }
+
+ if _, ok := curveForCurveID(curveID); !ok {
+ return errors.New("tls: server selected unsupported curve")
+ }
+
+ key, err := generateECDHEKey(config.rand(), curveID)
+ if err != nil {
+ return err
+ }
+ ka.key = key
+
+ peerKey, err := key.Curve().NewPublicKey(publicKey)
+ if err != nil {
+ return errServerKeyExchange
+ }
+ ka.preMasterSecret, err = key.ECDH(peerKey)
+ if err != nil {
+ return errServerKeyExchange
+ }
+
+ ourPublicKey := key.PublicKey().Bytes()
+ ka.ckx = new(clientKeyExchangeMsg)
+ ka.ckx.ciphertext = make([]byte, 1+len(ourPublicKey))
+ ka.ckx.ciphertext[0] = byte(len(ourPublicKey))
+ copy(ka.ckx.ciphertext[1:], ourPublicKey)
+
+ var sigType uint8
+ var sigHash crypto.Hash
+ if ka.version >= VersionTLS12 {
+ signatureAlgorithm := SignatureScheme(sig[0])<<8 | SignatureScheme(sig[1])
+ sig = sig[2:]
+ if len(sig) < 2 {
+ return errServerKeyExchange
+ }
+
+ if !isSupportedSignatureAlgorithm(signatureAlgorithm, clientHello.supportedSignatureAlgorithms) {
+ return errors.New("tls: certificate used with invalid signature algorithm")
+ }
+ sigType, sigHash, err = typeAndHashFromSignatureScheme(signatureAlgorithm)
+ if err != nil {
+ return err
+ }
+ } else {
+ sigType, sigHash, err = legacyTypeAndHashFromPublicKey(cert.PublicKey)
+ if err != nil {
+ return err
+ }
+ }
+ if (sigType == signaturePKCS1v15 || sigType == signatureRSAPSS) != ka.isRSA {
+ return errServerKeyExchange
+ }
+
+ sigLen := int(sig[0])<<8 | int(sig[1])
+ if sigLen+2 != len(sig) {
+ return errServerKeyExchange
+ }
+ sig = sig[2:]
+
+ signed := hashForServerKeyExchange(sigType, sigHash, ka.version, clientHello.random, serverHello.random, serverECDHEParams)
+ if err := verifyHandshakeSignature(sigType, cert.PublicKey, sigHash, signed, sig); err != nil {
+ return errors.New("tls: invalid signature by the server certificate: " + err.Error())
+ }
+ return nil
+}
+
+func (ka *ecdheKeyAgreement) generateClientKeyExchange(config *Config, clientHello *clientHelloMsg, cert *x509.Certificate) ([]byte, *clientKeyExchangeMsg, error) {
+ if ka.ckx == nil {
+ return nil, nil, errors.New("tls: missing ServerKeyExchange message")
+ }
+
+ return ka.preMasterSecret, ka.ckx, nil
+}
diff --git a/src/crypto/tls/key_schedule.go b/src/crypto/tls/key_schedule.go
new file mode 100644
index 0000000..ae8f80a
--- /dev/null
+++ b/src/crypto/tls/key_schedule.go
@@ -0,0 +1,158 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "crypto/ecdh"
+ "crypto/hmac"
+ "errors"
+ "fmt"
+ "hash"
+ "io"
+
+ "golang.org/x/crypto/cryptobyte"
+ "golang.org/x/crypto/hkdf"
+)
+
+// This file contains the functions necessary to compute the TLS 1.3 key
+// schedule. See RFC 8446, Section 7.
+
+const (
+ resumptionBinderLabel = "res binder"
+ clientHandshakeTrafficLabel = "c hs traffic"
+ serverHandshakeTrafficLabel = "s hs traffic"
+ clientApplicationTrafficLabel = "c ap traffic"
+ serverApplicationTrafficLabel = "s ap traffic"
+ exporterLabel = "exp master"
+ resumptionLabel = "res master"
+ trafficUpdateLabel = "traffic upd"
+)
+
+// expandLabel implements HKDF-Expand-Label from RFC 8446, Section 7.1.
+func (c *cipherSuiteTLS13) expandLabel(secret []byte, label string, context []byte, length int) []byte {
+ var hkdfLabel cryptobyte.Builder
+ hkdfLabel.AddUint16(uint16(length))
+ hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes([]byte("tls13 "))
+ b.AddBytes([]byte(label))
+ })
+ hkdfLabel.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(context)
+ })
+ hkdfLabelBytes, err := hkdfLabel.Bytes()
+ if err != nil {
+ // Rather than calling BytesOrPanic, we explicitly handle this error, in
+ // order to provide a reasonable error message. It should be basically
+ // impossible for this to panic, and routing errors back through the
+ // tree rooted in this function is quite painful. The labels are fixed
+ // size, and the context is either a fixed-length computed hash, or
+ // parsed from a field which has the same length limitation. As such, an
+ // error here is likely to only be caused during development.
+ //
+ // NOTE: another reasonable approach here might be to return a
+ // randomized slice if we encounter an error, which would break the
+ // connection, but avoid panicking. This would perhaps be safer but
+ // significantly more confusing to users.
+ panic(fmt.Errorf("failed to construct HKDF label: %s", err))
+ }
+ out := make([]byte, length)
+ n, err := hkdf.Expand(c.hash.New, secret, hkdfLabelBytes).Read(out)
+ if err != nil || n != length {
+ panic("tls: HKDF-Expand-Label invocation failed unexpectedly")
+ }
+ return out
+}
+
+// deriveSecret implements Derive-Secret from RFC 8446, Section 7.1.
+func (c *cipherSuiteTLS13) deriveSecret(secret []byte, label string, transcript hash.Hash) []byte {
+ if transcript == nil {
+ transcript = c.hash.New()
+ }
+ return c.expandLabel(secret, label, transcript.Sum(nil), c.hash.Size())
+}
+
+// extract implements HKDF-Extract with the cipher suite hash.
+func (c *cipherSuiteTLS13) extract(newSecret, currentSecret []byte) []byte {
+ if newSecret == nil {
+ newSecret = make([]byte, c.hash.Size())
+ }
+ return hkdf.Extract(c.hash.New, newSecret, currentSecret)
+}
+
+// nextTrafficSecret generates the next traffic secret, given the current one,
+// according to RFC 8446, Section 7.2.
+func (c *cipherSuiteTLS13) nextTrafficSecret(trafficSecret []byte) []byte {
+ return c.expandLabel(trafficSecret, trafficUpdateLabel, nil, c.hash.Size())
+}
+
+// trafficKey generates traffic keys according to RFC 8446, Section 7.3.
+func (c *cipherSuiteTLS13) trafficKey(trafficSecret []byte) (key, iv []byte) {
+ key = c.expandLabel(trafficSecret, "key", nil, c.keyLen)
+ iv = c.expandLabel(trafficSecret, "iv", nil, aeadNonceLength)
+ return
+}
+
+// finishedHash generates the Finished verify_data or PskBinderEntry according
+// to RFC 8446, Section 4.4.4. See sections 4.4 and 4.2.11.2 for the baseKey
+// selection.
+func (c *cipherSuiteTLS13) finishedHash(baseKey []byte, transcript hash.Hash) []byte {
+ finishedKey := c.expandLabel(baseKey, "finished", nil, c.hash.Size())
+ verifyData := hmac.New(c.hash.New, finishedKey)
+ verifyData.Write(transcript.Sum(nil))
+ return verifyData.Sum(nil)
+}
+
+// exportKeyingMaterial implements RFC5705 exporters for TLS 1.3 according to
+// RFC 8446, Section 7.5.
+func (c *cipherSuiteTLS13) exportKeyingMaterial(masterSecret []byte, transcript hash.Hash) func(string, []byte, int) ([]byte, error) {
+ expMasterSecret := c.deriveSecret(masterSecret, exporterLabel, transcript)
+ return func(label string, context []byte, length int) ([]byte, error) {
+ secret := c.deriveSecret(expMasterSecret, label, nil)
+ h := c.hash.New()
+ h.Write(context)
+ return c.expandLabel(secret, "exporter", h.Sum(nil), length), nil
+ }
+}
+
+// generateECDHEKey returns a PrivateKey that implements Diffie-Hellman
+// according to RFC 8446, Section 4.2.8.2.
+func generateECDHEKey(rand io.Reader, curveID CurveID) (*ecdh.PrivateKey, error) {
+ curve, ok := curveForCurveID(curveID)
+ if !ok {
+ return nil, errors.New("tls: internal error: unsupported curve")
+ }
+
+ return curve.GenerateKey(rand)
+}
+
+func curveForCurveID(id CurveID) (ecdh.Curve, bool) {
+ switch id {
+ case X25519:
+ return ecdh.X25519(), true
+ case CurveP256:
+ return ecdh.P256(), true
+ case CurveP384:
+ return ecdh.P384(), true
+ case CurveP521:
+ return ecdh.P521(), true
+ default:
+ return nil, false
+ }
+}
+
+func curveIDForCurve(curve ecdh.Curve) (CurveID, bool) {
+ switch curve {
+ case ecdh.X25519():
+ return X25519, true
+ case ecdh.P256():
+ return CurveP256, true
+ case ecdh.P384():
+ return CurveP384, true
+ case ecdh.P521():
+ return CurveP521, true
+ default:
+ return 0, false
+ }
+}
diff --git a/src/crypto/tls/key_schedule_test.go b/src/crypto/tls/key_schedule_test.go
new file mode 100644
index 0000000..79ff6a6
--- /dev/null
+++ b/src/crypto/tls/key_schedule_test.go
@@ -0,0 +1,175 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "bytes"
+ "encoding/hex"
+ "hash"
+ "strings"
+ "testing"
+ "unicode"
+)
+
+// This file contains tests derived from draft-ietf-tls-tls13-vectors-07.
+
+func parseVector(v string) []byte {
+ v = strings.Map(func(c rune) rune {
+ if unicode.IsSpace(c) {
+ return -1
+ }
+ return c
+ }, v)
+ parts := strings.Split(v, ":")
+ v = parts[len(parts)-1]
+ res, err := hex.DecodeString(v)
+ if err != nil {
+ panic(err)
+ }
+ return res
+}
+
+func TestDeriveSecret(t *testing.T) {
+ chTranscript := cipherSuitesTLS13[0].hash.New()
+ chTranscript.Write(parseVector(`
+ payload (512 octets): 01 00 01 fc 03 03 1b c3 ce b6 bb e3 9c ff
+ 93 83 55 b5 a5 0a db 6d b2 1b 7a 6a f6 49 d7 b4 bc 41 9d 78 76
+ 48 7d 95 00 00 06 13 01 13 03 13 02 01 00 01 cd 00 00 00 0b 00
+ 09 00 00 06 73 65 72 76 65 72 ff 01 00 01 00 00 0a 00 14 00 12
+ 00 1d 00 17 00 18 00 19 01 00 01 01 01 02 01 03 01 04 00 33 00
+ 26 00 24 00 1d 00 20 e4 ff b6 8a c0 5f 8d 96 c9 9d a2 66 98 34
+ 6c 6b e1 64 82 ba dd da fe 05 1a 66 b4 f1 8d 66 8f 0b 00 2a 00
+ 00 00 2b 00 03 02 03 04 00 0d 00 20 00 1e 04 03 05 03 06 03 02
+ 03 08 04 08 05 08 06 04 01 05 01 06 01 02 01 04 02 05 02 06 02
+ 02 02 00 2d 00 02 01 01 00 1c 00 02 40 01 00 15 00 57 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
+ 00 29 00 dd 00 b8 00 b2 2c 03 5d 82 93 59 ee 5f f7 af 4e c9 00
+ 00 00 00 26 2a 64 94 dc 48 6d 2c 8a 34 cb 33 fa 90 bf 1b 00 70
+ ad 3c 49 88 83 c9 36 7c 09 a2 be 78 5a bc 55 cd 22 60 97 a3 a9
+ 82 11 72 83 f8 2a 03 a1 43 ef d3 ff 5d d3 6d 64 e8 61 be 7f d6
+ 1d 28 27 db 27 9c ce 14 50 77 d4 54 a3 66 4d 4e 6d a4 d2 9e e0
+ 37 25 a6 a4 da fc d0 fc 67 d2 ae a7 05 29 51 3e 3d a2 67 7f a5
+ 90 6c 5b 3f 7d 8f 92 f2 28 bd a4 0d da 72 14 70 f9 fb f2 97 b5
+ ae a6 17 64 6f ac 5c 03 27 2e 97 07 27 c6 21 a7 91 41 ef 5f 7d
+ e6 50 5e 5b fb c3 88 e9 33 43 69 40 93 93 4a e4 d3 57 fa d6 aa
+ cb 00 21 20 3a dd 4f b2 d8 fd f8 22 a0 ca 3c f7 67 8e f5 e8 8d
+ ae 99 01 41 c5 92 4d 57 bb 6f a3 1b 9e 5f 9d`))
+
+ type args struct {
+ secret []byte
+ label string
+ transcript hash.Hash
+ }
+ tests := []struct {
+ name string
+ args args
+ want []byte
+ }{
+ {
+ `derive secret for handshake "tls13 derived"`,
+ args{
+ parseVector(`PRK (32 octets): 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c e2
+ 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a`),
+ "derived",
+ nil,
+ },
+ parseVector(`expanded (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba
+ b6 97 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba`),
+ },
+ {
+ `derive secret "tls13 c e traffic"`,
+ args{
+ parseVector(`PRK (32 octets): 9b 21 88 e9 b2 fc 6d 64 d7 1d c3 29 90 0e 20 bb
+ 41 91 50 00 f6 78 aa 83 9c bb 79 7c b7 d8 33 2c`),
+ "c e traffic",
+ chTranscript,
+ },
+ parseVector(`expanded (32 octets): 3f bb e6 a6 0d eb 66 c3 0a 32 79 5a ba 0e
+ ff 7e aa 10 10 55 86 e7 be 5c 09 67 8d 63 b6 ca ab 62`),
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ c := cipherSuitesTLS13[0]
+ if got := c.deriveSecret(tt.args.secret, tt.args.label, tt.args.transcript); !bytes.Equal(got, tt.want) {
+ t.Errorf("cipherSuiteTLS13.deriveSecret() = % x, want % x", got, tt.want)
+ }
+ })
+ }
+}
+
+func TestTrafficKey(t *testing.T) {
+ trafficSecret := parseVector(
+ `PRK (32 octets): b6 7b 7d 69 0c c1 6c 4e 75 e5 42 13 cb 2d 37 b4
+ e9 c9 12 bc de d9 10 5d 42 be fd 59 d3 91 ad 38`)
+ wantKey := parseVector(
+ `key expanded (16 octets): 3f ce 51 60 09 c2 17 27 d0 f2 e4 e8 6e
+ e4 03 bc`)
+ wantIV := parseVector(
+ `iv expanded (12 octets): 5d 31 3e b2 67 12 76 ee 13 00 0b 30`)
+
+ c := cipherSuitesTLS13[0]
+ gotKey, gotIV := c.trafficKey(trafficSecret)
+ if !bytes.Equal(gotKey, wantKey) {
+ t.Errorf("cipherSuiteTLS13.trafficKey() gotKey = % x, want % x", gotKey, wantKey)
+ }
+ if !bytes.Equal(gotIV, wantIV) {
+ t.Errorf("cipherSuiteTLS13.trafficKey() gotIV = % x, want % x", gotIV, wantIV)
+ }
+}
+
+func TestExtract(t *testing.T) {
+ type args struct {
+ newSecret []byte
+ currentSecret []byte
+ }
+ tests := []struct {
+ name string
+ args args
+ want []byte
+ }{
+ {
+ `extract secret "early"`,
+ args{
+ nil,
+ nil,
+ },
+ parseVector(`secret (32 octets): 33 ad 0a 1c 60 7e c0 3b 09 e6 cd 98 93 68 0c
+ e2 10 ad f3 00 aa 1f 26 60 e1 b2 2e 10 f1 70 f9 2a`),
+ },
+ {
+ `extract secret "master"`,
+ args{
+ nil,
+ parseVector(`salt (32 octets): 43 de 77 e0 c7 77 13 85 9a 94 4d b9 db 25 90 b5
+ 31 90 a6 5b 3e e2 e4 f1 2d d7 a0 bb 7c e2 54 b4`),
+ },
+ parseVector(`secret (32 octets): 18 df 06 84 3d 13 a0 8b f2 a4 49 84 4c 5f 8a
+ 47 80 01 bc 4d 4c 62 79 84 d5 a4 1d a8 d0 40 29 19`),
+ },
+ {
+ `extract secret "handshake"`,
+ args{
+ parseVector(`IKM (32 octets): 8b d4 05 4f b5 5b 9d 63 fd fb ac f9 f0 4b 9f 0d
+ 35 e6 d6 3f 53 75 63 ef d4 62 72 90 0f 89 49 2d`),
+ parseVector(`salt (32 octets): 6f 26 15 a1 08 c7 02 c5 67 8f 54 fc 9d ba b6 97
+ 16 c0 76 18 9c 48 25 0c eb ea c3 57 6c 36 11 ba`),
+ },
+ parseVector(`secret (32 octets): 1d c8 26 e9 36 06 aa 6f dc 0a ad c1 2f 74 1b
+ 01 04 6a a6 b9 9f 69 1e d2 21 a9 f0 ca 04 3f be ac`),
+ },
+ }
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ c := cipherSuitesTLS13[0]
+ if got := c.extract(tt.args.newSecret, tt.args.currentSecret); !bytes.Equal(got, tt.want) {
+ t.Errorf("cipherSuiteTLS13.extract() = % x, want % x", got, tt.want)
+ }
+ })
+ }
+}
diff --git a/src/crypto/tls/link_test.go b/src/crypto/tls/link_test.go
new file mode 100644
index 0000000..454d370
--- /dev/null
+++ b/src/crypto/tls/link_test.go
@@ -0,0 +1,107 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "bytes"
+ "internal/testenv"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "testing"
+)
+
+// Tests that the linker is able to remove references to the Client or Server if unused.
+func TestLinkerGC(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ t.Parallel()
+ goBin := testenv.GoToolPath(t)
+ testenv.MustHaveGoBuild(t)
+
+ tests := []struct {
+ name string
+ program string
+ want []string
+ bad []string
+ }{
+ {
+ name: "empty_import",
+ program: `package main
+import _ "crypto/tls"
+func main() {}
+`,
+ bad: []string{
+ "tls.(*Conn)",
+ "type:crypto/tls.clientHandshakeState",
+ "type:crypto/tls.serverHandshakeState",
+ },
+ },
+ {
+ name: "client_and_server",
+ program: `package main
+import "crypto/tls"
+func main() {
+ tls.Dial("", "", nil)
+ tls.Server(nil, nil)
+}
+`,
+ want: []string{
+ "crypto/tls.(*Conn).clientHandshake",
+ "crypto/tls.(*Conn).serverHandshake",
+ },
+ },
+ {
+ name: "only_client",
+ program: `package main
+import "crypto/tls"
+func main() { tls.Dial("", "", nil) }
+`,
+ want: []string{
+ "crypto/tls.(*Conn).clientHandshake",
+ },
+ bad: []string{
+ "crypto/tls.(*Conn).serverHandshake",
+ },
+ },
+ // TODO: add only_server like func main() { tls.Server(nil, nil) }
+ // That currently brings in the client via Conn.handleRenegotiation.
+
+ }
+ tmpDir := t.TempDir()
+ goFile := filepath.Join(tmpDir, "x.go")
+ exeFile := filepath.Join(tmpDir, "x.exe")
+ for _, tt := range tests {
+ t.Run(tt.name, func(t *testing.T) {
+ if err := os.WriteFile(goFile, []byte(tt.program), 0644); err != nil {
+ t.Fatal(err)
+ }
+ os.Remove(exeFile)
+ cmd := exec.Command(goBin, "build", "-o", "x.exe", "x.go")
+ cmd.Dir = tmpDir
+ if out, err := cmd.CombinedOutput(); err != nil {
+ t.Fatalf("compile: %v, %s", err, out)
+ }
+
+ cmd = exec.Command(goBin, "tool", "nm", "x.exe")
+ cmd.Dir = tmpDir
+ nm, err := cmd.CombinedOutput()
+ if err != nil {
+ t.Fatalf("nm: %v, %s", err, nm)
+ }
+ for _, sym := range tt.want {
+ if !bytes.Contains(nm, []byte(sym)) {
+ t.Errorf("expected symbol %q not found", sym)
+ }
+ }
+ for _, sym := range tt.bad {
+ if bytes.Contains(nm, []byte(sym)) {
+ t.Errorf("unexpected symbol %q found", sym)
+ }
+ }
+ })
+ }
+}
diff --git a/src/crypto/tls/notboring.go b/src/crypto/tls/notboring.go
new file mode 100644
index 0000000..7d85b39
--- /dev/null
+++ b/src/crypto/tls/notboring.go
@@ -0,0 +1,20 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !boringcrypto
+
+package tls
+
+func needFIPS() bool { return false }
+
+func supportedSignatureAlgorithms() []SignatureScheme {
+ return defaultSupportedSignatureAlgorithms
+}
+
+func fipsMinVersion(c *Config) uint16 { panic("fipsMinVersion") }
+func fipsMaxVersion(c *Config) uint16 { panic("fipsMaxVersion") }
+func fipsCurvePreferences(c *Config) []CurveID { panic("fipsCurvePreferences") }
+func fipsCipherSuites(c *Config) []uint16 { panic("fipsCipherSuites") }
+
+var fipsSupportedSignatureAlgorithms []SignatureScheme
diff --git a/src/crypto/tls/prf.go b/src/crypto/tls/prf.go
new file mode 100644
index 0000000..b60166d
--- /dev/null
+++ b/src/crypto/tls/prf.go
@@ -0,0 +1,283 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "crypto"
+ "crypto/hmac"
+ "crypto/md5"
+ "crypto/sha1"
+ "crypto/sha256"
+ "crypto/sha512"
+ "errors"
+ "fmt"
+ "hash"
+)
+
+// Split a premaster secret in two as specified in RFC 4346, Section 5.
+func splitPreMasterSecret(secret []byte) (s1, s2 []byte) {
+ s1 = secret[0 : (len(secret)+1)/2]
+ s2 = secret[len(secret)/2:]
+ return
+}
+
+// pHash implements the P_hash function, as defined in RFC 4346, Section 5.
+func pHash(result, secret, seed []byte, hash func() hash.Hash) {
+ h := hmac.New(hash, secret)
+ h.Write(seed)
+ a := h.Sum(nil)
+
+ j := 0
+ for j < len(result) {
+ h.Reset()
+ h.Write(a)
+ h.Write(seed)
+ b := h.Sum(nil)
+ copy(result[j:], b)
+ j += len(b)
+
+ h.Reset()
+ h.Write(a)
+ a = h.Sum(nil)
+ }
+}
+
+// prf10 implements the TLS 1.0 pseudo-random function, as defined in RFC 2246, Section 5.
+func prf10(result, secret, label, seed []byte) {
+ hashSHA1 := sha1.New
+ hashMD5 := md5.New
+
+ labelAndSeed := make([]byte, len(label)+len(seed))
+ copy(labelAndSeed, label)
+ copy(labelAndSeed[len(label):], seed)
+
+ s1, s2 := splitPreMasterSecret(secret)
+ pHash(result, s1, labelAndSeed, hashMD5)
+ result2 := make([]byte, len(result))
+ pHash(result2, s2, labelAndSeed, hashSHA1)
+
+ for i, b := range result2 {
+ result[i] ^= b
+ }
+}
+
+// prf12 implements the TLS 1.2 pseudo-random function, as defined in RFC 5246, Section 5.
+func prf12(hashFunc func() hash.Hash) func(result, secret, label, seed []byte) {
+ return func(result, secret, label, seed []byte) {
+ labelAndSeed := make([]byte, len(label)+len(seed))
+ copy(labelAndSeed, label)
+ copy(labelAndSeed[len(label):], seed)
+
+ pHash(result, secret, labelAndSeed, hashFunc)
+ }
+}
+
+const (
+ masterSecretLength = 48 // Length of a master secret in TLS 1.1.
+ finishedVerifyLength = 12 // Length of verify_data in a Finished message.
+)
+
+var masterSecretLabel = []byte("master secret")
+var keyExpansionLabel = []byte("key expansion")
+var clientFinishedLabel = []byte("client finished")
+var serverFinishedLabel = []byte("server finished")
+
+func prfAndHashForVersion(version uint16, suite *cipherSuite) (func(result, secret, label, seed []byte), crypto.Hash) {
+ switch version {
+ case VersionTLS10, VersionTLS11:
+ return prf10, crypto.Hash(0)
+ case VersionTLS12:
+ if suite.flags&suiteSHA384 != 0 {
+ return prf12(sha512.New384), crypto.SHA384
+ }
+ return prf12(sha256.New), crypto.SHA256
+ default:
+ panic("unknown version")
+ }
+}
+
+func prfForVersion(version uint16, suite *cipherSuite) func(result, secret, label, seed []byte) {
+ prf, _ := prfAndHashForVersion(version, suite)
+ return prf
+}
+
+// masterFromPreMasterSecret generates the master secret from the pre-master
+// secret. See RFC 5246, Section 8.1.
+func masterFromPreMasterSecret(version uint16, suite *cipherSuite, preMasterSecret, clientRandom, serverRandom []byte) []byte {
+ seed := make([]byte, 0, len(clientRandom)+len(serverRandom))
+ seed = append(seed, clientRandom...)
+ seed = append(seed, serverRandom...)
+
+ masterSecret := make([]byte, masterSecretLength)
+ prfForVersion(version, suite)(masterSecret, preMasterSecret, masterSecretLabel, seed)
+ return masterSecret
+}
+
+// keysFromMasterSecret generates the connection keys from the master
+// secret, given the lengths of the MAC key, cipher key and IV, as defined in
+// RFC 2246, Section 6.3.
+func keysFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte, macLen, keyLen, ivLen int) (clientMAC, serverMAC, clientKey, serverKey, clientIV, serverIV []byte) {
+ seed := make([]byte, 0, len(serverRandom)+len(clientRandom))
+ seed = append(seed, serverRandom...)
+ seed = append(seed, clientRandom...)
+
+ n := 2*macLen + 2*keyLen + 2*ivLen
+ keyMaterial := make([]byte, n)
+ prfForVersion(version, suite)(keyMaterial, masterSecret, keyExpansionLabel, seed)
+ clientMAC = keyMaterial[:macLen]
+ keyMaterial = keyMaterial[macLen:]
+ serverMAC = keyMaterial[:macLen]
+ keyMaterial = keyMaterial[macLen:]
+ clientKey = keyMaterial[:keyLen]
+ keyMaterial = keyMaterial[keyLen:]
+ serverKey = keyMaterial[:keyLen]
+ keyMaterial = keyMaterial[keyLen:]
+ clientIV = keyMaterial[:ivLen]
+ keyMaterial = keyMaterial[ivLen:]
+ serverIV = keyMaterial[:ivLen]
+ return
+}
+
+func newFinishedHash(version uint16, cipherSuite *cipherSuite) finishedHash {
+ var buffer []byte
+ if version >= VersionTLS12 {
+ buffer = []byte{}
+ }
+
+ prf, hash := prfAndHashForVersion(version, cipherSuite)
+ if hash != 0 {
+ return finishedHash{hash.New(), hash.New(), nil, nil, buffer, version, prf}
+ }
+
+ return finishedHash{sha1.New(), sha1.New(), md5.New(), md5.New(), buffer, version, prf}
+}
+
+// A finishedHash calculates the hash of a set of handshake messages suitable
+// for including in a Finished message.
+type finishedHash struct {
+ client hash.Hash
+ server hash.Hash
+
+ // Prior to TLS 1.2, an additional MD5 hash is required.
+ clientMD5 hash.Hash
+ serverMD5 hash.Hash
+
+ // In TLS 1.2, a full buffer is sadly required.
+ buffer []byte
+
+ version uint16
+ prf func(result, secret, label, seed []byte)
+}
+
+func (h *finishedHash) Write(msg []byte) (n int, err error) {
+ h.client.Write(msg)
+ h.server.Write(msg)
+
+ if h.version < VersionTLS12 {
+ h.clientMD5.Write(msg)
+ h.serverMD5.Write(msg)
+ }
+
+ if h.buffer != nil {
+ h.buffer = append(h.buffer, msg...)
+ }
+
+ return len(msg), nil
+}
+
+func (h finishedHash) Sum() []byte {
+ if h.version >= VersionTLS12 {
+ return h.client.Sum(nil)
+ }
+
+ out := make([]byte, 0, md5.Size+sha1.Size)
+ out = h.clientMD5.Sum(out)
+ return h.client.Sum(out)
+}
+
+// clientSum returns the contents of the verify_data member of a client's
+// Finished message.
+func (h finishedHash) clientSum(masterSecret []byte) []byte {
+ out := make([]byte, finishedVerifyLength)
+ h.prf(out, masterSecret, clientFinishedLabel, h.Sum())
+ return out
+}
+
+// serverSum returns the contents of the verify_data member of a server's
+// Finished message.
+func (h finishedHash) serverSum(masterSecret []byte) []byte {
+ out := make([]byte, finishedVerifyLength)
+ h.prf(out, masterSecret, serverFinishedLabel, h.Sum())
+ return out
+}
+
+// hashForClientCertificate returns the handshake messages so far, pre-hashed if
+// necessary, suitable for signing by a TLS client certificate.
+func (h finishedHash) hashForClientCertificate(sigType uint8, hashAlg crypto.Hash) []byte {
+ if (h.version >= VersionTLS12 || sigType == signatureEd25519) && h.buffer == nil {
+ panic("tls: handshake hash for a client certificate requested after discarding the handshake buffer")
+ }
+
+ if sigType == signatureEd25519 {
+ return h.buffer
+ }
+
+ if h.version >= VersionTLS12 {
+ hash := hashAlg.New()
+ hash.Write(h.buffer)
+ return hash.Sum(nil)
+ }
+
+ if sigType == signatureECDSA {
+ return h.server.Sum(nil)
+ }
+
+ return h.Sum()
+}
+
+// discardHandshakeBuffer is called when there is no more need to
+// buffer the entirety of the handshake messages.
+func (h *finishedHash) discardHandshakeBuffer() {
+ h.buffer = nil
+}
+
+// noExportedKeyingMaterial is used as a value of
+// ConnectionState.ekm when renegotiation is enabled and thus
+// we wish to fail all key-material export requests.
+func noExportedKeyingMaterial(label string, context []byte, length int) ([]byte, error) {
+ return nil, errors.New("crypto/tls: ExportKeyingMaterial is unavailable when renegotiation is enabled")
+}
+
+// ekmFromMasterSecret generates exported keying material as defined in RFC 5705.
+func ekmFromMasterSecret(version uint16, suite *cipherSuite, masterSecret, clientRandom, serverRandom []byte) func(string, []byte, int) ([]byte, error) {
+ return func(label string, context []byte, length int) ([]byte, error) {
+ switch label {
+ case "client finished", "server finished", "master secret", "key expansion":
+ // These values are reserved and may not be used.
+ return nil, fmt.Errorf("crypto/tls: reserved ExportKeyingMaterial label: %s", label)
+ }
+
+ seedLen := len(serverRandom) + len(clientRandom)
+ if context != nil {
+ seedLen += 2 + len(context)
+ }
+ seed := make([]byte, 0, seedLen)
+
+ seed = append(seed, clientRandom...)
+ seed = append(seed, serverRandom...)
+
+ if context != nil {
+ if len(context) >= 1<<16 {
+ return nil, fmt.Errorf("crypto/tls: ExportKeyingMaterial context too long")
+ }
+ seed = append(seed, byte(len(context)>>8), byte(len(context)))
+ seed = append(seed, context...)
+ }
+
+ keyMaterial := make([]byte, length)
+ prfForVersion(version, suite)(keyMaterial, masterSecret, []byte(label), seed)
+ return keyMaterial, nil
+ }
+}
diff --git a/src/crypto/tls/prf_test.go b/src/crypto/tls/prf_test.go
new file mode 100644
index 0000000..8233985
--- /dev/null
+++ b/src/crypto/tls/prf_test.go
@@ -0,0 +1,140 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "encoding/hex"
+ "testing"
+)
+
+type testSplitPreMasterSecretTest struct {
+ in, out1, out2 string
+}
+
+var testSplitPreMasterSecretTests = []testSplitPreMasterSecretTest{
+ {"", "", ""},
+ {"00", "00", "00"},
+ {"0011", "00", "11"},
+ {"001122", "0011", "1122"},
+ {"00112233", "0011", "2233"},
+}
+
+func TestSplitPreMasterSecret(t *testing.T) {
+ for i, test := range testSplitPreMasterSecretTests {
+ in, _ := hex.DecodeString(test.in)
+ out1, out2 := splitPreMasterSecret(in)
+ s1 := hex.EncodeToString(out1)
+ s2 := hex.EncodeToString(out2)
+ if s1 != test.out1 || s2 != test.out2 {
+ t.Errorf("#%d: got: (%s, %s) want: (%s, %s)", i, s1, s2, test.out1, test.out2)
+ }
+ }
+}
+
+type testKeysFromTest struct {
+ version uint16
+ suite *cipherSuite
+ preMasterSecret string
+ clientRandom, serverRandom string
+ masterSecret string
+ clientMAC, serverMAC string
+ clientKey, serverKey string
+ macLen, keyLen int
+ contextKeyingMaterial, noContextKeyingMaterial string
+}
+
+func TestKeysFromPreMasterSecret(t *testing.T) {
+ for i, test := range testKeysFromTests {
+ in, _ := hex.DecodeString(test.preMasterSecret)
+ clientRandom, _ := hex.DecodeString(test.clientRandom)
+ serverRandom, _ := hex.DecodeString(test.serverRandom)
+
+ masterSecret := masterFromPreMasterSecret(test.version, test.suite, in, clientRandom, serverRandom)
+ if s := hex.EncodeToString(masterSecret); s != test.masterSecret {
+ t.Errorf("#%d: bad master secret %s, want %s", i, s, test.masterSecret)
+ continue
+ }
+
+ clientMAC, serverMAC, clientKey, serverKey, _, _ := keysFromMasterSecret(test.version, test.suite, masterSecret, clientRandom, serverRandom, test.macLen, test.keyLen, 0)
+ clientMACString := hex.EncodeToString(clientMAC)
+ serverMACString := hex.EncodeToString(serverMAC)
+ clientKeyString := hex.EncodeToString(clientKey)
+ serverKeyString := hex.EncodeToString(serverKey)
+ if clientMACString != test.clientMAC ||
+ serverMACString != test.serverMAC ||
+ clientKeyString != test.clientKey ||
+ serverKeyString != test.serverKey {
+ t.Errorf("#%d: got: (%s, %s, %s, %s) want: (%s, %s, %s, %s)", i, clientMACString, serverMACString, clientKeyString, serverKeyString, test.clientMAC, test.serverMAC, test.clientKey, test.serverKey)
+ }
+
+ ekm := ekmFromMasterSecret(test.version, test.suite, masterSecret, clientRandom, serverRandom)
+ contextKeyingMaterial, err := ekm("label", []byte("context"), 32)
+ if err != nil {
+ t.Fatalf("ekmFromMasterSecret failed: %v", err)
+ }
+
+ noContextKeyingMaterial, err := ekm("label", nil, 32)
+ if err != nil {
+ t.Fatalf("ekmFromMasterSecret failed: %v", err)
+ }
+
+ if hex.EncodeToString(contextKeyingMaterial) != test.contextKeyingMaterial ||
+ hex.EncodeToString(noContextKeyingMaterial) != test.noContextKeyingMaterial {
+ t.Errorf("#%d: got keying material: (%s, %s) want: (%s, %s)", i, contextKeyingMaterial, noContextKeyingMaterial, test.contextKeyingMaterial, test.noContextKeyingMaterial)
+ }
+ }
+}
+
+// These test vectors were generated from GnuTLS using `gnutls-cli --insecure -d 9 `
+var testKeysFromTests = []testKeysFromTest{
+ {
+ VersionTLS10,
+ cipherSuiteByID(TLS_RSA_WITH_RC4_128_SHA),
+ "0302cac83ad4b1db3b9ab49ad05957de2a504a634a386fc600889321e1a971f57479466830ac3e6f468e87f5385fa0c5",
+ "4ae66303755184a3917fcb44880605fcc53baa01912b22ed94473fc69cebd558",
+ "4ae663020ec16e6bb5130be918cfcafd4d765979a3136a5d50c593446e4e44db",
+ "3d851bab6e5556e959a16bc36d66cfae32f672bfa9ecdef6096cbb1b23472df1da63dbbd9827606413221d149ed08ceb",
+ "805aaa19b3d2c0a0759a4b6c9959890e08480119",
+ "2d22f9fe519c075c16448305ceee209fc24ad109",
+ "d50b5771244f850cd8117a9ccafe2cf1",
+ "e076e33206b30507a85c32855acd0919",
+ 20,
+ 16,
+ "4d1bb6fc278c37d27aa6e2a13c2e079095d143272c2aa939da33d88c1c0cec22",
+ "93fba89599b6321ae538e27c6548ceb8b46821864318f5190d64a375e5d69d41",
+ },
+ {
+ VersionTLS10,
+ cipherSuiteByID(TLS_RSA_WITH_RC4_128_SHA),
+ "03023f7527316bc12cbcd69e4b9e8275d62c028f27e65c745cfcddc7ce01bd3570a111378b63848127f1c36e5f9e4890",
+ "4ae66364b5ea56b20ce4e25555aed2d7e67f42788dd03f3fee4adae0459ab106",
+ "4ae66363ab815cbf6a248b87d6b556184e945e9b97fbdf247858b0bdafacfa1c",
+ "7d64be7c80c59b740200b4b9c26d0baaa1c5ae56705acbcf2307fe62beb4728c19392c83f20483801cce022c77645460",
+ "97742ed60a0554ca13f04f97ee193177b971e3b0",
+ "37068751700400e03a8477a5c7eec0813ab9e0dc",
+ "207cddbc600d2a200abac6502053ee5c",
+ "df3f94f6e1eacc753b815fe16055cd43",
+ 20,
+ 16,
+ "2c9f8961a72b97cbe76553b5f954caf8294fc6360ef995ac1256fe9516d0ce7f",
+ "274f19c10291d188857ad8878e2119f5aa437d4da556601cf1337aff23154016",
+ },
+ {
+ VersionTLS10,
+ cipherSuiteByID(TLS_RSA_WITH_RC4_128_SHA),
+ "832d515f1d61eebb2be56ba0ef79879efb9b527504abb386fb4310ed5d0e3b1f220d3bb6b455033a2773e6d8bdf951d278a187482b400d45deb88a5d5a6bb7d6a7a1decc04eb9ef0642876cd4a82d374d3b6ff35f0351dc5d411104de431375355addc39bfb1f6329fb163b0bc298d658338930d07d313cd980a7e3d9196cac1",
+ "4ae663b2ee389c0de147c509d8f18f5052afc4aaf9699efe8cb05ece883d3a5e",
+ "4ae664d503fd4cff50cfc1fb8fc606580f87b0fcdac9554ba0e01d785bdf278e",
+ "1aff2e7a2c4279d0126f57a65a77a8d9d0087cf2733366699bec27eb53d5740705a8574bb1acc2abbe90e44f0dd28d6c",
+ "3c7647c93c1379a31a609542aa44e7f117a70085",
+ "0d73102994be74a575a3ead8532590ca32a526d4",
+ "ac7581b0b6c10d85bbd905ffbf36c65e",
+ "ff07edde49682b45466bd2e39464b306",
+ 20,
+ 16,
+ "678b0d43f607de35241dc7e9d1a7388a52c35033a1a0336d4d740060a6638fe2",
+ "f3b4ac743f015ef21d79978297a53da3e579ee047133f38c234d829c0f907dab",
+ },
+}
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
new file mode 100644
index 0000000..d93f679
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-ECDSA
@@ -0,0 +1,134 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 59 02 00 00 55 03 01 f1 70 ef e1 e5 |....Y...U...p...|
+00000010 96 73 83 d3 e2 b9 53 7e 81 ae 1d 40 24 5a ca f2 |.s....S~...@$Z..|
+00000020 06 b3 b6 01 e4 02 fb 81 bc d9 3d 20 1f 1a f0 b5 |..........= ....|
+00000030 b2 93 42 da 00 4d bf f6 dc 99 54 8d 3b 17 a4 74 |..B..M....T.;..t|
+00000040 ca 93 e1 5c a9 c4 d1 35 af f2 d8 f9 c0 09 00 00 |...\...5........|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 01 00 b5 0c 00 00 b1 03 00 1d 20 f0 8c |*............ ..|
+00000280 cd 6a c2 7a ea f0 2b 4a 34 6d a9 3b 7a 29 5d 04 |.j.z..+J4m.;z)].|
+00000290 65 70 97 30 e7 10 6e c2 7e 50 c5 89 4a 3f 00 8b |ep.0..n.~P..J?..|
+000002a0 30 81 88 02 42 00 be e2 67 30 f0 8a cb 63 6c 13 |0...B...g0...cl.|
+000002b0 e0 4e 88 52 6e bc e4 83 53 f4 18 75 b7 46 a5 46 |.N.Rn...S..u.F.F|
+000002c0 11 f1 4b f9 bd 58 4e 62 5c fb a8 f2 93 99 3c 94 |..K..XNb\.....<.|
+000002d0 18 1d 7a f1 74 bf 9d c6 fe 65 b1 bc 54 2b c7 ba |..z.t....e..T+..|
+000002e0 f7 45 a8 0a 21 ad 23 02 42 01 c8 fd 48 62 e2 5e |.E..!.#.B...Hb.^|
+000002f0 f1 9c 95 c0 28 c4 c5 04 31 e5 ba a5 3c 09 d9 d7 |....(...1...<...|
+00000300 43 aa 8c 35 26 ed 47 57 6d c6 15 86 50 3c 72 e1 |C..5&.GWm...P<r.|
+00000310 6f 2b 85 63 97 5e 20 58 fc cf 0c f9 37 27 42 fb |o+.c.^ X....7'B.|
+00000320 cd ed c3 40 ac 5f d9 06 5c a3 27 16 03 01 00 0a |...@._..\.'.....|
+00000330 0d 00 00 06 03 01 02 40 00 00 16 03 01 00 04 0e |.......@........|
+00000340 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 01 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
+00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
+00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1|
+00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.|
+00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat|
+00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte|
+00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty|
+00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413|
+00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132|
+00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...|
+000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS|
+000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm|
+000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo|
+000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.|
+000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....|
+000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.|
+00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N|
+00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..|
+00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.|
+00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J|
+00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A|
+00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......|
+00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN|
+00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..|
+00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.|
+00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?|
+000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH|
+000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........|
+000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...|
+000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._|
+000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
+000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
+00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
+00000210 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b|
+00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......|
+00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 91 0f 00 |...._X.;t.......|
+00000240 00 8d 00 8b 30 81 88 02 42 01 4c 44 9a a6 7e 6e |....0...B.LD..~n|
+00000250 8a f0 40 c0 63 cf 50 4d 1c 36 55 c2 ae 89 19 5a |..@.c.PM.6U....Z|
+00000260 3f ef 2b 2e 0d 66 4f fe c2 cb 17 86 7c a1 2c e9 |?.+..fO.....|.,.|
+00000270 d8 44 b6 45 36 cc 3a 29 74 19 3c 98 c1 f6 8f 9c |.D.E6.:)t.<.....|
+00000280 bb 29 fa ae d5 73 de c8 b3 27 7f 02 42 01 86 c9 |.)...s...'..B...|
+00000290 9d e6 1d 45 8b 35 7d ee 7d de ce 4b 15 40 1e 26 |...E.5}.}..K.@.&|
+000002a0 95 eb 8e b2 6d ac a3 52 b3 fe bc 9d 2b 61 1a 41 |....m..R....+a.A|
+000002b0 5c b5 e5 c0 df 3f 5b 84 4b d6 b2 c5 3a 15 05 0d |\....?[.K...:...|
+000002c0 3f 0a 6e d7 8d 49 35 50 67 3e 6e c5 a7 ba 84 14 |?.n..I5Pg>n.....|
+000002d0 03 01 00 01 01 16 03 01 00 30 91 e2 f5 b4 fc 0d |.........0......|
+000002e0 43 92 f1 18 99 68 d8 4d 94 ab e0 87 60 e5 46 e3 |C....h.M....`.F.|
+000002f0 dd b8 0c b5 c6 5b 73 ba ae e7 7f 0c 6d 6d 94 e7 |.....[s.....mm..|
+00000300 e2 21 c5 5c 0e b9 e6 c7 88 92 |.!.\......|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 30 24 93 c5 b1 d0 |..........0$....|
+00000010 bf 5e 5c 79 18 91 d4 c2 5d 82 bd b9 77 44 a8 75 |.^\y....]...wD.u|
+00000020 2a aa 22 c1 71 79 4c ad 7f 95 1f 94 b7 2b 5d cb |*.".qyL......+].|
+00000030 85 57 0a 7e 55 f1 56 4b 98 da b8 |.W.~U.VK...|
+>>> Flow 5 (client to server)
+00000000 17 03 01 00 20 21 19 00 1b 74 03 79 83 6a cf 87 |.... !...t.y.j..|
+00000010 c5 1f c6 e6 ff 1c 8d 9e a9 2b 3c 7e e5 e0 d5 b5 |.........+<~....|
+00000020 c0 d5 1a 84 45 17 03 01 00 20 77 40 7e ac d0 9e |....E.... w@~...|
+00000030 d1 86 73 26 d2 c6 a0 a4 94 9e d7 7e 28 59 5c b2 |..s&.......~(Y\.|
+00000040 9f 4d fa c5 c9 b7 a2 b2 b1 7b 15 03 01 00 20 59 |.M.......{.... Y|
+00000050 aa 2f 3f 2c 20 f1 15 ef 24 95 29 66 c0 48 78 00 |./?, ...$.)f.Hx.|
+00000060 19 d6 1e 95 af 83 03 6e d8 c7 8e bb c3 54 02 |.......n.....T.|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
new file mode 100644
index 0000000..afe6e10
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-ECDSA-RSA
@@ -0,0 +1,138 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 59 02 00 00 55 03 01 b5 1a 96 ea d5 |....Y...U.......|
+00000010 01 ef fb 42 1d 49 e1 1b 7c e4 15 ec cc 7f b9 fc |...B.I..|.......|
+00000020 22 e0 0b 1d 66 0e c8 d6 9b cd ec 20 d5 2b fe 9a |"...f...... .+..|
+00000030 f7 e7 10 1c c4 15 10 f1 24 8d 8f f6 25 90 aa 1c |........$...%...|
+00000040 10 c4 87 c6 36 23 5b 6a c1 ae 20 5e c0 13 00 00 |....6#[j.. ^....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 01 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 |.=.`.\!.;.......|
+000002c0 aa 0c 00 00 a6 03 00 1d 20 87 d5 d1 27 70 92 d9 |........ ...'p..|
+000002d0 15 56 e4 fd a8 52 a9 a5 f6 db ab f5 e2 61 fa 5d |.V...R.......a.]|
+000002e0 64 ba c2 ee 37 0b 53 cf 3c 00 80 71 cd eb 4b 1c |d...7.S.<..q..K.|
+000002f0 f7 84 85 6a 20 5c c8 40 59 1c b0 8e 1b b6 b6 19 |...j \.@Y.......|
+00000300 f1 66 ad 7d 1d d5 58 da c3 c4 dd 12 57 04 05 0d |.f.}..X.....W...|
+00000310 79 46 20 0b 8c a3 49 95 e0 96 22 75 56 44 21 6b |yF ...I..."uVD!k|
+00000320 42 17 ed 32 eb 9c f3 fd b0 b3 08 da 61 7e f3 9b |B..2........a~..|
+00000330 43 51 c0 09 e3 53 17 5d 84 3f c4 52 db 73 f9 d1 |CQ...S.].?.R.s..|
+00000340 21 0e 55 a4 bc a1 1b b6 3a 5a d1 cb 15 7e 8b a4 |!.U.....:Z...~..|
+00000350 fb 0f e7 7e 36 a7 1b a4 c0 1f 79 37 49 17 84 d3 |...~6.....y7I...|
+00000360 97 39 78 1f 55 77 e8 aa 37 2a 36 16 03 01 00 0a |.9x.Uw..7*6.....|
+00000370 0d 00 00 06 03 01 02 40 00 00 16 03 01 00 04 0e |.......@........|
+00000380 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 01 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
+00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
+00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1|
+00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.|
+00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat|
+00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte|
+00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty|
+00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413|
+00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132|
+00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...|
+000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS|
+000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm|
+000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo|
+000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.|
+000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....|
+000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.|
+00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N|
+00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..|
+00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.|
+00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J|
+00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A|
+00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......|
+00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN|
+00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..|
+00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.|
+00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?|
+000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH|
+000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........|
+000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...|
+000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._|
+000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
+000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
+00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
+00000210 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b|
+00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......|
+00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 91 0f 00 |...._X.;t.......|
+00000240 00 8d 00 8b 30 81 88 02 42 01 e7 32 ab 5d d7 f8 |....0...B..2.]..|
+00000250 b6 25 f9 b6 e6 19 eb 20 75 99 90 bc 41 06 74 ce |.%..... u...A.t.|
+00000260 92 31 fc 9e cd f3 b4 b1 b1 f7 1e d3 3c 5e 01 92 |.1..........<^..|
+00000270 a0 c6 24 05 6e 3b ba 6c 51 61 6c 11 fd fe d7 9f |..$.n;.lQal.....|
+00000280 0b 16 b3 1a f7 20 fa b2 3d 92 c9 02 42 01 d7 dc |..... ..=...B...|
+00000290 20 50 f6 91 a3 63 2a 79 37 d4 8b 71 0a 1e 73 f8 | P...c*y7..q..s.|
+000002a0 1e 1c 04 c5 c8 66 bc 5e 67 5e bb 94 76 87 23 12 |.....f.^g^..v.#.|
+000002b0 64 18 cb 09 66 58 f1 06 17 93 1e b9 83 67 9d 3d |d...fX.......g.=|
+000002c0 39 0a fb 37 7b a9 bf d2 59 1a 49 0f 4c 10 df 14 |9..7{...Y.I.L...|
+000002d0 03 01 00 01 01 16 03 01 00 30 4f 0e ba fc 20 81 |.........0O... .|
+000002e0 73 58 e0 47 33 b9 5e c4 6a 10 c2 1a 42 c3 85 2b |sX.G3.^.j...B..+|
+000002f0 20 38 80 5d 40 81 4a 78 40 d9 13 ac af b3 45 e7 | 8.]@.Jx@.....E.|
+00000300 1e 19 c6 b5 63 6e 9c 5c 8a 8d |....cn.\..|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 30 c6 bb 74 56 db |..........0..tV.|
+00000010 fd f7 a7 dd 3b a3 50 10 11 44 83 a1 c6 b1 6e 70 |....;.P..D....np|
+00000020 37 6e 68 b2 5a 45 6b fb e9 9d 4e 68 cf ba ea af |7nh.ZEk...Nh....|
+00000030 7d f6 65 ee 22 14 9e 5a a7 85 65 |}.e."..Z..e|
+>>> Flow 5 (client to server)
+00000000 17 03 01 00 20 c7 78 67 68 03 48 2e a5 c3 7a 0a |.... .xgh.H...z.|
+00000010 56 73 14 02 12 f7 26 ac 48 19 3e e6 4b 0f ac d0 |Vs....&.H.>.K...|
+00000020 4e 74 dc 66 68 17 03 01 00 20 bf db fb e7 85 35 |Nt.fh.... .....5|
+00000030 50 4d 39 3f ab 25 95 30 4c 7a 20 d8 89 db 74 ff |PM9?.%.0Lz ...t.|
+00000040 e6 e1 05 30 98 17 f3 93 8a 0d 15 03 01 00 20 f9 |...0.......... .|
+00000050 33 18 32 46 d3 28 46 a4 06 8c e1 9b 9b 1d d1 d8 |3.2F.(F.........|
+00000060 7b 9f 6c ad 5d 2a 36 10 2c dd f8 30 23 54 ac |{.l.]*6.,..0#T.|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-Ed25519 b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-Ed25519
new file mode 100644
index 0000000..a14cef1
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-Ed25519
@@ -0,0 +1,110 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a8 |.............2..|
+00000050 cc a9 c0 2f c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 |.../.+.0.,.'...#|
+00000060 c0 09 c0 14 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 |...........<./.5|
+00000070 c0 12 00 0a 00 05 c0 11 c0 07 13 01 13 03 13 02 |................|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 08 05 08 06 04 01 04 |................|
+000000b0 03 05 01 05 03 06 01 06 03 02 01 02 03 08 07 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 59 02 00 00 55 03 01 55 df 11 fe c6 |....Y...U..U....|
+00000010 aa d4 85 4b 87 c2 35 4c ac a9 c3 15 a3 7f 6d 7e |...K..5L......m~|
+00000020 15 d1 47 b2 d2 09 16 4d 08 1b dd 20 49 d9 51 42 |..G....M... I.QB|
+00000030 97 cf 36 b3 74 3e 05 0a e5 c9 97 ef 01 9c 24 34 |..6.t>........$4|
+00000040 31 17 e1 8a 6a ce 37 60 02 47 46 7f c0 13 00 00 |1...j.7`.GF.....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 01 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 |.=.`.\!.;.......|
+000002c0 aa 0c 00 00 a6 03 00 1d 20 17 27 58 d2 5f 59 a3 |........ .'X._Y.|
+000002d0 62 62 d4 97 4a 49 c4 ff ec dc f7 d3 c9 ea f3 00 |bb..JI..........|
+000002e0 61 1b d3 73 38 9e af 7d 17 00 80 59 7a 4e 55 97 |a..s8..}...YzNU.|
+000002f0 5a 81 0e 2e 85 0b c2 61 f0 79 72 0e d1 d5 3b bf |Z......a.yr...;.|
+00000300 6a 77 03 0a 9a 51 42 f5 98 2f 09 d5 7b 17 76 b8 |jw...QB../..{.v.|
+00000310 2c a7 95 ee 61 65 d7 37 b3 1b 16 3c 48 7e 9d ed |,...ae.7...<H~..|
+00000320 87 25 b0 77 d9 93 44 28 9f 2a f1 2f 35 23 0d e5 |.%.w..D(.*./5#..|
+00000330 7b 08 e0 b0 42 9b d5 0d e7 ca 73 49 b0 09 03 e2 |{...B.....sI....|
+00000340 bf 25 92 be bf d5 ac 84 38 1e a4 39 66 3b 18 71 |.%......8..9f;.q|
+00000350 31 df 4b 42 9b bf 38 c1 72 81 5c d6 4c 67 b1 58 |1.KB..8.r.\.Lg.X|
+00000360 24 84 71 73 0b 5d 21 9d e2 e6 89 16 03 01 00 0a |$.qs.]!.........|
+00000370 0d 00 00 06 03 01 02 40 00 00 16 03 01 00 04 0e |.......@........|
+00000380 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 01 01 3c 0b 00 01 38 00 01 35 00 01 32 30 |....<...8..5..20|
+00000010 82 01 2e 30 81 e1 a0 03 02 01 02 02 10 17 d1 81 |...0............|
+00000020 93 be 2a 8c 21 20 10 25 15 e8 34 23 4f 30 05 06 |..*.! .%..4#O0..|
+00000030 03 2b 65 70 30 12 31 10 30 0e 06 03 55 04 0a 13 |.+ep0.1.0...U...|
+00000040 07 41 63 6d 65 20 43 6f 30 1e 17 0d 31 39 30 35 |.Acme Co0...1905|
+00000050 31 36 32 31 35 34 32 36 5a 17 0d 32 30 30 35 31 |16215426Z..20051|
+00000060 35 32 31 35 34 32 36 5a 30 12 31 10 30 0e 06 03 |5215426Z0.1.0...|
+00000070 55 04 0a 13 07 41 63 6d 65 20 43 6f 30 2a 30 05 |U....Acme Co0*0.|
+00000080 06 03 2b 65 70 03 21 00 0b e0 b5 60 b5 e2 79 30 |..+ep.!....`..y0|
+00000090 3d be e3 1e e0 50 b1 04 c8 6d c7 78 6c 69 2f c5 |=....P...m.xli/.|
+000000a0 14 ad 9a 63 6f 79 12 91 a3 4d 30 4b 30 0e 06 03 |...coy...M0K0...|
+000000b0 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 |U...........0...|
+000000c0 55 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 |U.%..0...+......|
+000000d0 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 |.0...U.......0.0|
+000000e0 16 06 03 55 1d 11 04 0f 30 0d 82 0b 65 78 61 6d |...U....0...exam|
+000000f0 70 6c 65 2e 63 6f 6d 30 05 06 03 2b 65 70 03 41 |ple.com0...+ep.A|
+00000100 00 fc 19 17 2a 94 a5 31 fa 29 c8 2e 7f 5b a0 5d |....*..1.)...[.]|
+00000110 8a 4e 34 40 39 d6 b3 10 dc 19 fe a0 22 71 b3 f5 |.N4@9......."q..|
+00000120 8f a1 58 0d cd f4 f1 85 24 bf e6 3d 14 df df ed |..X.....$..=....|
+00000130 0e e1 17 d8 11 a2 60 d0 8a 37 23 2a c2 46 aa 3a |......`..7#*.F.:|
+00000140 08 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 |.....%...! /.}.G|
+00000150 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af |.bC.(.._.).0....|
+00000160 c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 46 |......_X.;t....F|
+00000170 0f 00 00 42 00 40 14 6a d7 c1 9c 3d 81 fa e9 da |...B.@.j...=....|
+00000180 96 5c 3a 09 e2 fc 36 e2 30 39 e4 6e 0d ac aa 54 |.\:...6.09.n...T|
+00000190 24 4d 8c f0 35 14 b0 0b e9 5b 57 52 31 02 9f 6c |$M..5....[WR1..l|
+000001a0 6f 6c d7 e9 b5 7f cb 30 fe b9 ba b9 7a 46 67 e3 |ol.....0....zFg.|
+000001b0 a7 50 ca ce e4 04 14 03 01 00 01 01 16 03 01 00 |.P..............|
+000001c0 30 8d 0a ca d1 5e 2c 7e 92 d0 69 f4 d9 e8 5d 0a |0....^,~..i...].|
+000001d0 11 72 67 20 3e 80 64 29 e5 79 f5 33 ad 06 78 07 |.rg >.d).y.3..x.|
+000001e0 4c 03 fc 2e 16 35 70 b1 72 e7 35 a9 cc 49 b8 29 |L....5p.r.5..I.)|
+000001f0 30 |0|
+>>> Flow 4 (server to client)
+00000000 15 03 01 00 02 02 50 |......P|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
new file mode 100644
index 0000000..3ee661e
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-ECDSA
@@ -0,0 +1,133 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 59 02 00 00 55 03 01 b4 ff c0 49 36 |....Y...U.....I6|
+00000010 1d 31 9a a7 f6 33 f5 16 78 d7 10 9e 19 eb 1d 67 |.1...3..x......g|
+00000020 20 39 f8 73 7e 27 e2 dc d1 ab 03 20 79 64 67 f7 | 9.s~'..... ydg.|
+00000030 8b c8 97 f0 b4 87 0e 2d 4b 22 6c ed 92 48 85 52 |.......-K"l..H.R|
+00000040 eb 57 56 a8 cf 19 9f 4d e3 38 5e a0 c0 09 00 00 |.WV....M.8^.....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 01 00 b4 0c 00 00 b0 03 00 1d 20 ec 38 |*............ .8|
+00000280 f7 41 d0 f3 f4 6a ca 47 18 74 f1 22 2c 47 ee 39 |.A...j.G.t.",G.9|
+00000290 c9 a2 db 64 05 01 ae 5d 08 65 53 7f 24 78 00 8a |...d...].eS.$x..|
+000002a0 30 81 87 02 41 64 39 65 56 fa d4 69 e7 c5 a5 32 |0...Ad9eV..i...2|
+000002b0 4c 52 55 96 fe 01 cd 41 3c 18 ed df fd 09 c3 89 |LRU....A<.......|
+000002c0 80 bd 88 9e d7 a1 85 16 d1 a4 5a f0 9a 76 e9 2f |..........Z..v./|
+000002d0 d2 a4 42 a4 89 98 6c 87 64 b1 49 4e 6a 68 d2 43 |..B...l.d.INjh.C|
+000002e0 41 a2 c7 a6 2f f7 02 42 01 6c bb 32 c0 47 7e 08 |A.../..B.l.2.G~.|
+000002f0 6b 7a 44 18 b7 5d 4c 4d 6d 80 92 bb e5 65 98 1b |kzD..]LMm....e..|
+00000300 d7 a6 a3 1b b5 f3 46 1a e7 e0 89 04 40 b0 29 aa |......F.....@.).|
+00000310 fe 85 6a 9a 4b 18 75 ab 00 52 71 54 41 8d eb 31 |..j.K.u..RqTA..1|
+00000320 47 69 9b 9d dc 3b 1b 3e 76 27 16 03 01 00 0a 0d |Gi...;.>v'......|
+00000330 00 00 06 03 01 02 40 00 00 16 03 01 00 04 0e 00 |......@.........|
+00000340 00 00 |..|
+>>> Flow 3 (client to server)
+00000000 16 03 01 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.|
+00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 |......._X.;t....|
+00000230 86 0f 00 00 82 00 80 05 7e 70 eb cb ef e3 d9 6f |........~p.....o|
+00000240 59 29 b5 da f2 07 f5 42 62 4e 74 9b cf 00 e1 5c |Y).....BbNt....\|
+00000250 69 a5 67 3a b0 b2 ca f2 10 ed 1c b4 81 5d 7d 9e |i.g:.........]}.|
+00000260 1a 45 69 42 13 c5 b0 86 dc 3d 60 e5 cf fd ae 0f |.EiB.....=`.....|
+00000270 17 bb 4a ed d7 06 eb f1 6d 47 98 b7 e8 87 eb 3c |..J.....mG.....<|
+00000280 12 55 2c 06 de 55 48 c7 59 85 cb 62 d6 e7 1d 05 |.U,..UH.Y..b....|
+00000290 1e 6d 69 84 cd 16 8e dd ed 5b 5a 2f f2 97 b7 78 |.mi......[Z/...x|
+000002a0 93 c1 fb 75 26 c8 b5 58 43 17 c7 52 54 20 4f 7d |...u&..XC..RT O}|
+000002b0 7c 46 89 65 fe 51 29 14 03 01 00 01 01 16 03 01 ||F.e.Q).........|
+000002c0 00 30 d9 59 e6 7e c0 a6 2a af 36 0c 2e cf 0f 42 |.0.Y.~..*.6....B|
+000002d0 54 d4 41 c6 3c f8 84 d9 2a a6 82 94 22 2d ac ae |T.A.<...*..."-..|
+000002e0 d9 f7 68 22 f6 f0 2e 56 c1 97 80 73 0d b3 f0 70 |..h"...V...s...p|
+000002f0 49 78 |Ix|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 30 06 19 79 49 41 |..........0..yIA|
+00000010 f9 9c 75 84 73 95 96 bd 1e 25 56 a9 49 ed 8e 38 |..u.s....%V.I..8|
+00000020 34 40 60 dc f0 2d f3 6c cf 5b 80 84 2b 81 db 5f |4@`..-.l.[..+.._|
+00000030 f4 27 03 ad b8 8d 80 0c 99 69 6f |.'.......io|
+>>> Flow 5 (client to server)
+00000000 17 03 01 00 20 20 67 bd ff 84 9b 0e 58 f3 45 1e |.... g.....X.E.|
+00000010 7a 25 d5 ae f0 26 4b 42 c7 f3 a5 77 7b 2f 42 21 |z%...&KB...w{/B!|
+00000020 2e c6 c9 81 23 17 03 01 00 20 69 1c 2a b9 05 16 |....#.... i.*...|
+00000030 8b 71 3a c2 18 76 bd 25 1f de 83 e9 14 e2 a3 5c |.q:..v.%.......\|
+00000040 9b 33 ee 14 39 da e2 e7 a3 a7 15 03 01 00 20 e9 |.3..9......... .|
+00000050 dc 16 0c 13 56 7a e5 fd ce b9 4f d1 c7 20 3f ca |....Vz....O.. ?.|
+00000060 72 20 15 f7 11 81 fe 88 ab 90 4c dc 0b a5 11 |r ........L....|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
new file mode 100644
index 0000000..980f933
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv10-ClientCert-RSA-RSA
@@ -0,0 +1,137 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 59 02 00 00 55 03 01 4d 6d 71 59 6b |....Y...U..MmqYk|
+00000010 cd 8c 6e b0 11 bf 4a 9e 25 90 12 cc ac b4 3f be |..n...J.%.....?.|
+00000020 86 1b 13 47 a6 be 3d a0 8f 0b 77 20 6b b5 57 6d |...G..=...w k.Wm|
+00000030 39 74 b0 9d b4 ae 2e 72 7e 90 d2 ab ed 32 fa 65 |9t.....r~....2.e|
+00000040 ed 85 63 d2 16 ef 47 af a6 37 17 88 c0 13 00 00 |..c...G..7......|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 01 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 |.=.`.\!.;.......|
+000002c0 aa 0c 00 00 a6 03 00 1d 20 96 0b 2f 57 e1 1e 07 |........ ../W...|
+000002d0 e0 7f a4 91 67 97 d0 a0 19 d3 9a b2 49 79 f9 5f |....g.......Iy._|
+000002e0 7f b5 65 d4 3a 89 92 8f 11 00 80 08 29 72 0b f7 |..e.:.......)r..|
+000002f0 7b 68 38 5e 47 15 89 f1 ee be f3 a9 26 a4 9c 6d |{h8^G.......&..m|
+00000300 2c 2a ff f0 d6 2d 25 a5 b0 93 66 7d 8c fb fe a5 |,*...-%...f}....|
+00000310 3b cc b6 71 f4 1b 55 c4 ef 08 73 b1 49 47 2c e6 |;..q..U...s.IG,.|
+00000320 a1 ef 53 ca bb 15 e3 25 ea e7 48 44 18 88 e1 d2 |..S....%..HD....|
+00000330 3b e9 f6 92 61 5e 5c 06 44 83 37 6c e6 b6 26 32 |;...a^\.D.7l..&2|
+00000340 fd d6 00 fc 87 a2 37 e3 84 d2 ad 2d 99 0d e1 ba |......7....-....|
+00000350 bb 2f 3b 0b dd 56 5c c2 14 af 86 58 2c 8b f8 64 |./;..V\....X,..d|
+00000360 75 ab d3 35 41 59 fa fe a5 48 26 16 03 01 00 0a |u..5AY...H&.....|
+00000370 0d 00 00 06 03 01 02 40 00 00 16 03 01 00 04 0e |.......@........|
+00000380 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 01 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.|
+00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 01 00 |......._X.;t....|
+00000230 86 0f 00 00 82 00 80 8f 5d a5 27 13 09 5e 49 5f |........].'..^I_|
+00000240 ff fd d6 88 75 83 cc 74 f3 e1 af 44 76 6a 35 16 |....u..t...Dvj5.|
+00000250 e8 36 5f b7 dc 21 69 77 61 12 c5 69 f7 0d 98 1f |.6_..!iwa..i....|
+00000260 d5 15 f1 e8 88 c5 30 e8 b5 c3 2a e5 26 93 cc a4 |......0...*.&...|
+00000270 eb 31 c6 d7 f5 f4 7c d5 f7 a2 3f 1f 75 cd b2 b2 |.1....|...?.u...|
+00000280 82 3a 03 8c 5e 15 0a d2 98 b8 65 cb 5f d5 db d0 |.:..^.....e._...|
+00000290 b6 36 8c 89 7e 48 fa 3a 9f 9a bd c1 48 e7 d6 20 |.6..~H.:....H.. |
+000002a0 ef 45 5b 24 32 04 58 82 b3 7b 42 fd fe ba 78 32 |.E[$2.X..{B...x2|
+000002b0 2a f5 b7 81 33 da db 14 03 01 00 01 01 16 03 01 |*...3...........|
+000002c0 00 30 5f 96 98 94 17 6d ff 84 72 d3 63 fd 14 59 |.0_....m..r.c..Y|
+000002d0 eb bf 5f 3e 8f dc f1 c1 dc 77 8a 33 f6 2e a2 4a |.._>.....w.3...J|
+000002e0 15 d1 2e a4 ec 0d 3c 0b 18 07 09 6c 0d 09 34 2e |......<....l..4.|
+000002f0 a4 6f |.o|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 30 b7 4a 5c 0c e6 |..........0.J\..|
+00000010 7c d9 43 7c e7 b4 2f d7 b5 c6 5e 36 c7 87 dd 82 ||.C|../...^6....|
+00000020 da d3 b2 4e 05 ae f5 8c b0 4d db c2 53 62 55 73 |...N.....M..SbUs|
+00000030 8c 2a 1b d5 df e4 7c a4 cf db 8b |.*....|....|
+>>> Flow 5 (client to server)
+00000000 17 03 01 00 20 b9 26 60 87 38 9c d9 c4 65 17 8e |.... .&`.8...e..|
+00000010 3c 7f 1a b4 23 cd 27 fd 4e 92 ee 0e f2 11 dc e2 |<...#.'.N.......|
+00000020 23 e4 26 f3 55 17 03 01 00 20 5e 89 33 21 f0 dc |#.&.U.... ^.3!..|
+00000030 e8 4f 33 1c 66 56 99 38 a5 4c 0e 0e 93 41 b7 48 |.O3.fV.8.L...A.H|
+00000040 5d ce 49 d0 d2 8a 56 a6 2d 68 15 03 01 00 20 05 |].I...V.-h.... .|
+00000050 e0 ed f9 c2 56 ec 64 e5 e7 0b f4 8a e2 41 96 9e |....V.d......A..|
+00000060 ed 94 c8 95 69 d7 ce 2d 0e bb 5b 18 5f 30 52 |....i..-..[._0R|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
new file mode 100644
index 0000000..6fc506f
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-ECDSA-AES
@@ -0,0 +1,91 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 59 02 00 00 55 03 01 a3 4e 79 27 af |....Y...U...Ny'.|
+00000010 c8 a3 15 a4 c2 7a 54 58 54 0e 0d 93 c2 ff e1 f9 |.....zTXT.......|
+00000020 55 ab 2c ea 32 cf d2 47 2e d7 8e 20 49 08 d1 66 |U.,.2..G... I..f|
+00000030 9b 9e aa af c9 90 95 ec cb 64 2e 3d f6 27 d5 f6 |.........d.=.'..|
+00000040 23 10 d5 6e 50 5f bc 89 fe c7 d7 de c0 09 00 00 |#..nP_..........|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 01 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 01 00 b5 0c 00 00 b1 03 00 1d 20 4a 7c |*............ J||
+00000280 0a 86 8a 81 f2 60 4a 3c ac d7 7d 3b fc 00 a5 b4 |.....`J<..};....|
+00000290 85 45 45 45 fb 09 53 d7 4a cf 24 9d c8 1a 00 8b |.EEE..S.J.$.....|
+000002a0 30 81 88 02 42 01 7a c9 c0 76 8c 26 98 63 4e a3 |0...B.z..v.&.cN.|
+000002b0 ad 4f 4e a3 d7 c7 d6 4a 69 28 cf d2 7b 0b 36 fb |.ON....Ji(..{.6.|
+000002c0 a3 ae 2f e1 83 ea ea 4a b7 2d ef a8 2d 13 96 e4 |../....J.-..-...|
+000002d0 73 83 66 70 5e 5c d9 5a d1 1c d1 33 18 0b b3 30 |s.fp^\.Z...3...0|
+000002e0 2a 21 d7 78 d8 70 18 02 42 00 c4 ab 80 33 8f f1 |*!.x.p..B....3..|
+000002f0 c2 74 1b 58 2f 59 d4 27 a1 19 42 bf 14 ea a8 a2 |.t.X/Y.'..B.....|
+00000300 cb bf 96 2d 60 7b 84 40 cc 31 f5 c4 e8 51 87 b8 |...-`{.@.1...Q..|
+00000310 7b 47 ec c4 c0 4a 9b 09 59 1e f8 b5 9a e1 45 a4 |{G...J..Y.....E.|
+00000320 a1 9b ee 78 55 f8 f5 fa 1a fb c5 16 03 01 00 04 |...xU...........|
+00000330 0e 00 00 00 |....|
+>>> Flow 3 (client to server)
+00000000 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 01 00 01 01 |....._X.;t......|
+00000030 16 03 01 00 30 b0 5e 4a 8a 07 e3 86 43 05 16 68 |....0.^J....C..h|
+00000040 0e d1 58 a6 05 49 e9 a6 42 89 2c 3f 33 68 8b 26 |..X..I..B.,?3h.&|
+00000050 23 21 3b 62 ab 7a 21 74 d8 49 15 03 b3 1e c6 53 |#!;b.z!t.I.....S|
+00000060 74 1e 1c 4e 0f |t..N.|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 30 64 4b 3c 1a e3 |..........0dK<..|
+00000010 7d bb bb bb 64 d8 51 c3 eb 92 65 65 58 35 dd 7b |}...d.Q...eeX5.{|
+00000020 d2 fd f0 0c c1 10 71 a5 a8 f7 14 84 69 b4 81 18 |......q.....i...|
+00000030 1e 0d d3 19 b6 23 72 1a a7 43 0e |.....#r..C.|
+>>> Flow 5 (client to server)
+00000000 17 03 01 00 20 c3 e6 70 2c 44 4f 04 0c fb 0b 7f |.... ..p,DO.....|
+00000010 1d 2c ef 4d cc c3 21 ba a2 db 74 76 46 ea 00 40 |.,.M..!...tvF..@|
+00000020 54 2d 4a fe 59 17 03 01 00 20 0c 6b 39 0d b5 f3 |T-J.Y.... .k9...|
+00000030 ed 7e d0 de 01 18 0c 32 4e 59 93 46 d3 c5 4f c0 |.~.....2NY.F..O.|
+00000040 f5 fd f1 d2 79 07 7d 07 b0 24 15 03 01 00 20 1d |....y.}..$.... .|
+00000050 f7 53 a2 e7 3f 88 87 35 01 6e a5 b1 d6 81 37 5b |.S..?..5.n....7[|
+00000060 a7 64 4c 29 f4 71 59 a1 36 c1 1a 24 93 31 7d |.dL).qY.6..$.1}|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
new file mode 100644
index 0000000..24da556
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv10-ECDHE-RSA-AES
@@ -0,0 +1,95 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 59 02 00 00 55 03 01 63 68 ea 52 0b |....Y...U..ch.R.|
+00000010 dc 68 c7 d0 75 3e 7d 6f 0b 8c cb 25 48 b0 bb df |.h..u>}o...%H...|
+00000020 7a 56 93 a9 d5 4f 0c 3a e2 37 ab 20 1f 0f a4 d3 |zV...O.:.7. ....|
+00000030 b4 f6 66 6f 39 6f 62 fb 6a 1f 41 09 4b 02 5c 15 |..fo9ob.j.A.K.\.|
+00000040 a0 ba cb a6 f9 bd 3b ec cb 76 6e ea c0 13 00 00 |......;..vn.....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 01 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 |.=.`.\!.;.......|
+000002c0 aa 0c 00 00 a6 03 00 1d 20 04 9f 8b 4f 13 83 26 |........ ...O..&|
+000002d0 a3 cf 08 6e 59 bf b5 49 b8 ff 95 94 21 8d 2a 56 |...nY..I....!.*V|
+000002e0 2e 4b be ad ac 89 6e 52 4d 00 80 5f 63 93 43 a2 |.K....nRM.._c.C.|
+000002f0 a6 fb 53 b0 ac 93 3f 55 1d c1 0f 71 1e 96 ba 9f |..S...?U...q....|
+00000300 86 19 f3 83 7d 90 ce 06 24 9a 60 69 f0 35 24 5d |....}...$.`i.5$]|
+00000310 9d ce 49 0d 6f ba 31 59 3c f2 64 27 66 76 0e f1 |..I.o.1Y<.d'fv..|
+00000320 33 eb b8 70 61 d3 0c 93 a3 62 c7 5e c2 06 9d 48 |3..pa....b.^...H|
+00000330 16 2e a6 62 50 18 f6 c0 79 c2 09 f3 d5 74 bf db |...bP...y....t..|
+00000340 b8 d4 25 06 a7 be 4a b0 62 82 86 d0 00 86 5e a2 |..%...J.b.....^.|
+00000350 34 49 9b 37 37 9a b6 eb cc b9 8b 17 1f 29 4b a3 |4I.77........)K.|
+00000360 51 e3 c3 e8 3e 6e df c4 1d e5 48 16 03 01 00 04 |Q...>n....H.....|
+00000370 0e 00 00 00 |....|
+>>> Flow 3 (client to server)
+00000000 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 01 00 01 01 |....._X.;t......|
+00000030 16 03 01 00 30 a6 3a 66 02 e6 09 6a dd 68 56 bc |....0.:f...j.hV.|
+00000040 aa ec 82 c4 69 9b b9 45 44 ec e2 c2 5b 49 5d 9b |....i..ED...[I].|
+00000050 f8 0e 81 1e 23 9e 13 72 d1 d2 0c 24 01 4f 35 aa |....#..r...$.O5.|
+00000060 27 fc b3 cc 08 |'....|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 30 0e 25 d7 a9 c0 |..........0.%...|
+00000010 18 3b bf 55 c0 47 3a 95 2d cb 6f c2 2c de e3 94 |.;.U.G:.-.o.,...|
+00000020 32 d3 eb e2 b6 6b 5f 42 9c 1e 47 d6 76 0c eb 95 |2....k_B..G.v...|
+00000030 fd 2d c3 9a ee ee 83 87 e8 8d 83 |.-.........|
+>>> Flow 5 (client to server)
+00000000 17 03 01 00 20 ba b0 c4 22 ee 52 81 ca 55 97 4d |.... ...".R..U.M|
+00000010 39 16 b9 37 bf df 7b d1 ae 4b 47 ac 10 12 a9 77 |9..7..{..KG....w|
+00000020 69 50 f3 60 13 17 03 01 00 20 90 d5 17 e4 96 38 |iP.`..... .....8|
+00000030 cd f7 30 6e 19 45 4e 32 ad 5f 1b 00 bf 22 9d c2 |..0n.EN2._..."..|
+00000040 16 30 fe 92 c7 fc 91 38 29 30 15 03 01 00 20 c0 |.0.....8)0.... .|
+00000050 02 ff 81 82 c9 25 c6 b0 06 ee 18 61 19 c8 d2 20 |.....%.....a... |
+00000060 d8 4e 7b a4 a5 57 17 64 4d ad 1e 1e 16 1e 52 |.N{..W.dM.....R|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-Ed25519 b/src/crypto/tls/testdata/Client-TLSv10-Ed25519
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv10-Ed25519
diff --git a/src/crypto/tls/testdata/Client-TLSv10-ExportKeyingMaterial b/src/crypto/tls/testdata/Client-TLSv10-ExportKeyingMaterial
new file mode 100644
index 0000000..6a40d83
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv10-ExportKeyingMaterial
@@ -0,0 +1,95 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 59 02 00 00 55 03 01 05 31 9d 41 04 |....Y...U...1.A.|
+00000010 c0 d4 34 1a fc 0f 63 26 47 d6 13 7f a0 d8 aa bf |..4...c&G.......|
+00000020 28 92 04 80 02 75 58 e6 01 e1 30 20 3c fc b0 02 |(....uX...0 <...|
+00000030 8b a4 9e 9e b2 5c 17 3c 48 0b 96 6f 15 80 d5 38 |.....\.<H..o...8|
+00000040 25 a2 f8 fb 6b fd 47 27 c2 53 6c 60 c0 13 00 00 |%...k.G'.Sl`....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 01 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 |.=.`.\!.;.......|
+000002c0 aa 0c 00 00 a6 03 00 1d 20 a4 50 9a 0d c7 2a 1b |........ .P...*.|
+000002d0 f6 d4 78 49 68 ac 5f 8b e7 78 68 05 4b f8 c6 b3 |..xIh._..xh.K...|
+000002e0 eb 28 79 96 d5 e6 aa c1 54 00 80 22 66 ec fd 14 |.(y.....T.."f...|
+000002f0 83 7b 03 86 14 75 84 a4 a6 d0 ee d3 d0 f7 95 d8 |.{...u..........|
+00000300 43 48 a4 eb 83 af 96 ac cf e8 65 20 05 c3 18 9a |CH........e ....|
+00000310 54 63 f5 2f b7 17 06 e0 2a b3 65 6a 2f cc cd 93 |Tc./....*.ej/...|
+00000320 1e b3 5a 4d 09 da 70 b0 12 46 60 11 e4 9f ee 9f |..ZM..p..F`.....|
+00000330 3b 6f ef df bc db 69 22 5e e8 4c 41 d6 b7 7b 06 |;o....i"^.LA..{.|
+00000340 b6 99 1c 6d 01 5a 61 7c 4e 3a af 3e 01 7e 46 bd |...m.Za|N:.>.~F.|
+00000350 c8 15 28 ba 7f b3 d6 9d 95 74 04 36 6c 38 16 86 |..(......t.6l8..|
+00000360 d2 1d 8a 85 d1 21 5c 33 17 50 a1 16 03 01 00 04 |.....!\3.P......|
+00000370 0e 00 00 00 |....|
+>>> Flow 3 (client to server)
+00000000 16 03 01 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 01 00 01 01 |....._X.;t......|
+00000030 16 03 01 00 30 f0 15 ea 81 0f a6 22 0a cd a5 a1 |....0......"....|
+00000040 38 4a da 1b 6c 81 19 d5 35 b7 af e9 ec 16 4d 98 |8J..l...5.....M.|
+00000050 21 c2 0e f7 0b fb ff d8 1e 2d 8b 04 56 82 48 c4 |!........-..V.H.|
+00000060 e5 f9 38 8c d2 |..8..|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 30 f0 b5 a3 bb bb |..........0.....|
+00000010 9d 85 7d 6f e7 a9 17 31 65 74 82 69 56 a9 33 21 |..}o...1et.iV.3!|
+00000020 16 9d 75 3a 28 88 a5 c2 a9 e1 a7 43 6e 03 26 96 |..u:(......Cn.&.|
+00000030 37 4b de 63 be 49 cb c8 d4 a2 b6 |7K.c.I.....|
+>>> Flow 5 (client to server)
+00000000 17 03 01 00 20 a9 9c 8f 74 ce f9 77 bc b3 86 2e |.... ...t..w....|
+00000010 a5 8e 94 3d 08 a6 96 bf 25 0b 10 c4 66 c2 59 9a |...=....%...f.Y.|
+00000020 4a 1a b4 77 12 17 03 01 00 20 03 72 60 38 58 88 |J..w..... .r`8X.|
+00000030 86 20 20 3f 18 52 c5 ca 55 3c 04 04 c7 e1 74 6f |. ?.R..U<....to|
+00000040 ca 1f cd 27 64 f2 51 12 9c ee 15 03 01 00 20 30 |...'d.Q....... 0|
+00000050 71 2a 78 bf 8b d5 11 7c 63 11 c7 25 0e 56 25 ce |q*x....|c..%.V%.|
+00000060 24 d5 d7 de a0 ba c7 ba e6 dc db 8e e3 93 a6 |$..............|
diff --git a/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4 b/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4
new file mode 100644
index 0000000..dcc18ad
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv10-RSA-RC4
@@ -0,0 +1,84 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 51 02 00 00 4d 03 01 2a 09 26 d2 61 |....Q...M..*.&.a|
+00000010 ac 38 91 3d 18 3f f7 a9 3c 34 91 b0 b1 e1 29 68 |.8.=.?..<4....)h|
+00000020 dd cb b9 a9 d8 39 0b 64 c6 93 7d 20 ea 51 ff 63 |.....9.d..} .Q.c|
+00000030 97 03 b2 6f a3 d6 55 0d 64 65 2a 5d 3a fe e9 3e |...o..U.de*]:..>|
+00000040 47 c1 7d c5 d8 03 c6 22 19 2f 6c 5a 00 05 00 00 |G.}...."./lZ....|
+00000050 05 ff 01 00 01 00 16 03 01 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 01 00 04 0e 00 00 00 |;............|
+>>> Flow 3 (client to server)
+00000000 16 03 01 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 01 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 01 00 24 29 ee 6c 54 d6 21 5e 31 30 9e |.....$).lT.!^10.|
+000000a0 fd 02 69 bb 32 c2 9e ad 28 b1 2d 94 49 0a 12 0c |..i.2...(.-.I...|
+000000b0 a1 12 b0 98 a6 33 eb 63 2b e4 |.....3.c+.|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 24 32 3e 45 f2 3a |..........$2>E.:|
+00000010 01 05 50 db 37 25 f6 b5 67 8e 38 3d f5 ba b7 90 |..P.7%..g.8=....|
+00000020 e0 05 a8 cb e0 33 1a 79 ab 44 86 d5 0c fd 86 |.....3.y.D.....|
+>>> Flow 5 (client to server)
+00000000 17 03 01 00 1a ac 0c 1f 12 4e d4 31 10 dd c1 04 |.........N.1....|
+00000010 8b 55 a2 2e a5 f4 e4 80 aa 23 7e bd 79 b0 ee 15 |.U.......#~.y...|
+00000020 03 01 00 16 fa d9 ff 50 7d 41 01 2a d2 13 ee 33 |.......P}A.*...3|
+00000030 52 ab 20 c5 e7 73 81 5d 81 60 |R. ..s.].`|
diff --git a/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
new file mode 100644
index 0000000..92cdc4c
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-ECDSA-AES
@@ -0,0 +1,93 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 02 00 59 02 00 00 55 03 02 bf ac 6b 91 53 |....Y...U....k.S|
+00000010 dc 1f d6 ee 0e 71 d6 a4 f5 a2 7c f0 10 69 41 dd |.....q....|..iA.|
+00000020 4a b7 30 53 e6 28 07 31 34 8f e5 20 59 d1 bd e1 |J.0S.(.14.. Y...|
+00000030 20 44 c4 05 07 e9 07 90 5d de 08 73 72 55 04 a6 | D......]..srU..|
+00000040 11 20 bf 32 e0 dd 46 d4 1d ed 45 62 c0 09 00 00 |. .2..F...Eb....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 02 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 02 00 b5 0c 00 00 b1 03 00 1d 20 ab ea |*............ ..|
+00000280 ff 17 1e b1 ef f6 22 03 40 8b e1 1a fa ab 01 cf |......".@.......|
+00000290 0f f0 b0 6d 43 3c 1f 03 a1 d6 4a 9d 79 43 00 8b |...mC<....J.yC..|
+000002a0 30 81 88 02 42 00 a1 b4 50 4b 9b a3 a5 ec ef dc |0...B...PK......|
+000002b0 bf c1 a2 65 24 2a 6c aa ab 26 01 ed d1 ad 2e 37 |...e$*l..&.....7|
+000002c0 4f f5 8b ff 98 ac ef 15 3e d9 46 07 a3 d2 35 de |O.......>.F...5.|
+000002d0 91 bc 3d a0 1f f1 68 55 28 ef 60 ad 13 05 ac 65 |..=...hU(.`....e|
+000002e0 e5 67 02 3f 85 8b 1b 02 42 01 26 3f fc 62 e3 93 |.g.?....B.&?.b..|
+000002f0 8e fa fb 93 0f 0b ff 68 25 46 ea 71 16 ae 6e d4 |.......h%F.q..n.|
+00000300 36 9e 48 2c 77 2b d8 f5 f6 1d 69 68 ed 28 8f e7 |6.H,w+....ih.(..|
+00000310 79 7e 78 56 52 ff e8 62 fc e2 bd 2e c7 e8 9f 3f |y~xVR..b.......?|
+00000320 93 47 d2 62 6c f6 5c 0e a2 b8 fe 16 03 02 00 04 |.G.bl.\.........|
+00000330 0e 00 00 00 |....|
+>>> Flow 3 (client to server)
+00000000 16 03 02 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 02 00 01 01 |....._X.;t......|
+00000030 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
+00000040 00 00 00 00 00 0f 55 37 4b 93 d5 ce b1 1c 6f a3 |......U7K.....o.|
+00000050 6d 56 32 f5 de 19 f6 a3 15 b0 6a 90 06 92 60 ca |mV2.......j...`.|
+00000060 ec 0e 2b d4 24 16 0a 26 f3 bd 3d ca c5 9f d2 9b |..+.$..&..=.....|
+00000070 79 2f af b6 b0 |y/...|
+>>> Flow 4 (server to client)
+00000000 14 03 02 00 01 01 16 03 02 00 40 4d e3 a9 af 51 |..........@M...Q|
+00000010 f5 d1 cd 04 f1 cf c5 48 0f 2e 0b 6e 57 4c 11 28 |.......H...nWL.(|
+00000020 dd 89 19 14 98 8e 2e 92 db 3c a4 0f 85 32 90 7e |.........<...2.~|
+00000030 49 13 17 a0 85 fa c6 25 79 24 13 90 86 dc ec 45 |I......%y$.....E|
+00000040 7c 74 35 92 e4 89 04 c2 51 27 66 ||t5.....Q'f|
+>>> Flow 5 (client to server)
+00000000 17 03 02 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+00000010 00 00 00 00 00 f9 ac 17 1f 08 b7 80 fb 70 87 e2 |.............p..|
+00000020 53 00 27 60 78 6c 80 5b 57 e7 70 72 8a e3 1b 32 |S.'`xl.[W.pr...2|
+00000030 8c f0 67 82 82 15 03 02 00 30 00 00 00 00 00 00 |..g......0......|
+00000040 00 00 00 00 00 00 00 00 00 00 01 e1 86 47 7f 65 |.............G.e|
+00000050 a9 d2 1c 22 7d 99 7c 41 dc 17 f5 16 40 5b b3 7f |..."}.|A....@[..|
+00000060 cc 0b 97 41 0c ae 1f 0c 39 e0 |...A....9.|
diff --git a/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
new file mode 100644
index 0000000..b2b7ecb
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv11-ECDHE-RSA-AES
@@ -0,0 +1,97 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 02 00 59 02 00 00 55 03 02 95 6e 24 5a ab |....Y...U...n$Z.|
+00000010 ae 3c 73 52 9d 31 63 50 cf f9 50 99 3c e4 94 22 |.<sR.1cP..P.<.."|
+00000020 5b 6f 0e f8 e3 a8 64 4c d2 8c 00 20 8b 2d 25 47 |[o....dL... .-%G|
+00000030 f9 74 41 93 b1 82 b5 c5 fc 3e 42 c9 35 fc 68 27 |.tA......>B.5.h'|
+00000040 c4 2b 35 0f f8 1c e3 28 e6 8a 59 dc c0 13 00 00 |.+5....(..Y.....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 02 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 02 00 |.=.`.\!.;.......|
+000002c0 aa 0c 00 00 a6 03 00 1d 20 b5 75 ee e5 26 6b c0 |........ .u..&k.|
+000002d0 af 34 8a 24 f7 c5 25 58 29 38 4c 08 d3 a2 0c 48 |.4.$..%X)8L....H|
+000002e0 18 eb a0 5b e8 64 62 62 78 00 80 d0 1c 9c 11 1a |...[.dbbx.......|
+000002f0 58 4c 46 5f 18 03 d7 d7 76 47 d5 56 7a bb bd 95 |XLF_....vG.Vz...|
+00000300 16 46 e8 0b 28 6e df 15 65 1a f6 95 fb 4a 6c 42 |.F..(n..e....JlB|
+00000310 1b 4c 5c 30 c5 de d0 83 08 d3 2e 4d 59 7e 7b 1b |.L\0.......MY~{.|
+00000320 20 9e b5 19 76 fe a3 dd 87 04 f4 9a 3e 3c c0 4a | ...v.......><.J|
+00000330 16 7f e3 4e 9a 1f 0a 36 1d f5 09 b4 88 09 b1 1b |...N...6........|
+00000340 9b 60 97 dc d7 ea 97 f4 d6 06 16 45 98 ee 5c 39 |.`.........E..\9|
+00000350 62 3f 7c 82 7b c3 52 59 01 d4 89 8c a6 e2 d5 eb |b?|.{.RY........|
+00000360 e8 30 a6 78 49 1e ec a5 92 ad 24 16 03 02 00 04 |.0.xI.....$.....|
+00000370 0e 00 00 00 |....|
+>>> Flow 3 (client to server)
+00000000 16 03 02 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 02 00 01 01 |....._X.;t......|
+00000030 16 03 02 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
+00000040 00 00 00 00 00 28 ab ed 77 d3 56 29 a8 4a 38 c8 |.....(..w.V).J8.|
+00000050 64 1c a5 d9 4e f9 6b 0e fa 82 42 ad 0d be 15 69 |d...N.k...B....i|
+00000060 9a ff 79 64 db 8f 3e 16 b3 86 93 82 6f 78 c4 2e |..yd..>.....ox..|
+00000070 7c 54 6c 4f 90 ||TlO.|
+>>> Flow 4 (server to client)
+00000000 14 03 02 00 01 01 16 03 02 00 40 15 e9 c5 15 59 |..........@....Y|
+00000010 b3 0d 46 22 0c ae a6 41 02 b4 f3 da 11 dc 85 79 |..F"...A.......y|
+00000020 bb d9 3f 23 38 51 24 1a 08 b5 a0 63 dc 4b 86 50 |..?#8Q$....c.K.P|
+00000030 ef b2 32 07 fd b5 e1 01 06 19 42 ce ba 69 ab 1a |..2.......B..i..|
+00000040 c9 bb db 7d d0 9f f9 7c f2 6c 18 |...}...|.l.|
+>>> Flow 5 (client to server)
+00000000 17 03 02 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+00000010 00 00 00 00 00 67 ef de df a4 91 69 58 b8 3f 06 |.....g.....iX.?.|
+00000020 c4 05 4e ad 88 9b c5 12 35 cf 63 39 3a 61 e9 4c |..N.....5.c9:a.L|
+00000030 49 22 93 f4 10 15 03 02 00 30 00 00 00 00 00 00 |I".......0......|
+00000040 00 00 00 00 00 00 00 00 00 00 00 2a 5a ba 39 7e |...........*Z.9~|
+00000050 a8 be 2e 72 f3 ba 7e 0a 32 b5 8c d8 f5 1b 93 6c |...r..~.2......l|
+00000060 3e 35 d8 ba cc f3 9f f4 19 74 |>5.......t|
diff --git a/src/crypto/tls/testdata/Client-TLSv11-Ed25519 b/src/crypto/tls/testdata/Client-TLSv11-Ed25519
new file mode 100644
index 0000000..e69de29
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv11-Ed25519
diff --git a/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4 b/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4
new file mode 100644
index 0000000..aeba311
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv11-RSA-RC4
@@ -0,0 +1,84 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 02 00 51 02 00 00 4d 03 02 82 5b 12 ac 33 |....Q...M...[..3|
+00000010 08 d4 28 8c 91 6e 52 c4 c6 09 13 24 bf 42 d2 37 |..(..nR....$.B.7|
+00000020 6d 78 60 b0 ea bd 9e b3 08 99 43 20 05 5a 93 f9 |mx`.......C .Z..|
+00000030 a4 39 43 4f c4 e3 27 20 7d 4c fa 7a 28 c1 c7 33 |.9CO..' }L.z(..3|
+00000040 72 fa 14 b8 ba c3 89 b0 a5 54 a3 7c 00 05 00 00 |r........T.|....|
+00000050 05 ff 01 00 01 00 16 03 02 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 02 00 04 0e 00 00 00 |;............|
+>>> Flow 3 (client to server)
+00000000 16 03 02 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 02 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 02 00 24 e1 1a bf e9 fd 4c fb 56 41 82 |.....$.....L.VA.|
+000000a0 c2 48 fc ca d9 d5 ec 2a 0a ee 63 25 e0 5f 53 cf |.H.....*..c%._S.|
+000000b0 24 ff fe da 6f f5 8b 61 b7 b9 |$...o..a..|
+>>> Flow 4 (server to client)
+00000000 14 03 02 00 01 01 16 03 02 00 24 99 2c e7 fa d0 |..........$.,...|
+00000010 29 d9 92 07 39 56 b0 0c ad 23 30 c8 d7 0b 38 da |)...9V...#0...8.|
+00000020 6f d3 c7 f9 66 d2 ec 8c 52 85 cb db a6 22 50 |o...f...R...."P|
+>>> Flow 5 (client to server)
+00000000 17 03 02 00 1a 9f 70 c4 77 f3 0a a8 e0 1a 75 87 |......p.w.....u.|
+00000010 ab 2a f1 23 52 79 9f 5c 8e af 5d ba 27 45 f9 15 |.*.#Ry.\..].'E..|
+00000020 03 02 00 16 f0 28 f3 71 a0 97 6b ba 7e 97 81 85 |.....(.q..k.~...|
+00000030 11 59 1b c9 fa a0 48 32 e9 65 |.Y....H2.e|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256 b/src/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256
new file mode 100644
index 0000000..ce92872
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-AES128-GCM-SHA256
@@ -0,0 +1,86 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 51 02 00 00 4d 03 03 a4 26 bb e9 70 |....Q...M...&..p|
+00000010 57 4e ec f8 ea 23 01 75 c3 f3 a9 d4 d6 e8 71 2b |WN...#.u......q+|
+00000020 01 5e c0 73 19 2b b9 d8 8e 3e d1 20 c8 c3 0a 22 |.^.s.+...>. ..."|
+00000030 7b ee cd 2e c9 e8 95 db 90 db 70 f5 59 e6 90 65 |{.........p.Y..e|
+00000040 35 87 a6 d4 bb dd 85 34 43 e8 66 49 00 9c 00 00 |5......4C.fI....|
+00000050 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 03 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 03 00 28 00 00 00 00 00 00 00 00 64 6c |.....(........dl|
+000000a0 08 78 1d 03 0c ed dd 01 30 d4 fb 7c 3f 24 45 cc |.x......0..|?$E.|
+000000b0 f6 b2 e3 42 07 93 8f 34 a8 21 d1 b0 08 e3 |...B...4.!....|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 75 9b 91 cd 7d |..........(u...}|
+00000010 8d f7 3c a0 d6 5e d4 f2 24 1a 0a f3 04 b1 d9 0b |..<..^..$.......|
+00000020 1d 31 ca 1c 8b e7 38 c0 8e 7d 12 19 89 33 28 4d |.1....8..}...3(M|
+00000030 83 28 b6 |.(.|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 7d fe 53 |.............}.S|
+00000010 73 aa ca 3d f3 27 b7 01 56 9e e7 c9 6d 79 2a 97 |s..=.'..V...my*.|
+00000020 b2 21 42 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.!B.............|
+00000030 de bd 3e 9e 8f c0 98 ec bd b4 9b 89 90 a2 26 a8 |..>...........&.|
+00000040 28 97 |(.|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-AES128-SHA256 b/src/crypto/tls/testdata/Client-TLSv12-AES128-SHA256
new file mode 100644
index 0000000..15394c7
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-AES128-SHA256
@@ -0,0 +1,95 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 51 02 00 00 4d 03 03 8a a8 2c 00 d8 |....Q...M....,..|
+00000010 d8 87 53 14 1e 7b ff ca 19 a2 6d bc 47 6f 73 12 |..S..{....m.Gos.|
+00000020 0d 54 6e 33 21 80 01 86 f8 81 9f 20 46 f6 8c e8 |.Tn3!...... F...|
+00000030 8b 90 02 b2 da e2 83 3a 2a 0f b3 f7 96 2b f8 96 |.......:*....+..|
+00000040 56 77 39 52 9e a1 bd 74 1e 2e b1 b0 00 3c 00 00 |Vw9R...t.....<..|
+00000050 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 03 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 03 00 50 00 00 00 00 00 00 00 00 00 00 |.....P..........|
+000000a0 00 00 00 00 00 00 8f d8 ac 7f ec 16 9e d8 e9 f2 |................|
+000000b0 ce 30 51 dc 87 e0 f9 80 57 66 d9 87 20 77 3a b1 |.0Q.....Wf.. w:.|
+000000c0 43 db fc 36 f5 64 6e 96 e9 b8 e2 ab bb 00 48 36 |C..6.dn.......H6|
+000000d0 60 9c 5a 7c 38 3f 13 e1 9c ef d9 15 96 91 56 e2 |`.Z|8?........V.|
+000000e0 87 2e 23 1a 98 40 |..#..@|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 50 80 01 08 cc d8 |..........P.....|
+00000010 08 a8 81 20 b2 bb 5b 50 79 74 4a b5 10 c4 7a 30 |... ..[PytJ...z0|
+00000020 6c 46 d6 e5 36 6e 4d cc e5 0c 2c ab 3b de 92 45 |lF..6nM...,.;..E|
+00000030 ee 20 58 a9 0f 03 26 3e 6c 05 a7 ef f2 7c a7 9b |. X...&>l....|..|
+00000040 57 c0 20 8d d0 69 0e b0 5a cc e6 26 5f e2 c3 24 |W. ..i..Z..&_..$|
+00000050 c4 db df 20 03 08 e1 aa 59 2b d2 |... ....Y+.|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
+00000010 00 00 00 00 00 a2 dd a6 ff 57 60 80 dd 97 cf 20 |.........W`.... |
+00000020 10 04 60 80 53 17 37 ce ce 39 b6 21 f4 06 61 aa |..`.S.7..9.!..a.|
+00000030 49 7b f0 d5 e0 72 4c 6f 38 d2 ab af 1c 94 bd 5b |I{...rLo8......[|
+00000040 1b ee 8a 9b e3 15 03 03 00 40 00 00 00 00 00 00 |.........@......|
+00000050 00 00 00 00 00 00 00 00 00 00 ba 18 32 e7 6d f5 |............2.m.|
+00000060 fa 2e 61 55 cc fe 3c 4d 19 fd 84 6d c4 2a 46 92 |..aU..<M...m.*F.|
+00000070 ae b7 f3 67 c8 3c ce cd b0 66 de ee 5d 3f 07 3b |...g.<...f..]?.;|
+00000080 a9 85 a1 93 1f 98 f7 95 c9 ac |..........|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384 b/src/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384
new file mode 100644
index 0000000..766bf95
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-AES256-GCM-SHA384
@@ -0,0 +1,86 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 51 02 00 00 4d 03 03 de 7a 77 5b eb |....Q...M...zw[.|
+00000010 fa 84 a0 ac ba 3b ca 25 dc b3 c0 06 44 da 31 5c |.....;.%....D.1\|
+00000020 27 e0 4e af be 47 07 5a a5 ab 20 20 72 b2 67 0c |'.N..G.Z.. r.g.|
+00000030 7e 71 5d e3 55 89 91 27 7f 65 ac 71 c6 e8 a5 4a |~q].U..'.e.q...J|
+00000040 ae e1 a2 0d 3f a6 62 08 17 7e 26 fd 00 9d 00 00 |....?.b..~&.....|
+00000050 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 03 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 03 00 28 00 00 00 00 00 00 00 00 0b 7d |.....(.........}|
+000000a0 83 0f 79 e2 4b ef d3 0e ff 57 d2 55 cd ea e9 be |..y.K....W.U....|
+000000b0 8b 38 1e 33 b0 6a eb e3 aa 51 52 82 e6 15 |.8.3.j...QR...|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 1a a3 bb d4 c4 |..........(.....|
+00000010 53 c7 5c 09 8c fb e7 51 41 73 d5 76 ef e6 40 9a |S.\....QAs.v..@.|
+00000020 06 27 c6 e8 9f 1b 25 f5 d1 7b 39 b7 74 ab e8 83 |.'....%..{9.t...|
+00000030 26 f6 40 |&.@|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 1c 0d 06 |................|
+00000010 d2 25 8a 06 d9 b4 d6 76 89 1c c6 b7 22 9f 44 63 |.%.....v....".Dc|
+00000020 a3 f9 89 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................|
+00000030 cb 34 e8 4b f7 b1 ab 1a 74 60 2c 2d cf a4 7d 9f |.4.K....t`,-..}.|
+00000040 f4 b4 |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ALPN b/src/crypto/tls/testdata/Client-TLSv12-ALPN
new file mode 100644
index 0000000..8b9a510
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ALPN
@@ -0,0 +1,93 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 01 0e 01 00 01 0a 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 8f 00 05 00 05 01 00 00 00 00 00 0a 00 |................|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 10 00 10 00 0e 06 70 72 6f 74 6f |...........proto|
+000000d0 32 06 70 72 6f 74 6f 31 00 12 00 00 00 2b 00 09 |2.proto1.....+..|
+000000e0 08 03 04 03 03 03 02 03 01 00 33 00 26 00 24 00 |..........3.&.$.|
+000000f0 1d 00 20 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f |.. /.}.G.bC.(.._|
+00000100 bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 |.).0.........._X|
+00000110 cb 3b 74 |.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 66 02 00 00 62 03 03 2d b3 e1 a8 44 |....f...b..-...D|
+00000010 c6 3e 20 b9 50 49 ab b8 48 c3 bf d6 f3 7b 2e 0a |.> .PI..H....{..|
+00000020 8c 49 ba e5 8e 54 5e 02 59 01 75 20 f0 a0 60 c2 |.I...T^.Y.u ..`.|
+00000030 81 df 62 f9 f8 7d 3c 3c ee 1e 0c 1d c2 11 58 7f |..b..}<<......X.|
+00000040 e0 dc b1 6c 17 9e 19 60 ca c2 40 84 cc a8 00 00 |...l...`..@.....|
+00000050 1a ff 01 00 01 00 00 0b 00 04 03 00 01 02 00 10 |................|
+00000060 00 09 00 07 06 70 72 6f 74 6f 31 16 03 03 02 59 |.....proto1....Y|
+00000070 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 |...U..R..O0..K0.|
+00000080 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b |.............?.[|
+00000090 ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 |..0...*.H.......|
+000000a0 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |.0.1.0...U....Go|
+000000b0 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f |1.0...U....Go Ro|
+000000c0 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 |ot0...1601010000|
+000000d0 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 |00Z..25010100000|
+000000e0 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 |0Z0.1.0...U....G|
+000000f0 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 |o1.0...U....Go0.|
+00000100 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 |.0...*.H........|
+00000110 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e |....0.......F}..|
+00000120 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e |.'.H..(!.~...]..|
+00000130 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be |RE.z6G....B[....|
+00000140 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 |.y.@.Om..+.....g|
+00000150 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 |....."8.J.ts+.4.|
+00000160 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 |.....t{.X.la<..A|
+00000170 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 |..++$#w[.;.u]. T|
+00000180 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 |..c...$....P....|
+00000190 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 |C...ub...R......|
+000001a0 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff |...0..0...U.....|
+000001b0 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 |......0...U.%..0|
+000001c0 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 |...+.........+..|
+000001d0 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 |.....0...U......|
+000001e0 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 |.0.0...U........|
+000001f0 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b |..CC>I..m....`0.|
+00000200 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 |..U.#..0...H.IM.|
+00000210 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 |~.1......n{0...U|
+00000220 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e |....0...example.|
+00000230 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d |golang0...*.H...|
+00000240 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 |..........0.@+[P|
+00000250 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 |.a...SX...(.X..8|
+00000260 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 |....1Z..f=C.-...|
+00000270 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 |... d8.$:....}.@|
+00000280 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c | ._...a..v......|
+00000290 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c |\.....l..s..Cw..|
+000002a0 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 |.....@.a.Lr+...F|
+000002b0 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 |..M...>...B...=.|
+000002c0 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c 00 |`.\!.;..........|
+000002d0 00 a8 03 00 1d 20 7b 47 ec ef 4d 39 ec 65 b9 7c |..... {G..M9.e.||
+000002e0 08 da b5 41 0d 62 0b 52 29 24 25 3d 39 21 ed d3 |...A.b.R)$%=9!..|
+000002f0 30 37 0c 15 66 49 08 04 00 80 4b 01 8e 80 78 ed |07..fI....K...x.|
+00000300 d1 44 e5 98 a4 43 9a 73 b7 dc 67 72 83 29 f3 e3 |.D...C.s..gr.)..|
+00000310 5b 72 ee d6 36 12 db bf ab d6 86 fd a8 54 a5 a0 |[r..6........T..|
+00000320 0e 76 ca ea a7 f5 f2 e1 87 94 a7 c5 d8 69 b7 58 |.v...........i.X|
+00000330 d2 f0 10 08 8c 08 ac bd aa 60 f5 45 20 15 77 71 |.........`.E .wq|
+00000340 5a bb 2a 8b 0a 4b a3 08 71 88 82 01 3c bc 54 ba |Z.*..K..q...<.T.|
+00000350 f4 42 7a 08 64 d7 57 5b dc ea 6a 72 e1 7d ca 96 |.Bz.d.W[..jr.}..|
+00000360 d9 89 eb 60 9e d2 a4 f5 cb d5 45 d1 4d 09 4e 18 |...`......E.M.N.|
+00000370 a2 4f 0f 59 97 a1 5f 7f 65 4f 16 03 03 00 04 0e |.O.Y.._.eO......|
+00000380 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 b9 f7 58 6f d3 29 b8 41 35 06 b7 |.... ..Xo.).A5..|
+00000040 55 85 c1 f0 63 fe 4f 5f 87 01 cc 67 0b f1 4c b4 |U...c.O_...g..L.|
+00000050 ca 92 bd c0 6d |....m|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 68 92 93 84 bd |.......... h....|
+00000010 0e de 33 1b db ca 54 b8 a0 2f 53 c5 76 de d2 c5 |..3...T../S.v...|
+00000020 7a 54 bb db 0c 08 86 79 d2 6c 58 |zT.....y.lX|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 79 38 07 9b be 83 44 9a 3e 11 1a |.....y8....D.>..|
+00000010 99 2f f2 4e 33 84 0b c7 8e ed c3 15 03 03 00 12 |./.N3...........|
+00000020 ca bd 7e 59 04 8c e0 52 80 1e 56 1e af c1 5f 61 |..~Y...R..V..._a|
+00000030 6c 6a |lj|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch b/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
new file mode 100644
index 0000000..62e7d11
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ALPN-NoMatch
@@ -0,0 +1,91 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 9c 01 00 00 98 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 28 c0 2f |.............(./|
+00000030 c0 2b c0 30 c0 2c c0 27 c0 13 c0 23 c0 09 c0 14 |.+.0.,.'...#....|
+00000040 c0 0a 00 9c 00 9d 00 3c 00 2f 00 35 c0 12 00 0a |.......<./.5....|
+00000050 00 05 c0 11 c0 07 01 00 00 47 33 74 00 00 00 05 |.........G3t....|
+00000060 00 05 01 00 00 00 00 00 0a 00 08 00 06 00 17 00 |................|
+00000070 18 00 19 00 0b 00 02 01 00 00 0d 00 0e 00 0c 04 |................|
+00000080 01 04 03 05 01 05 03 02 01 02 03 ff 01 00 01 00 |................|
+00000090 00 10 00 09 00 07 06 70 72 6f 74 6f 33 00 12 00 |.......proto3...|
+000000a0 00 |.|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 36 0e 9f 51 42 |....Y...U..6..QB|
+00000010 82 65 fa b5 17 7a 86 d6 40 33 a9 67 d3 3d aa 2f |.e...z..@3.g.=./|
+00000020 89 a0 39 82 af 16 30 8e 64 80 d4 20 23 a6 d0 12 |..9...0.d.. #...|
+00000030 ff 8c fc b4 b5 47 ec 10 fe ba 73 fb 0f ab e8 1c |.....G....s.....|
+00000040 15 c1 fb 11 c1 b2 e1 8a f7 5d 5b ad c0 2f 00 00 |.........][../..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 cd 0c 00 00 c9 03 00 17 41 04 11 b4 a9 10 7e 5c |........A.....~\|
+000002d0 41 5e 39 12 15 a3 ed 5b 3e 5d 68 c8 ad 48 39 ef |A^9....[>]h..H9.|
+000002e0 09 8b b1 a7 bf db 5f 54 49 cd d5 de 4d b3 47 4c |......_TI...M.GL|
+000002f0 18 02 84 7c ec 75 4e d0 3e 8a d1 6c 80 83 98 64 |...|.uN.>..l...d|
+00000300 4a 81 bc 8f 84 c7 e5 b4 2d fa 04 01 00 80 72 ee |J.......-.....r.|
+00000310 41 38 f2 b8 a1 56 81 d8 04 78 75 05 f4 78 5f f2 |A8...V...xu..x_.|
+00000320 2b 5d a2 46 23 9d 48 c8 63 a9 1d de a8 78 6e 99 |+].F#.H.c....xn.|
+00000330 cd 59 6b 19 20 f5 b1 11 e1 f8 1c 5b 40 c3 b8 cd |.Yk. ......[@...|
+00000340 66 a3 98 37 c5 c2 5c b7 d6 cc 61 b4 5e 97 fa dd |f..7..\...a.^...|
+00000350 b7 85 5d b6 34 8c 39 4a 60 5a 03 20 47 7f e3 65 |..].4.9J`Z. G..e|
+00000360 01 18 00 2c c3 eb be d4 aa 58 57 a9 5e 69 fb 3c |...,.....XW.^i.<|
+00000370 fa c6 28 1a 5c f7 00 d5 21 e5 c1 30 db 84 38 c3 |..(.\...!..0..8.|
+00000380 08 aa 08 5f c9 fd a0 b7 8e d0 66 77 bf 13 16 03 |..._......fw....|
+00000390 03 00 04 0e 00 00 00 |.......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
+00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
+00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
+00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
+00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
+00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 4f 7e |.....(........O~|
+00000060 9a 3a cc 74 a4 91 77 01 0b 0e 28 0a c5 bd 55 b7 |.:.t..w...(...U.|
+00000070 9a 4c 40 4e e9 c9 46 d5 5f c5 e1 77 c3 f2 |.L@N..F._..w..|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 62 4b 13 ef 22 |..........(bK.."|
+00000010 f9 a8 8d ec 42 3a 36 80 5d a8 5b e9 60 d1 ba 65 |....B:6.].[.`..e|
+00000020 2b d8 37 64 e5 12 b2 ef 84 75 87 0c 0f 3d 35 6e |+.7d.....u...=5n|
+00000030 59 7c 51 |Y|Q|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 5f cd 4d |............._.M|
+00000010 7b a7 c0 f9 6c 1f 80 93 cf 55 3b 12 c7 21 12 86 |{...l....U;..!..|
+00000020 f6 b1 52 15 03 03 00 1a 00 00 00 00 00 00 00 02 |..R.............|
+00000030 fd 31 a4 4b d1 e9 f0 e0 18 b5 96 28 f7 b4 0c 29 |.1.K.......(...)|
+00000040 8c 0c |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
new file mode 100644
index 0000000..4b5a4ca
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-ECDSA
@@ -0,0 +1,139 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 8f fe 05 df f3 |....Y...U.......|
+00000010 02 70 ec 72 c4 3d 1e 52 c3 63 b8 1d dc e0 36 72 |.p.r.=.R.c....6r|
+00000020 8b 04 94 a5 45 fb 97 a5 0b e1 a7 20 9d fb e5 2b |....E...... ...+|
+00000030 77 d7 1b da e8 d7 3e fe c5 8f 4e b6 5a 40 29 02 |w.....>...N.Z@).|
+00000040 fd 08 46 4e 27 24 53 e1 de 88 8a 77 c0 09 00 00 |..FN'$S....w....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 03 00 b7 0c 00 00 b3 03 00 1d 20 82 a8 |*............ ..|
+00000280 4b 0e 10 e1 2b a2 f6 9d 11 0a 4d 0b c0 2f 12 85 |K...+.....M../..|
+00000290 bc f3 e9 9f b4 50 50 fa b1 a9 fd 35 d1 39 04 03 |.....PP....5.9..|
+000002a0 00 8b 30 81 88 02 42 01 b1 cb c7 7a 83 6a 95 5b |..0...B....z.j.[|
+000002b0 09 4c 59 d6 9a 6b 9d 0c e9 f5 22 1c 46 76 5b 4e |.LY..k....".Fv[N|
+000002c0 3c 4a ac 81 b7 96 29 7c e2 e8 08 e7 5f be 9d dc |<J....)|...._...|
+000002d0 8d 9e 1d a1 84 4c 18 1a 8a 2d bd 97 de 26 70 14 |.....L...-...&p.|
+000002e0 11 74 49 4b e9 2e 59 30 9c 02 42 00 b5 9e 89 32 |.tIK..Y0..B....2|
+000002f0 45 02 71 19 6e 83 fc 26 26 b4 28 08 6a 7d d3 72 |E.q.n..&&.(.j}.r|
+00000300 4e ed 82 68 2f ad ff 39 5a ce 34 b8 e4 39 f2 f1 |N..h/..9Z.4..9..|
+00000310 60 5d 84 c4 da 4d 5a 33 f8 20 5a f2 7f aa 7e 18 |`]...MZ3. Z...~.|
+00000320 14 14 2a 68 a8 9d dd d0 ec e3 00 87 49 16 03 03 |..*h........I...|
+00000330 00 3a 0d 00 00 36 03 01 02 40 00 2e 04 03 05 03 |.:...6...@......|
+00000340 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 |................|
+00000350 08 06 04 01 05 01 06 01 03 03 02 03 03 01 02 01 |................|
+00000360 03 02 02 02 04 02 05 02 06 02 00 00 16 03 03 00 |................|
+00000370 04 0e 00 00 00 |.....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
+00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
+00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1|
+00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.|
+00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat|
+00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte|
+00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty|
+00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413|
+00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132|
+00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...|
+000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS|
+000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm|
+000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo|
+000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.|
+000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....|
+000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.|
+00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N|
+00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..|
+00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.|
+00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J|
+00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A|
+00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......|
+00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN|
+00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..|
+00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.|
+00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?|
+000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH|
+000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........|
+000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...|
+000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._|
+000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
+000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
+00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
+00000210 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b|
+00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......|
+00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 93 0f 00 |...._X.;t.......|
+00000240 00 8f 04 03 00 8b 30 81 88 02 42 01 cd 6b 44 a0 |......0...B..kD.|
+00000250 80 3b f5 5d f0 99 24 dd 89 94 b9 96 34 e7 04 e7 |.;.]..$.....4...|
+00000260 38 72 64 36 5a e9 ac bc e3 54 1b 75 69 e2 de 03 |8rd6Z....T.ui...|
+00000270 ce a9 2c 76 92 dd 6b 31 0a 93 10 57 69 8b e0 cf |..,v..k1...Wi...|
+00000280 7d 75 e4 e1 a9 d2 d3 29 b6 a7 ff 86 d4 02 42 01 |}u.....)......B.|
+00000290 e4 d9 31 56 23 62 e6 c2 2d 57 8a 6f d3 3f 1f 4d |..1V#b..-W.o.?.M|
+000002a0 ca 0e c0 60 53 55 1f fb 56 24 22 82 c0 fe d9 0b |...`SU..V$".....|
+000002b0 9b de fb f2 d4 a6 e4 98 9f 2c 07 07 01 83 ab 93 |.........,......|
+000002c0 3e c6 02 41 e9 8b 8d 95 eb cf b9 0f b5 fb 2c 9f |>..A..........,.|
+000002d0 90 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 |...........@....|
+000002e0 00 00 00 00 00 00 00 00 00 00 00 00 aa 12 12 09 |................|
+000002f0 c5 08 94 28 8d 59 f3 68 cc 02 69 47 fa cf 9c 81 |...(.Y.h..iG....|
+00000300 a6 a5 b5 c7 e7 26 45 4a 59 67 ca 0a ed 6c 58 38 |.....&EJYg...lX8|
+00000310 23 12 48 a9 3c 0c 26 00 78 58 db 21 |#.H.<.&.xX.!|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 5a 63 b1 0f 47 |..........@Zc..G|
+00000010 76 ac c4 69 62 82 63 77 8b 26 7b a9 8a 7d 3d fe |v..ib.cw.&{..}=.|
+00000020 4a 04 b4 80 17 cc be 5e 9e b2 5d a3 2d 48 85 44 |J......^..].-H.D|
+00000030 7d db 62 77 31 27 18 b1 55 61 b3 64 6c d6 39 f7 |}.bw1'..Ua.dl.9.|
+00000040 f2 fe 7c 73 c8 3f 31 c9 78 83 8c |..|s.?1.x..|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+00000010 00 00 00 00 00 b9 a3 b6 37 76 c9 69 20 8d 97 e3 |........7v.i ...|
+00000020 0d f1 6e d4 6d 79 0b 64 4f a5 0d 30 ff 1c cd 56 |..n.my.dO..0...V|
+00000030 e7 ce 69 a6 48 15 03 03 00 30 00 00 00 00 00 00 |..i.H....0......|
+00000040 00 00 00 00 00 00 00 00 00 00 c6 3c 3b f2 09 05 |...........<;...|
+00000050 2c 4d 07 4f 95 34 29 ec ef 3b b5 31 c6 a4 91 5e |,M.O.4)..;.1...^|
+00000060 14 20 5b c5 34 19 f9 1d 22 63 |. [.4..."c|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
new file mode 100644
index 0000000..36bddc2
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-ECDSA-RSA
@@ -0,0 +1,139 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 b8 f6 b1 71 c5 |....Y...U.....q.|
+00000010 d0 3f 36 fb 8a b9 15 35 ae c5 08 8e eb c6 d5 ad |.?6....5........|
+00000020 a1 8a ff 65 2e 78 f5 2a 2b cb f7 20 26 1e c1 94 |...e.x.*+.. &...|
+00000030 85 a9 b1 ca 8d 5f 3f 00 6a 44 c9 ed 28 36 97 f2 |....._?.jD..(6..|
+00000040 7d 38 0a 56 75 a2 12 ac 34 ed 7e 14 c0 2f 00 00 |}8.Vu...4.~../..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 9d 82 84 ba 8e 4b 7e |........ .....K~|
+000002d0 bc f4 8e ab c1 31 68 42 cb 36 1d 64 60 55 74 11 |.....1hB.6.d`Ut.|
+000002e0 cf 63 d2 f4 c9 e7 a9 bf 7b 08 04 00 80 ce b2 06 |.c......{.......|
+000002f0 a3 54 1e fd f7 c4 a6 54 40 ea 74 8c e0 de ec aa |.T.....T@.t.....|
+00000300 30 66 c3 e4 a9 7f 86 cc f7 34 6b 55 a4 97 fd 6e |0f.......4kU...n|
+00000310 3b 1f c4 e9 17 3c 6d 94 66 78 e0 1a ab 41 64 9b |;....<m.fx...Ad.|
+00000320 2b 2e 14 99 96 68 aa ef 97 65 ea e7 72 28 9c 0f |+....h...e..r(..|
+00000330 f9 11 57 b7 1f 31 54 87 1a 36 45 ec c1 0f 72 53 |..W..1T..6E...rS|
+00000340 56 a1 8d e4 d0 93 3e bb 77 8a 32 bd fb 07 0b ce |V.....>.w.2.....|
+00000350 82 d3 a1 ab 6f 80 ac ac 4e da b7 7f 84 fe 3f 26 |....o...N.....?&|
+00000360 f4 d9 b9 b6 2b 68 1a cc ef 31 97 22 bf 16 03 03 |....+h...1."....|
+00000370 00 3a 0d 00 00 36 03 01 02 40 00 2e 04 03 05 03 |.:...6...@......|
+00000380 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 |................|
+00000390 08 06 04 01 05 01 06 01 03 03 02 03 03 01 02 01 |................|
+000003a0 03 02 02 02 04 02 05 02 06 02 00 00 16 03 03 00 |................|
+000003b0 04 0e 00 00 00 |.....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
+00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
+00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1|
+00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.|
+00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat|
+00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte|
+00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty|
+00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413|
+00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132|
+00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...|
+000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS|
+000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm|
+000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo|
+000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.|
+000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....|
+000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.|
+00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N|
+00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..|
+00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.|
+00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J|
+00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A|
+00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......|
+00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN|
+00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..|
+00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.|
+00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?|
+000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH|
+000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........|
+000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...|
+000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._|
+000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
+000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
+00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
+00000210 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd 62 |...%...! /.}.G.b|
+00000220 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......|
+00000230 c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 93 0f 00 |...._X.;t.......|
+00000240 00 8f 04 03 00 8b 30 81 88 02 42 01 d0 ef 2f 75 |......0...B.../u|
+00000250 25 6e 4b 2a 16 21 c4 73 59 80 a8 c9 27 45 1b 06 |%nK*.!.sY...'E..|
+00000260 75 20 61 01 db aa c4 90 25 16 1b fb ec 92 54 f7 |u a.....%.....T.|
+00000270 16 9b 8c e0 34 48 3e 62 57 92 99 42 7f d1 35 09 |....4H>bW..B..5.|
+00000280 e1 55 4c 32 cc ed 9d 3e 18 25 1d 31 b8 02 42 01 |.UL2...>.%.1..B.|
+00000290 dd d8 20 b1 12 a2 7d 3b 6b 40 f3 db 59 2b 33 db |.. ...};k@..Y+3.|
+000002a0 5f 85 4d b4 5f 6f 23 ae d2 a2 74 2b 22 94 60 51 |_.M._o#...t+".`Q|
+000002b0 75 aa 66 88 2f 5a db f5 91 b2 7c f4 c4 e9 25 fa |u.f./Z....|...%.|
+000002c0 f7 74 20 00 c3 08 22 8e 88 28 1c 72 4b 36 cd 03 |.t ..."..(.rK6..|
+000002d0 46 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 |F..........(....|
+000002e0 00 00 00 00 2c 30 d5 ee d2 79 8c 68 62 7a c7 36 |....,0...y.hbz.6|
+000002f0 ce c9 39 25 4b 6d 3e 59 7d 42 21 72 65 00 41 45 |..9%Km>Y}B!re.AE|
+00000300 ba 47 88 64 |.G.d|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 9c e9 30 06 da |..........(..0..|
+00000010 ef 89 4a 77 db 17 d4 51 79 36 c1 97 45 8a b0 c9 |..Jw...Qy6..E...|
+00000020 b7 d4 69 8d fc f2 5e 1a c8 e3 43 6c 7a b4 0a 40 |..i...^...Clz..@|
+00000030 ec 35 c9 |.5.|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 f2 3b 7e |..............;~|
+00000010 59 d0 c1 2f 93 f8 8a 48 8d e6 f4 54 70 63 4a 2d |Y../...H...TpcJ-|
+00000020 90 5d 9b 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.]..............|
+00000030 42 1f 5c b2 d3 14 4d 6e 30 85 59 89 5a 34 80 00 |B.\...Mn0.Y.Z4..|
+00000040 fe ab |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-Ed25519 b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-Ed25519
new file mode 100644
index 0000000..9ecd8e3
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-Ed25519
@@ -0,0 +1,119 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 5c 37 b1 d2 6c |....Y...U..\7..l|
+00000010 bc dd 26 8c 4e f7 04 80 09 3c fd 76 23 d4 52 16 |..&.N....<.v#.R.|
+00000020 df 0e 79 ab f4 cf 8c f3 61 31 c6 20 7d 7a 1d 8f |..y.....a1. }z..|
+00000030 09 3e 2b 25 04 7f 0f 0a a7 0c 03 fd 9c 09 f3 5d |.>+%...........]|
+00000040 96 75 f8 da 5b 6b 1b fb ca d7 ec 7a cc a8 00 00 |.u..[k.....z....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 aa c7 43 e7 1e 3b 2b |........ ..C..;+|
+000002d0 28 c2 68 aa 83 cc 85 63 68 c4 b8 4d fb 18 fa b9 |(.h....ch..M....|
+000002e0 3e 9a f2 7c 04 33 7f 48 6b 08 04 00 80 28 28 c7 |>..|.3.Hk....((.|
+000002f0 84 79 65 11 07 43 7a ce f1 d6 cb 0e fe 6a 24 2c |.ye..Cz......j$,|
+00000300 f3 f0 e5 9c 80 a6 c7 41 c7 51 f2 84 be 6e 58 df |.......A.Q...nX.|
+00000310 f2 d2 d4 d9 62 08 c8 35 75 b9 8e 49 c2 98 b0 9d |....b..5u..I....|
+00000320 32 aa db bf 03 c1 61 83 f7 20 d7 ec 07 27 5e 45 |2.....a.. ...'^E|
+00000330 dc d6 92 4c a1 4f 4e 7c 53 c5 ca 42 48 40 0f 83 |...L.ON|S..BH@..|
+00000340 fc 9d 60 a1 7c 43 d1 f5 f8 3f fe 50 3f d0 03 bc |..`.|C...?.P?...|
+00000350 3e 8b ac 69 8f ae b6 9a c8 d4 98 84 30 f1 79 9b |>..i........0.y.|
+00000360 af 5d 4e 41 2a 7c 46 22 df 46 42 74 f6 16 03 03 |.]NA*|F".FBt....|
+00000370 00 3a 0d 00 00 36 03 01 02 40 00 2e 04 03 05 03 |.:...6...@......|
+00000380 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 |................|
+00000390 08 06 04 01 05 01 06 01 03 03 02 03 03 01 02 01 |................|
+000003a0 03 02 02 02 04 02 05 02 06 02 00 00 16 03 03 00 |................|
+000003b0 04 0e 00 00 00 |.....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 01 3c 0b 00 01 38 00 01 35 00 01 32 30 |....<...8..5..20|
+00000010 82 01 2e 30 81 e1 a0 03 02 01 02 02 10 17 d1 81 |...0............|
+00000020 93 be 2a 8c 21 20 10 25 15 e8 34 23 4f 30 05 06 |..*.! .%..4#O0..|
+00000030 03 2b 65 70 30 12 31 10 30 0e 06 03 55 04 0a 13 |.+ep0.1.0...U...|
+00000040 07 41 63 6d 65 20 43 6f 30 1e 17 0d 31 39 30 35 |.Acme Co0...1905|
+00000050 31 36 32 31 35 34 32 36 5a 17 0d 32 30 30 35 31 |16215426Z..20051|
+00000060 35 32 31 35 34 32 36 5a 30 12 31 10 30 0e 06 03 |5215426Z0.1.0...|
+00000070 55 04 0a 13 07 41 63 6d 65 20 43 6f 30 2a 30 05 |U....Acme Co0*0.|
+00000080 06 03 2b 65 70 03 21 00 0b e0 b5 60 b5 e2 79 30 |..+ep.!....`..y0|
+00000090 3d be e3 1e e0 50 b1 04 c8 6d c7 78 6c 69 2f c5 |=....P...m.xli/.|
+000000a0 14 ad 9a 63 6f 79 12 91 a3 4d 30 4b 30 0e 06 03 |...coy...M0K0...|
+000000b0 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 |U...........0...|
+000000c0 55 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 |U.%..0...+......|
+000000d0 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 |.0...U.......0.0|
+000000e0 16 06 03 55 1d 11 04 0f 30 0d 82 0b 65 78 61 6d |...U....0...exam|
+000000f0 70 6c 65 2e 63 6f 6d 30 05 06 03 2b 65 70 03 41 |ple.com0...+ep.A|
+00000100 00 fc 19 17 2a 94 a5 31 fa 29 c8 2e 7f 5b a0 5d |....*..1.)...[.]|
+00000110 8a 4e 34 40 39 d6 b3 10 dc 19 fe a0 22 71 b3 f5 |.N4@9......."q..|
+00000120 8f a1 58 0d cd f4 f1 85 24 bf e6 3d 14 df df ed |..X.....$..=....|
+00000130 0e e1 17 d8 11 a2 60 d0 8a 37 23 2a c2 46 aa 3a |......`..7#*.F.:|
+00000140 08 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 |.....%...! /.}.G|
+00000150 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af |.bC.(.._.).0....|
+00000160 c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 48 |......_X.;t....H|
+00000170 0f 00 00 44 08 07 00 40 07 e0 a5 14 ca cf 31 d7 |...D...@......1.|
+00000180 99 96 c7 c7 d8 d8 a7 f7 82 e7 c6 c0 12 5d 91 5a |.............].Z|
+00000190 bc eb 4a c0 59 c6 5b 7b 03 df 2a ff 48 ca 55 d8 |..J.Y.[{..*.H.U.|
+000001a0 3e 10 c1 94 2c 03 b2 e7 16 83 4d e5 5a 3d 8a 48 |>...,.....M.Z=.H|
+000001b0 2f e5 c4 59 de 6f 47 05 14 03 03 00 01 01 16 03 |/..Y.oG.........|
+000001c0 03 00 20 ae 35 81 df 88 0e a3 2e 67 3f 33 02 3d |.. .5......g?3.=|
+000001d0 b8 7e 47 db cb be 05 c7 ba 43 dc 5b 52 3b 4b ca |.~G......C.[R;K.|
+000001e0 c0 dc 78 |..x|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 63 23 49 7c 83 |.......... c#I|.|
+00000010 1a 8b cd 48 02 e7 86 4d ab 8b 3c 4f 40 27 a6 48 |...H...M..<O@'.H|
+00000020 95 d5 80 8a 7a e0 56 0b e6 34 70 |....z.V..4p|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 aa b4 5b 75 04 96 c5 4a e3 2a fb |.......[u...J.*.|
+00000010 be 29 32 9e c5 e4 15 bd 38 df 69 15 03 03 00 12 |.)2.....8.i.....|
+00000020 50 4d b6 c0 95 e6 5a db f2 b7 ea 02 cb 3e 01 ea |PM....Z......>..|
+00000030 35 0d |5.|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384 b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384
new file mode 100644
index 0000000..35ec347
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-AES256-GCM-SHA384
@@ -0,0 +1,137 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 16 f7 21 0a 97 |....Y...U....!..|
+00000010 89 11 ec c3 c4 05 41 79 72 60 40 6d ec 78 90 26 |......Ayr`@m.x.&|
+00000020 0c a4 f8 5d d5 27 e9 70 bb 40 21 20 b0 bb 98 5d |...].'.p.@! ...]|
+00000030 a2 27 08 1e 4a fe f9 e1 cf a5 79 d3 eb c6 40 f7 |.'..J.....y...@.|
+00000040 ee 4f 0b fa a1 bb 09 62 07 24 30 b7 c0 30 00 00 |.O.....b.$0..0..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 39 1f 7e 66 c8 20 24 |........ 9.~f. $|
+000002d0 cf 8e 51 f6 bf 2a 01 a9 3b 51 19 f1 9d 32 b6 fa |..Q..*..;Q...2..|
+000002e0 05 3b 90 c9 a3 8b 49 92 2a 08 04 00 80 da 65 ad |.;....I.*.....e.|
+000002f0 fa f9 d5 f6 d7 13 34 d2 ab ac ea 57 37 69 c6 b1 |......4....W7i..|
+00000300 91 ee 89 b7 04 6b 17 fb 80 23 df df ef a1 62 9b |.....k...#....b.|
+00000310 e4 0a 4e ca b0 35 b2 d3 2a cf 4f c1 e3 d9 37 78 |..N..5..*.O...7x|
+00000320 aa c8 59 f8 25 c7 43 51 19 6c c7 50 90 a4 2c 92 |..Y.%.CQ.l.P..,.|
+00000330 01 0e 8d ff f0 88 4b af 1d 03 ee 51 8b 18 e4 ee |......K....Q....|
+00000340 35 48 16 e7 4c 26 1d d8 af 91 b1 75 38 b5 65 42 |5H..L&.....u8.eB|
+00000350 8e 60 c7 f9 25 a7 85 35 72 41 6f f6 c4 61 1d c0 |.`..%..5rAo..a..|
+00000360 c8 cf da ae 31 5e 2e d6 9c ca f1 d6 31 16 03 03 |....1^......1...|
+00000370 00 3a 0d 00 00 36 03 01 02 40 00 2e 04 03 05 03 |.:...6...@......|
+00000380 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 |................|
+00000390 08 06 04 01 05 01 06 01 03 03 02 03 03 01 02 01 |................|
+000003a0 03 02 02 02 04 02 05 02 06 02 00 00 16 03 03 00 |................|
+000003b0 04 0e 00 00 00 |.....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.|
+00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 |......._X.;t....|
+00000230 88 0f 00 00 84 08 04 00 80 56 1c 58 51 d8 51 bc |.........V.XQ.Q.|
+00000240 8e 4b b8 24 64 85 81 d2 26 9b 38 bf 13 19 e7 0a |.K.$d...&.8.....|
+00000250 f7 94 e8 b5 94 bf 6f ae f2 07 1a 46 24 38 7b 8b |......o....F$8{.|
+00000260 2f a6 da 91 1a 5f 7d 3f cf c4 1b 14 9c 44 8e 6a |/...._}?.....D.j|
+00000270 6b c8 c4 60 c6 15 e6 f2 c0 45 e7 46 c4 32 06 b1 |k..`.....E.F.2..|
+00000280 46 5e 25 1d ba f7 d8 81 b0 6b 50 40 81 b1 93 89 |F^%......kP@....|
+00000290 cb 90 ae 10 b1 db 08 99 e6 0e 8f 17 0f 4d a7 a7 |.............M..|
+000002a0 f5 42 8a be ca d6 75 c4 32 44 22 ab df cf 22 f7 |.B....u.2D"...".|
+000002b0 58 d9 9f 52 c2 04 c0 81 59 14 03 03 00 01 01 16 |X..R....Y.......|
+000002c0 03 03 00 28 00 00 00 00 00 00 00 00 eb 5a 97 41 |...(.........Z.A|
+000002d0 1d da 2b 81 da 7a b7 9a f8 5e fe 50 75 e5 a4 6a |..+..z...^.Pu..j|
+000002e0 21 90 b7 3d 4e bc 44 cf 86 8f cd c3 |!..=N.D.....|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 93 a5 d4 a8 16 |..........(.....|
+00000010 4e a2 b2 c3 b9 ce dd 0e 57 49 7c eb 92 e4 e7 e3 |N.......WI|.....|
+00000020 a8 55 3a 56 54 53 92 b8 ce 15 e3 c3 c2 da 52 01 |.U:VTS........R.|
+00000030 6f 35 fd |o5.|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 5b 20 4f |.............[ O|
+00000010 e9 3f 09 28 6e 88 5d 1d 57 90 2c 35 74 37 d1 df |.?.(n.].W.,5t7..|
+00000020 aa 39 9b 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.9..............|
+00000030 bb e3 77 62 e5 c9 78 f4 a5 09 93 b0 20 9a 1b a4 |..wb..x..... ...|
+00000040 48 44 |HD|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
new file mode 100644
index 0000000..110f689
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-ECDSA
@@ -0,0 +1,138 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 68 dc 2e 5e 8e |....Y...U..h..^.|
+00000010 80 38 0e 65 a3 b0 f6 a0 c0 8f 1e 62 ef 1d 5a 54 |.8.e.......b..ZT|
+00000020 82 dc 9c 68 77 88 57 dd f3 9d c2 20 4e 56 dd 44 |...hw.W.... NV.D|
+00000030 a0 46 67 4c 09 2b d5 e6 fe 15 fb b3 8e 19 ef a3 |.FgL.+..........|
+00000040 8e 5c a9 70 00 cf 96 d7 3b 8b c9 64 c0 09 00 00 |.\.p....;..d....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 03 00 b6 0c 00 00 b2 03 00 1d 20 24 d0 |*............ $.|
+00000280 e5 11 4c 95 2c 96 58 62 01 df 20 c8 24 ce 29 a2 |..L.,.Xb.. .$.).|
+00000290 1a 3e 97 e2 df 29 49 e6 3a e8 c2 d3 72 49 04 03 |.>...)I.:...rI..|
+000002a0 00 8a 30 81 87 02 41 71 15 8d 50 f6 69 40 d7 cd |..0...Aq..P.i@..|
+000002b0 da c9 c3 ee 37 c2 5f c3 89 62 23 e0 ef 37 f9 9e |....7._..b#..7..|
+000002c0 2a 26 85 10 56 28 08 de 49 3b fa 03 f3 14 4b 3a |*&..V(..I;....K:|
+000002d0 b2 3d de 84 d2 08 8d 4e 59 3e 80 8f 6a 44 af 6f |.=.....NY>..jD.o|
+000002e0 be ee 08 ae 35 40 42 bc 02 42 00 f3 e9 89 a5 7f |....5@B..B......|
+000002f0 9c 50 7c 07 34 e4 cf f0 2b 0f cf f7 68 57 fa fd |.P|.4...+...hW..|
+00000300 2f 52 04 f8 90 7b 97 eb c3 e0 cc 68 f7 bf 22 21 |/R...{.....h.."!|
+00000310 62 b3 51 c8 a4 30 38 c5 88 46 df 55 21 21 d0 4f |b.Q..08..F.U!!.O|
+00000320 6f 95 7b 5f 5a c6 98 dd 2d d1 0a 95 16 03 03 00 |o.{_Z...-.......|
+00000330 3a 0d 00 00 36 03 01 02 40 00 2e 04 03 05 03 06 |:...6...@.......|
+00000340 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 08 |................|
+00000350 06 04 01 05 01 06 01 03 03 02 03 03 01 02 01 03 |................|
+00000360 02 02 02 04 02 05 02 06 02 00 00 16 03 03 00 04 |................|
+00000370 0e 00 00 00 |....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.|
+00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 |......._X.;t....|
+00000230 88 0f 00 00 84 08 04 00 80 84 38 78 4d dd 9f 84 |..........8xM...|
+00000240 ae cb b8 2f e9 f3 76 66 41 56 f6 ed a5 fb 8b f2 |.../..vfAV......|
+00000250 43 0f 27 56 9e 7d a8 06 3e 8f ad b0 17 d5 d6 52 |C.'V.}..>......R|
+00000260 f4 88 e5 af 55 5b 55 fc 26 c1 a9 d5 a9 34 2b 50 |....U[U.&....4+P|
+00000270 96 09 db 59 cc f4 e8 cf 84 6f 9d b1 fd 3b a4 66 |...Y.....o...;.f|
+00000280 66 43 74 6d 4f e5 52 2c 22 2d c9 4c 67 3d ff 3d |fCtmO.R,"-.Lg=.=|
+00000290 c2 79 b3 b1 85 56 08 cc 02 7c 53 a7 be 39 04 21 |.y...V...|S..9.!|
+000002a0 fb db fe ff 1b a6 c7 7a e9 4c 11 c3 34 a6 7c 4f |.......z.L..4.|O|
+000002b0 23 61 d9 47 b0 6c ae cb 72 14 03 03 00 01 01 16 |#a.G.l..r.......|
+000002c0 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 00 |...@............|
+000002d0 00 00 00 00 d3 95 4a 65 d9 8e 3d 9c 2b 18 67 aa |......Je..=.+.g.|
+000002e0 e0 d7 a6 dd fb af 42 06 0d 56 cc 3d 12 3e 7e 95 |......B..V.=.>~.|
+000002f0 18 6e 97 d6 cc 84 eb 90 a1 c3 b6 6e 3c 42 d1 2e |.n.........n<B..|
+00000300 7a dc 41 81 |z.A.|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 71 ee 1d 4f 55 |..........@q..OU|
+00000010 b4 47 3d 26 52 5a 00 a5 ce 0e 31 6c 2d 09 95 df |.G=&RZ....1l-...|
+00000020 fb 74 30 89 32 3d 47 29 58 ee 61 70 74 18 8c 01 |.t0.2=G)X.apt...|
+00000030 e3 16 d7 6e 3d a1 30 75 61 b8 99 e4 c5 82 82 d5 |...n=.0ua.......|
+00000040 75 f6 e1 b4 f8 97 77 92 00 64 06 |u.....w..d.|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+00000010 00 00 00 00 00 e2 68 77 75 6a f8 3c 3d 2c 96 52 |......hwuj.<=,.R|
+00000020 2d fc d5 3b d3 17 c0 29 df 99 f1 09 23 13 9f 89 |-..;...)....#...|
+00000030 dd 21 15 23 36 15 03 03 00 30 00 00 00 00 00 00 |.!.#6....0......|
+00000040 00 00 00 00 00 00 00 00 00 00 37 4e ac 91 80 02 |..........7N....|
+00000050 4f 4a 9f b4 3c 0e 24 87 c8 d0 41 24 ce 01 e2 bb |OJ..<.$...A$....|
+00000060 18 af bc ce 09 4b 41 f6 db 08 |.....KA...|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
new file mode 100644
index 0000000..cbc4bcc
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSA
@@ -0,0 +1,137 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 b6 96 f2 bc ed |....Y...U.......|
+00000010 1b 14 73 de 12 10 cc e9 4d f2 c7 8b 46 d8 63 55 |..s.....M...F.cU|
+00000020 8f 04 33 ec 89 b5 70 93 01 1c f2 20 72 82 e1 16 |..3...p.... r...|
+00000030 9c 0e 70 25 84 2c 09 a6 4f 19 c0 ed 44 d6 98 13 |..p%.,..O...D...|
+00000040 97 f6 19 08 d4 b6 d3 ad 82 96 ef db c0 2f 00 00 |............./..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 21 1b d1 91 16 9c c1 |........ !......|
+000002d0 51 52 39 07 6b 6d ab 07 28 f7 d0 ae 02 13 5e 73 |QR9.km..(.....^s|
+000002e0 5b 51 30 96 27 57 56 e5 37 08 04 00 80 6a 13 82 |[Q0.'WV.7....j..|
+000002f0 97 81 ea 32 51 cb cb 8e 3b ee e5 dd 4f 80 20 50 |...2Q...;...O. P|
+00000300 c9 f0 19 9b d5 1b ae 21 f7 e6 24 4e a3 22 ec b9 |.......!..$N."..|
+00000310 25 6e 77 19 12 08 16 8a c7 c1 db 29 e9 be 05 55 |%nw........)...U|
+00000320 09 c1 6e 44 c3 d7 bd 18 80 c8 1f 42 53 3b e6 09 |..nD.......BS;..|
+00000330 00 29 20 c4 94 04 97 6f f7 e6 f4 3b 66 77 2f e5 |.) ....o...;fw/.|
+00000340 de 96 6f c3 67 c5 ce 4b 5e 4b 0e 90 02 fc 32 7f |..o.g..K^K....2.|
+00000350 71 f4 63 76 37 57 75 30 fb 1b f5 99 98 5f c3 b1 |q.cv7Wu0....._..|
+00000360 fb e3 76 ad 8e 2f 7a 72 86 ed 34 18 98 16 03 03 |..v../zr..4.....|
+00000370 00 3a 0d 00 00 36 03 01 02 40 00 2e 04 03 05 03 |.:...6...@......|
+00000380 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 |................|
+00000390 08 06 04 01 05 01 06 01 03 03 02 03 03 01 02 01 |................|
+000003a0 03 02 02 02 04 02 05 02 06 02 00 00 16 03 03 00 |................|
+000003b0 04 0e 00 00 00 |.....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.|
+00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 |......._X.;t....|
+00000230 88 0f 00 00 84 08 04 00 80 90 53 1e fc 7c 63 b0 |..........S..|c.|
+00000240 98 c5 19 40 fb 4f cf c3 53 51 81 68 54 c7 49 38 |...@.O..SQ.hT.I8|
+00000250 0c 41 f0 12 7d a6 e4 8a 4e 77 97 49 5a 07 7d 30 |.A..}...Nw.IZ.}0|
+00000260 fa df 77 2f 51 cf 37 65 07 0b 2c 91 15 43 1d c9 |..w/Q.7e..,..C..|
+00000270 69 46 e2 26 66 72 98 ec 62 1a 22 ae e8 3e 3a 28 |iF.&fr..b."..>:(|
+00000280 17 83 b9 74 57 59 a2 ec 31 95 17 1f c3 ec 9a 01 |...tWY..1.......|
+00000290 f2 d4 07 d5 ee d5 0e f2 f4 75 3b d6 b8 df aa ad |.........u;.....|
+000002a0 0b 87 37 30 43 7e c1 b1 e1 0d 7e 90 3d 87 9d 93 |..70C~....~.=...|
+000002b0 d7 06 57 18 5c 12 c2 32 0d 14 03 03 00 01 01 16 |..W.\..2........|
+000002c0 03 03 00 28 00 00 00 00 00 00 00 00 ff 2a ae f8 |...(.........*..|
+000002d0 c9 1c bd 3f 62 0e 68 42 e7 96 ec ee c0 fa 71 34 |...?b.hB......q4|
+000002e0 f1 e2 67 76 82 cf c3 2a fb b2 5a c1 |..gv...*..Z.|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 da 70 e7 aa 1b |..........(.p...|
+00000010 6c 66 cb 9b 07 d9 4e 87 6f 87 60 fb 46 f5 e9 33 |lf....N.o.`.F..3|
+00000020 48 59 ff 3e b5 bf 0b 0c b2 39 79 64 f6 3c 2e 95 |HY.>.....9yd.<..|
+00000030 04 51 87 |.Q.|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 21 29 d2 |.............!).|
+00000010 27 05 2d b4 a2 bf ea f2 96 8a 61 c9 91 75 9f 0f |'.-.......a..u..|
+00000020 50 4a 76 15 03 03 00 1a 00 00 00 00 00 00 00 02 |PJv.............|
+00000030 a9 40 eb 86 b2 f0 85 a2 75 bc 4e 09 8c c9 ca 31 |.@......u.N....1|
+00000040 e5 49 |.I|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSAPKCS1v15 b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSAPKCS1v15
new file mode 100644
index 0000000..b8ecfff
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSAPKCS1v15
@@ -0,0 +1,134 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 ad e1 a7 5e 0b |....Y...U.....^.|
+00000010 b8 bd 9d 05 c2 8e 6c f2 ea 7d a1 c8 32 cc d1 74 |......l..}..2..t|
+00000020 ba 86 75 98 33 27 39 c3 0a 6f 49 20 2b 37 9a 0f |..u.3'9..oI +7..|
+00000030 9b de 1f 1d 5f 2b 45 29 6c 9b 33 c6 bc c1 15 a4 |...._+E)l.3.....|
+00000040 19 9b 70 6c 15 eb 4a 92 92 5f b7 6b c0 2f 00 00 |..pl..J.._.k./..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 ba ad fb 1e 28 95 96 |........ ....(..|
+000002d0 f3 62 9d 97 87 0f fd fc a9 91 a2 4b 8d 69 ec 8f |.b.........K.i..|
+000002e0 7d 49 08 6e fe 7d b3 5b 03 04 01 00 80 86 57 23 |}I.n.}.[......W#|
+000002f0 58 bb 9a 50 d8 bb 99 d9 f5 cc 66 43 38 f0 14 8a |X..P......fC8...|
+00000300 cb 6d 8b c0 83 52 f8 53 75 94 07 e3 12 2c 10 bb |.m...R.Su....,..|
+00000310 f3 9b 74 84 1f 11 f3 06 c3 f4 df db f0 1e 0a cd |..t.............|
+00000320 1b 45 18 44 88 67 79 ca 3e 6e 2b 73 c2 10 84 d8 |.E.D.gy.>n+s....|
+00000330 7b c5 2e 81 7d 53 19 46 09 35 35 8b 66 8a a8 cc |{...}S.F.55.f...|
+00000340 20 ba 20 15 9f d1 27 9c 6b 3c bb 48 79 4a 7e 11 | . ...'.k<.HyJ~.|
+00000350 da e3 26 5b 3a 95 da 4d bd 86 3e 8c 97 55 7c 22 |..&[:..M..>..U|"|
+00000360 a1 d3 88 61 ae e1 3b 51 25 c6 01 7e 10 16 03 03 |...a..;Q%..~....|
+00000370 00 0c 0d 00 00 08 01 01 00 02 04 01 00 00 16 03 |................|
+00000380 03 00 04 0e 00 00 00 |.......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 |.5....%...! /.}.|
+00000210 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000220 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 16 03 03 00 |......._X.;t....|
+00000230 88 0f 00 00 84 04 01 00 80 12 a4 42 13 85 6f 92 |...........B..o.|
+00000240 6d 26 5d 05 3c b7 80 ab a9 e0 74 3d 89 67 79 a0 |m&].<.....t=.gy.|
+00000250 9f e1 a9 20 d8 82 e2 22 99 38 03 fe 32 d9 1f c7 |... ...".8..2...|
+00000260 39 1e 27 31 59 05 eb aa bc 2c 10 eb f0 82 65 65 |9.'1Y....,....ee|
+00000270 ce b2 e9 83 67 21 43 03 19 2d 14 9f c3 db bc dc |....g!C..-......|
+00000280 59 66 95 d7 4e 09 3c f0 f2 4a 39 f7 db c4 0c 4e |Yf..N.<..J9....N|
+00000290 73 e2 d6 59 f1 bc 06 d8 75 df 32 b7 f1 b4 01 98 |s..Y....u.2.....|
+000002a0 4f 93 43 a3 a6 09 da cd 1c ee 26 65 ab d1 2a 56 |O.C.......&e..*V|
+000002b0 74 32 24 46 27 f3 d9 6a df 14 03 03 00 01 01 16 |t2$F'..j........|
+000002c0 03 03 00 28 00 00 00 00 00 00 00 00 68 27 5e 44 |...(........h'^D|
+000002d0 d7 73 26 f6 51 86 01 f5 f3 5d 61 a0 05 cd c3 00 |.s&.Q....]a.....|
+000002e0 85 6f ea 56 85 1e 7a c3 4c d3 6d 64 |.o.V..z.L.md|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 81 f3 33 d8 2a |..........(..3.*|
+00000010 57 45 53 2c ee 68 8b 79 ed 07 dc 90 c3 a7 84 38 |WES,.h.y.......8|
+00000020 8c 33 03 e9 c6 51 04 b2 73 8a 8b 81 12 eb 6c 5f |.3...Q..s.....l_|
+00000030 a3 8f 5e |..^|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 e5 c6 d7 |................|
+00000010 4d e0 d1 0c ff a0 66 c4 71 53 af 7e 16 01 3d 2e |M.....f.qS.~..=.|
+00000020 6c ab 90 15 03 03 00 1a 00 00 00 00 00 00 00 02 |l...............|
+00000030 92 12 87 24 c8 7e 74 23 df f7 23 49 01 9a dd 3b |...$.~t#..#I...;|
+00000040 2c 68 |,h|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSAPSS b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSAPSS
new file mode 100644
index 0000000..de05fec
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ClientCert-RSA-RSAPSS
@@ -0,0 +1,142 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 61 fe 1e 35 33 |....Y...U..a..53|
+00000010 4b b4 dd 9b 0f 55 58 f4 0c c5 b2 73 51 7b 84 e7 |K....UX....sQ{..|
+00000020 25 f7 8f 12 5a 12 11 e1 7b e6 52 20 ad 86 a9 f9 |%...Z...{.R ....|
+00000030 7f 6a 30 da 79 23 c3 c4 dc 88 f6 19 1d cc 16 8b |.j0.y#..........|
+00000040 96 74 84 ce 53 56 65 e2 cb 94 61 0c c0 2f 00 00 |.t..SVe...a../..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 66 0b 00 02 62 00 02 5f 00 02 5c 30 82 02 |..f...b.._..\0..|
+00000070 58 30 82 01 8d a0 03 02 01 02 02 11 00 f2 99 26 |X0.............&|
+00000080 eb 87 ea 8a 0d b9 fc c2 47 34 7c 11 b0 30 41 06 |........G4|..0A.|
+00000090 09 2a 86 48 86 f7 0d 01 01 0a 30 34 a0 0f 30 0d |.*.H......04..0.|
+000000a0 06 09 60 86 48 01 65 03 04 02 01 05 00 a1 1c 30 |..`.H.e........0|
+000000b0 1a 06 09 2a 86 48 86 f7 0d 01 01 08 30 0d 06 09 |...*.H......0...|
+000000c0 60 86 48 01 65 03 04 02 01 05 00 a2 03 02 01 20 |`.H.e.......... |
+000000d0 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 6d |0.1.0...U....Acm|
+000000e0 65 20 43 6f 30 1e 17 0d 31 37 31 31 32 33 31 36 |e Co0...17112316|
+000000f0 31 36 31 30 5a 17 0d 31 38 31 31 32 33 31 36 31 |1610Z..181123161|
+00000100 36 31 30 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 |610Z0.1.0...U...|
+00000110 07 41 63 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a |.Acme Co0..0...*|
+00000120 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 |.H............0.|
+00000130 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc 06 |......F}...'.H..|
+00000140 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 47 |(!.~...]..RE.z6G|
+00000150 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb 4f |....B[.....y.@.O|
+00000160 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 22 |m..+.....g....."|
+00000170 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 74 |8.J.ts+.4......t|
+00000180 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 23 |{.X.la<..A..++$#|
+00000190 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d 1e |w[.;.u]. T..c...|
+000001a0 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 62 |$....P....C...ub|
+000001b0 f4 14 c8 52 d7 02 03 01 00 01 a3 46 30 44 30 0e |...R.......F0D0.|
+000001c0 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 |..U...........0.|
+000001d0 06 03 55 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 |..U.%..0...+....|
+000001e0 07 03 01 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 |...0...U.......0|
+000001f0 00 30 0f 06 03 55 1d 11 04 08 30 06 87 04 7f 00 |.0...U....0.....|
+00000200 00 01 30 41 06 09 2a 86 48 86 f7 0d 01 01 0a 30 |..0A..*.H......0|
+00000210 34 a0 0f 30 0d 06 09 60 86 48 01 65 03 04 02 01 |4..0...`.H.e....|
+00000220 05 00 a1 1c 30 1a 06 09 2a 86 48 86 f7 0d 01 01 |....0...*.H.....|
+00000230 08 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 |.0...`.H.e......|
+00000240 a2 03 02 01 20 03 81 81 00 cd ac 4e f2 ce 5f 8d |.... ......N.._.|
+00000250 79 88 10 42 70 7f 7c bf 1b 5a 8a 00 ef 19 15 4b |y..Bp.|..Z.....K|
+00000260 40 15 17 71 00 6c d4 16 26 e5 49 6d 56 da 0c 1a |@..q.l..&.ImV...|
+00000270 13 9f d8 46 95 59 3c b6 7f 87 76 5e 18 aa 03 ea |...F.Y<...v^....|
+00000280 06 75 22 dd 78 d2 a5 89 b8 c9 23 64 e1 28 38 ce |.u".x.....#d.(8.|
+00000290 34 6c 6e 06 7b 51 f1 a7 e6 f4 b3 7f fa b1 3f 14 |4ln.{Q........?.|
+000002a0 11 89 66 79 d1 8e 88 0e 0b a0 9e 30 2a c0 67 ef |..fy.......0*.g.|
+000002b0 ca 46 02 88 e9 53 81 22 69 22 97 ad 80 93 d4 f7 |.F...S."i"......|
+000002c0 dd 70 14 24 d7 70 0a 46 a1 16 03 03 00 ac 0c 00 |.p.$.p.F........|
+000002d0 00 a8 03 00 1d 20 e0 90 02 58 37 69 79 d6 78 e5 |..... ...X7iy.x.|
+000002e0 1d c6 7e a0 c6 38 1b ff 47 72 d6 c2 52 cb 6c 52 |..~..8..Gr..R.lR|
+000002f0 36 7e 03 c3 35 1d 08 04 00 80 79 5f 23 fd b1 ee |6~..5.....y_#...|
+00000300 ac 62 c8 72 09 52 1f 9a 0f ac 95 3e 4e e4 97 d2 |.b.r.R.....>N...|
+00000310 a3 04 ae 19 3f 25 ad 3e b7 78 1f d9 79 5f c8 26 |....?%.>.x..y_.&|
+00000320 f0 26 e5 ee 54 46 4a 05 84 15 01 4f 7a 7e 60 bd |.&..TFJ....Oz~`.|
+00000330 86 74 78 d7 7c 86 91 2b 4f 76 b6 aa 78 27 c8 21 |.tx.|..+Ov..x'.!|
+00000340 7e df 88 2f 26 f0 9d 3c a2 e8 95 f6 9f 5a a4 5e |~../&..<.....Z.^|
+00000350 18 dc cd 0d 70 e8 85 b7 e5 57 f6 c2 f4 33 28 1c |....p....W...3(.|
+00000360 58 7b 94 b0 9e ee d8 b3 42 b5 f3 63 78 a1 30 f3 |X{......B..cx.0.|
+00000370 f7 e4 5e 72 64 6f 80 32 70 4e 16 03 03 00 0c 0d |..^rdo.2pN......|
+00000380 00 00 08 01 01 00 02 08 04 00 00 16 03 03 00 04 |................|
+00000390 0e 00 00 00 |....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 02 66 0b 00 02 62 00 02 5f 00 02 5c 30 |....f...b.._..\0|
+00000010 82 02 58 30 82 01 8d a0 03 02 01 02 02 11 00 f2 |..X0............|
+00000020 99 26 eb 87 ea 8a 0d b9 fc c2 47 34 7c 11 b0 30 |.&........G4|..0|
+00000030 41 06 09 2a 86 48 86 f7 0d 01 01 0a 30 34 a0 0f |A..*.H......04..|
+00000040 30 0d 06 09 60 86 48 01 65 03 04 02 01 05 00 a1 |0...`.H.e.......|
+00000050 1c 30 1a 06 09 2a 86 48 86 f7 0d 01 01 08 30 0d |.0...*.H......0.|
+00000060 06 09 60 86 48 01 65 03 04 02 01 05 00 a2 03 02 |..`.H.e.........|
+00000070 01 20 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 |. 0.1.0...U....A|
+00000080 63 6d 65 20 43 6f 30 1e 17 0d 31 37 31 31 32 33 |cme Co0...171123|
+00000090 31 36 31 36 31 30 5a 17 0d 31 38 31 31 32 33 31 |161610Z..1811231|
+000000a0 36 31 36 31 30 5a 30 12 31 10 30 0e 06 03 55 04 |61610Z0.1.0...U.|
+000000b0 0a 13 07 41 63 6d 65 20 43 6f 30 81 9f 30 0d 06 |...Acme Co0..0..|
+000000c0 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 |.*.H............|
+000000d0 30 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 |0.......F}...'.H|
+000000e0 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a |..(!.~...]..RE.z|
+000000f0 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 |6G....B[.....y.@|
+00000100 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e |.Om..+.....g....|
+00000110 d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 |."8.J.ts+.4.....|
+00000120 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b |.t{.X.la<..A..++|
+00000130 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 |$#w[.;.u]. T..c.|
+00000140 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 |..$....P....C...|
+00000150 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 46 30 44 |ub...R.......F0D|
+00000160 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 a0 |0...U...........|
+00000170 30 13 06 03 55 1d 25 04 0c 30 0a 06 08 2b 06 01 |0...U.%..0...+..|
+00000180 05 05 07 03 01 30 0c 06 03 55 1d 13 01 01 ff 04 |.....0...U......|
+00000190 02 30 00 30 0f 06 03 55 1d 11 04 08 30 06 87 04 |.0.0...U....0...|
+000001a0 7f 00 00 01 30 41 06 09 2a 86 48 86 f7 0d 01 01 |....0A..*.H.....|
+000001b0 0a 30 34 a0 0f 30 0d 06 09 60 86 48 01 65 03 04 |.04..0...`.H.e..|
+000001c0 02 01 05 00 a1 1c 30 1a 06 09 2a 86 48 86 f7 0d |......0...*.H...|
+000001d0 01 01 08 30 0d 06 09 60 86 48 01 65 03 04 02 01 |...0...`.H.e....|
+000001e0 05 00 a2 03 02 01 20 03 81 81 00 cd ac 4e f2 ce |...... ......N..|
+000001f0 5f 8d 79 88 10 42 70 7f 7c bf 1b 5a 8a 00 ef 19 |_.y..Bp.|..Z....|
+00000200 15 4b 40 15 17 71 00 6c d4 16 26 e5 49 6d 56 da |.K@..q.l..&.ImV.|
+00000210 0c 1a 13 9f d8 46 95 59 3c b6 7f 87 76 5e 18 aa |.....F.Y<...v^..|
+00000220 03 ea 06 75 22 dd 78 d2 a5 89 b8 c9 23 64 e1 28 |...u".x.....#d.(|
+00000230 38 ce 34 6c 6e 06 7b 51 f1 a7 e6 f4 b3 7f fa b1 |8.4ln.{Q........|
+00000240 3f 14 11 89 66 79 d1 8e 88 0e 0b a0 9e 30 2a c0 |?...fy.......0*.|
+00000250 67 ef ca 46 02 88 e9 53 81 22 69 22 97 ad 80 93 |g..F...S."i"....|
+00000260 d4 f7 dd 70 14 24 d7 70 0a 46 a1 16 03 03 00 25 |...p.$.p.F.....%|
+00000270 10 00 00 21 20 2f e5 7d a3 47 cd 62 43 15 28 da |...! /.}.G.bC.(.|
+00000280 ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 |._.).0..........|
+00000290 5f 58 cb 3b 74 16 03 03 00 88 0f 00 00 84 08 04 |_X.;t...........|
+000002a0 00 80 b2 c4 60 82 75 ca be 40 dc 28 ec 6d 14 6f |....`.u..@.(.m.o|
+000002b0 6c 88 ca 9a d7 ae ce 94 26 a7 10 ad d8 c3 b9 a6 |l.......&.......|
+000002c0 48 4e 01 7d ee 6e f8 e0 15 d9 72 c4 79 8d ac 25 |HN.}.n....r.y..%|
+000002d0 37 29 83 fc e6 f1 2e 4f 76 49 6a 36 b9 1e b4 58 |7).....OvIj6...X|
+000002e0 a2 3e f7 ff 96 5e d9 17 f2 40 05 1f ec bb 5b f5 |.>...^...@....[.|
+000002f0 28 86 d2 fc 0e 7e 70 3a 3d 90 4c 46 a5 3e bc 57 |(....~p:=.LF.>.W|
+00000300 24 4c ee 35 23 99 6f 21 12 db ba d8 3a 5f 37 1f |$L.5#.o!....:_7.|
+00000310 da 3d c2 c9 bf b6 11 8b b9 b9 43 0b 52 ff 6d 2a |.=........C.R.m*|
+00000320 74 a7 14 03 03 00 01 01 16 03 03 00 28 00 00 00 |t...........(...|
+00000330 00 00 00 00 00 34 bd 90 a0 3f 1c 0c 11 5c 8a e4 |.....4...?...\..|
+00000340 28 82 c4 57 59 73 fd a4 dc a9 91 4b df 2a c6 b5 |(..WYs.....K.*..|
+00000350 f0 6e cf 41 70 |.n.Ap|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 e2 44 81 59 e4 |..........(.D.Y.|
+00000010 6c cf e2 e7 04 78 61 02 36 29 2c 5c c4 6f 13 0b |l....xa.6),\.o..|
+00000020 29 ba 74 b0 13 e8 8f 67 39 b5 ea d1 9d 99 d2 f6 |).t....g9.......|
+00000030 f7 32 be |.2.|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 5c 7b 38 |.............\{8|
+00000010 46 af 57 57 05 5a c5 cb 83 f3 fd 17 d4 c3 2e 93 |F.WW.Z..........|
+00000020 d7 70 52 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.pR.............|
+00000030 df 2b d8 62 ec 97 c6 ab be d4 7f c9 91 f4 fe 55 |.+.b...........U|
+00000040 ac bd |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
new file mode 100644
index 0000000..d21e9b3
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES
@@ -0,0 +1,93 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 ec 4a 6a f8 c5 |....Y...U...Jj..|
+00000010 42 65 f9 d3 4f 65 6f 14 6b bd ae a9 82 5d 06 9b |Be..Oeo.k....]..|
+00000020 9d 03 bb 67 eb ba 52 70 74 c3 01 20 f2 ef 69 54 |...g..Rpt.. ..iT|
+00000030 1f 4b 79 f7 5b d5 08 b4 18 4c af 8e 55 58 45 22 |.Ky.[....L..UXE"|
+00000040 c1 c9 6f cf 36 67 45 20 c7 c5 3a af c0 09 00 00 |..o.6gE ..:.....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 03 00 b7 0c 00 00 b3 03 00 1d 20 7f e5 |*............ ..|
+00000280 3b 03 9e 6a 77 11 1b 0f bc 4a db 44 7c 3b 81 1c |;..jw....J.D|;..|
+00000290 03 8b 15 a6 f3 16 a0 58 5b 13 c5 1e d2 2c 04 03 |.......X[....,..|
+000002a0 00 8b 30 81 88 02 42 00 cc 7c 76 94 81 89 8f 25 |..0...B..|v....%|
+000002b0 16 e2 a0 0d 80 4f 7a 8f 8c 83 23 53 23 45 9c c1 |.....Oz...#S#E..|
+000002c0 39 e3 0c c2 1b 4d f3 78 cd ea b9 c8 d4 b6 30 bb |9....M.x......0.|
+000002d0 ff d7 ad 6c b2 fd 62 4d 8a 05 19 cf 58 ec 81 17 |...l..bM....X...|
+000002e0 21 7c 71 a1 d7 ad 87 11 8d 02 42 01 a2 9e c8 e4 |!|q.......B.....|
+000002f0 04 7c 75 22 df 14 97 94 8a 1b a1 34 95 95 dd 4c |.|u".......4...L|
+00000300 9f 1a c7 c7 96 db ef 87 82 27 9a 27 3a 3d 75 26 |.........'.':=u&|
+00000310 04 47 66 eb 55 60 9f 93 4e b2 09 14 fa 71 5b 3f |.Gf.U`..N....q[?|
+00000320 33 37 3f 0c f2 5c 4f 1e cc fa b1 6f 70 16 03 03 |37?..\O....op...|
+00000330 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
+00000040 00 00 00 00 00 d6 67 cb d5 7c 95 9b 16 e2 3b 86 |......g..|....;.|
+00000050 22 bd 8c c7 40 36 9b b6 7e 0a 77 78 38 14 37 3c |"...@6..~.wx8.7<|
+00000060 48 42 37 a7 07 31 bb 57 c4 e9 f5 e5 a7 58 71 f8 |HB7..1.W.....Xq.|
+00000070 82 f7 12 97 72 |....r|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 56 45 5c a3 b3 |..........@VE\..|
+00000010 64 43 54 7f b5 90 1a 34 ab 2b 68 25 49 41 bf 78 |dCT....4.+h%IA.x|
+00000020 50 b0 66 35 20 76 e1 d0 5c 8a 82 2e 03 83 cf c6 |P.f5 v..\.......|
+00000030 b7 48 3d 2c c4 cf f5 31 c1 ab 9a 3b 09 3a 75 e3 |.H=,...1...;.:u.|
+00000040 b2 05 fa d9 79 cc 1b 0e 30 44 e1 |....y...0D.|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+00000010 00 00 00 00 00 76 5f 1f ec 55 ec f4 87 06 91 b4 |.....v_..U......|
+00000020 ba 71 4f 7f 9c ce e1 c7 e6 3d 75 05 fd ba 98 c4 |.qO......=u.....|
+00000030 d0 39 24 b8 d4 15 03 03 00 30 00 00 00 00 00 00 |.9$......0......|
+00000040 00 00 00 00 00 00 00 00 00 00 e8 4e 09 a1 5f db |...........N.._.|
+00000050 91 d5 5b e8 6a 86 7a 6c 7d 4a e1 94 8a 7d 99 52 |..[.j.zl}J...}.R|
+00000060 e6 5d d8 35 7c a0 68 8f 09 f9 |.].5|.h...|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
new file mode 100644
index 0000000..02bad39
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES-GCM
@@ -0,0 +1,88 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 d4 97 12 a8 e7 |....Y...U.......|
+00000010 be a9 2d 80 f0 db 01 49 07 04 f4 d1 02 db 3d 4a |..-....I......=J|
+00000020 f0 af 31 38 39 d7 4c 1a d3 74 71 20 0f a3 76 14 |..189.L..tq ..v.|
+00000030 73 ff 25 1b ef 29 b3 5e 0b 8f fe ee a6 19 d3 31 |s.%..).^.......1|
+00000040 5d 2e 71 ab 74 58 e9 d6 c5 9b f4 93 c0 2b 00 00 |].q.tX.......+..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 03 00 b7 0c 00 00 b3 03 00 1d 20 a8 15 |*............ ..|
+00000280 13 40 df f8 dc 39 f0 af 90 53 a8 34 a9 61 68 c8 |.@...9...S.4.ah.|
+00000290 ad be 4f 02 0e d2 83 fd 2e 35 bf 8c 8e 13 04 03 |..O......5......|
+000002a0 00 8b 30 81 88 02 42 00 bc 69 df 5b ec 9f 17 ff |..0...B..i.[....|
+000002b0 e6 e5 24 71 f6 2b a5 88 40 78 12 ef f3 dc 25 a9 |..$q.+..@x....%.|
+000002c0 7c 89 24 0d c7 46 b2 db ae 72 b4 2a 87 87 fe 7e ||.$..F...r.*...~|
+000002d0 22 8f e6 d4 c4 7b 61 14 c3 04 39 98 87 6f 1f 54 |"....{a...9..o.T|
+000002e0 e0 50 16 0b 52 8e d6 1e 0a 02 42 00 b7 40 26 a8 |.P..R.....B..@&.|
+000002f0 11 09 77 ec 36 e5 88 26 6d 83 6f e7 c3 b1 98 c3 |..w.6..&m.o.....|
+00000300 4b 83 92 48 65 31 87 68 ee 49 25 ec 95 59 82 b5 |K..He1.h.I%..Y..|
+00000310 93 92 c8 17 d6 d9 1c 99 60 48 1b 18 50 b4 e7 df |........`H..P...|
+00000320 ed 75 1a f2 08 e8 3d 93 99 27 ef 4d e3 16 03 03 |.u....=..'.M....|
+00000330 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 28 00 00 00 00 00 00 00 00 30 f1 a9 |....(........0..|
+00000040 4a 7e 86 a1 5d b7 db 2f c6 e2 ec 36 41 83 66 75 |J~..]../...6A.fu|
+00000050 a3 6c 7d e7 61 36 ac f7 76 f8 8e d8 81 |.l}.a6..v....|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 2c 78 86 13 dc |..........(,x...|
+00000010 a4 b9 bf ad 50 45 a3 d9 b3 df 33 a2 79 b1 1b 25 |....PE....3.y..%|
+00000020 12 94 97 99 07 6b 52 c4 52 64 ab 89 40 8c 93 4a |.....kR.Rd..@..J|
+00000030 e3 cc d9 |...|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 fa 9e 8b |................|
+00000010 92 8c f5 32 e6 d4 11 46 b4 73 62 56 f6 83 15 6f |...2...F.sbV...o|
+00000020 ce de 2d 15 03 03 00 1a 00 00 00 00 00 00 00 02 |..-.............|
+00000030 93 24 68 83 67 b6 f9 27 b5 26 52 78 5d f3 c9 d2 |.$h.g..'.&Rx]...|
+00000040 26 a0 |&.|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES128-SHA256 b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES128-SHA256
new file mode 100644
index 0000000..4946fe4
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES128-SHA256
@@ -0,0 +1,97 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 d1 af 88 61 b7 |....Y...U.....a.|
+00000010 b3 01 16 1a 44 26 1c a1 4f 2d 8a f6 9c f2 7e 1a |....D&..O-....~.|
+00000020 1f ce cb dd 5b f0 c6 2f 16 5e 4a 20 b3 c7 ae 3f |....[../.^J ...?|
+00000030 de d0 d8 9e 48 3e 87 23 f0 9d 43 10 50 3c 66 8b |....H>.#..C.P<f.|
+00000040 7f d2 9b 4f f5 e4 b3 53 db d6 65 d0 c0 23 00 00 |...O...S..e..#..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 03 00 b6 0c 00 00 b2 03 00 1d 20 dc 43 |*............ .C|
+00000280 15 b7 95 81 41 bf e2 bd 56 82 23 46 05 29 05 95 |....A...V.#F.)..|
+00000290 ae 67 08 38 9f 10 70 25 21 92 b4 a0 82 4e 04 03 |.g.8..p%!....N..|
+000002a0 00 8a 30 81 87 02 41 5d ca d6 a2 fd e3 e2 be 2f |..0...A]......./|
+000002b0 69 b5 7d 5c a3 2b 36 4c 8b 81 05 89 12 e1 30 26 |i.}\.+6L......0&|
+000002c0 fa ae 82 b9 4f 8e ba ac ee 7b 62 d5 60 f8 df a4 |....O....{b.`...|
+000002d0 c1 a1 15 73 f8 fb 0b 47 64 b3 34 4a 44 02 a6 32 |...s...Gd.4JD..2|
+000002e0 bc 0d 7b a5 c1 84 cf 77 02 42 01 f3 e5 7f d1 47 |..{....w.B.....G|
+000002f0 bc be 0a ec cd d6 4f 2c 26 5a 95 d3 0f 9b c3 c6 |......O,&Z......|
+00000300 05 b5 5e d7 f6 ca 64 17 94 aa a5 e6 b1 88 57 21 |..^...d.......W!|
+00000310 f8 da 02 de 32 8c ea 5b 7c 36 c9 93 e1 96 38 93 |....2..[|6....8.|
+00000320 9b f9 e5 44 47 a6 74 fa 0e 5f 8f 22 16 03 03 00 |...DG.t.._."....|
+00000330 04 0e 00 00 00 |.....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 50 00 00 00 00 00 00 00 00 00 00 00 |....P...........|
+00000040 00 00 00 00 00 85 db ae c1 37 85 25 3d ee 5f f5 |.........7.%=._.|
+00000050 12 95 df ee 29 4a f7 3a 80 ca bd c2 b3 d8 f3 8c |....)J.:........|
+00000060 56 62 d2 68 13 1d 73 51 09 93 a3 b9 43 4a 2c 0f |Vb.h..sQ....CJ,.|
+00000070 bf 3c 96 76 08 a9 17 68 e2 9a 3f 39 e7 04 76 f8 |.<.v...h..?9..v.|
+00000080 8f fe e8 f5 ce |.....|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 50 fa 85 cc bc dd |..........P.....|
+00000010 0e 16 86 b1 5c 51 8a b9 cc 78 cd cd 64 5d 23 ca |....\Q...x..d]#.|
+00000020 59 84 b3 42 dd ae a7 98 43 05 21 4f 35 43 75 5c |Y..B....C.!O5Cu\|
+00000030 13 c8 e0 b6 66 0f 55 32 69 7a 8b 8f cd c2 37 38 |....f.U2iz....78|
+00000040 f6 fa 0b 66 cf 46 91 3e 9f f5 43 44 f5 c7 2b e1 |...f.F.>..CD..+.|
+00000050 39 3a f7 3c f2 03 c4 85 dc 58 66 |9:.<.....Xf|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
+00000010 00 00 00 00 00 44 e6 99 40 ae 12 bc d9 92 c5 ae |.....D..@.......|
+00000020 fb 4d 5f 64 7a 77 0f 80 8e a4 be d0 ba ba 41 b1 |.M_dzw........A.|
+00000030 0d 40 e9 0e 50 32 dc 35 2d 5e 5c 8a ef 20 75 80 |.@..P2.5-^\.. u.|
+00000040 a0 e5 9c 61 49 15 03 03 00 40 00 00 00 00 00 00 |...aI....@......|
+00000050 00 00 00 00 00 00 00 00 00 00 57 91 40 2a a5 f7 |..........W.@*..|
+00000060 9f 29 0f 02 8e 50 ac 4b 2e 55 9a 78 72 f0 d7 c5 |.)...P.K.U.xr...|
+00000070 3b f2 cd 28 4d 8b 49 d8 50 a6 22 96 de df 16 d6 |;..(M.I.P.".....|
+00000080 61 4b 23 5c 5d de a1 0a 5b 16 |aK#\]...[.|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384 b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384
new file mode 100644
index 0000000..14af5ae
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-AES256-GCM-SHA384
@@ -0,0 +1,88 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 bb 8a 66 ee 44 |....Y...U....f.D|
+00000010 42 dc 59 c7 a7 7b a8 57 8e 63 21 f0 4e 31 f4 5c |B.Y..{.W.c!.N1.\|
+00000020 1d d3 42 e5 de eb 8c 78 3a 01 01 20 9b 89 05 d6 |..B....x:.. ....|
+00000030 d2 07 38 8b 4c 5f 6d 62 9f 43 a0 cd d3 40 0f 77 |..8.L_mb.C...@.w|
+00000040 17 ff 43 4a 5c b3 8c 83 b7 4b c7 e7 c0 2c 00 00 |..CJ\....K...,..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 03 00 b7 0c 00 00 b3 03 00 1d 20 fd 71 |*............ .q|
+00000280 c1 3a 6a a3 69 6a 34 f3 02 c5 1d e5 db 63 f4 eb |.:j.ij4......c..|
+00000290 97 4c 70 bc b3 4e 9d 2c 2f b2 b9 9d ac 3f 04 03 |.Lp..N.,/....?..|
+000002a0 00 8b 30 81 88 02 42 01 bd 9d ad 24 37 b9 60 55 |..0...B....$7.`U|
+000002b0 e4 cc bc 49 c3 88 3b ed ac e4 42 8e fa 81 01 d9 |...I..;...B.....|
+000002c0 39 4c f0 1c 7d 39 a2 81 8a e1 17 0e 8d 37 76 96 |9L..}9.......7v.|
+000002d0 37 13 3a 1e 2e fd 0d 0a 3c 90 9d 43 3d 06 c0 b1 |7.:.....<..C=...|
+000002e0 4e 07 3e c3 9f f2 43 40 0b 02 42 01 d6 d0 20 ad |N.>...C@..B... .|
+000002f0 48 09 c0 9b 5d c8 84 46 3b 98 37 9b 5a 91 4a 07 |H...]..F;.7.Z.J.|
+00000300 79 68 71 92 76 dc 70 0f 5c 44 7e 81 c3 c6 3f 19 |yhq.v.p.\D~...?.|
+00000310 f4 0f 6a 0b aa cc bb 65 e7 34 b5 e9 67 2d 32 98 |..j....e.4..g-2.|
+00000320 1c f6 76 4c 96 73 df 21 d6 e1 ea 34 86 16 03 03 |..vL.s.!...4....|
+00000330 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 28 00 00 00 00 00 00 00 00 27 fd 98 |....(........'..|
+00000040 47 79 56 f9 e8 0e fd 18 c2 8f 2d 32 51 f7 19 b5 |GyV.......-2Q...|
+00000050 ab 2f 81 ed b6 cf 6f b5 65 81 81 f1 44 |./....o.e...D|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 a9 b7 63 61 57 |..........(..caW|
+00000010 54 57 f0 b2 60 58 e3 dc 6e e1 40 3e 67 b4 99 8f |TW..`X..n.@>g...|
+00000020 e9 6b 11 f1 1a 54 bd c1 d3 b9 5b 01 12 27 a4 0b |.k...T....[..'..|
+00000030 e9 ec 01 |...|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 e0 8a 6e |...............n|
+00000010 62 5d e3 db 99 10 d2 53 b6 21 2e 79 31 cf 71 1d |b].....S.!.y1.q.|
+00000020 34 71 2a 15 03 03 00 1a 00 00 00 00 00 00 00 02 |4q*.............|
+00000030 e7 4a 8d b9 2f 1b b1 70 72 da 7f d8 fa 4f 9f d6 |.J../..pr....O..|
+00000040 ca f3 |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-CHACHA20-POLY1305 b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-CHACHA20-POLY1305
new file mode 100644
index 0000000..3113b3c
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-ECDSA-CHACHA20-POLY1305
@@ -0,0 +1,84 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 d0 01 00 00 cc 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 08 cc a9 |................|
+00000050 13 03 13 01 13 02 01 00 00 7b 00 05 00 05 01 00 |.........{......|
+00000060 00 00 00 00 0a 00 0a 00 08 00 1d 00 17 00 18 00 |................|
+00000070 19 00 0b 00 02 01 00 00 0d 00 1a 00 18 08 04 04 |................|
+00000080 03 08 07 08 05 08 06 04 01 05 01 06 01 05 03 06 |................|
+00000090 03 02 01 02 03 ff 01 00 01 00 00 12 00 00 00 2b |...............+|
+000000a0 00 09 08 03 04 03 03 03 02 03 01 00 33 00 26 00 |............3.&.|
+000000b0 24 00 1d 00 20 2f e5 7d a3 47 cd 62 43 15 28 da |$... /.}.G.bC.(.|
+000000c0 ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 |._.).0..........|
+000000d0 5f 58 cb 3b 74 |_X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 e1 cc 3c 49 04 |....Y...U....<I.|
+00000010 bb 5b 18 c7 44 8f 52 62 d9 74 84 94 fa 61 3f 12 |.[..D.Rb.t...a?.|
+00000020 c8 23 50 0b 8a 5c 81 23 c2 9d 3d 20 1f b2 67 b0 |.#P..\.#..= ..g.|
+00000030 e9 2d a9 ed 35 4e ab b9 73 59 32 2f 49 ed 1e 60 |.-..5N..sY2/I..`|
+00000040 4c 31 11 6e 27 79 e0 62 e0 e4 ca 16 cc a9 00 00 |L1.n'y.b........|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 |.............0..|
+00000070 00 30 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 |.0..b.....-G....|
+00000080 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 |0...*.H.=..0E1.0|
+00000090 09 06 03 55 04 06 13 02 41 55 31 13 30 11 06 03 |...U....AU1.0...|
+000000a0 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 |U....Some-State1|
+000000b0 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e |!0...U....Intern|
+000000c0 65 74 20 57 69 64 67 69 74 73 20 50 74 79 20 4c |et Widgits Pty L|
+000000d0 74 64 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 |td0...1211221506|
+000000e0 33 32 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 |32Z..22112015063|
+000000f0 32 5a 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 |2Z0E1.0...U....A|
+00000100 55 31 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 |U1.0...U....Some|
+00000110 2d 53 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 |-State1!0...U...|
+00000120 18 49 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 |.Internet Widgit|
+00000130 73 20 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 |s Pty Ltd0..0...|
+00000140 2a 86 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 |*.H.=....+...#..|
+00000150 86 00 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 |...........Hs6~.|
+00000160 16 56 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 |.V.".=S.;M!=.ku.|
+00000170 f6 b0 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 |.....&.....r2|.d|
+00000180 2f 1c 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 |/....h#.~..%.H:i|
+00000190 e0 28 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 |.(m.7...b....pb.|
+000001a0 d8 81 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 |...d1...1...h..#|
+000001b0 de 76 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd |.vd?.\....XX._p.|
+000001c0 9b d8 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a |...........0f[f.|
+000001d0 20 e2 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d | .'...;0...*.H.=|
+000001e0 04 01 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb |......0...B...O.|
+000001f0 e2 45 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e |.E.H}.......Gp.^|
+00000200 1b b6 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b |../...M.a@......|
+00000210 7e 92 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 |~.~.v..;~.?....Y|
+00000220 ec 47 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 |.G-|..N....o..B.|
+00000230 4d fc be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 |M..g..-...?..%.3|
+00000240 13 83 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd |.......7z..z....|
+00000250 d7 11 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d |..i..|V..1x+..x.|
+00000260 ae cb be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f |....N6$1{j.9....|
+00000270 2a 16 03 03 00 b6 0c 00 00 b2 03 00 1d 20 cc a1 |*............ ..|
+00000280 4d a4 b1 22 86 e5 91 9b e2 1a 28 c6 66 06 1a 89 |M.."......(.f...|
+00000290 a9 62 23 93 09 54 ae 67 a8 ab 18 ac 67 37 04 03 |.b#..T.g....g7..|
+000002a0 00 8a 30 81 87 02 42 01 f0 46 f3 3f 13 a7 1d 84 |..0...B..F.?....|
+000002b0 73 65 9e 91 16 6c 3d 8f 21 ab 17 db 24 34 21 8c |se...l=.!...$4!.|
+000002c0 a9 e1 9b a6 17 c8 0d 7a b4 8e f0 46 cd c5 b9 b2 |.......z...F....|
+000002d0 5e 64 7f 9f 9d 03 14 7a 23 5d 55 70 ae d1 ff 08 |^d.....z#]Up....|
+000002e0 e8 70 f5 5d 55 90 74 04 0d 02 41 09 ca 7d 60 ea |.p.]U.t...A..}`.|
+000002f0 13 17 42 e8 53 e7 c5 31 15 4a 58 14 d6 54 f5 40 |..B.S..1.JX..T.@|
+00000300 a1 aa fe 4b 13 f5 29 04 05 cc 12 26 e2 b7 e5 a6 |...K..)....&....|
+00000310 90 7c 5e 66 2f ed 41 7c 97 a1 72 87 5e 46 5a 5b |.|^f/.A|..r.^FZ[|
+00000320 1b d1 7b 3c 34 ba 3f 47 7d a9 84 33 16 03 03 00 |..{<4.?G}..3....|
+00000330 04 0e 00 00 00 |.....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 7f ab 78 f0 a6 b6 57 bd c3 b9 32 |.... ..x...W...2|
+00000040 96 3f 7c 9d a0 4d dc 74 c9 e8 1a 88 c4 b2 10 27 |.?|..M.t.......'|
+00000050 e3 9c 1e 9b e1 |.....|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 0c b7 0c 47 8e |.......... ...G.|
+00000010 40 6b 9f 9c d2 cd 24 25 db 12 e8 0c 50 be f3 98 |@k....$%....P...|
+00000020 4a 6f f9 42 58 07 b9 64 d0 00 91 |Jo.BX..d...|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 1d 32 1c ef 0b 1f a4 ba 39 a3 63 |......2......9.c|
+00000010 04 29 e5 67 1e bb 5a 6e c7 3c c1 15 03 03 00 12 |.).g..Zn.<......|
+00000020 0e 0b 0f 49 30 fe d4 c3 35 85 e3 db 6e 65 e3 2d |...I0...5...ne.-|
+00000030 d1 1d |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
new file mode 100644
index 0000000..ea6c787
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES
@@ -0,0 +1,97 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 1e 2f 6f fa 02 |....Y...U.../o..|
+00000010 44 3e 0d d0 3e b5 e6 0c a2 d6 aa 04 5b ba 93 39 |D>..>.......[..9|
+00000020 29 dd e7 7e b8 11 f9 85 97 a5 e4 20 9c 64 e9 47 |)..~....... .d.G|
+00000030 cb 7c 0c 77 9d 83 5a c4 e8 05 62 40 95 8e 8e aa |.|.w..Z...b@....|
+00000040 39 bb 24 8f b7 29 75 77 18 66 60 29 c0 13 00 00 |9.$..)uw.f`)....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 92 ed 81 60 d9 51 c2 |........ ...`.Q.|
+000002d0 00 3d 99 84 82 c5 83 67 60 b3 11 59 0c c5 5d ff |.=.....g`..Y..].|
+000002e0 d6 28 79 68 2d 73 7f 84 40 08 04 00 80 b6 a0 4b |.(yh-s..@......K|
+000002f0 3d fb e1 e6 76 cc ae e3 59 d0 1c 50 5c 09 5d 80 |=...v...Y..P\.].|
+00000300 c2 58 0d 36 d7 1a 78 e3 c2 66 73 3a 14 06 37 6f |.X.6..x..fs:..7o|
+00000310 3a 95 2e 2a eb cc e5 e3 f7 30 eb 0d 33 04 51 6e |:..*.....0..3.Qn|
+00000320 06 86 8f 53 6d fd 97 75 b3 13 2e 4e ee 8f 03 68 |...Sm..u...N...h|
+00000330 23 32 83 96 af 01 ed b0 21 a7 13 06 47 f4 08 b9 |#2......!...G...|
+00000340 8a 47 cc 12 99 20 c6 31 77 28 2c 2e d6 a0 20 8c |.G... .1w(,... .|
+00000350 e6 67 c7 70 23 ed 98 9c c9 47 1c e0 37 95 42 aa |.g.p#....G..7.B.|
+00000360 c2 19 1b 55 09 5c 58 fb ef 67 a9 b5 65 16 03 03 |...U.\X..g..e...|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
+00000040 00 00 00 00 00 dd 81 23 e0 a3 01 33 bb 87 0d 93 |.......#...3....|
+00000050 b2 61 16 01 e3 87 e0 05 cc b0 ec 15 56 df ff 9c |.a..........V...|
+00000060 e6 9c 6a 57 79 8a 0b 86 f9 fb 60 3f ca 0d ef f2 |..jWy.....`?....|
+00000070 81 c0 5e 22 bf |..^".|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 d4 d3 ba 7f 4c |..........@....L|
+00000010 1a ee d9 ca 66 a0 5b d7 08 78 5d 5c fd 17 32 71 |....f.[..x]\..2q|
+00000020 7f 8c 2e eb 80 bc 82 0f 0c ed 71 ac 34 59 71 d1 |..........q.4Yq.|
+00000030 aa d3 fd 0c 50 7d 4b 1b 01 5d 4c 03 9f 6c 16 8f |....P}K..]L..l..|
+00000040 5d f7 8d c0 4b 3f 01 96 23 40 22 |]...K?..#@"|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+00000010 00 00 00 00 00 36 49 0e f6 26 13 f7 69 15 54 27 |.....6I..&..i.T'|
+00000020 5a e6 f2 fb 7d ad e0 30 d3 cd ed 08 24 74 5f 77 |Z...}..0....$t_w|
+00000030 f7 8b 3f bf 94 15 03 03 00 30 00 00 00 00 00 00 |..?......0......|
+00000040 00 00 00 00 00 00 00 00 00 00 28 09 ed 2f d8 6f |..........(../.o|
+00000050 95 fc db 9e ec d8 81 7e a4 d4 8e c5 ec d3 24 bc |.......~......$.|
+00000060 ab 52 e6 01 75 98 b9 e5 9f d9 |.R..u.....|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES128-SHA256 b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES128-SHA256
new file mode 100644
index 0000000..88d0d01
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-AES128-SHA256
@@ -0,0 +1,101 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 e6 04 5e a9 bb |....Y...U....^..|
+00000010 23 56 bd cc e7 72 9f 10 b1 fc 23 48 22 19 cb 27 |#V...r....#H"..'|
+00000020 3e c4 22 ec b9 7a 9c 81 60 c5 55 20 b9 7f 8a 0e |>."..z..`.U ....|
+00000030 6b d6 cf cb 35 85 52 f3 9f 28 00 87 22 88 6d 7c |k...5.R..(..".m||
+00000040 35 0e f6 af 7c 28 b4 71 cc 46 c1 b5 c0 27 00 00 |5...|(.q.F...'..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 55 af 53 a0 54 77 df |........ U.S.Tw.|
+000002d0 ca 8f 49 1a 4d d0 9b 24 a6 a9 2b b2 2a 33 46 b8 |..I.M..$..+.*3F.|
+000002e0 01 d6 4e fd fb c1 e4 e6 64 08 04 00 80 5c da 2f |..N.....d....\./|
+000002f0 01 2b 10 b9 e9 35 f2 b1 2a 28 4f 78 58 7b 3d 9a |.+...5..*(OxX{=.|
+00000300 13 e4 7c 77 41 95 fa 7a 90 1f eb f5 20 55 7c 76 |..|wA..z.... U|v|
+00000310 dd c5 66 08 88 eb ba 17 f0 de f3 0c a5 a6 3c 21 |..f...........<!|
+00000320 52 89 25 b1 4d 86 e3 0b 8a 14 dc 8b a6 76 41 25 |R.%.M........vA%|
+00000330 9e d3 20 b6 61 8a 26 8b 0d b7 cb 98 ac 45 e0 3b |.. .a.&......E.;|
+00000340 6f d6 b2 52 8b a2 31 63 c8 44 1d 2a 3a c1 35 87 |o..R..1c.D.*:.5.|
+00000350 7a 7b 2a fa dd ab d3 48 9b e2 fa e1 93 7c 09 f7 |z{*....H.....|..|
+00000360 e1 72 83 f8 23 07 30 3a 4a 4f 56 97 1b 16 03 03 |.r..#.0:JOV.....|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 50 00 00 00 00 00 00 00 00 00 00 00 |....P...........|
+00000040 00 00 00 00 00 91 c1 82 23 f0 03 79 83 38 ef d0 |........#..y.8..|
+00000050 73 71 9b 7d 55 5e 53 3b d3 cf 86 48 60 2f 42 97 |sq.}U^S;...H`/B.|
+00000060 63 e8 4b 20 4c 92 3e 2f aa b3 32 46 8a 96 69 42 |c.K L.>/..2F..iB|
+00000070 96 9a 4b bd 04 f2 3d b6 5f f9 37 4f a4 3d f1 cb |..K...=._.7O.=..|
+00000080 d5 57 fc 5e 8e |.W.^.|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 50 e1 91 69 dc 7b |..........P..i.{|
+00000010 5f a4 c7 7a 8f ba bb 8d 98 c3 0e 3f 10 f1 3e 3f |_..z.......?..>?|
+00000020 37 6f 11 81 3f c5 7c 22 6f 22 a3 94 ae 3a 77 17 |7o..?.|"o"...:w.|
+00000030 a2 7b cc 8e 5e 6e 9b 4b 98 fd 16 f8 46 9e 78 19 |.{..^n.K....F.x.|
+00000040 43 e6 da e3 05 9a 0a 49 b0 09 c7 e5 4b 41 dc b4 |C......I....KA..|
+00000050 c0 81 9b 46 7e dd c3 64 2e f8 6e |...F~..d..n|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
+00000010 00 00 00 00 00 65 4c 71 31 d4 47 4d 0b 81 1f 75 |.....eLq1.GM...u|
+00000020 b6 71 64 4a e6 a8 80 a1 f1 e2 0a 14 77 af a4 c6 |.qdJ........w...|
+00000030 1d 6a 7d 79 6a 15 a1 0e 86 6c 8e e1 32 64 0b 5d |.j}yj....l..2d.]|
+00000040 af e0 f5 05 91 15 03 03 00 40 00 00 00 00 00 00 |.........@......|
+00000050 00 00 00 00 00 00 00 00 00 00 ca 46 1b 95 2a 41 |...........F..*A|
+00000060 ce dc 30 d6 e0 cf 2f 2b 1f 61 81 33 a4 58 e7 af |..0.../+.a.3.X..|
+00000070 90 9c 15 42 9b ab 26 64 d1 39 46 45 6b 74 b9 c4 |...B..&d.9FEkt..|
+00000080 21 d9 ef 2d 69 51 dc e7 8a 6b |!..-iQ...k|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-CHACHA20-POLY1305 b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-CHACHA20-POLY1305
new file mode 100644
index 0000000..2c2cb45
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ECDHE-RSA-CHACHA20-POLY1305
@@ -0,0 +1,88 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 d0 01 00 00 cc 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 08 cc a8 |................|
+00000050 13 03 13 01 13 02 01 00 00 7b 00 05 00 05 01 00 |.........{......|
+00000060 00 00 00 00 0a 00 0a 00 08 00 1d 00 17 00 18 00 |................|
+00000070 19 00 0b 00 02 01 00 00 0d 00 1a 00 18 08 04 04 |................|
+00000080 03 08 07 08 05 08 06 04 01 05 01 06 01 05 03 06 |................|
+00000090 03 02 01 02 03 ff 01 00 01 00 00 12 00 00 00 2b |...............+|
+000000a0 00 09 08 03 04 03 03 03 02 03 01 00 33 00 26 00 |............3.&.|
+000000b0 24 00 1d 00 20 2f e5 7d a3 47 cd 62 43 15 28 da |$... /.}.G.bC.(.|
+000000c0 ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 |._.).0..........|
+000000d0 5f 58 cb 3b 74 |_X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 2a 76 db 4b d5 |....Y...U..*v.K.|
+00000010 10 f3 21 f2 4b 29 a2 2e 7a 7d 0b 86 c4 af 60 95 |..!.K)..z}....`.|
+00000020 5b 11 84 27 8a 59 7f af a0 27 de 20 02 f7 dc 9b |[..'.Y...'. ....|
+00000030 63 8e 2e da 48 b5 73 81 8e 76 13 da dd 2e 17 2b |c...H.s..v.....+|
+00000040 ff 18 ad d7 9d f3 44 ed b6 60 0e 42 cc a8 00 00 |......D..`.B....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 0d c3 c2 b5 73 da 39 |........ ....s.9|
+000002d0 82 e5 8c 18 0d 8d 16 c2 a5 e7 3e 39 fd 25 00 18 |..........>9.%..|
+000002e0 25 16 c0 a7 6e c6 dd bb 01 08 04 00 80 b3 bd 01 |%...n...........|
+000002f0 ae dd b1 c8 2a 5d 0e 66 6d 1e b3 92 f4 01 63 59 |....*].fm.....cY|
+00000300 0c c1 62 df 75 8f 4f 19 5a cf 2f 63 79 d0 06 31 |..b.u.O.Z./cy..1|
+00000310 c0 60 6a 4f db 70 18 bd 80 8b 30 94 40 dd 13 39 |.`jO.p....0.@..9|
+00000320 4f db 2b 54 a4 97 f7 ef a5 a3 ff f5 14 3d e2 2d |O.+T.........=.-|
+00000330 0c 0e 71 4a bd a8 59 48 ab 06 55 53 45 2a ee 3e |..qJ..YH..USE*.>|
+00000340 65 1f 47 ee 8d e3 f6 4e 2e b1 4c d0 af 50 15 02 |e.G....N..L..P..|
+00000350 5e 84 fe 76 d5 f3 c5 fb 2a 91 44 f0 92 32 ee ea |^..v....*.D..2..|
+00000360 a0 26 77 5c 94 88 24 e3 2f 75 e3 fd b7 16 03 03 |.&w\..$./u......|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 0b 58 fe b5 63 ac 28 f8 34 d6 72 |.... .X..c.(.4.r|
+00000040 1a a3 ec 26 91 70 07 8d 6a 3a 3b 3a 94 5e a3 fa |...&.p..j:;:.^..|
+00000050 6e 92 3a 15 65 |n.:.e|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 01 fa e1 2f 29 |.......... .../)|
+00000010 ee f6 d4 e8 22 b6 e0 8f 82 37 81 83 1b 03 4d 5f |...."....7....M_|
+00000020 00 80 cb eb 9a 3a 01 c7 aa e9 9a |.....:.....|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 43 6a e8 f2 ca f9 4f 3c 6d ff 5e |.....Cj....O<m.^|
+00000010 f3 19 eb ee 96 1c d8 68 c5 53 86 15 03 03 00 12 |.......h.S......|
+00000020 c2 72 4e 3c 33 93 fa f3 21 32 bb fd e3 c4 ef 1a |.rN<3...!2......|
+00000030 46 df |F.|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-Ed25519 b/src/crypto/tls/testdata/Client-TLSv12-Ed25519
new file mode 100644
index 0000000..72d564f
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-Ed25519
@@ -0,0 +1,68 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 6c 5f 04 9e a6 |....Y...U..l_...|
+00000010 c6 41 0c ee a2 2c af 45 f0 bc de 67 2d 20 1c 9c |.A...,.E...g- ..|
+00000020 82 33 fd 86 86 b3 50 04 77 ec da 20 f3 09 fb 8c |.3....P.w.. ....|
+00000030 79 83 f9 82 58 b9 76 bb d3 58 44 3d 52 0c 37 ae |y...X.v..XD=R.7.|
+00000040 18 98 84 9a 56 af 5d 2b 68 68 c7 30 cc a9 00 00 |....V.]+hh.0....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 01 3c 0b 00 01 38 00 01 35 00 01 32 30 82 01 |..<...8..5..20..|
+00000070 2e 30 81 e1 a0 03 02 01 02 02 10 0f 43 1c 42 57 |.0..........C.BW|
+00000080 93 94 1d e9 87 e4 f1 ad 15 00 5d 30 05 06 03 2b |..........]0...+|
+00000090 65 70 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 |ep0.1.0...U....A|
+000000a0 63 6d 65 20 43 6f 30 1e 17 0d 31 39 30 35 31 36 |cme Co0...190516|
+000000b0 32 31 33 38 30 31 5a 17 0d 32 30 30 35 31 35 32 |213801Z..2005152|
+000000c0 31 33 38 30 31 5a 30 12 31 10 30 0e 06 03 55 04 |13801Z0.1.0...U.|
+000000d0 0a 13 07 41 63 6d 65 20 43 6f 30 2a 30 05 06 03 |...Acme Co0*0...|
+000000e0 2b 65 70 03 21 00 3f e2 15 2e e6 e3 ef 3f 4e 85 |+ep.!.?......?N.|
+000000f0 4a 75 77 a3 64 9e ed e0 bf 84 2c cc 92 26 8f fa |Juw.d.....,..&..|
+00000100 6f 34 83 aa ec 8f a3 4d 30 4b 30 0e 06 03 55 1d |o4.....M0K0...U.|
+00000110 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 1d |..........0...U.|
+00000120 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 30 |%..0...+.......0|
+00000130 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 16 06 |...U.......0.0..|
+00000140 03 55 1d 11 04 0f 30 0d 82 0b 65 78 61 6d 70 6c |.U....0...exampl|
+00000150 65 2e 63 6f 6d 30 05 06 03 2b 65 70 03 41 00 63 |e.com0...+ep.A.c|
+00000160 44 ed 9c c4 be 53 24 53 9f d2 10 8d 9f e8 21 08 |D....S$S......!.|
+00000170 90 95 39 e5 0d c1 55 ff 2c 16 b7 1d fc ab 7d 4d |..9...U.,.....}M|
+00000180 d4 e0 93 13 d0 a9 42 e0 b6 6b fe 5d 67 48 d7 9f |......B..k.]gH..|
+00000190 50 bc 6c cd 4b 03 83 7c f2 08 58 cd ac cf 0c 16 |P.l.K..|..X.....|
+000001a0 03 03 00 6c 0c 00 00 68 03 00 1d 20 a7 28 ef 3e |...l...h... .(.>|
+000001b0 1c 65 9f 8e 9a 80 0b 7d ac 9c ce d6 1e 97 54 30 |.e.....}......T0|
+000001c0 53 9b e6 0c 61 e0 ea 9c ae 70 f2 78 08 07 00 40 |S...a....p.x...@|
+000001d0 0c 49 38 23 a0 75 28 fb ec 71 a4 89 79 45 d1 ca |.I8#.u(..q..yE..|
+000001e0 83 6f 5d dd 01 d4 c6 63 53 5d 6e 8f 06 09 80 a1 |.o]....cS]n.....|
+000001f0 f7 ef af 2d 29 af aa 10 86 1c 18 19 3f be bb 90 |...-).......?...|
+00000200 0e c3 9d 1e 6e 60 49 7f fc c8 42 61 89 c2 e3 04 |....n`I...Ba....|
+00000210 16 03 03 00 04 0e 00 00 00 |.........|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 b2 7f b6 1b 9c ec bf 2e ae a5 70 |.... ..........p|
+00000040 d5 33 9b 63 02 66 77 7d 00 ec 86 e4 bb d4 57 68 |.3.c.fw}......Wh|
+00000050 49 2a d3 be e7 |I*...|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 4c 7d ef ed ea |.......... L}...|
+00000010 ab 8d 4f 38 46 6e 8f 56 b4 1d f2 1f 2c df 57 c0 |..O8Fn.V....,.W.|
+00000020 f9 8a c2 71 f8 6d df b7 c7 1e 23 |...q.m....#|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 26 f1 7c ee c8 3a 61 b0 f7 5a bd |.....&.|..:a..Z.|
+00000010 b7 61 61 60 69 db cd ea 10 ee 63 15 03 03 00 12 |.aa`i.....c.....|
+00000020 22 c0 65 a4 5d 0e 48 9c 56 f8 54 17 82 5f 29 97 |".e.].H.V.T.._).|
+00000030 be 6b |.k|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-ExportKeyingMaterial b/src/crypto/tls/testdata/Client-TLSv12-ExportKeyingMaterial
new file mode 100644
index 0000000..adf1f72
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-ExportKeyingMaterial
@@ -0,0 +1,90 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 79 92 2e 86 bc |....Y...U..y....|
+00000010 c0 b7 56 2a 25 58 75 b3 25 ac 58 1d 8d 8e d5 87 |..V*%Xu.%.X.....|
+00000020 2d 67 8e 6e d4 d4 b6 67 b1 42 96 20 91 75 0b fa |-g.n...g.B. .u..|
+00000030 d0 6f ab 91 4a c3 15 07 1d 6c 8e e5 55 f2 26 aa |.o..J....l..U.&.|
+00000040 4d 5c 57 3b 93 a6 fc 46 c9 f6 80 1e cc a8 00 00 |M\W;...F........|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 5f 3c a6 bb 4e 32 85 |........ _<..N2.|
+000002d0 69 4b 23 df 18 9c 07 ac 0b a8 dd 9b 59 33 00 02 |iK#.........Y3..|
+000002e0 99 de 4e 66 1e 04 3b ce 4b 08 04 00 80 82 41 7c |..Nf..;.K.....A||
+000002f0 7b b8 ee d4 23 08 c3 23 8d b1 ea 27 43 e7 8e f1 |{...#..#...'C...|
+00000300 7b 87 b0 88 ab f7 b1 15 2e 45 c5 50 e7 cd 05 31 |{........E.P...1|
+00000310 bf 99 30 c8 ff 6a 23 ec 9d e5 c8 09 fa ec 50 a8 |..0..j#.......P.|
+00000320 fa b3 54 b7 c5 61 99 f6 94 12 e6 34 4a 59 e3 dd |..T..a.....4JY..|
+00000330 e5 7f f4 88 c9 2a 4c 09 65 d9 75 a6 ce 12 96 82 |.....*L.e.u.....|
+00000340 a2 36 f2 5e 93 f2 4e 1c 05 91 a7 5a 67 36 e9 3d |.6.^..N....Zg6.=|
+00000350 33 cd 6a 77 9c 8d 14 95 80 41 61 bd 80 ed 7b 51 |3.jw.....Aa...{Q|
+00000360 cf 76 87 4d ac dc 5f c1 5d 52 a7 f9 51 16 03 03 |.v.M.._.]R..Q...|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 bc c3 7c c2 cc a4 4e 8f d0 79 7a |.... ..|...N..yz|
+00000040 a4 7d 4c 3d 17 8c 19 93 4f 49 03 50 f6 71 4d 16 |.}L=....OI.P.qM.|
+00000050 97 bb 18 88 67 |....g|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 00 c4 8a f9 1e |.......... .....|
+00000010 c0 66 ab ef 39 ae 41 7a 05 9c e3 06 e4 4d 00 bb |.f..9.Az.....M..|
+00000020 d4 ef 21 71 a3 54 23 fe db 4a 86 |..!q.T#..J.|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 0c d3 9a f5 1d f4 5f b2 45 c7 7c |..........._.E.||
+00000010 38 59 6e df 6e 59 d5 94 8b a9 bb 15 03 03 00 12 |8Yn.nY..........|
+00000020 9e 74 a5 0e c1 7f 33 52 be 17 f6 f5 4d 9f 3d d1 |.t....3R....M.=.|
+00000030 b5 65 |.e|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-P256-ECDHE b/src/crypto/tls/testdata/Client-TLSv12-P256-ECDHE
new file mode 100644
index 0000000..3331435
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-P256-ECDHE
@@ -0,0 +1,98 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 01 15 01 00 01 11 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 96 00 05 00 05 01 00 00 00 00 00 0a 00 |................|
+00000090 04 00 02 00 17 00 0b 00 02 01 00 00 0d 00 1a 00 |................|
+000000a0 18 08 04 04 03 08 07 08 05 08 06 04 01 05 01 06 |................|
+000000b0 01 05 03 06 03 02 01 02 03 ff 01 00 01 00 00 12 |................|
+000000c0 00 00 00 2b 00 09 08 03 04 03 03 03 02 03 01 00 |...+............|
+000000d0 33 00 47 00 45 00 17 00 41 04 1e 18 37 ef 0d 19 |3.G.E...A...7...|
+000000e0 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..|
+000000f0 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..|
+00000100 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.|
+00000110 b5 68 1a 41 03 56 6b dc 5a 89 |.h.A.Vk.Z.|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 0b f0 3e a1 66 |....Y...U....>.f|
+00000010 13 35 53 83 59 3c 9e 2a 0f 0b b0 9a 42 de e4 f1 |.5S.Y<.*....B...|
+00000020 8a 2d 34 ef 15 fe 28 55 42 d8 bf 20 aa 27 5c 5f |.-4...(UB.. .'\_|
+00000030 24 59 17 ef 43 f3 18 f8 40 97 8f 1a 6a f4 e4 4a |$Y..C...@...j..J|
+00000040 a3 b7 11 39 01 bd 98 8c 61 08 d9 50 c0 2f 00 00 |...9....a..P./..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 cd 0c 00 00 c9 03 00 17 41 04 79 6a df 70 26 49 |........A.yj.p&I|
+000002d0 c0 5a 39 fc 7c 80 d1 2c cd 76 d0 4c 6f a7 7d bc |.Z9.|..,.v.Lo.}.|
+000002e0 32 c6 54 c6 76 58 e2 0f 3f 33 ad 92 61 33 11 16 |2.T.vX..?3..a3..|
+000002f0 d7 42 a8 ba 2a 8f 22 2a eb 88 3e 74 78 2a 67 de |.B..*."*..>tx*g.|
+00000300 39 75 63 2c 1d 2e da 33 77 a5 08 04 00 80 61 f5 |9uc,...3w.....a.|
+00000310 ed 56 5b f1 dd 78 a0 c4 8a 9b ac 28 c5 91 0c bd |.V[..x.....(....|
+00000320 f1 d5 c1 f6 31 2e 8c c3 d5 84 3a 15 e8 6d f1 bc |....1.....:..m..|
+00000330 9e a6 04 fd 95 2f 51 60 2f c6 ff 99 cf 38 24 bf |...../Q`/....8$.|
+00000340 a4 32 a2 1f a1 6b bd 27 98 00 14 23 0d 12 66 67 |.2...k.'...#..fg|
+00000350 48 33 92 51 e7 e7 3c f5 ef 13 ca 46 3c 39 53 70 |H3.Q..<....F<9Sp|
+00000360 41 78 4a 02 70 87 48 ce b0 31 02 33 0b 06 78 b9 |AxJ.p.H..1.3..x.|
+00000370 87 0b 07 e0 f7 15 c8 3e 27 a1 a3 20 24 9e 20 93 |.......>'.. $. .|
+00000380 7f b5 53 7b 18 88 96 87 2b df 02 ba 0c d8 16 03 |..S{....+.......|
+00000390 03 00 04 0e 00 00 00 |.......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 46 10 00 00 42 41 04 1e 18 37 ef 0d |....F...BA...7..|
+00000010 19 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd |.Q.5uq..T[....g.|
+00000020 a7 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e |.$ >.V...(^.+-O.|
+00000030 f1 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 |...lK[.V.2B.X..I|
+00000040 a6 b5 68 1a 41 03 56 6b dc 5a 89 14 03 03 00 01 |..h.A.Vk.Z......|
+00000050 01 16 03 03 00 28 00 00 00 00 00 00 00 00 c1 90 |.....(..........|
+00000060 a0 8b 53 87 a8 e3 56 4c 5c ad 5f dc 00 af 29 5f |..S...VL\._...)_|
+00000070 11 53 7d 49 25 f8 74 16 dc 84 5f 3b c6 24 |.S}I%.t..._;.$|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 00 f9 b2 51 85 |..........(...Q.|
+00000010 72 7e ec 79 72 59 90 ae 69 51 79 61 10 3b 4e 4b |r~.yrY..iQya.;NK|
+00000020 45 d6 a5 9a c0 1a 69 c9 9f 1c ee cd ad 6a e8 ea |E.....i......j..|
+00000030 c4 9e f1 |...|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 86 5a 45 |..............ZE|
+00000010 24 60 90 dc bc b3 f6 61 6f db 60 02 99 f9 e2 93 |$`.....ao.`.....|
+00000020 07 85 0d 15 03 03 00 1a 00 00 00 00 00 00 00 02 |................|
+00000030 36 86 b0 60 b5 5d dd 28 64 c6 5b c7 ed 01 07 b1 |6..`.].(d.[.....|
+00000040 12 39 |.9|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4 b/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4
new file mode 100644
index 0000000..12fb594
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-RSA-RC4
@@ -0,0 +1,84 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 51 02 00 00 4d 03 03 b0 e7 ee 09 45 |....Q...M......E|
+00000010 36 f1 7a 92 be 9e d8 9d ae cd c1 4e b2 12 94 3e |6.z........N...>|
+00000020 6c 34 71 ed 5f e0 97 7f 25 e4 dd 20 f4 43 01 03 |l4q._...%.. .C..|
+00000030 88 33 26 7f 48 c1 f2 d1 4d d3 f8 1a bd 86 4c 50 |.3&.H...M.....LP|
+00000040 18 89 dc 08 99 f1 51 c5 84 be b9 fd 00 05 00 00 |......Q.........|
+00000050 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000060 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000070 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000080 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000090 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+000000a0 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+000000b0 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000c0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000d0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000e0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000f0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+00000100 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+00000110 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000120 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000130 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000140 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000150 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000160 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000170 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000180 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000190 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+000001a0 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+000001b0 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001c0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001d0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001e0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001f0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+00000200 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+00000210 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000220 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000230 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000240 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000250 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000260 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000270 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000280 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000290 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+000002a0 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+000002b0 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 b9 65 8d bf a7 |............e...|
+00000010 c8 4b 79 ce 6f cb 8b 13 1c ac b9 7d 66 5e e9 ba |.Ky.o......}f^..|
+00000020 1d 71 4e a9 e9 34 ae f6 64 65 90 3b d8 16 52 a2 |.qN..4..de.;..R.|
+00000030 6f f4 cb 8a 13 74 a2 ee b7 27 69 b4 41 c0 90 68 |o....t...'i.A..h|
+00000040 bc 02 69 e1 c6 48 4f 39 36 30 25 ca 4c 17 ce 83 |..i..HO960%.L...|
+00000050 9e 08 56 e3 05 49 93 9e 2e c4 fb e6 c8 01 f1 0f |..V..I..........|
+00000060 c5 70 0f 08 83 48 e9 48 ef 6e 50 8b 05 7e e5 84 |.p...H.H.nP..~..|
+00000070 25 fa 55 c7 ae 31 02 27 00 ef 3f 98 86 20 12 89 |%.U..1.'..?.. ..|
+00000080 91 59 28 b4 f7 d7 af d2 69 61 35 14 03 03 00 01 |.Y(.....ia5.....|
+00000090 01 16 03 03 00 24 08 65 01 80 0d 59 b8 ac 0f 09 |.....$.e...Y....|
+000000a0 bf 61 31 32 e0 74 e9 f4 72 e3 2c 79 11 4d b2 a2 |.a12.t..r.,y.M..|
+000000b0 55 65 94 c8 cd 0a 61 99 07 b8 |Ue....a...|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 24 04 20 46 cd fb |..........$. F..|
+00000010 6c 46 9c 47 21 03 fe 9b a4 c6 da 2c 71 2f db 92 |lF.G!......,q/..|
+00000020 40 da 7d 46 2e e4 9c 81 86 89 7f 53 46 91 28 |@.}F.......SF.(|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1a 89 2b 2e 49 21 19 b7 d0 df 85 da |......+.I!......|
+00000010 b8 a7 f3 73 5f fe 44 e5 0c a1 af 16 74 93 bc 15 |...s_.D.....t...|
+00000020 03 03 00 16 5f 9e 64 d0 91 50 34 44 cf f6 1f e0 |...._.d..P4D....|
+00000030 e0 13 b9 67 da 5c 99 16 f1 b3 |...g.\....|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-RenegotiateOnce b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateOnce
new file mode 100644
index 0000000..06752de
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateOnce
@@ -0,0 +1,244 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 5b 4b bb c4 39 |....Y...U..[K..9|
+00000010 fb 45 5c 54 03 30 0f 71 c3 2e 48 25 33 fd 6d 40 |.E\T.0.q..H%3.m@|
+00000020 18 6e 75 43 66 9e 08 fb 6a a1 f8 20 34 3c c4 2a |.nuCf...j.. 4<.*|
+00000030 b5 9b 65 b0 cd b9 fc ce cf 51 f8 cc a1 5d 00 ed |..e......Q...]..|
+00000040 49 5b 43 9a ff c4 cf 6b d8 2a ea e5 cc a8 00 00 |I[C....k.*......|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 76 c4 f4 ec a2 d6 c1 |........ v......|
+000002d0 b1 d8 b0 41 71 8a ee e9 8a 17 06 90 6b 0c 05 66 |...Aq.......k..f|
+000002e0 54 d8 a6 ad 50 95 11 f0 03 08 04 00 80 46 0b da |T...P........F..|
+000002f0 0b 0c 6c 1a 2e a2 7e 28 40 1b 40 9a b4 5c 36 88 |..l...~(@.@..\6.|
+00000300 c1 ad cd 45 be 23 17 a6 98 e5 11 fe a8 78 c6 21 |...E.#.......x.!|
+00000310 17 a6 a8 7d ce 28 c4 ef 51 76 f8 b1 b1 75 31 04 |...}.(..Qv...u1.|
+00000320 b9 14 bc 3b bf 59 50 b8 e1 ad c6 86 45 3c e1 70 |...;.YP.....E<.p|
+00000330 fb cd 69 8c 0a 5f f6 2d bd 10 95 30 ed 4c 9a 47 |..i.._.-...0.L.G|
+00000340 73 8b 39 72 00 0a 7e 8f a9 42 27 01 6f 3d 37 f9 |s.9r..~..B'.o=7.|
+00000350 7d d4 1b a2 6a 07 37 dc 5e 6c 8b b1 d5 75 3a 9b |}...j.7.^l...u:.|
+00000360 d1 45 c5 d8 e0 90 f0 62 3d d5 01 00 9e 16 03 03 |.E.....b=.......|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 bb f4 78 64 23 f7 31 50 42 3d 97 |.... ..xd#.1PB=.|
+00000040 8f 73 89 b9 90 8f 74 b6 e4 7d 58 27 65 25 59 8a |.s....t..}X'e%Y.|
+00000050 5a 8d 8f fa bd |Z....|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 0a 43 74 53 47 |.......... .CtSG|
+00000010 41 4b 0a f1 f7 75 51 a9 22 c9 e0 5c 53 90 6b d7 |AK...uQ."..\S.k.|
+00000020 97 18 c6 ef c3 85 32 f5 7c 26 97 |......2.|&.|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 8e 83 1a 32 53 02 1c fa 84 89 4f |........2S.....O|
+00000010 25 fb 5f 85 4f bd ee ae 9f 0f ea |%._.O......|
+>>> Flow 6 (server to client)
+00000000 16 03 03 00 14 96 76 32 c4 6d e6 23 bf 21 a8 09 |......v2.m.#.!..|
+00000010 a3 8b 69 98 cd c3 c9 ce 73 |..i.....s|
+>>> Flow 7 (client to server)
+00000000 16 03 03 01 16 72 5b d9 30 b2 b0 91 e2 3d 2b 12 |.....r[.0....=+.|
+00000010 2c c9 43 f1 67 ae 54 ee ce a1 15 12 12 9a 27 46 |,.C.g.T.......'F|
+00000020 7e 47 90 d4 f2 7d b9 98 ec f8 61 b8 84 52 9f 21 |~G...}....a..R.!|
+00000030 c1 83 6a ce 1a 68 fc 5b 25 42 f3 8f 55 ee 92 45 |..j..h.[%B..U..E|
+00000040 af a4 d1 c4 a6 b5 0e 58 3d 70 76 98 ec 47 af 6f |.......X=pv..G.o|
+00000050 e3 4f 9f ef 52 a3 aa 33 75 83 f6 57 33 a8 dc f5 |.O..R..3u..W3...|
+00000060 36 49 09 1c 72 31 c1 43 52 64 4a b5 ca ce 06 f5 |6I..r1.CRdJ.....|
+00000070 91 18 90 85 f0 c9 96 4f bf 4c de 9e 50 a2 1c de |.......O.L..P...|
+00000080 86 51 1f 0b 73 e1 df 1d 2d 90 6d 7f a2 f1 28 e8 |.Q..s...-.m...(.|
+00000090 5f 2a 78 2d 8e ab f2 05 19 85 4e 92 a8 cf cd 16 |_*x-......N.....|
+000000a0 1e df 1d 51 ee 8b ba 72 cd ac d2 01 4b 84 46 62 |...Q...r....K.Fb|
+000000b0 1c 28 4d 3f 44 c1 62 12 13 4f f8 73 f4 da c0 98 |.(M?D.b..O.s....|
+000000c0 14 da 31 6a 48 0d 1d bb 24 6c ef 0f 98 c0 3c 86 |..1jH...$l....<.|
+000000d0 c6 d6 8e ab bd 20 bd 06 e9 ba aa ce 3a 88 25 95 |..... ......:.%.|
+000000e0 54 15 fb c6 49 c7 98 ff 27 92 c0 60 6a 3c f8 26 |T...I...'..`j<.&|
+000000f0 fd 28 ac c4 8f 5c 4f 15 24 10 45 3c 07 3d 3f 50 |.(...\O.$.E<.=?P|
+00000100 e5 db cf 78 bd b0 d2 24 a2 4b 3e a6 9c 2d 3b 0d |...x...$.K>..-;.|
+00000110 d8 1b 86 88 dc 0c 3c 9c 16 cf ea |......<....|
+>>> Flow 8 (server to client)
+00000000 16 03 03 00 81 2e c9 cd ad df 75 cf b6 8d 7f 8c |..........u.....|
+00000010 c6 bb 5b e6 2b 40 a0 36 45 13 ae 93 f1 04 bf f3 |..[.+@.6E.......|
+00000020 62 bd c8 62 d9 cf 05 a3 4c e9 37 af 35 a6 83 8e |b..b....L.7.5...|
+00000030 71 46 b8 2a 5b 02 3b 81 d5 15 b8 17 72 c4 1e 00 |qF.*[.;.....r...|
+00000040 78 d9 4a 04 a7 b3 5b 80 bd 1f 88 ba fa 22 b5 0e |x.J...[......"..|
+00000050 ca 44 55 27 c0 67 ce 37 4c 9a 9a d7 77 da 58 35 |.DU'.g.7L...w.X5|
+00000060 83 b3 39 90 8d e2 7f 08 2e cc 5a 8e 5e a8 c3 bb |..9.......Z.^...|
+00000070 db e5 a2 56 56 04 37 13 f3 b1 71 2d ea 0a 56 00 |...VV.7...q-..V.|
+00000080 6e 8d 8b 20 79 30 16 03 03 02 69 76 4b a4 c6 5e |n.. y0....ivK..^|
+00000090 0a a2 3c 89 24 f6 93 94 25 4e 0b 8a d2 33 2f 03 |..<.$...%N...3/.|
+000000a0 ab 20 22 33 ad 84 6d aa 31 6b 5a 10 0e 42 1b dd |. "3..m.1kZ..B..|
+000000b0 35 9b a0 dc 31 f8 65 91 c4 14 78 2e 74 2e 1d 46 |5...1.e...x.t..F|
+000000c0 3a 66 41 f0 a3 9a 4e ae bc 9b 55 f9 d1 9c c5 6e |:fA...N...U....n|
+000000d0 38 24 19 15 fb e6 c3 85 de ef f0 97 a2 a1 db ed |8$..............|
+000000e0 b8 d0 05 ae 93 77 d7 45 50 a5 4e 8a 83 84 07 fb |.....w.EP.N.....|
+000000f0 3a 80 c6 69 3c 6e b2 e3 e0 97 f7 03 93 76 dd 32 |:..i<n.......v.2|
+00000100 0c 5d a2 e6 1f 82 90 8b dd 93 06 ef eb b7 e0 74 |.].............t|
+00000110 1a 7d 8f 37 c2 c1 41 9c 30 74 ca 37 17 5e 71 a0 |.}.7..A.0t.7.^q.|
+00000120 cb d6 00 47 9d 14 93 aa fe 57 56 10 ae 88 13 65 |...G.....WV....e|
+00000130 f4 6c 20 4e f9 14 87 73 36 5e d5 20 93 34 db 87 |.l N...s6^. .4..|
+00000140 e7 f8 84 6e 36 9d 60 20 b5 8f 47 33 84 94 22 e1 |...n6.` ..G3..".|
+00000150 5d c6 1c 35 39 61 71 47 90 a9 b4 c6 5e 31 58 d1 |]..59aqG....^1X.|
+00000160 40 d8 22 22 23 c2 53 e3 75 1f 98 1c cc 7f 2d 11 |@.""#.S.u.....-.|
+00000170 31 5e 49 a1 2c d9 c8 db 6e 4e 9d da 57 e1 c9 32 |1^I.,...nN..W..2|
+00000180 03 6c f0 9b df c2 03 d5 b7 e2 04 77 e8 87 bc 14 |.l.........w....|
+00000190 73 66 b0 fb d1 d6 26 0c 36 90 2c 20 43 16 c6 68 |sf....&.6., C..h|
+000001a0 6c c0 ee be 2c da 6f 4f 95 1e cf a0 31 e8 40 48 |l...,.oO....1.@H|
+000001b0 88 61 26 7b 53 5b 42 14 2a 89 a3 1e 03 01 16 9d |.a&{S[B.*.......|
+000001c0 41 6d de 60 75 1d 36 12 cd 16 8b 1c 93 da 17 79 |Am.`u.6........y|
+000001d0 4b d2 1d 78 64 da 6c cc 5c 7c e3 f9 4d 70 a2 07 |K..xd.l.\|..Mp..|
+000001e0 b4 24 33 de 19 bc d2 1a 43 42 f4 26 8b c0 81 e4 |.$3.....CB.&....|
+000001f0 a3 32 97 09 ec 6f 39 d7 ca c9 c5 ee 38 fd 91 dd |.2...o9.....8...|
+00000200 c4 dc 3c 53 38 60 c7 b6 60 c6 a9 ff ae 81 e9 8c |..<S8`..`.......|
+00000210 ea 49 19 3f fe 0e 8e b8 e6 7c ec 4b 63 66 d8 7a |.I.?.....|.Kcf.z|
+00000220 82 51 7f 24 51 ae ad 91 5d 0e 2c aa ee fa 9f d3 |.Q.$Q...].,.....|
+00000230 22 1a 8b 8d 12 48 bb 3a 7c ea f0 09 af 1a 7e 7e |"....H.:|.....~~|
+00000240 47 74 b9 b9 1f 97 8e 64 62 52 ae 08 d5 f1 13 cb |Gt.....dbR......|
+00000250 51 64 b0 6a 33 1f 48 78 c1 91 91 91 a7 75 29 cb |Qd.j3.Hx.....u).|
+00000260 32 60 96 d4 27 3f a4 8f 12 e9 5d 79 4d fd f9 19 |2`..'?....]yM...|
+00000270 b8 f7 39 d8 53 e5 45 96 0f c6 4f f2 27 c6 e6 07 |..9.S.E...O.'...|
+00000280 40 47 29 94 b9 6a 38 9e 24 bf 9e 92 f6 67 3f e3 |@G)..j8.$....g?.|
+00000290 48 0f 3b 3a d7 7b 14 4e 34 a3 8a 25 b4 a2 d6 15 |H.;:.{.N4..%....|
+000002a0 3f 38 9e ba fa 7e 33 fd a4 4c ed e7 58 93 65 7d |?8...~3..L..X.e}|
+000002b0 90 48 fc 70 7e 10 a5 d0 0a ec 96 c4 cf 26 ae 94 |.H.p~........&..|
+000002c0 d7 3f 92 40 2f ad ed c8 bb 69 b1 3e 0b ab 4f 4e |.?.@/....i.>..ON|
+000002d0 73 91 a6 05 2b a7 89 e8 63 28 39 51 53 8d 2c 5e |s...+...c(9QS.,^|
+000002e0 c8 64 90 c3 b7 2d ee 00 aa 7f 38 ca 57 ab b8 aa |.d...-....8.W...|
+000002f0 93 12 af c5 16 03 03 00 bc 0e 58 31 64 e6 68 e6 |..........X1d.h.|
+00000300 10 81 2f 79 e3 49 3a d9 cc 70 09 7e b6 b5 61 c4 |../y.I:..p.~..a.|
+00000310 92 16 22 d0 e5 af b8 b8 91 2e 72 7c cf 95 cb ef |..".......r|....|
+00000320 14 81 73 33 34 98 65 1b 69 db 2c 9d eb 1c ce be |..s34.e.i.,.....|
+00000330 1f ce 48 b4 22 8d f0 6e 48 21 8e aa af 83 43 d2 |..H."..nH!....C.|
+00000340 65 54 0f 57 6b ce b1 24 ef 09 bf 7f 23 92 35 07 |eT.Wk..$....#.5.|
+00000350 55 2f 2f e7 b7 d7 72 d2 7c 5f 71 d6 20 9a 68 e8 |U//...r.|_q. .h.|
+00000360 1b 90 0b 13 f7 37 e2 35 0d fc 04 ea 32 50 2d 04 |.....7.5....2P-.|
+00000370 72 1a db d9 71 e1 4e d1 76 7c c3 f5 22 97 92 c5 |r...q.N.v|.."...|
+00000380 61 19 e0 40 b1 14 de 37 9d 8e e7 fd fe 2b 28 97 |a..@...7.....+(.|
+00000390 91 77 8f a7 d4 b1 db bc a2 78 65 5c a8 8d 41 21 |.w.......xe\..A!|
+000003a0 0e 56 6b ac 0b da a9 dd b1 51 84 19 20 ab e5 eb |.Vk......Q.. ...|
+000003b0 f2 52 8d 48 a2 16 03 03 00 4a 69 44 32 65 c2 09 |.R.H.....JiD2e..|
+000003c0 9c c1 d6 66 06 29 c3 a6 c3 10 2e d9 9e d6 0a d3 |...f.)..........|
+000003d0 06 a3 d2 d2 67 52 bd 19 26 a8 ef 08 ed 9f 2b e8 |....gR..&.....+.|
+000003e0 96 ea 08 b7 46 a2 36 e3 c1 84 4b c2 a2 b5 34 9c |....F.6...K...4.|
+000003f0 83 ea 94 51 e6 ca 9c 0b e1 e3 86 13 b7 1b 1f 4e |...Q...........N|
+00000400 ee a1 10 70 16 03 03 00 14 5a 1c c1 14 fd d9 ff |...p.....Z......|
+00000410 e3 46 ac 89 3b b3 e1 8e 6b 90 41 44 1f |.F..;...k.AD.|
+>>> Flow 9 (client to server)
+00000000 16 03 03 02 69 c8 db 54 92 d3 ea 2f 24 47 f9 24 |....i..T.../$G.$|
+00000010 53 c1 d4 6a e8 dd 1d 71 d6 fb 2c 7e 3a 41 75 f6 |S..j...q..,~:Au.|
+00000020 0c 08 70 b6 f9 0a 12 4b 0d 3d 34 03 a9 36 9e f1 |..p....K.=4..6..|
+00000030 c7 93 dc 51 e4 15 3d fd a7 67 28 24 32 fe ff d3 |...Q..=..g($2...|
+00000040 cd 69 d6 4a 5d 11 78 3b aa 07 8d 1e c4 97 22 34 |.i.J].x;......"4|
+00000050 df 03 f2 37 fd 4f 76 c3 04 a6 a6 0f 35 1c 0f 13 |...7.Ov.....5...|
+00000060 7e 0a b9 5e 47 d2 9a 8c d8 a3 f4 7a e4 92 5f 12 |~..^G......z.._.|
+00000070 a6 20 fb 51 16 af eb 55 d0 23 4e b5 f9 e8 cc 33 |. .Q...U.#N....3|
+00000080 bd d1 52 27 21 96 06 05 67 fa 68 0e ab 2c 84 05 |..R'!...g.h..,..|
+00000090 c9 97 6a db 69 57 a8 5c 55 a9 e1 cf 33 01 28 9a |..j.iW.\U...3.(.|
+000000a0 76 09 64 a4 a3 31 36 13 72 27 0c 85 e9 59 47 27 |v.d..16.r'...YG'|
+000000b0 89 07 ee e2 e0 68 a6 f0 fa d5 c3 8b 2f 75 68 d0 |.....h....../uh.|
+000000c0 8e d8 fe ae 1d 0d af 0b 40 3d 9f ec 85 03 24 20 |........@=....$ |
+000000d0 c5 11 30 aa 25 ee 2c 86 42 ae 4f 0d 6b 18 70 1d |..0.%.,.B.O.k.p.|
+000000e0 5f ae 1e cf 99 a7 0e c8 9b b3 63 58 cd b6 7d be |_.........cX..}.|
+000000f0 01 43 96 37 87 45 5f 2f aa 9c 12 48 ef 3b c8 d9 |.C.7.E_/...H.;..|
+00000100 60 20 26 69 68 56 48 aa 64 59 9e 41 ed 7e 8d c3 |` &ihVH.dY.A.~..|
+00000110 0f cd 0e 19 7a 76 89 95 f8 20 68 cd f9 81 e9 a0 |....zv... h.....|
+00000120 21 ff 60 e5 0f 6d dd 73 d2 19 1e 2a 76 f7 9a 46 |!.`..m.s...*v..F|
+00000130 5d d5 6b b2 19 28 c2 ac 9c e0 35 c8 d2 2a 53 fa |].k..(....5..*S.|
+00000140 3e 58 9e f2 05 7e 6b ce 51 6d 3d 2a ce 2e 9b 59 |>X...~k.Qm=*...Y|
+00000150 aa d4 8d cc ad 1f 82 e7 ca 5a ef a6 87 d5 41 0b |.........Z....A.|
+00000160 8d 27 6d 09 4d 40 c3 26 a3 a9 91 dd 1b 37 5d ff |.'m.M@.&.....7].|
+00000170 8f c3 c7 b1 bf be f5 d1 19 4d 93 86 a7 5f 5e 8f |.........M..._^.|
+00000180 14 34 82 50 76 25 42 04 b8 4b d3 da 15 ee 60 d1 |.4.Pv%B..K....`.|
+00000190 35 56 4c 63 0d ba 64 13 4f 3d 12 87 84 5a 45 41 |5VLc..d.O=...ZEA|
+000001a0 14 b6 6f 91 c4 b9 4f 97 c1 10 d6 3e b3 99 21 18 |..o...O....>..!.|
+000001b0 c3 91 82 e4 b6 91 3e bb 01 89 9a f0 60 ac 8e 7d |......>.....`..}|
+000001c0 cf c2 f9 b4 4f da 40 e3 5e 83 a1 8f b4 fa 28 aa |....O.@.^.....(.|
+000001d0 c9 ae 7b 8f 7d c9 d1 f8 7b b2 b5 3f 0a 9b 00 9e |..{.}...{..?....|
+000001e0 1d fa 59 ff 39 b7 85 4d 2a b9 b8 67 03 df a0 f9 |..Y.9..M*..g....|
+000001f0 f1 7e 9d 27 1c 55 a9 76 44 9e f1 13 78 7d 34 4d |.~.'.U.vD...x}4M|
+00000200 c9 23 07 e6 db 93 d7 70 3c 1b 5d 89 ed 8d 3d 43 |.#.....p<.]...=C|
+00000210 2e 89 f6 14 83 ff 87 db 26 a5 9a cd 98 5d 32 24 |........&....]2$|
+00000220 70 d2 e0 72 a7 6f a4 b4 2b 37 db 7e 39 4f d7 37 |p..r.o..+7.~9O.7|
+00000230 ea 68 b5 98 33 0e 23 21 3f 43 b3 ff 18 8e df 85 |.h..3.#!?C......|
+00000240 ba 15 48 3a fe 09 9b b6 27 40 d4 60 a8 3e 55 a3 |..H:....'@.`.>U.|
+00000250 75 c9 32 38 b5 21 46 ab 41 99 24 e6 09 3f 64 e6 |u.28.!F.A.$..?d.|
+00000260 09 40 cb 93 25 ab 1a 90 c7 d5 a6 40 36 a0 16 03 |.@..%......@6...|
+00000270 03 00 35 0f c7 e4 c3 16 c0 4f 7f 25 04 06 63 e7 |..5......O.%..c.|
+00000280 79 79 f9 4f c9 66 ca cd ba e3 af 4a 50 a3 3d c3 |yy.O.f.....JP.=.|
+00000290 79 0c 71 d9 2f df 93 79 30 8f 6b 0f 54 f9 be 07 |y.q./..y0.k.T...|
+000002a0 f3 d6 9b c0 2a 3a 0a a1 16 03 03 00 98 b8 f1 fc |....*:..........|
+000002b0 87 62 e9 6b 40 fd 50 ac b7 fa 52 69 51 66 ae 9b |.b.k@.P...RiQf..|
+000002c0 05 7e f2 38 73 27 d8 0c 2a 53 37 30 62 76 5d e9 |.~.8s'..*S70bv].|
+000002d0 fd 95 c6 14 d2 9d 34 13 e9 4c a5 7c c0 b6 e0 c4 |......4..L.|....|
+000002e0 97 ef 01 c0 f9 38 39 ee 17 c0 20 01 76 4f a7 10 |.....89... .vO..|
+000002f0 b0 45 9d c7 c3 cd a9 47 14 4a ed 00 1f 06 70 5b |.E.....G.J....p[|
+00000300 f5 04 8b 77 ad af 1e 77 7a 9d cc fc a4 1f d2 8d |...w...wz.......|
+00000310 8f e3 31 d3 3c de e6 85 f3 3d c0 ae 78 f7 22 c6 |..1.<....=..x.".|
+00000320 ec 2e a2 f0 5f ed 95 33 54 8c 89 35 c9 e4 25 4b |...._..3T..5..%K|
+00000330 84 5e 31 83 04 d0 f1 67 69 73 8b 7f 24 ae e0 87 |.^1....gis..$...|
+00000340 6b f7 ba f0 23 14 03 03 00 11 7a c7 6a 32 2b 9b |k...#.....z.j2+.|
+00000350 25 c2 d2 ee 37 b2 8d 7b f2 90 6d 16 03 03 00 20 |%...7..{..m.... |
+00000360 c1 1c 9d 18 a9 41 92 fc 05 19 93 7c 7e 2f b2 39 |.....A.....|~/.9|
+00000370 8c 76 4b 29 5a 67 cc f5 55 9f c0 e3 8f ad ee 3c |.vK)Zg..U......<|
+>>> Flow 10 (server to client)
+00000000 14 03 03 00 11 49 66 13 ec 09 83 0d 47 82 45 61 |.....If.....G.Ea|
+00000010 06 14 cc f5 da 41 16 03 03 00 20 34 d4 0c bd 86 |.....A.... 4....|
+00000020 6d ef a9 b6 97 68 e6 88 84 ed 1c 9d a1 8d 2b c9 |m....h........+.|
+00000030 2f 45 75 5b e5 6a 08 72 71 a9 c6 17 03 03 00 19 |/Eu[.j.rq.......|
+00000040 e8 83 4c f5 19 ea d1 ef e3 27 25 f9 af d2 f0 a6 |..L......'%.....|
+00000050 b3 62 15 66 ec 72 ce 4e e2 |.b.f.r.N.|
+>>> Flow 11 (client to server)
+00000000 15 03 03 00 12 2e 39 ba ca ad 7c a9 ae 3f 6a 78 |......9...|..?jx|
+00000010 b6 31 d2 d0 4e 1f dc |.1..N..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice
new file mode 100644
index 0000000..20aa6c9
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwice
@@ -0,0 +1,343 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 68 39 1d 0e 5a |....Y...U..h9..Z|
+00000010 22 ba 13 5f b6 c1 52 5d 13 e5 07 18 aa ec 24 0f |".._..R]......$.|
+00000020 c9 56 3a 83 a1 32 a1 7f 02 e8 7b 20 31 e2 f8 c4 |.V:..2....{ 1...|
+00000030 5b c2 57 9a 1d a4 6f a7 9c 1c 93 b1 9f 19 c3 cb |[.W...o.........|
+00000040 e1 73 87 1b a8 88 d9 4c 67 2f 44 aa cc a8 00 00 |.s.....Lg/D.....|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 57 22 18 98 ed 7f 12 |........ W".....|
+000002d0 e7 e3 83 6b 42 82 ff 49 54 f8 0b 7d 93 3d 11 42 |...kB..IT..}.=.B|
+000002e0 67 cf 89 47 77 31 c5 59 4a 08 04 00 80 69 d4 13 |g..Gw1.YJ....i..|
+000002f0 f8 1c 68 9d 40 10 c8 aa e6 44 0e 14 b9 38 6e ca |..h.@....D...8n.|
+00000300 a9 50 05 4a ce a0 03 ea 02 92 e4 5a ed 42 6f 70 |.P.J.......Z.Bop|
+00000310 e1 c1 99 49 a4 34 20 6b 5e 14 e8 a1 d3 27 ff 0d |...I.4 k^....'..|
+00000320 0c d7 47 49 1e 8f 8a 3a 62 1d c9 81 3c 5f a3 16 |..GI...:b...<_..|
+00000330 16 34 a0 53 a7 01 1d 09 f7 d9 d4 62 b2 0a 1c 1f |.4.S.......b....|
+00000340 b2 e5 24 1b 7e 78 35 43 ed 47 f8 62 53 2d 04 ec |..$.~x5C.G.bS-..|
+00000350 81 b5 68 11 3a 2d ee 88 ef 86 eb 71 d0 5e 31 42 |..h.:-.....q.^1B|
+00000360 57 6d b6 f2 be 32 4c 38 f8 2a 93 2f db 16 03 03 |Wm...2L8.*./....|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 2a 03 0a 58 36 31 ec 26 df e5 7c |.... *..X61.&..||
+00000040 88 b5 d1 f7 6d fc 4b 0a 91 54 4a e7 8c 83 a3 54 |....m.K..TJ....T|
+00000050 0a 10 5b ff 69 |..[.i|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 27 b0 69 0c 67 |.......... '.i.g|
+00000010 c7 3a ec c1 aa 02 20 cf f9 e8 22 86 3b d3 e1 4f |.:.... ...".;..O|
+00000020 bc fd 04 40 19 77 bf bd 38 28 56 |...@.w..8(V|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 8a 2c 24 1b b8 53 01 54 c8 bd f3 |......,$..S.T...|
+00000010 e1 ec a9 ab 83 a0 66 a9 29 1c 4e |......f.).N|
+>>> Flow 6 (server to client)
+00000000 16 03 03 00 14 c5 e3 03 06 89 d8 47 1a 66 18 0e |...........G.f..|
+00000010 8d 36 c5 f4 30 80 7e 72 a2 |.6..0.~r.|
+>>> Flow 7 (client to server)
+00000000 16 03 03 01 16 7e eb a3 b5 ea 58 e3 4a 26 35 7d |.....~....X.J&5}|
+00000010 54 15 93 74 e8 e4 63 34 38 d9 e0 02 3d 28 f8 98 |T..t..c48...=(..|
+00000020 0f 24 6b ca 08 7f b6 77 68 ec 85 c3 4a 6b 69 c3 |.$k....wh...Jki.|
+00000030 8d 8e 1b 8b 41 11 9b 0d d1 c8 99 2b c9 d2 4c f1 |....A......+..L.|
+00000040 fd 82 e5 35 ba a3 3b f3 6d 47 82 45 08 e7 02 bb |...5..;.mG.E....|
+00000050 10 a6 7b 76 83 78 e0 aa 5a 78 24 59 1c db ae a3 |..{v.x..Zx$Y....|
+00000060 37 20 b3 12 98 48 68 d3 b3 72 9f 4f d4 de 50 b4 |7 ...Hh..r.O..P.|
+00000070 4a c1 37 93 e0 55 ae e8 37 2a 40 de ac 30 e1 1d |J.7..U..7*@..0..|
+00000080 f0 03 19 8c af 77 f5 26 98 af a8 a8 d2 72 6c 68 |.....w.&.....rlh|
+00000090 75 00 32 10 e6 3f 91 a8 24 a7 d8 05 23 04 52 23 |u.2..?..$...#.R#|
+000000a0 e7 e6 83 ac 37 1b 36 a7 ca d4 7e d5 21 4c ab 38 |....7.6...~.!L.8|
+000000b0 23 cb 7c a9 f4 66 26 5e 7f 3e d6 ab 7a ac 34 38 |#.|..f&^.>..z.48|
+000000c0 95 16 df e2 e4 cf 3a 62 82 78 cb 71 32 06 6d 07 |......:b.x.q2.m.|
+000000d0 84 91 0c e9 d0 63 88 9e d1 b5 f0 fb 43 2b 07 0b |.....c......C+..|
+000000e0 32 d7 20 af b8 76 17 da ee cc e6 03 bb 7a 0b f2 |2. ..v.......z..|
+000000f0 61 4f db 7f a3 66 b0 05 a8 88 b8 0b b3 6e 9c df |aO...f.......n..|
+00000100 48 8b 7e eb 42 cd ea eb 1d bb 63 a0 e4 ee df 21 |H.~.B.....c....!|
+00000110 20 67 11 26 dd f1 47 1b 15 2b a0 | g.&..G..+.|
+>>> Flow 8 (server to client)
+00000000 16 03 03 00 81 60 70 d6 32 5a 0a 8f df ed cd f2 |.....`p.2Z......|
+00000010 d7 bf d0 da fd 53 63 65 bf f5 26 83 0c f5 6e e9 |.....Sce..&...n.|
+00000020 78 9b 03 7b 17 5f f4 d2 af 2a a3 85 13 92 be 00 |x..{._...*......|
+00000030 93 3f b3 f1 cb 04 aa 55 f8 ed c8 e6 9c 32 08 79 |.?.....U.....2.y|
+00000040 86 84 ef ac 72 bd 93 07 9c ca d2 e7 74 dd 51 a0 |....r.......t.Q.|
+00000050 6d 0e d3 32 3c 33 9d 58 aa 46 a9 ff 22 08 bc 2c |m..2<3.X.F.."..,|
+00000060 de 81 aa a8 5a 3c f8 36 93 d3 12 06 79 61 1f 71 |....Z<.6....ya.q|
+00000070 5f 45 d7 99 b2 55 10 22 db 56 d9 39 64 57 ad c3 |_E...U.".V.9dW..|
+00000080 59 a9 bd cb f2 22 16 03 03 02 69 34 e7 f2 7a bc |Y...."....i4..z.|
+00000090 0b 90 72 a3 3b 6b 38 a3 f8 7a 19 39 ff b4 d6 8c |..r.;k8..z.9....|
+000000a0 c9 92 4f a3 23 1a f0 89 bb 01 e4 b2 24 f7 db 3d |..O.#.......$..=|
+000000b0 f4 4b 02 75 d0 ca 3c ed e8 d9 13 61 c5 61 4e 7c |.K.u..<....a.aN||
+000000c0 fe b9 49 69 63 cc 23 5f 9b 23 85 ec 86 e5 17 28 |..Iic.#_.#.....(|
+000000d0 8a 1e 0c 45 e5 4d c2 be 66 92 47 88 28 ec 52 eb |...E.M..f.G.(.R.|
+000000e0 72 e5 30 89 58 8d 15 2b 98 eb cd e2 18 7c 53 f2 |r.0.X..+.....|S.|
+000000f0 89 ba 71 a5 91 20 64 17 7c 56 f1 01 8a 52 17 66 |..q.. d.|V...R.f|
+00000100 ef d7 bc 5b ff 54 53 13 2e 80 53 4c 84 6d a2 20 |...[.TS...SL.m. |
+00000110 0f e6 3d 33 90 7a 5b 1a 50 29 ce 1e af 74 a5 b3 |..=3.z[.P)...t..|
+00000120 0e 29 c8 e5 c1 50 b6 5d c8 bb e4 b5 f5 6b 04 a8 |.)...P.].....k..|
+00000130 24 a6 a8 cc 77 7c 72 d5 b1 f3 6a 1c 2e d7 7e e0 |$...w|r...j...~.|
+00000140 4c 46 3f 26 61 2e 54 7d ab d8 d6 ec 1e b0 0d d1 |LF?&a.T}........|
+00000150 02 57 00 7f 29 aa d3 1d a4 40 73 d7 21 12 76 58 |.W..)....@s.!.vX|
+00000160 7d 79 a5 c1 d2 57 63 48 0e 63 5f 24 49 8a 57 ba |}y...WcH.c_$I.W.|
+00000170 26 1c 39 4a f8 b3 89 79 e2 be 4e 8e 37 ae 16 75 |&.9J...y..N.7..u|
+00000180 42 5e 2e 9b 14 d5 b3 06 5f b9 c8 f7 16 8f eb 1c |B^......_.......|
+00000190 48 0a da 1e b3 4a 78 f7 f8 b4 35 bf 7d 3f c5 8d |H....Jx...5.}?..|
+000001a0 fa 7d c0 b7 52 af d3 13 de 96 39 76 fd 49 80 55 |.}..R.....9v.I.U|
+000001b0 bb b3 0f 5b 0c 84 4d 8b da 62 8a 20 4b a1 28 28 |...[..M..b. K.((|
+000001c0 3d 74 cc 34 9d 95 8e af c0 05 a2 5c 73 9d 73 d8 |=t.4.......\s.s.|
+000001d0 6c 4e 77 25 c5 8c 22 07 c6 b9 55 47 0c b2 12 73 |lNw%.."...UG...s|
+000001e0 2e f5 95 f7 28 c3 e4 24 2c fd 05 ac e2 3e df 93 |....(..$,....>..|
+000001f0 5a 28 66 aa d4 86 8a 48 e2 c8 69 01 18 90 54 10 |Z(f....H..i...T.|
+00000200 67 80 a1 be a8 9a 7f f3 17 ee dc 83 06 7a 70 6c |g............zpl|
+00000210 59 c2 2d 8f ff 79 a7 e5 e2 f2 f3 f3 5b 44 42 25 |Y.-..y......[DB%|
+00000220 a3 8c a0 83 07 5c f6 73 e9 bd f5 6b 86 89 b4 11 |.....\.s...k....|
+00000230 7b 9a 28 52 4f 55 70 4a 75 00 73 cc 84 fa 4a ef |{.(ROUpJu.s...J.|
+00000240 f8 8a 8d f9 18 e2 bc 13 48 cb 80 4d 6f fc d7 23 |........H..Mo..#|
+00000250 3a 9c 6c fd 46 27 94 8a 3d 9d fb 17 f5 06 4d a1 |:.l.F'..=.....M.|
+00000260 18 75 a7 9b 08 f8 47 b5 52 b4 19 4b b7 0f a4 e0 |.u....G.R..K....|
+00000270 78 f8 8b a4 cc eb d3 85 e1 ad 21 29 0f c7 09 28 |x.........!)...(|
+00000280 3f 21 12 6c fd 76 05 13 10 a0 c1 ce ba 7c e8 6f |?!.l.v.......|.o|
+00000290 e9 99 67 0a 9d 3a 7f f1 a6 8a 53 56 f1 09 22 21 |..g..:....SV.."!|
+000002a0 24 23 6e bc 77 fc 56 3b 31 15 58 1b e9 03 a1 bf |$#n.w.V;1.X.....|
+000002b0 0a 06 a0 fb 47 77 b7 ad 01 db ee 6a bc a4 a1 77 |....Gw.....j...w|
+000002c0 6f 3e 70 84 4c a6 21 ec ff fa f0 f0 68 ee 7d b1 |o>p.L.!.....h.}.|
+000002d0 e6 37 f1 1c aa 43 c7 b9 0e c4 52 7d 54 d8 f7 c5 |.7...C....R}T...|
+000002e0 16 21 99 89 cb 02 d0 54 b8 0e 91 2e 58 25 32 6e |.!.....T....X%2n|
+000002f0 fa ae 62 c9 16 03 03 00 bc 0c 2f 7e 22 d8 7f 21 |..b......./~"..!|
+00000300 0c 1a ec e1 37 72 3f 03 1d cc 73 f9 63 95 cd 47 |....7r?...s.c..G|
+00000310 66 17 60 8c da b4 35 a2 44 b1 d8 d1 1c 98 5b 8b |f.`...5.D.....[.|
+00000320 c8 9b c8 cb c4 15 0d 8d 08 1e 7c 3a 6b 20 3a f1 |..........|:k :.|
+00000330 d1 86 ae 08 bb fd 74 c5 62 9a 50 74 07 96 10 0e |......t.b.Pt....|
+00000340 e0 e4 a4 da c4 9d d1 f4 15 97 7d 21 0f 6f cb 39 |..........}!.o.9|
+00000350 8e 4e 40 1a 2a 7f 15 88 94 52 bc fd 61 b8 37 d1 |.N@.*....R..a.7.|
+00000360 48 62 bc 53 a3 a6 62 ec 0e c3 1f 82 67 19 71 fa |Hb.S..b.....g.q.|
+00000370 99 16 c3 cf d6 82 44 36 9e 0b f0 41 12 ca 7b 67 |......D6...A..{g|
+00000380 c3 a6 2d f7 13 14 0f d1 16 f9 2a 5a dd 43 45 c6 |..-.......*Z.CE.|
+00000390 c0 f4 17 36 64 11 fc ed e6 66 b6 0c e2 3d fb 72 |...6d....f...=.r|
+000003a0 93 27 46 20 db 1b 24 f9 69 a0 c7 71 e2 27 6a 93 |.'F ..$.i..q.'j.|
+000003b0 36 73 71 10 bd 16 03 03 00 4a cb 15 91 9c 22 96 |6sq......J....".|
+000003c0 f0 c8 b9 4d 9a 6c b0 eb 1a c5 d4 06 12 89 44 1b |...M.l........D.|
+000003d0 52 cd fb 32 3f 2c 25 f4 d3 88 0f e4 9c 18 91 59 |R..2?,%........Y|
+000003e0 42 98 a8 65 35 62 f7 ce fa a3 56 46 c5 b1 da ac |B..e5b....VF....|
+000003f0 9e 4e de 8d 14 fc 3c f3 94 74 50 99 1d 65 6b a6 |.N....<..tP..ek.|
+00000400 a9 38 93 9f 16 03 03 00 14 d7 5b 68 ca 4c 80 92 |.8........[h.L..|
+00000410 f8 13 5d fe 14 22 6f 9a 42 3a 27 de c8 |..].."o.B:'..|
+>>> Flow 9 (client to server)
+00000000 16 03 03 02 69 aa 39 9e c8 e7 89 97 7f 22 3c 28 |....i.9......"<(|
+00000010 76 ac d9 48 51 e0 cd 22 53 a1 6d e7 b4 00 27 7d |v..HQ.."S.m...'}|
+00000020 89 4b f0 54 d8 39 d0 a3 fc 35 a6 36 4b 3c eb 3a |.K.T.9...5.6K<.:|
+00000030 00 b0 c1 17 9d c8 13 a5 58 ba 16 9e cb 21 50 dd |........X....!P.|
+00000040 8a e0 2d 57 dd a6 bf 4d 6e b3 21 3b 46 f4 c3 77 |..-W...Mn.!;F..w|
+00000050 a1 86 07 c7 db e9 0a cb 2d 0f ff b5 1b ad 6b c4 |........-.....k.|
+00000060 c4 a4 4e 14 cf cb b2 6c 07 65 17 d2 db 30 e9 ec |..N....l.e...0..|
+00000070 41 4e 78 26 12 27 08 a6 a7 84 39 c0 4b e7 4b 23 |ANx&.'....9.K.K#|
+00000080 2f ca ff 1e 41 9a e8 44 fc 5d a0 34 4e ca a8 6d |/...A..D.].4N..m|
+00000090 31 51 57 c9 7e d1 0a 42 22 f2 b4 f9 a7 f9 28 d8 |1QW.~..B".....(.|
+000000a0 2a dd 19 0d 90 8b e1 78 b1 1c da 3a bb 5e 05 54 |*......x...:.^.T|
+000000b0 0d 0e f8 73 ed 01 e2 e4 d4 c1 f8 fa c3 d6 6f 42 |...s..........oB|
+000000c0 cc cb 99 99 97 18 b0 fb ab 51 42 66 45 67 b6 29 |.........QBfEg.)|
+000000d0 02 60 ab 74 30 db f6 16 8a 8f 8e 9c cc d5 47 fa |.`.t0.........G.|
+000000e0 f5 af 94 4f b1 94 40 57 ab 85 59 e4 3e cc c5 a0 |...O..@W..Y.>...|
+000000f0 61 b7 64 f9 dc 96 40 ae fb 4c 57 39 9e 9a 23 8e |a.d...@..LW9..#.|
+00000100 c9 36 6c 75 11 c7 6e 54 c3 1c e9 25 6a a0 f8 bb |.6lu..nT...%j...|
+00000110 6b 5c ca 5c 06 6c 03 88 01 27 4c 89 02 e6 b6 1a |k\.\.l...'L.....|
+00000120 92 99 4d 15 c1 1a aa 58 20 49 d7 4a f9 09 34 1e |..M....X I.J..4.|
+00000130 d7 d8 31 79 9f d8 b3 a0 76 ba 96 77 77 77 5b 80 |..1y....v..www[.|
+00000140 88 ab a0 90 c7 5f 3d 82 e1 23 29 6e 3a 4d 9b f0 |....._=..#)n:M..|
+00000150 7b 6a b1 9d 78 ba 4c 7e 02 1f a0 73 3e 91 cf 75 |{j..x.L~...s>..u|
+00000160 c6 52 2d c6 79 be 85 65 0e e4 73 39 fe 53 6d e0 |.R-.y..e..s9.Sm.|
+00000170 a3 18 d5 69 80 ca f1 c8 ad f5 f4 fb b5 40 2e f8 |...i.........@..|
+00000180 30 82 ca 2c 46 6a ab a6 b2 83 9f a8 95 95 30 e3 |0..,Fj........0.|
+00000190 e3 30 6d f5 7c 83 96 af 12 d8 d6 d6 f9 6a ad bd |.0m.|........j..|
+000001a0 bb 96 83 99 99 d8 6d 20 0e e1 be da 58 05 44 88 |......m ....X.D.|
+000001b0 a6 07 47 84 d4 77 fc 9b fb d7 ac 60 70 0b e7 76 |..G..w.....`p..v|
+000001c0 13 c7 38 d9 3d 60 eb a6 9f a5 6d fc 5c d5 f6 2f |..8.=`....m.\../|
+000001d0 31 02 38 65 8d be 04 06 84 95 86 b1 84 d9 ce c7 |1.8e............|
+000001e0 30 b9 d3 85 9f 1b 12 0f 5c 0e d6 8d e3 a0 15 04 |0.......\.......|
+000001f0 03 62 9d 52 7b e7 f4 13 aa 02 64 d9 d4 4b fd 6f |.b.R{.....d..K.o|
+00000200 de ea 4a aa 91 60 e7 78 af 84 b5 9d c3 d2 c6 3a |..J..`.x.......:|
+00000210 2a 9f 9b c6 8d 9e 5e 2c 90 6c d3 9d c1 be 96 5a |*.....^,.l.....Z|
+00000220 60 d8 73 6c 49 50 c8 03 ec 58 73 bc b3 8c 30 c1 |`.slIP...Xs...0.|
+00000230 f4 a2 7d 74 3d 8d 7e 64 c1 a7 b6 24 13 06 72 1b |..}t=.~d...$..r.|
+00000240 d0 87 22 af df 2a e7 fe 57 fa db e7 00 ba 74 35 |.."..*..W.....t5|
+00000250 16 34 20 3f 75 69 35 5f 64 7e 26 56 7c 93 05 4e |.4 ?ui5_d~&V|..N|
+00000260 42 65 b8 bf 59 8e 82 13 f1 d0 05 95 c2 3d 16 03 |Be..Y........=..|
+00000270 03 00 35 99 1d 52 84 73 d6 e7 90 f6 41 9e 69 07 |..5..R.s....A.i.|
+00000280 39 0b bc b6 c7 f4 f2 a0 93 80 b9 c7 bb b4 a6 06 |9...............|
+00000290 50 5b 5d 75 97 cf c5 dc 2d 07 3d 8f 9e ae fa bf |P[]u....-.=.....|
+000002a0 5b 6b 3e 98 02 fd e4 7d 16 03 03 00 98 80 ac e9 |[k>....}........|
+000002b0 4e e0 f8 b5 8c c2 2e 84 ec e0 3b eb b7 a0 14 2d |N.........;....-|
+000002c0 ff d2 bf 35 14 20 06 00 2e 48 c7 f8 a3 fd 4f 50 |...5. ...H....OP|
+000002d0 4a 04 3e c7 07 50 90 72 29 f0 5c ac e1 fd 9d 3f |J.>..P.r).\....?|
+000002e0 42 99 77 32 a9 79 24 7f 9e cc 84 1c d0 db 87 1c |B.w2.y$.........|
+000002f0 3c 9a ae e3 45 e5 67 83 5f 75 e9 27 f3 ef 8a 15 |<...E.g._u.'....|
+00000300 88 2b 3f cc 6f 6f a4 78 d5 b2 96 3e 72 d4 c8 43 |.+?.oo.x...>r..C|
+00000310 98 a7 60 ae 38 8e fe 21 49 5b c2 80 d6 ef 6f 9b |..`.8..!I[....o.|
+00000320 08 18 07 c2 64 00 a1 a0 09 8b b4 b7 eb 0c 68 30 |....d.........h0|
+00000330 26 87 f9 99 85 63 35 81 5a e4 31 19 9e f8 b8 7b |&....c5.Z.1....{|
+00000340 81 aa 24 ff cd 14 03 03 00 11 84 c7 e1 8f 74 66 |..$...........tf|
+00000350 e6 bd 14 55 a8 d3 67 30 2d c4 fb 16 03 03 00 20 |...U..g0-...... |
+00000360 3a 63 a5 86 f3 78 f1 62 18 77 f7 25 71 52 56 17 |:c...x.b.w.%qRV.|
+00000370 d2 a5 e4 fa bc bb 44 07 85 37 cb 36 84 c7 6a 97 |......D..7.6..j.|
+>>> Flow 10 (server to client)
+00000000 14 03 03 00 11 9e 99 89 2d 10 21 a1 38 04 77 1a |........-.!.8.w.|
+00000010 f8 1d b4 01 d1 9f 16 03 03 00 20 2a cb 67 8b 1b |.......... *.g..|
+00000020 44 26 41 7b c4 6d a1 f4 cb ee 15 87 01 65 18 5a |D&A{.m.......e.Z|
+00000030 c7 2d 10 e4 91 01 cb 22 e8 92 1a 17 03 03 00 19 |.-....."........|
+00000040 1a 46 a0 9a c5 1a 27 0c e2 f9 03 55 3a e8 43 a7 |.F....'....U:.C.|
+00000050 d7 47 a5 95 6a e7 a1 12 69 16 03 03 00 14 d6 e0 |.G..j...i.......|
+00000060 1d 89 e0 c2 9a 52 d5 bc d4 08 3e f6 81 dd 57 a2 |.....R....>...W.|
+00000070 25 f6 |%.|
+>>> Flow 11 (client to server)
+00000000 16 03 03 01 16 27 50 ce c0 8e 5a e2 54 55 cb c0 |.....'P...Z.TU..|
+00000010 08 c7 20 87 7e 78 c6 da a6 7a 62 fd 7f f5 87 b3 |.. .~x...zb.....|
+00000020 83 a0 c8 70 ab 57 9b ca bf 4c 07 06 f1 89 b9 b6 |...p.W...L......|
+00000030 24 f0 ae 72 e1 36 31 9f 74 ed 06 ad 44 3b 51 2c |$..r.61.t...D;Q,|
+00000040 ed f0 c2 d8 9b 27 d2 9a ec 44 88 80 7c 5a d0 66 |.....'...D..|Z.f|
+00000050 3d 84 e3 7c 24 89 b9 dd 8c eb 86 cd ce 69 0d e3 |=..|$........i..|
+00000060 97 ee ad 74 53 7f 9c f0 05 31 43 2a 8c 09 c4 11 |...tS....1C*....|
+00000070 46 3e 82 2c 3c 69 91 d1 eb 4b 8a ab a9 cb 24 00 |F>.,<i...K....$.|
+00000080 00 25 bd 26 d3 85 19 ff 3b 2b 92 3f 43 b0 9f 24 |.%.&....;+.?C..$|
+00000090 59 4f 3d a6 ce 65 27 5c 75 47 92 7b 4a d3 ca 55 |YO=..e'\uG.{J..U|
+000000a0 38 00 ac 37 0c 6e 2d 04 bc 6e fe 3a 9a 43 b6 7f |8..7.n-..n.:.C..|
+000000b0 18 c1 a6 ce 49 b4 61 d3 97 8d a2 c9 fb fb cd 23 |....I.a........#|
+000000c0 f6 2f 0c 0b 2a b8 31 9e fd ff 9f 44 1e 33 c3 23 |./..*.1....D.3.#|
+000000d0 bf 09 d2 de 90 b6 61 9c 33 33 33 46 bc 00 7e 16 |......a.333F..~.|
+000000e0 3c bd 82 2d 31 51 5b 11 87 ec 7f 25 d8 95 f9 9c |<..-1Q[....%....|
+000000f0 df 00 54 40 f3 c1 08 fa ef ba bc 5d b1 96 ae 8f |..T@.......]....|
+00000100 35 0e 43 b2 50 c7 7e c4 b2 71 2e 40 3a b7 90 2b |5.C.P.~..q.@:..+|
+00000110 81 ac 00 14 9d da d8 ca 5e 25 62 |........^%b|
+>>> Flow 12 (server to client)
+00000000 16 03 03 00 81 37 3a f4 1b 6a 43 d2 6a 02 02 33 |.....7:..jC.j..3|
+00000010 b9 d5 9a 5c d1 3b 52 73 f2 27 a6 c0 f0 9b dd f3 |...\.;Rs.'......|
+00000020 d7 cd 89 ec 21 e0 d3 2f 4d 6c b0 cf 50 a7 39 43 |....!../Ml..P.9C|
+00000030 c2 56 d2 f8 45 d7 3c a6 b6 b9 06 3f ca a7 f8 37 |.V..E.<....?...7|
+00000040 4c 89 01 49 82 5f 27 15 3c bf f0 86 7c 1a 84 03 |L..I._'.<...|...|
+00000050 5a 90 77 03 01 fd b8 60 2a be cc 60 c6 54 b5 ec |Z.w....`*..`.T..|
+00000060 c1 5d 6b e6 f0 2c 8c e6 7e e3 b6 c3 8b 63 3c 69 |.]k..,..~....c<i|
+00000070 ac 2c 9a 24 a7 77 5f 0c 36 08 68 6c 8b 76 f1 80 |.,.$.w_.6.hl.v..|
+00000080 4a bf f7 e6 15 5b 16 03 03 02 69 a1 ce a6 de 44 |J....[....i....D|
+00000090 cf d6 f7 88 f4 da 01 06 2b e5 cf 54 8d f6 78 ab |........+..T..x.|
+000000a0 53 c5 ea d9 97 4b 94 22 24 9b 98 ba ba ee 42 9d |S....K."$.....B.|
+000000b0 c3 e4 12 e3 be 35 24 86 3d 38 a0 6e b7 e6 cf dc |.....5$.=8.n....|
+000000c0 e7 5c e1 0d 7c 05 bb 63 7c 8b c4 a4 db 9a 85 a4 |.\..|..c|.......|
+000000d0 ba d6 d4 79 38 79 01 52 2d cf c1 c7 6e 09 64 ff |...y8y.R-...n.d.|
+000000e0 e9 b6 3e f2 a0 2b 4c 91 3f e2 fe 1a 40 4b 14 ea |..>..+L.?...@K..|
+000000f0 77 8f 40 1c a2 96 7c d3 ce 34 5e d8 13 5a 82 33 |w.@...|..4^..Z.3|
+00000100 41 59 fa d9 81 1c 85 41 9c 61 b9 ca d5 46 e2 77 |AY.....A.a...F.w|
+00000110 3d a9 50 4f 11 b1 34 aa ae fd e5 ec fe 12 e6 10 |=.PO..4.........|
+00000120 36 84 fb 25 f8 a4 6f 44 e3 ac 89 67 e4 9a 02 c4 |6..%..oD...g....|
+00000130 8f a9 4a d0 f4 64 e2 de da 80 02 60 cb a9 2d e0 |..J..d.....`..-.|
+00000140 fa d9 b9 ee 43 e1 3e ed 79 79 6b 21 62 3d 6f b0 |....C.>.yyk!b=o.|
+00000150 77 53 db 26 60 e1 d6 ff a7 01 2b b7 f0 49 df b8 |wS.&`.....+..I..|
+00000160 bc d9 ac 77 80 f8 53 66 16 8d 3a 8d 63 fa 12 e1 |...w..Sf..:.c...|
+00000170 ed f7 8b c0 40 46 16 70 e3 db f3 38 87 9f 11 eb |....@F.p...8....|
+00000180 0b f5 b3 44 e4 16 e1 ed 85 e6 67 d5 35 60 20 99 |...D......g.5` .|
+00000190 7d bd 9f 65 b9 52 68 6c 6b 83 f9 06 e3 a7 3e 0f |}..e.Rhlk.....>.|
+000001a0 9e 7c a5 ac 87 7a 45 53 a5 3f 27 5b 99 a9 34 c2 |.|...zES.?'[..4.|
+000001b0 5a 44 9a 30 08 30 c6 ff 60 8a a5 72 f7 49 d3 7c |ZD.0.0..`..r.I.||
+000001c0 1f f9 8b 74 a0 b1 c8 65 84 6d 91 86 ab 1e 82 3b |...t...e.m.....;|
+000001d0 d5 c4 bb 06 b3 31 61 bb 0e 65 3e 18 4d 0c c1 c1 |.....1a..e>.M...|
+000001e0 9d 7f ea ad cf 53 2e 9c 1c 7e aa c8 84 9e 0d ce |.....S...~......|
+000001f0 91 53 3c d4 05 7e 57 d1 8b 55 ea e4 6e 57 90 4c |.S<..~W..U..nW.L|
+00000200 bb 74 9c 87 1c 6a 89 cf 2c 50 8d 04 04 e6 18 c8 |.t...j..,P......|
+00000210 0c 9f 38 84 f4 f4 94 8d 33 2b a1 27 0b 5c 6a 2a |..8.....3+.'.\j*|
+00000220 0c 13 b7 07 b7 a0 c9 e5 3c 9d 5a 7e 96 c9 53 fc |........<.Z~..S.|
+00000230 ff c4 3a 8f 16 1f 2d 64 50 1d 13 c3 55 fb af d2 |..:...-dP...U...|
+00000240 0e f9 e6 18 e3 62 ce 6a 8f 96 ff 00 0e fe 27 53 |.....b.j......'S|
+00000250 70 57 53 2d fd f3 02 c7 fe b3 19 49 88 27 7e a2 |pWS-.......I.'~.|
+00000260 42 7b 22 d0 77 4e e5 04 aa 0d b6 9d b9 48 97 ab |B{".wN.......H..|
+00000270 33 e7 14 97 65 82 f9 2c dc 71 9e 4b eb ed 42 73 |3...e..,.q.K..Bs|
+00000280 c6 c8 93 8a 3a 24 bd f9 b4 6a 95 c1 1b 22 1d f5 |....:$...j..."..|
+00000290 c8 33 c5 38 1e a7 2e 91 68 35 4c 0a 37 57 ac e2 |.3.8....h5L.7W..|
+000002a0 c9 37 9e d9 1c b8 76 73 c2 d2 0c d0 c4 a1 c0 d5 |.7....vs........|
+000002b0 72 39 bf 03 f7 8d db e0 8f fe e2 d6 d0 d4 cc bb |r9..............|
+000002c0 7d 78 c6 c5 13 a8 4e 45 1e 66 60 77 fe 26 4d 18 |}x....NE.f`w.&M.|
+000002d0 90 e8 e1 0c 5b 2b 25 9b ee 6d 76 3f f6 23 a2 26 |....[+%..mv?.#.&|
+000002e0 52 8d a9 4e 7f ed 8e e2 6d 7c b4 eb 25 46 54 27 |R..N....m|..%FT'|
+000002f0 e2 2d 2c 59 16 03 03 00 bc 6e c1 fb 66 55 ca ea |.-,Y.....n..fU..|
+00000300 56 62 78 2f fd c4 ff da 78 dd e7 4d 34 59 a5 8f |Vbx/....x..M4Y..|
+00000310 05 ab ac 7f 80 35 f6 de 9d 3f fe 4b d4 79 07 3b |.....5...?.K.y.;|
+00000320 c0 8d 02 b8 1a 28 b5 eb 9b 55 6c 26 12 8d 38 01 |.....(...Ul&..8.|
+00000330 55 ed 28 68 aa 48 13 61 d3 fe 29 f0 fe 18 4e ae |U.(h.H.a..)...N.|
+00000340 6e f9 47 7c 65 91 f9 5e 17 80 68 fd 19 4d ed 17 |n.G|e..^..h..M..|
+00000350 7f 11 c4 15 5d 4b fc ea a7 5c df 76 a0 08 2e 15 |....]K...\.v....|
+00000360 d1 c6 ae 7b 0d 1f 79 d7 0c 59 6b 53 46 b6 c0 2b |...{..y..YkSF..+|
+00000370 ce 09 39 12 7a df f6 7d a2 4b 86 2a df ab b8 7c |..9.z..}.K.*...||
+00000380 07 10 3c 34 cd 15 4c ac 68 a4 28 8a f8 fc 30 a4 |..<4..L.h.(...0.|
+00000390 4f 15 77 b4 91 ca 02 ee bb 64 36 90 1b 4b 9d 2b |O.w......d6..K.+|
+000003a0 72 e7 dc 10 bd 83 97 18 3c 56 68 58 c9 e3 22 df |r.......<VhX..".|
+000003b0 33 43 81 7d 5f 16 03 03 00 14 a8 eb 40 73 19 19 |3C.}_.......@s..|
+000003c0 22 10 63 ed f0 6d 73 8c f4 bd f9 ba ad 2e |".c..ms.......|
+>>> Flow 13 (client to server)
+00000000 16 03 03 00 35 67 14 4b ca 21 7f d2 82 1d 2e b3 |....5g.K.!......|
+00000010 1a 82 ae 2d d9 d6 7c 76 94 78 d4 ec 0e 4d fe 5c |...-..|v.x...M.\|
+00000020 d5 56 5e 6d 32 f4 a0 64 50 1e f6 e4 32 28 92 80 |.V^m2..dP...2(..|
+00000030 d4 15 1c d5 f6 52 fc ca c0 e7 14 03 03 00 11 df |.....R..........|
+00000040 9d f3 d1 64 92 92 7e 11 77 64 e5 67 01 33 49 17 |...d..~.wd.g.3I.|
+00000050 16 03 03 00 20 c8 0f d9 d2 c8 b7 d6 a5 ac 2c 33 |.... .........,3|
+00000060 f8 77 8f b1 df db 16 de 43 6c e6 5a eb a0 6e ff |.w......Cl.Z..n.|
+00000070 be 1d 69 ab 30 |..i.0|
+>>> Flow 14 (server to client)
+00000000 14 03 03 00 11 6e 2c 51 c5 dd fa 70 2a 34 e0 cc |.....n,Q...p*4..|
+00000010 3c 9f b8 66 15 e6 16 03 03 00 20 78 02 96 c6 24 |<..f...... x...$|
+00000020 57 ca 4a 60 47 68 f6 5a 13 8b 3b ce 90 60 d2 e3 |W.J`Gh.Z..;..`..|
+00000030 1b d8 ab 1c df d4 5e c2 8d 5c 5b 17 03 03 00 19 |......^..\[.....|
+00000040 b7 15 fb 91 10 48 ae 25 0c cd 4f 06 fa 2a 59 49 |.....H.%..O..*YI|
+00000050 2f 18 5e 7e 36 1b 2e cb 3a |/.^~6...:|
+>>> Flow 15 (client to server)
+00000000 15 03 03 00 12 c3 ff f7 b3 dc d4 b3 f5 d4 7c a3 |..............|.|
+00000010 18 db 08 a2 50 ad 75 |....P.u|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwiceRejected b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwiceRejected
new file mode 100644
index 0000000..784bcef
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-RenegotiateTwiceRejected
@@ -0,0 +1,247 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 96 8a 79 30 8b |....Y...U....y0.|
+00000010 13 f5 d3 1c 09 45 76 83 d7 2e e5 ad e3 ee e1 c4 |.....Ev.........|
+00000020 d4 b4 4c 37 93 cb 90 e1 9a 5e 52 20 fb 25 91 ea |..L7.....^R .%..|
+00000030 1a 96 b6 fb 1f 0c a8 62 06 a0 fe 51 68 c0 fb a5 |.......b...Qh...|
+00000040 f1 05 28 02 be dc 87 31 e6 ff 90 1a cc a8 00 00 |..(....1........|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 ad 8e 56 2a c0 d0 7c |........ ..V*..||
+000002d0 e1 cb 6b 20 0b 3e 53 33 28 25 37 42 5b 13 3c d5 |..k .>S3(%7B[.<.|
+000002e0 26 98 9e 0f df 45 6d 27 67 08 04 00 80 72 49 21 |&....Em'g....rI!|
+000002f0 f0 02 02 a3 7c e1 2a 18 d0 d0 21 8e 50 17 ad 0c |....|.*...!.P...|
+00000300 3c a2 6d 65 b5 cb bc 7f 9e 7d 7f e2 36 3d b6 c8 |<.me.....}..6=..|
+00000310 df 7e b9 28 ab 01 99 2a 68 a4 be 46 11 94 9f 8c |.~.(...*h..F....|
+00000320 67 02 92 1e 3c 51 78 f3 7a 35 ed f4 bb 8b fe b3 |g...<Qx.z5......|
+00000330 8c 32 aa c1 05 4f 99 68 b0 8a 75 65 1d e6 d6 6a |.2...O.h..ue...j|
+00000340 61 65 aa 00 01 6b 29 06 99 d4 5b c7 c3 d2 0c 17 |ae...k)...[.....|
+00000350 74 59 d4 ee 99 b8 ef 5b 53 ff 33 df 9e 05 49 4f |tY.....[S.3...IO|
+00000360 31 c6 95 81 67 c2 52 8a 0c e9 6a 46 22 16 03 03 |1...g.R...jF"...|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 b8 c8 5d 3d b8 b8 2b c7 06 94 ec |.... ..]=..+....|
+00000040 cc 92 01 22 3d cd 38 d8 aa 9f 1f 18 ef a0 ee 59 |..."=.8........Y|
+00000050 c0 3b 04 56 49 |.;.VI|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 be 6c dd f4 ef |.......... .l...|
+00000010 71 1d 9c a7 24 ef 74 81 c4 01 1e e0 ef ac 78 90 |q...$.t.......x.|
+00000020 4e 51 fd 8a ca 83 e7 57 95 07 fa |NQ.....W...|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 35 96 43 38 06 49 b1 3f 01 ae 85 |.....5.C8.I.?...|
+00000010 1a ee 4b 2b fe c0 75 76 b6 4a b0 |..K+..uv.J.|
+>>> Flow 6 (server to client)
+00000000 16 03 03 00 14 df 6c d7 78 02 f5 a7 cb d8 2f fb |......l.x...../.|
+00000010 04 dc 30 bc 28 51 f9 ec b8 |..0.(Q...|
+>>> Flow 7 (client to server)
+00000000 16 03 03 01 16 8c 2a 91 5b 60 aa 44 e7 b7 7e b8 |......*.[`.D..~.|
+00000010 ee c2 3e f3 c4 2f 6a 75 8e 25 07 5a 5c 42 81 fd |..>../ju.%.Z\B..|
+00000020 65 4c 2a fb a9 80 f0 ba 33 1b 06 a8 79 a8 15 8e |eL*.....3...y...|
+00000030 3a c4 08 95 a5 23 f0 ba fb 43 58 26 84 b5 9d 17 |:....#...CX&....|
+00000040 03 e5 e7 08 ce 8b 79 9c 5e fb c6 6e a6 b8 12 cf |......y.^..n....|
+00000050 b9 6e 4a 2a 90 d0 6b 65 93 bf 41 31 25 7f 3a 7c |.nJ*..ke..A1%.:||
+00000060 75 1f d6 4e 22 d3 90 7b 71 14 57 c6 b6 89 ef 79 |u..N"..{q.W....y|
+00000070 74 7e 63 79 b9 63 d6 ef 02 b7 54 4b 53 0e 7f 70 |t~cy.c....TKS..p|
+00000080 8a 34 b1 85 98 ae a7 05 b8 41 9d 49 a3 ca eb 7d |.4.......A.I...}|
+00000090 8b 64 e7 5d ca 11 71 93 e0 ff 6e 43 37 b4 e9 ec |.d.]..q...nC7...|
+000000a0 23 6f d6 c6 bc cb ef a2 0b d0 4b ba 4f 40 b0 4b |#o........K.O@.K|
+000000b0 ec 57 cb 8a 10 ae fe cd 14 70 42 a0 b9 1c 81 f6 |.W.......pB.....|
+000000c0 d2 79 47 31 4a b8 aa ac 89 98 cf ae 4e 8f 3d 36 |.yG1J.......N.=6|
+000000d0 c5 41 0e d8 e6 f3 88 2a 19 e5 e7 71 e2 2f 32 93 |.A.....*...q./2.|
+000000e0 ae 05 95 25 8f ec 4e 10 25 7e 53 60 6e c2 f2 72 |...%..N.%~S`n..r|
+000000f0 fc 7a 69 c1 93 e9 b8 2e 94 f3 19 31 5b 23 7c fd |.zi........1[#|.|
+00000100 04 5d 59 ca 00 cc 37 0b 05 0d 50 10 50 3f b0 86 |.]Y...7...P.P?..|
+00000110 84 d4 fc 6a 0a 94 dc ba 88 fe ad |...j.......|
+>>> Flow 8 (server to client)
+00000000 16 03 03 00 81 41 25 27 5b 76 24 a0 4f f0 bf ca |.....A%'[v$.O...|
+00000010 c4 4f f8 7c c6 e8 2a d4 d1 ed f1 b8 34 84 d6 d5 |.O.|..*.....4...|
+00000020 93 20 70 7d 8e 75 c5 16 a8 ff 5c e6 de 16 ea 96 |. p}.u....\.....|
+00000030 3f 86 3b bd 6d fa 96 3d 27 18 34 b8 18 86 ee 65 |?.;.m..='.4....e|
+00000040 7f f2 cc 7a b9 f8 2e 5a 32 f3 16 e2 a2 27 fd 4b |...z...Z2....'.K|
+00000050 31 19 e6 81 d9 ef 02 10 ac b6 55 d3 0b e2 b0 09 |1.........U.....|
+00000060 56 ea 50 5a 96 b3 ff 07 78 48 df 77 3f 15 c9 ff |V.PZ....xH.w?...|
+00000070 a7 24 af 28 ec 99 1a c9 36 09 16 9c 7c 5a c0 85 |.$.(....6...|Z..|
+00000080 7c 93 e4 61 2e 5b 16 03 03 02 69 ef 17 31 d5 9c ||..a.[....i..1..|
+00000090 bc 09 f9 b7 75 e2 c8 ea 93 6f b7 49 e3 0e af bb |....u....o.I....|
+000000a0 84 d6 3b 20 e2 89 13 6f 7a d1 73 a7 cb d5 03 b2 |..; ...oz.s.....|
+000000b0 20 40 40 76 d9 5d 3b 23 cb 48 ba 3c 1b e7 5d de | @@v.];#.H.<..].|
+000000c0 16 be 82 91 39 d0 b4 83 3e 4c b8 a0 66 56 47 6c |....9...>L..fVGl|
+000000d0 08 03 b1 0f be 3f d3 5e 7e b4 40 db db 5b ce 61 |.....?.^~.@..[.a|
+000000e0 d9 dc 02 7d ea df ea 43 08 2c b0 1c af 76 8f d3 |...}...C.,...v..|
+000000f0 cd af 51 cd 17 df 70 58 90 bd 83 aa 4b e5 fe cd |..Q...pX....K...|
+00000100 90 30 e0 b5 d0 95 49 c2 10 06 8c 5a dd a2 37 ad |.0....I....Z..7.|
+00000110 d5 d1 0e 73 c7 92 a9 ab 67 51 da 9d a4 62 6d a6 |...s....gQ...bm.|
+00000120 d7 89 22 2b 97 59 ad 02 65 e9 1d 48 44 07 c9 c0 |.."+.Y..e..HD...|
+00000130 c4 1f 7f da 64 0c 35 19 16 b3 70 41 d8 61 c3 47 |....d.5...pA.a.G|
+00000140 59 4d c2 e6 07 86 55 92 b9 98 8e 5c 86 d2 d5 51 |YM....U....\...Q|
+00000150 6a 50 19 99 75 0a cf 6e 49 cc 8a 76 b5 2b 20 48 |jP..u..nI..v.+ H|
+00000160 2b 11 d4 54 a2 ea 98 ce d8 56 22 c8 f8 eb e5 25 |+..T.....V"....%|
+00000170 c8 cf ec 86 95 09 51 7e 18 89 bb 8f d4 66 b8 44 |......Q~.....f.D|
+00000180 c2 78 f4 4d ad eb 2d 79 f8 f6 02 4f d2 35 d4 71 |.x.M..-y...O.5.q|
+00000190 b3 ae e6 7d f6 45 6c 99 07 57 3c 01 bb c1 fb f1 |...}.El..W<.....|
+000001a0 1a ac ba 92 b6 60 52 63 8b 21 eb bf 77 02 c6 29 |.....`Rc.!..w..)|
+000001b0 7f 10 f7 11 ac a2 90 a9 8b 47 da c1 2c 41 c9 da |.........G..,A..|
+000001c0 3f 18 ab be f0 eb 20 98 80 c6 d2 14 9e 8e d3 41 |?..... ........A|
+000001d0 c3 37 ab 12 5b cc d0 25 bd af 16 49 4e 89 a1 92 |.7..[..%...IN...|
+000001e0 d1 09 49 59 dc cf f8 6c 73 02 cb 72 6d 28 6e 28 |..IY...ls..rm(n(|
+000001f0 c5 a8 84 20 e6 f8 1b ad c1 6c 8f b0 30 b2 49 84 |... .....l..0.I.|
+00000200 22 42 7d ec e1 c7 ab 29 de 1c 84 1f cf 59 c6 80 |"B}....).....Y..|
+00000210 7e 13 13 d7 c5 e5 f2 e0 3b 9d 81 c9 3f 86 21 27 |~.......;...?.!'|
+00000220 d7 c8 45 c1 25 f6 19 8d 0a f6 e9 5a 9b d5 64 a1 |..E.%......Z..d.|
+00000230 e4 6d fe 6a cf d1 c3 1b d4 ea d9 1f 6b dc f9 a7 |.m.j........k...|
+00000240 e9 d2 6c 31 19 db e1 f4 f8 82 6e 8b da fd b1 fd |..l1......n.....|
+00000250 0a 56 84 73 db 25 5f bb 12 61 70 de 67 34 28 1c |.V.s.%_..ap.g4(.|
+00000260 c3 e6 eb 81 c8 94 55 ca 52 25 e8 72 bf a1 c5 88 |......U.R%.r....|
+00000270 b8 ce 72 8d 64 6c 38 d9 19 07 f3 51 51 91 84 f2 |..r.dl8....QQ...|
+00000280 c4 76 7f 8b 57 09 71 94 38 aa f1 64 51 6f 62 50 |.v..W.q.8..dQobP|
+00000290 c8 50 68 82 b9 54 b1 28 54 99 21 26 7d 75 c7 c7 |.Ph..T.(T.!&}u..|
+000002a0 79 e7 65 93 72 a4 39 2d 4c ec ba b2 4c 92 ae ee |y.e.r.9-L...L...|
+000002b0 34 a2 22 2f f9 b9 75 a9 27 77 63 2d ac 27 87 ce |4."/..u.'wc-.'..|
+000002c0 ee 37 c0 c7 c1 b6 4c 13 d7 78 97 64 dc af ea 0d |.7....L..x.d....|
+000002d0 7c 12 0e 7b 0b 26 77 01 e4 1c 24 e8 9f fc 19 2f ||..{.&w...$..../|
+000002e0 46 a2 81 3d 0d c7 16 7e 49 25 b4 c1 0f 0a 71 05 |F..=...~I%....q.|
+000002f0 25 eb 53 e4 16 03 03 00 bc 0b 79 2d c6 0a 63 68 |%.S.......y-..ch|
+00000300 f0 21 37 d0 42 4a 0f 2f 7d 2f a0 7d 3d c3 94 c4 |.!7.BJ./}/.}=...|
+00000310 36 f5 a6 db e1 ad 0f 94 07 67 57 54 d4 57 86 50 |6........gWT.W.P|
+00000320 a2 e1 78 09 f2 e3 7b bc 6d 1b c0 fe 16 eb d3 ef |..x...{.m.......|
+00000330 fb ec 22 44 ee 2f 78 99 84 e2 c1 4c f7 0d 4f bc |.."D./x....L..O.|
+00000340 ca 57 be de 5f 52 08 33 b0 e1 1d 7b 45 9e 5d 17 |.W.._R.3...{E.].|
+00000350 41 2c 10 43 44 18 84 38 f3 0b 6a a1 76 bf 75 c9 |A,.CD..8..j.v.u.|
+00000360 56 b2 53 4c 98 39 c0 6f 30 13 96 8a 27 59 12 03 |V.SL.9.o0...'Y..|
+00000370 60 64 ce 28 54 c0 03 f4 c4 d1 df 94 e3 6e 43 61 |`d.(T........nCa|
+00000380 fa 43 40 e5 05 3b 26 dc c4 41 bd 73 c3 9e a0 db |.C@..;&..A.s....|
+00000390 fb c9 50 b4 4a d9 2d 71 cf e8 ff 3d 17 9e 29 35 |..P.J.-q...=..)5|
+000003a0 61 6c ab 11 ac 21 fa 90 6b 75 1f 0a 9d 30 3f 13 |al...!..ku...0?.|
+000003b0 fa c3 97 7a 74 16 03 03 00 4a 3d ca 3b 3d c8 6f |...zt....J=.;=.o|
+000003c0 44 4e 53 3d 05 27 97 aa bd 58 33 d6 ad 4a 34 71 |DNS=.'...X3..J4q|
+000003d0 22 d9 36 96 17 a5 ba 6b b3 20 2e da 64 65 14 c7 |".6....k. ..de..|
+000003e0 6a c7 07 39 55 db bb ad e2 49 84 09 5e 78 88 b5 |j..9U....I..^x..|
+000003f0 4b d5 23 fa 17 c5 f2 b8 2a c6 e5 1e 15 47 01 36 |K.#.....*....G.6|
+00000400 ef 7f 0a 14 16 03 03 00 14 28 e3 58 7e b9 36 d6 |.........(.X~.6.|
+00000410 ef 65 c8 bc fb 10 57 3d 48 70 7f 68 7d |.e....W=Hp.h}|
+>>> Flow 9 (client to server)
+00000000 16 03 03 02 69 d8 c1 81 7e a9 d7 70 97 62 c7 68 |....i...~..p.b.h|
+00000010 df 02 01 9d cc dc 38 d0 d6 bb 48 03 1d 0b be 73 |......8...H....s|
+00000020 b3 1a 88 91 a0 1b 55 91 51 a5 d7 54 58 c4 ea 50 |......U.Q..TX..P|
+00000030 e5 67 b1 60 78 b6 e2 7f d7 6c b4 76 d7 24 fd af |.g.`x....l.v.$..|
+00000040 f6 68 90 8c de 71 cd 15 4f d0 c8 f6 ba 89 ce 05 |.h...q..O.......|
+00000050 be 35 e8 9e 7a 8b 8d 0d 23 d4 5a bd 3a 9e d0 bf |.5..z...#.Z.:...|
+00000060 80 08 f5 ad 7d 84 f1 8a 16 de 97 6b b2 75 8e 49 |....}......k.u.I|
+00000070 0f d7 8b 10 57 f7 21 1f c0 87 de 06 c5 ae ae dd |....W.!.........|
+00000080 9c 22 92 a1 6c c7 46 8d e2 be 43 32 9c be 47 6b |."..l.F...C2..Gk|
+00000090 4d 2a 60 f0 b6 3a 09 16 d6 16 a1 92 4a 2d 2d 72 |M*`..:......J--r|
+000000a0 00 8f 40 7c 3e a9 61 be 35 c8 f8 48 b4 1c 90 61 |..@|>.a.5..H...a|
+000000b0 90 c5 aa f8 ae aa d4 8a 15 74 b2 5d aa 24 cf 45 |.........t.].$.E|
+000000c0 ef 02 bd 29 b9 50 b4 fe 83 05 fa 4a a5 82 10 28 |...).P.....J...(|
+000000d0 b7 ab c3 ca c3 65 bb 51 a4 7c ac 57 03 78 28 e3 |.....e.Q.|.W.x(.|
+000000e0 91 9f c1 ce 02 08 70 84 8c 11 1f ae 35 a5 06 12 |......p.....5...|
+000000f0 f8 78 5b 38 0a 11 c8 1c 2d 1b 0c 21 66 d9 41 b2 |.x[8....-..!f.A.|
+00000100 ed 66 3c 47 f2 dc ab c1 59 7d 65 df bb 80 37 1c |.f<G....Y}e...7.|
+00000110 5e 9b 41 e1 1d 5f b5 24 e4 77 61 3b e8 36 93 03 |^.A.._.$.wa;.6..|
+00000120 6d 87 17 e9 d7 77 35 b1 83 a3 b9 80 4d 40 20 82 |m....w5.....M@ .|
+00000130 94 36 53 94 ad 6b b3 ad 0a 70 fd 11 ce 81 56 ca |.6S..k...p....V.|
+00000140 c2 5d 16 69 e3 59 7e 37 3b cd f3 54 1e b8 5e 1a |.].i.Y~7;..T..^.|
+00000150 64 3f bf c6 ba ff fa b5 bf 4b c2 8e 5a 4d 43 1f |d?.......K..ZMC.|
+00000160 8e 50 bc 7a 82 13 c7 25 aa b4 a8 97 45 49 12 25 |.P.z...%....EI.%|
+00000170 f5 4d 52 df 90 e5 74 0f a0 d2 fd c3 6f bd 41 ed |.MR...t.....o.A.|
+00000180 ff 78 e8 97 f2 e2 d1 5b 7c e6 27 01 16 27 1d b6 |.x.....[|.'..'..|
+00000190 8a cf c6 5b 8d b3 d8 8e 0c ee 2a d5 21 f6 4b d3 |...[......*.!.K.|
+000001a0 5a 74 7e 3d c6 fb 0e 35 97 de e7 52 c0 b2 c3 37 |Zt~=...5...R...7|
+000001b0 94 28 41 e0 3b 65 56 f1 4f 60 03 48 88 1d db fc |.(A.;eV.O`.H....|
+000001c0 60 9f 33 e1 4d 37 eb 22 36 b2 76 ae 1c 3d 1c 5e |`.3.M7."6.v..=.^|
+000001d0 3a c5 5b 00 eb 72 8b 54 ba 76 d1 71 77 5f 76 54 |:.[..r.T.v.qw_vT|
+000001e0 5f fd 0e d1 3a 50 ad b1 55 4a db 6d bf 2f 33 90 |_...:P..UJ.m./3.|
+000001f0 fc 42 de cd e4 a9 dd 11 25 d1 9f 56 1e 8a 2b 5c |.B......%..V..+\|
+00000200 6c ed e7 51 84 42 6b ab 7d 77 b4 95 c3 75 b3 24 |l..Q.Bk.}w...u.$|
+00000210 ce 70 b0 e1 63 7f ec b0 ea 6a a4 a1 d5 e8 3e 96 |.p..c....j....>.|
+00000220 65 99 40 46 73 c8 e1 6e 86 65 92 bf 3d 92 a3 4f |e.@Fs..n.e..=..O|
+00000230 37 6d bb 80 33 a5 7d aa d3 a9 37 77 a6 4e 5b d6 |7m..3.}...7w.N[.|
+00000240 f3 f9 b2 42 75 18 1f 5a 58 f3 08 35 bc f4 2b 93 |...Bu..ZX..5..+.|
+00000250 62 0b 8a 83 f9 44 d0 e1 1a 44 b2 66 45 6f de b3 |b....D...D.fEo..|
+00000260 d2 ec 34 ac 15 89 76 b4 da dd 95 ca 44 5b 16 03 |..4...v.....D[..|
+00000270 03 00 35 39 e8 06 21 47 85 b5 53 96 03 0b 08 3b |..59..!G..S....;|
+00000280 d2 9d 55 1f 23 4f 3a c0 be 4f e0 e0 0a f1 65 6f |..U.#O:..O....eo|
+00000290 78 22 c4 10 6b d0 96 dc 04 78 e8 d3 95 f6 9a 78 |x"..k....x.....x|
+000002a0 09 f2 42 d3 79 57 99 c4 16 03 03 00 98 37 6b 75 |..B.yW.......7ku|
+000002b0 79 17 fa 67 7f 94 2e aa 88 61 91 97 dc 10 1e e6 |y..g.....a......|
+000002c0 6d 6d fa d5 64 17 f4 ec ba 01 43 99 88 e2 a7 13 |mm..d.....C.....|
+000002d0 e0 9e 6a e9 97 c7 b3 ec b9 c9 72 51 3d 01 eb c0 |..j.......rQ=...|
+000002e0 03 0f 08 48 90 27 36 6b bd e7 0d 4e 41 6a ef 11 |...H.'6k...NAj..|
+000002f0 42 5b ae d1 16 ec 8f b7 47 a2 f5 b4 6a d4 32 bb |B[......G...j.2.|
+00000300 0c cc 4f 2a e0 be 44 47 c8 77 09 f5 78 4b d6 ec |..O*..DG.w..xK..|
+00000310 87 95 dc e1 74 75 54 af 45 bb 7a f5 2e f7 ac 3d |....tuT.E.z....=|
+00000320 d1 b2 31 5a c0 24 c7 7c 25 36 62 a7 48 73 66 44 |..1Z.$.|%6b.HsfD|
+00000330 c1 78 47 f3 48 c5 a0 f7 66 3e 78 27 2c 3c dc 83 |.xG.H...f>x',<..|
+00000340 f5 6c e1 09 31 14 03 03 00 11 79 32 99 fd 2d 8d |.l..1.....y2..-.|
+00000350 14 33 fd 1b 1b a8 3d 99 4b 0a b7 16 03 03 00 20 |.3....=.K...... |
+00000360 76 25 53 83 f2 c5 bf a6 fa 2e d3 5a 62 67 5b 1d |v%S........Zbg[.|
+00000370 23 9a 9c b3 16 01 3f 6a e9 4c ea e1 d4 d1 09 42 |#.....?j.L.....B|
+>>> Flow 10 (server to client)
+00000000 14 03 03 00 11 a7 38 2a 4e 04 a5 b7 df d6 05 bb |......8*N.......|
+00000010 b5 93 38 bc 9e 62 16 03 03 00 20 f3 d3 e1 7d 80 |..8..b.... ...}.|
+00000020 41 ce 05 99 92 c7 47 fe b5 08 3b 78 9d ae b0 5f |A.....G...;x..._|
+00000030 2c ed bd 0b 90 e0 94 9e 0b b0 a5 17 03 03 00 19 |,...............|
+00000040 27 f0 6a 55 af 3f c1 82 85 1a 6b 28 e1 cd dc 59 |'.jU.?....k(...Y|
+00000050 43 be c7 18 16 30 08 b2 9e 16 03 03 00 14 c1 c5 |C....0..........|
+00000060 64 ef 72 4f 6c 96 f1 f6 5b 70 29 e4 59 36 0a cd |d.rOl...[p).Y6..|
+00000070 d2 a3 |..|
+>>> Flow 11 (client to server)
+00000000 15 03 03 00 12 af 73 0e 40 39 dd 1e 04 99 3e 10 |......s.@9....>.|
+00000010 c9 62 b3 78 77 9b 56 15 03 03 00 12 25 8b 87 29 |.b.xw.V.....%..)|
+00000020 82 d0 9f 5e 9a 27 bd c1 bf b7 a2 f0 92 ac |...^.'........|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected b/src/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected
new file mode 100644
index 0000000..f7a7668
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-RenegotiationRejected
@@ -0,0 +1,95 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 a3 55 d2 e2 bd |....Y...U...U...|
+00000010 94 8f 04 51 26 1c a6 61 b1 ed 05 e2 39 44 33 05 |...Q&..a....9D3.|
+00000020 79 14 b7 1f 89 1e bb ba 53 0d 12 20 09 29 6d 26 |y.......S.. .)m&|
+00000030 04 70 4a 5d 01 90 f2 c6 28 df 11 6a 64 23 ec 9e |.pJ]....(..jd#..|
+00000040 9f 2b 15 33 dc 88 26 35 3a b0 86 92 cc a8 00 00 |.+.3..&5:.......|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 43 6b 44 5b 79 c9 38 |........ CkD[y.8|
+000002d0 dc e4 ab fa 88 fa e6 06 89 b1 4e ff ab 8d d6 f7 |..........N.....|
+000002e0 21 b4 ff 9d a0 c8 54 cc 63 08 04 00 80 cd f4 d6 |!.....T.c.......|
+000002f0 c8 ad 03 e7 f0 e8 f4 c9 f0 e6 28 db cd 3b 7c bf |..........(..;|.|
+00000300 05 af 3d fe c1 f9 f1 7a ec 41 bf 1f a8 95 6d ee |..=....z.A....m.|
+00000310 e6 92 cb c0 ff fd c1 ed 86 b0 59 45 3e 2d 1d 66 |..........YE>-.f|
+00000320 56 d1 9f e2 b7 79 ac aa 81 6d b0 42 36 96 80 4d |V....y...m.B6..M|
+00000330 ca 36 29 1b 65 03 73 3f 85 ec 59 cb b4 a5 a0 c0 |.6).e.s?..Y.....|
+00000340 0c 16 ad e2 6b 35 3c ab 1e da 69 19 7d a2 63 a7 |....k5<...i.}.c.|
+00000350 69 2a d2 3f 12 17 bf 4c ed 8a f7 75 fe ce d4 2b |i*.?...L...u...+|
+00000360 4d 35 bf 65 d6 9e 01 69 a8 0a 73 26 34 16 03 03 |M5.e...i..s&4...|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 b8 d8 22 20 8d 69 23 05 34 eb 69 |.... .." .i#.4.i|
+00000040 92 a0 a9 6c cd 94 3b 72 49 91 72 8e 65 79 ca 62 |...l..;rI.r.ey.b|
+00000050 14 cf da 2e b6 |.....|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 31 25 d4 c7 92 |.......... 1%...|
+00000010 16 0b 92 2d a2 20 8b b2 c7 96 a6 b7 b6 b3 82 3a |...-. .........:|
+00000020 4d a1 a8 96 29 fb 99 e9 ea 04 6c |M...).....l|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 8b 92 f3 f8 99 bf a3 7c c4 03 d8 |............|...|
+00000010 4d e7 1b ad 50 e1 99 17 33 68 e2 |M...P...3h.|
+>>> Flow 6 (server to client)
+00000000 16 03 03 00 14 91 99 15 68 ae 92 52 bd 13 75 45 |........h..R..uE|
+00000010 6d a9 f0 2d ee f5 c3 9b e7 |m..-.....|
+>>> Flow 7 (client to server)
+00000000 15 03 03 00 12 be 8b 4b a6 a7 7a 62 45 32 ff db |.......K..zbE2..|
+00000010 07 ad a0 1b 46 9d c9 15 03 03 00 12 16 da d4 86 |....F...........|
+00000020 4f c8 26 5a d0 34 82 fe 47 34 ae 31 db a7 |O.&Z.4..G4.1..|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-SCT b/src/crypto/tls/testdata/Client-TLSv12-SCT
new file mode 100644
index 0000000..8492ee9
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-SCT
@@ -0,0 +1,113 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 01 c6 02 00 01 c2 03 03 b0 59 eb bc ae |............Y...|
+00000010 f3 42 03 d1 fe 2c 7d 6f 0e ff e4 0c 9e 13 00 b9 |.B...,}o........|
+00000020 46 99 e2 84 49 64 a9 05 05 8a fb 20 16 12 dc b7 |F...Id..... ....|
+00000030 e0 09 a2 a6 56 83 43 54 de 40 53 47 43 f0 2f c9 |....V.CT.@SGC./.|
+00000040 2d 92 5e a0 9d a3 6a c4 55 17 01 cb cc a8 00 01 |-.^...j.U.......|
+00000050 7a 00 12 01 69 01 67 00 75 00 a4 b9 09 90 b4 18 |z...i.g.u.......|
+00000060 58 14 87 bb 13 a2 cc 67 70 0a 3c 35 98 04 f9 1b |X......gp.<5....|
+00000070 df b8 e3 77 cd 0e c8 0d dc 10 00 00 01 47 97 99 |...w.........G..|
+00000080 ee 16 00 00 04 03 00 46 30 44 02 20 1c 4b 82 5d |.......F0D. .K.]|
+00000090 95 6e 67 5b db 04 95 4b f6 ce f4 32 3e 86 7a 7a |.ng[...K...2>.zz|
+000000a0 32 ab 18 60 74 de 08 da 05 91 4c 2f 02 20 73 54 |2..`t.....L/. sT|
+000000b0 1b 6e 7f a1 b0 7d 11 bc e6 f3 85 2f 97 66 1a f7 |.n...}...../.f..|
+000000c0 8a e4 10 25 8f 12 f4 6f 39 0f d2 9e 18 f0 00 76 |...%...o9......v|
+000000d0 00 68 f6 98 f8 1f 64 82 be 3a 8c ee b9 28 1d 4c |.h....d..:...(.L|
+000000e0 fc 71 51 5d 67 93 d4 44 d1 0a 67 ac bb 4f 4f fb |.qQ]g..D..g..OO.|
+000000f0 c4 00 00 01 47 97 e1 b5 70 00 00 04 03 00 47 30 |....G...p.....G0|
+00000100 45 02 20 32 21 14 38 06 d8 72 2e 00 30 64 1a e2 |E. 2!.8..r..0d..|
+00000110 e8 6d 4e 5a e1 d9 42 1e 82 4b 96 25 89 d5 26 13 |.mNZ..B..K.%..&.|
+00000120 d3 9c fa 02 21 00 8f 12 28 64 51 4f 44 d5 8c 18 |....!...(dQOD...|
+00000130 62 23 b2 43 93 33 05 f3 43 55 a1 d9 ee cd c5 71 |b#.C.3..CU.....q|
+00000140 35 91 dd 49 d1 0b 00 76 00 ee 4b bd b7 75 ce 60 |5..I...v..K..u.`|
+00000150 ba e1 42 69 1f ab e1 9e 66 a3 0f 7e 5f b0 72 d8 |..Bi....f..~_.r.|
+00000160 83 00 c4 7b 89 7a a8 fd cb 00 00 01 48 5c 64 8a |...{.z......H\d.|
+00000170 87 00 00 04 03 00 47 30 45 02 20 29 89 d6 b0 53 |......G0E. )...S|
+00000180 d3 d2 e9 91 bc f1 b5 40 be 1e 2e e7 5c b4 74 27 |.......@....\.t'|
+00000190 ed 8f 9b 02 e9 fa c2 4c ba a2 be 02 21 00 af 43 |.......L....!..C|
+000001a0 64 52 71 15 29 58 40 91 c7 08 16 96 03 a8 73 a5 |dRq.)X@.......s.|
+000001b0 65 a0 6c b8 48 56 5a b6 29 83 64 6d 2a 9d ff 01 |e.l.HVZ.).dm*...|
+000001c0 00 01 00 00 0b 00 04 03 00 01 02 16 03 03 02 59 |...............Y|
+000001d0 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 |...U..R..O0..K0.|
+000001e0 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b |.............?.[|
+000001f0 ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 |..0...*.H.......|
+00000200 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |.0.1.0...U....Go|
+00000210 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f |1.0...U....Go Ro|
+00000220 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 |ot0...1601010000|
+00000230 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 |00Z..25010100000|
+00000240 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 |0Z0.1.0...U....G|
+00000250 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 |o1.0...U....Go0.|
+00000260 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 |.0...*.H........|
+00000270 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e |....0.......F}..|
+00000280 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e |.'.H..(!.~...]..|
+00000290 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be |RE.z6G....B[....|
+000002a0 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 |.y.@.Om..+.....g|
+000002b0 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 |....."8.J.ts+.4.|
+000002c0 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 |.....t{.X.la<..A|
+000002d0 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 |..++$#w[.;.u]. T|
+000002e0 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 |..c...$....P....|
+000002f0 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 |C...ub...R......|
+00000300 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff |...0..0...U.....|
+00000310 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 |......0...U.%..0|
+00000320 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 |...+.........+..|
+00000330 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 |.....0...U......|
+00000340 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 |.0.0...U........|
+00000350 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b |..CC>I..m....`0.|
+00000360 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 |..U.#..0...H.IM.|
+00000370 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 |~.1......n{0...U|
+00000380 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e |....0...example.|
+00000390 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d |golang0...*.H...|
+000003a0 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 |..........0.@+[P|
+000003b0 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 |.a...SX...(.X..8|
+000003c0 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 |....1Z..f=C.-...|
+000003d0 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 |... d8.$:....}.@|
+000003e0 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c | ._...a..v......|
+000003f0 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c |\.....l..s..Cw..|
+00000400 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 |.....@.a.Lr+...F|
+00000410 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 |..M...>...B...=.|
+00000420 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c 00 |`.\!.;..........|
+00000430 00 a8 03 00 1d 20 4c 46 c9 9f ed 2e 81 0f 8c 4b |..... LF.......K|
+00000440 bc 05 53 74 c6 c8 76 99 21 94 1b 8f 93 c6 64 ce |..St..v.!.....d.|
+00000450 e9 9d 6b 1d 66 51 08 04 00 80 09 9e c2 21 89 93 |..k.fQ.......!..|
+00000460 1f c5 2e 2c fa 67 7b 42 23 e1 e0 67 5c 6d e9 1e |...,.g{B#..g\m..|
+00000470 e8 a2 ac d7 cf f4 12 98 f6 e6 3d 51 0c 2c 29 ad |..........=Q.,).|
+00000480 f8 8e 24 2a a3 99 2e f3 b2 a7 fe a9 6c e9 00 d8 |..$*........l...|
+00000490 6a 7f 41 12 84 a0 d6 19 38 b1 5a 13 b6 71 cf bd |j.A.....8.Z..q..|
+000004a0 e2 6e 04 01 c8 cd 83 12 71 85 ae bc 94 b1 e4 4d |.n......q......M|
+000004b0 a5 5f 9e a5 5d 95 76 fe f5 d6 a9 f0 4c 07 c9 6e |._..].v.....L..n|
+000004c0 fc 4a 56 2b 56 4e 9c ec 2c fe bc 9c 9e 57 f3 90 |.JV+VN..,....W..|
+000004d0 c6 6e 77 5a cf 8c 1a 15 cd 90 16 03 03 00 04 0e |.nwZ............|
+000004e0 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 20 19 bf ac 05 d4 bb 8a 6d 11 f4 98 |.... .......m...|
+00000040 0d af 78 57 49 74 5c 44 45 9e 2c 92 26 b9 10 b5 |..xWIt\DE.,.&...|
+00000050 6d 5f 24 bc a6 |m_$..|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 69 3a c4 9c ee |.......... i:...|
+00000010 91 6b bc 33 39 82 64 c2 0a f0 a4 dd 85 16 3c ce |.k.39.d.......<.|
+00000020 39 c4 98 37 77 47 1e c2 c6 d8 f6 |9..7wG.....|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 92 25 9b 97 11 08 71 63 b2 c1 35 |......%....qc..5|
+00000010 14 3b e7 15 f6 05 67 51 46 db ba 15 03 03 00 12 |.;....gQF.......|
+00000020 b2 53 a1 ec a8 cf 79 7d f8 86 70 05 e5 81 a1 6c |.S....y}..p....l|
+00000030 41 ab |A.|
diff --git a/src/crypto/tls/testdata/Client-TLSv12-X25519-ECDHE b/src/crypto/tls/testdata/Client-TLSv12-X25519-ECDHE
new file mode 100644
index 0000000..3d3de61
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv12-X25519-ECDHE
@@ -0,0 +1,92 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 f4 01 00 00 f0 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 75 00 05 00 05 01 00 00 00 00 00 0a 00 |...u............|
+00000090 04 00 02 00 1d 00 0b 00 02 01 00 00 0d 00 1a 00 |................|
+000000a0 18 08 04 04 03 08 07 08 05 08 06 04 01 05 01 06 |................|
+000000b0 01 05 03 06 03 02 01 02 03 ff 01 00 01 00 00 12 |................|
+000000c0 00 00 00 2b 00 09 08 03 04 03 03 03 02 03 01 00 |...+............|
+000000d0 33 00 26 00 24 00 1d 00 20 2f e5 7d a3 47 cd 62 |3.&.$... /.}.G.b|
+000000e0 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......|
+000000f0 c2 ed 90 99 5f 58 cb 3b 74 |...._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 59 02 00 00 55 03 03 f7 79 97 18 3c |....Y...U...y..<|
+00000010 fa 52 c6 d2 6b 1e de a5 60 da d5 e2 0b f6 23 a8 |.R..k...`.....#.|
+00000020 48 94 e8 1f fb b9 76 43 94 e8 98 20 31 a5 85 d5 |H.....vC... 1...|
+00000030 2f c4 93 b1 ae aa 50 bc 14 9e 57 79 18 85 cd ef |/.....P...Wy....|
+00000040 b4 f0 42 c9 6c b1 86 c1 03 27 ca df c0 2f 00 00 |..B.l....'.../..|
+00000050 0d ff 01 00 01 00 00 0b 00 04 03 00 01 02 16 03 |................|
+00000060 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 |..Y...U..R..O0..|
+00000070 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d |K0..............|
+00000080 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 |?.[..0...*.H....|
+00000090 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 |....0.1.0...U...|
+000000a0 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f |.Go1.0...U....Go|
+000000b0 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 | Root0...1601010|
+000000c0 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 |00000Z..25010100|
+000000d0 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a |0000Z0.1.0...U..|
+000000e0 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 |..Go1.0...U....G|
+000000f0 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |o0..0...*.H.....|
+00000100 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 |.......0.......F|
+00000110 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 |}...'.H..(!.~...|
+00000120 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 |]..RE.z6G....B[.|
+00000130 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 |....y.@.Om..+...|
+00000140 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b |..g....."8.J.ts+|
+00000150 c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c |.4......t{.X.la<|
+00000160 c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d |..A..++$#w[.;.u]|
+00000170 ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b |. T..c...$....P.|
+00000180 aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 |...C...ub...R...|
+00000190 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f |......0..0...U..|
+000001a0 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 |.........0...U.%|
+000001b0 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 |..0...+.........|
+000001c0 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 |+.......0...U...|
+000001d0 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 |....0.0...U.....|
+000001e0 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f |.....CC>I..m....|
+000001f0 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 |`0...U.#..0...H.|
+00000200 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 |IM.~.1......n{0.|
+00000210 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 |..U....0...examp|
+00000220 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 |le.golang0...*.H|
+00000230 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 |.............0.@|
+00000240 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 |+[P.a...SX...(.X|
+00000250 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d |..8....1Z..f=C.-|
+00000260 d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c |...... d8.$:....|
+00000270 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 |}.@ ._...a..v...|
+00000280 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 |...\.....l..s..C|
+00000290 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d |w.......@.a.Lr+.|
+000002a0 ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db |..F..M...>...B..|
+000002b0 fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 |.=.`.\!.;.......|
+000002c0 ac 0c 00 00 a8 03 00 1d 20 90 95 bd 82 cf 8a cc |........ .......|
+000002d0 08 b4 09 09 8d 59 2d 03 7a bb 92 4a c4 5c 08 4d |.....Y-.z..J.\.M|
+000002e0 42 a3 ba cb 9a 43 ae f0 22 08 04 00 80 a0 97 ac |B....C..".......|
+000002f0 01 a5 c8 7b 4c 73 7e 70 7a 9a fc 9d 71 2f fe 67 |...{Ls~pz...q/.g|
+00000300 ca dd 6b 43 db 64 0f 64 52 e7 d3 5d 6d b2 7c 50 |..kC.d.dR..]m.|P|
+00000310 74 7e 80 d5 22 77 3f fb c2 e8 dc 92 37 4f 1e 1e |t~.."w?.....7O..|
+00000320 e7 13 f2 01 33 80 32 66 4f c2 17 8e ec 4f ed 4a |....3.2fO....O.J|
+00000330 15 6c e8 86 ec df d5 46 6c a5 43 0d 40 fe a0 c8 |.l.....Fl.C.@...|
+00000340 65 b4 76 46 b8 36 2c da 87 7c 60 87 db 39 4c 2e |e.vF.6,..|`..9L.|
+00000350 0f e4 72 32 11 26 99 7e c8 7a c0 bc 9c a7 29 57 |..r2.&.~.z....)W|
+00000360 9d 27 37 4e ec c5 bb fd a1 3c f3 66 63 16 03 03 |.'7N.....<.fc...|
+00000370 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 2f e5 7d a3 47 cd |....%...! /.}.G.|
+00000010 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+00000020 cf c2 ed 90 99 5f 58 cb 3b 74 14 03 03 00 01 01 |....._X.;t......|
+00000030 16 03 03 00 28 00 00 00 00 00 00 00 00 81 b1 2c |....(..........,|
+00000040 a2 3b 38 34 a6 66 57 02 e3 67 1b ee 73 95 50 de |.;84.fW..g..s.P.|
+00000050 dd 5a fd 4e 0d ee b7 a6 46 1a 34 61 73 |.Z.N....F.4as|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 2f a9 80 36 d8 |..........(/..6.|
+00000010 d0 74 e4 39 46 04 88 8e 91 ea fd 96 ed 1f 89 9f |.t.9F...........|
+00000020 a4 e9 24 0e ca 48 2b 5c 5d f1 cc 57 ce 92 1a ad |..$..H+\]..W....|
+00000030 b9 10 11 |...|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 1e 00 00 00 00 00 00 00 01 da be 68 |...............h|
+00000010 97 b4 a4 72 d0 ed 75 66 6a a9 6f 39 8a 08 a9 db |...r..ufj.o9....|
+00000020 de 4d e1 15 03 03 00 1a 00 00 00 00 00 00 00 02 |.M..............|
+00000030 14 90 0e 1d 26 5c 18 c6 5c 93 66 c4 90 78 a8 91 |....&\..\.f..x..|
+00000040 cb fd |..|
diff --git a/src/crypto/tls/testdata/Client-TLSv13-AES128-SHA256 b/src/crypto/tls/testdata/Client-TLSv13-AES128-SHA256
new file mode 100644
index 0000000..f8a733e
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv13-AES128-SHA256
@@ -0,0 +1,90 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 f1 4c f4 16 24 |....z...v...L..$|
+00000010 e5 c6 b5 ce 72 08 3b 33 9f 1f 1f 80 2c 10 0b 34 |....r.;3....,..4|
+00000020 01 99 85 ba b0 3c 85 50 3d bf 73 20 00 00 00 00 |.....<.P=.s ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 01 00 00 |................|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 69 |..+.....3.$... i|
+00000060 94 3b 83 cd 1f 93 53 53 82 de 14 cb 76 2a 19 62 |.;....SS....v*.b|
+00000070 0f f8 9e d1 e3 e0 a9 d5 23 ac 07 64 53 27 4b 14 |........#..dS'K.|
+00000080 03 03 00 01 01 17 03 03 00 17 ef 24 2c ea 6f 05 |...........$,.o.|
+00000090 c2 07 7a d2 12 30 ce 01 f4 96 b8 dc e6 c2 27 02 |..z..0........'.|
+000000a0 bd 17 03 03 02 6d 99 2b cb 79 43 01 66 24 eb f1 |.....m.+.yC.f$..|
+000000b0 14 d2 ea 1e 57 67 81 e3 a0 9c 99 1b 1f d5 f0 c7 |....Wg..........|
+000000c0 78 48 61 01 42 25 85 0b cd a1 b1 75 3c 50 01 cc |xHa.B%.....u<P..|
+000000d0 69 09 22 a5 fb db 43 76 2f 4e 34 4e 14 a3 e4 89 |i."...Cv/N4N....|
+000000e0 f7 d7 cd 66 da b3 1d fd f0 98 60 18 41 09 a5 22 |...f......`.A.."|
+000000f0 6d c9 21 bc c3 cd 53 ca c3 a5 d7 24 57 b4 f5 bc |m.!...S....$W...|
+00000100 ec b1 48 70 12 55 a5 a6 01 10 68 0f c4 e5 de 89 |..Hp.U....h.....|
+00000110 f9 0d ab 48 92 d4 12 d7 75 77 c3 2f ae 2f 6f 58 |...H....uw././oX|
+00000120 2d 6e ad 72 43 dc ce 4b c9 74 3d eb db da 37 2c |-n.rC..K.t=...7,|
+00000130 1e a2 86 c4 b3 64 69 f6 84 ce 52 b5 32 c6 b9 c2 |.....di...R.2...|
+00000140 49 2d 08 f9 d4 9a 29 09 5b 71 09 81 a3 19 c2 4d |I-....).[q.....M|
+00000150 8c 48 2c e3 c6 cb 81 d4 7f 10 b3 c8 2b 21 ad 83 |.H,.........+!..|
+00000160 97 d2 bd 11 90 39 1e f4 de 65 e2 e8 e8 c7 ce f9 |.....9...e......|
+00000170 6d ad b0 60 5c 4b 59 c4 96 ce b3 a1 83 b2 7c 71 |m..`\KY.......|q|
+00000180 74 e6 a9 a7 89 bf 8d 0d 6c 8d b5 04 33 38 ff 68 |t.......l...38.h|
+00000190 42 0e 84 da d2 b2 16 29 83 66 82 a9 2a d2 67 1b |B......).f..*.g.|
+000001a0 18 a6 7d e3 f1 d3 f1 b4 cc 6c 14 e2 cd 2d 96 7b |..}......l...-.{|
+000001b0 76 dd b0 1d 24 7f ea c0 14 24 d7 37 00 7c cd e3 |v...$....$.7.|..|
+000001c0 20 33 a4 3a 22 2a be 3e e8 f8 7c 0d 3e 51 f7 6b | 3.:"*.>..|.>Q.k|
+000001d0 ce f3 51 cf 7e ae 55 40 bb ab 0e 40 6b d9 8a 3b |..Q.~.U@...@k..;|
+000001e0 d5 f2 1f 76 6a 05 9b 87 e2 3b db fa cc e8 93 8a |...vj....;......|
+000001f0 d9 ba 2b 63 77 77 62 f1 22 ce 11 a9 26 b5 e8 a2 |..+cwwb."...&...|
+00000200 ec 3f 98 44 01 27 d7 e1 39 26 33 e3 86 00 60 f7 |.?.D.'..9&3...`.|
+00000210 a7 91 07 45 f8 3f 78 dc 88 71 30 26 0c f9 0d 51 |...E.?x..q0&...Q|
+00000220 2a c5 ce 33 ac b7 91 a9 74 2e 46 68 80 6e 62 cd |*..3....t.Fh.nb.|
+00000230 2d 5e 43 fe bd d1 37 07 71 85 5d c7 38 17 50 3a |-^C...7.q.].8.P:|
+00000240 1c 5e 9f cf 1e 3c 96 d0 26 5d 4c 82 78 a8 69 e7 |.^...<..&]L.x.i.|
+00000250 d3 9a 81 e5 85 66 c3 d9 74 a1 82 9d fb 24 81 13 |.....f..t....$..|
+00000260 0d ce cb 43 61 3c 3a a7 d1 80 7f 1d 41 d8 62 43 |...Ca<:.....A.bC|
+00000270 c6 08 5d 91 05 ed 2c 50 04 42 8c db 2a 11 61 96 |..]...,P.B..*.a.|
+00000280 9b d2 1d 40 af 83 ed 93 06 ba 65 22 0a a5 e8 a6 |...@......e"....|
+00000290 b9 4a 63 6f c0 ac da 72 10 24 c6 ed 08 86 c8 a1 |.Jco...r.$......|
+000002a0 92 5e d0 d8 8b 04 b7 43 50 0b 03 41 3f f9 96 16 |.^.....CP..A?...|
+000002b0 a3 c8 09 e8 ac 91 b2 45 d5 58 5f 41 05 7c b3 88 |.......E.X_A.|..|
+000002c0 7a 59 cd 1a 00 86 29 72 77 a5 19 43 32 79 fc d6 |zY....)rw..C2y..|
+000002d0 d7 e9 81 08 e3 d9 d9 56 39 59 7c 1e d3 10 3e a4 |.......V9Y|...>.|
+000002e0 c6 80 d3 8b 9b 36 51 c5 d3 14 64 a6 65 e2 1a 26 |.....6Q...d.e..&|
+000002f0 c4 a8 31 07 bb 58 8c 9b d8 7d 86 fd 54 6c c9 ae |..1..X...}..Tl..|
+00000300 7d 88 4b 13 0f 52 10 41 d6 be 01 32 f2 42 47 0f |}.K..R.A...2.BG.|
+00000310 7a 8c 7e 17 03 03 00 99 8b ce c4 db 9c 9c 88 e3 |z.~.............|
+00000320 88 58 de 8f 10 e9 fb 4a c7 26 96 60 48 84 2c b1 |.X.....J.&.`H.,.|
+00000330 2b 6c 35 70 8a d7 39 91 51 d7 3f db 81 f0 41 07 |+l5p..9.Q.?...A.|
+00000340 a2 c9 c1 74 76 62 58 f1 cb e2 50 48 57 bb 6e 3d |...tvbX...PHW.n=|
+00000350 ee ee 4a 53 e7 3c 66 aa e3 d9 c1 f1 74 1a 93 b9 |..JS.<f.....t...|
+00000360 44 90 f6 a5 a4 da f5 6b 75 01 38 52 8f 9c ab 01 |D......ku.8R....|
+00000370 78 88 a6 cc 65 15 61 a8 8c cc 14 59 07 ea 6f 25 |x...e.a....Y..o%|
+00000380 5c 86 89 16 eb e7 da 20 82 d7 96 e4 78 7a c3 36 |\...... ....xz.6|
+00000390 b3 5c e7 17 1b 07 30 a2 72 ca a2 f3 dc 7e 45 c9 |.\....0.r....~E.|
+000003a0 7f 94 f8 a1 7b bb 2a 30 d7 bc 51 03 fb e6 2a fa |....{.*0..Q...*.|
+000003b0 17 17 03 03 00 35 c1 a0 76 b6 35 4b 5c 26 94 c6 |.....5..v.5K\&..|
+000003c0 ba b1 7b b1 13 00 f2 2c 17 ed ac ab 47 9a a1 8d |..{....,....G...|
+000003d0 3a 1c 78 44 14 a1 04 31 3d eb 9a 8d bb 2f 73 46 |:.xD...1=..../sF|
+000003e0 cb 5c f6 86 81 fa 56 fb 39 8c 55 |.\....V.9.U|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 97 2c 39 3a a5 |..........5.,9:.|
+00000010 32 33 e5 74 43 97 98 ef ef 30 de 27 8b f7 b5 ab |23.tC....0.'....|
+00000020 dd af 87 7c a5 5e 76 cf 50 2a 03 f8 94 a4 7a df |...|.^v.P*....z.|
+00000030 14 0a 2d 39 57 3b 02 97 c5 d7 63 85 21 3f 55 27 |..-9W;....c.!?U'|
+00000040 17 03 03 00 17 7c b4 8b 82 f0 0a ec 6f fa 60 ef |.....|......o.`.|
+00000050 4c 0a 1c 0b ad 99 c3 89 fb a4 40 2c 17 03 03 00 |L.........@,....|
+00000060 13 f2 d5 58 ba 6b ca e8 f4 14 4c 66 23 38 f2 e8 |...X.k....Lf#8..|
+00000070 ea a9 ba c1 |....|
diff --git a/src/crypto/tls/testdata/Client-TLSv13-AES256-SHA384 b/src/crypto/tls/testdata/Client-TLSv13-AES256-SHA384
new file mode 100644
index 0000000..8ea3ed6
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv13-AES256-SHA384
@@ -0,0 +1,92 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 71 00 90 30 07 |....z...v..q..0.|
+00000010 24 01 ae 33 b2 e8 4f 1f 9a 2c 83 e5 7b 30 1e a2 |$..3..O..,..{0..|
+00000020 8e 4a d0 df d1 ec 23 b5 ba aa 75 20 00 00 00 00 |.J....#...u ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 02 00 00 |................|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 06 |..+.....3.$... .|
+00000060 2a 26 bd 81 c2 90 9b 17 6e d0 b5 ab 72 e6 93 ce |*&......n...r...|
+00000070 53 6d 8c 54 b5 a4 50 91 93 32 6e 88 e6 b2 69 14 |Sm.T..P..2n...i.|
+00000080 03 03 00 01 01 17 03 03 00 17 7d 11 37 f0 18 b1 |..........}.7...|
+00000090 53 55 38 bb 12 7c e8 b3 89 bc 35 fb 2a 36 d1 0f |SU8..|....5.*6..|
+000000a0 3a 17 03 03 02 6d a0 fa dc 8e ac a6 90 5a 20 0e |:....m.......Z .|
+000000b0 ee 22 89 7b 69 5b c9 1a a1 c6 43 b9 40 f6 85 78 |.".{i[....C.@..x|
+000000c0 61 0b 14 c6 e6 3b a9 ac 4c 7a 96 9b 7b 87 d0 ce |a....;..Lz..{...|
+000000d0 42 cc 75 9d fc 06 44 3e e8 12 3a 94 b7 de 86 c4 |B.u...D>..:.....|
+000000e0 b5 66 e1 f5 48 21 f7 f1 58 7f 23 6c 3f 76 a0 cb |.f..H!..X.#l?v..|
+000000f0 a7 f6 72 34 07 fa c1 55 3e 61 cf 72 c4 6c f1 ca |..r4...U>a.r.l..|
+00000100 dd dc ec 66 3d 7b f6 cf 53 3b 28 bd 27 1b aa a6 |...f={..S;(.'...|
+00000110 28 2a ab fa 48 a5 08 67 b5 49 c7 c7 5d f8 2c ec |(*..H..g.I..].,.|
+00000120 83 af 58 33 42 6c c1 4c 94 17 7e 36 1c a9 48 34 |..X3Bl.L..~6..H4|
+00000130 5f 26 78 f6 69 88 3a a5 1b d1 76 ad 88 63 25 33 |_&x.i.:...v..c%3|
+00000140 0d e3 d0 34 6b 7f fc 96 2b 8d 22 6f 3f 21 8a 14 |...4k...+."o?!..|
+00000150 01 e0 5c 54 6c c3 b8 12 f9 17 f5 4c ce e0 bd 10 |..\Tl......L....|
+00000160 e7 e1 29 24 73 94 c2 5e b0 ad d3 91 9e 87 ea 23 |..)$s..^.......#|
+00000170 4d fd 8f 12 ca 87 ff 2e 93 9f 16 a8 18 e1 66 8f |M.............f.|
+00000180 50 76 15 cd 70 5c a2 1d 91 51 e5 54 13 5f 73 d3 |Pv..p\...Q.T._s.|
+00000190 b2 6e b1 27 80 0b 3d 64 d5 fa f3 a4 fb 77 33 cb |.n.'..=d.....w3.|
+000001a0 ac 93 54 36 2d 71 c3 9e dd 37 02 a9 9d b0 9b ac |..T6-q...7......|
+000001b0 f8 c5 dc 43 9b d8 db c7 d0 fb cf 69 fa 62 e4 9d |...C.......i.b..|
+000001c0 b7 04 f8 49 d3 a7 8d bd cf 8a e3 4a 62 cb bb 29 |...I.......Jb..)|
+000001d0 b5 db 21 80 76 eb 28 67 34 1e 40 0b 83 83 19 10 |..!.v.(g4.@.....|
+000001e0 46 8f bd 78 d6 7c 05 c2 19 82 1c e8 7d 84 f2 79 |F..x.|......}..y|
+000001f0 c4 a6 e0 f7 7e df 70 7f 42 48 9f e4 99 03 7f 9e |....~.p.BH......|
+00000200 e8 fd 75 c3 8a 55 55 8e 08 2e 62 28 a5 16 b7 11 |..u..UU...b(....|
+00000210 d8 9a 11 48 46 ad d3 ba 4f 91 c8 fd 72 d9 df 98 |...HF...O...r...|
+00000220 1a 59 51 55 af ab 73 b9 f3 bf fe 7d 55 7d 44 54 |.YQU..s....}U}DT|
+00000230 cd bb f3 eb 6e ff 5a 09 e9 b9 c1 66 97 8e a5 7c |....n.Z....f...||
+00000240 89 4a 51 1d 8b e4 40 fb 97 ce ef 9d 7c 02 e4 db |.JQ...@.....|...|
+00000250 f1 ca 01 d9 05 b4 de 10 23 33 92 ff 26 3b 09 8f |........#3..&;..|
+00000260 11 7c 37 ad fb 58 ed 7a 10 08 fd df 98 dd d6 c5 |.|7..X.z........|
+00000270 b8 fd 59 37 21 1d 6e 27 8a 56 24 45 e7 64 61 0b |..Y7!.n'.V$E.da.|
+00000280 20 2d bc 79 89 fa 6d 7a 06 77 61 0c 60 25 e2 79 | -.y..mz.wa.`%.y|
+00000290 6a 54 9e 5b 4b 33 68 17 da 63 ba a7 f9 ad 2c 84 |jT.[K3h..c....,.|
+000002a0 52 e9 27 85 71 74 d2 5f c9 f8 8e 67 f7 47 58 f5 |R.'.qt._...g.GX.|
+000002b0 e4 72 a7 bd 1c 94 4b 4d 13 5a 62 69 d9 6f 3a 51 |.r....KM.Zbi.o:Q|
+000002c0 f0 18 90 e5 b6 21 23 97 70 74 93 ba 9b bc dc e4 |.....!#.pt......|
+000002d0 3d 9c 52 3f 93 f0 48 05 e8 50 d0 b4 98 92 7a 18 |=.R?..H..P....z.|
+000002e0 3f 39 ba f8 f7 ee 19 b0 ce ac d0 ab 9e 83 ee 0e |?9..............|
+000002f0 5d 2a 72 74 a8 8b 4d de 6b a9 91 ad b4 a4 26 99 |]*rt..M.k.....&.|
+00000300 4e aa 6d 48 77 83 78 78 be 96 f1 17 d6 96 74 4a |N.mHw.xx......tJ|
+00000310 80 d1 5b 17 03 03 00 99 d9 40 96 5c fb 5d 65 69 |..[......@.\.]ei|
+00000320 db 54 a8 f6 8c b7 d3 25 8d 2d c5 f1 40 5b f2 26 |.T.....%.-..@[.&|
+00000330 f3 86 9e 61 6a a5 b9 66 b1 27 b1 20 6b 2c 64 84 |...aj..f.'. k,d.|
+00000340 3f 48 24 5d d9 90 4b d1 ed 1b 0e 05 84 7f ad 0e |?H$]..K.........|
+00000350 e6 75 f6 f9 33 90 73 7c 88 10 d7 e9 74 41 4b c3 |.u..3.s|....tAK.|
+00000360 19 8e e1 a8 a6 7c 3c 9a bc 69 a7 e7 bb d6 af 98 |.....|<..i......|
+00000370 f1 49 53 14 95 80 d6 95 81 5a 5e 88 2c 29 70 df |.IS......Z^.,)p.|
+00000380 b2 df fe f3 17 03 e7 de af 12 57 c5 7a ef 70 eb |..........W.z.p.|
+00000390 8a c6 c3 05 de 5b 15 af 5f 54 8c 7b 23 b7 e1 f1 |.....[.._T.{#...|
+000003a0 30 b1 ed 34 4c 59 f5 68 c2 50 e8 c3 83 78 1d 1f |0..4LY.h.P...x..|
+000003b0 eb 17 03 03 00 45 1a d4 61 ba 4a a5 1e 02 80 04 |.....E..a.J.....|
+000003c0 2a 19 11 af 8c e9 bd ab 22 6b 75 41 a8 40 de 57 |*......."kuA.@.W|
+000003d0 54 8c dc 09 cc 57 76 82 27 5e 59 0c 30 f7 9d c4 |T....Wv.'^Y.0...|
+000003e0 fe 1c 09 f2 f4 5f e0 79 ac 02 06 80 f3 60 c4 92 |....._.y.....`..|
+000003f0 cd 6a df b6 46 7c de 90 8d bb 94 |.j..F|.....|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 45 8c 37 d5 7e 3e |..........E.7.~>|
+00000010 c4 24 64 8b fa fc 8d 03 a7 92 34 35 c3 2c f2 54 |.$d.......45.,.T|
+00000020 43 06 5d 8a c9 c0 e8 7d 22 d3 99 58 01 0e 44 aa |C.]....}"..X..D.|
+00000030 3c 26 eb 68 45 14 cd bf 6c 61 bb 31 91 9d b4 57 |<&.hE...la.1...W|
+00000040 42 79 14 8c 67 c6 65 52 15 07 c8 f3 c3 9f 23 ef |By..g.eR......#.|
+00000050 17 03 03 00 17 21 51 dd 67 e4 be f8 7c 7b 84 0d |.....!Q.g...|{..|
+00000060 78 3c 7f ac 50 f8 34 7b fb 38 09 d0 17 03 03 00 |x<..P.4{.8......|
+00000070 13 35 1a 52 9d de 4a 74 1f 01 70 de 05 c5 c3 b9 |.5.R..Jt..p.....|
+00000080 e6 de 9c 0f |....|
diff --git a/src/crypto/tls/testdata/Client-TLSv13-ALPN b/src/crypto/tls/testdata/Client-TLSv13-ALPN
new file mode 100644
index 0000000..1d8da26
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv13-ALPN
@@ -0,0 +1,93 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 01 0e 01 00 01 0a 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 8f 00 05 00 05 01 00 00 00 00 00 0a 00 |................|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 10 00 10 00 0e 06 70 72 6f 74 6f |...........proto|
+000000d0 32 06 70 72 6f 74 6f 31 00 12 00 00 00 2b 00 09 |2.proto1.....+..|
+000000e0 08 03 04 03 03 03 02 03 01 00 33 00 26 00 24 00 |..........3.&.$.|
+000000f0 1d 00 20 2f e5 7d a3 47 cd 62 43 15 28 da ac 5f |.. /.}.G.bC.(.._|
+00000100 bb 29 07 30 ff f6 84 af c4 cf c2 ed 90 99 5f 58 |.).0.........._X|
+00000110 cb 3b 74 |.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 c2 91 70 7a 7a |....z...v....pzz|
+00000010 d4 c9 46 7a e9 44 d1 c0 92 a6 0a 43 34 08 b2 ce |..Fz.D.....C4...|
+00000020 14 99 8f 6c f7 37 fb a1 28 00 ae 20 00 00 00 00 |...l.7..(.. ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 03 00 00 |................|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 60 |..+.....3.$... `|
+00000060 96 62 c2 30 4e ae b6 89 f2 06 e0 4e 8e 32 27 04 |.b.0N......N.2'.|
+00000070 b5 74 80 d8 c3 f5 76 7d 0e 0e e1 8d bc 2c 2c 14 |.t....v}.....,,.|
+00000080 03 03 00 01 01 17 03 03 00 24 45 c7 50 3e a9 63 |.........$E.P>.c|
+00000090 24 0b e9 80 3f 59 bb be 23 8a 5d 46 eb ee 17 9c |$...?Y..#.]F....|
+000000a0 70 6f 52 1f 18 f3 9f 72 d6 35 44 55 91 d2 17 03 |poR....r.5DU....|
+000000b0 03 02 6d c2 c0 1f 53 2a 0c 3c 7f 08 c3 cb 53 4e |..m...S*.<....SN|
+000000c0 b2 f5 b3 2d a5 10 e1 97 00 89 67 db 4e df ad 75 |...-......g.N..u|
+000000d0 94 b4 56 c4 8a a3 49 41 43 a1 3f aa 9b 8e e1 8d |..V...IAC.?.....|
+000000e0 4c 9c 36 f6 80 da 4e 7f 00 10 c0 81 3e 45 1b a0 |L.6...N.....>E..|
+000000f0 b7 7f 2c bd eb 2a 8b c4 e6 fa c8 b3 59 28 f6 b8 |..,..*......Y(..|
+00000100 0a 93 cb b3 bf 28 e7 1a ae a0 f5 ff 3a 42 f5 64 |.....(......:B.d|
+00000110 92 2c dd c2 24 77 2f a6 7e 23 63 3f 24 16 b3 d5 |.,..$w/.~#c?$...|
+00000120 b7 df 3f 30 23 a4 aa c9 14 78 6c f2 82 45 52 df |..?0#....xl..ER.|
+00000130 cf a1 1d 35 fd 2a 30 89 14 38 5a 23 b1 63 2c c1 |...5.*0..8Z#.c,.|
+00000140 6d 6b 07 d0 41 38 4f 4c 87 d3 bd f1 ec ed 29 52 |mk..A8OL......)R|
+00000150 3d c7 74 3d e9 d3 ce 47 1c 24 d5 78 19 c9 5e 01 |=.t=...G.$.x..^.|
+00000160 66 a0 f1 8f ea a6 c1 e4 b4 e0 c2 2e d7 d6 64 36 |f.............d6|
+00000170 c9 bc d1 27 33 6f 26 a8 c6 aa 0d bc ae f9 2e bc |...'3o&.........|
+00000180 f1 a7 82 42 09 83 62 88 c0 9f 20 95 a9 38 50 b4 |...B..b... ..8P.|
+00000190 55 d6 e9 f4 c6 a1 e6 67 a9 5f e4 15 97 44 13 ef |U......g._...D..|
+000001a0 d3 50 8b 61 38 5e 89 75 b1 cf 6a 6f 0c c5 26 13 |.P.a8^.u..jo..&.|
+000001b0 2c 5a 26 c9 81 98 88 cd ec 8c 2c 99 a0 ff 55 8f |,Z&.......,...U.|
+000001c0 3f 9b c3 3b 52 d0 a3 3a f9 b8 f0 17 81 53 00 f3 |?..;R..:.....S..|
+000001d0 ef 72 b3 4e b9 65 28 8f a2 48 dc dd 6b 16 61 c3 |.r.N.e(..H..k.a.|
+000001e0 4e 0e c0 1c ac 8c 40 28 27 63 66 c7 74 40 8d 93 |N.....@('cf.t@..|
+000001f0 71 e9 f6 3f d8 8d 5d c6 28 11 4f ac 55 6f 80 1b |q..?..].(.O.Uo..|
+00000200 2e 84 05 94 e0 4f e7 63 62 65 c7 52 99 49 2f 5d |.....O.cbe.R.I/]|
+00000210 b4 99 d3 c3 fa b9 f5 83 aa 28 2e 9d ce af 72 7f |.........(....r.|
+00000220 57 ea 81 f3 bf b5 d7 93 3a 1f a0 83 4d 8a 91 85 |W.......:...M...|
+00000230 fe b7 a1 b3 cb 1d b1 85 9b bb 36 1b 12 9f ed 13 |..........6.....|
+00000240 09 55 31 bd ee 61 06 57 b4 07 4d c6 1e fa b9 7f |.U1..a.W..M.....|
+00000250 c7 b6 60 70 92 b7 9a ff 80 7d da 7f 2a 62 89 be |..`p.....}..*b..|
+00000260 79 43 d3 ae 9c f1 00 6d 68 6c a3 f6 48 6e e0 48 |yC.....mhl..Hn.H|
+00000270 97 0f 5c 44 43 9f a8 88 27 96 fc 53 a0 e1 f2 7a |..\DC...'..S...z|
+00000280 a6 a7 d9 96 2e 3d c4 e0 d9 18 79 ec 83 c2 9b da |.....=....y.....|
+00000290 0b d4 8b 87 c5 98 f5 8b e7 e3 d1 bd 2b 2b 42 e2 |............++B.|
+000002a0 4b 3e 64 88 4b 72 d0 35 cc c3 e6 68 c6 f6 4f 23 |K>d.Kr.5...h..O#|
+000002b0 39 a7 94 8d f3 e6 bd cd d5 e9 8c 53 83 a7 87 09 |9..........S....|
+000002c0 15 fe ea eb 2e 56 da 6b d9 5b b7 b1 c5 c4 ba 65 |.....V.k.[.....e|
+000002d0 39 89 16 f5 f6 4e e6 3a 63 34 1b 5d f5 fa 6b 8d |9....N.:c4.]..k.|
+000002e0 c3 49 07 88 12 ca 18 c5 50 da 74 44 c0 c0 33 bd |.I......P.tD..3.|
+000002f0 2e 45 94 af e1 40 90 00 11 2d 08 7b fc e4 3b f0 |.E...@...-.{..;.|
+00000300 94 fd 5a 0c 3a f9 76 df 3b 5e a3 0d 0f e7 2d df |..Z.:.v.;^....-.|
+00000310 fd e9 ce 45 5a 13 36 a6 18 ae 46 30 00 fc d5 e3 |...EZ.6...F0....|
+00000320 17 03 03 00 99 0e 35 b6 91 ad cd a6 62 6e 79 12 |......5.....bny.|
+00000330 53 d5 f0 78 72 c5 dd 94 00 e3 75 2c 11 a3 72 f6 |S..xr.....u,..r.|
+00000340 b7 b3 5e d9 51 79 d5 a9 1e 21 2f df 0d 53 9a c8 |..^.Qy...!/..S..|
+00000350 43 a9 58 e2 a9 3d 9a b4 b4 72 bb 62 65 4b 83 f8 |C.X..=...r.beK..|
+00000360 cd 1b 58 e0 69 d9 87 3b 8d 05 42 e1 22 23 e9 5b |..X.i..;..B."#.[|
+00000370 3a 5a 38 17 17 fb 3a 56 de fc 56 f8 77 12 31 4a |:Z8...:V..V.w.1J|
+00000380 c5 38 ec 69 72 54 e5 63 2a a0 1e b4 7d 86 43 29 |.8.irT.c*...}.C)|
+00000390 21 ba 56 c2 d9 1b 9f a4 c1 02 f3 83 c1 9a 56 69 |!.V...........Vi|
+000003a0 5c 9e 5f ae 94 9d 6f 03 ec 75 7a 19 98 cd a9 dd |\._...o..uz.....|
+000003b0 4a 01 41 72 2e 60 9f ca 4c d2 27 d9 0f 4f 17 03 |J.Ar.`..L.'..O..|
+000003c0 03 00 35 5d 61 3c 07 70 2f 35 ba d0 93 44 16 bd |..5]a<.p/5...D..|
+000003d0 73 4b a0 fb 05 52 6a cc 5a 2e f2 94 d6 77 98 03 |sK...Rj.Z....w..|
+000003e0 c3 2e 8e a9 d1 38 14 d2 cd e6 e3 b6 ad ec d6 a0 |.....8..........|
+000003f0 cf b0 58 5f 8f d3 43 4b |..X_..CK|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 3d 0a fd 33 39 |..........5=..39|
+00000010 b6 94 43 53 ae ee 3f 4e c6 2d a2 3a f0 ef 94 7d |..CS..?N.-.:...}|
+00000020 32 0a b6 90 cd a1 6f 29 88 ff 3c 91 c1 e5 e5 ae |2.....o)..<.....|
+00000030 b7 a0 0b b3 c0 e6 37 9d 06 8b d8 ae 06 c0 0e 7b |......7........{|
+00000040 17 03 03 00 17 c2 a1 82 db df fa 54 28 79 a0 0c |...........T(y..|
+00000050 97 8c 82 ee 22 c9 b9 35 32 7a 21 4b 17 03 03 00 |...."..52z!K....|
+00000060 13 87 2b f8 38 81 df fa e5 2e ff e2 d2 51 3e bc |..+.8........Q>.|
+00000070 dd d3 e8 62 |...b|
diff --git a/src/crypto/tls/testdata/Client-TLSv13-CHACHA20-SHA256 b/src/crypto/tls/testdata/Client-TLSv13-CHACHA20-SHA256
new file mode 100644
index 0000000..69749f0
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv13-CHACHA20-SHA256
@@ -0,0 +1,90 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 39 b2 74 80 d8 |....z...v..9.t..|
+00000010 49 72 79 63 9b 7b da d7 cf b4 29 20 f8 80 ed d9 |Iryc.{....) ....|
+00000020 66 09 65 22 b6 27 16 c5 a7 6f 8b 20 00 00 00 00 |f.e".'...o. ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 03 00 00 |................|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 42 |..+.....3.$... B|
+00000060 80 fb 4a d3 49 53 a5 9f f6 da ca 64 f8 5d 2c f5 |..J.IS.....d.],.|
+00000070 45 4d f1 a5 ec c3 c6 fc d2 ff 56 b1 63 53 1a 14 |EM........V.cS..|
+00000080 03 03 00 01 01 17 03 03 00 17 f8 d8 e1 1a e0 c8 |................|
+00000090 75 f9 40 90 da 16 a0 41 4f 8c 23 e7 47 43 89 cf |u.@....AO.#.GC..|
+000000a0 d4 17 03 03 02 6d d6 23 1d c6 c0 d4 5e a3 fe 2b |.....m.#....^..+|
+000000b0 03 04 6c 88 d1 4a ac 9b dd 90 e5 18 c5 35 9c 4a |..l..J.......5.J|
+000000c0 f3 c4 64 e2 c2 40 62 fb 68 b3 22 37 9f f4 eb ae |..d..@b.h."7....|
+000000d0 45 d9 a8 be f4 1e 89 16 88 b5 10 e3 5c 2e 42 15 |E...........\.B.|
+000000e0 34 24 f3 bd dd 73 6d 6b d1 db 3e 69 b0 0a 54 e6 |4$...smk..>i..T.|
+000000f0 b7 2c b7 80 86 93 91 d5 26 02 77 bf 10 38 ee 40 |.,......&.w..8.@|
+00000100 22 4d 3f 67 02 6b f8 1c 4a ad 2b c7 f6 19 d4 36 |"M?g.k..J.+....6|
+00000110 9b ff c4 08 73 e1 48 0a a6 e8 80 3b 88 8a c2 e8 |....s.H....;....|
+00000120 c6 4a ae da a1 4f 3b 9e fb 80 3b 78 ca 80 42 00 |.J...O;...;x..B.|
+00000130 a4 5c 9d a0 6c 63 a7 66 e6 26 b7 14 d8 8b ba 1a |.\..lc.f.&......|
+00000140 4b 13 81 3c e4 76 4e ac 6c 2f b4 71 e9 dc c4 c8 |K..<.vN.l/.q....|
+00000150 ef f0 61 22 f4 6b 83 ae d8 d0 a7 c6 d9 ea 95 85 |..a".k..........|
+00000160 77 90 0f 22 a0 50 cb ff 50 a5 98 ee de e4 89 f3 |w..".P..P.......|
+00000170 20 f2 63 a2 45 3a 48 33 d5 b9 ff 5e f8 7d c5 2d | .c.E:H3...^.}.-|
+00000180 b9 9c b2 65 bf d5 13 36 46 a5 96 9f f4 de 7c 1c |...e...6F.....|.|
+00000190 78 3f 1a 0a 62 14 13 8e 55 7e cd 47 87 1b 7e a8 |x?..b...U~.G..~.|
+000001a0 7f 03 ec 1c d3 72 eb e5 94 d9 9d 95 d6 f5 ad 2c |.....r.........,|
+000001b0 e9 7d 0f 2c ea 7b 1e 8e d7 b4 f1 5d 12 be d7 cf |.}.,.{.....]....|
+000001c0 b7 43 89 65 e9 04 0e f8 b4 b4 4d 9c 9c 42 3c 50 |.C.e......M..B<P|
+000001d0 a7 91 d0 7f c0 de fb 99 08 ce 5c fd 67 3a cb 1a |..........\.g:..|
+000001e0 d3 1a 4c a2 2e 7d 73 01 2b 5f bb a2 86 7d 0e e0 |..L..}s.+_...}..|
+000001f0 a1 c9 06 c0 4a 0a f6 c6 c4 b5 53 51 3e 2f f4 60 |....J.....SQ>/.`|
+00000200 1d 41 55 9d c4 88 f3 76 4f 92 b5 03 98 23 6b c4 |.AU....vO....#k.|
+00000210 c3 62 bd 12 dd 3a bc 37 d0 18 64 c6 e1 2c cb 62 |.b...:.7..d..,.b|
+00000220 f6 d3 24 35 47 e7 cf 15 d3 53 9d ac 3f 97 48 c1 |..$5G....S..?.H.|
+00000230 b8 d3 a3 2c 9f cd 2b 72 bc bd a6 8a b1 54 48 7b |...,..+r.....TH{|
+00000240 e0 b7 a2 2e 46 04 cc e5 29 1d 73 c7 67 f8 f0 d8 |....F...).s.g...|
+00000250 e0 88 f0 7b 11 ff e1 1d 95 6c 85 c4 08 72 3e 94 |...{.....l...r>.|
+00000260 92 4b 8a 58 62 04 10 83 7c 5e 65 20 a7 5d 6d 16 |.K.Xb...|^e .]m.|
+00000270 30 64 fc aa 7f 8f 06 ed 4e 3c 86 c8 10 92 fb 0d |0d......N<......|
+00000280 7b 81 10 07 cf 30 7f 6b 11 63 60 2a 61 92 cb 74 |{....0.k.c`*a..t|
+00000290 82 a4 04 cf 23 43 21 55 45 2a 29 93 42 0f 0c f6 |....#C!UE*).B...|
+000002a0 9b 14 b5 96 09 25 1b bc b0 7b 72 e2 6f b8 55 74 |.....%...{r.o.Ut|
+000002b0 00 bb 1c 7c b1 9b 58 63 97 bb 6d c5 fb a4 da 24 |...|..Xc..m....$|
+000002c0 1e b2 97 18 75 ab 8b a2 77 50 38 4d f8 a0 39 58 |....u...wP8M..9X|
+000002d0 8c 2d 3e ba 27 03 e9 51 87 0a 95 e0 08 40 5d e6 |.->.'..Q.....@].|
+000002e0 6a dd 10 1d 6d 8c 32 88 a8 32 ee dd 44 9c 9b b0 |j...m.2..2..D...|
+000002f0 6f f5 4b 08 60 9d 83 1e ab 83 c0 92 10 c7 aa 90 |o.K.`...........|
+00000300 d2 b2 61 5e 12 b5 e8 ea a7 68 59 17 a4 f4 15 f7 |..a^.....hY.....|
+00000310 dc 10 81 17 03 03 00 99 8a 61 79 8f 33 51 7b a9 |.........ay.3Q{.|
+00000320 ce 3f 82 2b bb da 40 2e 73 c8 d9 6e 7d 72 ba 94 |.?.+..@.s..n}r..|
+00000330 7d ad fb b7 ba 9c 74 00 0b c9 1d b6 8d 54 b9 48 |}.....t......T.H|
+00000340 eb 49 78 c3 1a 75 b8 16 22 5d 50 f5 4a 81 59 d3 |.Ix..u.."]P.J.Y.|
+00000350 38 79 38 c1 35 11 55 69 6b d2 86 3c 0f 12 26 57 |8y8.5.Uik..<..&W|
+00000360 f5 84 d7 dd 74 61 6f b8 08 66 e9 3c f7 43 29 a5 |....tao..f.<.C).|
+00000370 94 9e ab af 68 04 c1 6a ae 9d 12 2d 57 e9 ff 30 |....h..j...-W..0|
+00000380 7d 80 35 65 cc df c8 65 0b a1 f9 6d 6b a5 0b df |}.5e...e...mk...|
+00000390 0c 1a 04 0a 00 8f ac 2b 29 60 92 4e 91 d3 42 25 |.......+)`.N..B%|
+000003a0 b4 a5 0a 1a 5f 83 ec 9a f0 0a 2c 6d 65 00 24 d3 |...._.....,me.$.|
+000003b0 e1 17 03 03 00 35 e4 72 aa 9e 6c a8 93 7b e4 49 |.....5.r..l..{.I|
+000003c0 1e 23 7c 50 18 59 00 08 3b f1 c1 5f 20 ba 51 56 |.#|P.Y..;.._ .QV|
+000003d0 fe bb 93 99 52 e6 5e 6d 26 cc 60 11 c2 a1 c8 18 |....R.^m&.`.....|
+000003e0 2e 72 bd ee 36 ca 41 25 73 f2 30 |.r..6.A%s.0|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 b6 c3 b9 b1 52 |..........5....R|
+00000010 88 d2 78 2b ec 1c 63 e8 d5 08 0e 4e d6 51 b9 02 |..x+..c....N.Q..|
+00000020 ba cc a8 ca b6 da 45 a9 7c 1a 18 39 47 84 db 34 |......E.|..9G..4|
+00000030 d6 05 6f e5 16 19 57 6f 65 0b 7a e7 37 b5 d3 28 |..o...Woe.z.7..(|
+00000040 17 03 03 00 17 dc b8 e2 1c aa b8 f5 cb b6 fd ba |................|
+00000050 29 34 73 bb c6 e0 3a fc 3e fb d3 01 17 03 03 00 |)4s...:.>.......|
+00000060 13 eb 66 ab 47 38 1b 01 96 6c 59 46 c2 ad bf 2d |..f.G8...lYF...-|
+00000070 36 22 97 19 |6"..|
diff --git a/src/crypto/tls/testdata/Client-TLSv13-ClientCert-ECDSA-RSA b/src/crypto/tls/testdata/Client-TLSv13-ClientCert-ECDSA-RSA
new file mode 100644
index 0000000..bd8f6cd
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv13-ClientCert-ECDSA-RSA
@@ -0,0 +1,139 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 85 46 7d 9f 55 |....z...v...F}.U|
+00000010 82 34 10 06 5e 8d 60 5d 00 9d 28 cd 18 c2 18 ee |.4..^.`]..(.....|
+00000020 cb 9a 63 ee 9a 30 7d 5d 87 3d 24 20 00 00 00 00 |..c..0}].=$ ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 03 00 00 |................|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 15 |..+.....3.$... .|
+00000060 b8 ae de 9d dc 14 58 fe 01 5d 08 ed 41 ac c6 c7 |......X..]..A...|
+00000070 85 fe b1 a3 ae b6 8c 47 f3 e1 4e c5 f8 8b 48 14 |.......G..N...H.|
+00000080 03 03 00 01 01 17 03 03 00 17 d6 72 35 0b 81 34 |...........r5..4|
+00000090 42 89 f1 9b 31 94 72 af 0c 3c 45 36 96 26 71 e8 |B...1.r..<E6.&q.|
+000000a0 86 17 03 03 00 42 47 ed 30 6f 20 53 07 4f b2 c1 |.....BG.0o S.O..|
+000000b0 35 49 fa 5b d9 af 6c 0b c3 71 7a f3 a8 5b 24 ba |5I.[..l..qz..[$.|
+000000c0 59 dd 34 b7 02 07 63 5d a1 ad ac 4c a2 58 e7 cd |Y.4...c]...L.X..|
+000000d0 6d f7 23 4e e1 a9 af 75 23 93 37 25 59 7e fb 52 |m.#N...u#.7%Y~.R|
+000000e0 65 a4 e7 ea 0a df a7 ce 17 03 03 02 6d e5 aa db |e...........m...|
+000000f0 1d 7e 55 0f b4 79 96 de 15 74 52 95 52 c8 ce d6 |.~U..y...tR.R...|
+00000100 85 a9 a8 6f 79 63 cf d7 3a 9e 38 d2 9d 0a 73 a0 |...oyc..:.8...s.|
+00000110 0b c3 f3 85 77 d3 63 16 9b 13 79 e6 61 96 08 57 |....w.c...y.a..W|
+00000120 ba 4a 64 b6 af 1a 98 22 a6 d9 20 82 2c 40 28 57 |.Jd....".. .,@(W|
+00000130 b8 95 d6 b4 94 46 8f 67 2d eb ee 02 74 d3 94 e7 |.....F.g-...t...|
+00000140 6e 5b 2f a9 7d a2 c2 aa 89 0c 43 c3 9d 92 6f 16 |n[/.}.....C...o.|
+00000150 27 84 d7 79 dd 4b 6a ed 9b fc cd d7 c0 c4 59 09 |'..y.Kj.......Y.|
+00000160 21 1f 83 67 e7 76 c8 ee bf f5 79 87 a0 bd 14 6d |!..g.v....y....m|
+00000170 db ac 06 04 c4 3b 3a a7 1e cb 22 d1 97 21 9d c2 |.....;:..."..!..|
+00000180 ee ed a8 41 f7 a0 6a a0 64 2f b0 0a 6f b7 78 b8 |...A..j.d/..o.x.|
+00000190 20 36 ed 7a e9 3c 26 cb 36 7d 3c ee 73 27 32 e7 | 6.z.<&.6}<.s'2.|
+000001a0 e7 fd 6e 27 d9 da ad 48 67 29 94 50 f5 0e 56 af |..n'...Hg).P..V.|
+000001b0 e4 c5 1d d3 59 a4 de 59 d7 79 7a f3 10 36 fb ed |....Y..Y.yz..6..|
+000001c0 b1 97 00 a4 dd 6e c2 65 19 0a 73 fe 2c 49 dc c5 |.....n.e..s.,I..|
+000001d0 df 19 53 c2 7e de 0b 2b 55 3d ca 0b 39 a4 77 c4 |..S.~..+U=..9.w.|
+000001e0 21 53 93 12 f0 9a 3a 3b 97 0c 93 80 50 23 80 9e |!S....:;....P#..|
+000001f0 84 2e ef 22 2b c1 b3 dd b1 55 38 76 9a d6 a6 f1 |..."+....U8v....|
+00000200 67 11 df d9 a0 8a 18 c6 68 ef d8 7b d7 36 4b 57 |g.......h..{.6KW|
+00000210 a7 bf 4e 77 a5 f6 4f 1e be 6e 14 40 67 73 1c 20 |..Nw..O..n.@gs. |
+00000220 9f 17 30 b6 76 00 87 56 8c 2b 76 5f 04 46 5a a1 |..0.v..V.+v_.FZ.|
+00000230 0f fa 64 b3 fa da 4e 72 eb a7 95 c3 93 de 97 20 |..d...Nr....... |
+00000240 2d ea 06 84 aa f0 b6 5a ac ea 64 06 2a 8c b0 eb |-......Z..d.*...|
+00000250 58 0a e8 51 e1 34 c4 03 38 9f f7 fb ec 98 78 07 |X..Q.4..8.....x.|
+00000260 71 73 ad a5 d7 d5 d1 2d 95 b6 4f 7c 5a ee d9 f1 |qs.....-..O|Z...|
+00000270 fa e3 7d ae bd 31 98 27 31 07 f2 86 cf e5 8d 2c |..}..1.'1......,|
+00000280 e8 55 40 69 b0 26 a3 51 e8 60 59 6f 66 bb 36 4f |.U@i.&.Q.`Yof.6O|
+00000290 85 fc 36 d1 72 99 9d e1 83 ad ec 3f e8 90 a8 48 |..6.r......?...H|
+000002a0 f5 d1 41 30 59 4e 44 79 e4 de 6f 0d 37 61 01 bb |..A0YNDy..o.7a..|
+000002b0 b8 7f ee c7 a2 35 c7 12 dc d3 ca 49 8d d9 3e d8 |.....5.....I..>.|
+000002c0 24 69 34 a4 8f 92 f2 77 61 cb b7 04 f8 02 25 9c |$i4....wa.....%.|
+000002d0 88 ea c7 f0 13 3e 17 bc ac 5a 80 c4 80 c6 b0 19 |.....>...Z......|
+000002e0 d3 73 b5 94 5a 27 df 08 05 23 6e 03 64 67 ab c8 |.s..Z'...#n.dg..|
+000002f0 63 7c 76 b3 92 39 ef 29 77 28 ec 6f 05 70 a6 2f |c|v..9.)w(.o.p./|
+00000300 a0 d2 73 fd f9 cc 4f d7 6f 86 db 9a 02 84 8c 6c |..s...O.o......l|
+00000310 39 3a 54 28 38 43 ca 0d da 34 b5 d4 03 0c f8 c1 |9:T(8C...4......|
+00000320 8d 48 d0 63 c7 41 da 4c db 0a 45 56 cf 6b 0b ca |.H.c.A.L..EV.k..|
+00000330 2f a3 82 6e 8e 90 6f 8a f2 41 33 c5 56 c5 15 bd |/..n..o..A3.V...|
+00000340 c2 02 45 41 7a e7 2b 0d 15 82 a7 37 34 ea 19 c2 |..EAz.+....74...|
+00000350 8b 1d d4 17 9c 2d d4 c0 9d f3 17 03 03 00 99 37 |.....-.........7|
+00000360 6a b2 6e 07 32 19 45 80 7b 80 ef 93 b3 6e c3 19 |j.n.2.E.{....n..|
+00000370 4d fe 3e e9 7f e4 b9 37 d2 b0 83 56 f7 2f 9b 61 |M.>....7...V./.a|
+00000380 67 a1 65 b4 38 4b a1 06 c5 4a 20 44 37 26 d0 2a |g.e.8K...J D7&.*|
+00000390 b7 96 1e 72 ef a8 5d fb 5a b8 ea 26 0e 4b 38 e0 |...r..].Z..&.K8.|
+000003a0 6a 3a ab 4a e3 b4 db 00 f8 30 e6 db 02 e4 cf 89 |j:.J.....0......|
+000003b0 5b 57 b8 b8 3e 0a 97 b4 61 9e 89 7d 76 b3 9f 51 |[W..>...a..}v..Q|
+000003c0 a0 b8 46 95 8b 2b b9 25 8e 39 29 f5 97 41 e6 f1 |..F..+.%.9)..A..|
+000003d0 f0 0c 8b 70 bc 63 a0 56 24 c0 fb 0d 44 7f d8 78 |...p.c.V$...D..x|
+000003e0 c0 d5 a2 b7 53 67 c5 6d 0f 37 25 3e dc 08 e2 50 |....Sg.m.7%>...P|
+000003f0 ca 28 c3 1b ec 28 26 0c 17 03 03 00 35 ef 63 88 |.(...(&.....5.c.|
+00000400 13 79 07 a1 28 af 88 6e 8c e4 ad b3 0a 28 2a ce |.y..(..n.....(*.|
+00000410 db 0f 63 8a 16 95 ab 0a 01 51 4f 28 79 15 78 00 |..c......QO(y.x.|
+00000420 f9 7a a6 40 1b 39 98 d8 8d df 1b b9 ab 82 b9 59 |.z.@.9.........Y|
+00000430 67 b9 |g.|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 02 1e ad ee 84 48 28 |..............H(|
+00000010 bb dc e6 01 81 4c b3 55 85 2a 73 3a 34 d6 6b 3a |.....L.U.*s:4.k:|
+00000020 c6 e7 6b da e8 97 dc 13 72 9c d4 03 e2 fc ec e0 |..k.....r.......|
+00000030 0b 00 09 a9 3c 85 19 79 80 a3 fc da 39 b1 13 90 |....<..y....9...|
+00000040 3e 0c be 19 5a be a9 ac a5 46 a0 07 79 74 be 59 |>...Z....F..yt.Y|
+00000050 18 23 55 79 c0 29 3f 8c 37 d6 21 0c 64 57 4c f0 |.#Uy.)?.7.!.dWL.|
+00000060 a1 34 e0 52 f7 e5 3c af 48 b4 82 78 bd be 7c 90 |.4.R..<.H..x..|.|
+00000070 df 0e f3 46 84 6a e2 bb 88 aa 9a a0 ce 04 de 2b |...F.j.........+|
+00000080 b3 17 78 e1 a0 bb 65 7f c5 b3 a6 45 13 c6 11 e1 |..x...e....E....|
+00000090 e2 b4 ec 80 43 80 b6 a5 12 58 ac 5e 30 d3 a0 61 |....C....X.^0..a|
+000000a0 60 c2 90 36 aa 82 f7 ff 55 aa 4e 25 b3 29 5d 41 |`..6....U.N%.)]A|
+000000b0 67 4e 9c d4 f1 1d 55 f1 29 54 13 25 3c 04 41 8f |gN....U.)T.%<.A.|
+000000c0 6b 9d 95 06 3f 04 84 55 dd 43 7a fb 9f 73 ff df |k...?..U.Cz..s..|
+000000d0 3b da 12 3b 97 36 fa 51 0b ca c7 0b fb 6a 09 dd |;..;.6.Q.....j..|
+000000e0 61 2a df 79 b3 66 90 45 76 3c 2b c6 98 42 5a 82 |a*.y.f.Ev<+..BZ.|
+000000f0 0e 93 cf 6f 2b 60 e4 66 67 ad 43 66 73 d2 8c 94 |...o+`.fg.Cfs...|
+00000100 7f 7a 97 d5 a1 8b 07 63 44 cb 51 18 ac 2a af 19 |.z.....cD.Q..*..|
+00000110 66 df ab 18 6f 2a bf fc 7a fa 64 52 c4 1e 91 71 |f...o*..z.dR...q|
+00000120 f1 f7 7f 79 e1 ed 07 3a e1 08 07 d3 db 4d 74 76 |...y...:.....Mtv|
+00000130 db fa b9 b4 68 e3 d8 e7 8d ad 49 a7 1d 6d 7e 4e |....h.....I..m~N|
+00000140 3a 6a d2 9a c3 b0 72 61 bb 72 b8 8d 98 58 6e 2e |:j....ra.r...Xn.|
+00000150 20 f8 ab 4a df 96 c7 6c fe 33 5b 76 b0 80 26 34 | ..J...l.3[v..&4|
+00000160 b9 5c 9a 79 50 d7 6a 29 25 11 20 4e 3c b6 a7 73 |.\.yP.j)%. N<..s|
+00000170 64 55 a6 8e 57 22 4a 98 5e 14 95 21 ff 8d 3f 05 |dU..W"J.^..!..?.|
+00000180 eb d9 30 8e f1 a3 56 3a d8 6d 6e 07 de a2 62 ec |..0...V:.mn...b.|
+00000190 e4 06 bb 96 ae a3 23 d0 bd fd c7 f3 ee 2f 21 3f |......#....../!?|
+000001a0 8f 25 7a 4a fb 47 cf 78 db 74 35 c8 67 e6 f0 99 |.%zJ.G.x.t5.g...|
+000001b0 39 4e 1f 50 1a bc 64 2e ae 8e b5 38 63 06 86 5a |9N.P..d....8c..Z|
+000001c0 2b 1b b5 b9 a1 18 58 24 32 ce c9 de 66 ba 21 b3 |+.....X$2...f.!.|
+000001d0 d8 0f fa 3a 88 ac 6e 66 57 2c 45 5b 59 85 d4 b0 |...:..nfW,E[Y...|
+000001e0 ad 32 8c ef 0c 2a 51 1a cc ca 6a 82 3e 70 41 cc |.2...*Q...j.>pA.|
+000001f0 b8 80 db a0 48 22 47 49 a1 a5 d2 9a 80 dc 09 bc |....H"GI........|
+00000200 c8 c7 dd 53 4b 44 2f 9a 75 06 b7 31 5e fd 74 f5 |...SKD/.u..1^.t.|
+00000210 d4 53 e2 90 dc b7 9a 13 ca 00 96 56 a1 1b dd 71 |.S.........V...q|
+00000220 54 25 77 fa 42 31 95 dd ba 17 03 03 00 a3 9e 23 |T%w.B1.........#|
+00000230 96 bb c9 d5 30 f7 f4 a3 4c 33 a4 bd 2b 09 93 f5 |....0...L3..+...|
+00000240 04 02 a7 d7 9d 2e 00 5e 18 bc 18 de 1b 94 28 51 |.......^......(Q|
+00000250 4b cd 2c 15 0e 75 b1 59 12 96 8f eb cb b5 a4 4a |K.,..u.Y.......J|
+00000260 ea c2 e0 1d 28 72 4b 8f 62 d3 7d f0 2f f1 c4 de |....(rK.b.}./...|
+00000270 6a 6e dc 9c 43 80 c8 ae 99 86 97 de 67 58 d6 4c |jn..C.......gX.L|
+00000280 91 74 dc c3 23 a5 32 9b df f5 1e 64 15 04 7d df |.t..#.2....d..}.|
+00000290 12 e4 40 52 77 5c a3 26 de 20 b6 92 a5 d8 18 cf |..@Rw\.&. ......|
+000002a0 63 7e 9e 47 b8 ed db ee b7 9d b6 1c e5 c0 ad 7f |c~.G............|
+000002b0 d6 07 89 d8 b3 a0 2e 87 b9 81 0d 44 37 c2 c5 13 |...........D7...|
+000002c0 cc cb 70 87 e3 49 6e eb 66 79 76 37 4a f1 c4 4e |..p..In.fyv7J..N|
+000002d0 82 17 03 03 00 35 52 42 2a a8 a5 7a eb 5f 32 d5 |.....5RB*..z._2.|
+000002e0 68 71 42 8b ce 62 f0 48 43 0b 0f b8 8c ed 16 f4 |hqB..b.HC.......|
+000002f0 64 7e d3 74 57 9d 83 00 ad bc 9b f8 ed bb 23 35 |d~.tW.........#5|
+00000300 07 e9 7c b2 a1 d6 76 d0 f5 ba 15 17 03 03 00 17 |..|...v.........|
+00000310 e2 3f a0 cb 23 fe 4c f1 aa cb 21 70 74 46 4f 10 |.?..#.L...!ptFO.|
+00000320 30 76 0a 72 49 09 65 17 03 03 00 13 ee 7b 9d 32 |0v.rI.e......{.2|
+00000330 ac d4 8a 40 99 1b 0a 23 f7 a4 c6 a6 ef 33 77 |...@...#.....3w|
diff --git a/src/crypto/tls/testdata/Client-TLSv13-ClientCert-Ed25519 b/src/crypto/tls/testdata/Client-TLSv13-ClientCert-Ed25519
new file mode 100644
index 0000000..689c287
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv13-ClientCert-Ed25519
@@ -0,0 +1,122 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 4e 4c 01 f1 4e |....z...v..NL..N|
+00000010 49 97 ec eb df ce 50 4d 1c 9c d0 35 92 10 97 0a |I.....PM...5....|
+00000020 dd fb a8 4f 39 c6 14 21 d6 42 ac 20 00 00 00 00 |...O9..!.B. ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 03 00 00 |................|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 c1 |..+.....3.$... .|
+00000060 c2 ca 32 aa 48 d8 52 bc c8 23 6d 98 18 3e 15 b6 |..2.H.R..#m..>..|
+00000070 0b 25 db f9 6f a7 e1 75 95 a1 46 d3 47 4a 0e 14 |.%..o..u..F.GJ..|
+00000080 03 03 00 01 01 17 03 03 00 17 87 10 92 da b4 9a |................|
+00000090 03 a5 0f 73 e6 93 cb 71 1d 58 6e 5d 27 eb ee b6 |...s...q.Xn]'...|
+000000a0 c7 17 03 03 00 42 89 8d 57 16 95 5b f0 98 ad c7 |.....B..W..[....|
+000000b0 d7 94 ba 4d 7e 88 b9 8d 13 26 a6 6c 81 90 a6 1e |...M~....&.l....|
+000000c0 2b 4e 91 70 e2 da 9d a2 0d 6f 9b 5b ee 69 58 a1 |+N.p.....o.[.iX.|
+000000d0 4c c3 59 57 28 62 b3 ed 26 15 79 db 01 8c 88 e3 |L.YW(b..&.y.....|
+000000e0 63 1f bc b0 01 c9 82 ca 17 03 03 02 6d e5 d6 77 |c...........m..w|
+000000f0 4e d3 af c3 5e 01 e9 1b 31 63 a4 84 d3 cc 2d f8 |N...^...1c....-.|
+00000100 5d 73 f9 3e 83 03 c5 c5 cd 95 00 7b f2 b5 79 fa |]s.>.......{..y.|
+00000110 47 e5 07 89 a9 22 49 7a 7e 7e 6e d2 3b 68 e8 9c |G...."Iz~~n.;h..|
+00000120 40 1c 86 2a 48 ee 59 8e 1c 04 8b 91 20 68 65 31 |@..*H.Y..... he1|
+00000130 e7 76 dc 6c 5a ce cb 32 d3 e8 71 7f 93 08 b5 01 |.v.lZ..2..q.....|
+00000140 84 0a b4 ec 80 68 69 9b b3 4a 4a 4d 56 16 eb 42 |.....hi..JJMV..B|
+00000150 29 93 4d b4 76 f6 e0 15 fe 25 b1 cb 5a da 22 4b |).M.v....%..Z."K|
+00000160 88 4c ec 66 48 09 e1 d1 0f 3e 3a ad 65 d7 d7 85 |.L.fH....>:.e...|
+00000170 1d cb 35 2c 84 60 ec a1 6d f1 60 cf c6 c7 82 1a |..5,.`..m.`.....|
+00000180 7c 91 40 2e 3e 88 1f ff 79 2e 6e 97 c5 45 9f e1 ||.@.>...y.n..E..|
+00000190 bf 33 ad 65 df f3 ce 1a d7 57 7e db f2 28 79 a9 |.3.e.....W~..(y.|
+000001a0 9e 4f 9e 8a ce 02 5a 18 bb f1 ac 72 5b 3f 4c 6b |.O....Z....r[?Lk|
+000001b0 97 14 14 f9 82 8a 4f 99 21 98 db af 3e 08 ab 4f |......O.!...>..O|
+000001c0 d8 3f f6 cc da 76 77 eb 02 39 0a 00 23 a5 e0 92 |.?...vw..9..#...|
+000001d0 01 10 3f 76 ab 1a 38 8e f9 a1 d0 25 c3 9d 50 a4 |..?v..8....%..P.|
+000001e0 ef a5 8c f8 5d bc d9 fd dd 25 cd 42 38 52 d1 cd |....]....%.B8R..|
+000001f0 d2 1b fc ba 7d 8b bd 82 05 23 c3 9d 02 ff 1b 4e |....}....#.....N|
+00000200 08 e1 f3 7c 35 15 0f e8 0e b7 8a e5 4a 2b da 45 |...|5.......J+.E|
+00000210 4a 72 9a 32 7e 55 52 65 d2 a8 32 90 53 bf 25 29 |Jr.2~URe..2.S.%)|
+00000220 1e 8d d7 a3 22 d6 40 19 95 58 a8 37 af a8 52 e7 |....".@..X.7..R.|
+00000230 79 b9 4e 61 d8 f0 7d d2 69 25 99 28 3f 31 f6 b2 |y.Na..}.i%.(?1..|
+00000240 44 65 1f 9c 41 08 17 c9 01 5d 20 ea ab fe 06 64 |De..A....] ....d|
+00000250 9a f4 d0 24 e0 b5 88 0a 2b 96 e9 71 11 a8 49 b4 |...$....+..q..I.|
+00000260 40 62 1b 45 15 47 cb a5 fc 4f 07 58 2b ef d4 5d |@b.E.G...O.X+..]|
+00000270 df 40 38 6c 6e ca 63 c5 95 2d 79 26 86 ff 33 02 |.@8ln.c..-y&..3.|
+00000280 da 5a 85 0c 8f 7f 58 ba ea 88 cf bc 51 92 12 86 |.Z....X.....Q...|
+00000290 f1 c1 f9 0a d0 6e cc b4 2b 16 98 ad f8 11 ad 63 |.....n..+......c|
+000002a0 82 d7 4e ea a5 ee 78 a2 9a 35 b6 b3 d9 24 cf 66 |..N...x..5...$.f|
+000002b0 03 d2 25 1f 15 37 c7 b5 8e bb 0a 40 0f 28 c2 16 |..%..7.....@.(..|
+000002c0 90 a4 61 9e dd fd b5 ad 97 39 0d 66 e7 fa 5b e2 |..a......9.f..[.|
+000002d0 c2 ef 44 5d 44 07 d6 c3 ed e2 89 6e 4c ed 79 42 |..D]D......nL.yB|
+000002e0 86 3b f4 94 0c 82 5e 52 ce 00 ab 5c 20 b4 18 db |.;....^R...\ ...|
+000002f0 c9 fe 8b be 8d da e9 86 13 62 6b 8d 0d 57 c8 fe |.........bk..W..|
+00000300 a6 4b 82 52 d5 d8 05 18 2f a0 43 d6 c8 89 fb e7 |.K.R..../.C.....|
+00000310 72 17 61 89 36 5b e0 aa 4d 6c 20 ee 68 db 32 e4 |r.a.6[..Ml .h.2.|
+00000320 97 9f 18 26 7c 1a cd e8 b9 05 ae fd 86 bf 0e 47 |...&|..........G|
+00000330 09 06 bd de 2d b9 50 6a 0c a6 27 04 5e aa e0 ce |....-.Pj..'.^...|
+00000340 e7 cf 98 f9 7e 7d b9 4d 77 9a 88 3a d4 41 07 cc |....~}.Mw..:.A..|
+00000350 87 b6 41 53 8b 8c 79 8e 07 b9 17 03 03 00 99 0b |..AS..y.........|
+00000360 63 4e d8 79 d7 11 f2 46 00 6c 5d d2 9e 49 df 7e |cN.y...F.l]..I.~|
+00000370 f2 96 1a 68 9d 6a 05 dc 61 45 47 a4 18 5c 65 04 |...h.j..aEG..\e.|
+00000380 00 38 d1 25 0c ff a3 a2 c0 c2 82 7f b1 1b a1 c6 |.8.%............|
+00000390 7b ac fb 71 48 b6 e4 e2 7b c4 d0 44 8e 22 d6 91 |{..qH...{..D."..|
+000003a0 99 87 a2 88 3d bb b4 80 13 57 2a 6a b0 2d 52 16 |....=....W*j.-R.|
+000003b0 d3 f2 e4 cd d0 79 9a 31 ce 68 65 b3 61 67 a0 b9 |.....y.1.he.ag..|
+000003c0 1e 6b 9f 73 dc 46 be 5e df d7 c2 30 d5 60 b5 e5 |.k.s.F.^...0.`..|
+000003d0 60 cc 10 ae 9a f9 b6 9a fd 14 b9 1e b7 3c 1d 3e |`............<.>|
+000003e0 34 a6 49 d2 48 f7 24 56 29 c9 98 f1 33 b1 e5 5e |4.I.H.$V)...3..^|
+000003f0 2c 7b bb 5f b6 53 6a c8 17 03 03 00 35 d9 af 32 |,{._.Sj.....5..2|
+00000400 1f a5 09 3f 8a 10 df a7 34 9b f8 ec 07 81 80 73 |...?....4......s|
+00000410 dc ba 09 fc 40 e4 1e df f6 de 02 54 3c 7d ea 49 |....@......T<}.I|
+00000420 91 16 72 70 8e 1a 21 76 c6 00 0e 03 9f 0a 82 fe |..rp..!v........|
+00000430 4c 18 |L.|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 01 50 1d 6e 16 0d 4e |..........P.n..N|
+00000010 c0 a2 41 c3 a2 84 c9 80 c0 f0 ef c0 5d 3a 3b f2 |..A.........]:;.|
+00000020 bf 1c 9e 79 d7 d3 94 0b 41 2d bc 50 eb 0f 60 f4 |...y....A-.P..`.|
+00000030 bd cd f6 03 22 7b 68 68 44 34 c9 0f 23 ca 76 6f |...."{hhD4..#.vo|
+00000040 f2 97 38 07 43 56 7e b7 ce 67 68 67 37 34 d0 f7 |..8.CV~..ghg74..|
+00000050 c5 92 fd 65 98 b8 7e 5f 48 a8 a3 aa a8 96 65 b5 |...e..~_H.....e.|
+00000060 48 be 91 99 67 0a 37 c7 31 b4 43 ba 26 bb 87 98 |H...g.7.1.C.&...|
+00000070 3c 55 e4 63 b0 33 ca ee 0a a5 fe 36 88 ef cf f0 |<U.c.3.....6....|
+00000080 ab 6b 7d e8 f6 1f 14 12 49 f7 14 b7 12 bb d8 1e |.k}.....I.......|
+00000090 e0 be ed 56 75 b9 ab 8a 20 75 d9 6f 45 2d 71 b3 |...Vu... u.oE-q.|
+000000a0 2f b7 cd 9c c5 16 ed 37 0e 08 15 a5 49 18 7c 13 |/......7....I.|.|
+000000b0 8e 0b 66 01 b1 8c 1d 89 d4 91 9e 5a 6b 94 f6 fa |..f........Zk...|
+000000c0 7b a8 14 1c a7 20 55 c5 e4 0e 9d e0 5b d6 d4 b7 |{.... U.....[...|
+000000d0 1d 93 2b 7c 25 46 28 11 06 57 a3 cb 2f 4b 39 cf |..+|%F(..W../K9.|
+000000e0 61 be 60 9a fd f1 6e e1 a2 a7 20 f2 fd 50 a2 d2 |a.`...n... ..P..|
+000000f0 17 db 16 4f 3f 8c 20 e4 4d 56 37 3b c2 42 17 cc |...O?. .MV7;.B..|
+00000100 5d 99 06 fc 18 0d 1a 88 e8 f9 6f cf 7d 2e 57 73 |].........o.}.Ws|
+00000110 85 47 ed d0 2d b3 9a 05 cf 0c 7d e6 ed 29 95 f4 |.G..-.....}..)..|
+00000120 d5 e0 96 6a 1d 67 3e 5f 43 9f b5 f6 66 f5 84 63 |...j.g>_C...f..c|
+00000130 bd 42 a6 f8 ef 38 42 8a d8 28 dc 55 e5 88 03 76 |.B...8B..(.U...v|
+00000140 96 ba 89 35 63 7e 6c da 39 d8 9a 27 04 ab d5 0e |...5c~l.9..'....|
+00000150 48 89 cc 81 25 44 61 16 2c b2 69 17 03 03 00 59 |H...%Da.,.i....Y|
+00000160 81 8f 94 30 8d fc 47 13 7e 84 06 9b 4a 85 2c bb |...0..G.~...J.,.|
+00000170 b3 a0 0d 4f 50 6a cb 0b 9b 40 ef cc 84 70 1f 69 |...OPj...@...p.i|
+00000180 b9 3e a6 c4 ba 66 eb a9 6f 78 83 7f d4 1f d8 c4 |.>...f..ox......|
+00000190 b0 f6 9b 03 29 7f b1 f8 60 40 0b 28 91 32 2c 03 |....)...`@.(.2,.|
+000001a0 aa 9e 7b fb 99 c2 11 51 1f a7 81 69 16 39 f4 52 |..{....Q...i.9.R|
+000001b0 ca d8 d0 f3 87 6f 58 ab 9a 17 03 03 00 35 de 03 |.....oX......5..|
+000001c0 88 61 50 5c 08 88 77 28 6a 1d 28 44 3d 49 8b 79 |.aP\..w(j.(D=I.y|
+000001d0 d1 a2 13 67 95 0f 7c 18 fe e2 e0 07 f1 ce b9 be |...g..|.........|
+000001e0 79 aa 40 d6 cf 66 53 ac 15 ae 2a 14 a9 63 98 55 |y.@..fS...*..c.U|
+000001f0 96 16 6f 17 03 03 00 17 a8 ac 17 c5 eb d9 8e 77 |..o............w|
+00000200 9e 4b e0 20 c6 0c 34 b6 c3 ab c4 b6 8b b2 77 17 |.K. ..4.......w.|
+00000210 03 03 00 13 58 d4 7b 8f ca 20 41 e3 3f d1 ae cf |....X.{.. A.?...|
+00000220 3d e1 86 91 c0 a1 08 |=......|
diff --git a/src/crypto/tls/testdata/Client-TLSv13-ClientCert-RSA-ECDSA b/src/crypto/tls/testdata/Client-TLSv13-ClientCert-RSA-ECDSA
new file mode 100644
index 0000000..8e361ea
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv13-ClientCert-RSA-ECDSA
@@ -0,0 +1,134 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 30 0a c5 df b0 |....z...v..0....|
+00000010 90 3a 48 4b 20 f1 89 62 be 1f 1b 64 c2 7e 69 25 |.:HK ..b...d.~i%|
+00000020 9f b7 f9 2c 86 e7 40 e7 e8 10 fa 20 00 00 00 00 |...,..@.... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 03 00 00 |................|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 94 |..+.....3.$... .|
+00000060 e8 ab 87 65 c8 dd 6f ee b4 d6 0b bb fd 18 9a 2d |...e..o........-|
+00000070 e4 bc c6 20 98 09 71 65 7d 54 35 73 22 99 1b 14 |... ..qe}T5s"...|
+00000080 03 03 00 01 01 17 03 03 00 17 37 b7 eb eb a2 9f |..........7.....|
+00000090 7f 00 8c 9d a9 50 7c 0c 15 31 63 71 45 7a 3d ee |.....P|..1cqEz=.|
+000000a0 5e 17 03 03 00 42 9f 23 07 cf d0 bc e8 bb 95 01 |^....B.#........|
+000000b0 37 94 18 2e 05 02 8a eb 0a 37 10 79 51 a9 d4 43 |7........7.yQ..C|
+000000c0 18 18 e6 00 9d 68 ff 74 f3 9c 19 bf 5e 51 0c 47 |.....h.t....^Q.G|
+000000d0 61 35 8c b2 58 5f 32 bc 88 c4 fb 5a 22 61 14 98 |a5..X_2....Z"a..|
+000000e0 28 26 8c 75 9d 1d 19 05 17 03 03 02 22 d2 2c 1a |(&.u........".,.|
+000000f0 e5 58 0d d7 0b c4 66 b2 06 90 bc 92 0f 05 34 5d |.X....f.......4]|
+00000100 2b 20 26 02 cc ac 90 40 a0 f1 5f 0e b9 99 7c 0f |+ &....@.._...|.|
+00000110 c9 3e 60 0b 39 ec 6c 94 3a d4 f7 b7 49 5e c7 6e |.>`.9.l.:...I^.n|
+00000120 df 3b cc 33 cb 32 41 53 dd 09 8e 91 97 d2 e0 06 |.;.3.2AS........|
+00000130 5e 0c 4c 49 46 18 83 fc ac b4 f8 76 2d 18 ee 0b |^.LIF......v-...|
+00000140 b6 4a b9 aa eb ee db 7a aa 6d 04 84 ed 8e 15 bc |.J.....z.m......|
+00000150 bf 6f a1 29 bc 0b 9f ba 05 a5 42 82 fd 1c 30 c9 |.o.)......B...0.|
+00000160 20 df 8e ba 28 ab 0b a2 42 09 5e e8 c1 61 d2 25 | ...(...B.^..a.%|
+00000170 fc 05 53 62 91 45 29 54 60 31 b8 4f 01 9c 7b 6a |..Sb.E)T`1.O..{j|
+00000180 04 27 df bc e0 a0 3d b3 80 73 22 ca 9b 41 be b6 |.'....=..s"..A..|
+00000190 09 22 67 1e 54 52 ce 14 b5 56 7a ca 3f a8 3e 01 |."g.TR...Vz.?.>.|
+000001a0 d2 e4 36 18 87 f6 08 19 55 d2 ba 3c a3 c5 11 84 |..6.....U..<....|
+000001b0 62 2a 09 c6 67 de cd ab 66 12 dd 0a 23 77 18 b7 |b*..g...f...#w..|
+000001c0 73 c1 29 61 52 32 95 eb a0 db 72 ae b7 ff 2a b2 |s.)aR2....r...*.|
+000001d0 08 f6 d7 69 32 c2 f8 8b e1 40 a9 d0 fe 11 64 a2 |...i2....@....d.|
+000001e0 a2 dd a7 e6 a6 dd 5d 79 49 df bb c0 83 da 56 7a |......]yI.....Vz|
+000001f0 a5 22 8e 60 df 89 48 e0 e2 e9 5f d5 fe dd ba 34 |.".`..H..._....4|
+00000200 ad 91 52 d8 2f 7e a4 73 50 e8 b7 83 e2 d9 5e 05 |..R./~.sP.....^.|
+00000210 96 08 e4 d4 bb 01 39 99 aa 1d fd 74 1b dc ca c2 |......9....t....|
+00000220 8f bb b8 bf c4 eb 00 6f cc 70 eb 7c c7 29 e4 64 |.......o.p.|.).d|
+00000230 8c 76 a7 b5 79 ea b6 96 fe eb 8f e7 81 9b d1 d0 |.v..y...........|
+00000240 41 16 db ef 9e 55 2a 77 6c 34 54 22 48 6a ca 78 |A....U*wl4T"Hj.x|
+00000250 31 6e d2 00 7f 54 93 65 ec 28 42 66 7b 74 4d 58 |1n...T.e.(Bf{tMX|
+00000260 fe 25 74 bd 9f a4 ff f2 45 06 c6 63 1f 11 68 a4 |.%t.....E..c..h.|
+00000270 fb fe 62 2b f8 19 e3 32 2c cc 5d 71 37 21 05 82 |..b+...2,.]q7!..|
+00000280 c9 c7 30 c7 74 64 d9 f9 6b c2 ae d8 15 2b 2a 79 |..0.td..k....+*y|
+00000290 a0 2d a3 18 1f d7 20 99 96 86 52 32 cf 84 bd 73 |.-.... ...R2...s|
+000002a0 63 85 82 a3 64 fb e3 ea 1b 31 f5 df 1c 74 06 48 |c...d....1...t.H|
+000002b0 69 8a e3 f0 72 8c 59 8b de 0b 06 02 47 54 4c 2d |i...r.Y.....GTL-|
+000002c0 46 ac d4 f5 4d 5c fe 0d bf af d0 37 58 82 3e d2 |F...M\.....7X.>.|
+000002d0 4e c1 7e 0f b0 21 f7 8e 2c 88 db 83 43 ed ad 5b |N.~..!..,...C..[|
+000002e0 0f a2 ce 47 e4 3f dd 1b 71 fe f0 a7 a1 8d 8c dc |...G.?..q.......|
+000002f0 75 e0 7a 89 f7 14 5b 37 9d 35 f6 23 91 a8 d2 1a |u.z...[7.5.#....|
+00000300 96 07 1b 5b 9c 35 27 b8 b9 0c 92 1e cf 1b 3c 17 |...[.5'.......<.|
+00000310 03 03 00 a4 f0 59 e1 1d 62 39 69 c5 53 ae 66 85 |.....Y..b9i.S.f.|
+00000320 df ea 32 73 ca 94 e2 b5 14 d4 30 07 dd fd 2f 9a |..2s......0.../.|
+00000330 16 fc e9 71 4a 20 b8 d2 7e 17 26 ff a9 55 56 24 |...qJ ..~.&..UV$|
+00000340 31 85 bc ea 19 1c 37 b7 fe 8b 47 5f a3 99 0f 5d |1.....7...G_...]|
+00000350 17 92 4b 2a 4c b5 6c db 8f bb 46 ee 89 31 53 79 |..K*L.l...F..1Sy|
+00000360 aa 34 9d 9b e8 9b e7 82 55 a3 92 f6 53 53 d3 72 |.4......U...SS.r|
+00000370 17 23 33 01 e8 75 7e 8d 63 91 a0 67 8f a5 f0 15 |.#3..u~.c..g....|
+00000380 8c f5 81 e2 c4 08 ff 14 1d 96 cf ef 4e 09 18 a1 |............N...|
+00000390 2c 38 0a f7 33 f0 1d ef 9d 12 4d 8c 25 f0 80 a2 |,8..3.....M.%...|
+000003a0 aa a7 cf e4 7c e6 44 58 6d 30 70 48 55 3b b5 79 |....|.DXm0pHU;.y|
+000003b0 55 aa 03 ed 14 ea e5 ee 17 03 03 00 35 72 1a ca |U...........5r..|
+000003c0 5c 3d 3b 75 29 cc a9 09 85 67 89 37 18 91 c0 af |\=;u)....g.7....|
+000003d0 28 d2 0c c9 8b 05 94 04 3a 68 38 f0 c3 db 95 89 |(.......:h8.....|
+000003e0 c8 28 fc 07 4b 49 7d b6 25 36 05 53 96 e0 d9 35 |.(..KI}.%6.S...5|
+000003f0 e5 7c |.||
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 02 11 6a 55 c4 ff 7a |...........jU..z|
+00000010 5b c4 b7 cb 8d ad ae 53 53 3d 41 3a fc 16 44 fd |[......SS=A:..D.|
+00000020 c8 5f 39 c3 5e 6b ee 7d ea 88 9c a9 78 f9 dc 51 |._9.^k.}....x..Q|
+00000030 b2 90 68 7d ae 2c b7 90 6e 79 cf f4 97 50 95 87 |..h}.,..ny...P..|
+00000040 f1 f6 2c 14 bc 2b a3 68 0d e6 c8 66 2f 3b 89 72 |..,..+.h...f/;.r|
+00000050 67 4d d8 e9 8d 6a 89 2a f9 e4 c1 b5 c0 92 16 25 |gM...j.*.......%|
+00000060 61 a6 98 ec b6 6b 52 8b a5 80 5a 9e 6d 03 ad 42 |a....kR...Z.m..B|
+00000070 a9 46 2f d8 e5 67 c9 8d 89 f7 34 93 82 7c a3 bb |.F/..g....4..|..|
+00000080 48 62 06 90 5c 5a aa fd 7c 71 88 24 22 f9 6a 2c |Hb..\Z..|q.$".j,|
+00000090 d1 d9 7e 0a 4c 39 11 e8 c0 17 1d 83 64 f2 2b c6 |..~.L9......d.+.|
+000000a0 c0 81 8c 6a 39 a9 09 aa 1e 58 eb 30 88 59 4d f2 |...j9....X.0.YM.|
+000000b0 d2 64 9f 4c 90 29 c0 66 94 e3 df 12 9c 75 33 24 |.d.L.).f.....u3$|
+000000c0 fb 14 bc 70 e1 b5 de 54 28 b0 3f 01 2c 2e 5f 35 |...p...T(.?.,._5|
+000000d0 e3 01 59 2a 3f ce ca 11 bb 29 97 03 f6 f4 30 b9 |..Y*?....)....0.|
+000000e0 66 db 3c f7 06 41 7b e8 f8 af 3e 03 65 2f 5f 88 |f.<..A{...>.e/_.|
+000000f0 fd 30 45 7a c9 b4 9f bf 03 eb c9 dd 06 ac 82 06 |.0Ez............|
+00000100 e8 81 8e ea 29 45 78 5c 0f 8e 21 8a fb 0b 95 c1 |....)Ex\..!.....|
+00000110 63 e9 18 c1 9a a4 c6 7d 56 4b 9a de 96 dd 37 54 |c......}VK....7T|
+00000120 92 ef 71 42 a8 66 e7 df e7 ea ec 4e 3c b3 8e 7d |..qB.f.....N<..}|
+00000130 ed 92 da 86 e5 fa 51 f8 e4 b0 09 f3 06 4d 38 f1 |......Q......M8.|
+00000140 d5 5f d2 72 1e 5f c3 1e 1d fd 96 70 e7 9c ae ea |._.r._.....p....|
+00000150 62 ce e4 a9 31 34 47 bc f0 9f 1c c7 b6 66 f0 70 |b...14G......f.p|
+00000160 7a e1 c5 a9 76 64 d4 25 0f 56 cd 36 17 67 bd 4d |z...vd.%.V.6.g.M|
+00000170 c7 78 d8 23 46 4b ac 46 34 1a d2 2d c5 e6 67 55 |.x.#FK.F4..-..gU|
+00000180 11 ec 8c f0 67 84 bf 89 ce 3c 71 4e 3a ab ff 22 |....g....<qN:.."|
+00000190 59 23 00 54 4b b6 9e c4 01 a1 9f e1 46 a6 a6 f3 |Y#.TK.......F...|
+000001a0 24 58 0c b4 6e 85 4c c1 8a d6 f8 02 c9 54 fb 85 |$X..n.L......T..|
+000001b0 c7 63 9b 47 28 10 a0 2d b6 c2 83 16 71 ae a7 c2 |.c.G(..-....q...|
+000001c0 e0 dc 8b 6d 57 e0 4b a2 a8 5d 4d 8b ed 72 31 d6 |...mW.K..]M..r1.|
+000001d0 54 33 78 df bb 4a f9 58 9f 8c 2b 11 36 29 a0 f0 |T3x..J.X..+.6)..|
+000001e0 8a 95 20 d8 f1 8c 08 e1 54 0a 81 79 33 20 23 de |.. .....T..y3 #.|
+000001f0 34 c8 2b 45 3a 59 c5 78 39 65 ea 70 e2 fe 59 4c |4.+E:Y.x9e.p..YL|
+00000200 ed 7f 07 07 25 a7 ff fa c9 c3 1f 33 55 c4 16 bb |....%......3U...|
+00000210 c9 b9 e0 2e ff 94 7c de 84 30 60 d6 17 03 03 00 |......|..0`.....|
+00000220 99 53 44 d2 12 38 c4 a7 7e f5 f5 67 b3 79 cf 8a |.SD..8..~..g.y..|
+00000230 34 0f 5d 49 0f bb 5f 30 c8 36 13 61 8d b5 b1 b0 |4.]I.._0.6.a....|
+00000240 dc 73 2f 1a 51 2f d4 8e 25 71 e1 46 af 11 96 19 |.s/.Q/..%q.F....|
+00000250 f7 fe 09 d9 6e 70 d5 fc b9 5b 1c ae ed 06 37 af |....np...[....7.|
+00000260 a1 bf 35 c6 6b 30 33 a2 c4 f6 c8 d4 73 34 73 8e |..5.k03.....s4s.|
+00000270 69 08 be 91 2c 8d 01 52 30 14 b3 d3 a0 7d 8a 9d |i...,..R0....}..|
+00000280 e9 af b2 77 64 eb 16 c1 8e 19 72 ad 4a fd d4 c9 |...wd.....r.J...|
+00000290 08 d0 54 6c f1 06 8c 70 2f e6 ef 23 23 67 96 db |..Tl...p/..##g..|
+000002a0 5f aa 81 6c 41 17 6b f4 30 ce 00 d6 a2 d8 28 f8 |_..lA.k.0.....(.|
+000002b0 be 9f 04 94 fa e3 fa 76 d0 30 17 03 03 00 35 9b |.......v.0....5.|
+000002c0 43 c4 8f dc b7 a1 44 4e 00 66 0a 95 a6 d7 46 79 |C.....DN.f....Fy|
+000002d0 30 2d 57 51 4e 21 a7 ed 43 e7 22 2d eb 07 9b 7d |0-WQN!..C."-...}|
+000002e0 ea a4 ff 14 5d 97 1f d5 e8 f1 3d 8d e3 13 b6 79 |....].....=....y|
+000002f0 36 ce 83 e8 17 03 03 00 17 d5 98 a6 a3 b7 40 2b |6.............@+|
+00000300 26 87 2f 4f 64 95 f1 2d e0 7b e3 98 c2 81 dc 7b |&./Od..-.{.....{|
+00000310 17 03 03 00 13 5b ab 65 e4 b1 d0 bd e9 c6 b2 3a |.....[.e.......:|
+00000320 4b 66 ce eb 25 0c bc 7d |Kf..%..}|
diff --git a/src/crypto/tls/testdata/Client-TLSv13-ClientCert-RSA-RSAPSS b/src/crypto/tls/testdata/Client-TLSv13-ClientCert-RSA-RSAPSS
new file mode 100644
index 0000000..2367a39
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv13-ClientCert-RSA-RSAPSS
@@ -0,0 +1,143 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 a9 f1 13 c3 3c |....z...v......<|
+00000010 1c dd c9 3a a1 ad 92 92 f1 f4 16 39 be 14 64 9c |...:.......9..d.|
+00000020 66 d8 28 cd b7 bb 40 43 ec f4 67 20 00 00 00 00 |f.(...@C..g ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 03 00 00 |................|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 ff |..+.....3.$... .|
+00000060 53 ac b3 b0 48 47 d0 1e b1 70 eb dd 02 e5 e8 07 |S...HG...p......|
+00000070 ce c7 e0 af d7 e0 46 c7 ff f5 97 30 e5 80 5b 14 |......F....0..[.|
+00000080 03 03 00 01 01 17 03 03 00 17 0b 12 ef 6d ea 5e |.............m.^|
+00000090 71 41 83 d6 35 9f 39 2c f0 ab 01 e9 03 54 c6 9e |qA..5.9,.....T..|
+000000a0 37 17 03 03 00 20 15 7a 35 f4 a6 6e 65 89 10 ae |7.... .z5..ne...|
+000000b0 18 31 c0 0c 15 1c b8 c5 5d f3 54 0c 98 32 a4 5e |.1......].T..2.^|
+000000c0 91 f7 03 8a 80 b9 17 03 03 02 7a fa 93 7f c6 d1 |..........z.....|
+000000d0 2f 7e 2d d6 1b b7 ff fd 96 6e a1 f7 0e 98 dc 77 |/~-......n.....w|
+000000e0 cc 6a 4e 91 3d c1 ad 4b 5c 28 ee ea a7 0a ce 8f |.jN.=..K\(......|
+000000f0 51 dd 89 fd 5a 81 6d 21 d6 0d 35 70 84 73 8c fa |Q...Z.m!..5p.s..|
+00000100 2e 7a e0 af ab 79 79 aa 67 2b 80 a8 b3 a8 fb 0d |.z...yy.g+......|
+00000110 eb 87 66 d5 be 33 0b f0 80 b8 5e 21 84 be 25 fe |..f..3....^!..%.|
+00000120 47 98 5a 26 5d c3 96 2e c5 b8 da 9f a6 d4 ca bb |G.Z&]...........|
+00000130 de 7f 2c 0a 28 a8 f3 41 bc a2 2e 70 f2 b3 6f a3 |..,.(..A...p..o.|
+00000140 10 0e 1f 11 af 11 50 2b 22 84 97 d7 80 f5 62 77 |......P+".....bw|
+00000150 a6 94 47 22 ef 24 c6 0e dc 5c f5 40 08 f7 21 78 |..G".$...\.@..!x|
+00000160 ae 11 f3 d8 a5 d8 20 ac 90 73 d7 a2 e3 f0 08 57 |...... ..s.....W|
+00000170 fc 74 70 66 fd 3d 49 c7 99 37 98 5e b1 1c c4 38 |.tpf.=I..7.^...8|
+00000180 64 09 e6 70 b6 8b 00 72 2d 5b b4 70 39 d6 e9 d5 |d..p...r-[.p9...|
+00000190 dc cd 8e 01 eb 5f 34 61 d0 97 62 0b 4f 81 ed 30 |....._4a..b.O..0|
+000001a0 64 56 f2 6e 31 5e 24 e8 56 2b d6 31 54 c4 48 47 |dV.n1^$.V+.1T.HG|
+000001b0 16 00 a7 65 c1 fa ea 12 30 78 41 e7 30 2d 71 cf |...e....0xA.0-q.|
+000001c0 b0 e9 be e4 a2 33 38 87 2d 37 14 2d 03 cf ae 87 |.....38.-7.-....|
+000001d0 9a 09 f2 ed f3 44 66 c3 8a 56 8e e4 c4 aa e9 f7 |.....Df..V......|
+000001e0 cd 75 52 1b d9 ed 66 04 13 dd dd cf 0f 44 cd 18 |.uR...f......D..|
+000001f0 68 c5 2c 4c f9 e3 d3 02 12 78 38 5c f6 96 d7 80 |h.,L.....x8\....|
+00000200 f0 83 03 fe 7a e0 35 7e a3 ad 99 52 ec fc ee 74 |....z.5~...R...t|
+00000210 f5 09 0f ca 69 f0 fb d0 40 90 1b 46 9e 2d 62 c9 |....i...@..F.-b.|
+00000220 0f 59 b2 cc a0 4a 9b 84 14 3a 1b 51 fc e7 e8 a1 |.Y...J...:.Q....|
+00000230 26 fd 20 8c 88 6f 87 11 ae 97 76 f8 4b cc 67 1a |&. ..o....v.K.g.|
+00000240 3e 58 65 77 77 82 06 c0 d4 41 4e 66 d2 5a 83 b1 |>Xeww....ANf.Z..|
+00000250 ee 19 5d 7b 99 34 d3 2f 6c bd 30 a3 8c 75 89 ec |..]{.4./l.0..u..|
+00000260 cb 90 8b 89 05 b8 e4 6e 3b 60 5d 0e 19 8f d6 c7 |.......n;`].....|
+00000270 86 f0 a9 2b c7 12 4a 4c d8 a5 e8 64 49 1d 49 99 |...+..JL...dI.I.|
+00000280 a7 80 01 f0 77 57 4a 78 3c ac 38 40 bb d2 10 24 |....wWJx<.8@...$|
+00000290 9d e2 29 b2 1e 4b 50 66 64 07 79 80 c7 81 9d e2 |..)..KPfd.y.....|
+000002a0 f5 a9 10 9a 8d 3b de 0e 21 85 13 ac 26 30 f9 e4 |.....;..!...&0..|
+000002b0 a6 f9 8f e0 3c c1 69 7e 11 4c d1 a8 4e 88 30 fc |....<.i~.L..N.0.|
+000002c0 52 6e b0 4f b6 7e 15 9e a5 8a 46 ca 1f ac 8e 2a |Rn.O.~....F....*|
+000002d0 07 34 d7 c2 14 c6 c1 ed a1 f9 1e 59 b4 b4 86 3e |.4.........Y...>|
+000002e0 d3 d0 78 a6 07 62 d3 88 80 54 a8 2a e9 38 2e 58 |..x..b...T.*.8.X|
+000002f0 43 94 cc ed f0 46 f6 cc 4b 7a b8 f5 a2 d6 a8 36 |C....F..Kz.....6|
+00000300 e2 8e 11 fb e7 21 19 c5 fa c9 90 98 72 43 88 ac |.....!......rC..|
+00000310 c0 56 84 9e cd b7 e5 26 d6 49 19 88 a5 12 ac 49 |.V.....&.I.....I|
+00000320 5d 77 37 2a ff 38 5a 7a 5b c8 74 5d 74 fc 22 7f |]w7*.8Zz[.t]t.".|
+00000330 46 97 2b 34 32 fb 83 65 75 b6 8b 5c 8a b1 d4 a2 |F.+42..eu..\....|
+00000340 14 7f 46 0d 63 17 03 03 00 99 c7 79 bb 4f 88 a0 |..F.c......y.O..|
+00000350 78 be 04 ca 39 1f 1f a8 82 59 b5 dd 96 93 0d c4 |x...9....Y......|
+00000360 30 f4 22 4c e2 52 51 d4 33 b8 35 7b ed 01 19 25 |0."L.RQ.3.5{...%|
+00000370 b5 31 36 25 23 a2 51 d9 7a a9 00 72 05 34 81 62 |.16%#.Q.z..r.4.b|
+00000380 d0 df 8b 3a 65 98 4e 87 e2 29 9b 44 77 8c dd c9 |...:e.N..).Dw...|
+00000390 4c a5 de 14 97 e0 f1 2c e8 5d 0e 8f d0 fd f6 77 |L......,.].....w|
+000003a0 c1 1f ac 79 4d 32 19 09 98 a8 f0 2f 3e d5 7e f7 |...yM2...../>.~.|
+000003b0 aa c1 f0 36 b1 8e c7 0b ce 09 00 ac 28 64 c0 33 |...6........(d.3|
+000003c0 58 cc 48 3a 15 a4 77 24 50 67 f2 39 53 4d 63 23 |X.H:..w$Pg.9SMc#|
+000003d0 48 74 bd 0a c8 02 17 be e4 64 af 6e 02 a9 22 92 |Ht.......d.n..".|
+000003e0 65 04 c6 17 03 03 00 35 e0 4e 15 4b 9d 53 57 c6 |e......5.N.K.SW.|
+000003f0 97 b4 9d 1a 03 39 26 b9 ca 5b 04 50 af db 52 99 |.....9&..[.P..R.|
+00000400 d9 13 40 6a 89 23 99 42 9a 91 1d d1 6c 07 a0 aa |..@j.#.B....l...|
+00000410 05 6e 60 0b fd e7 de 32 c3 97 18 0d 9b |.n`....2.....|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 02 7a 94 78 2d 5d 5a |..........z.x-]Z|
+00000010 3e 96 7f 19 29 51 99 f3 6e d3 a4 d5 3c 9a 3d d5 |>...)Q..n...<.=.|
+00000020 37 bc 3b 71 b3 54 83 d9 5e 9d 64 76 f9 74 7a 24 |7.;q.T..^.dv.tz$|
+00000030 e3 cb ea aa 17 f4 44 41 73 71 39 d6 9b d5 a6 a2 |......DAsq9.....|
+00000040 6a 1e 1c 02 a1 d5 e3 e8 f5 f7 07 9d 3b ea f8 6d |j...........;..m|
+00000050 80 cf 6b 14 71 b8 bd c4 8a 07 49 31 e7 bd d5 91 |..k.q.....I1....|
+00000060 ac 80 70 25 5e f4 db 07 ed 36 c2 3a 1d ad 86 6e |..p%^....6.:...n|
+00000070 68 1a ca 4f a1 ba c3 2f de 49 01 fa a9 39 a6 51 |h..O.../.I...9.Q|
+00000080 3a e6 9f cf 6b 02 4e 1e 70 dd f2 10 c2 62 9b 1f |:...k.N.p....b..|
+00000090 83 10 fa 85 52 a8 a7 08 37 9c 92 b0 9c fe 00 78 |....R...7......x|
+000000a0 0b a4 7b b5 f9 9f 87 d2 d3 07 72 b2 ab 96 9e 73 |..{.......r....s|
+000000b0 55 3c 1e 65 99 89 36 78 7e 42 8f 05 de b6 fb fc |U<.e..6x~B......|
+000000c0 1b 34 18 e6 4d 15 6c d1 2f 2c b0 ef 00 e9 07 89 |.4..M.l./,......|
+000000d0 ca 91 d9 c1 73 bf 8f a5 a4 7d 7e cc f5 85 fb af |....s....}~.....|
+000000e0 57 70 35 63 71 d6 78 57 13 48 27 ba a4 42 22 c2 |Wp5cq.xW.H'..B".|
+000000f0 56 f4 ae 38 39 a0 1f 57 44 57 c4 8a 70 90 30 70 |V..89..WDW..p.0p|
+00000100 ba 4a 98 29 0f aa e2 33 27 24 ee d9 e9 02 80 68 |.J.)...3'$.....h|
+00000110 4c 55 08 fb 3d 25 d6 d4 9d 83 ea 14 99 c2 77 94 |LU..=%........w.|
+00000120 f9 70 34 a8 ed 35 e6 4f c2 75 50 63 d5 9d 9a 89 |.p4..5.O.uPc....|
+00000130 8f 2e 5b ca 6b b3 ad e7 a2 c6 f7 0c 45 08 b7 f4 |..[.k.......E...|
+00000140 58 d3 d5 54 c2 67 f3 76 fb fc 9d fe 42 43 ea 90 |X..T.g.v....BC..|
+00000150 2b 29 e7 10 2f d7 9c 04 c4 cc 89 8f a9 36 14 f6 |+)../........6..|
+00000160 fc f1 25 6c 90 12 bf c6 cd ad 46 ce 17 3b 26 fb |..%l......F..;&.|
+00000170 c6 98 cb 6c f2 2c fd b9 2f 52 3e 56 42 78 0b 92 |...l.,../R>VBx..|
+00000180 a5 27 56 18 3d d6 26 3f e4 a1 6f ce c8 f1 f1 7a |.'V.=.&?..o....z|
+00000190 1f 84 66 c9 d9 8a 5c 0e 34 80 ba 58 b3 8b 7f f3 |..f...\.4..X....|
+000001a0 8a c9 6b c4 99 94 2c b7 e8 e8 9a a5 43 75 f8 e0 |..k...,.....Cu..|
+000001b0 29 1f 70 77 c7 4a 9f de ca 92 88 7c 37 12 d9 ef |).pw.J.....|7...|
+000001c0 2f 94 de ea d1 d9 69 6a 93 06 36 e0 68 02 53 ae |/.....ij..6.h.S.|
+000001d0 0e 00 cd ad d3 10 a7 89 2c 53 a7 03 d9 07 3c e9 |........,S....<.|
+000001e0 0b b0 18 2e 03 88 03 5c f4 b2 7e 59 f4 22 8c f7 |.......\..~Y."..|
+000001f0 5e d7 c7 ea ac 0f bc f7 3e 3f 75 fd 6d 9c 4c 3c |^.......>?u.m.L<|
+00000200 41 8d f5 30 17 20 83 c3 27 83 ce 84 6a e3 75 2b |A..0. ..'...j.u+|
+00000210 9d 7d de 2a bf 5a fb e1 2f 80 74 74 f6 09 bc 1f |.}.*.Z../.tt....|
+00000220 be f0 59 9e ce a1 62 46 54 a4 9a 25 97 b7 cd 1a |..Y...bFT..%....|
+00000230 0a d0 44 f6 ea a4 ed 63 e7 49 9a 4b f4 1a 39 91 |..D....c.I.K..9.|
+00000240 e6 34 e1 7b dd e7 53 ab 83 56 57 b2 89 3f 90 1f |.4.{..S..VW..?..|
+00000250 98 c4 64 27 b5 f5 f6 57 16 ca d9 0a 33 de 24 c3 |..d'...W....3.$.|
+00000260 f3 7c 23 37 94 93 c5 1a 42 da 18 6b 24 dd 37 54 |.|#7....B..k$.7T|
+00000270 ae f3 8a 3e 10 42 20 6e 49 23 1a 0f bd 65 7e 45 |...>.B nI#...e~E|
+00000280 12 7a 64 9a 30 17 03 03 00 99 af 41 cf 95 21 1f |.zd.0......A..!.|
+00000290 34 df 1c c7 a8 b6 ee 31 8d b3 9e 5a 59 8e c4 37 |4......1...ZY..7|
+000002a0 79 a4 d8 75 22 da 12 21 e5 de d4 ad 98 17 e2 ae |y..u"..!........|
+000002b0 ae 9f f6 e8 29 66 d0 ac b4 08 16 24 40 67 9d d5 |....)f.....$@g..|
+000002c0 bf a4 64 91 a1 17 82 c0 e7 77 b6 20 26 4a 70 1d |..d......w. &Jp.|
+000002d0 c8 f8 ec 18 b7 c6 3c 81 b9 c6 04 9c 0d 37 a6 39 |......<......7.9|
+000002e0 fd 2d 99 d7 ba 41 a4 91 60 f1 1f d2 76 76 aa 47 |.-...A..`...vv.G|
+000002f0 89 0a d1 97 0b 91 20 a9 43 c9 ce 2c 84 ba 81 7a |...... .C..,...z|
+00000300 39 91 7d 12 75 05 8e 87 b1 3f 80 8d 12 ca 8f 91 |9.}.u....?......|
+00000310 23 84 28 11 c3 81 ed 09 05 16 6e 50 57 76 ad 5c |#.(.......nPWv.\|
+00000320 c5 92 77 17 03 03 00 35 5a d9 15 29 1f a3 f0 cf |..w....5Z..)....|
+00000330 74 c4 1d 0c c3 fa 54 59 1e 54 06 0d 1b ce 07 00 |t.....TY.T......|
+00000340 f9 66 3d e1 75 10 cf de cb 7d 0d d6 d1 4d 87 81 |.f=.u....}...M..|
+00000350 13 ec 2c 28 13 a5 b3 01 c7 86 3a 84 65 17 03 03 |..,(......:.e...|
+00000360 00 17 b4 e4 18 61 62 04 b3 ca 98 36 93 42 a2 be |.....ab....6.B..|
+00000370 2c f5 18 11 bd 7d 64 70 bc 17 03 03 00 13 32 65 |,....}dp......2e|
+00000380 fa 07 3e 3c ed 9d 85 31 ba 8e 92 ea de 17 59 cd |..><...1......Y.|
+00000390 db |.|
diff --git a/src/crypto/tls/testdata/Client-TLSv13-ECDSA b/src/crypto/tls/testdata/Client-TLSv13-ECDSA
new file mode 100644
index 0000000..dac9ef7
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv13-ECDSA
@@ -0,0 +1,86 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 e3 21 e8 24 fb |....z...v...!.$.|
+00000010 e8 fe 46 e2 54 a7 db 98 ae a4 b2 fc f8 17 99 b4 |..F.T...........|
+00000020 ed 6a aa 9c f9 ce e2 0f f8 88 05 20 00 00 00 00 |.j......... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 03 00 00 |................|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 a9 |..+.....3.$... .|
+00000060 5a 5c e9 b1 71 e8 a8 64 97 65 02 6b 3d 25 6f 6f |Z\..q..d.e.k=%oo|
+00000070 9a 47 cb 4a 81 ac 89 23 22 c1 f4 3d db 77 1e 14 |.G.J...#"..=.w..|
+00000080 03 03 00 01 01 17 03 03 00 17 12 15 75 15 9f 10 |............u...|
+00000090 90 07 34 9c eb 05 d0 a1 4b 36 5b 4c 7b 26 2a 00 |..4.....K6[L{&*.|
+000000a0 29 17 03 03 02 22 85 a0 67 d7 72 57 83 19 79 12 |)...."..g.rW..y.|
+000000b0 b7 bd 37 ed ab 49 5d 15 49 2b 4f a1 b2 25 08 22 |..7..I].I+O..%."|
+000000c0 88 83 70 07 bc 8f 69 45 1b 21 36 99 f4 99 40 f8 |..p...iE.!6...@.|
+000000d0 0d 30 13 87 70 68 f6 9d ce c7 9e 25 2c 1e 7a b5 |.0..ph.....%,.z.|
+000000e0 52 ed f8 0f f7 d9 e5 15 fc a3 47 83 0d 18 c4 de |R.........G.....|
+000000f0 a1 a6 24 35 aa 56 d1 8b 95 07 5f 0f ba 1f 96 c3 |..$5.V...._.....|
+00000100 5b 36 cc d2 15 e6 b4 88 8f e3 7f 79 c2 24 d5 f3 |[6.........y.$..|
+00000110 a7 35 69 4e d2 2a f7 5c 08 8a c0 26 dd b9 77 5b |.5iN.*.\...&..w[|
+00000120 96 1b 5f 03 89 07 a0 6a b1 14 1d 02 46 08 eb 80 |.._....j....F...|
+00000130 d5 4c dc 69 63 8f 14 a1 e5 02 95 05 8a 8b c8 68 |.L.ic..........h|
+00000140 c3 d8 75 56 47 94 32 ba 67 71 ed 4b b4 62 ba 6a |..uVG.2.gq.K.b.j|
+00000150 31 20 a7 d6 f8 8c a0 e9 e8 d2 1a 6b 85 6b b7 ee |1 .........k.k..|
+00000160 78 e1 2e 4c 14 f0 b3 3e b8 dc 7d af f0 9d 29 f3 |x..L...>..}...).|
+00000170 54 1d 9d dc 9e a3 9f 29 5b 33 1d f7 00 98 85 bd |T......)[3......|
+00000180 42 39 85 75 cf fa dc f3 7e 80 14 4e a5 90 80 b6 |B9.u....~..N....|
+00000190 e3 37 d3 27 c6 7b b9 ee 32 61 a5 72 e5 2f a6 ab |.7.'.{..2a.r./..|
+000001a0 cb 8e ac 53 4b 86 24 92 4b 77 d6 8d aa b4 37 d5 |...SK.$.Kw....7.|
+000001b0 2b b2 2f 07 23 37 4a d9 1f cc 6c 72 c6 21 5b 38 |+./.#7J...lr.![8|
+000001c0 a3 33 5c 86 50 69 34 8f 5a b8 cc 5e 82 7d 5b b2 |.3\.Pi4.Z..^.}[.|
+000001d0 5b f5 58 7f 2c 61 08 4b 3d 8b 67 09 19 01 d2 4f |[.X.,a.K=.g....O|
+000001e0 06 62 17 4e d4 bf 88 89 bb c4 6e 14 2b 3a 50 c9 |.b.N......n.+:P.|
+000001f0 56 8a c1 0a 45 e6 67 32 f3 96 37 4b ba c2 2a 2b |V...E.g2..7K..*+|
+00000200 84 e1 ff bb e0 ea 68 9b 98 fc 78 26 25 f6 50 25 |......h...x&%.P%|
+00000210 52 57 83 94 39 b9 a7 8d 38 43 70 a8 b7 61 a6 cf |RW..9...8Cp..a..|
+00000220 09 77 db 3d 64 94 63 73 5b a1 6d f4 06 c1 b3 fb |.w.=d.cs[.m.....|
+00000230 c6 9a 0b ea 9f 8e 6d 58 53 0e 13 e0 a6 21 69 7a |......mXS....!iz|
+00000240 d3 57 32 d4 c6 32 ef 02 8e 54 1d 72 2d d6 a7 dc |.W2..2...T.r-...|
+00000250 59 54 be 69 3f 5c 53 23 a9 f7 3e a9 e6 e7 e0 98 |YT.i?\S#..>.....|
+00000260 65 f6 74 f4 49 1c 77 0f 92 34 87 81 29 85 d1 e0 |e.t.I.w..4..)...|
+00000270 1e 4d b4 eb c2 44 43 a7 10 51 7c 5e 8e a4 b6 37 |.M...DC..Q|^...7|
+00000280 78 e8 35 02 07 3d 60 a5 01 75 01 25 f3 ff 32 ff |x.5..=`..u.%..2.|
+00000290 34 ab a4 c3 4c ad 21 b8 91 0a d6 54 4b 7d cf c5 |4...L.!....TK}..|
+000002a0 ec 0f e5 4a 4d 75 4c ec fc 37 2b 26 5a 73 93 70 |...JMuL..7+&Zs.p|
+000002b0 88 c7 9c cf 32 f9 ee a7 27 6e 1d 9e 36 a2 31 9e |....2...'n..6.1.|
+000002c0 cd 0e c2 89 ef 2b 40 1a 17 03 03 00 a4 ad 19 05 |.....+@.........|
+000002d0 e6 40 5e b1 ec 69 6b 47 ef 5d d3 ee a6 94 51 85 |.@^..ikG.]....Q.|
+000002e0 d8 28 d9 df 8b d0 df 23 7e bd 98 6c 33 26 45 fa |.(.....#~..l3&E.|
+000002f0 60 71 8b f5 71 5c 22 4e b3 a7 01 fe 17 39 89 67 |`q..q\"N.....9.g|
+00000300 0b 70 ff 52 b9 10 9c e9 02 c0 1c 56 9d c8 45 51 |.p.R.......V..EQ|
+00000310 5a dd 86 79 6d a7 7d eb 16 c2 1a 5f 6a 3b 93 42 |Z..ym.}...._j;.B|
+00000320 13 f3 3d 8a 39 21 5f a9 7f cf 4b 1e 22 f1 a3 f8 |..=.9!_...K."...|
+00000330 5c 35 41 2a e2 91 72 4f 59 61 1c 15 be 27 6a bd |\5A*..rOYa...'j.|
+00000340 b7 16 1f 63 97 51 d6 96 dd 81 f9 e7 fd 97 33 6e |...c.Q........3n|
+00000350 da 5a 61 77 57 6e 3b 65 24 db b3 3a 18 7b dc f4 |.ZawWn;e$..:.{..|
+00000360 7c ff ab 43 7f 1b ae ae b8 73 71 9e be 91 d6 56 ||..C.....sq....V|
+00000370 13 17 03 03 00 35 39 61 a3 b7 e5 1d 3d 87 92 84 |.....59a....=...|
+00000380 11 39 7d f4 ce 29 b9 4b fd 3c 0c 5a b6 3a fa e2 |.9}..).K.<.Z.:..|
+00000390 a8 5b e6 d2 e5 7e e3 a6 33 59 e4 a8 59 95 5d b9 |.[...~..3Y..Y.].|
+000003a0 31 6d 51 90 22 be c0 3f 6e 43 f2 |1mQ."..?nC.|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 50 4f ce ae a5 |..........5PO...|
+00000010 f7 b0 7e 2b 91 86 72 da 90 65 fd 1b a5 46 c6 98 |..~+..r..e...F..|
+00000020 47 90 5a f2 b8 5a 1f 18 44 19 bd ca dd 2a 15 e7 |G.Z..Z..D....*..|
+00000030 53 f5 17 e8 7d 9b f1 9a 63 ac b0 b0 df c3 0e 4c |S...}...c......L|
+00000040 17 03 03 00 17 8b bd fb bc fd f7 af 53 9b 8b 1a |............S...|
+00000050 a3 e5 f6 e9 87 bd 4a 8a 1b 0e c9 d9 17 03 03 00 |......J.........|
+00000060 13 8e c6 d3 6e 04 8f 3b d4 76 a4 c7 c8 63 a8 a8 |....n..;.v...c..|
+00000070 9e ba e7 fd |....|
diff --git a/src/crypto/tls/testdata/Client-TLSv13-Ed25519 b/src/crypto/tls/testdata/Client-TLSv13-Ed25519
new file mode 100644
index 0000000..d284740
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv13-Ed25519
@@ -0,0 +1,68 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 6f b6 d3 79 9b |....z...v..o..y.|
+00000010 00 17 a8 46 3f e4 bc fc 08 1e 56 6c d8 63 86 f3 |...F?.....Vl.c..|
+00000020 83 1b d8 26 6d 86 d6 4c f3 4f e1 20 00 00 00 00 |...&m..L.O. ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 03 00 00 |................|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 5b |..+.....3.$... [|
+00000060 8f 4f 5a a9 95 6b 04 07 31 d3 ed 91 8b 25 b4 7b |.OZ..k..1....%.{|
+00000070 5c a1 0a a6 26 09 92 9b b0 72 26 f9 0d 09 60 14 |\...&....r&...`.|
+00000080 03 03 00 01 01 17 03 03 00 17 a8 99 d3 76 1f 12 |.............v..|
+00000090 19 18 15 8e 4c 59 43 92 11 4a aa 50 98 7e 4c d9 |....LYC..J.P.~L.|
+000000a0 63 17 03 03 01 50 66 f5 d6 ce 35 0f 10 e5 ab 34 |c....Pf...5....4|
+000000b0 78 17 c6 b6 60 40 eb 53 34 9f ce 02 c4 36 51 18 |x...`@.S4....6Q.|
+000000c0 c2 b3 fb f3 98 92 d0 f2 b7 be 28 f5 c7 2d fa 1f |..........(..-..|
+000000d0 9b 8b aa e5 45 54 6b 0e ed 6b 44 cb d4 4d 62 b2 |....ETk..kD..Mb.|
+000000e0 30 c9 df ac cf a3 7e 43 58 1e bf 6e 5b 69 4e 48 |0.....~CX..n[iNH|
+000000f0 1c 39 49 eb 8a 0c 22 f3 70 4a 80 50 39 d6 68 29 |.9I...".pJ.P9.h)|
+00000100 d0 6d 08 20 26 39 6d 37 5a 9f 79 e9 16 e3 7e 94 |.m. &9m7Z.y...~.|
+00000110 8f 5f 9b 97 2d e1 b1 48 e4 a3 36 63 40 5a 80 93 |._..-..H..6c@Z..|
+00000120 06 27 3b 93 d9 ed 2d b1 3e 74 ed bc 38 a1 cb 17 |.';...-.>t..8...|
+00000130 06 4a 9b c1 c1 d7 7a 1c ca ff 4d ee 91 6d d0 3c |.J....z...M..m.<|
+00000140 c2 4b cc 33 c6 7c 76 8e db a2 e0 fe 15 e2 ec db |.K.3.|v.........|
+00000150 1f 5d 05 c8 5e 0e 7f 2c 7a 95 08 34 68 a2 2c 7c |.]..^..,z..4h.,||
+00000160 04 16 92 7a c8 ec 52 2d 1a c4 7a ea 12 cd 0f b9 |...z..R-..z.....|
+00000170 7c 00 51 55 02 5b 02 7d ec 89 af f5 6d 76 89 0e ||.QU.[.}....mv..|
+00000180 67 42 f0 e4 67 4d 3f 70 ff 2c 64 81 1c 4a 92 1f |gB..gM?p.,d..J..|
+00000190 26 8b a4 4f 15 18 b5 11 4a 61 df 45 53 74 fd 8d |&..O....Ja.ESt..|
+000001a0 ff 22 32 91 af c7 7f a4 7b 62 c3 3b 30 51 b6 34 |."2.....{b.;0Q.4|
+000001b0 b6 01 21 f9 86 74 be 62 27 1a 41 1f f0 0d 8b 5c |..!..t.b'.A....\|
+000001c0 4b 82 ea 76 23 9c 36 af 25 1f f6 2d 5f 9c 28 bd |K..v#.6.%..-_.(.|
+000001d0 b6 d5 1e 26 8b c1 dc ac ed 6d 10 ff 13 ed fc 08 |...&.....m......|
+000001e0 08 0a 74 1c b1 5b f8 45 e4 83 44 f2 be ce 8d ac |..t..[.E..D.....|
+000001f0 ee ae e6 21 da c7 17 03 03 00 59 d9 b3 95 0a f7 |...!......Y.....|
+00000200 1a 1a 54 fa ab 09 38 6d 6d 53 0a ef 11 73 bc a2 |..T...8mmS...s..|
+00000210 20 03 31 48 e2 0a d1 af 56 6c ca dd 88 ba 72 3a | .1H....Vl....r:|
+00000220 c1 e0 c5 60 44 74 d6 c9 18 23 96 2c e7 88 c8 3e |...`Dt...#.,...>|
+00000230 02 73 c0 38 d4 bd 85 a4 bb 78 a0 ba d3 fd f1 c4 |.s.8.....x......|
+00000240 27 08 05 fb 2c 26 20 b7 1a 41 87 a6 b7 97 19 26 |'...,& ..A.....&|
+00000250 50 ed 9a e4 17 03 03 00 35 68 36 c7 78 c3 5e ff |P.......5h6.x.^.|
+00000260 b3 92 a7 25 31 2a a2 fa 24 d9 da 69 16 03 8b db |...%1*..$..i....|
+00000270 fe b2 3f 63 88 49 f1 14 63 7a 58 a9 6f c5 64 92 |..?c.I..czX.o.d.|
+00000280 21 84 82 d8 49 98 fb f3 f1 fd 52 83 32 97 |!...I.....R.2.|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 07 7b a2 7a 4f |..........5.{.zO|
+00000010 40 e9 a2 94 9f b7 2d 91 87 1e 37 b0 ca b7 ea 91 |@.....-...7.....|
+00000020 53 f1 bf 7d 56 6a 0c 6a 9d 07 ac 93 9c db ca ac |S..}Vj.j........|
+00000030 43 7b eb 56 9d 6c 79 f2 72 f8 0b 8d 15 08 84 d5 |C{.V.ly.r.......|
+00000040 17 03 03 00 17 07 b3 7d a9 56 c4 76 e5 12 97 29 |.......}.V.v...)|
+00000050 b7 99 e6 3e 08 79 2d fb 1a 5b eb 7a 17 03 03 00 |...>.y-..[.z....|
+00000060 13 66 b7 65 57 0d 54 7b 6a 34 98 a1 4e 29 d5 92 |.f.eW.T{j4..N)..|
+00000070 1e b6 52 bc |..R.|
diff --git a/src/crypto/tls/testdata/Client-TLSv13-ExportKeyingMaterial b/src/crypto/tls/testdata/Client-TLSv13-ExportKeyingMaterial
new file mode 100644
index 0000000..a0ede61
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv13-ExportKeyingMaterial
@@ -0,0 +1,90 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 d6 7f ef 2d f6 |....z...v.....-.|
+00000010 82 d9 be 6d 33 80 73 c0 d4 d8 63 e9 95 a6 5b 1f |...m3.s...c...[.|
+00000020 ce c0 ec 13 07 f4 68 7d cc 79 18 20 00 00 00 00 |......h}.y. ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 03 00 00 |................|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 00 |..+.....3.$... .|
+00000060 e9 40 7a 65 78 98 47 43 aa e1 63 fd 6b c4 21 1d |.@zex.GC..c.k.!.|
+00000070 58 45 5f 64 a0 18 55 a0 c3 14 7d 4e 12 93 7c 14 |XE_d..U...}N..|.|
+00000080 03 03 00 01 01 17 03 03 00 17 4c 01 0b f7 e7 1b |..........L.....|
+00000090 a9 47 84 10 3b 50 85 6e 3d 8e 52 bc 99 bf d4 35 |.G..;P.n=.R....5|
+000000a0 45 17 03 03 02 6d 8c b3 22 04 de 8b 09 e5 e7 9f |E....m..".......|
+000000b0 d5 1f fb 8a 57 ad a7 93 4c 5f 29 46 df c3 e5 86 |....W...L_)F....|
+000000c0 66 f1 c7 6b 14 79 cf 9d cc e1 f5 3f 31 2c dc ff |f..k.y.....?1,..|
+000000d0 77 99 14 9e 56 12 4e a4 cb 56 5c d6 c0 5b 57 dc |w...V.N..V\..[W.|
+000000e0 22 72 12 2d d6 a0 8a c7 90 e6 41 66 78 1a d7 a6 |"r.-......Afx...|
+000000f0 87 db f1 e3 9b 86 8c cf 94 22 cf 81 99 20 bc 19 |........."... ..|
+00000100 50 f9 fe 6c ab ea d4 a2 ee f8 17 1d ae 37 86 2a |P..l.........7.*|
+00000110 f9 83 3c 59 d0 aa 63 22 18 d5 12 40 be f7 02 f1 |..<Y..c"...@....|
+00000120 9a bf 07 39 23 73 23 a1 66 70 b7 be 9a 24 de 30 |...9#s#.fp...$.0|
+00000130 2f 62 6e f8 d5 ee 69 a7 87 3c 73 10 4c 7c 97 42 |/bn...i..<s.L|.B|
+00000140 62 b9 d5 74 40 f0 d7 b3 74 42 73 d7 41 bc 35 43 |b..t@...tBs.A.5C|
+00000150 87 2e c5 1b e9 15 e8 5e 18 b9 6b 57 2a ee 59 7a |.......^..kW*.Yz|
+00000160 1c a6 2b cb b4 db e8 bb 99 87 74 4a ee 57 3a 87 |..+.......tJ.W:.|
+00000170 3c 2d b9 76 41 4a 7a a5 6a fa 92 e9 80 24 08 dc |<-.vAJz.j....$..|
+00000180 18 44 4b 59 7c 81 99 29 f2 c4 55 b6 58 71 0d 68 |.DKY|..)..U.Xq.h|
+00000190 6b 06 bd 13 2c a0 04 15 2e 49 cc 99 7f a6 b4 5d |k...,....I.....]|
+000001a0 d3 49 a5 21 15 d7 66 2d a2 e8 cd a7 7e 46 c4 ac |.I.!..f-....~F..|
+000001b0 89 ae cb 58 73 42 9f dc c3 c9 5a 13 2f 6f f7 ab |...XsB....Z./o..|
+000001c0 04 4b 9f f1 6c c4 ac 0f f5 eb 8d 7a ef cf 01 00 |.K..l......z....|
+000001d0 8a 02 ec 16 09 c1 e9 27 81 32 70 b1 24 d4 db 4e |.......'.2p.$..N|
+000001e0 9e 22 65 21 a7 8f 19 d5 c6 57 78 8a fa a6 41 87 |."e!.....Wx...A.|
+000001f0 52 eb 5d ef f8 7e 3b 34 a5 31 ff 33 33 fd 85 03 |R.]..~;4.1.33...|
+00000200 e4 94 56 ef 11 c0 fe 84 f6 87 94 26 de 7c bd d1 |..V........&.|..|
+00000210 1b ea 15 34 62 e5 da bd e6 c4 b0 74 b5 27 ad 21 |...4b......t.'.!|
+00000220 39 16 c8 be e8 41 50 7b de fb 71 10 4c b1 f4 5a |9....AP{..q.L..Z|
+00000230 bf ea fd 9b 86 a5 c6 e7 2f c2 13 e4 d2 cd 32 7a |......../.....2z|
+00000240 6b ad ab 43 12 3b 45 b9 5c e4 cf 2c f9 f3 44 2c |k..C.;E.\..,..D,|
+00000250 11 31 ce c5 65 dd ea e6 52 bd 8a 35 d0 31 d4 4f |.1..e...R..5.1.O|
+00000260 01 24 54 e4 d2 bf 6e 79 b2 bf a8 f0 5d 9d 72 44 |.$T...ny....].rD|
+00000270 6e df 29 8a d2 cc a8 d2 ee 0c 51 50 cd 71 a6 2a |n.).......QP.q.*|
+00000280 fe 53 2e f7 ae fa 4c 34 d0 68 31 d5 69 be 64 a5 |.S....L4.h1.i.d.|
+00000290 03 54 31 1a dc f0 9e c7 82 1f 15 d1 64 ff 79 07 |.T1.........d.y.|
+000002a0 5e 71 3a 98 3c 21 a7 8e 1e bf 2d f3 86 4b 3f 30 |^q:.<!....-..K?0|
+000002b0 73 0d 7c 5d 57 1b a9 89 2b 52 70 84 8e e6 bb fe |s.|]W...+Rp.....|
+000002c0 b7 1f 65 6a 08 63 58 16 81 51 09 b2 79 7d 84 c0 |..ej.cX..Q..y}..|
+000002d0 6f e1 ab 92 35 16 2e 8f 5c 17 2d 5e 68 7f d4 94 |o...5...\.-^h...|
+000002e0 5a 1b 1d 6c 5f e0 36 a0 ae 54 5b e9 39 1f bc 73 |Z..l_.6..T[.9..s|
+000002f0 f9 04 80 e9 36 d2 2c de 64 ca 08 95 d0 98 4b da |....6.,.d.....K.|
+00000300 7b 0d 7f 79 1b a0 56 6c dd 3c 40 52 3e 7a 8f 52 |{..y..Vl.<@R>z.R|
+00000310 3c c9 2f 17 03 03 00 99 07 91 f0 6b e0 bb 6f 0b |<./........k..o.|
+00000320 ff 08 69 bc d2 1d f1 40 d2 d7 c7 f6 c2 b3 57 d7 |..i....@......W.|
+00000330 90 00 c9 9e ef 40 b6 96 86 0d 27 8b 6f ac 54 2f |.....@....'.o.T/|
+00000340 73 b3 b4 82 1b d3 f5 e9 41 a7 fd d5 b1 67 f7 6e |s.......A....g.n|
+00000350 2e c1 06 34 ef a3 b9 97 4d a8 64 4f f8 48 24 5c |...4....M.dO.H$\|
+00000360 66 f4 d7 d4 e3 ad 45 fb 4a 42 0d 19 bb a1 cc b3 |f.....E.JB......|
+00000370 88 d2 2a d7 c3 53 c4 7b 08 a5 68 dc c4 1a f6 f3 |..*..S.{..h.....|
+00000380 a1 42 48 1c c9 2b 1f fb 5d fc 49 ed ce 16 14 34 |.BH..+..].I....4|
+00000390 34 01 c9 ef e6 29 9c 81 1a 7d 7b bd 95 eb ad 5f |4....)...}{...._|
+000003a0 ce 19 30 9c e6 ae 09 15 3c 2b 38 8b e6 97 76 4e |..0.....<+8...vN|
+000003b0 dd 17 03 03 00 35 d2 a1 3f 22 e9 2b b6 7a d1 d8 |.....5..?".+.z..|
+000003c0 7b 87 bf d1 bf 56 0b 55 52 d0 a9 cf ae 57 6e 6f |{....V.UR....Wno|
+000003d0 29 0c c3 f7 f3 d4 bf ff a4 6b 49 1a 57 57 27 89 |)........kI.WW'.|
+000003e0 e0 f5 bb d2 16 85 39 40 fd 77 a3 |......9@.w.|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 b3 39 ad 6b 24 |..........5.9.k$|
+00000010 47 e3 9f 11 f9 7e 9a cf 41 db c8 43 ce 86 ae ce |G....~..A..C....|
+00000020 0c af 17 42 d7 24 57 13 e6 ba a7 44 7c 72 38 aa |...B.$W....D|r8.|
+00000030 8f fa a2 a2 9f b0 ba 43 47 20 e8 03 3c 00 ee ad |.......CG ..<...|
+00000040 17 03 03 00 17 ff 5b 79 f8 c8 0c 7a 52 6d b0 b2 |......[y...zRm..|
+00000050 22 17 3b 5d f9 75 23 bb 27 38 35 a6 17 03 03 00 |".;].u#.'85.....|
+00000060 13 d3 94 d9 b5 8b fa dc b6 fe 26 ca b0 52 5c ef |..........&..R\.|
+00000070 84 e3 3c f9 |..<.|
diff --git a/src/crypto/tls/testdata/Client-TLSv13-HelloRetryRequest b/src/crypto/tls/testdata/Client-TLSv13-HelloRetryRequest
new file mode 100644
index 0000000..4840339
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv13-HelloRetryRequest
@@ -0,0 +1,119 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 f6 01 00 00 f2 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 77 00 05 00 05 01 00 00 00 00 00 0a 00 |...w............|
+00000090 06 00 04 00 1d 00 17 00 0b 00 02 01 00 00 0d 00 |................|
+000000a0 1a 00 18 08 04 04 03 08 07 08 05 08 06 04 01 05 |................|
+000000b0 01 06 01 05 03 06 03 02 01 02 03 ff 01 00 01 00 |................|
+000000c0 00 12 00 00 00 2b 00 09 08 03 04 03 03 03 02 03 |.....+..........|
+000000d0 01 00 33 00 26 00 24 00 1d 00 20 2f e5 7d a3 47 |..3.&.$... /.}.G|
+000000e0 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af |.bC.(.._.).0....|
+000000f0 c4 cf c2 ed 90 99 5f 58 cb 3b 74 |......_X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 58 02 00 00 54 03 03 cf 21 ad 74 e5 |....X...T...!.t.|
+00000010 9a 61 11 be 1d 8c 02 1e 65 b8 91 c2 a2 11 16 7a |.a......e......z|
+00000020 bb 8c 5e 07 9e 09 e2 c8 a8 33 9c 20 00 00 00 00 |..^......3. ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 03 00 00 |................|
+00000050 0c 00 2b 00 02 03 04 00 33 00 02 00 17 14 03 03 |..+.....3.......|
+00000060 00 01 01 |...|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 16 03 03 01 17 01 00 01 13 03 |................|
+00000010 03 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000030 00 20 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |. ..............|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000050 00 00 00 32 cc a9 cc a8 c0 2b c0 2f c0 2c c0 30 |...2.....+./.,.0|
+00000060 c0 09 c0 13 c0 0a c0 14 00 9c 00 9d 00 2f 00 35 |............./.5|
+00000070 c0 12 00 0a c0 23 c0 27 00 3c c0 07 c0 11 00 05 |.....#.'.<......|
+00000080 13 03 13 01 13 02 01 00 00 98 00 05 00 05 01 00 |................|
+00000090 00 00 00 00 0a 00 06 00 04 00 1d 00 17 00 0b 00 |................|
+000000a0 02 01 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 |................|
+000000b0 05 08 06 04 01 05 01 06 01 05 03 06 03 02 01 02 |................|
+000000c0 03 ff 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 |...........+....|
+000000d0 04 03 03 03 02 03 01 00 33 00 47 00 45 00 17 00 |........3.G.E...|
+000000e0 41 04 1e 18 37 ef 0d 19 51 88 35 75 71 b5 e5 54 |A...7...Q.5uq..T|
+000000f0 5b 12 2e 8f 09 67 fd a7 24 20 3e b2 56 1c ce 97 |[....g..$ >.V...|
+00000100 28 5e f8 2b 2d 4f 9e f1 07 9f 6c 4b 5b 83 56 e2 |(^.+-O....lK[.V.|
+00000110 32 42 e9 58 b6 d7 49 a6 b5 68 1a 41 03 56 6b dc |2B.X..I..h.A.Vk.|
+00000120 5a 89 |Z.|
+>>> Flow 4 (server to client)
+00000000 16 03 03 00 9b 02 00 00 97 03 03 1d 65 62 8f 58 |............eb.X|
+00000010 2b 99 04 1d fd cc e3 0b 46 5c 55 a9 3a 80 76 60 |+.......F\U.:.v`|
+00000020 8f 52 09 6e 48 5d 5a e3 92 da a3 20 00 00 00 00 |.R.nH]Z.... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 03 00 00 |................|
+00000050 4f 00 2b 00 02 03 04 00 33 00 45 00 17 00 41 04 |O.+.....3.E...A.|
+00000060 1c 01 c6 9e c8 49 43 49 6f 0f 17 f3 ce 87 1a 0f |.....ICIo.......|
+00000070 1f 2c 70 18 e4 29 f2 16 a2 e0 02 b7 9d 52 bc b9 |.,p..).......R..|
+00000080 d4 b0 1d 19 da 3a 38 f6 93 04 0b ae 5f 60 45 87 |.....:8....._`E.|
+00000090 57 80 20 27 c6 9c d4 eb ec c0 85 df f5 aa be de |W. '............|
+000000a0 17 03 03 00 17 d4 a9 5f 09 d3 e6 47 ad a7 7b 38 |......._...G..{8|
+000000b0 a3 b8 02 37 16 ec 03 56 df d5 8d ec 17 03 03 02 |...7...V........|
+000000c0 6d be 1b 2a 60 52 3c 01 2e 6e 7f e3 68 fa de 09 |m..*`R<..n..h...|
+000000d0 ed 5e 8f 0f a0 34 d5 0a 8b 2f 30 8f 6c 56 9e fe |.^...4.../0.lV..|
+000000e0 e6 9a a9 f1 6e 7c 63 a7 d8 88 e2 95 fa 17 ad 0c |....n|c.........|
+000000f0 49 20 93 18 3c ba db fc a1 14 60 2c 77 d4 44 5f |I ..<.....`,w.D_|
+00000100 69 9c c7 a3 b9 d0 ee e8 c5 ec 45 d3 79 d0 ee 04 |i.........E.y...|
+00000110 fd c3 6d 12 1a f2 6e 62 9f eb ff 32 88 17 4c df |..m...nb...2..L.|
+00000120 20 4f cc f9 fd d5 7c 8b 8c c2 da 7d 8a c9 f9 27 | O....|....}...'|
+00000130 32 06 75 fe 75 e2 bb bd 6c 31 5d 32 af 36 95 39 |2.u.u...l1]2.6.9|
+00000140 92 6c 32 e5 4f b5 f7 07 9f b3 1b b8 10 a8 d9 db |.l2.O...........|
+00000150 d3 b0 40 2f 1e e6 54 f5 35 73 7d 22 b3 6b b8 3c |..@/..T.5s}".k.<|
+00000160 83 82 8a 75 f4 ec 18 94 57 0c de 98 41 73 61 63 |...u....W...Asac|
+00000170 5b 95 3e 4e d4 02 c3 b7 f9 4c 6f 01 c9 52 3c b9 |[.>N.....Lo..R<.|
+00000180 ad 61 83 2c 89 6d 63 40 fd d4 67 83 36 8b 9a 1c |.a.,.mc@..g.6...|
+00000190 ca 93 16 d8 e3 91 08 d1 3f ba af cb d9 69 09 10 |........?....i..|
+000001a0 07 a7 54 9c ee a2 7d 97 ce b6 1f 31 9b 85 b0 82 |..T...}....1....|
+000001b0 fc 22 87 70 93 59 9c c9 e3 07 9b d0 c0 a4 1d d4 |.".p.Y..........|
+000001c0 2e 36 c0 72 b6 d5 2a f5 b3 fa ab fb 1a 90 05 51 |.6.r..*........Q|
+000001d0 b7 19 15 af d9 b2 5f 32 ef e6 5a 2d 4a 2c 7f a9 |......_2..Z-J,..|
+000001e0 43 cf b8 ac e4 8a f0 bf 68 90 b9 7c 1c 7e fa f0 |C.......h..|.~..|
+000001f0 bc e3 a9 4f a7 2d 3a f3 12 eb b1 93 b4 b9 1b d7 |...O.-:.........|
+00000200 81 31 db 58 c4 8e 9f 46 44 39 74 a1 a8 b0 78 0c |.1.X...FD9t...x.|
+00000210 b9 23 6d 90 bb a8 b0 7c e2 a3 a3 c4 e6 83 32 5d |.#m....|......2]|
+00000220 ea 5a a4 3d 94 ca 51 3c 71 28 cf 43 27 9f 66 9b |.Z.=..Q<q(.C'.f.|
+00000230 ec 49 0f a4 12 f5 a3 96 cd 3e 05 5b 9c d0 07 6f |.I.......>.[...o|
+00000240 8a 11 df 2f be a7 1d 0d 9f a8 04 41 3d 5e 1b f6 |.../.......A=^..|
+00000250 b0 10 9b 6a 49 da 6c f9 6c 6e 2e 6c 9b cf f1 fe |...jI.l.ln.l....|
+00000260 49 92 2b 16 3f 63 ef 87 71 9c da 0d 49 63 2a 4c |I.+.?c..q...Ic*L|
+00000270 b5 82 c8 b0 75 5b 7b 89 39 cd 9a da dc 42 d1 1f |....u[{.9....B..|
+00000280 92 61 e1 71 b9 b5 d2 40 3c 7a 4a 8d 91 1f e6 9d |.a.q...@<zJ.....|
+00000290 79 37 71 3c dc a3 98 0b b3 64 39 74 f1 8f 84 35 |y7q<.....d9t...5|
+000002a0 1d 6b b7 0a f9 aa 26 55 a8 39 7f 11 26 18 98 fe |.k....&U.9..&...|
+000002b0 94 fb 5d e4 a1 2f 0f 3b f0 b6 78 d5 87 32 73 6e |..]../.;..x..2sn|
+000002c0 3e b1 3e 3c 19 31 7a ae d8 73 67 96 56 9c 38 a6 |>.><.1z..sg.V.8.|
+000002d0 bc 39 1f 11 74 ad 69 c6 d2 40 0f 65 d8 ee aa 87 |.9..t.i..@.e....|
+000002e0 b3 4c 6c 1a 1d 62 4a 7a d9 15 05 54 0d 8a 22 68 |.Ll..bJz...T.."h|
+000002f0 8e 41 22 b0 ee 41 b3 94 5d 1a 62 d8 bb ac f2 87 |.A"..A..].b.....|
+00000300 ad 91 19 e7 e1 bc 29 3b 96 8c d1 76 99 e5 82 48 |......);...v...H|
+00000310 0b 87 6a 93 3b 2c b7 c1 73 07 53 7c 1f 9f 48 dd |..j.;,..s.S|..H.|
+00000320 71 da 55 e1 4a a3 86 d2 ff 23 b2 1d ea b0 17 03 |q.U.J....#......|
+00000330 03 00 99 75 af 84 36 54 8e 17 09 c7 2e 72 de 7d |...u..6T.....r.}|
+00000340 29 5c 94 a9 e3 d3 d0 9b 3e a0 84 e6 cf b4 48 d8 |)\......>.....H.|
+00000350 dd 7c 8a 82 96 15 aa cb 95 38 88 9e 48 c4 bf 75 |.|.......8..H..u|
+00000360 9c f4 07 ed 5d 4d 36 8b 58 7f 9c 32 0b f9 d2 44 |....]M6.X..2...D|
+00000370 3d d6 ab 3b 3d 38 1f 8d 7e e8 b6 26 57 c9 c6 98 |=..;=8..~..&W...|
+00000380 49 4f 1e ad 5d fa 8b ca bc ce 99 f2 d9 5b 14 54 |IO..]........[.T|
+00000390 56 0c 59 c8 22 9f 77 f1 db 92 43 c3 dd a5 29 ec |V.Y.".w...C...).|
+000003a0 0d 79 0d b3 04 3f 4b 6b d6 a8 da 99 64 94 78 a5 |.y...?Kk....d.x.|
+000003b0 e9 cd 7e f8 0c fb 72 d6 03 89 dd 00 13 f3 14 18 |..~...r.........|
+000003c0 ba 59 3c 04 7f 6a b5 62 37 56 2e 2d 17 03 03 00 |.Y<..j.b7V.-....|
+000003d0 35 af eb 05 4e ec ee 4b d6 6b 03 35 d8 ba a3 cf |5...N..K.k.5....|
+000003e0 50 c6 80 07 90 92 1c ed 1f d2 d5 12 e3 7f 74 1a |P.............t.|
+000003f0 2c 3b 4b 6c f4 58 af 9a 1a cd 90 f4 d8 78 97 09 |,;Kl.X.......x..|
+00000400 2f f6 35 c1 29 b8 |/.5.).|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 35 8d 07 5a 33 f5 d1 e7 6d 71 48 45 |....5..Z3...mqHE|
+00000010 3e 2a c0 7e 66 03 77 b5 69 b1 e5 13 04 0e 0d ea |>*.~f.w.i.......|
+00000020 6f 80 46 a1 9a 54 09 6f a7 be b7 a3 a1 0c d4 ba |o.F..T.o........|
+00000030 0e 7d 00 8f 1b 01 0b d4 6b 4c 17 03 03 00 17 b9 |.}......kL......|
+00000040 fd 5a 5c a1 c2 33 71 63 99 25 bd 03 a3 24 a7 b6 |.Z\..3qc.%...$..|
+00000050 e7 42 04 6a 81 c5 17 03 03 00 13 b6 4a f1 0a 26 |.B.j........J..&|
+00000060 95 e8 fb 4b d1 db 24 95 8f 65 1f 3c 5d b9 |...K..$..e.<].|
diff --git a/src/crypto/tls/testdata/Client-TLSv13-KeyUpdate b/src/crypto/tls/testdata/Client-TLSv13-KeyUpdate
new file mode 100644
index 0000000..ea10f66
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv13-KeyUpdate
@@ -0,0 +1,102 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 fa 01 00 00 f6 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 7b 00 05 00 05 01 00 00 00 00 00 0a 00 |...{............|
+00000090 0a 00 08 00 1d 00 17 00 18 00 19 00 0b 00 02 01 |................|
+000000a0 00 00 0d 00 1a 00 18 08 04 04 03 08 07 08 05 08 |................|
+000000b0 06 04 01 05 01 06 01 05 03 06 03 02 01 02 03 ff |................|
+000000c0 01 00 01 00 00 12 00 00 00 2b 00 09 08 03 04 03 |.........+......|
+000000d0 03 03 02 03 01 00 33 00 26 00 24 00 1d 00 20 2f |......3.&.$... /|
+000000e0 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+000000f0 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 |.........._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 86 ed 46 3d 38 |....z...v....F=8|
+00000010 c5 47 10 b5 4e ac e5 b7 d7 ba cc 23 db f5 0a f4 |.G..N......#....|
+00000020 5e d3 62 af 47 8a 23 34 59 5c db 20 00 00 00 00 |^.b.G.#4Y\. ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 03 00 00 |................|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 e3 |..+.....3.$... .|
+00000060 ff 35 33 31 c9 d8 5c 68 2a e5 73 98 4d 11 5b d7 |.531..\h*.s.M.[.|
+00000070 06 18 a9 dd 0e 4a 21 92 5b 15 8f bb 91 a9 6c 14 |.....J!.[.....l.|
+00000080 03 03 00 01 01 17 03 03 00 17 ea ac f8 a0 41 47 |..............AG|
+00000090 af 01 fb 51 2e ec 3b 79 f1 8a 54 2b 93 45 33 c3 |...Q..;y..T+.E3.|
+000000a0 79 17 03 03 02 6d 0e c9 a4 55 8e 8c 09 55 cd a6 |y....m...U...U..|
+000000b0 d4 dc 1e 5a de ee 56 c8 c2 ac 12 77 77 76 82 fc |...Z..V....wwv..|
+000000c0 a6 44 cb c8 c3 16 c4 5e bc 3f f3 3b 6c 33 f3 35 |.D.....^.?.;l3.5|
+000000d0 ed bd 8e 37 1a 25 de 7e b3 88 71 ce f9 e5 9b a6 |...7.%.~..q.....|
+000000e0 99 11 0f 71 6b 36 11 04 66 a2 5f 74 1c c6 6a 99 |...qk6..f._t..j.|
+000000f0 49 84 d1 36 96 df 6d 2c c5 a3 cf 5a c9 37 22 8a |I..6..m,...Z.7".|
+00000100 72 e4 d4 25 ed 4a b1 c4 85 5a 9a f7 de 0b dd 41 |r..%.J...Z.....A|
+00000110 7d 14 63 35 2e 1c 77 6c 9e 6f 41 d1 cb 29 ca 6d |}.c5..wl.oA..).m|
+00000120 88 1c 35 53 1b 14 24 79 84 ec 85 0d de e3 0f 2c |..5S..$y.......,|
+00000130 23 ae 41 72 85 fb 43 36 82 ba 8f 78 79 a2 c3 95 |#.Ar..C6...xy...|
+00000140 72 19 ea 1d 2f 29 0e d5 11 85 e4 cc 8c a5 f4 8e |r.../)..........|
+00000150 39 ba 88 8f e1 5a 54 7c 53 8b a3 1a 44 9c ae 5b |9....ZT|S...D..[|
+00000160 1f 0e ea 06 f1 8e 5f 22 d1 ef ee e1 4c b6 1a 26 |......_"....L..&|
+00000170 db 53 96 e6 bc 0b 2f ee b7 fa 47 af 1e 9c f6 7b |.S..../...G....{|
+00000180 81 97 0f c3 08 9b 2c a3 de bd f7 8a 1e 13 ad de |......,.........|
+00000190 a5 fc 5f c7 7a 53 72 e5 17 dc 0a eb 90 91 29 2e |.._.zSr.......).|
+000001a0 7a a5 09 fd be 31 ff 81 ec a3 fc 91 41 4f cb c7 |z....1......AO..|
+000001b0 27 c3 39 8f cd 77 62 72 9a e9 e9 16 da 90 b6 6b |'.9..wbr.......k|
+000001c0 05 70 c8 aa f5 cd 88 13 4d ff a5 a9 0f e7 d2 d3 |.p......M.......|
+000001d0 97 2b eb e1 d7 fe 74 da fb 1e af 94 e6 52 18 48 |.+....t......R.H|
+000001e0 5b e8 c3 10 9d 76 de 17 86 67 83 4a e9 fa 30 e8 |[....v...g.J..0.|
+000001f0 46 95 f5 81 b1 a5 76 38 57 37 3a 8d df ad e7 30 |F.....v8W7:....0|
+00000200 41 b2 94 31 da 0d d6 5c df 76 01 cd 4d c2 1b fe |A..1...\.v..M...|
+00000210 bc 69 41 ac dd d7 dd 0a 7c 5b 31 5c c8 1e b3 14 |.iA.....|[1\....|
+00000220 39 20 51 26 6d e5 55 27 a4 9a bb fc 3d 4b 6a b0 |9 Q&m.U'....=Kj.|
+00000230 54 92 ee 33 1b 9b d5 41 fd ef 21 c6 f0 f8 90 a0 |T..3...A..!.....|
+00000240 c4 f5 86 d4 d9 c7 89 6f 67 23 37 31 44 2f 8f 55 |.......og#71D/.U|
+00000250 0a aa e1 9a ec 32 26 e2 ce 96 90 c6 f5 cc 95 79 |.....2&........y|
+00000260 da 0c b4 c1 62 d3 0a 8d 7b 83 33 8e af ff 57 c0 |....b...{.3...W.|
+00000270 5b ca 0f b5 64 10 81 43 12 86 67 cf b2 0a 53 f2 |[...d..C..g...S.|
+00000280 04 46 4f 99 ee e2 cd ce 3e 82 1f 34 43 26 f9 4c |.FO.....>..4C&.L|
+00000290 57 b0 10 c0 37 40 9c 4f fb 14 fa 4e 1e 4b 40 da |W...7@.O...N.K@.|
+000002a0 cc c3 d0 d7 ee 63 18 2e 97 06 a6 49 69 07 7a 3e |.....c.....Ii.z>|
+000002b0 da 47 68 70 b0 10 bf 8d 18 d2 14 c0 18 18 b2 61 |.Ghp...........a|
+000002c0 45 54 e8 20 34 f8 a3 74 5a 8d aa c2 63 af e8 ff |ET. 4..tZ...c...|
+000002d0 f9 1b 33 d6 34 c2 f2 c2 3d d8 0e 32 7a 10 cc 21 |..3.4...=..2z..!|
+000002e0 02 22 a6 aa 7d 15 c3 7b 3f a2 50 5a 4e 53 ec f5 |."..}..{?.PZNS..|
+000002f0 11 dd 48 6e 7e e9 c5 94 2c c4 9a 6e 10 a6 c6 a5 |..Hn~...,..n....|
+00000300 9d e1 c5 43 e6 69 a1 91 65 50 eb e6 76 db f0 09 |...C.i..eP..v...|
+00000310 14 45 ef 17 03 03 00 99 e4 82 99 6b d8 57 ca 1b |.E.........k.W..|
+00000320 78 98 88 ad c7 04 b7 d2 b2 d5 00 3b a9 bf 86 66 |x..........;...f|
+00000330 a7 30 72 95 29 2a 27 9f 9a 3d bd 0b e6 a0 04 22 |.0r.)*'..=....."|
+00000340 56 3d d8 08 84 a7 e7 c5 67 74 34 7d 57 1f c9 df |V=......gt4}W...|
+00000350 71 0c 97 55 5a d9 8d 99 df 49 b5 a9 57 6d b0 c7 |q..UZ....I..Wm..|
+00000360 2d 4b 70 9d e7 e3 70 31 f0 2f 32 15 7b 67 b4 4c |-Kp...p1./2.{g.L|
+00000370 f0 f0 4a 16 a5 37 b2 ae 9b 2a 72 7c 2e d8 22 a1 |..J..7...*r|..".|
+00000380 2b 91 f2 14 fc f9 27 fd ca ad 27 dd 15 11 df b1 |+.....'...'.....|
+00000390 cc 4c 3a 45 3f b6 7c 53 c5 d0 82 49 1a f2 28 63 |.L:E?.|S...I..(c|
+000003a0 a2 be 6f 2f db d8 d3 76 0a 12 fa 87 14 00 11 e7 |..o/...v........|
+000003b0 1f 17 03 03 00 35 0c af 49 a1 ba 14 d4 e5 5c cf |.....5..I.....\.|
+000003c0 c8 f7 fb 93 e3 d5 45 ac 59 ed 56 3c 1c e6 53 6a |......E.Y.V<..Sj|
+000003d0 77 62 a3 1a 8c 55 14 b0 d8 6f dd 1c fb a4 6f 25 |wb...U...o....o%|
+000003e0 18 28 ab 9e a5 ad 6d 97 63 f4 9c |.(....m.c..|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 12 2a a7 31 42 |..........5.*.1B|
+00000010 e9 65 d6 88 9c 49 85 53 16 6c 85 bc d1 70 65 3a |.e...I.S.l...pe:|
+00000020 aa cd d3 12 ce 69 e3 3a 63 7a 8d ed 54 df 9c 97 |.....i.:cz..T...|
+00000030 4e ef 7c 20 ce 41 ac 33 a9 3b fc 5e 35 34 65 00 |N.| .A.3.;.^54e.|
+00000040 17 03 03 00 17 11 5f 88 3b 45 0e 4e 8a 26 43 a3 |......_.;E.N.&C.|
+00000050 9e 77 10 76 8c e1 ed d3 19 f4 27 5f |.w.v......'_|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 16 7d 92 67 60 95 ba fa a0 5f 03 e9 |.....}.g`...._..|
+00000010 2b e6 53 ed fb 6b 4f b9 e9 09 10 |+.S..kO....|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 16 06 17 fb 4b 33 c7 06 d5 a9 40 e8 |........K3....@.|
+00000010 c7 09 65 b2 5c 2d 45 2f bf 45 a8 |..e.\-E/.E.|
+>>> Flow 6 (server to client)
+00000000 17 03 03 00 1a 04 5e c0 bb ad 6c 2f 65 61 5c 39 |......^...l/ea\9|
+00000010 a9 e2 c4 9e 0e 4c 68 d2 a9 97 8a bf 95 39 3f |.....Lh......9?|
+>>> Flow 7 (client to server)
+00000000 17 03 03 00 1d 1f 74 d0 fb ed fa 59 81 21 7e f0 |......t....Y.!~.|
+00000010 41 c8 6e 6b 9f b6 1a 86 ad 2e ac 9e 3d 3b 66 c9 |A.nk........=;f.|
+00000020 4a 87 17 03 03 00 13 7b 76 c4 85 c1 41 47 6d 35 |J......{v...AGm5|
+00000030 98 86 02 d5 3b e4 6b 4c 3e 7a |....;.kL>z|
diff --git a/src/crypto/tls/testdata/Client-TLSv13-P256-ECDHE b/src/crypto/tls/testdata/Client-TLSv13-P256-ECDHE
new file mode 100644
index 0000000..db87bef
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv13-P256-ECDHE
@@ -0,0 +1,94 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 01 15 01 00 01 11 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 96 00 05 00 05 01 00 00 00 00 00 0a 00 |................|
+00000090 04 00 02 00 17 00 0b 00 02 01 00 00 0d 00 1a 00 |................|
+000000a0 18 08 04 04 03 08 07 08 05 08 06 04 01 05 01 06 |................|
+000000b0 01 05 03 06 03 02 01 02 03 ff 01 00 01 00 00 12 |................|
+000000c0 00 00 00 2b 00 09 08 03 04 03 03 03 02 03 01 00 |...+............|
+000000d0 33 00 47 00 45 00 17 00 41 04 1e 18 37 ef 0d 19 |3.G.E...A...7...|
+000000e0 51 88 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 |Q.5uq..T[....g..|
+000000f0 24 20 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 |$ >.V...(^.+-O..|
+00000100 07 9f 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 |..lK[.V.2B.X..I.|
+00000110 b5 68 1a 41 03 56 6b dc 5a 89 |.h.A.Vk.Z.|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 9b 02 00 00 97 03 03 bb 03 f1 4e 88 |..............N.|
+00000010 23 9e 85 ee 32 13 db 0d 69 11 48 47 c6 c9 e5 b2 |#...2...i.HG....|
+00000020 25 9d 0c 27 87 05 3f 58 42 60 2d 20 00 00 00 00 |%..'..?XB`- ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 03 00 00 |................|
+00000050 4f 00 2b 00 02 03 04 00 33 00 45 00 17 00 41 04 |O.+.....3.E...A.|
+00000060 85 3c 83 1b e5 02 e9 0d 89 cc c0 f7 af 1e ba af |.<..............|
+00000070 de ad cb 8f 4d 58 04 40 c2 60 e9 41 8b 94 26 76 |....MX.@.`.A..&v|
+00000080 73 64 c3 27 e3 51 9d 5f 21 97 59 a3 02 cc 20 61 |sd.'.Q._!.Y... a|
+00000090 b7 ef cb bb d9 31 b6 b7 b1 77 ea 8d 69 13 13 48 |.....1...w..i..H|
+000000a0 14 03 03 00 01 01 17 03 03 00 17 ab ac 2e 62 de |..............b.|
+000000b0 b6 f4 c7 35 cf b4 75 fc a4 a5 2c 40 68 f5 48 80 |...5..u...,@h.H.|
+000000c0 d2 8b 17 03 03 02 6d a9 36 b5 10 78 1f af 79 65 |......m.6..x..ye|
+000000d0 dd ee 36 08 b9 96 e2 bf 09 53 c7 ee 12 19 1b de |..6......S......|
+000000e0 96 25 cb a7 55 71 28 22 16 3f 4b 3e 15 a2 2e 57 |.%..Uq(".?K>...W|
+000000f0 99 85 28 b2 01 16 3a 75 ff 5e 21 39 6c be fc bd |..(...:u.^!9l...|
+00000100 24 33 ec c7 50 83 49 91 8a ed 43 38 b5 48 cd 92 |$3..P.I...C8.H..|
+00000110 dd 9a f1 b7 90 61 3b 8f ff b9 cf 97 3d 8e 23 8e |.....a;.....=.#.|
+00000120 d1 78 52 b4 ba a1 75 97 32 52 e3 1f c8 43 ca b7 |.xR...u.2R...C..|
+00000130 89 46 e6 30 c2 c5 32 b3 5f a8 ea ea e2 31 d2 41 |.F.0..2._....1.A|
+00000140 23 5e 64 a2 b9 23 27 73 b2 df 77 cd 04 8b dd 37 |#^d..#'s..w....7|
+00000150 a5 77 df 0e 4f 9d 01 22 7b be 7a 0c 18 5c 8b 62 |.w..O.."{.z..\.b|
+00000160 7c 6b 7e a7 54 8c 69 97 50 d7 cf a0 a4 cb 3a 3b ||k~.T.i.P.....:;|
+00000170 76 7b 0a de 80 d1 40 c3 05 5e b3 4e 71 cd 03 82 |v{....@..^.Nq...|
+00000180 d5 95 d0 38 ab 65 83 24 66 d2 31 2d 9e 58 16 87 |...8.e.$f.1-.X..|
+00000190 b8 ab 4c 4e 75 40 7e 3d 33 2f f4 ed 0b a8 11 1c |..LNu@~=3/......|
+000001a0 7a a4 b0 e3 6a 73 d0 6e e6 82 39 c1 cf 57 a4 9a |z...js.n..9..W..|
+000001b0 8b fc bc 8e e8 6a c3 e1 b0 64 18 55 6d 19 30 25 |.....j...d.Um.0%|
+000001c0 34 f8 b1 ef cf 3c 04 08 69 10 ad 08 67 5b 8d 64 |4....<..i...g[.d|
+000001d0 eb 83 72 39 2e 56 e4 d2 e9 f2 da 40 3e 85 29 ab |..r9.V.....@>.).|
+000001e0 5b 83 e5 b0 d2 9b eb c3 99 6e 2a f3 78 95 d4 7a |[........n*.x..z|
+000001f0 7f bf 9c 16 55 77 43 4d 67 f7 4a 6f 40 27 a2 82 |....UwCMg.Jo@'..|
+00000200 b9 86 05 5d 90 e2 52 a2 d4 7c 7b 3e da 30 c1 aa |...]..R..|{>.0..|
+00000210 30 2e 9a 34 c5 59 dd db e9 25 67 da 22 47 f2 be |0..4.Y...%g."G..|
+00000220 cc c8 5a 4e da cf ad 86 8d bd b0 68 26 69 ea 3a |..ZN.......h&i.:|
+00000230 1c 1e 29 ae e1 09 63 88 f0 81 31 f9 70 a7 92 27 |..)...c...1.p..'|
+00000240 32 9e 3b 6f 09 5e 42 20 53 88 bf 09 8b a8 17 5c |2.;o.^B S......\|
+00000250 24 7c 18 1f 9c 99 9b db 6d 11 26 8e 92 2c a1 b4 |$|......m.&..,..|
+00000260 5c 9f d9 0a a8 af 25 f7 84 f5 65 d1 b1 6c d8 aa |\.....%...e..l..|
+00000270 49 c7 a6 13 47 2e 55 f4 2e de 3d 43 c1 15 8d 60 |I...G.U...=C...`|
+00000280 c1 27 59 7e 7b 14 ee 54 09 fc 99 79 c9 bf fb 45 |.'Y~{..T...y...E|
+00000290 2d 32 ed 1a 2c 84 bc f4 a2 b5 5f 4e cf 60 29 91 |-2..,....._N.`).|
+000002a0 90 b6 ab 06 8f 2d 43 a5 a5 54 0d 67 52 c2 1c fb |.....-C..T.gR...|
+000002b0 f3 41 b7 67 b4 50 05 86 19 75 93 8b 6c c3 bf 08 |.A.g.P...u..l...|
+000002c0 64 f2 df ff 37 6d 2f 1e 3a 28 f4 ba 27 8d 61 d5 |d...7m/.:(..'.a.|
+000002d0 79 70 19 82 99 7a e5 68 f3 c1 23 da 5d e1 98 b2 |yp...z.h..#.]...|
+000002e0 69 ca 42 83 61 29 3f d9 20 51 f2 a9 ea 1c 0b 5a |i.B.a)?. Q.....Z|
+000002f0 20 b0 af 70 cc c5 ad 72 6b 09 85 56 8a 26 86 cf | ..p...rk..V.&..|
+00000300 4e 9a 56 97 5d 63 8d 1d 46 04 48 16 c9 1e 91 47 |N.V.]c..F.H....G|
+00000310 74 53 28 51 7e 3c 84 a1 50 d6 f3 ac 31 ce 04 18 |tS(Q~<..P...1...|
+00000320 81 38 0d c5 3d f5 d5 04 2f f0 96 9b 73 49 4c d6 |.8..=.../...sIL.|
+00000330 89 d9 b9 be 17 03 03 00 99 3a 37 ed 2d 98 80 f9 |.........:7.-...|
+00000340 d0 04 14 12 8c 63 45 cc 8d cb 29 5f 0e f0 86 ef |.....cE...)_....|
+00000350 8d 6c d6 0f ef 66 99 91 e8 8c d7 7b 21 07 7e 96 |.l...f.....{!.~.|
+00000360 84 f8 f9 5b 1b 39 8b 4f 16 ec 5c 69 7b 18 09 5d |...[.9.O..\i{..]|
+00000370 95 f1 f3 73 4b 8f 84 66 ee 61 85 dd fe ea 36 df |...sK..f.a....6.|
+00000380 e5 2a 71 ec 2d 7e 47 1c b7 79 2d 87 f8 dc 44 27 |.*q.-~G..y-...D'|
+00000390 8a f1 13 6e df ca 59 79 9b 18 01 7e 31 bd 44 f7 |...n..Yy...~1.D.|
+000003a0 8d ad 1c 97 e7 e1 b9 a6 17 d1 25 d1 b8 0d 04 bb |..........%.....|
+000003b0 21 a4 08 db a2 08 87 5c 04 9a 11 fa c6 24 db 20 |!......\.....$. |
+000003c0 42 79 9c 97 dd 6c d2 e7 24 b4 79 47 be f3 43 87 |By...l..$.yG..C.|
+000003d0 0f 95 17 03 03 00 35 9e 7d 12 0e d6 0a e6 af a3 |......5.}.......|
+000003e0 83 dd eb 08 73 2d 43 7e 81 85 51 4c d1 ad d0 77 |....s-C~..QL...w|
+000003f0 8d 28 62 44 41 9c b0 e9 93 d7 3d 07 e4 e1 6e 4c |.(bDA.....=...nL|
+00000400 a8 5b 4a 3f 58 3f 97 07 73 d7 5a 62 |.[J?X?..s.Zb|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 df 31 1a 84 e2 |..........5.1...|
+00000010 93 54 01 f2 d1 e8 32 6c 32 91 e5 64 86 68 ad 5f |.T....2l2..d.h._|
+00000020 aa 24 54 86 b2 39 92 24 06 65 5c 06 67 43 7d 09 |.$T..9.$.e\.gC}.|
+00000030 79 78 c6 f3 cf 6c a9 ec 38 e3 ec 81 c4 9b c5 33 |yx...l..8......3|
+00000040 17 03 03 00 17 25 ed 98 67 8f ad e8 60 ce 5b ad |.....%..g...`.[.|
+00000050 ab 3e 67 64 e3 8d bf 98 96 a2 3d 99 17 03 03 00 |.>gd......=.....|
+00000060 13 9d 28 f2 24 fe d6 11 b0 64 d6 8a 8d c1 81 e0 |..(.$....d......|
+00000070 17 d5 a0 f3 |....|
diff --git a/src/crypto/tls/testdata/Client-TLSv13-X25519-ECDHE b/src/crypto/tls/testdata/Client-TLSv13-X25519-ECDHE
new file mode 100644
index 0000000..4a43382
--- /dev/null
+++ b/src/crypto/tls/testdata/Client-TLSv13-X25519-ECDHE
@@ -0,0 +1,90 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 f4 01 00 00 f0 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 00 00 00 00 |........... ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 00 32 cc a9 |.............2..|
+00000050 cc a8 c0 2b c0 2f c0 2c c0 30 c0 09 c0 13 c0 0a |...+./.,.0......|
+00000060 c0 14 00 9c 00 9d 00 2f 00 35 c0 12 00 0a c0 23 |......./.5.....#|
+00000070 c0 27 00 3c c0 07 c0 11 00 05 13 03 13 01 13 02 |.'.<............|
+00000080 01 00 00 75 00 05 00 05 01 00 00 00 00 00 0a 00 |...u............|
+00000090 04 00 02 00 1d 00 0b 00 02 01 00 00 0d 00 1a 00 |................|
+000000a0 18 08 04 04 03 08 07 08 05 08 06 04 01 05 01 06 |................|
+000000b0 01 05 03 06 03 02 01 02 03 ff 01 00 01 00 00 12 |................|
+000000c0 00 00 00 2b 00 09 08 03 04 03 03 03 02 03 01 00 |...+............|
+000000d0 33 00 26 00 24 00 1d 00 20 2f e5 7d a3 47 cd 62 |3.&.$... /.}.G.b|
+000000e0 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf |C.(.._.).0......|
+000000f0 c2 ed 90 99 5f 58 cb 3b 74 |...._X.;t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 eb 1b 4e e5 65 |....z...v....N.e|
+00000010 54 ab 07 68 1c d9 32 0f 0e c2 ae a3 2a 89 37 50 |T..h..2.....*.7P|
+00000020 23 51 61 7d 68 60 34 0d 40 2f b8 20 00 00 00 00 |#Qa}h`4.@/. ....|
+00000030 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000040 00 00 00 00 00 00 00 00 00 00 00 00 13 03 00 00 |................|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 17 |..+.....3.$... .|
+00000060 7d df 14 8a ad 43 51 c3 c2 08 3a ea f7 e3 96 6a |}....CQ...:....j|
+00000070 b7 8b 61 66 d9 82 c5 7b b9 77 bc 62 6a 19 04 14 |..af...{.w.bj...|
+00000080 03 03 00 01 01 17 03 03 00 17 4e 7b b6 d1 b1 19 |..........N{....|
+00000090 0d 0c d0 d3 5a 66 44 5c 81 49 74 f3 71 3b 97 5e |....ZfD\.It.q;.^|
+000000a0 ee 17 03 03 02 6d 00 17 b1 4d b9 f5 fc ea 48 72 |.....m...M....Hr|
+000000b0 aa a5 1c 8b fe 97 08 54 ab 2d 0a 0e f7 51 41 bf |.......T.-...QA.|
+000000c0 7b 14 ba b7 d9 0a 30 44 db b9 06 e7 6b a9 0a 94 |{.....0D....k...|
+000000d0 49 a2 29 50 f2 7f 7e 68 91 41 ad a9 cb ee e2 bd |I.)P..~h.A......|
+000000e0 03 fd 95 79 ea c3 77 ee 88 3b 7a 81 15 9f 17 96 |...y..w..;z.....|
+000000f0 b2 db b9 f3 26 dd 75 69 ef 12 c0 63 b0 04 63 ae |....&.ui...c..c.|
+00000100 aa b3 67 f8 7f a5 17 cf 56 5f ee 34 2d d7 83 23 |..g.....V_.4-..#|
+00000110 84 00 4b 94 1a 76 2a 01 ce 49 0a 57 7d c8 65 7a |..K..v*..I.W}.ez|
+00000120 d7 16 34 1c a8 37 fd 71 d4 79 08 b1 44 9f 9e a7 |..4..7.q.y..D...|
+00000130 78 ab 9d 0d c4 80 0e 81 35 75 23 59 89 1b 2c d3 |x.......5u#Y..,.|
+00000140 bc c9 86 b9 7b 22 19 30 dd cc 68 93 ab d2 98 dd |....{".0..h.....|
+00000150 c2 9f 20 af c9 1a 87 b3 28 73 84 83 ca 98 1d 60 |.. .....(s.....`|
+00000160 df 12 19 70 80 f2 ff 20 64 b5 8c ef e2 e8 6a 5a |...p... d.....jZ|
+00000170 df 8e ba 95 d8 2c c4 b6 4f a1 33 8c 8d a3 fc d3 |.....,..O.3.....|
+00000180 c4 4b ba b2 6d 3a f7 da 38 23 5f 03 a7 92 13 76 |.K..m:..8#_....v|
+00000190 12 73 26 17 30 e0 21 f1 16 8f a1 e5 6d f0 21 a8 |.s&.0.!.....m.!.|
+000001a0 c6 25 64 86 95 5e 6f 4d 21 f0 f3 a3 27 23 2b 4b |.%d..^oM!...'#+K|
+000001b0 90 03 ba 6c ce 9c 20 ed 69 15 76 cb 39 bc fd 44 |...l.. .i.v.9..D|
+000001c0 10 b4 72 d5 44 9d f7 eb a4 b0 d5 07 20 a1 6b 71 |..r.D....... .kq|
+000001d0 16 e4 f7 8f a0 d8 fa 86 db e6 ef eb 63 41 a0 17 |............cA..|
+000001e0 83 71 0d 1c 4b ec 58 c3 90 9c ea 34 79 a7 91 43 |.q..K.X....4y..C|
+000001f0 ad 3d ff 28 c8 b4 3e 7a b6 83 53 f4 99 0b 86 bc |.=.(..>z..S.....|
+00000200 f2 cf ae 1d a7 5c 7f 57 d9 85 95 25 33 bb 4d 79 |.....\.W...%3.My|
+00000210 25 2e 54 6d 5d 14 32 68 7d 6e 45 bd b1 e1 24 30 |%.Tm].2h}nE...$0|
+00000220 c2 1c 45 b9 a2 42 ae b5 c6 6a 56 f9 8a 12 51 f9 |..E..B...jV...Q.|
+00000230 61 a2 9d 56 98 09 8d ea 70 17 48 d8 23 48 ca 18 |a..V....p.H.#H..|
+00000240 43 1e a2 bc 88 69 3d 45 95 89 cc f0 74 8d 88 36 |C....i=E....t..6|
+00000250 5e a8 1b be 88 41 35 8d de a9 20 23 f3 5e ab c9 |^....A5... #.^..|
+00000260 61 22 2e 86 54 2f c4 4a 60 04 c2 e3 b8 cf 1a 41 |a"..T/.J`......A|
+00000270 a6 31 ab 7a b5 07 dc 54 82 89 b1 1f 9f 62 98 bc |.1.z...T.....b..|
+00000280 bd 39 be 23 ed d5 bc 0d 8e a6 69 14 26 39 fe ed |.9.#......i.&9..|
+00000290 98 c8 48 36 6c 8e 9f 93 57 7a ba 33 03 35 c6 de |..H6l...Wz.3.5..|
+000002a0 55 03 63 e8 a4 53 08 0a b0 a7 3e a3 cb f2 df 3d |U.c..S....>....=|
+000002b0 cd 59 df ee f6 45 2d 77 39 32 4a 1f 08 21 e7 db |.Y...E-w92J..!..|
+000002c0 52 2a 06 86 e6 00 98 ca 9f a3 ad 0f 7f d3 25 6d |R*............%m|
+000002d0 56 58 21 e2 39 59 56 15 74 4d 18 37 f5 40 29 db |VX!.9YV.tM.7.@).|
+000002e0 de be 49 77 e0 2c 5c 6b ee b1 bd 4a ea 2a 07 94 |..Iw.,\k...J.*..|
+000002f0 0f 21 7c bb 1f bd 3e ad 9e b6 95 7d 16 e8 f0 4e |.!|...>....}...N|
+00000300 de e2 ca 9c 34 9f b8 e5 57 d5 b7 b5 8d 60 dd c2 |....4...W....`..|
+00000310 ce 47 2c 17 03 03 00 99 37 37 20 49 98 44 f6 b4 |.G,.....77 I.D..|
+00000320 58 54 ff 5e b0 05 22 8e c6 68 9a ae 49 51 e9 f1 |XT.^.."..h..IQ..|
+00000330 71 75 cf 1a 79 da 33 f1 5f 7e a1 02 81 05 12 8b |qu..y.3._~......|
+00000340 a3 a8 ad 87 ee f0 87 da f1 16 80 9d 2e fa 5a 22 |..............Z"|
+00000350 a5 f5 b9 14 f5 8f 9b 35 87 ba 1a f7 c4 17 c8 f6 |.......5........|
+00000360 a1 1e 28 cd fe 03 90 9f f0 81 d3 80 bb 4c 1a b1 |..(..........L..|
+00000370 c6 11 de 19 a1 5a 3c 73 77 f0 70 b8 d1 38 16 f3 |.....Z<sw.p..8..|
+00000380 64 d0 8e 9c fe 4d 83 48 dc 20 78 db 6a 65 3f f4 |d....M.H. x.je?.|
+00000390 0f a0 70 cc 30 bb cd 86 51 0c 20 ea 59 a5 ed e8 |..p.0...Q. .Y...|
+000003a0 72 d9 5e f3 c3 41 0b 19 f3 97 0f fc 77 42 6d 15 |r.^..A......wBm.|
+000003b0 92 17 03 03 00 35 ac 97 30 a0 8a d8 d2 e6 4a 5b |.....5..0.....J[|
+000003c0 f5 58 32 22 63 8e 36 2e 21 a2 30 33 ae 49 55 76 |.X2"c.6.!.03.IUv|
+000003d0 cf c8 b3 3f 82 8d c3 0e ea 22 ec 8f 65 c8 c4 0d |...?....."..e...|
+000003e0 bf cc 6a 86 e9 32 50 db 02 93 ec |..j..2P....|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 e5 27 80 72 fd |..........5.'.r.|
+00000010 6c 0d b5 a7 14 23 08 0b f5 54 70 8c 29 61 d0 2a |l....#...Tp.)a.*|
+00000020 81 2d 05 83 2a 21 1e 16 94 5b 65 0d 6a ca b6 81 |.-..*!...[e.j...|
+00000030 d9 9d 3c 5c 9c fe 2b 01 a8 3b 23 fb 9e eb 2c 56 |..<\..+..;#...,V|
+00000040 17 03 03 00 17 79 fd 43 29 72 96 e0 ad fd 7e 60 |.....y.C)r....~`|
+00000050 94 51 8d 8a 6e 6a 5d 6c f3 0d 4b 74 17 03 03 00 |.Q..nj]l..Kt....|
+00000060 13 a4 7c e1 31 71 61 82 e7 7d 28 0f 63 d7 ae 76 |..|.1qa..}(.c..v|
+00000070 9c 71 37 cd |.q7.|
diff --git a/src/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
new file mode 100644
index 0000000..c8f11ea
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv10-ECDHE-ECDSA-AES
@@ -0,0 +1,79 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 51 01 00 00 4d 03 01 8a c0 af 21 2c |....Q...M.....!,|
+00000010 ff 48 d6 fd 10 92 4a 8c 84 c7 9e c3 90 3a f5 bf |.H....J......:..|
+00000020 cd 36 1b 2f 96 8b 13 86 f1 ff 5e 00 00 04 c0 0a |.6./......^.....|
+00000030 00 ff 01 00 00 20 00 0b 00 04 03 00 01 02 00 0a |..... ..........|
+00000040 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 16 |................|
+00000050 00 00 00 17 00 00 |......|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 37 02 00 00 33 03 01 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 00 00 c0 0a 00 00 |...DOWNGRD......|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 01 02 |................|
+00000040 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 00 30 |...........0...0|
+00000050 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 30 09 |..b.....-G....0.|
+00000060 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 09 06 |..*.H.=..0E1.0..|
+00000070 03 55 04 06 13 02 41 55 31 13 30 11 06 03 55 04 |.U....AU1.0...U.|
+00000080 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 |...Some-State1!0|
+00000090 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 |...U....Internet|
+000000a0 20 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 64 | Widgits Pty Ltd|
+000000b0 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 33 32 |0...121122150632|
+000000c0 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 32 5a |Z..221120150632Z|
+000000d0 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 |0E1.0...U....AU1|
+000000e0 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 |.0...U....Some-S|
+000000f0 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 |tate1!0...U....I|
+00000100 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 |nternet Widgits |
+00000110 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 2a 86 |Pty Ltd0..0...*.|
+00000120 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....|
+00000130 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 16 56 |.........Hs6~..V|
+00000140 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 f6 b0 |.".=S.;M!=.ku...|
+00000150 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 2f 1c |...&.....r2|.d/.|
+00000160 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 e0 28 |...h#.~..%.H:i.(|
+00000170 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 d8 81 |m.7...b....pb...|
+00000180 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 de 76 |.d1...1...h..#.v|
+00000190 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd 9b d8 |d?.\....XX._p...|
+000001a0 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a 20 e2 |.........0f[f. .|
+000001b0 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d 04 01 |'...;0...*.H.=..|
+000001c0 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb e2 45 |....0...B...O..E|
+000001d0 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e 1b b6 |.H}.......Gp.^..|
+000001e0 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b 7e 92 |/...M.a@......~.|
+000001f0 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 ec 47 |~.v..;~.?....Y.G|
+00000200 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 4d fc |-|..N....o..B.M.|
+00000210 be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 13 83 |.g..-...?..%.3..|
+00000220 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd d7 11 |.....7z..z......|
+00000230 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d ae cb |i..|V..1x+..x...|
+00000240 be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f 2a 16 |..N6$1{j.9....*.|
+00000250 03 01 00 b4 0c 00 00 b0 03 00 1d 20 2f e5 7d a3 |........... /.}.|
+00000260 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000270 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 00 8a 30 81 |......._X.;t..0.|
+00000280 87 02 42 01 ea 1b 6f 67 3e cd 57 50 12 78 5a db |..B...og>.WP.xZ.|
+00000290 06 12 77 04 9d df 0c b0 98 4b a7 e8 23 fb ad 46 |..w......K..#..F|
+000002a0 ef 9b 99 d3 02 4b 46 51 c4 49 2a ae 29 b4 a7 e5 |.....KFQ.I*.)...|
+000002b0 08 d0 db ce 28 af 21 43 37 d4 29 03 00 e3 5f 50 |....(.!C7.)..._P|
+000002c0 35 cd 0a 3f 9d 02 41 35 05 7c a0 ed 81 23 98 38 |5..?..A5.|...#.8|
+000002d0 af 2c 12 8f 59 94 77 c7 56 ef 0b db 60 d0 5b 72 |.,..Y.w.V...`.[r|
+000002e0 9e fd 2a 6c ea 1d af cb ce 5b df 34 52 2a 4b 38 |..*l.....[.4R*K8|
+000002f0 48 81 2c 39 76 61 58 19 80 1b e0 eb fb 53 35 94 |H.,9vaX......S5.|
+00000300 55 ba a6 2b a2 b3 50 b4 16 03 01 00 04 0e 00 00 |U..+..P.........|
+00000310 00 |.|
+>>> Flow 3 (client to server)
+00000000 16 03 01 00 25 10 00 00 21 20 29 f2 f2 54 f4 ff |....%...! )..T..|
+00000010 59 de df ab 55 18 04 cd 8c 27 28 7e 11 11 09 84 |Y...U....'(~....|
+00000020 18 e1 0f 09 70 f8 d7 13 a1 38 14 03 01 00 01 01 |....p....8......|
+00000030 16 03 01 00 30 d8 40 dc 30 cb d6 25 de 23 01 84 |....0.@.0..%.#..|
+00000040 30 75 1c 17 bd f3 fe 7e b4 cd 61 f3 55 c4 30 55 |0u.....~..a.U.0U|
+00000050 ee 43 6f f0 6b a7 0a ed 88 d9 d4 72 7c c7 c6 c7 |.Co.k......r|...|
+00000060 4d 2f 7b 9f 9b |M/{..|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 30 60 b7 c0 a3 ba |..........0`....|
+00000010 ad dd 52 99 15 7a f2 9e 10 21 02 7c 91 6d cf c9 |..R..z...!.|.m..|
+00000020 09 ab fe 9c b3 46 46 60 1c 24 66 3f b6 14 b1 51 |.....FF`.$f?...Q|
+00000030 ac 05 75 48 03 c1 e0 3a c2 6d 5e 17 03 01 00 20 |..uH...:.m^.... |
+00000040 82 87 18 81 c3 24 55 8f 9c a3 49 fc 8a 8a 7a fe |.....$U...I...z.|
+00000050 93 05 c9 7e 90 73 a4 b1 0a d7 3b 7d 72 1f fc 6c |...~.s....;}r..l|
+00000060 17 03 01 00 30 1f 51 a5 44 2e 7a 40 12 43 28 c6 |....0.Q.D.z@.C(.|
+00000070 99 05 6d 92 d9 ed 0d f2 fb a7 48 a3 03 e9 34 b1 |..m.......H...4.|
+00000080 52 32 e1 be a9 7e bf b1 0e 1f b4 1c 3e 0a 9d d9 |R2...~......>...|
+00000090 90 10 4f 79 dd 15 03 01 00 20 57 98 fd dd 09 f9 |..Oy..... W.....|
+000000a0 c5 d9 33 24 1a b2 ed 56 ad 91 c9 25 2f ff ff 09 |..3$...V...%/...|
+000000b0 dc b0 2c 38 cc 70 1f cc 6f f4 |..,8.p..o.|
diff --git a/src/crypto/tls/testdata/Server-TLSv10-ExportKeyingMaterial b/src/crypto/tls/testdata/Server-TLSv10-ExportKeyingMaterial
new file mode 100644
index 0000000..cb3b8da
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv10-ExportKeyingMaterial
@@ -0,0 +1,93 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 67 01 00 00 63 03 01 41 69 16 b5 d5 |....g...c..Ai...|
+00000010 c2 9d 36 2b 95 8e e5 41 9b 92 82 27 2a cc 4e 6e |..6+...A...'*.Nn|
+00000020 5d f1 1b 58 49 3c 95 1d 8b 61 35 00 00 04 c0 14 |]..XI<...a5.....|
+00000030 00 ff 01 00 00 36 00 00 00 0e 00 0c 00 00 09 31 |.....6.........1|
+00000040 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
+00000050 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 |................|
+00000060 00 23 00 00 00 16 00 00 00 17 00 00 |.#..........|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 3b 02 00 00 37 03 01 00 00 00 00 00 |....;...7.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 00 00 c0 14 00 00 |...DOWNGRD......|
+00000030 0f 00 23 00 00 ff 01 00 01 00 00 0b 00 02 01 00 |..#.............|
+00000040 16 03 01 02 59 0b 00 02 55 00 02 52 00 02 4f 30 |....Y...U..R..O0|
+00000050 82 02 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 |..K0............|
+00000060 f0 9d 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 |..?.[..0...*.H..|
+00000070 0d 01 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 |......0.1.0...U.|
+00000080 0a 13 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 |...Go1.0...U....|
+00000090 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 |Go Root0...16010|
+000000a0 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 |1000000Z..250101|
+000000b0 30 30 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 |000000Z0.1.0...U|
+000000c0 04 0a 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 |....Go1.0...U...|
+000000d0 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d |.Go0..0...*.H...|
+000000e0 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 |.........0......|
+000000f0 db 46 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 |.F}...'.H..(!.~.|
+00000100 b6 a2 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 |..]..RE.z6G....B|
+00000110 5b c2 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 |[.....y.@.Om..+.|
+00000120 8b c2 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 |....g....."8.J.t|
+00000130 73 2b c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c |s+.4......t{.X.l|
+00000140 61 3c c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd |a<..A..++$#w[.;.|
+00000150 75 5d ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a |u]. T..c...$....|
+00000160 50 8b aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 |P....C...ub...R.|
+00000170 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 |........0..0...U|
+00000180 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 |...........0...U|
+00000190 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+000001a0 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d |..+.......0...U.|
+000001b0 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 |......0.0...U...|
+000001c0 12 04 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 |.......CC>I..m..|
+000001d0 d7 9f 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 |..`0...U.#..0...|
+000001e0 48 13 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b |H.IM.~.1......n{|
+000001f0 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 |0...U....0...exa|
+00000200 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a |mple.golang0...*|
+00000210 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 |.H.............0|
+00000220 cc 40 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 |.@+[P.a...SX...(|
+00000230 a9 58 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 |.X..8....1Z..f=C|
+00000240 d3 2d d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc |.-...... d8.$:..|
+00000250 cf 9c 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd |..}.@ ._...a..v.|
+00000260 13 c3 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb |.....\.....l..s.|
+00000270 b3 43 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 |.Cw.......@.a.Lr|
+00000280 2b 9d ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 |+...F..M...>...B|
+00000290 d4 db fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 |...=.`.\!.;.....|
+000002a0 01 00 aa 0c 00 00 a6 03 00 1d 20 2f e5 7d a3 47 |.......... /.}.G|
+000002b0 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af |.bC.(.._.).0....|
+000002c0 c4 cf c2 ed 90 99 5f 58 cb 3b 74 00 80 c6 ad e2 |......_X.;t.....|
+000002d0 21 0d d7 30 42 da 08 52 d5 46 70 a3 e5 d6 40 ab |!..0B..R.Fp...@.|
+000002e0 bf 52 f8 da a5 41 86 1d 48 e6 51 91 52 8d 3c 5d |.R...A..H.Q.R.<]|
+000002f0 ca 36 4c 62 d1 6b c8 48 8c 99 50 89 a9 27 4b 21 |.6Lb.k.H..P..'K!|
+00000300 c9 9d a6 43 34 d2 47 a7 b3 1a 6d 98 b3 7f 37 94 |...C4.G...m...7.|
+00000310 60 ba 88 f1 b7 ed 34 2b 47 f4 80 27 d3 a0 74 6a |`.....4+G..'..tj|
+00000320 c6 d6 49 e3 8a e5 5d f1 a7 54 8a b4 84 8d a8 6b |..I...]..T.....k|
+00000330 3b 7a 3f eb 81 77 4b bf be 1e ac cd aa f9 4b 79 |;z?..wK.......Ky|
+00000340 24 78 6c 67 14 13 ab f8 ad 33 7c 94 38 16 03 01 |$xlg.....3|.8...|
+00000350 00 04 0e 00 00 00 |......|
+>>> Flow 3 (client to server)
+00000000 16 03 01 00 25 10 00 00 21 20 f5 be 48 cb fb 0d |....%...! ..H...|
+00000010 69 27 a8 ab 59 c4 9a ac 92 71 46 d1 17 7e 35 67 |i'..Y....qF..~5g|
+00000020 15 b1 ea 9f 53 48 a3 b5 f9 55 14 03 01 00 01 01 |....SH...U......|
+00000030 16 03 01 00 30 e1 79 95 7c ab 01 74 35 39 9b ce |....0.y.|..t59..|
+00000040 79 5f 15 21 88 fc be fc 46 a9 31 ca 82 07 0c 1f |y_.!....F.1.....|
+00000050 d8 2f 93 b5 5d 23 bf f9 10 40 bc b5 22 53 df d6 |./..]#...@.."S..|
+00000060 b1 10 b9 16 96 |.....|
+>>> Flow 4 (server to client)
+00000000 16 03 01 00 8b 04 00 00 87 00 00 00 00 00 81 50 |...............P|
+00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
+00000030 6d ec a4 83 51 ed 14 ef 68 ca 42 c5 4c d2 34 08 |m...Q...h.B.L.4.|
+00000040 0b cc b9 32 8f 21 f7 50 c4 e1 28 9b 7d 5e ed de |...2.!.P..(.}^..|
+00000050 0a df 30 0d 16 34 6b 6d 22 3c d3 c8 b2 99 84 8e |..0..4km"<......|
+00000060 09 6d 3c 62 d4 0f f6 37 dc 53 ae 72 40 49 38 16 |.m<b...7.S.r@I8.|
+00000070 9c 30 34 bf 6e 34 bb 54 73 33 c0 c9 8c 12 ae bc |.04.n4.Ts3......|
+00000080 e9 a8 80 23 de d0 e5 d3 46 d8 6a 86 c7 a5 6c 61 |...#....F.j...la|
+00000090 14 03 01 00 01 01 16 03 01 00 30 27 a7 5d e7 93 |..........0'.]..|
+000000a0 54 9a 77 d5 43 aa e3 ec 21 00 fa d4 36 04 c3 82 |T.w.C...!...6...|
+000000b0 b0 b7 f5 b4 19 ce f9 58 0a b4 7f d6 bf 95 43 9d |.......X......C.|
+000000c0 26 44 46 77 48 cd 77 82 e2 48 51 17 03 01 00 20 |&DFwH.w..HQ.... |
+000000d0 c0 9b b1 d3 9f e6 4f 55 59 17 5a dc e4 2f bc 04 |......OUY.Z../..|
+000000e0 6f eb 4d d9 22 6e 97 20 33 94 d4 91 aa 70 4d ab |o.M."n. 3....pM.|
+000000f0 17 03 01 00 30 9b 0f 50 a8 95 f5 db 67 96 c2 3e |....0..P....g..>|
+00000100 46 a7 41 99 d5 e2 ab 60 b1 eb 8d 68 2f 71 30 70 |F.A....`...h/q0p|
+00000110 75 cc b8 50 1a 58 3b 96 d3 5c 99 43 27 4f b1 4a |u..P.X;..\.C'O.J|
+00000120 c8 8d 5b ab 49 15 03 01 00 20 34 a6 41 25 fd 23 |..[.I.... 4.A%.#|
+00000130 44 6d 60 7f 79 5d 27 23 f7 cb 77 d0 cd 81 c4 67 |Dm`.y]'#..w....g|
+00000140 0e 56 92 60 ac a1 32 a5 0d 94 |.V.`..2...|
diff --git a/src/crypto/tls/testdata/Server-TLSv10-RSA-3DES b/src/crypto/tls/testdata/Server-TLSv10-RSA-3DES
new file mode 100644
index 0000000..502fd28
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv10-RSA-3DES
@@ -0,0 +1,76 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 63 01 00 00 5f 03 01 25 03 63 bf 34 |....c..._..%.c.4|
+00000010 89 c8 9e f6 e0 46 f8 30 5c e8 62 0a f7 db 68 c9 |.....F.0\.b...h.|
+00000020 50 54 0e c2 15 f1 cb 07 66 06 3d 00 00 04 00 0a |PT......f.=.....|
+00000030 00 ff 01 00 00 32 00 00 00 0e 00 0c 00 00 09 31 |.....2.........1|
+00000040 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
+00000050 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 |................|
+00000060 00 16 00 00 00 17 00 00 |........|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 37 02 00 00 33 03 01 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 00 00 00 0a 00 00 |...DOWNGRD......|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 01 02 |................|
+00000040 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 |Y...U..R..O0..K0|
+00000050 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 |..............?.|
+00000060 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b |[..0...*.H......|
+00000070 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 |..0.1.0...U....G|
+00000080 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 |o1.0...U....Go R|
+00000090 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 |oot0...160101000|
+000000a0 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 |000Z..2501010000|
+000000b0 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 |00Z0.1.0...U....|
+000000c0 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 |Go1.0...U....Go0|
+000000d0 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......|
+000000e0 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 |.....0.......F}.|
+000000f0 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe |..'.H..(!.~...].|
+00000100 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 |.RE.z6G....B[...|
+00000110 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e |..y.@.Om..+.....|
+00000120 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 |g....."8.J.ts+.4|
+00000130 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 |......t{.X.la<..|
+00000140 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 |A..++$#w[.;.u]. |
+00000150 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 |T..c...$....P...|
+00000160 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 |.C...ub...R.....|
+00000170 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 |....0..0...U....|
+00000180 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 |.......0...U.%..|
+00000190 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 |0...+.........+.|
+000001a0 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff |......0...U.....|
+000001b0 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f |..0.0...U.......|
+000001c0 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 |...CC>I..m....`0|
+000001d0 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d |...U.#..0...H.IM|
+000001e0 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 |.~.1......n{0...|
+000001f0 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 |U....0...example|
+00000200 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 |.golang0...*.H..|
+00000210 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b |...........0.@+[|
+00000220 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 |P.a...SX...(.X..|
+00000230 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b |8....1Z..f=C.-..|
+00000240 f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 |.... d8.$:....}.|
+00000250 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 |@ ._...a..v.....|
+00000260 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d |.\.....l..s..Cw.|
+00000270 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db |......@.a.Lr+...|
+00000280 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d |F..M...>...B...=|
+00000290 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 04 0e |.`.\!.;.........|
+000002a0 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 01 00 86 10 00 00 82 00 80 0f e9 83 ca 77 |...............w|
+00000010 c8 26 16 24 00 b7 09 d2 73 aa c1 d9 77 f3 fc 38 |.&.$....s...w..8|
+00000020 1c 2e c0 26 b4 a6 40 e1 1b 93 39 8f a2 1f f2 f9 |...&..@...9.....|
+00000030 18 2a 7b 0e cd 9b 9b 9c 49 86 43 3d 48 fd 40 d7 |.*{.....I.C=H.@.|
+00000040 af f9 2b 5e c6 cc c6 2d 8d 36 fe b1 75 c1 b5 a0 |..+^...-.6..u...|
+00000050 57 97 0f 01 ee b4 6a af 0c fe f0 68 78 04 6a 3e |W.....j....hx.j>|
+00000060 83 d0 72 34 80 d8 7d cd 8b 83 06 5b 36 50 10 8e |..r4..}....[6P..|
+00000070 b4 27 3d 6a ae b7 7f 8b 2a b1 0b 51 49 05 b5 01 |.'=j....*..QI...|
+00000080 3c 27 9a 59 e3 41 18 38 d6 8f 7a 14 03 01 00 01 |<'.Y.A.8..z.....|
+00000090 01 16 03 01 00 28 c0 46 65 9f 7f d8 c3 c4 a7 33 |.....(.Fe......3|
+000000a0 50 f9 07 41 95 12 a6 f3 ca 53 b9 96 f8 a8 a6 5f |P..A.....S....._|
+000000b0 1e c8 20 e5 8b 87 4e 12 73 13 e0 e4 c6 89 |.. ...N.s.....|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 28 e2 47 2b 57 fe |..........(.G+W.|
+00000010 74 71 95 6a ee 68 2b f3 48 40 13 52 35 46 58 d4 |tq.j.h+.H@.R5FX.|
+00000020 ee aa 4c a8 53 0f 3a 19 ed 18 37 2d e4 b9 1e e6 |..L.S.:...7-....|
+00000030 28 42 a1 17 03 01 00 18 d8 7c 20 f2 03 6d a9 ed |(B.......| ..m..|
+00000040 c9 73 50 d7 56 4f 0b d8 4b 44 f6 80 e4 c1 a9 f5 |.sP.VO..KD......|
+00000050 17 03 01 00 28 f5 b2 11 6b a6 4b 22 30 42 3c cc |....(...k.K"0B<.|
+00000060 07 0d ed 10 d0 c7 7b ec b3 60 0b 2b 3c fb ec 3a |......{..`.+<..:|
+00000070 c0 be 44 e7 76 b6 9e db 17 36 92 df 88 15 03 01 |..D.v....6......|
+00000080 00 18 7a d9 2f 46 2e 0f ec c5 ee 7b ef bd fb e5 |..z./F.....{....|
+00000090 26 40 0a a2 4e eb 56 0e ca 03 |&@..N.V...|
diff --git a/src/crypto/tls/testdata/Server-TLSv10-RSA-AES b/src/crypto/tls/testdata/Server-TLSv10-RSA-AES
new file mode 100644
index 0000000..7425376
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv10-RSA-AES
@@ -0,0 +1,79 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 63 01 00 00 5f 03 01 78 91 f6 ad 9e |....c..._..x....|
+00000010 79 23 92 10 d9 c5 43 52 8f f6 f4 3f f4 eb ac 6b |y#....CR...?...k|
+00000020 f3 ce a9 76 a2 bf c3 5b 9d bc 52 00 00 04 00 2f |...v...[..R..../|
+00000030 00 ff 01 00 00 32 00 00 00 0e 00 0c 00 00 09 31 |.....2.........1|
+00000040 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
+00000050 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 |................|
+00000060 00 16 00 00 00 17 00 00 |........|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 37 02 00 00 33 03 01 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 00 00 00 2f 00 00 |...DOWNGRD.../..|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 01 02 |................|
+00000040 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 |Y...U..R..O0..K0|
+00000050 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 |..............?.|
+00000060 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b |[..0...*.H......|
+00000070 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 |..0.1.0...U....G|
+00000080 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 |o1.0...U....Go R|
+00000090 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 |oot0...160101000|
+000000a0 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 |000Z..2501010000|
+000000b0 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 |00Z0.1.0...U....|
+000000c0 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 |Go1.0...U....Go0|
+000000d0 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......|
+000000e0 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 |.....0.......F}.|
+000000f0 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe |..'.H..(!.~...].|
+00000100 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 |.RE.z6G....B[...|
+00000110 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e |..y.@.Om..+.....|
+00000120 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 |g....."8.J.ts+.4|
+00000130 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 |......t{.X.la<..|
+00000140 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 |A..++$#w[.;.u]. |
+00000150 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 |T..c...$....P...|
+00000160 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 |.C...ub...R.....|
+00000170 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 |....0..0...U....|
+00000180 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 |.......0...U.%..|
+00000190 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 |0...+.........+.|
+000001a0 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff |......0...U.....|
+000001b0 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f |..0.0...U.......|
+000001c0 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 |...CC>I..m....`0|
+000001d0 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d |...U.#..0...H.IM|
+000001e0 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 |.~.1......n{0...|
+000001f0 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 |U....0...example|
+00000200 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 |.golang0...*.H..|
+00000210 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b |...........0.@+[|
+00000220 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 |P.a...SX...(.X..|
+00000230 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b |8....1Z..f=C.-..|
+00000240 f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 |.... d8.$:....}.|
+00000250 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 |@ ._...a..v.....|
+00000260 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d |.\.....l..s..Cw.|
+00000270 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db |......@.a.Lr+...|
+00000280 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d |F..M...>...B...=|
+00000290 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 04 0e |.`.\!.;.........|
+000002a0 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 01 00 86 10 00 00 82 00 80 73 aa be d1 21 |...........s...!|
+00000010 67 e9 9c 20 40 cf 0a 47 31 61 e9 2b ba 06 4f aa |g.. @..G1a.+..O.|
+00000020 ce 15 6a b7 df 0d 0e b0 fe b5 f2 c0 26 81 39 6e |..j.........&.9n|
+00000030 5b 96 3c 2f 42 4f 08 92 48 a3 95 c8 ad 0d 0e 8f |[.</BO..H.......|
+00000040 9c 9e fc bf d7 25 2e c7 d1 e2 e6 66 9b bf 20 94 |.....%.....f.. .|
+00000050 6f d3 62 77 38 0f f6 96 ae 54 f1 8c 6a c2 17 bd |o.bw8....T..j...|
+00000060 c6 7c 99 f0 e5 6d 1b f2 81 c6 49 29 c2 24 db a7 |.|...m....I).$..|
+00000070 0f c0 53 15 6f 3e 9b d8 c2 32 f1 3e 16 b7 d3 b2 |..S.o>...2.>....|
+00000080 36 99 9f b7 53 ef 34 e8 d6 13 3b 14 03 01 00 01 |6...S.4...;.....|
+00000090 01 16 03 01 00 30 c6 d2 a6 85 cf 2a e4 9e 9e e1 |.....0.....*....|
+000000a0 d0 82 d0 2a f8 e5 bd f6 9a 67 0b c6 47 07 9c 14 |...*.....g..G...|
+000000b0 7e 73 9e 4c 8b d2 55 4f b2 32 9a 16 16 a5 e8 25 |~s.L..UO.2.....%|
+000000c0 62 e2 e9 88 b6 44 |b....D|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 30 21 7a ee 62 6a |..........0!z.bj|
+00000010 20 39 2a 39 d1 d3 f7 bd 53 05 4f 1a 36 71 3b b6 | 9*9....S.O.6q;.|
+00000020 c5 5a b7 3b c3 0b 3f b9 2f ac 62 1c c2 2f fa 29 |.Z.;..?./.b../.)|
+00000030 dd f3 bc ff 35 28 7f 86 b8 0f 33 17 03 01 00 20 |....5(....3.... |
+00000040 3a 6c 47 23 37 5a 15 bd 03 c6 64 c5 59 2f 91 e8 |:lG#7Z....d.Y/..|
+00000050 a6 1b d5 04 c2 a7 80 0e 94 6c 3c e4 70 2c ea 81 |.........l<.p,..|
+00000060 17 03 01 00 30 60 14 bc 6b 84 16 9f 53 b6 ee c9 |....0`..k...S...|
+00000070 43 cf f3 46 97 45 e1 2f 86 96 26 cc ef ea 09 72 |C..F.E./..&....r|
+00000080 36 92 4e 9e 2a 8e a2 d7 9a cd 5f 38 a8 07 c4 54 |6.N.*....._8...T|
+00000090 a1 4d 6e 7a 36 15 03 01 00 20 1e c2 df a3 3e 8e |.Mnz6.... ....>.|
+000000a0 15 c4 c0 90 8f 7c 5a e0 68 d7 ea 86 76 8d d1 27 |.....|Z.h...v..'|
+000000b0 c1 d9 32 55 f9 ce f5 92 e6 51 |..2U.....Q|
diff --git a/src/crypto/tls/testdata/Server-TLSv10-RSA-RC4 b/src/crypto/tls/testdata/Server-TLSv10-RSA-RC4
new file mode 100644
index 0000000..8b1de03
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv10-RSA-RC4
@@ -0,0 +1,73 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 63 01 00 00 5f 03 01 55 31 1a ed 02 |....c..._..U1...|
+00000010 35 fe 3c ea 62 08 52 96 93 bc 2a 1b 82 fe b9 8f |5.<.b.R...*.....|
+00000020 7a 47 0e 6a 9b e8 86 ca 89 a0 e6 00 00 04 00 05 |zG.j............|
+00000030 00 ff 01 00 00 32 00 00 00 0e 00 0c 00 00 09 31 |.....2.........1|
+00000040 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
+00000050 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 |................|
+00000060 00 16 00 00 00 17 00 00 |........|
+>>> Flow 2 (server to client)
+00000000 16 03 01 00 37 02 00 00 33 03 01 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 00 00 00 05 00 00 |...DOWNGRD......|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 01 02 |................|
+00000040 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 |Y...U..R..O0..K0|
+00000050 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 |..............?.|
+00000060 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b |[..0...*.H......|
+00000070 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 |..0.1.0...U....G|
+00000080 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 |o1.0...U....Go R|
+00000090 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 |oot0...160101000|
+000000a0 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 |000Z..2501010000|
+000000b0 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 |00Z0.1.0...U....|
+000000c0 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 |Go1.0...U....Go0|
+000000d0 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......|
+000000e0 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 |.....0.......F}.|
+000000f0 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe |..'.H..(!.~...].|
+00000100 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 |.RE.z6G....B[...|
+00000110 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e |..y.@.Om..+.....|
+00000120 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 |g....."8.J.ts+.4|
+00000130 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 |......t{.X.la<..|
+00000140 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 |A..++$#w[.;.u]. |
+00000150 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 |T..c...$....P...|
+00000160 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 |.C...ub...R.....|
+00000170 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 |....0..0...U....|
+00000180 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 |.......0...U.%..|
+00000190 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 |0...+.........+.|
+000001a0 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff |......0...U.....|
+000001b0 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f |..0.0...U.......|
+000001c0 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 |...CC>I..m....`0|
+000001d0 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d |...U.#..0...H.IM|
+000001e0 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 |.~.1......n{0...|
+000001f0 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 |U....0...example|
+00000200 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 |.golang0...*.H..|
+00000210 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b |...........0.@+[|
+00000220 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 |P.a...SX...(.X..|
+00000230 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b |8....1Z..f=C.-..|
+00000240 f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 |.... d8.$:....}.|
+00000250 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 |@ ._...a..v.....|
+00000260 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d |.\.....l..s..Cw.|
+00000270 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db |......@.a.Lr+...|
+00000280 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d |F..M...>...B...=|
+00000290 13 60 84 5c 21 d3 3b e9 fa e7 16 03 01 00 04 0e |.`.\!.;.........|
+000002a0 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 01 00 86 10 00 00 82 00 80 75 7d be e3 5b |...........u}..[|
+00000010 66 4b 58 09 f7 86 6a ca 93 8e ba 3c 18 11 47 5e |fKX...j....<..G^|
+00000020 7e c2 b1 0c 5e a4 c1 07 ef 25 00 d7 bf c7 b0 03 |~...^....%......|
+00000030 0d f6 ff a9 c2 73 a2 c0 dc 8d db f9 5a a9 18 7d |.....s......Z..}|
+00000040 1f 8e 0b 9c 24 6c c8 49 99 e1 42 e0 86 d5 e1 e1 |....$l.I..B.....|
+00000050 d1 ae fd d2 c4 ef 07 8c 28 95 b7 54 25 57 40 1c |........(..T%W@.|
+00000060 c6 af 85 46 a0 31 d4 39 b8 47 43 88 a0 a6 5d d7 |...F.1.9.GC...].|
+00000070 95 fb 88 64 ce 36 2b c5 56 85 56 40 f8 d4 d3 90 |...d.6+.V.V@....|
+00000080 d1 25 53 06 d8 ab a0 f2 21 8f 88 14 03 01 00 01 |.%S.....!.......|
+00000090 01 16 03 01 00 24 26 50 7a 2c ab 3f db 41 06 cf |.....$&Pz,.?.A..|
+000000a0 8b 7b f8 46 ad a4 77 b6 06 f0 44 23 04 34 88 9d |.{.F..w...D#.4..|
+000000b0 48 d7 5e cc 9e e6 46 a3 04 69 |H.^...F..i|
+>>> Flow 4 (server to client)
+00000000 14 03 01 00 01 01 16 03 01 00 24 57 fc eb dd 40 |..........$W...@|
+00000010 83 1d 9a 9a 80 a3 62 a0 08 23 c3 97 fd d5 fb d7 |......b..#......|
+00000020 98 f8 14 ae 61 c7 21 fb 8a 18 1e c8 15 05 e7 17 |....a.!.........|
+00000030 03 01 00 21 7c 2b 2d 72 2f 63 56 3a 09 51 4e ab |...!|+-r/cV:.QN.|
+00000040 31 25 c8 7e 34 5b a4 ab 30 87 50 07 ed 32 3f 79 |1%.~4[..0.P..2?y|
+00000050 f1 db c0 17 f3 15 03 01 00 16 fc ce c9 0c b6 0c |................|
+00000060 c5 2d d9 3f 2a 9e 9a 83 40 e1 a3 b9 5f 89 aa 75 |.-.?*...@..._..u|
diff --git a/src/crypto/tls/testdata/Server-TLSv11-FallbackSCSV b/src/crypto/tls/testdata/Server-TLSv11-FallbackSCSV
new file mode 100644
index 0000000..7bd0341
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv11-FallbackSCSV
@@ -0,0 +1,11 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 77 01 00 00 73 03 02 0a 6b c9 55 9d |....w...s...k.U.|
+00000010 bf 4e 61 b2 0a c7 c6 96 9f eb 90 91 87 ca d3 d3 |.Na.............|
+00000020 62 dc b6 b4 db ea 41 fe 43 3e a3 00 00 14 c0 0a |b.....A.C>......|
+00000030 c0 14 00 39 c0 09 c0 13 00 33 00 35 00 2f 00 ff |...9.....3.5./..|
+00000040 56 00 01 00 00 36 00 00 00 0e 00 0c 00 00 09 31 |V....6.........1|
+00000050 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
+00000060 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 |................|
+00000070 00 23 00 00 00 16 00 00 00 17 00 00 |.#..........|
+>>> Flow 2 (server to client)
+00000000 15 03 02 00 02 02 56 |......V|
diff --git a/src/crypto/tls/testdata/Server-TLSv11-RSA-RC4 b/src/crypto/tls/testdata/Server-TLSv11-RSA-RC4
new file mode 100644
index 0000000..dc70edf
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv11-RSA-RC4
@@ -0,0 +1,73 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 63 01 00 00 5f 03 02 2b b6 22 28 e3 |....c..._..+."(.|
+00000010 1f 42 f4 2e d0 43 4b 9a ea 2b 36 44 ca 93 6c 71 |.B...CK..+6D..lq|
+00000020 b9 4d 52 44 64 57 b2 05 9b 41 da 00 00 04 00 05 |.MRDdW...A......|
+00000030 00 ff 01 00 00 32 00 00 00 0e 00 0c 00 00 09 31 |.....2.........1|
+00000040 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
+00000050 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 |................|
+00000060 00 16 00 00 00 17 00 00 |........|
+>>> Flow 2 (server to client)
+00000000 16 03 02 00 37 02 00 00 33 03 02 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 00 00 00 05 00 00 |...DOWNGRD......|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 02 02 |................|
+00000040 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 |Y...U..R..O0..K0|
+00000050 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 |..............?.|
+00000060 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b |[..0...*.H......|
+00000070 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 |..0.1.0...U....G|
+00000080 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 |o1.0...U....Go R|
+00000090 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 |oot0...160101000|
+000000a0 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 |000Z..2501010000|
+000000b0 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 |00Z0.1.0...U....|
+000000c0 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 |Go1.0...U....Go0|
+000000d0 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......|
+000000e0 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 |.....0.......F}.|
+000000f0 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe |..'.H..(!.~...].|
+00000100 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 |.RE.z6G....B[...|
+00000110 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e |..y.@.Om..+.....|
+00000120 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 |g....."8.J.ts+.4|
+00000130 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 |......t{.X.la<..|
+00000140 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 |A..++$#w[.;.u]. |
+00000150 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 |T..c...$....P...|
+00000160 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 |.C...ub...R.....|
+00000170 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 |....0..0...U....|
+00000180 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 |.......0...U.%..|
+00000190 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 |0...+.........+.|
+000001a0 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff |......0...U.....|
+000001b0 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f |..0.0...U.......|
+000001c0 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 |...CC>I..m....`0|
+000001d0 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d |...U.#..0...H.IM|
+000001e0 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 |.~.1......n{0...|
+000001f0 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 |U....0...example|
+00000200 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 |.golang0...*.H..|
+00000210 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b |...........0.@+[|
+00000220 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 |P.a...SX...(.X..|
+00000230 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b |8....1Z..f=C.-..|
+00000240 f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 |.... d8.$:....}.|
+00000250 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 |@ ._...a..v.....|
+00000260 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d |.\.....l..s..Cw.|
+00000270 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db |......@.a.Lr+...|
+00000280 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d |F..M...>...B...=|
+00000290 13 60 84 5c 21 d3 3b e9 fa e7 16 03 02 00 04 0e |.`.\!.;.........|
+000002a0 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 02 00 86 10 00 00 82 00 80 3d 47 85 0a ef |...........=G...|
+00000010 47 7c c5 93 bb 6f 7c 57 dc 2b 3f f4 e7 da 4e fc |G|...o|W.+?...N.|
+00000020 04 52 36 71 c5 63 1f 6f e6 43 91 06 bc 5c 14 b0 |.R6q.c.o.C...\..|
+00000030 ee 83 ed 3d 7a d2 4e 2c d2 2c bb f0 0c b5 82 d5 |...=z.N,.,......|
+00000040 9d c2 5a 03 12 b6 70 20 3c 89 84 af 1b 2c 2f b7 |..Z...p <....,/.|
+00000050 9b fe dd 71 06 ac 46 30 a7 b5 9f 0b aa 6e 58 50 |...q..F0.....nXP|
+00000060 9d da 6b ba 00 51 e9 2a e9 d2 e9 0f 83 62 73 19 |..k..Q.*.....bs.|
+00000070 91 a4 46 bd 53 42 f7 15 ab ab 6b 8f f3 6f d1 07 |..F.SB....k..o..|
+00000080 44 41 97 4c 7d 89 4b 33 55 30 30 14 03 02 00 01 |DA.L}.K3U00.....|
+00000090 01 16 03 02 00 24 54 fe a0 7c 16 47 de 0b 8f 7d |.....$T..|.G...}|
+000000a0 51 68 05 da 1e 6d 96 c9 e1 94 68 fa 79 46 02 db |Qh...m....h.yF..|
+000000b0 03 4e 2e 70 9f 7e 14 85 fd 1d |.N.p.~....|
+>>> Flow 4 (server to client)
+00000000 14 03 02 00 01 01 16 03 02 00 24 4b c5 cf 20 3f |..........$K.. ?|
+00000010 0a 13 1f 55 25 26 9b 33 fd 14 61 0f 44 32 26 b3 |...U%&.3..a.D2&.|
+00000020 ab 01 ee c2 1f d3 38 08 f0 af 76 6a 0d e1 b7 17 |......8...vj....|
+00000030 03 02 00 21 97 16 df 99 06 81 f2 00 d3 fd b4 03 |...!............|
+00000040 be 16 b6 aa 74 d4 c7 25 67 94 14 34 25 ec 0d 12 |....t..%g..4%...|
+00000050 c7 43 2d a2 1d 15 03 02 00 16 94 58 af 6b 55 5f |.C-........X.kU_|
+00000060 25 0c 80 28 99 2d 75 1a ce 24 cd 75 0d 7f b9 71 |%..(.-u..$.u...q|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ALPN b/src/crypto/tls/testdata/Server-TLSv12-ALPN
new file mode 100644
index 0000000..d738662
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-ALPN
@@ -0,0 +1,92 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 9d 01 00 00 99 03 03 53 49 69 68 95 |...........SIih.|
+00000010 b9 7b 2a 84 d2 03 93 d4 33 e7 b7 7e bc b5 97 b0 |.{*.....3..~....|
+00000020 4f 4f 6c d0 96 43 aa c8 6f da 90 00 00 04 cc a8 |OOl..C..o.......|
+00000030 00 ff 01 00 00 6c 00 0b 00 04 03 00 01 02 00 0a |.....l..........|
+00000040 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#|
+00000050 00 00 00 10 00 10 00 0e 06 70 72 6f 74 6f 32 06 |.........proto2.|
+00000060 70 72 6f 74 6f 31 00 16 00 00 00 17 00 00 00 0d |proto1..........|
+00000070 00 30 00 2e 04 03 05 03 06 03 08 07 08 08 08 09 |.0..............|
+00000080 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 06 01 |................|
+00000090 03 03 02 03 03 01 02 01 03 02 02 02 04 02 05 02 |................|
+000000a0 06 02 |..|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 48 02 00 00 44 03 03 00 00 00 00 00 |....H...D.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 cc a8 00 00 |...DOWNGRD......|
+00000030 1c 00 23 00 00 ff 01 00 01 00 00 10 00 09 00 07 |..#.............|
+00000040 06 70 72 6f 74 6f 31 00 0b 00 02 01 00 16 03 03 |.proto1.........|
+00000050 02 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b |.Y...U..R..O0..K|
+00000060 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f |0..............?|
+00000070 e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 |.[..0...*.H.....|
+00000080 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 |...0.1.0...U....|
+00000090 47 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 |Go1.0...U....Go |
+000000a0 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 |Root0...16010100|
+000000b0 30 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 |0000Z..250101000|
+000000c0 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 |000Z0.1.0...U...|
+000000d0 02 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f |.Go1.0...U....Go|
+000000e0 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 |0..0...*.H......|
+000000f0 05 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d |......0.......F}|
+00000100 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d |...'.H..(!.~...]|
+00000110 fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 |..RE.z6G....B[..|
+00000120 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 |...y.@.Om..+....|
+00000130 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 |.g....."8.J.ts+.|
+00000140 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 |4......t{.X.la<.|
+00000150 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce |.A..++$#w[.;.u].|
+00000160 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa | T..c...$....P..|
+00000170 b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 |..C...ub...R....|
+00000180 00 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 |.....0..0...U...|
+00000190 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 |........0...U.%.|
+000001a0 16 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b |.0...+.........+|
+000001b0 06 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 |.......0...U....|
+000001c0 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 |...0.0...U......|
+000001d0 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 |....CC>I..m....`|
+000001e0 30 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 |0...U.#..0...H.I|
+000001f0 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 |M.~.1......n{0..|
+00000200 03 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c |.U....0...exampl|
+00000210 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 |e.golang0...*.H.|
+00000220 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b |............0.@+|
+00000230 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a |[P.a...SX...(.X.|
+00000240 a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 |.8....1Z..f=C.-.|
+00000250 0b f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d |..... d8.$:....}|
+00000260 b7 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc |.@ ._...a..v....|
+00000270 e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 |..\.....l..s..Cw|
+00000280 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae |.......@.a.Lr+..|
+00000290 db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe |.F..M...>...B...|
+000002a0 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac |=.`.\!.;........|
+000002b0 0c 00 00 a8 03 00 1d 20 2f e5 7d a3 47 cd 62 43 |....... /.}.G.bC|
+000002c0 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 |.(.._.).0.......|
+000002d0 ed 90 99 5f 58 cb 3b 74 08 04 00 80 3b cd 7a 99 |..._X.;t....;.z.|
+000002e0 3f bf 03 5a 26 21 90 db b4 8d 3b 69 14 82 1c ae |?..Z&!....;i....|
+000002f0 7d 72 8f 4e eb ff c4 f0 13 fa 6f 69 48 e7 6d 3d |}r.N......oiH.m=|
+00000300 fc b3 1c 54 60 54 cf 83 48 1d a3 50 55 28 3f 2c |...T`T..H..PU(?,|
+00000310 db d3 dc c7 d9 58 74 de eb 5e 21 26 2f 32 c6 b2 |.....Xt..^!&/2..|
+00000320 be 1b 08 fa d6 9f 3b b0 2b e8 c2 36 2f 9d c1 35 |......;.+..6/..5|
+00000330 c1 54 4b 37 5f ff 99 4f c1 e4 ad 69 a0 c8 52 d3 |.TK7_..O...i..R.|
+00000340 01 23 0d 57 17 08 7c 07 9a 3a 6d c8 87 5d 7e 09 |.#.W..|..:m..]~.|
+00000350 7b 03 f9 5e de 83 4d 13 89 08 72 96 16 03 03 00 |{..^..M...r.....|
+00000360 04 0e 00 00 00 |.....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 fb eb 44 09 0e 62 |....%...! ..D..b|
+00000010 b0 ce d8 1f c5 f9 46 31 1e 1d e8 fb 02 5f 34 3b |......F1....._4;|
+00000020 c1 6f 9a 38 6a 46 d2 cd a0 53 14 03 03 00 01 01 |.o.8jF...S......|
+00000030 16 03 03 00 20 88 73 90 39 bc 9b 02 e4 c0 35 f0 |.... .s.9.....5.|
+00000040 ef 40 b0 08 ca b9 bd 25 6b cd 03 7d ec 58 73 65 |.@.....%k..}.Xse|
+00000050 d5 89 f2 f1 70 |....p|
+>>> Flow 4 (server to client)
+00000000 16 03 03 00 8b 04 00 00 87 00 00 00 00 00 81 50 |...............P|
+00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
+00000030 6f e0 18 83 51 ed 14 ef 68 ca 42 c5 4c cd 0b 21 |o...Q...h.B.L..!|
+00000040 a5 29 ef 62 07 a5 11 b9 1f 4e 54 c3 66 4c 1e d3 |.).b.....NT.fL..|
+00000050 1a 00 52 34 67 2b af 73 02 5f c9 6c 7c 6e ba f2 |..R4g+.s._.l|n..|
+00000060 e6 38 bd 23 97 3f 80 6a 3b 8e bb 98 29 49 38 16 |.8.#.?.j;...)I8.|
+00000070 77 74 2a a1 c7 36 80 de c9 91 cd b2 7d bc 6c 64 |wt*..6......}.ld|
+00000080 6c 06 57 22 d1 f2 51 5f 84 ad 30 85 3a c0 4f e7 |l.W"..Q_..0.:.O.|
+00000090 14 03 03 00 01 01 16 03 03 00 20 32 71 5a d3 94 |.......... 2qZ..|
+000000a0 d5 17 e4 8c 3a 78 d1 48 4e 1b f5 83 36 f1 5a 38 |....:x.HN...6.Z8|
+000000b0 e4 b5 6d ab 46 89 e0 24 74 87 80 17 03 03 00 1d |..m.F..$t.......|
+000000c0 69 4c a6 24 67 79 18 59 92 4f 9a d0 2d 1d 57 e0 |iL.$gy.Y.O..-.W.|
+000000d0 ec 0c 00 25 6f 2f 3a be 8a aa 80 94 ac 15 03 03 |...%o/:.........|
+000000e0 00 12 ef 86 3e 93 42 bb 72 f1 1b 90 df 9a d3 ed |....>.B.r.......|
+000000f0 d8 74 35 23 |.t5#|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ALPN-Fallback b/src/crypto/tls/testdata/Server-TLSv12-ALPN-Fallback
new file mode 100644
index 0000000..4fadf39
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-ALPN-Fallback
@@ -0,0 +1,91 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 a6 01 00 00 a2 03 03 b5 c9 ab 32 7f |..............2.|
+00000010 e1 af 3f f2 ac 2a 11 dd 33 f9 b5 21 88 0d e4 29 |..?..*..3..!...)|
+00000020 e2 47 49 dc c7 31 a8 a5 25 81 0c 00 00 04 cc a8 |.GI..1..%.......|
+00000030 00 ff 01 00 00 75 00 0b 00 04 03 00 01 02 00 0a |.....u..........|
+00000040 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#|
+00000050 00 00 00 10 00 19 00 17 06 70 72 6f 74 6f 33 08 |.........proto3.|
+00000060 68 74 74 70 2f 31 2e 31 06 70 72 6f 74 6f 34 00 |http/1.1.proto4.|
+00000070 16 00 00 00 17 00 00 00 0d 00 30 00 2e 04 03 05 |..........0.....|
+00000080 03 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 |................|
+00000090 05 08 06 04 01 05 01 06 01 03 03 02 03 03 01 02 |................|
+000000a0 01 03 02 02 02 04 02 05 02 06 02 |...........|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 3b 02 00 00 37 03 03 00 00 00 00 00 |....;...7.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 cc a8 00 00 |...DOWNGRD......|
+00000030 0f 00 23 00 00 ff 01 00 01 00 00 0b 00 02 01 00 |..#.............|
+00000040 16 03 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 |....Y...U..R..O0|
+00000050 82 02 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 |..K0............|
+00000060 f0 9d 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 |..?.[..0...*.H..|
+00000070 0d 01 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 |......0.1.0...U.|
+00000080 0a 13 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 |...Go1.0...U....|
+00000090 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 |Go Root0...16010|
+000000a0 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 |1000000Z..250101|
+000000b0 30 30 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 |000000Z0.1.0...U|
+000000c0 04 0a 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 |....Go1.0...U...|
+000000d0 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d |.Go0..0...*.H...|
+000000e0 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 |.........0......|
+000000f0 db 46 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 |.F}...'.H..(!.~.|
+00000100 b6 a2 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 |..]..RE.z6G....B|
+00000110 5b c2 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 |[.....y.@.Om..+.|
+00000120 8b c2 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 |....g....."8.J.t|
+00000130 73 2b c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c |s+.4......t{.X.l|
+00000140 61 3c c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd |a<..A..++$#w[.;.|
+00000150 75 5d ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a |u]. T..c...$....|
+00000160 50 8b aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 |P....C...ub...R.|
+00000170 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 |........0..0...U|
+00000180 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 |...........0...U|
+00000190 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+000001a0 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d |..+.......0...U.|
+000001b0 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 |......0.0...U...|
+000001c0 12 04 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 |.......CC>I..m..|
+000001d0 d7 9f 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 |..`0...U.#..0...|
+000001e0 48 13 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b |H.IM.~.1......n{|
+000001f0 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 |0...U....0...exa|
+00000200 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a |mple.golang0...*|
+00000210 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 |.H.............0|
+00000220 cc 40 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 |.@+[P.a...SX...(|
+00000230 a9 58 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 |.X..8....1Z..f=C|
+00000240 d3 2d d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc |.-...... d8.$:..|
+00000250 cf 9c 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd |..}.@ ._...a..v.|
+00000260 13 c3 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb |.....\.....l..s.|
+00000270 b3 43 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 |.Cw.......@.a.Lr|
+00000280 2b 9d ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 |+...F..M...>...B|
+00000290 d4 db fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 |...=.`.\!.;.....|
+000002a0 03 00 ac 0c 00 00 a8 03 00 1d 20 2f e5 7d a3 47 |.......... /.}.G|
+000002b0 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af |.bC.(.._.).0....|
+000002c0 c4 cf c2 ed 90 99 5f 58 cb 3b 74 08 04 00 80 5f |......_X.;t...._|
+000002d0 37 27 84 58 1e ea 1e 40 1b de a9 8f 04 d4 94 64 |7'.X...@.......d|
+000002e0 4e 27 c7 f1 b3 30 d0 53 f5 3d 57 50 d2 17 97 c8 |N'...0.S.=WP....|
+000002f0 3d 61 af a6 21 ab 1c 34 47 70 f8 b1 3b 9c 06 86 |=a..!..4Gp..;...|
+00000300 87 00 e2 13 50 83 91 ad bc 84 bd b4 7b f3 4b ed |....P.......{.K.|
+00000310 ca 81 0c 94 37 a8 ec 67 ca 9c f3 00 f6 af c2 92 |....7..g........|
+00000320 c4 8c 78 07 18 0e 43 24 1b 98 16 50 5c 2b 75 0e |..x...C$...P\+u.|
+00000330 40 66 dc 40 cd 10 1a 51 25 f3 96 25 1a 3e 70 af |@f.@...Q%..%.>p.|
+00000340 16 24 d0 1c 0e 33 f9 c1 74 cf b7 e2 28 ac 60 16 |.$...3..t...(.`.|
+00000350 03 03 00 04 0e 00 00 00 |........|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 30 f2 bb f7 a7 ac |....%...! 0.....|
+00000010 23 20 22 ee 73 0d 49 9c b3 7b c1 9a db 2c 85 f3 |# ".s.I..{...,..|
+00000020 c0 82 31 60 bd 8b 14 4e 73 43 14 03 03 00 01 01 |..1`...NsC......|
+00000030 16 03 03 00 20 09 8d c7 86 ee cc f4 c7 36 a3 49 |.... ........6.I|
+00000040 d3 f7 a1 4a 68 a2 1e b4 fc cc a2 15 cb 01 92 d8 |...Jh...........|
+00000050 72 b0 d1 6f eb |r..o.|
+>>> Flow 4 (server to client)
+00000000 16 03 03 00 8b 04 00 00 87 00 00 00 00 00 81 50 |...............P|
+00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
+00000030 6f e0 18 83 51 ed 14 ef 68 ca 42 c5 4c a2 ac 05 |o...Q...h.B.L...|
+00000040 9c 69 69 99 08 9f de a4 d4 e7 37 ab 14 38 4c 47 |.ii.......7..8LG|
+00000050 70 f0 97 1d db 2d 0a 14 c2 1e f0 16 9f 6d 37 02 |p....-.......m7.|
+00000060 4b f1 16 be 98 3f df 74 83 7c 19 85 61 49 38 16 |K....?.t.|..aI8.|
+00000070 ee 35 7a e2 3f 74 fe 8d e3 07 93 a1 5e fa f2 02 |.5z.?t......^...|
+00000080 e5 c8 60 3f 11 83 8b 0e 32 52 f1 aa 52 b7 0a 89 |..`?....2R..R...|
+00000090 14 03 03 00 01 01 16 03 03 00 20 9e 65 15 cf 45 |.......... .e..E|
+000000a0 a5 03 69 c9 b1 d8 9e 92 a3 a2 b0 df 2e 62 b1 3a |..i..........b.:|
+000000b0 17 78 cd e5 1d f3 51 42 7e 4e 25 17 03 03 00 1d |.x....QB~N%.....|
+000000c0 d9 ae d0 fa b7 90 a9 2f 28 8d 1d 6f 54 1f c0 1e |......./(..oT...|
+000000d0 4d ae b6 91 f0 e8 84 cf 86 11 22 25 ea 15 03 03 |M........."%....|
+000000e0 00 12 0e 71 f2 11 9e 9f 58 ad c0 d8 fc fa 34 bc |...q....X.....4.|
+000000f0 02 5a 60 00 |.Z`.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch b/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
new file mode 100644
index 0000000..2d8a2eb
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-ALPN-NoMatch
@@ -0,0 +1,14 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 9d 01 00 00 99 03 03 24 15 a8 f2 f5 |...........$....|
+00000010 53 02 78 f0 4c f7 82 3c 68 7d a0 b1 9a 0f 29 32 |S.x.L..<h}....)2|
+00000020 9c 38 cc e7 92 95 63 f2 30 53 46 00 00 04 cc a8 |.8....c.0SF.....|
+00000030 00 ff 01 00 00 6c 00 0b 00 04 03 00 01 02 00 0a |.....l..........|
+00000040 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#|
+00000050 00 00 00 10 00 10 00 0e 06 70 72 6f 74 6f 32 06 |.........proto2.|
+00000060 70 72 6f 74 6f 31 00 16 00 00 00 17 00 00 00 0d |proto1..........|
+00000070 00 30 00 2e 04 03 05 03 06 03 08 07 08 08 08 09 |.0..............|
+00000080 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 06 01 |................|
+00000090 03 03 02 03 03 01 02 01 03 02 02 02 04 02 05 02 |................|
+000000a0 06 02 |..|
+>>> Flow 2 (server to client)
+00000000 15 03 03 00 02 02 78 |......x|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ALPN-NotConfigured b/src/crypto/tls/testdata/Server-TLSv12-ALPN-NotConfigured
new file mode 100644
index 0000000..e1c991b
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-ALPN-NotConfigured
@@ -0,0 +1,91 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 9d 01 00 00 99 03 03 92 d8 d4 4f 2e |..............O.|
+00000010 82 ad e9 4f a2 c3 f7 23 da 2e dc 23 c0 87 fc 33 |...O...#...#...3|
+00000020 14 63 f1 da 98 a8 af 70 3a 7e f3 00 00 04 cc a8 |.c.....p:~......|
+00000030 00 ff 01 00 00 6c 00 0b 00 04 03 00 01 02 00 0a |.....l..........|
+00000040 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#|
+00000050 00 00 00 10 00 10 00 0e 06 70 72 6f 74 6f 32 06 |.........proto2.|
+00000060 70 72 6f 74 6f 31 00 16 00 00 00 17 00 00 00 0d |proto1..........|
+00000070 00 30 00 2e 04 03 05 03 06 03 08 07 08 08 08 09 |.0..............|
+00000080 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 06 01 |................|
+00000090 03 03 02 03 03 01 02 01 03 02 02 02 04 02 05 02 |................|
+000000a0 06 02 |..|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 3b 02 00 00 37 03 03 00 00 00 00 00 |....;...7.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 cc a8 00 00 |...DOWNGRD......|
+00000030 0f 00 23 00 00 ff 01 00 01 00 00 0b 00 02 01 00 |..#.............|
+00000040 16 03 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 |....Y...U..R..O0|
+00000050 82 02 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 |..K0............|
+00000060 f0 9d 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 |..?.[..0...*.H..|
+00000070 0d 01 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 |......0.1.0...U.|
+00000080 0a 13 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 |...Go1.0...U....|
+00000090 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 |Go Root0...16010|
+000000a0 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 |1000000Z..250101|
+000000b0 30 30 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 |000000Z0.1.0...U|
+000000c0 04 0a 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 |....Go1.0...U...|
+000000d0 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d |.Go0..0...*.H...|
+000000e0 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 |.........0......|
+000000f0 db 46 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 |.F}...'.H..(!.~.|
+00000100 b6 a2 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 |..]..RE.z6G....B|
+00000110 5b c2 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 |[.....y.@.Om..+.|
+00000120 8b c2 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 |....g....."8.J.t|
+00000130 73 2b c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c |s+.4......t{.X.l|
+00000140 61 3c c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd |a<..A..++$#w[.;.|
+00000150 75 5d ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a |u]. T..c...$....|
+00000160 50 8b aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 |P....C...ub...R.|
+00000170 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 |........0..0...U|
+00000180 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 |...........0...U|
+00000190 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+000001a0 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d |..+.......0...U.|
+000001b0 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 |......0.0...U...|
+000001c0 12 04 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 |.......CC>I..m..|
+000001d0 d7 9f 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 |..`0...U.#..0...|
+000001e0 48 13 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b |H.IM.~.1......n{|
+000001f0 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 |0...U....0...exa|
+00000200 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a |mple.golang0...*|
+00000210 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 |.H.............0|
+00000220 cc 40 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 |.@+[P.a...SX...(|
+00000230 a9 58 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 |.X..8....1Z..f=C|
+00000240 d3 2d d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc |.-...... d8.$:..|
+00000250 cf 9c 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd |..}.@ ._...a..v.|
+00000260 13 c3 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb |.....\.....l..s.|
+00000270 b3 43 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 |.Cw.......@.a.Lr|
+00000280 2b 9d ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 |+...F..M...>...B|
+00000290 d4 db fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 |...=.`.\!.;.....|
+000002a0 03 00 ac 0c 00 00 a8 03 00 1d 20 2f e5 7d a3 47 |.......... /.}.G|
+000002b0 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af |.bC.(.._.).0....|
+000002c0 c4 cf c2 ed 90 99 5f 58 cb 3b 74 08 04 00 80 8c |......_X.;t.....|
+000002d0 cb 8c f6 6c dd 02 5f c9 13 7e c2 26 26 41 7a 1a |...l.._..~.&&Az.|
+000002e0 25 c7 3e 22 11 30 32 c0 67 a5 53 32 1e 32 21 cb |%.>".02.g.S2.2!.|
+000002f0 ff 0a b7 e1 7a 98 26 e9 bf 05 30 f6 13 38 ee 1d |....z.&...0..8..|
+00000300 90 56 a6 0d e0 65 a8 02 0e 08 3e c0 31 ff dd fa |.V...e....>.1...|
+00000310 05 3a 22 7c f8 ce 65 43 0c b6 c4 9a e4 ed 22 eb |.:"|..eC......".|
+00000320 c4 46 b2 3d 1d 9c c1 e7 d4 6a 79 4f cf 8f 1c 45 |.F.=.....jyO...E|
+00000330 52 51 b3 d1 a4 0d 0d df 4e 19 15 e6 af 2e 5a d5 |RQ......N.....Z.|
+00000340 8a 2e 3c 48 8a f7 86 e5 53 0e 35 9a 8a c6 dd 16 |..<H....S.5.....|
+00000350 03 03 00 04 0e 00 00 00 |........|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 b7 d6 2f 99 8f c7 |....%...! ../...|
+00000010 bc 48 b8 4f 01 f8 2c ff 75 e5 fe 10 c6 2d 2d d5 |.H.O..,.u....--.|
+00000020 43 2b c3 14 cb d0 b2 7a e9 71 14 03 03 00 01 01 |C+.....z.q......|
+00000030 16 03 03 00 20 c9 88 f1 a0 1a 9b 8a 14 00 33 f0 |.... .........3.|
+00000040 e8 01 f3 c2 66 06 98 44 4d 35 89 8f 1b 65 d0 cf |....f..DM5...e..|
+00000050 eb 7d 9f b1 df |.}...|
+>>> Flow 4 (server to client)
+00000000 16 03 03 00 8b 04 00 00 87 00 00 00 00 00 81 50 |...............P|
+00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
+00000030 6f e0 18 83 51 ed 14 ef 68 ca 42 c5 4c 76 fb ec |o...Q...h.B.Lv..|
+00000040 0d 89 48 e7 19 98 64 df 59 8f df 50 ce 28 e8 3c |..H...d.Y..P.(.<|
+00000050 b6 f8 5a ae bc 6b 2e a2 d6 23 05 f6 7f 36 ea 55 |..Z..k...#...6.U|
+00000060 13 54 9e 9c 31 df d0 56 00 1f a7 6a b2 49 38 16 |.T..1..V...j.I8.|
+00000070 7f d0 78 12 95 86 11 ca 98 63 07 4a 81 a5 d3 bd |..x......c.J....|
+00000080 dc 9e 54 9c 25 f2 55 d5 fd cf 36 94 99 e0 c5 82 |..T.%.U...6.....|
+00000090 14 03 03 00 01 01 16 03 03 00 20 e6 d9 c2 bb ca |.......... .....|
+000000a0 02 d3 79 a4 fb b0 00 7d e2 47 46 d3 e7 b4 fe be |..y....}.GF.....|
+000000b0 b3 8f c4 98 b7 f7 25 bc cc 3f a8 17 03 03 00 1d |......%..?......|
+000000c0 ad f3 27 a0 c4 a4 5b 7b 40 11 a4 35 e6 10 03 63 |..'...[{@..5...c|
+000000d0 13 d3 1c ce 75 8f 09 8b 85 6c 93 b1 9f 15 03 03 |....u....l......|
+000000e0 00 12 79 0c dd 21 72 68 b8 30 45 5d 45 39 a9 c4 |..y..!rh.0E]E9..|
+000000f0 a6 d7 12 99 |....|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
new file mode 100644
index 0000000..3d1ceaf
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndECDSAGiven
@@ -0,0 +1,126 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 6d 01 00 00 69 03 03 b0 00 44 aa 86 |....m...i....D..|
+00000010 30 87 8e 3f f1 89 9a 4a f6 4c 3b 11 f3 4f e9 9f |0..?...J.L;..O..|
+00000020 00 22 47 82 26 57 c7 d0 f9 59 6f 00 00 04 00 2f |."G.&W...Yo..../|
+00000030 00 ff 01 00 00 3c 00 16 00 00 00 17 00 00 00 0d |.....<..........|
+00000040 00 30 00 2e 04 03 05 03 06 03 08 07 08 08 08 09 |.0..............|
+00000050 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 06 01 |................|
+00000060 03 03 02 03 03 01 02 01 03 02 02 02 04 02 05 02 |................|
+00000070 06 02 |..|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 00 2f 00 00 |...DOWNGRD.../..|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 23 0d 00 00 1f 02 01 40 |;.......#......@|
+000002a0 00 18 08 04 04 03 08 07 08 05 08 06 04 01 05 01 |................|
+000002b0 06 01 05 03 06 03 02 01 02 03 00 00 16 03 03 00 |................|
+000002c0 04 0e 00 00 00 |.....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 02 0a 0b 00 02 06 00 02 03 00 02 00 30 |...............0|
+00000010 82 01 fc 30 82 01 5e 02 09 00 9a 30 84 6c 26 35 |...0..^....0.l&5|
+00000020 d9 17 30 09 06 07 2a 86 48 ce 3d 04 01 30 45 31 |..0...*.H.=..0E1|
+00000030 0b 30 09 06 03 55 04 06 13 02 41 55 31 13 30 11 |.0...U....AU1.0.|
+00000040 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 74 61 74 |..U....Some-Stat|
+00000050 65 31 21 30 1f 06 03 55 04 0a 13 18 49 6e 74 65 |e1!0...U....Inte|
+00000060 72 6e 65 74 20 57 69 64 67 69 74 73 20 50 74 79 |rnet Widgits Pty|
+00000070 20 4c 74 64 30 1e 17 0d 31 32 31 31 31 34 31 33 | Ltd0...12111413|
+00000080 32 35 35 33 5a 17 0d 32 32 31 31 31 32 31 33 32 |2553Z..221112132|
+00000090 35 35 33 5a 30 41 31 0b 30 09 06 03 55 04 06 13 |553Z0A1.0...U...|
+000000a0 02 41 55 31 0c 30 0a 06 03 55 04 08 13 03 4e 53 |.AU1.0...U....NS|
+000000b0 57 31 10 30 0e 06 03 55 04 07 13 07 50 79 72 6d |W1.0...U....Pyrm|
+000000c0 6f 6e 74 31 12 30 10 06 03 55 04 03 13 09 4a 6f |ont1.0...U....Jo|
+000000d0 65 6c 20 53 69 6e 67 30 81 9b 30 10 06 07 2a 86 |el Sing0..0...*.|
+000000e0 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....|
+000000f0 04 00 95 8c 91 75 14 c0 5e c4 57 b4 d4 c3 6f 8d |.....u..^.W...o.|
+00000100 ae 68 1e dd 6f ce 86 e1 7e 6e b2 48 3e 81 e5 4e |.h..o...~n.H>..N|
+00000110 e2 c6 88 4b 64 dc f5 30 bb d3 ff 65 cc 5b f4 dd |...Kd..0...e.[..|
+00000120 b5 6a 3e 3e d0 1d de 47 c3 76 ad 19 f6 45 2c 8c |.j>>...G.v...E,.|
+00000130 bc d8 1d 01 4c 1f 70 90 46 76 48 8b 8f 83 cc 4a |....L.p.FvH....J|
+00000140 5c 8f 40 76 da e0 89 ec 1d 2b c4 4e 30 76 28 41 |\.@v.....+.N0v(A|
+00000150 b2 62 a8 fb 5b f1 f9 4e 7a 8d bd 09 b8 ae ea 8b |.b..[..Nz.......|
+00000160 18 27 4f 2e 70 fe 13 96 ba c3 d3 40 16 cd 65 4e |.'O.p......@..eN|
+00000170 ac 11 1e e6 f1 30 09 06 07 2a 86 48 ce 3d 04 01 |.....0...*.H.=..|
+00000180 03 81 8c 00 30 81 88 02 42 00 e0 14 c4 60 60 0b |....0...B....``.|
+00000190 72 68 b0 32 5d 61 4a 02 74 5c c2 81 b9 16 a8 3f |rh.2]aJ.t\.....?|
+000001a0 29 c8 36 c7 81 ff 6c b6 5b d9 70 f1 38 3b 50 48 |).6...l.[.p.8;PH|
+000001b0 28 94 cb 09 1a 52 f1 5d ee 8d f2 b9 f0 f0 da d9 |(....R.]........|
+000001c0 15 3a f9 bd 03 7a 87 a2 23 35 ec 02 42 01 a3 d4 |.:...z..#5..B...|
+000001d0 8a 78 35 1c 4a 9a 23 d2 0a be 2b 10 31 9d 9c 5f |.x5.J.#...+.1.._|
+000001e0 be e8 91 b3 da 1a f5 5d a3 23 f5 26 8b 45 70 8d |.......].#.&.Ep.|
+000001f0 65 62 9b 7e 01 99 3d 18 f6 10 9a 38 61 9b 2e 57 |eb.~..=....8a..W|
+00000200 e4 fa cc b1 8a ce e2 23 a0 87 f0 e1 67 51 eb 16 |.......#....gQ..|
+00000210 03 03 00 86 10 00 00 82 00 80 10 ab 2f 0f b9 29 |............/..)|
+00000220 9f 26 36 09 00 96 9a 3d 2a 01 50 03 f3 d6 ac fc |.&6....=*.P.....|
+00000230 40 76 96 d0 e6 a6 67 89 24 b0 56 80 58 5e 6d 03 |@v....g.$.V.X^m.|
+00000240 e3 0f dc 61 d1 de 25 95 8a 54 9f 5b 3e f2 31 dd |...a..%..T.[>.1.|
+00000250 14 2a e2 de 7b 70 66 b5 ed 95 d9 cc 6f c0 b3 a1 |.*..{pf.....o...|
+00000260 bb 41 b2 0f 7d e8 ce b5 11 eb 99 e2 ce c0 33 bc |.A..}.........3.|
+00000270 6a 67 10 84 d2 dd ac 15 8f 8e aa 2b 1a 7b ca d3 |jg.........+.{..|
+00000280 bb 4b 92 c4 b9 2b 08 c1 0d b2 cf 96 63 64 9d 12 |.K...+......cd..|
+00000290 a6 93 cd 21 3b bc 8e 94 72 76 16 03 03 00 93 0f |...!;...rv......|
+000002a0 00 00 8f 04 03 00 8b 30 81 88 02 42 00 d5 05 54 |.......0...B...T|
+000002b0 b2 68 a5 04 d6 3c 7b 7d c1 be e3 d1 b4 25 42 d6 |.h...<{}.....%B.|
+000002c0 2a 3a 2e ea 73 0d 57 ba 0f 96 78 66 c2 c5 d7 57 |*:..s.W...xf...W|
+000002d0 79 9c 22 8b 76 e9 45 ff ef 92 e9 43 3e b8 8b b4 |y.".v.E....C>...|
+000002e0 cf 3f 67 aa 70 d1 e8 a2 1c a8 3d 24 a2 78 02 42 |.?g.p.....=$.x.B|
+000002f0 01 b2 17 64 66 2f 2e 0d 2d b9 1d 67 45 de 48 9e |...df/..-..gE.H.|
+00000300 32 f2 1f 79 38 39 b8 bb 8b 7f 82 e9 46 fd 9b 1b |2..y89......F...|
+00000310 b3 dd a4 9c 15 b2 a2 88 4c f7 42 a2 62 92 c0 d0 |........L.B.b...|
+00000320 a1 78 aa 8b 2d 78 4f 02 5a f7 eb ca c7 34 fc b6 |.x..-xO.Z....4..|
+00000330 6c 6e 14 03 03 00 01 01 16 03 03 00 40 bd 47 9b |ln..........@.G.|
+00000340 ce 31 2c 09 d3 a8 2c bb 28 0c e8 bd 01 a9 54 34 |.1,...,.(.....T4|
+00000350 a5 74 af e0 d2 38 f3 1b fa d0 2b a6 39 24 ae de |.t...8....+.9$..|
+00000360 0a cf 4b c0 a2 3b bf 80 23 71 0a 60 ca 94 b7 23 |..K..;..#q.`...#|
+00000370 80 e3 89 89 42 74 0b a1 c6 f6 d2 c0 79 |....Bt......y|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 54 52 4a 33 9e |...........TRJ3.|
+00000020 bb 59 7e 21 03 a6 23 bd 68 18 43 b5 c5 c5 37 a2 |.Y~!..#.h.C...7.|
+00000030 6f ac 8c 78 c5 cf 8f e6 01 df 17 53 45 6f 1a e0 |o..x.......SEo..|
+00000040 9c 4a 3d 2c cb 0d 55 7d 32 81 ec 17 03 03 00 40 |.J=,..U}2......@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 ba 75 93 00 86 1c bc 66 9e 27 2f 2b 5a 68 0e 44 |.u.....f.'/+Zh.D|
+00000070 81 15 0d 67 e6 ee 7a 43 08 78 93 71 91 00 56 0e |...g..zC.x.q..V.|
+00000080 c6 e1 73 4b af 2f e6 e0 92 4d e5 35 ea 53 7c 45 |..sK./...M.5.S|E|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 8d 7e 99 bb 93 bd 5d ba 31 b0 0d |......~....].1..|
+000000b0 1f 76 95 50 7c 1e 24 62 9d 05 65 3f ee b7 c2 24 |.v.P|.$b..e?...$|
+000000c0 13 60 43 69 3a |.`Ci:|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndEd25519Given b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndEd25519Given
new file mode 100644
index 0000000..1c3b08f
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndEd25519Given
@@ -0,0 +1,109 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 6d 01 00 00 69 03 03 aa ad c9 dc 56 |....m...i......V|
+00000010 79 2e da 42 a6 b2 9e 0a 85 a6 1b e0 5e cd 4e f5 |y..B........^.N.|
+00000020 93 93 0c d5 62 a8 53 17 10 f7 e6 00 00 04 00 2f |....b.S......../|
+00000030 00 ff 01 00 00 3c 00 16 00 00 00 17 00 00 00 0d |.....<..........|
+00000040 00 30 00 2e 04 03 05 03 06 03 08 07 08 08 08 09 |.0..............|
+00000050 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 06 01 |................|
+00000060 03 03 02 03 03 01 02 01 03 02 02 02 04 02 05 02 |................|
+00000070 06 02 |..|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 00 2f 00 00 |...DOWNGRD.../..|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 23 0d 00 00 1f 02 01 40 |;.......#......@|
+000002a0 00 18 08 04 04 03 08 07 08 05 08 06 04 01 05 01 |................|
+000002b0 06 01 05 03 06 03 02 01 02 03 00 00 16 03 03 00 |................|
+000002c0 04 0e 00 00 00 |.....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 01 3c 0b 00 01 38 00 01 35 00 01 32 30 |....<...8..5..20|
+00000010 82 01 2e 30 81 e1 a0 03 02 01 02 02 10 17 d1 81 |...0............|
+00000020 93 be 2a 8c 21 20 10 25 15 e8 34 23 4f 30 05 06 |..*.! .%..4#O0..|
+00000030 03 2b 65 70 30 12 31 10 30 0e 06 03 55 04 0a 13 |.+ep0.1.0...U...|
+00000040 07 41 63 6d 65 20 43 6f 30 1e 17 0d 31 39 30 35 |.Acme Co0...1905|
+00000050 31 36 32 31 35 34 32 36 5a 17 0d 32 30 30 35 31 |16215426Z..20051|
+00000060 35 32 31 35 34 32 36 5a 30 12 31 10 30 0e 06 03 |5215426Z0.1.0...|
+00000070 55 04 0a 13 07 41 63 6d 65 20 43 6f 30 2a 30 05 |U....Acme Co0*0.|
+00000080 06 03 2b 65 70 03 21 00 0b e0 b5 60 b5 e2 79 30 |..+ep.!....`..y0|
+00000090 3d be e3 1e e0 50 b1 04 c8 6d c7 78 6c 69 2f c5 |=....P...m.xli/.|
+000000a0 14 ad 9a 63 6f 79 12 91 a3 4d 30 4b 30 0e 06 03 |...coy...M0K0...|
+000000b0 55 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 |U...........0...|
+000000c0 55 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 |U.%..0...+......|
+000000d0 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 |.0...U.......0.0|
+000000e0 16 06 03 55 1d 11 04 0f 30 0d 82 0b 65 78 61 6d |...U....0...exam|
+000000f0 70 6c 65 2e 63 6f 6d 30 05 06 03 2b 65 70 03 41 |ple.com0...+ep.A|
+00000100 00 fc 19 17 2a 94 a5 31 fa 29 c8 2e 7f 5b a0 5d |....*..1.)...[.]|
+00000110 8a 4e 34 40 39 d6 b3 10 dc 19 fe a0 22 71 b3 f5 |.N4@9......."q..|
+00000120 8f a1 58 0d cd f4 f1 85 24 bf e6 3d 14 df df ed |..X.....$..=....|
+00000130 0e e1 17 d8 11 a2 60 d0 8a 37 23 2a c2 46 aa 3a |......`..7#*.F.:|
+00000140 08 16 03 03 00 86 10 00 00 82 00 80 14 f2 ac 22 |..............."|
+00000150 fb 0b f8 03 a7 cf 23 d5 ea 9f b0 f2 64 ae 41 fe |......#.....d.A.|
+00000160 33 f7 54 69 f5 41 b7 c1 91 6d 2b 3e 14 2a f6 c8 |3.Ti.A...m+>.*..|
+00000170 96 45 00 28 13 f5 2f de 35 f9 64 89 5c 99 3e 89 |.E.(../.5.d.\.>.|
+00000180 06 ff 59 56 69 db 5f 6e 02 84 dd 1c 44 7b 86 e8 |..YVi._n....D{..|
+00000190 e3 d9 03 f1 16 9e 06 23 00 43 91 ec a9 dd da a4 |.......#.C......|
+000001a0 ac fe 5b f8 62 f9 76 19 38 83 54 b4 8c 0b 02 f0 |..[.b.v.8.T.....|
+000001b0 fa 7a 8e 2e da 9d e1 4a c6 51 92 9b f6 4b a1 31 |.z.....J.Q...K.1|
+000001c0 c9 64 b2 a6 9a 01 52 86 b3 7a 43 17 16 03 03 00 |.d....R..zC.....|
+000001d0 48 0f 00 00 44 08 07 00 40 29 35 71 34 aa b1 f1 |H...D...@)5q4...|
+000001e0 64 08 4e 06 43 db 00 f7 f5 98 8e b6 51 d7 c4 b5 |d.N.C.......Q...|
+000001f0 2b fa 56 8b bd 7b 18 f2 81 e9 2f 81 82 d8 90 e7 |+.V..{..../.....|
+00000200 5b bc 72 7e f7 97 43 df cd 07 bf 7b ae 60 08 8b |[.r~..C....{.`..|
+00000210 0a 71 c5 bf f0 7a 3e cc 0b 14 03 03 00 01 01 16 |.q...z>.........|
+00000220 03 03 00 40 85 4f e0 c0 f3 3e a4 51 68 d6 ec 1b |...@.O...>.Qh...|
+00000230 f1 4b 3e 0e 13 84 87 e3 3c 9a 5f 67 75 3a ad 08 |.K>.....<._gu:..|
+00000240 be 29 15 b0 1f 62 27 fd d8 dd 58 b1 65 e7 e2 db |.)...b'...X.e...|
+00000250 fe 55 a5 2d 2e 71 59 07 ad 12 12 80 12 bb 26 36 |.U.-.qY.......&6|
+00000260 93 fb ea b1 |....|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 f4 ed 23 ce da |.............#..|
+00000020 73 5f ef 6b a2 82 3d a5 c6 f1 fd 8f a0 47 4e 34 |s_.k..=......GN4|
+00000030 f9 7c d0 67 49 00 11 c3 76 83 23 3f 99 41 d5 5c |.|.gI...v.#?.A.\|
+00000040 aa 9f 97 66 b7 0a 59 ba f3 40 83 17 03 03 00 40 |...f..Y..@.....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 82 66 85 d7 47 a6 5a 19 4f 89 5c 56 43 cb 6a bd |.f..G.Z.O.\VC.j.|
+00000070 1b ae 46 40 7d e8 a9 7b 57 04 91 8b d5 de 24 f1 |..F@}..{W.....$.|
+00000080 c0 df 37 45 e9 af d7 c5 1c e7 ee 80 0d 61 2a 7f |..7E.........a*.|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 5a 97 f3 38 e5 3a f1 07 79 b7 eb |.....Z..8.:..y..|
+000000b0 ed 85 57 3a 96 16 51 38 85 86 ec 1b 9b 48 82 9c |..W:..Q8.....H..|
+000000c0 05 bf 4d e5 fb |..M..|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
new file mode 100644
index 0000000..3dec0de
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndGiven
@@ -0,0 +1,125 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 6d 01 00 00 69 03 03 e7 7e 1f 56 df |....m...i...~.V.|
+00000010 f1 1b e5 92 47 3b fb 25 a6 57 7d 13 47 08 f0 0f |....G;.%.W}.G...|
+00000020 5b 64 64 00 d3 25 33 e5 a5 5b e3 00 00 04 00 2f |[dd..%3..[...../|
+00000030 00 ff 01 00 00 3c 00 16 00 00 00 17 00 00 00 0d |.....<..........|
+00000040 00 30 00 2e 04 03 05 03 06 03 08 07 08 08 08 09 |.0..............|
+00000050 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 06 01 |................|
+00000060 03 03 02 03 03 01 02 01 03 02 02 02 04 02 05 02 |................|
+00000070 06 02 |..|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 00 2f 00 00 |...DOWNGRD.../..|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 23 0d 00 00 1f 02 01 40 |;.......#......@|
+000002a0 00 18 08 04 04 03 08 07 08 05 08 06 04 01 05 01 |................|
+000002b0 06 01 05 03 06 03 02 01 02 03 00 00 16 03 03 00 |................|
+000002c0 04 0e 00 00 00 |.....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 03 00 86 10 00 00 82 00 80 7f 38 c9 |.5............8.|
+00000210 56 ed de 7d a6 2c dc cc 24 61 ea d3 8a fc b8 18 |V..}.,..$a......|
+00000220 b8 e5 50 3e c3 d1 ca cf f7 0c d9 9b 22 d8 6d 0f |..P>........".m.|
+00000230 71 e7 dd 7c 24 84 c6 f1 6a ac a0 3d ea d7 65 24 |q..|$...j..=..e$|
+00000240 d7 3a 17 d5 b7 ec f7 03 bc 58 3a 01 d5 08 27 25 |.:.......X:...'%|
+00000250 b9 2f 3b 96 cb d5 7c 12 20 f4 f1 91 58 13 fb 50 |./;...|. ...X..P|
+00000260 f8 d5 5c e4 43 85 e8 41 37 3e ff fa a6 64 92 4d |..\.C..A7>...d.M|
+00000270 bd d4 96 59 bd 94 f1 95 21 ad 75 1e 0d a2 8d 30 |...Y....!.u....0|
+00000280 a3 82 f4 56 0f ba 5d 40 32 7f 0c 5f 5a 16 03 03 |...V..]@2.._Z...|
+00000290 00 88 0f 00 00 84 08 04 00 80 39 b4 f4 68 e9 96 |..........9..h..|
+000002a0 01 53 95 31 26 fa 3c 70 46 9f ba 62 b4 37 ea a6 |.S.1&.<pF..b.7..|
+000002b0 e4 81 d1 21 f4 1f 21 d4 6d c0 98 20 40 56 52 79 |...!..!.m.. @VRy|
+000002c0 99 18 c7 f1 6f 01 25 e1 65 71 33 9e 4b 81 11 a0 |....o.%.eq3.K...|
+000002d0 68 e2 be 39 05 86 81 44 a5 64 3d 07 e3 3b 48 70 |h..9...D.d=..;Hp|
+000002e0 14 fd 1f 75 05 23 44 57 3e dd 47 79 17 c3 5e 70 |...u.#DW>.Gy..^p|
+000002f0 30 8c 11 3f 27 43 4f 5d 81 89 83 39 9d fe 0c c3 |0..?'CO]...9....|
+00000300 af 40 8d 2a 41 bf 57 67 7a df b4 89 29 10 9a 84 |.@.*A.Wgz...)...|
+00000310 ff 8c 2f 58 1a 0a b9 62 4e 8e 14 03 03 00 01 01 |../X...bN.......|
+00000320 16 03 03 00 40 7c 7a 79 ae 84 60 b8 95 83 30 78 |....@|zy..`...0x|
+00000330 e9 6e 02 36 52 85 5a 6a a7 b5 f5 6d 4d a9 09 9d |.n.6R.Zj...mM...|
+00000340 43 9d 46 da d0 cf 75 25 49 e1 79 0b 23 2d 85 c2 |C.F...u%I.y.#-..|
+00000350 fd 5d 90 08 f5 75 81 ab 01 a0 f4 93 12 87 fb e3 |.]...u..........|
+00000360 9b 99 4d fa c5 |..M..|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 48 61 67 c0 1e |...........Hag..|
+00000020 09 79 82 cc 55 60 fa e5 bd 1a 1d 14 d3 25 e6 4b |.y..U`.......%.K|
+00000030 b7 a6 47 64 01 65 12 b3 37 42 1a 13 d9 90 12 7e |..Gd.e..7B.....~|
+00000040 ea d8 30 39 e2 25 5e 9a 05 61 11 17 03 03 00 40 |..09.%^..a.....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 cf c5 73 08 e9 15 25 b6 d8 e3 fa 0c a1 25 33 75 |..s...%......%3u|
+00000070 8a 2e 66 03 c2 2d 50 c7 e1 10 b4 2a 0c 88 87 90 |..f..-P....*....|
+00000080 04 4a 80 26 85 4b fd 9a 4f 0e b1 2c f0 18 57 f5 |.J.&.K..O..,..W.|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 ce e0 a1 71 be 3d 1e b0 bd 06 4c |........q.=....L|
+000000b0 1f 5b 10 8d 77 18 e0 c5 81 c9 4e 1b 3b 96 f6 6d |.[..w.....N.;..m|
+000000c0 88 03 53 54 30 |..ST0|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndPKCS1v15Given b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndPKCS1v15Given
new file mode 100644
index 0000000..8efbc91
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedAndPKCS1v15Given
@@ -0,0 +1,125 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 6d 01 00 00 69 03 03 4c 65 99 ab e0 |....m...i..Le...|
+00000010 4b 0a 08 f5 06 20 f9 3d 96 4f 05 e3 58 6f 41 50 |K.... .=.O..XoAP|
+00000020 c1 5f e8 a8 0a 5f 8f f2 de 7f 16 00 00 04 00 2f |._..._........./|
+00000030 00 ff 01 00 00 3c 00 16 00 00 00 17 00 00 00 0d |.....<..........|
+00000040 00 30 00 2e 04 03 05 03 06 03 08 07 08 08 08 09 |.0..............|
+00000050 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 06 01 |................|
+00000060 03 03 02 03 03 01 02 01 03 02 02 02 04 02 05 02 |................|
+00000070 06 02 |..|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 00 2f 00 00 |...DOWNGRD.../..|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 23 0d 00 00 1f 02 01 40 |;.......#......@|
+000002a0 00 18 08 04 04 03 08 07 08 05 08 06 04 01 05 01 |................|
+000002b0 06 01 05 03 06 03 02 01 02 03 00 00 16 03 03 00 |................|
+000002c0 04 0e 00 00 00 |.....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 01 fd 0b 00 01 f9 00 01 f6 00 01 f3 30 |...............0|
+00000010 82 01 ef 30 82 01 58 a0 03 02 01 02 02 10 5c 19 |...0..X.......\.|
+00000020 c1 89 65 83 55 6f dc 0b c9 b9 93 9f e9 bc 30 0d |..e.Uo........0.|
+00000030 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 12 31 |..*.H........0.1|
+00000040 10 30 0e 06 03 55 04 0a 13 07 41 63 6d 65 20 43 |.0...U....Acme C|
+00000050 6f 30 1e 17 0d 31 36 30 38 31 37 32 31 35 32 33 |o0...16081721523|
+00000060 31 5a 17 0d 31 37 30 38 31 37 32 31 35 32 33 31 |1Z..170817215231|
+00000070 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 |Z0.1.0...U....Ac|
+00000080 6d 65 20 43 6f 30 81 9f 30 0d 06 09 2a 86 48 86 |me Co0..0...*.H.|
+00000090 f7 0d 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 |...........0....|
+000000a0 81 00 ba 6f aa 86 bd cf bf 9f f2 ef 5c 94 60 78 |...o........\.`x|
+000000b0 6f e8 13 f2 d1 96 6f cd d9 32 6e 22 37 ce 41 f9 |o.....o..2n"7.A.|
+000000c0 ca 5d 29 ac e1 27 da 61 a2 ee 81 cb 10 c7 df 34 |.])..'.a.......4|
+000000d0 58 95 86 e9 3d 19 e6 5c 27 73 60 c8 8d 78 02 f4 |X...=..\'s`..x..|
+000000e0 1d a4 98 09 a3 19 70 69 3c 25 62 66 2a ab 22 23 |......pi<%bf*."#|
+000000f0 c5 7b 85 38 4f 2e 09 73 32 a7 bd 3e 9b ad ca 84 |.{.8O..s2..>....|
+00000100 07 e6 0f 3a ff 77 c5 9d 41 85 00 8a b6 9b ee b0 |...:.w..A.......|
+00000110 a4 3f 2d 4c 4c e6 42 3e bb 51 c8 dd 48 54 f4 0c |.?-LL.B>.Q..HT..|
+00000120 8e 47 02 03 01 00 01 a3 46 30 44 30 0e 06 03 55 |.G......F0D0...U|
+00000130 1d 0f 01 01 ff 04 04 03 02 05 a0 30 13 06 03 55 |...........0...U|
+00000140 1d 25 04 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+00000150 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 0f |0...U.......0.0.|
+00000160 06 03 55 1d 11 04 08 30 06 87 04 7f 00 00 01 30 |..U....0.......0|
+00000170 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 03 81 |...*.H..........|
+00000180 81 00 46 ab 44 a2 fb 28 54 f8 5a 67 f8 62 94 f1 |..F.D..(T.Zg.b..|
+00000190 9a b2 18 9e f2 b1 de 1d 7e 6f 76 95 a9 ba e7 5d |........~ov....]|
+000001a0 a8 16 6c 9c f7 09 d3 37 e4 4b 2b 36 7c 01 ad 41 |..l....7.K+6|..A|
+000001b0 d2 32 d8 c3 d2 93 f9 10 6b 8e 95 b9 2c 17 8a a3 |.2......k...,...|
+000001c0 44 48 bc 59 13 83 16 04 88 a4 81 5c 25 0d 98 0c |DH.Y.......\%...|
+000001d0 ac 11 b1 28 56 be 1d cd 61 62 84 09 bf d6 80 c6 |...(V...ab......|
+000001e0 45 8d 82 2c b4 d8 83 9b db c9 22 b7 2a 12 11 7b |E..,......".*..{|
+000001f0 fa 02 3b c1 c9 ff ea c9 9d a8 49 d3 95 d7 d5 0e |..;.......I.....|
+00000200 e5 35 16 03 03 00 86 10 00 00 82 00 80 41 62 b4 |.5...........Ab.|
+00000210 fb 81 80 58 e3 0d c7 b2 c0 55 ee 5b 1a ba 2d 8f |...X.....U.[..-.|
+00000220 9f 79 24 0a d5 be c7 2b 55 ec 51 6d b9 78 63 85 |.y$....+U.Qm.xc.|
+00000230 82 d2 ea 02 0c 06 fe 05 fd ed 08 be 71 99 5f 53 |............q._S|
+00000240 94 85 01 ff ba 2a ee 14 cb 99 0a df 1e 67 0d 95 |.....*.......g..|
+00000250 63 8d 1f 96 41 75 f9 5d 1a 21 03 6c e3 eb 4f 5e |c...Au.].!.l..O^|
+00000260 28 c3 4d bb 6d 29 33 bc 24 75 8c 3b f2 c4 6b f5 |(.M.m)3.$u.;..k.|
+00000270 86 db 40 59 34 43 fb a9 1e ea 6f 3f 0e b4 35 39 |..@Y4C....o?..59|
+00000280 52 d8 0f 85 ed 3b 52 b6 5b 7f b0 bf c3 16 03 03 |R....;R.[.......|
+00000290 00 88 0f 00 00 84 04 01 00 80 52 85 ca 08 7d 07 |..........R...}.|
+000002a0 bc d8 0c a4 b8 36 01 c0 b8 8a 18 ba d8 d4 a3 fa |.....6..........|
+000002b0 fd 32 e2 00 72 e5 d2 c8 5a 59 6b 5e 6e df 35 da |.2..r...ZYk^n.5.|
+000002c0 c7 1e ee af 87 4b d6 30 7e 27 1c 76 70 28 79 ac |.....K.0~'.vp(y.|
+000002d0 7f 31 bc 44 55 3c 15 61 d2 0d 24 9c 48 43 9f 12 |.1.DU<.a..$.HC..|
+000002e0 a6 74 5c 2f 5b 4e 96 4a 47 b4 6b 7c fa da 37 96 |.t\/[N.JG.k|..7.|
+000002f0 ec 46 7d 05 be 24 8f cf 11 31 ab 4c 5b c7 3e 94 |.F}..$...1.L[.>.|
+00000300 9a 2a 39 e8 fe aa aa ee e3 00 a3 a8 1e 75 4a 21 |.*9..........uJ!|
+00000310 b4 ad 24 8f ee e8 30 85 b1 28 14 03 03 00 01 01 |..$...0..(......|
+00000320 16 03 03 00 40 71 47 13 68 49 74 9c 2a 81 35 94 |....@qG.hIt.*.5.|
+00000330 52 f6 44 44 67 3b 62 e1 ef 34 18 e7 8a 56 71 88 |R.DDg;b..4...Vq.|
+00000340 83 7e 67 28 20 18 b1 c5 8a c8 8b 6a fe ee bf da |.~g( ......j....|
+00000350 5f 6e cd fa a8 5c af 5c 3c 83 80 78 f3 fe 1b dc |_n...\.\<..x....|
+00000360 95 fe 22 16 82 |.."..|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 20 f7 51 8f 23 |........... .Q.#|
+00000020 08 8d 67 5d 12 06 b0 48 81 2d 0c ba 88 03 88 31 |..g]...H.-.....1|
+00000030 d0 ab 63 0d 9f 28 60 21 0a a3 58 47 c2 04 cc f1 |..c..(`!..XG....|
+00000040 50 0d 88 b2 e5 54 50 26 e6 6e ed 17 03 03 00 40 |P....TP&.n.....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 fa 4d e5 00 14 2c 65 82 5d 1b bf 99 6a 54 16 98 |.M...,e.]...jT..|
+00000070 ef 55 15 00 f9 c4 3e 61 88 83 63 fd 60 66 f1 87 |.U....>a..c.`f..|
+00000080 fa c4 45 ae de b8 0a 36 75 f5 b2 b6 f5 d8 9b df |..E....6u.......|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 54 cc c0 15 e5 6d 62 4d 13 54 e8 |.....T....mbM.T.|
+000000b0 fa cf 76 a6 de d6 48 f8 0d ef 30 b7 12 05 cf 75 |..v...H...0....u|
+000000c0 8b 00 9e d5 63 |....c|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
new file mode 100644
index 0000000..a81c173
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-ClientAuthRequestedNotGiven
@@ -0,0 +1,85 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 6d 01 00 00 69 03 03 be a7 a4 6c f7 |....m...i.....l.|
+00000010 f6 b4 f2 64 5d 0e 36 b6 05 f5 f1 c9 fe 3c c2 8e |...d].6......<..|
+00000020 c4 b7 18 68 b9 0c 1d 51 50 2f 1e 00 00 04 00 2f |...h...QP/...../|
+00000030 00 ff 01 00 00 3c 00 16 00 00 00 17 00 00 00 0d |.....<..........|
+00000040 00 30 00 2e 04 03 05 03 06 03 08 07 08 08 08 09 |.0..............|
+00000050 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 06 01 |................|
+00000060 03 03 02 03 03 01 02 01 03 02 02 02 04 02 05 02 |................|
+00000070 06 02 |..|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 00 2f 00 00 |...DOWNGRD.../..|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 23 0d 00 00 1f 02 01 40 |;.......#......@|
+000002a0 00 18 08 04 04 03 08 07 08 05 08 06 04 01 05 01 |................|
+000002b0 06 01 05 03 06 03 02 01 02 03 00 00 16 03 03 00 |................|
+000002c0 04 0e 00 00 00 |.....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 07 0b 00 00 03 00 00 00 16 03 03 00 |................|
+00000010 86 10 00 00 82 00 80 a9 b6 12 e2 84 71 62 7a 20 |............qbz |
+00000020 63 80 99 c6 ee f7 61 f9 74 d6 0b ab 31 74 69 ca |c.....a.t...1ti.|
+00000030 94 20 9e 1b 0e 52 45 c4 f4 b3 cb fb a4 07 61 6f |. ...RE.......ao|
+00000040 a1 5a 84 4c 4f f6 4a e4 bc c5 c2 b0 ee 8a 30 5b |.Z.LO.J.......0[|
+00000050 10 e0 ed d3 4c b7 32 8c ed 3f 89 a7 a7 95 60 86 |....L.2..?....`.|
+00000060 97 1a ae ab 2f 5c e6 6d 1b c3 35 bd f5 c1 f0 1a |..../\.m..5.....|
+00000070 d4 70 e5 00 f2 d4 d1 20 6a 82 db e7 52 ca 88 e5 |.p..... j...R...|
+00000080 2d cc 79 0c f6 09 84 65 f0 30 41 67 10 0a 48 d1 |-.y....e.0Ag..H.|
+00000090 09 3e 56 7a aa 57 bc 14 03 03 00 01 01 16 03 03 |.>Vz.W..........|
+000000a0 00 40 e6 0a 91 5f 30 f8 52 75 94 8e ab 82 ec 1d |.@..._0.Ru......|
+000000b0 b7 a1 1c 18 1a aa 1c f8 73 93 0e 20 ad 68 a7 65 |........s.. .h.e|
+000000c0 86 c9 f5 90 f9 b2 fd d1 32 94 52 6e 82 9b b9 45 |........2.Rn...E|
+000000d0 97 52 4b 1e c2 31 a6 2e c8 b3 1a 62 22 83 8f df |.RK..1.....b"...|
+000000e0 d7 06 |..|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 b0 2c 61 79 87 |............,ay.|
+00000020 59 d4 9e 4d e7 56 4a 34 ba 78 d5 06 98 a2 92 35 |Y..M.VJ4.x.....5|
+00000030 a1 fc 57 5a 6e d3 0f 44 08 1c a1 7b 3c d3 f1 86 |..WZn..D...{<...|
+00000040 a2 04 04 5e 1b 7c 00 4f 51 71 73 17 03 03 00 40 |...^.|.OQqs....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 aa 5c 1a 9a 70 bc b3 fb 70 07 0b 24 cb 95 84 61 |.\..p...p..$...a|
+00000070 96 ed d8 97 2f d6 79 51 ed cd 67 44 e5 d4 a3 57 |..../.yQ..gD...W|
+00000080 95 f6 c8 31 a8 95 c2 07 a4 ce 1c fc 4a dc 93 d9 |...1........J...|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 ae dd c4 f4 04 d3 b1 1a 8a 56 f7 |..............V.|
+000000b0 73 c9 d5 aa 6c 59 d7 66 77 34 64 2d 19 79 13 80 |s...lY.fw4d-.y..|
+000000c0 98 60 6d f4 d9 |.`m..|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
new file mode 100644
index 0000000..62f4311
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-ECDHE-ECDSA-AES
@@ -0,0 +1,84 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 85 01 00 00 81 03 03 20 34 f0 4b 7a |........... 4.Kz|
+00000010 4f ed 31 de 38 ef 33 2e 69 7d 74 35 e5 02 b9 bb |O.1.8.3.i}t5....|
+00000020 bd 1a 5c 3a f2 57 f1 23 62 66 52 00 00 04 c0 0a |..\:.W.#bfR.....|
+00000030 00 ff 01 00 00 54 00 0b 00 04 03 00 01 02 00 0a |.....T..........|
+00000040 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 16 |................|
+00000050 00 00 00 17 00 00 00 0d 00 30 00 2e 04 03 05 03 |.........0......|
+00000060 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 |................|
+00000070 08 06 04 01 05 01 06 01 03 03 02 03 03 01 02 01 |................|
+00000080 03 02 02 02 04 02 05 02 06 02 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 37 02 00 00 33 03 03 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 c0 0a 00 00 |...DOWNGRD......|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 03 02 |................|
+00000040 0e 0b 00 02 0a 00 02 07 00 02 04 30 82 02 00 30 |...........0...0|
+00000050 82 01 62 02 09 00 b8 bf 2d 47 a0 d2 eb f4 30 09 |..b.....-G....0.|
+00000060 06 07 2a 86 48 ce 3d 04 01 30 45 31 0b 30 09 06 |..*.H.=..0E1.0..|
+00000070 03 55 04 06 13 02 41 55 31 13 30 11 06 03 55 04 |.U....AU1.0...U.|
+00000080 08 13 0a 53 6f 6d 65 2d 53 74 61 74 65 31 21 30 |...Some-State1!0|
+00000090 1f 06 03 55 04 0a 13 18 49 6e 74 65 72 6e 65 74 |...U....Internet|
+000000a0 20 57 69 64 67 69 74 73 20 50 74 79 20 4c 74 64 | Widgits Pty Ltd|
+000000b0 30 1e 17 0d 31 32 31 31 32 32 31 35 30 36 33 32 |0...121122150632|
+000000c0 5a 17 0d 32 32 31 31 32 30 31 35 30 36 33 32 5a |Z..221120150632Z|
+000000d0 30 45 31 0b 30 09 06 03 55 04 06 13 02 41 55 31 |0E1.0...U....AU1|
+000000e0 13 30 11 06 03 55 04 08 13 0a 53 6f 6d 65 2d 53 |.0...U....Some-S|
+000000f0 74 61 74 65 31 21 30 1f 06 03 55 04 0a 13 18 49 |tate1!0...U....I|
+00000100 6e 74 65 72 6e 65 74 20 57 69 64 67 69 74 73 20 |nternet Widgits |
+00000110 50 74 79 20 4c 74 64 30 81 9b 30 10 06 07 2a 86 |Pty Ltd0..0...*.|
+00000120 48 ce 3d 02 01 06 05 2b 81 04 00 23 03 81 86 00 |H.=....+...#....|
+00000130 04 00 c4 a1 ed be 98 f9 0b 48 73 36 7e c3 16 56 |.........Hs6~..V|
+00000140 11 22 f2 3d 53 c3 3b 4d 21 3d cd 6b 75 e6 f6 b0 |.".=S.;M!=.ku...|
+00000150 dc 9a df 26 c1 bc b2 87 f0 72 32 7c b3 64 2f 1c |...&.....r2|.d/.|
+00000160 90 bc ea 68 23 10 7e fe e3 25 c0 48 3a 69 e0 28 |...h#.~..%.H:i.(|
+00000170 6d d3 37 00 ef 04 62 dd 0d a0 9c 70 62 83 d8 81 |m.7...b....pb...|
+00000180 d3 64 31 aa 9e 97 31 bd 96 b0 68 c0 9b 23 de 76 |.d1...1...h..#.v|
+00000190 64 3f 1a 5c 7f e9 12 0e 58 58 b6 5f 70 dd 9b d8 |d?.\....XX._p...|
+000001a0 ea d5 d7 f5 d5 cc b9 b6 9f 30 66 5b 66 9a 20 e2 |.........0f[f. .|
+000001b0 27 e5 bf fe 3b 30 09 06 07 2a 86 48 ce 3d 04 01 |'...;0...*.H.=..|
+000001c0 03 81 8c 00 30 81 88 02 42 01 88 a2 4f eb e2 45 |....0...B...O..E|
+000001d0 c5 48 7d 1b ac f5 ed 98 9d ae 47 70 c0 5e 1b b6 |.H}.......Gp.^..|
+000001e0 2f bd f1 b6 4d b7 61 40 d3 11 a2 ce ee 0b 7e 92 |/...M.a@......~.|
+000001f0 7e ff 76 9d c3 3b 7e a5 3f ce fa 10 e2 59 ec 47 |~.v..;~.?....Y.G|
+00000200 2d 7c ac da 4e 97 0e 15 a0 6f d0 02 42 01 4d fc |-|..N....o..B.M.|
+00000210 be 67 13 9c 2d 05 0e bd 3f a3 8c 25 c1 33 13 83 |.g..-...?..%.3..|
+00000220 0d 94 06 bb d4 37 7a f6 ec 7a c9 86 2e dd d7 11 |.....7z..z......|
+00000230 69 7f 85 7c 56 de fb 31 78 2b e4 c7 78 0d ae cb |i..|V..1x+..x...|
+00000240 be 9e 4e 36 24 31 7b 6a 0f 39 95 12 07 8f 2a 16 |..N6$1{j.9....*.|
+00000250 03 03 00 b6 0c 00 00 b2 03 00 1d 20 2f e5 7d a3 |........... /.}.|
+00000260 47 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 |G.bC.(.._.).0...|
+00000270 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 04 03 00 8a |......._X.;t....|
+00000280 30 81 87 02 41 21 2b cf 6b fc 8a 13 b6 21 8a 46 |0...A!+.k....!.F|
+00000290 fc 7c 56 7e 28 22 4d b2 c2 c8 45 92 cc 99 6a 3c |.|V~("M...E...j<|
+000002a0 48 0f 16 95 6c 43 3d ea bd ac 25 88 a3 35 0c 14 |H...lC=...%..5..|
+000002b0 c6 43 46 16 ec b5 57 76 86 1c 5a d1 52 44 3b 8c |.CF...Wv..Z.RD;.|
+000002c0 e5 b3 46 3b 47 d8 02 42 01 ad a2 c3 4c 69 35 13 |..F;G..B....Li5.|
+000002d0 d7 66 37 63 c9 43 50 68 f6 ff 7f 7d be 7e 8d 89 |.f7c.CPh...}.~..|
+000002e0 db 57 3e 0f 51 c8 49 9b 3a e2 87 65 dd 28 21 9a |.W>.Q.I.:..e.(!.|
+000002f0 c3 36 28 a4 e8 25 7b ae 8e 45 35 22 8f 2d 97 27 |.6(..%{..E5".-.'|
+00000300 fe b8 99 a9 c1 5f d8 8b 70 d3 16 03 03 00 04 0e |....._..p.......|
+00000310 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 c4 25 45 6f 39 18 |....%...! .%Eo9.|
+00000010 b1 f6 0a b3 f7 3e 98 ed 63 ae bd 74 12 91 0d 81 |.....>..c..t....|
+00000020 84 71 13 3c a7 cf a5 d2 24 5f 14 03 03 00 01 01 |.q.<....$_......|
+00000030 16 03 03 00 40 27 8d 44 74 7a ae 8a 4e 1c f9 1b |....@'.Dtz..N...|
+00000040 05 23 c4 89 57 27 4c dc db 4a ae aa 08 74 00 55 |.#..W'L..J...t.U|
+00000050 f9 4e 63 02 75 24 ca fb 30 78 cc 82 8a 69 be ab |.Nc.u$..0x...i..|
+00000060 10 9d 25 2d a8 b6 bb 64 6e 32 68 4b 0a 32 06 74 |..%-...dn2hK.2.t|
+00000070 26 5e bc 68 25 |&^.h%|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 b0 cf 70 b3 00 |.............p..|
+00000020 89 e2 77 af 87 08 f5 2f 2c c8 75 ce 8a ed 30 d8 |..w..../,.u...0.|
+00000030 f7 44 f3 9d 8b 4c 42 7a 52 d0 c8 37 9b 45 46 1c |.D...LBzR..7.EF.|
+00000040 56 3b ee 52 5d c4 72 04 13 49 aa 17 03 03 00 40 |V;.R].r..I.....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 ce c4 34 c2 d8 4e f5 db d1 ff 6d 64 ae 39 6d 78 |..4..N....md.9mx|
+00000070 3c c4 57 32 d1 af 35 d3 b4 79 3c b4 bd a1 21 7b |<.W2..5..y<...!{|
+00000080 1f ef b8 3c 97 37 18 e5 10 62 e8 3d 7d 12 f5 db |...<.7...b.=}...|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 81 75 ae 71 18 61 61 ae 35 ce c8 |......u.q.aa.5..|
+000000b0 43 57 52 c9 68 5e 0d 63 c4 0e 7d 36 90 b2 f6 f6 |CWR.h^.c..}6....|
+000000c0 ea 72 3c d9 41 |.r<.A|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-Ed25519 b/src/crypto/tls/testdata/Server-TLSv12-Ed25519
new file mode 100644
index 0000000..dd34592
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-Ed25519
@@ -0,0 +1,58 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 85 01 00 00 81 03 03 f0 8d 1b 90 67 |...............g|
+00000010 3b 23 46 ac f7 79 f2 f9 e8 90 98 b3 52 b2 55 2a |;#F..y......R.U*|
+00000020 fb 0f 1e dd 4f b3 75 4b 9b 88 0e 00 00 04 cc a9 |....O.uK........|
+00000030 00 ff 01 00 00 54 00 0b 00 04 03 00 01 02 00 0a |.....T..........|
+00000040 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 16 |................|
+00000050 00 00 00 17 00 00 00 0d 00 30 00 2e 04 03 05 03 |.........0......|
+00000060 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 |................|
+00000070 08 06 04 01 05 01 06 01 03 03 02 03 03 01 02 01 |................|
+00000080 03 02 02 02 04 02 05 02 06 02 |..........|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 37 02 00 00 33 03 03 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 cc a9 00 00 |...DOWNGRD......|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 03 01 |................|
+00000040 3c 0b 00 01 38 00 01 35 00 01 32 30 82 01 2e 30 |<...8..5..20...0|
+00000050 81 e1 a0 03 02 01 02 02 10 0f 43 1c 42 57 93 94 |..........C.BW..|
+00000060 1d e9 87 e4 f1 ad 15 00 5d 30 05 06 03 2b 65 70 |........]0...+ep|
+00000070 30 12 31 10 30 0e 06 03 55 04 0a 13 07 41 63 6d |0.1.0...U....Acm|
+00000080 65 20 43 6f 30 1e 17 0d 31 39 30 35 31 36 32 31 |e Co0...19051621|
+00000090 33 38 30 31 5a 17 0d 32 30 30 35 31 35 32 31 33 |3801Z..200515213|
+000000a0 38 30 31 5a 30 12 31 10 30 0e 06 03 55 04 0a 13 |801Z0.1.0...U...|
+000000b0 07 41 63 6d 65 20 43 6f 30 2a 30 05 06 03 2b 65 |.Acme Co0*0...+e|
+000000c0 70 03 21 00 3f e2 15 2e e6 e3 ef 3f 4e 85 4a 75 |p.!.?......?N.Ju|
+000000d0 77 a3 64 9e ed e0 bf 84 2c cc 92 26 8f fa 6f 34 |w.d.....,..&..o4|
+000000e0 83 aa ec 8f a3 4d 30 4b 30 0e 06 03 55 1d 0f 01 |.....M0K0...U...|
+000000f0 01 ff 04 04 03 02 05 a0 30 13 06 03 55 1d 25 04 |........0...U.%.|
+00000100 0c 30 0a 06 08 2b 06 01 05 05 07 03 01 30 0c 06 |.0...+.......0..|
+00000110 03 55 1d 13 01 01 ff 04 02 30 00 30 16 06 03 55 |.U.......0.0...U|
+00000120 1d 11 04 0f 30 0d 82 0b 65 78 61 6d 70 6c 65 2e |....0...example.|
+00000130 63 6f 6d 30 05 06 03 2b 65 70 03 41 00 63 44 ed |com0...+ep.A.cD.|
+00000140 9c c4 be 53 24 53 9f d2 10 8d 9f e8 21 08 90 95 |...S$S......!...|
+00000150 39 e5 0d c1 55 ff 2c 16 b7 1d fc ab 7d 4d d4 e0 |9...U.,.....}M..|
+00000160 93 13 d0 a9 42 e0 b6 6b fe 5d 67 48 d7 9f 50 bc |....B..k.]gH..P.|
+00000170 6c cd 4b 03 83 7c f2 08 58 cd ac cf 0c 16 03 03 |l.K..|..X.......|
+00000180 00 6c 0c 00 00 68 03 00 1d 20 2f e5 7d a3 47 cd |.l...h... /.}.G.|
+00000190 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af c4 |bC.(.._.).0.....|
+000001a0 cf c2 ed 90 99 5f 58 cb 3b 74 08 07 00 40 1f 56 |....._X.;t...@.V|
+000001b0 21 8a 44 04 69 65 ee f8 93 52 4c f0 49 42 57 4c |!.D.ie...RL.IBWL|
+000001c0 5b f5 1a ef 43 ad 39 93 03 a3 64 84 da e5 82 32 |[...C.9...d....2|
+000001d0 fc 77 12 61 f3 f4 2c d8 61 9e 86 01 1f c0 a0 98 |.w.a..,.a.......|
+000001e0 94 a3 7f 15 75 c8 e6 2f 20 bd af 7c be 0e 16 03 |....u../ ..|....|
+000001f0 03 00 04 0e 00 00 00 |.......|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 26 b0 6c 90 e7 71 |....%...! &.l..q|
+00000010 23 78 4b a1 a1 32 7c 28 e9 df 7e 98 e9 78 be 8d |#xK..2|(..~..x..|
+00000020 0d ec fc 30 82 99 16 f0 9f 20 14 03 03 00 01 01 |...0..... ......|
+00000030 16 03 03 00 20 e9 81 b0 ea b3 f3 21 40 9a 3b 3e |.... ......!@.;>|
+00000040 71 a7 13 f5 3a 8a cd 86 34 8b 7e 41 b5 2a 1b 03 |q...:...4.~A.*..|
+00000050 29 77 b3 b2 da |)w...|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 54 5a ff 09 7d |.......... TZ..}|
+00000010 46 04 40 62 c5 63 71 85 c7 b4 6c 09 ee 15 71 6b |F.@b.cq...l...qk|
+00000020 60 3b 00 3d 46 47 13 a5 f7 15 16 17 03 03 00 1d |`;.=FG..........|
+00000030 13 8d 00 50 58 d0 2a 47 a8 d8 de 87 d4 3e ff ee |...PX.*G.....>..|
+00000040 f1 4d 6b 25 94 6f 01 7b 70 ee 53 d9 be 15 03 03 |.Mk%.o.{p.S.....|
+00000050 00 12 13 ea 17 69 00 0e 2b ae 21 a9 5e 0a 41 2d |.....i..+.!.^.A-|
+00000060 1b 73 f0 2d |.s.-|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ExportKeyingMaterial b/src/crypto/tls/testdata/Server-TLSv12-ExportKeyingMaterial
new file mode 100644
index 0000000..e01c32c
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-ExportKeyingMaterial
@@ -0,0 +1,89 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 89 01 00 00 85 03 03 9a d9 fe da 40 |...............@|
+00000010 cf 8b ed 11 09 8e 3f 29 4b 0d 46 ff fc f6 56 2c |......?)K.F...V,|
+00000020 a8 e7 16 84 8a a4 e9 44 89 97 0b 00 00 04 cc a8 |.......D........|
+00000030 00 ff 01 00 00 58 00 0b 00 04 03 00 01 02 00 0a |.....X..........|
+00000040 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#|
+00000050 00 00 00 16 00 00 00 17 00 00 00 0d 00 30 00 2e |.............0..|
+00000060 04 03 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b |................|
+00000070 08 04 08 05 08 06 04 01 05 01 06 01 03 03 02 03 |................|
+00000080 03 01 02 01 03 02 02 02 04 02 05 02 06 02 |..............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 3b 02 00 00 37 03 03 00 00 00 00 00 |....;...7.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 cc a8 00 00 |...DOWNGRD......|
+00000030 0f 00 23 00 00 ff 01 00 01 00 00 0b 00 02 01 00 |..#.............|
+00000040 16 03 03 02 59 0b 00 02 55 00 02 52 00 02 4f 30 |....Y...U..R..O0|
+00000050 82 02 4b 30 82 01 b4 a0 03 02 01 02 02 09 00 e8 |..K0............|
+00000060 f0 9d 3f e2 5b ea a6 30 0d 06 09 2a 86 48 86 f7 |..?.[..0...*.H..|
+00000070 0d 01 01 0b 05 00 30 1f 31 0b 30 09 06 03 55 04 |......0.1.0...U.|
+00000080 0a 13 02 47 6f 31 10 30 0e 06 03 55 04 03 13 07 |...Go1.0...U....|
+00000090 47 6f 20 52 6f 6f 74 30 1e 17 0d 31 36 30 31 30 |Go Root0...16010|
+000000a0 31 30 30 30 30 30 30 5a 17 0d 32 35 30 31 30 31 |1000000Z..250101|
+000000b0 30 30 30 30 30 30 5a 30 1a 31 0b 30 09 06 03 55 |000000Z0.1.0...U|
+000000c0 04 0a 13 02 47 6f 31 0b 30 09 06 03 55 04 03 13 |....Go1.0...U...|
+000000d0 02 47 6f 30 81 9f 30 0d 06 09 2a 86 48 86 f7 0d |.Go0..0...*.H...|
+000000e0 01 01 01 05 00 03 81 8d 00 30 81 89 02 81 81 00 |.........0......|
+000000f0 db 46 7d 93 2e 12 27 06 48 bc 06 28 21 ab 7e c4 |.F}...'.H..(!.~.|
+00000100 b6 a2 5d fe 1e 52 45 88 7a 36 47 a5 08 0d 92 42 |..]..RE.z6G....B|
+00000110 5b c2 81 c0 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 |[.....y.@.Om..+.|
+00000120 8b c2 a5 2e 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 |....g....."8.J.t|
+00000130 73 2b c2 34 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c |s+.4......t{.X.l|
+00000140 61 3c c0 b0 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd |a<..A..++$#w[.;.|
+00000150 75 5d ce 20 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a |u]. T..c...$....|
+00000160 50 8b aa b6 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 |P....C...ub...R.|
+00000170 02 03 01 00 01 a3 81 93 30 81 90 30 0e 06 03 55 |........0..0...U|
+00000180 1d 0f 01 01 ff 04 04 03 02 05 a0 30 1d 06 03 55 |...........0...U|
+00000190 1d 25 04 16 30 14 06 08 2b 06 01 05 05 07 03 01 |.%..0...+.......|
+000001a0 06 08 2b 06 01 05 05 07 03 02 30 0c 06 03 55 1d |..+.......0...U.|
+000001b0 13 01 01 ff 04 02 30 00 30 19 06 03 55 1d 0e 04 |......0.0...U...|
+000001c0 12 04 10 9f 91 16 1f 43 43 3e 49 a6 de 6d b6 80 |.......CC>I..m..|
+000001d0 d7 9f 60 30 1b 06 03 55 1d 23 04 14 30 12 80 10 |..`0...U.#..0...|
+000001e0 48 13 49 4d 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b |H.IM.~.1......n{|
+000001f0 30 19 06 03 55 1d 11 04 12 30 10 82 0e 65 78 61 |0...U....0...exa|
+00000200 6d 70 6c 65 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a |mple.golang0...*|
+00000210 86 48 86 f7 0d 01 01 0b 05 00 03 81 81 00 9d 30 |.H.............0|
+00000220 cc 40 2b 5b 50 a0 61 cb ba e5 53 58 e1 ed 83 28 |.@+[P.a...SX...(|
+00000230 a9 58 1a a9 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 |.X..8....1Z..f=C|
+00000240 d3 2d d9 0b f2 97 df d3 20 64 38 92 24 3a 00 bc |.-...... d8.$:..|
+00000250 cf 9c 7d b7 40 20 01 5f aa d3 16 61 09 a2 76 fd |..}.@ ._...a..v.|
+00000260 13 c3 cc e1 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb |.....\.....l..s.|
+00000270 b3 43 77 8d 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 |.Cw.......@.a.Lr|
+00000280 2b 9d ae db 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 |+...F..M...>...B|
+00000290 d4 db fe 3d 13 60 84 5c 21 d3 3b e9 fa e7 16 03 |...=.`.\!.;.....|
+000002a0 03 00 ac 0c 00 00 a8 03 00 1d 20 2f e5 7d a3 47 |.......... /.}.G|
+000002b0 cd 62 43 15 28 da ac 5f bb 29 07 30 ff f6 84 af |.bC.(.._.).0....|
+000002c0 c4 cf c2 ed 90 99 5f 58 cb 3b 74 08 04 00 80 89 |......_X.;t.....|
+000002d0 f8 62 c5 1a ba 78 74 da 6f 96 76 00 0f 6b a9 fb |.b...xt.o.v..k..|
+000002e0 83 d4 52 c0 80 0b 81 02 e3 b0 07 c2 9d ff b4 cc |..R.............|
+000002f0 ea 2e c7 82 91 35 74 ef 1e 9a ba 78 3e 60 6c 86 |.....5t....x>`l.|
+00000300 1d b0 14 52 84 84 70 ce 66 22 31 66 e2 53 04 bd |...R..p.f"1f.S..|
+00000310 4d 2b 5e 86 8b 79 dc 17 7a 4f bc 62 5a 21 a1 f6 |M+^..y..zO.bZ!..|
+00000320 46 1a 12 aa 7a 98 25 02 97 a8 9c 71 a4 4a 5b 28 |F...z.%....q.J[(|
+00000330 c8 11 6a 5f f1 b3 13 a7 f2 26 12 59 02 fa 28 e2 |..j_.....&.Y..(.|
+00000340 ba 8c c0 cd 50 c6 60 db 69 9a a1 92 12 26 23 16 |....P.`.i....&#.|
+00000350 03 03 00 04 0e 00 00 00 |........|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 ba 1b c8 ae 22 78 |....%...! ...."x|
+00000010 84 ba d8 1c b3 87 52 f0 bf 13 76 2b a5 47 37 13 |......R...v+.G7.|
+00000020 30 89 01 13 1a cb 63 ea b3 37 14 03 03 00 01 01 |0.....c..7......|
+00000030 16 03 03 00 20 ac d7 79 45 e6 65 1d 20 1a 95 5e |.... ..yE.e. ..^|
+00000040 68 f7 0f ee 8c 3f 3d 0b bc 58 31 aa 46 d7 e3 00 |h....?=..X1.F...|
+00000050 7b 10 8c 01 5d |{...]|
+>>> Flow 4 (server to client)
+00000000 16 03 03 00 8b 04 00 00 87 00 00 00 00 00 81 50 |...............P|
+00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
+00000030 6f e0 18 83 51 ed 14 ef 68 ca 42 c5 4c f8 79 c6 |o...Q...h.B.L.y.|
+00000040 80 85 74 9c 35 6f 4e 9d 60 0b a2 28 b0 45 b6 f6 |..t.5oN.`..(.E..|
+00000050 71 a3 f6 a6 95 71 cd 1e 53 e9 58 9f 94 18 ac d6 |q....q..S.X.....|
+00000060 6b 03 ba ac b4 4f c2 02 cc 1c 5b 88 84 49 38 16 |k....O....[..I8.|
+00000070 d9 5e b8 11 ab c6 f8 a7 9d 5d 58 99 b1 b6 8a be |.^.......]X.....|
+00000080 4e 9e 40 3d 00 22 11 25 c7 51 8e cb d2 10 d4 7d |N.@=.".%.Q.....}|
+00000090 14 03 03 00 01 01 16 03 03 00 20 ff 4b 1e 87 3e |.......... .K..>|
+000000a0 05 5c b4 3e e4 b9 5c 47 f0 a2 0b 67 47 89 c6 48 |.\.>..\G...gG..H|
+000000b0 d5 e3 73 d2 00 44 56 e4 8d b6 fb 17 03 03 00 1d |..s..DV.........|
+000000c0 58 28 94 02 c2 a9 99 3d b6 0b de 9c fd 52 61 bf |X(.....=.....Ra.|
+000000d0 55 c0 12 7f be a8 52 98 d7 99 a5 d0 60 15 03 03 |U.....R.....`...|
+000000e0 00 12 26 44 ad f0 a7 56 e5 23 6f 1b 7a 7e f8 e4 |..&D...V.#o.z~..|
+000000f0 42 49 5d 1d |BI].|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-IssueTicket b/src/crypto/tls/testdata/Server-TLSv12-IssueTicket
new file mode 100644
index 0000000..f70c759
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-IssueTicket
@@ -0,0 +1,91 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 71 01 00 00 6d 03 03 3d 21 91 3a 4e |....q...m..=!.:N|
+00000010 8e cd 65 eb 0f 1c ae 2a 58 40 4c 38 22 c9 46 2c |..e....*X@L8".F,|
+00000020 b8 cd dd 38 ad c6 4b a7 60 a9 56 00 00 04 00 2f |...8..K.`.V..../|
+00000030 00 ff 01 00 00 40 00 23 00 00 00 16 00 00 00 17 |.....@.#........|
+00000040 00 00 00 0d 00 30 00 2e 04 03 05 03 06 03 08 07 |.....0..........|
+00000050 08 08 08 09 08 0a 08 0b 08 04 08 05 08 06 04 01 |................|
+00000060 05 01 06 01 03 03 02 03 03 01 02 01 03 02 02 02 |................|
+00000070 04 02 05 02 06 02 |......|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 00 2f 00 00 |...DOWNGRD.../..|
+00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 59 0b |..#...........Y.|
+00000040 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 01 |..U..R..O0..K0..|
+00000050 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b ea |............?.[.|
+00000060 a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
+00000070 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 |0.1.0...U....Go1|
+00000080 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
+00000090 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 30 |t0...16010100000|
+000000a0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
+000000b0 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |Z0.1.0...U....Go|
+000000c0 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 9f |1.0...U....Go0..|
+000000d0 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 |0...*.H.........|
+000000e0 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e 12 |...0.......F}...|
+000000f0 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 |'.H..(!.~...]..R|
+00000100 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 |E.z6G....B[.....|
+00000110 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 |y.@.Om..+.....g.|
+00000120 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 |...."8.J.ts+.4..|
+00000130 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 |....t{.X.la<..A.|
+00000140 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf |.++$#w[.;.u]. T.|
+00000150 a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 |.c...$....P....C|
+00000160 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 |...ub...R.......|
+00000170 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff 04 |..0..0...U......|
+00000180 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 |.....0...U.%..0.|
+00000190 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 05 |..+.........+...|
+000001a0 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 |....0...U.......|
+000001b0 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 16 |0.0...U.........|
+000001c0 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 |.CC>I..m....`0..|
+000001d0 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 7e |.U.#..0...H.IM.~|
+000001e0 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 1d |.1......n{0...U.|
+000001f0 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e 67 |...0...example.g|
+00000200 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d 01 |olang0...*.H....|
+00000210 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 |.........0.@+[P.|
+00000220 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 |a...SX...(.X..8.|
+00000230 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 |...1Z..f=C.-....|
+00000240 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 20 |.. d8.$:....}.@ |
+00000250 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c |._...a..v......\|
+00000260 ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c |.....l..s..Cw...|
+00000270 f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 06 |....@.a.Lr+...F.|
+00000280 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 |.M...>...B...=.`|
+00000290 84 5c 21 d3 3b e9 fa e7 16 03 03 00 04 0e 00 00 |.\!.;...........|
+000002a0 00 |.|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 1d 1a 1a b8 f4 |................|
+00000010 05 77 7a 96 2b 5f 50 7f 1e 69 14 be 40 ad 0c c9 |.wz.+_P..i..@...|
+00000020 7e df 2f 1d aa 74 ee b4 a5 05 fa 05 e1 85 a4 87 |~./..t..........|
+00000030 59 6a d1 e4 98 ce df e3 a5 82 98 77 c2 c4 fc 2f |Yj.........w.../|
+00000040 ec 1d 2e 96 0c 27 12 0d 64 ba 58 90 ff 7d d1 27 |.....'..d.X..}.'|
+00000050 9a b9 b5 fb 1d 76 6f 3e af f8 70 a3 cc 53 95 98 |.....vo>..p..S..|
+00000060 2c 7e a9 42 25 e5 3a e2 55 3f 19 57 6b 83 43 6a |,~.B%.:.U?.Wk.Cj|
+00000070 93 34 2c 6e cb 4e 9d 25 8b 4d 7d d7 cc e1 16 59 |.4,n.N.%.M}....Y|
+00000080 2a 95 60 e4 31 0e df 7f cb 9d b7 14 03 03 00 01 |*.`.1...........|
+00000090 01 16 03 03 00 40 28 33 df 69 4f 4c 48 b1 fb 8d |.....@(3.iOLH...|
+000000a0 3f 3c d2 81 7c 33 cf 21 6a f7 d6 43 82 22 5b de |?<..|3.!j..C."[.|
+000000b0 46 7f 7b e2 39 23 bd 39 fa 03 bd 11 9d a8 a2 84 |F.{.9#.9........|
+000000c0 4a 90 1a ab e1 b4 23 9f 72 d0 97 9e 05 5c 47 2b |J.....#.r....\G+|
+000000d0 7a 53 bb ec a0 07 |zS....|
+>>> Flow 4 (server to client)
+00000000 16 03 03 00 8b 04 00 00 87 00 00 00 00 00 81 50 |...............P|
+00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
+00000030 6f 2c 9f 83 51 ed 14 ef 68 ca 42 c5 4c 75 5e a5 |o,..Q...h.B.Lu^.|
+00000040 6f d2 49 61 e4 fb 83 46 7c 4c ab f9 c6 d1 3c 9e |o.Ia...F|L....<.|
+00000050 5b 8d d8 bc c0 a5 2d 84 db 24 dd a0 16 60 1d 87 |[.....-..$...`..|
+00000060 a0 52 88 25 6c c6 8e 5b 71 0f 74 c3 48 49 38 16 |.R.%l..[q.t.HI8.|
+00000070 92 8c de 77 bd 8a 2b 45 4d 58 86 40 b1 d6 0f 99 |...w..+EMX.@....|
+00000080 de 27 41 b2 41 27 aa fe 26 e9 24 91 2a 00 ff 08 |.'A.A'..&.$.*...|
+00000090 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+000000a0 00 00 00 00 00 00 00 00 00 00 00 fc cd 6b 01 90 |.............k..|
+000000b0 7b 0c 31 54 a0 3a 8b f7 ba 45 e7 e0 df 9a 59 6d |{.1T.:...E....Ym|
+000000c0 83 b6 b2 c8 93 d8 d9 b6 fe 19 56 51 75 a3 ea 0e |..........VQu...|
+000000d0 f4 4b 64 27 66 fc 19 7b 7e 13 e7 17 03 03 00 40 |.Kd'f..{~......@|
+000000e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+000000f0 c2 1b 6f f1 1e 05 1b 8a 19 16 67 00 0f dc a8 a2 |..o.......g.....|
+00000100 00 56 49 0a bb c5 df 7e 96 0c 5c db a0 f4 3e b4 |.VI....~..\...>.|
+00000110 30 3e b6 f0 16 dd d4 ed c9 de 64 49 00 9b 51 dc |0>........dI..Q.|
+00000120 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+00000130 00 00 00 00 00 e1 9d 08 1a 2e 9a 0f 84 6d 4e e5 |.............mN.|
+00000140 2c 50 b9 28 5d 88 ea bb 48 4d af 26 7f 82 0b 56 |,P.(]...HM.&...V|
+00000150 c5 87 71 2a e7 |..q*.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable b/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
new file mode 100644
index 0000000..8cb57f5
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-IssueTicketPreDisable
@@ -0,0 +1,91 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 71 01 00 00 6d 03 03 e1 40 35 c8 5c |....q...m...@5.\|
+00000010 71 63 3f 5a 00 42 e6 3e 64 62 b8 c4 e7 e7 ba 98 |qc?Z.B.>db......|
+00000020 d8 fa 2c b5 65 f7 50 db 43 d9 70 00 00 04 00 2f |..,.e.P.C.p..../|
+00000030 00 ff 01 00 00 40 00 23 00 00 00 16 00 00 00 17 |.....@.#........|
+00000040 00 00 00 0d 00 30 00 2e 04 03 05 03 06 03 08 07 |.....0..........|
+00000050 08 08 08 09 08 0a 08 0b 08 04 08 05 08 06 04 01 |................|
+00000060 05 01 06 01 03 03 02 03 03 01 02 01 03 02 02 02 |................|
+00000070 04 02 05 02 06 02 |......|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 35 02 00 00 31 03 03 00 00 00 00 00 |....5...1.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 00 2f 00 00 |...DOWNGRD.../..|
+00000030 09 00 23 00 00 ff 01 00 01 00 16 03 03 02 59 0b |..#...........Y.|
+00000040 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 82 01 |..U..R..O0..K0..|
+00000050 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 5b ea |............?.[.|
+00000060 a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |.0...*.H........|
+00000070 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 |0.1.0...U....Go1|
+00000080 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 6f 6f |.0...U....Go Roo|
+00000090 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 30 30 |t0...16010100000|
+000000a0 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 30 30 |0Z..250101000000|
+000000b0 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 47 6f |Z0.1.0...U....Go|
+000000c0 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 81 9f |1.0...U....Go0..|
+000000d0 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 00 03 |0...*.H.........|
+000000e0 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 2e 12 |...0.......F}...|
+000000f0 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 |'.H..(!.~...]..R|
+00000100 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 be 97 |E.z6G....B[.....|
+00000110 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 |y.@.Om..+.....g.|
+00000120 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 |...."8.J.ts+.4..|
+00000130 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 |....t{.X.la<..A.|
+00000140 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 54 cf |.++$#w[.;.u]. T.|
+00000150 a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 |.c...$....P....C|
+00000160 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 01 a3 |...ub...R.......|
+00000170 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 ff 04 |..0..0...U......|
+00000180 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 30 14 |.....0...U.%..0.|
+00000190 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 01 05 |..+.........+...|
+000001a0 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff 04 02 |....0...U.......|
+000001b0 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f 91 16 |0.0...U.........|
+000001c0 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 |.CC>I..m....`0..|
+000001d0 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d 13 7e |.U.#..0...H.IM.~|
+000001e0 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 55 1d |.1......n{0...U.|
+000001f0 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 2e 67 |...0...example.g|
+00000200 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 0d 01 |olang0...*.H....|
+00000210 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 |.........0.@+[P.|
+00000220 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 |a...SX...(.X..8.|
+00000230 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 |...1Z..f=C.-....|
+00000240 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 40 20 |.. d8.$:....}.@ |
+00000250 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c |._...a..v......\|
+00000260 ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c |.....l..s..Cw...|
+00000270 f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db 46 06 |....@.a.Lr+...F.|
+00000280 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 |.M...>...B...=.`|
+00000290 84 5c 21 d3 3b e9 fa e7 16 03 03 00 04 0e 00 00 |.\!.;...........|
+000002a0 00 |.|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 4f ce 06 88 66 |...........O...f|
+00000010 dd e1 0a 55 ef fb 1b 9e 70 62 8b 3b 0d e4 19 0f |...U....pb.;....|
+00000020 4f 16 c9 79 92 9c 4d 16 21 ea 43 d7 58 7f 35 65 |O..y..M.!.C.X.5e|
+00000030 a3 15 7a 8d b5 6e 9b f6 73 19 c2 0c 58 be 9d 8a |..z..n..s...X...|
+00000040 5a a8 be f3 89 48 64 28 6a 7f be b7 4a 58 93 af |Z....Hd(j...JX..|
+00000050 c0 ff 8a ae 01 34 1f cf 7b b0 7a 5e 69 19 43 fa |.....4..{.z^i.C.|
+00000060 21 b8 dc ee 0e ab 3b 81 c9 b9 be b9 56 a0 dd 62 |!.....;.....V..b|
+00000070 02 45 14 54 4d 05 5a cc 31 68 1f 17 91 a6 0e d7 |.E.TM.Z.1h......|
+00000080 5a f3 ae bb 5e 90 1d c3 c9 56 2a 14 03 03 00 01 |Z...^....V*.....|
+00000090 01 16 03 03 00 40 a1 34 07 ef 45 42 d2 88 bb 6e |.....@.4..EB...n|
+000000a0 7f 3a 2a 39 67 3f 90 76 95 b7 cc 86 b6 1a 6c c6 |.:*9g?.v......l.|
+000000b0 da 8f 26 f3 34 6c 1f 6f 05 11 39 40 00 46 00 be |..&.4l.o..9@.F..|
+000000c0 8f 3a af 86 d6 6d 5d 00 f3 5d 22 1c 31 2c 24 ee |.:...m]..]".1,$.|
+000000d0 e5 11 ba 94 5f b1 |...._.|
+>>> Flow 4 (server to client)
+00000000 16 03 03 00 8b 04 00 00 87 00 00 00 00 00 81 50 |...............P|
+00000010 46 ad c1 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 |F....8.{+....B>.|
+00000020 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 94 |................|
+00000030 6f 2c 9f 83 51 ed 14 ef 68 ca 42 c5 4c 20 33 6c |o,..Q...h.B.L 3l|
+00000040 01 97 a5 69 44 bf 8f ea db 83 05 fb ef cc 51 1f |...iD.........Q.|
+00000050 0b 4d 44 77 89 11 cf c8 38 16 67 ea a2 3e 8b 2a |.MDw....8.g..>.*|
+00000060 18 f2 f7 25 ce e0 d8 4c 93 31 b0 59 23 49 38 16 |...%...L.1.Y#I8.|
+00000070 3a f9 63 9e 61 21 1b ab 67 09 6a 23 07 8e d0 4a |:.c.a!..g.j#...J|
+00000080 19 78 9c 1e 60 40 a7 83 c5 9a 48 41 35 c4 e9 63 |.x..`@....HA5..c|
+00000090 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+000000a0 00 00 00 00 00 00 00 00 00 00 00 b8 46 07 9e 14 |............F...|
+000000b0 85 ba 6d e0 f1 f5 99 43 80 9a 54 6b 33 1e 4f c1 |..m....C..Tk3.O.|
+000000c0 88 b7 3d 60 04 d4 e9 b0 b2 6d c4 1a ca 3b 9f 83 |..=`.....m...;..|
+000000d0 28 5f ea b2 54 e4 11 78 69 de 1a 17 03 03 00 40 |(_..T..xi......@|
+000000e0 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+000000f0 55 34 ad ae 9b 37 df cd 88 ae fc 6a ac c5 cf 16 |U4...7.....j....|
+00000100 ec f1 bc 22 1e d2 c1 52 5e a2 e7 d2 6e 37 7a 29 |..."...R^...n7z)|
+00000110 c8 b9 d4 7d 81 63 1a f0 53 d9 10 fd 4f 3d 1c dd |...}.c..S...O=..|
+00000120 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+00000130 00 00 00 00 00 8f f2 11 0d 93 99 83 29 d4 10 a4 |............)...|
+00000140 7c bb 26 7b 24 f1 15 3a 9b 81 0e cb 0a 51 4b 39 ||.&{$..:.....QK9|
+00000150 69 1d e5 38 5e |i..8^|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-P256 b/src/crypto/tls/testdata/Server-TLSv12-P256
new file mode 100644
index 0000000..58b9bed
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-P256
@@ -0,0 +1,86 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 8f 01 00 00 8b 03 03 49 de 51 77 8e |...........I.Qw.|
+00000010 58 03 e9 25 0b 9a 88 ef 35 2d 35 a8 30 29 22 61 |X..%....5-5.0)"a|
+00000020 ae b4 af 8a a1 2c 45 59 40 5f aa 00 00 04 c0 2f |.....,EY@_...../|
+00000030 00 ff 01 00 00 5e 00 00 00 0e 00 0c 00 00 09 31 |.....^.........1|
+00000040 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
+00000050 00 0a 00 04 00 02 00 17 00 16 00 00 00 17 00 00 |................|
+00000060 00 0d 00 30 00 2e 04 03 05 03 06 03 08 07 08 08 |...0............|
+00000070 08 09 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 |................|
+00000080 06 01 03 03 02 03 03 01 02 01 03 02 02 02 04 02 |................|
+00000090 05 02 06 02 |....|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 37 02 00 00 33 03 03 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 c0 2f 00 00 |...DOWNGRD.../..|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 03 02 |................|
+00000040 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 |Y...U..R..O0..K0|
+00000050 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 |..............?.|
+00000060 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b |[..0...*.H......|
+00000070 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 |..0.1.0...U....G|
+00000080 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 |o1.0...U....Go R|
+00000090 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 |oot0...160101000|
+000000a0 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 |000Z..2501010000|
+000000b0 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 |00Z0.1.0...U....|
+000000c0 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 |Go1.0...U....Go0|
+000000d0 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......|
+000000e0 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 |.....0.......F}.|
+000000f0 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe |..'.H..(!.~...].|
+00000100 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 |.RE.z6G....B[...|
+00000110 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e |..y.@.Om..+.....|
+00000120 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 |g....."8.J.ts+.4|
+00000130 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 |......t{.X.la<..|
+00000140 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 |A..++$#w[.;.u]. |
+00000150 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 |T..c...$....P...|
+00000160 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 |.C...ub...R.....|
+00000170 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 |....0..0...U....|
+00000180 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 |.......0...U.%..|
+00000190 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 |0...+.........+.|
+000001a0 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff |......0...U.....|
+000001b0 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f |..0.0...U.......|
+000001c0 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 |...CC>I..m....`0|
+000001d0 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d |...U.#..0...H.IM|
+000001e0 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 |.~.1......n{0...|
+000001f0 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 |U....0...example|
+00000200 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 |.golang0...*.H..|
+00000210 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b |...........0.@+[|
+00000220 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 |P.a...SX...(.X..|
+00000230 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b |8....1Z..f=C.-..|
+00000240 f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 |.... d8.$:....}.|
+00000250 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 |@ ._...a..v.....|
+00000260 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d |.\.....l..s..Cw.|
+00000270 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db |......@.a.Lr+...|
+00000280 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d |F..M...>...B...=|
+00000290 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 cd 0c |.`.\!.;.........|
+000002a0 00 00 c9 03 00 17 41 04 1e 18 37 ef 0d 19 51 88 |......A...7...Q.|
+000002b0 35 75 71 b5 e5 54 5b 12 2e 8f 09 67 fd a7 24 20 |5uq..T[....g..$ |
+000002c0 3e b2 56 1c ce 97 28 5e f8 2b 2d 4f 9e f1 07 9f |>.V...(^.+-O....|
+000002d0 6c 4b 5b 83 56 e2 32 42 e9 58 b6 d7 49 a6 b5 68 |lK[.V.2B.X..I..h|
+000002e0 1a 41 03 56 6b dc 5a 89 08 04 00 80 7b bd 89 a1 |.A.Vk.Z.....{...|
+000002f0 d8 9d cf e4 75 ac 15 60 a9 49 0c c7 68 61 4e e4 |....u..`.I..haN.|
+00000300 2b 51 37 5a 65 38 a4 52 6a d0 4f 8b 76 93 a4 7c |+Q7Ze8.Rj.O.v..||
+00000310 ac 30 6b 89 f1 c7 88 8f f3 5c c7 e9 d6 7c 33 94 |.0k......\...|3.|
+00000320 f7 fc f8 69 35 f3 f7 e0 ea fc 51 5c b2 e2 dc 9e |...i5.....Q\....|
+00000330 57 03 af e6 19 0d 0d e4 25 b6 52 19 12 ad 35 fc |W.......%.R...5.|
+00000340 7f c3 6a 1f ed 06 82 34 81 13 d7 c1 67 a9 18 88 |..j....4....g...|
+00000350 2f bb 00 54 5d d9 01 16 29 dd 03 3c 69 f7 46 52 |/..T]...)..<i.FR|
+00000360 6a 95 51 81 75 68 fa 15 09 11 38 94 16 03 03 00 |j.Q.uh....8.....|
+00000370 04 0e 00 00 00 |.....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 46 10 00 00 42 41 04 a6 c3 8d d1 32 |....F...BA.....2|
+00000010 8e b4 ac 27 75 4a 57 26 7f 6a 52 a7 82 ee c2 b1 |...'uJW&.jR.....|
+00000020 a3 68 0a 8d 09 ff 82 61 57 f3 32 5e ec 1a 2f 20 |.h.....aW.2^../ |
+00000030 8c c1 d4 cf 27 7b f0 1d f9 5d f6 24 80 6a 45 d2 |....'{...].$.jE.|
+00000040 97 cf f1 5d a2 e3 b0 15 7d e6 a4 14 03 03 00 01 |...]....}.......|
+00000050 01 16 03 03 00 28 21 36 fe 82 d2 4a b4 da f8 14 |.....(!6...J....|
+00000060 d6 d6 8c be 56 1f ca 82 7f 20 bb 01 be fb 2a 0d |....V.... ....*.|
+00000070 a8 31 ee 79 f7 8a 8b 4a 1b a7 66 3a 89 67 |.1.y...J..f:.g|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....|
+00000010 00 00 00 00 0a 97 89 c3 74 09 63 25 2a fc e1 29 |........t.c%*..)|
+00000020 18 b1 bc d6 75 2e 3b 2a fb 90 17 b9 b8 ea e2 c4 |....u.;*........|
+00000030 29 94 16 17 03 03 00 25 00 00 00 00 00 00 00 01 |)......%........|
+00000040 8c 30 76 b7 fd b1 96 0b 2a 8f f3 e1 b3 38 16 15 |.0v.....*....8..|
+00000050 10 3d 32 ee 29 b5 12 cb cb cf 98 a3 c5 15 03 03 |.=2.)...........|
+00000060 00 1a 00 00 00 00 00 00 00 02 9e 4a 55 8e 91 ff |...........JU...|
+00000070 13 0b 56 be 3c 5d b8 26 42 f1 c8 28 |..V.<].&B..(|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-3DES b/src/crypto/tls/testdata/Server-TLSv12-RSA-3DES
new file mode 100644
index 0000000..17a5ad0
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-3DES
@@ -0,0 +1,80 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 97 01 00 00 93 03 03 e2 8f 43 82 4c |.............C.L|
+00000010 13 33 88 d2 53 5d b6 02 d2 b6 b2 a1 11 f0 30 14 |.3..S]........0.|
+00000020 41 1e 8c 79 85 38 75 cd e8 a6 a7 00 00 04 00 0a |A..y.8u.........|
+00000030 00 ff 01 00 00 66 00 00 00 0e 00 0c 00 00 09 31 |.....f.........1|
+00000040 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
+00000050 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 |................|
+00000060 00 16 00 00 00 17 00 00 00 0d 00 30 00 2e 04 03 |...........0....|
+00000070 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 |................|
+00000080 08 05 08 06 04 01 05 01 06 01 03 03 02 03 03 01 |................|
+00000090 02 01 03 02 02 02 04 02 05 02 06 02 |............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 37 02 00 00 33 03 03 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 00 0a 00 00 |...DOWNGRD......|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 03 02 |................|
+00000040 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 |Y...U..R..O0..K0|
+00000050 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 |..............?.|
+00000060 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b |[..0...*.H......|
+00000070 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 |..0.1.0...U....G|
+00000080 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 |o1.0...U....Go R|
+00000090 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 |oot0...160101000|
+000000a0 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 |000Z..2501010000|
+000000b0 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 |00Z0.1.0...U....|
+000000c0 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 |Go1.0...U....Go0|
+000000d0 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......|
+000000e0 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 |.....0.......F}.|
+000000f0 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe |..'.H..(!.~...].|
+00000100 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 |.RE.z6G....B[...|
+00000110 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e |..y.@.Om..+.....|
+00000120 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 |g....."8.J.ts+.4|
+00000130 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 |......t{.X.la<..|
+00000140 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 |A..++$#w[.;.u]. |
+00000150 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 |T..c...$....P...|
+00000160 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 |.C...ub...R.....|
+00000170 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 |....0..0...U....|
+00000180 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 |.......0...U.%..|
+00000190 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 |0...+.........+.|
+000001a0 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff |......0...U.....|
+000001b0 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f |..0.0...U.......|
+000001c0 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 |...CC>I..m....`0|
+000001d0 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d |...U.#..0...H.IM|
+000001e0 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 |.~.1......n{0...|
+000001f0 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 |U....0...example|
+00000200 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 |.golang0...*.H..|
+00000210 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b |...........0.@+[|
+00000220 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 |P.a...SX...(.X..|
+00000230 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b |8....1Z..f=C.-..|
+00000240 f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 |.... d8.$:....}.|
+00000250 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 |@ ._...a..v.....|
+00000260 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d |.\.....l..s..Cw.|
+00000270 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db |......@.a.Lr+...|
+00000280 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d |F..M...>...B...=|
+00000290 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 04 0e |.`.\!.;.........|
+000002a0 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 57 ce 41 c0 4d |...........W.A.M|
+00000010 b1 69 27 6e cb 92 a5 71 52 85 e7 a8 69 b0 31 d1 |.i'n...qR...i.1.|
+00000020 0a b0 3d a6 9d ab 04 e8 a2 4c d8 67 95 97 da 63 |..=......L.g...c|
+00000030 f7 0b 6e 62 29 5b 8b cf 77 f1 80 a5 1f 67 08 71 |..nb)[..w....g.q|
+00000040 50 c3 a9 90 ea b8 11 3d 5d c9 f5 1c 37 fa 67 b1 |P......=]...7.g.|
+00000050 64 b0 04 3e c1 0d db 77 fe b9 a0 ea f2 0f 1d af |d..>...w........|
+00000060 9a 77 b3 96 4f 3f 3c 52 a7 ed c4 3f 48 ef ff f8 |.w..O?<R...?H...|
+00000070 38 f6 34 60 5a 29 12 37 85 23 1c 39 8e 1a a7 2f |8.4`Z).7.#.9.../|
+00000080 68 39 1f 37 ed 08 a8 a5 b2 c1 f0 14 03 03 00 01 |h9.7............|
+00000090 01 16 03 03 00 30 8d 64 b1 cb 97 76 8a 78 08 d1 |.....0.d...v.x..|
+000000a0 c0 af 60 9c 0d f0 ae 41 93 f4 97 2b 46 f7 65 52 |..`....A...+F.eR|
+000000b0 55 a7 90 4a 83 47 cc e4 51 29 0d 6e 0b 42 52 c2 |U..J.G..Q).n.BR.|
+000000c0 bf 13 b8 01 72 d3 |....r.|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 30 00 00 00 00 00 |..........0.....|
+00000010 00 00 00 0d 0f 3c 6a 28 f0 97 90 1a c3 7e c8 63 |.....<j(.....~.c|
+00000020 15 75 1b 71 c8 bb 7d 83 b0 9b a6 73 3d 3d 51 7a |.u.q..}....s==Qz|
+00000030 52 5b e4 33 16 93 40 23 43 7c a2 17 03 03 00 30 |R[.3..@#C|.....0|
+00000040 00 00 00 00 00 00 00 00 be db 1d 03 aa 15 53 49 |..............SI|
+00000050 a3 57 00 24 75 3a b1 48 71 ec d9 7d e1 40 5c dc |.W.$u:.Hq..}.@\.|
+00000060 fd f5 33 6f 6b c7 3e 9e 2e 05 af 1b 12 73 75 8c |..3ok.>......su.|
+00000070 15 03 03 00 20 00 00 00 00 00 00 00 00 5c 30 63 |.... ........\0c|
+00000080 23 55 26 ee 8d 81 9a 2e b4 e7 38 6b 04 e7 42 43 |#U&.......8k..BC|
+00000090 50 de 1e 40 2d |P..@-|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES
new file mode 100644
index 0000000..0196e21
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES
@@ -0,0 +1,84 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 97 01 00 00 93 03 03 dd 28 eb 68 4a |............(.hJ|
+00000010 8a 71 d2 98 d0 2d 21 c7 e9 19 19 de c8 13 0b 67 |.q...-!........g|
+00000020 f4 ff 4c d0 37 f5 72 9f 2d fb b3 00 00 04 00 2f |..L.7.r.-....../|
+00000030 00 ff 01 00 00 66 00 00 00 0e 00 0c 00 00 09 31 |.....f.........1|
+00000040 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
+00000050 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 |................|
+00000060 00 16 00 00 00 17 00 00 00 0d 00 30 00 2e 04 03 |...........0....|
+00000070 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 |................|
+00000080 08 05 08 06 04 01 05 01 06 01 03 03 02 03 03 01 |................|
+00000090 02 01 03 02 02 02 04 02 05 02 06 02 |............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 37 02 00 00 33 03 03 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 00 2f 00 00 |...DOWNGRD.../..|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 03 02 |................|
+00000040 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 |Y...U..R..O0..K0|
+00000050 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 |..............?.|
+00000060 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b |[..0...*.H......|
+00000070 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 |..0.1.0...U....G|
+00000080 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 |o1.0...U....Go R|
+00000090 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 |oot0...160101000|
+000000a0 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 |000Z..2501010000|
+000000b0 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 |00Z0.1.0...U....|
+000000c0 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 |Go1.0...U....Go0|
+000000d0 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......|
+000000e0 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 |.....0.......F}.|
+000000f0 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe |..'.H..(!.~...].|
+00000100 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 |.RE.z6G....B[...|
+00000110 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e |..y.@.Om..+.....|
+00000120 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 |g....."8.J.ts+.4|
+00000130 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 |......t{.X.la<..|
+00000140 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 |A..++$#w[.;.u]. |
+00000150 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 |T..c...$....P...|
+00000160 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 |.C...ub...R.....|
+00000170 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 |....0..0...U....|
+00000180 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 |.......0...U.%..|
+00000190 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 |0...+.........+.|
+000001a0 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff |......0...U.....|
+000001b0 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f |..0.0...U.......|
+000001c0 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 |...CC>I..m....`0|
+000001d0 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d |...U.#..0...H.IM|
+000001e0 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 |.~.1......n{0...|
+000001f0 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 |U....0...example|
+00000200 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 |.golang0...*.H..|
+00000210 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b |...........0.@+[|
+00000220 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 |P.a...SX...(.X..|
+00000230 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b |8....1Z..f=C.-..|
+00000240 f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 |.... d8.$:....}.|
+00000250 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 |@ ._...a..v.....|
+00000260 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d |.\.....l..s..Cw.|
+00000270 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db |......@.a.Lr+...|
+00000280 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d |F..M...>...B...=|
+00000290 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 04 0e |.`.\!.;.........|
+000002a0 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 c0 37 ef f3 d9 |............7...|
+00000010 6b 7b 3f c4 9f 46 d2 6b 8f 7f 8d ce 89 cf 8e 2b |k{?..F.k.......+|
+00000020 1f 0d 86 f9 90 5a 23 28 6c d3 14 ce 2a 0b f1 0e |.....Z#(l...*...|
+00000030 96 1c 11 7d c0 b8 fb 4b 2e cb 07 1c fe b9 e1 62 |...}...K.......b|
+00000040 2c 38 1c 46 21 74 23 a9 f2 0b 15 36 ef 88 32 e8 |,8.F!t#....6..2.|
+00000050 28 66 8e ab 14 be e9 02 04 9d 92 99 cc 6e 28 d0 |(f...........n(.|
+00000060 f9 3d dc 61 7f f7 17 59 ab 1c 86 94 9a 28 7b 46 |.=.a...Y.....({F|
+00000070 3c 36 ff d3 26 3c ad 2d 33 ef 99 83 09 a5 a8 2f |<6..&<.-3....../|
+00000080 b3 a3 74 7f 49 a3 f1 47 7d 8c 12 14 03 03 00 01 |..t.I..G}.......|
+00000090 01 16 03 03 00 40 32 68 cb ea 32 cb f2 7a 0e 4b |.....@2h..2..z.K|
+000000a0 63 72 96 93 e8 2d 5b 22 a6 3a 05 9d 60 50 e5 d0 |cr...-[".:..`P..|
+000000b0 f3 f8 14 ed 81 fe 17 a0 ee 3f 7b aa ca dc 06 bc |.........?{.....|
+000000c0 28 90 73 33 84 0c 92 39 b7 cb da 06 08 05 0b 03 |(.s3...9........|
+000000d0 86 be cc 70 0e c2 |...p..|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 10 a0 48 48 86 |.............HH.|
+00000020 ac 1f f4 05 4d 12 9d 90 54 26 ec c8 1f 6d e7 d5 |....M...T&...m..|
+00000030 0c 92 61 88 2f 43 77 75 0c 08 0f 33 ac c3 d3 b0 |..a./Cwu...3....|
+00000040 94 68 e3 3f 9f c9 43 a5 8b ee ed 17 03 03 00 40 |.h.?..C........@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 fd 7d d3 d6 3f a5 10 37 a1 93 20 ca c8 8c 9d c3 |.}..?..7.. .....|
+00000070 90 df 2f 40 e6 83 af b6 be e4 3d 07 ff 0d 24 97 |../@......=...$.|
+00000080 c2 ff af 81 eb b5 91 72 6b 6d 70 8c af 3f 9f 76 |.......rkmp..?.v|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 6b 80 aa 88 45 8c 39 a8 4c ca 33 |.....k...E.9.L.3|
+000000b0 f2 33 85 a0 74 6a 64 a3 43 17 4c 5c 9b 50 e5 8d |.3..tjd.C.L\.P..|
+000000c0 ff 26 03 e1 07 |.&...|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
new file mode 100644
index 0000000..fa4b47b
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES-GCM
@@ -0,0 +1,82 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 97 01 00 00 93 03 03 8a ca f1 8f ad |................|
+00000010 fe 0b a3 e1 b8 08 10 1a 40 57 b6 f7 f7 e3 72 c4 |........@W....r.|
+00000020 57 4a 71 f8 30 cd 62 62 c7 0f 2d 00 00 04 c0 2f |WJq.0.bb..-..../|
+00000030 00 ff 01 00 00 66 00 00 00 0e 00 0c 00 00 09 31 |.....f.........1|
+00000040 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
+00000050 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 |................|
+00000060 00 16 00 00 00 17 00 00 00 0d 00 30 00 2e 04 03 |...........0....|
+00000070 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 |................|
+00000080 08 05 08 06 04 01 05 01 06 01 03 03 02 03 03 01 |................|
+00000090 02 01 03 02 02 02 04 02 05 02 06 02 |............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 37 02 00 00 33 03 03 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 c0 2f 00 00 |...DOWNGRD.../..|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 03 02 |................|
+00000040 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 |Y...U..R..O0..K0|
+00000050 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 |..............?.|
+00000060 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b |[..0...*.H......|
+00000070 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 |..0.1.0...U....G|
+00000080 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 |o1.0...U....Go R|
+00000090 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 |oot0...160101000|
+000000a0 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 |000Z..2501010000|
+000000b0 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 |00Z0.1.0...U....|
+000000c0 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 |Go1.0...U....Go0|
+000000d0 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......|
+000000e0 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 |.....0.......F}.|
+000000f0 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe |..'.H..(!.~...].|
+00000100 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 |.RE.z6G....B[...|
+00000110 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e |..y.@.Om..+.....|
+00000120 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 |g....."8.J.ts+.4|
+00000130 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 |......t{.X.la<..|
+00000140 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 |A..++$#w[.;.u]. |
+00000150 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 |T..c...$....P...|
+00000160 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 |.C...ub...R.....|
+00000170 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 |....0..0...U....|
+00000180 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 |.......0...U.%..|
+00000190 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 |0...+.........+.|
+000001a0 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff |......0...U.....|
+000001b0 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f |..0.0...U.......|
+000001c0 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 |...CC>I..m....`0|
+000001d0 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d |...U.#..0...H.IM|
+000001e0 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 |.~.1......n{0...|
+000001f0 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 |U....0...example|
+00000200 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 |.golang0...*.H..|
+00000210 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b |...........0.@+[|
+00000220 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 |P.a...SX...(.X..|
+00000230 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b |8....1Z..f=C.-..|
+00000240 f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 |.... d8.$:....}.|
+00000250 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 |@ ._...a..v.....|
+00000260 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d |.\.....l..s..Cw.|
+00000270 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db |......@.a.Lr+...|
+00000280 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d |F..M...>...B...=|
+00000290 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c |.`.\!.;.........|
+000002a0 00 00 a8 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 |...... /.}.G.bC.|
+000002b0 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed |(.._.).0........|
+000002c0 90 99 5f 58 cb 3b 74 08 04 00 80 50 0b d9 1c 03 |.._X.;t....P....|
+000002d0 6f 08 05 a6 39 cc 9f 7e 3d f1 fb af 8e 0b 9a ef |o...9..~=.......|
+000002e0 39 d3 b6 e3 71 9c 5a 37 a1 86 f2 f0 59 01 fc b2 |9...q.Z7....Y...|
+000002f0 51 1c 0e 22 42 24 3e c6 db fb a1 39 9d 75 f4 79 |Q.."B$>....9.u.y|
+00000300 55 dd e5 99 0b 22 5b ed c7 19 ac db ed d3 ee 23 |U...."[........#|
+00000310 b9 37 2b 51 ea 7f 39 4d 8b 0a bc a2 2e f2 ef 9e |.7+Q..9M........|
+00000320 a5 8c 99 77 ff d2 fb 46 e4 10 4e a9 b2 a9 ce b6 |...w...F..N.....|
+00000330 50 d4 0a 28 a5 3f 0e 2c 60 cd 0f 07 9c 7e 60 c3 |P..(.?.,`....~`.|
+00000340 79 a5 cf f3 cd 77 5a 16 8d fc 14 16 03 03 00 04 |y....wZ.........|
+00000350 0e 00 00 00 |....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 ef 3b b1 d2 a3 f6 |....%...! .;....|
+00000010 be f2 fc 2e b5 ed d3 ec 6a fb 2f 0d 5a 04 98 61 |........j./.Z..a|
+00000020 92 26 59 ba 17 26 1b 60 27 2b 14 03 03 00 01 01 |.&Y..&.`'+......|
+00000030 16 03 03 00 28 e2 94 22 bb 71 70 c8 a6 63 e5 6f |....(..".qp..c.o|
+00000040 2e 00 0f b9 bf 6b 54 34 dc ce b0 12 0b 16 e5 ac |.....kT4........|
+00000050 8f 6b 1e 96 a1 e3 86 b7 6f 8c 76 09 da |.k......o.v..|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....|
+00000010 00 00 00 f5 dc 00 28 06 03 50 9b b2 db 4d 89 25 |......(..P...M.%|
+00000020 3a 94 04 85 5b 7a 3f 16 fb 55 8f e0 c3 a3 33 21 |:...[z?..U....3!|
+00000030 65 84 c5 17 03 03 00 25 00 00 00 00 00 00 00 01 |e......%........|
+00000040 a9 35 62 24 4b 63 6e 62 1c 8f 99 e4 e0 3e f0 a2 |.5b$Kcnb.....>..|
+00000050 e3 02 34 6f 10 71 9c 6b b3 4a 2d 7f 71 15 03 03 |..4o.q.k.J-.q...|
+00000060 00 1a 00 00 00 00 00 00 00 02 91 43 07 98 b1 ba |...........C....|
+00000070 06 1b dd 21 46 82 63 67 8b bb 1f b5 |...!F.cg....|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384 b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384
new file mode 100644
index 0000000..2cc2c28
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-AES256-GCM-SHA384
@@ -0,0 +1,82 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 97 01 00 00 93 03 03 0f 13 d8 49 94 |..............I.|
+00000010 b9 cc 41 1d d4 3d bb d2 c9 a3 2c 74 11 ca 01 e8 |..A..=....,t....|
+00000020 5b b0 2e 57 60 b5 30 37 2d b9 f0 00 00 04 c0 30 |[..W`.07-......0|
+00000030 00 ff 01 00 00 66 00 00 00 0e 00 0c 00 00 09 31 |.....f.........1|
+00000040 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
+00000050 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 |................|
+00000060 00 16 00 00 00 17 00 00 00 0d 00 30 00 2e 04 03 |...........0....|
+00000070 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 |................|
+00000080 08 05 08 06 04 01 05 01 06 01 03 03 02 03 03 01 |................|
+00000090 02 01 03 02 02 02 04 02 05 02 06 02 |............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 37 02 00 00 33 03 03 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 c0 30 00 00 |...DOWNGRD...0..|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 03 02 |................|
+00000040 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 |Y...U..R..O0..K0|
+00000050 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 |..............?.|
+00000060 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b |[..0...*.H......|
+00000070 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 |..0.1.0...U....G|
+00000080 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 |o1.0...U....Go R|
+00000090 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 |oot0...160101000|
+000000a0 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 |000Z..2501010000|
+000000b0 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 |00Z0.1.0...U....|
+000000c0 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 |Go1.0...U....Go0|
+000000d0 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......|
+000000e0 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 |.....0.......F}.|
+000000f0 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe |..'.H..(!.~...].|
+00000100 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 |.RE.z6G....B[...|
+00000110 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e |..y.@.Om..+.....|
+00000120 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 |g....."8.J.ts+.4|
+00000130 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 |......t{.X.la<..|
+00000140 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 |A..++$#w[.;.u]. |
+00000150 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 |T..c...$....P...|
+00000160 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 |.C...ub...R.....|
+00000170 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 |....0..0...U....|
+00000180 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 |.......0...U.%..|
+00000190 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 |0...+.........+.|
+000001a0 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff |......0...U.....|
+000001b0 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f |..0.0...U.......|
+000001c0 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 |...CC>I..m....`0|
+000001d0 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d |...U.#..0...H.IM|
+000001e0 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 |.~.1......n{0...|
+000001f0 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 |U....0...example|
+00000200 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 |.golang0...*.H..|
+00000210 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b |...........0.@+[|
+00000220 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 |P.a...SX...(.X..|
+00000230 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b |8....1Z..f=C.-..|
+00000240 f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 |.... d8.$:....}.|
+00000250 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 |@ ._...a..v.....|
+00000260 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d |.\.....l..s..Cw.|
+00000270 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db |......@.a.Lr+...|
+00000280 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d |F..M...>...B...=|
+00000290 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c |.`.\!.;.........|
+000002a0 00 00 a8 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 |...... /.}.G.bC.|
+000002b0 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed |(.._.).0........|
+000002c0 90 99 5f 58 cb 3b 74 08 04 00 80 40 f3 67 86 41 |.._X.;t....@.g.A|
+000002d0 93 17 f7 db b2 80 ca 73 f9 f8 45 24 cc 46 57 47 |.......s..E$.FWG|
+000002e0 28 83 19 df e8 63 e7 19 c4 a2 04 85 25 7d ec 55 |(....c......%}.U|
+000002f0 91 d4 df eb 77 53 c2 3b d5 71 1a f7 39 d2 ee b4 |....wS.;.q..9...|
+00000300 06 4b e4 07 b7 fa 8a 8e fa 64 22 83 dd 22 8b b8 |.K.......d".."..|
+00000310 4d a5 1a f5 e3 81 01 81 6a a1 6e 62 54 3a 3a 09 |M.......j.nbT::.|
+00000320 ed 76 f2 5a d3 4e 4b 74 be 46 50 0d 51 77 34 f6 |.v.Z.NKt.FP.Qw4.|
+00000330 02 ef 57 39 29 bf d9 64 ad 65 06 ae a6 8d 94 86 |..W9)..d.e......|
+00000340 84 76 cf 2c 36 98 04 5b a1 59 6c 16 03 03 00 04 |.v.,6..[.Yl.....|
+00000350 0e 00 00 00 |....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 d5 2b 0e 3c e9 3e |....%...! .+.<.>|
+00000010 e9 b0 3d 86 a9 85 b5 68 af cf 27 cf 4b d4 49 2e |..=....h..'.K.I.|
+00000020 68 f2 9e 3c 32 7c cb fb dc 57 14 03 03 00 01 01 |h..<2|...W......|
+00000030 16 03 03 00 28 5a cc f4 77 38 94 46 7b 39 5d 81 |....(Z..w8.F{9].|
+00000040 be 77 a5 4a 76 c9 46 62 17 0b 2b ea 89 c2 29 bd |.w.Jv.Fb..+...).|
+00000050 4b b0 dd 51 1e b8 7b a9 55 f5 fb b3 6a |K..Q..{.U...j|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....|
+00000010 00 00 00 b9 9b c0 b1 2b 71 af 0b 44 4e 4a cd e8 |.......+q..DNJ..|
+00000020 c6 68 b8 2a d9 67 6f 7f 18 12 22 5c 4b 5c ca 43 |.h.*.go..."\K\.C|
+00000030 ff c1 9d 17 03 03 00 25 00 00 00 00 00 00 00 01 |.......%........|
+00000040 3c ae 33 dd 69 6c 01 a0 d2 a7 91 52 43 f3 78 38 |<.3.il.....RC.x8|
+00000050 94 f4 24 0b 3d c9 bb 5f 02 27 89 bb 9b 15 03 03 |..$.=.._.'......|
+00000060 00 1a 00 00 00 00 00 00 00 02 68 8d d7 d8 2f 95 |..........h.../.|
+00000070 61 09 59 52 0d b8 12 fc 6a 07 28 37 |a.YR....j.(7|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-RC4 b/src/crypto/tls/testdata/Server-TLSv12-RSA-RC4
new file mode 100644
index 0000000..47a4ef2
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-RC4
@@ -0,0 +1,76 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 97 01 00 00 93 03 03 2c 3c 18 04 94 |...........,<...|
+00000010 e0 bb 10 99 7c 0c cd 0e e7 72 bc 83 4d f0 cf d7 |....|....r..M...|
+00000020 4b 8e 2c 8b 52 bf ed 86 65 d2 a3 00 00 04 00 05 |K.,.R...e.......|
+00000030 00 ff 01 00 00 66 00 00 00 0e 00 0c 00 00 09 31 |.....f.........1|
+00000040 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
+00000050 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 |................|
+00000060 00 16 00 00 00 17 00 00 00 0d 00 30 00 2e 04 03 |...........0....|
+00000070 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 |................|
+00000080 08 05 08 06 04 01 05 01 06 01 03 03 02 03 03 01 |................|
+00000090 02 01 03 02 02 02 04 02 05 02 06 02 |............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 37 02 00 00 33 03 03 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 00 05 00 00 |...DOWNGRD......|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 03 02 |................|
+00000040 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 |Y...U..R..O0..K0|
+00000050 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 |..............?.|
+00000060 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b |[..0...*.H......|
+00000070 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 |..0.1.0...U....G|
+00000080 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 |o1.0...U....Go R|
+00000090 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 |oot0...160101000|
+000000a0 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 |000Z..2501010000|
+000000b0 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 |00Z0.1.0...U....|
+000000c0 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 |Go1.0...U....Go0|
+000000d0 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......|
+000000e0 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 |.....0.......F}.|
+000000f0 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe |..'.H..(!.~...].|
+00000100 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 |.RE.z6G....B[...|
+00000110 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e |..y.@.Om..+.....|
+00000120 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 |g....."8.J.ts+.4|
+00000130 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 |......t{.X.la<..|
+00000140 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 |A..++$#w[.;.u]. |
+00000150 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 |T..c...$....P...|
+00000160 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 |.C...ub...R.....|
+00000170 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 |....0..0...U....|
+00000180 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 |.......0...U.%..|
+00000190 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 |0...+.........+.|
+000001a0 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff |......0...U.....|
+000001b0 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f |..0.0...U.......|
+000001c0 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 |...CC>I..m....`0|
+000001d0 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d |...U.#..0...H.IM|
+000001e0 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 |.~.1......n{0...|
+000001f0 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 |U....0...example|
+00000200 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 |.golang0...*.H..|
+00000210 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b |...........0.@+[|
+00000220 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 |P.a...SX...(.X..|
+00000230 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b |8....1Z..f=C.-..|
+00000240 f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 |.... d8.$:....}.|
+00000250 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 |@ ._...a..v.....|
+00000260 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d |.\.....l..s..Cw.|
+00000270 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db |......@.a.Lr+...|
+00000280 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d |F..M...>...B...=|
+00000290 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 04 0e |.`.\!.;.........|
+000002a0 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 a2 43 45 e6 1e |............CE..|
+00000010 08 d3 29 62 0b 40 75 98 a3 f6 68 d7 78 31 b0 c9 |..)b.@u...h.x1..|
+00000020 f4 f8 a6 98 dc d8 72 c1 2a 68 80 26 54 1c 16 af |......r.*h.&T...|
+00000030 9f 67 cf ee 74 de 9e 29 b6 cd 0d eb df aa ea 44 |.g..t..).......D|
+00000040 72 c9 aa fc ff c9 2d 9d bf bc f0 9b c1 7b 0d 5c |r.....-......{.\|
+00000050 69 0c 75 d8 23 09 29 97 f6 38 9c f9 4f 1b 4a d5 |i.u.#.)..8..O.J.|
+00000060 bd 04 d4 15 b3 a6 80 02 a4 11 32 d7 c0 cf 89 1f |..........2.....|
+00000070 93 80 2b 48 49 51 44 b7 77 3c bf b1 a6 87 a3 ff |..+HIQD.w<......|
+00000080 39 37 4a 42 49 92 93 25 0a 51 9a 14 03 03 00 01 |97JBI..%.Q......|
+00000090 01 16 03 03 00 24 b5 c9 d6 9c ec 77 38 d2 30 79 |.....$.....w8.0y|
+000000a0 f1 00 77 31 78 9b e6 ab ed 46 7c c6 e5 26 0b 44 |..w1x....F|..&.D|
+000000b0 fd 30 b0 fe 0c 84 6f 9a cf 57 |.0....o..W|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 24 58 cc 9f 3f ac |..........$X..?.|
+00000010 2e 20 73 c9 5e 13 d3 12 3a 63 1e a9 ee 13 3d 0d |. s.^...:c....=.|
+00000020 51 e9 15 5b 7b 33 92 85 6c fa d6 8a 15 16 dc 17 |Q..[{3..l.......|
+00000030 03 03 00 21 bc af 01 72 48 0c 16 c9 7a c0 3c 27 |...!...rH...z.<'|
+00000040 63 0a f8 34 e4 54 6a 39 39 61 02 bc c2 a0 07 03 |c..4.Tj99a......|
+00000050 fb 2c d0 1b 6a 15 03 03 00 16 98 71 13 a6 5d f5 |.,..j......q..].|
+00000060 7d aa 6d 05 2d a2 dc c0 7b 41 88 36 a2 49 a4 8b |}.m.-...{A.6.I..|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-RSAPKCS1v15 b/src/crypto/tls/testdata/Server-TLSv12-RSA-RSAPKCS1v15
new file mode 100644
index 0000000..b193771
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-RSAPKCS1v15
@@ -0,0 +1,77 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 59 01 00 00 55 03 03 60 c3 e9 6a 99 |....Y...U..`..j.|
+00000010 72 7a 1c b9 1e 10 4b 9a 82 d5 ea b9 b0 6f 1e 05 |rz....K......o..|
+00000020 74 a4 35 bb 71 c7 d2 56 87 b8 69 00 00 04 cc a8 |t.5.q..V..i.....|
+00000030 00 ff 01 00 00 28 00 0b 00 04 03 00 01 02 00 0a |.....(..........|
+00000040 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 16 |................|
+00000050 00 00 00 17 00 00 00 0d 00 04 00 02 04 01 |..............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 37 02 00 00 33 03 03 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 cc a8 00 00 |...DOWNGRD......|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 03 02 |................|
+00000040 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 |Y...U..R..O0..K0|
+00000050 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 |..............?.|
+00000060 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b |[..0...*.H......|
+00000070 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 |..0.1.0...U....G|
+00000080 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 |o1.0...U....Go R|
+00000090 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 |oot0...160101000|
+000000a0 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 |000Z..2501010000|
+000000b0 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 |00Z0.1.0...U....|
+000000c0 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 |Go1.0...U....Go0|
+000000d0 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......|
+000000e0 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 |.....0.......F}.|
+000000f0 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe |..'.H..(!.~...].|
+00000100 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 |.RE.z6G....B[...|
+00000110 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e |..y.@.Om..+.....|
+00000120 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 |g....."8.J.ts+.4|
+00000130 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 |......t{.X.la<..|
+00000140 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 |A..++$#w[.;.u]. |
+00000150 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 |T..c...$....P...|
+00000160 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 |.C...ub...R.....|
+00000170 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 |....0..0...U....|
+00000180 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 |.......0...U.%..|
+00000190 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 |0...+.........+.|
+000001a0 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff |......0...U.....|
+000001b0 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f |..0.0...U.......|
+000001c0 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 |...CC>I..m....`0|
+000001d0 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d |...U.#..0...H.IM|
+000001e0 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 |.~.1......n{0...|
+000001f0 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 |U....0...example|
+00000200 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 |.golang0...*.H..|
+00000210 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b |...........0.@+[|
+00000220 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 |P.a...SX...(.X..|
+00000230 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b |8....1Z..f=C.-..|
+00000240 f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 |.... d8.$:....}.|
+00000250 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 |@ ._...a..v.....|
+00000260 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d |.\.....l..s..Cw.|
+00000270 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db |......@.a.Lr+...|
+00000280 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d |F..M...>...B...=|
+00000290 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c |.`.\!.;.........|
+000002a0 00 00 a8 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 |...... /.}.G.bC.|
+000002b0 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed |(.._.).0........|
+000002c0 90 99 5f 58 cb 3b 74 04 01 00 80 4e c9 fd 39 89 |.._X.;t....N..9.|
+000002d0 52 c1 6b ba 3b c9 02 35 89 e8 e3 f8 41 15 ee 6d |R.k.;..5....A..m|
+000002e0 f6 08 6d 1a 47 aa 3b 5c 1d 9b 42 9b 50 85 af 56 |..m.G.;\..B.P..V|
+000002f0 a3 99 78 84 7f 06 91 97 e9 33 0d 1d 9b 17 ce 3b |..x......3.....;|
+00000300 30 f2 d0 10 1c b6 e2 7d fd b3 e1 bc 14 7a 1a 96 |0......}.....z..|
+00000310 be b9 dc 0d 29 33 84 5f d1 77 91 0a a1 f2 2b cc |....)3._.w....+.|
+00000320 dc 5e 9b f9 8b e3 34 d2 bd f3 46 b4 0d 97 de 44 |.^....4...F....D|
+00000330 aa 83 10 82 bd ca 83 27 d0 40 a7 b1 64 15 dd 84 |.......'.@..d...|
+00000340 5f 3c d9 62 42 0d 8f a6 19 0f b1 16 03 03 00 04 |_<.bB...........|
+00000350 0e 00 00 00 |....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 82 3a 50 41 f7 b1 |....%...! .:PA..|
+00000010 0f 97 ba 38 04 db f3 a6 ec 8b d1 db 06 c1 84 89 |...8............|
+00000020 a0 53 84 92 27 a2 53 e8 5d 21 14 03 03 00 01 01 |.S..'.S.]!......|
+00000030 16 03 03 00 20 7d 80 6d 7f a9 28 d6 0d 50 d6 b4 |.... }.m..(..P..|
+00000040 24 d3 92 f8 0b 8e 6b d8 7c 64 9e 6c 87 a9 8e 37 |$.....k.|d.l...7|
+00000050 9e 1b 0b 2d a5 |...-.|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 e4 58 cf fb 81 |.......... .X...|
+00000010 be dd 5b 98 97 bd bd 6a f0 76 92 b6 bb 2c 8f a3 |..[....j.v...,..|
+00000020 e5 52 5b 1d f4 17 7b 2a a8 40 26 17 03 03 00 1d |.R[...{*.@&.....|
+00000030 58 ef 4f 1d 98 0f 3d 59 88 df 6e ac c9 37 43 d5 |X.O...=Y..n..7C.|
+00000040 f5 58 b3 7a 62 a3 7d 26 a2 a2 80 23 ef 15 03 03 |.X.zb.}&...#....|
+00000050 00 12 05 b8 57 6a 80 71 b6 a4 58 94 15 f4 2f 0c |....Wj.q..X.../.|
+00000060 8e 76 b2 aa |.v..|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-RSA-RSAPSS b/src/crypto/tls/testdata/Server-TLSv12-RSA-RSAPSS
new file mode 100644
index 0000000..af4c069
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-RSA-RSAPSS
@@ -0,0 +1,77 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 5b 01 00 00 57 03 03 e0 83 fd ef f8 |....[...W.......|
+00000010 cb 41 23 14 36 21 07 eb 4e 01 7d 80 63 e4 b9 45 |.A#.6!..N.}.c..E|
+00000020 f0 84 72 71 9b ac 60 49 6c 70 74 00 00 04 cc a8 |..rq..`Ilpt.....|
+00000030 00 ff 01 00 00 2a 00 0b 00 04 03 00 01 02 00 0a |.....*..........|
+00000040 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 16 |................|
+00000050 00 00 00 17 00 00 00 0d 00 06 00 04 08 06 08 04 |................|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 37 02 00 00 33 03 03 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 cc a8 00 00 |...DOWNGRD......|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 03 02 |................|
+00000040 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 |Y...U..R..O0..K0|
+00000050 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 |..............?.|
+00000060 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b |[..0...*.H......|
+00000070 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 |..0.1.0...U....G|
+00000080 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 |o1.0...U....Go R|
+00000090 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 |oot0...160101000|
+000000a0 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 |000Z..2501010000|
+000000b0 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 |00Z0.1.0...U....|
+000000c0 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 |Go1.0...U....Go0|
+000000d0 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......|
+000000e0 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 |.....0.......F}.|
+000000f0 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe |..'.H..(!.~...].|
+00000100 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 |.RE.z6G....B[...|
+00000110 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e |..y.@.Om..+.....|
+00000120 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 |g....."8.J.ts+.4|
+00000130 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 |......t{.X.la<..|
+00000140 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 |A..++$#w[.;.u]. |
+00000150 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 |T..c...$....P...|
+00000160 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 |.C...ub...R.....|
+00000170 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 |....0..0...U....|
+00000180 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 |.......0...U.%..|
+00000190 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 |0...+.........+.|
+000001a0 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff |......0...U.....|
+000001b0 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f |..0.0...U.......|
+000001c0 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 |...CC>I..m....`0|
+000001d0 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d |...U.#..0...H.IM|
+000001e0 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 |.~.1......n{0...|
+000001f0 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 |U....0...example|
+00000200 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 |.golang0...*.H..|
+00000210 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b |...........0.@+[|
+00000220 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 |P.a...SX...(.X..|
+00000230 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b |8....1Z..f=C.-..|
+00000240 f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 |.... d8.$:....}.|
+00000250 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 |@ ._...a..v.....|
+00000260 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d |.\.....l..s..Cw.|
+00000270 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db |......@.a.Lr+...|
+00000280 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d |F..M...>...B...=|
+00000290 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c |.`.\!.;.........|
+000002a0 00 00 a8 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 |...... /.}.G.bC.|
+000002b0 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed |(.._.).0........|
+000002c0 90 99 5f 58 cb 3b 74 08 04 00 80 58 d3 5f 28 bc |.._X.;t....X._(.|
+000002d0 50 79 b9 3d f1 ac a1 af 52 cd d3 fd e7 75 47 c3 |Py.=....R....uG.|
+000002e0 65 3a 6f 62 22 c2 b5 cc 2b 22 f3 5d 3f b5 b6 9e |e:ob"...+".]?...|
+000002f0 57 bf c7 4e 08 bd fb 5a 17 13 09 1a e9 6c b6 ce |W..N...Z.....l..|
+00000300 b2 0e 88 ae ba a3 a0 b5 2c ff 51 b5 87 95 14 09 |........,.Q.....|
+00000310 6d 9c 73 3f f0 c7 40 6b 4c ca 40 96 d6 44 96 d0 |m.s?..@kL.@..D..|
+00000320 6f b1 a0 1c 4f 66 cc 9b 4f 85 98 3c 03 68 e3 a8 |o...Of..O..<.h..|
+00000330 5b 28 04 fb 1e be 9e 2a 66 c1 6e f1 2e a4 20 08 |[(.....*f.n... .|
+00000340 7e 11 78 7b fc c4 43 af 2a b4 8b 16 03 03 00 04 |~.x{..C.*.......|
+00000350 0e 00 00 00 |....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 e2 54 7d 82 d2 8d |....%...! .T}...|
+00000010 b8 d6 87 17 ec 2a 64 4e 15 6b b0 b3 01 66 b0 7d |.....*dN.k...f.}|
+00000020 73 20 9f cb 30 9d 3c 27 ac 13 14 03 03 00 01 01 |s ..0.<'........|
+00000030 16 03 03 00 20 fa a0 b7 eb ef 49 97 d5 da f0 9d |.... .....I.....|
+00000040 85 a6 e6 67 f3 30 e8 f0 82 3a 7a c4 3f 76 f6 c5 |...g.0...:z.?v..|
+00000050 8f d3 a5 65 f3 |...e.|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 20 6b cf 58 e1 52 |.......... k.X.R|
+00000010 e3 2c 05 e6 a3 05 c1 36 02 f0 90 63 bb 86 0f 54 |.,.....6...c...T|
+00000020 61 d7 1a 31 7d bd 08 00 22 71 09 17 03 03 00 1d |a..1}..."q......|
+00000030 4a 8e 05 28 e3 77 31 43 be ac 32 c6 af f2 7b 1c |J..(.w1C..2...{.|
+00000040 ab 11 7f 32 5a 6a eb 76 ac c6 eb f1 dc 15 03 03 |...2Zj.v........|
+00000050 00 12 3a f1 ee a3 6f bf 9b 9e 5e b8 20 76 84 bc |..:...o...^. v..|
+00000060 1e 2e a0 87 |....|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-Resume b/src/crypto/tls/testdata/Server-TLSv12-Resume
new file mode 100644
index 0000000..456fe2a
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-Resume
@@ -0,0 +1,46 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 01 12 01 00 01 0e 03 03 90 27 78 df 71 |............'x.q|
+00000010 d3 0e ce 1d de ec d2 1b 70 e0 89 da 98 a9 45 3e |........p.....E>|
+00000020 9c ee 93 90 8f 61 d0 a3 b4 a4 5a 20 9d cd d4 81 |.....a....Z ....|
+00000030 e2 c0 59 81 21 bc 9f 2a 84 3e 91 15 3e b9 c0 a1 |..Y.!..*.>..>...|
+00000040 e0 6b 73 9c 45 53 03 ad b9 e6 c2 77 00 04 00 2f |.ks.ES.....w.../|
+00000050 00 ff 01 00 00 c1 00 23 00 81 50 46 ad c1 db a8 |.......#..PF....|
+00000060 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 00 00 |8.{+....B>......|
+00000070 00 00 00 00 00 00 00 00 00 00 94 6f 2c 9f 83 51 |...........o,..Q|
+00000080 ed 14 ef 68 ca 42 c5 4c 75 5e a5 6f d2 49 61 e4 |...h.B.Lu^.o.Ia.|
+00000090 fb 83 46 7c 4c ab f9 c6 d1 3c 9e 5b 8d d8 bc c0 |..F|L....<.[....|
+000000a0 a5 2d 84 db 24 dd a0 16 60 1d 87 a0 52 88 25 6c |.-..$...`...R.%l|
+000000b0 c6 8e 5b 71 0f 74 c3 48 49 38 16 92 8c de 77 bd |..[q.t.HI8....w.|
+000000c0 8a 2b 45 4d 58 86 40 b1 d6 0f 99 de 27 41 b2 41 |.+EMX.@.....'A.A|
+000000d0 27 aa fe 26 e9 24 91 2a 00 ff 08 00 16 00 00 00 |'..&.$.*........|
+000000e0 17 00 00 00 0d 00 30 00 2e 04 03 05 03 06 03 08 |......0.........|
+000000f0 07 08 08 08 09 08 0a 08 0b 08 04 08 05 08 06 04 |................|
+00000100 01 05 01 06 01 03 03 02 03 03 01 02 01 03 02 02 |................|
+00000110 02 04 02 05 02 06 02 |.......|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 51 02 00 00 4d 03 03 00 00 00 00 00 |....Q...M.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 20 9d cd d4 81 |...DOWNGRD. ....|
+00000030 e2 c0 59 81 21 bc 9f 2a 84 3e 91 15 3e b9 c0 a1 |..Y.!..*.>..>...|
+00000040 e0 6b 73 9c 45 53 03 ad b9 e6 c2 77 00 2f 00 00 |.ks.ES.....w./..|
+00000050 05 ff 01 00 01 00 14 03 03 00 01 01 16 03 03 00 |................|
+00000060 40 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |@...............|
+00000070 00 57 8e 5f 0a f6 3f 3b 43 f1 33 bc ef 5e c6 8d |.W._..?;C.3..^..|
+00000080 86 92 58 58 71 51 e8 54 57 96 5f bd 36 3a 9f d3 |..XXqQ.TW._.6:..|
+00000090 e9 27 01 bf fb 6a 05 57 de 2d db b2 79 38 72 95 |.'...j.W.-..y8r.|
+000000a0 fd |.|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 16 03 03 00 40 6d 3c 76 31 a4 |..........@m<v1.|
+00000010 c5 41 d4 67 9f 20 7d 3e f4 35 76 02 ef a2 4b 18 |.A.g. }>.5v...K.|
+00000020 01 f8 a8 83 0c eb 58 f7 d6 93 c6 b6 40 0e c8 24 |......X.....@..$|
+00000030 46 58 0c 79 4a c6 b4 15 65 1e 9c bd ff 51 4d d0 |FX.yJ...e....QM.|
+00000040 44 66 fe c0 98 d5 26 11 98 cf 52 |Df....&...R|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 40 00 00 00 00 00 00 00 00 00 00 00 |....@...........|
+00000010 00 00 00 00 00 4e 8e bd e5 c8 d4 1a 14 00 f1 ed |.....N..........|
+00000020 c4 88 b3 5c 92 b9 ad 8a 68 d4 f3 85 1b 02 25 aa |...\....h.....%.|
+00000030 a0 65 49 08 0d 2a b4 0a 64 eb ea ab 06 73 08 ca |.eI..*..d....s..|
+00000040 62 c9 56 45 a9 15 03 03 00 30 00 00 00 00 00 00 |b.VE.....0......|
+00000050 00 00 00 00 00 00 00 00 00 00 60 51 ae 81 79 6d |..........`Q..ym|
+00000060 91 95 02 42 30 3f c4 3c 2b fc 74 47 a7 a9 17 22 |...B0?.<+.tG..."|
+00000070 88 26 6d 18 b9 8f ad 43 e3 b0 |.&m....C..|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled b/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
new file mode 100644
index 0000000..339fd9a
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-ResumeDisabled
@@ -0,0 +1,91 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 01 12 01 00 01 0e 03 03 b8 aa 9b e6 98 |................|
+00000010 be 93 d6 03 f2 cd 62 23 76 dd 74 6c 48 ac 9a f6 |......b#v.tlH...|
+00000020 f3 27 62 93 6e 99 b2 0d 54 af b7 20 2d 20 97 9a |.'b.n...T.. - ..|
+00000030 c8 88 50 65 95 2a 02 8f 7b 47 77 6d 3c 49 ba a9 |..Pe.*..{Gwm<I..|
+00000040 0c 8a 68 0d b9 30 64 c9 c1 f0 d4 61 00 04 00 2f |..h..0d....a.../|
+00000050 00 ff 01 00 00 c1 00 23 00 81 50 46 ad c1 db a8 |.......#..PF....|
+00000060 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 00 00 |8.{+....B>......|
+00000070 00 00 00 00 00 00 00 00 00 00 94 6f 2c 9f 83 51 |...........o,..Q|
+00000080 ed 14 ef 68 ca 42 c5 4c 20 33 6c 01 97 a5 69 44 |...h.B.L 3l...iD|
+00000090 bf 8f ea db 83 05 fb ef cc 51 1f 0b 4d 44 77 89 |.........Q..MDw.|
+000000a0 11 cf c8 38 16 67 ea a2 3e 8b 2a 18 f2 f7 25 ce |...8.g..>.*...%.|
+000000b0 e0 d8 4c 93 31 b0 59 23 49 38 16 3a f9 63 9e 61 |..L.1.Y#I8.:.c.a|
+000000c0 21 1b ab 67 09 6a 23 07 8e d0 4a 19 78 9c 1e 60 |!..g.j#...J.x..`|
+000000d0 40 a7 83 c5 9a 48 41 35 c4 e9 63 00 16 00 00 00 |@....HA5..c.....|
+000000e0 17 00 00 00 0d 00 30 00 2e 04 03 05 03 06 03 08 |......0.........|
+000000f0 07 08 08 08 09 08 0a 08 0b 08 04 08 05 08 06 04 |................|
+00000100 01 05 01 06 01 03 03 02 03 03 01 02 01 03 02 02 |................|
+00000110 02 04 02 05 02 06 02 |.......|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 31 02 00 00 2d 03 03 00 00 00 00 00 |....1...-.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 00 2f 00 00 |...DOWNGRD.../..|
+00000030 05 ff 01 00 01 00 16 03 03 02 59 0b 00 02 55 00 |..........Y...U.|
+00000040 02 52 00 02 4f 30 82 02 4b 30 82 01 b4 a0 03 02 |.R..O0..K0......|
+00000050 01 02 02 09 00 e8 f0 9d 3f e2 5b ea a6 30 0d 06 |........?.[..0..|
+00000060 09 2a 86 48 86 f7 0d 01 01 0b 05 00 30 1f 31 0b |.*.H........0.1.|
+00000070 30 09 06 03 55 04 0a 13 02 47 6f 31 10 30 0e 06 |0...U....Go1.0..|
+00000080 03 55 04 03 13 07 47 6f 20 52 6f 6f 74 30 1e 17 |.U....Go Root0..|
+00000090 0d 31 36 30 31 30 31 30 30 30 30 30 30 5a 17 0d |.160101000000Z..|
+000000a0 32 35 30 31 30 31 30 30 30 30 30 30 5a 30 1a 31 |250101000000Z0.1|
+000000b0 0b 30 09 06 03 55 04 0a 13 02 47 6f 31 0b 30 09 |.0...U....Go1.0.|
+000000c0 06 03 55 04 03 13 02 47 6f 30 81 9f 30 0d 06 09 |..U....Go0..0...|
+000000d0 2a 86 48 86 f7 0d 01 01 01 05 00 03 81 8d 00 30 |*.H............0|
+000000e0 81 89 02 81 81 00 db 46 7d 93 2e 12 27 06 48 bc |.......F}...'.H.|
+000000f0 06 28 21 ab 7e c4 b6 a2 5d fe 1e 52 45 88 7a 36 |.(!.~...]..RE.z6|
+00000100 47 a5 08 0d 92 42 5b c2 81 c0 be 97 79 98 40 fb |G....B[.....y.@.|
+00000110 4f 6d 14 fd 2b 13 8b c2 a5 2e 67 d8 d4 09 9e d6 |Om..+.....g.....|
+00000120 22 38 b7 4a 0b 74 73 2b c2 34 f1 d1 93 e5 96 d9 |"8.J.ts+.4......|
+00000130 74 7b f3 58 9f 6c 61 3c c0 b0 41 d4 d9 2b 2b 24 |t{.X.la<..A..++$|
+00000140 23 77 5b 1c 3b bd 75 5d ce 20 54 cf a1 63 87 1d |#w[.;.u]. T..c..|
+00000150 1e 24 c4 f3 1d 1a 50 8b aa b6 14 43 ed 97 a7 75 |.$....P....C...u|
+00000160 62 f4 14 c8 52 d7 02 03 01 00 01 a3 81 93 30 81 |b...R.........0.|
+00000170 90 30 0e 06 03 55 1d 0f 01 01 ff 04 04 03 02 05 |.0...U..........|
+00000180 a0 30 1d 06 03 55 1d 25 04 16 30 14 06 08 2b 06 |.0...U.%..0...+.|
+00000190 01 05 05 07 03 01 06 08 2b 06 01 05 05 07 03 02 |........+.......|
+000001a0 30 0c 06 03 55 1d 13 01 01 ff 04 02 30 00 30 19 |0...U.......0.0.|
+000001b0 06 03 55 1d 0e 04 12 04 10 9f 91 16 1f 43 43 3e |..U..........CC>|
+000001c0 49 a6 de 6d b6 80 d7 9f 60 30 1b 06 03 55 1d 23 |I..m....`0...U.#|
+000001d0 04 14 30 12 80 10 48 13 49 4d 13 7e 16 31 bb a3 |..0...H.IM.~.1..|
+000001e0 01 d5 ac ab 6e 7b 30 19 06 03 55 1d 11 04 12 30 |....n{0...U....0|
+000001f0 10 82 0e 65 78 61 6d 70 6c 65 2e 67 6f 6c 61 6e |...example.golan|
+00000200 67 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b 05 00 |g0...*.H........|
+00000210 03 81 81 00 9d 30 cc 40 2b 5b 50 a0 61 cb ba e5 |.....0.@+[P.a...|
+00000220 53 58 e1 ed 83 28 a9 58 1a a9 38 a4 95 a1 ac 31 |SX...(.X..8....1|
+00000230 5a 1a 84 66 3d 43 d3 2d d9 0b f2 97 df d3 20 64 |Z..f=C.-...... d|
+00000240 38 92 24 3a 00 bc cf 9c 7d b7 40 20 01 5f aa d3 |8.$:....}.@ ._..|
+00000250 16 61 09 a2 76 fd 13 c3 cc e1 0c 5c ee b1 87 82 |.a..v......\....|
+00000260 f1 6c 04 ed 73 bb b3 43 77 8d 0c 1c f1 0f a1 d8 |.l..s..Cw.......|
+00000270 40 83 61 c9 4c 72 2b 9d ae db 46 06 06 4d f4 c1 |@.a.Lr+...F..M..|
+00000280 b3 3e c0 d1 bd 42 d4 db fe 3d 13 60 84 5c 21 d3 |.>...B...=.`.\!.|
+00000290 3b e9 fa e7 16 03 03 00 04 0e 00 00 00 |;............|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 1f e2 43 ee 88 |.............C..|
+00000010 22 0d a0 66 18 ce 8a 04 d1 00 fc 2b 6b 93 d5 b6 |"..f.......+k...|
+00000020 fd 13 48 fd ea 19 d8 5d 02 bf 8c d9 fb 64 e8 17 |..H....].....d..|
+00000030 a3 49 dc 1d 4d b7 8c eb 7d 8b 1d 13 20 78 4e 02 |.I..M...}... xN.|
+00000040 49 7e a5 bd dd 57 ac 45 47 e6 ea 2e 87 6f d2 ca |I~...W.EG....o..|
+00000050 e6 ef a4 9e 2d 3a 02 22 2e 67 6f ff 2d 78 6c 7d |....-:.".go.-xl}|
+00000060 33 a1 4c 5b ec d5 ae cb 4f db c0 7d 75 01 61 fa |3.L[....O..}u.a.|
+00000070 c2 8a dc 75 77 51 60 90 5d 35 45 ca 13 bb 1a c4 |...uwQ`.]5E.....|
+00000080 eb f3 74 ef 77 ec 23 ec 98 30 3c 14 03 03 00 01 |..t.w.#..0<.....|
+00000090 01 16 03 03 00 40 7a 07 bc 74 d3 6f ef 93 22 69 |.....@z..t.o.."i|
+000000a0 a8 05 df df db 5e 58 1e 4b 84 4f 20 7c f5 2c c3 |.....^X.K.O |.,.|
+000000b0 0d 51 0a a8 d0 a8 f0 07 02 d5 ca ec f2 4b 3f ef |.Q...........K?.|
+000000c0 c9 57 cb 9b 26 2e 62 e7 f2 84 6e ed b9 6e 1d 15 |.W..&.b...n..n..|
+000000d0 32 8c d6 b8 0d 8a |2.....|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 67 e1 22 17 24 |...........g.".$|
+00000020 95 b4 e5 62 59 15 56 4a af e4 82 76 ad b7 48 81 |...bY.VJ...v..H.|
+00000030 cf 55 d1 75 cd 36 86 0d 9d 15 24 4b 84 23 bc 98 |.U.u.6....$K.#..|
+00000040 8e c4 62 57 ab 96 0c 27 5d 1c 07 17 03 03 00 40 |..bW...']......@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 c9 b2 0e 04 40 43 26 92 91 45 e3 63 d7 49 09 3e |....@C&..E.c.I.>|
+00000070 03 45 e3 d6 af a2 d8 d9 61 36 e5 95 83 75 66 fa |.E......a6...uf.|
+00000080 90 c2 80 53 a2 d5 31 aa b1 2a da 45 a9 b3 aa 1f |...S..1..*.E....|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 c4 52 cf b9 f6 0f e2 30 ba 90 18 |......R.....0...|
+000000b0 0c 76 c2 ee 4c 78 fb c2 cb 34 7f cb 35 15 5e b0 |.v..Lx...4..5.^.|
+000000c0 17 70 cb 76 8a |.p.v.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-SNI b/src/crypto/tls/testdata/Server-TLSv12-SNI
new file mode 100644
index 0000000..0ea8375
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-SNI
@@ -0,0 +1,84 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 99 01 00 00 95 03 03 fb d6 71 b2 32 |.............q.2|
+00000010 74 6c e1 56 19 42 e6 46 a2 0e 37 1f ad 96 4b af |tl.V.B.F..7...K.|
+00000020 8b 4c aa 71 2a 53 d8 df 74 7d 39 00 00 04 00 2f |.L.q*S..t}9..../|
+00000030 00 ff 01 00 00 68 00 00 00 10 00 0e 00 00 0b 73 |.....h.........s|
+00000040 6e 69 74 65 73 74 2e 63 6f 6d 00 0b 00 04 03 00 |nitest.com......|
+00000050 01 02 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 |................|
+00000060 00 18 00 16 00 00 00 17 00 00 00 0d 00 30 00 2e |.............0..|
+00000070 04 03 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b |................|
+00000080 08 04 08 05 08 06 04 01 05 01 06 01 03 03 02 03 |................|
+00000090 03 01 02 01 03 02 02 02 04 02 05 02 06 02 |..............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 37 02 00 00 33 03 03 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 00 2f 00 00 |...DOWNGRD.../..|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 03 02 |................|
+00000040 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 |Y...U..R..O0..K0|
+00000050 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 |..............?.|
+00000060 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b |[..0...*.H......|
+00000070 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 |..0.1.0...U....G|
+00000080 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 |o1.0...U....Go R|
+00000090 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 |oot0...160101000|
+000000a0 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 |000Z..2501010000|
+000000b0 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 |00Z0.1.0...U....|
+000000c0 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 |Go1.0...U....Go0|
+000000d0 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......|
+000000e0 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 |.....0.......F}.|
+000000f0 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe |..'.H..(!.~...].|
+00000100 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 |.RE.z6G....B[...|
+00000110 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e |..y.@.Om..+.....|
+00000120 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 |g....."8.J.ts+.4|
+00000130 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 |......t{.X.la<..|
+00000140 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 |A..++$#w[.;.u]. |
+00000150 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 |T..c...$....P...|
+00000160 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 |.C...ub...R.....|
+00000170 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 |....0..0...U....|
+00000180 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 |.......0...U.%..|
+00000190 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 |0...+.........+.|
+000001a0 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff |......0...U.....|
+000001b0 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f |..0.0...U.......|
+000001c0 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 |...CC>I..m....`0|
+000001d0 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d |...U.#..0...H.IM|
+000001e0 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 |.~.1......n{0...|
+000001f0 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 |U....0...example|
+00000200 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 |.golang0...*.H..|
+00000210 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b |...........0.@+[|
+00000220 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 |P.a...SX...(.X..|
+00000230 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b |8....1Z..f=C.-..|
+00000240 f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 |.... d8.$:....}.|
+00000250 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 |@ ._...a..v.....|
+00000260 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d |.\.....l..s..Cw.|
+00000270 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db |......@.a.Lr+...|
+00000280 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d |F..M...>...B...=|
+00000290 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 04 0e |.`.\!.;.........|
+000002a0 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 a4 48 88 75 7b |............H.u{|
+00000010 a2 04 19 14 69 30 12 d6 14 00 0c 44 e4 68 06 c6 |....i0.....D.h..|
+00000020 11 56 53 0c e5 52 fb 84 e2 6e b7 c6 eb 0d 79 25 |.VS..R...n....y%|
+00000030 19 f0 bf e4 51 73 85 d5 82 5a 07 53 b2 65 97 6a |....Qs...Z.S.e.j|
+00000040 a1 1b 56 bb 23 35 15 83 0f 60 ee de 16 a2 ea 61 |..V.#5...`.....a|
+00000050 23 10 e1 5e cf 73 fe 5d 5a 53 16 42 0c 29 a5 ff |#..^.s.]ZS.B.)..|
+00000060 06 e5 c4 87 11 d6 24 91 25 e5 58 81 40 80 9e 71 |......$.%.X.@..q|
+00000070 49 40 47 50 37 28 7b ed 76 cc 5a fb 04 ba 9c f8 |I@GP7({.v.Z.....|
+00000080 be ce 87 07 75 d2 30 88 09 cf bc 14 03 03 00 01 |....u.0.........|
+00000090 01 16 03 03 00 40 60 1c 31 95 7d c2 a9 9b 29 c2 |.....@`.1.}...).|
+000000a0 ef 59 58 dd fb 26 34 81 60 dc 17 19 c1 23 8d 8f |.YX..&4.`....#..|
+000000b0 a8 d2 62 31 96 3d d2 61 b9 c8 7e bf 47 4c 04 fd |..b1.=.a..~.GL..|
+000000c0 7c 30 05 37 8e 03 df 13 a1 4d f1 81 05 d7 4c 49 ||0.7.....M....LI|
+000000d0 88 d6 c0 21 52 e3 |...!R.|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 73 15 54 76 ad |...........s.Tv.|
+00000020 c4 38 b0 40 45 32 a8 ca 05 19 bd ce 6e 39 77 6b |.8.@E2......n9wk|
+00000030 46 a7 f8 45 a8 cd cd 98 8c aa cf 46 83 f0 20 93 |F..E.......F.. .|
+00000040 0d 18 99 d4 2a f9 15 4a 2b f6 bf 17 03 03 00 40 |....*..J+......@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 79 8d 24 ef 72 b3 2c e2 10 a5 6d 3d 61 6c df c1 |y.$.r.,...m=al..|
+00000070 26 bf 7e b5 cd b2 8e 87 b9 54 bf ee 35 07 bc 55 |&.~......T..5..U|
+00000080 6c cd a2 d3 b4 bb 8c 63 fd ef b1 f0 2f 6d aa d9 |l......c..../m..|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 7b f7 81 e6 5c f2 5c 9d 45 ec 1f |.....{...\.\.E..|
+000000b0 7b 0d f8 62 19 d4 83 a8 e5 90 71 03 6e 6a 72 4b |{..b......q.njrK|
+000000c0 7e 64 c4 c4 1a |~d...|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate b/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate
new file mode 100644
index 0000000..199253f
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificate
@@ -0,0 +1,84 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 99 01 00 00 95 03 03 cf 09 e7 0d ce |................|
+00000010 ce d4 72 66 9d 30 e8 ee 39 b3 95 4c 3b 59 25 66 |..rf.0..9..L;Y%f|
+00000020 d2 f5 d3 82 68 7d e7 26 2e 38 97 00 00 04 00 2f |....h}.&.8...../|
+00000030 00 ff 01 00 00 68 00 00 00 10 00 0e 00 00 0b 73 |.....h.........s|
+00000040 6e 69 74 65 73 74 2e 63 6f 6d 00 0b 00 04 03 00 |nitest.com......|
+00000050 01 02 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 |................|
+00000060 00 18 00 16 00 00 00 17 00 00 00 0d 00 30 00 2e |.............0..|
+00000070 04 03 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b |................|
+00000080 08 04 08 05 08 06 04 01 05 01 06 01 03 03 02 03 |................|
+00000090 03 01 02 01 03 02 02 02 04 02 05 02 06 02 |..............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 37 02 00 00 33 03 03 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 00 2f 00 00 |...DOWNGRD.../..|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 03 02 |................|
+00000040 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 |Y...U..R..O0..K0|
+00000050 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 |..............?.|
+00000060 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b |[..0...*.H......|
+00000070 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 |..0.1.0...U....G|
+00000080 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 |o1.0...U....Go R|
+00000090 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 |oot0...160101000|
+000000a0 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 |000Z..2501010000|
+000000b0 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 |00Z0.1.0...U....|
+000000c0 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 |Go1.0...U....Go0|
+000000d0 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......|
+000000e0 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 |.....0.......F}.|
+000000f0 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe |..'.H..(!.~...].|
+00000100 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 |.RE.z6G....B[...|
+00000110 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e |..y.@.Om..+.....|
+00000120 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 |g....."8.J.ts+.4|
+00000130 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 |......t{.X.la<..|
+00000140 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 |A..++$#w[.;.u]. |
+00000150 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 |T..c...$....P...|
+00000160 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 |.C...ub...R.....|
+00000170 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 |....0..0...U....|
+00000180 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 |.......0...U.%..|
+00000190 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 |0...+.........+.|
+000001a0 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff |......0...U.....|
+000001b0 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f |..0.0...U.......|
+000001c0 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 |...CC>I..m....`0|
+000001d0 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d |...U.#..0...H.IM|
+000001e0 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 |.~.1......n{0...|
+000001f0 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 |U....0...example|
+00000200 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 |.golang0...*.H..|
+00000210 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b |...........0.@+[|
+00000220 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 |P.a...SX...(.X..|
+00000230 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b |8....1Z..f=C.-..|
+00000240 f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 |.... d8.$:....}.|
+00000250 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 |@ ._...a..v.....|
+00000260 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d |.\.....l..s..Cw.|
+00000270 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db |......@.a.Lr+...|
+00000280 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d |F..M...>...B...=|
+00000290 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 04 0e |.`.\!.;.........|
+000002a0 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 04 57 b2 56 f0 |............W.V.|
+00000010 a5 fb c3 4d 4e 7d ba 29 18 04 ea 6e 66 d3 97 68 |...MN}.)...nf..h|
+00000020 58 4e c1 47 fe 30 42 4d bf 5b 10 38 6a 01 83 98 |XN.G.0BM.[.8j...|
+00000030 2b e3 3a ac c8 67 e5 41 0c 5c 3f 88 d5 15 a2 ab |+.:..g.A.\?.....|
+00000040 6a 2b 70 24 d8 40 78 c1 d9 58 78 04 4d 90 03 eb |j+p$.@x..Xx.M...|
+00000050 3c b1 61 da 26 62 db b3 41 ab dc 94 22 44 66 b8 |<.a.&b..A..."Df.|
+00000060 49 2c fa 59 de c0 69 3c 20 f8 2f a5 e0 47 1d ec |I,.Y..i< ./..G..|
+00000070 3c 49 2d 39 f6 41 09 06 79 5f 26 c4 12 3d 9c 8d |<I-9.A..y_&..=..|
+00000080 16 7b 45 25 65 01 69 9c a8 f7 90 14 03 03 00 01 |.{E%e.i.........|
+00000090 01 16 03 03 00 40 96 71 33 e6 7e 26 2c 52 9b a5 |.....@.q3.~&,R..|
+000000a0 b3 d2 4e a3 6a 8f 9f 2a ec c6 23 51 6c 92 5d dd |..N.j..*..#Ql.].|
+000000b0 6e dd f2 5f 28 5e 8d e4 1f 80 35 16 84 59 0f 36 |n.._(^....5..Y.6|
+000000c0 ce a4 36 16 18 09 a8 30 8b 73 f6 22 0a 8f 22 28 |..6....0.s.".."(|
+000000d0 00 62 d2 8e 19 82 |.b....|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 5e ea d1 03 d7 |...........^....|
+00000020 de 82 9a b4 07 52 46 16 fd 28 86 fe 17 2e 77 52 |.....RF..(....wR|
+00000030 67 8f ec 64 93 1e 8e c9 fc fb 69 61 47 78 1a 1b |g..d......iaGx..|
+00000040 97 8d fc 56 76 f6 53 8b 62 53 4f 17 03 03 00 40 |...Vv.S.bSO....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 f8 17 e8 ba c4 fb 0b 76 f5 a8 2d 3c 48 44 73 da |.......v..-<HDs.|
+00000070 dc 34 5d fe e4 23 85 28 38 df 1d fe c6 a6 32 35 |.4]..#.(8.....25|
+00000080 c6 bb 71 4a 6e ec e7 c4 4f e6 28 2b fc 06 5e ac |..qJn...O.(+..^.|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 b0 5a ef 20 24 de e4 16 ad 7e 54 |......Z. $....~T|
+000000b0 43 d1 22 a8 fb a6 a4 98 54 74 58 2d 5c af 34 24 |C.".....TtX-\.4$|
+000000c0 89 d1 ab 32 8b |...2.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound b/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound
new file mode 100644
index 0000000..870e8fa
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-SNI-GetCertificateNotFound
@@ -0,0 +1,84 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 99 01 00 00 95 03 03 34 7d 89 eb 2a |...........4}..*|
+00000010 19 64 32 17 5d 37 0e dd 51 2c 7e 08 56 47 f3 2c |.d2.]7..Q,~.VG.,|
+00000020 ca d0 08 51 86 a6 a3 10 85 5a 41 00 00 04 00 2f |...Q.....ZA..../|
+00000030 00 ff 01 00 00 68 00 00 00 10 00 0e 00 00 0b 73 |.....h.........s|
+00000040 6e 69 74 65 73 74 2e 63 6f 6d 00 0b 00 04 03 00 |nitest.com......|
+00000050 01 02 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 |................|
+00000060 00 18 00 16 00 00 00 17 00 00 00 0d 00 30 00 2e |.............0..|
+00000070 04 03 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b |................|
+00000080 08 04 08 05 08 06 04 01 05 01 06 01 03 03 02 03 |................|
+00000090 03 01 02 01 03 02 02 02 04 02 05 02 06 02 |..............|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 37 02 00 00 33 03 03 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 00 2f 00 00 |...DOWNGRD.../..|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 03 02 |................|
+00000040 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 |Y...U..R..O0..K0|
+00000050 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 |..............?.|
+00000060 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b |[..0...*.H......|
+00000070 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 |..0.1.0...U....G|
+00000080 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 |o1.0...U....Go R|
+00000090 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 |oot0...160101000|
+000000a0 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 |000Z..2501010000|
+000000b0 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 |00Z0.1.0...U....|
+000000c0 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 |Go1.0...U....Go0|
+000000d0 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......|
+000000e0 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 |.....0.......F}.|
+000000f0 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe |..'.H..(!.~...].|
+00000100 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 |.RE.z6G....B[...|
+00000110 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e |..y.@.Om..+.....|
+00000120 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 |g....."8.J.ts+.4|
+00000130 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 |......t{.X.la<..|
+00000140 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 |A..++$#w[.;.u]. |
+00000150 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 |T..c...$....P...|
+00000160 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 |.C...ub...R.....|
+00000170 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 |....0..0...U....|
+00000180 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 |.......0...U.%..|
+00000190 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 |0...+.........+.|
+000001a0 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff |......0...U.....|
+000001b0 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f |..0.0...U.......|
+000001c0 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 |...CC>I..m....`0|
+000001d0 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d |...U.#..0...H.IM|
+000001e0 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 |.~.1......n{0...|
+000001f0 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 |U....0...example|
+00000200 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 |.golang0...*.H..|
+00000210 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b |...........0.@+[|
+00000220 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 |P.a...SX...(.X..|
+00000230 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b |8....1Z..f=C.-..|
+00000240 f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 |.... d8.$:....}.|
+00000250 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 |@ ._...a..v.....|
+00000260 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d |.\.....l..s..Cw.|
+00000270 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db |......@.a.Lr+...|
+00000280 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d |F..M...>...B...=|
+00000290 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 04 0e |.`.\!.;.........|
+000002a0 00 00 00 |...|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 86 10 00 00 82 00 80 38 86 92 3e 9a |...........8..>.|
+00000010 54 2d 44 46 76 d1 7c 07 04 83 2f 19 6d 89 c6 95 |T-DFv.|.../.m...|
+00000020 07 63 17 7d ac e5 f7 95 7f f7 f2 3a f6 eb 38 26 |.c.}.......:..8&|
+00000030 e5 c9 32 b1 27 88 46 85 f8 f6 eb 27 a8 9e de 5b |..2.'.F....'...[|
+00000040 92 f7 3f 03 be 73 f0 de 2e b4 44 a8 89 4a 5a 6f |..?..s....D..JZo|
+00000050 dc e7 16 9c dc f7 9f ca 40 9e 34 4b c2 45 58 7a |........@.4K.EXz|
+00000060 6d 5c 4c 58 6a 45 10 21 fb b5 2a 58 17 7d d9 c4 |m\LXjE.!..*X.}..|
+00000070 c9 7d d1 3b df 39 1b 59 6a 49 18 e1 fd 02 a2 1d |.}.;.9.YjI......|
+00000080 5a 2d 3d c5 ab e7 f6 60 0d aa 38 14 03 03 00 01 |Z-=....`..8.....|
+00000090 01 16 03 03 00 40 0e 2a fd e7 cd d0 72 ce 06 5c |.....@.*....r..\|
+000000a0 40 c1 81 ef eb 27 e9 77 a8 d4 cc 5c 1e 15 7c 62 |@....'.w...\..|b|
+000000b0 87 bd c5 8e b4 e6 6a 3f be 37 9d c0 fe f7 65 8b |......j?.7....e.|
+000000c0 b1 3a b8 b4 76 67 ca 58 1c f5 3f f1 10 7c 5b 57 |.:..vg.X..?..|[W|
+000000d0 90 e6 43 de d6 25 |..C..%|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 40 00 00 00 00 00 |..........@.....|
+00000010 00 00 00 00 00 00 00 00 00 00 00 8b 11 9a 67 af |..............g.|
+00000020 5b 0e c9 01 dc 76 e8 48 2f 40 5c 76 13 ca 28 63 |[....v.H/@\v..(c|
+00000030 a9 6d 3c 6b c1 d4 79 4d 39 17 55 a5 b9 0e b6 fd |.m<k..yM9.U.....|
+00000040 9b 1a 8c 62 98 34 3c 85 b9 2b 40 17 03 03 00 40 |...b.4<..+@....@|
+00000050 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000060 5e 82 20 cb bc 9a fd 36 13 3d aa 1b d6 72 df cb |^. ....6.=...r..|
+00000070 09 e1 2f 85 6c 99 12 36 73 f3 c7 44 47 d7 60 19 |../.l..6s..DG.`.|
+00000080 2e 59 23 7d fa 16 b9 64 40 ed 96 79 66 b7 97 4c |.Y#}...d@..yf..L|
+00000090 15 03 03 00 30 00 00 00 00 00 00 00 00 00 00 00 |....0...........|
+000000a0 00 00 00 00 00 88 a2 85 5b 80 7d ee 4a 63 be da |........[.}.Jc..|
+000000b0 e4 8f cd 6f 1d f4 03 da ee 7c 29 2b d0 2d 3e 1c |...o.....|)+.->.|
+000000c0 b2 ea 47 71 1f |..Gq.|
diff --git a/src/crypto/tls/testdata/Server-TLSv12-X25519 b/src/crypto/tls/testdata/Server-TLSv12-X25519
new file mode 100644
index 0000000..c196336
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv12-X25519
@@ -0,0 +1,82 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 8f 01 00 00 8b 03 03 5d ff d6 27 db |...........]..'.|
+00000010 3b e5 2b 79 3a a6 cf 75 3d f7 c9 d9 0a d4 8c b2 |;.+y:..u=.......|
+00000020 af 3c 29 84 65 a2 d6 98 52 e2 eb 00 00 04 c0 2f |.<).e...R....../|
+00000030 00 ff 01 00 00 5e 00 00 00 0e 00 0c 00 00 09 31 |.....^.........1|
+00000040 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
+00000050 00 0a 00 04 00 02 00 1d 00 16 00 00 00 17 00 00 |................|
+00000060 00 0d 00 30 00 2e 04 03 05 03 06 03 08 07 08 08 |...0............|
+00000070 08 09 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 |................|
+00000080 06 01 03 03 02 03 03 01 02 01 03 02 02 02 04 02 |................|
+00000090 05 02 06 02 |....|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 37 02 00 00 33 03 03 00 00 00 00 00 |....7...3.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 44 4f 57 4e 47 52 44 01 00 c0 2f 00 00 |...DOWNGRD.../..|
+00000030 0b ff 01 00 01 00 00 0b 00 02 01 00 16 03 03 02 |................|
+00000040 59 0b 00 02 55 00 02 52 00 02 4f 30 82 02 4b 30 |Y...U..R..O0..K0|
+00000050 82 01 b4 a0 03 02 01 02 02 09 00 e8 f0 9d 3f e2 |..............?.|
+00000060 5b ea a6 30 0d 06 09 2a 86 48 86 f7 0d 01 01 0b |[..0...*.H......|
+00000070 05 00 30 1f 31 0b 30 09 06 03 55 04 0a 13 02 47 |..0.1.0...U....G|
+00000080 6f 31 10 30 0e 06 03 55 04 03 13 07 47 6f 20 52 |o1.0...U....Go R|
+00000090 6f 6f 74 30 1e 17 0d 31 36 30 31 30 31 30 30 30 |oot0...160101000|
+000000a0 30 30 30 5a 17 0d 32 35 30 31 30 31 30 30 30 30 |000Z..2501010000|
+000000b0 30 30 5a 30 1a 31 0b 30 09 06 03 55 04 0a 13 02 |00Z0.1.0...U....|
+000000c0 47 6f 31 0b 30 09 06 03 55 04 03 13 02 47 6f 30 |Go1.0...U....Go0|
+000000d0 81 9f 30 0d 06 09 2a 86 48 86 f7 0d 01 01 01 05 |..0...*.H.......|
+000000e0 00 03 81 8d 00 30 81 89 02 81 81 00 db 46 7d 93 |.....0.......F}.|
+000000f0 2e 12 27 06 48 bc 06 28 21 ab 7e c4 b6 a2 5d fe |..'.H..(!.~...].|
+00000100 1e 52 45 88 7a 36 47 a5 08 0d 92 42 5b c2 81 c0 |.RE.z6G....B[...|
+00000110 be 97 79 98 40 fb 4f 6d 14 fd 2b 13 8b c2 a5 2e |..y.@.Om..+.....|
+00000120 67 d8 d4 09 9e d6 22 38 b7 4a 0b 74 73 2b c2 34 |g....."8.J.ts+.4|
+00000130 f1 d1 93 e5 96 d9 74 7b f3 58 9f 6c 61 3c c0 b0 |......t{.X.la<..|
+00000140 41 d4 d9 2b 2b 24 23 77 5b 1c 3b bd 75 5d ce 20 |A..++$#w[.;.u]. |
+00000150 54 cf a1 63 87 1d 1e 24 c4 f3 1d 1a 50 8b aa b6 |T..c...$....P...|
+00000160 14 43 ed 97 a7 75 62 f4 14 c8 52 d7 02 03 01 00 |.C...ub...R.....|
+00000170 01 a3 81 93 30 81 90 30 0e 06 03 55 1d 0f 01 01 |....0..0...U....|
+00000180 ff 04 04 03 02 05 a0 30 1d 06 03 55 1d 25 04 16 |.......0...U.%..|
+00000190 30 14 06 08 2b 06 01 05 05 07 03 01 06 08 2b 06 |0...+.........+.|
+000001a0 01 05 05 07 03 02 30 0c 06 03 55 1d 13 01 01 ff |......0...U.....|
+000001b0 04 02 30 00 30 19 06 03 55 1d 0e 04 12 04 10 9f |..0.0...U.......|
+000001c0 91 16 1f 43 43 3e 49 a6 de 6d b6 80 d7 9f 60 30 |...CC>I..m....`0|
+000001d0 1b 06 03 55 1d 23 04 14 30 12 80 10 48 13 49 4d |...U.#..0...H.IM|
+000001e0 13 7e 16 31 bb a3 01 d5 ac ab 6e 7b 30 19 06 03 |.~.1......n{0...|
+000001f0 55 1d 11 04 12 30 10 82 0e 65 78 61 6d 70 6c 65 |U....0...example|
+00000200 2e 67 6f 6c 61 6e 67 30 0d 06 09 2a 86 48 86 f7 |.golang0...*.H..|
+00000210 0d 01 01 0b 05 00 03 81 81 00 9d 30 cc 40 2b 5b |...........0.@+[|
+00000220 50 a0 61 cb ba e5 53 58 e1 ed 83 28 a9 58 1a a9 |P.a...SX...(.X..|
+00000230 38 a4 95 a1 ac 31 5a 1a 84 66 3d 43 d3 2d d9 0b |8....1Z..f=C.-..|
+00000240 f2 97 df d3 20 64 38 92 24 3a 00 bc cf 9c 7d b7 |.... d8.$:....}.|
+00000250 40 20 01 5f aa d3 16 61 09 a2 76 fd 13 c3 cc e1 |@ ._...a..v.....|
+00000260 0c 5c ee b1 87 82 f1 6c 04 ed 73 bb b3 43 77 8d |.\.....l..s..Cw.|
+00000270 0c 1c f1 0f a1 d8 40 83 61 c9 4c 72 2b 9d ae db |......@.a.Lr+...|
+00000280 46 06 06 4d f4 c1 b3 3e c0 d1 bd 42 d4 db fe 3d |F..M...>...B...=|
+00000290 13 60 84 5c 21 d3 3b e9 fa e7 16 03 03 00 ac 0c |.`.\!.;.........|
+000002a0 00 00 a8 03 00 1d 20 2f e5 7d a3 47 cd 62 43 15 |...... /.}.G.bC.|
+000002b0 28 da ac 5f bb 29 07 30 ff f6 84 af c4 cf c2 ed |(.._.).0........|
+000002c0 90 99 5f 58 cb 3b 74 08 04 00 80 73 d6 a4 35 5f |.._X.;t....s..5_|
+000002d0 3f 46 ad de 81 13 a8 d9 21 17 25 37 61 cb 62 0d |?F......!.%7a.b.|
+000002e0 e2 bf 95 51 0e 9e e7 b1 ab bc be f6 ec 80 b1 f4 |...Q............|
+000002f0 3e 9c 69 3f c8 1e a4 02 82 fd 57 01 e7 0c 18 be |>.i?......W.....|
+00000300 c6 1b 01 68 cb ef dc d8 16 92 fb 1b 07 fd 98 f8 |...h............|
+00000310 00 77 a9 8e 71 2a e0 6c 68 d5 83 f9 36 c3 3b 99 |.w..q*.lh...6.;.|
+00000320 44 98 a0 96 00 1a 02 95 c5 7c ea ae 51 81 89 94 |D........|..Q...|
+00000330 57 b6 37 c5 88 56 9f 49 bf 36 26 48 08 36 a1 69 |W.7..V.I.6&H.6.i|
+00000340 48 a2 c4 b2 6f 0f 43 70 91 1e 8a 16 03 03 00 04 |H...o.Cp........|
+00000350 0e 00 00 00 |....|
+>>> Flow 3 (client to server)
+00000000 16 03 03 00 25 10 00 00 21 20 0a 1b 78 c4 bb eb |....%...! ..x...|
+00000010 a4 01 33 3b 69 95 c2 06 5d c9 3e b3 13 51 4b 93 |..3;i...].>..QK.|
+00000020 5e 3c 3e a7 42 12 22 e8 7e 49 14 03 03 00 01 01 |^<>.B.".~I......|
+00000030 16 03 03 00 28 fc c7 a1 45 50 e0 fe 27 fd ac a4 |....(...EP..'...|
+00000040 d8 a2 c6 54 df e1 d3 6f e7 d8 45 a6 57 16 2f 1f |...T...o..E.W./.|
+00000050 cf 89 26 c6 0a c3 4f 63 df ac bc c9 79 |..&...Oc....y|
+>>> Flow 4 (server to client)
+00000000 14 03 03 00 01 01 16 03 03 00 28 00 00 00 00 00 |..........(.....|
+00000010 00 00 00 37 25 28 76 4e 31 dd 5e b0 5b 39 87 fc |...7%(vN1.^.[9..|
+00000020 0f 10 3c bc 6d 12 9a dd 59 89 0b 09 bc f2 2c d8 |..<.m...Y.....,.|
+00000030 05 a7 77 17 03 03 00 25 00 00 00 00 00 00 00 01 |..w....%........|
+00000040 fe 79 9d dd d9 e3 bc 48 47 65 30 64 c7 74 82 0a |.y.....HGe0d.t..|
+00000050 9f b7 45 a2 62 40 b5 dd 79 b9 ce 06 83 15 03 03 |..E.b@..y.......|
+00000060 00 1a 00 00 00 00 00 00 00 02 58 ed 37 40 33 e4 |..........X.7@3.|
+00000070 75 f0 a6 fa 14 f5 6b 93 9e 54 f2 a4 |u.....k..T..|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-AES128-SHA256 b/src/crypto/tls/testdata/Server-TLSv13-AES128-SHA256
new file mode 100644
index 0000000..a071f60
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-AES128-SHA256
@@ -0,0 +1,100 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 dc 01 00 00 d8 03 03 5f b5 79 18 5f |..........._.y._|
+00000010 d2 f8 b0 fc da 39 90 af e1 ba 04 b5 70 86 c3 6b |.....9......p..k|
+00000020 ba b4 87 e3 81 9a 86 02 9b 26 44 20 21 e3 5b 03 |.........&D !.[.|
+00000030 0d 0a 6c 1f 71 ea b4 4c 56 aa b6 d1 e8 91 d6 7b |..l.q..LV......{|
+00000040 59 12 63 af db d2 69 80 cd 5f 62 22 00 04 13 01 |Y.c...i.._b"....|
+00000050 00 ff 01 00 00 8b 00 00 00 0e 00 0c 00 00 09 31 |...............1|
+00000060 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
+00000070 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 |................|
+00000080 00 16 00 00 00 17 00 00 00 0d 00 1e 00 1c 04 03 |................|
+00000090 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 |................|
+000000a0 08 05 08 06 04 01 05 01 06 01 00 2b 00 03 02 03 |...........+....|
+000000b0 04 00 2d 00 02 01 01 00 33 00 26 00 24 00 1d 00 |..-.....3.&.$...|
+000000c0 20 57 12 bc 06 e0 46 c7 75 43 b8 af f9 c1 f6 b8 | W....F.uC......|
+000000d0 e4 1e 13 6b 02 07 23 d2 e6 89 ec 18 ab c0 9f ae |...k..#.........|
+000000e0 69 |i|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 21 e3 5b 03 |........... !.[.|
+00000030 0d 0a 6c 1f 71 ea b4 4c 56 aa b6 d1 e8 91 d6 7b |..l.q..LV......{|
+00000040 59 12 63 af db d2 69 80 cd 5f 62 22 13 01 00 00 |Y.c...i.._b"....|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 17 be 8f 95 d9 22 d7 |..............".|
+00000090 f7 ff 75 78 b6 9c bc 93 23 2f 76 62 c6 cd c6 92 |..ux....#/vb....|
+000000a0 fe 17 03 03 02 6d 31 54 c9 32 d0 38 53 8f f0 15 |.....m1T.2.8S...|
+000000b0 03 42 16 39 71 61 f9 17 f2 da c5 2e 4c 19 c3 30 |.B.9qa......L..0|
+000000c0 d5 c6 b8 ea 5d 3b 47 1b d9 20 31 64 ab 5c f3 00 |....];G.. 1d.\..|
+000000d0 43 5b e7 3b 36 69 12 c9 3b 3d e7 4f 91 72 e4 29 |C[.;6i..;=.O.r.)|
+000000e0 93 54 65 50 88 07 b9 e2 ed 5e 18 f7 00 0a 49 e5 |.TeP.....^....I.|
+000000f0 19 cc d8 e5 b2 c5 f6 bd 34 7a 7f e2 f1 7c 9d a0 |........4z...|..|
+00000100 d6 0c 50 4f 80 8a c5 a1 fe b8 2e 54 7c 0c ae 48 |..PO.......T|..H|
+00000110 c5 ff 46 d9 45 e6 c0 df 61 74 fc d5 e8 ec e1 84 |..F.E...at......|
+00000120 0b c8 df 73 77 e4 9f 13 e5 52 e5 0b d8 9f 65 b7 |...sw....R....e.|
+00000130 89 d5 04 74 f8 8d a6 2a c7 a1 76 ff 27 85 6a bb |...t...*..v.'.j.|
+00000140 ee 86 c9 38 5a 54 bc ac bc ad 79 85 7c 26 65 c3 |...8ZT....y.|&e.|
+00000150 36 97 56 76 d2 4c 55 32 71 82 ec d1 81 22 46 9e |6.Vv.LU2q...."F.|
+00000160 75 d8 55 a8 1e 61 10 c8 dc e8 c7 ad fe 96 0e 54 |u.U..a.........T|
+00000170 1c 79 0c 41 b9 98 b0 44 f8 45 6e c7 b3 41 68 2d |.y.A...D.En..Ah-|
+00000180 ea 73 be 55 99 fe 88 02 e3 5d 0f f3 d1 70 9a 5e |.s.U.....]...p.^|
+00000190 be e7 80 96 6c 94 7f 9f ec 1c b6 24 28 ef 90 95 |....l......$(...|
+000001a0 d5 5b d4 7b 1b b1 a4 9c 66 09 11 23 ad f5 87 ee |.[.{....f..#....|
+000001b0 0b 1f e5 d2 0e 57 16 e9 14 ae 0f 98 9b a1 bc 9e |.....W..........|
+000001c0 68 dc d0 fb 76 aa c8 f2 bc e5 d3 ff e2 85 df 01 |h...v...........|
+000001d0 2f ad 72 78 85 0f f7 0a 64 a4 cd 61 2a e6 2b a3 |/.rx....d..a*.+.|
+000001e0 d5 4a c9 08 00 af 5c 6c 9d 35 e4 1e 7c 32 1a d0 |.J....\l.5..|2..|
+000001f0 f3 6d 73 16 9c c8 72 28 4b 67 cf d8 ff 2b 1e 33 |.ms...r(Kg...+.3|
+00000200 18 c4 ed c9 31 5d 6a 0f c5 05 bf 08 eb 0b 44 05 |....1]j.......D.|
+00000210 83 49 40 d2 1f 7f 5c 08 ef 98 1f 09 f1 09 33 02 |.I@...\.......3.|
+00000220 56 04 66 53 69 93 ef 07 0d 8a e7 84 b5 03 b9 78 |V.fSi..........x|
+00000230 bb 52 84 3f bb 4e d3 f9 c4 8a 2a d1 59 02 59 36 |.R.?.N....*.Y.Y6|
+00000240 88 52 6a 9d 1f 7e c1 5b a6 8a a4 cc 42 f4 44 59 |.Rj..~.[....B.DY|
+00000250 ca d2 fa 0e 09 5f 25 e5 cc 27 55 8b 16 b5 f1 62 |....._%..'U....b|
+00000260 aa f7 a9 bc 7a 36 fa 16 34 b7 ce 2d b8 bd 67 f0 |....z6..4..-..g.|
+00000270 75 15 17 c4 49 81 55 b1 5a e0 d2 b8 45 79 d0 16 |u...I.U.Z...Ey..|
+00000280 71 21 01 57 ad 10 48 1f 0d bf 43 da b7 c9 a8 93 |q!.W..H...C.....|
+00000290 88 af be 2d 65 a0 81 26 23 de fe e2 a3 9c f6 40 |...-e..&#......@|
+000002a0 96 f9 a1 21 0b fe 31 7f 24 ec 75 ae cf b0 8c a7 |...!..1.$.u.....|
+000002b0 fe f8 2f ee 60 65 72 5c 86 a6 45 22 11 55 62 29 |../.`er\..E".Ub)|
+000002c0 02 8b b5 ff 4b f8 73 71 3d 8c c3 37 68 2d 2c 24 |....K.sq=..7h-,$|
+000002d0 b7 dc be 5a 37 d8 25 3b b6 16 e6 2a e9 80 48 0b |...Z7.%;...*..H.|
+000002e0 77 be 05 35 b2 86 97 51 49 31 ac de 85 eb a9 a8 |w..5...QI1......|
+000002f0 74 1d 00 07 4c 1b 8c a5 ec 1b b5 7a 57 84 da 40 |t...L......zW..@|
+00000300 10 6c c9 ed b3 43 06 81 11 e2 84 3c 4c ae 22 6b |.l...C.....<L."k|
+00000310 e6 96 dc 17 03 03 00 99 2b 4a 51 8f 5e c1 82 70 |........+JQ.^..p|
+00000320 e7 e2 ca 34 cb d1 24 c9 da 69 06 7c 75 d0 0f 16 |...4..$..i.|u...|
+00000330 cc 9c e1 26 60 d0 cc 18 16 18 15 f0 26 f8 d4 d7 |...&`.......&...|
+00000340 f8 81 77 0c 68 cd fe 7a 28 d6 32 60 29 c3 e2 87 |..w.h..z(.2`)...|
+00000350 9b 1c ad 3b 7d 42 31 23 74 61 f5 b7 28 5f 5a 8a |...;}B1#ta..(_Z.|
+00000360 16 98 f8 74 01 63 7d 0a 2c 51 d7 5e 04 8b 2e 58 |...t.c}.,Q.^...X|
+00000370 c3 6f d7 4a 1e fa 55 84 8d a9 24 ef de 4c e3 2e |.o.J..U...$..L..|
+00000380 44 2b 1f e8 b4 a2 6f cc e6 a6 d2 1f fa 60 ab 20 |D+....o......`. |
+00000390 e0 06 8e 00 1a 24 57 50 93 e5 71 d0 cc 63 9b 60 |.....$WP..q..c.`|
+000003a0 f8 e9 c2 de 4b 65 b6 9a 3b dd 60 d6 fb 37 c7 3c |....Ke..;.`..7.<|
+000003b0 e2 17 03 03 00 35 82 7c 22 13 69 48 00 19 51 5c |.....5.|".iH..Q\|
+000003c0 9d 19 3b 1a 25 a9 b8 db 9b c3 25 40 c9 ed c7 dd |..;.%.....%@....|
+000003d0 e6 31 e7 55 ed 48 f0 af 95 1b 0e ca 9a f4 7f 60 |.1.U.H.........`|
+000003e0 03 11 e8 51 57 5e df 4e c2 ec 7a 17 03 03 00 93 |...QW^.N..z.....|
+000003f0 76 84 60 d6 f5 6f 27 c2 47 88 fa 80 78 a6 22 0a |v.`..o'.G...x.".|
+00000400 16 a6 26 12 1b 14 6c 6f 40 10 ce 7c 7c 16 f9 64 |..&...lo@..||..d|
+00000410 e6 98 13 51 36 b0 41 d9 6d 9c fb ba 3e 59 9d 33 |...Q6.A.m...>Y.3|
+00000420 76 f0 23 23 27 94 df 2f 21 6a c0 a9 5a 3d af 41 |v.##'../!j..Z=.A|
+00000430 31 4d 9b d5 75 57 f1 a9 c5 57 2a 7a c7 1d b1 a7 |1M..uW...W*z....|
+00000440 15 a5 80 ae 63 f8 85 92 46 13 d2 31 26 62 7d 83 |....c...F..1&b}.|
+00000450 95 f9 97 9d e8 86 7d 09 f3 cc 30 b1 db 54 2a 8d |......}...0..T*.|
+00000460 0f 04 da d9 cf 59 52 2a e3 7d 64 20 f3 26 4a 2e |.....YR*.}d .&J.|
+00000470 74 07 c5 2f 98 a2 f7 e1 53 01 e0 c2 3b c7 42 1b |t../....S...;.B.|
+00000480 a0 48 12 |.H.|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 57 4a c4 5a c1 |..........5WJ.Z.|
+00000010 3a b9 ae f0 1d e8 8f 31 38 0e 64 9e 61 13 e6 b2 |:......18.d.a...|
+00000020 1b 02 aa b6 46 5a 50 97 07 93 86 13 dc 3d 76 6a |....FZP......=vj|
+00000030 67 01 1b 18 9b 7e 21 b2 c1 d4 a5 25 22 4d 14 dc |g....~!....%"M..|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 1e 61 63 5a 22 d2 e6 8e e8 8e 69 7d |.....acZ".....i}|
+00000010 24 69 a5 b8 e3 59 98 ac 64 0b 34 6b 16 60 92 db |$i...Y..d.4k.`..|
+00000020 6b 62 45 17 03 03 00 13 b7 12 c6 59 fe 23 f4 6c |kbE........Y.#.l|
+00000030 a6 d3 8d 59 1b 40 60 72 d6 97 b4 |...Y.@`r...|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-AES256-SHA384 b/src/crypto/tls/testdata/Server-TLSv13-AES256-SHA384
new file mode 100644
index 0000000..60aa82d
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-AES256-SHA384
@@ -0,0 +1,103 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 dc 01 00 00 d8 03 03 70 b7 07 12 16 |...........p....|
+00000010 50 d7 b9 c9 5f 02 47 2d ff 93 a7 2f e8 51 dc a0 |P..._.G-.../.Q..|
+00000020 8f 0d c8 80 38 c7 af 7e da bb ed 20 67 73 58 d7 |....8..~... gsX.|
+00000030 11 8b c6 0d 72 86 e0 08 3e 2d d9 b9 16 9f 85 6e |....r...>-.....n|
+00000040 3c 87 fd 87 c3 95 f6 4c 76 21 50 af 00 04 13 02 |<......Lv!P.....|
+00000050 00 ff 01 00 00 8b 00 00 00 0e 00 0c 00 00 09 31 |...............1|
+00000060 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
+00000070 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 |................|
+00000080 00 16 00 00 00 17 00 00 00 0d 00 1e 00 1c 04 03 |................|
+00000090 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 |................|
+000000a0 08 05 08 06 04 01 05 01 06 01 00 2b 00 03 02 03 |...........+....|
+000000b0 04 00 2d 00 02 01 01 00 33 00 26 00 24 00 1d 00 |..-.....3.&.$...|
+000000c0 20 f4 08 51 f6 69 b7 d6 a9 3e 18 a7 ee c0 30 f3 | ..Q.i...>....0.|
+000000d0 13 63 52 40 30 7c 79 6c 24 03 c9 89 25 bd a4 5f |.cR@0|yl$...%.._|
+000000e0 64 |d|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 67 73 58 d7 |........... gsX.|
+00000030 11 8b c6 0d 72 86 e0 08 3e 2d d9 b9 16 9f 85 6e |....r...>-.....n|
+00000040 3c 87 fd 87 c3 95 f6 4c 76 21 50 af 13 02 00 00 |<......Lv!P.....|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 17 cc b9 e4 43 5e f6 |.............C^.|
+00000090 9a 5a 62 14 02 39 fb 13 76 e8 10 db 26 1c 07 ec |.Zb..9..v...&...|
+000000a0 06 17 03 03 02 6d 39 e9 a0 33 ee 39 36 54 62 f1 |.....m9..3.96Tb.|
+000000b0 e9 1d 32 45 0f 5a ca 72 f7 7e 43 d8 89 97 00 3d |..2E.Z.r.~C....=|
+000000c0 59 70 08 b4 d1 e1 84 24 7a b8 45 3c b8 32 93 b5 |Yp.....$z.E<.2..|
+000000d0 51 a5 58 60 3f 60 52 aa c1 ff 85 fb fd 50 87 38 |Q.X`?`R......P.8|
+000000e0 47 7a 88 c6 d1 e6 3c b3 16 14 5b cb 23 50 26 7a |Gz....<...[.#P&z|
+000000f0 1d 28 d1 d2 29 5d b0 40 97 2f 3b 58 7c 8a 76 1f |.(..)].@./;X|.v.|
+00000100 1c c1 d2 2b 63 9d 53 bc fb c2 42 cb 40 0d d0 7c |...+c.S...B.@..||
+00000110 73 6c dc 63 90 89 e3 66 67 2b a2 70 af e0 af fe |sl.c...fg+.p....|
+00000120 0c c0 db 41 76 d0 16 37 2a 09 7a 79 31 03 c6 4a |...Av..7*.zy1..J|
+00000130 f4 06 22 ac 96 b4 25 1f 54 11 24 c8 67 22 8f 2a |.."...%.T.$.g".*|
+00000140 56 0c 24 fa 20 ed a8 37 66 f7 38 44 43 e2 e6 e3 |V.$. ..7f.8DC...|
+00000150 96 b5 d5 dd a5 2c 23 e4 57 57 7d 7a 59 e2 4f 66 |.....,#.WW}zY.Of|
+00000160 c4 29 d6 d1 32 a3 9c 4c dd 63 b2 a6 dc ff 6f 61 |.)..2..L.c....oa|
+00000170 c2 db 88 80 23 c1 27 d4 be dd 4f b4 c9 b8 56 4c |....#.'...O...VL|
+00000180 65 b6 f8 32 b2 60 7b af 5f 54 71 61 20 db 25 85 |e..2.`{._Tqa .%.|
+00000190 34 b6 58 9b 71 01 dd 53 cd 13 65 2e 23 69 96 0e |4.X.q..S..e.#i..|
+000001a0 89 94 75 09 64 60 76 d2 65 85 38 3d f1 0e cb 47 |..u.d`v.e.8=...G|
+000001b0 c1 2c 52 f8 ce 7a a6 9f dd 7c 39 7e a7 f9 a6 1b |.,R..z...|9~....|
+000001c0 c1 23 81 a6 7a b1 6c d4 3c 1c f3 71 ce 72 24 01 |.#..z.l.<..q.r$.|
+000001d0 4a 8d e9 24 47 51 73 67 dc 7a 9f 0b 63 7d 29 e1 |J..$GQsg.z..c}).|
+000001e0 3e 5e ac 72 d7 c8 d9 c2 13 de 92 dd 04 cb 09 21 |>^.r...........!|
+000001f0 ad 41 69 27 77 48 eb 87 cb 3b 23 ba 06 a3 68 96 |.Ai'wH...;#...h.|
+00000200 ad 24 35 f6 a6 03 87 a7 4d 9f d4 bf e5 8b 9f 56 |.$5.....M......V|
+00000210 54 dd 0e 08 da 29 ff eb 9b e1 0a a5 25 b1 85 be |T....)......%...|
+00000220 f8 ae 63 f4 49 64 cc 0a 41 0e 26 8a 8e bc 6f c9 |..c.Id..A.&...o.|
+00000230 f5 41 55 80 0d bd 70 ad 85 b0 d4 8d 33 ac b6 40 |.AU...p.....3..@|
+00000240 3e 76 fc fb 8f d2 7d 06 14 d4 45 24 6e 36 46 1c |>v....}...E$n6F.|
+00000250 06 d3 f7 f3 4c 3a a5 83 4f 75 72 77 b4 5e 37 49 |....L:..Ourw.^7I|
+00000260 41 f1 9f e6 d1 46 87 56 c8 64 28 fd 38 f0 0f 9c |A....F.V.d(.8...|
+00000270 d0 39 ff 4b 46 56 73 0d 12 7d bf 63 b4 b8 0d 33 |.9.KFVs..}.c...3|
+00000280 6b 4a 2b f8 39 67 f1 ec 2d a6 0b 5c 91 2d d8 3e |kJ+.9g..-..\.-.>|
+00000290 91 81 1a 37 29 c7 14 d2 be db 31 61 dc 5d b1 e4 |...7).....1a.]..|
+000002a0 64 af 14 9c 93 85 e7 5b 0e 42 63 c7 5e b5 cc 51 |d......[.Bc.^..Q|
+000002b0 ca 83 ca fa 52 bd 44 a1 1c 76 20 bc 3d 9f 82 79 |....R.D..v .=..y|
+000002c0 20 5c 01 14 e3 07 02 4c f6 87 f7 46 b8 de 47 23 | \.....L...F..G#|
+000002d0 5d 5c b3 8f cd 96 49 51 32 3f d2 5d 92 32 19 b5 |]\....IQ2?.].2..|
+000002e0 10 33 46 37 f0 b5 82 23 a5 91 1f 60 fb 21 2c 08 |.3F7...#...`.!,.|
+000002f0 c3 6e 17 72 0b 5d c9 7b cc 77 97 6f 20 d9 a6 fa |.n.r.].{.w.o ...|
+00000300 cc 4a bb c6 3b 0e b1 66 ae 57 f5 1b 16 46 36 b7 |.J..;..f.W...F6.|
+00000310 a5 94 ae 17 03 03 00 99 d7 86 a0 5f c0 d2 33 3e |..........._..3>|
+00000320 ce ce ea db cb a1 a5 11 b7 cc a1 48 b6 86 f5 11 |...........H....|
+00000330 d6 32 8c f9 e8 bb e3 3e ea 6f 1a df 64 cd c8 7d |.2.....>.o..d..}|
+00000340 e9 cb e4 19 fe cd 75 74 03 4a fe 91 1d 87 28 65 |......ut.J....(e|
+00000350 25 79 3a 19 13 ba 67 16 aa 7e 8e c0 e6 53 4f bb |%y:...g..~...SO.|
+00000360 98 ed cc 59 db 5e 73 23 d4 a9 a7 2a 6d 01 73 4a |...Y.^s#...*m.sJ|
+00000370 e6 65 2e c0 34 49 c1 d8 70 2e 70 1b 10 97 74 23 |.e..4I..p.p...t#|
+00000380 fe 6b 5d cd fa 71 c8 43 c3 5b 42 5c 7b e0 9e 3f |.k]..q.C.[B\{..?|
+00000390 a8 3d a9 d1 97 17 87 80 af 7c 5d 8b 70 ba 87 06 |.=.......|].p...|
+000003a0 67 dd 29 df f3 ca 9a f4 c8 93 e8 f8 ac c0 df 8e |g.).............|
+000003b0 c5 17 03 03 00 45 40 a4 26 66 29 18 b8 d6 a7 87 |.....E@.&f).....|
+000003c0 91 5f 6d 79 13 f8 7a 47 cf ac 93 7c 11 cb 4a b2 |._my..zG...|..J.|
+000003d0 24 a6 40 fb d4 ed 71 ec 19 53 ba ae e0 bb e6 cf |$.@...q..S......|
+000003e0 d6 8a a6 3c 6a 4e a3 6f 6c d7 2d e1 8a a4 6c da |...<jN.ol.-...l.|
+000003f0 a1 ab fd c0 de 59 e9 18 fc 47 f2 17 03 03 00 a3 |.....Y...G......|
+00000400 5b 85 84 a4 0d ff be 3e ea 00 71 3d ea be c7 e2 |[......>..q=....|
+00000410 dc 2f 4a 62 c2 9f e2 e5 16 51 ff 35 a7 70 df 12 |./Jb.....Q.5.p..|
+00000420 23 d6 f7 6c 96 91 7f 0f 6d d4 45 5f c6 8c c5 93 |#..l....m.E_....|
+00000430 b1 b7 46 ef f0 f4 a3 68 35 ff 09 38 8d 6d c6 84 |..F....h5..8.m..|
+00000440 d3 1c 4d 48 4e fc 4a c0 46 06 b1 a5 1c 74 a0 44 |..MHN.J.F....t.D|
+00000450 69 68 20 33 df 70 60 69 57 c7 85 bd 3e ed 55 d0 |ih 3.p`iW...>.U.|
+00000460 56 84 8f 19 03 5a 54 9a d5 3e 5d 37 98 40 4c f0 |V....ZT..>]7.@L.|
+00000470 5e f1 26 e5 97 01 fc 0f 2a 09 e9 7a 51 69 c0 8e |^.&.....*..zQi..|
+00000480 d4 25 80 f4 ca 91 f3 a7 5c 0c 96 ba ec a8 b5 ee |.%......\.......|
+00000490 ab ec 05 cb 99 30 78 48 1b 78 bf 3d b9 f4 e8 33 |.....0xH.x.=...3|
+000004a0 4d 45 d1 |ME.|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 45 54 0e c1 aa 95 |..........ET....|
+00000010 fd c5 d2 8b a0 ae 40 a1 9a b8 87 39 17 53 f7 10 |......@....9.S..|
+00000020 62 6f 55 18 42 cf 75 cb 05 de 32 28 c4 a0 f1 17 |boU.B.u...2(....|
+00000030 f1 55 ae 2c 97 9e dd d2 d0 a7 6b c6 51 51 c6 0c |.U.,......k.QQ..|
+00000040 81 3f 04 db 94 e6 68 f0 a1 80 10 39 06 99 25 e2 |.?....h....9..%.|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 1e e4 4f d5 b0 e7 a0 e2 13 69 75 7c |......O......iu||
+00000010 b1 84 93 be 99 ea 27 20 dd 08 89 6c e2 5a c6 bc |......' ...l.Z..|
+00000020 b8 41 3d 17 03 03 00 13 cf 64 ad ad d9 84 87 36 |.A=......d.....6|
+00000030 b9 ea b8 76 97 93 c1 03 44 c5 de |...v....D..|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-ALPN b/src/crypto/tls/testdata/Server-TLSv13-ALPN
new file mode 100644
index 0000000..df8dd45
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-ALPN
@@ -0,0 +1,100 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 e2 01 00 00 de 03 03 8e d2 a1 8f ea |................|
+00000010 e3 7d 5f 7c 70 74 c3 7e 5f 06 bb 21 35 28 38 7a |.}_|pt.~_..!5(8z|
+00000020 7f 00 11 86 6e ac 19 38 7f d4 88 20 33 3a b2 14 |....n..8... 3:..|
+00000030 c2 4e 6a 39 71 24 81 21 27 21 2d b7 3d bc 5e 97 |.Nj9q$.!'!-.=.^.|
+00000040 f8 ed 55 83 be 9a d3 27 b5 e0 0e bd 00 04 13 03 |..U....'........|
+00000050 00 ff 01 00 00 91 00 0b 00 04 03 00 01 02 00 0a |................|
+00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#|
+00000070 00 00 00 10 00 10 00 0e 06 70 72 6f 74 6f 32 06 |.........proto2.|
+00000080 70 72 6f 74 6f 31 00 16 00 00 00 17 00 00 00 0d |proto1..........|
+00000090 00 1e 00 1c 04 03 05 03 06 03 08 07 08 08 08 09 |................|
+000000a0 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 06 01 |................|
+000000b0 00 2b 00 03 02 03 04 00 2d 00 02 01 01 00 33 00 |.+......-.....3.|
+000000c0 26 00 24 00 1d 00 20 89 4d b8 22 62 39 22 e6 5a |&.$... .M."b9".Z|
+000000d0 b1 86 ea c9 d9 d1 77 c9 12 c3 62 e1 8e 17 cb ab |......w...b.....|
+000000e0 91 83 d8 af 9b be 0a |.......|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 33 3a b2 14 |........... 3:..|
+00000030 c2 4e 6a 39 71 24 81 21 27 21 2d b7 3d bc 5e 97 |.Nj9q$.!'!-.=.^.|
+00000040 f8 ed 55 83 be 9a d3 27 b5 e0 0e bd 13 03 00 00 |..U....'........|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 24 60 9e a3 43 47 75 |.........$`..CGu|
+00000090 d2 38 11 fd 9d da a5 f6 65 de 3c 2a 3d a9 46 7e |.8......e.<*=.F~|
+000000a0 50 c8 52 a1 7d e6 95 a7 4b 48 b7 35 e7 a7 17 03 |P.R.}...KH.5....|
+000000b0 03 02 6d b8 30 43 88 03 d4 6c cf c6 45 80 b2 6c |..m.0C...l..E..l|
+000000c0 52 d7 1e 08 de 0b 6e 7a 27 c8 2c 59 d4 03 41 24 |R.....nz'.,Y..A$|
+000000d0 e3 4a e1 d3 85 68 de 23 f6 c4 3a bb 45 ae b1 ac |.J...h.#..:.E...|
+000000e0 8b b3 22 7d e7 a6 7c e3 07 68 b1 9c 97 6a d3 e4 |.."}..|..h...j..|
+000000f0 5d 0a 73 a3 16 ad e4 7f b9 d7 0a b7 7c 48 bb f2 |].s.........|H..|
+00000100 ed 49 61 f7 cb 5e ea d2 d9 a3 73 ea a7 4f a3 10 |.Ia..^....s..O..|
+00000110 f7 3e 8f ce b9 56 a0 88 54 52 59 1f f3 55 2b 15 |.>...V..TRY..U+.|
+00000120 df fd fa 85 9e 20 ff 72 f3 26 6a 2c 1f 11 a8 3d |..... .r.&j,...=|
+00000130 8e 66 75 aa 90 fc 9f 9f a7 67 8f ac 98 54 19 04 |.fu......g...T..|
+00000140 c9 1f 48 f7 ed 8f 13 0a f9 6c 9b f8 e9 0a c5 a9 |..H......l......|
+00000150 f2 ef 5b 65 a1 ad 40 e4 e7 ff c1 ff e9 d6 ab 5c |..[e..@........\|
+00000160 f8 f1 7b 4d 39 33 1d 68 d3 38 20 10 c4 3b 7a 9f |..{M93.h.8 ..;z.|
+00000170 fe 55 1d 83 5c 8f 67 d0 bb 5f 32 80 b2 91 38 0a |.U..\.g.._2...8.|
+00000180 71 bb b4 3a 10 1c 98 f9 d4 19 7c 7d d5 f7 4b 0a |q..:......|}..K.|
+00000190 02 2f bd 0b f9 ff 28 b2 2d ba dd 7f 0d 51 a2 4c |./....(.-....Q.L|
+000001a0 51 92 1e e9 47 51 ae 1a d0 66 9c ef 0a 02 dc 69 |Q...GQ...f.....i|
+000001b0 95 79 2b b0 8f 7b a2 3d 57 cf 5c 7e b4 0a 91 34 |.y+..{.=W.\~...4|
+000001c0 e6 d0 0d 93 1b 6c 61 9e 58 12 47 5f 3a ec 67 19 |.....la.X.G_:.g.|
+000001d0 d8 fb 44 43 4d cd 4e ad 1d bc f2 05 66 42 3f 3f |..DCM.N.....fB??|
+000001e0 85 5d 93 56 8e ca 62 47 38 ee d2 0e 81 8b 71 7d |.].V..bG8.....q}|
+000001f0 d8 cf 6e 4b 61 80 fe 28 34 f4 f1 58 06 36 2a 40 |..nKa..(4..X.6*@|
+00000200 93 98 3d d0 9c 69 6f 6a 3a 40 b9 8c 2e 71 5d 52 |..=..ioj:@...q]R|
+00000210 66 5d 55 45 e7 38 b7 ce 74 c2 1c ae 2e 4a 03 86 |f]UE.8..t....J..|
+00000220 d4 15 c3 40 d9 58 b7 ba ed 84 fd 20 35 a4 1c c6 |...@.X..... 5...|
+00000230 8a 50 7a 0c 87 53 d7 2d 4b 5b 7d 23 79 8f 66 f8 |.Pz..S.-K[}#y.f.|
+00000240 72 05 72 7b 7d 7a 64 97 8d da c9 dd 23 6a 44 b6 |r.r{}zd.....#jD.|
+00000250 e1 99 e4 45 76 a5 53 d8 1b 54 a0 b9 9e ec 0e d3 |...Ev.S..T......|
+00000260 91 1b 5e c0 a7 c8 3a 34 22 f9 58 7d da 2b f4 fd |..^...:4".X}.+..|
+00000270 2b 9a 9e 26 20 6f d3 9d e9 48 a1 62 70 fe 06 04 |+..& o...H.bp...|
+00000280 c2 63 f7 c4 a2 b9 74 28 a8 b3 f9 f0 a1 2a 46 0c |.c....t(.....*F.|
+00000290 f5 6b cc 7e b4 c0 47 eb 00 96 6a 3d 32 58 e0 0a |.k.~..G...j=2X..|
+000002a0 59 01 3c 42 45 a7 76 6d 78 05 1f 2c db a4 08 5b |Y.<BE.vmx..,...[|
+000002b0 e8 8e b1 10 cb a9 d9 e5 c3 a4 5a f7 63 30 c7 ac |..........Z.c0..|
+000002c0 8d 62 14 9d 30 ee 9f 9f 1b c4 ca 7f e8 d4 64 2a |.b..0.........d*|
+000002d0 46 0d 43 e1 bd 4e ed 83 f1 6b 33 78 ed 8e 98 58 |F.C..N...k3x...X|
+000002e0 13 c5 7a 8a b3 20 c4 db 17 1a 83 7d 04 ec ae 02 |..z.. .....}....|
+000002f0 cd ef 9b 27 5a f0 94 0d 71 24 bf 6f 31 c4 05 a3 |...'Z...q$.o1...|
+00000300 ca b5 bf 5d cb 23 e7 76 75 b0 2e 8b d7 65 60 12 |...].#.vu....e`.|
+00000310 97 8b 02 6c 4a ba 44 2d a3 e8 47 ff 0e cd 7e a1 |...lJ.D-..G...~.|
+00000320 17 03 03 00 99 a9 d7 60 8b 76 f6 fa 62 91 32 fe |.......`.v..b.2.|
+00000330 70 3f a1 87 36 b3 d0 01 22 61 76 4f 62 52 26 08 |p?..6..."avObR&.|
+00000340 06 db 41 b9 f6 57 ed 7f 7d 69 5b 19 37 f1 8c 99 |..A..W..}i[.7...|
+00000350 c1 8f d8 45 ab 6f 30 5f 11 34 12 9e 18 7a e9 8d |...E.o0_.4...z..|
+00000360 33 23 c1 61 19 f7 3b 90 60 04 86 53 7d a0 be e9 |3#.a..;.`..S}...|
+00000370 c8 48 19 ef 99 16 54 e1 82 7f e9 7c b4 50 bd d0 |.H....T....|.P..|
+00000380 75 31 69 77 f5 d5 64 41 82 21 5c aa a9 a6 b2 cf |u1iw..dA.!\.....|
+00000390 d6 73 d3 79 3f b5 ba cb d4 4a 70 ae b8 9a d8 0f |.s.y?....Jp.....|
+000003a0 24 47 3a 30 31 6e 4c 79 a4 28 63 6e 2b 90 1c 6d |$G:01nLy.(cn+..m|
+000003b0 00 6e e3 90 60 fb d2 96 66 f9 a2 c0 af c9 17 03 |.n..`...f.......|
+000003c0 03 00 35 f6 41 b8 95 b6 98 56 4b 39 4f 42 8a 88 |..5.A....VK9OB..|
+000003d0 35 f1 15 7f 7a e0 0e 04 a8 6f 02 f0 64 e8 83 f2 |5...z....o..d...|
+000003e0 2f 03 2e 1f 24 0f 7a 4e 36 2d f7 54 9e ad 22 15 |/...$.zN6-.T..".|
+000003f0 f5 57 8f 19 f0 f0 46 11 17 03 03 00 93 26 4a 78 |.W....F......&Jx|
+00000400 60 d7 d6 5c 18 17 12 f5 a7 c5 42 de 63 6a cb 10 |`..\......B.cj..|
+00000410 c3 a1 66 57 85 0e 78 50 99 77 aa 5e 8f fb 0d 59 |..fW..xP.w.^...Y|
+00000420 f0 09 b1 b1 10 be a5 64 e1 85 48 79 8d b6 07 52 |.......d..Hy...R|
+00000430 05 bb aa 0d 46 42 dd 1d 1b 2e a7 cb 28 cd 97 24 |....FB......(..$|
+00000440 8e d4 7a 2d 1c 4a 25 12 eb 25 0b 14 40 94 0e 5d |..z-.J%..%..@..]|
+00000450 d0 04 9c 87 88 44 d5 70 c6 3d 0b 3f 10 19 cc 18 |.....D.p.=.?....|
+00000460 c5 89 b8 c3 5d 5f 3e 96 cc 9b 63 e9 f3 b1 66 2f |....]_>...c...f/|
+00000470 24 2a 06 1b f3 91 a7 7c dd d9 b5 1f b3 9e 7f ce |$*.....|........|
+00000480 db 96 cd 2e 36 69 f0 94 0c 5f e8 0b 15 6a 38 40 |....6i..._...j8@|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 32 39 09 c6 64 |..........529..d|
+00000010 aa 86 b7 a7 37 6c fa ef 66 01 d4 de e6 35 8d 31 |....7l..f....5.1|
+00000020 68 71 f3 27 56 fd 7f 7b cf c8 3c d1 44 ff e0 c7 |hq.'V..{..<.D...|
+00000030 78 b7 6c c8 ac 01 0e ee e1 78 b9 dd 1a e1 a9 b6 |x.l......x......|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 1e da e7 79 04 f5 65 2e f6 c3 c3 b9 |.......y..e.....|
+00000010 34 37 14 8f c2 32 cb 81 58 bc cf d0 3b 08 f0 61 |47...2..X...;..a|
+00000020 b3 ae b4 17 03 03 00 13 e3 32 09 02 e0 29 5e 4a |.........2...)^J|
+00000030 9b 36 a9 b0 65 e9 2c 1d fb ad 50 |.6..e.,...P|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-ALPN-Fallback b/src/crypto/tls/testdata/Server-TLSv13-ALPN-Fallback
new file mode 100644
index 0000000..6203e68
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-ALPN-Fallback
@@ -0,0 +1,100 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 eb 01 00 00 e7 03 03 1c d3 8e 3b d9 |..............;.|
+00000010 fe 7d e7 f9 9f fa c6 51 c3 8c 1b dd dc 87 95 f4 |.}.....Q........|
+00000020 39 23 67 e4 d6 bd 94 93 fc 88 4e 20 c3 c0 e2 c1 |9#g.......N ....|
+00000030 3d 12 ec 4c 0a 3f 40 51 13 24 61 11 c0 5d 09 f9 |=..L.?@Q.$a..]..|
+00000040 08 d6 3e cd e7 b3 51 c3 06 8f b4 42 00 04 13 03 |..>...Q....B....|
+00000050 00 ff 01 00 00 9a 00 0b 00 04 03 00 01 02 00 0a |................|
+00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#|
+00000070 00 00 00 10 00 19 00 17 06 70 72 6f 74 6f 33 08 |.........proto3.|
+00000080 68 74 74 70 2f 31 2e 31 06 70 72 6f 74 6f 34 00 |http/1.1.proto4.|
+00000090 16 00 00 00 17 00 00 00 0d 00 1e 00 1c 04 03 05 |................|
+000000a0 03 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 |................|
+000000b0 05 08 06 04 01 05 01 06 01 00 2b 00 03 02 03 04 |..........+.....|
+000000c0 00 2d 00 02 01 01 00 33 00 26 00 24 00 1d 00 20 |.-.....3.&.$... |
+000000d0 f4 05 eb 4a 7a 73 20 18 74 aa 14 2a 0c 35 63 29 |...Jzs .t..*.5c)|
+000000e0 cb f2 ad d1 a2 3d bd 9d 02 b4 62 00 bc eb 10 58 |.....=....b....X|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 c3 c0 e2 c1 |........... ....|
+00000030 3d 12 ec 4c 0a 3f 40 51 13 24 61 11 c0 5d 09 f9 |=..L.?@Q.$a..]..|
+00000040 08 d6 3e cd e7 b3 51 c3 06 8f b4 42 13 03 00 00 |..>...Q....B....|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 17 fb 75 d8 5c 50 35 |...........u.\P5|
+00000090 55 82 ba 65 1e 63 73 b8 c1 e9 d7 f5 28 68 3c c1 |U..e.cs.....(h<.|
+000000a0 5d 17 03 03 02 6d 56 c9 a9 09 73 6a bc fd 1a 3c |]....mV...sj...<|
+000000b0 6a f8 3e 32 99 83 e8 f6 01 9e 5e 30 e8 53 7f 72 |j.>2......^0.S.r|
+000000c0 fd 86 72 a8 9e 47 25 67 c1 f1 9a 03 c0 9d 6f 9d |..r..G%g......o.|
+000000d0 bd ed 29 30 8f 3c 01 ce 49 bb 5f dd 58 9a ae 80 |..)0.<..I._.X...|
+000000e0 5c 2d 81 fc ea 7b 03 03 3d 5d bb 92 23 73 67 89 |\-...{..=]..#sg.|
+000000f0 2e f0 ec 08 20 8a 36 eb 43 a6 a1 68 d0 39 95 37 |.... .6.C..h.9.7|
+00000100 6b 15 a9 0e 46 20 92 51 9c 04 bf 3b 07 97 84 cb |k...F .Q...;....|
+00000110 1f 30 38 37 2e ff e7 0f f5 14 93 5a 84 f1 f7 10 |.087.......Z....|
+00000120 c2 a5 0d bb 97 96 ef 4a e0 13 c0 63 72 2b 60 f3 |.......J...cr+`.|
+00000130 59 b5 57 aa 5f d1 da a9 0e dd 9c dd c2 cb 61 fe |Y.W._.........a.|
+00000140 e2 69 8e db 5d 70 6c 3a 33 e0 9e db 9a 31 26 6a |.i..]pl:3....1&j|
+00000150 2b 9e 19 8e bb 5d 06 48 ea c0 a1 c6 11 24 fb c4 |+....].H.....$..|
+00000160 ce ae 48 54 64 81 d1 84 38 a6 e0 7a 7b 74 2b bc |..HTd...8..z{t+.|
+00000170 ce 07 8b b6 04 1f 5b 4c 36 29 68 0c 8c c7 32 15 |......[L6)h...2.|
+00000180 93 e0 10 52 c2 27 23 96 c5 0c 9c e9 e2 a9 08 7d |...R.'#........}|
+00000190 25 68 65 f5 4e 44 eb a9 85 78 13 e1 0d 86 5e dc |%he.ND...x....^.|
+000001a0 fd e5 c6 dd 65 46 8e 2f 32 82 83 0b dd 67 f8 42 |....eF./2....g.B|
+000001b0 65 87 3b 08 fe b1 f5 12 e9 74 21 04 12 6d 75 35 |e.;......t!..mu5|
+000001c0 b2 eb 93 95 72 10 fa 56 96 77 c3 0c 17 8c 9e f6 |....r..V.w......|
+000001d0 77 19 28 37 96 3e 73 98 f4 d2 91 4f 40 db 76 56 |w.(7.>s....O@.vV|
+000001e0 ce b5 a8 7a b8 86 d0 9a ba b5 8b 40 c2 63 e1 cf |...z.......@.c..|
+000001f0 49 29 2c 5d 1a 9b 8b 56 cb 93 ca 2c c0 d0 15 b7 |I),]...V...,....|
+00000200 8a f1 6a d5 0a a8 81 57 b1 6e 10 cd a5 ff b1 4d |..j....W.n.....M|
+00000210 47 c6 9b 35 f1 5f 83 91 22 f6 88 68 65 b3 b9 c9 |G..5._.."..he...|
+00000220 02 dc 4b f7 13 39 06 e6 3a ec 94 ef 51 15 05 72 |..K..9..:...Q..r|
+00000230 1d f4 9d 3b da ca 8d 2c 64 be 9b 45 99 2c 63 cc |...;...,d..E.,c.|
+00000240 22 b3 8b 93 ad f6 2c f0 d2 d9 11 3f 5b c0 40 fa |".....,....?[.@.|
+00000250 90 6e a0 76 b2 43 b9 4c 72 c4 24 28 a2 bf 56 d6 |.n.v.C.Lr.$(..V.|
+00000260 d2 a7 2a d1 8c 5e 1d eb f8 be d0 43 da 7a c7 88 |..*..^.....C.z..|
+00000270 61 67 a2 69 85 23 43 3e d4 88 f2 33 c3 5b 38 0a |ag.i.#C>...3.[8.|
+00000280 1e de 28 3b 3b 19 de 95 2f 84 c0 37 88 80 59 2f |..(;;.../..7..Y/|
+00000290 a6 ee 93 1a 69 08 c3 df 7c cf da c3 9b 96 70 d9 |....i...|.....p.|
+000002a0 60 c5 e9 0f 42 f6 1a f2 58 5e f2 32 61 6a b2 a3 |`...B...X^.2aj..|
+000002b0 1f 97 fa 08 6c 3f 4b 83 1f 04 66 80 8a 26 3a 7f |....l?K...f..&:.|
+000002c0 24 30 ec 10 ae 7d 19 ff 39 91 ca 97 4e ed 0a d7 |$0...}..9...N...|
+000002d0 64 3b 6b 50 29 33 0d b2 10 bc 83 63 3c fb 9a 82 |d;kP)3.....c<...|
+000002e0 3b 7f bc 04 40 f1 33 64 4a 80 cd 01 f9 f4 c6 89 |;...@.3dJ.......|
+000002f0 65 27 25 f9 cf 4f 7e c8 6e d9 0e ec 47 4a 51 29 |e'%..O~.n...GJQ)|
+00000300 2f be 34 50 bd 9b d2 d8 b7 ea bb 0b a1 e0 20 1b |/.4P.......... .|
+00000310 02 9c f2 17 03 03 00 99 61 dc 0b 3a 30 de 39 f6 |........a..:0.9.|
+00000320 f3 db f8 6c 3b fa 4e 1e 7e 62 a5 ae 73 ba e1 41 |...l;.N.~b..s..A|
+00000330 58 77 2a c1 7a 0c 50 bb 0c 57 b4 c4 25 bf 2f 9f |Xw*.z.P..W..%./.|
+00000340 38 91 e2 65 22 9d ca ac 18 58 7e 81 2d fd 74 24 |8..e"....X~.-.t$|
+00000350 28 69 76 11 df 9d 23 b8 be ae 8b e0 93 8e 5d df |(iv...#.......].|
+00000360 0a 64 d0 b7 02 68 aa 86 01 0d 55 11 3b 76 70 c6 |.d...h....U.;vp.|
+00000370 83 0c 5e 0a e3 37 a5 8b ad 25 50 b9 e8 5c 6b 04 |..^..7...%P..\k.|
+00000380 b4 51 ec 9c d3 fa c6 b7 9c f0 46 aa 73 da 3c 0d |.Q........F.s.<.|
+00000390 d3 bd 32 81 d4 d2 f1 1a b0 92 f3 73 3e 54 2b 05 |..2........s>T+.|
+000003a0 92 24 34 75 df d6 18 a0 6a 82 95 4c 9b fc 7e b6 |.$4u....j..L..~.|
+000003b0 8e 17 03 03 00 35 8f 34 0e 3b 91 d8 e7 74 24 71 |.....5.4.;...t$q|
+000003c0 0e 7b f3 12 bb 76 2f 31 12 17 b8 9e 24 ce f9 2f |.{...v/1....$../|
+000003d0 3f 5d f2 13 4b 2e 9b 1e c4 78 03 a6 c8 07 11 a3 |?]..K....x......|
+000003e0 98 79 61 6e 4f 44 6e 18 ee c4 9b 17 03 03 00 93 |.yanODn.........|
+000003f0 64 dd 52 a9 d9 51 63 6a a0 a3 c2 75 6b 5d 1d 54 |d.R..Qcj...uk].T|
+00000400 ce d4 53 7e 14 8e d9 26 93 28 78 65 16 1b 95 77 |..S~...&.(xe...w|
+00000410 68 0a 46 f1 82 36 bb 8a fa 0d df 54 8c 3d 83 e0 |h.F..6.....T.=..|
+00000420 d7 de 2d 96 e9 c4 d7 22 d3 97 8e ae 90 f8 fc e6 |..-...."........|
+00000430 a6 4b 78 98 4c c5 28 87 91 46 fa f4 1c 8d 0e ec |.Kx.L.(..F......|
+00000440 0d 71 40 9a 04 49 b4 e8 5b 62 6f cd 16 c1 d5 fb |.q@..I..[bo.....|
+00000450 73 2a 96 8f e5 a2 f4 11 1e df 2d 40 45 6b d5 a9 |s*........-@Ek..|
+00000460 e4 e3 f7 93 fc fa d7 20 af d5 f7 b4 0e 09 ad d5 |....... ........|
+00000470 26 87 b8 6c e2 20 95 fb c0 70 3e 38 be b7 b1 9f |&..l. ...p>8....|
+00000480 70 da c1 |p..|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 29 d2 b9 bb 9b |..........5)....|
+00000010 de 6c 5d 22 23 c1 fe 99 4c c5 33 bf fd 70 36 6b |.l]"#...L.3..p6k|
+00000020 f1 a5 92 e8 bf 7c 3d 6e ef 6a 44 73 bc cb 27 1c |.....|=n.jDs..'.|
+00000030 09 5d bf 99 4c 19 24 c3 3b 30 91 b5 e3 b6 63 45 |.]..L.$.;0....cE|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 1e 52 55 85 7c b8 87 dd c7 b2 d9 5b |.....RU.|......[|
+00000010 18 1d bb ac bf b6 ab 76 82 be 64 0e b2 7b 2c 0f |.......v..d..{,.|
+00000020 aa 17 92 17 03 03 00 13 79 0a 60 b1 46 20 33 74 |........y.`.F 3t|
+00000030 ed 12 a0 23 de 68 88 fc 6f dd 8e |...#.h..o..|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-ALPN-NoMatch b/src/crypto/tls/testdata/Server-TLSv13-ALPN-NoMatch
new file mode 100644
index 0000000..b51ff25
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-ALPN-NoMatch
@@ -0,0 +1,27 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 e2 01 00 00 de 03 03 9f 73 81 5f 56 |............s._V|
+00000010 a9 02 5f 8c 33 db dc 2a 92 d0 5e 7c e9 e6 01 d7 |.._.3..*..^|....|
+00000020 67 b6 bb 74 da bb d0 c1 11 08 20 20 9f bd d6 f8 |g..t...... ....|
+00000030 d7 8c e5 32 15 1d 4a 4c 36 ce 72 90 cb 68 ca dc |...2..JL6.r..h..|
+00000040 ea b3 57 93 9a 12 e6 0e 9a bd 91 1a 00 04 13 03 |..W.............|
+00000050 00 ff 01 00 00 91 00 0b 00 04 03 00 01 02 00 0a |................|
+00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#|
+00000070 00 00 00 10 00 10 00 0e 06 70 72 6f 74 6f 32 06 |.........proto2.|
+00000080 70 72 6f 74 6f 31 00 16 00 00 00 17 00 00 00 0d |proto1..........|
+00000090 00 1e 00 1c 04 03 05 03 06 03 08 07 08 08 08 09 |................|
+000000a0 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 06 01 |................|
+000000b0 00 2b 00 03 02 03 04 00 2d 00 02 01 01 00 33 00 |.+......-.....3.|
+000000c0 26 00 24 00 1d 00 20 79 79 04 d3 03 58 93 22 5d |&.$... yy...X."]|
+000000d0 06 69 1a 03 11 4e 65 e5 30 85 29 02 22 c8 11 6d |.i...Ne.0.)."..m|
+000000e0 21 86 d4 4d 58 93 74 |!..MX.t|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 9f bd d6 f8 |........... ....|
+00000030 d7 8c e5 32 15 1d 4a 4c 36 ce 72 90 cb 68 ca dc |...2..JL6.r..h..|
+00000040 ea b3 57 93 9a 12 e6 0e 9a bd 91 1a 13 03 00 00 |..W.............|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 13 7c ab 7f dd 94 cf |..........|.....|
+00000090 d7 98 34 16 75 02 63 37 fa 4f 19 4e 18 |..4.u.c7.O.N.|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-ALPN-NotConfigured b/src/crypto/tls/testdata/Server-TLSv13-ALPN-NotConfigured
new file mode 100644
index 0000000..e0830d3
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-ALPN-NotConfigured
@@ -0,0 +1,100 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 e2 01 00 00 de 03 03 9f 49 a7 46 f8 |............I.F.|
+00000010 72 04 47 a1 8e 4f 89 c3 cd 89 92 2f 7a 8a 07 37 |r.G..O...../z..7|
+00000020 8c 25 10 42 26 07 8b a2 71 3e 92 20 4c 83 1b 70 |.%.B&...q>. L..p|
+00000030 45 c3 79 68 c3 83 a7 05 c2 22 06 c6 91 da 8b 96 |E.yh....."......|
+00000040 4c 9d 89 c2 ec b8 49 87 17 3f 6c ae 00 04 13 03 |L.....I..?l.....|
+00000050 00 ff 01 00 00 91 00 0b 00 04 03 00 01 02 00 0a |................|
+00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#|
+00000070 00 00 00 10 00 10 00 0e 06 70 72 6f 74 6f 32 06 |.........proto2.|
+00000080 70 72 6f 74 6f 31 00 16 00 00 00 17 00 00 00 0d |proto1..........|
+00000090 00 1e 00 1c 04 03 05 03 06 03 08 07 08 08 08 09 |................|
+000000a0 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 06 01 |................|
+000000b0 00 2b 00 03 02 03 04 00 2d 00 02 01 01 00 33 00 |.+......-.....3.|
+000000c0 26 00 24 00 1d 00 20 f4 91 87 6a ac cd 25 5e f1 |&.$... ...j..%^.|
+000000d0 0d 25 fb af a4 d4 fb 16 32 63 af 04 2d 21 d7 2f |.%......2c..-!./|
+000000e0 61 f2 c2 d4 c4 6c 2b |a....l+|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 4c 83 1b 70 |........... L..p|
+00000030 45 c3 79 68 c3 83 a7 05 c2 22 06 c6 91 da 8b 96 |E.yh....."......|
+00000040 4c 9d 89 c2 ec b8 49 87 17 3f 6c ae 13 03 00 00 |L.....I..?l.....|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 17 60 79 16 61 4f 6c |..........`y.aOl|
+00000090 9e 2e ce fd cc f5 29 67 38 e7 53 67 92 b1 5f 9d |......)g8.Sg.._.|
+000000a0 db 17 03 03 02 6d 54 d9 d6 a1 8e c2 1b 70 3f 3d |.....mT......p?=|
+000000b0 a2 2e 0f a5 37 96 e1 68 66 69 cc f8 e9 06 4d bc |....7..hfi....M.|
+000000c0 c2 9a 6e 0f ea d4 73 59 6a 59 28 79 7f 44 0c 32 |..n...sYjY(y.D.2|
+000000d0 29 22 51 d1 fb 00 c7 33 44 8b 19 71 98 8a 03 44 |)"Q....3D..q...D|
+000000e0 e0 95 ad 8f 91 66 e6 15 b8 99 b3 f8 2f 02 e9 a0 |.....f....../...|
+000000f0 4a 25 ec 3f 36 56 0c eb 0a a3 e0 d3 79 a1 b3 9e |J%.?6V......y...|
+00000100 dc 42 08 76 a4 c3 55 91 06 11 e7 0c 94 dd 71 fc |.B.v..U.......q.|
+00000110 bf 8a 87 d2 97 07 a3 b9 36 7e 58 ff ef b3 a3 f4 |........6~X.....|
+00000120 6e f1 23 d6 50 e3 23 d3 dc e7 20 ce 9d 84 17 cf |n.#.P.#... .....|
+00000130 2d 5f b1 f9 8d 36 41 7d ba 3b 93 63 2f bc be f0 |-_...6A}.;.c/...|
+00000140 a1 3a bb 5f b3 99 03 13 fb d2 2c 1a 8c cc 32 02 |.:._......,...2.|
+00000150 ef 93 b4 58 a8 f8 b1 42 52 24 c2 73 01 cb 5a fb |...X...BR$.s..Z.|
+00000160 9f fc 38 08 d7 f9 0d d7 20 fa dc 8b 1a 8c 73 0f |..8..... .....s.|
+00000170 f8 79 b2 84 e1 49 2d 8e 6d 46 16 38 0e 02 2a 2c |.y...I-.mF.8..*,|
+00000180 f4 44 89 da f1 7a 01 55 9e 93 a8 d6 d5 f5 72 28 |.D...z.U......r(|
+00000190 47 2b 4f 17 7e a5 01 fd ad 85 e0 6d f9 82 e8 cd |G+O.~......m....|
+000001a0 09 18 84 8c 9d 4f 4e a1 43 ff d6 3d 55 05 fc 56 |.....ON.C..=U..V|
+000001b0 e6 d6 b6 61 4a c7 c7 9c 62 64 26 1d 33 1e 4f d5 |...aJ...bd&.3.O.|
+000001c0 5e ee 1f a9 ad 24 e4 7f 05 cc 02 7a f7 e0 c2 ce |^....$.....z....|
+000001d0 b8 11 c9 a1 fd c5 d8 0e ef f8 c9 6a 2d 49 30 63 |...........j-I0c|
+000001e0 e3 9b 43 bf 87 e1 5f 55 39 fa 80 ec 84 55 59 5d |..C..._U9....UY]|
+000001f0 52 76 4c f4 70 eb 43 6a b2 07 d5 29 4c 58 39 04 |RvL.p.Cj...)LX9.|
+00000200 46 42 70 8d 28 61 7c d5 7a 3a 2e a0 9f 74 49 2d |FBp.(a|.z:...tI-|
+00000210 33 8d 39 18 70 8d 3c 50 4f 62 07 77 2d 15 1f 4b |3.9.p.<POb.w-..K|
+00000220 22 01 c6 cb ac 2f 2d 9a cf a6 9b 0e 24 99 41 64 |"..../-.....$.Ad|
+00000230 3e f2 9f 5f 17 7b d7 b8 3c b6 6d 24 5b 91 8c 13 |>.._.{..<.m$[...|
+00000240 1a 40 4e 80 7f 44 12 57 c9 03 57 c6 9b 54 0d 39 |.@N..D.W..W..T.9|
+00000250 91 88 72 3e c8 f9 18 eb 34 7c 0a eb 2d c8 56 1c |..r>....4|..-.V.|
+00000260 84 8a 62 a2 3a 0a 52 b8 5a b6 5d 54 78 ae 05 b2 |..b.:.R.Z.]Tx...|
+00000270 f4 6c 2d 5e 92 94 6b f3 1e 93 13 1a 65 74 60 e3 |.l-^..k.....et`.|
+00000280 dd 15 36 62 2b 71 b1 bb 59 19 08 af 8e 9b d0 47 |..6b+q..Y......G|
+00000290 05 7b a3 89 ac 68 cf a0 32 ba 4a 2b 9e 5f a5 dc |.{...h..2.J+._..|
+000002a0 b3 00 79 a8 1c f6 11 b8 6d 9c 51 b7 f1 f6 b2 13 |..y.....m.Q.....|
+000002b0 56 57 4e ac 97 ff 5a b8 52 33 0c c1 3d 52 81 6e |VWN...Z.R3..=R.n|
+000002c0 85 ba b2 04 4b eb 41 aa 03 ff ae 63 93 72 3a 5f |....K.A....c.r:_|
+000002d0 65 81 f9 6a 2a e4 70 f8 b3 59 31 51 62 ad 25 24 |e..j*.p..Y1Qb.%$|
+000002e0 82 0c b5 ad 7c 87 21 97 07 c0 c1 6d f0 22 97 0d |....|.!....m."..|
+000002f0 28 cf a7 4d 74 d2 9c ac d7 15 83 26 f7 2f 76 d4 |(..Mt......&./v.|
+00000300 ad cf e7 ef 1c f4 3e 1f b4 f4 4f 76 6a 98 15 01 |......>...Ovj...|
+00000310 cd 17 8b 17 03 03 00 99 0b 15 9d 16 c6 2a 52 53 |.............*RS|
+00000320 33 d7 01 db 8a 49 1d d6 83 b7 28 a4 07 f0 73 5e |3....I....(...s^|
+00000330 60 03 2c 6f 3f e0 88 a1 76 22 d6 23 0a df ca 86 |`.,o?...v".#....|
+00000340 b0 44 b9 1d 9a d7 53 f2 2b 57 a1 65 01 d4 e7 b4 |.D....S.+W.e....|
+00000350 9e 22 00 d2 20 da cd 55 7d 61 86 86 19 81 f9 ed |.".. ..U}a......|
+00000360 f8 af c4 69 54 1d 35 0a 6f 9e 69 40 13 08 82 dd |...iT.5.o.i@....|
+00000370 59 11 31 f2 81 a7 4b f1 bd d9 f2 5c 29 22 16 49 |Y.1...K....\)".I|
+00000380 86 62 8c a8 b8 89 58 96 cc d1 e4 e8 5e ef 6c b7 |.b....X.....^.l.|
+00000390 00 71 3d ab 92 b8 78 56 a7 25 5e a0 c4 d8 8c 02 |.q=...xV.%^.....|
+000003a0 c4 c8 eb d3 be 68 21 05 5c 5f 9c b0 ec 20 99 ff |.....h!.\_... ..|
+000003b0 00 17 03 03 00 35 c9 c1 5e 25 1c b9 64 8e c2 fd |.....5..^%..d...|
+000003c0 50 87 48 e6 02 36 75 31 67 f6 82 3c 94 79 7d 0b |P.H..6u1g..<.y}.|
+000003d0 cb 83 b1 f4 e1 00 5f a6 b6 2c 2d 63 40 ab 98 f9 |......_..,-c@...|
+000003e0 e3 8e 4a 7e d4 77 3d 55 90 10 75 17 03 03 00 93 |..J~.w=U..u.....|
+000003f0 47 c4 6e 19 29 c2 5e d5 93 b7 c2 cc 46 a9 49 9d |G.n.).^.....F.I.|
+00000400 8a 3b 9a 35 bb 45 22 13 b6 eb c9 ec ba 44 3c 24 |.;.5.E"......D<$|
+00000410 f2 ed bd 76 11 cc af 00 b3 89 63 5d 79 32 cc d7 |...v......c]y2..|
+00000420 5c 34 f3 5e 64 36 92 5d ac ac 33 74 f4 3d c4 b8 |\4.^d6.]..3t.=..|
+00000430 4d ac d0 49 4e 59 1c 16 74 8c 43 94 4b 13 b9 22 |M..INY..t.C.K.."|
+00000440 de d7 ee 30 09 63 f3 32 5f a2 9d a1 20 ea ee 91 |...0.c.2_... ...|
+00000450 ca d8 01 33 df 43 19 69 63 ee 6a 2c 80 99 ad f0 |...3.C.ic.j,....|
+00000460 5e 20 b6 b6 81 28 b6 9d 4a 9a 91 30 30 04 c1 70 |^ ...(..J..00..p|
+00000470 68 54 1e e0 72 00 4c fd 23 a8 41 a2 6a ab a3 01 |hT..r.L.#.A.j...|
+00000480 7a 40 1a |z@.|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 20 1f 0d 20 a8 |..........5 .. .|
+00000010 34 c4 dc fa f9 d6 2b fe 01 eb f1 54 f0 14 c2 2d |4.....+....T...-|
+00000020 bb 59 db 04 96 f2 18 8b bd 7e b0 38 b7 15 b5 d8 |.Y.......~.8....|
+00000030 6b f2 80 25 40 f6 97 67 fb 9e 5a 5c ad 33 c6 5f |k..%@..g..Z\.3._|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 1e 3a 8a fc 60 3a 99 ee b6 01 b7 fe |.....:..`:......|
+00000010 54 a9 2d 34 28 ae af 3b 6a bd e0 32 6b df 87 fe |T.-4(..;j..2k...|
+00000020 d0 97 8d 17 03 03 00 13 c6 89 d5 ae 4c fa d5 71 |............L..q|
+00000030 66 6e 07 b5 9b 00 e8 50 7e b9 5f |fn.....P~._|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-CHACHA20-SHA256 b/src/crypto/tls/testdata/Server-TLSv13-CHACHA20-SHA256
new file mode 100644
index 0000000..760c597
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-CHACHA20-SHA256
@@ -0,0 +1,100 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 dc 01 00 00 d8 03 03 7f d6 02 2f 2d |............../-|
+00000010 ed b1 3c f2 c2 48 5e d5 f4 57 c9 8c ba 81 36 52 |..<..H^..W....6R|
+00000020 85 3e 79 de 79 cc 36 6a f9 88 89 20 db e1 89 a5 |.>y.y.6j... ....|
+00000030 26 4c 2a 2d 0f 33 e2 3f 57 05 cc 74 cd 4c 96 be |&L*-.3.?W..t.L..|
+00000040 91 94 ef 54 1c 1f 01 ef d4 36 75 2f 00 04 13 03 |...T.....6u/....|
+00000050 00 ff 01 00 00 8b 00 00 00 0e 00 0c 00 00 09 31 |...............1|
+00000060 32 37 2e 30 2e 30 2e 31 00 0b 00 04 03 00 01 02 |27.0.0.1........|
+00000070 00 0a 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 |................|
+00000080 00 16 00 00 00 17 00 00 00 0d 00 1e 00 1c 04 03 |................|
+00000090 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 |................|
+000000a0 08 05 08 06 04 01 05 01 06 01 00 2b 00 03 02 03 |...........+....|
+000000b0 04 00 2d 00 02 01 01 00 33 00 26 00 24 00 1d 00 |..-.....3.&.$...|
+000000c0 20 30 20 a8 d0 3d ea df 38 aa 65 6f dd c8 25 13 | 0 ..=..8.eo..%.|
+000000d0 03 c4 a2 24 d4 a8 0d 1a a6 65 32 75 83 ef 71 70 |...$.....e2u..qp|
+000000e0 30 |0|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 db e1 89 a5 |........... ....|
+00000030 26 4c 2a 2d 0f 33 e2 3f 57 05 cc 74 cd 4c 96 be |&L*-.3.?W..t.L..|
+00000040 91 94 ef 54 1c 1f 01 ef d4 36 75 2f 13 03 00 00 |...T.....6u/....|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 17 f4 9a 6e ea 99 81 |............n...|
+00000090 59 33 26 a6 6a 40 1d a9 59 67 31 35 09 b0 ed 15 |Y3&.j@..Yg15....|
+000000a0 83 17 03 03 02 6d 56 59 69 c8 6d 45 c6 2f 58 3d |.....mVYi.mE./X=|
+000000b0 db 87 dd 56 0f 2d d9 21 1b 97 94 77 f2 72 28 0d |...V.-.!...w.r(.|
+000000c0 48 04 79 83 7e 2e a1 c9 30 56 d7 9c c8 0a 37 65 |H.y.~...0V....7e|
+000000d0 b6 6b 31 ae 9a 5f ff 13 15 94 99 7c 92 e1 32 80 |.k1.._.....|..2.|
+000000e0 28 3c ab b1 cc fe ba 92 3c 03 bb fd b8 55 f5 f2 |(<......<....U..|
+000000f0 ba be 28 90 c5 7e 07 48 d5 45 b6 84 80 02 2d cd |..(..~.H.E....-.|
+00000100 14 27 81 b6 4e b4 7f 5f 78 a3 26 c2 0c af 12 d6 |.'..N.._x.&.....|
+00000110 e9 14 22 c8 ee 2e 5e fc c3 ca 8f 01 9b 37 6a b0 |.."...^......7j.|
+00000120 f8 53 b2 8e 31 d7 1f 34 f6 35 ed 81 e0 f7 6f e1 |.S..1..4.5....o.|
+00000130 90 cf 1a 4f 44 50 d5 cd 96 c3 4a 22 7a 54 28 bd |...ODP....J"zT(.|
+00000140 88 56 5c 77 67 eb a6 78 5c 8b 82 39 03 13 55 c3 |.V\wg..x\..9..U.|
+00000150 20 68 45 26 7a 96 fe 1c f9 33 14 1e 1d 8a 5f 51 | hE&z....3...._Q|
+00000160 c3 2f 17 91 ba 37 63 49 e1 65 89 bf e8 a1 27 5f |./...7cI.e....'_|
+00000170 fd 59 46 80 f7 9b 45 89 50 ab cd 9b aa b4 45 04 |.YF...E.P.....E.|
+00000180 b5 1b 85 88 1c 59 ba b2 d6 50 0b fd 5c d9 59 83 |.....Y...P..\.Y.|
+00000190 7a 6c 9b ad 27 33 a0 49 74 eb a6 cd a8 e8 4b d7 |zl..'3.It.....K.|
+000001a0 71 ef 63 64 ff 24 a7 09 2e b7 f6 6f 9d 9f 75 84 |q.cd.$.....o..u.|
+000001b0 97 0a 76 bf 72 ed ff e8 1a 49 ca 0b 0d f5 2c fb |..v.r....I....,.|
+000001c0 69 c2 5c fe db 58 0a a1 9c d4 47 6a 8f a6 bd ec |i.\..X....Gj....|
+000001d0 32 fb 40 6a 71 9d 19 37 e6 fd d4 3d fa 5b f3 53 |2.@jq..7...=.[.S|
+000001e0 43 df d5 fa 53 29 40 70 77 a6 9e f7 03 7d 08 8b |C...S)@pw....}..|
+000001f0 5a 71 73 e5 af 45 58 56 9f 56 ad 73 aa d2 b3 7c |Zqs..EXV.V.s...||
+00000200 92 99 c8 04 16 bf ca f2 81 2e 29 c3 79 21 f1 11 |..........).y!..|
+00000210 92 f4 1d 34 24 73 e3 82 28 5a 31 70 45 da 8d 94 |...4$s..(Z1pE...|
+00000220 38 75 31 bc f9 e5 2b 11 7e fd bc 19 fe 65 ad 53 |8u1...+.~....e.S|
+00000230 e5 e6 17 b8 69 ea 54 fd 92 a9 41 7a 8c 7f da 4f |....i.T...Az...O|
+00000240 ba f1 9f a2 e2 5b e7 7a 23 17 9e 29 95 7e 72 79 |.....[.z#..).~ry|
+00000250 22 67 c5 68 0a 4d fb e9 64 61 3a 53 18 e7 dd 7d |"g.h.M..da:S...}|
+00000260 5b 16 b9 fa 69 95 82 eb ee 1a 30 97 93 97 fc ee |[...i.....0.....|
+00000270 9e 2b 22 64 08 7d 25 05 77 5e d7 bd 0e c3 9f a4 |.+"d.}%.w^......|
+00000280 f4 bf 77 3d 56 84 c8 a1 10 1c e0 5b da 39 3d 2d |..w=V......[.9=-|
+00000290 92 80 9a 07 b2 29 c5 ab e0 e1 1c ad ba 3e fa 4e |.....).......>.N|
+000002a0 65 4f 31 63 de 33 6a 5c af e0 88 70 fc 6e 6a a2 |eO1c.3j\...p.nj.|
+000002b0 ca da 2f 14 1d 4f 8c 7d 8d da 36 9b ea 7f 7e 79 |../..O.}..6...~y|
+000002c0 9c dc 4a 3b 69 d9 50 31 bb f2 f8 8a 7f 6e 73 bc |..J;i.P1.....ns.|
+000002d0 41 7c 3a 86 10 91 9b 3a 8e 3e c8 bc 6a c4 4d f2 |A|:....:.>..j.M.|
+000002e0 45 87 49 49 d2 2f aa 4d d0 6f e9 1e a4 d6 06 63 |E.II./.M.o.....c|
+000002f0 ac 90 ce 9a cb f7 97 55 2b e8 8c 8d 55 f6 32 26 |.......U+...U.2&|
+00000300 55 d4 60 0e c0 0b da 0e ac c9 4c c3 95 03 54 d7 |U.`.......L...T.|
+00000310 99 ec e1 17 03 03 00 99 c4 65 5e 67 e3 a1 98 d6 |.........e^g....|
+00000320 f8 34 15 ed a9 55 80 c7 c0 e7 ca 67 f1 cb 58 e2 |.4...U.....g..X.|
+00000330 6e 4d d4 9e 18 c3 37 c2 ff 72 bc cb 8e 6a 97 e2 |nM....7..r...j..|
+00000340 b5 83 75 34 2a 75 9f 7f 8e 1e 47 e6 cd 53 85 c5 |..u4*u....G..S..|
+00000350 69 b6 c0 46 9f 46 a8 09 6a 21 d5 af 36 d2 d0 ba |i..F.F..j!..6...|
+00000360 65 0f da a5 af eb 3a 0c 8b 85 00 2a dd 11 71 28 |e.....:....*..q(|
+00000370 5b 71 a9 df 69 20 8a d9 27 1e 4f 02 89 03 6f 27 |[q..i ..'.O...o'|
+00000380 20 e1 37 17 69 c2 62 3e 46 39 43 2d 64 43 f3 cc | .7.i.b>F9C-dC..|
+00000390 14 5f a0 73 06 bf 42 cb da 79 21 28 b1 a1 c4 de |._.s..B..y!(....|
+000003a0 39 98 83 ad 3a d6 05 fd 58 b0 2c 97 bf 48 74 0e |9...:...X.,..Ht.|
+000003b0 25 17 03 03 00 35 69 10 76 25 e3 9e 63 10 76 73 |%....5i.v%..c.vs|
+000003c0 f5 fc 90 2c 95 e5 dc 29 79 a0 ed 0a 3a 72 58 38 |...,...)y...:rX8|
+000003d0 bf b9 17 af 77 9f 05 92 af d4 a7 c7 d6 56 77 01 |....w........Vw.|
+000003e0 da 94 31 d2 be be 95 e1 b1 95 75 17 03 03 00 93 |..1.......u.....|
+000003f0 f9 fa a9 41 89 d3 e8 3b cb 11 63 76 56 fe 28 86 |...A...;..cvV.(.|
+00000400 87 b0 0f d0 4d a8 fb 22 e9 89 f6 40 8a db 51 be |....M.."...@..Q.|
+00000410 2c 9f 9c 39 f4 43 bc 1f b0 32 9b 9c 8e a6 6e e1 |,..9.C...2....n.|
+00000420 f3 f7 f0 91 ed 56 6f 2d be 37 6b 3b ed f7 5b a6 |.....Vo-.7k;..[.|
+00000430 d3 14 0a f9 58 b8 7b 37 fc 15 97 57 79 16 8c 0c |....X.{7...Wy...|
+00000440 d2 93 7a 58 b8 48 51 f7 58 82 7d a0 4b e1 41 f6 |..zX.HQ.X.}.K.A.|
+00000450 e1 44 12 1e ea 80 f3 b6 d0 72 ec 5c 84 01 6a b3 |.D.......r.\..j.|
+00000460 f7 83 b5 47 22 0b e7 03 60 09 a7 23 23 20 5e 6b |...G"...`..## ^k|
+00000470 f6 25 34 64 11 ad 46 90 db cb 13 f5 10 0a 75 e8 |.%4d..F.......u.|
+00000480 3e c8 03 |>..|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 27 f0 39 68 fc |..........5'.9h.|
+00000010 9f 6c a4 fd a7 cf 1f 25 67 54 3c e6 9e 7c 99 5a |.l.....%gT<..|.Z|
+00000020 e9 b7 3c 0c f2 dc b6 22 36 0d 43 a3 ee 76 4b a9 |..<...."6.C..vK.|
+00000030 6a cb b8 f6 8a c8 58 91 79 19 95 7c 83 a0 87 57 |j.....X.y..|...W|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 1e d5 8a ef 04 f9 6c 27 62 0a f1 a4 |..........l'b...|
+00000010 4b 7f e4 e4 ff 53 f3 61 20 b9 56 96 30 f9 06 c9 |K....S.a .V.0...|
+00000020 cc 9c ed 17 03 03 00 13 4a 83 cd 86 98 97 20 45 |........J..... E|
+00000030 ab 2f c5 72 15 f6 ed a8 8c 8c 0e |./.r.......|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-ClientAuthRequestedAndECDSAGiven b/src/crypto/tls/testdata/Server-TLSv13-ClientAuthRequestedAndECDSAGiven
new file mode 100644
index 0000000..0b6eaf4
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-ClientAuthRequestedAndECDSAGiven
@@ -0,0 +1,179 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 ca 01 00 00 c6 03 03 54 78 64 8e b6 |...........Txd..|
+00000010 69 c6 1c 8a 69 eb 09 ef 32 59 f9 9f 63 ac 6e 66 |i...i...2Y..c.nf|
+00000020 97 b4 bb b7 71 27 60 52 af c4 64 20 26 de 8d 3e |....q'`R..d &..>|
+00000030 90 5b c8 96 b5 10 a3 e4 67 f3 39 fb f5 b7 df 50 |.[......g.9....P|
+00000040 2b 8f 2d cb a5 c4 0a c9 28 1b c3 21 00 04 13 01 |+.-.....(..!....|
+00000050 00 ff 01 00 00 79 00 0b 00 04 03 00 01 02 00 0a |.....y..........|
+00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 16 |................|
+00000070 00 00 00 17 00 00 00 0d 00 1e 00 1c 04 03 05 03 |................|
+00000080 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 |................|
+00000090 08 06 04 01 05 01 06 01 00 2b 00 03 02 03 04 00 |.........+......|
+000000a0 2d 00 02 01 01 00 33 00 26 00 24 00 1d 00 20 65 |-.....3.&.$... e|
+000000b0 42 a2 bd 1e e0 0a 52 2d 7a 1e f0 37 86 db 9e c6 |B.....R-z..7....|
+000000c0 d6 cd ff 7b 71 f3 4c a3 23 44 2d 94 60 93 0b |...{q.L.#D-.`..|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 26 de 8d 3e |........... &..>|
+00000030 90 5b c8 96 b5 10 a3 e4 67 f3 39 fb f5 b7 df 50 |.[......g.9....P|
+00000040 2b 8f 2d cb a5 c4 0a c9 28 1b c3 21 13 01 00 00 |+.-.....(..!....|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 17 f1 7c 16 5a 86 b4 |...........|.Z..|
+00000090 13 82 93 fa ba 07 35 24 03 f5 24 25 cc 2d c8 e5 |......5$..$%.-..|
+000000a0 6c 17 03 03 00 3e cb 02 08 06 a3 75 03 c6 5d d9 |l....>.....u..].|
+000000b0 9c 66 ad db 29 6d 93 a6 53 c6 38 7f 9c 56 1e b1 |.f..)m..S.8..V..|
+000000c0 f5 a8 77 19 43 c3 93 5e 67 dc 80 db 1b c8 30 b2 |..w.C..^g.....0.|
+000000d0 04 85 6e 5c 8f 3a 4a f2 d2 aa 17 c7 d3 ea 29 f2 |..n\.:J.......).|
+000000e0 09 08 49 90 17 03 03 02 6d dd 26 0f f5 1b 6b 11 |..I.....m.&...k.|
+000000f0 1c c7 e9 87 bf de 58 08 e4 bc a6 49 98 fd bf 87 |......X....I....|
+00000100 31 35 59 c1 88 5a 8c 0d e7 42 47 b6 cb ec 3c 6f |15Y..Z...BG...<o|
+00000110 ba 01 4a bb 0c 7d d3 ae 0c 62 97 20 b5 f4 84 a0 |..J..}...b. ....|
+00000120 4c 30 87 8e 3c 11 24 b6 6f cc 8b de d4 ee 47 c0 |L0..<.$.o.....G.|
+00000130 47 92 00 0f 56 91 04 b3 42 93 1f 5c df 6e f6 f1 |G...V...B..\.n..|
+00000140 51 68 95 ad cd 4d 6e 7e 98 b9 57 da fb 01 45 45 |Qh...Mn~..W...EE|
+00000150 a7 d6 62 3d cb 48 f2 7c 18 03 52 50 51 c4 84 3e |..b=.H.|..RPQ..>|
+00000160 16 e6 ff be 29 a3 60 13 f8 8c 82 6c 84 dd c1 c8 |....).`....l....|
+00000170 8b a2 bf e5 70 03 c3 a4 92 3d 99 a8 fc 92 15 e4 |....p....=......|
+00000180 1d 13 7d b5 1f d3 a6 76 1c 8c 9f 9f e7 87 b4 fb |..}....v........|
+00000190 25 b8 cf 83 0a 3b bd c7 e8 30 d4 15 6f ae d5 b9 |%....;...0..o...|
+000001a0 da 3b c6 3f 0c 06 7a 78 e6 ac ca 64 cb 34 cc 7b |.;.?..zx...d.4.{|
+000001b0 46 78 ec e2 22 9e 31 39 63 a7 7b 1d d6 c2 4b 91 |Fx..".19c.{...K.|
+000001c0 45 fa 95 54 ef 9b b3 2e 55 83 77 c8 cf 15 b5 34 |E..T....U.w....4|
+000001d0 11 4c 92 36 22 54 3d 2f b0 cb 28 7f 2b 1e b1 3f |.L.6"T=/..(.+..?|
+000001e0 38 4a 4a d6 e8 a1 e6 e0 4f 20 ab 04 6f 6b 00 5e |8JJ.....O ..ok.^|
+000001f0 d4 16 42 ab a5 04 67 9b 89 45 78 8b ea 0e 7d c8 |..B...g..Ex...}.|
+00000200 24 d5 fb 83 c7 13 25 b7 1b 6f 3f 2a 2e cf bb 71 |$.....%..o?*...q|
+00000210 11 48 5d e6 98 5e ca dd f7 6d dc 93 b1 51 1e 99 |.H]..^...m...Q..|
+00000220 b9 e0 4c 39 c8 82 d8 9f 8d 70 25 78 5b b1 85 1d |..L9.....p%x[...|
+00000230 cb 75 31 61 c3 ad d5 c1 d5 1f 26 06 60 5f cd eb |.u1a......&.`_..|
+00000240 ee 4c 99 43 02 b9 e5 f5 99 98 94 cf 14 1c ad 54 |.L.C...........T|
+00000250 20 a9 d3 73 f2 3f bc a1 25 39 8b ff c4 e0 ee 8b | ..s.?..%9......|
+00000260 ba ec fc b0 c2 42 4c 5a 30 9c 26 1b f0 f2 da 94 |.....BLZ0.&.....|
+00000270 26 69 55 0e fb 84 a0 58 95 43 08 6c 87 82 93 02 |&iU....X.C.l....|
+00000280 cf 27 99 94 a3 ae 9f 08 d0 6e f2 a8 e8 29 fc a8 |.'.......n...)..|
+00000290 67 d3 20 37 83 5d 8a 12 0a 57 10 bf 30 5a e1 05 |g. 7.]...W..0Z..|
+000002a0 30 e0 b7 7b 47 7e a6 07 cc 9a dd 6d e8 11 89 c7 |0..{G~.....m....|
+000002b0 7d 98 c3 6d 83 9f 1b f4 ff ca 31 c8 39 7b c2 fb |}..m......1.9{..|
+000002c0 69 dc ee eb ab e2 39 72 35 6b 22 e4 84 2f 1d 58 |i.....9r5k"../.X|
+000002d0 07 b0 9e 3e 69 ca ff 17 44 d6 e4 a8 56 6a 24 35 |...>i...D...Vj$5|
+000002e0 08 39 42 41 da 76 4b 4f 00 ce 41 58 4e 70 d5 b6 |.9BA.vKO..AXNp..|
+000002f0 50 b4 88 91 47 4a 89 04 ef e8 14 2e cf e3 9d 36 |P...GJ.........6|
+00000300 c0 b5 2b 8e 42 2f 4b 95 39 55 6f 5a 23 5b 5e 05 |..+.B/K.9UoZ#[^.|
+00000310 f0 34 70 c0 f7 92 54 e2 5c 52 20 b0 c1 2a 9a cb |.4p...T.\R ..*..|
+00000320 3a 32 0e 93 77 96 f2 6a d8 f7 bc 7c d8 40 4e 5e |:2..w..j...|.@N^|
+00000330 37 1c 8b aa 75 89 94 51 da 19 72 80 86 c8 3d bd |7...u..Q..r...=.|
+00000340 fd 7d 06 13 bb 54 a1 0b 46 58 07 e5 35 b3 f3 ff |.}...T..FX..5...|
+00000350 8a 98 9d e6 e8 05 17 03 03 00 99 5a 63 3c ff cc |...........Zc<..|
+00000360 a0 ec 5f 52 4d 28 96 80 22 f7 8c a7 ad b7 1f 4a |.._RM(.."......J|
+00000370 8c 46 79 06 31 96 46 f9 f0 57 8c c4 5b f9 71 61 |.Fy.1.F..W..[.qa|
+00000380 34 0d 3e 78 67 05 1c 93 a7 a2 cd ea ce e5 a2 6e |4.>xg..........n|
+00000390 37 4f 16 a4 e4 4c 60 d5 5a 37 f1 2a bf ce 2f 80 |7O...L`.Z7.*../.|
+000003a0 ea 65 e6 25 03 fc 2b 17 3f a4 71 3f 04 46 2b f7 |.e.%..+.?.q?.F+.|
+000003b0 12 b0 a6 f3 fc 8d cf 5e 95 85 84 88 e4 db 46 a4 |.......^......F.|
+000003c0 f2 3a a5 27 44 3d a2 03 b3 65 af 1f e3 44 aa 02 |.:.'D=...e...D..|
+000003d0 0f 39 eb 3d 0e 2a ae 0c 1b ed 84 df 8d e3 a2 1d |.9.=.*..........|
+000003e0 6d 55 bf d6 13 f6 00 da 93 a7 fc b1 50 79 2c a9 |mU..........Py,.|
+000003f0 93 cb 7d 70 17 03 03 00 35 9e b7 c2 c6 29 a9 43 |..}p....5....).C|
+00000400 3f df 06 80 31 ac d9 f7 3b cd 14 16 a0 85 ca e6 |?...1...;.......|
+00000410 34 70 e3 fc af 1c 94 9b 87 b3 17 6c a4 83 64 2c |4p.........l..d,|
+00000420 6e 26 4c e9 ab 79 a9 c8 1d d4 1c 96 2c f2 |n&L..y......,.|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 02 1e 08 6d ee 1c 88 |............m...|
+00000010 63 86 93 3e 73 8e 87 6f 51 8b d3 d2 91 c5 cb 55 |c..>s..oQ......U|
+00000020 2d 7c 9f 32 d8 0a ab e5 53 95 4b 0c 22 12 23 56 |-|.2....S.K.".#V|
+00000030 07 ce 1b e1 46 f7 46 84 cb 47 83 62 4a 16 39 44 |....F.F..G.bJ.9D|
+00000040 bf 58 25 6e f1 22 d0 ea 06 d8 da 44 91 bb 27 41 |.X%n.".....D..'A|
+00000050 1f 6e 46 89 88 93 a7 0a 60 8f 1a e5 31 19 5c 27 |.nF.....`...1.\'|
+00000060 a3 f6 8c 1b ee 5b 2b 21 c4 64 c7 d9 92 7b e9 ca |.....[+!.d...{..|
+00000070 e0 16 29 d0 64 32 95 a8 8f a8 24 cc 56 c6 3e 7d |..).d2....$.V.>}|
+00000080 1b f6 06 a6 fa d6 dc 79 38 60 4f 6f b7 e1 10 ab |.......y8`Oo....|
+00000090 21 14 8e e1 90 95 6d b6 f3 ca 86 1a dd 32 c5 33 |!.....m......2.3|
+000000a0 e1 fc 8c da 77 02 54 88 73 f3 72 71 c6 58 ad 1a |....w.T.s.rq.X..|
+000000b0 10 b8 15 c3 69 f1 cc 71 b6 ea 7e b7 81 4b de 7b |....i..q..~..K.{|
+000000c0 77 87 24 e0 c0 39 5c 5b 17 ad 7c 59 53 43 cf 7e |w.$..9\[..|YSC.~|
+000000d0 cb 70 4d 51 f1 7e 8c 2b 19 61 13 75 bf 25 df 80 |.pMQ.~.+.a.u.%..|
+000000e0 f2 fa cd 70 8d db eb bc 38 ae 6a 0c ad ef d2 e2 |...p....8.j.....|
+000000f0 f0 f1 02 97 ce 37 8b 8f 9e bd 4f 92 40 e7 8f 9f |.....7....O.@...|
+00000100 26 b7 cd ef cf 57 28 2f 12 cc 69 e1 be f2 59 c6 |&....W(/..i...Y.|
+00000110 be dc 51 9a 67 be 4a f1 97 f9 7a d9 01 05 1f d0 |..Q.g.J...z.....|
+00000120 2b 96 5b b5 4d 1d c1 2e 99 7e eb e3 20 92 b0 f8 |+.[.M....~.. ...|
+00000130 ac 9f c1 e3 10 cd b1 e9 05 46 15 3c c2 fb ce 27 |.........F.<...'|
+00000140 5e f1 47 e7 d8 ca 89 0e 77 37 86 6c c9 d4 e3 ae |^.G.....w7.l....|
+00000150 1e 6e 63 4f 5c 2d aa a0 88 7c 35 47 87 e8 40 22 |.ncO\-...|5G..@"|
+00000160 f8 45 2f 57 b4 e8 e1 95 45 58 02 53 3c 19 b5 92 |.E/W....EX.S<...|
+00000170 73 55 fd 49 31 ec db dc 4c 6f 6f a7 9a 90 89 83 |sU.I1...Loo.....|
+00000180 08 97 53 5a c6 6c 23 75 cd 68 37 54 2c 00 d3 56 |..SZ.l#u.h7T,..V|
+00000190 5e 24 87 7b 92 a9 61 73 1e 84 31 0e ff d7 f2 fb |^$.{..as..1.....|
+000001a0 62 5e f9 27 35 18 bb ca b2 c2 d7 5c bf 7f 6d 36 |b^.'5......\..m6|
+000001b0 fa e6 02 4a d0 fa bd b8 c0 d0 2f 0c 27 6b 49 92 |...J....../.'kI.|
+000001c0 20 54 01 ea 3c d2 07 f1 2e d6 e3 a3 a3 bd 1d 33 | T..<..........3|
+000001d0 90 ee 26 ad a6 5c ee c7 de 4d e8 fc d2 b5 5a b5 |..&..\...M....Z.|
+000001e0 7c 6f c5 61 23 11 20 eb 0f 7c b7 0a cc 8c 65 b7 ||o.a#. ..|....e.|
+000001f0 e2 87 16 10 b0 fd 40 75 78 d1 3c 70 54 66 b8 cb |......@ux.<pTf..|
+00000200 a5 84 c6 ee af 57 3c 73 64 2d ba 5d b9 a3 93 84 |.....W<sd-.]....|
+00000210 d1 2e d4 87 15 4f 9b 1c e5 da 02 b0 c5 2e 9f 31 |.....O.........1|
+00000220 d4 3f 6e e8 b7 02 d3 f3 71 17 03 03 00 a4 14 81 |.?n.....q.......|
+00000230 dd 8d 55 4d 0a 18 cb 08 0a b0 1e e3 7d d6 54 8e |..UM........}.T.|
+00000240 e3 e6 5d 2a c8 59 6c 5e 19 a7 db 0f 96 b2 55 db |..]*.Yl^......U.|
+00000250 71 f8 6f bb a4 b8 d3 c7 a2 ee 01 c0 1a 15 00 20 |q.o............ |
+00000260 1a 88 07 b5 69 83 4d 8b 45 65 da 6d e5 df c2 82 |....i.M.Ee.m....|
+00000270 a3 b5 92 75 7b 76 86 f8 f8 13 63 c9 37 2f 06 ce |...u{v....c.7/..|
+00000280 7c 64 da 08 1f 4e a3 4f a4 5a 4a 36 a3 b8 99 6f ||d...N.O.ZJ6...o|
+00000290 fa b2 8a f6 41 91 ea 5e 6c bd c9 40 65 a1 10 08 |....A..^l..@e...|
+000002a0 c2 a5 2e 13 d9 ce 59 d8 fb d1 48 77 94 5a 2d d0 |......Y...Hw.Z-.|
+000002b0 23 ba 02 4a 55 b5 be da ca c1 61 f5 15 d0 7a ba |#..JU.....a...z.|
+000002c0 a4 cf e7 1f 1d 99 32 cf 41 19 87 eb 79 97 0e fa |......2.A...y...|
+000002d0 6e ae 17 03 03 00 35 7c 26 f7 77 3f 3c 10 90 47 |n.....5|&.w?<..G|
+000002e0 54 bd e7 c6 b7 9e 14 a9 ca 3a 12 c8 42 9a e1 38 |T........:..B..8|
+000002f0 e4 60 ed a9 4a d8 d3 6d 15 ab b2 f2 16 81 09 b1 |.`..J..m........|
+00000300 fd b5 56 67 8d e0 b1 e9 4b b9 ad 7a |..Vg....K..z|
+>>> Flow 4 (server to client)
+00000000 17 03 03 02 98 07 3b b6 4e c1 7e 84 44 a0 5d 3c |......;.N.~.D.]<|
+00000010 b8 45 37 1e bf 0f 43 cf d6 11 c7 0d d9 a4 25 7b |.E7...C.......%{|
+00000020 27 fa 6e e1 9c 24 5f e5 f9 12 e8 a1 33 2e cc 24 |'.n..$_.....3..$|
+00000030 43 3b ac e3 bd f2 7b 1d 66 70 eb 31 21 7f 3e 5e |C;....{.fp.1!.>^|
+00000040 09 7a 29 8f 43 43 cb c4 6d 70 a7 51 1c 0f dc 21 |.z).CC..mp.Q...!|
+00000050 e9 4c f5 16 8f 35 e8 5b ae 7f e0 47 e7 d4 53 66 |.L...5.[...G..Sf|
+00000060 b2 cc ef 44 b7 3e 34 2b 32 a9 e6 89 b9 c6 f6 56 |...D.>4+2......V|
+00000070 97 b3 78 37 3c 89 2f 35 8e a5 c7 ae c4 92 91 69 |..x7<./5.......i|
+00000080 50 ae ee c9 7b 7a 3a 10 ce 1c 68 fd 09 57 3d 92 |P...{z:...h..W=.|
+00000090 52 42 0e 4e 91 12 b4 fd e4 59 d4 1e 5a c7 25 b3 |RB.N.....Y..Z.%.|
+000000a0 dd a1 dd 7d 7d 92 08 52 ec 85 15 c7 b6 60 70 fb |...}}..R.....`p.|
+000000b0 76 6b 42 da 84 8e e5 a9 cb a4 b1 76 89 51 93 55 |vkB........v.Q.U|
+000000c0 f3 92 aa cc 04 3b 78 97 ed 10 88 d8 77 d1 32 35 |.....;x.....w.25|
+000000d0 93 82 a4 1d ca 47 df c8 72 93 10 90 e0 75 2d 3f |.....G..r....u-?|
+000000e0 b0 6a 3d 9e b6 20 1d 0a 2a 03 66 be 18 18 d3 25 |.j=.. ..*.f....%|
+000000f0 47 a2 ab 67 08 44 24 cb 94 29 8a f7 8b 8e ca a0 |G..g.D$..)......|
+00000100 20 71 d0 af 87 5b e1 d9 5d e0 0c 70 13 3d 82 42 | q...[..]..p.=.B|
+00000110 b3 b8 fb 5e 1d f1 58 88 ea 11 67 28 49 11 d4 27 |...^..X...g(I..'|
+00000120 05 87 e4 b1 21 15 d1 3a 6a df ee 6d 40 7c 3f 8c |....!..:j..m@|?.|
+00000130 7e cd 7b 0c 0e ef fd 17 29 29 f8 03 98 8e 76 ac |~.{.....))....v.|
+00000140 23 e2 81 30 8b c7 7b 9b 5a 78 f7 6a 53 32 5c bd |#..0..{.Zx.jS2\.|
+00000150 d7 42 cb 77 f5 1d ea 03 74 9f ec 1d 1b 68 72 aa |.B.w....t....hr.|
+00000160 9f e0 7d 58 2f 26 47 6b 2d e4 1f 78 f4 ab d3 ae |..}X/&Gk-..x....|
+00000170 51 6c 2a 35 0a 6f 9a c8 2b 75 ff 69 3e 4b 61 bc |Ql*5.o..+u.i>Ka.|
+00000180 03 29 60 04 8b 53 9f ae e4 00 7f 88 7a d4 70 b8 |.)`..S......z.p.|
+00000190 65 83 87 96 5d ef f1 b2 e8 7e 0e af 0b 2c 07 dd |e...]....~...,..|
+000001a0 a9 0e f8 c3 9b 59 aa cf 74 02 5e 46 8c cb 3d ee |.....Y..t.^F..=.|
+000001b0 72 67 7c 46 37 29 78 d8 80 6e 42 16 b7 a8 59 35 |rg|F7)x..nB...Y5|
+000001c0 cb 36 ce 73 50 80 d2 35 7a 69 b9 f3 14 73 04 e7 |.6.sP..5zi...s..|
+000001d0 ec dd 92 80 b0 f6 b7 51 28 15 56 c4 bb 83 00 86 |.......Q(.V.....|
+000001e0 9e 21 e7 bd 91 33 15 d4 aa da 8a 07 eb 2e d9 48 |.!...3.........H|
+000001f0 c3 71 1a da be 6f 00 45 bd 08 a3 70 17 d5 c0 1a |.q...o.E...p....|
+00000200 74 87 5a 95 60 aa 1d ce 0e e1 46 57 85 8c e0 ae |t.Z.`.....FW....|
+00000210 98 1a f9 83 7f ec 04 bd 90 dc 51 4f 7e d2 52 28 |..........QO~.R(|
+00000220 ca 33 f6 60 4a 0c e4 7d b3 93 4f 70 7a ce d3 3e |.3.`J..}..Opz..>|
+00000230 0a dd 50 b0 17 0a 2e db 2c ad 3d 86 d3 e6 60 07 |..P.....,.=...`.|
+00000240 43 61 9c a0 ff 45 37 9a 60 3d c5 f7 4d 27 fc b4 |Ca...E7.`=..M'..|
+00000250 9a 05 1c 0a ae 08 9d d9 5c 15 09 c9 8e 24 bb e2 |........\....$..|
+00000260 ec a1 a7 27 f0 42 97 a9 af ed 25 fd 5f f1 2a 4d |...'.B....%._.*M|
+00000270 ac ab 9c a5 7d 28 6b c8 36 ec 0c 12 5b eb fa 64 |....}(k.6...[..d|
+00000280 83 74 13 6e 44 5a 23 38 f0 a6 22 3e f9 88 f1 0d |.t.nDZ#8..">....|
+00000290 2a 55 b8 bf aa 87 de a4 7f 8b ba 52 23 17 03 03 |*U.........R#...|
+000002a0 00 1e fb 80 15 2b ff db 63 29 a7 77 ef 1e 82 28 |.....+..c).w...(|
+000002b0 8d d5 f0 5b 5d 42 8e 34 f9 64 5c 47 eb c3 10 4c |...[]B.4.d\G...L|
+000002c0 17 03 03 00 13 a1 8b 9e d8 57 0e 04 96 7c b4 83 |.........W...|..|
+000002d0 70 a2 20 03 ee 28 23 c7 |p. ..(#.|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-ClientAuthRequestedAndEd25519Given b/src/crypto/tls/testdata/Server-TLSv13-ClientAuthRequestedAndEd25519Given
new file mode 100644
index 0000000..d80b76f
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-ClientAuthRequestedAndEd25519Given
@@ -0,0 +1,149 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 ca 01 00 00 c6 03 03 3d 6d 5a b0 92 |...........=mZ..|
+00000010 7b 62 6d 14 22 f5 08 70 77 4a 80 fa 69 1a 1c 92 |{bm."..pwJ..i...|
+00000020 4c d3 e5 ca 3a d0 ee 33 40 c8 64 20 e5 a7 f1 57 |L...:..3@.d ...W|
+00000030 39 32 e3 9f 7c 33 58 16 61 58 29 44 aa e4 50 b1 |92..|3X.aX)D..P.|
+00000040 37 c5 59 27 f2 d5 b8 6e 01 24 c2 6b 00 04 13 01 |7.Y'...n.$.k....|
+00000050 00 ff 01 00 00 79 00 0b 00 04 03 00 01 02 00 0a |.....y..........|
+00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 16 |................|
+00000070 00 00 00 17 00 00 00 0d 00 1e 00 1c 04 03 05 03 |................|
+00000080 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 |................|
+00000090 08 06 04 01 05 01 06 01 00 2b 00 03 02 03 04 00 |.........+......|
+000000a0 2d 00 02 01 01 00 33 00 26 00 24 00 1d 00 20 cb |-.....3.&.$... .|
+000000b0 da f4 03 da e7 6f e5 2b 25 c0 cb cf 52 0a fb af |.....o.+%...R...|
+000000c0 8a 87 4c 2b 88 e4 1a b3 a0 34 30 fb 9d 4e 0e |..L+.....40..N.|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 e5 a7 f1 57 |........... ...W|
+00000030 39 32 e3 9f 7c 33 58 16 61 58 29 44 aa e4 50 b1 |92..|3X.aX)D..P.|
+00000040 37 c5 59 27 f2 d5 b8 6e 01 24 c2 6b 13 01 00 00 |7.Y'...n.$.k....|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 17 2d 8b 08 3c eb 5e |..........-..<.^|
+00000090 e6 d7 8e 9a 11 d0 e1 a3 3f 88 cc 83 49 e3 af 50 |........?...I..P|
+000000a0 66 17 03 03 00 3e 24 ba 0e 2f d7 51 a9 52 5d 51 |f....>$../.Q.R]Q|
+000000b0 a4 7d b6 dc 5c 43 2e d8 58 5e 72 f1 86 98 15 b8 |.}..\C..X^r.....|
+000000c0 db 0a 48 0a 06 c4 ad 36 41 84 f1 89 36 e9 24 da |..H....6A...6.$.|
+000000d0 05 5a dc 82 02 a1 3d 39 ae 4c 7e d9 7b 43 1f 2c |.Z....=9.L~.{C.,|
+000000e0 06 71 a0 2f 17 03 03 02 6d 48 44 6b d1 65 fb e1 |.q./....mHDk.e..|
+000000f0 fb 96 00 e5 ad c6 60 e2 b5 f6 bf 7c b7 f4 6f 0e |......`....|..o.|
+00000100 db a2 4b f7 cd d7 73 29 f8 af 23 5d d4 55 df 37 |..K...s)..#].U.7|
+00000110 b7 62 38 d0 95 5c f1 48 32 5f cb fa 67 18 20 7f |.b8..\.H2_..g. .|
+00000120 b7 0f ac fc 64 b7 b0 7b 4b 1f 65 1d 2a 94 8d 76 |....d..{K.e.*..v|
+00000130 b4 30 3b ee 44 a5 f6 74 5b 7e bd a7 bb b2 d8 d6 |.0;.D..t[~......|
+00000140 ac c6 1f b4 88 34 85 7e 89 2c 2e 0d bf 6c 16 0c |.....4.~.,...l..|
+00000150 ce 35 57 13 29 55 60 20 86 21 20 c0 46 bc 9e dd |.5W.)U` .! .F...|
+00000160 8a a0 41 60 b5 a9 16 cc 66 cb 4a ba 58 e0 70 d1 |..A`....f.J.X.p.|
+00000170 a5 b4 eb ac 54 7e 95 11 00 f0 70 63 af 56 57 99 |....T~....pc.VW.|
+00000180 68 57 b4 5b aa db f1 08 2e c0 fb df 93 b8 4a f8 |hW.[..........J.|
+00000190 2e 04 b3 2c 2b f9 47 09 a1 5f a3 3e 97 eb d4 d5 |...,+.G.._.>....|
+000001a0 df ec d1 9e 05 5e 10 b0 2b 7e 0e b4 c8 e1 e3 50 |.....^..+~.....P|
+000001b0 29 19 8b 3c f7 d0 95 30 ae 4c e4 60 c8 13 09 15 |)..<...0.L.`....|
+000001c0 b7 80 f3 ad a0 06 6b a7 b7 4a c4 6d 65 09 21 d3 |......k..J.me.!.|
+000001d0 3b 56 dc ce f5 d3 fa 93 e9 03 8e 0c c9 47 21 89 |;V...........G!.|
+000001e0 7f 39 23 f8 aa 68 f6 b4 82 50 1f b8 46 5d 26 dc |.9#..h...P..F]&.|
+000001f0 b1 1f e5 e5 6b ad ad 0d d8 55 b7 8b 7a f8 5d fc |....k....U..z.].|
+00000200 bd 74 a4 15 72 33 1b a7 3b 8c 09 55 d9 fd 21 bf |.t..r3..;..U..!.|
+00000210 cd dd 67 d2 0c d0 bd 9b de 52 e3 5f 4d 54 c0 6c |..g......R._MT.l|
+00000220 bd 93 ae 66 55 4b e9 75 6b db cd 6b 80 33 f4 b7 |...fUK.uk..k.3..|
+00000230 61 9e e4 5d 75 b5 44 26 79 b5 da bf af 54 8c 40 |a..]u.D&y....T.@|
+00000240 23 99 32 60 2a 76 b3 0a 46 37 c9 85 1c fe e9 a1 |#.2`*v..F7......|
+00000250 a3 e8 61 67 04 eb 3e e8 2b d3 12 75 87 04 67 40 |..ag..>.+..u..g@|
+00000260 19 63 c5 ef 75 d0 39 63 a0 c3 ae 3c b1 88 34 db |.c..u.9c...<..4.|
+00000270 c7 29 0c 33 c8 40 c0 b0 e6 76 44 cc 99 4f 2b a6 |.).3.@...vD..O+.|
+00000280 b3 e1 28 69 6c 41 74 55 53 a9 87 06 9a cb 14 5d |..(ilAtUS......]|
+00000290 ec 74 77 e2 a0 ce 54 02 ba f8 04 2c 84 9a de 2b |.tw...T....,...+|
+000002a0 dc 02 32 01 ad 96 5c a0 87 3c 55 dd ee 4d cb fd |..2...\..<U..M..|
+000002b0 ee a1 d4 9e 3f fd 66 10 fc eb cf 2e d3 f1 aa 9d |....?.f.........|
+000002c0 a2 fe 37 d5 b7 c7 6a b2 59 48 7a 57 9f 45 ff 22 |..7...j.YHzW.E."|
+000002d0 4c e2 dd 50 72 00 e0 9e af 35 7e 19 32 f2 f8 f0 |L..Pr....5~.2...|
+000002e0 5c af ff 4f e8 37 44 8a 12 f5 14 e6 c2 79 7e 90 |\..O.7D......y~.|
+000002f0 72 65 b7 cf f4 51 fc c9 fb 08 80 ef d5 4c ba 4e |re...Q.......L.N|
+00000300 a0 e2 0a 72 1a 4c 02 35 14 59 41 02 28 73 12 94 |...r.L.5.YA.(s..|
+00000310 ef 39 c5 b8 0e 43 ae 4e 0e 96 de d3 6e 25 8f ae |.9...C.N....n%..|
+00000320 ff 52 c2 ca 22 bb 77 b3 48 0c 9b e8 c1 0c 03 94 |.R..".w.H.......|
+00000330 a9 1e a5 6b 00 46 39 f7 52 4f 39 14 07 40 99 5a |...k.F9.RO9..@.Z|
+00000340 b0 c0 ba d3 0f a6 1e 30 ab 06 b4 5a b6 21 c6 93 |.......0...Z.!..|
+00000350 88 f8 a4 18 4d 37 17 03 03 00 99 87 d1 c8 64 88 |....M7........d.|
+00000360 d3 01 40 b6 89 cd 3d 26 a9 ea 36 bb 13 29 fa a0 |..@...=&..6..)..|
+00000370 f2 ba 28 65 a9 55 05 ff 47 53 37 0d 09 c6 30 b2 |..(e.U..GS7...0.|
+00000380 be 9f 31 e3 97 bc 5f 06 25 c2 d1 8a b6 3b c1 4e |..1..._.%....;.N|
+00000390 54 1a ea 57 2a 10 33 df ec 57 27 2e 71 a9 ea 16 |T..W*.3..W'.q...|
+000003a0 09 98 dd 40 f1 4d f3 34 d8 c5 f9 7a d3 db 57 f1 |...@.M.4...z..W.|
+000003b0 cc e8 1a 0f 88 51 ba 52 23 5f e9 91 f5 e3 1c ef |.....Q.R#_......|
+000003c0 59 b1 e1 e5 da 64 0e 56 00 65 77 82 32 b9 eb bd |Y....d.V.ew.2...|
+000003d0 d2 07 87 cd 83 94 39 63 64 90 d7 e7 8e 25 b9 66 |......9cd....%.f|
+000003e0 34 d3 a1 80 06 33 4d c9 69 ff ab 28 12 b9 19 a4 |4....3M.i..(....|
+000003f0 a6 05 94 db 17 03 03 00 35 68 36 21 a4 85 d8 96 |........5h6!....|
+00000400 52 51 a3 99 61 41 1e c4 84 97 9f 85 ed da d7 72 |RQ..aA.........r|
+00000410 79 ce 52 3a b9 31 31 19 f3 e5 d7 03 72 0c ab a9 |y.R:.11.....r...|
+00000420 7c 0f 17 38 9c 82 26 a5 95 1f 02 85 5b f6 ||..8..&.....[.|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 01 50 d8 03 a6 37 13 |..........P...7.|
+00000010 5f fb 65 9f 33 33 79 ae 89 c3 de ea 4b 55 e2 b3 |_.e.33y.....KU..|
+00000020 13 07 0d 95 c6 f7 79 74 ad 8a 42 dd 78 55 a5 01 |......yt..B.xU..|
+00000030 69 f2 11 cf 72 de 85 04 56 78 9c ba 21 77 b8 76 |i...r...Vx..!w.v|
+00000040 e3 58 23 3d 2b 8a ee a4 5c 52 60 4b 50 0d c4 83 |.X#=+...\R`KP...|
+00000050 a1 8d 06 82 68 99 34 65 7a 7b 55 8e 46 04 47 55 |....h.4ez{U.F.GU|
+00000060 4d 42 02 41 b6 e4 dd a4 33 6a 04 97 e6 4a 80 3a |MB.A....3j...J.:|
+00000070 e1 7e 0a a5 4f 0c f9 de 7a 91 96 4f 6a 6a 8a 4b |.~..O...z..Ojj.K|
+00000080 fd 24 b9 bf e7 d5 5a 27 17 18 45 77 1d e2 c9 ea |.$....Z'..Ew....|
+00000090 23 57 c4 e1 30 9e de d2 bd 0c 28 59 dc a1 12 d9 |#W..0.....(Y....|
+000000a0 ee 2e 43 4b 83 fc d7 6c a4 e7 47 c4 14 c1 1f ee |..CK...l..G.....|
+000000b0 79 60 26 86 73 5c ec c9 c0 ec f9 c9 38 98 2d ba |y`&.s\......8.-.|
+000000c0 10 83 1b fe 8f cf 59 77 f0 60 fe c0 d0 7e 0f 2d |......Yw.`...~.-|
+000000d0 69 04 dd 79 49 c5 b1 d9 9b 48 ad de 55 cf d3 47 |i..yI....H..U..G|
+000000e0 9b eb 64 ae ed cb b0 48 78 a9 27 24 b8 8d 53 36 |..d....Hx.'$..S6|
+000000f0 b7 0f 82 1c ee 11 4b 5a 98 1d 21 73 b4 f4 06 ce |......KZ..!s....|
+00000100 50 bc 36 27 e1 87 70 04 68 1b 30 3a 86 68 b3 71 |P.6'..p.h.0:.h.q|
+00000110 8c 57 69 60 d6 a8 bd fa 13 46 2b 52 00 dc 45 53 |.Wi`.....F+R..ES|
+00000120 06 79 5b 96 78 69 d0 a8 cd 2d 39 8c 11 12 9f 65 |.y[.xi...-9....e|
+00000130 72 01 5e b4 c5 df bc 9d a2 7f 00 a7 cc 95 3b 0b |r.^...........;.|
+00000140 09 05 19 9f a5 b7 dd 48 3f ab f1 aa 36 da 70 96 |.......H?...6.p.|
+00000150 0f f9 f3 bc 80 84 09 a3 76 92 56 17 03 03 00 59 |........v.V....Y|
+00000160 4a ba a9 1c c7 f6 ef 77 8e cc 9a 8c 51 9f 43 1e |J......w....Q.C.|
+00000170 ec 8f f3 33 93 eb 81 db 06 03 97 fd 3f b2 e0 e5 |...3........?...|
+00000180 e7 73 b2 2c 2c f0 c0 a4 51 18 10 79 4e 30 96 3a |.s.,,...Q..yN0.:|
+00000190 d8 26 b1 a0 f4 1b e6 12 fe 74 58 68 97 45 1e 85 |.&.......tXh.E..|
+000001a0 3a db 04 a6 12 5d ba 19 e4 f6 b1 17 f3 04 75 f2 |:....]........u.|
+000001b0 ea 04 db 6c d4 d8 d5 cc fb 17 03 03 00 35 1d c5 |...l.........5..|
+000001c0 cd 92 9c 80 3a ec 3c 06 3e 12 ed 7a 82 23 ab 18 |....:.<.>..z.#..|
+000001d0 67 4a 92 7d 30 e4 57 7b 25 34 a1 54 46 41 b7 60 |gJ.}0.W{%4.TFA.`|
+000001e0 69 cf a2 61 7a 59 6f b3 78 6f 41 0f 7d 9b 4f 00 |i..azYo.xoA.}.O.|
+000001f0 91 c7 93 |...|
+>>> Flow 4 (server to client)
+00000000 17 03 03 01 ca 52 99 bb 74 e8 8e ab 48 c6 03 1d |.....R..t...H...|
+00000010 f9 9a a8 be e4 b1 dc b9 8d e5 a8 11 2b d6 54 63 |............+.Tc|
+00000020 6f 0d dc 6e d7 55 c8 af 3c 88 c4 3e ab 30 ab b9 |o..n.U..<..>.0..|
+00000030 69 94 75 60 0f 75 77 e1 b1 29 09 9f db c1 74 43 |i.u`.uw..)....tC|
+00000040 92 2a 55 b9 ae 71 12 79 b9 4d ba 82 84 96 b1 01 |.*U..q.y.M......|
+00000050 14 b5 9c 5d 0c fe eb cc a6 44 e5 0b 93 1c 8d 45 |...].....D.....E|
+00000060 d8 aa 7c 1b d1 47 5a 36 46 f8 f5 82 c7 fe 2b f3 |..|..GZ6F.....+.|
+00000070 46 17 9f 0c 03 df cd dd 0a 38 77 28 45 45 f2 3c |F........8w(EE.<|
+00000080 06 1d 88 1b 55 d8 8f 70 9b a8 bb 37 a8 41 81 a6 |....U..p...7.A..|
+00000090 a7 f4 28 c1 f1 d2 8b ba 98 0e 35 92 88 ac cb b6 |..(.......5.....|
+000000a0 25 dd 5e 62 d5 e7 e9 da 4f 0e 55 b4 36 4d 09 20 |%.^b....O.U.6M. |
+000000b0 73 ef b3 6c 4c 6d c6 6a e9 f3 f8 28 74 0d 50 b0 |s..lLm.j...(t.P.|
+000000c0 ad 75 f7 c5 fb eb bc 06 6b 07 23 80 70 87 8e a8 |.u......k.#.p...|
+000000d0 3e 66 87 07 53 8e 19 bb 3f 94 f1 9e 4b 05 f6 55 |>f..S...?...K..U|
+000000e0 34 3b d0 14 36 32 66 6a 62 8a ec 22 a1 82 0a 95 |4;..62fjb.."....|
+000000f0 95 b6 85 0c 2c c4 b4 3e 00 59 2a 1e c6 03 4b 2a |....,..>.Y*...K*|
+00000100 e4 06 d5 29 e5 a1 e1 57 b0 a1 45 1b b7 0c 12 3f |...)...W..E....?|
+00000110 0d 31 1a b2 ef 3d 90 73 3a 39 28 00 8a 0d e0 20 |.1...=.s:9(.... |
+00000120 83 a7 32 b8 02 d0 9f 90 f3 b3 ca df 36 ae d4 f8 |..2.........6...|
+00000130 c4 4b 82 06 13 04 66 e7 01 63 4e e8 80 b8 52 c0 |.K....f..cN...R.|
+00000140 8c a4 5b 3f b9 85 48 ac 01 f0 b6 ee db 73 d0 62 |..[?..H......s.b|
+00000150 e2 05 e7 71 7e 87 4b 7b cf d0 a1 77 eb 38 64 85 |...q~.K{...w.8d.|
+00000160 5c 3d af fc e3 17 46 e7 c5 71 c9 63 bf 03 ae 35 |\=....F..q.c...5|
+00000170 7b 60 61 5d 5a 7b 57 88 79 82 55 68 45 a1 59 bc |{`a]Z{W.y.UhE.Y.|
+00000180 e5 3b 5a 31 32 5c 24 13 e3 fc b7 53 41 76 1d 24 |.;Z12\$....SAv.$|
+00000190 7f 08 89 c6 f0 b9 57 3a 4d 91 66 66 e4 57 33 51 |......W:M.ff.W3Q|
+000001a0 1d b9 1e c5 68 9a 6a 74 1e c3 16 de 15 92 e3 d0 |....h.jt........|
+000001b0 0a 64 a4 64 e8 c4 a5 9c 55 30 a9 c3 b0 53 72 54 |.d.d....U0...SrT|
+000001c0 75 d7 a0 7a 54 85 6e 9a 4d ff 9f 13 3c b9 42 17 |u..zT.n.M...<.B.|
+000001d0 03 03 00 1e 6f 06 3f 1c da f6 55 50 05 de 38 9d |....o.?...UP..8.|
+000001e0 07 00 bb 28 32 a5 3f 04 22 4c 6e f2 ea 3a e0 cc |...(2.?."Ln..:..|
+000001f0 5d 5b 17 03 03 00 13 3b b8 7c df 14 b4 ba fa 6e |][.....;.|.....n|
+00000200 2e 61 d6 6b bf b5 ad c2 35 73 |.a.k....5s|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-ClientAuthRequestedAndGiven b/src/crypto/tls/testdata/Server-TLSv13-ClientAuthRequestedAndGiven
new file mode 100644
index 0000000..800f999
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-ClientAuthRequestedAndGiven
@@ -0,0 +1,177 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 ca 01 00 00 c6 03 03 c8 2f b4 54 5b |............/.T[|
+00000010 11 8a 88 a9 a2 9b bf 66 f2 b4 e5 fb 32 af d6 dd |.......f....2...|
+00000020 6c 6c 99 4f d6 48 cd eb 63 6e 1d 20 bb 0a 48 2e |ll.O.H..cn. ..H.|
+00000030 45 4e 86 2d ae d6 fb 3e 0c 3e 9f a3 17 4a e3 39 |EN.-...>.>...J.9|
+00000040 58 a7 92 92 cb 30 03 0d be b5 79 a5 00 04 13 01 |X....0....y.....|
+00000050 00 ff 01 00 00 79 00 0b 00 04 03 00 01 02 00 0a |.....y..........|
+00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 16 |................|
+00000070 00 00 00 17 00 00 00 0d 00 1e 00 1c 04 03 05 03 |................|
+00000080 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 |................|
+00000090 08 06 04 01 05 01 06 01 00 2b 00 03 02 03 04 00 |.........+......|
+000000a0 2d 00 02 01 01 00 33 00 26 00 24 00 1d 00 20 f0 |-.....3.&.$... .|
+000000b0 8e 19 a6 04 b7 f1 b0 cd a1 28 bb 10 60 30 92 dc |.........(..`0..|
+000000c0 bc 7a 1c fc a7 f4 dc 01 2e 88 f3 0e 80 82 71 |.z............q|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 bb 0a 48 2e |........... ..H.|
+00000030 45 4e 86 2d ae d6 fb 3e 0c 3e 9f a3 17 4a e3 39 |EN.-...>.>...J.9|
+00000040 58 a7 92 92 cb 30 03 0d be b5 79 a5 13 01 00 00 |X....0....y.....|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 17 1a 9d c2 a8 12 c1 |................|
+00000090 c3 97 41 bd 1f 6e 48 98 36 4b 13 cd b9 9f 70 34 |..A..nH.6K....p4|
+000000a0 60 17 03 03 00 3e f8 19 ab 88 f7 15 07 97 72 ec |`....>........r.|
+000000b0 41 6c 0a 64 b3 26 4a 56 21 20 d7 9c a2 84 06 ab |Al.d.&JV! ......|
+000000c0 cb e6 99 1b 45 ce ca e7 c6 57 04 c9 3a 76 84 97 |....E....W..:v..|
+000000d0 fe a3 be 60 b2 2c 53 31 ab cd 49 d5 fc 59 80 69 |...`.,S1..I..Y.i|
+000000e0 38 d3 66 32 17 03 03 02 6d 8f 8b 7a 7d 78 d3 4b |8.f2....m..z}x.K|
+000000f0 98 1e 0b 05 38 60 58 d0 0a 7a f8 a7 70 53 67 ce |....8`X..z..pSg.|
+00000100 ea ed 86 3e 79 9d 37 66 b2 61 be 34 bf 15 5a d8 |...>y.7f.a.4..Z.|
+00000110 4e fb 52 62 8d e2 ae e9 58 b9 bc f9 e9 75 81 16 |N.Rb....X....u..|
+00000120 af fa 92 c3 aa ac d2 2c 7b c2 21 2f b0 0d e9 53 |.......,{.!/...S|
+00000130 d3 e3 ec d5 e7 95 23 83 d9 b1 ff 25 55 47 6a 1c |......#....%UGj.|
+00000140 97 37 84 9a ce 67 15 63 0f ff 24 63 af 43 8a 7d |.7...g.c..$c.C.}|
+00000150 46 63 bb 33 67 7a de 86 b4 6a 70 2d 6a 7f 82 c2 |Fc.3gz...jp-j...|
+00000160 24 3c e1 0f a9 7f 93 76 d2 c9 e2 56 d3 cb b9 17 |$<.....v...V....|
+00000170 97 2f 8a 25 40 dc 35 e4 00 3a 3f 2b 1e 09 1b f2 |./.%@.5..:?+....|
+00000180 12 2a 76 c0 2e cd 17 06 32 a9 f8 08 70 3f 06 fa |.*v.....2...p?..|
+00000190 c7 1b c4 50 4f b8 1e 0f 6f 6a 3a ba f6 28 1b d0 |...PO...oj:..(..|
+000001a0 a7 34 a5 8c 02 fe 35 4f b4 97 45 96 48 bc b9 0d |.4....5O..E.H...|
+000001b0 c9 2f df bd c1 8b 19 44 33 12 90 2c d2 99 09 36 |./.....D3..,...6|
+000001c0 97 3f 29 56 30 77 15 df 15 c9 b1 26 9c f4 6a 59 |.?)V0w.....&..jY|
+000001d0 00 3e d8 28 74 19 6c 38 6c 68 63 16 ab cb f0 3d |.>.(t.l8lhc....=|
+000001e0 ce 30 f6 9c 06 00 06 cc 5a 8e 78 73 af 53 a4 e6 |.0......Z.xs.S..|
+000001f0 49 10 5b 9d 4d f3 7d 48 f0 5d 87 27 d8 7e 58 a6 |I.[.M.}H.].'.~X.|
+00000200 86 51 a0 d6 e8 82 20 6b d3 f9 99 4d 11 b7 49 ad |.Q.... k...M..I.|
+00000210 f9 1a 1b f5 cd 81 81 bd 51 76 a4 5a 5f 35 7a 52 |........Qv.Z_5zR|
+00000220 12 1b 73 f6 f3 1d cf 93 7a 8e a0 1d 4c f3 b2 f5 |..s.....z...L...|
+00000230 16 00 57 21 2f c6 85 af 8c 8b f9 bd 2a f1 ee 15 |..W!/.......*...|
+00000240 ec ee 80 b9 8b 0a 50 36 cb 53 fd ca 53 b4 0e 96 |......P6.S..S...|
+00000250 7b db e6 93 f7 9e 8d e4 6a d5 ff e3 74 31 76 3a |{.......j...t1v:|
+00000260 a8 de ce 06 97 3d 4e 91 c5 cd 85 06 c9 a6 02 91 |.....=N.........|
+00000270 f9 36 33 8d 28 23 54 f5 c3 f0 b2 1a a1 6b b7 c6 |.63.(#T......k..|
+00000280 d1 c3 31 ad d6 6f 0c 44 e4 34 d8 26 b6 ff 06 6f |..1..o.D.4.&...o|
+00000290 f3 56 19 46 8d f3 75 c2 d9 69 4a 5b ff 3a b8 1d |.V.F..u..iJ[.:..|
+000002a0 86 a9 6f 45 dc 3a e4 aa 9b 7d 3a 5a 50 ad c6 f6 |..oE.:...}:ZP...|
+000002b0 8c e3 0e ca b6 7a 99 e7 4b 58 26 c2 18 95 14 a4 |.....z..KX&.....|
+000002c0 f9 ae 79 4f f6 c0 f8 0e d4 52 fb 3c 5d a2 30 9c |..yO.....R.<].0.|
+000002d0 ea d9 8d f4 27 4c 6f 7a 02 45 8f ca 8c b1 bc d2 |....'Loz.E......|
+000002e0 c5 dc 8b 09 d7 c4 0f ea f6 51 be f7 cd 01 1e 78 |.........Q.....x|
+000002f0 a1 37 4a 88 ae 5f c5 79 9c e2 4d c9 74 e7 2e 18 |.7J.._.y..M.t...|
+00000300 86 e8 62 3f 6c 39 73 eb c2 e2 54 0c 13 ca f6 57 |..b?l9s...T....W|
+00000310 20 92 6a 1d 03 28 d0 53 6f 6e cb 57 da 33 20 1a | .j..(.Son.W.3 .|
+00000320 c8 3d 09 73 5f 28 14 6f 4c 16 8c 41 cd 44 ad df |.=.s_(.oL..A.D..|
+00000330 77 08 0f f1 3c 4c 2b 37 03 60 9d 07 85 e7 66 f7 |w...<L+7.`....f.|
+00000340 e7 7f 7b 45 0a db 3f 62 88 ca 84 ff e9 08 32 92 |..{E..?b......2.|
+00000350 07 77 cc c0 b7 31 17 03 03 00 99 d0 7e f0 62 28 |.w...1......~.b(|
+00000360 21 cb 07 5c 54 0b 79 94 26 e3 63 25 57 df e4 79 |!..\T.y.&.c%W..y|
+00000370 32 d1 1d 08 dc 66 76 30 68 62 c1 a7 9c 72 f6 07 |2....fv0hb...r..|
+00000380 e6 0e 30 de ef 4a 6e d8 0d 0e df 40 e7 6e 8b 48 |..0..Jn....@.n.H|
+00000390 07 62 27 7f 97 c8 8d 3f 8d ce b3 e4 9e ed c5 e0 |.b'....?........|
+000003a0 9e ec f2 7b 7e 4d e0 1b 14 69 ef c6 5d 04 5c a6 |...{~M...i..].\.|
+000003b0 1a 41 62 25 79 88 39 0e b5 1a 6c 75 d0 fe 92 6a |.Ab%y.9...lu...j|
+000003c0 7e 4f e2 36 f0 09 b8 a7 1a 4a 3a 94 f6 27 25 7f |~O.6.....J:..'%.|
+000003d0 c9 ad 2e 50 41 64 a4 73 34 d2 4e 02 05 af 68 84 |...PAd.s4.N...h.|
+000003e0 40 81 d9 f7 a9 0b 77 ee 6c 83 0c d5 d5 70 49 e5 |@.....w.l....pI.|
+000003f0 a5 0a 3e 12 17 03 03 00 35 35 88 42 4c 14 18 a9 |..>.....55.BL...|
+00000400 3e 26 15 0a f1 c3 a6 ab 94 a3 72 bd c7 04 22 bc |>&........r...".|
+00000410 67 32 15 16 23 f5 50 97 bc 7f ab f8 ef f0 02 7d |g2..#.P........}|
+00000420 2d 76 01 18 72 18 77 c1 f5 9b e9 e9 97 8d |-v..r.w.......|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 02 11 4b 29 10 c9 7b |...........K)..{|
+00000010 98 9a fa ce 7a 17 a4 7d 15 5f 97 4f 40 67 37 f0 |....z..}._.O@g7.|
+00000020 0b 2d ca 62 77 23 ab 78 d7 9f b6 1d 5c 64 fb 68 |.-.bw#.x....\d.h|
+00000030 70 5f 21 df e1 55 3b e3 bb 8e 61 31 11 ba 2b eb |p_!..U;...a1..+.|
+00000040 de 78 39 5c 31 62 a3 fb 9a 57 a4 50 34 43 76 55 |.x9\1b...W.P4CvU|
+00000050 ae f9 36 b1 35 ee 2b 8d ab c2 70 52 b0 8c d6 1b |..6.5.+...pR....|
+00000060 fe 0f fc 5e 79 c3 cf ab d3 9a 81 af 63 2c b3 f7 |...^y.......c,..|
+00000070 a6 b7 13 c4 70 22 fa 56 6d 77 cb d1 bf a5 9e c8 |....p".Vmw......|
+00000080 74 83 80 f9 9a 19 f3 a3 94 15 72 7c 55 0e 21 47 |t.........r|U.!G|
+00000090 2b a2 d3 b8 74 e1 07 37 7f 12 f6 ad ba 71 e5 ca |+...t..7.....q..|
+000000a0 17 42 2b 78 9e 90 7d 28 b1 f4 dd 7d b8 69 dd c6 |.B+x..}(...}.i..|
+000000b0 eb 3d 93 45 06 ac 5d fe 02 18 b8 f3 8c e4 4e 97 |.=.E..].......N.|
+000000c0 05 8b 36 94 cb 0f 66 64 ed a8 50 22 ba c8 a7 23 |..6...fd..P"...#|
+000000d0 7d f9 d5 4f d5 27 83 f3 b6 09 3f 4f 69 92 6d be |}..O.'....?Oi.m.|
+000000e0 4a 30 02 d2 d5 e6 14 d4 21 e2 c8 5b cb 08 1e 9a |J0......!..[....|
+000000f0 28 f7 f4 13 8c 58 9b 69 2c 55 3d 78 f2 ce 93 89 |(....X.i,U=x....|
+00000100 2f 62 56 ea a3 21 96 f6 e7 ee a4 3d d8 7d 86 4d |/bV..!.....=.}.M|
+00000110 79 c9 3b c8 cf ea a0 6b 5f 29 8c ed c2 d6 73 27 |y.;....k_)....s'|
+00000120 a0 35 bb 2b 8b 6c 4e 59 74 e5 84 c4 d2 1a f1 0d |.5.+.lNYt.......|
+00000130 5c 36 33 f7 42 d6 08 c3 f8 5b ea 27 a1 cc b9 72 |\63.B....[.'...r|
+00000140 d5 b9 4e 17 36 b3 05 29 50 da 52 bc 23 f7 82 82 |..N.6..)P.R.#...|
+00000150 c0 67 2b 80 a2 7f e2 ec b9 12 bb dc b6 04 b6 4f |.g+............O|
+00000160 87 15 16 13 de c4 1c 04 71 33 ba d7 a7 da f1 f5 |........q3......|
+00000170 77 c6 4e 8e b2 65 a1 6c a8 c2 5b a1 f5 da 49 6c |w.N..e.l..[...Il|
+00000180 85 ee 21 8d 10 6b 82 bf 0c 0f 7e 33 8b 5e 44 5b |..!..k....~3.^D[|
+00000190 70 db bc 76 40 a0 5c 02 f6 8a 9b de aa a4 b2 94 |p..v@.\.........|
+000001a0 d0 e0 b7 60 af df ad 3d e3 17 a9 60 e0 d9 a8 3e |...`...=...`...>|
+000001b0 c6 06 9b ad 97 0b dc 21 16 9d 42 29 74 a1 f5 03 |.......!..B)t...|
+000001c0 d4 15 0d ee fd fa 6b 85 12 2f 8c 26 fd 96 ce 85 |......k../.&....|
+000001d0 a5 b7 ba bb ac 8a 6d 54 f5 fd e6 6c 32 24 a9 e7 |......mT...l2$..|
+000001e0 1a 11 bf 4d cb f9 18 9a b8 1e a6 e4 1f 61 b1 ce |...M.........a..|
+000001f0 1c ca 5d 81 e7 84 e0 a9 4e c7 f9 5d 71 72 76 4b |..].....N..]qrvK|
+00000200 65 ca 3a a4 4d d8 ec 82 aa 33 80 bb 15 48 2d 7c |e.:.M....3...H-||
+00000210 4e 5e d2 ec 13 1a e7 03 d5 29 95 80 17 03 03 00 |N^.......)......|
+00000220 99 60 a2 43 34 23 c0 a4 4c 0a 18 c5 27 96 2f 7c |.`.C4#..L...'./||
+00000230 af 2b 2c 36 f2 9b cf 93 e7 3e 79 3b 20 d4 3b 60 |.+,6.....>y; .;`|
+00000240 a2 ef af 36 d5 45 d4 20 89 be 80 1d 1e ca f7 19 |...6.E. ........|
+00000250 35 8f 26 3f be c0 a2 f6 c6 85 a3 88 76 cd 06 f9 |5.&?........v...|
+00000260 4f ff 54 79 6c ac 33 71 31 90 70 36 eb 9c c1 b4 |O.Tyl.3q1.p6....|
+00000270 4a c8 3a 52 85 2b be 4a 19 8a 24 fd 6f 08 47 19 |J.:R.+.J..$.o.G.|
+00000280 84 88 a0 48 f6 17 80 f8 fe 9e 21 68 e1 75 17 14 |...H......!h.u..|
+00000290 d4 e2 3a e2 de 9d 19 56 ad cc 33 13 f3 52 b2 1b |..:....V..3..R..|
+000002a0 f4 65 04 05 79 9f 3e 14 fb 1f 9c d1 c4 53 c0 93 |.e..y.>......S..|
+000002b0 49 ad 3c 2e de c1 b4 fe be b3 17 03 03 00 35 32 |I.<...........52|
+000002c0 81 98 1a 6c 38 ca 67 64 c5 30 0b 81 7d fd a1 b9 |...l8.gd.0..}...|
+000002d0 2e af 41 1d e9 b7 31 17 d8 08 ce d5 f6 12 4d da |..A...1.......M.|
+000002e0 fc db fb e1 fa 5b cd 70 12 e7 bb 26 dd 53 9c 43 |.....[.p...&.S.C|
+000002f0 02 06 1f 70 |...p|
+>>> Flow 4 (server to client)
+00000000 17 03 03 02 8b 8e b1 29 40 b6 53 bc 89 c7 87 69 |.......)@.S....i|
+00000010 4c 6d 5b 61 d9 ba 5b 96 22 ac 57 71 58 f8 0e ea |Lm[a..[.".WqX...|
+00000020 81 ea bf f9 34 6d a0 ce 1f d2 97 52 62 2b 9e f7 |....4m.....Rb+..|
+00000030 03 28 96 56 c0 a1 0e 69 7c 98 13 e5 91 8c 48 5f |.(.V...i|.....H_|
+00000040 4e 78 87 14 38 f8 fa 3c 17 97 f9 de 38 3b cf 0f |Nx..8..<....8;..|
+00000050 d9 dd 41 0a bb 65 ca a7 0b fd a5 11 c2 c3 6a b8 |..A..e........j.|
+00000060 5a e1 68 a1 8d f8 35 9d c6 e1 3e e1 03 a9 06 ee |Z.h...5...>.....|
+00000070 1f 92 ca b5 f4 df 3e e5 69 63 9e a2 ea 5e b8 d9 |......>.ic...^..|
+00000080 26 31 9e 25 de a8 ea 44 1a c0 86 0b 38 75 04 dc |&1.%...D....8u..|
+00000090 2d 37 ad 40 e3 2f d1 b0 9e 9e 64 57 8b 31 20 d6 |-7.@./....dW.1 .|
+000000a0 16 64 fd 1b c1 01 58 af 4b 88 49 23 7a f6 a2 15 |.d....X.K.I#z...|
+000000b0 ca 02 4b d6 6d 7c f8 7a c9 c0 0d 32 6e 1d 83 ca |..K.m|.z...2n...|
+000000c0 47 e5 6f 86 a0 f7 8b 50 1d 91 ec fa 2b 4a 72 f7 |G.o....P....+Jr.|
+000000d0 a0 09 f1 65 fb 81 32 d2 a0 be 18 07 9f 5d 89 98 |...e..2......]..|
+000000e0 08 09 a6 1d 9a 5a 10 67 81 58 82 00 9d 01 48 a8 |.....Z.g.X....H.|
+000000f0 5b df 54 b3 cd 84 87 e0 41 e6 1e 47 46 33 56 0c |[.T.....A..GF3V.|
+00000100 67 82 b9 bc 28 68 f3 5b 51 a8 c0 0e 43 14 62 bb |g...(h.[Q...C.b.|
+00000110 8a bd 3f 4d d6 33 c4 76 4f c1 06 f8 9b bf 64 41 |..?M.3.vO.....dA|
+00000120 6c e5 40 8d 93 4a 6b 6f fe 72 6b db ac 35 b4 fc |l.@..Jko.rk..5..|
+00000130 84 13 fa 8a 7d 35 e3 73 12 eb 1a 5f a9 e2 28 53 |....}5.s..._..(S|
+00000140 0c 6d 41 ec 4b 76 f5 d9 48 2a c2 85 2a 1f 7d 61 |.mA.Kv..H*..*.}a|
+00000150 f6 1f 27 ef 47 c9 c7 b3 19 5c 07 d5 18 ec fd 3e |..'.G....\.....>|
+00000160 78 41 cb a4 3a 47 22 cf 7e 7e 17 be 27 c4 90 ce |xA..:G".~~..'...|
+00000170 2a cb cd ed 0f a3 bf 1e 4c 62 7a 80 ff 21 38 c5 |*.......Lbz..!8.|
+00000180 c2 37 9f 62 4b d8 c0 9e df ae 3c 69 cd 25 f5 65 |.7.bK.....<i.%.e|
+00000190 ec f6 c2 0e 0f f0 b2 12 85 c4 2a 4b 8f 18 1a 0a |..........*K....|
+000001a0 fa 4d 12 5f ee d4 11 64 21 f9 c7 c4 a6 ba e5 3b |.M._...d!......;|
+000001b0 e9 54 ec ee e6 d3 09 31 9f 6e 99 ec 71 7e 42 5d |.T.....1.n..q~B]|
+000001c0 78 88 ba eb 9f dd 99 59 fe 4e 29 1a 2e 35 12 4b |x......Y.N)..5.K|
+000001d0 98 d4 14 79 80 b7 86 d3 da b5 c8 a6 34 cb 06 57 |...y........4..W|
+000001e0 a6 70 5c 6d 15 0b a7 ec c9 ab fb 24 ad b7 c0 2b |.p\m.......$...+|
+000001f0 ec fb 9b d4 57 b1 44 86 cf 75 c4 de c6 32 f9 01 |....W.D..u...2..|
+00000200 ab 84 85 17 2a 0a 7e 48 e9 94 28 0c ba a8 98 a8 |....*.~H..(.....|
+00000210 b2 36 89 62 ed 0d d8 e8 af 91 1b fd f8 97 25 c9 |.6.b..........%.|
+00000220 56 27 ff 1b d8 56 23 ec 96 8f ed 7b db 80 1e d4 |V'...V#....{....|
+00000230 b8 79 d4 23 d2 3c 89 38 32 14 b9 4e b4 55 99 1f |.y.#.<.82..N.U..|
+00000240 4f 56 3f 65 c7 b8 bd 28 47 f8 74 50 bb 16 5f de |OV?e...(G.tP.._.|
+00000250 e1 4d bf d9 bf 0e c0 57 3b a4 7d 7a 95 42 49 95 |.M.....W;.}z.BI.|
+00000260 b2 e2 99 68 72 38 9b 87 b6 c0 4c d5 b9 da 08 81 |...hr8....L.....|
+00000270 27 f8 5f 68 30 fd 01 7f c4 d5 74 9f e6 3f 28 93 |'._h0.....t..?(.|
+00000280 83 18 38 bd c5 cf be c7 a1 bd 65 a1 74 fb cc e9 |..8.......e.t...|
+00000290 17 03 03 00 1e c3 24 ce a6 69 b8 6c fe 2a 71 a9 |......$..i.l.*q.|
+000002a0 74 4a 04 8b 40 f4 06 06 99 e0 52 fd 13 78 b2 08 |tJ..@.....R..x..|
+000002b0 b7 c1 8a 17 03 03 00 13 ea fb 49 f8 a7 37 b2 f0 |..........I..7..|
+000002c0 ef 9d 6b 7e 68 04 5a 27 fa 36 a5 |..k~h.Z'.6.|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-ClientAuthRequestedNotGiven b/src/crypto/tls/testdata/Server-TLSv13-ClientAuthRequestedNotGiven
new file mode 100644
index 0000000..fb2fb34
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-ClientAuthRequestedNotGiven
@@ -0,0 +1,104 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 ca 01 00 00 c6 03 03 15 b6 db 09 24 |...............$|
+00000010 50 ea d6 f7 ae d7 32 2f 72 25 23 db 11 ad 6f c1 |P.....2/r%#...o.|
+00000020 5d 62 af e7 93 63 1a 8b f3 82 80 20 5f 15 2e 86 |]b...c..... _...|
+00000030 86 2c 2e 2f 82 11 3c d2 9f 00 32 d4 3d 05 04 fa |.,./..<...2.=...|
+00000040 36 41 8d dc 30 ce a6 2b 6e d4 3c 9c 00 04 13 01 |6A..0..+n.<.....|
+00000050 00 ff 01 00 00 79 00 0b 00 04 03 00 01 02 00 0a |.....y..........|
+00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 16 |................|
+00000070 00 00 00 17 00 00 00 0d 00 1e 00 1c 04 03 05 03 |................|
+00000080 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 |................|
+00000090 08 06 04 01 05 01 06 01 00 2b 00 03 02 03 04 00 |.........+......|
+000000a0 2d 00 02 01 01 00 33 00 26 00 24 00 1d 00 20 98 |-.....3.&.$... .|
+000000b0 b7 40 03 d8 a3 4c 9e 16 82 77 16 9b c1 17 3a 2a |.@...L...w....:*|
+000000c0 fc 25 73 5d 2d 5c dc 15 78 36 12 7a 28 f2 0e |.%s]-\..x6.z(..|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 5f 15 2e 86 |........... _...|
+00000030 86 2c 2e 2f 82 11 3c d2 9f 00 32 d4 3d 05 04 fa |.,./..<...2.=...|
+00000040 36 41 8d dc 30 ce a6 2b 6e d4 3c 9c 13 01 00 00 |6A..0..+n.<.....|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 17 14 12 e8 30 75 5a |.............0uZ|
+00000090 a4 27 7d 83 2e 51 0e 48 14 7b 53 0c 65 24 71 c5 |.'}..Q.H.{S.e$q.|
+000000a0 44 17 03 03 00 3e 34 38 ac c0 b5 05 e1 03 e1 a3 |D....>48........|
+000000b0 d3 42 ec e3 94 96 e7 a3 05 d8 44 ca 1d 89 b6 6f |.B........D....o|
+000000c0 52 ce 3c 7d 61 f1 b4 a2 83 31 ab cf e7 ca 53 57 |R.<}a....1....SW|
+000000d0 b8 eb f4 7a 8a 7c ce 31 fe a4 b6 c7 a5 ed f2 2d |...z.|.1.......-|
+000000e0 da 36 d6 49 17 03 03 02 6d 2c b4 e1 f3 87 4e c7 |.6.I....m,....N.|
+000000f0 ab db ea fa 0d 31 20 f2 1e 63 1d 10 bd 61 98 a2 |.....1 ..c...a..|
+00000100 50 8d 12 0d c8 5c f8 e4 97 9c 5f f3 47 f4 60 a5 |P....\...._.G.`.|
+00000110 59 16 a2 27 06 94 80 93 af 1e 9d c0 9a 23 20 bf |Y..'.........# .|
+00000120 a4 5a 26 2c 37 86 d8 8a b7 e2 bd e2 4f ab 53 65 |.Z&,7.......O.Se|
+00000130 bd 34 2c 1a 88 72 bf 8f 20 0c e2 51 0f ea 3f 47 |.4,..r.. ..Q..?G|
+00000140 dc 0e cd 21 3c d0 cc 7d 38 b8 b9 1b 20 67 83 a9 |...!<..}8... g..|
+00000150 af 4c f7 7b c0 d9 00 5c 66 e3 d7 2e 3b 6a b5 9c |.L.{...\f...;j..|
+00000160 6e f6 ed 96 25 3c ce ea db fa 85 ba e2 d8 4c 95 |n...%<........L.|
+00000170 92 06 0a 38 19 7f 52 30 2b ef fc 23 c6 b3 e5 d1 |...8..R0+..#....|
+00000180 83 2e 56 65 d6 ef 06 3a 71 d6 39 e9 16 62 65 78 |..Ve...:q.9..bex|
+00000190 59 c1 9f 7f 99 be c2 b9 0b 56 0a db 26 ec 16 15 |Y........V..&...|
+000001a0 be 27 cb bb cf 4a 9c a1 fd 5c 7d 5d c6 df a2 ed |.'...J...\}]....|
+000001b0 f1 70 74 03 40 7c 8f af ea 3c 6a c7 c6 30 98 4c |.pt.@|...<j..0.L|
+000001c0 5a c1 e5 33 fb 56 8f 02 df 22 01 7b 11 f7 8a 5f |Z..3.V...".{..._|
+000001d0 70 75 39 96 f9 1f 1b c9 d4 64 d8 8c a2 04 33 fd |pu9......d....3.|
+000001e0 5e 07 37 30 12 2a 91 21 6f 83 23 95 2b 5a 72 13 |^.70.*.!o.#.+Zr.|
+000001f0 5a 0d 4a 05 57 c9 dd fc 77 ff 74 b1 5d 14 25 70 |Z.J.W...w.t.].%p|
+00000200 ee 8e 93 1b bc d3 3c d9 ba 3f 8a f0 79 45 a2 c6 |......<..?..yE..|
+00000210 23 f2 7d dc 21 4f cd 01 a5 4a 2c 46 96 21 5c 15 |#.}.!O...J,F.!\.|
+00000220 30 eb 1d 44 0f e7 fc 45 6b d5 e6 33 f5 88 71 53 |0..D...Ek..3..qS|
+00000230 96 2a c1 c7 61 cb 1d 6a 95 8d ee 64 8a 58 1c a6 |.*..a..j...d.X..|
+00000240 6a c9 75 86 6a f0 d2 4c f0 1c 6d 36 18 fd 6b d8 |j.u.j..L..m6..k.|
+00000250 da 3d d0 0f 7b d3 33 f8 30 c9 f2 1a c2 1d 55 3d |.=..{.3.0.....U=|
+00000260 2d 71 15 6d 26 f7 ad 05 23 de b0 50 83 f5 c0 39 |-q.m&...#..P...9|
+00000270 09 62 73 d6 c2 b9 53 c9 85 ff b9 ff 60 23 5c 06 |.bs...S.....`#\.|
+00000280 f9 87 e3 25 28 cf 75 9d 58 26 76 9e 55 91 71 aa |...%(.u.X&v.U.q.|
+00000290 92 ea 3c 97 d4 43 4b d8 b8 5f 8a fc 4b a4 ad a0 |..<..CK.._..K...|
+000002a0 aa 5b 91 b6 8d 5d 84 19 40 13 93 5a 33 a9 fd 65 |.[...]..@..Z3..e|
+000002b0 86 ca b3 fe be e7 ef 75 a5 b2 35 8d 6f cb ed 27 |.......u..5.o..'|
+000002c0 17 2e 72 f8 46 60 f1 90 79 46 30 6b 42 31 09 4b |..r.F`..yF0kB1.K|
+000002d0 fa a4 9b 69 4c 86 0c 9f e4 6b 13 08 c4 9c 81 a3 |...iL....k......|
+000002e0 f3 74 99 1f d7 c1 d6 7c 12 25 25 92 3a 05 33 eb |.t.....|.%%.:.3.|
+000002f0 3b be 38 f3 07 1d 3b 9d a9 1b cc bc 37 2d 41 1d |;.8...;.....7-A.|
+00000300 61 c6 ac b7 30 30 78 df b4 be f6 1d d6 e5 c8 af |a...00x.........|
+00000310 42 9b a7 b3 9c 4c 70 2c 23 e8 d5 8b 14 e0 21 d1 |B....Lp,#.....!.|
+00000320 66 af 2a 3a b4 f0 fa 44 88 2e 05 7a 2a 36 b2 21 |f.*:...D...z*6.!|
+00000330 27 5f a7 ff 3a cf dc 63 9e bd 81 d1 30 06 4b da |'_..:..c....0.K.|
+00000340 ed f5 3f 1e 69 83 9b e2 7c 58 26 fa de d9 49 8c |..?.i...|X&...I.|
+00000350 96 35 d0 37 63 08 17 03 03 00 99 4b 17 f2 3b bc |.5.7c......K..;.|
+00000360 f3 b5 e2 0a da dd 4f 17 49 78 51 9b 58 b1 5c 79 |......O.IxQ.X.\y|
+00000370 d7 bd ac ee b9 25 24 9e 3d 28 37 ea 81 3c 98 ac |.....%$.=(7..<..|
+00000380 c6 bd a8 e2 8a b4 f7 15 a3 07 b0 2c 09 de 62 4d |...........,..bM|
+00000390 be 09 6e 3c 4f 7d c2 0e 35 d7 22 39 0e 8b 0a 99 |..n<O}..5."9....|
+000003a0 c8 60 21 cf bd 41 57 da 69 47 fe 6e 15 22 90 a7 |.`!..AW.iG.n."..|
+000003b0 34 51 64 d2 3a b6 8e 6e 28 a6 e3 42 1e 45 d9 9a |4Qd.:..n(..B.E..|
+000003c0 95 71 82 a8 18 2b 13 93 ed 8f dd 74 8e 20 6e c7 |.q...+.....t. n.|
+000003d0 09 35 94 92 6b 98 9c c8 2c 03 30 16 67 f1 ee 4d |.5..k...,.0.g..M|
+000003e0 26 7c be ae 38 83 e3 b9 e4 60 cc e3 6b 3f 8e ad |&|..8....`..k?..|
+000003f0 63 90 c5 25 17 03 03 00 35 d9 2b cb 6f 6c 5b ac |c..%....5.+.ol[.|
+00000400 01 e1 c6 f8 5e 70 62 56 03 a9 a4 19 c4 55 d2 d5 |....^pbV.....U..|
+00000410 96 1f 48 85 13 24 57 f1 34 4c 4e 79 03 ec 84 c2 |..H..$W.4LNy....|
+00000420 ce c6 83 3c 71 1d 93 6d d7 e3 7a e0 4a 11 |...<q..m..z.J.|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 19 83 88 d2 c3 d4 |................|
+00000010 a8 98 6c 8f fa 1b 52 a5 83 58 e3 62 89 3e 22 a3 |..l...R..X.b.>".|
+00000020 37 b8 ee 13 17 03 03 00 35 b5 5f aa fd ca 85 74 |7.......5._....t|
+00000030 ee c6 06 d9 2e d8 4f 7d 87 a2 b7 20 80 a5 3b 97 |......O}... ..;.|
+00000040 41 bc 80 20 af b5 c4 66 26 2e 39 fd 81 e0 1a a0 |A.. ...f&.9.....|
+00000050 6f c3 08 d0 23 c2 27 49 91 58 77 15 2d 49 |o...#.'I.Xw.-I|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 93 10 f4 e9 f1 51 30 25 9e f0 c4 d2 |.........Q0%....|
+00000010 b8 f4 4b ad dd 89 ad ab 1a 39 88 44 98 a2 53 4e |..K......9.D..SN|
+00000020 1c e9 bb 4a b7 c1 d8 cc bc 76 e6 a8 e6 41 b9 42 |...J.....v...A.B|
+00000030 c8 7a 0a f4 35 73 cc 9f 9d 30 ff 4e e3 44 89 a5 |.z..5s...0.N.D..|
+00000040 d0 2b 88 36 0a 87 72 b4 bf 48 6a 4e 2e 03 1a 96 |.+.6..r..HjN....|
+00000050 1e 01 07 90 61 b0 f1 c5 58 e0 48 30 db d6 e9 5c |....a...X.H0...\|
+00000060 88 05 0d 47 fc d1 33 6e 7e c4 fb 81 e3 80 ce 67 |...G..3n~......g|
+00000070 93 59 5e 68 39 6c b2 c3 c3 56 09 61 e5 a1 d6 d9 |.Y^h9l...V.a....|
+00000080 95 3a 70 6a 5c 4a 51 24 d9 e7 ed 88 7f 6c 32 0a |.:pj\JQ$.....l2.|
+00000090 2d 5d 79 40 75 c9 b9 d4 17 03 03 00 1e 24 cc 07 |-]y@u........$..|
+000000a0 53 2b 27 c1 36 47 88 b8 3c 91 9e 8b 13 da 9d 3c |S+'.6G..<......<|
+000000b0 f9 65 9d 78 ed 92 36 11 41 fe 42 17 03 03 00 13 |.e.x..6.A.B.....|
+000000c0 2b 52 80 d0 d5 39 77 77 38 ad e0 ad 78 f8 0a 59 |+R...9ww8...x..Y|
+000000d0 96 18 7e |..~|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-ECDHE-ECDSA-AES b/src/crypto/tls/testdata/Server-TLSv13-ECDHE-ECDSA-AES
new file mode 100644
index 0000000..22909cc
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-ECDHE-ECDSA-AES
@@ -0,0 +1,94 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 ca 01 00 00 c6 03 03 30 09 bc 8e d5 |...........0....|
+00000010 59 36 2b f3 2b 0f 9d 32 ff 23 ba c7 4a 1f 50 e6 |Y6+.+..2.#..J.P.|
+00000020 32 bd 0e c3 f6 df b7 70 dc d5 0c 20 44 0e b7 7b |2......p... D..{|
+00000030 a0 37 9f 1d 8d 7e 93 f7 c0 7d 25 d3 f8 e5 65 50 |.7...~...}%...eP|
+00000040 79 5e 4f 53 e5 67 40 f0 bf ad 4d f8 00 04 13 01 |y^OS.g@...M.....|
+00000050 00 ff 01 00 00 79 00 0b 00 04 03 00 01 02 00 0a |.....y..........|
+00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 16 |................|
+00000070 00 00 00 17 00 00 00 0d 00 1e 00 1c 04 03 05 03 |................|
+00000080 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 |................|
+00000090 08 06 04 01 05 01 06 01 00 2b 00 03 02 03 04 00 |.........+......|
+000000a0 2d 00 02 01 01 00 33 00 26 00 24 00 1d 00 20 23 |-.....3.&.$... #|
+000000b0 23 ab 76 3d e8 d5 1b 9f 03 71 bc bf 3d 18 3a 86 |#.v=.....q..=.:.|
+000000c0 5d 59 ee ac b9 0a 2f f6 fc 5d 13 7b 3e 88 68 |]Y..../..].{>.h|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 44 0e b7 7b |........... D..{|
+00000030 a0 37 9f 1d 8d 7e 93 f7 c0 7d 25 d3 f8 e5 65 50 |.7...~...}%...eP|
+00000040 79 5e 4f 53 e5 67 40 f0 bf ad 4d f8 13 01 00 00 |y^OS.g@...M.....|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 17 2a db 0a 1b 36 73 |..........*...6s|
+00000090 de 3d 2f d9 c8 c0 2b 93 43 b3 a8 96 30 d2 bc 3d |.=/...+.C...0..=|
+000000a0 f7 17 03 03 02 22 72 49 cc 6d 9e 7f f5 42 1c 8b |....."rI.m...B..|
+000000b0 8a 0e 1b ad 71 f4 21 50 be ad 91 df e0 d4 a0 dc |....q.!P........|
+000000c0 61 d2 eb 6a 39 f1 8d 31 66 9f 97 d9 b2 79 bf 10 |a..j9..1f....y..|
+000000d0 cc e1 2a 7f da 9f ff 10 22 a8 0b d6 26 c9 7c a4 |..*....."...&.|.|
+000000e0 51 8d a7 62 af 96 ec 01 72 7b 08 27 9f ff 1d a6 |Q..b....r{.'....|
+000000f0 26 54 6e 48 09 73 ac 7c b2 bc a5 04 4e a2 41 66 |&TnH.s.|....N.Af|
+00000100 37 07 dd 7f 0d 8b 5b fa 84 a4 12 8b 44 9b b3 44 |7.....[.....D..D|
+00000110 71 bb 3a ce 95 8b a1 c5 e2 9f d2 86 0b 2b b2 43 |q.:..........+.C|
+00000120 aa 24 4c 69 0f c8 e8 7d ff 53 2a 56 e8 dd 53 bf |.$Li...}.S*V..S.|
+00000130 1b a7 fa 74 f2 c3 3d fa 11 b4 30 ce c0 9b 05 a5 |...t..=...0.....|
+00000140 13 b9 d1 1d a7 02 0a a6 36 31 b5 91 1f 5e 7f 65 |........61...^.e|
+00000150 24 48 3c ec fa d3 db 11 31 d1 c3 cd 47 b2 89 95 |$H<.....1...G...|
+00000160 80 55 25 1a 66 bf d9 ba 42 05 1d 20 b3 6e 09 bc |.U%.f...B.. .n..|
+00000170 5f 1d 81 15 b2 54 c6 65 7e 75 35 e7 54 60 28 e1 |_....T.e~u5.T`(.|
+00000180 15 0e ee 51 09 3c c1 5b ba 90 2e af 0a 85 40 0a |...Q.<.[......@.|
+00000190 de 78 c8 c9 15 75 61 1f 75 a2 5c 80 d5 ed a5 71 |.x...ua.u.\....q|
+000001a0 a7 d8 21 f3 9c 84 f5 af b1 5c 45 76 de a7 05 20 |..!......\Ev... |
+000001b0 7f c4 c4 71 b1 68 e0 a2 17 7f ac f8 c4 80 a8 89 |...q.h..........|
+000001c0 e8 35 68 ae 98 cf 2d 29 4e dc 84 45 21 d3 bb 0a |.5h...-)N..E!...|
+000001d0 d8 c9 e1 41 48 b2 a8 53 31 5c 26 d0 28 9e 8e df |...AH..S1\&.(...|
+000001e0 72 f2 ef f7 78 3d 7e b9 09 0c a4 e8 3e c5 a5 f6 |r...x=~.....>...|
+000001f0 e3 aa 32 1d da 98 7b 0a f1 0a 42 f6 71 92 45 01 |..2...{...B.q.E.|
+00000200 e4 28 f3 c6 0f a2 cf c3 74 3b 09 f5 75 51 8e fa |.(......t;..uQ..|
+00000210 6c 12 9e 80 2b 0a 87 fb 29 3d 0d a6 c4 7b c8 42 |l...+...)=...{.B|
+00000220 75 57 48 b3 78 20 2c b3 a1 d7 b7 6f 95 18 a2 bc |uWH.x ,....o....|
+00000230 fd c9 22 d3 49 ae 5b 2a ec b1 1a ff cd 38 3a bf |..".I.[*.....8:.|
+00000240 45 e8 a8 fe 39 d5 f8 a2 89 73 7f 8f 2c 65 8a e6 |E...9....s..,e..|
+00000250 b7 20 f7 c9 5c 02 ea 33 4f f6 fc 68 2f d6 a0 d9 |. ..\..3O..h/...|
+00000260 73 10 38 35 ba d8 74 2d cf 05 07 ee d4 fc 09 89 |s.85..t-........|
+00000270 0b 77 72 61 74 1f 16 8d 1f 29 3b 20 8d ef 99 b8 |.wrat....); ....|
+00000280 3d 80 24 5a 1d 32 9b 2e 50 4c 35 7e 4f c9 bc a7 |=.$Z.2..PL5~O...|
+00000290 6e ae 26 42 fb 4e c3 a8 7c 77 b4 c5 4c 1b 3a db |n.&B.N..|w..L.:.|
+000002a0 cc 3f 44 fe ae d7 3f 42 5f ee 05 6a 1d 72 98 0e |.?D...?B_..j.r..|
+000002b0 db 97 3c 11 06 c7 9e 5b 03 95 e0 52 09 54 39 b1 |..<....[...R.T9.|
+000002c0 13 19 f3 98 6c ed e3 ab 17 03 03 00 a3 49 60 43 |....l........I`C|
+000002d0 34 81 d3 6f fe c4 eb ac 49 64 51 9f 22 81 03 41 |4..o....IdQ."..A|
+000002e0 fd bc 4f 41 78 59 81 8a 82 b5 c3 06 79 8d d4 b2 |..OAxY......y...|
+000002f0 8b 9f 08 2b 09 ae 88 7d bd 87 6a 40 19 b8 c7 1b |...+...}..j@....|
+00000300 e1 55 69 8d 47 7a 49 66 fe 22 1f 95 c7 b5 15 ce |.Ui.GzIf."......|
+00000310 6b d6 5b 37 45 57 72 ba 5f a3 62 49 13 80 b9 47 |k.[7EWr._.bI...G|
+00000320 9c e3 ce 6e a0 40 03 7d 41 4e 41 0d 21 ee e4 f6 |...n.@.}ANA.!...|
+00000330 71 74 12 48 1e d1 b2 80 82 b0 bf ff 07 61 04 82 |qt.H.........a..|
+00000340 db 4b 00 a1 11 97 48 1b 9b 13 b3 0e 5b 7f 99 f3 |.K....H.....[...|
+00000350 6f c1 a0 2f 41 d9 e2 30 f9 fa 0b 8a ef 6d d1 e1 |o../A..0.....m..|
+00000360 30 3d 07 5a 8a ef 8b a1 2b 44 c5 58 0d 3f 13 d7 |0=.Z....+D.X.?..|
+00000370 17 03 03 00 35 a2 fb e8 71 06 77 fa 70 66 75 01 |....5...q.w.pfu.|
+00000380 0a a0 d7 49 20 f0 8a f0 ea bf 79 20 68 46 02 43 |...I .....y hF.C|
+00000390 3c b9 cc c9 5f 1d c7 80 d8 58 f5 e3 94 6e 85 02 |<..._....X...n..|
+000003a0 c8 b2 4e a1 a2 43 b8 8d ae 89 17 03 03 00 93 4a |..N..C.........J|
+000003b0 dd 6b 37 b9 20 fa 51 b2 e2 60 a1 8e 08 40 bf c6 |.k7. .Q..`...@..|
+000003c0 25 22 9a 26 3a ec 35 aa f2 26 9c bc 39 05 91 7b |%".&:.5..&..9..{|
+000003d0 81 45 18 8d f7 f4 29 88 76 43 a8 63 e3 d3 59 d7 |.E....).vC.c..Y.|
+000003e0 2d 67 b3 4d 2f 6d c6 62 cf fd ac ed d6 80 04 57 |-g.M/m.b.......W|
+000003f0 b3 ac af 59 ce 35 43 94 1d 97 8c 2d 8d 89 b1 a7 |...Y.5C....-....|
+00000400 90 76 89 ec e4 0a 8f a9 9b 8d 22 02 8b 87 55 a4 |.v........"...U.|
+00000410 9b 55 da 85 a6 06 47 63 4c a2 1c 96 eb e1 77 35 |.U....GcL.....w5|
+00000420 71 0d 7e e5 78 ab 25 da ee 5e ae 07 a9 ed 44 3a |q.~.x.%..^....D:|
+00000430 75 ff 5c 4f 4e e5 01 27 7f 9e eb 63 db e2 85 70 |u.\ON..'...c...p|
+00000440 fc 99 |..|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 8c c8 26 94 66 |..........5..&.f|
+00000010 2e fd e0 4e bf b8 77 9d 12 d9 f6 9c 1b 15 c4 f1 |...N..w.........|
+00000020 39 f8 91 27 16 0c 34 ef 33 46 22 4e 19 d6 d0 d2 |9..'..4.3F"N....|
+00000030 ef 6b 57 91 f8 e4 17 fe f9 ec f4 f1 ce c0 44 26 |.kW...........D&|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 1e ab 4d 1a 04 59 10 8b ef f9 b5 8a |......M..Y......|
+00000010 62 34 91 4e f9 cd 93 8c 7a 6d be d6 72 42 ad 45 |b4.N....zm..rB.E|
+00000020 21 f5 4e 17 03 03 00 13 1e bf bd 27 1a ad ab 1f |!.N........'....|
+00000030 32 f5 99 95 dc 34 e3 eb 9c c1 1c |2....4.....|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-Ed25519 b/src/crypto/tls/testdata/Server-TLSv13-Ed25519
new file mode 100644
index 0000000..a94597a
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-Ed25519
@@ -0,0 +1,76 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 ca 01 00 00 c6 03 03 a1 5b 14 56 ac |............[.V.|
+00000010 3f 2b b0 8e e9 0b ae 7e f7 3b 3b 20 90 b6 e4 06 |?+.....~.;; ....|
+00000020 c2 b9 71 88 e4 4c 01 28 41 b3 e8 20 49 01 f7 fc |..q..L.(A.. I...|
+00000030 ce 52 3e f4 58 60 56 7d 36 21 ba 23 87 21 f7 36 |.R>.X`V}6!.#.!.6|
+00000040 48 88 22 78 26 37 27 a4 fc 7a 8b ea 00 04 13 03 |H."x&7'..z......|
+00000050 00 ff 01 00 00 79 00 0b 00 04 03 00 01 02 00 0a |.....y..........|
+00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 16 |................|
+00000070 00 00 00 17 00 00 00 0d 00 1e 00 1c 04 03 05 03 |................|
+00000080 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 |................|
+00000090 08 06 04 01 05 01 06 01 00 2b 00 03 02 03 04 00 |.........+......|
+000000a0 2d 00 02 01 01 00 33 00 26 00 24 00 1d 00 20 f4 |-.....3.&.$... .|
+000000b0 2c db e8 c0 9e 7d 52 f6 fa 33 fe f7 9a 66 ca 5f |,....}R..3...f._|
+000000c0 a3 28 e9 80 21 28 b8 ef e9 9f 1e 26 9c cf 0f |.(..!(.....&...|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 49 01 f7 fc |........... I...|
+00000030 ce 52 3e f4 58 60 56 7d 36 21 ba 23 87 21 f7 36 |.R>.X`V}6!.#.!.6|
+00000040 48 88 22 78 26 37 27 a4 fc 7a 8b ea 13 03 00 00 |H."x&7'..z......|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 17 f9 df 7b 4f f9 a1 |............{O..|
+00000090 f7 78 eb 10 59 5c 4f ed 42 09 08 10 0f c7 a4 81 |.x..Y\O.B.......|
+000000a0 8b 17 03 03 01 50 38 d7 96 35 05 7d 3d 3a 60 02 |.....P8..5.}=:`.|
+000000b0 bf 93 37 f2 60 3e 64 cb 1a 6f 9c 69 af 06 ca 70 |..7.`>d..o.i...p|
+000000c0 94 e2 d1 7f 4a 5d c7 57 0e 11 c7 4e 24 c6 ba 57 |....J].W...N$..W|
+000000d0 9f d7 67 3a 0a 8b 93 08 d4 de c5 be 62 79 61 2a |..g:........bya*|
+000000e0 3d 4e 57 f9 98 e5 4f 5e 5a 74 52 5b a4 d0 07 ae |=NW...O^ZtR[....|
+000000f0 8c 2a cb 50 dd b3 76 ab 3a 61 5b 55 83 8e 37 8d |.*.P..v.:a[U..7.|
+00000100 39 e5 4f 58 7e 7a bc 80 26 f6 0f 47 8f 11 55 77 |9.OX~z..&..G..Uw|
+00000110 24 b1 a7 06 d8 d2 30 82 0d 99 39 04 5f 97 d8 1d |$.....0...9._...|
+00000120 99 67 99 89 f0 ee 4f 18 8b 49 24 d3 6a d0 65 c9 |.g....O..I$.j.e.|
+00000130 01 a2 48 54 8b d2 bb 56 d4 0a 73 62 88 fa 70 4e |..HT...V..sb..pN|
+00000140 7f dd 59 5b 14 7b 28 02 07 75 01 4d 41 ab 1d 7e |..Y[.{(..u.MA..~|
+00000150 ef 24 42 ee 85 7f fa 5f 9e f0 9f f2 7f 92 00 52 |.$B...._.......R|
+00000160 ca 73 8a 73 c6 d7 13 f5 9d 31 6f 76 75 db e7 53 |.s.s.....1ovu..S|
+00000170 4d 44 40 8f 47 be bd 0e 71 13 d0 f7 f2 72 67 3a |MD@.G...q....rg:|
+00000180 de b8 da b0 1d 84 85 d0 c2 c4 8d 16 87 68 c7 98 |.............h..|
+00000190 40 0a 92 c8 fb 8a 3a e4 7b 34 43 47 b7 4f 28 8e |@.....:.{4CG.O(.|
+000001a0 11 01 98 88 b6 cd ca aa d4 dc 52 5d f9 cf 55 bb |..........R]..U.|
+000001b0 f3 13 f2 ce dc 67 74 a7 4d 5e 65 6f 18 cd 82 4e |.....gt.M^eo...N|
+000001c0 fc 80 2c 14 17 99 08 6d 59 b3 3f 38 00 52 a2 a3 |..,....mY.?8.R..|
+000001d0 c1 98 84 15 91 82 3f e9 47 82 12 a0 94 dc 19 9e |......?.G.......|
+000001e0 2e b7 25 79 30 b9 81 d6 9f 33 8e 49 80 7a 4c a2 |..%y0....3.I.zL.|
+000001f0 b7 9a e6 17 2c 06 17 03 03 00 59 97 c7 4b ac c3 |....,.....Y..K..|
+00000200 ed b3 bd 82 7a c2 45 a0 18 70 7b 88 fe 8b fd 6b |....z.E..p{....k|
+00000210 83 f2 dd 77 15 74 9c f0 a6 27 22 bf ee 25 53 07 |...w.t...'"..%S.|
+00000220 81 95 3c 91 b3 89 3c ca f9 5b c7 cf bb 32 55 f8 |..<...<..[...2U.|
+00000230 3c 76 70 f6 11 ca 5d 92 aa 78 9e 8a 2f ab e0 6f |<vp...]..x../..o|
+00000240 c0 94 df 24 59 05 83 1a 28 c9 23 c8 e9 92 e1 bf |...$Y...(.#.....|
+00000250 9c 90 99 07 17 03 03 00 35 4c 01 d0 d9 5f b3 6a |........5L..._.j|
+00000260 a3 50 58 45 99 82 f4 a5 52 73 9e 7d 54 62 88 b1 |.PXE....Rs.}Tb..|
+00000270 2a 11 56 be be 57 9c 34 77 88 ab ca a6 48 c8 47 |*.V..W.4w....H.G|
+00000280 a8 25 ff 84 c6 e7 49 4e 9a dd 6f 7f 2c 4f 17 03 |.%....IN..o.,O..|
+00000290 03 00 93 72 a7 27 87 ee 0d f2 27 49 d1 8a 3f 9a |...r.'....'I..?.|
+000002a0 4b 8c 67 72 58 b0 cf 11 24 72 44 6e e1 53 06 1f |K.grX...$rDn.S..|
+000002b0 6a 70 ce c8 46 40 ca a0 6c fd 09 1d b1 58 2a 8f |jp..F@..l....X*.|
+000002c0 13 37 00 3d 02 c0 a8 e2 bc 77 39 83 43 f5 c1 c5 |.7.=.....w9.C...|
+000002d0 d8 5f 32 0a 16 b1 25 4b 74 b8 b8 09 d8 c8 dd 7e |._2...%Kt......~|
+000002e0 c7 6e 03 16 93 f2 1e a2 14 e1 ee 14 ec 8d 59 4f |.n............YO|
+000002f0 f4 b5 50 f0 68 d3 06 ea 22 78 94 18 52 e7 3d 98 |..P.h..."x..R.=.|
+00000300 41 8c 5a bb d0 08 f7 b1 16 91 ce c9 73 41 24 e0 |A.Z.........sA$.|
+00000310 6d ea 7b e5 3f 98 9c d7 3f 91 2c 51 5a 9f ab 82 |m.{.?...?.,QZ...|
+00000320 4a f7 b7 39 f1 b5 |J..9..|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 19 fa 19 c0 ce |..........5.....|
+00000010 09 87 c2 06 69 56 2a 0a a7 9c 79 76 03 1b 70 5e |....iV*...yv..p^|
+00000020 56 2d d4 a1 09 e3 99 f7 a9 7a e5 ba 3e 17 8b b2 |V-.......z..>...|
+00000030 fe da 70 81 d9 30 83 27 b1 da 2e df da 94 75 72 |..p..0.'......ur|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 1e 83 53 ed 09 07 d3 87 ab 37 a2 08 |......S......7..|
+00000010 a8 50 66 87 97 54 04 38 4b a6 25 f8 ab 75 ac 39 |.Pf..T.8K.%..u.9|
+00000020 52 e2 8d 17 03 03 00 13 86 58 ef 44 c1 59 5e 2e |R........X.D.Y^.|
+00000030 e4 2e df 93 6e 52 76 58 c1 9d 2a |....nRvX..*|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-ExportKeyingMaterial b/src/crypto/tls/testdata/Server-TLSv13-ExportKeyingMaterial
new file mode 100644
index 0000000..8267ca0
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-ExportKeyingMaterial
@@ -0,0 +1,99 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 ce 01 00 00 ca 03 03 26 86 8d 61 97 |...........&..a.|
+00000010 6c da 93 d7 43 5c b3 0c 06 5c c2 cb e0 89 46 9f |l...C\...\....F.|
+00000020 cc b0 a3 cf 41 3d cf 7a 9e 02 bc 20 a6 33 fe 0b |....A=.z... .3..|
+00000030 90 24 8b ed 69 48 86 9b d2 1a 5c 04 66 52 4f 5d |.$..iH....\.fRO]|
+00000040 a4 24 6b d2 84 08 c0 48 a9 55 ef 0c 00 04 13 03 |.$k....H.U......|
+00000050 00 ff 01 00 00 7d 00 0b 00 04 03 00 01 02 00 0a |.....}..........|
+00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#|
+00000070 00 00 00 16 00 00 00 17 00 00 00 0d 00 1e 00 1c |................|
+00000080 04 03 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b |................|
+00000090 08 04 08 05 08 06 04 01 05 01 06 01 00 2b 00 03 |.............+..|
+000000a0 02 03 04 00 2d 00 02 01 01 00 33 00 26 00 24 00 |....-.....3.&.$.|
+000000b0 1d 00 20 b9 ab 39 93 6b 9f aa 46 0a 61 c6 f8 58 |.. ..9.k..F.a..X|
+000000c0 45 26 16 6f b6 cb 42 52 e8 24 ab cc a4 2d b6 7a |E&.o..BR.$...-.z|
+000000d0 a5 90 67 |..g|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 a6 33 fe 0b |........... .3..|
+00000030 90 24 8b ed 69 48 86 9b d2 1a 5c 04 66 52 4f 5d |.$..iH....\.fRO]|
+00000040 a4 24 6b d2 84 08 c0 48 a9 55 ef 0c 13 03 00 00 |.$k....H.U......|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 17 e9 4c 8a ed 0c af |...........L....|
+00000090 04 d2 18 14 38 48 c1 71 da 59 db 46 f4 00 0d 19 |....8H.q.Y.F....|
+000000a0 1e 17 03 03 02 6d e0 d2 7b bf 0a 51 48 a9 67 46 |.....m..{..QH.gF|
+000000b0 25 3b 07 e9 68 da 4d cf 47 31 0f 7d ad 4e 0d 6d |%;..h.M.G1.}.N.m|
+000000c0 c3 ad 03 61 4a c0 ae 06 4d b7 84 29 1b 44 49 26 |...aJ...M..).DI&|
+000000d0 f4 99 fc 58 1e 5b f0 15 ee be 19 c3 b3 23 20 f0 |...X.[.......# .|
+000000e0 7a 10 e4 ab c8 00 f6 e4 93 d6 b3 2a fd 14 10 c9 |z..........*....|
+000000f0 72 b2 21 ba 93 50 08 4e d2 1f 3f 64 68 73 3c c7 |r.!..P.N..?dhs<.|
+00000100 11 3c f5 84 61 b0 2c 84 42 0c ef a9 03 a2 74 aa |.<..a.,.B.....t.|
+00000110 3b 07 e0 d5 f5 c4 d1 a8 8e f5 64 0e 52 41 b1 4d |;.........d.RA.M|
+00000120 aa 43 0d f3 6b 0c 19 36 66 fe 4c 73 cd 52 03 2f |.C..k..6f.Ls.R./|
+00000130 61 f1 9d 23 12 e2 b9 69 d9 48 92 07 1b 5d 6f 28 |a..#...i.H...]o(|
+00000140 e1 96 39 d8 59 19 9d 9c bf 99 3a af 03 68 bd 34 |..9.Y.....:..h.4|
+00000150 38 04 9d 8c 9a bf 75 67 74 dd 9c eb 89 13 6d 55 |8.....ugt.....mU|
+00000160 b4 c4 17 11 05 54 d7 f9 d7 5a ed ec d5 15 31 5e |.....T...Z....1^|
+00000170 2f ed 69 fa 99 23 57 e3 62 98 35 27 17 34 e1 c4 |/.i..#W.b.5'.4..|
+00000180 3c 95 3f 69 de 01 aa a9 66 55 4a 40 3a f1 4f 19 |<.?i....fUJ@:.O.|
+00000190 02 2f df 51 0c 69 ec 48 7a 60 f7 72 5e f6 f0 4d |./.Q.i.Hz`.r^..M|
+000001a0 a1 b2 7a 06 df 69 a1 19 42 29 56 5c 67 99 3d 0e |..z..i..B)V\g.=.|
+000001b0 5d da df 7b 93 8e 9a 26 6e 2e 09 c4 30 40 ad a9 |]..{...&n...0@..|
+000001c0 ee 4b bd 21 41 b6 cb fc 97 0f fc a2 cf 26 31 d6 |.K.!A........&1.|
+000001d0 d6 77 96 4e c6 a2 fd 5a 0e cb d5 31 a6 21 e8 76 |.w.N...Z...1.!.v|
+000001e0 a2 48 4d 43 d4 c9 18 b2 21 cc 13 13 84 f2 c2 cf |.HMC....!.......|
+000001f0 60 8f 2e 36 39 8a a8 26 03 1d 51 24 b4 08 c5 5d |`..69..&..Q$...]|
+00000200 96 b9 4a 46 02 41 1f 59 ea 47 a9 37 bc a0 c4 70 |..JF.A.Y.G.7...p|
+00000210 26 d6 8c 11 62 45 1d 92 5d ea 39 cd af af 13 38 |&...bE..].9....8|
+00000220 85 ca a8 74 1a 09 07 f2 7c d6 49 0d 2d ad 1c 9f |...t....|.I.-...|
+00000230 db 8b 56 91 45 51 32 db ca 9c f4 d2 72 09 8a fe |..V.EQ2.....r...|
+00000240 98 9e a8 b5 b2 49 9c 0b e9 3a 42 d0 53 e0 20 6c |.....I...:B.S. l|
+00000250 e3 07 36 ef cc 85 56 fd b4 6e ff d2 7c 96 52 27 |..6...V..n..|.R'|
+00000260 46 c9 3c b3 bf fb 16 0b 61 54 09 9c ac 3b 18 5f |F.<.....aT...;._|
+00000270 5a 01 4b 25 67 22 ef 19 86 a3 3a 80 f0 12 f5 60 |Z.K%g"....:....`|
+00000280 4c 77 cf bd a9 e8 a1 19 d4 8c e1 a8 b2 b8 19 b8 |Lw..............|
+00000290 98 85 c3 da 1a b8 4d 6e 1f 35 73 28 32 3c a0 44 |......Mn.5s(2<.D|
+000002a0 c9 77 46 b8 c6 54 4d 80 67 72 58 c4 e3 0b f3 6c |.wF..TM.grX....l|
+000002b0 43 eb e2 89 f1 30 cc 90 b4 e9 b8 ec e2 5f c1 31 |C....0......._.1|
+000002c0 a2 de 9d e9 fe 9c fe b0 83 b7 aa e9 2e 62 35 89 |.............b5.|
+000002d0 90 0d 36 79 8f 23 bb 7a ae dc db db 1c c3 96 5d |..6y.#.z.......]|
+000002e0 7c 06 e9 1c ee 82 58 46 7c 1b 90 9d cf 2d 31 54 ||.....XF|....-1T|
+000002f0 96 94 58 dc 95 26 85 c7 f4 c9 9c 2b 8a 2f ae b3 |..X..&.....+./..|
+00000300 70 10 bf f1 0e 66 ef f1 1c 66 da 6c 52 d8 6e aa |p....f...f.lR.n.|
+00000310 3a 14 d8 17 03 03 00 99 69 45 ee c3 c9 b3 4d 9a |:.......iE....M.|
+00000320 01 00 70 27 54 8c 12 bb 74 67 e8 88 07 ac 4e ab |..p'T...tg....N.|
+00000330 b1 41 f4 65 ee 3b 06 87 79 5d 9b 1d 70 df 2f f7 |.A.e.;..y]..p./.|
+00000340 e0 88 45 2b a1 b9 ca 67 88 65 65 33 51 41 c0 b2 |..E+...g.ee3QA..|
+00000350 da 6a 7a 7c bf 42 58 8d ae 7b 24 d0 8a f7 47 c0 |.jz|.BX..{$...G.|
+00000360 a9 45 da 24 82 03 a1 65 03 7c 3c 2a bf 48 e2 0d |.E.$...e.|<*.H..|
+00000370 fa cc 3f 00 53 63 5d f9 b4 a1 00 d2 a7 3c 81 64 |..?.Sc]......<.d|
+00000380 8a d5 90 4f b9 58 2b 1e 1d a7 7e ad 3e 8f d4 4a |...O.X+...~.>..J|
+00000390 7b 66 b7 4e 68 04 ac 66 24 6e 76 ed f4 5c aa 52 |{f.Nh..f$nv..\.R|
+000003a0 3d f8 f5 ea d0 0a 74 ba 39 da 21 e0 f1 03 80 cd |=.....t.9.!.....|
+000003b0 5b 17 03 03 00 35 7b 1f 6e 37 6c 15 5b 1b f7 ea |[....5{.n7l.[...|
+000003c0 bf 03 68 5f 15 1f e7 99 a8 64 f1 60 3d e0 b6 5e |..h_.....d.`=..^|
+000003d0 c1 60 18 61 e5 ea dc ab b5 d3 5f 10 1b 5c 3a 1b |.`.a......_..\:.|
+000003e0 c5 fe a6 d3 fc 45 6b db b1 27 60 17 03 03 00 93 |.....Ek..'`.....|
+000003f0 e3 f1 5f f1 18 a6 ab 67 88 e4 5a f9 fd 71 77 4b |.._....g..Z..qwK|
+00000400 6c 0d 98 ef 71 72 2a aa d2 0a 2d 72 ac 40 57 2d |l...qr*...-r.@W-|
+00000410 73 ad 77 cd 01 19 19 be e7 49 d4 6a aa 97 f9 40 |s.w......I.j...@|
+00000420 b1 85 cc bb 5c 57 1a 17 a8 48 65 d3 4d e9 a9 29 |....\W...He.M..)|
+00000430 4b 08 6b b3 33 2c 97 d0 89 0a 50 e2 66 06 c6 63 |K.k.3,....P.f..c|
+00000440 c3 6f 8d 5e ab a4 af 7a 6a 5e 25 8d 4a 17 ea aa |.o.^...zj^%.J...|
+00000450 67 8a ad af c3 1e d6 47 db a5 b5 db 32 1b 83 f8 |g......G....2...|
+00000460 2d f9 bc 99 28 07 0d d0 fe 34 bf 52 ae 59 27 40 |-...(....4.R.Y'@|
+00000470 cd 0e 4d 4d 12 28 21 01 30 38 b1 c3 df 63 e9 9e |..MM.(!.08...c..|
+00000480 34 91 84 |4..|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 1d d8 d0 a8 ec |..........5.....|
+00000010 04 45 13 43 a1 72 38 4e 54 85 7a a2 17 dc eb 39 |.E.C.r8NT.z....9|
+00000020 36 7d 50 25 5f d3 0d 7f c3 a7 75 93 e9 1e 17 0a |6}P%_.....u.....|
+00000030 a3 d7 a8 74 23 98 5e 3a 3a 4c 2c d3 78 b4 04 48 |...t#.^::L,.x..H|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 1e 53 e2 0d f2 62 e8 be 84 e0 33 1a |.....S...b....3.|
+00000010 56 bc 45 f9 0b 69 63 72 03 f3 34 c6 72 d8 f9 c4 |V.E..icr..4.r...|
+00000020 ba 53 3d 17 03 03 00 13 11 b5 0d 7f d4 e7 51 90 |.S=...........Q.|
+00000030 39 be 2b d8 d6 7c e8 12 ea 61 83 |9.+..|...a.|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-HelloRetryRequest b/src/crypto/tls/testdata/Server-TLSv13-HelloRetryRequest
new file mode 100644
index 0000000..95eefd2
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-HelloRetryRequest
@@ -0,0 +1,123 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 c4 01 00 00 c0 03 03 16 5e f5 e2 4e |............^..N|
+00000010 27 ce 8e 88 0b e9 13 6d 12 a6 6d 27 c9 ab 95 47 |'......m..m'...G|
+00000020 6f 9d 5d a0 92 64 35 c1 b6 70 90 20 ff 47 6f 67 |o.]..d5..p. .Gog|
+00000030 69 49 88 2a 84 69 79 48 fe cc 92 db 6e 9e ab 47 |iI.*.iyH....n..G|
+00000040 8e 47 10 58 db ad 22 8e da bb 86 e6 00 04 13 03 |.G.X..".........|
+00000050 00 ff 01 00 00 73 00 0b 00 04 03 00 01 02 00 0a |.....s..........|
+00000060 00 06 00 04 00 1d 00 17 00 16 00 00 00 17 00 00 |................|
+00000070 00 0d 00 1e 00 1c 04 03 05 03 06 03 08 07 08 08 |................|
+00000080 08 09 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 |................|
+00000090 06 01 00 2b 00 03 02 03 04 00 2d 00 02 01 01 00 |...+......-.....|
+000000a0 33 00 26 00 24 00 1d 00 20 7e a4 de 34 df 01 99 |3.&.$... ~..4...|
+000000b0 37 77 f7 de 6a e2 79 e7 63 eb 86 6c 62 61 fd b0 |7w..j.y.c..lba..|
+000000c0 c6 95 04 c8 63 29 cd 32 00 |....c).2.|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 58 02 00 00 54 03 03 cf 21 ad 74 e5 |....X...T...!.t.|
+00000010 9a 61 11 be 1d 8c 02 1e 65 b8 91 c2 a2 11 16 7a |.a......e......z|
+00000020 bb 8c 5e 07 9e 09 e2 c8 a8 33 9c 20 ff 47 6f 67 |..^......3. .Gog|
+00000030 69 49 88 2a 84 69 79 48 fe cc 92 db 6e 9e ab 47 |iI.*.iyH....n..G|
+00000040 8e 47 10 58 db ad 22 8e da bb 86 e6 13 03 00 00 |.G.X..".........|
+00000050 0c 00 2b 00 02 03 04 00 33 00 02 00 17 14 03 03 |..+.....3.......|
+00000060 00 01 01 |...|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 16 03 03 00 e5 01 00 00 e1 03 |................|
+00000010 03 16 5e f5 e2 4e 27 ce 8e 88 0b e9 13 6d 12 a6 |..^..N'......m..|
+00000020 6d 27 c9 ab 95 47 6f 9d 5d a0 92 64 35 c1 b6 70 |m'...Go.]..d5..p|
+00000030 90 20 ff 47 6f 67 69 49 88 2a 84 69 79 48 fe cc |. .GogiI.*.iyH..|
+00000040 92 db 6e 9e ab 47 8e 47 10 58 db ad 22 8e da bb |..n..G.G.X.."...|
+00000050 86 e6 00 04 13 03 00 ff 01 00 00 94 00 0b 00 04 |................|
+00000060 03 00 01 02 00 0a 00 06 00 04 00 1d 00 17 00 16 |................|
+00000070 00 00 00 17 00 00 00 0d 00 1e 00 1c 04 03 05 03 |................|
+00000080 06 03 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 |................|
+00000090 08 06 04 01 05 01 06 01 00 2b 00 03 02 03 04 00 |.........+......|
+000000a0 2d 00 02 01 01 00 33 00 47 00 45 00 17 00 41 04 |-.....3.G.E...A.|
+000000b0 ca c3 69 88 b3 ed f4 ad 7f 9c 03 6c 7a 44 55 d6 |..i........lzDU.|
+000000c0 68 1d a4 27 67 57 d7 27 08 27 e8 b9 c9 32 49 a2 |h..'gW.'.'...2I.|
+000000d0 e4 f6 c2 f2 62 bd 74 67 77 f9 26 27 ee d7 a7 f0 |....b.tgw.&'....|
+000000e0 9c 9a 41 cd 8b bf 76 25 df ff 5a 9f 4e f5 41 95 |..A...v%..Z.N.A.|
+>>> Flow 4 (server to client)
+00000000 16 03 03 00 9b 02 00 00 97 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 ff 47 6f 67 |........... .Gog|
+00000030 69 49 88 2a 84 69 79 48 fe cc 92 db 6e 9e ab 47 |iI.*.iyH....n..G|
+00000040 8e 47 10 58 db ad 22 8e da bb 86 e6 13 03 00 00 |.G.X..".........|
+00000050 4f 00 2b 00 02 03 04 00 33 00 45 00 17 00 41 04 |O.+.....3.E...A.|
+00000060 1e 18 37 ef 0d 19 51 88 35 75 71 b5 e5 54 5b 12 |..7...Q.5uq..T[.|
+00000070 2e 8f 09 67 fd a7 24 20 3e b2 56 1c ce 97 28 5e |...g..$ >.V...(^|
+00000080 f8 2b 2d 4f 9e f1 07 9f 6c 4b 5b 83 56 e2 32 42 |.+-O....lK[.V.2B|
+00000090 e9 58 b6 d7 49 a6 b5 68 1a 41 03 56 6b dc 5a 89 |.X..I..h.A.Vk.Z.|
+000000a0 17 03 03 00 17 c0 07 64 56 b1 bb f8 bf 36 6b df |.......dV....6k.|
+000000b0 e9 ee 72 cc 79 45 f5 8c b8 0c b3 5d 17 03 03 02 |..r.yE.....]....|
+000000c0 6d 2e ab b5 84 4f d7 9e 4e 0d 6e a0 42 c1 f0 a6 |m....O..N.n.B...|
+000000d0 62 a3 26 eb 9d 9a 42 a5 5d 1f 59 ad 37 a9 8a af |b.&...B.].Y.7...|
+000000e0 0d 7b 8f 5a d1 d5 d8 bc 15 5b 0d 0e d2 a9 bb 14 |.{.Z.....[......|
+000000f0 56 ed 30 4e 9b aa f9 5a 66 7d 4c 41 8e 6d 58 90 |V.0N...Zf}LA.mX.|
+00000100 52 4a f2 78 72 59 34 aa 58 7e 0c 44 1e bc 84 d8 |RJ.xrY4.X~.D....|
+00000110 50 17 bd aa 8c 4c d0 c5 e7 69 32 b8 c3 d6 e6 f9 |P....L...i2.....|
+00000120 70 93 99 1c 75 1b 13 f2 85 e0 b5 07 1b d8 5a 31 |p...u.........Z1|
+00000130 0a 1a 2e 97 86 ff 75 a1 db 45 b2 47 68 ed 88 d9 |......u..E.Gh...|
+00000140 fe 31 c9 c0 5e 37 f2 62 37 f7 01 81 11 07 a7 0f |.1..^7.b7.......|
+00000150 44 ec 17 3a 4a 38 b3 91 9f 77 6f f9 58 9e 9c 12 |D..:J8...wo.X...|
+00000160 6e 54 4c de 43 58 46 a5 f6 c7 58 7e df 33 d7 91 |nTL.CXF...X~.3..|
+00000170 e5 cb 9e 28 9d 7f a7 8a bd be 01 48 b7 b1 1e e2 |...(.......H....|
+00000180 7a 80 aa f9 cd 3f 62 0d a0 a0 63 0c ca 4b 5f a8 |z....?b...c..K_.|
+00000190 a9 5f 42 ac 44 57 67 b2 0f 5a b5 bb 59 a9 56 bd |._B.DWg..Z..Y.V.|
+000001a0 28 3c fb 5e 43 33 61 43 7b 60 48 7d 27 67 6a 06 |(<.^C3aC{`H}'gj.|
+000001b0 ac 0d db e4 d2 d4 b8 fa fb e8 32 f3 22 83 3a 63 |..........2.".:c|
+000001c0 f6 73 02 62 e0 d5 8a d2 61 a5 bf e1 2d 10 59 93 |.s.b....a...-.Y.|
+000001d0 55 60 be 32 ce 5c d5 5a f0 54 21 7d 8a 02 23 cf |U`.2.\.Z.T!}..#.|
+000001e0 38 2b 2b 67 50 22 72 f7 f7 bf 20 c2 34 df ae 3a |8++gP"r... .4..:|
+000001f0 44 b0 a6 2a 51 79 6f b1 7b ff d7 77 45 83 a9 fa |D..*Qyo.{..wE...|
+00000200 bf 3c de 34 e8 6a 33 74 6c 24 0b 85 39 ea 7c 13 |.<.4.j3tl$..9.|.|
+00000210 43 26 13 1b 61 56 85 0a 08 83 04 45 5f 5a 36 df |C&..aV.....E_Z6.|
+00000220 17 c0 59 e9 92 d8 6b 78 66 1f 43 a0 99 f8 4b b1 |..Y...kxf.C...K.|
+00000230 f0 8d 25 6f 0f 2e c7 f9 4d bb 79 74 b8 95 e6 b7 |..%o....M.yt....|
+00000240 41 0c de 2a d3 7e fc 0f 18 87 2d 21 dd 8d 5f 20 |A..*.~....-!.._ |
+00000250 4c 88 cb 63 f4 9c 07 64 14 02 0c 19 46 32 e5 1e |L..c...d....F2..|
+00000260 85 84 4a 71 b8 a5 50 92 ca 72 fe f4 9c 69 05 d4 |..Jq..P..r...i..|
+00000270 93 22 38 c1 09 e2 da 49 17 e8 e1 b3 f9 42 ee bf |."8....I.....B..|
+00000280 ea 40 b2 00 af b9 a8 f9 97 8e ef de 41 de 01 87 |.@..........A...|
+00000290 cc 13 23 64 8c a1 10 9a 91 38 9b cb fb 0b 04 66 |..#d.....8.....f|
+000002a0 fb 4b e3 77 e7 da 7a 75 5c 66 20 7e dc 22 a9 e6 |.K.w..zu\f ~."..|
+000002b0 6a 27 06 ed 3c fc 4c 30 ed f0 31 92 b2 eb a1 f3 |j'..<.L0..1.....|
+000002c0 a4 fd 83 20 37 62 71 95 ff 7c 65 e8 88 aa e7 c7 |... 7bq..|e.....|
+000002d0 3f 17 9c 94 6f 1a d9 c8 ac 00 8d ec 30 22 98 85 |?...o.......0"..|
+000002e0 da cc 69 41 f4 3a 66 1b e6 4c 38 62 8d 37 dc a1 |..iA.:f..L8b.7..|
+000002f0 08 cf 88 d4 26 7f 47 33 54 d8 aa d6 c5 02 fc 72 |....&.G3T......r|
+00000300 ff 50 19 9f 4a 0e 8b c8 32 6d 8e 15 e4 f1 ed 2e |.P..J...2m......|
+00000310 43 cb 9f 8c 7a 0e e1 a2 79 e2 f9 52 12 e4 2f a9 |C...z...y..R../.|
+00000320 c1 c5 0b 1f c2 21 c5 2e 21 de 3e 76 29 db 17 03 |.....!..!.>v)...|
+00000330 03 00 99 8a ee 54 88 93 d0 4b a0 31 18 ed 83 ff |.....T...K.1....|
+00000340 2c 44 78 ab 88 ea 72 d2 2a 27 71 a9 a1 ba 26 a5 |,Dx...r.*'q...&.|
+00000350 9a 9b 64 92 e8 c9 f8 02 47 b9 9f 53 95 a8 ad 5b |..d.....G..S...[|
+00000360 bd 81 17 87 69 0c 77 c1 0e d7 cb 5b 9f 2d 36 86 |....i.w....[.-6.|
+00000370 f5 fc 6d ba d8 f5 63 dd e4 f5 0a 61 8d b2 a9 bb |..m...c....a....|
+00000380 a5 a5 d6 41 d4 aa db 46 79 56 02 51 f4 ac d3 57 |...A...FyV.Q...W|
+00000390 57 b4 53 71 9f fe ea a6 76 f3 0f ca 39 93 f3 34 |W.Sq....v...9..4|
+000003a0 c6 96 96 09 8e 12 04 cc 1e 82 9f 78 6b 1c a2 fc |...........xk...|
+000003b0 0c 9d c6 00 3c 33 3a 92 c5 ce 96 15 50 1a 75 6d |....<3:.....P.um|
+000003c0 85 ec b6 64 12 2b eb 3a 52 8f 6d 35 17 03 03 00 |...d.+.:R.m5....|
+000003d0 35 7f 2b 30 fa e0 92 25 a2 1b 11 f8 cd 04 0d 57 |5.+0...%.......W|
+000003e0 01 42 cf e9 0c 92 7f d1 fd fa 26 61 0d 85 d7 d5 |.B........&a....|
+000003f0 3c fd cf 73 98 dc 88 a2 76 63 59 82 45 2d e3 bc |<..s....vcY.E-..|
+00000400 a2 c0 0b 83 41 75 17 03 03 00 93 f3 17 09 b2 e8 |....Au..........|
+00000410 53 11 9b 3e 3a 10 a0 e6 58 04 81 82 cb eb a5 19 |S..>:...X.......|
+00000420 0f a3 25 e2 eb ab 7c 07 2b e6 22 19 30 aa fc a6 |..%...|.+.".0...|
+00000430 bd c4 7d 69 33 38 2b 58 55 5b a7 27 29 86 af d5 |..}i38+XU[.')...|
+00000440 f9 5a b4 85 ad a0 73 ab f7 61 3f 2e 66 53 f5 8f |.Z....s..a?.fS..|
+00000450 c7 09 4b 01 99 d0 68 93 32 d1 2e 8f 89 e5 e1 ea |..K...h.2.......|
+00000460 ba f2 fb 07 ee 58 7c 28 ff 59 1d d7 f7 b3 e2 56 |.....X|(.Y.....V|
+00000470 98 56 cd 9d d1 4f 26 7e 77 0d a0 c1 92 c5 a0 83 |.V...O&~w.......|
+00000480 c9 7c d8 7d a8 91 d3 ae 71 41 1d 06 33 68 b8 52 |.|.}....qA..3h.R|
+00000490 ad 84 a7 21 80 8f e5 c6 37 11 da 6c 5a 3a |...!....7..lZ:|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 35 28 34 b9 16 07 9a c1 82 ad 9f b7 |....5(4.........|
+00000010 78 fa 1a d0 1f 57 98 95 37 86 cf 1d 67 19 47 48 |x....W..7...g.GH|
+00000020 e9 ab fe 0c ff 26 c6 78 88 1a ad 75 48 63 4b 6e |.....&.x...uHcKn|
+00000030 72 4a 44 4f 27 b6 9d 56 b6 43 |rJDO'..V.C|
+>>> Flow 6 (server to client)
+00000000 17 03 03 00 1e d9 1f 35 86 22 7e 10 f1 8d e5 82 |.......5."~.....|
+00000010 f2 f6 88 81 a3 66 da 6a 1e 2f 94 94 16 02 2a 52 |.....f.j./....*R|
+00000020 69 8b bb 17 03 03 00 13 3c 87 88 8c c0 78 64 18 |i.......<....xd.|
+00000030 9a 9e 07 fd ac d7 2d 5d ab bf a8 |......-]...|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-IssueTicket b/src/crypto/tls/testdata/Server-TLSv13-IssueTicket
new file mode 100644
index 0000000..fa1f801
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-IssueTicket
@@ -0,0 +1,99 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 ce 01 00 00 ca 03 03 bb e2 a4 a5 7e |...............~|
+00000010 63 65 5c a5 7f 3f 13 a1 9d 5f 53 3c d2 b1 84 bd |ce\..?..._S<....|
+00000020 51 0c 9a 14 e8 8a 5a 53 b8 27 88 20 e7 04 4d dc |Q.....ZS.'. ..M.|
+00000030 76 f3 7f bd 00 ce 46 d2 a6 58 26 99 02 91 88 bf |v.....F..X&.....|
+00000040 b5 6b 56 2b b6 bc 51 b2 e4 cd 82 8d 00 04 13 01 |.kV+..Q.........|
+00000050 00 ff 01 00 00 7d 00 0b 00 04 03 00 01 02 00 0a |.....}..........|
+00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#|
+00000070 00 00 00 16 00 00 00 17 00 00 00 0d 00 1e 00 1c |................|
+00000080 04 03 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b |................|
+00000090 08 04 08 05 08 06 04 01 05 01 06 01 00 2b 00 03 |.............+..|
+000000a0 02 03 04 00 2d 00 02 01 01 00 33 00 26 00 24 00 |....-.....3.&.$.|
+000000b0 1d 00 20 b2 99 9c bb d1 4c c7 61 5f aa bf 2f 06 |.. .....L.a_../.|
+000000c0 a3 50 e7 49 7d 11 ae 68 9b b0 be be 82 6d 27 29 |.P.I}..h.....m')|
+000000d0 89 4c 4a |.LJ|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 e7 04 4d dc |........... ..M.|
+00000030 76 f3 7f bd 00 ce 46 d2 a6 58 26 99 02 91 88 bf |v.....F..X&.....|
+00000040 b5 6b 56 2b b6 bc 51 b2 e4 cd 82 8d 13 01 00 00 |.kV+..Q.........|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 17 c6 67 93 be 69 04 |...........g..i.|
+00000090 58 4f 1d 93 b6 5c 1c 10 8a 91 d0 c0 db 0b d1 0a |XO...\..........|
+000000a0 d1 17 03 03 02 6d da d6 28 74 c7 60 d6 02 3e 28 |.....m..(t.`..>(|
+000000b0 29 17 50 b9 01 4b 9b 93 07 9d 09 f0 17 05 e0 88 |).P..K..........|
+000000c0 53 ec c3 28 f7 a6 4e 9b 80 a3 fd 20 db 97 51 6a |S..(..N.... ..Qj|
+000000d0 b1 7a 6d 93 26 61 c8 9c 6d 37 65 94 b4 74 a0 60 |.zm.&a..m7e..t.`|
+000000e0 b1 a1 38 4c eb 5e a9 c4 bd d4 29 ee e9 e3 ab 56 |..8L.^....)....V|
+000000f0 68 67 57 da b3 3d 85 bd 26 67 e1 52 83 a6 69 14 |hgW..=..&g.R..i.|
+00000100 3b 30 31 c7 71 83 fa 62 13 ea a3 a5 de 4b 32 3f |;01.q..b.....K2?|
+00000110 c6 48 0b 96 cd 4b da 96 6d e2 31 88 ca 96 5f 63 |.H...K..m.1..._c|
+00000120 cb 39 37 d8 fa 8f 1f b9 e2 c5 6b ae 60 05 5b ed |.97.......k.`.[.|
+00000130 e0 5d 83 fa 2b 22 f4 e8 33 27 48 e7 c4 3d 54 22 |.]..+"..3'H..=T"|
+00000140 5a 60 a9 7a 0d 9b 42 e2 50 28 0e 6c 13 16 a1 51 |Z`.z..B.P(.l...Q|
+00000150 60 81 8f 80 e2 1b 53 24 62 78 b7 0a 4a 9b 2f a7 |`.....S$bx..J./.|
+00000160 97 b3 ba e5 34 0d 76 a6 0e ea ec 91 f0 9c a9 6d |....4.v........m|
+00000170 57 47 ef a3 c4 7a 62 a8 1f c0 1a d7 ea 31 90 20 |WG...zb......1. |
+00000180 76 13 ae f1 24 9d 60 9f 30 9f 2b 2a 2f 0a 39 6c |v...$.`.0.+*/.9l|
+00000190 7a 47 fe 11 1c 78 42 a1 1c ed c3 cd d2 6a cd 4f |zG...xB......j.O|
+000001a0 66 1b 51 d4 43 4e 45 23 15 48 e4 84 3e 89 a3 55 |f.Q.CNE#.H..>..U|
+000001b0 7e b0 a6 c2 1c cd eb cf 88 6b e7 d2 07 25 ef 37 |~........k...%.7|
+000001c0 e1 8a a5 b9 03 7e 70 73 9c 23 1a 62 07 56 db ed |.....~ps.#.b.V..|
+000001d0 93 e3 8a 91 8b 90 74 14 14 cc ff 9e ea e5 45 dd |......t.......E.|
+000001e0 a6 2d dc e6 cb 8c 59 33 91 da e6 5c b4 73 4f 36 |.-....Y3...\.sO6|
+000001f0 f1 3c d9 6e ba 2c c4 51 de 4f 8a 69 62 c4 db b1 |.<.n.,.Q.O.ib...|
+00000200 9e 67 7a 5f 01 7b b7 b2 55 b1 14 c0 46 d1 43 16 |.gz_.{..U...F.C.|
+00000210 a0 70 84 7e b8 a3 04 ce e3 e0 0e 5e 5f 3f 95 7a |.p.~.......^_?.z|
+00000220 ef 79 8d 50 84 cd 02 f1 e0 e5 f9 26 cf 7a f9 da |.y.P.......&.z..|
+00000230 a3 7d 22 31 4d 61 82 f6 ff fd 69 23 07 53 07 df |.}"1Ma....i#.S..|
+00000240 5a eb 50 86 28 44 24 06 9b 21 ef ef 78 bc 67 13 |Z.P.(D$..!..x.g.|
+00000250 c5 27 d8 18 db c7 fa d5 a6 0c 40 09 e3 e5 17 0c |.'........@.....|
+00000260 61 ae bc 48 98 ab 7b 57 82 f7 87 a5 4b 96 25 77 |a..H..{W....K.%w|
+00000270 e4 59 53 d1 d3 7b 55 08 e0 1a 5d 9b 0f 2e 6f cd |.YS..{U...]...o.|
+00000280 96 9d 19 09 07 84 08 c1 cf bd 99 af 80 52 c0 f7 |.............R..|
+00000290 0c 50 85 14 7c fd cb 61 01 05 ee 92 60 bb ac 4c |.P..|..a....`..L|
+000002a0 b4 37 48 dc b1 34 9d 26 3a fd dc ae 21 2f d3 51 |.7H..4.&:...!/.Q|
+000002b0 84 c3 0e 8f e1 b4 fb 0b 2e 3b 51 a9 e8 c2 d9 d9 |.........;Q.....|
+000002c0 6b a5 af 90 30 97 a2 32 9a a3 9d 5d b3 75 c6 48 |k...0..2...].u.H|
+000002d0 4b ee a3 23 85 98 a5 b5 00 fd c5 3a 27 65 9e d0 |K..#.......:'e..|
+000002e0 19 a8 5a 8c 8b eb 49 c6 58 16 9a 88 67 54 82 a9 |..Z...I.X...gT..|
+000002f0 29 0a 98 82 e4 f8 f0 c9 17 a6 81 91 1b c1 2a b7 |).............*.|
+00000300 de c3 8b 2d a6 55 1f 61 89 90 84 15 c8 33 6e cb |...-.U.a.....3n.|
+00000310 5c f4 e2 17 03 03 00 99 49 e0 38 43 34 61 b9 37 |\.......I.8C4a.7|
+00000320 2c 3e d5 c7 8c d7 9b a6 6c 8e ef a6 28 13 3c 79 |,>......l...(.<y|
+00000330 36 35 3e ba 70 5b 4e 6b c3 f5 52 06 ae ff 68 1d |65>.p[Nk..R...h.|
+00000340 a0 07 ac c1 17 6e d1 11 76 1d d7 1e e2 26 3e 76 |.....n..v....&>v|
+00000350 2b f9 a4 55 67 0b 9c cd db ab 71 1a 84 33 74 eb |+..Ug.....q..3t.|
+00000360 b1 4b 26 d8 e8 1c 84 2b 62 c7 70 27 16 fb 16 ae |.K&....+b.p'....|
+00000370 9d 72 3a 42 c1 cb cd c8 d0 dd 9c f0 51 2e 33 c1 |.r:B........Q.3.|
+00000380 46 35 56 ad 3b ea be 6e 14 4d 05 d1 6d 85 93 86 |F5V.;..n.M..m...|
+00000390 cc 6a 1c bf 03 cf 8f 92 c9 18 74 e0 66 0a b6 9a |.j........t.f...|
+000003a0 38 ac 1a 73 f4 e0 70 ec 93 61 67 9f b8 12 6f 1f |8..s..p..ag...o.|
+000003b0 17 17 03 03 00 35 59 6b 86 a8 cc 89 c6 fa 4f 95 |.....5Yk......O.|
+000003c0 25 b6 90 08 ac bf 9f d5 c9 3c 6c e5 cd 0d 14 00 |%........<l.....|
+000003d0 20 c9 01 ca 44 bc 9f 66 e0 3d e9 a0 11 40 c7 72 | ...D..f.=...@.r|
+000003e0 57 c8 54 d2 30 65 34 a1 09 27 63 17 03 03 00 93 |W.T.0e4..'c.....|
+000003f0 34 b8 fe 42 51 8b 9a 39 66 52 ec 19 95 2d 38 84 |4..BQ..9fR...-8.|
+00000400 36 36 09 e8 7c 86 51 81 90 7c b8 3b ed ec 9e a9 |66..|.Q..|.;....|
+00000410 09 ef 3b ca 86 2c 4d 05 3c 83 62 1c 8c e2 73 a1 |..;..,M.<.b...s.|
+00000420 3b 99 97 d9 90 24 df be 94 67 73 36 ac 92 ce 10 |;....$...gs6....|
+00000430 7a be 6f 1f b8 9d 0c c5 31 90 47 95 02 4d bd 86 |z.o.....1.G..M..|
+00000440 1a 89 3c e7 b6 71 9a f0 5c 36 41 a2 8f b6 d3 5c |..<..q..\6A....\|
+00000450 3b 2f a2 0e c8 c5 ae eb d1 4a d2 ab 12 8c 86 3a |;/.......J.....:|
+00000460 51 ef 9a e0 44 6f 0a cc 17 61 5d 12 db 2c d7 9f |Q...Do...a]..,..|
+00000470 d1 a3 30 2e ad f2 4c c8 f8 1e 7f 4c a5 8c c6 f8 |..0...L....L....|
+00000480 3d cb 01 |=..|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 74 1e 4a 56 2c |..........5t.JV,|
+00000010 fc 14 0b 66 ab 2f 56 5b fd 33 fe c2 a4 df 0b 62 |...f./V[.3.....b|
+00000020 63 11 40 67 d2 11 1b 53 c5 b9 1e 0e 20 83 85 b0 |c.@g...S.... ...|
+00000030 3a 81 79 bc a7 9f 49 ab 22 bd 10 8d 3e c9 95 79 |:.y...I."...>..y|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 1e a4 83 3b 61 a1 00 d5 56 84 4c 83 |.......;a...V.L.|
+00000010 0a 8c 86 13 0c e7 95 71 aa 48 e0 d2 5f 11 5f 45 |.......q.H.._._E|
+00000020 41 7a 10 17 03 03 00 13 ca 8b f5 38 e5 5f e0 8a |Az.........8._..|
+00000030 e3 08 ba 7d 06 f6 b3 b4 6f e9 2b |...}....o.+|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-IssueTicketPreDisable b/src/crypto/tls/testdata/Server-TLSv13-IssueTicketPreDisable
new file mode 100644
index 0000000..a939822
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-IssueTicketPreDisable
@@ -0,0 +1,99 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 ce 01 00 00 ca 03 03 cd 51 e4 0b ee |............Q...|
+00000010 9c 83 0f a1 bd 1a c8 b4 94 17 5e 17 fb 63 43 31 |..........^..cC1|
+00000020 89 86 03 fa 82 d4 bb c5 ba 9d 60 20 a1 0b c7 9c |..........` ....|
+00000030 b0 3f d9 7a 52 bd c0 3f cd c5 21 54 40 a5 60 73 |.?.zR..?..!T@.`s|
+00000040 fd ff 07 99 75 59 0d f3 bd 57 f6 81 00 04 13 01 |....uY...W......|
+00000050 00 ff 01 00 00 7d 00 0b 00 04 03 00 01 02 00 0a |.....}..........|
+00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#|
+00000070 00 00 00 16 00 00 00 17 00 00 00 0d 00 1e 00 1c |................|
+00000080 04 03 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b |................|
+00000090 08 04 08 05 08 06 04 01 05 01 06 01 00 2b 00 03 |.............+..|
+000000a0 02 03 04 00 2d 00 02 01 01 00 33 00 26 00 24 00 |....-.....3.&.$.|
+000000b0 1d 00 20 04 16 08 0b 67 76 58 60 4a 32 c2 ea 1b |.. ....gvX`J2...|
+000000c0 4a 54 fa 55 9b 39 d8 80 c4 eb 42 cc 1a 84 fe d7 |JT.U.9....B.....|
+000000d0 0a 0d 43 |..C|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 a1 0b c7 9c |........... ....|
+00000030 b0 3f d9 7a 52 bd c0 3f cd c5 21 54 40 a5 60 73 |.?.zR..?..!T@.`s|
+00000040 fd ff 07 99 75 59 0d f3 bd 57 f6 81 13 01 00 00 |....uY...W......|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 17 ec 4d 41 82 de 4f |...........MA..O|
+00000090 c6 cf 1e 56 06 65 0e a4 e7 66 34 1d 89 59 b3 c2 |...V.e...f4..Y..|
+000000a0 0a 17 03 03 02 6d 00 e1 17 f1 b3 5e a7 14 b3 f8 |.....m.....^....|
+000000b0 3a ab 85 d4 80 75 69 01 6c 91 3f 79 ab 8f 51 e0 |:....ui.l.?y..Q.|
+000000c0 f6 a5 65 ab 7e 72 e5 83 99 b2 cb cd f9 5f 27 db |..e.~r......._'.|
+000000d0 90 70 9c c1 e5 6d 80 3e 59 7c 4d fa f1 23 8a a7 |.p...m.>Y|M..#..|
+000000e0 f4 81 22 32 5b e2 4e d0 eb ab bd 96 05 42 05 5c |.."2[.N......B.\|
+000000f0 20 5c 8a 3e ca fd b8 aa dd f2 c4 3e dc 7e a5 ab | \.>.......>.~..|
+00000100 95 a4 20 03 0e 41 9b 14 55 91 1b 9c 3b 17 bc 2a |.. ..A..U...;..*|
+00000110 60 c0 ee b1 78 e9 37 c4 65 ef 8c 29 ec d9 10 81 |`...x.7.e..)....|
+00000120 a0 1d c9 ac cf e5 36 90 88 d3 70 6d 59 66 61 a8 |......6...pmYfa.|
+00000130 18 79 ad d8 c7 3e 1f a5 db dc b5 21 83 b0 ae 16 |.y...>.....!....|
+00000140 ce 8e 98 d4 8e 28 c1 d3 d2 ef 51 35 45 41 a7 b4 |.....(....Q5EA..|
+00000150 e1 15 bb 32 10 aa b1 27 be 53 5e 96 ef 0b bd 2f |...2...'.S^..../|
+00000160 81 66 18 f4 8b 9a cc be 67 c1 32 e3 c0 ea e5 c0 |.f......g.2.....|
+00000170 76 2c 36 7f 91 11 13 c1 a4 04 7e 8e 7b 60 a5 3d |v,6.......~.{`.=|
+00000180 fa 3c d8 68 9a 7e 4b 23 3d 18 1b a3 34 a9 81 a4 |.<.h.~K#=...4...|
+00000190 00 09 cd 56 eb f2 29 9f 17 8d 48 4d 21 a2 4e ec |...V..)...HM!.N.|
+000001a0 f0 a0 8d b1 ed d6 c7 01 d0 8e 2f 25 65 9f ac eb |........../%e...|
+000001b0 44 09 f2 75 db 37 a3 94 cb 70 29 59 37 97 71 63 |D..u.7...p)Y7.qc|
+000001c0 9b fa 0f 0f 33 75 0a 60 4f 78 97 9e 6a 2c 4b df |....3u.`Ox..j,K.|
+000001d0 54 cc c0 ac 57 4c f3 3a e3 79 01 b9 c3 8c 37 d2 |T...WL.:.y....7.|
+000001e0 8f d9 e7 cd 33 5a 0c bb 43 7e 39 5f 63 9f a5 11 |....3Z..C~9_c...|
+000001f0 f5 6e e0 95 1f 09 03 56 0f ec b9 7d 08 31 c5 57 |.n.....V...}.1.W|
+00000200 fa a6 57 15 6c 6b 91 d4 9f 5d c2 40 8b 3d 3a 57 |..W.lk...].@.=:W|
+00000210 c2 64 55 bd 88 bb 5e 24 7f fe 79 0c 88 f3 a7 1c |.dU...^$..y.....|
+00000220 f8 20 6f ba d6 ec fc b2 04 2a d7 b7 17 5e 4c 2e |. o......*...^L.|
+00000230 24 cd 1b 8a 04 fe 21 e0 5b 90 ec f4 30 df bf fe |$.....!.[...0...|
+00000240 a8 f9 2b 40 c1 23 15 f2 44 87 9a aa 30 80 70 27 |..+@.#..D...0.p'|
+00000250 80 6f 90 08 b5 47 2e 01 ea 77 3a ba a4 4b 77 8a |.o...G...w:..Kw.|
+00000260 12 b4 4e e1 a6 04 8a 01 31 60 27 35 bf 76 de 09 |..N.....1`'5.v..|
+00000270 aa 8a c4 c4 21 31 9f eb c2 92 05 be a1 b5 24 eb |....!1........$.|
+00000280 71 24 55 f9 aa 5c 62 59 49 bf 42 4c 69 01 4f f7 |q$U..\bYI.BLi.O.|
+00000290 b6 27 14 d4 cc 40 80 13 9b 8b 30 55 1f 32 c1 ee |.'...@....0U.2..|
+000002a0 51 bd 71 f7 63 3f c2 00 90 60 dc 13 0f 62 c3 06 |Q.q.c?...`...b..|
+000002b0 80 f6 4f cc 44 71 d7 5c 2e 18 82 45 ca 80 b7 0e |..O.Dq.\...E....|
+000002c0 0c 6f 75 1b 23 cb 86 c1 2d 1e 1b 02 2a 15 fa c7 |.ou.#...-...*...|
+000002d0 b2 af 80 5c 48 c2 b7 12 59 a3 e4 3c ed df 26 d0 |...\H...Y..<..&.|
+000002e0 85 9b 5a 2d 7b 66 e6 c4 b3 fe cd 4d 72 4d fb da |..Z-{f.....MrM..|
+000002f0 1c 0d 5c fb 2f 8a e3 70 98 ee 95 9c 12 1a fa c7 |..\./..p........|
+00000300 94 7a 8e ca 4d a4 bb 2f 70 3b 67 95 fb 23 fb 8f |.z..M../p;g..#..|
+00000310 8c 77 4c 17 03 03 00 99 8a 72 14 c7 82 18 d7 ed |.wL......r......|
+00000320 c7 5d 32 df 44 91 6b 40 3e 0b eb a1 74 da d9 3a |.]2.D.k@>...t..:|
+00000330 3c 7a 2e 7a 73 3b 63 72 33 c4 c5 27 29 33 f5 30 |<z.zs;cr3..')3.0|
+00000340 cf d3 e7 50 3f 44 33 79 6c 96 ed 80 32 02 5f 6b |...P?D3yl...2._k|
+00000350 d7 ec d7 67 df 2d 7d bc 2b dd f0 21 39 ef 54 9b |...g.-}.+..!9.T.|
+00000360 c3 55 1f f9 85 c4 4e 31 ce ba 28 a5 3d 68 64 60 |.U....N1..(.=hd`|
+00000370 9e 0a 99 76 a3 25 7c d6 4f 30 37 48 b4 93 6a 4f |...v.%|.O07H..jO|
+00000380 ff 0b df 83 ac 6f 27 9e ec d0 01 17 03 b9 a8 74 |.....o'........t|
+00000390 b9 b4 4c 59 ae da de 8a 18 16 54 18 ac 69 01 20 |..LY......T..i. |
+000003a0 6c f3 0b 93 8d 8c e7 70 79 d5 be 80 5e 87 5a 9c |l......py...^.Z.|
+000003b0 86 17 03 03 00 35 a7 cf 76 44 4f 48 f3 8c 9b 43 |.....5..vDOH...C|
+000003c0 a2 4e bf c5 e3 e7 08 43 d1 a4 4d 92 b3 3b f4 0a |.N.....C..M..;..|
+000003d0 06 2f b0 84 43 39 8e 29 a9 42 5d 63 c1 b2 f3 2d |./..C9.).B]c...-|
+000003e0 0e 57 8e c6 39 aa 29 45 d3 7e 78 17 03 03 00 93 |.W..9.)E.~x.....|
+000003f0 af 0d 9c 38 bd aa 63 fc de 80 59 28 32 11 0f f5 |...8..c...Y(2...|
+00000400 91 57 cd 15 f7 21 37 43 71 d8 32 7d 14 4b d2 28 |.W...!7Cq.2}.K.(|
+00000410 03 45 12 b5 cf f2 55 02 ae 47 34 ac f0 4c 6e d6 |.E....U..G4..Ln.|
+00000420 30 e4 eb 22 08 a8 10 8c bb 40 6e ec 96 68 b5 6b |0..".....@n..h.k|
+00000430 c2 a0 eb fb 53 49 4c 1d 73 b5 4d 80 18 b2 e4 af |....SIL.s.M.....|
+00000440 8b fa 85 f4 48 d4 e6 51 58 16 04 87 53 5c ff 93 |....H..QX...S\..|
+00000450 3d a8 e4 79 7e 82 79 e9 1f 6a dc ba 43 6f 15 b6 |=..y~.y..j..Co..|
+00000460 35 1b 84 72 a3 4c 65 3d f3 71 45 0b dc b9 74 13 |5..r.Le=.qE...t.|
+00000470 ed ce 9c fc dd b3 8c d8 ce 84 3e 95 d2 7e 62 60 |..........>..~b`|
+00000480 5d 0a 82 |]..|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 35 fd 9a 7d 02 |..........55..}.|
+00000010 fb b2 eb fa 51 27 3e 80 ab 60 f6 a1 54 31 13 2f |....Q'>..`..T1./|
+00000020 02 b9 19 ac 68 be 25 69 b3 c4 48 87 42 75 b0 93 |....h.%i..H.Bu..|
+00000030 66 3e 2e 0b 79 4f 0b 3a 59 ef 89 83 65 c9 10 9b |f>..yO.:Y...e...|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 1e 58 0f 73 e3 ba ff d3 19 0d 89 c9 |.....X.s........|
+00000010 94 8a fb 24 02 58 2a 2c eb 69 29 4e 57 d3 d2 5e |...$.X*,.i)NW..^|
+00000020 ba b2 75 17 03 03 00 13 9c 5c 46 44 71 dc 68 b8 |..u......\FDq.h.|
+00000030 39 cc e1 fd 2d 2a a1 a9 50 6c af |9...-*..Pl.|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-P256 b/src/crypto/tls/testdata/Server-TLSv13-P256
new file mode 100644
index 0000000..dd8e0f4
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-P256
@@ -0,0 +1,102 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 e3 01 00 00 df 03 03 c8 5f 11 a2 29 |............_..)|
+00000010 7b c3 b7 72 5e ba e1 c5 83 45 c8 87 e1 51 27 d9 |{..r^....E...Q'.|
+00000020 33 0e 68 e0 71 76 9e 8f 4e f4 da 20 da fd c6 1d |3.h.qv..N.. ....|
+00000030 46 55 42 89 0a 80 e0 d3 e4 dd db 7d b1 3a 76 a3 |FUB........}.:v.|
+00000040 5b d9 2a c7 f1 1a 3b 0b 8c 24 dd 4d 00 04 13 03 |[.*...;..$.M....|
+00000050 00 ff 01 00 00 92 00 0b 00 04 03 00 01 02 00 0a |................|
+00000060 00 04 00 02 00 17 00 16 00 00 00 17 00 00 00 0d |................|
+00000070 00 1e 00 1c 04 03 05 03 06 03 08 07 08 08 08 09 |................|
+00000080 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 06 01 |................|
+00000090 00 2b 00 03 02 03 04 00 2d 00 02 01 01 00 33 00 |.+......-.....3.|
+000000a0 47 00 45 00 17 00 41 04 04 48 71 9f a6 06 17 16 |G.E...A..Hq.....|
+000000b0 04 d2 b4 e7 6b 5c cf d8 9f ca 64 a7 39 9e 1a 22 |....k\....d.9.."|
+000000c0 aa fc b5 4c d9 d3 b3 37 e3 d4 e1 3b 5b 00 74 df |...L...7...;[.t.|
+000000d0 df e5 29 8f 7c f7 6b 02 f0 e7 fb 9b 43 6a 41 fb |..).|.k.....CjA.|
+000000e0 77 5b c2 6e 99 48 69 78 |w[.n.Hix|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 9b 02 00 00 97 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 da fd c6 1d |........... ....|
+00000030 46 55 42 89 0a 80 e0 d3 e4 dd db 7d b1 3a 76 a3 |FUB........}.:v.|
+00000040 5b d9 2a c7 f1 1a 3b 0b 8c 24 dd 4d 13 03 00 00 |[.*...;..$.M....|
+00000050 4f 00 2b 00 02 03 04 00 33 00 45 00 17 00 41 04 |O.+.....3.E...A.|
+00000060 1e 18 37 ef 0d 19 51 88 35 75 71 b5 e5 54 5b 12 |..7...Q.5uq..T[.|
+00000070 2e 8f 09 67 fd a7 24 20 3e b2 56 1c ce 97 28 5e |...g..$ >.V...(^|
+00000080 f8 2b 2d 4f 9e f1 07 9f 6c 4b 5b 83 56 e2 32 42 |.+-O....lK[.V.2B|
+00000090 e9 58 b6 d7 49 a6 b5 68 1a 41 03 56 6b dc 5a 89 |.X..I..h.A.Vk.Z.|
+000000a0 14 03 03 00 01 01 17 03 03 00 17 81 b8 e3 25 04 |..............%.|
+000000b0 6c d8 f6 7c 04 a1 2c 8b 1f 0d cb de 29 1b e1 a3 |l..|..,.....)...|
+000000c0 6f 8c 17 03 03 02 6d 81 db bc b4 f8 02 f3 c5 4e |o.....m........N|
+000000d0 9e f7 5f 55 54 3e 25 a9 2f 03 06 62 2f 1e 7e d4 |.._UT>%./..b/.~.|
+000000e0 19 27 88 1e ac f2 44 87 29 84 08 69 2f 5d a3 ca |.'....D.)..i/]..|
+000000f0 de 8f 98 ad 25 6b c5 94 62 34 44 95 bc 17 ed e6 |....%k..b4D.....|
+00000100 fe 89 9c ef 46 c9 cb ee 16 d4 42 b6 d3 50 7b 3a |....F.....B..P{:|
+00000110 51 d8 20 23 02 3e 69 a8 1a 80 eb bf 7c 82 2b 1f |Q. #.>i.....|.+.|
+00000120 10 5a 30 85 dd bc ff 65 4d c6 4f 7b bc 3d 64 e2 |.Z0....eM.O{.=d.|
+00000130 93 2a 05 a0 af de b1 41 48 85 db 98 c9 a9 96 5c |.*.....AH......\|
+00000140 64 a4 70 2e f9 4e de 38 9f 48 f7 eb 6e 14 42 3f |d.p..N.8.H..n.B?|
+00000150 9f 86 0f 2d 70 6a 30 96 1c dd c6 11 28 6f 86 b6 |...-pj0.....(o..|
+00000160 da bb 5b 76 c8 56 18 4a 67 bf 59 db 56 46 f0 c7 |..[v.V.Jg.Y.VF..|
+00000170 80 2b 0f 0c 8a 02 58 a1 13 aa 2e 5d 61 e2 d5 23 |.+....X....]a..#|
+00000180 3c 1c 75 06 e4 e4 e1 39 eb 65 6a ff 38 21 28 c9 |<.u....9.ej.8!(.|
+00000190 c5 8b a5 12 21 18 2a 59 e7 4e 66 53 be d3 49 97 |....!.*Y.NfS..I.|
+000001a0 f9 b1 7d e2 75 44 37 38 36 35 af 78 27 f4 74 e0 |..}.uD7865.x'.t.|
+000001b0 45 ca fd 79 3c 39 65 00 46 58 4b 8b db f9 6e c0 |E..y<9e.FXK...n.|
+000001c0 69 ec 1e 25 87 66 e1 b8 d8 cc 16 5b 16 9e 90 2e |i..%.f.....[....|
+000001d0 16 0c 8f 25 04 cf 40 c8 50 dd c4 63 19 8f f1 76 |...%..@.P..c...v|
+000001e0 5e fa 24 1d 8a d2 c1 d4 98 49 48 f0 e6 fa f3 6e |^.$......IH....n|
+000001f0 63 0b a5 7a 2f f2 f0 47 0b c0 89 9f 7b 9f ef 48 |c..z/..G....{..H|
+00000200 df fd 38 5d a9 71 ce 0c 3c 6f 88 0b 1b d3 93 8c |..8].q..<o......|
+00000210 14 9a ff 8a db 3f 07 f7 46 54 fe c0 8c 06 7f e0 |.....?..FT......|
+00000220 de e9 c8 3c 4b cd 7b c3 59 11 63 01 8e 69 40 00 |...<K.{.Y.c..i@.|
+00000230 d5 e0 4c 01 00 12 89 3a 98 e3 3f e1 a3 69 f6 ee |..L....:..?..i..|
+00000240 e7 94 65 b1 61 58 08 07 4a d5 ab aa 43 3e cf 02 |..e.aX..J...C>..|
+00000250 96 5a 3c 97 8e 7b 47 b8 f0 58 16 12 05 69 69 a1 |.Z<..{G..X...ii.|
+00000260 36 7b ff dd 92 60 26 e2 f9 53 4c 3a 25 ac 88 dd |6{...`&..SL:%...|
+00000270 9a 81 7c 1f 58 27 33 14 68 44 06 e2 01 14 94 99 |..|.X'3.hD......|
+00000280 00 05 8f 64 47 ca 95 fa 92 57 a9 1a 53 d5 47 52 |...dG....W..S.GR|
+00000290 e8 c4 aa eb 0a f5 1b a9 09 72 92 37 f5 8d 90 b8 |.........r.7....|
+000002a0 4b 08 7f 55 19 2d a7 d8 7b d9 ba 7f 5e 56 bb 80 |K..U.-..{...^V..|
+000002b0 c7 d0 49 99 ae ce 2f a4 f0 ab d1 bd ba f3 0f 85 |..I.../.........|
+000002c0 f1 68 c1 9d 2a 37 ff de a4 0a 6f 58 27 1d 1d 2b |.h..*7....oX'..+|
+000002d0 87 9d 52 d3 70 37 a6 03 cd 77 61 9b 56 64 49 62 |..R.p7...wa.VdIb|
+000002e0 ef a1 ed fe 75 1a 61 4a 58 01 d6 80 2f ab ab fc |....u.aJX.../...|
+000002f0 b2 49 1f 51 b7 51 29 c1 a1 39 fc f4 0a 9b 0d 76 |.I.Q.Q)..9.....v|
+00000300 c6 d0 89 c9 8f 88 e9 ec 13 90 78 4f 0c f5 c9 7e |..........xO...~|
+00000310 d5 b3 13 ad 35 6d 53 d0 88 50 e8 47 15 a0 ca fc |....5mS..P.G....|
+00000320 5f 6e 98 23 46 6a 69 84 3c a9 3f eb d1 05 f5 97 |_n.#Fji.<.?.....|
+00000330 11 39 7f 39 17 03 03 00 99 84 8e 37 a9 57 78 12 |.9.9.......7.Wx.|
+00000340 8e 9a e7 8e 45 ee 55 61 66 24 ed 5a 36 19 e3 1c |....E.Uaf$.Z6...|
+00000350 22 3b 8b c0 4b c9 cd 2c 4c 17 d2 a9 40 2c 02 40 |";..K..,L...@,.@|
+00000360 74 ba 11 de a5 d4 01 11 ae 9d 71 76 4c f0 87 0f |t.........qvL...|
+00000370 5e 75 c0 67 c0 33 e7 3e 9b d3 a4 21 e8 40 a6 9f |^u.g.3.>...!.@..|
+00000380 d8 24 a7 d7 c1 99 cc 8d 33 10 91 0a 41 a6 05 1c |.$......3...A...|
+00000390 85 4c c5 a8 c9 dd 74 d0 5c 67 2e 2a 50 4e 30 c7 |.L....t.\g.*PN0.|
+000003a0 bb fa f8 65 ee 48 23 f5 c5 d3 a1 ec 4d 3f ac 4b |...e.H#.....M?.K|
+000003b0 ef 1e 8d 84 07 b9 69 2a 34 51 73 ba fb b5 7d 64 |......i*4Qs...}d|
+000003c0 1f fc 0e c8 33 d9 77 5e 41 00 65 25 ea 75 75 c9 |....3.w^A.e%.uu.|
+000003d0 2b 03 17 03 03 00 35 54 c2 06 55 7c 6f 92 8a d2 |+.....5T..U|o...|
+000003e0 d5 35 0c 4b 0d df cb d7 6e 5d 64 e1 2e cf 50 b8 |.5.K....n]d...P.|
+000003f0 d8 04 9a f4 ce 69 d3 ac bb 47 cd 57 ac 07 aa 40 |.....i...G.W...@|
+00000400 e3 fc 01 bc d6 a1 0e 16 4e 6b 04 cc 17 03 03 00 |........Nk......|
+00000410 93 b2 c3 64 29 13 07 75 b4 c4 84 f7 0e 99 d9 9f |...d)..u........|
+00000420 8d 5b fd 26 07 42 48 33 3a ab 6f 7d 07 8b f6 8a |.[.&.BH3:.o}....|
+00000430 22 a4 ce 64 0f 69 ea 61 95 70 6d d3 f8 5f 8b ad |"..d.i.a.pm.._..|
+00000440 02 43 94 41 51 f4 f8 0b 52 fc 58 c1 23 5e 22 a7 |.C.AQ...R.X.#^".|
+00000450 74 49 a1 46 e8 29 ab d6 ae 02 a4 7b e4 23 f1 89 |tI.F.).....{.#..|
+00000460 1c b1 74 86 92 1b 6a 7c 2f 55 2b 89 f6 01 fc e2 |..t...j|/U+.....|
+00000470 d6 15 b9 b1 64 1c 4a af f8 fe 3e e0 76 0f cf 08 |....d.J...>.v...|
+00000480 e1 2c db f6 1c 77 6f e4 a4 80 ad 13 74 3d 02 52 |.,...wo.....t=.R|
+00000490 a1 ff 3e 85 1d d3 77 bc f2 48 73 1c 45 09 62 34 |..>...w..Hs.E.b4|
+000004a0 80 09 21 41 |..!A|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 ab dd 69 66 c8 |..........5..if.|
+00000010 f9 eb e6 e6 b0 a9 9b 10 1d fc ad 89 ad 4d f5 2b |.............M.+|
+00000020 e4 d7 12 5b 1c 1e 81 12 df 24 ba ea 6b 3e 6f 82 |...[.....$..k>o.|
+00000030 dd 2f 38 a1 65 07 55 6a 4f 8e 99 5d 4f 35 b8 5d |./8.e.UjO..]O5.]|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 1e e5 f4 e6 14 79 8c b9 a9 77 6b c9 |.........y...wk.|
+00000010 ff ad 60 f3 03 cf 48 19 19 71 6c 85 da 92 cb 79 |..`...H..ql....y|
+00000020 2b 20 41 17 03 03 00 13 69 de ca 08 9c cf 70 37 |+ A.....i.....p7|
+00000030 5e fc 32 31 1c 93 d1 e4 01 f3 c6 |^.21.......|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-RSA-RSAPSS b/src/crypto/tls/testdata/Server-TLSv13-RSA-RSAPSS
new file mode 100644
index 0000000..db53ebb
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-RSA-RSAPSS
@@ -0,0 +1,97 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 b2 01 00 00 ae 03 03 4d a5 7b 2c da |...........M.{,.|
+00000010 67 11 9d 4d a0 92 2a 96 6c 85 ef 8c 52 0a 31 cf |g..M..*.l...R.1.|
+00000020 43 23 3e 8d 67 63 9b 7e 84 94 17 20 a2 a1 87 c6 |C#>.gc.~... ....|
+00000030 5e 64 34 75 da ac ee ba d4 d8 8f 2a a6 55 9f 4f |^d4u.......*.U.O|
+00000040 48 38 5a 29 61 a4 ef 7d 1d 74 a7 71 00 04 13 03 |H8Z)a..}.t.q....|
+00000050 00 ff 01 00 00 61 00 0b 00 04 03 00 01 02 00 0a |.....a..........|
+00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 16 |................|
+00000070 00 00 00 17 00 00 00 0d 00 06 00 04 08 06 08 04 |................|
+00000080 00 2b 00 03 02 03 04 00 2d 00 02 01 01 00 33 00 |.+......-.....3.|
+00000090 26 00 24 00 1d 00 20 16 5e 23 ca e7 24 31 81 c2 |&.$... .^#..$1..|
+000000a0 78 21 3a ee 8a f3 61 8a 46 a0 56 ee a9 ed 82 3a |x!:...a.F.V....:|
+000000b0 87 b7 4a 0a 03 fe 59 |..J...Y|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 a2 a1 87 c6 |........... ....|
+00000030 5e 64 34 75 da ac ee ba d4 d8 8f 2a a6 55 9f 4f |^d4u.......*.U.O|
+00000040 48 38 5a 29 61 a4 ef 7d 1d 74 a7 71 13 03 00 00 |H8Z)a..}.t.q....|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 17 f8 7a 9c bc 58 8d |...........z..X.|
+00000090 ce cd ff e6 ae 2d c2 e0 40 33 4e c4 ec f5 90 dd |.....-..@3N.....|
+000000a0 ba 17 03 03 02 6d f3 65 a1 b4 fe ef 40 37 72 fa |.....m.e....@7r.|
+000000b0 a5 b8 10 ad 32 e3 08 e1 ac bb 14 f2 34 bf 25 19 |....2.......4.%.|
+000000c0 aa 2d 1a 78 cc 26 2f 5c 0b 7e 13 73 36 85 92 96 |.-.x.&/\.~.s6...|
+000000d0 0a 7a 27 f5 35 86 f1 ea 1a 5f 5c 3a 90 28 63 6a |.z'.5...._\:.(cj|
+000000e0 b3 7c e0 56 32 10 55 67 59 e0 65 d6 11 ef 7c 50 |.|.V2.UgY.e...|P|
+000000f0 0b 9e 88 0a 61 96 93 cf 05 51 47 33 c3 5c e3 82 |....a....QG3.\..|
+00000100 01 6d f1 f7 5c dc df b2 61 7c d7 9f de b4 3e c0 |.m..\...a|....>.|
+00000110 6d b5 52 39 3b f6 33 c2 03 65 2b 66 39 ed d6 f0 |m.R9;.3..e+f9...|
+00000120 83 46 61 db fc 27 a5 8a 68 d6 8a 85 5d 3f b1 46 |.Fa..'..h...]?.F|
+00000130 a2 3a 32 37 1f e0 76 a6 79 7f eb b2 81 52 e7 e0 |.:27..v.y....R..|
+00000140 4f b2 db 48 7d 20 61 52 d4 22 2a b7 81 2f da 5b |O..H} aR."*../.[|
+00000150 f6 e8 0a a6 91 b5 d1 f5 6b 5e 2b ad fd 70 cd a1 |........k^+..p..|
+00000160 f8 4d 73 31 3d 2a 49 d3 2e 6b b3 31 95 61 09 08 |.Ms1=*I..k.1.a..|
+00000170 c5 f9 eb db 42 b0 e1 5d 47 00 3e 7e 80 31 c6 d2 |....B..]G.>~.1..|
+00000180 37 dc 68 d7 36 05 ad 8a a4 05 87 7a 1c 12 f6 ab |7.h.6......z....|
+00000190 0e e1 5b 29 b1 1c 16 20 29 75 5a b0 59 24 59 df |..[)... )uZ.Y$Y.|
+000001a0 62 fe f2 26 ad ab bf 2b 25 d7 9e db 04 f6 26 96 |b..&...+%.....&.|
+000001b0 f7 5f 2c ff 2e 6d 85 c7 58 c8 15 9c d0 7d dd 8e |._,..m..X....}..|
+000001c0 1a 39 fc 3d 62 58 47 ce 83 7a ff fc 45 98 02 3d |.9.=bXG..z..E..=|
+000001d0 aa 37 b7 5e a7 7b 8e fa f2 05 8b 61 7f 04 08 f5 |.7.^.{.....a....|
+000001e0 af 1d 6e 55 18 d2 12 2e bd 8a 80 3d cb e6 0f cd |..nU.......=....|
+000001f0 3c d8 a5 38 db ee 07 c6 3b 75 55 c2 ee 2e 6a a3 |<..8....;uU...j.|
+00000200 fa 54 ce e3 45 92 c0 b9 8c 10 3d 2f 86 cb a5 c9 |.T..E.....=/....|
+00000210 af 37 f7 f6 6c 3e 4b 15 04 bd 46 98 31 5a b9 8c |.7..l>K...F.1Z..|
+00000220 ec 67 0d 97 9d 26 56 65 9c a7 74 bb 88 45 dc 4e |.g...&Ve..t..E.N|
+00000230 ce 70 a1 fc ce fc a7 d4 e1 7d a7 43 82 a6 e2 30 |.p.......}.C...0|
+00000240 e2 94 88 e5 1a 05 c5 28 06 14 7b 29 75 f9 4d 2c |.......(..{)u.M,|
+00000250 bb 54 ee f5 17 4e 2a bf 04 e6 38 f2 cf ed ab a2 |.T...N*...8.....|
+00000260 ef ae ac 3d 80 5e 03 71 74 70 0c 68 93 ca ea 93 |...=.^.qtp.h....|
+00000270 e5 b1 d1 18 80 98 0e c6 e8 f5 65 87 e7 9a 33 1d |..........e...3.|
+00000280 e6 3d e2 28 82 19 2a 9d 5f 1a a2 74 fa 27 8b d0 |.=.(..*._..t.'..|
+00000290 09 9a ba 1b c5 a6 4c 3b c3 02 12 61 a1 8a 20 d3 |......L;...a.. .|
+000002a0 a4 3c 3b aa f2 08 de e0 de 07 9f a0 13 b4 e8 23 |.<;............#|
+000002b0 d3 a5 ff 12 74 55 29 3a 57 f5 14 b3 af e6 28 ed |....tU):W.....(.|
+000002c0 b1 60 9c 6b 7d 55 a1 58 50 ab 42 71 5d 0e dc 76 |.`.k}U.XP.Bq]..v|
+000002d0 87 cd a1 d3 e4 26 25 c4 c1 23 1e 3b 31 13 3d f8 |.....&%..#.;1.=.|
+000002e0 b2 1b a8 07 f6 68 83 b4 7e 94 ca 84 95 55 38 d1 |.....h..~....U8.|
+000002f0 eb af 19 83 90 4a ab 0a 8d f6 48 9a 25 fa 59 97 |.....J....H.%.Y.|
+00000300 3c 5f 6a 2d 68 ec 29 d5 53 b4 9a 97 ea 59 fe 74 |<_j-h.).S....Y.t|
+00000310 81 0e b9 17 03 03 00 99 12 25 df 91 85 91 ac c0 |.........%......|
+00000320 60 4e 6e ed c4 b2 f0 f3 8b 66 53 75 11 07 29 d6 |`Nn......fSu..).|
+00000330 1f 01 81 60 de 5f b7 6b 5e 39 c8 ea f1 f8 2a 94 |...`._.k^9....*.|
+00000340 dd b6 c5 a9 31 be 87 a7 aa a9 64 03 16 40 df ef |....1.....d..@..|
+00000350 37 ac 66 4c 19 f1 60 d5 b4 88 93 a7 42 ac e3 81 |7.fL..`.....B...|
+00000360 c8 88 3f e2 30 a0 ff b7 d5 19 fc f2 72 a7 97 a8 |..?.0.......r...|
+00000370 31 ce 20 be 90 bc f5 8a 24 31 b1 c6 2b 2a ad c5 |1. .....$1..+*..|
+00000380 7a 34 69 eb a7 86 53 61 a1 88 4f 58 2a 65 a2 18 |z4i...Sa..OX*e..|
+00000390 7a 93 81 c6 bd c7 bc 84 5b ff 85 aa ff fc 68 50 |z.......[.....hP|
+000003a0 cb 57 37 54 a7 0f 2e 64 82 53 b7 dc ea c2 e3 49 |.W7T...d.S.....I|
+000003b0 fd 17 03 03 00 35 da 2a 8c 37 83 a5 a0 d4 06 c4 |.....5.*.7......|
+000003c0 ff f3 85 6f e4 11 1f 37 0f 06 35 45 e9 51 43 6f |...o...7..5E.QCo|
+000003d0 d2 a4 cb b7 ad f0 66 1c 20 40 c3 14 32 c0 57 71 |......f. @..2.Wq|
+000003e0 d3 8c 9c 7f 5b e6 50 a1 c2 e5 62 17 03 03 00 93 |....[.P...b.....|
+000003f0 30 b8 ab dc 3b df 60 aa b1 d2 25 5a 60 da b6 c8 |0...;.`...%Z`...|
+00000400 22 88 93 79 25 44 56 aa ec 93 e8 01 11 bf 69 ad |"..y%DV.......i.|
+00000410 b2 c9 43 67 33 aa 6d ae 73 a3 95 2b f0 86 ed a2 |..Cg3.m.s..+....|
+00000420 db df e3 dc 9b 16 1d 8d fc 2f a5 c4 41 d0 86 2f |........./..A../|
+00000430 cc a1 a1 ce 9a e5 e6 c8 a2 d1 a8 b2 a4 15 9c 69 |...............i|
+00000440 38 5a fa fd de d4 02 95 24 67 1b 61 76 1f c4 65 |8Z......$g.av..e|
+00000450 01 fc 36 2d ef 2d 0f 8e f0 5a 6d 04 07 b8 26 18 |..6-.-...Zm...&.|
+00000460 90 fc 82 1b 99 68 b0 13 7f 6e a1 9b c4 2a f3 b8 |.....h...n...*..|
+00000470 0b 6a 44 cd 04 e8 20 96 6d f5 48 cb 71 8a 04 10 |.jD... .m.H.q...|
+00000480 b8 8d 56 |..V|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 54 e5 3f f8 77 |..........5T.?.w|
+00000010 59 e3 8b 02 0b 80 8d 59 12 22 23 09 cb d9 93 67 |Y......Y."#....g|
+00000020 c7 35 b4 45 a0 54 49 fd 65 b5 ff e6 3e 3c b9 bf |.5.E.TI.e...><..|
+00000030 26 ca df 86 db a4 66 b5 3e 1f 36 69 a5 99 2b ed |&.....f.>.6i..+.|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 1e e3 b4 3e 81 ff 1a 36 f8 11 53 64 |.......>...6..Sd|
+00000010 b9 28 4e 68 de ee 9c b6 4d 71 21 fa 85 56 30 ad |.(Nh....Mq!..V0.|
+00000020 e9 c2 27 17 03 03 00 13 3d b8 13 b0 5f df 5a 05 |..'.....=..._.Z.|
+00000030 85 cf eb 48 86 fb c5 a0 67 f7 ee |...H....g..|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-RSA-RSAPSS-TooSmall b/src/crypto/tls/testdata/Server-TLSv13-RSA-RSAPSS-TooSmall
new file mode 100644
index 0000000..6d27e90
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-RSA-RSAPSS-TooSmall
@@ -0,0 +1,15 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 b0 01 00 00 ac 03 03 15 df ef fb ff |................|
+00000010 00 89 4d bf 59 d2 30 f1 f3 e7 20 24 c6 06 ba a4 |..M.Y.0... $....|
+00000020 28 b4 ba 3d 00 f2 18 9b 98 a3 f2 20 7e d9 d0 58 |(..=....... ~..X|
+00000030 50 25 90 2d f0 af 72 66 fb f8 54 33 6e d4 2b f0 |P%.-..rf..T3n.+.|
+00000040 0f 1a ea dc 9e 08 34 ed 68 a8 d8 bd 00 04 13 03 |......4.h.......|
+00000050 00 ff 01 00 00 5f 00 0b 00 04 03 00 01 02 00 0a |....._..........|
+00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 16 |................|
+00000070 00 00 00 17 00 00 00 0d 00 04 00 02 08 06 00 2b |...............+|
+00000080 00 03 02 03 04 00 2d 00 02 01 01 00 33 00 26 00 |......-.....3.&.|
+00000090 24 00 1d 00 20 6e 42 98 d4 04 32 d1 21 0f 64 c9 |$... nB...2.!.d.|
+000000a0 b7 f2 b2 52 6f 2b b7 b1 95 4b 57 85 7b 69 d9 63 |...Ro+...KW.{i.c|
+000000b0 19 48 d2 1c 1e |.H...|
+>>> Flow 2 (server to client)
+00000000 15 03 03 00 02 02 28 |......(|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-Resume b/src/crypto/tls/testdata/Server-TLSv13-Resume
new file mode 100644
index 0000000..091ffc3
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-Resume
@@ -0,0 +1,60 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 01 6e 01 00 01 6a 03 03 b6 39 89 61 fd |....n...j...9.a.|
+00000010 11 84 b3 4b a9 18 23 b2 35 3d 82 85 75 5c e2 f3 |...K..#.5=..u\..|
+00000020 c9 f4 b0 2f 05 fb 5a 90 da 73 38 20 7f 06 81 e5 |.../..Z..s8 ....|
+00000030 d0 10 08 d1 b0 3c 3c 4b 28 39 34 9a 56 ca 47 4a |.....<<K(94.V.GJ|
+00000040 01 f9 03 2b 54 f1 14 53 bd 28 22 60 00 04 13 01 |...+T..S.("`....|
+00000050 00 ff 01 00 01 1d 00 0b 00 04 03 00 01 02 00 0a |................|
+00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#|
+00000070 00 00 00 16 00 00 00 17 00 00 00 0d 00 1e 00 1c |................|
+00000080 04 03 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b |................|
+00000090 08 04 08 05 08 06 04 01 05 01 06 01 00 2b 00 03 |.............+..|
+000000a0 02 03 04 00 2d 00 02 01 01 00 33 00 26 00 24 00 |....-.....3.&.$.|
+000000b0 1d 00 20 83 a4 df 27 8d 52 a8 ce 3c af 7e 79 0c |.. ...'.R..<.~y.|
+000000c0 b7 30 5e 5f 8d d6 14 1c a1 65 72 40 73 bc 22 44 |.0^_.....er@s."D|
+000000d0 58 05 10 00 29 00 9c 00 77 00 71 50 46 ad c1 db |X...)...w.qPF...|
+000000e0 a8 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 00 |.8.{+....B>.....|
+000000f0 00 00 00 00 00 00 00 00 00 00 00 94 68 2c a3 82 |............h,..|
+00000100 51 ed 14 ef 68 ca 42 c5 5c ab 26 c2 91 a9 01 83 |Q...h.B.\.&.....|
+00000110 13 26 8f 62 7c 89 c0 a2 b5 9b 6d 4f a4 c9 e2 49 |.&.b|.....mO...I|
+00000120 34 03 2c b2 7d d9 af eb 1a 99 76 3c a5 ef 70 78 |4.,.}.....v<..px|
+00000130 59 58 1c 45 80 c5 f1 b8 91 b2 54 71 3f bf 4f 2a |YX.E......Tq?.O*|
+00000140 b2 9d 9d 6f 6f 1c f1 3c 6c e6 a2 73 00 00 00 00 |...oo..<l..s....|
+00000150 00 21 20 95 92 91 9a 6d da d5 c4 94 f7 2e ed 1a |.! ....m........|
+00000160 5b cd 54 55 8f 87 25 ee 58 d6 92 94 a4 e7 c5 e3 |[.TU..%.X.......|
+00000170 58 4f bd |XO.|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 80 02 00 00 7c 03 03 00 00 00 00 00 |........|.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 7f 06 81 e5 |........... ....|
+00000030 d0 10 08 d1 b0 3c 3c 4b 28 39 34 9a 56 ca 47 4a |.....<<K(94.V.GJ|
+00000040 01 f9 03 2b 54 f1 14 53 bd 28 22 60 13 01 00 00 |...+T..S.("`....|
+00000050 34 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |4.+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 00 |.........._X.;t.|
+00000080 29 00 02 00 00 14 03 03 00 01 01 17 03 03 00 17 |)...............|
+00000090 18 d7 0c 38 47 21 c2 8e 01 fe e7 1f 35 ee 7f 8f |...8G!......5...|
+000000a0 04 10 7a 06 61 1f 4d 17 03 03 00 35 b3 38 29 ce |..z.a.M....5.8).|
+000000b0 18 2b 22 5e 01 4d 07 04 87 65 68 85 9d 10 e9 9e |.+"^.M...eh.....|
+000000c0 5a a8 a5 cb 8d f9 48 fe 1b 17 30 04 be 55 92 ce |Z.....H...0..U..|
+000000d0 74 9b 8e 9c 6b 77 5d 09 ca 58 8e c0 ac 85 3b 4e |t...kw]..X....;N|
+000000e0 0b 17 03 03 00 93 90 64 70 a6 d7 20 8e 50 6d b7 |.......dp.. .Pm.|
+000000f0 53 3d ed eb 85 e0 2f fe a2 88 84 3d 26 8a 18 65 |S=..../....=&..e|
+00000100 d1 c0 d2 c4 66 2a 2e 8c 06 5f 46 ee fe 36 f7 00 |....f*..._F..6..|
+00000110 57 3f 95 b3 36 47 0c 1a 78 c4 e3 d6 c1 ae 2f 96 |W?..6G..x...../.|
+00000120 f0 e6 5e 61 86 d7 c1 d7 cc d2 a6 19 0c 29 f5 19 |..^a.........)..|
+00000130 d5 5e 75 6f 8b 49 4b 0b e9 c9 3c 69 87 ab b7 1d |.^uo.IK...<i....|
+00000140 38 84 28 0e 40 79 be 71 dc 61 68 72 c9 a6 83 a4 |8.(.@y.q.ahr....|
+00000150 79 c9 53 4d 43 98 0f e9 33 3c 63 d3 99 e2 97 46 |y.SMC...3<c....F|
+00000160 d1 c1 18 b6 b8 14 ee 19 df 56 94 43 34 b8 af 1f |.........V.C4...|
+00000170 4f f7 c1 e6 d5 17 13 6c bd |O......l.|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 69 08 b0 a0 71 |..........5i...q|
+00000010 1f 95 45 c4 b2 11 43 a9 b5 da ba 11 0a 2b 24 49 |..E...C......+$I|
+00000020 ac 3d 8e ec 32 c9 7f 3e cc 1b fc 9a 68 d0 22 cb |.=..2..>....h.".|
+00000030 37 0e 8f fe 4f 75 1a 62 44 20 60 c2 64 de 48 6d |7...Ou.bD `.d.Hm|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 1e d5 71 aa 53 2d 55 b7 76 11 45 b0 |......q.S-U.v.E.|
+00000010 f3 de f7 f1 78 0b 10 3f 49 7f ea 83 17 2e b9 50 |....x..?I......P|
+00000020 ec d2 0f 17 03 03 00 13 0a 22 58 66 d8 f7 ad fc |........."Xf....|
+00000030 9c f2 da d1 ae 02 f8 99 d2 26 63 |.........&c|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-Resume-HelloRetryRequest b/src/crypto/tls/testdata/Server-TLSv13-Resume-HelloRetryRequest
new file mode 100644
index 0000000..d0aa66a
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-Resume-HelloRetryRequest
@@ -0,0 +1,96 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 01 68 01 00 01 64 03 03 a0 27 b0 af b0 |....h...d...'...|
+00000010 15 2c ed 88 b2 e8 c5 67 2e db 0d 29 13 64 bb 58 |.,.....g...).d.X|
+00000020 3b 71 67 a9 47 65 8a 3c 09 44 29 20 46 fe 89 4b |;qg.Ge.<.D) F..K|
+00000030 f3 1d ed 40 2d 5c 1b 23 26 f5 72 6f d1 b4 77 f5 |...@-\.#&.ro..w.|
+00000040 1a 9f d1 98 34 46 fe 89 0b 2d c1 f9 00 04 13 01 |....4F...-......|
+00000050 00 ff 01 00 01 17 00 0b 00 04 03 00 01 02 00 0a |................|
+00000060 00 06 00 04 00 1d 00 17 00 23 00 00 00 16 00 00 |.........#......|
+00000070 00 17 00 00 00 0d 00 1e 00 1c 04 03 05 03 06 03 |................|
+00000080 08 07 08 08 08 09 08 0a 08 0b 08 04 08 05 08 06 |................|
+00000090 04 01 05 01 06 01 00 2b 00 03 02 03 04 00 2d 00 |.......+......-.|
+000000a0 02 01 01 00 33 00 26 00 24 00 1d 00 20 8c 7b 61 |....3.&.$... .{a|
+000000b0 71 c8 0b 1a 17 14 d9 eb 21 38 e6 2f c0 40 e9 2d |q.......!8./.@.-|
+000000c0 3c 91 c5 4e 9d bb dd af 40 bc 91 38 74 00 29 00 |<..N....@..8t.).|
+000000d0 9c 00 77 00 71 50 46 ad c1 db a8 38 86 7b 2b bb |..w.qPF....8.{+.|
+000000e0 fd d0 c3 42 3e 00 00 00 00 00 00 00 00 00 00 00 |...B>...........|
+000000f0 00 00 00 00 00 94 68 2c a3 82 51 ed 14 ef 68 ca |......h,..Q...h.|
+00000100 42 c5 5c ab 26 c2 91 a9 01 83 13 26 8f 62 7c 89 |B.\.&......&.b|.|
+00000110 c0 a2 b5 9b 6d 4f a4 c9 e2 49 34 03 2c b2 7d d9 |....mO...I4.,.}.|
+00000120 af eb 1a 99 76 3c a5 ef 70 78 59 58 1c 45 80 c5 |....v<..pxYX.E..|
+00000130 f1 b8 91 b2 54 71 3f bf 4f 2a b2 9d 9d 6f 6f 1c |....Tq?.O*...oo.|
+00000140 f1 3c 6c e6 a2 73 00 00 00 00 00 21 20 7b 6e 44 |.<l..s.....! {nD|
+00000150 ea e1 4c 20 9a d4 1c b5 32 0b d4 79 8e c7 50 fb |..L ....2..y..P.|
+00000160 4e 94 6e 02 1c d3 6a 4e 86 cb ae 2c 02 |N.n...jN...,.|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 58 02 00 00 54 03 03 cf 21 ad 74 e5 |....X...T...!.t.|
+00000010 9a 61 11 be 1d 8c 02 1e 65 b8 91 c2 a2 11 16 7a |.a......e......z|
+00000020 bb 8c 5e 07 9e 09 e2 c8 a8 33 9c 20 46 fe 89 4b |..^......3. F..K|
+00000030 f3 1d ed 40 2d 5c 1b 23 26 f5 72 6f d1 b4 77 f5 |...@-\.#&.ro..w.|
+00000040 1a 9f d1 98 34 46 fe 89 0b 2d c1 f9 13 01 00 00 |....4F...-......|
+00000050 0c 00 2b 00 02 03 04 00 33 00 02 00 17 14 03 03 |..+.....3.......|
+00000060 00 01 01 |...|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 16 03 03 01 89 01 00 01 85 03 |................|
+00000010 03 a0 27 b0 af b0 15 2c ed 88 b2 e8 c5 67 2e db |..'....,.....g..|
+00000020 0d 29 13 64 bb 58 3b 71 67 a9 47 65 8a 3c 09 44 |.).d.X;qg.Ge.<.D|
+00000030 29 20 46 fe 89 4b f3 1d ed 40 2d 5c 1b 23 26 f5 |) F..K...@-\.#&.|
+00000040 72 6f d1 b4 77 f5 1a 9f d1 98 34 46 fe 89 0b 2d |ro..w.....4F...-|
+00000050 c1 f9 00 04 13 01 00 ff 01 00 01 38 00 0b 00 04 |...........8....|
+00000060 03 00 01 02 00 0a 00 06 00 04 00 1d 00 17 00 23 |...............#|
+00000070 00 00 00 16 00 00 00 17 00 00 00 0d 00 1e 00 1c |................|
+00000080 04 03 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b |................|
+00000090 08 04 08 05 08 06 04 01 05 01 06 01 00 2b 00 03 |.............+..|
+000000a0 02 03 04 00 2d 00 02 01 01 00 33 00 47 00 45 00 |....-.....3.G.E.|
+000000b0 17 00 41 04 6e 14 0d ac 3f 1a 2a 36 54 4f ec 9d |..A.n...?.*6TO..|
+000000c0 da 5b 93 12 42 eb 58 11 1b 4c 5c 39 a2 32 b8 5b |.[..B.X..L\9.2.[|
+000000d0 41 13 51 05 88 fe 45 d2 01 ef 8d 14 bc 96 de d3 |A.Q...E.........|
+000000e0 1c e3 eb 0c a0 a7 a3 7c 1c b1 9e 38 c2 dc f6 35 |.......|...8...5|
+000000f0 7b 5b 08 2e 00 29 00 9c 00 77 00 71 50 46 ad c1 |{[...)...w.qPF..|
+00000100 db a8 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 |..8.{+....B>....|
+00000110 00 00 00 00 00 00 00 00 00 00 00 00 94 68 2c a3 |.............h,.|
+00000120 82 51 ed 14 ef 68 ca 42 c5 5c ab 26 c2 91 a9 01 |.Q...h.B.\.&....|
+00000130 83 13 26 8f 62 7c 89 c0 a2 b5 9b 6d 4f a4 c9 e2 |..&.b|.....mO...|
+00000140 49 34 03 2c b2 7d d9 af eb 1a 99 76 3c a5 ef 70 |I4.,.}.....v<..p|
+00000150 78 59 58 1c 45 80 c5 f1 b8 91 b2 54 71 3f bf 4f |xYX.E......Tq?.O|
+00000160 2a b2 9d 9d 6f 6f 1c f1 3c 6c e6 a2 73 00 00 00 |*...oo..<l..s...|
+00000170 00 00 21 20 10 ac 47 8c dd 4f 9c ee f3 b2 0a 6b |..! ..G..O.....k|
+00000180 30 56 13 1e a9 53 5b 02 a8 a0 c0 db 1a 44 f7 43 |0V...S[......D.C|
+00000190 af a3 8f b8 |....|
+>>> Flow 4 (server to client)
+00000000 16 03 03 00 a1 02 00 00 9d 03 03 00 00 00 00 00 |................|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 46 fe 89 4b |........... F..K|
+00000030 f3 1d ed 40 2d 5c 1b 23 26 f5 72 6f d1 b4 77 f5 |...@-\.#&.ro..w.|
+00000040 1a 9f d1 98 34 46 fe 89 0b 2d c1 f9 13 01 00 00 |....4F...-......|
+00000050 55 00 2b 00 02 03 04 00 33 00 45 00 17 00 41 04 |U.+.....3.E...A.|
+00000060 1e 18 37 ef 0d 19 51 88 35 75 71 b5 e5 54 5b 12 |..7...Q.5uq..T[.|
+00000070 2e 8f 09 67 fd a7 24 20 3e b2 56 1c ce 97 28 5e |...g..$ >.V...(^|
+00000080 f8 2b 2d 4f 9e f1 07 9f 6c 4b 5b 83 56 e2 32 42 |.+-O....lK[.V.2B|
+00000090 e9 58 b6 d7 49 a6 b5 68 1a 41 03 56 6b dc 5a 89 |.X..I..h.A.Vk.Z.|
+000000a0 00 29 00 02 00 00 17 03 03 00 17 ea 86 30 48 65 |.)...........0He|
+000000b0 cf a6 d4 9d af f7 75 d4 d3 dd af 79 ce 3a 42 5b |......u....y.:B[|
+000000c0 68 7a 17 03 03 00 35 ef d6 22 53 ec 3c 27 84 c7 |hz....5.."S.<'..|
+000000d0 7f b2 81 8e 3e 70 51 25 95 b4 6a 79 01 15 60 c0 |....>pQ%..jy..`.|
+000000e0 39 eb 5b 90 7b 50 f5 3b 50 64 d2 b2 d6 c7 72 cf |9.[.{P.;Pd....r.|
+000000f0 35 f3 25 1c 86 4b 69 ab 6e 50 86 2e 17 03 03 00 |5.%..Ki.nP......|
+00000100 93 66 5a c1 de c6 92 96 95 92 48 90 e7 0f e1 08 |.fZ.......H.....|
+00000110 25 b2 72 a5 7f c5 17 6e 70 5d 6e 68 78 32 72 8d |%.r....np]nhx2r.|
+00000120 3a fa 7a 66 76 26 10 9e f9 92 ca 3b a7 6c 6c fa |:.zfv&.....;.ll.|
+00000130 72 d1 22 f4 b0 b9 2a 90 bd ce 58 e4 ff 1d 88 99 |r."...*...X.....|
+00000140 a4 8d f9 10 af c8 35 cd c4 6f 99 cd 9e 6c 95 b1 |......5..o...l..|
+00000150 b7 6e a4 48 9e 75 f1 d3 c0 b3 27 f1 61 83 ea 13 |.n.H.u....'.a...|
+00000160 06 7f 37 38 f1 31 9e 71 5a 97 15 b5 46 63 44 e8 |..78.1.qZ...FcD.|
+00000170 f4 a1 fc 81 5d f4 c7 65 be 76 da 79 bd fb e4 e6 |....]..e.v.y....|
+00000180 68 de ce f3 32 6b 0c ee 19 18 75 33 77 f2 34 3d |h...2k....u3w.4=|
+00000190 9e c3 da b7 |....|
+>>> Flow 5 (client to server)
+00000000 17 03 03 00 35 59 51 fe aa 0a 69 ef d5 0e ee e3 |....5YQ...i.....|
+00000010 0e 21 f7 e0 80 88 a0 da 23 7a 38 7f 73 e1 da e9 |.!......#z8.s...|
+00000020 7c 02 73 5e f2 64 e5 60 0e c6 d5 9e 7a 45 c2 0b ||.s^.d.`....zE..|
+00000030 6f 08 46 46 5b f1 5b 67 5d 42 |o.FF[.[g]B|
+>>> Flow 6 (server to client)
+00000000 17 03 03 00 1e 3c a5 86 73 ea 62 44 ee 3b 45 a2 |.....<..s.bD.;E.|
+00000010 2a 57 ed 27 0e 65 40 48 23 10 7f ff 27 e5 4e d1 |*W.'.e@H#...'.N.|
+00000020 99 9a e1 17 03 03 00 13 1e 78 1a 08 4b 24 1b fc |.........x..K$..|
+00000030 78 e5 ab fd 8f bf 53 26 f9 b7 c0 |x.....S&...|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-ResumeDisabled b/src/crypto/tls/testdata/Server-TLSv13-ResumeDisabled
new file mode 100644
index 0000000..9f14b60
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-ResumeDisabled
@@ -0,0 +1,99 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 01 6e 01 00 01 6a 03 03 0f 31 f0 17 d6 |....n...j...1...|
+00000010 3e ee f6 b9 14 05 57 cb 41 0b a4 6a 2f 70 9e 69 |>.....W.A..j/p.i|
+00000020 09 2a eb ec 9a f4 47 61 09 43 09 20 d2 5d cf 57 |.*....Ga.C. .].W|
+00000030 b8 81 3c a5 0a 77 50 0a c3 88 79 7a dc d0 2f 8a |..<..wP...yz../.|
+00000040 08 ea 5f 53 54 a6 ff 43 d2 03 55 0e 00 04 13 01 |.._ST..C..U.....|
+00000050 00 ff 01 00 01 1d 00 0b 00 04 03 00 01 02 00 0a |................|
+00000060 00 0c 00 0a 00 1d 00 17 00 1e 00 19 00 18 00 23 |...............#|
+00000070 00 00 00 16 00 00 00 17 00 00 00 0d 00 1e 00 1c |................|
+00000080 04 03 05 03 06 03 08 07 08 08 08 09 08 0a 08 0b |................|
+00000090 08 04 08 05 08 06 04 01 05 01 06 01 00 2b 00 03 |.............+..|
+000000a0 02 03 04 00 2d 00 02 01 01 00 33 00 26 00 24 00 |....-.....3.&.$.|
+000000b0 1d 00 20 b4 ef 07 d4 1b 0e a1 42 ee f1 f3 84 3e |.. .......B....>|
+000000c0 9f fe bb a6 af 59 9d 04 96 03 1b 43 1a b8 f7 7f |.....Y.....C....|
+000000d0 44 64 60 00 29 00 9c 00 77 00 71 50 46 ad c1 db |Dd`.)...w.qPF...|
+000000e0 a8 38 86 7b 2b bb fd d0 c3 42 3e 00 00 00 00 00 |.8.{+....B>.....|
+000000f0 00 00 00 00 00 00 00 00 00 00 00 94 68 2c a3 82 |............h,..|
+00000100 51 ed 14 ef 68 ca 42 c5 5c 90 6b 88 83 a9 b3 63 |Q...h.B.\.k....c|
+00000110 7c 1c 04 ce dd be 5a 26 ef 4e 37 52 ea 9a 45 6b ||.....Z&.N7R..Ek|
+00000120 ea 89 a5 26 7d c3 ea 67 db 99 76 3c e5 52 89 d0 |...&}..g..v<.R..|
+00000130 4b 46 41 2e 62 5c ce a8 2e 9a 67 e9 52 f0 40 d2 |KFA.b\....g.R.@.|
+00000140 f1 0e ab 02 0f 54 c8 0b 5e 91 8f 8b 00 00 00 00 |.....T..^.......|
+00000150 00 21 20 e0 71 35 06 a0 30 9f bf 5a 6e f3 14 fd |.! .q5..0..Zn...|
+00000160 34 0b 6d d5 36 08 82 8f d0 79 cc f3 74 7c a9 a5 |4.m.6....y..t|..|
+00000170 c3 81 27 |..'|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 d2 5d cf 57 |........... .].W|
+00000030 b8 81 3c a5 0a 77 50 0a c3 88 79 7a dc d0 2f 8a |..<..wP...yz../.|
+00000040 08 ea 5f 53 54 a6 ff 43 d2 03 55 0e 13 01 00 00 |.._ST..C..U.....|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 17 df 85 83 6b 9d e0 |.............k..|
+00000090 8d b4 da b1 f2 c7 ff c1 13 33 d4 53 b8 92 bf 83 |.........3.S....|
+000000a0 6c 17 03 03 02 6d 6b 0f f6 15 41 46 aa 92 06 af |l....mk...AF....|
+000000b0 c9 a2 73 c5 31 64 c1 cd 3a e5 e6 9a d9 04 f4 01 |..s.1d..:.......|
+000000c0 d5 0e d6 30 e2 7a 6d 0c 23 d5 4b b1 70 58 c8 ca |...0.zm.#.K.pX..|
+000000d0 5d 1f c9 7c 76 f8 f9 90 b0 f6 05 f6 85 d2 10 b6 |]..|v...........|
+000000e0 bb b1 49 07 8a ba 9b d8 1a f4 48 18 f5 c5 90 f1 |..I.......H.....|
+000000f0 a7 24 cd 3b ab 2f 49 28 fa 3c 64 80 50 a6 38 d9 |.$.;./I(.<d.P.8.|
+00000100 38 15 b1 37 ca 8d 38 58 5b 8d c6 7f 01 98 f1 98 |8..7..8X[.......|
+00000110 3b 33 47 44 b5 47 d3 84 d4 96 bd 48 58 3f 62 86 |;3GD.G.....HX?b.|
+00000120 2a 50 18 8d 64 7c 8d 79 70 3d c1 4f 8a 0a 40 09 |*P..d|.yp=.O..@.|
+00000130 54 7d bf 8a b6 86 12 c8 d8 bd 7a c9 ff 2c 6a b1 |T}........z..,j.|
+00000140 20 a1 c1 90 4b 7a bc 4f 43 b4 f5 bd b6 1d cb de | ...Kz.OC.......|
+00000150 aa e5 b6 13 a5 ee 52 c4 9a d9 46 d6 2e e8 28 97 |......R...F...(.|
+00000160 84 7d 9f 14 dd a9 2b bd 00 f9 3e ff 48 32 e5 9b |.}....+...>.H2..|
+00000170 37 13 08 f2 cc cb bb f5 55 d5 7d 97 5e 6a df 11 |7.......U.}.^j..|
+00000180 33 fd 34 65 99 c2 40 7b a3 7a 04 92 63 ad 19 9d |3.4e..@{.z..c...|
+00000190 02 2a 6f d1 c8 f7 e1 d1 0f a1 c3 5b 81 70 b0 e5 |.*o........[.p..|
+000001a0 97 a4 b2 76 c5 9b 55 f5 da 2d 53 d2 49 4b a7 6a |...v..U..-S.IK.j|
+000001b0 0f 0f c8 d6 a5 00 83 52 fb 12 c6 6b 98 51 a3 4e |.......R...k.Q.N|
+000001c0 86 39 ab 7e 76 1f 31 b5 5e 50 53 1b 21 af 7f a0 |.9.~v.1.^PS.!...|
+000001d0 b9 3c cf 59 19 c7 c8 b6 ef d7 4f e5 ea 5e bc 67 |.<.Y......O..^.g|
+000001e0 00 47 97 50 85 15 54 19 eb de b8 11 0e 39 9a b0 |.G.P..T......9..|
+000001f0 be cd db d9 53 88 9c 78 e8 b9 5e 12 4b 30 63 d5 |....S..x..^.K0c.|
+00000200 eb 48 d1 d4 95 94 58 61 9c 53 ad 97 bd 45 3a 09 |.H....Xa.S...E:.|
+00000210 d0 83 a7 ba 8c 64 87 42 b7 e1 fa 1b 32 58 8b de |.....d.B....2X..|
+00000220 70 34 34 6d fb 0f a0 27 c3 8b 69 61 43 30 24 b2 |p44m...'..iaC0$.|
+00000230 32 4b ca 6c 0b ea f7 4b df e5 5f 3d 06 ea 0d 31 |2K.l...K.._=...1|
+00000240 4a c6 19 44 61 a1 5b 45 ee 9b ea 69 42 8f 35 86 |J..Da.[E...iB.5.|
+00000250 09 c7 83 51 32 e6 7b 45 bb fb 11 1f 4d 3f b8 10 |...Q2.{E....M?..|
+00000260 6a 0c 52 4c fd 20 62 0f 75 26 8a 65 67 e9 7e 56 |j.RL. b.u&.eg.~V|
+00000270 f4 ed 01 67 9e 27 0d 39 98 b4 97 44 50 f6 26 11 |...g.'.9...DP.&.|
+00000280 3c e4 40 17 5c f1 eb 85 1f 13 f9 8d 22 66 2d 2e |<.@.\......."f-.|
+00000290 3b f8 eb 08 7d df f6 ba 7b ec 15 34 04 e2 6d aa |;...}...{..4..m.|
+000002a0 e2 1c 5a e6 e8 4f 00 0c 07 1b dd 6e 07 03 ed 6d |..Z..O.....n...m|
+000002b0 df c0 7d ed 05 84 bb ad 0c 1f df 8b 8d 0a ad 33 |..}............3|
+000002c0 90 38 44 db 8a 32 9f 9d b3 ae 2e 92 d6 ab d3 25 |.8D..2.........%|
+000002d0 12 32 2d 6e a9 17 0d c9 f9 79 25 17 f0 62 1b 91 |.2-n.....y%..b..|
+000002e0 ad d5 2d ec 0d ea cd c4 86 77 04 92 ab a8 8d ea |..-......w......|
+000002f0 ce fc 13 7b a0 ca 32 96 50 49 99 dd 25 d7 73 93 |...{..2.PI..%.s.|
+00000300 f2 00 72 ca 31 07 fd 7e 12 8a 8b 76 51 4e fe 30 |..r.1..~...vQN.0|
+00000310 4d 5c 65 17 03 03 00 99 5b 19 25 c3 5a 4d f0 bd |M\e.....[.%.ZM..|
+00000320 71 0e 48 63 61 bb 55 6b d3 26 81 25 cf ea 45 e6 |q.Hca.Uk.&.%..E.|
+00000330 52 e4 4e c9 5a a8 c2 e2 72 97 51 8a 38 c6 8d 27 |R.N.Z...r.Q.8..'|
+00000340 8d df 09 ce 37 87 a6 41 cb c4 bd 6d 19 ef 56 1a |....7..A...m..V.|
+00000350 e8 79 df ad 76 9e a6 92 e3 da b3 a6 0d 9f 6f 6f |.y..v.........oo|
+00000360 3f 76 0b 62 b4 cf 2c 5b 24 65 bd c1 90 bb 88 ec |?v.b..,[$e......|
+00000370 8b 0c 7d 6b 42 38 26 78 62 5c b0 21 74 95 5f fe |..}kB8&xb\.!t._.|
+00000380 68 7d 31 8c 5f f5 dc a4 f0 23 6b 75 be 70 ea b3 |h}1._....#ku.p..|
+00000390 19 cc 83 9b 8a f6 cb cc 04 2e 66 b5 77 bb 11 68 |..........f.w..h|
+000003a0 56 85 0c b1 b8 b1 4e ed ca bd ea 3c 91 38 8a 63 |V.....N....<.8.c|
+000003b0 f3 17 03 03 00 35 06 2f 99 10 0c 41 cf 70 d2 aa |.....5./...A.p..|
+000003c0 f9 74 e7 3a cb bb 77 1c e6 5c bf f9 3f 02 df af |.t.:..w..\..?...|
+000003d0 ba 08 fa f7 42 60 ad de 65 62 2e 54 5f 35 90 4f |....B`..eb.T_5.O|
+000003e0 9c b1 34 3d 5d f5 6e 04 d8 5a 50 |..4=].n..ZP|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 7e dc fc 3f 66 |..........5~..?f|
+00000010 cb ed 57 e3 5c 83 19 22 31 18 cb eb d5 b8 d2 3c |..W.\.."1......<|
+00000020 6c 10 1f be 5c 04 cf 88 6b ec 04 3d aa 0d 15 68 |l...\...k..=...h|
+00000030 e4 42 bb c9 86 12 ef f7 90 c4 f5 41 39 56 62 d0 |.B.........A9Vb.|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 1e ee b9 1c 7b 56 61 76 91 40 90 11 |........{Vav.@..|
+00000010 61 4a 0c 46 60 e2 c1 a7 dd 0c a1 0d da 65 98 3e |aJ.F`........e.>|
+00000020 30 62 98 17 03 03 00 13 27 7a 29 e5 53 f1 9b 41 |0b......'z).S..A|
+00000030 7a 19 ec cd 29 0e 04 57 90 59 7e |z...)..W.Y~|
diff --git a/src/crypto/tls/testdata/Server-TLSv13-X25519 b/src/crypto/tls/testdata/Server-TLSv13-X25519
new file mode 100644
index 0000000..0160c5a
--- /dev/null
+++ b/src/crypto/tls/testdata/Server-TLSv13-X25519
@@ -0,0 +1,98 @@
+>>> Flow 1 (client to server)
+00000000 16 03 01 00 c2 01 00 00 be 03 03 cb 53 78 a8 58 |............Sx.X|
+00000010 de 5b 75 c2 c5 b3 ac fa c3 6e 85 a7 e5 a3 a4 ca |.[u......n......|
+00000020 1f 82 95 38 fa 79 4c e2 c8 66 8a 20 be 7a 94 d6 |...8.yL..f. .z..|
+00000030 f4 82 e2 2f 3b 2c e4 5f ae c2 8b be d1 2f b6 67 |.../;,._...../.g|
+00000040 9e 78 7a 51 86 1f c1 d9 8f 43 2f 78 00 04 13 03 |.xzQ.....C/x....|
+00000050 00 ff 01 00 00 71 00 0b 00 04 03 00 01 02 00 0a |.....q..........|
+00000060 00 04 00 02 00 1d 00 16 00 00 00 17 00 00 00 0d |................|
+00000070 00 1e 00 1c 04 03 05 03 06 03 08 07 08 08 08 09 |................|
+00000080 08 0a 08 0b 08 04 08 05 08 06 04 01 05 01 06 01 |................|
+00000090 00 2b 00 03 02 03 04 00 2d 00 02 01 01 00 33 00 |.+......-.....3.|
+000000a0 26 00 24 00 1d 00 20 7f 3e a2 2e 2f 88 8a e1 f3 |&.$... .>../....|
+000000b0 6a a4 47 d7 6d b7 3c 02 c4 bb f6 de 41 38 50 74 |j.G.m.<.....A8Pt|
+000000c0 29 21 f5 fe 9f 0b 6f |)!....o|
+>>> Flow 2 (server to client)
+00000000 16 03 03 00 7a 02 00 00 76 03 03 00 00 00 00 00 |....z...v.......|
+00000010 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 |................|
+00000020 00 00 00 00 00 00 00 00 00 00 00 20 be 7a 94 d6 |........... .z..|
+00000030 f4 82 e2 2f 3b 2c e4 5f ae c2 8b be d1 2f b6 67 |.../;,._...../.g|
+00000040 9e 78 7a 51 86 1f c1 d9 8f 43 2f 78 13 03 00 00 |.xzQ.....C/x....|
+00000050 2e 00 2b 00 02 03 04 00 33 00 24 00 1d 00 20 2f |..+.....3.$... /|
+00000060 e5 7d a3 47 cd 62 43 15 28 da ac 5f bb 29 07 30 |.}.G.bC.(.._.).0|
+00000070 ff f6 84 af c4 cf c2 ed 90 99 5f 58 cb 3b 74 14 |.........._X.;t.|
+00000080 03 03 00 01 01 17 03 03 00 17 fb 0e 8b 72 0d 35 |.............r.5|
+00000090 97 db e2 2e b8 20 be 96 27 6b cd ab 6b 24 5b c4 |..... ..'k..k$[.|
+000000a0 e9 17 03 03 02 6d 3a 21 03 ea 45 e9 4e f1 19 1e |.....m:!..E.N...|
+000000b0 33 37 04 5b 3e db 54 f0 27 6f c7 96 78 50 01 46 |37.[>.T.'o..xP.F|
+000000c0 d1 8b 8f 79 70 21 9d 62 97 b9 bf 6d 14 e5 82 f4 |...yp!.b...m....|
+000000d0 ad 89 90 77 12 1f 61 8e 1d 94 d3 27 0f 0e eb 77 |...w..a....'...w|
+000000e0 8d b2 2f fb 58 b4 ee 88 19 91 47 d1 3d 10 9e 4a |../.X.....G.=..J|
+000000f0 1e 41 b9 c6 41 8f 59 11 7f e0 ac e7 b9 d5 be 40 |.A..A.Y........@|
+00000100 cc aa bc ab 56 5a 2b a9 c9 cf df c0 dc 8f d2 9d |....VZ+.........|
+00000110 59 a7 88 36 98 2e 87 c6 1d af 26 a1 e8 08 2d bd |Y..6......&...-.|
+00000120 9b 5b 1c 4e 22 d2 a1 7c 4d 0b 0f af da 5d fe f7 |.[.N"..|M....]..|
+00000130 83 4d f6 54 c1 fe 03 73 6d c9 17 02 6b 78 09 91 |.M.T...sm...kx..|
+00000140 aa 61 9a 93 04 66 fa 6b e8 2e d7 18 d2 4d 6e 25 |.a...f.k.....Mn%|
+00000150 c3 01 2f a5 0e 1b da a1 64 67 e5 a5 c0 5b ef ec |../.....dg...[..|
+00000160 83 5a d3 0e 44 b7 d5 97 9c c7 c4 94 b4 4b 01 e6 |.Z..D........K..|
+00000170 48 28 21 cb 04 10 be b0 3b 53 df 15 47 12 67 ea |H(!.....;S..G.g.|
+00000180 24 65 a1 ce 0b af 05 5b c9 95 bf 28 2e 55 3c 21 |$e.....[...(.U<!|
+00000190 dc 6f 43 54 87 4d 2a b0 4a e8 01 01 e8 cf 07 6a |.oCT.M*.J......j|
+000001a0 09 d0 f7 ae 97 e1 68 78 ff 33 7e 07 e1 77 ee ec |......hx.3~..w..|
+000001b0 b8 1f d5 73 34 06 3f 32 57 e2 a4 52 82 31 86 cc |...s4.?2W..R.1..|
+000001c0 2f 1b 9c 77 78 64 de 01 ac 4c f4 b9 bc 3d 0e f8 |/..wxd...L...=..|
+000001d0 d1 b7 bd 9c 35 05 19 dc 1c 3b 05 c2 c0 66 e7 c3 |....5....;...f..|
+000001e0 68 0e 6d d0 83 92 46 d1 7b 81 9b 87 5b 3f 5b b9 |h.m...F.{...[?[.|
+000001f0 fa cc a5 cc 04 d3 01 54 39 a7 66 50 82 b8 64 a6 |.......T9.fP..d.|
+00000200 06 e3 24 34 62 80 79 28 74 15 1c 8d 91 00 b0 fa |..$4b.y(t.......|
+00000210 af 52 c3 6a fb c8 41 af 77 3d bd 67 d3 e6 2a 76 |.R.j..A.w=.g..*v|
+00000220 ab 63 90 bc 3c 56 31 2d 62 dd 84 98 3f 6a 6b e9 |.c..<V1-b...?jk.|
+00000230 af 2a ed 1a bf da b9 bd 23 f3 b0 5b a3 a3 72 21 |.*......#..[..r!|
+00000240 fb e9 0d 27 58 27 bd 11 60 49 4f f4 6a 38 a4 db |...'X'..`IO.j8..|
+00000250 ff 26 88 d6 1b 50 35 a6 02 d9 e8 c6 05 54 2d 62 |.&...P5......T-b|
+00000260 92 7a 45 86 e5 7d 61 93 05 d6 61 ae af b4 43 cf |.zE..}a...a...C.|
+00000270 21 40 d0 f1 7f 92 48 92 ed d5 bd 33 3c f9 69 0d |!@....H....3<.i.|
+00000280 bf 7c 72 c4 85 e0 c3 42 4d 69 30 d1 5a 2d 11 95 |.|r....BMi0.Z-..|
+00000290 ee 9f 69 9b 99 b9 0c 17 51 15 17 d7 ea fb c8 01 |..i.....Q.......|
+000002a0 22 ac 3e 54 9f 2c 95 9d 3f 98 d3 9c ec d9 ac d8 |".>T.,..?.......|
+000002b0 71 6a d6 0f 53 5e ea 92 53 e3 dd 96 be 38 61 74 |qj..S^..S....8at|
+000002c0 5d 74 ac c4 8c 72 c6 82 dc f4 22 fb 5c 64 0f 33 |]t...r....".\d.3|
+000002d0 b3 31 a1 a9 e0 6d 96 14 0b e1 00 7d 42 44 45 02 |.1...m.....}BDE.|
+000002e0 42 63 a1 15 14 73 b6 e4 18 a7 30 9e e0 df a9 ba |Bc...s....0.....|
+000002f0 44 72 64 ea 06 a4 a1 46 58 07 b1 a8 48 dc ea 73 |Drd....FX...H..s|
+00000300 35 d8 98 de 6c 13 93 bb 7a 64 fb df bf 93 cb 65 |5...l...zd.....e|
+00000310 a4 1a 3a 17 03 03 00 99 41 8d 8b b5 97 ae 6a fb |..:.....A.....j.|
+00000320 28 ae 10 17 a7 a7 bd a2 a2 54 61 33 ea 5c 3d 82 |(........Ta3.\=.|
+00000330 6c 7d fe 3e 3b 6f 92 6b 6a 0a ee fe 85 90 67 59 |l}.>;o.kj.....gY|
+00000340 df d9 fc c0 4a 9a 5b ae 57 29 5d fb ff 74 28 f1 |....J.[.W)]..t(.|
+00000350 27 f4 ab ee f9 e8 04 cf 2b 62 4d a8 6a 4f ac 85 |'.......+bM.jO..|
+00000360 ec a5 18 d7 88 74 9e 3e ea 79 8e 5d df f8 8a 1c |.....t.>.y.]....|
+00000370 10 1b 1d d3 4a cf 2a 56 f2 ca 90 1f 37 2c cc b7 |....J.*V....7,..|
+00000380 31 91 fb d7 7f bb 07 e2 ec 84 8a 6f 08 a1 7e 2e |1..........o..~.|
+00000390 62 8a 5c b9 76 d3 68 e5 d0 b8 73 92 86 80 e5 af |b.\.v.h...s.....|
+000003a0 b4 ef 13 ea 3c 09 2a 3f 7e be 16 72 1c 46 a0 29 |....<.*?~..r.F.)|
+000003b0 0a 17 03 03 00 35 a7 10 63 c4 a1 7f 26 17 ba b7 |.....5..c...&...|
+000003c0 e3 86 6e 52 36 00 8e 68 84 dc 51 8d a6 0c 21 ba |..nR6..h..Q...!.|
+000003d0 c3 d9 84 49 ed 57 78 98 68 be 78 a6 d1 f0 67 ac |...I.Wx.h.x...g.|
+000003e0 65 9e d2 d8 f3 b9 58 27 24 57 83 17 03 03 00 93 |e.....X'$W......|
+000003f0 00 54 de 7f 11 18 1d 12 83 10 77 b2 e9 fd a7 a4 |.T........w.....|
+00000400 46 c4 1c 15 0d 24 e0 94 f8 ff 84 19 45 ad 52 c8 |F....$......E.R.|
+00000410 85 0b c5 4a a7 6d a1 b0 12 cb 13 58 f6 44 a3 e2 |...J.m.....X.D..|
+00000420 b8 7a b5 8c 8f 8a 47 76 ef cb 2d 7b 6e 75 81 39 |.z....Gv..-{nu.9|
+00000430 3e 12 e8 b5 c6 2d cb e0 fd ac af 58 5a 01 70 32 |>....-.....XZ.p2|
+00000440 0e 12 32 95 10 70 94 28 ec 9b 50 e5 78 c4 b7 75 |..2..p.(..P.x..u|
+00000450 97 4a 54 97 bb 30 e6 19 8a 86 87 d7 50 02 8f a8 |.JT..0......P...|
+00000460 1b 97 d6 e7 bf 25 66 9a 5a cd 5c 84 33 42 f1 72 |.....%f.Z.\.3B.r|
+00000470 d2 44 f1 64 e1 3d 38 b7 7a 32 e3 e8 9a 49 19 90 |.D.d.=8.z2...I..|
+00000480 00 2b f6 |.+.|
+>>> Flow 3 (client to server)
+00000000 14 03 03 00 01 01 17 03 03 00 35 9d c7 a1 4d 5f |..........5...M_|
+00000010 7f 3a 04 b0 cf de 09 d5 84 c1 8f 9b 85 a6 a0 53 |.:.............S|
+00000020 c3 aa 19 5e a0 b2 a2 f1 22 f2 51 e0 25 c5 49 57 |...^....".Q.%.IW|
+00000030 52 de ad 75 ec e4 e3 36 84 78 22 c8 6c 80 88 8c |R..u...6.x".l...|
+>>> Flow 4 (server to client)
+00000000 17 03 03 00 1e 3f 0d f6 84 47 21 4e 37 7b df eb |.....?...G!N7{..|
+00000010 eb 38 af a5 ec b9 b6 20 24 f5 1a 1e 25 77 92 82 |.8..... $...%w..|
+00000020 97 88 9f 17 03 03 00 13 e2 80 d8 e1 2a bf d5 e3 |............*...|
+00000030 bc b7 82 2f 50 2c e5 b9 4b 8c d6 |.../P,..K..|
diff --git a/src/crypto/tls/testdata/example-cert.pem b/src/crypto/tls/testdata/example-cert.pem
new file mode 100644
index 0000000..e0bf7db
--- /dev/null
+++ b/src/crypto/tls/testdata/example-cert.pem
@@ -0,0 +1,11 @@
+-----BEGIN CERTIFICATE-----
+MIIBhTCCASugAwIBAgIQIRi6zePL6mKjOipn+dNuaTAKBggqhkjOPQQDAjASMRAw
+DgYDVQQKEwdBY21lIENvMB4XDTE3MTAyMDE5NDMwNloXDTE4MTAyMDE5NDMwNlow
+EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABD0d
+7VNhbWvZLWPuj/RtHFjvtJBEwOkhbN/BnnE8rnZR8+sbwnc/KhCk3FhnpHZnQz7B
+5aETbbIgmuvewdjvSBSjYzBhMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
+BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MCkGA1UdEQQiMCCCDmxvY2FsaG9zdDo1
+NDUzgg4xMjcuMC4wLjE6NTQ1MzAKBggqhkjOPQQDAgNIADBFAiEA2zpJEPQyz6/l
+Wf86aX6PepsntZv2GYlA5UpabfT2EZICICpJ5h/iI+i341gBmLiAFQOyTDT+/wQc
+6MF9+Yw1Yy0t
+-----END CERTIFICATE-----
diff --git a/src/crypto/tls/testdata/example-key.pem b/src/crypto/tls/testdata/example-key.pem
new file mode 100644
index 0000000..104fb09
--- /dev/null
+++ b/src/crypto/tls/testdata/example-key.pem
@@ -0,0 +1,5 @@
+-----BEGIN EC PRIVATE KEY-----
+MHcCAQEEIIrYSSNQFaA2Hwf1duRSxKtLYX5CB04fSeQ6tF1aY/PuoAoGCCqGSM49
+AwEHoUQDQgAEPR3tU2Fta9ktY+6P9G0cWO+0kETA6SFs38GecTyudlHz6xvCdz8q
+EKTcWGekdmdDPsHloRNtsiCa697B2O9IFA==
+-----END EC PRIVATE KEY-----
diff --git a/src/crypto/tls/ticket.go b/src/crypto/tls/ticket.go
new file mode 100644
index 0000000..b82ccd1
--- /dev/null
+++ b/src/crypto/tls/ticket.go
@@ -0,0 +1,185 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "bytes"
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/hmac"
+ "crypto/sha256"
+ "crypto/subtle"
+ "errors"
+ "io"
+
+ "golang.org/x/crypto/cryptobyte"
+)
+
+// sessionState contains the information that is serialized into a session
+// ticket in order to later resume a connection.
+type sessionState struct {
+ vers uint16
+ cipherSuite uint16
+ createdAt uint64
+ masterSecret []byte // opaque master_secret<1..2^16-1>;
+ // struct { opaque certificate<1..2^24-1> } Certificate;
+ certificates [][]byte // Certificate certificate_list<0..2^24-1>;
+
+ // usedOldKey is true if the ticket from which this session came from
+ // was encrypted with an older key and thus should be refreshed.
+ usedOldKey bool
+}
+
+func (m *sessionState) marshal() ([]byte, error) {
+ var b cryptobyte.Builder
+ b.AddUint16(m.vers)
+ b.AddUint16(m.cipherSuite)
+ addUint64(&b, m.createdAt)
+ b.AddUint16LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.masterSecret)
+ })
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ for _, cert := range m.certificates {
+ b.AddUint24LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(cert)
+ })
+ }
+ })
+ return b.Bytes()
+}
+
+func (m *sessionState) unmarshal(data []byte) bool {
+ *m = sessionState{usedOldKey: m.usedOldKey}
+ s := cryptobyte.String(data)
+ if ok := s.ReadUint16(&m.vers) &&
+ s.ReadUint16(&m.cipherSuite) &&
+ readUint64(&s, &m.createdAt) &&
+ readUint16LengthPrefixed(&s, &m.masterSecret) &&
+ len(m.masterSecret) != 0; !ok {
+ return false
+ }
+ var certList cryptobyte.String
+ if !s.ReadUint24LengthPrefixed(&certList) {
+ return false
+ }
+ for !certList.Empty() {
+ var cert []byte
+ if !readUint24LengthPrefixed(&certList, &cert) {
+ return false
+ }
+ m.certificates = append(m.certificates, cert)
+ }
+ return s.Empty()
+}
+
+// sessionStateTLS13 is the content of a TLS 1.3 session ticket. Its first
+// version (revision = 0) doesn't carry any of the information needed for 0-RTT
+// validation and the nonce is always empty.
+type sessionStateTLS13 struct {
+ // uint8 version = 0x0304;
+ // uint8 revision = 0;
+ cipherSuite uint16
+ createdAt uint64
+ resumptionSecret []byte // opaque resumption_master_secret<1..2^8-1>;
+ certificate Certificate // CertificateEntry certificate_list<0..2^24-1>;
+}
+
+func (m *sessionStateTLS13) marshal() ([]byte, error) {
+ var b cryptobyte.Builder
+ b.AddUint16(VersionTLS13)
+ b.AddUint8(0) // revision
+ b.AddUint16(m.cipherSuite)
+ addUint64(&b, m.createdAt)
+ b.AddUint8LengthPrefixed(func(b *cryptobyte.Builder) {
+ b.AddBytes(m.resumptionSecret)
+ })
+ marshalCertificate(&b, m.certificate)
+ return b.Bytes()
+}
+
+func (m *sessionStateTLS13) unmarshal(data []byte) bool {
+ *m = sessionStateTLS13{}
+ s := cryptobyte.String(data)
+ var version uint16
+ var revision uint8
+ return s.ReadUint16(&version) &&
+ version == VersionTLS13 &&
+ s.ReadUint8(&revision) &&
+ revision == 0 &&
+ s.ReadUint16(&m.cipherSuite) &&
+ readUint64(&s, &m.createdAt) &&
+ readUint8LengthPrefixed(&s, &m.resumptionSecret) &&
+ len(m.resumptionSecret) != 0 &&
+ unmarshalCertificate(&s, &m.certificate) &&
+ s.Empty()
+}
+
+func (c *Conn) encryptTicket(state []byte) ([]byte, error) {
+ if len(c.ticketKeys) == 0 {
+ return nil, errors.New("tls: internal error: session ticket keys unavailable")
+ }
+
+ encrypted := make([]byte, ticketKeyNameLen+aes.BlockSize+len(state)+sha256.Size)
+ keyName := encrypted[:ticketKeyNameLen]
+ iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
+ macBytes := encrypted[len(encrypted)-sha256.Size:]
+
+ if _, err := io.ReadFull(c.config.rand(), iv); err != nil {
+ return nil, err
+ }
+ key := c.ticketKeys[0]
+ copy(keyName, key.keyName[:])
+ block, err := aes.NewCipher(key.aesKey[:])
+ if err != nil {
+ return nil, errors.New("tls: failed to create cipher while encrypting ticket: " + err.Error())
+ }
+ cipher.NewCTR(block, iv).XORKeyStream(encrypted[ticketKeyNameLen+aes.BlockSize:], state)
+
+ mac := hmac.New(sha256.New, key.hmacKey[:])
+ mac.Write(encrypted[:len(encrypted)-sha256.Size])
+ mac.Sum(macBytes[:0])
+
+ return encrypted, nil
+}
+
+func (c *Conn) decryptTicket(encrypted []byte) (plaintext []byte, usedOldKey bool) {
+ if len(encrypted) < ticketKeyNameLen+aes.BlockSize+sha256.Size {
+ return nil, false
+ }
+
+ keyName := encrypted[:ticketKeyNameLen]
+ iv := encrypted[ticketKeyNameLen : ticketKeyNameLen+aes.BlockSize]
+ macBytes := encrypted[len(encrypted)-sha256.Size:]
+ ciphertext := encrypted[ticketKeyNameLen+aes.BlockSize : len(encrypted)-sha256.Size]
+
+ keyIndex := -1
+ for i, candidateKey := range c.ticketKeys {
+ if bytes.Equal(keyName, candidateKey.keyName[:]) {
+ keyIndex = i
+ break
+ }
+ }
+ if keyIndex == -1 {
+ return nil, false
+ }
+ key := &c.ticketKeys[keyIndex]
+
+ mac := hmac.New(sha256.New, key.hmacKey[:])
+ mac.Write(encrypted[:len(encrypted)-sha256.Size])
+ expected := mac.Sum(nil)
+
+ if subtle.ConstantTimeCompare(macBytes, expected) != 1 {
+ return nil, false
+ }
+
+ block, err := aes.NewCipher(key.aesKey[:])
+ if err != nil {
+ return nil, false
+ }
+ plaintext = make([]byte, len(ciphertext))
+ cipher.NewCTR(block, iv).XORKeyStream(plaintext, ciphertext)
+
+ return plaintext, keyIndex > 0
+}
diff --git a/src/crypto/tls/tls.go b/src/crypto/tls/tls.go
new file mode 100644
index 0000000..b529c70
--- /dev/null
+++ b/src/crypto/tls/tls.go
@@ -0,0 +1,356 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package tls partially implements TLS 1.2, as specified in RFC 5246,
+// and TLS 1.3, as specified in RFC 8446.
+package tls
+
+// BUG(agl): The crypto/tls package only implements some countermeasures
+// against Lucky13 attacks on CBC-mode encryption, and only on SHA1
+// variants. See http://www.isg.rhul.ac.uk/tls/TLStiming.pdf and
+// https://www.imperialviolet.org/2013/02/04/luckythirteen.html.
+
+import (
+ "bytes"
+ "context"
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/pem"
+ "errors"
+ "fmt"
+ "net"
+ "os"
+ "strings"
+)
+
+// Server returns a new TLS server side connection
+// using conn as the underlying transport.
+// The configuration config must be non-nil and must include
+// at least one certificate or else set GetCertificate.
+func Server(conn net.Conn, config *Config) *Conn {
+ c := &Conn{
+ conn: conn,
+ config: config,
+ }
+ c.handshakeFn = c.serverHandshake
+ return c
+}
+
+// Client returns a new TLS client side connection
+// using conn as the underlying transport.
+// The config cannot be nil: users must set either ServerName or
+// InsecureSkipVerify in the config.
+func Client(conn net.Conn, config *Config) *Conn {
+ c := &Conn{
+ conn: conn,
+ config: config,
+ isClient: true,
+ }
+ c.handshakeFn = c.clientHandshake
+ return c
+}
+
+// A listener implements a network listener (net.Listener) for TLS connections.
+type listener struct {
+ net.Listener
+ config *Config
+}
+
+// Accept waits for and returns the next incoming TLS connection.
+// The returned connection is of type *Conn.
+func (l *listener) Accept() (net.Conn, error) {
+ c, err := l.Listener.Accept()
+ if err != nil {
+ return nil, err
+ }
+ return Server(c, l.config), nil
+}
+
+// NewListener creates a Listener which accepts connections from an inner
+// Listener and wraps each connection with Server.
+// The configuration config must be non-nil and must include
+// at least one certificate or else set GetCertificate.
+func NewListener(inner net.Listener, config *Config) net.Listener {
+ l := new(listener)
+ l.Listener = inner
+ l.config = config
+ return l
+}
+
+// Listen creates a TLS listener accepting connections on the
+// given network address using net.Listen.
+// The configuration config must be non-nil and must include
+// at least one certificate or else set GetCertificate.
+func Listen(network, laddr string, config *Config) (net.Listener, error) {
+ if config == nil || len(config.Certificates) == 0 &&
+ config.GetCertificate == nil && config.GetConfigForClient == nil {
+ return nil, errors.New("tls: neither Certificates, GetCertificate, nor GetConfigForClient set in Config")
+ }
+ l, err := net.Listen(network, laddr)
+ if err != nil {
+ return nil, err
+ }
+ return NewListener(l, config), nil
+}
+
+type timeoutError struct{}
+
+func (timeoutError) Error() string { return "tls: DialWithDialer timed out" }
+func (timeoutError) Timeout() bool { return true }
+func (timeoutError) Temporary() bool { return true }
+
+// DialWithDialer connects to the given network address using dialer.Dial and
+// then initiates a TLS handshake, returning the resulting TLS connection. Any
+// timeout or deadline given in the dialer apply to connection and TLS
+// handshake as a whole.
+//
+// DialWithDialer interprets a nil configuration as equivalent to the zero
+// configuration; see the documentation of Config for the defaults.
+//
+// DialWithDialer uses context.Background internally; to specify the context,
+// use Dialer.DialContext with NetDialer set to the desired dialer.
+func DialWithDialer(dialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
+ return dial(context.Background(), dialer, network, addr, config)
+}
+
+func dial(ctx context.Context, netDialer *net.Dialer, network, addr string, config *Config) (*Conn, error) {
+ if netDialer.Timeout != 0 {
+ var cancel context.CancelFunc
+ ctx, cancel = context.WithTimeout(ctx, netDialer.Timeout)
+ defer cancel()
+ }
+
+ if !netDialer.Deadline.IsZero() {
+ var cancel context.CancelFunc
+ ctx, cancel = context.WithDeadline(ctx, netDialer.Deadline)
+ defer cancel()
+ }
+
+ rawConn, err := netDialer.DialContext(ctx, network, addr)
+ if err != nil {
+ return nil, err
+ }
+
+ colonPos := strings.LastIndex(addr, ":")
+ if colonPos == -1 {
+ colonPos = len(addr)
+ }
+ hostname := addr[:colonPos]
+
+ if config == nil {
+ config = defaultConfig()
+ }
+ // If no ServerName is set, infer the ServerName
+ // from the hostname we're connecting to.
+ if config.ServerName == "" {
+ // Make a copy to avoid polluting argument or default.
+ c := config.Clone()
+ c.ServerName = hostname
+ config = c
+ }
+
+ conn := Client(rawConn, config)
+ if err := conn.HandshakeContext(ctx); err != nil {
+ rawConn.Close()
+ return nil, err
+ }
+ return conn, nil
+}
+
+// Dial connects to the given network address using net.Dial
+// and then initiates a TLS handshake, returning the resulting
+// TLS connection.
+// Dial interprets a nil configuration as equivalent to
+// the zero configuration; see the documentation of Config
+// for the defaults.
+func Dial(network, addr string, config *Config) (*Conn, error) {
+ return DialWithDialer(new(net.Dialer), network, addr, config)
+}
+
+// Dialer dials TLS connections given a configuration and a Dialer for the
+// underlying connection.
+type Dialer struct {
+ // NetDialer is the optional dialer to use for the TLS connections'
+ // underlying TCP connections.
+ // A nil NetDialer is equivalent to the net.Dialer zero value.
+ NetDialer *net.Dialer
+
+ // Config is the TLS configuration to use for new connections.
+ // A nil configuration is equivalent to the zero
+ // configuration; see the documentation of Config for the
+ // defaults.
+ Config *Config
+}
+
+// Dial connects to the given network address and initiates a TLS
+// handshake, returning the resulting TLS connection.
+//
+// The returned Conn, if any, will always be of type *Conn.
+//
+// Dial uses context.Background internally; to specify the context,
+// use DialContext.
+func (d *Dialer) Dial(network, addr string) (net.Conn, error) {
+ return d.DialContext(context.Background(), network, addr)
+}
+
+func (d *Dialer) netDialer() *net.Dialer {
+ if d.NetDialer != nil {
+ return d.NetDialer
+ }
+ return new(net.Dialer)
+}
+
+// DialContext connects to the given network address and initiates a TLS
+// handshake, returning the resulting TLS connection.
+//
+// The provided Context must be non-nil. If the context expires before
+// the connection is complete, an error is returned. Once successfully
+// connected, any expiration of the context will not affect the
+// connection.
+//
+// The returned Conn, if any, will always be of type *Conn.
+func (d *Dialer) DialContext(ctx context.Context, network, addr string) (net.Conn, error) {
+ c, err := dial(ctx, d.netDialer(), network, addr, d.Config)
+ if err != nil {
+ // Don't return c (a typed nil) in an interface.
+ return nil, err
+ }
+ return c, nil
+}
+
+// LoadX509KeyPair reads and parses a public/private key pair from a pair
+// of files. The files must contain PEM encoded data. The certificate file
+// may contain intermediate certificates following the leaf certificate to
+// form a certificate chain. On successful return, Certificate.Leaf will
+// be nil because the parsed form of the certificate is not retained.
+func LoadX509KeyPair(certFile, keyFile string) (Certificate, error) {
+ certPEMBlock, err := os.ReadFile(certFile)
+ if err != nil {
+ return Certificate{}, err
+ }
+ keyPEMBlock, err := os.ReadFile(keyFile)
+ if err != nil {
+ return Certificate{}, err
+ }
+ return X509KeyPair(certPEMBlock, keyPEMBlock)
+}
+
+// X509KeyPair parses a public/private key pair from a pair of
+// PEM encoded data. On successful return, Certificate.Leaf will be nil because
+// the parsed form of the certificate is not retained.
+func X509KeyPair(certPEMBlock, keyPEMBlock []byte) (Certificate, error) {
+ fail := func(err error) (Certificate, error) { return Certificate{}, err }
+
+ var cert Certificate
+ var skippedBlockTypes []string
+ for {
+ var certDERBlock *pem.Block
+ certDERBlock, certPEMBlock = pem.Decode(certPEMBlock)
+ if certDERBlock == nil {
+ break
+ }
+ if certDERBlock.Type == "CERTIFICATE" {
+ cert.Certificate = append(cert.Certificate, certDERBlock.Bytes)
+ } else {
+ skippedBlockTypes = append(skippedBlockTypes, certDERBlock.Type)
+ }
+ }
+
+ if len(cert.Certificate) == 0 {
+ if len(skippedBlockTypes) == 0 {
+ return fail(errors.New("tls: failed to find any PEM data in certificate input"))
+ }
+ if len(skippedBlockTypes) == 1 && strings.HasSuffix(skippedBlockTypes[0], "PRIVATE KEY") {
+ return fail(errors.New("tls: failed to find certificate PEM data in certificate input, but did find a private key; PEM inputs may have been switched"))
+ }
+ return fail(fmt.Errorf("tls: failed to find \"CERTIFICATE\" PEM block in certificate input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
+ }
+
+ skippedBlockTypes = skippedBlockTypes[:0]
+ var keyDERBlock *pem.Block
+ for {
+ keyDERBlock, keyPEMBlock = pem.Decode(keyPEMBlock)
+ if keyDERBlock == nil {
+ if len(skippedBlockTypes) == 0 {
+ return fail(errors.New("tls: failed to find any PEM data in key input"))
+ }
+ if len(skippedBlockTypes) == 1 && skippedBlockTypes[0] == "CERTIFICATE" {
+ return fail(errors.New("tls: found a certificate rather than a key in the PEM for the private key"))
+ }
+ return fail(fmt.Errorf("tls: failed to find PEM block with type ending in \"PRIVATE KEY\" in key input after skipping PEM blocks of the following types: %v", skippedBlockTypes))
+ }
+ if keyDERBlock.Type == "PRIVATE KEY" || strings.HasSuffix(keyDERBlock.Type, " PRIVATE KEY") {
+ break
+ }
+ skippedBlockTypes = append(skippedBlockTypes, keyDERBlock.Type)
+ }
+
+ // We don't need to parse the public key for TLS, but we so do anyway
+ // to check that it looks sane and matches the private key.
+ x509Cert, err := x509.ParseCertificate(cert.Certificate[0])
+ if err != nil {
+ return fail(err)
+ }
+
+ cert.PrivateKey, err = parsePrivateKey(keyDERBlock.Bytes)
+ if err != nil {
+ return fail(err)
+ }
+
+ switch pub := x509Cert.PublicKey.(type) {
+ case *rsa.PublicKey:
+ priv, ok := cert.PrivateKey.(*rsa.PrivateKey)
+ if !ok {
+ return fail(errors.New("tls: private key type does not match public key type"))
+ }
+ if pub.N.Cmp(priv.N) != 0 {
+ return fail(errors.New("tls: private key does not match public key"))
+ }
+ case *ecdsa.PublicKey:
+ priv, ok := cert.PrivateKey.(*ecdsa.PrivateKey)
+ if !ok {
+ return fail(errors.New("tls: private key type does not match public key type"))
+ }
+ if pub.X.Cmp(priv.X) != 0 || pub.Y.Cmp(priv.Y) != 0 {
+ return fail(errors.New("tls: private key does not match public key"))
+ }
+ case ed25519.PublicKey:
+ priv, ok := cert.PrivateKey.(ed25519.PrivateKey)
+ if !ok {
+ return fail(errors.New("tls: private key type does not match public key type"))
+ }
+ if !bytes.Equal(priv.Public().(ed25519.PublicKey), pub) {
+ return fail(errors.New("tls: private key does not match public key"))
+ }
+ default:
+ return fail(errors.New("tls: unknown public key algorithm"))
+ }
+
+ return cert, nil
+}
+
+// Attempt to parse the given private key DER block. OpenSSL 0.9.8 generates
+// PKCS #1 private keys by default, while OpenSSL 1.0.0 generates PKCS #8 keys.
+// OpenSSL ecparam generates SEC1 EC private keys for ECDSA. We try all three.
+func parsePrivateKey(der []byte) (crypto.PrivateKey, error) {
+ if key, err := x509.ParsePKCS1PrivateKey(der); err == nil {
+ return key, nil
+ }
+ if key, err := x509.ParsePKCS8PrivateKey(der); err == nil {
+ switch key := key.(type) {
+ case *rsa.PrivateKey, *ecdsa.PrivateKey, ed25519.PrivateKey:
+ return key, nil
+ default:
+ return nil, errors.New("tls: found unknown private key type in PKCS#8 wrapping")
+ }
+ }
+ if key, err := x509.ParseECPrivateKey(der); err == nil {
+ return key, nil
+ }
+
+ return nil, errors.New("tls: failed to parse private key")
+}
diff --git a/src/crypto/tls/tls_test.go b/src/crypto/tls/tls_test.go
new file mode 100644
index 0000000..d8a43ad
--- /dev/null
+++ b/src/crypto/tls/tls_test.go
@@ -0,0 +1,1611 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package tls
+
+import (
+ "bytes"
+ "context"
+ "crypto"
+ "crypto/x509"
+ "encoding/json"
+ "errors"
+ "fmt"
+ "internal/testenv"
+ "io"
+ "math"
+ "net"
+ "os"
+ "reflect"
+ "sort"
+ "strings"
+ "testing"
+ "time"
+)
+
+var rsaCertPEM = `-----BEGIN CERTIFICATE-----
+MIIB0zCCAX2gAwIBAgIJAI/M7BYjwB+uMA0GCSqGSIb3DQEBBQUAMEUxCzAJBgNV
+BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
+aWRnaXRzIFB0eSBMdGQwHhcNMTIwOTEyMjE1MjAyWhcNMTUwOTEyMjE1MjAyWjBF
+MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
+ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMFwwDQYJKoZIhvcNAQEBBQADSwAwSAJBANLJ
+hPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wok/4xIA+ui35/MmNa
+rtNuC+BdZ1tMuVCPFZcCAwEAAaNQME4wHQYDVR0OBBYEFJvKs8RfJaXTH08W+SGv
+zQyKn0H8MB8GA1UdIwQYMBaAFJvKs8RfJaXTH08W+SGvzQyKn0H8MAwGA1UdEwQF
+MAMBAf8wDQYJKoZIhvcNAQEFBQADQQBJlffJHybjDGxRMqaRmDhX0+6v02TUKZsW
+r5QuVbpQhH6u+0UgcW0jp9QwpxoPTLTWGXEWBBBurxFwiCBhkQ+V
+-----END CERTIFICATE-----
+`
+
+var rsaKeyPEM = testingKey(`-----BEGIN RSA TESTING KEY-----
+MIIBOwIBAAJBANLJhPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wo
+k/4xIA+ui35/MmNartNuC+BdZ1tMuVCPFZcCAwEAAQJAEJ2N+zsR0Xn8/Q6twa4G
+6OB1M1WO+k+ztnX/1SvNeWu8D6GImtupLTYgjZcHufykj09jiHmjHx8u8ZZB/o1N
+MQIhAPW+eyZo7ay3lMz1V01WVjNKK9QSn1MJlb06h/LuYv9FAiEA25WPedKgVyCW
+SmUwbPw8fnTcpqDWE3yTO3vKcebqMSsCIBF3UmVue8YU3jybC3NxuXq3wNm34R8T
+xVLHwDXh/6NJAiEAl2oHGGLz64BuAfjKrqwz7qMYr9HCLIe/YsoWq/olzScCIQDi
+D2lWusoe2/nEqfDVVWGWlyJ7yOmqaVm/iNUN9B2N2g==
+-----END RSA TESTING KEY-----
+`)
+
+// keyPEM is the same as rsaKeyPEM, but declares itself as just
+// "PRIVATE KEY", not "RSA PRIVATE KEY". https://golang.org/issue/4477
+var keyPEM = testingKey(`-----BEGIN TESTING KEY-----
+MIIBOwIBAAJBANLJhPHhITqQbPklG3ibCVxwGMRfp/v4XqhfdQHdcVfHap6NQ5Wo
+k/4xIA+ui35/MmNartNuC+BdZ1tMuVCPFZcCAwEAAQJAEJ2N+zsR0Xn8/Q6twa4G
+6OB1M1WO+k+ztnX/1SvNeWu8D6GImtupLTYgjZcHufykj09jiHmjHx8u8ZZB/o1N
+MQIhAPW+eyZo7ay3lMz1V01WVjNKK9QSn1MJlb06h/LuYv9FAiEA25WPedKgVyCW
+SmUwbPw8fnTcpqDWE3yTO3vKcebqMSsCIBF3UmVue8YU3jybC3NxuXq3wNm34R8T
+xVLHwDXh/6NJAiEAl2oHGGLz64BuAfjKrqwz7qMYr9HCLIe/YsoWq/olzScCIQDi
+D2lWusoe2/nEqfDVVWGWlyJ7yOmqaVm/iNUN9B2N2g==
+-----END TESTING KEY-----
+`)
+
+var ecdsaCertPEM = `-----BEGIN CERTIFICATE-----
+MIIB/jCCAWICCQDscdUxw16XFDAJBgcqhkjOPQQBMEUxCzAJBgNVBAYTAkFVMRMw
+EQYDVQQIEwpTb21lLVN0YXRlMSEwHwYDVQQKExhJbnRlcm5ldCBXaWRnaXRzIFB0
+eSBMdGQwHhcNMTIxMTE0MTI0MDQ4WhcNMTUxMTE0MTI0MDQ4WjBFMQswCQYDVQQG
+EwJBVTETMBEGA1UECBMKU29tZS1TdGF0ZTEhMB8GA1UEChMYSW50ZXJuZXQgV2lk
+Z2l0cyBQdHkgTHRkMIGbMBAGByqGSM49AgEGBSuBBAAjA4GGAAQBY9+my9OoeSUR
+lDQdV/x8LsOuLilthhiS1Tz4aGDHIPwC1mlvnf7fg5lecYpMCrLLhauAc1UJXcgl
+01xoLuzgtAEAgv2P/jgytzRSpUYvgLBt1UA0leLYBy6mQQbrNEuqT3INapKIcUv8
+XxYP0xMEUksLPq6Ca+CRSqTtrd/23uTnapkwCQYHKoZIzj0EAQOBigAwgYYCQXJo
+A7Sl2nLVf+4Iu/tAX/IF4MavARKC4PPHK3zfuGfPR3oCCcsAoz3kAzOeijvd0iXb
+H5jBImIxPL4WxQNiBTexAkF8D1EtpYuWdlVQ80/h/f4pBcGiXPqX5h2PQSQY7hP1
++jwM1FGS4fREIOvlBYr/SzzQRtwrvrzGYxDEDbsC0ZGRnA==
+-----END CERTIFICATE-----
+`
+
+var ecdsaKeyPEM = testingKey(`-----BEGIN EC PARAMETERS-----
+BgUrgQQAIw==
+-----END EC PARAMETERS-----
+-----BEGIN EC TESTING KEY-----
+MIHcAgEBBEIBrsoKp0oqcv6/JovJJDoDVSGWdirrkgCWxrprGlzB9o0X8fV675X0
+NwuBenXFfeZvVcwluO7/Q9wkYoPd/t3jGImgBwYFK4EEACOhgYkDgYYABAFj36bL
+06h5JRGUNB1X/Hwuw64uKW2GGJLVPPhoYMcg/ALWaW+d/t+DmV5xikwKssuFq4Bz
+VQldyCXTXGgu7OC0AQCC/Y/+ODK3NFKlRi+AsG3VQDSV4tgHLqZBBus0S6pPcg1q
+kohxS/xfFg/TEwRSSws+roJr4JFKpO2t3/be5OdqmQ==
+-----END EC TESTING KEY-----
+`)
+
+var keyPairTests = []struct {
+ algo string
+ cert string
+ key string
+}{
+ {"ECDSA", ecdsaCertPEM, ecdsaKeyPEM},
+ {"RSA", rsaCertPEM, rsaKeyPEM},
+ {"RSA-untyped", rsaCertPEM, keyPEM}, // golang.org/issue/4477
+}
+
+func TestX509KeyPair(t *testing.T) {
+ t.Parallel()
+ var pem []byte
+ for _, test := range keyPairTests {
+ pem = []byte(test.cert + test.key)
+ if _, err := X509KeyPair(pem, pem); err != nil {
+ t.Errorf("Failed to load %s cert followed by %s key: %s", test.algo, test.algo, err)
+ }
+ pem = []byte(test.key + test.cert)
+ if _, err := X509KeyPair(pem, pem); err != nil {
+ t.Errorf("Failed to load %s key followed by %s cert: %s", test.algo, test.algo, err)
+ }
+ }
+}
+
+func TestX509KeyPairErrors(t *testing.T) {
+ _, err := X509KeyPair([]byte(rsaKeyPEM), []byte(rsaCertPEM))
+ if err == nil {
+ t.Fatalf("X509KeyPair didn't return an error when arguments were switched")
+ }
+ if subStr := "been switched"; !strings.Contains(err.Error(), subStr) {
+ t.Fatalf("Expected %q in the error when switching arguments to X509KeyPair, but the error was %q", subStr, err)
+ }
+
+ _, err = X509KeyPair([]byte(rsaCertPEM), []byte(rsaCertPEM))
+ if err == nil {
+ t.Fatalf("X509KeyPair didn't return an error when both arguments were certificates")
+ }
+ if subStr := "certificate"; !strings.Contains(err.Error(), subStr) {
+ t.Fatalf("Expected %q in the error when both arguments to X509KeyPair were certificates, but the error was %q", subStr, err)
+ }
+
+ const nonsensePEM = `
+-----BEGIN NONSENSE-----
+Zm9vZm9vZm9v
+-----END NONSENSE-----
+`
+
+ _, err = X509KeyPair([]byte(nonsensePEM), []byte(nonsensePEM))
+ if err == nil {
+ t.Fatalf("X509KeyPair didn't return an error when both arguments were nonsense")
+ }
+ if subStr := "NONSENSE"; !strings.Contains(err.Error(), subStr) {
+ t.Fatalf("Expected %q in the error when both arguments to X509KeyPair were nonsense, but the error was %q", subStr, err)
+ }
+}
+
+func TestX509MixedKeyPair(t *testing.T) {
+ if _, err := X509KeyPair([]byte(rsaCertPEM), []byte(ecdsaKeyPEM)); err == nil {
+ t.Error("Load of RSA certificate succeeded with ECDSA private key")
+ }
+ if _, err := X509KeyPair([]byte(ecdsaCertPEM), []byte(rsaKeyPEM)); err == nil {
+ t.Error("Load of ECDSA certificate succeeded with RSA private key")
+ }
+}
+
+func newLocalListener(t testing.TB) net.Listener {
+ ln, err := net.Listen("tcp", "127.0.0.1:0")
+ if err != nil {
+ ln, err = net.Listen("tcp6", "[::1]:0")
+ }
+ if err != nil {
+ t.Fatal(err)
+ }
+ return ln
+}
+
+func TestDialTimeout(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ listener := newLocalListener(t)
+
+ addr := listener.Addr().String()
+ defer listener.Close()
+
+ complete := make(chan bool)
+ defer close(complete)
+
+ go func() {
+ conn, err := listener.Accept()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ <-complete
+ conn.Close()
+ }()
+
+ dialer := &net.Dialer{
+ Timeout: 10 * time.Millisecond,
+ }
+
+ var err error
+ if _, err = DialWithDialer(dialer, "tcp", addr, nil); err == nil {
+ t.Fatal("DialWithTimeout completed successfully")
+ }
+
+ if !isTimeoutError(err) {
+ t.Errorf("resulting error not a timeout: %v\nType %T: %#v", err, err, err)
+ }
+}
+
+func TestDeadlineOnWrite(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+
+ ln := newLocalListener(t)
+ defer ln.Close()
+
+ srvCh := make(chan *Conn, 1)
+
+ go func() {
+ sconn, err := ln.Accept()
+ if err != nil {
+ srvCh <- nil
+ return
+ }
+ srv := Server(sconn, testConfig.Clone())
+ if err := srv.Handshake(); err != nil {
+ srvCh <- nil
+ return
+ }
+ srvCh <- srv
+ }()
+
+ clientConfig := testConfig.Clone()
+ clientConfig.MaxVersion = VersionTLS12
+ conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn.Close()
+
+ srv := <-srvCh
+ if srv == nil {
+ t.Error(err)
+ }
+
+ // Make sure the client/server is setup correctly and is able to do a typical Write/Read
+ buf := make([]byte, 6)
+ if _, err := srv.Write([]byte("foobar")); err != nil {
+ t.Errorf("Write err: %v", err)
+ }
+ if n, err := conn.Read(buf); n != 6 || err != nil || string(buf) != "foobar" {
+ t.Errorf("Read = %d, %v, data %q; want 6, nil, foobar", n, err, buf)
+ }
+
+ // Set a deadline which should cause Write to timeout
+ if err = srv.SetDeadline(time.Now()); err != nil {
+ t.Fatalf("SetDeadline(time.Now()) err: %v", err)
+ }
+ if _, err = srv.Write([]byte("should fail")); err == nil {
+ t.Fatal("Write should have timed out")
+ }
+
+ // Clear deadline and make sure it still times out
+ if err = srv.SetDeadline(time.Time{}); err != nil {
+ t.Fatalf("SetDeadline(time.Time{}) err: %v", err)
+ }
+ if _, err = srv.Write([]byte("This connection is permanently broken")); err == nil {
+ t.Fatal("Write which previously failed should still time out")
+ }
+
+ // Verify the error
+ if ne := err.(net.Error); ne.Temporary() != false {
+ t.Error("Write timed out but incorrectly classified the error as Temporary")
+ }
+ if !isTimeoutError(err) {
+ t.Error("Write timed out but did not classify the error as a Timeout")
+ }
+}
+
+type readerFunc func([]byte) (int, error)
+
+func (f readerFunc) Read(b []byte) (int, error) { return f(b) }
+
+// TestDialer tests that tls.Dialer.DialContext can abort in the middle of a handshake.
+// (The other cases are all handled by the existing dial tests in this package, which
+// all also flow through the same code shared code paths)
+func TestDialer(t *testing.T) {
+ ln := newLocalListener(t)
+ defer ln.Close()
+
+ unblockServer := make(chan struct{}) // close-only
+ defer close(unblockServer)
+ go func() {
+ conn, err := ln.Accept()
+ if err != nil {
+ return
+ }
+ defer conn.Close()
+ <-unblockServer
+ }()
+
+ ctx, cancel := context.WithCancel(context.Background())
+ d := Dialer{Config: &Config{
+ Rand: readerFunc(func(b []byte) (n int, err error) {
+ // By the time crypto/tls wants randomness, that means it has a TCP
+ // connection, so we're past the Dialer's dial and now blocked
+ // in a handshake. Cancel our context and see if we get unstuck.
+ // (Our TCP listener above never reads or writes, so the Handshake
+ // would otherwise be stuck forever)
+ cancel()
+ return len(b), nil
+ }),
+ ServerName: "foo",
+ }}
+ _, err := d.DialContext(ctx, "tcp", ln.Addr().String())
+ if err != context.Canceled {
+ t.Errorf("err = %v; want context.Canceled", err)
+ }
+}
+
+func isTimeoutError(err error) bool {
+ if ne, ok := err.(net.Error); ok {
+ return ne.Timeout()
+ }
+ return false
+}
+
+// tests that Conn.Read returns (non-zero, io.EOF) instead of
+// (non-zero, nil) when a Close (alertCloseNotify) is sitting right
+// behind the application data in the buffer.
+func TestConnReadNonzeroAndEOF(t *testing.T) {
+ // This test is racy: it assumes that after a write to a
+ // localhost TCP connection, the peer TCP connection can
+ // immediately read it. Because it's racy, we skip this test
+ // in short mode, and then retry it several times with an
+ // increasing sleep in between our final write (via srv.Close
+ // below) and the following read.
+ if testing.Short() {
+ t.Skip("skipping in short mode")
+ }
+ var err error
+ for delay := time.Millisecond; delay <= 64*time.Millisecond; delay *= 2 {
+ if err = testConnReadNonzeroAndEOF(t, delay); err == nil {
+ return
+ }
+ }
+ t.Error(err)
+}
+
+func testConnReadNonzeroAndEOF(t *testing.T, delay time.Duration) error {
+ ln := newLocalListener(t)
+ defer ln.Close()
+
+ srvCh := make(chan *Conn, 1)
+ var serr error
+ go func() {
+ sconn, err := ln.Accept()
+ if err != nil {
+ serr = err
+ srvCh <- nil
+ return
+ }
+ serverConfig := testConfig.Clone()
+ srv := Server(sconn, serverConfig)
+ if err := srv.Handshake(); err != nil {
+ serr = fmt.Errorf("handshake: %v", err)
+ srvCh <- nil
+ return
+ }
+ srvCh <- srv
+ }()
+
+ clientConfig := testConfig.Clone()
+ // In TLS 1.3, alerts are encrypted and disguised as application data, so
+ // the opportunistic peek won't work.
+ clientConfig.MaxVersion = VersionTLS12
+ conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn.Close()
+
+ srv := <-srvCh
+ if srv == nil {
+ return serr
+ }
+
+ buf := make([]byte, 6)
+
+ srv.Write([]byte("foobar"))
+ n, err := conn.Read(buf)
+ if n != 6 || err != nil || string(buf) != "foobar" {
+ return fmt.Errorf("Read = %d, %v, data %q; want 6, nil, foobar", n, err, buf)
+ }
+
+ srv.Write([]byte("abcdef"))
+ srv.Close()
+ time.Sleep(delay)
+ n, err = conn.Read(buf)
+ if n != 6 || string(buf) != "abcdef" {
+ return fmt.Errorf("Read = %d, buf= %q; want 6, abcdef", n, buf)
+ }
+ if err != io.EOF {
+ return fmt.Errorf("Second Read error = %v; want io.EOF", err)
+ }
+ return nil
+}
+
+func TestTLSUniqueMatches(t *testing.T) {
+ ln := newLocalListener(t)
+ defer ln.Close()
+
+ serverTLSUniques := make(chan []byte)
+ parentDone := make(chan struct{})
+ childDone := make(chan struct{})
+ defer close(parentDone)
+ go func() {
+ defer close(childDone)
+ for i := 0; i < 2; i++ {
+ sconn, err := ln.Accept()
+ if err != nil {
+ t.Error(err)
+ return
+ }
+ serverConfig := testConfig.Clone()
+ serverConfig.MaxVersion = VersionTLS12 // TLSUnique is not defined in TLS 1.3
+ srv := Server(sconn, serverConfig)
+ if err := srv.Handshake(); err != nil {
+ t.Error(err)
+ return
+ }
+ select {
+ case <-parentDone:
+ return
+ case serverTLSUniques <- srv.ConnectionState().TLSUnique:
+ }
+ }
+ }()
+
+ clientConfig := testConfig.Clone()
+ clientConfig.ClientSessionCache = NewLRUClientSessionCache(1)
+ conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ var serverTLSUniquesValue []byte
+ select {
+ case <-childDone:
+ return
+ case serverTLSUniquesValue = <-serverTLSUniques:
+ }
+
+ if !bytes.Equal(conn.ConnectionState().TLSUnique, serverTLSUniquesValue) {
+ t.Error("client and server channel bindings differ")
+ }
+ conn.Close()
+
+ conn, err = Dial("tcp", ln.Addr().String(), clientConfig)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn.Close()
+ if !conn.ConnectionState().DidResume {
+ t.Error("second session did not use resumption")
+ }
+
+ select {
+ case <-childDone:
+ return
+ case serverTLSUniquesValue = <-serverTLSUniques:
+ }
+
+ if !bytes.Equal(conn.ConnectionState().TLSUnique, serverTLSUniquesValue) {
+ t.Error("client and server channel bindings differ when session resumption is used")
+ }
+}
+
+func TestVerifyHostname(t *testing.T) {
+ testenv.MustHaveExternalNetwork(t)
+
+ c, err := Dial("tcp", "www.google.com:https", nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := c.VerifyHostname("www.google.com"); err != nil {
+ t.Fatalf("verify www.google.com: %v", err)
+ }
+ if err := c.VerifyHostname("www.yahoo.com"); err == nil {
+ t.Fatalf("verify www.yahoo.com succeeded")
+ }
+
+ c, err = Dial("tcp", "www.google.com:https", &Config{InsecureSkipVerify: true})
+ if err != nil {
+ t.Fatal(err)
+ }
+ if err := c.VerifyHostname("www.google.com"); err == nil {
+ t.Fatalf("verify www.google.com succeeded with InsecureSkipVerify=true")
+ }
+}
+
+func TestConnCloseBreakingWrite(t *testing.T) {
+ ln := newLocalListener(t)
+ defer ln.Close()
+
+ srvCh := make(chan *Conn, 1)
+ var serr error
+ var sconn net.Conn
+ go func() {
+ var err error
+ sconn, err = ln.Accept()
+ if err != nil {
+ serr = err
+ srvCh <- nil
+ return
+ }
+ serverConfig := testConfig.Clone()
+ srv := Server(sconn, serverConfig)
+ if err := srv.Handshake(); err != nil {
+ serr = fmt.Errorf("handshake: %v", err)
+ srvCh <- nil
+ return
+ }
+ srvCh <- srv
+ }()
+
+ cconn, err := net.Dial("tcp", ln.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer cconn.Close()
+
+ conn := &changeImplConn{
+ Conn: cconn,
+ }
+
+ clientConfig := testConfig.Clone()
+ tconn := Client(conn, clientConfig)
+ if err := tconn.Handshake(); err != nil {
+ t.Fatal(err)
+ }
+
+ srv := <-srvCh
+ if srv == nil {
+ t.Fatal(serr)
+ }
+ defer sconn.Close()
+
+ connClosed := make(chan struct{})
+ conn.closeFunc = func() error {
+ close(connClosed)
+ return nil
+ }
+
+ inWrite := make(chan bool, 1)
+ var errConnClosed = errors.New("conn closed for test")
+ conn.writeFunc = func(p []byte) (n int, err error) {
+ inWrite <- true
+ <-connClosed
+ return 0, errConnClosed
+ }
+
+ closeReturned := make(chan bool, 1)
+ go func() {
+ <-inWrite
+ tconn.Close() // test that this doesn't block forever.
+ closeReturned <- true
+ }()
+
+ _, err = tconn.Write([]byte("foo"))
+ if err != errConnClosed {
+ t.Errorf("Write error = %v; want errConnClosed", err)
+ }
+
+ <-closeReturned
+ if err := tconn.Close(); err != net.ErrClosed {
+ t.Errorf("Close error = %v; want net.ErrClosed", err)
+ }
+}
+
+func TestConnCloseWrite(t *testing.T) {
+ ln := newLocalListener(t)
+ defer ln.Close()
+
+ clientDoneChan := make(chan struct{})
+
+ serverCloseWrite := func() error {
+ sconn, err := ln.Accept()
+ if err != nil {
+ return fmt.Errorf("accept: %v", err)
+ }
+ defer sconn.Close()
+
+ serverConfig := testConfig.Clone()
+ srv := Server(sconn, serverConfig)
+ if err := srv.Handshake(); err != nil {
+ return fmt.Errorf("handshake: %v", err)
+ }
+ defer srv.Close()
+
+ data, err := io.ReadAll(srv)
+ if err != nil {
+ return err
+ }
+ if len(data) > 0 {
+ return fmt.Errorf("Read data = %q; want nothing", data)
+ }
+
+ if err := srv.CloseWrite(); err != nil {
+ return fmt.Errorf("server CloseWrite: %v", err)
+ }
+
+ // Wait for clientCloseWrite to finish, so we know we
+ // tested the CloseWrite before we defer the
+ // sconn.Close above, which would also cause the
+ // client to unblock like CloseWrite.
+ <-clientDoneChan
+ return nil
+ }
+
+ clientCloseWrite := func() error {
+ defer close(clientDoneChan)
+
+ clientConfig := testConfig.Clone()
+ conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
+ if err != nil {
+ return err
+ }
+ if err := conn.Handshake(); err != nil {
+ return err
+ }
+ defer conn.Close()
+
+ if err := conn.CloseWrite(); err != nil {
+ return fmt.Errorf("client CloseWrite: %v", err)
+ }
+
+ if _, err := conn.Write([]byte{0}); err != errShutdown {
+ return fmt.Errorf("CloseWrite error = %v; want errShutdown", err)
+ }
+
+ data, err := io.ReadAll(conn)
+ if err != nil {
+ return err
+ }
+ if len(data) > 0 {
+ return fmt.Errorf("Read data = %q; want nothing", data)
+ }
+ return nil
+ }
+
+ errChan := make(chan error, 2)
+
+ go func() { errChan <- serverCloseWrite() }()
+ go func() { errChan <- clientCloseWrite() }()
+
+ for i := 0; i < 2; i++ {
+ select {
+ case err := <-errChan:
+ if err != nil {
+ t.Fatal(err)
+ }
+ case <-time.After(10 * time.Second):
+ t.Fatal("deadlock")
+ }
+ }
+
+ // Also test CloseWrite being called before the handshake is
+ // finished:
+ {
+ ln2 := newLocalListener(t)
+ defer ln2.Close()
+
+ netConn, err := net.Dial("tcp", ln2.Addr().String())
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer netConn.Close()
+ conn := Client(netConn, testConfig.Clone())
+
+ if err := conn.CloseWrite(); err != errEarlyCloseWrite {
+ t.Errorf("CloseWrite error = %v; want errEarlyCloseWrite", err)
+ }
+ }
+}
+
+func TestWarningAlertFlood(t *testing.T) {
+ ln := newLocalListener(t)
+ defer ln.Close()
+
+ server := func() error {
+ sconn, err := ln.Accept()
+ if err != nil {
+ return fmt.Errorf("accept: %v", err)
+ }
+ defer sconn.Close()
+
+ serverConfig := testConfig.Clone()
+ srv := Server(sconn, serverConfig)
+ if err := srv.Handshake(); err != nil {
+ return fmt.Errorf("handshake: %v", err)
+ }
+ defer srv.Close()
+
+ _, err = io.ReadAll(srv)
+ if err == nil {
+ return errors.New("unexpected lack of error from server")
+ }
+ const expected = "too many ignored"
+ if str := err.Error(); !strings.Contains(str, expected) {
+ return fmt.Errorf("expected error containing %q, but saw: %s", expected, str)
+ }
+
+ return nil
+ }
+
+ errChan := make(chan error, 1)
+ go func() { errChan <- server() }()
+
+ clientConfig := testConfig.Clone()
+ clientConfig.MaxVersion = VersionTLS12 // there are no warning alerts in TLS 1.3
+ conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer conn.Close()
+ if err := conn.Handshake(); err != nil {
+ t.Fatal(err)
+ }
+
+ for i := 0; i < maxUselessRecords+1; i++ {
+ conn.sendAlert(alertNoRenegotiation)
+ }
+
+ if err := <-errChan; err != nil {
+ t.Fatal(err)
+ }
+}
+
+func TestCloneFuncFields(t *testing.T) {
+ const expectedCount = 6
+ called := 0
+
+ c1 := Config{
+ Time: func() time.Time {
+ called |= 1 << 0
+ return time.Time{}
+ },
+ GetCertificate: func(*ClientHelloInfo) (*Certificate, error) {
+ called |= 1 << 1
+ return nil, nil
+ },
+ GetClientCertificate: func(*CertificateRequestInfo) (*Certificate, error) {
+ called |= 1 << 2
+ return nil, nil
+ },
+ GetConfigForClient: func(*ClientHelloInfo) (*Config, error) {
+ called |= 1 << 3
+ return nil, nil
+ },
+ VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
+ called |= 1 << 4
+ return nil
+ },
+ VerifyConnection: func(ConnectionState) error {
+ called |= 1 << 5
+ return nil
+ },
+ }
+
+ c2 := c1.Clone()
+
+ c2.Time()
+ c2.GetCertificate(nil)
+ c2.GetClientCertificate(nil)
+ c2.GetConfigForClient(nil)
+ c2.VerifyPeerCertificate(nil, nil)
+ c2.VerifyConnection(ConnectionState{})
+
+ if called != (1<<expectedCount)-1 {
+ t.Fatalf("expected %d calls but saw calls %b", expectedCount, called)
+ }
+}
+
+func TestCloneNonFuncFields(t *testing.T) {
+ var c1 Config
+ v := reflect.ValueOf(&c1).Elem()
+
+ typ := v.Type()
+ for i := 0; i < typ.NumField(); i++ {
+ f := v.Field(i)
+ // testing/quick can't handle functions or interfaces and so
+ // isn't used here.
+ switch fn := typ.Field(i).Name; fn {
+ case "Rand":
+ f.Set(reflect.ValueOf(io.Reader(os.Stdin)))
+ case "Time", "GetCertificate", "GetConfigForClient", "VerifyPeerCertificate", "VerifyConnection", "GetClientCertificate":
+ // DeepEqual can't compare functions. If you add a
+ // function field to this list, you must also change
+ // TestCloneFuncFields to ensure that the func field is
+ // cloned.
+ case "Certificates":
+ f.Set(reflect.ValueOf([]Certificate{
+ {Certificate: [][]byte{{'b'}}},
+ }))
+ case "NameToCertificate":
+ f.Set(reflect.ValueOf(map[string]*Certificate{"a": nil}))
+ case "RootCAs", "ClientCAs":
+ f.Set(reflect.ValueOf(x509.NewCertPool()))
+ case "ClientSessionCache":
+ f.Set(reflect.ValueOf(NewLRUClientSessionCache(10)))
+ case "KeyLogWriter":
+ f.Set(reflect.ValueOf(io.Writer(os.Stdout)))
+ case "NextProtos":
+ f.Set(reflect.ValueOf([]string{"a", "b"}))
+ case "ServerName":
+ f.Set(reflect.ValueOf("b"))
+ case "ClientAuth":
+ f.Set(reflect.ValueOf(VerifyClientCertIfGiven))
+ case "InsecureSkipVerify", "SessionTicketsDisabled", "DynamicRecordSizingDisabled", "PreferServerCipherSuites":
+ f.Set(reflect.ValueOf(true))
+ case "MinVersion", "MaxVersion":
+ f.Set(reflect.ValueOf(uint16(VersionTLS12)))
+ case "SessionTicketKey":
+ f.Set(reflect.ValueOf([32]byte{}))
+ case "CipherSuites":
+ f.Set(reflect.ValueOf([]uint16{1, 2}))
+ case "CurvePreferences":
+ f.Set(reflect.ValueOf([]CurveID{CurveP256}))
+ case "Renegotiation":
+ f.Set(reflect.ValueOf(RenegotiateOnceAsClient))
+ case "mutex", "autoSessionTicketKeys", "sessionTicketKeys":
+ continue // these are unexported fields that are handled separately
+ default:
+ t.Errorf("all fields must be accounted for, but saw unknown field %q", fn)
+ }
+ }
+ // Set the unexported fields related to session ticket keys, which are copied with Clone().
+ c1.autoSessionTicketKeys = []ticketKey{c1.ticketKeyFromBytes(c1.SessionTicketKey)}
+ c1.sessionTicketKeys = []ticketKey{c1.ticketKeyFromBytes(c1.SessionTicketKey)}
+
+ c2 := c1.Clone()
+ if !reflect.DeepEqual(&c1, c2) {
+ t.Errorf("clone failed to copy a field")
+ }
+}
+
+func TestCloneNilConfig(t *testing.T) {
+ var config *Config
+ if cc := config.Clone(); cc != nil {
+ t.Fatalf("Clone with nil should return nil, got: %+v", cc)
+ }
+}
+
+// changeImplConn is a net.Conn which can change its Write and Close
+// methods.
+type changeImplConn struct {
+ net.Conn
+ writeFunc func([]byte) (int, error)
+ closeFunc func() error
+}
+
+func (w *changeImplConn) Write(p []byte) (n int, err error) {
+ if w.writeFunc != nil {
+ return w.writeFunc(p)
+ }
+ return w.Conn.Write(p)
+}
+
+func (w *changeImplConn) Close() error {
+ if w.closeFunc != nil {
+ return w.closeFunc()
+ }
+ return w.Conn.Close()
+}
+
+func throughput(b *testing.B, version uint16, totalBytes int64, dynamicRecordSizingDisabled bool) {
+ ln := newLocalListener(b)
+ defer ln.Close()
+
+ N := b.N
+
+ // Less than 64KB because Windows appears to use a TCP rwin < 64KB.
+ // See Issue #15899.
+ const bufsize = 32 << 10
+
+ go func() {
+ buf := make([]byte, bufsize)
+ for i := 0; i < N; i++ {
+ sconn, err := ln.Accept()
+ if err != nil {
+ // panic rather than synchronize to avoid benchmark overhead
+ // (cannot call b.Fatal in goroutine)
+ panic(fmt.Errorf("accept: %v", err))
+ }
+ serverConfig := testConfig.Clone()
+ serverConfig.CipherSuites = nil // the defaults may prefer faster ciphers
+ serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
+ srv := Server(sconn, serverConfig)
+ if err := srv.Handshake(); err != nil {
+ panic(fmt.Errorf("handshake: %v", err))
+ }
+ if _, err := io.CopyBuffer(srv, srv, buf); err != nil {
+ panic(fmt.Errorf("copy buffer: %v", err))
+ }
+ }
+ }()
+
+ b.SetBytes(totalBytes)
+ clientConfig := testConfig.Clone()
+ clientConfig.CipherSuites = nil // the defaults may prefer faster ciphers
+ clientConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
+ clientConfig.MaxVersion = version
+
+ buf := make([]byte, bufsize)
+ chunks := int(math.Ceil(float64(totalBytes) / float64(len(buf))))
+ for i := 0; i < N; i++ {
+ conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
+ if err != nil {
+ b.Fatal(err)
+ }
+ for j := 0; j < chunks; j++ {
+ _, err := conn.Write(buf)
+ if err != nil {
+ b.Fatal(err)
+ }
+ _, err = io.ReadFull(conn, buf)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+ conn.Close()
+ }
+}
+
+func BenchmarkThroughput(b *testing.B) {
+ for _, mode := range []string{"Max", "Dynamic"} {
+ for size := 1; size <= 64; size <<= 1 {
+ name := fmt.Sprintf("%sPacket/%dMB", mode, size)
+ b.Run(name, func(b *testing.B) {
+ b.Run("TLSv12", func(b *testing.B) {
+ throughput(b, VersionTLS12, int64(size<<20), mode == "Max")
+ })
+ b.Run("TLSv13", func(b *testing.B) {
+ throughput(b, VersionTLS13, int64(size<<20), mode == "Max")
+ })
+ })
+ }
+ }
+}
+
+type slowConn struct {
+ net.Conn
+ bps int
+}
+
+func (c *slowConn) Write(p []byte) (int, error) {
+ if c.bps == 0 {
+ panic("too slow")
+ }
+ t0 := time.Now()
+ wrote := 0
+ for wrote < len(p) {
+ time.Sleep(100 * time.Microsecond)
+ allowed := int(time.Since(t0).Seconds()*float64(c.bps)) / 8
+ if allowed > len(p) {
+ allowed = len(p)
+ }
+ if wrote < allowed {
+ n, err := c.Conn.Write(p[wrote:allowed])
+ wrote += n
+ if err != nil {
+ return wrote, err
+ }
+ }
+ }
+ return len(p), nil
+}
+
+func latency(b *testing.B, version uint16, bps int, dynamicRecordSizingDisabled bool) {
+ ln := newLocalListener(b)
+ defer ln.Close()
+
+ N := b.N
+
+ go func() {
+ for i := 0; i < N; i++ {
+ sconn, err := ln.Accept()
+ if err != nil {
+ // panic rather than synchronize to avoid benchmark overhead
+ // (cannot call b.Fatal in goroutine)
+ panic(fmt.Errorf("accept: %v", err))
+ }
+ serverConfig := testConfig.Clone()
+ serverConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
+ srv := Server(&slowConn{sconn, bps}, serverConfig)
+ if err := srv.Handshake(); err != nil {
+ panic(fmt.Errorf("handshake: %v", err))
+ }
+ io.Copy(srv, srv)
+ }
+ }()
+
+ clientConfig := testConfig.Clone()
+ clientConfig.DynamicRecordSizingDisabled = dynamicRecordSizingDisabled
+ clientConfig.MaxVersion = version
+
+ buf := make([]byte, 16384)
+ peek := make([]byte, 1)
+
+ for i := 0; i < N; i++ {
+ conn, err := Dial("tcp", ln.Addr().String(), clientConfig)
+ if err != nil {
+ b.Fatal(err)
+ }
+ // make sure we're connected and previous connection has stopped
+ if _, err := conn.Write(buf[:1]); err != nil {
+ b.Fatal(err)
+ }
+ if _, err := io.ReadFull(conn, peek); err != nil {
+ b.Fatal(err)
+ }
+ if _, err := conn.Write(buf); err != nil {
+ b.Fatal(err)
+ }
+ if _, err = io.ReadFull(conn, peek); err != nil {
+ b.Fatal(err)
+ }
+ conn.Close()
+ }
+}
+
+func BenchmarkLatency(b *testing.B) {
+ for _, mode := range []string{"Max", "Dynamic"} {
+ for _, kbps := range []int{200, 500, 1000, 2000, 5000} {
+ name := fmt.Sprintf("%sPacket/%dkbps", mode, kbps)
+ b.Run(name, func(b *testing.B) {
+ b.Run("TLSv12", func(b *testing.B) {
+ latency(b, VersionTLS12, kbps*1000, mode == "Max")
+ })
+ b.Run("TLSv13", func(b *testing.B) {
+ latency(b, VersionTLS13, kbps*1000, mode == "Max")
+ })
+ })
+ }
+ }
+}
+
+func TestConnectionStateMarshal(t *testing.T) {
+ cs := &ConnectionState{}
+ _, err := json.Marshal(cs)
+ if err != nil {
+ t.Errorf("json.Marshal failed on ConnectionState: %v", err)
+ }
+}
+
+func TestConnectionState(t *testing.T) {
+ issuer, err := x509.ParseCertificate(testRSACertificateIssuer)
+ if err != nil {
+ panic(err)
+ }
+ rootCAs := x509.NewCertPool()
+ rootCAs.AddCert(issuer)
+
+ now := func() time.Time { return time.Unix(1476984729, 0) }
+
+ const alpnProtocol = "golang"
+ const serverName = "example.golang"
+ var scts = [][]byte{[]byte("dummy sct 1"), []byte("dummy sct 2")}
+ var ocsp = []byte("dummy ocsp")
+
+ for _, v := range []uint16{VersionTLS12, VersionTLS13} {
+ var name string
+ switch v {
+ case VersionTLS12:
+ name = "TLSv12"
+ case VersionTLS13:
+ name = "TLSv13"
+ }
+ t.Run(name, func(t *testing.T) {
+ config := &Config{
+ Time: now,
+ Rand: zeroSource{},
+ Certificates: make([]Certificate, 1),
+ MaxVersion: v,
+ RootCAs: rootCAs,
+ ClientCAs: rootCAs,
+ ClientAuth: RequireAndVerifyClientCert,
+ NextProtos: []string{alpnProtocol},
+ ServerName: serverName,
+ }
+ config.Certificates[0].Certificate = [][]byte{testRSACertificate}
+ config.Certificates[0].PrivateKey = testRSAPrivateKey
+ config.Certificates[0].SignedCertificateTimestamps = scts
+ config.Certificates[0].OCSPStaple = ocsp
+
+ ss, cs, err := testHandshake(t, config, config)
+ if err != nil {
+ t.Fatalf("Handshake failed: %v", err)
+ }
+
+ if ss.Version != v || cs.Version != v {
+ t.Errorf("Got versions %x (server) and %x (client), expected %x", ss.Version, cs.Version, v)
+ }
+
+ if !ss.HandshakeComplete || !cs.HandshakeComplete {
+ t.Errorf("Got HandshakeComplete %v (server) and %v (client), expected true", ss.HandshakeComplete, cs.HandshakeComplete)
+ }
+
+ if ss.DidResume || cs.DidResume {
+ t.Errorf("Got DidResume %v (server) and %v (client), expected false", ss.DidResume, cs.DidResume)
+ }
+
+ if ss.CipherSuite == 0 || cs.CipherSuite == 0 {
+ t.Errorf("Got invalid cipher suite: %v (server) and %v (client)", ss.CipherSuite, cs.CipherSuite)
+ }
+
+ if ss.NegotiatedProtocol != alpnProtocol || cs.NegotiatedProtocol != alpnProtocol {
+ t.Errorf("Got negotiated protocol %q (server) and %q (client), expected %q", ss.NegotiatedProtocol, cs.NegotiatedProtocol, alpnProtocol)
+ }
+
+ if !cs.NegotiatedProtocolIsMutual {
+ t.Errorf("Got false NegotiatedProtocolIsMutual on the client side")
+ }
+ // NegotiatedProtocolIsMutual on the server side is unspecified.
+
+ if ss.ServerName != serverName {
+ t.Errorf("Got server name %q, expected %q", ss.ServerName, serverName)
+ }
+ if cs.ServerName != serverName {
+ t.Errorf("Got server name on client connection %q, expected %q", cs.ServerName, serverName)
+ }
+
+ if len(ss.PeerCertificates) != 1 || len(cs.PeerCertificates) != 1 {
+ t.Errorf("Got %d (server) and %d (client) peer certificates, expected %d", len(ss.PeerCertificates), len(cs.PeerCertificates), 1)
+ }
+
+ if len(ss.VerifiedChains) != 1 || len(cs.VerifiedChains) != 1 {
+ t.Errorf("Got %d (server) and %d (client) verified chains, expected %d", len(ss.VerifiedChains), len(cs.VerifiedChains), 1)
+ } else if len(ss.VerifiedChains[0]) != 2 || len(cs.VerifiedChains[0]) != 2 {
+ t.Errorf("Got %d (server) and %d (client) long verified chain, expected %d", len(ss.VerifiedChains[0]), len(cs.VerifiedChains[0]), 2)
+ }
+
+ if len(cs.SignedCertificateTimestamps) != 2 {
+ t.Errorf("Got %d SCTs, expected %d", len(cs.SignedCertificateTimestamps), 2)
+ }
+ if !bytes.Equal(cs.OCSPResponse, ocsp) {
+ t.Errorf("Got OCSPs %x, expected %x", cs.OCSPResponse, ocsp)
+ }
+ // Only TLS 1.3 supports OCSP and SCTs on client certs.
+ if v == VersionTLS13 {
+ if len(ss.SignedCertificateTimestamps) != 2 {
+ t.Errorf("Got %d client SCTs, expected %d", len(ss.SignedCertificateTimestamps), 2)
+ }
+ if !bytes.Equal(ss.OCSPResponse, ocsp) {
+ t.Errorf("Got client OCSPs %x, expected %x", ss.OCSPResponse, ocsp)
+ }
+ }
+
+ if v == VersionTLS13 {
+ if ss.TLSUnique != nil || cs.TLSUnique != nil {
+ t.Errorf("Got TLSUnique %x (server) and %x (client), expected nil in TLS 1.3", ss.TLSUnique, cs.TLSUnique)
+ }
+ } else {
+ if ss.TLSUnique == nil || cs.TLSUnique == nil {
+ t.Errorf("Got TLSUnique %x (server) and %x (client), expected non-nil", ss.TLSUnique, cs.TLSUnique)
+ }
+ }
+ })
+ }
+}
+
+// Issue 28744: Ensure that we don't modify memory
+// that Config doesn't own such as Certificates.
+func TestBuildNameToCertificate_doesntModifyCertificates(t *testing.T) {
+ c0 := Certificate{
+ Certificate: [][]byte{testRSACertificate},
+ PrivateKey: testRSAPrivateKey,
+ }
+ c1 := Certificate{
+ Certificate: [][]byte{testSNICertificate},
+ PrivateKey: testRSAPrivateKey,
+ }
+ config := testConfig.Clone()
+ config.Certificates = []Certificate{c0, c1}
+
+ config.BuildNameToCertificate()
+ got := config.Certificates
+ want := []Certificate{c0, c1}
+ if !reflect.DeepEqual(got, want) {
+ t.Fatalf("Certificates were mutated by BuildNameToCertificate\nGot: %#v\nWant: %#v\n", got, want)
+ }
+}
+
+func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") }
+
+func TestClientHelloInfo_SupportsCertificate(t *testing.T) {
+ rsaCert := &Certificate{
+ Certificate: [][]byte{testRSACertificate},
+ PrivateKey: testRSAPrivateKey,
+ }
+ pkcs1Cert := &Certificate{
+ Certificate: [][]byte{testRSACertificate},
+ PrivateKey: testRSAPrivateKey,
+ SupportedSignatureAlgorithms: []SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256},
+ }
+ ecdsaCert := &Certificate{
+ // ECDSA P-256 certificate
+ Certificate: [][]byte{testP256Certificate},
+ PrivateKey: testP256PrivateKey,
+ }
+ ed25519Cert := &Certificate{
+ Certificate: [][]byte{testEd25519Certificate},
+ PrivateKey: testEd25519PrivateKey,
+ }
+
+ tests := []struct {
+ c *Certificate
+ chi *ClientHelloInfo
+ wantErr string
+ }{
+ {rsaCert, &ClientHelloInfo{
+ ServerName: "example.golang",
+ SignatureSchemes: []SignatureScheme{PSSWithSHA256},
+ SupportedVersions: []uint16{VersionTLS13},
+ }, ""},
+ {ecdsaCert, &ClientHelloInfo{
+ SignatureSchemes: []SignatureScheme{PSSWithSHA256, ECDSAWithP256AndSHA256},
+ SupportedVersions: []uint16{VersionTLS13, VersionTLS12},
+ }, ""},
+ {rsaCert, &ClientHelloInfo{
+ ServerName: "example.com",
+ SignatureSchemes: []SignatureScheme{PSSWithSHA256},
+ SupportedVersions: []uint16{VersionTLS13},
+ }, "not valid for requested server name"},
+ {ecdsaCert, &ClientHelloInfo{
+ SignatureSchemes: []SignatureScheme{ECDSAWithP384AndSHA384},
+ SupportedVersions: []uint16{VersionTLS13},
+ }, "signature algorithms"},
+ {pkcs1Cert, &ClientHelloInfo{
+ SignatureSchemes: []SignatureScheme{PSSWithSHA256, ECDSAWithP256AndSHA256},
+ SupportedVersions: []uint16{VersionTLS13},
+ }, "signature algorithms"},
+
+ {rsaCert, &ClientHelloInfo{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ SignatureSchemes: []SignatureScheme{PKCS1WithSHA1},
+ SupportedVersions: []uint16{VersionTLS13, VersionTLS12},
+ }, "signature algorithms"},
+ {rsaCert, &ClientHelloInfo{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ SignatureSchemes: []SignatureScheme{PKCS1WithSHA1},
+ SupportedVersions: []uint16{VersionTLS13, VersionTLS12},
+ config: &Config{
+ MaxVersion: VersionTLS12,
+ },
+ }, ""}, // Check that mutual version selection works.
+
+ {ecdsaCert, &ClientHelloInfo{
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ SupportedCurves: []CurveID{CurveP256},
+ SupportedPoints: []uint8{pointFormatUncompressed},
+ SignatureSchemes: []SignatureScheme{ECDSAWithP256AndSHA256},
+ SupportedVersions: []uint16{VersionTLS12},
+ }, ""},
+ {ecdsaCert, &ClientHelloInfo{
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ SupportedCurves: []CurveID{CurveP256},
+ SupportedPoints: []uint8{pointFormatUncompressed},
+ SignatureSchemes: []SignatureScheme{ECDSAWithP384AndSHA384},
+ SupportedVersions: []uint16{VersionTLS12},
+ }, ""}, // TLS 1.2 does not restrict curves based on the SignatureScheme.
+ {ecdsaCert, &ClientHelloInfo{
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ SupportedCurves: []CurveID{CurveP256},
+ SupportedPoints: []uint8{pointFormatUncompressed},
+ SignatureSchemes: nil,
+ SupportedVersions: []uint16{VersionTLS12},
+ }, ""}, // TLS 1.2 comes with default signature schemes.
+ {ecdsaCert, &ClientHelloInfo{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ SupportedCurves: []CurveID{CurveP256},
+ SupportedPoints: []uint8{pointFormatUncompressed},
+ SignatureSchemes: []SignatureScheme{ECDSAWithP256AndSHA256},
+ SupportedVersions: []uint16{VersionTLS12},
+ }, "cipher suite"},
+ {ecdsaCert, &ClientHelloInfo{
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ SupportedCurves: []CurveID{CurveP256},
+ SupportedPoints: []uint8{pointFormatUncompressed},
+ SignatureSchemes: []SignatureScheme{ECDSAWithP256AndSHA256},
+ SupportedVersions: []uint16{VersionTLS12},
+ config: &Config{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ },
+ }, "cipher suite"},
+ {ecdsaCert, &ClientHelloInfo{
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ SupportedCurves: []CurveID{CurveP384},
+ SupportedPoints: []uint8{pointFormatUncompressed},
+ SignatureSchemes: []SignatureScheme{ECDSAWithP256AndSHA256},
+ SupportedVersions: []uint16{VersionTLS12},
+ }, "certificate curve"},
+ {ecdsaCert, &ClientHelloInfo{
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ SupportedCurves: []CurveID{CurveP256},
+ SupportedPoints: []uint8{1},
+ SignatureSchemes: []SignatureScheme{ECDSAWithP256AndSHA256},
+ SupportedVersions: []uint16{VersionTLS12},
+ }, "doesn't support ECDHE"},
+ {ecdsaCert, &ClientHelloInfo{
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ SupportedCurves: []CurveID{CurveP256},
+ SupportedPoints: []uint8{pointFormatUncompressed},
+ SignatureSchemes: []SignatureScheme{PSSWithSHA256},
+ SupportedVersions: []uint16{VersionTLS12},
+ }, "signature algorithms"},
+
+ {ed25519Cert, &ClientHelloInfo{
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ SupportedCurves: []CurveID{CurveP256}, // only relevant for ECDHE support
+ SupportedPoints: []uint8{pointFormatUncompressed},
+ SignatureSchemes: []SignatureScheme{Ed25519},
+ SupportedVersions: []uint16{VersionTLS12},
+ }, ""},
+ {ed25519Cert, &ClientHelloInfo{
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ SupportedCurves: []CurveID{CurveP256}, // only relevant for ECDHE support
+ SupportedPoints: []uint8{pointFormatUncompressed},
+ SignatureSchemes: []SignatureScheme{Ed25519},
+ SupportedVersions: []uint16{VersionTLS10},
+ }, "doesn't support Ed25519"},
+ {ed25519Cert, &ClientHelloInfo{
+ CipherSuites: []uint16{TLS_ECDHE_ECDSA_WITH_AES_128_GCM_SHA256},
+ SupportedCurves: []CurveID{},
+ SupportedPoints: []uint8{pointFormatUncompressed},
+ SignatureSchemes: []SignatureScheme{Ed25519},
+ SupportedVersions: []uint16{VersionTLS12},
+ }, "doesn't support ECDHE"},
+
+ {rsaCert, &ClientHelloInfo{
+ CipherSuites: []uint16{TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA},
+ SupportedCurves: []CurveID{CurveP256}, // only relevant for ECDHE support
+ SupportedPoints: []uint8{pointFormatUncompressed},
+ SupportedVersions: []uint16{VersionTLS10},
+ }, ""},
+ {rsaCert, &ClientHelloInfo{
+ CipherSuites: []uint16{TLS_RSA_WITH_AES_128_GCM_SHA256},
+ SupportedVersions: []uint16{VersionTLS12},
+ }, ""}, // static RSA fallback
+ }
+ for i, tt := range tests {
+ err := tt.chi.SupportsCertificate(tt.c)
+ switch {
+ case tt.wantErr == "" && err != nil:
+ t.Errorf("%d: unexpected error: %v", i, err)
+ case tt.wantErr != "" && err == nil:
+ t.Errorf("%d: unexpected success", i)
+ case tt.wantErr != "" && !strings.Contains(err.Error(), tt.wantErr):
+ t.Errorf("%d: got error %q, expected %q", i, err, tt.wantErr)
+ }
+ }
+}
+
+func TestCipherSuites(t *testing.T) {
+ var lastID uint16
+ for _, c := range CipherSuites() {
+ if lastID > c.ID {
+ t.Errorf("CipherSuites are not ordered by ID: got %#04x after %#04x", c.ID, lastID)
+ } else {
+ lastID = c.ID
+ }
+
+ if c.Insecure {
+ t.Errorf("%#04x: Insecure CipherSuite returned by CipherSuites()", c.ID)
+ }
+ }
+ lastID = 0
+ for _, c := range InsecureCipherSuites() {
+ if lastID > c.ID {
+ t.Errorf("InsecureCipherSuites are not ordered by ID: got %#04x after %#04x", c.ID, lastID)
+ } else {
+ lastID = c.ID
+ }
+
+ if !c.Insecure {
+ t.Errorf("%#04x: not Insecure CipherSuite returned by InsecureCipherSuites()", c.ID)
+ }
+ }
+
+ CipherSuiteByID := func(id uint16) *CipherSuite {
+ for _, c := range CipherSuites() {
+ if c.ID == id {
+ return c
+ }
+ }
+ for _, c := range InsecureCipherSuites() {
+ if c.ID == id {
+ return c
+ }
+ }
+ return nil
+ }
+
+ for _, c := range cipherSuites {
+ cc := CipherSuiteByID(c.id)
+ if cc == nil {
+ t.Errorf("%#04x: no CipherSuite entry", c.id)
+ continue
+ }
+
+ if tls12Only := c.flags&suiteTLS12 != 0; tls12Only && len(cc.SupportedVersions) != 1 {
+ t.Errorf("%#04x: suite is TLS 1.2 only, but SupportedVersions is %v", c.id, cc.SupportedVersions)
+ } else if !tls12Only && len(cc.SupportedVersions) != 3 {
+ t.Errorf("%#04x: suite TLS 1.0-1.2, but SupportedVersions is %v", c.id, cc.SupportedVersions)
+ }
+
+ if got := CipherSuiteName(c.id); got != cc.Name {
+ t.Errorf("%#04x: unexpected CipherSuiteName: got %q, expected %q", c.id, got, cc.Name)
+ }
+ }
+ for _, c := range cipherSuitesTLS13 {
+ cc := CipherSuiteByID(c.id)
+ if cc == nil {
+ t.Errorf("%#04x: no CipherSuite entry", c.id)
+ continue
+ }
+
+ if cc.Insecure {
+ t.Errorf("%#04x: Insecure %v, expected false", c.id, cc.Insecure)
+ }
+ if len(cc.SupportedVersions) != 1 || cc.SupportedVersions[0] != VersionTLS13 {
+ t.Errorf("%#04x: suite is TLS 1.3 only, but SupportedVersions is %v", c.id, cc.SupportedVersions)
+ }
+
+ if got := CipherSuiteName(c.id); got != cc.Name {
+ t.Errorf("%#04x: unexpected CipherSuiteName: got %q, expected %q", c.id, got, cc.Name)
+ }
+ }
+
+ if got := CipherSuiteName(0xabc); got != "0x0ABC" {
+ t.Errorf("unexpected fallback CipherSuiteName: got %q, expected 0x0ABC", got)
+ }
+
+ if len(cipherSuitesPreferenceOrder) != len(cipherSuites) {
+ t.Errorf("cipherSuitesPreferenceOrder is not the same size as cipherSuites")
+ }
+ if len(cipherSuitesPreferenceOrderNoAES) != len(cipherSuitesPreferenceOrder) {
+ t.Errorf("cipherSuitesPreferenceOrderNoAES is not the same size as cipherSuitesPreferenceOrder")
+ }
+
+ // Check that disabled suites are at the end of the preference lists, and
+ // that they are marked insecure.
+ for i, id := range disabledCipherSuites {
+ offset := len(cipherSuitesPreferenceOrder) - len(disabledCipherSuites)
+ if cipherSuitesPreferenceOrder[offset+i] != id {
+ t.Errorf("disabledCipherSuites[%d]: not at the end of cipherSuitesPreferenceOrder", i)
+ }
+ if cipherSuitesPreferenceOrderNoAES[offset+i] != id {
+ t.Errorf("disabledCipherSuites[%d]: not at the end of cipherSuitesPreferenceOrderNoAES", i)
+ }
+ c := CipherSuiteByID(id)
+ if c == nil {
+ t.Errorf("%#04x: no CipherSuite entry", id)
+ continue
+ }
+ if !c.Insecure {
+ t.Errorf("%#04x: disabled by default but not marked insecure", id)
+ }
+ }
+
+ for i, prefOrder := range [][]uint16{cipherSuitesPreferenceOrder, cipherSuitesPreferenceOrderNoAES} {
+ // Check that insecure and HTTP/2 bad cipher suites are at the end of
+ // the preference lists.
+ var sawInsecure, sawBad bool
+ for _, id := range prefOrder {
+ c := CipherSuiteByID(id)
+ if c == nil {
+ t.Errorf("%#04x: no CipherSuite entry", id)
+ continue
+ }
+
+ if c.Insecure {
+ sawInsecure = true
+ } else if sawInsecure {
+ t.Errorf("%#04x: secure suite after insecure one(s)", id)
+ }
+
+ if http2isBadCipher(id) {
+ sawBad = true
+ } else if sawBad {
+ t.Errorf("%#04x: non-bad suite after bad HTTP/2 one(s)", id)
+ }
+ }
+
+ // Check that the list is sorted according to the documented criteria.
+ isBetter := func(a, b int) bool {
+ aSuite, bSuite := cipherSuiteByID(prefOrder[a]), cipherSuiteByID(prefOrder[b])
+ aName, bName := CipherSuiteName(prefOrder[a]), CipherSuiteName(prefOrder[b])
+ // * < RC4
+ if !strings.Contains(aName, "RC4") && strings.Contains(bName, "RC4") {
+ return true
+ } else if strings.Contains(aName, "RC4") && !strings.Contains(bName, "RC4") {
+ return false
+ }
+ // * < CBC_SHA256
+ if !strings.Contains(aName, "CBC_SHA256") && strings.Contains(bName, "CBC_SHA256") {
+ return true
+ } else if strings.Contains(aName, "CBC_SHA256") && !strings.Contains(bName, "CBC_SHA256") {
+ return false
+ }
+ // * < 3DES
+ if !strings.Contains(aName, "3DES") && strings.Contains(bName, "3DES") {
+ return true
+ } else if strings.Contains(aName, "3DES") && !strings.Contains(bName, "3DES") {
+ return false
+ }
+ // ECDHE < *
+ if aSuite.flags&suiteECDHE != 0 && bSuite.flags&suiteECDHE == 0 {
+ return true
+ } else if aSuite.flags&suiteECDHE == 0 && bSuite.flags&suiteECDHE != 0 {
+ return false
+ }
+ // AEAD < CBC
+ if aSuite.aead != nil && bSuite.aead == nil {
+ return true
+ } else if aSuite.aead == nil && bSuite.aead != nil {
+ return false
+ }
+ // AES < ChaCha20
+ if strings.Contains(aName, "AES") && strings.Contains(bName, "CHACHA20") {
+ return i == 0 // true for cipherSuitesPreferenceOrder
+ } else if strings.Contains(aName, "CHACHA20") && strings.Contains(bName, "AES") {
+ return i != 0 // true for cipherSuitesPreferenceOrderNoAES
+ }
+ // AES-128 < AES-256
+ if strings.Contains(aName, "AES_128") && strings.Contains(bName, "AES_256") {
+ return true
+ } else if strings.Contains(aName, "AES_256") && strings.Contains(bName, "AES_128") {
+ return false
+ }
+ // ECDSA < RSA
+ if aSuite.flags&suiteECSign != 0 && bSuite.flags&suiteECSign == 0 {
+ return true
+ } else if aSuite.flags&suiteECSign == 0 && bSuite.flags&suiteECSign != 0 {
+ return false
+ }
+ t.Fatalf("two ciphersuites are equal by all criteria: %v and %v", aName, bName)
+ panic("unreachable")
+ }
+ if !sort.SliceIsSorted(prefOrder, isBetter) {
+ t.Error("preference order is not sorted according to the rules")
+ }
+ }
+}
+
+// http2isBadCipher is copied from net/http.
+// TODO: if it ends up exposed somewhere, use that instead.
+func http2isBadCipher(cipher uint16) bool {
+ switch cipher {
+ case TLS_RSA_WITH_RC4_128_SHA,
+ TLS_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_RSA_WITH_AES_128_CBC_SHA,
+ TLS_RSA_WITH_AES_256_CBC_SHA,
+ TLS_RSA_WITH_AES_128_CBC_SHA256,
+ TLS_RSA_WITH_AES_128_GCM_SHA256,
+ TLS_RSA_WITH_AES_256_GCM_SHA384,
+ TLS_ECDHE_ECDSA_WITH_RC4_128_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_RC4_128_SHA,
+ TLS_ECDHE_RSA_WITH_3DES_EDE_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA,
+ TLS_ECDHE_RSA_WITH_AES_256_CBC_SHA,
+ TLS_ECDHE_ECDSA_WITH_AES_128_CBC_SHA256,
+ TLS_ECDHE_RSA_WITH_AES_128_CBC_SHA256:
+ return true
+ default:
+ return false
+ }
+}
+
+type brokenSigner struct{ crypto.Signer }
+
+func (s brokenSigner) Sign(rand io.Reader, digest []byte, opts crypto.SignerOpts) (signature []byte, err error) {
+ // Replace opts with opts.HashFunc(), so rsa.PSSOptions are discarded.
+ return s.Signer.Sign(rand, digest, opts.HashFunc())
+}
+
+// TestPKCS1OnlyCert uses a client certificate with a broken crypto.Signer that
+// always makes PKCS #1 v1.5 signatures, so can't be used with RSA-PSS.
+func TestPKCS1OnlyCert(t *testing.T) {
+ clientConfig := testConfig.Clone()
+ clientConfig.Certificates = []Certificate{{
+ Certificate: [][]byte{testRSACertificate},
+ PrivateKey: brokenSigner{testRSAPrivateKey},
+ }}
+ serverConfig := testConfig.Clone()
+ serverConfig.MaxVersion = VersionTLS12 // TLS 1.3 doesn't support PKCS #1 v1.5
+ serverConfig.ClientAuth = RequireAnyClientCert
+
+ // If RSA-PSS is selected, the handshake should fail.
+ if _, _, err := testHandshake(t, clientConfig, serverConfig); err == nil {
+ t.Fatal("expected broken certificate to cause connection to fail")
+ }
+
+ clientConfig.Certificates[0].SupportedSignatureAlgorithms =
+ []SignatureScheme{PKCS1WithSHA1, PKCS1WithSHA256}
+
+ // But if the certificate restricts supported algorithms, RSA-PSS should not
+ // be selected, and the handshake should succeed.
+ if _, _, err := testHandshake(t, clientConfig, serverConfig); err != nil {
+ t.Error(err)
+ }
+}
diff --git a/src/crypto/x509/boring.go b/src/crypto/x509/boring.go
new file mode 100644
index 0000000..095b58c
--- /dev/null
+++ b/src/crypto/x509/boring.go
@@ -0,0 +1,39 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto
+
+package x509
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/internal/boring/fipstls"
+ "crypto/rsa"
+)
+
+// boringAllowCert reports whether c is allowed to be used
+// in a certificate chain by the current fipstls enforcement setting.
+// It is called for each leaf, intermediate, and root certificate.
+func boringAllowCert(c *Certificate) bool {
+ if !fipstls.Required() {
+ return true
+ }
+
+ // The key must be RSA 2048, RSA 3072, RSA 4096,
+ // or ECDSA P-256, P-384, P-521.
+ switch k := c.PublicKey.(type) {
+ default:
+ return false
+ case *rsa.PublicKey:
+ if size := k.N.BitLen(); size != 2048 && size != 3072 && size != 4096 {
+ return false
+ }
+ case *ecdsa.PublicKey:
+ if k.Curve != elliptic.P256() && k.Curve != elliptic.P384() && k.Curve != elliptic.P521() {
+ return false
+ }
+ }
+ return true
+}
diff --git a/src/crypto/x509/boring_test.go b/src/crypto/x509/boring_test.go
new file mode 100644
index 0000000..33fd0ed
--- /dev/null
+++ b/src/crypto/x509/boring_test.go
@@ -0,0 +1,142 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build boringcrypto
+
+package x509
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/internal/boring/fipstls"
+ "crypto/rand"
+ "crypto/rsa"
+ "crypto/x509/pkix"
+ "fmt"
+ "math/big"
+ "strings"
+ "testing"
+ "time"
+)
+
+const (
+ boringCertCA = iota
+ boringCertLeaf
+ boringCertFIPSOK = 0x80
+)
+
+func boringRSAKey(t *testing.T, size int) *rsa.PrivateKey {
+ k, err := rsa.GenerateKey(rand.Reader, size)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return k
+}
+
+func boringECDSAKey(t *testing.T, curve elliptic.Curve) *ecdsa.PrivateKey {
+ k, err := ecdsa.GenerateKey(curve, rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ return k
+}
+
+type boringCertificate struct {
+ name string
+ org string
+ parentOrg string
+ der []byte
+ cert *Certificate
+ key interface{}
+ fipsOK bool
+}
+
+func TestBoringAllowCert(t *testing.T) {
+ R1 := testBoringCert(t, "R1", boringRSAKey(t, 2048), nil, boringCertCA|boringCertFIPSOK)
+ R2 := testBoringCert(t, "R2", boringRSAKey(t, 512), nil, boringCertCA)
+ R3 := testBoringCert(t, "R3", boringRSAKey(t, 4096), nil, boringCertCA|boringCertFIPSOK)
+
+ M1_R1 := testBoringCert(t, "M1_R1", boringECDSAKey(t, elliptic.P256()), R1, boringCertCA|boringCertFIPSOK)
+ M2_R1 := testBoringCert(t, "M2_R1", boringECDSAKey(t, elliptic.P224()), R1, boringCertCA)
+
+ I_R1 := testBoringCert(t, "I_R1", boringRSAKey(t, 3072), R1, boringCertCA|boringCertFIPSOK)
+ testBoringCert(t, "I_R2", I_R1.key, R2, boringCertCA|boringCertFIPSOK)
+ testBoringCert(t, "I_M1", I_R1.key, M1_R1, boringCertCA|boringCertFIPSOK)
+ testBoringCert(t, "I_M2", I_R1.key, M2_R1, boringCertCA|boringCertFIPSOK)
+
+ I_R3 := testBoringCert(t, "I_R3", boringRSAKey(t, 3072), R3, boringCertCA|boringCertFIPSOK)
+ testBoringCert(t, "I_R3", I_R3.key, R3, boringCertCA|boringCertFIPSOK)
+
+ testBoringCert(t, "L1_I", boringECDSAKey(t, elliptic.P384()), I_R1, boringCertLeaf|boringCertFIPSOK)
+ testBoringCert(t, "L2_I", boringRSAKey(t, 1024), I_R1, boringCertLeaf)
+}
+
+func testBoringCert(t *testing.T, name string, key interface{}, parent *boringCertificate, mode int) *boringCertificate {
+ org := name
+ parentOrg := ""
+ if i := strings.Index(org, "_"); i >= 0 {
+ org = org[:i]
+ parentOrg = name[i+1:]
+ }
+ tmpl := &Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
+ Organization: []string{org},
+ },
+ NotBefore: time.Unix(0, 0),
+ NotAfter: time.Unix(0, 0),
+
+ KeyUsage: KeyUsageKeyEncipherment | KeyUsageDigitalSignature,
+ ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth},
+ BasicConstraintsValid: true,
+ }
+ if mode&^boringCertFIPSOK == boringCertLeaf {
+ tmpl.DNSNames = []string{"example.com"}
+ } else {
+ tmpl.IsCA = true
+ tmpl.KeyUsage |= KeyUsageCertSign
+ }
+
+ var pcert *Certificate
+ var pkey interface{}
+ if parent != nil {
+ pcert = parent.cert
+ pkey = parent.key
+ } else {
+ pcert = tmpl
+ pkey = key
+ }
+
+ var pub interface{}
+ var desc string
+ switch k := key.(type) {
+ case *rsa.PrivateKey:
+ pub = &k.PublicKey
+ desc = fmt.Sprintf("RSA-%d", k.N.BitLen())
+ case *ecdsa.PrivateKey:
+ pub = &k.PublicKey
+ desc = "ECDSA-" + k.Curve.Params().Name
+ default:
+ t.Fatalf("invalid key %T", key)
+ }
+
+ der, err := CreateCertificate(rand.Reader, tmpl, pcert, pub, pkey)
+ if err != nil {
+ t.Fatal(err)
+ }
+ cert, err := ParseCertificate(der)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Tell isBoringCertificate to enforce FIPS restrictions for this check.
+ fipstls.Force()
+ defer fipstls.Abandon()
+
+ fipsOK := mode&boringCertFIPSOK != 0
+ if boringAllowCert(cert) != fipsOK {
+ t.Errorf("boringAllowCert(cert with %s key) = %v, want %v", desc, !fipsOK, fipsOK)
+ }
+ return &boringCertificate{name, org, parentOrg, der, cert, key, fipsOK}
+}
diff --git a/src/crypto/x509/cert_pool.go b/src/crypto/x509/cert_pool.go
new file mode 100644
index 0000000..e9b2c12
--- /dev/null
+++ b/src/crypto/x509/cert_pool.go
@@ -0,0 +1,268 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "bytes"
+ "crypto/sha256"
+ "encoding/pem"
+ "sync"
+)
+
+type sum224 [sha256.Size224]byte
+
+// CertPool is a set of certificates.
+type CertPool struct {
+ byName map[string][]int // cert.RawSubject => index into lazyCerts
+
+ // lazyCerts contains funcs that return a certificate,
+ // lazily parsing/decompressing it as needed.
+ lazyCerts []lazyCert
+
+ // haveSum maps from sum224(cert.Raw) to true. It's used only
+ // for AddCert duplicate detection, to avoid CertPool.contains
+ // calls in the AddCert path (because the contains method can
+ // call getCert and otherwise negate savings from lazy getCert
+ // funcs).
+ haveSum map[sum224]bool
+
+ // systemPool indicates whether this is a special pool derived from the
+ // system roots. If it includes additional roots, it requires doing two
+ // verifications, one using the roots provided by the caller, and one using
+ // the system platform verifier.
+ systemPool bool
+}
+
+// lazyCert is minimal metadata about a Cert and a func to retrieve it
+// in its normal expanded *Certificate form.
+type lazyCert struct {
+ // rawSubject is the Certificate.RawSubject value.
+ // It's the same as the CertPool.byName key, but in []byte
+ // form to make CertPool.Subjects (as used by crypto/tls) do
+ // fewer allocations.
+ rawSubject []byte
+
+ // getCert returns the certificate.
+ //
+ // It is not meant to do network operations or anything else
+ // where a failure is likely; the func is meant to lazily
+ // parse/decompress data that is already known to be good. The
+ // error in the signature primarily is meant for use in the
+ // case where a cert file existed on local disk when the program
+ // started up is deleted later before it's read.
+ getCert func() (*Certificate, error)
+}
+
+// NewCertPool returns a new, empty CertPool.
+func NewCertPool() *CertPool {
+ return &CertPool{
+ byName: make(map[string][]int),
+ haveSum: make(map[sum224]bool),
+ }
+}
+
+// len returns the number of certs in the set.
+// A nil set is a valid empty set.
+func (s *CertPool) len() int {
+ if s == nil {
+ return 0
+ }
+ return len(s.lazyCerts)
+}
+
+// cert returns cert index n in s.
+func (s *CertPool) cert(n int) (*Certificate, error) {
+ return s.lazyCerts[n].getCert()
+}
+
+// Clone returns a copy of s.
+func (s *CertPool) Clone() *CertPool {
+ p := &CertPool{
+ byName: make(map[string][]int, len(s.byName)),
+ lazyCerts: make([]lazyCert, len(s.lazyCerts)),
+ haveSum: make(map[sum224]bool, len(s.haveSum)),
+ systemPool: s.systemPool,
+ }
+ for k, v := range s.byName {
+ indexes := make([]int, len(v))
+ copy(indexes, v)
+ p.byName[k] = indexes
+ }
+ for k := range s.haveSum {
+ p.haveSum[k] = true
+ }
+ copy(p.lazyCerts, s.lazyCerts)
+ return p
+}
+
+// SystemCertPool returns a copy of the system cert pool.
+//
+// On Unix systems other than macOS the environment variables SSL_CERT_FILE and
+// SSL_CERT_DIR can be used to override the system default locations for the SSL
+// certificate file and SSL certificate files directory, respectively. The
+// latter can be a colon-separated list.
+//
+// Any mutations to the returned pool are not written to disk and do not affect
+// any other pool returned by SystemCertPool.
+//
+// New changes in the system cert pool might not be reflected in subsequent calls.
+func SystemCertPool() (*CertPool, error) {
+ if sysRoots := systemRootsPool(); sysRoots != nil {
+ return sysRoots.Clone(), nil
+ }
+
+ return loadSystemRoots()
+}
+
+// findPotentialParents returns the indexes of certificates in s which might
+// have signed cert.
+func (s *CertPool) findPotentialParents(cert *Certificate) []*Certificate {
+ if s == nil {
+ return nil
+ }
+
+ // consider all candidates where cert.Issuer matches cert.Subject.
+ // when picking possible candidates the list is built in the order
+ // of match plausibility as to save cycles in buildChains:
+ // AKID and SKID match
+ // AKID present, SKID missing / AKID missing, SKID present
+ // AKID and SKID don't match
+ var matchingKeyID, oneKeyID, mismatchKeyID []*Certificate
+ for _, c := range s.byName[string(cert.RawIssuer)] {
+ candidate, err := s.cert(c)
+ if err != nil {
+ continue
+ }
+ kidMatch := bytes.Equal(candidate.SubjectKeyId, cert.AuthorityKeyId)
+ switch {
+ case kidMatch:
+ matchingKeyID = append(matchingKeyID, candidate)
+ case (len(candidate.SubjectKeyId) == 0 && len(cert.AuthorityKeyId) > 0) ||
+ (len(candidate.SubjectKeyId) > 0 && len(cert.AuthorityKeyId) == 0):
+ oneKeyID = append(oneKeyID, candidate)
+ default:
+ mismatchKeyID = append(mismatchKeyID, candidate)
+ }
+ }
+
+ found := len(matchingKeyID) + len(oneKeyID) + len(mismatchKeyID)
+ if found == 0 {
+ return nil
+ }
+ candidates := make([]*Certificate, 0, found)
+ candidates = append(candidates, matchingKeyID...)
+ candidates = append(candidates, oneKeyID...)
+ candidates = append(candidates, mismatchKeyID...)
+ return candidates
+}
+
+func (s *CertPool) contains(cert *Certificate) bool {
+ if s == nil {
+ return false
+ }
+ return s.haveSum[sha256.Sum224(cert.Raw)]
+}
+
+// AddCert adds a certificate to a pool.
+func (s *CertPool) AddCert(cert *Certificate) {
+ if cert == nil {
+ panic("adding nil Certificate to CertPool")
+ }
+ s.addCertFunc(sha256.Sum224(cert.Raw), string(cert.RawSubject), func() (*Certificate, error) {
+ return cert, nil
+ })
+}
+
+// addCertFunc adds metadata about a certificate to a pool, along with
+// a func to fetch that certificate later when needed.
+//
+// The rawSubject is Certificate.RawSubject and must be non-empty.
+// The getCert func may be called 0 or more times.
+func (s *CertPool) addCertFunc(rawSum224 sum224, rawSubject string, getCert func() (*Certificate, error)) {
+ if getCert == nil {
+ panic("getCert can't be nil")
+ }
+
+ // Check that the certificate isn't being added twice.
+ if s.haveSum[rawSum224] {
+ return
+ }
+
+ s.haveSum[rawSum224] = true
+ s.lazyCerts = append(s.lazyCerts, lazyCert{
+ rawSubject: []byte(rawSubject),
+ getCert: getCert,
+ })
+ s.byName[rawSubject] = append(s.byName[rawSubject], len(s.lazyCerts)-1)
+}
+
+// AppendCertsFromPEM attempts to parse a series of PEM encoded certificates.
+// It appends any certificates found to s and reports whether any certificates
+// were successfully parsed.
+//
+// On many Linux systems, /etc/ssl/cert.pem will contain the system wide set
+// of root CAs in a format suitable for this function.
+func (s *CertPool) AppendCertsFromPEM(pemCerts []byte) (ok bool) {
+ for len(pemCerts) > 0 {
+ var block *pem.Block
+ block, pemCerts = pem.Decode(pemCerts)
+ if block == nil {
+ break
+ }
+ if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
+ continue
+ }
+
+ certBytes := block.Bytes
+ cert, err := ParseCertificate(certBytes)
+ if err != nil {
+ continue
+ }
+ var lazyCert struct {
+ sync.Once
+ v *Certificate
+ }
+ s.addCertFunc(sha256.Sum224(cert.Raw), string(cert.RawSubject), func() (*Certificate, error) {
+ lazyCert.Do(func() {
+ // This can't fail, as the same bytes already parsed above.
+ lazyCert.v, _ = ParseCertificate(certBytes)
+ certBytes = nil
+ })
+ return lazyCert.v, nil
+ })
+ ok = true
+ }
+
+ return ok
+}
+
+// Subjects returns a list of the DER-encoded subjects of
+// all of the certificates in the pool.
+//
+// Deprecated: if s was returned by SystemCertPool, Subjects
+// will not include the system roots.
+func (s *CertPool) Subjects() [][]byte {
+ res := make([][]byte, s.len())
+ for i, lc := range s.lazyCerts {
+ res[i] = lc.rawSubject
+ }
+ return res
+}
+
+// Equal reports whether s and other are equal.
+func (s *CertPool) Equal(other *CertPool) bool {
+ if s == nil || other == nil {
+ return s == other
+ }
+ if s.systemPool != other.systemPool || len(s.haveSum) != len(other.haveSum) {
+ return false
+ }
+ for h := range s.haveSum {
+ if !other.haveSum[h] {
+ return false
+ }
+ }
+ return true
+}
diff --git a/src/crypto/x509/cert_pool_test.go b/src/crypto/x509/cert_pool_test.go
new file mode 100644
index 0000000..a12beda
--- /dev/null
+++ b/src/crypto/x509/cert_pool_test.go
@@ -0,0 +1,108 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import "testing"
+
+func TestCertPoolEqual(t *testing.T) {
+ tc := &Certificate{Raw: []byte{1, 2, 3}, RawSubject: []byte{2}}
+ otherTC := &Certificate{Raw: []byte{9, 8, 7}, RawSubject: []byte{8}}
+
+ emptyPool := NewCertPool()
+ nonSystemPopulated := NewCertPool()
+ nonSystemPopulated.AddCert(tc)
+ nonSystemPopulatedAlt := NewCertPool()
+ nonSystemPopulatedAlt.AddCert(otherTC)
+ emptySystem, err := SystemCertPool()
+ if err != nil {
+ t.Fatal(err)
+ }
+ populatedSystem, err := SystemCertPool()
+ if err != nil {
+ t.Fatal(err)
+ }
+ populatedSystem.AddCert(tc)
+ populatedSystemAlt, err := SystemCertPool()
+ if err != nil {
+ t.Fatal(err)
+ }
+ populatedSystemAlt.AddCert(otherTC)
+ tests := []struct {
+ name string
+ a *CertPool
+ b *CertPool
+ equal bool
+ }{
+ {
+ name: "two empty pools",
+ a: emptyPool,
+ b: emptyPool,
+ equal: true,
+ },
+ {
+ name: "one empty pool, one populated pool",
+ a: emptyPool,
+ b: nonSystemPopulated,
+ equal: false,
+ },
+ {
+ name: "two populated pools",
+ a: nonSystemPopulated,
+ b: nonSystemPopulated,
+ equal: true,
+ },
+ {
+ name: "two populated pools, different content",
+ a: nonSystemPopulated,
+ b: nonSystemPopulatedAlt,
+ equal: false,
+ },
+ {
+ name: "two empty system pools",
+ a: emptySystem,
+ b: emptySystem,
+ equal: true,
+ },
+ {
+ name: "one empty system pool, one populated system pool",
+ a: emptySystem,
+ b: populatedSystem,
+ equal: false,
+ },
+ {
+ name: "two populated system pools",
+ a: populatedSystem,
+ b: populatedSystem,
+ equal: true,
+ },
+ {
+ name: "two populated pools, different content",
+ a: populatedSystem,
+ b: populatedSystemAlt,
+ equal: false,
+ },
+ {
+ name: "two nil pools",
+ a: nil,
+ b: nil,
+ equal: true,
+ },
+ {
+ name: "one nil pool, one empty pool",
+ a: nil,
+ b: emptyPool,
+ equal: false,
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ equal := tc.a.Equal(tc.b)
+ if equal != tc.equal {
+ t.Errorf("Unexpected Equal result: got %t, want %t", equal, tc.equal)
+ }
+ })
+ }
+}
diff --git a/src/crypto/x509/example_test.go b/src/crypto/x509/example_test.go
new file mode 100644
index 0000000..19d249a
--- /dev/null
+++ b/src/crypto/x509/example_test.go
@@ -0,0 +1,137 @@
+// Copyright 2014 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509_test
+
+import (
+ "crypto/dsa"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/rsa"
+ "crypto/x509"
+ "encoding/pem"
+ "fmt"
+)
+
+func ExampleCertificate_Verify() {
+ // Verifying with a custom list of root certificates.
+
+ const rootPEM = `
+-----BEGIN CERTIFICATE-----
+MIIEBDCCAuygAwIBAgIDAjppMA0GCSqGSIb3DQEBBQUAMEIxCzAJBgNVBAYTAlVT
+MRYwFAYDVQQKEw1HZW9UcnVzdCBJbmMuMRswGQYDVQQDExJHZW9UcnVzdCBHbG9i
+YWwgQ0EwHhcNMTMwNDA1MTUxNTU1WhcNMTUwNDA0MTUxNTU1WjBJMQswCQYDVQQG
+EwJVUzETMBEGA1UEChMKR29vZ2xlIEluYzElMCMGA1UEAxMcR29vZ2xlIEludGVy
+bmV0IEF1dGhvcml0eSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AJwqBHdc2FCROgajguDYUEi8iT/xGXAaiEZ+4I/F8YnOIe5a/mENtzJEiaB0C1NP
+VaTOgmKV7utZX8bhBYASxF6UP7xbSDj0U/ck5vuR6RXEz/RTDfRK/J9U3n2+oGtv
+h8DQUB8oMANA2ghzUWx//zo8pzcGjr1LEQTrfSTe5vn8MXH7lNVg8y5Kr0LSy+rE
+ahqyzFPdFUuLH8gZYR/Nnag+YyuENWllhMgZxUYi+FOVvuOAShDGKuy6lyARxzmZ
+EASg8GF6lSWMTlJ14rbtCMoU/M4iarNOz0YDl5cDfsCx3nuvRTPPuj5xt970JSXC
+DTWJnZ37DhF5iR43xa+OcmkCAwEAAaOB+zCB+DAfBgNVHSMEGDAWgBTAephojYn7
+qwVkDBF9qn1luMrMTjAdBgNVHQ4EFgQUSt0GFhu89mi1dvWBtrtiGrpagS8wEgYD
+VR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAQYwOgYDVR0fBDMwMTAvoC2g
+K4YpaHR0cDovL2NybC5nZW90cnVzdC5jb20vY3Jscy9ndGdsb2JhbC5jcmwwPQYI
+KwYBBQUHAQEEMTAvMC0GCCsGAQUFBzABhiFodHRwOi8vZ3RnbG9iYWwtb2NzcC5n
+ZW90cnVzdC5jb20wFwYDVR0gBBAwDjAMBgorBgEEAdZ5AgUBMA0GCSqGSIb3DQEB
+BQUAA4IBAQA21waAESetKhSbOHezI6B1WLuxfoNCunLaHtiONgaX4PCVOzf9G0JY
+/iLIa704XtE7JW4S615ndkZAkNoUyHgN7ZVm2o6Gb4ChulYylYbc3GrKBIxbf/a/
+zG+FA1jDaFETzf3I93k9mTXwVqO94FntT0QJo544evZG0R0SnU++0ED8Vf4GXjza
+HFa9llF7b1cq26KqltyMdMKVvvBulRP/F/A8rLIQjcxz++iPAsbw+zOzlTvjwsto
+WHPbqCRiOwY1nQ2pM714A5AuTHhdUDqB1O6gyHA43LL5Z/qHQF1hwFGPa4NrzQU6
+yuGnBXj8ytqU0CwIPX4WecigUCAkVDNx
+-----END CERTIFICATE-----`
+
+ const certPEM = `
+-----BEGIN CERTIFICATE-----
+MIIDujCCAqKgAwIBAgIIE31FZVaPXTUwDQYJKoZIhvcNAQEFBQAwSTELMAkGA1UE
+BhMCVVMxEzARBgNVBAoTCkdvb2dsZSBJbmMxJTAjBgNVBAMTHEdvb2dsZSBJbnRl
+cm5ldCBBdXRob3JpdHkgRzIwHhcNMTQwMTI5MTMyNzQzWhcNMTQwNTI5MDAwMDAw
+WjBpMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwN
+TW91bnRhaW4gVmlldzETMBEGA1UECgwKR29vZ2xlIEluYzEYMBYGA1UEAwwPbWFp
+bC5nb29nbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAEfRrObuSW5T7q
+5CnSEqefEmtH4CCv6+5EckuriNr1CjfVvqzwfAhopXkLrq45EQm8vkmf7W96XJhC
+7ZM0dYi1/qOCAU8wggFLMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAa
+BgNVHREEEzARgg9tYWlsLmdvb2dsZS5jb20wCwYDVR0PBAQDAgeAMGgGCCsGAQUF
+BwEBBFwwWjArBggrBgEFBQcwAoYfaHR0cDovL3BraS5nb29nbGUuY29tL0dJQUcy
+LmNydDArBggrBgEFBQcwAYYfaHR0cDovL2NsaWVudHMxLmdvb2dsZS5jb20vb2Nz
+cDAdBgNVHQ4EFgQUiJxtimAuTfwb+aUtBn5UYKreKvMwDAYDVR0TAQH/BAIwADAf
+BgNVHSMEGDAWgBRK3QYWG7z2aLV29YG2u2IaulqBLzAXBgNVHSAEEDAOMAwGCisG
+AQQB1nkCBQEwMAYDVR0fBCkwJzAloCOgIYYfaHR0cDovL3BraS5nb29nbGUuY29t
+L0dJQUcyLmNybDANBgkqhkiG9w0BAQUFAAOCAQEAH6RYHxHdcGpMpFE3oxDoFnP+
+gtuBCHan2yE2GRbJ2Cw8Lw0MmuKqHlf9RSeYfd3BXeKkj1qO6TVKwCh+0HdZk283
+TZZyzmEOyclm3UGFYe82P/iDFt+CeQ3NpmBg+GoaVCuWAARJN/KfglbLyyYygcQq
+0SgeDh8dRKUiaW3HQSoYvTvdTuqzwK4CXsr3b5/dAOY8uMuG/IAR3FgwTbZ1dtoW
+RvOTa8hYiU6A475WuZKyEHcwnGYe57u2I2KbMgcKjPniocj4QzgYsVAVKW3IwaOh
+yE+vPxsiUkvQHdO2fojCkY8jg70jxM+gu59tPDNbw3Uh/2Ij310FgTHsnGQMyA==
+-----END CERTIFICATE-----`
+
+ // First, create the set of root certificates. For this example we only
+ // have one. It's also possible to omit this in order to use the
+ // default root set of the current operating system.
+ roots := x509.NewCertPool()
+ ok := roots.AppendCertsFromPEM([]byte(rootPEM))
+ if !ok {
+ panic("failed to parse root certificate")
+ }
+
+ block, _ := pem.Decode([]byte(certPEM))
+ if block == nil {
+ panic("failed to parse certificate PEM")
+ }
+ cert, err := x509.ParseCertificate(block.Bytes)
+ if err != nil {
+ panic("failed to parse certificate: " + err.Error())
+ }
+
+ opts := x509.VerifyOptions{
+ DNSName: "mail.google.com",
+ Roots: roots,
+ }
+
+ if _, err := cert.Verify(opts); err != nil {
+ panic("failed to verify certificate: " + err.Error())
+ }
+}
+
+func ExampleParsePKIXPublicKey() {
+ const pubPEM = `
+-----BEGIN PUBLIC KEY-----
+MIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAlRuRnThUjU8/prwYxbty
+WPT9pURI3lbsKMiB6Fn/VHOKE13p4D8xgOCADpdRagdT6n4etr9atzDKUSvpMtR3
+CP5noNc97WiNCggBjVWhs7szEe8ugyqF23XwpHQ6uV1LKH50m92MbOWfCtjU9p/x
+qhNpQQ1AZhqNy5Gevap5k8XzRmjSldNAFZMY7Yv3Gi+nyCwGwpVtBUwhuLzgNFK/
+yDtw2WcWmUU7NuC8Q6MWvPebxVtCfVp/iQU6q60yyt6aGOBkhAX0LpKAEhKidixY
+nP9PNVBvxgu3XZ4P36gZV6+ummKdBVnc3NqwBLu5+CcdRdusmHPHd5pHf4/38Z3/
+6qU2a/fPvWzceVTEgZ47QjFMTCTmCwNt29cvi7zZeQzjtwQgn4ipN9NibRH/Ax/q
+TbIzHfrJ1xa2RteWSdFjwtxi9C20HUkjXSeI4YlzQMH0fPX6KCE7aVePTOnB69I/
+a9/q96DiXZajwlpq3wFctrs1oXqBp5DVrCIj8hU2wNgB7LtQ1mCtsYz//heai0K9
+PhE4X6hiE0YmeAZjR0uHl8M/5aW9xCoJ72+12kKpWAa0SFRWLy6FejNYCYpkupVJ
+yecLk/4L1W0l6jQQZnWErXZYe0PNFcmwGXy1Rep83kfBRNKRy5tvocalLlwXLdUk
+AIU+2GKjyT3iMuzZxxFxPFMCAwEAAQ==
+-----END PUBLIC KEY-----`
+
+ block, _ := pem.Decode([]byte(pubPEM))
+ if block == nil {
+ panic("failed to parse PEM block containing the public key")
+ }
+
+ pub, err := x509.ParsePKIXPublicKey(block.Bytes)
+ if err != nil {
+ panic("failed to parse DER encoded public key: " + err.Error())
+ }
+
+ switch pub := pub.(type) {
+ case *rsa.PublicKey:
+ fmt.Println("pub is of type RSA:", pub)
+ case *dsa.PublicKey:
+ fmt.Println("pub is of type DSA:", pub)
+ case *ecdsa.PublicKey:
+ fmt.Println("pub is of type ECDSA:", pub)
+ case ed25519.PublicKey:
+ fmt.Println("pub is of type Ed25519:", pub)
+ default:
+ panic("unknown type of public key")
+ }
+}
diff --git a/src/crypto/x509/hybrid_pool_test.go b/src/crypto/x509/hybrid_pool_test.go
new file mode 100644
index 0000000..2b8eb62
--- /dev/null
+++ b/src/crypto/x509/hybrid_pool_test.go
@@ -0,0 +1,123 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509_test
+
+import (
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/tls"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "internal/testenv"
+ "math/big"
+ "runtime"
+ "testing"
+ "time"
+)
+
+func TestHybridPool(t *testing.T) {
+ t.Parallel()
+ if !(runtime.GOOS == "windows" || runtime.GOOS == "darwin" || runtime.GOOS == "ios") {
+ t.Skipf("platform verifier not available on %s", runtime.GOOS)
+ }
+ if !testenv.HasExternalNetwork() {
+ t.Skip()
+ }
+ if runtime.GOOS == "windows" {
+ // NOTE(#51599): on the Windows builders we sometimes see that the state
+ // of the root pool is not fully initialized, causing an expected
+ // platform verification to fail. In part this is because Windows
+ // dynamically populates roots into its local trust store at time of
+ // use. We can attempt to prime the pool by attempting TLS connections
+ // to google.com until it works, suggesting the pool has been properly
+ // updated. If after we hit the dealine, the pool has _still_ not been
+ // populated with the expected root, it's unlikely we are ever going to
+ // get into a good state, and so we just fail the test. #52108 suggests
+ // a better possible long term solution.
+
+ deadline := time.Now().Add(time.Second * 10)
+ nextSleep := 10 * time.Millisecond
+ for i := 0; ; i++ {
+ c, err := tls.Dial("tcp", "google.com:443", nil)
+ if err == nil {
+ c.Close()
+ break
+ }
+ nextSleep = nextSleep * time.Duration(i)
+ if time.Until(deadline) < nextSleep {
+ t.Fatal("windows root pool appears to be in an uninitialized state (missing root that chains to google.com)")
+ }
+ time.Sleep(nextSleep)
+ }
+ }
+
+ // Get the google.com chain, which should be valid on all platforms we
+ // are testing
+ c, err := tls.Dial("tcp", "google.com:443", &tls.Config{InsecureSkipVerify: true})
+ if err != nil {
+ t.Fatalf("tls connection failed: %s", err)
+ }
+ googChain := c.ConnectionState().PeerCertificates
+
+ rootTmpl := &x509.Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{CommonName: "Go test root"},
+ IsCA: true,
+ BasicConstraintsValid: true,
+ NotBefore: time.Now().Add(-time.Hour),
+ NotAfter: time.Now().Add(time.Hour * 10),
+ }
+ k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatalf("failed to generate test key: %s", err)
+ }
+ rootDER, err := x509.CreateCertificate(rand.Reader, rootTmpl, rootTmpl, k.Public(), k)
+ if err != nil {
+ t.Fatalf("failed to create test cert: %s", err)
+ }
+ root, err := x509.ParseCertificate(rootDER)
+ if err != nil {
+ t.Fatalf("failed to parse test cert: %s", err)
+ }
+
+ pool, err := x509.SystemCertPool()
+ if err != nil {
+ t.Fatalf("SystemCertPool failed: %s", err)
+ }
+ opts := x509.VerifyOptions{Roots: pool}
+
+ _, err = googChain[0].Verify(opts)
+ if err != nil {
+ t.Fatalf("verification failed for google.com chain (system only pool): %s", err)
+ }
+
+ pool.AddCert(root)
+
+ _, err = googChain[0].Verify(opts)
+ if err != nil {
+ t.Fatalf("verification failed for google.com chain (hybrid pool): %s", err)
+ }
+
+ certTmpl := &x509.Certificate{
+ SerialNumber: big.NewInt(1),
+ NotBefore: time.Now().Add(-time.Hour),
+ NotAfter: time.Now().Add(time.Hour * 10),
+ DNSNames: []string{"example.com"},
+ }
+ certDER, err := x509.CreateCertificate(rand.Reader, certTmpl, rootTmpl, k.Public(), k)
+ if err != nil {
+ t.Fatalf("failed to create test cert: %s", err)
+ }
+ cert, err := x509.ParseCertificate(certDER)
+ if err != nil {
+ t.Fatalf("failed to parse test cert: %s", err)
+ }
+
+ _, err = cert.Verify(opts)
+ if err != nil {
+ t.Fatalf("verification failed for custom chain (hybrid pool): %s", err)
+ }
+}
diff --git a/src/crypto/x509/internal/macos/corefoundation.go b/src/crypto/x509/internal/macos/corefoundation.go
new file mode 100644
index 0000000..b4032a5
--- /dev/null
+++ b/src/crypto/x509/internal/macos/corefoundation.go
@@ -0,0 +1,219 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build darwin
+
+// Package macOS provides cgo-less wrappers for Core Foundation and
+// Security.framework, similarly to how package syscall provides access to
+// libSystem.dylib.
+package macOS
+
+import (
+ "bytes"
+ "errors"
+ "internal/abi"
+ "runtime"
+ "time"
+ "unsafe"
+)
+
+// Core Foundation linker flags for the external linker. See Issue 42459.
+//
+//go:cgo_ldflag "-framework"
+//go:cgo_ldflag "CoreFoundation"
+
+// CFRef is an opaque reference to a Core Foundation object. It is a pointer,
+// but to memory not owned by Go, so not an unsafe.Pointer.
+type CFRef uintptr
+
+// CFDataToSlice returns a copy of the contents of data as a bytes slice.
+func CFDataToSlice(data CFRef) []byte {
+ length := CFDataGetLength(data)
+ ptr := CFDataGetBytePtr(data)
+ src := unsafe.Slice((*byte)(unsafe.Pointer(ptr)), length)
+ return bytes.Clone(src)
+}
+
+// CFStringToString returns a Go string representation of the passed
+// in CFString, or an empty string if it's invalid.
+func CFStringToString(ref CFRef) string {
+ data, err := CFStringCreateExternalRepresentation(ref)
+ if err != nil {
+ return ""
+ }
+ b := CFDataToSlice(data)
+ CFRelease(data)
+ return string(b)
+}
+
+// TimeToCFDateRef converts a time.Time into an apple CFDateRef.
+func TimeToCFDateRef(t time.Time) CFRef {
+ secs := t.Sub(time.Date(2001, 1, 1, 0, 0, 0, 0, time.UTC)).Seconds()
+ ref := CFDateCreate(secs)
+ return ref
+}
+
+type CFString CFRef
+
+const kCFAllocatorDefault = 0
+const kCFStringEncodingUTF8 = 0x08000100
+
+//go:cgo_import_dynamic x509_CFDataCreate CFDataCreate "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func BytesToCFData(b []byte) CFRef {
+ p := unsafe.Pointer(unsafe.SliceData(b))
+ ret := syscall(abi.FuncPCABI0(x509_CFDataCreate_trampoline), kCFAllocatorDefault, uintptr(p), uintptr(len(b)), 0, 0, 0)
+ runtime.KeepAlive(p)
+ return CFRef(ret)
+}
+func x509_CFDataCreate_trampoline()
+
+//go:cgo_import_dynamic x509_CFStringCreateWithBytes CFStringCreateWithBytes "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+// StringToCFString returns a copy of the UTF-8 contents of s as a new CFString.
+func StringToCFString(s string) CFString {
+ p := unsafe.Pointer(unsafe.StringData(s))
+ ret := syscall(abi.FuncPCABI0(x509_CFStringCreateWithBytes_trampoline), kCFAllocatorDefault, uintptr(p),
+ uintptr(len(s)), uintptr(kCFStringEncodingUTF8), 0 /* isExternalRepresentation */, 0)
+ runtime.KeepAlive(p)
+ return CFString(ret)
+}
+func x509_CFStringCreateWithBytes_trampoline()
+
+//go:cgo_import_dynamic x509_CFDictionaryGetValueIfPresent CFDictionaryGetValueIfPresent "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFDictionaryGetValueIfPresent(dict CFRef, key CFString) (value CFRef, ok bool) {
+ ret := syscall(abi.FuncPCABI0(x509_CFDictionaryGetValueIfPresent_trampoline), uintptr(dict), uintptr(key),
+ uintptr(unsafe.Pointer(&value)), 0, 0, 0)
+ if ret == 0 {
+ return 0, false
+ }
+ return value, true
+}
+func x509_CFDictionaryGetValueIfPresent_trampoline()
+
+const kCFNumberSInt32Type = 3
+
+//go:cgo_import_dynamic x509_CFNumberGetValue CFNumberGetValue "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFNumberGetValue(num CFRef) (int32, error) {
+ var value int32
+ ret := syscall(abi.FuncPCABI0(x509_CFNumberGetValue_trampoline), uintptr(num), uintptr(kCFNumberSInt32Type),
+ uintptr(unsafe.Pointer(&value)), 0, 0, 0)
+ if ret == 0 {
+ return 0, errors.New("CFNumberGetValue call failed")
+ }
+ return value, nil
+}
+func x509_CFNumberGetValue_trampoline()
+
+//go:cgo_import_dynamic x509_CFDataGetLength CFDataGetLength "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFDataGetLength(data CFRef) int {
+ ret := syscall(abi.FuncPCABI0(x509_CFDataGetLength_trampoline), uintptr(data), 0, 0, 0, 0, 0)
+ return int(ret)
+}
+func x509_CFDataGetLength_trampoline()
+
+//go:cgo_import_dynamic x509_CFDataGetBytePtr CFDataGetBytePtr "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFDataGetBytePtr(data CFRef) uintptr {
+ ret := syscall(abi.FuncPCABI0(x509_CFDataGetBytePtr_trampoline), uintptr(data), 0, 0, 0, 0, 0)
+ return ret
+}
+func x509_CFDataGetBytePtr_trampoline()
+
+//go:cgo_import_dynamic x509_CFArrayGetCount CFArrayGetCount "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFArrayGetCount(array CFRef) int {
+ ret := syscall(abi.FuncPCABI0(x509_CFArrayGetCount_trampoline), uintptr(array), 0, 0, 0, 0, 0)
+ return int(ret)
+}
+func x509_CFArrayGetCount_trampoline()
+
+//go:cgo_import_dynamic x509_CFArrayGetValueAtIndex CFArrayGetValueAtIndex "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFArrayGetValueAtIndex(array CFRef, index int) CFRef {
+ ret := syscall(abi.FuncPCABI0(x509_CFArrayGetValueAtIndex_trampoline), uintptr(array), uintptr(index), 0, 0, 0, 0)
+ return CFRef(ret)
+}
+func x509_CFArrayGetValueAtIndex_trampoline()
+
+//go:cgo_import_dynamic x509_CFEqual CFEqual "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFEqual(a, b CFRef) bool {
+ ret := syscall(abi.FuncPCABI0(x509_CFEqual_trampoline), uintptr(a), uintptr(b), 0, 0, 0, 0)
+ return ret == 1
+}
+func x509_CFEqual_trampoline()
+
+//go:cgo_import_dynamic x509_CFRelease CFRelease "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFRelease(ref CFRef) {
+ syscall(abi.FuncPCABI0(x509_CFRelease_trampoline), uintptr(ref), 0, 0, 0, 0, 0)
+}
+func x509_CFRelease_trampoline()
+
+//go:cgo_import_dynamic x509_CFArrayCreateMutable CFArrayCreateMutable "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFArrayCreateMutable() CFRef {
+ ret := syscall(abi.FuncPCABI0(x509_CFArrayCreateMutable_trampoline), kCFAllocatorDefault, 0, 0 /* kCFTypeArrayCallBacks */, 0, 0, 0)
+ return CFRef(ret)
+}
+func x509_CFArrayCreateMutable_trampoline()
+
+//go:cgo_import_dynamic x509_CFArrayAppendValue CFArrayAppendValue "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFArrayAppendValue(array CFRef, val CFRef) {
+ syscall(abi.FuncPCABI0(x509_CFArrayAppendValue_trampoline), uintptr(array), uintptr(val), 0, 0, 0, 0)
+}
+func x509_CFArrayAppendValue_trampoline()
+
+//go:cgo_import_dynamic x509_CFDateCreate CFDateCreate "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFDateCreate(seconds float64) CFRef {
+ ret := syscall(abi.FuncPCABI0(x509_CFDateCreate_trampoline), kCFAllocatorDefault, 0, 0, 0, 0, seconds)
+ return CFRef(ret)
+}
+func x509_CFDateCreate_trampoline()
+
+//go:cgo_import_dynamic x509_CFErrorCopyDescription CFErrorCopyDescription "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFErrorCopyDescription(errRef CFRef) CFRef {
+ ret := syscall(abi.FuncPCABI0(x509_CFErrorCopyDescription_trampoline), uintptr(errRef), 0, 0, 0, 0, 0)
+ return CFRef(ret)
+}
+func x509_CFErrorCopyDescription_trampoline()
+
+//go:cgo_import_dynamic x509_CFErrorGetCode CFErrorGetCode "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFErrorGetCode(errRef CFRef) int {
+ return int(syscall(abi.FuncPCABI0(x509_CFErrorGetCode_trampoline), uintptr(errRef), 0, 0, 0, 0, 0))
+}
+func x509_CFErrorGetCode_trampoline()
+
+//go:cgo_import_dynamic x509_CFStringCreateExternalRepresentation CFStringCreateExternalRepresentation "/System/Library/Frameworks/CoreFoundation.framework/Versions/A/CoreFoundation"
+
+func CFStringCreateExternalRepresentation(strRef CFRef) (CFRef, error) {
+ ret := syscall(abi.FuncPCABI0(x509_CFStringCreateExternalRepresentation_trampoline), kCFAllocatorDefault, uintptr(strRef), kCFStringEncodingUTF8, 0, 0, 0)
+ if ret == 0 {
+ return 0, errors.New("string can't be represented as UTF-8")
+ }
+ return CFRef(ret), nil
+}
+func x509_CFStringCreateExternalRepresentation_trampoline()
+
+// syscall is implemented in the runtime package (runtime/sys_darwin.go)
+func syscall(fn, a1, a2, a3, a4, a5 uintptr, f1 float64) uintptr
+
+// ReleaseCFArray iterates through an array, releasing its contents, and then
+// releases the array itself. This is necessary because we cannot, easily, set the
+// CFArrayCallBacks argument when creating CFArrays.
+func ReleaseCFArray(array CFRef) {
+ for i := 0; i < CFArrayGetCount(array); i++ {
+ ref := CFArrayGetValueAtIndex(array, i)
+ CFRelease(ref)
+ }
+ CFRelease(array)
+}
diff --git a/src/crypto/x509/internal/macos/corefoundation.s b/src/crypto/x509/internal/macos/corefoundation.s
new file mode 100644
index 0000000..49cd084
--- /dev/null
+++ b/src/crypto/x509/internal/macos/corefoundation.s
@@ -0,0 +1,43 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build darwin
+
+#include "textflag.h"
+
+// The trampolines are ABIInternal as they are address-taken in
+// Go code.
+
+TEXT ·x509_CFArrayGetCount_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFArrayGetCount(SB)
+TEXT ·x509_CFArrayGetValueAtIndex_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFArrayGetValueAtIndex(SB)
+TEXT ·x509_CFDataGetBytePtr_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFDataGetBytePtr(SB)
+TEXT ·x509_CFDataGetLength_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFDataGetLength(SB)
+TEXT ·x509_CFStringCreateWithBytes_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFStringCreateWithBytes(SB)
+TEXT ·x509_CFRelease_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFRelease(SB)
+TEXT ·x509_CFDictionaryGetValueIfPresent_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFDictionaryGetValueIfPresent(SB)
+TEXT ·x509_CFNumberGetValue_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFNumberGetValue(SB)
+TEXT ·x509_CFEqual_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFEqual(SB)
+TEXT ·x509_CFArrayCreateMutable_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFArrayCreateMutable(SB)
+TEXT ·x509_CFArrayAppendValue_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFArrayAppendValue(SB)
+TEXT ·x509_CFDateCreate_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFDateCreate(SB)
+TEXT ·x509_CFDataCreate_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFDataCreate(SB)
+TEXT ·x509_CFErrorCopyDescription_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFErrorCopyDescription(SB)
+TEXT ·x509_CFErrorGetCode_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFErrorGetCode(SB)
+TEXT ·x509_CFStringCreateExternalRepresentation_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_CFStringCreateExternalRepresentation(SB)
diff --git a/src/crypto/x509/internal/macos/security.go b/src/crypto/x509/internal/macos/security.go
new file mode 100644
index 0000000..a6972c0
--- /dev/null
+++ b/src/crypto/x509/internal/macos/security.go
@@ -0,0 +1,247 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build darwin
+
+package macOS
+
+import (
+ "errors"
+ "internal/abi"
+ "strconv"
+ "unsafe"
+)
+
+// Security.framework linker flags for the external linker. See Issue 42459.
+//
+//go:cgo_ldflag "-framework"
+//go:cgo_ldflag "Security"
+
+// Based on https://opensource.apple.com/source/Security/Security-59306.41.2/base/Security.h
+
+type SecTrustSettingsResult int32
+
+const (
+ SecTrustSettingsResultInvalid SecTrustSettingsResult = iota
+ SecTrustSettingsResultTrustRoot
+ SecTrustSettingsResultTrustAsRoot
+ SecTrustSettingsResultDeny
+ SecTrustSettingsResultUnspecified
+)
+
+type SecTrustResultType int32
+
+const (
+ SecTrustResultInvalid SecTrustResultType = iota
+ SecTrustResultProceed
+ SecTrustResultConfirm // deprecated
+ SecTrustResultDeny
+ SecTrustResultUnspecified
+ SecTrustResultRecoverableTrustFailure
+ SecTrustResultFatalTrustFailure
+ SecTrustResultOtherError
+)
+
+type SecTrustSettingsDomain int32
+
+const (
+ SecTrustSettingsDomainUser SecTrustSettingsDomain = iota
+ SecTrustSettingsDomainAdmin
+ SecTrustSettingsDomainSystem
+)
+
+const (
+ // various macOS error codes that can be returned from
+ // SecTrustEvaluateWithError that we can map to Go cert
+ // verification error types.
+ ErrSecCertificateExpired = -67818
+ ErrSecHostNameMismatch = -67602
+ ErrSecNotTrusted = -67843
+)
+
+type OSStatus struct {
+ call string
+ status int32
+}
+
+func (s OSStatus) Error() string {
+ return s.call + " error: " + strconv.Itoa(int(s.status))
+}
+
+// Dictionary keys are defined as build-time strings with CFSTR, but the Go
+// linker's internal linking mode can't handle CFSTR relocations. Create our
+// own dynamic strings instead and just never release them.
+//
+// Note that this might be the only thing that can break over time if
+// these values change, as the ABI arguably requires using the strings
+// pointed to by the symbols, not values that happen to be equal to them.
+
+var SecTrustSettingsResultKey = StringToCFString("kSecTrustSettingsResult")
+var SecTrustSettingsPolicy = StringToCFString("kSecTrustSettingsPolicy")
+var SecTrustSettingsPolicyString = StringToCFString("kSecTrustSettingsPolicyString")
+var SecPolicyOid = StringToCFString("SecPolicyOid")
+var SecPolicyAppleSSL = StringToCFString("1.2.840.113635.100.1.3") // defined by POLICYMACRO
+
+var ErrNoTrustSettings = errors.New("no trust settings found")
+
+const errSecNoTrustSettings = -25263
+
+//go:cgo_import_dynamic x509_SecTrustSettingsCopyCertificates SecTrustSettingsCopyCertificates "/System/Library/Frameworks/Security.framework/Versions/A/Security"
+
+func SecTrustSettingsCopyCertificates(domain SecTrustSettingsDomain) (certArray CFRef, err error) {
+ ret := syscall(abi.FuncPCABI0(x509_SecTrustSettingsCopyCertificates_trampoline), uintptr(domain),
+ uintptr(unsafe.Pointer(&certArray)), 0, 0, 0, 0)
+ if int32(ret) == errSecNoTrustSettings {
+ return 0, ErrNoTrustSettings
+ } else if ret != 0 {
+ return 0, OSStatus{"SecTrustSettingsCopyCertificates", int32(ret)}
+ }
+ return certArray, nil
+}
+func x509_SecTrustSettingsCopyCertificates_trampoline()
+
+const errSecItemNotFound = -25300
+
+//go:cgo_import_dynamic x509_SecTrustSettingsCopyTrustSettings SecTrustSettingsCopyTrustSettings "/System/Library/Frameworks/Security.framework/Versions/A/Security"
+
+func SecTrustSettingsCopyTrustSettings(cert CFRef, domain SecTrustSettingsDomain) (trustSettings CFRef, err error) {
+ ret := syscall(abi.FuncPCABI0(x509_SecTrustSettingsCopyTrustSettings_trampoline), uintptr(cert), uintptr(domain),
+ uintptr(unsafe.Pointer(&trustSettings)), 0, 0, 0)
+ if int32(ret) == errSecItemNotFound {
+ return 0, ErrNoTrustSettings
+ } else if ret != 0 {
+ return 0, OSStatus{"SecTrustSettingsCopyTrustSettings", int32(ret)}
+ }
+ return trustSettings, nil
+}
+func x509_SecTrustSettingsCopyTrustSettings_trampoline()
+
+//go:cgo_import_dynamic x509_SecTrustCreateWithCertificates SecTrustCreateWithCertificates "/System/Library/Frameworks/Security.framework/Versions/A/Security"
+
+func SecTrustCreateWithCertificates(certs CFRef, policies CFRef) (CFRef, error) {
+ var trustObj CFRef
+ ret := syscall(abi.FuncPCABI0(x509_SecTrustCreateWithCertificates_trampoline), uintptr(certs), uintptr(policies),
+ uintptr(unsafe.Pointer(&trustObj)), 0, 0, 0)
+ if int32(ret) != 0 {
+ return 0, OSStatus{"SecTrustCreateWithCertificates", int32(ret)}
+ }
+ return trustObj, nil
+}
+func x509_SecTrustCreateWithCertificates_trampoline()
+
+//go:cgo_import_dynamic x509_SecCertificateCreateWithData SecCertificateCreateWithData "/System/Library/Frameworks/Security.framework/Versions/A/Security"
+
+func SecCertificateCreateWithData(b []byte) (CFRef, error) {
+ data := BytesToCFData(b)
+ defer CFRelease(data)
+ ret := syscall(abi.FuncPCABI0(x509_SecCertificateCreateWithData_trampoline), kCFAllocatorDefault, uintptr(data), 0, 0, 0, 0)
+ // Returns NULL if the data passed in the data parameter is not a valid
+ // DER-encoded X.509 certificate.
+ if ret == 0 {
+ return 0, errors.New("SecCertificateCreateWithData: invalid certificate")
+ }
+ return CFRef(ret), nil
+}
+func x509_SecCertificateCreateWithData_trampoline()
+
+//go:cgo_import_dynamic x509_SecPolicyCreateSSL SecPolicyCreateSSL "/System/Library/Frameworks/Security.framework/Versions/A/Security"
+
+func SecPolicyCreateSSL(name string) (CFRef, error) {
+ var hostname CFString
+ if name != "" {
+ hostname = StringToCFString(name)
+ defer CFRelease(CFRef(hostname))
+ }
+ ret := syscall(abi.FuncPCABI0(x509_SecPolicyCreateSSL_trampoline), 1 /* true */, uintptr(hostname), 0, 0, 0, 0)
+ if ret == 0 {
+ return 0, OSStatus{"SecPolicyCreateSSL", int32(ret)}
+ }
+ return CFRef(ret), nil
+}
+func x509_SecPolicyCreateSSL_trampoline()
+
+//go:cgo_import_dynamic x509_SecTrustSetVerifyDate SecTrustSetVerifyDate "/System/Library/Frameworks/Security.framework/Versions/A/Security"
+
+func SecTrustSetVerifyDate(trustObj CFRef, dateRef CFRef) error {
+ ret := syscall(abi.FuncPCABI0(x509_SecTrustSetVerifyDate_trampoline), uintptr(trustObj), uintptr(dateRef), 0, 0, 0, 0)
+ if int32(ret) != 0 {
+ return OSStatus{"SecTrustSetVerifyDate", int32(ret)}
+ }
+ return nil
+}
+func x509_SecTrustSetVerifyDate_trampoline()
+
+//go:cgo_import_dynamic x509_SecTrustEvaluate SecTrustEvaluate "/System/Library/Frameworks/Security.framework/Versions/A/Security"
+
+func SecTrustEvaluate(trustObj CFRef) (CFRef, error) {
+ var result CFRef
+ ret := syscall(abi.FuncPCABI0(x509_SecTrustEvaluate_trampoline), uintptr(trustObj), uintptr(unsafe.Pointer(&result)), 0, 0, 0, 0)
+ if int32(ret) != 0 {
+ return 0, OSStatus{"SecTrustEvaluate", int32(ret)}
+ }
+ return CFRef(result), nil
+}
+func x509_SecTrustEvaluate_trampoline()
+
+//go:cgo_import_dynamic x509_SecTrustGetResult SecTrustGetResult "/System/Library/Frameworks/Security.framework/Versions/A/Security"
+
+func SecTrustGetResult(trustObj CFRef, result CFRef) (CFRef, CFRef, error) {
+ var chain, info CFRef
+ ret := syscall(abi.FuncPCABI0(x509_SecTrustGetResult_trampoline), uintptr(trustObj), uintptr(unsafe.Pointer(&result)),
+ uintptr(unsafe.Pointer(&chain)), uintptr(unsafe.Pointer(&info)), 0, 0)
+ if int32(ret) != 0 {
+ return 0, 0, OSStatus{"SecTrustGetResult", int32(ret)}
+ }
+ return chain, info, nil
+}
+func x509_SecTrustGetResult_trampoline()
+
+//go:cgo_import_dynamic x509_SecTrustEvaluateWithError SecTrustEvaluateWithError "/System/Library/Frameworks/Security.framework/Versions/A/Security"
+
+func SecTrustEvaluateWithError(trustObj CFRef) (int, error) {
+ var errRef CFRef
+ ret := syscall(abi.FuncPCABI0(x509_SecTrustEvaluateWithError_trampoline), uintptr(trustObj), uintptr(unsafe.Pointer(&errRef)), 0, 0, 0, 0)
+ if int32(ret) != 1 {
+ errStr := CFErrorCopyDescription(errRef)
+ err := errors.New(CFStringToString(errStr))
+ errCode := CFErrorGetCode(errRef)
+ CFRelease(errRef)
+ CFRelease(errStr)
+ return errCode, err
+ }
+ return 0, nil
+}
+func x509_SecTrustEvaluateWithError_trampoline()
+
+//go:cgo_import_dynamic x509_SecTrustGetCertificateCount SecTrustGetCertificateCount "/System/Library/Frameworks/Security.framework/Versions/A/Security"
+
+func SecTrustGetCertificateCount(trustObj CFRef) int {
+ ret := syscall(abi.FuncPCABI0(x509_SecTrustGetCertificateCount_trampoline), uintptr(trustObj), 0, 0, 0, 0, 0)
+ return int(ret)
+}
+func x509_SecTrustGetCertificateCount_trampoline()
+
+//go:cgo_import_dynamic x509_SecTrustGetCertificateAtIndex SecTrustGetCertificateAtIndex "/System/Library/Frameworks/Security.framework/Versions/A/Security"
+
+func SecTrustGetCertificateAtIndex(trustObj CFRef, i int) (CFRef, error) {
+ ret := syscall(abi.FuncPCABI0(x509_SecTrustGetCertificateAtIndex_trampoline), uintptr(trustObj), uintptr(i), 0, 0, 0, 0)
+ if ret == 0 {
+ return 0, OSStatus{"SecTrustGetCertificateAtIndex", int32(ret)}
+ }
+ return CFRef(ret), nil
+}
+func x509_SecTrustGetCertificateAtIndex_trampoline()
+
+//go:cgo_import_dynamic x509_SecCertificateCopyData SecCertificateCopyData "/System/Library/Frameworks/Security.framework/Versions/A/Security"
+
+func SecCertificateCopyData(cert CFRef) ([]byte, error) {
+ ret := syscall(abi.FuncPCABI0(x509_SecCertificateCopyData_trampoline), uintptr(cert), 0, 0, 0, 0, 0)
+ if ret == 0 {
+ return nil, errors.New("x509: invalid certificate object")
+ }
+ b := CFDataToSlice(CFRef(ret))
+ CFRelease(CFRef(ret))
+ return b, nil
+}
+func x509_SecCertificateCopyData_trampoline()
diff --git a/src/crypto/x509/internal/macos/security.s b/src/crypto/x509/internal/macos/security.s
new file mode 100644
index 0000000..ed726f1
--- /dev/null
+++ b/src/crypto/x509/internal/macos/security.s
@@ -0,0 +1,35 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build darwin
+
+#include "textflag.h"
+
+// The trampolines are ABIInternal as they are address-taken in
+// Go code.
+
+TEXT ·x509_SecTrustSettingsCopyCertificates_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_SecTrustSettingsCopyCertificates(SB)
+TEXT ·x509_SecTrustSettingsCopyTrustSettings_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_SecTrustSettingsCopyTrustSettings(SB)
+TEXT ·x509_SecTrustCreateWithCertificates_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_SecTrustCreateWithCertificates(SB)
+TEXT ·x509_SecCertificateCreateWithData_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_SecCertificateCreateWithData(SB)
+TEXT ·x509_SecPolicyCreateSSL_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_SecPolicyCreateSSL(SB)
+TEXT ·x509_SecTrustSetVerifyDate_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_SecTrustSetVerifyDate(SB)
+TEXT ·x509_SecTrustEvaluate_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_SecTrustEvaluate(SB)
+TEXT ·x509_SecTrustGetResult_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_SecTrustGetResult(SB)
+TEXT ·x509_SecTrustEvaluateWithError_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_SecTrustEvaluateWithError(SB)
+TEXT ·x509_SecTrustGetCertificateCount_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_SecTrustGetCertificateCount(SB)
+TEXT ·x509_SecTrustGetCertificateAtIndex_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_SecTrustGetCertificateAtIndex(SB)
+TEXT ·x509_SecCertificateCopyData_trampoline(SB),NOSPLIT,$0-0
+ JMP x509_SecCertificateCopyData(SB)
diff --git a/src/crypto/x509/name_constraints_test.go b/src/crypto/x509/name_constraints_test.go
new file mode 100644
index 0000000..4c22c4c
--- /dev/null
+++ b/src/crypto/x509/name_constraints_test.go
@@ -0,0 +1,2171 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "bytes"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "encoding/hex"
+ "encoding/pem"
+ "fmt"
+ "math/big"
+ "net"
+ "net/url"
+ "os"
+ "os/exec"
+ "strconv"
+ "strings"
+ "sync"
+ "testing"
+ "time"
+)
+
+const (
+ // testNameConstraintsAgainstOpenSSL can be set to true to run tests
+ // against the system OpenSSL. This is disabled by default because Go
+ // cannot depend on having OpenSSL installed at testing time.
+ testNameConstraintsAgainstOpenSSL = false
+
+ // debugOpenSSLFailure can be set to true, when
+ // testNameConstraintsAgainstOpenSSL is also true, to cause
+ // intermediate files to be preserved for debugging.
+ debugOpenSSLFailure = false
+)
+
+type nameConstraintsTest struct {
+ roots []constraintsSpec
+ intermediates [][]constraintsSpec
+ leaf leafSpec
+ requestedEKUs []ExtKeyUsage
+ expectedError string
+ noOpenSSL bool
+ ignoreCN bool
+}
+
+type constraintsSpec struct {
+ ok []string
+ bad []string
+ ekus []string
+}
+
+type leafSpec struct {
+ sans []string
+ ekus []string
+ cn string
+}
+
+var nameConstraintsTests = []nameConstraintsTest{
+ // #0: dummy test for the certificate generation process itself.
+ {
+ roots: make([]constraintsSpec, 1),
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ },
+ },
+
+ // #1: dummy test for the certificate generation process itself: single
+ // level of intermediate.
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ },
+ },
+
+ // #2: dummy test for the certificate generation process itself: two
+ // levels of intermediates.
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ },
+ },
+
+ // #3: matching DNS constraint in root
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ },
+ },
+
+ // #4: matching DNS constraint in intermediate.
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ ok: []string{"dns:example.com"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ },
+ },
+
+ // #5: .example.com only matches subdomains.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:.example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ },
+ expectedError: "\"example.com\" is not permitted",
+ },
+
+ // #6: .example.com matches subdomains.
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ ok: []string{"dns:.example.com"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:foo.example.com"},
+ },
+ },
+
+ // #7: .example.com matches multiple levels of subdomains
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:.example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:foo.bar.example.com"},
+ },
+ },
+
+ // #8: specifying a permitted list of names does not exclude other name
+ // types
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:.example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"ip:10.1.1.1"},
+ },
+ },
+
+ // #9: specifying a permitted list of names does not exclude other name
+ // types
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"ip:10.0.0.0/8"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ },
+ },
+
+ // #10: intermediates can try to permit other names, which isn't
+ // forbidden if the leaf doesn't mention them. I.e. name constraints
+ // apply to names, not constraints themselves.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ ok: []string{"dns:example.com", "dns:foo.com"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ },
+ },
+
+ // #11: intermediates cannot add permitted names that the root doesn't
+ // grant them.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ ok: []string{"dns:example.com", "dns:foo.com"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:foo.com"},
+ },
+ expectedError: "\"foo.com\" is not permitted",
+ },
+
+ // #12: intermediates can further limit their scope if they wish.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:.example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ ok: []string{"dns:.bar.example.com"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:foo.bar.example.com"},
+ },
+ },
+
+ // #13: intermediates can further limit their scope and that limitation
+ // is effective
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:.example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ ok: []string{"dns:.bar.example.com"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:foo.notbar.example.com"},
+ },
+ expectedError: "\"foo.notbar.example.com\" is not permitted",
+ },
+
+ // #14: roots can exclude subtrees and that doesn't affect other names.
+ {
+ roots: []constraintsSpec{
+ {
+ bad: []string{"dns:.example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:foo.com"},
+ },
+ },
+
+ // #15: roots exclusions are effective.
+ {
+ roots: []constraintsSpec{
+ {
+ bad: []string{"dns:.example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:foo.example.com"},
+ },
+ expectedError: "\"foo.example.com\" is excluded",
+ },
+
+ // #16: intermediates can also exclude names and that doesn't affect
+ // other names.
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ bad: []string{"dns:.example.com"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:foo.com"},
+ },
+ },
+
+ // #17: intermediate exclusions are effective.
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ bad: []string{"dns:.example.com"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:foo.example.com"},
+ },
+ expectedError: "\"foo.example.com\" is excluded",
+ },
+
+ // #18: having an exclusion doesn't prohibit other types of names.
+ {
+ roots: []constraintsSpec{
+ {
+ bad: []string{"dns:.example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:foo.com", "ip:10.1.1.1"},
+ },
+ },
+
+ // #19: IP-based exclusions are permitted and don't affect unrelated IP
+ // addresses.
+ {
+ roots: []constraintsSpec{
+ {
+ bad: []string{"ip:10.0.0.0/8"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"ip:192.168.1.1"},
+ },
+ },
+
+ // #20: IP-based exclusions are effective
+ {
+ roots: []constraintsSpec{
+ {
+ bad: []string{"ip:10.0.0.0/8"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"ip:10.0.0.1"},
+ },
+ expectedError: "\"10.0.0.1\" is excluded",
+ },
+
+ // #21: intermediates can further constrain IP ranges.
+ {
+ roots: []constraintsSpec{
+ {
+ bad: []string{"ip:0.0.0.0/1"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ bad: []string{"ip:11.0.0.0/8"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"ip:11.0.0.1"},
+ },
+ expectedError: "\"11.0.0.1\" is excluded",
+ },
+
+ // #22: when multiple intermediates are present, chain building can
+ // avoid intermediates with incompatible constraints.
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ ok: []string{"dns:.foo.com"},
+ },
+ {
+ ok: []string{"dns:.example.com"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:foo.example.com"},
+ },
+ noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
+ },
+
+ // #23: (same as the previous test, but in the other order in ensure
+ // that we don't pass it by luck.)
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ ok: []string{"dns:.example.com"},
+ },
+ {
+ ok: []string{"dns:.foo.com"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:foo.example.com"},
+ },
+ noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
+ },
+
+ // #24: when multiple roots are valid, chain building can avoid roots
+ // with incompatible constraints.
+ {
+ roots: []constraintsSpec{
+ {},
+ {
+ ok: []string{"dns:foo.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ },
+ noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
+ },
+
+ // #25: (same as the previous test, but in the other order in ensure
+ // that we don't pass it by luck.)
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:foo.com"},
+ },
+ {},
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ },
+ noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
+ },
+
+ // #26: chain building can find a valid path even with multiple levels
+ // of alternative intermediates and alternative roots.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:foo.com"},
+ },
+ {
+ ok: []string{"dns:example.com"},
+ },
+ {},
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ {
+ ok: []string{"dns:foo.com"},
+ },
+ },
+ {
+ {},
+ {
+ ok: []string{"dns:foo.com"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:bar.com"},
+ },
+ noOpenSSL: true, // OpenSSL's chain building is not informed by constraints.
+ },
+
+ // #27: chain building doesn't get stuck when there is no valid path.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:foo.com"},
+ },
+ {
+ ok: []string{"dns:example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ {
+ ok: []string{"dns:foo.com"},
+ },
+ },
+ {
+ {
+ ok: []string{"dns:bar.com"},
+ },
+ {
+ ok: []string{"dns:foo.com"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:bar.com"},
+ },
+ expectedError: "\"bar.com\" is not permitted",
+ },
+
+ // #28: unknown name types don't cause a problem without constraints.
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"unknown:"},
+ },
+ },
+
+ // #29: unknown name types are allowed even in constrained chains.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:foo.com", "dns:.foo.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"unknown:"},
+ },
+ },
+
+ // #30: without SANs, a certificate with a CN is still accepted in a
+ // constrained chain, since we ignore the CN in VerifyHostname.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:foo.com", "dns:.foo.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{},
+ cn: "foo.com",
+ },
+ },
+
+ // #31: IPv6 addresses work in constraints: roots can permit them as
+ // expected.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"ip:2000:abcd::/32"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"ip:2000:abcd:1234::"},
+ },
+ },
+
+ // #32: IPv6 addresses work in constraints: root restrictions are
+ // effective.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"ip:2000:abcd::/32"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"ip:2000:1234:abcd::"},
+ },
+ expectedError: "\"2000:1234:abcd::\" is not permitted",
+ },
+
+ // #33: An IPv6 permitted subtree doesn't affect DNS names.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"ip:2000:abcd::/32"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"ip:2000:abcd::", "dns:foo.com"},
+ },
+ },
+
+ // #34: IPv6 exclusions don't affect unrelated addresses.
+ {
+ roots: []constraintsSpec{
+ {
+ bad: []string{"ip:2000:abcd::/32"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"ip:2000:1234::"},
+ },
+ },
+
+ // #35: IPv6 exclusions are effective.
+ {
+ roots: []constraintsSpec{
+ {
+ bad: []string{"ip:2000:abcd::/32"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"ip:2000:abcd::"},
+ },
+ expectedError: "\"2000:abcd::\" is excluded",
+ },
+
+ // #36: IPv6 constraints do not permit IPv4 addresses.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"ip:2000:abcd::/32"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"ip:10.0.0.1"},
+ },
+ expectedError: "\"10.0.0.1\" is not permitted",
+ },
+
+ // #37: IPv4 constraints do not permit IPv6 addresses.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"ip:10.0.0.0/8"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"ip:2000:abcd::"},
+ },
+ expectedError: "\"2000:abcd::\" is not permitted",
+ },
+
+ // #38: an exclusion of an unknown type doesn't affect other names.
+ {
+ roots: []constraintsSpec{
+ {
+ bad: []string{"unknown:"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ },
+ },
+
+ // #39: a permitted subtree of an unknown type doesn't affect other
+ // name types.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"unknown:"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ },
+ },
+
+ // #40: exact email constraints work
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"email:foo@example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"email:foo@example.com"},
+ },
+ },
+
+ // #41: exact email constraints are effective
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"email:foo@example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"email:bar@example.com"},
+ },
+ expectedError: "\"bar@example.com\" is not permitted",
+ },
+
+ // #42: email canonicalisation works.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"email:foo@example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"email:\"\\f\\o\\o\"@example.com"},
+ },
+ noOpenSSL: true, // OpenSSL doesn't canonicalise email addresses before matching
+ },
+
+ // #43: limiting email addresses to a host works.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"email:example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"email:foo@example.com"},
+ },
+ },
+
+ // #44: a leading dot matches hosts one level deep
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"email:.example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"email:foo@sub.example.com"},
+ },
+ },
+
+ // #45: a leading dot does not match the host itself
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"email:.example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"email:foo@example.com"},
+ },
+ expectedError: "\"foo@example.com\" is not permitted",
+ },
+
+ // #46: a leading dot also matches two (or more) levels deep.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"email:.example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"email:foo@sub.sub.example.com"},
+ },
+ },
+
+ // #47: the local part of an email is case-sensitive
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"email:foo@example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"email:Foo@example.com"},
+ },
+ expectedError: "\"Foo@example.com\" is not permitted",
+ },
+
+ // #48: the domain part of an email is not case-sensitive
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"email:foo@EXAMPLE.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"email:foo@example.com"},
+ },
+ },
+
+ // #49: the domain part of a DNS constraint is also not case-sensitive.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:EXAMPLE.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ },
+ },
+
+ // #50: URI constraints only cover the host part of the URI
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"uri:example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{
+ "uri:http://example.com/bar",
+ "uri:http://example.com:8080/",
+ "uri:https://example.com/wibble#bar",
+ },
+ },
+ },
+
+ // #51: URIs with IPs are rejected
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"uri:example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"uri:http://1.2.3.4/"},
+ },
+ expectedError: "URI with IP",
+ },
+
+ // #52: URIs with IPs and ports are rejected
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"uri:example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"uri:http://1.2.3.4:43/"},
+ },
+ expectedError: "URI with IP",
+ },
+
+ // #53: URIs with IPv6 addresses are also rejected
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"uri:example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"uri:http://[2006:abcd::1]/"},
+ },
+ expectedError: "URI with IP",
+ },
+
+ // #54: URIs with IPv6 addresses with ports are also rejected
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"uri:example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"uri:http://[2006:abcd::1]:16/"},
+ },
+ expectedError: "URI with IP",
+ },
+
+ // #55: URI constraints are effective
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"uri:example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"uri:http://bar.com/"},
+ },
+ expectedError: "\"http://bar.com/\" is not permitted",
+ },
+
+ // #56: URI constraints are effective
+ {
+ roots: []constraintsSpec{
+ {
+ bad: []string{"uri:foo.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"uri:http://foo.com/"},
+ },
+ expectedError: "\"http://foo.com/\" is excluded",
+ },
+
+ // #57: URI constraints can allow subdomains
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"uri:.foo.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"uri:http://www.foo.com/"},
+ },
+ },
+
+ // #58: excluding an IPv4-mapped-IPv6 address doesn't affect the IPv4
+ // version of that address.
+ {
+ roots: []constraintsSpec{
+ {
+ bad: []string{"ip:::ffff:1.2.3.4/128"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"ip:1.2.3.4"},
+ },
+ },
+
+ // #59: a URI constraint isn't matched by a URN.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"uri:example.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"uri:urn:example"},
+ },
+ expectedError: "URI with empty host",
+ },
+
+ // #60: excluding all IPv6 addresses doesn't exclude all IPv4 addresses
+ // too, even though IPv4 is mapped into the IPv6 range.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"ip:1.2.3.0/24"},
+ bad: []string{"ip:::0/0"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"ip:1.2.3.4"},
+ },
+ },
+
+ // #61: omitting extended key usage in a CA certificate implies that
+ // any usage is ok.
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ ekus: []string{"serverAuth", "other"},
+ },
+ },
+
+ // #62: The “any” EKU also means that any usage is ok.
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ ekus: []string{"any"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ ekus: []string{"serverAuth", "other"},
+ },
+ },
+
+ // #63: An intermediate with enumerated EKUs causes a failure if we
+ // test for an EKU not in that set. (ServerAuth is required by
+ // default.)
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ ekus: []string{"email"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ ekus: []string{"serverAuth"},
+ },
+ expectedError: "incompatible key usage",
+ },
+
+ // #64: an unknown EKU in the leaf doesn't break anything, even if it's not
+ // correctly nested.
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ ekus: []string{"email"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ ekus: []string{"other"},
+ },
+ requestedEKUs: []ExtKeyUsage{ExtKeyUsageAny},
+ },
+
+ // #65: trying to add extra permitted key usages in an intermediate
+ // (after a limitation in the root) is acceptable so long as the leaf
+ // certificate doesn't use them.
+ {
+ roots: []constraintsSpec{
+ {
+ ekus: []string{"serverAuth"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ ekus: []string{"serverAuth", "email"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ ekus: []string{"serverAuth"},
+ },
+ },
+
+ // #66: EKUs in roots are not ignored.
+ {
+ roots: []constraintsSpec{
+ {
+ ekus: []string{"email"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ ekus: []string{"serverAuth"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ ekus: []string{"serverAuth"},
+ },
+ expectedError: "incompatible key usage",
+ },
+
+ // #67: SGC key usages used to permit serverAuth and clientAuth,
+ // but don't anymore.
+ {
+ roots: []constraintsSpec{
+ {},
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ ekus: []string{"netscapeSGC"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ ekus: []string{"serverAuth", "clientAuth"},
+ },
+ expectedError: "incompatible key usage",
+ },
+
+ // #68: SGC key usages used to permit serverAuth and clientAuth,
+ // but don't anymore.
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ ekus: []string{"msSGC"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ ekus: []string{"serverAuth", "clientAuth"},
+ },
+ expectedError: "incompatible key usage",
+ },
+
+ // #69: an empty DNS constraint should allow anything.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ },
+ },
+
+ // #70: an empty DNS constraint should also reject everything.
+ {
+ roots: []constraintsSpec{
+ {
+ bad: []string{"dns:"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ },
+ expectedError: "\"example.com\" is excluded",
+ },
+
+ // #71: an empty email constraint should allow anything
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"email:"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"email:foo@example.com"},
+ },
+ },
+
+ // #72: an empty email constraint should also reject everything.
+ {
+ roots: []constraintsSpec{
+ {
+ bad: []string{"email:"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"email:foo@example.com"},
+ },
+ expectedError: "\"foo@example.com\" is excluded",
+ },
+
+ // #73: an empty URI constraint should allow anything
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"uri:"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"uri:https://example.com/test"},
+ },
+ },
+
+ // #74: an empty URI constraint should also reject everything.
+ {
+ roots: []constraintsSpec{
+ {
+ bad: []string{"uri:"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"uri:https://example.com/test"},
+ },
+ expectedError: "\"https://example.com/test\" is excluded",
+ },
+
+ // #75: serverAuth in a leaf shouldn't permit clientAuth when requested in
+ // VerifyOptions.
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ ekus: []string{"serverAuth"},
+ },
+ requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth},
+ expectedError: "incompatible key usage",
+ },
+
+ // #76: MSSGC in a leaf used to match a request for serverAuth, but doesn't
+ // anymore.
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ ekus: []string{"msSGC"},
+ },
+ requestedEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ expectedError: "incompatible key usage",
+ },
+
+ // An invalid DNS SAN should be detected only at validation time so
+ // that we can process CA certificates in the wild that have invalid SANs.
+ // See https://github.com/golang/go/issues/23995
+
+ // #77: an invalid DNS or mail SAN will not be detected if name constraint
+ // checking is not triggered.
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:this is invalid", "email:this @ is invalid"},
+ },
+ },
+
+ // #78: an invalid DNS SAN will be detected if any name constraint checking
+ // is triggered.
+ {
+ roots: []constraintsSpec{
+ {
+ bad: []string{"uri:"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:this is invalid"},
+ },
+ expectedError: "cannot parse dnsName",
+ },
+
+ // #79: an invalid email SAN will be detected if any name constraint
+ // checking is triggered.
+ {
+ roots: []constraintsSpec{
+ {
+ bad: []string{"uri:"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"email:this @ is invalid"},
+ },
+ expectedError: "cannot parse rfc822Name",
+ },
+
+ // #80: if several EKUs are requested, satisfying any of them is sufficient.
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ ekus: []string{"email"},
+ },
+ requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageEmailProtection},
+ },
+
+ // #81: EKUs that are not asserted in VerifyOpts are not required to be
+ // nested.
+ {
+ roots: make([]constraintsSpec, 1),
+ intermediates: [][]constraintsSpec{
+ {
+ {
+ ekus: []string{"serverAuth"},
+ },
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ // There's no email EKU in the intermediate. This would be rejected if
+ // full nesting was required.
+ ekus: []string{"email", "serverAuth"},
+ },
+ },
+
+ // #82: a certificate without SANs and CN is accepted in a constrained chain.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:foo.com", "dns:.foo.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{},
+ },
+ },
+
+ // #83: a certificate without SANs and with a CN that does not parse as a
+ // hostname is accepted in a constrained chain.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:foo.com", "dns:.foo.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{},
+ cn: "foo,bar",
+ },
+ },
+
+ // #84: a certificate with SANs and CN is accepted in a constrained chain.
+ {
+ roots: []constraintsSpec{
+ {
+ ok: []string{"dns:foo.com", "dns:.foo.com"},
+ },
+ },
+ intermediates: [][]constraintsSpec{
+ {
+ {},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:foo.com"},
+ cn: "foo.bar",
+ },
+ },
+}
+
+func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
+ var serialBytes [16]byte
+ rand.Read(serialBytes[:])
+
+ template := &Certificate{
+ SerialNumber: new(big.Int).SetBytes(serialBytes[:]),
+ Subject: pkix.Name{
+ CommonName: name,
+ },
+ NotBefore: time.Unix(1000, 0),
+ NotAfter: time.Unix(2000, 0),
+ KeyUsage: KeyUsageCertSign,
+ BasicConstraintsValid: true,
+ IsCA: true,
+ }
+
+ if err := addConstraintsToTemplate(constraints, template); err != nil {
+ return nil, err
+ }
+
+ if parent == nil {
+ parent = template
+ }
+ derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey)
+ if err != nil {
+ return nil, err
+ }
+
+ caCert, err := ParseCertificate(derBytes)
+ if err != nil {
+ return nil, err
+ }
+
+ return caCert, nil
+}
+
+func makeConstraintsLeafCert(leaf leafSpec, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
+ var serialBytes [16]byte
+ rand.Read(serialBytes[:])
+
+ template := &Certificate{
+ SerialNumber: new(big.Int).SetBytes(serialBytes[:]),
+ Subject: pkix.Name{
+ OrganizationalUnit: []string{"Leaf"},
+ CommonName: leaf.cn,
+ },
+ NotBefore: time.Unix(1000, 0),
+ NotAfter: time.Unix(2000, 0),
+ KeyUsage: KeyUsageDigitalSignature,
+ BasicConstraintsValid: true,
+ IsCA: false,
+ }
+
+ for _, name := range leaf.sans {
+ switch {
+ case strings.HasPrefix(name, "dns:"):
+ template.DNSNames = append(template.DNSNames, name[4:])
+
+ case strings.HasPrefix(name, "ip:"):
+ ip := net.ParseIP(name[3:])
+ if ip == nil {
+ return nil, fmt.Errorf("cannot parse IP %q", name[3:])
+ }
+ template.IPAddresses = append(template.IPAddresses, ip)
+
+ case strings.HasPrefix(name, "invalidip:"):
+ ipBytes, err := hex.DecodeString(name[10:])
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse invalid IP: %s", err)
+ }
+ template.IPAddresses = append(template.IPAddresses, net.IP(ipBytes))
+
+ case strings.HasPrefix(name, "email:"):
+ template.EmailAddresses = append(template.EmailAddresses, name[6:])
+
+ case strings.HasPrefix(name, "uri:"):
+ uri, err := url.Parse(name[4:])
+ if err != nil {
+ return nil, fmt.Errorf("cannot parse URI %q: %s", name[4:], err)
+ }
+ template.URIs = append(template.URIs, uri)
+
+ case strings.HasPrefix(name, "unknown:"):
+ // This is a special case for testing unknown
+ // name types. A custom SAN extension is
+ // injected into the certificate.
+ if len(leaf.sans) != 1 {
+ panic("when using unknown name types, it must be the sole name")
+ }
+
+ template.ExtraExtensions = append(template.ExtraExtensions, pkix.Extension{
+ Id: []int{2, 5, 29, 17},
+ Value: []byte{
+ 0x30, // SEQUENCE
+ 3, // three bytes
+ 9, // undefined GeneralName type 9
+ 1,
+ 1,
+ },
+ })
+
+ default:
+ return nil, fmt.Errorf("unknown name type %q", name)
+ }
+ }
+
+ var err error
+ if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(leaf.ekus); err != nil {
+ return nil, err
+ }
+
+ if parent == nil {
+ parent = template
+ }
+
+ derBytes, err := CreateCertificate(rand.Reader, template, parent, &key.PublicKey, parentKey)
+ if err != nil {
+ return nil, err
+ }
+
+ return ParseCertificate(derBytes)
+}
+
+func customConstraintsExtension(typeNum int, constraint []byte, isExcluded bool) pkix.Extension {
+ appendConstraint := func(contents []byte, tag uint8) []byte {
+ contents = append(contents, tag|32 /* constructed */ |0x80 /* context-specific */)
+ contents = append(contents, byte(4+len(constraint)) /* length */)
+ contents = append(contents, 0x30 /* SEQUENCE */)
+ contents = append(contents, byte(2+len(constraint)) /* length */)
+ contents = append(contents, byte(typeNum) /* GeneralName type */)
+ contents = append(contents, byte(len(constraint)))
+ return append(contents, constraint...)
+ }
+
+ var contents []byte
+ if !isExcluded {
+ contents = appendConstraint(contents, 0 /* tag 0 for permitted */)
+ } else {
+ contents = appendConstraint(contents, 1 /* tag 1 for excluded */)
+ }
+
+ var value []byte
+ value = append(value, 0x30 /* SEQUENCE */)
+ value = append(value, byte(len(contents)))
+ value = append(value, contents...)
+
+ return pkix.Extension{
+ Id: []int{2, 5, 29, 30},
+ Value: value,
+ }
+}
+
+func addConstraintsToTemplate(constraints constraintsSpec, template *Certificate) error {
+ parse := func(constraints []string) (dnsNames []string, ips []*net.IPNet, emailAddrs []string, uriDomains []string, err error) {
+ for _, constraint := range constraints {
+ switch {
+ case strings.HasPrefix(constraint, "dns:"):
+ dnsNames = append(dnsNames, constraint[4:])
+
+ case strings.HasPrefix(constraint, "ip:"):
+ _, ipNet, err := net.ParseCIDR(constraint[3:])
+ if err != nil {
+ return nil, nil, nil, nil, err
+ }
+ ips = append(ips, ipNet)
+
+ case strings.HasPrefix(constraint, "email:"):
+ emailAddrs = append(emailAddrs, constraint[6:])
+
+ case strings.HasPrefix(constraint, "uri:"):
+ uriDomains = append(uriDomains, constraint[4:])
+
+ default:
+ return nil, nil, nil, nil, fmt.Errorf("unknown constraint %q", constraint)
+ }
+ }
+
+ return dnsNames, ips, emailAddrs, uriDomains, err
+ }
+
+ handleSpecialConstraint := func(constraint string, isExcluded bool) bool {
+ switch {
+ case constraint == "unknown:":
+ template.ExtraExtensions = append(template.ExtraExtensions, customConstraintsExtension(9 /* undefined GeneralName type */, []byte{1}, isExcluded))
+
+ default:
+ return false
+ }
+
+ return true
+ }
+
+ if len(constraints.ok) == 1 && len(constraints.bad) == 0 {
+ if handleSpecialConstraint(constraints.ok[0], false) {
+ return nil
+ }
+ }
+
+ if len(constraints.bad) == 1 && len(constraints.ok) == 0 {
+ if handleSpecialConstraint(constraints.bad[0], true) {
+ return nil
+ }
+ }
+
+ var err error
+ template.PermittedDNSDomains, template.PermittedIPRanges, template.PermittedEmailAddresses, template.PermittedURIDomains, err = parse(constraints.ok)
+ if err != nil {
+ return err
+ }
+
+ template.ExcludedDNSDomains, template.ExcludedIPRanges, template.ExcludedEmailAddresses, template.ExcludedURIDomains, err = parse(constraints.bad)
+ if err != nil {
+ return err
+ }
+
+ if template.ExtKeyUsage, template.UnknownExtKeyUsage, err = parseEKUs(constraints.ekus); err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func parseEKUs(ekuStrs []string) (ekus []ExtKeyUsage, unknowns []asn1.ObjectIdentifier, err error) {
+ for _, s := range ekuStrs {
+ switch s {
+ case "serverAuth":
+ ekus = append(ekus, ExtKeyUsageServerAuth)
+ case "clientAuth":
+ ekus = append(ekus, ExtKeyUsageClientAuth)
+ case "email":
+ ekus = append(ekus, ExtKeyUsageEmailProtection)
+ case "netscapeSGC":
+ ekus = append(ekus, ExtKeyUsageNetscapeServerGatedCrypto)
+ case "msSGC":
+ ekus = append(ekus, ExtKeyUsageMicrosoftServerGatedCrypto)
+ case "any":
+ ekus = append(ekus, ExtKeyUsageAny)
+ case "other":
+ unknowns = append(unknowns, asn1.ObjectIdentifier{2, 4, 1, 2, 3})
+ default:
+ return nil, nil, fmt.Errorf("unknown EKU %q", s)
+ }
+ }
+
+ return
+}
+
+func TestConstraintCases(t *testing.T) {
+ privateKeys := sync.Pool{
+ New: func() any {
+ priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ panic(err)
+ }
+ return priv
+ },
+ }
+
+ for i, test := range nameConstraintsTests {
+ t.Run(fmt.Sprintf("#%d", i), func(t *testing.T) {
+ rootPool := NewCertPool()
+ rootKey := privateKeys.Get().(*ecdsa.PrivateKey)
+ rootName := "Root " + strconv.Itoa(i)
+
+ // keys keeps track of all the private keys used in a given
+ // test and puts them back in the privateKeys pool at the end.
+ keys := []*ecdsa.PrivateKey{rootKey}
+
+ // At each level (root, intermediate(s), leaf), parent points to
+ // an example parent certificate and parentKey the key for the
+ // parent level. Since all certificates at a given level have
+ // the same name and public key, any parent certificate is
+ // sufficient to get the correct issuer name and authority
+ // key ID.
+ var parent *Certificate
+ parentKey := rootKey
+
+ for _, root := range test.roots {
+ rootCert, err := makeConstraintsCACert(root, rootName, rootKey, nil, rootKey)
+ if err != nil {
+ t.Fatalf("failed to create root: %s", err)
+ }
+
+ parent = rootCert
+ rootPool.AddCert(rootCert)
+ }
+
+ intermediatePool := NewCertPool()
+
+ for level, intermediates := range test.intermediates {
+ levelKey := privateKeys.Get().(*ecdsa.PrivateKey)
+ keys = append(keys, levelKey)
+ levelName := "Intermediate level " + strconv.Itoa(level)
+ var last *Certificate
+
+ for _, intermediate := range intermediates {
+ caCert, err := makeConstraintsCACert(intermediate, levelName, levelKey, parent, parentKey)
+ if err != nil {
+ t.Fatalf("failed to create %q: %s", levelName, err)
+ }
+
+ last = caCert
+ intermediatePool.AddCert(caCert)
+ }
+
+ parent = last
+ parentKey = levelKey
+ }
+
+ leafKey := privateKeys.Get().(*ecdsa.PrivateKey)
+ keys = append(keys, leafKey)
+
+ leafCert, err := makeConstraintsLeafCert(test.leaf, leafKey, parent, parentKey)
+ if err != nil {
+ t.Fatalf("cannot create leaf: %s", err)
+ }
+
+ // Skip tests with CommonName set because OpenSSL will try to match it
+ // against name constraints, while we ignore it when it's not hostname-looking.
+ if !test.noOpenSSL && testNameConstraintsAgainstOpenSSL && test.leaf.cn == "" {
+ output, err := testChainAgainstOpenSSL(t, leafCert, intermediatePool, rootPool)
+ if err == nil && len(test.expectedError) > 0 {
+ t.Error("unexpectedly succeeded against OpenSSL")
+ if debugOpenSSLFailure {
+ return
+ }
+ }
+
+ if err != nil {
+ if _, ok := err.(*exec.ExitError); !ok {
+ t.Errorf("OpenSSL failed to run: %s", err)
+ } else if len(test.expectedError) == 0 {
+ t.Errorf("OpenSSL unexpectedly failed: %v", output)
+ if debugOpenSSLFailure {
+ return
+ }
+ }
+ }
+ }
+
+ verifyOpts := VerifyOptions{
+ Roots: rootPool,
+ Intermediates: intermediatePool,
+ CurrentTime: time.Unix(1500, 0),
+ KeyUsages: test.requestedEKUs,
+ }
+ _, err = leafCert.Verify(verifyOpts)
+
+ logInfo := true
+ if len(test.expectedError) == 0 {
+ if err != nil {
+ t.Errorf("unexpected failure: %s", err)
+ } else {
+ logInfo = false
+ }
+ } else {
+ if err == nil {
+ t.Error("unexpected success")
+ } else if !strings.Contains(err.Error(), test.expectedError) {
+ t.Errorf("expected error containing %q, but got: %s", test.expectedError, err)
+ } else {
+ logInfo = false
+ }
+ }
+
+ if logInfo {
+ certAsPEM := func(cert *Certificate) string {
+ var buf bytes.Buffer
+ pem.Encode(&buf, &pem.Block{Type: "CERTIFICATE", Bytes: cert.Raw})
+ return buf.String()
+ }
+ t.Errorf("root:\n%s", certAsPEM(rootPool.mustCert(t, 0)))
+ if intermediates := allCerts(t, intermediatePool); len(intermediates) > 0 {
+ for ii, intermediate := range intermediates {
+ t.Errorf("intermediate %d:\n%s", ii, certAsPEM(intermediate))
+ }
+ }
+ t.Errorf("leaf:\n%s", certAsPEM(leafCert))
+ }
+
+ for _, key := range keys {
+ privateKeys.Put(key)
+ }
+ })
+ }
+}
+
+func writePEMsToTempFile(certs []*Certificate) *os.File {
+ file, err := os.CreateTemp("", "name_constraints_test")
+ if err != nil {
+ panic("cannot create tempfile")
+ }
+
+ pemBlock := &pem.Block{Type: "CERTIFICATE"}
+ for _, cert := range certs {
+ pemBlock.Bytes = cert.Raw
+ pem.Encode(file, pemBlock)
+ }
+
+ return file
+}
+
+func testChainAgainstOpenSSL(t *testing.T, leaf *Certificate, intermediates, roots *CertPool) (string, error) {
+ args := []string{"verify", "-no_check_time"}
+
+ rootsFile := writePEMsToTempFile(allCerts(t, roots))
+ if debugOpenSSLFailure {
+ println("roots file:", rootsFile.Name())
+ } else {
+ defer os.Remove(rootsFile.Name())
+ }
+ args = append(args, "-CAfile", rootsFile.Name())
+
+ if intermediates.len() > 0 {
+ intermediatesFile := writePEMsToTempFile(allCerts(t, intermediates))
+ if debugOpenSSLFailure {
+ println("intermediates file:", intermediatesFile.Name())
+ } else {
+ defer os.Remove(intermediatesFile.Name())
+ }
+ args = append(args, "-untrusted", intermediatesFile.Name())
+ }
+
+ leafFile := writePEMsToTempFile([]*Certificate{leaf})
+ if debugOpenSSLFailure {
+ println("leaf file:", leafFile.Name())
+ } else {
+ defer os.Remove(leafFile.Name())
+ }
+ args = append(args, leafFile.Name())
+
+ var output bytes.Buffer
+ cmd := exec.Command("openssl", args...)
+ cmd.Stdout = &output
+ cmd.Stderr = &output
+
+ err := cmd.Run()
+ return output.String(), err
+}
+
+var rfc2821Tests = []struct {
+ in string
+ localPart, domain string
+}{
+ {"foo@example.com", "foo", "example.com"},
+ {"@example.com", "", ""},
+ {"\"@example.com", "", ""},
+ {"\"\"@example.com", "", "example.com"},
+ {"\"a\"@example.com", "a", "example.com"},
+ {"\"\\a\"@example.com", "a", "example.com"},
+ {"a\"@example.com", "", ""},
+ {"foo..bar@example.com", "", ""},
+ {".foo.bar@example.com", "", ""},
+ {"foo.bar.@example.com", "", ""},
+ {"|{}?'@example.com", "|{}?'", "example.com"},
+
+ // Examples from RFC 3696
+ {"Abc\\@def@example.com", "Abc@def", "example.com"},
+ {"Fred\\ Bloggs@example.com", "Fred Bloggs", "example.com"},
+ {"Joe.\\\\Blow@example.com", "Joe.\\Blow", "example.com"},
+ {"\"Abc@def\"@example.com", "Abc@def", "example.com"},
+ {"\"Fred Bloggs\"@example.com", "Fred Bloggs", "example.com"},
+ {"customer/department=shipping@example.com", "customer/department=shipping", "example.com"},
+ {"$A12345@example.com", "$A12345", "example.com"},
+ {"!def!xyz%abc@example.com", "!def!xyz%abc", "example.com"},
+ {"_somename@example.com", "_somename", "example.com"},
+}
+
+func TestRFC2821Parsing(t *testing.T) {
+ for i, test := range rfc2821Tests {
+ mailbox, ok := parseRFC2821Mailbox(test.in)
+ expectedFailure := len(test.localPart) == 0 && len(test.domain) == 0
+
+ if ok && expectedFailure {
+ t.Errorf("#%d: %q unexpectedly parsed as (%q, %q)", i, test.in, mailbox.local, mailbox.domain)
+ continue
+ }
+
+ if !ok && !expectedFailure {
+ t.Errorf("#%d: unexpected failure for %q", i, test.in)
+ continue
+ }
+
+ if !ok {
+ continue
+ }
+
+ if mailbox.local != test.localPart || mailbox.domain != test.domain {
+ t.Errorf("#%d: %q parsed as (%q, %q), but wanted (%q, %q)", i, test.in, mailbox.local, mailbox.domain, test.localPart, test.domain)
+ }
+ }
+}
+
+func TestBadNamesInConstraints(t *testing.T) {
+ constraintParseError := func(err error) bool {
+ str := err.Error()
+ return strings.Contains(str, "failed to parse ") && strings.Contains(str, "constraint")
+ }
+
+ encodingError := func(err error) bool {
+ return strings.Contains(err.Error(), "cannot be encoded as an IA5String")
+ }
+
+ // Bad names in constraints should not parse.
+ badNames := []struct {
+ name string
+ matcher func(error) bool
+ }{
+ {"dns:foo.com.", constraintParseError},
+ {"email:abc@foo.com.", constraintParseError},
+ {"email:foo.com.", constraintParseError},
+ {"uri:example.com.", constraintParseError},
+ {"uri:1.2.3.4", constraintParseError},
+ {"uri:ffff::1", constraintParseError},
+ {"dns:not–hyphen.com", encodingError},
+ {"email:foo@not–hyphen.com", encodingError},
+ {"uri:not–hyphen.com", encodingError},
+ }
+
+ priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ panic(err)
+ }
+
+ for _, test := range badNames {
+ _, err := makeConstraintsCACert(constraintsSpec{
+ ok: []string{test.name},
+ }, "TestAbsoluteNamesInConstraints", priv, nil, priv)
+
+ if err == nil {
+ t.Errorf("bad name %q unexpectedly accepted in name constraint", test.name)
+ continue
+ } else {
+ if !test.matcher(err) {
+ t.Errorf("bad name %q triggered unrecognised error: %s", test.name, err)
+ }
+ }
+ }
+}
+
+func TestBadNamesInSANs(t *testing.T) {
+ // Bad names in URI and IP SANs should not parse. Bad DNS and email SANs
+ // will parse and are tested in name constraint tests at the top of this
+ // file.
+ badNames := []string{
+ "uri:https://example.com./dsf",
+ "invalidip:0102",
+ "invalidip:0102030405",
+ }
+
+ priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ panic(err)
+ }
+
+ for _, badName := range badNames {
+ _, err := makeConstraintsLeafCert(leafSpec{sans: []string{badName}}, priv, nil, priv)
+
+ if err == nil {
+ t.Errorf("bad name %q unexpectedly accepted in SAN", badName)
+ continue
+ }
+
+ if str := err.Error(); !strings.Contains(str, "cannot parse ") {
+ t.Errorf("bad name %q triggered unrecognised error: %s", badName, str)
+ }
+ }
+}
diff --git a/src/crypto/x509/notboring.go b/src/crypto/x509/notboring.go
new file mode 100644
index 0000000..c83a727
--- /dev/null
+++ b/src/crypto/x509/notboring.go
@@ -0,0 +1,9 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build !boringcrypto
+
+package x509
+
+func boringAllowCert(c *Certificate) bool { return true }
diff --git a/src/crypto/x509/parser.go b/src/crypto/x509/parser.go
new file mode 100644
index 0000000..6ea3017
--- /dev/null
+++ b/src/crypto/x509/parser.go
@@ -0,0 +1,1175 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "bytes"
+ "crypto/dsa"
+ "crypto/ecdh"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/elliptic"
+ "crypto/rsa"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "errors"
+ "fmt"
+ "math/big"
+ "net"
+ "net/url"
+ "strconv"
+ "strings"
+ "time"
+ "unicode/utf16"
+ "unicode/utf8"
+
+ "golang.org/x/crypto/cryptobyte"
+ cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
+)
+
+// isPrintable reports whether the given b is in the ASN.1 PrintableString set.
+// This is a simplified version of encoding/asn1.isPrintable.
+func isPrintable(b byte) bool {
+ return 'a' <= b && b <= 'z' ||
+ 'A' <= b && b <= 'Z' ||
+ '0' <= b && b <= '9' ||
+ '\'' <= b && b <= ')' ||
+ '+' <= b && b <= '/' ||
+ b == ' ' ||
+ b == ':' ||
+ b == '=' ||
+ b == '?' ||
+ // This is technically not allowed in a PrintableString.
+ // However, x509 certificates with wildcard strings don't
+ // always use the correct string type so we permit it.
+ b == '*' ||
+ // This is not technically allowed either. However, not
+ // only is it relatively common, but there are also a
+ // handful of CA certificates that contain it. At least
+ // one of which will not expire until 2027.
+ b == '&'
+}
+
+// parseASN1String parses the ASN.1 string types T61String, PrintableString,
+// UTF8String, BMPString, IA5String, and NumericString. This is mostly copied
+// from the respective encoding/asn1.parse... methods, rather than just
+// increasing the API surface of that package.
+func parseASN1String(tag cryptobyte_asn1.Tag, value []byte) (string, error) {
+ switch tag {
+ case cryptobyte_asn1.T61String:
+ return string(value), nil
+ case cryptobyte_asn1.PrintableString:
+ for _, b := range value {
+ if !isPrintable(b) {
+ return "", errors.New("invalid PrintableString")
+ }
+ }
+ return string(value), nil
+ case cryptobyte_asn1.UTF8String:
+ if !utf8.Valid(value) {
+ return "", errors.New("invalid UTF-8 string")
+ }
+ return string(value), nil
+ case cryptobyte_asn1.Tag(asn1.TagBMPString):
+ if len(value)%2 != 0 {
+ return "", errors.New("invalid BMPString")
+ }
+
+ // Strip terminator if present.
+ if l := len(value); l >= 2 && value[l-1] == 0 && value[l-2] == 0 {
+ value = value[:l-2]
+ }
+
+ s := make([]uint16, 0, len(value)/2)
+ for len(value) > 0 {
+ s = append(s, uint16(value[0])<<8+uint16(value[1]))
+ value = value[2:]
+ }
+
+ return string(utf16.Decode(s)), nil
+ case cryptobyte_asn1.IA5String:
+ s := string(value)
+ if isIA5String(s) != nil {
+ return "", errors.New("invalid IA5String")
+ }
+ return s, nil
+ case cryptobyte_asn1.Tag(asn1.TagNumericString):
+ for _, b := range value {
+ if !('0' <= b && b <= '9' || b == ' ') {
+ return "", errors.New("invalid NumericString")
+ }
+ }
+ return string(value), nil
+ }
+ return "", fmt.Errorf("unsupported string type: %v", tag)
+}
+
+// parseName parses a DER encoded Name as defined in RFC 5280. We may
+// want to export this function in the future for use in crypto/tls.
+func parseName(raw cryptobyte.String) (*pkix.RDNSequence, error) {
+ if !raw.ReadASN1(&raw, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: invalid RDNSequence")
+ }
+
+ var rdnSeq pkix.RDNSequence
+ for !raw.Empty() {
+ var rdnSet pkix.RelativeDistinguishedNameSET
+ var set cryptobyte.String
+ if !raw.ReadASN1(&set, cryptobyte_asn1.SET) {
+ return nil, errors.New("x509: invalid RDNSequence")
+ }
+ for !set.Empty() {
+ var atav cryptobyte.String
+ if !set.ReadASN1(&atav, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: invalid RDNSequence: invalid attribute")
+ }
+ var attr pkix.AttributeTypeAndValue
+ if !atav.ReadASN1ObjectIdentifier(&attr.Type) {
+ return nil, errors.New("x509: invalid RDNSequence: invalid attribute type")
+ }
+ var rawValue cryptobyte.String
+ var valueTag cryptobyte_asn1.Tag
+ if !atav.ReadAnyASN1(&rawValue, &valueTag) {
+ return nil, errors.New("x509: invalid RDNSequence: invalid attribute value")
+ }
+ var err error
+ attr.Value, err = parseASN1String(valueTag, rawValue)
+ if err != nil {
+ return nil, fmt.Errorf("x509: invalid RDNSequence: invalid attribute value: %s", err)
+ }
+ rdnSet = append(rdnSet, attr)
+ }
+
+ rdnSeq = append(rdnSeq, rdnSet)
+ }
+
+ return &rdnSeq, nil
+}
+
+func parseAI(der cryptobyte.String) (pkix.AlgorithmIdentifier, error) {
+ ai := pkix.AlgorithmIdentifier{}
+ if !der.ReadASN1ObjectIdentifier(&ai.Algorithm) {
+ return ai, errors.New("x509: malformed OID")
+ }
+ if der.Empty() {
+ return ai, nil
+ }
+ var params cryptobyte.String
+ var tag cryptobyte_asn1.Tag
+ if !der.ReadAnyASN1Element(&params, &tag) {
+ return ai, errors.New("x509: malformed parameters")
+ }
+ ai.Parameters.Tag = int(tag)
+ ai.Parameters.FullBytes = params
+ return ai, nil
+}
+
+func parseTime(der *cryptobyte.String) (time.Time, error) {
+ var t time.Time
+ switch {
+ case der.PeekASN1Tag(cryptobyte_asn1.UTCTime):
+ if !der.ReadASN1UTCTime(&t) {
+ return t, errors.New("x509: malformed UTCTime")
+ }
+ case der.PeekASN1Tag(cryptobyte_asn1.GeneralizedTime):
+ if !der.ReadASN1GeneralizedTime(&t) {
+ return t, errors.New("x509: malformed GeneralizedTime")
+ }
+ default:
+ return t, errors.New("x509: unsupported time format")
+ }
+ return t, nil
+}
+
+func parseValidity(der cryptobyte.String) (time.Time, time.Time, error) {
+ notBefore, err := parseTime(&der)
+ if err != nil {
+ return time.Time{}, time.Time{}, err
+ }
+ notAfter, err := parseTime(&der)
+ if err != nil {
+ return time.Time{}, time.Time{}, err
+ }
+
+ return notBefore, notAfter, nil
+}
+
+func parseExtension(der cryptobyte.String) (pkix.Extension, error) {
+ var ext pkix.Extension
+ if !der.ReadASN1ObjectIdentifier(&ext.Id) {
+ return ext, errors.New("x509: malformed extension OID field")
+ }
+ if der.PeekASN1Tag(cryptobyte_asn1.BOOLEAN) {
+ if !der.ReadASN1Boolean(&ext.Critical) {
+ return ext, errors.New("x509: malformed extension critical field")
+ }
+ }
+ var val cryptobyte.String
+ if !der.ReadASN1(&val, cryptobyte_asn1.OCTET_STRING) {
+ return ext, errors.New("x509: malformed extension value field")
+ }
+ ext.Value = val
+ return ext, nil
+}
+
+func parsePublicKey(keyData *publicKeyInfo) (any, error) {
+ oid := keyData.Algorithm.Algorithm
+ params := keyData.Algorithm.Parameters
+ der := cryptobyte.String(keyData.PublicKey.RightAlign())
+ switch {
+ case oid.Equal(oidPublicKeyRSA):
+ // RSA public keys must have a NULL in the parameters.
+ // See RFC 3279, Section 2.3.1.
+ if !bytes.Equal(params.FullBytes, asn1.NullBytes) {
+ return nil, errors.New("x509: RSA key missing NULL parameters")
+ }
+
+ p := &pkcs1PublicKey{N: new(big.Int)}
+ if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: invalid RSA public key")
+ }
+ if !der.ReadASN1Integer(p.N) {
+ return nil, errors.New("x509: invalid RSA modulus")
+ }
+ if !der.ReadASN1Integer(&p.E) {
+ return nil, errors.New("x509: invalid RSA public exponent")
+ }
+
+ if p.N.Sign() <= 0 {
+ return nil, errors.New("x509: RSA modulus is not a positive number")
+ }
+ if p.E <= 0 {
+ return nil, errors.New("x509: RSA public exponent is not a positive number")
+ }
+
+ pub := &rsa.PublicKey{
+ E: p.E,
+ N: p.N,
+ }
+ return pub, nil
+ case oid.Equal(oidPublicKeyECDSA):
+ paramsDer := cryptobyte.String(params.FullBytes)
+ namedCurveOID := new(asn1.ObjectIdentifier)
+ if !paramsDer.ReadASN1ObjectIdentifier(namedCurveOID) {
+ return nil, errors.New("x509: invalid ECDSA parameters")
+ }
+ namedCurve := namedCurveFromOID(*namedCurveOID)
+ if namedCurve == nil {
+ return nil, errors.New("x509: unsupported elliptic curve")
+ }
+ x, y := elliptic.Unmarshal(namedCurve, der)
+ if x == nil {
+ return nil, errors.New("x509: failed to unmarshal elliptic curve point")
+ }
+ pub := &ecdsa.PublicKey{
+ Curve: namedCurve,
+ X: x,
+ Y: y,
+ }
+ return pub, nil
+ case oid.Equal(oidPublicKeyEd25519):
+ // RFC 8410, Section 3
+ // > For all of the OIDs, the parameters MUST be absent.
+ if len(params.FullBytes) != 0 {
+ return nil, errors.New("x509: Ed25519 key encoded with illegal parameters")
+ }
+ if len(der) != ed25519.PublicKeySize {
+ return nil, errors.New("x509: wrong Ed25519 public key size")
+ }
+ return ed25519.PublicKey(der), nil
+ case oid.Equal(oidPublicKeyX25519):
+ // RFC 8410, Section 3
+ // > For all of the OIDs, the parameters MUST be absent.
+ if len(params.FullBytes) != 0 {
+ return nil, errors.New("x509: X25519 key encoded with illegal parameters")
+ }
+ return ecdh.X25519().NewPublicKey(der)
+ case oid.Equal(oidPublicKeyDSA):
+ y := new(big.Int)
+ if !der.ReadASN1Integer(y) {
+ return nil, errors.New("x509: invalid DSA public key")
+ }
+ pub := &dsa.PublicKey{
+ Y: y,
+ Parameters: dsa.Parameters{
+ P: new(big.Int),
+ Q: new(big.Int),
+ G: new(big.Int),
+ },
+ }
+ paramsDer := cryptobyte.String(params.FullBytes)
+ if !paramsDer.ReadASN1(&paramsDer, cryptobyte_asn1.SEQUENCE) ||
+ !paramsDer.ReadASN1Integer(pub.Parameters.P) ||
+ !paramsDer.ReadASN1Integer(pub.Parameters.Q) ||
+ !paramsDer.ReadASN1Integer(pub.Parameters.G) {
+ return nil, errors.New("x509: invalid DSA parameters")
+ }
+ if pub.Y.Sign() <= 0 || pub.Parameters.P.Sign() <= 0 ||
+ pub.Parameters.Q.Sign() <= 0 || pub.Parameters.G.Sign() <= 0 {
+ return nil, errors.New("x509: zero or negative DSA parameter")
+ }
+ return pub, nil
+ default:
+ return nil, errors.New("x509: unknown public key algorithm")
+ }
+}
+
+func parseKeyUsageExtension(der cryptobyte.String) (KeyUsage, error) {
+ var usageBits asn1.BitString
+ if !der.ReadASN1BitString(&usageBits) {
+ return 0, errors.New("x509: invalid key usage")
+ }
+
+ var usage int
+ for i := 0; i < 9; i++ {
+ if usageBits.At(i) != 0 {
+ usage |= 1 << uint(i)
+ }
+ }
+ return KeyUsage(usage), nil
+}
+
+func parseBasicConstraintsExtension(der cryptobyte.String) (bool, int, error) {
+ var isCA bool
+ if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) {
+ return false, 0, errors.New("x509: invalid basic constraints a")
+ }
+ if der.PeekASN1Tag(cryptobyte_asn1.BOOLEAN) {
+ if !der.ReadASN1Boolean(&isCA) {
+ return false, 0, errors.New("x509: invalid basic constraints b")
+ }
+ }
+ maxPathLen := -1
+ if !der.Empty() && der.PeekASN1Tag(cryptobyte_asn1.INTEGER) {
+ if !der.ReadASN1Integer(&maxPathLen) {
+ return false, 0, errors.New("x509: invalid basic constraints c")
+ }
+ }
+
+ // TODO: map out.MaxPathLen to 0 if it has the -1 default value? (Issue 19285)
+ return isCA, maxPathLen, nil
+}
+
+func forEachSAN(der cryptobyte.String, callback func(tag int, data []byte) error) error {
+ if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) {
+ return errors.New("x509: invalid subject alternative names")
+ }
+ for !der.Empty() {
+ var san cryptobyte.String
+ var tag cryptobyte_asn1.Tag
+ if !der.ReadAnyASN1(&san, &tag) {
+ return errors.New("x509: invalid subject alternative name")
+ }
+ if err := callback(int(tag^0x80), san); err != nil {
+ return err
+ }
+ }
+
+ return nil
+}
+
+func parseSANExtension(der cryptobyte.String) (dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL, err error) {
+ err = forEachSAN(der, func(tag int, data []byte) error {
+ switch tag {
+ case nameTypeEmail:
+ email := string(data)
+ if err := isIA5String(email); err != nil {
+ return errors.New("x509: SAN rfc822Name is malformed")
+ }
+ emailAddresses = append(emailAddresses, email)
+ case nameTypeDNS:
+ name := string(data)
+ if err := isIA5String(name); err != nil {
+ return errors.New("x509: SAN dNSName is malformed")
+ }
+ dnsNames = append(dnsNames, string(name))
+ case nameTypeURI:
+ uriStr := string(data)
+ if err := isIA5String(uriStr); err != nil {
+ return errors.New("x509: SAN uniformResourceIdentifier is malformed")
+ }
+ uri, err := url.Parse(uriStr)
+ if err != nil {
+ return fmt.Errorf("x509: cannot parse URI %q: %s", uriStr, err)
+ }
+ if len(uri.Host) > 0 {
+ if _, ok := domainToReverseLabels(uri.Host); !ok {
+ return fmt.Errorf("x509: cannot parse URI %q: invalid domain", uriStr)
+ }
+ }
+ uris = append(uris, uri)
+ case nameTypeIP:
+ switch len(data) {
+ case net.IPv4len, net.IPv6len:
+ ipAddresses = append(ipAddresses, data)
+ default:
+ return errors.New("x509: cannot parse IP address of length " + strconv.Itoa(len(data)))
+ }
+ }
+
+ return nil
+ })
+
+ return
+}
+
+func parseExtKeyUsageExtension(der cryptobyte.String) ([]ExtKeyUsage, []asn1.ObjectIdentifier, error) {
+ var extKeyUsages []ExtKeyUsage
+ var unknownUsages []asn1.ObjectIdentifier
+ if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) {
+ return nil, nil, errors.New("x509: invalid extended key usages")
+ }
+ for !der.Empty() {
+ var eku asn1.ObjectIdentifier
+ if !der.ReadASN1ObjectIdentifier(&eku) {
+ return nil, nil, errors.New("x509: invalid extended key usages")
+ }
+ if extKeyUsage, ok := extKeyUsageFromOID(eku); ok {
+ extKeyUsages = append(extKeyUsages, extKeyUsage)
+ } else {
+ unknownUsages = append(unknownUsages, eku)
+ }
+ }
+ return extKeyUsages, unknownUsages, nil
+}
+
+func parseCertificatePoliciesExtension(der cryptobyte.String) ([]asn1.ObjectIdentifier, error) {
+ var oids []asn1.ObjectIdentifier
+ if !der.ReadASN1(&der, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: invalid certificate policies")
+ }
+ for !der.Empty() {
+ var cp cryptobyte.String
+ if !der.ReadASN1(&cp, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: invalid certificate policies")
+ }
+ var oid asn1.ObjectIdentifier
+ if !cp.ReadASN1ObjectIdentifier(&oid) {
+ return nil, errors.New("x509: invalid certificate policies")
+ }
+ oids = append(oids, oid)
+ }
+
+ return oids, nil
+}
+
+// isValidIPMask reports whether mask consists of zero or more 1 bits, followed by zero bits.
+func isValidIPMask(mask []byte) bool {
+ seenZero := false
+
+ for _, b := range mask {
+ if seenZero {
+ if b != 0 {
+ return false
+ }
+
+ continue
+ }
+
+ switch b {
+ case 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe:
+ seenZero = true
+ case 0xff:
+ default:
+ return false
+ }
+ }
+
+ return true
+}
+
+func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandled bool, err error) {
+ // RFC 5280, 4.2.1.10
+
+ // NameConstraints ::= SEQUENCE {
+ // permittedSubtrees [0] GeneralSubtrees OPTIONAL,
+ // excludedSubtrees [1] GeneralSubtrees OPTIONAL }
+ //
+ // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
+ //
+ // GeneralSubtree ::= SEQUENCE {
+ // base GeneralName,
+ // minimum [0] BaseDistance DEFAULT 0,
+ // maximum [1] BaseDistance OPTIONAL }
+ //
+ // BaseDistance ::= INTEGER (0..MAX)
+
+ outer := cryptobyte.String(e.Value)
+ var toplevel, permitted, excluded cryptobyte.String
+ var havePermitted, haveExcluded bool
+ if !outer.ReadASN1(&toplevel, cryptobyte_asn1.SEQUENCE) ||
+ !outer.Empty() ||
+ !toplevel.ReadOptionalASN1(&permitted, &havePermitted, cryptobyte_asn1.Tag(0).ContextSpecific().Constructed()) ||
+ !toplevel.ReadOptionalASN1(&excluded, &haveExcluded, cryptobyte_asn1.Tag(1).ContextSpecific().Constructed()) ||
+ !toplevel.Empty() {
+ return false, errors.New("x509: invalid NameConstraints extension")
+ }
+
+ if !havePermitted && !haveExcluded || len(permitted) == 0 && len(excluded) == 0 {
+ // From RFC 5280, Section 4.2.1.10:
+ // “either the permittedSubtrees field
+ // or the excludedSubtrees MUST be
+ // present”
+ return false, errors.New("x509: empty name constraints extension")
+ }
+
+ getValues := func(subtrees cryptobyte.String) (dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) {
+ for !subtrees.Empty() {
+ var seq, value cryptobyte.String
+ var tag cryptobyte_asn1.Tag
+ if !subtrees.ReadASN1(&seq, cryptobyte_asn1.SEQUENCE) ||
+ !seq.ReadAnyASN1(&value, &tag) {
+ return nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension")
+ }
+
+ var (
+ dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific()
+ emailTag = cryptobyte_asn1.Tag(1).ContextSpecific()
+ ipTag = cryptobyte_asn1.Tag(7).ContextSpecific()
+ uriTag = cryptobyte_asn1.Tag(6).ContextSpecific()
+ )
+
+ switch tag {
+ case dnsTag:
+ domain := string(value)
+ if err := isIA5String(domain); err != nil {
+ return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
+ }
+
+ trimmedDomain := domain
+ if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' {
+ // constraints can have a leading
+ // period to exclude the domain
+ // itself, but that's not valid in a
+ // normal domain name.
+ trimmedDomain = trimmedDomain[1:]
+ }
+ if _, ok := domainToReverseLabels(trimmedDomain); !ok {
+ return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain)
+ }
+ dnsNames = append(dnsNames, domain)
+
+ case ipTag:
+ l := len(value)
+ var ip, mask []byte
+
+ switch l {
+ case 8:
+ ip = value[:4]
+ mask = value[4:]
+
+ case 32:
+ ip = value[:16]
+ mask = value[16:]
+
+ default:
+ return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l)
+ }
+
+ if !isValidIPMask(mask) {
+ return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask)
+ }
+
+ ips = append(ips, &net.IPNet{IP: net.IP(ip), Mask: net.IPMask(mask)})
+
+ case emailTag:
+ constraint := string(value)
+ if err := isIA5String(constraint); err != nil {
+ return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
+ }
+
+ // If the constraint contains an @ then
+ // it specifies an exact mailbox name.
+ if strings.Contains(constraint, "@") {
+ if _, ok := parseRFC2821Mailbox(constraint); !ok {
+ return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
+ }
+ } else {
+ // Otherwise it's a domain name.
+ domain := constraint
+ if len(domain) > 0 && domain[0] == '.' {
+ domain = domain[1:]
+ }
+ if _, ok := domainToReverseLabels(domain); !ok {
+ return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
+ }
+ }
+ emails = append(emails, constraint)
+
+ case uriTag:
+ domain := string(value)
+ if err := isIA5String(domain); err != nil {
+ return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
+ }
+
+ if net.ParseIP(domain) != nil {
+ return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain)
+ }
+
+ trimmedDomain := domain
+ if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' {
+ // constraints can have a leading
+ // period to exclude the domain itself,
+ // but that's not valid in a normal
+ // domain name.
+ trimmedDomain = trimmedDomain[1:]
+ }
+ if _, ok := domainToReverseLabels(trimmedDomain); !ok {
+ return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain)
+ }
+ uriDomains = append(uriDomains, domain)
+
+ default:
+ unhandled = true
+ }
+ }
+
+ return dnsNames, ips, emails, uriDomains, nil
+ }
+
+ if out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil {
+ return false, err
+ }
+ if out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil {
+ return false, err
+ }
+ out.PermittedDNSDomainsCritical = e.Critical
+
+ return unhandled, nil
+}
+
+func processExtensions(out *Certificate) error {
+ var err error
+ for _, e := range out.Extensions {
+ unhandled := false
+
+ if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 {
+ switch e.Id[3] {
+ case 15:
+ out.KeyUsage, err = parseKeyUsageExtension(e.Value)
+ if err != nil {
+ return err
+ }
+ case 19:
+ out.IsCA, out.MaxPathLen, err = parseBasicConstraintsExtension(e.Value)
+ if err != nil {
+ return err
+ }
+ out.BasicConstraintsValid = true
+ out.MaxPathLenZero = out.MaxPathLen == 0
+ case 17:
+ out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(e.Value)
+ if err != nil {
+ return err
+ }
+
+ if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 && len(out.URIs) == 0 {
+ // If we didn't parse anything then we do the critical check, below.
+ unhandled = true
+ }
+
+ case 30:
+ unhandled, err = parseNameConstraintsExtension(out, e)
+ if err != nil {
+ return err
+ }
+
+ case 31:
+ // RFC 5280, 4.2.1.13
+
+ // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
+ //
+ // DistributionPoint ::= SEQUENCE {
+ // distributionPoint [0] DistributionPointName OPTIONAL,
+ // reasons [1] ReasonFlags OPTIONAL,
+ // cRLIssuer [2] GeneralNames OPTIONAL }
+ //
+ // DistributionPointName ::= CHOICE {
+ // fullName [0] GeneralNames,
+ // nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
+ val := cryptobyte.String(e.Value)
+ if !val.ReadASN1(&val, cryptobyte_asn1.SEQUENCE) {
+ return errors.New("x509: invalid CRL distribution points")
+ }
+ for !val.Empty() {
+ var dpDER cryptobyte.String
+ if !val.ReadASN1(&dpDER, cryptobyte_asn1.SEQUENCE) {
+ return errors.New("x509: invalid CRL distribution point")
+ }
+ var dpNameDER cryptobyte.String
+ var dpNamePresent bool
+ if !dpDER.ReadOptionalASN1(&dpNameDER, &dpNamePresent, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) {
+ return errors.New("x509: invalid CRL distribution point")
+ }
+ if !dpNamePresent {
+ continue
+ }
+ if !dpNameDER.ReadASN1(&dpNameDER, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) {
+ return errors.New("x509: invalid CRL distribution point")
+ }
+ for !dpNameDER.Empty() {
+ if !dpNameDER.PeekASN1Tag(cryptobyte_asn1.Tag(6).ContextSpecific()) {
+ break
+ }
+ var uri cryptobyte.String
+ if !dpNameDER.ReadASN1(&uri, cryptobyte_asn1.Tag(6).ContextSpecific()) {
+ return errors.New("x509: invalid CRL distribution point")
+ }
+ out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(uri))
+ }
+ }
+
+ case 35:
+ // RFC 5280, 4.2.1.1
+ val := cryptobyte.String(e.Value)
+ var akid cryptobyte.String
+ if !val.ReadASN1(&akid, cryptobyte_asn1.SEQUENCE) {
+ return errors.New("x509: invalid authority key identifier")
+ }
+ if akid.PeekASN1Tag(cryptobyte_asn1.Tag(0).ContextSpecific()) {
+ if !akid.ReadASN1(&akid, cryptobyte_asn1.Tag(0).ContextSpecific()) {
+ return errors.New("x509: invalid authority key identifier")
+ }
+ out.AuthorityKeyId = akid
+ }
+ case 37:
+ out.ExtKeyUsage, out.UnknownExtKeyUsage, err = parseExtKeyUsageExtension(e.Value)
+ if err != nil {
+ return err
+ }
+ case 14:
+ // RFC 5280, 4.2.1.2
+ val := cryptobyte.String(e.Value)
+ var skid cryptobyte.String
+ if !val.ReadASN1(&skid, cryptobyte_asn1.OCTET_STRING) {
+ return errors.New("x509: invalid subject key identifier")
+ }
+ out.SubjectKeyId = skid
+ case 32:
+ out.PolicyIdentifiers, err = parseCertificatePoliciesExtension(e.Value)
+ if err != nil {
+ return err
+ }
+ default:
+ // Unknown extensions are recorded if critical.
+ unhandled = true
+ }
+ } else if e.Id.Equal(oidExtensionAuthorityInfoAccess) {
+ // RFC 5280 4.2.2.1: Authority Information Access
+ val := cryptobyte.String(e.Value)
+ if !val.ReadASN1(&val, cryptobyte_asn1.SEQUENCE) {
+ return errors.New("x509: invalid authority info access")
+ }
+ for !val.Empty() {
+ var aiaDER cryptobyte.String
+ if !val.ReadASN1(&aiaDER, cryptobyte_asn1.SEQUENCE) {
+ return errors.New("x509: invalid authority info access")
+ }
+ var method asn1.ObjectIdentifier
+ if !aiaDER.ReadASN1ObjectIdentifier(&method) {
+ return errors.New("x509: invalid authority info access")
+ }
+ if !aiaDER.PeekASN1Tag(cryptobyte_asn1.Tag(6).ContextSpecific()) {
+ continue
+ }
+ if !aiaDER.ReadASN1(&aiaDER, cryptobyte_asn1.Tag(6).ContextSpecific()) {
+ return errors.New("x509: invalid authority info access")
+ }
+ switch {
+ case method.Equal(oidAuthorityInfoAccessOcsp):
+ out.OCSPServer = append(out.OCSPServer, string(aiaDER))
+ case method.Equal(oidAuthorityInfoAccessIssuers):
+ out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(aiaDER))
+ }
+ }
+ } else {
+ // Unknown extensions are recorded if critical.
+ unhandled = true
+ }
+
+ if e.Critical && unhandled {
+ out.UnhandledCriticalExtensions = append(out.UnhandledCriticalExtensions, e.Id)
+ }
+ }
+
+ return nil
+}
+
+func parseCertificate(der []byte) (*Certificate, error) {
+ cert := &Certificate{}
+
+ input := cryptobyte.String(der)
+ // we read the SEQUENCE including length and tag bytes so that
+ // we can populate Certificate.Raw, before unwrapping the
+ // SEQUENCE so it can be operated on
+ if !input.ReadASN1Element(&input, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed certificate")
+ }
+ cert.Raw = input
+ if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed certificate")
+ }
+
+ var tbs cryptobyte.String
+ // do the same trick again as above to extract the raw
+ // bytes for Certificate.RawTBSCertificate
+ if !input.ReadASN1Element(&tbs, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed tbs certificate")
+ }
+ cert.RawTBSCertificate = tbs
+ if !tbs.ReadASN1(&tbs, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed tbs certificate")
+ }
+
+ if !tbs.ReadOptionalASN1Integer(&cert.Version, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific(), 0) {
+ return nil, errors.New("x509: malformed version")
+ }
+ if cert.Version < 0 {
+ return nil, errors.New("x509: malformed version")
+ }
+ // for backwards compat reasons Version is one-indexed,
+ // rather than zero-indexed as defined in 5280
+ cert.Version++
+ if cert.Version > 3 {
+ return nil, errors.New("x509: invalid version")
+ }
+
+ serial := new(big.Int)
+ if !tbs.ReadASN1Integer(serial) {
+ return nil, errors.New("x509: malformed serial number")
+ }
+ // we ignore the presence of negative serial numbers because
+ // of their prevalence, despite them being invalid
+ // TODO(rolandshoemaker): revisit this decision, there are currently
+ // only 10 trusted certificates with negative serial numbers
+ // according to censys.io.
+ cert.SerialNumber = serial
+
+ var sigAISeq cryptobyte.String
+ if !tbs.ReadASN1(&sigAISeq, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed signature algorithm identifier")
+ }
+ // Before parsing the inner algorithm identifier, extract
+ // the outer algorithm identifier and make sure that they
+ // match.
+ var outerSigAISeq cryptobyte.String
+ if !input.ReadASN1(&outerSigAISeq, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed algorithm identifier")
+ }
+ if !bytes.Equal(outerSigAISeq, sigAISeq) {
+ return nil, errors.New("x509: inner and outer signature algorithm identifiers don't match")
+ }
+ sigAI, err := parseAI(sigAISeq)
+ if err != nil {
+ return nil, err
+ }
+ cert.SignatureAlgorithm = getSignatureAlgorithmFromAI(sigAI)
+
+ var issuerSeq cryptobyte.String
+ if !tbs.ReadASN1Element(&issuerSeq, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed issuer")
+ }
+ cert.RawIssuer = issuerSeq
+ issuerRDNs, err := parseName(issuerSeq)
+ if err != nil {
+ return nil, err
+ }
+ cert.Issuer.FillFromRDNSequence(issuerRDNs)
+
+ var validity cryptobyte.String
+ if !tbs.ReadASN1(&validity, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed validity")
+ }
+ cert.NotBefore, cert.NotAfter, err = parseValidity(validity)
+ if err != nil {
+ return nil, err
+ }
+
+ var subjectSeq cryptobyte.String
+ if !tbs.ReadASN1Element(&subjectSeq, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed issuer")
+ }
+ cert.RawSubject = subjectSeq
+ subjectRDNs, err := parseName(subjectSeq)
+ if err != nil {
+ return nil, err
+ }
+ cert.Subject.FillFromRDNSequence(subjectRDNs)
+
+ var spki cryptobyte.String
+ if !tbs.ReadASN1Element(&spki, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed spki")
+ }
+ cert.RawSubjectPublicKeyInfo = spki
+ if !spki.ReadASN1(&spki, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed spki")
+ }
+ var pkAISeq cryptobyte.String
+ if !spki.ReadASN1(&pkAISeq, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed public key algorithm identifier")
+ }
+ pkAI, err := parseAI(pkAISeq)
+ if err != nil {
+ return nil, err
+ }
+ cert.PublicKeyAlgorithm = getPublicKeyAlgorithmFromOID(pkAI.Algorithm)
+ var spk asn1.BitString
+ if !spki.ReadASN1BitString(&spk) {
+ return nil, errors.New("x509: malformed subjectPublicKey")
+ }
+ if cert.PublicKeyAlgorithm != UnknownPublicKeyAlgorithm {
+ cert.PublicKey, err = parsePublicKey(&publicKeyInfo{
+ Algorithm: pkAI,
+ PublicKey: spk,
+ })
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if cert.Version > 1 {
+ if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(1).ContextSpecific()) {
+ return nil, errors.New("x509: malformed issuerUniqueID")
+ }
+ if !tbs.SkipOptionalASN1(cryptobyte_asn1.Tag(2).ContextSpecific()) {
+ return nil, errors.New("x509: malformed subjectUniqueID")
+ }
+ if cert.Version == 3 {
+ var extensions cryptobyte.String
+ var present bool
+ if !tbs.ReadOptionalASN1(&extensions, &present, cryptobyte_asn1.Tag(3).Constructed().ContextSpecific()) {
+ return nil, errors.New("x509: malformed extensions")
+ }
+ if present {
+ seenExts := make(map[string]bool)
+ if !extensions.ReadASN1(&extensions, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed extensions")
+ }
+ for !extensions.Empty() {
+ var extension cryptobyte.String
+ if !extensions.ReadASN1(&extension, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed extension")
+ }
+ ext, err := parseExtension(extension)
+ if err != nil {
+ return nil, err
+ }
+ oidStr := ext.Id.String()
+ if seenExts[oidStr] {
+ return nil, errors.New("x509: certificate contains duplicate extensions")
+ }
+ seenExts[oidStr] = true
+ cert.Extensions = append(cert.Extensions, ext)
+ }
+ err = processExtensions(cert)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+ }
+
+ var signature asn1.BitString
+ if !input.ReadASN1BitString(&signature) {
+ return nil, errors.New("x509: malformed signature")
+ }
+ cert.Signature = signature.RightAlign()
+
+ return cert, nil
+}
+
+// ParseCertificate parses a single certificate from the given ASN.1 DER data.
+func ParseCertificate(der []byte) (*Certificate, error) {
+ cert, err := parseCertificate(der)
+ if err != nil {
+ return nil, err
+ }
+ if len(der) != len(cert.Raw) {
+ return nil, errors.New("x509: trailing data")
+ }
+ return cert, err
+}
+
+// ParseCertificates parses one or more certificates from the given ASN.1 DER
+// data. The certificates must be concatenated with no intermediate padding.
+func ParseCertificates(der []byte) ([]*Certificate, error) {
+ var certs []*Certificate
+ for len(der) > 0 {
+ cert, err := parseCertificate(der)
+ if err != nil {
+ return nil, err
+ }
+ certs = append(certs, cert)
+ der = der[len(cert.Raw):]
+ }
+ return certs, nil
+}
+
+// The X.509 standards confusingly 1-indexed the version names, but 0-indexed
+// the actual encoded version, so the version for X.509v2 is 1.
+const x509v2Version = 1
+
+// ParseRevocationList parses a X509 v2 Certificate Revocation List from the given
+// ASN.1 DER data.
+func ParseRevocationList(der []byte) (*RevocationList, error) {
+ rl := &RevocationList{}
+
+ input := cryptobyte.String(der)
+ // we read the SEQUENCE including length and tag bytes so that
+ // we can populate RevocationList.Raw, before unwrapping the
+ // SEQUENCE so it can be operated on
+ if !input.ReadASN1Element(&input, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed crl")
+ }
+ rl.Raw = input
+ if !input.ReadASN1(&input, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed crl")
+ }
+
+ var tbs cryptobyte.String
+ // do the same trick again as above to extract the raw
+ // bytes for Certificate.RawTBSCertificate
+ if !input.ReadASN1Element(&tbs, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed tbs crl")
+ }
+ rl.RawTBSRevocationList = tbs
+ if !tbs.ReadASN1(&tbs, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed tbs crl")
+ }
+
+ var version int
+ if !tbs.PeekASN1Tag(cryptobyte_asn1.INTEGER) {
+ return nil, errors.New("x509: unsupported crl version")
+ }
+ if !tbs.ReadASN1Integer(&version) {
+ return nil, errors.New("x509: malformed crl")
+ }
+ if version != x509v2Version {
+ return nil, fmt.Errorf("x509: unsupported crl version: %d", version)
+ }
+
+ var sigAISeq cryptobyte.String
+ if !tbs.ReadASN1(&sigAISeq, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed signature algorithm identifier")
+ }
+ // Before parsing the inner algorithm identifier, extract
+ // the outer algorithm identifier and make sure that they
+ // match.
+ var outerSigAISeq cryptobyte.String
+ if !input.ReadASN1(&outerSigAISeq, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed algorithm identifier")
+ }
+ if !bytes.Equal(outerSigAISeq, sigAISeq) {
+ return nil, errors.New("x509: inner and outer signature algorithm identifiers don't match")
+ }
+ sigAI, err := parseAI(sigAISeq)
+ if err != nil {
+ return nil, err
+ }
+ rl.SignatureAlgorithm = getSignatureAlgorithmFromAI(sigAI)
+
+ var signature asn1.BitString
+ if !input.ReadASN1BitString(&signature) {
+ return nil, errors.New("x509: malformed signature")
+ }
+ rl.Signature = signature.RightAlign()
+
+ var issuerSeq cryptobyte.String
+ if !tbs.ReadASN1Element(&issuerSeq, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed issuer")
+ }
+ rl.RawIssuer = issuerSeq
+ issuerRDNs, err := parseName(issuerSeq)
+ if err != nil {
+ return nil, err
+ }
+ rl.Issuer.FillFromRDNSequence(issuerRDNs)
+
+ rl.ThisUpdate, err = parseTime(&tbs)
+ if err != nil {
+ return nil, err
+ }
+ if tbs.PeekASN1Tag(cryptobyte_asn1.GeneralizedTime) || tbs.PeekASN1Tag(cryptobyte_asn1.UTCTime) {
+ rl.NextUpdate, err = parseTime(&tbs)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if tbs.PeekASN1Tag(cryptobyte_asn1.SEQUENCE) {
+ var revokedSeq cryptobyte.String
+ if !tbs.ReadASN1(&revokedSeq, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed crl")
+ }
+ for !revokedSeq.Empty() {
+ var certSeq cryptobyte.String
+ if !revokedSeq.ReadASN1(&certSeq, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed crl")
+ }
+ rc := pkix.RevokedCertificate{}
+ rc.SerialNumber = new(big.Int)
+ if !certSeq.ReadASN1Integer(rc.SerialNumber) {
+ return nil, errors.New("x509: malformed serial number")
+ }
+ rc.RevocationTime, err = parseTime(&certSeq)
+ if err != nil {
+ return nil, err
+ }
+ var extensions cryptobyte.String
+ var present bool
+ if !certSeq.ReadOptionalASN1(&extensions, &present, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed extensions")
+ }
+ if present {
+ for !extensions.Empty() {
+ var extension cryptobyte.String
+ if !extensions.ReadASN1(&extension, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed extension")
+ }
+ ext, err := parseExtension(extension)
+ if err != nil {
+ return nil, err
+ }
+ rc.Extensions = append(rc.Extensions, ext)
+ }
+ }
+
+ rl.RevokedCertificates = append(rl.RevokedCertificates, rc)
+ }
+ }
+
+ var extensions cryptobyte.String
+ var present bool
+ if !tbs.ReadOptionalASN1(&extensions, &present, cryptobyte_asn1.Tag(0).Constructed().ContextSpecific()) {
+ return nil, errors.New("x509: malformed extensions")
+ }
+ if present {
+ if !extensions.ReadASN1(&extensions, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed extensions")
+ }
+ for !extensions.Empty() {
+ var extension cryptobyte.String
+ if !extensions.ReadASN1(&extension, cryptobyte_asn1.SEQUENCE) {
+ return nil, errors.New("x509: malformed extension")
+ }
+ ext, err := parseExtension(extension)
+ if err != nil {
+ return nil, err
+ }
+ if ext.Id.Equal(oidExtensionAuthorityKeyId) {
+ rl.AuthorityKeyId = ext.Value
+ } else if ext.Id.Equal(oidExtensionCRLNumber) {
+ value := cryptobyte.String(ext.Value)
+ rl.Number = new(big.Int)
+ if !value.ReadASN1Integer(rl.Number) {
+ return nil, errors.New("x509: malformed crl number")
+ }
+ }
+ rl.Extensions = append(rl.Extensions, ext)
+ }
+ }
+
+ return rl, nil
+}
diff --git a/src/crypto/x509/parser_test.go b/src/crypto/x509/parser_test.go
new file mode 100644
index 0000000..b31f9cd
--- /dev/null
+++ b/src/crypto/x509/parser_test.go
@@ -0,0 +1,103 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "encoding/asn1"
+ "testing"
+
+ cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
+)
+
+func TestParseASN1String(t *testing.T) {
+ tests := []struct {
+ name string
+ tag cryptobyte_asn1.Tag
+ value []byte
+ expected string
+ expectedErr string
+ }{
+ {
+ name: "T61String",
+ tag: cryptobyte_asn1.T61String,
+ value: []byte{80, 81, 82},
+ expected: string("PQR"),
+ },
+ {
+ name: "PrintableString",
+ tag: cryptobyte_asn1.PrintableString,
+ value: []byte{80, 81, 82},
+ expected: string("PQR"),
+ },
+ {
+ name: "PrintableString (invalid)",
+ tag: cryptobyte_asn1.PrintableString,
+ value: []byte{1, 2, 3},
+ expectedErr: "invalid PrintableString",
+ },
+ {
+ name: "UTF8String",
+ tag: cryptobyte_asn1.UTF8String,
+ value: []byte{80, 81, 82},
+ expected: string("PQR"),
+ },
+ {
+ name: "UTF8String (invalid)",
+ tag: cryptobyte_asn1.UTF8String,
+ value: []byte{255},
+ expectedErr: "invalid UTF-8 string",
+ },
+ {
+ name: "BMPString",
+ tag: cryptobyte_asn1.Tag(asn1.TagBMPString),
+ value: []byte{80, 81},
+ expected: string("偑"),
+ },
+ {
+ name: "BMPString (invalid length)",
+ tag: cryptobyte_asn1.Tag(asn1.TagBMPString),
+ value: []byte{255},
+ expectedErr: "invalid BMPString",
+ },
+ {
+ name: "IA5String",
+ tag: cryptobyte_asn1.IA5String,
+ value: []byte{80, 81},
+ expected: string("PQ"),
+ },
+ {
+ name: "IA5String (invalid)",
+ tag: cryptobyte_asn1.IA5String,
+ value: []byte{255},
+ expectedErr: "invalid IA5String",
+ },
+ {
+ name: "NumericString",
+ tag: cryptobyte_asn1.Tag(asn1.TagNumericString),
+ value: []byte{49, 50},
+ expected: string("12"),
+ },
+ {
+ name: "NumericString (invalid)",
+ tag: cryptobyte_asn1.Tag(asn1.TagNumericString),
+ value: []byte{80},
+ expectedErr: "invalid NumericString",
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ out, err := parseASN1String(tc.tag, tc.value)
+ if err != nil && err.Error() != tc.expectedErr {
+ t.Fatalf("parseASN1String returned unexpected error: got %q, want %q", err, tc.expectedErr)
+ } else if err == nil && tc.expectedErr != "" {
+ t.Fatalf("parseASN1String didn't fail, expected: %s", tc.expectedErr)
+ }
+ if out != tc.expected {
+ t.Fatalf("parseASN1String returned unexpected value: got %q, want %q", out, tc.expected)
+ }
+ })
+ }
+}
diff --git a/src/crypto/x509/pem_decrypt.go b/src/crypto/x509/pem_decrypt.go
new file mode 100644
index 0000000..682923a
--- /dev/null
+++ b/src/crypto/x509/pem_decrypt.go
@@ -0,0 +1,252 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+// RFC 1423 describes the encryption of PEM blocks. The algorithm used to
+// generate a key from the password was derived by looking at the OpenSSL
+// implementation.
+
+import (
+ "crypto/aes"
+ "crypto/cipher"
+ "crypto/des"
+ "crypto/md5"
+ "encoding/hex"
+ "encoding/pem"
+ "errors"
+ "io"
+ "strings"
+)
+
+type PEMCipher int
+
+// Possible values for the EncryptPEMBlock encryption algorithm.
+const (
+ _ PEMCipher = iota
+ PEMCipherDES
+ PEMCipher3DES
+ PEMCipherAES128
+ PEMCipherAES192
+ PEMCipherAES256
+)
+
+// rfc1423Algo holds a method for enciphering a PEM block.
+type rfc1423Algo struct {
+ cipher PEMCipher
+ name string
+ cipherFunc func(key []byte) (cipher.Block, error)
+ keySize int
+ blockSize int
+}
+
+// rfc1423Algos holds a slice of the possible ways to encrypt a PEM
+// block. The ivSize numbers were taken from the OpenSSL source.
+var rfc1423Algos = []rfc1423Algo{{
+ cipher: PEMCipherDES,
+ name: "DES-CBC",
+ cipherFunc: des.NewCipher,
+ keySize: 8,
+ blockSize: des.BlockSize,
+}, {
+ cipher: PEMCipher3DES,
+ name: "DES-EDE3-CBC",
+ cipherFunc: des.NewTripleDESCipher,
+ keySize: 24,
+ blockSize: des.BlockSize,
+}, {
+ cipher: PEMCipherAES128,
+ name: "AES-128-CBC",
+ cipherFunc: aes.NewCipher,
+ keySize: 16,
+ blockSize: aes.BlockSize,
+}, {
+ cipher: PEMCipherAES192,
+ name: "AES-192-CBC",
+ cipherFunc: aes.NewCipher,
+ keySize: 24,
+ blockSize: aes.BlockSize,
+}, {
+ cipher: PEMCipherAES256,
+ name: "AES-256-CBC",
+ cipherFunc: aes.NewCipher,
+ keySize: 32,
+ blockSize: aes.BlockSize,
+},
+}
+
+// deriveKey uses a key derivation function to stretch the password into a key
+// with the number of bits our cipher requires. This algorithm was derived from
+// the OpenSSL source.
+func (c rfc1423Algo) deriveKey(password, salt []byte) []byte {
+ hash := md5.New()
+ out := make([]byte, c.keySize)
+ var digest []byte
+
+ for i := 0; i < len(out); i += len(digest) {
+ hash.Reset()
+ hash.Write(digest)
+ hash.Write(password)
+ hash.Write(salt)
+ digest = hash.Sum(digest[:0])
+ copy(out[i:], digest)
+ }
+ return out
+}
+
+// IsEncryptedPEMBlock returns whether the PEM block is password encrypted
+// according to RFC 1423.
+//
+// Deprecated: Legacy PEM encryption as specified in RFC 1423 is insecure by
+// design. Since it does not authenticate the ciphertext, it is vulnerable to
+// padding oracle attacks that can let an attacker recover the plaintext.
+func IsEncryptedPEMBlock(b *pem.Block) bool {
+ _, ok := b.Headers["DEK-Info"]
+ return ok
+}
+
+// IncorrectPasswordError is returned when an incorrect password is detected.
+var IncorrectPasswordError = errors.New("x509: decryption password incorrect")
+
+// DecryptPEMBlock takes a PEM block encrypted according to RFC 1423 and the
+// password used to encrypt it and returns a slice of decrypted DER encoded
+// bytes. It inspects the DEK-Info header to determine the algorithm used for
+// decryption. If no DEK-Info header is present, an error is returned. If an
+// incorrect password is detected an IncorrectPasswordError is returned. Because
+// of deficiencies in the format, it's not always possible to detect an
+// incorrect password. In these cases no error will be returned but the
+// decrypted DER bytes will be random noise.
+//
+// Deprecated: Legacy PEM encryption as specified in RFC 1423 is insecure by
+// design. Since it does not authenticate the ciphertext, it is vulnerable to
+// padding oracle attacks that can let an attacker recover the plaintext.
+func DecryptPEMBlock(b *pem.Block, password []byte) ([]byte, error) {
+ dek, ok := b.Headers["DEK-Info"]
+ if !ok {
+ return nil, errors.New("x509: no DEK-Info header in block")
+ }
+
+ mode, hexIV, ok := strings.Cut(dek, ",")
+ if !ok {
+ return nil, errors.New("x509: malformed DEK-Info header")
+ }
+
+ ciph := cipherByName(mode)
+ if ciph == nil {
+ return nil, errors.New("x509: unknown encryption mode")
+ }
+ iv, err := hex.DecodeString(hexIV)
+ if err != nil {
+ return nil, err
+ }
+ if len(iv) != ciph.blockSize {
+ return nil, errors.New("x509: incorrect IV size")
+ }
+
+ // Based on the OpenSSL implementation. The salt is the first 8 bytes
+ // of the initialization vector.
+ key := ciph.deriveKey(password, iv[:8])
+ block, err := ciph.cipherFunc(key)
+ if err != nil {
+ return nil, err
+ }
+
+ if len(b.Bytes)%block.BlockSize() != 0 {
+ return nil, errors.New("x509: encrypted PEM data is not a multiple of the block size")
+ }
+
+ data := make([]byte, len(b.Bytes))
+ dec := cipher.NewCBCDecrypter(block, iv)
+ dec.CryptBlocks(data, b.Bytes)
+
+ // Blocks are padded using a scheme where the last n bytes of padding are all
+ // equal to n. It can pad from 1 to blocksize bytes inclusive. See RFC 1423.
+ // For example:
+ // [x y z 2 2]
+ // [x y 7 7 7 7 7 7 7]
+ // If we detect a bad padding, we assume it is an invalid password.
+ dlen := len(data)
+ if dlen == 0 || dlen%ciph.blockSize != 0 {
+ return nil, errors.New("x509: invalid padding")
+ }
+ last := int(data[dlen-1])
+ if dlen < last {
+ return nil, IncorrectPasswordError
+ }
+ if last == 0 || last > ciph.blockSize {
+ return nil, IncorrectPasswordError
+ }
+ for _, val := range data[dlen-last:] {
+ if int(val) != last {
+ return nil, IncorrectPasswordError
+ }
+ }
+ return data[:dlen-last], nil
+}
+
+// EncryptPEMBlock returns a PEM block of the specified type holding the
+// given DER encoded data encrypted with the specified algorithm and
+// password according to RFC 1423.
+//
+// Deprecated: Legacy PEM encryption as specified in RFC 1423 is insecure by
+// design. Since it does not authenticate the ciphertext, it is vulnerable to
+// padding oracle attacks that can let an attacker recover the plaintext.
+func EncryptPEMBlock(rand io.Reader, blockType string, data, password []byte, alg PEMCipher) (*pem.Block, error) {
+ ciph := cipherByKey(alg)
+ if ciph == nil {
+ return nil, errors.New("x509: unknown encryption mode")
+ }
+ iv := make([]byte, ciph.blockSize)
+ if _, err := io.ReadFull(rand, iv); err != nil {
+ return nil, errors.New("x509: cannot generate IV: " + err.Error())
+ }
+ // The salt is the first 8 bytes of the initialization vector,
+ // matching the key derivation in DecryptPEMBlock.
+ key := ciph.deriveKey(password, iv[:8])
+ block, err := ciph.cipherFunc(key)
+ if err != nil {
+ return nil, err
+ }
+ enc := cipher.NewCBCEncrypter(block, iv)
+ pad := ciph.blockSize - len(data)%ciph.blockSize
+ encrypted := make([]byte, len(data), len(data)+pad)
+ // We could save this copy by encrypting all the whole blocks in
+ // the data separately, but it doesn't seem worth the additional
+ // code.
+ copy(encrypted, data)
+ // See RFC 1423, Section 1.1.
+ for i := 0; i < pad; i++ {
+ encrypted = append(encrypted, byte(pad))
+ }
+ enc.CryptBlocks(encrypted, encrypted)
+
+ return &pem.Block{
+ Type: blockType,
+ Headers: map[string]string{
+ "Proc-Type": "4,ENCRYPTED",
+ "DEK-Info": ciph.name + "," + hex.EncodeToString(iv),
+ },
+ Bytes: encrypted,
+ }, nil
+}
+
+func cipherByName(name string) *rfc1423Algo {
+ for i := range rfc1423Algos {
+ alg := &rfc1423Algos[i]
+ if alg.name == name {
+ return alg
+ }
+ }
+ return nil
+}
+
+func cipherByKey(key PEMCipher) *rfc1423Algo {
+ for i := range rfc1423Algos {
+ alg := &rfc1423Algos[i]
+ if alg.cipher == key {
+ return alg
+ }
+ }
+ return nil
+}
diff --git a/src/crypto/x509/pem_decrypt_test.go b/src/crypto/x509/pem_decrypt_test.go
new file mode 100644
index 0000000..dacef8b
--- /dev/null
+++ b/src/crypto/x509/pem_decrypt_test.go
@@ -0,0 +1,249 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "bytes"
+ "crypto/rand"
+ "encoding/base64"
+ "encoding/pem"
+ "strings"
+ "testing"
+)
+
+func TestDecrypt(t *testing.T) {
+ for i, data := range testData {
+ t.Logf("test %v. %v", i, data.kind)
+ block, rest := pem.Decode(data.pemData)
+ if len(rest) > 0 {
+ t.Error("extra data")
+ }
+ der, err := DecryptPEMBlock(block, data.password)
+ if err != nil {
+ t.Error("decrypt failed: ", err)
+ continue
+ }
+ if _, err := ParsePKCS1PrivateKey(der); err != nil {
+ t.Error("invalid private key: ", err)
+ }
+ plainDER, err := base64.StdEncoding.DecodeString(data.plainDER)
+ if err != nil {
+ t.Fatal("cannot decode test DER data: ", err)
+ }
+ if !bytes.Equal(der, plainDER) {
+ t.Error("data mismatch")
+ }
+ }
+}
+
+func TestEncrypt(t *testing.T) {
+ for i, data := range testData {
+ t.Logf("test %v. %v", i, data.kind)
+ plainDER, err := base64.StdEncoding.DecodeString(data.plainDER)
+ if err != nil {
+ t.Fatal("cannot decode test DER data: ", err)
+ }
+ password := []byte("kremvax1")
+ block, err := EncryptPEMBlock(rand.Reader, "RSA PRIVATE KEY", plainDER, password, data.kind)
+ if err != nil {
+ t.Error("encrypt: ", err)
+ continue
+ }
+ if !IsEncryptedPEMBlock(block) {
+ t.Error("PEM block does not appear to be encrypted")
+ }
+ if block.Type != "RSA PRIVATE KEY" {
+ t.Errorf("unexpected block type; got %q want %q", block.Type, "RSA PRIVATE KEY")
+ }
+ if block.Headers["Proc-Type"] != "4,ENCRYPTED" {
+ t.Errorf("block does not have correct Proc-Type header")
+ }
+ der, err := DecryptPEMBlock(block, password)
+ if err != nil {
+ t.Error("decrypt: ", err)
+ continue
+ }
+ if !bytes.Equal(der, plainDER) {
+ t.Errorf("data mismatch")
+ }
+ }
+}
+
+var testData = []struct {
+ kind PEMCipher
+ password []byte
+ pemData []byte
+ plainDER string
+}{
+ {
+ kind: PEMCipherDES,
+ password: []byte("asdf"),
+ pemData: []byte(testingKey(`
+-----BEGIN RSA TESTING KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-CBC,34F09A4FC8DE22B5
+
+WXxy8kbZdiZvANtKvhmPBLV7eVFj2A5z6oAxvI9KGyhG0ZK0skfnt00C24vfU7m5
+ICXeoqP67lzJ18xCzQfHjDaBNs53DSDT+Iz4e8QUep1xQ30+8QKX2NA2coee3nwc
+6oM1cuvhNUDemBH2i3dKgMVkfaga0zQiiOq6HJyGSncCMSruQ7F9iWEfRbFcxFCx
+qtHb1kirfGKEtgWTF+ynyco6+2gMXNu70L7nJcnxnV/RLFkHt7AUU1yrclxz7eZz
+XOH9VfTjb52q/I8Suozq9coVQwg4tXfIoYUdT//O+mB7zJb9HI9Ps77b9TxDE6Gm
+4C9brwZ3zg2vqXcwwV6QRZMtyll9rOpxkbw6NPlpfBqkc3xS51bbxivbO/Nve4KD
+r12ymjFNF4stXCfJnNqKoZ50BHmEEUDu5Wb0fpVn82XrGw7CYc4iug==
+-----END RSA TESTING KEY-----`)),
+ plainDER: `
+MIIBPAIBAAJBAPASZe+tCPU6p80AjHhDkVsLYa51D35e/YGa8QcZyooeZM8EHozo
+KD0fNiKI+53bHdy07N+81VQ8/ejPcRoXPlsCAwEAAQJBAMTxIuSq27VpR+zZ7WJf
+c6fvv1OBvpMZ0/d1pxL/KnOAgq2rD5hDtk9b0LGhTPgQAmrrMTKuSeGoIuYE+gKQ
+QvkCIQD+GC1m+/do+QRurr0uo46Kx1LzLeSCrjBk34wiOp2+dwIhAPHfTLRXS2fv
+7rljm0bYa4+eDZpz+E8RcXEgzhhvcQQ9AiAI5eHZJGOyml3MXnQjiPi55WcDOw0w
+glcRgT6QCEtz2wIhANSyqaFtosIkHKqrDUGfz/bb5tqMYTAnBruVPaf/WEOBAiEA
+9xORWeRG1tRpso4+dYy4KdDkuLPIO01KY6neYGm3BCM=`,
+ },
+ {
+ kind: PEMCipher3DES,
+ password: []byte("asdf"),
+ pemData: []byte(testingKey(`
+-----BEGIN RSA TESTING KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: DES-EDE3-CBC,C1F4A6A03682C2C7
+
+0JqVdBEH6iqM7drTkj+e2W/bE3LqakaiWhb9WUVonFkhyu8ca/QzebY3b5gCvAZQ
+YwBvDcT/GHospKqPx+cxDHJNsUASDZws6bz8ZXWJGwZGExKzr0+Qx5fgXn44Ms3x
+8g1ENFuTXtxo+KoNK0zuAMAqp66Llcds3Fjl4XR18QaD0CrVNAfOdgATWZm5GJxk
+Fgx5f84nT+/ovvreG+xeOzWgvtKo0UUZVrhGOgfKLpa57adumcJ6SkUuBtEFpZFB
+ldw5w7WC7d13x2LsRkwo8ZrDKgIV+Y9GNvhuCCkTzNP0V3gNeJpd201HZHR+9n3w
+3z0VjR/MGqsfcy1ziEWMNOO53At3zlG6zP05aHMnMcZoVXadEK6L1gz++inSSDCq
+gI0UJP4e3JVB7AkgYymYAwiYALAkoEIuanxoc50njJk=
+-----END RSA TESTING KEY-----`)),
+ plainDER: `
+MIIBOwIBAAJBANOCXKdoNS/iP/MAbl9cf1/SF3P+Ns7ZeNL27CfmDh0O6Zduaax5
+NBiumd2PmjkaCu7lQ5JOibHfWn+xJsc3kw0CAwEAAQJANX/W8d1Q/sCqzkuAn4xl
+B5a7qfJWaLHndu1QRLNTRJPn0Ee7OKJ4H0QKOhQM6vpjRrz+P2u9thn6wUxoPsef
+QQIhAP/jCkfejFcy4v15beqKzwz08/tslVjF+Yq41eJGejmxAiEA05pMoqfkyjcx
+fyvGhpoOyoCp71vSGUfR2I9CR65oKh0CIC1Msjs66LlfJtQctRq6bCEtFCxEcsP+
+eEjYo/Sk6WphAiEAxpgWPMJeU/shFT28gS+tmhjPZLpEoT1qkVlC14u0b3ECIQDX
+tZZZxCtPAm7shftEib0VU77Lk8MsXJcx2C4voRsjEw==`,
+ },
+ {
+ kind: PEMCipherAES128,
+ password: []byte("asdf"),
+ pemData: []byte(testingKey(`
+-----BEGIN RSA TESTING KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,D4492E793FC835CC038A728ED174F78A
+
+EyfQSzXSjv6BaNH+NHdXRlkHdimpF9izWlugVJAPApgXrq5YldPe2aGIOFXyJ+QE
+ZIG20DYqaPzJRjTEbPNZ6Es0S2JJ5yCpKxwJuDkgJZKtF39Q2i36JeGbSZQIuWJE
+GZbBpf1jDH/pr0iGonuAdl2PCCZUiy+8eLsD2tyviHUkFLOB+ykYoJ5t8ngZ/B6D
+33U43LLb7+9zD4y3Q9OVHqBFGyHcxCY9+9Qh4ZnFp7DTf6RY5TNEvE3s4g6aDpBs
+3NbvRVvYTgs8K9EPk4K+5R+P2kD8J8KvEIGxVa1vz8QoCJ/jr7Ka2rvNgPCex5/E
+080LzLHPCrXKdlr/f50yhNWq08ZxMWQFkui+FDHPDUaEELKAXV8/5PDxw80Rtybo
+AVYoCVIbZXZCuCO81op8UcOgEpTtyU5Lgh3Mw5scQL0=
+-----END RSA TESTING KEY-----`)),
+ plainDER: `
+MIIBOgIBAAJBAMBlj5FxYtqbcy8wY89d/S7n0+r5MzD9F63BA/Lpl78vQKtdJ5dT
+cDGh/rBt1ufRrNp0WihcmZi7Mpl/3jHjiWECAwEAAQJABNOHYnKhtDIqFYj1OAJ3
+k3GlU0OlERmIOoeY/cL2V4lgwllPBEs7r134AY4wMmZSBUj8UR/O4SNO668ElKPE
+cQIhAOuqY7/115x5KCdGDMWi+jNaMxIvI4ETGwV40ykGzqlzAiEA0P9oEC3m9tHB
+kbpjSTxaNkrXxDgdEOZz8X0uOUUwHNsCIAwzcSCiGLyYJTULUmP1ESERfW1mlV78
+XzzESaJpIM/zAiBQkSTcl9VhcJreQqvjn5BnPZLP4ZHS4gPwJAGdsj5J4QIhAOVR
+B3WlRNTXR2WsJ5JdByezg9xzdXzULqmga0OE339a`,
+ },
+ {
+ kind: PEMCipherAES192,
+ password: []byte("asdf"),
+ pemData: []byte(testingKey(`
+-----BEGIN RSA TESTING KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-192-CBC,E2C9FB02BCA23ADE1829F8D8BC5F5369
+
+cqVslvHqDDM6qwU6YjezCRifXmKsrgEev7ng6Qs7UmDJOpHDgJQZI9fwMFUhIyn5
+FbCu1SHkLMW52Ld3CuEqMnzWMlhPrW8tFvUOrMWPYSisv7nNq88HobZEJcUNL2MM
+Y15XmHW6IJwPqhKyLHpWXyOCVEh4ODND2nV15PCoi18oTa475baxSk7+1qH7GuIs
+Rb7tshNTMqHbCpyo9Rn3UxeFIf9efdl8YLiMoIqc7J8E5e9VlbeQSdLMQOgDAQJG
+ReUtTw8exmKsY4gsSjhkg5uiw7/ZB1Ihto0qnfQJgjGc680qGkT1d6JfvOfeYAk6
+xn5RqS/h8rYAYm64KnepfC9vIujo4NqpaREDmaLdX5MJPQ+SlytITQvgUsUq3q/t
+Ss85xjQEZH3hzwjQqdJvmA4hYP6SUjxYpBM+02xZ1Xw=
+-----END RSA TESTING KEY-----`)),
+ plainDER: `
+MIIBOwIBAAJBAMGcRrZiNNmtF20zyS6MQ7pdGx17aFDl+lTl+qnLuJRUCMUG05xs
+OmxmL/O1Qlf+bnqR8Bgg65SfKg21SYuLhiMCAwEAAQJBAL94uuHyO4wux2VC+qpj
+IzPykjdU7XRcDHbbvksf4xokSeUFjjD3PB0Qa83M94y89ZfdILIqS9x5EgSB4/lX
+qNkCIQD6cCIqLfzq/lYbZbQgAAjpBXeQVYsbvVtJrPrXJAlVVQIhAMXpDKMeFPMn
+J0g2rbx1gngx0qOa5r5iMU5w/noN4W2XAiBjf+WzCG5yFvazD+dOx3TC0A8+4x3P
+uZ3pWbaXf5PNuQIgAcdXarvhelH2w2piY1g3BPeFqhzBSCK/yLGxR82KIh8CIQDD
++qGKsd09NhQ/G27y/DARzOYtml1NvdmCQAgsDIIOLA==`,
+ },
+ {
+ kind: PEMCipherAES256,
+ password: []byte("asdf"),
+ pemData: []byte(testingKey(`
+-----BEGIN RSA TESTING KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-256-CBC,8E7ED5CD731902CE938957A886A5FFBD
+
+4Mxr+KIzRVwoOP0wwq6caSkvW0iS+GE2h2Ov/u+n9ZTMwL83PRnmjfjzBgfRZLVf
+JFPXxUK26kMNpIdssNnqGOds+DhB+oSrsNKoxgxSl5OBoYv9eJTVYm7qOyAFIsjr
+DRKAcjYCmzfesr7PVTowwy0RtHmYwyXMGDlAzzZrEvaiySFFmMyKKvtoavwaFoc7
+Pz3RZScwIuubzTGJ1x8EzdffYOsdCa9Mtgpp3L136+23dOd6L/qK2EG2fzrJSHs/
+2XugkleBFSMKzEp9mxXKRfa++uidQvMZTFLDK9w5YjrRvMBo/l2BoZIsq0jAIE1N
+sv5Z/KwlX+3MDEpPQpUwGPlGGdLnjI3UZ+cjgqBcoMiNc6HfgbBgYJSU6aDSHuCk
+clCwByxWkBNgJ2GrkwNrF26v+bGJJJNR4SKouY1jQf0=
+-----END RSA TESTING KEY-----`)),
+ plainDER: `
+MIIBOgIBAAJBAKy3GFkstoCHIEeUU/qO8207m8WSrjksR+p9B4tf1w5k+2O1V/GY
+AQ5WFCApItcOkQe/I0yZZJk/PmCqMzSxrc8CAwEAAQJAOCAz0F7AW9oNelVQSP8F
+Sfzx7O1yom+qWyAQQJF/gFR11gpf9xpVnnyu1WxIRnDUh1LZwUsjwlDYb7MB74id
+oQIhANPcOiLwOPT4sIUpRM5HG6BF1BI7L77VpyGVk8xNP7X/AiEA0LMHZtk4I+lJ
+nClgYp4Yh2JZ1Znbu7IoQMCEJCjwKDECIGd8Dzm5tViTkUW6Hs3Tlf73nNs65duF
+aRnSglss8I3pAiEAonEnKruawgD8RavDFR+fUgmQiPz4FnGGeVgfwpGG1JECIBYq
+PXHYtPqxQIbD2pScR5qum7iGUh11lEUPkmt+2uqS`,
+ },
+ {
+ // generated with:
+ // openssl genrsa -aes128 -passout pass:asdf -out server.orig.key 128
+ kind: PEMCipherAES128,
+ password: []byte("asdf"),
+ pemData: []byte(testingKey(`
+-----BEGIN RSA TESTING KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,74611ABC2571AF11B1BF9B69E62C89E7
+
+6ei/MlytjE0FFgZOGQ+jrwomKfpl8kdefeE0NSt/DMRrw8OacHAzBNi3pPEa0eX3
+eND9l7C9meCirWovjj9QWVHrXyugFuDIqgdhQ8iHTgCfF3lrmcttVrbIfMDw+smD
+hTP8O1mS/MHl92NE0nhv0w==
+-----END RSA TESTING KEY-----`)),
+ plainDER: `
+MGMCAQACEQC6ssxmYuauuHGOCDAI54RdAgMBAAECEQCWIn6Yv2O+kBcDF7STctKB
+AgkA8SEfu/2i3g0CCQDGNlXbBHX7kQIIK3Ww5o0cYbECCQDCimPb0dYGsQIIeQ7A
+jryIst8=`,
+ },
+}
+
+var incompleteBlockPEM = testingKey(`
+-----BEGIN RSA TESTING KEY-----
+Proc-Type: 4,ENCRYPTED
+DEK-Info: AES-128-CBC,74611ABC2571AF11B1BF9B69E62C89E7
+
+6L8yXK2MTQUWBk4ZD6OvCiYp+mXyR1594TQ1K38MxGvDw5pwcDME2Lek8RrR5fd40P2XsL2Z4KKt
+ai+OP1BZUetfK6AW4MiqB2FDyIdOAJ8XeWuZy21Wtsh8wPD6yYOFM/w7WZL8weX3Y0TSeG/T
+-----END RSA TESTING KEY-----`)
+
+func TestIncompleteBlock(t *testing.T) {
+ // incompleteBlockPEM contains ciphertext that is not a multiple of the
+ // block size. This previously panicked. See #11215.
+ block, _ := pem.Decode([]byte(incompleteBlockPEM))
+ _, err := DecryptPEMBlock(block, []byte("foo"))
+ if err == nil {
+ t.Fatal("Bad PEM data decrypted successfully")
+ }
+ const expectedSubstr = "block size"
+ if e := err.Error(); !strings.Contains(e, expectedSubstr) {
+ t.Fatalf("Expected error containing %q but got: %q", expectedSubstr, e)
+ }
+}
+
+func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") }
diff --git a/src/crypto/x509/pkcs1.go b/src/crypto/x509/pkcs1.go
new file mode 100644
index 0000000..f9d3840
--- /dev/null
+++ b/src/crypto/x509/pkcs1.go
@@ -0,0 +1,173 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "crypto/rsa"
+ "encoding/asn1"
+ "errors"
+ "math/big"
+)
+
+// pkcs1PrivateKey is a structure which mirrors the PKCS #1 ASN.1 for an RSA private key.
+type pkcs1PrivateKey struct {
+ Version int
+ N *big.Int
+ E int
+ D *big.Int
+ P *big.Int
+ Q *big.Int
+ // We ignore these values, if present, because rsa will calculate them.
+ Dp *big.Int `asn1:"optional"`
+ Dq *big.Int `asn1:"optional"`
+ Qinv *big.Int `asn1:"optional"`
+
+ AdditionalPrimes []pkcs1AdditionalRSAPrime `asn1:"optional,omitempty"`
+}
+
+type pkcs1AdditionalRSAPrime struct {
+ Prime *big.Int
+
+ // We ignore these values because rsa will calculate them.
+ Exp *big.Int
+ Coeff *big.Int
+}
+
+// pkcs1PublicKey reflects the ASN.1 structure of a PKCS #1 public key.
+type pkcs1PublicKey struct {
+ N *big.Int
+ E int
+}
+
+// ParsePKCS1PrivateKey parses an RSA private key in PKCS #1, ASN.1 DER form.
+//
+// This kind of key is commonly encoded in PEM blocks of type "RSA PRIVATE KEY".
+func ParsePKCS1PrivateKey(der []byte) (*rsa.PrivateKey, error) {
+ var priv pkcs1PrivateKey
+ rest, err := asn1.Unmarshal(der, &priv)
+ if len(rest) > 0 {
+ return nil, asn1.SyntaxError{Msg: "trailing data"}
+ }
+ if err != nil {
+ if _, err := asn1.Unmarshal(der, &ecPrivateKey{}); err == nil {
+ return nil, errors.New("x509: failed to parse private key (use ParseECPrivateKey instead for this key format)")
+ }
+ if _, err := asn1.Unmarshal(der, &pkcs8{}); err == nil {
+ return nil, errors.New("x509: failed to parse private key (use ParsePKCS8PrivateKey instead for this key format)")
+ }
+ return nil, err
+ }
+
+ if priv.Version > 1 {
+ return nil, errors.New("x509: unsupported private key version")
+ }
+
+ if priv.N.Sign() <= 0 || priv.D.Sign() <= 0 || priv.P.Sign() <= 0 || priv.Q.Sign() <= 0 {
+ return nil, errors.New("x509: private key contains zero or negative value")
+ }
+
+ key := new(rsa.PrivateKey)
+ key.PublicKey = rsa.PublicKey{
+ E: priv.E,
+ N: priv.N,
+ }
+
+ key.D = priv.D
+ key.Primes = make([]*big.Int, 2+len(priv.AdditionalPrimes))
+ key.Primes[0] = priv.P
+ key.Primes[1] = priv.Q
+ for i, a := range priv.AdditionalPrimes {
+ if a.Prime.Sign() <= 0 {
+ return nil, errors.New("x509: private key contains zero or negative prime")
+ }
+ key.Primes[i+2] = a.Prime
+ // We ignore the other two values because rsa will calculate
+ // them as needed.
+ }
+
+ err = key.Validate()
+ if err != nil {
+ return nil, err
+ }
+ key.Precompute()
+
+ return key, nil
+}
+
+// MarshalPKCS1PrivateKey converts an RSA private key to PKCS #1, ASN.1 DER form.
+//
+// This kind of key is commonly encoded in PEM blocks of type "RSA PRIVATE KEY".
+// For a more flexible key format which is not RSA specific, use
+// MarshalPKCS8PrivateKey.
+func MarshalPKCS1PrivateKey(key *rsa.PrivateKey) []byte {
+ key.Precompute()
+
+ version := 0
+ if len(key.Primes) > 2 {
+ version = 1
+ }
+
+ priv := pkcs1PrivateKey{
+ Version: version,
+ N: key.N,
+ E: key.PublicKey.E,
+ D: key.D,
+ P: key.Primes[0],
+ Q: key.Primes[1],
+ Dp: key.Precomputed.Dp,
+ Dq: key.Precomputed.Dq,
+ Qinv: key.Precomputed.Qinv,
+ }
+
+ priv.AdditionalPrimes = make([]pkcs1AdditionalRSAPrime, len(key.Precomputed.CRTValues))
+ for i, values := range key.Precomputed.CRTValues {
+ priv.AdditionalPrimes[i].Prime = key.Primes[2+i]
+ priv.AdditionalPrimes[i].Exp = values.Exp
+ priv.AdditionalPrimes[i].Coeff = values.Coeff
+ }
+
+ b, _ := asn1.Marshal(priv)
+ return b
+}
+
+// ParsePKCS1PublicKey parses an RSA public key in PKCS #1, ASN.1 DER form.
+//
+// This kind of key is commonly encoded in PEM blocks of type "RSA PUBLIC KEY".
+func ParsePKCS1PublicKey(der []byte) (*rsa.PublicKey, error) {
+ var pub pkcs1PublicKey
+ rest, err := asn1.Unmarshal(der, &pub)
+ if err != nil {
+ if _, err := asn1.Unmarshal(der, &publicKeyInfo{}); err == nil {
+ return nil, errors.New("x509: failed to parse public key (use ParsePKIXPublicKey instead for this key format)")
+ }
+ return nil, err
+ }
+ if len(rest) > 0 {
+ return nil, asn1.SyntaxError{Msg: "trailing data"}
+ }
+
+ if pub.N.Sign() <= 0 || pub.E <= 0 {
+ return nil, errors.New("x509: public key contains zero or negative value")
+ }
+ if pub.E > 1<<31-1 {
+ return nil, errors.New("x509: public key contains large public exponent")
+ }
+
+ return &rsa.PublicKey{
+ E: pub.E,
+ N: pub.N,
+ }, nil
+}
+
+// MarshalPKCS1PublicKey converts an RSA public key to PKCS #1, ASN.1 DER form.
+//
+// This kind of key is commonly encoded in PEM blocks of type "RSA PUBLIC KEY".
+func MarshalPKCS1PublicKey(key *rsa.PublicKey) []byte {
+ derBytes, _ := asn1.Marshal(pkcs1PublicKey{
+ N: key.N,
+ E: key.E,
+ })
+ return derBytes
+}
diff --git a/src/crypto/x509/pkcs8.go b/src/crypto/x509/pkcs8.go
new file mode 100644
index 0000000..2d085e0
--- /dev/null
+++ b/src/crypto/x509/pkcs8.go
@@ -0,0 +1,175 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "crypto/ecdh"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/rsa"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "errors"
+ "fmt"
+)
+
+// pkcs8 reflects an ASN.1, PKCS #8 PrivateKey. See
+// ftp://ftp.rsasecurity.com/pub/pkcs/pkcs-8/pkcs-8v1_2.asn
+// and RFC 5208.
+type pkcs8 struct {
+ Version int
+ Algo pkix.AlgorithmIdentifier
+ PrivateKey []byte
+ // optional attributes omitted.
+}
+
+// ParsePKCS8PrivateKey parses an unencrypted private key in PKCS #8, ASN.1 DER form.
+//
+// It returns a *rsa.PrivateKey, a *ecdsa.PrivateKey, a ed25519.PrivateKey (not
+// a pointer), or a *ecdh.PrivateKey (for X25519). More types might be supported
+// in the future.
+//
+// This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY".
+func ParsePKCS8PrivateKey(der []byte) (key any, err error) {
+ var privKey pkcs8
+ if _, err := asn1.Unmarshal(der, &privKey); err != nil {
+ if _, err := asn1.Unmarshal(der, &ecPrivateKey{}); err == nil {
+ return nil, errors.New("x509: failed to parse private key (use ParseECPrivateKey instead for this key format)")
+ }
+ if _, err := asn1.Unmarshal(der, &pkcs1PrivateKey{}); err == nil {
+ return nil, errors.New("x509: failed to parse private key (use ParsePKCS1PrivateKey instead for this key format)")
+ }
+ return nil, err
+ }
+ switch {
+ case privKey.Algo.Algorithm.Equal(oidPublicKeyRSA):
+ key, err = ParsePKCS1PrivateKey(privKey.PrivateKey)
+ if err != nil {
+ return nil, errors.New("x509: failed to parse RSA private key embedded in PKCS#8: " + err.Error())
+ }
+ return key, nil
+
+ case privKey.Algo.Algorithm.Equal(oidPublicKeyECDSA):
+ bytes := privKey.Algo.Parameters.FullBytes
+ namedCurveOID := new(asn1.ObjectIdentifier)
+ if _, err := asn1.Unmarshal(bytes, namedCurveOID); err != nil {
+ namedCurveOID = nil
+ }
+ key, err = parseECPrivateKey(namedCurveOID, privKey.PrivateKey)
+ if err != nil {
+ return nil, errors.New("x509: failed to parse EC private key embedded in PKCS#8: " + err.Error())
+ }
+ return key, nil
+
+ case privKey.Algo.Algorithm.Equal(oidPublicKeyEd25519):
+ if l := len(privKey.Algo.Parameters.FullBytes); l != 0 {
+ return nil, errors.New("x509: invalid Ed25519 private key parameters")
+ }
+ var curvePrivateKey []byte
+ if _, err := asn1.Unmarshal(privKey.PrivateKey, &curvePrivateKey); err != nil {
+ return nil, fmt.Errorf("x509: invalid Ed25519 private key: %v", err)
+ }
+ if l := len(curvePrivateKey); l != ed25519.SeedSize {
+ return nil, fmt.Errorf("x509: invalid Ed25519 private key length: %d", l)
+ }
+ return ed25519.NewKeyFromSeed(curvePrivateKey), nil
+
+ case privKey.Algo.Algorithm.Equal(oidPublicKeyX25519):
+ if l := len(privKey.Algo.Parameters.FullBytes); l != 0 {
+ return nil, errors.New("x509: invalid X25519 private key parameters")
+ }
+ var curvePrivateKey []byte
+ if _, err := asn1.Unmarshal(privKey.PrivateKey, &curvePrivateKey); err != nil {
+ return nil, fmt.Errorf("x509: invalid X25519 private key: %v", err)
+ }
+ return ecdh.X25519().NewPrivateKey(curvePrivateKey)
+
+ default:
+ return nil, fmt.Errorf("x509: PKCS#8 wrapping contained private key with unknown algorithm: %v", privKey.Algo.Algorithm)
+ }
+}
+
+// MarshalPKCS8PrivateKey converts a private key to PKCS #8, ASN.1 DER form.
+//
+// The following key types are currently supported: *rsa.PrivateKey,
+// *ecdsa.PrivateKey, ed25519.PrivateKey (not a pointer), and *ecdh.PrivateKey.
+// Unsupported key types result in an error.
+//
+// This kind of key is commonly encoded in PEM blocks of type "PRIVATE KEY".
+func MarshalPKCS8PrivateKey(key any) ([]byte, error) {
+ var privKey pkcs8
+
+ switch k := key.(type) {
+ case *rsa.PrivateKey:
+ privKey.Algo = pkix.AlgorithmIdentifier{
+ Algorithm: oidPublicKeyRSA,
+ Parameters: asn1.NullRawValue,
+ }
+ privKey.PrivateKey = MarshalPKCS1PrivateKey(k)
+
+ case *ecdsa.PrivateKey:
+ oid, ok := oidFromNamedCurve(k.Curve)
+ if !ok {
+ return nil, errors.New("x509: unknown curve while marshaling to PKCS#8")
+ }
+ oidBytes, err := asn1.Marshal(oid)
+ if err != nil {
+ return nil, errors.New("x509: failed to marshal curve OID: " + err.Error())
+ }
+ privKey.Algo = pkix.AlgorithmIdentifier{
+ Algorithm: oidPublicKeyECDSA,
+ Parameters: asn1.RawValue{
+ FullBytes: oidBytes,
+ },
+ }
+ if privKey.PrivateKey, err = marshalECPrivateKeyWithOID(k, nil); err != nil {
+ return nil, errors.New("x509: failed to marshal EC private key while building PKCS#8: " + err.Error())
+ }
+
+ case ed25519.PrivateKey:
+ privKey.Algo = pkix.AlgorithmIdentifier{
+ Algorithm: oidPublicKeyEd25519,
+ }
+ curvePrivateKey, err := asn1.Marshal(k.Seed())
+ if err != nil {
+ return nil, fmt.Errorf("x509: failed to marshal private key: %v", err)
+ }
+ privKey.PrivateKey = curvePrivateKey
+
+ case *ecdh.PrivateKey:
+ if k.Curve() == ecdh.X25519() {
+ privKey.Algo = pkix.AlgorithmIdentifier{
+ Algorithm: oidPublicKeyX25519,
+ }
+ var err error
+ if privKey.PrivateKey, err = asn1.Marshal(k.Bytes()); err != nil {
+ return nil, fmt.Errorf("x509: failed to marshal private key: %v", err)
+ }
+ } else {
+ oid, ok := oidFromECDHCurve(k.Curve())
+ if !ok {
+ return nil, errors.New("x509: unknown curve while marshaling to PKCS#8")
+ }
+ oidBytes, err := asn1.Marshal(oid)
+ if err != nil {
+ return nil, errors.New("x509: failed to marshal curve OID: " + err.Error())
+ }
+ privKey.Algo = pkix.AlgorithmIdentifier{
+ Algorithm: oidPublicKeyECDSA,
+ Parameters: asn1.RawValue{
+ FullBytes: oidBytes,
+ },
+ }
+ if privKey.PrivateKey, err = marshalECDHPrivateKey(k); err != nil {
+ return nil, errors.New("x509: failed to marshal EC private key while building PKCS#8: " + err.Error())
+ }
+ }
+
+ default:
+ return nil, fmt.Errorf("x509: unknown key type while marshaling PKCS#8: %T", key)
+ }
+
+ return asn1.Marshal(privKey)
+}
diff --git a/src/crypto/x509/pkcs8_test.go b/src/crypto/x509/pkcs8_test.go
new file mode 100644
index 0000000..d032880
--- /dev/null
+++ b/src/crypto/x509/pkcs8_test.go
@@ -0,0 +1,175 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "bytes"
+ "crypto/ecdh"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/elliptic"
+ "crypto/rsa"
+ "encoding/hex"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+// Generated using:
+//
+// openssl genrsa 1024 | openssl pkcs8 -topk8 -nocrypt
+var pkcs8RSAPrivateKeyHex = `30820278020100300d06092a864886f70d0101010500048202623082025e02010002818100cfb1b5bf9685ffa97b4f99df4ff122b70e59ac9b992f3bc2b3dde17d53c1a34928719b02e8fd17839499bfbd515bd6ef99c7a1c47a239718fe36bfd824c0d96060084b5f67f0273443007a24dfaf5634f7772c9346e10eb294c2306671a5a5e719ae24b4de467291bc571014b0e02dec04534d66a9bb171d644b66b091780e8d020301000102818100b595778383c4afdbab95d2bfed12b3f93bb0a73a7ad952f44d7185fd9ec6c34de8f03a48770f2009c8580bcd275e9632714e9a5e3f32f29dc55474b2329ff0ebc08b3ffcb35bc96e6516b483df80a4a59cceb71918cbabf91564e64a39d7e35dce21cb3031824fdbc845dba6458852ec16af5dddf51a8397a8797ae0337b1439024100ea0eb1b914158c70db39031dd8904d6f18f408c85fbbc592d7d20dee7986969efbda081fdf8bc40e1b1336d6b638110c836bfdc3f314560d2e49cd4fbde1e20b024100e32a4e793b574c9c4a94c8803db5152141e72d03de64e54ef2c8ed104988ca780cd11397bc359630d01b97ebd87067c5451ba777cf045ca23f5912f1031308c702406dfcdbbd5a57c9f85abc4edf9e9e29153507b07ce0a7ef6f52e60dcfebe1b8341babd8b789a837485da6c8d55b29bbb142ace3c24a1f5b54b454d01b51e2ad03024100bd6a2b60dee01e1b3bfcef6a2f09ed027c273cdbbaf6ba55a80f6dcc64e4509ee560f84b4f3e076bd03b11e42fe71a3fdd2dffe7e0902c8584f8cad877cdc945024100aa512fa4ada69881f1d8bb8ad6614f192b83200aef5edf4811313d5ef30a86cbd0a90f7b025c71ea06ec6b34db6306c86b1040670fd8654ad7291d066d06d031`
+
+// Generated using:
+//
+// openssl ecparam -genkey -name secp224r1 | openssl pkcs8 -topk8 -nocrypt
+var pkcs8P224PrivateKeyHex = `3078020100301006072a8648ce3d020106052b810400210461305f020101041cca3d72b3e88fed2684576dad9b80a9180363a5424986900e3abcab3fa13c033a0004f8f2a6372872a4e61263ed893afb919576a4cacfecd6c081a2cbc76873cf4ba8530703c6042b3a00e2205087e87d2435d2e339e25702fae1`
+
+// Generated using:
+//
+// openssl ecparam -genkey -name secp256r1 | openssl pkcs8 -topk8 -nocrypt
+var pkcs8P256PrivateKeyHex = `308187020100301306072a8648ce3d020106082a8648ce3d030107046d306b0201010420dad6b2f49ca774c36d8ae9517e935226f667c929498f0343d2424d0b9b591b43a14403420004b9c9b90095476afe7b860d8bd43568cab7bcb2eed7b8bf2fa0ce1762dd20b04193f859d2d782b1e4cbfd48492f1f533113a6804903f292258513837f07fda735`
+
+// Generated using:
+//
+// openssl ecparam -genkey -name secp384r1 | openssl pkcs8 -topk8 -nocrypt
+var pkcs8P384PrivateKeyHex = `3081b6020100301006072a8648ce3d020106052b8104002204819e30819b02010104309bf832f6aaaeacb78ce47ffb15e6fd0fd48683ae79df6eca39bfb8e33829ac94aa29d08911568684c2264a08a4ceb679a164036200049070ad4ed993c7770d700e9f6dc2baa83f63dd165b5507f98e8ff29b5d2e78ccbe05c8ddc955dbf0f7497e8222cfa49314fe4e269459f8e880147f70d785e530f2939e4bf9f838325bb1a80ad4cf59272ae0e5efe9a9dc33d874492596304bd3`
+
+// Generated using:
+//
+// openssl ecparam -genkey -name secp521r1 | openssl pkcs8 -topk8 -nocrypt
+//
+// Note that OpenSSL will truncate the private key if it can (i.e. it emits it
+// like an integer, even though it's an OCTET STRING field). Thus if you
+// regenerate this you may, randomly, find that it's a byte shorter than
+// expected and the Go test will fail to recreate it exactly.
+var pkcs8P521PrivateKeyHex = `3081ee020100301006072a8648ce3d020106052b810400230481d63081d3020101044200cfe0b87113a205cf291bb9a8cd1a74ac6c7b2ebb8199aaa9a5010d8b8012276fa3c22ac913369fa61beec2a3b8b4516bc049bde4fb3b745ac11b56ab23ac52e361a1818903818600040138f75acdd03fbafa4f047a8e4b272ba9d555c667962b76f6f232911a5786a0964e5edea6bd21a6f8725720958de049c6e3e6661c1c91b227cebee916c0319ed6ca003db0a3206d372229baf9dd25d868bf81140a518114803ce40c1855074d68c4e9dab9e65efba7064c703b400f1767f217dac82715ac1f6d88c74baf47a7971de4ea`
+
+// From RFC 8410, Section 7.
+var pkcs8Ed25519PrivateKeyHex = `302e020100300506032b657004220420d4ee72dbf913584ad5b6d8f1f769f8ad3afe7c28cbf1d4fbe097a88f44755842`
+
+// Generated using:
+//
+// openssl genpkey -algorithm x25519
+var pkcs8X25519PrivateKeyHex = `302e020100300506032b656e0422042068ff93a73c5adefd6d498b24e588fd4daa10924d992afed01b43ca5725025a6b`
+
+func TestPKCS8(t *testing.T) {
+ tests := []struct {
+ name string
+ keyHex string
+ keyType reflect.Type
+ curve elliptic.Curve
+ }{
+ {
+ name: "RSA private key",
+ keyHex: pkcs8RSAPrivateKeyHex,
+ keyType: reflect.TypeOf(&rsa.PrivateKey{}),
+ },
+ {
+ name: "P-224 private key",
+ keyHex: pkcs8P224PrivateKeyHex,
+ keyType: reflect.TypeOf(&ecdsa.PrivateKey{}),
+ curve: elliptic.P224(),
+ },
+ {
+ name: "P-256 private key",
+ keyHex: pkcs8P256PrivateKeyHex,
+ keyType: reflect.TypeOf(&ecdsa.PrivateKey{}),
+ curve: elliptic.P256(),
+ },
+ {
+ name: "P-384 private key",
+ keyHex: pkcs8P384PrivateKeyHex,
+ keyType: reflect.TypeOf(&ecdsa.PrivateKey{}),
+ curve: elliptic.P384(),
+ },
+ {
+ name: "P-521 private key",
+ keyHex: pkcs8P521PrivateKeyHex,
+ keyType: reflect.TypeOf(&ecdsa.PrivateKey{}),
+ curve: elliptic.P521(),
+ },
+ {
+ name: "Ed25519 private key",
+ keyHex: pkcs8Ed25519PrivateKeyHex,
+ keyType: reflect.TypeOf(ed25519.PrivateKey{}),
+ },
+ {
+ name: "X25519 private key",
+ keyHex: pkcs8X25519PrivateKeyHex,
+ keyType: reflect.TypeOf(&ecdh.PrivateKey{}),
+ },
+ }
+
+ for _, test := range tests {
+ derBytes, err := hex.DecodeString(test.keyHex)
+ if err != nil {
+ t.Errorf("%s: failed to decode hex: %s", test.name, err)
+ continue
+ }
+ privKey, err := ParsePKCS8PrivateKey(derBytes)
+ if err != nil {
+ t.Errorf("%s: failed to decode PKCS#8: %s", test.name, err)
+ continue
+ }
+ if reflect.TypeOf(privKey) != test.keyType {
+ t.Errorf("%s: decoded PKCS#8 returned unexpected key type: %T", test.name, privKey)
+ continue
+ }
+ if ecKey, isEC := privKey.(*ecdsa.PrivateKey); isEC && ecKey.Curve != test.curve {
+ t.Errorf("%s: decoded PKCS#8 returned unexpected curve %#v", test.name, ecKey.Curve)
+ continue
+ }
+ reserialised, err := MarshalPKCS8PrivateKey(privKey)
+ if err != nil {
+ t.Errorf("%s: failed to marshal into PKCS#8: %s", test.name, err)
+ continue
+ }
+ if !bytes.Equal(derBytes, reserialised) {
+ t.Errorf("%s: marshaled PKCS#8 didn't match original: got %x, want %x", test.name, reserialised, derBytes)
+ continue
+ }
+
+ if ecKey, isEC := privKey.(*ecdsa.PrivateKey); isEC {
+ ecdhKey, err := ecKey.ECDH()
+ if err != nil {
+ if ecKey.Curve != elliptic.P224() {
+ t.Errorf("%s: failed to convert to ecdh: %s", test.name, err)
+ }
+ continue
+ }
+ reserialised, err := MarshalPKCS8PrivateKey(ecdhKey)
+ if err != nil {
+ t.Errorf("%s: failed to marshal into PKCS#8: %s", test.name, err)
+ continue
+ }
+ if !bytes.Equal(derBytes, reserialised) {
+ t.Errorf("%s: marshaled PKCS#8 didn't match original: got %x, want %x", test.name, reserialised, derBytes)
+ continue
+ }
+ }
+ }
+}
+
+const hexPKCS8TestPKCS1Key = "3082025c02010002818100b1a1e0945b9289c4d3f1329f8a982c4a2dcd59bfd372fb8085a9c517554607ebd2f7990eef216ac9f4605f71a03b04f42a5255b158cf8e0844191f5119348baa44c35056e20609bcf9510f30ead4b481c81d7865fb27b8e0090e112b717f3ee08cdfc4012da1f1f7cf2a1bc34c73a54a12b06372d09714742dd7895eadde4aa5020301000102818062b7fa1db93e993e40237de4d89b7591cc1ea1d04fed4904c643f17ae4334557b4295270d0491c161cb02a9af557978b32b20b59c267a721c4e6c956c2d147046e9ae5f2da36db0106d70021fa9343455f8f973a4b355a26fd19e6b39dee0405ea2b32deddf0f4817759ef705d02b34faab9ca93c6766e9f722290f119f34449024100d9c29a4a013a90e35fd1be14a3f747c589fac613a695282d61812a711906b8a0876c6181f0333ca1066596f57bff47e7cfcabf19c0fc69d9cd76df743038b3cb024100d0d3546fecf879b5551f2bd2c05e6385f2718a08a6face3d2aecc9d7e03645a480a46c81662c12ad6bd6901e3bd4f38029462de7290859567cdf371c79088d4f024100c254150657e460ea58573fcf01a82a4791e3d6223135c8bdfed69afe84fbe7857274f8eb5165180507455f9b4105c6b08b51fe8a481bb986a202245576b713530240045700003b7a867d0041df9547ae2e7f50248febd21c9040b12dae9c2feab0d3d4609668b208e4727a3541557f84d372ac68eaf74ce1018a4c9a0ef92682c8fd02405769731480bb3a4570abf422527c5f34bf732fa6c1e08cc322753c511ce055fac20fc770025663ad3165324314df907f1f1942f0448a7e9cdbf87ecd98b92156"
+const hexPKCS8TestECKey = "3081a40201010430bdb9839c08ee793d1157886a7a758a3c8b2a17a4df48f17ace57c72c56b4723cf21dcda21d4e1ad57ff034f19fcfd98ea00706052b81040022a16403620004feea808b5ee2429cfcce13c32160e1c960990bd050bb0fdf7222f3decd0a55008e32a6aa3c9062051c4cba92a7a3b178b24567412d43cdd2f882fa5addddd726fe3e208d2c26d733a773a597abb749714df7256ead5105fa6e7b3650de236b50"
+
+var pkcs8MismatchKeyTests = []struct {
+ hexKey string
+ errorContains string
+}{
+ {hexKey: hexPKCS8TestECKey, errorContains: "use ParseECPrivateKey instead"},
+ {hexKey: hexPKCS8TestPKCS1Key, errorContains: "use ParsePKCS1PrivateKey instead"},
+}
+
+func TestPKCS8MismatchKeyFormat(t *testing.T) {
+ for i, test := range pkcs8MismatchKeyTests {
+ derBytes, _ := hex.DecodeString(test.hexKey)
+ _, err := ParsePKCS8PrivateKey(derBytes)
+ if !strings.Contains(err.Error(), test.errorContains) {
+ t.Errorf("#%d: expected error containing %q, got %s", i, test.errorContains, err)
+ }
+ }
+}
diff --git a/src/crypto/x509/pkix/pkix.go b/src/crypto/x509/pkix/pkix.go
new file mode 100644
index 0000000..22a50ee
--- /dev/null
+++ b/src/crypto/x509/pkix/pkix.go
@@ -0,0 +1,320 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package pkix contains shared, low level structures used for ASN.1 parsing
+// and serialization of X.509 certificates, CRL and OCSP.
+package pkix
+
+import (
+ "encoding/asn1"
+ "encoding/hex"
+ "fmt"
+ "math/big"
+ "time"
+)
+
+// AlgorithmIdentifier represents the ASN.1 structure of the same name. See RFC
+// 5280, section 4.1.1.2.
+type AlgorithmIdentifier struct {
+ Algorithm asn1.ObjectIdentifier
+ Parameters asn1.RawValue `asn1:"optional"`
+}
+
+type RDNSequence []RelativeDistinguishedNameSET
+
+var attributeTypeNames = map[string]string{
+ "2.5.4.6": "C",
+ "2.5.4.10": "O",
+ "2.5.4.11": "OU",
+ "2.5.4.3": "CN",
+ "2.5.4.5": "SERIALNUMBER",
+ "2.5.4.7": "L",
+ "2.5.4.8": "ST",
+ "2.5.4.9": "STREET",
+ "2.5.4.17": "POSTALCODE",
+}
+
+// String returns a string representation of the sequence r,
+// roughly following the RFC 2253 Distinguished Names syntax.
+func (r RDNSequence) String() string {
+ s := ""
+ for i := 0; i < len(r); i++ {
+ rdn := r[len(r)-1-i]
+ if i > 0 {
+ s += ","
+ }
+ for j, tv := range rdn {
+ if j > 0 {
+ s += "+"
+ }
+
+ oidString := tv.Type.String()
+ typeName, ok := attributeTypeNames[oidString]
+ if !ok {
+ derBytes, err := asn1.Marshal(tv.Value)
+ if err == nil {
+ s += oidString + "=#" + hex.EncodeToString(derBytes)
+ continue // No value escaping necessary.
+ }
+
+ typeName = oidString
+ }
+
+ valueString := fmt.Sprint(tv.Value)
+ escaped := make([]rune, 0, len(valueString))
+
+ for k, c := range valueString {
+ escape := false
+
+ switch c {
+ case ',', '+', '"', '\\', '<', '>', ';':
+ escape = true
+
+ case ' ':
+ escape = k == 0 || k == len(valueString)-1
+
+ case '#':
+ escape = k == 0
+ }
+
+ if escape {
+ escaped = append(escaped, '\\', c)
+ } else {
+ escaped = append(escaped, c)
+ }
+ }
+
+ s += typeName + "=" + string(escaped)
+ }
+ }
+
+ return s
+}
+
+type RelativeDistinguishedNameSET []AttributeTypeAndValue
+
+// AttributeTypeAndValue mirrors the ASN.1 structure of the same name in
+// RFC 5280, Section 4.1.2.4.
+type AttributeTypeAndValue struct {
+ Type asn1.ObjectIdentifier
+ Value any
+}
+
+// AttributeTypeAndValueSET represents a set of ASN.1 sequences of
+// AttributeTypeAndValue sequences from RFC 2986 (PKCS #10).
+type AttributeTypeAndValueSET struct {
+ Type asn1.ObjectIdentifier
+ Value [][]AttributeTypeAndValue `asn1:"set"`
+}
+
+// Extension represents the ASN.1 structure of the same name. See RFC
+// 5280, section 4.2.
+type Extension struct {
+ Id asn1.ObjectIdentifier
+ Critical bool `asn1:"optional"`
+ Value []byte
+}
+
+// Name represents an X.509 distinguished name. This only includes the common
+// elements of a DN. Note that Name is only an approximation of the X.509
+// structure. If an accurate representation is needed, asn1.Unmarshal the raw
+// subject or issuer as an RDNSequence.
+type Name struct {
+ Country, Organization, OrganizationalUnit []string
+ Locality, Province []string
+ StreetAddress, PostalCode []string
+ SerialNumber, CommonName string
+
+ // Names contains all parsed attributes. When parsing distinguished names,
+ // this can be used to extract non-standard attributes that are not parsed
+ // by this package. When marshaling to RDNSequences, the Names field is
+ // ignored, see ExtraNames.
+ Names []AttributeTypeAndValue
+
+ // ExtraNames contains attributes to be copied, raw, into any marshaled
+ // distinguished names. Values override any attributes with the same OID.
+ // The ExtraNames field is not populated when parsing, see Names.
+ ExtraNames []AttributeTypeAndValue
+}
+
+// FillFromRDNSequence populates n from the provided RDNSequence.
+// Multi-entry RDNs are flattened, all entries are added to the
+// relevant n fields, and the grouping is not preserved.
+func (n *Name) FillFromRDNSequence(rdns *RDNSequence) {
+ for _, rdn := range *rdns {
+ if len(rdn) == 0 {
+ continue
+ }
+
+ for _, atv := range rdn {
+ n.Names = append(n.Names, atv)
+ value, ok := atv.Value.(string)
+ if !ok {
+ continue
+ }
+
+ t := atv.Type
+ if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
+ switch t[3] {
+ case 3:
+ n.CommonName = value
+ case 5:
+ n.SerialNumber = value
+ case 6:
+ n.Country = append(n.Country, value)
+ case 7:
+ n.Locality = append(n.Locality, value)
+ case 8:
+ n.Province = append(n.Province, value)
+ case 9:
+ n.StreetAddress = append(n.StreetAddress, value)
+ case 10:
+ n.Organization = append(n.Organization, value)
+ case 11:
+ n.OrganizationalUnit = append(n.OrganizationalUnit, value)
+ case 17:
+ n.PostalCode = append(n.PostalCode, value)
+ }
+ }
+ }
+ }
+}
+
+var (
+ oidCountry = []int{2, 5, 4, 6}
+ oidOrganization = []int{2, 5, 4, 10}
+ oidOrganizationalUnit = []int{2, 5, 4, 11}
+ oidCommonName = []int{2, 5, 4, 3}
+ oidSerialNumber = []int{2, 5, 4, 5}
+ oidLocality = []int{2, 5, 4, 7}
+ oidProvince = []int{2, 5, 4, 8}
+ oidStreetAddress = []int{2, 5, 4, 9}
+ oidPostalCode = []int{2, 5, 4, 17}
+)
+
+// appendRDNs appends a relativeDistinguishedNameSET to the given RDNSequence
+// and returns the new value. The relativeDistinguishedNameSET contains an
+// attributeTypeAndValue for each of the given values. See RFC 5280, A.1, and
+// search for AttributeTypeAndValue.
+func (n Name) appendRDNs(in RDNSequence, values []string, oid asn1.ObjectIdentifier) RDNSequence {
+ if len(values) == 0 || oidInAttributeTypeAndValue(oid, n.ExtraNames) {
+ return in
+ }
+
+ s := make([]AttributeTypeAndValue, len(values))
+ for i, value := range values {
+ s[i].Type = oid
+ s[i].Value = value
+ }
+
+ return append(in, s)
+}
+
+// ToRDNSequence converts n into a single RDNSequence. The following
+// attributes are encoded as multi-value RDNs:
+//
+// - Country
+// - Organization
+// - OrganizationalUnit
+// - Locality
+// - Province
+// - StreetAddress
+// - PostalCode
+//
+// Each ExtraNames entry is encoded as an individual RDN.
+func (n Name) ToRDNSequence() (ret RDNSequence) {
+ ret = n.appendRDNs(ret, n.Country, oidCountry)
+ ret = n.appendRDNs(ret, n.Province, oidProvince)
+ ret = n.appendRDNs(ret, n.Locality, oidLocality)
+ ret = n.appendRDNs(ret, n.StreetAddress, oidStreetAddress)
+ ret = n.appendRDNs(ret, n.PostalCode, oidPostalCode)
+ ret = n.appendRDNs(ret, n.Organization, oidOrganization)
+ ret = n.appendRDNs(ret, n.OrganizationalUnit, oidOrganizationalUnit)
+ if len(n.CommonName) > 0 {
+ ret = n.appendRDNs(ret, []string{n.CommonName}, oidCommonName)
+ }
+ if len(n.SerialNumber) > 0 {
+ ret = n.appendRDNs(ret, []string{n.SerialNumber}, oidSerialNumber)
+ }
+ for _, atv := range n.ExtraNames {
+ ret = append(ret, []AttributeTypeAndValue{atv})
+ }
+
+ return ret
+}
+
+// String returns the string form of n, roughly following
+// the RFC 2253 Distinguished Names syntax.
+func (n Name) String() string {
+ var rdns RDNSequence
+ // If there are no ExtraNames, surface the parsed value (all entries in
+ // Names) instead.
+ if n.ExtraNames == nil {
+ for _, atv := range n.Names {
+ t := atv.Type
+ if len(t) == 4 && t[0] == 2 && t[1] == 5 && t[2] == 4 {
+ switch t[3] {
+ case 3, 5, 6, 7, 8, 9, 10, 11, 17:
+ // These attributes were already parsed into named fields.
+ continue
+ }
+ }
+ // Place non-standard parsed values at the beginning of the sequence
+ // so they will be at the end of the string. See Issue 39924.
+ rdns = append(rdns, []AttributeTypeAndValue{atv})
+ }
+ }
+ rdns = append(rdns, n.ToRDNSequence()...)
+ return rdns.String()
+}
+
+// oidInAttributeTypeAndValue reports whether a type with the given OID exists
+// in atv.
+func oidInAttributeTypeAndValue(oid asn1.ObjectIdentifier, atv []AttributeTypeAndValue) bool {
+ for _, a := range atv {
+ if a.Type.Equal(oid) {
+ return true
+ }
+ }
+ return false
+}
+
+// CertificateList represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1. Use Certificate.CheckCRLSignature to verify the
+// signature.
+//
+// Deprecated: x509.RevocationList should be used instead.
+type CertificateList struct {
+ TBSCertList TBSCertificateList
+ SignatureAlgorithm AlgorithmIdentifier
+ SignatureValue asn1.BitString
+}
+
+// HasExpired reports whether certList should have been updated by now.
+func (certList *CertificateList) HasExpired(now time.Time) bool {
+ return !now.Before(certList.TBSCertList.NextUpdate)
+}
+
+// TBSCertificateList represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1.
+//
+// Deprecated: x509.RevocationList should be used instead.
+type TBSCertificateList struct {
+ Raw asn1.RawContent
+ Version int `asn1:"optional,default:0"`
+ Signature AlgorithmIdentifier
+ Issuer RDNSequence
+ ThisUpdate time.Time
+ NextUpdate time.Time `asn1:"optional"`
+ RevokedCertificates []RevokedCertificate `asn1:"optional"`
+ Extensions []Extension `asn1:"tag:0,optional,explicit"`
+}
+
+// RevokedCertificate represents the ASN.1 structure of the same name. See RFC
+// 5280, section 5.1.
+type RevokedCertificate struct {
+ SerialNumber *big.Int
+ RevocationTime time.Time
+ Extensions []Extension `asn1:"optional"`
+}
diff --git a/src/crypto/x509/root.go b/src/crypto/x509/root.go
new file mode 100644
index 0000000..d6b07a1
--- /dev/null
+++ b/src/crypto/x509/root.go
@@ -0,0 +1,72 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "internal/godebug"
+ "sync"
+)
+
+var (
+ once sync.Once
+ systemRootsMu sync.RWMutex
+ systemRoots *CertPool
+ systemRootsErr error
+ fallbacksSet bool
+)
+
+func systemRootsPool() *CertPool {
+ once.Do(initSystemRoots)
+ systemRootsMu.RLock()
+ defer systemRootsMu.RUnlock()
+ return systemRoots
+}
+
+func initSystemRoots() {
+ systemRootsMu.Lock()
+ defer systemRootsMu.Unlock()
+ systemRoots, systemRootsErr = loadSystemRoots()
+ if systemRootsErr != nil {
+ systemRoots = nil
+ }
+}
+
+var forceFallback = godebug.New("x509usefallbackroots")
+
+// SetFallbackRoots sets the roots to use during certificate verification, if no
+// custom roots are specified and a platform verifier or a system certificate
+// pool is not available (for instance in a container which does not have a root
+// certificate bundle). SetFallbackRoots will panic if roots is nil.
+//
+// SetFallbackRoots may only be called once, if called multiple times it will
+// panic.
+//
+// The fallback behavior can be forced on all platforms, even when there is a
+// system certificate pool, by setting GODEBUG=x509usefallbackroots=1 (note that
+// on Windows and macOS this will disable usage of the platform verification
+// APIs and cause the pure Go verifier to be used). Setting
+// x509usefallbackroots=1 without calling SetFallbackRoots has no effect.
+func SetFallbackRoots(roots *CertPool) {
+ if roots == nil {
+ panic("roots must be non-nil")
+ }
+
+ // trigger initSystemRoots if it hasn't already been called before we
+ // take the lock
+ _ = systemRootsPool()
+
+ systemRootsMu.Lock()
+ defer systemRootsMu.Unlock()
+
+ if fallbacksSet {
+ panic("SetFallbackRoots has already been called")
+ }
+ fallbacksSet = true
+
+ if systemRoots != nil && (systemRoots.len() > 0 || systemRoots.systemPool) && forceFallback.Value() != "1" {
+ return
+ }
+ systemRoots, systemRootsErr = roots, nil
+}
diff --git a/src/crypto/x509/root_aix.go b/src/crypto/x509/root_aix.go
new file mode 100644
index 0000000..99b7463
--- /dev/null
+++ b/src/crypto/x509/root_aix.go
@@ -0,0 +1,15 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+// Possible certificate files; stop after finding one.
+var certFiles = []string{
+ "/var/ssl/certs/ca-bundle.crt",
+}
+
+// Possible directories with certificate files; all will be read.
+var certDirectories = []string{
+ "/var/ssl/certs",
+}
diff --git a/src/crypto/x509/root_bsd.go b/src/crypto/x509/root_bsd.go
new file mode 100644
index 0000000..a76aef8
--- /dev/null
+++ b/src/crypto/x509/root_bsd.go
@@ -0,0 +1,22 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build dragonfly || freebsd || netbsd || openbsd
+
+package x509
+
+// Possible certificate files; stop after finding one.
+var certFiles = []string{
+ "/usr/local/etc/ssl/cert.pem", // FreeBSD
+ "/etc/ssl/cert.pem", // OpenBSD
+ "/usr/local/share/certs/ca-root-nss.crt", // DragonFly
+ "/etc/openssl/certs/ca-certificates.crt", // NetBSD
+}
+
+// Possible directories with certificate files; all will be read.
+var certDirectories = []string{
+ "/etc/ssl/certs", // FreeBSD 12.2+
+ "/usr/local/share/certs", // FreeBSD
+ "/etc/openssl/certs", // NetBSD
+}
diff --git a/src/crypto/x509/root_darwin.go b/src/crypto/x509/root_darwin.go
new file mode 100644
index 0000000..469e907
--- /dev/null
+++ b/src/crypto/x509/root_darwin.go
@@ -0,0 +1,130 @@
+// Copyright 2020 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ macOS "crypto/x509/internal/macos"
+ "errors"
+ "fmt"
+)
+
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ certs := macOS.CFArrayCreateMutable()
+ defer macOS.ReleaseCFArray(certs)
+ leaf, err := macOS.SecCertificateCreateWithData(c.Raw)
+ if err != nil {
+ return nil, errors.New("invalid leaf certificate")
+ }
+ macOS.CFArrayAppendValue(certs, leaf)
+ if opts.Intermediates != nil {
+ for _, lc := range opts.Intermediates.lazyCerts {
+ c, err := lc.getCert()
+ if err != nil {
+ return nil, err
+ }
+ sc, err := macOS.SecCertificateCreateWithData(c.Raw)
+ if err != nil {
+ return nil, err
+ }
+ macOS.CFArrayAppendValue(certs, sc)
+ }
+ }
+
+ policies := macOS.CFArrayCreateMutable()
+ defer macOS.ReleaseCFArray(policies)
+ sslPolicy, err := macOS.SecPolicyCreateSSL(opts.DNSName)
+ if err != nil {
+ return nil, err
+ }
+ macOS.CFArrayAppendValue(policies, sslPolicy)
+
+ trustObj, err := macOS.SecTrustCreateWithCertificates(certs, policies)
+ if err != nil {
+ return nil, err
+ }
+ defer macOS.CFRelease(trustObj)
+
+ if !opts.CurrentTime.IsZero() {
+ dateRef := macOS.TimeToCFDateRef(opts.CurrentTime)
+ defer macOS.CFRelease(dateRef)
+ if err := macOS.SecTrustSetVerifyDate(trustObj, dateRef); err != nil {
+ return nil, err
+ }
+ }
+
+ // TODO(roland): we may want to allow passing in SCTs via VerifyOptions and
+ // set them via SecTrustSetSignedCertificateTimestamps, since Apple will
+ // always enforce its SCT requirements, and there are still _some_ people
+ // using TLS or OCSP for that.
+
+ if ret, err := macOS.SecTrustEvaluateWithError(trustObj); err != nil {
+ switch ret {
+ case macOS.ErrSecCertificateExpired:
+ return nil, CertificateInvalidError{c, Expired, err.Error()}
+ case macOS.ErrSecHostNameMismatch:
+ return nil, HostnameError{c, opts.DNSName}
+ case macOS.ErrSecNotTrusted:
+ return nil, UnknownAuthorityError{Cert: c}
+ default:
+ return nil, fmt.Errorf("x509: %s", err)
+ }
+ }
+
+ chain := [][]*Certificate{{}}
+ numCerts := macOS.SecTrustGetCertificateCount(trustObj)
+ for i := 0; i < numCerts; i++ {
+ certRef, err := macOS.SecTrustGetCertificateAtIndex(trustObj, i)
+ if err != nil {
+ return nil, err
+ }
+ cert, err := exportCertificate(certRef)
+ if err != nil {
+ return nil, err
+ }
+ chain[0] = append(chain[0], cert)
+ }
+ if len(chain[0]) == 0 {
+ // This should _never_ happen, but to be safe
+ return nil, errors.New("x509: macOS certificate verification internal error")
+ }
+
+ if opts.DNSName != "" {
+ // If we have a DNS name, apply our own name verification
+ if err := chain[0][0].VerifyHostname(opts.DNSName); err != nil {
+ return nil, err
+ }
+ }
+
+ keyUsages := opts.KeyUsages
+ if len(keyUsages) == 0 {
+ keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
+ }
+
+ // If any key usage is acceptable then we're done.
+ for _, usage := range keyUsages {
+ if usage == ExtKeyUsageAny {
+ return chain, nil
+ }
+ }
+
+ if !checkChainForKeyUsage(chain[0], keyUsages) {
+ return nil, CertificateInvalidError{c, IncompatibleUsage, ""}
+ }
+
+ return chain, nil
+}
+
+// exportCertificate returns a *Certificate for a SecCertificateRef.
+func exportCertificate(cert macOS.CFRef) (*Certificate, error) {
+ data, err := macOS.SecCertificateCopyData(cert)
+ if err != nil {
+ return nil, err
+ }
+ return ParseCertificate(data)
+}
+
+func loadSystemRoots() (*CertPool, error) {
+ return &CertPool{systemPool: true}, nil
+}
diff --git a/src/crypto/x509/root_darwin_test.go b/src/crypto/x509/root_darwin_test.go
new file mode 100644
index 0000000..299cecf
--- /dev/null
+++ b/src/crypto/x509/root_darwin_test.go
@@ -0,0 +1,122 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509_test
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "internal/testenv"
+ "testing"
+ "time"
+)
+
+func TestPlatformVerifier(t *testing.T) {
+ if !testenv.HasExternalNetwork() {
+ t.Skip()
+ }
+
+ getChain := func(host string) []*x509.Certificate {
+ t.Helper()
+ c, err := tls.Dial("tcp", host+":443", &tls.Config{InsecureSkipVerify: true})
+ if err != nil {
+ t.Fatalf("tls connection failed: %s", err)
+ }
+ return c.ConnectionState().PeerCertificates
+ }
+
+ tests := []struct {
+ name string
+ host string
+ verifyName string
+ verifyTime time.Time
+ verifyEKU []x509.ExtKeyUsage
+ expectedErr string
+ }{
+ {
+ // whatever google.com serves should, hopefully, be trusted
+ name: "valid chain",
+ host: "google.com",
+ },
+ {
+ name: "expired leaf",
+ host: "expired.badssl.com",
+ expectedErr: "x509: certificate has expired or is not yet valid: “*.badssl.com” certificate is expired",
+ },
+ {
+ name: "wrong host for leaf",
+ host: "wrong.host.badssl.com",
+ verifyName: "wrong.host.badssl.com",
+ expectedErr: "x509: certificate is valid for *.badssl.com, badssl.com, not wrong.host.badssl.com",
+ },
+ {
+ name: "self-signed leaf",
+ host: "self-signed.badssl.com",
+ expectedErr: "x509: certificate signed by unknown authority",
+ },
+ {
+ name: "untrusted root",
+ host: "untrusted-root.badssl.com",
+ expectedErr: "x509: certificate signed by unknown authority",
+ },
+ {
+ name: "revoked leaf",
+ host: "revoked.badssl.com",
+ expectedErr: "x509: “revoked.badssl.com” certificate is revoked",
+ },
+ {
+ name: "leaf missing SCTs",
+ host: "no-sct.badssl.com",
+ expectedErr: "x509: “no-sct.badssl.com” certificate is not standards compliant",
+ },
+ {
+ name: "expired leaf (custom time)",
+ host: "google.com",
+ verifyTime: time.Time{}.Add(time.Hour),
+ expectedErr: "x509: certificate has expired or is not yet valid: “*.google.com” certificate is expired",
+ },
+ {
+ name: "valid chain (custom time)",
+ host: "google.com",
+ verifyTime: time.Now(),
+ },
+ {
+ name: "leaf doesn't have acceptable ExtKeyUsage",
+ host: "google.com",
+ expectedErr: "x509: certificate specifies an incompatible key usage",
+ verifyEKU: []x509.ExtKeyUsage{x509.ExtKeyUsageEmailProtection},
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ chain := getChain(tc.host)
+ var opts x509.VerifyOptions
+ if len(chain) > 1 {
+ opts.Intermediates = x509.NewCertPool()
+ for _, c := range chain[1:] {
+ opts.Intermediates.AddCert(c)
+ }
+ }
+ if tc.verifyName != "" {
+ opts.DNSName = tc.verifyName
+ }
+ if !tc.verifyTime.IsZero() {
+ opts.CurrentTime = tc.verifyTime
+ }
+ if len(tc.verifyEKU) > 0 {
+ opts.KeyUsages = tc.verifyEKU
+ }
+
+ _, err := chain[0].Verify(opts)
+ if err != nil && tc.expectedErr == "" {
+ t.Errorf("unexpected verification error: %s", err)
+ } else if err != nil && err.Error() != tc.expectedErr {
+ t.Errorf("unexpected verification error: got %q, want %q", err.Error(), tc.expectedErr)
+ } else if err == nil && tc.expectedErr != "" {
+ t.Errorf("unexpected verification success: want %q", tc.expectedErr)
+ }
+ })
+ }
+}
diff --git a/src/crypto/x509/root_js.go b/src/crypto/x509/root_js.go
new file mode 100644
index 0000000..7b3f1e4
--- /dev/null
+++ b/src/crypto/x509/root_js.go
@@ -0,0 +1,13 @@
+// Copyright 2018 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build js && wasm
+
+package x509
+
+// Possible certificate files; stop after finding one.
+var certFiles = []string{}
+
+// Possible directories with certificate files; all will be read.
+var certDirectories = []string{}
diff --git a/src/crypto/x509/root_linux.go b/src/crypto/x509/root_linux.go
new file mode 100644
index 0000000..e32989b
--- /dev/null
+++ b/src/crypto/x509/root_linux.go
@@ -0,0 +1,22 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+// Possible certificate files; stop after finding one.
+var certFiles = []string{
+ "/etc/ssl/certs/ca-certificates.crt", // Debian/Ubuntu/Gentoo etc.
+ "/etc/pki/tls/certs/ca-bundle.crt", // Fedora/RHEL 6
+ "/etc/ssl/ca-bundle.pem", // OpenSUSE
+ "/etc/pki/tls/cacert.pem", // OpenELEC
+ "/etc/pki/ca-trust/extracted/pem/tls-ca-bundle.pem", // CentOS/RHEL 7
+ "/etc/ssl/cert.pem", // Alpine Linux
+}
+
+// Possible directories with certificate files; all will be read.
+var certDirectories = []string{
+ "/etc/ssl/certs", // SLES10/SLES11, https://golang.org/issue/12139
+ "/etc/pki/tls/certs", // Fedora/RHEL
+ "/system/etc/security/cacerts", // Android
+}
diff --git a/src/crypto/x509/root_plan9.go b/src/crypto/x509/root_plan9.go
new file mode 100644
index 0000000..3bd06fe
--- /dev/null
+++ b/src/crypto/x509/root_plan9.go
@@ -0,0 +1,39 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build plan9
+
+package x509
+
+import (
+ "os"
+)
+
+// Possible certificate files; stop after finding one.
+var certFiles = []string{
+ "/sys/lib/tls/ca.pem",
+}
+
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ return nil, nil
+}
+
+func loadSystemRoots() (*CertPool, error) {
+ roots := NewCertPool()
+ var bestErr error
+ for _, file := range certFiles {
+ data, err := os.ReadFile(file)
+ if err == nil {
+ roots.AppendCertsFromPEM(data)
+ return roots, nil
+ }
+ if bestErr == nil || (os.IsNotExist(bestErr) && !os.IsNotExist(err)) {
+ bestErr = err
+ }
+ }
+ if bestErr == nil {
+ return roots, nil
+ }
+ return nil, bestErr
+}
diff --git a/src/crypto/x509/root_solaris.go b/src/crypto/x509/root_solaris.go
new file mode 100644
index 0000000..617f269
--- /dev/null
+++ b/src/crypto/x509/root_solaris.go
@@ -0,0 +1,17 @@
+// Copyright 2015 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+// Possible certificate files; stop after finding one.
+var certFiles = []string{
+ "/etc/certs/ca-certificates.crt", // Solaris 11.2+
+ "/etc/ssl/certs/ca-certificates.crt", // Joyent SmartOS
+ "/etc/ssl/cacert.pem", // OmniOS
+}
+
+// Possible directories with certificate files; all will be read.
+var certDirectories = []string{
+ "/etc/certs/CA",
+}
diff --git a/src/crypto/x509/root_test.go b/src/crypto/x509/root_test.go
new file mode 100644
index 0000000..94ee6a6
--- /dev/null
+++ b/src/crypto/x509/root_test.go
@@ -0,0 +1,108 @@
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "testing"
+)
+
+func TestFallbackPanic(t *testing.T) {
+ defer func() {
+ if recover() == nil {
+ t.Fatal("Multiple calls to SetFallbackRoots should panic")
+ }
+ }()
+ SetFallbackRoots(nil)
+ SetFallbackRoots(nil)
+}
+
+func TestFallback(t *testing.T) {
+ // call systemRootsPool so that the sync.Once is triggered, and we can
+ // manipulate systemRoots without worrying about our working being overwritten
+ systemRootsPool()
+ if systemRoots != nil {
+ originalSystemRoots := *systemRoots
+ defer func() { systemRoots = &originalSystemRoots }()
+ }
+
+ tests := []struct {
+ name string
+ systemRoots *CertPool
+ systemPool bool
+ poolContent []*Certificate
+ forceFallback bool
+ returnsFallback bool
+ }{
+ {
+ name: "nil systemRoots",
+ returnsFallback: true,
+ },
+ {
+ name: "empty systemRoots",
+ systemRoots: NewCertPool(),
+ returnsFallback: true,
+ },
+ {
+ name: "empty systemRoots system pool",
+ systemRoots: NewCertPool(),
+ systemPool: true,
+ },
+ {
+ name: "filled systemRoots system pool",
+ systemRoots: NewCertPool(),
+ poolContent: []*Certificate{{}},
+ systemPool: true,
+ },
+ {
+ name: "filled systemRoots",
+ systemRoots: NewCertPool(),
+ poolContent: []*Certificate{{}},
+ },
+ {
+ name: "filled systemRoots, force fallback",
+ systemRoots: NewCertPool(),
+ poolContent: []*Certificate{{}},
+ forceFallback: true,
+ returnsFallback: true,
+ },
+ {
+ name: "filled systemRoot system pool, force fallback",
+ systemRoots: NewCertPool(),
+ poolContent: []*Certificate{{}},
+ systemPool: true,
+ forceFallback: true,
+ returnsFallback: true,
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ fallbacksSet = false
+ systemRoots = tc.systemRoots
+ if systemRoots != nil {
+ systemRoots.systemPool = tc.systemPool
+ }
+ for _, c := range tc.poolContent {
+ systemRoots.AddCert(c)
+ }
+ if tc.forceFallback {
+ t.Setenv("GODEBUG", "x509usefallbackroots=1")
+ } else {
+ t.Setenv("GODEBUG", "x509usefallbackroots=0")
+ }
+
+ fallbackPool := NewCertPool()
+ SetFallbackRoots(fallbackPool)
+
+ systemPoolIsFallback := systemRoots == fallbackPool
+
+ if tc.returnsFallback && !systemPoolIsFallback {
+ t.Error("systemRoots was not set to fallback pool")
+ } else if !tc.returnsFallback && systemPoolIsFallback {
+ t.Error("systemRoots was set to fallback pool when it shouldn't have been")
+ }
+ })
+ }
+}
diff --git a/src/crypto/x509/root_unix.go b/src/crypto/x509/root_unix.go
new file mode 100644
index 0000000..aa54f89
--- /dev/null
+++ b/src/crypto/x509/root_unix.go
@@ -0,0 +1,108 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build aix || dragonfly || freebsd || (js && wasm) || linux || netbsd || openbsd || solaris
+
+package x509
+
+import (
+ "io/fs"
+ "os"
+ "path/filepath"
+ "strings"
+)
+
+const (
+ // certFileEnv is the environment variable which identifies where to locate
+ // the SSL certificate file. If set this overrides the system default.
+ certFileEnv = "SSL_CERT_FILE"
+
+ // certDirEnv is the environment variable which identifies which directory
+ // to check for SSL certificate files. If set this overrides the system default.
+ // It is a colon separated list of directories.
+ // See https://www.openssl.org/docs/man1.0.2/man1/c_rehash.html.
+ certDirEnv = "SSL_CERT_DIR"
+)
+
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ return nil, nil
+}
+
+func loadSystemRoots() (*CertPool, error) {
+ roots := NewCertPool()
+
+ files := certFiles
+ if f := os.Getenv(certFileEnv); f != "" {
+ files = []string{f}
+ }
+
+ var firstErr error
+ for _, file := range files {
+ data, err := os.ReadFile(file)
+ if err == nil {
+ roots.AppendCertsFromPEM(data)
+ break
+ }
+ if firstErr == nil && !os.IsNotExist(err) {
+ firstErr = err
+ }
+ }
+
+ dirs := certDirectories
+ if d := os.Getenv(certDirEnv); d != "" {
+ // OpenSSL and BoringSSL both use ":" as the SSL_CERT_DIR separator.
+ // See:
+ // * https://golang.org/issue/35325
+ // * https://www.openssl.org/docs/man1.0.2/man1/c_rehash.html
+ dirs = strings.Split(d, ":")
+ }
+
+ for _, directory := range dirs {
+ fis, err := readUniqueDirectoryEntries(directory)
+ if err != nil {
+ if firstErr == nil && !os.IsNotExist(err) {
+ firstErr = err
+ }
+ continue
+ }
+ for _, fi := range fis {
+ data, err := os.ReadFile(directory + "/" + fi.Name())
+ if err == nil {
+ roots.AppendCertsFromPEM(data)
+ }
+ }
+ }
+
+ if roots.len() > 0 || firstErr == nil {
+ return roots, nil
+ }
+
+ return nil, firstErr
+}
+
+// readUniqueDirectoryEntries is like os.ReadDir but omits
+// symlinks that point within the directory.
+func readUniqueDirectoryEntries(dir string) ([]fs.DirEntry, error) {
+ files, err := os.ReadDir(dir)
+ if err != nil {
+ return nil, err
+ }
+ uniq := files[:0]
+ for _, f := range files {
+ if !isSameDirSymlink(f, dir) {
+ uniq = append(uniq, f)
+ }
+ }
+ return uniq, nil
+}
+
+// isSameDirSymlink reports whether fi in dir is a symlink with a
+// target not containing a slash.
+func isSameDirSymlink(f fs.DirEntry, dir string) bool {
+ if f.Type()&fs.ModeSymlink == 0 {
+ return false
+ }
+ target, err := os.Readlink(filepath.Join(dir, f.Name()))
+ return err == nil && !strings.Contains(target, "/")
+}
diff --git a/src/crypto/x509/root_unix_test.go b/src/crypto/x509/root_unix_test.go
new file mode 100644
index 0000000..d5215b9
--- /dev/null
+++ b/src/crypto/x509/root_unix_test.go
@@ -0,0 +1,228 @@
+// Copyright 2017 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build dragonfly || freebsd || linux || netbsd || openbsd || solaris
+
+package x509
+
+import (
+ "bytes"
+ "fmt"
+ "os"
+ "path/filepath"
+ "reflect"
+ "strings"
+ "testing"
+)
+
+const (
+ testDir = "testdata"
+ testDirCN = "test-dir"
+ testFile = "test-file.crt"
+ testFileCN = "test-file"
+ testMissing = "missing"
+)
+
+func TestEnvVars(t *testing.T) {
+ testCases := []struct {
+ name string
+ fileEnv string
+ dirEnv string
+ files []string
+ dirs []string
+ cns []string
+ }{
+ {
+ // Environment variables override the default locations preventing fall through.
+ name: "override-defaults",
+ fileEnv: testMissing,
+ dirEnv: testMissing,
+ files: []string{testFile},
+ dirs: []string{testDir},
+ cns: nil,
+ },
+ {
+ // File environment overrides default file locations.
+ name: "file",
+ fileEnv: testFile,
+ dirEnv: "",
+ files: nil,
+ dirs: nil,
+ cns: []string{testFileCN},
+ },
+ {
+ // Directory environment overrides default directory locations.
+ name: "dir",
+ fileEnv: "",
+ dirEnv: testDir,
+ files: nil,
+ dirs: nil,
+ cns: []string{testDirCN},
+ },
+ {
+ // File & directory environment overrides both default locations.
+ name: "file+dir",
+ fileEnv: testFile,
+ dirEnv: testDir,
+ files: nil,
+ dirs: nil,
+ cns: []string{testFileCN, testDirCN},
+ },
+ {
+ // Environment variable empty / unset uses default locations.
+ name: "empty-fall-through",
+ fileEnv: "",
+ dirEnv: "",
+ files: []string{testFile},
+ dirs: []string{testDir},
+ cns: []string{testFileCN, testDirCN},
+ },
+ }
+
+ // Save old settings so we can restore before the test ends.
+ origCertFiles, origCertDirectories := certFiles, certDirectories
+ origFile, origDir := os.Getenv(certFileEnv), os.Getenv(certDirEnv)
+ defer func() {
+ certFiles = origCertFiles
+ certDirectories = origCertDirectories
+ os.Setenv(certFileEnv, origFile)
+ os.Setenv(certDirEnv, origDir)
+ }()
+
+ for _, tc := range testCases {
+ t.Run(tc.name, func(t *testing.T) {
+ if err := os.Setenv(certFileEnv, tc.fileEnv); err != nil {
+ t.Fatalf("setenv %q failed: %v", certFileEnv, err)
+ }
+ if err := os.Setenv(certDirEnv, tc.dirEnv); err != nil {
+ t.Fatalf("setenv %q failed: %v", certDirEnv, err)
+ }
+
+ certFiles, certDirectories = tc.files, tc.dirs
+
+ r, err := loadSystemRoots()
+ if err != nil {
+ t.Fatal("unexpected failure:", err)
+ }
+
+ if r == nil {
+ t.Fatal("nil roots")
+ }
+
+ // Verify that the returned certs match, otherwise report where the mismatch is.
+ for i, cn := range tc.cns {
+ if i >= r.len() {
+ t.Errorf("missing cert %v @ %v", cn, i)
+ } else if r.mustCert(t, i).Subject.CommonName != cn {
+ fmt.Printf("%#v\n", r.mustCert(t, 0).Subject)
+ t.Errorf("unexpected cert common name %q, want %q", r.mustCert(t, i).Subject.CommonName, cn)
+ }
+ }
+ if r.len() > len(tc.cns) {
+ t.Errorf("got %v certs, which is more than %v wanted", r.len(), len(tc.cns))
+ }
+ })
+ }
+}
+
+// Ensure that "SSL_CERT_DIR" when used as the environment
+// variable delimited by colons, allows loadSystemRoots to
+// load all the roots from the respective directories.
+// See https://golang.org/issue/35325.
+func TestLoadSystemCertsLoadColonSeparatedDirs(t *testing.T) {
+ origFile, origDir := os.Getenv(certFileEnv), os.Getenv(certDirEnv)
+ origCertFiles := certFiles[:]
+
+ // To prevent any other certs from being loaded in
+ // through "SSL_CERT_FILE" or from known "certFiles",
+ // clear them all, and they'll be reverting on defer.
+ certFiles = certFiles[:0]
+ os.Setenv(certFileEnv, "")
+
+ defer func() {
+ certFiles = origCertFiles[:]
+ os.Setenv(certDirEnv, origDir)
+ os.Setenv(certFileEnv, origFile)
+ }()
+
+ tmpDir := t.TempDir()
+
+ rootPEMs := []string{
+ gtsRoot,
+ googleLeaf,
+ startComRoot,
+ }
+
+ var certDirs []string
+ for i, certPEM := range rootPEMs {
+ certDir := filepath.Join(tmpDir, fmt.Sprintf("cert-%d", i))
+ if err := os.MkdirAll(certDir, 0755); err != nil {
+ t.Fatalf("Failed to create certificate dir: %v", err)
+ }
+ certOutFile := filepath.Join(certDir, "cert.crt")
+ if err := os.WriteFile(certOutFile, []byte(certPEM), 0655); err != nil {
+ t.Fatalf("Failed to write certificate to file: %v", err)
+ }
+ certDirs = append(certDirs, certDir)
+ }
+
+ // Sanity check: the number of certDirs should be equal to the number of roots.
+ if g, w := len(certDirs), len(rootPEMs); g != w {
+ t.Fatalf("Failed sanity check: len(certsDir)=%d is not equal to len(rootsPEMS)=%d", g, w)
+ }
+
+ // Now finally concatenate them with a colon.
+ colonConcatCertDirs := strings.Join(certDirs, ":")
+ os.Setenv(certDirEnv, colonConcatCertDirs)
+ gotPool, err := loadSystemRoots()
+ if err != nil {
+ t.Fatalf("Failed to load system roots: %v", err)
+ }
+ subjects := gotPool.Subjects()
+ // We expect exactly len(rootPEMs) subjects back.
+ if g, w := len(subjects), len(rootPEMs); g != w {
+ t.Fatalf("Invalid number of subjects: got %d want %d", g, w)
+ }
+
+ wantPool := NewCertPool()
+ for _, certPEM := range rootPEMs {
+ wantPool.AppendCertsFromPEM([]byte(certPEM))
+ }
+ strCertPool := func(p *CertPool) string {
+ return string(bytes.Join(p.Subjects(), []byte("\n")))
+ }
+
+ if !certPoolEqual(gotPool, wantPool) {
+ g, w := strCertPool(gotPool), strCertPool(wantPool)
+ t.Fatalf("Mismatched certPools\nGot:\n%s\n\nWant:\n%s", g, w)
+ }
+}
+
+func TestReadUniqueDirectoryEntries(t *testing.T) {
+ tmp := t.TempDir()
+ temp := func(base string) string { return filepath.Join(tmp, base) }
+ if f, err := os.Create(temp("file")); err != nil {
+ t.Fatal(err)
+ } else {
+ f.Close()
+ }
+ if err := os.Symlink("target-in", temp("link-in")); err != nil {
+ t.Fatal(err)
+ }
+ if err := os.Symlink("../target-out", temp("link-out")); err != nil {
+ t.Fatal(err)
+ }
+ got, err := readUniqueDirectoryEntries(tmp)
+ if err != nil {
+ t.Fatal(err)
+ }
+ gotNames := []string{}
+ for _, fi := range got {
+ gotNames = append(gotNames, fi.Name())
+ }
+ wantNames := []string{"file", "link-out"}
+ if !reflect.DeepEqual(gotNames, wantNames) {
+ t.Errorf("got %q; want %q", gotNames, wantNames)
+ }
+}
diff --git a/src/crypto/x509/root_windows.go b/src/crypto/x509/root_windows.go
new file mode 100644
index 0000000..76d6e6a
--- /dev/null
+++ b/src/crypto/x509/root_windows.go
@@ -0,0 +1,276 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "bytes"
+ "errors"
+ "syscall"
+ "unsafe"
+)
+
+func loadSystemRoots() (*CertPool, error) {
+ return &CertPool{systemPool: true}, nil
+}
+
+// Creates a new *syscall.CertContext representing the leaf certificate in an in-memory
+// certificate store containing itself and all of the intermediate certificates specified
+// in the opts.Intermediates CertPool.
+//
+// A pointer to the in-memory store is available in the returned CertContext's Store field.
+// The store is automatically freed when the CertContext is freed using
+// syscall.CertFreeCertificateContext.
+func createStoreContext(leaf *Certificate, opts *VerifyOptions) (*syscall.CertContext, error) {
+ var storeCtx *syscall.CertContext
+
+ leafCtx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &leaf.Raw[0], uint32(len(leaf.Raw)))
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.CertFreeCertificateContext(leafCtx)
+
+ handle, err := syscall.CertOpenStore(syscall.CERT_STORE_PROV_MEMORY, 0, 0, syscall.CERT_STORE_DEFER_CLOSE_UNTIL_LAST_FREE_FLAG, 0)
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.CertCloseStore(handle, 0)
+
+ err = syscall.CertAddCertificateContextToStore(handle, leafCtx, syscall.CERT_STORE_ADD_ALWAYS, &storeCtx)
+ if err != nil {
+ return nil, err
+ }
+
+ if opts.Intermediates != nil {
+ for i := 0; i < opts.Intermediates.len(); i++ {
+ intermediate, err := opts.Intermediates.cert(i)
+ if err != nil {
+ return nil, err
+ }
+ ctx, err := syscall.CertCreateCertificateContext(syscall.X509_ASN_ENCODING|syscall.PKCS_7_ASN_ENCODING, &intermediate.Raw[0], uint32(len(intermediate.Raw)))
+ if err != nil {
+ return nil, err
+ }
+
+ err = syscall.CertAddCertificateContextToStore(handle, ctx, syscall.CERT_STORE_ADD_ALWAYS, nil)
+ syscall.CertFreeCertificateContext(ctx)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ return storeCtx, nil
+}
+
+// extractSimpleChain extracts the final certificate chain from a CertSimpleChain.
+func extractSimpleChain(simpleChain **syscall.CertSimpleChain, count int) (chain []*Certificate, err error) {
+ if simpleChain == nil || count == 0 {
+ return nil, errors.New("x509: invalid simple chain")
+ }
+
+ simpleChains := unsafe.Slice(simpleChain, count)
+ lastChain := simpleChains[count-1]
+ elements := unsafe.Slice(lastChain.Elements, lastChain.NumElements)
+ for i := 0; i < int(lastChain.NumElements); i++ {
+ // Copy the buf, since ParseCertificate does not create its own copy.
+ cert := elements[i].CertContext
+ encodedCert := unsafe.Slice(cert.EncodedCert, cert.Length)
+ buf := bytes.Clone(encodedCert)
+ parsedCert, err := ParseCertificate(buf)
+ if err != nil {
+ return nil, err
+ }
+ chain = append(chain, parsedCert)
+ }
+
+ return chain, nil
+}
+
+// checkChainTrustStatus checks the trust status of the certificate chain, translating
+// any errors it finds into Go errors in the process.
+func checkChainTrustStatus(c *Certificate, chainCtx *syscall.CertChainContext) error {
+ if chainCtx.TrustStatus.ErrorStatus != syscall.CERT_TRUST_NO_ERROR {
+ status := chainCtx.TrustStatus.ErrorStatus
+ switch status {
+ case syscall.CERT_TRUST_IS_NOT_TIME_VALID:
+ return CertificateInvalidError{c, Expired, ""}
+ case syscall.CERT_TRUST_IS_NOT_VALID_FOR_USAGE:
+ return CertificateInvalidError{c, IncompatibleUsage, ""}
+ // TODO(filippo): surface more error statuses.
+ default:
+ return UnknownAuthorityError{c, nil, nil}
+ }
+ }
+ return nil
+}
+
+// checkChainSSLServerPolicy checks that the certificate chain in chainCtx is valid for
+// use as a certificate chain for a SSL/TLS server.
+func checkChainSSLServerPolicy(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) error {
+ servernamep, err := syscall.UTF16PtrFromString(opts.DNSName)
+ if err != nil {
+ return err
+ }
+ sslPara := &syscall.SSLExtraCertChainPolicyPara{
+ AuthType: syscall.AUTHTYPE_SERVER,
+ ServerName: servernamep,
+ }
+ sslPara.Size = uint32(unsafe.Sizeof(*sslPara))
+
+ para := &syscall.CertChainPolicyPara{
+ ExtraPolicyPara: (syscall.Pointer)(unsafe.Pointer(sslPara)),
+ }
+ para.Size = uint32(unsafe.Sizeof(*para))
+
+ status := syscall.CertChainPolicyStatus{}
+ err = syscall.CertVerifyCertificateChainPolicy(syscall.CERT_CHAIN_POLICY_SSL, chainCtx, para, &status)
+ if err != nil {
+ return err
+ }
+
+ // TODO(mkrautz): use the lChainIndex and lElementIndex fields
+ // of the CertChainPolicyStatus to provide proper context, instead
+ // using c.
+ if status.Error != 0 {
+ switch status.Error {
+ case syscall.CERT_E_EXPIRED:
+ return CertificateInvalidError{c, Expired, ""}
+ case syscall.CERT_E_CN_NO_MATCH:
+ return HostnameError{c, opts.DNSName}
+ case syscall.CERT_E_UNTRUSTEDROOT:
+ return UnknownAuthorityError{c, nil, nil}
+ default:
+ return UnknownAuthorityError{c, nil, nil}
+ }
+ }
+
+ return nil
+}
+
+// windowsExtKeyUsageOIDs are the C NUL-terminated string representations of the
+// OIDs for use with the Windows API.
+var windowsExtKeyUsageOIDs = make(map[ExtKeyUsage][]byte, len(extKeyUsageOIDs))
+
+func init() {
+ for _, eku := range extKeyUsageOIDs {
+ windowsExtKeyUsageOIDs[eku.extKeyUsage] = []byte(eku.oid.String() + "\x00")
+ }
+}
+
+func verifyChain(c *Certificate, chainCtx *syscall.CertChainContext, opts *VerifyOptions) (chain []*Certificate, err error) {
+ err = checkChainTrustStatus(c, chainCtx)
+ if err != nil {
+ return nil, err
+ }
+
+ if opts != nil && len(opts.DNSName) > 0 {
+ err = checkChainSSLServerPolicy(c, chainCtx, opts)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ chain, err = extractSimpleChain(chainCtx.Chains, int(chainCtx.ChainCount))
+ if err != nil {
+ return nil, err
+ }
+ if len(chain) == 0 {
+ return nil, errors.New("x509: internal error: system verifier returned an empty chain")
+ }
+
+ // Mitigate CVE-2020-0601, where the Windows system verifier might be
+ // tricked into using custom curve parameters for a trusted root, by
+ // double-checking all ECDSA signatures. If the system was tricked into
+ // using spoofed parameters, the signature will be invalid for the correct
+ // ones we parsed. (We don't support custom curves ourselves.)
+ for i, parent := range chain[1:] {
+ if parent.PublicKeyAlgorithm != ECDSA {
+ continue
+ }
+ if err := parent.CheckSignature(chain[i].SignatureAlgorithm,
+ chain[i].RawTBSCertificate, chain[i].Signature); err != nil {
+ return nil, err
+ }
+ }
+ return chain, nil
+}
+
+// systemVerify is like Verify, except that it uses CryptoAPI calls
+// to build certificate chains and verify them.
+func (c *Certificate) systemVerify(opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ storeCtx, err := createStoreContext(c, opts)
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.CertFreeCertificateContext(storeCtx)
+
+ para := new(syscall.CertChainPara)
+ para.Size = uint32(unsafe.Sizeof(*para))
+
+ keyUsages := opts.KeyUsages
+ if len(keyUsages) == 0 {
+ keyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
+ }
+ oids := make([]*byte, 0, len(keyUsages))
+ for _, eku := range keyUsages {
+ if eku == ExtKeyUsageAny {
+ oids = nil
+ break
+ }
+ if oid, ok := windowsExtKeyUsageOIDs[eku]; ok {
+ oids = append(oids, &oid[0])
+ }
+ }
+ if oids != nil {
+ para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_OR
+ para.RequestedUsage.Usage.Length = uint32(len(oids))
+ para.RequestedUsage.Usage.UsageIdentifiers = &oids[0]
+ } else {
+ para.RequestedUsage.Type = syscall.USAGE_MATCH_TYPE_AND
+ para.RequestedUsage.Usage.Length = 0
+ para.RequestedUsage.Usage.UsageIdentifiers = nil
+ }
+
+ var verifyTime *syscall.Filetime
+ if opts != nil && !opts.CurrentTime.IsZero() {
+ ft := syscall.NsecToFiletime(opts.CurrentTime.UnixNano())
+ verifyTime = &ft
+ }
+
+ // The default is to return only the highest quality chain,
+ // setting this flag will add additional lower quality contexts.
+ // These are returned in the LowerQualityChains field.
+ const CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS = 0x00000080
+
+ // CertGetCertificateChain will traverse Windows's root stores in an attempt to build a verified certificate chain
+ var topCtx *syscall.CertChainContext
+ err = syscall.CertGetCertificateChain(syscall.Handle(0), storeCtx, verifyTime, storeCtx.Store, para, CERT_CHAIN_RETURN_LOWER_QUALITY_CONTEXTS, 0, &topCtx)
+ if err != nil {
+ return nil, err
+ }
+ defer syscall.CertFreeCertificateChain(topCtx)
+
+ chain, topErr := verifyChain(c, topCtx, opts)
+ if topErr == nil {
+ chains = append(chains, chain)
+ }
+
+ if lqCtxCount := topCtx.LowerQualityChainCount; lqCtxCount > 0 {
+ lqCtxs := unsafe.Slice(topCtx.LowerQualityChains, lqCtxCount)
+ for _, ctx := range lqCtxs {
+ chain, err := verifyChain(c, ctx, opts)
+ if err == nil {
+ chains = append(chains, chain)
+ }
+ }
+ }
+
+ if len(chains) == 0 {
+ // Return the error from the highest quality context.
+ return nil, topErr
+ }
+
+ return chains, nil
+}
diff --git a/src/crypto/x509/root_windows_test.go b/src/crypto/x509/root_windows_test.go
new file mode 100644
index 0000000..f6dafe4
--- /dev/null
+++ b/src/crypto/x509/root_windows_test.go
@@ -0,0 +1,115 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509_test
+
+import (
+ "crypto/tls"
+ "crypto/x509"
+ "errors"
+ "internal/testenv"
+ "net"
+ "strings"
+ "syscall"
+ "testing"
+ "time"
+)
+
+func TestPlatformVerifier(t *testing.T) {
+ if !testenv.HasExternalNetwork() {
+ t.Skip()
+ }
+
+ getChain := func(t *testing.T, host string) []*x509.Certificate {
+ t.Helper()
+ c, err := tls.Dial("tcp", host+":443", &tls.Config{InsecureSkipVerify: true})
+ if err != nil {
+ // From https://docs.microsoft.com/en-us/windows/win32/winsock/windows-sockets-error-codes-2,
+ // matching the error string observed in https://go.dev/issue/52094.
+ const WSATRY_AGAIN syscall.Errno = 11002
+ var errDNS *net.DNSError
+ if strings.HasSuffix(host, ".badssl.com") && errors.As(err, &errDNS) && strings.HasSuffix(errDNS.Err, WSATRY_AGAIN.Error()) {
+ t.Log(err)
+ testenv.SkipFlaky(t, 52094)
+ }
+
+ t.Fatalf("tls connection failed: %s", err)
+ }
+ return c.ConnectionState().PeerCertificates
+ }
+
+ tests := []struct {
+ name string
+ host string
+ verifyName string
+ verifyTime time.Time
+ expectedErr string
+ }{
+ {
+ // whatever google.com serves should, hopefully, be trusted
+ name: "valid chain",
+ host: "google.com",
+ },
+ {
+ name: "expired leaf",
+ host: "expired.badssl.com",
+ expectedErr: "x509: certificate has expired or is not yet valid: ",
+ },
+ {
+ name: "wrong host for leaf",
+ host: "wrong.host.badssl.com",
+ verifyName: "wrong.host.badssl.com",
+ expectedErr: "x509: certificate is valid for *.badssl.com, badssl.com, not wrong.host.badssl.com",
+ },
+ {
+ name: "self-signed leaf",
+ host: "self-signed.badssl.com",
+ expectedErr: "x509: certificate signed by unknown authority",
+ },
+ {
+ name: "untrusted root",
+ host: "untrusted-root.badssl.com",
+ expectedErr: "x509: certificate signed by unknown authority",
+ },
+ {
+ name: "expired leaf (custom time)",
+ host: "google.com",
+ verifyTime: time.Time{}.Add(time.Hour),
+ expectedErr: "x509: certificate has expired or is not yet valid: ",
+ },
+ {
+ name: "valid chain (custom time)",
+ host: "google.com",
+ verifyTime: time.Now(),
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ chain := getChain(t, tc.host)
+ var opts x509.VerifyOptions
+ if len(chain) > 1 {
+ opts.Intermediates = x509.NewCertPool()
+ for _, c := range chain[1:] {
+ opts.Intermediates.AddCert(c)
+ }
+ }
+ if tc.verifyName != "" {
+ opts.DNSName = tc.verifyName
+ }
+ if !tc.verifyTime.IsZero() {
+ opts.CurrentTime = tc.verifyTime
+ }
+
+ _, err := chain[0].Verify(opts)
+ if err != nil && tc.expectedErr == "" {
+ t.Errorf("unexpected verification error: %s", err)
+ } else if err != nil && err.Error() != tc.expectedErr {
+ t.Errorf("unexpected verification error: got %q, want %q", err.Error(), tc.expectedErr)
+ } else if err == nil && tc.expectedErr != "" {
+ t.Errorf("unexpected verification success: want %q", tc.expectedErr)
+ }
+ })
+ }
+}
diff --git a/src/crypto/x509/sec1.go b/src/crypto/x509/sec1.go
new file mode 100644
index 0000000..027c17c
--- /dev/null
+++ b/src/crypto/x509/sec1.go
@@ -0,0 +1,136 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "crypto/ecdh"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "encoding/asn1"
+ "errors"
+ "fmt"
+ "math/big"
+)
+
+const ecPrivKeyVersion = 1
+
+// ecPrivateKey reflects an ASN.1 Elliptic Curve Private Key Structure.
+// References:
+//
+// RFC 5915
+// SEC1 - http://www.secg.org/sec1-v2.pdf
+//
+// Per RFC 5915 the NamedCurveOID is marked as ASN.1 OPTIONAL, however in
+// most cases it is not.
+type ecPrivateKey struct {
+ Version int
+ PrivateKey []byte
+ NamedCurveOID asn1.ObjectIdentifier `asn1:"optional,explicit,tag:0"`
+ PublicKey asn1.BitString `asn1:"optional,explicit,tag:1"`
+}
+
+// ParseECPrivateKey parses an EC private key in SEC 1, ASN.1 DER form.
+//
+// This kind of key is commonly encoded in PEM blocks of type "EC PRIVATE KEY".
+func ParseECPrivateKey(der []byte) (*ecdsa.PrivateKey, error) {
+ return parseECPrivateKey(nil, der)
+}
+
+// MarshalECPrivateKey converts an EC private key to SEC 1, ASN.1 DER form.
+//
+// This kind of key is commonly encoded in PEM blocks of type "EC PRIVATE KEY".
+// For a more flexible key format which is not EC specific, use
+// MarshalPKCS8PrivateKey.
+func MarshalECPrivateKey(key *ecdsa.PrivateKey) ([]byte, error) {
+ oid, ok := oidFromNamedCurve(key.Curve)
+ if !ok {
+ return nil, errors.New("x509: unknown elliptic curve")
+ }
+
+ return marshalECPrivateKeyWithOID(key, oid)
+}
+
+// marshalECPrivateKeyWithOID marshals an EC private key into ASN.1, DER format and
+// sets the curve ID to the given OID, or omits it if OID is nil.
+func marshalECPrivateKeyWithOID(key *ecdsa.PrivateKey, oid asn1.ObjectIdentifier) ([]byte, error) {
+ if !key.Curve.IsOnCurve(key.X, key.Y) {
+ return nil, errors.New("invalid elliptic key public key")
+ }
+ privateKey := make([]byte, (key.Curve.Params().N.BitLen()+7)/8)
+ return asn1.Marshal(ecPrivateKey{
+ Version: 1,
+ PrivateKey: key.D.FillBytes(privateKey),
+ NamedCurveOID: oid,
+ PublicKey: asn1.BitString{Bytes: elliptic.Marshal(key.Curve, key.X, key.Y)},
+ })
+}
+
+// marshalECPrivateKeyWithOID marshals an EC private key into ASN.1, DER format
+// suitable for NIST curves.
+func marshalECDHPrivateKey(key *ecdh.PrivateKey) ([]byte, error) {
+ return asn1.Marshal(ecPrivateKey{
+ Version: 1,
+ PrivateKey: key.Bytes(),
+ PublicKey: asn1.BitString{Bytes: key.PublicKey().Bytes()},
+ })
+}
+
+// parseECPrivateKey parses an ASN.1 Elliptic Curve Private Key Structure.
+// The OID for the named curve may be provided from another source (such as
+// the PKCS8 container) - if it is provided then use this instead of the OID
+// that may exist in the EC private key structure.
+func parseECPrivateKey(namedCurveOID *asn1.ObjectIdentifier, der []byte) (key *ecdsa.PrivateKey, err error) {
+ var privKey ecPrivateKey
+ if _, err := asn1.Unmarshal(der, &privKey); err != nil {
+ if _, err := asn1.Unmarshal(der, &pkcs8{}); err == nil {
+ return nil, errors.New("x509: failed to parse private key (use ParsePKCS8PrivateKey instead for this key format)")
+ }
+ if _, err := asn1.Unmarshal(der, &pkcs1PrivateKey{}); err == nil {
+ return nil, errors.New("x509: failed to parse private key (use ParsePKCS1PrivateKey instead for this key format)")
+ }
+ return nil, errors.New("x509: failed to parse EC private key: " + err.Error())
+ }
+ if privKey.Version != ecPrivKeyVersion {
+ return nil, fmt.Errorf("x509: unknown EC private key version %d", privKey.Version)
+ }
+
+ var curve elliptic.Curve
+ if namedCurveOID != nil {
+ curve = namedCurveFromOID(*namedCurveOID)
+ } else {
+ curve = namedCurveFromOID(privKey.NamedCurveOID)
+ }
+ if curve == nil {
+ return nil, errors.New("x509: unknown elliptic curve")
+ }
+
+ k := new(big.Int).SetBytes(privKey.PrivateKey)
+ curveOrder := curve.Params().N
+ if k.Cmp(curveOrder) >= 0 {
+ return nil, errors.New("x509: invalid elliptic curve private key value")
+ }
+ priv := new(ecdsa.PrivateKey)
+ priv.Curve = curve
+ priv.D = k
+
+ privateKey := make([]byte, (curveOrder.BitLen()+7)/8)
+
+ // Some private keys have leading zero padding. This is invalid
+ // according to [SEC1], but this code will ignore it.
+ for len(privKey.PrivateKey) > len(privateKey) {
+ if privKey.PrivateKey[0] != 0 {
+ return nil, errors.New("x509: invalid private key length")
+ }
+ privKey.PrivateKey = privKey.PrivateKey[1:]
+ }
+
+ // Some private keys remove all leading zeros, this is also invalid
+ // according to [SEC1] but since OpenSSL used to do this, we ignore
+ // this too.
+ copy(privateKey[len(privateKey)-len(privKey.PrivateKey):], privKey.PrivateKey)
+ priv.X, priv.Y = curve.ScalarBaseMult(privateKey)
+
+ return priv, nil
+}
diff --git a/src/crypto/x509/sec1_test.go b/src/crypto/x509/sec1_test.go
new file mode 100644
index 0000000..9ac2518
--- /dev/null
+++ b/src/crypto/x509/sec1_test.go
@@ -0,0 +1,66 @@
+// Copyright 2012 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "bytes"
+ "encoding/hex"
+ "strings"
+ "testing"
+)
+
+var ecKeyTests = []struct {
+ derHex string
+ shouldReserialize bool
+}{
+ // Generated using:
+ // openssl ecparam -genkey -name secp384r1 -outform PEM
+ {"3081a40201010430bdb9839c08ee793d1157886a7a758a3c8b2a17a4df48f17ace57c72c56b4723cf21dcda21d4e1ad57ff034f19fcfd98ea00706052b81040022a16403620004feea808b5ee2429cfcce13c32160e1c960990bd050bb0fdf7222f3decd0a55008e32a6aa3c9062051c4cba92a7a3b178b24567412d43cdd2f882fa5addddd726fe3e208d2c26d733a773a597abb749714df7256ead5105fa6e7b3650de236b50", true},
+ // This key was generated by GnuTLS and has illegal zero-padding of the
+ // private key. See https://golang.org/issues/13699.
+ {"3078020101042100f9f43a04b9bdc3ab01f53be6df80e7a7bc3eaf7b87fc24e630a4a0aa97633645a00a06082a8648ce3d030107a1440342000441a51bc318461b4c39a45048a16d4fc2a935b1ea7fe86e8c1fa219d6f2438f7c7fd62957d3442efb94b6a23eb0ea66dda663dc42f379cda6630b21b7888a5d3d", false},
+ // This was generated using an old version of OpenSSL and is missing a
+ // leading zero byte in the private key that should be present.
+ {"3081db0201010441607b4f985774ac21e633999794542e09312073480baa69550914d6d43d8414441e61b36650567901da714f94dffb3ce0e2575c31928a0997d51df5c440e983ca17a00706052b81040023a181890381860004001661557afedd7ac8d6b70e038e576558c626eb62edda36d29c3a1310277c11f67a8c6f949e5430a37dcfb95d902c1b5b5379c389873b9dd17be3bdb088a4774a7401072f830fb9a08d93bfa50a03dd3292ea07928724ddb915d831917a338f6b0aecfbc3cf5352c4a1295d356890c41c34116d29eeb93779aab9d9d78e2613437740f6", false},
+}
+
+func TestParseECPrivateKey(t *testing.T) {
+ for i, test := range ecKeyTests {
+ derBytes, _ := hex.DecodeString(test.derHex)
+ key, err := ParseECPrivateKey(derBytes)
+ if err != nil {
+ t.Fatalf("#%d: failed to decode EC private key: %s", i, err)
+ }
+ serialized, err := MarshalECPrivateKey(key)
+ if err != nil {
+ t.Fatalf("#%d: failed to encode EC private key: %s", i, err)
+ }
+ matches := bytes.Equal(serialized, derBytes)
+ if matches != test.shouldReserialize {
+ t.Fatalf("#%d: when serializing key: matches=%t, should match=%t: original %x, reserialized %x", i, matches, test.shouldReserialize, serialized, derBytes)
+ }
+ }
+}
+
+const hexECTestPKCS1Key = "3082025c02010002818100b1a1e0945b9289c4d3f1329f8a982c4a2dcd59bfd372fb8085a9c517554607ebd2f7990eef216ac9f4605f71a03b04f42a5255b158cf8e0844191f5119348baa44c35056e20609bcf9510f30ead4b481c81d7865fb27b8e0090e112b717f3ee08cdfc4012da1f1f7cf2a1bc34c73a54a12b06372d09714742dd7895eadde4aa5020301000102818062b7fa1db93e993e40237de4d89b7591cc1ea1d04fed4904c643f17ae4334557b4295270d0491c161cb02a9af557978b32b20b59c267a721c4e6c956c2d147046e9ae5f2da36db0106d70021fa9343455f8f973a4b355a26fd19e6b39dee0405ea2b32deddf0f4817759ef705d02b34faab9ca93c6766e9f722290f119f34449024100d9c29a4a013a90e35fd1be14a3f747c589fac613a695282d61812a711906b8a0876c6181f0333ca1066596f57bff47e7cfcabf19c0fc69d9cd76df743038b3cb024100d0d3546fecf879b5551f2bd2c05e6385f2718a08a6face3d2aecc9d7e03645a480a46c81662c12ad6bd6901e3bd4f38029462de7290859567cdf371c79088d4f024100c254150657e460ea58573fcf01a82a4791e3d6223135c8bdfed69afe84fbe7857274f8eb5165180507455f9b4105c6b08b51fe8a481bb986a202245576b713530240045700003b7a867d0041df9547ae2e7f50248febd21c9040b12dae9c2feab0d3d4609668b208e4727a3541557f84d372ac68eaf74ce1018a4c9a0ef92682c8fd02405769731480bb3a4570abf422527c5f34bf732fa6c1e08cc322753c511ce055fac20fc770025663ad3165324314df907f1f1942f0448a7e9cdbf87ecd98b92156"
+const hexECTestPKCS8Key = "30820278020100300d06092a864886f70d0101010500048202623082025e02010002818100cfb1b5bf9685ffa97b4f99df4ff122b70e59ac9b992f3bc2b3dde17d53c1a34928719b02e8fd17839499bfbd515bd6ef99c7a1c47a239718fe36bfd824c0d96060084b5f67f0273443007a24dfaf5634f7772c9346e10eb294c2306671a5a5e719ae24b4de467291bc571014b0e02dec04534d66a9bb171d644b66b091780e8d020301000102818100b595778383c4afdbab95d2bfed12b3f93bb0a73a7ad952f44d7185fd9ec6c34de8f03a48770f2009c8580bcd275e9632714e9a5e3f32f29dc55474b2329ff0ebc08b3ffcb35bc96e6516b483df80a4a59cceb71918cbabf91564e64a39d7e35dce21cb3031824fdbc845dba6458852ec16af5dddf51a8397a8797ae0337b1439024100ea0eb1b914158c70db39031dd8904d6f18f408c85fbbc592d7d20dee7986969efbda081fdf8bc40e1b1336d6b638110c836bfdc3f314560d2e49cd4fbde1e20b024100e32a4e793b574c9c4a94c8803db5152141e72d03de64e54ef2c8ed104988ca780cd11397bc359630d01b97ebd87067c5451ba777cf045ca23f5912f1031308c702406dfcdbbd5a57c9f85abc4edf9e9e29153507b07ce0a7ef6f52e60dcfebe1b8341babd8b789a837485da6c8d55b29bbb142ace3c24a1f5b54b454d01b51e2ad03024100bd6a2b60dee01e1b3bfcef6a2f09ed027c273cdbbaf6ba55a80f6dcc64e4509ee560f84b4f3e076bd03b11e42fe71a3fdd2dffe7e0902c8584f8cad877cdc945024100aa512fa4ada69881f1d8bb8ad6614f192b83200aef5edf4811313d5ef30a86cbd0a90f7b025c71ea06ec6b34db6306c86b1040670fd8654ad7291d066d06d031"
+
+var ecMismatchKeyTests = []struct {
+ hexKey string
+ errorContains string
+}{
+ {hexKey: hexECTestPKCS8Key, errorContains: "use ParsePKCS8PrivateKey instead"},
+ {hexKey: hexECTestPKCS1Key, errorContains: "use ParsePKCS1PrivateKey instead"},
+}
+
+func TestECMismatchKeyFormat(t *testing.T) {
+ for i, test := range ecMismatchKeyTests {
+ derBytes, _ := hex.DecodeString(test.hexKey)
+ _, err := ParseECPrivateKey(derBytes)
+ if !strings.Contains(err.Error(), test.errorContains) {
+ t.Errorf("#%d: expected error containing %q, got %s", i, test.errorContains, err)
+ }
+ }
+}
diff --git a/src/crypto/x509/test-file.crt b/src/crypto/x509/test-file.crt
new file mode 100644
index 0000000..caa83b9
--- /dev/null
+++ b/src/crypto/x509/test-file.crt
@@ -0,0 +1,32 @@
+-----BEGIN CERTIFICATE-----
+MIIFbTCCA1WgAwIBAgIJAN338vEmMtLsMA0GCSqGSIb3DQEBCwUAME0xCzAJBgNV
+BAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYDVQQKDAxHb2xhbmcgVGVz
+dHMxEjAQBgNVBAMMCXRlc3QtZmlsZTAeFw0xNzAyMDEyMzUyMDhaFw0yNzAxMzAy
+MzUyMDhaME0xCzAJBgNVBAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYD
+VQQKDAxHb2xhbmcgVGVzdHMxEjAQBgNVBAMMCXRlc3QtZmlsZTCCAiIwDQYJKoZI
+hvcNAQEBBQADggIPADCCAgoCggIBAPMGiLjdiffQo3Xc8oUe7wsDhSaAJFOhO6Qs
+i0xYrYl7jmCuz9rGD2fdgk5cLqGazKuQ6fIFzHXFU2BKs4CWXt9KO0KFEhfvZeuW
+jG5d7C1ZUiuKOrPqjKVu8SZtFPc7y7Ke7msXzY+Z2LLyiJJ93LCMq4+cTSGNXVlI
+KqUxhxeoD5/QkUPyQy/ilu3GMYfx/YORhDP6Edcuskfj8wRh1UxBejP8YPMvI6St
+cE2GkxoEGqDWnQ/61F18te6WI3MD29tnKXOkXVhnSC+yvRLljotW2/tAhHKBG4tj
+iQWT5Ri4Wrw2tXxPKRLsVWc7e1/hdxhnuvYpXkWNhKsm002jzkFXlzfEwPd8nZdw
+5aT6gPUBN2AAzdoqZI7E200i0orEF7WaSoMfjU1tbHvExp3vyAPOfJ5PS2MQ6W03
+Zsy5dTVH+OBH++rkRzQCFcnIv/OIhya5XZ9KX9nFPgBEP7Xq2A+IjH7B6VN/S/bv
+8lhp2V+SQvlew9GttKC4hKuPsl5o7+CMbcqcNUdxm9gGkN8epGEKCuix97bpNlxN
+fHZxHE5+8GMzPXMkCD56y5TNKR6ut7JGHMPtGl5lPCLqzG/HzYyFgxsDfDUu2B0A
+GKj0lGpnLfGqwhs2/s3jpY7+pcvVQxEpvVTId5byDxu1ujP4HjO/VTQ2P72rE8Ft
+C6J2Av0tAgMBAAGjUDBOMB0GA1UdDgQWBBTLT/RbyfBB/Pa07oBnaM+QSJPO9TAf
+BgNVHSMEGDAWgBTLT/RbyfBB/Pa07oBnaM+QSJPO9TAMBgNVHRMEBTADAQH/MA0G
+CSqGSIb3DQEBCwUAA4ICAQB3sCntCcQwhMgRPPyvOCMyTcQ/Iv+cpfxz2Ck14nlx
+AkEAH2CH0ov5GWTt07/ur3aa5x+SAKi0J3wTD1cdiw4U/6Uin6jWGKKxvoo4IaeK
+SbM8w/6eKx6UbmHx7PA/eRABY9tTlpdPCVgw7/o3WDr03QM+IAtatzvaCPPczake
+pbdLwmBZB/v8V+6jUajy6jOgdSH0PyffGnt7MWgDETmNC6p/Xigp5eh+C8Fb4NGT
+xgHES5PBC+sruWp4u22bJGDKTvYNdZHsnw/CaKQWNsQqwisxa3/8N5v+PCff/pxl
+r05pE3PdHn9JrCl4iWdVlgtiI9BoPtQyDfa/OEFaScE8KYR8LxaAgdgp3zYncWls
+BpwQ6Y/A2wIkhlD9eEp5Ib2hz7isXOs9UwjdriKqrBXqcIAE5M+YIk3+KAQKxAtd
+4YsK3CSJ010uphr12YKqlScj4vuKFjuOtd5RyyMIxUG3lrrhAu2AzCeKCLdVgA8+
+75FrYMApUdvcjp4uzbBoED4XRQlx9kdFHVbYgmE/+yddBYJM8u4YlgAL0hW2/D8p
+z9JWIfxVmjJnBnXaKGBuiUyZ864A3PJndP6EMMo7TzS2CDnfCYuJjvI0KvDjFNmc
+rQA04+qfMSEz3nmKhbbZu4eYLzlADhfH8tT4GMtXf71WLA5AUHGf2Y4+HIHTsmHG
+vQ==
+-----END CERTIFICATE-----
diff --git a/src/crypto/x509/testdata/test-dir.crt b/src/crypto/x509/testdata/test-dir.crt
new file mode 100644
index 0000000..b7fc9c5
--- /dev/null
+++ b/src/crypto/x509/testdata/test-dir.crt
@@ -0,0 +1,31 @@
+-----BEGIN CERTIFICATE-----
+MIIFazCCA1OgAwIBAgIJAL8a/lsnspOqMA0GCSqGSIb3DQEBCwUAMEwxCzAJBgNV
+BAYTAlVLMRMwEQYDVQQIDApUZXN0LVN0YXRlMRUwEwYDVQQKDAxHb2xhbmcgVGVz
+dHMxETAPBgNVBAMMCHRlc3QtZGlyMB4XDTE3MDIwMTIzNTAyN1oXDTI3MDEzMDIz
+NTAyN1owTDELMAkGA1UEBhMCVUsxEzARBgNVBAgMClRlc3QtU3RhdGUxFTATBgNV
+BAoMDEdvbGFuZyBUZXN0czERMA8GA1UEAwwIdGVzdC1kaXIwggIiMA0GCSqGSIb3
+DQEBAQUAA4ICDwAwggIKAoICAQDzBoi43Yn30KN13PKFHu8LA4UmgCRToTukLItM
+WK2Je45grs/axg9n3YJOXC6hmsyrkOnyBcx1xVNgSrOAll7fSjtChRIX72Xrloxu
+XewtWVIrijqz6oylbvEmbRT3O8uynu5rF82Pmdiy8oiSfdywjKuPnE0hjV1ZSCql
+MYcXqA+f0JFD8kMv4pbtxjGH8f2DkYQz+hHXLrJH4/MEYdVMQXoz/GDzLyOkrXBN
+hpMaBBqg1p0P+tRdfLXuliNzA9vbZylzpF1YZ0gvsr0S5Y6LVtv7QIRygRuLY4kF
+k+UYuFq8NrV8TykS7FVnO3tf4XcYZ7r2KV5FjYSrJtNNo85BV5c3xMD3fJ2XcOWk
++oD1ATdgAM3aKmSOxNtNItKKxBe1mkqDH41NbWx7xMad78gDznyeT0tjEOltN2bM
+uXU1R/jgR/vq5Ec0AhXJyL/ziIcmuV2fSl/ZxT4ARD+16tgPiIx+welTf0v27/JY
+adlfkkL5XsPRrbSguISrj7JeaO/gjG3KnDVHcZvYBpDfHqRhCgrosfe26TZcTXx2
+cRxOfvBjMz1zJAg+esuUzSkerreyRhzD7RpeZTwi6sxvx82MhYMbA3w1LtgdABio
+9JRqZy3xqsIbNv7N46WO/qXL1UMRKb1UyHeW8g8btboz+B4zv1U0Nj+9qxPBbQui
+dgL9LQIDAQABo1AwTjAdBgNVHQ4EFgQUy0/0W8nwQfz2tO6AZ2jPkEiTzvUwHwYD
+VR0jBBgwFoAUy0/0W8nwQfz2tO6AZ2jPkEiTzvUwDAYDVR0TBAUwAwEB/zANBgkq
+hkiG9w0BAQsFAAOCAgEAvEVnUYsIOt87rggmLPqEueynkuQ+562M8EDHSQl82zbe
+xDCxeg3DvPgKb+RvaUdt1362z/szK10SoeMgx6+EQLoV9LiVqXwNqeYfixrhrdw3
+ppAhYYhymdkbUQCEMHypmXP1vPhAz4o8Bs+eES1M+zO6ErBiD7SqkmBElT+GixJC
+6epC9ZQFs+dw3lPlbiZSsGE85sqc3VAs0/JgpL/pb1/Eg4s0FUhZD2C2uWdSyZGc
+g0/v3aXJCp4j/9VoNhI1WXz3M45nysZIL5OQgXymLqJElQa1pZ3Wa4i/nidvT4AT
+Xlxc/qijM8set/nOqp7hVd5J0uG6qdwLRILUddZ6OpXd7ZNi1EXg+Bpc7ehzGsDt
+3UFGzYXDjxYnK2frQfjLS8stOQIqSrGthW6x0fdkVx0y8BByvd5J6+JmZl4UZfzA
+m99VxXSt4B9x6BvnY7ktzcFDOjtuLc4B/7yg9fv1eQuStA4cHGGAttsCg1X/Kx8W
+PvkkeH0UWDZ9vhH9K36703z89da6MWF+bz92B0+4HoOmlVaXRkvblsNaynJnL0LC
+Ayry7QBxuh5cMnDdRwJB3AVJIiJ1GVpb7aGvBOnx+s2lwRv9HWtghb+cbwwktx1M
+JHyBf3GZNSWTpKY7cD8V+NnBv3UuioOVVo+XAU4LF/bYUjdRpxWADJizNtZrtFo=
+-----END CERTIFICATE-----
diff --git a/src/crypto/x509/verify.go b/src/crypto/x509/verify.go
new file mode 100644
index 0000000..0b01f8b
--- /dev/null
+++ b/src/crypto/x509/verify.go
@@ -0,0 +1,1179 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/x509/pkix"
+ "errors"
+ "fmt"
+ "net"
+ "net/url"
+ "reflect"
+ "runtime"
+ "strings"
+ "time"
+ "unicode/utf8"
+)
+
+type InvalidReason int
+
+const (
+ // NotAuthorizedToSign results when a certificate is signed by another
+ // which isn't marked as a CA certificate.
+ NotAuthorizedToSign InvalidReason = iota
+ // Expired results when a certificate has expired, based on the time
+ // given in the VerifyOptions.
+ Expired
+ // CANotAuthorizedForThisName results when an intermediate or root
+ // certificate has a name constraint which doesn't permit a DNS or
+ // other name (including IP address) in the leaf certificate.
+ CANotAuthorizedForThisName
+ // TooManyIntermediates results when a path length constraint is
+ // violated.
+ TooManyIntermediates
+ // IncompatibleUsage results when the certificate's key usage indicates
+ // that it may only be used for a different purpose.
+ IncompatibleUsage
+ // NameMismatch results when the subject name of a parent certificate
+ // does not match the issuer name in the child.
+ NameMismatch
+ // NameConstraintsWithoutSANs is a legacy error and is no longer returned.
+ NameConstraintsWithoutSANs
+ // UnconstrainedName results when a CA certificate contains permitted
+ // name constraints, but leaf certificate contains a name of an
+ // unsupported or unconstrained type.
+ UnconstrainedName
+ // TooManyConstraints results when the number of comparison operations
+ // needed to check a certificate exceeds the limit set by
+ // VerifyOptions.MaxConstraintComparisions. This limit exists to
+ // prevent pathological certificates can consuming excessive amounts of
+ // CPU time to verify.
+ TooManyConstraints
+ // CANotAuthorizedForExtKeyUsage results when an intermediate or root
+ // certificate does not permit a requested extended key usage.
+ CANotAuthorizedForExtKeyUsage
+)
+
+// CertificateInvalidError results when an odd error occurs. Users of this
+// library probably want to handle all these errors uniformly.
+type CertificateInvalidError struct {
+ Cert *Certificate
+ Reason InvalidReason
+ Detail string
+}
+
+func (e CertificateInvalidError) Error() string {
+ switch e.Reason {
+ case NotAuthorizedToSign:
+ return "x509: certificate is not authorized to sign other certificates"
+ case Expired:
+ return "x509: certificate has expired or is not yet valid: " + e.Detail
+ case CANotAuthorizedForThisName:
+ return "x509: a root or intermediate certificate is not authorized to sign for this name: " + e.Detail
+ case CANotAuthorizedForExtKeyUsage:
+ return "x509: a root or intermediate certificate is not authorized for an extended key usage: " + e.Detail
+ case TooManyIntermediates:
+ return "x509: too many intermediates for path length constraint"
+ case IncompatibleUsage:
+ return "x509: certificate specifies an incompatible key usage"
+ case NameMismatch:
+ return "x509: issuer name does not match subject from issuing certificate"
+ case NameConstraintsWithoutSANs:
+ return "x509: issuer has name constraints but leaf doesn't have a SAN extension"
+ case UnconstrainedName:
+ return "x509: issuer has name constraints but leaf contains unknown or unconstrained name: " + e.Detail
+ }
+ return "x509: unknown error"
+}
+
+// HostnameError results when the set of authorized names doesn't match the
+// requested name.
+type HostnameError struct {
+ Certificate *Certificate
+ Host string
+}
+
+func (h HostnameError) Error() string {
+ c := h.Certificate
+
+ if !c.hasSANExtension() && matchHostnames(c.Subject.CommonName, h.Host) {
+ return "x509: certificate relies on legacy Common Name field, use SANs instead"
+ }
+
+ var valid string
+ if ip := net.ParseIP(h.Host); ip != nil {
+ // Trying to validate an IP
+ if len(c.IPAddresses) == 0 {
+ return "x509: cannot validate certificate for " + h.Host + " because it doesn't contain any IP SANs"
+ }
+ for _, san := range c.IPAddresses {
+ if len(valid) > 0 {
+ valid += ", "
+ }
+ valid += san.String()
+ }
+ } else {
+ valid = strings.Join(c.DNSNames, ", ")
+ }
+
+ if len(valid) == 0 {
+ return "x509: certificate is not valid for any names, but wanted to match " + h.Host
+ }
+ return "x509: certificate is valid for " + valid + ", not " + h.Host
+}
+
+// UnknownAuthorityError results when the certificate issuer is unknown
+type UnknownAuthorityError struct {
+ Cert *Certificate
+ // hintErr contains an error that may be helpful in determining why an
+ // authority wasn't found.
+ hintErr error
+ // hintCert contains a possible authority certificate that was rejected
+ // because of the error in hintErr.
+ hintCert *Certificate
+}
+
+func (e UnknownAuthorityError) Error() string {
+ s := "x509: certificate signed by unknown authority"
+ if e.hintErr != nil {
+ certName := e.hintCert.Subject.CommonName
+ if len(certName) == 0 {
+ if len(e.hintCert.Subject.Organization) > 0 {
+ certName = e.hintCert.Subject.Organization[0]
+ } else {
+ certName = "serial:" + e.hintCert.SerialNumber.String()
+ }
+ }
+ s += fmt.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e.hintErr, certName)
+ }
+ return s
+}
+
+// SystemRootsError results when we fail to load the system root certificates.
+type SystemRootsError struct {
+ Err error
+}
+
+func (se SystemRootsError) Error() string {
+ msg := "x509: failed to load system roots and no roots provided"
+ if se.Err != nil {
+ return msg + "; " + se.Err.Error()
+ }
+ return msg
+}
+
+func (se SystemRootsError) Unwrap() error { return se.Err }
+
+// errNotParsed is returned when a certificate without ASN.1 contents is
+// verified. Platform-specific verification needs the ASN.1 contents.
+var errNotParsed = errors.New("x509: missing ASN.1 contents; use ParseCertificate")
+
+// VerifyOptions contains parameters for Certificate.Verify.
+type VerifyOptions struct {
+ // DNSName, if set, is checked against the leaf certificate with
+ // Certificate.VerifyHostname or the platform verifier.
+ DNSName string
+
+ // Intermediates is an optional pool of certificates that are not trust
+ // anchors, but can be used to form a chain from the leaf certificate to a
+ // root certificate.
+ Intermediates *CertPool
+ // Roots is the set of trusted root certificates the leaf certificate needs
+ // to chain up to. If nil, the system roots or the platform verifier are used.
+ Roots *CertPool
+
+ // CurrentTime is used to check the validity of all certificates in the
+ // chain. If zero, the current time is used.
+ CurrentTime time.Time
+
+ // KeyUsages specifies which Extended Key Usage values are acceptable. A
+ // chain is accepted if it allows any of the listed values. An empty list
+ // means ExtKeyUsageServerAuth. To accept any key usage, include ExtKeyUsageAny.
+ KeyUsages []ExtKeyUsage
+
+ // MaxConstraintComparisions is the maximum number of comparisons to
+ // perform when checking a given certificate's name constraints. If
+ // zero, a sensible default is used. This limit prevents pathological
+ // certificates from consuming excessive amounts of CPU time when
+ // validating. It does not apply to the platform verifier.
+ MaxConstraintComparisions int
+}
+
+const (
+ leafCertificate = iota
+ intermediateCertificate
+ rootCertificate
+)
+
+// rfc2821Mailbox represents a “mailbox” (which is an email address to most
+// people) by breaking it into the “local” (i.e. before the '@') and “domain”
+// parts.
+type rfc2821Mailbox struct {
+ local, domain string
+}
+
+// parseRFC2821Mailbox parses an email address into local and domain parts,
+// based on the ABNF for a “Mailbox” from RFC 2821. According to RFC 5280,
+// Section 4.2.1.6 that's correct for an rfc822Name from a certificate: “The
+// format of an rfc822Name is a "Mailbox" as defined in RFC 2821, Section 4.1.2”.
+func parseRFC2821Mailbox(in string) (mailbox rfc2821Mailbox, ok bool) {
+ if len(in) == 0 {
+ return mailbox, false
+ }
+
+ localPartBytes := make([]byte, 0, len(in)/2)
+
+ if in[0] == '"' {
+ // Quoted-string = DQUOTE *qcontent DQUOTE
+ // non-whitespace-control = %d1-8 / %d11 / %d12 / %d14-31 / %d127
+ // qcontent = qtext / quoted-pair
+ // qtext = non-whitespace-control /
+ // %d33 / %d35-91 / %d93-126
+ // quoted-pair = ("\" text) / obs-qp
+ // text = %d1-9 / %d11 / %d12 / %d14-127 / obs-text
+ //
+ // (Names beginning with “obs-” are the obsolete syntax from RFC 2822,
+ // Section 4. Since it has been 16 years, we no longer accept that.)
+ in = in[1:]
+ QuotedString:
+ for {
+ if len(in) == 0 {
+ return mailbox, false
+ }
+ c := in[0]
+ in = in[1:]
+
+ switch {
+ case c == '"':
+ break QuotedString
+
+ case c == '\\':
+ // quoted-pair
+ if len(in) == 0 {
+ return mailbox, false
+ }
+ if in[0] == 11 ||
+ in[0] == 12 ||
+ (1 <= in[0] && in[0] <= 9) ||
+ (14 <= in[0] && in[0] <= 127) {
+ localPartBytes = append(localPartBytes, in[0])
+ in = in[1:]
+ } else {
+ return mailbox, false
+ }
+
+ case c == 11 ||
+ c == 12 ||
+ // Space (char 32) is not allowed based on the
+ // BNF, but RFC 3696 gives an example that
+ // assumes that it is. Several “verified”
+ // errata continue to argue about this point.
+ // We choose to accept it.
+ c == 32 ||
+ c == 33 ||
+ c == 127 ||
+ (1 <= c && c <= 8) ||
+ (14 <= c && c <= 31) ||
+ (35 <= c && c <= 91) ||
+ (93 <= c && c <= 126):
+ // qtext
+ localPartBytes = append(localPartBytes, c)
+
+ default:
+ return mailbox, false
+ }
+ }
+ } else {
+ // Atom ("." Atom)*
+ NextChar:
+ for len(in) > 0 {
+ // atext from RFC 2822, Section 3.2.4
+ c := in[0]
+
+ switch {
+ case c == '\\':
+ // Examples given in RFC 3696 suggest that
+ // escaped characters can appear outside of a
+ // quoted string. Several “verified” errata
+ // continue to argue the point. We choose to
+ // accept it.
+ in = in[1:]
+ if len(in) == 0 {
+ return mailbox, false
+ }
+ fallthrough
+
+ case ('0' <= c && c <= '9') ||
+ ('a' <= c && c <= 'z') ||
+ ('A' <= c && c <= 'Z') ||
+ c == '!' || c == '#' || c == '$' || c == '%' ||
+ c == '&' || c == '\'' || c == '*' || c == '+' ||
+ c == '-' || c == '/' || c == '=' || c == '?' ||
+ c == '^' || c == '_' || c == '`' || c == '{' ||
+ c == '|' || c == '}' || c == '~' || c == '.':
+ localPartBytes = append(localPartBytes, in[0])
+ in = in[1:]
+
+ default:
+ break NextChar
+ }
+ }
+
+ if len(localPartBytes) == 0 {
+ return mailbox, false
+ }
+
+ // From RFC 3696, Section 3:
+ // “period (".") may also appear, but may not be used to start
+ // or end the local part, nor may two or more consecutive
+ // periods appear.”
+ twoDots := []byte{'.', '.'}
+ if localPartBytes[0] == '.' ||
+ localPartBytes[len(localPartBytes)-1] == '.' ||
+ bytes.Contains(localPartBytes, twoDots) {
+ return mailbox, false
+ }
+ }
+
+ if len(in) == 0 || in[0] != '@' {
+ return mailbox, false
+ }
+ in = in[1:]
+
+ // The RFC species a format for domains, but that's known to be
+ // violated in practice so we accept that anything after an '@' is the
+ // domain part.
+ if _, ok := domainToReverseLabels(in); !ok {
+ return mailbox, false
+ }
+
+ mailbox.local = string(localPartBytes)
+ mailbox.domain = in
+ return mailbox, true
+}
+
+// domainToReverseLabels converts a textual domain name like foo.example.com to
+// the list of labels in reverse order, e.g. ["com", "example", "foo"].
+func domainToReverseLabels(domain string) (reverseLabels []string, ok bool) {
+ for len(domain) > 0 {
+ if i := strings.LastIndexByte(domain, '.'); i == -1 {
+ reverseLabels = append(reverseLabels, domain)
+ domain = ""
+ } else {
+ reverseLabels = append(reverseLabels, domain[i+1:])
+ domain = domain[:i]
+ }
+ }
+
+ if len(reverseLabels) > 0 && len(reverseLabels[0]) == 0 {
+ // An empty label at the end indicates an absolute value.
+ return nil, false
+ }
+
+ for _, label := range reverseLabels {
+ if len(label) == 0 {
+ // Empty labels are otherwise invalid.
+ return nil, false
+ }
+
+ for _, c := range label {
+ if c < 33 || c > 126 {
+ // Invalid character.
+ return nil, false
+ }
+ }
+ }
+
+ return reverseLabels, true
+}
+
+func matchEmailConstraint(mailbox rfc2821Mailbox, constraint string) (bool, error) {
+ // If the constraint contains an @, then it specifies an exact mailbox
+ // name.
+ if strings.Contains(constraint, "@") {
+ constraintMailbox, ok := parseRFC2821Mailbox(constraint)
+ if !ok {
+ return false, fmt.Errorf("x509: internal error: cannot parse constraint %q", constraint)
+ }
+ return mailbox.local == constraintMailbox.local && strings.EqualFold(mailbox.domain, constraintMailbox.domain), nil
+ }
+
+ // Otherwise the constraint is like a DNS constraint of the domain part
+ // of the mailbox.
+ return matchDomainConstraint(mailbox.domain, constraint)
+}
+
+func matchURIConstraint(uri *url.URL, constraint string) (bool, error) {
+ // From RFC 5280, Section 4.2.1.10:
+ // “a uniformResourceIdentifier that does not include an authority
+ // component with a host name specified as a fully qualified domain
+ // name (e.g., if the URI either does not include an authority
+ // component or includes an authority component in which the host name
+ // is specified as an IP address), then the application MUST reject the
+ // certificate.”
+
+ host := uri.Host
+ if len(host) == 0 {
+ return false, fmt.Errorf("URI with empty host (%q) cannot be matched against constraints", uri.String())
+ }
+
+ if strings.Contains(host, ":") && !strings.HasSuffix(host, "]") {
+ var err error
+ host, _, err = net.SplitHostPort(uri.Host)
+ if err != nil {
+ return false, err
+ }
+ }
+
+ if strings.HasPrefix(host, "[") && strings.HasSuffix(host, "]") ||
+ net.ParseIP(host) != nil {
+ return false, fmt.Errorf("URI with IP (%q) cannot be matched against constraints", uri.String())
+ }
+
+ return matchDomainConstraint(host, constraint)
+}
+
+func matchIPConstraint(ip net.IP, constraint *net.IPNet) (bool, error) {
+ if len(ip) != len(constraint.IP) {
+ return false, nil
+ }
+
+ for i := range ip {
+ if mask := constraint.Mask[i]; ip[i]&mask != constraint.IP[i]&mask {
+ return false, nil
+ }
+ }
+
+ return true, nil
+}
+
+func matchDomainConstraint(domain, constraint string) (bool, error) {
+ // The meaning of zero length constraints is not specified, but this
+ // code follows NSS and accepts them as matching everything.
+ if len(constraint) == 0 {
+ return true, nil
+ }
+
+ domainLabels, ok := domainToReverseLabels(domain)
+ if !ok {
+ return false, fmt.Errorf("x509: internal error: cannot parse domain %q", domain)
+ }
+
+ // RFC 5280 says that a leading period in a domain name means that at
+ // least one label must be prepended, but only for URI and email
+ // constraints, not DNS constraints. The code also supports that
+ // behaviour for DNS constraints.
+
+ mustHaveSubdomains := false
+ if constraint[0] == '.' {
+ mustHaveSubdomains = true
+ constraint = constraint[1:]
+ }
+
+ constraintLabels, ok := domainToReverseLabels(constraint)
+ if !ok {
+ return false, fmt.Errorf("x509: internal error: cannot parse domain %q", constraint)
+ }
+
+ if len(domainLabels) < len(constraintLabels) ||
+ (mustHaveSubdomains && len(domainLabels) == len(constraintLabels)) {
+ return false, nil
+ }
+
+ for i, constraintLabel := range constraintLabels {
+ if !strings.EqualFold(constraintLabel, domainLabels[i]) {
+ return false, nil
+ }
+ }
+
+ return true, nil
+}
+
+// checkNameConstraints checks that c permits a child certificate to claim the
+// given name, of type nameType. The argument parsedName contains the parsed
+// form of name, suitable for passing to the match function. The total number
+// of comparisons is tracked in the given count and should not exceed the given
+// limit.
+func (c *Certificate) checkNameConstraints(count *int,
+ maxConstraintComparisons int,
+ nameType string,
+ name string,
+ parsedName any,
+ match func(parsedName, constraint any) (match bool, err error),
+ permitted, excluded any) error {
+
+ excludedValue := reflect.ValueOf(excluded)
+
+ *count += excludedValue.Len()
+ if *count > maxConstraintComparisons {
+ return CertificateInvalidError{c, TooManyConstraints, ""}
+ }
+
+ for i := 0; i < excludedValue.Len(); i++ {
+ constraint := excludedValue.Index(i).Interface()
+ match, err := match(parsedName, constraint)
+ if err != nil {
+ return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()}
+ }
+
+ if match {
+ return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is excluded by constraint %q", nameType, name, constraint)}
+ }
+ }
+
+ permittedValue := reflect.ValueOf(permitted)
+
+ *count += permittedValue.Len()
+ if *count > maxConstraintComparisons {
+ return CertificateInvalidError{c, TooManyConstraints, ""}
+ }
+
+ ok := true
+ for i := 0; i < permittedValue.Len(); i++ {
+ constraint := permittedValue.Index(i).Interface()
+
+ var err error
+ if ok, err = match(parsedName, constraint); err != nil {
+ return CertificateInvalidError{c, CANotAuthorizedForThisName, err.Error()}
+ }
+
+ if ok {
+ break
+ }
+ }
+
+ if !ok {
+ return CertificateInvalidError{c, CANotAuthorizedForThisName, fmt.Sprintf("%s %q is not permitted by any constraint", nameType, name)}
+ }
+
+ return nil
+}
+
+// isValid performs validity checks on c given that it is a candidate to append
+// to the chain in currentChain.
+func (c *Certificate) isValid(certType int, currentChain []*Certificate, opts *VerifyOptions) error {
+ if len(c.UnhandledCriticalExtensions) > 0 {
+ return UnhandledCriticalExtension{}
+ }
+
+ if len(currentChain) > 0 {
+ child := currentChain[len(currentChain)-1]
+ if !bytes.Equal(child.RawIssuer, c.RawSubject) {
+ return CertificateInvalidError{c, NameMismatch, ""}
+ }
+ }
+
+ now := opts.CurrentTime
+ if now.IsZero() {
+ now = time.Now()
+ }
+ if now.Before(c.NotBefore) {
+ return CertificateInvalidError{
+ Cert: c,
+ Reason: Expired,
+ Detail: fmt.Sprintf("current time %s is before %s", now.Format(time.RFC3339), c.NotBefore.Format(time.RFC3339)),
+ }
+ } else if now.After(c.NotAfter) {
+ return CertificateInvalidError{
+ Cert: c,
+ Reason: Expired,
+ Detail: fmt.Sprintf("current time %s is after %s", now.Format(time.RFC3339), c.NotAfter.Format(time.RFC3339)),
+ }
+ }
+
+ maxConstraintComparisons := opts.MaxConstraintComparisions
+ if maxConstraintComparisons == 0 {
+ maxConstraintComparisons = 250000
+ }
+ comparisonCount := 0
+
+ var leaf *Certificate
+ if certType == intermediateCertificate || certType == rootCertificate {
+ if len(currentChain) == 0 {
+ return errors.New("x509: internal error: empty chain when appending CA cert")
+ }
+ leaf = currentChain[0]
+ }
+
+ if (certType == intermediateCertificate || certType == rootCertificate) &&
+ c.hasNameConstraints() {
+ toCheck := []*Certificate{}
+ if leaf.hasSANExtension() {
+ toCheck = append(toCheck, leaf)
+ }
+ if c.hasSANExtension() {
+ toCheck = append(toCheck, c)
+ }
+ for _, sanCert := range toCheck {
+ err := forEachSAN(sanCert.getSANExtension(), func(tag int, data []byte) error {
+ switch tag {
+ case nameTypeEmail:
+ name := string(data)
+ mailbox, ok := parseRFC2821Mailbox(name)
+ if !ok {
+ return fmt.Errorf("x509: cannot parse rfc822Name %q", mailbox)
+ }
+
+ if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "email address", name, mailbox,
+ func(parsedName, constraint any) (bool, error) {
+ return matchEmailConstraint(parsedName.(rfc2821Mailbox), constraint.(string))
+ }, c.PermittedEmailAddresses, c.ExcludedEmailAddresses); err != nil {
+ return err
+ }
+
+ case nameTypeDNS:
+ name := string(data)
+ if _, ok := domainToReverseLabels(name); !ok {
+ return fmt.Errorf("x509: cannot parse dnsName %q", name)
+ }
+
+ if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "DNS name", name, name,
+ func(parsedName, constraint any) (bool, error) {
+ return matchDomainConstraint(parsedName.(string), constraint.(string))
+ }, c.PermittedDNSDomains, c.ExcludedDNSDomains); err != nil {
+ return err
+ }
+
+ case nameTypeURI:
+ name := string(data)
+ uri, err := url.Parse(name)
+ if err != nil {
+ return fmt.Errorf("x509: internal error: URI SAN %q failed to parse", name)
+ }
+
+ if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "URI", name, uri,
+ func(parsedName, constraint any) (bool, error) {
+ return matchURIConstraint(parsedName.(*url.URL), constraint.(string))
+ }, c.PermittedURIDomains, c.ExcludedURIDomains); err != nil {
+ return err
+ }
+
+ case nameTypeIP:
+ ip := net.IP(data)
+ if l := len(ip); l != net.IPv4len && l != net.IPv6len {
+ return fmt.Errorf("x509: internal error: IP SAN %x failed to parse", data)
+ }
+
+ if err := c.checkNameConstraints(&comparisonCount, maxConstraintComparisons, "IP address", ip.String(), ip,
+ func(parsedName, constraint any) (bool, error) {
+ return matchIPConstraint(parsedName.(net.IP), constraint.(*net.IPNet))
+ }, c.PermittedIPRanges, c.ExcludedIPRanges); err != nil {
+ return err
+ }
+
+ default:
+ // Unknown SAN types are ignored.
+ }
+
+ return nil
+ })
+
+ if err != nil {
+ return err
+ }
+ }
+ }
+
+ // KeyUsage status flags are ignored. From Engineering Security, Peter
+ // Gutmann: A European government CA marked its signing certificates as
+ // being valid for encryption only, but no-one noticed. Another
+ // European CA marked its signature keys as not being valid for
+ // signatures. A different CA marked its own trusted root certificate
+ // as being invalid for certificate signing. Another national CA
+ // distributed a certificate to be used to encrypt data for the
+ // country’s tax authority that was marked as only being usable for
+ // digital signatures but not for encryption. Yet another CA reversed
+ // the order of the bit flags in the keyUsage due to confusion over
+ // encoding endianness, essentially setting a random keyUsage in
+ // certificates that it issued. Another CA created a self-invalidating
+ // certificate by adding a certificate policy statement stipulating
+ // that the certificate had to be used strictly as specified in the
+ // keyUsage, and a keyUsage containing a flag indicating that the RSA
+ // encryption key could only be used for Diffie-Hellman key agreement.
+
+ if certType == intermediateCertificate && (!c.BasicConstraintsValid || !c.IsCA) {
+ return CertificateInvalidError{c, NotAuthorizedToSign, ""}
+ }
+
+ if c.BasicConstraintsValid && c.MaxPathLen >= 0 {
+ numIntermediates := len(currentChain) - 1
+ if numIntermediates > c.MaxPathLen {
+ return CertificateInvalidError{c, TooManyIntermediates, ""}
+ }
+ }
+
+ if !boringAllowCert(c) {
+ // IncompatibleUsage is not quite right here,
+ // but it's also the "no chains found" error
+ // and is close enough.
+ return CertificateInvalidError{c, IncompatibleUsage, ""}
+ }
+
+ return nil
+}
+
+// Verify attempts to verify c by building one or more chains from c to a
+// certificate in opts.Roots, using certificates in opts.Intermediates if
+// needed. If successful, it returns one or more chains where the first
+// element of the chain is c and the last element is from opts.Roots.
+//
+// If opts.Roots is nil, the platform verifier might be used, and
+// verification details might differ from what is described below. If system
+// roots are unavailable the returned error will be of type SystemRootsError.
+//
+// Name constraints in the intermediates will be applied to all names claimed
+// in the chain, not just opts.DNSName. Thus it is invalid for a leaf to claim
+// example.com if an intermediate doesn't permit it, even if example.com is not
+// the name being validated. Note that DirectoryName constraints are not
+// supported.
+//
+// Name constraint validation follows the rules from RFC 5280, with the
+// addition that DNS name constraints may use the leading period format
+// defined for emails and URIs. When a constraint has a leading period
+// it indicates that at least one additional label must be prepended to
+// the constrained name to be considered valid.
+//
+// Extended Key Usage values are enforced nested down a chain, so an intermediate
+// or root that enumerates EKUs prevents a leaf from asserting an EKU not in that
+// list. (While this is not specified, it is common practice in order to limit
+// the types of certificates a CA can issue.)
+//
+// Certificates that use SHA1WithRSA and ECDSAWithSHA1 signatures are not supported,
+// and will not be used to build chains.
+//
+// Certificates other than c in the returned chains should not be modified.
+//
+// WARNING: this function doesn't do any revocation checking.
+func (c *Certificate) Verify(opts VerifyOptions) (chains [][]*Certificate, err error) {
+ // Platform-specific verification needs the ASN.1 contents so
+ // this makes the behavior consistent across platforms.
+ if len(c.Raw) == 0 {
+ return nil, errNotParsed
+ }
+ for i := 0; i < opts.Intermediates.len(); i++ {
+ c, err := opts.Intermediates.cert(i)
+ if err != nil {
+ return nil, fmt.Errorf("crypto/x509: error fetching intermediate: %w", err)
+ }
+ if len(c.Raw) == 0 {
+ return nil, errNotParsed
+ }
+ }
+
+ // Use platform verifiers, where available, if Roots is from SystemCertPool.
+ if runtime.GOOS == "windows" || runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
+ // Don't use the system verifier if the system pool was replaced with a non-system pool,
+ // i.e. if SetFallbackRoots was called with x509usefallbackroots=1.
+ systemPool := systemRootsPool()
+ if opts.Roots == nil && (systemPool == nil || systemPool.systemPool) {
+ return c.systemVerify(&opts)
+ }
+ if opts.Roots != nil && opts.Roots.systemPool {
+ platformChains, err := c.systemVerify(&opts)
+ // If the platform verifier succeeded, or there are no additional
+ // roots, return the platform verifier result. Otherwise, continue
+ // with the Go verifier.
+ if err == nil || opts.Roots.len() == 0 {
+ return platformChains, err
+ }
+ }
+ }
+
+ if opts.Roots == nil {
+ opts.Roots = systemRootsPool()
+ if opts.Roots == nil {
+ return nil, SystemRootsError{systemRootsErr}
+ }
+ }
+
+ err = c.isValid(leafCertificate, nil, &opts)
+ if err != nil {
+ return
+ }
+
+ if len(opts.DNSName) > 0 {
+ err = c.VerifyHostname(opts.DNSName)
+ if err != nil {
+ return
+ }
+ }
+
+ var candidateChains [][]*Certificate
+ if opts.Roots.contains(c) {
+ candidateChains = [][]*Certificate{{c}}
+ } else {
+ candidateChains, err = c.buildChains([]*Certificate{c}, nil, &opts)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ if len(opts.KeyUsages) == 0 {
+ opts.KeyUsages = []ExtKeyUsage{ExtKeyUsageServerAuth}
+ }
+
+ for _, eku := range opts.KeyUsages {
+ if eku == ExtKeyUsageAny {
+ // If any key usage is acceptable, no need to check the chain for
+ // key usages.
+ return candidateChains, nil
+ }
+ }
+
+ chains = make([][]*Certificate, 0, len(candidateChains))
+ for _, candidate := range candidateChains {
+ if checkChainForKeyUsage(candidate, opts.KeyUsages) {
+ chains = append(chains, candidate)
+ }
+ }
+
+ if len(chains) == 0 {
+ return nil, CertificateInvalidError{c, IncompatibleUsage, ""}
+ }
+
+ return chains, nil
+}
+
+func appendToFreshChain(chain []*Certificate, cert *Certificate) []*Certificate {
+ n := make([]*Certificate, len(chain)+1)
+ copy(n, chain)
+ n[len(chain)] = cert
+ return n
+}
+
+// alreadyInChain checks whether a candidate certificate is present in a chain.
+// Rather than doing a direct byte for byte equivalency check, we check if the
+// subject, public key, and SAN, if present, are equal. This prevents loops that
+// are created by mutual cross-signatures, or other cross-signature bridge
+// oddities.
+func alreadyInChain(candidate *Certificate, chain []*Certificate) bool {
+ type pubKeyEqual interface {
+ Equal(crypto.PublicKey) bool
+ }
+
+ var candidateSAN *pkix.Extension
+ for _, ext := range candidate.Extensions {
+ if ext.Id.Equal(oidExtensionSubjectAltName) {
+ candidateSAN = &ext
+ break
+ }
+ }
+
+ for _, cert := range chain {
+ if !bytes.Equal(candidate.RawSubject, cert.RawSubject) {
+ continue
+ }
+ if !candidate.PublicKey.(pubKeyEqual).Equal(cert.PublicKey) {
+ continue
+ }
+ var certSAN *pkix.Extension
+ for _, ext := range cert.Extensions {
+ if ext.Id.Equal(oidExtensionSubjectAltName) {
+ certSAN = &ext
+ break
+ }
+ }
+ if candidateSAN == nil && certSAN == nil {
+ return true
+ } else if candidateSAN == nil || certSAN == nil {
+ return false
+ }
+ if bytes.Equal(candidateSAN.Value, certSAN.Value) {
+ return true
+ }
+ }
+ return false
+}
+
+// maxChainSignatureChecks is the maximum number of CheckSignatureFrom calls
+// that an invocation of buildChains will (transitively) make. Most chains are
+// less than 15 certificates long, so this leaves space for multiple chains and
+// for failed checks due to different intermediates having the same Subject.
+const maxChainSignatureChecks = 100
+
+func (c *Certificate) buildChains(currentChain []*Certificate, sigChecks *int, opts *VerifyOptions) (chains [][]*Certificate, err error) {
+ var (
+ hintErr error
+ hintCert *Certificate
+ )
+
+ considerCandidate := func(certType int, candidate *Certificate) {
+ if alreadyInChain(candidate, currentChain) {
+ return
+ }
+
+ if sigChecks == nil {
+ sigChecks = new(int)
+ }
+ *sigChecks++
+ if *sigChecks > maxChainSignatureChecks {
+ err = errors.New("x509: signature check attempts limit reached while verifying certificate chain")
+ return
+ }
+
+ if err := c.CheckSignatureFrom(candidate); err != nil {
+ if hintErr == nil {
+ hintErr = err
+ hintCert = candidate
+ }
+ return
+ }
+
+ err = candidate.isValid(certType, currentChain, opts)
+ if err != nil {
+ if hintErr == nil {
+ hintErr = err
+ hintCert = candidate
+ }
+ return
+ }
+
+ switch certType {
+ case rootCertificate:
+ chains = append(chains, appendToFreshChain(currentChain, candidate))
+ case intermediateCertificate:
+ var childChains [][]*Certificate
+ childChains, err = candidate.buildChains(appendToFreshChain(currentChain, candidate), sigChecks, opts)
+ chains = append(chains, childChains...)
+ }
+ }
+
+ for _, root := range opts.Roots.findPotentialParents(c) {
+ considerCandidate(rootCertificate, root)
+ }
+ for _, intermediate := range opts.Intermediates.findPotentialParents(c) {
+ considerCandidate(intermediateCertificate, intermediate)
+ }
+
+ if len(chains) > 0 {
+ err = nil
+ }
+ if len(chains) == 0 && err == nil {
+ err = UnknownAuthorityError{c, hintErr, hintCert}
+ }
+
+ return
+}
+
+func validHostnamePattern(host string) bool { return validHostname(host, true) }
+func validHostnameInput(host string) bool { return validHostname(host, false) }
+
+// validHostname reports whether host is a valid hostname that can be matched or
+// matched against according to RFC 6125 2.2, with some leniency to accommodate
+// legacy values.
+func validHostname(host string, isPattern bool) bool {
+ if !isPattern {
+ host = strings.TrimSuffix(host, ".")
+ }
+ if len(host) == 0 {
+ return false
+ }
+
+ for i, part := range strings.Split(host, ".") {
+ if part == "" {
+ // Empty label.
+ return false
+ }
+ if isPattern && i == 0 && part == "*" {
+ // Only allow full left-most wildcards, as those are the only ones
+ // we match, and matching literal '*' characters is probably never
+ // the expected behavior.
+ continue
+ }
+ for j, c := range part {
+ if 'a' <= c && c <= 'z' {
+ continue
+ }
+ if '0' <= c && c <= '9' {
+ continue
+ }
+ if 'A' <= c && c <= 'Z' {
+ continue
+ }
+ if c == '-' && j != 0 {
+ continue
+ }
+ if c == '_' {
+ // Not a valid character in hostnames, but commonly
+ // found in deployments outside the WebPKI.
+ continue
+ }
+ return false
+ }
+ }
+
+ return true
+}
+
+func matchExactly(hostA, hostB string) bool {
+ if hostA == "" || hostA == "." || hostB == "" || hostB == "." {
+ return false
+ }
+ return toLowerCaseASCII(hostA) == toLowerCaseASCII(hostB)
+}
+
+func matchHostnames(pattern, host string) bool {
+ pattern = toLowerCaseASCII(pattern)
+ host = toLowerCaseASCII(strings.TrimSuffix(host, "."))
+
+ if len(pattern) == 0 || len(host) == 0 {
+ return false
+ }
+
+ patternParts := strings.Split(pattern, ".")
+ hostParts := strings.Split(host, ".")
+
+ if len(patternParts) != len(hostParts) {
+ return false
+ }
+
+ for i, patternPart := range patternParts {
+ if i == 0 && patternPart == "*" {
+ continue
+ }
+ if patternPart != hostParts[i] {
+ return false
+ }
+ }
+
+ return true
+}
+
+// toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use
+// an explicitly ASCII function to avoid any sharp corners resulting from
+// performing Unicode operations on DNS labels.
+func toLowerCaseASCII(in string) string {
+ // If the string is already lower-case then there's nothing to do.
+ isAlreadyLowerCase := true
+ for _, c := range in {
+ if c == utf8.RuneError {
+ // If we get a UTF-8 error then there might be
+ // upper-case ASCII bytes in the invalid sequence.
+ isAlreadyLowerCase = false
+ break
+ }
+ if 'A' <= c && c <= 'Z' {
+ isAlreadyLowerCase = false
+ break
+ }
+ }
+
+ if isAlreadyLowerCase {
+ return in
+ }
+
+ out := []byte(in)
+ for i, c := range out {
+ if 'A' <= c && c <= 'Z' {
+ out[i] += 'a' - 'A'
+ }
+ }
+ return string(out)
+}
+
+// VerifyHostname returns nil if c is a valid certificate for the named host.
+// Otherwise it returns an error describing the mismatch.
+//
+// IP addresses can be optionally enclosed in square brackets and are checked
+// against the IPAddresses field. Other names are checked case insensitively
+// against the DNSNames field. If the names are valid hostnames, the certificate
+// fields can have a wildcard as the left-most label.
+//
+// Note that the legacy Common Name field is ignored.
+func (c *Certificate) VerifyHostname(h string) error {
+ // IP addresses may be written in [ ].
+ candidateIP := h
+ if len(h) >= 3 && h[0] == '[' && h[len(h)-1] == ']' {
+ candidateIP = h[1 : len(h)-1]
+ }
+ if ip := net.ParseIP(candidateIP); ip != nil {
+ // We only match IP addresses against IP SANs.
+ // See RFC 6125, Appendix B.2.
+ for _, candidate := range c.IPAddresses {
+ if ip.Equal(candidate) {
+ return nil
+ }
+ }
+ return HostnameError{c, candidateIP}
+ }
+
+ candidateName := toLowerCaseASCII(h) // Save allocations inside the loop.
+ validCandidateName := validHostnameInput(candidateName)
+
+ for _, match := range c.DNSNames {
+ // Ideally, we'd only match valid hostnames according to RFC 6125 like
+ // browsers (more or less) do, but in practice Go is used in a wider
+ // array of contexts and can't even assume DNS resolution. Instead,
+ // always allow perfect matches, and only apply wildcard and trailing
+ // dot processing to valid hostnames.
+ if validCandidateName && validHostnamePattern(match) {
+ if matchHostnames(match, candidateName) {
+ return nil
+ }
+ } else {
+ if matchExactly(match, candidateName) {
+ return nil
+ }
+ }
+ }
+
+ return HostnameError{c, h}
+}
+
+func checkChainForKeyUsage(chain []*Certificate, keyUsages []ExtKeyUsage) bool {
+ usages := make([]ExtKeyUsage, len(keyUsages))
+ copy(usages, keyUsages)
+
+ if len(chain) == 0 {
+ return false
+ }
+
+ usagesRemaining := len(usages)
+
+ // We walk down the list and cross out any usages that aren't supported
+ // by each certificate. If we cross out all the usages, then the chain
+ // is unacceptable.
+
+NextCert:
+ for i := len(chain) - 1; i >= 0; i-- {
+ cert := chain[i]
+ if len(cert.ExtKeyUsage) == 0 && len(cert.UnknownExtKeyUsage) == 0 {
+ // The certificate doesn't have any extended key usage specified.
+ continue
+ }
+
+ for _, usage := range cert.ExtKeyUsage {
+ if usage == ExtKeyUsageAny {
+ // The certificate is explicitly good for any usage.
+ continue NextCert
+ }
+ }
+
+ const invalidUsage ExtKeyUsage = -1
+
+ NextRequestedUsage:
+ for i, requestedUsage := range usages {
+ if requestedUsage == invalidUsage {
+ continue
+ }
+
+ for _, usage := range cert.ExtKeyUsage {
+ if requestedUsage == usage {
+ continue NextRequestedUsage
+ }
+ }
+
+ usages[i] = invalidUsage
+ usagesRemaining--
+ if usagesRemaining == 0 {
+ return false
+ }
+ }
+ }
+
+ return true
+}
diff --git a/src/crypto/x509/verify_test.go b/src/crypto/x509/verify_test.go
new file mode 100644
index 0000000..14856f8
--- /dev/null
+++ b/src/crypto/x509/verify_test.go
@@ -0,0 +1,2636 @@
+// Copyright 2011 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "crypto"
+ "crypto/ecdsa"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "encoding/pem"
+ "errors"
+ "fmt"
+ "internal/testenv"
+ "math/big"
+ "os/exec"
+ "reflect"
+ "runtime"
+ "sort"
+ "strconv"
+ "strings"
+ "testing"
+ "time"
+)
+
+type verifyTest struct {
+ name string
+ leaf string
+ intermediates []string
+ roots []string
+ currentTime int64
+ dnsName string
+ systemSkip bool
+ systemLax bool
+ keyUsages []ExtKeyUsage
+
+ errorCallback func(*testing.T, error)
+ expectedChains [][]string
+}
+
+var verifyTests = []verifyTest{
+ {
+ name: "Valid",
+ leaf: googleLeaf,
+ intermediates: []string{gtsIntermediate},
+ roots: []string{gtsRoot},
+ currentTime: 1677615892,
+ dnsName: "www.google.com",
+
+ expectedChains: [][]string{
+ {"www.google.com", "GTS CA 1C3", "GTS Root R1"},
+ },
+ },
+ {
+ name: "MixedCase",
+ leaf: googleLeaf,
+ intermediates: []string{gtsIntermediate},
+ roots: []string{gtsRoot},
+ currentTime: 1677615892,
+ dnsName: "WwW.GooGLE.coM",
+
+ expectedChains: [][]string{
+ {"www.google.com", "GTS CA 1C3", "GTS Root R1"},
+ },
+ },
+ {
+ name: "HostnameMismatch",
+ leaf: googleLeaf,
+ intermediates: []string{gtsIntermediate},
+ roots: []string{gtsRoot},
+ currentTime: 1677615892,
+ dnsName: "www.example.com",
+
+ errorCallback: expectHostnameError("certificate is valid for"),
+ },
+ {
+ name: "IPMissing",
+ leaf: googleLeaf,
+ intermediates: []string{gtsIntermediate},
+ roots: []string{gtsRoot},
+ currentTime: 1677615892,
+ dnsName: "1.2.3.4",
+
+ errorCallback: expectHostnameError("doesn't contain any IP SANs"),
+ },
+ {
+ name: "Expired",
+ leaf: googleLeaf,
+ intermediates: []string{gtsIntermediate},
+ roots: []string{gtsRoot},
+ currentTime: 1,
+ dnsName: "www.example.com",
+
+ errorCallback: expectExpired,
+ },
+ {
+ name: "MissingIntermediate",
+ leaf: googleLeaf,
+ roots: []string{gtsRoot},
+ currentTime: 1677615892,
+ dnsName: "www.google.com",
+
+ // Skip when using systemVerify, since Windows
+ // *will* find the missing intermediate cert.
+ systemSkip: true,
+ errorCallback: expectAuthorityUnknown,
+ },
+ {
+ name: "RootInIntermediates",
+ leaf: googleLeaf,
+ intermediates: []string{gtsRoot, gtsIntermediate},
+ roots: []string{gtsRoot},
+ currentTime: 1677615892,
+ dnsName: "www.google.com",
+
+ expectedChains: [][]string{
+ {"www.google.com", "GTS CA 1C3", "GTS Root R1"},
+ },
+ // CAPI doesn't build the chain with the duplicated GeoTrust
+ // entry so the results don't match.
+ systemLax: true,
+ },
+ {
+ name: "dnssec-exp",
+ leaf: dnssecExpLeaf,
+ intermediates: []string{startComIntermediate},
+ roots: []string{startComRoot},
+ currentTime: 1302726541,
+
+ // The StartCom root is not trusted by Windows when the default
+ // ServerAuth EKU is requested.
+ systemSkip: true,
+
+ expectedChains: [][]string{
+ {"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
+ },
+ },
+ {
+ name: "dnssec-exp/AnyEKU",
+ leaf: dnssecExpLeaf,
+ intermediates: []string{startComIntermediate},
+ roots: []string{startComRoot},
+ currentTime: 1302726541,
+ keyUsages: []ExtKeyUsage{ExtKeyUsageAny},
+
+ expectedChains: [][]string{
+ {"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
+ },
+ },
+ {
+ name: "dnssec-exp/RootInIntermediates",
+ leaf: dnssecExpLeaf,
+ intermediates: []string{startComIntermediate, startComRoot},
+ roots: []string{startComRoot},
+ currentTime: 1302726541,
+ systemSkip: true, // see dnssec-exp test
+
+ expectedChains: [][]string{
+ {"dnssec-exp", "StartCom Class 1", "StartCom Certification Authority"},
+ },
+ },
+ {
+ name: "InvalidHash",
+ leaf: googleLeafWithInvalidHash,
+ intermediates: []string{gtsIntermediate},
+ roots: []string{gtsRoot},
+ currentTime: 1677615892,
+ dnsName: "www.google.com",
+
+ // The specific error message may not occur when using system
+ // verification.
+ systemLax: true,
+ errorCallback: expectHashError,
+ },
+ // EKULeaf tests use an unconstrained chain leading to a leaf certificate
+ // with an E-mail Protection EKU but not a Server Auth one, checking that
+ // the EKUs on the leaf are enforced.
+ {
+ name: "EKULeaf",
+ leaf: smimeLeaf,
+ intermediates: []string{smimeIntermediate},
+ roots: []string{smimeRoot},
+ currentTime: 1594673418,
+
+ errorCallback: expectUsageError,
+ },
+ {
+ name: "EKULeafExplicit",
+ leaf: smimeLeaf,
+ intermediates: []string{smimeIntermediate},
+ roots: []string{smimeRoot},
+ currentTime: 1594673418,
+ keyUsages: []ExtKeyUsage{ExtKeyUsageServerAuth},
+
+ errorCallback: expectUsageError,
+ },
+ {
+ name: "EKULeafValid",
+ leaf: smimeLeaf,
+ intermediates: []string{smimeIntermediate},
+ roots: []string{smimeRoot},
+ currentTime: 1594673418,
+ keyUsages: []ExtKeyUsage{ExtKeyUsageEmailProtection},
+
+ expectedChains: [][]string{
+ {"CORPORATIVO FICTICIO ACTIVO", "EAEko Herri Administrazioen CA - CA AAPP Vascas (2)", "IZENPE S.A."},
+ },
+ },
+ {
+ // Check that a name constrained intermediate works even when
+ // it lists multiple constraints.
+ name: "MultipleConstraints",
+ leaf: nameConstraintsLeaf,
+ intermediates: []string{nameConstraintsIntermediate1, nameConstraintsIntermediate2},
+ roots: []string{globalSignRoot},
+ currentTime: 1382387896,
+ dnsName: "secure.iddl.vt.edu",
+
+ expectedChains: [][]string{
+ {
+ "Technology-enhanced Learning and Online Strategies",
+ "Virginia Tech Global Qualified Server CA",
+ "Trusted Root CA G2",
+ "GlobalSign Root CA",
+ },
+ },
+ },
+ {
+ // Check that SHA-384 intermediates (which are popping up)
+ // work.
+ name: "SHA-384",
+ leaf: trustAsiaLeaf,
+ intermediates: []string{trustAsiaSHA384Intermediate},
+ roots: []string{digicertRoot},
+ currentTime: 1558051200,
+ dnsName: "tm.cn",
+
+ // CryptoAPI can find alternative validation paths.
+ systemLax: true,
+
+ expectedChains: [][]string{
+ {
+ "tm.cn",
+ "TrustAsia ECC OV TLS Pro CA",
+ "DigiCert Global Root CA",
+ },
+ },
+ },
+ {
+ // Putting a certificate as a root directly should work as a
+ // way of saying “exactly this”.
+ name: "LeafInRoots",
+ leaf: selfSigned,
+ roots: []string{selfSigned},
+ currentTime: 1471624472,
+ dnsName: "foo.example",
+ systemSkip: true, // does not chain to a system root
+
+ expectedChains: [][]string{
+ {"Acme Co"},
+ },
+ },
+ {
+ // Putting a certificate as a root directly should not skip
+ // other checks however.
+ name: "LeafInRootsInvalid",
+ leaf: selfSigned,
+ roots: []string{selfSigned},
+ currentTime: 1471624472,
+ dnsName: "notfoo.example",
+ systemSkip: true, // does not chain to a system root
+
+ errorCallback: expectHostnameError("certificate is valid for"),
+ },
+ {
+ // An X.509 v1 certificate should not be accepted as an
+ // intermediate.
+ name: "X509v1Intermediate",
+ leaf: x509v1TestLeaf,
+ intermediates: []string{x509v1TestIntermediate},
+ roots: []string{x509v1TestRoot},
+ currentTime: 1481753183,
+ systemSkip: true, // does not chain to a system root
+
+ errorCallback: expectNotAuthorizedError,
+ },
+ {
+ name: "IgnoreCNWithSANs",
+ leaf: ignoreCNWithSANLeaf,
+ dnsName: "foo.example.com",
+ roots: []string{ignoreCNWithSANRoot},
+ currentTime: 1486684488,
+ systemSkip: true, // does not chain to a system root
+
+ errorCallback: expectHostnameError("certificate is not valid for any names"),
+ },
+ {
+ // Test that excluded names are respected.
+ name: "ExcludedNames",
+ leaf: excludedNamesLeaf,
+ dnsName: "bender.local",
+ intermediates: []string{excludedNamesIntermediate},
+ roots: []string{excludedNamesRoot},
+ currentTime: 1486684488,
+ systemSkip: true, // does not chain to a system root
+
+ errorCallback: expectNameConstraintsError,
+ },
+ {
+ // Test that unknown critical extensions in a leaf cause a
+ // verify error.
+ name: "CriticalExtLeaf",
+ leaf: criticalExtLeafWithExt,
+ intermediates: []string{criticalExtIntermediate},
+ roots: []string{criticalExtRoot},
+ currentTime: 1486684488,
+ systemSkip: true, // does not chain to a system root
+
+ errorCallback: expectUnhandledCriticalExtension,
+ },
+ {
+ // Test that unknown critical extensions in an intermediate
+ // cause a verify error.
+ name: "CriticalExtIntermediate",
+ leaf: criticalExtLeaf,
+ intermediates: []string{criticalExtIntermediateWithExt},
+ roots: []string{criticalExtRoot},
+ currentTime: 1486684488,
+ systemSkip: true, // does not chain to a system root
+
+ errorCallback: expectUnhandledCriticalExtension,
+ },
+ {
+ name: "ValidCN",
+ leaf: validCNWithoutSAN,
+ dnsName: "foo.example.com",
+ roots: []string{invalidCNRoot},
+ currentTime: 1540000000,
+ systemSkip: true, // does not chain to a system root
+
+ errorCallback: expectHostnameError("certificate relies on legacy Common Name field"),
+ },
+ {
+ // A certificate with an AKID should still chain to a parent without SKID.
+ // See Issue 30079.
+ name: "AKIDNoSKID",
+ leaf: leafWithAKID,
+ roots: []string{rootWithoutSKID},
+ currentTime: 1550000000,
+ dnsName: "example",
+ systemSkip: true, // does not chain to a system root
+
+ expectedChains: [][]string{
+ {"Acme LLC", "Acme Co"},
+ },
+ },
+ {
+ // When there are two parents, one with a incorrect subject but matching SKID
+ // and one with a correct subject but missing SKID, the latter should be
+ // considered as a possible parent.
+ leaf: leafMatchingAKIDMatchingIssuer,
+ roots: []string{rootMatchingSKIDMismatchingSubject, rootMismatchingSKIDMatchingSubject},
+ currentTime: 1550000000,
+ dnsName: "example",
+ systemSkip: true,
+
+ expectedChains: [][]string{
+ {"Leaf", "Root B"},
+ },
+ },
+}
+
+func expectHostnameError(msg string) func(*testing.T, error) {
+ return func(t *testing.T, err error) {
+ if _, ok := err.(HostnameError); !ok {
+ t.Fatalf("error was not a HostnameError: %v", err)
+ }
+ if !strings.Contains(err.Error(), msg) {
+ t.Fatalf("HostnameError did not contain %q: %v", msg, err)
+ }
+ }
+}
+
+func expectExpired(t *testing.T, err error) {
+ if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != Expired {
+ t.Fatalf("error was not Expired: %v", err)
+ }
+}
+
+func expectUsageError(t *testing.T, err error) {
+ if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != IncompatibleUsage {
+ t.Fatalf("error was not IncompatibleUsage: %v", err)
+ }
+}
+
+func expectAuthorityUnknown(t *testing.T, err error) {
+ e, ok := err.(UnknownAuthorityError)
+ if !ok {
+ t.Fatalf("error was not UnknownAuthorityError: %v", err)
+ }
+ if e.Cert == nil {
+ t.Fatalf("error was UnknownAuthorityError, but missing Cert: %v", err)
+ }
+}
+
+func expectHashError(t *testing.T, err error) {
+ if err == nil {
+ t.Fatalf("no error resulted from invalid hash")
+ }
+ if expected := "algorithm unimplemented"; !strings.Contains(err.Error(), expected) {
+ t.Fatalf("error resulting from invalid hash didn't contain '%s', rather it was: %v", expected, err)
+ }
+}
+
+func expectNameConstraintsError(t *testing.T, err error) {
+ if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != CANotAuthorizedForThisName {
+ t.Fatalf("error was not a CANotAuthorizedForThisName: %v", err)
+ }
+}
+
+func expectNotAuthorizedError(t *testing.T, err error) {
+ if inval, ok := err.(CertificateInvalidError); !ok || inval.Reason != NotAuthorizedToSign {
+ t.Fatalf("error was not a NotAuthorizedToSign: %v", err)
+ }
+}
+
+func expectUnhandledCriticalExtension(t *testing.T, err error) {
+ if _, ok := err.(UnhandledCriticalExtension); !ok {
+ t.Fatalf("error was not an UnhandledCriticalExtension: %v", err)
+ }
+}
+
+func certificateFromPEM(pemBytes string) (*Certificate, error) {
+ block, _ := pem.Decode([]byte(pemBytes))
+ if block == nil {
+ return nil, errors.New("failed to decode PEM")
+ }
+ return ParseCertificate(block.Bytes)
+}
+
+func testVerify(t *testing.T, test verifyTest, useSystemRoots bool) {
+ opts := VerifyOptions{
+ Intermediates: NewCertPool(),
+ DNSName: test.dnsName,
+ CurrentTime: time.Unix(test.currentTime, 0),
+ KeyUsages: test.keyUsages,
+ }
+
+ if !useSystemRoots {
+ opts.Roots = NewCertPool()
+ for j, root := range test.roots {
+ ok := opts.Roots.AppendCertsFromPEM([]byte(root))
+ if !ok {
+ t.Fatalf("failed to parse root #%d", j)
+ }
+ }
+ }
+
+ for j, intermediate := range test.intermediates {
+ ok := opts.Intermediates.AppendCertsFromPEM([]byte(intermediate))
+ if !ok {
+ t.Fatalf("failed to parse intermediate #%d", j)
+ }
+ }
+
+ leaf, err := certificateFromPEM(test.leaf)
+ if err != nil {
+ t.Fatalf("failed to parse leaf: %v", err)
+ }
+
+ chains, err := leaf.Verify(opts)
+
+ if test.errorCallback == nil && err != nil {
+ if runtime.GOOS == "windows" && strings.HasSuffix(testenv.Builder(), "-2008") && err.Error() == "x509: certificate signed by unknown authority" {
+ testenv.SkipFlaky(t, 19564)
+ }
+ t.Fatalf("unexpected error: %v", err)
+ }
+ if test.errorCallback != nil {
+ if useSystemRoots && test.systemLax {
+ if err == nil {
+ t.Fatalf("expected error")
+ }
+ } else {
+ test.errorCallback(t, err)
+ }
+ }
+
+ doesMatch := func(expectedChain []string, chain []*Certificate) bool {
+ if len(chain) != len(expectedChain) {
+ return false
+ }
+
+ for k, cert := range chain {
+ if !strings.Contains(nameToKey(&cert.Subject), expectedChain[k]) {
+ return false
+ }
+ }
+ return true
+ }
+
+ // Every expected chain should match one (or more) returned chain. We tolerate multiple
+ // matches, as due to root store semantics it is plausible that (at least on the system
+ // verifiers) multiple identical (looking) chains may be returned when two roots with the
+ // same subject are present.
+ for _, expectedChain := range test.expectedChains {
+ var match bool
+ for _, chain := range chains {
+ if doesMatch(expectedChain, chain) {
+ match = true
+ break
+ }
+ }
+
+ if !match {
+ t.Errorf("No match found for %v", expectedChain)
+ }
+ }
+
+ // Every returned chain should match 1 expected chain (or <2 if testing against the system)
+ for _, chain := range chains {
+ nMatched := 0
+ for _, expectedChain := range test.expectedChains {
+ if doesMatch(expectedChain, chain) {
+ nMatched++
+ }
+ }
+ // Allow additional unknown chains if systemLax is set
+ if nMatched == 0 && test.systemLax == false || nMatched > 1 {
+ t.Errorf("Got %v matches for chain %v", nMatched, chainToDebugString(chain))
+ for _, expectedChain := range test.expectedChains {
+ if doesMatch(expectedChain, chain) {
+ t.Errorf("\t matched %v", expectedChain)
+ }
+ }
+ }
+ }
+}
+
+func TestGoVerify(t *testing.T) {
+ // Temporarily enable SHA-1 verification since a number of test chains
+ // require it. TODO(filippo): regenerate test chains.
+ t.Setenv("GODEBUG", "x509sha1=1")
+
+ for _, test := range verifyTests {
+ t.Run(test.name, func(t *testing.T) {
+ testVerify(t, test, false)
+ })
+ }
+}
+
+func TestSystemVerify(t *testing.T) {
+ if runtime.GOOS != "windows" {
+ t.Skipf("skipping verify test using system APIs on %q", runtime.GOOS)
+ }
+
+ for _, test := range verifyTests {
+ t.Run(test.name, func(t *testing.T) {
+ if test.systemSkip {
+ t.SkipNow()
+ }
+ testVerify(t, test, true)
+ })
+ }
+}
+
+func chainToDebugString(chain []*Certificate) string {
+ var chainStr string
+ for _, cert := range chain {
+ if len(chainStr) > 0 {
+ chainStr += " -> "
+ }
+ chainStr += nameToKey(&cert.Subject)
+ }
+ return chainStr
+}
+
+func nameToKey(name *pkix.Name) string {
+ return strings.Join(name.Country, ",") + "/" + strings.Join(name.Organization, ",") + "/" + strings.Join(name.OrganizationalUnit, ",") + "/" + name.CommonName
+}
+
+const gtsIntermediate = `-----BEGIN CERTIFICATE-----
+MIIFljCCA36gAwIBAgINAgO8U1lrNMcY9QFQZjANBgkqhkiG9w0BAQsFADBHMQsw
+CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
+MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMjAwODEzMDAwMDQyWhcNMjcwOTMwMDAw
+MDQyWjBGMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
+Y2VzIExMQzETMBEGA1UEAxMKR1RTIENBIDFDMzCCASIwDQYJKoZIhvcNAQEBBQAD
+ggEPADCCAQoCggEBAPWI3+dijB43+DdCkH9sh9D7ZYIl/ejLa6T/belaI+KZ9hzp
+kgOZE3wJCor6QtZeViSqejOEH9Hpabu5dOxXTGZok3c3VVP+ORBNtzS7XyV3NzsX
+lOo85Z3VvMO0Q+sup0fvsEQRY9i0QYXdQTBIkxu/t/bgRQIh4JZCF8/ZK2VWNAcm
+BA2o/X3KLu/qSHw3TT8An4Pf73WELnlXXPxXbhqW//yMmqaZviXZf5YsBvcRKgKA
+gOtjGDxQSYflispfGStZloEAoPtR28p3CwvJlk/vcEnHXG0g/Zm0tOLKLnf9LdwL
+tmsTDIwZKxeWmLnwi/agJ7u2441Rj72ux5uxiZ0CAwEAAaOCAYAwggF8MA4GA1Ud
+DwEB/wQEAwIBhjAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0T
+AQH/BAgwBgEB/wIBADAdBgNVHQ4EFgQUinR/r4XN7pXNPZzQ4kYU83E1HScwHwYD
+VR0jBBgwFoAU5K8rJnEaK0gnhS9SZizv8IkTcT4waAYIKwYBBQUHAQEEXDBaMCYG
+CCsGAQUFBzABhhpodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHNyMTAwBggrBgEFBQcw
+AoYkaHR0cDovL3BraS5nb29nL3JlcG8vY2VydHMvZ3RzcjEuZGVyMDQGA1UdHwQt
+MCswKaAnoCWGI2h0dHA6Ly9jcmwucGtpLmdvb2cvZ3RzcjEvZ3RzcjEuY3JsMFcG
+A1UdIARQME4wOAYKKwYBBAHWeQIFAzAqMCgGCCsGAQUFBwIBFhxodHRwczovL3Br
+aS5nb29nL3JlcG9zaXRvcnkvMAgGBmeBDAECATAIBgZngQwBAgIwDQYJKoZIhvcN
+AQELBQADggIBAIl9rCBcDDy+mqhXlRu0rvqrpXJxtDaV/d9AEQNMwkYUuxQkq/BQ
+cSLbrcRuf8/xam/IgxvYzolfh2yHuKkMo5uhYpSTld9brmYZCwKWnvy15xBpPnrL
+RklfRuFBsdeYTWU0AIAaP0+fbH9JAIFTQaSSIYKCGvGjRFsqUBITTcFTNvNCCK9U
++o53UxtkOCcXCb1YyRt8OS1b887U7ZfbFAO/CVMkH8IMBHmYJvJh8VNS/UKMG2Yr
+PxWhu//2m+OBmgEGcYk1KCTd4b3rGS3hSMs9WYNRtHTGnXzGsYZbr8w0xNPM1IER
+lQCh9BIiAfq0g3GvjLeMcySsN1PCAJA/Ef5c7TaUEDu9Ka7ixzpiO2xj2YC/WXGs
+Yye5TBeg2vZzFb8q3o/zpWwygTMD0IZRcZk0upONXbVRWPeyk+gB9lm+cZv9TSjO
+z23HFtz30dZGm6fKa+l3D/2gthsjgx0QGtkJAITgRNOidSOzNIb2ILCkXhAd4FJG
+AJ2xDx8hcFH1mt0G/FX0Kw4zd8NLQsLxdxP8c4CU6x+7Nz/OAipmsHMdMqUybDKw
+juDEI/9bfU1lcKwrmz3O2+BtjjKAvpafkmO8l7tdufThcV4q5O8DIrGKZTqPwJNl
+1IXNDw9bg1kWRxYtnCQ6yICmJhSFm/Y3m6xv+cXDBlHz4n/FsRC6UfTd
+-----END CERTIFICATE-----`
+
+const gtsRoot = `-----BEGIN CERTIFICATE-----
+MIIFVzCCAz+gAwIBAgINAgPlk28xsBNJiGuiFzANBgkqhkiG9w0BAQwFADBHMQsw
+CQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExMQzEU
+MBIGA1UEAxMLR1RTIFJvb3QgUjEwHhcNMTYwNjIyMDAwMDAwWhcNMzYwNjIyMDAw
+MDAwWjBHMQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZp
+Y2VzIExMQzEUMBIGA1UEAxMLR1RTIFJvb3QgUjEwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQC2EQKLHuOhd5s73L+UPreVp0A8of2C+X0yBoJx9vaMf/vo
+27xqLpeXo4xL+Sv2sfnOhB2x+cWX3u+58qPpvBKJXqeqUqv4IyfLpLGcY9vXmX7w
+Cl7raKb0xlpHDU0QM+NOsROjyBhsS+z8CZDfnWQpJSMHobTSPS5g4M/SCYe7zUjw
+TcLCeoiKu7rPWRnWr4+wB7CeMfGCwcDfLqZtbBkOtdh+JhpFAz2weaSUKK0Pfybl
+qAj+lug8aJRT7oM6iCsVlgmy4HqMLnXWnOunVmSPlk9orj2XwoSPwLxAwAtcvfaH
+szVsrBhQf4TgTM2S0yDpM7xSma8ytSmzJSq0SPly4cpk9+aCEI3oncKKiPo4Zor8
+Y/kB+Xj9e1x3+naH+uzfsQ55lVe0vSbv1gHR6xYKu44LtcXFilWr06zqkUspzBmk
+MiVOKvFlRNACzqrOSbTqn3yDsEB750Orp2yjj32JgfpMpf/VjsPOS+C12LOORc92
+wO1AK/1TD7Cn1TsNsYqiA94xrcx36m97PtbfkSIS5r762DL8EGMUUXLeXdYWk70p
+aDPvOmbsB4om3xPXV2V4J95eSRQAogB/mqghtqmxlbCluQ0WEdrHbEg8QOB+DVrN
+VjzRlwW5y0vtOUucxD/SVRNuJLDWcfr0wbrM7Rv1/oFB2ACYPTrIrnqYNxgFlQID
+AQABo0IwQDAOBgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4E
+FgQU5K8rJnEaK0gnhS9SZizv8IkTcT4wDQYJKoZIhvcNAQEMBQADggIBAJ+qQibb
+C5u+/x6Wki4+omVKapi6Ist9wTrYggoGxval3sBOh2Z5ofmmWJyq+bXmYOfg6LEe
+QkEzCzc9zolwFcq1JKjPa7XSQCGYzyI0zzvFIoTgxQ6KfF2I5DUkzps+GlQebtuy
+h6f88/qBVRRiClmpIgUxPoLW7ttXNLwzldMXG+gnoot7TiYaelpkttGsN/H9oPM4
+7HLwEXWdyzRSjeZ2axfG34arJ45JK3VmgRAhpuo+9K4l/3wV3s6MJT/KYnAK9y8J
+ZgfIPxz88NtFMN9iiMG1D53Dn0reWVlHxYciNuaCp+0KueIHoI17eko8cdLiA6Ef
+MgfdG+RCzgwARWGAtQsgWSl4vflVy2PFPEz0tv/bal8xa5meLMFrUKTX5hgUvYU/
+Z6tGn6D/Qqc6f1zLXbBwHSs09dR2CQzreExZBfMzQsNhFRAbd03OIozUhfJFfbdT
+6u9AWpQKXCBfTkBdYiJ23//OYb2MI3jSNwLgjt7RETeJ9r/tSQdirpLsQBqvFAnZ
+0E6yove+7u7Y/9waLd64NnHi/Hm3lCXRSHNboTXns5lndcEZOitHTtNCjv0xyBZm
+2tIMPNuzjsmhDYAPexZ3FL//2wmUspO8IFgV6dtxQ/PeEMMA3KgqlbbC1j+Qa3bb
+bP6MvPJwNQzcmRk13NfIRmPVNnGuV/u3gm3c
+-----END CERTIFICATE-----`
+
+const googleLeaf = `-----BEGIN CERTIFICATE-----
+MIIFUjCCBDqgAwIBAgIQERmRWTzVoz0SMeozw2RM3DANBgkqhkiG9w0BAQsFADBG
+MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
+QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMzAxMDIwODE5MTlaFw0yMzAzMjcw
+ODE5MThaMBkxFzAVBgNVBAMTDnd3dy5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAq30odrKMT54TJikMKL8S+lwoCMT5geP0u9pWjk6a
+wdB6i3kO+UE4ijCAmhbcZKeKaLnGJ38weZNwB1ayabCYyX7hDiC/nRcZU49LX5+o
+55kDVaNn14YKkg2kCeX25HDxSwaOsNAIXKPTqiQL5LPvc4Twhl8HY51hhNWQrTEr
+N775eYbixEULvyVLq5BLbCOpPo8n0/MTjQ32ku1jQq3GIYMJC/Rf2VW5doF6t9zs
+KleflAN8OdKp0ME9OHg0T1P3yyb67T7n0SpisHbeG06AmQcKJF9g/9VPJtRf4l1Q
+WRPDC+6JUqzXCxAGmIRGZ7TNMxPMBW/7DRX6w8oLKVNb0wIDAQABo4ICZzCCAmMw
+DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQC
+MAAwHQYDVR0OBBYEFBnboj3lf9+Xat4oEgo6ZtIMr8ZuMB8GA1UdIwQYMBaAFIp0
+f6+Fze6VzT2c0OJGFPNxNR0nMGoGCCsGAQUFBwEBBF4wXDAnBggrBgEFBQcwAYYb
+aHR0cDovL29jc3AucGtpLmdvb2cvZ3RzMWMzMDEGCCsGAQUFBzAChiVodHRwOi8v
+cGtpLmdvb2cvcmVwby9jZXJ0cy9ndHMxYzMuZGVyMBkGA1UdEQQSMBCCDnd3dy5n
+b29nbGUuY29tMCEGA1UdIAQaMBgwCAYGZ4EMAQIBMAwGCisGAQQB1nkCBQMwPAYD
+VR0fBDUwMzAxoC+gLYYraHR0cDovL2NybHMucGtpLmdvb2cvZ3RzMWMzL1FPdkow
+TjFzVDJBLmNybDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AHoyjFTYty22IOo4
+4FIe6YQWcDIThU070ivBOlejUutSAAABhXHHOiUAAAQDAEcwRQIgBUkikUIXdo+S
+3T8PP0/cvokhUlumRE3GRWGL4WRMLpcCIQDY+bwK384mZxyXGZ5lwNRTAPNzT8Fx
+1+//nbaGK3BQMAB2AOg+0No+9QY1MudXKLyJa8kD08vREWvs62nhd31tBr1uAAAB
+hXHHOfQAAAQDAEcwRQIgLoVydNfMFKV9IoZR+M0UuJ2zOqbxIRum7Sn9RMPOBGMC
+IQD1/BgzCSDTvYvco6kpB6ifKSbg5gcb5KTnYxQYwRW14TANBgkqhkiG9w0BAQsF
+AAOCAQEA2bQQu30e3OFu0bmvQHmcqYvXBu6tF6e5b5b+hj4O+Rn7BXTTmaYX3M6p
+MsfRH4YVJJMB/dc3PROR2VtnKFC6gAZX+RKM6nXnZhIlOdmQnonS1ecOL19PliUd
+VXbwKjXqAO0Ljd9y9oXaXnyPyHmUJNI5YXAcxE+XXiOZhcZuMYyWmoEKJQ/XlSga
+zWfTn1IcKhA3IC7A1n/5bkkWD1Xi1mdWFQ6DQDMp//667zz7pKOgFMlB93aPDjvI
+c78zEqNswn6xGKXpWF5xVwdFcsx9HKhJ6UAi2bQ/KQ1yb7LPUOR6wXXWrG1cLnNP
+i8eNLnKL9PXQ+5SwJFCzfEhcIZuhzg==
+-----END CERTIFICATE-----`
+
+// googleLeafWithInvalidHash is the same as googleLeaf, but the signature
+// algorithm in the certificate contains a nonsense OID.
+const googleLeafWithInvalidHash = `-----BEGIN CERTIFICATE-----
+MIIFUjCCBDqgAwIBAgIQERmRWTzVoz0SMeozw2RM3DANBgkqhkiG9w0BAQ4FADBG
+MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
+QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMzAxMDIwODE5MTlaFw0yMzAzMjcw
+ODE5MThaMBkxFzAVBgNVBAMTDnd3dy5nb29nbGUuY29tMIIBIjANBgkqhkiG9w0B
+AQEFAAOCAQ8AMIIBCgKCAQEAq30odrKMT54TJikMKL8S+lwoCMT5geP0u9pWjk6a
+wdB6i3kO+UE4ijCAmhbcZKeKaLnGJ38weZNwB1ayabCYyX7hDiC/nRcZU49LX5+o
+55kDVaNn14YKkg2kCeX25HDxSwaOsNAIXKPTqiQL5LPvc4Twhl8HY51hhNWQrTEr
+N775eYbixEULvyVLq5BLbCOpPo8n0/MTjQ32ku1jQq3GIYMJC/Rf2VW5doF6t9zs
+KleflAN8OdKp0ME9OHg0T1P3yyb67T7n0SpisHbeG06AmQcKJF9g/9VPJtRf4l1Q
+WRPDC+6JUqzXCxAGmIRGZ7TNMxPMBW/7DRX6w8oLKVNb0wIDAQABo4ICZzCCAmMw
+DgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoGCCsGAQUFBwMBMAwGA1UdEwEB/wQC
+MAAwHQYDVR0OBBYEFBnboj3lf9+Xat4oEgo6ZtIMr8ZuMB8GA1UdIwQYMBaAFIp0
+f6+Fze6VzT2c0OJGFPNxNR0nMGoGCCsGAQUFBwEBBF4wXDAnBggrBgEFBQcwAYYb
+aHR0cDovL29jc3AucGtpLmdvb2cvZ3RzMWMzMDEGCCsGAQUFBzAChiVodHRwOi8v
+cGtpLmdvb2cvcmVwby9jZXJ0cy9ndHMxYzMuZGVyMBkGA1UdEQQSMBCCDnd3dy5n
+b29nbGUuY29tMCEGA1UdIAQaMBgwCAYGZ4EMAQIBMAwGCisGAQQB1nkCBQMwPAYD
+VR0fBDUwMzAxoC+gLYYraHR0cDovL2NybHMucGtpLmdvb2cvZ3RzMWMzL1FPdkow
+TjFzVDJBLmNybDCCAQQGCisGAQQB1nkCBAIEgfUEgfIA8AB2AHoyjFTYty22IOo4
+4FIe6YQWcDIThU070ivBOlejUutSAAABhXHHOiUAAAQDAEcwRQIgBUkikUIXdo+S
+3T8PP0/cvokhUlumRE3GRWGL4WRMLpcCIQDY+bwK384mZxyXGZ5lwNRTAPNzT8Fx
+1+//nbaGK3BQMAB2AOg+0No+9QY1MudXKLyJa8kD08vREWvs62nhd31tBr1uAAAB
+hXHHOfQAAAQDAEcwRQIgLoVydNfMFKV9IoZR+M0UuJ2zOqbxIRum7Sn9RMPOBGMC
+IQD1/BgzCSDTvYvco6kpB6ifKSbg5gcb5KTnYxQYwRW14TANBgkqhkiG9w0BAQ4F
+AAOCAQEA2bQQu30e3OFu0bmvQHmcqYvXBu6tF6e5b5b+hj4O+Rn7BXTTmaYX3M6p
+MsfRH4YVJJMB/dc3PROR2VtnKFC6gAZX+RKM6nXnZhIlOdmQnonS1ecOL19PliUd
+VXbwKjXqAO0Ljd9y9oXaXnyPyHmUJNI5YXAcxE+XXiOZhcZuMYyWmoEKJQ/XlSga
+zWfTn1IcKhA3IC7A1n/5bkkWD1Xi1mdWFQ6DQDMp//667zz7pKOgFMlB93aPDjvI
+c78zEqNswn6xGKXpWF5xVwdFcsx9HKhJ6UAi2bQ/KQ1yb7LPUOR6wXXWrG1cLnNP
+i8eNLnKL9PXQ+5SwJFCzfEhcIZuhzg==
+-----END CERTIFICATE-----`
+
+const dnssecExpLeaf = `-----BEGIN CERTIFICATE-----
+MIIGzTCCBbWgAwIBAgIDAdD6MA0GCSqGSIb3DQEBBQUAMIGMMQswCQYDVQQGEwJJ
+TDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0
+YWwgQ2VydGlmaWNhdGUgU2lnbmluZzE4MDYGA1UEAxMvU3RhcnRDb20gQ2xhc3Mg
+MSBQcmltYXJ5IEludGVybWVkaWF0ZSBTZXJ2ZXIgQ0EwHhcNMTAwNzA0MTQ1MjQ1
+WhcNMTEwNzA1MTA1NzA0WjCBwTEgMB4GA1UEDRMXMjIxMTM3LWxpOWE5dHhJRzZM
+NnNyVFMxCzAJBgNVBAYTAlVTMR4wHAYDVQQKExVQZXJzb25hIE5vdCBWYWxpZGF0
+ZWQxKTAnBgNVBAsTIFN0YXJ0Q29tIEZyZWUgQ2VydGlmaWNhdGUgTWVtYmVyMRsw
+GQYDVQQDExJ3d3cuZG5zc2VjLWV4cC5vcmcxKDAmBgkqhkiG9w0BCQEWGWhvc3Rt
+YXN0ZXJAZG5zc2VjLWV4cC5vcmcwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK
+AoIBAQDEdF/22vaxrPbqpgVYMWi+alfpzBctpbfLBdPGuqOazJdCT0NbWcK8/+B4
+X6OlSOURNIlwLzhkmwVsWdVv6dVSaN7d4yI/fJkvgfDB9+au+iBJb6Pcz8ULBfe6
+D8HVvqKdORp6INzHz71z0sghxrQ0EAEkoWAZLh+kcn2ZHdcmZaBNUfjmGbyU6PRt
+RjdqoP+owIaC1aktBN7zl4uO7cRjlYFdusINrh2kPP02KAx2W84xjxX1uyj6oS6e
+7eBfvcwe8czW/N1rbE0CoR7h9+HnIrjnVG9RhBiZEiw3mUmF++Up26+4KTdRKbu3
++BL4yMpfd66z0+zzqu+HkvyLpFn5AgMBAAGjggL/MIIC+zAJBgNVHRMEAjAAMAsG
+A1UdDwQEAwIDqDATBgNVHSUEDDAKBggrBgEFBQcDATAdBgNVHQ4EFgQUy04I5guM
+drzfh2JQaXhgV86+4jUwHwYDVR0jBBgwFoAU60I00Jiwq5/0G2sI98xkLu8OLEUw
+LQYDVR0RBCYwJIISd3d3LmRuc3NlYy1leHAub3Jngg5kbnNzZWMtZXhwLm9yZzCC
+AUIGA1UdIASCATkwggE1MIIBMQYLKwYBBAGBtTcBAgIwggEgMC4GCCsGAQUFBwIB
+FiJodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMDQGCCsGAQUFBwIB
+FihodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9pbnRlcm1lZGlhdGUucGRmMIG3Bggr
+BgEFBQcCAjCBqjAUFg1TdGFydENvbSBMdGQuMAMCAQEagZFMaW1pdGVkIExpYWJp
+bGl0eSwgc2VlIHNlY3Rpb24gKkxlZ2FsIExpbWl0YXRpb25zKiBvZiB0aGUgU3Rh
+cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkgUG9saWN5IGF2YWlsYWJsZSBh
+dCBodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS9wb2xpY3kucGRmMGEGA1UdHwRaMFgw
+KqAooCaGJGh0dHA6Ly93d3cuc3RhcnRzc2wuY29tL2NydDEtY3JsLmNybDAqoCig
+JoYkaHR0cDovL2NybC5zdGFydHNzbC5jb20vY3J0MS1jcmwuY3JsMIGOBggrBgEF
+BQcBAQSBgTB/MDkGCCsGAQUFBzABhi1odHRwOi8vb2NzcC5zdGFydHNzbC5jb20v
+c3ViL2NsYXNzMS9zZXJ2ZXIvY2EwQgYIKwYBBQUHMAKGNmh0dHA6Ly93d3cuc3Rh
+cnRzc2wuY29tL2NlcnRzL3N1Yi5jbGFzczEuc2VydmVyLmNhLmNydDAjBgNVHRIE
+HDAahhhodHRwOi8vd3d3LnN0YXJ0c3NsLmNvbS8wDQYJKoZIhvcNAQEFBQADggEB
+ACXj6SB59KRJPenn6gUdGEqcta97U769SATyiQ87i9er64qLwvIGLMa3o2Rcgl2Y
+kghUeyLdN/EXyFBYA8L8uvZREPoc7EZukpT/ZDLXy9i2S0jkOxvF2fD/XLbcjGjM
+iEYG1/6ASw0ri9C0k4oDDoJLCoeH9++yqF7SFCCMcDkJqiAGXNb4euDpa8vCCtEQ
+CSS+ObZbfkreRt3cNCf5LfCXe9OsTnCfc8Cuq81c0oLaG+SmaLUQNBuToq8e9/Zm
++b+/a3RVjxmkV5OCcGVBxsXNDn54Q6wsdw0TBMcjwoEndzpLS7yWgFbbkq5ZiGpw
+Qibb2+CfKuQ+WFV1GkVQmVA=
+-----END CERTIFICATE-----`
+
+const startComIntermediate = `-----BEGIN CERTIFICATE-----
+MIIGNDCCBBygAwIBAgIBGDANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDcxMDI0MjA1NDE3WhcNMTcxMDI0MjA1NDE3WjCB
+jDELMAkGA1UEBhMCSUwxFjAUBgNVBAoTDVN0YXJ0Q29tIEx0ZC4xKzApBgNVBAsT
+IlNlY3VyZSBEaWdpdGFsIENlcnRpZmljYXRlIFNpZ25pbmcxODA2BgNVBAMTL1N0
+YXJ0Q29tIENsYXNzIDEgUHJpbWFyeSBJbnRlcm1lZGlhdGUgU2VydmVyIENBMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAtonGrO8JUngHrJJj0PREGBiE
+gFYfka7hh/oyULTTRwbw5gdfcA4Q9x3AzhA2NIVaD5Ksg8asWFI/ujjo/OenJOJA
+pgh2wJJuniptTT9uYSAK21ne0n1jsz5G/vohURjXzTCm7QduO3CHtPn66+6CPAVv
+kvek3AowHpNz/gfK11+AnSJYUq4G2ouHI2mw5CrY6oPSvfNx23BaKA+vWjhwRRI/
+ME3NO68X5Q/LoKldSKqxYVDLNM08XMML6BDAjJvwAwNi/rJsPnIO7hxDKslIDlc5
+xDEhyBDBLIf+VJVSH1I8MRKbf+fAoKVZ1eKPPvDVqOHXcDGpxLPPr21TLwb0pwID
+AQABo4IBrTCCAakwDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMCAQYwHQYD
+VR0OBBYEFOtCNNCYsKuf9BtrCPfMZC7vDixFMB8GA1UdIwQYMBaAFE4L7xqkQFul
+F2mHMMo0aEPQQa7yMGYGCCsGAQUFBwEBBFowWDAnBggrBgEFBQcwAYYbaHR0cDov
+L29jc3Auc3RhcnRzc2wuY29tL2NhMC0GCCsGAQUFBzAChiFodHRwOi8vd3d3LnN0
+YXJ0c3NsLmNvbS9zZnNjYS5jcnQwWwYDVR0fBFQwUjAnoCWgI4YhaHR0cDovL3d3
+dy5zdGFydHNzbC5jb20vc2ZzY2EuY3JsMCegJaAjhiFodHRwOi8vY3JsLnN0YXJ0
+c3NsLmNvbS9zZnNjYS5jcmwwgYAGA1UdIAR5MHcwdQYLKwYBBAGBtTcBAgEwZjAu
+BggrBgEFBQcCARYiaHR0cDovL3d3dy5zdGFydHNzbC5jb20vcG9saWN5LnBkZjA0
+BggrBgEFBQcCARYoaHR0cDovL3d3dy5zdGFydHNzbC5jb20vaW50ZXJtZWRpYXRl
+LnBkZjANBgkqhkiG9w0BAQUFAAOCAgEAIQlJPqWIbuALi0jaMU2P91ZXouHTYlfp
+tVbzhUV1O+VQHwSL5qBaPucAroXQ+/8gA2TLrQLhxpFy+KNN1t7ozD+hiqLjfDen
+xk+PNdb01m4Ge90h2c9W/8swIkn+iQTzheWq8ecf6HWQTd35RvdCNPdFWAwRDYSw
+xtpdPvkBnufh2lWVvnQce/xNFE+sflVHfXv0pQ1JHpXo9xLBzP92piVH0PN1Nb6X
+t1gW66pceG/sUzCv6gRNzKkC4/C2BBL2MLERPZBOVmTX3DxDX3M570uvh+v2/miI
+RHLq0gfGabDBoYvvF0nXYbFFSF87ICHpW7LM9NfpMfULFWE7epTj69m8f5SuauNi
+YpaoZHy4h/OZMn6SolK+u/hlz8nyMPyLwcKmltdfieFcNID1j0cHL7SRv7Gifl9L
+WtBbnySGBVFaaQNlQ0lxxeBvlDRr9hvYqbBMflPrj0jfyjO1SPo2ShpTpjMM0InN
+SRXNiTE8kMBy12VLUjWKRhFEuT2OKGWmPnmeXAhEKa2wNREuIU640ucQPl2Eg7PD
+wuTSxv0JS3QJ3fGz0xk+gA2iCxnwOOfFwq/iI9th4p1cbiCJSS4jarJiwUW0n6+L
+p/EiO/h94pDQehn7Skzj0n1fSoMD7SfWI55rjbRZotnvbIIp3XUZPD9MEI3vu3Un
+0q6Dp6jOW6c=
+-----END CERTIFICATE-----`
+
+const startComRoot = `-----BEGIN CERTIFICATE-----
+MIIHyTCCBbGgAwIBAgIBATANBgkqhkiG9w0BAQUFADB9MQswCQYDVQQGEwJJTDEW
+MBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMiU2VjdXJlIERpZ2l0YWwg
+Q2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3RhcnRDb20gQ2VydGlmaWNh
+dGlvbiBBdXRob3JpdHkwHhcNMDYwOTE3MTk0NjM2WhcNMzYwOTE3MTk0NjM2WjB9
+MQswCQYDVQQGEwJJTDEWMBQGA1UEChMNU3RhcnRDb20gTHRkLjErMCkGA1UECxMi
+U2VjdXJlIERpZ2l0YWwgQ2VydGlmaWNhdGUgU2lnbmluZzEpMCcGA1UEAxMgU3Rh
+cnRDb20gQ2VydGlmaWNhdGlvbiBBdXRob3JpdHkwggIiMA0GCSqGSIb3DQEBAQUA
+A4ICDwAwggIKAoICAQDBiNsJvGxGfHiflXu1M5DycmLWwTYgIiRezul38kMKogZk
+pMyONvg45iPwbm2xPN1yo4UcodM9tDMr0y+v/uqwQVlntsQGfQqedIXWeUyAN3rf
+OQVSWff0G0ZDpNKFhdLDcfN1YjS6LIp/Ho/u7TTQEceWzVI9ujPW3U3eCztKS5/C
+Ji/6tRYccjV3yjxd5srhJosaNnZcAdt0FCX+7bWgiA/deMotHweXMAEtcnn6RtYT
+Kqi5pquDSR3l8u/d5AGOGAqPY1MWhWKpDhk6zLVmpsJrdAfkK+F2PrRt2PZE4XNi
+HzvEvqBTViVsUQn3qqvKv3b9bZvzndu/PWa8DFaqr5hIlTpL36dYUNk4dalb6kMM
+Av+Z6+hsTXBbKWWc3apdzK8BMewM69KN6Oqce+Zu9ydmDBpI125C4z/eIT574Q1w
++2OqqGwaVLRcJXrJosmLFqa7LH4XXgVNWG4SHQHuEhANxjJ/GP/89PrNbpHoNkm+
+Gkhpi8KWTRoSsmkXwQqQ1vp5Iki/untp+HDH+no32NgN0nZPV/+Qt+OR0t3vwmC3
+Zzrd/qqc8NSLf3Iizsafl7b4r4qgEKjZ+xjGtrVcUjyJthkqcwEKDwOzEmDyei+B
+26Nu/yYwl/WL3YlXtq09s68rxbd2AvCl1iuahhQqcvbjM4xdCUsT37uMdBNSSwID
+AQABo4ICUjCCAk4wDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAa4wHQYDVR0OBBYE
+FE4L7xqkQFulF2mHMMo0aEPQQa7yMGQGA1UdHwRdMFswLKAqoCiGJmh0dHA6Ly9j
+ZXJ0LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMCugKaAnhiVodHRwOi8vY3Js
+LnN0YXJ0Y29tLm9yZy9zZnNjYS1jcmwuY3JsMIIBXQYDVR0gBIIBVDCCAVAwggFM
+BgsrBgEEAYG1NwEBATCCATswLwYIKwYBBQUHAgEWI2h0dHA6Ly9jZXJ0LnN0YXJ0
+Y29tLm9yZy9wb2xpY3kucGRmMDUGCCsGAQUFBwIBFilodHRwOi8vY2VydC5zdGFy
+dGNvbS5vcmcvaW50ZXJtZWRpYXRlLnBkZjCB0AYIKwYBBQUHAgIwgcMwJxYgU3Rh
+cnQgQ29tbWVyY2lhbCAoU3RhcnRDb20pIEx0ZC4wAwIBARqBl0xpbWl0ZWQgTGlh
+YmlsaXR5LCByZWFkIHRoZSBzZWN0aW9uICpMZWdhbCBMaW1pdGF0aW9ucyogb2Yg
+dGhlIFN0YXJ0Q29tIENlcnRpZmljYXRpb24gQXV0aG9yaXR5IFBvbGljeSBhdmFp
+bGFibGUgYXQgaHR0cDovL2NlcnQuc3RhcnRjb20ub3JnL3BvbGljeS5wZGYwEQYJ
+YIZIAYb4QgEBBAQDAgAHMDgGCWCGSAGG+EIBDQQrFilTdGFydENvbSBGcmVlIFNT
+TCBDZXJ0aWZpY2F0aW9uIEF1dGhvcml0eTANBgkqhkiG9w0BAQUFAAOCAgEAFmyZ
+9GYMNPXQhV59CuzaEE44HF7fpiUFS5Eyweg78T3dRAlbB0mKKctmArexmvclmAk8
+jhvh3TaHK0u7aNM5Zj2gJsfyOZEdUauCe37Vzlrk4gNXcGmXCPleWKYK34wGmkUW
+FjgKXlf2Ysd6AgXmvB618p70qSmD+LIU424oh0TDkBreOKk8rENNZEXO3SipXPJz
+ewT4F+irsfMuXGRuczE6Eri8sxHkfY+BUZo7jYn0TZNmezwD7dOaHZrzZVD1oNB1
+ny+v8OqCQ5j4aZyJecRDjkZy42Q2Eq/3JR44iZB3fsNrarnDy0RLrHiQi+fHLB5L
+EUTINFInzQpdn4XBidUaePKVEFMy3YCEZnXZtWgo+2EuvoSoOMCZEoalHmdkrQYu
+L6lwhceWD3yJZfWOQ1QOq92lgDmUYMA0yZZwLKMS9R9Ie70cfmu3nZD0Ijuu+Pwq
+yvqCUqDvr0tVk+vBtfAii6w0TiYiBKGHLHVKt+V9E9e4DGTANtLJL4YSjCMJwRuC
+O3NJo2pXh5Tl1njFmUNj403gdy3hZZlyaQQaRwnmDwFWJPsfvw55qVguucQJAX6V
+um0ABj6y6koQOdjQK/W/7HW/lwLFCRsI3FU34oH7N4RDYiDK51ZLZer+bMEkkySh
+NOsF/5oirpt9P/FlUQqmMGqz9IgcgA38corog14=
+-----END CERTIFICATE-----`
+
+const smimeLeaf = `-----BEGIN CERTIFICATE-----
+MIIIPDCCBiSgAwIBAgIQaMDxFS0pOMxZZeOBxoTJtjANBgkqhkiG9w0BAQsFADCB
+nTELMAkGA1UEBhMCRVMxFDASBgNVBAoMC0laRU5QRSBTLkEuMTowOAYDVQQLDDFB
+WlogWml1cnRhZ2lyaSBwdWJsaWtvYSAtIENlcnRpZmljYWRvIHB1YmxpY28gU0NB
+MTwwOgYDVQQDDDNFQUVrbyBIZXJyaSBBZG1pbmlzdHJhemlvZW4gQ0EgLSBDQSBB
+QVBQIFZhc2NhcyAoMikwHhcNMTcwNzEyMDg1MzIxWhcNMjEwNzEyMDg1MzIxWjCC
+AQwxDzANBgNVBAoMBklaRU5QRTE4MDYGA1UECwwvWml1cnRhZ2lyaSBrb3Jwb3Jh
+dGlib2EtQ2VydGlmaWNhZG8gY29ycG9yYXRpdm8xQzBBBgNVBAsMOkNvbmRpY2lv
+bmVzIGRlIHVzbyBlbiB3d3cuaXplbnBlLmNvbSBub2xhIGVyYWJpbGkgamFraXRl
+a28xFzAVBgNVBC4TDi1kbmkgOTk5OTk5ODlaMSQwIgYDVQQDDBtDT1JQT1JBVElW
+TyBGSUNUSUNJTyBBQ1RJVk8xFDASBgNVBCoMC0NPUlBPUkFUSVZPMREwDwYDVQQE
+DAhGSUNUSUNJTzESMBAGA1UEBRMJOTk5OTk5ODlaMIIBIjANBgkqhkiG9w0BAQEF
+AAOCAQ8AMIIBCgKCAQEAwVOMwUDfBtsH0XuxYnb+v/L774jMH8valX7RPH8cl2Lb
+SiqSo0RchW2RGA2d1yuYHlpChC9jGmt0X/g66/E/+q2hUJlfJtqVDJFwtFYV4u2S
+yzA3J36V4PRkPQrKxAsbzZriFXAF10XgiHQz9aVeMMJ9GBhmh9+DK8Tm4cMF6i8l
++AuC35KdngPF1x0ealTYrYZplpEJFO7CiW42aLi6vQkDR2R7nmZA4AT69teqBWsK
+0DZ93/f0G/3+vnWwNTBF0lB6dIXoaz8OMSyHLqGnmmAtMrzbjAr/O/WWgbB/BqhR
+qjJQ7Ui16cuDldXaWQ/rkMzsxmsAox0UF+zdQNvXUQIDAQABo4IDBDCCAwAwgccG
+A1UdEgSBvzCBvIYVaHR0cDovL3d3dy5pemVucGUuY29tgQ9pbmZvQGl6ZW5wZS5j
+b22kgZEwgY4xRzBFBgNVBAoMPklaRU5QRSBTLkEuIC0gQ0lGIEEwMTMzNzI2MC1S
+TWVyYy5WaXRvcmlhLUdhc3RlaXogVDEwNTUgRjYyIFM4MUMwQQYDVQQJDDpBdmRh
+IGRlbCBNZWRpdGVycmFuZW8gRXRvcmJpZGVhIDE0IC0gMDEwMTAgVml0b3JpYS1H
+YXN0ZWl6MB4GA1UdEQQXMBWBE2ZpY3RpY2lvQGl6ZW5wZS5ldXMwDgYDVR0PAQH/
+BAQDAgXgMCkGA1UdJQQiMCAGCCsGAQUFBwMCBggrBgEFBQcDBAYKKwYBBAGCNxQC
+AjAdBgNVHQ4EFgQUyeoOD4cgcljKY0JvrNuX2waFQLAwHwYDVR0jBBgwFoAUwKlK
+90clh/+8taaJzoLSRqiJ66MwggEnBgNVHSAEggEeMIIBGjCCARYGCisGAQQB8zkB
+AQEwggEGMDMGCCsGAQUFBwIBFidodHRwOi8vd3d3Lml6ZW5wZS5jb20vcnBhc2Nh
+Y29ycG9yYXRpdm8wgc4GCCsGAQUFBwICMIHBGoG+Wml1cnRhZ2lyaWEgRXVza2Fs
+IEF1dG9ub21pYSBFcmtpZGVnb2tvIHNla3RvcmUgcHVibGlrb2tvIGVyYWt1bmRl
+ZW4gYmFybmUtc2FyZWV0YW4gYmFrYXJyaWsgZXJhYmlsIGRhaXRla2UuIFVzbyBy
+ZXN0cmluZ2lkbyBhbCBhbWJpdG8gZGUgcmVkZXMgaW50ZXJuYXMgZGUgRW50aWRh
+ZGVzIGRlbCBTZWN0b3IgUHVibGljbyBWYXNjbzAyBggrBgEFBQcBAQQmMCQwIgYI
+KwYBBQUHMAGGFmh0dHA6Ly9vY3NwLml6ZW5wZS5jb20wOgYDVR0fBDMwMTAvoC2g
+K4YpaHR0cDovL2NybC5pemVucGUuY29tL2NnaS1iaW4vY3JsaW50ZXJuYTIwDQYJ
+KoZIhvcNAQELBQADggIBAIy5PQ+UZlCRq6ig43vpHwlwuD9daAYeejV0Q+ZbgWAE
+GtO0kT/ytw95ZEJMNiMw3fYfPRlh27ThqiT0VDXZJDlzmn7JZd6QFcdXkCsiuv4+
+ZoXAg/QwnA3SGUUO9aVaXyuOIIuvOfb9MzoGp9xk23SMV3eiLAaLMLqwB5DTfBdt
+BGI7L1MnGJBv8RfP/TL67aJ5bgq2ri4S8vGHtXSjcZ0+rCEOLJtmDNMnTZxancg3
+/H5edeNd+n6Z48LO+JHRxQufbC4mVNxVLMIP9EkGUejlq4E4w6zb5NwCQczJbSWL
+i31rk2orsNsDlyaLGsWZp3JSNX6RmodU4KAUPor4jUJuUhrrm3Spb73gKlV/gcIw
+bCE7mML1Kss3x1ySaXsis6SZtLpGWKkW2iguPWPs0ydV6RPhmsCxieMwPPIJ87vS
+5IejfgyBae7RSuAIHyNFy4uI5xwvwUFf6OZ7az8qtW7ImFOgng3Ds+W9k1S2CNTx
+d0cnKTfA6IpjGo8EeHcxnIXT8NPImWaRj0qqonvYady7ci6U4m3lkNSdXNn1afgw
+mYust+gxVtOZs1gk2MUCgJ1V1X+g7r/Cg7viIn6TLkLrpS1kS1hvMqkl9M+7XqPo
+Qd95nJKOkusQpy99X4dF/lfbYAQnnjnqh3DLD2gvYObXFaAYFaiBKTiMTV2X72F+
+-----END CERTIFICATE-----`
+
+const smimeIntermediate = `-----BEGIN CERTIFICATE-----
+MIIHNzCCBSGgAwIBAgIQJMXIqlZvjuhMvqcFXOFkpDALBgkqhkiG9w0BAQswODEL
+MAkGA1UEBhMCRVMxFDASBgNVBAoMC0laRU5QRSBTLkEuMRMwEQYDVQQDDApJemVu
+cGUuY29tMB4XDTEwMTAyMDA4MjMzM1oXDTM3MTIxMjIzMDAwMFowgZ0xCzAJBgNV
+BAYTAkVTMRQwEgYDVQQKDAtJWkVOUEUgUy5BLjE6MDgGA1UECwwxQVpaIFppdXJ0
+YWdpcmkgcHVibGlrb2EgLSBDZXJ0aWZpY2FkbyBwdWJsaWNvIFNDQTE8MDoGA1UE
+AwwzRUFFa28gSGVycmkgQWRtaW5pc3RyYXppb2VuIENBIC0gQ0EgQUFQUCBWYXNj
+YXMgKDIpMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAoIM7nEdI0N1h
+rR5T4xuV/usKDoMIasaiKvfLhbwxaNtTt+a7W/6wV5bv3svQFIy3sUXjjdzV1nG2
+To2wo/YSPQiOt8exWvOapvL21ogiof+kelWnXFjWaKJI/vThHYLgIYEMj/y4HdtU
+ojI646rZwqsb4YGAopwgmkDfUh5jOhV2IcYE3TgJAYWVkj6jku9PLaIsHiarAHjD
+PY8dig8a4SRv0gm5Yk7FXLmW1d14oxQBDeHZ7zOEXfpafxdEDO2SNaRJjpkh8XRr
+PGqkg2y1Q3gT6b4537jz+StyDIJ3omylmlJsGCwqT7p8mEqjGJ5kC5I2VnjXKuNn
+soShc72khWZVUJiJo5SGuAkNE2ZXqltBVm5Jv6QweQKsX6bkcMc4IZok4a+hx8FM
+8IBpGf/I94pU6HzGXqCyc1d46drJgDY9mXa+6YDAJFl3xeXOOW2iGCfwXqhiCrKL
+MYvyMZzqF3QH5q4nb3ZnehYvraeMFXJXDn+Utqp8vd2r7ShfQJz01KtM4hgKdgSg
+jtW+shkVVN5ng/fPN85ovfAH2BHXFfHmQn4zKsYnLitpwYM/7S1HxlT61cdQ7Nnk
+3LZTYEgAoOmEmdheklT40WAYakksXGM5VrzG7x9S7s1Tm+Vb5LSThdHC8bxxwyTb
+KsDRDNJ84N9fPDO6qHnzaL2upQ43PycCAwEAAaOCAdkwggHVMIHHBgNVHREEgb8w
+gbyGFWh0dHA6Ly93d3cuaXplbnBlLmNvbYEPaW5mb0BpemVucGUuY29tpIGRMIGO
+MUcwRQYDVQQKDD5JWkVOUEUgUy5BLiAtIENJRiBBMDEzMzcyNjAtUk1lcmMuVml0
+b3JpYS1HYXN0ZWl6IFQxMDU1IEY2MiBTODFDMEEGA1UECQw6QXZkYSBkZWwgTWVk
+aXRlcnJhbmVvIEV0b3JiaWRlYSAxNCAtIDAxMDEwIFZpdG9yaWEtR2FzdGVpejAP
+BgNVHRMBAf8EBTADAQH/MA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUwKlK90cl
+h/+8taaJzoLSRqiJ66MwHwYDVR0jBBgwFoAUHRxlDqjyJXu0kc/ksbHmvVV0bAUw
+OgYDVR0gBDMwMTAvBgRVHSAAMCcwJQYIKwYBBQUHAgEWGWh0dHA6Ly93d3cuaXpl
+bnBlLmNvbS9jcHMwNwYIKwYBBQUHAQEEKzApMCcGCCsGAQUFBzABhhtodHRwOi8v
+b2NzcC5pemVucGUuY29tOjgwOTQwMwYDVR0fBCwwKjAooCagJIYiaHR0cDovL2Ny
+bC5pemVucGUuY29tL2NnaS1iaW4vYXJsMjALBgkqhkiG9w0BAQsDggIBAMbjc3HM
+3DG9ubWPkzsF0QsktukpujbTTcGk4h20G7SPRy1DiiTxrRzdAMWGjZioOP3/fKCS
+M539qH0M+gsySNie+iKlbSZJUyE635T1tKw+G7bDUapjlH1xyv55NC5I6wCXGC6E
+3TEP5B/E7dZD0s9E4lS511ubVZivFgOzMYo1DO96diny/N/V1enaTCpRl1qH1OyL
+xUYTijV4ph2gL6exwuG7pxfRcVNHYlrRaXWfTz3F6NBKyULxrI3P/y6JAtN1GqT4
+VF/+vMygx22n0DufGepBwTQz6/rr1ulSZ+eMnuJiTXgh/BzQnkUsXTb8mHII25iR
+0oYF2qAsk6ecWbLiDpkHKIDHmML21MZE13MS8NSvTHoqJO4LyAmDe6SaeNHtrPlK
+b6mzE1BN2ug+ZaX8wLA5IMPFaf0jKhb/Cxu8INsxjt00brsErCc9ip1VNaH0M4bi
+1tGxfiew2436FaeyUxW7Pl6G5GgkNbuUc7QIoRy06DdU/U38BxW3uyJMY60zwHvS
+FlKAn0OvYp4niKhAJwaBVN3kowmJuOU5Rid+TUnfyxbJ9cttSgzaF3hP/N4zgMEM
+5tikXUskeckt8LUK96EH0QyssavAMECUEb/xrupyRdYWwjQGvNLq6T5+fViDGyOw
+k+lzD44wofy8paAy9uC9Owae0zMEzhcsyRm7
+-----END CERTIFICATE-----`
+
+const smimeRoot = `-----BEGIN CERTIFICATE-----
+MIIF8TCCA9mgAwIBAgIQALC3WhZIX7/hy/WL1xnmfTANBgkqhkiG9w0BAQsFADA4
+MQswCQYDVQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6
+ZW5wZS5jb20wHhcNMDcxMjEzMTMwODI4WhcNMzcxMjEzMDgyNzI1WjA4MQswCQYD
+VQQGEwJFUzEUMBIGA1UECgwLSVpFTlBFIFMuQS4xEzARBgNVBAMMCkl6ZW5wZS5j
+b20wggIiMA0GCSqGSIb3DQEBAQUAA4ICDwAwggIKAoICAQDJ03rKDx6sp4boFmVq
+scIbRTJxldn+EFvMr+eleQGPicPK8lVx93e+d5TzcqQsRNiekpsUOqHnJJAKClaO
+xdgmlOHZSOEtPtoKct2jmRXagaKH9HtuJneJWK3W6wyyQXpzbm3benhB6QiIEn6H
+LmYRY2xU+zydcsC8Lv/Ct90NduM61/e0aL6i9eOBbsFGb12N4E3GVFWJGjMxCrFX
+uaOKmMPsOzTFlUFpfnXCPCDFYbpRR6AgkJOhkEvzTnyFRVSa0QUmQbC1TR0zvsQD
+yCV8wXDbO/QJLVQnSKwv4cSsPsjLkkxTOTcj7NMB+eAJRE1NZMDhDVqHIrytG6P+
+JrUV86f8hBnp7KGItERphIPzidF0BqnMC9bC3ieFUCbKF7jJeodWLBoBHmy+E60Q
+rLUk9TiRodZL2vG70t5HtfG8gfZZa88ZU+mNFctKy6lvROUbQc/hhqfK0GqfvEyN
+BjNaooXlkDWgYlwWTvDjovoDGrQscbNYLN57C9saD+veIR8GdwYDsMnvmfzAuU8L
+hij+0rnq49qlw0dpEuDb8PYZi+17cNcC1u2HGCgsBCRMd+RIihrGO5rUD8r6ddIB
+QFqNeb+Lz0vPqhbBleStTIo+F5HUsWLlguWABKQDfo2/2n+iD5dPDNMN+9fR5XJ+
+HMh3/1uaD7euBUbl8agW7EekFwIDAQABo4H2MIHzMIGwBgNVHREEgagwgaWBD2lu
+Zm9AaXplbnBlLmNvbaSBkTCBjjFHMEUGA1UECgw+SVpFTlBFIFMuQS4gLSBDSUYg
+QTAxMzM3MjYwLVJNZXJjLlZpdG9yaWEtR2FzdGVpeiBUMTA1NSBGNjIgUzgxQzBB
+BgNVBAkMOkF2ZGEgZGVsIE1lZGl0ZXJyYW5lbyBFdG9yYmlkZWEgMTQgLSAwMTAx
+MCBWaXRvcmlhLUdhc3RlaXowDwYDVR0TAQH/BAUwAwEB/zAOBgNVHQ8BAf8EBAMC
+AQYwHQYDVR0OBBYEFB0cZQ6o8iV7tJHP5LGx5r1VdGwFMA0GCSqGSIb3DQEBCwUA
+A4ICAQB4pgwWSp9MiDrAyw6lFn2fuUhfGI8NYjb2zRlrrKvV9pF9rnHzP7MOeIWb
+laQnIUdCSnxIOvVFfLMMjlF4rJUT3sb9fbgakEyrkgPH7UIBzg/YsfqikuFgba56
+awmqxinuaElnMIAkejEWOVt+8Rwu3WwJrfIxwYJOubv5vr8qhT/AQKM6WfxZSzwo
+JNu0FXWuDYi6LnPAvViH5ULy617uHjAimcs30cQhbIHsvm0m5hzkQiCeR7Csg1lw
+LDXWrzY0tM07+DKo7+N4ifuNRSzanLh+QBxh5z6ikixL8s36mLYp//Pye6kfLqCT
+VyvehQP5aTfLnnhqBbTFMXiJ7HqnheG5ezzevh55hM6fcA5ZwjUukCox2eRFekGk
+LhObNA5me0mrZJfQRsN5nXJQY6aYWwa9SG3YOYNw6DXwBdGqvOPbyALqfP2C2sJb
+UjWumDqtujWTI6cfSN01RpiyEGjkpTHCClguGYEQyVB1/OpaFs4R1+7vUIgtYf8/
+QnMFlEPVjjxOAToZpR9GTnfQXeWBIiGH/pR9hNiTrdZoQ0iy2+tzJOeRf1SktoA+
+naM8THLCV8Sg1Mw4J87VBp6iSNnpn86CcDaTmjvfliHjWbcM2pE38P1ZWrOZyGls
+QyYBNWNgVYkDOnXYukrZVP/u3oDYLdE41V4tC5h9Pmzb/CaIxw==
+-----END CERTIFICATE-----`
+
+var nameConstraintsLeaf = `-----BEGIN CERTIFICATE-----
+MIIHMTCCBRmgAwIBAgIIIZaV/3ezOJkwDQYJKoZIhvcNAQEFBQAwgcsxCzAJBgNV
+BAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEj
+MCEGA1UECxMaR2xvYmFsIFF1YWxpZmllZCBTZXJ2ZXIgQ0ExPDA6BgNVBAoTM1Zp
+cmdpbmlhIFBvbHl0ZWNobmljIEluc3RpdHV0ZSBhbmQgU3RhdGUgVW5pdmVyc2l0
+eTExMC8GA1UEAxMoVmlyZ2luaWEgVGVjaCBHbG9iYWwgUXVhbGlmaWVkIFNlcnZl
+ciBDQTAeFw0xMzA5MTkxNDM2NTVaFw0xNTA5MTkxNDM2NTVaMIHNMQswCQYDVQQG
+EwJVUzERMA8GA1UECAwIVmlyZ2luaWExEzARBgNVBAcMCkJsYWNrc2J1cmcxPDA6
+BgNVBAoMM1ZpcmdpbmlhIFBvbHl0ZWNobmljIEluc3RpdHV0ZSBhbmQgU3RhdGUg
+VW5pdmVyc2l0eTE7MDkGA1UECwwyVGVjaG5vbG9neS1lbmhhbmNlZCBMZWFybmlu
+ZyBhbmQgT25saW5lIFN0cmF0ZWdpZXMxGzAZBgNVBAMMEnNlY3VyZS5pZGRsLnZ0
+LmVkdTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAKkOyPpsOK/6IuPG
+WnIBlVwlHzeYf+cUlggqkLq0b0+vZbiTXgio9/VCuNQ8opSoss7J7o3ygV9to+9Y
+YwJKVC5WDT/y5JWpQey0CWILymViJnpNSwnxBc8A+Q8w5NUGDd/UhtPx/U8/hqbd
+WPDYj2hbOqyq8UlRhfS5pwtnv6BbCTaY11I6FhCLK7zttISyTuWCf9p9o/ggiipP
+ii/5oh4dkl+r5SfuSp5GPNHlYO8lWqys5NAPoDD4fc/kuflcK7Exx7XJ+Oqu0W0/
+psjEY/tES1ZgDWU/ParcxxFpFmKHbD5DXsfPOObzkVWXIY6tGMutSlE1Froy/Nn0
+OZsAOrcCAwEAAaOCAhMwggIPMIG4BggrBgEFBQcBAQSBqzCBqDBYBggrBgEFBQcw
+AoZMaHR0cDovL3d3dy5wa2kudnQuZWR1L2dsb2JhbHF1YWxpZmllZHNlcnZlci9j
+YWNlcnQvZ2xvYmFscXVhbGlmaWVkc2VydmVyLmNydDBMBggrBgEFBQcwAYZAaHR0
+cDovL3Z0Y2EtcC5lcHJvdi5zZXRpLnZ0LmVkdTo4MDgwL2VqYmNhL3B1YmxpY3dl
+Yi9zdGF0dXMvb2NzcDAdBgNVHQ4EFgQUp7xbO6iHkvtZbPE4jmndmnAbSEcwDAYD
+VR0TAQH/BAIwADAfBgNVHSMEGDAWgBS8YmAn1eM1SBfpS6tFatDIqHdxjDBqBgNV
+HSAEYzBhMA4GDCsGAQQBtGgFAgICATAOBgwrBgEEAbRoBQICAQEwPwYMKwYBBAG0
+aAUCAgMBMC8wLQYIKwYBBQUHAgEWIWh0dHA6Ly93d3cucGtpLnZ0LmVkdS9nbG9i
+YWwvY3BzLzBKBgNVHR8EQzBBMD+gPaA7hjlodHRwOi8vd3d3LnBraS52dC5lZHUv
+Z2xvYmFscXVhbGlmaWVkc2VydmVyL2NybC9jYWNybC5jcmwwDgYDVR0PAQH/BAQD
+AgTwMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAdBgNVHREEFjAUghJz
+ZWN1cmUuaWRkbC52dC5lZHUwDQYJKoZIhvcNAQEFBQADggIBAEgoYo4aUtatY3gI
+OyyKp7QlIOaLbTJZywESHqy+L5EGDdJW2DJV+mcE0LDGvqa2/1Lo+AR1ntsZwfOi
+Y718JwgVVaX/RCd5+QKP25c5/x72xI8hb/L1bgS0ED9b0YAhd7Qm1K1ot82+6mqX
+DW6WiGeDr8Z07MQ3143qQe2rBlq+QI69DYzm2GOqAIAnUIWv7tCyLUm31b4DwmrJ
+TeudVreTKUbBNB1TWRFHEPkWhjjXKZnNGRO11wHXcyBu6YekIvVZ+vmx8ePee4jJ
+3GFOi7lMuWOeq57jTVL7KOKaKLVXBb6gqo5aq+Wwt8RUD5MakrCAEeQZj7DKaFmZ
+oQCO0Pxrsl3InCGvxnGzT+bFVO9nJ/BAMj7hknFdm9Jr6Bg5q33Z+gnf909AD9QF
+ESqUSykaHu2LVdJx2MaCH1CyKnRgMw5tEwE15EXpUjCm24m8FMOYC+rNtf18pgrz
+5D8Jhh+oxK9PjcBYqXNtnioIxiMCYcV0q5d4w4BYFEh71tk7/bYB0R55CsBUVPmp
+timWNOdRd57Tfpk3USaVsumWZAf9MP3wPiC7gb4d5tYEEAG5BuDT8ruFw838wU8G
+1VvAVutSiYBg7k3NYO7AUqZ+Ax4klQX3aM9lgonmJ78Qt94UPtbptrfZ4/lSqEf8
+GBUwDrQNTb+gsXsDkjd5lcYxNx6l
+-----END CERTIFICATE-----`
+
+var nameConstraintsIntermediate1 = `-----BEGIN CERTIFICATE-----
+MIINLjCCDBagAwIBAgIRIqpyf/YoGgvHc8HiDAxAI8owDQYJKoZIhvcNAQEFBQAw
+XDELMAkGA1UEBhMCQkUxFTATBgNVBAsTDFRydXN0ZWQgUm9vdDEZMBcGA1UEChMQ
+R2xvYmFsU2lnbiBudi1zYTEbMBkGA1UEAxMSVHJ1c3RlZCBSb290IENBIEcyMB4X
+DTEyMTIxMzAwMDAwMFoXDTE3MTIxMzAwMDAwMFowgcsxCzAJBgNVBAYTAlVTMREw
+DwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVyZzEjMCEGA1UECxMa
+R2xvYmFsIFF1YWxpZmllZCBTZXJ2ZXIgQ0ExPDA6BgNVBAoTM1ZpcmdpbmlhIFBv
+bHl0ZWNobmljIEluc3RpdHV0ZSBhbmQgU3RhdGUgVW5pdmVyc2l0eTExMC8GA1UE
+AxMoVmlyZ2luaWEgVGVjaCBHbG9iYWwgUXVhbGlmaWVkIFNlcnZlciBDQTCCAiIw
+DQYJKoZIhvcNAQEBBQADggIPADCCAgoCggIBALgIZhEaptBWADBqdJ45ueFGzMXa
+GHnzNxoxR1fQIaaRQNdCg4cw3A4dWKMeEgYLtsp65ai3Xfw62Qaus0+KJ3RhgV+r
+ihqK81NUzkls78fJlADVDI4fCTlothsrE1CTOMiy97jKHai5mVTiWxmcxpmjv7fm
+5Nhc+uHgh2hIz6npryq495mD51ZrUTIaqAQN6Pw/VHfAmR524vgriTOjtp1t4lA9
+pXGWjF/vkhAKFFheOQSQ00rngo2wHgCqMla64UTN0oz70AsCYNZ3jDLx0kOP0YmM
+R3Ih91VA63kLqPXA0R6yxmmhhxLZ5bcyAy1SLjr1N302MIxLM/pSy6aquEnbELhz
+qyp9yGgRyGJay96QH7c4RJY6gtcoPDbldDcHI9nXngdAL4DrZkJ9OkDkJLyqG66W
+ZTF5q4EIs6yMdrywz0x7QP+OXPJrjYpbeFs6tGZCFnWPFfmHCRJF8/unofYrheq+
+9J7Jx3U55S/k57NXbAM1RAJOuMTlfn9Etf9Dpoac9poI4Liav6rBoUQk3N3JWqnV
+HNx/NdCyJ1/6UbKMJUZsStAVglsi6lVPo289HHOE4f7iwl3SyekizVOp01wUin3y
+cnbZB/rXmZbwapSxTTSBf0EIOr9i4EGfnnhCAVA9U5uLrI5OEB69IY8PNX0071s3
+Z2a2fio5c8m3JkdrAgMBAAGjggh5MIIIdTAOBgNVHQ8BAf8EBAMCAQYwTAYDVR0g
+BEUwQzBBBgkrBgEEAaAyATwwNDAyBggrBgEFBQcCARYmaHR0cHM6Ly93d3cuZ2xv
+YmFsc2lnbi5jb20vcmVwb3NpdG9yeS8wEgYDVR0TAQH/BAgwBgEB/wIBADCCBtAG
+A1UdHgSCBscwggbDoIIGvzASghAzZGJsYWNrc2J1cmcub3JnMBiCFmFjY2VsZXJh
+dGV2aXJnaW5pYS5jb20wGIIWYWNjZWxlcmF0ZXZpcmdpbmlhLm9yZzALgglhY3Zj
+cC5vcmcwCYIHYmV2Lm5ldDAJggdiZXYub3JnMAuCCWNsaWdzLm9yZzAMggpjbWl3
+ZWIub3JnMBeCFWVhc3Rlcm5icm9va3Ryb3V0Lm5ldDAXghVlYXN0ZXJuYnJvb2t0
+cm91dC5vcmcwEYIPZWNvcnJpZG9ycy5pbmZvMBOCEWVkZ2FycmVzZWFyY2gub3Jn
+MBKCEGdldC1lZHVjYXRlZC5jb20wE4IRZ2V0LWVkdWNhdGVkLmluZm8wEYIPZ2V0
+ZWR1Y2F0ZWQubmV0MBKCEGdldC1lZHVjYXRlZC5uZXQwEYIPZ2V0ZWR1Y2F0ZWQu
+b3JnMBKCEGdldC1lZHVjYXRlZC5vcmcwD4INaG9raWVjbHViLmNvbTAQgg5ob2tp
+ZXBob3RvLmNvbTAPgg1ob2tpZXNob3AuY29tMBGCD2hva2llc3BvcnRzLmNvbTAS
+ghBob2tpZXRpY2tldHMuY29tMBKCEGhvdGVscm9hbm9rZS5jb20wE4IRaHVtYW53
+aWxkbGlmZS5vcmcwF4IVaW5uYXR2aXJnaW5pYXRlY2guY29tMA+CDWlzY2hwMjAx
+MS5vcmcwD4INbGFuZHJlaGFiLm9yZzAggh5uYXRpb25hbHRpcmVyZXNlYXJjaGNl
+bnRlci5jb20wFYITbmV0d29ya3ZpcmdpbmlhLm5ldDAMggpwZHJjdnQuY29tMBiC
+FnBldGVkeWVyaXZlcmNvdXJzZS5jb20wDYILcmFkaW9pcS5vcmcwFYITcml2ZXJj
+b3Vyc2Vnb2xmLmNvbTALgglzZGltaS5vcmcwEIIOc292YW1vdGlvbi5jb20wHoIc
+c3VzdGFpbmFibGUtYmlvbWF0ZXJpYWxzLmNvbTAeghxzdXN0YWluYWJsZS1iaW9t
+YXRlcmlhbHMub3JnMBWCE3RoaXNpc3RoZWZ1dHVyZS5jb20wGIIWdGhpcy1pcy10
+aGUtZnV0dXJlLmNvbTAVghN0aGlzaXN0aGVmdXR1cmUubmV0MBiCFnRoaXMtaXMt
+dGhlLWZ1dHVyZS5uZXQwCoIIdmFkcy5vcmcwDIIKdmFsZWFmLm9yZzANggt2YXRl
+Y2guaW5mbzANggt2YXRlY2gubW9iaTAcghp2YXRlY2hsaWZlbG9uZ2xlYXJuaW5n
+LmNvbTAcghp2YXRlY2hsaWZlbG9uZ2xlYXJuaW5nLm5ldDAcghp2YXRlY2hsaWZl
+bG9uZ2xlYXJuaW5nLm9yZzAKggh2Y29tLmVkdTASghB2aXJnaW5pYXZpZXcubmV0
+MDSCMnZpcmdpbmlhcG9seXRlY2huaWNpbnN0aXR1dGVhbmRzdGF0ZXVuaXZlcnNp
+dHkuY29tMDWCM3ZpcmdpbmlhcG9seXRlY2huaWNpbnN0aXR1dGVhbmRzdGF0ZXVu
+aXZlcnNpdHkuaW5mbzA0gjJ2aXJnaW5pYXBvbHl0ZWNobmljaW5zdGl0dXRlYW5k
+c3RhdGV1bml2ZXJzaXR5Lm5ldDA0gjJ2aXJnaW5pYXBvbHl0ZWNobmljaW5zdGl0
+dXRlYW5kc3RhdGV1bml2ZXJzaXR5Lm9yZzAZghd2aXJnaW5pYXB1YmxpY3JhZGlv
+Lm9yZzASghB2aXJnaW5pYXRlY2guZWR1MBOCEXZpcmdpbmlhdGVjaC5tb2JpMByC
+GnZpcmdpbmlhdGVjaGZvdW5kYXRpb24ub3JnMAiCBnZ0LmVkdTALggl2dGFyYy5v
+cmcwDIIKdnQtYXJjLm9yZzALggl2dGNyYy5jb20wCoIIdnRpcC5vcmcwDIIKdnRs
+ZWFuLm9yZzAWghR2dGtub3dsZWRnZXdvcmtzLmNvbTAYghZ2dGxpZmVsb25nbGVh
+cm5pbmcuY29tMBiCFnZ0bGlmZWxvbmdsZWFybmluZy5uZXQwGIIWdnRsaWZlbG9u
+Z2xlYXJuaW5nLm9yZzATghF2dHNwb3J0c21lZGlhLmNvbTALggl2dHdlaS5jb20w
+D4INd2l3YXR3ZXJjLmNvbTAKggh3dnRmLm9yZzAIgQZ2dC5lZHUwd6R1MHMxCzAJ
+BgNVBAYTAlVTMREwDwYDVQQIEwhWaXJnaW5pYTETMBEGA1UEBxMKQmxhY2tzYnVy
+ZzE8MDoGA1UEChMzVmlyZ2luaWEgUG9seXRlY2huaWMgSW5zdGl0dXRlIGFuZCBT
+dGF0ZSBVbml2ZXJzaXR5MCcGA1UdJQQgMB4GCCsGAQUFBwMCBggrBgEFBQcDAQYI
+KwYBBQUHAwkwPQYDVR0fBDYwNDAyoDCgLoYsaHR0cDovL2NybC5nbG9iYWxzaWdu
+LmNvbS9ncy90cnVzdHJvb3RnMi5jcmwwgYQGCCsGAQUFBwEBBHgwdjAzBggrBgEF
+BQcwAYYnaHR0cDovL29jc3AyLmdsb2JhbHNpZ24uY29tL3RydXN0cm9vdGcyMD8G
+CCsGAQUFBzAChjNodHRwOi8vc2VjdXJlLmdsb2JhbHNpZ24uY29tL2NhY2VydC90
+cnVzdHJvb3RnMi5jcnQwHQYDVR0OBBYEFLxiYCfV4zVIF+lLq0Vq0Miod3GMMB8G
+A1UdIwQYMBaAFBT25YsxtkWASkxt/MKHico2w5BiMA0GCSqGSIb3DQEBBQUAA4IB
+AQAyJm/lOB2Er4tHXhc/+fSufSzgjohJgYfMkvG4LknkvnZ1BjliefR8tTXX49d2
+SCDFWfGjqyJZwavavkl/4p3oXPG/nAMDMvxh4YAT+CfEK9HH+6ICV087kD4BLegi
++aFJMj8MMdReWCzn5sLnSR1rdse2mo2arX3Uod14SW+PGrbUmTuWNyvRbz3fVmxp
+UdbGmj3laknO9YPsBGgHfv73pVVsTJkW4ZfY/7KdD/yaVv6ophpOB3coXfjl2+kd
+Z4ypn2zK+cx9IL/LSewqd/7W9cD55PCUy4X9OTbEmAccwiz3LB66mQoUGfdHdkoB
+jUY+v9vLQXmaVwI0AYL7g9LN
+-----END CERTIFICATE-----`
+
+var nameConstraintsIntermediate2 = `-----BEGIN CERTIFICATE-----
+MIIEXTCCA0WgAwIBAgILBAAAAAABNuk6OrMwDQYJKoZIhvcNAQEFBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw0xMjA0MjUxMTAw
+MDBaFw0yNzA0MjUxMTAwMDBaMFwxCzAJBgNVBAYTAkJFMRUwEwYDVQQLEwxUcnVz
+dGVkIFJvb3QxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExGzAZBgNVBAMTElRy
+dXN0ZWQgUm9vdCBDQSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEB
+AKyuvqrtcMr7g7EuNbu4sKwxM127UsCmx1RxbxxgcArGS7rjiefpBH/w4LYrymjf
+vcw1ueyMNoqLo9nJMz/ORXupb35NNfE667prQYHa+tTjl1IiKpB7QUwt3wXPuTMF
+Ja1tXtjKzkqJyuJlNuPKT76HcjgNqgV1s9qG44MD5I2JvI12du8zI1bgdQ+l/KsX
+kTfbGjUvhOLOlVNWVQDpL+YMIrGqgBYxy5TUNgrAcRtwpNdS2KkF5otSmMweVb5k
+hoUVv3u8UxQH/WWbNhHq1RrIlg/0rBUfi/ziShYFSB7U+aLx5DxPphTFBiDquQGp
+tB+FC4JvnukDStFihZCZ1R8CAwEAAaOCASMwggEfMA4GA1UdDwEB/wQEAwIBBjAP
+BgNVHRMBAf8EBTADAQH/MEcGA1UdIARAMD4wPAYEVR0gADA0MDIGCCsGAQUFBwIB
+FiZodHRwczovL3d3dy5nbG9iYWxzaWduLmNvbS9yZXBvc2l0b3J5LzAdBgNVHQ4E
+FgQUFPblizG2RYBKTG38woeJyjbDkGIwMwYDVR0fBCwwKjAooCagJIYiaHR0cDov
+L2NybC5nbG9iYWxzaWduLm5ldC9yb290LmNybDA+BggrBgEFBQcBAQQyMDAwLgYI
+KwYBBQUHMAGGImh0dHA6Ly9vY3NwMi5nbG9iYWxzaWduLmNvbS9yb290cjEwHwYD
+VR0jBBgwFoAUYHtmGkUNl8qJUC99BM00qP/8/UswDQYJKoZIhvcNAQEFBQADggEB
+AL7IG0l+k4LkcpI+a/kvZsSRwSM4uA6zGX34e78A2oytr8RG8bJwVb8+AHMUD+Xe
+2kYdh/Uj/waQXfqR0OgxQXL9Ct4ZM+JlR1avsNKXWL5AwYXAXCOB3J5PW2XOck7H
+Zw0vRbGQhjWjQx+B4KOUFg1b3ov/z6Xkr3yaCfRQhXh7KC0Bc0RXPPG5Nv5lCW+z
+tbbg0zMm3kyfQITRusMSg6IBsDJqOnjaiaKQRcXiD0Sk43ZXb2bUKMxC7+Td3QL4
+RyHcWJbQ7YylLTS/x+jxWIcOQ0oO5/54t5PTQ14neYhOz9x4gUk2AYAW6d1vePwb
+hcC8roQwkHT7HvfYBoc74FM=
+-----END CERTIFICATE-----`
+
+var globalSignRoot = `-----BEGIN CERTIFICATE-----
+MIIDdTCCAl2gAwIBAgILBAAAAAABFUtaw5QwDQYJKoZIhvcNAQEFBQAwVzELMAkG
+A1UEBhMCQkUxGTAXBgNVBAoTEEdsb2JhbFNpZ24gbnYtc2ExEDAOBgNVBAsTB1Jv
+b3QgQ0ExGzAZBgNVBAMTEkdsb2JhbFNpZ24gUm9vdCBDQTAeFw05ODA5MDExMjAw
+MDBaFw0yODAxMjgxMjAwMDBaMFcxCzAJBgNVBAYTAkJFMRkwFwYDVQQKExBHbG9i
+YWxTaWduIG52LXNhMRAwDgYDVQQLEwdSb290IENBMRswGQYDVQQDExJHbG9iYWxT
+aWduIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQDaDuaZ
+jc6j40+Kfvvxi4Mla+pIH/EqsLmVEQS98GPR4mdmzxzdzxtIK+6NiY6arymAZavp
+xy0Sy6scTHAHoT0KMM0VjU/43dSMUBUc71DuxC73/OlS8pF94G3VNTCOXkNz8kHp
+1Wrjsok6Vjk4bwY8iGlbKk3Fp1S4bInMm/k8yuX9ifUSPJJ4ltbcdG6TRGHRjcdG
+snUOhugZitVtbNV4FpWi6cgKOOvyJBNPc1STE4U6G7weNLWLBYy5d4ux2x8gkasJ
+U26Qzns3dLlwR5EiUWMWea6xrkEmCMgZK9FGqkjWZCrXgzT/LCrBbBlDSgeF59N8
+9iFo7+ryUp9/k5DPAgMBAAGjQjBAMA4GA1UdDwEB/wQEAwIBBjAPBgNVHRMBAf8E
+BTADAQH/MB0GA1UdDgQWBBRge2YaRQ2XyolQL30EzTSo//z9SzANBgkqhkiG9w0B
+AQUFAAOCAQEA1nPnfE920I2/7LqivjTFKDK1fPxsnCwrvQmeU79rXqoRSLblCKOz
+yj1hTdNGCbM+w6DjY1Ub8rrvrTnhQ7k4o+YviiY776BQVvnGCv04zcQLcFGUl5gE
+38NflNUVyRRBnMRddWQVDf9VMOyGj/8N7yy5Y0b2qvzfvGn9LhJIZJrglfCm7ymP
+AbEVtQwdpf5pLGkkeB6zpxxxYu7KyJesF12KwvhHhm4qxFYxldBniYUr+WymXUad
+DKqC5JlR3XC321Y9YeRq4VzW9v493kHMB65jUr9TU/Qr6cf9tveCX4XSQRjbgbME
+HMUfpIBvFSDJ3gyICh3WZlXi/EjJKSZp4A==
+-----END CERTIFICATE-----`
+
+const digicertRoot = `-----BEGIN CERTIFICATE-----
+MIIDrzCCApegAwIBAgIQCDvgVpBCRrGhdWrJWZHHSjANBgkqhkiG9w0BAQUFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
+QTAeFw0wNjExMTAwMDAwMDBaFw0zMTExMTAwMDAwMDBaMGExCzAJBgNVBAYTAlVT
+MRUwEwYDVQQKEwxEaWdpQ2VydCBJbmMxGTAXBgNVBAsTEHd3dy5kaWdpY2VydC5j
+b20xIDAeBgNVBAMTF0RpZ2lDZXJ0IEdsb2JhbCBSb290IENBMIIBIjANBgkqhkiG
+9w0BAQEFAAOCAQ8AMIIBCgKCAQEA4jvhEXLeqKTTo1eqUKKPC3eQyaKl7hLOllsB
+CSDMAZOnTjC3U/dDxGkAV53ijSLdhwZAAIEJzs4bg7/fzTtxRuLWZscFs3YnFo97
+nh6Vfe63SKMI2tavegw5BmV/Sl0fvBf4q77uKNd0f3p4mVmFaG5cIzJLv07A6Fpt
+43C/dxC//AH2hdmoRBBYMql1GNXRor5H4idq9Joz+EkIYIvUX7Q6hL+hqkpMfT7P
+T19sdl6gSzeRntwi5m3OFBqOasv+zbMUZBfHWymeMr/y7vrTC0LUq7dBMtoM1O/4
+gdW7jVg/tRvoSSiicNoxBN33shbyTApOB6jtSj1etX+jkMOvJwIDAQABo2MwYTAO
+BgNVHQ8BAf8EBAMCAYYwDwYDVR0TAQH/BAUwAwEB/zAdBgNVHQ4EFgQUA95QNVbR
+TLtm8KPiGxvDl7I90VUwHwYDVR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUw
+DQYJKoZIhvcNAQEFBQADggEBAMucN6pIExIK+t1EnE9SsPTfrgT1eXkIoyQY/Esr
+hMAtudXH/vTBH1jLuG2cenTnmCmrEbXjcKChzUyImZOMkXDiqw8cvpOp/2PV5Adg
+06O/nVsJ8dWO41P0jmP6P6fbtGbfYmbW0W5BjfIttep3Sp+dWOIrWcBAI+0tKIJF
+PnlUkiaY4IBIqDfv8NZ5YBberOgOzW6sRBc4L0na4UU+Krk2U886UAb3LujEV0ls
+YSEY1QSteDwsOoBrp+uvFRTp2InBuThs4pFsiv9kuXclVzDAGySj4dzp30d8tbQk
+CAUw7C29C79Fv1C5qfPrmAESrciIxpg0X40KPMbp1ZWVbd4=
+-----END CERTIFICATE-----`
+
+const trustAsiaSHA384Intermediate = `-----BEGIN CERTIFICATE-----
+MIID9zCCAt+gAwIBAgIQC965p4OR4AKrGlsyW0XrDzANBgkqhkiG9w0BAQwFADBh
+MQswCQYDVQQGEwJVUzEVMBMGA1UEChMMRGlnaUNlcnQgSW5jMRkwFwYDVQQLExB3
+d3cuZGlnaWNlcnQuY29tMSAwHgYDVQQDExdEaWdpQ2VydCBHbG9iYWwgUm9vdCBD
+QTAeFw0xODA0MjcxMjQyNTlaFw0yODA0MjcxMjQyNTlaMFoxCzAJBgNVBAYTAkNO
+MSUwIwYDVQQKExxUcnVzdEFzaWEgVGVjaG5vbG9naWVzLCBJbmMuMSQwIgYDVQQD
+ExtUcnVzdEFzaWEgRUNDIE9WIFRMUyBQcm8gQ0EwdjAQBgcqhkjOPQIBBgUrgQQA
+IgNiAAQPIUn75M5BCQLKoPsSU2KTr3mDMh13usnAQ38XfKOzjXiyQ+W0inA7meYR
+xS+XMQgvnbCigEsKj3ErPIzO68uC9V/KdqMaXWBJp85Ws9A4KL92NB4Okbn5dp6v
+Qzy08PajggFeMIIBWjAdBgNVHQ4EFgQULdRyBx6HyIH/+LOvuexyH5p/3PwwHwYD
+VR0jBBgwFoAUA95QNVbRTLtm8KPiGxvDl7I90VUwDgYDVR0PAQH/BAQDAgGGMB0G
+A1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjASBgNVHRMBAf8ECDAGAQH/AgEA
+MDcGCCsGAQUFBwEBBCswKTAnBggrBgEFBQcwAYYbaHR0cDovL29jc3AuZGlnaWNl
+cnQtY24uY29tMEQGA1UdHwQ9MDswOaA3oDWGM2h0dHA6Ly9jcmwuZGlnaWNlcnQt
+Y24uY29tL0RpZ2lDZXJ0R2xvYmFsUm9vdENBLmNybDBWBgNVHSAETzBNMDcGCWCG
+SAGG/WwBATAqMCgGCCsGAQUFBwIBFhxodHRwczovL3d3dy5kaWdpY2VydC5jb20v
+Q1BTMAgGBmeBDAECAjAIBgZngQwBAgMwDQYJKoZIhvcNAQEMBQADggEBACVRufYd
+j81xUqngFCO+Pk8EYXie0pxHKsBZnOPygAyXKx+awUasKBAnHjmhoFPXaDGAP2oV
+OeZTWgwnURVr6wUCuTkz2/8Tgl1egC7OrVcHSa0fIIhaVo9/zRA/hr31xMG7LFBk
+GNd7jd06Up4f/UOGbcJsqJexc5QRcUeSwe1MiUDcTNiyCjZk74QCPdcfdFYM4xsa
+SlUpboB5vyT7jFePZ2v95CKjcr0EhiQ0gwxpdgoipZdfYTiMFGxCLsk6v8pUv7Tq
+PT/qadOGyC+PfLuZh1PtLp20mF06K+MzheCiv+w1NT5ofhmcObvukc68wvbvRFL6
+rRzZxAYN36q1SX8=
+-----END CERTIFICATE-----`
+
+const trustAsiaLeaf = `-----BEGIN CERTIFICATE-----
+MIIEwTCCBEegAwIBAgIQBOjomZfHfhgz2bVYZVuf2DAKBggqhkjOPQQDAzBaMQsw
+CQYDVQQGEwJDTjElMCMGA1UEChMcVHJ1c3RBc2lhIFRlY2hub2xvZ2llcywgSW5j
+LjEkMCIGA1UEAxMbVHJ1c3RBc2lhIEVDQyBPViBUTFMgUHJvIENBMB4XDTE5MDUx
+NzAwMDAwMFoXDTIwMDcyODEyMDAwMFowgY0xCzAJBgNVBAYTAkNOMRIwEAYDVQQI
+DAnnpo/lu7rnnIExEjAQBgNVBAcMCeWOpumXqOW4gjEqMCgGA1UECgwh5Y6m6Zeo
+5Y+B546W5Y+B56eR5oqA5pyJ6ZmQ5YWs5Y+4MRgwFgYDVQQLDA/nn6Xor4bkuqfm
+nYPpg6gxEDAOBgNVBAMMByoudG0uY24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNC
+AARx/MDQ0oGnCLagQIzjIz57iqFYFmz4/W6gaU6N+GHBkzyvQU8aX02QkdlTTNYL
+TCoGFJxHB0XlZVSxrqoIPlNKo4ICuTCCArUwHwYDVR0jBBgwFoAULdRyBx6HyIH/
++LOvuexyH5p/3PwwHQYDVR0OBBYEFGTyf5adc5smW8NvDZyummJwZRLEMBkGA1Ud
+EQQSMBCCByoudG0uY26CBXRtLmNuMA4GA1UdDwEB/wQEAwIHgDAdBgNVHSUEFjAU
+BggrBgEFBQcDAQYIKwYBBQUHAwIwRgYDVR0fBD8wPTA7oDmgN4Y1aHR0cDovL2Ny
+bC5kaWdpY2VydC1jbi5jb20vVHJ1c3RBc2lhRUNDT1ZUTFNQcm9DQS5jcmwwTAYD
+VR0gBEUwQzA3BglghkgBhv1sAQEwKjAoBggrBgEFBQcCARYcaHR0cHM6Ly93d3cu
+ZGlnaWNlcnQuY29tL0NQUzAIBgZngQwBAgIwfgYIKwYBBQUHAQEEcjBwMCcGCCsG
+AQUFBzABhhtodHRwOi8vb2NzcC5kaWdpY2VydC1jbi5jb20wRQYIKwYBBQUHMAKG
+OWh0dHA6Ly9jYWNlcnRzLmRpZ2ljZXJ0LWNuLmNvbS9UcnVzdEFzaWFFQ0NPVlRM
+U1Byb0NBLmNydDAMBgNVHRMBAf8EAjAAMIIBAwYKKwYBBAHWeQIEAgSB9ASB8QDv
+AHUA7ku9t3XOYLrhQmkfq+GeZqMPfl+wctiDAMR7iXqo/csAAAFqxGMTnwAABAMA
+RjBEAiAz13zKEoyqd4e/96SK/fxfjl7uR+xhfoDZeyA1BvtfOwIgTY+8nJMGekv8
+leIVdW6AGh7oqH31CIGTAbNJJWzaSFYAdgCHdb/nWXz4jEOZX73zbv9WjUdWNv9K
+tWDBtOr/XqCDDwAAAWrEYxTCAAAEAwBHMEUCIQDlWm7+limbRiurcqUwXav3NSmx
+x/aMnolLbh6+f+b1XAIgQfinHwLw6pDr4R9UkndUsX8QFF4GXS3/IwRR8HCp+pIw
+CgYIKoZIzj0EAwMDaAAwZQIwHg8JmjRtcq+OgV0vVmdVBPqehi1sQJ9PZ+51CG+Z
+0GOu+2HwS/fyLRViwSc/MZoVAjEA7NgbgpPN4OIsZn2XjMGxemtVxGFS6ZR+1364
+EEeHB9vhZAEjQSePAfjR9aAGhXRa
+-----END CERTIFICATE-----`
+
+const selfSigned = `-----BEGIN CERTIFICATE-----
+MIIC/DCCAeSgAwIBAgIRAK0SWRVmi67xU3z0gkgY+PkwDQYJKoZIhvcNAQELBQAw
+EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNjA4MTkxNjMzNDdaFw0xNzA4MTkxNjMz
+NDdaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDWkm1kdCwxyKEt6OTmZitkmLGH8cQu9z7rUdrhW8lWNm4kh2SuaUWP
+pscBjda5iqg51aoKuWJR2rw6ElDne+X5eit2FT8zJgAU8v39lMFjbaVZfS9TFOYF
+w0Tk0Luo/PyKJpZnwhsP++iiGQiteJbndy8aLKmJ2MpLfpDGIgxEIyNb5dgoDi0D
+WReDCpE6K9WDYqvKVGnQ2Jvqqra6Gfx0tFkuqJxQuqA8aUOlPHcCH4KBZdNEoXdY
+YL3E4dCAh0YiDs80wNZx4cHqEM3L8gTEFqW2Tn1TSuPZO6gjJ9QPsuUZVjaMZuuO
+NVxqLGujZkDzARhC3fBpptMuaAfi20+BAgMBAAGjTTBLMA4GA1UdDwEB/wQEAwIF
+oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBYGA1UdEQQPMA2C
+C2Zvby5leGFtcGxlMA0GCSqGSIb3DQEBCwUAA4IBAQBPvvfnDhsHWt+/cfwdAVim
+4EDn+hYOMkTQwU0pouYIvY8QXYkZ8MBxpBtBMK4JhFU+ewSWoBAEH2dCCvx/BDxN
+UGTSJHMbsvJHcFvdmsvvRxOqQ/cJz7behx0cfoeHMwcs0/vWv8ms5wHesb5Ek7L0
+pl01FCBGTcncVqr6RK1r4fTpeCCfRIERD+YRJz8TtPH6ydesfLL8jIV40H8NiDfG
+vRAvOtNiKtPzFeQVdbRPOskC4rcHyPeiDAMAMixeLi63+CFty4da3r5lRezeedCE
+cw3ESZzThBwWqvPOtJdpXdm+r57pDW8qD+/0lY8wfImMNkQAyCUCLg/1Lxt/hrBj
+-----END CERTIFICATE-----`
+
+const issuerSubjectMatchRoot = `-----BEGIN CERTIFICATE-----
+MIICIDCCAYmgAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwIzEPMA0GA1UE
+ChMGR29sYW5nMRAwDgYDVQQDEwdSb290IGNhMB4XDTE1MDEwMTAwMDAwMFoXDTI1
+MDEwMTAwMDAwMFowIzEPMA0GA1UEChMGR29sYW5nMRAwDgYDVQQDEwdSb290IGNh
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpDn8RDOZa5oaDcPZRBy4CeBH1
+siSSOO4mYgLHlPE+oXdqwI/VImi2XeJM2uCFETXCknJJjYG0iJdrt/yyRFvZTQZw
++QzGj+mz36NqhGxDWb6dstB2m8PX+plZw7jl81MDvUnWs8yiQ/6twgu5AbhWKZQD
+JKcNKCEpqa6UW0r5nwIDAQABo10wWzAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYw
+FAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIE
+EEA31wH7QC+4HH5UBCeMWQEwDQYJKoZIhvcNAQELBQADgYEAb4TfSeCZ1HFmHTKG
+VsvqWmsOAGrRWm4fBiMH/8vRGnTkJEMLqiqgc3Ulgry/P6n4SIis7TqUOw3TiMhn
+RGEz33Fsxa/tFoy/gvlJu+MqB1M2NyV33pGkdwl/b7KRWMQFieqO+uE7Ge/49pS3
+eyfm5ITdK/WT9TzYhsU4AVZcn20=
+-----END CERTIFICATE-----`
+
+const issuerSubjectMatchLeaf = `-----BEGIN CERTIFICATE-----
+MIICODCCAaGgAwIBAgIJAOjwnT/iW+qmMA0GCSqGSIb3DQEBCwUAMCMxDzANBgNV
+BAoTBkdvbGFuZzEQMA4GA1UEAxMHUm9vdCBDQTAeFw0xNTAxMDEwMDAwMDBaFw0y
+NTAxMDEwMDAwMDBaMCAxDzANBgNVBAoTBkdvbGFuZzENMAsGA1UEAxMETGVhZjCB
+nzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA20Z9ky4SJwZIvAYoIat+xLaiXf4e
+UkWIejZHpQgNkkJbwoHAvpd5mED7T20U/SsTi8KlLmfY1Ame1iI4t0oLdHMrwjTx
+0ZPlltl0e/NYn2xhPMCwQdTZKyskI3dbHDu9dV3OIFTPoWOHHR4kxPMdGlCLqrYU
+Q+2Xp3Vi9BTIUtcCAwEAAaN3MHUwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQG
+CCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBCfkRYf
+Q0M+SabebbaA159gMBsGA1UdIwQUMBKAEEA31wH7QC+4HH5UBCeMWQEwDQYJKoZI
+hvcNAQELBQADgYEAjYYF2on1HcUWFEG5NIcrXDiZ49laW3pb3gtcCEUJbxydMV8I
+ynqjmdqDCyK+TwI1kU5dXDe/iSJYfTB20i/QoO53nnfA1hnr7KBjNWqAm4AagN5k
+vEA4PCJprUYmoj3q9MKSSRYDlq5kIbl87mSRR4GqtAwJKxIasvOvULOxziQ=
+-----END CERTIFICATE-----`
+
+const x509v1TestRoot = `-----BEGIN CERTIFICATE-----
+MIICIDCCAYmgAwIBAgIIAj5CwoHlWuYwDQYJKoZIhvcNAQELBQAwIzEPMA0GA1UE
+ChMGR29sYW5nMRAwDgYDVQQDEwdSb290IENBMB4XDTE1MDEwMTAwMDAwMFoXDTI1
+MDEwMTAwMDAwMFowIzEPMA0GA1UEChMGR29sYW5nMRAwDgYDVQQDEwdSb290IENB
+MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDpDn8RDOZa5oaDcPZRBy4CeBH1
+siSSOO4mYgLHlPE+oXdqwI/VImi2XeJM2uCFETXCknJJjYG0iJdrt/yyRFvZTQZw
++QzGj+mz36NqhGxDWb6dstB2m8PX+plZw7jl81MDvUnWs8yiQ/6twgu5AbhWKZQD
+JKcNKCEpqa6UW0r5nwIDAQABo10wWzAOBgNVHQ8BAf8EBAMCAgQwHQYDVR0lBBYw
+FAYIKwYBBQUHAwEGCCsGAQUFBwMCMA8GA1UdEwEB/wQFMAMBAf8wGQYDVR0OBBIE
+EEA31wH7QC+4HH5UBCeMWQEwDQYJKoZIhvcNAQELBQADgYEAcIwqeNUpQr9cOcYm
+YjpGpYkQ6b248xijCK7zI+lOeWN89zfSXn1AvfsC9pSdTMeDklWktbF/Ad0IN8Md
+h2NtN34ard0hEfHc8qW8mkXdsysVmq6cPvFYaHz+dBtkHuHDoy8YQnC0zdN/WyYB
+/1JmacUUofl+HusHuLkDxmadogI=
+-----END CERTIFICATE-----`
+
+const x509v1TestIntermediate = `-----BEGIN CERTIFICATE-----
+MIIByjCCATMCCQCCdEMsT8ykqTANBgkqhkiG9w0BAQsFADAjMQ8wDQYDVQQKEwZH
+b2xhbmcxEDAOBgNVBAMTB1Jvb3QgQ0EwHhcNMTUwMTAxMDAwMDAwWhcNMjUwMTAx
+MDAwMDAwWjAwMQ8wDQYDVQQKEwZHb2xhbmcxHTAbBgNVBAMTFFguNTA5djEgaW50
+ZXJtZWRpYXRlMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQDJ2QyniAOT+5YL
+jeinEBJr3NsC/Q2QJ/VKmgvp+xRxuKTHJiVmxVijmp0vWg8AWfkmuE4p3hXQbbqM
+k5yxrk1n60ONhim2L4VXriEvCE7X2OXhTmBls5Ufr7aqIgPMikwjScCXwz8E8qI8
+UxyAhnjeJwMYBU8TuwBImSd4LBHoQQIDAQABMA0GCSqGSIb3DQEBCwUAA4GBAIab
+DRG6FbF9kL9jb/TDHkbVBk+sl/Pxi4/XjuFyIALlARgAkeZcPmL5tNW1ImHkwsHR
+zWE77kJDibzd141u21ZbLsKvEdUJXjla43bdyMmEqf5VGpC3D4sFt3QVH7lGeRur
+x5Wlq1u3YDL/j6s1nU2dQ3ySB/oP7J+vQ9V4QeM+
+-----END CERTIFICATE-----`
+
+const x509v1TestLeaf = `-----BEGIN CERTIFICATE-----
+MIICMzCCAZygAwIBAgIJAPo99mqJJrpJMA0GCSqGSIb3DQEBCwUAMDAxDzANBgNV
+BAoTBkdvbGFuZzEdMBsGA1UEAxMUWC41MDl2MSBpbnRlcm1lZGlhdGUwHhcNMTUw
+MTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjArMQ8wDQYDVQQKEwZHb2xhbmcxGDAW
+BgNVBAMTD2Zvby5leGFtcGxlLmNvbTCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkC
+gYEApUh60Z+a5/oKJxG//Dn8CihSo2CJHNIIO3zEJZ1EeNSMZCynaIR6D3IPZEIR
++RG2oGt+f5EEukAPYxwasp6VeZEezoQWJ+97nPCT6DpwLlWp3i2MF8piK2R9vxkG
+Z5n0+HzYk1VM8epIrZFUXSMGTX8w1y041PX/yYLxbdEifdcCAwEAAaNaMFgwDgYD
+VR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNV
+HRMBAf8EAjAAMBkGA1UdDgQSBBBFozXe0SnzAmjy+1U6M/cvMA0GCSqGSIb3DQEB
+CwUAA4GBADYzYUvaToO/ucBskPdqXV16AaakIhhSENswYVSl97/sODaxsjishKq9
+5R7siu+JnIFotA7IbBe633p75xEnLN88X626N/XRFG9iScLzpj0o0PWXBUiB+fxL
+/jt8qszOXCv2vYdUTPNuPqufXLWMoirpuXrr1liJDmedCcAHepY/
+-----END CERTIFICATE-----`
+
+const ignoreCNWithSANRoot = `-----BEGIN CERTIFICATE-----
+MIIDPzCCAiegAwIBAgIIJkzCwkNrPHMwDQYJKoZIhvcNAQELBQAwMDEQMA4GA1UE
+ChMHVEVTVElORzEcMBoGA1UEAxMTKipUZXN0aW5nKiogUm9vdCBDQTAeFw0xNTAx
+MDEwMDAwMDBaFw0yNTAxMDEwMDAwMDBaMDAxEDAOBgNVBAoTB1RFU1RJTkcxHDAa
+BgNVBAMTEyoqVGVzdGluZyoqIFJvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IB
+DwAwggEKAoIBAQC4YAf5YqlXGcikvbMWtVrNICt+V/NNWljwfvSKdg4Inm7k6BwW
+P6y4Y+n4qSYIWNU4iRkdpajufzctxQCO6ty13iw3qVktzcC5XBIiS6ymiRhhDgnY
+VQqyakVGw9MxrPwdRZVlssUv3Hmy6tU+v5Ok31SLY5z3wKgYWvSyYs0b8bKNU8kf
+2FmSHnBN16lxGdjhe3ji58F/zFMr0ds+HakrLIvVdFcQFAnQopM8FTHpoWNNzGU3
+KaiO0jBbMFkd6uVjVnuRJ+xjuiqi/NWwiwQA+CEr9HKzGkxOF8nAsHamdmO1wW+w
+OsCrC0qWQ/f5NTOVATTJe0vj88OMTvo3071VAgMBAAGjXTBbMA4GA1UdDwEB/wQE
+AwICpDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUw
+AwEB/zAZBgNVHQ4EEgQQQDfXAftAL7gcflQEJ4xZATANBgkqhkiG9w0BAQsFAAOC
+AQEAGOn3XjxHyHbXLKrRmpwV447B7iNBXR5VlhwOgt1kWaHDL2+8f/9/h0HMkB6j
+fC+/yyuYVqYuOeavqMGVrh33D2ODuTQcFlOx5lXukP46j3j+Lm0jjZ1qNX7vlP8I
+VlUXERhbelkw8O4oikakwIY9GE8syuSgYf+VeBW/lvuAZQrdnPfabxe05Tre6RXy
+nJHMB1q07YHpbwIkcV/lfCE9pig2nPXTLwYZz9cl46Ul5RCpPUi+IKURo3x8y0FU
+aSLjI/Ya0zwUARMmyZ3RRGCyhIarPb20mKSaMf1/Nb23pS3k1QgmZhk5pAnXYsWu
+BJ6bvwEAasFiLGP6Zbdmxb2hIA==
+-----END CERTIFICATE-----`
+
+const ignoreCNWithSANLeaf = `-----BEGIN CERTIFICATE-----
+MIIDaTCCAlGgAwIBAgIJAONakvRTxgJhMA0GCSqGSIb3DQEBCwUAMDAxEDAOBgNV
+BAoTB1RFU1RJTkcxHDAaBgNVBAMTEyoqVGVzdGluZyoqIFJvb3QgQ0EwHhcNMTUw
+MTAxMDAwMDAwWhcNMjUwMTAxMDAwMDAwWjAsMRAwDgYDVQQKEwdURVNUSU5HMRgw
+FgYDVQQDEw9mb28uZXhhbXBsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDBqskp89V/JMIBBqcauKSOVLcMyIE/t0jgSWVrsI4sksBTabLsfMdS
+ui2n+dHQ1dRBuw3o4g4fPrWwS3nMnV3pZUHEn2TPi5N1xkjTaxObXgKIY2GKmFP3
+rJ9vYqHT6mT4K93kCHoRcmJWWySc7S3JAOhTcdB4G+tIdQJN63E+XRYQQfNrn5HZ
+hxQoOzaguHFx+ZGSD4Ntk6BSZz5NfjqCYqYxe+iCpTpEEYhIpi8joSPSmkTMTxBW
+S1W2gXbYNQ9KjNkGM6FnQsUJrSPMrWs4v3UB/U88N5LkZeF41SqD9ySFGwbGajFV
+nyzj12+4K4D8BLhlOc0Eo/F/8GwOwvmxAgMBAAGjgYkwgYYwDgYDVR0PAQH/BAQD
+AgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAMBgNVHRMBAf8EAjAA
+MBkGA1UdDgQSBBCjeab27q+5pV43jBGANOJ1MBsGA1UdIwQUMBKAEEA31wH7QC+4
+HH5UBCeMWQEwDwYDVR0RBAgwBocEfwAAATANBgkqhkiG9w0BAQsFAAOCAQEAGZfZ
+ErTVxxpIg64s22mQpXSk/72THVQsfsKHzlXmztM0CJzH8ccoN67ZqKxJCfdiE/FI
+Emb6BVV4cGPeIKpcxaM2dwX/Y+Y0JaxpQJvqLxs+EByRL0gPP3shgg86WWCjYLxv
+AgOn862d/JXGDrC9vIlQ/DDQcyL5g0JV5UjG2G9TUigbnrXxBw7BoWK6wmoSaHnR
+sZKEHSs3RUJvm7qqpA9Yfzm9jg+i9j32zh1xFacghAOmFRFXa9eCVeigZ/KK2mEY
+j2kBQyvnyKsXHLAKUoUOpd6t/1PHrfXnGj+HmzZNloJ/BZ1kiWb4eLvMljoLGkZn
+xZbqP3Krgjj4XNaXjg==
+-----END CERTIFICATE-----`
+
+const excludedNamesLeaf = `-----BEGIN CERTIFICATE-----
+MIID4DCCAsigAwIBAgIHDUSFtJknhzANBgkqhkiG9w0BAQsFADCBnjELMAkGA1UE
+BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU
+MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5
+ICgzNzM0NTE1NTYyODA2Mzk3KTEhMB8GA1UEAwwYSW50ZXJtZWRpYXRlIENBIGZv
+ciAzMzkyMB4XDTE3MDIwODIxMTUwNFoXDTE4MDIwODIwMjQ1OFowgZAxCzAJBgNV
+BAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRIwEAYDVQQHDAlMb3MgR2F0b3Mx
+FDASBgNVBAoMC05ldGZsaXggSW5jMS0wKwYDVQQLDCRQbGF0Zm9ybSBTZWN1cml0
+eSAoMzczNDUxNTc0ODUwMjY5NikxEzARBgNVBAMMCjE3Mi4xNi4wLjEwggEiMA0G
+CSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCZ0oP1bMv6bOeqcKbzinnGpNOpenhA
+zdFFsgea62znWsH3Wg4+1Md8uPCqlaQIsaJQKZHc50eKD3bg0Io7c6kxHkBQr1b8
+Q7cGeK3CjdqG3NwS/aizzrLKOwL693hFwwy7JY7GGCvogbhyQRKn6iV0U9zMm7bu
+/9pQVV/wx8u01u2uAlLttjyQ5LJkxo5t8cATFVqxdN5J9eY//VSDiTwXnlpQITBP
+/Ow+zYuZ3kFlzH3CtCOhOEvNG3Ar1NvP3Icq35PlHV+Eki4otnKfixwByoiGpqCB
+UEIY04VrZJjwBxk08y/3jY2B3VLYGgi+rryyCxIqkB7UpSNPMMWSG4UpAgMBAAGj
+LzAtMAwGA1UdEwEB/wQCMAAwHQYDVR0RBBYwFIIMYmVuZGVyLmxvY2FshwSsEAAB
+MA0GCSqGSIb3DQEBCwUAA4IBAQCLW3JO8L7LKByjzj2RciPjCGH5XF87Wd20gYLq
+sNKcFwCIeyZhnQy5aZ164a5G9AIk2HLvH6HevBFPhA9Ivmyv/wYEfnPd1VcFkpgP
+hDt8MCFJ8eSjCyKdtZh1MPMLrLVymmJV+Rc9JUUYM9TIeERkpl0rskcO1YGewkYt
+qKlWE+0S16+pzsWvKn831uylqwIb8ANBPsCX4aM4muFBHavSWAHgRO+P+yXVw8Q+
+VQDnMHUe5PbZd1/+1KKVs1K/CkBCtoHNHp1d/JT+2zUQJphwja9CcgfFdVhSnHL4
+oEEOFtqVMIuQfR2isi08qW/JGOHc4sFoLYB8hvdaxKWSE19A
+-----END CERTIFICATE-----`
+
+const excludedNamesIntermediate = `-----BEGIN CERTIFICATE-----
+MIIDzTCCArWgAwIBAgIHDUSFqYeczDANBgkqhkiG9w0BAQsFADCBmTELMAkGA1UE
+BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU
+MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5
+ICgzNzM0NTE1NDc5MDY0NjAyKTEcMBoGA1UEAwwTTG9jYWwgUm9vdCBmb3IgMzM5
+MjAeFw0xNzAyMDgyMTE1MDRaFw0xODAyMDgyMDI0NThaMIGeMQswCQYDVQQGEwJV
+UzETMBEGA1UECAwKQ2FsaWZvcm5pYTESMBAGA1UEBwwJTG9zIEdhdG9zMRQwEgYD
+VQQKDAtOZXRmbGl4IEluYzEtMCsGA1UECwwkUGxhdGZvcm0gU2VjdXJpdHkgKDM3
+MzQ1MTU1NjI4MDYzOTcpMSEwHwYDVQQDDBhJbnRlcm1lZGlhdGUgQ0EgZm9yIDMz
+OTIwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQCOyEs6tJ/t9emQTvlx
+3FS7uJSou5rKkuqVxZdIuYQ+B2ZviBYUnMRT9bXDB0nsVdKZdp0hdchdiwNXDG/I
+CiWu48jkcv/BdynVyayOT+0pOJSYLaPYpzBx1Pb9M5651ct9GSbj6Tz0ChVonoIE
+1AIZ0kkebucZRRFHd0xbAKVRKyUzPN6HJ7WfgyauUp7RmlC35wTmrmARrFohQLlL
+7oICy+hIQePMy9x1LSFTbPxZ5AUUXVC3eUACU3vLClF/Xs8XGHebZpUXCdMQjOGS
+nq1eFguFHR1poSB8uSmmLqm4vqUH9CDhEgiBAC8yekJ8//kZQ7lUEqZj3YxVbk+Y
+E4H5AgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8wDQYJKoZIhvcNAQELBQADggEB
+ADxrnmNX5gWChgX9K5fYwhFDj5ofxZXAKVQk+WjmkwMcmCx3dtWSm++Wdksj/ZlA
+V1cLW3ohWv1/OAZuOlw7sLf98aJpX+UUmIYYQxDubq+4/q7VA7HzEf2k/i/oN1NI
+JgtrhpPcZ/LMO6k7DYx0qlfYq8pTSfd6MI4LnWKgLc+JSPJJjmvspgio2ZFcnYr7
+A264BwLo6v1Mos1o1JUvFFcp4GANlw0XFiWh7JXYRl8WmS5DoouUC+aNJ3lmyF6z
+LbIjZCSfgZnk/LK1KU1j91FI2bc2ULYZvAC1PAg8/zvIgxn6YM2Q7ZsdEgWw0FpS
+zMBX1/lk4wkFckeUIlkD55Y=
+-----END CERTIFICATE-----`
+
+const excludedNamesRoot = `-----BEGIN CERTIFICATE-----
+MIIEGTCCAwGgAwIBAgIHDUSFpInn/zANBgkqhkiG9w0BAQsFADCBozELMAkGA1UE
+BhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBHYXRvczEU
+MBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNlY3VyaXR5
+ICgzNzMxNTA5NDM3NDYyNDg1KTEmMCQGA1UEAwwdTmFtZSBDb25zdHJhaW50cyBU
+ZXN0IFJvb3QgQ0EwHhcNMTcwMjA4MjExNTA0WhcNMTgwMjA4MjAyNDU4WjCBmTEL
+MAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExEjAQBgNVBAcMCUxvcyBH
+YXRvczEUMBIGA1UECgwLTmV0ZmxpeCBJbmMxLTArBgNVBAsMJFBsYXRmb3JtIFNl
+Y3VyaXR5ICgzNzM0NTE1NDc5MDY0NjAyKTEcMBoGA1UEAwwTTG9jYWwgUm9vdCBm
+b3IgMzM5MjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAJymcnX29ekc
+7+MLyr8QuAzoHWznmGdDd2sITwWRjM89/21cdlHCGKSpULUNdFp9HDLWvYECtxt+
+8TuzKiQz7qAerzGUT1zI5McIjHy0e/i4xIkfiBiNeTCuB/N9QRbZlcfM80ErkaA4
+gCAFK8qZAcWkHIl6e+KaQFMPLKk9kckgAnVDHEJe8oLNCogCJ15558b65g05p9eb
+5Lg+E98hoPRTQaDwlz3CZPfTTA2EiEZInSi8qzodFCbTpJUVTbiVUH/JtVjlibbb
+smdcx5PORK+8ZJkhLEh54AjaWOX4tB/7Tkk8stg2VBmrIARt/j4UVj7cTrIWU3bV
+m8TwHJG+YgsCAwEAAaNaMFgwDwYDVR0TAQH/BAUwAwEB/zBFBgNVHR4EPjA8oBww
+CocICgEAAP//AAAwDoIMYmVuZGVyLmxvY2FsoRwwCocICgEAAP//AAAwDoIMYmVu
+ZGVyLmxvY2FsMA0GCSqGSIb3DQEBCwUAA4IBAQAMjbheffPxtSKSv9NySW+8qmHs
+n7Mb5GGyCFu+cMZSoSaabstbml+zHEFJvWz6/1E95K4F8jKhAcu/CwDf4IZrSD2+
+Hee0DolVSQhZpnHgPyj7ZATz48e3aJaQPUlhCEOh0wwF4Y0N4FV0t7R6woLylYRZ
+yU1yRHUqUYpN0DWFpsPbBqgM6uUAVO2ayBFhPgWUaqkmSbZ/Nq7isGvknaTmcIwT
+6mOAFN0qFb4RGzfGJW7x6z7KCULS7qVDp6fU3tRoScHFEgRubks6jzQ1W5ooSm4o
++NQCZDd5eFeU8PpNX7rgaYE4GPq+EEmLVCBYmdctr8QVdqJ//8Xu3+1phjDy
+-----END CERTIFICATE-----`
+
+const invalidCNRoot = `-----BEGIN CERTIFICATE-----
+MIIBFjCBvgIJAIsu4r+jb70UMAoGCCqGSM49BAMCMBQxEjAQBgNVBAsMCVRlc3Qg
+cm9vdDAeFw0xODA3MTExODMyMzVaFw0yODA3MDgxODMyMzVaMBQxEjAQBgNVBAsM
+CVRlc3Qgcm9vdDBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF6oDgMg0LV6YhPj
+QXaPXYCc2cIyCdqp0ROUksRz0pOLTc5iY2nraUheRUD1vRRneq7GeXOVNn7uXONg
+oCGMjNwwCgYIKoZIzj0EAwIDRwAwRAIgDSiwgIn8g1lpruYH0QD1GYeoWVunfmrI
+XzZZl0eW/ugCICgOfXeZ2GGy3wIC0352BaC3a8r5AAb2XSGNe+e9wNN6
+-----END CERTIFICATE-----`
+
+const validCNWithoutSAN = `-----BEGIN CERTIFICATE-----
+MIIBJzCBzwIUB7q8t9mrDAL+UB1OFaMN5BEWFKQwCgYIKoZIzj0EAwIwFDESMBAG
+A1UECwwJVGVzdCByb290MB4XDTE4MDcxMTE4NDcyNFoXDTI4MDcwODE4NDcyNFow
+GjEYMBYGA1UEAwwPZm9vLmV4YW1wbGUuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0D
+AQcDQgAEp6Z8IjOnR38Iky1fYTUu2kVndvKXcxiwARJKGtW3b0E8uwVp9AZd/+sr
+p4ULTPdFToFAeqnGHbu62bkms8pQkDAKBggqhkjOPQQDAgNHADBEAiBTbNe3WWFR
+cqUYo0sNUuoV+tCTMDJUS+0PWIW4qBqCOwIgFHdLDn5PCk9kJpfc0O2qZx03hdq0
+h7olHCpY9yMRiz0=
+-----END CERTIFICATE-----`
+
+const rootWithoutSKID = `-----BEGIN CERTIFICATE-----
+MIIBbzCCARSgAwIBAgIQeCkq3C8SOX/JM5PqYTl9cDAKBggqhkjOPQQDAjASMRAw
+DgYDVQQKEwdBY21lIENvMB4XDTE5MDIwNDIyNTYzNFoXDTI5MDIwMTIyNTYzNFow
+EjEQMA4GA1UEChMHQWNtZSBDbzBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABISm
+jGlTr4dLOWT+BCTm2PzWRjk1DpLcSAh+Al8eB1Nc2eBWxYIH9qPirfatvqBOA4c5
+ZwycRpFoaw6O+EmXnVujTDBKMA4GA1UdDwEB/wQEAwICpDATBgNVHSUEDDAKBggr
+BgEFBQcDATAPBgNVHRMBAf8EBTADAQH/MBIGA1UdEQQLMAmCB2V4YW1wbGUwCgYI
+KoZIzj0EAwIDSQAwRgIhAMaBYWFCjTfn0MNyQ0QXvYT/iIFompkIqzw6wB7qjLrA
+AiEA3sn65V7G4tsjZEOpN0Jykn9uiTjqniqn/S/qmv8gIec=
+-----END CERTIFICATE-----`
+
+const leafWithAKID = `-----BEGIN CERTIFICATE-----
+MIIBjTCCATSgAwIBAgIRAPCKYvADhKLPaWOtcTu2XYwwCgYIKoZIzj0EAwIwEjEQ
+MA4GA1UEChMHQWNtZSBDbzAeFw0xOTAyMDQyMzA2NTJaFw0yOTAyMDEyMzA2NTJa
+MBMxETAPBgNVBAoTCEFjbWUgTExDMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE
+Wk5N+/8X97YT6ClFNIE5/4yc2YwKn921l0wrIJEcT2u+Uydm7EqtCJNtZjYMAnBd
+Acp/wynpTwC6tBTsxcM0s6NqMGgwDgYDVR0PAQH/BAQDAgWgMBMGA1UdJQQMMAoG
+CCsGAQUFBwMBMAwGA1UdEwEB/wQCMAAwHwYDVR0jBBgwFoAUwitfkXg0JglCjW9R
+ssWvTAveakIwEgYDVR0RBAswCYIHZXhhbXBsZTAKBggqhkjOPQQDAgNHADBEAiBk
+4LpWiWPOIl5PIhX9PDVkmjpre5oyoH/3aYwG8ABYuAIgCeSfbYueOOG2AdXuMqSU
+ZZMqeJS7JldLx91sPUArY5A=
+-----END CERTIFICATE-----`
+
+const rootMatchingSKIDMismatchingSubject = `-----BEGIN CERTIFICATE-----
+MIIBQjCB6aADAgECAgEAMAoGCCqGSM49BAMCMBExDzANBgNVBAMTBlJvb3QgQTAe
+Fw0wOTExMTAyMzAwMDBaFw0xOTExMDgyMzAwMDBaMBExDzANBgNVBAMTBlJvb3Qg
+QTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPK4p1uXq2aAeDtKDHIokg2rTcPM
+2gq3N9Y96wiW6/7puBK1+INEW//cO9x6FpzkcsHw/TriAqy4sck/iDAvf9WjMjAw
+MA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAMBgNVHQ4EBQQDAQID
+MAoGCCqGSM49BAMCA0gAMEUCIQDgtAp7iVHxMnKxZPaLQPC+Tv2r7+DJc88k2SKH
+MPs/wQIgFjjNvBoQEl7vSHTcRGCCcFMdlN4l0Dqc9YwGa9fyrQs=
+-----END CERTIFICATE-----`
+
+const rootMismatchingSKIDMatchingSubject = `-----BEGIN CERTIFICATE-----
+MIIBNDCB26ADAgECAgEAMAoGCCqGSM49BAMCMBExDzANBgNVBAMTBlJvb3QgQjAe
+Fw0wOTExMTAyMzAwMDBaFw0xOTExMDgyMzAwMDBaMBExDzANBgNVBAMTBlJvb3Qg
+QjBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABI1YRFcIlkWzm9BdEVrIsEQJ2dT6
+qiW8/WV9GoIhmDtX9SEDHospc0Cgm+TeD2QYW2iMrS5mvNe4GSw0Jezg/bOjJDAi
+MA8GA1UdJQQIMAYGBFUdJQAwDwYDVR0TAQH/BAUwAwEB/zAKBggqhkjOPQQDAgNI
+ADBFAiEAukWOiuellx8bugRiwCS5XQ6IOJ1SZcjuZxj76WojwxkCIHqa71qNw8FM
+DtA5yoL9M2pDFF6ovFWnaCe+KlzSwAW/
+-----END CERTIFICATE-----`
+
+const leafMatchingAKIDMatchingIssuer = `-----BEGIN CERTIFICATE-----
+MIIBNTCB26ADAgECAgEAMAoGCCqGSM49BAMCMBExDzANBgNVBAMTBlJvb3QgQjAe
+Fw0wOTExMTAyMzAwMDBaFw0xOTExMDgyMzAwMDBaMA8xDTALBgNVBAMTBExlYWYw
+WTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAASNWERXCJZFs5vQXRFayLBECdnU+qol
+vP1lfRqCIZg7V/UhAx6LKXNAoJvk3g9kGFtojK0uZrzXuBksNCXs4P2zoyYwJDAO
+BgNVHSMEBzAFgAMBAgMwEgYDVR0RBAswCYIHZXhhbXBsZTAKBggqhkjOPQQDAgNJ
+ADBGAiEAnV9XV7a4h0nfJB8pWv+pBUXRlRFA2uZz3mXEpee8NYACIQCWa+wL70GL
+ePBQCV1F9sE2q4ZrnsT9TZoNrSe/bMDjzA==
+-----END CERTIFICATE-----`
+
+var unknownAuthorityErrorTests = []struct {
+ name string
+ cert string
+ expected string
+}{
+ {"self-signed, cn", selfSignedWithCommonName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"test\")"},
+ {"self-signed, no cn, org", selfSignedNoCommonNameWithOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"ca\")"},
+ {"self-signed, no cn, no org", selfSignedNoCommonNameNoOrgName, "x509: certificate signed by unknown authority (possibly because of \"empty\" while trying to verify candidate authority certificate \"serial:0\")"},
+}
+
+func TestUnknownAuthorityError(t *testing.T) {
+ for i, tt := range unknownAuthorityErrorTests {
+ t.Run(tt.name, func(t *testing.T) {
+ der, _ := pem.Decode([]byte(tt.cert))
+ if der == nil {
+ t.Fatalf("#%d: Unable to decode PEM block", i)
+ }
+ c, err := ParseCertificate(der.Bytes)
+ if err != nil {
+ t.Fatalf("#%d: Unable to parse certificate -> %v", i, err)
+ }
+ uae := &UnknownAuthorityError{
+ Cert: c,
+ hintErr: fmt.Errorf("empty"),
+ hintCert: c,
+ }
+ actual := uae.Error()
+ if actual != tt.expected {
+ t.Errorf("#%d: UnknownAuthorityError.Error() response invalid actual: %s expected: %s", i, actual, tt.expected)
+ }
+ })
+ }
+}
+
+var nameConstraintTests = []struct {
+ constraint, domain string
+ expectError bool
+ shouldMatch bool
+}{
+ {"", "anything.com", false, true},
+ {"example.com", "example.com", false, true},
+ {"example.com.", "example.com", true, false},
+ {"example.com", "example.com.", true, false},
+ {"example.com", "ExAmPle.coM", false, true},
+ {"example.com", "exampl1.com", false, false},
+ {"example.com", "www.ExAmPle.coM", false, true},
+ {"example.com", "sub.www.ExAmPle.coM", false, true},
+ {"example.com", "notexample.com", false, false},
+ {".example.com", "example.com", false, false},
+ {".example.com", "www.example.com", false, true},
+ {".example.com", "www..example.com", true, false},
+}
+
+func TestNameConstraints(t *testing.T) {
+ for i, test := range nameConstraintTests {
+ result, err := matchDomainConstraint(test.domain, test.constraint)
+
+ if err != nil && !test.expectError {
+ t.Errorf("unexpected error for test #%d: domain=%s, constraint=%s, err=%s", i, test.domain, test.constraint, err)
+ continue
+ }
+
+ if err == nil && test.expectError {
+ t.Errorf("unexpected success for test #%d: domain=%s, constraint=%s", i, test.domain, test.constraint)
+ continue
+ }
+
+ if result != test.shouldMatch {
+ t.Errorf("unexpected result for test #%d: domain=%s, constraint=%s, result=%t", i, test.domain, test.constraint, result)
+ }
+ }
+}
+
+const selfSignedWithCommonName = `-----BEGIN CERTIFICATE-----
+MIIDCjCCAfKgAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
+MAkGA1UEAxMCY2EwHhcNMTYwODI4MTcwOTE4WhcNMjEwODI3MTcwOTE4WjAcMQsw
+CQYDVQQKEwJjYTENMAsGA1UEAxMEdGVzdDCCASIwDQYJKoZIhvcNAQEBBQADggEP
+ADCCAQoCggEBAOH55PfRsbvmcabfLLko1w/yuapY/hk13Cgmc3WE/Z1ZStxGiVxY
+gQVH9n4W/TbUsrep/TmcC4MV7xEm5252ArcgaH6BeQ4QOTFj/6Jx0RT7U/ix+79x
+8RRysf7OlzNpGIctwZEM7i/G+0ZfqX9ULxL/EW9tppSxMX1jlXZQarnU7BERL5cH
++G2jcbU9H28FXYishqpVYE9L7xrXMm61BAwvGKB0jcVW6JdhoAOSfQbbgp7JjIlq
+czXqUsv1UdORO/horIoJptynTvuARjZzyWatya6as7wyOgEBllE6BjPK9zpn+lp3
+tQ8dwKVqm/qBPhIrVqYG/Ec7pIv8mJfYabMCAwEAAaNZMFcwDgYDVR0PAQH/BAQD
+AgOoMB0GA1UdJQQWMBQGCCsGAQUFBwMCBggrBgEFBQcDATAMBgNVHRMBAf8EAjAA
+MAoGA1UdDgQDBAEAMAwGA1UdIwQFMAOAAQAwDQYJKoZIhvcNAQELBQADggEBAAAM
+XMFphzq4S5FBcRdB2fRrmcoz+jEROBWvIH/1QUJeBEBz3ZqBaJYfBtQTvqCA5Rjw
+dxyIwVd1W3q3aSulM0tO62UCU6L6YeeY/eq8FmpD7nMJo7kCrXUUAMjxbYvS3zkT
+v/NErK6SgWnkQiPJBZNX1Q9+aSbLT/sbaCTdbWqcGNRuLGJkmqfIyoxRt0Hhpqsx
+jP5cBaVl50t4qoCuVIE9cOucnxYXnI7X5HpXWvu8Pfxo4SwVjb1az8Fk5s8ZnxGe
+fPB6Q3L/pKBe0SEe5GywpwtokPLB3lAygcuHbxp/1FlQ1NQZqq+vgXRIla26bNJf
+IuYkJwt6w+LH/9HZgf8=
+-----END CERTIFICATE-----`
+const selfSignedNoCommonNameWithOrgName = `-----BEGIN CERTIFICATE-----
+MIIC+zCCAeOgAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
+MAkGA1UEAxMCY2EwHhcNMTYwODI4MTgxMzQ4WhcNMjEwODI3MTgxMzQ4WjANMQsw
+CQYDVQQKEwJjYTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAL5EjrUa
+7EtOMxWiIgTzp2FlQvncPsG329O3l3uNGnbigb8TmNMw2M8UhoDjd84pnU5RAfqd
+8t5TJyw/ybnIKBN131Q2xX+gPQ0dFyMvcO+i1CUgCxmYZomKVA2MXO1RD1hLTYGS
+gOVjc3no3MBwd8uVQp0NStqJ1QvLtNG4Uy+B28qe+ZFGGbjGqx8/CU4A8Szlpf7/
+xAZR8w5qFUUlpA2LQYeHHJ5fQVXw7kyL1diNrKNi0G3qcY0IrBh++hT+hnEEXyXu
+g8a0Ux18hoE8D6rAr34rCZl6AWfqW5wjwm+N5Ns2ugr9U4N8uCKJYMPHb2CtdubU
+46IzVucpTfGLdaMCAwEAAaNZMFcwDgYDVR0PAQH/BAQDAgOoMB0GA1UdJQQWMBQG
+CCsGAQUFBwMCBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMAoGA1UdDgQDBAEAMAwG
+A1UdIwQFMAOAAQAwDQYJKoZIhvcNAQELBQADggEBAEn5SgVpJ3zjsdzPqK7Qd/sB
+bYd1qtPHlrszjhbHBg35C6mDgKhcv4o6N+fuC+FojZb8lIxWzJtvT9pQbfy/V6u3
+wOb816Hm71uiP89sioIOKCvSAstj/p9doKDOUaKOcZBTw0PS2m9eja8bnleZzBvK
+rD8cNkHf74v98KvBhcwBlDifVzmkWzMG6TL1EkRXUyLKiWgoTUFSkCDV927oXXMR
+DKnszq+AVw+K8hbeV2A7GqT7YfeqOAvSbatTDnDtKOPmlCnQui8A149VgZzXv7eU
+29ssJSqjUPyp58dlV6ZuynxPho1QVZUOQgnJToXIQ3/5vIvJRXy52GJCs4/Gh/w=
+-----END CERTIFICATE-----`
+const selfSignedNoCommonNameNoOrgName = `-----BEGIN CERTIFICATE-----
+MIIC7jCCAdagAwIBAgIBADANBgkqhkiG9w0BAQsFADAaMQswCQYDVQQKEwJjYTEL
+MAkGA1UEAxMCY2EwHhcNMTYwODI4MTgxOTQ1WhcNMjEwODI3MTgxOTQ1WjAAMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAp3E+Jl6DpgzogHUW/i/AAcCM
+fnNJLOamNVKFGmmxhb4XTHxRaWoTzrlsyzIMS0WzivvJeZVe6mWbvuP2kZanKgIz
+35YXRTR9HbqkNTMuvnpUESzWxbGWE2jmt2+a/Jnz89FS4WIYRhF7nI2z8PvZOfrI
+2gETTT2tEpoF2S4soaYfm0DBeT8K0/rogAaf+oeUS6V+v3miRcAooJgpNJGu9kqm
+S0xKPn1RCFVjpiRd6YNS0xZirjYQIBMFBvoSoHjaOdgJptNRBprYPOxVJ/ItzGf0
+kPmzPFCx2tKfxV9HLYBPgxi+fP3IIx8aIYuJn8yReWtYEMYU11hDPeAFN5Gm+wID
+AQABo1kwVzAOBgNVHQ8BAf8EBAMCA6gwHQYDVR0lBBYwFAYIKwYBBQUHAwIGCCsG
+AQUFBwMBMAwGA1UdEwEB/wQCMAAwCgYDVR0OBAMEAQAwDAYDVR0jBAUwA4ABADAN
+BgkqhkiG9w0BAQsFAAOCAQEATZVOFeiCpPM5QysToLv+8k7Rjoqt6L5IxMUJGEpq
+4ENmldmwkhEKr9VnYEJY3njydnnTm97d9vOfnLj9nA9wMBODeOO3KL2uJR2oDnmM
+9z1NSe2aQKnyBb++DM3ZdikpHn/xEpGV19pYKFQVn35x3lpPh2XijqRDO/erKemb
+w67CoNRb81dy+4Q1lGpA8ORoLWh5fIq2t2eNGc4qB8vlTIKiESzAwu7u3sRfuWQi
+4R+gnfLd37FWflMHwztFbVTuNtPOljCX0LN7KcuoXYlr05RhQrmoN7fQHsrZMNLs
+8FVjHdKKu+uPstwd04Uy4BR/H2y1yerN9j/L6ZkMl98iiA==
+-----END CERTIFICATE-----`
+
+const criticalExtRoot = `-----BEGIN CERTIFICATE-----
+MIIBqzCCAVGgAwIBAgIJAJ+mI/85cXApMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT
+A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw
+MDBaMB0xDDAKBgNVBAoTA09yZzENMAsGA1UEAxMEUm9vdDBZMBMGByqGSM49AgEG
+CCqGSM49AwEHA0IABJGp9joiG2QSQA+1FczEDAsWo84rFiP3GTL+n+ugcS6TyNib
+gzMsdbJgVi+a33y0SzLZxB+YvU3/4KTk8yKLC+2jejB4MA4GA1UdDwEB/wQEAwIC
+BDAdBgNVHSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB
+/zAZBgNVHQ4EEgQQQDfXAftAL7gcflQEJ4xZATAbBgNVHSMEFDASgBBAN9cB+0Av
+uBx+VAQnjFkBMAoGCCqGSM49BAMCA0gAMEUCIFeSV00fABFceWR52K+CfIgOHotY
+FizzGiLB47hGwjMuAiEA8e0um2Kr8FPQ4wmFKaTRKHMaZizCGl3m+RG5QsE1KWo=
+-----END CERTIFICATE-----`
+
+const criticalExtIntermediate = `-----BEGIN CERTIFICATE-----
+MIIBszCCAVmgAwIBAgIJAL2kcGZKpzVqMAoGCCqGSM49BAMCMB0xDDAKBgNVBAoT
+A09yZzENMAsGA1UEAxMEUm9vdDAeFw0xNTAxMDEwMDAwMDBaFw0yNTAxMDEwMDAw
+MDBaMCUxDDAKBgNVBAoTA09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMFkwEwYH
+KoZIzj0CAQYIKoZIzj0DAQcDQgAESqVq92iPEq01cL4o99WiXDc5GZjpjNlzMS1n
+rk8oHcVDp4tQRRQG3F4A6dF1rn/L923ha3b0fhDLlAvXZB+7EKN6MHgwDgYDVR0P
+AQH/BAQDAgIEMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcDAjAPBgNVHRMB
+Af8EBTADAQH/MBkGA1UdDgQSBBCMGmiotXbbXVd7H40UsgajMBsGA1UdIwQUMBKA
+EEA31wH7QC+4HH5UBCeMWQEwCgYIKoZIzj0EAwIDSAAwRQIhAOhhNRb6KV7h3wbE
+cdap8bojzvUcPD78fbsQPCNw1jPxAiBOeAJhlTwpKn9KHpeJphYSzydj9NqcS26Y
+xXbdbm27KQ==
+-----END CERTIFICATE-----`
+
+const criticalExtLeafWithExt = `-----BEGIN CERTIFICATE-----
+MIIBxTCCAWugAwIBAgIJAJZAUtw5ccb1MAoGCCqGSM49BAMCMCUxDDAKBgNVBAoT
+A09yZzEVMBMGA1UEAxMMSW50ZXJtZWRpYXRlMB4XDTE1MDEwMTAwMDAwMFoXDTI1
+MDEwMTAwMDAwMFowJDEMMAoGA1UEChMDT3JnMRQwEgYDVQQDEwtleGFtcGxlLmNv
+bTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABF3ABa2+B6gUyg6ayCaRQWYY/+No
+6PceLqEavZNUeVNuz7bS74Toy8I7R3bGMkMgbKpLSPlPTroAATvebTXoBaijgYQw
+gYEwDgYDVR0PAQH/BAQDAgWgMB0GA1UdJQQWMBQGCCsGAQUFBwMBBggrBgEFBQcD
+AjAMBgNVHRMBAf8EAjAAMBkGA1UdDgQSBBBRNtBL2vq8nCV3qVp7ycxMMBsGA1Ud
+IwQUMBKAEIwaaKi1dttdV3sfjRSyBqMwCgYDUQMEAQH/BAAwCgYIKoZIzj0EAwID
+SAAwRQIgVjy8GBgZFiagexEuDLqtGjIRJQtBcf7lYgf6XFPH1h4CIQCT6nHhGo6E
+I+crEm4P5q72AnA/Iy0m24l7OvLuXObAmg==
+-----END CERTIFICATE-----`
+
+const criticalExtIntermediateWithExt = `-----BEGIN CERTIFICATE-----
+MIIB2TCCAX6gAwIBAgIIQD3NrSZtcUUwCgYIKoZIzj0EAwIwHTEMMAoGA1UEChMD
+T3JnMQ0wCwYDVQQDEwRSb290MB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAw
+MFowPTEMMAoGA1UEChMDT3JnMS0wKwYDVQQDEyRJbnRlcm1lZGlhdGUgd2l0aCBD
+cml0aWNhbCBFeHRlbnNpb24wWTATBgcqhkjOPQIBBggqhkjOPQMBBwNCAAQtnmzH
+mcRm10bdDBnJE7xQEJ25cLCL5okuEphRR0Zneo6+nQZikoh+UBbtt5GV3Dms7LeP
+oF5HOplYDCd8wi/wo4GHMIGEMA4GA1UdDwEB/wQEAwICBDAdBgNVHSUEFjAUBggr
+BgEFBQcDAQYIKwYBBQUHAwIwDwYDVR0TAQH/BAUwAwEB/zAZBgNVHQ4EEgQQKxdv
+UuQZ6sO3XvBsxgNZ3zAbBgNVHSMEFDASgBBAN9cB+0AvuBx+VAQnjFkBMAoGA1ED
+BAEB/wQAMAoGCCqGSM49BAMCA0kAMEYCIQCQzTPd6XKex+OAPsKT/1DsoMsg8vcG
+c2qZ4Q0apT/kvgIhAKu2TnNQMIUdcO0BYQIl+Uhxc78dc9h4lO+YJB47pHGx
+-----END CERTIFICATE-----`
+
+const criticalExtLeaf = `-----BEGIN CERTIFICATE-----
+MIIBzzCCAXWgAwIBAgIJANoWFIlhCI9MMAoGCCqGSM49BAMCMD0xDDAKBgNVBAoT
+A09yZzEtMCsGA1UEAxMkSW50ZXJtZWRpYXRlIHdpdGggQ3JpdGljYWwgRXh0ZW5z
+aW9uMB4XDTE1MDEwMTAwMDAwMFoXDTI1MDEwMTAwMDAwMFowJDEMMAoGA1UEChMD
+T3JnMRQwEgYDVQQDEwtleGFtcGxlLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEH
+A0IABG1Lfh8A0Ho2UvZN5H0+ONil9c8jwtC0y0xIZftyQE+Fwr9XwqG3rV2g4M1h
+GnJa9lV9MPHg8+b85Hixm0ZSw7SjdzB1MA4GA1UdDwEB/wQEAwIFoDAdBgNVHSUE
+FjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwDAYDVR0TAQH/BAIwADAZBgNVHQ4EEgQQ
+UNhY4JhezH9gQYqvDMWrWDAbBgNVHSMEFDASgBArF29S5Bnqw7de8GzGA1nfMAoG
+CCqGSM49BAMCA0gAMEUCIQClA3d4tdrDu9Eb5ZBpgyC+fU1xTZB0dKQHz6M5fPZA
+2AIgN96lM+CPGicwhN24uQI6flOsO3H0TJ5lNzBYLtnQtlc=
+-----END CERTIFICATE-----`
+
+func TestValidHostname(t *testing.T) {
+ tests := []struct {
+ host string
+ validInput, validPattern bool
+ }{
+ {host: "example.com", validInput: true, validPattern: true},
+ {host: "eXample123-.com", validInput: true, validPattern: true},
+ {host: "-eXample123-.com"},
+ {host: ""},
+ {host: "."},
+ {host: "example..com"},
+ {host: ".example.com"},
+ {host: "example.com.", validInput: true},
+ {host: "*.example.com."},
+ {host: "*.example.com", validPattern: true},
+ {host: "*foo.example.com"},
+ {host: "foo.*.example.com"},
+ {host: "exa_mple.com", validInput: true, validPattern: true},
+ {host: "foo,bar"},
+ {host: "project-dev:us-central1:main"},
+ }
+ for _, tt := range tests {
+ if got := validHostnamePattern(tt.host); got != tt.validPattern {
+ t.Errorf("validHostnamePattern(%q) = %v, want %v", tt.host, got, tt.validPattern)
+ }
+ if got := validHostnameInput(tt.host); got != tt.validInput {
+ t.Errorf("validHostnameInput(%q) = %v, want %v", tt.host, got, tt.validInput)
+ }
+ }
+}
+
+func generateCert(cn string, isCA bool, issuer *Certificate, issuerKey crypto.PrivateKey) (*Certificate, crypto.PrivateKey, error) {
+ priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ serialNumberLimit := new(big.Int).Lsh(big.NewInt(1), 128)
+ serialNumber, _ := rand.Int(rand.Reader, serialNumberLimit)
+
+ template := &Certificate{
+ SerialNumber: serialNumber,
+ Subject: pkix.Name{CommonName: cn},
+ NotBefore: time.Now().Add(-1 * time.Hour),
+ NotAfter: time.Now().Add(24 * time.Hour),
+
+ KeyUsage: KeyUsageKeyEncipherment | KeyUsageDigitalSignature | KeyUsageCertSign,
+ ExtKeyUsage: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ BasicConstraintsValid: true,
+ IsCA: isCA,
+ }
+ if issuer == nil {
+ issuer = template
+ issuerKey = priv
+ }
+
+ derBytes, err := CreateCertificate(rand.Reader, template, issuer, priv.Public(), issuerKey)
+ if err != nil {
+ return nil, nil, err
+ }
+ cert, err := ParseCertificate(derBytes)
+ if err != nil {
+ return nil, nil, err
+ }
+
+ return cert, priv, nil
+}
+
+func TestPathologicalChain(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping generation of a long chain of certificates in short mode")
+ }
+
+ // Build a chain where all intermediates share the same subject, to hit the
+ // path building worst behavior.
+ roots, intermediates := NewCertPool(), NewCertPool()
+
+ parent, parentKey, err := generateCert("Root CA", true, nil, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ roots.AddCert(parent)
+
+ for i := 1; i < 100; i++ {
+ parent, parentKey, err = generateCert("Intermediate CA", true, parent, parentKey)
+ if err != nil {
+ t.Fatal(err)
+ }
+ intermediates.AddCert(parent)
+ }
+
+ leaf, _, err := generateCert("Leaf", false, parent, parentKey)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ start := time.Now()
+ _, err = leaf.Verify(VerifyOptions{
+ Roots: roots,
+ Intermediates: intermediates,
+ })
+ t.Logf("verification took %v", time.Since(start))
+
+ if err == nil || !strings.Contains(err.Error(), "signature check attempts limit") {
+ t.Errorf("expected verification to fail with a signature checks limit error; got %v", err)
+ }
+}
+
+func TestLongChain(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping generation of a long chain of certificates in short mode")
+ }
+
+ roots, intermediates := NewCertPool(), NewCertPool()
+
+ parent, parentKey, err := generateCert("Root CA", true, nil, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+ roots.AddCert(parent)
+
+ for i := 1; i < 15; i++ {
+ name := fmt.Sprintf("Intermediate CA #%d", i)
+ parent, parentKey, err = generateCert(name, true, parent, parentKey)
+ if err != nil {
+ t.Fatal(err)
+ }
+ intermediates.AddCert(parent)
+ }
+
+ leaf, _, err := generateCert("Leaf", false, parent, parentKey)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ start := time.Now()
+ if _, err := leaf.Verify(VerifyOptions{
+ Roots: roots,
+ Intermediates: intermediates,
+ }); err != nil {
+ t.Error(err)
+ }
+ t.Logf("verification took %v", time.Since(start))
+}
+
+func TestSystemRootsError(t *testing.T) {
+ if runtime.GOOS == "windows" || runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
+ t.Skip("Windows and darwin do not use (or support) systemRoots")
+ }
+
+ defer func(oldSystemRoots *CertPool) { systemRoots = oldSystemRoots }(systemRootsPool())
+
+ opts := VerifyOptions{
+ Intermediates: NewCertPool(),
+ DNSName: "www.google.com",
+ CurrentTime: time.Unix(1677615892, 0),
+ }
+
+ if ok := opts.Intermediates.AppendCertsFromPEM([]byte(gtsIntermediate)); !ok {
+ t.Fatalf("failed to parse intermediate")
+ }
+
+ leaf, err := certificateFromPEM(googleLeaf)
+ if err != nil {
+ t.Fatalf("failed to parse leaf: %v", err)
+ }
+
+ systemRoots = nil
+
+ _, err = leaf.Verify(opts)
+ if _, ok := err.(SystemRootsError); !ok {
+ t.Errorf("error was not SystemRootsError: %v", err)
+ }
+}
+
+func TestSystemRootsErrorUnwrap(t *testing.T) {
+ var err1 = errors.New("err1")
+ err := SystemRootsError{Err: err1}
+ if !errors.Is(err, err1) {
+ t.Error("errors.Is failed, wanted success")
+ }
+}
+
+func macosMajorVersion(t *testing.T) (int, error) {
+ cmd := testenv.Command(t, "sw_vers", "-productVersion")
+ out, err := cmd.Output()
+ if err != nil {
+ if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 {
+ return 0, fmt.Errorf("%v: %v\n%s", cmd, err, ee.Stderr)
+ }
+ return 0, fmt.Errorf("%v: %v", cmd, err)
+ }
+ before, _, ok := strings.Cut(string(out), ".")
+ major, err := strconv.Atoi(before)
+ if !ok || err != nil {
+ return 0, fmt.Errorf("%v: unexpected output: %q", cmd, out)
+ }
+
+ return major, nil
+}
+
+func TestIssue51759(t *testing.T) {
+ if runtime.GOOS != "darwin" {
+ t.Skip("only affects darwin")
+ }
+
+ testenv.MustHaveExecPath(t, "sw_vers")
+ if vers, err := macosMajorVersion(t); err != nil {
+ if builder := testenv.Builder(); builder != "" {
+ t.Fatalf("unable to determine macOS version: %s", err)
+ } else {
+ t.Skip("unable to determine macOS version")
+ }
+ } else if vers < 11 {
+ t.Skip("behavior only enforced in macOS 11 and after")
+ }
+
+ // badCertData contains a cert that we parse as valid
+ // but that macOS SecCertificateCreateWithData rejects.
+ const badCertData = "0\x82\x01U0\x82\x01\a\xa0\x03\x02\x01\x02\x02\x01\x020\x05\x06\x03+ep0R1P0N\x06\x03U\x04\x03\x13Gderpkey8dc58100b2493614ee1692831a461f3f4dd3f9b3b088e244f887f81b4906ac260\x1e\x17\r220112235755Z\x17\r220313235755Z0R1P0N\x06\x03U\x04\x03\x13Gderpkey8dc58100b2493614ee1692831a461f3f4dd3f9b3b088e244f887f81b4906ac260*0\x05\x06\x03+ep\x03!\x00bA\xd8e\xadW\xcb\xefZ\x89\xb5\"\x1eR\x9d\xba\x0e:\x1042Q@\u007f\xbd\xfb{ks\x04\xd1£\x020\x000\x05\x06\x03+ep\x03A\x00[\xa7\x06y\x86(\x94\x97\x9eLwA\x00\x01x\xaa\xbc\xbd Ê]\n(΅!ف0\xf5\x9a%I\x19<\xffo\xf1\xeaaf@\xb1\xa7\xaf\xfd\xe9R\xc7\x0f\x8d&\xd5\xfc\x0f;Ϙ\x82\x84a\xbc\r"
+ badCert, err := ParseCertificate([]byte(badCertData))
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ t.Run("leaf", func(t *testing.T) {
+ opts := VerifyOptions{}
+ expectedErr := "invalid leaf certificate"
+ _, err = badCert.Verify(opts)
+ if err == nil || err.Error() != expectedErr {
+ t.Fatalf("unexpected error: want %q, got %q", expectedErr, err)
+ }
+ })
+
+ goodCert, err := certificateFromPEM(googleLeaf)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ t.Run("intermediate", func(t *testing.T) {
+ opts := VerifyOptions{
+ Intermediates: NewCertPool(),
+ }
+ opts.Intermediates.AddCert(badCert)
+ expectedErr := "SecCertificateCreateWithData: invalid certificate"
+ _, err = goodCert.Verify(opts)
+ if err == nil || err.Error() != expectedErr {
+ t.Fatalf("unexpected error: want %q, got %q", expectedErr, err)
+ }
+ })
+}
+
+type trustGraphEdge struct {
+ Issuer string
+ Subject string
+ Type int
+ MutateTemplate func(*Certificate)
+}
+
+type trustGraphDescription struct {
+ Roots []string
+ Leaf string
+ Graph []trustGraphEdge
+}
+
+func genCertEdge(t *testing.T, subject string, key crypto.Signer, mutateTmpl func(*Certificate), certType int, issuer *Certificate, signer crypto.Signer) *Certificate {
+ t.Helper()
+
+ serial, err := rand.Int(rand.Reader, big.NewInt(100))
+ if err != nil {
+ t.Fatalf("failed to generate test serial: %s", err)
+ }
+ tmpl := &Certificate{
+ SerialNumber: serial,
+ Subject: pkix.Name{CommonName: subject},
+ NotBefore: time.Now().Add(-time.Hour),
+ NotAfter: time.Now().Add(time.Hour),
+ }
+ if certType == rootCertificate || certType == intermediateCertificate {
+ tmpl.IsCA, tmpl.BasicConstraintsValid = true, true
+ tmpl.KeyUsage = KeyUsageCertSign
+ } else if certType == leafCertificate {
+ tmpl.DNSNames = []string{"localhost"}
+ }
+ if mutateTmpl != nil {
+ mutateTmpl(tmpl)
+ }
+
+ if certType == rootCertificate {
+ issuer = tmpl
+ signer = key
+ }
+
+ d, err := CreateCertificate(rand.Reader, tmpl, issuer, key.Public(), signer)
+ if err != nil {
+ t.Fatalf("failed to generate test cert: %s", err)
+ }
+ c, err := ParseCertificate(d)
+ if err != nil {
+ t.Fatalf("failed to parse test cert: %s", err)
+ }
+ return c
+}
+
+func buildTrustGraph(t *testing.T, d trustGraphDescription) (*CertPool, *CertPool, *Certificate) {
+ t.Helper()
+
+ certs := map[string]*Certificate{}
+ keys := map[string]crypto.Signer{}
+ roots := []*Certificate{}
+ for _, r := range d.Roots {
+ k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatalf("failed to generate test key: %s", err)
+ }
+ root := genCertEdge(t, r, k, nil, rootCertificate, nil, nil)
+ roots = append(roots, root)
+ certs[r] = root
+ keys[r] = k
+ }
+
+ intermediates := []*Certificate{}
+ var leaf *Certificate
+ for _, e := range d.Graph {
+ issuerCert, ok := certs[e.Issuer]
+ if !ok {
+ t.Fatalf("unknown issuer %s", e.Issuer)
+ }
+ issuerKey, ok := keys[e.Issuer]
+ if !ok {
+ t.Fatalf("unknown issuer %s", e.Issuer)
+ }
+
+ k, ok := keys[e.Subject]
+ if !ok {
+ var err error
+ k, err = ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatalf("failed to generate test key: %s", err)
+ }
+ keys[e.Subject] = k
+ }
+ cert := genCertEdge(t, e.Subject, k, e.MutateTemplate, e.Type, issuerCert, issuerKey)
+ certs[e.Subject] = cert
+ if e.Subject == d.Leaf {
+ leaf = cert
+ } else {
+ intermediates = append(intermediates, cert)
+ }
+ }
+
+ rootPool, intermediatePool := NewCertPool(), NewCertPool()
+ for i := len(roots) - 1; i >= 0; i-- {
+ rootPool.AddCert(roots[i])
+ }
+ for i := len(intermediates) - 1; i >= 0; i-- {
+ intermediatePool.AddCert(intermediates[i])
+ }
+
+ return rootPool, intermediatePool, leaf
+}
+
+func chainsToStrings(chains [][]*Certificate) []string {
+ chainStrings := []string{}
+ for _, chain := range chains {
+ names := []string{}
+ for _, c := range chain {
+ names = append(names, c.Subject.String())
+ }
+ chainStrings = append(chainStrings, strings.Join(names, " -> "))
+ }
+ sort.Strings(chainStrings)
+ return chainStrings
+}
+
+func TestPathBuilding(t *testing.T) {
+ tests := []struct {
+ name string
+ graph trustGraphDescription
+ expectedChains []string
+ expectedErr string
+ }{
+ {
+ // Build the following graph from RFC 4158, figure 7 (note that in this graph edges represent
+ // certificates where the parent is the issuer and the child is the subject.) For the certificate
+ // C->B, use an unsupported ExtKeyUsage (in this case ExtKeyUsageCodeSigning) which invalidates
+ // the path Trust Anchor -> C -> B -> EE. The remaining valid paths should be:
+ // * Trust Anchor -> A -> B -> EE
+ // * Trust Anchor -> C -> A -> B -> EE
+ //
+ // +---------+
+ // | Trust |
+ // | Anchor |
+ // +---------+
+ // | |
+ // v v
+ // +---+ +---+
+ // | A |<-->| C |
+ // +---+ +---+
+ // | |
+ // | +---+ |
+ // +->| B |<-+
+ // +---+
+ // |
+ // v
+ // +----+
+ // | EE |
+ // +----+
+ name: "bad EKU",
+ graph: trustGraphDescription{
+ Roots: []string{"root"},
+ Leaf: "leaf",
+ Graph: []trustGraphEdge{
+ {
+ Issuer: "root",
+ Subject: "inter a",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "root",
+ Subject: "inter c",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter c",
+ Subject: "inter a",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter a",
+ Subject: "inter c",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter c",
+ Subject: "inter b",
+ Type: intermediateCertificate,
+ MutateTemplate: func(t *Certificate) {
+ t.ExtKeyUsage = []ExtKeyUsage{ExtKeyUsageCodeSigning}
+ },
+ },
+ {
+ Issuer: "inter a",
+ Subject: "inter b",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter b",
+ Subject: "leaf",
+ Type: leafCertificate,
+ },
+ },
+ },
+ expectedChains: []string{
+ "CN=leaf -> CN=inter b -> CN=inter a -> CN=inter c -> CN=root",
+ "CN=leaf -> CN=inter b -> CN=inter a -> CN=root",
+ },
+ },
+ {
+ // Build the following graph from RFC 4158, figure 7 (note that in this graph edges represent
+ // certificates where the parent is the issuer and the child is the subject.) For the certificate
+ // C->B, use a unconstrained SAN which invalidates the path Trust Anchor -> C -> B -> EE. The
+ // remaining valid paths should be:
+ // * Trust Anchor -> A -> B -> EE
+ // * Trust Anchor -> C -> A -> B -> EE
+ //
+ // +---------+
+ // | Trust |
+ // | Anchor |
+ // +---------+
+ // | |
+ // v v
+ // +---+ +---+
+ // | A |<-->| C |
+ // +---+ +---+
+ // | |
+ // | +---+ |
+ // +->| B |<-+
+ // +---+
+ // |
+ // v
+ // +----+
+ // | EE |
+ // +----+
+ name: "bad EKU",
+ graph: trustGraphDescription{
+ Roots: []string{"root"},
+ Leaf: "leaf",
+ Graph: []trustGraphEdge{
+ {
+ Issuer: "root",
+ Subject: "inter a",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "root",
+ Subject: "inter c",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter c",
+ Subject: "inter a",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter a",
+ Subject: "inter c",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter c",
+ Subject: "inter b",
+ Type: intermediateCertificate,
+ MutateTemplate: func(t *Certificate) {
+ t.PermittedDNSDomains = []string{"good"}
+ t.DNSNames = []string{"bad"}
+ },
+ },
+ {
+ Issuer: "inter a",
+ Subject: "inter b",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter b",
+ Subject: "leaf",
+ Type: leafCertificate,
+ },
+ },
+ },
+ expectedChains: []string{
+ "CN=leaf -> CN=inter b -> CN=inter a -> CN=inter c -> CN=root",
+ "CN=leaf -> CN=inter b -> CN=inter a -> CN=root",
+ },
+ },
+ {
+ // Build the following graph, we should find both paths:
+ // * Trust Anchor -> A -> C -> EE
+ // * Trust Anchor -> A -> B -> C -> EE
+ //
+ // +---------+
+ // | Trust |
+ // | Anchor |
+ // +---------+
+ // |
+ // v
+ // +---+
+ // | A |
+ // +---+
+ // | |
+ // | +----+
+ // | v
+ // | +---+
+ // | | B |
+ // | +---+
+ // | |
+ // | +---v
+ // v v
+ // +---+
+ // | C |
+ // +---+
+ // |
+ // v
+ // +----+
+ // | EE |
+ // +----+
+ name: "all paths",
+ graph: trustGraphDescription{
+ Roots: []string{"root"},
+ Leaf: "leaf",
+ Graph: []trustGraphEdge{
+ {
+ Issuer: "root",
+ Subject: "inter a",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter a",
+ Subject: "inter b",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter a",
+ Subject: "inter c",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter b",
+ Subject: "inter c",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter c",
+ Subject: "leaf",
+ Type: leafCertificate,
+ },
+ },
+ },
+ expectedChains: []string{
+ "CN=leaf -> CN=inter c -> CN=inter a -> CN=root",
+ "CN=leaf -> CN=inter c -> CN=inter b -> CN=inter a -> CN=root",
+ },
+ },
+ {
+ // Build the following graph, which contains a cross-signature loop
+ // (A and C cross sign each other). Paths that include the A -> C -> A
+ // (and vice versa) loop should be ignored, resulting in the paths:
+ // * Trust Anchor -> A -> B -> EE
+ // * Trust Anchor -> C -> B -> EE
+ // * Trust Anchor -> A -> C -> B -> EE
+ // * Trust Anchor -> C -> A -> B -> EE
+ //
+ // +---------+
+ // | Trust |
+ // | Anchor |
+ // +---------+
+ // | |
+ // v v
+ // +---+ +---+
+ // | A |<-->| C |
+ // +---+ +---+
+ // | |
+ // | +---+ |
+ // +->| B |<-+
+ // +---+
+ // |
+ // v
+ // +----+
+ // | EE |
+ // +----+
+ name: "ignore cross-sig loops",
+ graph: trustGraphDescription{
+ Roots: []string{"root"},
+ Leaf: "leaf",
+ Graph: []trustGraphEdge{
+ {
+ Issuer: "root",
+ Subject: "inter a",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "root",
+ Subject: "inter c",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter c",
+ Subject: "inter a",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter a",
+ Subject: "inter c",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter c",
+ Subject: "inter b",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter a",
+ Subject: "inter b",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter b",
+ Subject: "leaf",
+ Type: leafCertificate,
+ },
+ },
+ },
+ expectedChains: []string{
+ "CN=leaf -> CN=inter b -> CN=inter a -> CN=inter c -> CN=root",
+ "CN=leaf -> CN=inter b -> CN=inter a -> CN=root",
+ "CN=leaf -> CN=inter b -> CN=inter c -> CN=inter a -> CN=root",
+ "CN=leaf -> CN=inter b -> CN=inter c -> CN=root",
+ },
+ },
+ {
+ // Build a simple two node graph, where the leaf is directly issued from
+ // the root and both certificates have matching subject and public key, but
+ // the leaf has SANs.
+ name: "leaf with same subject, key, as parent but with SAN",
+ graph: trustGraphDescription{
+ Roots: []string{"root"},
+ Leaf: "root",
+ Graph: []trustGraphEdge{
+ {
+ Issuer: "root",
+ Subject: "root",
+ Type: leafCertificate,
+ MutateTemplate: func(c *Certificate) {
+ c.DNSNames = []string{"localhost"}
+ },
+ },
+ },
+ },
+ expectedChains: []string{
+ "CN=root -> CN=root",
+ },
+ },
+ {
+ // Build a basic graph with two paths from leaf to root, but the path passing
+ // through C should be ignored, because it has invalid EKU nesting.
+ name: "ignore invalid EKU path",
+ graph: trustGraphDescription{
+ Roots: []string{"root"},
+ Leaf: "leaf",
+ Graph: []trustGraphEdge{
+ {
+ Issuer: "root",
+ Subject: "inter a",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "root",
+ Subject: "inter c",
+ Type: intermediateCertificate,
+ },
+ {
+ Issuer: "inter c",
+ Subject: "inter b",
+ Type: intermediateCertificate,
+ MutateTemplate: func(t *Certificate) {
+ t.ExtKeyUsage = []ExtKeyUsage{ExtKeyUsageCodeSigning}
+ },
+ },
+ {
+ Issuer: "inter a",
+ Subject: "inter b",
+ Type: intermediateCertificate,
+ MutateTemplate: func(t *Certificate) {
+ t.ExtKeyUsage = []ExtKeyUsage{ExtKeyUsageServerAuth}
+ },
+ },
+ {
+ Issuer: "inter b",
+ Subject: "leaf",
+ Type: leafCertificate,
+ MutateTemplate: func(t *Certificate) {
+ t.ExtKeyUsage = []ExtKeyUsage{ExtKeyUsageServerAuth}
+ },
+ },
+ },
+ },
+ expectedChains: []string{
+ "CN=leaf -> CN=inter b -> CN=inter a -> CN=root",
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ roots, intermediates, leaf := buildTrustGraph(t, tc.graph)
+ chains, err := leaf.Verify(VerifyOptions{
+ Roots: roots,
+ Intermediates: intermediates,
+ })
+ if err != nil && err.Error() != tc.expectedErr {
+ t.Fatalf("unexpected error: got %q, want %q", err, tc.expectedErr)
+ }
+ gotChains := chainsToStrings(chains)
+ if !reflect.DeepEqual(gotChains, tc.expectedChains) {
+ t.Errorf("unexpected chains returned:\ngot:\n\t%s\nwant:\n\t%s", strings.Join(gotChains, "\n\t"), strings.Join(tc.expectedChains, "\n\t"))
+ }
+ })
+ }
+}
+
+func TestEKUEnforcement(t *testing.T) {
+ type ekuDescs struct {
+ EKUs []ExtKeyUsage
+ Unknown []asn1.ObjectIdentifier
+ }
+ tests := []struct {
+ name string
+ root ekuDescs
+ inters []ekuDescs
+ leaf ekuDescs
+ verifyEKUs []ExtKeyUsage
+ err string
+ }{
+ {
+ name: "valid, full chain",
+ root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
+ inters: []ekuDescs{ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}}},
+ leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
+ verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ },
+ {
+ name: "valid, only leaf has EKU",
+ root: ekuDescs{},
+ inters: []ekuDescs{ekuDescs{}},
+ leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
+ verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ },
+ {
+ name: "invalid, serverAuth not nested",
+ root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageClientAuth}},
+ inters: []ekuDescs{ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}}},
+ leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}},
+ verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ err: "x509: certificate specifies an incompatible key usage",
+ },
+ {
+ name: "valid, two EKUs, one path",
+ root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
+ inters: []ekuDescs{ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}}},
+ leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}},
+ verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth},
+ },
+ {
+ name: "invalid, ladder",
+ root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
+ inters: []ekuDescs{
+ ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}},
+ ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageClientAuth}},
+ ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth}},
+ ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
+ },
+ leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
+ verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth},
+ err: "x509: certificate specifies an incompatible key usage",
+ },
+ {
+ name: "valid, intermediate has no EKU",
+ root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
+ inters: []ekuDescs{ekuDescs{}},
+ leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
+ verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ },
+ {
+ name: "invalid, intermediate has no EKU and no nested path",
+ root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageClientAuth}},
+ inters: []ekuDescs{ekuDescs{}},
+ leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
+ verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth, ExtKeyUsageClientAuth},
+ err: "x509: certificate specifies an incompatible key usage",
+ },
+ {
+ name: "invalid, intermediate has unknown EKU",
+ root: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
+ inters: []ekuDescs{ekuDescs{Unknown: []asn1.ObjectIdentifier{{1, 2, 3}}}},
+ leaf: ekuDescs{EKUs: []ExtKeyUsage{ExtKeyUsageServerAuth}},
+ verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ err: "x509: certificate specifies an incompatible key usage",
+ },
+ }
+
+ k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatalf("failed to generate test key: %s", err)
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ rootPool := NewCertPool()
+ root := genCertEdge(t, "root", k, func(c *Certificate) {
+ c.ExtKeyUsage = tc.root.EKUs
+ c.UnknownExtKeyUsage = tc.root.Unknown
+ }, rootCertificate, nil, k)
+ rootPool.AddCert(root)
+
+ parent := root
+ interPool := NewCertPool()
+ for i, interEKUs := range tc.inters {
+ inter := genCertEdge(t, fmt.Sprintf("inter %d", i), k, func(c *Certificate) {
+ c.ExtKeyUsage = interEKUs.EKUs
+ c.UnknownExtKeyUsage = interEKUs.Unknown
+ }, intermediateCertificate, parent, k)
+ interPool.AddCert(inter)
+ parent = inter
+ }
+
+ leaf := genCertEdge(t, "leaf", k, func(c *Certificate) {
+ c.ExtKeyUsage = tc.leaf.EKUs
+ c.UnknownExtKeyUsage = tc.leaf.Unknown
+ }, intermediateCertificate, parent, k)
+
+ _, err := leaf.Verify(VerifyOptions{Roots: rootPool, Intermediates: interPool, KeyUsages: tc.verifyEKUs})
+ if err == nil && tc.err != "" {
+ t.Errorf("expected error")
+ } else if err != nil && err.Error() != tc.err {
+ t.Errorf("unexpected error: want %q, got %q", err.Error(), tc.err)
+ }
+ })
+ }
+}
+
+func TestVerifyEKURootAsLeaf(t *testing.T) {
+ k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatalf("failed to generate key: %s", err)
+ }
+
+ for _, tc := range []struct {
+ rootEKUs []ExtKeyUsage
+ verifyEKUs []ExtKeyUsage
+ succeed bool
+ }{
+ {
+ verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ succeed: true,
+ },
+ {
+ rootEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ succeed: true,
+ },
+ {
+ rootEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ succeed: true,
+ },
+ {
+ rootEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ verifyEKUs: []ExtKeyUsage{ExtKeyUsageAny},
+ succeed: true,
+ },
+ {
+ rootEKUs: []ExtKeyUsage{ExtKeyUsageAny},
+ verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ succeed: true,
+ },
+ {
+ rootEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth},
+ verifyEKUs: []ExtKeyUsage{ExtKeyUsageServerAuth},
+ succeed: false,
+ },
+ } {
+ t.Run(fmt.Sprintf("root EKUs %#v, verify EKUs %#v", tc.rootEKUs, tc.verifyEKUs), func(t *testing.T) {
+ tmpl := &Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{CommonName: "root"},
+ NotBefore: time.Now().Add(-time.Hour),
+ NotAfter: time.Now().Add(time.Hour),
+ DNSNames: []string{"localhost"},
+ ExtKeyUsage: tc.rootEKUs,
+ }
+ rootDER, err := CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k)
+ if err != nil {
+ t.Fatalf("failed to create certificate: %s", err)
+ }
+ root, err := ParseCertificate(rootDER)
+ if err != nil {
+ t.Fatalf("failed to parse certificate: %s", err)
+ }
+ roots := NewCertPool()
+ roots.AddCert(root)
+
+ _, err = root.Verify(VerifyOptions{Roots: roots, KeyUsages: tc.verifyEKUs})
+ if err == nil && !tc.succeed {
+ t.Error("verification succeed")
+ } else if err != nil && tc.succeed {
+ t.Errorf("verification failed: %q", err)
+ }
+ })
+ }
+
+}
diff --git a/src/crypto/x509/x509.go b/src/crypto/x509/x509.go
new file mode 100644
index 0000000..36229bb
--- /dev/null
+++ b/src/crypto/x509/x509.go
@@ -0,0 +1,2371 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+// Package x509 implements a subset of the X.509 standard.
+//
+// It allows parsing and generating certificates, certificate signing
+// requests, certificate revocation lists, and encoded public and private keys.
+// It provides a certificate verifier, complete with a chain builder.
+//
+// The package targets the X.509 technical profile defined by the IETF (RFC
+// 2459/3280/5280), and as further restricted by the CA/Browser Forum Baseline
+// Requirements. There is minimal support for features outside of these
+// profiles, as the primary goal of the package is to provide compatibility
+// with the publicly trusted TLS certificate ecosystem and its policies and
+// constraints.
+//
+// On macOS and Windows, certificate verification is handled by system APIs, but
+// the package aims to apply consistent validation rules across operating
+// systems.
+package x509
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/ecdh"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/elliptic"
+ "crypto/rsa"
+ "crypto/sha1"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "encoding/pem"
+ "errors"
+ "fmt"
+ "internal/godebug"
+ "io"
+ "math/big"
+ "net"
+ "net/url"
+ "strconv"
+ "time"
+ "unicode"
+
+ // Explicitly import these for their crypto.RegisterHash init side-effects.
+ // Keep these as blank imports, even if they're imported above.
+ _ "crypto/sha1"
+ _ "crypto/sha256"
+ _ "crypto/sha512"
+
+ "golang.org/x/crypto/cryptobyte"
+ cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
+)
+
+// pkixPublicKey reflects a PKIX public key structure. See SubjectPublicKeyInfo
+// in RFC 3280.
+type pkixPublicKey struct {
+ Algo pkix.AlgorithmIdentifier
+ BitString asn1.BitString
+}
+
+// ParsePKIXPublicKey parses a public key in PKIX, ASN.1 DER form. The encoded
+// public key is a SubjectPublicKeyInfo structure (see RFC 5280, Section 4.1).
+//
+// It returns a *rsa.PublicKey, *dsa.PublicKey, *ecdsa.PublicKey,
+// ed25519.PublicKey (not a pointer), or *ecdh.PublicKey (for X25519).
+// More types might be supported in the future.
+//
+// This kind of key is commonly encoded in PEM blocks of type "PUBLIC KEY".
+func ParsePKIXPublicKey(derBytes []byte) (pub any, err error) {
+ var pki publicKeyInfo
+ if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil {
+ if _, err := asn1.Unmarshal(derBytes, &pkcs1PublicKey{}); err == nil {
+ return nil, errors.New("x509: failed to parse public key (use ParsePKCS1PublicKey instead for this key format)")
+ }
+ return nil, err
+ } else if len(rest) != 0 {
+ return nil, errors.New("x509: trailing data after ASN.1 of public-key")
+ }
+ return parsePublicKey(&pki)
+}
+
+func marshalPublicKey(pub any) (publicKeyBytes []byte, publicKeyAlgorithm pkix.AlgorithmIdentifier, err error) {
+ switch pub := pub.(type) {
+ case *rsa.PublicKey:
+ publicKeyBytes, err = asn1.Marshal(pkcs1PublicKey{
+ N: pub.N,
+ E: pub.E,
+ })
+ if err != nil {
+ return nil, pkix.AlgorithmIdentifier{}, err
+ }
+ publicKeyAlgorithm.Algorithm = oidPublicKeyRSA
+ // This is a NULL parameters value which is required by
+ // RFC 3279, Section 2.3.1.
+ publicKeyAlgorithm.Parameters = asn1.NullRawValue
+ case *ecdsa.PublicKey:
+ oid, ok := oidFromNamedCurve(pub.Curve)
+ if !ok {
+ return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve")
+ }
+ if !pub.Curve.IsOnCurve(pub.X, pub.Y) {
+ return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: invalid elliptic curve public key")
+ }
+ publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y)
+ publicKeyAlgorithm.Algorithm = oidPublicKeyECDSA
+ var paramBytes []byte
+ paramBytes, err = asn1.Marshal(oid)
+ if err != nil {
+ return
+ }
+ publicKeyAlgorithm.Parameters.FullBytes = paramBytes
+ case ed25519.PublicKey:
+ publicKeyBytes = pub
+ publicKeyAlgorithm.Algorithm = oidPublicKeyEd25519
+ case *ecdh.PublicKey:
+ publicKeyBytes = pub.Bytes()
+ if pub.Curve() == ecdh.X25519() {
+ publicKeyAlgorithm.Algorithm = oidPublicKeyX25519
+ } else {
+ oid, ok := oidFromECDHCurve(pub.Curve())
+ if !ok {
+ return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve")
+ }
+ publicKeyAlgorithm.Algorithm = oidPublicKeyECDSA
+ var paramBytes []byte
+ paramBytes, err = asn1.Marshal(oid)
+ if err != nil {
+ return
+ }
+ publicKeyAlgorithm.Parameters.FullBytes = paramBytes
+ }
+ default:
+ return nil, pkix.AlgorithmIdentifier{}, fmt.Errorf("x509: unsupported public key type: %T", pub)
+ }
+
+ return publicKeyBytes, publicKeyAlgorithm, nil
+}
+
+// MarshalPKIXPublicKey converts a public key to PKIX, ASN.1 DER form.
+// The encoded public key is a SubjectPublicKeyInfo structure
+// (see RFC 5280, Section 4.1).
+//
+// The following key types are currently supported: *rsa.PublicKey,
+// *ecdsa.PublicKey, ed25519.PublicKey (not a pointer), and *ecdh.PublicKey.
+// Unsupported key types result in an error.
+//
+// This kind of key is commonly encoded in PEM blocks of type "PUBLIC KEY".
+func MarshalPKIXPublicKey(pub any) ([]byte, error) {
+ var publicKeyBytes []byte
+ var publicKeyAlgorithm pkix.AlgorithmIdentifier
+ var err error
+
+ if publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(pub); err != nil {
+ return nil, err
+ }
+
+ pkix := pkixPublicKey{
+ Algo: publicKeyAlgorithm,
+ BitString: asn1.BitString{
+ Bytes: publicKeyBytes,
+ BitLength: 8 * len(publicKeyBytes),
+ },
+ }
+
+ ret, _ := asn1.Marshal(pkix)
+ return ret, nil
+}
+
+// These structures reflect the ASN.1 structure of X.509 certificates.:
+
+type certificate struct {
+ TBSCertificate tbsCertificate
+ SignatureAlgorithm pkix.AlgorithmIdentifier
+ SignatureValue asn1.BitString
+}
+
+type tbsCertificate struct {
+ Raw asn1.RawContent
+ Version int `asn1:"optional,explicit,default:0,tag:0"`
+ SerialNumber *big.Int
+ SignatureAlgorithm pkix.AlgorithmIdentifier
+ Issuer asn1.RawValue
+ Validity validity
+ Subject asn1.RawValue
+ PublicKey publicKeyInfo
+ UniqueId asn1.BitString `asn1:"optional,tag:1"`
+ SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"`
+ Extensions []pkix.Extension `asn1:"omitempty,optional,explicit,tag:3"`
+}
+
+type dsaAlgorithmParameters struct {
+ P, Q, G *big.Int
+}
+
+type validity struct {
+ NotBefore, NotAfter time.Time
+}
+
+type publicKeyInfo struct {
+ Raw asn1.RawContent
+ Algorithm pkix.AlgorithmIdentifier
+ PublicKey asn1.BitString
+}
+
+// RFC 5280, 4.2.1.1
+type authKeyId struct {
+ Id []byte `asn1:"optional,tag:0"`
+}
+
+type SignatureAlgorithm int
+
+const (
+ UnknownSignatureAlgorithm SignatureAlgorithm = iota
+
+ MD2WithRSA // Unsupported.
+ MD5WithRSA // Only supported for signing, not verification.
+ SHA1WithRSA // Only supported for signing, and verification of CRLs, CSRs, and OCSP responses.
+ SHA256WithRSA
+ SHA384WithRSA
+ SHA512WithRSA
+ DSAWithSHA1 // Unsupported.
+ DSAWithSHA256 // Unsupported.
+ ECDSAWithSHA1 // Only supported for signing, and verification of CRLs, CSRs, and OCSP responses.
+ ECDSAWithSHA256
+ ECDSAWithSHA384
+ ECDSAWithSHA512
+ SHA256WithRSAPSS
+ SHA384WithRSAPSS
+ SHA512WithRSAPSS
+ PureEd25519
+)
+
+func (algo SignatureAlgorithm) isRSAPSS() bool {
+ switch algo {
+ case SHA256WithRSAPSS, SHA384WithRSAPSS, SHA512WithRSAPSS:
+ return true
+ default:
+ return false
+ }
+}
+
+func (algo SignatureAlgorithm) String() string {
+ for _, details := range signatureAlgorithmDetails {
+ if details.algo == algo {
+ return details.name
+ }
+ }
+ return strconv.Itoa(int(algo))
+}
+
+type PublicKeyAlgorithm int
+
+const (
+ UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota
+ RSA
+ DSA // Only supported for parsing.
+ ECDSA
+ Ed25519
+)
+
+var publicKeyAlgoName = [...]string{
+ RSA: "RSA",
+ DSA: "DSA",
+ ECDSA: "ECDSA",
+ Ed25519: "Ed25519",
+}
+
+func (algo PublicKeyAlgorithm) String() string {
+ if 0 < algo && int(algo) < len(publicKeyAlgoName) {
+ return publicKeyAlgoName[algo]
+ }
+ return strconv.Itoa(int(algo))
+}
+
+// OIDs for signature algorithms
+//
+// pkcs-1 OBJECT IDENTIFIER ::= {
+// iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
+//
+// RFC 3279 2.2.1 RSA Signature Algorithms
+//
+// md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
+//
+// md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
+//
+// sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
+//
+// dsaWithSha1 OBJECT IDENTIFIER ::= {
+// iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 }
+//
+// RFC 3279 2.2.3 ECDSA Signature Algorithm
+//
+// ecdsa-with-SHA1 OBJECT IDENTIFIER ::= {
+// iso(1) member-body(2) us(840) ansi-x962(10045)
+// signatures(4) ecdsa-with-SHA1(1)}
+//
+// RFC 4055 5 PKCS #1 Version 1.5
+//
+// sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }
+//
+// sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 }
+//
+// sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
+//
+// RFC 5758 3.1 DSA Signature Algorithms
+//
+// dsaWithSha256 OBJECT IDENTIFIER ::= {
+// joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101)
+// csor(3) algorithms(4) id-dsa-with-sha2(3) 2}
+//
+// RFC 5758 3.2 ECDSA Signature Algorithm
+//
+// ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 }
+//
+// ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 }
+//
+// ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2)
+// us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 }
+//
+// RFC 8410 3 Curve25519 and Curve448 Algorithm Identifiers
+//
+// id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 }
+var (
+ oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
+ oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
+ oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5}
+ oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11}
+ oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12}
+ oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13}
+ oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10}
+ oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3}
+ oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2}
+ oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1}
+ oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2}
+ oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3}
+ oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
+ oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112}
+
+ oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1}
+ oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2}
+ oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3}
+
+ oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8}
+
+ // oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA
+ // but it's specified by ISO. Microsoft's makecert.exe has been known
+ // to produce certificates with this OID.
+ oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29}
+)
+
+var signatureAlgorithmDetails = []struct {
+ algo SignatureAlgorithm
+ name string
+ oid asn1.ObjectIdentifier
+ pubKeyAlgo PublicKeyAlgorithm
+ hash crypto.Hash
+}{
+ {MD2WithRSA, "MD2-RSA", oidSignatureMD2WithRSA, RSA, crypto.Hash(0) /* no value for MD2 */},
+ {MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, RSA, crypto.MD5},
+ {SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, RSA, crypto.SHA1},
+ {SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, RSA, crypto.SHA1},
+ {SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, RSA, crypto.SHA256},
+ {SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, RSA, crypto.SHA384},
+ {SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, RSA, crypto.SHA512},
+ {SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA256},
+ {SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA384},
+ {SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, RSA, crypto.SHA512},
+ {DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, DSA, crypto.SHA1},
+ {DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, DSA, crypto.SHA256},
+ {ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, ECDSA, crypto.SHA1},
+ {ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, ECDSA, crypto.SHA256},
+ {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384},
+ {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512},
+ {PureEd25519, "Ed25519", oidSignatureEd25519, Ed25519, crypto.Hash(0) /* no pre-hashing */},
+}
+
+// hashToPSSParameters contains the DER encoded RSA PSS parameters for the
+// SHA256, SHA384, and SHA512 hashes as defined in RFC 3447, Appendix A.2.3.
+// The parameters contain the following values:
+// - hashAlgorithm contains the associated hash identifier with NULL parameters
+// - maskGenAlgorithm always contains the default mgf1SHA1 identifier
+// - saltLength contains the length of the associated hash
+// - trailerField always contains the default trailerFieldBC value
+var hashToPSSParameters = map[crypto.Hash]asn1.RawValue{
+ crypto.SHA256: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 162, 3, 2, 1, 32}},
+ crypto.SHA384: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 162, 3, 2, 1, 48}},
+ crypto.SHA512: asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 162, 3, 2, 1, 64}},
+}
+
+// pssParameters reflects the parameters in an AlgorithmIdentifier that
+// specifies RSA PSS. See RFC 3447, Appendix A.2.3.
+type pssParameters struct {
+ // The following three fields are not marked as
+ // optional because the default values specify SHA-1,
+ // which is no longer suitable for use in signatures.
+ Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"`
+ MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"`
+ SaltLength int `asn1:"explicit,tag:2"`
+ TrailerField int `asn1:"optional,explicit,tag:3,default:1"`
+}
+
+func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) SignatureAlgorithm {
+ if ai.Algorithm.Equal(oidSignatureEd25519) {
+ // RFC 8410, Section 3
+ // > For all of the OIDs, the parameters MUST be absent.
+ if len(ai.Parameters.FullBytes) != 0 {
+ return UnknownSignatureAlgorithm
+ }
+ }
+
+ if !ai.Algorithm.Equal(oidSignatureRSAPSS) {
+ for _, details := range signatureAlgorithmDetails {
+ if ai.Algorithm.Equal(details.oid) {
+ return details.algo
+ }
+ }
+ return UnknownSignatureAlgorithm
+ }
+
+ // RSA PSS is special because it encodes important parameters
+ // in the Parameters.
+
+ var params pssParameters
+ if _, err := asn1.Unmarshal(ai.Parameters.FullBytes, &params); err != nil {
+ return UnknownSignatureAlgorithm
+ }
+
+ var mgf1HashFunc pkix.AlgorithmIdentifier
+ if _, err := asn1.Unmarshal(params.MGF.Parameters.FullBytes, &mgf1HashFunc); err != nil {
+ return UnknownSignatureAlgorithm
+ }
+
+ // PSS is greatly overburdened with options. This code forces them into
+ // three buckets by requiring that the MGF1 hash function always match the
+ // message hash function (as recommended in RFC 3447, Section 8.1), that the
+ // salt length matches the hash length, and that the trailer field has the
+ // default value.
+ if (len(params.Hash.Parameters.FullBytes) != 0 && !bytes.Equal(params.Hash.Parameters.FullBytes, asn1.NullBytes)) ||
+ !params.MGF.Algorithm.Equal(oidMGF1) ||
+ !mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) ||
+ (len(mgf1HashFunc.Parameters.FullBytes) != 0 && !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1.NullBytes)) ||
+ params.TrailerField != 1 {
+ return UnknownSignatureAlgorithm
+ }
+
+ switch {
+ case params.Hash.Algorithm.Equal(oidSHA256) && params.SaltLength == 32:
+ return SHA256WithRSAPSS
+ case params.Hash.Algorithm.Equal(oidSHA384) && params.SaltLength == 48:
+ return SHA384WithRSAPSS
+ case params.Hash.Algorithm.Equal(oidSHA512) && params.SaltLength == 64:
+ return SHA512WithRSAPSS
+ }
+
+ return UnknownSignatureAlgorithm
+}
+
+var (
+ // RFC 3279, 2.3 Public Key Algorithms
+ //
+ // pkcs-1 OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840)
+ // rsadsi(113549) pkcs(1) 1 }
+ //
+ // rsaEncryption OBJECT IDENTIFIER ::== { pkcs1-1 1 }
+ //
+ // id-dsa OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840)
+ // x9-57(10040) x9cm(4) 1 }
+ oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
+ oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}
+ // RFC 5480, 2.1.1 Unrestricted Algorithm Identifier and Parameters
+ //
+ // id-ecPublicKey OBJECT IDENTIFIER ::= {
+ // iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 }
+ oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
+ // RFC 8410, Section 3
+ //
+ // id-X25519 OBJECT IDENTIFIER ::= { 1 3 101 110 }
+ // id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 }
+ oidPublicKeyX25519 = asn1.ObjectIdentifier{1, 3, 101, 110}
+ oidPublicKeyEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112}
+)
+
+// getPublicKeyAlgorithmFromOID returns the exposed PublicKeyAlgorithm
+// identifier for public key types supported in certificates and CSRs. Marshal
+// and Parse functions may support a different set of public key types.
+func getPublicKeyAlgorithmFromOID(oid asn1.ObjectIdentifier) PublicKeyAlgorithm {
+ switch {
+ case oid.Equal(oidPublicKeyRSA):
+ return RSA
+ case oid.Equal(oidPublicKeyDSA):
+ return DSA
+ case oid.Equal(oidPublicKeyECDSA):
+ return ECDSA
+ case oid.Equal(oidPublicKeyEd25519):
+ return Ed25519
+ }
+ return UnknownPublicKeyAlgorithm
+}
+
+// RFC 5480, 2.1.1.1. Named Curve
+//
+// secp224r1 OBJECT IDENTIFIER ::= {
+// iso(1) identified-organization(3) certicom(132) curve(0) 33 }
+//
+// secp256r1 OBJECT IDENTIFIER ::= {
+// iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3)
+// prime(1) 7 }
+//
+// secp384r1 OBJECT IDENTIFIER ::= {
+// iso(1) identified-organization(3) certicom(132) curve(0) 34 }
+//
+// secp521r1 OBJECT IDENTIFIER ::= {
+// iso(1) identified-organization(3) certicom(132) curve(0) 35 }
+//
+// NB: secp256r1 is equivalent to prime256v1
+var (
+ oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33}
+ oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7}
+ oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34}
+ oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35}
+)
+
+func namedCurveFromOID(oid asn1.ObjectIdentifier) elliptic.Curve {
+ switch {
+ case oid.Equal(oidNamedCurveP224):
+ return elliptic.P224()
+ case oid.Equal(oidNamedCurveP256):
+ return elliptic.P256()
+ case oid.Equal(oidNamedCurveP384):
+ return elliptic.P384()
+ case oid.Equal(oidNamedCurveP521):
+ return elliptic.P521()
+ }
+ return nil
+}
+
+func oidFromNamedCurve(curve elliptic.Curve) (asn1.ObjectIdentifier, bool) {
+ switch curve {
+ case elliptic.P224():
+ return oidNamedCurveP224, true
+ case elliptic.P256():
+ return oidNamedCurveP256, true
+ case elliptic.P384():
+ return oidNamedCurveP384, true
+ case elliptic.P521():
+ return oidNamedCurveP521, true
+ }
+
+ return nil, false
+}
+
+func oidFromECDHCurve(curve ecdh.Curve) (asn1.ObjectIdentifier, bool) {
+ switch curve {
+ case ecdh.X25519():
+ return oidPublicKeyX25519, true
+ case ecdh.P256():
+ return oidNamedCurveP256, true
+ case ecdh.P384():
+ return oidNamedCurveP384, true
+ case ecdh.P521():
+ return oidNamedCurveP521, true
+ }
+
+ return nil, false
+}
+
+// KeyUsage represents the set of actions that are valid for a given key. It's
+// a bitmap of the KeyUsage* constants.
+type KeyUsage int
+
+const (
+ KeyUsageDigitalSignature KeyUsage = 1 << iota
+ KeyUsageContentCommitment
+ KeyUsageKeyEncipherment
+ KeyUsageDataEncipherment
+ KeyUsageKeyAgreement
+ KeyUsageCertSign
+ KeyUsageCRLSign
+ KeyUsageEncipherOnly
+ KeyUsageDecipherOnly
+)
+
+// RFC 5280, 4.2.1.12 Extended Key Usage
+//
+// anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 }
+//
+// id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }
+//
+// id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 }
+// id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 }
+// id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 }
+// id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 }
+// id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 }
+// id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 }
+var (
+ oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0}
+ oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1}
+ oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2}
+ oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3}
+ oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4}
+ oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5}
+ oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6}
+ oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7}
+ oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8}
+ oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9}
+ oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3}
+ oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1}
+ oidExtKeyUsageMicrosoftCommercialCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 2, 1, 22}
+ oidExtKeyUsageMicrosoftKernelCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 61, 1, 1}
+)
+
+// ExtKeyUsage represents an extended set of actions that are valid for a given key.
+// Each of the ExtKeyUsage* constants define a unique action.
+type ExtKeyUsage int
+
+const (
+ ExtKeyUsageAny ExtKeyUsage = iota
+ ExtKeyUsageServerAuth
+ ExtKeyUsageClientAuth
+ ExtKeyUsageCodeSigning
+ ExtKeyUsageEmailProtection
+ ExtKeyUsageIPSECEndSystem
+ ExtKeyUsageIPSECTunnel
+ ExtKeyUsageIPSECUser
+ ExtKeyUsageTimeStamping
+ ExtKeyUsageOCSPSigning
+ ExtKeyUsageMicrosoftServerGatedCrypto
+ ExtKeyUsageNetscapeServerGatedCrypto
+ ExtKeyUsageMicrosoftCommercialCodeSigning
+ ExtKeyUsageMicrosoftKernelCodeSigning
+)
+
+// extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID.
+var extKeyUsageOIDs = []struct {
+ extKeyUsage ExtKeyUsage
+ oid asn1.ObjectIdentifier
+}{
+ {ExtKeyUsageAny, oidExtKeyUsageAny},
+ {ExtKeyUsageServerAuth, oidExtKeyUsageServerAuth},
+ {ExtKeyUsageClientAuth, oidExtKeyUsageClientAuth},
+ {ExtKeyUsageCodeSigning, oidExtKeyUsageCodeSigning},
+ {ExtKeyUsageEmailProtection, oidExtKeyUsageEmailProtection},
+ {ExtKeyUsageIPSECEndSystem, oidExtKeyUsageIPSECEndSystem},
+ {ExtKeyUsageIPSECTunnel, oidExtKeyUsageIPSECTunnel},
+ {ExtKeyUsageIPSECUser, oidExtKeyUsageIPSECUser},
+ {ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping},
+ {ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning},
+ {ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto},
+ {ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto},
+ {ExtKeyUsageMicrosoftCommercialCodeSigning, oidExtKeyUsageMicrosoftCommercialCodeSigning},
+ {ExtKeyUsageMicrosoftKernelCodeSigning, oidExtKeyUsageMicrosoftKernelCodeSigning},
+}
+
+func extKeyUsageFromOID(oid asn1.ObjectIdentifier) (eku ExtKeyUsage, ok bool) {
+ for _, pair := range extKeyUsageOIDs {
+ if oid.Equal(pair.oid) {
+ return pair.extKeyUsage, true
+ }
+ }
+ return
+}
+
+func oidFromExtKeyUsage(eku ExtKeyUsage) (oid asn1.ObjectIdentifier, ok bool) {
+ for _, pair := range extKeyUsageOIDs {
+ if eku == pair.extKeyUsage {
+ return pair.oid, true
+ }
+ }
+ return
+}
+
+// A Certificate represents an X.509 certificate.
+type Certificate struct {
+ Raw []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature).
+ RawTBSCertificate []byte // Certificate part of raw ASN.1 DER content.
+ RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo.
+ RawSubject []byte // DER encoded Subject
+ RawIssuer []byte // DER encoded Issuer
+
+ Signature []byte
+ SignatureAlgorithm SignatureAlgorithm
+
+ PublicKeyAlgorithm PublicKeyAlgorithm
+ PublicKey any
+
+ Version int
+ SerialNumber *big.Int
+ Issuer pkix.Name
+ Subject pkix.Name
+ NotBefore, NotAfter time.Time // Validity bounds.
+ KeyUsage KeyUsage
+
+ // Extensions contains raw X.509 extensions. When parsing certificates,
+ // this can be used to extract non-critical extensions that are not
+ // parsed by this package. When marshaling certificates, the Extensions
+ // field is ignored, see ExtraExtensions.
+ Extensions []pkix.Extension
+
+ // ExtraExtensions contains extensions to be copied, raw, into any
+ // marshaled certificates. Values override any extensions that would
+ // otherwise be produced based on the other fields. The ExtraExtensions
+ // field is not populated when parsing certificates, see Extensions.
+ ExtraExtensions []pkix.Extension
+
+ // UnhandledCriticalExtensions contains a list of extension IDs that
+ // were not (fully) processed when parsing. Verify will fail if this
+ // slice is non-empty, unless verification is delegated to an OS
+ // library which understands all the critical extensions.
+ //
+ // Users can access these extensions using Extensions and can remove
+ // elements from this slice if they believe that they have been
+ // handled.
+ UnhandledCriticalExtensions []asn1.ObjectIdentifier
+
+ ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages.
+ UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package.
+
+ // BasicConstraintsValid indicates whether IsCA, MaxPathLen,
+ // and MaxPathLenZero are valid.
+ BasicConstraintsValid bool
+ IsCA bool
+
+ // MaxPathLen and MaxPathLenZero indicate the presence and
+ // value of the BasicConstraints' "pathLenConstraint".
+ //
+ // When parsing a certificate, a positive non-zero MaxPathLen
+ // means that the field was specified, -1 means it was unset,
+ // and MaxPathLenZero being true mean that the field was
+ // explicitly set to zero. The case of MaxPathLen==0 with MaxPathLenZero==false
+ // should be treated equivalent to -1 (unset).
+ //
+ // When generating a certificate, an unset pathLenConstraint
+ // can be requested with either MaxPathLen == -1 or using the
+ // zero value for both MaxPathLen and MaxPathLenZero.
+ MaxPathLen int
+ // MaxPathLenZero indicates that BasicConstraintsValid==true
+ // and MaxPathLen==0 should be interpreted as an actual
+ // maximum path length of zero. Otherwise, that combination is
+ // interpreted as MaxPathLen not being set.
+ MaxPathLenZero bool
+
+ SubjectKeyId []byte
+ AuthorityKeyId []byte
+
+ // RFC 5280, 4.2.2.1 (Authority Information Access)
+ OCSPServer []string
+ IssuingCertificateURL []string
+
+ // Subject Alternate Name values. (Note that these values may not be valid
+ // if invalid values were contained within a parsed certificate. For
+ // example, an element of DNSNames may not be a valid DNS domain name.)
+ DNSNames []string
+ EmailAddresses []string
+ IPAddresses []net.IP
+ URIs []*url.URL
+
+ // Name constraints
+ PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical.
+ PermittedDNSDomains []string
+ ExcludedDNSDomains []string
+ PermittedIPRanges []*net.IPNet
+ ExcludedIPRanges []*net.IPNet
+ PermittedEmailAddresses []string
+ ExcludedEmailAddresses []string
+ PermittedURIDomains []string
+ ExcludedURIDomains []string
+
+ // CRL Distribution Points
+ CRLDistributionPoints []string
+
+ PolicyIdentifiers []asn1.ObjectIdentifier
+}
+
+// ErrUnsupportedAlgorithm results from attempting to perform an operation that
+// involves algorithms that are not currently implemented.
+var ErrUnsupportedAlgorithm = errors.New("x509: cannot verify signature: algorithm unimplemented")
+
+// An InsecureAlgorithmError indicates that the SignatureAlgorithm used to
+// generate the signature is not secure, and the signature has been rejected.
+//
+// To temporarily restore support for SHA-1 signatures, include the value
+// "x509sha1=1" in the GODEBUG environment variable. Note that this option will
+// be removed in a future release.
+type InsecureAlgorithmError SignatureAlgorithm
+
+func (e InsecureAlgorithmError) Error() string {
+ var override string
+ if SignatureAlgorithm(e) == SHA1WithRSA || SignatureAlgorithm(e) == ECDSAWithSHA1 {
+ override = " (temporarily override with GODEBUG=x509sha1=1)"
+ }
+ return fmt.Sprintf("x509: cannot verify signature: insecure algorithm %v", SignatureAlgorithm(e)) + override
+}
+
+// ConstraintViolationError results when a requested usage is not permitted by
+// a certificate. For example: checking a signature when the public key isn't a
+// certificate signing key.
+type ConstraintViolationError struct{}
+
+func (ConstraintViolationError) Error() string {
+ return "x509: invalid signature: parent certificate cannot sign this kind of certificate"
+}
+
+func (c *Certificate) Equal(other *Certificate) bool {
+ if c == nil || other == nil {
+ return c == other
+ }
+ return bytes.Equal(c.Raw, other.Raw)
+}
+
+func (c *Certificate) hasSANExtension() bool {
+ return oidInExtensions(oidExtensionSubjectAltName, c.Extensions)
+}
+
+// CheckSignatureFrom verifies that the signature on c is a valid signature from parent.
+//
+// This is a low-level API that performs very limited checks, and not a full
+// path verifier. Most users should use [Certificate.Verify] instead.
+func (c *Certificate) CheckSignatureFrom(parent *Certificate) error {
+ // RFC 5280, 4.2.1.9:
+ // "If the basic constraints extension is not present in a version 3
+ // certificate, or the extension is present but the cA boolean is not
+ // asserted, then the certified public key MUST NOT be used to verify
+ // certificate signatures."
+ if parent.Version == 3 && !parent.BasicConstraintsValid ||
+ parent.BasicConstraintsValid && !parent.IsCA {
+ return ConstraintViolationError{}
+ }
+
+ if parent.KeyUsage != 0 && parent.KeyUsage&KeyUsageCertSign == 0 {
+ return ConstraintViolationError{}
+ }
+
+ if parent.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm {
+ return ErrUnsupportedAlgorithm
+ }
+
+ return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature, parent.PublicKey, false)
+}
+
+// CheckSignature verifies that signature is a valid signature over signed from
+// c's public key.
+//
+// This is a low-level API that performs no validity checks on the certificate.
+//
+// [MD5WithRSA] signatures are rejected, while [SHA1WithRSA] and [ECDSAWithSHA1]
+// signatures are currently accepted.
+func (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) error {
+ return checkSignature(algo, signed, signature, c.PublicKey, true)
+}
+
+func (c *Certificate) hasNameConstraints() bool {
+ return oidInExtensions(oidExtensionNameConstraints, c.Extensions)
+}
+
+func (c *Certificate) getSANExtension() []byte {
+ for _, e := range c.Extensions {
+ if e.Id.Equal(oidExtensionSubjectAltName) {
+ return e.Value
+ }
+ }
+ return nil
+}
+
+func signaturePublicKeyAlgoMismatchError(expectedPubKeyAlgo PublicKeyAlgorithm, pubKey any) error {
+ return fmt.Errorf("x509: signature algorithm specifies an %s public key, but have public key of type %T", expectedPubKeyAlgo.String(), pubKey)
+}
+
+var x509sha1 = godebug.New("x509sha1")
+
+// checkSignature verifies that signature is a valid signature over signed from
+// a crypto.PublicKey.
+func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey, allowSHA1 bool) (err error) {
+ var hashType crypto.Hash
+ var pubKeyAlgo PublicKeyAlgorithm
+
+ for _, details := range signatureAlgorithmDetails {
+ if details.algo == algo {
+ hashType = details.hash
+ pubKeyAlgo = details.pubKeyAlgo
+ }
+ }
+
+ switch hashType {
+ case crypto.Hash(0):
+ if pubKeyAlgo != Ed25519 {
+ return ErrUnsupportedAlgorithm
+ }
+ case crypto.MD5:
+ return InsecureAlgorithmError(algo)
+ case crypto.SHA1:
+ // SHA-1 signatures are mostly disabled. See go.dev/issue/41682.
+ if !allowSHA1 && x509sha1.Value() != "1" {
+ return InsecureAlgorithmError(algo)
+ }
+ fallthrough
+ default:
+ if !hashType.Available() {
+ return ErrUnsupportedAlgorithm
+ }
+ h := hashType.New()
+ h.Write(signed)
+ signed = h.Sum(nil)
+ }
+
+ switch pub := publicKey.(type) {
+ case *rsa.PublicKey:
+ if pubKeyAlgo != RSA {
+ return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub)
+ }
+ if algo.isRSAPSS() {
+ return rsa.VerifyPSS(pub, hashType, signed, signature, &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash})
+ } else {
+ return rsa.VerifyPKCS1v15(pub, hashType, signed, signature)
+ }
+ case *ecdsa.PublicKey:
+ if pubKeyAlgo != ECDSA {
+ return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub)
+ }
+ if !ecdsa.VerifyASN1(pub, signed, signature) {
+ return errors.New("x509: ECDSA verification failure")
+ }
+ return
+ case ed25519.PublicKey:
+ if pubKeyAlgo != Ed25519 {
+ return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub)
+ }
+ if !ed25519.Verify(pub, signed, signature) {
+ return errors.New("x509: Ed25519 verification failure")
+ }
+ return
+ }
+ return ErrUnsupportedAlgorithm
+}
+
+// CheckCRLSignature checks that the signature in crl is from c.
+//
+// Deprecated: Use RevocationList.CheckSignatureFrom instead.
+func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) error {
+ algo := getSignatureAlgorithmFromAI(crl.SignatureAlgorithm)
+ return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign())
+}
+
+type UnhandledCriticalExtension struct{}
+
+func (h UnhandledCriticalExtension) Error() string {
+ return "x509: unhandled critical extension"
+}
+
+type basicConstraints struct {
+ IsCA bool `asn1:"optional"`
+ MaxPathLen int `asn1:"optional,default:-1"`
+}
+
+// RFC 5280 4.2.1.4
+type policyInformation struct {
+ Policy asn1.ObjectIdentifier
+ // policyQualifiers omitted
+}
+
+const (
+ nameTypeEmail = 1
+ nameTypeDNS = 2
+ nameTypeURI = 6
+ nameTypeIP = 7
+)
+
+// RFC 5280, 4.2.2.1
+type authorityInfoAccess struct {
+ Method asn1.ObjectIdentifier
+ Location asn1.RawValue
+}
+
+// RFC 5280, 4.2.1.14
+type distributionPoint struct {
+ DistributionPoint distributionPointName `asn1:"optional,tag:0"`
+ Reason asn1.BitString `asn1:"optional,tag:1"`
+ CRLIssuer asn1.RawValue `asn1:"optional,tag:2"`
+}
+
+type distributionPointName struct {
+ FullName []asn1.RawValue `asn1:"optional,tag:0"`
+ RelativeName pkix.RDNSequence `asn1:"optional,tag:1"`
+}
+
+func reverseBitsInAByte(in byte) byte {
+ b1 := in>>4 | in<<4
+ b2 := b1>>2&0x33 | b1<<2&0xcc
+ b3 := b2>>1&0x55 | b2<<1&0xaa
+ return b3
+}
+
+// asn1BitLength returns the bit-length of bitString by considering the
+// most-significant bit in a byte to be the "first" bit. This convention
+// matches ASN.1, but differs from almost everything else.
+func asn1BitLength(bitString []byte) int {
+ bitLen := len(bitString) * 8
+
+ for i := range bitString {
+ b := bitString[len(bitString)-i-1]
+
+ for bit := uint(0); bit < 8; bit++ {
+ if (b>>bit)&1 == 1 {
+ return bitLen
+ }
+ bitLen--
+ }
+ }
+
+ return 0
+}
+
+var (
+ oidExtensionSubjectKeyId = []int{2, 5, 29, 14}
+ oidExtensionKeyUsage = []int{2, 5, 29, 15}
+ oidExtensionExtendedKeyUsage = []int{2, 5, 29, 37}
+ oidExtensionAuthorityKeyId = []int{2, 5, 29, 35}
+ oidExtensionBasicConstraints = []int{2, 5, 29, 19}
+ oidExtensionSubjectAltName = []int{2, 5, 29, 17}
+ oidExtensionCertificatePolicies = []int{2, 5, 29, 32}
+ oidExtensionNameConstraints = []int{2, 5, 29, 30}
+ oidExtensionCRLDistributionPoints = []int{2, 5, 29, 31}
+ oidExtensionAuthorityInfoAccess = []int{1, 3, 6, 1, 5, 5, 7, 1, 1}
+ oidExtensionCRLNumber = []int{2, 5, 29, 20}
+)
+
+var (
+ oidAuthorityInfoAccessOcsp = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1}
+ oidAuthorityInfoAccessIssuers = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 2}
+)
+
+// oidInExtensions reports whether an extension with the given oid exists in
+// extensions.
+func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) bool {
+ for _, e := range extensions {
+ if e.Id.Equal(oid) {
+ return true
+ }
+ }
+ return false
+}
+
+// marshalSANs marshals a list of addresses into a the contents of an X.509
+// SubjectAlternativeName extension.
+func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL) (derBytes []byte, err error) {
+ var rawValues []asn1.RawValue
+ for _, name := range dnsNames {
+ if err := isIA5String(name); err != nil {
+ return nil, err
+ }
+ rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeDNS, Class: 2, Bytes: []byte(name)})
+ }
+ for _, email := range emailAddresses {
+ if err := isIA5String(email); err != nil {
+ return nil, err
+ }
+ rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeEmail, Class: 2, Bytes: []byte(email)})
+ }
+ for _, rawIP := range ipAddresses {
+ // If possible, we always want to encode IPv4 addresses in 4 bytes.
+ ip := rawIP.To4()
+ if ip == nil {
+ ip = rawIP
+ }
+ rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeIP, Class: 2, Bytes: ip})
+ }
+ for _, uri := range uris {
+ uriStr := uri.String()
+ if err := isIA5String(uriStr); err != nil {
+ return nil, err
+ }
+ rawValues = append(rawValues, asn1.RawValue{Tag: nameTypeURI, Class: 2, Bytes: []byte(uriStr)})
+ }
+ return asn1.Marshal(rawValues)
+}
+
+func isIA5String(s string) error {
+ for _, r := range s {
+ // Per RFC5280 "IA5String is limited to the set of ASCII characters"
+ if r > unicode.MaxASCII {
+ return fmt.Errorf("x509: %q cannot be encoded as an IA5String", s)
+ }
+ }
+
+ return nil
+}
+
+func buildCertExtensions(template *Certificate, subjectIsEmpty bool, authorityKeyId []byte, subjectKeyId []byte) (ret []pkix.Extension, err error) {
+ ret = make([]pkix.Extension, 10 /* maximum number of elements. */)
+ n := 0
+
+ if template.KeyUsage != 0 &&
+ !oidInExtensions(oidExtensionKeyUsage, template.ExtraExtensions) {
+ ret[n], err = marshalKeyUsage(template.KeyUsage)
+ if err != nil {
+ return nil, err
+ }
+ n++
+ }
+
+ if (len(template.ExtKeyUsage) > 0 || len(template.UnknownExtKeyUsage) > 0) &&
+ !oidInExtensions(oidExtensionExtendedKeyUsage, template.ExtraExtensions) {
+ ret[n], err = marshalExtKeyUsage(template.ExtKeyUsage, template.UnknownExtKeyUsage)
+ if err != nil {
+ return nil, err
+ }
+ n++
+ }
+
+ if template.BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, template.ExtraExtensions) {
+ ret[n], err = marshalBasicConstraints(template.IsCA, template.MaxPathLen, template.MaxPathLenZero)
+ if err != nil {
+ return nil, err
+ }
+ n++
+ }
+
+ if len(subjectKeyId) > 0 && !oidInExtensions(oidExtensionSubjectKeyId, template.ExtraExtensions) {
+ ret[n].Id = oidExtensionSubjectKeyId
+ ret[n].Value, err = asn1.Marshal(subjectKeyId)
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ if len(authorityKeyId) > 0 && !oidInExtensions(oidExtensionAuthorityKeyId, template.ExtraExtensions) {
+ ret[n].Id = oidExtensionAuthorityKeyId
+ ret[n].Value, err = asn1.Marshal(authKeyId{authorityKeyId})
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ if (len(template.OCSPServer) > 0 || len(template.IssuingCertificateURL) > 0) &&
+ !oidInExtensions(oidExtensionAuthorityInfoAccess, template.ExtraExtensions) {
+ ret[n].Id = oidExtensionAuthorityInfoAccess
+ var aiaValues []authorityInfoAccess
+ for _, name := range template.OCSPServer {
+ aiaValues = append(aiaValues, authorityInfoAccess{
+ Method: oidAuthorityInfoAccessOcsp,
+ Location: asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)},
+ })
+ }
+ for _, name := range template.IssuingCertificateURL {
+ aiaValues = append(aiaValues, authorityInfoAccess{
+ Method: oidAuthorityInfoAccessIssuers,
+ Location: asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte(name)},
+ })
+ }
+ ret[n].Value, err = asn1.Marshal(aiaValues)
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) &&
+ !oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
+ ret[n].Id = oidExtensionSubjectAltName
+ // From RFC 5280, Section 4.2.1.6:
+ // “If the subject field contains an empty sequence ... then
+ // subjectAltName extension ... is marked as critical”
+ ret[n].Critical = subjectIsEmpty
+ ret[n].Value, err = marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses, template.URIs)
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ if len(template.PolicyIdentifiers) > 0 &&
+ !oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) {
+ ret[n], err = marshalCertificatePolicies(template.PolicyIdentifiers)
+ if err != nil {
+ return nil, err
+ }
+ n++
+ }
+
+ if (len(template.PermittedDNSDomains) > 0 || len(template.ExcludedDNSDomains) > 0 ||
+ len(template.PermittedIPRanges) > 0 || len(template.ExcludedIPRanges) > 0 ||
+ len(template.PermittedEmailAddresses) > 0 || len(template.ExcludedEmailAddresses) > 0 ||
+ len(template.PermittedURIDomains) > 0 || len(template.ExcludedURIDomains) > 0) &&
+ !oidInExtensions(oidExtensionNameConstraints, template.ExtraExtensions) {
+ ret[n].Id = oidExtensionNameConstraints
+ ret[n].Critical = template.PermittedDNSDomainsCritical
+
+ ipAndMask := func(ipNet *net.IPNet) []byte {
+ maskedIP := ipNet.IP.Mask(ipNet.Mask)
+ ipAndMask := make([]byte, 0, len(maskedIP)+len(ipNet.Mask))
+ ipAndMask = append(ipAndMask, maskedIP...)
+ ipAndMask = append(ipAndMask, ipNet.Mask...)
+ return ipAndMask
+ }
+
+ serialiseConstraints := func(dns []string, ips []*net.IPNet, emails []string, uriDomains []string) (der []byte, err error) {
+ var b cryptobyte.Builder
+
+ for _, name := range dns {
+ if err = isIA5String(name); err != nil {
+ return nil, err
+ }
+
+ b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
+ b.AddASN1(cryptobyte_asn1.Tag(2).ContextSpecific(), func(b *cryptobyte.Builder) {
+ b.AddBytes([]byte(name))
+ })
+ })
+ }
+
+ for _, ipNet := range ips {
+ b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
+ b.AddASN1(cryptobyte_asn1.Tag(7).ContextSpecific(), func(b *cryptobyte.Builder) {
+ b.AddBytes(ipAndMask(ipNet))
+ })
+ })
+ }
+
+ for _, email := range emails {
+ if err = isIA5String(email); err != nil {
+ return nil, err
+ }
+
+ b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
+ b.AddASN1(cryptobyte_asn1.Tag(1).ContextSpecific(), func(b *cryptobyte.Builder) {
+ b.AddBytes([]byte(email))
+ })
+ })
+ }
+
+ for _, uriDomain := range uriDomains {
+ if err = isIA5String(uriDomain); err != nil {
+ return nil, err
+ }
+
+ b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
+ b.AddASN1(cryptobyte_asn1.Tag(6).ContextSpecific(), func(b *cryptobyte.Builder) {
+ b.AddBytes([]byte(uriDomain))
+ })
+ })
+ }
+
+ return b.Bytes()
+ }
+
+ permitted, err := serialiseConstraints(template.PermittedDNSDomains, template.PermittedIPRanges, template.PermittedEmailAddresses, template.PermittedURIDomains)
+ if err != nil {
+ return nil, err
+ }
+
+ excluded, err := serialiseConstraints(template.ExcludedDNSDomains, template.ExcludedIPRanges, template.ExcludedEmailAddresses, template.ExcludedURIDomains)
+ if err != nil {
+ return nil, err
+ }
+
+ var b cryptobyte.Builder
+ b.AddASN1(cryptobyte_asn1.SEQUENCE, func(b *cryptobyte.Builder) {
+ if len(permitted) > 0 {
+ b.AddASN1(cryptobyte_asn1.Tag(0).ContextSpecific().Constructed(), func(b *cryptobyte.Builder) {
+ b.AddBytes(permitted)
+ })
+ }
+
+ if len(excluded) > 0 {
+ b.AddASN1(cryptobyte_asn1.Tag(1).ContextSpecific().Constructed(), func(b *cryptobyte.Builder) {
+ b.AddBytes(excluded)
+ })
+ }
+ })
+
+ ret[n].Value, err = b.Bytes()
+ if err != nil {
+ return nil, err
+ }
+ n++
+ }
+
+ if len(template.CRLDistributionPoints) > 0 &&
+ !oidInExtensions(oidExtensionCRLDistributionPoints, template.ExtraExtensions) {
+ ret[n].Id = oidExtensionCRLDistributionPoints
+
+ var crlDp []distributionPoint
+ for _, name := range template.CRLDistributionPoints {
+ dp := distributionPoint{
+ DistributionPoint: distributionPointName{
+ FullName: []asn1.RawValue{
+ {Tag: 6, Class: 2, Bytes: []byte(name)},
+ },
+ },
+ }
+ crlDp = append(crlDp, dp)
+ }
+
+ ret[n].Value, err = asn1.Marshal(crlDp)
+ if err != nil {
+ return
+ }
+ n++
+ }
+
+ // Adding another extension here? Remember to update the maximum number
+ // of elements in the make() at the top of the function and the list of
+ // template fields used in CreateCertificate documentation.
+
+ return append(ret[:n], template.ExtraExtensions...), nil
+}
+
+func marshalKeyUsage(ku KeyUsage) (pkix.Extension, error) {
+ ext := pkix.Extension{Id: oidExtensionKeyUsage, Critical: true}
+
+ var a [2]byte
+ a[0] = reverseBitsInAByte(byte(ku))
+ a[1] = reverseBitsInAByte(byte(ku >> 8))
+
+ l := 1
+ if a[1] != 0 {
+ l = 2
+ }
+
+ bitString := a[:l]
+ var err error
+ ext.Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)})
+ return ext, err
+}
+
+func marshalExtKeyUsage(extUsages []ExtKeyUsage, unknownUsages []asn1.ObjectIdentifier) (pkix.Extension, error) {
+ ext := pkix.Extension{Id: oidExtensionExtendedKeyUsage}
+
+ oids := make([]asn1.ObjectIdentifier, len(extUsages)+len(unknownUsages))
+ for i, u := range extUsages {
+ if oid, ok := oidFromExtKeyUsage(u); ok {
+ oids[i] = oid
+ } else {
+ return ext, errors.New("x509: unknown extended key usage")
+ }
+ }
+
+ copy(oids[len(extUsages):], unknownUsages)
+
+ var err error
+ ext.Value, err = asn1.Marshal(oids)
+ return ext, err
+}
+
+func marshalBasicConstraints(isCA bool, maxPathLen int, maxPathLenZero bool) (pkix.Extension, error) {
+ ext := pkix.Extension{Id: oidExtensionBasicConstraints, Critical: true}
+ // Leaving MaxPathLen as zero indicates that no maximum path
+ // length is desired, unless MaxPathLenZero is set. A value of
+ // -1 causes encoding/asn1 to omit the value as desired.
+ if maxPathLen == 0 && !maxPathLenZero {
+ maxPathLen = -1
+ }
+ var err error
+ ext.Value, err = asn1.Marshal(basicConstraints{isCA, maxPathLen})
+ return ext, err
+}
+
+func marshalCertificatePolicies(policyIdentifiers []asn1.ObjectIdentifier) (pkix.Extension, error) {
+ ext := pkix.Extension{Id: oidExtensionCertificatePolicies}
+ policies := make([]policyInformation, len(policyIdentifiers))
+ for i, policy := range policyIdentifiers {
+ policies[i].Policy = policy
+ }
+ var err error
+ ext.Value, err = asn1.Marshal(policies)
+ return ext, err
+}
+
+func buildCSRExtensions(template *CertificateRequest) ([]pkix.Extension, error) {
+ var ret []pkix.Extension
+
+ if (len(template.DNSNames) > 0 || len(template.EmailAddresses) > 0 || len(template.IPAddresses) > 0 || len(template.URIs) > 0) &&
+ !oidInExtensions(oidExtensionSubjectAltName, template.ExtraExtensions) {
+ sanBytes, err := marshalSANs(template.DNSNames, template.EmailAddresses, template.IPAddresses, template.URIs)
+ if err != nil {
+ return nil, err
+ }
+
+ ret = append(ret, pkix.Extension{
+ Id: oidExtensionSubjectAltName,
+ Value: sanBytes,
+ })
+ }
+
+ return append(ret, template.ExtraExtensions...), nil
+}
+
+func subjectBytes(cert *Certificate) ([]byte, error) {
+ if len(cert.RawSubject) > 0 {
+ return cert.RawSubject, nil
+ }
+
+ return asn1.Marshal(cert.Subject.ToRDNSequence())
+}
+
+// signingParamsForPublicKey returns the parameters to use for signing with
+// priv. If requestedSigAlgo is not zero then it overrides the default
+// signature algorithm.
+func signingParamsForPublicKey(pub any, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
+ var pubType PublicKeyAlgorithm
+
+ switch pub := pub.(type) {
+ case *rsa.PublicKey:
+ pubType = RSA
+ hashFunc = crypto.SHA256
+ sigAlgo.Algorithm = oidSignatureSHA256WithRSA
+ sigAlgo.Parameters = asn1.NullRawValue
+
+ case *ecdsa.PublicKey:
+ pubType = ECDSA
+
+ switch pub.Curve {
+ case elliptic.P224(), elliptic.P256():
+ hashFunc = crypto.SHA256
+ sigAlgo.Algorithm = oidSignatureECDSAWithSHA256
+ case elliptic.P384():
+ hashFunc = crypto.SHA384
+ sigAlgo.Algorithm = oidSignatureECDSAWithSHA384
+ case elliptic.P521():
+ hashFunc = crypto.SHA512
+ sigAlgo.Algorithm = oidSignatureECDSAWithSHA512
+ default:
+ err = errors.New("x509: unknown elliptic curve")
+ }
+
+ case ed25519.PublicKey:
+ pubType = Ed25519
+ sigAlgo.Algorithm = oidSignatureEd25519
+
+ default:
+ err = errors.New("x509: only RSA, ECDSA and Ed25519 keys supported")
+ }
+
+ if err != nil {
+ return
+ }
+
+ if requestedSigAlgo == 0 {
+ return
+ }
+
+ found := false
+ for _, details := range signatureAlgorithmDetails {
+ if details.algo == requestedSigAlgo {
+ if details.pubKeyAlgo != pubType {
+ err = errors.New("x509: requested SignatureAlgorithm does not match private key type")
+ return
+ }
+ sigAlgo.Algorithm, hashFunc = details.oid, details.hash
+ if hashFunc == 0 && pubType != Ed25519 {
+ err = errors.New("x509: cannot sign with hash function requested")
+ return
+ }
+ if hashFunc == crypto.MD5 {
+ err = errors.New("x509: signing with MD5 is not supported")
+ return
+ }
+ if requestedSigAlgo.isRSAPSS() {
+ sigAlgo.Parameters = hashToPSSParameters[hashFunc]
+ }
+ found = true
+ break
+ }
+ }
+
+ if !found {
+ err = errors.New("x509: unknown SignatureAlgorithm")
+ }
+
+ return
+}
+
+// emptyASN1Subject is the ASN.1 DER encoding of an empty Subject, which is
+// just an empty SEQUENCE.
+var emptyASN1Subject = []byte{0x30, 0}
+
+// CreateCertificate creates a new X.509 v3 certificate based on a template.
+// The following members of template are currently used:
+//
+// - AuthorityKeyId
+// - BasicConstraintsValid
+// - CRLDistributionPoints
+// - DNSNames
+// - EmailAddresses
+// - ExcludedDNSDomains
+// - ExcludedEmailAddresses
+// - ExcludedIPRanges
+// - ExcludedURIDomains
+// - ExtKeyUsage
+// - ExtraExtensions
+// - IPAddresses
+// - IsCA
+// - IssuingCertificateURL
+// - KeyUsage
+// - MaxPathLen
+// - MaxPathLenZero
+// - NotAfter
+// - NotBefore
+// - OCSPServer
+// - PermittedDNSDomains
+// - PermittedDNSDomainsCritical
+// - PermittedEmailAddresses
+// - PermittedIPRanges
+// - PermittedURIDomains
+// - PolicyIdentifiers
+// - SerialNumber
+// - SignatureAlgorithm
+// - Subject
+// - SubjectKeyId
+// - URIs
+// - UnknownExtKeyUsage
+//
+// The certificate is signed by parent. If parent is equal to template then the
+// certificate is self-signed. The parameter pub is the public key of the
+// certificate to be generated and priv is the private key of the signer.
+//
+// The returned slice is the certificate in DER encoding.
+//
+// The currently supported key types are *rsa.PublicKey, *ecdsa.PublicKey and
+// ed25519.PublicKey. pub must be a supported key type, and priv must be a
+// crypto.Signer with a supported public key.
+//
+// The AuthorityKeyId will be taken from the SubjectKeyId of parent, if any,
+// unless the resulting certificate is self-signed. Otherwise the value from
+// template will be used.
+//
+// If SubjectKeyId from template is empty and the template is a CA, SubjectKeyId
+// will be generated from the hash of the public key.
+func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv any) ([]byte, error) {
+ key, ok := priv.(crypto.Signer)
+ if !ok {
+ return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
+ }
+
+ if template.SerialNumber == nil {
+ return nil, errors.New("x509: no SerialNumber given")
+ }
+
+ // RFC 5280 Section 4.1.2.2: serial number must positive
+ //
+ // We _should_ also restrict serials to <= 20 octets, but it turns out a lot of people
+ // get this wrong, in part because the encoding can itself alter the length of the
+ // serial. For now we accept these non-conformant serials.
+ if template.SerialNumber.Sign() == -1 {
+ return nil, errors.New("x509: serial number must be positive")
+ }
+
+ if template.BasicConstraintsValid && !template.IsCA && template.MaxPathLen != -1 && (template.MaxPathLen != 0 || template.MaxPathLenZero) {
+ return nil, errors.New("x509: only CAs are allowed to specify MaxPathLen")
+ }
+
+ hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
+ if err != nil {
+ return nil, err
+ }
+
+ publicKeyBytes, publicKeyAlgorithm, err := marshalPublicKey(pub)
+ if err != nil {
+ return nil, err
+ }
+ if getPublicKeyAlgorithmFromOID(publicKeyAlgorithm.Algorithm) == UnknownPublicKeyAlgorithm {
+ return nil, fmt.Errorf("x509: unsupported public key type: %T", pub)
+ }
+
+ asn1Issuer, err := subjectBytes(parent)
+ if err != nil {
+ return nil, err
+ }
+
+ asn1Subject, err := subjectBytes(template)
+ if err != nil {
+ return nil, err
+ }
+
+ authorityKeyId := template.AuthorityKeyId
+ if !bytes.Equal(asn1Issuer, asn1Subject) && len(parent.SubjectKeyId) > 0 {
+ authorityKeyId = parent.SubjectKeyId
+ }
+
+ subjectKeyId := template.SubjectKeyId
+ if len(subjectKeyId) == 0 && template.IsCA {
+ // SubjectKeyId generated using method 1 in RFC 5280, Section 4.2.1.2:
+ // (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the
+ // value of the BIT STRING subjectPublicKey (excluding the tag,
+ // length, and number of unused bits).
+ h := sha1.Sum(publicKeyBytes)
+ subjectKeyId = h[:]
+ }
+
+ // Check that the signer's public key matches the private key, if available.
+ type privateKey interface {
+ Equal(crypto.PublicKey) bool
+ }
+ if privPub, ok := key.Public().(privateKey); !ok {
+ return nil, errors.New("x509: internal error: supported public key does not implement Equal")
+ } else if parent.PublicKey != nil && !privPub.Equal(parent.PublicKey) {
+ return nil, errors.New("x509: provided PrivateKey doesn't match parent's PublicKey")
+ }
+
+ extensions, err := buildCertExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId, subjectKeyId)
+ if err != nil {
+ return nil, err
+ }
+
+ encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes}
+ c := tbsCertificate{
+ Version: 2,
+ SerialNumber: template.SerialNumber,
+ SignatureAlgorithm: signatureAlgorithm,
+ Issuer: asn1.RawValue{FullBytes: asn1Issuer},
+ Validity: validity{template.NotBefore.UTC(), template.NotAfter.UTC()},
+ Subject: asn1.RawValue{FullBytes: asn1Subject},
+ PublicKey: publicKeyInfo{nil, publicKeyAlgorithm, encodedPublicKey},
+ Extensions: extensions,
+ }
+
+ tbsCertContents, err := asn1.Marshal(c)
+ if err != nil {
+ return nil, err
+ }
+ c.Raw = tbsCertContents
+
+ signed := tbsCertContents
+ if hashFunc != 0 {
+ h := hashFunc.New()
+ h.Write(signed)
+ signed = h.Sum(nil)
+ }
+
+ var signerOpts crypto.SignerOpts = hashFunc
+ if template.SignatureAlgorithm != 0 && template.SignatureAlgorithm.isRSAPSS() {
+ signerOpts = &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthEqualsHash,
+ Hash: hashFunc,
+ }
+ }
+
+ var signature []byte
+ signature, err = key.Sign(rand, signed, signerOpts)
+ if err != nil {
+ return nil, err
+ }
+
+ signedCert, err := asn1.Marshal(certificate{
+ c,
+ signatureAlgorithm,
+ asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+ })
+ if err != nil {
+ return nil, err
+ }
+
+ // Check the signature to ensure the crypto.Signer behaved correctly.
+ if err := checkSignature(getSignatureAlgorithmFromAI(signatureAlgorithm), c.Raw, signature, key.Public(), true); err != nil {
+ return nil, fmt.Errorf("x509: signature over certificate returned by signer is invalid: %w", err)
+ }
+
+ return signedCert, nil
+}
+
+// pemCRLPrefix is the magic string that indicates that we have a PEM encoded
+// CRL.
+var pemCRLPrefix = []byte("-----BEGIN X509 CRL")
+
+// pemType is the type of a PEM encoded CRL.
+var pemType = "X509 CRL"
+
+// ParseCRL parses a CRL from the given bytes. It's often the case that PEM
+// encoded CRLs will appear where they should be DER encoded, so this function
+// will transparently handle PEM encoding as long as there isn't any leading
+// garbage.
+//
+// Deprecated: Use ParseRevocationList instead.
+func ParseCRL(crlBytes []byte) (*pkix.CertificateList, error) {
+ if bytes.HasPrefix(crlBytes, pemCRLPrefix) {
+ block, _ := pem.Decode(crlBytes)
+ if block != nil && block.Type == pemType {
+ crlBytes = block.Bytes
+ }
+ }
+ return ParseDERCRL(crlBytes)
+}
+
+// ParseDERCRL parses a DER encoded CRL from the given bytes.
+//
+// Deprecated: Use ParseRevocationList instead.
+func ParseDERCRL(derBytes []byte) (*pkix.CertificateList, error) {
+ certList := new(pkix.CertificateList)
+ if rest, err := asn1.Unmarshal(derBytes, certList); err != nil {
+ return nil, err
+ } else if len(rest) != 0 {
+ return nil, errors.New("x509: trailing data after CRL")
+ }
+ return certList, nil
+}
+
+// CreateCRL returns a DER encoded CRL, signed by this Certificate, that
+// contains the given list of revoked certificates.
+//
+// Deprecated: this method does not generate an RFC 5280 conformant X.509 v2 CRL.
+// To generate a standards compliant CRL, use CreateRevocationList instead.
+func (c *Certificate) CreateCRL(rand io.Reader, priv any, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) {
+ key, ok := priv.(crypto.Signer)
+ if !ok {
+ return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
+ }
+
+ hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(key.Public(), 0)
+ if err != nil {
+ return nil, err
+ }
+
+ // Force revocation times to UTC per RFC 5280.
+ revokedCertsUTC := make([]pkix.RevokedCertificate, len(revokedCerts))
+ for i, rc := range revokedCerts {
+ rc.RevocationTime = rc.RevocationTime.UTC()
+ revokedCertsUTC[i] = rc
+ }
+
+ tbsCertList := pkix.TBSCertificateList{
+ Version: 1,
+ Signature: signatureAlgorithm,
+ Issuer: c.Subject.ToRDNSequence(),
+ ThisUpdate: now.UTC(),
+ NextUpdate: expiry.UTC(),
+ RevokedCertificates: revokedCertsUTC,
+ }
+
+ // Authority Key Id
+ if len(c.SubjectKeyId) > 0 {
+ var aki pkix.Extension
+ aki.Id = oidExtensionAuthorityKeyId
+ aki.Value, err = asn1.Marshal(authKeyId{Id: c.SubjectKeyId})
+ if err != nil {
+ return
+ }
+ tbsCertList.Extensions = append(tbsCertList.Extensions, aki)
+ }
+
+ tbsCertListContents, err := asn1.Marshal(tbsCertList)
+ if err != nil {
+ return
+ }
+
+ signed := tbsCertListContents
+ if hashFunc != 0 {
+ h := hashFunc.New()
+ h.Write(signed)
+ signed = h.Sum(nil)
+ }
+
+ var signature []byte
+ signature, err = key.Sign(rand, signed, hashFunc)
+ if err != nil {
+ return
+ }
+
+ return asn1.Marshal(pkix.CertificateList{
+ TBSCertList: tbsCertList,
+ SignatureAlgorithm: signatureAlgorithm,
+ SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+ })
+}
+
+// CertificateRequest represents a PKCS #10, certificate signature request.
+type CertificateRequest struct {
+ Raw []byte // Complete ASN.1 DER content (CSR, signature algorithm and signature).
+ RawTBSCertificateRequest []byte // Certificate request info part of raw ASN.1 DER content.
+ RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo.
+ RawSubject []byte // DER encoded Subject.
+
+ Version int
+ Signature []byte
+ SignatureAlgorithm SignatureAlgorithm
+
+ PublicKeyAlgorithm PublicKeyAlgorithm
+ PublicKey any
+
+ Subject pkix.Name
+
+ // Attributes contains the CSR attributes that can parse as
+ // pkix.AttributeTypeAndValueSET.
+ //
+ // Deprecated: Use Extensions and ExtraExtensions instead for parsing and
+ // generating the requestedExtensions attribute.
+ Attributes []pkix.AttributeTypeAndValueSET
+
+ // Extensions contains all requested extensions, in raw form. When parsing
+ // CSRs, this can be used to extract extensions that are not parsed by this
+ // package.
+ Extensions []pkix.Extension
+
+ // ExtraExtensions contains extensions to be copied, raw, into any CSR
+ // marshaled by CreateCertificateRequest. Values override any extensions
+ // that would otherwise be produced based on the other fields but are
+ // overridden by any extensions specified in Attributes.
+ //
+ // The ExtraExtensions field is not populated by ParseCertificateRequest,
+ // see Extensions instead.
+ ExtraExtensions []pkix.Extension
+
+ // Subject Alternate Name values.
+ DNSNames []string
+ EmailAddresses []string
+ IPAddresses []net.IP
+ URIs []*url.URL
+}
+
+// These structures reflect the ASN.1 structure of X.509 certificate
+// signature requests (see RFC 2986):
+
+type tbsCertificateRequest struct {
+ Raw asn1.RawContent
+ Version int
+ Subject asn1.RawValue
+ PublicKey publicKeyInfo
+ RawAttributes []asn1.RawValue `asn1:"tag:0"`
+}
+
+type certificateRequest struct {
+ Raw asn1.RawContent
+ TBSCSR tbsCertificateRequest
+ SignatureAlgorithm pkix.AlgorithmIdentifier
+ SignatureValue asn1.BitString
+}
+
+// oidExtensionRequest is a PKCS #9 OBJECT IDENTIFIER that indicates requested
+// extensions in a CSR.
+var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14}
+
+// newRawAttributes converts AttributeTypeAndValueSETs from a template
+// CertificateRequest's Attributes into tbsCertificateRequest RawAttributes.
+func newRawAttributes(attributes []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) {
+ var rawAttributes []asn1.RawValue
+ b, err := asn1.Marshal(attributes)
+ if err != nil {
+ return nil, err
+ }
+ rest, err := asn1.Unmarshal(b, &rawAttributes)
+ if err != nil {
+ return nil, err
+ }
+ if len(rest) != 0 {
+ return nil, errors.New("x509: failed to unmarshal raw CSR Attributes")
+ }
+ return rawAttributes, nil
+}
+
+// parseRawAttributes Unmarshals RawAttributes into AttributeTypeAndValueSETs.
+func parseRawAttributes(rawAttributes []asn1.RawValue) []pkix.AttributeTypeAndValueSET {
+ var attributes []pkix.AttributeTypeAndValueSET
+ for _, rawAttr := range rawAttributes {
+ var attr pkix.AttributeTypeAndValueSET
+ rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr)
+ // Ignore attributes that don't parse into pkix.AttributeTypeAndValueSET
+ // (i.e.: challengePassword or unstructuredName).
+ if err == nil && len(rest) == 0 {
+ attributes = append(attributes, attr)
+ }
+ }
+ return attributes
+}
+
+// parseCSRExtensions parses the attributes from a CSR and extracts any
+// requested extensions.
+func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error) {
+ // pkcs10Attribute reflects the Attribute structure from RFC 2986, Section 4.1.
+ type pkcs10Attribute struct {
+ Id asn1.ObjectIdentifier
+ Values []asn1.RawValue `asn1:"set"`
+ }
+
+ var ret []pkix.Extension
+ requestedExts := make(map[string]bool)
+ for _, rawAttr := range rawAttributes {
+ var attr pkcs10Attribute
+ if rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr); err != nil || len(rest) != 0 || len(attr.Values) == 0 {
+ // Ignore attributes that don't parse.
+ continue
+ }
+
+ if !attr.Id.Equal(oidExtensionRequest) {
+ continue
+ }
+
+ var extensions []pkix.Extension
+ if _, err := asn1.Unmarshal(attr.Values[0].FullBytes, &extensions); err != nil {
+ return nil, err
+ }
+ for _, ext := range extensions {
+ oidStr := ext.Id.String()
+ if requestedExts[oidStr] {
+ return nil, errors.New("x509: certificate request contains duplicate requested extensions")
+ }
+ requestedExts[oidStr] = true
+ }
+ ret = append(ret, extensions...)
+ }
+
+ return ret, nil
+}
+
+// CreateCertificateRequest creates a new certificate request based on a
+// template. The following members of template are used:
+//
+// - SignatureAlgorithm
+// - Subject
+// - DNSNames
+// - EmailAddresses
+// - IPAddresses
+// - URIs
+// - ExtraExtensions
+// - Attributes (deprecated)
+//
+// priv is the private key to sign the CSR with, and the corresponding public
+// key will be included in the CSR. It must implement crypto.Signer and its
+// Public() method must return a *rsa.PublicKey or a *ecdsa.PublicKey or a
+// ed25519.PublicKey. (A *rsa.PrivateKey, *ecdsa.PrivateKey or
+// ed25519.PrivateKey satisfies this.)
+//
+// The returned slice is the certificate request in DER encoding.
+func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv any) (csr []byte, err error) {
+ key, ok := priv.(crypto.Signer)
+ if !ok {
+ return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
+ }
+
+ var hashFunc crypto.Hash
+ var sigAlgo pkix.AlgorithmIdentifier
+ hashFunc, sigAlgo, err = signingParamsForPublicKey(key.Public(), template.SignatureAlgorithm)
+ if err != nil {
+ return nil, err
+ }
+
+ var publicKeyBytes []byte
+ var publicKeyAlgorithm pkix.AlgorithmIdentifier
+ publicKeyBytes, publicKeyAlgorithm, err = marshalPublicKey(key.Public())
+ if err != nil {
+ return nil, err
+ }
+
+ extensions, err := buildCSRExtensions(template)
+ if err != nil {
+ return nil, err
+ }
+
+ // Make a copy of template.Attributes because we may alter it below.
+ attributes := make([]pkix.AttributeTypeAndValueSET, 0, len(template.Attributes))
+ for _, attr := range template.Attributes {
+ values := make([][]pkix.AttributeTypeAndValue, len(attr.Value))
+ copy(values, attr.Value)
+ attributes = append(attributes, pkix.AttributeTypeAndValueSET{
+ Type: attr.Type,
+ Value: values,
+ })
+ }
+
+ extensionsAppended := false
+ if len(extensions) > 0 {
+ // Append the extensions to an existing attribute if possible.
+ for _, atvSet := range attributes {
+ if !atvSet.Type.Equal(oidExtensionRequest) || len(atvSet.Value) == 0 {
+ continue
+ }
+
+ // specifiedExtensions contains all the extensions that we
+ // found specified via template.Attributes.
+ specifiedExtensions := make(map[string]bool)
+
+ for _, atvs := range atvSet.Value {
+ for _, atv := range atvs {
+ specifiedExtensions[atv.Type.String()] = true
+ }
+ }
+
+ newValue := make([]pkix.AttributeTypeAndValue, 0, len(atvSet.Value[0])+len(extensions))
+ newValue = append(newValue, atvSet.Value[0]...)
+
+ for _, e := range extensions {
+ if specifiedExtensions[e.Id.String()] {
+ // Attributes already contained a value for
+ // this extension and it takes priority.
+ continue
+ }
+
+ newValue = append(newValue, pkix.AttributeTypeAndValue{
+ // There is no place for the critical
+ // flag in an AttributeTypeAndValue.
+ Type: e.Id,
+ Value: e.Value,
+ })
+ }
+
+ atvSet.Value[0] = newValue
+ extensionsAppended = true
+ break
+ }
+ }
+
+ rawAttributes, err := newRawAttributes(attributes)
+ if err != nil {
+ return
+ }
+
+ // If not included in attributes, add a new attribute for the
+ // extensions.
+ if len(extensions) > 0 && !extensionsAppended {
+ attr := struct {
+ Type asn1.ObjectIdentifier
+ Value [][]pkix.Extension `asn1:"set"`
+ }{
+ Type: oidExtensionRequest,
+ Value: [][]pkix.Extension{extensions},
+ }
+
+ b, err := asn1.Marshal(attr)
+ if err != nil {
+ return nil, errors.New("x509: failed to serialise extensions attribute: " + err.Error())
+ }
+
+ var rawValue asn1.RawValue
+ if _, err := asn1.Unmarshal(b, &rawValue); err != nil {
+ return nil, err
+ }
+
+ rawAttributes = append(rawAttributes, rawValue)
+ }
+
+ asn1Subject := template.RawSubject
+ if len(asn1Subject) == 0 {
+ asn1Subject, err = asn1.Marshal(template.Subject.ToRDNSequence())
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ tbsCSR := tbsCertificateRequest{
+ Version: 0, // PKCS #10, RFC 2986
+ Subject: asn1.RawValue{FullBytes: asn1Subject},
+ PublicKey: publicKeyInfo{
+ Algorithm: publicKeyAlgorithm,
+ PublicKey: asn1.BitString{
+ Bytes: publicKeyBytes,
+ BitLength: len(publicKeyBytes) * 8,
+ },
+ },
+ RawAttributes: rawAttributes,
+ }
+
+ tbsCSRContents, err := asn1.Marshal(tbsCSR)
+ if err != nil {
+ return
+ }
+ tbsCSR.Raw = tbsCSRContents
+
+ signed := tbsCSRContents
+ if hashFunc != 0 {
+ h := hashFunc.New()
+ h.Write(signed)
+ signed = h.Sum(nil)
+ }
+
+ var signature []byte
+ signature, err = key.Sign(rand, signed, hashFunc)
+ if err != nil {
+ return
+ }
+
+ return asn1.Marshal(certificateRequest{
+ TBSCSR: tbsCSR,
+ SignatureAlgorithm: sigAlgo,
+ SignatureValue: asn1.BitString{
+ Bytes: signature,
+ BitLength: len(signature) * 8,
+ },
+ })
+}
+
+// ParseCertificateRequest parses a single certificate request from the
+// given ASN.1 DER data.
+func ParseCertificateRequest(asn1Data []byte) (*CertificateRequest, error) {
+ var csr certificateRequest
+
+ rest, err := asn1.Unmarshal(asn1Data, &csr)
+ if err != nil {
+ return nil, err
+ } else if len(rest) != 0 {
+ return nil, asn1.SyntaxError{Msg: "trailing data"}
+ }
+
+ return parseCertificateRequest(&csr)
+}
+
+func parseCertificateRequest(in *certificateRequest) (*CertificateRequest, error) {
+ out := &CertificateRequest{
+ Raw: in.Raw,
+ RawTBSCertificateRequest: in.TBSCSR.Raw,
+ RawSubjectPublicKeyInfo: in.TBSCSR.PublicKey.Raw,
+ RawSubject: in.TBSCSR.Subject.FullBytes,
+
+ Signature: in.SignatureValue.RightAlign(),
+ SignatureAlgorithm: getSignatureAlgorithmFromAI(in.SignatureAlgorithm),
+
+ PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(in.TBSCSR.PublicKey.Algorithm.Algorithm),
+
+ Version: in.TBSCSR.Version,
+ Attributes: parseRawAttributes(in.TBSCSR.RawAttributes),
+ }
+
+ var err error
+ if out.PublicKeyAlgorithm != UnknownPublicKeyAlgorithm {
+ out.PublicKey, err = parsePublicKey(&in.TBSCSR.PublicKey)
+ if err != nil {
+ return nil, err
+ }
+ }
+
+ var subject pkix.RDNSequence
+ if rest, err := asn1.Unmarshal(in.TBSCSR.Subject.FullBytes, &subject); err != nil {
+ return nil, err
+ } else if len(rest) != 0 {
+ return nil, errors.New("x509: trailing data after X.509 Subject")
+ }
+
+ out.Subject.FillFromRDNSequence(&subject)
+
+ if out.Extensions, err = parseCSRExtensions(in.TBSCSR.RawAttributes); err != nil {
+ return nil, err
+ }
+
+ for _, extension := range out.Extensions {
+ switch {
+ case extension.Id.Equal(oidExtensionSubjectAltName):
+ out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(extension.Value)
+ if err != nil {
+ return nil, err
+ }
+ }
+ }
+
+ return out, nil
+}
+
+// CheckSignature reports whether the signature on c is valid.
+func (c *CertificateRequest) CheckSignature() error {
+ return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey, true)
+}
+
+// RevocationList contains the fields used to create an X.509 v2 Certificate
+// Revocation list with CreateRevocationList.
+type RevocationList struct {
+ // Raw contains the complete ASN.1 DER content of the CRL (tbsCertList,
+ // signatureAlgorithm, and signatureValue.)
+ Raw []byte
+ // RawTBSRevocationList contains just the tbsCertList portion of the ASN.1
+ // DER.
+ RawTBSRevocationList []byte
+ // RawIssuer contains the DER encoded Issuer.
+ RawIssuer []byte
+
+ // Issuer contains the DN of the issuing certificate.
+ Issuer pkix.Name
+ // AuthorityKeyId is used to identify the public key associated with the
+ // issuing certificate. It is populated from the authorityKeyIdentifier
+ // extension when parsing a CRL. It is ignored when creating a CRL; the
+ // extension is populated from the issuing certificate itself.
+ AuthorityKeyId []byte
+
+ Signature []byte
+ // SignatureAlgorithm is used to determine the signature algorithm to be
+ // used when signing the CRL. If 0 the default algorithm for the signing
+ // key will be used.
+ SignatureAlgorithm SignatureAlgorithm
+
+ // RevokedCertificates is used to populate the revokedCertificates
+ // sequence in the CRL, it may be empty. RevokedCertificates may be nil,
+ // in which case an empty CRL will be created.
+ RevokedCertificates []pkix.RevokedCertificate
+
+ // Number is used to populate the X.509 v2 cRLNumber extension in the CRL,
+ // which should be a monotonically increasing sequence number for a given
+ // CRL scope and CRL issuer. It is also populated from the cRLNumber
+ // extension when parsing a CRL.
+ Number *big.Int
+
+ // ThisUpdate is used to populate the thisUpdate field in the CRL, which
+ // indicates the issuance date of the CRL.
+ ThisUpdate time.Time
+ // NextUpdate is used to populate the nextUpdate field in the CRL, which
+ // indicates the date by which the next CRL will be issued. NextUpdate
+ // must be greater than ThisUpdate.
+ NextUpdate time.Time
+
+ // Extensions contains raw X.509 extensions. When creating a CRL,
+ // the Extensions field is ignored, see ExtraExtensions.
+ Extensions []pkix.Extension
+
+ // ExtraExtensions contains any additional extensions to add directly to
+ // the CRL.
+ ExtraExtensions []pkix.Extension
+}
+
+// These structures reflect the ASN.1 structure of X.509 CRLs better than
+// the existing crypto/x509/pkix variants do. These mirror the existing
+// certificate structs in this file.
+//
+// Notably, we include issuer as an asn1.RawValue, mirroring the behavior of
+// tbsCertificate and allowing raw (unparsed) subjects to be passed cleanly.
+type certificateList struct {
+ TBSCertList tbsCertificateList
+ SignatureAlgorithm pkix.AlgorithmIdentifier
+ SignatureValue asn1.BitString
+}
+
+type tbsCertificateList struct {
+ Raw asn1.RawContent
+ Version int `asn1:"optional,default:0"`
+ Signature pkix.AlgorithmIdentifier
+ Issuer asn1.RawValue
+ ThisUpdate time.Time
+ NextUpdate time.Time `asn1:"optional"`
+ RevokedCertificates []pkix.RevokedCertificate `asn1:"optional"`
+ Extensions []pkix.Extension `asn1:"tag:0,optional,explicit"`
+}
+
+// CreateRevocationList creates a new X.509 v2 Certificate Revocation List,
+// according to RFC 5280, based on template.
+//
+// The CRL is signed by priv which should be the private key associated with
+// the public key in the issuer certificate.
+//
+// The issuer may not be nil, and the crlSign bit must be set in KeyUsage in
+// order to use it as a CRL issuer.
+//
+// The issuer distinguished name CRL field and authority key identifier
+// extension are populated using the issuer certificate. issuer must have
+// SubjectKeyId set.
+func CreateRevocationList(rand io.Reader, template *RevocationList, issuer *Certificate, priv crypto.Signer) ([]byte, error) {
+ if template == nil {
+ return nil, errors.New("x509: template can not be nil")
+ }
+ if issuer == nil {
+ return nil, errors.New("x509: issuer can not be nil")
+ }
+ if (issuer.KeyUsage & KeyUsageCRLSign) == 0 {
+ return nil, errors.New("x509: issuer must have the crlSign key usage bit set")
+ }
+ if len(issuer.SubjectKeyId) == 0 {
+ return nil, errors.New("x509: issuer certificate doesn't contain a subject key identifier")
+ }
+ if template.NextUpdate.Before(template.ThisUpdate) {
+ return nil, errors.New("x509: template.ThisUpdate is after template.NextUpdate")
+ }
+ if template.Number == nil {
+ return nil, errors.New("x509: template contains nil Number field")
+ }
+
+ hashFunc, signatureAlgorithm, err := signingParamsForPublicKey(priv.Public(), template.SignatureAlgorithm)
+ if err != nil {
+ return nil, err
+ }
+
+ // Force revocation times to UTC per RFC 5280.
+ revokedCertsUTC := make([]pkix.RevokedCertificate, len(template.RevokedCertificates))
+ for i, rc := range template.RevokedCertificates {
+ rc.RevocationTime = rc.RevocationTime.UTC()
+ revokedCertsUTC[i] = rc
+ }
+
+ aki, err := asn1.Marshal(authKeyId{Id: issuer.SubjectKeyId})
+ if err != nil {
+ return nil, err
+ }
+
+ if numBytes := template.Number.Bytes(); len(numBytes) > 20 || (len(numBytes) == 20 && numBytes[0]&0x80 != 0) {
+ return nil, errors.New("x509: CRL number exceeds 20 octets")
+ }
+ crlNum, err := asn1.Marshal(template.Number)
+ if err != nil {
+ return nil, err
+ }
+
+ // Correctly use the issuer's subject sequence if one is specified.
+ issuerSubject, err := subjectBytes(issuer)
+ if err != nil {
+ return nil, err
+ }
+
+ tbsCertList := tbsCertificateList{
+ Version: 1, // v2
+ Signature: signatureAlgorithm,
+ Issuer: asn1.RawValue{FullBytes: issuerSubject},
+ ThisUpdate: template.ThisUpdate.UTC(),
+ NextUpdate: template.NextUpdate.UTC(),
+ Extensions: []pkix.Extension{
+ {
+ Id: oidExtensionAuthorityKeyId,
+ Value: aki,
+ },
+ {
+ Id: oidExtensionCRLNumber,
+ Value: crlNum,
+ },
+ },
+ }
+ if len(revokedCertsUTC) > 0 {
+ tbsCertList.RevokedCertificates = revokedCertsUTC
+ }
+
+ if len(template.ExtraExtensions) > 0 {
+ tbsCertList.Extensions = append(tbsCertList.Extensions, template.ExtraExtensions...)
+ }
+
+ tbsCertListContents, err := asn1.Marshal(tbsCertList)
+ if err != nil {
+ return nil, err
+ }
+
+ // Optimization to only marshal this struct once, when signing and
+ // then embedding in certificateList below.
+ tbsCertList.Raw = tbsCertListContents
+
+ input := tbsCertListContents
+ if hashFunc != 0 {
+ h := hashFunc.New()
+ h.Write(tbsCertListContents)
+ input = h.Sum(nil)
+ }
+ var signerOpts crypto.SignerOpts = hashFunc
+ if template.SignatureAlgorithm.isRSAPSS() {
+ signerOpts = &rsa.PSSOptions{
+ SaltLength: rsa.PSSSaltLengthEqualsHash,
+ Hash: hashFunc,
+ }
+ }
+
+ signature, err := priv.Sign(rand, input, signerOpts)
+ if err != nil {
+ return nil, err
+ }
+
+ return asn1.Marshal(certificateList{
+ TBSCertList: tbsCertList,
+ SignatureAlgorithm: signatureAlgorithm,
+ SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
+ })
+}
+
+// CheckSignatureFrom verifies that the signature on rl is a valid signature
+// from issuer.
+func (rl *RevocationList) CheckSignatureFrom(parent *Certificate) error {
+ if parent.Version == 3 && !parent.BasicConstraintsValid ||
+ parent.BasicConstraintsValid && !parent.IsCA {
+ return ConstraintViolationError{}
+ }
+
+ if parent.KeyUsage != 0 && parent.KeyUsage&KeyUsageCRLSign == 0 {
+ return ConstraintViolationError{}
+ }
+
+ if parent.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm {
+ return ErrUnsupportedAlgorithm
+ }
+
+ return parent.CheckSignature(rl.SignatureAlgorithm, rl.RawTBSRevocationList, rl.Signature)
+}
diff --git a/src/crypto/x509/x509_test.go b/src/crypto/x509/x509_test.go
new file mode 100644
index 0000000..8846b00
--- /dev/null
+++ b/src/crypto/x509/x509_test.go
@@ -0,0 +1,3844 @@
+// Copyright 2009 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package x509
+
+import (
+ "bytes"
+ "crypto"
+ "crypto/dsa"
+ "crypto/ecdh"
+ "crypto/ecdsa"
+ "crypto/ed25519"
+ "crypto/elliptic"
+ "crypto/rand"
+ "crypto/rsa"
+ _ "crypto/sha256"
+ _ "crypto/sha512"
+ "crypto/x509/pkix"
+ "encoding/asn1"
+ "encoding/base64"
+ "encoding/hex"
+ "encoding/pem"
+ "fmt"
+ "internal/testenv"
+ "io"
+ "math/big"
+ "net"
+ "net/url"
+ "os/exec"
+ "reflect"
+ "runtime"
+ "strings"
+ "testing"
+ "time"
+)
+
+func TestParsePKCS1PrivateKey(t *testing.T) {
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ priv, err := ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ t.Errorf("Failed to parse private key: %s", err)
+ return
+ }
+ if priv.PublicKey.N.Cmp(rsaPrivateKey.PublicKey.N) != 0 ||
+ priv.PublicKey.E != rsaPrivateKey.PublicKey.E ||
+ priv.D.Cmp(rsaPrivateKey.D) != 0 ||
+ priv.Primes[0].Cmp(rsaPrivateKey.Primes[0]) != 0 ||
+ priv.Primes[1].Cmp(rsaPrivateKey.Primes[1]) != 0 {
+ t.Errorf("got:%+v want:%+v", priv, rsaPrivateKey)
+ }
+
+ // This private key includes an invalid prime that
+ // rsa.PrivateKey.Validate should reject.
+ data := []byte("0\x16\x02\x00\x02\x02\u007f\x00\x02\x0200\x02\x0200\x02\x02\x00\x01\x02\x02\u007f\x00")
+ if _, err := ParsePKCS1PrivateKey(data); err == nil {
+ t.Errorf("parsing invalid private key did not result in an error")
+ }
+}
+
+func TestPKCS1MismatchPublicKeyFormat(t *testing.T) {
+
+ const pkixPublicKey = "30820122300d06092a864886f70d01010105000382010f003082010a0282010100dd5a0f37d3ca5232852ccc0e81eebec270e2f2c6c44c6231d852971a0aad00aa7399e9b9de444611083c59ea919a9d76c20a7be131a99045ec19a7bb452d647a72429e66b87e28be9e8187ed1d2a2a01ef3eb2360706bd873b07f2d1f1a72337aab5ec94e983e39107f52c480d404915e84d75a3db2cfd601726a128cb1d7f11492d4bdb53272e652276667220795c709b8a9b4af6489cbf48bb8173b8fb607c834a71b6e8bf2d6aab82af3c8ad7ce16d8dcf58373a6edc427f7484d09744d4c08f4e19ed07adbf6cb31243bc5d0d1145e77a08a6fc5efd208eca67d6abf2d6f38f58b6fdd7c28774fb0cc03fc4935c6e074842d2e1479d3d8787249258719f90203010001"
+ const errorContains = "use ParsePKIXPublicKey instead"
+ derBytes, _ := hex.DecodeString(pkixPublicKey)
+ _, err := ParsePKCS1PublicKey(derBytes)
+ if !strings.Contains(err.Error(), errorContains) {
+ t.Errorf("expected error containing %q, got %s", errorContains, err)
+ }
+}
+
+func TestMarshalInvalidPublicKey(t *testing.T) {
+ _, err := MarshalPKIXPublicKey(&ecdsa.PublicKey{})
+ if err == nil {
+ t.Errorf("expected error, got MarshalPKIXPublicKey success")
+ }
+ _, err = MarshalPKIXPublicKey(&ecdsa.PublicKey{
+ Curve: elliptic.P256(),
+ X: big.NewInt(1), Y: big.NewInt(2),
+ })
+ if err == nil {
+ t.Errorf("expected error, got MarshalPKIXPublicKey success")
+ }
+}
+
+func testParsePKIXPublicKey(t *testing.T, pemBytes string) (pub any) {
+ block, _ := pem.Decode([]byte(pemBytes))
+ pub, err := ParsePKIXPublicKey(block.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse public key: %s", err)
+ }
+
+ pubBytes2, err := MarshalPKIXPublicKey(pub)
+ if err != nil {
+ t.Errorf("Failed to marshal public key for the second time: %s", err)
+ return
+ }
+ if !bytes.Equal(pubBytes2, block.Bytes) {
+ t.Errorf("Reserialization of public key didn't match. got %x, want %x", pubBytes2, block.Bytes)
+ }
+ return
+}
+
+func TestParsePKIXPublicKey(t *testing.T) {
+ t.Run("RSA", func(t *testing.T) {
+ pub := testParsePKIXPublicKey(t, pemPublicKey)
+ _, ok := pub.(*rsa.PublicKey)
+ if !ok {
+ t.Errorf("Value returned from ParsePKIXPublicKey was not an RSA public key")
+ }
+ })
+ t.Run("Ed25519", func(t *testing.T) {
+ pub := testParsePKIXPublicKey(t, pemEd25519Key)
+ _, ok := pub.(ed25519.PublicKey)
+ if !ok {
+ t.Errorf("Value returned from ParsePKIXPublicKey was not an Ed25519 public key")
+ }
+ })
+ t.Run("X25519", func(t *testing.T) {
+ pub := testParsePKIXPublicKey(t, pemX25519Key)
+ k, ok := pub.(*ecdh.PublicKey)
+ if !ok || k.Curve() != ecdh.X25519() {
+ t.Errorf("Value returned from ParsePKIXPublicKey was not an X25519 public key")
+ }
+ })
+}
+
+var pemPublicKey = `-----BEGIN PUBLIC KEY-----
+MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA3VoPN9PKUjKFLMwOge6+
+wnDi8sbETGIx2FKXGgqtAKpzmem53kRGEQg8WeqRmp12wgp74TGpkEXsGae7RS1k
+enJCnma4fii+noGH7R0qKgHvPrI2Bwa9hzsH8tHxpyM3qrXslOmD45EH9SxIDUBJ
+FehNdaPbLP1gFyahKMsdfxFJLUvbUycuZSJ2ZnIgeVxwm4qbSvZInL9Iu4FzuPtg
+fINKcbbovy1qq4KvPIrXzhbY3PWDc6btxCf3SE0JdE1MCPThntB62/bLMSQ7xdDR
+FF53oIpvxe/SCOymfWq/LW849Ytv3Xwod0+wzAP8STXG4HSELS4UedPYeHJJJYcZ
++QIDAQAB
+-----END PUBLIC KEY-----
+`
+
+var pemPrivateKey = testingKey(`
+-----BEGIN RSA TESTING KEY-----
+MIICXAIBAAKBgQCxoeCUW5KJxNPxMp+KmCxKLc1Zv9Ny+4CFqcUXVUYH69L3mQ7v
+IWrJ9GBfcaA7BPQqUlWxWM+OCEQZH1EZNIuqRMNQVuIGCbz5UQ8w6tS0gcgdeGX7
+J7jgCQ4RK3F/PuCM38QBLaHx988qG8NMc6VKErBjctCXFHQt14lerd5KpQIDAQAB
+AoGAYrf6Hbk+mT5AI33k2Jt1kcweodBP7UkExkPxeuQzRVe0KVJw0EkcFhywKpr1
+V5eLMrILWcJnpyHE5slWwtFHBG6a5fLaNtsBBtcAIfqTQ0Vfj5c6SzVaJv0Z5rOd
+7gQF6isy3t3w9IF3We9wXQKzT6q5ypPGdm6fciKQ8RnzREkCQQDZwppKATqQ41/R
+vhSj90fFifrGE6aVKC1hgSpxGQa4oIdsYYHwMzyhBmWW9Xv/R+fPyr8ZwPxp2c12
+33QwOLPLAkEA0NNUb+z4ebVVHyvSwF5jhfJxigim+s49KuzJ1+A2RaSApGyBZiwS
+rWvWkB471POAKUYt5ykIWVZ83zcceQiNTwJBAMJUFQZX5GDqWFc/zwGoKkeR49Yi
+MTXIvf7Wmv6E++eFcnT461FlGAUHRV+bQQXGsItR/opIG7mGogIkVXa3E1MCQARX
+AAA7eoZ9AEHflUeuLn9QJI/r0hyQQLEtrpwv6rDT1GCWaLII5HJ6NUFVf4TTcqxo
+6vdM4QGKTJoO+SaCyP0CQFdpcxSAuzpFcKv0IlJ8XzS/cy+mweCMwyJ1PFEc4FX6
+wg/HcAJWY60xZTJDFN+Qfx8ZQvBEin6c2/h+zZi5IVY=
+-----END RSA TESTING KEY-----
+`)
+
+// pemEd25519Key is the example from RFC 8410, Secrion 4.
+var pemEd25519Key = `
+-----BEGIN PUBLIC KEY-----
+MCowBQYDK2VwAyEAGb9ECWmEzf6FQbrBZ9w7lshQhqowtrbLDFw4rXAxZuE=
+-----END PUBLIC KEY-----
+`
+
+// pemX25519Key was generated from pemX25519Key with "openssl pkey -pubout".
+var pemX25519Key = `
+-----BEGIN PUBLIC KEY-----
+MCowBQYDK2VuAyEA5yGXrH/6OzxuWEhEWS01/f4OP+Of3Yrddy6/J1kDTVM=
+-----END PUBLIC KEY-----
+`
+
+func TestPKIXMismatchPublicKeyFormat(t *testing.T) {
+
+ const pkcs1PublicKey = "308201080282010100817cfed98bcaa2e2a57087451c7674e0c675686dc33ff1268b0c2a6ee0202dec710858ee1c31bdf5e7783582e8ca800be45f3275c6576adc35d98e26e95bb88ca5beb186f853b8745d88bc9102c5f38753bcda519fb05948d5c77ac429255ff8aaf27d9f45d1586e95e2e9ba8a7cb771b8a09dd8c8fed3f933fd9b439bc9f30c475953418ef25f71a2b6496f53d94d39ce850aa0cc75d445b5f5b4f4ee4db78ab197a9a8d8a852f44529a007ac0ac23d895928d60ba538b16b0b087a7f903ed29770e215019b77eaecc360f35f7ab11b6d735978795b2c4a74e5bdea4dc6594cd67ed752a108e666729a753ab36d6c4f606f8760f507e1765be8cd744007e629020103"
+ const errorContains = "use ParsePKCS1PublicKey instead"
+ derBytes, _ := hex.DecodeString(pkcs1PublicKey)
+ _, err := ParsePKIXPublicKey(derBytes)
+ if !strings.Contains(err.Error(), errorContains) {
+ t.Errorf("expected error containing %q, got %s", errorContains, err)
+ }
+}
+
+var testPrivateKey *rsa.PrivateKey
+
+func init() {
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+
+ var err error
+ if testPrivateKey, err = ParsePKCS1PrivateKey(block.Bytes); err != nil {
+ panic("Failed to parse private key: " + err.Error())
+ }
+}
+
+func bigFromString(s string) *big.Int {
+ ret := new(big.Int)
+ ret.SetString(s, 10)
+ return ret
+}
+
+func fromBase10(base10 string) *big.Int {
+ i := new(big.Int)
+ i.SetString(base10, 10)
+ return i
+}
+
+func bigFromHexString(s string) *big.Int {
+ ret := new(big.Int)
+ ret.SetString(s, 16)
+ return ret
+}
+
+var rsaPrivateKey = &rsa.PrivateKey{
+ PublicKey: rsa.PublicKey{
+ N: bigFromString("124737666279038955318614287965056875799409043964547386061640914307192830334599556034328900586693254156136128122194531292927142396093148164407300419162827624945636708870992355233833321488652786796134504707628792159725681555822420087112284637501705261187690946267527866880072856272532711620639179596808018872997"),
+ E: 65537,
+ },
+ D: bigFromString("69322600686866301945688231018559005300304807960033948687567105312977055197015197977971637657636780793670599180105424702854759606794705928621125408040473426339714144598640466128488132656829419518221592374964225347786430566310906679585739468938549035854760501049443920822523780156843263434219450229353270690889"),
+ Primes: []*big.Int{
+ bigFromString("11405025354575369741595561190164746858706645478381139288033759331174478411254205003127028642766986913445391069745480057674348716675323735886284176682955723"),
+ bigFromString("10937079261204603443118731009201819560867324167189758120988909645641782263430128449826989846631183550578761324239709121189827307416350485191350050332642639"),
+ },
+}
+
+func TestMarshalRSAPrivateKey(t *testing.T) {
+ priv := &rsa.PrivateKey{
+ PublicKey: rsa.PublicKey{
+ N: fromBase10("16346378922382193400538269749936049106320265317511766357599732575277382844051791096569333808598921852351577762718529818072849191122419410612033592401403764925096136759934497687765453905884149505175426053037420486697072448609022753683683718057795566811401938833367954642951433473337066311978821180526439641496973296037000052546108507805269279414789035461158073156772151892452251106173507240488993608650881929629163465099476849643165682709047462010581308719577053905787496296934240246311806555924593059995202856826239801816771116902778517096212527979497399966526283516447337775509777558018145573127308919204297111496233"),
+ E: 3,
+ },
+ D: fromBase10("10897585948254795600358846499957366070880176878341177571733155050184921896034527397712889205732614568234385175145686545381899460748279607074689061600935843283397424506622998458510302603922766336783617368686090042765718290914099334449154829375179958369993407724946186243249568928237086215759259909861748642124071874879861299389874230489928271621259294894142840428407196932444474088857746123104978617098858619445675532587787023228852383149557470077802718705420275739737958953794088728369933811184572620857678792001136676902250566845618813972833750098806496641114644760255910789397593428910198080271317419213080834885003"),
+ Primes: []*big.Int{
+ fromBase10("1025363189502892836833747188838978207017355117492483312747347695538428729137306368764177201532277413433182799108299960196606011786562992097313508180436744488171474690412562218914213688661311117337381958560443"),
+ fromBase10("3467903426626310123395340254094941045497208049900750380025518552334536945536837294961497712862519984786362199788654739924501424784631315081391467293694361474867825728031147665777546570788493758372218019373"),
+ fromBase10("4597024781409332673052708605078359346966325141767460991205742124888960305710298765592730135879076084498363772408626791576005136245060321874472727132746643162385746062759369754202494417496879741537284589047"),
+ },
+ }
+
+ derBytes := MarshalPKCS1PrivateKey(priv)
+
+ priv2, err := ParsePKCS1PrivateKey(derBytes)
+ if err != nil {
+ t.Errorf("error parsing serialized key: %s", err)
+ return
+ }
+ if priv.PublicKey.N.Cmp(priv2.PublicKey.N) != 0 ||
+ priv.PublicKey.E != priv2.PublicKey.E ||
+ priv.D.Cmp(priv2.D) != 0 ||
+ len(priv2.Primes) != 3 ||
+ priv.Primes[0].Cmp(priv2.Primes[0]) != 0 ||
+ priv.Primes[1].Cmp(priv2.Primes[1]) != 0 ||
+ priv.Primes[2].Cmp(priv2.Primes[2]) != 0 {
+ t.Errorf("got:%+v want:%+v", priv, priv2)
+ }
+}
+
+func TestMarshalRSAPublicKey(t *testing.T) {
+ pub := &rsa.PublicKey{
+ N: fromBase10("16346378922382193400538269749936049106320265317511766357599732575277382844051791096569333808598921852351577762718529818072849191122419410612033592401403764925096136759934497687765453905884149505175426053037420486697072448609022753683683718057795566811401938833367954642951433473337066311978821180526439641496973296037000052546108507805269279414789035461158073156772151892452251106173507240488993608650881929629163465099476849643165682709047462010581308719577053905787496296934240246311806555924593059995202856826239801816771116902778517096212527979497399966526283516447337775509777558018145573127308919204297111496233"),
+ E: 3,
+ }
+ derBytes := MarshalPKCS1PublicKey(pub)
+ pub2, err := ParsePKCS1PublicKey(derBytes)
+ if err != nil {
+ t.Errorf("ParsePKCS1PublicKey: %s", err)
+ }
+ if pub.N.Cmp(pub2.N) != 0 || pub.E != pub2.E {
+ t.Errorf("ParsePKCS1PublicKey = %+v, want %+v", pub, pub2)
+ }
+
+ // It's never been documented that asn1.Marshal/Unmarshal on rsa.PublicKey works,
+ // but it does, and we know of code that depends on it.
+ // Lock that in, even though we'd prefer that people use MarshalPKCS1PublicKey and ParsePKCS1PublicKey.
+ derBytes2, err := asn1.Marshal(*pub)
+ if err != nil {
+ t.Errorf("Marshal(rsa.PublicKey): %v", err)
+ } else if !bytes.Equal(derBytes, derBytes2) {
+ t.Errorf("Marshal(rsa.PublicKey) = %x, want %x", derBytes2, derBytes)
+ }
+ pub3 := new(rsa.PublicKey)
+ rest, err := asn1.Unmarshal(derBytes, pub3)
+ if err != nil {
+ t.Errorf("Unmarshal(rsa.PublicKey): %v", err)
+ }
+ if len(rest) != 0 || pub.N.Cmp(pub3.N) != 0 || pub.E != pub3.E {
+ t.Errorf("Unmarshal(rsa.PublicKey) = %+v, %q want %+v, %q", pub, rest, pub2, []byte(nil))
+ }
+
+ publicKeys := []struct {
+ derBytes []byte
+ expectedErrSubstr string
+ }{
+ {
+ derBytes: []byte{
+ 0x30, 6, // SEQUENCE, 6 bytes
+ 0x02, 1, // INTEGER, 1 byte
+ 17,
+ 0x02, 1, // INTEGER, 1 byte
+ 3, // 3
+ },
+ }, {
+ derBytes: []byte{
+ 0x30, 6, // SEQUENCE
+ 0x02, 1, // INTEGER, 1 byte
+ 0xff, // -1
+ 0x02, 1, // INTEGER, 1 byte
+ 3,
+ },
+ expectedErrSubstr: "zero or negative",
+ }, {
+ derBytes: []byte{
+ 0x30, 6, // SEQUENCE
+ 0x02, 1, // INTEGER, 1 byte
+ 17,
+ 0x02, 1, // INTEGER, 1 byte
+ 0xff, // -1
+ },
+ expectedErrSubstr: "zero or negative",
+ }, {
+ derBytes: []byte{
+ 0x30, 6, // SEQUENCE
+ 0x02, 1, // INTEGER, 1 byte
+ 17,
+ 0x02, 1, // INTEGER, 1 byte
+ 3,
+ 1,
+ },
+ expectedErrSubstr: "trailing data",
+ }, {
+ derBytes: []byte{
+ 0x30, 9, // SEQUENCE
+ 0x02, 1, // INTEGER, 1 byte
+ 17,
+ 0x02, 4, // INTEGER, 4 bytes
+ 0x7f, 0xff, 0xff, 0xff,
+ },
+ }, {
+ derBytes: []byte{
+ 0x30, 10, // SEQUENCE
+ 0x02, 1, // INTEGER, 1 byte
+ 17,
+ 0x02, 5, // INTEGER, 5 bytes
+ 0x00, 0x80, 0x00, 0x00, 0x00,
+ },
+ // On 64-bit systems, encoding/asn1 will accept the
+ // public exponent, but ParsePKCS1PublicKey will return
+ // an error. On 32-bit systems, encoding/asn1 will
+ // return the error. The common substring of both error
+ // is the word “large”.
+ expectedErrSubstr: "large",
+ },
+ }
+
+ for i, test := range publicKeys {
+ shouldFail := len(test.expectedErrSubstr) > 0
+ pub, err := ParsePKCS1PublicKey(test.derBytes)
+ if shouldFail {
+ if err == nil {
+ t.Errorf("#%d: unexpected success, got %#v", i, pub)
+ } else if !strings.Contains(err.Error(), test.expectedErrSubstr) {
+ t.Errorf("#%d: expected error containing %q, got %s", i, test.expectedErrSubstr, err)
+ }
+ } else {
+ if err != nil {
+ t.Errorf("#%d: unexpected failure: %s", i, err)
+ continue
+ }
+ reserialized := MarshalPKCS1PublicKey(pub)
+ if !bytes.Equal(reserialized, test.derBytes) {
+ t.Errorf("#%d: failed to reserialize: got %x, expected %x", i, reserialized, test.derBytes)
+ }
+ }
+ }
+}
+
+type matchHostnamesTest struct {
+ pattern, host string
+ ok bool
+}
+
+var matchHostnamesTests = []matchHostnamesTest{
+ {"a.b.c", "a.b.c", true},
+ {"a.b.c", "b.b.c", false},
+ {"", "b.b.c", false},
+ {"a.b.c", "", false},
+ {"example.com", "example.com", true},
+ {"example.com", "www.example.com", false},
+ {"*.example.com", "example.com", false},
+ {"*.example.com", "www.example.com", true},
+ {"*.example.com", "www.example.com.", true},
+ {"*.example.com", "xyz.www.example.com", false},
+ {"*.example.com", "https://www.example.com", false}, // Issue 27591
+ {"*.example..com", "www.example..com", false},
+ {"www.example..com", "www.example..com", true},
+ {"*.*.example.com", "xyz.www.example.com", false},
+ {"*.www.*.com", "xyz.www.example.com", false},
+ {"*bar.example.com", "foobar.example.com", false},
+ {"f*.example.com", "foobar.example.com", false},
+ {"www.example.com", "*.example.com", false},
+ {"", ".", false},
+ {".", "", false},
+ {".", ".", false},
+ {"example.com", "example.com.", true},
+ {"example.com.", "example.com", false},
+ {"example.com.", "example.com.", true}, // perfect matches allow trailing dots in patterns
+ {"*.com.", "example.com.", false},
+ {"*.com.", "example.com", false},
+ {"*.com", "example.com", true},
+ {"*.com", "example.com.", true},
+ {"foo:bar", "foo:bar", true},
+ {"*.foo:bar", "xxx.foo:bar", false},
+ {"*.2.3.4", "1.2.3.4", false},
+ {"*.2.3.4", "[1.2.3.4]", false},
+ {"*:4860:4860::8888", "2001:4860:4860::8888", false},
+ {"*:4860:4860::8888", "[2001:4860:4860::8888]", false},
+ {"2001:4860:4860::8888", "2001:4860:4860::8888", false},
+ {"2001:4860:4860::8888", "[2001:4860:4860::8888]", false},
+ {"[2001:4860:4860::8888]", "2001:4860:4860::8888", false},
+ {"[2001:4860:4860::8888]", "[2001:4860:4860::8888]", false},
+}
+
+func TestMatchHostnames(t *testing.T) {
+ for i, test := range matchHostnamesTests {
+ c := &Certificate{DNSNames: []string{test.pattern}}
+ r := c.VerifyHostname(test.host) == nil
+ if r != test.ok {
+ t.Errorf("#%d mismatch got: %t want: %t when matching '%s' against '%s'", i, r, test.ok, test.host, test.pattern)
+ }
+ }
+}
+
+func TestMatchIP(t *testing.T) {
+ // Check that pattern matching is working.
+ c := &Certificate{
+ DNSNames: []string{"*.foo.bar.baz"},
+ Subject: pkix.Name{
+ CommonName: "*.foo.bar.baz",
+ },
+ }
+ err := c.VerifyHostname("quux.foo.bar.baz")
+ if err != nil {
+ t.Fatalf("VerifyHostname(quux.foo.bar.baz): %v", err)
+ }
+
+ // But check that if we change it to be matching against an IP address,
+ // it is rejected.
+ c = &Certificate{
+ DNSNames: []string{"*.2.3.4"},
+ Subject: pkix.Name{
+ CommonName: "*.2.3.4",
+ },
+ }
+ err = c.VerifyHostname("1.2.3.4")
+ if err == nil {
+ t.Fatalf("VerifyHostname(1.2.3.4) should have failed, did not")
+ }
+
+ c = &Certificate{
+ IPAddresses: []net.IP{net.ParseIP("127.0.0.1"), net.ParseIP("::1")},
+ }
+ err = c.VerifyHostname("127.0.0.1")
+ if err != nil {
+ t.Fatalf("VerifyHostname(127.0.0.1): %v", err)
+ }
+ err = c.VerifyHostname("::1")
+ if err != nil {
+ t.Fatalf("VerifyHostname(::1): %v", err)
+ }
+ err = c.VerifyHostname("[::1]")
+ if err != nil {
+ t.Fatalf("VerifyHostname([::1]): %v", err)
+ }
+}
+
+func TestCertificateParse(t *testing.T) {
+ s, _ := base64.StdEncoding.DecodeString(certBytes)
+ certs, err := ParseCertificates(s)
+ if err != nil {
+ t.Error(err)
+ }
+ if len(certs) != 2 {
+ t.Errorf("Wrong number of certs: got %d want 2", len(certs))
+ return
+ }
+
+ err = certs[0].CheckSignatureFrom(certs[1])
+ if err != nil {
+ t.Error(err)
+ }
+
+ if err := certs[0].VerifyHostname("mail.google.com"); err != nil {
+ t.Error(err)
+ }
+
+ const expectedExtensions = 10
+ if n := len(certs[0].Extensions); n != expectedExtensions {
+ t.Errorf("want %d extensions, got %d", expectedExtensions, n)
+ }
+}
+
+func TestCertificateEqualOnNil(t *testing.T) {
+ cNonNil := new(Certificate)
+ var cNil1, cNil2 *Certificate
+ if !cNil1.Equal(cNil2) {
+ t.Error("Nil certificates: cNil1 is not equal to cNil2")
+ }
+ if !cNil2.Equal(cNil1) {
+ t.Error("Nil certificates: cNil2 is not equal to cNil1")
+ }
+ if cNil1.Equal(cNonNil) {
+ t.Error("Unexpectedly cNil1 is equal to cNonNil")
+ }
+ if cNonNil.Equal(cNil1) {
+ t.Error("Unexpectedly cNonNil is equal to cNil1")
+ }
+}
+
+func TestMismatchedSignatureAlgorithm(t *testing.T) {
+ der, _ := pem.Decode([]byte(rsaPSSSelfSignedPEM))
+ if der == nil {
+ t.Fatal("Failed to find PEM block")
+ }
+
+ cert, err := ParseCertificate(der.Bytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ if err = cert.CheckSignature(ECDSAWithSHA256, nil, nil); err == nil {
+ t.Fatal("CheckSignature unexpectedly return no error")
+ }
+
+ const expectedSubstring = " but have public key of type "
+ if !strings.Contains(err.Error(), expectedSubstring) {
+ t.Errorf("Expected error containing %q, but got %q", expectedSubstring, err)
+ }
+}
+
+var certBytes = "MIIE0jCCA7qgAwIBAgIQWcvS+TTB3GwCAAAAAGEAWzANBgkqhkiG9w0BAQsFADBCMQswCQYD" +
+ "VQQGEwJVUzEeMBwGA1UEChMVR29vZ2xlIFRydXN0IFNlcnZpY2VzMRMwEQYDVQQDEwpHVFMg" +
+ "Q0EgMU8xMB4XDTIwMDQwMTEyNTg1NloXDTIwMDYyNDEyNTg1NlowaTELMAkGA1UEBhMCVVMx" +
+ "EzARBgNVBAgTCkNhbGlmb3JuaWExFjAUBgNVBAcTDU1vdW50YWluIFZpZXcxEzARBgNVBAoT" +
+ "Ckdvb2dsZSBMTEMxGDAWBgNVBAMTD21haWwuZ29vZ2xlLmNvbTBZMBMGByqGSM49AgEGCCqG" +
+ "SM49AwEHA0IABO+dYiPnkFl+cZVf6mrWeNp0RhQcJSBGH+sEJxjvc+cYlW3QJCnm57qlpFdd" +
+ "pz3MPyVejvXQdM6iI1mEWP4C2OujggJmMIICYjAOBgNVHQ8BAf8EBAMCB4AwEwYDVR0lBAww" +
+ "CgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQUI6pZhnQ/lQgmPDwSKR2A54G7" +
+ "AS4wHwYDVR0jBBgwFoAUmNH4bhDrz5vsYJ8YkBug630J/SswZAYIKwYBBQUHAQEEWDBWMCcG" +
+ "CCsGAQUFBzABhhtodHRwOi8vb2NzcC5wa2kuZ29vZy9ndHMxbzEwKwYIKwYBBQUHMAKGH2h0" +
+ "dHA6Ly9wa2kuZ29vZy9nc3IyL0dUUzFPMS5jcnQwLAYDVR0RBCUwI4IPbWFpbC5nb29nbGUu" +
+ "Y29tghBpbmJveC5nb29nbGUuY29tMCEGA1UdIAQaMBgwCAYGZ4EMAQICMAwGCisGAQQB1nkC" +
+ "BQMwLwYDVR0fBCgwJjAkoCKgIIYeaHR0cDovL2NybC5wa2kuZ29vZy9HVFMxTzEuY3JsMIIB" +
+ "AwYKKwYBBAHWeQIEAgSB9ASB8QDvAHYAsh4FzIuizYogTodm+Su5iiUgZ2va+nDnsklTLe+L" +
+ "kF4AAAFxNgmxKgAABAMARzBFAiEA12/OHdTGXQ3qHHC3NvYCyB8aEz/+ZFOLCAI7lhqj28sC" +
+ "IG2/7Yz2zK6S6ai+dH7cTMZmoFGo39gtaTqtZAqEQX7nAHUAXqdz+d9WwOe1Nkh90EngMnqR" +
+ "mgyEoRIShBh1loFxRVgAAAFxNgmxTAAABAMARjBEAiA7PNq+MFfv6O9mBkxFViS2TfU66yRB" +
+ "/njcebWglLQjZQIgOyRKhxlEizncFRml7yn4Bg48ktXKGjo+uiw6zXEINb0wDQYJKoZIhvcN" +
+ "AQELBQADggEBADM2Rh306Q10PScsolYMxH1B/K4Nb2WICvpY0yDPJFdnGjqCYym196TjiEvs" +
+ "R6etfeHdyzlZj6nh82B4TVyHjiWM02dQgPalOuWQcuSy0OvLh7F1E7CeHzKlczdFPBTOTdM1" +
+ "RDTxlvw1bAqc0zueM8QIAyEy3opd7FxAcGQd5WRIJhzLBL+dbbMOW/LTeW7cm/Xzq8cgCybN" +
+ "BSZAvhjseJ1L29OlCTZL97IfnX0IlFQzWuvvHy7V2B0E3DHlzM0kjwkkCKDUUp/wajv2NZKC" +
+ "TkhEyERacZRKc9U0ADxwsAzHrdz5+5zfD2usEV/MQ5V6d8swLXs+ko0X6swrd4YCiB8wggRK" +
+ "MIIDMqADAgECAg0B47SaoY2KqYElaVC4MA0GCSqGSIb3DQEBCwUAMEwxIDAeBgNVBAsTF0ds" +
+ "b2JhbFNpZ24gUm9vdCBDQSAtIFIyMRMwEQYDVQQKEwpHbG9iYWxTaWduMRMwEQYDVQQDEwpH" +
+ "bG9iYWxTaWduMB4XDTE3MDYxNTAwMDA0MloXDTIxMTIxNTAwMDA0MlowQjELMAkGA1UEBhMC" +
+ "VVMxHjAcBgNVBAoTFUdvb2dsZSBUcnVzdCBTZXJ2aWNlczETMBEGA1UEAxMKR1RTIENBIDFP" +
+ "MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANAYz0XUi83TnORA73603WkhG8nP" +
+ "PI5MdbkPMRmEPZ48Ke9QDRCTbwWAgJ8qoL0SSwLhPZ9YFiT+MJ8LdHdVkx1L903hkoIQ9lGs" +
+ "DMOyIpQPNGuYEEnnC52DOd0gxhwt79EYYWXnI4MgqCMS/9Ikf9Qv50RqW03XUGawr55CYwX7" +
+ "4BzEY2Gvn2oz/2KXvUjZ03wUZ9x13C5p6PhteGnQtxAFuPExwjsk/RozdPgj4OxrGYoWxuPN" +
+ "pM0L27OkWWA4iDutHbnGjKdTG/y82aSrvN08YdeTFZjugb2P4mRHIEAGTtesl+i5wFkSoUkl" +
+ "I+TtcDQspbRjfPmjPYPRzW0krAcCAwEAAaOCATMwggEvMA4GA1UdDwEB/wQEAwIBhjAdBgNV" +
+ "HSUEFjAUBggrBgEFBQcDAQYIKwYBBQUHAwIwEgYDVR0TAQH/BAgwBgEB/wIBADAdBgNVHQ4E" +
+ "FgQUmNH4bhDrz5vsYJ8YkBug630J/SswHwYDVR0jBBgwFoAUm+IHV2ccHsBqBt5ZtJot39wZ" +
+ "hi4wNQYIKwYBBQUHAQEEKTAnMCUGCCsGAQUFBzABhhlodHRwOi8vb2NzcC5wa2kuZ29vZy9n" +
+ "c3IyMDIGA1UdHwQrMCkwJ6AloCOGIWh0dHA6Ly9jcmwucGtpLmdvb2cvZ3NyMi9nc3IyLmNy" +
+ "bDA/BgNVHSAEODA2MDQGBmeBDAECAjAqMCgGCCsGAQUFBwIBFhxodHRwczovL3BraS5nb29n" +
+ "L3JlcG9zaXRvcnkvMA0GCSqGSIb3DQEBCwUAA4IBAQAagD42efvzLqlGN31eVBY1rsdOCJn+" +
+ "vdE0aSZSZgc9CrpJy2L08RqO/BFPaJZMdCvTZ96yo6oFjYRNTCBlD6WW2g0W+Gw7228EI4hr" +
+ "OmzBYL1on3GO7i1YNAfw1VTphln9e14NIZT1jMmo+NjyrcwPGvOap6kEJ/mjybD/AnhrYbrH" +
+ "NSvoVvpPwxwM7bY8tEvq7czhPOzcDYzWPpvKQliLzBYhF0C8otZm79rEFVvNiaqbCSbnMtIN" +
+ "bmcgAlsQsJAJnAwfnq3YO+qh/GzoEFwIUhlRKnG7rHq13RXtK8kIKiyKtKYhq2P/11JJUNCJ" +
+ "t63yr/tQri/hlQ3zRq2dnPXK"
+
+func parseCIDR(s string) *net.IPNet {
+ _, net, err := net.ParseCIDR(s)
+ if err != nil {
+ panic(err)
+ }
+ return net
+}
+
+func parseURI(s string) *url.URL {
+ uri, err := url.Parse(s)
+ if err != nil {
+ panic(err)
+ }
+ return uri
+}
+
+func TestCreateSelfSignedCertificate(t *testing.T) {
+ random := rand.Reader
+
+ ecdsaPriv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatalf("Failed to generate ECDSA key: %s", err)
+ }
+
+ ed25519Pub, ed25519Priv, err := ed25519.GenerateKey(random)
+ if err != nil {
+ t.Fatalf("Failed to generate Ed25519 key: %s", err)
+ }
+
+ tests := []struct {
+ name string
+ pub, priv any
+ checkSig bool
+ sigAlgo SignatureAlgorithm
+ }{
+ {"RSA/RSA", &testPrivateKey.PublicKey, testPrivateKey, true, SHA384WithRSA},
+ {"RSA/ECDSA", &testPrivateKey.PublicKey, ecdsaPriv, false, ECDSAWithSHA384},
+ {"ECDSA/RSA", &ecdsaPriv.PublicKey, testPrivateKey, false, SHA256WithRSA},
+ {"ECDSA/ECDSA", &ecdsaPriv.PublicKey, ecdsaPriv, true, ECDSAWithSHA256},
+ {"RSAPSS/RSAPSS", &testPrivateKey.PublicKey, testPrivateKey, true, SHA256WithRSAPSS},
+ {"ECDSA/RSAPSS", &ecdsaPriv.PublicKey, testPrivateKey, false, SHA256WithRSAPSS},
+ {"RSAPSS/ECDSA", &testPrivateKey.PublicKey, ecdsaPriv, false, ECDSAWithSHA384},
+ {"Ed25519", ed25519Pub, ed25519Priv, true, PureEd25519},
+ }
+
+ testExtKeyUsage := []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageServerAuth}
+ testUnknownExtKeyUsage := []asn1.ObjectIdentifier{[]int{1, 2, 3}, []int{2, 59, 1}}
+ extraExtensionData := []byte("extra extension")
+
+ for _, test := range tests {
+ commonName := "test.example.com"
+ template := Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
+ CommonName: commonName,
+ Organization: []string{"Σ Acme Co"},
+ Country: []string{"US"},
+ ExtraNames: []pkix.AttributeTypeAndValue{
+ {
+ Type: []int{2, 5, 4, 42},
+ Value: "Gopher",
+ },
+ // This should override the Country, above.
+ {
+ Type: []int{2, 5, 4, 6},
+ Value: "NL",
+ },
+ },
+ },
+ NotBefore: time.Unix(1000, 0),
+ NotAfter: time.Unix(100000, 0),
+
+ SignatureAlgorithm: test.sigAlgo,
+
+ SubjectKeyId: []byte{1, 2, 3, 4},
+ KeyUsage: KeyUsageCertSign,
+
+ ExtKeyUsage: testExtKeyUsage,
+ UnknownExtKeyUsage: testUnknownExtKeyUsage,
+
+ BasicConstraintsValid: true,
+ IsCA: true,
+
+ OCSPServer: []string{"http://ocsp.example.com"},
+ IssuingCertificateURL: []string{"http://crt.example.com/ca1.crt"},
+
+ DNSNames: []string{"test.example.com"},
+ EmailAddresses: []string{"gopher@golang.org"},
+ IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1).To4(), net.ParseIP("2001:4860:0:2001::68")},
+ URIs: []*url.URL{parseURI("https://foo.com/wibble#foo")},
+
+ PolicyIdentifiers: []asn1.ObjectIdentifier{[]int{1, 2, 3}},
+ PermittedDNSDomains: []string{".example.com", "example.com"},
+ ExcludedDNSDomains: []string{"bar.example.com"},
+ PermittedIPRanges: []*net.IPNet{parseCIDR("192.168.1.1/16"), parseCIDR("1.2.3.4/8")},
+ ExcludedIPRanges: []*net.IPNet{parseCIDR("2001:db8::/48")},
+ PermittedEmailAddresses: []string{"foo@example.com"},
+ ExcludedEmailAddresses: []string{".example.com", "example.com"},
+ PermittedURIDomains: []string{".bar.com", "bar.com"},
+ ExcludedURIDomains: []string{".bar2.com", "bar2.com"},
+
+ CRLDistributionPoints: []string{"http://crl1.example.com/ca1.crl", "http://crl2.example.com/ca1.crl"},
+
+ ExtraExtensions: []pkix.Extension{
+ {
+ Id: []int{1, 2, 3, 4},
+ Value: extraExtensionData,
+ },
+ // This extension should override the SubjectKeyId, above.
+ {
+ Id: oidExtensionSubjectKeyId,
+ Critical: false,
+ Value: []byte{0x04, 0x04, 4, 3, 2, 1},
+ },
+ },
+ }
+
+ derBytes, err := CreateCertificate(random, &template, &template, test.pub, test.priv)
+ if err != nil {
+ t.Errorf("%s: failed to create certificate: %s", test.name, err)
+ continue
+ }
+
+ cert, err := ParseCertificate(derBytes)
+ if err != nil {
+ t.Errorf("%s: failed to parse certificate: %s", test.name, err)
+ continue
+ }
+
+ if len(cert.PolicyIdentifiers) != 1 || !cert.PolicyIdentifiers[0].Equal(template.PolicyIdentifiers[0]) {
+ t.Errorf("%s: failed to parse policy identifiers: got:%#v want:%#v", test.name, cert.PolicyIdentifiers, template.PolicyIdentifiers)
+ }
+
+ if len(cert.PermittedDNSDomains) != 2 || cert.PermittedDNSDomains[0] != ".example.com" || cert.PermittedDNSDomains[1] != "example.com" {
+ t.Errorf("%s: failed to parse name constraints: %#v", test.name, cert.PermittedDNSDomains)
+ }
+
+ if len(cert.ExcludedDNSDomains) != 1 || cert.ExcludedDNSDomains[0] != "bar.example.com" {
+ t.Errorf("%s: failed to parse name constraint exclusions: %#v", test.name, cert.ExcludedDNSDomains)
+ }
+
+ if len(cert.PermittedIPRanges) != 2 || cert.PermittedIPRanges[0].String() != "192.168.0.0/16" || cert.PermittedIPRanges[1].String() != "1.0.0.0/8" {
+ t.Errorf("%s: failed to parse IP constraints: %#v", test.name, cert.PermittedIPRanges)
+ }
+
+ if len(cert.ExcludedIPRanges) != 1 || cert.ExcludedIPRanges[0].String() != "2001:db8::/48" {
+ t.Errorf("%s: failed to parse IP constraint exclusions: %#v", test.name, cert.ExcludedIPRanges)
+ }
+
+ if len(cert.PermittedEmailAddresses) != 1 || cert.PermittedEmailAddresses[0] != "foo@example.com" {
+ t.Errorf("%s: failed to parse permitted email addresses: %#v", test.name, cert.PermittedEmailAddresses)
+ }
+
+ if len(cert.ExcludedEmailAddresses) != 2 || cert.ExcludedEmailAddresses[0] != ".example.com" || cert.ExcludedEmailAddresses[1] != "example.com" {
+ t.Errorf("%s: failed to parse excluded email addresses: %#v", test.name, cert.ExcludedEmailAddresses)
+ }
+
+ if len(cert.PermittedURIDomains) != 2 || cert.PermittedURIDomains[0] != ".bar.com" || cert.PermittedURIDomains[1] != "bar.com" {
+ t.Errorf("%s: failed to parse permitted URIs: %#v", test.name, cert.PermittedURIDomains)
+ }
+
+ if len(cert.ExcludedURIDomains) != 2 || cert.ExcludedURIDomains[0] != ".bar2.com" || cert.ExcludedURIDomains[1] != "bar2.com" {
+ t.Errorf("%s: failed to parse excluded URIs: %#v", test.name, cert.ExcludedURIDomains)
+ }
+
+ if cert.Subject.CommonName != commonName {
+ t.Errorf("%s: subject wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Subject.CommonName, commonName)
+ }
+
+ if len(cert.Subject.Country) != 1 || cert.Subject.Country[0] != "NL" {
+ t.Errorf("%s: ExtraNames didn't override Country", test.name)
+ }
+
+ for _, ext := range cert.Extensions {
+ if ext.Id.Equal(oidExtensionSubjectAltName) {
+ if ext.Critical {
+ t.Fatal("SAN extension is marked critical")
+ }
+ }
+ }
+
+ found := false
+ for _, atv := range cert.Subject.Names {
+ if atv.Type.Equal([]int{2, 5, 4, 42}) {
+ found = true
+ break
+ }
+ }
+ if !found {
+ t.Errorf("%s: Names didn't contain oid 2.5.4.42 from ExtraNames", test.name)
+ }
+
+ if cert.Issuer.CommonName != commonName {
+ t.Errorf("%s: issuer wasn't correctly copied from the template. Got %s, want %s", test.name, cert.Issuer.CommonName, commonName)
+ }
+
+ if cert.SignatureAlgorithm != test.sigAlgo {
+ t.Errorf("%s: SignatureAlgorithm wasn't copied from template. Got %v, want %v", test.name, cert.SignatureAlgorithm, test.sigAlgo)
+ }
+
+ if !reflect.DeepEqual(cert.ExtKeyUsage, testExtKeyUsage) {
+ t.Errorf("%s: extkeyusage wasn't correctly copied from the template. Got %v, want %v", test.name, cert.ExtKeyUsage, testExtKeyUsage)
+ }
+
+ if !reflect.DeepEqual(cert.UnknownExtKeyUsage, testUnknownExtKeyUsage) {
+ t.Errorf("%s: unknown extkeyusage wasn't correctly copied from the template. Got %v, want %v", test.name, cert.UnknownExtKeyUsage, testUnknownExtKeyUsage)
+ }
+
+ if !reflect.DeepEqual(cert.OCSPServer, template.OCSPServer) {
+ t.Errorf("%s: OCSP servers differ from template. Got %v, want %v", test.name, cert.OCSPServer, template.OCSPServer)
+ }
+
+ if !reflect.DeepEqual(cert.IssuingCertificateURL, template.IssuingCertificateURL) {
+ t.Errorf("%s: Issuing certificate URLs differ from template. Got %v, want %v", test.name, cert.IssuingCertificateURL, template.IssuingCertificateURL)
+ }
+
+ if !reflect.DeepEqual(cert.DNSNames, template.DNSNames) {
+ t.Errorf("%s: SAN DNS names differ from template. Got %v, want %v", test.name, cert.DNSNames, template.DNSNames)
+ }
+
+ if !reflect.DeepEqual(cert.EmailAddresses, template.EmailAddresses) {
+ t.Errorf("%s: SAN emails differ from template. Got %v, want %v", test.name, cert.EmailAddresses, template.EmailAddresses)
+ }
+
+ if len(cert.URIs) != 1 || cert.URIs[0].String() != "https://foo.com/wibble#foo" {
+ t.Errorf("%s: URIs differ from template. Got %v, want %v", test.name, cert.URIs, template.URIs)
+ }
+
+ if !reflect.DeepEqual(cert.IPAddresses, template.IPAddresses) {
+ t.Errorf("%s: SAN IPs differ from template. Got %v, want %v", test.name, cert.IPAddresses, template.IPAddresses)
+ }
+
+ if !reflect.DeepEqual(cert.CRLDistributionPoints, template.CRLDistributionPoints) {
+ t.Errorf("%s: CRL distribution points differ from template. Got %v, want %v", test.name, cert.CRLDistributionPoints, template.CRLDistributionPoints)
+ }
+
+ if !bytes.Equal(cert.SubjectKeyId, []byte{4, 3, 2, 1}) {
+ t.Errorf("%s: ExtraExtensions didn't override SubjectKeyId", test.name)
+ }
+
+ if !bytes.Contains(derBytes, extraExtensionData) {
+ t.Errorf("%s: didn't find extra extension in DER output", test.name)
+ }
+
+ if test.checkSig {
+ err = cert.CheckSignatureFrom(cert)
+ if err != nil {
+ t.Errorf("%s: signature verification failed: %s", test.name, err)
+ }
+ }
+ }
+}
+
+// Self-signed certificate using ECDSA with SHA1 & secp256r1
+var ecdsaSHA1CertPem = `
+-----BEGIN CERTIFICATE-----
+MIICDjCCAbUCCQDF6SfN0nsnrjAJBgcqhkjOPQQBMIGPMQswCQYDVQQGEwJVUzET
+MBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNTW91bnRhaW4gVmlldzEVMBMG
+A1UECgwMR29vZ2xlLCBJbmMuMRcwFQYDVQQDDA53d3cuZ29vZ2xlLmNvbTEjMCEG
+CSqGSIb3DQEJARYUZ29sYW5nLWRldkBnbWFpbC5jb20wHhcNMTIwNTIwMjAyMDUw
+WhcNMjIwNTE4MjAyMDUwWjCBjzELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlm
+b3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTATBgNVBAoMDEdvb2dsZSwg
+SW5jLjEXMBUGA1UEAwwOd3d3Lmdvb2dsZS5jb20xIzAhBgkqhkiG9w0BCQEWFGdv
+bGFuZy1kZXZAZ21haWwuY29tMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE/Wgn
+WQDo5+bz71T0327ERgd5SDDXFbXLpzIZDXTkjpe8QTEbsF+ezsQfrekrpDPC4Cd3
+P9LY0tG+aI8IyVKdUjAJBgcqhkjOPQQBA0gAMEUCIGlsqMcRqWVIWTD6wXwe6Jk2
+DKxL46r/FLgJYnzBEH99AiEA3fBouObsvV1R3oVkb4BQYnD4/4LeId6lAT43YvyV
+a/A=
+-----END CERTIFICATE-----
+`
+
+// Self-signed certificate using ECDSA with SHA256 & secp256r1
+var ecdsaSHA256p256CertPem = `
+-----BEGIN CERTIFICATE-----
+MIICDzCCAbYCCQDlsuMWvgQzhTAKBggqhkjOPQQDAjCBjzELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFTAT
+BgNVBAoMDEdvb2dsZSwgSW5jLjEXMBUGA1UEAwwOd3d3Lmdvb2dsZS5jb20xIzAh
+BgkqhkiG9w0BCQEWFGdvbGFuZy1kZXZAZ21haWwuY29tMB4XDTEyMDUyMTAwMTkx
+NloXDTIyMDUxOTAwMTkxNlowgY8xCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxp
+Zm9ybmlhMRYwFAYDVQQHDA1Nb3VudGFpbiBWaWV3MRUwEwYDVQQKDAxHb29nbGUs
+IEluYy4xFzAVBgNVBAMMDnd3dy5nb29nbGUuY29tMSMwIQYJKoZIhvcNAQkBFhRn
+b2xhbmctZGV2QGdtYWlsLmNvbTBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABPMt
+2ErhxAty5EJRu9yM+MTy+hUXm3pdW1ensAv382KoGExSXAFWP7pjJnNtHO+XSwVm
+YNtqjcAGFKpweoN//kQwCgYIKoZIzj0EAwIDRwAwRAIgIYSaUA/IB81gjbIw/hUV
+70twxJr5EcgOo0hLp3Jm+EYCIFDO3NNcgmURbJ1kfoS3N/0O+irUtoPw38YoNkqJ
+h5wi
+-----END CERTIFICATE-----
+`
+
+// Self-signed certificate using ECDSA with SHA256 & secp384r1
+var ecdsaSHA256p384CertPem = `
+-----BEGIN CERTIFICATE-----
+MIICSjCCAdECCQDje/no7mXkVzAKBggqhkjOPQQDAjCBjjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFDAS
+BgNVBAoMC0dvb2dsZSwgSW5jMRcwFQYDVQQDDA53d3cuZ29vZ2xlLmNvbTEjMCEG
+CSqGSIb3DQEJARYUZ29sYW5nLWRldkBnbWFpbC5jb20wHhcNMTIwNTIxMDYxMDM0
+WhcNMjIwNTE5MDYxMDM0WjCBjjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlm
+b3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFDASBgNVBAoMC0dvb2dsZSwg
+SW5jMRcwFQYDVQQDDA53d3cuZ29vZ2xlLmNvbTEjMCEGCSqGSIb3DQEJARYUZ29s
+YW5nLWRldkBnbWFpbC5jb20wdjAQBgcqhkjOPQIBBgUrgQQAIgNiAARRuzRNIKRK
+jIktEmXanNmrTR/q/FaHXLhWRZ6nHWe26Fw7Rsrbk+VjGy4vfWtNn7xSFKrOu5ze
+qxKnmE0h5E480MNgrUiRkaGO2GMJJVmxx20aqkXOk59U8yGA4CghE6MwCgYIKoZI
+zj0EAwIDZwAwZAIwBZEN8gvmRmfeP/9C1PRLzODIY4JqWub2PLRT4mv9GU+yw3Gr
+PU9A3CHMdEcdw/MEAjBBO1lId8KOCh9UZunsSMfqXiVurpzmhWd6VYZ/32G+M+Mh
+3yILeYQzllt/g0rKVRk=
+-----END CERTIFICATE-----
+`
+
+// Self-signed certificate using ECDSA with SHA384 & secp521r1
+var ecdsaSHA384p521CertPem = `
+-----BEGIN CERTIFICATE-----
+MIICljCCAfcCCQDhp1AFD/ahKjAKBggqhkjOPQQDAzCBjjELMAkGA1UEBhMCVVMx
+EzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFDAS
+BgNVBAoMC0dvb2dsZSwgSW5jMRcwFQYDVQQDDA53d3cuZ29vZ2xlLmNvbTEjMCEG
+CSqGSIb3DQEJARYUZ29sYW5nLWRldkBnbWFpbC5jb20wHhcNMTIwNTIxMTUwNDI5
+WhcNMjIwNTE5MTUwNDI5WjCBjjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlm
+b3JuaWExFjAUBgNVBAcMDU1vdW50YWluIFZpZXcxFDASBgNVBAoMC0dvb2dsZSwg
+SW5jMRcwFQYDVQQDDA53d3cuZ29vZ2xlLmNvbTEjMCEGCSqGSIb3DQEJARYUZ29s
+YW5nLWRldkBnbWFpbC5jb20wgZswEAYHKoZIzj0CAQYFK4EEACMDgYYABACqx9Rv
+IssRs1LWYcNN+WffwlHw4Tv3y8/LIAA9MF1ZScIonU9nRMxt4a2uGJVCPDw6JHpz
+PaYc0E9puLoE9AfKpwFr59Jkot7dBg55SKPEFkddoip/rvmN7NPAWjMBirOwjOkm
+8FPthvPhGPqsu9AvgVuHu3PosWiHGNrhh379pva8MzAKBggqhkjOPQQDAwOBjAAw
+gYgCQgEHNmswkUdPpHqrVxp9PvLVl+xxPuHBkT+75z9JizyxtqykHQo9Uh6SWCYH
+BF9KLolo01wMt8DjoYP5Fb3j5MH7xwJCAbWZzTOp4l4DPkIvAh4LeC4VWbwPPyqh
+kBg71w/iEcSY3wUKgHGcJJrObZw7wys91I5kENljqw/Samdr3ka+jBJa
+-----END CERTIFICATE-----
+`
+
+var ecdsaTests = []struct {
+ sigAlgo SignatureAlgorithm
+ pemCert string
+}{
+ {ECDSAWithSHA256, ecdsaSHA256p256CertPem},
+ {ECDSAWithSHA256, ecdsaSHA256p384CertPem},
+ {ECDSAWithSHA384, ecdsaSHA384p521CertPem},
+}
+
+func TestECDSA(t *testing.T) {
+ for i, test := range ecdsaTests {
+ pemBlock, _ := pem.Decode([]byte(test.pemCert))
+ cert, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ t.Errorf("%d: failed to parse certificate: %s", i, err)
+ continue
+ }
+ if sa := cert.SignatureAlgorithm; sa != test.sigAlgo {
+ t.Errorf("%d: signature algorithm is %v, want %v", i, sa, test.sigAlgo)
+ }
+ if parsedKey, ok := cert.PublicKey.(*ecdsa.PublicKey); !ok {
+ t.Errorf("%d: wanted an ECDSA public key but found: %#v", i, parsedKey)
+ }
+ if pka := cert.PublicKeyAlgorithm; pka != ECDSA {
+ t.Errorf("%d: public key algorithm is %v, want ECDSA", i, pka)
+ }
+ if err = cert.CheckSignatureFrom(cert); err != nil {
+ t.Errorf("%d: certificate verification failed: %s", i, err)
+ }
+ }
+}
+
+// Self-signed certificate using DSA with SHA1
+var dsaCertPem = `-----BEGIN CERTIFICATE-----
+MIIEDTCCA82gAwIBAgIJALHPghaoxeDhMAkGByqGSM44BAMweTELMAkGA1UEBhMC
+VVMxCzAJBgNVBAgTAk5DMQ8wDQYDVQQHEwZOZXd0b24xFDASBgNVBAoTC0dvb2ds
+ZSwgSW5jMRIwEAYDVQQDEwlKb24gQWxsaWUxIjAgBgkqhkiG9w0BCQEWE2pvbmFs
+bGllQGdvb2dsZS5jb20wHhcNMTEwNTE0MDMwMTQ1WhcNMTEwNjEzMDMwMTQ1WjB5
+MQswCQYDVQQGEwJVUzELMAkGA1UECBMCTkMxDzANBgNVBAcTBk5ld3RvbjEUMBIG
+A1UEChMLR29vZ2xlLCBJbmMxEjAQBgNVBAMTCUpvbiBBbGxpZTEiMCAGCSqGSIb3
+DQEJARYTam9uYWxsaWVAZ29vZ2xlLmNvbTCCAbcwggEsBgcqhkjOOAQBMIIBHwKB
+gQC8hLUnQ7FpFYu4WXTj6DKvXvz8QrJkNJCVMTpKAT7uBpobk32S5RrPKXocd4gN
+8lyGB9ggS03EVlEwXvSmO0DH2MQtke2jl9j1HLydClMf4sbx5V6TV9IFw505U1iW
+jL7awRMgxge+FsudtJK254FjMFo03ZnOQ8ZJJ9E6AEDrlwIVAJpnBn9moyP11Ox5
+Asc/5dnjb6dPAoGBAJFHd4KVv1iTVCvEG6gGiYop5DJh28hUQcN9kul+2A0yPUSC
+X93oN00P8Vh3eYgSaCWZsha7zDG53MrVJ0Zf6v/X/CoZNhLldeNOepivTRAzn+Rz
+kKUYy5l1sxYLHQKF0UGNCXfFKZT0PCmgU+PWhYNBBMn6/cIh44vp85ideo5CA4GE
+AAKBgFmifCafzeRaohYKXJgMGSEaggCVCRq5xdyDCat+wbOkjC4mfG01/um3G8u5
+LxasjlWRKTR/tcAL7t0QuokVyQaYdVypZXNaMtx1db7YBuHjj3aP+8JOQRI9xz8c
+bp5NDJ5pISiFOv4p3GZfqZPcqckDt78AtkQrmnal2txhhjF6o4HeMIHbMB0GA1Ud
+DgQWBBQVyyr7hO11ZFFpWX50298Sa3V+rzCBqwYDVR0jBIGjMIGggBQVyyr7hO11
+ZFFpWX50298Sa3V+r6F9pHsweTELMAkGA1UEBhMCVVMxCzAJBgNVBAgTAk5DMQ8w
+DQYDVQQHEwZOZXd0b24xFDASBgNVBAoTC0dvb2dsZSwgSW5jMRIwEAYDVQQDEwlK
+b24gQWxsaWUxIjAgBgkqhkiG9w0BCQEWE2pvbmFsbGllQGdvb2dsZS5jb22CCQCx
+z4IWqMXg4TAMBgNVHRMEBTADAQH/MAkGByqGSM44BAMDLwAwLAIUPtn/5j8Q1jJI
+7ggOIsgrhgUdjGQCFCsmDq1H11q9+9Wp9IMeGrTSKHIM
+-----END CERTIFICATE-----
+`
+
+func TestParseCertificateWithDsaPublicKey(t *testing.T) {
+ expectedKey := &dsa.PublicKey{
+ Parameters: dsa.Parameters{
+ P: bigFromHexString("00BC84B52743B169158BB85974E3E832AF5EFCFC42B264349095313A4A013EEE069A1B937D92E51ACF297A1C77880DF25C8607D8204B4DC45651305EF4A63B40C7D8C42D91EDA397D8F51CBC9D0A531FE2C6F1E55E9357D205C39D395358968CBEDAC11320C607BE16CB9DB492B6E78163305A34DD99CE43C64927D13A0040EB97"),
+ Q: bigFromHexString("009A67067F66A323F5D4EC7902C73FE5D9E36FA74F"),
+ G: bigFromHexString("009147778295BF5893542BC41BA806898A29E43261DBC85441C37D92E97ED80D323D44825FDDE8374D0FF15877798812682599B216BBCC31B9DCCAD527465FEAFFD7FC2A193612E575E34E7A98AF4D10339FE47390A518CB9975B3160B1D0285D1418D0977C52994F43C29A053E3D685834104C9FAFDC221E38BE9F3989D7A8E42"),
+ },
+ Y: bigFromHexString("59A27C269FCDE45AA2160A5C980C19211A820095091AB9C5DC8309AB7EC1B3A48C2E267C6D35FEE9B71BCBB92F16AC8E559129347FB5C00BEEDD10BA8915C90698755CA965735A32DC7575BED806E1E38F768FFBC24E41123DC73F1C6E9E4D0C9E692128853AFE29DC665FA993DCA9C903B7BF00B6442B9A76A5DADC6186317A"),
+ }
+ pemBlock, _ := pem.Decode([]byte(dsaCertPem))
+ cert, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse certificate: %s", err)
+ }
+ if cert.PublicKeyAlgorithm != DSA {
+ t.Errorf("Parsed key algorithm was not DSA")
+ }
+ parsedKey, ok := cert.PublicKey.(*dsa.PublicKey)
+ if !ok {
+ t.Fatalf("Parsed key was not a DSA key: %s", err)
+ }
+ if expectedKey.Y.Cmp(parsedKey.Y) != 0 ||
+ expectedKey.P.Cmp(parsedKey.P) != 0 ||
+ expectedKey.Q.Cmp(parsedKey.Q) != 0 ||
+ expectedKey.G.Cmp(parsedKey.G) != 0 {
+ t.Fatal("Parsed key differs from expected key")
+ }
+}
+
+func TestParseCertificateWithDSASignatureAlgorithm(t *testing.T) {
+ pemBlock, _ := pem.Decode([]byte(dsaCertPem))
+ cert, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse certificate: %s", err)
+ }
+ if cert.SignatureAlgorithm != DSAWithSHA1 {
+ t.Errorf("Parsed signature algorithm was not DSAWithSHA1")
+ }
+}
+
+func TestVerifyCertificateWithDSASignature(t *testing.T) {
+ pemBlock, _ := pem.Decode([]byte(dsaCertPem))
+ cert, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse certificate: %s", err)
+ }
+ // test cert is self-signed
+ if err = cert.CheckSignatureFrom(cert); err == nil {
+ t.Fatalf("Expected error verifying DSA certificate")
+ }
+}
+
+var rsaPSSSelfSignedPEM = `-----BEGIN CERTIFICATE-----
+MIIGHjCCA9KgAwIBAgIBdjBBBgkqhkiG9w0BAQowNKAPMA0GCWCGSAFlAwQCAQUA
+oRwwGgYJKoZIhvcNAQEIMA0GCWCGSAFlAwQCAQUAogMCASAwbjELMAkGA1UEBhMC
+SlAxHDAaBgNVBAoME0phcGFuZXNlIEdvdmVybm1lbnQxKDAmBgNVBAsMH1RoZSBN
+aW5pc3RyeSBvZiBGb3JlaWduIEFmZmFpcnMxFzAVBgNVBAMMDmUtcGFzc3BvcnRD
+U0NBMB4XDTEzMDUxNDA1MDczMFoXDTI5MDUxNDA1MDczMFowbjELMAkGA1UEBhMC
+SlAxHDAaBgNVBAoME0phcGFuZXNlIEdvdmVybm1lbnQxKDAmBgNVBAsMH1RoZSBN
+aW5pc3RyeSBvZiBGb3JlaWduIEFmZmFpcnMxFzAVBgNVBAMMDmUtcGFzc3BvcnRD
+U0NBMIICIjANBgkqhkiG9w0BAQEFAAOCAg8AMIICCgKCAgEAx/E3WRVxcCDXhoST
+8nVSLjW6hwM4Ni99AegWzcGtfGFo0zjFA1Cl5URqxauvYu3gQgQHBGA1CovWeGrl
+yVSRzOL1imcYsSgLOcnhVYB3Xcrof4ebv9+W+TwNdc9YzAwcj8rNd5nP6PKXIQ+W
+PCkEOXdyb80YEnxuT+NPjkVfFSPBS7QYZpvT2fwy4fZ0eh48253+7VleSmTO0mqj
+7TlzaG56q150SLZbhpOd8jD8bM/wACnLCPR88wj4hCcDLEwoLyY85HJCTIQQMnoT
+UpqyzEeupPREIm6yi4d8C9YqIWFn2YTnRcWcmMaJLzq+kYwKoudfnoC6RW2vzZXn
+defQs68IZuK+uALu9G3JWGPgu0CQGj0JNDT8zkiDV++4eNrZczWKjr1YnAL+VbLK
+bApwL2u19l2WDpfUklimhWfraqHNIUKU6CjZOG31RzXcplIj0mtqs0E1r7r357Es
+yFoB28iNo4cz1lCulh0E4WJzWzLZcT4ZspHHRCFyvYnXoibXEV1nULq8ByKKG0FS
+7nn4SseoV+8PvjHLPhmHGMvi4mxkbcXdV3wthHT1/HXdqY84A4xHWt1+sB/TpTek
+tDhFlEfcUygvTu58UtOnysomOVVeERmi7WSujfzKsGJAJYeetiA5R+zX7BxeyFVE
+qW0zh1Tkwh0S8LRe5diJh4+6FG0CAwEAAaNfMF0wHQYDVR0OBBYEFD+oahaikBTV
+Urk81Uz7kRS2sx0aMA4GA1UdDwEB/wQEAwIBBjAYBgNVHSAEETAPMA0GCyqDCIaP
+fgYFAQEBMBIGA1UdEwEB/wQIMAYBAf8CAQAwQQYJKoZIhvcNAQEKMDSgDzANBglg
+hkgBZQMEAgEFAKEcMBoGCSqGSIb3DQEBCDANBglghkgBZQMEAgEFAKIDAgEgA4IC
+AQAaxWBQn5CZuNBfyzL57mn31ukHUFd61OMROSX3PT7oCv1Dy+C2AdRlxOcbN3/n
+li0yfXUUqiY3COlLAHKRlkr97mLtxEFoJ0R8nVN2IQdChNQM/XSCzSGyY8NVa1OR
+TTpEWLnexJ9kvIdbFXwUqdTnAkOI0m7Rg8j+E+lRRHg1xDAA1qKttrtUj3HRQWf3
+kNTu628SiMvap6aIdncburaK56MP7gkR1Wr/ichOfjIA3Jgw2PapI31i0GqeMd66
+U1+lC9FeyMAJpuSVp/SoiYzYo+79SFcVoM2yw3yAnIKg7q9GLYYqzncdykT6C06c
+15gWFI6igmReAsD9ITSvYh0jLrLHfEYcPTOD3ZXJ4EwwHtWSoO3gq1EAtOYKu/Lv
+C8zfBsZcFdsHvsSiYeBU8Oioe42mguky3Ax9O7D805Ek6R68ra07MW/G4YxvV7IN
+2BfSaYy8MX9IG0ZMIOcoc0FeF5xkFmJ7kdrlTaJzC0IE9PNxNaH5QnOAFB8vxHcO
+FioUxb6UKdHcPLR1VZtAdTdTMjSJxUqD/35Cdfqs7oDJXz8f6TXO2Tdy6G++YUs9
+qsGZWxzFvvkXUkQSl0dQQ5jO/FtUJcAVXVVp20LxPemfatAHpW31WdJYeWSQWky2
++f9b5TXKXVyjlUL7uHxowWrT2AtTchDH22wTEtqLEF9Z3Q==
+-----END CERTIFICATE-----`
+
+// openssl req -newkey rsa:2048 -keyout test.key -sha256 -sigopt \
+// rsa_padding_mode:pss -sigopt rsa_pss_saltlen:32 -sigopt rsa_mgf1_md:sha256 \
+// -x509 -days 3650 -nodes -subj '/C=US/ST=CA/L=SF/O=Test/CN=Test' -out \
+// test.pem
+var rsaPSSSelfSignedOpenSSL110PEM = `-----BEGIN CERTIFICATE-----
+MIIDwDCCAnigAwIBAgIJAM9LAMHTE5xpMD0GCSqGSIb3DQEBCjAwoA0wCwYJYIZI
+AWUDBAIBoRowGAYJKoZIhvcNAQEIMAsGCWCGSAFlAwQCAaIDAgEgMEUxCzAJBgNV
+BAYTAlVTMQswCQYDVQQIDAJDQTELMAkGA1UEBwwCU0YxDTALBgNVBAoMBFRlc3Qx
+DTALBgNVBAMMBFRlc3QwHhcNMTgwMjIyMjIxMzE4WhcNMjgwMjIwMjIxMzE4WjBF
+MQswCQYDVQQGEwJVUzELMAkGA1UECAwCQ0ExCzAJBgNVBAcMAlNGMQ0wCwYDVQQK
+DARUZXN0MQ0wCwYDVQQDDARUZXN0MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
+CgKCAQEA4Zrsydod+GoTAJLLutWNF87qhhVPBsK1zB1Gj+NAAe4+VbrZ1E41H1wp
+qITx7DA8DRtJEf+NqrTAnAdZWBG/tAOA5LfXVax0ZSQtLnYLSeylLoMtDyY3eFAj
+TmuTOoyVy6raktowCnHCh01NsstqqTfrx6SbmzOmDmKTkq/I+7K0MCVsn41xRDVM
++ShD0WGFGioEGoiWnFSWupxJDA3Q6jIDEygVwNKHwnhv/2NgG2kqZzrZSQA67en0
+iKAXtoDNPpmyD5oS9YbEJ+2Nbm7oLeON30i6kZvXKIzJXx+UWViazHZqnsi5rQ8G
+RHF+iVFXsqd0MzDKmkKOT5FDhrsbKQIDAQABo1MwUTAdBgNVHQ4EFgQU9uFY/nlg
+gLH00NBnr/o7QvpN9ugwHwYDVR0jBBgwFoAU9uFY/nlggLH00NBnr/o7QvpN9ugw
+DwYDVR0TAQH/BAUwAwEB/zA9BgkqhkiG9w0BAQowMKANMAsGCWCGSAFlAwQCAaEa
+MBgGCSqGSIb3DQEBCDALBglghkgBZQMEAgGiAwIBIAOCAQEAhJzpwxBNGKvzKWDe
+WLqv6RMrl/q4GcH3b7M9wjxe0yOm4F+Tb2zJ7re4h+D39YkJf8cX1NV9UQVu6z4s
+Fvo2kmlR0qZOXAg5augmCQ1xS0WHFoF6B52anNzHkZQbAIYJ3kGoFsUHzs7Sz7F/
+656FsRpHA9UzJQ3avPPMrA4Y4aoJ7ANJ6XIwTrdWrhULOVuvYRLCl4CdTVztVFX6
+wxX8nS1ISYd8jXPUMgsBKVbWufvLoIymMJW8CZbpprVZel5zFn0bmPrON8IHS30w
+Gs+ITJjKEnZgXmAQ25SLKVzkZkBcGANs2GsdHNJ370Puisy0FIPD2NXR5uASAf7J
++w9fjQ==
+-----END CERTIFICATE-----`
+
+func TestRSAPSSSelfSigned(t *testing.T) {
+ for i, pemBlock := range []string{rsaPSSSelfSignedPEM, rsaPSSSelfSignedOpenSSL110PEM} {
+ der, _ := pem.Decode([]byte(pemBlock))
+ if der == nil {
+ t.Errorf("#%d: failed to find PEM block", i)
+ continue
+ }
+
+ cert, err := ParseCertificate(der.Bytes)
+ if err != nil {
+ t.Errorf("#%d: failed to parse: %s", i, err)
+ continue
+ }
+
+ if err = cert.CheckSignatureFrom(cert); err != nil {
+ t.Errorf("#%d: signature check failed: %s", i, err)
+ continue
+ }
+ }
+}
+
+const ed25519Certificate = `
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 0c:83:d8:21:2b:82:cb:23:98:23:63:e2:f7:97:8a:43:5b:f3:bd:92
+ Signature Algorithm: ED25519
+ Issuer: CN = Ed25519 test certificate
+ Validity
+ Not Before: May 6 17:27:16 2019 GMT
+ Not After : Jun 5 17:27:16 2019 GMT
+ Subject: CN = Ed25519 test certificate
+ Subject Public Key Info:
+ Public Key Algorithm: ED25519
+ ED25519 Public-Key:
+ pub:
+ 36:29:c5:6c:0d:4f:14:6c:81:d0:ff:75:d3:6a:70:
+ 5f:69:cd:0f:4d:66:d5:da:98:7e:82:49:89:a3:8a:
+ 3c:fa
+ X509v3 extensions:
+ X509v3 Subject Key Identifier:
+ 09:3B:3A:9D:4A:29:D8:95:FF:68:BE:7B:43:54:72:E0:AD:A2:E3:AE
+ X509v3 Authority Key Identifier:
+ keyid:09:3B:3A:9D:4A:29:D8:95:FF:68:BE:7B:43:54:72:E0:AD:A2:E3:AE
+
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ Signature Algorithm: ED25519
+ 53:a5:58:1c:2c:3b:2a:9e:ac:9d:4e:a5:1d:5f:5d:6d:a6:b5:
+ 08:de:12:82:f3:97:20:ae:fa:d8:98:f4:1a:83:32:6b:91:f5:
+ 24:1d:c4:20:7f:2c:e2:4d:da:13:3b:6d:54:1a:d2:a8:28:dc:
+ 60:b9:d4:f4:78:4b:3c:1c:91:00
+-----BEGIN CERTIFICATE-----
+MIIBWzCCAQ2gAwIBAgIUDIPYISuCyyOYI2Pi95eKQ1vzvZIwBQYDK2VwMCMxITAf
+BgNVBAMMGEVkMjU1MTkgdGVzdCBjZXJ0aWZpY2F0ZTAeFw0xOTA1MDYxNzI3MTZa
+Fw0xOTA2MDUxNzI3MTZaMCMxITAfBgNVBAMMGEVkMjU1MTkgdGVzdCBjZXJ0aWZp
+Y2F0ZTAqMAUGAytlcAMhADYpxWwNTxRsgdD/ddNqcF9pzQ9NZtXamH6CSYmjijz6
+o1MwUTAdBgNVHQ4EFgQUCTs6nUop2JX/aL57Q1Ry4K2i464wHwYDVR0jBBgwFoAU
+CTs6nUop2JX/aL57Q1Ry4K2i464wDwYDVR0TAQH/BAUwAwEB/zAFBgMrZXADQQBT
+pVgcLDsqnqydTqUdX11tprUI3hKC85cgrvrYmPQagzJrkfUkHcQgfyziTdoTO21U
+GtKoKNxgudT0eEs8HJEA
+-----END CERTIFICATE-----`
+
+func TestEd25519SelfSigned(t *testing.T) {
+ der, _ := pem.Decode([]byte(ed25519Certificate))
+ if der == nil {
+ t.Fatalf("Failed to find PEM block")
+ }
+
+ cert, err := ParseCertificate(der.Bytes)
+ if err != nil {
+ t.Fatalf("Failed to parse: %s", err)
+ }
+
+ if cert.PublicKeyAlgorithm != Ed25519 {
+ t.Fatalf("Parsed key algorithm was not Ed25519")
+ }
+ parsedKey, ok := cert.PublicKey.(ed25519.PublicKey)
+ if !ok {
+ t.Fatalf("Parsed key was not an Ed25519 key: %s", err)
+ }
+ if len(parsedKey) != ed25519.PublicKeySize {
+ t.Fatalf("Invalid Ed25519 key")
+ }
+
+ if err = cert.CheckSignatureFrom(cert); err != nil {
+ t.Fatalf("Signature check failed: %s", err)
+ }
+}
+
+const pemCertificate = `-----BEGIN CERTIFICATE-----
+MIIDATCCAemgAwIBAgIRAKQkkrFx1T/dgB/Go/xBM5swDQYJKoZIhvcNAQELBQAw
+EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xNjA4MTcyMDM2MDdaFw0xNzA4MTcyMDM2
+MDdaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDAoJtjG7M6InsWwIo+l3qq9u+g2rKFXNu9/mZ24XQ8XhV6PUR+5HQ4
+jUFWC58ExYhottqK5zQtKGkw5NuhjowFUgWB/VlNGAUBHtJcWR/062wYrHBYRxJH
+qVXOpYKbIWwFKoXu3hcpg/CkdOlDWGKoZKBCwQwUBhWE7MDhpVdQ+ZljUJWL+FlK
+yQK5iRsJd5TGJ6VUzLzdT4fmN2DzeK6GLeyMpVpU3sWV90JJbxWQ4YrzkKzYhMmB
+EcpXTG2wm+ujiHU/k2p8zlf8Sm7VBM/scmnMFt0ynNXop4FWvJzEm1G0xD2t+e2I
+5Utr04dOZPCgkm++QJgYhtZvgW7ZZiGTAgMBAAGjUjBQMA4GA1UdDwEB/wQEAwIF
+oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBsGA1UdEQQUMBKC
+EHRlc3QuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggEBADpqKQxrthH5InC7
+X96UP0OJCu/lLEMkrjoEWYIQaFl7uLPxKH5AmQPH4lYwF7u7gksR7owVG9QU9fs6
+1fK7II9CVgCd/4tZ0zm98FmU4D0lHGtPARrrzoZaqVZcAvRnFTlPX5pFkPhVjjai
+/mkxX9LpD8oK1445DFHxK5UjLMmPIIWd8EOi+v5a+hgGwnJpoW7hntSl8kHMtTmy
+fnnktsblSUV4lRCit0ymC7Ojhe+gzCCwkgs5kDzVVag+tnl/0e2DloIjASwOhpbH
+KVcg7fBd484ht/sS+l0dsB4KDOSpd8JzVDMF8OZqlaydizoJO0yWr9GbCN1+OKq5
+EhLrEqU=
+-----END CERTIFICATE-----`
+
+const ed25519CRLCertificate = `
+Certificate:
+Data:
+ Version: 3 (0x2)
+ Serial Number:
+ 7a:07:a0:9d:14:04:16:fc:1f:d8:e5:fe:d1:1d:1f:8d
+ Signature Algorithm: ED25519
+ Issuer: CN = Ed25519 CRL Test CA
+ Validity
+ Not Before: Oct 30 01:20:20 2019 GMT
+ Not After : Dec 31 23:59:59 9999 GMT
+ Subject: CN = Ed25519 CRL Test CA
+ Subject Public Key Info:
+ Public Key Algorithm: ED25519
+ ED25519 Public-Key:
+ pub:
+ 95:73:3b:b0:06:2a:31:5a:b6:a7:a6:6e:ef:71:df:
+ ac:6f:6b:39:03:85:5e:63:4b:f8:a6:0f:68:c6:6f:
+ 75:21
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature, Certificate Sign, CRL Sign
+ X509v3 Extended Key Usage:
+ TLS Web Client Authentication, TLS Web Server Authentication, OCSP Signing
+ X509v3 Basic Constraints: critical
+ CA:TRUE
+ X509v3 Subject Key Identifier:
+ B7:17:DA:16:EA:C5:ED:1F:18:49:44:D3:D2:E3:A0:35:0A:81:93:60
+ X509v3 Authority Key Identifier:
+ keyid:B7:17:DA:16:EA:C5:ED:1F:18:49:44:D3:D2:E3:A0:35:0A:81:93:60
+
+Signature Algorithm: ED25519
+ fc:3e:14:ea:bb:70:c2:6f:38:34:70:bc:c8:a7:f4:7c:0d:1e:
+ 28:d7:2a:9f:22:8a:45:e8:02:76:84:1e:2d:64:2d:1e:09:b5:
+ 29:71:1f:95:8a:4e:79:87:51:60:9a:e7:86:40:f6:60:c7:d1:
+ ee:68:76:17:1d:90:cc:92:93:07
+-----BEGIN CERTIFICATE-----
+MIIBijCCATygAwIBAgIQegegnRQEFvwf2OX+0R0fjTAFBgMrZXAwHjEcMBoGA1UE
+AxMTRWQyNTUxOSBDUkwgVGVzdCBDQTAgFw0xOTEwMzAwMTIwMjBaGA85OTk5MTIz
+MTIzNTk1OVowHjEcMBoGA1UEAxMTRWQyNTUxOSBDUkwgVGVzdCBDQTAqMAUGAytl
+cAMhAJVzO7AGKjFatqembu9x36xvazkDhV5jS/imD2jGb3Uho4GNMIGKMA4GA1Ud
+DwEB/wQEAwIBhjAnBgNVHSUEIDAeBggrBgEFBQcDAgYIKwYBBQUHAwEGCCsGAQUF
+BwMJMA8GA1UdEwEB/wQFMAMBAf8wHQYDVR0OBBYEFLcX2hbqxe0fGElE09LjoDUK
+gZNgMB8GA1UdIwQYMBaAFLcX2hbqxe0fGElE09LjoDUKgZNgMAUGAytlcANBAPw+
+FOq7cMJvODRwvMin9HwNHijXKp8iikXoAnaEHi1kLR4JtSlxH5WKTnmHUWCa54ZA
+9mDH0e5odhcdkMySkwc=
+-----END CERTIFICATE-----`
+
+var ed25519CRLKey = testingKey(`-----BEGIN TEST KEY-----
+MC4CAQAwBQYDK2VwBCIEINdKh2096vUBYu4EIFpjShsUSh3vimKya1sQ1YTT4RZG
+-----END TEST KEY-----`)
+
+func TestCRLCreation(t *testing.T) {
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ privRSA, _ := ParsePKCS1PrivateKey(block.Bytes)
+ block, _ = pem.Decode([]byte(pemCertificate))
+ certRSA, _ := ParseCertificate(block.Bytes)
+
+ block, _ = pem.Decode([]byte(ed25519CRLKey))
+ privEd25519, _ := ParsePKCS8PrivateKey(block.Bytes)
+ block, _ = pem.Decode([]byte(ed25519CRLCertificate))
+ certEd25519, _ := ParseCertificate(block.Bytes)
+
+ tests := []struct {
+ name string
+ priv any
+ cert *Certificate
+ }{
+ {"RSA CA", privRSA, certRSA},
+ {"Ed25519 CA", privEd25519, certEd25519},
+ }
+
+ loc := time.FixedZone("Oz/Atlantis", int((2 * time.Hour).Seconds()))
+
+ now := time.Unix(1000, 0).In(loc)
+ nowUTC := now.UTC()
+ expiry := time.Unix(10000, 0)
+
+ revokedCerts := []pkix.RevokedCertificate{
+ {
+ SerialNumber: big.NewInt(1),
+ RevocationTime: nowUTC,
+ },
+ {
+ SerialNumber: big.NewInt(42),
+ // RevocationTime should be converted to UTC before marshaling.
+ RevocationTime: now,
+ },
+ }
+ expectedCerts := []pkix.RevokedCertificate{
+ {
+ SerialNumber: big.NewInt(1),
+ RevocationTime: nowUTC,
+ },
+ {
+ SerialNumber: big.NewInt(42),
+ RevocationTime: nowUTC,
+ },
+ }
+
+ for _, test := range tests {
+ crlBytes, err := test.cert.CreateCRL(rand.Reader, test.priv, revokedCerts, now, expiry)
+ if err != nil {
+ t.Errorf("%s: error creating CRL: %s", test.name, err)
+ }
+
+ parsedCRL, err := ParseDERCRL(crlBytes)
+ if err != nil {
+ t.Errorf("%s: error reparsing CRL: %s", test.name, err)
+ }
+ if !reflect.DeepEqual(parsedCRL.TBSCertList.RevokedCertificates, expectedCerts) {
+ t.Errorf("%s: RevokedCertificates mismatch: got %v; want %v.", test.name,
+ parsedCRL.TBSCertList.RevokedCertificates, expectedCerts)
+ }
+ }
+}
+
+func fromBase64(in string) []byte {
+ out := make([]byte, base64.StdEncoding.DecodedLen(len(in)))
+ n, err := base64.StdEncoding.Decode(out, []byte(in))
+ if err != nil {
+ panic("failed to base64 decode")
+ }
+ return out[:n]
+}
+
+func TestParseDERCRL(t *testing.T) {
+ derBytes := fromBase64(derCRLBase64)
+ certList, err := ParseDERCRL(derBytes)
+ if err != nil {
+ t.Errorf("error parsing: %s", err)
+ return
+ }
+ numCerts := len(certList.TBSCertList.RevokedCertificates)
+ expected := 88
+ if numCerts != expected {
+ t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
+ }
+
+ if certList.HasExpired(time.Unix(1302517272, 0)) {
+ t.Errorf("CRL has expired (but shouldn't have)")
+ }
+
+ // Can't check the signature here without a package cycle.
+}
+
+func TestCRLWithoutExpiry(t *testing.T) {
+ derBytes := fromBase64("MIHYMIGZMAkGByqGSM44BAMwEjEQMA4GA1UEAxMHQ2FybERTUxcNOTkwODI3MDcwMDAwWjBpMBMCAgDIFw05OTA4MjIwNzAwMDBaMBMCAgDJFw05OTA4MjIwNzAwMDBaMBMCAgDTFw05OTA4MjIwNzAwMDBaMBMCAgDSFw05OTA4MjIwNzAwMDBaMBMCAgDUFw05OTA4MjQwNzAwMDBaMAkGByqGSM44BAMDLwAwLAIUfmVSdjP+NHMX0feW+aDU2G1cfT0CFAJ6W7fVWxjBz4fvftok8yqDnDWh")
+ certList, err := ParseDERCRL(derBytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !certList.TBSCertList.NextUpdate.IsZero() {
+ t.Errorf("NextUpdate is not the zero value")
+ }
+}
+
+func TestParsePEMCRL(t *testing.T) {
+ pemBytes := fromBase64(pemCRLBase64)
+ certList, err := ParseCRL(pemBytes)
+ if err != nil {
+ t.Errorf("error parsing: %s", err)
+ return
+ }
+ numCerts := len(certList.TBSCertList.RevokedCertificates)
+ expected := 2
+ if numCerts != expected {
+ t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
+ }
+
+ if certList.HasExpired(time.Unix(1302517272, 0)) {
+ t.Errorf("CRL has expired (but shouldn't have)")
+ }
+
+ // Can't check the signature here without a package cycle.
+}
+
+func TestImports(t *testing.T) {
+ if testing.Short() {
+ t.Skip("skipping in -short mode")
+ }
+ testenv.MustHaveGoRun(t)
+
+ if out, err := exec.Command(testenv.GoToolPath(t), "run", "x509_test_import.go").CombinedOutput(); err != nil {
+ t.Errorf("failed to run x509_test_import.go: %s\n%s", err, out)
+ }
+}
+
+const derCRLBase64 = "MIINqzCCDJMCAQEwDQYJKoZIhvcNAQEFBQAwVjEZMBcGA1UEAxMQUEtJIEZJTk1FQ0NBTklDQTEVMBMGA1UEChMMRklOTUVDQ0FOSUNBMRUwEwYDVQQLEwxGSU5NRUNDQU5JQ0ExCzAJBgNVBAYTAklUFw0xMTA1MDQxNjU3NDJaFw0xMTA1MDQyMDU3NDJaMIIMBzAhAg4Ze1od49Lt1qIXBydAzhcNMDkwNzE2MDg0MzIyWjAAMCECDl0HSL9bcZ1Ci/UHJ0DPFw0wOTA3MTYwODQzMTNaMAAwIQIOESB9tVAmX3cY7QcnQNAXDTA5MDcxNjA4NDUyMlowADAhAg4S1tGAQ3mHt8uVBydA1RcNMDkwODA0MTUyNTIyWjAAMCECDlQ249Y7vtC25ScHJ0DWFw0wOTA4MDQxNTI1MzdaMAAwIQIOISMop3NkA4PfYwcnQNkXDTA5MDgwNDExMDAzNFowADAhAg56/BMoS29KEShTBydA2hcNMDkwODA0MTEwMTAzWjAAMCECDnBp/22HPH5CSWoHJ0DbFw0wOTA4MDQxMDU0NDlaMAAwIQIOV9IP+8CD8bK+XAcnQNwXDTA5MDgwNDEwNTcxN1owADAhAg4v5aRz0IxWqYiXBydA3RcNMDkwODA0MTA1NzQ1WjAAMCECDlOU34VzvZAybQwHJ0DeFw0wOTA4MDQxMDU4MjFaMAAwIAINO4CD9lluIxcwBydBAxcNMDkwNzIyMTUzMTU5WjAAMCECDgOllfO8Y1QA7/wHJ0ExFw0wOTA3MjQxMTQxNDNaMAAwIQIOJBX7jbiCdRdyjgcnQUQXDTA5MDkxNjA5MzAwOFowADAhAg5iYSAgmDrlH/RZBydBRRcNMDkwOTE2MDkzMDE3WjAAMCECDmu6k6srP3jcMaQHJ0FRFw0wOTA4MDQxMDU2NDBaMAAwIQIOX8aHlO0V+WVH4QcnQVMXDTA5MDgwNDEwNTcyOVowADAhAg5flK2rg3NnsRgDBydBzhcNMTEwMjAxMTUzMzQ2WjAAMCECDg35yJDL1jOPTgoHJ0HPFw0xMTAyMDExNTM0MjZaMAAwIQIOMyFJ6+e9iiGVBQcnQdAXDTA5MDkxODEzMjAwNVowADAhAg5Emb/Oykucmn8fBydB1xcNMDkwOTIxMTAxMDQ3WjAAMCECDjQKCncV+MnUavMHJ0HaFw0wOTA5MjIwODE1MjZaMAAwIQIOaxiFUt3dpd+tPwcnQfQXDTEwMDYxODA4NDI1MVowADAhAg5G7P8nO0tkrMt7BydB9RcNMTAwNjE4MDg0MjMwWjAAMCECDmTCC3SXhmDRst4HJ0H2Fw0wOTA5MjgxMjA3MjBaMAAwIQIOHoGhUr/pRwzTKgcnQfcXDTA5MDkyODEyMDcyNFowADAhAg50wrcrCiw8mQmPBydCBBcNMTAwMjE2MTMwMTA2WjAAMCECDifWmkvwyhEqwEcHJ0IFFw0xMDAyMTYxMzAxMjBaMAAwIQIOfgPmlW9fg+osNgcnQhwXDTEwMDQxMzA5NTIwMFowADAhAg4YHAGuA6LgCk7tBydCHRcNMTAwNDEzMDk1MTM4WjAAMCECDi1zH1bxkNJhokAHJ0IsFw0xMDA0MTMwOTU5MzBaMAAwIQIOMipNccsb/wo2fwcnQi0XDTEwMDQxMzA5NTkwMFowADAhAg46lCmvPl4GpP6ABydCShcNMTAwMTE5MDk1MjE3WjAAMCECDjaTcaj+wBpcGAsHJ0JLFw0xMDAxMTkwOTUyMzRaMAAwIQIOOMC13EOrBuxIOQcnQloXDTEwMDIwMTA5NDcwNVowADAhAg5KmZl+krz4RsmrBydCWxcNMTAwMjAxMDk0NjQwWjAAMCECDmLG3zQJ/fzdSsUHJ0JiFw0xMDAzMDEwOTUxNDBaMAAwIQIOP39ksgHdojf4owcnQmMXDTEwMDMwMTA5NTExN1owADAhAg4LDQzvWNRlD6v9BydCZBcNMTAwMzAxMDk0NjIyWjAAMCECDkmNfeclaFhIaaUHJ0JlFw0xMDAzMDEwOTQ2MDVaMAAwIQIOT/qWWfpH/m8NTwcnQpQXDTEwMDUxMTA5MTgyMVowADAhAg5m/ksYxvCEgJSvBydClRcNMTAwNTExMDkxODAxWjAAMCECDgvf3Ohq6JOPU9AHJ0KWFw0xMDA1MTEwOTIxMjNaMAAwIQIOKSPas10z4jNVIQcnQpcXDTEwMDUxMTA5MjEwMlowADAhAg4mCWmhoZ3lyKCDBydCohcNMTEwNDI4MTEwMjI1WjAAMCECDkeiyRsBMK0Gvr4HJ0KjFw0xMTA0MjgxMTAyMDdaMAAwIQIOa09b/nH2+55SSwcnQq4XDTExMDQwMTA4Mjk0NlowADAhAg5O7M7iq7gGplr1BydCrxcNMTEwNDAxMDgzMDE3WjAAMCECDjlT6mJxUjTvyogHJ0K1Fw0xMTAxMjcxNTQ4NTJaMAAwIQIODS/l4UUFLe21NAcnQrYXDTExMDEyNzE1NDgyOFowADAhAg5lPRA0XdOUF6lSBydDHhcNMTEwMTI4MTQzNTA1WjAAMCECDixKX4fFGGpENwgHJ0MfFw0xMTAxMjgxNDM1MzBaMAAwIQIORNBkqsPnpKTtbAcnQ08XDTEwMDkwOTA4NDg0MlowADAhAg5QL+EMM3lohedEBydDUBcNMTAwOTA5MDg0ODE5WjAAMCECDlhDnHK+HiTRAXcHJ0NUFw0xMDEwMTkxNjIxNDBaMAAwIQIOdBFqAzq/INz53gcnQ1UXDTEwMTAxOTE2MjA0NFowADAhAg4OjR7s8MgKles1BydDWhcNMTEwMTI3MTY1MzM2WjAAMCECDmfR/elHee+d0SoHJ0NbFw0xMTAxMjcxNjUzNTZaMAAwIQIOBTKv2ui+KFMI+wcnQ5YXDTEwMDkxNTEwMjE1N1owADAhAg49F3c/GSah+oRUBydDmxcNMTEwMTI3MTczMjMzWjAAMCECDggv4I61WwpKFMMHJ0OcFw0xMTAxMjcxNzMyNTVaMAAwIQIOXx/Y8sEvwS10LAcnQ6UXDTExMDEyODExMjkzN1owADAhAg5LSLbnVrSKaw/9BydDphcNMTEwMTI4MTEyOTIwWjAAMCECDmFFoCuhKUeACQQHJ0PfFw0xMTAxMTExMDE3MzdaMAAwIQIOQTDdFh2fSPF6AAcnQ+AXDTExMDExMTEwMTcxMFowADAhAg5B8AOXX61FpvbbBydD5RcNMTAxMDA2MTAxNDM2WjAAMCECDh41P2Gmi7PkwI4HJ0PmFw0xMDEwMDYxMDE2MjVaMAAwIQIOWUHGLQCd+Ale9gcnQ/0XDTExMDUwMjA3NTYxMFowADAhAg5Z2c9AYkikmgWOBydD/hcNMTEwNTAyMDc1NjM0WjAAMCECDmf/UD+/h8nf+74HJ0QVFw0xMTA0MTUwNzI4MzNaMAAwIQIOICvj4epy3MrqfwcnRBYXDTExMDQxNTA3Mjg1NlowADAhAg4bouRMfOYqgv4xBydEHxcNMTEwMzA4MTYyNDI1WjAAMCECDhebWHGoKiTp7pEHJ0QgFw0xMTAzMDgxNjI0NDhaMAAwIQIOX+qnxxAqJ8LtawcnRDcXDTExMDEzMTE1MTIyOFowADAhAg4j0fICqZ+wkOdqBydEOBcNMTEwMTMxMTUxMTQxWjAAMCECDhmXjsV4SUpWtAMHJ0RLFw0xMTAxMjgxMTI0MTJaMAAwIQIODno/w+zG43kkTwcnREwXDTExMDEyODExMjM1MlowADAhAg4b1gc88767Fr+LBydETxcNMTEwMTI4MTEwMjA4WjAAMCECDn+M3Pa1w2nyFeUHJ0RQFw0xMTAxMjgxMDU4NDVaMAAwIQIOaduoyIH61tqybAcnRJUXDTEwMTIxNTA5NDMyMlowADAhAg4nLqQPkyi3ESAKBydElhcNMTAxMjE1MDk0MzM2WjAAMCECDi504NIMH8578gQHJ0SbFw0xMTAyMTQxNDA1NDFaMAAwIQIOGuaM8PDaC5u1egcnRJwXDTExMDIxNDE0MDYwNFowADAhAg4ehYq/BXGnB5PWBydEnxcNMTEwMjA0MDgwOTUxWjAAMCECDkSD4eS4FxW5H20HJ0SgFw0xMTAyMDQwODA5MjVaMAAwIQIOOCcb6ilYObt1egcnRKEXDTExMDEyNjEwNDEyOVowADAhAg58tISWCCwFnKGnBydEohcNMTEwMjA0MDgxMzQyWjAAMCECDn5rjtabY/L/WL0HJ0TJFw0xMTAyMDQxMTAzNDFaMAAwDQYJKoZIhvcNAQEFBQADggEBAGnF2Gs0+LNiYCW1Ipm83OXQYP/bd5tFFRzyz3iepFqNfYs4D68/QihjFoRHQoXEB0OEe1tvaVnnPGnEOpi6krwekquMxo4H88B5SlyiFIqemCOIss0SxlCFs69LmfRYvPPvPEhoXtQ3ZThe0UvKG83GOklhvGl6OaiRf4Mt+m8zOT4Wox/j6aOBK6cw6qKCdmD+Yj1rrNqFGg1CnSWMoD6S6mwNgkzwdBUJZ22BwrzAAo4RHa2Uy3ef1FjwD0XtU5N3uDSxGGBEDvOe5z82rps3E22FpAA8eYl8kaXtmWqyvYU0epp4brGuTxCuBMCAsxt/OjIjeNNQbBGkwxgfYA0="
+
+const pemCRLBase64 = "LS0tLS1CRUdJTiBYNTA5IENSTC0tLS0tDQpNSUlCOWpDQ0FWOENBUUV3RFFZSktvWklodmNOQVFFRkJRQXdiREVhTUJnR0ExVUVDaE1SVWxOQklGTmxZM1Z5DQphWFI1SUVsdVl5NHhIakFjQmdOVkJBTVRGVkpUUVNCUWRXSnNhV01nVW05dmRDQkRRU0IyTVRFdU1Dd0dDU3FHDQpTSWIzRFFFSkFSWWZjbk5oYTJWdmJuSnZiM1J6YVdkdVFISnpZWE5sWTNWeWFYUjVMbU52YlJjTk1URXdNakl6DQpNVGt5T0RNd1doY05NVEV3T0RJeU1Ua3lPRE13V2pDQmpEQktBaEVBckRxb2g5RkhKSFhUN09QZ3V1bjQrQmNODQpNRGt4TVRBeU1UUXlOekE1V2pBbU1Bb0dBMVVkRlFRRENnRUpNQmdHQTFVZEdBUVJHQTh5TURBNU1URXdNakUwDQpNalExTlZvd1BnSVJBTEd6blowOTVQQjVhQU9MUGc1N2ZNTVhEVEF5TVRBeU16RTBOVEF4TkZvd0dqQVlCZ05WDQpIUmdFRVJnUE1qQXdNakV3TWpNeE5EVXdNVFJhb0RBd0xqQWZCZ05WSFNNRUdEQVdnQlQxVERGNlVRTS9MTmVMDQpsNWx2cUhHUXEzZzltekFMQmdOVkhSUUVCQUlDQUlRd0RRWUpLb1pJaHZjTkFRRUZCUUFEZ1lFQUZVNUFzNk16DQpxNVBSc2lmYW9iUVBHaDFhSkx5QytNczVBZ2MwYld5QTNHQWR4dXI1U3BQWmVSV0NCamlQL01FSEJXSkNsQkhQDQpHUmNxNXlJZDNFakRrYUV5eFJhK2k2N0x6dmhJNmMyOUVlNks5cFNZd2ppLzdSVWhtbW5Qclh0VHhsTDBsckxyDQptUVFKNnhoRFJhNUczUUE0Q21VZHNITnZicnpnbUNZcHZWRT0NCi0tLS0tRU5EIFg1MDkgQ1JMLS0tLS0NCg0K"
+
+func TestCreateCertificateRequest(t *testing.T) {
+ random := rand.Reader
+
+ ecdsa256Priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatalf("Failed to generate ECDSA key: %s", err)
+ }
+
+ ecdsa384Priv, err := ecdsa.GenerateKey(elliptic.P384(), rand.Reader)
+ if err != nil {
+ t.Fatalf("Failed to generate ECDSA key: %s", err)
+ }
+
+ ecdsa521Priv, err := ecdsa.GenerateKey(elliptic.P521(), rand.Reader)
+ if err != nil {
+ t.Fatalf("Failed to generate ECDSA key: %s", err)
+ }
+
+ _, ed25519Priv, err := ed25519.GenerateKey(random)
+ if err != nil {
+ t.Fatalf("Failed to generate Ed25519 key: %s", err)
+ }
+
+ tests := []struct {
+ name string
+ priv any
+ sigAlgo SignatureAlgorithm
+ }{
+ {"RSA", testPrivateKey, SHA256WithRSA},
+ {"ECDSA-256", ecdsa256Priv, ECDSAWithSHA256},
+ {"ECDSA-384", ecdsa384Priv, ECDSAWithSHA256},
+ {"ECDSA-521", ecdsa521Priv, ECDSAWithSHA256},
+ {"Ed25519", ed25519Priv, PureEd25519},
+ }
+
+ for _, test := range tests {
+ template := CertificateRequest{
+ Subject: pkix.Name{
+ CommonName: "test.example.com",
+ Organization: []string{"Σ Acme Co"},
+ },
+ SignatureAlgorithm: test.sigAlgo,
+ DNSNames: []string{"test.example.com"},
+ EmailAddresses: []string{"gopher@golang.org"},
+ IPAddresses: []net.IP{net.IPv4(127, 0, 0, 1).To4(), net.ParseIP("2001:4860:0:2001::68")},
+ }
+
+ derBytes, err := CreateCertificateRequest(random, &template, test.priv)
+ if err != nil {
+ t.Errorf("%s: failed to create certificate request: %s", test.name, err)
+ continue
+ }
+
+ out, err := ParseCertificateRequest(derBytes)
+ if err != nil {
+ t.Errorf("%s: failed to create certificate request: %s", test.name, err)
+ continue
+ }
+
+ err = out.CheckSignature()
+ if err != nil {
+ t.Errorf("%s: failed to check certificate request signature: %s", test.name, err)
+ continue
+ }
+
+ if out.Subject.CommonName != template.Subject.CommonName {
+ t.Errorf("%s: output subject common name and template subject common name don't match", test.name)
+ } else if len(out.Subject.Organization) != len(template.Subject.Organization) {
+ t.Errorf("%s: output subject organisation and template subject organisation don't match", test.name)
+ } else if len(out.DNSNames) != len(template.DNSNames) {
+ t.Errorf("%s: output DNS names and template DNS names don't match", test.name)
+ } else if len(out.EmailAddresses) != len(template.EmailAddresses) {
+ t.Errorf("%s: output email addresses and template email addresses don't match", test.name)
+ } else if len(out.IPAddresses) != len(template.IPAddresses) {
+ t.Errorf("%s: output IP addresses and template IP addresses names don't match", test.name)
+ }
+ }
+}
+
+func marshalAndParseCSR(t *testing.T, template *CertificateRequest) *CertificateRequest {
+ derBytes, err := CreateCertificateRequest(rand.Reader, template, testPrivateKey)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ csr, err := ParseCertificateRequest(derBytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ return csr
+}
+
+func TestCertificateRequestOverrides(t *testing.T) {
+ sanContents, err := marshalSANs([]string{"foo.example.com"}, nil, nil, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ template := CertificateRequest{
+ Subject: pkix.Name{
+ CommonName: "test.example.com",
+ Organization: []string{"Σ Acme Co"},
+ },
+ DNSNames: []string{"test.example.com"},
+
+ // An explicit extension should override the DNSNames from the
+ // template.
+ ExtraExtensions: []pkix.Extension{
+ {
+ Id: oidExtensionSubjectAltName,
+ Value: sanContents,
+ Critical: true,
+ },
+ },
+ }
+
+ csr := marshalAndParseCSR(t, &template)
+
+ if len(csr.DNSNames) != 1 || csr.DNSNames[0] != "foo.example.com" {
+ t.Errorf("Extension did not override template. Got %v\n", csr.DNSNames)
+ }
+
+ if len(csr.Extensions) != 1 || !csr.Extensions[0].Id.Equal(oidExtensionSubjectAltName) || !csr.Extensions[0].Critical {
+ t.Errorf("SAN extension was not faithfully copied, got %#v", csr.Extensions)
+ }
+
+ // If there is already an attribute with X.509 extensions then the
+ // extra extensions should be added to it rather than creating a CSR
+ // with two extension attributes.
+
+ template.Attributes = []pkix.AttributeTypeAndValueSET{
+ {
+ Type: oidExtensionRequest,
+ Value: [][]pkix.AttributeTypeAndValue{
+ {
+ {
+ Type: oidExtensionAuthorityInfoAccess,
+ Value: []byte("foo"),
+ },
+ },
+ },
+ },
+ }
+
+ csr = marshalAndParseCSR(t, &template)
+ if l := len(csr.Attributes); l != 1 {
+ t.Errorf("incorrect number of attributes: %d\n", l)
+ }
+
+ if !csr.Attributes[0].Type.Equal(oidExtensionRequest) ||
+ len(csr.Attributes[0].Value) != 1 ||
+ len(csr.Attributes[0].Value[0]) != 2 {
+ t.Errorf("bad attributes: %#v\n", csr.Attributes)
+ }
+
+ sanContents2, err := marshalSANs([]string{"foo2.example.com"}, nil, nil, nil)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Extensions in Attributes should override those in ExtraExtensions.
+ template.Attributes[0].Value[0] = append(template.Attributes[0].Value[0], pkix.AttributeTypeAndValue{
+ Type: oidExtensionSubjectAltName,
+ Value: sanContents2,
+ })
+
+ csr = marshalAndParseCSR(t, &template)
+
+ if len(csr.DNSNames) != 1 || csr.DNSNames[0] != "foo2.example.com" {
+ t.Errorf("Attributes did not override ExtraExtensions. Got %v\n", csr.DNSNames)
+ }
+}
+
+func TestParseCertificateRequest(t *testing.T) {
+ for _, csrBase64 := range csrBase64Array {
+ csrBytes := fromBase64(csrBase64)
+ csr, err := ParseCertificateRequest(csrBytes)
+ if err != nil {
+ t.Fatalf("failed to parse CSR: %s", err)
+ }
+
+ if len(csr.EmailAddresses) != 1 || csr.EmailAddresses[0] != "gopher@golang.org" {
+ t.Errorf("incorrect email addresses found: %v", csr.EmailAddresses)
+ }
+
+ if len(csr.DNSNames) != 1 || csr.DNSNames[0] != "test.example.com" {
+ t.Errorf("incorrect DNS names found: %v", csr.DNSNames)
+ }
+
+ if len(csr.Subject.Country) != 1 || csr.Subject.Country[0] != "AU" {
+ t.Errorf("incorrect Subject name: %v", csr.Subject)
+ }
+
+ found := false
+ for _, e := range csr.Extensions {
+ if e.Id.Equal(oidExtensionBasicConstraints) {
+ found = true
+ break
+ }
+ }
+ if !found {
+ t.Errorf("basic constraints extension not found in CSR")
+ }
+ }
+}
+
+func TestCriticalFlagInCSRRequestedExtensions(t *testing.T) {
+ // This CSR contains an extension request where the extensions have a
+ // critical flag in them. In the past we failed to handle this.
+ const csrBase64 = "MIICrTCCAZUCAQIwMzEgMB4GA1UEAwwXU0NFUCBDQSBmb3IgRGV2ZWxlciBTcmwxDzANBgNVBAsMBjQzNTk3MTCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBALFMAJ7Zy9YyfgbNlbUWAW0LalNRMPs7aXmLANsCpjhnw3lLlfDPaLeWyKh1nK5I5ojaJOW6KIOSAcJkDUe3rrE0wR0RVt3UxArqs0R/ND3u5Q+bDQY2X1HAFUHzUzcdm5JRAIA355v90teMckaWAIlkRQjDE22Lzc6NAl64KOd1rqOUNj8+PfX6fSo20jm94Pp1+a6mfk3G/RUWVuSm7owO5DZI/Fsi2ijdmb4NUar6K/bDKYTrDFkzcqAyMfP3TitUtBp19Mp3B1yAlHjlbp/r5fSSXfOGHZdgIvp0WkLuK2u5eQrX5l7HMB/5epgUs3HQxKY6ljhh5wAjDwz//LsCAwEAAaA1MDMGCSqGSIb3DQEJDjEmMCQwEgYDVR0TAQH/BAgwBgEB/wIBADAOBgNVHQ8BAf8EBAMCAoQwDQYJKoZIhvcNAQEFBQADggEBAAMq3bxJSPQEgzLYR/yaVvgjCDrc3zUbIwdOis6Go06Q4RnjH5yRaSZAqZQTDsPurQcnz2I39VMGEiSkFJFavf4QHIZ7QFLkyXadMtALc87tm17Ej719SbHcBSSZayR9VYJUNXRLayI6HvyUrmqcMKh+iX3WY3ICr59/wlM0tYa8DYN4yzmOa2Onb29gy3YlaF5A2AKAMmk003cRT9gY26mjpv7d21czOSSeNyVIoZ04IR9ee71vWTMdv0hu/af5kSjQ+ZG5/Qgc0+mnECLz/1gtxt1srLYbtYQ/qAY8oX1DCSGFS61tN/vl+4cxGMD/VGcGzADRLRHSlVqy2Qgss6Q="
+
+ csrBytes := fromBase64(csrBase64)
+ csr, err := ParseCertificateRequest(csrBytes)
+ if err != nil {
+ t.Fatalf("failed to parse CSR: %s", err)
+ }
+
+ expected := []struct {
+ Id asn1.ObjectIdentifier
+ Value []byte
+ }{
+ {oidExtensionBasicConstraints, fromBase64("MAYBAf8CAQA=")},
+ {oidExtensionKeyUsage, fromBase64("AwIChA==")},
+ }
+
+ if n := len(csr.Extensions); n != len(expected) {
+ t.Fatalf("expected to find %d extensions but found %d", len(expected), n)
+ }
+
+ for i, extension := range csr.Extensions {
+ if !extension.Id.Equal(expected[i].Id) {
+ t.Fatalf("extension #%d has unexpected type %v (expected %v)", i, extension.Id, expected[i].Id)
+ }
+
+ if !bytes.Equal(extension.Value, expected[i].Value) {
+ t.Fatalf("extension #%d has unexpected contents %x (expected %x)", i, extension.Value, expected[i].Value)
+ }
+ }
+}
+
+// serialiseAndParse generates a self-signed certificate from template and
+// returns a parsed version of it.
+func serialiseAndParse(t *testing.T, template *Certificate) *Certificate {
+ derBytes, err := CreateCertificate(rand.Reader, template, template, &testPrivateKey.PublicKey, testPrivateKey)
+ if err != nil {
+ t.Fatalf("failed to create certificate: %s", err)
+ return nil
+ }
+
+ cert, err := ParseCertificate(derBytes)
+ if err != nil {
+ t.Fatalf("failed to parse certificate: %s", err)
+ return nil
+ }
+
+ return cert
+}
+
+func TestMaxPathLenNotCA(t *testing.T) {
+ template := &Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
+ CommonName: "Σ Acme Co",
+ },
+ NotBefore: time.Unix(1000, 0),
+ NotAfter: time.Unix(100000, 0),
+
+ BasicConstraintsValid: true,
+ IsCA: false,
+ }
+ if m := serialiseAndParse(t, template).MaxPathLen; m != -1 {
+ t.Errorf("MaxPathLen should be -1 when IsCa is false, got %d", m)
+ }
+
+ template.MaxPathLen = -1
+ if m := serialiseAndParse(t, template).MaxPathLen; m != -1 {
+ t.Errorf("MaxPathLen should be -1 when IsCa is false and MaxPathLen set to -1, got %d", m)
+ }
+
+ template.MaxPathLen = 5
+ if _, err := CreateCertificate(rand.Reader, template, template, &testPrivateKey.PublicKey, testPrivateKey); err == nil {
+ t.Error("specifying a MaxPathLen when IsCA is false should fail")
+ }
+
+ template.MaxPathLen = 0
+ template.MaxPathLenZero = true
+ if _, err := CreateCertificate(rand.Reader, template, template, &testPrivateKey.PublicKey, testPrivateKey); err == nil {
+ t.Error("setting MaxPathLenZero when IsCA is false should fail")
+ }
+
+ template.BasicConstraintsValid = false
+ if m := serialiseAndParse(t, template).MaxPathLen; m != 0 {
+ t.Errorf("Bad MaxPathLen should be ignored if BasicConstraintsValid is false, got %d", m)
+ }
+}
+
+func TestMaxPathLen(t *testing.T) {
+ template := &Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
+ CommonName: "Σ Acme Co",
+ },
+ NotBefore: time.Unix(1000, 0),
+ NotAfter: time.Unix(100000, 0),
+
+ BasicConstraintsValid: true,
+ IsCA: true,
+ }
+
+ cert1 := serialiseAndParse(t, template)
+ if m := cert1.MaxPathLen; m != -1 {
+ t.Errorf("Omitting MaxPathLen didn't turn into -1, got %d", m)
+ }
+ if cert1.MaxPathLenZero {
+ t.Errorf("Omitting MaxPathLen resulted in MaxPathLenZero")
+ }
+
+ template.MaxPathLen = 1
+ cert2 := serialiseAndParse(t, template)
+ if m := cert2.MaxPathLen; m != 1 {
+ t.Errorf("Setting MaxPathLen didn't work. Got %d but set 1", m)
+ }
+ if cert2.MaxPathLenZero {
+ t.Errorf("Setting MaxPathLen resulted in MaxPathLenZero")
+ }
+
+ template.MaxPathLen = 0
+ template.MaxPathLenZero = true
+ cert3 := serialiseAndParse(t, template)
+ if m := cert3.MaxPathLen; m != 0 {
+ t.Errorf("Setting MaxPathLenZero didn't work, got %d", m)
+ }
+ if !cert3.MaxPathLenZero {
+ t.Errorf("Setting MaxPathLen to zero didn't result in MaxPathLenZero")
+ }
+}
+
+func TestNoAuthorityKeyIdInSelfSignedCert(t *testing.T) {
+ template := &Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
+ CommonName: "Σ Acme Co",
+ },
+ NotBefore: time.Unix(1000, 0),
+ NotAfter: time.Unix(100000, 0),
+
+ BasicConstraintsValid: true,
+ IsCA: true,
+ SubjectKeyId: []byte{1, 2, 3, 4},
+ }
+
+ if cert := serialiseAndParse(t, template); len(cert.AuthorityKeyId) != 0 {
+ t.Fatalf("self-signed certificate contained default authority key id")
+ }
+
+ template.AuthorityKeyId = []byte{1, 2, 3, 4}
+ if cert := serialiseAndParse(t, template); len(cert.AuthorityKeyId) == 0 {
+ t.Fatalf("self-signed certificate erased explicit authority key id")
+ }
+}
+
+func TestNoSubjectKeyIdInCert(t *testing.T) {
+ template := &Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
+ CommonName: "Σ Acme Co",
+ },
+ NotBefore: time.Unix(1000, 0),
+ NotAfter: time.Unix(100000, 0),
+
+ BasicConstraintsValid: true,
+ IsCA: true,
+ }
+ if cert := serialiseAndParse(t, template); len(cert.SubjectKeyId) == 0 {
+ t.Fatalf("self-signed certificate did not generate subject key id using the public key")
+ }
+
+ template.IsCA = false
+ if cert := serialiseAndParse(t, template); len(cert.SubjectKeyId) != 0 {
+ t.Fatalf("self-signed certificate generated subject key id when it isn't a CA")
+ }
+
+ template.SubjectKeyId = []byte{1, 2, 3, 4}
+ if cert := serialiseAndParse(t, template); len(cert.SubjectKeyId) == 0 {
+ t.Fatalf("self-signed certificate erased explicit subject key id")
+ }
+}
+
+func TestASN1BitLength(t *testing.T) {
+ tests := []struct {
+ bytes []byte
+ bitLen int
+ }{
+ {nil, 0},
+ {[]byte{0x00}, 0},
+ {[]byte{0x00, 0x00}, 0},
+ {[]byte{0xf0}, 4},
+ {[]byte{0x88}, 5},
+ {[]byte{0xff}, 8},
+ {[]byte{0xff, 0x80}, 9},
+ {[]byte{0xff, 0x81}, 16},
+ }
+
+ for i, test := range tests {
+ if got := asn1BitLength(test.bytes); got != test.bitLen {
+ t.Errorf("#%d: calculated bit-length of %d for %x, wanted %d", i, got, test.bytes, test.bitLen)
+ }
+ }
+}
+
+func TestVerifyEmptyCertificate(t *testing.T) {
+ if _, err := new(Certificate).Verify(VerifyOptions{}); err != errNotParsed {
+ t.Errorf("Verifying empty certificate resulted in unexpected error: %q (wanted %q)", err, errNotParsed)
+ }
+}
+
+func TestInsecureAlgorithmErrorString(t *testing.T) {
+ tests := []struct {
+ sa SignatureAlgorithm
+ want string
+ }{
+ {MD5WithRSA, "x509: cannot verify signature: insecure algorithm MD5-RSA"},
+ {SHA1WithRSA, "x509: cannot verify signature: insecure algorithm SHA1-RSA (temporarily override with GODEBUG=x509sha1=1)"},
+ {ECDSAWithSHA1, "x509: cannot verify signature: insecure algorithm ECDSA-SHA1 (temporarily override with GODEBUG=x509sha1=1)"},
+ {MD2WithRSA, "x509: cannot verify signature: insecure algorithm MD2-RSA"},
+ {-1, "x509: cannot verify signature: insecure algorithm -1"},
+ {0, "x509: cannot verify signature: insecure algorithm 0"},
+ {9999, "x509: cannot verify signature: insecure algorithm 9999"},
+ }
+ for i, tt := range tests {
+ if got := fmt.Sprint(InsecureAlgorithmError(tt.sa)); got != tt.want {
+ t.Errorf("%d. mismatch.\n got: %s\nwant: %s\n", i, got, tt.want)
+ }
+ }
+}
+
+// These CSR was generated with OpenSSL:
+//
+// openssl req -out CSR.csr -new -sha256 -nodes -keyout privateKey.key -config openssl.cnf
+//
+// With openssl.cnf containing the following sections:
+//
+// [ v3_req ]
+// basicConstraints = CA:FALSE
+// keyUsage = nonRepudiation, digitalSignature, keyEncipherment
+// subjectAltName = email:gopher@golang.org,DNS:test.example.com
+// [ req_attributes ]
+// challengePassword = ignored challenge
+// unstructuredName = ignored unstructured name
+var csrBase64Array = [...]string{
+ // Just [ v3_req ]
+ "MIIDHDCCAgQCAQAwfjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAwwLQ29tbW9uIE5hbWUxITAfBgkqhkiG9w0BCQEWEnRlc3RAZW1haWwuYWRkcmVzczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK1GY4YFx2ujlZEOJxQVYmsjUnLsd5nFVnNpLE4cV+77sgv9NPNlB8uhn3MXt5leD34rm/2BisCHOifPucYlSrszo2beuKhvwn4+2FxDmWtBEMu/QA16L5IvoOfYZm/gJTsPwKDqvaR0tTU67a9OtxwNTBMI56YKtmwd/o8d3hYv9cg+9ZGAZ/gKONcg/OWYx/XRh6bd0g8DMbCikpWgXKDsvvK1Nk+VtkDO1JxuBaj4Lz/p/MifTfnHoqHxWOWl4EaTs4Ychxsv34/rSj1KD1tJqorIv5Xv2aqv4sjxfbrYzX4kvS5SC1goIovLnhj5UjmQ3Qy8u65eow/LLWw+YFcCAwEAAaBZMFcGCSqGSIb3DQEJDjFKMEgwCQYDVR0TBAIwADALBgNVHQ8EBAMCBeAwLgYDVR0RBCcwJYERZ29waGVyQGdvbGFuZy5vcmeCEHRlc3QuZXhhbXBsZS5jb20wDQYJKoZIhvcNAQELBQADggEBAB6VPMRrchvNW61Tokyq3ZvO6/NoGIbuwUn54q6l5VZW0Ep5Nq8juhegSSnaJ0jrovmUgKDN9vEo2KxuAtwG6udS6Ami3zP+hRd4k9Q8djJPb78nrjzWiindLK5Fps9U5mMoi1ER8ViveyAOTfnZt/jsKUaRsscY2FzE9t9/o5moE6LTcHUS4Ap1eheR+J72WOnQYn3cifYaemsA9MJuLko+kQ6xseqttbh9zjqd9fiCSh/LNkzos9c+mg2yMADitaZinAh+HZi50ooEbjaT3erNq9O6RqwJlgD00g6MQdoz9bTAryCUhCQfkIaepmQ7BxS0pqWNW3MMwfDwx/Snz6g=",
+ // Both [ v3_req ] and [ req_attributes ]
+ "MIIDaTCCAlECAQAwfjELMAkGA1UEBhMCQVUxEzARBgNVBAgMClNvbWUtU3RhdGUxITAfBgNVBAoMGEludGVybmV0IFdpZGdpdHMgUHR5IEx0ZDEUMBIGA1UEAwwLQ29tbW9uIE5hbWUxITAfBgkqhkiG9w0BCQEWEnRlc3RAZW1haWwuYWRkcmVzczCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBAK1GY4YFx2ujlZEOJxQVYmsjUnLsd5nFVnNpLE4cV+77sgv9NPNlB8uhn3MXt5leD34rm/2BisCHOifPucYlSrszo2beuKhvwn4+2FxDmWtBEMu/QA16L5IvoOfYZm/gJTsPwKDqvaR0tTU67a9OtxwNTBMI56YKtmwd/o8d3hYv9cg+9ZGAZ/gKONcg/OWYx/XRh6bd0g8DMbCikpWgXKDsvvK1Nk+VtkDO1JxuBaj4Lz/p/MifTfnHoqHxWOWl4EaTs4Ychxsv34/rSj1KD1tJqorIv5Xv2aqv4sjxfbrYzX4kvS5SC1goIovLnhj5UjmQ3Qy8u65eow/LLWw+YFcCAwEAAaCBpTAgBgkqhkiG9w0BCQcxEwwRaWdub3JlZCBjaGFsbGVuZ2UwKAYJKoZIhvcNAQkCMRsMGWlnbm9yZWQgdW5zdHJ1Y3R1cmVkIG5hbWUwVwYJKoZIhvcNAQkOMUowSDAJBgNVHRMEAjAAMAsGA1UdDwQEAwIF4DAuBgNVHREEJzAlgRFnb3BoZXJAZ29sYW5nLm9yZ4IQdGVzdC5leGFtcGxlLmNvbTANBgkqhkiG9w0BAQsFAAOCAQEAgxe2N5O48EMsYE7o0rZBB0wi3Ov5/yYfnmmVI22Y3sP6VXbLDW0+UWIeSccOhzUCcZ/G4qcrfhhx6gTZTeA01nP7TdTJURvWAH5iFqj9sQ0qnLq6nEcVHij3sG6M5+BxAIVClQBk6lTCzgphc835Fjj6qSLuJ20XHdL5UfUbiJxx299CHgyBRL+hBUIPfz8p+ZgamyAuDLfnj54zzcRVyLlrmMLNPZNll1Q70RxoU6uWvLH8wB8vQe3Q/guSGubLyLRTUQVPh+dw1L4t8MKFWfX/48jwRM4gIRHFHPeAAE9D9YAoqdIvj/iFm/eQ++7DP8MDwOZWsXeB6jjwHuLmkQ==",
+}
+
+var md5cert = `
+-----BEGIN CERTIFICATE-----
+MIIB4TCCAUoCCQCfmw3vMgPS5TANBgkqhkiG9w0BAQQFADA1MQswCQYDVQQGEwJB
+VTETMBEGA1UECBMKU29tZS1TdGF0ZTERMA8GA1UEChMITUQ1IEluYy4wHhcNMTUx
+MjAzMTkyOTMyWhcNMjkwODEyMTkyOTMyWjA1MQswCQYDVQQGEwJBVTETMBEGA1UE
+CBMKU29tZS1TdGF0ZTERMA8GA1UEChMITUQ1IEluYy4wgZ8wDQYJKoZIhvcNAQEB
+BQADgY0AMIGJAoGBANrq2nhLQj5mlXbpVX3QUPhfEm/vdEqPkoWtR/jRZIWm4WGf
+Wpq/LKHJx2Pqwn+t117syN8l4U5unyAi1BJSXjBwPZNd7dXjcuJ+bRLV7FZ/iuvs
+cfYyQQFTxan4TaJMd0x1HoNDbNbjHa02IyjjYE/r3mb/PIg+J2t5AZEh80lPAgMB
+AAEwDQYJKoZIhvcNAQEEBQADgYEAjGzp3K3ey/YfKHohf33yHHWd695HQxDAP+wY
+cs9/TAyLR+gJzJP7d18EcDDLJWVi7bhfa4EAD86di05azOh9kWSn4b3o9QYRGCSw
+GNnI3Zk0cwNKA49hZntKKiy22DhRk7JAHF01d6Bu3KkHkmENrtJ+zj/+159WAnUa
+qViorq4=
+-----END CERTIFICATE-----
+`
+
+func TestMD5(t *testing.T) {
+ pemBlock, _ := pem.Decode([]byte(md5cert))
+ cert, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ t.Fatalf("failed to parse certificate: %s", err)
+ }
+ if sa := cert.SignatureAlgorithm; sa != MD5WithRSA {
+ t.Errorf("signature algorithm is %v, want %v", sa, MD5WithRSA)
+ }
+ if err = cert.CheckSignatureFrom(cert); err == nil {
+ t.Fatalf("certificate verification succeeded incorrectly")
+ }
+ if _, ok := err.(InsecureAlgorithmError); !ok {
+ t.Fatalf("certificate verification returned %v (%T), wanted InsecureAlgorithmError", err, err)
+ }
+}
+
+func TestSHA1(t *testing.T) {
+ pemBlock, _ := pem.Decode([]byte(ecdsaSHA1CertPem))
+ cert, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ t.Fatalf("failed to parse certificate: %s", err)
+ }
+ if sa := cert.SignatureAlgorithm; sa != ECDSAWithSHA1 {
+ t.Errorf("signature algorithm is %v, want %v", sa, ECDSAWithSHA1)
+ }
+ if err = cert.CheckSignatureFrom(cert); err == nil {
+ t.Fatalf("certificate verification succeeded incorrectly")
+ }
+ if _, ok := err.(InsecureAlgorithmError); !ok {
+ t.Fatalf("certificate verification returned %v (%T), wanted InsecureAlgorithmError", err, err)
+ }
+
+ t.Setenv("GODEBUG", "x509sha1=1")
+ if err = cert.CheckSignatureFrom(cert); err != nil {
+ t.Fatalf("SHA-1 certificate did not verify with GODEBUG=x509sha1=1: %v", err)
+ }
+}
+
+// certMissingRSANULL contains an RSA public key where the AlgorithmIdentifier
+// parameters are omitted rather than being an ASN.1 NULL.
+const certMissingRSANULL = `
+-----BEGIN CERTIFICATE-----
+MIIB7TCCAVigAwIBAgIBADALBgkqhkiG9w0BAQUwJjEQMA4GA1UEChMHQWNtZSBD
+bzESMBAGA1UEAxMJMTI3LjAuMC4xMB4XDTExMTIwODA3NTUxMloXDTEyMTIwNzA4
+MDAxMlowJjEQMA4GA1UEChMHQWNtZSBDbzESMBAGA1UEAxMJMTI3LjAuMC4xMIGc
+MAsGCSqGSIb3DQEBAQOBjAAwgYgCgYBO0Hsx44Jk2VnAwoekXh6LczPHY1PfZpIG
+hPZk1Y/kNqcdK+izIDZFI7Xjla7t4PUgnI2V339aEu+H5Fto5OkOdOwEin/ekyfE
+ARl6vfLcPRSr0FTKIQzQTW6HLlzF0rtNS0/Otiz3fojsfNcCkXSmHgwa2uNKWi7e
+E5xMQIhZkwIDAQABozIwMDAOBgNVHQ8BAf8EBAMCAKAwDQYDVR0OBAYEBAECAwQw
+DwYDVR0jBAgwBoAEAQIDBDALBgkqhkiG9w0BAQUDgYEANh+zegx1yW43RmEr1b3A
+p0vMRpqBWHyFeSnIyMZn3TJWRSt1tukkqVCavh9a+hoV2cxVlXIWg7nCto/9iIw4
+hB2rXZIxE0/9gzvGnfERYraL7KtnvshksBFQRlgXa5kc0x38BvEO5ZaoDPl4ILdE
+GFGNEH5PlGffo05wc46QkYU=
+-----END CERTIFICATE-----`
+
+func TestRSAMissingNULLParameters(t *testing.T) {
+ block, _ := pem.Decode([]byte(certMissingRSANULL))
+ if _, err := ParseCertificate(block.Bytes); err == nil {
+ t.Error("unexpected success when parsing certificate with missing RSA NULL parameter")
+ } else if !strings.Contains(err.Error(), "missing NULL") {
+ t.Errorf("unrecognised error when parsing certificate with missing RSA NULL parameter: %s", err)
+ }
+}
+
+const certISOOID = `
+-----BEGIN CERTIFICATE-----
+MIIB5TCCAVKgAwIBAgIQtwyL3RPWV7dJQp34HwZG9DAJBgUrDgMCHQUAMBExDzAN
+BgNVBAMTBm15dGVzdDAeFw0xNjA4MDkyMjExMDVaFw0zOTEyMzEyMzU5NTlaMBEx
+DzANBgNVBAMTBm15dGVzdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEArzIH
+GsyDB3ohIGkkvijF2PTRUX1bvOtY1eUUpjwHyu0twpAKSuaQv2Ha+/63+aHe8O86
+BT+98wjXFX6RFSagtAujo80rIF2dSm33BGt18pDN8v6zp93dnAm0jRaSQrHJ75xw
+5O+S1oEYR1LtUoFJy6qB104j6aINBAgOiLIKiMkCAwEAAaNGMEQwQgYDVR0BBDsw
+OYAQVuYVQ/WDjdGSkZRlTtJDNKETMBExDzANBgNVBAMTBm15dGVzdIIQtwyL3RPW
+V7dJQp34HwZG9DAJBgUrDgMCHQUAA4GBABngrSkH7vG5lY4sa4AZF59lAAXqBVJE
+J4TBiKC62hCdZv18rBleP6ETfhbPg7pTs8p4ebQbpmtNxRS9Lw3MzQ8Ya5Ybwzj2
+NwBSyCtCQl7mrEg4nJqJl4A2EUhnET/oVxU0oTV/SZ3ziGXcY1oG1s6vidV7TZTu
+MCRtdSdaM7g3
+-----END CERTIFICATE-----`
+
+func TestISOOIDInCertificate(t *testing.T) {
+ block, _ := pem.Decode([]byte(certISOOID))
+ if cert, err := ParseCertificate(block.Bytes); err != nil {
+ t.Errorf("certificate with ISO OID failed to parse: %s", err)
+ } else if cert.SignatureAlgorithm == UnknownSignatureAlgorithm {
+ t.Errorf("ISO OID not recognised in certificate")
+ }
+}
+
+// certMultipleRDN contains a RelativeDistinguishedName with two elements (the
+// common name and serial number). This particular certificate was the first
+// such certificate in the “Pilot” Certificate Transparency log.
+const certMultipleRDN = `
+-----BEGIN CERTIFICATE-----
+MIIFRzCCBC+gAwIBAgIEOl59NTANBgkqhkiG9w0BAQUFADA9MQswCQYDVQQGEwJz
+aTEbMBkGA1UEChMSc3RhdGUtaW5zdGl0dXRpb25zMREwDwYDVQQLEwhzaWdvdi1j
+YTAeFw0xMjExMTYxMDUyNTdaFw0xNzExMTYxMjQ5MDVaMIGLMQswCQYDVQQGEwJz
+aTEbMBkGA1UEChMSc3RhdGUtaW5zdGl0dXRpb25zMRkwFwYDVQQLExB3ZWItY2Vy
+dGlmaWNhdGVzMRAwDgYDVQQLEwdTZXJ2ZXJzMTIwFAYDVQQFEw0xMjM2NDg0MDEw
+MDEwMBoGA1UEAxMTZXBvcnRhbC5tc3MuZWR1cy5zaTCCASIwDQYJKoZIhvcNAQEB
+BQADggEPADCCAQoCggEBAMrNkZH9MPuBTjMGNk3sJX8V+CkFx/4ru7RTlLS6dlYM
+098dtSfJ3s2w0p/1NB9UmR8j0yS0Kg6yoZ3ShsSO4DWBtcQD8820a6BYwqxxQTNf
+HSRZOc+N/4TQrvmK6t4k9Aw+YEYTMrWOU4UTeyhDeCcUsBdh7HjfWsVaqNky+2sv
+oic3zP5gF+2QfPkvOoHT3FLR8olNhViIE6Kk3eFIEs4dkq/ZzlYdLb8pHQoj/sGI
+zFmA5AFvm1HURqOmJriFjBwaCtn8AVEYOtQrnUCzJYu1ex8azyS2ZgYMX0u8A5Z/
+y2aMS/B2W+H79WcgLpK28vPwe7vam0oFrVytAd+u65ECAwEAAaOCAf4wggH6MA4G
+A1UdDwEB/wQEAwIFoDBABgNVHSAEOTA3MDUGCisGAQQBr1kBAwMwJzAlBggrBgEF
+BQcCARYZaHR0cDovL3d3dy5jYS5nb3Yuc2kvY3BzLzAfBgNVHREEGDAWgRRwb2Rw
+b3JhLm1pemtzQGdvdi5zaTCB8QYDVR0fBIHpMIHmMFWgU6BRpE8wTTELMAkGA1UE
+BhMCc2kxGzAZBgNVBAoTEnN0YXRlLWluc3RpdHV0aW9uczERMA8GA1UECxMIc2ln
+b3YtY2ExDjAMBgNVBAMTBUNSTDM5MIGMoIGJoIGGhldsZGFwOi8veDUwMC5nb3Yu
+c2kvb3U9c2lnb3YtY2Esbz1zdGF0ZS1pbnN0aXR1dGlvbnMsYz1zaT9jZXJ0aWZp
+Y2F0ZVJldm9jYXRpb25MaXN0P2Jhc2WGK2h0dHA6Ly93d3cuc2lnb3YtY2EuZ292
+LnNpL2NybC9zaWdvdi1jYS5jcmwwKwYDVR0QBCQwIoAPMjAxMjExMTYxMDUyNTda
+gQ8yMDE3MTExNjEyNDkwNVowHwYDVR0jBBgwFoAUHvjUU2uzgwbpBAZXAvmlv8ZY
+PHIwHQYDVR0OBBYEFGI1Duuu+wTGDZka/xHNbwcbM69ZMAkGA1UdEwQCMAAwGQYJ
+KoZIhvZ9B0EABAwwChsEVjcuMQMCA6gwDQYJKoZIhvcNAQEFBQADggEBAHny0K1y
+BQznrzDu3DDpBcGYguKU0dvU9rqsV1ua4nxkriSMWjgsX6XJFDdDW60I3P4VWab5
+ag5fZzbGqi8kva/CzGgZh+CES0aWCPy+4Gb8lwOTt+854/laaJvd6kgKTER7z7U9
+9C86Ch2y4sXNwwwPJ1A9dmrZJZOcJjS/WYZgwaafY2Hdxub5jqPE5nehwYUPVu9R
+uH6/skk4OEKcfOtN0hCnISOVuKYyS4ANARWRG5VGHIH06z3lGUVARFRJ61gtAprd
+La+fgSS+LVZ+kU2TkeoWAKvGq8MAgDq4D4Xqwekg7WKFeuyusi/NI5rm40XgjBMF
+DF72IUofoVt7wo0=
+-----END CERTIFICATE-----`
+
+func TestMultipleRDN(t *testing.T) {
+ block, _ := pem.Decode([]byte(certMultipleRDN))
+ cert, err := ParseCertificate(block.Bytes)
+ if err != nil {
+ t.Fatalf("certificate with two elements in an RDN failed to parse: %v", err)
+ }
+
+ if want := "eportal.mss.edus.si"; cert.Subject.CommonName != want {
+ t.Errorf("got common name of %q, but want %q", cert.Subject.CommonName, want)
+ }
+
+ if want := "1236484010010"; cert.Subject.SerialNumber != want {
+ t.Errorf("got serial number of %q, but want %q", cert.Subject.SerialNumber, want)
+ }
+}
+
+func TestSystemCertPool(t *testing.T) {
+ if runtime.GOOS == "windows" || runtime.GOOS == "darwin" || runtime.GOOS == "ios" {
+ t.Skip("not implemented on Windows (Issue 16736, 18609) or darwin (Issue 46287)")
+ }
+ a, err := SystemCertPool()
+ if err != nil {
+ t.Fatal(err)
+ }
+ b, err := SystemCertPool()
+ if err != nil {
+ t.Fatal(err)
+ }
+ if !certPoolEqual(a, b) {
+ t.Fatal("two calls to SystemCertPool had different results")
+ }
+ if ok := b.AppendCertsFromPEM([]byte(`
+-----BEGIN CERTIFICATE-----
+MIIDBjCCAe6gAwIBAgIRANXM5I3gjuqDfTp/PYrs+u8wDQYJKoZIhvcNAQELBQAw
+EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0xODAzMjcxOTU2MjFaFw0xOTAzMjcxOTU2
+MjFaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDK+9m3rjsO2Djes6bIYQZ3eV29JF09ZrjOrEHLtaKrD6/acsoSoTsf
+cQr+rzzztdB5ijWXCS64zo/0OiqBeZUNZ67jVdToa9qW5UYe2H0Y+ZNdfA5GYMFD
+yk/l3/uBu3suTZPfXiW2TjEi27Q8ruNUIZ54DpTcs6y2rBRFzadPWwn/VQMlvRXM
+jrzl8Y08dgnYmaAHprxVzwMXcQ/Brol+v9GvjaH1DooHqkn8O178wsPQNhdtvN01
+IXL46cYdcUwWrE/GX5u+9DaSi+0KWxAPQ+NVD5qUI0CKl4714yGGh7feXMjJdHgl
+VG4QJZlJvC4FsURgCHJT6uHGIelnSwhbAgMBAAGjVzBVMA4GA1UdDwEB/wQEAwIF
+oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMCAGA1UdEQQZMBeC
+FVRlc3RTeXN0ZW1DZXJ0UG9vbC5nbzANBgkqhkiG9w0BAQsFAAOCAQEAwuSRx/VR
+BKh2ICxZjL6jBwk/7UlU1XKbhQD96RqkidDNGEc6eLZ90Z5XXTurEsXqdm5jQYPs
+1cdcSW+fOSMl7MfW9e5tM66FaIPZl9rKZ1r7GkOfgn93xdLAWe8XHd19xRfDreub
+YC8DVqgLASOEYFupVSl76ktPfxkU5KCvmUf3P2PrRybk1qLGFytGxfyice2gHSNI
+gify3K/+H/7wCkyFW4xYvzl7WW4mXxoqPRPjQt1J423DhnnQ4G1P8V/vhUpXNXOq
+N9IEPnWuihC09cyx/WMQIUlWnaQLHdfpPS04Iez3yy2PdfXJzwfPrja7rNE+skK6
+pa/O1nF0AfWOpw==
+-----END CERTIFICATE-----
+ `)); !ok {
+ t.Fatal("AppendCertsFromPEM failed")
+ }
+ if reflect.DeepEqual(a, b) {
+ t.Fatal("changing one pool modified the other")
+ }
+}
+
+const emptyNameConstraintsPEM = `
+-----BEGIN CERTIFICATE-----
+MIIC1jCCAb6gAwIBAgICEjQwDQYJKoZIhvcNAQELBQAwKDEmMCQGA1UEAxMdRW1w
+dHkgbmFtZSBjb25zdHJhaW50cyBpc3N1ZXIwHhcNMTMwMjAxMDAwMDAwWhcNMjAw
+NTMwMTA0ODM4WjAhMR8wHQYDVQQDExZFbXB0eSBuYW1lIGNvbnN0cmFpbnRzMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwriElUIt3LCqmJObs+yDoWPD
+F5IqgWk6moIobYjPfextZiYU6I3EfvAwoNxPDkN2WowcocUZMJbEeEq5ebBksFnx
+f12gBxlIViIYwZAzu7aFvhDMyPKQI3C8CG0ZSC9ABZ1E3umdA3CEueNOmP/TChNq
+Cl23+BG1Qb/PJkpAO+GfpWSVhTcV53Mf/cKvFHcjGNrxzdSoq9fyW7a6gfcGEQY0
+LVkmwFWUfJ0wT8kaeLr0E0tozkIfo01KNWNzv6NcYP80QOBRDlApWu9ODmEVJHPD
+blx4jzTQ3JLa+4DvBNOjVUOp+mgRmjiW0rLdrxwOxIqIOwNjweMCp/hgxX/hTQID
+AQABoxEwDzANBgNVHR4EBjAEoAChADANBgkqhkiG9w0BAQsFAAOCAQEAWG+/zUMH
+QhP8uNCtgSHyim/vh7wminwAvWgMKxlkLBFns6nZeQqsOV1lABY7U0Zuoqa1Z5nb
+6L+iJa4ElREJOi/erLc9uLwBdDCAR0hUTKD7a6i4ooS39DTle87cUnj0MW1CUa6H
+v5SsvpYW+1XleYJk/axQOOTcy4Es53dvnZsjXH0EA/QHnn7UV+JmlE3rtVxcYp6M
+LYPmRhTioROA/drghicRkiu9hxdPyxkYS16M5g3Zj30jdm+k/6C6PeNtN9YmOOga
+nCOSyFYfGhqOANYzpmuV+oIedAsPpIbfIzN8njYUs1zio+1IoI4o8ddM9sCbtPU8
+o+WoY6IsCKXV/g==
+-----END CERTIFICATE-----`
+
+func TestEmptyNameConstraints(t *testing.T) {
+ block, _ := pem.Decode([]byte(emptyNameConstraintsPEM))
+ _, err := ParseCertificate(block.Bytes)
+ if err == nil {
+ t.Fatal("unexpected success")
+ }
+
+ const expected = "empty name constraints"
+ if str := err.Error(); !strings.Contains(str, expected) {
+ t.Errorf("expected %q in error but got %q", expected, str)
+ }
+}
+
+func TestPKIXNameString(t *testing.T) {
+ der, err := base64.StdEncoding.DecodeString(certBytes)
+ if err != nil {
+ t.Fatal(err)
+ }
+ certs, err := ParseCertificates(der)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ // Check that parsed non-standard attributes are printed.
+ rdns := pkix.Name{
+ Locality: []string{"Gophertown"},
+ ExtraNames: []pkix.AttributeTypeAndValue{
+ {Type: asn1.ObjectIdentifier([]int{1, 2, 3, 4, 5}), Value: "golang.org"}},
+ }.ToRDNSequence()
+ nn := pkix.Name{}
+ nn.FillFromRDNSequence(&rdns)
+
+ // Check that zero-length non-nil ExtraNames hide Names.
+ extra := []pkix.AttributeTypeAndValue{
+ {Type: asn1.ObjectIdentifier([]int{1, 2, 3, 4, 5}), Value: "backing array"}}
+ extraNotNil := pkix.Name{
+ Locality: []string{"Gophertown"},
+ ExtraNames: extra[:0],
+ Names: []pkix.AttributeTypeAndValue{
+ {Type: asn1.ObjectIdentifier([]int{1, 2, 3, 4, 5}), Value: "golang.org"}},
+ }
+
+ tests := []struct {
+ dn pkix.Name
+ want string
+ }{
+ {nn, "L=Gophertown,1.2.3.4.5=#130a676f6c616e672e6f7267"},
+ {extraNotNil, "L=Gophertown"},
+ {pkix.Name{
+ CommonName: "Steve Kille",
+ Organization: []string{"Isode Limited"},
+ OrganizationalUnit: []string{"RFCs"},
+ Locality: []string{"Richmond"},
+ Province: []string{"Surrey"},
+ StreetAddress: []string{"The Square"},
+ PostalCode: []string{"TW9 1DT"},
+ SerialNumber: "RFC 2253",
+ Country: []string{"GB"},
+ }, "SERIALNUMBER=RFC 2253,CN=Steve Kille,OU=RFCs,O=Isode Limited,POSTALCODE=TW9 1DT,STREET=The Square,L=Richmond,ST=Surrey,C=GB"},
+ {certs[0].Subject,
+ "CN=mail.google.com,O=Google LLC,L=Mountain View,ST=California,C=US"},
+ {pkix.Name{
+ Organization: []string{"#Google, Inc. \n-> 'Alphabet\" "},
+ Country: []string{"US"},
+ }, "O=\\#Google\\, Inc. \n-\\> 'Alphabet\\\"\\ ,C=US"},
+ {pkix.Name{
+ CommonName: "foo.com",
+ Organization: []string{"Gopher Industries"},
+ ExtraNames: []pkix.AttributeTypeAndValue{
+ {Type: asn1.ObjectIdentifier([]int{2, 5, 4, 3}), Value: "bar.com"}},
+ }, "CN=bar.com,O=Gopher Industries"},
+ {pkix.Name{
+ Locality: []string{"Gophertown"},
+ ExtraNames: []pkix.AttributeTypeAndValue{
+ {Type: asn1.ObjectIdentifier([]int{1, 2, 3, 4, 5}), Value: "golang.org"}},
+ }, "1.2.3.4.5=#130a676f6c616e672e6f7267,L=Gophertown"},
+ // If there are no ExtraNames, the Names are printed instead.
+ {pkix.Name{
+ Locality: []string{"Gophertown"},
+ Names: []pkix.AttributeTypeAndValue{
+ {Type: asn1.ObjectIdentifier([]int{1, 2, 3, 4, 5}), Value: "golang.org"}},
+ }, "L=Gophertown,1.2.3.4.5=#130a676f6c616e672e6f7267"},
+ // If there are both, print only the ExtraNames.
+ {pkix.Name{
+ Locality: []string{"Gophertown"},
+ ExtraNames: []pkix.AttributeTypeAndValue{
+ {Type: asn1.ObjectIdentifier([]int{1, 2, 3, 4, 5}), Value: "golang.org"}},
+ Names: []pkix.AttributeTypeAndValue{
+ {Type: asn1.ObjectIdentifier([]int{1, 2, 3, 4, 6}), Value: "example.com"}},
+ }, "1.2.3.4.5=#130a676f6c616e672e6f7267,L=Gophertown"},
+ }
+
+ for i, test := range tests {
+ if got := test.dn.String(); got != test.want {
+ t.Errorf("#%d: String() = \n%s\n, want \n%s", i, got, test.want)
+ }
+ }
+
+ if extra[0].Value != "backing array" {
+ t.Errorf("the backing array of an empty ExtraNames got modified by String")
+ }
+}
+
+func TestRDNSequenceString(t *testing.T) {
+ // Test some extra cases that get lost in pkix.Name conversions such as
+ // multi-valued attributes.
+
+ var (
+ oidCountry = []int{2, 5, 4, 6}
+ oidOrganization = []int{2, 5, 4, 10}
+ oidOrganizationalUnit = []int{2, 5, 4, 11}
+ oidCommonName = []int{2, 5, 4, 3}
+ )
+
+ tests := []struct {
+ seq pkix.RDNSequence
+ want string
+ }{
+ {
+ seq: pkix.RDNSequence{
+ pkix.RelativeDistinguishedNameSET{
+ pkix.AttributeTypeAndValue{Type: oidCountry, Value: "US"},
+ },
+ pkix.RelativeDistinguishedNameSET{
+ pkix.AttributeTypeAndValue{Type: oidOrganization, Value: "Widget Inc."},
+ },
+ pkix.RelativeDistinguishedNameSET{
+ pkix.AttributeTypeAndValue{Type: oidOrganizationalUnit, Value: "Sales"},
+ pkix.AttributeTypeAndValue{Type: oidCommonName, Value: "J. Smith"},
+ },
+ },
+ want: "OU=Sales+CN=J. Smith,O=Widget Inc.,C=US",
+ },
+ }
+
+ for i, test := range tests {
+ if got := test.seq.String(); got != test.want {
+ t.Errorf("#%d: String() = \n%s\n, want \n%s", i, got, test.want)
+ }
+ }
+}
+
+const criticalNameConstraintWithUnknownTypePEM = `
+-----BEGIN CERTIFICATE-----
+MIIC/TCCAeWgAwIBAgICEjQwDQYJKoZIhvcNAQELBQAwKDEmMCQGA1UEAxMdRW1w
+dHkgbmFtZSBjb25zdHJhaW50cyBpc3N1ZXIwHhcNMTMwMjAxMDAwMDAwWhcNMjAw
+NTMwMTA0ODM4WjAhMR8wHQYDVQQDExZFbXB0eSBuYW1lIGNvbnN0cmFpbnRzMIIB
+IjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAwriElUIt3LCqmJObs+yDoWPD
+F5IqgWk6moIobYjPfextZiYU6I3EfvAwoNxPDkN2WowcocUZMJbEeEq5ebBksFnx
+f12gBxlIViIYwZAzu7aFvhDMyPKQI3C8CG0ZSC9ABZ1E3umdA3CEueNOmP/TChNq
+Cl23+BG1Qb/PJkpAO+GfpWSVhTcV53Mf/cKvFHcjGNrxzdSoq9fyW7a6gfcGEQY0
+LVkmwFWUfJ0wT8kaeLr0E0tozkIfo01KNWNzv6NcYP80QOBRDlApWu9ODmEVJHPD
+blx4jzTQ3JLa+4DvBNOjVUOp+mgRmjiW0rLdrxwOxIqIOwNjweMCp/hgxX/hTQID
+AQABozgwNjA0BgNVHR4BAf8EKjAooCQwIokgIACrzQAAAAAAAAAAAAAAAP////8A
+AAAAAAAAAAAAAAChADANBgkqhkiG9w0BAQsFAAOCAQEAWG+/zUMHQhP8uNCtgSHy
+im/vh7wminwAvWgMKxlkLBFns6nZeQqsOV1lABY7U0Zuoqa1Z5nb6L+iJa4ElREJ
+Oi/erLc9uLwBdDCAR0hUTKD7a6i4ooS39DTle87cUnj0MW1CUa6Hv5SsvpYW+1Xl
+eYJk/axQOOTcy4Es53dvnZsjXH0EA/QHnn7UV+JmlE3rtVxcYp6MLYPmRhTioROA
+/drghicRkiu9hxdPyxkYS16M5g3Zj30jdm+k/6C6PeNtN9YmOOganCOSyFYfGhqO
+ANYzpmuV+oIedAsPpIbfIzN8njYUs1zio+1IoI4o8ddM9sCbtPU8o+WoY6IsCKXV
+/g==
+-----END CERTIFICATE-----`
+
+func TestCriticalNameConstraintWithUnknownType(t *testing.T) {
+ block, _ := pem.Decode([]byte(criticalNameConstraintWithUnknownTypePEM))
+ cert, err := ParseCertificate(block.Bytes)
+ if err != nil {
+ t.Fatalf("unexpected parsing failure: %s", err)
+ }
+
+ if l := len(cert.UnhandledCriticalExtensions); l != 1 {
+ t.Fatalf("expected one unhandled critical extension, but found %d", l)
+ }
+}
+
+const badIPMaskPEM = `
+-----BEGIN CERTIFICATE-----
+MIICzzCCAbegAwIBAgICEjQwDQYJKoZIhvcNAQELBQAwHTEbMBkGA1UEAxMSQmFk
+IElQIG1hc2sgaXNzdWVyMB4XDTEzMDIwMTAwMDAwMFoXDTIwMDUzMDEwNDgzOFow
+FjEUMBIGA1UEAxMLQmFkIElQIG1hc2swggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQDCuISVQi3csKqYk5uz7IOhY8MXkiqBaTqagihtiM997G1mJhTojcR+
+8DCg3E8OQ3ZajByhxRkwlsR4Srl5sGSwWfF/XaAHGUhWIhjBkDO7toW+EMzI8pAj
+cLwIbRlIL0AFnUTe6Z0DcIS5406Y/9MKE2oKXbf4EbVBv88mSkA74Z+lZJWFNxXn
+cx/9wq8UdyMY2vHN1Kir1/JbtrqB9wYRBjQtWSbAVZR8nTBPyRp4uvQTS2jOQh+j
+TUo1Y3O/o1xg/zRA4FEOUCla704OYRUkc8NuXHiPNNDcktr7gO8E06NVQ6n6aBGa
+OJbSst2vHA7Eiog7A2PB4wKn+GDFf+FNAgMBAAGjIDAeMBwGA1UdHgEB/wQSMBCg
+DDAKhwgBAgME//8BAKEAMA0GCSqGSIb3DQEBCwUAA4IBAQBYb7/NQwdCE/y40K2B
+IfKKb++HvCaKfAC9aAwrGWQsEWezqdl5Cqw5XWUAFjtTRm6iprVnmdvov6IlrgSV
+EQk6L96stz24vAF0MIBHSFRMoPtrqLiihLf0NOV7ztxSePQxbUJRroe/lKy+lhb7
+VeV5gmT9rFA45NzLgSznd2+dmyNcfQQD9AeeftRX4maUTeu1XFxinowtg+ZGFOKh
+E4D92uCGJxGSK72HF0/LGRhLXozmDdmPfSN2b6T/oLo942031iY46BqcI5LIVh8a
+Go4A1jOma5X6gh50Cw+kht8jM3yeNhSzXOKj7Uigjijx10z2wJu09Tyj5ahjoiwI
+pdX+
+-----END CERTIFICATE-----`
+
+func TestBadIPMask(t *testing.T) {
+ block, _ := pem.Decode([]byte(badIPMaskPEM))
+ _, err := ParseCertificate(block.Bytes)
+ if err == nil {
+ t.Fatalf("unexpected success")
+ }
+
+ const expected = "contained invalid mask"
+ if !strings.Contains(err.Error(), expected) {
+ t.Fatalf("expected %q in error but got: %s", expected, err)
+ }
+}
+
+const additionalGeneralSubtreePEM = `
+-----BEGIN CERTIFICATE-----
+MIIG4TCCBMmgAwIBAgIRALss+4rLw2Ia7tFFhxE8g5cwDQYJKoZIhvcNAQELBQAw
+bjELMAkGA1UEBhMCTkwxIDAeBgNVBAoMF01pbmlzdGVyaWUgdmFuIERlZmVuc2ll
+MT0wOwYDVQQDDDRNaW5pc3RlcmllIHZhbiBEZWZlbnNpZSBDZXJ0aWZpY2F0aWUg
+QXV0b3JpdGVpdCAtIEcyMB4XDTEzMDMwNjEyMDM0OVoXDTEzMTEzMDEyMDM1MFow
+bDELMAkGA1UEBhMCVVMxFjAUBgNVBAoTDUNlcnRpUGF0aCBMTEMxIjAgBgNVBAsT
+GUNlcnRpZmljYXRpb24gQXV0aG9yaXRpZXMxITAfBgNVBAMTGENlcnRpUGF0aCBC
+cmlkZ2UgQ0EgLSBHMjCCASIwDQYJKoZIhvcNAQEBBQADggEPADCCAQoCggEBANLW
+4kXiRqvwBhJfN9uz12FA+P2D34MPxOt7TGXljm2plJ2CLzvaH8/ymsMdSWdJBS1M
+8FmwvNL1w3A6ZuzksJjPikAu8kY3dcp3mrkk9eCPORDAwGtfsXwZysLiuEaDWpbD
+dHOaHnI6qWU0N6OI+hNX58EjDpIGC1WQdho1tHOTPc5Hf5/hOpM/29v/wr7kySjs
+Z+7nsvkm5rNhuJNzPsLsgzVaJ5/BVyOplZy24FKM8Y43MjR4osZm+a2e0zniqw6/
+rvcjcGYabYaznZfQG1GXoyf2Vea+CCgpgUhlVafgkwEs8izl8rIpvBzXiFAgFQuG
+Ituoy92PJbDs430fA/cCAwEAAaOCAnowggJ2MEUGCCsGAQUFBwEBBDkwNzA1Bggr
+BgEFBQcwAoYpaHR0cDovL2NlcnRzLmNhLm1pbmRlZi5ubC9taW5kZWYtY2EtMi5w
+N2MwHwYDVR0jBBgwFoAUzln9WSPz2M64Rl2HYf2/KD8StmQwDwYDVR0TAQH/BAUw
+AwEB/zCB6QYDVR0gBIHhMIHeMEgGCmCEEAGHawECBQEwOjA4BggrBgEFBQcCARYs
+aHR0cDovL2Nwcy5kcC5jYS5taW5kZWYubmwvbWluZGVmLWNhLWRwLWNwcy8wSAYK
+YIQQAYdrAQIFAjA6MDgGCCsGAQUFBwIBFixodHRwOi8vY3BzLmRwLmNhLm1pbmRl
+Zi5ubC9taW5kZWYtY2EtZHAtY3BzLzBIBgpghBABh2sBAgUDMDowOAYIKwYBBQUH
+AgEWLGh0dHA6Ly9jcHMuZHAuY2EubWluZGVmLm5sL21pbmRlZi1jYS1kcC1jcHMv
+MDkGA1UdHwQyMDAwLqAsoCqGKGh0dHA6Ly9jcmxzLmNhLm1pbmRlZi5ubC9taW5k
+ZWYtY2EtMi5jcmwwDgYDVR0PAQH/BAQDAgEGMEYGA1UdHgEB/wQ8MDqhODA2pDEw
+LzELMAkGA1UEBhMCTkwxIDAeBgNVBAoTF01pbmlzdGVyaWUgdmFuIERlZmVuc2ll
+gQFjMF0GA1UdIQRWMFQwGgYKYIQQAYdrAQIFAQYMKwYBBAGBu1MBAQECMBoGCmCE
+EAGHawECBQIGDCsGAQQBgbtTAQEBAjAaBgpghBABh2sBAgUDBgwrBgEEAYG7UwEB
+AQIwHQYDVR0OBBYEFNDCjBM3M3ZKkag84ei3/aKc0d0UMA0GCSqGSIb3DQEBCwUA
+A4ICAQAQXFn9jF90/DNFf15JhoGtta/0dNInb14PMu3PAjcdrXYCDPpQZOArTUng
+5YT1WuzfmjnXiTsziT3my0r9Mxvz/btKK/lnVOMW4c2q/8sIsIPnnW5ZaRGrsANB
+dNDZkzMYmeG2Pfgvd0AQSOrpE/TVgWfu/+MMRWwX9y6VbooBR7BLv7zMuVH0WqLn
+6OMFth7fqsThlfMSzkE/RDSaU6n3wXAWT1SIqBITtccRjSUQUFm/q3xrb2cwcZA6
+8vdS4hzNd+ttS905ay31Ks4/1Wrm1bH5RhEfRSH0VSXnc0b+z+RyBbmiwtVZqzxE
+u3UQg/rAmtLDclLFEzjp8YDTIRYSLwstDbEXO/0ArdGrQm79HQ8i/3ZbP2357myW
+i15qd6gMJIgGHS4b8Hc7R1K8LQ9Gm1aLKBEWVNGZlPK/cpXThpVmoEyslN2DHCrc
+fbMbjNZpXlTMa+/b9z7Fa4X8dY8u/ELzZuJXJv5Rmqtg29eopFFYDCl0Nkh1XAjo
+QejEoHHUvYV8TThHZr6Z6Ib8CECgTehU4QvepkgDXNoNrKRZBG0JhLjkwxh2whZq
+nvWBfALC2VuNOM6C0rDY+HmhMlVt0XeqnybD9MuQALMit7Z00Cw2CIjNsBI9xBqD
+xKK9CjUb7gzRUWSpB9jGHsvpEMHOzIFhufvH2Bz1XJw+Cl7khw==
+-----END CERTIFICATE-----`
+
+func TestAdditionFieldsInGeneralSubtree(t *testing.T) {
+ // Very rarely, certificates can include additional fields in the
+ // GeneralSubtree structure. This tests that such certificates can be
+ // parsed.
+ block, _ := pem.Decode([]byte(additionalGeneralSubtreePEM))
+ if _, err := ParseCertificate(block.Bytes); err != nil {
+ t.Fatalf("failed to parse certificate: %s", err)
+ }
+}
+
+func TestEmptySubject(t *testing.T) {
+ template := Certificate{
+ SerialNumber: big.NewInt(1),
+ DNSNames: []string{"example.com"},
+ }
+
+ derBytes, err := CreateCertificate(rand.Reader, &template, &template, &testPrivateKey.PublicKey, testPrivateKey)
+ if err != nil {
+ t.Fatalf("failed to create certificate: %s", err)
+ }
+
+ cert, err := ParseCertificate(derBytes)
+ if err != nil {
+ t.Fatalf("failed to parse certificate: %s", err)
+ }
+
+ for _, ext := range cert.Extensions {
+ if ext.Id.Equal(oidExtensionSubjectAltName) {
+ if !ext.Critical {
+ t.Fatal("SAN extension is not critical")
+ }
+ return
+ }
+ }
+
+ t.Fatal("SAN extension is missing")
+}
+
+// multipleURLsInCRLDPPEM contains two URLs in a single CRL DistributionPoint
+// structure. It is taken from https://crt.sh/?id=12721534.
+const multipleURLsInCRLDPPEM = `
+-----BEGIN CERTIFICATE-----
+MIIF4TCCBMmgAwIBAgIQc+6uFePfrahUGpXs8lhiTzANBgkqhkiG9w0BAQsFADCB
+8zELMAkGA1UEBhMCRVMxOzA5BgNVBAoTMkFnZW5jaWEgQ2F0YWxhbmEgZGUgQ2Vy
+dGlmaWNhY2lvIChOSUYgUS0wODAxMTc2LUkpMSgwJgYDVQQLEx9TZXJ2ZWlzIFB1
+YmxpY3MgZGUgQ2VydGlmaWNhY2lvMTUwMwYDVQQLEyxWZWdldSBodHRwczovL3d3
+dy5jYXRjZXJ0Lm5ldC92ZXJhcnJlbCAoYykwMzE1MDMGA1UECxMsSmVyYXJxdWlh
+IEVudGl0YXRzIGRlIENlcnRpZmljYWNpbyBDYXRhbGFuZXMxDzANBgNVBAMTBkVD
+LUFDQzAeFw0xNDA5MTgwODIxMDBaFw0zMDA5MTgwODIxMDBaMIGGMQswCQYDVQQG
+EwJFUzEzMDEGA1UECgwqQ09OU09SQ0kgQURNSU5JU1RSQUNJTyBPQkVSVEEgREUg
+Q0FUQUxVTllBMSowKAYDVQQLDCFTZXJ2ZWlzIFDDumJsaWNzIGRlIENlcnRpZmlj
+YWNpw7MxFjAUBgNVBAMMDUVDLUNpdXRhZGFuaWEwggEiMA0GCSqGSIb3DQEBAQUA
+A4IBDwAwggEKAoIBAQDFkHPRZPZlXTWZ5psJhbS/Gx+bxcTpGrlVQHHtIkgGz77y
+TA7UZUFb2EQMncfbOhR0OkvQQn1aMvhObFJSR6nI+caf2D+h/m/InMl1MyH3S0Ak
+YGZZsthnyC6KxqK2A/NApncrOreh70ULkQs45aOKsi1kR1W0zE+iFN+/P19P7AkL
+Rl3bXBCVd8w+DLhcwRrkf1FCDw6cEqaFm3cGgf5cbBDMaVYAweWTxwBZAq2RbQAW
+jE7mledcYghcZa4U6bUmCBPuLOnO8KMFAvH+aRzaf3ws5/ZoOVmryyLLJVZ54peZ
+OwnP9EL4OuWzmXCjBifXR2IAblxs5JYj57tls45nAgMBAAGjggHaMIIB1jASBgNV
+HRMBAf8ECDAGAQH/AgEAMA4GA1UdDwEB/wQEAwIBBjAdBgNVHQ4EFgQUC2hZPofI
+oxUa4ECCIl+fHbLFNxUwHwYDVR0jBBgwFoAUoMOLRKo3pUW/l4Ba0fF4opvpXY0w
+gdYGA1UdIASBzjCByzCByAYEVR0gADCBvzAxBggrBgEFBQcCARYlaHR0cHM6Ly93
+d3cuYW9jLmNhdC9DQVRDZXJ0L1JlZ3VsYWNpbzCBiQYIKwYBBQUHAgIwfQx7QXF1
+ZXN0IGNlcnRpZmljYXQgw6lzIGVtw6hzIMO6bmljYSBpIGV4Y2x1c2l2YW1lbnQg
+YSBFbnRpdGF0cyBkZSBDZXJ0aWZpY2FjacOzLiBWZWdldSBodHRwczovL3d3dy5h
+b2MuY2F0L0NBVENlcnQvUmVndWxhY2lvMDMGCCsGAQUFBwEBBCcwJTAjBggrBgEF
+BQcwAYYXaHR0cDovL29jc3AuY2F0Y2VydC5jYXQwYgYDVR0fBFswWTBXoFWgU4Yn
+aHR0cDovL2Vwc2NkLmNhdGNlcnQubmV0L2NybC9lYy1hY2MuY3JshihodHRwOi8v
+ZXBzY2QyLmNhdGNlcnQubmV0L2NybC9lYy1hY2MuY3JsMA0GCSqGSIb3DQEBCwUA
+A4IBAQChqFTjlAH5PyIhLjLgEs68CyNNC1+vDuZXRhy22TI83JcvGmQrZosPvVIL
+PsUXx+C06Pfqmh48Q9S89X9K8w1SdJxP/rZeGEoRiKpwvQzM4ArD9QxyC8jirxex
+3Umg9Ai/sXQ+1lBf6xw4HfUUr1WIp7pNHj0ZWLo106urqktcdeAFWme+/klis5fu
+labCSVPuT/QpwakPrtqOhRms8vgpKiXa/eLtL9ZiA28X/Mker0zlAeTA7Z7uAnp6
+oPJTlZu1Gg1ZDJueTWWsLlO+P+Wzm3MRRIbcgdRzm4mdO7ubu26SzX/aQXDhuih+
+eVxXDTCfs7GUlxnjOp5j559X/N0A
+-----END CERTIFICATE-----
+`
+
+func TestMultipleURLsInCRLDP(t *testing.T) {
+ block, _ := pem.Decode([]byte(multipleURLsInCRLDPPEM))
+ cert, err := ParseCertificate(block.Bytes)
+ if err != nil {
+ t.Fatalf("failed to parse certificate: %s", err)
+ }
+
+ want := []string{
+ "http://epscd.catcert.net/crl/ec-acc.crl",
+ "http://epscd2.catcert.net/crl/ec-acc.crl",
+ }
+ if got := cert.CRLDistributionPoints; !reflect.DeepEqual(got, want) {
+ t.Errorf("CRL distribution points = %#v, want #%v", got, want)
+ }
+}
+
+const hexPKCS1TestPKCS8Key = "30820278020100300d06092a864886f70d0101010500048202623082025e02010002818100cfb1b5bf9685ffa97b4f99df4ff122b70e59ac9b992f3bc2b3dde17d53c1a34928719b02e8fd17839499bfbd515bd6ef99c7a1c47a239718fe36bfd824c0d96060084b5f67f0273443007a24dfaf5634f7772c9346e10eb294c2306671a5a5e719ae24b4de467291bc571014b0e02dec04534d66a9bb171d644b66b091780e8d020301000102818100b595778383c4afdbab95d2bfed12b3f93bb0a73a7ad952f44d7185fd9ec6c34de8f03a48770f2009c8580bcd275e9632714e9a5e3f32f29dc55474b2329ff0ebc08b3ffcb35bc96e6516b483df80a4a59cceb71918cbabf91564e64a39d7e35dce21cb3031824fdbc845dba6458852ec16af5dddf51a8397a8797ae0337b1439024100ea0eb1b914158c70db39031dd8904d6f18f408c85fbbc592d7d20dee7986969efbda081fdf8bc40e1b1336d6b638110c836bfdc3f314560d2e49cd4fbde1e20b024100e32a4e793b574c9c4a94c8803db5152141e72d03de64e54ef2c8ed104988ca780cd11397bc359630d01b97ebd87067c5451ba777cf045ca23f5912f1031308c702406dfcdbbd5a57c9f85abc4edf9e9e29153507b07ce0a7ef6f52e60dcfebe1b8341babd8b789a837485da6c8d55b29bbb142ace3c24a1f5b54b454d01b51e2ad03024100bd6a2b60dee01e1b3bfcef6a2f09ed027c273cdbbaf6ba55a80f6dcc64e4509ee560f84b4f3e076bd03b11e42fe71a3fdd2dffe7e0902c8584f8cad877cdc945024100aa512fa4ada69881f1d8bb8ad6614f192b83200aef5edf4811313d5ef30a86cbd0a90f7b025c71ea06ec6b34db6306c86b1040670fd8654ad7291d066d06d031"
+const hexPKCS1TestECKey = "3081a40201010430bdb9839c08ee793d1157886a7a758a3c8b2a17a4df48f17ace57c72c56b4723cf21dcda21d4e1ad57ff034f19fcfd98ea00706052b81040022a16403620004feea808b5ee2429cfcce13c32160e1c960990bd050bb0fdf7222f3decd0a55008e32a6aa3c9062051c4cba92a7a3b178b24567412d43cdd2f882fa5addddd726fe3e208d2c26d733a773a597abb749714df7256ead5105fa6e7b3650de236b50"
+
+var pkcs1MismatchKeyTests = []struct {
+ hexKey string
+ errorContains string
+}{
+ {hexKey: hexPKCS1TestPKCS8Key, errorContains: "use ParsePKCS8PrivateKey instead"},
+ {hexKey: hexPKCS1TestECKey, errorContains: "use ParseECPrivateKey instead"},
+}
+
+func TestPKCS1MismatchKeyFormat(t *testing.T) {
+ for i, test := range pkcs1MismatchKeyTests {
+ derBytes, _ := hex.DecodeString(test.hexKey)
+ _, err := ParsePKCS1PrivateKey(derBytes)
+ if !strings.Contains(err.Error(), test.errorContains) {
+ t.Errorf("#%d: expected error containing %q, got %s", i, test.errorContains, err)
+ }
+ }
+}
+
+func TestCreateRevocationList(t *testing.T) {
+ ec256Priv, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatalf("Failed to generate ECDSA P256 key: %s", err)
+ }
+ _, ed25519Priv, err := ed25519.GenerateKey(rand.Reader)
+ if err != nil {
+ t.Fatalf("Failed to generate Ed25519 key: %s", err)
+ }
+
+ // Generation command:
+ // openssl req -x509 -newkey rsa -keyout key.pem -out cert.pem -days 365 -nodes -subj '/C=US/ST=California/L=San Francisco/O=Internet Widgets, Inc./OU=WWW/CN=Root/emailAddress=admin@example.com' -sha256 -addext basicConstraints=CA:TRUE -addext "keyUsage = digitalSignature, keyEncipherment, dataEncipherment, cRLSign, keyCertSign" -utf8
+ utf8CAStr := "MIIEITCCAwmgAwIBAgIUXHXy7NdtDv+ClaHvIvlwCYiI4a4wDQYJKoZIhvcNAQELBQAwgZoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMR8wHQYDVQQKDBZJbnRlcm5ldCBXaWRnZXRzLCBJbmMuMQwwCgYDVQQLDANXV1cxDTALBgNVBAMMBFJvb3QxIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMB4XDTIyMDcwODE1MzgyMFoXDTIzMDcwODE1MzgyMFowgZoxCzAJBgNVBAYTAlVTMRMwEQYDVQQIDApDYWxpZm9ybmlhMRYwFAYDVQQHDA1TYW4gRnJhbmNpc2NvMR8wHQYDVQQKDBZJbnRlcm5ldCBXaWRnZXRzLCBJbmMuMQwwCgYDVQQLDANXV1cxDTALBgNVBAMMBFJvb3QxIDAeBgkqhkiG9w0BCQEWEWFkbWluQGV4YW1wbGUuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAmXvp0WNjsZzySWT7Ce5zewQNKq8ujeZGphJ44Vdrwut/b6TcC4iYENds5+7/3PYwBllp3K5TRpCcafSxdhJsvA7/zWlHHNRcJhJLNt9qsKWP6ukI2Iw6OmFMg6kJQ8f67RXkT8HR3v0UqE+lWrA0g+oRuj4erLtfOtSpnl4nsE/Rs2qxbELFWAf7F5qMqH4dUyveWKrNT8eI6YQN+wBg0MAjoKRvDJnBhuo+IvvXX8Aq1QWUcBGPK3or/Ehxy5f/gEmSUXyEU1Ht/vATt2op+eRaEEpBdGRvO+DrKjlcQV2XMN18A9LAX6hCzH43sGye87dj7RZ9yj+waOYNaM7kFQIDAQABo10wWzAdBgNVHQ4EFgQUtbSlrW4hGL2kNjviM6wcCRwvOEEwHwYDVR0jBBgwFoAUtbSlrW4hGL2kNjviM6wcCRwvOEEwDAYDVR0TBAUwAwEB/zALBgNVHQ8EBAMCAbYwDQYJKoZIhvcNAQELBQADggEBAAko82YNNI2n/45L3ya21vufP6nZihIOIxgcRPUMX+IDJZk16qsFdcLgH3KAP8uiVLn8sULuCj35HpViR4IcAk2d+DqfG11l8kY+e5P7nYsViRfy0AatF59/sYlWf+3RdmPXfL70x4mE9OqlMdDm0kR2obps8rng83VLDNvj3R5sBnQwdw6LKLGzaE+RiCTmkH0+P6vnbOJ33su9+9al1+HvJUg3UM1Xq5Bw7TE8DQTetMV3c2Q35RQaJB9pQ4blJOnW9hfnt8yQzU6TU1bU4mRctTm1o1f8btPqUpi+/blhi5MUJK0/myj1XD00pmyfp8QAFl1EfqmTMIBMLg633A0="
+ utf8CABytes, _ := base64.StdEncoding.DecodeString(utf8CAStr)
+ utf8CA, _ := ParseCertificate(utf8CABytes)
+
+ utf8KeyStr := "MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCZe+nRY2OxnPJJZPsJ7nN7BA0qry6N5kamEnjhV2vC639vpNwLiJgQ12zn7v/c9jAGWWncrlNGkJxp9LF2Emy8Dv/NaUcc1FwmEks232qwpY/q6QjYjDo6YUyDqQlDx/rtFeRPwdHe/RSoT6VasDSD6hG6Ph6su1861KmeXiewT9GzarFsQsVYB/sXmoyofh1TK95Yqs1Px4jphA37AGDQwCOgpG8MmcGG6j4i+9dfwCrVBZRwEY8reiv8SHHLl/+ASZJRfIRTUe3+8BO3ain55FoQSkF0ZG874OsqOVxBXZcw3XwD0sBfqELMfjewbJ7zt2PtFn3KP7Bo5g1ozuQVAgMBAAECggEAIscjKiD9PAe2Fs9c2tk/LYazfRKI1/pv072nylfGwToffCq8+ZgP7PEDamKLc4QNScME685MbFbkOlYJyBlQriQv7lmGlY/A+Zd3l410XWaGf9IiAP91Sjk13zd0M/micApf23qtlXt/LMwvSadXnvRw4+SjirxCTdBWRt5K2/ZAN550v7bHFk1EZc3UBF6sOoNsjQWh9Ek79UmQYJBPiZDBHO7O2fh2GSIbUutTma+Tb2i1QUZzg+AG3cseF3p1i3uhNrCh+p+01bJSzGTQsRod2xpD1tpWwR3kIftCOmD1XnhpaBQi7PXjEuNbfucaftnoYj2ShDdmgD5RkkbTAQKBgQC8Ghu5MQ/yIeqXg9IpcSxuWtUEAEfK33/cC/IvuntgbNEnWQm5Lif4D6a9zjkxiCS+9HhrUu5U2EV8NxOyaqmtub3Np1Z5mPuI9oiZ119bjUJd4X+jKOTaePWvOv/rL/pTHYqzXohVMrXy+DaTIq4lOcv3n72SuhuTcKU95rhKtQKBgQDQ4t+HsRZd5fJzoCgRQhlNK3EbXQDv2zXqMW3GfpF7GaDP18I530inRURSJa++rvi7/MCFg/TXVS3QC4HXtbzTYTqhE+VHzSr+/OcsqpLE8b0jKBDv/SBkz811PUJDs3LsX31DT3K0zUpMpNSd/5SYTyJKef9L6mxmwlC1S2Yv4QKBgQC57SiYDdnQIRwrtZ2nXvlm/xttAAX2jqJoU9qIuNA4yHaYaRcGVowlUvsiw9OelQ6VPTpGA0wWy0src5lhkrKzSFRHEe+U89U1VVJCljLoYKFIAJvUH5jOJh/am/vYca0COMIfeAJUDHLyfcwb9XyiyRVGZzvP62tUelSq8gIZvQKBgCAHeaDzzWsudCO4ngwvZ3PGwnwgoaElqrmzRJLYG3SVtGvKOJTpINnNLDGwZ6dEaw1gLyEJ38QY4oJxEULDMiXzVasXQuPkmMAqhUP7D7A1JPw8C4TQ+mOa3XUppHx/CpMl/S4SA5OnmsnvyE5Fv0IveCGVXUkFtAN5rihuXEfhAoGANUkuGU3A0Upk2mzv0JTGP4H95JFG93cqnyPNrYs30M6RkZNgTW27yyr+Nhs4/cMdrg1AYTB0+6ItQWSDmYLs7JEbBE/8L8fdD1irIcygjIHE9nJh96TgZCt61kVGLE8758lOdmoB2rZOpGwi16QIhdQb+IyozYqfX+lQUojL/W0="
+ utf8KeyBytes, _ := base64.StdEncoding.DecodeString(utf8KeyStr)
+ utf8KeyRaw, _ := ParsePKCS8PrivateKey(utf8KeyBytes)
+ utf8Key := utf8KeyRaw.(crypto.Signer)
+
+ tests := []struct {
+ name string
+ key crypto.Signer
+ issuer *Certificate
+ template *RevocationList
+ expectedError string
+ }{
+ {
+ name: "nil template",
+ key: ec256Priv,
+ issuer: nil,
+ template: nil,
+ expectedError: "x509: template can not be nil",
+ },
+ {
+ name: "nil issuer",
+ key: ec256Priv,
+ issuer: nil,
+ template: &RevocationList{},
+ expectedError: "x509: issuer can not be nil",
+ },
+ {
+ name: "issuer doesn't have crlSign key usage bit set",
+ key: ec256Priv,
+ issuer: &Certificate{
+ KeyUsage: KeyUsageCertSign,
+ },
+ template: &RevocationList{},
+ expectedError: "x509: issuer must have the crlSign key usage bit set",
+ },
+ {
+ name: "issuer missing SubjectKeyId",
+ key: ec256Priv,
+ issuer: &Certificate{
+ KeyUsage: KeyUsageCRLSign,
+ },
+ template: &RevocationList{},
+ expectedError: "x509: issuer certificate doesn't contain a subject key identifier",
+ },
+ {
+ name: "nextUpdate before thisUpdate",
+ key: ec256Priv,
+ issuer: &Certificate{
+ KeyUsage: KeyUsageCRLSign,
+ Subject: pkix.Name{
+ CommonName: "testing",
+ },
+ SubjectKeyId: []byte{1, 2, 3},
+ },
+ template: &RevocationList{
+ ThisUpdate: time.Time{}.Add(time.Hour),
+ NextUpdate: time.Time{},
+ },
+ expectedError: "x509: template.ThisUpdate is after template.NextUpdate",
+ },
+ {
+ name: "nil Number",
+ key: ec256Priv,
+ issuer: &Certificate{
+ KeyUsage: KeyUsageCRLSign,
+ Subject: pkix.Name{
+ CommonName: "testing",
+ },
+ SubjectKeyId: []byte{1, 2, 3},
+ },
+ template: &RevocationList{
+ ThisUpdate: time.Time{}.Add(time.Hour * 24),
+ NextUpdate: time.Time{}.Add(time.Hour * 48),
+ },
+ expectedError: "x509: template contains nil Number field",
+ },
+ {
+ name: "long Number",
+ key: ec256Priv,
+ issuer: &Certificate{
+ KeyUsage: KeyUsageCRLSign,
+ Subject: pkix.Name{
+ CommonName: "testing",
+ },
+ SubjectKeyId: []byte{1, 2, 3},
+ },
+ template: &RevocationList{
+ ThisUpdate: time.Time{}.Add(time.Hour * 24),
+ NextUpdate: time.Time{}.Add(time.Hour * 48),
+ Number: big.NewInt(0).SetBytes(append([]byte{1}, make([]byte, 20)...)),
+ },
+ expectedError: "x509: CRL number exceeds 20 octets",
+ },
+ {
+ name: "long Number (20 bytes, MSB set)",
+ key: ec256Priv,
+ issuer: &Certificate{
+ KeyUsage: KeyUsageCRLSign,
+ Subject: pkix.Name{
+ CommonName: "testing",
+ },
+ SubjectKeyId: []byte{1, 2, 3},
+ },
+ template: &RevocationList{
+ ThisUpdate: time.Time{}.Add(time.Hour * 24),
+ NextUpdate: time.Time{}.Add(time.Hour * 48),
+ Number: big.NewInt(0).SetBytes(append([]byte{255}, make([]byte, 19)...)),
+ },
+ expectedError: "x509: CRL number exceeds 20 octets",
+ },
+ {
+ name: "invalid signature algorithm",
+ key: ec256Priv,
+ issuer: &Certificate{
+ KeyUsage: KeyUsageCRLSign,
+ Subject: pkix.Name{
+ CommonName: "testing",
+ },
+ SubjectKeyId: []byte{1, 2, 3},
+ },
+ template: &RevocationList{
+ SignatureAlgorithm: SHA256WithRSA,
+ RevokedCertificates: []pkix.RevokedCertificate{
+ {
+ SerialNumber: big.NewInt(2),
+ RevocationTime: time.Time{}.Add(time.Hour),
+ },
+ },
+ Number: big.NewInt(5),
+ ThisUpdate: time.Time{}.Add(time.Hour * 24),
+ NextUpdate: time.Time{}.Add(time.Hour * 48),
+ },
+ expectedError: "x509: requested SignatureAlgorithm does not match private key type",
+ },
+ {
+ name: "valid",
+ key: ec256Priv,
+ issuer: &Certificate{
+ KeyUsage: KeyUsageCRLSign,
+ Subject: pkix.Name{
+ CommonName: "testing",
+ },
+ SubjectKeyId: []byte{1, 2, 3},
+ },
+ template: &RevocationList{
+ RevokedCertificates: []pkix.RevokedCertificate{
+ {
+ SerialNumber: big.NewInt(2),
+ RevocationTime: time.Time{}.Add(time.Hour),
+ },
+ },
+ Number: big.NewInt(5),
+ ThisUpdate: time.Time{}.Add(time.Hour * 24),
+ NextUpdate: time.Time{}.Add(time.Hour * 48),
+ },
+ },
+ {
+ name: "valid, extra entry extension",
+ key: ec256Priv,
+ issuer: &Certificate{
+ KeyUsage: KeyUsageCRLSign,
+ Subject: pkix.Name{
+ CommonName: "testing",
+ },
+ SubjectKeyId: []byte{1, 2, 3},
+ },
+ template: &RevocationList{
+ RevokedCertificates: []pkix.RevokedCertificate{
+ {
+ SerialNumber: big.NewInt(2),
+ RevocationTime: time.Time{}.Add(time.Hour),
+ Extensions: []pkix.Extension{
+ {
+ Id: []int{2, 5, 29, 99},
+ Value: []byte{5, 0},
+ },
+ },
+ },
+ },
+ Number: big.NewInt(5),
+ ThisUpdate: time.Time{}.Add(time.Hour * 24),
+ NextUpdate: time.Time{}.Add(time.Hour * 48),
+ },
+ },
+ {
+ name: "valid, Ed25519 key",
+ key: ed25519Priv,
+ issuer: &Certificate{
+ KeyUsage: KeyUsageCRLSign,
+ Subject: pkix.Name{
+ CommonName: "testing",
+ },
+ SubjectKeyId: []byte{1, 2, 3},
+ },
+ template: &RevocationList{
+ RevokedCertificates: []pkix.RevokedCertificate{
+ {
+ SerialNumber: big.NewInt(2),
+ RevocationTime: time.Time{}.Add(time.Hour),
+ },
+ },
+ Number: big.NewInt(5),
+ ThisUpdate: time.Time{}.Add(time.Hour * 24),
+ NextUpdate: time.Time{}.Add(time.Hour * 48),
+ },
+ },
+ {
+ name: "valid, non-default signature algorithm",
+ key: ec256Priv,
+ issuer: &Certificate{
+ KeyUsage: KeyUsageCRLSign,
+ Subject: pkix.Name{
+ CommonName: "testing",
+ },
+ SubjectKeyId: []byte{1, 2, 3},
+ },
+ template: &RevocationList{
+ SignatureAlgorithm: ECDSAWithSHA512,
+ RevokedCertificates: []pkix.RevokedCertificate{
+ {
+ SerialNumber: big.NewInt(2),
+ RevocationTime: time.Time{}.Add(time.Hour),
+ },
+ },
+ Number: big.NewInt(5),
+ ThisUpdate: time.Time{}.Add(time.Hour * 24),
+ NextUpdate: time.Time{}.Add(time.Hour * 48),
+ },
+ },
+ {
+ name: "valid, extra extension",
+ key: ec256Priv,
+ issuer: &Certificate{
+ KeyUsage: KeyUsageCRLSign,
+ Subject: pkix.Name{
+ CommonName: "testing",
+ },
+ SubjectKeyId: []byte{1, 2, 3},
+ },
+ template: &RevocationList{
+ RevokedCertificates: []pkix.RevokedCertificate{
+ {
+ SerialNumber: big.NewInt(2),
+ RevocationTime: time.Time{}.Add(time.Hour),
+ },
+ },
+ Number: big.NewInt(5),
+ ThisUpdate: time.Time{}.Add(time.Hour * 24),
+ NextUpdate: time.Time{}.Add(time.Hour * 48),
+ ExtraExtensions: []pkix.Extension{
+ {
+ Id: []int{2, 5, 29, 99},
+ Value: []byte{5, 0},
+ },
+ },
+ },
+ },
+ {
+ name: "valid, empty list",
+ key: ec256Priv,
+ issuer: &Certificate{
+ KeyUsage: KeyUsageCRLSign,
+ Subject: pkix.Name{
+ CommonName: "testing",
+ },
+ SubjectKeyId: []byte{1, 2, 3},
+ },
+ template: &RevocationList{
+ Number: big.NewInt(5),
+ ThisUpdate: time.Time{}.Add(time.Hour * 24),
+ NextUpdate: time.Time{}.Add(time.Hour * 48),
+ },
+ },
+ {
+ name: "valid CA with utf8 Subject fields including Email, empty list",
+ key: utf8Key,
+ issuer: utf8CA,
+ template: &RevocationList{
+ Number: big.NewInt(5),
+ ThisUpdate: time.Time{}.Add(time.Hour * 24),
+ NextUpdate: time.Time{}.Add(time.Hour * 48),
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ crl, err := CreateRevocationList(rand.Reader, tc.template, tc.issuer, tc.key)
+ if err != nil && tc.expectedError == "" {
+ t.Fatalf("CreateRevocationList failed unexpectedly: %s", err)
+ } else if err != nil && tc.expectedError != err.Error() {
+ t.Fatalf("CreateRevocationList failed unexpectedly, wanted: %s, got: %s", tc.expectedError, err)
+ } else if err == nil && tc.expectedError != "" {
+ t.Fatalf("CreateRevocationList didn't fail, expected: %s", tc.expectedError)
+ }
+ if tc.expectedError != "" {
+ return
+ }
+
+ parsedCRL, err := ParseRevocationList(crl)
+ if err != nil {
+ t.Fatalf("Failed to parse generated CRL: %s", err)
+ }
+
+ if tc.template.SignatureAlgorithm != UnknownSignatureAlgorithm &&
+ parsedCRL.SignatureAlgorithm != tc.template.SignatureAlgorithm {
+ t.Fatalf("SignatureAlgorithm mismatch: got %v; want %v.", parsedCRL.SignatureAlgorithm,
+ tc.template.SignatureAlgorithm)
+ }
+
+ if !reflect.DeepEqual(parsedCRL.RevokedCertificates, tc.template.RevokedCertificates) {
+ t.Fatalf("RevokedCertificates mismatch: got %v; want %v.",
+ parsedCRL.RevokedCertificates, tc.template.RevokedCertificates)
+ }
+
+ if len(parsedCRL.Extensions) != 2+len(tc.template.ExtraExtensions) {
+ t.Fatalf("Generated CRL has wrong number of extensions, wanted: %d, got: %d", 2+len(tc.template.ExtraExtensions), len(parsedCRL.Extensions))
+ }
+ expectedAKI, err := asn1.Marshal(authKeyId{Id: tc.issuer.SubjectKeyId})
+ if err != nil {
+ t.Fatalf("asn1.Marshal failed: %s", err)
+ }
+ akiExt := pkix.Extension{
+ Id: oidExtensionAuthorityKeyId,
+ Value: expectedAKI,
+ }
+ if !reflect.DeepEqual(parsedCRL.Extensions[0], akiExt) {
+ t.Fatalf("Unexpected first extension: got %v, want %v",
+ parsedCRL.Extensions[0], akiExt)
+ }
+ expectedNum, err := asn1.Marshal(tc.template.Number)
+ if err != nil {
+ t.Fatalf("asn1.Marshal failed: %s", err)
+ }
+ crlExt := pkix.Extension{
+ Id: oidExtensionCRLNumber,
+ Value: expectedNum,
+ }
+ if !reflect.DeepEqual(parsedCRL.Extensions[1], crlExt) {
+ t.Fatalf("Unexpected second extension: got %v, want %v",
+ parsedCRL.Extensions[1], crlExt)
+ }
+
+ // With Go 1.19's updated RevocationList, we can now directly compare
+ // the RawSubject of the certificate to RawIssuer on the parsed CRL.
+ // However, this doesn't work with our hacked issuers above (that
+ // aren't parsed from a proper DER bundle but are instead manually
+ // constructed). Prefer RawSubject when it is set.
+ if len(tc.issuer.RawSubject) > 0 {
+ issuerSubj, err := subjectBytes(tc.issuer)
+ if err != nil {
+ t.Fatalf("failed to get issuer subject: %s", err)
+ }
+ if !bytes.Equal(issuerSubj, parsedCRL.RawIssuer) {
+ t.Fatalf("Unexpected issuer subject; wanted: %v, got: %v", hex.EncodeToString(issuerSubj), hex.EncodeToString(parsedCRL.RawIssuer))
+ }
+ } else {
+ // When we hack our custom Subject in the test cases above,
+ // we don't set the additional fields (such as Names) in the
+ // hacked issuer. Round-trip a parsing of pkix.Name so that
+ // we add these missing fields for the comparison.
+ issuerRDN := tc.issuer.Subject.ToRDNSequence()
+ var caIssuer pkix.Name
+ caIssuer.FillFromRDNSequence(&issuerRDN)
+ if !reflect.DeepEqual(caIssuer, parsedCRL.Issuer) {
+ t.Fatalf("Expected issuer.Subject, parsedCRL.Issuer to be the same; wanted: %#v, got: %#v", caIssuer, parsedCRL.Issuer)
+ }
+ }
+
+ if len(parsedCRL.Extensions[2:]) == 0 && len(tc.template.ExtraExtensions) == 0 {
+ // If we don't have anything to check return early so we don't
+ // hit a [] != nil false positive below.
+ return
+ }
+ if !reflect.DeepEqual(parsedCRL.Extensions[2:], tc.template.ExtraExtensions) {
+ t.Fatalf("Extensions mismatch: got %v; want %v.",
+ parsedCRL.Extensions[2:], tc.template.ExtraExtensions)
+ }
+
+ if tc.template.Number != nil && parsedCRL.Number == nil {
+ t.Fatalf("Generated CRL missing Number: got nil, want %s",
+ tc.template.Number.String())
+ }
+ if tc.template.Number != nil && tc.template.Number.Cmp(parsedCRL.Number) != 0 {
+ t.Fatalf("Generated CRL has wrong Number: got %s, want %s",
+ parsedCRL.Number.String(), tc.template.Number.String())
+ }
+ if !bytes.Equal(parsedCRL.AuthorityKeyId, expectedAKI) {
+ t.Fatalf("Generated CRL has wrong Number: got %x, want %x",
+ parsedCRL.AuthorityKeyId, expectedAKI)
+ }
+ })
+ }
+}
+
+func TestRSAPSAParameters(t *testing.T) {
+ generateParams := func(hashFunc crypto.Hash) []byte {
+ var hashOID asn1.ObjectIdentifier
+
+ switch hashFunc {
+ case crypto.SHA256:
+ hashOID = oidSHA256
+ case crypto.SHA384:
+ hashOID = oidSHA384
+ case crypto.SHA512:
+ hashOID = oidSHA512
+ }
+
+ params := pssParameters{
+ Hash: pkix.AlgorithmIdentifier{
+ Algorithm: hashOID,
+ Parameters: asn1.NullRawValue,
+ },
+ MGF: pkix.AlgorithmIdentifier{
+ Algorithm: oidMGF1,
+ },
+ SaltLength: hashFunc.Size(),
+ TrailerField: 1,
+ }
+
+ mgf1Params := pkix.AlgorithmIdentifier{
+ Algorithm: hashOID,
+ Parameters: asn1.NullRawValue,
+ }
+
+ var err error
+ params.MGF.Parameters.FullBytes, err = asn1.Marshal(mgf1Params)
+ if err != nil {
+ t.Fatalf("failed to marshal MGF parameters: %s", err)
+ }
+
+ serialized, err := asn1.Marshal(params)
+ if err != nil {
+ t.Fatalf("failed to marshal parameters: %s", err)
+ }
+
+ return serialized
+ }
+
+ for h, params := range hashToPSSParameters {
+ generated := generateParams(h)
+ if !bytes.Equal(params.FullBytes, generated) {
+ t.Errorf("hardcoded parameters for %s didn't match generated parameters: got (generated) %x, wanted (hardcoded) %x", h, generated, params.FullBytes)
+ }
+ }
+}
+
+func TestUnknownExtKey(t *testing.T) {
+ const errorContains = "unknown extended key usage"
+
+ template := &Certificate{
+ SerialNumber: big.NewInt(10),
+ DNSNames: []string{"foo"},
+ ExtKeyUsage: []ExtKeyUsage{ExtKeyUsage(-1)},
+ }
+ signer, err := rsa.GenerateKey(rand.Reader, 1024)
+ if err != nil {
+ t.Errorf("failed to generate key for TestUnknownExtKey")
+ }
+
+ _, err = CreateCertificate(rand.Reader, template, template, signer.Public(), signer)
+ if !strings.Contains(err.Error(), errorContains) {
+ t.Errorf("expected error containing %q, got %s", errorContains, err)
+ }
+}
+
+func TestIA5SANEnforcement(t *testing.T) {
+ k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatalf("ecdsa.GenerateKey failed: %s", err)
+ }
+
+ testURL, err := url.Parse("https://example.com/")
+ if err != nil {
+ t.Fatalf("url.Parse failed: %s", err)
+ }
+ testURL.RawQuery = "∞"
+
+ marshalTests := []struct {
+ name string
+ template *Certificate
+ expectedError string
+ }{
+ {
+ name: "marshal: unicode dNSName",
+ template: &Certificate{
+ SerialNumber: big.NewInt(0),
+ DNSNames: []string{"∞"},
+ },
+ expectedError: "x509: \"∞\" cannot be encoded as an IA5String",
+ },
+ {
+ name: "marshal: unicode rfc822Name",
+ template: &Certificate{
+ SerialNumber: big.NewInt(0),
+ EmailAddresses: []string{"∞"},
+ },
+ expectedError: "x509: \"∞\" cannot be encoded as an IA5String",
+ },
+ {
+ name: "marshal: unicode uniformResourceIdentifier",
+ template: &Certificate{
+ SerialNumber: big.NewInt(0),
+ URIs: []*url.URL{testURL},
+ },
+ expectedError: "x509: \"https://example.com/?∞\" cannot be encoded as an IA5String",
+ },
+ }
+
+ for _, tc := range marshalTests {
+ t.Run(tc.name, func(t *testing.T) {
+ _, err := CreateCertificate(rand.Reader, tc.template, tc.template, k.Public(), k)
+ if err == nil {
+ t.Errorf("expected CreateCertificate to fail with template: %v", tc.template)
+ } else if err.Error() != tc.expectedError {
+ t.Errorf("unexpected error: got %q, want %q", err.Error(), tc.expectedError)
+ }
+ })
+ }
+
+ unmarshalTests := []struct {
+ name string
+ cert string
+ expectedError string
+ }{
+ {
+ name: "unmarshal: unicode dNSName",
+ cert: "308201083081aea003020102020100300a06082a8648ce3d04030230003022180f30303031303130313030303030305a180f30303031303130313030303030305a30003059301306072a8648ce3d020106082a8648ce3d0301070342000424bcc48180d8d9db794028f2575ebe3cac79f04d7b0d0151c5292e588aac3668c495f108c626168462e0668c9705e08a211dd103a659d2684e0adf8c2bfd47baa315301330110603551d110101ff040730058203e2889e300a06082a8648ce3d04030203490030460221008ac7827ac326a6ee0fa70b2afe99af575ec60b975f820f3c25f60fff43fbccd0022100bffeed93556722d43d13e461d5b3e33efc61f6349300327d3a0196cb6da501c2",
+ expectedError: "x509: SAN dNSName is malformed",
+ },
+ {
+ name: "unmarshal: unicode rfc822Name",
+ cert: "308201083081aea003020102020100300a06082a8648ce3d04030230003022180f30303031303130313030303030305a180f30303031303130313030303030305a30003059301306072a8648ce3d020106082a8648ce3d0301070342000405cb4c4ba72aac980f7b11b0285191425e29e196ce7c5df1c83f56886566e517f196657cc1b73de89ab84ce503fd634e2f2af88fde24c63ca536dc3a5eed2665a315301330110603551d110101ff040730058103e2889e300a06082a8648ce3d0403020349003046022100ed1431cd4b9bb03d88d1511a0ec128a51204375764c716280dc36e2a60142c8902210088c96d25cfaf97eea851ff17d87bb6fe619d6546656e1739f35c3566051c3d0f",
+ expectedError: "x509: SAN rfc822Name is malformed",
+ },
+ {
+ name: "unmarshal: unicode uniformResourceIdentifier",
+ cert: "3082011b3081c3a003020102020100300a06082a8648ce3d04030230003022180f30303031303130313030303030305a180f30303031303130313030303030305a30003059301306072a8648ce3d020106082a8648ce3d03010703420004ce0a79b511701d9188e1ea76bcc5907f1db51de6cc1a037b803f256e8588145ca409d120288bfeb4e38f3088104674d374b35bb91fc80d768d1d519dbe2b0b5aa32a302830260603551d110101ff041c301a861868747470733a2f2f6578616d706c652e636f6d2f3fe2889e300a06082a8648ce3d0403020347003044022044f4697779fd1dae1e382d2452413c5c5ca67851e267d6bc64a8d164977c172c0220505015e657637aa1945d46e7650b6f59b968fc1508ca8b152c99f782446dfc81",
+ expectedError: "x509: SAN uniformResourceIdentifier is malformed",
+ },
+ }
+
+ for _, tc := range unmarshalTests {
+ der, err := hex.DecodeString(tc.cert)
+ if err != nil {
+ t.Fatalf("failed to decode test cert: %s", err)
+ }
+ _, err = ParseCertificate(der)
+ if err == nil {
+ t.Error("expected CreateCertificate to fail")
+ } else if err.Error() != tc.expectedError {
+ t.Errorf("unexpected error: got %q, want %q", err.Error(), tc.expectedError)
+ }
+ }
+}
+
+func BenchmarkCreateCertificate(b *testing.B) {
+ template := &Certificate{
+ SerialNumber: big.NewInt(10),
+ DNSNames: []string{"example.com"},
+ }
+ tests := []struct {
+ name string
+ gen func() crypto.Signer
+ }{
+ {
+ name: "RSA 2048",
+ gen: func() crypto.Signer {
+ k, err := rsa.GenerateKey(rand.Reader, 2048)
+ if err != nil {
+ b.Fatalf("failed to generate test key: %s", err)
+ }
+ return k
+ },
+ },
+ {
+ name: "ECDSA P256",
+ gen: func() crypto.Signer {
+ k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ b.Fatalf("failed to generate test key: %s", err)
+ }
+ return k
+ },
+ },
+ }
+
+ for _, tc := range tests {
+ k := tc.gen()
+ b.ResetTimer()
+ b.Run(tc.name, func(b *testing.B) {
+ for i := 0; i < b.N; i++ {
+ _, err := CreateCertificate(rand.Reader, template, template, k.Public(), k)
+ if err != nil {
+ b.Fatalf("failed to create certificate: %s", err)
+ }
+ }
+ })
+ }
+}
+
+type brokenSigner struct {
+ pub crypto.PublicKey
+}
+
+func (bs *brokenSigner) Public() crypto.PublicKey {
+ return bs.pub
+}
+
+func (bs *brokenSigner) Sign(_ io.Reader, _ []byte, _ crypto.SignerOpts) ([]byte, error) {
+ return []byte{1, 2, 3}, nil
+}
+
+func TestCreateCertificateBrokenSigner(t *testing.T) {
+ template := &Certificate{
+ SerialNumber: big.NewInt(10),
+ DNSNames: []string{"example.com"},
+ }
+ k, err := rsa.GenerateKey(rand.Reader, 1024)
+ if err != nil {
+ t.Fatalf("failed to generate test key: %s", err)
+ }
+ expectedErr := "x509: signature over certificate returned by signer is invalid: crypto/rsa: verification error"
+ _, err = CreateCertificate(rand.Reader, template, template, k.Public(), &brokenSigner{k.Public()})
+ if err == nil {
+ t.Fatal("expected CreateCertificate to fail with a broken signer")
+ } else if err.Error() != expectedErr {
+ t.Fatalf("CreateCertificate returned an unexpected error: got %q, want %q", err, expectedErr)
+ }
+}
+
+func TestCreateCertificateLegacy(t *testing.T) {
+ sigAlg := MD5WithRSA
+ template := &Certificate{
+ SerialNumber: big.NewInt(10),
+ DNSNames: []string{"example.com"},
+ SignatureAlgorithm: sigAlg,
+ }
+ _, err := CreateCertificate(rand.Reader, template, template, testPrivateKey.Public(), &brokenSigner{testPrivateKey.Public()})
+ if err == nil {
+ t.Fatal("CreateCertificate didn't fail when SignatureAlgorithm = MD5WithRSA")
+ }
+}
+
+func (s *CertPool) mustCert(t *testing.T, n int) *Certificate {
+ c, err := s.lazyCerts[n].getCert()
+ if err != nil {
+ t.Fatalf("failed to load cert %d: %v", n, err)
+ }
+ return c
+}
+
+func allCerts(t *testing.T, p *CertPool) []*Certificate {
+ all := make([]*Certificate, p.len())
+ for i := range all {
+ all[i] = p.mustCert(t, i)
+ }
+ return all
+}
+
+// certPoolEqual reports whether a and b are equal, except for the
+// function pointers.
+func certPoolEqual(a, b *CertPool) bool {
+ if (a != nil) != (b != nil) {
+ return false
+ }
+ if a == nil {
+ return true
+ }
+ if !reflect.DeepEqual(a.byName, b.byName) ||
+ len(a.lazyCerts) != len(b.lazyCerts) {
+ return false
+ }
+ for i := range a.lazyCerts {
+ la, lb := a.lazyCerts[i], b.lazyCerts[i]
+ if !bytes.Equal(la.rawSubject, lb.rawSubject) {
+ return false
+ }
+ ca, err := la.getCert()
+ if err != nil {
+ panic(err)
+ }
+ cb, err := la.getCert()
+ if err != nil {
+ panic(err)
+ }
+ if !ca.Equal(cb) {
+ return false
+ }
+ }
+
+ return true
+}
+
+func TestCertificateRequestRoundtripFields(t *testing.T) {
+ urlA, err := url.Parse("https://example.com/_")
+ if err != nil {
+ t.Fatal(err)
+ }
+ urlB, err := url.Parse("https://example.org/_")
+ if err != nil {
+ t.Fatal(err)
+ }
+ in := &CertificateRequest{
+ DNSNames: []string{"example.com", "example.org"},
+ EmailAddresses: []string{"a@example.com", "b@example.com"},
+ IPAddresses: []net.IP{net.IPv4(192, 0, 2, 0), net.IPv6loopback},
+ URIs: []*url.URL{urlA, urlB},
+ }
+ out := marshalAndParseCSR(t, in)
+
+ if !reflect.DeepEqual(in.DNSNames, out.DNSNames) {
+ t.Fatalf("Unexpected DNSNames: got %v, want %v", out.DNSNames, in.DNSNames)
+ }
+ if !reflect.DeepEqual(in.EmailAddresses, out.EmailAddresses) {
+ t.Fatalf("Unexpected EmailAddresses: got %v, want %v", out.EmailAddresses, in.EmailAddresses)
+ }
+ if len(in.IPAddresses) != len(out.IPAddresses) ||
+ !in.IPAddresses[0].Equal(out.IPAddresses[0]) ||
+ !in.IPAddresses[1].Equal(out.IPAddresses[1]) {
+ t.Fatalf("Unexpected IPAddresses: got %v, want %v", out.IPAddresses, in.IPAddresses)
+ }
+ if !reflect.DeepEqual(in.URIs, out.URIs) {
+ t.Fatalf("Unexpected URIs: got %v, want %v", out.URIs, in.URIs)
+ }
+}
+
+func BenchmarkParseCertificate(b *testing.B) {
+ cases := []struct {
+ name string
+ pem string
+ }{
+ {
+ name: "ecdsa leaf",
+ pem: `-----BEGIN CERTIFICATE-----
+MIIINjCCBx6gAwIBAgIQHdQ6oBMoe/MJAAAAAEHzmTANBgkqhkiG9w0BAQsFADBG
+MQswCQYDVQQGEwJVUzEiMCAGA1UEChMZR29vZ2xlIFRydXN0IFNlcnZpY2VzIExM
+QzETMBEGA1UEAxMKR1RTIENBIDFDMzAeFw0yMDEyMDgwOTExMzZaFw0yMTAzMDIw
+OTExMzVaMBcxFTATBgNVBAMMDCouZ29vZ2xlLmNvbTBZMBMGByqGSM49AgEGCCqG
+SM49AwEHA0IABEFYegyHh1AHRS1nar5+zYJgMACcsIQMtg0YMyK/59ml8ERIt/JF
+kXM3XIvQuCJhghUawZrrAcAs8djZF1U9M4mjggYYMIIGFDAOBgNVHQ8BAf8EBAMC
+B4AwEwYDVR0lBAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU
+6SWWF36XBsmXJ6iV0EHPXUFoMbwwHwYDVR0jBBgwFoAUinR/r4XN7pXNPZzQ4kYU
+83E1HScwagYIKwYBBQUHAQEEXjBcMCcGCCsGAQUFBzABhhtodHRwOi8vb2NzcC5w
+a2kuZ29vZy9ndHMxYzMwMQYIKwYBBQUHMAKGJWh0dHA6Ly9wa2kuZ29vZy9yZXBv
+L2NlcnRzL2d0czFjMy5kZXIwggTCBgNVHREEggS5MIIEtYIMKi5nb29nbGUuY29t
+gg0qLmFuZHJvaWQuY29tghYqLmFwcGVuZ2luZS5nb29nbGUuY29tggkqLmJkbi5k
+ZXaCEiouY2xvdWQuZ29vZ2xlLmNvbYIYKi5jcm93ZHNvdXJjZS5nb29nbGUuY29t
+ghgqLmRhdGFjb21wdXRlLmdvb2dsZS5jb22CBiouZy5jb4IOKi5nY3AuZ3Z0Mi5j
+b22CESouZ2NwY2RuLmd2dDEuY29tggoqLmdncGh0LmNugg4qLmdrZWNuYXBwcy5j
+boIWKi5nb29nbGUtYW5hbHl0aWNzLmNvbYILKi5nb29nbGUuY2GCCyouZ29vZ2xl
+LmNsgg4qLmdvb2dsZS5jby5pboIOKi5nb29nbGUuY28uanCCDiouZ29vZ2xlLmNv
+LnVrgg8qLmdvb2dsZS5jb20uYXKCDyouZ29vZ2xlLmNvbS5hdYIPKi5nb29nbGUu
+Y29tLmJygg8qLmdvb2dsZS5jb20uY2+CDyouZ29vZ2xlLmNvbS5teIIPKi5nb29n
+bGUuY29tLnRygg8qLmdvb2dsZS5jb20udm6CCyouZ29vZ2xlLmRlggsqLmdvb2ds
+ZS5lc4ILKi5nb29nbGUuZnKCCyouZ29vZ2xlLmh1ggsqLmdvb2dsZS5pdIILKi5n
+b29nbGUubmyCCyouZ29vZ2xlLnBsggsqLmdvb2dsZS5wdIISKi5nb29nbGVhZGFw
+aXMuY29tgg8qLmdvb2dsZWFwaXMuY26CESouZ29vZ2xlY25hcHBzLmNughQqLmdv
+b2dsZWNvbW1lcmNlLmNvbYIRKi5nb29nbGV2aWRlby5jb22CDCouZ3N0YXRpYy5j
+boINKi5nc3RhdGljLmNvbYISKi5nc3RhdGljY25hcHBzLmNuggoqLmd2dDEuY29t
+ggoqLmd2dDIuY29tghQqLm1ldHJpYy5nc3RhdGljLmNvbYIMKi51cmNoaW4uY29t
+ghAqLnVybC5nb29nbGUuY29tghMqLndlYXIuZ2tlY25hcHBzLmNughYqLnlvdXR1
+YmUtbm9jb29raWUuY29tgg0qLnlvdXR1YmUuY29tghYqLnlvdXR1YmVlZHVjYXRp
+b24uY29tghEqLnlvdXR1YmVraWRzLmNvbYIHKi55dC5iZYILKi55dGltZy5jb22C
+GmFuZHJvaWQuY2xpZW50cy5nb29nbGUuY29tggthbmRyb2lkLmNvbYIbZGV2ZWxv
+cGVyLmFuZHJvaWQuZ29vZ2xlLmNughxkZXZlbG9wZXJzLmFuZHJvaWQuZ29vZ2xl
+LmNuggRnLmNvgghnZ3BodC5jboIMZ2tlY25hcHBzLmNuggZnb28uZ2yCFGdvb2ds
+ZS1hbmFseXRpY3MuY29tggpnb29nbGUuY29tgg9nb29nbGVjbmFwcHMuY26CEmdv
+b2dsZWNvbW1lcmNlLmNvbYIYc291cmNlLmFuZHJvaWQuZ29vZ2xlLmNuggp1cmNo
+aW4uY29tggp3d3cuZ29vLmdsggh5b3V0dS5iZYILeW91dHViZS5jb22CFHlvdXR1
+YmVlZHVjYXRpb24uY29tgg95b3V0dWJla2lkcy5jb22CBXl0LmJlMCEGA1UdIAQa
+MBgwCAYGZ4EMAQIBMAwGCisGAQQB1nkCBQMwNQYDVR0fBC4wLDAqoCigJoYkaHR0
+cDovL2NybC5wa2kuZ29vZy9ndHNyMS9ndHMxYzMuY3JsMBMGCisGAQQB1nkCBAMB
+Af8EAgUAMA0GCSqGSIb3DQEBCwUAA4IBAQAlDQm5zY7JcPxcJ9ulfTGsWV/m6Pro
+gLYmAlBUPGKy313aetT4Zjz44ZseVtUOKsXVHh4avPA9O+ta1FgkASlbkgJ05ivb
+j/+MMqkrLemdMv9Svvx3CNaAq2jJ2E+8GdrA1RzMkiNthJCiRafaPnXnN6hOHGNr
+GtqYfMHsvrRHW8J2IPHW0/MUHmJ/NDu/vNchxke2OEfCPLtseo3hJt8l8HbH+yE8
+DFrt8YVRi1CLomEyuPJDF4og3O3ZsoXuxcPd9UPxULOCxycdolRw8Iv/Xgr082j3
+svXC3HUd3apM2Yy3xJAlk/mUkzVXfdJZ+Zy1huNsUoJ+gM8rmpyGhYyx
+-----END CERTIFICATE-----`,
+ },
+ {
+ name: "rsa leaf",
+ pem: `-----BEGIN CERTIFICATE-----
+MIIJXjCCCEagAwIBAgIRAPYaTUsjP4iRBQAAAACHSSgwDQYJKoZIhvcNAQELBQAw
+QjELMAkGA1UEBhMCVVMxHjAcBgNVBAoTFUdvb2dsZSBUcnVzdCBTZXJ2aWNlczET
+MBEGA1UEAxMKR1RTIENBIDFPMTAeFw0yMTAxMjYwODQ2MzRaFw0yMTA0MjAwODQ2
+MzNaMGYxCzAJBgNVBAYTAlVTMRMwEQYDVQQIEwpDYWxpZm9ybmlhMRYwFAYDVQQH
+Ew1Nb3VudGFpbiBWaWV3MRMwEQYDVQQKEwpHb29nbGUgTExDMRUwEwYDVQQDDAwq
+Lmdvb2dsZS5jb20wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEKAoIBAQC76xx0
+UdZ36/41rZNPfQ/yQ05vsBLUO0d+3uMOhvDlpst+XvIsG6L+vLDgf3RiQRFlei0h
+KqqLOtWLDc/y0+OmaaC+8ft1zljBYdvQlAYoZrT79Cc5pAIDq7G1OZ7cC4ahDno/
+n46FHjT/UTUAMYa8cKWBaMPneMIsKvn8nMdZzHkfO2nUd6OEecn90XweMvNmx8De
+6h5AlIgG3m66hkD/UCSdxn7yJHBQVdHgkfTqzv3sz2YyBQGNi288F1bn541f6khE
+fYti1MvXRtkky7yLCQNUG6PtvuSU4cKaNvRklHigf5i1nVdGEuH61gAElZIklSia
+OVK46UyU4DGtbdWNAgMBAAGjggYpMIIGJTAOBgNVHQ8BAf8EBAMCBaAwEwYDVR0l
+BAwwCgYIKwYBBQUHAwEwDAYDVR0TAQH/BAIwADAdBgNVHQ4EFgQU8zCvllLd3jhB
+k//+Wdjo40Q+T3gwHwYDVR0jBBgwFoAUmNH4bhDrz5vsYJ8YkBug630J/SswaAYI
+KwYBBQUHAQEEXDBaMCsGCCsGAQUFBzABhh9odHRwOi8vb2NzcC5wa2kuZ29vZy9n
+dHMxbzFjb3JlMCsGCCsGAQUFBzAChh9odHRwOi8vcGtpLmdvb2cvZ3NyMi9HVFMx
+TzEuY3J0MIIE1wYDVR0RBIIEzjCCBMqCDCouZ29vZ2xlLmNvbYINKi5hbmRyb2lk
+LmNvbYIWKi5hcHBlbmdpbmUuZ29vZ2xlLmNvbYIJKi5iZG4uZGV2ghIqLmNsb3Vk
+Lmdvb2dsZS5jb22CGCouY3Jvd2Rzb3VyY2UuZ29vZ2xlLmNvbYIYKi5kYXRhY29t
+cHV0ZS5nb29nbGUuY29tghMqLmZsYXNoLmFuZHJvaWQuY29tggYqLmcuY2+CDiou
+Z2NwLmd2dDIuY29tghEqLmdjcGNkbi5ndnQxLmNvbYIKKi5nZ3BodC5jboIOKi5n
+a2VjbmFwcHMuY26CFiouZ29vZ2xlLWFuYWx5dGljcy5jb22CCyouZ29vZ2xlLmNh
+ggsqLmdvb2dsZS5jbIIOKi5nb29nbGUuY28uaW6CDiouZ29vZ2xlLmNvLmpwgg4q
+Lmdvb2dsZS5jby51a4IPKi5nb29nbGUuY29tLmFygg8qLmdvb2dsZS5jb20uYXWC
+DyouZ29vZ2xlLmNvbS5icoIPKi5nb29nbGUuY29tLmNvgg8qLmdvb2dsZS5jb20u
+bXiCDyouZ29vZ2xlLmNvbS50coIPKi5nb29nbGUuY29tLnZuggsqLmdvb2dsZS5k
+ZYILKi5nb29nbGUuZXOCCyouZ29vZ2xlLmZyggsqLmdvb2dsZS5odYILKi5nb29n
+bGUuaXSCCyouZ29vZ2xlLm5sggsqLmdvb2dsZS5wbIILKi5nb29nbGUucHSCEiou
+Z29vZ2xlYWRhcGlzLmNvbYIPKi5nb29nbGVhcGlzLmNughEqLmdvb2dsZWNuYXBw
+cy5jboIUKi5nb29nbGVjb21tZXJjZS5jb22CESouZ29vZ2xldmlkZW8uY29tggwq
+LmdzdGF0aWMuY26CDSouZ3N0YXRpYy5jb22CEiouZ3N0YXRpY2NuYXBwcy5jboIK
+Ki5ndnQxLmNvbYIKKi5ndnQyLmNvbYIUKi5tZXRyaWMuZ3N0YXRpYy5jb22CDCou
+dXJjaGluLmNvbYIQKi51cmwuZ29vZ2xlLmNvbYITKi53ZWFyLmdrZWNuYXBwcy5j
+boIWKi55b3V0dWJlLW5vY29va2llLmNvbYINKi55b3V0dWJlLmNvbYIWKi55b3V0
+dWJlZWR1Y2F0aW9uLmNvbYIRKi55b3V0dWJla2lkcy5jb22CByoueXQuYmWCCyou
+eXRpbWcuY29tghphbmRyb2lkLmNsaWVudHMuZ29vZ2xlLmNvbYILYW5kcm9pZC5j
+b22CG2RldmVsb3Blci5hbmRyb2lkLmdvb2dsZS5jboIcZGV2ZWxvcGVycy5hbmRy
+b2lkLmdvb2dsZS5jboIEZy5jb4IIZ2dwaHQuY26CDGdrZWNuYXBwcy5jboIGZ29v
+LmdsghRnb29nbGUtYW5hbHl0aWNzLmNvbYIKZ29vZ2xlLmNvbYIPZ29vZ2xlY25h
+cHBzLmNughJnb29nbGVjb21tZXJjZS5jb22CGHNvdXJjZS5hbmRyb2lkLmdvb2ds
+ZS5jboIKdXJjaGluLmNvbYIKd3d3Lmdvby5nbIIIeW91dHUuYmWCC3lvdXR1YmUu
+Y29tghR5b3V0dWJlZWR1Y2F0aW9uLmNvbYIPeW91dHViZWtpZHMuY29tggV5dC5i
+ZTAhBgNVHSAEGjAYMAgGBmeBDAECAjAMBgorBgEEAdZ5AgUDMDMGA1UdHwQsMCow
+KKAmoCSGImh0dHA6Ly9jcmwucGtpLmdvb2cvR1RTMU8xY29yZS5jcmwwEwYKKwYB
+BAHWeQIEAwEB/wQCBQAwDQYJKoZIhvcNAQELBQADggEBAHh9/ozYUGRd+W5akWlM
+4WvX808TK2oUISnagbxCCFZ2trpg2oi03CJf4o4o3Je5Qzzz10s22oQY6gPHAR0B
+QHzrpqAveQw9D5vd8xjgtQ/SAujPzPKNQee5511rS7/EKW9I83ccd5XhhoEyx8A1
+/65RTS+2hKpJKTMkr0yHBPJV7kUW+n/KIef5YaSOA9VYK7hyH0niDpvm9EmoqvWS
+U5xAFAe/Xrrq3sxTuDJPQA8alk6h/ql5Klkw6dL53csiPka/MevDqdifWkzuT/6n
+YK/ePeJzPD17FA9V+N1rcuF3Wk29AZvCOSasdIkIuE82vGr3dfNrsrn9E9lWIbCr
+Qc4=
+-----END CERTIFICATE-----`,
+ },
+ }
+ for _, c := range cases {
+ b.Run(c.name, func(b *testing.B) {
+ pemBlock, _ := pem.Decode([]byte(c.pem))
+ b.ReportAllocs()
+ b.ResetTimer()
+ for i := 0; i < b.N; i++ {
+ _, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ b.Fatal(err)
+ }
+ }
+ })
+ }
+}
+
+func TestParseCertificateRawEquals(t *testing.T) {
+ p, _ := pem.Decode([]byte(pemCertificate))
+ cert, err := ParseCertificate(p.Bytes)
+ if err != nil {
+ t.Fatalf("failed to parse certificate: %s", err)
+ }
+ if !bytes.Equal(p.Bytes, cert.Raw) {
+ t.Fatalf("unexpected Certificate.Raw\ngot: %x\nwant: %x\n", cert.Raw, p.Bytes)
+ }
+}
+
+// mismatchingSigAlgIDPEM contains a certificate where the Certificate
+// signatureAlgorithm and the TBSCertificate signature contain
+// mismatching OIDs
+const mismatchingSigAlgIDPEM = `-----BEGIN CERTIFICATE-----
+MIIBBzCBrqADAgECAgEAMAoGCCqGSM49BAMCMAAwIhgPMDAwMTAxMDEwMDAwMDBa
+GA8wMDAxMDEwMTAwMDAwMFowADBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOqV
+EDuVXxwZgIU3+dOwv1SsMu0xuV48hf7xmK8n7sAMYgllB+96DnPqBeboJj4snYnx
+0AcE0PDVQ1l4Z3YXsQWjFTATMBEGA1UdEQEB/wQHMAWCA2FzZDAKBggqhkjOPQQD
+AwNIADBFAiBi1jz/T2HT5nAfrD7zsgR+68qh7Erc6Q4qlxYBOgKG4QIhAOtjIn+Q
+tA+bq+55P3ntxTOVRq0nv1mwnkjwt9cQR9Fn
+-----END CERTIFICATE-----`
+
+// mismatchingSigAlgParamPEM contains a certificate where the Certificate
+// signatureAlgorithm and the TBSCertificate signature contain
+// mismatching parameters
+const mismatchingSigAlgParamPEM = `-----BEGIN CERTIFICATE-----
+MIIBCTCBrqADAgECAgEAMAoGCCqGSM49BAMCMAAwIhgPMDAwMTAxMDEwMDAwMDBa
+GA8wMDAxMDEwMTAwMDAwMFowADBZMBMGByqGSM49AgEGCCqGSM49AwEHA0IABOqV
+EDuVXxwZgIU3+dOwv1SsMu0xuV48hf7xmK8n7sAMYgllB+96DnPqBeboJj4snYnx
+0AcE0PDVQ1l4Z3YXsQWjFTATMBEGA1UdEQEB/wQHMAWCA2FzZDAMBggqhkjOPQQD
+AgUAA0gAMEUCIGLWPP9PYdPmcB+sPvOyBH7ryqHsStzpDiqXFgE6AobhAiEA62Mi
+f5C0D5ur7nk/ee3FM5VGrSe/WbCeSPC31xBH0Wc=
+-----END CERTIFICATE-----`
+
+func TestSigAlgMismatch(t *testing.T) {
+ for _, certPEM := range []string{mismatchingSigAlgIDPEM, mismatchingSigAlgParamPEM} {
+ b, _ := pem.Decode([]byte(certPEM))
+ if b == nil {
+ t.Fatalf("couldn't decode test certificate")
+ }
+ _, err := ParseCertificate(b.Bytes)
+ if err == nil {
+ t.Fatalf("expected ParseCertificate to fail")
+ }
+ expected := "x509: inner and outer signature algorithm identifiers don't match"
+ if err.Error() != expected {
+ t.Errorf("unexpected error from ParseCertificate: got %q, want %q", err.Error(), expected)
+ }
+ }
+}
+
+const optionalAuthKeyIDPEM = `-----BEGIN CERTIFICATE-----
+MIIFEjCCBHugAwIBAgICAQwwDQYJKoZIhvcNAQEFBQAwgbsxJDAiBgNVBAcTG1Zh
+bGlDZXJ0IFZhbGlkYXRpb24gTmV0d29yazEXMBUGA1UEChMOVmFsaUNlcnQsIElu
+Yy4xNTAzBgNVBAsTLFZhbGlDZXJ0IENsYXNzIDIgUG9saWN5IFZhbGlkYXRpb24g
+QXV0aG9yaXR5MSEwHwYDVQQDExhodHRwOi8vd3d3LnZhbGljZXJ0LmNvbS8xIDAe
+BgkqhkiG9w0BCQEWEWluZm9AdmFsaWNlcnQuY29tMB4XDTA0MDYyOTE3MzkxNloX
+DTI0MDYyOTE3MzkxNlowaDELMAkGA1UEBhMCVVMxJTAjBgNVBAoTHFN0YXJmaWVs
+ZCBUZWNobm9sb2dpZXMsIEluYy4xMjAwBgNVBAsTKVN0YXJmaWVsZCBDbGFzcyAy
+IENlcnRpZmljYXRpb24gQXV0aG9yaXR5MIIBIDANBgkqhkiG9w0BAQEFAAOCAQ0A
+MIIBCAKCAQEAtzLI/ulxpgSFrQwRZN/OTe/IAxiHP6Gr+zymn/DDodrU2G4rU5D7
+JKQ+hPCe6F/s5SdE9SimP3ve4CrwyK9TL57KBQGTHo9mHDmnTfpatnMEJWbrd3/n
+WcZKmSUUVOsmx/N/GdUwcI+vsEYq/63rKe3Xn6oEh6PU+YmlNF/bQ5GCNtlmPLG4
+uYL9nDo+EMg77wZlZnqbGRg9/3FRPDAuX749d3OyXQZswyNWmiuFJpIcpwKz5D8N
+rwh5grg2Peqc0zWzvGnK9cyd6P1kjReAM25eSl2ZyR6HtJ0awNVuEzUjXt+bXz3v
+1vd2wuo+u3gNHEJnawTY+Nbab4vyRKABqwIBA6OCAfMwggHvMB0GA1UdDgQWBBS/
+X7fRzt0fhvRbVazc1xDCDqmI5zCB0gYDVR0jBIHKMIHHoYHBpIG+MIG7MSQwIgYD
+VQQHExtWYWxpQ2VydCBWYWxpZGF0aW9uIE5ldHdvcmsxFzAVBgNVBAoTDlZhbGlD
+ZXJ0LCBJbmMuMTUwMwYDVQQLEyxWYWxpQ2VydCBDbGFzcyAyIFBvbGljeSBWYWxp
+ZGF0aW9uIEF1dGhvcml0eTEhMB8GA1UEAxMYaHR0cDovL3d3dy52YWxpY2VydC5j
+b20vMSAwHgYJKoZIhvcNAQkBFhFpbmZvQHZhbGljZXJ0LmNvbYIBATAPBgNVHRMB
+Af8EBTADAQH/MDkGCCsGAQUFBwEBBC0wKzApBggrBgEFBQcwAYYdaHR0cDovL29j
+c3Auc3RhcmZpZWxkdGVjaC5jb20wSgYDVR0fBEMwQTA/oD2gO4Y5aHR0cDovL2Nl
+cnRpZmljYXRlcy5zdGFyZmllbGR0ZWNoLmNvbS9yZXBvc2l0b3J5L3Jvb3QuY3Js
+MFEGA1UdIARKMEgwRgYEVR0gADA+MDwGCCsGAQUFBwIBFjBodHRwOi8vY2VydGlm
+aWNhdGVzLnN0YXJmaWVsZHRlY2guY29tL3JlcG9zaXRvcnkwDgYDVR0PAQH/BAQD
+AgEGMA0GCSqGSIb3DQEBBQUAA4GBAKVi8afCXSWlcD284ipxs33kDTcdVWptobCr
+mADkhWBKIMuh8D1195TaQ39oXCUIuNJ9MxB73HZn8bjhU3zhxoNbKXuNSm8uf0So
+GkVrMgfHeMpkksK0hAzc3S1fTbvdiuo43NlmouxBulVtWmQ9twPMHOKRUJ7jCUSV
+FxdzPcwl
+-----END CERTIFICATE-----`
+
+func TestAuthKeyIdOptional(t *testing.T) {
+ b, _ := pem.Decode([]byte(optionalAuthKeyIDPEM))
+ if b == nil {
+ t.Fatalf("couldn't decode test certificate")
+ }
+ _, err := ParseCertificate(b.Bytes)
+ if err != nil {
+ t.Fatalf("ParseCertificate to failed to parse certificate with optional authority key identifier fields: %s", err)
+ }
+}
+
+const largeOIDPEM = `
+Certificate:
+ Data:
+ Version: 3 (0x2)
+ Serial Number:
+ da:ba:53:19:1b:09:4b:82:b2:89:26:7d:c7:6f:a0:02
+ Signature Algorithm: sha256WithRSAEncryption
+ Issuer: O = Acme Co
+ Validity
+ Not Before: Dec 21 16:59:27 2021 GMT
+ Not After : Dec 21 16:59:27 2022 GMT
+ Subject: O = Acme Co
+ Subject Public Key Info:
+ Public Key Algorithm: rsaEncryption
+ RSA Public-Key: (2048 bit)
+ Modulus:
+ 00:bf:17:16:d8:bc:29:9c:16:e5:76:b4:93:15:78:
+ ad:6e:45:c5:4a:63:46:a1:b2:76:71:65:51:9c:14:
+ c4:ea:74:13:e4:34:df:2f:2c:65:11:e8:56:52:69:
+ 11:f9:0e:fc:77:bb:63:a8:7c:1a:c6:a1:7b:6e:6c:
+ e7:18:25:25:c9:e8:fb:06:7f:a2:a9:98:fe:2a:bc:
+ 8a:b3:75:b6:b8:7d:b6:c9:6b:29:08:32:22:10:cb:
+ 8d:d6:60:c8:83:ad:f5:58:91:d6:11:e8:55:56:fb:
+ 8f:a3:a2:9f:48:cb:79:e4:65:4a:8c:a6:52:64:9f:
+ 99:38:35:d4:d5:ac:6f:cf:a0:cb:42:8c:07:eb:21:
+ 17:31:3a:eb:91:7b:62:43:a4:75:5f:ef:a7:2f:94:
+ f8:69:0b:d4:ec:09:e6:00:c0:8c:dd:07:63:0b:e4:
+ 77:aa:60:18:3c:a0:e0:ae:0a:ea:0e:52:3b:b4:fa:
+ 6a:30:1b:50:62:21:73:53:33:01:60:a1:6b:99:58:
+ 00:f3:77:c6:0f:46:19:ca:c2:5d:cd:f5:e2:52:4d:
+ 84:94:23:d3:32:2f:ae:5f:da:43:a1:19:95:d2:17:
+ dd:49:14:b4:d9:48:1c:08:13:93:8e:d5:09:43:21:
+ b6:ce:52:e8:87:bb:d2:60:0d:c6:4e:bf:c5:93:6a:
+ c6:bf
+ Exponent: 65537 (0x10001)
+ X509v3 extensions:
+ X509v3 Key Usage: critical
+ Digital Signature, Key Encipherment
+ X509v3 Extended Key Usage:
+ TLS Web Server Authentication
+ X509v3 Basic Constraints: critical
+ CA:FALSE
+ X509v3 Subject Alternative Name:
+ DNS:longOID.example
+ X509v3 Certificate Policies:
+ Policy: 1.3.6.1.4.1.311.21.8.1492336001
+
+ Signature Algorithm: sha256WithRSAEncryption
+ 72:77:8b:de:48:fb:6d:9a:94:b1:be:d4:90:7d:4c:e6:d3:79:
+ fa:fb:fc:3e:d5:3d:e9:a0:ce:28:2b:2f:94:77:3f:87:f8:9c:
+ 9f:91:1c:f3:f6:58:91:15:6b:24:b9:ca:ae:9f:ee:ca:c8:31:
+ db:1a:3d:bb:6b:83:6d:bc:81:8b:a1:79:d5:3e:bb:dd:93:fe:
+ 35:3e:b7:99:e0:d6:eb:58:0c:fd:42:73:dc:49:da:e2:b7:ae:
+ 15:ee:e6:cc:aa:ef:91:41:9a:18:46:8d:4a:39:65:a2:85:3c:
+ 7f:0c:41:f8:0b:9c:e8:1f:35:36:60:8d:8c:e0:8e:18:b1:06:
+ 57:d0:4e:c4:c3:cd:8f:6f:e7:76:02:52:da:03:43:61:2b:b3:
+ bf:19:fd:73:0d:6a:0b:b4:b6:cb:a9:6f:70:4e:53:2a:54:07:
+ b3:74:fd:85:49:57:5b:23:8d:8c:6b:53:2b:09:e8:41:a5:80:
+ 3f:69:1b:11:d1:6b:13:35:2e:f9:d6:50:15:d9:91:38:42:43:
+ e9:17:af:67:d9:96:a4:d1:6a:4f:cc:b4:a7:8e:48:1f:00:72:
+ 69:de:4d:f1:73:a4:47:12:67:e9:f9:07:3e:79:75:90:42:b8:
+ d4:b5:fd:d1:7e:35:04:f7:00:04:cf:f1:36:be:0f:27:81:1f:
+ a6:ba:88:6c
+-----BEGIN CERTIFICATE-----
+MIIDHTCCAgWgAwIBAgIRANq6UxkbCUuCsokmfcdvoAIwDQYJKoZIhvcNAQELBQAw
+EjEQMA4GA1UEChMHQWNtZSBDbzAeFw0yMTEyMjExNjU5MjdaFw0yMjEyMjExNjU5
+MjdaMBIxEDAOBgNVBAoTB0FjbWUgQ28wggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAw
+ggEKAoIBAQC/FxbYvCmcFuV2tJMVeK1uRcVKY0ahsnZxZVGcFMTqdBPkNN8vLGUR
+6FZSaRH5Dvx3u2OofBrGoXtubOcYJSXJ6PsGf6KpmP4qvIqzdba4fbbJaykIMiIQ
+y43WYMiDrfVYkdYR6FVW+4+jop9Iy3nkZUqMplJkn5k4NdTVrG/PoMtCjAfrIRcx
+OuuRe2JDpHVf76cvlPhpC9TsCeYAwIzdB2ML5HeqYBg8oOCuCuoOUju0+mowG1Bi
+IXNTMwFgoWuZWADzd8YPRhnKwl3N9eJSTYSUI9MyL65f2kOhGZXSF91JFLTZSBwI
+E5OO1QlDIbbOUuiHu9JgDcZOv8WTasa/AgMBAAGjbjBsMA4GA1UdDwEB/wQEAwIF
+oDATBgNVHSUEDDAKBggrBgEFBQcDATAMBgNVHRMBAf8EAjAAMBoGA1UdEQQTMBGC
+D2xvbmdPSUQuZXhhbXBsZTAbBgNVHSAEFDASMBAGDisGAQQBgjcVCIXHzPsBMA0G
+CSqGSIb3DQEBCwUAA4IBAQByd4veSPttmpSxvtSQfUzm03n6+/w+1T3poM4oKy+U
+dz+H+JyfkRzz9liRFWskucqun+7KyDHbGj27a4NtvIGLoXnVPrvdk/41PreZ4Nbr
+WAz9QnPcSdrit64V7ubMqu+RQZoYRo1KOWWihTx/DEH4C5zoHzU2YI2M4I4YsQZX
+0E7Ew82Pb+d2AlLaA0NhK7O/Gf1zDWoLtLbLqW9wTlMqVAezdP2FSVdbI42Ma1Mr
+CehBpYA/aRsR0WsTNS751lAV2ZE4QkPpF69n2Zak0WpPzLSnjkgfAHJp3k3xc6RH
+Emfp+Qc+eXWQQrjUtf3RfjUE9wAEz/E2vg8ngR+muohs
+-----END CERTIFICATE-----`
+
+func TestLargeOID(t *testing.T) {
+ // See Issue 49678.
+ b, _ := pem.Decode([]byte(largeOIDPEM))
+ if b == nil {
+ t.Fatalf("couldn't decode test certificate")
+ }
+ _, err := ParseCertificate(b.Bytes)
+ if err != nil {
+ t.Fatalf("ParseCertificate to failed to parse certificate with large OID: %s", err)
+ }
+}
+
+const uniqueIDPEM = `-----BEGIN CERTIFICATE-----
+MIIFsDCCBJigAwIBAgIIrOyC1ydafZMwDQYJKoZIhvcNAQEFBQAwgY4xgYswgYgG
+A1UEAx6BgABNAGkAYwByAG8AcwBvAGYAdAAgAEYAbwByAGUAZgByAG8AbgB0ACAA
+VABNAEcAIABIAFQAVABQAFMAIABJAG4AcwBwAGUAYwB0AGkAbwBuACAAQwBlAHIA
+dABpAGYAaQBjAGEAdABpAG8AbgAgAEEAdQB0AGgAbwByAGkAdAB5MB4XDTE0MDEx
+ODAwNDEwMFoXDTE1MTExNTA5Mzc1NlowgZYxCzAJBgNVBAYTAklEMRAwDgYDVQQI
+EwdqYWthcnRhMRIwEAYDVQQHEwlJbmRvbmVzaWExHDAaBgNVBAoTE3N0aG9ub3Jl
+aG90ZWxyZXNvcnQxHDAaBgNVBAsTE3N0aG9ub3JlaG90ZWxyZXNvcnQxJTAjBgNV
+BAMTHG1haWwuc3Rob25vcmVob3RlbHJlc29ydC5jb20wggEiMA0GCSqGSIb3DQEB
+AQUAA4IBDwAwggEKAoIBAQCvuu0qpI+Ko2X84Twkf84cRD/rgp6vpgc5Ebejx/D4
+PEVON5edZkazrMGocK/oQqIlRxx/lefponN/chlGcllcVVPWTuFjs8k+Aat6T1qp
+4iXxZekAqX+U4XZMIGJD3PckPL6G2RQSlF7/LhGCsRNRdKpMWSTbou2Ma39g52Kf
+gsl3SK/GwLiWpxpcSkNQD1hugguEIsQYLxbeNwpcheXZtxbBGguPzQ7rH8c5vuKU
+BkMOzaiNKLzHbBdFSrua8KWwCJg76Vdq/q36O9GlW6YgG3i+A4pCJjXWerI1lWwX
+Ktk5V+SvUHGey1bkDuZKJ6myMk2pGrrPWCT7jP7WskChAgMBAAGBCQBCr1dgEleo
+cKOCAfswggH3MIHDBgNVHREEgbswgbiCHG1haWwuc3Rob25vcmVob3RlbHJlc29y
+dC5jb22CIGFzaGNoc3ZyLnN0aG9ub3JlaG90ZWxyZXNvcnQuY29tgiRBdXRvRGlz
+Y292ZXIuc3Rob25vcmVob3RlbHJlc29ydC5jb22CHEF1dG9EaXNjb3Zlci5ob3Rl
+bHJlc29ydC5jb22CCEFTSENIU1ZSghdzdGhvbm9yZWhvdGVscmVzb3J0LmNvbYIP
+aG90ZWxyZXNvcnQuY29tMCEGCSsGAQQBgjcUAgQUHhIAVwBlAGIAUwBlAHIAdgBl
+AHIwHQYDVR0OBBYEFMAC3UR4FwAdGekbhMgnd6lMejtbMAsGA1UdDwQEAwIFoDAT
+BgNVHSUEDDAKBggrBgEFBQcDATAJBgNVHRMEAjAAMIG/BgNVHQEEgbcwgbSAFGfF
+6xihk+gJJ5TfwvtWe1UFnHLQoYGRMIGOMYGLMIGIBgNVBAMegYAATQBpAGMAcgBv
+AHMAbwBmAHQAIABGAG8AcgBlAGYAcgBvAG4AdAAgAFQATQBHACAASABUAFQAUABT
+ACAASQBuAHMAcABlAGMAdABpAG8AbgAgAEMAZQByAHQAaQBmAGkAYwBhAHQAaQBv
+AG4AIABBAHUAdABoAG8AcgBpAHQAeYIIcKhXEmBXr0IwDQYJKoZIhvcNAQEFBQAD
+ggEBABlSxyCMr3+ANr+WmPSjyN5YCJBgnS0IFCwJAzIYP87bcTye/U8eQ2+E6PqG
+Q7Huj7nfHEw9qnGo+HNyPp1ad3KORzXDb54c6xEoi+DeuPzYHPbn4c3hlH49I0aQ
+eWW2w4RslSWpLvO6Y7Lboyz2/Thk/s2kd4RHxkkWpH2ltPqJuYYg3X6oM5+gIFHJ
+WGnh+ojZ5clKvS5yXh3Wkj78M6sb32KfcBk0Hx6NkCYPt60ODYmWtvqwtw6r73u5
+TnTYWRNvo2svX69TriL+CkHY9O1Hkwf2It5zHl3gNiKTJVaak8AuEz/CKWZneovt
+yYLwhUhg3PX5Co1VKYE+9TxloiE=
+-----END CERTIFICATE-----`
+
+func TestParseUniqueID(t *testing.T) {
+ b, _ := pem.Decode([]byte(uniqueIDPEM))
+ if b == nil {
+ t.Fatalf("couldn't decode test certificate")
+ }
+ cert, err := ParseCertificate(b.Bytes)
+ if err != nil {
+ t.Fatalf("ParseCertificate to failed to parse certificate with unique identifier id: %s", err)
+ }
+ if len(cert.Extensions) != 7 {
+ t.Fatalf("unexpected number of extensions (probably because the extension section was not parsed): got %d, want 7", len(cert.Extensions))
+ }
+}
+
+func TestDisableSHA1ForCertOnly(t *testing.T) {
+ t.Setenv("GODEBUG", "")
+
+ tmpl := &Certificate{
+ SerialNumber: big.NewInt(1),
+ NotBefore: time.Now().Add(-time.Hour),
+ NotAfter: time.Now().Add(time.Hour),
+ SignatureAlgorithm: SHA1WithRSA,
+ BasicConstraintsValid: true,
+ IsCA: true,
+ KeyUsage: KeyUsageCertSign | KeyUsageCRLSign,
+ }
+ certDER, err := CreateCertificate(rand.Reader, tmpl, tmpl, rsaPrivateKey.Public(), rsaPrivateKey)
+ if err != nil {
+ t.Fatalf("failed to generate test cert: %s", err)
+ }
+ cert, err := ParseCertificate(certDER)
+ if err != nil {
+ t.Fatalf("failed to parse test cert: %s", err)
+ }
+
+ err = cert.CheckSignatureFrom(cert)
+ if err == nil {
+ t.Error("expected CheckSignatureFrom to fail")
+ } else if _, ok := err.(InsecureAlgorithmError); !ok {
+ t.Errorf("expected InsecureAlgorithmError error, got %T", err)
+ }
+
+ crlDER, err := CreateRevocationList(rand.Reader, &RevocationList{
+ SignatureAlgorithm: SHA1WithRSA,
+ Number: big.NewInt(1),
+ ThisUpdate: time.Now().Add(-time.Hour),
+ NextUpdate: time.Now().Add(time.Hour),
+ }, cert, rsaPrivateKey)
+ if err != nil {
+ t.Fatalf("failed to generate test CRL: %s", err)
+ }
+ crl, err := ParseRevocationList(crlDER)
+ if err != nil {
+ t.Fatalf("failed to parse test CRL: %s", err)
+ }
+
+ if err = crl.CheckSignatureFrom(cert); err != nil {
+ t.Errorf("unexpected error: %s", err)
+ }
+
+ // This is an unrelated OCSP response, which will fail signature verification
+ // but shouldn't return a InsecureAlgorithmError, since SHA1 should be allowed
+ // for OCSP.
+ ocspTBSHex := "30819fa2160414884451ff502a695e2d88f421bad90cf2cecbea7c180f32303133303631383037323434335a30743072304a300906052b0e03021a0500041448b60d38238df8456e4ee5843ea394111802979f0414884451ff502a695e2d88f421bad90cf2cecbea7c021100f78b13b946fc9635d8ab49de9d2148218000180f32303133303631383037323434335aa011180f32303133303632323037323434335a"
+ ocspTBS, err := hex.DecodeString(ocspTBSHex)
+ if err != nil {
+ t.Fatalf("failed to decode OCSP response TBS hex: %s", err)
+ }
+
+ err = cert.CheckSignature(SHA1WithRSA, ocspTBS, nil)
+ if err != rsa.ErrVerification {
+ t.Errorf("unexpected error: %s", err)
+ }
+}
+
+func TestParseRevocationList(t *testing.T) {
+ derBytes := fromBase64(derCRLBase64)
+ certList, err := ParseRevocationList(derBytes)
+ if err != nil {
+ t.Errorf("error parsing: %s", err)
+ return
+ }
+ numCerts := len(certList.RevokedCertificates)
+ expected := 88
+ if numCerts != expected {
+ t.Errorf("bad number of revoked certificates. got: %d want: %d", numCerts, expected)
+ }
+}
+
+func TestRevocationListCheckSignatureFrom(t *testing.T) {
+ goodKey, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
+ if err != nil {
+ t.Fatalf("failed to generate test key: %s", err)
+ }
+ badKey, err := ecdsa.GenerateKey(elliptic.P224(), rand.Reader)
+ if err != nil {
+ t.Fatalf("failed to generate test key: %s", err)
+ }
+ tests := []struct {
+ name string
+ issuer *Certificate
+ err string
+ }{
+ {
+ name: "valid",
+ issuer: &Certificate{
+ Version: 3,
+ BasicConstraintsValid: true,
+ IsCA: true,
+ PublicKeyAlgorithm: ECDSA,
+ PublicKey: goodKey.Public(),
+ },
+ },
+ {
+ name: "valid, key usage set",
+ issuer: &Certificate{
+ Version: 3,
+ BasicConstraintsValid: true,
+ IsCA: true,
+ PublicKeyAlgorithm: ECDSA,
+ PublicKey: goodKey.Public(),
+ KeyUsage: KeyUsageCRLSign,
+ },
+ },
+ {
+ name: "invalid issuer, wrong key usage",
+ issuer: &Certificate{
+ Version: 3,
+ BasicConstraintsValid: true,
+ IsCA: true,
+ PublicKeyAlgorithm: ECDSA,
+ PublicKey: goodKey.Public(),
+ KeyUsage: KeyUsageCertSign,
+ },
+ err: "x509: invalid signature: parent certificate cannot sign this kind of certificate",
+ },
+ {
+ name: "invalid issuer, no basic constraints/ca",
+ issuer: &Certificate{
+ Version: 3,
+ PublicKeyAlgorithm: ECDSA,
+ PublicKey: goodKey.Public(),
+ },
+ err: "x509: invalid signature: parent certificate cannot sign this kind of certificate",
+ },
+ {
+ name: "invalid issuer, unsupported public key type",
+ issuer: &Certificate{
+ Version: 3,
+ BasicConstraintsValid: true,
+ IsCA: true,
+ PublicKeyAlgorithm: UnknownPublicKeyAlgorithm,
+ PublicKey: goodKey.Public(),
+ },
+ err: "x509: cannot verify signature: algorithm unimplemented",
+ },
+ {
+ name: "wrong key",
+ issuer: &Certificate{
+ Version: 3,
+ BasicConstraintsValid: true,
+ IsCA: true,
+ PublicKeyAlgorithm: ECDSA,
+ PublicKey: badKey.Public(),
+ },
+ err: "x509: ECDSA verification failure",
+ },
+ }
+
+ crlIssuer := &Certificate{
+ BasicConstraintsValid: true,
+ IsCA: true,
+ PublicKeyAlgorithm: ECDSA,
+ PublicKey: goodKey.Public(),
+ KeyUsage: KeyUsageCRLSign,
+ SubjectKeyId: []byte{1, 2, 3},
+ }
+ for _, tc := range tests {
+ t.Run(tc.name, func(t *testing.T) {
+ crlDER, err := CreateRevocationList(rand.Reader, &RevocationList{Number: big.NewInt(1)}, crlIssuer, goodKey)
+ if err != nil {
+ t.Fatalf("failed to generate CRL: %s", err)
+ }
+ crl, err := ParseRevocationList(crlDER)
+ if err != nil {
+ t.Fatalf("failed to parse test CRL: %s", err)
+ }
+ err = crl.CheckSignatureFrom(tc.issuer)
+ if err != nil && err.Error() != tc.err {
+ t.Errorf("unexpected error: got %s, want %s", err, tc.err)
+ } else if err == nil && tc.err != "" {
+ t.Errorf("CheckSignatureFrom did not fail: want %s", tc.err)
+ }
+ })
+ }
+}
+
+func TestOmitEmptyExtensions(t *testing.T) {
+ k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ tmpl := &Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
+ CommonName: ":)",
+ },
+ NotAfter: time.Now().Add(time.Hour),
+ NotBefore: time.Now().Add(-time.Hour),
+ }
+ der, err := CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k)
+ if err != nil {
+ t.Fatal(err)
+ }
+
+ emptyExtSeq := []byte{0xA3, 0x02, 0x30, 0x00}
+ if bytes.Contains(der, emptyExtSeq) {
+ t.Error("DER encoding contains the an empty extensions SEQUENCE")
+ }
+}
+
+var negativeSerialCert = `-----BEGIN CERTIFICATE-----
+MIIBBTCBraADAgECAgH/MAoGCCqGSM49BAMCMA0xCzAJBgNVBAMTAjopMB4XDTIy
+MDQxNDIzNTYwNFoXDTIyMDQxNTAxNTYwNFowDTELMAkGA1UEAxMCOikwWTATBgcq
+hkjOPQIBBggqhkjOPQMBBwNCAAQ9ezsIsj+q17K87z/PXE/rfGRN72P/Wyn5d6oo
+5M0ZbSatuntMvfKdX79CQxXAxN4oXk3Aov4jVSG12AcDI8ShMAoGCCqGSM49BAMC
+A0cAMEQCIBzfBU5eMPT6m5lsR6cXaJILpAaiD9YxOl4v6dT3rzEjAiBHmjnHmAss
+RqUAyJKFzqZxOlK2q4j2IYnuj5+LrLGbQA==
+-----END CERTIFICATE-----`
+
+func TestParseNegativeSerial(t *testing.T) {
+ pemBlock, _ := pem.Decode([]byte(negativeSerialCert))
+ _, err := ParseCertificate(pemBlock.Bytes)
+ if err != nil {
+ t.Fatalf("failed to parse certificate: %s", err)
+ }
+}
+
+func TestCreateNegativeSerial(t *testing.T) {
+ k, err := ecdsa.GenerateKey(elliptic.P256(), rand.Reader)
+ if err != nil {
+ t.Fatal(err)
+ }
+ tmpl := &Certificate{
+ SerialNumber: big.NewInt(-1),
+ Subject: pkix.Name{
+ CommonName: ":)",
+ },
+ NotAfter: time.Now().Add(time.Hour),
+ NotBefore: time.Now().Add(-time.Hour),
+ }
+ expectedErr := "x509: serial number must be positive"
+ _, err = CreateCertificate(rand.Reader, tmpl, tmpl, k.Public(), k)
+ if err == nil || err.Error() != expectedErr {
+ t.Errorf("CreateCertificate returned unexpected error: want %q, got %q", expectedErr, err)
+ }
+}
+
+const dupExtCert = `-----BEGIN CERTIFICATE-----
+MIIBrjCCARegAwIBAgIBATANBgkqhkiG9w0BAQsFADAPMQ0wCwYDVQQDEwR0ZXN0
+MCIYDzAwMDEwMTAxMDAwMDAwWhgPMDAwMTAxMDEwMDAwMDBaMA8xDTALBgNVBAMT
+BHRlc3QwgZ8wDQYJKoZIhvcNAQEBBQADgY0AMIGJAoGBAMiFchnHms9l9NninAIz
+SkY9acwl9Bk2AtmJrNCenFpiA17AcOO5q8DJYwdXi6WPKlVgcyH+ysW8XMWkq+CP
+yhtF/+LMzl9odaUF2iUy3vgTC5gxGLWH5URVssx21Und2Pm2f4xyou5IVxbS9dxy
+jLvV9PEY9BIb0H+zFthjhihDAgMBAAGjFjAUMAgGAioDBAIFADAIBgIqAwQCBQAw
+DQYJKoZIhvcNAQELBQADgYEAlhQ4TQQKIQ8GUyzGiN/75TCtQtjhMGemxc0cNgre
+d9rmm4DjydH0t7/sMCB56lQrfhJNplguzsbjFW4l245KbNKHfLiqwEGUgZjBNKur
+ot6qX/skahLtt0CNOaFIge75HVKe/69OrWQGdp18dkay/KS4Glu8YMKIjOhfrUi1
+NZA=
+-----END CERTIFICATE-----`
+
+func TestDuplicateExtensionsCert(t *testing.T) {
+ b, _ := pem.Decode([]byte(dupExtCert))
+ if b == nil {
+ t.Fatalf("couldn't decode test certificate")
+ }
+ _, err := ParseCertificate(b.Bytes)
+ if err == nil {
+ t.Fatal("ParseCertificate should fail when parsing certificate with duplicate extensions")
+ }
+}
+
+const dupExtCSR = `-----BEGIN CERTIFICATE REQUEST-----
+MIIBczCB3QIBADAPMQ0wCwYDVQQDEwR0ZXN0MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQC5PbxMGVJ8aLF9lq/EvGObXTRMB7ieiZL9N+DJZg1n/ECCnZLIvYrr
+ZmmDV7YZsClgxKGfjJB0RQFFyZElFM9EfHEs8NJdidDKCRdIhDXQWRyhXKevHvdm
+CQNKzUeoxvdHpU/uscSkw6BgUzPyLyTx9A6ye2ix94z8Y9hGOBO2DQIDAQABoCUw
+IwYJKoZIhvcNAQkOMRYwFDAIBgIqAwQCBQAwCAYCKgMEAgUAMA0GCSqGSIb3DQEB
+CwUAA4GBAHROEsE7URk1knXmBnQtIHwoq663vlMcX3Hes58pUy020rWP8QkocA+X
+VF18/phg3p5ILlS4fcbbP2bEeV0pePo2k00FDPsJEKCBAX2LKxbU7Vp2OuV2HM2+
+VLOVx0i+/Q7fikp3hbN1JwuMTU0v2KL/IKoUcZc02+5xiYrnOIt5
+-----END CERTIFICATE REQUEST-----`
+
+func TestDuplicateExtensionsCSR(t *testing.T) {
+ b, _ := pem.Decode([]byte(dupExtCSR))
+ if b == nil {
+ t.Fatalf("couldn't decode test CSR")
+ }
+ _, err := ParseCertificateRequest(b.Bytes)
+ if err == nil {
+ t.Fatal("ParseCertificateRequest should fail when parsing CSR with duplicate extensions")
+ }
+}
+
+const dupAttCSR = `-----BEGIN CERTIFICATE REQUEST-----
+MIIBbDCB1gIBADAPMQ0wCwYDVQQDEwR0ZXN0MIGfMA0GCSqGSIb3DQEBAQUAA4GN
+ADCBiQKBgQCj5Po3PKO/JNuxr+B+WNfMIzqqYztdlv+mTQhT0jOR5rTkUvxeeHH8
+YclryES2dOISjaUOTmOAr5GQIIdQl4Ql33Cp7ZR/VWcRn+qvTak0Yow+xVsDo0n4
+7IcvvP6CJ7FRoYBUakVczeXLxCjLwdyK16VGJM06eRzDLykPxpPwLQIDAQABoB4w
+DQYCKgMxBwwFdGVzdDEwDQYCKgMxBwwFdGVzdDIwDQYJKoZIhvcNAQELBQADgYEA
+UJ8hsHxtnIeqb2ufHnQFJO+wEJhx2Uxm/BTuzHOeffuQkwATez4skZ7SlX9exgb7
+6jRMRilqb4F7f8w+uDoqxRrA9zc8mwY16zPsyBhRet+ZGbj/ilgvGmtZ21qZZ/FU
+0pJFJIVLM3l49Onr5uIt5+hCWKwHlgE0nGpjKLR3cMg=
+-----END CERTIFICATE REQUEST-----`
+
+func TestDuplicateAttributesCSR(t *testing.T) {
+ b, _ := pem.Decode([]byte(dupAttCSR))
+ if b == nil {
+ t.Fatalf("couldn't decode test CSR")
+ }
+ _, err := ParseCertificateRequest(b.Bytes)
+ if err != nil {
+ t.Fatal("ParseCertificateRequest should succeed when parsing CSR with duplicate attributes")
+ }
+}
diff --git a/src/crypto/x509/x509_test_import.go b/src/crypto/x509/x509_test_import.go
new file mode 100644
index 0000000..2474e3d
--- /dev/null
+++ b/src/crypto/x509/x509_test_import.go
@@ -0,0 +1,56 @@
+// Copyright 2013 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+//go:build ignore
+
+// This file is run by the x509 tests to ensure that a program with minimal
+// imports can sign certificates without errors resulting from missing hash
+// functions.
+package main
+
+import (
+ "crypto/rand"
+ "crypto/x509"
+ "crypto/x509/pkix"
+ "encoding/pem"
+ "math/big"
+ "strings"
+ "time"
+)
+
+func main() {
+ block, _ := pem.Decode([]byte(pemPrivateKey))
+ rsaPriv, err := x509.ParsePKCS1PrivateKey(block.Bytes)
+ if err != nil {
+ panic("Failed to parse private key: " + err.Error())
+ }
+
+ template := x509.Certificate{
+ SerialNumber: big.NewInt(1),
+ Subject: pkix.Name{
+ CommonName: "test",
+ Organization: []string{"Σ Acme Co"},
+ },
+ NotBefore: time.Unix(1000, 0),
+ NotAfter: time.Unix(100000, 0),
+ KeyUsage: x509.KeyUsageCertSign,
+ }
+
+ if _, err = x509.CreateCertificate(rand.Reader, &template, &template, &rsaPriv.PublicKey, rsaPriv); err != nil {
+ panic("failed to create certificate with basic imports: " + err.Error())
+ }
+}
+
+var pemPrivateKey = testingKey(`-----BEGIN RSA TESTING KEY-----
+MIIBOgIBAAJBALKZD0nEffqM1ACuak0bijtqE2QrI/KLADv7l3kK3ppMyCuLKoF0
+fd7Ai2KW5ToIwzFofvJcS/STa6HA5gQenRUCAwEAAQJBAIq9amn00aS0h/CrjXqu
+/ThglAXJmZhOMPVn4eiu7/ROixi9sex436MaVeMqSNf7Ex9a8fRNfWss7Sqd9eWu
+RTUCIQDasvGASLqmjeffBNLTXV2A5g4t+kLVCpsEIZAycV5GswIhANEPLmax0ME/
+EO+ZJ79TJKN5yiGBRsv5yvx5UiHxajEXAiAhAol5N4EUyq6I9w1rYdhPMGpLfk7A
+IU2snfRJ6Nq2CQIgFrPsWRCkV+gOYcajD17rEqmuLrdIRexpg8N1DOSXoJ8CIGlS
+tAboUGBxTDq3ZroNism3DaMIbKPyYrAqhKov1h5V
+-----END RSA TESTING KEY-----
+`)
+
+func testingKey(s string) string { return strings.ReplaceAll(s, "TESTING KEY", "PRIVATE KEY") }