l1k / linux

Linux kernel source tree

Geek Repo:Geek Repo

Github PK Tool:Github PK Tool

spdm: certificate validation

twilfredo opened this issue · comments

Hey,

This may not be an issue and I might just be creating the certificates incorrectly here. That said, in pci_cma_validate(), in the call to asn1_ber_decoder() I'm always seeing a failure due to tag mismatch, which errors out here:

goto tag_mismatch;

I have generated the certificates with conformance to the PCI_CMA requirements for SAN. Do you have any ideas as to what may be causing this? Have you been able to authenticate?

Note: I am adding the certificate to the _cma keyring using keyctl padd if that makes any difference.

Cheers

commented

I haven't tested that (new) code myself yet, so it's quite possible there are still bugs.

Can you send me the certificate you've created so I can analyze its contents?
Do you have docs somewhere how to test with the qemu branch so I can reproduce?

Thanks a lot!

I haven't tested that (new) code myself yet, so it's quite possible there are still bugs.

Can you send me the certificate you've created so I can analyze its contents?

With spdm-emu as the QEMU backend , these are the default certs used:
https://github.com/DMTF/libspdm/tree/3.0.0/unit_test/sample_key/

However, these certs are created with SANs that don't conform to the PCI_CMA guidelines. The certificate I used is basically the same with the SAN modified to the following:

in openssl.cnf (generic config)

...
subjectAltName = otherName:2.23.147;UTF8:Vendor=1b36:Device=0010:CC=010802:REV=02:SSVID=1af4:SSID=1100
...

so the generated cert has:

╰─λ openssl x509 -noout -ext subjectAltName -in ca.cert.der                                                                                            0 (0.121s)
X509v3 Subject Alternative Name: 
    othername: 2.23.147::Vendor=1b36:Device=0010:CC=010802:REV=02:SSVID=1af4:SSID=1100

Does that seem right to you? On the Kernel side, SAN parsing fails on the line I mentioned in the original post. I am not familiar with the decoding side of things so it's a bit hard to follow asn1_ber_decoder(). But I thought it seemed odd that it's failing on a tag mismatch (?). Note: both the cert I modified to conform to PCI CMA SAN requirements and the default certs for SPDM-EMU with arbitrary SAN, both seem to fail at the same point in the parser.

Do you have docs somewhere how to test with the qemu branch so I can reproduce?

Yep, I've made some notes: https://github.com/twilfredo/spdm-emulation-guide-b This is how I'm setting up the test environment.

Also @alistair23 should be up-streaming the QEMU patches soon

Note there are some minor changes here compared to the fork (mine) used in the guide... just to qemify things more for upstream. Feel free to use either, functionally the same.

Thanks a lot!

No worries, thanks for following up :)

commented

Wow, that documentation is awesome. Let me try to set that up on my system and reproduce the issue. Please allow a few days, sorry I'm slow. ;)

Wow, that documentation is awesome. Let me try to set that up on my system and reproduce the issue. Please allow a few days, sorry I'm slow. ;)

Sounds good! let me know if you run into any issues with the docs :)

commented

I got qemu up and running using your documentation and immediately found another bug:

I got the Truncated algorithms response message (presumably because I was using a libspdm version that lacks your conformance fix) and that message was emitted not once but twice. Turns out I was reauthenticating when pci_reset_bus_function() was called with probe=false, which is wrong.

With that fixed, I can now focus on the validation issue you reported. Please stand by... :)

I got qemu up and running using your documentation and immediately found another bug:

I got the Truncated algorithms response message (presumably because I was using a libspdm version that lacks your conformance fix) and that message was emitted not once but twice. Turns out I was reauthenticating when pci_reset_bus_function() was called with probe=false, which is wrong.

Ah I noticed this too, I thought it was by design that it attempted to re-authenticate so didn't look into it.

With that fixed, I can now focus on the validation issue you reported. Please stand by... :)

Awesome! thanks!

commented

Had to do a deep dive into ASN.1 encoding corner cases. It was an issue in drivers/pci/cma.asn1. I've documented it in a code comment there because this is less than obvious:

-- The ASN.1 module in RFC 5280 defaults to IMPLICIT encoding (due to
-- "DEFINITIONS IMPLICIT TAGS ::=") whereas the kernel's simplified
-- asn1_compiler.c defaults to EXPLICIT encoding.
--
-- Hence this ASN.1 module differs from RFC 5280 in that it specifies
-- "[0] IMPLICIT OtherName" (RFC 5280 just uses "[0] OtherName") and
-- "[0] UTF8String" (RFC 5280 needs to use "[0] EXPLICIT UTF8String").

I now get a different error message with the stock libspdm certificates: Missing X.509 OtherName with CMA OID

Which is correct. Will update the certificates with a CMA OtherName and retry.

commented

It seems to authenticate just fine.

This is what I changed in openssl.cnf:

