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:
Line 255 in 4bbbe36
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
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 :)
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 :)
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 whenpci_reset_bus_function()
was called withprobe=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!
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.
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. :(
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
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.
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.
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 🎉🎉