Johannes Bauer | 57ec206 | 2023-03-22 21:39:48 +0100 | [diff] [blame] | 1 | .. _userland_integration: |
| 2 | |
| 3 | ########################## |
| 4 | Linux userland integration |
| 5 | ########################## |
| 6 | |
| 7 | This document gives pointers on how particular features of OP-TEE may be used |
| 8 | from the Linux userland in typical application scenarios. |
| 9 | |
| 10 | PKCS#11 driver |
| 11 | ************** |
| 12 | |
| 13 | A common use-case is the integration of OP-TEE to securely store asymmetric |
| 14 | keys inside the secure enclave. For example, when using TLS with client |
| 15 | certificates, the corresponding private keys would reside securely within |
| 16 | OP-TEE. If this client certificate is then used from within userspace, the |
| 17 | corresponding cryptographic primitives are relayed to OP-TEE which establishes |
| 18 | the connection using the requested client certificate on behalf of the |
| 19 | application. However, the key itself never leaves secure storage (this is where |
| 20 | it is created and resides). |
| 21 | |
| 22 | The way this is done is via PKCS#11 (aka Cryptoki API). PKCS#11 specifies a |
| 23 | number of standard calls to relay cryptographic requests (such as a signing |
| 24 | operation) to a third party module. Such a module may be a smart card or, in |
| 25 | the case of OP-TEE, it is a software PKCS#11 trusted application that appears |
| 26 | to the userland as one. This trusted application is accessed using a shared |
| 27 | object (dynamic library) which serves as the "glue" to translate cryptographic |
| 28 | requests into OP-TEE calls. This shared object is ``libckteec.so`` which is |
| 29 | part of the `OP-TEE client tools <https://github.com/OP-TEE/optee_client>`_. |
| 30 | |
| 31 | Once OP-TEE has been compiled with the PKCS#11 TA, the client tools shared |
| 32 | object has been built and the OP-TEE supplicant has been started, we can use |
| 33 | ``pkcs11-tool`` of the `OpenSC project <https://github.com/OpenSC/OpenSC>`_ to |
| 34 | initiate first communication with the emulated smart card. In the following, |
| 35 | we assume that ``libckteec.so`` has been installed in |
| 36 | ``/usr/lib/libckteec.so``. For simplicity reasons, we define an alias to call |
| 37 | pkcs11-tool using the appropriate PKCS#11 module. |
| 38 | |
| 39 | .. code-block:: none |
| 40 | |
| 41 | # alias p11="pkcs11-tool --module /usr/lib/libckteec.so" |
| 42 | # p11 --show-info |
| 43 | Cryptoki version 2.40 |
| 44 | Manufacturer Linaro |
| 45 | Library OP-TEE PKCS11 Cryptoki library (ver 0.1) |
| 46 | Using slot 0 with a present token (0x0) |
| 47 | |
| 48 | .. hint:: |
| 49 | |
| 50 | When testing OP-TEE under QEMU, OpenSC should be built by default as well |
| 51 | and the ``pkcs11-tool`` should be available without modifications to the |
| 52 | configuration. It can be explicitly requested by using the |
| 53 | |
| 54 | .. code-block:: bash |
| 55 | |
| 56 | make BR2_PACKAGE_OPENSC=y |
| 57 | |
| 58 | build parameter when compiling OP-TEE. |
| 59 | |
| 60 | This tells us the library code is already working. We can now display the |
| 61 | different "slots". You can think of them as different "card readers" for |
| 62 | virtual smart cards. In a typical use case, only one slot is used for a single |
| 63 | smart card. |
| 64 | |
| 65 | .. code-block:: none |
| 66 | |
| 67 | # p11 --list-slots |
| 68 | Available slots: |
| 69 | Slot 0 (0x0): OP-TEE PKCS11 TA - TEE UUID 94e9ab89-4c43-56ea-8b35-45dc07226830 |
| 70 | token state: uninitialized |
| 71 | Slot 1 (0x1): OP-TEE PKCS11 TA - TEE UUID 94e9ab89-4c43-56ea-8b35-45dc07226830 |
| 72 | token state: uninitialized |
| 73 | Slot 2 (0x2): OP-TEE PKCS11 TA - TEE UUID 94e9ab89-4c43-56ea-8b35-45dc07226830 |
| 74 | token state: uninitialized |
| 75 | |
| 76 | Observe that the connection to the TA is also successfully working and it is |
| 77 | showing three inserted (but "empty", uninitialized) smart cards/tokens. Before |
| 78 | we are able to create keys on these tokens, we need to initialize them with a |
| 79 | SO-PIN and PIN. The SO-PIN is the "super pin", while the PIN is the "user |
| 80 | pin". The concept is likely familiar to you from the SIM card of your phone, |
| 81 | where the PUK acts as the "super pin". |
| 82 | |
| 83 | First, we initialize the SO-PIN of slot 0 and name our token "mytoken": |
| 84 | |
| 85 | .. code-block:: none |
| 86 | |
| 87 | # p11 --init-token --label mytoken --so-pin 1234567890 |
| 88 | Using slot 0 with a present token (0x0) |
| 89 | Token successfully initialized |
| 90 | |
| 91 | We have successfully initialized the SO-PIN to "1234567890". Now we "log in" |
| 92 | into the token using that SO-PIN and, using the SO-PIN authorization, |
| 93 | initialize the PIN of the token to "12345": |
| 94 | |
| 95 | .. code-block:: none |
| 96 | |
| 97 | # p11 --label mytoken --login --so-pin 1234567890 --init-pin --pin 12345 |
| 98 | Using slot 0 with a present token (0x0) |
| 99 | User PIN successfully initialized |
| 100 | |
| 101 | We can now verify that the token has been successfully initialized: |
| 102 | |
| 103 | .. code-block:: none |
| 104 | |
| 105 | # p11 --list-slots |
| 106 | Available slots: |
| 107 | Slot 0 (0x0): OP-TEE PKCS11 TA - TEE UUID 94e9ab89-4c43-56ea-8b35-45dc07226830 |
| 108 | token label : mytoken |
| 109 | token manufacturer : Linaro |
| 110 | token model : OP-TEE TA |
| 111 | token flags : login required, rng, token initialized, PIN initialized |
| 112 | hardware version : 0.0 |
| 113 | firmware version : 0.1 |
| 114 | serial num : 0000000000000000 |
| 115 | pin min/max : 4/128 |
| 116 | Slot 1 (0x1): OP-TEE PKCS11 TA - TEE UUID 94e9ab89-4c43-56ea-8b35-45dc07226830 |
| 117 | token state: uninitialized |
| 118 | Slot 2 (0x2): OP-TEE PKCS11 TA - TEE UUID 94e9ab89-4c43-56ea-8b35-45dc07226830 |
| 119 | token state: uninitialized |
| 120 | |
| 121 | Now we have a fully initialized token but it still contains no keys. To list |
| 122 | what cryptographic primitives the particular OP-TEE version offers, you can |
| 123 | query the supported mechanisms: |
| 124 | |
| 125 | .. code-block:: none |
| 126 | |
| 127 | # p11 --list-mechanisms |
| 128 | Using slot 0 with a present token (0x0) |
| 129 | Supported mechanisms: |
| 130 | SHA224-RSA-PKCS-PSS, keySize={256,4096}, sign, verify |
| 131 | SHA224-RSA-PKCS, keySize={256,4096}, sign, verify |
| 132 | SHA512-RSA-PKCS-PSS, keySize={256,4096}, sign, verify |
| 133 | SHA384-RSA-PKCS-PSS, keySize={256,4096}, sign, verify |
| 134 | SHA256-RSA-PKCS-PSS, keySize={256,4096}, sign, verify |
| 135 | SHA512-RSA-PKCS, keySize={256,4096}, sign, verify |
| 136 | SHA384-RSA-PKCS, keySize={256,4096}, sign, verify |
| 137 | SHA256-RSA-PKCS, keySize={256,4096}, sign, verify |
| 138 | SHA1-RSA-PKCS-PSS, keySize={256,4096}, sign, verify |
| 139 | RSA-PKCS-OAEP, keySize={256,4096}, encrypt, decrypt |
| 140 | SHA1-RSA-PKCS, keySize={256,4096}, sign, verify |
| 141 | MD5-RSA-PKCS, keySize={256,4096}, sign, verify |
| 142 | RSA-PKCS-PSS, sign, verify |
| 143 | RSA-PKCS, keySize={256,4096}, encrypt, decrypt, sign, verify |
| 144 | RSA-PKCS-KEY-PAIR-GEN, keySize={256,4096}, generate_key_pair |
| 145 | ECDSA-SHA512, keySize={160,521}, sign, verify |
| 146 | ECDSA-SHA384, keySize={160,521}, sign, verify |
| 147 | ECDSA-SHA256, keySize={160,521}, sign, verify |
| 148 | ECDSA-SHA224, keySize={160,521}, sign, verify |
| 149 | ECDSA-SHA1, keySize={160,521}, sign, verify |
| 150 | ECDSA, keySize={160,521}, sign, verify |
| 151 | ECDSA-KEY-PAIR-GEN, keySize={160,521}, generate_key_pair |
| 152 | mechtype-0x272, keySize={32,128}, sign, verify |
| 153 | mechtype-0x262, keySize={32,128}, sign, verify |
| 154 | mechtype-0x252, keySize={24,128}, sign, verify |
| 155 | mechtype-0x257, keySize={14,64}, sign, verify |
| 156 | SHA-1-HMAC-GENERAL, keySize={10,64}, sign, verify |
| 157 | MD5-HMAC-GENERAL, keySize={8,64}, sign, verify |
| 158 | SHA512-HMAC, keySize={32,128}, sign, verify |
| 159 | SHA384-HMAC, keySize={32,128}, sign, verify |
| 160 | SHA256-HMAC, keySize={24,128}, sign, verify |
| 161 | SHA224-HMAC, keySize={14,64}, sign, verify |
| 162 | SHA-1-HMAC, keySize={10,64}, sign, verify |
| 163 | MD5-HMAC, keySize={8,64}, sign, verify |
| 164 | SHA512, digest |
| 165 | SHA384, digest |
| 166 | SHA256, digest |
| 167 | SHA224, digest |
| 168 | SHA-1, digest |
| 169 | MD5, digest |
| 170 | GENERIC-SECRET-KEY-GEN, keySize={1,4096}, generate |
| 171 | AES-KEY-GEN, keySize={16,32}, generate |
| 172 | AES-CBC-ENCRYPT-DATA, derive |
| 173 | AES-ECB-ENCRYPT-DATA, derive |
| 174 | mechtype-0x108B, keySize={16,32}, sign, verify |
| 175 | AES-CMAC, keySize={16,32}, sign, verify |
| 176 | mechtype-0x1089, keySize={16,32}, encrypt, decrypt |
| 177 | AES-CTR, keySize={16,32}, encrypt, decrypt |
| 178 | AES-CBC-PAD, keySize={16,32}, encrypt, decrypt |
| 179 | AES-CBC, keySize={16,32}, encrypt, decrypt, wrap, unwrap |
| 180 | AES-ECB, keySize={16,32}, encrypt, decrypt, wrap, unwrap |
| 181 | |
| 182 | In our case, we would want to create an elliptic curve keypair on P-256 (aka |
| 183 | secp256r1 or prime256v1). As you can see, this is supported ("ECDSA-KEY-PAIR-GEN" supports |
| 184 | between 160 and 521 bit curves). |
| 185 | |
| 186 | .. code-block:: none |
| 187 | |
| 188 | # p11 -l --pin 12345 --keypairgen --key-type EC:prime256v1 --label mykey |
| 189 | Using slot 0 with a present token (0x0) |
| 190 | Key pair generated: |
| 191 | Private Key Object; EC |
| 192 | label: mykey |
| 193 | Usage: sign, derive |
| 194 | Access: sensitive, always sensitive, never extractable, local |
| 195 | Public Key Object; EC EC_POINT 256 bits |
| 196 | EC_POINT: 044104e3f89bd32ac8101ba675815fbaf34c4f34bb7bb2d233589983bad934cfa09795d56811747778d22b94e245028d3af6aff9e6abbbdb3a75fe1433182c605868c7 |
| 197 | EC_PARAMS: 06082a8648ce3d030107 |
| 198 | label: mykey |
| 199 | Usage: verify, derive |
| 200 | Access: local |
| 201 | |
| 202 | You can see the public key, which is a point on the elliptic curve. The byte |
| 203 | ``04`` at byte offset 2 indicates that this point is represented in |
| 204 | uncompressed affine representation, i.e., X and Y coordinates follow that byte |
| 205 | directly. This format is not ideal to interface common libraries, however. |
| 206 | Especially when using PKI with X.509 certificates, we typically want a |
| 207 | PEM-formatted CSR to be able to create a certificate from. |
| 208 | |
| 209 | For this, we create a small configuration file for OpenSSL and call it |
| 210 | ``optee_hsm.conf``. It references a library of `libp11 |
| 211 | <https://github.com/OpenSC/libp11>`_ which acts as a driver that enables |
| 212 | OpenSSL to interface with a PKCS#11 library. |
| 213 | |
| 214 | .. code-block:: |
| 215 | |
| 216 | openssl_conf = openssl_conf |
| 217 | |
| 218 | [openssl_conf] |
| 219 | engines = engine_section |
| 220 | |
| 221 | [engine_section] |
| 222 | pkcs11 = pkcs11_section |
| 223 | |
| 224 | [pkcs11_section] |
| 225 | engine_id = pkcs11 |
| 226 | dynamic_path = /usr/lib/engines-1.1/libpkcs11.so |
| 227 | MODULE_PATH = /usr/lib/libckteec.so |
| 228 | PIN = 12345 |
| 229 | |
| 230 | [req] |
| 231 | distinguished_name = req_distinguished_name |
| 232 | |
| 233 | [req_distinguished_name] |
| 234 | |
| 235 | .. hint:: |
| 236 | |
| 237 | When testing OP-TEE under QEMU, libp11 is not compiled by default. For easy |
| 238 | access to this library, you can build OP-TEE using the command |
| 239 | |
| 240 | .. code-block:: none |
| 241 | |
| 242 | make BR2_PACKAGE_OPENSC=y BR2_PACKAGE_LIBOPENSSL=y BR2_PACKAGE_LIBOPENSSL_BIN=y BR2_PACKAGE_LIBP11=y |
| 243 | |
| 244 | This will ensure that OpenSC (for the command line utility ``pkcs11-tool``), |
| 245 | OpenSSL, and libp11 are all built and installed in the QEMU environment. |
| 246 | Note that in that environment, ``libpkcs11.so`` will reside at |
| 247 | ``/usr/lib/engines-1.1/libpkcs11.so``. |
| 248 | |
| 249 | Then, we can ask OpenSSL to create a CSR from the key we have previously created: |
| 250 | |
| 251 | .. code-block:: none |
| 252 | |
| 253 | # OPENSSL_CONF=optee_hsm.conf openssl req -new -engine pkcs11 -keyform engine -key label_mykey -subj "/CN=My CSR" -out mykey_csr.pem |
| 254 | engine "pkcs11" set. |
| 255 | |
| 256 | We can then inspect said CSR: |
| 257 | |
| 258 | .. code-block:: none |
| 259 | |
| 260 | $ openssl req -in mykey_csr.pem -text |
| 261 | Certificate Request: |
| 262 | Data: |
| 263 | Version: 1 (0x0) |
| 264 | Subject: CN = My CSR |
| 265 | Subject Public Key Info: |
| 266 | Public Key Algorithm: id-ecPublicKey |
| 267 | Public-Key: (256 bit) |
| 268 | pub: |
| 269 | 04:e3:f8:9b:d3:2a:c8:10:1b:a6:75:81:5f:ba:f3: |
| 270 | 4c:4f:34:bb:7b:b2:d2:33:58:99:83:ba:d9:34:cf: |
| 271 | a0:97:95:d5:68:11:74:77:78:d2:2b:94:e2:45:02: |
| 272 | 8d:3a:f6:af:f9:e6:ab:bb:db:3a:75:fe:14:33:18: |
| 273 | 2c:60:58:68:c7 |
| 274 | ASN1 OID: prime256v1 |
| 275 | NIST CURVE: P-256 |
| 276 | Attributes: |
| 277 | a0:00 |
| 278 | Signature Algorithm: ecdsa-with-SHA256 |
| 279 | 30:45:02:20:61:7e:05:30:cf:4d:d0:93:22:78:9e:45:cf:af: |
| 280 | 3c:83:bb:04:c4:f0:81:f6:9a:5c:97:cd:ac:1e:94:cd:17:1b: |
| 281 | 02:21:00:e7:7f:88:1d:4f:56:b8:e2:87:be:76:de:28:b3:92: |
| 282 | 68:a7:16:3a:56:af:79:2f:98:bd:fd:6d:b3:82:e1:15:6c |
| 283 | |
| 284 | Note that the public key matches exactly that which we have previously created |
| 285 | (``04 e3 f8...``). This CSR could then be signed by a CA. For simplicity |
| 286 | purposes, we can also use a self-signed certificate and sign with our own |
| 287 | OP-TEE contained key: |
| 288 | |
| 289 | .. code-block:: none |
| 290 | |
| 291 | # OPENSSL_CONF=optee_hsm.conf openssl req -new -engine pkcs11 -keyform engine -key label_mykey -subj "/CN=My CSR" -x509 -out mykey_selfsigned_cert.pem |
| 292 | engine "pkcs11" set. |
| 293 | |
| 294 | Again we can review this self-signed certificate: |
| 295 | |
| 296 | .. code-block:: none |
| 297 | |
| 298 | $ openssl x509 -in mykey_selfsigned_cert.pem -text |
| 299 | Certificate: |
| 300 | Data: |
| 301 | Version: 1 (0x0) |
| 302 | Serial Number: |
| 303 | 3f:8f:c8:c0:de:a8:75:ca:9d:62:79:31:c2:6c:48:f4:fd:50:22:1d |
| 304 | Signature Algorithm: ecdsa-with-SHA256 |
| 305 | Issuer: CN = My CSR |
| 306 | Validity |
| 307 | Not Before: Mar 22 20:19:15 2023 GMT |
| 308 | Not After : Apr 21 20:19:15 2023 GMT |
| 309 | Subject: CN = My CSR |
| 310 | Subject Public Key Info: |
| 311 | Public Key Algorithm: id-ecPublicKey |
| 312 | Public-Key: (256 bit) |
| 313 | pub: |
| 314 | 04:e3:f8:9b:d3:2a:c8:10:1b:a6:75:81:5f:ba:f3: |
| 315 | 4c:4f:34:bb:7b:b2:d2:33:58:99:83:ba:d9:34:cf: |
| 316 | a0:97:95:d5:68:11:74:77:78:d2:2b:94:e2:45:02: |
| 317 | 8d:3a:f6:af:f9:e6:ab:bb:db:3a:75:fe:14:33:18: |
| 318 | 2c:60:58:68:c7 |
| 319 | ASN1 OID: prime256v1 |
| 320 | NIST CURVE: P-256 |
| 321 | Signature Algorithm: ecdsa-with-SHA256 |
| 322 | 30:45:02:20:4a:9d:63:f2:e0:12:4b:46:eb:eb:62:34:9e:86: |
| 323 | 3d:d4:c8:cf:5f:c0:44:fe:8b:71:a0:b8:fa:41:d9:0b:60:3a: |
| 324 | 02:21:00:fb:c2:b3:0a:7b:54:e9:bb:66:7b:8e:f7:11:52:81: |
| 325 | 69:81:a6:cc:d0:bf:a2:7c:f7:2a:67:db:ab:f1:f3:2c:9f |
| 326 | -----BEGIN CERTIFICATE----- |
| 327 | MIIBHDCBwwIUP4/IwN6odcqdYnkxwmxI9P1QIh0wCgYIKoZIzj0EAwIwETEPMA0G |
| 328 | A1UEAwwGTXkgQ1NSMB4XDTIzMDMyMjIwMTkxNVoXDTIzMDQyMTIwMTkxNVowETEP |
| 329 | MA0GA1UEAwwGTXkgQ1NSMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE4/ib0yrI |
| 330 | EBumdYFfuvNMTzS7e7LSM1iZg7rZNM+gl5XVaBF0d3jSK5TiRQKNOvav+earu9s6 |
| 331 | df4UMxgsYFhoxzAKBggqhkjOPQQDAgNIADBFAiBKnWPy4BJLRuvrYjSehj3UyM9f |
| 332 | wET+i3GguPpB2QtgOgIhAPvCswp7VOm7ZnuO9xFSgWmBpszQv6J89ypn26vx8yyf |
| 333 | -----END CERTIFICATE----- |
| 334 | |
| 335 | To test our self-signed certificate as a client certificate, we first need to |
| 336 | initialize a TLS server. This can either be done on a remote machine or |
| 337 | locally. For the server we will again use a self-signed certificate (but simply |
| 338 | store the corresponding private key in a file). |
| 339 | |
| 340 | .. code-block:: none |
| 341 | |
| 342 | $ openssl ecparam -genkey -name prime256v1 -out server_key.pem |
| 343 | $ openssl req -new -x509 -key server_key.pem -subj '/CN=Server' -out server_cert.pem |
| 344 | $ openssl s_server -accept 9876 -cert server_cert.pem -key server_key.pem -www -Verify 1 |
| 345 | verify depth is 1, must return a certificate |
| 346 | Using default temp DH parameters |
| 347 | ACCEPT |
| 348 | |
| 349 | This starts a HTTPS server which listens at port 9876 and requires a TLS client |
| 350 | certificate. We can validate that the connection to the server is refused if no |
| 351 | client certificate is provided. Assume that ``192.168.178.34`` is the IPv4 |
| 352 | address of the server: |
| 353 | |
| 354 | .. code-block:: none |
| 355 | |
| 356 | $ curl -k https://192.168.178.34:9876 |
| 357 | curl: (56) OpenSSL SSL_read: error:0A00045C:SSL routines::tlsv13 alert certificate required, errno 0 |
| 358 | |
| 359 | Now on our OP-TEE device we can use OpenSSL to establish a connection using our |
| 360 | OP-TEE stored client certificate: |
| 361 | |
| 362 | .. code-block:: none |
| 363 | |
| 364 | # OPENSSL_CONF=optee_hsm.conf openssl s_client -engine pkcs11 -connect 192.168.178.34:9876 -cert mykey_selfsigned_cert.pem -keyform engine -key label_mykey |
| 365 | engine "pkcs11" set. |
| 366 | CONNECTED(00000004) |
| 367 | Can't use SSL_get_servername |
| 368 | depth=0 CN = Server |
| 369 | verify error:num=18:self signed certificate |
| 370 | verify return:1 |
| 371 | depth=0 CN = Server |
| 372 | verify return:1 |
| 373 | --- |
| 374 | Certificate chain |
| 375 | 0 s:CN = Server |
| 376 | i:CN = Server |
| 377 | --- |
| 378 | Server certificate |
| 379 | -----BEGIN CERTIFICATE----- |
| 380 | MIIBeDCCAR2gAwIBAgIUDnUzOcNS9AgeJhvVmp73wF5DwxQwCgYIKoZIzj0EAwIw |
| 381 | ETEPMA0GA1UEAwwGU2VydmVyMB4XDTIzMDMyMjIwMjMwMloXDTIzMDQyMTIwMjMw |
| 382 | MlowETEPMA0GA1UEAwwGU2VydmVyMFkwEwYHKoZIzj0CAQYIKoZIzj0DAQcDQgAE |
| 383 | qnCvLjLa1XWBtY1OQjaHa60re5vnZ2WY555XSsFCe2RoF7wGBDDrdXKkQz9Vy0t4 |
| 384 | d5OC6VMcFhia967nGa5zPqNTMFEwHQYDVR0OBBYEFBKTMLG057a/a2exmeF7dHVH |
| 385 | 85D0MB8GA1UdIwQYMBaAFBKTMLG057a/a2exmeF7dHVH85D0MA8GA1UdEwEB/wQF |
| 386 | MAMBAf8wCgYIKoZIzj0EAwIDSQAwRgIhAIeKwlghSkhA8zvpXsl9y6WSCXo9fRzt |
| 387 | DSl6myUsgac/AiEAhipKSjVQAvJAqXIecmMylqjY79XVzrbxKWYjsL1XdLw= |
| 388 | -----END CERTIFICATE----- |
| 389 | subject=CN = Server |
| 390 | |
| 391 | issuer=CN = Server |
| 392 | |
| 393 | --- |
| 394 | No client certificate CA names sent |
| 395 | Requested Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:Ed25519:Ed448:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512:ECDSA+SHA224:RSA+SHA224 |
| 396 | Shared Requested Signature Algorithms: ECDSA+SHA256:ECDSA+SHA384:ECDSA+SHA512:Ed25519:Ed448:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA-PSS+SHA256:RSA-PSS+SHA384:RSA-PSS+SHA512:RSA+SHA256:RSA+SHA384:RSA+SHA512 |
| 397 | Peer signing digest: SHA256 |
| 398 | Peer signature type: ECDSA |
| 399 | Server Temp Key: X25519, 253 bits |
| 400 | --- |
| 401 | SSL handshake has read 817 bytes and written 797 bytes |
| 402 | Verification error: self signed certificate |
| 403 | --- |
| 404 | New, TLSv1.3, Cipher is TLS_AES_256_GCM_SHA384 |
| 405 | Server public key is 256 bit |
| 406 | Secure Renegotiation IS NOT supported |
| 407 | Compression: NONE |
| 408 | Expansion: NONE |
| 409 | No ALPN negotiated |
| 410 | Early data was not sent |
| 411 | Verify return code: 18 (self signed certificate) |
| 412 | [...] |
| 413 | |
| 414 | When connected, you can type "GET /" and press return to get a HTML response |
| 415 | back from the HTTPS server, which will echo your client certificate inside a |
| 416 | HTML page. |