--- ../../../libspdm/unit_test/sample_key/openssl.cnf	2023-09-23 13:47:18.234787000 +0200
+++ ../openssl.cnf	2023-09-23 13:49:02.251162000 +0200
@@ -10,13 +10,11 @@
 basicConstraints = critical,CA:false
 keyUsage = nonRepudiation, digitalSignature, keyEncipherment
 subjectKeyIdentifier = hash
-subjectAltName = otherName:1.3.6.1.4.1.412.274.1;UTF8:ACME:WIDGET:1234567890
+#subjectAltName = otherName:1.3.6.1.4.1.412.274.1;UTF8:ACME:WIDGET:1234567890
+subjectAltName = otherName:2.23.147;UTF8:Vendor=1b36:Device=0010:CC=010802:REV=02:SSVID=1af4:SSID=1100
 extendedKeyUsage = critical, serverAuth, clientAuth, OCSPSigning
-1.3.6.1.4.1.412.274.6 = ASN1:SEQUENCE:id_spdm_cert_oids
-[id_spdm_cert_oids]
-field1 = SEQUENCE:id_spdm_cert_oid
-[id_spdm_cert_oid]
-field1 = OID:1.3.6.1.4.1.412.274.2
+1.3.6.1.4.1.412.274.6 = ASN1:OID:1.3.6.1.4.1.412.274.2
+2.23.147 = ASN1:OID:2.23.147
 
 [v3_end_with_spdm_req_rsp_eku]
 basicConstraints = critical,CA:false

Then I regenerated the cert chain like this:

cd ecp384
openssl req -nodes -newkey ec:param.pem -keyout end_responder.key -out end_responder.req -sha384 -batch -subj "/CN=DMTF libspdm ECP384 responder cert"
openssl x509 -req -in end_responder.req -out end_responder.cert -CA inter.cert -CAkey inter.key -sha384 -days 3650 -set_serial 3 -extensions v3_end -extfile ../openssl.cnf
openssl asn1parse -in end_responder.cert -out end_responder.cert.der
cat ca.cert.der inter.cert.der end_responder.cert.der > bundle_responder.certchain.der

You may want to add something like this to your docs. :)

Pity that libspdm doesn't provide Makefile rules to regenerate the cert chain more comfortably. :(

commented

I've tested whether parsing works correctly if the Subject Alternative Name contains multiple OtherName entries and unrelated DNSName entries. Turns out I had to add even more IMPLICIT annotations to the ASN.1 grammar. But this is now also working fine, although the likelihood of such certificates actually being used is probably small:

--- ../../../libspdm/unit_test/sample_key/openssl.cnf	2023-09-23 13:47:18.234787000 +0200
+++ ../openssl.cnf	2023-09-24 10:21:17.011349867 +0200
@@ -10,13 +10,16 @@
 basicConstraints = critical,CA:false
 keyUsage = nonRepudiation, digitalSignature, keyEncipherment
 subjectKeyIdentifier = hash
-subjectAltName = otherName:1.3.6.1.4.1.412.274.1;UTF8:ACME:WIDGET:1234567890
+subjectAltName = @alt_names
 extendedKeyUsage = critical, serverAuth, clientAuth, OCSPSigning
-1.3.6.1.4.1.412.274.6 = ASN1:SEQUENCE:id_spdm_cert_oids
-[id_spdm_cert_oids]
-field1 = SEQUENCE:id_spdm_cert_oid
-[id_spdm_cert_oid]
-field1 = OID:1.3.6.1.4.1.412.274.2
+1.3.6.1.4.1.412.274.6 = ASN1:OID:1.3.6.1.4.1.412.274.2
+2.23.147 = ASN1:OID:2.23.147
+
+[ alt_names ]
+otherName.1 = 1.3.6.1.4.1.412.274.1;UTF8:ACME:WIDGET:1234567890
+otherName.2 = 2.23.147;UTF8:Vendor=1b36:Device=0010:CC=010802:REV=02:SSVID=1af4:SSID=1100
+DNS.1 = www.example.com
+DNS.2 = hello.example.com
 
 [v3_end_with_spdm_req_rsp_eku]
 basicConstraints = critical,CA:false
commented

I've tested RSA3072 instead of ECDSA by specifying --asym RSASSA_3072 on the spdm_responder_emu command line. Works just fine. Had to regenerate the cert with a correct Subject Alternative Name of course.

commented

Tested SPDM 1.1 by specifying --ver 1.1 and this seems to be working fine as well. With SPDM versions < 1.2, the signature generation and validation is different than with >= 1.2.

Unfortunately we can't test version 1.3. The kernel supports it but libspdm does not.

commented

I've realized that the builtin key rings all begin with . instead of _, so I've renamed _cma to .cma.

You've got a few occurrences of _cma in your documentation. Sorry for the churn!

Awesome! thanks for fixing this. It is now authenticating for me . The issue I was running into seems to be fixed with the changes you described in #4 (comment) , as before, I didn't even get to Missing X.509 OtherName with CMA OID.

I will update the docs to fixup the .cma rename and add a part about certificate generation and SAN conformance to PCIe specification.

Closing this, as the issue discussed has been resolved 🎉🎉