├── .gitmodules ├── LICENSE ├── LICENSE.GPL-2.0-or-later ├── LICENSE.LGPL-2.1-or-later ├── README.md ├── certs ├── ca │ ├── ca_cert.pem │ └── ca_key.pem ├── client │ ├── client_cert.pem │ └── client_key.pem ├── policies │ └── policies ├── server.conf └── server │ ├── server_cert.pem │ └── server_key.pem ├── doc ├── sedcli-kmip.8 └── sedcli.8 ├── etc ├── sedcli │ └── sedcli.conf └── udev │ └── rules.d │ └── 63-sedcli.rules └── src ├── Makefile ├── aliases ├── argp.c ├── argp.h ├── config_file.c ├── config_file.h ├── configure ├── crypto_lib.c ├── crypto_lib.h ├── kmip_lib.c ├── kmip_lib.h ├── lib ├── include │ └── libsed.h ├── nvme_access.c ├── nvme_access.h ├── nvme_pt_ioctl.c ├── nvme_pt_ioctl.h ├── opal_parser.c ├── opal_parser.h ├── sed.c ├── sed_util.c ├── sed_util.h └── sedcli_log.h ├── metadata_serializer.c ├── metadata_serializer.h ├── sedcli_kmip.c ├── sedcli_main.c ├── sedcli_util.c └── sedcli_util.h /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "src/libkmip"] 2 | path = src/libkmip 3 | url = https://github.com/OpenKMIP/libkmip.git 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | sedcli is made available under the terms of GPL-2.0-or-later license. 2 | libsed is made available under the terms of LGPL-2.1-or-later licens. 3 | 4 | Contributions into sedcli are accepted on GPL-2.0-or-later license, 5 | while contributions into libsed are accepted on LGPL-2.1-or-later license. 6 | -------------------------------------------------------------------------------- /LICENSE.GPL-2.0-or-later: -------------------------------------------------------------------------------- 1 | sedcli - utility for management of Self-Encrypting Drives 2 | 3 | Copyright (C) 2018-2019, 2023 Solidigm 4 | 5 | This program is free software; you can redistribute it and/or modify it 6 | under the terms of the GNU General Public License, as published 7 | by the Free Software Foundation; either version 2 of the License, 8 | or (at your option) any later version. 9 | 10 | This program is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU General Public License for more details. 14 | 15 | You should have received a copy of the GNU General Public License 16 | along with this program; if not, see . 17 | 18 | In addition, as a special exception, the copyright holders of sedcli 19 | give you permission to combine sedcli with free software programs or 20 | libraries that are released under the GNU LGPL and with code included 21 | in the standard release of OpenSSL under the OpenSSL license (or modified 22 | versions of such code, with unchanged license). You may copy and distribute 23 | such a system following the terms of the GNU GPL for sedcli and the 24 | licenses of the other code concerned, provided that you include the source 25 | code of that other code when and as the GNU GPL requires distribution of 26 | source code. 27 | 28 | SPDX-License-Identifier: GPL-2.0-or-later 29 | -------------------------------------------------------------------------------- /LICENSE.LGPL-2.1-or-later: -------------------------------------------------------------------------------- 1 | libsed - library allowing programmatic management of Self-Encrypting Drives 2 | 3 | Copyright (C) 2018-2019, 2023 Solidigm 4 | 5 | This library is free software; you can redistribute it and/or modify it 6 | under the terms of the GNU Lesser General Public License as published 7 | by the Free Software Foundation; either version 2.1 of the License, 8 | or (at your option) any later version. 9 | 10 | This library is distributed in the hope that it will be useful, 11 | but WITHOUT ANY WARRANTY; without even the implied warranty of 12 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 | GNU Lesser General Public License for more details. 14 | 15 | You should have received a copy of the GNU Lesser General Public License 16 | along with this library; if not, see . 17 | 18 | In addition, as a special exception, the copyright holders of libsed give 19 | you permission to combine libsed simultaneously with free software programs 20 | or libraries that are released under the GNU GPL (with or without an 21 | exception for OpenSSL's license) and with code included in the standard 22 | release of OpenSSL under the OpenSSL license (or modified versions of such 23 | code, with unchanged license). You may copy and distribute such a system 24 | following the terms of the GNU GPL for libsed and the licenses of the other 25 | code concerned. 26 | 27 | SPDX-License-Identifier: LGPL-2.1-or-later 28 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # sedcli and libsed overview 2 | 3 | TCG Opal is an industry standard allowing Self-Encrypting Drives management, i.e. enable locking, configuring users, locking ranges etc. 4 | 5 | Sedcli is an utility for managing NVMe SEDs that are TCG Opal complaint. 6 | 7 | Libsed is a library allowing to programatically manage NVMe SEDs that are TCG Opal complaint. 8 | 9 | ## Getting started 10 | 11 | In order to get started use following steps (\ denotes top level directory for sedcli): 12 | 13 | ``` 14 | # navigate to source directory 15 | cd /src 16 | 17 | # perform build environment configuration and run compilation 18 | chmod +x ./configure 19 | ./configure 20 | make all 21 | make install 22 | make install-cert 23 | 24 | # invoke sedcli help to available commands and its syntax 25 | sedcli --help 26 | 27 | ``` 28 | For more information goto [doc](doc) directory. 29 | 30 | ## Features 31 | 32 | * Interactive management of NVMe SED allowing to: configure locking, change lock state, revert disk back to manafactured state 33 | * Auto management with disk key being retrieved from network attached Key Management Server that is OASIS KMIP complaint 34 | 35 | ## Talks and papers 36 | 37 | * SNIA SDC 2019: [Data at Rest Protection at Scale with NVMe and Opal](https://www.youtube.com/watch?v=5mmJlNplcAY) 38 | 39 | ## Contributing 40 | 41 | We encourage contributions! Patches are accepted via pull request: 42 | * Contributions into sedcli are accepted on GPL-2.0-or-later license 43 | * Contributions into libsed are accepted on LGPL-2.1-or-later license 44 | 45 | ## Maintainers 46 | 47 | * Piotr Rudnicki 48 | 49 | Feel free to contact us anytime with questions, feedback or suggestions. 50 | We would love to hear how you see sedcli going forward. 51 | -------------------------------------------------------------------------------- /certs/ca/ca_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC7zCCAdegAwIBAgIUSdqtiDmDtVWDqeo4Uo41hqN1M4MwDQYJKoZIhvcNAQEL 3 | BQAwJzETMBEGA1UECgwKVGVzdCwgSW5jLjEQMA4GA1UEAwwHUm9vdCBDQTAeFw0x 4 | OTEwMjIyMDEwMjFaFw0yOTEwMTkyMDEwMjFaMCcxEzARBgNVBAoMClRlc3QsIElu 5 | Yy4xEDAOBgNVBAMMB1Jvb3QgQ0EwggEiMA0GCSqGSIb3DQEBAQUAA4IBDwAwggEK 6 | AoIBAQCsCJCFCwSYCWhEGWQaKjulKp5Rkaq0jCYGgZVeg4ovS1IlNxQHuT9eRArl 7 | rSEHQye7BIhbUci6A9x0YV3d7H4Zc4WgeC6eQVgfq1RjC+LTGnCC1ona3RyDvzpv 8 | PxEK09mJcakZXOiklsHfsbb6CSnikK32eJO4DqXtj0JBSFxyoQFMrUgtNJWY/av9 9 | TLjxwuKZ5loe6NRgZR547NlRRLB8eqMrPfbhCbgJmkzjSAFZX/fFJa5wg5FK9mtQ 10 | 9KiQcMGjJmzs1gifB0zoh6nb/NLnr1FL0J1FoiP6P2A6wu0lQtmPY/7TWa3sMlxk 11 | Ln326f4vozDMlBmPctMqzhlmWomLAgMBAAGjEzARMA8GA1UdEwEB/wQFMAMBAf8w 12 | DQYJKoZIhvcNAQELBQADggEBAJhBDz0VdtvaljfhVJhpkPXMJPOBsIBjKcM+IRwE 13 | Ks14ULOv1HDVd7SXr0CYHuXiy69PexZwBKetq9fyTY66KHoFApfb7b46+pBffQKf 14 | +/rGqHQIirk2H3sxW8bAbQm6TjLZKzar0duh+Bo6VtFkwNSO8rRvRVLcPywiqGsJ 15 | eC/5MAjDHvbpKoWEwHtkTpraa0ikGlF74eHtZJnPdQOtXRLMPcX3CAMOPTQGmfLQ 16 | NumJELRF+i67vCyJUYmbe98SGVDH/IRKkka7iv0BqqQEQA0Sr69hn1CncmvhvSEb 17 | XIGUaLp4ETFt7XJ8/XtTQTzl8BFfYcCV9+7t0LRMvVvLNPc= 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /certs/ca/ca_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvAIBADANBgkqhkiG9w0BAQEFAASCBKYwggSiAgEAAoIBAQCsCJCFCwSYCWhE 3 | GWQaKjulKp5Rkaq0jCYGgZVeg4ovS1IlNxQHuT9eRArlrSEHQye7BIhbUci6A9x0 4 | YV3d7H4Zc4WgeC6eQVgfq1RjC+LTGnCC1ona3RyDvzpvPxEK09mJcakZXOiklsHf 5 | sbb6CSnikK32eJO4DqXtj0JBSFxyoQFMrUgtNJWY/av9TLjxwuKZ5loe6NRgZR54 6 | 7NlRRLB8eqMrPfbhCbgJmkzjSAFZX/fFJa5wg5FK9mtQ9KiQcMGjJmzs1gifB0zo 7 | h6nb/NLnr1FL0J1FoiP6P2A6wu0lQtmPY/7TWa3sMlxkLn326f4vozDMlBmPctMq 8 | zhlmWomLAgMBAAECggEARreOkOIilUzoq3W0jHzn39FRGz7B6U3jI7GI8T0pRJ+1 9 | uM6XUUV5IwrdX+R3O0EDyADo/ID1/mEv8jdEGsHoZBX0zC4bG7rIutv26HAuYZDw 10 | xxfhuzJBUnb9UlWeb9D+D13FoUNr7px6PbYT/Vxe919542NVdcevtaO6HJPeTM/t 11 | ed4CKQ0n0sPUyEeFTOmD7oRa+u/hYyiUYwbmvMnxNEcZtM1ip4QlF7uFrIaJzyyJ 12 | COk/gIQnp7KOIzuy2tjoSOa92+4V50cQJAV8aDHnZmX1eecObFEG/4CI5cxjdjRS 13 | 3bP/aT1dtnqdrijlgS/o8Av8o98229wBeFwKmO2xQQKBgQDhgo5ui4eEZD8FOIuu 14 | dN8p+CRhdB+qmwZQKQeD0E3nVqnIRE88DSwRBoFVpKcVfowG1a6oMZRGmS/XlNHM 15 | L7MQY60vb2U2xWHdxpzSUhDG6KA/NuhgawY6KJYCY4XBZYA6Q9pz2xhiLcVZDiG7 16 | DIIYp59z+2dvXQ65WiIIVjXTgwKBgQDDSw6BYV50EmL5hCIuNqhXSXTytMsZPt7x 17 | ebbK4f+CWezZkpiaeOFfIrdhN5g7lZa0VUXpOiYQKOrSUi8K1yVHaOoHYDYThOlw 18 | sxoCPxh8H8XdIm8OtxzQKC18pSEH/qGoNU/e2NAmHXLdeGy9poF+09/jIgYiZP5f 19 | VSl5DN8rWQKBgHyxgixh/qcX/zjV0Xa/rP459XPlj/T4D3+XkE40ij8Wzn6sNtvP 20 | tMQdQrqmdrUN6kOFODRMZd67qZac9XzgCzVOyF5oTCEC92B4CBLLyfcSfjk2FTvr 21 | MeBKvNfJTBZqF4MgLdTOGyd+g5cAl2okOnODjEnHg6QyYofe7N6LPOwdAoGAKhvd 22 | 9dG73wUz6B8wi4xngeKp38dR35Cp26Fl45sVT9L5+fPdCbm0xqGirsig/4ACrcGR 23 | QHe0S1m3QEBOOmUneZ1KkOqS3mSTPSSxH/jg26qyLDtHfQHIqa1wGWc1lxa1XqKY 24 | JTHUt9MzuENGFyJ225TtunjUn8fs/TtMpPg8iokCgYBE59po5ZxV2qCdqs8QC3bG 25 | 5r2/VXU13Dh7ouqeKVKueQSwJm2bzG4y9nCU/E7EHQtWDH7bpp8cM/6CC6uoHc+F 26 | hQbNlVKd06RhhGHMvgRSQ02xivnTLb0WHBVWIE9Mc5aG7D6acDL2m5UtYBFQQRzU 27 | jZRGCJGXDfdeR20CB+fh3g== 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /certs/client/client_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC9zCCAd+gAwIBAgIUfZHWcBCc1fqyE+EqbO61czGH6TIwDQYJKoZIhvcNAQEL 3 | BQAwJzETMBEGA1UECgwKVGVzdCwgSW5jLjEQMA4GA1UEAwwHUm9vdCBDQTAeFw0x 4 | OTEwMjIyMDEwMjFaFw0yOTEwMTkyMDEwMjFaMCgxEzARBgNVBAoMClRlc3QsIElu 5 | Yy4xETAPBgNVBAMMCEpvaG4gRG9lMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB 6 | CgKCAQEAvDxnK+3qPFaaZE2FJy721WH3dE5LL4tmwVMrPorEMIK149UMowT6ABfn 7 | vaUW3Bo1gr4ycZsL7MCnLzhRh2KcUnOmpLgPusRyVOlrKnvOGut59SSeyq6f3Q37 8 | F1RHm85a3FVGe1LuY9ySpASAViIMaBJr043PbUIYPUFZDQu8g4c/ObSRYuEP1+3T 9 | CbL/O+JBuVYygdbho610KOvyF5O/CzwABlx5ERDYe98rFWLoWWvAdbwxxwczIDVR 10 | KRo9XNHFWJ+EPHaBBHZshzICx3z/wLjcnGI4RS14dXRFEq+F82yhojG/rRmbyyJh 11 | 1iXhJCVZR+eqXM4Yymn9hAQnLSu2PQIDAQABoxowGDAWBgNVHSUBAf8EDDAKBggr 12 | BgEFBQcDAjANBgkqhkiG9w0BAQsFAAOCAQEAbCCcRxr1k0HWLfxrfeNan9A8bf/E 13 | RmHIRg+R7p5Da5WP5AoKKzkVN51fuHKmA5RZneZLSrPjrTNfbfrVyZEDRorCP9jm 14 | wQr1muLA0sm71HeQRJ3R39wZ+tvNs9GIz+pcgBI5jEfMkYjjFfi1v8d0A9pe5/EK 15 | fDAZHKtnI6wCfdu3Kf4a+Eo+fn98wvmWjDySOdnIS9FGNJODtMOPsTfdtHTZMyI2 16 | LlHiKtZ+jodag0SgDmG7p3FSloKwzxsFh6Gy7JBKMPzABJC6Fk/MsyYf8ugQAQH0 17 | J44ek+Zhx8sQOB9YZqEcbbv1hAWhalTjDnGZ7pACwF4J+grbKuJWdjPDdA== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /certs/client/client_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQC8PGcr7eo8Vppk 3 | TYUnLvbVYfd0Tksvi2bBUys+isQwgrXj1QyjBPoAF+e9pRbcGjWCvjJxmwvswKcv 4 | OFGHYpxSc6akuA+6xHJU6Wsqe84a63n1JJ7Krp/dDfsXVEebzlrcVUZ7Uu5j3JKk 5 | BIBWIgxoEmvTjc9tQhg9QVkNC7yDhz85tJFi4Q/X7dMJsv874kG5VjKB1uGjrXQo 6 | 6/IXk78LPAAGXHkRENh73ysVYuhZa8B1vDHHBzMgNVEpGj1c0cVYn4Q8doEEdmyH 7 | MgLHfP/AuNycYjhFLXh1dEUSr4XzbKGiMb+tGZvLImHWJeEkJVlH56pczhjKaf2E 8 | BCctK7Y9AgMBAAECggEAE2y8TNk5Yc6iEhW51uhOyohYi+UEdzyQdwTJIqQZSNRE 9 | RuWWb0A1OEs/O9/Mcxw1R2+vLvAME/txhTrvluQDM7MBkF/6J5DcJ40K5RBvnXGN 10 | XVHRHSNWFe66aZbl6Nsrny8hndpaBW4ep9RbFghfdWHpRKSOsjyu2atjsCf05TGj 11 | OEhg1Kn9iSB1GgdVTFGN7Ve6+F5Iat3JlBcltaqVQk/Bhdn+Hig3uCMhsVJb5kP5 12 | LPRTIVZynJVn7eCkPWxmeu5NVHEx7m30f0fTCUtBSbjIU2uU9fyqt+KCz4EjdFoT 13 | Iv2bybdWJlgWxyJfdJQzjtUIYXw3McFwz9UZcVwqdQKBgQDyyKbUn5Yl0ISV1DqE 14 | P1t4KFXd4EBZ6wkKuINvdUxwhUJLSrQw689PdUiG7DPJ8Z9WuiEHPplabAVoJ/AQ 15 | egWouG4y3IfHanqjkloK2sad6BP9viAEkfbpLBZpUQk9uF02hc+AkW07eDxsN4CS 16 | KVaN4wHVQC2R+yUq815spM54VwKBgQDGe5eOUMtEJw51eli/SVX8SxmHY2x7yrps 17 | 7RtChJc3oFIPq71USmo7YDEzm08YoM9ZTq8cikMTEnDFVhXYBFlE9uwTJ2+ZtKLo 18 | qxgA95CySOnWRJQtW2h/vvehAgoaJR+QKqBLxs1Z8FHpYn3X5Vuto/BFl2ZSHowA 19 | qOBtosM5iwKBgFO3CH+sf5OOcQlQ4tSTHDE0h1c4ajgXKUj/EqMuKStrZ86adcOg 20 | rB1T7axIahsqK602BQmAdlSNhtfBXa/ww17IKYd0L4V9m8gnQNEZWv879Ri7pEKv 21 | KhqAz0GFZdBYcBvKzCAjBS1KaltOUBEWG/hU3F7yAESj+s7ymA6STXeFAoGAVQL+ 22 | qOAGD8zCrqKWfGfGwmbQKmL1RhhQvPLZaCYuNo8eVsPyNbYhxgivSjFNMXk/FjtT 23 | WWAG1pZhYsQ6WumR6q3v80xCyozJ8enGQDPI7/O25CU/aiXqnjyHB5k+BnC8Eh2P 24 | xqUBs3HxQ4sB54S/PaIn+UaddrLKuEWcypiaEX0CgYEAuoOXzgobLBFCrRJmCWSE 25 | 3zkDQddsdFxjLQv2HukZrPjQ2+zhGMB4K0yR6GGTuFElxEGMLZBVQybLFzpcFDF1 26 | l1AFwb5K0Xq7Mx9xfRLTkbEwy2MXJ8l62GoQVG4Rdt5ZM2diplNVRpGztknOD4kC 27 | qCIKiOP241rpazBJ7CWcoHo= 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /certs/policies/policies: -------------------------------------------------------------------------------- 1 | { 2 | "example": { 3 | "preset": { 4 | "CERTIFICATE": { 5 | "LOCATE": "ALLOW_ALL", 6 | "CHECK": "ALLOW_ALL", 7 | "GET": "ALLOW_ALL", 8 | "GET_ATTRIBUTES": "ALLOW_ALL", 9 | "GET_ATTRIBUTE_LIST": "ALLOW_ALL", 10 | "ADD_ATTRIBUTE": "ALLOW_OWNER", 11 | "MODIFY_ATTRIBUTE": "ALLOW_OWNER", 12 | "DELETE_ATTRIBUTE": "ALLOW_OWNER", 13 | "OBTAIN_LEASE": "ALLOW_ALL", 14 | "ACTIVATE": "ALLOW_OWNER", 15 | "REVOKE": "ALLOW_OWNER", 16 | "DESTROY": "ALLOW_OWNER", 17 | "ARCHIVE": "ALLOW_OWNER", 18 | "RECOVER": "ALLOW_OWNER" 19 | }, 20 | "SYMMETRIC_KEY": { 21 | "REKEY": "ALLOW_OWNER", 22 | "REKEY_KEY_PAIR": "ALLOW_OWNER", 23 | "DERIVE_KEY": "ALLOW_OWNER", 24 | "LOCATE": "ALLOW_OWNER", 25 | "CHECK": "ALLOW_OWNER", 26 | "GET": "ALLOW_OWNER", 27 | "GET_ATTRIBUTES": "ALLOW_OWNER", 28 | "GET_ATTRIBUTE_LIST": "ALLOW_OWNER", 29 | "ADD_ATTRIBUTE": "ALLOW_OWNER", 30 | "MODIFY_ATTRIBUTE": "ALLOW_OWNER", 31 | "DELETE_ATTRIBUTE": "ALLOW_OWNER", 32 | "OBTAIN_LEASE": "ALLOW_OWNER", 33 | "GET_USAGE_ALLOCATION": "ALLOW_OWNER", 34 | "ACTIVATE": "ALLOW_OWNER", 35 | "REVOKE": "ALLOW_OWNER", 36 | "DESTROY": "ALLOW_OWNER", 37 | "ARCHIVE": "ALLOW_OWNER", 38 | "RECOVER": "ALLOW_OWNER" 39 | }, 40 | "PUBLIC_KEY": { 41 | "LOCATE": "ALLOW_ALL", 42 | "CHECK": "ALLOW_ALL", 43 | "GET": "ALLOW_ALL", 44 | "GET_ATTRIBUTES": "ALLOW_ALL", 45 | "GET_ATTRIBUTE_LIST": "ALLOW_ALL", 46 | "ADD_ATTRIBUTE": "ALLOW_OWNER", 47 | "MODIFY_ATTRIBUTE": "ALLOW_OWNER", 48 | "DELETE_ATTRIBUTE": "ALLOW_OWNER", 49 | "OBTAIN_LEASE": "ALLOW_ALL", 50 | "ACTIVATE": "ALLOW_OWNER", 51 | "REVOKE": "ALLOW_OWNER", 52 | "DESTROY": "ALLOW_OWNER", 53 | "ARCHIVE": "ALLOW_OWNER", 54 | "RECOVER": "ALLOW_OWNER" 55 | }, 56 | "PRIVATE_KEY": { 57 | "REKEY": "ALLOW_OWNER", 58 | "REKEY_KEY_PAIR": "ALLOW_OWNER", 59 | "DERIVE_KEY": "ALLOW_OWNER", 60 | "LOCATE": "ALLOW_OWNER", 61 | "CHECK": "ALLOW_OWNER", 62 | "GET": "ALLOW_OWNER", 63 | "GET_ATTRIBUTES": "ALLOW_OWNER", 64 | "GET_ATTRIBUTE_LIST": "ALLOW_OWNER", 65 | "ADD_ATTRIBUTE": "ALLOW_OWNER", 66 | "MODIFY_ATTRIBUTE": "ALLOW_OWNER", 67 | "DELETE_ATTRIBUTE": "ALLOW_OWNER", 68 | "OBTAIN_LEASE": "ALLOW_OWNER", 69 | "GET_USAGE_ALLOCATION": "ALLOW_OWNER", 70 | "ACTIVATE": "ALLOW_OWNER", 71 | "REVOKE": "ALLOW_OWNER", 72 | "DESTROY": "ALLOW_OWNER", 73 | "ARCHIVE": "ALLOW_OWNER", 74 | "RECOVER": "ALLOW_OWNER" 75 | }, 76 | "SPLIT_KEY": { 77 | "REKEY": "ALLOW_OWNER", 78 | "REKEY_KEY_PAIR": "ALLOW_OWNER", 79 | "DERIVE_KEY": "ALLOW_OWNER", 80 | "LOCATE": "ALLOW_OWNER", 81 | "CHECK": "ALLOW_OWNER", 82 | "GET": "ALLOW_OWNER", 83 | "GET_ATTRIBUTES": "ALLOW_OWNER", 84 | "GET_ATTRIBUTE_LIST": "ALLOW_OWNER", 85 | "ADD_ATTRIBUTE": "ALLOW_OWNER", 86 | "MODIFY_ATTRIBUTE": "ALLOW_OWNER", 87 | "DELETE_ATTRIBUTE": "ALLOW_OWNER", 88 | "OBTAIN_LEASE": "ALLOW_OWNER", 89 | "GET_USAGE_ALLOCATION": "ALLOW_OWNER", 90 | "ACTIVATE": "ALLOW_OWNER", 91 | "REVOKE": "ALLOW_OWNER", 92 | "DESTROY": "ALLOW_OWNER", 93 | "ARCHIVE": "ALLOW_OWNER", 94 | "RECOVER": "ALLOW_OWNER" 95 | }, 96 | "TEMPLATE": { 97 | "LOCATE": "ALLOW_OWNER", 98 | "GET": "ALLOW_OWNER", 99 | "GET_ATTRIBUTES": "ALLOW_OWNER", 100 | "GET_ATTRIBUTE_LIST": "ALLOW_OWNER", 101 | "ADD_ATTRIBUTE": "ALLOW_OWNER", 102 | "MODIFY_ATTRIBUTE": "ALLOW_OWNER", 103 | "DELETE_ATTRIBUTE": "ALLOW_OWNER", 104 | "DESTROY": "ALLOW_OWNER" 105 | }, 106 | "SECRET_DATA": { 107 | "REKEY": "ALLOW_OWNER", 108 | "REKEY_KEY_PAIR": "ALLOW_OWNER", 109 | "DERIVE_KEY": "ALLOW_OWNER", 110 | "LOCATE": "ALLOW_OWNER", 111 | "CHECK": "ALLOW_OWNER", 112 | "GET": "ALLOW_OWNER", 113 | "GET_ATTRIBUTES": "ALLOW_OWNER", 114 | "GET_ATTRIBUTE_LIST": "ALLOW_OWNER", 115 | "ADD_ATTRIBUTE": "ALLOW_OWNER", 116 | "MODIFY_ATTRIBUTE": "ALLOW_OWNER", 117 | "DELETE_ATTRIBUTE": "ALLOW_OWNER", 118 | "OBTAIN_LEASE": "ALLOW_OWNER", 119 | "GET_USAGE_ALLOCATION": "ALLOW_OWNER", 120 | "ACTIVATE": "ALLOW_OWNER", 121 | "REVOKE": "ALLOW_OWNER", 122 | "DESTROY": "ALLOW_OWNER", 123 | "ARCHIVE": "ALLOW_OWNER", 124 | "RECOVER": "ALLOW_OWNER" 125 | }, 126 | "OPAQUE_DATA": { 127 | "REKEY": "ALLOW_OWNER", 128 | "REKEY_KEY_PAIR": "ALLOW_OWNER", 129 | "DERIVE_KEY": "ALLOW_OWNER", 130 | "LOCATE": "ALLOW_OWNER", 131 | "CHECK": "ALLOW_OWNER", 132 | "GET": "ALLOW_OWNER", 133 | "GET_ATTRIBUTES": "ALLOW_OWNER", 134 | "GET_ATTRIBUTE_LIST": "ALLOW_OWNER", 135 | "ADD_ATTRIBUTE": "ALLOW_OWNER", 136 | "MODIFY_ATTRIBUTE": "ALLOW_OWNER", 137 | "DELETE_ATTRIBUTE": "ALLOW_OWNER", 138 | "OBTAIN_LEASE": "ALLOW_OWNER", 139 | "GET_USAGE_ALLOCATION": "ALLOW_OWNER", 140 | "ACTIVATE": "ALLOW_OWNER", 141 | "REVOKE": "ALLOW_OWNER", 142 | "DESTROY": "ALLOW_OWNER", 143 | "ARCHIVE": "ALLOW_OWNER", 144 | "RECOVER": "ALLOW_OWNER" 145 | }, 146 | "PGP_KEY": { 147 | "REKEY": "ALLOW_OWNER", 148 | "REKEY_KEY_PAIR": "ALLOW_OWNER", 149 | "DERIVE_KEY": "ALLOW_OWNER", 150 | "LOCATE": "ALLOW_OWNER", 151 | "CHECK": "ALLOW_OWNER", 152 | "GET": "ALLOW_OWNER", 153 | "GET_ATTRIBUTES": "ALLOW_OWNER", 154 | "GET_ATTRIBUTE_LIST": "ALLOW_OWNER", 155 | "ADD_ATTRIBUTE": "ALLOW_OWNER", 156 | "MODIFY_ATTRIBUTE": "ALLOW_OWNER", 157 | "DELETE_ATTRIBUTE": "ALLOW_OWNER", 158 | "OBTAIN_LEASE": "ALLOW_OWNER", 159 | "GET_USAGE_ALLOCATION": "ALLOW_OWNER", 160 | "ACTIVATE": "ALLOW_OWNER", 161 | "REVOKE": "ALLOW_OWNER", 162 | "DESTROY": "ALLOW_OWNER", 163 | "ARCHIVE": "ALLOW_OWNER", 164 | "RECOVER": "ALLOW_OWNER" 165 | } 166 | } 167 | } 168 | } 169 | -------------------------------------------------------------------------------- /certs/server.conf: -------------------------------------------------------------------------------- 1 | [server] 2 | hostname=0.0.0.0 3 | port=5696 4 | certificate_path=/etc/pykmip/certs/server_cert.pem 5 | key_path=/etc/pykmip/certs/server_key.pem 6 | ca_path=/etc/pykmip/certs/ca_cert.pem 7 | auth_suite=TLS1.2 8 | policy_path=/etc/pykmip/policies 9 | enable_tls_client_auth=True 10 | tls_cipher_suites= 11 | TLS_RSA_WITH_AES_128_CBC_SHA256 12 | TLS_RSA_WITH_AES_256_CBC_SHA256 13 | TLS_ECDHE_ECDSA_WITH_AES_256_CBC_SHA384 14 | logging_level=DEBUG 15 | -------------------------------------------------------------------------------- /certs/server/server_cert.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN CERTIFICATE----- 2 | MIIC5TCCAc2gAwIBAgIUOvMalE/ZQcPARekPGuYffRWud2AwDQYJKoZIhvcNAQEL 3 | BQAwJzETMBEGA1UECgwKVGVzdCwgSW5jLjEQMA4GA1UEAwwHUm9vdCBDQTAeFw0x 4 | OTEwMjIyMDEwMjFaFw0yOTEwMTkyMDEwMjFaMDIxEzARBgNVBAoMClRlc3QsIElu 5 | Yy4xGzAZBgNVBAMMElNlcnZlciBDZXJ0aWZpY2F0ZTCCASIwDQYJKoZIhvcNAQEB 6 | BQADggEPADCCAQoCggEBAKItoUMnwEQaxrUPLXKWsj2XpZFT3WpbtFQJc5xiHzqi 7 | 1OKbOxCmRd056keEpr88ndCsTkUmRJaBT1SFrHoseLZwaV74YKbfDE2By/WZn19q 8 | oIizx/L1w0t+j1RFmSqSbM7bHJzLkBwy7QwXt3wRG9xxGmvi3LjxPFSRdG/LTYNf 9 | 6zpPcjMRAOFbFVuSYYFtN4SnZ5MeNQhjHsWJj9iRf+qFJEd0nYdw/76H4vxc/hLa 10 | L6Zny97TzZm7tbNsomw+vTQZm+ec94QGjZnxnY+zSA9eZVZEDcJE58UacASFDGnB 11 | WMgCxDEIR2VZs2+PfFdnFPcqaTglbD5TzYhcLwBxCl8CAwEAATANBgkqhkiG9w0B 12 | AQsFAAOCAQEAQWTDDn2t/PEsbY8Ro9bFWUtGCqAKfFZd+Bu7Nf9szF1WUWjQgYGa 13 | 6ImsZUCEGsq6hjLlaGBI1uGHfIZ/uieAAtHkJ3VBAeQFRVd31gTXLin+Gfrf6BoZ 14 | aMD+k7hAvv2eBXZJHRoDm55Det6nCjyZdDQJOnNvffo5+2n0AdQRd+A3LcBYogo/ 15 | y/LN7o/DZGuzWm5p0/TtSJoafe7nDZ3274BDPC/8xJvGaoPiBh0oxwRq9vHogTa0 16 | KyMEb2f2iNIAyiBFuOGUCmCcF/NdNzlkTbB3GvGEHR4JYeaQY33mObdjUTb7XqPj 17 | +uVdzcZP34sV0yCoJJVw0noOxqzL1Wk8Hg== 18 | -----END CERTIFICATE----- 19 | -------------------------------------------------------------------------------- /certs/server/server_key.pem: -------------------------------------------------------------------------------- 1 | -----BEGIN PRIVATE KEY----- 2 | MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCiLaFDJ8BEGsa1 3 | Dy1ylrI9l6WRU91qW7RUCXOcYh86otTimzsQpkXdOepHhKa/PJ3QrE5FJkSWgU9U 4 | hax6LHi2cGle+GCm3wxNgcv1mZ9faqCIs8fy9cNLfo9URZkqkmzO2xycy5AcMu0M 5 | F7d8ERvccRpr4ty48TxUkXRvy02DX+s6T3IzEQDhWxVbkmGBbTeEp2eTHjUIYx7F 6 | iY/YkX/qhSRHdJ2HcP++h+L8XP4S2i+mZ8ve082Zu7WzbKJsPr00GZvnnPeEBo2Z 7 | 8Z2Ps0gPXmVWRA3CROfFGnAEhQxpwVjIAsQxCEdlWbNvj3xXZxT3Kmk4JWw+U82I 8 | XC8AcQpfAgMBAAECggEBAI3B/tSZeXjOQuReqOYhjRlDZaibOs3N7NkMDe8i4ZM6 9 | Y4TUFRPfku/lwL/U1oAQdw3AnwXYhllcHECQO4vrNXSa26/0wV77VmClVOeP6XvY 10 | 0wvKwbrAUX262YPa9h/9L3i8k80GLihH52YLkQm0Vrsgbezhtvc9ffOZ1MInXdC3 11 | cccB2GL/AkDviN2GULAr4FxGCluZW6ZWX7Rqell/KrOuUxC0NGowPr1HqGHa152R 12 | j38ic0/cs5Pxu3keWdnZBIqzqwV6kddDijfP9Yh5nTqYcUJC+NUiAJra9VQuzi7d 13 | ooLHYD1i00ZQqjCp243nuHgKhi2IO/MFxwnxLRLsZtkCgYEAzYOj2J5NdptCp9tv 14 | mEh8xv4I5iCWtOt8WFwlDPdROjUIT7bqkwA13/sA+eSKiB8UF9k4I+odx+hdydL7 15 | w44w2RDSC6dTstVhP1PCqSFSxqvUFfOWceH+llbMffxi7sYqdDIuRPyIXi+lC4AZ 16 | FTzNi3+KggsEVL7li9d90HeOjq0CgYEAygSuSvur6FXKhKK7sUDtU6trKzQ5s1Yr 17 | i+fv60ujtD40PSnFhXzh7hFEE03IasTuH/xC+Rre6j8dMBBJGiRL+J2QrPeunLl0 18 | SfSktDGIT6PpWt8vSDWL0uUjdXzh2ycGSqOqjmw1XfaVPfDiJqnl0tjwZmoBzGtc 19 | tiRu2SR+WrsCgYA2JMJb5YjfAJSVCJjj8+T7wB20E03hKFFALjaMrfO2dBZWeghe 20 | 5iVLdyOQsodUyWtPxSinPZzO+AcNjwpJQQLZjTbpXxIMAW93cafNSzw1nztm9R/j 21 | rPiXvxJs9rtR0N+KcVYDUszSk5bV6s+w6q30XIuvKxve/9QV/ZXmADmMmQKBgCgu 22 | NChv1Cpa3fPxlhlUS5/nqWIneg6EZhbmo96N5dqUwLkllMbPJvS99GdOgj1SO/aa 23 | qwt2372BniGQK6oKbB3f4QW2IcHEVS/ce+HnNDB67pAHchUPqWbh8mKM2zNGmMbB 24 | tMutFBRDVj3Cqoh8JF0CjxYfoYnyFLeZmX6Q9py/AoGBAL5Eb/Er5A67PNQwx8CI 25 | 4rpBG6G1k2meoEk/mjz1NF0zji52KzkS6zMQ6SbkXqFUSTtdd6+QH+zP77i5rG+j 26 | 41/JZ9Mti4URDx2I938SVTkXE4BdfjUqJNf53a5ISWoRXTafmAN30L+fA3Us7RqC 27 | /WmPTywqOwocQfJeSVKfCVUt 28 | -----END PRIVATE KEY----- 29 | -------------------------------------------------------------------------------- /doc/sedcli-kmip.8: -------------------------------------------------------------------------------- 1 | .TH sedcli-kmip 8 2 | .SH NAME 3 | sedcli-kmip \- autoprovision and autounlock TCG Opal SEDs using Key Management 4 | Server (KMS) 5 | 6 | .SH SYNOPSIS 7 | 8 | \fBsedcli-kmip\fR [options...] 9 | 10 | .SH DESCRIPTION 11 | Sedcli-kmip is part of sedcli package and allows system Administrator/Operator 12 | to automatically provision and automatically unlock NVMe SEDs that are TCG Opal 13 | compliant. 14 | 15 | .PP 16 | Automatic management requires sedcli-kmip to be configured with OASIS KMIP (Key 17 | Management Interoperability Protocol) compatible Key Management Server. There 18 | are commercial and open source implementations of KMIP server available. 19 | Sedcli-kmip has been developed and tested using PyKMIP implementation. 20 | 21 | .PP 22 | Sedcli-kmip when run for the first time on a given platform, communicates with 23 | KMS and generates Platform Encryption Key (PEK) on it. PEK is a single per 24 | platform AES-256 bits long key that is used to wrap/unwrap individual disk keys 25 | called Disk Encryption Key (DEK). Encrypted version of DEK is stored in sedcli 26 | metadata region in Opal datastore on disk itself. 27 | 28 | .PP 29 | NVMe SED provisioning may be triggered manually in command line or automatically 30 | on hot-insert event or OS boot. This requires proper udev rules to be installed. 31 | When NVMe SED is provisioned for security DEK key is used for SID and Admin1 32 | authorities. 33 | 34 | .PP 35 | Sedcli-kmip performs secure communication with KMS using SSL. KMS uses 36 | certificate based authentication and authorization. Path to sedcli-kmip client 37 | certificate and CA certificate should be stored in /etc/sedcli/sedcli.conf 38 | file. 39 | 40 | .PP 41 | It is possible to perform periodic key rotation using key backup functionality. 42 | User needs to store old DEK key in a backup file and then reprovision SSD using 43 | backup file to authenticate to the drive and perform necessary updates. 44 | 45 | .SH OPTIONS 46 | 47 | .IP "\fB\-\-help\fR" 48 | Prints global and command specific help on available commands and usage 49 | 50 | .IP "To print command specific help use following syntax:" 51 | .IP "\fBsedcli-kmip --help\fR" 52 | .IP "For example:" 53 | .IP "\fBsedcli-kmip --provision --help\fR" 54 | 55 | .SH COPYRIGHT 56 | Copyright (C) 2018-2019, 20222-2023 Solidigm. All Rights Reserved. 57 | 58 | .SH AUTHOR 59 | This manual page was created by Piotr Rudnicki 60 | 61 | .SH FILES 62 | .PP 63 | sedcli-kmip 64 | .PP 65 | /etc/sedcli/sedcli.conf 66 | 67 | .SH SEE ALSO 68 | .TP 69 | sedcli(8) 70 | -------------------------------------------------------------------------------- /doc/sedcli.8: -------------------------------------------------------------------------------- 1 | .TH sedcli 8 2 | .SH NAME 3 | sedcli \- manage Opal Self-Encrypting Drives (SEDs) NVMe SSDs 4 | 5 | .SH SYNOPSIS 6 | 7 | \fBsedcli\fR [options...] 8 | 9 | .SH DESCRIPTION 10 | Sedcli enables a system Administrator/Operator to manage NVMe SEDs that are TCG 11 | Opal compliant. In Opal terminology SED is called a Trusted Peripheral (TPer) 12 | and provides an Admin Security Provider (Admin SP) and Locking Security Provider 13 | (Locking SP). 14 | 15 | .PP 16 | Management of the TCG Opal features require several operations that are performed 17 | as an Administrator within the TCG Opal command set to either the AdminSP or 18 | LockingSP. The AdminSP provides commands that enable the user to perform 19 | administrative operations such as taking ownership of the device, activation of 20 | the LockingSP, and revert the TPer, whereas the LockingSP provides commands that 21 | enable the user to configure and enable locking enforcement on user data either 22 | globally or on a locking range basis after the LockingSP has been activated by 23 | the AdminSP. 24 | 25 | .PP 26 | To start Opal management, an Administrator typically needs to perform the 27 | following process at a minimum: 28 | .IP 29 | 1. Take ownership of the device (setting a non-MSID credential for the SID 30 | Authority in the AdminSP) 31 | .IP 32 | 2. Activate the LockingSP (this will move the Opal feature to the Manufactured 33 | state and copy the SID authority password to the LockingSP Admin1 password) 34 | .IP 35 | 3. Enable Read Lock Enabled and Write Lock Enabled on all desired ranges 36 | (e.g. Global Range) 37 | .PP 38 | After these steps are accomplished, the TPer will be Read or Write locked after 39 | power cycle or when explicitly locked using sedcli command. 40 | 41 | .PP 42 | In addition to these basic flows, one can perform crypto erase of the TPer 43 | using the SID authority or the PSID authority as part of revert TPer operation. 44 | In case of using the PSID authority the operator needs to provide the credential 45 | that is printed on the disk label. The Revert TPer operation reverts device 46 | back to the Manufactured-Inactive state, which then requires re-configuration 47 | of the Opal management system using the process previously identified (i.e. 48 | take ownership, activate LSP, enable global range). It is also possible to 49 | update Admin1 password for Locking SP. 50 | 51 | .SH OPTIONS 52 | 53 | .IP "\fB\-\-version\fR" 54 | Prints version of sedcli. 55 | 56 | .IP "\fB\-\-help\fR" 57 | Prints global help on available commands and usage 58 | 59 | .IP "To print command specific help use following syntax:" 60 | .IP "\fBsedcli --help\fR" 61 | .IP "For example:" 62 | .IP "\fBsedcli --discovery --help\fR" 63 | 64 | .SH COPYRIGHT 65 | Copyright (C) 2018-2019, 2022-2023 Solidigm. All Rights Reserved. 66 | 67 | .SH AUTHOR 68 | This manual page was created by Piotr Rudnicki 69 | 70 | .SH SEE ALSO 71 | .TP 72 | sedcli-kmip(8) 73 | -------------------------------------------------------------------------------- /etc/sedcli/sedcli.conf: -------------------------------------------------------------------------------- 1 | ## SEDCLI configuration file 2 | 3 | ## KMIP access section 4 | # KMIP server IP 5 | #kmip_ip= 6 | kmip_ip=127.0.0.1 7 | 8 | # KMIP server port 9 | #kmip_port= 10 | kmip_port=5696 11 | 12 | # Client certificate for connection w/ KMIP 13 | # Use of absolute path is recommended to avoid file 14 | # not found errors 15 | #client_cert= 16 | client_cert=/etc/sedcli/certs/client_cert.pem 17 | 18 | # Client key for connection w/ KMIP 19 | # Use of absolute path is recommended to avoid file 20 | # not found errors 21 | #client_key= 22 | client_key=/etc/sedcli/certs/client_key.pem 23 | 24 | # Certificate Authority(CA) certificate 25 | # Use of absolute path is recommended to avoid file 26 | # not found errors 27 | #ca_cert= 28 | ca_cert=/etc/sedcli/certs/ca_cert.pem 29 | 30 | ## Key caching policy should go here 31 | 32 | ## Device selection policy should go here -------------------------------------------------------------------------------- /etc/udev/rules.d/63-sedcli.rules: -------------------------------------------------------------------------------- 1 | SUBSYSTEM!="block", GOTO="sedcli_end" 2 | KERNEL!="nvme*[0-9]n*[0-9]", GOTO="sedcli_end" 3 | ACTION!="add", GOTO="sedcli_end" 4 | ENV{DEVTYPE}!="disk", GOTO="sedcli_end" 5 | 6 | # Perform Discovery to detect if disk is SED and its state 7 | IMPORT{program}="/usr/sbin/sedcli -discovery --device $env{DEVNAME} -f udev" 8 | 9 | ENV{DEV_SED_COMPATIBLE}=="ENABLED", GOTO="check_sedcli_lock" 10 | ENV{DEV_SED_COMPATIBLE}=="DISABLED", GOTO="sedcli_end" 11 | 12 | LABEL="check_sedcli_lock" 13 | ENV{DEV_SED_LOCKED}=="DISABLED", GOTO="sedcli_provision" 14 | ENV{DEV_SED_LOCKED}=="ENABLED", GOTO="sedcli_unlock" 15 | 16 | LABEL="sedcli_provision" 17 | # Intial provisioning of the device 18 | RUN+="/usr/sbin/sedcli-kmip --provision --device $env{DEVNAME}", GOTO="sedcli_end" 19 | 20 | LABEL="sedcli_unlock" 21 | # Unlock the device 22 | RUN+="/usr/sbin/sedcli-kmip --lock-unlock --device $env{DEVNAME} --access-type RW", GOTO="sedcli_end" 23 | 24 | LABEL="sedcli_end" 25 | -------------------------------------------------------------------------------- /src/Makefile: -------------------------------------------------------------------------------- 1 | # 2 | # Copyright (C) 2018-2019, 2022-2023 Solidigm. All Rights Reserved. 3 | # 4 | # SPDX-License-Identifier: GPL-2.0-or-later 5 | # 6 | 7 | SHELL := /bin/bash 8 | 9 | ifeq (, $(filter $(MAKECMDGOALS), clean distclean)) 10 | ifeq ("$(wildcard config.mk config.h)", "") 11 | $(error Run ./configure before invoking make) 12 | endif 13 | include config.mk 14 | endif 15 | 16 | # 17 | # Flags for compilation 18 | # 19 | CFLAGS += $(patsubst %,-I%,$(INCLUDES)) 20 | CFLAGS += $(patsubst %,-D%,$(DEFINES)) 21 | 22 | OBJDIR = .obj/ 23 | LIBOBJDIR = .libobj/ 24 | TARGET = sedcli 25 | LIB = libsed 26 | 27 | ifneq (clean,$(filter clean,$(MAKECMDGOALS))) 28 | $(info CFLAGS: $(CFLAGS)) 29 | $(info LDFLAGS: $(LDFLAGS)) 30 | ifdef CONFIG_KMIP 31 | $(info LDFLAGS_KMIP: $(LDFLAGS_KMIP)) 32 | endif 33 | $(info TARGET: $(TARGET)) 34 | $(info LIB: $(LIB)) 35 | $(info INCLUDES: $(INCLUDES)) 36 | $(info DEFINES: $(DEFINES)) 37 | endif 38 | 39 | # 40 | # Files to be compiled 41 | # 42 | LIBOBJS = sed.o 43 | LIBOBJS += sed_util.o 44 | LIBOBJS += nvme_access.o 45 | LIBOBJS += nvme_pt_ioctl.o 46 | LIBOBJS += opal_parser.o 47 | 48 | OBJS = argp.o 49 | OBJS += sedcli_main.o 50 | OBJS += sedcli_util.o 51 | 52 | ifdef CONFIG_KMIP 53 | KMIP_OBJS = argp.o 54 | KMIP_OBJS += metadata_serializer.o 55 | KMIP_OBJS += config_file.o 56 | KMIP_OBJS += crypto_lib.o 57 | KMIP_OBJS += kmip_lib.o 58 | KMIP_OBJS += sedcli_util.o 59 | KMIP_OBJS += sedcli_kmip.o 60 | endif 61 | 62 | ALL_TARGETS = $(TARGET)-static $(TARGET)-dynamic 63 | ifdef CONFIG_KMIP 64 | ALL_TARGETS += $(TARGET)-kmip 65 | endif 66 | 67 | INSTALL_TARGETS = install-$(TARGET) 68 | ifdef CONFIG_KMIP 69 | INSTALL_TARGETS += install-$(TARGET)-kmip 70 | endif 71 | 72 | all: $(ALL_TARGETS) 73 | @ln -sf $(TARGET)-static $(TARGET) 74 | 75 | $(TARGET)-static: $(TARGET).a $(LIB).a 76 | @echo " LD " $@ 77 | @$(CC) $(TARGET).a $(LDFLAGS) -Wl,-Bstatic -lsed -Wl,-Bdynamic -o $@ 78 | 79 | $(TARGET)-dynamic: $(TARGET).a $(LIB).so 80 | @echo " LD " $@ 81 | @$(CC) $(TARGET).a $(LDFLAGS) -lsed -o $@ 82 | 83 | $(TARGET).a: $(patsubst %,$(OBJDIR)%,$(OBJS)) 84 | @echo " AR " $@ 85 | @ar rcs $@ $^ 86 | 87 | $(TARGET)-kmip.a: $(patsubst %,$(OBJDIR)%,$(KMIP_OBJS)) 88 | @echo " AR " $@ 89 | @ar rcs $@ $(patsubst %,$(OBJDIR)%,$(KMIP_OBJS)) 90 | 91 | $(TARGET)-kmip: $(TARGET)-kmip.a $(LIB).a 92 | @echo " LD " $@ 93 | @$(CC) $(TARGET)-kmip.a $(LDFLAGS) $(LDFLAGS_KMIP) -Wl,-Bstatic -lsed -lkmip -Wl,-Bdynamic -o $@ 94 | 95 | # 96 | # Static library 97 | # 98 | $(LIB).a: $(patsubst %,$(LIBOBJDIR)%,$(LIBOBJS)) 99 | @echo " AR " $@ 100 | @ar rcs $@ $^ 101 | 102 | # 103 | # Shared library 104 | # 105 | $(LIB).so: $(LIB).a 106 | @echo " LD " $@ 107 | @$(CC) -shared -Wl,-soname,$@.1 -Wl,--whole-archive $(LIB).a -Wl,--no-whole-archive -o $@.1.0.1 108 | @ln -sf $@.1.0.1 $@.1 109 | @ln -sf $@.1.0.1 $@ 110 | 111 | # 112 | # Main targets for compilation 113 | # 114 | $(OBJDIR)%.o: %.c 115 | @echo " CC " $< 116 | @mkdir -p $(dir $@) 117 | @$(CC) -c $(CFLAGS) -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<" 118 | 119 | $(LIBOBJDIR)%.o: lib/%.c 120 | @echo " CC " $< 121 | @mkdir -p $(dir $@) 122 | @$(CC) -c $(CFLAGS) -shared -fPIC -MMD -MP -MF"$(@:%.o=%.d)" -MT"$(@:%.o=%.d)" -o "$@" "$<" 123 | 124 | clean: 125 | @echo " CLEAN " 126 | @rm -f $(TARGET).a $(LIB).a $(TARGET)-kmip $(TARGET)-kmip.a $(TARGET)-static $(TARGET)-dynamic $(TARGET) $(LIB).so* 127 | @rm -fr $(OBJDIR) $(LIBOBJDIR) 128 | @rm -f properties 129 | 130 | distclean: clean 131 | @rm -f config.log config.mk config.h 132 | 133 | install-$(TARGET): 134 | @echo " Installing $(TARGET)" 135 | install -m 755 $(TARGET)-dynamic $(DESTDIR)/usr/sbin/$(TARGET) 136 | install -m 755 $(LIB).so.1.0.1 $(DESTDIR)$(LIB_DIR) 137 | ln -sf $(LIB_DIR)/$(LIB).so.1.0.1 $(DESTDIR)$(LIB_DIR)/$(LIB).so.1 138 | # install -m 644 ../doc/$(TARGET).8 $(DESTDIR)/usr/share/man/man8/$(TARGET).8 139 | 140 | install-$(TARGET)-kmip: install-$(TARGET) 141 | @echo " Installing $(TARGET)-kmip" 142 | install -m 755 $(TARGET)-kmip $(DESTDIR)/usr/sbin/$(TARGET)-kmip 143 | install -m 644 ../etc/udev/rules.d/63-sedcli.rules $(DESTDIR)/etc/udev/rules.d/ 144 | install -m 755 -d /etc/sedcli $(DESTDIR)/etc/sedcli/certs 145 | install -m 644 ../etc/sedcli/sedcli.conf $(DESTDIR)/etc/sedcli/ 146 | touch $(DESTDIR)/etc/sedcli/sedcli_kmip && chmod 644 $(DESTDIR)/etc/sedcli/sedcli_kmip 147 | # install -m 644 ../doc/$(TARGET)-kmip.8 $(DESTDIR)/usr/share/man/man8/$(TARGET)-kmip.8 148 | 149 | install-cert: 150 | install -m 644 ../certs/ca/ca_cert.pem $(DESTDIR)/etc/sedcli/certs/ 151 | install -m 644 ../certs/client/client_cert.pem $(DESTDIR)/etc/sedcli/certs/ 152 | install -m 644 ../certs/client/client_key.pem $(DESTDIR)/etc/sedcli/certs/ 153 | 154 | install: $(INSTALL_TARGETS) 155 | 156 | uninstall: 157 | @echo " Removing $(TARGET)" 158 | -rm $(DESTDIR)/usr/sbin/$(TARGET) 159 | -rm $(DESTDIR)$(LIB_DIR)/$(LIB).so* 160 | -rm $(DESTDIR)/usr/sbin/$(TARGET)-kmip 161 | -rm $(DESTDIR)/etc/udev/rules.d/63-sedcli.rules 162 | -rm $(DESTDIR)/etc/sedcli/sedcli.conf 163 | -rm $(DESTDIR)/etc/sedcli/sedcli_kmip 164 | # -rm $(DESTDIR)/usr/share/man/man8/$(TARGET).8 165 | # -rm $(DESTDIR)/usr/share/man/man8/$(TARGET)-kmip.8 166 | 167 | uninstall-cert: 168 | -rm $(DESTDIR)/etc/sedcli/certs/ca_cert.pem 169 | -rm $(DESTDIR)/etc/sedcli/certs/client_cert.pem 170 | -rm $(DESTDIR)/etc/sedcli/certs/client_key.pem 171 | -rm -r $(DESTDIR)/etc/sedcli/certs 172 | -rm -r $(DESTDIR)/etc/sedcli 173 | 174 | .PHONY: clean all distclean install uninstall 175 | -------------------------------------------------------------------------------- /src/aliases: -------------------------------------------------------------------------------- 1 | sid 2 | 00-00-00-09-00-00-00-06 3 | psid 4 | 00-00-00-09-00-01-FF-01 5 | --- sp 6 | admin_sp 7 | 00-00-02-05-00-00-00-01 8 | locking_sp 9 | 00-00-02-05-00-00-00-02 10 | this_sp 11 | 00-00-00-00-00-00-00-01 12 | --- admins - authority table 13 | admin1 14 | 00-00-00-09-00-01-00-01 15 | admin2 16 | 00-00-00-09-00-01-00-02 17 | admin3 18 | 00-00-00-09-00-01-00-03 19 | admin4 20 | 00-00-00-09-00-01-00-04 21 | --- admins - C_PIN table 22 | admin1_cpin 23 | 00-00-00-0b-00-01-00-01 24 | admin2_cpin 25 | 00-00-00-0b-00-01-00-02 26 | --- users 27 | user1 28 | 00-00-00-09-00-03-00-01 29 | user2 30 | 00-00-00-09-00-03-00-02 31 | user3 32 | 00-00-00-09-00-03-00-03 33 | user4 34 | 00-00-00-09-00-03-00-04 35 | user5 36 | 00-00-00-09-00-03-00-05 37 | user6 38 | 00-00-00-09-00-03-00-06 39 | user7 40 | 00-00-00-09-00-03-00-07 41 | user8 42 | 00-00-00-09-00-03-00-08 43 | -------------------------------------------------------------------------------- /src/argp.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2019, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | 17 | #include "argp.h" 18 | #include "libsed.h" 19 | #include "kmip_lib.h" 20 | 21 | 22 | #define PADDING " " 23 | #define MAX_OPT_HELP_LEN 40 24 | #define TIMESTAMP_LEN (4096) 25 | 26 | #define MAX_LOG_LEVEL LOG_WARNING 27 | #define SEDCLI_LOGFILE "/var/log/sedcli.log" 28 | 29 | #ifndef F_ULOCK 30 | #define F_ULOCK 0 31 | #endif 32 | #ifndef F_LOCK 33 | #define F_LOCK 1 34 | #endif 35 | int vsedcli_log(int log_level, const char *template, va_list args) 36 | { 37 | FILE *log; 38 | time_t t; 39 | struct tm *tm; 40 | char *timestamp; 41 | int ret; 42 | 43 | if (log_level > MAX_LOG_LEVEL) 44 | return 0; 45 | 46 | log = fopen(SEDCLI_LOGFILE, "a"); 47 | if (!log) 48 | return FAILURE; 49 | 50 | ret = lockf(fileno(log), F_LOCK, 0); 51 | if (ret < 0) 52 | goto out; 53 | 54 | t = time(NULL); 55 | tm = localtime(&t); 56 | if (!tm) { 57 | ret = FAILURE; 58 | goto out; 59 | } 60 | 61 | timestamp = asctime(tm); 62 | if (!timestamp) { 63 | ret = FAILURE; 64 | goto out; 65 | } 66 | 67 | timestamp[strnlen(timestamp, TIMESTAMP_LEN)-1] = 0; 68 | 69 | fseek(log, 0, SEEK_END); 70 | fprintf(log, "%s sedcli: ", timestamp); 71 | vfprintf(log, template, args); 72 | fflush(log); 73 | 74 | ret = lockf(fileno(log), F_ULOCK, 0); 75 | 76 | out: 77 | fclose(log); 78 | return ret; 79 | } 80 | 81 | __attribute__((format(printf, 2, 3))) 82 | int sedcli_log(int log_level, const char *template, ...) 83 | { 84 | va_list args; 85 | va_start(args, template); 86 | vsedcli_log(log_level, template, args); 87 | va_end(args); 88 | return 0; 89 | } 90 | 91 | __attribute__((format(printf, 2, 3))) 92 | int std_printf(int log_level, const char *template, ...) 93 | { 94 | va_list args; 95 | 96 | 97 | va_start(args, template); 98 | if (LOG_WARNING >= log_level) { 99 | va_list args_copy; 100 | va_copy(args_copy, args); 101 | vfprintf(stderr, template, args); 102 | vsedcli_log(log_level, template, args_copy); 103 | va_end(args_copy); 104 | } else { 105 | vfprintf(stdout, template, args); 106 | } 107 | va_end(args); 108 | return 0; 109 | } 110 | 111 | sedcli_printf_t sedcli_printf = std_printf; 112 | 113 | static int is_su_required(const cli_command* commands, int cmd) 114 | { 115 | return commands[cmd].flags & CLI_SU_REQUIRED; 116 | } 117 | 118 | static int is_command_hidden(const cli_command* commands, int cmd) 119 | { 120 | return commands[cmd].flags & CLI_COMMAND_HIDDEN; 121 | } 122 | 123 | static void print_short_usage(const app *app_values) 124 | { 125 | sedcli_printf(LOG_INFO, "Usage: %s %s\n\n", app_values->name, app_values->info); 126 | sedcli_printf(LOG_INFO, "The '' must be a block device (e.g. /dev/nvme0n1).\n"); 127 | } 128 | 129 | static void print_info(const app *app_values) 130 | { 131 | sedcli_printf(LOG_INFO, "Try `%s --help' for more information.\n", app_values->name); 132 | } 133 | 134 | char *get_short_name_string(const char short_name, char *buf) 135 | { 136 | if (short_name) { 137 | snprintf(buf, 3, "-%c", short_name); 138 | } else { 139 | buf[0] = 0; 140 | } 141 | return buf; 142 | } 143 | 144 | char *command_name_with_slash(char *buf, size_t buf_size, char short_name, char *long_name) { 145 | if (short_name) { 146 | snprintf(buf, buf_size, "-%c/--%s", short_name, long_name); 147 | } else { 148 | snprintf(buf, buf_size, "--%s", long_name); 149 | } 150 | return buf; 151 | } 152 | 153 | char *command_name_in_brackets(char *buf, size_t buf_size, char short_name, char *long_name) { 154 | if (short_name) { 155 | snprintf(buf, buf_size, "--%s (-%c)", long_name, short_name); 156 | } else { 157 | snprintf(buf, buf_size, "--%s", long_name); 158 | } 159 | return buf; 160 | } 161 | 162 | void print_options_usage(cli_option* options, const char *separator, 163 | int (*view)(cli_option* options, int flag), int flag) 164 | { 165 | int print_separator = 0; 166 | int i; 167 | 168 | if (NULL == options) { 169 | return; 170 | } 171 | 172 | for (i = 0; options[i].long_name != NULL; ++i) { 173 | if (0 == view(&options[i], flag)) { 174 | continue; 175 | } 176 | 177 | if (print_separator) { 178 | /* Separator */ 179 | sedcli_printf(LOG_INFO, "%s", separator); 180 | } 181 | print_separator = 1; 182 | 183 | /* Long option name */ 184 | sedcli_printf(LOG_INFO, "--%s", options[i].long_name); 185 | 186 | /* Parameter */ 187 | if (options[i].arg != NULL) { 188 | sedcli_printf(LOG_INFO, " <%s>", 189 | options[i].arg); 190 | } 191 | } 192 | } 193 | 194 | void print_command_header(const cli_command *cmd) 195 | { 196 | sedcli_printf(LOG_INFO, "%s%s\n\n", PADDING, cmd->long_desc != NULL ? cmd->long_desc : cmd->desc); 197 | } 198 | 199 | void print_list_options(cli_option* options, int flag, int (*view)(cli_option* options, int flag)) 200 | { 201 | for (; options->long_name != NULL; options++) { 202 | char *desc = options->desc; 203 | char short_name[3]; 204 | 205 | if (0 == view(options, flag)) 206 | continue; 207 | 208 | get_short_name_string(options->short_name, short_name); 209 | if (options->arg != NULL) { 210 | char buf[MAX_OPT_HELP_LEN]; 211 | if (options->flags & CLI_OPTION_OPTIONAL) 212 | snprintf(buf, MAX_OPT_HELP_LEN, "--%s [<%s>]", options->long_name, options->arg); 213 | else 214 | snprintf(buf, MAX_OPT_HELP_LEN, "--%s <%s>", options->long_name, options->arg); 215 | 216 | sedcli_printf(LOG_INFO, "%s%-4s%-32s%s\n", PADDING, short_name, buf, desc); 217 | } else 218 | sedcli_printf(LOG_INFO, "%s%-4s--%-30s%s\n", PADDING, short_name, options->long_name, desc); 219 | } 220 | } 221 | 222 | static void print_options_help(cli_option *options) 223 | { 224 | int i; 225 | 226 | for (i = 0; options[i].long_name != NULL; ++i) { 227 | char *desc = options[i].desc; 228 | char short_name[3]; 229 | if (options[i].flags & CLI_OPTION_HIDDEN) 230 | continue; 231 | 232 | get_short_name_string(options[i].short_name, short_name); 233 | if (options[i].arg != NULL) { 234 | char buf[MAX_OPT_HELP_LEN]; 235 | if (options[i].flags & CLI_OPTION_OPTIONAL) { 236 | snprintf(buf, MAX_OPT_HELP_LEN, "--%s [<%s>]", 237 | options[i].long_name, 238 | options[i].arg); 239 | } else { 240 | snprintf(buf, MAX_OPT_HELP_LEN, "--%s <%s>", 241 | options[i].long_name, 242 | options[i].arg); 243 | } 244 | 245 | sedcli_printf(LOG_INFO, "%s%-4s%-38s%s\n", PADDING, short_name, buf, desc); 246 | } else 247 | sedcli_printf(LOG_INFO, "%s%-4s--%-36s%s\n", PADDING, short_name, options[i].long_name, desc); 248 | } 249 | } 250 | 251 | static void print_namespace_help(app *app_values, cli_command *cmd) 252 | { 253 | char command_name[MAX_STR_LEN]; 254 | char option_name[MAX_STR_LEN]; 255 | cli_namespace *ns = cmd->namespace; 256 | int i; 257 | 258 | sedcli_printf(LOG_INFO, "Usage: %s --%s --%s \n\n", app_values->name, cmd->name, ns->long_name); 259 | 260 | print_command_header(cmd); 261 | 262 | command_name_in_brackets(command_name, MAX_STR_LEN, cmd->short_name, cmd->name); 263 | command_name_in_brackets(option_name, MAX_STR_LEN, ns->short_name, ns->long_name); 264 | 265 | sedcli_printf(LOG_INFO, "Valid values of NAME are:\n"); 266 | for (i = 0; ns->entries[i].name; ++i) 267 | sedcli_printf(LOG_INFO, "%s%s - %s\n", PADDING, ns->entries[i].name, ns->entries[i].desc); 268 | 269 | sedcli_printf(LOG_INFO, "\n"); 270 | 271 | for (i = 0; ns->entries[i].name; ++i) { 272 | sedcli_printf(LOG_INFO, "Options that are valid with %s %s %s are:\n", command_name, option_name, 273 | ns->entries[i].name); 274 | print_options_help(ns->entries[i].options); 275 | if (ns->entries[i + 1].name) 276 | sedcli_printf(LOG_INFO, "\n"); 277 | } 278 | } 279 | 280 | static void print_command_help(app *app_values, cli_command *cmd) 281 | { 282 | int all_mandatory = 1; 283 | int all_hidden = 1; 284 | int i; 285 | 286 | if (cmd->help) { 287 | (cmd->help)(app_values, cmd); 288 | return; 289 | } 290 | 291 | if (cmd->namespace) { 292 | print_namespace_help(app_values, cmd); 293 | return; 294 | } 295 | 296 | sedcli_printf(LOG_INFO, "Usage: %s --%s", app_values->name, cmd->name); 297 | 298 | if (cmd->options != NULL) { 299 | for (i = 0; cmd->options[i].long_name != NULL; ++i) { 300 | if (cmd->options[i].flags & CLI_OPTION_HIDDEN) { 301 | continue; 302 | } 303 | 304 | all_hidden = 0; 305 | 306 | if (cmd->options[i].flags & CLI_OPTION_REQUIRED) { 307 | sedcli_printf(LOG_INFO, " --%s", cmd->options[i].long_name); 308 | if (cmd->options[i].arg != NULL) { 309 | if (cmd->options[i].flags & CLI_OPTION_OPTIONAL) { 310 | sedcli_printf(LOG_INFO, " [<%s>]", cmd->options[i].arg); 311 | } else { 312 | sedcli_printf(LOG_INFO, " <%s>", cmd->options[i].arg); 313 | } 314 | } 315 | } else { 316 | all_mandatory = 0; 317 | } 318 | } 319 | 320 | if (!all_mandatory) { 321 | sedcli_printf(LOG_INFO, " [option...]"); 322 | } 323 | } 324 | sedcli_printf(LOG_INFO, "\n\n"); 325 | 326 | print_command_header(cmd); 327 | 328 | if (cmd->options && !all_hidden) { 329 | char option_name[MAX_STR_LEN]; 330 | command_name_in_brackets(option_name, MAX_STR_LEN, cmd->short_name, cmd->name); 331 | sedcli_printf(LOG_INFO, "Options that are valid with %s are:\n", option_name); 332 | print_options_help(cmd->options); 333 | } 334 | } 335 | 336 | void print_help(const app *app_values, const cli_command *commands) 337 | { 338 | sedcli_printf(LOG_INFO, "%s\n\n", app_values->title); 339 | print_short_usage(app_values); 340 | 341 | sedcli_printf(LOG_INFO, "\nAvailable commands:\n"); 342 | for (int i = 0;; ++i) { 343 | char short_name[3]; 344 | 345 | if (commands[i].name == NULL) 346 | break; 347 | 348 | if (is_command_hidden(commands, i)) 349 | continue; 350 | 351 | char* buf = get_short_name_string(commands[i].short_name, short_name); 352 | if (buf[0]) 353 | sedcli_printf(LOG_INFO, "%s%-4s--%-25s%s\n", PADDING, short_name, commands[i].name, commands[i].desc); 354 | else 355 | sedcli_printf(LOG_INFO, "%s--%-25s%s\n", PADDING, commands[i].name, commands[i].desc); 356 | } 357 | 358 | sedcli_printf(LOG_INFO, "\nSee 'sedcli --help' for more information on a specific command.\n" 359 | "e.g.\n%s%s --%s --help\n", PADDING, app_values->name, commands[0].name); 360 | 361 | if (app_values->man != NULL) 362 | sedcli_printf(LOG_INFO, "For more information, please refer to manpage (man %s).\n", app_values->man); 363 | else 364 | sedcli_printf(LOG_INFO, "For more information, please refer to manpage.\n"); 365 | } 366 | 367 | static int args_is_unrecognized(const char *cmd) 368 | { 369 | if (strempty(cmd)) { 370 | return 1; 371 | } 372 | 373 | if ('-' == cmd[0]) { 374 | char c = cmd[1]; 375 | 376 | /* Check if short option (command) is proper */ 377 | if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { 378 | if ('\0' == cmd[2]) { 379 | return 0; 380 | } else { 381 | return 1; 382 | } 383 | } 384 | 385 | if ('-' == cmd[1]) { 386 | char c = cmd[2]; 387 | /* Long option (command), check if it is valid */ 388 | 389 | if ((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z')) { 390 | return 0; 391 | } 392 | } 393 | } 394 | 395 | return 1; 396 | } 397 | 398 | static int args_is(const char *in, const char *arg, const char c) 399 | { 400 | if (strempty(in)) 401 | return 0; 402 | 403 | if ('-' == in[0]) { 404 | if (0 != c && c == in[1]) { 405 | if ('\0' == in[2]) { 406 | return 1; 407 | } 408 | } 409 | 410 | if ('-' == in[1]) { 411 | /* Long option */ 412 | if (0 == strncmp(&(in[2]), arg, MAX_STR_LEN)) { 413 | return 1; 414 | } 415 | } 416 | } 417 | 418 | return 0; 419 | } 420 | 421 | static int is_help(const char* cmd) 422 | { 423 | return args_is(cmd, "help", 'H'); 424 | } 425 | 426 | static int is_version(const char* cmd) 427 | { 428 | return args_is(cmd, "version", 'V'); 429 | } 430 | 431 | static int get_help_position(int argc, char **argv) 432 | { 433 | for (int i = 2; i < argc; i++) 434 | if (is_help(argv[i])) { 435 | return i; 436 | } 437 | 438 | return -1; 439 | } 440 | 441 | static int get_option(const cli_option *options, const char* opt) 442 | { 443 | for (int i = 0; options[i].long_name; ++i) { 444 | if (args_is(opt, options[i].long_name, options[i].short_name)) { 445 | return i; 446 | } 447 | } 448 | 449 | return -1; 450 | } 451 | 452 | /** 453 | * log command as it was entered in CLI 454 | */ 455 | void log_command(int argc, char **argv, int result, long long int timespan) 456 | { 457 | const int def_cmd_buf_len = 100; 458 | int cmd_buf_len = def_cmd_buf_len; 459 | int cmd_len = 0; 460 | 461 | char *command = malloc(cmd_buf_len); 462 | if (!command) { 463 | sedcli_printf(LOG_ERR, "sedcli: Memory allocation failed for logging."); 464 | return; 465 | } 466 | 467 | for (int i = 0 ; i != argc ; ++i) { 468 | int tok_len = strnlen(argv[i], MAX_STR_LEN); 469 | /* if reconstructed command width is longer than current 470 | * cmd_buf_len (length of command buffer), than resize it 471 | * to make it twice as big. 472 | */ 473 | if (tok_len + 1 + cmd_len > cmd_buf_len) { 474 | cmd_buf_len = (tok_len + 1 + cmd_buf_len) * 2; 475 | char *tmp = realloc(command, cmd_buf_len); 476 | /* if reallocation failed, cancel logging */ 477 | if (!tmp) { 478 | sedcli_printf(LOG_ERR, "sedcli: Memory allocation failed for logging."); 479 | free(command); 480 | return; 481 | } 482 | command = tmp; 483 | } 484 | /* append additional token to a string */ 485 | /*memcpy_s(command + cmd_len, cmd_buf_len - cmd_len, 486 | argv[i], tok_len);*/ 487 | memcpy(command + cmd_len, argv[i], tok_len); 488 | cmd_len += tok_len; 489 | /* either a space or a null terminator */ 490 | command[cmd_len] = (i == argc - 1) ? 0 : ' '; 491 | cmd_len++; 492 | } 493 | 494 | sedcli_log(LOG_DEBUG, "sedcli invoked with: \"%s\". " 495 | "Exit status is %d (%s). Command took %lld.%02lld s.", 496 | command, result, result? "failure" : "success", 497 | timespan / 1000, (timespan % 1000) / 10); 498 | free(command); 499 | } 500 | 501 | static const char *sed_statuses[] = { 502 | /* 0x00 */ [SED_SUCCESS] = "SUCCESS", 503 | /* 0x01 */ [SED_NOT_AUTHORIZED] = "NOT_AUTHORIZED", 504 | /* 0x02 */ [SED_UNKNOWN_ERROR] = "OBSOLETE", // as in spec 505 | /* 0x03 */ [SED_SP_BUSY] = "SP_BUSY", 506 | /* 0x04 */ [SED_SP_FAILED] = "SP_FAILED", 507 | /* 0x05 */ [SED_SP_DISABLED] = "SP_DISABLED", 508 | /* 0x06 */ [SED_SP_FROZEN] = "SP_FROZEN", 509 | /* 0x07 */ [SED_NO_SESSIONS_AVAILABLE] = "NO_SESSIONS_AVAILABLE", 510 | /* 0x08 */ [SED_UNIQUENESS_CONFLICT] = "UNIQUENESS_CONFLICT", 511 | /* 0x09 */ [SED_INSUFFICIENT_SPACE] = "INSUFFICIENT_SPACE", 512 | /* 0x0A */ [SED_INSUFFICIENT_ROWS] = "INSUFFICIENT_ROWS", 513 | /* 0x0B */ [SED_INVALID_FUNCTION] = "OBSOLETE", // not in spec 514 | /* 0x0C */ [SED_INVALID_PARAMETER] = "INVALID PARAMETER", 515 | /* 0x0D */ [SED_INVALID_REFERENCE] = "OBSOLETE", // as in spec 516 | /* 0x0E */ [SED_UNKNOWN_ERROR_1] = "OBSOLETE", // as in spec 517 | /* 0x0F */ [SED_TPER_MALFUNCTION] = "TPER_MALFUNCTION", 518 | /* 0x10 */ [SED_TRANSACTION_FAILURE] = "TRANSACTION_FAILURE", 519 | /* 0x11 */ [SED_RESPONSE_OVERFLOW] = "RESPONSE_OVERFLOW", 520 | /* 0x12 */ [SED_AUTHORITY_LOCKED_OUT] = "AUTHORITY_LOCKED_OUT", 521 | /* 0x3F */ [SED_FAIL] = "FAIL", 522 | }; 523 | 524 | const char *sed_error_text(int sed_status) 525 | { 526 | if (sed_status < SED_SUCCESS || sed_status > SED_FAIL) 527 | return NULL; 528 | 529 | return sed_statuses[sed_status]; 530 | } 531 | 532 | typedef union { 533 | struct { 534 | uint8_t SC : 8; 535 | uint8_t SCT : 3; 536 | uint8_t CRD : 2; 537 | uint8_t M : 1; 538 | uint8_t DNR : 1; 539 | uint8_t Reserved : 1; 540 | } error_bits; 541 | uint16_t status; 542 | } nvme_error_status; 543 | 544 | extern uint32_t nvme_error; 545 | static void print_sed_status(int status) 546 | { 547 | const char *sed_status = NULL; 548 | 549 | if (status < 0) { 550 | if (sed_cli == SED_CLI_STANDARD) { 551 | if (status == -EINVAL) 552 | sedcli_printf(LOG_ERR, "sedcli: Invalid parameter.\n"); 553 | else if (status == -ENODEV) 554 | sedcli_printf(LOG_ERR, "sedcli: Couldn't determine device state.\n"); 555 | else if (status == -ENOMEM) 556 | sedcli_printf(LOG_ERR, "sedcli: No memory.\n"); 557 | else 558 | sedcli_printf(LOG_ERR, "sedcli: Unknown error.\n"); 559 | } else { 560 | if (status == KMIP_FAILURE) 561 | sedcli_printf(LOG_ERR, "sedcli-kmip: Failure.\n"); 562 | else 563 | sedcli_printf(LOG_ERR, "sedcli-kmip: Unknown error.\n"); 564 | } 565 | } else if (sed_cli == SED_CLI_KMIP && status >= KMIP_SUCCESS) { 566 | if (status == KMIP_SUCCESS_CONNECTED) 567 | sedcli_printf(LOG_ERR, "sedcli-kmip: Successful connection to the KMIP server.\n"); 568 | } else { 569 | if (nvme_error == 4) 570 | { 571 | sedcli_printf(LOG_ERR, "sedcli: IOCTL error: 0x04 Interrupted system call.\n"); 572 | return; 573 | } else if (nvme_error == 5) { 574 | sedcli_printf(LOG_ERR, "sedcli: IOCTL error: 0x05 I/O error.\n"); 575 | return; 576 | } 577 | 578 | sed_status = sed_error_text(status); 579 | if (sed_status == NULL && status > 0 && status <= 0xFFFF) { 580 | if (nvme_error) { 581 | nvme_error_status nes = { 0 }; 582 | nes.status = (uint32_t)status; 583 | sedcli_printf(LOG_ERR, "sedcli: NVMe error: %d\nSC: %d | SCT: %d | CRD: %d | M: %d | DNR: %d\n", 584 | status, nes.error_bits.SC, nes.error_bits.SCT, nes.error_bits.CRD, nes.error_bits.M, nes.error_bits.DNR); 585 | } 586 | else 587 | sedcli_printf(LOG_ERR, "status: Unknown status: %d\n", status); 588 | } 589 | else 590 | sedcli_printf((status == 0) ? LOG_INFO : LOG_ERR, "status: 0x%02x %s\n", status, sed_status); 591 | } 592 | } 593 | 594 | /** 595 | * run command. Additionally log its execution and report any errors if 596 | * they've happened 597 | */ 598 | #ifndef CLOCK_REALTIME 599 | #define CLOCK_REALTIME 0 600 | #endif 601 | int run_command(cli_command *commands, int cmd, int argc, char **argv) 602 | { 603 | int result; 604 | const char *syslog_path = "/var/log/messages"; 605 | /* time buffer and stat buffer after running command */ 606 | struct timespec t0; 607 | FILE *messages_f; 608 | /* time buffer and stat buffer after running command */ 609 | struct timespec t1; 610 | long long int timespan; 611 | 612 | /* collect time */ 613 | clock_gettime(CLOCK_REALTIME, &t0); 614 | /* collect stat buffer for syslog */ 615 | messages_f = fopen(syslog_path, "r"); 616 | if (messages_f) { 617 | fseek(messages_f, 0, SEEK_END); 618 | /* if opening file failed, don't stop command execution. 619 | * - just omit checking for /var/log/messages at the end 620 | */ 621 | } else { 622 | /* ubuntu case*/ 623 | syslog_path = "/var/log/syslog"; 624 | messages_f = fopen(syslog_path, "r"); 625 | if (messages_f) 626 | fseek(messages_f, 0, SEEK_END); 627 | } 628 | 629 | /* execute command */ 630 | result = commands[cmd].handle(); 631 | if (is_help(argv[1]) == false && is_version(argv[1]) == false) 632 | print_sed_status(result); 633 | 634 | clock_gettime(CLOCK_REALTIME, &t1); 635 | timespan = (1000 * (t1.tv_sec - t0.tv_sec) + (t1.tv_nsec - t0.tv_nsec) / 1000000); 636 | 637 | if (commands[cmd].short_name != 'V') 638 | log_command(argc, argv, result, timespan); 639 | 640 | if (messages_f) 641 | fclose(messages_f); 642 | 643 | return result; 644 | } 645 | 646 | static int count_arg_params(char **argv, int argc) 647 | { 648 | int i = 0; 649 | 650 | for (; i < argc; i++) 651 | if ('-' == argv[i][0] && 0 != argv[i][1]) { 652 | return i; 653 | } 654 | 655 | return i; 656 | } 657 | 658 | void configure_cli_commands(cli_command *commands) 659 | { 660 | cli_command *cmd = commands; 661 | while(cmd && cmd->name) { 662 | if (cmd->configure) { 663 | if (cmd->configure(cmd) < 0) { 664 | cmd->flags |= CLI_COMMAND_HIDDEN; 665 | } 666 | } 667 | cmd++; 668 | } 669 | } 670 | 671 | int args_parse(app *app_values, cli_command *commands, int argc, char **argv) 672 | { 673 | int i, j, k, status = SUCCESS; 674 | int args_count, args_offset; 675 | char **args_list = NULL; 676 | const char* cmd_name = argv[1]; 677 | cli_ns_entry *entry = NULL; 678 | cli_option *options; 679 | int cmd = -1, first_opt; 680 | 681 | if (argc < 2) { 682 | sedcli_printf(LOG_ERR, "sedcli: No command given.\n"); 683 | print_info(app_values); 684 | return FAILURE; 685 | } 686 | 687 | if (args_is_unrecognized(cmd_name)) { 688 | sedcli_printf(LOG_ERR, "sedcli: Unrecognized command %s.\n", cmd_name); 689 | print_info(app_values); 690 | return FAILURE; 691 | } 692 | 693 | for (i = 0;; ++i) { 694 | if (commands[i].name == NULL) { 695 | if (is_help(cmd_name)) { 696 | print_help(app_values, commands); 697 | return SUCCESS; 698 | } 699 | break; 700 | } else if (args_is(cmd_name, commands[i].name, commands[i].short_name)) { 701 | cmd = i; 702 | break; 703 | } 704 | } 705 | 706 | if (cmd == -1) { 707 | sedcli_printf(LOG_ERR, "sedcli: Unrecognized command %s.\n", cmd_name); 708 | print_info(app_values); 709 | return FAILURE; 710 | } 711 | 712 | configure_cli_commands(commands); 713 | 714 | if (argc >= 3 && get_help_position(argc, argv) != -1) { 715 | if (!is_command_hidden(commands, i)) { 716 | print_command_help(app_values, &commands[i]); 717 | } 718 | return SUCCESS; 719 | } 720 | 721 | if (is_su_required(commands, cmd)) { 722 | if (getuid() != 0) { 723 | sedcli_printf(LOG_ERR, "sedcli: Must be run as root.\n"); 724 | return FAILURE; 725 | } 726 | } 727 | 728 | if (commands[cmd].options) { 729 | options = commands[cmd].options; 730 | first_opt = 2; 731 | } else if (commands[cmd].namespace) { 732 | if (argc < 3) { 733 | sedcli_printf(LOG_ERR, "sedcli: Missing namespace option.\n"); 734 | print_info(app_values); 735 | return FAILURE; 736 | } 737 | 738 | if (argc < 4) { 739 | sedcli_printf(LOG_ERR, "sedcli: Missing namespace name.\n"); 740 | print_info(app_values); 741 | return FAILURE; 742 | } 743 | 744 | if (!args_is(argv[2], commands[cmd].namespace->long_name, commands[cmd].namespace->short_name)) { 745 | sedcli_printf(LOG_ERR, "sedcli: Unrecognized option.\n"); 746 | print_info(app_values); 747 | return FAILURE; 748 | } 749 | 750 | entry = commands[cmd].namespace->entries; 751 | while (true) { 752 | if (!strncmp(argv[3], entry->name, 255)) 753 | break; 754 | 755 | if (!(++entry)->name) { 756 | sedcli_printf(LOG_ERR, "sedcli: Unrecognized namespace entry.\n"); 757 | print_info(app_values); 758 | return FAILURE; 759 | } 760 | } 761 | 762 | options = entry->options; 763 | first_opt = 4; 764 | } else { 765 | return run_command(commands, cmd, argc, argv); 766 | } 767 | 768 | /* for each possible option: 769 | * - if it is required, check if it is supplied exactly once 770 | * - if it is not required, check if it is supplied at most once 771 | */ 772 | for (i = 0; options[i].long_name; ++i) { 773 | char option_name[MAX_STR_LEN]; 774 | 775 | /* count occurrences of an option (k as counter) */ 776 | k = 0; 777 | for (j = first_opt; j < argc; ++j) { 778 | if (args_is(argv[j], options[i].long_name, options[i].short_name)) { 779 | k++; 780 | } 781 | } 782 | 783 | command_name_with_slash(option_name, MAX_STR_LEN, options[i].short_name, options[i].long_name); 784 | 785 | if (options[i].flags & CLI_OPTION_REQUIRED) { 786 | if (!k) { 787 | sedcli_printf(LOG_ERR, "sedcli: Missing required option %s.\n", option_name); 788 | print_info(app_values); 789 | return FAILURE; 790 | } 791 | } 792 | 793 | if (options[i].args_count != 0 && k > options[i].args_count) { 794 | sedcli_printf(LOG_ERR, "sedcli: Option supplied too many times %s.\n", option_name); 795 | print_info(app_values); 796 | return FAILURE; 797 | } 798 | } 799 | 800 | /* Store parameters for arguments. Terminate each list with NULL element. 801 | * Accomodate for max no of parameters */ 802 | args_list = malloc(sizeof(*args_list) * (argc + 1)); 803 | if (args_list == NULL) { 804 | return FAILURE; 805 | } 806 | 807 | /* iterate over all arguments that were actually passed to the CLI */ 808 | args_count = args_offset = 0; 809 | for (i = first_opt; i < argc; ++i) { 810 | if (args_is_unrecognized(argv[i])) { 811 | sedcli_printf(LOG_ERR, "sedcli: Invalid format %s.\n", argv[i]); 812 | print_info(app_values); 813 | 814 | status = FAILURE; 815 | goto free_args; 816 | } 817 | 818 | int opt = get_option(options, argv[i]); 819 | if (opt == -1) { 820 | sedcli_printf(LOG_ERR, "sedcli: Unrecognized option %s.\n", argv[i]); 821 | print_info(app_values); 822 | 823 | status = FAILURE; 824 | goto free_args; 825 | } 826 | 827 | if (options[opt].arg != NULL) { 828 | /* Count params for current argument. */ 829 | args_count = count_arg_params(&argv[i + 1], argc - i - 1); 830 | bool invalid = false; 831 | 832 | if (options[opt].args_count > 0) 833 | { 834 | if (options[opt].flags & CLI_OPTION_REQUIRED || 835 | options[opt].flags & CLI_OPTION_OPTIONAL) { 836 | if (args_count == 0) { 837 | invalid = true; 838 | } 839 | } 840 | 841 | if (args_count > options[opt].args_count) { 842 | invalid = true; 843 | } 844 | } 845 | 846 | if (invalid) { 847 | sedcli_printf(LOG_ERR, "sedcli: Invalid number of arguments for %s.\n", argv[i]); 848 | print_info(app_values); 849 | 850 | status = FAILURE; 851 | goto free_args; 852 | } 853 | 854 | /* Add params for current argument. 855 | * Terminate list with NULL element.*/ 856 | for (k = args_offset, j = 0; j < args_count; j++) { 857 | args_list[k++] = argv[j + i + 1]; 858 | } 859 | args_list[args_offset + args_count] = NULL; 860 | 861 | i += args_count; 862 | } 863 | 864 | if (commands[cmd].options_parse) { 865 | status = commands[cmd].options_parse( 866 | options[opt].long_name, 867 | &args_list[args_offset]); 868 | } else if (commands[cmd].namespace_opts_parse && entry != NULL) { 869 | status = commands[cmd].namespace_opts_parse( 870 | entry->name, 871 | options[opt].long_name, 872 | &args_list[args_offset]); 873 | } else { 874 | sedcli_printf(LOG_ERR, "sedcli: Internal error.\n"); 875 | status = FAILURE; 876 | goto free_args; 877 | } 878 | args_offset += args_count; 879 | 880 | if (0 != status) { 881 | sedcli_printf(LOG_ERR, "sedcli: Error during options handling.\n"); 882 | print_info(app_values); 883 | 884 | status = FAILURE; 885 | goto free_args; 886 | } 887 | } 888 | 889 | status = run_command(commands, cmd, argc, argv); 890 | 891 | free_args: 892 | if (NULL != args_list) { 893 | free(args_list); 894 | args_list = NULL; 895 | } 896 | 897 | return status; 898 | } 899 | -------------------------------------------------------------------------------- /src/argp.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2019, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #ifndef _ARGP_H 8 | #define _ARGP_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | 16 | #define MAX_STR_LEN PATH_MAX 17 | 18 | __attribute__((format(printf, 2, 3))) 19 | typedef int (*sedcli_printf_t)(int log_level, const char *format, ...); 20 | 21 | enum CLI_OPTION_FLAGS { 22 | CLI_OPTION_REQUIRED = 1 << 0, 23 | CLI_OPTION_HIDDEN = 1 << 1, 24 | CLI_OPTION_RANGE_INT = 1 << 2, /*! if option has a min/max value */ 25 | CLI_OPTION_DEFAULT_INT = 1 << 3, /*! if option has a default value */ 26 | CLI_OPTION_OPTIONAL = 1 << 4 /*! if option argument is optional */ 27 | }; 28 | 29 | enum CLI_COMMAND_FLAGS { 30 | CLI_SU_REQUIRED = 1 << 0, 31 | CLI_COMMAND_HIDDEN = 1 << 1 32 | }; 33 | 34 | #define ERROR -1 35 | #define SUCCESS 0 36 | #define FAILURE 1 37 | 38 | /** 39 | * structure representing each single option for CLI command (i.e. -i, -j for -R) 40 | */ 41 | typedef struct { 42 | char short_name; /*!< short option name, one-letter. i.e. 'i' representing -i 43 | *!< as --cache-id */ 44 | char* long_name; /*!< long option name (in above described case it would be 45 | *!< "cache-id" */ 46 | char* desc; /*!< description of an option (longer text... 47 | *!< may contain single %d for default value and/or pair of %d marks 48 | *!< for range of correct values. If it has both, default must come 49 | *!< after the range, so be careful about wording such messages) */ 50 | int args_count; /*!< number of arguments (0 - no arguments, -1 - unspecified) */ 51 | char* arg; /*!< type of an argument, descriptive. i.e. "NUM", "NAME" */ 52 | int flags; /*!< as per CLI_OPTION_FLAGS */ 53 | } cli_option; 54 | 55 | /* 56 | * In namespace entries options array is nested in another flexible array 57 | * (array of entries), so it cannot be flexible array itself. Because of that 58 | * we make it static array of options with reasonable lenght. 59 | */ 60 | #define MAX_OPTIONS 32 61 | 62 | typedef struct { 63 | char* name; /*!< namespace entry name */ 64 | char* desc; /*!< description of an namespace entry */ 65 | cli_option options[MAX_OPTIONS]; /*!< pointer to first element in null-terminated array of cli_option */ 66 | } cli_ns_entry; 67 | 68 | typedef struct { 69 | char short_name; /*!< short name of namespace */ 70 | char* long_name; /*!< long name of namespace */ 71 | cli_ns_entry entries[]; /*!< null-terminated array of namespace entries */ 72 | } cli_namespace; 73 | 74 | typedef struct { 75 | const char* name; 76 | char* info; 77 | char* title; 78 | char* doc; 79 | char* man; 80 | int block; 81 | } app; 82 | 83 | struct _cli_command; 84 | typedef struct _cli_command cli_command; 85 | 86 | /** 87 | * structure representing each CLI command, i.e. -S, -T... 88 | */ 89 | struct _cli_command { 90 | char* name; /*!< name of command (i.e. "start-cache" for --start-cache) */ 91 | char short_name; /*!< short name of command (i.e. "S" for -S/--start-cache) */ 92 | char* desc; /*!< description that appears with "casadm -H" invocation */ 93 | char* long_desc; /*!< option descripotion that appears with "casadm -O -H invocation */ 94 | cli_option* options; /*!< pointer to first element in null-terminated array of cli_option */ 95 | int (*options_parse)(char*, char**); /*! function pointer to function that processes options to command */ 96 | cli_namespace* namespace; /*! namespace description */ 97 | int (*namespace_opts_parse)(char*, char*, char**); /*! function pointer to function that processes options to namespace */ 98 | int (*handle)(void); /*! function pointer to function that executes a command */ 99 | int flags; /*! command flags, as per CLI_COMMAND_FLAGS */ 100 | void (*help)(app *app_values, cli_command *cmd); /*! Custom help provider */ 101 | int (*configure)(cli_command *cmd); /*! function pointer to function that configures command */ 102 | }; 103 | 104 | /** 105 | * Check if string is empty 106 | * 107 | * @param str - reference to the string 108 | * @retval 1 string is empty 109 | * @retval 0 string is not empty 110 | */ 111 | static inline int strempty(const char *str) 112 | { 113 | if (NULL == str) { 114 | return 1; 115 | } else if ('\0' == str[0]) { 116 | return 1; 117 | } else { 118 | return 0; 119 | } 120 | } 121 | 122 | char *command_name_in_brackets(char *buf, size_t buf_size, char short_name, char *long_name); 123 | void print_help(const app *app_values, const cli_command *commands); 124 | void print_options_usage(cli_option* options, const char *separator, int (*view)(cli_option* options, int flag), int flag); 125 | void print_list_options(cli_option* options, int flag, int (*view)(cli_option* options, int flag)); 126 | void print_command_header(const cli_command *cmd); 127 | void configure_cli_commands(cli_command *commands); 128 | int args_parse(app *app_values, cli_command *commands, int argc, char **argv); 129 | 130 | #endif 131 | -------------------------------------------------------------------------------- /src/config_file.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include 14 | #include 15 | #include 16 | 17 | #include "config_file.h" 18 | #include "lib/sedcli_log.h" 19 | 20 | #define SEDCLI_CONF_DELIM "=" 21 | 22 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) 23 | 24 | enum { 25 | KMIP_IP = 0, 26 | KMIP_PORT, 27 | CLIENT_CERT, 28 | CLIENT_KEY, 29 | CA_CERT, 30 | UNDEFINED 31 | }; 32 | 33 | enum { 34 | PEK_ID = 0 35 | }; 36 | 37 | static char *line_prefix[] = { 38 | [KMIP_IP] = "kmip_ip", 39 | [KMIP_PORT] = "kmip_port", 40 | [CLIENT_CERT] = "client_cert", 41 | [CLIENT_KEY] = "client_key", 42 | [CA_CERT] = "ca_cert", 43 | }; 44 | 45 | static char *line_dynamic_prefix[] = { 46 | [PEK_ID] = "pek_id" 47 | }; 48 | 49 | static int get_line_type(char *line, int char_no) 50 | { 51 | int i, size; 52 | 53 | size = ARRAY_SIZE(line_prefix); 54 | 55 | for (i = 0; i < size; i++) 56 | if (strncmp(line_prefix[i], line, char_no) == 0) 57 | return i; 58 | 59 | return UNDEFINED; 60 | } 61 | 62 | static int get_line_dynamic_type(char *line, int char_no) 63 | { 64 | int i, size; 65 | 66 | size = ARRAY_SIZE(line_dynamic_prefix); 67 | 68 | for (i = 0; i < size; i++) 69 | if (strncmp(line_dynamic_prefix[i], line, char_no) == 0) 70 | return i; 71 | 72 | return UNDEFINED; 73 | } 74 | 75 | static int process_line_stat(struct sedcli_stat_conf *conf, char *line, int len) 76 | { 77 | int offset, type, bytes_no, status = 0; 78 | char *found; 79 | 80 | found = strstr(line, SEDCLI_CONF_DELIM); 81 | if (found == NULL) 82 | return -1; 83 | 84 | /* Calculate len and move pointer after delimiter */ 85 | offset = found - line; 86 | found++; 87 | 88 | /* Calculate len of configuration option value */ 89 | bytes_no = len - offset - 1; 90 | 91 | /* Eliminate newline character if present */ 92 | if (line[len - 1] == '\n') 93 | bytes_no--; 94 | 95 | type = get_line_type(line, offset); 96 | switch (type) { 97 | case KMIP_IP: 98 | if (bytes_no <= MAX_IP_LEN) 99 | memcpy(conf->kmip_ip, found, bytes_no); 100 | else 101 | status = -EINVAL; 102 | break; 103 | case KMIP_PORT: 104 | if (bytes_no <= MAX_PORT_LEN) 105 | memcpy(conf->kmip_port, found, bytes_no); 106 | else 107 | status = -EINVAL; 108 | break; 109 | case CLIENT_CERT: 110 | if (bytes_no <= MAX_PATH_LEN) 111 | memcpy(conf->client_cert_path, found, bytes_no); 112 | else 113 | status = -EINVAL; 114 | break; 115 | case CLIENT_KEY: 116 | if (bytes_no <= MAX_PATH_LEN) 117 | memcpy(conf->client_key_path, found, bytes_no); 118 | else 119 | status = -EINVAL; 120 | break; 121 | case CA_CERT: 122 | if (bytes_no <= MAX_PATH_LEN) 123 | memcpy(conf->ca_cert_path, found, bytes_no); 124 | else 125 | status = -EINVAL; 126 | break; 127 | default: 128 | return -1; 129 | } 130 | 131 | return status; 132 | } 133 | 134 | static int process_line_dyn(struct sedcli_dyn_conf *conf, char *line, int len) 135 | { 136 | char *found = strstr(line, SEDCLI_CONF_DELIM); 137 | if (found == NULL) 138 | return -1; 139 | 140 | /* Calculate len and move pointer after delimiter */ 141 | int offset = found - line; 142 | found++; 143 | 144 | /* Calculate len of configuration option value */ 145 | int bytes_no = len - offset - 1; 146 | 147 | /* Eliminate newline character if present */ 148 | if (line[len - 1] == '\n') 149 | bytes_no--; 150 | 151 | int type = get_line_dynamic_type(line, offset); 152 | switch (type) { 153 | case PEK_ID: 154 | if (bytes_no <= MAX_PEK_ID_LEN) { 155 | memcpy(conf->pek_id, found, bytes_no); 156 | SEDCLI_DEBUG_PARAM("pek_id: %s", found); 157 | if (bytes_no < MAX_PEK_ID_LEN) 158 | conf->pek_id[bytes_no] = 0; 159 | conf->pek_id[MAX_PEK_ID_LEN - 1] = '\0'; 160 | conf->pek_id_size = strlen(conf->pek_id); 161 | } else { 162 | conf->pek_id_size = 0; 163 | return -EINVAL; 164 | } 165 | break; 166 | 167 | default: 168 | return 0; 169 | } 170 | 171 | return 0; 172 | } 173 | 174 | int read_stat_config(struct sedcli_stat_conf *conf) 175 | { 176 | char *conf_file = SEDCLI_DEF_STAT_CONFIG_FILE; 177 | FILE *file = fopen(conf_file, "r"); 178 | if (file == NULL) { 179 | conf_file = SEDCLI_BKP_STAT_CONFIG_FILE; 180 | file = fopen(conf_file, "r"); 181 | if (file == NULL) 182 | return -ENOENT; 183 | } 184 | 185 | int status = 0; 186 | char *line = NULL; 187 | size_t len = 0; 188 | ssize_t read; 189 | while ((read = getline(&line, &len, file)) != -1) { 190 | /* Ignore comment lines */ 191 | if (line[0] != '#' && line[0] != '\n') { 192 | status = process_line_stat(conf, line, read); 193 | if (status != 0) { 194 | SEDCLI_DEBUG_PARAM("error %d while processing line %s\n", status, line); 195 | status = -EINVAL; 196 | break; 197 | } 198 | } 199 | } 200 | 201 | free(line); 202 | 203 | fclose(file); 204 | 205 | return status; 206 | } 207 | 208 | int read_dyn_config(struct sedcli_dyn_conf *conf) 209 | { 210 | char *conf_file = SEDCLI_DEF_DYN_CONFIG_FILE; 211 | SEDCLI_DEBUG_PARAM("Opening config file: %s\n", conf_file); 212 | FILE *file = fopen(conf_file, "r"); 213 | if (file == NULL) { 214 | conf_file = SEDCLI_BKP_DYN_CONFIG_FILE; 215 | file = fopen(conf_file, "r"); 216 | if (file == NULL) 217 | return -ENOENT; 218 | } 219 | 220 | int status = 0; 221 | char *line = NULL; 222 | size_t len = 0; 223 | ssize_t read; 224 | while ((read = getline(&line, &len, file)) != -1) { 225 | /* Ignore comment lines */ 226 | if (line[0] != '#' && line[0] != '\n') { 227 | size_t line_len = strlen(line); 228 | if (line_len == 0 || line_len > 256) { 229 | SEDCLI_DEBUG_PARAM("error %d while processing line %s - length.\n", status, line); 230 | status = -EINVAL; 231 | break; 232 | } else { 233 | SEDCLI_DEBUG_PARAM("Processing line: %s", line); 234 | status = process_line_dyn(conf, line, read); 235 | if (status != 0) { 236 | SEDCLI_DEBUG_PARAM("error %d while processing line %s.\n", status, line); 237 | status = -EINVAL; 238 | break; 239 | } 240 | } 241 | } 242 | } 243 | 244 | free(line); 245 | 246 | fclose(file); 247 | 248 | return status; 249 | } 250 | 251 | int write_dyn_conf(const char *data, int data_size) 252 | { 253 | FILE *file; 254 | char *conf_file = SEDCLI_DEF_DYN_CONFIG_FILE; 255 | int bytes_written; 256 | 257 | file = fopen(conf_file, "w+"); 258 | if (file == NULL) { 259 | conf_file = SEDCLI_BKP_DYN_CONFIG_FILE; 260 | 261 | file = fopen(conf_file, "w+"); 262 | 263 | if (file == NULL) 264 | return -ENOENT; 265 | } 266 | 267 | fwrite("pek_id=", 7, 1, file); 268 | bytes_written = fwrite(data, 1, data_size, file); 269 | fwrite("\n", 1, 1, file); 270 | 271 | fclose(file); 272 | 273 | if (bytes_written != data_size) 274 | return -ENOSPC; 275 | 276 | return 0; 277 | } 278 | -------------------------------------------------------------------------------- /src/config_file.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #ifndef _CONFIG_FILE_H_ 8 | #define _CONFIG_FILE_H_ 9 | 10 | #define MAX_PATH_LEN (4096) 11 | #define MAX_IP_LEN (255) 12 | #define MAX_PORT_LEN (255) 13 | 14 | #define MAX_PEK_ID_LEN (255) 15 | 16 | #define SEDCLI_DEF_STAT_CONFIG_FILE "/etc/sedcli/sedcli.conf" 17 | #define SEDCLI_BKP_STAT_CONFIG_FILE "../etc/sedcli/sedcli.conf" 18 | 19 | #define SEDCLI_DEF_DYN_CONFIG_FILE "/etc/sedcli/sedcli_kmip" 20 | #define SEDCLI_BKP_DYN_CONFIG_FILE "../etc/sedcli/sedcli_kmip" 21 | 22 | struct sedcli_stat_conf { 23 | char kmip_ip[MAX_IP_LEN]; 24 | char kmip_port[MAX_PORT_LEN]; 25 | 26 | char client_cert_path[MAX_PATH_LEN]; 27 | char client_key_path[MAX_PATH_LEN]; 28 | 29 | char ca_cert_path[MAX_PATH_LEN]; 30 | }; 31 | 32 | struct sedcli_dyn_conf { 33 | char pek_id[MAX_PEK_ID_LEN]; 34 | int pek_id_size; 35 | }; 36 | 37 | int read_stat_config(struct sedcli_stat_conf *conf); 38 | 39 | int read_dyn_config(struct sedcli_dyn_conf *conf); 40 | 41 | int write_dyn_conf(const char *data, int data_size); 42 | 43 | #endif /* _CONFIG_FILE_H_ */ 44 | -------------------------------------------------------------------------------- /src/configure: -------------------------------------------------------------------------------- 1 | #!/bin/bash 2 | 3 | # 4 | # Copyright (C) 2018-2019, 2022-2023 Solidigm. All Rights Reserved. 5 | # 6 | # SPDX-License-Identifier: GPL-2.0-or-later 7 | # 8 | 9 | TMP_SRC="`mktemp`.c" 10 | TMP_BIN="`mktemp`" 11 | 12 | CONFIG_LOG="config.log" 13 | CONFIG_MK="config.mk" 14 | CONFIG_H="config.h" 15 | 16 | cc=gcc 17 | 18 | rm -fr ${CONFIG_LOG} ${CONFIG_MK} ${CONFIG_H} 19 | touch ${CONFIG_LOG} 20 | 21 | touch ${CONFIG_H} 22 | touch ${CONFIG_MK} 23 | 24 | function app_config_mk() { 25 | echo "${1}" >> ${CONFIG_MK} 26 | } 27 | 28 | function app_config_h() { 29 | echo "$1" >> ${CONFIG_H} 30 | } 31 | 32 | function print_status() { 33 | printf "%-30s%s\n" "$1" "$2" 34 | } 35 | 36 | function test_compile() { 37 | echo "Compiling test case $1" >> config.log 38 | 39 | if [ "$4" != "" ]; then 40 | src=$4 41 | else 42 | src=$TMP_SRC 43 | fi 44 | 45 | $cc $2 $3 -o $TMP_BIN $src >> config.log 2>&1 || return $? 46 | } 47 | 48 | function generate_version() { 49 | SEDCLI_KMIP_VERSION="1.2" 50 | echo "#define SEDCLI_KMIP_VERSION (\"${SEDCLI_KMIP_VERSION}\")" >> ${CONFIG_H} 51 | 52 | SEDCLI_VERSION="1.2" 53 | echo "#define SEDCLI_VERSION (\"${SEDCLI_VERSION}\")" >> ${CONFIG_H} 54 | } 55 | 56 | function common_def() { 57 | app_config_h "#define _GNU_SOURCE" 58 | app_config_h "#define __CHECK_ENDIAN__" 59 | } 60 | 61 | function common_mk() { 62 | app_config_mk "INCLUDES=./lib/include" 63 | app_config_mk "CFLAGS+=-include ${CONFIG_H}" 64 | # Fixes some errors in newer GCC versions 65 | app_config_mk "CFLAGS+=-fcommon" 66 | 67 | app_config_mk "CFLAGS+=-g -std=c17" 68 | if [ "${sedcli_logging}" == "yes" ]; then 69 | # asan, ubsan 70 | app_config_mk "CFLAGS+=-fstack-protector-all" 71 | fi 72 | 73 | app_config_mk "LDFLAGS+=-L." 74 | # Fixes some errors in newer GCC versions 75 | app_config_mk "LDFLAGS+=-fcommon" 76 | if [ -f /etc/lsb-release ] && [ -n "`cat /etc/lsb-release | grep -i ubuntu`" ]; then 77 | app_config_mk "LIB_DIR=/lib/x86_64-linux-gnu" 78 | else 79 | app_config_mk "LIB_DIR=/usr/lib64" 80 | fi 81 | 82 | if [ "${sedcli_logging}" == "yes" ]; then 83 | # asan, ubsan 84 | app_config_mk "LDFLAGS+=-fsanitize=address -fsanitize=undefined" 85 | app_config_mk "CFLAGS+=-fsanitize=address -fsanitize=undefined" 86 | 87 | # enable all warnings 88 | app_config_mk "CFLAGS+=-Wall -Werror -Wextra" 89 | 90 | # debug info 91 | app_config_mk "CFLAGS+=-O0" 92 | else 93 | app_config_mk "CFLAGS+=-O2" 94 | fi 95 | } 96 | 97 | function print_help() { 98 | echo "Configures sedcli/sedcli-kmip build procedure." 99 | echo "Options:" 100 | echo " --enable-logging Turns on debug logging to stdout." 101 | echo " --offline Do not update kmip submodule." 102 | } 103 | 104 | function print_summary() { 105 | echo "" 106 | echo "Configuration written to: ${CONFIG_MK} ${CONFIG_H}" 107 | echo "See more details in ${CONFIG_LOG}" 108 | } 109 | 110 | # Default settings 111 | sedcli_logging="no" 112 | offline="no" 113 | 114 | # Process user specified options 115 | for option do 116 | case "$option" in 117 | --enable-logging) sedcli_logging="yes" 118 | ;; 119 | --offline) offline="yes" 120 | ;; 121 | --help) 122 | print_help 123 | exit 0 124 | ;; 125 | *) 126 | echo "Wrong option: ${option}" 127 | esac 128 | done 129 | 130 | # Common and basic stuff 131 | app_config_mk "CC=gcc" 132 | generate_version 133 | common_def 134 | common_mk 135 | 136 | # Handle library logging 137 | if [ "${sedcli_logging}" == "yes" ]; then 138 | app_config_h "#define SEDCLI_DEBUG_LOGGING" 139 | fi 140 | print_status "Debug logging" ${sedcli_logging} 141 | # ========================================== 142 | # Handle kmip 143 | ret_code=$? 144 | print_status "Offline" ${offline} 145 | if [ "${offline}" == "no" ]; then 146 | print_status " update repository start" 147 | # Clone libkmip repo 148 | pushd . > /dev/null 149 | cd ../ 150 | git submodule deinit --quiet --all --force 151 | git submodule update --quiet --init 152 | git submodule update --quiet --remote 153 | print_status " updating repository done" 154 | print_status " libkmip local install start" 155 | cd src/libkmip 156 | make all > /dev/null 157 | make PREFIX=local install > /dev/null 158 | print_status " libkmip local install done" 159 | cd .. 160 | cp ./libkmip/local/lib/libkmip.a* ./ 161 | ret_code=$? 162 | popd > /dev/null 163 | fi 164 | cat > $TMP_SRC < 167 | #include 168 | 169 | int main(int argc, char **argv) 170 | { 171 | printf("%s\n", OPENSSL_VERSION_TEXT); 172 | 173 | return 0; 174 | } 175 | EOF 176 | 177 | if [ "${ret_code}" -eq "0" ] && \ 178 | test_compile "openssl" "" "-lcrypto -lssl"; then 179 | openssl_ver="`${TMP_BIN}`" 180 | print_status "KMIP support" "yes (detected ${openssl_ver})" 181 | app_config_mk "CONFIG_KMIP=y" 182 | app_config_mk "INCLUDES+=./libkmip/local/include" 183 | app_config_mk "LDFLAGS_KMIP+=-lkmip -lcrypto -lssl" 184 | else 185 | print_status "KMIP support" "no" 186 | fi 187 | 188 | # ========================================== 189 | 190 | print_summary 191 | 192 | # Cleanup 193 | rm -fr ${TMP_SRC} ${TMP_BIN} 194 | -------------------------------------------------------------------------------- /src/crypto_lib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | #include 15 | 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | #include 22 | #include 23 | 24 | #include 25 | 26 | #include "crypto_lib.h" 27 | 28 | #define CRYPTO_BS (16) 29 | 30 | int get_random_bytes(uint8_t *buffer, size_t bytes_no) 31 | { 32 | if (RAND_priv_bytes(buffer, bytes_no)) 33 | return 0; 34 | else 35 | return -EOPNOTSUPP; 36 | } 37 | 38 | int derive_key(uint8_t *buffer, int buffer_len, uint8_t *salt, int salt_len, 39 | uint8_t *out, int out_len) 40 | { 41 | int status; 42 | int iterations = 10000; 43 | 44 | status = PKCS5_PBKDF2_HMAC((char *) buffer, buffer_len, salt, salt_len, 45 | iterations, EVP_sha512(), out_len, out); 46 | 47 | if (status == 0) { 48 | ERR_print_errors_fp(stderr); 49 | return -1; 50 | } 51 | 52 | return 0; 53 | } 54 | 55 | /* 56 | * Crypto_block_size is 16B, key is 32B, IV is 16B, DEK key (plain text) is 32B. 57 | * Padding is disabled, so the encrypted DEK key (cipher) size should be 32B 58 | */ 59 | int encrypt_dek(uint8_t *plain, int plain_size, 60 | uint8_t *auth_data, int auth_data_len, 61 | uint8_t *cipher, int cipher_size, 62 | uint8_t *key, int key_size, 63 | uint8_t *iv, int iv_size, 64 | uint8_t *tag, int tag_size) 65 | { 66 | int status, len, total_bytes = 0; 67 | EVP_CIPHER_CTX *ctx; 68 | 69 | /* Perform sanity checks for provided input */ 70 | if (plain_size % CRYPTO_BS != 0 || iv_size != CRYPTO_BS || 71 | cipher_size != plain_size || key_size != SED_KMIP_KEY_LEN || 72 | tag_size < TAG_SIZE) 73 | return -EINVAL; 74 | 75 | ctx = EVP_CIPHER_CTX_new(); 76 | if (ctx == NULL) { 77 | ERR_print_errors_fp(stderr); 78 | return -1; 79 | } 80 | 81 | status = EVP_EncryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); 82 | if (status != 1) { 83 | ERR_print_errors_fp(stderr); 84 | return -1; 85 | } 86 | 87 | status = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_size, NULL); 88 | if (status != 1) { 89 | ERR_print_errors_fp(stderr); 90 | return -1; 91 | } 92 | 93 | status = EVP_EncryptInit_ex(ctx, NULL, NULL, key, iv); 94 | if (status != 1) { 95 | ERR_print_errors_fp(stderr); 96 | return -1; 97 | } 98 | 99 | if (auth_data_len > 0) { 100 | /* Provide additional authenticated data for encryption */ 101 | status = EVP_EncryptUpdate(ctx, NULL, &len, auth_data, 102 | auth_data_len); 103 | if (status != 1) { 104 | ERR_print_errors_fp(stderr); 105 | return -1; 106 | } 107 | } 108 | 109 | status = EVP_EncryptUpdate(ctx, cipher, &len, plain, plain_size); 110 | total_bytes += len; 111 | 112 | if (status != 1) { 113 | ERR_print_errors_fp(stderr); 114 | return -1; 115 | } 116 | 117 | status = EVP_EncryptFinal_ex(ctx, &cipher[len], &len); 118 | total_bytes += len; 119 | 120 | if (status != 1) { 121 | ERR_print_errors_fp(stderr); 122 | return -1; 123 | } 124 | 125 | status = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_GET_TAG, tag_size, tag); 126 | if (status != 1) { 127 | ERR_print_errors_fp(stderr); 128 | return -1; 129 | } 130 | 131 | EVP_CIPHER_CTX_free(ctx); 132 | 133 | return total_bytes; 134 | } 135 | 136 | /* 137 | * Crypto_block_size is 16B, key is 32B, IV is 16B, encrypted DEK key (cipher 138 | * text) is 32B. Padding is disabled, so the plain text DEK key size should be 139 | * 32B. 140 | */ 141 | int decrypt_dek(uint8_t *cipher, int cipher_size, 142 | uint8_t *auth_data, int auth_data_len, 143 | uint8_t *plain, int plain_size, 144 | uint8_t *key, int key_size, 145 | uint8_t *iv, int iv_size, 146 | uint8_t *tag, int tag_size) 147 | { 148 | int status, len, total_bytes = 0; 149 | EVP_CIPHER_CTX *ctx; 150 | 151 | /* Perform sanity checks for provided input */ 152 | if (plain_size % CRYPTO_BS != 0 || iv_size != CRYPTO_BS || 153 | cipher_size != plain_size || key_size != SED_KMIP_KEY_LEN || 154 | tag_size < TAG_SIZE) 155 | return -EINVAL; 156 | 157 | ctx = EVP_CIPHER_CTX_new(); 158 | 159 | if (ctx == NULL) { 160 | ERR_print_errors_fp(stderr); 161 | return -1; 162 | } 163 | 164 | status = EVP_DecryptInit_ex(ctx, EVP_aes_256_gcm(), NULL, NULL, NULL); 165 | if (status != 1) { 166 | ERR_print_errors_fp(stderr); 167 | return -1; 168 | } 169 | 170 | status = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_IVLEN, iv_size, NULL); 171 | if (status != 1) { 172 | ERR_print_errors_fp(stderr); 173 | return -1; 174 | } 175 | 176 | status = EVP_DecryptInit_ex(ctx, NULL, NULL, key, iv); 177 | if (status != 1) { 178 | ERR_print_errors_fp(stderr); 179 | return -1; 180 | } 181 | 182 | if (auth_data_len > 0) { 183 | /* Provide additional authenticated data for encryption */ 184 | status = EVP_DecryptUpdate(ctx, NULL, &len, auth_data, 185 | auth_data_len); 186 | if (status != 1) { 187 | ERR_print_errors_fp(stderr); 188 | return -1; 189 | } 190 | } 191 | 192 | status = EVP_DecryptUpdate(ctx, plain, &len, cipher, cipher_size); 193 | total_bytes = len; 194 | 195 | if (status != 1) { 196 | ERR_print_errors_fp(stderr); 197 | return -1; 198 | } 199 | 200 | status = EVP_CIPHER_CTX_ctrl(ctx, EVP_CTRL_GCM_SET_TAG, tag_size, tag); 201 | if (status != 1) { 202 | ERR_print_errors_fp(stderr); 203 | return -1; 204 | } 205 | 206 | status = EVP_DecryptFinal_ex(ctx, &plain[len], &len); 207 | 208 | EVP_CIPHER_CTX_free(ctx); 209 | 210 | if (status > 0) { 211 | total_bytes += len; 212 | return total_bytes; 213 | } 214 | 215 | return -1; 216 | } 217 | 218 | -------------------------------------------------------------------------------- /src/crypto_lib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #ifndef _SEDCLI_CRYPTO_LIB_H_ 8 | #define _SEDCLI_CRYPTO_LIB_H_ 9 | 10 | #define SALT_SIZE (16) 11 | #define TAG_SIZE (16) 12 | #define IV_SIZE (16) 13 | 14 | #define SED_KMIP_KEY_LEN 32 15 | 16 | int derive_key(uint8_t *buffer, int buffer_len, uint8_t *salt, int salt_len, 17 | uint8_t *out, int out_len); 18 | 19 | int get_random_bytes(uint8_t *buffer, size_t bytes); 20 | 21 | int encrypt_dek(uint8_t *plain, int plain_size, 22 | uint8_t *auth_data, int auth_data_len, 23 | uint8_t *cipher, int cipher_size, 24 | uint8_t *key, int key_size, 25 | uint8_t *iv, int iv_size, 26 | uint8_t *tag, int tag_size); 27 | 28 | int decrypt_dek(uint8_t *cipher, int cipher_size, 29 | uint8_t *auth_data, int auth_data_len, 30 | uint8_t *plain, int plain_size, 31 | uint8_t *key, int key_size, 32 | uint8_t *iv, int iv_size, 33 | uint8_t *tag, int tag_size); 34 | 35 | #endif /* _SEDCLI_CRYPTO_LIB_H_ */ 36 | -------------------------------------------------------------------------------- /src/kmip_lib.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include 8 | 9 | #include 10 | 11 | #include 12 | #include 13 | 14 | #include 15 | 16 | #include "argp.h" 17 | #include "kmip_lib.h" 18 | #include "lib/sedcli_log.h" 19 | 20 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) 21 | 22 | extern sedcli_printf_t sedcli_printf; 23 | 24 | /* Use 256 bit key for symmetric encryption and decryption */ 25 | static enum cryptographic_algorithm algorithm = KMIP_CRYPTOALG_AES; 26 | static int32 length = 256; 27 | static int32 mask = KMIP_CRYPTOMASK_ENCRYPT | KMIP_CRYPTOMASK_DECRYPT; 28 | 29 | static Attribute attribs[] = { 30 | { .type = KMIP_ATTR_CRYPTOGRAPHIC_ALGORITHM, .value = &algorithm, .index = KMIP_UNSET }, 31 | { .type = KMIP_ATTR_CRYPTOGRAPHIC_LENGTH, .value = &length, .index = KMIP_UNSET }, 32 | { .type = KMIP_ATTR_CRYPTOGRAPHIC_USAGE_MASK, .value = &mask, .index = KMIP_UNSET }, 33 | }; 34 | 35 | static TemplateAttribute templ_attr = { 36 | .attributes = attribs, 37 | .attribute_count = ARRAY_SIZE(attribs) 38 | }; 39 | 40 | int sed_kmip_init(struct sed_kmip_ctx *ctx, char *ip, char *port, char *client_cert_path, char *client_key_path, 41 | char *ca_cert_path) 42 | { 43 | if (ctx == NULL) 44 | return -EINVAL; 45 | 46 | memset(ctx, 0, sizeof(*ctx)); 47 | 48 | memcpy(ctx->ip, ip, strnlen(ip, MAX_IP_SIZE)); 49 | memcpy(ctx->port, port, strnlen(port, MAX_PORT_SIZE)); 50 | memcpy(ctx->client_cert_path, client_cert_path, 51 | strnlen(client_cert_path, MAX_CLIENT_CERT_PATH_SIZE)); 52 | memcpy(ctx->client_key_path, client_key_path, 53 | strnlen(client_key_path, MAX_CLIENT_KEY_PATH_SIZE)); 54 | memcpy(ctx->ca_cert_path, ca_cert_path, 55 | strnlen(ca_cert_path, MAX_CA_CERT_PATH_SIZE)); 56 | 57 | OPENSSL_init_ssl(0, NULL); 58 | ctx->ssl_ctx = SSL_CTX_new(TLS_client_method()); 59 | 60 | int status = SSL_CTX_use_certificate_file(ctx->ssl_ctx, ctx->client_cert_path, SSL_FILETYPE_PEM); 61 | if (status != 1) { 62 | sedcli_printf(LOG_ERR, "Loading the client certificate failed\n"); 63 | goto error; 64 | } 65 | 66 | status = SSL_CTX_use_PrivateKey_file(ctx->ssl_ctx, ctx->client_key_path, SSL_FILETYPE_PEM); 67 | if (status != 1) { 68 | sedcli_printf(LOG_ERR, "Loading the client key failed\n"); 69 | goto error; 70 | } 71 | 72 | status = SSL_CTX_load_verify_locations(ctx->ssl_ctx, ctx->ca_cert_path, NULL); 73 | if (status != 1) { 74 | sedcli_printf(LOG_ERR, "Loading the CA file failed\n"); 75 | goto error; 76 | } 77 | 78 | return status; 79 | 80 | error: 81 | ERR_print_errors_fp(stderr); 82 | sed_kmip_deinit(ctx); 83 | 84 | return -ENOENT; 85 | } 86 | 87 | void sed_kmip_deinit(struct sed_kmip_ctx *ctx) 88 | { 89 | if (ctx == NULL) 90 | return; 91 | 92 | if (ctx->bio) { 93 | BIO_free_all(ctx->bio); 94 | ctx->bio = NULL; 95 | } 96 | 97 | if (ctx->ssl_ctx) { 98 | SSL_CTX_free(ctx->ssl_ctx); 99 | ctx->ssl_ctx = NULL; 100 | } 101 | 102 | if (ctx->ssl) 103 | ctx->ssl = NULL; 104 | } 105 | 106 | int sed_kmip_connect(struct sed_kmip_ctx *ctx) 107 | { 108 | if (ctx == NULL) 109 | return -EINVAL; 110 | 111 | ctx->bio = BIO_new_ssl_connect(ctx->ssl_ctx); 112 | BIO_get_ssl(ctx->bio, &ctx->ssl); 113 | 114 | if (ctx->ssl == NULL) { 115 | sedcli_printf(LOG_ERR, "Can't locate SSL pointer\n"); 116 | goto error; 117 | } 118 | 119 | /* No retries */ 120 | SSL_set_mode(ctx->ssl, SSL_MODE_AUTO_RETRY); 121 | 122 | /* Setup address */ 123 | BIO_set_conn_hostname(ctx->bio, ctx->ip); 124 | BIO_set_conn_port(ctx->bio, ctx->port); 125 | 126 | if (BIO_do_connect(ctx->bio) <= 0) { 127 | sedcli_printf(LOG_ERR, "Error connecting to KMIP server IP: %s, port: %s\n", ctx->ip, ctx->port); 128 | goto error; 129 | } 130 | 131 | sedcli_printf(LOG_INFO, "Connected to KMIP server IP: %s, port: %s\n", ctx->ip, ctx->port); 132 | 133 | return SUCCESS; 134 | 135 | error: 136 | ERR_print_errors_fp(stderr); 137 | sed_kmip_deinit(ctx); 138 | 139 | return -ECONNREFUSED; 140 | } 141 | 142 | int sed_kmip_gen_platform_key(struct sed_kmip_ctx *ctx, char **pek_id, int *pek_id_size) 143 | { 144 | if (!ctx || !pek_id || !pek_id_size) 145 | return -EINVAL; 146 | 147 | /* Send the request message. */ 148 | int result = kmip_bio_create_symmetric_key(ctx->bio, &templ_attr, pek_id, pek_id_size); 149 | 150 | SEDCLI_DEBUG_PARAM("Creating symmetric key finished status=%d pek_id=%s", result, 151 | result == KMIP_STATUS_SUCCESS ? *pek_id : ""); 152 | 153 | /* Handle the response results. */ 154 | if (result < 0) 155 | sedcli_printf(LOG_ERR, "Error while creating new key: %d\n", result); 156 | 157 | return result; 158 | } 159 | 160 | int sed_kmip_get_platform_key(struct sed_kmip_ctx *ctx, char *pek_id, int pek_id_size, char **pek, int *pek_size) 161 | { 162 | if (!ctx || !pek_id || !pek_id_size || !pek || !pek_size) 163 | return -EINVAL; 164 | 165 | /* Send the request message. */ 166 | int result = kmip_bio_get_symmetric_key(ctx->bio, pek_id, pek_id_size, pek, pek_size); 167 | 168 | SEDCLI_DEBUG_PARAM("Retrieving symmetric key finished status=%d key_size=%d[B]\n", result, 169 | result == KMIP_STATUS_SUCCESS ? *pek_size : 0); 170 | 171 | /* Handle the response results. */ 172 | if (result < 0) 173 | sedcli_printf(LOG_ERR, "Error while retrieving key: %d\n", result); 174 | 175 | return result; 176 | } 177 | -------------------------------------------------------------------------------- /src/kmip_lib.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #ifndef _SEDCLI_KMIP_H_ 8 | #define _SEDCLI_KMIP_H_ 9 | 10 | #include 11 | #include 12 | 13 | #define MAX_IP_SIZE (255) 14 | #define MAX_PORT_SIZE (255) 15 | #define MAX_CLIENT_CERT_PATH_SIZE (255) 16 | #define MAX_CLIENT_KEY_PATH_SIZE (255) 17 | #define MAX_CA_CERT_PATH_SIZE (255) 18 | 19 | struct sed_kmip_ctx { 20 | char ip[MAX_IP_SIZE]; 21 | char port[MAX_PORT_SIZE]; 22 | char client_cert_path[MAX_CLIENT_CERT_PATH_SIZE]; 23 | char client_key_path[MAX_CLIENT_KEY_PATH_SIZE]; 24 | char ca_cert_path[MAX_CA_CERT_PATH_SIZE]; 25 | 26 | SSL_CTX *ssl_ctx; 27 | SSL *ssl; 28 | BIO *bio; 29 | }; 30 | 31 | #define KMIP_FAILURE -1 32 | #define KMIP_SUCCESS 10000 33 | #define KMIP_SUCCESS_CONNECTED (KMIP_SUCCESS + 1) 34 | 35 | int sed_kmip_init(struct sed_kmip_ctx *ctx, char *ip, char *port, 36 | char *client_cert_path, char *client_key_path, 37 | char *ca_cert_path); 38 | 39 | int sed_kmip_connect(struct sed_kmip_ctx *ctx); 40 | 41 | int sed_kmip_gen_platform_key(struct sed_kmip_ctx *ctx, 42 | char **pek_id, int *pek_id_size); 43 | 44 | int sed_kmip_get_platform_key(struct sed_kmip_ctx *ctx, 45 | char *pek_id, int pek_id_size, 46 | char **pek, int *pek_size); 47 | 48 | void sed_kmip_deinit(struct sed_kmip_ctx *ctx); 49 | 50 | #endif /* _SEDCLI_KMIP_H_ */ 51 | -------------------------------------------------------------------------------- /src/lib/include/libsed.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2019, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | 7 | #ifndef _LIBSED_H_ 8 | #define _LIBSED_H_ 9 | 10 | #include 11 | #include 12 | #include 13 | 14 | #define OPAL_UID_LENGTH 8 15 | 16 | #define SED_MAX_KEY_LEN 255 17 | 18 | #define SED_OPAL_MAX_LRS 9 19 | #define OPAL_MAX_DSTS 256 20 | 21 | #define MAX_PROP_NAME_LEN 32 22 | #define NUM_TPER_PROPS 50 23 | #define NUM_HOST_PROPS 20 24 | 25 | #define SED_OPAL_MANUFACTURED_INACTIVE 0x08 26 | 27 | enum SED_CLI_TYPE { 28 | SED_CLI_STANDARD, 29 | SED_CLI_KMIP 30 | } sed_cli; 31 | 32 | enum SED_ACCESS_TYPE { 33 | SED_ACCESS_RO = 1 << 0, // read only 34 | SED_ACCESS_WO = 1 << 1, // write only 35 | SED_ACCESS_RW = 1 << 2, // read write 36 | SED_ACCESS_LK = 1 << 3, // locked (read and write not allowed) 37 | }; 38 | 39 | enum SED_AUTHORITY { 40 | SED_ANYBODY, 41 | SED_ADMINS, 42 | SED_MAKERS, 43 | SED_MAKERSYMK, 44 | SED_MAKERPUK, 45 | SED_SID, 46 | SED_PSID, 47 | SED_TPERSIGN, 48 | SED_TPEREXCH, 49 | SED_ADMINEXCH, 50 | SED_ISSUERS, 51 | SED_EDITORS, 52 | SED_DELETERS, 53 | SED_SERVERS, 54 | SED_RESERVE0, 55 | SED_RESERVE1, 56 | SED_RESERVE2, 57 | SED_RESERVE3, 58 | SED_ADMIN, 59 | SED_ADMIN1, 60 | SED_ADMIN2, 61 | SED_ADMIN3, 62 | SED_ADMIN4, 63 | SED_USERS, 64 | SED_USER, 65 | SED_USER1, 66 | SED_USER2, 67 | SED_USER3, 68 | SED_USER4, 69 | SED_USER5, 70 | SED_USER6, 71 | SED_USER7, 72 | SED_USER8, 73 | SED_USER9, 74 | SED_BAND_MASTER_0, 75 | SED_ERASE_MASTER 76 | }; 77 | 78 | struct sed_device; 79 | 80 | struct sed_tper_feat { 81 | uint8_t sync_supp : 1; 82 | uint8_t async_supp : 1; 83 | uint8_t ack_nak_supp : 1; 84 | uint8_t buff_mgmt_supp : 1; 85 | uint8_t stream_supp : 1; 86 | uint8_t reserved1 : 1; 87 | uint8_t comid_mgmt_supp : 1; 88 | uint8_t reserved : 1; 89 | uint16_t code; 90 | uint8_t rev; 91 | uint8_t len; 92 | } __attribute__((__packed__)); 93 | 94 | struct sed_locking_feat { 95 | uint8_t locking_supp : 1; 96 | uint8_t locking_en : 1; 97 | uint8_t locked : 1; 98 | uint8_t media_enc : 1; 99 | uint8_t mbr_en : 1; 100 | uint8_t mbr_done : 1; 101 | uint8_t mbr_shadowing_not_supported : 1; 102 | uint8_t mbr_hw_reset_for_lor_dor_supported : 1; 103 | uint16_t code; 104 | uint8_t rev; 105 | uint8_t len; 106 | } __attribute__((__packed__)); 107 | 108 | struct sed_geometry_feat { 109 | struct { 110 | uint8_t align : 1; 111 | uint8_t reserved : 7; 112 | } __attribute__((__packed__)) align; 113 | uint8_t reserved2[7]; 114 | uint32_t logical_blk_sz; 115 | uint64_t alignmnt_granularity; 116 | uint64_t lowest_aligned_lba; 117 | uint16_t code; 118 | uint8_t rev; 119 | uint8_t len; 120 | } __attribute__((__packed__)); 121 | 122 | struct sed_datastore_feat { 123 | uint16_t max_num_datastores; 124 | uint32_t max_total_size_datastore_tables; 125 | uint32_t datastore_size_align; 126 | uint16_t code; 127 | uint8_t rev; 128 | uint8_t len; 129 | } __attribute__((__packed__)); 130 | 131 | struct sed_opalv100_feat { 132 | uint16_t v1_base_comid; 133 | uint16_t v1_comid_num; 134 | uint16_t code; 135 | uint8_t rev; 136 | uint8_t len; 137 | } __attribute__((__packed__)); 138 | 139 | struct sed_opalv200_feat { 140 | uint16_t base_comid; 141 | uint16_t comid_num; 142 | struct { 143 | uint8_t range_crossing : 1; 144 | uint8_t reserved : 7; 145 | } __attribute__((__packed__)); 146 | uint16_t admin_lp_auth_num; 147 | uint16_t user_lp_auth_num; 148 | uint8_t init_pin; 149 | uint8_t revert_pin; 150 | uint8_t reserved2[5]; 151 | uint16_t code; 152 | union { 153 | struct { 154 | uint8_t feature_descriptor_version : 4; 155 | uint8_t ssc_minor_version : 4; 156 | } __attribute__((__packed__)) ver; 157 | uint8_t rev; 158 | } rev; 159 | uint8_t len; 160 | } __attribute__((__packed__)); 161 | 162 | struct sed_pyrite_feat { 163 | uint16_t base_comid; 164 | uint16_t comid_num; 165 | uint8_t reserved[5]; 166 | uint8_t init_pin; 167 | uint8_t revert_pin; 168 | uint8_t reserved2[5]; 169 | uint16_t code; 170 | uint8_t rev; 171 | uint8_t len; 172 | } __attribute__((__packed__)); 173 | 174 | #define DR_TIME_FOR_SUPPORTED_DRM_BITS_COUNT 6 175 | struct sed_data_rm_feat { 176 | uint8_t reserved; 177 | struct { 178 | uint8_t dr_operation_interrupted : 1; 179 | uint8_t dr_operation_processing : 1; 180 | uint8_t reserved2 : 6; 181 | } __attribute__((__packed__)); 182 | uint8_t supported_drm; 183 | uint8_t dr_time_format_for_bit; 184 | uint16_t dr_time_for_supported_drm_bits[DR_TIME_FOR_SUPPORTED_DRM_BITS_COUNT]; 185 | uint8_t reserved3[16]; 186 | uint16_t code; 187 | uint8_t rev; 188 | uint8_t len; 189 | } __attribute__((__packed__)); 190 | 191 | struct sed_tper_properties { 192 | struct { 193 | char key_name[MAX_PROP_NAME_LEN]; 194 | uint64_t value; 195 | } property[NUM_TPER_PROPS]; 196 | } __attribute__((__packed__)); 197 | 198 | struct sed_block_sid_feat { 199 | uint8_t sid_valuestate : 1; 200 | uint8_t sid_blockstate : 1; 201 | uint8_t lsp_freeze_lock_support : 1; 202 | uint8_t lsp_freeze_lock_state : 1; 203 | uint8_t reserved1 : 4; 204 | uint8_t hardware_reset : 1; 205 | uint8_t reserved2 : 7; 206 | uint8_t reserved3[10]; 207 | uint16_t code; 208 | uint8_t rev; 209 | uint8_t len; 210 | } __attribute__((__packed__)); 211 | 212 | struct sed_sum_feat { 213 | uint32_t number_of_locking_objects_supported; 214 | uint8_t any : 1; 215 | uint8_t all : 1; 216 | uint8_t policy : 1; 217 | uint8_t reserved : 5; 218 | uint16_t code; 219 | uint8_t rev; 220 | uint8_t len; 221 | } __attribute__((__packed__)); 222 | 223 | struct sed_cnl_feat { 224 | struct { 225 | uint8_t reseverd : 5; 226 | uint8_t sum_c : 1; 227 | uint8_t range_p : 1; 228 | uint8_t range_c : 1; 229 | } __attribute__((__packed__)); 230 | uint8_t reseverd2[3]; 231 | uint32_t max_key_count; 232 | uint32_t unused_key_count; 233 | uint32_t max_ranges_per_ns; 234 | uint16_t code; 235 | uint8_t rev; 236 | uint8_t len; 237 | } __attribute__((__packed__)); 238 | 239 | struct sed_siis_feat { 240 | uint8_t siis_revision_number; 241 | struct { 242 | uint8_t reseverd2 : 5; 243 | uint8_t identifier_usage_scope : 2; 244 | uint8_t key_change_zone_behavior : 1; 245 | } __attribute__((__packed__)); 246 | uint8_t reseverd3[10]; 247 | uint16_t code; 248 | struct { 249 | uint8_t data_structure_version : 4; 250 | uint8_t reseverd : 4; 251 | } __attribute__((__packed__)); 252 | uint8_t len; 253 | } __attribute__((__packed__)); 254 | 255 | struct sed_opal_level0_discovery_header { 256 | uint32_t len; 257 | uint32_t rev; 258 | uint64_t reserved; 259 | uint8_t vendor_specific[32]; 260 | } __attribute__((__packed__)); 261 | 262 | struct sed_opal_level0_discovery { 263 | struct { 264 | uint64_t feat_tper : 1; 265 | uint64_t feat_locking : 1; 266 | uint64_t feat_geometry : 1; 267 | uint64_t feat_datastore : 1; 268 | uint64_t feat_opalv100 : 1; 269 | uint64_t feat_opalv200 : 1; 270 | uint64_t feat_ruby : 1; 271 | uint64_t feat_pyritev100 : 1; 272 | uint64_t feat_pyritev200 : 1; 273 | uint64_t feat_data_rm : 1; 274 | uint64_t feat_block_sid : 1; 275 | uint64_t feat_sum : 1; 276 | uint64_t feat_cnl : 1; 277 | uint64_t feat_siis : 1; 278 | uint64_t reserved : 50; 279 | } __attribute__((__packed__)) feat_avail_flag; 280 | 281 | struct sed_tper_feat sed_tper; 282 | struct sed_locking_feat sed_locking; 283 | struct sed_geometry_feat sed_geometry; 284 | struct sed_datastore_feat sed_datastore; 285 | struct sed_opalv100_feat sed_opalv100; 286 | struct sed_opalv200_feat sed_opalv200; 287 | struct sed_opalv200_feat sed_ruby; 288 | struct sed_pyrite_feat sed_pyritev100; 289 | struct sed_pyrite_feat sed_pyritev200; 290 | struct sed_data_rm_feat sed_data_rm; 291 | struct sed_block_sid_feat sed_block_sid; 292 | struct sed_sum_feat sed_sum; 293 | struct sed_cnl_feat sed_cnl; 294 | struct sed_siis_feat sed_siis; 295 | }; 296 | 297 | struct sed_opal_device_discovery { 298 | struct sed_opal_level0_discovery_header sed_lvl0_discovery_header; 299 | struct sed_opal_level0_discovery sed_lvl0_discovery; 300 | struct sed_tper_properties sed_tper_props; 301 | struct sed_tper_properties sed_host_props; 302 | }; 303 | 304 | struct sed_tper_state { 305 | uint8_t session_open; 306 | uint8_t blk_sid_val_state; 307 | uint8_t locking_en; 308 | uint8_t admisp_lc; 309 | uint8_t lsp_lc; 310 | }; 311 | 312 | struct sed_key { 313 | char key[SED_MAX_KEY_LEN]; 314 | uint8_t len; 315 | }; 316 | 317 | struct sed_opal_locking_range { 318 | size_t start; 319 | size_t length; 320 | uint8_t lr_id : 4; 321 | uint8_t read_locked : 1; 322 | uint8_t write_locked : 1; 323 | uint8_t rle : 1; 324 | uint8_t wle : 1; 325 | }; 326 | 327 | struct sed_opal_locking_ranges { 328 | struct sed_opal_locking_range lrs[SED_OPAL_MAX_LRS]; 329 | uint8_t lr_num; 330 | }; 331 | 332 | enum SED_TOKEN_TYPE { 333 | SED_DATA_BYTESTRING = 0xE0, 334 | SED_DATA_SINT = 0xE1, 335 | SED_DATA_UINT = 0xE2, 336 | SED_DATA_TOKEN = 0xE3, 337 | SED_DATA_TOKEN_INVALID = 0x0, 338 | }; 339 | 340 | enum SED_SP_TYPE { 341 | SED_ADMIN_SP, 342 | SED_LOCKING_SP, 343 | SED_THIS_SP, 344 | SED_UID_SP, 345 | }; 346 | 347 | enum SED_FLAG_TYPE { 348 | SED_FLAG_UNDEFINED, 349 | SED_FLAG_ENABLED, 350 | SED_FLAG_DISABLED 351 | }; 352 | 353 | struct opal_req_item { 354 | uint8_t type; 355 | int len; 356 | union { 357 | uint8_t byte; 358 | uint64_t uint; 359 | const uint8_t *bytes; 360 | } val; 361 | }; 362 | 363 | struct sed_opal_col_info { 364 | void *data; 365 | uint32_t len; 366 | enum SED_TOKEN_TYPE type; 367 | uint8_t opal_type; 368 | struct sed_opal_col_info *next_col; 369 | }; 370 | 371 | struct sed_locking_object { 372 | uint32_t nsid; /* NS id assigned */ 373 | uint8_t uid[OPAL_UID_LENGTH]; /* Locking Object UID */ 374 | uint8_t nsgid; /* True or False */ 375 | }; 376 | 377 | struct sed_next_uids { 378 | uint8_t **uids; 379 | uint32_t size; 380 | }; 381 | 382 | struct sed_session { 383 | uint32_t hsn; 384 | uint32_t tsn; 385 | }; 386 | 387 | enum sed_status { 388 | SED_SUCCESS, 389 | SED_NOT_AUTHORIZED, 390 | SED_UNKNOWN_ERROR, // not in spec 391 | SED_SP_BUSY, 392 | SED_SP_FAILED, 393 | SED_SP_DISABLED, 394 | SED_SP_FROZEN, 395 | SED_NO_SESSIONS_AVAILABLE, 396 | SED_UNIQUENESS_CONFLICT, 397 | SED_INSUFFICIENT_SPACE, 398 | SED_INSUFFICIENT_ROWS, 399 | SED_INVALID_FUNCTION, // not in spec 400 | SED_INVALID_PARAMETER, 401 | SED_INVALID_REFERENCE, // not in spec 402 | SED_UNKNOWN_ERROR_1, // not in spec 403 | SED_TPER_MALFUNCTION, 404 | SED_TRANSACTION_FAILURE, 405 | SED_RESPONSE_OVERFLOW, 406 | SED_AUTHORITY_LOCKED_OUT, 407 | SED_FAIL = 0x3F, /* Fail status code as defined by Opal is higher value */ 408 | }; 409 | 410 | /** 411 | * This function initializes libsed for usage. It opens device node file and 412 | * stores relevant information in data structure representing libsed context. 413 | * Libsed context must be passed to other libsed functions for its proper 414 | * operation. 415 | */ 416 | int sed_init(struct sed_device **dev, const char *dev_path, bool try); 417 | 418 | int sed_host_prop(struct sed_device *dev, const char *prop, uint32_t *val); 419 | 420 | int sed_dev_discovery(struct sed_device *dev, 421 | struct sed_opal_device_discovery *discovery); 422 | 423 | int sed_parse_tper_state(struct sed_device *dev, 424 | struct sed_tper_state *tper_state); 425 | 426 | void sed_deinit(struct sed_device *dev); 427 | 428 | int sed_key_init(struct sed_key *disk_key, char *key, const uint8_t key_len); 429 | 430 | int sed_get_msid_pin(struct sed_device *dev, struct sed_key *msid_pin); 431 | 432 | int sed_take_ownership(struct sed_device *dev, const struct sed_key *key); 433 | 434 | int sed_activate_sp(struct sed_device *dev, const struct sed_key *key, 435 | uint8_t *sp_uid, uint8_t *auth_uid, uint8_t *target_sp_uid, char *lr_str, 436 | uint8_t range_start_length_policy, char *dsts_str); 437 | 438 | int sed_setup_global_range(struct sed_device *dev, const struct sed_key *key, 439 | enum SED_FLAG_TYPE rle, enum SED_FLAG_TYPE wle); 440 | 441 | int sed_lock_unlock(struct sed_device *dev, const struct sed_key *key, 442 | uint8_t *auth_uid, uint8_t lr, bool sum, enum SED_ACCESS_TYPE access_type); 443 | 444 | int sed_revert(struct sed_device *dev, const struct sed_key *key, 445 | uint8_t *sp_uid, uint8_t *auth_uid, uint8_t *target_sp_uid); 446 | 447 | int sed_revert_lsp(struct sed_device *dev, const struct sed_key *key, 448 | uint8_t *auth_uid, bool keep_global_range_key); 449 | 450 | int sed_set_password(struct sed_device *dev, uint8_t *sp_uid, uint8_t *auth_uid, 451 | const struct sed_key *auth_key, uint8_t *user_uid, 452 | const struct sed_key *new_user_key); 453 | 454 | int sed_list_lr(struct sed_device *dev, const struct sed_key *key, 455 | struct sed_opal_locking_ranges *lrs); 456 | 457 | int sed_ds_add_anybody_get(struct sed_device *dev, const struct sed_key *key); 458 | 459 | int sed_ds_read(struct sed_device *dev, enum SED_AUTHORITY auth, 460 | const struct sed_key *key, uint8_t *to, uint32_t size, 461 | uint32_t offset); 462 | 463 | int sed_ds_write(struct sed_device *dev, enum SED_AUTHORITY auth, 464 | const struct sed_key *key, const void *from, uint32_t size, 465 | uint32_t offset); 466 | 467 | int sed_shadow_mbr(struct sed_device *dev, const struct sed_key *key, bool mbr); 468 | 469 | int sed_mbr_done(struct sed_device *dev, const struct sed_key *key, bool mbr); 470 | 471 | int sed_read_shadow_mbr(struct sed_device *dev, enum SED_AUTHORITY auth, 472 | const struct sed_key *key,uint8_t *to, uint32_t size, 473 | uint32_t offset); 474 | 475 | int sed_write_shadow_mbr(struct sed_device *dev, const struct sed_key *key, 476 | const uint8_t *from, uint32_t size, uint32_t offset); 477 | 478 | int sed_issue_block_sid_cmd(struct sed_device *dev, bool hw_reset); 479 | 480 | int sed_add_user_to_lr(struct sed_device *dev, const struct sed_key *key, 481 | const char *user, enum SED_ACCESS_TYPE access_type, uint8_t lr); 482 | 483 | int sed_setup_lr(struct sed_device *dev, const struct sed_key *key, 484 | uint8_t *sp_uid, uint8_t *auth_uid, uint8_t *lr_uid, uint64_t range_start, 485 | uint64_t range_length, enum SED_FLAG_TYPE rle, enum SED_FLAG_TYPE wle); 486 | 487 | int sed_enable_user(struct sed_device *dev, const struct sed_key *key, 488 | uint8_t *sp_uid, uint8_t *auth_uid, uint8_t *user_uid); 489 | 490 | int sed_erase(struct sed_device *dev, const struct sed_key *key, 491 | uint8_t *sp_uid, uint8_t *auth_uid, uint8_t *uid); 492 | 493 | int sed_genkey(struct sed_device *dev, const struct sed_key *key, 494 | uint8_t *sp_uid, uint8_t *auth_uid, uint8_t *uid, 495 | uint32_t public_exponent, uint32_t pin_length); 496 | 497 | int sed_start_session(struct sed_device *dev, const struct sed_key *key, 498 | uint8_t *sp_uid, uint8_t *auth_uid, struct sed_session *session); 499 | 500 | int sed_end_session(struct sed_device *dev, struct sed_session *session); 501 | 502 | int sed_start_end_transactions(struct sed_device *dev, bool start, 503 | uint8_t status); 504 | 505 | int sed_set_with_buf(struct sed_device *dev, const struct sed_key *key, 506 | uint8_t *sp_uid, uint8_t *auth_uid, uint8_t *uid, struct opal_req_item *cmd, 507 | size_t cmd_len); 508 | 509 | int sed_get_set_col_val(struct sed_device *dev, const struct sed_key *key, 510 | uint8_t *sp_uid, uint8_t *auth_uid, uint8_t *uid, uint64_t col, 511 | bool get, struct sed_opal_col_info *col_info); 512 | 513 | int sed_get_set_byte_table(struct sed_device *dev, const struct sed_key *key, 514 | const enum SED_SP_TYPE sp, const char *user, uint8_t *uid, uint64_t start, 515 | uint64_t end, uint8_t *buffer, bool is_set); 516 | 517 | int sed_stack_reset(struct sed_device *dev, int32_t com_id, uint64_t extended_com_id, uint8_t *response); 518 | 519 | int sed_tper_reset(struct sed_device *dev); 520 | 521 | int sed_reactivate_sp(struct sed_device *dev, const struct sed_key *key, 522 | uint8_t *sp_uid, uint8_t *auth_uid, uint8_t *target_sp_uid, char *lr_str, 523 | uint8_t range_start_length_policy, const struct sed_key *admin1_pwd, 524 | char *dsts_str); 525 | 526 | int sed_assign(struct sed_device *dev, const struct sed_key *key, 527 | uint8_t *sp_uid, uint8_t *auth_uid, uint32_t nsid, 528 | uint8_t range_start, uint8_t range_length, struct sed_locking_object *info); 529 | 530 | int sed_deassign(struct sed_device *dev, const struct sed_key *key, 531 | uint8_t *sp_uid, uint8_t *auth_uid, const uint8_t *uid, 532 | bool keep_ns_global_range_key); 533 | 534 | int sed_table_next(struct sed_device *dev, const struct sed_key *key, 535 | uint8_t *sp_uid, uint8_t *auth_uid, uint8_t *uid, 536 | uint8_t *where, uint16_t count, struct sed_next_uids *next_uids); 537 | 538 | int sed_authenticate(struct sed_device *dev, enum SED_AUTHORITY auth, 539 | const struct sed_key *key); 540 | 541 | int sed_get_acl(struct sed_device *dev, const struct sed_key *key, 542 | uint8_t *sp_uid, uint8_t *auth_uid, const uint8_t *invoking_uid, 543 | const uint8_t *method_uid, struct sed_next_uids *next_uids); 544 | 545 | #endif /* _LIBSED_H_ */ 546 | -------------------------------------------------------------------------------- /src/lib/nvme_access.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2019, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include "nvme_pt_ioctl.h" 12 | 13 | 14 | #define NVME_SECURITY_SEND (0x81) 15 | #define NVME_SECURITY_RECV (0x82) 16 | 17 | #define OPAL_SLEEP (15000) 18 | 19 | #define SEND (1) 20 | #define RECV (0) 21 | 22 | static int send_recv_nvme_pt_ioctl(int fd, int send, uint8_t proto_id, uint16_t com_id, void *sec_cmd, 23 | uint32_t sec_cmd_len) 24 | { 25 | struct nvme_admin_cmd nvme_cmd; 26 | memset(&nvme_cmd, 0, sizeof(nvme_cmd)); 27 | 28 | nvme_cmd.opcode = send ? NVME_SECURITY_SEND : NVME_SECURITY_RECV; 29 | 30 | nvme_cmd.cdw10 = proto_id << 24 | com_id << 8; 31 | nvme_cmd.cdw11 = sec_cmd_len; 32 | 33 | nvme_cmd.data_len = sec_cmd_len; 34 | nvme_cmd.addr = (uint64_t)sec_cmd; 35 | 36 | int status = ioctl(fd, NVME_IOCTL_ADMIN_CMD, &nvme_cmd); 37 | if (status < 0) 38 | return errno; 39 | 40 | return status; 41 | } 42 | 43 | int opal_send(int fd, uint8_t proto_id, uint16_t com_id, uint8_t *buf, int buf_len) 44 | { 45 | int ret; 46 | 47 | ret = send_recv_nvme_pt_ioctl(fd, SEND, proto_id, com_id, buf, buf_len); 48 | 49 | return ret; 50 | } 51 | 52 | int opal_recv(int fd, uint8_t proto_id, uint16_t com_id, uint8_t *buf, int buf_len) 53 | { 54 | int ret; 55 | 56 | bool done = false; 57 | while (done == false) { 58 | done = true; 59 | memset(buf, 0, buf_len); 60 | 61 | ret = send_recv_nvme_pt_ioctl(fd, RECV, proto_id, com_id, buf, buf_len); 62 | if (ret == 0) { 63 | struct opal_header *header = (struct opal_header *)buf; 64 | 65 | uint32_t outstanding_data = be32toh(header->compacket.outstanding_data); 66 | uint32_t min_transfer = be32toh(header->compacket.min_transfer); 67 | 68 | if (outstanding_data != 0 && min_transfer == 0) { 69 | usleep(OPAL_SLEEP); 70 | done = false; 71 | } 72 | } 73 | } 74 | 75 | return ret; 76 | } 77 | 78 | int opal_send_recv(int fd, uint8_t proto_id, uint16_t com_id, uint8_t *req_buf, int req_buf_len, uint8_t *resp_buf, 79 | int resp_buf_len) 80 | { 81 | int ret = 0; 82 | 83 | 84 | ret = opal_send(fd, proto_id, com_id, req_buf, req_buf_len); 85 | if (ret) 86 | return ret; 87 | 88 | ret = opal_recv(fd, proto_id, com_id, resp_buf, resp_buf_len); 89 | 90 | 91 | return ret; 92 | } 93 | -------------------------------------------------------------------------------- /src/lib/nvme_access.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2019, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | 7 | #ifndef _NVME_ACCESS_H_ 8 | #define _NVME_ACCESS_H_ 9 | 10 | #define OPAL_DISCOVERY_COMID (0x0001) 11 | 12 | int opal_send_recv(int fd, uint8_t proto_id, uint16_t com_id, uint8_t *req_buf, int req_buf_len, uint8_t *resp_buf, 13 | int resp_buf_len); 14 | 15 | int opal_send(int fd, uint8_t proto_id, uint16_t com_id, uint8_t *buf, int buf_len); 16 | int opal_recv(int fd, uint8_t proto_id, uint16_t com_id, uint8_t *buf, int buf_len); 17 | 18 | #endif /* _NVME_ACCESS_H_ */ 19 | -------------------------------------------------------------------------------- /src/lib/nvme_pt_ioctl.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2019, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | 7 | #ifndef _NVME_PT_IOCTL_H 8 | #define _NVME_PT_IOCTL_H 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include 21 | 22 | #include "sed_util.h" 23 | 24 | #define GENERIC_HOST_SESSION_NUM 0x41 25 | 26 | /* 27 | * TSM SHALL NOT assign any TSN in the range 0 to 4095 to a regular session. 28 | * These TSNs are reserved by TCG for special sessions 29 | */ 30 | #define RSVD_TPER_SESSION_NUM (4096) 31 | 32 | #define OPAL_SUCCESS (0) 33 | 34 | #define MAX_FEATURES 64 35 | 36 | #define DTAERROR_NO_METHOD_STATUS 0x89 37 | 38 | #define TPER_SYNC_SUPPORTED 0x01 39 | #define MBR_ENABLED_MASK 0x10 40 | 41 | /* Derived from TCG Core spec 2.01 Section: 42 | * 3.2.2.1 43 | * Data Type 44 | */ 45 | #define TINY_ATOM_BYTE 0x7F 46 | #define SHORT_ATOM_BYTE 0xBF 47 | #define MEDIUM_ATOM_BYTE 0xDF 48 | #define LONG_ATOM_BYTE 0xE3 49 | 50 | /* 51 | * User IDs used in the TCG storage SSCs 52 | * Derived from: TCG_Storage_Architecture_Core_Spec_v2.01_r1.00 53 | * Section: 6.3 Assigned UIDs 54 | */ 55 | #define OPAL_UID_LENGTH 8 56 | #define OPAL_METHOD_LENGTH 8 57 | #define OPAL_MSID_KEYLEN 15 58 | #define OPAL_UID_LENGTH_HALF 4 59 | 60 | #define OPAL_INVALID_PARAM 12 61 | 62 | #define OPAL_ISSUED 0x00 63 | #define OPAL_ISSUED_DISABLED 0x01 64 | #define OPAL_ISSUED_FROZEN 0x02 65 | #define OPAL_ISSUED_DISABLED_FROZEN 0x03 66 | #define OPAL_ISSUED_FAILED 0x04 67 | #define OPAL_RESERVED_05 0x05 68 | #define OPAL_RESERVED_06 0x06 69 | #define OPAL_RESERVED_07 0x07 70 | #define OPAL_MANUFACTURED_INACTIVE 0x08 71 | #define OPAL_MANUFACTURED 0x09 72 | #define OPAL_MANUFACTURED_DISABLED 0x0A 73 | #define OPAL_MANUFACTURED_FROZEN 0x0B 74 | #define OPAL_MANUFACTURED_DISABLED_FROZEN 0x0C 75 | #define OPAL_MANUFACTURED_FAILED 0x0D 76 | #define OPAL_RESERVED_0E 0x0E 77 | #define OPAL_RESERVED_0F 0x0F 78 | 79 | #define LOCKING_RANGE_NON_GLOBAL 0x03 80 | 81 | #define FC_TPER 0x0001 82 | #define FC_LOCKING 0x0002 83 | #define FC_GEOMETRY 0x0003 84 | #define FC_ENTERPRISE 0x0100 85 | #define FC_DATASTORE 0x0202 86 | #define FC_SINGLEUSER 0x0201 87 | #define FC_OPALV100 0x0200 88 | #define FC_OPALV200 0x0203 89 | 90 | #define KEEP_GLOBAL_RANGE_KEY (0x060000) 91 | 92 | enum { 93 | TCG_SECP_00 = 0, 94 | TCG_SECP_01, 95 | TCG_SECP_02, 96 | }; 97 | 98 | enum opaluid { 99 | /* users uid */ 100 | OPAL_SM_UID, 101 | OPAL_THIS_SP_UID, 102 | OPAL_ADMIN_SP_UID, 103 | OPAL_LOCKING_SP_UID, 104 | OPAL_ENTERPRISE_LOCKING_SP_UID, 105 | 106 | /* authority */ 107 | OPAL_ANYBODY_UID, 108 | OPAL_ADMINS_UID, 109 | OPAL_MAKERS_UID, 110 | OPAL_MAKERSYMK_UID, 111 | OPAL_MAKERPUK_UID, 112 | OPAL_SID_UID, 113 | OPAL_PSID_UID, 114 | OPAL_TPERSIGN_UID, 115 | OPAL_TPEREXCH_UID, 116 | OPAL_ADMINEXCH_UID, 117 | OPAL_ISSUERS_UID, 118 | OPAL_ADMIN1_ADMIN_SP_UID = OPAL_ISSUERS_UID, 119 | OPAL_EDITORS_UID, 120 | OPAL_DELETERS_UID, 121 | OPAL_SERVERS_UID, 122 | OPAL_RESERVE0_UID, 123 | OPAL_RESERVE1_UID, 124 | OPAL_RESERVE2_UID, 125 | OPAL_RESERVE3_UID, 126 | OPAL_ADMIN_UID, 127 | OPAL_ADMIN1_UID, 128 | OPAL_ADMIN2_UID, 129 | OPAL_ADMIN3_UID, 130 | OPAL_ADMIN4_UID, 131 | OPAL_USERS_UID, 132 | OPAL_USER_UID, 133 | OPAL_USER1_UID, 134 | OPAL_USER2_UID, 135 | OPAL_USER3_UID, 136 | OPAL_USER4_UID, 137 | OPAL_USER5_UID, 138 | OPAL_USER6_UID, 139 | OPAL_USER7_UID, 140 | OPAL_USER8_UID, 141 | OPAL_USER9_UID, 142 | OPAL_ENTERPRISE_BANDMASTER0_UID, 143 | OPAL_ENTERPRISE_ERASEMASTER_UID, 144 | 145 | /* tables uid */ 146 | OPAL_TABLE_TABLE_UID, 147 | OPAL_LOCKING_TABLE_UID, 148 | OPAL_LOCKINGRANGE_GLOBAL_UID, 149 | OPAL_LOCKINGRANGE_ACE_RDLOCKED_UID, 150 | OPAL_LOCKINGRANGE_ACE_WRLOCKED_UID, 151 | OPAL_MBRCONTROL_UID, 152 | OPAL_MBR_UID, 153 | OPAL_AUTHORITY_TABLE_UID, 154 | OPAL_C_PIN_TABLE_UID, 155 | OPAL_LOCKING_INFO_TABLE_UID, 156 | OPAL_ENTERPRISE_LOCKING_INFO_TABLE_UID, 157 | OPAL_DATASTORE_UID, 158 | OPAL_ACCESS_CONTROL_UID, 159 | 160 | /* c_pin_table objects UID's */ 161 | OPAL_C_PIN_MSID_UID, 162 | OPAL_C_PIN_SID_UID, 163 | OPAL_C_PIN_ADMIN_SP_ADMIN1_UID, 164 | OPAL_C_PIN_LOCKING_SP_ADMIN1_UID, 165 | OPAL_C_PIN_USER1_UID, 166 | 167 | /* half UID's (only the first four bytes used) */ 168 | OPAL_HALF_UID_AUTHORITY_OBJ_REF_UID, 169 | OPAL_HALF_UID_BOOLEAN_ACE_UID, 170 | 171 | /* ACE DS UIDs */ 172 | OPAL_ACE_DS_GET_ALL_UID, 173 | OPAL_ACE_DS_SET_ALL_UID, 174 | 175 | /* optional parameter UID */ 176 | OPAL_UID_HEXFF_UID, 177 | }; 178 | 179 | enum opalmethod { 180 | OPAL_PROPERTIES_METHOD_UID, 181 | OPAL_STARTSESSION_METHOD_UID, 182 | OPAL_REVERT_METHOD_UID, 183 | OPAL_ACTIVATE_METHOD_UID, 184 | OPAL_EGET_METHOD_UID, 185 | OPAL_ESET_METHOD_UID, 186 | OPAL_NEXT_METHOD_UID, 187 | OPAL_EAUTHENTICATE_METHOD_UID, 188 | OPAL_GETACL_METHOD_UID, 189 | OPAL_GENKEY_METHOD_UID, 190 | OPAL_REVERTSP_METHOD_UID, 191 | OPAL_GET_METHOD_UID, 192 | OPAL_SET_METHOD_UID, 193 | OPAL_AUTHENTICATE_METHOD_UID, 194 | OPAL_RANDOM_METHOD_UID, 195 | OPAL_ERASE_METHOD_UID, 196 | OPAL_REACTIVATE_METHOD_UID, 197 | OPAL_ASSIGN_METHOD_UID, 198 | OPAL_DEASSIGN_METHOD_UID, 199 | }; 200 | 201 | enum opaltoken { 202 | /* Boolean */ 203 | OPAL_TRUE = 0x01, 204 | OPAL_FALSE = 0x00, 205 | OPAL_BOOLEAN_EXPR = 0x03, 206 | /* cellblocks */ 207 | OPAL_TABLE = 0x00, 208 | OPAL_STARTROW = 0x01, 209 | OPAL_ENDROW = 0x02, 210 | OPAL_STARTCOLUMN = 0x03, 211 | OPAL_ENDCOLUMN = 0x04, 212 | OPAL_VALUES = 0x01, 213 | /* opal tables */ 214 | OPAL_TABLE_ROW = 0x07, 215 | /* authority table */ 216 | OPAL_PIN = 0x03, 217 | /* locking tokens */ 218 | OPAL_RANGESTART = 0x03, 219 | OPAL_RANGELENGTH = 0x04, 220 | OPAL_READLOCKENABLED = 0x05, 221 | OPAL_WRITELOCKENABLED = 0x06, 222 | OPAL_READLOCKED = 0x07, 223 | OPAL_WRITELOCKED = 0x08, 224 | OPAL_ACTIVEKEY = 0x0A, 225 | /* lockingsp table */ 226 | OPAL_LIFECYCLE = 0x06, 227 | /* locking info table */ 228 | OPAL_MAXRANGES = 0x04, 229 | /* mbr control */ 230 | OPAL_MBRENABLE = 0x01, 231 | OPAL_MBRDONE = 0x02, 232 | /* properties */ 233 | OPAL_HOSTPROPERTIES = 0x00, 234 | /* atoms */ 235 | OPAL_STARTLIST = 0xf0, 236 | OPAL_ENDLIST = 0xf1, 237 | OPAL_STARTNAME = 0xf2, 238 | OPAL_ENDNAME = 0xf3, 239 | OPAL_CALL = 0xf8, 240 | OPAL_ENDOFDATA = 0xf9, 241 | OPAL_ENDOFSESSION = 0xfa, 242 | OPAL_STARTTRANSACTON = 0xfb, 243 | OPAL_ENDTRANSACTON = 0xfc, 244 | OPAL_EMPTYATOM = 0xff, 245 | OPAL_WHERE = 0x00, 246 | /* CNL NS col */ 247 | OPAL_NS_ID = 0x14, 248 | OPAL_NS_GLOBAL_RANGE = 0x15, 249 | }; 250 | 251 | struct tper_feat { 252 | uint8_t sync_supp : 1; 253 | uint8_t async_supp : 1; 254 | uint8_t ack_nak_supp : 1; 255 | uint8_t buff_mgmt_supp : 1; 256 | uint8_t stream_supp : 1; 257 | uint8_t reserved1 : 1; 258 | uint8_t comid_mgmt_supp : 1; 259 | uint8_t reserved2 : 1; 260 | } __attribute__((__packed__)); 261 | 262 | struct locking_feat { 263 | uint8_t locking_supp : 1; 264 | uint8_t locking_en : 1; 265 | uint8_t locked : 1; 266 | uint8_t media_enc : 1; 267 | uint8_t mbr_en : 1; 268 | uint8_t mbr_done : 1; 269 | uint8_t reserved : 2; 270 | } __attribute__((__packed__)); 271 | 272 | struct geometry_feat { 273 | struct { 274 | uint8_t align : 1; 275 | uint8_t rsvd1 : 7; 276 | } __attribute__((__packed__)) rsvd_align; 277 | uint8_t rsvd2[7]; 278 | uint32_t logical_blk_sz; 279 | uint64_t alignment_granularity; 280 | uint64_t lowest_aligned_lba; 281 | } __attribute__((__packed__)); 282 | 283 | struct datastore_feat { 284 | uint16_t max_num_datastores; 285 | uint32_t max_total_size_datastore_tbls; 286 | uint32_t datastore_size_align; 287 | } __attribute__((__packed__)); 288 | 289 | struct block_sid_feat { 290 | uint8_t sid_valuestate : 1; 291 | uint8_t sid_blockedstate : 1; 292 | uint8_t reserved : 6; 293 | uint8_t hardware_reset : 1; 294 | uint8_t reserved1 : 7; 295 | uint8_t reserved2[10]; 296 | } __attribute__((__packed__)); 297 | 298 | struct opalv100_feat { 299 | uint16_t v1_base_comid; 300 | uint16_t v1_comid_num; 301 | } __attribute__((__packed__)); 302 | 303 | struct opalv200_feat { 304 | uint16_t base_comid; 305 | uint16_t comid_num; 306 | struct { 307 | uint8_t range_crossing : 1; 308 | uint8_t rsvd1 : 7; 309 | } __attribute__((__packed__)) rangecross_rsvd; 310 | uint16_t admin_lp_auth_num; 311 | uint16_t user_lp_auth_num; 312 | uint8_t init_pin; 313 | uint8_t revert_pin; 314 | uint8_t reserved2[5]; 315 | } __attribute__((__packed__)); 316 | 317 | struct pyrite_feat { 318 | uint16_t base_comid; 319 | uint16_t comid_num; 320 | uint8_t reserved[5]; 321 | uint8_t init_pin; 322 | uint8_t revert_pin; 323 | uint8_t reserved2[5]; 324 | } __attribute__((__packed__)); 325 | 326 | struct data_rm_feat { 327 | uint8_t data[36]; 328 | } __attribute__((__packed__)); 329 | 330 | struct siis_feat { 331 | uint8_t data[16]; 332 | } __attribute__((__packed__)); 333 | 334 | struct sum_feat { 335 | uint32_t number_of_locking_objects_supported; 336 | uint8_t any : 1; 337 | uint8_t all : 1; 338 | uint8_t policy : 1; 339 | uint8_t reserved : 5; 340 | } __attribute__((__packed__)); 341 | 342 | struct cnl_feat { 343 | struct { 344 | uint8_t rsvd1 : 6; 345 | uint8_t range_p : 1; 346 | uint8_t range_c : 1; 347 | } __attribute__((__packed__)) ranges_rsvd; 348 | uint8_t rsvd2[3]; 349 | uint32_t max_key_count; 350 | uint32_t unused_key_count; 351 | uint32_t max_ranges_per_ns; 352 | } __attribute__((__packed__)); 353 | 354 | struct opal_l0_feat { 355 | int type; 356 | union { 357 | struct { 358 | struct tper_feat flags; 359 | } __attribute__((__packed__))tper; 360 | struct{ 361 | struct locking_feat flags; 362 | } __attribute__((__packed__)) locking; 363 | struct opalv100_feat opalv100; 364 | struct opalv200_feat opalv200; 365 | struct opalv200_feat ruby; 366 | struct pyrite_feat pyritev100; 367 | struct pyrite_feat pyritev200; 368 | } __attribute__((__packed__)) feat; 369 | } __attribute__((__packed__)); 370 | 371 | struct opal_l0_disc { 372 | uint32_t rev; 373 | uint16_t comid; 374 | struct opal_l0_feat feats[MAX_FEATURES]; 375 | } __attribute__((__packed__)); 376 | 377 | struct opal_level0_header { 378 | uint32_t len; 379 | uint32_t rev; 380 | uint64_t reserved; 381 | uint8_t vendor_specific[32]; 382 | } __attribute__((__packed__)) ; 383 | 384 | struct opal_level0_feat_desc { 385 | uint16_t code; 386 | uint8_t reserved : 4; 387 | uint8_t rev : 4; 388 | uint8_t len; 389 | union { 390 | struct { 391 | struct tper_feat flags; 392 | uint8_t reserved[11]; 393 | } __attribute__((__packed__)) tper; 394 | struct { 395 | struct locking_feat flags; 396 | uint8_t reserved[11]; 397 | } __attribute__((__packed__)) locking; 398 | struct { 399 | uint8_t reserved[2]; 400 | struct datastore_feat datastore; 401 | } datastore; 402 | struct geometry_feat geometry; 403 | struct opalv100_feat opalv100; 404 | struct opalv200_feat opalv200; 405 | struct opalv200_feat ruby; 406 | struct pyrite_feat pyritev100; 407 | struct pyrite_feat pyritev200; 408 | struct data_rm_feat data_rm; 409 | struct block_sid_feat block_sid; 410 | struct cnl_feat cnl; 411 | struct siis_feat siis; 412 | struct sum_feat sum; 413 | } feat; 414 | } __attribute__((__packed__)) ; 415 | 416 | struct opal_compacket { 417 | uint32_t reserved; 418 | uint8_t ext_comid[4]; 419 | uint32_t outstanding_data; 420 | uint32_t min_transfer; 421 | uint32_t length; 422 | } __attribute__((__packed__)); 423 | 424 | struct opal_packet { 425 | struct { 426 | uint32_t tsn; 427 | uint32_t hsn; 428 | } __attribute__((__packed__)) session; 429 | uint32_t seq_num; 430 | uint16_t reserved; 431 | uint16_t ack_type; 432 | uint32_t ack; 433 | uint32_t length; 434 | } __attribute__((__packed__)); 435 | 436 | struct opal_subpacket { 437 | uint8_t reserved[6]; 438 | uint16_t kind; 439 | uint32_t length; 440 | } __attribute__((__packed__)); 441 | 442 | struct opal_header { 443 | struct opal_compacket compacket; 444 | struct opal_packet packet; 445 | struct opal_subpacket subpacket; 446 | uint8_t payload[]; 447 | } __attribute__((__packed__)); 448 | 449 | struct opal_level0_discovery { 450 | struct tper_feat tper; 451 | struct locking_feat locking; 452 | struct geometry_feat geometry; 453 | struct datastore_feat datastore; 454 | struct opalv100_feat opalv100; 455 | struct opalv200_feat opalv200; 456 | }; 457 | 458 | int opal_init_pt(struct sed_device *dev, const char *device_path, bool try); 459 | 460 | int opal_host_prop_pt(struct sed_device *dev, const char *props, uint32_t *vals); 461 | 462 | int opal_dev_discovery_pt(struct sed_device *dev, struct sed_opal_device_discovery *discovery); 463 | 464 | int opal_parse_tper_state_pt(struct sed_device *dev, struct sed_tper_state *tper_state); 465 | 466 | int opal_start_session_pt(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, struct sed_session *session); 467 | 468 | int opal_end_session_pt(struct sed_device *dev, struct sed_session *session); 469 | 470 | int opal_start_end_transactions_pt(struct sed_device *dev, bool start, uint8_t status); 471 | 472 | int opal_take_ownership_pt(struct sed_device *dev, const struct sed_key *key); 473 | 474 | int opal_get_msid_pin_pt(struct sed_device *dev, struct sed_key *msid_pin); 475 | 476 | int opal_revert_pt(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, uint8_t *target_sp_uid); 477 | 478 | int opal_revert_lsp_pt(struct sed_device *dev, const struct sed_key *key, uint8_t *auth_uid, bool keep_global_range_key); 479 | 480 | int opal_activate_sp_pt(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 481 | uint8_t *target_sp_uid, char *lr_str, uint8_t range_start_length_policy, char *dsts_str); 482 | 483 | int opal_add_user_to_lr_pt(struct sed_device *dev, const struct sed_key *key, const char *user, 484 | enum SED_ACCESS_TYPE access_type, uint8_t lr); 485 | 486 | int opal_enable_user_pt(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, uint8_t *user_uid); 487 | 488 | int opal_setup_global_range_pt(struct sed_device *dev, const struct sed_key *key, enum SED_FLAG_TYPE rle, 489 | enum SED_FLAG_TYPE wle); 490 | 491 | int opal_setup_lr_pt(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, uint8_t *lr_uid, 492 | uint64_t range_start, uint64_t range_length, enum SED_FLAG_TYPE rle, enum SED_FLAG_TYPE wle); 493 | 494 | int opal_lock_unlock_pt(struct sed_device *dev, const struct sed_key *key, uint8_t *auth_uid, uint8_t lr, bool sum, 495 | enum SED_ACCESS_TYPE access_type); 496 | 497 | int opal_set_password_pt(struct sed_device *dev, uint8_t *sp_uid, uint8_t *auth_uid, const struct sed_key *auth_key, 498 | uint8_t *user_uid, const struct sed_key *new_user_key); 499 | 500 | int opal_mbr_done_pt(struct sed_device *dev, const struct sed_key *key, bool mbr_done); 501 | 502 | int opal_shadow_mbr_pt(struct sed_device *dev, const struct sed_key *key, bool mbr); 503 | 504 | int opal_read_shadow_mbr_pt(struct sed_device *dev, enum SED_AUTHORITY auth, const struct sed_key *key, uint8_t *to, 505 | uint32_t size, uint32_t offset); 506 | 507 | int opal_write_shadow_mbr_pt(struct sed_device *dev, const struct sed_key *key, const uint8_t *from, uint32_t size, 508 | uint32_t offset); 509 | 510 | int opal_erase_pt(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, uint8_t *uid); 511 | 512 | int opal_genkey_pt(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 513 | uint8_t *uid, uint32_t public_exponent, uint32_t pin_length); 514 | 515 | int opal_ds_read_pt(struct sed_device *, enum SED_AUTHORITY, const struct sed_key *, uint8_t *to, uint32_t size, 516 | uint32_t offset); 517 | 518 | int opal_ds_write_pt(struct sed_device *, enum SED_AUTHORITY, const struct sed_key *, const uint8_t *from, 519 | uint32_t size, uint32_t offset); 520 | 521 | int opal_ds_add_anybody_get_pt(struct sed_device *dev, const struct sed_key *key); 522 | 523 | int opal_list_lr_pt(struct sed_device *dev, const struct sed_key *key, struct sed_opal_locking_ranges *lrs); 524 | 525 | int opal_block_sid_pt(struct sed_device *dev, bool hw_reset); 526 | 527 | int opal_stack_reset_pt(struct sed_device *device, int32_t com_id, uint64_t extended_com_id, uint8_t *response); 528 | 529 | int opal_set_with_buf_pt(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 530 | uint8_t *uid, struct opal_req_item *cmd, size_t cmd_len); 531 | 532 | int opal_get_set_col_val_pt(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 533 | uint8_t *uid, uint64_t col, bool get, struct sed_opal_col_info *col_info); 534 | 535 | int opal_get_set_byte_table_pt(struct sed_device *dev, const struct sed_key *key, const enum SED_SP_TYPE sp, 536 | const char *user, uint8_t *uid, uint64_t start, uint64_t end, uint8_t *buffer, bool is_set); 537 | 538 | int opal_tper_reset_pt(struct sed_device *dev); 539 | 540 | int opal_reactivate_sp_pt(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 541 | uint8_t *target_sp_uid, char *lr_str, uint8_t range_start_length_policy, const struct sed_key *admin1_pwd, 542 | char *dsts_str); 543 | 544 | int opal_assign_pt(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 545 | uint32_t nsid, uint8_t range_start, uint8_t range_len, struct sed_locking_object *info); 546 | 547 | int opal_deassign_pt(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 548 | const uint8_t *uid, bool keep_ns_global_range_key); 549 | 550 | int opal_table_next_pt(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 551 | uint8_t *uid, uint8_t *where, uint16_t count, struct sed_next_uids *next_uids); 552 | 553 | int opal_authenticate_pt(struct sed_device *dev, enum SED_AUTHORITY auth, const struct sed_key *key); 554 | 555 | int opal_get_acl_pt(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 556 | const uint8_t *invoking_uid, const uint8_t *method_uid, struct sed_next_uids *next_uids); 557 | 558 | void opal_deinit_pt(struct sed_device *dev); 559 | 560 | #endif /* _NVME_PT_IOCTL_H */ 561 | -------------------------------------------------------------------------------- /src/lib/opal_parser.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2019, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | 14 | #include "opal_parser.h" 15 | #include "sedcli_log.h" 16 | 17 | #define msb64(x) (64 - __builtin_clzll(x)) 18 | 19 | #define MAX_SHORT_ATOM_DATA_LEN 16 20 | #define MAX_MEDIUM_ATOM_DATA_LEN 2048 21 | #define MAX_LONG_ATOM_DATA_LEN 16777216 22 | 23 | struct _opal_token { 24 | struct opal_token token; 25 | struct _opal_token *next; 26 | }; 27 | 28 | /* Token data storage */ 29 | static __thread struct _opal_token free_token_list = { .next = NULL }; 30 | static __thread struct _opal_token *token_storage = NULL; 31 | 32 | static int div_roundup(int n, int d) 33 | { 34 | if (n % d == 0) 35 | return (n / d); 36 | return (n / d + 1); 37 | } 38 | 39 | int opal_parser_init(void) 40 | { 41 | token_storage = (struct _opal_token *) malloc(sizeof(*token_storage) * OPAL_MAX_TOKENS); 42 | if (token_storage == NULL) { 43 | return -ENOMEM; 44 | } 45 | 46 | for (int i = 0; i < OPAL_MAX_TOKENS; i++) { 47 | token_storage[i].next = free_token_list.next; 48 | token_storage[i].token.priv = &token_storage[i]; 49 | free_token_list.next = &token_storage[i]; 50 | } 51 | 52 | return 0; 53 | } 54 | 55 | void opal_parser_deinit(void) 56 | { 57 | if (token_storage != NULL) { 58 | free(token_storage); 59 | token_storage = NULL; 60 | } 61 | free_token_list.next = NULL; 62 | } 63 | 64 | static int append_short_atom_bytes_header(uint8_t *buf, size_t len, int data_len) 65 | { 66 | uint8_t val = 0; 67 | 68 | if (len >= 1) { 69 | val |= OPAL_ATOM_SHORT_CODE; 70 | val |= OPAL_ATOM_SHORT_BYTESTRING; 71 | val |= 0; 72 | val |= data_len & OPAL_ATOM_SHORT_LEN_MASK; 73 | 74 | buf[0] = val; 75 | 76 | return 1; 77 | } 78 | 79 | return 0; 80 | } 81 | 82 | static int append_short_atom_uint_header(uint8_t *buf, size_t len, int data_len) 83 | { 84 | uint8_t val = 0; 85 | 86 | if (len >= 1) { 87 | val |= OPAL_ATOM_SHORT_CODE; 88 | val |= 0; 89 | val |= 0; 90 | val |= data_len & OPAL_ATOM_SHORT_LEN_MASK; 91 | 92 | buf[0] = val; 93 | 94 | return 1; 95 | } 96 | 97 | return 0; 98 | } 99 | 100 | static int append_medium_atom_bytes_header(uint8_t *buf, size_t len, int data_len) 101 | { 102 | uint8_t val = 0; 103 | 104 | if (len >= 2) { 105 | val = OPAL_ATOM_MEDIUM_CODE; 106 | val |= OPAL_ATOM_MEDIUM_BYTESTRING; 107 | val |= 0; 108 | val |= (data_len >> 8) & OPAL_ATOM_MEDIUM_LEN_MASK; 109 | 110 | buf[0] = val; 111 | buf[1] = data_len; 112 | 113 | return 2; 114 | } 115 | 116 | return 0; 117 | } 118 | 119 | static int append_long_atom_bytes_header(uint8_t *buf, size_t len, int data_len) 120 | { 121 | uint8_t val = 0; 122 | 123 | if (len >= 4) { 124 | val = OPAL_ATOM_LONG_CODE; 125 | val |= OPAL_ATOM_LONG_BYTESTRING; 126 | 127 | buf[0] = val; 128 | buf[1] = (data_len >> 16) & 0xff; 129 | buf[2] = (data_len >> 8) & 0xff; 130 | buf[3] = (data_len >> 0) & 0xff; 131 | 132 | return 4; 133 | } 134 | 135 | return 0; 136 | } 137 | 138 | int append_u8(uint8_t *buf, size_t len, uint8_t val) 139 | { 140 | if (len >= 1) { 141 | buf[0] = val; 142 | return 1; 143 | } 144 | else 145 | return 0; 146 | } 147 | 148 | /*assumption is that val is Little Endian*/ 149 | int append_u64(uint8_t *buf, size_t len, uint64_t val) 150 | { 151 | int ret = 0; 152 | 153 | /* number fits into tiny atom */ 154 | if (!(val & ~OPAL_ATOM_TINY_DATA_MASK)) { 155 | if (len >= 1) { 156 | buf[0] = val; 157 | ret += 1; 158 | } 159 | /* number fits into short atom */ 160 | } else { 161 | uint64_t bytes_no = 0; 162 | 163 | /* round up number of bytes needed */ 164 | bytes_no = div_roundup(val ? msb64(val) : 0, 8); 165 | 166 | if (len >= (bytes_no + 1)) { 167 | ret += append_short_atom_uint_header(buf, len, bytes_no); 168 | /* put number into buffer as big endian */ 169 | while (bytes_no--) { 170 | ret += append_u8(buf + ret, len - ret, val >> 171 | (bytes_no * 8)); 172 | } 173 | } 174 | } 175 | 176 | return ret; 177 | } 178 | 179 | int append_bytes(uint8_t *buf, size_t len, const uint8_t *src, size_t src_len) 180 | { 181 | int ret = 0; 182 | 183 | assert(src_len < MAX_LONG_ATOM_DATA_LEN); 184 | 185 | /* data fits into opal short atom */ 186 | if (src_len < MAX_SHORT_ATOM_DATA_LEN) { 187 | if (len >= src_len + 1) 188 | ret += append_short_atom_bytes_header(buf, len, src_len); 189 | 190 | /* data fits into opal medium atom */ 191 | } else if (src_len < MAX_MEDIUM_ATOM_DATA_LEN) { 192 | if (len >= src_len + 2) 193 | ret += append_medium_atom_bytes_header(buf, len, src_len); 194 | 195 | /* data fits into opal long atom */ 196 | } else if (src_len < MAX_LONG_ATOM_DATA_LEN) { 197 | if (len >= src_len + 4) 198 | ret += append_long_atom_bytes_header(buf, len, src_len); 199 | } 200 | 201 | memcpy(buf + ret, src, src_len); 202 | ret += src_len; 203 | 204 | return ret; 205 | } 206 | 207 | static void parse_tiny_token(struct opal_token *token, uint8_t curr_byte) 208 | { 209 | token->width = OPAL_WIDTH_TINY; 210 | token->len = 1; 211 | 212 | if ((curr_byte >> 6) & 1) 213 | token->type = OPAL_DTA_TOKENID_SINT; 214 | else { 215 | token->type = OPAL_DTA_TOKENID_UINT; 216 | token->vals.uint = curr_byte & 0x3f; 217 | } 218 | } 219 | 220 | static size_t parse_short_token(struct opal_token *token, const uint8_t *buf, int len) 221 | { 222 | uint8_t curr_byte; 223 | int i, idx = 0; 224 | 225 | curr_byte = buf[0]; 226 | token->vals.uint = 0; 227 | token->width = OPAL_WIDTH_SHORT; 228 | token->len = (curr_byte & OPAL_ATOM_SHORT_LEN_MASK) + 1; 229 | token->pos = buf; 230 | 231 | if (len - token->len <= 0) 232 | return -1; 233 | 234 | if (curr_byte & OPAL_ATOM_SHORT_BYTESTRING) 235 | token->type = OPAL_DTA_TOKENID_BYTESTRING; 236 | else { 237 | if (curr_byte & OPAL_ATOM_SHORT_SIGNED) 238 | token->type = OPAL_DTA_TOKENID_SINT; 239 | else { 240 | token->type = OPAL_DTA_TOKENID_UINT; 241 | if (token->len <= 9) { 242 | for (i = token->len - 1; i > 0; i--) { 243 | token->vals.uint |= (uint64_t)buf[i] << (8 * idx); 244 | idx++; 245 | } 246 | } 247 | else { 248 | SEDCLI_DEBUG_MSG("unsigned integer exceeds 8 bytes.\n"); 249 | return -EINVAL; 250 | } 251 | } 252 | } 253 | 254 | return token->len; 255 | } 256 | 257 | static size_t parse_medium_token(struct opal_token *token, const uint8_t *buf, int len) 258 | { 259 | token->width = OPAL_WIDTH_MEDIUM; 260 | token->len = (((buf[0] & OPAL_ATOM_MEDIUM_LEN_MASK) << 8) | buf[1]) + 2; 261 | token->pos = buf; 262 | 263 | if (len - token->len <= 0) 264 | return -1; 265 | 266 | if (buf[0] & OPAL_ATOM_MEDIUM_BYTESTRING) 267 | token->type = OPAL_DTA_TOKENID_BYTESTRING; 268 | else if (buf[0] & OPAL_ATOM_MEDIUM_SIGNED) 269 | token->type = OPAL_DTA_TOKENID_SINT; 270 | else 271 | token->type = OPAL_DTA_TOKENID_UINT; 272 | 273 | return token->len; 274 | } 275 | 276 | static size_t parse_long_token(struct opal_token *token, const uint8_t *buf, int len) 277 | { 278 | token->width = OPAL_WIDTH_LONG; 279 | token->len = ((buf[1] << 16) | (buf[2] << 8) | buf[3]) + 4; 280 | token->pos = buf; 281 | 282 | if (len - token->len <= 0) { 283 | return -1; 284 | } 285 | 286 | /* Check if the token is a byte_string or unsigned or signed */ 287 | if (buf[0] & OPAL_ATOM_LONG_BYTESTRING) 288 | token->type = OPAL_DTA_TOKENID_BYTESTRING; 289 | else if (buf[0] & OPAL_ATOM_LONG_SIGNED) 290 | token->type = OPAL_DTA_TOKENID_SINT; 291 | else 292 | token->type = OPAL_DTA_TOKENID_UINT; 293 | 294 | return token->len; 295 | } 296 | 297 | static struct opal_token *alloc_token(struct _opal_token *free_head) 298 | { 299 | struct _opal_token *ret; 300 | 301 | ret = free_head->next; 302 | if (ret == NULL) 303 | return NULL; 304 | 305 | free_head->next = ret->next; 306 | ret->next = NULL; 307 | 308 | return &ret->token; 309 | } 310 | 311 | static void dealloc_token(struct _opal_token *free_head, struct opal_token *item) 312 | { 313 | struct _opal_token *ret_item = (struct _opal_token *)item->priv; 314 | 315 | ret_item->next = free_head->next; 316 | free_head->next = ret_item; 317 | } 318 | 319 | static void opal_put_token(struct opal_token *token) 320 | { 321 | dealloc_token(&free_token_list, token); 322 | } 323 | 324 | void opal_put_all_tokens(struct opal_token **tokens, size_t *len) 325 | { 326 | if (*len >= OPAL_MAX_TOKENS) { 327 | SEDCLI_DEBUG_MSG("Put tokens error!\n"); 328 | return; 329 | } 330 | 331 | if (tokens) { 332 | for (size_t i = 0; i < *len; i++) { 333 | if (tokens[i] != NULL) { 334 | opal_put_token(tokens[i]); 335 | tokens[i] = NULL; 336 | } 337 | } 338 | } 339 | 340 | *len = 0; 341 | } 342 | 343 | /* Assumptions: 344 | * 1. TCG reserved tokens are ignored, 345 | * 2. Buffer pointer "pos" points to begining of the token 346 | * 3. Last position in buffer is returned in the last parameter 347 | * 4. NULL is returned if buffer is too small 348 | */ 349 | static struct opal_token *opal_get_next_token(uint8_t *buf, int len, int *pos) 350 | { 351 | struct opal_token *token; 352 | uint8_t curr_byte; 353 | int offset = 0, done; 354 | size_t status; 355 | 356 | token = alloc_token(&free_token_list); 357 | if (token == NULL) 358 | return NULL; 359 | 360 | offset = *pos; 361 | 362 | /* iterate until non-empty and non-reserved token has been found */ 363 | done = 0; 364 | while (!done) { 365 | if ((len - offset) <= 0) { 366 | *pos = offset; 367 | goto put_token; 368 | } 369 | 370 | curr_byte = buf[0]; 371 | done = 1; 372 | 373 | switch (curr_byte) { 374 | case 0x00 ... 0x7F: 375 | parse_tiny_token(token, curr_byte); 376 | token->pos = buf; 377 | offset++; 378 | break; 379 | case 0x80 ... 0xBF: 380 | status = parse_short_token(token, buf, len - offset); 381 | if (status > 0) 382 | offset += status; 383 | else 384 | goto put_token; 385 | 386 | break; 387 | case 0xC0 ... 0xDF: 388 | status = parse_medium_token(token, buf, len - offset); 389 | if (status > 0) 390 | offset += status; 391 | else 392 | goto put_token; 393 | break; 394 | case 0xE0 ... 0xE3: 395 | status = parse_long_token(token, buf, len - offset); 396 | if (status > 0) 397 | offset += status; 398 | else 399 | goto put_token; 400 | 401 | break; 402 | default: 403 | token->width = OPAL_WIDTH_TOKEN; 404 | /* the actual token is returned */ 405 | token->type = OPAL_DTA_TOKENID_TOKEN; 406 | 407 | token->len = 1; 408 | token->pos = buf; 409 | offset++; 410 | break; 411 | } 412 | } 413 | 414 | *pos = offset; 415 | 416 | return token; 417 | 418 | put_token: 419 | opal_put_token(token); 420 | 421 | return NULL; 422 | } 423 | 424 | int opal_parse_data_payload(uint8_t *buf, size_t len, struct opal_parsed_payload *payload) 425 | { 426 | struct opal_token *token; 427 | int offset = 0, i = 0; 428 | 429 | payload->len = 0; 430 | while ((token = opal_get_next_token(buf + offset, len, &offset)) != NULL) { 431 | payload->tokens[i] = &(*token); 432 | i++; 433 | } 434 | 435 | /* TODO: check if any errors while parsing data payload */ 436 | if (i == 0) { 437 | SEDCLI_DEBUG_MSG("The no. of tokens is 0 and the response can't be parsed.\n"); 438 | return -EINVAL; 439 | } 440 | 441 | payload->len = i; 442 | 443 | return i; 444 | } 445 | -------------------------------------------------------------------------------- /src/lib/opal_parser.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2019, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | 7 | #ifndef _OPAL_PARSER_H_ 8 | #define _OPAL_PARSER_H_ 9 | 10 | #define OPAL_MAX_TOKENS 32768 11 | #define OPAL_MAX_LRS 9 12 | #define OPAL_MAX_DSTS 256 13 | 14 | #define OPAL_ATOM_TINY_CODE 0X00 15 | #define OPAL_ATOM_TINY_DATA_MASK 0x3F 16 | #define OPAL_ATOM_TINY_SIGNED 0x40 17 | 18 | #define OPAL_ATOM_SHORT_CODE 0x80 19 | #define OPAL_ATOM_SHORT_LEN_MASK 0x0F 20 | #define OPAL_ATOM_SHORT_SIGNED 0x10 21 | #define OPAL_ATOM_SHORT_BYTESTRING 0x20 22 | 23 | #define OPAL_ATOM_MEDIUM_CODE 0xC0 24 | #define OPAL_ATOM_MEDIUM_LEN_MASK 0x07 25 | #define OPAL_ATOM_MEDIUM_SIGNED 0x8 26 | #define OPAL_ATOM_MEDIUM_BYTESTRING 0x10 27 | 28 | #define OPAL_ATOM_LONG_CODE 0xe0 29 | #define OPAL_ATOM_LONG_SIGNED 0x1 30 | #define OPAL_ATOM_LONG_BYTESTRING 0x2 31 | 32 | #define OPAL_U8 (1) 33 | #define OPAL_U64 (2) 34 | #define OPAL_BYTES (3) 35 | 36 | enum opal_atom_width { 37 | OPAL_WIDTH_TINY, 38 | OPAL_WIDTH_SHORT, 39 | OPAL_WIDTH_MEDIUM, 40 | OPAL_WIDTH_LONG, 41 | OPAL_WIDTH_TOKEN 42 | }; 43 | 44 | enum opal_token_type { 45 | OPAL_DTA_TOKENID_BYTESTRING = 0xE0, 46 | OPAL_DTA_TOKENID_SINT = 0xE1, 47 | OPAL_DTA_TOKENID_UINT = 0xE2, 48 | OPAL_DTA_TOKENID_TOKEN = 0xE3, /* actual token is returned */ 49 | OPAL_DTA_TOKENID_INVALID = 0X0 50 | }; 51 | 52 | enum opal_mbr { 53 | OPAL_MBR_ENABLE = 0x00, 54 | OPAL_MBR_DISABLE = 0x01, 55 | }; 56 | 57 | enum opal_user { 58 | OPAL_ADMIN1 = 0x0, 59 | OPAL_USER1 = 0x01, 60 | OPAL_USER2 = 0x02, 61 | OPAL_USER3 = 0x03, 62 | OPAL_USER4 = 0x04, 63 | OPAL_USER5 = 0x05, 64 | OPAL_USER6 = 0x06, 65 | OPAL_USER7 = 0x07, 66 | OPAL_USER8 = 0x08, 67 | OPAL_USER9 = 0x09, 68 | }; 69 | 70 | enum opal_lock_state { 71 | OPAL_RO = 0x01, /* 0001 */ 72 | OPAL_RW = 0x02, /* 0010 */ 73 | OPAL_LK = 0x04, /* 0100 */ 74 | }; 75 | 76 | struct opal_token { 77 | void *priv; 78 | int len; 79 | const uint8_t *pos; 80 | enum opal_atom_width width; 81 | enum opal_token_type type; 82 | union { 83 | int64_t sint; 84 | uint64_t uint; 85 | } vals; 86 | }; 87 | 88 | struct opal_parsed_payload { 89 | struct opal_token *tokens[OPAL_MAX_TOKENS]; 90 | size_t len; 91 | }; 92 | 93 | int opal_parser_init(void); 94 | void opal_parser_deinit(void); 95 | 96 | int append_u8(uint8_t *buf, size_t len, uint8_t val); 97 | int append_u64(uint8_t *buf, size_t len, uint64_t val); 98 | int append_bytes(uint8_t *buf, size_t len, const uint8_t *src, size_t src_len); 99 | 100 | int opal_parse_data_payload(uint8_t *buf, size_t len, struct opal_parsed_payload *payload); 101 | void opal_put_all_tokens(struct opal_token **tokens, size_t *len); 102 | 103 | #endif /* _OPAL_PARSER_H_ */ 104 | -------------------------------------------------------------------------------- /src/lib/sed.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2019, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | 13 | #include "nvme_pt_ioctl.h" 14 | #include "sed_util.h" 15 | #include "sedcli_log.h" 16 | 17 | #define ARRAY_SIZE(x) ((size_t)(sizeof(x) / sizeof(x[0]))) 18 | #define NVME_DEV_PREFIX "nvme" 19 | #define PATH_MAX 4096 20 | 21 | typedef int (*init)(struct sed_device *, const char *, bool); 22 | typedef int (*host_prop)(struct sed_device *, const char *, uint32_t *); 23 | typedef int (*dev_discovery)(struct sed_device *, struct sed_opal_device_discovery *); 24 | typedef int (*parse_tper_state)(struct sed_device *, struct sed_tper_state *); 25 | typedef int (*take_ownership)(struct sed_device *, const struct sed_key *); 26 | typedef int (*get_msid_pin)(struct sed_device *, struct sed_key *); 27 | typedef int (*revert)(struct sed_device *, const struct sed_key *, uint8_t *, uint8_t *, uint8_t *); 28 | typedef int (*revert_lsp)(struct sed_device *, const struct sed_key *, uint8_t *, bool); 29 | typedef int (*activate_sp)(struct sed_device *, const struct sed_key *, uint8_t *, uint8_t *, uint8_t *, char *, 30 | uint8_t, char *); 31 | typedef int (*setup_global_range)(struct sed_device *, const struct sed_key *, enum SED_FLAG_TYPE, enum SED_FLAG_TYPE); 32 | typedef int (*add_user_to_lr)(struct sed_device *, const struct sed_key *, const char *, enum SED_ACCESS_TYPE, uint8_t); 33 | typedef int (*enable_user)(struct sed_device *, const struct sed_key *, uint8_t *, uint8_t *, uint8_t *); 34 | typedef int (*setup_lr)(struct sed_device *, const struct sed_key *, uint8_t *, uint8_t *, uint8_t *, uint64_t, uint64_t, 35 | enum SED_FLAG_TYPE, enum SED_FLAG_TYPE); 36 | typedef int (*lock_unlock)(struct sed_device *, const struct sed_key *, uint8_t *, uint8_t, bool, enum SED_ACCESS_TYPE); 37 | typedef int (*set_password)(struct sed_device *, uint8_t *, uint8_t *, const struct sed_key *, uint8_t *, 38 | const struct sed_key *); 39 | typedef int (*shadow_mbr)(struct sed_device *, const struct sed_key *, bool); 40 | typedef int (*mbr_done) (struct sed_device *, const struct sed_key *, bool); 41 | typedef int (*read_shadow_mbr) (struct sed_device *, enum SED_AUTHORITY, const struct sed_key *, uint8_t *, uint32_t, 42 | uint32_t); 43 | typedef int (*write_shadow_mbr)(struct sed_device *, const struct sed_key *, const uint8_t *, uint32_t, uint32_t); 44 | typedef int (*erase)(struct sed_device *, const struct sed_key *, uint8_t *, uint8_t *, uint8_t *); 45 | typedef int (*genkey) (struct sed_device *, const struct sed_key *, uint8_t *, uint8_t *, uint8_t *, 46 | uint32_t, uint32_t); 47 | typedef int (*ds_add_anybody_get)(struct sed_device *, const struct sed_key *); 48 | typedef int (*ds_read)(struct sed_device *, enum SED_AUTHORITY, const struct sed_key *, uint8_t *, uint32_t, uint32_t); 49 | typedef int (*ds_write)(struct sed_device *, enum SED_AUTHORITY, const struct sed_key *, const uint8_t *, uint32_t, 50 | uint32_t); 51 | typedef int (*list_lr)(struct sed_device *, const struct sed_key *, struct sed_opal_locking_ranges *); 52 | typedef int (*block_sid)(struct sed_device *, bool); 53 | typedef int (*stack_reset)(struct sed_device *, int32_t com_id, uint64_t extended_com_id, uint8_t *response); 54 | typedef int (*start_session)(struct sed_device *, const struct sed_key *, uint8_t *, uint8_t *, struct sed_session *); 55 | typedef int (*end_session)(struct sed_device *, struct sed_session *); 56 | typedef int (*start_end_transactions)(struct sed_device *, bool, uint8_t); 57 | typedef int (*set_with_buf)(struct sed_device *, const struct sed_key *, uint8_t *, uint8_t *, uint8_t *, 58 | struct opal_req_item *, size_t); 59 | typedef int (*get_set_col_val)(struct sed_device *, const struct sed_key *, uint8_t *, uint8_t *, uint8_t *, 60 | uint64_t, bool, struct sed_opal_col_info *); 61 | typedef int (*tper_reset)(struct sed_device *); 62 | typedef int (*get_set_byte_table)(struct sed_device *, const struct sed_key *, const enum SED_SP_TYPE, 63 | const char *, uint8_t *, uint64_t, uint64_t, uint8_t *, bool is_set); 64 | typedef int (*reactivate_sp)(struct sed_device *, const struct sed_key *, uint8_t *, uint8_t *, uint8_t *, char *, uint8_t, 65 | const struct sed_key *, char *); 66 | typedef int (*assign)(struct sed_device *, const struct sed_key *, uint8_t *, uint8_t *, uint32_t, 67 | uint8_t, uint8_t, struct sed_locking_object *); 68 | typedef int (*deassign)(struct sed_device *, const struct sed_key *, uint8_t *, uint8_t *, 69 | const uint8_t *, bool); 70 | typedef int (*table_next)(struct sed_device *, const struct sed_key *, uint8_t *, uint8_t *, uint8_t *, uint8_t *, 71 | uint16_t, struct sed_next_uids *); 72 | typedef int (*authenticate)(struct sed_device *, enum SED_AUTHORITY, const struct sed_key *); 73 | typedef int (*get_acl)(struct sed_device *, const struct sed_key *, uint8_t *, uint8_t *, const uint8_t *, 74 | const uint8_t *, struct sed_next_uids *); 75 | typedef void (*deinit)(struct sed_device *); 76 | 77 | #define OPAL_INTERFACE(FN) FN FN ##_fn 78 | 79 | struct opal_interface { 80 | OPAL_INTERFACE(init); 81 | OPAL_INTERFACE(host_prop); 82 | OPAL_INTERFACE(dev_discovery); 83 | OPAL_INTERFACE(parse_tper_state); 84 | OPAL_INTERFACE(take_ownership); 85 | OPAL_INTERFACE(get_msid_pin); 86 | OPAL_INTERFACE(revert); 87 | OPAL_INTERFACE(revert_lsp); 88 | OPAL_INTERFACE(activate_sp); 89 | OPAL_INTERFACE(setup_global_range); 90 | OPAL_INTERFACE(add_user_to_lr); 91 | OPAL_INTERFACE(enable_user); 92 | OPAL_INTERFACE(setup_lr); 93 | OPAL_INTERFACE(lock_unlock); 94 | OPAL_INTERFACE(set_password); 95 | OPAL_INTERFACE(shadow_mbr); 96 | OPAL_INTERFACE(read_shadow_mbr); 97 | OPAL_INTERFACE(write_shadow_mbr); 98 | OPAL_INTERFACE(mbr_done); 99 | OPAL_INTERFACE(erase); 100 | OPAL_INTERFACE(genkey); 101 | OPAL_INTERFACE(ds_add_anybody_get); 102 | OPAL_INTERFACE(ds_read); 103 | OPAL_INTERFACE(ds_write); 104 | OPAL_INTERFACE(list_lr); 105 | OPAL_INTERFACE(block_sid); 106 | OPAL_INTERFACE(stack_reset); 107 | OPAL_INTERFACE(start_session); 108 | OPAL_INTERFACE(end_session); 109 | OPAL_INTERFACE(start_end_transactions); 110 | OPAL_INTERFACE(set_with_buf); 111 | OPAL_INTERFACE(get_set_col_val); 112 | OPAL_INTERFACE(tper_reset); 113 | OPAL_INTERFACE(reactivate_sp); 114 | OPAL_INTERFACE(assign); 115 | OPAL_INTERFACE(deassign); 116 | OPAL_INTERFACE(table_next); 117 | OPAL_INTERFACE(authenticate); 118 | OPAL_INTERFACE(get_acl); 119 | OPAL_INTERFACE(deinit); 120 | OPAL_INTERFACE(get_set_byte_table); 121 | }; 122 | 123 | #define OPAL_INTERFACE_DEF(FN) .FN ## _fn = opal_ ## FN ## _pt 124 | 125 | static struct opal_interface nvmept_if = { 126 | OPAL_INTERFACE_DEF(init), 127 | OPAL_INTERFACE_DEF(host_prop), 128 | OPAL_INTERFACE_DEF(dev_discovery), 129 | OPAL_INTERFACE_DEF(parse_tper_state), 130 | OPAL_INTERFACE_DEF(take_ownership), 131 | OPAL_INTERFACE_DEF(get_msid_pin), 132 | OPAL_INTERFACE_DEF(revert), 133 | OPAL_INTERFACE_DEF(revert_lsp), 134 | OPAL_INTERFACE_DEF(activate_sp), 135 | OPAL_INTERFACE_DEF(setup_global_range), 136 | OPAL_INTERFACE_DEF(add_user_to_lr), 137 | OPAL_INTERFACE_DEF(enable_user), 138 | OPAL_INTERFACE_DEF(setup_lr), 139 | OPAL_INTERFACE_DEF(lock_unlock), 140 | OPAL_INTERFACE_DEF(set_password), 141 | OPAL_INTERFACE_DEF(shadow_mbr), 142 | OPAL_INTERFACE_DEF(read_shadow_mbr), 143 | OPAL_INTERFACE_DEF(write_shadow_mbr), 144 | OPAL_INTERFACE_DEF(mbr_done), 145 | OPAL_INTERFACE_DEF(erase), 146 | OPAL_INTERFACE_DEF(genkey), 147 | OPAL_INTERFACE_DEF(ds_add_anybody_get), 148 | OPAL_INTERFACE_DEF(ds_read), 149 | OPAL_INTERFACE_DEF(ds_write), 150 | OPAL_INTERFACE_DEF(list_lr), 151 | OPAL_INTERFACE_DEF(block_sid), 152 | OPAL_INTERFACE_DEF(stack_reset), 153 | OPAL_INTERFACE_DEF(start_session), 154 | OPAL_INTERFACE_DEF(end_session), 155 | OPAL_INTERFACE_DEF(start_end_transactions), 156 | OPAL_INTERFACE_DEF(set_with_buf), 157 | OPAL_INTERFACE_DEF(get_set_col_val), 158 | OPAL_INTERFACE_DEF(tper_reset), 159 | OPAL_INTERFACE_DEF(reactivate_sp), 160 | OPAL_INTERFACE_DEF(assign), 161 | OPAL_INTERFACE_DEF(deassign), 162 | OPAL_INTERFACE_DEF(table_next), 163 | OPAL_INTERFACE_DEF(authenticate), 164 | OPAL_INTERFACE_DEF(get_acl), 165 | OPAL_INTERFACE_DEF(deinit), 166 | OPAL_INTERFACE_DEF(get_set_byte_table), 167 | }; 168 | 169 | static struct opal_interface *curr_if = &nvmept_if; 170 | 171 | uint32_t nvme_error = 0; 172 | int sed_init(struct sed_device **dev, const char *dev_path, bool try) 173 | { 174 | struct sed_device *ret = malloc(sizeof(*ret)); 175 | if (ret == NULL) 176 | return -ENOMEM; 177 | 178 | memset(ret, 0, sizeof(*ret)); 179 | 180 | char *base = basename(dev_path); 181 | if (strncmp(base, NVME_DEV_PREFIX, strnlen(NVME_DEV_PREFIX, PATH_MAX))) { 182 | sed_deinit(ret); 183 | SEDCLI_DEBUG_PARAM("%s is not an NVMe device and opal-driver not built-in!\n", dev_path); 184 | return -EINVAL; 185 | } 186 | 187 | int status = curr_if->init_fn(ret, dev_path, try); 188 | if (status != 0) { 189 | sed_deinit(ret); 190 | SEDCLI_DEBUG_PARAM("Error initializing the device: %s with status: %d\n", dev_path, status); 191 | nvme_error = status; 192 | return status; 193 | } 194 | 195 | *dev = ret; 196 | 197 | return status; 198 | } 199 | 200 | int sed_host_prop(struct sed_device *dev, const char *props, uint32_t *vals) 201 | { 202 | if (curr_if->host_prop_fn == NULL) 203 | return -EOPNOTSUPP; 204 | 205 | return curr_if->host_prop_fn(dev, props, vals); 206 | } 207 | 208 | int sed_dev_discovery(struct sed_device *dev, struct sed_opal_device_discovery *discovery) 209 | { 210 | if (curr_if->dev_discovery_fn == NULL) 211 | return -EOPNOTSUPP; 212 | 213 | return curr_if->dev_discovery_fn(dev, discovery); 214 | } 215 | 216 | int sed_parse_tper_state(struct sed_device *dev, struct sed_tper_state *tper_state) 217 | { 218 | if (curr_if->parse_tper_state_fn == NULL) 219 | return -EOPNOTSUPP; 220 | 221 | return curr_if->parse_tper_state_fn(dev, tper_state); 222 | } 223 | 224 | void sed_deinit(struct sed_device *dev) 225 | { 226 | if (dev != NULL) { 227 | curr_if->deinit_fn(dev); 228 | memset(dev, 0, sizeof(*dev)); 229 | free(dev); 230 | } 231 | } 232 | 233 | int sed_key_init(struct sed_key *auth_key, char *key, const uint8_t key_len) 234 | { 235 | if (key_len == 0) 236 | return -EINVAL; 237 | 238 | memcpy(auth_key->key, key, key_len); 239 | auth_key->len = key_len; 240 | 241 | return 0; 242 | } 243 | 244 | int sed_take_ownership(struct sed_device *dev, const struct sed_key *key) 245 | { 246 | if (curr_if->take_ownership_fn == NULL) 247 | return -EOPNOTSUPP; 248 | 249 | return curr_if->take_ownership_fn(dev, key); 250 | } 251 | 252 | int sed_get_msid_pin(struct sed_device *dev, struct sed_key *msid_pin) 253 | { 254 | if (curr_if->get_msid_pin_fn == NULL) 255 | return -EOPNOTSUPP; 256 | 257 | return curr_if->get_msid_pin_fn(dev, msid_pin); 258 | } 259 | 260 | int sed_setup_global_range(struct sed_device *dev, const struct sed_key *key, enum SED_FLAG_TYPE rle, 261 | enum SED_FLAG_TYPE wle) 262 | { 263 | if (curr_if->setup_global_range_fn == NULL) 264 | return -EOPNOTSUPP; 265 | 266 | return curr_if->setup_global_range_fn(dev, key, rle, wle); 267 | } 268 | 269 | int sed_revert(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, uint8_t *target_sp_uid) 270 | { 271 | if (curr_if->revert_fn == NULL) 272 | return -EOPNOTSUPP; 273 | 274 | return curr_if->revert_fn(dev, key, sp_uid, auth_uid, target_sp_uid); 275 | } 276 | 277 | int sed_revert_lsp(struct sed_device *dev, const struct sed_key *key, uint8_t *auth_uid, bool keep_global_range_key) 278 | { 279 | if (curr_if->revert_lsp_fn == NULL) 280 | return -EOPNOTSUPP; 281 | 282 | return curr_if->revert_lsp_fn(dev, key, auth_uid, keep_global_range_key); 283 | } 284 | 285 | int sed_activate_sp(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 286 | uint8_t *target_sp_uid, char *lr_str, uint8_t range_start_length_policy, char *dsts_str) 287 | { 288 | if (curr_if->activate_sp_fn == NULL) 289 | return -EOPNOTSUPP; 290 | 291 | return curr_if->activate_sp_fn(dev, key, sp_uid, auth_uid, target_sp_uid, lr_str, range_start_length_policy, dsts_str); 292 | } 293 | 294 | int sed_lock_unlock(struct sed_device *dev, const struct sed_key *key, uint8_t *auth_uid, uint8_t lr, bool sum, 295 | enum SED_ACCESS_TYPE access_type) 296 | { 297 | if (curr_if->lock_unlock_fn == NULL) 298 | return -EOPNOTSUPP; 299 | 300 | return curr_if->lock_unlock_fn(dev, key, auth_uid, lr, sum, access_type); 301 | } 302 | 303 | int sed_add_user_to_lr(struct sed_device *dev, const struct sed_key *key, const char *user, 304 | enum SED_ACCESS_TYPE access_type, uint8_t lr) 305 | { 306 | if (curr_if->add_user_to_lr_fn == NULL) 307 | return -EOPNOTSUPP; 308 | 309 | return curr_if->add_user_to_lr_fn(dev, key, user, access_type, lr); 310 | } 311 | 312 | int sed_enable_user(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 313 | uint8_t *user_uid) 314 | { 315 | if (curr_if->enable_user_fn == NULL) 316 | return -EOPNOTSUPP; 317 | 318 | return curr_if->enable_user_fn(dev, key, sp_uid, auth_uid, user_uid); 319 | } 320 | 321 | int sed_setup_lr(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 322 | uint8_t *lr_uid, uint64_t range_start, uint64_t range_length, enum SED_FLAG_TYPE rle, enum SED_FLAG_TYPE wle) 323 | { 324 | return curr_if->setup_lr_fn(dev, key, sp_uid, auth_uid, lr_uid, range_start, range_length, rle, wle); 325 | } 326 | 327 | int sed_set_password(struct sed_device *dev, uint8_t *sp_uid, uint8_t *auth_uid, const struct sed_key *auth_key, 328 | uint8_t *user_uid, const struct sed_key *new_user_key) 329 | { 330 | return curr_if->set_password_fn(dev, sp_uid, auth_uid, auth_key, user_uid, new_user_key); 331 | } 332 | 333 | int sed_shadow_mbr(struct sed_device *dev, const struct sed_key *key, bool mbr) 334 | { 335 | return curr_if->shadow_mbr_fn(dev, key, mbr); 336 | } 337 | 338 | int sed_read_shadow_mbr(struct sed_device *dev, enum SED_AUTHORITY auth, const struct sed_key *key,uint8_t *to, 339 | uint32_t size, uint32_t offset) 340 | { 341 | if (curr_if->read_shadow_mbr_fn == NULL) 342 | return -EOPNOTSUPP; 343 | 344 | return curr_if->read_shadow_mbr_fn(dev, auth, key, to, size, offset); 345 | } 346 | 347 | int sed_write_shadow_mbr(struct sed_device *dev, const struct sed_key *key, const uint8_t *from, uint32_t size, 348 | uint32_t offset) 349 | { 350 | if (curr_if->write_shadow_mbr_fn == NULL) 351 | return -EOPNOTSUPP; 352 | 353 | return curr_if->write_shadow_mbr_fn(dev, key, from, size, offset); 354 | } 355 | 356 | int sed_mbr_done(struct sed_device *dev, const struct sed_key *key, bool mbr) 357 | { 358 | if (curr_if->mbr_done_fn == NULL) 359 | return -EOPNOTSUPP; 360 | 361 | return curr_if->mbr_done_fn(dev, key, mbr); 362 | } 363 | 364 | int sed_erase(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 365 | uint8_t *uid) 366 | { 367 | if (curr_if->erase_fn == NULL) 368 | return -EOPNOTSUPP; 369 | 370 | return curr_if->erase_fn(dev, key, sp_uid, auth_uid, uid); 371 | } 372 | 373 | int sed_genkey(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 374 | uint8_t *uid, uint32_t public_exponent, uint32_t pin_length) 375 | { 376 | if (curr_if->genkey_fn == NULL) 377 | return -EOPNOTSUPP; 378 | 379 | return curr_if->genkey_fn(dev, key, sp_uid, auth_uid, uid, public_exponent, pin_length); 380 | } 381 | 382 | int sed_ds_read(struct sed_device *dev, enum SED_AUTHORITY auth, const struct sed_key *key, uint8_t *to, uint32_t size, 383 | uint32_t offset) 384 | { 385 | if (curr_if->ds_read_fn == NULL) 386 | return -EOPNOTSUPP; 387 | 388 | if (auth != SED_ANYBODY && key == NULL) { 389 | SEDCLI_DEBUG_MSG("Key can't be null\n"); 390 | return -EINVAL; 391 | } 392 | 393 | return curr_if->ds_read_fn(dev, auth, key, to, size, offset); 394 | } 395 | 396 | int sed_ds_write(struct sed_device *dev, enum SED_AUTHORITY auth, const struct sed_key *key, const void *from, 397 | uint32_t size, uint32_t offset) 398 | { 399 | if (curr_if->ds_write_fn == NULL) 400 | return -EOPNOTSUPP; 401 | 402 | if (auth != SED_ANYBODY && key == NULL) { 403 | SEDCLI_DEBUG_MSG("Key can't be null\n"); 404 | return -EINVAL; 405 | } 406 | 407 | return curr_if->ds_write_fn(dev, auth, key, from, size, offset); 408 | } 409 | 410 | int sed_ds_add_anybody_get(struct sed_device *dev, const struct sed_key *key) 411 | { 412 | if (curr_if->ds_add_anybody_get_fn == NULL) 413 | return -EOPNOTSUPP; 414 | 415 | return curr_if->ds_add_anybody_get_fn(dev, key); 416 | } 417 | 418 | int sed_list_lr(struct sed_device *dev, const struct sed_key *key, struct sed_opal_locking_ranges *lrs) 419 | { 420 | if (curr_if->list_lr_fn == NULL) 421 | return -EOPNOTSUPP; 422 | 423 | return curr_if->list_lr_fn(dev, key, lrs); 424 | } 425 | 426 | int sed_issue_block_sid_cmd(struct sed_device *dev, bool hw_reset) 427 | { 428 | if (curr_if->block_sid_fn == NULL) 429 | return -EOPNOTSUPP; 430 | 431 | return curr_if->block_sid_fn(dev, hw_reset); 432 | } 433 | 434 | int sed_stack_reset(struct sed_device *dev, int32_t com_id, uint64_t extended_com_id, uint8_t *response) 435 | { 436 | if (curr_if->stack_reset_fn == NULL) 437 | return -EOPNOTSUPP; 438 | 439 | return curr_if->stack_reset_fn(dev, com_id, extended_com_id, response); 440 | } 441 | 442 | int sed_start_session(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 443 | struct sed_session *session) 444 | { 445 | if (curr_if->start_session_fn == NULL) 446 | return -EOPNOTSUPP; 447 | 448 | return curr_if->start_session_fn(dev, key, sp_uid, auth_uid, session); 449 | } 450 | 451 | int sed_end_session(struct sed_device *dev, struct sed_session *session) 452 | { 453 | if (curr_if->end_session_fn == NULL) 454 | return -EOPNOTSUPP; 455 | 456 | return curr_if->end_session_fn(dev, session); 457 | } 458 | 459 | int sed_start_end_transactions(struct sed_device *dev, bool start, uint8_t status) 460 | { 461 | if (curr_if->start_end_transactions_fn == NULL) 462 | return -EOPNOTSUPP; 463 | 464 | return curr_if->start_end_transactions_fn(dev, start, status); 465 | } 466 | 467 | int sed_set_with_buf(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 468 | uint8_t *uid, struct opal_req_item *cmd, size_t cmd_len) 469 | { 470 | if (curr_if->set_with_buf_fn == NULL) 471 | return -EOPNOTSUPP; 472 | 473 | return curr_if->set_with_buf_fn(dev, key, sp_uid, auth_uid, uid, cmd, cmd_len); 474 | } 475 | 476 | int sed_get_set_col_val(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 477 | uint8_t *uid, uint64_t col, bool get, struct sed_opal_col_info *col_info) 478 | { 479 | if (curr_if->get_set_col_val_fn == NULL) 480 | return -EOPNOTSUPP; 481 | 482 | return curr_if->get_set_col_val_fn(dev, key, sp_uid, auth_uid, uid, col, get, col_info); 483 | } 484 | 485 | int sed_get_set_byte_table(struct sed_device *dev, const struct sed_key *key, const enum SED_SP_TYPE sp, 486 | const char *user, uint8_t *uid, uint64_t start, uint64_t end, uint8_t *buffer, bool is_set) 487 | { 488 | if (curr_if->get_set_byte_table_fn == NULL) 489 | return -EOPNOTSUPP; 490 | 491 | return curr_if->get_set_byte_table_fn(dev, key, sp, user, uid, start, end, buffer, is_set); 492 | } 493 | 494 | int sed_tper_reset(struct sed_device *dev) 495 | { 496 | if (curr_if->tper_reset_fn == NULL) 497 | return -EOPNOTSUPP; 498 | 499 | return curr_if->tper_reset_fn(dev); 500 | } 501 | 502 | int sed_reactivate_sp(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 503 | uint8_t *target_sp_uid, char *lr_str, uint8_t range_start_length_policy, const struct sed_key *admin1_pwd, char *dsts_str) 504 | { 505 | if (curr_if->reactivate_sp_fn == NULL) 506 | return -EOPNOTSUPP; 507 | 508 | return curr_if->reactivate_sp_fn(dev, key, sp_uid, auth_uid, target_sp_uid, lr_str, range_start_length_policy, admin1_pwd, dsts_str); 509 | } 510 | 511 | int sed_assign(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 512 | uint32_t nsid, uint8_t range_start, uint8_t range_len, struct sed_locking_object *info) 513 | { 514 | if (curr_if->assign_fn == NULL) 515 | return -EOPNOTSUPP; 516 | 517 | return curr_if->assign_fn(dev, key, sp_uid, auth_uid, nsid, range_start, range_len, info); 518 | } 519 | 520 | int sed_deassign(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 521 | const uint8_t *uid, bool keep_ns_global_range_key) 522 | { 523 | if (curr_if->deassign_fn == NULL) 524 | return -EOPNOTSUPP; 525 | 526 | return curr_if->deassign_fn(dev, key, sp_uid, auth_uid, uid, keep_ns_global_range_key); 527 | } 528 | 529 | int sed_table_next(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 530 | uint8_t *uid, uint8_t *where, uint16_t count, struct sed_next_uids *next_uids) 531 | { 532 | if (curr_if->table_next_fn == NULL) 533 | return -EOPNOTSUPP; 534 | 535 | return curr_if->table_next_fn(dev, key, sp_uid, auth_uid, uid, where, count, next_uids); 536 | } 537 | 538 | int sed_authenticate(struct sed_device *dev, enum SED_AUTHORITY auth, const struct sed_key *key) 539 | { 540 | if (curr_if->authenticate_fn == NULL) 541 | return -EOPNOTSUPP; 542 | 543 | return curr_if->authenticate_fn(dev, auth, key); 544 | } 545 | 546 | int sed_get_acl(struct sed_device *dev, const struct sed_key *key, uint8_t *sp_uid, uint8_t *auth_uid, 547 | const uint8_t *invoking_uid, const uint8_t *method_uid, struct sed_next_uids *next_uids) 548 | { 549 | if (curr_if->get_acl_fn == NULL) 550 | return -EOPNOTSUPP; 551 | 552 | return curr_if->get_acl_fn(dev, key, sp_uid, auth_uid, invoking_uid, method_uid, next_uids); 553 | } 554 | -------------------------------------------------------------------------------- /src/lib/sed_util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2019, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | 7 | #include 8 | #include 9 | 10 | #include 11 | #include 12 | #include 13 | #include 14 | #include 15 | #include 16 | #include 17 | #include 18 | #include 19 | 20 | #include "../argp.h" 21 | 22 | #include "nvme_pt_ioctl.h" 23 | #include "sed_util.h" 24 | #include "sedcli_log.h" 25 | 26 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) 27 | 28 | extern uint8_t opal_uid[][OPAL_UID_LENGTH]; 29 | 30 | extern sedcli_printf_t sedcli_printf; 31 | 32 | int open_dev(const char *dev, bool try) 33 | { 34 | int err, fd; 35 | struct stat _stat; 36 | 37 | err = open(dev, O_RDONLY); 38 | if (err < 0) 39 | goto perror; 40 | fd = err; 41 | 42 | err = fstat(fd, &_stat); 43 | if (err < 0) { 44 | close(fd); 45 | goto perror; 46 | } 47 | 48 | if (!S_ISBLK(_stat.st_mode)) { 49 | SEDCLI_DEBUG_PARAM("%s is not a block device!\n", dev); 50 | close(fd); 51 | return -ENODEV; 52 | } 53 | 54 | return fd; 55 | 56 | perror: 57 | if (try == false) 58 | perror(dev); 59 | return err; 60 | } 61 | 62 | int sed2opal_map[] = { 63 | [SED_ANYBODY] = OPAL_ANYBODY_UID, 64 | [SED_ADMINS] = OPAL_ADMINS_UID, 65 | [SED_MAKERS] = OPAL_MAKERS_UID, 66 | [SED_MAKERSYMK] = OPAL_MAKERSYMK_UID, 67 | [SED_MAKERPUK] = OPAL_MAKERPUK_UID, 68 | [SED_SID] = OPAL_SID_UID, 69 | [SED_PSID] = OPAL_PSID_UID, 70 | [SED_TPERSIGN] = OPAL_TPERSIGN_UID, 71 | [SED_TPEREXCH] = OPAL_TPEREXCH_UID, 72 | [SED_ADMINEXCH] = OPAL_ADMINEXCH_UID, 73 | [SED_ISSUERS] = OPAL_ISSUERS_UID, 74 | [SED_EDITORS] = OPAL_EDITORS_UID, 75 | [SED_DELETERS] = OPAL_DELETERS_UID, 76 | [SED_SERVERS] = OPAL_SERVERS_UID, 77 | [SED_RESERVE0] = OPAL_RESERVE0_UID, 78 | [SED_RESERVE1] = OPAL_RESERVE1_UID, 79 | [SED_RESERVE2] = OPAL_RESERVE2_UID, 80 | [SED_RESERVE3] = OPAL_RESERVE3_UID, 81 | [SED_ADMIN] = OPAL_ADMIN_UID, 82 | [SED_ADMIN1] = OPAL_ADMIN1_UID, 83 | [SED_ADMIN2] = OPAL_ADMIN2_UID, 84 | [SED_ADMIN3] = OPAL_ADMIN3_UID, 85 | [SED_ADMIN4] = OPAL_ADMIN4_UID, 86 | [SED_USERS] = OPAL_USERS_UID, 87 | [SED_USER] = OPAL_USER_UID, 88 | [SED_USER1] = OPAL_USER1_UID, 89 | [SED_USER2] = OPAL_USER2_UID, 90 | [SED_USER3] = OPAL_USER3_UID, 91 | [SED_USER4] = OPAL_USER4_UID, 92 | [SED_USER5] = OPAL_USER5_UID, 93 | [SED_USER6] = OPAL_USER6_UID, 94 | [SED_USER7] = OPAL_USER7_UID, 95 | [SED_USER8] = OPAL_USER8_UID, 96 | [SED_USER9] = OPAL_USER9_UID, 97 | [SED_BAND_MASTER_0] = OPAL_ENTERPRISE_BANDMASTER0_UID, 98 | [SED_ERASE_MASTER] = OPAL_ENTERPRISE_ERASEMASTER_UID 99 | }; 100 | 101 | bool parse_uid(char **arg, uint8_t *uid) 102 | { 103 | // uid in hex as 8 bytes table format 00-01-02-03-04-05-06-07 104 | uint8_t id = 0; 105 | char *p = arg[0]; 106 | 107 | // parse all nums from table 108 | char *str; 109 | while (id < 8) { 110 | if (isxdigit(p[0]) == false || isxdigit(p[1]) == false) 111 | return false; 112 | 113 | // parse two-chars num as hex 114 | char byte[3]; 115 | memcpy(byte, p, sizeof(char) * 2); 116 | byte[2] = 0; 117 | uid[id++] = (int)strtoul(byte, &str, 16); 118 | if (str == byte) 119 | return false; 120 | 121 | // skip 2 bytes for already parsed num 122 | p += 2; 123 | 124 | // skip 1 byte for dash 125 | if (id < 7 && *p != '-') 126 | return false; 127 | p += 1; 128 | } 129 | 130 | return true; 131 | } 132 | 133 | int get_opal_user_auth_uid(char *user_auth, bool user_auth_is_uid, uint8_t *user_auth_uid) 134 | { 135 | if (user_auth_is_uid == false) { 136 | uint8_t user_auth_id; 137 | 138 | bool alias = false; 139 | FILE *tfp = fopen("aliases", "r"); 140 | if (tfp) { 141 | char line[256] = { 0 } ; 142 | char auth_tmp[256] = { 0 }; 143 | memcpy(auth_tmp, user_auth, strlen(user_auth)); 144 | auth_tmp[strlen(user_auth)] = 0; 145 | memcpy(auth_tmp + strlen(auth_tmp), "\n", 1); 146 | while (fgets(line, sizeof(line), tfp)) { 147 | if (strncmp(line, auth_tmp, 255) == 0) 148 | if (fgets(line, sizeof(line), tfp)) { 149 | char *p = line; 150 | if (parse_uid(&p, user_auth_uid)) { 151 | alias = true; 152 | if (sed_cli == SED_CLI_STANDARD) { 153 | sedcli_printf(LOG_INFO, "Found alias for %s: ", user_auth); 154 | for (uint8_t i = 0; i < OPAL_UID_LENGTH; i++) { 155 | sedcli_printf(LOG_INFO, "%02x", user_auth_uid[i]); 156 | if (i < OPAL_UID_LENGTH - 1) 157 | sedcli_printf(LOG_INFO, "-"); 158 | else 159 | sedcli_printf(LOG_INFO, "\n"); 160 | } 161 | } 162 | break; 163 | } 164 | } 165 | memset(line, 0, sizeof(line)); 166 | } 167 | 168 | fclose(tfp); 169 | } 170 | 171 | if (alias) 172 | return SED_SUCCESS; 173 | 174 | if (sed_get_authority_uid(user_auth, &user_auth_id) != SED_SUCCESS) 175 | return -EINVAL; 176 | 177 | memcpy(user_auth_uid, opal_uid[user_auth_id], sizeof(uint8_t) * OPAL_UID_LENGTH); 178 | } 179 | 180 | return SED_SUCCESS; 181 | } 182 | 183 | int get_opal_auth_id(enum SED_AUTHORITY auth, uint8_t *auth_id) 184 | { 185 | if (auth > ARRAY_SIZE(sed2opal_map)) { 186 | return -EINVAL; 187 | } 188 | 189 | *auth_id = sed2opal_map[auth]; 190 | 191 | return SED_SUCCESS; 192 | } 193 | 194 | int sp2uid_map[] = { 195 | [SED_ADMIN_SP] = OPAL_ADMIN_SP_UID, 196 | [SED_LOCKING_SP] = OPAL_LOCKING_SP_UID, 197 | [SED_THIS_SP] = OPAL_THIS_SP_UID, 198 | }; 199 | 200 | int get_opal_sp_uid(enum SED_SP_TYPE sp, uint8_t *sp_uid) 201 | { 202 | if (sp == SED_UID_SP) 203 | return SED_SUCCESS; 204 | 205 | if (sp > ARRAY_SIZE(sp2uid_map)) { 206 | SEDCLI_DEBUG_MSG("error: get_opal_sp_uid\n"); 207 | return -EINVAL; 208 | } 209 | 210 | memcpy(sp_uid, opal_uid[sp2uid_map[sp]], sizeof(uint8_t) * OPAL_UID_LENGTH); 211 | 212 | return SED_SUCCESS; 213 | } 214 | 215 | int sed_get_authority_uid(const char *authority, uint8_t *authority_uid) 216 | { 217 | if (!strncmp(authority, "sid", MAX_INPUT)) *authority_uid = OPAL_SID_UID; 218 | else if (!strncmp(authority, "anybody", MAX_INPUT)) *authority_uid = OPAL_ANYBODY_UID; 219 | else if (!strncmp(authority, "admin1", MAX_INPUT)) *authority_uid = OPAL_ADMIN1_UID; 220 | else if (!strncmp(authority, "user1", MAX_INPUT)) *authority_uid = OPAL_USER1_UID; 221 | else { 222 | *authority_uid = -1; 223 | return -EINVAL; 224 | } 225 | 226 | return SED_SUCCESS; 227 | } 228 | 229 | int sed_get_user_admin(const char *user, uint32_t *who, bool *admin) 230 | { 231 | unsigned int unum = 0; 232 | char *error; 233 | 234 | if (strlen(user) < 5) { 235 | SEDCLI_DEBUG_MSG("Incorrect User, please provide userN/Admin1\n"); 236 | return -EINVAL; 237 | } 238 | 239 | if (!strncasecmp(user, "admin", 5)) { 240 | SEDCLI_DEBUG_MSG("Making the user an admin\n"); 241 | unum = strtol(&user[5], &error, 10); 242 | *admin = true; 243 | } else if (!strncasecmp(user, "user", 4)) { 244 | unum = strtol(&user[4], &error, 10); 245 | *admin = false; 246 | } else { 247 | SEDCLI_DEBUG_MSG("Incorrect User provide. Provide adminN/userN\n"); 248 | return -EINVAL; 249 | } 250 | 251 | if (error == &user[4]) { 252 | SEDCLI_DEBUG_MSG("Failed to parse user # from string\n"); 253 | return -EINVAL; 254 | } 255 | 256 | *who = unum; 257 | 258 | return 0; 259 | } 260 | 261 | bool compare_uid(uint8_t *uid1, uint8_t *uid2) 262 | { 263 | if (memcmp(uid1, uid2, sizeof(uint8_t) * OPAL_UID_LENGTH) == 0) 264 | return true; 265 | 266 | return false; 267 | } 268 | 269 | bool compare_uid_range(uint8_t *uid1, uint8_t *uid2, uint8_t start, uint8_t end) 270 | { 271 | uint8_t uid_temp[OPAL_UID_LENGTH]; 272 | memcpy(uid_temp, uid1, sizeof(uint8_t) * OPAL_UID_LENGTH); 273 | for (uint8_t i = start; i < end; i++) { 274 | uid_temp[OPAL_UID_LENGTH - 1] = i; 275 | if (memcmp(uid_temp, uid2, sizeof(uint8_t) * OPAL_UID_LENGTH) == 0) 276 | return true; 277 | } 278 | 279 | return false; 280 | } 281 | -------------------------------------------------------------------------------- /src/lib/sed_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2019, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | 7 | #ifndef _SED_UTIL_H_ 8 | #define _SED_UTIL_H_ 9 | 10 | #include 11 | #include "libsed.h" 12 | 13 | struct sed_device { 14 | int fd; 15 | struct sed_opal_device_discovery discovery; 16 | void *priv; 17 | }; 18 | 19 | int open_dev(const char *dev, bool try); 20 | 21 | bool parse_uid(char **arg, uint8_t *uid); 22 | int sed_get_user_admin(const char *user, uint32_t *who, bool *admin); 23 | 24 | int sed_get_authority_uid(const char *user, uint8_t *user_uid); 25 | int get_opal_auth_id(enum SED_AUTHORITY auth, uint8_t *auth_uid); 26 | 27 | int get_opal_user_auth_uid(char *user_auth, bool user_auth_is_uid, uint8_t *user_auth_uid); 28 | int get_opal_sp_uid(enum SED_SP_TYPE sp, uint8_t *sp_uid); 29 | 30 | bool compare_uid(uint8_t *uid1, uint8_t *uid2); 31 | bool compare_uid_range(uint8_t *uid1, uint8_t *uid2, uint8_t start, uint8_t end); 32 | 33 | #endif /* _SED_UTIL_H_ */ 34 | -------------------------------------------------------------------------------- /src/lib/sedcli_log.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2018-2019, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: LGPL-2.1-or-later 5 | */ 6 | 7 | #ifndef SRC_SEDCLI_LOG_H_ 8 | #define SRC_SEDCLI_LOG_H_ 9 | 10 | #ifdef SEDCLI_DEBUG_LOGGING 11 | 12 | #define SEDCLI_DEBUG_TRACE() printf("[SEDCLI] %s:%d()\n", __FILE__, __LINE__) 13 | #define SEDCLI_DEBUG_MSG(msg) printf("[SEDCLI] %s:%d() - %s", __FILE__, __LINE__, msg) 14 | #define SEDCLI_DEBUG_PARAM(format, ...) printf("[SEDCLI] %s:%d() - "format, __FILE__, __LINE__, ##__VA_ARGS__) 15 | #define SEDCLI_DEBUG_SIMPLE(format, ...) printf(""format, ##__VA_ARGS__) 16 | 17 | #else 18 | 19 | #define SEDCLI_DEBUG_TRACE() 20 | #define SEDCLI_DEBUG_MSG(msg) 21 | #define SEDCLI_DEBUG_PARAM(format, ...) 22 | #define SEDCLI_DEBUG_SIMPLE(format, ...) 23 | 24 | #endif 25 | 26 | #endif /* SRC_SEDCLI_LOG_H_ */ 27 | -------------------------------------------------------------------------------- /src/metadata_serializer.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include 14 | 15 | #include "metadata_serializer.h" 16 | 17 | struct sedcli_metadata *sedcli_metadata_alloc_buffer() 18 | { 19 | uint8_t *buffer; 20 | 21 | buffer = malloc(SEDCLI_METADATA_SIZE); 22 | if (!buffer) 23 | return NULL; 24 | 25 | memset(buffer, 0, SEDCLI_METADATA_SIZE); 26 | 27 | return (struct sedcli_metadata *)buffer; 28 | } 29 | 30 | void sedcli_metadata_free_buffer(struct sedcli_metadata *buffer) 31 | { 32 | if (!buffer) 33 | return; 34 | 35 | memset(buffer, 0, SEDCLI_METADATA_SIZE); 36 | free(buffer); 37 | } 38 | 39 | void sedcli_metadata_init(struct sedcli_metadata *meta, uint32_t pek_id_size, 40 | uint32_t iv_size, uint32_t enc_dek_size, uint32_t tag_size) 41 | { 42 | if (!meta) 43 | return; 44 | 45 | meta->magic_num = htole64(SEDCLI_META_MAGIC); 46 | meta->version = htole32(SEDCLI_META_VERSION); 47 | 48 | meta->pek_id_size = htole32(pek_id_size); 49 | meta->iv_size = htole32(iv_size); 50 | meta->enc_dek_size = htole32(enc_dek_size); 51 | meta->tag_size = htole32(tag_size); 52 | } 53 | 54 | uint8_t *sedcli_meta_get_pek_id_addr(struct sedcli_metadata *meta) 55 | { 56 | return meta == NULL ? NULL : meta->data; 57 | } 58 | 59 | uint8_t *sedcli_meta_get_iv_addr(struct sedcli_metadata *meta) 60 | { 61 | uint32_t offset = 0; 62 | 63 | if (!meta) 64 | return NULL; 65 | 66 | offset += sedcli_meta_get_pek_id_size(meta); 67 | 68 | return &meta->data[offset]; 69 | } 70 | 71 | uint8_t *sedcli_meta_get_enc_dek_addr(struct sedcli_metadata *meta) 72 | { 73 | uint32_t offset = 0; 74 | 75 | if (!meta) 76 | return NULL; 77 | 78 | offset += sedcli_meta_get_pek_id_size(meta); 79 | offset += sedcli_meta_get_iv_size(meta); 80 | 81 | return &meta->data[offset]; 82 | } 83 | 84 | uint8_t *sedcli_meta_get_tag_addr(struct sedcli_metadata *meta) 85 | { 86 | uint32_t offset = 0; 87 | 88 | if (!meta) 89 | return NULL; 90 | 91 | offset += sedcli_meta_get_pek_id_size(meta); 92 | offset += sedcli_meta_get_iv_size(meta); 93 | offset += sedcli_meta_get_enc_dek_size(meta); 94 | 95 | return &meta->data[offset]; 96 | } 97 | 98 | uint32_t sedcli_meta_get_pek_id_size(struct sedcli_metadata *meta) 99 | { 100 | return meta != NULL ? le32toh(meta->pek_id_size) : 0; 101 | } 102 | 103 | void sedcli_meta_set_pek_id_size(struct sedcli_metadata *meta, uint32_t pek_id_size) 104 | { 105 | if (!meta) 106 | return; 107 | 108 | meta->pek_id_size = htole32(pek_id_size); 109 | } 110 | 111 | uint32_t sedcli_meta_get_iv_size(struct sedcli_metadata *meta) 112 | { 113 | return meta != NULL ? le32toh(meta->iv_size) : 0; 114 | } 115 | 116 | void sedcli_meta_set_iv_size(struct sedcli_metadata *meta, uint32_t iv_size) 117 | { 118 | if (!meta) 119 | return ; 120 | 121 | meta->iv_size = htole32(iv_size); 122 | } 123 | 124 | uint32_t sedcli_meta_get_enc_dek_size(struct sedcli_metadata *meta) 125 | { 126 | return meta != NULL ? le32toh(meta->enc_dek_size) : 0; 127 | } 128 | 129 | void sedcli_meta_set_enc_dek_size(struct sedcli_metadata *meta, uint32_t enc_dek_size) 130 | { 131 | if (!meta) 132 | return ; 133 | 134 | meta->enc_dek_size = htole32(enc_dek_size); 135 | } 136 | 137 | uint32_t sedcli_meta_get_tag_size(struct sedcli_metadata *meta) 138 | { 139 | return meta != NULL ? le32toh(meta->tag_size) : 0; 140 | } 141 | 142 | void sedcli_meta_set_tag_size(struct sedcli_metadata *meta, uint32_t tag_size) 143 | { 144 | if (!meta) 145 | return ; 146 | 147 | meta->tag_size = htole32(tag_size); 148 | } 149 | 150 | -------------------------------------------------------------------------------- /src/metadata_serializer.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #ifndef _SEDCLI_METADATA_H_ 8 | #define _SEDCLI_METADATA_H_ 9 | 10 | #include 11 | 12 | #define SEDCLI_META_MAGIC (0x41494C4344455341) /* "ASEDCLIA" */ 13 | #define SEDCLI_META_VERSION 0X01 14 | #define SEDCLI_META_HEADER_SIZE (sizeof(uint64_t) + (4 * sizeof(uint32_t))) 15 | #define SEDCLI_METADATA_SIZE (512) 16 | 17 | struct sedcli_metadata { 18 | uint64_t magic_num; /* 8B size */ 19 | uint32_t version; /* 4B size */ 20 | uint32_t pek_id_size; /* 4B size */ 21 | uint32_t iv_size; /* 4B size */ 22 | uint32_t enc_dek_size; /* 4B size */ 23 | uint32_t tag_size; /* 4B size */ 24 | uint8_t data[]; /* Data contains: pek_id, IV, enc_key, tag remaining piece 25 | is filled with all-zeroes */ 26 | }; 27 | 28 | struct sedcli_metadata *sedcli_metadata_alloc_buffer(); 29 | 30 | void sedcli_metadata_free_buffer(struct sedcli_metadata *buffer); 31 | 32 | void sedcli_metadata_init(struct sedcli_metadata *meta, uint32_t pek_id_size, 33 | uint32_t iv_size, uint32_t enc_dek_size, uint32_t tag_size); 34 | 35 | uint32_t sedcli_meta_get_pek_id_size(struct sedcli_metadata *meta); 36 | 37 | void sedcli_meta_set_pek_id_size(struct sedcli_metadata *meta, uint32_t pek_id_size); 38 | 39 | uint32_t sedcli_meta_get_iv_size(struct sedcli_metadata *meta); 40 | 41 | void sedcli_meta_set_iv_size(struct sedcli_metadata *meta, uint32_t iv_size); 42 | 43 | uint32_t sedcli_meta_get_enc_dek_size(struct sedcli_metadata *meta); 44 | 45 | void sedcli_meta_set_enc_dek_size(struct sedcli_metadata *meta, uint32_t enc_dek_size); 46 | 47 | uint32_t sedcli_meta_get_tag_size(struct sedcli_metadata *meta); 48 | 49 | void sedcli_meta_set_tag_size(struct sedcli_metadata *meta, uint32_t tag_size); 50 | 51 | uint8_t *sedcli_meta_get_pek_id_addr(struct sedcli_metadata *meta); 52 | 53 | uint8_t *sedcli_meta_get_iv_addr(struct sedcli_metadata *meta); 54 | 55 | uint8_t *sedcli_meta_get_enc_dek_addr(struct sedcli_metadata *meta); 56 | 57 | uint8_t *sedcli_meta_get_tag_addr(struct sedcli_metadata *meta); 58 | 59 | #endif /* _SEDCLI_METADATA_H_ */ 60 | -------------------------------------------------------------------------------- /src/sedcli_util.c: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #include 8 | #include 9 | #include 10 | #include 11 | 12 | #include 13 | #include 14 | 15 | #include 16 | 17 | #include "argp.h" 18 | 19 | #define ARRAY_SIZE(x) (sizeof(x) / sizeof(x[0])) 20 | 21 | static struct termios term; 22 | extern sedcli_printf_t sedcli_printf; 23 | 24 | int get_access_type(const char *access_type_str, enum SED_ACCESS_TYPE *access_type) 25 | { 26 | if (!strncmp("RO", access_type_str, MAX_INPUT)) 27 | *access_type = SED_ACCESS_RO; 28 | else if (!strncmp("WO", access_type_str, MAX_INPUT)) 29 | *access_type = SED_ACCESS_WO; 30 | else if (!strncmp("RW", access_type_str, MAX_INPUT)) 31 | *access_type = SED_ACCESS_RW; 32 | else if (!strncmp("LK", access_type_str, MAX_INPUT)) 33 | *access_type = SED_ACCESS_LK; 34 | else 35 | return -EINVAL; 36 | 37 | return SED_SUCCESS; 38 | } 39 | 40 | static void echo_disable() 41 | { 42 | tcgetattr(1, &term); 43 | term.c_cc[VMIN] = 1; 44 | term.c_lflag &= ~(ECHO | ICANON); 45 | tcsetattr(1, 0, &term); 46 | } 47 | 48 | static void echo_enable() 49 | { 50 | term.c_lflag |= ECHO | ICANON; 51 | tcsetattr(1, 0, &term); 52 | } 53 | 54 | int get_password(char *pwd, uint8_t *len, int max) 55 | { 56 | size_t dest = max + 2; 57 | char temp[dest]; // note that this is VLA 58 | int ret, temp_len; 59 | 60 | echo_disable(); 61 | 62 | memset(temp, 0, dest); 63 | 64 | if (fgets((char *) temp, dest, stdin) == NULL) { 65 | sedcli_printf(LOG_ERR, "Error getting password.\n"); 66 | ret = -EINVAL; 67 | goto err; 68 | } 69 | sedcli_printf(LOG_INFO, "\n"); 70 | 71 | /* 72 | * The temp buffer is chosen to be 2-Bytes greater than the MAX_KEY_LEN 73 | * This helps to identify if the user is trying to exceed the MAX 74 | * allowable key_len, by checking for NULL or NEW-LINE character at index 75 | * dest-2. (Last Byte is always a NULL character as per the fgets functionality) 76 | */ 77 | if (temp[dest - 2] != '\n' && temp[dest - 2] != '\0') { 78 | sedcli_printf(LOG_ERR, "Password too long..!!\n"); 79 | sedcli_printf(LOG_ERR, "Please provide password max %d characters long.\n", max); 80 | ret = -EINVAL; 81 | goto err; 82 | } 83 | 84 | temp_len = strnlen(temp, SED_MAX_KEY_LEN); 85 | if (temp[temp_len - 1] == '\n') { 86 | temp[temp_len - 1] = '\0'; 87 | --temp_len; 88 | } 89 | 90 | *len = temp_len; 91 | memcpy(pwd, temp, *len); 92 | ret = 0; 93 | 94 | err: 95 | memset(temp, 0, dest); 96 | echo_enable(); 97 | return ret; 98 | } 99 | 100 | void *alloc_locked_buffer(size_t size) 101 | { 102 | void *buf = malloc(size); 103 | if (buf == NULL) 104 | return NULL; 105 | 106 | memset(buf, 0, size); 107 | 108 | int status = mlock(buf, size); 109 | if (status) { 110 | free(buf); 111 | return NULL; 112 | } 113 | 114 | return buf; 115 | } 116 | 117 | void free_locked_buffer(void *buf, size_t buf_size) 118 | { 119 | if (!buf) 120 | return; 121 | 122 | memset(buf, 0, buf_size); 123 | munlock(buf, buf_size); 124 | free(buf); 125 | } 126 | -------------------------------------------------------------------------------- /src/sedcli_util.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (C) 2020, 2022-2023 Solidigm. All Rights Reserved. 3 | * 4 | * SPDX-License-Identifier: GPL-2.0-or-later 5 | */ 6 | 7 | #ifndef _SEDCLI_UTIL_H_ 8 | #define _SEDCLI_UTIL_H_ 9 | 10 | int get_access_type(const char *access_type_str, enum SED_ACCESS_TYPE *access_type); 11 | 12 | int get_password(char *pwd, uint8_t *len, uint8_t max); 13 | 14 | void *alloc_locked_buffer(size_t size); 15 | 16 | void free_locked_buffer(void *buf, size_t buf_size); 17 | 18 | #endif /* _SEDCLI_UTIL_H_ */ 19 | --------------------------------------------------------------------------------