├── .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 |
--------------------------------------------------------------------------------