The SPDM library has just been amended to keep a log of received signatures from a device and expose it in sysfs. Currently challenge-response authentication with a device is only performed if one of its up to 8 certificate chains is considered valid by the kernel. Valid means several things: * That the certificate chain adheres to requirements in the SPDM specification (e.g. each certificate in the chain is signed by the preceding certificate), * that the certificate chain adheres to requirements in other specifications such as PCIe r6.1 sec 6.31.3, * that the first certificate in the chain is signed by a trusted root certificate on the kernel's keyring * or that none of the certificates in the chain is on the kernel's blacklist_keyring. User space should be given the chance to make up its own mind on the validity of a certificate chain and the signature generated with it. So if none of the 8 certificate chains is considered valid by the kernel, pick one of them and perform challenge-response authentication with it for the sole purpose of exposing a signature to user space. Do not verify that signature because if the kernel considers the certificate chain invalid, the signature implicitly is as well. Arbitrarily select the certificate chain in the first provisioned slot (which is normally slot 0) for such "for user space only" authentication attempts. Signed-off-by: Lukas Wunner <lukas@xxxxxxxxx> --- I'd like to know whether people actually find this feature useful. The patch is somewhat tentative and I may drop it if there is no interest, so comments welcome! Documentation/ABI/testing/sysfs-devices-spdm | 5 +++ lib/spdm/req-authenticate.c | 38 +++++++++++++------- 2 files changed, 31 insertions(+), 12 deletions(-) diff --git a/Documentation/ABI/testing/sysfs-devices-spdm b/Documentation/ABI/testing/sysfs-devices-spdm index 8d8ee01672e1..5ce34ce10b9c 100644 --- a/Documentation/ABI/testing/sysfs-devices-spdm +++ b/Documentation/ABI/testing/sysfs-devices-spdm @@ -162,6 +162,11 @@ Description: dissector needs to be fed the concatenation of "transcript" and "signature". + Signatures are added to the log even if the kernel was unable + to verify them (e.g. due to a missing trusted root certificate + or forged signature). Thereby, remote attestation services + may make up their own mind on the signature's validity. + Because the number prefixed to the filenames is 32 bit, it wraps around to 0 after 4,294,967,295 signatures. The kernel avoids filename collisions on wraparound by purging old files, diff --git a/lib/spdm/req-authenticate.c b/lib/spdm/req-authenticate.c index 0c74dc0e5cf4..7c977f5835c1 100644 --- a/lib/spdm/req-authenticate.c +++ b/lib/spdm/req-authenticate.c @@ -615,7 +615,7 @@ static size_t spdm_challenge_rsp_sz(struct spdm_state *spdm_state, return size + spdm_state->sig_len; /* Signature */ } -static int spdm_challenge(struct spdm_state *spdm_state, u8 slot) +static int spdm_challenge(struct spdm_state *spdm_state, u8 slot, bool verify) { size_t req_sz, rsp_sz, rsp_sz_max, req_nonce_off, rsp_nonce_off; struct spdm_challenge_rsp *rsp __free(kfree); @@ -661,14 +661,19 @@ static int spdm_challenge(struct spdm_state *spdm_state, u8 slot) if (rc) return rc; - /* Verify signature at end of transcript against leaf key */ - rc = spdm_verify_signature(spdm_state, spdm_context); - if (rc) - dev_err(spdm_state->dev, - "Cannot verify challenge_auth signature: %d\n", rc); - else - dev_info(spdm_state->dev, - "Authenticated with certificate slot %u\n", slot); + rc = -EKEYREJECTED; + if (verify) { + /* Verify signature at end of transcript against leaf key */ + rc = spdm_verify_signature(spdm_state, spdm_context); + if (rc) + dev_err(spdm_state->dev, + "Cannot verify challenge_auth signature: %d\n", + rc); + else + dev_info(spdm_state->dev, + "Authenticated with certificate slot %u\n", + slot); + } spdm_create_log_entry(spdm_state, spdm_context, slot, req_nonce_off, rsp_nonce_off); @@ -692,6 +697,7 @@ static int spdm_challenge(struct spdm_state *spdm_state, u8 slot) */ int spdm_authenticate(struct spdm_state *spdm_state) { + bool verify = false; u8 slot; int rc; @@ -726,13 +732,21 @@ int spdm_authenticate(struct spdm_state *spdm_state) for_each_set_bit(slot, &spdm_state->provisioned_slots, SPDM_SLOTS) { rc = spdm_validate_cert_chain(spdm_state, slot); - if (rc == 0) + if (rc == 0) { + verify = true; break; + } } + + /* + * If no cert chain validates, perform challenge-response with + * arbitrary slot to be able to expose a signature in sysfs + * about which user space can make up its own mind. + */ if (rc) - goto unlock; + slot = __ffs(spdm_state->provisioned_slots); - rc = spdm_challenge(spdm_state, slot); + rc = spdm_challenge(spdm_state, slot, verify); unlock: if (rc) -- 2.43.0