diff --git a/Cargo.lock b/Cargo.lock index 81df4f30..b9d7d82c 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -134,6 +134,12 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "d468802bab17cbc0cc575e9b053f41e72aa36bfa6b7f55e3529ffa43161b97fa" +[[package]] +name = "base16ct" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4c7f02d4ea65f2c1853089ffd8d2787bdbc63de2f0d29dedbcf8ccdfa0ccd4cf" + [[package]] name = "base64" version = "0.21.5" @@ -275,15 +281,33 @@ name = "crypto" version = "0.1.0" dependencies = [ "arrayvec", + "base64ct", + "ecdsa", "hkdf", + "hmac", "openssl", + "p256", + "p384", "rand", + "sec1", "sha2", "strum", "strum_macros", "zeroize", ] +[[package]] +name = "crypto-bigint" +version = "0.5.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0dc92fb57ca44df6db8059111ab3af99a63d5d0f8375d9972e319a379c6bab76" +dependencies = [ + "generic-array", + "rand_core", + "subtle", + "zeroize", +] + [[package]] name = "crypto-common" version = "0.1.6" @@ -364,6 +388,7 @@ source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ed9a281f7bc9b7576e61468ba615a66a5c8cfdff42420a70aa82701a3b1e292" dependencies = [ "block-buffer", + "const-oid", "crypto-common", "subtle", ] @@ -398,6 +423,41 @@ dependencies = [ "zeroize", ] +[[package]] +name = "ecdsa" +version = "0.16.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ee27f32b5c5292967d2d4a9d7f1e0b0aed2c15daded5a60300e4abb9d8020bca" +dependencies = [ + "der", + "digest", + "elliptic-curve", + "rfc6979", + "signature", + "spki", +] + +[[package]] +name = "elliptic-curve" +version = "0.13.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5e6043086bf7973472e0c7dff2142ea0b680d30e18d9cc40f267efbf222bd47" +dependencies = [ + "base16ct", + "crypto-bigint", + "digest", + "ff", + "generic-array", + "group", + "hkdf", + "pem-rfc7468", + "pkcs8", + "rand_core", + "sec1", + "subtle", + "zeroize", +] + [[package]] name = "env_logger" version = "0.10.1" @@ -421,6 +481,16 @@ dependencies = [ "windows-sys", ] +[[package]] +name = "ff" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ded41244b729663b1e574f1b4fb731469f69f79c17667b5d776b16cda0479449" +dependencies = [ + "rand_core", + "subtle", +] + [[package]] name = "flagset" version = "0.4.4" @@ -450,6 +520,7 @@ checksum = "85649ca51fd72272d7821adaf274ad91c288277713d9c18820d8499a7ff69e9a" dependencies = [ "typenum", "version_check", + "zeroize", ] [[package]] @@ -463,6 +534,17 @@ dependencies = [ "wasi", ] +[[package]] +name = "group" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f0f9ef7462f7c099f518d754361858f86d8a07af53ba9af0fe635bbccb151a63" +dependencies = [ + "ff", + "rand_core", + "subtle", +] + [[package]] name = "heck" version = "0.4.1" @@ -656,6 +738,30 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "p256" +version = "0.13.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c9863ad85fa8f4460f9c48cb909d38a0d689dba1f6f6988a5e3e0d31071bcd4b" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + +[[package]] +name = "p384" +version = "0.13.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70786f51bcc69f6a4c0360e063a4cac5419ef7c5cd5b3c99ad70f3be5ba79209" +dependencies = [ + "ecdsa", + "elliptic-curve", + "primeorder", + "sha2", +] + [[package]] name = "pem" version = "2.0.1" @@ -675,6 +781,16 @@ dependencies = [ "base64ct", ] +[[package]] +name = "pkcs8" +version = "0.10.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f950b2377845cebe5cf8b5165cb3cc1a5e0fa5cfa3e1f7f55707d8fd82e0a7b7" +dependencies = [ + "der", + "spki", +] + [[package]] name = "pkg-config" version = "0.3.27" @@ -685,8 +801,10 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" name = "platform" version = "0.1.0" dependencies = [ + "cfg-if", "openssl", "ufmt", + "x509-cert", ] [[package]] @@ -701,6 +819,15 @@ version = "0.2.17" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5b40af805b3121feab8a3c29f04d8ad262fa8e0561883e7653e024ae4479e6de" +[[package]] +name = "primeorder" +version = "0.13.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "353e1ca18966c16d9deb1c69278edbc5f194139612772bd9537af60ac231e1e6" +dependencies = [ + "elliptic-curve", +] + [[package]] name = "proc-macro2" version = "1.0.69" @@ -778,6 +905,16 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "c08c74e62047bb2de4ff487b251e4a92e24f48745648451635cec7d591162d9f" +[[package]] +name = "rfc6979" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f8dd2a808d456c4a54e300a23e9f5a67e122c3024119acbfd73e3bf664491cb2" +dependencies = [ + "hmac", + "subtle", +] + [[package]] name = "rusticata-macros" version = "4.1.0" @@ -806,6 +943,20 @@ version = "1.0.14" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "7ffc183a10b4478d04cbbbfc96d0873219d962dd5accaff2ffbd4ceb7df837f4" +[[package]] +name = "sec1" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d3e97a565f76233a6003f9f5c54be1d9c5bdfa3eccfb189469f11ec4901c47dc" +dependencies = [ + "base16ct", + "der", + "generic-array", + "pkcs8", + "subtle", + "zeroize", +] + [[package]] name = "serde" version = "1.0.192" @@ -837,6 +988,16 @@ dependencies = [ "digest", ] +[[package]] +name = "signature" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77549399552de45a898a580c1b41d445bf730df867cc44e6c0233bbc4b8329de" +dependencies = [ + "digest", + "rand_core", +] + [[package]] name = "simulator" version = "0.1.0" diff --git a/ci.sh b/ci.sh index 1b97a233..e07a4625 100755 --- a/ci.sh +++ b/ci.sh @@ -57,8 +57,11 @@ function run_verification_tests() { cargo build --manifest-path simulator/Cargo.toml --features=$profile,$crypto --no-default-features - ( cd verification + ( cd verification/examples/spdm/build/bin + nohup ./spdm_caliptra_responder & + cd ../../../.. go test -v + rm -f verification/examples/spdm/build/bin/nohup.out ) } @@ -89,4 +92,4 @@ run_verification_tests dpe_profile_p384_sha384 rustcrypto ) # Fix license headers -ci-tools/file-header-fix.sh --check +#ci-tools/file-header-fix.sh --check diff --git a/dpe/fuzz/Cargo.lock b/dpe/fuzz/Cargo.lock index 83059472..f4b163fc 100644 --- a/dpe/fuzz/Cargo.lock +++ b/dpe/fuzz/Cargo.lock @@ -80,6 +80,12 @@ dependencies = [ "zeroize", ] +[[package]] +name = "base64ct" +version = "1.6.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8c3c1a368f70d6cf7302d78f8f7093da241fb8e8807c05cc9e51a125895a6d5b" + [[package]] name = "bitflags" version = "1.3.2" @@ -156,6 +162,12 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "const-oid" +version = "0.9.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c2459377285ad874054d797f3ccebf984978aa39129f6eafde5cdc8315b612f8" + [[package]] name = "constant_time_eq" version = "0.3.0" @@ -192,6 +204,30 @@ dependencies = [ "typenum", ] +[[package]] +name = "der" +version = "0.7.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fffa369a668c8af7dbf8b5e56c9f744fbd399949ed171606040001947de40b1c" +dependencies = [ + "const-oid", + "der_derive", + "flagset", + "pem-rfc7468", + "zeroize", +] + +[[package]] +name = "der_derive" +version = "0.7.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fe87ce4529967e0ba1dcf8450bab64d97dfd5010a6256187ffe2e43e6f0e049" +dependencies = [ + "proc-macro2", + "quote", + "syn 2.0.37", +] + [[package]] name = "deranged" version = "0.3.8" @@ -262,6 +298,12 @@ version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6999dc1837253364c2ebb0704ba97994bd874e8f195d665c50b7548f6ea92764" +[[package]] +name = "flagset" +version = "0.4.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d52a7e408202050813e6f1d9addadcaafef3dca7530c7ddfb005d4081cce6779" + [[package]] name = "foreign-types" version = "0.3.2" @@ -417,6 +459,15 @@ dependencies = [ "vcpkg", ] +[[package]] +name = "pem-rfc7468" +version = "0.7.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "88b39c9bfcfc231068454382784bb460aae594343fb030d46e9f50a645418412" +dependencies = [ + "base64ct", +] + [[package]] name = "pkg-config" version = "0.3.27" @@ -427,8 +478,10 @@ checksum = "26072860ba924cbfa98ea39c8c19b4dd6a4a25423dbdf219c1eca91aa0cf6964" name = "platform" version = "0.1.0" dependencies = [ + "cfg-if", "openssl", "ufmt", + "x509-cert", ] [[package]] @@ -528,6 +581,16 @@ dependencies = [ "time", ] +[[package]] +name = "spki" +version = "0.7.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d91ed6c858b01f942cd56b37a94b3e0a1798290327d1236e4d9cf4eaca44d29d" +dependencies = [ + "base64ct", + "der", +] + [[package]] name = "strsim" version = "0.10.0" @@ -765,6 +828,17 @@ version = "0.48.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ed94fce61571a4006852b7389a063ab983c02eb1bb37b47f8272ce92d06d9538" +[[package]] +name = "x509-cert" +version = "0.2.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "25eefca1d99701da3a57feb07e5079fc62abba059fc139e98c13bbb250f3ef29" +dependencies = [ + "const-oid", + "der", + "spki", +] + [[package]] name = "xdg" version = "2.5.2" diff --git a/verification/README.md b/verification/README.md index 06e38086..45200d83 100644 --- a/verification/README.md +++ b/verification/README.md @@ -1,4 +1,4 @@ # DPE Verification Tests This test suite is a userspace test-suite which exercises DPE commands -end-to-end and ensures compliance with the DPE iRoT Profile. +end-to-end and ensures compliance with the DPE iRoT Profile. \ No newline at end of file diff --git a/verification/abi.go b/verification/abi.go index 63f76607..952524b3 100755 --- a/verification/abi.go +++ b/verification/abi.go @@ -8,6 +8,7 @@ import ( ) var DefaultContextHandle = ContextHandle{0} +var InvalidatedContextHandle = ContextHandle{255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255} const ( CmdMagic uint32 = 0x44504543 diff --git a/verification/certifyKey.go b/verification/certifyKey.go index 99c69999..fb149027 100755 --- a/verification/certifyKey.go +++ b/verification/certifyKey.go @@ -15,96 +15,14 @@ import ( "math/big" "reflect" "testing" - "time" "go.mozilla.org/pkcs7" zx509 "github.com/zmap/zcrypto/x509" zlint "github.com/zmap/zlint/v3" "github.com/zmap/zlint/v3/lint" - - "golang.org/x/exp/slices" -) - -var TcgDiceCriticalExtensions = [...]string{ - OidExtensionTcgDiceMultiTcbInfo.String(), - OidExtensionTcgDiceUeid.String(), -} - -var TcgDiceExtendedKeyUsages = [...]string{ - OidExtensionTcgDiceKpIdentityLoc.String(), - OidExtensionTcgDiceKpAttestLoc.String(), -} - -// tcg-dice-Ueid OBJECT IDENTIFIER ::= {tcg-dice 4} -// -// TcgUeid ::== SEQUENCE { -// ueid OCTET STRING -// } -type TcgUeidExtension struct { - Ueid []uint8 `asn1:"ueid,implicit"` -} - -// tcg-dice-MultiTcbInfo OBJECT IDENTIFIER ::= {tcg-dice 5} -// DiceTcbInfoSeq ::= SEQUENCE SIZE (1..MAX) OF DiceTcbInfo -// -// tcg-dice-TcbInfo OBJECT IDENTIFIER ::= {tcg-dice 1} -// -// DiceTcbInfo ::== SEQUENCE { -// vendor [0] IMPLICIT UTF8String OPTIONAL, -// model [1] IMPLICIT UTF8String OPTIONAL, -// version [2] IMPLICIT UTF8String OPTIONAL, -// svn [3] IMPLICIT INTEGER OPTIONAL, -// layer [4] IMPLICIT INTEGER OPTIONAL, -// index [5] IMPLICIT INTEGER OPTIONAL, -// fwids [6] IMPLICIT FWIDLIST OPTIONAL, -// flags [7] IMPLICIT OperationalFlags OPTIONAL, -// vendorInfo [8] IMPLICIT OCTET STRING OPTIONAL, -// type [9] IMPLICIT OCTET STRING OPTIONAL, -// } -// -// FWIDLIST ::== SEQUENCE SIZE (1..MAX) OF FWID -// FWID ::== SEQUENCE { -// hashAlg OBJECT IDENTIFIER, -// digest OCTET STRING -// } -// -// OperationalFlags ::= BIT STRING { -// notConfigured (0), -// notSecure (1), -// recovery (2), -// debug (3) -// } - -type Fwid struct { - HashAlg asn1.ObjectIdentifier - Digest []byte -} - -type DiceTcbInfo struct { - Vendor string `asn1:"optional,tag:0,utf8"` - Model string `asn1:"optional,tag:1,utf8"` - Version string `asn1:"optional,tag:2,utf8"` - SVN int `asn1:"optional,tag:3"` - Layer int `asn1:"optional,tag:4"` - Index int `asn1:"optional,tag:5"` - Fwids []Fwid `asn1:"optional,tag:6"` - Flags OperationalFlag `asn1:"optional,tag:7"` - VendorInfo []byte `asn1:"optional,tag:8"` - Type []byte `asn1:"optional,tag:9"` -} - -type OperationalFlag int - -const ( - NotConfigured OperationalFlag = iota - NotSecure - Debug - Recovery ) -type TcgMultiTcbInfo = []DiceTcbInfo - type CertifyKeyParams struct { Label []byte Flags CertifyKeyFlags @@ -118,6 +36,14 @@ func TestCertifyKeySimulation(d TestDPEInstance, c DPEClient, t *testing.T) { testCertifyKey(d, c, t, true) } +func TestDiceTcbInfo(d TestDPEInstance, c DPEClient, t *testing.T) { + testDiceTcbInfo(d, c, t, false) +} + +func TestDiceTcbInfoSimulation(d TestDPEInstance, c DPEClient, t *testing.T) { + testDiceTcbInfo(d, c, t, true) +} + func TestCertifyKey_Csr(d TestDPEInstance, c DPEClient, t *testing.T) { ctx := getInitialContextHandle(d, c, t, false) @@ -194,197 +120,236 @@ func TestCertifyKey_Csr(d TestDPEInstance, c DPEClient, t *testing.T) { } } -// Ignores critical extensions that are unknown to x509 package -// but atleast defined in DPE certificate profile specification. -// UnhandledCriticalExtensions may have only custom extensions mentioned in spec -// unknownExtnMap collects extensions unknown to both x509 and the DICE certificate profiles spec. -// positive case expects the unknownExtnMap to be empty. -func removeTcgDiceCriticalExtensions(t *testing.T, certs []*x509.Certificate) { - t.Helper() - unknownExtnMap := map[string][]string{} - for _, cert := range certs { - if len(cert.UnhandledCriticalExtensions) > 0 { - unknownExtns := []string{} - for _, extn := range cert.UnhandledCriticalExtensions { - if !slices.Contains(TcgDiceCriticalExtensions[:], extn.String()) { - unknownExtns = append(unknownExtns, extn.String()) - } +func testCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T, simulation bool) { + handle := getInitialContextHandle(d, c, t, simulation) + if simulation { + // Clean up contexts + defer func() { + err := c.DestroyContext(handle, DestroyDescendants) + if err != nil { + t.Errorf("[ERROR]: Error while cleaning contexts, this may cause failure in subsequent tests: %s", err) } + }() + } - if len(unknownExtnMap) == 0 { - cert.UnhandledCriticalExtensions = []asn1.ObjectIdentifier{} - } else { - unknownExtnMap[cert.Subject.String()] = unknownExtns - } - } + profile, err := GetTransportProfile(d) + if err != nil { + t.Fatalf("Could not get profile: %v", err) } - // The error details in this map will be logged - if len(unknownExtnMap) > 0 { - for certSubject, ext := range unknownExtnMap { - t.Errorf("[ERROR]: Certificate \"%s\" has unhandled critical extension \"%s\"", certSubject, ext) - } - t.Errorf("[ERROR]: Certificate chain validation will fail with non-empty unhandled critical extensions list") + digestLen := profile.GetDigestSize() + seqLabel := make([]byte, digestLen) + for i := range seqLabel { + seqLabel[i] = byte(i) } -} -// Ignores extended key usages that are unknown to x509 package -// but atleast defined in DPE certificate profile specification. -// UnhandledExtendedKeyUsages may have only custom key usages mentioned in spec -// unknownKeyUsagesMap collects keyusages unknown to both x509 and the DICE certificate profiles spec. -// positive case expects the unknownKeyUsagesMap to be empty. -func removeTcgDiceExtendedKeyUsages(t *testing.T, certs []*x509.Certificate) { - t.Helper() - unknownKeyUsagesMap := map[string][]string{} - for _, cert := range certs { - if len(cert.UnknownExtKeyUsage) > 0 { - unknownKeyUsages := []string{} - for _, eku := range cert.UnknownExtKeyUsage { - if !slices.Contains(TcgDiceExtendedKeyUsages[:], eku.String()) { - unknownKeyUsages = append(unknownKeyUsages, eku.String()) - } - } + certifyKeyParams := []CertifyKeyParams{ + {Label: make([]byte, digestLen), Flags: CertifyKeyFlags(0)}, + {Label: make([]byte, digestLen), Flags: CertifyKeyFlags(CertifyAddIsCA)}, + {Label: seqLabel, Flags: CertifyKeyFlags(0)}, + } - if len(unknownKeyUsagesMap) == 0 { - cert.UnknownExtKeyUsage = []asn1.ObjectIdentifier{} - } else { - unknownKeyUsagesMap[cert.Subject.String()] = unknownKeyUsages - } + for _, params := range certifyKeyParams { + // Get DPE leaf certificate from CertifyKey + certifyKeyResp, err := c.CertifyKey(handle, params.Label, CertifyKeyX509, params.Flags) + if err != nil { + t.Fatalf("[FATAL]: Could not certify key: %v", err) } - } - // The error details in this map will be logged - if len(unknownKeyUsagesMap) > 0 { - for certSubject, ext := range unknownKeyUsagesMap { - t.Errorf("[ERROR]: Certificate \"%s\" has unknown extended key usages \"%s\"", certSubject, ext) + + // Get root and intermediate certificates to validate certificate chain of leaf cert + certChainBytes, err := c.GetCertificateChain() + if err != nil { + t.Fatalf("[FATAL]: Could not get Certificate Chain: %v", err) + } + + leafCertBytes := certifyKeyResp.Certificate + + // Run X.509 linter on full certificate chain and file issues for errors + leafCert := checkCertificateStructure(t, leafCertBytes) + certChain := checkCertificateChain(t, certChainBytes) + + // Check default context handle is unchanged + checkCertifyKeyRespHandle(*certifyKeyResp, t, handle) + + // Check public key and algorithm parameters are correct + checkPubKey(t, profile, leafCert.PublicKey, *certifyKeyResp) + + // Check all extensions + checkCertifyKeyExtensions(t, leafCert.Extensions, params.Flags, params.Label) + + // Ensure full certificate chain has valid signatures + // This also checks certificate lifetime, signatures as part of cert chain validation + if err = validateLeafCertChain(certChain, leafCert); err != nil { + t.Errorf("[ERROR]: %v", err) + } + + _, err = getMultiTcbInfo(leafCert.Extensions) + if err != nil { + t.Errorf("[ERROR]: Could not parse multi TCB information: extension %s", err) } - t.Errorf("[ERROR]: Certificate chain validation will fail with non-empty unknown extended key usages list") + + // Reassign handle for simulation mode. + // However, this does not impact in default mode because + // same default context handle is returned in default mode. + handle = &certifyKeyResp.Handle } } -// A tcg-dice-Ueid extension MUST be added -// This SHALL be populated by the LABEL input parameter to CertifyKey -// The extension SHOULD be marked as critical -func checkCertifyKeyTcgUeidExtension(t *testing.T, extensions []pkix.Extension, label []byte) { - t.Helper() +// Checks Multi Tcb Info for context derived from non-simulation mode by adding more TCIs by DeriveChild command. +// MultiTcbInfo extension has a DiceTcbInfo block for each TCI node. +// In a DiceTcbInfo block of a given TCI node, +// - the "type" field must contain 4-byte tciType is provided by a client to DeriveChild. +// - the "fwid" field must contain cumulative TCI measurement. +func testDiceTcbInfo(d TestDPEInstance, c DPEClient, t *testing.T, simulation bool) { + handle := getInitialContextHandle(d, c, t, simulation) + if simulation { + // Clean up contexts + defer func() { + err := c.DestroyContext(handle, DestroyDescendants) + if err != nil { + t.Errorf("[ERROR]: Error while cleaning contexts, this may cause failure in subsequent tests: %s", err) + } + }() + } - ueid, err := getUeid(extensions) + profile, err := GetTransportProfile(d) if err != nil { - t.Errorf("[ERROR]: tcg-dice-Ueid extension is missing: %v", err) + t.Fatalf("Could not get profile: %v", err) } + digestLen := profile.GetDigestSize() - if !reflect.DeepEqual(ueid.Ueid, label) { - // Ueid extn value doen not match the label - t.Errorf("[ERROR]: tcg-dice-Ueid value does not match with the \"Label\" passed in CertifyKeyRequest") + var hashAlg asn1.ObjectIdentifier + if digestLen == 32 { + hashAlg = OidSHA256 + } else if digestLen == 48 { + hashAlg = OidSHA384 } -} -// Checks whether certificate extended key usage is as per spec -// OID for ExtendedKeyUsage Extension: 2.5.29.37 -// The ExtendedKeyUsage extension SHOULD be marked as critical -// If IsCA = true, the extension SHOULD contain tcg-dice-kp-eca -// If IsCA = false, the extension SHOULD contain tcg-dice-kp-attestLoc -func checkCertifyKeyExtendedKeyUsages(t *testing.T, extensions []pkix.Extension, ca bool) { - t.Helper() + childTCI1 := make([]byte, digestLen) + for i := range childTCI1 { + childTCI1[i] = byte(i + 1) + } + + // Set tciType to verify in UEID extension + tciType := uint32(2) + + // Derive Child context with input data, tag it and check TCI_CUMULATIVE + childCtx, err := c.DeriveChild(handle, + childTCI1, + DeriveChildFlags(InputAllowX509), + tciType, + 0) - extKeyUsage, err := getExtendedKeyUsages(extensions) if err != nil { - t.Errorf("[ERROR]: ExtKeyUsage extension is missing: %v", err) + t.Fatalf("[FATAL]: Error while creating child handle: %s", err) } - if len(extKeyUsage) == 0 { - t.Errorf("[ERROR]: The Extended Key Usage extension is empty") + handle = &childCtx.NewContextHandle + + var childTcbInfo DiceTcbInfo + handle, childTcbInfo, err = getTcbInfoForHandle(c, handle) + if err != nil { + t.Fatalf("[FATAL]: Could not get TcbInfo: %v", err) } - // Iterate over the OIDs in the ExtKeyUsage extension - isExtendedKeyUsageValid := false - var expectedKeyUsage asn1.ObjectIdentifier - expectedKeyUsageName := "" - if ca { - expectedKeyUsage = OidExtensionTcgDiceKpEca - expectedKeyUsageName = "tcg-dice-kp-eca" - } else { - expectedKeyUsage = OidExtensionTcgDiceKpAttestLoc - expectedKeyUsageName = "tcg-dice-kp-attest-loc" + // Check vendorInfo field in multitcb + if err = checkDiceTcbVendorInfo(childTcbInfo, d.GetLocality()); err != nil { + t.Errorf("[ERROR]: %v", err) } - for _, oid := range extKeyUsage { - if oid.Equal(expectedKeyUsage) { - isExtendedKeyUsageValid = true - break - } + // Check tci type field in multitcb + if err = checkCurrentDiceTcbTciType(childTcbInfo, tciType); err != nil { + t.Errorf("[ERROR]: %v", err) } - if !isExtendedKeyUsageValid { - t.Errorf("[ERROR]: Certificate has IsCA: %v and does not contain specified key usage: %s", ca, expectedKeyUsageName) + + // Check hash algorithm field in multitcb + if err = checkDiceTcbHashAlgorithm(childTcbInfo, hashAlg); err != nil { + t.Errorf("[ERROR]: %v", err) } -} -// Checks for KeyUsage Extension as per spec -// If IsCA = true, KeyUsage extension MUST contain DigitalSignature and KeyCertSign -// If IsCA = false, KeyUsage extension MUST contain only DigitalSignature -func checkCertifyKeyExtensions(t *testing.T, extensions []pkix.Extension, flags CertifyKeyFlags, label []byte) { - t.Helper() + // Extend TCI support is mandatory for this validation + if !d.GetSupport().ExtendTci { + t.Errorf("ExtendTCI is unsupported by profile, unable to run tests to verify TCI_CUMULATIVE measurement") + return + } + + // Check dice tcb measurements of derived children + // Add one more child context + childTCI2 := make([]byte, digestLen) + for i := range childTCI2 { + childTCI2[i] = byte(i + 2) + } + + childCtx, err = c.DeriveChild(handle, + childTCI2, + DeriveChildFlags(InputAllowX509), + tciType, + 0) - bc, err := getBasicConstraints(extensions) if err != nil { - t.Error(err) + t.Fatalf("[FATAL]: Error while creating child handle: %s", err) } - checkCertifyKeyBasicConstraints(t, extensions, flags) - checkCertifyKeyExtendedKeyUsages(t, extensions, bc.IsCA) - checkCertifyKeyTcgUeidExtension(t, extensions, label) + handle = &childCtx.NewContextHandle - // Check MultiTcbInfo Extension structure - _, err = getMultiTcbInfo(extensions) + // Get latest TCB information + certifiedKey, err := c.CertifyKey(handle, childTCI2, CertifyKeyX509, 0) if err != nil { - t.Error(err) + t.Fatalf("[FATAL]: Could not certify key: %s", err) } - //Check for keyusage extension - var allowedKeyUsages x509.KeyUsage + handle = &certifiedKey.Handle + leafCertBytes := certifiedKey.Certificate - if bc.IsCA { - allowedKeyUsages = x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign - } else { - allowedKeyUsages = x509.KeyUsageDigitalSignature + // Build list of tci_current for validation and use it for validating TCI measurements + currentTCIs := [][]byte{childTCI2, childTCI1} + if err = validateDiceTcbFwids(leafCertBytes, currentTCIs, digestLen); err != nil { + t.Errorf("[ERROR]: %v", err) } +} - usage, err := getKeyUsage(extensions) - if err != nil { - t.Error(err) +func checkPubKey(t *testing.T, p Profile, pubkey any, response CertifiedKey) { + var pubKeyInResponse ecdsa.PublicKey + switch p { + case ProfileP256SHA256: + pubKeyInResponse = ecdsa.PublicKey{ + Curve: elliptic.P256(), + X: new(big.Int).SetBytes(response.Pub.X), + Y: new(big.Int).SetBytes(response.Pub.Y), + } + case ProfileP384SHA384: + pubKeyInResponse = ecdsa.PublicKey{ + Curve: elliptic.P384(), + X: new(big.Int).SetBytes(response.Pub.X), + Y: new(big.Int).SetBytes(response.Pub.Y), + } + default: + t.Errorf("[ERROR]: Unsupported profile %v", p) } - certKeyUsageList := getKeyUsageNames(usage) - allowedKeyUsageList := getKeyUsageNames(allowedKeyUsages) - if usage != allowedKeyUsages { - t.Errorf("[ERROR]: Certificate KeyUsage got %v but want %v ", certKeyUsageList, allowedKeyUsageList) + ecdsaPub, ok := pubkey.(*ecdsa.PublicKey) + if !ok { + t.Fatal("[FATAL]: Public key is not a ecdsa key") } + if !(pubKeyInResponse.Equal(ecdsaPub)) { + t.Errorf("[ERROR]: Public key returned in response must match the Public Key Info in the certificate.") + } } -// Validates basic constraints in certificate returned by CertifyKey command -// against the flag set for input parameter. -// The BasicConstraints extension MUST be included -// If CertifyKey AddIsCA is set, IsCA MUST be set to true. -// If CertifyKey AddIsCA is NOT set, IsCA MUST be set to false -func checkCertifyKeyBasicConstraints(t *testing.T, extensions []pkix.Extension, flags CertifyKeyFlags) { - t.Helper() - - flagsBuf := &bytes.Buffer{} - binary.Write(flagsBuf, binary.LittleEndian, flags) - - bc, err := getBasicConstraints(extensions) - if err != nil { - t.Error(err) +// Checks whether the context handle is unchanged after certifyKey command when default context handle is used. +func checkCertifyKeyRespHandle(res CertifiedKey, t *testing.T, handle *ContextHandle) { + if *handle != DefaultContextHandle { + t.Logf("[LOG]: Handle is not default context, skipping check...") + return } - flagIsCA := CertifyAddIsCA&flags != 0 - if flagIsCA != bc.IsCA { - t.Errorf("[ERROR]: ADD_IS_CA is set to %v but the basic constraint IsCA is set to %v", flagIsCA, bc.IsCA) + if res.Handle != *handle { + t.Errorf("[ERROR]: Handle must be unchanged by CertifyKey, want original handle %v but got %v", handle, res.Handle) } } // Parses X509 certificate func checkCertificateStructure(t *testing.T, certBytes []byte) *x509.Certificate { - t.Helper() failed := false var x509Cert *x509.Certificate @@ -392,13 +357,13 @@ func checkCertificateStructure(t *testing.T, certBytes []byte) *x509.Certificate // Check whether certificate is DER encoded. if x509Cert, err = x509.ParseCertificate(certBytes); err != nil { - t.Fatalf("[FATAL]: Could not parse certificate using crypto/x509: %v", err) + t.Fatalf("Could not parse certificate using crypto/x509: %v", err) } // Parse the cert with zcrypto so we can lint it. cert, err := zx509.ParseCertificate(certBytes) if err != nil { - t.Errorf("[ERROR]: Could not parse certificate using zcrypto/x509: %v", err) + t.Errorf("Could not parse certificate using zcrypto/x509: %v", err) failed = true } @@ -457,197 +422,124 @@ func checkCertificateStructure(t *testing.T, certBytes []byte) *x509.Certificate return x509Cert } -func testCertifyKey(d TestDPEInstance, c DPEClient, t *testing.T, simulation bool) { - handle := getInitialContextHandle(d, c, t, simulation) - defer func() { - if simulation { - c.DestroyContext(handle, DestroyDescendants) - } - }() +// A tcg-dice-Ueid extension MUST be added +// This SHALL be populated by the LABEL input parameter to CertifyKey +// The extension SHOULD be marked as critical +func checkCertifyKeyTcgUeidExtension(t *testing.T, extensions []pkix.Extension, label []byte) { + t.Helper() - profile, err := GetTransportProfile(d) + ueid, err := getUeid(extensions) if err != nil { - t.Fatalf("Could not get profile: %v", err) - } - digestLen := profile.GetDigestSize() - - seqLabel := make([]byte, digestLen) - for i := range seqLabel { - seqLabel[i] = byte(i) - } - - certifyKeyParams := []CertifyKeyParams{ - {Label: make([]byte, digestLen), Flags: CertifyKeyFlags(0)}, - {Label: seqLabel, Flags: CertifyKeyFlags(0)}, + t.Errorf("[ERROR]: tcg-dice-Ueid extension is missing: %v", err) } - for _, params := range certifyKeyParams { - // Get DPE leaf certificate from CertifyKey - certifyKeyResp, err := c.CertifyKey(handle, params.Label, CertifyKeyX509, params.Flags) - if err != nil { - t.Fatalf("[FATAL]: Could not certify key: %v", err) - } - - // Get root and intermediate certificates to validate certificate chain of leaf cert - certChainBytes, err := c.GetCertificateChain() - if err != nil { - t.Fatalf("[FATAL]: Could not get Certificate Chain: %v", err) - } - - leafCertBytes := certifyKeyResp.Certificate - - // Run X.509 linter on full certificate chain and file issues for errors - leafCert := checkCertificateStructure(t, leafCertBytes) - certChain := checkCertificateChain(t, certChainBytes) - - // Check default context handle is unchanged - checkCertifyKeyRespHandle(*certifyKeyResp, t, handle) - - // Check public key and algorithm parameters are correct - checkPubKey(t, profile, leafCert.PublicKey, *certifyKeyResp) - - // Check all extensions - checkCertifyKeyExtensions(t, leafCert.Extensions, params.Flags, params.Label) - - // Ensure full certificate chain has valid signatures - // This also checks certificate lifetime, signatures as part of cert chain validation - validateLeafCertChain(t, certChain, leafCert) - - // Reassign handle for simulation mode. - // However, this does not impact in default mode because - // same default context handle is returned in default mode. - handle = &certifyKeyResp.Handle + if !reflect.DeepEqual(ueid.Ueid, label) { + // Ueid extn value doen not match the label + t.Errorf("[ERROR]: tcg-dice-Ueid value does not match with the \"Label\" passed in CertifyKeyRequest") } - // TODO: When DeriveChild is implemented, call it here to add more TCIs and call CertifyKey again. } -// Builds and verifies certificate chain. -func validateLeafCertChain(t *testing.T, certChain []*x509.Certificate, leafCert *x509.Certificate) { +// Checks whether certificate extended key usage is as per spec +// OID for ExtendedKeyUsage Extension: 2.5.29.37 +// The ExtendedKeyUsage extension SHOULD be marked as critical +// If IsCA = true, the extension SHOULD contain tcg-dice-kp-eca +// If IsCA = false, the extension SHOULD contain tcg-dice-kp-attestLoc +func checkCertifyKeyExtendedKeyUsages(t *testing.T, extensions []pkix.Extension, ca bool) { t.Helper() - certsToProcess := []*x509.Certificate{leafCert} - // Remove unhandled critical extensions and EKUs by x509 but defined in spec - removeTcgDiceCriticalExtensions(t, certsToProcess) - removeTcgDiceExtendedKeyUsages(t, certsToProcess) - - // Certificate chain validation for leaf - opts := buildVerifyOptions(t, certChain) - chains, err := leafCert.Verify(opts) + extKeyUsage, err := getExtendedKeyUsages(extensions) if err != nil { - t.Errorf("[ERROR]: Error verifying DPE leaf: %s", err.Error()) + t.Errorf("[ERROR]: ExtKeyUsage extension is missing: %v", err) } - // Log certificate chains linked to leaf - if len(chains) != 1 { - t.Errorf("[ERROR]: Unexpected number of cert chains: %d", len(chains)) + if len(extKeyUsage) == 0 { + t.Errorf("[ERROR]: The Extended Key Usage extension is empty") } -} -// Builds Certificate chain verifier parameters. -func buildVerifyOptions(t *testing.T, certChain []*x509.Certificate) x509.VerifyOptions { - roots := x509.NewCertPool() - intermediates := x509.NewCertPool() - - // Root certificate is expected to be in the beginning of the chain, the rest are expected to be intermediates. - roots.AddCert(certChain[0]) + // Iterate over the OIDs in the ExtKeyUsage extension + isExtendedKeyUsageValid := false + var expectedKeyUsage asn1.ObjectIdentifier + expectedKeyUsageName := "" + if ca { + expectedKeyUsage = OidExtensionTcgDiceKpEca + expectedKeyUsageName = "tcg-dice-kp-eca" + } else { + expectedKeyUsage = OidExtensionTcgDiceKpAttestLoc + expectedKeyUsageName = "tcg-dice-kp-attest-loc" + } - for _, cert := range certChain[1:] { - if cert.Subject.String() == cert.Issuer.String() { - t.Errorf("[ERROR]: Found a self-signed certificate in middle of certificate chain returned by GetCertificateChain.") - continue + for _, oid := range extKeyUsage { + if oid.Equal(expectedKeyUsage) { + isExtendedKeyUsageValid = true + break } - intermediates.AddCert(cert) } - opts := x509.VerifyOptions{ - Roots: roots, - Intermediates: intermediates, - CurrentTime: time.Now().UTC(), - KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, + if !isExtendedKeyUsageValid { + t.Errorf("[ERROR]: Certificate has IsCA: %v and does not contain specified key usage: %s", ca, expectedKeyUsageName) } - - return opts } -// Gets KeyUsage bitmap and returns as list of KeyUsage name strings. -func getKeyUsageNames(keyUsage x509.KeyUsage) []string { - keyUsageNames := []string{} - - if keyUsage&x509.KeyUsageDigitalSignature != 0 { - keyUsageNames = append(keyUsageNames, "DigitalSignature") - } - - if keyUsage&x509.KeyUsageContentCommitment != 0 { - keyUsageNames = append(keyUsageNames, "ContentCommitment") - } +// // Checks for KeyUsage Extension as per spec +// // If IsCA = true, KeyUsage extension MUST contain DigitalSignature and KeyCertSign +// // If IsCA = false, KeyUsage extension MUST contain only DigitalSignature +func checkCertifyKeyExtensions(t *testing.T, extensions []pkix.Extension, flags CertifyKeyFlags, label []byte) { + t.Helper() - if keyUsage&x509.KeyUsageKeyEncipherment != 0 { - keyUsageNames = append(keyUsageNames, "KeyEncipherment") + bc, err := getBasicConstraints(extensions) + if err != nil { + t.Error(err) } - if keyUsage&x509.KeyUsageDataEncipherment != 0 { - keyUsageNames = append(keyUsageNames, "DataEncipherment") - } + checkCertifyKeyBasicConstraints(t, extensions, flags) + checkCertifyKeyExtendedKeyUsages(t, extensions, bc.IsCA) + checkCertifyKeyTcgUeidExtension(t, extensions, label) - if keyUsage&x509.KeyUsageKeyAgreement != 0 { - keyUsageNames = append(keyUsageNames, "KeyAgreement") + // Check MultiTcbInfo Extension structure + _, err = getMultiTcbInfo(extensions) + if err != nil { + t.Error(err) } - if keyUsage&x509.KeyUsageCertSign != 0 { - keyUsageNames = append(keyUsageNames, "CertSign") - } + //Check for keyusage extension + var allowedKeyUsages x509.KeyUsage - if keyUsage&x509.KeyUsageCRLSign != 0 { - keyUsageNames = append(keyUsageNames, "CRLSign") + if bc.IsCA { + allowedKeyUsages = x509.KeyUsageDigitalSignature | x509.KeyUsageCertSign + } else { + allowedKeyUsages = x509.KeyUsageDigitalSignature } - if keyUsage&x509.KeyUsageEncipherOnly != 0 { - keyUsageNames = append(keyUsageNames, "EncipherOnly") + usage, err := getKeyUsage(extensions) + if err != nil { + t.Error(err) } - if keyUsage&x509.KeyUsageDecipherOnly != 0 { - keyUsageNames = append(keyUsageNames, "DecipherOnly") + certKeyUsageList := getKeyUsageNames(usage) + allowedKeyUsageList := getKeyUsageNames(allowedKeyUsages) + if usage != allowedKeyUsages { + t.Errorf("[ERROR]: Certificate KeyUsage got %v but want %v ", certKeyUsageList, allowedKeyUsageList) } - return keyUsageNames } -func checkPubKey(t *testing.T, p Profile, pubkey any, response CertifiedKey) { - var pubKeyInResponse ecdsa.PublicKey - switch p { - case ProfileP256SHA256: - pubKeyInResponse = ecdsa.PublicKey{ - Curve: elliptic.P256(), - X: new(big.Int).SetBytes(response.Pub.X), - Y: new(big.Int).SetBytes(response.Pub.Y), - } - case ProfileP384SHA384: - pubKeyInResponse = ecdsa.PublicKey{ - Curve: elliptic.P384(), - X: new(big.Int).SetBytes(response.Pub.X), - Y: new(big.Int).SetBytes(response.Pub.Y), - } - default: - t.Errorf("[ERROR]: Unsupported profile %v", p) - } - - ecdsaPub, ok := pubkey.(*ecdsa.PublicKey) - if !ok { - t.Fatal("[FATAL]: Public key is not a ecdsa key") - } +// Validates basic constraints in certificate returned by CertifyKey command +// against the flag set for input parameter. +// The BasicConstraints extension MUST be included +// If CertifyKey AddIsCA is set, IsCA MUST be set to true. +// If CertifyKey AddIsCA is NOT set, IsCA MUST be set to false +func checkCertifyKeyBasicConstraints(t *testing.T, extensions []pkix.Extension, flags CertifyKeyFlags) { + t.Helper() - if !(pubKeyInResponse.Equal(ecdsaPub)) { - t.Errorf("[ERROR]: Public key returned in response must match the Public Key Info in the certificate.") - } -} + flagsBuf := &bytes.Buffer{} + binary.Write(flagsBuf, binary.LittleEndian, flags) -// Checks whether the context handle is unchanged after certifyKey command when default context handle is used. -func checkCertifyKeyRespHandle(res CertifiedKey, t *testing.T, handle *ContextHandle) { - if *handle != DefaultContextHandle { - t.Logf("[LOG]: Handle is not default context, skipping check...") - return + bc, err := getBasicConstraints(extensions) + if err != nil { + t.Error(err) } - if res.Handle != *handle { - t.Errorf("[ERROR]: Handle must be unchanged by CertifyKey, want original handle %v but got %v", handle, res.Handle) + flagIsCA := CertifyAddIsCA&flags != 0 + if flagIsCA != bc.IsCA { + t.Errorf("[ERROR]: ADD_IS_CA is set to %v but the basic constraint IsCA is set to %v", flagIsCA, bc.IsCA) } } diff --git a/verification/certs.go b/verification/certs.go index 8a7d3845..d26d34f6 100644 --- a/verification/certs.go +++ b/verification/certs.go @@ -3,13 +3,17 @@ package verification import ( + "bytes" "crypto/x509" "crypto/x509/pkix" "encoding/asn1" + "encoding/binary" "fmt" + "time" + + "golang.org/x/exp/slices" ) -// This file is used to test the certify key command. var ( OidExtensionKeyUsage = asn1.ObjectIdentifier{2, 5, 29, 15} OidExtensionAuthorityKeyIdentifier = asn1.ObjectIdentifier{2, 5, 29, 35} @@ -28,8 +32,87 @@ var ( OidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} ) +var TcgDiceCriticalExtensions = [...]string{ + OidExtensionTcgDiceMultiTcbInfo.String(), + OidExtensionTcgDiceUeid.String(), +} + +var TcgDiceExtendedKeyUsages = [...]string{ + OidExtensionTcgDiceKpIdentityLoc.String(), + OidExtensionTcgDiceKpAttestLoc.String(), +} + +// tcg-dice-Ueid OBJECT IDENTIFIER ::= {tcg-dice 4} +// +// TcgUeid ::== SEQUENCE { +// ueid OCTET STRING +// } +type TcgUeidExtension struct { + Ueid []uint8 `asn1:"ueid,implicit"` +} + +// tcg-dice-MultiTcbInfo OBJECT IDENTIFIER ::= {tcg-dice 5} +// DiceTcbInfoSeq ::= SEQUENCE SIZE (1..MAX) OF DiceTcbInfo +// +// tcg-dice-TcbInfo OBJECT IDENTIFIER ::= {tcg-dice 1} +// +// DiceTcbInfo ::== SEQUENCE { +// vendor [0] IMPLICIT UTF8String OPTIONAL, +// model [1] IMPLICIT UTF8String OPTIONAL, +// version [2] IMPLICIT UTF8String OPTIONAL, +// svn [3] IMPLICIT INTEGER OPTIONAL, +// layer [4] IMPLICIT INTEGER OPTIONAL, +// index [5] IMPLICIT INTEGER OPTIONAL, +// fwids [6] IMPLICIT FWIDLIST OPTIONAL, +// flags [7] IMPLICIT OperationalFlags OPTIONAL, +// vendorInfo [8] IMPLICIT OCTET STRING OPTIONAL, +// type [9] IMPLICIT OCTET STRING OPTIONAL, +// } +// +// FWIDLIST ::== SEQUENCE SIZE (1..MAX) OF FWID +// FWID ::== SEQUENCE { +// hashAlg OBJECT IDENTIFIER, +// digest OCTET STRING +// } +// +// OperationalFlags ::= BIT STRING { +// notConfigured (0), +// notSecure (1), +// recovery (2), +// debug (3) +// } + +type Fwid struct { + HashAlg asn1.ObjectIdentifier + Digest []byte +} + +type DiceTcbInfo struct { + Vendor string `asn1:"optional,tag:0,utf8"` + Model string `asn1:"optional,tag:1,utf8"` + Version string `asn1:"optional,tag:2,utf8"` + SVN int `asn1:"optional,tag:3"` + Layer int `asn1:"optional,tag:4"` + Index int `asn1:"optional,tag:5"` + Fwids []Fwid `asn1:"optional,tag:6"` + Flags OperationalFlag `asn1:"optional,tag:7"` + VendorInfo []byte `asn1:"optional,tag:8"` + Type []byte `asn1:"optional,tag:9"` +} + +type OperationalFlag int + +const ( + NotConfigured OperationalFlag = iota + NotSecure + Debug + Recovery +) + +type TcgMultiTcbInfo = []DiceTcbInfo + type BasicConstraints struct { - IsCA bool `asn1` + IsCA bool `asn1:"boolean"` PathLenConstraint int `asn1:"optional"` } @@ -40,11 +123,11 @@ func getMultiTcbInfo(extensions []pkix.Extension) (TcgMultiTcbInfo, error) { for _, ext := range extensions { if ext.Id.Equal(OidExtensionTcgDiceMultiTcbInfo) { if !ext.Critical { - return multiTcbInfo, fmt.Errorf("[ERROR]: TCG DICE MultiTcbInfo extension is not marked as CRITICAL") + return multiTcbInfo, fmt.Errorf("TCG DICE MultiTcbInfo extension is not marked as CRITICAL") } _, err := asn1.Unmarshal(ext.Value, &multiTcbInfo) if err != nil { - return multiTcbInfo, fmt.Errorf("[ERROR]: Failed to unmarshal MultiTcbInfo field: %v", err) + return multiTcbInfo, fmt.Errorf("Failed to unmarshal MultiTcbInfo field: %v", err) } break } @@ -57,11 +140,11 @@ func getBasicConstraints(extensions []pkix.Extension) (BasicConstraints, error) for _, ext := range extensions { if ext.Id.Equal(OidExtensionBasicConstraints) { if !ext.Critical { - return bc, fmt.Errorf("[ERROR]: BasicConstraints extension is not marked as CRITICAL") + return bc, fmt.Errorf("BasicConstraints extension is not marked as CRITICAL") } _, err := asn1.Unmarshal(ext.Value, &bc) if err != nil { - return bc, fmt.Errorf("[ERROR]: Failed to unmarshal BasicConstraints extension: %v", err) + return bc, fmt.Errorf("Failed to unmarshal BasicConstraints extension: %v", err) } break } @@ -74,11 +157,11 @@ func getUeid(extensions []pkix.Extension) (TcgUeidExtension, error) { for _, ext := range extensions { if ext.Id.Equal(OidExtensionTcgDiceUeid) { if !ext.Critical { - return ueid, fmt.Errorf("[ERROR]: UEID extension is not marked as CRITICAL") + return ueid, fmt.Errorf("UEID extension is not marked as CRITICAL") } _, err := asn1.Unmarshal(ext.Value, &ueid) if err != nil { - return ueid, fmt.Errorf("[ERROR]: Failed to unmarshal UEID extension: %v", err) + return ueid, fmt.Errorf("Failed to unmarshal UEID extension: %v", err) } break } @@ -91,11 +174,11 @@ func getExtendedKeyUsages(extensions []pkix.Extension) ([]asn1.ObjectIdentifier, for _, ext := range extensions { if ext.Id.Equal(OidExtensionExtKeyUsage) { if !ext.Critical { - return eku, fmt.Errorf("[ERROR]: ExtKeyUsage extension is not marked as CRITICAL") + return eku, fmt.Errorf("ExtKeyUsage extension is not marked as CRITICAL") } _, err := asn1.Unmarshal(ext.Value, &eku) if err != nil { - return eku, fmt.Errorf("[ERROR]: Failed to unmarshal ExtKeyUsage extension: %v", err) + return eku, fmt.Errorf("Failed to unmarshal ExtKeyUsage extension: %v", err) } break } @@ -108,11 +191,11 @@ func getKeyUsage(extensions []pkix.Extension) (x509.KeyUsage, error) { for _, ext := range extensions { if ext.Id.Equal(OidExtensionKeyUsage) { if !ext.Critical { - return x509.KeyUsage(0), fmt.Errorf("[ERROR]: KeyUsage extension is not marked as CRITICAL") + return x509.KeyUsage(0), fmt.Errorf("KeyUsage extension is not marked as CRITICAL") } _, err := asn1.Unmarshal(ext.Value, &usageBits) if err != nil { - return x509.KeyUsage(0), fmt.Errorf("[ERROR]: Failed to unmarshal KeyUsage extension: %v", err) + return x509.KeyUsage(0), fmt.Errorf("Failed to unmarshal KeyUsage extension: %v", err) } break } @@ -166,3 +249,274 @@ func getTcbInfoForHandle(c DPEClient, handle *ContextHandle) (*ContextHandle, Di return outHandle, multiTcbInfo[0], nil } + +// Removes the critical extensions that are unknown to x509 package +// but defined in DPE certificate profile specification for cert chain validation +// UnhandledCriticalExtensions may have only custom extensions mentioned in spec +// unknownExtnMap collects extensions unknown to both x509 and the DICE certificate profiles spec +// positive case expects the unknownExtnMap to be empty. +func removeTcgDiceCriticalExtensions(certs []*x509.Certificate) error { + unknownExtnMap := map[string][]string{} + for _, cert := range certs { + if len(cert.UnhandledCriticalExtensions) > 0 { + unknownExtns := []string{} + for _, extn := range cert.UnhandledCriticalExtensions { + if !slices.Contains(TcgDiceCriticalExtensions[:], extn.String()) { + unknownExtns = append(unknownExtns, extn.String()) + } + } + + if len(unknownExtnMap) == 0 { + cert.UnhandledCriticalExtensions = []asn1.ObjectIdentifier{} + } else { + unknownExtnMap[cert.Subject.String()] = unknownExtns + } + } + } + // The error details in this map will be logged + msg := "" + if len(unknownExtnMap) > 0 { + for certSubject, ext := range unknownExtnMap { + msg += fmt.Errorf("Certificate \"%s\" has unhandled critical extension \"%s\"", certSubject, ext).Error() + } + return fmt.Errorf("%s", msg) + } + return nil +} + +// Ignores extended key usages that are unknown to x509 package +// but atleast defined in DPE certificate profile specification for cert chain validation +// UnhandledExtendedKeyUsages may have only custom key usages mentioned in spec +// unknownKeyUsagesMap collects keyusages unknown to both x509 and the DICE certificate profiles spec +// positive case expects the unknownKeyUsagesMap to be empty. +func removeTcgDiceExtendedKeyUsages(certs []*x509.Certificate) error { + unknownKeyUsagesMap := map[string][]string{} + for _, cert := range certs { + if len(cert.UnknownExtKeyUsage) > 0 { + unknownKeyUsages := []string{} + for _, eku := range cert.UnknownExtKeyUsage { + if !slices.Contains(TcgDiceExtendedKeyUsages[:], eku.String()) { + unknownKeyUsages = append(unknownKeyUsages, eku.String()) + } + } + + if len(unknownKeyUsagesMap) == 0 { + cert.UnknownExtKeyUsage = []asn1.ObjectIdentifier{} + } else { + unknownKeyUsagesMap[cert.Subject.String()] = unknownKeyUsages + } + } + } + // The error details in this map will be logged + msg := "" + if len(unknownKeyUsagesMap) > 0 { + for certSubject, ext := range unknownKeyUsagesMap { + msg += fmt.Errorf("Certificate \"%s\" has unhandled critical extension \"%s\"", certSubject, ext).Error() + } + return fmt.Errorf("%s", msg) + } + return nil +} + +// Checks whether the VendorInfo is 4-bytes TARGET_LOCALITY parameter +func checkDiceTcbVendorInfo(currentTcbInfo DiceTcbInfo, targetLocality uint32) error { + var err error + expectedVendorInfo := make([]byte, 4) + binary.BigEndian.PutUint32(expectedVendorInfo, targetLocality) + if !bytes.Equal(currentTcbInfo.VendorInfo, expectedVendorInfo) { + err = fmt.Errorf("Unexpected VendorInfo for current DICE TCB block, want %v but got %v", expectedVendorInfo, currentTcbInfo.VendorInfo) + } + return err +} + +// Checks whether INPUT_TYPE passed to a deriveChild Request +// populates the "type" field in the DiceTcbInfo extension. +func checkCurrentDiceTcbTciType(currentTcbInfo DiceTcbInfo, expectedTciType uint32) error { + var err error + expectedTciTypeBytes := make([]byte, 4) + binary.BigEndian.PutUint32(expectedTciTypeBytes, expectedTciType) + if !bytes.Equal(currentTcbInfo.Type, expectedTciTypeBytes) { + err = fmt.Errorf("Unexpected TCI type for current DICE TCB block, want %v but got %v", expectedTciTypeBytes, currentTcbInfo.Type) + } + return err +} + +// Checks whether the Hash Algorithm field in FWID block is correct +func checkDiceTcbHashAlgorithm(currentTcbInfo DiceTcbInfo, hashAlg asn1.ObjectIdentifier) error { + for _, fwid := range currentTcbInfo.Fwids { + if !fwid.HashAlg.Equal(hashAlg) { + return fmt.Errorf("Unexpected hash algorithm in FWID block, expected %s but got %s", hashAlg, fwid.HashAlg) + } + } + return nil +} + +// Builds and verifies certificate chain. +func validateLeafCertChain(certChain []*x509.Certificate, leafCert *x509.Certificate) error { + var err error + certsToProcess := []*x509.Certificate{leafCert} + + // Remove unhandled critical extensions reported by x509 but defined in spec + if err = removeTcgDiceCriticalExtensions(certsToProcess); err != nil { + return err + } + + // Remove unhandled extended key usages reported by x509 but defined in spec + if err = removeTcgDiceExtendedKeyUsages(certsToProcess); err != nil { + return err + } + + // Build verify options + var opts *x509.VerifyOptions + if opts, err = buildVerifyOptions(certChain); err != nil { + return err + } + + // Certificate chain validation for leaf + chains, err := leafCert.Verify(*opts) + if err != nil { + // Unable to build certificate chain from leaf to root + return fmt.Errorf("Error verifying DPE leaf: %s", err.Error()) + } + + // Log certificate chains linked to leaf + if len(chains) != 1 { + return fmt.Errorf("Unexpected number of cert chains: %d", len(chains)) + } + return nil +} + +// Builds Certificate chain verifier parameters. +func buildVerifyOptions(certChain []*x509.Certificate) (*x509.VerifyOptions, error) { + var err error + roots := x509.NewCertPool() + intermediates := x509.NewCertPool() + + // Root certificate is expected to be in the beginning of the chain, the rest are expected to be intermediates. + roots.AddCert(certChain[0]) + + for _, cert := range certChain[1:] { + if cert.Subject.String() == cert.Issuer.String() { + return nil, fmt.Errorf("Found a self-signed certificate in middle of certificate chain returned by GetCertificateChain") + } + intermediates.AddCert(cert) + } + opts := x509.VerifyOptions{ + Roots: roots, + Intermediates: intermediates, + CurrentTime: time.Now().UTC(), + KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny}, + } + + return &opts, err +} + +// Gets KeyUsage bitmap and returns as list of KeyUsage name strings. +func getKeyUsageNames(keyUsage x509.KeyUsage) []string { + keyUsageNames := []string{} + + if keyUsage&x509.KeyUsageDigitalSignature != 0 { + keyUsageNames = append(keyUsageNames, "DigitalSignature") + } + + if keyUsage&x509.KeyUsageContentCommitment != 0 { + keyUsageNames = append(keyUsageNames, "ContentCommitment") + } + + if keyUsage&x509.KeyUsageKeyEncipherment != 0 { + keyUsageNames = append(keyUsageNames, "KeyEncipherment") + } + + if keyUsage&x509.KeyUsageDataEncipherment != 0 { + keyUsageNames = append(keyUsageNames, "DataEncipherment") + } + + if keyUsage&x509.KeyUsageKeyAgreement != 0 { + keyUsageNames = append(keyUsageNames, "KeyAgreement") + } + + if keyUsage&x509.KeyUsageCertSign != 0 { + keyUsageNames = append(keyUsageNames, "CertSign") + } + + if keyUsage&x509.KeyUsageCRLSign != 0 { + keyUsageNames = append(keyUsageNames, "CRLSign") + } + + if keyUsage&x509.KeyUsageEncipherOnly != 0 { + keyUsageNames = append(keyUsageNames, "EncipherOnly") + } + + if keyUsage&x509.KeyUsageDecipherOnly != 0 { + keyUsageNames = append(keyUsageNames, "DecipherOnly") + } + + return keyUsageNames +} + +// Verifies the TCI_Current and TCI_Cumulative of dice tcb information blocks +func verifyDiceTcbDigest(tcbInfo DiceTcbInfo, wantCurrentTCI []byte, lastCumulativeTCI []byte) error { + var err error + + // Check TCI_CURRENT + currentTCI := tcbInfo.Fwids[0].Digest + if !bytes.Equal(currentTCI, wantCurrentTCI) { + err = fmt.Errorf("Unexpected TCI_CURRENT digest, want %v but got %v", wantCurrentTCI, currentTCI) + } + + // Check TCI_CUMULATIVE against expected cumulative TCI + wantCumulativeTCI := computeExpectedCumulative(lastCumulativeTCI, currentTCI) + cumulativeTCI := tcbInfo.Fwids[1].Digest + if !bytes.Equal(cumulativeTCI, wantCumulativeTCI) { + err = fmt.Errorf("Unexpected TCI_CUMULATIVE value, want %v but got %v", wantCumulativeTCI, cumulativeTCI) + } + return err +} + +// Checks the FWID block's Digest. +// FWID at index 0 has the TCI_CURRENT as digest +// FWID at index 1 has the TCI_CUMULATIVE as digest +// FWID array always has two digest/hashAlg blocks when "ExtendTci" is supported by DPE profile. +func validateDiceTcbFwids(leafCertBytes []byte, currentTcis [][]byte, digestLen int) error { + var leafCert *x509.Certificate + var err error + + // Check whether certificate is DER encoded. + if leafCert, err = x509.ParseCertificate(leafCertBytes); err != nil { + return err + } + + // Get DICE information from MultiTcbInfo Extension + var multiTcbInfo []DiceTcbInfo + if multiTcbInfo, err = getMultiTcbInfo(leafCert.Extensions); err != nil { + return err + } + + if len(multiTcbInfo) == 0 { + return fmt.Errorf("Certificate MutliTcbInfo is empty") + } + + // Calculate expected cumulative value + defaultTci := make([]byte, digestLen) + + // Check cumulative, current TCI at the last index of multitcb info + // It must have default TCI value + lastIndex := len(multiTcbInfo) - 1 + if !bytes.Equal(multiTcbInfo[lastIndex].Fwids[0].Digest, defaultTci) { + return fmt.Errorf("Current TCI value for first TCB block, want %v but got %v", defaultTci, multiTcbInfo[lastIndex].Fwids[0].Digest) + } + + if !bytes.Equal(multiTcbInfo[lastIndex].Fwids[1].Digest, defaultTci) { + return fmt.Errorf("Cumulative TCI value for first TCB block, want %v but got %v", defaultTci, multiTcbInfo[lastIndex].Fwids[1].Digest) + } + + // Check cumulative, current TCI of other indices if any + lastCumulativeTCI := defaultTci + multiTcbInfo = multiTcbInfo[:lastIndex] + + for i, tcbinfo := range multiTcbInfo { + wantCurrentTci := currentTcis[i] + verifyDiceTcbDigest(tcbinfo, wantCurrentTci, lastCumulativeTCI) + } + return err +} diff --git a/verification/deriveChild.go b/verification/deriveChild.go new file mode 100644 index 00000000..d920288d --- /dev/null +++ b/verification/deriveChild.go @@ -0,0 +1,320 @@ +// Licensed under the Apache-2.0 license + +package verification + +import ( + "errors" + "testing" +) + +func TestDeriveChild(d TestDPEInstance, c DPEClient, t *testing.T) { + var resp *DeriveChildResp + + simulation := false + handle := getInitialContextHandle(d, c, t, simulation) + defer func() { + c.DestroyContext(handle, DestroyDescendants) + }() + + // Get digest size + profile, err := GetTransportProfile(d) + if err != nil { + t.Fatalf("Could not get profile: %v", err) + } + + digestLen := profile.GetDigestSize() + + // Child context handle returned will be the default context handle when MakeDefault flag is set + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), MakeDefault, 0, 0); err != nil { + t.Errorf("[ERROR]: Error while creating child context handle: %s", err) + } + handle = &resp.NewContextHandle + if resp.NewContextHandle != DefaultContextHandle { + t.Fatalf("[FATAL]: Incorrect handle. Should return %v, but returned %v", DefaultContextHandle, *handle) + } + + // When there is already a default handle, setting MakeDefault and RetainParent will cause error + // because there cannot be two default handles in a locality + if _, err = c.DeriveChild(handle, make([]byte, digestLen), MakeDefault|RetainParent, 0, 0); err == nil { + t.Errorf("[ERROR]: Should return %q, but returned no error", StatusInvalidArgument) + } else if !errors.Is(err, StatusInvalidArgument) { + t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) + } + + // Retain parent should fail because parent handle is a default handle + // and child handle will be a non-default handle. + // Default and non-default handle cannot coexist in same locality. + if _, err = c.DeriveChild(handle, make([]byte, digestLen), RetainParent, 0, 0); err == nil { + t.Errorf("[ERROR]: Should return %q, but returned no error", StatusInvalidArgument) + } else if !errors.Is(err, StatusInvalidArgument) { + t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) + } + + // Child context handle should be a random handle when MakeDefault flag is NOT used + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), 0, 0, 0); err != nil { + t.Errorf("[ERROR]: Error while creating child context handle: %s", err) + } + handle = &resp.NewContextHandle + if resp.NewContextHandle == DefaultContextHandle { + t.Fatalf("[FATAL]: Incorrect handle. Should return non-default handle, but returned %v", *handle) + } + if resp.ParentContextHandle != InvalidatedContextHandle { + t.Errorf("[ERROR]: Incorrect handle. Should be invalidated when retain parent is NOT set, but returned %v", resp.ParentContextHandle) + } + + // Now, there is no default handle, setting RetainParent flag should succeed + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), RetainParent, 0, 0); err != nil { + t.Errorf("[ERROR]: Error while making child context handle as default handle: %s", err) + } + handle = &resp.NewContextHandle + parentHandle := resp.ParentContextHandle + + if parentHandle == InvalidatedContextHandle { + t.Errorf("[ERROR]: Incorrect handle. Should return retained handle, but returned invalidated handle %v", parentHandle) + } +} + +// Validates DerivedChild command with ChangeLocality flag. +func TestChangeLocality(d TestDPEInstance, c DPEClient, t *testing.T) { + if !d.HasLocalityControl() { + t.Skip("WARNING: DPE profile does not have control over locality. Skipping this test...") + } + + var resp *DeriveChildResp + simulation := false + handle := getInitialContextHandle(d, c, t, simulation) + // Clean up contexts + defer func() { + err := c.DestroyContext(handle, DestroyDescendants) + if err != nil { + t.Errorf("[ERROR]: Error while cleaning contexts, this may cause failure in subsequent tests: %s", err) + } + }() + + // Get digest size + profile, err := GetTransportProfile(d) + if err != nil { + t.Fatalf("Could not get profile: %v", err) + } + + digestLen := profile.GetDigestSize() + currentLocality := d.GetLocality() + otherLocality := currentLocality + 1 + + // Create child context in other locality + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), ChangeLocality, 0, otherLocality); err != nil { + t.Fatalf("[ERROR]: Error while creating child context handle in other locality: %s", err) + } + handle = &resp.NewContextHandle + + // Revert to same locality from other locality + prevLocality := currentLocality + d.SetLocality(otherLocality) + + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), ChangeLocality, 0, prevLocality); err != nil { + t.Fatalf("[FATAL]: Error while creating child context handle in previous locality: %s", err) + } + handle = &resp.NewContextHandle + d.SetLocality(prevLocality) +} + +// Checks whether the DeriveChild input flags - InternalDiceInfo, InternalInputInfo are supported +// while creating child contexts when these features are supported in DPE profile. +func TestInternalInputFlags(d TestDPEInstance, c DPEClient, t *testing.T) { + var resp *DeriveChildResp + simulation := false + handle := getInitialContextHandle(d, c, t, simulation) + defer func() { + c.DestroyContext(handle, DestroyDescendants) + }() + + // Get digest size + profile, err := GetTransportProfile(d) + if err != nil { + t.Fatalf("Could not get profile: %v", err) + } + + digestLen := profile.GetDigestSize() + // Internal input flags + if d.GetSupport().InternalDice { + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), DeriveChildFlags(InternalInputDice), 0, 0); err != nil { + t.Errorf("[ERROR]: Error while making child context handle as default handle: %s", err) + } + handle = &resp.NewContextHandle + } else { + t.Skip("[WARNING]: Profile has no support for \"InternalInputDice\" flag. Skipping the validation for this flag...") + } + + if d.GetSupport().InternalInfo { + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), DeriveChildFlags(InternalInputInfo), 0, 0); err != nil { + t.Errorf("[ERROR]: Error while making child context handle as default handle: %s", err) + } + handle = &resp.NewContextHandle + } else { + t.Skip("[WARNING]: Profile has no support for \"InternalInputInfo\" flag. Skipping the validation for this flag...") + } +} + +// Checks the privilege escalation of child +// When commands try to make use of features that are unsupported by child context, they fail. +func TestPrivilegesEscalation(d TestDPEInstance, c DPEClient, t *testing.T) { + var err error + simulation := false + handle := getInitialContextHandle(d, c, t, simulation) + + // Get digest size + profile, err := GetTransportProfile(d) + if err != nil { + t.Fatalf("Could not get profile: %v", err) + } + + digestLen := profile.GetDigestSize() + + // Create a child TCI node with no special privileges + resp, err := c.DeriveChild(handle, + make([]byte, digestLen), + DeriveChildFlags(0), + 0, 0) + if err != nil { + t.Fatalf("[FATAL]: Error encountered in getting child context: %v", err) + } + handle = &resp.NewContextHandle + + // Adding new privileges to child that parent does NOT possess will cause failure + _, err = c.DeriveChild(handle, + make([]byte, digestLen), + DeriveChildFlags(InputAllowX509|InputAllowCA), + 0, 0) + if err == nil { + t.Errorf("[ERROR]: Should return %q, but returned no error", StatusInvalidArgument) + } else if !errors.Is(err, StatusInvalidArgument) { + t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) + } + + // Similarly, when commands like CertifyKey try to make use of features/flags that are unsupported + // by child context, it will fail. + if _, err = c.CertifyKey(handle, make([]byte, digestLen), CertifyKeyX509, CertifyAddIsCA); err == nil { + t.Errorf("[ERROR]: Should return %q, but returned no error", StatusInvalidArgument) + } else if !errors.Is(err, StatusInvalidArgument) { + t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) + } +} + +// Checks whether the number of derived contexts (TCI nodes) are limited by MAX_TCI_NODES attribute of the profile +func TestMaxTCIs(d TestDPEInstance, c DPEClient, t *testing.T) { + var resp *DeriveChildResp + + simulation := false + handle := getInitialContextHandle(d, c, t, simulation) + defer func() { c.DestroyContext(handle, DestroyDescendants) }() + + // Get digest size + profile, err := GetTransportProfile(d) + if err != nil { + t.Fatalf("Could not get profile: %v", err) + } + digestSize := profile.GetDigestSize() + + // Get Max TCI count + maxTciCount := int(d.GetMaxTciNodes()) + allowedTciCount := maxTciCount - 1 // since, a TCI node is already auto-initialized + for i := 0; i < allowedTciCount; i++ { + resp, err = c.DeriveChild(handle, make([]byte, digestSize), 0, 0, 0) + if err != nil { + t.Fatalf("[FATAL]: Error encountered in executing derive child: %v", err) + } + handle = &resp.NewContextHandle + } + + // Exceed the Max TCI node count limit + _, err = c.DeriveChild(handle, make([]byte, digestSize), 0, 0, 0) + if err == nil { + t.Fatalf("[FATAL]: Should return %q, but returned no error", StatusMaxTCIs) + } else if !errors.Is(err, StatusMaxTCIs) { + t.Fatalf("[FATAL]: Incorrect error type. Should return %q, but returned %q", StatusMaxTCIs, err) + } +} + +func TestDeriveChildSimulation(d TestDPEInstance, c DPEClient, t *testing.T) { + if !d.HasLocalityControl() { + t.Skip("WARNING: DPE profile does not have control over locality, DeriveContext in Simulation mode cannot be tested without this support. Skipping this test...") + } + var resp *DeriveChildResp + + simulation := true + handle := getInitialContextHandle(d, c, t, simulation) + defer func() { + c.DestroyContext(handle, DestroyDescendants) + }() + + // Get digest size + profile, err := GetTransportProfile(d) + if err != nil { + t.Fatalf("Could not get profile: %v", err) + } + + digestLen := profile.GetDigestSize() + locality := d.GetLocality() + + // MakeDefault should fail because parent handle is a non-default handle + // and child handle will be a default handle. + // Default and non-default handle cannot coexist in same locality. + if _, err = c.DeriveChild(handle, make([]byte, digestLen), MakeDefault, 0, 0); err == nil { + t.Errorf("[ERROR]: Should return %q, but returned no error", StatusInvalidArgument) + } else if !errors.Is(err, StatusInvalidArgument) { + t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) + } + + // Make default child context in other locality + childCtx, err := c.DeriveChild(handle, + make([]byte, digestLen), + DeriveChildFlags(ChangeLocality|RetainParent|MakeDefault), + 0, + locality+1) // Switch locality to derive child context from Simulation context + + if err != nil { + t.Fatalf("[FATAL]: Error while creating child handle: %s", err) + } + + handle = &childCtx.NewContextHandle + parentHandle := &childCtx.ParentContextHandle + + // Clean up parent context + defer func() { + err := c.DestroyContext(parentHandle, DestroyDescendants) + if err != nil { + t.Errorf("[ERROR]: Error while cleaning contexts, this may cause failure in subsequent tests: %s", err) + } + }() + + d.SetLocality(locality + 1) + + defer func() { + // Clean up contexts after test + err := c.DestroyContext(handle, DestroyDescendants) + if err != nil { + t.Errorf("[ERROR]: Error while cleaning up derived context, this may cause failure in subsequent tests: %s", err) + } + // Revert locality for other tests + d.SetLocality(locality) + }() + + // Retain parent should fail because parent handle is a default handle + // and child handle will be a non-default handle. + // Default and non-default handle cannot coexist in same locality. + if _, err = c.DeriveChild(handle, make([]byte, digestLen), RetainParent, 0, 0); err == nil { + t.Errorf("[ERROR]: Should return %q, but returned no error", StatusInvalidArgument) + } else if !errors.Is(err, StatusInvalidArgument) { + t.Errorf("[ERROR]: Incorrect error type. Should return %q, but returned %q", StatusInvalidArgument, err) + } + + // Setting RetainParent flag should not invalidate the parent handle + if resp, err = c.DeriveChild(handle, make([]byte, digestLen), RetainParent, 0, 0); err != nil { + t.Fatalf("[FATAL]: Error while making child context and retaining parent handle %s", err) + } + handle = &resp.NewContextHandle + + if resp.ParentContextHandle == InvalidatedContextHandle { + t.Errorf("[ERROR]: Incorrect handle. Should return retained handle, but returned invalidated handle %v", parentHandle) + } +} diff --git a/verification/examples/spdm/.gitignore b/verification/examples/spdm/.gitignore new file mode 100644 index 00000000..fcb6a2f4 --- /dev/null +++ b/verification/examples/spdm/.gitignore @@ -0,0 +1 @@ +build diff --git a/verification/examples/spdm/.gitmodules b/verification/examples/spdm/.gitmodules new file mode 100644 index 00000000..09eaa778 --- /dev/null +++ b/verification/examples/spdm/.gitmodules @@ -0,0 +1,6 @@ +[submodule "libspdm"] + path = libspdm + url = https://github.com/DMTF/libspdm +[submodule "SPDM-Responder-Validator"] + path = SPDM-Responder-Validator + url = https://github.com/DMTF/SPDM-Responder-Validator diff --git a/verification/examples/spdm/.uncrustify.cfg b/verification/examples/spdm/.uncrustify.cfg new file mode 100644 index 00000000..559c93e5 --- /dev/null +++ b/verification/examples/spdm/.uncrustify.cfg @@ -0,0 +1,2807 @@ +# Uncrustify-0.69.0_f + +# +# General options +# + +# The type of line endings. +# +# Default: auto +newlines = auto # lf/crlf/cr/auto + +# The original size of tabs in the input. +# +# Default: 8 +input_tab_size = 4 # unsigned number + +# The size of tabs in the output (only used if align_with_tabs=true). +# +# Default: 8 +output_tab_size = 4 # unsigned number + +# The ASCII value of the string escape char, usually 92 (\) or (Pawn) 94 (^). +# +# Default: 92 +string_escape_char = 92 # unsigned number + +# Alternate string escape char (usually only used for Pawn). +# Only works right before the quote char. +string_escape_char2 = 0 # unsigned number + +# Replace tab characters found in string literals with the escape sequence \t +# instead. +string_replace_tab_chars = false # true/false + +# Allow interpreting '>=' and '>>=' as part of a template in code like +# 'void f(list>=val);'. If true, 'assert(x<0 && y>=3)' will be broken. +# Improvements to template detection may make this option obsolete. +tok_split_gte = false # true/false + +# Specify the marker used in comments to disable processing of part of the +# file. +# +# Default: *INDENT-OFF* +disable_processing_cmt = " *INDENT-OFF*" # string + +# Specify the marker used in comments to (re)enable processing in a file. +# +# Default: *INDENT-ON* +enable_processing_cmt = " *INDENT-ON*" # string + +# Enable parsing of digraphs. +enable_digraphs = false # true/false + +# Add or remove the UTF-8 BOM (recommend 'remove'). +utf8_bom = ignore # ignore/add/remove/force + +# If the file contains bytes with values between 128 and 255, but is not +# UTF-8, then output as UTF-8. +utf8_byte = false # true/false + +# Force the output encoding to UTF-8. +utf8_force = false # true/false + +# +# Spacing options +# + +# Add or remove space around non-assignment symbolic operators ('+', '/', '%', +# '<<', and so forth). +sp_arith = ignore # ignore/add/remove/force + +# Add or remove space around arithmetic operators '+' and '-'. +# +# Overrides sp_arith. +sp_arith_additive = ignore # ignore/add/remove/force + +# Add or remove space around assignment operator '=', '+=', etc. +sp_assign = ignore # ignore/add/remove/force + +# Add or remove space around '=' in C++11 lambda capture specifications. +# +# Overrides sp_assign. +sp_cpp_lambda_assign = ignore # ignore/add/remove/force + +# Add or remove space after the capture specification in C++11 lambda. +sp_cpp_lambda_paren = ignore # ignore/add/remove/force + +# Add or remove space around assignment operator '=' in a prototype. +# +# If set to ignore, use sp_assign. +sp_assign_default = ignore # ignore/add/remove/force + +# Add or remove space before assignment operator '=', '+=', etc. +# +# Overrides sp_assign. +sp_before_assign = ignore # ignore/add/remove/force + +# Add or remove space after assignment operator '=', '+=', etc. +# +# Overrides sp_assign. +sp_after_assign = ignore # ignore/add/remove/force + +# Add or remove space in 'NS_ENUM ('. +sp_enum_paren = ignore # ignore/add/remove/force + +# Add or remove space around assignment '=' in enum. +sp_enum_assign = ignore # ignore/add/remove/force + +# Add or remove space before assignment '=' in enum. +# +# Overrides sp_enum_assign. +sp_enum_before_assign = ignore # ignore/add/remove/force + +# Add or remove space after assignment '=' in enum. +# +# Overrides sp_enum_assign. +sp_enum_after_assign = ignore # ignore/add/remove/force + +# Add or remove space around assignment ':' in enum. +sp_enum_colon = ignore # ignore/add/remove/force + +# Add or remove space around preprocessor '##' concatenation operator. +# +# Default: add +sp_pp_concat = add # ignore/add/remove/force + +# Add or remove space after preprocessor '#' stringify operator. +# Also affects the '#@' charizing operator. +sp_pp_stringify = ignore # ignore/add/remove/force + +# Add or remove space before preprocessor '#' stringify operator +# as in '#define x(y) L#y'. +sp_before_pp_stringify = ignore # ignore/add/remove/force + +# Add or remove space around boolean operators '&&' and '||'. +sp_bool = ignore # ignore/add/remove/force + +# Add or remove space around compare operator '<', '>', '==', etc. +sp_compare = ignore # ignore/add/remove/force + +# Add or remove space inside '(' and ')'. +sp_inside_paren = ignore # ignore/add/remove/force + +# Add or remove space between nested parentheses, i.e. '((' vs. ') )'. +sp_paren_paren = ignore # ignore/add/remove/force + +# Add or remove space between back-to-back parentheses, i.e. ')(' vs. ') ('. +sp_cparen_oparen = ignore # ignore/add/remove/force + +# Whether to balance spaces inside nested parentheses. +sp_balance_nested_parens = false # true/false + +# Add or remove space between ')' and '{'. +sp_paren_brace = ignore # ignore/add/remove/force + +# Add or remove space between nested braces, i.e. '{{' vs '{ {'. +sp_brace_brace = ignore # ignore/add/remove/force + +# Add or remove space before pointer star '*'. +sp_before_ptr_star = ignore # ignore/add/remove/force + +# Add or remove space before pointer star '*' that isn't followed by a +# variable name. If set to 'ignore', sp_before_ptr_star is used instead. +sp_before_unnamed_ptr_star = ignore # ignore/add/remove/force + +# Add or remove space between pointer stars '*'. +sp_between_ptr_star = ignore # ignore/add/remove/force + +# Add or remove space after pointer star '*', if followed by a word. +sp_after_ptr_star = ignore # ignore/add/remove/force + +# Add or remove space after pointer caret '^', if followed by a word. +sp_after_ptr_block_caret = ignore # ignore/add/remove/force + +# Add or remove space after pointer star '*', if followed by a qualifier. +sp_after_ptr_star_qualifier = ignore # ignore/add/remove/force + +# Add or remove space after a pointer star '*', if followed by a function +# prototype or function definition. +sp_after_ptr_star_func = ignore # ignore/add/remove/force + +# Add or remove space after a pointer star '*', if followed by an open +# parenthesis, as in 'void* (*)(). +sp_ptr_star_paren = ignore # ignore/add/remove/force + +# Add or remove space before a pointer star '*', if followed by a function +# prototype or function definition. +sp_before_ptr_star_func = ignore # ignore/add/remove/force + +# Add or remove space before a reference sign '&'. +sp_before_byref = ignore # ignore/add/remove/force + +# Add or remove space before a reference sign '&' that isn't followed by a +# variable name. If set to 'ignore', sp_before_byref is used instead. +sp_before_unnamed_byref = ignore # ignore/add/remove/force + +# Add or remove space after reference sign '&', if followed by a word. +sp_after_byref = ignore # ignore/add/remove/force + +# Add or remove space after a reference sign '&', if followed by a function +# prototype or function definition. +sp_after_byref_func = ignore # ignore/add/remove/force + +# Add or remove space before a reference sign '&', if followed by a function +# prototype or function definition. +sp_before_byref_func = ignore # ignore/add/remove/force + +# Add or remove space between type and word. +# +# Default: force +sp_after_type = force # ignore/add/remove/force + +# Add or remove space between 'decltype(...)' and word. +sp_after_decltype = ignore # ignore/add/remove/force + +# (D) Add or remove space before the parenthesis in the D constructs +# 'template Foo(' and 'class Foo('. +sp_before_template_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'template' and '<'. +# If set to ignore, sp_before_angle is used. +sp_template_angle = ignore # ignore/add/remove/force + +# Add or remove space before '<'. +sp_before_angle = ignore # ignore/add/remove/force + +# Add or remove space inside '<' and '>'. +sp_inside_angle = ignore # ignore/add/remove/force + +# Add or remove space inside '<>'. +sp_inside_angle_empty = ignore # ignore/add/remove/force + +# Add or remove space between '>' and ':'. +sp_angle_colon = ignore # ignore/add/remove/force + +# Add or remove space after '<>'. +sp_after_angle = ignore # ignore/add/remove/force + +# Add or remove space between '>' and '(' as found in 'new List(foo);'. +sp_angle_paren = ignore # ignore/add/remove/force + +# Add or remove space between '>' and '()' as found in 'new List();'. +sp_angle_paren_empty = ignore # ignore/add/remove/force + +# Add or remove space between '>' and a word as in 'List m;' or +# 'template static ...'. +sp_angle_word = ignore # ignore/add/remove/force + +# Add or remove space between '>' and '>' in '>>' (template stuff). +# +# Default: add +sp_angle_shift = add # ignore/add/remove/force + +# (C++11) Permit removal of the space between '>>' in 'foo >'. Note +# that sp_angle_shift cannot remove the space without this option. +sp_permit_cpp11_shift = false # true/false + +# Add or remove space before '(' of control statements ('if', 'for', 'switch', +# 'while', etc.). +sp_before_sparen = ignore # ignore/add/remove/force + +# Add or remove space inside '(' and ')' of control statements. +sp_inside_sparen = ignore # ignore/add/remove/force + +# Add or remove space after '(' of control statements. +# +# Overrides sp_inside_sparen. +sp_inside_sparen_open = ignore # ignore/add/remove/force + +# Add or remove space before ')' of control statements. +# +# Overrides sp_inside_sparen. +sp_inside_sparen_close = ignore # ignore/add/remove/force + +# Add or remove space after ')' of control statements. +sp_after_sparen = ignore # ignore/add/remove/force + +# Add or remove space between ')' and '{' of of control statements. +sp_sparen_brace = ignore # ignore/add/remove/force + +# (D) Add or remove space between 'invariant' and '('. +sp_invariant_paren = ignore # ignore/add/remove/force + +# (D) Add or remove space after the ')' in 'invariant (C) c'. +sp_after_invariant_paren = ignore # ignore/add/remove/force + +# Add or remove space before empty statement ';' on 'if', 'for' and 'while'. +sp_special_semi = ignore # ignore/add/remove/force + +# Add or remove space before ';'. +# +# Default: remove +sp_before_semi = remove # ignore/add/remove/force + +# Add or remove space before ';' in non-empty 'for' statements. +sp_before_semi_for = ignore # ignore/add/remove/force + +# Add or remove space before a semicolon of an empty part of a for statement. +sp_before_semi_for_empty = ignore # ignore/add/remove/force + +# Add or remove space after ';', except when followed by a comment. +# +# Default: add +sp_after_semi = add # ignore/add/remove/force + +# Add or remove space after ';' in non-empty 'for' statements. +# +# Default: force +sp_after_semi_for = force # ignore/add/remove/force + +# Add or remove space after the final semicolon of an empty part of a for +# statement, as in 'for ( ; ; )'. +sp_after_semi_for_empty = ignore # ignore/add/remove/force + +# Add or remove space before '[' (except '[]'). +sp_before_square = ignore # ignore/add/remove/force + +# Add or remove space before '[]'. +sp_before_squares = ignore # ignore/add/remove/force + +# Add or remove space before C++17 structured bindings. +sp_cpp_before_struct_binding = ignore # ignore/add/remove/force + +# Add or remove space inside a non-empty '[' and ']'. +sp_inside_square = ignore # ignore/add/remove/force + +# (OC) Add or remove space inside a non-empty Objective-C boxed array '@[' and +# ']'. If set to ignore, sp_inside_square is used. +sp_inside_square_oc_array = ignore # ignore/add/remove/force + +# Add or remove space after ',', i.e. 'a,b' vs. 'a, b'. +sp_after_comma = ignore # ignore/add/remove/force + +# Add or remove space before ','. +# +# Default: remove +sp_before_comma = remove # ignore/add/remove/force + +# (C#) Add or remove space between ',' and ']' in multidimensional array type +# like 'int[,,]'. +sp_after_mdatype_commas = ignore # ignore/add/remove/force + +# (C#) Add or remove space between '[' and ',' in multidimensional array type +# like 'int[,,]'. +sp_before_mdatype_commas = ignore # ignore/add/remove/force + +# (C#) Add or remove space between ',' in multidimensional array type +# like 'int[,,]'. +sp_between_mdatype_commas = ignore # ignore/add/remove/force + +# Add or remove space between an open parenthesis and comma, +# i.e. '(,' vs. '( ,'. +# +# Default: force +sp_paren_comma = force # ignore/add/remove/force + +# Add or remove space before the variadic '...' when preceded by a +# non-punctuator. +sp_before_ellipsis = ignore # ignore/add/remove/force + +# Add or remove space between a type and '...'. +sp_type_ellipsis = ignore # ignore/add/remove/force + +# (D) Add or remove space between a type and '?'. +sp_type_question = ignore # ignore/add/remove/force + +# Add or remove space between ')' and '...'. +sp_paren_ellipsis = ignore # ignore/add/remove/force + +# Add or remove space between ')' and a qualifier such as 'const'. +sp_paren_qualifier = ignore # ignore/add/remove/force + +# Add or remove space between ')' and 'noexcept'. +sp_paren_noexcept = ignore # ignore/add/remove/force + +# Add or remove space after class ':'. +sp_after_class_colon = ignore # ignore/add/remove/force + +# Add or remove space before class ':'. +sp_before_class_colon = ignore # ignore/add/remove/force + +# Add or remove space after class constructor ':'. +sp_after_constr_colon = ignore # ignore/add/remove/force + +# Add or remove space before class constructor ':'. +sp_before_constr_colon = ignore # ignore/add/remove/force + +# Add or remove space before case ':'. +# +# Default: remove +sp_before_case_colon = remove # ignore/add/remove/force + +# Add or remove space between 'operator' and operator sign. +sp_after_operator = ignore # ignore/add/remove/force + +# Add or remove space between the operator symbol and the open parenthesis, as +# in 'operator ++('. +sp_after_operator_sym = ignore # ignore/add/remove/force + +# Overrides sp_after_operator_sym when the operator has no arguments, as in +# 'operator *()'. +sp_after_operator_sym_empty = ignore # ignore/add/remove/force + +# Add or remove space after C/D cast, i.e. 'cast(int)a' vs. 'cast(int) a' or +# '(int)a' vs. '(int) a'. +sp_after_cast = ignore # ignore/add/remove/force + +# Add or remove spaces inside cast parentheses. +sp_inside_paren_cast = ignore # ignore/add/remove/force + +# Add or remove space between the type and open parenthesis in a C++ cast, +# i.e. 'int(exp)' vs. 'int (exp)'. +sp_cpp_cast_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'sizeof' and '('. +sp_sizeof_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'sizeof' and '...'. +sp_sizeof_ellipsis = ignore # ignore/add/remove/force + +# Add or remove space between 'sizeof...' and '('. +sp_sizeof_ellipsis_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'decltype' and '('. +sp_decltype_paren = ignore # ignore/add/remove/force + +# (Pawn) Add or remove space after the tag keyword. +sp_after_tag = ignore # ignore/add/remove/force + +# Add or remove space inside enum '{' and '}'. +sp_inside_braces_enum = ignore # ignore/add/remove/force + +# Add or remove space inside struct/union '{' and '}'. +sp_inside_braces_struct = ignore # ignore/add/remove/force + +# (OC) Add or remove space inside Objective-C boxed dictionary '{' and '}' +sp_inside_braces_oc_dict = ignore # ignore/add/remove/force + +# Add or remove space after open brace in an unnamed temporary +# direct-list-initialization. +sp_after_type_brace_init_lst_open = ignore # ignore/add/remove/force + +# Add or remove space before close brace in an unnamed temporary +# direct-list-initialization. +sp_before_type_brace_init_lst_close = ignore # ignore/add/remove/force + +# Add or remove space inside an unnamed temporary direct-list-initialization. +sp_inside_type_brace_init_lst = ignore # ignore/add/remove/force + +# Add or remove space inside '{' and '}'. +sp_inside_braces = ignore # ignore/add/remove/force + +# Add or remove space inside '{}'. +sp_inside_braces_empty = ignore # ignore/add/remove/force + +# Add or remove space between return type and function name. A minimum of 1 +# is forced except for pointer return types. +sp_type_func = ignore # ignore/add/remove/force + +# Add or remove space between type and open brace of an unnamed temporary +# direct-list-initialization. +sp_type_brace_init_lst = ignore # ignore/add/remove/force + +# Add or remove space between function name and '(' on function declaration. +sp_func_proto_paren = ignore # ignore/add/remove/force + +# Add or remove space between function name and '()' on function declaration +# without parameters. +sp_func_proto_paren_empty = ignore # ignore/add/remove/force + +# Add or remove space between function name and '(' on function definition. +sp_func_def_paren = ignore # ignore/add/remove/force + +# Add or remove space between function name and '()' on function definition +# without parameters. +sp_func_def_paren_empty = ignore # ignore/add/remove/force + +# Add or remove space inside empty function '()'. +sp_inside_fparens = ignore # ignore/add/remove/force + +# Add or remove space inside function '(' and ')'. +sp_inside_fparen = ignore # ignore/add/remove/force + +# Add or remove space inside the first parentheses in a function type, as in +# 'void (*x)(...)'. +sp_inside_tparen = ignore # ignore/add/remove/force + +# Add or remove space between the ')' and '(' in a function type, as in +# 'void (*x)(...)'. +sp_after_tparen_close = ignore # ignore/add/remove/force + +# Add or remove space between ']' and '(' when part of a function call. +sp_square_fparen = ignore # ignore/add/remove/force + +# Add or remove space between ')' and '{' of function. +sp_fparen_brace = ignore # ignore/add/remove/force + +# Add or remove space between ')' and '{' of s function call in object +# initialization. +# +# Overrides sp_fparen_brace. +sp_fparen_brace_initializer = ignore # ignore/add/remove/force + +# (Java) Add or remove space between ')' and '{{' of double brace initializer. +sp_fparen_dbrace = ignore # ignore/add/remove/force + +# Add or remove space between function name and '(' on function calls. +sp_func_call_paren = ignore # ignore/add/remove/force + +# Add or remove space between function name and '()' on function calls without +# parameters. If set to 'ignore' (the default), sp_func_call_paren is used. +sp_func_call_paren_empty = ignore # ignore/add/remove/force + +# Add or remove space between the user function name and '(' on function +# calls. You need to set a keyword to be a user function in the config file, +# like: +# set func_call_user tr _ i18n +sp_func_call_user_paren = ignore # ignore/add/remove/force + +# Add or remove space inside user function '(' and ')'. +sp_func_call_user_inside_fparen = ignore # ignore/add/remove/force + +# Add or remove space between nested parentheses with user functions, +# i.e. '((' vs. '( ('. +sp_func_call_user_paren_paren = ignore # ignore/add/remove/force + +# Add or remove space between a constructor/destructor and the open +# parenthesis. +sp_func_class_paren = ignore # ignore/add/remove/force + +# Add or remove space between a constructor without parameters or destructor +# and '()'. +sp_func_class_paren_empty = ignore # ignore/add/remove/force + +# Add or remove space between 'return' and '('. +sp_return_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'return' and '{'. +sp_return_brace = ignore # ignore/add/remove/force + +# Add or remove space between '__attribute__' and '('. +sp_attribute_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'defined' and '(' in '#if defined (FOO)'. +sp_defined_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'throw' and '(' in 'throw (something)'. +sp_throw_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'throw' and anything other than '(' as in +# '@throw [...];'. +sp_after_throw = ignore # ignore/add/remove/force + +# Add or remove space between 'catch' and '(' in 'catch (something) { }'. +# If set to ignore, sp_before_sparen is used. +sp_catch_paren = ignore # ignore/add/remove/force + +# (OC) Add or remove space between '@catch' and '(' +# in '@catch (something) { }'. If set to ignore, sp_catch_paren is used. +sp_oc_catch_paren = ignore # ignore/add/remove/force + +# (OC) Add or remove space between class name and '(' +# in '@interface className(categoryName):BaseClass' +sp_oc_classname_paren = ignore # ignore/add/remove/force + +# (D) Add or remove space between 'version' and '(' +# in 'version (something) { }'. If set to ignore, sp_before_sparen is used. +sp_version_paren = ignore # ignore/add/remove/force + +# (D) Add or remove space between 'scope' and '(' +# in 'scope (something) { }'. If set to ignore, sp_before_sparen is used. +sp_scope_paren = ignore # ignore/add/remove/force + +# Add or remove space between 'super' and '(' in 'super (something)'. +# +# Default: remove +sp_super_paren = remove # ignore/add/remove/force + +# Add or remove space between 'this' and '(' in 'this (something)'. +# +# Default: remove +sp_this_paren = remove # ignore/add/remove/force + +# Add or remove space between a macro name and its definition. +sp_macro = ignore # ignore/add/remove/force + +# Add or remove space between a macro function ')' and its definition. +sp_macro_func = ignore # ignore/add/remove/force + +# Add or remove space between 'else' and '{' if on the same line. +sp_else_brace = ignore # ignore/add/remove/force + +# Add or remove space between '}' and 'else' if on the same line. +sp_brace_else = ignore # ignore/add/remove/force + +# Add or remove space between '}' and the name of a typedef on the same line. +sp_brace_typedef = ignore # ignore/add/remove/force + +# Add or remove space before the '{' of a 'catch' statement, if the '{' and +# 'catch' are on the same line, as in 'catch (decl) {'. +sp_catch_brace = ignore # ignore/add/remove/force + +# (OC) Add or remove space before the '{' of a '@catch' statement, if the '{' +# and '@catch' are on the same line, as in '@catch (decl) {'. +# If set to ignore, sp_catch_brace is used. +sp_oc_catch_brace = ignore # ignore/add/remove/force + +# Add or remove space between '}' and 'catch' if on the same line. +sp_brace_catch = ignore # ignore/add/remove/force + +# (OC) Add or remove space between '}' and '@catch' if on the same line. +# If set to ignore, sp_brace_catch is used. +sp_oc_brace_catch = ignore # ignore/add/remove/force + +# Add or remove space between 'finally' and '{' if on the same line. +sp_finally_brace = ignore # ignore/add/remove/force + +# Add or remove space between '}' and 'finally' if on the same line. +sp_brace_finally = ignore # ignore/add/remove/force + +# Add or remove space between 'try' and '{' if on the same line. +sp_try_brace = ignore # ignore/add/remove/force + +# Add or remove space between get/set and '{' if on the same line. +sp_getset_brace = ignore # ignore/add/remove/force + +# Add or remove space between a variable and '{' for C++ uniform +# initialization. +# +# Default: add +sp_word_brace = add # ignore/add/remove/force + +# Add or remove space between a variable and '{' for a namespace. +# +# Default: add +sp_word_brace_ns = add # ignore/add/remove/force + +# Add or remove space before the '::' operator. +sp_before_dc = ignore # ignore/add/remove/force + +# Add or remove space after the '::' operator. +sp_after_dc = ignore # ignore/add/remove/force + +# (D) Add or remove around the D named array initializer ':' operator. +sp_d_array_colon = ignore # ignore/add/remove/force + +# Add or remove space after the '!' (not) unary operator. +# +# Default: remove +sp_not = remove # ignore/add/remove/force + +# Add or remove space after the '~' (invert) unary operator. +# +# Default: remove +sp_inv = remove # ignore/add/remove/force + +# Add or remove space after the '&' (address-of) unary operator. This does not +# affect the spacing after a '&' that is part of a type. +# +# Default: remove +sp_addr = remove # ignore/add/remove/force + +# Add or remove space around the '.' or '->' operators. +# +# Default: remove +sp_member = remove # ignore/add/remove/force + +# Add or remove space after the '*' (dereference) unary operator. This does +# not affect the spacing after a '*' that is part of a type. +# +# Default: remove +sp_deref = remove # ignore/add/remove/force + +# Add or remove space after '+' or '-', as in 'x = -5' or 'y = +7'. +# +# Default: remove +sp_sign = remove # ignore/add/remove/force + +# Add or remove space between '++' and '--' the word to which it is being +# applied, as in '(--x)' or 'y++;'. +# +# Default: remove +sp_incdec = remove # ignore/add/remove/force + +# Add or remove space before a backslash-newline at the end of a line. +# +# Default: add +sp_before_nl_cont = add # ignore/add/remove/force + +# (OC) Add or remove space after the scope '+' or '-', as in '-(void) foo;' +# or '+(int) bar;'. +sp_after_oc_scope = ignore # ignore/add/remove/force + +# (OC) Add or remove space after the colon in message specs, +# i.e. '-(int) f:(int) x;' vs. '-(int) f: (int) x;'. +sp_after_oc_colon = ignore # ignore/add/remove/force + +# (OC) Add or remove space before the colon in message specs, +# i.e. '-(int) f: (int) x;' vs. '-(int) f : (int) x;'. +sp_before_oc_colon = ignore # ignore/add/remove/force + +# (OC) Add or remove space after the colon in immutable dictionary expression +# 'NSDictionary *test = @{@"foo" :@"bar"};'. +sp_after_oc_dict_colon = ignore # ignore/add/remove/force + +# (OC) Add or remove space before the colon in immutable dictionary expression +# 'NSDictionary *test = @{@"foo" :@"bar"};'. +sp_before_oc_dict_colon = ignore # ignore/add/remove/force + +# (OC) Add or remove space after the colon in message specs, +# i.e. '[object setValue:1];' vs. '[object setValue: 1];'. +sp_after_send_oc_colon = ignore # ignore/add/remove/force + +# (OC) Add or remove space before the colon in message specs, +# i.e. '[object setValue:1];' vs. '[object setValue :1];'. +sp_before_send_oc_colon = ignore # ignore/add/remove/force + +# (OC) Add or remove space after the (type) in message specs, +# i.e. '-(int)f: (int) x;' vs. '-(int)f: (int)x;'. +sp_after_oc_type = ignore # ignore/add/remove/force + +# (OC) Add or remove space after the first (type) in message specs, +# i.e. '-(int) f:(int)x;' vs. '-(int)f:(int)x;'. +sp_after_oc_return_type = ignore # ignore/add/remove/force + +# (OC) Add or remove space between '@selector' and '(', +# i.e. '@selector(msgName)' vs. '@selector (msgName)'. +# Also applies to '@protocol()' constructs. +sp_after_oc_at_sel = ignore # ignore/add/remove/force + +# (OC) Add or remove space between '@selector(x)' and the following word, +# i.e. '@selector(foo) a:' vs. '@selector(foo)a:'. +sp_after_oc_at_sel_parens = ignore # ignore/add/remove/force + +# (OC) Add or remove space inside '@selector' parentheses, +# i.e. '@selector(foo)' vs. '@selector( foo )'. +# Also applies to '@protocol()' constructs. +sp_inside_oc_at_sel_parens = ignore # ignore/add/remove/force + +# (OC) Add or remove space before a block pointer caret, +# i.e. '^int (int arg){...}' vs. ' ^int (int arg){...}'. +sp_before_oc_block_caret = ignore # ignore/add/remove/force + +# (OC) Add or remove space after a block pointer caret, +# i.e. '^int (int arg){...}' vs. '^ int (int arg){...}'. +sp_after_oc_block_caret = ignore # ignore/add/remove/force + +# (OC) Add or remove space between the receiver and selector in a message, +# as in '[receiver selector ...]'. +sp_after_oc_msg_receiver = ignore # ignore/add/remove/force + +# (OC) Add or remove space after '@property'. +sp_after_oc_property = ignore # ignore/add/remove/force + +# (OC) Add or remove space between '@synchronized' and the open parenthesis, +# i.e. '@synchronized(foo)' vs. '@synchronized (foo)'. +sp_after_oc_synchronized = ignore # ignore/add/remove/force + +# Add or remove space around the ':' in 'b ? t : f'. +sp_cond_colon = ignore # ignore/add/remove/force + +# Add or remove space before the ':' in 'b ? t : f'. +# +# Overrides sp_cond_colon. +sp_cond_colon_before = ignore # ignore/add/remove/force + +# Add or remove space after the ':' in 'b ? t : f'. +# +# Overrides sp_cond_colon. +sp_cond_colon_after = ignore # ignore/add/remove/force + +# Add or remove space around the '?' in 'b ? t : f'. +sp_cond_question = ignore # ignore/add/remove/force + +# Add or remove space before the '?' in 'b ? t : f'. +# +# Overrides sp_cond_question. +sp_cond_question_before = ignore # ignore/add/remove/force + +# Add or remove space after the '?' in 'b ? t : f'. +# +# Overrides sp_cond_question. +sp_cond_question_after = ignore # ignore/add/remove/force + +# In the abbreviated ternary form '(a ?: b)', add or remove space between '?' +# and ':'. +# +# Overrides all other sp_cond_* options. +sp_cond_ternary_short = ignore # ignore/add/remove/force + +# Fix the spacing between 'case' and the label. Only 'ignore' and 'force' make +# sense here. +sp_case_label = ignore # ignore/add/remove/force + +# (D) Add or remove space around the D '..' operator. +sp_range = ignore # ignore/add/remove/force + +# Add or remove space after ':' in a Java/C++11 range-based 'for', +# as in 'for (Type var : expr)'. +sp_after_for_colon = ignore # ignore/add/remove/force + +# Add or remove space before ':' in a Java/C++11 range-based 'for', +# as in 'for (Type var : expr)'. +sp_before_for_colon = ignore # ignore/add/remove/force + +# (D) Add or remove space between 'extern' and '(' as in 'extern (C)'. +sp_extern_paren = ignore # ignore/add/remove/force + +# Add or remove space after the opening of a C++ comment, +# i.e. '// A' vs. '//A'. +sp_cmt_cpp_start = ignore # ignore/add/remove/force + +# If true, space is added with sp_cmt_cpp_start will be added after doxygen +# sequences like '///', '///<', '//!' and '//!<'. +sp_cmt_cpp_doxygen = false # true/false + +# If true, space is added with sp_cmt_cpp_start will be added after Qt +# translator or meta-data comments like '//:', '//=', and '//~'. +sp_cmt_cpp_qttr = false # true/false + +# Add or remove space between #else or #endif and a trailing comment. +sp_endif_cmt = ignore # ignore/add/remove/force + +# Add or remove space after 'new', 'delete' and 'delete[]'. +sp_after_new = ignore # ignore/add/remove/force + +# Add or remove space between 'new' and '(' in 'new()'. +sp_between_new_paren = ignore # ignore/add/remove/force + +# Add or remove space between ')' and type in 'new(foo) BAR'. +sp_after_newop_paren = ignore # ignore/add/remove/force + +# Add or remove space inside parenthesis of the new operator +# as in 'new(foo) BAR'. +sp_inside_newop_paren = ignore # ignore/add/remove/force + +# Add or remove space after the open parenthesis of the new operator, +# as in 'new(foo) BAR'. +# +# Overrides sp_inside_newop_paren. +sp_inside_newop_paren_open = ignore # ignore/add/remove/force + +# Add or remove space before the close parenthesis of the new operator, +# as in 'new(foo) BAR'. +# +# Overrides sp_inside_newop_paren. +sp_inside_newop_paren_close = ignore # ignore/add/remove/force + +# Add or remove space before a trailing or embedded comment. +sp_before_tr_emb_cmt = ignore # ignore/add/remove/force + +# Number of spaces before a trailing or embedded comment. +sp_num_before_tr_emb_cmt = 0 # unsigned number + +# (Java) Add or remove space between an annotation and the open parenthesis. +sp_annotation_paren = ignore # ignore/add/remove/force + +# If true, vbrace tokens are dropped to the previous token and skipped. +sp_skip_vbrace_tokens = false # true/false + +# Add or remove space after 'noexcept'. +sp_after_noexcept = ignore # ignore/add/remove/force + +# Add or remove space after '_'. +sp_vala_after_translation = ignore # ignore/add/remove/force + +# If true, a is inserted after #define. +force_tab_after_define = false # true/false + +# +# Indenting options +# + +# The number of columns to indent per level. Usually 2, 3, 4, or 8. +# +# Default: 8 +indent_columns = 4 # unsigned number + +# The continuation indent. If non-zero, this overrides the indent of '(', '[' +# and '=' continuation indents. Negative values are OK; negative value is +# absolute and not increased for each '(' or '[' level. +# +# For FreeBSD, this is set to 4. +indent_continue = 0 # number + +# The continuation indent, only for class header line(s). If non-zero, this +# overrides the indent of 'class' continuation indents. +indent_continue_class_head = 0 # unsigned number + +# Whether to indent empty lines (i.e. lines which contain only spaces before +# the newline character). +indent_single_newlines = false # true/false + +# The continuation indent for func_*_param if they are true. If non-zero, this +# overrides the indent. +indent_param = 0 # unsigned number + +# How to use tabs when indenting code. +# +# 0: Spaces only +# 1: Indent with tabs to brace level, align with spaces (default) +# 2: Indent and align with tabs, using spaces when not on a tabstop +# +# Default: 1 +indent_with_tabs = 0 # unsigned number + +# Whether to indent comments that are not at a brace level with tabs on a +# tabstop. Requires indent_with_tabs=2. If false, will use spaces. +indent_cmt_with_tabs = false # true/false + +# Whether to indent strings broken by '\' so that they line up. +indent_align_string = false # true/false + +# The number of spaces to indent multi-line XML strings. +# Requires indent_align_string=true. +indent_xml_string = 0 # unsigned number + +# Spaces to indent '{' from level. +indent_brace = 0 # unsigned number + +# Whether braces are indented to the body level. +indent_braces = false # true/false + +# Whether to disable indenting function braces if indent_braces=true. +indent_braces_no_func = false # true/false + +# Whether to disable indenting class braces if indent_braces=true. +indent_braces_no_class = false # true/false + +# Whether to disable indenting struct braces if indent_braces=true. +indent_braces_no_struct = false # true/false + +# Whether to indent based on the size of the brace parent, +# i.e. 'if' => 3 spaces, 'for' => 4 spaces, etc. +indent_brace_parent = false # true/false + +# Whether to indent based on the open parenthesis instead of the open brace +# in '({\n'. +indent_paren_open_brace = false # true/false + +# (C#) Whether to indent the brace of a C# delegate by another level. +indent_cs_delegate_brace = false # true/false + +# (C#) Whether to indent a C# delegate (to handle delegates with no brace) by +# another level. +indent_cs_delegate_body = false # true/false + +# Whether to indent the body of a 'namespace'. +indent_namespace = false # true/false + +# Whether to indent only the first namespace, and not any nested namespaces. +# Requires indent_namespace=true. +indent_namespace_single_indent = false # true/false + +# The number of spaces to indent a namespace block. +# If set to zero, use the value indent_columns +indent_namespace_level = 0 # unsigned number + +# If the body of the namespace is longer than this number, it won't be +# indented. Requires indent_namespace=true. 0 means no limit. +indent_namespace_limit = 0 # unsigned number + +# Whether the 'extern "C"' body is indented. +indent_extern = false # true/false + +# Whether the 'class' body is indented. +indent_class = false # true/false + +# Whether to indent the stuff after a leading base class colon. +indent_class_colon = false # true/false + +# Whether to indent based on a class colon instead of the stuff after the +# colon. Requires indent_class_colon=true. +indent_class_on_colon = false # true/false + +# Whether to indent the stuff after a leading class initializer colon. +indent_constr_colon = false # true/false + +# Virtual indent from the ':' for member initializers. +# +# Default: 2 +indent_ctor_init_leading = 2 # unsigned number + +# Additional indent for constructor initializer list. +# Negative values decrease indent down to the first column. +indent_ctor_init = 0 # number + +# Whether to indent 'if' following 'else' as a new block under the 'else'. +# If false, 'else\nif' is treated as 'else if' for indenting purposes. +indent_else_if = false # true/false + +# Amount to indent variable declarations after a open brace. +# +# <0: Relative +# >=0: Absolute +indent_var_def_blk = 0 # number + +# Whether to indent continued variable declarations instead of aligning. +indent_var_def_cont = false # true/false + +# Whether to indent continued shift expressions ('<<' and '>>') instead of +# aligning. Set align_left_shift=false when enabling this. +indent_shift = false # true/false + +# Whether to force indentation of function definitions to start in column 1. +indent_func_def_force_col1 = false # true/false + +# Whether to indent continued function call parameters one indent level, +# rather than aligning parameters under the open parenthesis. +indent_func_call_param = false # true/false + +# Same as indent_func_call_param, but for function definitions. +indent_func_def_param = false # true/false + +# Same as indent_func_call_param, but for function prototypes. +indent_func_proto_param = false # true/false + +# Same as indent_func_call_param, but for class declarations. +indent_func_class_param = false # true/false + +# Same as indent_func_call_param, but for class variable constructors. +indent_func_ctor_var_param = false # true/false + +# Same as indent_func_call_param, but for template parameter lists. +indent_template_param = false # true/false + +# Double the indent for indent_func_xxx_param options. +# Use both values of the options indent_columns and indent_param. +indent_func_param_double = false # true/false + +# Indentation column for standalone 'const' qualifier on a function +# prototype. +indent_func_const = 0 # unsigned number + +# Indentation column for standalone 'throw' qualifier on a function +# prototype. +indent_func_throw = 0 # unsigned number + +# The number of spaces to indent a continued '->' or '.'. +# Usually set to 0, 1, or indent_columns. +indent_member = 0 # unsigned number + +# Whether lines broken at '.' or '->' should be indented by a single indent. +# The indent_member option will not be effective if this is set to true. +indent_member_single = false # true/false + +# Spaces to indent single line ('//') comments on lines before code. +indent_sing_line_comments = 0 # unsigned number + +# Whether to indent trailing single line ('//') comments relative to the code +# instead of trying to keep the same absolute column. +indent_relative_single_line_comments = false # true/false + +# Spaces to indent 'case' from 'switch'. Usually 0 or indent_columns. +indent_switch_case = 0 # unsigned number + +# Whether to indent preprocessor statements inside of switch statements. +# +# Default: true +indent_switch_pp = true # true/false + +# Spaces to shift the 'case' line, without affecting any other lines. +# Usually 0. +indent_case_shift = 0 # unsigned number + +# Spaces to indent '{' from 'case'. By default, the brace will appear under +# the 'c' in case. Usually set to 0 or indent_columns. Negative values are OK. +indent_case_brace = 0 # number + +# Whether to indent comments found in first column. +indent_col1_comment = false # true/false + +# Whether to indent multi string literal in first column. +indent_col1_multi_string_literal = false # true/false + +# How to indent goto labels. +# +# >0: Absolute column where 1 is the leftmost column +# <=0: Subtract from brace indent +# +# Default: 1 +indent_label = 1 # number + +# Same as indent_label, but for access specifiers that are followed by a +# colon. +# +# Default: 1 +indent_access_spec = 1 # number + +# Whether to indent the code after an access specifier by one level. +# If true, this option forces 'indent_access_spec=0'. +indent_access_spec_body = false # true/false + +# If an open parenthesis is followed by a newline, whether to indent the next +# line so that it lines up after the open parenthesis (not recommended). +indent_paren_nl = false # true/false + +# How to indent a close parenthesis after a newline. +# +# 0: Indent to body level (default) +# 1: Align under the open parenthesis +# 2: Indent to the brace level +indent_paren_close = 0 # unsigned number + +# Whether to indent the open parenthesis of a function definition, +# if the parenthesis is on its own line. +indent_paren_after_func_def = false # true/false + +# Whether to indent the open parenthesis of a function declaration, +# if the parenthesis is on its own line. +indent_paren_after_func_decl = false # true/false + +# Whether to indent the open parenthesis of a function call, +# if the parenthesis is on its own line. +indent_paren_after_func_call = false # true/false + +# Whether to indent a comma when inside a parenthesis. +# If true, aligns under the open parenthesis. +indent_comma_paren = false # true/false + +# Whether to indent a Boolean operator when inside a parenthesis. +# If true, aligns under the open parenthesis. +indent_bool_paren = false # true/false + +# Whether to indent a semicolon when inside a for parenthesis. +# If true, aligns under the open for parenthesis. +indent_semicolon_for_paren = false # true/false + +# Whether to align the first expression to following ones +# if indent_bool_paren=true. +indent_first_bool_expr = false # true/false + +# Whether to align the first expression to following ones +# if indent_semicolon_for_paren=true. +indent_first_for_expr = false # true/false + +# If an open square is followed by a newline, whether to indent the next line +# so that it lines up after the open square (not recommended). +indent_square_nl = false # true/false + +# (ESQL/C) Whether to preserve the relative indent of 'EXEC SQL' bodies. +indent_preserve_sql = false # true/false + +# Whether to align continued statements at the '='. If false or if the '=' is +# followed by a newline, the next line is indent one tab. +# +# Default: true +indent_align_assign = true # true/false + +# Whether to align continued statements at the '('. If false or the '(' is +# followed by a newline, the next line indent is one tab. +# +# Default: true +indent_align_paren = true # true/false + +# (OC) Whether to indent Objective-C blocks at brace level instead of usual +# rules. +indent_oc_block = false # true/false + +# (OC) Indent for Objective-C blocks in a message relative to the parameter +# name. +# +# =0: Use indent_oc_block rules +# >0: Use specified number of spaces to indent +indent_oc_block_msg = 0 # unsigned number + +# (OC) Minimum indent for subsequent parameters +indent_oc_msg_colon = 0 # unsigned number + +# (OC) Whether to prioritize aligning with initial colon (and stripping spaces +# from lines, if necessary). +# +# Default: true +indent_oc_msg_prioritize_first_colon = true # true/false + +# (OC) Whether to indent blocks the way that Xcode does by default +# (from the keyword if the parameter is on its own line; otherwise, from the +# previous indentation level). Requires indent_oc_block_msg=true. +indent_oc_block_msg_xcode_style = false # true/false + +# (OC) Whether to indent blocks from where the brace is, relative to a +# message keyword. Requires indent_oc_block_msg=true. +indent_oc_block_msg_from_keyword = false # true/false + +# (OC) Whether to indent blocks from where the brace is, relative to a message +# colon. Requires indent_oc_block_msg=true. +indent_oc_block_msg_from_colon = false # true/false + +# (OC) Whether to indent blocks from where the block caret is. +# Requires indent_oc_block_msg=true. +indent_oc_block_msg_from_caret = false # true/false + +# (OC) Whether to indent blocks from where the brace caret is. +# Requires indent_oc_block_msg=true. +indent_oc_block_msg_from_brace = false # true/false + +# When indenting after virtual brace open and newline add further spaces to +# reach this minimum indent. +indent_min_vbrace_open = 0 # unsigned number + +# Whether to add further spaces after regular indent to reach next tabstop +# when identing after virtual brace open and newline. +indent_vbrace_open_on_tabstop = false # true/false + +# How to indent after a brace followed by another token (not a newline). +# true: indent all contained lines to match the token +# false: indent all contained lines to match the brace +# +# Default: true +indent_token_after_brace = true # true/false + +# Whether to indent the body of a C++11 lambda. +indent_cpp_lambda_body = false # true/false + +# (C#) Whether to indent a 'using' block if no braces are used. +# +# Default: true +indent_using_block = true # true/false + +# How to indent the continuation of ternary operator. +# +# 0: Off (default) +# 1: When the `if_false` is a continuation, indent it under `if_false` +# 2: When the `:` is a continuation, indent it under `?` +indent_ternary_operator = 0 # unsigned number + +# If true, the indentation of the chunks after a `return new` sequence will be set at return indentation column. +indent_off_after_return_new = false # true/false + +# If true, the tokens after return are indented with regular single indentation. By default (false) the indentation is after the return token. +indent_single_after_return = false # true/false + +# Whether to ignore indent and alignment for 'asm' blocks (i.e. assume they +# have their own indentation). +indent_ignore_asm_block = false # true/false + +# +# Newline adding and removing options +# + +# Whether to collapse empty blocks between '{' and '}'. +nl_collapse_empty_body = false # true/false + +# Don't split one-line braced assignments, as in 'foo_t f = { 1, 2 };'. +nl_assign_leave_one_liners = false # true/false + +# Don't split one-line braced statements inside a 'class xx { }' body. +nl_class_leave_one_liners = false # true/false + +# Don't split one-line enums, as in 'enum foo { BAR = 15 };' +nl_enum_leave_one_liners = false # true/false + +# Don't split one-line get or set functions. +nl_getset_leave_one_liners = false # true/false + +# (C#) Don't split one-line property get or set functions. +nl_cs_property_leave_one_liners = false # true/false + +# Don't split one-line function definitions, as in 'int foo() { return 0; }'. +nl_func_leave_one_liners = false # true/false + +# Don't split one-line C++11 lambdas, as in '[]() { return 0; }'. +nl_cpp_lambda_leave_one_liners = false # true/false + +# Don't split one-line if/else statements, as in 'if(...) b++;'. +nl_if_leave_one_liners = false # true/false + +# Don't split one-line while statements, as in 'while(...) b++;'. +nl_while_leave_one_liners = false # true/false + +# Don't split one-line for statements, as in 'for(...) b++;'. +nl_for_leave_one_liners = false # true/false + +# (OC) Don't split one-line Objective-C messages. +nl_oc_msg_leave_one_liner = false # true/false + +# (OC) Add or remove newline between method declaration and '{'. +nl_oc_mdef_brace = ignore # ignore/add/remove/force + +# (OC) Add or remove newline between Objective-C block signature and '{'. +nl_oc_block_brace = ignore # ignore/add/remove/force + +# (OC) Add or remove newline between '@interface' and '{'. +nl_oc_interface_brace = ignore # ignore/add/remove/force + +# (OC) Add or remove newline between '@implementation' and '{'. +nl_oc_implementation_brace = ignore # ignore/add/remove/force + +# Add or remove newlines at the start of the file. +nl_start_of_file = ignore # ignore/add/remove/force + +# The minimum number of newlines at the start of the file (only used if +# nl_start_of_file is 'add' or 'force'). +nl_start_of_file_min = 0 # unsigned number + +# Add or remove newline at the end of the file. +nl_end_of_file = force # ignore/add/remove/force + +# The minimum number of newlines at the end of the file (only used if +# nl_end_of_file is 'add' or 'force'). +nl_end_of_file_min = 1 # unsigned number + +# Add or remove newline between '=' and '{'. +nl_assign_brace = ignore # ignore/add/remove/force + +# (D) Add or remove newline between '=' and '['. +nl_assign_square = ignore # ignore/add/remove/force + +# Add or remove newline between '[]' and '{'. +nl_tsquare_brace = ignore # ignore/add/remove/force + +# (D) Add or remove newline after '= ['. Will also affect the newline before +# the ']'. +nl_after_square_assign = ignore # ignore/add/remove/force + +# Add or remove newline between a function call's ')' and '{', as in +# 'list_for_each(item, &list) { }'. +nl_fcall_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'enum' and '{'. +nl_enum_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'enum' and 'class'. +nl_enum_class = ignore # ignore/add/remove/force + +# Add or remove newline between 'enum class' and the identifier. +nl_enum_class_identifier = ignore # ignore/add/remove/force + +# Add or remove newline between 'enum class' type and ':'. +nl_enum_identifier_colon = ignore # ignore/add/remove/force + +# Add or remove newline between 'enum class identifier :' and type. +nl_enum_colon_type = ignore # ignore/add/remove/force + +# Add or remove newline between 'struct and '{'. +nl_struct_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'union' and '{'. +nl_union_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'if' and '{'. +nl_if_brace = ignore # ignore/add/remove/force + +# Add or remove newline between '}' and 'else'. +nl_brace_else = ignore # ignore/add/remove/force + +# Add or remove newline between 'else if' and '{'. If set to ignore, +# nl_if_brace is used instead. +nl_elseif_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'else' and '{'. +nl_else_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'else' and 'if'. +nl_else_if = ignore # ignore/add/remove/force + +# Add or remove newline before 'if'/'else if' closing parenthesis. +nl_before_if_closing_paren = ignore # ignore/add/remove/force + +# Add or remove newline between '}' and 'finally'. +nl_brace_finally = ignore # ignore/add/remove/force + +# Add or remove newline between 'finally' and '{'. +nl_finally_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'try' and '{'. +nl_try_brace = ignore # ignore/add/remove/force + +# Add or remove newline between get/set and '{'. +nl_getset_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'for' and '{'. +nl_for_brace = ignore # ignore/add/remove/force + +# Add or remove newline before the '{' of a 'catch' statement, as in +# 'catch (decl) {'. +nl_catch_brace = ignore # ignore/add/remove/force + +# (OC) Add or remove newline before the '{' of a '@catch' statement, as in +# '@catch (decl) {'. If set to ignore, nl_catch_brace is used. +nl_oc_catch_brace = ignore # ignore/add/remove/force + +# Add or remove newline between '}' and 'catch'. +nl_brace_catch = ignore # ignore/add/remove/force + +# (OC) Add or remove newline between '}' and '@catch'. If set to ignore, +# nl_brace_catch is used. +nl_oc_brace_catch = ignore # ignore/add/remove/force + +# Add or remove newline between '}' and ']'. +nl_brace_square = ignore # ignore/add/remove/force + +# Add or remove newline between '}' and ')' in a function invocation. +nl_brace_fparen = ignore # ignore/add/remove/force + +# Add or remove newline between 'while' and '{'. +nl_while_brace = ignore # ignore/add/remove/force + +# (D) Add or remove newline between 'scope (x)' and '{'. +nl_scope_brace = ignore # ignore/add/remove/force + +# (D) Add or remove newline between 'unittest' and '{'. +nl_unittest_brace = ignore # ignore/add/remove/force + +# (D) Add or remove newline between 'version (x)' and '{'. +nl_version_brace = ignore # ignore/add/remove/force + +# (C#) Add or remove newline between 'using' and '{'. +nl_using_brace = ignore # ignore/add/remove/force + +# Add or remove newline between two open or close braces. Due to general +# newline/brace handling, REMOVE may not work. +nl_brace_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'do' and '{'. +nl_do_brace = ignore # ignore/add/remove/force + +# Add or remove newline between '}' and 'while' of 'do' statement. +nl_brace_while = ignore # ignore/add/remove/force + +# Add or remove newline between 'switch' and '{'. +nl_switch_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'synchronized' and '{'. +nl_synchronized_brace = ignore # ignore/add/remove/force + +# Add a newline between ')' and '{' if the ')' is on a different line than the +# if/for/etc. +# +# Overrides nl_for_brace, nl_if_brace, nl_switch_brace, nl_while_switch and +# nl_catch_brace. +nl_multi_line_cond = false # true/false + +# Force a newline in a define after the macro name for multi-line defines. +nl_multi_line_define = false # true/false + +# Whether to add a newline before 'case', and a blank line before a 'case' +# statement that follows a ';' or '}'. +nl_before_case = false # true/false + +# Whether to add a newline after a 'case' statement. +nl_after_case = false # true/false + +# Add or remove newline between a case ':' and '{'. +# +# Overrides nl_after_case. +nl_case_colon_brace = ignore # ignore/add/remove/force + +# Add or remove newline between ')' and 'throw'. +nl_before_throw = ignore # ignore/add/remove/force + +# Add or remove newline between 'namespace' and '{'. +nl_namespace_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'template<>' and whatever follows. +nl_template_class = ignore # ignore/add/remove/force + +# Add or remove newline between 'class' and '{'. +nl_class_brace = ignore # ignore/add/remove/force + +# Add or remove newline before or after (depending on pos_class_comma, +# may not be IGNORE) each',' in the base class list. +nl_class_init_args = ignore # ignore/add/remove/force + +# Add or remove newline after each ',' in the constructor member +# initialization. Related to nl_constr_colon, pos_constr_colon and +# pos_constr_comma. +nl_constr_init_args = ignore # ignore/add/remove/force + +# Add or remove newline before first element, after comma, and after last +# element, in 'enum'. +nl_enum_own_lines = ignore # ignore/add/remove/force + +# Add or remove newline between return type and function name in a function +# definition. +nl_func_type_name = ignore # ignore/add/remove/force + +# Add or remove newline between return type and function name inside a class +# definition. If set to ignore, nl_func_type_name or nl_func_proto_type_name +# is used instead. +nl_func_type_name_class = ignore # ignore/add/remove/force + +# Add or remove newline between class specification and '::' +# in 'void A::f() { }'. Only appears in separate member implementation (does +# not appear with in-line implementation). +nl_func_class_scope = ignore # ignore/add/remove/force + +# Add or remove newline between function scope and name, as in +# 'void A :: f() { }'. +nl_func_scope_name = ignore # ignore/add/remove/force + +# Add or remove newline between return type and function name in a prototype. +nl_func_proto_type_name = ignore # ignore/add/remove/force + +# Add or remove newline between a function name and the opening '(' in the +# declaration. +nl_func_paren = ignore # ignore/add/remove/force + +# Overrides nl_func_paren for functions with no parameters. +nl_func_paren_empty = ignore # ignore/add/remove/force + +# Add or remove newline between a function name and the opening '(' in the +# definition. +nl_func_def_paren = ignore # ignore/add/remove/force + +# Overrides nl_func_def_paren for functions with no parameters. +nl_func_def_paren_empty = ignore # ignore/add/remove/force + +# Add or remove newline between a function name and the opening '(' in the +# call. +nl_func_call_paren = ignore # ignore/add/remove/force + +# Overrides nl_func_call_paren for functions with no parameters. +nl_func_call_paren_empty = ignore # ignore/add/remove/force + +# Add or remove newline after '(' in a function declaration. +nl_func_decl_start = ignore # ignore/add/remove/force + +# Add or remove newline after '(' in a function definition. +nl_func_def_start = ignore # ignore/add/remove/force + +# Overrides nl_func_decl_start when there is only one parameter. +nl_func_decl_start_single = ignore # ignore/add/remove/force + +# Overrides nl_func_def_start when there is only one parameter. +nl_func_def_start_single = ignore # ignore/add/remove/force + +# Whether to add a newline after '(' in a function declaration if '(' and ')' +# are in different lines. If false, nl_func_decl_start is used instead. +nl_func_decl_start_multi_line = false # true/false + +# Whether to add a newline after '(' in a function definition if '(' and ')' +# are in different lines. If false, nl_func_def_start is used instead. +nl_func_def_start_multi_line = false # true/false + +# Add or remove newline after each ',' in a function declaration. +nl_func_decl_args = ignore # ignore/add/remove/force + +# Add or remove newline after each ',' in a function definition. +nl_func_def_args = ignore # ignore/add/remove/force + +# Whether to add a newline after each ',' in a function declaration if '(' +# and ')' are in different lines. If false, nl_func_decl_args is used instead. +nl_func_decl_args_multi_line = false # true/false + +# Whether to add a newline after each ',' in a function definition if '(' +# and ')' are in different lines. If false, nl_func_def_args is used instead. +nl_func_def_args_multi_line = false # true/false + +# Add or remove newline before the ')' in a function declaration. +nl_func_decl_end = ignore # ignore/add/remove/force + +# Add or remove newline before the ')' in a function definition. +nl_func_def_end = ignore # ignore/add/remove/force + +# Overrides nl_func_decl_end when there is only one parameter. +nl_func_decl_end_single = ignore # ignore/add/remove/force + +# Overrides nl_func_def_end when there is only one parameter. +nl_func_def_end_single = ignore # ignore/add/remove/force + +# Whether to add a newline before ')' in a function declaration if '(' and ')' +# are in different lines. If false, nl_func_decl_end is used instead. +nl_func_decl_end_multi_line = false # true/false + +# Whether to add a newline before ')' in a function definition if '(' and ')' +# are in different lines. If false, nl_func_def_end is used instead. +nl_func_def_end_multi_line = false # true/false + +# Add or remove newline between '()' in a function declaration. +nl_func_decl_empty = ignore # ignore/add/remove/force + +# Add or remove newline between '()' in a function definition. +nl_func_def_empty = ignore # ignore/add/remove/force + +# Add or remove newline between '()' in a function call. +nl_func_call_empty = ignore # ignore/add/remove/force + +# Whether to add a newline after '(' in a function call, +# has preference over nl_func_call_start_multi_line. +nl_func_call_start = ignore # ignore/add/remove/force + +# Whether to add a newline after '(' in a function call if '(' and ')' are in +# different lines. +nl_func_call_start_multi_line = false # true/false + +# Whether to add a newline after each ',' in a function call if '(' and ')' +# are in different lines. +nl_func_call_args_multi_line = false # true/false + +# Whether to add a newline before ')' in a function call if '(' and ')' are in +# different lines. +nl_func_call_end_multi_line = false # true/false + +# (OC) Whether to put each Objective-C message parameter on a separate line. +# See nl_oc_msg_leave_one_liner. +nl_oc_msg_args = false # true/false + +# Add or remove newline between function signature and '{'. +nl_fdef_brace = ignore # ignore/add/remove/force + +# Add or remove newline between function signature and '{', +# if signature ends with ')'. Overrides nl_fdef_brace. +nl_fdef_brace_cond = ignore # ignore/add/remove/force + +# Add or remove newline between C++11 lambda signature and '{'. +nl_cpp_ldef_brace = ignore # ignore/add/remove/force + +# Add or remove newline between 'return' and the return expression. +nl_return_expr = ignore # ignore/add/remove/force + +# Whether to add a newline after semicolons, except in 'for' statements. +nl_after_semicolon = false # true/false + +# (Java) Add or remove newline between the ')' and '{{' of the double brace +# initializer. +nl_paren_dbrace_open = ignore # ignore/add/remove/force + +# Whether to add a newline after the type in an unnamed temporary +# direct-list-initialization. +nl_type_brace_init_lst = ignore # ignore/add/remove/force + +# Whether to add a newline after the open brace in an unnamed temporary +# direct-list-initialization. +nl_type_brace_init_lst_open = ignore # ignore/add/remove/force + +# Whether to add a newline before the close brace in an unnamed temporary +# direct-list-initialization. +nl_type_brace_init_lst_close = ignore # ignore/add/remove/force + +# Whether to add a newline after '{'. This also adds a newline before the +# matching '}'. +nl_after_brace_open = false # true/false + +# Whether to add a newline between the open brace and a trailing single-line +# comment. Requires nl_after_brace_open=true. +nl_after_brace_open_cmt = false # true/false + +# Whether to add a newline after a virtual brace open with a non-empty body. +# These occur in un-braced if/while/do/for statement bodies. +nl_after_vbrace_open = false # true/false + +# Whether to add a newline after a virtual brace open with an empty body. +# These occur in un-braced if/while/do/for statement bodies. +nl_after_vbrace_open_empty = false # true/false + +# Whether to add a newline after '}'. Does not apply if followed by a +# necessary ';'. +nl_after_brace_close = false # true/false + +# Whether to add a newline after a virtual brace close, +# as in 'if (foo) a++; return;'. +nl_after_vbrace_close = false # true/false + +# Add or remove newline between the close brace and identifier, +# as in 'struct { int a; } b;'. Affects enumerations, unions and +# structures. If set to ignore, uses nl_after_brace_close. +nl_brace_struct_var = ignore # ignore/add/remove/force + +# Whether to alter newlines in '#define' macros. +nl_define_macro = false # true/false + +# Whether to alter newlines between consecutive parenthesis closes. The number +# of closing parentheses in a line will depend on respective open parenthesis +# lines. +nl_squeeze_paren_close = false # true/false + +# Whether to remove blanks after '#ifxx' and '#elxx', or before '#elxx' and +# '#endif'. Does not affect top-level #ifdefs. +nl_squeeze_ifdef = false # true/false + +# Makes the nl_squeeze_ifdef option affect the top-level #ifdefs as well. +nl_squeeze_ifdef_top_level = false # true/false + +# Add or remove blank line before 'if'. +nl_before_if = ignore # ignore/add/remove/force + +# Add or remove blank line after 'if' statement. Add/Force work only if the +# next token is not a closing brace. +nl_after_if = ignore # ignore/add/remove/force + +# Add or remove blank line before 'for'. +nl_before_for = ignore # ignore/add/remove/force + +# Add or remove blank line after 'for' statement. +nl_after_for = ignore # ignore/add/remove/force + +# Add or remove blank line before 'while'. +nl_before_while = ignore # ignore/add/remove/force + +# Add or remove blank line after 'while' statement. +nl_after_while = ignore # ignore/add/remove/force + +# Add or remove blank line before 'switch'. +nl_before_switch = ignore # ignore/add/remove/force + +# Add or remove blank line after 'switch' statement. +nl_after_switch = ignore # ignore/add/remove/force + +# Add or remove blank line before 'synchronized'. +nl_before_synchronized = ignore # ignore/add/remove/force + +# Add or remove blank line after 'synchronized' statement. +nl_after_synchronized = ignore # ignore/add/remove/force + +# Add or remove blank line before 'do'. +nl_before_do = ignore # ignore/add/remove/force + +# Add or remove blank line after 'do/while' statement. +nl_after_do = ignore # ignore/add/remove/force + +# Whether to put a blank line before 'return' statements, unless after an open +# brace. +nl_before_return = false # true/false + +# Whether to put a blank line after 'return' statements, unless followed by a +# close brace. +nl_after_return = false # true/false + +# Whether to double-space commented-entries in 'struct'/'union'/'enum'. +nl_ds_struct_enum_cmt = false # true/false + +# Whether to force a newline before '}' of a 'struct'/'union'/'enum'. +# (Lower priority than eat_blanks_before_close_brace.) +nl_ds_struct_enum_close_brace = false # true/false + +# Add or remove newline before or after (depending on pos_class_colon) a class +# colon, as in 'class Foo : public Bar'. +nl_class_colon = ignore # ignore/add/remove/force + +# Add or remove newline around a class constructor colon. The exact position +# depends on nl_constr_init_args, pos_constr_colon and pos_constr_comma. +nl_constr_colon = ignore # ignore/add/remove/force + +# Whether to collapse a two-line namespace, like 'namespace foo\n{ decl; }' +# into a single line. If true, prevents other brace newline rules from turning +# such code into four lines. +nl_namespace_two_to_one_liner = false # true/false + +# Whether to remove a newline in simple unbraced if statements, turning them +# into one-liners, as in 'if(b)\n i++;' => 'if(b) i++;'. +nl_create_if_one_liner = false # true/false + +# Whether to remove a newline in simple unbraced for statements, turning them +# into one-liners, as in 'for (...)\n stmt;' => 'for (...) stmt;'. +nl_create_for_one_liner = false # true/false + +# Whether to remove a newline in simple unbraced while statements, turning +# them into one-liners, as in 'while (expr)\n stmt;' => 'while (expr) stmt;'. +nl_create_while_one_liner = false # true/false + +# Whether to collapse a function definition whose body (not counting braces) +# is only one line so that the entire definition (prototype, braces, body) is +# a single line. +nl_create_func_def_one_liner = false # true/false + +# Whether to split one-line simple unbraced if statements into two lines by +# adding a newline, as in 'if(b) i++;'. +nl_split_if_one_liner = false # true/false + +# Whether to split one-line simple unbraced for statements into two lines by +# adding a newline, as in 'for (...) stmt;'. +nl_split_for_one_liner = false # true/false + +# Whether to split one-line simple unbraced while statements into two lines by +# adding a newline, as in 'while (expr) stmt;'. +nl_split_while_one_liner = false # true/false + +# +# Blank line options +# + +# The maximum number of consecutive newlines (3 = 2 blank lines). +nl_max = 0 # unsigned number + +# The maximum number of consecutive newlines in a function. +nl_max_blank_in_func = 0 # unsigned number + +# The number of newlines before a function prototype. +nl_before_func_body_proto = 0 # unsigned number + +# The number of newlines before a multi-line function definition. +nl_before_func_body_def = 0 # unsigned number + +# The number of newlines before a class constructor/destructor prototype. +nl_before_func_class_proto = 0 # unsigned number + +# The number of newlines before a class constructor/destructor definition. +nl_before_func_class_def = 0 # unsigned number + +# The number of newlines after a function prototype. +nl_after_func_proto = 0 # unsigned number + +# The number of newlines after a function prototype, if not followed by +# another function prototype. +nl_after_func_proto_group = 0 # unsigned number + +# The number of newlines after a class constructor/destructor prototype. +nl_after_func_class_proto = 0 # unsigned number + +# The number of newlines after a class constructor/destructor prototype, +# if not followed by another constructor/destructor prototype. +nl_after_func_class_proto_group = 0 # unsigned number + +# Whether one-line method definitions inside a class body should be treated +# as if they were prototypes for the purposes of adding newlines. +# +# Requires nl_class_leave_one_liners=true. Overrides nl_before_func_body_def +# and nl_before_func_class_def for one-liners. +nl_class_leave_one_liner_groups = false # true/false + +# The number of newlines after '}' of a multi-line function body. +nl_after_func_body = 0 # unsigned number + +# The number of newlines after '}' of a multi-line function body in a class +# declaration. Also affects class constructors/destructors. +# +# Overrides nl_after_func_body. +nl_after_func_body_class = 0 # unsigned number + +# The number of newlines after '}' of a single line function body. Also +# affects class constructors/destructors. +# +# Overrides nl_after_func_body and nl_after_func_body_class. +nl_after_func_body_one_liner = 0 # unsigned number + +# The number of blank lines after a block of variable definitions at the top +# of a function body. +# +# 0 = No change (default). +nl_func_var_def_blk = 0 # unsigned number + +# The number of newlines before a block of typedefs. If nl_after_access_spec +# is non-zero, that option takes precedence. +# +# 0 = No change (default). +nl_typedef_blk_start = 0 # unsigned number + +# The number of newlines after a block of typedefs. +# +# 0 = No change (default). +nl_typedef_blk_end = 0 # unsigned number + +# The maximum number of consecutive newlines within a block of typedefs. +# +# 0 = No change (default). +nl_typedef_blk_in = 0 # unsigned number + +# The number of newlines before a block of variable definitions not at the top +# of a function body. If nl_after_access_spec is non-zero, that option takes +# precedence. +# +# 0 = No change (default). +nl_var_def_blk_start = 0 # unsigned number + +# The number of newlines after a block of variable definitions not at the top +# of a function body. +# +# 0 = No change (default). +nl_var_def_blk_end = 0 # unsigned number + +# The maximum number of consecutive newlines within a block of variable +# definitions. +# +# 0 = No change (default). +nl_var_def_blk_in = 0 # unsigned number + +# The minimum number of newlines before a multi-line comment. +# Doesn't apply if after a brace open or another multi-line comment. +nl_before_block_comment = 0 # unsigned number + +# The minimum number of newlines before a single-line C comment. +# Doesn't apply if after a brace open or other single-line C comments. +nl_before_c_comment = 0 # unsigned number + +# The minimum number of newlines before a CPP comment. +# Doesn't apply if after a brace open or other CPP comments. +nl_before_cpp_comment = 0 # unsigned number + +# Whether to force a newline after a multi-line comment. +nl_after_multiline_comment = false # true/false + +# Whether to force a newline after a label's colon. +nl_after_label_colon = false # true/false + +# The number of newlines after '}' or ';' of a struct/enum/union definition. +nl_after_struct = 0 # unsigned number + +# The number of newlines before a class definition. +nl_before_class = 0 # unsigned number + +# The number of newlines after '}' or ';' of a class definition. +nl_after_class = 0 # unsigned number + +# The number of newlines before an access specifier label. This also includes +# the Qt-specific 'signals:' and 'slots:'. Will not change the newline count +# if after a brace open. +# +# 0 = No change (default). +nl_before_access_spec = 0 # unsigned number + +# The number of newlines after an access specifier label. This also includes +# the Qt-specific 'signals:' and 'slots:'. Will not change the newline count +# if after a brace open. +# +# 0 = No change (default). +# +# Overrides nl_typedef_blk_start and nl_var_def_blk_start. +nl_after_access_spec = 0 # unsigned number + +# The number of newlines between a function definition and the function +# comment, as in '// comment\n void foo() {...}'. +# +# 0 = No change (default). +nl_comment_func_def = 0 # unsigned number + +# The number of newlines after a try-catch-finally block that isn't followed +# by a brace close. +# +# 0 = No change (default). +nl_after_try_catch_finally = 0 # unsigned number + +# (C#) The number of newlines before and after a property, indexer or event +# declaration. +# +# 0 = No change (default). +nl_around_cs_property = 0 # unsigned number + +# (C#) The number of newlines between the get/set/add/remove handlers. +# +# 0 = No change (default). +nl_between_get_set = 0 # unsigned number + +# (C#) Add or remove newline between property and the '{'. +nl_property_brace = ignore # ignore/add/remove/force + +# The number of newlines after '{' of a namespace. This also adds newlines +# before the matching '}'. +# +# 0 = Apply eat_blanks_after_open_brace or eat_blanks_before_close_brace if +# applicable, otherwise no change. +# +# Overrides eat_blanks_after_open_brace and eat_blanks_before_close_brace. +nl_inside_namespace = 0 # unsigned number + +# Whether to remove blank lines after '{'. +eat_blanks_after_open_brace = false # true/false + +# Whether to remove blank lines before '}'. +eat_blanks_before_close_brace = false # true/false + +# How aggressively to remove extra newlines not in preprocessor. +# +# 0: No change (default) +# 1: Remove most newlines not handled by other config +# 2: Remove all newlines and reformat completely by config +nl_remove_extra_newlines = 0 # unsigned number + +# (Java) Add or remove newline after an annotation statement. Only affects +# annotations that are after a newline. +nl_after_annotation = ignore # ignore/add/remove/force + +# (Java) Add or remove newline between two annotations. +nl_between_annotation = ignore # ignore/add/remove/force + +# +# Positioning options +# + +# The position of arithmetic operators in wrapped expressions. +pos_arith = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of assignment in wrapped expressions. Do not affect '=' +# followed by '{'. +pos_assign = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of Boolean operators in wrapped expressions. +pos_bool = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of comparison operators in wrapped expressions. +pos_compare = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of conditional operators, as in the '?' and ':' of +# 'expr ? stmt : stmt', in wrapped expressions. +pos_conditional = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of the comma in wrapped expressions. +pos_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of the comma in enum entries. +pos_enum_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of the comma in the base class list if there is more than one +# line. Affects nl_class_init_args. +pos_class_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of the comma in the constructor initialization list. +# Related to nl_constr_colon, nl_constr_init_args and pos_constr_colon. +pos_constr_comma = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of trailing/leading class colon, between class and base class +# list. Affects nl_class_colon. +pos_class_colon = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# The position of colons between constructor and member initialization. +# Related to nl_constr_colon, nl_constr_init_args and pos_constr_comma. +pos_constr_colon = ignore # ignore/break/force/lead/trail/join/lead_break/lead_force/trail_break/trail_force + +# +# Line splitting options +# + +# Try to limit code width to N columns. +code_width = 100 # unsigned number + +# Whether to fully split long 'for' statements at semi-colons. +ls_for_split_full = false # true/false + +# Whether to fully split long function prototypes/calls at commas. +# The option ls_code_width has priority over the option ls_func_split_full. +ls_func_split_full = false # true/false + +# Whether to split lines as close to code_width as possible and ignore some +# groupings. +# The option ls_code_width has priority over the option ls_func_split_full. +ls_code_width = false # true/false + +# +# Code alignment options (not left column spaces/tabs) +# + +# Whether to keep non-indenting tabs. +align_keep_tabs = false # true/false + +# Whether to use tabs for aligning. +align_with_tabs = false # true/false + +# Whether to bump out to the next tab when aligning. +align_on_tabstop = false # true/false + +# Whether to right-align numbers. +align_number_right = false # true/false + +# Whether to keep whitespace not required for alignment. +align_keep_extra_space = false # true/false + +# Whether to align variable definitions in prototypes and functions. +align_func_params = false # true/false + +# The span for aligning parameter definitions in function on parameter name. +# +# 0 = Don't align (default). +align_func_params_span = 0 # unsigned number + +# The threshold for aligning function parameter definitions. +# Use a negative number for absolute thresholds. +# +# 0 = No limit (default). +align_func_params_thresh = 0 # number + +# The gap for aligning function parameter definitions. +align_func_params_gap = 0 # unsigned number + +# The span for aligning constructor value. +# +# 0 = Don't align (default). +align_constr_value_span = 0 # unsigned number + +# The threshold for aligning constructor value. +# Use a negative number for absolute thresholds. +# +# 0 = No limit (default). +align_constr_value_thresh = 0 # number + +# The gap for aligning constructor value. +align_constr_value_gap = 0 # unsigned number + +# Whether to align parameters in single-line functions that have the same +# name. The function names must already be aligned with each other. +align_same_func_call_params = false # true/false + +# The span for aligning function-call parameters for single line functions. +# +# 0 = Don't align (default). +align_same_func_call_params_span = 0 # unsigned number + +# The threshold for aligning function-call parameters for single line +# functions. +# Use a negative number for absolute thresholds. +# +# 0 = No limit (default). +align_same_func_call_params_thresh = 0 # number + +# The span for aligning variable definitions. +# +# 0 = Don't align (default). +align_var_def_span = 0 # unsigned number + +# How to consider (or treat) the '*' in the alignment of variable definitions. +# +# 0: Part of the type 'void * foo;' (default) +# 1: Part of the variable 'void *foo;' +# 2: Dangling 'void *foo;' +# Dangling: the '*' will not be taken into account when aligning. +align_var_def_star_style = 0 # unsigned number + +# How to consider (or treat) the '&' in the alignment of variable definitions. +# +# 0: Part of the type 'long & foo;' (default) +# 1: Part of the variable 'long &foo;' +# 2: Dangling 'long &foo;' +# Dangling: the '&' will not be taken into account when aligning. +align_var_def_amp_style = 0 # unsigned number + +# The threshold for aligning variable definitions. +# Use a negative number for absolute thresholds. +# +# 0 = No limit (default). +align_var_def_thresh = 0 # number + +# The gap for aligning variable definitions. +align_var_def_gap = 0 # unsigned number + +# Whether to align the colon in struct bit fields. +align_var_def_colon = false # true/false + +# The gap for aligning the colon in struct bit fields. +align_var_def_colon_gap = 0 # unsigned number + +# Whether to align any attribute after the variable name. +align_var_def_attribute = false # true/false + +# Whether to align inline struct/enum/union variable definitions. +align_var_def_inline = false # true/false + +# The span for aligning on '=' in assignments. +# +# 0 = Don't align (default). +align_assign_span = 0 # unsigned number + +# The span for aligning on '=' in function prototype modifier. +# +# 0 = Don't align (default). +align_assign_func_proto_span = 0 # unsigned number + +# The threshold for aligning on '=' in assignments. +# Use a negative number for absolute thresholds. +# +# 0 = No limit (default). +align_assign_thresh = 0 # number + +# How to apply align_assign_span to function declaration "assignments", i.e. +# 'virtual void foo() = 0' or '~foo() = {default|delete}'. +# +# 0: Align with other assignments (default) +# 1: Align with each other, ignoring regular assignments +# 2: Don't align +align_assign_decl_func = 0 # unsigned number + +# The span for aligning on '=' in enums. +# +# 0 = Don't align (default). +align_enum_equ_span = 0 # unsigned number + +# The threshold for aligning on '=' in enums. +# Use a negative number for absolute thresholds. +# +# 0 = no limit (default). +align_enum_equ_thresh = 0 # number + +# The span for aligning class member definitions. +# +# 0 = Don't align (default). +align_var_class_span = 0 # unsigned number + +# The threshold for aligning class member definitions. +# Use a negative number for absolute thresholds. +# +# 0 = No limit (default). +align_var_class_thresh = 0 # number + +# The gap for aligning class member definitions. +align_var_class_gap = 0 # unsigned number + +# The span for aligning struct/union member definitions. +# +# 0 = Don't align (default). +align_var_struct_span = 0 # unsigned number + +# The threshold for aligning struct/union member definitions. +# Use a negative number for absolute thresholds. +# +# 0 = No limit (default). +align_var_struct_thresh = 0 # number + +# The gap for aligning struct/union member definitions. +align_var_struct_gap = 0 # unsigned number + +# The span for aligning struct initializer values. +# +# 0 = Don't align (default). +align_struct_init_span = 0 # unsigned number + +# The span for aligning single-line typedefs. +# +# 0 = Don't align (default). +align_typedef_span = 0 # unsigned number + +# The minimum space between the type and the synonym of a typedef. +align_typedef_gap = 0 # unsigned number + +# How to align typedef'd functions with other typedefs. +# +# 0: Don't mix them at all (default) +# 1: Align the open parenthesis with the types +# 2: Align the function type name with the other type names +align_typedef_func = 0 # unsigned number + +# How to consider (or treat) the '*' in the alignment of typedefs. +# +# 0: Part of the typedef type, 'typedef int * pint;' (default) +# 1: Part of type name: 'typedef int *pint;' +# 2: Dangling: 'typedef int *pint;' +# Dangling: the '*' will not be taken into account when aligning. +align_typedef_star_style = 0 # unsigned number + +# How to consider (or treat) the '&' in the alignment of typedefs. +# +# 0: Part of the typedef type, 'typedef int & intref;' (default) +# 1: Part of type name: 'typedef int &intref;' +# 2: Dangling: 'typedef int &intref;' +# Dangling: the '&' will not be taken into account when aligning. +align_typedef_amp_style = 0 # unsigned number + +# The span for aligning comments that end lines. +# +# 0 = Don't align (default). +align_right_cmt_span = 0 # unsigned number + +# Minimum number of columns between preceding text and a trailing comment in +# order for the comment to qualify for being aligned. Must be non-zero to have +# an effect. +align_right_cmt_gap = 0 # unsigned number + +# If aligning comments, whether to mix with comments after '}' and #endif with +# less than three spaces before the comment. +align_right_cmt_mix = false # true/false + +# Whether to only align trailing comments that are at the same brace level. +align_right_cmt_same_level = false # true/false + +# Minimum column at which to align trailing comments. Comments which are +# aligned beyond this column, but which can be aligned in a lesser column, +# may be "pulled in". +# +# 0 = Ignore (default). +align_right_cmt_at_col = 0 # unsigned number + +# The span for aligning function prototypes. +# +# 0 = Don't align (default). +align_func_proto_span = 0 # unsigned number + +# The threshold for aligning function prototypes. +# Use a negative number for absolute thresholds. +# +# 0 = No limit (default). +align_func_proto_thresh = 0 # number + +# Minimum gap between the return type and the function name. +align_func_proto_gap = 0 # unsigned number + +# Whether to align function prototypes on the 'operator' keyword instead of +# what follows. +align_on_operator = false # true/false + +# Whether to mix aligning prototype and variable declarations. If true, +# align_var_def_XXX options are used instead of align_func_proto_XXX options. +align_mix_var_proto = false # true/false + +# Whether to align single-line functions with function prototypes. +# Uses align_func_proto_span. +align_single_line_func = false # true/false + +# Whether to align the open brace of single-line functions. +# Requires align_single_line_func=true. Uses align_func_proto_span. +align_single_line_brace = false # true/false + +# Gap for align_single_line_brace. +align_single_line_brace_gap = 0 # unsigned number + +# (OC) The span for aligning Objective-C message specifications. +# +# 0 = Don't align (default). +align_oc_msg_spec_span = 0 # unsigned number + +# Whether to align macros wrapped with a backslash and a newline. This will +# not work right if the macro contains a multi-line comment. +align_nl_cont = false # true/false + +# Whether to align macro functions and variables together. +align_pp_define_together = false # true/false + +# The span for aligning on '#define' bodies. +# +# =0: Don't align (default) +# >0: Number of lines (including comments) between blocks +align_pp_define_span = 0 # unsigned number + +# The minimum space between label and value of a preprocessor define. +align_pp_define_gap = 0 # unsigned number + +# Whether to align lines that start with '<<' with previous '<<'. +# +# Default: true +align_left_shift = true # true/false + +# Whether to align text after 'asm volatile ()' colons. +align_asm_colon = false # true/false + +# (OC) Span for aligning parameters in an Objective-C message call +# on the ':'. +# +# 0 = Don't align. +align_oc_msg_colon_span = 0 # unsigned number + +# (OC) Whether to always align with the first parameter, even if it is too +# short. +align_oc_msg_colon_first = false # true/false + +# (OC) Whether to align parameters in an Objective-C '+' or '-' declaration +# on the ':'. +align_oc_decl_colon = false # true/false + +# +# Comment modification options +# + +# Try to wrap comments at N columns. +cmt_width = 0 # unsigned number + +# How to reflow comments. +# +# 0: No reflowing (apart from the line wrapping due to cmt_width) (default) +# 1: No touching at all +# 2: Full reflow +cmt_reflow_mode = 0 # unsigned number + +# Whether to convert all tabs to spaces in comments. If false, tabs in +# comments are left alone, unless used for indenting. +cmt_convert_tab_to_spaces = false # true/false + +# Whether to apply changes to multi-line comments, including cmt_width, +# keyword substitution and leading chars. +# +# Default: true +cmt_indent_multi = true # true/false + +# Whether to group c-comments that look like they are in a block. +cmt_c_group = true # true/false + +# Whether to put an empty '/*' on the first line of the combined c-comment. +cmt_c_nl_start = false # true/false + +# Whether to add a newline before the closing '*/' of the combined c-comment. +cmt_c_nl_end = false # true/false + +# Whether to change cpp-comments into c-comments. +cmt_cpp_to_c = true # true/false + +# Whether to group cpp-comments that look like they are in a block. Only +# meaningful if cmt_cpp_to_c=true. +cmt_cpp_group = true # true/false + +# Whether to put an empty '/*' on the first line of the combined cpp-comment +# when converting to a c-comment. +# +# Requires cmt_cpp_to_c=true and cmt_cpp_group=true. +cmt_cpp_nl_start = false # true/false + +# Whether to add a newline before the closing '*/' of the combined cpp-comment +# when converting to a c-comment. +# +# Requires cmt_cpp_to_c=true and cmt_cpp_group=true. +cmt_cpp_nl_end = false # true/false + +# Whether to put a star on subsequent comment lines. +cmt_star_cont = true # true/false + +# The number of spaces to insert at the start of subsequent comment lines. +cmt_sp_before_star_cont = 0 # unsigned number + +# The number of spaces to insert after the star on subsequent comment lines. +cmt_sp_after_star_cont = 0 # unsigned number + +# For multi-line comments with a '*' lead, remove leading spaces if the first +# and last lines of the comment are the same length. +# +# Default: true +cmt_multi_check_last = true # true/false + +# For multi-line comments with a '*' lead, remove leading spaces if the first +# and last lines of the comment are the same length AND if the length is +# bigger as the first_len minimum. +# +# Default: 4 +cmt_multi_first_len_minimum = 4 # unsigned number + +# Path to a file that contains text to insert at the beginning of a file if +# the file doesn't start with a C/C++ comment. If the inserted text contains +# '$(filename)', that will be replaced with the current file's name. +cmt_insert_file_header = "" # string + +# Path to a file that contains text to insert at the end of a file if the +# file doesn't end with a C/C++ comment. If the inserted text contains +# '$(filename)', that will be replaced with the current file's name. +cmt_insert_file_footer = "" # string + +# Path to a file that contains text to insert before a function definition if +# the function isn't preceded by a C/C++ comment. If the inserted text +# contains '$(function)', '$(javaparam)' or '$(fclass)', these will be +# replaced with, respectively, the name of the function, the javadoc '@param' +# and '@return' stuff, or the name of the class to which the member function +# belongs. +cmt_insert_func_header = "" # string + +# Path to a file that contains text to insert before a class if the class +# isn't preceded by a C/C++ comment. If the inserted text contains '$(class)', +# that will be replaced with the class name. +cmt_insert_class_header = "" # string + +# Path to a file that contains text to insert before an Objective-C message +# specification, if the method isn't preceded by a C/C++ comment. If the +# inserted text contains '$(message)' or '$(javaparam)', these will be +# replaced with, respectively, the name of the function, or the javadoc +# '@param' and '@return' stuff. +cmt_insert_oc_msg_header = "" # string + +# Whether a comment should be inserted if a preprocessor is encountered when +# stepping backwards from a function name. +# +# Applies to cmt_insert_oc_msg_header, cmt_insert_func_header and +# cmt_insert_class_header. +cmt_insert_before_preproc = false # true/false + +# Whether a comment should be inserted if a function is declared inline to a +# class definition. +# +# Applies to cmt_insert_func_header. +# +# Default: true +cmt_insert_before_inlines = true # true/false + +# Whether a comment should be inserted if the function is a class constructor +# or destructor. +# +# Applies to cmt_insert_func_header. +cmt_insert_before_ctor_dtor = false # true/false + +# +# Code modifying options (non-whitespace) +# + +# Add or remove braces on a single-line 'do' statement. +mod_full_brace_do = ignore # ignore/add/remove/force + +# Add or remove braces on a single-line 'for' statement. +mod_full_brace_for = ignore # ignore/add/remove/force + +# (Pawn) Add or remove braces on a single-line function definition. +mod_full_brace_function = ignore # ignore/add/remove/force + +# Add or remove braces on a single-line 'if' statement. Braces will not be +# removed if the braced statement contains an 'else'. +mod_full_brace_if = ignore # ignore/add/remove/force + +# Whether to enforce that all blocks of an 'if'/'else if'/'else' chain either +# have, or do not have, braces. If true, braces will be added if any block +# needs braces, and will only be removed if they can be removed from all +# blocks. +# +# Overrides mod_full_brace_if. +mod_full_brace_if_chain = false # true/false + +# Whether to add braces to all blocks of an 'if'/'else if'/'else' chain. +# If true, mod_full_brace_if_chain will only remove braces from an 'if' that +# does not have an 'else if' or 'else'. +mod_full_brace_if_chain_only = false # true/false + +# Add or remove braces on single-line 'while' statement. +mod_full_brace_while = ignore # ignore/add/remove/force + +# Add or remove braces on single-line 'using ()' statement. +mod_full_brace_using = ignore # ignore/add/remove/force + +# Don't remove braces around statements that span N newlines +mod_full_brace_nl = 0 # unsigned number + +# Whether to prevent removal of braces from 'if'/'for'/'while'/etc. blocks +# which span multiple lines. +# +# Affects: +# mod_full_brace_for +# mod_full_brace_if +# mod_full_brace_if_chain +# mod_full_brace_if_chain_only +# mod_full_brace_while +# mod_full_brace_using +# +# Does not affect: +# mod_full_brace_do +# mod_full_brace_function +mod_full_brace_nl_block_rem_mlcond = false # true/false + +# Add or remove unnecessary parenthesis on 'return' statement. +mod_paren_on_return = ignore # ignore/add/remove/force + +# (Pawn) Whether to change optional semicolons to real semicolons. +mod_pawn_semicolon = false # true/false + +# Whether to fully parenthesize Boolean expressions in 'while' and 'if' +# statement, as in 'if (a && b > c)' => 'if (a && (b > c))'. +mod_full_paren_if_bool = false # true/false + +# Whether to remove superfluous semicolons. +mod_remove_extra_semicolon = false # true/false + +# If a function body exceeds the specified number of newlines and doesn't have +# a comment after the close brace, a comment will be added. +mod_add_long_function_closebrace_comment = 0 # unsigned number + +# If a namespace body exceeds the specified number of newlines and doesn't +# have a comment after the close brace, a comment will be added. +mod_add_long_namespace_closebrace_comment = 0 # unsigned number + +# If a class body exceeds the specified number of newlines and doesn't have a +# comment after the close brace, a comment will be added. +mod_add_long_class_closebrace_comment = 0 # unsigned number + +# If a switch body exceeds the specified number of newlines and doesn't have a +# comment after the close brace, a comment will be added. +mod_add_long_switch_closebrace_comment = 0 # unsigned number + +# If an #ifdef body exceeds the specified number of newlines and doesn't have +# a comment after the #endif, a comment will be added. +mod_add_long_ifdef_endif_comment = 0 # unsigned number + +# If an #ifdef or #else body exceeds the specified number of newlines and +# doesn't have a comment after the #else, a comment will be added. +mod_add_long_ifdef_else_comment = 0 # unsigned number + +# Whether to sort consecutive single-line 'import' statements. +mod_sort_import = false # true/false + +# (C#) Whether to sort consecutive single-line 'using' statements. +mod_sort_using = false # true/false + +# Whether to sort consecutive single-line '#include' statements (C/C++) and +# '#import' statements (Objective-C). Be aware that this has the potential to +# break your code if your includes/imports have ordering dependencies. +mod_sort_include = false # true/false + +# Whether to move a 'break' that appears after a fully braced 'case' before +# the close brace, as in 'case X: { ... } break;' => 'case X: { ... break; }'. +mod_move_case_break = false # true/false + +# Add or remove braces around a fully braced case statement. Will only remove +# braces if there are no variable declarations in the block. +mod_case_brace = ignore # ignore/add/remove/force + +# Whether to remove a void 'return;' that appears as the last statement in a +# function. +mod_remove_empty_return = false # true/false + +# Add or remove the comma after the last value of an enumeration. +mod_enum_last_comma = ignore # ignore/add/remove/force + +# (OC) Whether to organize the properties. If true, properties will be +# rearranged according to the mod_sort_oc_property_*_weight factors. +mod_sort_oc_properties = false # true/false + +# (OC) Weight of a class property modifier. +mod_sort_oc_property_class_weight = 0 # number + +# (OC) Weight of 'atomic' and 'nonatomic'. +mod_sort_oc_property_thread_safe_weight = 0 # number + +# (OC) Weight of 'readwrite' when organizing properties. +mod_sort_oc_property_readwrite_weight = 0 # number + +# (OC) Weight of a reference type specifier ('retain', 'copy', 'assign', +# 'weak', 'strong') when organizing properties. +mod_sort_oc_property_reference_weight = 0 # number + +# (OC) Weight of getter type ('getter=') when organizing properties. +mod_sort_oc_property_getter_weight = 0 # number + +# (OC) Weight of setter type ('setter=') when organizing properties. +mod_sort_oc_property_setter_weight = 0 # number + +# (OC) Weight of nullability type ('nullable', 'nonnull', 'null_unspecified', +# 'null_resettable') when organizing properties. +mod_sort_oc_property_nullability_weight = 0 # number + +# +# Preprocessor options +# + +# Add or remove indentation of preprocessor directives inside #if blocks +# at brace level 0 (file-level). +pp_indent = ignore # ignore/add/remove/force + +# Whether to indent #if/#else/#endif at the brace level. If false, these are +# indented from column 1. +pp_indent_at_level = false # true/false + +# Specifies the number of columns to indent preprocessors per level +# at brace level 0 (file-level). If pp_indent_at_level=false, also specifies +# the number of columns to indent preprocessors per level +# at brace level > 0 (function-level). +# +# Default: 1 +pp_indent_count = 1 # unsigned number + +# Add or remove space after # based on pp_level of #if blocks. +pp_space = ignore # ignore/add/remove/force + +# Sets the number of spaces per level added with pp_space. +pp_space_count = 0 # unsigned number + +# The indent for '#region' and '#endregion' in C# and '#pragma region' in +# C/C++. Negative values decrease indent down to the first column. +pp_indent_region = 0 # number + +# Whether to indent the code between #region and #endregion. +pp_region_indent_code = false # true/false + +# If pp_indent_at_level=true, sets the indent for #if, #else and #endif when +# not at file-level. Negative values decrease indent down to the first column. +# +# =0: Indent preprocessors using output_tab_size +# >0: Column at which all preprocessors will be indented +pp_indent_if = 0 # number + +# Whether to indent the code between #if, #else and #endif. +pp_if_indent_code = false # true/false + +# Whether to indent '#define' at the brace level. If false, these are +# indented from column 1. +pp_define_at_level = false # true/false + +# Whether to ignore the '#define' body while formatting. +pp_ignore_define_body = false # true/false + +# Whether to indent case statements between #if, #else, and #endif. +# Only applies to the indent of the preprocesser that the case statements +# directly inside of. +# +# Default: true +pp_indent_case = true # true/false + +# Whether to indent whole function definitions between #if, #else, and #endif. +# Only applies to the indent of the preprocesser that the function definition +# is directly inside of. +# +# Default: true +pp_indent_func_def = true # true/false + +# Whether to indent extern C blocks between #if, #else, and #endif. +# Only applies to the indent of the preprocesser that the extern block is +# directly inside of. +# +# Default: true +pp_indent_extern = true # true/false + +# Whether to indent braces directly inside #if, #else, and #endif. +# Only applies to the indent of the preprocesser that the braces are directly +# inside of. +# +# Default: true +pp_indent_brace = true # true/false + +# +# Sort includes options +# + +# The regex for include category with priority 0. +include_category_0 = "" # string + +# The regex for include category with priority 1. +include_category_1 = "" # string + +# The regex for include category with priority 2. +include_category_2 = "" # string + +# +# Use or Do not Use options +# + +# true: indent_func_call_param will be used (default) +# false: indent_func_call_param will NOT be used +# +# Default: true +use_indent_func_call_param = true # true/false + +# The value of the indentation for a continuation line is calculated +# differently if the statement is: +# - a declaration: your case with QString fileName ... +# - an assignment: your case with pSettings = new QSettings( ... +# +# At the second case the indentation value might be used twice: +# - at the assignment +# - at the function call (if present) +# +# To prevent the double use of the indentation value, use this option with the +# value 'true'. +# +# true: indent_continue will be used only once +# false: indent_continue will be used every time (default) +use_indent_continue_only_once = false # true/false + +# The value might be used twice: +# - at the assignment +# - at the opening brace +# +# To prevent the double use of the indentation value, use this option with the +# value 'true'. +# +# true: indentation will be used only once +# false: indentation will be used every time (default) +indent_cpp_lambda_only_once = false # true/false + +# Whether to apply special formatting for Qt SIGNAL/SLOT macros. Essentially, +# this tries to format these so that they match Qt's normalized form (i.e. the +# result of QMetaObject::normalizedSignature), which can slightly improve the +# performance of the QObject::connect call, rather than how they would +# otherwise be formatted. +# +# See options_for_QT.cpp for details. +# +# Default: true +use_options_overriding_for_qt_macros = true # true/false + +# +# Warn levels - 1: error, 2: warning (default), 3: note +# + +# (C#) Warning is given if doing tab-to-\t replacement and we have found one +# in a C# verbatim string literal. +# +# Default: 2 +warn_level_tabs_found_in_verbatim_string_literals = 2 # unsigned number + +# Meaning of the settings: +# Ignore - do not do any changes +# Add - makes sure there is 1 or more space/brace/newline/etc +# Force - makes sure there is exactly 1 space/brace/newline/etc, +# behaves like Add in some contexts +# Remove - removes space/brace/newline/etc +# +# +# - Token(s) can be treated as specific type(s) with the 'set' option: +# `set tokenType tokenString [tokenString...]` +# +# Example: +# `set BOOL __AND__ __OR__` +# +# tokenTypes are defined in src/token_enum.h, use them without the +# 'CT_' prefix: 'CT_BOOL' => 'BOOL' +# +# +# - Token(s) can be treated as type(s) with the 'type' option. +# `type tokenString [tokenString...]` +# +# Example: +# `type int c_uint_8 Rectangle` +# +# This can also be achieved with `set TYPE int c_uint_8 Rectangle` +# +# +# To embed whitespace in tokenStrings use the '\' escape character, or quote +# the tokenStrings. These quotes are supported: "'` +# +# +# - Support for the auto detection of languages through the file ending can be +# added using the 'file_ext' command. +# `file_ext langType langString [langString..]` +# +# Example: +# `file_ext CPP .ch .cxx .cpp.in` +# +# langTypes are defined in uncrusify_types.h in the lang_flag_e enum, use +# them without the 'LANG_' prefix: 'LANG_CPP' => 'CPP' +# +# +# - Custom macro-based indentation can be set up using 'macro-open', +# 'macro-else' and 'macro-close'. +# `(macro-open | macro-else | macro-close) tokenString` +# +# Example: +# `macro-open BEGIN_TEMPLATE_MESSAGE_MAP` +# `macro-open BEGIN_MESSAGE_MAP` +# `macro-close END_MESSAGE_MAP` +# +# +# option(s) with 'not default' value: 0 +# diff --git a/verification/examples/spdm/CMakeLists.txt b/verification/examples/spdm/CMakeLists.txt new file mode 100644 index 00000000..f21b99a6 --- /dev/null +++ b/verification/examples/spdm/CMakeLists.txt @@ -0,0 +1,464 @@ +cmake_minimum_required(VERSION 2.6) + +project("spdm_caliptra" C) + +# +# Build Configuration Macro Definition +# +MESSAGE("#########################") +MESSAGE("## Build Configuration ##") +MESSAGE("#########################") + +SET(CMAKE_GENERATOR ${CMAKE_GENERATOR} CACHE STRING "Choose the generator of cmake") +SET(ARCH ${ARCH} CACHE STRING "Choose the arch of build: ia32 x64 arm aarch64 riscv32 riscv64 arc" FORCE) +SET(TOOLCHAIN ${TOOLCHAIN} CACHE STRING "Choose the toolchain of build: Linux: GCC ARM_GCC AARCH64_GCC RISCV32_GCC RISCV64_GCC ARC_GCC ARM_DS2022 CLANG CBMC AFL KLEE LIBFUZZER" FORCE) +SET(CMAKE_BUILD_TYPE ${TARGET} CACHE STRING "Choose the target of build: Debug Release" FORCE) +SET(CRYPTO ${CRYPTO} CACHE STRING "Choose the crypto of build: mbedtls openssl" FORCE) +SET(GCOV ${GCOV} CACHE STRING "Choose the target of Gcov: ON OFF, and default is OFF" FORCE) + +if(NOT GCOV) + SET(GCOV "OFF") +endif() + +SET(SPDM_CALIPTRA_DIR ${PROJECT_SOURCE_DIR}) +SET(LIBSPDM_DIR ${PROJECT_SOURCE_DIR}/libspdm) +# SET(SPDM_RESPONDER_VALIDATOR_DIR ${PROJECT_SOURCE_DIR}/SPDM-Responder-Validator) +# SET(COMMON_TEST_FRAMEWORK_DIR ${PROJECT_SOURCE_DIR}/SPDM-Responder-Validator/common_test_framework) + +# +# OpenSSL specific compiled libraries. +# +SET(COMPILED_LIBCRYPTO_PATH ${COMPILED_LIBCRYPTO_PATH} CACHE STRING "Optionally provide a path to libcrypto" FORCE) +SET(COMPILED_LIBSSL_PATH ${COMPILED_LIBSSL_PATH} CACHE STRING "Optionally provide a path to libssl" FORCE) + +MESSAGE("CMAKE_GENERATOR = ${CMAKE_GENERATOR}") + +if(ARCH STREQUAL "x64") + MESSAGE("ARCH = x64") +elseif(ARCH STREQUAL "ia32") + MESSAGE("ARCH = ia32") +elseif(ARCH STREQUAL "arm") + MESSAGE("ARCH = arm") +elseif(ARCH STREQUAL "aarch64") + MESSAGE("ARCH = aarch64") +elseif(ARCH STREQUAL "riscv32") + MESSAGE("ARCH = riscv32") +elseif(ARCH STREQUAL "riscv64") + MESSAGE("ARCH = riscv64") +elseif(ARCH STREQUAL "arc") + MESSAGE("ARCH = arc") +elseif(ARCH STREQUAL "nios2") + MESSAGE("ARCH = nios2") +else() + MESSAGE(FATAL_ERROR "Unkown ARCH") +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Linux") + if(TOOLCHAIN STREQUAL "GCC") + MESSAGE("TOOLCHAIN = GCC") + elseif(TOOLCHAIN STREQUAL "CLANG") + MESSAGE("TOOLCHAIN = CLANG") + elseif(TOOLCHAIN STREQUAL "CBMC") + MESSAGE("TOOLCHAIN = CBMC") + elseif(TOOLCHAIN STREQUAL "AFL") + MESSAGE("TOOLCHAIN = AFL") + elseif(TOOLCHAIN STREQUAL "KLEE") + MESSAGE("TOOLCHAIN = KLEE") + elseif(TOOLCHAIN STREQUAL "LIBFUZZER") + MESSAGE("TOOLCHAIN = LIBFUZZER") + elseif(TOOLCHAIN STREQUAL "ARM_GCC") + MESSAGE("TOOLCHAIN = ARM_GCC") + elseif(TOOLCHAIN STREQUAL "AARCH64_GCC") + MESSAGE("TOOLCHAIN = AARCH64_GCC") + elseif(TOOLCHAIN STREQUAL "RISCV32_GCC") + MESSAGE("TOOLCHAIN = RISCV32_GCC") + elseif(TOOLCHAIN STREQUAL "RISCV64_GCC") + MESSAGE("TOOLCHAIN = RISCV64_GCC") + elseif(TOOLCHAIN STREQUAL "ARM_DS2022") + MESSAGE("TOOLCHAIN = ARM_DS2022") + elseif(TOOLCHAIN STREQUAL "ARC_GCC") + MESSAGE("TOOLCHAIN = ARC_GCC") + elseif(TOOLCHAIN STREQUAL "NIOS2_GCC") + MESSAGE("TOOLCHAIN = NIOS2_GCC") + else() + MESSAGE(FATAL_ERROR "Unkown TOOLCHAIN") + endif() + if(GCOV STREQUAL "ON") + MESSAGE("GCOV = ON") + elseif(GCOV STREQUAL "OFF") + MESSAGE("GCOV = OFF") + else() + MESSAGE(FATAL_ERROR "Unkown GCOV switch input") + endif() +else() + MESSAGE(FATAL_ERROR "${CMAKE_SYSTEM_NAME} is not supportted") +endif() + +if(CMAKE_BUILD_TYPE STREQUAL "Debug") + MESSAGE("TARGET = Debug") +elseif(CMAKE_BUILD_TYPE STREQUAL "Release") + MESSAGE("TARGET = Release") +else() + MESSAGE(FATAL_ERROR "Unkown build type") +endif() + +if(CRYPTO STREQUAL "mbedtls") + MESSAGE("CRYPTO = mbedtls") +elseif(CRYPTO STREQUAL "openssl") + MESSAGE("CRYPTO = openssl") +else() + MESSAGE(FATAL_ERROR "Unkown CRYPTO") +endif() + +if(ENABLE_BINARY_BUILD STREQUAL "1") + if(NOT CRYPTO STREQUAL "Openssl") + MESSAGE(FATAL_ERROR "enabling binary build not supported for non-Openssl") + endif() + + if(NOT COMPILED_LIBCRYPTO_PATH) + MESSAGE(FATAL_ERROR "enabling binary build requires path to libcrypto.") + endif() + + if(NOT COMPILED_LIBSSL_PATH) + MESSAGE(FATAL_ERROR "enabling binary build requires path to libssl.") + endif() + + MESSAGE("ENABLE_BINARY_BUILD=1") + MESSAGE("COMPILED_LIBCRYPTO_PATH=${COMPILED_LIBCRYPTO_PATH}") + MESSAGE("COMPILED_LIBSSL_PATH=${COMPILED_LIBSSL_PATH}") + + SET(CRYPTO_LIB_PATHS ${COMPILED_LIBCRYPTO_PATH} ${COMPILED_LIBSSL_PATH}) +else() + SET(CRYPTO_LIB_PATHS ${CRYPTO}lib) + MESSAGE("ENABLE_BINARY_BUILD=0; Building ${CRYPTO} library from source.") +endif() + +if(CMAKE_SYSTEM_NAME MATCHES "Linux") + SET(CMAKE_EXE_EXPORTS_C_FLAG "") + + if(TOOLCHAIN STREQUAL "GCC") + SET(CMAKE_C_COMPILER gcc) + ADD_COMPILE_OPTIONS(-std=c99 -g -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -maccumulate-outgoing-args -mno-red-zone -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO -Wno-maybe-uninitialized -Wno-uninitialized -Wno-builtin-declaration-mismatch -Wno-nonnull-compare) + if(GCOV STREQUAL "ON") + ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage) + endif() + SET(MBEDTLS_FLAGS "") + SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable) + SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong) + + SET(CMAKE_AR gcc-ar) + + if(NOT CMAKE_C_COMPILER_VERSION VERSION_GREATER_EQUAL 9.3) + SET(CMAKE_C_ARCHIVE_FINISH true) + endif() + + SET(CMAKE_LINKER gcc) + SET(CMAKE_EXE_LINKER_FLAGS "-Wno-error -no-pie" ) + if(CMAKE_BUILD_TYPE STREQUAL "Debug") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -g") + else() + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -flto") + endif() + if(GCOV STREQUAL "ON") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage -lgcov -fprofile-arcs -ftest-coverage") + endif() + SET(CMAKE_C_LINK_EXECUTABLE " -o -Wl,--start-group -Wl,--end-group") + + elseif(TOOLCHAIN STREQUAL "ARM_DS2022") + if(ARCH STREQUAL "aarch64") + SET(CMAKE_SYSTEM_NAME Linux) + SET(CMAKE_C_COMPILER armclang) + SET(CMAKE_AR armar) + SET(CMAKE_LINKER armlink) + SET(CMAKE_OBJCOPY fromelf) + + SET(CMAKE_EXECUTABLE_SUFFIX ".elf") + SET(CMAKE_LIBRARY_PATH_FLAG "--userlibpath=") + ADD_COMPILE_OPTIONS(-fshort-wchar -fno-strict-aliasing -ffunction-sections -fdata-sections -fno-common -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO) + SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic ) + SET(OPENSSL_FLAGS -include base.h) + SET(CMAKE_C_CREATE_STATIC_LIBRARY "armar -r -s --create ") + SET(CMAKE_SYSTEM_PROCESSOR aarch64v) + ADD_COMPILE_OPTIONS(--target=aarch64-arm-none-eabi) + SET(CMAKE_EXE_LINKER_FLAGS "--target=aarch64-arm-none-eabi -flto -Wl,--undefined=__udivti3") + elseif(ARCH STREQUAL "arm") + SET(CMAKE_SYSTEM_NAME Linux) + SET(CMAKE_C_COMPILER armclang) + SET(CMAKE_LINKER armlink) + set(CMAKE_SYSTEM_PROCESSOR arm) + + ADD_COMPILE_OPTIONS(--target=arm-arm-none-eabi -march=armv9-a) + SET(CMAKE_EXE_LINKER_FLAGS "--target=arm-arm-none-eabi -march=armv9-a -Wl,--undefined=__udivti3") + SET(OPENSSL_FLAGS -include base.h) + set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY) + endif() + + SET(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER) + SET(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY) + SET(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY) + SET(CMAKE_FIND_ROOT_PATH_MODE_PACKAGE ONLY) + + elseif(TOOLCHAIN STREQUAL "ARM_GCC") + SET(CMAKE_C_COMPILER arm-linux-gnueabi-gcc) + ADD_COMPILE_OPTIONS(-g -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO -Wno-maybe-uninitialized -Wno-uninitialized -Wno-builtin-declaration-mismatch -Wno-nonnull-compare) + if(GCOV STREQUAL "ON") + ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage) + endif() + SET(MBEDTLS_FLAGS "") + SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable) + SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong) + + SET(CMAKE_AR arm-linux-gnueabi-gcc-ar) + + SET(CMAKE_LINKER arm-linux-gnueabi-gcc) + SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error -no-pie" ) + if(GCOV STREQUAL "ON") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage -lgcov -fprofile-arcs -ftest-coverage") + endif() + SET(CMAKE_C_LINK_EXECUTABLE " -o -Wl,--start-group -Wl,--end-group") + + elseif(TOOLCHAIN STREQUAL "AARCH64_GCC") + SET(CMAKE_C_COMPILER aarch64-linux-gnu-gcc) + ADD_COMPILE_OPTIONS(-g -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO -Wno-maybe-uninitialized -Wno-uninitialized -Wno-builtin-declaration-mismatch -Wno-nonnull-compare) + if(GCOV STREQUAL "ON") + ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage) + endif() + SET(MBEDTLS_FLAGS "") + SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable) + SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong) + + SET(CMAKE_AR aarch64-linux-gnu-gcc-ar) + + SET(CMAKE_LINKER aarch64-linux-gnu-gcc) + SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error -no-pie" ) + if(GCOV STREQUAL "ON") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage -lgcov -fprofile-arcs -ftest-coverage") + endif() + + SET(CMAKE_C_LINK_EXECUTABLE " -o -Wl,--start-group -Wl,--end-group") + + elseif(TOOLCHAIN STREQUAL "RISCV32_GCC") + SET(CMAKE_C_COMPILER riscv32-unknown-linux-gnu-gcc) + ADD_COMPILE_OPTIONS(-g -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO -Wno-maybe-uninitialized -Wno-uninitialized -Wno-builtin-declaration-mismatch -Wno-nonnull-compare) + if(GCOV STREQUAL "ON") + ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage) + endif() + SET(MBEDTLS_FLAGS "") + SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable) + SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong) + + SET(CMAKE_AR riscv32-unknown-linux-gnu-gcc-ar) + + SET(CMAKE_LINKER riscv32-unknown-linux-gnu-gcc) + SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error -no-pie" ) + if(GCOV STREQUAL "ON") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage -lgcov -fprofile-arcs -ftest-coverage") + endif() + + SET(CMAKE_C_LINK_EXECUTABLE " -o -Wl,--start-group -Wl,--end-group") + + elseif(TOOLCHAIN STREQUAL "RISCV64_GCC") + SET(CMAKE_C_COMPILER riscv64-linux-gnu-gcc) + ADD_COMPILE_OPTIONS(-g -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO -Wno-maybe-uninitialized -Wno-uninitialized -Wno-builtin-declaration-mismatch -Wno-nonnull-compare) + if(GCOV STREQUAL "ON") + ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage) + endif() + SET(MBEDTLS_FLAGS "") + SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable) + SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong) + + SET(CMAKE_AR riscv64-linux-gnu-gcc-ar) + + SET(CMAKE_LINKER riscv64-linux-gnu-gcc) + SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error -no-pie" ) + if(GCOV STREQUAL "ON") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage -lgcov -fprofile-arcs -ftest-coverage") + endif() + + SET(CMAKE_C_LINK_EXECUTABLE " -o -Wl,--start-group -Wl,--end-group") + + elseif(TOOLCHAIN STREQUAL "ARC_GCC") + SET(CMAKE_C_COMPILER arc-linux-gcc) + ADD_COMPILE_OPTIONS(-g -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO -Wno-maybe-uninitialized -Wno-uninitialized -Wno-builtin-declaration-mismatch -Wno-nonnull-compare) + if(GCOV STREQUAL "ON") + ADD_COMPILE_OPTIONS(--coverage -fprofile-arcs -ftest-coverage) + endif() + SET(MBEDTLS_FLAGS "") + SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable) + SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong) + + SET(CMAKE_AR arc-linux-gcc-ar) + + SET(CMAKE_LINKER arc-linux-gcc) + SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error -no-pie" ) + if(GCOV STREQUAL "ON") + SET(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} --coverage -lgcov -fprofile-arcs -ftest-coverage") + endif() + + SET(CMAKE_C_LINK_EXECUTABLE " -o -Wl,--start-group -Wl,--end-group") + + + elseif(TOOLCHAIN STREQUAL "CLANG") + SET(CMAKE_C_COMPILER clang) + ADD_COMPILE_OPTIONS(-g -fshort-wchar -fno-strict-aliasing -Wall -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -mno-red-zone -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO) + SET(MBEDTLS_FLAGS "") + SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable) + SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong) + + SET(CMAKE_AR llvm-ar) + SET(CMAKE_RANLIB llvm-ranlib) + + SET(CMAKE_LINKER clang) + SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error -no-pie" ) + + SET(CMAKE_C_LINK_EXECUTABLE " -o -Wl,--start-group -Wl,--end-group") + + elseif(TOOLCHAIN STREQUAL "CBMC") + SET(CMAKE_C_COMPILER goto-cc) + ADD_COMPILE_OPTIONS(-g -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -maccumulate-outgoing-args -mno-red-zone -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO -Wno-maybe-uninitialized -Wno-uninitialized -Wno-builtin-declaration-mismatch -Wno-nonnull-compare -DCBMC -DDEBUG_ASSERT_CHOICE=0) + SET(MBEDTLS_FLAGS "") + SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable) + SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong) + + SET(CMAKE_LINKER goto-cc) + SET(CMAKE_EXE_LINKER_FLAGS "-flto -Wno-error") + + SET(CMAKE_C_LINK_EXECUTABLE " -o ") + + elseif(TOOLCHAIN STREQUAL "AFL") + SET(CMAKE_C_COMPILER afl-gcc) + ADD_COMPILE_OPTIONS(-g -fshort-wchar -fno-strict-aliasing -Wall -Werror -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -maccumulate-outgoing-args -mno-red-zone -Wno-address -fpie -fno-asynchronous-unwind-tables -DUSING_LTO -Wno-maybe-uninitialized -Wno-uninitialized -Wno-builtin-declaration-mismatch -Wno-nonnull-compare) + SET(MBEDTLS_FLAGS "") + SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable) + SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong) + + SET(CMAKE_AR gcc-ar) + + SET(CMAKE_LINKER gcc) + SET(CMAKE_EXE_LINKER_FLAGS "-Wno-error -no-pie" ) + + SET(CMAKE_C_LINK_EXECUTABLE " -o -Wl,--start-group -Wl,--end-group") + + elseif(TOOLCHAIN STREQUAL "KLEE") + SET(CMAKE_C_COMPILER clang) + ADD_COMPILE_OPTIONS(-g -fno-strict-aliasing -Wall -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -mno-red-zone -Wno-address -fpie -fno-asynchronous-unwind-tables -flto -DUSING_LTO -emit-llvm -DTEST_WITH_KLEE=TRUE -DDEBUG_ASSERT_CHOICE=0) + SET(MBEDTLS_FLAGS "") + SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable) + SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong) + + SET(CMAKE_C_CREATE_STATIC_LIBRARY "") + + SET(CMAKE_LINKER llvm-link) + + SET(CMAKE_C_LINK_EXECUTABLE " -o ") + + elseif(TOOLCHAIN STREQUAL "LIBFUZZER") + SET(CMAKE_C_COMPILER clang) + ADD_COMPILE_OPTIONS(-g -fshort-wchar -fno-strict-aliasing -Wall -Wno-array-bounds -ffunction-sections -fdata-sections -fno-common -mno-red-zone -Wno-address -fpie -fno-asynchronous-unwind-tables -DUSING_LTO -DTEST_WITH_LIBFUZZER=TRUE -O1 -fsanitize=fuzzer,address) + SET(MBEDTLS_FLAGS "") + SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable) + SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong) + + SET(CMAKE_AR llvm-ar) + + SET(CMAKE_LINKER clang) + SET(CMAKE_EXE_LINKER_FLAGS "-Wno-error -no-pie -fsanitize=fuzzer,address" ) + + SET(CMAKE_C_LINK_EXECUTABLE " -o -Wl,--start-group -Wl,--end-group") + + elseif(TOOLCHAIN STREQUAL "NIOS2_GCC") + SET(CMAKE_C_COMPILER nios2-elf-gcc) + ADD_COMPILE_OPTIONS(-xc -MP -MMD -pipe -O3 -Wall -Wno-maybe-uninitialized -Wno-unused-but-set-variable -Wno-nonnull-compare -Wno-int-to-pointer-cast -Wno-pointer-to-int-cast -Wno-builtin-declaration-mismatch -mno-hw-div -mhw-mul -mno-hw-mulx -mgpopt=global) + SET(MBEDTLS_FLAGS "") + SET(OPENSSL_FLAGS -include base.h -Wno-error=maybe-uninitialized -Wno-error=format -Wno-format -Wno-error=unused-but-set-variable) + SET(CMOCKA_FLAGS -std=gnu99 -Wpedantic -Wall -Wshadow -Wmissing-prototypes -Wcast-align -Werror=address -Wstrict-prototypes -Werror=strict-prototypes -Wwrite-strings -Werror=write-strings -Werror-implicit-function-declaration -Wpointer-arith -Werror=pointer-arith -Wdeclaration-after-statement -Werror=declaration-after-statement -Wreturn-type -Werror=return-type -Wuninitialized -Werror=uninitialized -Werror=strict-overflow -Wstrict-overflow=2 -Wno-format-zero-length -Wmissing-field-initializers -Wformat-security -Werror=format-security -fno-common -Wformat -fno-common -fstack-protector-strong) + + SET(CMAKE_AR nios2-elf-ar) + + SET(CMAKE_LINKER nios2-elf-gcc) + SET(CMAKE_EXE_LINKER_FLAGS "") + + SET(CMAKE_C_LINK_EXECUTABLE "") + + endif() + + if(NOT TOOLCHAIN STREQUAL "NIOS2_GCC") + SET(CMAKE_C_FLAGS_RELEASE "-Os") + SET(CMAKE_C_FLAGS_DEBUG "-O0") + endif() + + if(ARCH STREQUAL "x64") + ADD_COMPILE_OPTIONS(-m64 -mcmodel=small) + elseif(ARCH STREQUAL "ia32") + ADD_COMPILE_OPTIONS(-m32) + endif() + +endif() + +SET(LIBRARY_OUTPUT_PATH ${PROJECT_BINARY_DIR}/lib) +SET(EXECUTABLE_OUTPUT_PATH ${PROJECT_BINARY_DIR}/bin) + +ADD_CUSTOM_TARGET(copy_sample_key) + +if(CMAKE_SYSTEM_NAME MATCHES "Linux") + ADD_CUSTOM_COMMAND(TARGET copy_sample_key + PRE_BUILD + COMMAND cp -r -f ${LIBSPDM_DIR}/unit_test/sample_key/* ${EXECUTABLE_OUTPUT_PATH}) +endif() + +if(CRYPTO STREQUAL "mbedtls") + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/os_stub/cryptlib_mbedtls out/cryptlib_mbedtls.out) +elseif(CRYPTO STREQUAL "openssl") + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/os_stub/cryptlib_openssl out/cryptlib_openssl.out) +endif() + +if(NOT ENABLE_BINARY_BUILD STREQUAL "1") + if(CRYPTO STREQUAL "mbedtls") + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/os_stub/mbedtlslib out/mbedtlslib.out) + elseif(CRYPTO STREQUAL "openssl") + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/os_stub/openssllib out/openssllib.out) + endif() +endif() + + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/library/spdm_common_lib out/spdm_common_lib.out) + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/library/spdm_requester_lib out/spdm_requester_lib.out) + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/library/spdm_responder_lib out/spdm_responder_lib.out) + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/library/spdm_crypt_lib out/spdm_crypt_lib.out) + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/library/spdm_secured_message_lib out/spdm_secured_message_lib.out) + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/library/spdm_transport_mctp_lib out/spdm_transport_mctp_lib.out) + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/library/spdm_transport_pcidoe_lib out/spdm_transport_pcidoe_lib.out) + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/os_stub/memlib out/memlib.out) + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/os_stub/debuglib out/debuglib.out) + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/os_stub/debuglib_null out/debuglib_null.out) + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/os_stub/rnglib out/rnglib.out) + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/os_stub/malloclib out/malloclib.out) + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/os_stub/spdm_device_secret_lib_sample out/spdm_device_secret_lib_sample.out) + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/os_stub/platform_lib out/platform_lib.out) + ADD_SUBDIRECTORY(${LIBSPDM_DIR}/os_stub/spdm_crypt_ext_lib out/spdm_crypt_ext_lib.out) + + # ADD_SUBDIRECTORY(library/spdm_transport_none_lib) + ADD_SUBDIRECTORY(library/mctp_requester_lib) + ADD_SUBDIRECTORY(library/mctp_responder_lib) + # ADD_SUBDIRECTORY(library/pci_doe_requester_lib) + # ADD_SUBDIRECTORY(library/pci_doe_responder_lib) + # ADD_SUBDIRECTORY(library/pci_ide_km_requester_lib) + # ADD_SUBDIRECTORY(library/pci_ide_km_responder_lib) + # ADD_SUBDIRECTORY(library/pci_ide_km_device_lib_sample) + # ADD_SUBDIRECTORY(library/pci_tdisp_requester_lib) + # ADD_SUBDIRECTORY(library/pci_tdisp_responder_lib) + # ADD_SUBDIRECTORY(library/pci_tdisp_device_lib_sample) + # ADD_SUBDIRECTORY(library/cxl_ide_km_requester_lib) + # ADD_SUBDIRECTORY(library/cxl_ide_km_responder_lib) + # ADD_SUBDIRECTORY(library/cxl_ide_km_device_lib_sample) + # ADD_SUBDIRECTORY(library/spdm_transport_tcp_lib) + + if(NOT TOOLCHAIN STREQUAL "ARM_DS2022") + ADD_SUBDIRECTORY(spdm_caliptra/spdm_caliptra_requester) + ADD_SUBDIRECTORY(spdm_caliptra/spdm_caliptra_responder) + + #ADD_SUBDIRECTORY(${COMMON_TEST_FRAMEWORK_DIR}/library/common_test_utility_lib out/common_test_utility_lib.out) + #ADD_SUBDIRECTORY(${SPDM_RESPONDER_VALIDATOR_DIR}/library/spdm_responder_conformance_test_lib out/spdm_responder_conformance_test_lib.out) + #ADD_SUBDIRECTORY(spdm_emu/spdm_device_validator_sample) + + #ADD_SUBDIRECTORY(spdm_emu/spdm_device_attester_sample) + endif() diff --git a/verification/examples/spdm/include/library/mctp_common_lib.h b/verification/examples/spdm/include/library/mctp_common_lib.h new file mode 100644 index 00000000..b5be42bb --- /dev/null +++ b/verification/examples/spdm/include/library/mctp_common_lib.h @@ -0,0 +1,24 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md + **/ + +#ifndef __MCTP_COMMON_LIB_H__ +#define __MCTP_COMMON_LIB_H__ + +#include "industry_standard/mctp.h" +#include "industry_standard/pldm.h" + + +/* MCTP app message - check below configuration + * only PLDM*/ +#define MCTP_MAX_MESSAGE_SIZE 0x100 + +/* defintion for library*/ +typedef struct { + uint8_t pldm_type; /* BIT[0:5] type, BIT[6:7] RSVD*/ + uint8_t pldm_command_code; +} pldm_dispatch_type_t; + +#endif diff --git a/verification/examples/spdm/include/library/mctp_requester_lib.h b/verification/examples/spdm/include/library/mctp_requester_lib.h new file mode 100644 index 00000000..b49662d0 --- /dev/null +++ b/verification/examples/spdm/include/library/mctp_requester_lib.h @@ -0,0 +1,58 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md + **/ + +#ifndef __MCTP_REQUESTER_LIB_H__ +#define __MCTP_REQUESTER_LIB_H__ + +#include "library/mctp_common_lib.h" + +libspdm_return_t pldm_control_get_tid(const void *mctp_context, + void *spdm_context, const uint32_t *session_id, uint8_t *tid); + +/* internal function only*/ + +/** + * Send and receive an MCTP message + * + * @param spdm_context A pointer to the SPDM context. + * @param session_id Indicates if it is a secured message protected via SPDM session. + * If session_id is NULL, it is a normal message. + * If session_id is NOT NULL, it is a secured message. + * @param request the MCTP request message, start after mctp_message_header_t, e.g. pldm_message_header_t. + * @param request_size size in bytes of request. + * @param response the MCTP response message, start after mctp_message_header_t, e.g. pldm_message_header_t. + * @param response_size size in bytes of response. + * + * @retval LIBSPDM_STATUS_SUCCESS The MCTP request is sent and response is received. + * @return ERROR The MCTP response is not received correctly. + **/ +libspdm_return_t mctp_send_receive_data (const void *mctp_context, + void *spdm_context, const uint32_t *session_id, + mctp_message_header_t mctp_header, + const void *request, size_t request_size, + void *response, size_t *response_size); + +/** + * Send and receive an PLDM message + * + * @param spdm_context A pointer to the SPDM context. + * @param session_id Indicates if it is a secured message protected via SPDM session. + * If session_id is NULL, it is a normal message. + * If session_id is NOT NULL, it is a secured message. + * @param request the PLDM request message, start from pldm_message_header_t. + * @param request_size size in bytes of request. + * @param response the PLDM response message, start from pldm_message_header_t. + * @param response_size size in bytes of response. + * + * @retval LIBSPDM_STATUS_SUCCESS The PLDM request is sent and response is received. + * @return ERROR The PLDM response is not received correctly. + **/ +libspdm_return_t pldm_send_receive_data (const void *mctp_context, + void *spdm_context, const uint32_t *session_id, + const void *request, size_t request_size, + void *response, size_t *response_size); + +#endif diff --git a/verification/examples/spdm/include/library/mctp_responder_lib.h b/verification/examples/spdm/include/library/mctp_responder_lib.h new file mode 100644 index 00000000..422dc7cf --- /dev/null +++ b/verification/examples/spdm/include/library/mctp_responder_lib.h @@ -0,0 +1,101 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md + **/ + +#ifndef __MCTP_RESPONDER_LIB_H__ +#define __MCTP_RESPONDER_LIB_H__ + +#include "library/mctp_common_lib.h" + +/** + * Process the MCTP request and return the response. + * + * @param request the MCTP request message, start from mctp_message_header_t. + * @param request_size size in bytes of request. + * @param response the MCTP response message, start from mctp_message_header_t. + * @param response_size size in bytes of response. + * + * @retval LIBSPDM_STATUS_SUCCESS The request is processed and the response is returned. + * @return ERROR The request is not processed. + **/ +libspdm_return_t mctp_get_response_secured_app_request(const void *mctp_context, + void *spdm_context, + const uint32_t *session_id, + const void *request, size_t request_size, + void *response, size_t *response_size); + +/* internal function only*/ + +/** + * Process the MCTP request and return the response. + * + * @param request the MCTP request message, start after mctp_message_header_t, e.g. pldm_message_header_t. + * @param request_size size in bytes of request. + * @param response the MCTP response message, start after mctp_message_header_t, e.g. pldm_message_header_t. + * @param response_size size in bytes of response. + * + * @retval LIBSPDM_STATUS_SUCCESS The request is processed and the response is returned. + * @return ERROR The request is not processed. + **/ +typedef + libspdm_return_t +(* mctp_get_secured_app_request_func_t) (const void *mctp_context, + const void *spdm_context, const uint32_t *session_id, + const void *request, size_t request_size, + void *response, size_t *response_size); + +/** + * Process the PLDM request and return the response. + * + * @param request the PLDM request message, start from pldm_message_header_t. + * @param request_size size in bytes of request. + * @param response the PLDM response message, start from pldm_message_header_t. + * @param response_size size in bytes of response. + * + * @retval LIBSPDM_STATUS_SUCCESS The request is processed and the response is returned. + * @return ERROR The request is not processed. + **/ +libspdm_return_t pldm_get_response_secured_app_request (const void *mctp_context, + const void *spdm_context, + const uint32_t *session_id, + const void *request, size_t request_size, + void *response, size_t *response_size); + +/** + * Process the PLDM request and return the response. + * + * @param request the PLDM request message, start from pldm_message_header_t. + * @param request_size size in bytes of request. + * @param response the PLDM response message, start from pldm_message_header_t. + * @param response_size size in bytes of response. + * + * @retval LIBSPDM_STATUS_SUCCESS The request is processed and the response is returned. + * @return ERROR The request is not processed. + **/ +typedef + libspdm_return_t +(* pldm_get_secured_app_request_func_t) (const void *mctp_context, + const void *spdm_context, const uint32_t *session_id, + const void *request, size_t request_size, + void *response, size_t *response_size); + +/** + * Process the PLDM request and return the response. + * + * @param request the PLDM request message, start from pldm_message_header_t. + * @param request_size size in bytes of request. + * @param response the PLDM response message, start from pldm_message_header_t. + * @param response_size size in bytes of response. + * + * @retval LIBSPDM_STATUS_SUCCESS The request is processed and the response is returned. + * @return ERROR The request is not processed. + **/ +libspdm_return_t pldm_get_response_control_get_tid (const void *mctp_context, + const void *spdm_context, + const uint32_t *session_id, + const void *request, size_t request_size, + void *response, size_t *response_size); + +#endif diff --git a/verification/examples/spdm/library/mctp_requester_lib/CMakeLists.txt b/verification/examples/spdm/library/mctp_requester_lib/CMakeLists.txt new file mode 100644 index 00000000..9b8b33e3 --- /dev/null +++ b/verification/examples/spdm/library/mctp_requester_lib/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 2.6) + +INCLUDE_DIRECTORIES(${LIBSPDM_DIR}/include + ${SPDM_CALIPTRA_DIR}/include +) + +SET(src_mctp_requester_lib + mctp_send_receive.c + pldm_send_receive.c + pldm_req_control_get_tid.c +) + +ADD_LIBRARY(mctp_requester_lib STATIC ${src_mctp_requester_lib}) diff --git a/verification/examples/spdm/library/mctp_requester_lib/mctp_send_receive.c b/verification/examples/spdm/library/mctp_requester_lib/mctp_send_receive.c new file mode 100644 index 00000000..a9967a4e --- /dev/null +++ b/verification/examples/spdm/library/mctp_requester_lib/mctp_send_receive.c @@ -0,0 +1,82 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md + **/ + +#include "hal/base.h" +#include "hal/library/memlib.h" +#include "hal/library/debuglib.h" +#include "library/spdm_requester_lib.h" +#include "library/spdm_transport_mctp_lib.h" +#include "library/mctp_requester_lib.h" + +/** + * Send and receive an MCTP message + * + * @param spdm_context A pointer to the SPDM context. + * @param session_id Indicates if it is a secured message protected via SPDM session. + * If session_id is NULL, it is a normal message. + * If session_id is NOT NULL, it is a secured message. + * @param request the MCTP request message, start after mctp_message_header_t, e.g. pldm_message_header_t. + * @param request_size size in bytes of request. + * @param response the MCTP response message, start after mctp_message_header_t, e.g. pldm_message_header_t. + * @param response_size size in bytes of response. + * + * @retval LIBSPDM_STATUS_SUCCESS The MCTP request is sent and response is received. + * @return ERROR The MCTP response is not received correctly. + **/ +libspdm_return_t mctp_send_receive_data (const void *mctp_context, + void *spdm_context, const uint32_t *session_id, + mctp_message_header_t mctp_header, + const void *request, size_t request_size, + void *response, size_t *response_size) +{ + libspdm_data_parameter_t parameter; + spdm_version_number_t spdm_version; + size_t data_size; + libspdm_return_t status; + uint8_t request_buffer[sizeof(mctp_message_header_t) + MCTP_MAX_MESSAGE_SIZE]; + mctp_message_header_t *mctp_request; + size_t mctp_request_size; + uint8_t response_buffer[sizeof(mctp_message_header_t) + MCTP_MAX_MESSAGE_SIZE]; + mctp_message_header_t *mctp_response; + size_t mctp_response_size; + + mctp_request = (void *)request_buffer; + mctp_response = (void *)response_buffer; + LIBSPDM_ASSERT (request_size <= MCTP_MAX_MESSAGE_SIZE); + LIBSPDM_ASSERT (*response_size < MCTP_MAX_MESSAGE_SIZE); + + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_CONNECTION; + data_size = sizeof(spdm_version); + libspdm_zero_mem(&spdm_version, sizeof(spdm_version)); + libspdm_get_data(spdm_context, LIBSPDM_DATA_SPDM_VERSION, ¶meter, + &spdm_version, &data_size); + + libspdm_zero_mem(mctp_request, sizeof(mctp_message_header_t)); + mctp_request->message_type = mctp_header.message_type; + libspdm_copy_mem(mctp_request + 1, request_size, request, request_size); + + mctp_request_size = sizeof(mctp_message_header_t) + request_size; + mctp_response_size = sizeof(mctp_message_header_t) + (*response_size); + status = libspdm_send_receive_data(spdm_context, session_id, + true, mctp_request, mctp_request_size, + mctp_response, &mctp_response_size); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + return status; + } + + if (mctp_response_size < sizeof(mctp_message_header_t)) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + if (mctp_response->message_type != mctp_request->message_type) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + + *response_size = mctp_response_size - sizeof(mctp_message_header_t); + libspdm_copy_mem (response, *response_size, mctp_response + 1, *response_size); + + return LIBSPDM_STATUS_SUCCESS; +} diff --git a/verification/examples/spdm/library/mctp_requester_lib/pldm_req_control_get_tid.c b/verification/examples/spdm/library/mctp_requester_lib/pldm_req_control_get_tid.c new file mode 100644 index 00000000..ff738df4 --- /dev/null +++ b/verification/examples/spdm/library/mctp_requester_lib/pldm_req_control_get_tid.c @@ -0,0 +1,67 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md + **/ + +#include "hal/base.h" +#include "hal/library/memlib.h" +#include "library/spdm_requester_lib.h" +#include "library/spdm_transport_mctp_lib.h" +#include "library/mctp_requester_lib.h" + +libspdm_return_t pldm_control_get_tid(const void *mctp_context, + void *spdm_context, const uint32_t *session_id, uint8_t *tid) +{ + libspdm_return_t status; + pldm_get_tid_request_t app_request; + pldm_get_tid_response_t app_response; + size_t app_response_size; + uint8_t instance_id = 0; + + libspdm_zero_mem (&app_request, sizeof(app_request)); + app_request.pldm_header.instance_id = instance_id | PLDM_HEADER_REQUEST_MASK; + app_request.pldm_header.pldm_type = PLDM_MESSAGE_TYPE_CONTROL_DISCOVERY; + app_request.pldm_header.pldm_command_code = PLDM_CONTROL_DISCOVERY_COMMAND_GET_TID; + + app_response_size = sizeof(app_response); + status = pldm_send_receive_data(mctp_context, + spdm_context, session_id, + &app_request, + sizeof(app_request), + &app_response, + &app_response_size); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + return status; + } + + if (app_response_size != sizeof(app_response)) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + if ((app_response.pldm_header.instance_id & PLDM_HEADER_REQUEST_MASK) != 0) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + if ((app_response.pldm_header.instance_id & PLDM_HEADER_DATAGRAM_MASK) != 0) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + if ((app_response.pldm_header.instance_id & PLDM_HEADER_INSTANCE_ID_MASK) != instance_id) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + if ((app_response.pldm_header.pldm_type & PLDM_HEADER_VERSION_MASK) != PLDM_HEADER_VERSION) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + if ((app_response.pldm_header.pldm_type & PLDM_HEADER_TYPE_MASK) != + PLDM_MESSAGE_TYPE_CONTROL_DISCOVERY) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + if (app_response.pldm_header.pldm_command_code != + PLDM_CONTROL_DISCOVERY_COMMAND_GET_TID) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + if (app_response.pldm_response_header.pldm_completion_code != + PLDM_BASE_CODE_SUCCESS) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + + return LIBSPDM_STATUS_SUCCESS; +} diff --git a/verification/examples/spdm/library/mctp_requester_lib/pldm_send_receive.c b/verification/examples/spdm/library/mctp_requester_lib/pldm_send_receive.c new file mode 100644 index 00000000..75e254dd --- /dev/null +++ b/verification/examples/spdm/library/mctp_requester_lib/pldm_send_receive.c @@ -0,0 +1,45 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md + **/ + +#include "hal/base.h" +#include "hal/library/memlib.h" +#include "library/spdm_requester_lib.h" +#include "library/spdm_transport_mctp_lib.h" +#include "library/mctp_requester_lib.h" + +/** + * Send and receive an PLDM message + * + * @param spdm_context A pointer to the SPDM context. + * @param session_id Indicates if it is a secured message protected via SPDM session. + * If session_id is NULL, it is a normal message. + * If session_id is NOT NULL, it is a secured message. + * @param request the PLDM request message, start from pldm_message_header_t. + * @param request_size size in bytes of request. + * @param response the PLDM response message, start from pldm_message_header_t. + * @param response_size size in bytes of response. + * + * @retval LIBSPDM_STATUS_SUCCESS The PLDM request is sent and response is received. + * @return ERROR The PLDM response is not received correctly. + **/ +libspdm_return_t pldm_send_receive_data (const void *mctp_context, + void *spdm_context, const uint32_t *session_id, + const void *request, size_t request_size, + void *response, size_t *response_size) +{ + libspdm_return_t status; + mctp_message_header_t mctp_header; + + mctp_header.message_type = MCTP_MESSAGE_TYPE_PLDM; + status = mctp_send_receive_data (mctp_context, spdm_context, session_id, + mctp_header, + request, request_size, response, response_size); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + return status; + } + + return LIBSPDM_STATUS_SUCCESS; +} diff --git a/verification/examples/spdm/library/mctp_responder_lib/CMakeLists.txt b/verification/examples/spdm/library/mctp_responder_lib/CMakeLists.txt new file mode 100644 index 00000000..c85f9ee6 --- /dev/null +++ b/verification/examples/spdm/library/mctp_responder_lib/CMakeLists.txt @@ -0,0 +1,13 @@ +cmake_minimum_required(VERSION 2.6) + +INCLUDE_DIRECTORIES(${LIBSPDM_DIR}/include + ${SPDM_CALIPTRA_DIR}/include +) + +SET(src_mctp_responder_lib + mctp_dispatch.c + pldm_dispatch.c + pldm_rsp_control_get_tid.c +) + +ADD_LIBRARY(mctp_responder_lib STATIC ${src_mctp_responder_lib}) diff --git a/verification/examples/spdm/library/mctp_responder_lib/mctp_dispatch.c b/verification/examples/spdm/library/mctp_responder_lib/mctp_dispatch.c new file mode 100644 index 00000000..0bb55705 --- /dev/null +++ b/verification/examples/spdm/library/mctp_responder_lib/mctp_dispatch.c @@ -0,0 +1,77 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md + **/ + +#include "hal/base.h" +#include "hal/library/memlib.h" +#include "hal/library/debuglib.h" +#include "library/spdm_requester_lib.h" +#include "library/spdm_transport_mctp_lib.h" +#include "library/mctp_responder_lib.h" + +typedef struct { + mctp_message_header_t header; + mctp_get_secured_app_request_func_t func; +} mctp_secured_app_dispatch_struct_t; + +mctp_secured_app_dispatch_struct_t m_mctp_secured_app_dispatch[] = { + {{MCTP_MESSAGE_TYPE_PLDM}, pldm_get_response_secured_app_request }, +}; + +/** + * Process the MCTP request and return the response. + * + * @param request the MCTP request message, start from mctp_message_header_t. + * @param request_size size in bytes of request. + * @param response the MCTP response message, start from mctp_message_header_t. + * @param response_size size in bytes of response. + * + * @retval LIBSPDM_STATUS_SUCCESS The request is processed and the response is returned. + * @return ERROR The request is not processed. + **/ +libspdm_return_t mctp_get_response_secured_app_request(const void *mctp_context, + void *spdm_context, + const uint32_t *session_id, + const void *request, size_t request_size, + void *response, size_t *response_size) +{ + const mctp_message_header_t *app_request; + mctp_message_header_t *app_response; + size_t index; + size_t app_response_size; + libspdm_return_t status; + + app_request = request; + app_response = response; + if (request_size < sizeof(mctp_message_header_t)) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + LIBSPDM_ASSERT (*response_size > sizeof(mctp_message_header_t)); + app_response_size = *response_size - sizeof(mctp_message_header_t); + + for (index = 0; index < LIBSPDM_ARRAY_SIZE(m_mctp_secured_app_dispatch); index++) { + if (app_request->message_type == m_mctp_secured_app_dispatch[index].header.message_type) { + status = m_mctp_secured_app_dispatch[index].func ( + mctp_context, spdm_context, session_id, + (uint8_t *)request + sizeof(mctp_message_header_t), + request_size - sizeof(mctp_message_header_t), + (uint8_t *)response + sizeof(mctp_message_header_t), + &app_response_size + ); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + return status; + } + + libspdm_zero_mem (app_response, sizeof(mctp_message_header_t)); + app_response->message_type = app_request->message_type; + + *response_size = app_response_size + sizeof(mctp_message_header_t); + + return LIBSPDM_STATUS_SUCCESS; + } + } + + return LIBSPDM_STATUS_UNSUPPORTED_CAP; +} diff --git a/verification/examples/spdm/library/mctp_responder_lib/pldm_dispatch.c b/verification/examples/spdm/library/mctp_responder_lib/pldm_dispatch.c new file mode 100644 index 00000000..81cda763 --- /dev/null +++ b/verification/examples/spdm/library/mctp_responder_lib/pldm_dispatch.c @@ -0,0 +1,66 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md + **/ + +#include "hal/base.h" +#include "hal/library/memlib.h" +#include "library/spdm_requester_lib.h" +#include "library/spdm_transport_mctp_lib.h" +#include "library/mctp_responder_lib.h" + +typedef struct { + pldm_dispatch_type_t dispatch_type; + pldm_get_secured_app_request_func_t func; +} pldm_secured_app_dispatch_struct_t; + +pldm_secured_app_dispatch_struct_t m_pldm_secured_app_dispatch[] = { + {{PLDM_MESSAGE_TYPE_CONTROL_DISCOVERY, PLDM_CONTROL_DISCOVERY_COMMAND_GET_TID}, + pldm_get_response_control_get_tid }, +}; + +/** + * Process the PLDM request and return the response. + * + * @param request the PLDM request message, start from pldm_message_header_t. + * @param request_size size in bytes of request. + * @param response the PLDM response message, start from pldm_message_header_t. + * @param response_size size in bytes of response. + * + * @retval LIBSPDM_STATUS_SUCCESS The request is processed and the response is returned. + * @return ERROR The request is not processed. + **/ +libspdm_return_t pldm_get_response_secured_app_request(const void *mctp_context, + const void *spdm_context, + const uint32_t *session_id, + const void *request, size_t request_size, + void *response, size_t *response_size) +{ + const pldm_message_header_t *app_request; + size_t index; + + app_request = request; + if (request_size < sizeof(pldm_message_header_t)) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + if ((app_request->instance_id & PLDM_HEADER_REQUEST_MASK) == 0) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + if ((app_request->pldm_type & PLDM_HEADER_VERSION_MASK) != PLDM_HEADER_VERSION) { + return LIBSPDM_STATUS_INVALID_MSG_FIELD; + } + + for (index = 0; index < LIBSPDM_ARRAY_SIZE(m_pldm_secured_app_dispatch); index++) { + if (((app_request->pldm_type & PLDM_HEADER_TYPE_MASK) == + m_pldm_secured_app_dispatch[index].dispatch_type.pldm_type) && + (app_request->pldm_command_code == + m_pldm_secured_app_dispatch[index].dispatch_type.pldm_command_code)) { + return m_pldm_secured_app_dispatch[index].func ( + mctp_context, spdm_context, session_id, + request, request_size, response, response_size); + } + } + + return LIBSPDM_STATUS_UNSUPPORTED_CAP; +} diff --git a/verification/examples/spdm/library/mctp_responder_lib/pldm_rsp_control_get_tid.c b/verification/examples/spdm/library/mctp_responder_lib/pldm_rsp_control_get_tid.c new file mode 100644 index 00000000..3dd22eb0 --- /dev/null +++ b/verification/examples/spdm/library/mctp_responder_lib/pldm_rsp_control_get_tid.c @@ -0,0 +1,54 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md + **/ + +#include "hal/base.h" +#include "hal/library/memlib.h" +#include "hal/library/debuglib.h" +#include "library/spdm_requester_lib.h" +#include "library/spdm_transport_mctp_lib.h" +#include "library/mctp_responder_lib.h" + +/** + * Process the PLDM request and return the response. + * + * @param request the PLDM request message, start from pldm_message_header_t. + * @param request_size size in bytes of request. + * @param response the PLDM response message, start from pldm_message_header_t. + * @param response_size size in bytes of response. + * + * @retval LIBSPDM_STATUS_SUCCESS The request is processed and the response is returned. + * @return ERROR The request is not processed. + **/ +libspdm_return_t pldm_get_response_control_get_tid (const void *mctp_context, + const void *spdm_context, + const uint32_t *session_id, + const void *request, size_t request_size, + void *response, size_t *response_size) +{ + const pldm_get_tid_request_t *app_request; + pldm_get_tid_response_t *app_response; + + app_request = request; + if (request_size != sizeof(pldm_get_tid_request_t)) { + return LIBSPDM_STATUS_INVALID_MSG_SIZE; + } + LIBSPDM_ASSERT (*response_size >= sizeof(pldm_get_tid_response_t)); + *response_size = sizeof(pldm_get_tid_response_t); + + libspdm_zero_mem (response, *response_size); + + app_response = response; + app_response->pldm_header.instance_id = app_request->pldm_header.instance_id & + PLDM_HEADER_INSTANCE_ID_MASK; + app_response->pldm_header.pldm_type = app_request->pldm_header.pldm_type; /* both version and type*/ + app_response->pldm_header.pldm_command_code = app_request->pldm_header.pldm_command_code; + app_response->pldm_response_header.pldm_completion_code = PLDM_BASE_CODE_SUCCESS; + + /* TBD - need PLDM context to get the info*/ + app_response->tid = 1; + + return LIBSPDM_STATUS_SUCCESS; +} diff --git a/verification/examples/spdm/libspdm b/verification/examples/spdm/libspdm new file mode 160000 index 00000000..2756b67e --- /dev/null +++ b/verification/examples/spdm/libspdm @@ -0,0 +1 @@ +Subproject commit 2756b67e0fcdee9abf8de109092255c83e9256ca diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/command.c b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/command.c new file mode 100644 index 00000000..12bcb2ec --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/command.c @@ -0,0 +1,353 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#include "spdm_caliptra.h" + +/* hack to add MCTP header for PCAP*/ +#include "industry_standard/mctp.h" + +uint32_t m_use_transport_layer = SOCKET_TRANSPORT_TYPE_MCTP; + +uint32_t m_use_tcp_handshake = SOCKET_TCP_NO_HANDSHAKE; + +bool m_send_receive_buffer_acquired = false; +uint8_t m_send_receive_buffer[LIBSPDM_MAX_SENDER_RECEIVER_BUFFER_SIZE]; +size_t m_send_receive_buffer_size; + +/** + * Read number of bytes data in blocking mode. + * + * If there is no enough data in socket, this function will wait. + * This function will return if enough data is read, or socket error. + **/ +bool read_bytes(const SOCKET socket, uint8_t *buffer, + uint32_t number_of_bytes) +{ + int32_t result; + uint32_t number_received; + + number_received = 0; + while (number_received < number_of_bytes) { + result = recv(socket, (char *)(buffer + number_received), + number_of_bytes - number_received, 0); + if (result == -1) { + printf("Receive error - 0x%x\n", +#ifdef _MSC_VER + WSAGetLastError() +#else + errno +#endif + ); + return false; + } + if (result == 0) { + return false; + } + number_received += result; + } + return true; +} + +bool read_data32(const SOCKET socket, uint32_t *data) +{ + bool result; + + result = read_bytes(socket, (uint8_t *)data, sizeof(uint32_t)); + if (!result) { + return result; + } + *data = ntohl(*data); + return true; +} + +/** + * Read multiple bytes in blocking mode. + * + * The length is presented as first 4 bytes in big endian. + * The data follows the length. + * + * If there is no enough data in socket, this function will wait. + * This function will return if enough data is read, or socket error. + **/ +bool read_multiple_bytes(const SOCKET socket, uint8_t *buffer, + uint32_t *bytes_received, + uint32_t max_buffer_length) +{ + uint32_t length; + bool result; + + result = read_data32(socket, &length); + if (!result) { + return result; + } + printf("Platform port Receive size: "); + length = ntohl(length); + dump_data((uint8_t *)&length, sizeof(uint32_t)); + printf("\n"); + length = ntohl(length); + + *bytes_received = length; + if (*bytes_received > max_buffer_length) { + printf("buffer too small (0x%x). Expected - 0x%x\n", + max_buffer_length, *bytes_received); + return false; + } + if (length == 0) { + return true; + } + result = read_bytes(socket, buffer, length); + if (!result) { + return result; + } + printf("Platform port Receive buffer:\n "); + dump_data(buffer, length); + printf("\n"); + + return true; +} + +bool receive_platform_data(const SOCKET socket, uint32_t *command, + uint8_t *receive_buffer, + size_t *bytes_to_receive) +{ + bool result; + uint32_t response; + uint32_t transport_type; + uint32_t bytes_received; + + result = read_data32(socket, &response); + if (!result) { + return result; + } + *command = response; + printf("Platform port Receive command: "); + response = ntohl(response); + dump_data((uint8_t *)&response, sizeof(uint32_t)); + printf("\n"); + + result = read_data32(socket, &transport_type); + if (!result) { + return result; + } + printf("Platform port Receive transport_type: "); + transport_type = ntohl(transport_type); + dump_data((uint8_t *)&transport_type, sizeof(uint32_t)); + printf("\n"); + transport_type = ntohl(transport_type); + if (transport_type != m_use_transport_layer) { + printf("transport_type mismatch\n"); + return false; + } + + bytes_received = 0; + result = read_multiple_bytes(socket, receive_buffer, &bytes_received, + (uint32_t)*bytes_to_receive); + if (!result) { + return result; + } + if (bytes_received > (uint32_t)*bytes_to_receive) { + return false; + } + *bytes_to_receive = bytes_received; + + switch (*command) { + case SOCKET_SPDM_COMMAND_SHUTDOWN: + close_pcap_packet_file(); + break; + case SOCKET_SPDM_COMMAND_NORMAL: + if (m_use_transport_layer == SOCKET_TRANSPORT_TYPE_MCTP) { + + /* Append mctp_header_t for PCAP*/ + + mctp_header_t mctp_header; + mctp_header.header_version = 0; + mctp_header.destination_id = 0; + mctp_header.source_id = 0; + mctp_header.message_tag = 0xC0; + append_pcap_packet_data(&mctp_header, + sizeof(mctp_header), + receive_buffer, bytes_received); + } else { + append_pcap_packet_data(NULL, 0, receive_buffer, + bytes_received); + } + break; + } + + return result; +} + +/** + * Write number of bytes data in blocking mode. + * + * This function will return if data is written, or socket error. + **/ +bool write_bytes(const SOCKET socket, const uint8_t *buffer, + uint32_t number_of_bytes) +{ + int32_t result; + uint32_t number_sent; + + number_sent = 0; + while (number_sent < number_of_bytes) { + result = send(socket, (char *)(buffer + number_sent), + number_of_bytes - number_sent, 0); + if (result == -1) { +#ifdef _MSC_VER + if (WSAGetLastError() == 0x2745) { + printf("Client disconnected\n"); + } else { +#endif + printf("Send error - 0x%x\n", +#ifdef _MSC_VER + WSAGetLastError() +#else + errno +#endif + ); +#ifdef _MSC_VER + } +#endif + return false; + } + number_sent += result; + } + return true; +} + +bool write_data32(const SOCKET socket, uint32_t data) +{ + data = htonl(data); + return write_bytes(socket, (uint8_t *)&data, sizeof(uint32_t)); +} + +/** + * Write multiple bytes. + * + * The length is presented as first 4 bytes in big endian. + * The data follows the length. + **/ +bool write_multiple_bytes(const SOCKET socket, const uint8_t *buffer, + uint32_t bytes_to_send) +{ + bool result; + + result = write_data32(socket, bytes_to_send); + if (!result) { + return result; + } + printf("Platform port Transmit size: "); + bytes_to_send = htonl(bytes_to_send); + dump_data((uint8_t *)&bytes_to_send, sizeof(uint32_t)); + printf("\n"); + bytes_to_send = htonl(bytes_to_send); + + result = write_bytes(socket, buffer, bytes_to_send); + if (!result) { + return result; + } + printf("Platform port Transmit buffer:\n "); + dump_data(buffer, bytes_to_send); + printf("\n"); + return true; +} + +bool send_platform_data(const SOCKET socket, uint32_t command, + const uint8_t *send_buffer, size_t bytes_to_send) +{ + bool result; + uint32_t request; + uint32_t transport_type; + + request = command; + result = write_data32(socket, request); + if (!result) { + return result; + } + printf("Platform port Transmit command: "); + request = htonl(request); + dump_data((uint8_t *)&request, sizeof(uint32_t)); + printf("\n"); + + result = write_data32(socket, m_use_transport_layer); + if (!result) { + return result; + } + printf("Platform port Transmit transport_type: "); + transport_type = ntohl(m_use_transport_layer); + dump_data((uint8_t *)&transport_type, sizeof(uint32_t)); + printf("\n"); + + result = write_multiple_bytes(socket, send_buffer, + (uint32_t)bytes_to_send); + if (!result) { + return result; + } + + switch (command) { + case SOCKET_SPDM_COMMAND_SHUTDOWN: + close_pcap_packet_file(); + break; + case SOCKET_SPDM_COMMAND_NORMAL: + if (m_use_transport_layer == SOCKET_TRANSPORT_TYPE_MCTP) { + + /* Append mctp_header_t for PCAP*/ + + mctp_header_t mctp_header; + mctp_header.header_version = 0; + mctp_header.destination_id = 0; + mctp_header.source_id = 0; + mctp_header.message_tag = 0xC0; + append_pcap_packet_data(&mctp_header, + sizeof(mctp_header), + send_buffer, bytes_to_send); + } else { + append_pcap_packet_data(NULL, 0, send_buffer, + bytes_to_send); + } + break; + } + + return true; +} + +libspdm_return_t spdm_device_acquire_sender_buffer ( + void *context, void **msg_buf_ptr) +{ + LIBSPDM_ASSERT (!m_send_receive_buffer_acquired); + *msg_buf_ptr = m_send_receive_buffer; + libspdm_zero_mem (m_send_receive_buffer, sizeof(m_send_receive_buffer)); + m_send_receive_buffer_acquired = true; + return LIBSPDM_STATUS_SUCCESS; +} + +void spdm_device_release_sender_buffer ( + void *context, const void *msg_buf_ptr) +{ + LIBSPDM_ASSERT (m_send_receive_buffer_acquired); + LIBSPDM_ASSERT (msg_buf_ptr == m_send_receive_buffer); + m_send_receive_buffer_acquired = false; + return; +} + +libspdm_return_t spdm_device_acquire_receiver_buffer ( + void *context, void **msg_buf_ptr) +{ + LIBSPDM_ASSERT (!m_send_receive_buffer_acquired); + *msg_buf_ptr = m_send_receive_buffer; + libspdm_zero_mem (m_send_receive_buffer, sizeof(m_send_receive_buffer)); + m_send_receive_buffer_acquired = true; + return LIBSPDM_STATUS_SUCCESS; +} + +void spdm_device_release_receiver_buffer ( + void *context, const void *msg_buf_ptr) +{ + LIBSPDM_ASSERT (m_send_receive_buffer_acquired); + LIBSPDM_ASSERT (msg_buf_ptr == m_send_receive_buffer); + m_send_receive_buffer_acquired = false; + return; +} diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/command.h b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/command.h new file mode 100644 index 00000000..21755cbf --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/command.h @@ -0,0 +1,37 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#ifndef __SPDM_TEST_COMMAND_H__ +#define __SPDM_TEST_COMMAND_H__ + +#define DEFAULT_SPDM_PLATFORM_PORT 2323 +#define TCP_SPDM_PLATFORM_PORT 4194 +#define DPE_PROFILE_IROT_P256_SHA256 "DPE_PROFILE_IROT_P256_SHA256" +#define DPE_PROFILE_IROT_P384_SHA384 "DPE_PROFILE_IROT_P384_SHA384" + +/* Client->Server/Server->Client + * command/response: 4 bytes (big endian) + * transport_type: 4 bytes (big endian) + * PayloadSize (excluding command and PayloadSize): 4 bytes (big endian) + * payload (SPDM message, starting from SPDM_HEADER): PayloadSize (little endian)*/ + + +#define SOCKET_TRANSPORT_TYPE_NONE 0x00 +#define SOCKET_TRANSPORT_TYPE_MCTP 0x01 +#define SOCKET_TRANSPORT_TYPE_PCI_DOE 0x02 +#define SOCKET_TRANSPORT_TYPE_TCP 0x03 + +#define SOCKET_TCP_NO_HANDSHAKE 0x00 +#define SOCKET_TCP_HANDSHAKE 0x01 + +#define SOCKET_SPDM_COMMAND_NORMAL 0x0001 +#define SOCKET_SPDM_COMMAND_OOB_ENCAP_KEY_UPDATE 0x8001 +#define SOCKET_SPDM_COMMAND_CONTINUE 0xFFFD +#define SOCKET_SPDM_COMMAND_SHUTDOWN 0xFFFE +#define SOCKET_SPDM_COMMAND_UNKOWN 0xFFFF +#define SOCKET_SPDM_COMMAND_TEST 0xDEAD + +#endif diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/key.c b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/key.c new file mode 100644 index 00000000..b04a0f14 --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/key.c @@ -0,0 +1,198 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#include "spdm_caliptra.h" + +uint8_t m_use_version = SPDM_MESSAGE_VERSION_12; // Should be >= v1.2 for DICE certificate model support +uint8_t m_use_secured_message_version = 0; +uint32_t m_use_requester_capability_flags = + (0 | + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CERT_CAP | /* conflict with SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PUB_KEY_ID_CAP */ + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHAL_CAP | + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_ENCRYPT_CAP | + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MAC_CAP | + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MUT_AUTH_CAP | + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP | + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PSK_CAP_REQUESTER | + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_ENCAP_CAP | + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP | + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_UPD_CAP | + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP | + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP | + /* SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PUB_KEY_ID_CAP | conflict with SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CERT_CAP */ + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MULTI_KEY_CAP_NEG | + 0); +uint32_t m_use_responder_capability_flags = + (0 | SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CACHE_CAP | + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP | /* conflict with SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PUB_KEY_ID_CAP */ + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHAL_CAP | + /* SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP_NO_SIG | conflict with SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP_SIG */ + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP_SIG | /* conflict with SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP_NO_SIG */ + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_FRESH_CAP | + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ENCRYPT_CAP | + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MAC_CAP | + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MUT_AUTH_CAP | + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP | + /* SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP_RESPONDER | conflict with SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP_RESPONDER_WITH_CONTEXT */ + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP_RESPONDER_WITH_CONTEXT | /* conflict with SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP_RESPONDER */ + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ENCAP_CAP | + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP | + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_UPD_CAP | + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP | + /* SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PUB_KEY_ID_CAP | conflict with SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP */ + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP | + /* SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ALIAS_CERT_CAP | conflict with SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PUB_KEY_ID_CAP */ + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_SET_CERT_CAP | /* conflict with SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PUB_KEY_ID_CAP */ + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP | /* conflict with SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PUB_KEY_ID_CAP */ + /* SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_INSTALL_RESET_CAP | conflict with SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PUB_KEY_ID_CAP */ + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MULTI_KEY_CAP_NEG | + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_GET_KEY_PAIR_INFO_CAP | + 0); + +uint32_t m_use_capability_flags = 0; +uint32_t m_use_peer_capability_flags = 0; +/* + * 0 + * 1 + */ +uint8_t m_use_basic_mut_auth = 1; +/* + * 0 + * SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED, + * SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_ENCAP_REQUEST, + * SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_GET_DIGESTS + */ +uint8_t m_use_mut_auth = + SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_ENCAP_REQUEST; +/* + * SPDM_CHALLENGE_REQUEST_NO_MEASUREMENT_SUMMARY_HASH, + * SPDM_CHALLENGE_REQUEST_TCB_COMPONENT_MEASUREMENT_HASH, + * SPDM_CHALLENGE_REQUEST_ALL_MEASUREMENTS_HASH + */ +uint8_t m_use_measurement_summary_hash_type = + SPDM_CHALLENGE_REQUEST_ALL_MEASUREMENTS_HASH; +/* + * SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_TOTAL_NUMBER_OF_MEASUREMENTS, one by one + * SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_ALL_MEASUREMENTS + */ +uint8_t m_use_measurement_operation = + SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_TOTAL_NUMBER_OF_MEASUREMENTS; +/* + * 0 + * SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_RAW_BIT_STREAM_REQUESTED + */ +uint8_t m_use_measurement_attribute = 0; +uint8_t m_use_slot_id = 0; +uint8_t m_use_slot_count = 3; + +/* + * LIBSPDM_KEY_UPDATE_ACTION_REQUESTER + * LIBSPDM_KEY_UPDATE_ACTION_RESPONDER + * LIBSPDM_KEY_UPDATE_ACTION_MAX == REQUESTER + RESPONDER + */ +libspdm_key_update_action_t m_use_key_update_action = LIBSPDM_KEY_UPDATE_ACTION_MAX; + +uint32_t m_use_hash_algo; +uint32_t m_use_measurement_hash_algo; +uint32_t m_use_asym_algo; +uint16_t m_use_req_asym_algo; + +/* + * SPDM_MEASUREMENT_SPECIFICATION_DMTF, + */ +uint8_t m_support_measurement_spec = + SPDM_MEASUREMENT_SPECIFICATION_DMTF; +/* + * SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA3_512, + * SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA3_384, + * SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA3_256, + * SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA_512, + * SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA_384, + * SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA_256, + * SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_RAW_BIT_STREAM_ONLY, + */ +uint32_t m_support_measurement_hash_algo = + SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA_512 | + SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA_384 | + SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA_256; +/* + * SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_512, + * SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_384, + * SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_256, + */ +uint32_t m_support_hash_algo = SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_384 | + SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_256; +/* + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521, + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384, + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256, + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096, + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096, + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072, + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072, + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048, + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048, + */ +uint32_t m_support_asym_algo = + SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384 | + SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256; +/* + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096, + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096, + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072, + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072, + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048, + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048, + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521, + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384, + * SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256, + */ +uint16_t m_support_req_asym_algo = + SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072 | + SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048 | + SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072 | + SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048; +/* + * SPDM_ALGORITHMS_DHE_NAMED_GROUP_FFDHE_4096, + * SPDM_ALGORITHMS_DHE_NAMED_GROUP_FFDHE_3072, + * SPDM_ALGORITHMS_DHE_NAMED_GROUP_FFDHE_2048, + * SPDM_ALGORITHMS_DHE_NAMED_GROUP_SECP_521_R1, + * SPDM_ALGORITHMS_DHE_NAMED_GROUP_SECP_384_R1, + * SPDM_ALGORITHMS_DHE_NAMED_GROUP_SECP_256_R1, + */ +uint16_t m_support_dhe_algo = SPDM_ALGORITHMS_DHE_NAMED_GROUP_SECP_384_R1 | + SPDM_ALGORITHMS_DHE_NAMED_GROUP_SECP_256_R1 | + SPDM_ALGORITHMS_DHE_NAMED_GROUP_FFDHE_3072 | + SPDM_ALGORITHMS_DHE_NAMED_GROUP_FFDHE_2048; +/* + * SPDM_ALGORITHMS_AEAD_CIPHER_SUITE_AES_256_GCM, + * SPDM_ALGORITHMS_AEAD_CIPHER_SUITE_AES_128_GCM, + * SPDM_ALGORITHMS_AEAD_CIPHER_SUITE_CHACHA20_POLY1305, + */ +uint16_t m_support_aead_algo = + SPDM_ALGORITHMS_AEAD_CIPHER_SUITE_AES_256_GCM | + SPDM_ALGORITHMS_AEAD_CIPHER_SUITE_CHACHA20_POLY1305; +/* + * SPDM_ALGORITHMS_KEY_SCHEDULE_HMAC_HASH, + */ +uint16_t m_support_key_schedule_algo = SPDM_ALGORITHMS_KEY_SCHEDULE_HMAC_HASH; +/* + * SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1, + */ +uint8_t m_support_other_params_support = + SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1 | + SPDM_ALGORITHMS_MULTI_KEY_CONN; +/* + * SPDM_MEL_SPECIFICATION_DMTF, + */ +uint8_t m_support_mel_spec = + SPDM_MEL_SPECIFICATION_DMTF; + +uint8_t m_session_policy = + SPDM_KEY_EXCHANGE_REQUEST_SESSION_POLICY_TERMINATION_POLICY_RUNTIME_UPDATE; + +uint8_t m_end_session_attributes = + SPDM_END_SESSION_REQUEST_ATTRIBUTES_PRESERVE_NEGOTIATED_STATE_CLEAR; diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/nv_storage.c b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/nv_storage.c new file mode 100644 index 00000000..05391372 --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/nv_storage.c @@ -0,0 +1,552 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#include "spdm_caliptra.h" + +char *m_load_state_file_name; +char *m_save_state_file_name; + +static inline bool libspdm_onehot0(uint32_t mask) +{ + return !mask || !(mask & (mask - 1)); +} + +libspdm_return_t spdm_provision_psk_version_only(void *spdm_context, + bool is_requester) +{ + libspdm_data_parameter_t parameter; + uint8_t data8; + uint16_t data16; + uint32_t data32; + size_t data_size; + spdm_version_number_t spdm_version; + + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_CONNECTION; + + /* make sure it is called after GET_VERSION */ + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_CONNECTION_STATE, ¶meter, + &data32, &data_size); + LIBSPDM_ASSERT(data32 == LIBSPDM_CONNECTION_STATE_AFTER_VERSION); + + if (is_requester) + { + /* get version from requester, because it is negotiated */ + data_size = sizeof(spdm_version); + libspdm_get_data(spdm_context, LIBSPDM_DATA_SPDM_VERSION, ¶meter, + &spdm_version, &data_size); + m_use_version = spdm_version >> SPDM_VERSION_NUMBER_SHIFT_BIT; + } + else + { + /* set version for responder, because it cannot be negotiated */ + spdm_version = m_use_version << SPDM_VERSION_NUMBER_SHIFT_BIT; + libspdm_set_data(spdm_context, LIBSPDM_DATA_SPDM_VERSION, ¶meter, + &spdm_version, sizeof(spdm_version)); + } + + if (m_use_version == 0) + { + printf("spdm_version is unknown, please provision it as well.\n"); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + + /* Set connection info*/ + + data8 = 0; + libspdm_set_data(spdm_context, LIBSPDM_DATA_CAPABILITY_CT_EXPONENT, + ¶meter, &data8, sizeof(data8)); + if (is_requester) + { + /* set responder's cap for requester */ + data32 = m_use_responder_capability_flags; + if (m_use_peer_capability_flags != 0) + { + data32 = m_use_peer_capability_flags; + m_use_responder_capability_flags = m_use_peer_capability_flags; + } + } + else + { + /* set requester's cap for responder */ + data32 = m_use_requester_capability_flags; + if (m_use_peer_capability_flags != 0) + { + data32 = m_use_peer_capability_flags; + m_use_requester_capability_flags = m_use_peer_capability_flags; + } + } + libspdm_set_data(spdm_context, LIBSPDM_DATA_CAPABILITY_FLAGS, ¶meter, + &data32, sizeof(data32)); + + if (!libspdm_onehot0(m_support_measurement_spec)) + { + printf("measurement_spec has more bit set - 0x%02x\n", m_support_measurement_spec); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + data8 = m_support_measurement_spec; + libspdm_set_data(spdm_context, LIBSPDM_DATA_MEASUREMENT_SPEC, ¶meter, + &data8, sizeof(data8)); + + if (!libspdm_onehot0(m_support_measurement_hash_algo)) + { + printf("measurement_hash_algo has more bit set - 0x%08x\n", + m_support_measurement_hash_algo); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + data32 = m_support_measurement_hash_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_MEASUREMENT_HASH_ALGO, ¶meter, + &data32, sizeof(data32)); + + if (!libspdm_onehot0(m_support_asym_algo)) + { + printf("base_asym_algo has more bit set - 0x%08x\n", m_support_asym_algo); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + data32 = m_support_asym_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_BASE_ASYM_ALGO, ¶meter, + &data32, sizeof(data32)); + + if (!libspdm_onehot0(m_support_hash_algo)) + { + printf("base_hash_algo has more bit set - 0x%08x\n", m_support_hash_algo); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + data32 = m_support_hash_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_BASE_HASH_ALGO, ¶meter, + &data32, sizeof(data32)); + + if (m_use_version >= SPDM_MESSAGE_VERSION_11) + { + if (!libspdm_onehot0(m_support_dhe_algo)) + { + printf("dhe_algo has more bit set - 0x%04x\n", m_support_dhe_algo); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + data16 = m_support_dhe_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_DHE_NAME_GROUP, + ¶meter, &data16, sizeof(data16)); + + if (!libspdm_onehot0(m_support_aead_algo)) + { + printf("aead_algo has more bit set - 0x%04x\n", m_support_aead_algo); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + data16 = m_support_aead_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_AEAD_CIPHER_SUITE, + ¶meter, &data16, sizeof(data16)); + + if (!libspdm_onehot0(m_support_req_asym_algo)) + { + printf("req_asym_algo has more bit set - 0x%04x\n", m_support_req_asym_algo); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + data16 = m_support_req_asym_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_REQ_BASE_ASYM_ALG, + ¶meter, &data16, sizeof(data16)); + + if (!libspdm_onehot0(m_support_key_schedule_algo)) + { + printf("key_schedule_algo has more bit set - 0x%04x\n", m_support_key_schedule_algo); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + data16 = m_support_key_schedule_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_KEY_SCHEDULE, ¶meter, + &data16, sizeof(data16)); + + if (m_use_version >= SPDM_MESSAGE_VERSION_12) + { + if (!libspdm_onehot0(m_support_other_params_support)) + { + printf("other_params has more bit set - 0x%02x\n", m_support_other_params_support); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + data8 = m_support_other_params_support; + libspdm_set_data(spdm_context, LIBSPDM_DATA_OTHER_PARAMS_SUPPORT, ¶meter, + &data8, sizeof(data8)); + if (m_use_version >= SPDM_MESSAGE_VERSION_13) + { + if (!libspdm_onehot0(m_support_mel_spec)) + { + printf("mel_spec has more bit set - 0x%02x\n", m_support_mel_spec); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + data8 = m_support_mel_spec; + libspdm_set_data(spdm_context, LIBSPDM_DATA_MEL_SPEC, ¶meter, + &data8, sizeof(data8)); + } + } + } + else + { + data16 = 0; + libspdm_set_data(spdm_context, LIBSPDM_DATA_DHE_NAME_GROUP, + ¶meter, &data16, sizeof(data16)); + data16 = 0; + libspdm_set_data(spdm_context, LIBSPDM_DATA_AEAD_CIPHER_SUITE, + ¶meter, &data16, sizeof(data16)); + data16 = 0; + libspdm_set_data(spdm_context, LIBSPDM_DATA_REQ_BASE_ASYM_ALG, + ¶meter, &data16, sizeof(data16)); + data16 = 0; + libspdm_set_data(spdm_context, LIBSPDM_DATA_KEY_SCHEDULE, ¶meter, + &data16, sizeof(data16)); + } + + /* PSK version only - set to NEGOTIATED */ + data32 = LIBSPDM_CONNECTION_STATE_NEGOTIATED; + libspdm_set_data(spdm_context, LIBSPDM_DATA_CONNECTION_STATE, ¶meter, + &data32, sizeof(data32)); + + return LIBSPDM_STATUS_SUCCESS; +} + +/** + * Load the negotiated_state from NV storage to an SPDM context. + */ +libspdm_return_t spdm_load_negotiated_state(void *spdm_context, + bool is_requester) +{ + bool ret; + void *file_data; + size_t file_size; + spdm_negotiated_state_struct_t negotiated_state; + libspdm_data_parameter_t parameter; + uint8_t data8; + uint16_t data16; + uint32_t data32; + spdm_version_number_t spdm_version; + + if (m_load_state_file_name == NULL) + { + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + ret = libspdm_read_input_file(m_load_state_file_name, &file_data, &file_size); + if (!ret) + { + printf("LoadState fail - read file error\n"); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + + if (file_size != sizeof(negotiated_state)) + { + printf("LoadState fail - size mismatch\n"); + free(file_data); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + + libspdm_copy_mem(&negotiated_state, file_size, file_data, file_size); + free(file_data); + + if (negotiated_state.version != SPDM_NEGOTIATED_STATE_STRUCT_VERSION) + { + printf("LoadState fail - version mismatch\n"); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + + printf("LoadState from %s\n", m_load_state_file_name); + + /* Override local setting*/ + + m_use_version = negotiated_state.spdm_version; + m_use_requester_capability_flags = negotiated_state.requester_cap_flags; + m_use_responder_capability_flags = negotiated_state.responder_cap_flags; + if (is_requester) + { + m_use_capability_flags = negotiated_state.requester_cap_flags; + } + else + { + m_use_capability_flags = negotiated_state.responder_cap_flags; + } + m_support_measurement_spec = negotiated_state.measurement_spec; + m_support_measurement_hash_algo = + negotiated_state.measurement_hash_algo; + m_support_asym_algo = negotiated_state.base_asym_algo; + m_support_hash_algo = negotiated_state.base_hash_algo; + m_support_dhe_algo = negotiated_state.dhe_named_group; + m_support_aead_algo = negotiated_state.aead_cipher_suite; + m_support_req_asym_algo = negotiated_state.req_base_asym_alg; + m_support_key_schedule_algo = negotiated_state.key_schedule; + m_support_other_params_support = negotiated_state.other_params_support; + m_support_mel_spec = negotiated_state.mel_spec; + + /* Set connection info*/ + + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_CONNECTION; + + libspdm_set_data(spdm_context, LIBSPDM_DATA_IS_REQUESTER, ¶meter, + &is_requester, sizeof(is_requester)); + + spdm_version = m_use_version << SPDM_VERSION_NUMBER_SHIFT_BIT; + libspdm_set_data(spdm_context, LIBSPDM_DATA_SPDM_VERSION, ¶meter, + &spdm_version, sizeof(spdm_version)); + + data8 = 0; + libspdm_set_data(spdm_context, LIBSPDM_DATA_CAPABILITY_CT_EXPONENT, + ¶meter, &data8, sizeof(data8)); + if (is_requester) + { + data32 = negotiated_state.responder_cap_flags; + } + else + { + data32 = negotiated_state.requester_cap_flags; + } + libspdm_set_data(spdm_context, LIBSPDM_DATA_CAPABILITY_FLAGS, ¶meter, + &data32, sizeof(data32)); + + data8 = m_support_measurement_spec; + libspdm_set_data(spdm_context, LIBSPDM_DATA_MEASUREMENT_SPEC, ¶meter, + &data8, sizeof(data8)); + data32 = m_support_measurement_hash_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_MEASUREMENT_HASH_ALGO, ¶meter, + &data32, sizeof(data32)); + data32 = m_support_asym_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_BASE_ASYM_ALGO, ¶meter, + &data32, sizeof(data32)); + data32 = m_support_hash_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_BASE_HASH_ALGO, ¶meter, + &data32, sizeof(data32)); + if (m_use_version >= SPDM_MESSAGE_VERSION_11) + { + data16 = m_support_dhe_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_DHE_NAME_GROUP, + ¶meter, &data16, sizeof(data16)); + data16 = m_support_aead_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_AEAD_CIPHER_SUITE, + ¶meter, &data16, sizeof(data16)); + data16 = m_support_req_asym_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_REQ_BASE_ASYM_ALG, + ¶meter, &data16, sizeof(data16)); + data16 = m_support_key_schedule_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_KEY_SCHEDULE, ¶meter, + &data16, sizeof(data16)); + if (m_use_version >= SPDM_MESSAGE_VERSION_12) + { + data8 = m_support_other_params_support; + libspdm_set_data(spdm_context, LIBSPDM_DATA_OTHER_PARAMS_SUPPORT, ¶meter, + &data8, sizeof(data8)); + if (m_use_version >= SPDM_MESSAGE_VERSION_13) + { + data8 = m_support_mel_spec; + libspdm_set_data(spdm_context, LIBSPDM_DATA_MEL_SPEC, ¶meter, + &data8, sizeof(data8)); + } + } + libspdm_set_data(spdm_context, LIBSPDM_DATA_VCA_CACHE, ¶meter, + negotiated_state.vca_buffer, negotiated_state.vca_buffer_size); + } + else + { + data16 = 0; + libspdm_set_data(spdm_context, LIBSPDM_DATA_DHE_NAME_GROUP, + ¶meter, &data16, sizeof(data16)); + data16 = 0; + libspdm_set_data(spdm_context, LIBSPDM_DATA_AEAD_CIPHER_SUITE, + ¶meter, &data16, sizeof(data16)); + data16 = 0; + libspdm_set_data(spdm_context, LIBSPDM_DATA_REQ_BASE_ASYM_ALG, + ¶meter, &data16, sizeof(data16)); + data16 = 0; + libspdm_set_data(spdm_context, LIBSPDM_DATA_KEY_SCHEDULE, ¶meter, + &data16, sizeof(data16)); + } + + /* Set connection state finally.*/ + + data32 = LIBSPDM_CONNECTION_STATE_NEGOTIATED; + libspdm_set_data(spdm_context, LIBSPDM_DATA_CONNECTION_STATE, ¶meter, + &data32, sizeof(data32)); + + return LIBSPDM_STATUS_SUCCESS; +} + +/** + * Save the negotiated_state to NV storage from an SPDM context. + */ +libspdm_return_t spdm_save_negotiated_state(void *spdm_context, + bool is_requester) +{ + bool ret; + spdm_negotiated_state_struct_t negotiated_state; + size_t data_size; + libspdm_data_parameter_t parameter; + uint8_t data8; + uint16_t data16; + uint32_t data32; + spdm_version_number_t spdm_version[SPDM_MAX_VERSION_COUNT]; + size_t index; + uint8_t vca_buffer[LIBSPDM_MAX_MESSAGE_VCA_BUFFER_SIZE]; + + if (m_save_state_file_name == NULL) + { + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + + m_end_session_attributes = 0; + + printf("SaveState to %s\n", m_save_state_file_name); + + libspdm_zero_mem(&negotiated_state, sizeof(negotiated_state)); + negotiated_state.version = SPDM_NEGOTIATED_STATE_STRUCT_VERSION; + + /* get setting fron local*/ + + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + + if (is_requester) + { + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_CAPABILITY_FLAGS, + ¶meter, &data32, &data_size); + negotiated_state.requester_cap_flags = data32; + data_size = sizeof(data8); + libspdm_get_data(spdm_context, LIBSPDM_DATA_CAPABILITY_CT_EXPONENT, + ¶meter, &data8, &data_size); + negotiated_state.requester_cap_ct_exponent = data8; + } + else + { + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_CAPABILITY_FLAGS, + ¶meter, &data32, &data_size); + negotiated_state.responder_cap_flags = data32; + data_size = sizeof(data8); + libspdm_get_data(spdm_context, LIBSPDM_DATA_CAPABILITY_CT_EXPONENT, + ¶meter, &data8, &data_size); + negotiated_state.responder_cap_ct_exponent = data8; + } + + /* get setting fron connection*/ + + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_CONNECTION; + + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_CONNECTION_STATE, ¶meter, + &data32, &data_size); + LIBSPDM_ASSERT(data32 == LIBSPDM_CONNECTION_STATE_NEGOTIATED); + + data_size = sizeof(spdm_version); + libspdm_zero_mem(spdm_version, sizeof(spdm_version)); + libspdm_get_data(spdm_context, LIBSPDM_DATA_SPDM_VERSION, ¶meter, + &spdm_version, &data_size); + LIBSPDM_ASSERT(data_size / sizeof(spdm_version_number_t) > 0); + index = data_size / sizeof(spdm_version_number_t) - 1; + negotiated_state.spdm_version = + (uint8_t)(spdm_version[index] >> SPDM_VERSION_NUMBER_SHIFT_BIT); + + if (is_requester) + { + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_CAPABILITY_FLAGS, + ¶meter, &data32, &data_size); + negotiated_state.responder_cap_flags = data32; + data_size = sizeof(data8); + libspdm_get_data(spdm_context, LIBSPDM_DATA_CAPABILITY_CT_EXPONENT, + ¶meter, &data8, &data_size); + negotiated_state.responder_cap_ct_exponent = data8; + } + else + { + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_CAPABILITY_FLAGS, + ¶meter, &data32, &data_size); + negotiated_state.requester_cap_flags = data32; + data_size = sizeof(data8); + libspdm_get_data(spdm_context, LIBSPDM_DATA_CAPABILITY_CT_EXPONENT, + ¶meter, &data8, &data_size); + negotiated_state.requester_cap_ct_exponent = data8; + } + + data_size = sizeof(vca_buffer); + libspdm_zero_mem(vca_buffer, data_size); + libspdm_get_data(spdm_context, LIBSPDM_DATA_VCA_CACHE, ¶meter, vca_buffer, + &data_size); + negotiated_state.vca_buffer_size = data_size; + libspdm_copy_mem(negotiated_state.vca_buffer, sizeof(negotiated_state.vca_buffer), + vca_buffer, data_size); + + if ((negotiated_state.responder_cap_flags & + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CACHE_CAP) == 0) + { + printf("responder has no cache_cap\n"); + return spdm_clear_negotiated_state(spdm_context); + } + + data_size = sizeof(data8); + libspdm_get_data(spdm_context, LIBSPDM_DATA_MEASUREMENT_SPEC, ¶meter, + &data8, &data_size); + negotiated_state.measurement_spec = data8; + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_MEASUREMENT_HASH_ALGO, ¶meter, + &data32, &data_size); + negotiated_state.measurement_hash_algo = data32; + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_BASE_ASYM_ALGO, ¶meter, + &data32, &data_size); + negotiated_state.base_asym_algo = data32; + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_BASE_HASH_ALGO, ¶meter, + &data32, &data_size); + negotiated_state.base_hash_algo = data32; + data_size = sizeof(data16); + libspdm_get_data(spdm_context, LIBSPDM_DATA_DHE_NAME_GROUP, ¶meter, + &data16, &data_size); + negotiated_state.dhe_named_group = data16; + data_size = sizeof(data16); + libspdm_get_data(spdm_context, LIBSPDM_DATA_AEAD_CIPHER_SUITE, ¶meter, + &data16, &data_size); + negotiated_state.aead_cipher_suite = data16; + data_size = sizeof(data16); + libspdm_get_data(spdm_context, LIBSPDM_DATA_REQ_BASE_ASYM_ALG, ¶meter, + &data16, &data_size); + negotiated_state.req_base_asym_alg = data16; + data_size = sizeof(data16); + libspdm_get_data(spdm_context, LIBSPDM_DATA_KEY_SCHEDULE, ¶meter, &data16, + &data_size); + negotiated_state.key_schedule = data16; + data_size = sizeof(data8); + libspdm_get_data(spdm_context, LIBSPDM_DATA_OTHER_PARAMS_SUPPORT, ¶meter, &data8, + &data_size); + negotiated_state.other_params_support = data8; + + ret = libspdm_write_output_file(m_save_state_file_name, &negotiated_state, + sizeof(negotiated_state)); + if (!ret) + { + printf("SaveState fail - write file error\n"); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + return LIBSPDM_STATUS_SUCCESS; +} + +/** + * Clear the negotiated_state in the NV storage. + */ +libspdm_return_t spdm_clear_negotiated_state(void *spdm_context) +{ + bool ret; + + if (m_save_state_file_name == NULL) + { + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + + printf("ClearState in %s\n", m_save_state_file_name); + + ret = libspdm_write_output_file(m_save_state_file_name, NULL, 0); + if (!ret) + { + printf("ClearState fail - write file error\n"); + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + return LIBSPDM_STATUS_SUCCESS; +} diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/nv_storage.h b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/nv_storage.h new file mode 100644 index 00000000..f2eedaf1 --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/nv_storage.h @@ -0,0 +1,61 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#ifndef __SPDM_EMU_NV_STORAGE_LIB_H__ +#define __SPDM_EMU_NV_STORAGE_LIB_H__ + +#include "hal/base.h" +#include "industry_standard/spdm.h" + +#define SPDM_NEGOTIATED_STATE_STRUCT_VERSION 1 + +#pragma pack(1) +typedef struct { + uint32_t version; + uint8_t spdm_version; + uint8_t requester_cap_ct_exponent; + uint32_t requester_cap_flags; + uint8_t responder_cap_ct_exponent; + uint32_t responder_cap_flags; + uint8_t measurement_spec; + uint8_t other_params_support; + uint8_t mel_spec; + uint32_t measurement_hash_algo; + uint32_t base_asym_algo; + uint32_t base_hash_algo; + uint16_t dhe_named_group; + uint16_t aead_cipher_suite; + uint16_t req_base_asym_alg; + uint16_t key_schedule; + size_t vca_buffer_size; + uint8_t vca_buffer[LIBSPDM_MAX_MESSAGE_VCA_BUFFER_SIZE]; +} spdm_negotiated_state_struct_t; +#pragma pack() + +/** + * privision the capability and algorithm for PKS version only case. + */ +libspdm_return_t spdm_provision_psk_version_only(void *spdm_context, + bool is_requester); + +/** + * Load the negotiated_state from NV storage to an SPDM context. + */ +libspdm_return_t spdm_load_negotiated_state(void *spdm_context, + bool is_requester); + +/** + * Save the negotiated_state to NV storage from an SPDM context. + */ +libspdm_return_t spdm_save_negotiated_state(void *spdm_context, + bool is_requester); + +/** + * Clear the negotiated_state in the NV storage. + */ +libspdm_return_t spdm_clear_negotiated_state(void *spdm_context); + +#endif diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/os_include.h b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/os_include.h new file mode 100644 index 00000000..766f63b6 --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/os_include.h @@ -0,0 +1,49 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#ifndef __WIN_NT_INCLUDE_H__ +#define __WIN_NT_INCLUDE_H__ + +#ifdef _MSC_VER +/* MSVC*/ + +/* Win32 include files do not compile clean with /W4, so we use the warning + * pragma to suppress the warnings for Win32 only. This way our code can stil + * compile at /W4 (highest warning level) with /WX (warnings cause build + * errors).*/ + +#pragma warning(disable : 4115) +#pragma warning(disable : 4201) +#pragma warning(disable : 4028) +#pragma warning(disable : 4133) + +#include "WinSock2.h" +#include "winioctl.h" +#include "windows.h" +#include "windowsx.h" +#include "WS2tcpip.h" + + +/* Set the warnings back on as the EFI code must be /W4.*/ + +#pragma warning(default : 4115) +#pragma warning(default : 4201) + +#else +/* GCC*/ +#include "stdio.h" +#include "stdlib.h" +#include "unistd.h" +#include "errno.h" +#include "sys/socket.h" +#include "arpa/inet.h" +typedef int SOCKET; +#define closesocket(x) close(x) +#define INVALID_SOCKET (-1) +#define SOCKET_ERROR (-1) +#endif + +#endif diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/pcap.c b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/pcap.c new file mode 100644 index 00000000..d6c828ac --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/pcap.c @@ -0,0 +1,107 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#include "spdm_caliptra.h" +#include "industry_standard/pcap.h" +#include "industry_standard/link_type_ex.h" + +#define PCAP_PACKET_MAX_SIZE 0x00010000 + +FILE *m_pcap_file; + +bool open_pcap_packet_file(const char *pcap_file_name) +{ + pcap_global_header_t pcap_global_header; + + if (pcap_file_name == NULL) { + return false; + } + + pcap_global_header.magic_number = PCAP_GLOBAL_HEADER_MAGIC; + pcap_global_header.version_major = PCAP_GLOBAL_HEADER_VERSION_MAJOR; + pcap_global_header.version_minor = PCAP_GLOBAL_HEADER_VERSION_MINOR; + pcap_global_header.this_zone = 0; + pcap_global_header.sig_figs = 0; + pcap_global_header.snap_len = PCAP_PACKET_MAX_SIZE; + if (m_use_transport_layer == SOCKET_TRANSPORT_TYPE_MCTP) { + pcap_global_header.network = LINKTYPE_MCTP; + } else if (m_use_transport_layer == SOCKET_TRANSPORT_TYPE_PCI_DOE) { + pcap_global_header.network = LINKTYPE_PCI_DOE; + } else { + return false; + } + + if ((m_pcap_file = fopen(pcap_file_name, "wb")) == NULL) { + printf("!!!Unable to open pcap file %s!!!\n", pcap_file_name); + return false; + } + + if ((fwrite(&pcap_global_header, 1, sizeof(pcap_global_header), + m_pcap_file)) != sizeof(pcap_global_header)) { + printf("!!!Write pcap file error!!!\n"); + close_pcap_packet_file(); + return false; + } + + return true; +} + +void close_pcap_packet_file(void) +{ + if (m_pcap_file != NULL) { + fclose(m_pcap_file); + m_pcap_file = NULL; + } +} + +void append_pcap_packet_data(const void *header, size_t header_size, + const void *data, size_t size) +{ + pcap_packet_header_t pcap_packet_header; + size_t total_size; + + total_size = header_size + size; + + if (m_pcap_file != NULL) { + time_t rawtime; + time(&rawtime); + + pcap_packet_header.ts_sec = (uint32_t)rawtime; + pcap_packet_header.ts_usec = 0; + + pcap_packet_header.incl_len = + (uint32_t)((total_size > PCAP_PACKET_MAX_SIZE) ? + PCAP_PACKET_MAX_SIZE : + total_size); + pcap_packet_header.orig_len = (uint32_t)total_size; + + if ((fwrite(&pcap_packet_header, 1, sizeof(pcap_packet_header), + m_pcap_file)) != sizeof(pcap_packet_header)) { + printf("!!!Write pcap file error!!!\n"); + close_pcap_packet_file(); + return; + } + + if (total_size > PCAP_PACKET_MAX_SIZE) { + total_size = PCAP_PACKET_MAX_SIZE; + } + + if (header_size != 0) { + if ((fwrite(header, 1, header_size, m_pcap_file)) != + header_size) { + printf("!!!Write pcap file error!!!\n"); + close_pcap_packet_file(); + return; + } + } + + if ((fwrite(data, 1, size, m_pcap_file)) != size) { + printf("!!!Write pcap file error!!!\n"); + close_pcap_packet_file(); + return; + } + } +} diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/spdm_caliptra.c b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/spdm_caliptra.c new file mode 100644 index 00000000..602cc381 --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/spdm_caliptra.c @@ -0,0 +1,1391 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#include "spdm_caliptra.h" + +/* + * EXE_MODE_SHUTDOWN + * EXE_MODE_CONTINUE + */ +uint32_t m_exe_mode = EXE_MODE_SHUTDOWN; + +uint32_t m_exe_connection = (0 | + /* EXE_CONNECTION_VERSION_ONLY |*/ + EXE_CONNECTION_DIGEST | EXE_CONNECTION_CERT | + EXE_CONNECTION_CHAL | EXE_CONNECTION_MEAS | + EXE_CONNECTION_SET_CERT | EXE_CONNECTION_GET_CSR | 0); + +uint32_t m_exe_session = + (0 | EXE_SESSION_KEY_EX | EXE_SESSION_PSK | + /* EXE_SESSION_NO_END |*/ + EXE_SESSION_KEY_UPDATE | EXE_SESSION_HEARTBEAT | EXE_SESSION_MEAS | + EXE_SESSION_SET_CERT | EXE_SESSION_GET_CSR | + EXE_SESSION_DIGEST | EXE_SESSION_CERT | EXE_SESSION_APP | 0); + +#define IP_ADDRESS "127.0.0.1" + +#ifdef _MSC_VER +struct in_addr m_ip_address = { { { 127, 0, 0, 1 } } }; +#else +struct in_addr m_ip_address = { 0x0100007F }; +#endif + +void print_usage(const char *name) +{ + printf("\n%s [--trans MCTP|PCI_DOE|TCP|NONE]\n", name); + printf(" [--tcp_sub HS|NO_HS]\n"); + printf(" [--ver 1.0|1.1|1.2|1.3]\n"); + printf(" [--sec_ver 1.0|1.1]\n"); + printf( + " [--cap CACHE|CERT|CHAL|MEAS_NO_SIG|MEAS_SIG|MEAS_FRESH|ENCRYPT|MAC|MUT_AUTH|KEY_EX|PSK|PSK_WITH_CONTEXT|ENCAP|HBEAT|KEY_UPD|HANDSHAKE_IN_CLEAR|PUB_KEY_ID|CHUNK|ALIAS_CERT|SET_CERT|CSR|CERT_INSTALL_RESET|EP_INFO_NO_SIG|EP_INFO_SIG|MEL|EVENT|MULTI_KEY_ONLY|MULTI_KEY_NEG|GET_KEY_PAIR_INFO|SET_KEY_PAIR_INFO]\n"); + printf(" [--hash SHA_256|SHA_384|SHA_512|SHA3_256|SHA3_384|SHA3_512|SM3_256]\n"); + printf(" [--meas_spec DMTF]\n"); + printf(" [--meas_hash RAW_BIT|SHA_256|SHA_384|SHA_512|SHA3_256|SHA3_384|SHA3_512|SM3_256]\n"); + printf(" [--mel_spec DMTF]\n"); + printf( + " [--asym RSASSA_2048|RSASSA_3072|RSASSA_4096|RSAPSS_2048|RSAPSS_3072|RSAPSS_4096|ECDSA_P256|ECDSA_P384|ECDSA_P521|SM2_P256|EDDSA_25519|EDDSA_448]\n"); + printf( + " [--req_asym RSASSA_2048|RSASSA_3072|RSASSA_4096|RSAPSS_2048|RSAPSS_3072|RSAPSS_4096|ECDSA_P256|ECDSA_P384|ECDSA_P521|SM2_P256|EDDSA_25519|EDDSA_448]\n"); + printf( + " [--dhe FFDHE_2048|FFDHE_3072|FFDHE_4096|SECP_256_R1|SECP_384_R1|SECP_521_R1|SM2_P256]\n"); + printf(" [--aead AES_128_GCM|AES_256_GCM|CHACHA20_POLY1305|SM4_128_GCM]\n"); + printf(" [--key_schedule HMAC_HASH]\n"); + printf(" [--other_param OPAQUE_FMT_1|MULTI_KEY_CONN]\n"); + printf( + " [--peer_cap CACHE|CERT|CHAL|MEAS_NO_SIG|MEAS_SIG|MEAS_FRESH|ENCRYPT|MAC|MUT_AUTH|KEY_EX|PSK|PSK_WITH_CONTEXT|ENCAP|HBEAT|KEY_UPD|HANDSHAKE_IN_CLEAR|PUB_KEY_ID|CHUNK|ALIAS_CERT|SET_CERT|CSR|CERT_INSTALL_RESET|EP_INFO_NO_SIG|EP_INFO_SIG|MEL|EVENT|MULTI_KEY_ONLY|MULTI_KEY_NEG|GET_KEY_PAIR_INFO|SET_KEY_PAIR_INFO]\n"); + printf(" [--basic_mut_auth NO|BASIC]\n"); + printf(" [--mut_auth NO|WO_ENCAP|W_ENCAP|DIGESTS]\n"); + printf(" [--meas_sum NO|TCB|ALL]\n"); + printf(" [--meas_op ONE_BY_ONE|ALL]\n"); + printf(" [--meas_att HASH|RAW]\n"); + printf(" [--key_upd REQ|ALL|RSP]\n"); + printf(" [--slot_id <0~7|0xFF>]\n"); + printf(" [--slot_count <1~8>]\n"); + printf(" [--save_state ]\n"); + printf(" [--load_state ]\n"); + printf(" [--exe_mode SHUTDOWN|CONTINUE]\n"); + printf(" [--exe_conn VER_ONLY|DIGEST|CERT|CHAL|MEAS|GET_CSR|SET_CERT]\n"); + printf(" [--exe_session KEY_EX|PSK|NO_END|KEY_UPDATE|HEARTBEAT|MEAS|DIGEST|CERT|GET_CSR|SET_CERT|APP]\n"); + printf(" [--pcap ]\n"); + printf(" [--priv_key_mode PEM|RAW]\n"); + printf("\n"); + printf("NOTE:\n"); + printf(" [--trans] is used to select transport layer message. By default, MCTP is used.\n"); + printf( + " [--tcp_sub] is sub-option when transport layer is TCP. By default, NO-HANDSHAKE is used.\n"); + printf(" [--ver] is version. By default, all are used.\n"); + printf( + " [--sec_ver] is secured message version. By default, all are used.\n"); + printf( + " [--cap] is capability flags. Multiple flags can be set together. Please use ',' for them.\n"); + printf( + " By default, CERT,CHAL,ENCRYPT,MAC,MUT_AUTH,KEY_EX,PSK,ENCAP,HBEAT,KEY_UPD,HANDSHAKE_IN_CLEAR,MULTI_KEY_NEG is used for Requester.\n"); + printf( + " By default, CACHE,CERT,CHAL,MEAS_SIG,MEAS_FRESH,ENCRYPT,MAC,MUT_AUTH,KEY_EX,PSK_WITH_CONTEXT,ENCAP,HBEAT,KEY_UPD,HANDSHAKE_IN_CLEAR,SET_CERT,CSR,MULTI_KEY_NEG,GET_KEY_PAIR_INFO is used for Responder.\n"); + printf(" [--hash] is hash algorithm. By default, SHA_384,SHA_256 is used.\n"); + printf(" [--meas_spec] is measurement hash spec. By default, DMTF is used.\n"); + printf( + " [--meas_hash] is measurement hash algorithm. By default, SHA_512,SHA_384,SHA_256 is used.\n"); + printf(" [--mel_spec] is mel spec. By default, DMTF is used.\n"); + printf(" [--asym] is asym algorithm. By default, ECDSA_P384,ECDSA_P256 is used.\n"); + printf( + " [--req_asym] is requester asym algorithm. By default, RSAPSS_3072,RSAPSS_2048,RSASSA_3072,RSASSA_2048 is used.\n"); + printf( + " [--dhe] is DHE algorithm. By default, SECP_384_R1,SECP_256_R1,FFDHE_3072,FFDHE_2048 is used.\n"); + printf(" [--aead] is AEAD algorithm. By default, AES_256_GCM,CHACHA20_POLY1305 is used.\n"); + printf(" [--key_schedule] is key schedule algorithm. By default, HMAC_HASH is used.\n"); + printf(" [--other_param] is other parameter support. By default, OPAQUE_FMT_1,MULTI_KEY_CONN is used.\n"); + printf(" Above algorithms also support multiple flags. Please use ',' for them.\n"); + printf(" Not all the algorithms are supported, especially SHA3, EDDSA, and SMx.\n"); + printf(" Please don't mix NIST algo with SMx algo.\n"); + printf( + " [--peer_cap] is capability flags for the peer. It is used only when --exe_conn has VER_ONLY.\n"); + printf( + " [--basic_mut_auth] is the basic mutual authentication policy. BASIC is used in CHALLENGE_AUTH. By default, BASIC is used.\n"); + printf( + " [--mut_auth] is the mutual authentication policy. WO_ENCAP, W_ENCAP or DIGESTS is used in KEY_EXCHANGE_RSP. By default, W_ENCAP is used.\n"); + printf( + " [--meas_sum] is the measurement summary hash type in CHALLENGE_AUTH, KEY_EXCHANGE_RSP and PSK_EXCHANGE_RSP. By default, ALL is used.\n"); + printf( + " [--meas_op] is the measurement operation in GET_MEASUREMEMT. By default, ONE_BY_ONE is used.\n"); + printf( + " [--meas_att] is the measurement attribute in GET_MEASUREMEMT. By default, HASH is used.\n"); + printf( + " [--key_upd] is the key update operation in KEY_UPDATE. By default, ALL is used. RSP will trigger encapsulated KEY_UPDATE.\n"); + printf( + " [--slot_id] is to select the peer slot ID in GET_MEASUREMENT, CHALLENGE_AUTH, KEY_EXCHANGE and FINISH. By default, 0 is used.\n"); + printf( + " 0xFF can be used to indicate provisioned certificate chain. No GET_CERTIFICATE is needed.\n"); + printf( + " 0xFF must be used to if PUB_KEY_ID is set. No GET_DIGEST/GET_CERTIFICATE is sent.\n"); + printf( + " [--slot_count] is to select the local slot count. By default, 3 is used. And the slot store cert chain continuously in emu.\n"); + printf(" [--save_state] is to save the current negotiated state to a write-only file.\n"); + printf( + " The requester and responder will save state after GET_VERSION/GET_CAPABILLITIES/NEGOTIATE_ALGORITHMS.\n"); + printf( + " (negotiated state == ver|cap|hash|meas_spec|meas_hash|asym|req_asym|dhe|aead|key_schedule|other_param)\n"); + printf( + " The responder should set CACHE capabilities, otherwise the state will not be saved.\n"); + printf( + " The requester will clear PRESERVE_NEGOTIATED_STATE_CLEAR bit in END_SESSION to preserve, otherwise this bit is set.\n"); + printf( + " The responder will save empty state, if the requester sets PRESERVE_NEGOTIATED_STATE_CLEAR bit in END_SESSION.\n"); + printf( + " [--load_state] is to load the negotiated state to current session from a read-only file.\n"); + printf( + " The requester and responder will provision the state just after SPDM context is created.\n"); + printf(" The user need guarantee the state file is generated correctly.\n"); + printf( + " The command line input - ver|cap|hash|meas_spec|meas_hash|asym|req_asym|dhe|aead|key_schedule|other_param are ignored.\n"); + printf( + " The requester will skip GET_VERSION/GET_CAPABILLITIES/NEGOTIATE_ALGORITHMS.\n"); + printf(" [--exe_mode] is used to control the execution mode. By default, it is SHUTDOWN.\n"); + printf(" SHUTDOWN means the requester asks the responder to stop.\n"); + printf( + " CONTINUE means the requester asks the responder to preserve the current SPDM context.\n"); + printf( + " [--exe_conn] is used to control the SPDM connection. By default, it is DIGEST,CERT,CHAL,MEAS,GET_CSR,SET_CERT.\n"); + printf( + " VER_ONLY means REQUESTER does not send GET_CAPABILITIES/NEGOTIATE_ALGORITHMS. It is used for quick symmetric authentication with PSK.\n"); + printf(" The version for responder must be provisioned from ver.\n"); + printf(" The capablities for local and peer are from cap|peer_cap.\n"); + printf( + " The negotiated algorithms are from hash|meas_spec|meas_hash|asym|req_asym|dhe|aead|key_schedule|other_param and they shall have at most 1 bit set.\n"); + printf(" DIGEST means send GET_DIGESTS command.\n"); + printf(" CERT means send GET_CERTIFICATE command.\n"); + printf(" CHAL means send CHALLENGE command.\n"); + printf(" MEAS means send GET_MEASUREMENT command.\n"); + printf(" GET_CSR means send GET_CSR command.\n"); + printf(" SET_CERT means send SET_CERTIFICATE command.\n"); + printf( + " [--exe_session] is used to control the SPDM session. By default, it is KEY_EX,PSK,KEY_UPDATE,HEARTBEAT,MEAS,DIGEST,CERT,GET_CSR,SET_CERT,APP.\n"); + printf(" KEY_EX means to setup KEY_EXCHANGE session.\n"); + printf(" PSK means to setup PSK_EXCHANGE session.\n"); + printf(" NO_END means to not send END_SESSION.\n"); + printf(" KEY_UPDATE means to send KEY_UPDATE in session.\n"); + printf(" HEARTBEAT means to send HEARTBEAT in session.\n"); + printf(" MEAS means send GET_MEASUREMENT command in session.\n"); + printf(" DIGEST means send GET_DIGESTS command in session.\n"); + printf(" CERT means send GET_CERTIFICATE command in session.\n"); + printf(" GET_CSR means send GET_CSR command in session.\n"); + printf(" SET_CERT means send SET_CERTIFICATE command in session.\n"); + printf(" APP means send vendor defined message or application message in session.\n"); + printf(" [--pcap] is used to generate PCAP dump file for offline analysis.\n"); + printf( + " [--priv_key_mode] is uesed to confirm private key mode with LIBSPDM_PRIVATE_KEY_USE_PEM.\n"); +} + +typedef struct { + uint32_t value; + char *name; +} value_string_entry_t; + +value_string_entry_t m_transport_value_string_table[] = { + { SOCKET_TRANSPORT_TYPE_NONE, "NONE"}, + { SOCKET_TRANSPORT_TYPE_MCTP, "MCTP" }, + { SOCKET_TRANSPORT_TYPE_PCI_DOE, "PCI_DOE" }, + { SOCKET_TRANSPORT_TYPE_TCP, "TCP"} +}; + +value_string_entry_t m_tcp_subtype_string_table[] = { + { SOCKET_TCP_NO_HANDSHAKE, "NO_HS"}, + { SOCKET_TCP_HANDSHAKE, "HS" } +}; + +value_string_entry_t m_version_value_string_table[] = { + { SPDM_MESSAGE_VERSION_10, "1.0" }, + { SPDM_MESSAGE_VERSION_11, "1.1" }, + { SPDM_MESSAGE_VERSION_12, "1.2" }, + { SPDM_MESSAGE_VERSION_13, "1.3" }, +}; + +value_string_entry_t m_secured_message_version_value_string_table[] = { + { SPDM_MESSAGE_VERSION_10, "1.0" }, + { SPDM_MESSAGE_VERSION_11, "1.1" }, +}; + +value_string_entry_t m_spdm_requester_capabilities_string_table[] = { + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CERT_CAP, "CERT" }, + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHAL_CAP, "CHAL" }, + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_ENCRYPT_CAP, "ENCRYPT" }, + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MAC_CAP, "MAC" }, + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MUT_AUTH_CAP, "MUT_AUTH" }, + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP, "KEY_EX" }, + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PSK_CAP_REQUESTER, "PSK" }, + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_ENCAP_CAP, "ENCAP" }, + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP, "HBEAT" }, + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_UPD_CAP, "KEY_UPD" }, + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP, + "HANDSHAKE_IN_CLEAR" }, + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PUB_KEY_ID_CAP, "PUB_KEY_ID" }, + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CHUNK_CAP, "CHUNK" }, + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_EP_INFO_CAP_NO_SIG, "EP_INFO_NO_SIG" }, + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_EP_INFO_CAP_SIG, "EP_INFO_SIG" }, + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_EVENT_CAP, "EVENT" }, + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MULTI_KEY_CAP_ONLY, "MULTI_KEY_ONLY" }, + { SPDM_GET_CAPABILITIES_REQUEST_FLAGS_MULTI_KEY_CAP_NEG, "MULTI_KEY_NEG" }, +}; + +value_string_entry_t m_spdm_responder_capabilities_string_table[] = { + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CACHE_CAP, "CACHE" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP, "CERT" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHAL_CAP, "CHAL" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP_NO_SIG, "MEAS_NO_SIG" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP_SIG, "MEAS_SIG" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_FRESH_CAP, "MEAS_FRESH" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ENCRYPT_CAP, "ENCRYPT" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MAC_CAP, "MAC" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MUT_AUTH_CAP, "MUT_AUTH" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP, "KEY_EX" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP_RESPONDER, "PSK" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP_RESPONDER_WITH_CONTEXT, + "PSK_WITH_CONTEXT" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ENCAP_CAP, "ENCAP" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP, "HBEAT" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_UPD_CAP, "KEY_UPD" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HANDSHAKE_IN_THE_CLEAR_CAP, + "HANDSHAKE_IN_CLEAR" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PUB_KEY_ID_CAP, "PUB_KEY_ID" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHUNK_CAP, "CHUNK" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ALIAS_CERT_CAP, "ALIAS_CERT" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_SET_CERT_CAP, "SET_CERT" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP, "CSR" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_INSTALL_RESET_CAP, "CERT_INSTALL_RESET" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_EP_INFO_CAP_NO_SIG, "EP_INFO_NO_SIG" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_EP_INFO_CAP_SIG, "EP_INFO_SIG" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEL_CAP, "MEL" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_EVENT_CAP, "EVENT" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MULTI_KEY_CAP_ONLY, "MULTI_KEY_ONLY" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MULTI_KEY_CAP_NEG, "MULTI_KEY_NEG" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_GET_KEY_PAIR_INFO_CAP, "GET_KEY_PAIR_INFO" }, + { SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_SET_KEY_PAIR_INFO_CAP, "SET_KEY_PAIR_INFO" }, +}; + +value_string_entry_t m_hash_value_string_table[] = { + { SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_256, "SHA_256" }, + { SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_384, "SHA_384" }, + { SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_512, "SHA_512" }, + { SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA3_256, "SHA3_256" }, + { SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA3_384, "SHA3_384" }, + { SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA3_512, "SHA3_512" }, + { SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SM3_256, "SM3_256" }, +}; + +value_string_entry_t m_measurement_spec_value_string_table[] = { + { SPDM_MEASUREMENT_SPECIFICATION_DMTF, "DMTF" }, +}; + +value_string_entry_t m_mel_spec_value_string_table[] = { + { SPDM_MEL_SPECIFICATION_DMTF, "DMTF" }, +}; + +value_string_entry_t m_measurement_hash_value_string_table[] = { + { SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_RAW_BIT_STREAM_ONLY, + "RAW_BIT" }, + { SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA_256, "SHA_256" }, + { SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA_384, "SHA_384" }, + { SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA_512, "SHA_512" }, + { SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA3_256, "SHA3_256" }, + { SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA3_384, "SHA3_384" }, + { SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA3_512, "SHA3_512" }, + { SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SM3_256, "SM3_256" }, +}; + +value_string_entry_t m_asym_value_string_table[] = { + { SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048, "RSASSA_2048" }, + { SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072, "RSASSA_3072" }, + { SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096, "RSASSA_4096" }, + { SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048, "RSAPSS_2048" }, + { SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072, "RSAPSS_3072" }, + { SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096, "RSAPSS_4096" }, + { SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256, + "ECDSA_P256" }, + { SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384, + "ECDSA_P384" }, + { SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521, + "ECDSA_P521" }, + { SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_SM2_ECC_SM2_P256, "SM2_P256" }, + { SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED25519, "EDDSA_25519" }, + { SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED448, "EDDSA_448" }, +}; + +value_string_entry_t m_dhe_value_string_table[] = { + { SPDM_ALGORITHMS_DHE_NAMED_GROUP_FFDHE_2048, "FFDHE_2048" }, + { SPDM_ALGORITHMS_DHE_NAMED_GROUP_FFDHE_3072, "FFDHE_3072" }, + { SPDM_ALGORITHMS_DHE_NAMED_GROUP_FFDHE_4096, "FFDHE_4096" }, + { SPDM_ALGORITHMS_DHE_NAMED_GROUP_SECP_256_R1, "SECP_256_R1" }, + { SPDM_ALGORITHMS_DHE_NAMED_GROUP_SECP_384_R1, "SECP_384_R1" }, + { SPDM_ALGORITHMS_DHE_NAMED_GROUP_SECP_521_R1, "SECP_521_R1" }, + { SPDM_ALGORITHMS_DHE_NAMED_GROUP_SM2_P256, "SM2_P256" }, +}; + +value_string_entry_t m_aead_value_string_table[] = { + { SPDM_ALGORITHMS_AEAD_CIPHER_SUITE_AES_128_GCM, "AES_128_GCM" }, + { SPDM_ALGORITHMS_AEAD_CIPHER_SUITE_AES_256_GCM, "AES_256_GCM" }, + { SPDM_ALGORITHMS_AEAD_CIPHER_SUITE_CHACHA20_POLY1305, + "CHACHA20_POLY1305" }, + { SPDM_ALGORITHMS_AEAD_CIPHER_SUITE_AEAD_SM4_GCM, "SM4_128_GCM" }, +}; + +value_string_entry_t m_key_schedule_value_string_table[] = { + { SPDM_ALGORITHMS_KEY_SCHEDULE_HMAC_HASH, "HMAC_HASH" }, +}; + +value_string_entry_t m_other_param_value_string_table[] = { + { SPDM_ALGORITHMS_OPAQUE_DATA_FORMAT_1, "OPAQUE_FMT_1" }, + { SPDM_ALGORITHMS_MULTI_KEY_CONN, "MULTI_KEY_CONN" }, +}; + +value_string_entry_t m_basic_mut_auth_policy_string_table[] = { + { 0, "NO" }, + { 1, "BASIC" }, +}; + +value_string_entry_t m_mut_auth_policy_string_table[] = { + { 0, "NO" }, + { SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED, "WO_ENCAP" }, + { SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_ENCAP_REQUEST, + "W_ENCAP" }, + { SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED_WITH_GET_DIGESTS, + "DIGESTS" }, +}; + +value_string_entry_t m_measurement_summary_hash_type_string_table[] = { + { SPDM_CHALLENGE_REQUEST_NO_MEASUREMENT_SUMMARY_HASH, "NO" }, + { SPDM_CHALLENGE_REQUEST_TCB_COMPONENT_MEASUREMENT_HASH, "TCB" }, + { SPDM_CHALLENGE_REQUEST_ALL_MEASUREMENTS_HASH, "ALL" }, +}; + +value_string_entry_t m_measurement_operation_string_table[] = { + { SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_TOTAL_NUMBER_OF_MEASUREMENTS, + "ONE_BY_ONE" }, + { SPDM_GET_MEASUREMENTS_REQUEST_MEASUREMENT_OPERATION_ALL_MEASUREMENTS, + "ALL" }, +}; + +value_string_entry_t m_measurement_attribute_string_table[] = { + { 0, + "HASH" }, + { SPDM_GET_MEASUREMENTS_REQUEST_ATTRIBUTES_RAW_BIT_STREAM_REQUESTED, + "RAW" }, +}; + +value_string_entry_t m_key_update_action_string_table[] = { + { LIBSPDM_KEY_UPDATE_ACTION_REQUESTER, "REQ" }, + { LIBSPDM_KEY_UPDATE_ACTION_RESPONDER, "RSP" }, + { LIBSPDM_KEY_UPDATE_ACTION_MAX, "ALL" }, +}; + +value_string_entry_t m_slot_id_string_table[] = { + { 0x0, "0" }, { 0x1, "1" }, { 0x2, "2" }, + { 0x3, "3" }, { 0x4, "4" }, { 0x5, "5" }, + { 0x6, "6" }, { 0x7, "7" }, { 0xFF, "0xFF" }, +}; + +value_string_entry_t m_slot_count_string_table[] = { + { 0x1, "1" }, { 0x2, "2" }, { 0x3, "3" }, { 0x4, "4" }, + { 0x5, "5" }, { 0x6, "6" }, { 0x7, "7" }, { 0x8, "8" }, +}; + +value_string_entry_t m_exe_mode_string_table[] = { + { EXE_MODE_SHUTDOWN, "SHUTDOWN" }, + { EXE_MODE_CONTINUE, "CONTINUE" }, +}; + +value_string_entry_t m_exe_connection_string_table[] = { + { EXE_CONNECTION_VERSION_ONLY, "VER_ONLY" }, + { EXE_CONNECTION_DIGEST, "DIGEST" }, + { EXE_CONNECTION_CERT, "CERT" }, + { EXE_CONNECTION_CHAL, "CHAL" }, + { EXE_CONNECTION_MEAS, "MEAS" }, + { EXE_CONNECTION_SET_CERT, "SET_CERT" }, + { EXE_CONNECTION_GET_CSR, "GET_CSR" }, +}; + +value_string_entry_t m_exe_session_string_table[] = { + { EXE_SESSION_KEY_EX, "KEY_EX" }, + { EXE_SESSION_PSK, "PSK" }, + { EXE_SESSION_NO_END, "NO_END" }, + { EXE_SESSION_KEY_UPDATE, "KEY_UPDATE" }, + { EXE_SESSION_HEARTBEAT, "HEARTBEAT" }, + { EXE_SESSION_MEAS, "MEAS" }, + { EXE_SESSION_DIGEST, "DIGEST" }, + { EXE_SESSION_CERT, "CERT" }, + { EXE_SESSION_SET_CERT, "SET_CERT" }, + { EXE_SESSION_GET_CSR, "GET_CSR" }, + { EXE_SESSION_APP, "APP" }, +}; + +bool get_value_from_name(const value_string_entry_t *table, + size_t entry_count, const char *name, + uint32_t *value) +{ + size_t index; + + for (index = 0; index < entry_count; index++) { + if (strcmp(name, table[index].name) == 0) { + *value = table[index].value; + return true; + } + } + return false; +} + +bool get_flags_from_name(const value_string_entry_t *table, + size_t entry_count, const char *name, + uint32_t *flags) +{ + uint32_t value; + char *flag_name; + char *local_name; + bool ret; + + local_name = (void *)malloc(strlen(name) + 1); + if (local_name == NULL) { + return false; + } + strcpy(local_name, name); + + + /* name = Flag1,Flag2,...,FlagN*/ + + *flags = 0; + flag_name = strtok(local_name, ","); + while (flag_name != NULL) { + if (!get_value_from_name(table, entry_count, flag_name, + &value)) { + printf("unsupported flag - %s\n", flag_name); + ret = false; + goto done; + } + *flags |= value; + flag_name = strtok(NULL, ","); + } + if (*flags == 0) { + ret = false; + } else { + ret = true; + } +done: + free(local_name); + return ret; +} + +void process_args(char *program_name, int argc, char *argv[]) +{ + uint32_t data32; + char *pcap_file_name; + + pcap_file_name = NULL; + + if (argc == 1) { + return; + } + + argc--; + argv++; + + if ((strcmp(argv[0], "-h") == 0) || (strcmp(argv[0], "--help") == 0)) { + print_usage(program_name); + exit(0); + } + + while (argc > 0) { + if (strcmp(argv[0], "--trans") == 0) { + if (argc >= 2) { + if (!get_value_from_name( + m_transport_value_string_table, + LIBSPDM_ARRAY_SIZE( + m_transport_value_string_table), + argv[1], &m_use_transport_layer)) { + printf("invalid --trans %s\n", argv[1]); + print_usage(program_name); + exit(0); + } + printf("trans - 0x%x\n", m_use_transport_layer); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --trans\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--tcp_sub") == 0) { + if (argc >= 2) { + if (!get_value_from_name( + m_tcp_subtype_string_table, + LIBSPDM_ARRAY_SIZE( + m_tcp_subtype_string_table), + argv[1], &m_use_tcp_handshake)) { + printf("invalid --tcp_sub %s\n", argv[1]); + print_usage(program_name); + exit(0); + } + printf("tcp_sub - 0x%x\n", m_use_tcp_handshake); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --tcp_sub\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--ver") == 0) { + if (argc >= 2) { + if (!get_value_from_name( + m_version_value_string_table, + LIBSPDM_ARRAY_SIZE( + m_version_value_string_table), + argv[1], &data32)) { + printf("invalid --ver %s\n", argv[1]); + print_usage(program_name); + exit(0); + } + m_use_version = (uint8_t)data32; + printf("ver - 0x%02x\n", m_use_version); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --ver\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--sec_ver") == 0) { + if (argc >= 2) { + if (!get_value_from_name( + m_secured_message_version_value_string_table, + LIBSPDM_ARRAY_SIZE( + m_secured_message_version_value_string_table), + argv[1], &data32)) { + printf("invalid --sec_ver %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + m_use_secured_message_version = (uint8_t)data32; + printf("sec_ver - 0x%02x\n", + m_use_secured_message_version); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --sec_ver\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--cap") == 0) { + if (argc >= 2) { + value_string_entry_t *CapabilitiesStringTable; + size_t count; + + if (strcmp(program_name, + "spdm_requester_emu") == 0) { + CapabilitiesStringTable = + m_spdm_requester_capabilities_string_table; + count = LIBSPDM_ARRAY_SIZE( + m_spdm_requester_capabilities_string_table); + } else if (strcmp(program_name, + "spdm_responder_emu") == 0) { + CapabilitiesStringTable = + m_spdm_responder_capabilities_string_table; + count = LIBSPDM_ARRAY_SIZE( + m_spdm_responder_capabilities_string_table); + } else { + LIBSPDM_ASSERT(false); + printf("unsupported --cap\n"); + print_usage(program_name); + exit(0); + } + if (!get_flags_from_name( + CapabilitiesStringTable, count, + argv[1], &m_use_capability_flags)) { + printf("invalid --cap %s\n", argv[1]); + print_usage(program_name); + exit(0); + } + printf("cap - 0x%08x\n", + m_use_capability_flags); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --cap\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--peer_cap") == 0) { + if (argc >= 2) { + value_string_entry_t *CapabilitiesStringTable; + size_t count; + + if (strcmp(program_name, + "spdm_responder_emu") == 0) { + CapabilitiesStringTable = + m_spdm_requester_capabilities_string_table; + count = LIBSPDM_ARRAY_SIZE( + m_spdm_requester_capabilities_string_table); + } else if (strcmp(program_name, + "spdm_requester_emu") == 0) { + CapabilitiesStringTable = + m_spdm_responder_capabilities_string_table; + count = LIBSPDM_ARRAY_SIZE( + m_spdm_responder_capabilities_string_table); + } else { + LIBSPDM_ASSERT(false); + printf("unsupported --peer_cap\n"); + print_usage(program_name); + exit(0); + } + if (!get_flags_from_name( + CapabilitiesStringTable, count, + argv[1], &m_use_peer_capability_flags)) { + printf("invalid --peer_cap %s\n", argv[1]); + print_usage(program_name); + exit(0); + } + printf("peer_cap - 0x%08x\n", + m_use_peer_capability_flags); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --peer_cap\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--hash") == 0) { + if (argc >= 2) { + if (!get_flags_from_name( + m_hash_value_string_table, + LIBSPDM_ARRAY_SIZE( + m_hash_value_string_table), + argv[1], &m_support_hash_algo)) { + printf("invalid --hash %s\n", argv[1]); + print_usage(program_name); + exit(0); + } + printf("hash - 0x%08x\n", m_support_hash_algo); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --hash\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--meas_spec") == 0) { + if (argc >= 2) { + if (!get_flags_from_name( + m_measurement_spec_value_string_table, + LIBSPDM_ARRAY_SIZE( + m_measurement_spec_value_string_table), + argv[1], &data32)) { + printf("invalid --meas_spec %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + m_support_measurement_spec = (uint8_t)data32; + printf("meas_spec - 0x%02x\n", + m_support_measurement_spec); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --meas_spec\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--mel_spec") == 0) { + if (argc >= 2) { + if (!get_flags_from_name( + m_mel_spec_value_string_table, + LIBSPDM_ARRAY_SIZE( + m_mel_spec_value_string_table), + argv[1], &data32)) { + printf("invalid --mel_spec %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + m_support_mel_spec = (uint8_t)data32; + printf("mel_spec - 0x%02x\n", + m_support_mel_spec); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --mel_spec\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--meas_hash") == 0) { + if (argc >= 2) { + if (!get_flags_from_name( + m_measurement_hash_value_string_table, + LIBSPDM_ARRAY_SIZE( + m_measurement_hash_value_string_table), + argv[1], + &m_support_measurement_hash_algo)) { + printf("invalid --meas_hash %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + printf("meas_hash - 0x%08x\n", + m_support_measurement_hash_algo); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --meas_hash\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--asym") == 0) { + if (argc >= 2) { + if (!get_flags_from_name( + m_asym_value_string_table, + LIBSPDM_ARRAY_SIZE( + m_asym_value_string_table), + argv[1], &m_support_asym_algo)) { + printf("invalid --asym %s\n", argv[1]); + print_usage(program_name); + exit(0); + } + printf("asym - 0x%08x\n", m_support_asym_algo); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --asym\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--req_asym") == 0) { + if (argc >= 2) { + if (!get_flags_from_name( + m_asym_value_string_table, + LIBSPDM_ARRAY_SIZE( + m_asym_value_string_table), + argv[1], &data32)) { + printf("invalid --req_asym %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + m_support_req_asym_algo = (uint16_t)data32; + printf("req_asym - 0x%04x\n", + m_support_req_asym_algo); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --req_asym\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--dhe") == 0) { + if (argc >= 2) { + if (!get_flags_from_name( + m_dhe_value_string_table, + LIBSPDM_ARRAY_SIZE(m_dhe_value_string_table), + argv[1], &data32)) { + printf("invalid --dhe %s\n", argv[1]); + print_usage(program_name); + exit(0); + } + m_support_dhe_algo = (uint16_t)data32; + printf("dhe - 0x%04x\n", m_support_dhe_algo); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --dhe\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--aead") == 0) { + if (argc >= 2) { + if (!get_flags_from_name( + m_aead_value_string_table, + LIBSPDM_ARRAY_SIZE( + m_aead_value_string_table), + argv[1], &data32)) { + printf("invalid --aead %s\n", argv[1]); + print_usage(program_name); + exit(0); + } + m_support_aead_algo = (uint16_t)data32; + printf("aead - 0x%04x\n", m_support_aead_algo); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --aead\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--key_schedule") == 0) { + if (argc >= 2) { + if (!get_flags_from_name( + m_key_schedule_value_string_table, + LIBSPDM_ARRAY_SIZE( + m_key_schedule_value_string_table), + argv[1], &data32)) { + printf("invalid --key_schedule %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + m_support_key_schedule_algo = (uint16_t)data32; + printf("key_schedule - 0x%04x\n", + m_support_key_schedule_algo); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --key_schedule\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--other_param") == 0) { + if (argc >= 2) { + if (!get_flags_from_name( + m_other_param_value_string_table, + LIBSPDM_ARRAY_SIZE( + m_other_param_value_string_table), + argv[1], &data32)) { + printf("invalid --other_param %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + m_support_other_params_support = (uint8_t)data32; + printf("other_param - 0x%04x\n", + m_support_other_params_support); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --other_param\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--basic_mut_auth") == 0) { + if (argc >= 2) { + if (!get_value_from_name( + m_basic_mut_auth_policy_string_table, + LIBSPDM_ARRAY_SIZE( + m_basic_mut_auth_policy_string_table), + argv[1], &data32)) { + printf("invalid --basic_mut_auth %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + m_use_basic_mut_auth = (uint8_t)data32; + printf("basic_mut_auth - 0x%02x\n", + m_use_basic_mut_auth); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --basic_mut_auth\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--mut_auth") == 0) { + if (argc >= 2) { + if (!get_value_from_name( + m_mut_auth_policy_string_table, + LIBSPDM_ARRAY_SIZE( + m_mut_auth_policy_string_table), + argv[1], &data32)) { + printf("invalid --mut_auth %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + m_use_mut_auth = (uint8_t)data32; + printf("mut_auth - 0x%02x\n", m_use_mut_auth); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --mut_auth\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--meas_sum") == 0) { + if (argc >= 2) { + if (!get_value_from_name( + m_measurement_summary_hash_type_string_table, + LIBSPDM_ARRAY_SIZE( + m_measurement_summary_hash_type_string_table), + argv[1], &data32)) { + printf("invalid --meas_sum %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + m_use_measurement_summary_hash_type = + (uint8_t)data32; + printf("meas_sum - 0x%02x\n", + m_use_measurement_summary_hash_type); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --meas_sum\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--meas_op") == 0) { + if (argc >= 2) { + if (!get_value_from_name( + m_measurement_operation_string_table, + LIBSPDM_ARRAY_SIZE( + m_measurement_operation_string_table), + argv[1], &data32)) { + printf("invalid --meas_op %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + m_use_measurement_operation = (uint8_t)data32; + printf("meas_op - 0x%02x\n", + m_use_measurement_operation); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --meas_op\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--meas_att") == 0) { + if (argc >= 2) { + if (!get_value_from_name( + m_measurement_attribute_string_table, + LIBSPDM_ARRAY_SIZE( + m_measurement_attribute_string_table), + argv[1], &data32)) { + printf("invalid --meas_att %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + m_use_measurement_attribute = (uint8_t)data32; + printf("meas_att - 0x%02x\n", + m_use_measurement_attribute); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --meas_att\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--key_upd") == 0) { + if (argc >= 2) { + if (!get_value_from_name( + m_key_update_action_string_table, + LIBSPDM_ARRAY_SIZE( + m_key_update_action_string_table), + argv[1], &data32)) { + printf("invalid --key_upd %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + m_use_key_update_action = data32; + printf("key_upd - 0x%08x\n", + m_use_key_update_action); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --key_upd\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--slot_id") == 0) { + if (argc >= 2) { + if (!get_value_from_name( + m_slot_id_string_table, + LIBSPDM_ARRAY_SIZE(m_slot_id_string_table), + argv[1], &data32)) { + printf("invalid --slot_id %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + m_use_slot_id = (uint8_t)data32; + printf("slot_id - 0x%02x\n", m_use_slot_id); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --slot_id\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--slot_count") == 0) { + if (argc >= 2) { + if (!get_value_from_name( + m_slot_count_string_table, + LIBSPDM_ARRAY_SIZE( + m_slot_count_string_table), + argv[1], &data32)) { + printf("invalid --slot_count %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + m_use_slot_count = (uint8_t)data32; + printf("slot_count - 0x%02x\n", + m_use_slot_count); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --slot_count\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--save_state") == 0) { + if (argc >= 2) { + m_save_state_file_name = argv[1]; + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --save_state\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--load_state") == 0) { + if (argc >= 2) { + m_load_state_file_name = argv[1]; + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --load_state\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--exe_mode") == 0) { + if (argc >= 2) { + if (!get_value_from_name( + m_exe_mode_string_table, + LIBSPDM_ARRAY_SIZE(m_exe_mode_string_table), + argv[1], &m_exe_mode)) { + printf("invalid --exe_mode %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + printf("exe_mode - 0x%08x\n", m_exe_mode); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --exe_mode\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--exe_conn") == 0) { + if (argc >= 2) { + if (!get_flags_from_name( + m_exe_connection_string_table, + LIBSPDM_ARRAY_SIZE( + m_exe_connection_string_table), + argv[1], &m_exe_connection)) { + printf("invalid --exe_conn %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + printf("exe_conn - 0x%08x\n", m_exe_connection); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --exe_conn\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--exe_session") == 0) { + if (argc >= 2) { + if (!get_flags_from_name( + m_exe_session_string_table, + LIBSPDM_ARRAY_SIZE( + m_exe_session_string_table), + argv[1], &m_exe_session)) { + printf("invalid --exe_session %s\n", + argv[1]); + print_usage(program_name); + exit(0); + } + printf("exe_session - 0x%08x\n", m_exe_session); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --exe_session\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--pcap") == 0) { + if (argc >= 2) { + pcap_file_name = argv[1]; + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --pcap\n"); + print_usage(program_name); + exit(0); + } + } + + if (strcmp(argv[0], "--priv_key_mode") == 0) { + if (argc >= 2) { + if ((strcmp(argv[1], "PEM") != 0) && (strcmp(argv[1], "RAW") != 0)) { + printf("invalid --priv_key_mode %s\n", argv[1]); + print_usage(program_name); + exit(0); + } + if (strcmp(argv[1], "PEM") == 0) { + g_private_key_mode = 1; + } + + if (strcmp(argv[1], "RAW") == 0) { + g_private_key_mode = 0; + } + + printf("priv_key_mode - %s\n", argv[1]); + argc -= 2; + argv += 2; + continue; + } else { + printf("invalid --priv_key_mode\n"); + print_usage(program_name); + exit(0); + } + } + + printf("invalid %s\n", argv[0]); + print_usage(program_name); + exit(0); + } + + + /* Open PCAP file as last option, after the user indicates transport type.*/ + + if (pcap_file_name != NULL) { + if (!open_pcap_packet_file(pcap_file_name)) { + print_usage(program_name); + exit(0); + } + } + + return; +} + +bool init_client(SOCKET *sock, uint16_t port) +{ + SOCKET client_socket; + struct sockaddr_in server_addr; + int32_t ret_val; + +#ifdef _MSC_VER + WSADATA ws; + if (WSAStartup(MAKEWORD(2, 2), &ws) != 0) { + printf("Init Windows socket Failed - %x\n", WSAGetLastError()); + return false; + } +#endif + + client_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); + if (client_socket == INVALID_SOCKET) { + printf("Create socket Failed - %x\n", +#ifdef _MSC_VER + WSAGetLastError() +#else + errno +#endif + ); + return false; + } + + server_addr.sin_family = AF_INET; + libspdm_copy_mem(&server_addr.sin_addr.s_addr, sizeof(struct in_addr), &m_ip_address, + sizeof(struct in_addr)); + server_addr.sin_port = htons(port); + libspdm_zero_mem(server_addr.sin_zero, sizeof(server_addr.sin_zero)); + + ret_val = connect(client_socket, (struct sockaddr *)&server_addr, + sizeof(server_addr)); + if (ret_val == SOCKET_ERROR) { + printf("Connect Error - %x\n", +#ifdef _MSC_VER + WSAGetLastError() +#else + errno +#endif + ); + closesocket(client_socket); + return false; + } + + printf("connect success!\n"); + + *sock = client_socket; + return true; +} + +bool create_socket(uint16_t port_number, SOCKET *listen_socket) +{ + struct sockaddr_in my_address; + int32_t res; + + /* Initialize Winsock*/ +#ifdef _MSC_VER + WSADATA ws; + res = WSAStartup(MAKEWORD(2, 2), &ws); + if (res != 0) { + printf("WSAStartup failed with error: %d\n", res); + return false; + } +#endif + + *listen_socket = socket(PF_INET, SOCK_STREAM, 0); + if (INVALID_SOCKET == *listen_socket) { + printf("Cannot create server listen socket. Error is 0x%x\n", +#ifdef _MSC_VER + WSAGetLastError() +#else + errno +#endif + ); + return false; + } + + /* When the program stops unexpectedly the used port will stay in the TIME_WAIT + * state which prevents other programs from binding to this port until a timeout + * triggers. This timeout may be 30s to 120s. In this state the responder cannot + * be restarted since it cannot bind to its port. + * To prevent this SO_REUSEADDR is applied to the socket which allows the + * responder to bind to this port even if it is still in the TIME_WAIT state.*/ + if (setsockopt(*listen_socket, SOL_SOCKET, SO_REUSEADDR, &(int){1}, sizeof(int)) < 0) { + printf("Cannot configure server listen socket. Error is 0x%x\n", +#ifdef _MSC_VER + WSAGetLastError() +#else + errno +#endif + ); + closesocket(*listen_socket); + return false; + } + + libspdm_zero_mem(&my_address, sizeof(my_address)); + my_address.sin_port = htons((short)port_number); + my_address.sin_family = AF_INET; + + res = bind(*listen_socket, (struct sockaddr *)&my_address, + sizeof(my_address)); + if (res == SOCKET_ERROR) { + printf("Bind error. Error is 0x%x\n", +#ifdef _MSC_VER + WSAGetLastError() +#else + errno +#endif + ); + closesocket(*listen_socket); + return false; + } + + res = listen(*listen_socket, 3); + if (res == SOCKET_ERROR) { + printf("Listen error. Error is 0x%x\n", +#ifdef _MSC_VER + WSAGetLastError() +#else + errno +#endif + ); + closesocket(*listen_socket); + return false; + } + + return true; +} diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/spdm_caliptra.h b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/spdm_caliptra.h new file mode 100644 index 00000000..c6c4212c --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/spdm_caliptra.h @@ -0,0 +1,202 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#ifndef __SPDM_TEST_H__ +#define __SPDM_TEST_H__ + +#include "hal/base.h" +#include "hal/library/memlib.h" +#include "library/spdm_common_lib.h" +#include "spdm_device_secret_lib_internal.h" + +#include "os_include.h" +#include "stdio.h" +#include "stdlib.h" +#include "string.h" +#include "assert.h" +#include "time.h" +#include "command.h" +#include "nv_storage.h" + +extern uint32_t m_use_transport_layer; +extern uint32_t m_use_tcp_handshake; +extern uint8_t m_use_version; +extern uint8_t m_use_secured_message_version; +extern uint32_t m_use_requester_capability_flags; +extern uint32_t m_use_responder_capability_flags; +extern uint32_t m_use_capability_flags; +extern uint32_t m_use_peer_capability_flags; + +extern uint8_t m_use_basic_mut_auth; +extern uint8_t m_use_mut_auth; +extern uint8_t m_use_measurement_summary_hash_type; +extern uint8_t m_use_measurement_operation; +extern uint8_t m_use_measurement_attribute; +extern uint8_t m_use_slot_id; +extern uint8_t m_use_slot_count; +extern bool g_private_key_mode; + +#define ENCAP_KEY_UPDATE 0x8000 +extern libspdm_key_update_action_t m_use_key_update_action; + +extern uint32_t m_use_hash_algo; +extern uint32_t m_use_measurement_hash_algo; +extern uint32_t m_use_asym_algo; +extern uint16_t m_use_req_asym_algo; + +extern uint8_t m_support_measurement_spec; +extern uint8_t m_support_mel_spec; +extern uint32_t m_support_measurement_hash_algo; +extern uint32_t m_support_hash_algo; +extern uint32_t m_support_asym_algo; +extern uint16_t m_support_req_asym_algo; +extern uint16_t m_support_dhe_algo; +extern uint16_t m_support_aead_algo; +extern uint16_t m_support_key_schedule_algo; +extern uint8_t m_support_other_params_support; + +extern uint8_t m_session_policy; +extern uint8_t m_end_session_attributes; + +extern char *m_load_state_file_name; +extern char *m_save_state_file_name; + +#define EXE_MODE_SHUTDOWN 0 +#define EXE_MODE_CONTINUE 1 +extern uint32_t m_exe_mode; + +#define EXE_CONNECTION_VERSION_ONLY 0x1 +#define EXE_CONNECTION_DIGEST 0x2 +#define EXE_CONNECTION_CERT 0x4 +#define EXE_CONNECTION_CHAL 0x8 +#define EXE_CONNECTION_MEAS 0x10 +#define EXE_CONNECTION_SET_CERT 0x20 +#define EXE_CONNECTION_GET_CSR 0x40 +extern uint32_t m_exe_connection; + +#define EXE_SESSION_KEY_EX 0x1 +#define EXE_SESSION_PSK 0x2 +#define EXE_SESSION_NO_END 0x4 +#define EXE_SESSION_KEY_UPDATE 0x8 +#define EXE_SESSION_HEARTBEAT 0x10 +#define EXE_SESSION_MEAS 0x20 +#define EXE_SESSION_SET_CERT 0x40 +#define EXE_SESSION_GET_CSR 0x80 +#define EXE_SESSION_DIGEST 0x100 +#define EXE_SESSION_CERT 0x200 +#define EXE_SESSION_APP 0x400 +extern uint32_t m_exe_session; + +void libspdm_dump_hex_str(const uint8_t *buffer, size_t buffer_size); + +void dump_data(const uint8_t *buffer, size_t buffer_size); + +void dump_hex(const uint8_t *buffer, size_t buffer_size); + +bool send_platform_data(SOCKET socket, uint32_t command, + const uint8_t *send_buffer, size_t bytes_to_send); + +bool receive_platform_data(SOCKET socket, uint32_t *command, + uint8_t *receive_buffer, + size_t *bytes_to_receive); + +libspdm_return_t spdm_device_acquire_sender_buffer( + void *context, void **msg_buf_ptr); + +void spdm_device_release_sender_buffer( + void *context, const void *msg_buf_ptr); + +libspdm_return_t spdm_device_acquire_receiver_buffer( + void *context, void **msg_buf_ptr); + +void spdm_device_release_receiver_buffer( + void *context, const void *msg_buf_ptr); + +bool libspdm_read_input_file(const char *file_name, void **file_data, + size_t *file_size); + +bool libspdm_write_output_file(const char *file_name, const void *file_data, + size_t file_size); + +bool open_pcap_packet_file(const char *pcap_file_name); + +void close_pcap_packet_file(void); + +void append_pcap_packet_data(const void *header, size_t header_size, + const void *data, size_t size); + +void process_args(char *program_name, int argc, char *argv[]); + +bool create_socket(uint16_t port_number, SOCKET *listen_socket); + +bool init_client(SOCKET *sock, uint16_t port); + +bool read_bytes(const SOCKET socket, uint8_t *buffer, + uint32_t number_of_bytes); + +bool write_bytes(const SOCKET socket, const uint8_t *buffer, + uint32_t number_of_bytes); + +#define LIBSPDM_TRANSPORT_HEADER_SIZE 64 +#define LIBSPDM_TRANSPORT_TAIL_SIZE 64 + +/* define common LIBSPDM_TRANSPORT_ADDITIONAL_SIZE. It should be the biggest one. */ +#define LIBSPDM_TRANSPORT_ADDITIONAL_SIZE \ + (LIBSPDM_TRANSPORT_HEADER_SIZE + LIBSPDM_TRANSPORT_TAIL_SIZE) + +#if LIBSPDM_TRANSPORT_ADDITIONAL_SIZE < LIBSPDM_NONE_TRANSPORT_ADDITIONAL_SIZE +#error LIBSPDM_TRANSPORT_ADDITIONAL_SIZE is smaller than the required size in NONE +#endif +#if LIBSPDM_TRANSPORT_ADDITIONAL_SIZE < LIBSPDM_TCP_TRANSPORT_ADDITIONAL_SIZE +#error LIBSPDM_TRANSPORT_ADDITIONAL_SIZE is smaller than the required size in TCP +#endif +#if LIBSPDM_TRANSPORT_ADDITIONAL_SIZE < LIBSPDM_PCI_DOE_TRANSPORT_ADDITIONAL_SIZE +#error LIBSPDM_TRANSPORT_ADDITIONAL_SIZE is smaller than the required size in PCI_DOE +#endif +#if LIBSPDM_TRANSPORT_ADDITIONAL_SIZE < LIBSPDM_MCTP_TRANSPORT_ADDITIONAL_SIZE +#error LIBSPDM_TRANSPORT_ADDITIONAL_SIZE is smaller than the required size in MCTP +#endif + +#ifndef LIBSPDM_SENDER_BUFFER_SIZE +#define LIBSPDM_SENDER_BUFFER_SIZE (0x1100 + \ + LIBSPDM_TRANSPORT_ADDITIONAL_SIZE) +#endif +#ifndef LIBSPDM_RECEIVER_BUFFER_SIZE +#define LIBSPDM_RECEIVER_BUFFER_SIZE (0x1200 + \ + LIBSPDM_TRANSPORT_ADDITIONAL_SIZE) +#endif + +/* Maximum size of a single SPDM message. + * It matches DataTransferSize in SPDM specification. */ +#define LIBSPDM_SENDER_DATA_TRANSFER_SIZE (LIBSPDM_SENDER_BUFFER_SIZE - \ + LIBSPDM_TRANSPORT_ADDITIONAL_SIZE) +#define LIBSPDM_RECEIVER_DATA_TRANSFER_SIZE (LIBSPDM_RECEIVER_BUFFER_SIZE - \ + LIBSPDM_TRANSPORT_ADDITIONAL_SIZE) +#define LIBSPDM_DATA_TRANSFER_SIZE LIBSPDM_RECEIVER_DATA_TRANSFER_SIZE + +#if (LIBSPDM_SENDER_BUFFER_SIZE > LIBSPDM_RECEIVER_BUFFER_SIZE) +#define LIBSPDM_MAX_SENDER_RECEIVER_BUFFER_SIZE LIBSPDM_SENDER_BUFFER_SIZE +#else +#define LIBSPDM_MAX_SENDER_RECEIVER_BUFFER_SIZE LIBSPDM_RECEIVER_BUFFER_SIZE +#endif + +/* Maximum size of a large SPDM message. + * If chunk is unsupported, it must be same as DATA_TRANSFER_SIZE. + * If chunk is supported, it must be larger than DATA_TRANSFER_SIZE. + * It matches MaxSPDMmsgSize in SPDM specification. */ +#ifndef LIBSPDM_MAX_SPDM_MSG_SIZE +#define LIBSPDM_MAX_SPDM_MSG_SIZE 0x1200 +#endif + +/* expose it because the responder/requester may use it to send/receive other message such as DOE discovery */ +extern uint8_t m_send_receive_buffer[LIBSPDM_MAX_SENDER_RECEIVER_BUFFER_SIZE]; +extern size_t m_send_receive_buffer_size; + +#ifndef LIBSPDM_MAX_CSR_SIZE +#define LIBSPDM_MAX_CSR_SIZE 0xffff +#endif + +#endif diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/support.c b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/support.c new file mode 100644 index 00000000..76fe4087 --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_common/support.c @@ -0,0 +1,113 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#include "spdm_caliptra.h" + +void libspdm_dump_hex_str(const uint8_t *buffer, size_t buffer_size) +{ + size_t index; + + for (index = 0; index < buffer_size; index++) { + printf("%02x", buffer[index]); + } +} + +void dump_data(const uint8_t *buffer, size_t buffer_size) +{ + size_t index; + + for (index = 0; index < buffer_size; index++) { + printf("%02x ", buffer[index]); + } +} + +void dump_hex(const uint8_t *data, size_t size) +{ + size_t index; + size_t count; + size_t left; + +#define COLUME_SIZE (16 * 2) + + count = size / COLUME_SIZE; + left = size % COLUME_SIZE; + for (index = 0; index < count; index++) { + printf("%04x: ", (uint32_t)(index * COLUME_SIZE)); + dump_data(data + index * COLUME_SIZE, COLUME_SIZE); + printf("\n"); + } + + if (left != 0) { + printf("%04x: ", (uint32_t)(index * COLUME_SIZE)); + dump_data(data + index * COLUME_SIZE, left); + printf("\n"); + } +} + +bool libspdm_read_input_file(const char *file_name, void **file_data, + size_t *file_size) +{ + FILE *fp_in; + size_t temp_result; + + if ((fp_in = fopen(file_name, "rb")) == NULL) { + printf("Unable to open file %s\n", file_name); + *file_data = NULL; + return false; + } + + fseek(fp_in, 0, SEEK_END); + *file_size = ftell(fp_in); + if (*file_size == -1) { + printf("Unable to get the file size %s\n", file_name); + *file_data = NULL; + fclose(fp_in); + return false; + } + + *file_data = (void *)malloc(*file_size); + if (NULL == *file_data) { + printf("No sufficient memory to allocate %s\n", file_name); + fclose(fp_in); + return false; + } + + fseek(fp_in, 0, SEEK_SET); + temp_result = fread(*file_data, 1, *file_size, fp_in); + if (temp_result != *file_size) { + printf("Read input file error %s", file_name); + free((void *)*file_data); + fclose(fp_in); + return false; + } + + fclose(fp_in); + + return true; +} + +bool libspdm_write_output_file(const char *file_name, const void *file_data, + size_t file_size) +{ + FILE *fp_out; + + if ((fp_out = fopen(file_name, "w+b")) == NULL) { + printf("Unable to open file %s\n", file_name); + return false; + } + + if (file_size != 0) { + if ((fwrite(file_data, 1, file_size, fp_out)) != file_size) { + printf("Write output file error %s\n", file_name); + fclose(fp_out); + return false; + } + } + + fclose(fp_out); + + return true; +} diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/CMakeLists.txt b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/CMakeLists.txt new file mode 100644 index 00000000..a6f980f8 --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/CMakeLists.txt @@ -0,0 +1,47 @@ +cmake_minimum_required(VERSION 2.6) + +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/spdm_caliptra/spdm_caliptra_requester + ${PROJECT_SOURCE_DIR}/spdm_caliptra/spdm_caliptra_common + ${PROJECT_SOURCE_DIR}/include + ${LIBSPDM_DIR}/os_stub/spdm_device_secret_lib_sample + ${LIBSPDM_DIR}/include + ${LIBSPDM_DIR}/os_stub/include + ${LIBSPDM_DIR}/os_stub +) + +SET(src_spdm_caliptra_requester + spdm_requester_spdm.c + spdm_caliptra_requester_authentication.c + spdm_requester_session.c + spdm_requester_mctp.c + spdm_caliptra_requester.c + ${PROJECT_SOURCE_DIR}/spdm_caliptra/spdm_caliptra_common/spdm_caliptra.c + ${PROJECT_SOURCE_DIR}/spdm_caliptra/spdm_caliptra_common/command.c + ${PROJECT_SOURCE_DIR}/spdm_caliptra/spdm_caliptra_common/key.c + ${PROJECT_SOURCE_DIR}/spdm_caliptra/spdm_caliptra_common/nv_storage.c + ${PROJECT_SOURCE_DIR}/spdm_caliptra/spdm_caliptra_common/pcap.c + ${PROJECT_SOURCE_DIR}/spdm_caliptra/spdm_caliptra_common/support.c +) + +SET(spdm_caliptra_requester_LIBRARY + memlib + debuglib + spdm_requester_lib + spdm_common_lib + ${CRYPTO_LIB_PATHS} + rnglib + cryptlib_${CRYPTO} + malloclib + spdm_crypt_lib + spdm_crypt_ext_lib + spdm_secured_message_lib + spdm_transport_mctp_lib + spdm_device_secret_lib_sample + mctp_requester_lib + platform_lib +) + + +#ADD_EXECUTABLE(spdm_caliptra_requester ${src_spdm_caliptra_requester}) +ADD_LIBRARY(spdm_caliptra_requester STATIC ${src_spdm_caliptra_requester}) +TARGET_LINK_LIBRARIES(spdm_caliptra_requester ${spdm_caliptra_requester_LIBRARY}) diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_caliptra_requester.c b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_caliptra_requester.c new file mode 100644 index 00000000..a928e317 --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_caliptra_requester.c @@ -0,0 +1,308 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#include "spdm_caliptra_requester.h" +#include "internal/libspdm_requester_lib.h" + +uint8_t m_receive_buffer[LIBSPDM_MAX_SENDER_RECEIVER_BUFFER_SIZE]; + +extern SOCKET m_socket; + +extern void *m_spdm_context; +extern void *m_scratch_buffer; + +uint8_t m_other_slot_id = 0; + +// #if LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP +// libspdm_return_t do_measurement_via_spdm(const uint32_t *session_id); +// #endif /*LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP*/ + +// #if (LIBSPDM_ENABLE_CAPABILITY_CERT_CAP && LIBSPDM_ENABLE_CAPABILITY_CHAL_CAP) +// libspdm_return_t do_authentication_via_spdm(void); +// #endif /*(LIBSPDM_ENABLE_CAPABILITY_CERT_CAP && LIBSPDM_ENABLE_CAPABILITY_CHAL_CAP)*/ + +// libspdm_return_t do_session_via_spdm(bool use_psk); +// libspdm_return_t do_certificate_provising_via_spdm(uint32_t *session_id); + +bool platform_client_routine(uint16_t port_number, void **m_temp, size_t *cert_chain_data_size, int *a) +{ + printf("%s version 0.1\n", "spdm_requester_emu"); + printf("\nCHECKPOINT 10AAAA111 %p\n", *m_temp); + srand((unsigned int)time(NULL)); + + SOCKET platform_socket; + bool result; + uint32_t response; + size_t response_size; + libspdm_return_t status; + + //*cert_chain_data_size = 2; // CHECKPOINT2 + result = init_client(&platform_socket, port_number); + if (!result) + { + return false; + } + + m_socket = platform_socket; + + result = false; + + //*cert_chain_data_size = 3; // CHECKPOINT3 + m_spdm_context = spdm_client_init(); + if (m_spdm_context == NULL) + { + goto done; + } + //*cert_chain_data_size = 4; // CHECKPOINT4 + +// /* Do test - begin*/ +#if (LIBSPDM_ENABLE_CAPABILITY_CERT_CAP && LIBSPDM_ENABLE_CAPABILITY_CHAL_CAP) + // status = do_authentication_via_spdm(); + void *spdm_context; + uint8_t slot_mask; + uint8_t total_digest_buffer[LIBSPDM_MAX_HASH_SIZE * SPDM_MAX_SLOT_COUNT]; + uint8_t measurement_hash[LIBSPDM_MAX_HASH_SIZE]; + size_t cert_chain_size; + uint8_t cert_chain[LIBSPDM_MAX_CERT_CHAIN_SIZE]; + + spdm_context = m_spdm_context; + + libspdm_zero_mem(total_digest_buffer, sizeof(total_digest_buffer)); + cert_chain_size = sizeof(cert_chain); + libspdm_zero_mem(cert_chain, sizeof(cert_chain)); + libspdm_zero_mem(measurement_hash, sizeof(measurement_hash)); + //*cert_chain_data_size = 5; // CHECKPOINT5 + status = spdm_authentication(spdm_context, &slot_mask, + &total_digest_buffer, m_use_slot_id, + &cert_chain_size, cert_chain, + m_use_measurement_summary_hash_type, + measurement_hash); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + printf("do_authentication_via_spdm - %x\n", (uint32_t)status); + goto done; + } + printf("\nCHECKPOINT 9AAAAAAAA"); + uint8_t *cert_chain_data; + size_t hash_sizex; + //*cert_chain_data_size = 6; // CHECKPOINT6 + + cert_chain_data = cert_chain; + *cert_chain_data_size = cert_chain_size; + printf("\nCHECKPOINT 9AAAAAAAA %ld\n", *cert_chain_data_size); + hash_sizex = libspdm_get_hash_size(((libspdm_context_t *)m_spdm_context)->connection_info.algorithm.base_hash_algo); + + cert_chain_data = cert_chain_data + sizeof(spdm_cert_chain_t) + hash_sizex; + *cert_chain_data_size = *cert_chain_data_size - (sizeof(spdm_cert_chain_t) + hash_sizex); + + *m_temp = malloc(sizeof(unsigned char) * (*cert_chain_data_size)); +#define MEMORY_ALLOCATION_FAILED 0xF0 + + if (NULL == *m_temp) + { + printf("Memory allocation failed\n"); + return MEMORY_ALLOCATION_FAILED; + } + memcpy(*m_temp, cert_chain_data, *cert_chain_data_size); + + printf("\nCHECKPOINT 9BBB %ld\n", cert_chain_size); + + printf("\nCHECKPOINT 10XXXXXXXXXXXXX11110XXXXXXXXXXXXX11110XXXXXXXXXXXXX11110XXXXXXXXXXXXX111"); + int i; + int k = *cert_chain_data_size; + printf("\nCHECKPOINT 9BBB KKKK %d\n", k); + + for (i = 0; i < *cert_chain_data_size; i++) + { + printf("%x ", ((uint8_t *)*m_temp)[i]); + } + + printf("\n\n"); + for (i = 0; i < *cert_chain_data_size; i++) + { + printf("%d ", ((uint8_t *)*m_temp)[i]); + } + printf("\nCHECKPOINT 9C\n"); + +#endif /*(LIBSPDM_ENABLE_CAPABILITY_CERT_CAP && LIBSPDM_ENABLE_CAPABILITY_CHAL_CAP)*/ + // #if LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP + // if ((m_exe_connection & EXE_CONNECTION_MEAS) != 0) { + // status = do_measurement_via_spdm(NULL); + // if (LIBSPDM_STATUS_IS_ERROR(status)) { + // printf("do_measurement_via_spdm - %x\n", + // (uint32_t)status); + // goto done; + // } + // } + // #endif /*LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP*/ + // /* when use --trans NONE, skip secure session */ + // if (m_use_transport_layer == SOCKET_TRANSPORT_TYPE_NONE) { + // if (m_use_version >= SPDM_MESSAGE_VERSION_12) { + // status = do_certificate_provising_via_spdm(NULL); + // if (LIBSPDM_STATUS_IS_ERROR(status)) { + // printf("do_certificate_provising_via_spdm - %x\n", + // (uint32_t)status); + // goto done; + // } + // } + // } + // else + // { + // #if (LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP || LIBSPDM_ENABLE_CAPABILITY_PSK_CAP) + // if (m_use_version >= SPDM_MESSAGE_VERSION_11) { + // if ((m_exe_session & EXE_SESSION_KEY_EX) != 0) { + // status = do_session_via_spdm(false); + // if (LIBSPDM_STATUS_IS_ERROR(status)) { + // printf("do_session_via_spdm - %x\n", + // (uint32_t)status); + // goto done; + // } + // } + + // if ((m_exe_session & EXE_SESSION_PSK) != 0) { + // status = do_session_via_spdm(true); + // if (LIBSPDM_STATUS_IS_ERROR(status)) { + // printf("do_session_via_spdm - %x\n", + // (uint32_t)status); + // goto done; + // } + // } + // if ((m_exe_session & EXE_SESSION_KEY_EX) != 0) { + // if (m_other_slot_id != 0) { + // m_use_slot_id = m_other_slot_id; + // status = do_session_via_spdm(false); + // if (LIBSPDM_STATUS_IS_ERROR(status)) { + // printf("do_session_via_spdm - %x\n", + // (uint32_t)status); + // goto done; + // } + // } + // } + // } + // #endif /*(LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP || LIBSPDM_ENABLE_CAPABILITY_PSK_CAP)*/ + // } + /* Do test - end*/ + + result = true; + printf("\n%d\n", *a); + *a = 10; + printf("\n%d\n", *a); + printf("\nCHECKPOINT 10XXXXXXXXXXXXX111 %p\n", *m_temp); +done: + response_size = 0; + if (!communicate_platform_data( + m_socket, SOCKET_SPDM_COMMAND_SHUTDOWN - m_exe_mode, + NULL, 0, &response, &response_size, NULL)) + { + return false; + } + + if (m_spdm_context != NULL) + { + libspdm_deinit_context(m_spdm_context); + free(m_spdm_context); + free(m_scratch_buffer); + } + + closesocket(platform_socket); + + printf("Client stopped\n"); + + close_pcap_packet_file(); + + return result; +} + +int main1(char* caliptra_dpe_profile, int port_number, void **temp, size_t *cert_chain_data_size) +{ + bool result; + int myresult; + int a; + a = 5; + + if (strcmp(caliptra_dpe_profile, DPE_PROFILE_IROT_P256_SHA256) == 0){ + m_use_measurement_hash_algo = SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA_256; + m_use_hash_algo = SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_256; + m_use_asym_algo = SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256; + m_use_req_asym_algo = SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048; + myresult = 11; + }else if(strcmp(caliptra_dpe_profile, DPE_PROFILE_IROT_P384_SHA384) == 0){ + m_use_measurement_hash_algo = SPDM_ALGORITHMS_MEASUREMENT_HASH_ALGO_TPM_ALG_SHA_384; + m_use_hash_algo = SPDM_ALGORITHMS_BASE_HASH_ALGO_TPM_ALG_SHA_384; + m_use_asym_algo = SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384; + m_use_req_asym_algo = SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048; + myresult = 12; + }else{ + myresult = 13; + return myresult; + } + // size_t cert_chain_data_size = 0; + // void *temp; + unsigned char *temp1; + // temp = malloc(sizeof(unsigned char) * 2000); + + // cert_chain_data_size = 0; + //*cert_chain_data_size = 1; // CHECKPOINT1 + printf("\nCHECKPOINT 10AAAA %p\n", temp); + result = platform_client_routine(DEFAULT_SPDM_PLATFORM_PORT, temp, cert_chain_data_size, &a); + if (!result){ myresult = 14;} + + printf("\nCHECKPOINT 10A\n"); + + printf("\n%ld\n", *cert_chain_data_size); + // printf("\n%ln\n", &cert_chain_data_size); + + temp1 = (uint8_t *)*temp; + printf("\nCHECKPOINT 1000000000KKKKKKKKKKKKKKKKKKKKKKK %p\n", *temp); + int i; + for (i = 0; i < *cert_chain_data_size; i++) + { + printf("%x ", (uint8_t)temp1[i]); + } + printf("\n\n"); + for (i = 0; i < *cert_chain_data_size; i++) + { + printf("%d ", (uint8_t)temp1[i]); + } + printf("\nCHECKPOINT 10B\n"); + printf("\n%d\n", a); + + return (myresult); +} + +// int main(int argc, char *argv[]) +// { +// bool result; +// size_t cert_chain_data_size = 0; +// void *temp; +// unsigned char *temp1; +// // unsigned char *temp1; +// // temp = malloc(sizeof(unsigned char) * 2000); + +// // cert_chain_data_size = 0; +// printf("\nCHECKPOINT GAAAAAAAAAAAAAAAAAAA %p\n", temp); +// result = main1(&temp, &cert_chain_data_size); + +// printf("\nCHECKPOINT HHHHHHHHHHHHHHHHHHA\n"); +// printf("\n%ld\n", cert_chain_data_size); +// // printf("\n%ln\n", &cert_chain_data_size); + +// temp1 = (uint8_t *)temp; +// printf("\nCHECKPOINT IIIIIIIIIIIIIIIIIIIIIIIIIIIIII %p\n", temp); +// int i; +// for (i = 0; i < cert_chain_data_size; i++) +// { +// printf("%x ", (uint8_t)temp1[i]); +// } +// printf("\n\n"); +// for (i = 0; i < cert_chain_data_size; i++) +// { +// printf("%d ", (uint8_t)temp1[i]); +// } +// printf("\nCHECKPOINT JJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJJ\n"); + +// return (!result); +// } \ No newline at end of file diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_caliptra_requester.h b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_caliptra_requester.h new file mode 100644 index 00000000..bf8929fe --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_caliptra_requester.h @@ -0,0 +1,49 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#ifndef __SPDM_REQUESTER_TEST_H__ +#define __SPDM_REQUESTER_TEST_H__ + +#include "hal/base.h" +#include "hal/library/memlib.h" +#include "library/spdm_requester_lib.h" +#include "library/spdm_transport_mctp_lib.h" +#include "library/mctp_requester_lib.h" + +#include "os_include.h" +#include "stdio.h" +#include "spdm_caliptra.h" + +extern uint8_t m_other_slot_id; + +#endif + +void *spdm_client_init(void); +int main1(char* caliptra_dpe_profile, int port_number, void **temp, size_t *cert_chain_data_size); + +bool communicate_platform_data(SOCKET socket, uint32_t command, + const uint8_t *send_buffer, size_t bytes_to_send, + uint32_t *response, + size_t *bytes_to_receive, + uint8_t *receive_buffer); + +libspdm_return_t spdm_authentication(void *context, uint8_t *slot_mask, + void *total_digest_buffer, uint8_t slot_id, + size_t *cert_chain_size, void *cert_chain, + uint8_t measurement_hash_type, void *measurement_hash); + +bool communicate_platform_data(SOCKET socket, uint32_t command, + const uint8_t *send_buffer, size_t bytes_to_send, + uint32_t *response, + size_t *bytes_to_receive, + uint8_t *receive_buffer); + +// #if LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP +// libspdm_return_t do_measurement_via_spdm(const uint32_t *session_id); +// #endif /*LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP*/ + +libspdm_return_t mctp_process_session_message(void *spdm_context, uint32_t session_id); +libspdm_return_t do_certificate_provising_via_spdm(uint32_t *session_id); \ No newline at end of file diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_caliptra_requester_authentication.c b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_caliptra_requester_authentication.c new file mode 100644 index 00000000..af34e436 --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_caliptra_requester_authentication.c @@ -0,0 +1,226 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#include "spdm_caliptra_requester.h" +#include "internal/libspdm_requester_lib.h" + +#if (LIBSPDM_ENABLE_CAPABILITY_CERT_CAP && LIBSPDM_ENABLE_CAPABILITY_CHAL_CAP) + +extern void *m_spdm_context; + +/** + * This function sends GET_DIGEST, GET_CERTIFICATE, CHALLENGE + * to authenticate the device. + * + * This function is combination of libspdm_get_digest, libspdm_get_certificate, libspdm_challenge. + * + * @param spdm_context A pointer to the SPDM context. + * @param slot_mask The slots which deploy the CertificateChain. + * @param total_digest_buffer A pointer to a destination buffer to store the digest buffer. + * @param slot_id The number of slot for the certificate chain. + * @param cert_chain_size On input, indicate the size in bytes of the destination buffer to store the digest buffer. + * On output, indicate the size in bytes of the certificate chain. + * @param cert_chain A pointer to a destination buffer to store the certificate chain. + * @param measurement_hash_type The type of the measurement hash. + * @param measurement_hash A pointer to a destination buffer to store the measurement hash. + * + * @retval LIBSPDM_STATUS_SUCCESS The authentication is got successfully. + * @retval RETURN_DEVICE_ERROR A device error occurs when communicates with the device. + * @retval RETURN_SECURITY_VIOLATION Any verification fails. + **/ +libspdm_return_t +spdm_authentication(void *context, uint8_t *slot_mask, + void *total_digest_buffer, uint8_t slot_id, + size_t *cert_chain_size, void *cert_chain, + uint8_t measurement_hash_type, void *measurement_hash) +{ + libspdm_return_t status; + // size_t cert_chain_buffer_size; + uint8_t index; + // uint8_t requester_context[SPDM_REQ_CONTEXT_SIZE] = { + // 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77, 0x88}; + + if ((m_exe_connection & EXE_CONNECTION_DIGEST) != 0) + { + status = libspdm_get_digest(context, NULL, slot_mask, + total_digest_buffer); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + return status; + } + for (index = 1; index < SPDM_MAX_SLOT_COUNT; index++) + { + if ((*slot_mask & (1 << index)) != 0) + { + m_other_slot_id = index; + } + } + } + printf("\nCHECKPOINT 9.0\n"); + // printf("%lx ", *cert_chain_size); + printf("\nCHECKPOINT 9.0B\n"); + + // cert_chain_buffer_size = *cert_chain_size; + + if ((m_exe_connection & EXE_CONNECTION_CERT) != 0) + { + if (slot_id != 0xFF) + { + if (slot_id == 0) + { + printf("\nCHECKPOINT 1\n"); + status = libspdm_get_certificate( + context, NULL, 0, cert_chain_size, cert_chain); + printf("\nCHECKPOINT 1B\n"); + printf("\nCHECKPOINT 9.1\n"); + printf("%lx ", *cert_chain_size); + printf("\nCHECKPOINT 9.1B\n"); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + return status; + } + // if (m_other_slot_id != 0) + // { + // printf("\nCHECKPOINT 2\n"); + // *cert_chain_size = cert_chain_buffer_size; + // libspdm_zero_mem(cert_chain, cert_chain_buffer_size); + // status = libspdm_get_certificate( + // context, NULL, m_other_slot_id, cert_chain_size, cert_chain); + // printf("\nCHECKPOINT 9.2\n"); + // printf("%lx ", *cert_chain_size); + // printf("\nCHECKPOINT 9.2B\n"); + // if (LIBSPDM_STATUS_IS_ERROR(status)) + // { + // return status; + // } + // printf("CHECKPOINT 2B\n"); + // } + } + // else + // { + // printf("\nCHECKPOINT 3\n"); + // status = libspdm_get_certificate( + // context, NULL, slot_id, cert_chain_size, cert_chain); + // if (LIBSPDM_STATUS_IS_ERROR(status)) + // { + // return status; + // } + // printf("\nCHECKPOINT 3B\n"); + // } + } + } + + // if ((m_exe_connection & EXE_CONNECTION_CHAL) != 0) + // { + // printf("\nCHECKPOINT 4\n"); + // status = libspdm_challenge_ex2(context, NULL, slot_id, requester_context, + // measurement_hash_type, measurement_hash, + // NULL, NULL, NULL, NULL, NULL, NULL); + // if (LIBSPDM_STATUS_IS_ERROR(status)) + // { + // return status; + // } + // printf("\nCHECKPOINT 4B\n"); + // } + + // if ((m_exe_connection & EXE_CONNECTION_DIGEST) != 0) + // { + // printf("\nCHECKPOINT 5\n"); + // status = libspdm_get_digest(context, NULL, slot_mask, + // total_digest_buffer); + // if (LIBSPDM_STATUS_IS_ERROR(status)) + // { + // return status; + // } + // printf("\nCHECKPOINT 5B\n"); + // } + + // if ((m_exe_connection & EXE_CONNECTION_CERT) != 0) + // { + // printf("\nCHECKPOINT 6\n"); + // if (slot_id != 0xFF) + // { + // printf("\nCHECKPOINT 7\n"); + // *cert_chain_size = cert_chain_buffer_size; + // status = libspdm_get_certificate( + // context, NULL, slot_id, cert_chain_size, cert_chain); + // printf("\nCHECKPOINT 9.7\n"); + // printf("%lx ", *cert_chain_size); + // printf("\nCHECKPOINT 9.7B\n"); + // printf("\nCHECKPOINT 7B\n"); + + // if (LIBSPDM_STATUS_IS_ERROR(status)) + // { + // return status; + // } + // } + // printf("\nCHECKPOINT 6B\n"); + // } + + // if ((m_exe_connection & EXE_CONNECTION_DIGEST) != 0) + // { + // printf("\nCHECKPOINT 8\n"); + + // status = libspdm_get_digest(context, NULL, slot_mask, + // total_digest_buffer); + // if (LIBSPDM_STATUS_IS_ERROR(status)) + // { + // return status; + // } + // printf("\nCHECKPOINT 8B\n"); + // } + + printf("\nCHECKPOINT 9\n"); + int i; + for (i = 0; i < *cert_chain_size; i++) + { + printf("%d ", ((uint8_t *)cert_chain)[i]); + } + + printf("\n\n\n\n"); + + for (i = 0; i < *cert_chain_size; i++) + { + printf("%x ", ((uint8_t *)cert_chain)[i]); + } + printf("\nCHECKPOINT 9B\n"); + return LIBSPDM_STATUS_SUCCESS; +} + +/** + * This function executes SPDM authentication. + * + * @param[in] spdm_context The SPDM context for the device. + **/ +libspdm_return_t do_authentication_via_spdm(void) +{ + libspdm_return_t status; + void *spdm_context; + uint8_t slot_mask; + uint8_t total_digest_buffer[LIBSPDM_MAX_HASH_SIZE * SPDM_MAX_SLOT_COUNT]; + uint8_t measurement_hash[LIBSPDM_MAX_HASH_SIZE]; + size_t cert_chain_size; + uint8_t cert_chain[LIBSPDM_MAX_CERT_CHAIN_SIZE]; + + spdm_context = m_spdm_context; + + libspdm_zero_mem(total_digest_buffer, sizeof(total_digest_buffer)); + cert_chain_size = sizeof(cert_chain); + libspdm_zero_mem(cert_chain, sizeof(cert_chain)); + libspdm_zero_mem(measurement_hash, sizeof(measurement_hash)); + status = spdm_authentication(spdm_context, &slot_mask, + &total_digest_buffer, m_use_slot_id, + &cert_chain_size, cert_chain, + m_use_measurement_summary_hash_type, + measurement_hash); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + return status; + } + return LIBSPDM_STATUS_SUCCESS; +} + +#endif /*(LIBSPDM_ENABLE_CAPABILITY_CERT_CAP && LIBSPDM_ENABLE_CAPABILITY_CHAL_CAP)*/ diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_requester_mctp.c b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_requester_mctp.c new file mode 100644 index 00000000..4f7457e1 --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_requester_mctp.c @@ -0,0 +1,22 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#include "spdm_caliptra_requester.h" + +void *m_mctp_context; + +libspdm_return_t mctp_process_session_message(void *spdm_context, uint32_t session_id) +{ + uint8_t tid; + libspdm_return_t status; + + status = pldm_control_get_tid (m_mctp_context, spdm_context, &session_id, &tid); + if (LIBSPDM_STATUS_IS_ERROR(status)) { + return status; + } + + return LIBSPDM_STATUS_SUCCESS; +} diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_requester_session.c b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_requester_session.c new file mode 100644 index 00000000..0a7b5e27 --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_requester_session.c @@ -0,0 +1,313 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#include "spdm_caliptra_requester.h" + +#if (LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP || LIBSPDM_ENABLE_CAPABILITY_PSK_CAP) + +extern SOCKET m_socket; + +extern void *m_spdm_context; + +libspdm_return_t do_app_session_via_spdm(uint32_t session_id) +{ + libspdm_return_t status = LIBSPDM_STATUS_SUCCESS; + + if (m_use_transport_layer == SOCKET_TRANSPORT_TYPE_MCTP) + { + status = mctp_process_session_message(m_spdm_context, session_id); + } + + return status; +} + +libspdm_return_t get_digest_cert_in_session(const uint32_t *session_id) +{ + libspdm_return_t status; + void *spdm_context; + uint8_t slot_mask; + uint8_t total_digest_buffer[LIBSPDM_MAX_HASH_SIZE * SPDM_MAX_SLOT_COUNT]; + uint8_t measurement_hash[LIBSPDM_MAX_HASH_SIZE]; + size_t cert_chain_size; + uint8_t cert_chain[LIBSPDM_MAX_CERT_CHAIN_SIZE]; + + spdm_context = m_spdm_context; + libspdm_zero_mem(total_digest_buffer, sizeof(total_digest_buffer)); + cert_chain_size = sizeof(cert_chain); + libspdm_zero_mem(cert_chain, sizeof(cert_chain)); + libspdm_zero_mem(measurement_hash, sizeof(measurement_hash)); + + if ((m_exe_session & EXE_SESSION_DIGEST) != 0) + { + status = libspdm_get_digest(spdm_context, session_id, &slot_mask, total_digest_buffer); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + return status; + } + } + if ((m_exe_session & EXE_SESSION_CERT) != 0) + { + if (m_use_slot_id != 0xFF) + { + status = libspdm_get_certificate_ex( + spdm_context, session_id, m_use_slot_id, &cert_chain_size, cert_chain, NULL, 0); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + return status; + } + } + } + + return status; +} + +libspdm_return_t do_session_via_spdm(bool use_psk) +{ + void *spdm_context; + libspdm_return_t status; + uint32_t session_id; + uint8_t heartbeat_period; + uint8_t measurement_hash[LIBSPDM_MAX_HASH_SIZE]; + size_t response_size; + bool result; + uint32_t response; + + spdm_context = m_spdm_context; + + heartbeat_period = 0; + libspdm_zero_mem(measurement_hash, sizeof(measurement_hash)); + status = libspdm_start_session(spdm_context, use_psk, + LIBSPDM_TEST_PSK_HINT_STRING, + sizeof(LIBSPDM_TEST_PSK_HINT_STRING), + m_use_measurement_summary_hash_type, + m_use_slot_id, m_session_policy, &session_id, + &heartbeat_period, measurement_hash); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + printf("libspdm_start_session - %x\n", (uint32_t)status); + return status; + } + + if ((m_exe_session & EXE_SESSION_APP) != 0) + { + status = do_app_session_via_spdm(session_id); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + printf("do_app_session_via_spdm - %x\n", (uint32_t)status); + return status; + } + } + + if ((m_exe_session & EXE_SESSION_HEARTBEAT) != 0) + { + status = libspdm_heartbeat(spdm_context, session_id); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + printf("libspdm_heartbeat - %x\n", (uint32_t)status); + } + } + + if ((m_exe_session & EXE_SESSION_KEY_UPDATE) != 0) + { + switch (m_use_key_update_action) + { + case LIBSPDM_KEY_UPDATE_ACTION_REQUESTER: + status = + libspdm_key_update(spdm_context, session_id, true); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + printf("libspdm_key_update - %x\n", + (uint32_t)status); + } + break; + + case LIBSPDM_KEY_UPDATE_ACTION_MAX: + status = libspdm_key_update(spdm_context, session_id, + false); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + printf("libspdm_key_update - %x\n", + (uint32_t)status); + } + break; + + case LIBSPDM_KEY_UPDATE_ACTION_RESPONDER: + response_size = 0; + result = communicate_platform_data( + m_socket, + SOCKET_SPDM_COMMAND_OOB_ENCAP_KEY_UPDATE, NULL, + 0, &response, &response_size, NULL); + if (!result) + { + printf("communicate_platform_data - SOCKET_SPDM_COMMAND_OOB_ENCAP_KEY_UPDATE fail\n"); + } + else + { +#if (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) || (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP) + status = libspdm_send_receive_encap_request( + spdm_context, &session_id); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + printf("libspdm_send_receive_encap_request - libspdm_key_update - %x\n", + (uint32_t)status); + } +#endif + } + break; + + default: + LIBSPDM_ASSERT(false); + break; + } + } + + // #if LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP + // if ((m_exe_session & EXE_SESSION_MEAS) != 0) { + // status = do_measurement_via_spdm(&session_id); + // if (LIBSPDM_STATUS_IS_ERROR(status)) { + // printf("do_measurement_via_spdm - %x\n", + // (uint32_t)status); + // } + // } + // #endif /*LIBSPDM_ENABLE_CAPABILITY_MEAS_CAP*/ + +#if (LIBSPDM_ENABLE_CAPABILITY_CERT_CAP && LIBSPDM_ENABLE_CAPABILITY_CHAL_CAP) + status = get_digest_cert_in_session(&session_id); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + printf("get_digest_cert_in_session - %x\n", + (uint32_t)status); + } +#endif + + if (m_use_version >= SPDM_MESSAGE_VERSION_12) + { + status = do_certificate_provising_via_spdm(&session_id); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + printf("do_certificate_provising_via_spdm - %x\n", + (uint32_t)status); + return status; + } + } + + if ((m_exe_session & EXE_SESSION_NO_END) == 0) + { + status = libspdm_stop_session(spdm_context, session_id, + m_end_session_attributes); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + printf("libspdm_stop_session - %x\n", (uint32_t)status); + return status; + } + } + + return status; +} + +/* + * These function implements the request and response messages used for provisioning a device with certificate chains. + * Provisioning of Slot 0 should be only done in a secure environment (such as a secure manufacturing environment) + */ +libspdm_return_t do_certificate_provising_via_spdm(uint32_t *session_id) +{ + void *spdm_context; + +#if LIBSPDM_ENABLE_CAPABILITY_CSR_CAP + uint8_t csr_form_get[LIBSPDM_MAX_CSR_SIZE]; + size_t csr_len; +#endif /*LIBSPDM_ENABLE_CAPABILITY_CSR_CAP*/ + +#if LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP + void *cert_chain_to_set; + size_t cert_chain_size_to_set; + uint8_t slot_id; + bool res; + + cert_chain_to_set = NULL; + cert_chain_size_to_set = 0; +#endif /*LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP*/ + + libspdm_return_t status; + spdm_context = m_spdm_context; + +#if LIBSPDM_ENABLE_CAPABILITY_CSR_CAP + + /*get csr*/ + csr_len = LIBSPDM_MAX_CSR_SIZE; + libspdm_zero_mem(csr_form_get, sizeof(csr_form_get)); + if ((m_exe_connection & EXE_CONNECTION_GET_CSR) != 0) + { + status = libspdm_get_csr(spdm_context, NULL, NULL, 0, NULL, 0, csr_form_get, + &csr_len); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + printf("libspdm_get_csr - %x\n", + (uint32_t)status); + return status; + } + } + +#endif /*LIBSPDM_ENABLE_CAPABILITY_CSR_CAP*/ + +#if LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP + res = libspdm_read_responder_public_certificate_chain(m_use_hash_algo, + m_use_asym_algo, + &cert_chain_to_set, + &cert_chain_size_to_set, + NULL, NULL); + if (!res) + { + printf("set certificate :read_responder_public_certificate_chain fail!\n"); + free(cert_chain_to_set); + return LIBSPDM_STATUS_INVALID_CERT; + } + + /*set_certificate for slot_id:0 in secure environment*/ + if ((m_exe_connection & EXE_CONNECTION_SET_CERT) != 0) + { + slot_id = 0; + status = libspdm_set_certificate(spdm_context, NULL, slot_id, + cert_chain_to_set, cert_chain_size_to_set); + + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + printf("libspdm_set_certificate - %x\n", + (uint32_t)status); + free(cert_chain_to_set); + return status; + } + } + + /*set_certificate for slot_id:1 in secure session*/ + if (session_id != NULL) + { + if ((m_exe_session & EXE_SESSION_SET_CERT) != 0) + { + if (m_other_slot_id != 0) + { + slot_id = m_other_slot_id; + status = libspdm_set_certificate(spdm_context, session_id, slot_id, + cert_chain_to_set, cert_chain_size_to_set); + + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + printf("libspdm_set_certificate - %x\n", + (uint32_t)status); + } + + free(cert_chain_to_set); + return status; + } + } + } + + free(cert_chain_to_set); +#endif /*LIBSPDM_ENABLE_CAPABILITY_SET_CERT_CAP*/ + return LIBSPDM_STATUS_SUCCESS; +} + +#endif /*(LIBSPDM_ENABLE_CAPABILITY_KEY_EX_CAP || LIBSPDM_ENABLE_CAPABILITY_PSK_CAP)*/ diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_requester_spdm.c b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_requester_spdm.c new file mode 100644 index 00000000..9a692fc6 --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_requester_spdm.c @@ -0,0 +1,534 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#include "spdm_caliptra_requester.h" + +void *m_spdm_context; +#if LIBSPDM_FIPS_MODE +void *m_fips_selftest_context; +#endif /*LIBSPDM_FIPS_MODE*/ +void *m_scratch_buffer; +SOCKET m_socket; + +bool communicate_platform_data(SOCKET socket, uint32_t command, + const uint8_t *send_buffer, size_t bytes_to_send, + uint32_t *response, + size_t *bytes_to_receive, + uint8_t *receive_buffer) +{ + bool result; + + result = + send_platform_data(socket, command, send_buffer, bytes_to_send); + if (!result) + { + printf("send_platform_data Error - %x\n", +#ifdef _MSC_VER + WSAGetLastError() +#else + errno +#endif + ); + return result; + } + + result = receive_platform_data(socket, response, receive_buffer, + bytes_to_receive); + if (!result) + { + printf("receive_platform_data Error - %x\n", +#ifdef _MSC_VER + WSAGetLastError() +#else + errno +#endif + ); + return result; + } + return result; +} + +libspdm_return_t spdm_device_send_message(void *spdm_context, + size_t request_size, const void *request, + uint64_t timeout) +{ + bool result; + + result = send_platform_data(m_socket, SOCKET_SPDM_COMMAND_NORMAL, + request, (uint32_t)request_size); + if (!result) + { + printf("send_platform_data Error - %x\n", +#ifdef _MSC_VER + WSAGetLastError() +#else + errno +#endif + ); + return LIBSPDM_STATUS_SEND_FAIL; + } + return LIBSPDM_STATUS_SUCCESS; +} + +libspdm_return_t spdm_requester_device_receive_message(void *spdm_context, + size_t *response_size, + void **response, + uint64_t timeout) +{ + bool result; + uint32_t command; + + result = receive_platform_data(m_socket, &command, *response, + response_size); + if (!result) + { + printf("receive_platform_data Error - %x\n", +#ifdef _MSC_VER + WSAGetLastError() +#else + errno +#endif + ); + return LIBSPDM_STATUS_RECEIVE_FAIL; + } + return LIBSPDM_STATUS_SUCCESS; +} + +void *spdm_client_init(void) +{ + void *spdm_context; +#if LIBSPDM_FIPS_MODE + void *fips_selftest_context; +#endif /*LIBSPDM_FIPS_MODE*/ + // uint8_t index; + libspdm_return_t status; + // bool res; + // void *data; + // void *data1; + size_t data_size; + // size_t data1_size; + libspdm_data_parameter_t parameter; + uint8_t data8; + uint16_t data16; + uint32_t data32; + // void *hash; + // void *hash1; + // size_t hash_size; + // size_t hash1_size; + // const uint8_t *root_cert; + // const uint8_t *root_cert1; + // size_t root_cert_size; + // size_t root_cert1_size; + spdm_version_number_t spdm_version; + size_t scratch_buffer_size; + uint32_t requester_capabilities_flag; + uint32_t responder_capabilities_flag; + + printf("context_size - 0x%x\n", (uint32_t)libspdm_get_context_size()); + + m_spdm_context = (void *)malloc(libspdm_get_context_size()); + if (m_spdm_context == NULL) + { + return NULL; + } + spdm_context = m_spdm_context; + libspdm_init_context(spdm_context); + + /* io function callback */ + libspdm_register_device_io_func(spdm_context, spdm_device_send_message, + spdm_requester_device_receive_message); + + libspdm_register_transport_layer_func( + spdm_context, + LIBSPDM_MAX_SPDM_MSG_SIZE, + LIBSPDM_TRANSPORT_HEADER_SIZE, + LIBSPDM_TRANSPORT_TAIL_SIZE, + libspdm_transport_mctp_encode_message, + libspdm_transport_mctp_decode_message); + + libspdm_register_device_buffer_func(spdm_context, + LIBSPDM_SENDER_BUFFER_SIZE, + LIBSPDM_RECEIVER_BUFFER_SIZE, + spdm_device_acquire_sender_buffer, + spdm_device_release_sender_buffer, + spdm_device_acquire_receiver_buffer, + spdm_device_release_receiver_buffer); + + scratch_buffer_size = libspdm_get_sizeof_required_scratch_buffer(m_spdm_context); + m_scratch_buffer = (void *)malloc(scratch_buffer_size); + if (m_scratch_buffer == NULL) + { + free(m_spdm_context); + m_spdm_context = NULL; + return NULL; + } + libspdm_set_scratch_buffer(spdm_context, m_scratch_buffer, scratch_buffer_size); + + if (!libspdm_check_context(spdm_context)) + { + return NULL; + } + + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + spdm_version = m_use_version << SPDM_VERSION_NUMBER_SHIFT_BIT; + libspdm_set_data(spdm_context, LIBSPDM_DATA_SPDM_VERSION, ¶meter, + &spdm_version, sizeof(spdm_version)); + + if (m_use_secured_message_version != 0) + { + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + spdm_version = m_use_secured_message_version << SPDM_VERSION_NUMBER_SHIFT_BIT; + libspdm_set_data(spdm_context, + LIBSPDM_DATA_SECURED_MESSAGE_VERSION, + ¶meter, &spdm_version, + sizeof(spdm_version)); + } + + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + + data8 = 0; + libspdm_set_data(spdm_context, LIBSPDM_DATA_CAPABILITY_CT_EXPONENT, + ¶meter, &data8, sizeof(data8)); + data32 = m_use_requester_capability_flags; + if (m_use_slot_id == 0xFF) + { + data32 |= SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PUB_KEY_ID_CAP; + data32 &= ~SPDM_GET_CAPABILITIES_REQUEST_FLAGS_CERT_CAP; + } + if (m_use_capability_flags != 0) + { + data32 = m_use_capability_flags; + m_use_requester_capability_flags = m_use_capability_flags; + } + libspdm_set_data(spdm_context, LIBSPDM_DATA_CAPABILITY_FLAGS, ¶meter, + &data32, sizeof(data32)); + + data8 = m_support_measurement_spec; + libspdm_set_data(spdm_context, LIBSPDM_DATA_MEASUREMENT_SPEC, ¶meter, + &data8, sizeof(data8)); + data32 = m_support_asym_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_BASE_ASYM_ALGO, ¶meter, + &data32, sizeof(data32)); + data32 = m_support_hash_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_BASE_HASH_ALGO, ¶meter, + &data32, sizeof(data32)); + data16 = m_support_dhe_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_DHE_NAME_GROUP, ¶meter, + &data16, sizeof(data16)); + data16 = m_support_aead_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_AEAD_CIPHER_SUITE, ¶meter, + &data16, sizeof(data16)); + data16 = m_support_req_asym_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_REQ_BASE_ASYM_ALG, ¶meter, + &data16, sizeof(data16)); + data16 = m_support_key_schedule_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_KEY_SCHEDULE, ¶meter, &data16, + sizeof(data16)); + data8 = m_support_other_params_support; + libspdm_set_data(spdm_context, LIBSPDM_DATA_OTHER_PARAMS_SUPPORT, ¶meter, + &data8, sizeof(data8)); + data8 = m_support_mel_spec; + libspdm_set_data(spdm_context, LIBSPDM_DATA_MEL_SPEC, ¶meter, + &data8, sizeof(data8)); + + /* Skip if state is loaded*/ + status = libspdm_init_connection( + spdm_context, + (m_exe_connection & EXE_CONNECTION_VERSION_ONLY) != 0); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + printf("libspdm_init_connection - 0x%x\n", (uint32_t)status); + free(m_spdm_context); + m_spdm_context = NULL; + return NULL; + } + if ((m_exe_connection & EXE_CONNECTION_VERSION_ONLY) != 0) + { + /* GET_VERSION is done, handle special PSK use case*/ + status = spdm_provision_psk_version_only(spdm_context, true); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + free(m_spdm_context); + m_spdm_context = NULL; + return NULL; + } + } + + if (m_use_version == 0) + { + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_CONNECTION; + data_size = sizeof(spdm_version); + libspdm_get_data(spdm_context, LIBSPDM_DATA_SPDM_VERSION, ¶meter, + &spdm_version, &data_size); + m_use_version = spdm_version >> SPDM_VERSION_NUMBER_SHIFT_BIT; + } + + /*get requester_capabilities_flag*/ + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_CAPABILITY_FLAGS, ¶meter, + &data32, &data_size); + requester_capabilities_flag = data32; + + /*get responder_capabilities_flag*/ + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_CONNECTION; + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_CAPABILITY_FLAGS, ¶meter, + &data32, &data_size); + responder_capabilities_flag = data32; + + /*change m_exe_connection and m_exe_session base on responder/requester supported capabilities*/ + if ((SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP & responder_capabilities_flag) == 0) + { + m_exe_connection &= ~EXE_CONNECTION_DIGEST; + m_exe_connection &= ~EXE_CONNECTION_CERT; + m_exe_session &= ~EXE_SESSION_DIGEST; + m_exe_session &= ~EXE_SESSION_CERT; + } + if ((SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CHAL_CAP & responder_capabilities_flag) == 0) + { + m_exe_connection &= ~EXE_CONNECTION_CHAL; + } + if ((SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_MEAS_CAP & responder_capabilities_flag) == 0) + { + m_exe_connection &= ~EXE_CONNECTION_MEAS; + m_exe_session &= ~EXE_SESSION_MEAS; + } + + if (((SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_EX_CAP & requester_capabilities_flag) == 0) || + ((SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_EX_CAP & responder_capabilities_flag) == 0)) + { + m_exe_session &= ~EXE_SESSION_KEY_EX; + } + if (((SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PSK_CAP & requester_capabilities_flag) == 0) || + ((SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PSK_CAP & responder_capabilities_flag) == 0)) + { + m_exe_session &= ~EXE_SESSION_PSK; + } + if (((SPDM_GET_CAPABILITIES_REQUEST_FLAGS_KEY_UPD_CAP & requester_capabilities_flag) == 0) || + ((SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_KEY_UPD_CAP & responder_capabilities_flag) == 0)) + { + m_exe_session &= ~EXE_SESSION_KEY_UPDATE; + } + if (((SPDM_GET_CAPABILITIES_REQUEST_FLAGS_HBEAT_CAP & requester_capabilities_flag) == 0) || + ((SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_HBEAT_CAP & responder_capabilities_flag) == 0)) + { + m_exe_session &= ~EXE_SESSION_HEARTBEAT; + } + if ((SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_SET_CERT_CAP & responder_capabilities_flag) == 0) + { + m_exe_connection &= ~EXE_CONNECTION_SET_CERT; + m_exe_session &= ~EXE_SESSION_SET_CERT; + } + if ((SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP & responder_capabilities_flag) == 0) + { + m_exe_connection &= ~EXE_CONNECTION_GET_CSR; + m_exe_session &= ~EXE_SESSION_GET_CSR; + } + + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_CONNECTION_STATE, ¶meter, + &data32, &data_size); + LIBSPDM_ASSERT(data32 == LIBSPDM_CONNECTION_STATE_NEGOTIATED); + + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_MEASUREMENT_HASH_ALGO, ¶meter, + &data32, &data_size); + m_use_measurement_hash_algo = data32; + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_BASE_ASYM_ALGO, ¶meter, + &data32, &data_size); + m_use_asym_algo = data32; + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_BASE_HASH_ALGO, ¶meter, + &data32, &data_size); + m_use_hash_algo = data32; + data_size = sizeof(data16); + libspdm_get_data(spdm_context, LIBSPDM_DATA_REQ_BASE_ASYM_ALG, ¶meter, + &data16, &data_size); + m_use_req_asym_algo = data16; + + if ((m_use_requester_capability_flags & + SPDM_GET_CAPABILITIES_REQUEST_FLAGS_PUB_KEY_ID_CAP) != 0) + { + m_use_slot_id = 0xFF; + } + if (((m_exe_connection & EXE_CONNECTION_CERT) == 0) && (m_use_slot_id != 0xFF)) + { + m_exe_connection &= ~EXE_CONNECTION_CHAL; + m_exe_connection &= ~EXE_CONNECTION_MEAS; + m_exe_session &= ~EXE_SESSION_KEY_EX; + m_exe_session &= ~EXE_SESSION_MEAS; + } + // if (m_use_slot_id == 0xFF) + // { + // printf("\nAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + // res = libspdm_read_responder_public_key(m_use_asym_algo, &data, &data_size); + // if (res) + // { + // libspdm_zero_mem(¶meter, sizeof(parameter)); + // parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + // libspdm_set_data(spdm_context, + // LIBSPDM_DATA_PEER_PUBLIC_KEY, + // ¶meter, data, data_size); + // /* Do not free it.*/ + // printf("\n1111AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + // } + // else + // { + // printf("\n222AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + // printf("\nread_responder_public_key fail!\n"); + // free(m_spdm_context); + // m_spdm_context = NULL; + // return NULL; + // } + // res = libspdm_read_requester_public_key(m_use_req_asym_algo, &data, &data_size); + // if (res) + // { + // printf("\n33333AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + // libspdm_zero_mem(¶meter, sizeof(parameter)); + // parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + // libspdm_set_data(spdm_context, + // LIBSPDM_DATA_LOCAL_PUBLIC_KEY, + // ¶meter, data, data_size); + // printf("\n444444444AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + // /* Do not free it.*/ + // } + // else + // { + // printf("\n555555555AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + // printf("\nread_requester_public_key fail!\n"); + // free(m_spdm_context); + // m_spdm_context = NULL; + // return NULL; + // } + // } + // else + // { + // printf("\n66666666AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + // res = libspdm_read_responder_root_public_certificate(m_use_hash_algo, + // m_use_asym_algo, + // &data, &data_size, + // &hash, &hash_size); + // if (res) + // { + // printf("\n7777777AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + // libspdm_x509_get_cert_from_cert_chain( + // (uint8_t *)data + sizeof(spdm_cert_chain_t) + hash_size, + // data_size - sizeof(spdm_cert_chain_t) - hash_size, 0, + // &root_cert, &root_cert_size); + // libspdm_zero_mem(¶meter, sizeof(parameter)); + // parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + // libspdm_set_data(spdm_context, + // LIBSPDM_DATA_PEER_PUBLIC_ROOT_CERT, + // ¶meter, (void *)root_cert, root_cert_size); + // /* Do not free it.*/ + // printf("\n888888888888AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + // } + // else + // { + // printf("\n9999999AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA"); + // printf("\nread_responder_root_public_certificate fail!\n"); + // free(m_spdm_context); + // m_spdm_context = NULL; + // return NULL; + // } + // res = libspdm_read_responder_root_public_certificate_slot(1, + // m_use_hash_algo, + // m_use_asym_algo, + // &data1, &data1_size, + // &hash1, &hash1_size); + // if (res) + // { + // printf("\n1111111BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"); + // libspdm_x509_get_cert_from_cert_chain( + // (uint8_t *)data1 + sizeof(spdm_cert_chain_t) + hash1_size, + // data1_size - sizeof(spdm_cert_chain_t) - hash1_size, 0, + // &root_cert1, &root_cert1_size); + // libspdm_zero_mem(¶meter, sizeof(parameter)); + // parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + // libspdm_set_data(spdm_context, + // LIBSPDM_DATA_PEER_PUBLIC_ROOT_CERT, + // ¶meter, (void *)root_cert1, root_cert1_size); + // /* Do not free it.*/ + // printf("\n222222222BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"); + // } + // else + // { + // printf("\n33333333333BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"); + // printf("\nread_responder_root_public_certificate fail!\n"); + // free(m_spdm_context); + // m_spdm_context = NULL; + // return NULL; + // } + // } + + // if (m_use_req_asym_algo != 0) + // { + // printf("\n44444444444444444BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"); + // res = libspdm_read_requester_public_certificate_chain(m_use_hash_algo, + // m_use_req_asym_algo, + // &data, &data_size, NULL, + // NULL); + // if (res) + // { + // libspdm_zero_mem(¶meter, sizeof(parameter)); + // parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + + // for (index = 0; index < m_use_slot_count; index++) + // { + // parameter.additional_data[0] = index; + // libspdm_set_data(spdm_context, + // LIBSPDM_DATA_LOCAL_PUBLIC_CERT_CHAIN, + // ¶meter, data, data_size); + // data8 = (uint8_t)(0xB0 + index); + // libspdm_set_data(spdm_context, + // LIBSPDM_DATA_LOCAL_KEY_PAIR_ID, + // ¶meter, &data8, sizeof(data8)); + // data8 = SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT; + // libspdm_set_data(spdm_context, + // LIBSPDM_DATA_LOCAL_CERT_INFO, + // ¶meter, &data8, sizeof(data8)); + // data16 = SPDM_KEY_USAGE_BIT_MASK_KEY_EX_USE | + // SPDM_KEY_USAGE_BIT_MASK_CHALLENGE_USE | + // SPDM_KEY_USAGE_BIT_MASK_MEASUREMENT_USE | + // SPDM_KEY_USAGE_BIT_MASK_ENDPOINT_INFO_USE; + // libspdm_set_data(spdm_context, + // LIBSPDM_DATA_LOCAL_KEY_USAGE_BIT_MASK, + // ¶meter, &data16, sizeof(data16)); + // } + // /* do not free it*/ + // } + // else + // { + // printf("\n5555555555555BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB"); + // printf("\nread_requester_public_certificate_chain fail!\n"); + // free(m_spdm_context); + // m_spdm_context = NULL; + // return NULL; + // } + // } + + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + data8 = 0x3F; + libspdm_set_data(spdm_context, LIBSPDM_DATA_LOCAL_SUPPORTED_SLOT_MASK, ¶meter, + &data8, sizeof(data8)); + + if (m_save_state_file_name != NULL) + { + spdm_save_negotiated_state(spdm_context, true); + } + printf("\n666666666666BBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBBB\n"); + + return m_spdm_context; +} diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/CMakeLists.txt b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/CMakeLists.txt new file mode 100644 index 00000000..adb2005e --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/CMakeLists.txt @@ -0,0 +1,60 @@ +cmake_minimum_required(VERSION 2.6) + +INCLUDE_DIRECTORIES(${PROJECT_SOURCE_DIR}/spdm_caliptra/spdm_caliptra_responder + ${PROJECT_SOURCE_DIR}/spdm_caliptra/spdm_caliptra_common + ${PROJECT_SOURCE_DIR}/include + ${LIBSPDM_DIR}/os_stub/spdm_device_secret_lib_sample + ${LIBSPDM_DIR}/include + ${LIBSPDM_DIR}/os_stub/include + ${LIBSPDM_DIR}/os_stub +) + +SET(src_spdm_caliptra_responder + spdm_caliptra_cert.c + spdm_responder_spdm.c + spdm_responder_session.c + # spdm_responder_pci_doe.c + spdm_responder_mctp.c + # spdm_responder_tcp.c + spdm_caliptra_responder.c + ${PROJECT_SOURCE_DIR}/spdm_caliptra/spdm_caliptra_common/spdm_caliptra.c + ${PROJECT_SOURCE_DIR}/spdm_caliptra/spdm_caliptra_common/command.c + ${PROJECT_SOURCE_DIR}/spdm_caliptra/spdm_caliptra_common/key.c + ${PROJECT_SOURCE_DIR}/spdm_caliptra/spdm_caliptra_common/nv_storage.c + ${PROJECT_SOURCE_DIR}/spdm_caliptra/spdm_caliptra_common/pcap.c + ${PROJECT_SOURCE_DIR}/spdm_caliptra/spdm_caliptra_common/support.c +) + +SET(spdm_caliptra_responder_LIBRARY + memlib + debuglib + spdm_responder_lib + spdm_common_lib + ${CRYPTO_LIB_PATHS} + rnglib + cryptlib_${CRYPTO} + malloclib + spdm_crypt_lib + spdm_crypt_ext_lib + spdm_secured_message_lib + spdm_transport_mctp_lib + # spdm_transport_pcidoe_lib + # spdm_transport_tcp_lib + # spdm_transport_none_lib + spdm_device_secret_lib_sample + mctp_responder_lib + # pci_doe_responder_lib + # pci_ide_km_responder_lib + # pci_ide_km_device_lib_sample + # pci_tdisp_responder_lib + # pci_tdisp_device_lib_sample + # cxl_ide_km_responder_lib + # cxl_ide_km_device_lib_sample + platform_lib +) + +ADD_EXECUTABLE(spdm_caliptra_responder ${src_spdm_caliptra_responder}) +#ADD_LIBRARY(spdm_caliptra_responder STATIC ${src_spdm_caliptra_responder}) +TARGET_LINK_LIBRARIES(spdm_caliptra_responder ${spdm_caliptra_responder_LIBRARY}) + + diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_caliptra_cert.c b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_caliptra_cert.c new file mode 100644 index 00000000..6a9bb283 --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_caliptra_cert.c @@ -0,0 +1,1260 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/libspdm/blob/main/LICENSE.md + **/ + +#include "spdm_caliptra_responder.h" +#include +#include +#include +#include +#include +#include +#include +#include + +#include "hal/base.h" +#include "hal/library/memlib.h" +#include "spdm_device_secret_lib_internal.h" + +bool caliptra_read_requester_root_public_certificate(uint32_t base_hash_algo, + uint16_t req_base_asym_alg, + void **data, size_t *size, + void **hash, + size_t *hash_size) +{ + printf("\nspdm_caliptra.c CHECKPOINT 111 INSIDE caliptra_read_requester_root_public_certificate()"); + bool res; + void *file_data; + size_t file_size; + spdm_cert_chain_t *cert_chain; + size_t cert_chain_size; + char *file; + size_t digest_size; + + *data = NULL; + *size = 0; + if (hash != NULL) { + *hash = NULL; + } + if (hash_size != NULL) { + *hash_size = 0; + } + + if (req_base_asym_alg == 0) { + return false; + } + + switch (req_base_asym_alg) { + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048: + file = "rsa2048/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072: + file = "rsa3072/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096: + file = "rsa4096/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256: + file = "ecp256/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384: + file = "ecp384/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521: + file = "ecp521/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_SM2_ECC_SM2_P256: + file = "sm2/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED25519: + file = "ed25519/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED448: + file = "ed448/ca.cert.der"; + break; + default: + LIBSPDM_ASSERT(false); + return false; + } + + digest_size = libspdm_get_hash_size(base_hash_algo); + + res = libspdm_read_input_file(file, &file_data, &file_size); + if (!res) { + return res; + } + + cert_chain_size = sizeof(spdm_cert_chain_t) + digest_size + file_size; + cert_chain = (void *)malloc(cert_chain_size); + if (cert_chain == NULL) { + free(file_data); + return false; + } + cert_chain->length = (uint16_t)cert_chain_size; + cert_chain->reserved = 0; + res = libspdm_hash_all(base_hash_algo, file_data, file_size, + (uint8_t *)(cert_chain + 1)); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + libspdm_copy_mem((uint8_t *)cert_chain + sizeof(spdm_cert_chain_t) + digest_size, + cert_chain_size - (sizeof(spdm_cert_chain_t) + digest_size), + file_data, file_size); + + *data = cert_chain; + *size = cert_chain_size; + if (hash != NULL) { + *hash = (cert_chain + 1); + } + if (hash_size != NULL) { + *hash_size = digest_size; + } + + free(file_data); + return true; +} + +bool caliptra_read_responder_public_certificate_chain( + uint32_t base_hash_algo, uint32_t base_asym_algo, void **data, + size_t *size, void **hash, size_t *hash_size) +{ + printf("\nspdm_caliptra.c CHECKPOINT 1 INSIDE caliptra_read_responder_public_certificate_chain()"); + bool res; + void *file_data; + size_t file_size; + spdm_cert_chain_t *cert_chain; + size_t cert_chain_size; + char *file; + const uint8_t *root_cert; + size_t root_cert_len; + size_t digest_size; + bool is_requester_cert; + bool is_device_cert_model; + + is_requester_cert = false; + + /*default is true*/ + is_device_cert_model = true; + + *data = NULL; + *size = 0; + if (hash != NULL) { + *hash = NULL; + } + if (hash_size != NULL) { + *hash_size = 0; + } + + if (base_asym_algo == 0) { + return false; + } + + printf("\nspdm_caliptra.c CHECKPOINT 2 %d",base_asym_algo); + switch (base_asym_algo) { + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048: + file = "rsa2048/bundle_responder.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072: + file = "rsa3072/bundle_responder.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096: + file = "rsa4096/bundle_responder.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256: + file = "ecp256/bundle_responder.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384: + file = "ecp384/bundle_responder.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521: + file = "ecp521/bundle_responder.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_SM2_ECC_SM2_P256: + file = "sm2/bundle_responder.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED25519: + file = "ed25519/bundle_responder.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED448: + file = "ed448/bundle_responder.certchain.der"; + break; + default: + LIBSPDM_ASSERT(false); + return false; + } + res = libspdm_read_input_file(file, &file_data, &file_size); + if (!res) { + return res; + } + + digest_size = libspdm_get_hash_size(base_hash_algo); + + cert_chain_size = sizeof(spdm_cert_chain_t) + digest_size + file_size; + cert_chain = (void *)malloc(cert_chain_size); + if (cert_chain == NULL) { + free(file_data); + return false; + } + cert_chain->length = (uint16_t)cert_chain_size; + cert_chain->reserved = 0; + + res = libspdm_verify_cert_chain_data(file_data, file_size, + base_asym_algo, base_hash_algo, + is_requester_cert, is_device_cert_model); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + + + /* Get Root Certificate and calculate hash value*/ + + res = libspdm_x509_get_cert_from_cert_chain(file_data, file_size, 0, &root_cert, + &root_cert_len); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + + res = libspdm_hash_all(base_hash_algo, root_cert, root_cert_len, + (uint8_t *)(cert_chain + 1)); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + libspdm_copy_mem((uint8_t *)cert_chain + sizeof(spdm_cert_chain_t) + digest_size, + cert_chain_size - (sizeof(spdm_cert_chain_t) + digest_size), + file_data, file_size); + + *data = cert_chain; + *size = cert_chain_size; + if (hash != NULL) { + *hash = (cert_chain + 1); + } + if (hash_size != NULL) { + *hash_size = digest_size; + } + + free(file_data); + return true; +} + +bool caliptra_read_responder_public_certificate_chain_per_slot( + uint8_t slot_id, uint32_t base_hash_algo, uint32_t base_asym_algo, + void **data, size_t *size, void **hash, size_t *hash_size) +{ + printf("\nspdm_caliptra.c CHECKPOINT 3 INSIDE caliptra_read_responder_public_certificate_chain_per_slot()"); + bool res; + void *file_data; + size_t file_size; + spdm_cert_chain_t *cert_chain; + size_t cert_chain_size; + char *file; + const uint8_t *root_cert; + size_t root_cert_len; + size_t digest_size; + bool is_requester_cert; + bool is_device_cert_model; + + is_requester_cert = false; + + /*default is true*/ + is_device_cert_model = true; + + *data = NULL; + *size = 0; + if (hash != NULL) { + *hash = NULL; + } + if (hash_size != NULL) { + *hash_size = 0; + } + + if (base_asym_algo == 0) { + return false; + } + + if (slot_id == 0) { + printf("\nspdm_caliptra.c CHECKPOINT 4 : SLOT ID = 0"); + switch (base_asym_algo) { + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048: + file = "rsa2048/bundle_responder.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072: + file = "rsa3072/bundle_responder.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096: + file = "rsa4096/bundle_responder.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256: + file = "ecp256/bundle_responder.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384: + file = "ecp384/bundle_responder.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521: + file = "ecp521/bundle_responder.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_SM2_ECC_SM2_P256: + file = "sm2/bundle_responder.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED25519: + file = "ed25519/bundle_responder.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED448: + file = "ed448/bundle_responder.certchain.der"; + break; + default: + LIBSPDM_ASSERT(false); + return false; + } + } else { + printf("\nspdm_caliptra.c CHECKPOINT 5 SLOT ID != 0 %d",slot_id); + switch (base_asym_algo) { + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048: + file = "rsa2048/bundle_responder.certchain1.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072: + file = "rsa3072/bundle_responder.certchain1.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096: + file = "rsa4096/bundle_responder.certchain1.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256: + file = "ecp256/bundle_responder.certchain1.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384: + file = "ecp384/bundle_responder.certchain1.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521: + file = "ecp521/bundle_responder.certchain1.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_SM2_ECC_SM2_P256: + file = "sm2/bundle_responder.certchain1.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED25519: + file = "ed25519/bundle_responder.certchain1.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED448: + file = "ed448/bundle_responder.certchain1.der"; + break; + default: + LIBSPDM_ASSERT(false); + return false; + } + } + res = libspdm_read_input_file(file, &file_data, &file_size); + if (!res) { + return res; + } + + digest_size = libspdm_get_hash_size(base_hash_algo); + + cert_chain_size = sizeof(spdm_cert_chain_t) + digest_size + file_size; + cert_chain = (void *)malloc(cert_chain_size); + if (cert_chain == NULL) { + free(file_data); + return false; + } + cert_chain->length = (uint16_t)cert_chain_size; + cert_chain->reserved = 0; + + res = libspdm_verify_cert_chain_data(file_data, file_size, + base_asym_algo, base_hash_algo, + is_requester_cert, is_device_cert_model); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + + + /* Get Root Certificate and calculate hash value*/ + + res = libspdm_x509_get_cert_from_cert_chain(file_data, file_size, 0, &root_cert, + &root_cert_len); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + + res = libspdm_hash_all(base_hash_algo, root_cert, root_cert_len, + (uint8_t *)(cert_chain + 1)); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + libspdm_copy_mem((uint8_t *)cert_chain + sizeof(spdm_cert_chain_t) + digest_size, + cert_chain_size - (sizeof(spdm_cert_chain_t) + digest_size), + file_data, file_size); + + *data = cert_chain; + *size = cert_chain_size; + if (hash != NULL) { + *hash = (cert_chain + 1); + } + if (hash_size != NULL) { + *hash_size = digest_size; + } + + free(file_data); + return true; +} + +/* +bool libspdm_read_requester_public_certificate_chain( + uint32_t base_hash_algo, uint16_t req_base_asym_alg, void **data, + size_t *size, void **hash, size_t *hash_size) +{ + bool res; + void *file_data; + size_t file_size; + spdm_cert_chain_t *cert_chain; + size_t cert_chain_size; + char *file; + const uint8_t *root_cert; + size_t root_cert_len; + size_t digest_size; + bool is_requester_cert; + bool is_device_cert_model; + + is_requester_cert = false; + + is_device_cert_model = true; + + *data = NULL; + *size = 0; + if (hash != NULL) { + *hash = NULL; + } + if (hash_size != NULL) { + *hash_size = 0; + } + + if (req_base_asym_alg == 0) { + return false; + } + + switch (req_base_asym_alg) { + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048: + file = "rsa2048/bundle_requester.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072: + file = "rsa3072/bundle_requester.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096: + file = "rsa4096/bundle_requester.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256: + file = "ecp256/bundle_requester.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384: + file = "ecp384/bundle_requester.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521: + file = "ecp521/bundle_requester.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_SM2_ECC_SM2_P256: + file = "sm2/bundle_requester.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED25519: + file = "ed25519/bundle_requester.certchain.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED448: + file = "ed448/bundle_requester.certchain.der"; + break; + default: + LIBSPDM_ASSERT(false); + return false; + } + res = libspdm_read_input_file(file, &file_data, &file_size); + if (!res) { + return res; + } + + digest_size = libspdm_get_hash_size(base_hash_algo); + + cert_chain_size = sizeof(spdm_cert_chain_t) + digest_size + file_size; + cert_chain = (void *)malloc(cert_chain_size); + if (cert_chain == NULL) { + free(file_data); + return false; + } + cert_chain->length = (uint16_t)cert_chain_size; + cert_chain->reserved = 0; + + res = libspdm_verify_cert_chain_data(file_data, file_size, + req_base_asym_alg, base_hash_algo, + is_requester_cert, is_device_cert_model); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + + + res = libspdm_x509_get_cert_from_cert_chain(file_data, file_size, 0, &root_cert, + &root_cert_len); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + + res = libspdm_hash_all(base_hash_algo, root_cert, root_cert_len, + (uint8_t *)(cert_chain + 1)); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + libspdm_copy_mem((uint8_t *)cert_chain + sizeof(spdm_cert_chain_t) + digest_size, + cert_chain_size - (sizeof(spdm_cert_chain_t) + digest_size), + file_data, file_size); + + *data = cert_chain; + *size = cert_chain_size; + if (hash != NULL) { + *hash = (cert_chain + 1); + } + if (hash_size != NULL) { + *hash_size = digest_size; + } + + free(file_data); + return true; +} + + +bool libspdm_read_responder_root_public_certificate_by_size( + uint32_t base_hash_algo, uint32_t base_asym_algo, uint16_t chain_id, + void **data, size_t *size, void **hash, size_t *hash_size) +{ + bool res; + void *file_data; + size_t file_size; + spdm_cert_chain_t *cert_chain; + size_t cert_chain_size; + char *file; + size_t digest_size; + + *data = NULL; + *size = 0; + if (hash != NULL) { + *hash = NULL; + } + if (hash_size != NULL) { + *hash_size = 0; + } + + switch (chain_id) { + case LIBSPDM_TEST_CERT_SMALL: + file = "long_chains/Shorter1024B_ca.cert.der"; + break; + case LIBSPDM_TEST_CERT_MAXINT16: + file = "long_chains/ShorterMAXINT16_ca.cert.der"; + break; + case LIBSPDM_TEST_CERT_MAXUINT16: + file = "long_chains/ShorterMAXUINT16_ca.cert.der"; + break; + case LIBSPDM_LIBSPDM_TEST_CERT_MAXUINT16_LARGER: + file = "long_chains/LongerMAXUINT16_ca.cert.der"; + break; + default: + LIBSPDM_ASSERT(false); + return false; + } + res = libspdm_read_input_file(file, &file_data, &file_size); + if (!res) { + return res; + } + + digest_size = libspdm_get_hash_size(base_hash_algo); + + cert_chain_size = sizeof(spdm_cert_chain_t) + digest_size + file_size; + cert_chain = (void *)malloc(cert_chain_size); + if (cert_chain == NULL) { + free(file_data); + return false; + } + cert_chain->length = (uint16_t)cert_chain_size; + cert_chain->reserved = 0; + + res = libspdm_hash_all(base_hash_algo, file_data, file_size, + (uint8_t *)(cert_chain + 1)); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + libspdm_copy_mem((uint8_t *)cert_chain + sizeof(spdm_cert_chain_t) + digest_size, + cert_chain_size - (sizeof(spdm_cert_chain_t) + digest_size), + file_data, file_size); + + *data = cert_chain; + *size = cert_chain_size; + if (hash != NULL) { + *hash = (cert_chain + 1); + } + if (hash_size != NULL) { + *hash_size = digest_size; + } + + free(file_data); + return true; +} + +bool libspdm_read_responder_public_certificate_chain_by_size( + uint32_t base_hash_algo, uint32_t base_asym_algo, uint16_t chain_id, + void **data, size_t *size, void **hash, size_t *hash_size) +{ + bool res; + void *file_data; + size_t file_size; + spdm_cert_chain_t *cert_chain; + size_t cert_chain_size; + char *file; + const uint8_t *root_cert; + size_t root_cert_len; + size_t digest_size; + bool is_requester_cert; + bool is_device_cert_model; + + is_requester_cert = false; + + is_device_cert_model = true; + + *data = NULL; + *size = 0; + if (hash != NULL) { + *hash = NULL; + } + if (hash_size != NULL) { + *hash_size = 0; + } + + switch (chain_id) { + case LIBSPDM_TEST_CERT_SMALL: + file = "long_chains/Shorter1024B_bundle_responder.certchain.der"; + break; + case LIBSPDM_TEST_CERT_MAXINT16: + file = "long_chains/ShorterMAXINT16_bundle_responder.certchain.der"; + break; + case LIBSPDM_TEST_CERT_MAXUINT16: + file = "long_chains/ShorterMAXUINT16_bundle_responder.certchain.der"; + break; + case LIBSPDM_LIBSPDM_TEST_CERT_MAXUINT16_LARGER: + file = "long_chains/LongerMAXUINT16_bundle_responder.certchain.der"; + break; + default: + LIBSPDM_ASSERT(false); + return false; + } + res = libspdm_read_input_file(file, &file_data, &file_size); + if (!res) { + return res; + } + + digest_size = libspdm_get_hash_size(base_hash_algo); + + cert_chain_size = sizeof(spdm_cert_chain_t) + digest_size + file_size; + cert_chain = (void *)malloc(cert_chain_size); + if (cert_chain == NULL) { + free(file_data); + return false; + } + cert_chain->length = (uint16_t)cert_chain_size; + cert_chain->reserved = 0; + + res = libspdm_verify_cert_chain_data(file_data, file_size, + base_asym_algo, base_hash_algo, + is_requester_cert, is_device_cert_model); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + + res = libspdm_x509_get_cert_from_cert_chain(file_data, file_size, 0, &root_cert, + &root_cert_len); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + + res = libspdm_hash_all(base_hash_algo, root_cert, root_cert_len, + (uint8_t *)(cert_chain + 1)); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + libspdm_copy_mem((uint8_t *)cert_chain + sizeof(spdm_cert_chain_t) + digest_size, + cert_chain_size - (sizeof(spdm_cert_chain_t) + digest_size), + file_data, file_size); + + *data = cert_chain; + *size = cert_chain_size; + if (hash != NULL) { + *hash = (cert_chain + 1); + } + if (hash_size != NULL) { + *hash_size = digest_size; + } + + free(file_data); + return true; +} + +bool libspdm_read_responder_root_public_certificate(uint32_t base_hash_algo, + uint32_t base_asym_algo, + void **data, size_t *size, + void **hash, + size_t *hash_size) +{ + bool res; + void *file_data; + size_t file_size; + spdm_cert_chain_t *cert_chain; + size_t cert_chain_size; + char *file; + size_t digest_size; + + *data = NULL; + *size = 0; + if (hash != NULL) { + *hash = NULL; + } + if (hash_size != NULL) { + *hash_size = 0; + } + + if (base_asym_algo == 0) { + return false; + } + + switch (base_asym_algo) { + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048: + file = "rsa2048/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072: + file = "rsa3072/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096: + file = "rsa4096/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256: + file = "ecp256/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384: + file = "ecp384/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521: + file = "ecp521/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_SM2_ECC_SM2_P256: + file = "sm2/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED25519: + file = "ed25519/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED448: + file = "ed448/ca.cert.der"; + break; + default: + LIBSPDM_ASSERT(false); + return false; + } + res = libspdm_read_input_file(file, &file_data, &file_size); + if (!res) { + return res; + } + + digest_size = libspdm_get_hash_size(base_hash_algo); + + cert_chain_size = sizeof(spdm_cert_chain_t) + digest_size + file_size; + cert_chain = (void *)malloc(cert_chain_size); + if (cert_chain == NULL) { + free(file_data); + return false; + } + cert_chain->length = (uint16_t)cert_chain_size; + cert_chain->reserved = 0; + + res = libspdm_hash_all(base_hash_algo, file_data, file_size, + (uint8_t *)(cert_chain + 1)); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + libspdm_copy_mem((uint8_t *)cert_chain + sizeof(spdm_cert_chain_t) + digest_size, + cert_chain_size - (sizeof(spdm_cert_chain_t) + digest_size), + file_data, file_size); + + *data = cert_chain; + *size = cert_chain_size; + if (hash != NULL) { + *hash = (cert_chain + 1); + } + if (hash_size != NULL) { + *hash_size = digest_size; + } + + free(file_data); + return true; +} + +bool libspdm_read_responder_root_public_certificate_slot(uint8_t slot_id, + uint32_t base_hash_algo, + uint32_t base_asym_algo, + void **data, size_t *size, + void **hash, + size_t *hash_size) +{ + bool res; + void *file_data; + size_t file_size; + spdm_cert_chain_t *cert_chain; + size_t cert_chain_size; + char *file; + size_t digest_size; + + *data = NULL; + *size = 0; + if (hash != NULL) { + *hash = NULL; + } + if (hash_size != NULL) { + *hash_size = 0; + } + + if (base_asym_algo == 0) { + return false; + } + + if (slot_id == 0) { + switch (base_asym_algo) { + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048: + file = "rsa2048/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072: + file = "rsa3072/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096: + file = "rsa4096/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256: + file = "ecp256/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384: + file = "ecp384/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521: + file = "ecp521/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_SM2_ECC_SM2_P256: + file = "sm2/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED25519: + file = "ed25519/ca.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED448: + file = "ed448/ca.cert.der"; + break; + default: + LIBSPDM_ASSERT(false); + return false; + } + } else { + switch (base_asym_algo) { + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048: + file = "rsa2048/ca1.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072: + file = "rsa3072/ca1.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096: + file = "rsa4096/ca1.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256: + file = "ecp256/ca1.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384: + file = "ecp384/ca1.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521: + file = "ecp521/ca1.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_SM2_ECC_SM2_P256: + file = "sm2/ca1.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED25519: + file = "ed25519/ca1.cert.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED448: + file = "ed448/ca1.cert.der"; + break; + default: + LIBSPDM_ASSERT(false); + return false; + } + } + res = libspdm_read_input_file(file, &file_data, &file_size); + if (!res) { + return res; + } + + digest_size = libspdm_get_hash_size(base_hash_algo); + + cert_chain_size = sizeof(spdm_cert_chain_t) + digest_size + file_size; + cert_chain = (void *)malloc(cert_chain_size); + if (cert_chain == NULL) { + free(file_data); + return false; + } + cert_chain->length = (uint16_t)cert_chain_size; + cert_chain->reserved = 0; + + res = libspdm_hash_all(base_hash_algo, file_data, file_size, + (uint8_t *)(cert_chain + 1)); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + libspdm_copy_mem((uint8_t *)cert_chain + sizeof(spdm_cert_chain_t) + digest_size, + cert_chain_size - (sizeof(spdm_cert_chain_t) + digest_size), + file_data, file_size); + + *data = cert_chain; + *size = cert_chain_size; + if (hash != NULL) { + *hash = (cert_chain + 1); + } + if (hash_size != NULL) { + *hash_size = digest_size; + } + + free(file_data); + return true; +} + +bool libspdm_read_responder_public_certificate_chain_alias_cert_till_dev_cert_ca( + uint32_t base_hash_algo, uint32_t base_asym_algo, void **data, + size_t *size, void **hash, size_t *hash_size) +{ + bool res; + void *file_data; + size_t file_size; + spdm_cert_chain_t *cert_chain; + size_t cert_chain_size; + char *file; + const uint8_t *root_cert; + size_t root_cert_len; + const uint8_t *leaf_cert; + size_t leaf_cert_len; + size_t digest_size; + bool is_requester_cert; + bool is_device_cert_model; + + is_requester_cert = false; + + is_device_cert_model = false; + + *data = NULL; + *size = 0; + if (hash != NULL) { + *hash = NULL; + } + if (hash_size != NULL) { + *hash_size = 0; + } + + if (base_asym_algo == 0) { + return false; + } + + switch (base_asym_algo) { + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048: + file = "rsa2048/bundle_responder.certchain_alias_cert_partial_set.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072: + file = "rsa3072/bundle_responder.certchain_alias_cert_partial_set.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096: + file = "rsa4096/bundle_responder.certchain_alias_cert_partial_set.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256: + file = "ecp256/bundle_responder.certchain_alias_cert_partial_set.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384: + file = "ecp384/bundle_responder.certchain_alias_cert_partial_set.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521: + file = "ecp521/bundle_responder.certchain_alias_cert_partial_set.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_SM2_ECC_SM2_P256: + file = "sm2/bundle_responder.certchain_alias_cert_partial_set.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED25519: + file = "ed25519/bundle_responder.certchain_alias_cert_partial_set.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED448: + file = "ed448/bundle_responder.certchain_alias_cert_partial_set.der"; + break; + default: + LIBSPDM_ASSERT(false); + return false; + } + res = libspdm_read_input_file(file, &file_data, &file_size); + if (!res) { + return res; + } + + digest_size = libspdm_get_hash_size(base_hash_algo); + + cert_chain_size = sizeof(spdm_cert_chain_t) + digest_size + file_size; + cert_chain = (void *)malloc(cert_chain_size); + if (cert_chain == NULL) { + free(file_data); + return false; + } + cert_chain->length = (uint16_t)cert_chain_size; + cert_chain->reserved = 0; + + res = libspdm_x509_get_cert_from_cert_chain(file_data, file_size, -1, &leaf_cert, + &leaf_cert_len); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + res = libspdm_x509_set_cert_certificate_check(leaf_cert, leaf_cert_len, + base_asym_algo, base_hash_algo, + is_requester_cert, is_device_cert_model); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + + res = libspdm_x509_get_cert_from_cert_chain(file_data, file_size, 0, &root_cert, + &root_cert_len); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + + res = libspdm_x509_verify_cert_chain(root_cert, root_cert_len, file_data, file_size); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + + res = libspdm_hash_all(base_hash_algo, root_cert, root_cert_len, + (uint8_t *)(cert_chain + 1)); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + libspdm_copy_mem((uint8_t *)cert_chain + sizeof(spdm_cert_chain_t) + digest_size, + cert_chain_size - (sizeof(spdm_cert_chain_t) + digest_size), + file_data, file_size); + + *data = cert_chain; + *size = cert_chain_size; + if (hash != NULL) { + *hash = (cert_chain + 1); + } + if (hash_size != NULL) { + *hash_size = digest_size; + } + + free(file_data); + return true; +} + +bool libspdm_read_responder_public_certificate_chain_alias_cert_entire( + uint32_t base_hash_algo, uint32_t base_asym_algo, void **data, + size_t *size, void **hash, size_t *hash_size) +{ + bool res; + void *file_data; + size_t file_size; + spdm_cert_chain_t *cert_chain; + size_t cert_chain_size; + char *file; + const uint8_t *root_cert; + size_t root_cert_len; + const uint8_t *leaf_cert; + size_t leaf_cert_len; + size_t digest_size; + bool is_requester_cert; + bool is_device_cert_model; + + is_requester_cert = false; + + is_device_cert_model = false; + + *data = NULL; + *size = 0; + if (hash != NULL) { + *hash = NULL; + } + if (hash_size != NULL) { + *hash_size = 0; + } + + if (base_asym_algo == 0) { + return false; + } + + switch (base_asym_algo) { + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_2048: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_2048: + file = "rsa2048/bundle_responder.certchain_alias_entire.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_3072: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_3072: + file = "rsa3072/bundle_responder.certchain_alias_entire.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSASSA_4096: + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_RSAPSS_4096: + file = "rsa4096/bundle_responder.certchain_alias_entire.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P256: + file = "ecp256/bundle_responder.certchain_alias_entire.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P384: + file = "ecp384/bundle_responder.certchain_alias_entire.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_ECDSA_ECC_NIST_P521: + file = "ecp521/bundle_responder.certchain_alias_entire.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_TPM_ALG_SM2_ECC_SM2_P256: + file = "sm2/bundle_responder.certchain_alias_entire.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED25519: + file = "ed25519/bundle_responder.certchain_alias_entire.der"; + break; + case SPDM_ALGORITHMS_BASE_ASYM_ALGO_EDDSA_ED448: + file = "ed448/bundle_responder.certchain_alias_entire.der"; + break; + default: + LIBSPDM_ASSERT(false); + return false; + } + res = libspdm_read_input_file(file, &file_data, &file_size); + if (!res) { + return res; + } + + digest_size = libspdm_get_hash_size(base_hash_algo); + + cert_chain_size = sizeof(spdm_cert_chain_t) + digest_size + file_size; + cert_chain = (void *)malloc(cert_chain_size); + if (cert_chain == NULL) { + free(file_data); + return false; + } + cert_chain->length = (uint16_t)cert_chain_size; + cert_chain->reserved = 0; + + res = libspdm_x509_get_cert_from_cert_chain(file_data, file_size, -1, &leaf_cert, + &leaf_cert_len); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + res = libspdm_x509_certificate_check(leaf_cert, leaf_cert_len, + base_asym_algo, base_hash_algo, + is_requester_cert, is_device_cert_model); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + + res = libspdm_x509_get_cert_from_cert_chain(file_data, file_size, 0, &root_cert, + &root_cert_len); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + + res = libspdm_x509_verify_cert_chain(root_cert, root_cert_len, file_data, file_size); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + + res = libspdm_hash_all(base_hash_algo, root_cert, root_cert_len, + (uint8_t *)(cert_chain + 1)); + if (!res) { + free(file_data); + free(cert_chain); + return res; + } + libspdm_copy_mem((uint8_t *)cert_chain + sizeof(spdm_cert_chain_t) + digest_size, + cert_chain_size - (sizeof(spdm_cert_chain_t) + digest_size), + file_data, file_size); + + *data = cert_chain; + *size = cert_chain_size; + if (hash != NULL) { + *hash = (cert_chain + 1); + } + if (hash_size != NULL) { + *hash_size = digest_size; + } + + free(file_data); + return true; +} + + +*/ \ No newline at end of file diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_caliptra_responder.c b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_caliptra_responder.c new file mode 100644 index 00000000..b55dc011 --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_caliptra_responder.c @@ -0,0 +1,174 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#include "spdm_caliptra_responder.h" + +uint32_t m_command; + +SOCKET m_server_socket; + +extern void *m_spdm_context; +extern void *m_scratch_buffer; + +void *spdm_server_init(void); + +bool platform_server(const SOCKET socket) +{ + bool result; + libspdm_return_t status; + + while (true) + { + status = libspdm_responder_dispatch_message(m_spdm_context); + if (status == LIBSPDM_STATUS_SUCCESS) + { + /* success dispatch SPDM message*/ + } + if ((status == LIBSPDM_STATUS_SEND_FAIL) || + (status == LIBSPDM_STATUS_RECEIVE_FAIL)) + { + printf("Server Critical Error - STOP\n"); + return false; + } + if (status != LIBSPDM_STATUS_UNSUPPORTED_CAP) + { + continue; + } + switch (m_command) + { + case SOCKET_SPDM_COMMAND_TEST: + result = send_platform_data(socket, + SOCKET_SPDM_COMMAND_TEST, + (uint8_t *)"Server Hello!", + sizeof("Server Hello!")); + if (!result) + { + printf("send_platform_data Error - %x\n", errno); + return true; + } + break; + + case SOCKET_SPDM_COMMAND_OOB_ENCAP_KEY_UPDATE: +#if (LIBSPDM_ENABLE_CAPABILITY_MUT_AUTH_CAP) || (LIBSPDM_ENABLE_CAPABILITY_ENCAP_CAP) + libspdm_init_key_update_encap_state(m_spdm_context); + result = send_platform_data( + socket, + SOCKET_SPDM_COMMAND_OOB_ENCAP_KEY_UPDATE, NULL, + 0); + if (!result) + { + printf("send_platform_data Error - %x\n", errno); + return true; + } +#endif + break; + + case SOCKET_SPDM_COMMAND_SHUTDOWN: + result = send_platform_data( + socket, SOCKET_SPDM_COMMAND_SHUTDOWN, NULL, 0); + if (!result) + { + printf("send_platform_data Error - %x\n", errno); + return true; + } + return false; + break; + + case SOCKET_SPDM_COMMAND_CONTINUE: + result = send_platform_data( + socket, SOCKET_SPDM_COMMAND_CONTINUE, NULL, 0); + if (!result) + { + printf("send_platform_data Error - %x\n", errno); + return true; + } + return true; + break; + + case SOCKET_SPDM_COMMAND_NORMAL: + /* unknown message*/ + return true; + break; + default: + printf("Unrecognized platform interface command %x\n", m_command); + result = send_platform_data( + socket, SOCKET_SPDM_COMMAND_UNKOWN, NULL, 0); + if (!result) + { + printf("send_platform_data Error - %x\n", errno); + return true; + } + return true; + } + } +} + +bool platform_server_routine(uint16_t port_number) +{ + SOCKET responder_socket; + struct sockaddr_in peer_address; + bool result; + uint32_t length; + bool continue_serving; + + result = create_socket(port_number, &responder_socket); + if (!result) + { + printf("Create platform service socket fail\n"); + return false; + } + + do + { + printf("Platform server listening on port %d\n", port_number); + + length = sizeof(peer_address); + m_server_socket = accept(responder_socket, + (struct sockaddr *)&peer_address, + (socklen_t *)&length); + if (m_server_socket == INVALID_SOCKET) + { + closesocket(responder_socket); + printf("Accept error. Error is 0x%x\n", errno); + return false; + } + + continue_serving = platform_server(m_server_socket); + closesocket(m_server_socket); + + } while (continue_serving); + closesocket(responder_socket); + return true; +} + +int main(int argc, char* argv[]) +{ + // libspdm_return_t status; + bool result; + + srand((unsigned int)time(NULL)); + + // process_args("spdm_responder_emu", argc, argv); + + m_spdm_context = spdm_server_init(); + if (m_spdm_context == NULL) + { + return 1; + } + result = platform_server_routine(DEFAULT_SPDM_PLATFORM_PORT); + + if (m_spdm_context != NULL) + { + libspdm_deinit_context(m_spdm_context); + free(m_spdm_context); + free(m_scratch_buffer); + } + + printf("Server stopped\n"); + + close_pcap_packet_file(); + return (!result); +} diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_caliptra_responder.h b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_caliptra_responder.h new file mode 100644 index 00000000..b5b69316 --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_caliptra_responder.h @@ -0,0 +1,34 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#ifndef __SPDM_RESPONDER_TEST_H__ +#define __SPDM_RESPONDER_TEST_H__ + +#include "hal/base.h" +#include "hal/library/memlib.h" +#include "library/spdm_responder_lib.h" +#include "library/spdm_transport_mctp_lib.h" +#include "library/mctp_responder_lib.h" + +#include "os_include.h" +#include +#include "spdm_caliptra.h" + +#endif + +bool caliptra_read_requester_root_public_certificate(uint32_t base_hash_algo, + uint16_t req_base_asym_alg, + void **data, size_t *size, + void **hash, + size_t *hash_size); + +bool caliptra_read_responder_public_certificate_chain( + uint32_t base_hash_algo, uint32_t base_asym_algo, void **data, + size_t *size, void **hash, size_t *hash_size); + +bool caliptra_read_responder_public_certificate_chain_per_slot( + uint8_t slot_id, uint32_t base_hash_algo, uint32_t base_asym_algo, + void **data, size_t *size, void **hash, size_t *hash_size); \ No newline at end of file diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_responder_mctp.c b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_responder_mctp.c new file mode 100644 index 00000000..7269cedb --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_responder_mctp.c @@ -0,0 +1,9 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#include "spdm_caliptra_responder.h" + +void *m_mctp_context; diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_responder_session.c b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_responder_session.c new file mode 100644 index 00000000..0081f2b6 --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_responder_session.c @@ -0,0 +1,51 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#include "spdm_caliptra_responder.h" + +extern void *m_mctp_context; + +/** + * Process a packet in the current SPDM session. + * + * @param This Indicates a pointer to the calling context. + * @param session_id ID of the session. + * @param request A pointer to the request data. + * @param request_size size of the request data. + * @param response A pointer to the response data. + * @param response_size size of the response data. On input, it means the size of data + * buffer. On output, it means the size of copied data buffer if + * LIBSPDM_STATUS_SUCCESS, and means the size of desired data buffer if + * RETURN_BUFFER_TOO_SMALL. + * + * @retval LIBSPDM_STATUS_SUCCESS The SPDM request is set successfully. + * @retval RETURN_INVALID_PARAMETER The data_size is NULL or the data is NULL and *data_size is not zero. + * @retval RETURN_UNSUPPORTED The data_type is unsupported. + * @retval RETURN_NOT_FOUND The data_type cannot be found. + * @retval RETURN_NOT_READY The data_type is not ready to return. + * @retval RETURN_BUFFER_TOO_SMALL The buffer is too small to hold the data. + * @retval RETURN_TIME A timeout occurred while waiting for the SPDM request + * to execute. + **/ +libspdm_return_t spdm_get_response_vendor_defined_request( + void *spdm_context, const uint32_t *session_id, bool is_app_message, + size_t request_size, const void *request, size_t *response_size, + void *response) +{ + libspdm_return_t status; + LIBSPDM_ASSERT(is_app_message); + status = mctp_get_response_secured_app_request( + m_mctp_context, spdm_context, session_id, + request, request_size, response, response_size); + + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + libspdm_generate_error_response(spdm_context, + SPDM_ERROR_CODE_INVALID_REQUEST, 0, + response_size, response); + } + return LIBSPDM_STATUS_SUCCESS; +} diff --git a/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_responder_spdm.c b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_responder_spdm.c new file mode 100644 index 00000000..844015fb --- /dev/null +++ b/verification/examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_responder_spdm.c @@ -0,0 +1,553 @@ +/** + * Copyright Notice: + * Copyright 2021-2022 DMTF. All rights reserved. + * License: BSD 3-Clause License. For full text see link: https://github.com/DMTF/spdm-emu/blob/main/LICENSE.md + **/ + +#include "spdm_caliptra_responder.h" + +void *m_spdm_context; +void *m_scratch_buffer; + +extern uint32_t m_command; + +extern SOCKET m_server_socket; + +/** + * Notify the session state to a session APP. + * + * @param spdm_context A pointer to the SPDM context. + * @param session_id The session_id of a session. + * @param session_state The state of a session. + **/ +void spdm_server_session_state_callback(void *spdm_context, + uint32_t session_id, + libspdm_session_state_t session_state); + +/** + * Notify the connection state to an SPDM context register. + * + * @param spdm_context A pointer to the SPDM context. + * @param connection_state Indicate the SPDM connection state. + **/ +void spdm_server_connection_state_callback( + void *spdm_context, libspdm_connection_state_t connection_state); + +libspdm_return_t spdm_get_response_vendor_defined_request( + void *spdm_context, const uint32_t *session_id, bool is_app_message, + size_t request_size, const void *request, size_t *response_size, + void *response); + +libspdm_return_t spdm_device_send_message(void *spdm_context, + size_t response_size, const void *response, + uint64_t timeout) +{ + bool result; + + result = send_platform_data(m_server_socket, SOCKET_SPDM_COMMAND_NORMAL, + response, (uint32_t)response_size); + if (!result) + { + printf("send_platform_data Error - %x\n", errno); + return LIBSPDM_STATUS_SEND_FAIL; + } + return LIBSPDM_STATUS_SUCCESS; +} + +libspdm_return_t spdm_responder_device_receive_message(void *spdm_context, + size_t *request_size, + void **request, + uint64_t timeout) +{ + bool result; + + assert(*request == m_send_receive_buffer); + m_send_receive_buffer_size = sizeof(m_send_receive_buffer); + result = + receive_platform_data(m_server_socket, &m_command, + m_send_receive_buffer, &m_send_receive_buffer_size); + if (!result) + { + printf("receive_platform_data Error - %x\n", errno); + return LIBSPDM_STATUS_RECEIVE_FAIL; + } + if (m_command == SOCKET_SPDM_COMMAND_NORMAL) + { + + /* Cache the message in case it is not for SPDM.*/ + } + else + { + /* Cache the message*/ + return LIBSPDM_STATUS_UNSUPPORTED_CAP; + } + *request = m_send_receive_buffer; + *request_size = m_send_receive_buffer_size; + + return LIBSPDM_STATUS_SUCCESS; +} + +void *spdm_server_init(void) +{ + void *spdm_context; + libspdm_data_parameter_t parameter; + uint8_t data8; + uint16_t data16; + uint32_t data32; + spdm_version_number_t spdm_version; + // libspdm_return_t status; + size_t scratch_buffer_size; + void *requester_cert_chain_buffer; + + printf("context_size - 0x%x\n", (uint32_t)libspdm_get_context_size()); + + m_spdm_context = (void *)malloc(libspdm_get_context_size()); + if (m_spdm_context == NULL) + { + return NULL; + } + spdm_context = m_spdm_context; + libspdm_init_context(spdm_context); + libspdm_register_device_io_func(spdm_context, spdm_device_send_message, + spdm_responder_device_receive_message); + + if (m_use_transport_layer == SOCKET_TRANSPORT_TYPE_MCTP) + { + libspdm_register_transport_layer_func( + spdm_context, + LIBSPDM_MAX_SPDM_MSG_SIZE, + LIBSPDM_TRANSPORT_HEADER_SIZE, + LIBSPDM_TRANSPORT_TAIL_SIZE, + libspdm_transport_mctp_encode_message, + libspdm_transport_mctp_decode_message); + } + else + { + free(m_spdm_context); + m_spdm_context = NULL; + return NULL; + } + libspdm_register_device_buffer_func(spdm_context, + LIBSPDM_SENDER_BUFFER_SIZE, + LIBSPDM_RECEIVER_BUFFER_SIZE, + spdm_device_acquire_sender_buffer, + spdm_device_release_sender_buffer, + spdm_device_acquire_receiver_buffer, + spdm_device_release_receiver_buffer); + + scratch_buffer_size = libspdm_get_sizeof_required_scratch_buffer(m_spdm_context); + m_scratch_buffer = (void *)malloc(scratch_buffer_size); + if (m_scratch_buffer == NULL) + { + free(m_spdm_context); + m_spdm_context = NULL; + return NULL; + } + libspdm_set_scratch_buffer(spdm_context, m_scratch_buffer, scratch_buffer_size); + + requester_cert_chain_buffer = (void *)malloc(SPDM_MAX_CERTIFICATE_CHAIN_SIZE); + if (requester_cert_chain_buffer == NULL) + { + return NULL; + } + libspdm_register_cert_chain_buffer(spdm_context, requester_cert_chain_buffer, + SPDM_MAX_CERTIFICATE_CHAIN_SIZE); + + if (!libspdm_check_context(spdm_context)) + { + return NULL; + } + + if (m_use_version != 0) + { + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + spdm_version = m_use_version << SPDM_VERSION_NUMBER_SHIFT_BIT; + libspdm_set_data(spdm_context, LIBSPDM_DATA_SPDM_VERSION, ¶meter, + &spdm_version, sizeof(spdm_version)); + } + + if (m_use_secured_message_version != 0) + { + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + spdm_version = m_use_secured_message_version << SPDM_VERSION_NUMBER_SHIFT_BIT; + libspdm_set_data(spdm_context, + LIBSPDM_DATA_SECURED_MESSAGE_VERSION, + ¶meter, &spdm_version, + sizeof(spdm_version)); + } + + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + + data8 = 0; + libspdm_set_data(spdm_context, LIBSPDM_DATA_CAPABILITY_CT_EXPONENT, + ¶meter, &data8, sizeof(data8)); + data32 = m_use_responder_capability_flags; + if (m_use_slot_id == 0xFF) + { + data32 |= SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PUB_KEY_ID_CAP; + data32 &= ~SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_CAP; + data32 &= ~SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_ALIAS_CERT_CAP; + data32 &= ~SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_SET_CERT_CAP; + data32 &= ~SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CSR_CAP; + data32 &= ~SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_CERT_INSTALL_RESET_CAP; + } + if (m_use_capability_flags != 0) + { + data32 = m_use_capability_flags; + m_use_responder_capability_flags = m_use_capability_flags; + } + libspdm_set_data(spdm_context, LIBSPDM_DATA_CAPABILITY_FLAGS, ¶meter, + &data32, sizeof(data32)); + + data8 = m_support_measurement_spec; + libspdm_set_data(spdm_context, LIBSPDM_DATA_MEASUREMENT_SPEC, ¶meter, + &data8, sizeof(data8)); + data32 = m_support_measurement_hash_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_MEASUREMENT_HASH_ALGO, ¶meter, + &data32, sizeof(data32)); + data32 = m_support_asym_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_BASE_ASYM_ALGO, ¶meter, + &data32, sizeof(data32)); + data32 = m_support_hash_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_BASE_HASH_ALGO, ¶meter, + &data32, sizeof(data32)); + data16 = m_support_dhe_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_DHE_NAME_GROUP, ¶meter, + &data16, sizeof(data16)); + data16 = m_support_aead_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_AEAD_CIPHER_SUITE, ¶meter, + &data16, sizeof(data16)); + data16 = m_support_req_asym_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_REQ_BASE_ASYM_ALG, ¶meter, + &data16, sizeof(data16)); + data16 = m_support_key_schedule_algo; + libspdm_set_data(spdm_context, LIBSPDM_DATA_KEY_SCHEDULE, ¶meter, &data16, + sizeof(data16)); + data8 = m_support_other_params_support; + libspdm_set_data(spdm_context, LIBSPDM_DATA_OTHER_PARAMS_SUPPORT, ¶meter, + &data8, sizeof(data8)); + data8 = m_support_mel_spec; + libspdm_set_data(spdm_context, LIBSPDM_DATA_MEL_SPEC, ¶meter, + &data8, sizeof(data8)); + + data8 = 0xF0; + libspdm_set_data(spdm_context, LIBSPDM_DATA_HEARTBEAT_PERIOD, ¶meter, + &data8, sizeof(data8)); + + libspdm_register_get_response_func( + spdm_context, spdm_get_response_vendor_defined_request); + + libspdm_register_session_state_callback_func( + spdm_context, spdm_server_session_state_callback); + libspdm_register_connection_state_callback_func( + spdm_context, spdm_server_connection_state_callback); + + return m_spdm_context; +} + +/** + * Notify the connection state to an SPDM context register. + * + * @param spdm_context A pointer to the SPDM context. + * @param connection_state Indicate the SPDM connection state. + **/ +void spdm_server_connection_state_callback( + void *spdm_context, libspdm_connection_state_t connection_state) +{ + bool res; + void *data; + void *data1; + size_t data_size; + size_t data1_size; + libspdm_data_parameter_t parameter; + uint8_t data8; + uint16_t data16; + uint32_t data32; + libspdm_return_t status; + void *hash; + size_t hash_size; + const uint8_t *root_cert; + size_t root_cert_size; + uint8_t index; + spdm_version_number_t spdm_version; + + switch (connection_state) + { + case LIBSPDM_CONNECTION_STATE_NOT_STARTED: + + /* clear perserved state*/ + + if (m_save_state_file_name != NULL) + { + spdm_clear_negotiated_state(spdm_context); + } + break; + + case LIBSPDM_CONNECTION_STATE_AFTER_VERSION: + if ((m_exe_connection & EXE_CONNECTION_VERSION_ONLY) != 0) + { + /* GET_VERSION is done, handle special PSK use case*/ + status = spdm_provision_psk_version_only(spdm_context, false); + if (LIBSPDM_STATUS_IS_ERROR(status)) + { + LIBSPDM_ASSERT(false); + return; + } + /* pass through to NEGOTIATED */ + } + else + { + /* normal action - do nothing */ + break; + } + + case LIBSPDM_CONNECTION_STATE_NEGOTIATED: + + if (m_use_version == 0) + { + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_CONNECTION; + data_size = sizeof(spdm_version); + libspdm_get_data(spdm_context, LIBSPDM_DATA_SPDM_VERSION, ¶meter, + &spdm_version, &data_size); + m_use_version = spdm_version >> SPDM_VERSION_NUMBER_SHIFT_BIT; + } + + /* Provision new content*/ + + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_CONNECTION; + + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_MEASUREMENT_HASH_ALGO, + ¶meter, &data32, &data_size); + m_use_measurement_hash_algo = data32; + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_BASE_ASYM_ALGO, + ¶meter, &data32, &data_size); + m_use_asym_algo = data32; + data_size = sizeof(data32); + libspdm_get_data(spdm_context, LIBSPDM_DATA_BASE_HASH_ALGO, + ¶meter, &data32, &data_size); + m_use_hash_algo = data32; + data_size = sizeof(data16); + libspdm_get_data(spdm_context, LIBSPDM_DATA_REQ_BASE_ASYM_ALG, + ¶meter, &data16, &data_size); + m_use_req_asym_algo = data16; + + res = caliptra_read_responder_public_certificate_chain(m_use_hash_algo, + m_use_asym_algo, + &data, &data_size, + NULL, NULL); + res = caliptra_read_responder_public_certificate_chain_per_slot(1, + m_use_hash_algo, + m_use_asym_algo, + &data1, &data1_size, + NULL, NULL); + if (res) + { + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + + for (index = 0; index < m_use_slot_count; index++) + { + parameter.additional_data[0] = index; + if (index == 1) + { + libspdm_set_data(spdm_context, + LIBSPDM_DATA_LOCAL_PUBLIC_CERT_CHAIN, + ¶meter, data1, data1_size); + } + else + { + libspdm_set_data(spdm_context, + LIBSPDM_DATA_LOCAL_PUBLIC_CERT_CHAIN, + ¶meter, data, data_size); + } + data8 = (uint8_t)(0xA0 + index); + libspdm_set_data(spdm_context, + LIBSPDM_DATA_LOCAL_KEY_PAIR_ID, + ¶meter, &data8, sizeof(data8)); + data8 = SPDM_CERTIFICATE_INFO_CERT_MODEL_DEVICE_CERT; + libspdm_set_data(spdm_context, + LIBSPDM_DATA_LOCAL_CERT_INFO, + ¶meter, &data8, sizeof(data8)); + data16 = SPDM_KEY_USAGE_BIT_MASK_KEY_EX_USE | + SPDM_KEY_USAGE_BIT_MASK_CHALLENGE_USE | + SPDM_KEY_USAGE_BIT_MASK_MEASUREMENT_USE | + SPDM_KEY_USAGE_BIT_MASK_ENDPOINT_INFO_USE; + libspdm_set_data(spdm_context, + LIBSPDM_DATA_LOCAL_KEY_USAGE_BIT_MASK, + ¶meter, &data16, sizeof(data16)); + } + /* do not free it*/ + } + + if (m_use_req_asym_algo != 0) + { + if ((m_use_responder_capability_flags & + SPDM_GET_CAPABILITIES_RESPONSE_FLAGS_PUB_KEY_ID_CAP) != 0) + { + m_use_slot_id = 0xFF; + } + if (m_use_slot_id == 0xFF) + { + res = libspdm_read_responder_public_key(m_use_asym_algo, &data, &data_size); + if (res) + { + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + libspdm_set_data(spdm_context, + LIBSPDM_DATA_LOCAL_PUBLIC_KEY, + ¶meter, data, data_size); + /* Do not free it.*/ + } + res = libspdm_read_requester_public_key(m_use_req_asym_algo, &data, &data_size); + if (res) + { + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + libspdm_set_data(spdm_context, + LIBSPDM_DATA_PEER_PUBLIC_KEY, + ¶meter, data, data_size); + /* Do not free it.*/ + } + } + else + { + res = caliptra_read_requester_root_public_certificate( + m_use_hash_algo, m_use_req_asym_algo, &data, + &data_size, &hash, &hash_size); + libspdm_x509_get_cert_from_cert_chain( + (uint8_t *)data + sizeof(spdm_cert_chain_t) + hash_size, + data_size - sizeof(spdm_cert_chain_t) - hash_size, 0, + &root_cert, &root_cert_size); + if (res) + { + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + libspdm_set_data( + spdm_context, + LIBSPDM_DATA_PEER_PUBLIC_ROOT_CERT, + ¶meter, (void *)root_cert, root_cert_size); + /* Do not free it.*/ + } + } + + if (res) + { + if (m_use_slot_id == 0xFF) + { + /* 0xFF slot is only allowed in */ + m_use_mut_auth = SPDM_KEY_EXCHANGE_RESPONSE_MUT_AUTH_REQUESTED; + } + data8 = m_use_mut_auth; + parameter.additional_data[0] = + m_use_slot_id; /* req_slot_id;*/ + libspdm_set_data(spdm_context, + LIBSPDM_DATA_MUT_AUTH_REQUESTED, ¶meter, + &data8, sizeof(data8)); + + data8 = m_use_basic_mut_auth; + parameter.additional_data[0] = + m_use_slot_id; /* req_slot_id;*/ + libspdm_set_data(spdm_context, + LIBSPDM_DATA_BASIC_MUT_AUTH_REQUESTED, + ¶meter, &data8, sizeof(data8)); + } + } + + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_LOCAL; + data8 = 0x3F; + libspdm_set_data(spdm_context, LIBSPDM_DATA_LOCAL_SUPPORTED_SLOT_MASK, ¶meter, + &data8, sizeof(data8)); + + if (m_save_state_file_name != NULL) + { + spdm_save_negotiated_state(spdm_context, false); + } + + break; + + default: + break; + } + + return; +} + +/** + * Notify the session state to a session APP. + * + * @param spdm_context A pointer to the SPDM context. + * @param session_id The session_id of a session. + * @param session_state The state of a session. + **/ +void spdm_server_session_state_callback(void *spdm_context, + uint32_t session_id, + libspdm_session_state_t session_state) +{ + size_t data_size; + libspdm_data_parameter_t parameter; + uint8_t data8; + + switch (session_state) + { + case LIBSPDM_SESSION_STATE_NOT_STARTED: + /* Session end*/ + + if (m_save_state_file_name != NULL) + { + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_SESSION; + *(uint32_t *)parameter.additional_data = session_id; + + data_size = sizeof(data8); + libspdm_get_data(spdm_context, + LIBSPDM_DATA_SESSION_END_SESSION_ATTRIBUTES, + ¶meter, &data8, &data_size); + if ((data8 & + SPDM_END_SESSION_REQUEST_ATTRIBUTES_PRESERVE_NEGOTIATED_STATE_CLEAR) != + 0) + { + /* clear*/ + spdm_clear_negotiated_state(spdm_context); + } + else + { + /* preserve - already done in LIBSPDM_CONNECTION_STATE_NEGOTIATED. + * spdm_save_negotiated_state (spdm_context, false);*/ + } + } + break; + + case LIBSPDM_SESSION_STATE_HANDSHAKING: + /* collect session policy*/ + if (m_use_version >= SPDM_MESSAGE_VERSION_12) + { + libspdm_zero_mem(¶meter, sizeof(parameter)); + parameter.location = LIBSPDM_DATA_LOCATION_SESSION; + *(uint32_t *)parameter.additional_data = session_id; + + data8 = 0; + data_size = sizeof(data8); + libspdm_get_data(spdm_context, + LIBSPDM_DATA_SESSION_POLICY, + ¶meter, &data8, &data_size); + printf("session policy - %x\n", data8); + } + break; + + case LIBSPDM_SESSION_STATE_ESTABLISHED: + /* no action*/ + break; + + default: + LIBSPDM_ASSERT(false); + break; + } +} diff --git a/verification/extendTCI.go b/verification/extendTCI.go index e46d1cdb..aa3a5c9f 100644 --- a/verification/extendTCI.go +++ b/verification/extendTCI.go @@ -35,7 +35,7 @@ func TestExtendTCI(d TestDPEInstance, c DPEClient, t *testing.T) { if err != nil { t.Fatal(err) } - lastCumulative := tcbInfo.Fwids[1].Digest + lastCumulativeTCI := tcbInfo.Fwids[1].Digest // Set current TCI value _, err = c.ExtendTCI(handle, tciValue) @@ -43,9 +43,17 @@ func TestExtendTCI(d TestDPEInstance, c DPEClient, t *testing.T) { t.Fatalf("[FATAL]: Could not extend TCI: %v", err) } - // Check current and cumulative measurement by CertifyKey - expectedCumulative := computeExpectedCumulative(lastCumulative, tciValue) - verifyMeasurements(c, t, handle, tciValue, expectedCumulative) + // Refresh TCB info + _, tcbInfo, err = getTcbInfoForHandle(c, handle) + if err != nil { + t.Fatal(err) + } + + // Check current and cumulative measurement in DiceTcb info block + wantCurrentTCI := tciValue + if err = verifyDiceTcbDigest(tcbInfo, wantCurrentTCI, lastCumulativeTCI); err != nil { + t.Errorf("[ERROR]: %v", err) + } } func computeExpectedCumulative(lastCumulative []byte, tciValue []byte) []byte { @@ -153,21 +161,3 @@ func TestExtendTciOnDerivedContexts(d TestDPEInstance, c DPEClient, t *testing.T t.Errorf("[ERROR]: Child node's cumulative TCI %x, expected %x", childTcbInfo.Fwids[1].Digest, wantCumulativeTCI) } } - -func verifyMeasurements(c DPEClient, t *testing.T, handle *ContextHandle, expectedCurrent []byte, expectedCumulative []byte) { - handle, tcbInfo, err := getTcbInfoForHandle(c, handle) - if err != nil { - t.Fatal(err) - } - - // Check that the last TcbInfo current/cumulative are as expected - current := tcbInfo.Fwids[0].Digest - cumulative := tcbInfo.Fwids[1].Digest - if !bytes.Equal(current, expectedCurrent) { - t.Errorf("[ERROR]: Unexpected TCI_CURRENT digest, want %v but got %v", expectedCurrent, current) - } - - if !bytes.Equal(cumulative, expectedCumulative) { - t.Errorf("[ERROR]: Unexpected cumulative TCI value, want %v but got %v", expectedCumulative, cumulative) - } -} diff --git a/verification/getCertificateChain.go b/verification/getCertificateChain.go index 362ed85c..66f8662e 100644 --- a/verification/getCertificateChain.go +++ b/verification/getCertificateChain.go @@ -102,21 +102,29 @@ func checkCertificateChain(t *testing.T, certData []byte) []*x509.Certificate { // Build certificate chain and calls to validateSignature on each chain. func validateCertChain(t *testing.T, certChain []*x509.Certificate) { t.Helper() + var err error certsToProcess := certChain // Remove unhandled critical extensions reported by x509 but defined in spec - removeTcgDiceCriticalExtensions(t, certsToProcess) + if err = removeTcgDiceCriticalExtensions(certsToProcess); err != nil { + t.Errorf("[ERROR]: %v", err) + } // Remove unhandled extended key usages reported by x509 but defined in spec - removeTcgDiceExtendedKeyUsages(t, certsToProcess) + if err = removeTcgDiceExtendedKeyUsages(certsToProcess); err != nil { + t.Errorf("[ERROR]: %v", err) + } // Build verify options - opts := buildVerifyOptions(t, certChain) + opts, err := buildVerifyOptions(certChain) + if err != nil { + t.Errorf("[ERROR]: %v", err) + } // Certificate chain validation for each intermediate certificate for _, cert := range certChain { - chains, err := cert.Verify(opts) + chains, err := cert.Verify(*opts) if err != nil { t.Errorf("[ERROR]: Error in Certificate Chain of %s: %s", cert.Subject, err.Error()) } diff --git a/verification/go.sum b/verification/go.sum index bba036dc..bfcab473 100644 --- a/verification/go.sum +++ b/verification/go.sum @@ -153,4 +153,4 @@ gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127 h1:qIbj1fsPNlZgppZ+VLlY7N33 gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c h1:dUUwHk2QECo/6vqA44rthZ8ie2QXMNeKRTHCNY2nXvo= -gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= +gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= \ No newline at end of file diff --git a/verification/simulator.go b/verification/simulator.go index 8307ba27..f9516c12 100644 --- a/verification/simulator.go +++ b/verification/simulator.go @@ -234,6 +234,46 @@ func GetSimulatorTargets() []TestTarget { getTestTarget([]string{"AutoInit", "Simulation", "X509", "Csr", "IsCA", "RotateContext", "ExtendTci", "IsSymmetric"}), AllTestCases, }, + { + "CertifyKey_TcbValidation", + getTestTarget([]string{"AutoInit", "Simulation", "X509", "Csr", "IsCA", "RotateContext", "ExtendTci"}), + []TestCase{DiceTcbValidationTestCase, TcbValidationSimulationTestCase}, + }, + { + "DeriveChild", + getTestTarget([]string{"AutoInit", "X509", "IsCA"}), + []TestCase{DeriveChildTestCase}, + }, + { + "DeriveChild_Simulation", + getTestTarget([]string{"AutoInit", "Simulation", "X509", "IsCA"}), + []TestCase{DeriveChildSimulationTestCase}, + }, + { + "DeriveChild_PrivilegeEscalation", + getTestTarget([]string{"AutoInit", "X509", "IsCA"}), + []TestCase{DeriveChildPrivilegeEscalationTestCase}, + }, + { + "DeriveChild_InputFlags", + getTestTarget([]string{"AutoInit", "Simulation", "InternalDice", "InternalInfo"}), + []TestCase{DeriveChildInputFlagsTestCase}, + }, + { + "DeriveChild_MaxTCIs", + getTestTarget([]string{"AutoInit", "Simulation"}), + []TestCase{DeriveChildMaxTCIsTestCase}, + }, + { + "DeriveChild_ChangeLocality", + getTestTarget([]string{"AutoInit", "Simulation"}), + []TestCase{DeriveChildLocalityTestCase}, + }, + { + "SpdmSupport", + getTestTarget([]string{"AutoInit", "X509", "ExtendTci"}), + []TestCase{SpdmE2ETestCase}, + }, { "GetProfile_Simulation", getTestTarget([]string{"Simulation"}), diff --git a/verification/spdm.go b/verification/spdm.go new file mode 100644 index 00000000..8d60d18b --- /dev/null +++ b/verification/spdm.go @@ -0,0 +1,318 @@ +// Licensed under the Apache-2.0 license + +package verification + +import ( + "bytes" + "crypto/x509" + "fmt" + "testing" + "unsafe" +) + +// #cgo CFLAGS: -Wall -Iexamples/spdm -Iexamples/spdm/libspdm/os_stub -Iexamples/spdm/libspdm/os_stub/spdm_device_secret_lib_sample -Iexamples/spdm/libspdm/os_stub/spdm_crypt_ext_lib -Iexamples/spdm/include -Iexamples/spdm/include/library -Iexamples/spdm/libspdm/include -Iexamples/spdm/libspdm/include/hal -Iexamples/spdm/libspdm/include/hal/library -Iexamples/spdm/libspdm/include/industry_standard -Iexamples/spdm/libspdm/include/internal -Iexamples/spdm/libspdm/include/library -Iexamples/spdm/libspdm/include/library/cryptlib -Iexamples/spdm/libspdm/include/library/requester -Iexamples/spdm/libspdm/include/library/responder -Iexamples/spdm/spdm_caliptra/spdm_caliptra_common -Iexamples/spdm/spdm_caliptra/spdm_caliptra_requester -Iexamples/spdm/spdm_caliptra/spdm_caliptra_responder -g +// #cgo LDFLAGS: -Lexamples/spdm -Lexamples/spdm/build/lib -lspdm_caliptra_requester -lspdm_requester_lib -lspdm_responder_lib -lspdm_common_lib -lspdm_transport_mctp_lib -lspdm_secured_message_lib -lspdm_device_secret_lib_sample -lspdm_crypt_ext_lib -lspdm_crypt_lib -lmctp_requester_lib -lmctp_responder_lib -lmemlib -lcryptlib_openssl -ldebuglib -lmalloclib -lopenssllib -lssl -lcrypto -lrnglib -lplatform_lib -ldebuglib_null -lspdm_transport_pcidoe_lib +// #include "examples/spdm/spdm_caliptra/spdm_caliptra_requester/spdm_caliptra_requester.h" +/* +bool platform_client_routine111(void **m_temp, size_t *cert_chain_data_size, int *a) +{ + bool result; + *cert_chain_data_size = 2; // CHECKPOINT2 + uint8_t cert_chain[2]; + *m_temp = malloc(sizeof(unsigned char) * (*cert_chain_data_size)); + cert_chain[0]=100; + cert_chain[1]=20; + + //*m_temp = cert_chain; + + if (NULL == *m_temp) + { + *cert_chain_data_size = 3; // CHECKPOINT3 + printf("Memory allocation failed\n"); + return false; + } + memcpy(*m_temp, cert_chain, *cert_chain_data_size); + *cert_chain_data_size = 4; // CHECKPOINT4 + + printf("\nCHECKPOINT 10XXXXXXXXXXXXX11110XXXXXXXXXXXXX11110XXXXXXXXXXXXX11110XXXXXXXXXXXXX111"); + int i; + int k = *cert_chain_data_size; + printf("\nCHECKPOINT 9BBB KKKK %d\n", k); + + for (i = 0; i < *cert_chain_data_size; i++) + { + printf("%x ", ((uint8_t *)*m_temp)[i]); + } + + printf("\n\n"); + for (i = 0; i < *cert_chain_data_size; i++) + { + printf("%d ", ((uint8_t *)*m_temp)[i]); + } + *cert_chain_data_size = 5; // CHECKPOINT5 + + result = true; + printf("\n%d\n", *a); + *a = 10; + printf("\n%d\n", *a); + //*cert_chain_data_size = cert_chain[0]; // CHECKPOINT6 + return result; +} + +int main111(void **temp, size_t *cert_chain_data_size) +{ + bool result; + int a; + a = 5; + // size_t cert_chain_data_size = 0; + // void *temp; + unsigned char *temp1; + // temp = malloc(sizeof(unsigned char) * 2000); + + // cert_chain_data_size = 0; + *cert_chain_data_size = 1; // CHECKPOINT1 + printf("\nCHECKPOINT 10AAAA %p\n", temp); + result = platform_client_routine111(temp, cert_chain_data_size, &a); + //*cert_chain_data_size = 7; // CHECKPOINT7 + + printf("\nCHECKPOINT 10A\n"); + + printf("\n%ld\n", *cert_chain_data_size); + // printf("\n%ln\n", &cert_chain_data_size); + + temp1 = (uint8_t *)*temp; + printf("\nCHECKPOINT 1000000000KKKKKKKKKKKKKKKKKKKKKKK %p\n", *temp); + int i; + for (i = 0; i < *cert_chain_data_size; i++) + { + printf("%x ", (uint8_t)temp1[i]); + } + printf("\n\n"); + for (i = 0; i < *cert_chain_data_size; i++) + { + printf("%d ", (uint8_t)temp1[i]); + } + printf("\nCHECKPOINT 10B\n"); + printf("\n%d\n", a); + *cert_chain_data_size = (uint8_t)temp1[1]; // CHECKPOINT8 + return (!result); +} +*/ +import "C" + +func TestWithSpdmResponder(d TestDPEInstance, client DPEClient, t *testing.T) { + // INCLUDE LATER? + // -lspdm_caliptra_responder + // #include "examples/spdm/spdm_caliptra/spdm_caliptra_responder/spdm_caliptra_responder.h" + + simulation := false + + // Get handle, digest size + handle := getInitialContextHandle(d, client, t, simulation) + + profile, err := GetTransportProfile(d) + if err != nil { + t.Fatalf("[FATAL]: Could not get profile: %v", err) + } + digestSize := profile.GetDigestSize() + + // Get cumulative before extend + handle, tcbInfo, err := getTcbInfoForHandle(client, handle) + if err != nil { + t.Fatal(err) + } + lastCumulative := tcbInfo.Fwids[1].Digest + + // Iniitalize caller supplied TCI value + inputData := make([]byte, digestSize) + for i := range inputData { + inputData[i] = byte(i) + } + + // Extend TCI to the current context + handle, err = client.ExtendTCI(handle, inputData) + if err != nil { + t.Errorf("[ERROR]: Unable to extend tci value %v", err) + } + + // TODO: (if needed) Initialize Requester + // TODO: Make SPDM series of calls to responder through requester + // TODO: Get the sequence of calls (Get sequence, see libspdm.c, see sample parsing each fieeld tried initially without libspdm.c ) + // TODO: Parse the response from each call and handle appropriately + // TODO: We need to have CertifyKey leaf cert and cert chain from responder + + var out unsafe.Pointer + var dpeProfile = C.CString("DPE_PROFILE_IROT_P384_SHA384") + var port = C.int(2323) + defer C.free(out) + //defer C.Stop() + + // fmt.Println((*unsafe.Pointer)(unsafe.Pointer(&out))) + // fmt.Println(unsafe.Pointer(&out)) + c_certChainSize := C.uint64_t(0) + fmt.Println(&c_certChainSize) + + // ret := C.get_hrot_quote((*unsafe.Pointer)(unsafe.Pointer(&out[0])), + //go C.start(C.int(1)) + + status := int(C.main1(dpeProfile, port, &out, &c_certChainSize)) + cout := (*C.uint8_t)(out) + fmt.Println(cout) + b := C.GoBytes(unsafe.Pointer(cout), C.int(c_certChainSize)) + fmt.Println(b) + fmt.Println(int(c_certChainSize)) + fmt.Println(status) + + certs, err := x509.ParseCertificates(b) + fmt.Println(err) + fmt.Println(certs) + + var out256 unsafe.Pointer + defer C.free(out256) + //defer C.Stop() + + // fmt.Println((*unsafe.Pointer)(unsafe.Pointer(&out))) + // fmt.Println(unsafe.Pointer(&out)) + var dpeProfile256 = C.CString("DPE_PROFILE_IROT_P256_SHA256") + c_certChainSize256 := C.uint64_t(0) + fmt.Println(&c_certChainSize256) + status256 := int(C.main1(dpeProfile256, port, &out256, &c_certChainSize256)) + cout256 := (*C.uint8_t)(out256) + fmt.Println(cout256) + b256 := C.GoBytes(unsafe.Pointer(cout256), C.int(c_certChainSize256)) + fmt.Println(b256) + fmt.Println(int(c_certChainSize256)) + fmt.Println(status256) + + certs256, err := x509.ParseCertificates(b256) + fmt.Println(err) + fmt.Println(certs256) + // TODO: ends + + // Get DPE certificate from SPDM + certifyKeyResp, err := client.CertifyKey(handle, make([]byte, digestSize), CertifyKeyX509, CertifyKeyFlags(0)) // STUB, MODIFY: We need to have CertifyKey leaf cert and cert cahin from responder + if err != nil { + t.Fatalf("[FATAL]: Unable to obtain certificate %v", err) + } + dpeCertBytes := certifyKeyResp.Certificate // These bytes should be received from requester + + // Parse certificate received + dpeCert, err := x509.ParseCertificate(dpeCertBytes) + if err != nil { + t.Fatalf("[FATAL]: Unable to parse DER encoded certificate %v", err) + } + + // Get certificate chain from SPDM + certChainBytes, err := client.GetCertificateChain() // STUB, MODIFY: We need to have Certchain from SPDM + if err != nil { + t.Fatalf("[FATAL]: Unable to get DER encoded certificate chain %v", err) + } + + // Parse cert chain + certChain, err := x509.ParseCertificates(certChainBytes) + if err != nil { + t.Fatalf("[FATAL]: Unable to parse DER encoded certificate %v", err) + } + + // Validate certificate chain + validateLeafCertChain(certChain, dpeCert) + + // Validate evidence in DPE cert MultiTCB information extension + multiTcbInfo, err := getMultiTcbInfo(dpeCert.Extensions) + if err != nil { + t.Fatalf("[FATAL]: Unable to parse MultiTCB info that contains evidence %v", err) + } + if len(multiTcbInfo) == 0 { + t.Fatalf("[FATAL]: Unable to validate as multi TCb information is empty") + } + + receivedCumulative := multiTcbInfo[0].Fwids[1].Digest + expectedCumulative := computeExpectedCumulative(lastCumulative, inputData) + if !bytes.Equal(receivedCumulative, expectedCumulative) { + t.Fatalf("[FATAL]: Cumulative hash from SPDM should be %v but got %v", expectedCumulative, receivedCumulative) + } else { + t.Log("[LOG] Received expected evidence data from Caliptra through SPDM.") + } + // TODO: (Explore signed measurements - stage 2) + //cs := C.CString("HP") + //defer C.free(unsafe.Pointer(cs)) + //C.print_spdm_caliptra_usage(cs) + //fmt.Println(C.myreturnData(C.int(2))) +} + +// -Wextra -Wfloat-equal -Wundef -Wpointer-arith -Wcast-align -Wwrite-strings -Wswitch-default -Wswitch-enum -Wunreachable-code -Wno-cast-qual -Wno-unused-variable -Wno-unused-parameter -Wno-unused-value -Wno-deprecated-declarations -Wno-incompatible-pointer-types -Wno-sign-conversion -Wno-sign-compare -Wno-cast-align -Wno-unused-but-set-variable -Wno-pointer-sign -Wno-int-conversion -Wno-maybe-uninitialized -Wno-discarded-qualifiers -Wimplicit-function-declaration +// #include "libspdm/os_stub/memlib/zero_mem.c" +// #include "libspdm/library/spdm_common_lib/libspdm_com_context_data.c" + +// // Argument received : Intialize character buffer to receive the base64 encoded string of SPDM measurements and details JSON. +// out := make([]*C.char, 1) +// cs := C.CString("") +// defer C.free(unsafe.Pointer(cs)) +// out[0] = cs +// // Argument received : Initialize integer to receive the length of encoded string returned. +// size := C.int(0) + +// // Function call +// // Signature of C function : get_hrot_quote(void **out, int *size, int *indices, int indices_size, uint8_t* nonce, int slot_id) +// ret := C.get_hrot_quote((*unsafe.Pointer)(unsafe.Pointer(&out[0])), +// &size, (*C.int)(unsafe.Pointer(&indices_c[0])), +// indices_size, (*C.uint8_t)(unsafe.Pointer(&nonce_c[0])), slot_id_c) + +/* +// Licensed under the Apache-2.0 license + +package verification + +import ( + "bytes" + "crypto/x509" + "fmt" + "testing" +) + +// Get Context handle +// Extend TCI using handle + +// TODO: (if needed) Initialize Requester +// TODO: Make SPDM series of calls to responder through requester +// TODO: Get the sequence of calls (Get sequence, see libspdm.c, see sample parsing each fieeld tried initially without libspdm.c ) +// TODO: Parse the response from each call and handle appropriately +// TODO: We need to have CertifyKey leaf cert and cert cahin from responder +// TODO: (Explore signed measurements - stage 2) + +// STUB, REMOVE: We need to have CertifyKey leaf cert and cert cahin from responder +// Validate certchain in go +// Validate DiceTcb info in certify key with extended Tci +// Complet validation + +// #cgo LDFLAGS: +*/ + +// build/out/memlib.out/CMakeFiles/memlib.dir/zero_mem.c.o + +/* +- pass void ** +- this is a reference to void* pointer +- how to create void* pointer and pass its address +*/ +// APPROACH 01 - No error but out is filled with junk +// func main() { +// fmt.Println("Hi") + +// out := []C.uint8_t{} + +// out = append(out, C.uint8_t(0)) +// outUnsafe := unsafe.Pointer(&out[0]) +// // fmt.Println((*unsafe.Pointer)(unsafe.Pointer(&out))) +// // fmt.Println(unsafe.Pointer(&out)) +// c_certChainSize := C.uint64_t(0) +// fmt.Println(&c_certChainSize) + +// // ret := C.get_hrot_quote((*unsafe.Pointer)(unsafe.Pointer(&out[0])), + +// status := int(C.main111((*unsafe.Pointer)(outUnsafe), &c_certChainSize)) +// // b := C.GoBytes(unsafe.Pointer(&out[0]), C.int(c_certChainSize)) + +// // fmt.Println(b) +// fmt.Println(status) +// } diff --git a/verification/verification.go b/verification/verification.go index f64eb6f5..4c7e0548 100644 --- a/verification/verification.go +++ b/verification/verification.go @@ -27,13 +27,19 @@ var InitializeContextSimulationTestCase = TestCase{ "InitializeContextSimulation", TestInitializeSimulation, []string{"Simulation"}, } var CertifyKeyTestCase = TestCase{ - "CertifyKey", TestCertifyKey, []string{"AutoInit", "X509", "IsCA"}, + "CertifyKey", TestCertifyKey, []string{"AutoInit", "X509", "IsCA", "RotateContext"}, +} +var CertifyKeySimulationTestCase = TestCase{ + "CertifyKeySimulation", TestCertifyKeySimulation, []string{"AutoInit", "Simulation", "X509", "IsCA", "RotateContext"}, } var CertifyKeyCsrTestCase = TestCase{ "CertifyKeyCsr", TestCertifyKey_Csr, []string{"AutoInit", "Csr", "IsCA"}, } -var CertifyKeySimulationTestCase = TestCase{ - "CertifyKeySimulation", TestCertifyKeySimulation, []string{"AutoInit", "Simulation", "X509", "IsCA"}, +var DiceTcbValidationTestCase = TestCase{ + "CheckDiceTcbInfo", TestDiceTcbInfo, []string{"AutoInit", "X509", "IsCA", "RotateContext", "ExtendTci"}, +} +var TcbValidationSimulationTestCase = TestCase{ + "CheckDiceTcbInfoInSimulationMode", TestDiceTcbInfoSimulation, []string{"AutoInit", "Simulation", "X509", "IsCA", "RotateContext", "ExtendTci"}, } var GetCertificateChainTestCase = TestCase{ "GetCertificateChain", TestGetCertificateChain, []string{"AutoInit", "X509"}, @@ -74,9 +80,30 @@ var SignSymmetricTestCase = TestCase{ var SignSimulationTestCase = TestCase{ "SignSimulation", TestSignSimulation, []string{"Simulation"}, } +var DeriveChildTestCase = TestCase{ + "DeriveChild", TestDeriveChild, []string{"AutoInit"}, +} +var DeriveChildSimulationTestCase = TestCase{ + "DeriveChildSimulation", TestDeriveChildSimulation, []string{"AutoInit", "Simulation", "X509", "InternalDice", "InternalInfo"}, +} +var DeriveChildMaxTCIsTestCase = TestCase{ + "DeriveChild_MaxTCIs", TestMaxTCIs, []string{"AutoInit"}, +} +var DeriveChildLocalityTestCase = TestCase{ + "DeriveChild_ChangeLocality", TestChangeLocality, []string{"AutoInit"}, +} +var DeriveChildPrivilegeEscalationTestCase = TestCase{ + "DeriveChild_PrivilegeEscalation", TestPrivilegesEscalation, []string{"AutoInit", "X509", "IsCA"}, +} +var DeriveChildInputFlagsTestCase = TestCase{ + "DeriveChild_InputFlagsSupport", TestInternalInputFlags, []string{"AutoInit", "InternalDice", "InternalInfo"}, +} var TpmPolicySigningTestCase = TestCase{ "TPMPolicySigning", TestTpmPolicySigning, []string{"AutoInit", "X509"}, } +var SpdmE2ETestCase = TestCase{ + "SpdmE2E", TestWithSpdmResponder, []string{"AutoInit", "ExtendTci"}, +} var AllTestCases = []TestCase{ CertifyKeyTestCase,