diff --git a/.github/workflows/lint.yml b/.github/workflows/lint.yml index 5e75f595..666bd15b 100644 --- a/.github/workflows/lint.yml +++ b/.github/workflows/lint.yml @@ -17,8 +17,8 @@ jobs: command: fmt args: --all -- --check - clippy: - name: cargo clippy + clippy-openssl: + name: cargo clippy openssl runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -31,7 +31,23 @@ jobs: - uses: actions-rs/cargo@v1 with: command: clippy - args: --all-features --all-targets -- -D clippy::all -D unused_imports -Dwarnings + args: --features=openssl,hw_tests,dangerous_hw_tests --all-targets -- -D clippy::all -D unused_imports -Dwarnings + + clippy-crypto_nossl: + name: cargo clippy crypto_nossl + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + components: clippy + toolchain: nightly + profile: minimal + override: true + - uses: actions-rs/cargo@v1 + with: + command: clippy + args: --features=crypto_nossl,hw_tests,dangerous_hw_tests --all-targets -- -D clippy::all -D unused_imports -Dwarnings readme: name: cargo readme diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index 9614ad77..d10353a1 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -1,8 +1,8 @@ on: [push, pull_request] name: test jobs: - sw: - name: sw ${{ matrix.toolchain }} ${{ matrix.profile.name }} ${{ matrix.features }} + sw-openssl: + name: sw openssl ${{ matrix.toolchain }} ${{ matrix.profile.name }} ${{ matrix.features }} runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -27,3 +27,30 @@ jobs: flag: --release features: - openssl + + sw-crypto_nossl: + name: sw crypto_nossl ${{ matrix.toolchain }} ${{ matrix.profile.name }} ${{ matrix.features }} + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v2 + - uses: actions-rs/toolchain@v1 + with: + toolchain: ${{ matrix.toolchain }} + override: true + - uses: actions-rs/cargo@v1 + with: + command: test + args: ${{ matrix.profile.flag }} --features=${{ matrix.features }} + strategy: + fail-fast: false + matrix: + toolchain: + - nightly + - beta + - stable + profile: + - name: debug + - name: release + flag: --release + features: + - crypto_nossl diff --git a/.gitignore b/.gitignore index 97e6d832..de358ff3 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,2 @@ /target -Cargo.lock .vscode/ diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 00000000..f8d75c50 --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,1107 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "autocfg" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" + +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + +[[package]] +name = "bincode" +version = "1.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b1f45e9417d87227c7a56d22e471c6206462cba514c7590c09aff4cf6d1ddcad" +dependencies = [ + "serde", +] + +[[package]] +name = "bitfield" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "46afbd2983a5d5a7bd740ccb198caf5b82f45c40c09c0eed36052d91cb92e719" + +[[package]] +name = "bitflags" +version = "1.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" + +[[package]] +name = "bitflags" +version = "2.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b4682ae6287fcf752ecaabbfcc7b6f9b72aa33933dc23a554d853aea8eea8635" + +[[package]] +name = "block-buffer" +version = "0.10.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3078c7629b62d3f0439517fa394996acacc5cbc91c5a20d8c658e77abd503a71" +dependencies = [ + "generic-array", +] + +[[package]] +name = "byteorder" +version = "1.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1fd0f2584146f6f2ef48085050886acf353beff7305ebd1ae69500e27c67f64b" + +[[package]] +name = "cc" +version = "1.0.83" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f1174fb0b6ec23863f8b971027804a42614e347eafb0a95bf0b12cdae21fc4d0" +dependencies = [ + "libc", +] + +[[package]] +name = "cfg-if" +version = "1.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" + +[[package]] +name = "codicon" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "12170080f3533d6f09a19f81596f836854d0fa4867dc32c8172b8474b4e9de61" + +[[package]] +name = "const-oid" +version = "0.9.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "28c122c3980598d243d63d9a704629a2d748d101f278052ff068be5a4423ab6f" + +[[package]] +name = "cpufeatures" +version = "0.2.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a17b76ff3a4162b0b27f354a0c87015ddad39d35f9c0c36607a3bdd175dde1f1" +dependencies = [ + "libc", +] + +[[package]] +name = "crypto-bigint" +version = "0.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "740fe28e594155f10cfc383984cbefd529d7396050557148f79cb0f621204124" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + +[[package]] +name = "crypto-common" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1bfb12502f3fc46cca1bb51ac28df9d618d813cdc3d2f25b9fe775a34af26bb3" +dependencies = [ + "generic-array", + "typenum", +] + +[[package]] +name = "dashmap" +version = "5.5.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "978747c1d849a7d2ee5e8adc0159961c48fb7e5db2f06af6723b80123bb53856" +dependencies = [ + "cfg-if", + "hashbrown", + "lock_api", + "once_cell", + "parking_lot_core", +] + +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "der_derive", + "flagset", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fe87ce4529967e0ba1dcf8450bab64d97dfd5010a6256187ffe2e43e6f0e049" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "digest" +version = "0.10.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" +dependencies = [ + "block-buffer", + "const-oid", + "crypto-common", + "subtle", +] + +[[package]] +name = "dirs" +version = "5.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "44c45a9d03d6676652bcb5e724c7e988de1acad23a711b5217ab9cbecbec2225" +dependencies = [ + "dirs-sys", +] + +[[package]] +name = "dirs-sys" +version = "0.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "520f05a5cbd335fae5a99ff7a6ab8627577660ee5cfd6a94a6a929b52ff0321c" +dependencies = [ + "libc", + "option-ext", + "redox_users", + "windows-sys", +] + +[[package]] +name = "ecdsa" +version = "0.16.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a4b1e0c257a9e9f25f90ff76d7a68360ed497ee519c8e428d1825ef0000799d4" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d97ca172ae9dc9f9b779a6e3a65d308f2af74e5b8c921299075bdb4a0370e914" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + +[[package]] +name = "flagset" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a7e408202050813e6f1d9addadcaafef3dca7530c7ddfb005d4081cce6779" + +[[package]] +name = "foreign-types" +version = "0.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f6f339eb8adc052cd2ca78910fda869aefa38d22d5cb648e6485e4d3fc06f3b1" +dependencies = [ + "foreign-types-shared", +] + +[[package]] +name = "foreign-types-shared" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "00b0228411908ca8685dba7fc2cdd70ec9990a6e753e89b6ac91a84c40fbaf4b" + +[[package]] +name = "futures" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "23342abe12aba583913b2e62f22225ff9c950774065e4bfb61a19cd9770fec40" +dependencies = [ + "futures-channel", + "futures-core", + "futures-executor", + "futures-io", + "futures-sink", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-channel" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "955518d47e09b25bbebc7a18df10b81f0c766eaf4c4f1cccef2fca5f2a4fb5f2" +dependencies = [ + "futures-core", + "futures-sink", +] + +[[package]] +name = "futures-core" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4bca583b7e26f571124fe5b7561d49cb2868d79116cfa0eefce955557c6fee8c" + +[[package]] +name = "futures-executor" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ccecee823288125bd88b4d7f565c9e58e41858e47ab72e8ea2d64e93624386e0" +dependencies = [ + "futures-core", + "futures-task", + "futures-util", +] + +[[package]] +name = "futures-io" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fff74096e71ed47f8e023204cfd0aa1289cd54ae5430a9523be060cdb849964" + +[[package]] +name = "futures-sink" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f43be4fe21a13b9781a69afa4985b0f6ee0e1afab2c6f454a8cf30e2b2237b6e" + +[[package]] +name = "futures-task" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "76d3d132be6c0e6aa1534069c705a74a5997a356c0dc2f86a47765e5617c5b65" + +[[package]] +name = "futures-util" +version = "0.3.28" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26b01e40b772d54cf6c6d721c1d1abd0647a0106a12ecaa1c186273392a69533" +dependencies = [ + "futures-channel", + "futures-core", + "futures-io", + "futures-sink", + "futures-task", + "memchr", + "pin-project-lite", + "pin-utils", + "slab", +] + +[[package]] +name = "generic-array" +version = "0.14.7" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" +dependencies = [ + "typenum", + "version_check", + "zeroize", +] + +[[package]] +name = "getrandom" +version = "0.2.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "be4136b2a15dd319360be1c07d9933517ccf0be8f16bf62a3bee4f0d618df427" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + +[[package]] +name = "hashbrown" +version = "0.14.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7dfda62a12f55daeae5015f81b0baea145391cb4520f86c248fc615d72640d12" + +[[package]] +name = "hex" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7f24254aa9a54b5c858eaee2f5bccdb46aaf0e486a595ed5fd8f86ba55232a70" + +[[package]] +name = "hkdf" +version = "0.12.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "791a029f6b9fc27657f6f188ec6e5e43f6911f6f878e0dc5501396e09809d437" +dependencies = [ + "hmac", +] + +[[package]] +name = "hmac" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6c49c37c09c17a53d937dfbb742eb3a961d65a994e6bcdcf37e7399d0cc8ab5e" +dependencies = [ + "digest", +] + +[[package]] +name = "iocuddle" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d8972d5be69940353d5347a1344cb375d9b457d6809b428b05bb1ca2fb9ce007" + +[[package]] +name = "kvm-bindings" +version = "0.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "efe70e65a5b092161d17f5005b66e5eefe7a94a70c332e755036fc4af78c4e79" +dependencies = [ + "vmm-sys-util", +] + +[[package]] +name = "kvm-ioctls" +version = "0.15.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9bdde2b46ee7b6587ef79f751019c4726c4f2d3e4628df5d69f3f9c5cb6c6bd4" +dependencies = [ + "kvm-bindings", + "libc", + "vmm-sys-util", +] + +[[package]] +name = "lazy_static" +version = "1.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646" +dependencies = [ + "spin", +] + +[[package]] +name = "libc" +version = "0.2.148" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9cdc71e17332e86d2e1d38c1f99edcb6288ee11b815fb1a4b049eaa2114d369b" + +[[package]] +name = "libm" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ec2a862134d2a7d32d7983ddcdd1c4923530833c9f2ea1a44fc5fa473989058" + +[[package]] +name = "lock_api" +version = "0.4.10" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c1cc9717a20b1bb222f333e6a92fd32f7d8a18ddc5a3191a11af45dcbf4dcd16" +dependencies = [ + "autocfg", + "scopeguard", +] + +[[package]] +name = "log" +version = "0.4.20" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6163cb8c49088c2c36f57875e58ccd8c87c7427f7fbd50ea6710b2f3f2e8f" + +[[package]] +name = "memchr" +version = "2.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f665ee40bc4a3c5590afb1e9677db74a508659dfd71e126420da8274909a0167" + +[[package]] +name = "num-bigint-dig" +version = "0.8.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc84195820f291c7697304f3cbdadd1cb7199c0efc917ff5eafd71225c136151" +dependencies = [ + "byteorder", + "lazy_static", + "libm", + "num-integer", + "num-iter", + "num-traits", + "rand", + "smallvec", + "zeroize", +] + +[[package]] +name = "num-integer" +version = "0.1.45" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "225d3389fb3509a24c93f5c29eb6bde2586b98d9f016636dff58d7c6f7569cd9" +dependencies = [ + "autocfg", + "num-traits", +] + +[[package]] +name = "num-iter" +version = "0.1.43" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7d03e6c028c5dc5cac6e2dec0efda81fc887605bb3d884578bb6d6bf7514e252" +dependencies = [ + "autocfg", + "num-integer", + "num-traits", +] + +[[package]] +name = "num-traits" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "39e3200413f237f41ab11ad6d161bc7239c84dcb631773ccd7de3dfe4b5c267c" +dependencies = [ + "autocfg", + "libm", +] + +[[package]] +name = "once_cell" +version = "1.18.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" + +[[package]] +name = "openssl" +version = "0.10.57" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bac25ee399abb46215765b1cb35bc0212377e58a061560d8b29b024fd0430e7c" +dependencies = [ + "bitflags 2.4.0", + "cfg-if", + "foreign-types", + "libc", + "once_cell", + "openssl-macros", + "openssl-sys", +] + +[[package]] +name = "openssl-macros" +version = "0.1.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a948666b637a0f465e8564c73e89d4dde00d72d4d473cc972f390fc3dcee7d9c" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "openssl-sys" +version = "0.9.93" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "db4d56a4c0478783083cfafcc42493dd4a981d41669da64b4572a2a089b51b1d" +dependencies = [ + "cc", + "libc", + "pkg-config", + "vcpkg", +] + +[[package]] +name = "option-ext" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d" + +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "parking_lot" +version = "0.12.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3742b2c103b9f06bc9fff0a37ff4912935851bee6d36f3c02bcc755bcfec228f" +dependencies = [ + "lock_api", + "parking_lot_core", +] + +[[package]] +name = "parking_lot_core" +version = "0.9.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93f00c865fe7cabf650081affecd3871070f26767e7b2070a3ffae14c654b447" +dependencies = [ + "cfg-if", + "libc", + "redox_syscall 0.3.5", + "smallvec", + "windows-targets", +] + +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + +[[package]] +name = "pin-project-lite" +version = "0.2.13" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8afb450f006bf6385ca15ef45d71d2288452bc3683ce2e2cacc0d18e4be60b58" + +[[package]] +name = "pin-utils" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b870d8c151b6f2fb93e84a13146138f05d02ed11c7e7c54f8826aaaf7c9f184" + +[[package]] +name = "pkcs1" +version = "0.7.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8ffb9f10fa047879315e6625af03c164b16962a5368d724ed16323b68ace47f" +dependencies = [ + "der", + "pkcs8", + "spki", +] + +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + +[[package]] +name = "pkg-config" +version = "0.3.27" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" + +[[package]] +name = "ppv-lite86" +version = "0.2.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" + +[[package]] +name = "primeorder" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3c2fcef82c0ec6eefcc179b978446c399b3cdf73c392c35604e399eee6df1ee3" +dependencies = [ + "elliptic-curve", +] + +[[package]] +name = "proc-macro2" +version = "1.0.67" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3d433d9f1a3e8c1263d9456598b16fec66f4acc9a74dacffd35c7bb09b3a1328" +dependencies = [ + "unicode-ident", +] + +[[package]] +name = "quote" +version = "1.0.33" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5267fca4496028628a95160fc423a33e8b2e6af8a5302579e322e4b520293cae" +dependencies = [ + "proc-macro2", +] + +[[package]] +name = "rand" +version = "0.8.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "34af8d1a0e25924bc5b7c43c079c942339d8f0a8b57c39049bef581b46327404" +dependencies = [ + "rand_chacha", + "rand_core", +] + +[[package]] +name = "rand_chacha" +version = "0.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e6c10a63a0fa32252be49d21e7709d4d4baf8d231c2dbce1eaa8141b9b127d88" +dependencies = [ + "ppv-lite86", + "rand_core", +] + +[[package]] +name = "rand_core" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" +dependencies = [ + "getrandom", +] + +[[package]] +name = "redox_syscall" +version = "0.2.16" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fb5a58c1855b4b6819d59012155603f0b22ad30cad752600aadfcb695265519a" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_syscall" +version = "0.3.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "567664f262709473930a4bf9e51bf2ebf3348f2e748ccc50dea20646858f8f29" +dependencies = [ + "bitflags 1.3.2", +] + +[[package]] +name = "redox_users" +version = "0.4.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b033d837a7cf162d7993aded9304e30a83213c648b6e389db233191f891e5c2b" +dependencies = [ + "getrandom", + "redox_syscall 0.2.16", + "thiserror", +] + +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + +[[package]] +name = "rsa" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "86ef35bf3e7fe15a53c4ab08a998e42271eab13eb0db224126bc7bc4c4bad96d" +dependencies = [ + "const-oid", + "digest", + "num-bigint-dig", + "num-integer", + "num-traits", + "pkcs1", + "pkcs8", + "rand_core", + "signature", + "spki", + "subtle", + "zeroize", +] + +[[package]] +name = "scopeguard" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "94143f37725109f92c262ed2cf5e59bce7498c01bcc1502d7b9afe439a4e9f49" + +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + +[[package]] +name = "serde" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf9e0fcba69a370eed61bcf2b728575f726b50b55cba78064753d708ddc7549e" +dependencies = [ + "serde_derive", +] + +[[package]] +name = "serde-big-array" +version = "0.5.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "11fc7cc2c76d73e0f27ee52abbd64eec84d46f370c88371120433196934e4b7f" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_bytes" +version = "0.11.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ab33ec92f677585af6d88c65593ae2375adde54efdbf16d597f2cbc7a6d368ff" +dependencies = [ + "serde", +] + +[[package]] +name = "serde_derive" +version = "1.0.188" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4eca7ac642d82aa35b60049a6eccb4be6be75e599bd2e9adb5f875a737654af2" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "serial_test" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0e56dd856803e253c8f298af3f4d7eb0ae5e23a737252cd90bb4f3b435033b2d" +dependencies = [ + "dashmap", + "futures", + "lazy_static", + "log", + "parking_lot", + "serial_test_derive", +] + +[[package]] +name = "serial_test_derive" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "91d129178576168c589c9ec973feedf7d3126c01ac2bf08795109aa35b69fb8f" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "sev" +version = "1.2.1" +dependencies = [ + "bincode", + "bitfield", + "bitflags 1.3.2", + "byteorder", + "codicon", + "dirs", + "hex", + "iocuddle", + "kvm-bindings", + "kvm-ioctls", + "lazy_static", + "libc", + "openssl", + "p384", + "rsa", + "serde", + "serde-big-array", + "serde_bytes", + "serial_test", + "sha2", + "static_assertions", + "uuid", + "x509-cert", +] + +[[package]] +name = "sha2" +version = "0.10.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "793db75ad2bcafc3ffa7c68b215fee268f537982cd901d132f89c6343f3a3dc8" +dependencies = [ + "cfg-if", + "cpufeatures", + "digest", +] + +[[package]] +name = "signature" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e1788eed21689f9cf370582dfc467ef36ed9c707f073528ddafa8d83e3b8500" +dependencies = [ + "digest", + "rand_core", +] + +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + +[[package]] +name = "smallvec" +version = "1.11.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "942b4a808e05215192e39f4ab80813e599068285906cc91aa64f923db842bd5a" + +[[package]] +name = "spin" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" + +[[package]] +name = "spki" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9d1e996ef02c474957d681f1b05213dfb0abab947b446a62d37770b23500184a" +dependencies = [ + "base64ct", + "der", +] + +[[package]] +name = "static_assertions" +version = "1.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a2eb9349b6444b326872e140eb1cf5e7c522154d69e7a0ffb0fb81c06b37543f" + +[[package]] +name = "subtle" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "81cdd64d312baedb58e21336b31bc043b77e01cc99033ce76ef539f78e965ebc" + +[[package]] +name = "syn" +version = "2.0.37" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7303ef2c05cd654186cb250d29049a24840ca25d2747c25c0381c8d9e2f582e8" +dependencies = [ + "proc-macro2", + "quote", + "unicode-ident", +] + +[[package]] +name = "thiserror" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1177e8c6d7ede7afde3585fd2513e611227efd6481bd78d2e82ba1ce16557ed4" +dependencies = [ + "thiserror-impl", +] + +[[package]] +name = "thiserror-impl" +version = "1.0.49" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "10712f02019e9288794769fba95cd6847df9874d49d871d062172f9dd41bc4cc" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + +[[package]] +name = "typenum" +version = "1.17.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "42ff0bf0c66b8238c6f3b578df37d0b7848e55df8577b3f74f92a69acceeb825" + +[[package]] +name = "unicode-ident" +version = "1.0.12" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3354b9ac3fae1ff6755cb6db53683adb661634f67557942dea4facebec0fee4b" + +[[package]] +name = "uuid" +version = "1.4.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "79daa5ed5740825c40b389c5e50312b9c86df53fccd33f281df655642b43869d" +dependencies = [ + "serde", +] + +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + +[[package]] +name = "version_check" +version = "0.9.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" + +[[package]] +name = "vmm-sys-util" +version = "0.11.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "48b7b084231214f7427041e4220d77dfe726897a6d41fddee450696e66ff2a29" +dependencies = [ + "bitflags 1.3.2", + "libc", +] + +[[package]] +name = "wasi" +version = "0.11.0+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423" + +[[package]] +name = "windows-sys" +version = "0.48.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "677d2418bec65e3338edb076e806bc1ec15693c5d0104683f2efe857f61056a9" +dependencies = [ + "windows-targets", +] + +[[package]] +name = "windows-targets" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9a2fa6e2155d7247be68c096456083145c183cbbbc2764150dda45a87197940c" +dependencies = [ + "windows_aarch64_gnullvm", + "windows_aarch64_msvc", + "windows_i686_gnu", + "windows_i686_msvc", + "windows_x86_64_gnu", + "windows_x86_64_gnullvm", + "windows_x86_64_msvc", +] + +[[package]] +name = "windows_aarch64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2b38e32f0abccf9987a4e3079dfb67dcd799fb61361e53e2882c3cbaf0d905d8" + +[[package]] +name = "windows_aarch64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dc35310971f3b2dbbf3f0690a219f40e2d9afcf64f9ab7cc1be722937c26b4bc" + +[[package]] +name = "windows_i686_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a75915e7def60c94dcef72200b9a8e58e5091744960da64ec734a6c6e9b3743e" + +[[package]] +name = "windows_i686_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f55c233f70c4b27f66c523580f78f1004e8b5a8b659e05a4eb49d4166cca406" + +[[package]] +name = "windows_x86_64_gnu" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "53d40abd2583d23e4718fddf1ebec84dbff8381c07cae67ff7768bbf19c6718e" + +[[package]] +name = "windows_x86_64_gnullvm" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0b7b52767868a23d5bab768e390dc5f5c55825b6d30b86c844ff2dc7414044cc" + +[[package]] +name = "windows_x86_64_msvc" +version = "0.48.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" + +[[package]] +name = "x509-cert" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25eefca1d99701da3a57feb07e5079fc62abba059fc139e98c13bbb250f3ef29" +dependencies = [ + "const-oid", + "der", + "spki", +] + +[[package]] +name = "zeroize" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2a0956f1ba7c7909bfb66c2e9e4124ab6f6482560f6628b5aaeba39207c9aad9" diff --git a/Cargo.toml b/Cargo.toml index 051dea5b..84589d81 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -30,13 +30,19 @@ maintenance = { status = "actively-developed" } is-it-maintained-issue-resolution = { repository = "virtee/sev" } is-it-maintained-open-issues = { repository = "virtee/sev" } +[lib] +crate-type = ["staticlib", "dylib", "rlib"] +name = 'sev' +path = "src/lib.rs" +doc = false + [features] default = ["sev", "snp","openssl"] hw_tests = [] dangerous_hw_tests = ["hw_tests"] sev = [] snp = [] -capi = [] +crypto_nossl = ["dep:p384", "dep:rsa", "dep:sha2", "dep:x509-cert"] [target.'cfg(target_os = "linux")'.dependencies] iocuddle = "0.1" @@ -56,6 +62,11 @@ bincode = "^1.3" hex = "0.4.3" libc = "0.2.147" lazy_static = "1.4.0" +p384 = { version = "0.13.0", optional = true } +rsa = { version = "0.9.2", optional = true } +sha2 = { version = "0.10.8", optional = true } +x509-cert = { version = "0.2.4", optional = true } +byteorder = "1.4.3" byteorder = "1.4.3" [dev-dependencies] diff --git a/README.md b/README.md index 6cf79f14..43957a23 100644 --- a/README.md +++ b/README.md @@ -24,6 +24,16 @@ Refer to the [`firmware`] module for more information. Refer to the [`launch`] module for more information. +### Cryptographic Verification + +To enable the cryptographic verification of certificate chains and +attestation reports, either the `openssl` or `crypto_nossl` feature +has to be enabled manually. With `openssl`, OpenSSL is used for the +verification. With `crypto_nossl`, OpenSSL is _not_ used for the +verification and instead pure-Rust libraries (e.g., `p384`, `rsa`, +etc.) are used. `openssl` and `crypto_nossl` are mutually exclusive, +and enabling both at the same time leads to a compiler error. + ### Remarks Note that the Linux kernel provides access to these APIs through a set diff --git a/build.sh b/build.sh new file mode 100644 index 00000000..f498c810 --- /dev/null +++ b/build.sh @@ -0,0 +1,14 @@ +#!/bin/sh +set -e + +cd "$(dirname $0)" || exit 1 +src="$(pwd)" +cd - >/dev/null || exit 1 + +if [ ! -d build]; then + # configure a debug build (unoptimized and with debug info) for development + /usr/bin/meson setup build --buildtype=debug +else + # If using containerized build we must reconfigure inside the container. + /usr/bin/meson setup --reconfigure build --buildtype=debug +fi diff --git a/cbindgen.toml b/cbindgen.toml deleted file mode 100644 index 4d6c4430..00000000 --- a/cbindgen.toml +++ /dev/null @@ -1,8 +0,0 @@ -include_guard = "RUST_SEV_FFI_H" -include_version = true -language = "C" -header = "/* C FFI API's for the Rust sev library */" -autogen_warning = "/* Warning, this file is autogenerated by cbindgen. Don't modify this manually. */" - -[export] -item_types = ["functions"] diff --git a/docs/meson.build b/docs/meson.build new file mode 100644 index 00000000..a25c65dd --- /dev/null +++ b/docs/meson.build @@ -0,0 +1,6 @@ +custom_target('sev.3', + command : ['rst2man', '@INPUT@', '@OUTPUT@'], + input : ['sev.rst'], + output : ['sev.3'], + install : true, + install_dir : join_paths(get_option('mandir'), 'man3')) diff --git a/docs/sev.rst b/docs/sev.rst new file mode 100644 index 00000000..7573f6f6 --- /dev/null +++ b/docs/sev.rst @@ -0,0 +1,154 @@ +=== +sev +=== +------------------------- +AMD SEV + SEV-SNP library +------------------------- +:Manual section: 3 + +DESCRIPTION +----------- +NOTE: This documentation only pertains to the C API provided by the AMD SEV Rust +library. For documentation for the Rust portion, please consult the generated +Rust docs here: https://docs.rs/sev/latest/sev/index.html. + +libsev is a library for managing and interacting with the AMD SEV device. It +implements APIs to the launch ioctls usable from the /dev/sev device. + +Error messages +~~~~~~~~~~~~~~ +Functions generally return 0 on success and -1 on failure. Each API requires an +argument ``fw_err``. With a failure, ``fw_err`` will be set to a SEV +firmware-specific error (if applicable). + +Initializing the SEV (and SEV-ES) launch flow +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Given the VM's file descriptor, the sev library will be able to initiate the SEV +launch flow for the guest:: + + int vm_fd = $(VM_FD), fw_err; + + int ret = sev_init(vm_fd, &fw_err); + if (ret != 0) { + fprintf(stderr, "Error initializing the SEV launch flow (fw_err = %d)\n", + fw_err); + return; + } + + int ret = sev_es_init(vm_fd, &fw_err); + if (ret != 0) { + fprintf(stderr, "Error initializing the SEV-ES launch flow (fw_err = %d)\n", + fw_err); + return; + } + + +Beginning the SEV launch flow +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Launch start requires the VM's file descriptor, a SEV policy, certificate chain, +and session buffer:: + + int vm_fd = $(VM_FD), fw_err; + unsigned int policy = 0x3; + unsigned char *cert_bytes = $(CERTIFICATE_BYTES); + unsigned char *session_bytes = $(SEV_LAUNCH_SESSION_BYTES); + + int ret = sev_launch_start(vm_fd, policy, cert_bytes, session_bytes, &fw_err); + if (ret != 0) { + fprintf(stderr, "Error beginning the SEV launch flow (fw_err = %d)\n", + fw_err); + return; + } + +Encrypt a portion of guest memory with SEV +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Updating guest data requires the VM's file descriptor, the guest memory address +of the region to encrypt, and the length of the aforementioned guest region:: + + int vm_fd = $(VM_FD), fw_err; + unsigned long uaddr = $(GUEST_MEM_ADDRESS); + unsigned long size = $(SIZE_OF_GUEST_MEMORY_TO_ENCRYPT); + + int ret = sev_launch_update_data(vm_fd, uaddr, size, &fw_err); + if (ret != 0) { + fprintf(stderr, "Error updating guest address %lu with SEV (fw_err = %d)\n", + uaddr, fw_err); + return; + } + +Encrypt the guest's VMCB save area with its VEK +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Updating guest VMSA requires the VM's file descriptor:: + + int vm_fd = $(VM_FD), fw_err; + + int ret = sev_launch_update_vmsa(vm_fd, &fw_err); + if (ret != 0) { + fprintf(stderr, "Error encrypting the guest VMSA (fw_err = %d)\n", fw_err); + return; + } + +Fetch the meaurement of the launched guest's memory pages and VMCB save area (if +ES is enabled) +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Launch measurement requires the VM's file descriptor and a pre-allocated pointer +to store the measurement data:: + + int vm_fd = $(VM_FD), fw_err; + unsigned char *data; // Must be allocated to fit at least 48 bytes. + + int ret = sev_launch_measure(vm_fd, data, &fw_err); + if (ret != 0) { + fprintf(stderr, "Error fetching guest measurement (fw_err = %d)\n", fw_err); + return; + } + +Inject a secret into the guest +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Launch secret injection requires the VM's file descriptor, pre-allocated buffers +for the header and ciphertext, the size of the ciphertext, and the guest memory +address to inject the secret:: + + int vm_fd = $(VM_FD), fw_err; + void *paddr; // The guest address to inject the secret. + unsigned int ciphertext_sz; // The size of the ciphertext buffer. + unsigned char *header, *ciphertext; // Must be allocated and filled with data. + + int ret = sev_inject_launch_secret(vm_fd, header, ciphertext, ciphertext_sz, + paddr, &fw_err); + if (ret != 0) { + fprintf(stderr, "Error injecting launch secret (fw_err = %d)\n", fw_err); + return; + } + +Finish the launch flow and transition the guest into a state ready to be run +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Launch finish requries the VM's file descriptor:: + + int vm_fd = $(VM_FD), fw_err; + + int ret = sev_launch_finish(vm_fd, &fw_err); + if (ret != 0) { + fprintf(stderr, "Error finishing launch flow (fw_err = %d\n)", fw_err); + return; + } + +Fetch the guest's attestation report +~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ +Launch attestation report fetching requires the VM's file descriptor, a 16-byte +mnonce buffer to include in the report (along with its size), a buffer to store +the attestation report, an argument to store the length of the attestation +report:: + + int vm_fd = $(VM_FD), fw_err; + unsigned char *mnonce; // Contains 16-byte mnonce to include in report. + unsigned char *report_bytes; // Must be pre-allocated to hold >= 208 bytes. + unsigned int len; // API fills with size of attestation report. + + int ret = sev_attestation_report(vm_fd, mnonce, strlen(mnonce), report_bytes, + &len, &fw_err); + if (ret != 0) { + fprintf(stderr, "Error fetching attestation report (fw_err = %d)\n", + fw_err); + return; + } diff --git a/include/libsev.h b/include/libsev.h new file mode 100644 index 00000000..b39ba93d --- /dev/null +++ b/include/libsev.h @@ -0,0 +1,35 @@ +// SPDX-License-Identifier: Apache-2.0 +/* + * AMD SEV, SEV-SNP library + * + * See sev(3) for API documentation. + */ + +#ifndef _RUST_LIBSEV_H +#define _RUST_LIBSEV_H + +#ifdef __cplusplus +extern "C" { +#endif + +int sev_init(int, int, int *); +int sev_es_init(int, int, int *); +int sev_launch_start(int, uint32_t, const void *, const void *, int *); +int sev_launch_update_data(int, uint64_t, uint64_t, int *); +int sev_launch_update_vmsa(int, int *); +int sev_launch_measure(int, unsigned char *, int *); +int sev_inject_launch_secret(int, + const unsigned char *, + const unsigned char *, + uint32_t, + const void *, + int *); +int sev_attestation_report(int, unsigned char *, uint32_t, unsigned char *, + unsigned int *, int *); +int sev_launch_finish(int, int *); + +#ifdef __cplusplus +} +#endif + +#endif /* _RUST_LIBSEV_H */ diff --git a/include/meson.build b/include/meson.build new file mode 100644 index 00000000..cdb33de7 --- /dev/null +++ b/include/meson.build @@ -0,0 +1,2 @@ +inc = include_directories('.') +install_headers('libsev.h') diff --git a/meson.build b/meson.build new file mode 100644 index 00000000..2bf68c39 --- /dev/null +++ b/meson.build @@ -0,0 +1,20 @@ +project('sev', ['c', 'rust'], + meson_version: '>=0.61.0', + license : 'Apache-2.0', + version : run_command(['./package-version.py'], check : true).stdout().strip(), + default_options : ['buildtype=release'], +) + +find_program('cargo', required: true) + +add_project_arguments( + '-D_GNU_SOURCE', + language : 'c', +) + +subdir('docs') +subdir('include') +subdir('src') # requires: include + +sev_dep = declare_dependency(include_directories: inc, + link_with: lib) diff --git a/package-version.py b/package-version.py new file mode 100644 index 00000000..56254ba5 --- /dev/null +++ b/package-version.py @@ -0,0 +1,11 @@ +# SPDX-License-Identifier: Apache-2.0 + +#!/usr/bin/env python3 +import json +import subprocess + +try: + out = subprocess.check_output(["cargo", "read-manifest"]) + print(json.loads(out)["version"]) +except FileNotFoundError: + print("unknown") diff --git a/src/cargo-build.sh b/src/cargo-build.sh new file mode 100644 index 00000000..2ffeb429 --- /dev/null +++ b/src/cargo-build.sh @@ -0,0 +1,57 @@ +#!/bin/bash +set -e + +meson_debug="$1" +meson_optimization="$2" +target_dir="$3" +output="$4" + +args=( --target-dir "${target_dir}" ) +rustflags=() + +case "${meson_debug}" in + true) rustflags+=( -C debuginfo=2 ) ;; + false) rustflags+=( -C debuginfo=0 ) ;; + *) exit 2 ;; +esac + +case "${meson_optimization}" in + plain) + # A release build without explicit optimization flags + profile=release + args+=( --release ) + ;; + 0) + profile=debug + rustflags+=( -C opt-level=0 ) + ;; + 1|2|3|s) + # Use release profile to enable optimization options other than + # opt-level. + profile=release + args+=( --release ) + rustflags+=( -C opt-level="${meson_optimization}" ) + ;; + *) + exit 2 + ;; +esac + +if [[ "${profile}" == "debug" ]] && command -v cargo-clippy >/dev/null; then + ( + cd "$( dirname "$0" )" && + set -x && + RUSTFLAGS="$RUSTFLAGS ${rustflags[*]}" cargo clippy "${args[@]}" \ + --color always --locked --all-features --all-targets --workspace \ + -- --deny warnings + ) +fi + +( + cd "$( dirname "$0" )" && + set -x && + RUSTFLAGS="$RUSTFLAGS ${rustflags[*]}" cargo build "${args[@]}" \ + --color always --locked +) + +cp -u "${target_dir}/${profile}/libsev.a" "${output}" diff --git a/src/certs/snp/builtin/genoa/mod.rs b/src/certs/snp/builtin/genoa/mod.rs index b92edade..2a821159 100644 --- a/src/certs/snp/builtin/genoa/mod.rs +++ b/src/certs/snp/builtin/genoa/mod.rs @@ -10,12 +10,12 @@ pub const ASK: &[u8] = include_bytes!("ask.pem"); /// Get the Genoa ARK Certificate. pub fn ark() -> Result { - Ok(Certificate::from(X509::from_pem(ARK)?)) + Certificate::from_pem(ARK) } /// Get the Genoa ASK Certificate. pub fn ask() -> Result { - Ok(Certificate::from(X509::from_pem(ASK)?)) + Certificate::from_pem(ASK) } mod tests { diff --git a/src/certs/snp/builtin/milan/mod.rs b/src/certs/snp/builtin/milan/mod.rs index 84c03ab1..574db92e 100644 --- a/src/certs/snp/builtin/milan/mod.rs +++ b/src/certs/snp/builtin/milan/mod.rs @@ -10,12 +10,12 @@ pub const ASK: &[u8] = include_bytes!("ask.pem"); /// Get the Milan ARK Certificate. pub fn ark() -> Result { - Ok(Certificate::from(X509::from_pem(ARK)?)) + Certificate::from_pem(ARK) } /// Get the Milan ASK Certificate. pub fn ask() -> Result { - Ok(Certificate::from(X509::from_pem(ASK)?)) + Certificate::from_pem(ASK) } mod tests { diff --git a/src/certs/snp/cert.rs b/src/certs/snp/cert.rs index 072ce357..cde15420 100644 --- a/src/certs/snp/cert.rs +++ b/src/certs/snp/cert.rs @@ -3,10 +3,11 @@ use super::*; use openssl::pkey::{PKey, Public}; +use openssl::x509::X509; /// Structures/interfaces for SEV-SNP certificates. -#[derive(Clone, Debug)] +#[derive(Clone, Debug, Eq, PartialEq)] pub struct Certificate(X509); /// Wrap an X509 struct into a Certificate. diff --git a/src/certs/snp/cert_nossl.rs b/src/certs/snp/cert_nossl.rs new file mode 100644 index 00000000..88aeb1a4 --- /dev/null +++ b/src/certs/snp/cert_nossl.rs @@ -0,0 +1,108 @@ +// SPDX-License-Identifier: Apache-2.0 + +use super::*; + +use der::{referenced::OwnedToRef, Decode, DecodePem, Encode}; +use rsa::signature; // re-export of signature crate +use signature::Verifier; +use spki::ObjectIdentifier; +use std::convert::TryFrom; +use std::io; +use std::io::ErrorKind; +use x509_cert::der; // re-export of der crate +use x509_cert::spki; // re-export of spki crate + +/// Structures/interfaces for SEV-SNP certificates. + +#[derive(Clone, Debug, Eq, PartialEq)] +pub struct Certificate(x509_cert::Certificate); + +const RSA_SSA_PSS_OID: ObjectIdentifier = ObjectIdentifier::new_unwrap("1.2.840.113549.1.1.10"); + +/// Verify if the public key of one Certificate signs another Certificate. +impl Verifiable for (&Certificate, &Certificate) { + type Output = (); + + fn verify(self) -> Result { + let signer = &self.0 .0; + let signee = &self.1 .0; + + if signee.signature_algorithm.oid != RSA_SSA_PSS_OID { + return Err(io_error_other(format!( + "unsupported signature algorithm: {:?}", + signee.signature_algorithm + ))); + } + + let rsa_verifying_key = { + let signer_spki_ref = signer + .tbs_certificate + .subject_public_key_info + .owned_to_ref(); + let signer_pubkey_rsa = rsa::RsaPublicKey::try_from(signer_spki_ref) + .map_err(|e| io_error_other(format!("invalid RSA public key: {e:?}")))?; + rsa::pss::VerifyingKey::::new(signer_pubkey_rsa) + }; + + let message = signee.tbs_certificate.to_der().map_err(|e| { + io_error_other(format!("failed to encode tbs_certificate as DER: {e:?}")) + })?; + + let rsa_signature = rsa::pss::Signature::try_from(signee.signature.raw_bytes()) + .map_err(|e| io_error_other(format!("invalid RSA signature: {e:?}")))?; + + rsa_verifying_key + .verify(&message, &rsa_signature) + .map_err(|e| { + io_error_other(format!( + "Signer certificate does not RSA sign signee certificate: {e}" + )) + }) + } +} + +impl Certificate { + /// Create a Certificate from a PEM-encoded X509 structure. + pub fn from_pem(pem: &[u8]) -> Result { + let cert = x509_cert::Certificate::from_pem(pem) + .map_err(|e| io::Error::new(ErrorKind::InvalidData, format!("invalid PEM: {}", e)))?; + Ok(Self(cert)) + } + + /// Serialize a Certificate struct to PEM. + pub fn to_pem(&self) -> Result> { + use der::EncodePem; + Ok(self + .0 + .to_pem(der::pem::LineEnding::default()) + .map_err(|e| io_error_other(format!("PEM-encoding failed: {}", e)))? + .into_bytes()) + } + + /// Create a Certificate from a DER-encoded X509 structure. + pub fn from_der(der: &[u8]) -> Result { + let cert = x509_cert::Certificate::from_der(der) + .map_err(|e| io::Error::new(ErrorKind::InvalidData, format!("invalid DER: {}", e)))?; + Ok(Self(cert)) + } + + /// Serialize a Certificate struct to DER. + pub fn to_der(&self) -> Result> { + self.0 + .to_der() + .map_err(|e| io_error_other(format!("DER-encoding failed: {e:?}"))) + } + + /// Retrieve the public key in SEC1 encoding. + pub fn public_key_sec1(&self) -> &[u8] { + self.0 + .tbs_certificate + .subject_public_key_info + .subject_public_key + .raw_bytes() + } +} + +fn io_error_other>(error: S) -> io::Error { + io::Error::new(ErrorKind::Other, error.into()) +} diff --git a/src/certs/snp/ecdsa/mod.rs b/src/certs/snp/ecdsa/mod.rs index bf18063f..c582e4d2 100644 --- a/src/certs/snp/ecdsa/mod.rs +++ b/src/certs/snp/ecdsa/mod.rs @@ -1,6 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 -#[cfg(feature = "openssl")] +#[cfg(any(feature = "openssl", feature = "crypto_nossl"))] use super::*; use crate::util::hexdump; @@ -8,7 +8,7 @@ use crate::util::hexdump; #[cfg(feature = "openssl")] use crate::certs::snp::{AsLeBytes, FromLe}; -#[cfg(feature = "openssl")] +#[cfg(any(feature = "openssl", feature = "crypto_nossl"))] use std::convert::TryFrom; use serde::{Deserialize, Serialize}; @@ -32,6 +32,18 @@ pub struct Signature { _reserved: [u8; 512 - R_S_SIZE], } +impl Signature { + /// Returns the signatures `r` component + pub fn r(&self) -> &[u8; 72] { + &self.r + } + + /// Returns the signatures `s` component + pub fn s(&self) -> &[u8; 72] { + &self.s + } +} + impl std::fmt::Debug for Signature { fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result { write!( @@ -109,6 +121,29 @@ impl TryFrom<&Signature> for ecdsa::EcdsaSig { } } +#[cfg(feature = "crypto_nossl")] +impl TryFrom<&Signature> for p384::ecdsa::Signature { + type Error = Error; + + #[inline] + fn try_from(signature: &Signature) -> Result { + let r_big_endian: Vec = signature.r.iter().copied().take(48).rev().collect(); + let s_big_endian: Vec = signature.s.iter().copied().take(48).rev().collect(); + + use p384::elliptic_curve::generic_array::GenericArray; + p384::ecdsa::Signature::from_scalars( + GenericArray::clone_from_slice(&r_big_endian), + GenericArray::clone_from_slice(&s_big_endian), + ) + .map_err(|e| { + Error::new( + ErrorKind::Other, + format!("failed to deserialize signature from scalars: {e:?}"), + ) + }) + } +} + #[cfg(feature = "openssl")] impl TryFrom<&Signature> for Vec { type Error = Error; diff --git a/src/certs/snp/mod.rs b/src/certs/snp/mod.rs index dc27ebb6..73f8524c 100644 --- a/src/certs/snp/mod.rs +++ b/src/certs/snp/mod.rs @@ -3,39 +3,40 @@ /// ECDSA signatures. pub mod ecdsa; -#[cfg(feature = "openssl")] +#[cfg(any(feature = "openssl", feature = "crypto_nossl"))] /// Certificate Authority (CA) certificates. pub mod ca; -#[cfg(feature = "openssl")] +#[cfg(any(feature = "openssl", feature = "crypto_nossl"))] /// Built-in certificates for Milan and Genoa machines. pub mod builtin; #[cfg(feature = "openssl")] mod cert; +#[cfg(feature = "crypto_nossl")] +mod cert_nossl; -#[cfg(feature = "openssl")] +#[cfg(any(feature = "openssl", feature = "crypto_nossl"))] mod chain; #[cfg(feature = "openssl")] pub use cert::Certificate; +#[cfg(feature = "crypto_nossl")] +pub use cert_nossl::Certificate; -#[cfg(feature = "openssl")] +#[cfg(any(feature = "openssl", feature = "crypto_nossl"))] pub use chain::Chain; use std::io::Result; -#[cfg(feature = "openssl")] +#[cfg(any(feature = "openssl", feature = "crypto_nossl"))] use std::io::{Error, ErrorKind}; -#[cfg(feature = "openssl")] -use openssl::x509::X509; - #[cfg(feature = "openssl")] #[allow(dead_code)] struct Body; -#[cfg(feature = "openssl")] +#[cfg(any(feature = "openssl", feature = "crypto_nossl"))] /// An interface for types that may contain entities such as /// signatures that must be verified. pub trait Verifiable { diff --git a/src/error.rs b/src/error.rs index 19c1bf4a..9a91d967 100644 --- a/src/error.rs +++ b/src/error.rs @@ -1,5 +1,6 @@ // SPDX-License-Identifier: Apache-2.0 +use bincode; use bincode; use std::{ array::TryFromSliceError, @@ -9,7 +10,6 @@ use std::{ io, }; -#[cfg(feature = "capi")] use std::os::raw::c_int; /// An error representingthe upper 32 bits of a SW_EXITINFO2 field set by the VMM. @@ -550,7 +550,6 @@ impl From for Indeterminate { } } -#[cfg(feature = "capi")] impl From> for c_int { fn from(err: Indeterminate) -> Self { match err { diff --git a/src/firmware/guest/types/snp.rs b/src/firmware/guest/types/snp.rs index 6764a138..fd501648 100644 --- a/src/firmware/guest/types/snp.rs +++ b/src/firmware/guest/types/snp.rs @@ -2,12 +2,12 @@ use crate::{certs::snp::ecdsa::Signature, firmware::host::TcbVersion, util::hexdump}; -#[cfg(feature = "openssl")] +#[cfg(any(feature = "openssl", feature = "crypto_nossl"))] use crate::certs::snp::{Chain, Verifiable}; use std::fmt::Display; -#[cfg(feature = "openssl")] +#[cfg(any(feature = "openssl", feature = "crypto_nossl"))] use std::{ convert::TryFrom, io::{self, Error, ErrorKind}, @@ -348,6 +348,48 @@ impl Verifiable for (&Chain, &AttestationReport) { } } +#[cfg(feature = "crypto_nossl")] +impl Verifiable for (&Chain, &AttestationReport) { + type Output = (); + + fn verify(self) -> io::Result { + // According to Chapter 3 of the [Versioned Chip Endorsement Key (VCEK) Certificate and + // KDS Interface Specification][spec], the VCEK certificate certifies an ECDSA public key on curve P-384, + // and the signature hash algorithm is sha384. + // [spec]: https://www.amd.com/content/dam/amd/en/documents/epyc-technical-docs/specifications/57230.pdf + + let vcek = self.0.verify()?; + + let sig = p384::ecdsa::Signature::try_from(&self.1.signature)?; + + let measurable_bytes: &[u8] = &bincode::serialize(self.1).map_err(|e| { + Error::new( + ErrorKind::Other, + format!("Unable to serialize bytes: {}", e), + ) + })?[..0x2a0]; + + use sha2::Digest; + let base_digest = sha2::Sha384::new_with_prefix(measurable_bytes); + + let verifying_key = p384::ecdsa::VerifyingKey::from_sec1_bytes(vcek.public_key_sec1()) + .map_err(|e| { + io::Error::new( + ErrorKind::Other, + format!("failed to deserialize public key from sec1 bytes: {e:?}"), + ) + })?; + + use p384::ecdsa::signature::DigestVerifier; + verifying_key.verify_digest(base_digest, &sig).map_err(|e| { + io::Error::new( + ErrorKind::Other, + format!("VCEK does not sign the attestation report: {e:?}"), + ) + }) + } +} + bitfield! { /// The firmware associates each guest with a guest policy that the guest owner provides. The /// firmware restricts what actions the hypervisor can take on this guest according to the guest policy. diff --git a/src/firmware/host/types/sev.rs b/src/firmware/host/types/sev.rs index 555b3a3a..1c0c72ad 100644 --- a/src/firmware/host/types/sev.rs +++ b/src/firmware/host/types/sev.rs @@ -2,8 +2,6 @@ //! Operations for managing the SEV platform. -#[cfg(target_os = "linux")] -pub use crate::firmware::host::Firmware; pub use crate::firmware::linux::host::types::PlatformStatusFlags; use crate::{firmware::host::State, Build}; diff --git a/src/lib.rs b/src/lib.rs index e880ef89..b6b49a59 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -19,6 +19,16 @@ //! //! Refer to the [`launch`] module for more information. //! +//! ## Cryptographic Verification +//! +//! To enable the cryptographic verification of certificate chains and +//! attestation reports, either the `openssl` or `crypto_nossl` feature +//! has to be enabled manually. With `openssl`, OpenSSL is used for the +//! verification. With `crypto_nossl`, OpenSSL is _not_ used for the +//! verification and instead pure-Rust libraries (e.g., `p384`, `rsa`, +//! etc.) are used. `openssl` and `crypto_nossl` are mutually exclusive, +//! and enabling both at the same time leads to a compiler error. +//! //! ## Remarks //! //! Note that the Linux kernel provides access to these APIs through a set @@ -46,6 +56,11 @@ #![allow(clippy::identity_op)] #![allow(clippy::unreadable_literal)] +#[cfg(all(feature = "openssl", feature = "crypto_nossl"))] +compile_error!( + "feature \"openssl\" and feature \"crypto_nossl\" cannot be enabled at the same time" +); + /// SEV and SEV-SNP certificates interface. pub mod certs; @@ -74,10 +89,30 @@ use certs::sev::ca::{Certificate, Chain as CertSevCaChain}; #[cfg(all(feature = "sev", feature = "openssl"))] use certs::sev::builtin as SevBuiltin; +#[cfg(feature = "sev")] +use crate::{certs::sev::sev::Certificate as SevCertificate, error::Indeterminate, launch::sev::*}; + #[cfg(all(feature = "sev", feature = "openssl"))] use std::convert::TryFrom; + use std::io::{Read, Write}; +#[cfg(feature = "sev")] +use std::{ + collections::HashMap, + io, + mem::size_of, + os::{ + fd::RawFd, + raw::{c_int, c_uchar, c_uint, c_void}, + }, + slice::{from_raw_parts, from_raw_parts_mut}, + sync::Mutex, +}; + +#[cfg(feature = "sev")] +use lazy_static::lazy_static; + use serde::{Deserialize, Serialize}; /// Information about the SEV platform version. @@ -246,353 +281,346 @@ impl TryFrom<&sev::Chain> for Generation { } } -/// The C FFI interface to the library. -#[cfg(feature = "capi")] -pub mod capi { - use crate::{certs::sev::sev::Certificate, error::Indeterminate, launch::sev::*}; - - use std::{ - collections::HashMap, - io, - mem::size_of, - os::{ - fd::RawFd, - raw::{c_int, c_uchar, c_ulonglong, c_void}, - }, - slice::{from_raw_parts, from_raw_parts_mut}, - sync::Mutex, - }; - - use lazy_static::lazy_static; - - lazy_static! { - static ref INIT_MAP: Mutex>> = - Mutex::new(HashMap::new()); - static ref STARTED_MAP: Mutex>> = - Mutex::new(HashMap::new()); - static ref MEASURED_MAP: Mutex>> = - Mutex::new(HashMap::new()); - static ref FINISHED_MAP: Mutex>> = - Mutex::new(HashMap::new()); - } +// The C FFI interface to the library. + +#[cfg(feature = "sev")] +lazy_static! { + static ref INIT_MAP: Mutex>> = + Mutex::new(HashMap::new()); + static ref STARTED_MAP: Mutex>> = + Mutex::new(HashMap::new()); + static ref MEASURED_MAP: Mutex>> = + Mutex::new(HashMap::new()); + static ref FINISHED_MAP: Mutex>> = + Mutex::new(HashMap::new()); +} - fn set_fw_err(ptr: *mut c_int, err: io::Error) { - unsafe { *ptr = Indeterminate::from(err).into() }; - } +#[cfg(feature = "sev")] +fn set_fw_err(ptr: *mut c_int, err: io::Error) { + unsafe { *ptr = Indeterminate::from(err).into() }; +} - /// A C FFI interface to the SEV_INIT ioctl. - /// - /// # Safety - /// - /// The caller of this function is responsible for ensuring that the pointer arguments are - /// valid. - #[no_mangle] - pub unsafe extern "C" fn sev_init(vm_fd: c_int, sev_fd: c_int, fw_err: *mut c_int) -> c_int { - let vm: RawFd = vm_fd; - let sev: RawFd = sev_fd; - - match Launcher::new(vm, sev) { - Ok(launcher) => { - let mut map = INIT_MAP.lock().unwrap(); - map.insert(vm_fd, launcher); - - 0 - } - Err(e) => { - set_fw_err(fw_err, e); - -1 - } +/// A C FFI interface to the SEV_INIT ioctl. +/// +/// # Safety +/// +/// The caller of this function is responsible for ensuring that the pointer arguments are +/// valid. +#[cfg(feature = "sev")] +#[no_mangle] +pub unsafe extern "C" fn sev_init(vm_fd: c_int, sev_fd: c_int, fw_err: *mut c_int) -> c_int { + let vm: RawFd = vm_fd; + let sev: RawFd = sev_fd; + + match Launcher::new(vm, sev) { + Ok(launcher) => { + let mut map = INIT_MAP.lock().unwrap(); + map.insert(vm_fd, launcher); + + 0 + } + Err(e) => { + set_fw_err(fw_err, e); + -1 } } +} - /// A C FFI interface to the SEV_ES_INIT ioctl. - /// - /// # Safety - /// - /// The caller of this function is responsible for ensuring that the pointer arguments are - /// valid. - #[no_mangle] - pub unsafe extern "C" fn sev_es_init(vm_fd: c_int, sev_fd: c_int, fw_err: *mut c_int) -> c_int { - let vm: RawFd = vm_fd; - let sev: RawFd = sev_fd; - - match Launcher::new_es(vm, sev) { - Ok(launcher) => { - let mut map = INIT_MAP.lock().unwrap(); - map.insert(vm_fd, launcher); - - 0 - } - Err(e) => { - set_fw_err(fw_err, e); - -1 - } +/// A C FFI interface to the SEV_ES_INIT ioctl. +/// +/// # Safety +/// +/// The caller of this function is responsible for ensuring that the pointer arguments are +/// valid. +#[cfg(feature = "sev")] +#[no_mangle] +pub unsafe extern "C" fn sev_es_init(vm_fd: c_int, sev_fd: c_int, fw_err: *mut c_int) -> c_int { + let vm: RawFd = vm_fd; + let sev: RawFd = sev_fd; + + match Launcher::new_es(vm, sev) { + Ok(launcher) => { + let mut map = INIT_MAP.lock().unwrap(); + map.insert(vm_fd, launcher); + + 0 + } + Err(e) => { + set_fw_err(fw_err, e); + -1 } } +} - /// A C FFI interface to the SEV_LAUNCH_START ioctl. - /// - /// # Safety - /// - /// The caller of this function is responsible for ensuring that the pointer arguments are - /// valid. - #[no_mangle] - pub unsafe extern "C" fn sev_launch_start( - vm_fd: c_int, - policy: u32, - cert_bytes: *const c_void, - session_bytes: *const c_void, - fw_err: *mut c_int, - ) -> c_int { - let mut map = INIT_MAP.lock().unwrap(); - let launcher = match map.remove(&vm_fd) { - Some(l) => l, - None => return -1, - }; +/// A C FFI interface to the SEV_LAUNCH_START ioctl. +/// +/// # Safety +/// +/// The caller of this function is responsible for ensuring that the pointer arguments are +/// valid. +#[cfg(feature = "sev")] +#[no_mangle] +pub unsafe extern "C" fn sev_launch_start( + vm_fd: c_int, + policy: u32, + cert_bytes: *const c_void, + session_bytes: *const c_void, + fw_err: *mut c_int, +) -> c_int { + let mut map = INIT_MAP.lock().unwrap(); + let launcher = match map.remove(&vm_fd) { + Some(l) => l, + None => return -1, + }; - let policy = Policy::from(policy); - let cert: Certificate = unsafe { *(cert_bytes as *const Certificate) }; - let session: Session = unsafe { *(session_bytes as *const Session) }; + let policy = Policy::from(policy); + let cert: SevCertificate = unsafe { *(cert_bytes as *const SevCertificate) }; + let session: Session = unsafe { *(session_bytes as *const Session) }; - let start = Start { - policy, - cert, - session, - }; + let start = Start { + policy, + cert, + session, + }; - match launcher.start(start) { - Ok(started) => { - let mut map = STARTED_MAP.lock().unwrap(); - if map.insert(vm_fd, started).is_none() { - return 0; - } - -1 - } - Err(e) => { - set_fw_err(fw_err, e); - -1 + match launcher.start(start) { + Ok(started) => { + let mut map = STARTED_MAP.lock().unwrap(); + if map.insert(vm_fd, started).is_none() { + return 0; } + -1 } - } - - /// A C FFI interface to the SEV_LAUNCH_UPDATE ioctl. - /// - /// # Safety - /// - /// The caller of this function is responsible for ensuring that the pointer arguments are - /// valid. - #[no_mangle] - pub unsafe extern "C" fn sev_launch_update_data( - vm_fd: c_int, - uaddr: u64, - len: u64, - fw_err: *mut c_int, - ) -> c_int { - let mut map = STARTED_MAP.lock().unwrap(); - let launcher = match map.get_mut(&vm_fd) { - Some(l) => l, - None => return -1, - }; - - let slice: &[u8] = unsafe { from_raw_parts(uaddr as *const u8, len as usize) }; - if let Err(e) = launcher.update_data(slice) { + Err(e) => { set_fw_err(fw_err, e); - return -1; + -1 } + } +} + +/// A C FFI interface to the SEV_LAUNCH_UPDATE ioctl. +/// +/// # Safety +/// +/// The caller of this function is responsible for ensuring that the pointer arguments are +/// valid. +#[cfg(feature = "sev")] +#[no_mangle] +pub unsafe extern "C" fn sev_launch_update_data( + vm_fd: c_int, + uaddr: u64, + len: u64, + fw_err: *mut c_int, +) -> c_int { + let mut map = STARTED_MAP.lock().unwrap(); + let launcher = match map.get_mut(&vm_fd) { + Some(l) => l, + None => return -1, + }; - 0 + let slice: &[u8] = unsafe { from_raw_parts(uaddr as *const u8, len as usize) }; + if let Err(e) = launcher.update_data(slice) { + set_fw_err(fw_err, e); + return -1; } - /// A C FFI interface to the SEV_LAUNCH_UPDATE_VMSA ioctl. - /// - /// # Safety - /// - /// The caller of this function is responsible for ensuring that the pointer arguments are - /// valid. - #[no_mangle] - pub unsafe extern "C" fn sev_launch_update_vmsa(vm_fd: c_int, fw_err: *mut c_int) -> c_int { - let mut map = STARTED_MAP.lock().unwrap(); - let launcher = match map.get_mut(&vm_fd) { - Some(l) => l, - None => return -1, - }; + 0 +} - if let Err(e) = launcher.update_vmsa() { - set_fw_err(fw_err, e); - return -1; - } +/// A C FFI interface to the SEV_LAUNCH_UPDATE_VMSA ioctl. +/// +/// # Safety +/// +/// The caller of this function is responsible for ensuring that the pointer arguments are +/// valid. +#[cfg(feature = "sev")] +#[no_mangle] +pub unsafe extern "C" fn sev_launch_update_vmsa(vm_fd: c_int, fw_err: *mut c_int) -> c_int { + let mut map = STARTED_MAP.lock().unwrap(); + let launcher = match map.get_mut(&vm_fd) { + Some(l) => l, + None => return -1, + }; - 0 + if let Err(e) = launcher.update_vmsa() { + set_fw_err(fw_err, e); + return -1; } - /// A C FFI interface to the SEV_LAUNCH_MEASURE ioctl. - /// - /// # Safety - /// - /// The caller of this function is responsible for ensuring that the pointer arguments are - /// valid. - /// - /// The "measurement_data" argument should be a valid pointer able to hold the meausurement's - /// bytes. The measurement is 48 bytes in size. - #[no_mangle] - pub unsafe extern "C" fn sev_launch_measure( - vm_fd: c_int, - measurement_data: *mut c_uchar, - fw_err: &mut c_int, - ) -> c_int { - let mut map = STARTED_MAP.lock().unwrap(); - let launcher = match map.remove(&vm_fd) { - Some(l) => l, - None => return -1, - }; + 0 +} - match launcher.measure() { - Ok(m) => { - let mut map = MEASURED_MAP.lock().unwrap(); - let measure = m.measurement(); - let slice: &mut [u8] = unsafe { - from_raw_parts_mut( - (&measure as *const Measurement) as *mut u8, - size_of::(), - ) - }; - map.insert(vm_fd, m); - - libc::memcpy( - measurement_data as _, - slice.as_ptr() as _, +/// A C FFI interface to the SEV_LAUNCH_MEASURE ioctl. +/// +/// # Safety +/// +/// The caller of this function is responsible for ensuring that the pointer arguments are +/// valid. +/// +/// The "measurement_data" argument should be a valid pointer able to hold the meausurement's +/// bytes. The measurement is 48 bytes in size. +#[cfg(feature = "sev")] +#[no_mangle] +pub unsafe extern "C" fn sev_launch_measure( + vm_fd: c_int, + measurement_data: *mut c_uchar, + fw_err: &mut c_int, +) -> c_int { + let mut map = STARTED_MAP.lock().unwrap(); + let launcher = match map.remove(&vm_fd) { + Some(l) => l, + None => return -1, + }; + + match launcher.measure() { + Ok(m) => { + let mut map = MEASURED_MAP.lock().unwrap(); + let measure = m.measurement(); + let slice: &mut [u8] = unsafe { + from_raw_parts_mut( + (&measure as *const Measurement) as *mut u8, size_of::(), - ); + ) + }; + map.insert(vm_fd, m); - 0 - } - Err(e) => { - set_fw_err(fw_err, e); + libc::memcpy( + measurement_data as _, + slice.as_ptr() as _, + size_of::(), + ); - -1 - } + 0 + } + Err(e) => { + set_fw_err(fw_err, e); + + -1 } } +} - /// A C FFI interface to the SEV_LAUNCH_SECRET ioctl. - /// - /// # Safety - /// - /// The caller of this function is responsible for ensuring that the pointer arguments are - /// valid. - #[no_mangle] - pub unsafe extern "C" fn sev_inject_launch_secret( - vm_fd: c_int, - header_bytes: *const c_uchar, - ct_bytes: *const c_uchar, - ct_size: u32, - paddr: *const c_void, - fw_err: *mut c_int, - ) -> c_int { - let mut map = MEASURED_MAP.lock().unwrap(); - let launcher = match map.get_mut(&vm_fd) { - Some(l) => l, - None => return -1, - }; +/// A C FFI interface to the SEV_LAUNCH_SECRET ioctl. +/// +/// # Safety +/// +/// The caller of this function is responsible for ensuring that the pointer arguments are +/// valid. +#[cfg(feature = "sev")] +#[no_mangle] +pub unsafe extern "C" fn sev_inject_launch_secret( + vm_fd: c_int, + header_bytes: *const c_uchar, + ct_bytes: *const c_uchar, + ct_size: u32, + paddr: *const c_void, + fw_err: *mut c_int, +) -> c_int { + let mut map = MEASURED_MAP.lock().unwrap(); + let launcher = match map.get_mut(&vm_fd) { + Some(l) => l, + None => return -1, + }; - let header = header_bytes as *const Header; - let ciphertext = { - let bytes: &[u8] = unsafe { from_raw_parts(ct_bytes, ct_size as usize) }; + let header = header_bytes as *const Header; + let ciphertext = { + let bytes: &[u8] = unsafe { from_raw_parts(ct_bytes, ct_size as usize) }; - bytes.to_owned().to_vec() - }; + bytes.to_owned().to_vec() + }; - let secret = Secret { - header: unsafe { *header }, - ciphertext, - }; + let secret = Secret { + header: unsafe { *header }, + ciphertext, + }; - match launcher.inject(&secret, paddr as usize) { - Ok(()) => 0, - Err(e) => { - set_fw_err(fw_err, e); - -1 - } + match launcher.inject(&secret, paddr as usize) { + Ok(()) => 0, + Err(e) => { + set_fw_err(fw_err, e); + -1 } } +} - /// A C FFI interface to the SEV_LAUNCH_FINISH ioctl. - /// - /// # Safety - /// - /// The caller of this function is responsible for ensuring that the mnonce is 16 bytes in - /// size. - /// - /// The caller of this function is responsible for ensuring that the pointer arguments are - /// valid. - #[no_mangle] - pub unsafe extern "C" fn sev_launch_finish(vm_fd: c_int, fw_err: *mut c_int) -> c_int { - let mut map = MEASURED_MAP.lock().unwrap(); - let launcher = match map.remove(&vm_fd) { - Some(l) => l, - None => return -1, - }; +/// A C FFI interface to the SEV_LAUNCH_FINISH ioctl. +/// +/// # Safety +/// +/// The caller of this function is responsible for ensuring that the mnonce is 16 bytes in +/// size. +/// +/// The caller of this function is responsible for ensuring that the pointer arguments are +/// valid. +#[cfg(feature = "sev")] +#[no_mangle] +pub unsafe extern "C" fn sev_launch_finish(vm_fd: c_int, fw_err: *mut c_int) -> c_int { + let mut map = MEASURED_MAP.lock().unwrap(); + let launcher = match map.remove(&vm_fd) { + Some(l) => l, + None => return -1, + }; - match launcher.finish_attestable() { - Ok(l) => { - let mut map = FINISHED_MAP.lock().unwrap(); - map.insert(vm_fd, l); + match launcher.finish_attestable() { + Ok(l) => { + let mut map = FINISHED_MAP.lock().unwrap(); + map.insert(vm_fd, l); - 0 - } - Err(e) => { - set_fw_err(fw_err, e); - -1 - } + 0 + } + Err(e) => { + set_fw_err(fw_err, e); + -1 } } +} - /// A C FFI interface to the SEV_ATTESTATION_REPORT ioctl. - /// - /// # Safety - /// - /// The caller of this function is responsible for ensuring that the pointer arguments are - /// valid. - #[allow(unused_assignments)] - #[no_mangle] - pub unsafe extern "C" fn sev_attestation_report( - vm_fd: c_int, - mnonce: *const c_uchar, - mnonce_len: u32, - mut bytes: *mut c_uchar, - len: *mut c_ulonglong, - fw_err: *mut c_int, - ) -> c_int { - let mut map = FINISHED_MAP.lock().unwrap(); - let launcher = match map.get_mut(&vm_fd) { - Some(l) => l, - None => return -1, - }; +/// A C FFI interface to the SEV_ATTESTATION_REPORT ioctl. +/// +/// # Safety +/// +/// The caller of this function is responsible for ensuring that the pointer arguments are +/// valid. +#[cfg(feature = "sev")] +#[allow(unused_assignments)] +#[no_mangle] +pub unsafe extern "C" fn sev_attestation_report( + vm_fd: c_int, + mnonce: *const c_uchar, + mnonce_len: u32, + mut bytes: *mut c_uchar, + len: *mut c_uint, + fw_err: *mut c_int, +) -> c_int { + let mut map = FINISHED_MAP.lock().unwrap(); + let launcher = match map.get_mut(&vm_fd) { + Some(l) => l, + None => return -1, + }; - if mnonce_len != 16 { - return -1; - } + if mnonce_len != 16 { + return -1; + } - let m: &[u8] = from_raw_parts(mnonce, 16); + let m: &[u8] = from_raw_parts(mnonce, 16); - let mut mnonce_cpy = [0u8; 16]; - mnonce_cpy.copy_from_slice(m); + let mut mnonce_cpy = [0u8; 16]; + mnonce_cpy.copy_from_slice(m); - match launcher.report(mnonce_cpy) { - Ok(r) => { - *len = r.len() as _; - bytes = libc::malloc(r.len()) as *mut c_uchar; + match launcher.report(mnonce_cpy) { + Ok(r) => { + *len = r.len() as _; + bytes = libc::malloc(r.len()) as *mut c_uchar; - libc::memcpy(bytes as _, r.as_ptr() as _, r.len()); + libc::memcpy(bytes as _, r.as_ptr() as _, r.len()); - 0 - } - Err(e) => { - set_fw_err(fw_err, e); - -1 - } - }; + 0 + } + Err(e) => { + set_fw_err(fw_err, e); + -1 + } + }; - -1 - } + -1 } diff --git a/src/meson.build b/src/meson.build new file mode 100644 index 00000000..30bfe49f --- /dev/null +++ b/src/meson.build @@ -0,0 +1,28 @@ +cargo_build = find_program('cargo-build.sh') + +v = meson.project_version().split('.') + +staticlib_name = 'libsev.a' + +staticlib_target = custom_target(staticlib_name, + build_by_default : true, + build_always_stale : true, + command : [cargo_build, get_option('debug').to_string(), + get_option('optimization'), meson.current_build_dir() / 'target', + '@OUTPUT@'], + console : true, + output : [staticlib_name]) + +math = meson.get_compiler('c').find_library('m', required: true) + +lib = library('sev', + link_whole: staticlib_target, + dependencies: [math], + install: true, + soversion: meson.project_version()) + +# generate pkg-config file + +import('pkgconfig').generate(libraries : ['-lsev'], + name : 'sev', + description : 'AMD SEV library') diff --git a/tests/certs.rs b/tests/certs.rs index a5e60cf0..f193a334 100644 --- a/tests/certs.rs +++ b/tests/certs.rs @@ -22,18 +22,14 @@ mod sev { } } -#[cfg(feature = "snp")] +#[cfg(all(feature = "snp", any(feature = "openssl", feature = "crypto_nossl")))] mod snp { - #[cfg(feature = "openssl")] use sev::certs::snp::{builtin::milan, ca, Certificate, Chain, Verifiable}; - #[cfg(feature = "openssl")] const TEST_MILAN_VCEK_DER: &[u8] = include_bytes!("certs_data/vcek_milan.der"); - #[cfg(feature = "openssl")] const TEST_MILAN_ATTESTATION_REPORT: &[u8] = include_bytes!("certs_data/report_milan.hex"); - #[cfg(feature = "openssl")] #[test] fn milan_chain() { let ark = milan::ark().unwrap(); @@ -42,12 +38,31 @@ mod snp { let ca = ca::Chain { ark, ask }; + let chain = Chain { + ca, + vcek: vcek.clone(), + }; + + assert_eq!(chain.verify().ok(), Some(&vcek)); + } + + #[test] + fn milan_chain_invalid() { + let ark = milan::ark().unwrap(); + let ask = milan::ask().unwrap(); + let vcek = { + let mut buf = TEST_MILAN_VCEK_DER.to_vec(); + buf[40] ^= 0xff; + Certificate::from_der(&buf).unwrap() + }; + + let ca = ca::Chain { ark, ask }; + let chain = Chain { ca, vcek }; - chain.verify().unwrap(); + assert_eq!(chain.verify().ok(), None); } - #[cfg(feature = "openssl")] #[test] fn milan_report() { use sev::firmware::guest::AttestationReport; @@ -64,6 +79,26 @@ mod snp { let report: AttestationReport = unsafe { std::ptr::read(report_bytes.as_ptr() as *const _) }; - (&chain, &report).verify().unwrap(); + assert_eq!((&chain, &report).verify().ok(), Some(())); + } + + #[test] + fn milan_report_invalid() { + use sev::firmware::guest::AttestationReport; + + let ark = milan::ark().unwrap(); + let ask = milan::ask().unwrap(); + let vcek = Certificate::from_der(TEST_MILAN_VCEK_DER).unwrap(); + + let ca = ca::Chain { ark, ask }; + + let chain = Chain { ca, vcek }; + + let mut report_bytes = hex::decode(TEST_MILAN_ATTESTATION_REPORT).unwrap(); + report_bytes[0] ^= 0x80; + let report: AttestationReport = + unsafe { std::ptr::read(report_bytes.as_ptr() as *const _) }; + + assert_eq!((&chain, &report).verify().ok(), None); } }