diff --git a/README.md b/README.md index c9352a68feec9ead3561de185ae1eb8e48fa8a4b..a9558a82f4fb0bd207b022cdef85984062a9af68 100644 --- a/README.md +++ b/README.md @@ -41,7 +41,7 @@ We have observed several projects aiming to address these challenges. 1. RPM/SRPM signature. 2. Detached PGP signature including ISO checksum and repo metadata. 3. Kernel module signature. - 4. EFI(todo). + 4. EFI. 5. Container Image(todo). 6. WSL Image(todo). 7. AppImage(todo). @@ -92,6 +92,11 @@ This project consists of several binaries: 3. **control-admin**: the control-admin is mainly used in develop environment for convenience, i.e. generate administrator and tokens without the integration of external OIDC server. 4. **client**: the client is responsible for handle signing task locally and will exchange signature with data server. +# Documents on sign/verify specific files +1. [RPM/SRPM file]() +2. [Kernel module file](./docs/how%20to%20sign%20kernelmodule%20file.md) +3. [EFI file](./docs/how%20to%20sign&verify%20a%20EFI%20image.md) + # Quick Start Guide diff --git a/docs/how to sign kernelmodule file.md b/docs/how to sign kernelmodule file.md new file mode 100644 index 0000000000000000000000000000000000000000..6d3385ce2ae5a410b1251bb33dd39affe3be975f --- /dev/null +++ b/docs/how to sign kernelmodule file.md @@ -0,0 +1,146 @@ +# How to sign an KernelModule(ko) file + +## Background + +KernelModule file is a file that can be loaded into the kernel at runtime, it's a binary file that contains the code and data that can be loaded into the kernel and run. And for the security concern we need to sign and verify the KernelModule file to make sure the file was not tampered. +There are two files located in the kernel repository that can be used to sign and verify the KernelModule file, they are `scripts/sign-file.c` and `scripts/extract-module-sig.pl`. +The `sign-file.c` is used to sign the KernelModule file and the `scripts/extract-module-sig.pl` is used to extract the certificate from the signed KernelModule file. + +## Signature Layout +The layout of signed KernelModule file is describe as below: + +![structure](./images/kernel_module_signature.png) + +1. The raw content of kernel module file. +2. The CMS signature, and signature is a DER encoded PKCS#7 structure. The PKCS#7 structure contains the certificate and the signature of the file. +3. The ModuleSignature structure is appended after in the PKCS#7 structure, which contains the information of the signature. +4. The Module Magic string("~Module signature appended~\n"), and it will be appended after the ModuleSignature structure, which is used to identify the signature. + + + +## Sign the KernelModule file with sign-file.c +For Ubuntu, you can locate the sign-file tool with command: +```bash +tommylike@ubuntu  ~  /usr/src/linux-headers-$(uname -r)/scripts/sign-file +Usage: scripts/sign-file [-dp] [] + scripts/sign-file -s [] +``` +sign-file support detached(-pd) and attached(-p) signature, considering you have generated the x509 key and cert, the command would as simple as: +```bash +tommylike@ubuntu  ~  /usr/src/linux-headers-$(uname -r)/scripts/sign-file -dp sha256 new.key new.crt simple.ko +``` +Command used to check the cms signature in text format: +```bash +tommylike@ubuntu  ~/sign-kernelmodule  openssl pkcs7 -in simple.ko.p7s -inform DER -text +-----BEGIN PKCS7----- +MIIBygYJKoZIhvcNAQcCoIIBuzCCAbcCAQExDTALBglghkgBZQMEAgEwCwYJKoZI +hvcNAQcBMYIBlDCCAZACAQEwazBmMQ4wDAYDVQQDDAVpbmZyYTEOMAwGA1UECwwF +SW5mcmExDzANBgNVBAoMBkh1YXdlaTERMA8GA1UEBwwIU2hlblpoZW4xEzARBgNV +BAgMCkd1YW5nIERvbmcxCzAJBgNVBAYTAkNOAgEAMAsGCWCGSAFlAwQCATANBgkq +hkiG9w0BAQEFAASCAQBqyJT0Ibos7e38AM6ni5QYhkgwcMAYJV9MoOTX7MH3onhu +SBw1y1wpO1TIHonhmuRkc9Jqw5lVzaB2kvyHBOfwZBGZJ5BVqSJwq+KEU7e3uIQr +nm4/6mOPY+GS5khaq92b5k7Oq/iDPirD0Wle6dqSu6/0i0oEVUzvdEOwY9J6NK38 +7EoP6RvN8YFm2rwxK9meaj8tWLsRdxtdiHscov/ZX/2TWV4VGRBAgzK5IdvfaTU6 +yVr45nWbamXzgYXpI1Eb7sr5pZXnkk48SjNt+9uNku5eL0OthPx9n0VTlZ4gc+sD +8SPZGyjWyn+VvQlSrGaT/XD49e2sWqeJ/RvP0bqN +-----END PKCS7----- +``` +or in ASN.1 format: +```bash +tommylike@ubuntu  ~/sign-kernelmodule  openssl asn1parse -inform der -in simple.ko.p7s + 0:d=0 hl=4 l= 458 cons: SEQUENCE + 4:d=1 hl=2 l= 9 prim: OBJECT :pkcs7-signedData + 15:d=1 hl=4 l= 443 cons: cont [ 0 ] + 19:d=2 hl=4 l= 439 cons: SEQUENCE + 23:d=3 hl=2 l= 1 prim: INTEGER :01 + 26:d=3 hl=2 l= 13 cons: SET + 28:d=4 hl=2 l= 11 cons: SEQUENCE + 30:d=5 hl=2 l= 9 prim: OBJECT :sha256 + 41:d=3 hl=2 l= 11 cons: SEQUENCE + 43:d=4 hl=2 l= 9 prim: OBJECT :pkcs7-data + 54:d=3 hl=4 l= 404 cons: SET + 58:d=4 hl=4 l= 400 cons: SEQUENCE + 62:d=5 hl=2 l= 1 prim: INTEGER :01 + 65:d=5 hl=2 l= 107 cons: SEQUENCE + 67:d=6 hl=2 l= 102 cons: SEQUENCE + 69:d=7 hl=2 l= 14 cons: SET + 71:d=8 hl=2 l= 12 cons: SEQUENCE + 73:d=9 hl=2 l= 3 prim: OBJECT :commonName + 78:d=9 hl=2 l= 5 prim: UTF8STRING :infra + 85:d=7 hl=2 l= 14 cons: SET + 87:d=8 hl=2 l= 12 cons: SEQUENCE + 89:d=9 hl=2 l= 3 prim: OBJECT :organizationalUnitName + 94:d=9 hl=2 l= 5 prim: UTF8STRING :Infra + 101:d=7 hl=2 l= 15 cons: SET + 103:d=8 hl=2 l= 13 cons: SEQUENCE + 105:d=9 hl=2 l= 3 prim: OBJECT :organizationName + 110:d=9 hl=2 l= 6 prim: UTF8STRING :Huawei + 118:d=7 hl=2 l= 17 cons: SET + 120:d=8 hl=2 l= 15 cons: SEQUENCE + 122:d=9 hl=2 l= 3 prim: OBJECT :localityName + 127:d=9 hl=2 l= 8 prim: UTF8STRING :ShenZhen + 137:d=7 hl=2 l= 19 cons: SET + 139:d=8 hl=2 l= 17 cons: SEQUENCE + 141:d=9 hl=2 l= 3 prim: OBJECT :stateOrProvinceName + 146:d=9 hl=2 l= 10 prim: UTF8STRING :Guang Dong + 158:d=7 hl=2 l= 11 cons: SET + 160:d=8 hl=2 l= 9 cons: SEQUENCE + 162:d=9 hl=2 l= 3 prim: OBJECT :countryName + 167:d=9 hl=2 l= 2 prim: PRINTABLESTRING :CN + 171:d=6 hl=2 l= 1 prim: INTEGER :00 + 174:d=5 hl=2 l= 11 cons: SEQUENCE + 176:d=6 hl=2 l= 9 prim: OBJECT :sha256 + 187:d=5 hl=2 l= 13 cons: SEQUENCE + 189:d=6 hl=2 l= 9 prim: OBJECT :rsaEncryption + 200:d=6 hl=2 l= 0 prim: NULL + 202:d=5 hl=4 l= 256 prim: OCTET STRING [HEX DUMP]:6AC894F421BA2CEDEDFC00CEA78B941886483070C018255F4CA0E4D7ECC1F7A2786E481C35CB5C293B54C81E89E19AE46473D26AC39955CDA07692FC8704E7F0641199279055A92270ABE28453B7B7B8842B9E6E3FEA638F63E192E6485AABDD9BE64ECEABF8833E2AC3D1695EE9DA92BBAFF48B4A04554CEF7443B063D27A34ADFCEC4A0FE91BCDF18166DABC312BD99E6A3F2D58BB11771B5D887B1CA2FFD95FFD93595E151910408332B921DBDF69353AC95AF8E6759B6A65F38185E923511BEECAF9A595E7924E3C4A336DFBDB8D92EE5E2F43AD84FC7D9F4553959E2073EB03F123D91B28D6CA7F95BD0952AC6693FD70F8F5EDAC5AA789FD1BCFD1BA8D +``` + +## Sign the KernelModule file with signatrust +Signatrust support sign KernelModule file within the command as following: +```bash + RUST_BACKTRACE=full RUST_LOG=debug ./target/debug/client --config /path/to/client.toml add --key-id default-x509 --file-type kernel-module --key-type x509 .data/simple.ko +``` +Signatrust supports to resign a signed KernelModule file, that's to say instead of append the cert and metadata at the end of file, signatrust will try to parse the kernel module file and replace the signature when resigning. +if you add the `--detached` flag, the signature will be detached from the file as `sign-file` tool, and the signature will be output to the file with the same name as the file to be signed, but with the extension .p7s appended to the file name. +```bash + RUST_BACKTRACE=full RUST_LOG=debug ./target/debug/client --config /path/to/client.toml add --key-id default-x509 --file-type kernel-module --key-type x509 --detached .data/simple.ko +``` + +## Verify the Signature of KernelModule file +In order to verify the signature of KernelModule file, you need to extract the signature from the file first, and then verify the signature with the extracted signature and the original file. +1. Download the certificate from signatrust control-server and save into local file(new.cert as below) in pem format: +```shell +curl -X 'POST' \ + 'https://localhost:8080/api/v1/keys//export' \ + -H 'accept: application/json' \ + -H 'Authorization: cBnLPLXl1fA7fKDZnjg9fd9dSWw2RXtUH3MGFUtq' \ + -d '' +``` +2. Extract the signature from the KernelModule file or use detached signature(.p7s) +```bash + tommylike@ubuntu  ~/sign-kernelmodule  perl extract-module-sig.pl -s simple.ko > detached.p7s +perl: warning: Setting locale failed. +perl: warning: Please check that your locale settings: + LANGUAGE = (unset), + LC_ALL = (unset), + LC_TERMINAL = "iTerm2", + LC_CTYPE = "UTF-8", + LANG = "en_US.UTF-8" + are supported and installed on your system. +perl: warning: Falling back to a fallback locale ("en_US.UTF-8"). +Read 15805 bytes from module file +Found magic number at 15805 +Found PKCS#7/CMS encapsulation +Found 461 bytes of signature [308201c906092a864886f70d010702a0] +``` +3. Verify the signature +```bash +openssl smime -verify -binary -inform DER -in detached.p7s -content simple.ko -certfile new.crt -nointern -noverify +...... +...... +Verification successful +``` + + + diff --git a/docs/how to sign&verify a EFI image.md b/docs/how to sign&verify a EFI image.md index 03a40fc3fecbd293184071c6ffb5b5e978f1988d..e38a3c03619063572dba3d62adff0651fdfc180a 100644 --- a/docs/how to sign&verify a EFI image.md +++ b/docs/how to sign&verify a EFI image.md @@ -1,5 +1,7 @@ -# prerequisite -- create a x509 key in data server if you do not have one +# Background +For the background of EFI signature, please refer to [this](how%20to%20sign%20EFI%20file.md) document. +# Prerequisite +- Create a x509 key in data server if you do not have one ```bash curl -X 'POST' \ 'http://10.0.0.139:8080/api/v1/keys/' \ @@ -24,7 +26,7 @@ "name": "my-x509" }' ``` -- export the x509 certificate into PEM format +- Export the x509 certificate into PEM format - get the key id ``` curl -X 'GET' \ @@ -123,12 +125,12 @@ -----END CERTIFICATE----- ``` -# sign a EFI file +# Sign a EFI file ``` RUST_BACKTRACE=1 RUST_LOG=debug ./target/debug/client -c client.toml add --file-type efi-image --key-type x509 --key-name my-x509 --sign-type authenticode `pwd`/shimx64.efi ``` -# verify the EFI file +# Verify the EFI file - first we should compile `sbsigntools` ``` git clone https://git.kernel.org/pub/scm/linux/kernel/git/jejb/sbsigntools.git diff --git a/docs/images/kernel_module_signature.png b/docs/images/kernel_module_signature.png new file mode 100644 index 0000000000000000000000000000000000000000..89fd24b3f7f57ed4082e494bb5c7489cae4dc171 Binary files /dev/null and b/docs/images/kernel_module_signature.png differ diff --git a/src/client/file_handler/kernel_module.rs b/src/client/file_handler/kernel_module.rs index 27c318992ac07a3ee7af242d3e3266f0aa4b72f4..5d7c77808cf4c7459b6b851c6037bf7da7c4b441 100644 --- a/src/client/file_handler/kernel_module.rs +++ b/src/client/file_handler/kernel_module.rs @@ -98,7 +98,7 @@ impl KernelModuleFileHandler { Ok(()) } - pub fn get_raw_content(&self, path: &PathBuf) -> Result> { + pub fn get_raw_content(&self, path: &PathBuf, sign_options: &mut HashMap) -> Result> { let raw_content = fs::read(path)?; let mut file = fs::File::open(path)?; if file.metadata()?.len() <= MAGIC_NUMBER_SIZE as u64 { @@ -127,6 +127,12 @@ impl KernelModuleFileHandler { "invalid kernel module signature size found".to_owned(), )); } + if let Some(detached) = sign_options.get("detached") { + if detached == "true" { + return Err(Error::SplitFileError( + "already signed kernel module file doesn't support detached signature".to_owned())); + } + } //read raw content Ok(raw_content [0..(raw_content.len() - SIGNATURE_SIZE - signature.sig_len as usize)] @@ -164,13 +170,13 @@ impl FileHandler for KernelModuleFileHandler { Ok(()) } - //NOTE: currently we don't support sign signed kernel module file + //NOTE: if it's a signed kernel module file, detached option will lead to the failure of verification. async fn split_data( &self, path: &PathBuf, - _sign_options: &mut HashMap, + sign_options: &mut HashMap, ) -> Result>> { - Ok(vec![self.get_raw_content(path)?]) + Ok(vec![self.get_raw_content(path, sign_options)?]) } /* when assemble checksum signature when only create another .asc file separately */