diff --git a/go.mod b/go.mod index 48fb0c28..1ebbea35 100644 --- a/go.mod +++ b/go.mod @@ -3,11 +3,9 @@ module github.com/notaryproject/notation-core-go go 1.18 require ( + github.com/fxamacker/cbor/v2 v2.4.0 github.com/golang-jwt/jwt/v4 v4.4.2 github.com/veraison/go-cose v1.0.0-rc.2 ) -require ( - github.com/fxamacker/cbor/v2 v2.4.0 // indirect - github.com/x448/float16 v0.8.4 // indirect -) +require github.com/x448/float16 v0.8.4 // indirect diff --git a/signature/cose/conformance_test.go b/signature/cose/conformance_test.go index b2d7cadb..f03c2e10 100644 --- a/signature/cose/conformance_test.go +++ b/signature/cose/conformance_test.go @@ -17,8 +17,6 @@ import ( ) type sign1 struct { - SigningTime int64 `json:"signingTime"` - Expiry int64 `json:"expiry"` Payload string `json:"payload"` ProtectedHeaders *cborStruct `json:"protectedHeaders"` UnprotectedHeaders *cborStruct `json:"unprotectedHeaders"` @@ -125,8 +123,8 @@ func getSignReq(sign1 *sign1) (*signature.SignRequest, error) { Content: []byte("hello COSE"), }, Signer: signer, - SigningTime: time.Unix(sign1.SigningTime, 0), - Expiry: time.Unix(sign1.Expiry, 0), + SigningTime: time.Unix(1661321924, 0), + Expiry: time.Unix(1661408324, 0), ExtendedSignedAttributes: []signature.Attribute{ {Key: "signedCritKey1", Value: "signedCritValue1", Critical: true}, {Key: "signedKey1", Value: "signedValue1", Critical: false}, @@ -195,7 +193,7 @@ func generateSign1(msg *cose.Sign1Message) *cose.Sign1Message { newMsg.Headers.Protected = msg.Headers.Protected newMsg.Headers.Unprotected["io.cncf.notary.signingAgent"] = msg.Headers.Unprotected["io.cncf.notary.signingAgent"] newMsg.Payload = msg.Payload - newMsg.Signature = hexToBytes("31b6cb0cd9c974b39d603465811c2aa3d96a5dff89f80b33cb4e321dc6e68a29b4ba65c00f0f9f22ee4376abfaec2cba6fd21c6881ecaab25775e3fb9226a88cf41660b2d6fd14184540d07ded3744e19ff9dbdd081e15c8f77bb6ca3072ef57141594fad4ea57d206c6b8dd3a6e0a0a7ed764ff08dbcc439bd722e1b3d282921a579a3d860cceea37d633184f9316cb6b4fa4ea550da5ad9e5bf3c2d768a787da76e594290cb10b5b1ead8b7e75967de28e9ff429fe9db814380608a15674f9741563902a620f312213d9dce5c264017cbcb3bb4f8cebee0d5ef32b364f68c11cba5630fac8e3165d06fdebaca095267223c552fe605b4529f25b65f8fa47b010b9096cec275307e82b1062f660a73e07d0b85b978b4a59b5cde51fc9a031b488a3deb38fc312a64ef2ec1250238ae16cfefc00d9aa1ceb938fe6de51f265eebe975c29f4cff8ab0afb40c45e8c985d17347bf20f455851c1a46ab655f51a159cf8910a424c5a8bbdd239e49e43a73c7b5174de29e835063e5e64b459558de5") + newMsg.Signature = hexToBytes("5bfec0a345098b9b9b6fb7358face7ab76d191b648ccd19e36fb03c2085ea072ec050d9c6e4fa4845478386d0831a2360d343a1ff027bdd56d496f996b90ac2db9da2460baffec21db7c0ca759ba83ab35cdf521c0926138681bde05277e2976cedbeb4040c930908ef2b113d935378bd3c5e7740119b2b81c59e9c6c24411abdf699547864f68f2e0f6346eeff627bf0d971abdf94e67e12a10134ccbbadfa0ab4031b18705696a9567a0f1f061247fdd00d343ea3a45f63da7f80771612b38fc9877375bcbce28aef1f3ee2b25869722c24737c49d8c6711376dd62b3d32b24d489746e2ba5d25fa76febcc6abf9d2baee67221c85a7a8f8763dadc5e20bb8c5c03a75c68211557813d2d6adea56ec5526f78c18460b1944c8307a4b0ed64a6d6b4abed5067de5a5ad38948a2ea140b01a7762c15b3e63d7d7bdc8962e6c4bff18b34d2a19fc627f02ebf88daf7fb25c55ce1b9ca06ade02f9d60ad16cb306f433f692e598132d67b5d0a02193191d5c9cd52ad81f4e31917e5b5d40ef5ce7") return newMsg } diff --git a/signature/cose/envelope.go b/signature/cose/envelope.go index 6654e885..567c6537 100644 --- a/signature/cose/envelope.go +++ b/signature/cose/envelope.go @@ -4,11 +4,13 @@ import ( "crypto" "crypto/rand" "crypto/x509" + "errors" "fmt" "io" "strconv" "time" + "github.com/fxamacker/cbor/v2" "github.com/notaryproject/notation-core-go/signature" "github.com/notaryproject/notation-core-go/signature/internal/base" "github.com/veraison/go-cose" @@ -17,10 +19,37 @@ import ( // MediaTypeEnvelope is the COSE signature envelope blob mediaType. const MediaTypeEnvelope = "application/cose" +var ( + // encMode is the encoding mode used in Sign + encMode cbor.EncMode + + // decMode is the decoding mode used in Content + decMode cbor.DecMode +) + func init() { - if err := signature.RegisterEnvelopeType(MediaTypeEnvelope, NewEnvelope, ParseEnvelope); err != nil { + err := signature.RegisterEnvelopeType(MediaTypeEnvelope, NewEnvelope, ParseEnvelope) + if err != nil { + panic(err) + } + + encOpts := cbor.EncOptions{ + Time: cbor.TimeUnix, + TimeTag: cbor.EncTagRequired, + } + encMode, err = encOpts.EncMode() + if err != nil { panic(err) } + + decOpts := cbor.DecOptions{ + TimeTag: cbor.DecTagRequired, + } + decMode, err = decOpts.DecMode() + if err != nil { + panic(err) + } + } // Protected Headers @@ -204,6 +233,7 @@ func (e *envelope) Sign(req *signature.SignRequest) ([]byte, error) { return nil, &signature.InvalidSignatureError{Msg: err.Error()} } e.base = msg + return encoded, nil } @@ -393,7 +423,11 @@ func generateProtectedHeaders(req *signature.SignRequest, protected cose.Protect if !ok { return &signature.InvalidSignRequestError{Msg: "signing scheme: require notary.x509 or notary.x509.signingAuthority"} } - protected[signingTimeLabel] = req.SigningTime.Unix() + rawTimeCBOR, err := encodeTime(req.SigningTime) + if err != nil { + return &signature.InvalidSignRequestError{Msg: fmt.Sprintf("signing time: %q", err)} + } + protected[signingTimeLabel] = rawTimeCBOR if signingTimeLabel == headerLabelAuthenticSigningTime { crit = append(crit, headerLabelAuthenticSigningTime) } @@ -401,7 +435,11 @@ func generateProtectedHeaders(req *signature.SignRequest, protected cose.Protect // expiry if !req.Expiry.IsZero() { crit = append(crit, headerLabelExpiry) - protected[headerLabelExpiry] = req.Expiry.Unix() + rawExpiryCBOR, err := encodeTime(req.Expiry) + if err != nil { + return &signature.InvalidSignRequestError{Msg: fmt.Sprintf("expiry: %q", err)} + } + protected[headerLabelExpiry] = rawExpiryCBOR } // extended attributes @@ -471,19 +509,19 @@ func parseProtectedHeaders(protected cose.ProtectedHeader, signerInfo *signature if !ok { return &signature.InvalidSignatureError{Msg: "unsupported signingScheme: " + signingSchemeString} } - signingTime, ok := protected[signingTimeLabel].(int64) - if !ok { - return &signature.InvalidSignatureError{Msg: "invalid signingTime under signing scheme: " + signingSchemeString} + signingTime, err := parseTime(protected[signingTimeLabel]) + if err != nil { + return &signature.InvalidSignatureError{Msg: fmt.Sprintf("invalid signingTime: %v", err)} } - signerInfo.SignedAttributes.SigningTime = time.Unix(signingTime, 0) + signerInfo.SignedAttributes.SigningTime = signingTime // populate signerInfo.SignedAttributes.Expiry - if exp, ok := protected[headerLabelExpiry]; ok { - expiry, ok := exp.(int64) - if !ok { - return &signature.InvalidSignatureError{Msg: "expiry requires int64 type"} + if _, ok := protected[headerLabelExpiry]; ok { + expiry, err := parseTime(protected[headerLabelExpiry]) + if err != nil { + return &signature.InvalidSignatureError{Msg: fmt.Sprintf("invalid expiry: %v", err)} } - signerInfo.SignedAttributes.Expiry = time.Unix(expiry, 0) + signerInfo.SignedAttributes.Expiry = expiry } // populate signerInfo.SignedAttributes.ExtendedAttributes @@ -569,3 +607,44 @@ func contains(s []interface{}, e interface{}) bool { } return false } + +// encodeTime generates a Tag1 Datetime CBOR object and casts it to +// cbor.RawMessage +func encodeTime(t time.Time) (cbor.RawMessage, error) { + timeCBOR, err := encMode.Marshal(t) + if err != nil { + return nil, err + } + + return cbor.RawMessage(timeCBOR), nil +} + +// decodeTime decodes cbor.RawMessage of Tag1 Datetime CBOR object +// into time.Time +func decodeTime(timeRaw cbor.RawMessage) (time.Time, error) { + var t time.Time + err := decMode.Unmarshal([]byte(timeRaw), &t) + if err != nil { + return time.Time{}, err + } + + return t, nil +} + +// parseTime parses time values from cose.ProtectedHeader +// in go-cose, CBOR times (tag 1) decode to time.Time. +// +// For more details: https://github.com/fxamacker/cbor/blob/7704fa5efaf3ef4ac35aff38f50f6ff567793072/decode.go#L52 +func parseTime(timeValue interface{}) (time.Time, error) { + switch t := timeValue.(type) { + case cbor.RawMessage: + return decodeTime(t) + // TODO: need a way to check the tag number of datetime inside the signature + // and fail if it's a Tag0. We only accept Tag1 datetime. + // https://github.com/notaryproject/notation-core-go/issues/97 + case time.Time: + return t, nil + } + + return time.Time{}, errors.New("invalid timeValue type") +} diff --git a/signature/cose/envelope_test.go b/signature/cose/envelope_test.go index b4cc51bf..e2cc837a 100644 --- a/signature/cose/envelope_test.go +++ b/signature/cose/envelope_test.go @@ -8,6 +8,7 @@ import ( "testing" "time" + "github.com/fxamacker/cbor/v2" "github.com/notaryproject/notation-core-go/signature" "github.com/notaryproject/notation-core-go/signature/signaturetest" "github.com/notaryproject/notation-core-go/testhelper" @@ -538,6 +539,21 @@ func TestSignerInfoErrors(t *testing.T) { } }) + t.Run("when decodeTime fails", func(t *testing.T) { + env, err := getVerifyCOSE("notary.x509", signature.KeyTypeRSA, 3072) + if err != nil { + t.Fatalf("getVerifyCOSE() failed. Error = %s", err) + } + raw := cbor.RawMessage{} + env.base.Headers.Protected[headerLabelSigningTime] = raw + raw = nil + _, err = env.Content() + expected := errors.New("invalid signingTime: EOF") + if !isErrEqual(expected, err) { + t.Fatalf("Content() expects error: %v, but got: %v.", expected, err) + } + }) + t.Run("when COSE envelope protected header has invalid signingTime", func(t *testing.T) { env, err := getVerifyCOSE("notary.x509", signature.KeyTypeRSA, 3072) if err != nil { @@ -545,7 +561,7 @@ func TestSignerInfoErrors(t *testing.T) { } env.base.Headers.Protected[headerLabelSigningTime] = "invalid" _, err = env.Content() - expected := errors.New("invalid signingTime under signing scheme: notary.x509") + expected := errors.New("invalid signingTime: invalid timeValue type") if !isErrEqual(expected, err) { t.Fatalf("Content() expects error: %v, but got: %v.", expected, err) } @@ -558,7 +574,7 @@ func TestSignerInfoErrors(t *testing.T) { } env.base.Headers.Protected[headerLabelExpiry] = "invalid" _, err = env.Content() - expected := errors.New("expiry requires int64 type") + expected := errors.New("invalid expiry: invalid timeValue type") if !isErrEqual(expected, err) { t.Fatalf("Content() expects error: %v, but got: %v.", expected, err) } diff --git a/signature/cose/testdata/conformance.json b/signature/cose/testdata/conformance.json index 254e69d0..bccb6fd8 100644 --- a/signature/cose/testdata/conformance.json +++ b/signature/cose/testdata/conformance.json @@ -5,15 +5,15 @@ "expiry": 1661408324, "payload": "68656C6C6F20434F5345", "protectedHeaders": { - "cborHex": "A80138250283781C696F2E636E63662E6E6F746172792E7369676E696E67536368656D6575696F2E636E63662E6E6F746172792E6578706972796E7369676E6564437269744B65793103782B6170706C69636174696F6E2F766E642E636E63662E6E6F746172792E7061796C6F61642E76312B6A736F6E6A7369676E65644B6579316C7369676E656456616C7565316E7369676E6564437269744B657931707369676E65644372697456616C75653175696F2E636E63662E6E6F746172792E6578706972791A63071444781A696F2E636E63662E6E6F746172792E7369676E696E6754696D651A6305C2C4781C696F2E636E63662E6E6F746172792E7369676E696E67536368656D656B6E6F746172792E78353039", - "cborDiag": "{1: -38, 2: [\"io.cncf.notary.signingScheme\", \"io.cncf.notary.expiry\", \"signedCritKey1\"], 3: \"application/vnd.cncf.notary.payload.v1+json\", \"signedKey1\": \"signedValue1\", \"signedCritKey1\": \"signedCritValue1\", \"io.cncf.notary.expiry\": 1661408324, \"io.cncf.notary.signingTime\": 1661321924, \"io.cncf.notary.signingScheme\": \"notary.x509\"}" + "cborHex": "A80138250283781C696F2E636E63662E6E6F746172792E7369676E696E67536368656D6575696F2E636E63662E6E6F746172792E6578706972796E7369676E6564437269744B65793103782B6170706C69636174696F6E2F766E642E636E63662E6E6F746172792E7061796C6F61642E76312B6A736F6E6A7369676E65644B6579316C7369676E656456616C7565316E7369676E6564437269744B657931707369676E65644372697456616C75653175696F2E636E63662E6E6F746172792E657870697279C11A63071444781A696F2E636E63662E6E6F746172792E7369676E696E6754696D65C11A6305C2C4781C696F2E636E63662E6E6F746172792E7369676E696E67536368656D656B6E6F746172792E78353039", + "cborDiag": "{1: -38, 2: [\"io.cncf.notary.signingScheme\", \"io.cncf.notary.expiry\", \"signedCritKey1\"], 3: \"application/vnd.cncf.notary.payload.v1+json\", \"signedKey1\": \"signedValue1\", \"signedCritKey1\": \"signedCritValue1\", \"io.cncf.notary.expiry\": 1(1661408324), \"io.cncf.notary.signingTime\": 1(1661321924), \"io.cncf.notary.signingScheme\": \"notary.x509\"}" }, "unprotectedHeaders": { "cborHex": "A1781B696F2E636E63662E6E6F746172792E7369676E696E674167656E74781D4E6F746174696F6E436F6E666F726D616E6365546573742F312E302E30", "cborDiag": "{\"io.cncf.notary.signingAgent\":\"NotationConformanceTest/1.0.0\"}" }, "expectedOutput": { - "cborHex": "D284590115A80138250283781C696F2E636E63662E6E6F746172792E7369676E696E67536368656D6575696F2E636E63662E6E6F746172792E6578706972796E7369676E6564437269744B65793103782B6170706C69636174696F6E2F766E642E636E63662E6E6F746172792E7061796C6F61642E76312B6A736F6E6A7369676E65644B6579316C7369676E656456616C7565316E7369676E6564437269744B657931707369676E65644372697456616C75653175696F2E636E63662E6E6F746172792E6578706972791A63071444781A696F2E636E63662E6E6F746172792E7369676E696E6754696D651A6305C2C4781C696F2E636E63662E6E6F746172792E7369676E696E67536368656D656B6E6F746172792E78353039A1781B696F2E636E63662E6E6F746172792E7369676E696E674167656E74781D4E6F746174696F6E436F6E666F726D616E6365546573742F312E302E304A68656C6C6F20434F534559018031B6CB0CD9C974B39D603465811C2AA3D96A5DFF89F80B33CB4E321DC6E68A29B4BA65C00F0F9F22EE4376ABFAEC2CBA6FD21C6881ECAAB25775E3FB9226A88CF41660B2D6FD14184540D07DED3744E19FF9DBDD081E15C8F77BB6CA3072EF57141594FAD4EA57D206C6B8DD3A6E0A0A7ED764FF08DBCC439BD722E1B3D282921A579A3D860CCEEA37D633184F9316CB6B4FA4EA550DA5AD9E5BF3C2D768A787DA76E594290CB10B5B1EAD8B7E75967DE28E9FF429FE9DB814380608A15674F9741563902A620F312213D9DCE5C264017CBCB3BB4F8CEBEE0D5EF32B364F68C11CBA5630FAC8E3165D06FDEBACA095267223C552FE605B4529F25B65F8FA47B010B9096CEC275307E82B1062F660A73E07D0B85B978B4A59B5CDE51FC9A031B488A3DEB38FC312A64EF2EC1250238AE16CFEFC00D9AA1CEB938FE6DE51F265EEBE975C29F4CFF8AB0AFB40C45E8C985D17347BF20F455851C1A46AB655F51A159CF8910A424C5A8BBDD239E49E43A73C7B5174DE29E835063E5E64B459558DE5", - "cborDiag": "18([h'A80138250283781C696F2E636E63662E6E6F746172792E7369676E696E67536368656D6575696F2E636E63662E6E6F746172792E6578706972796E7369676E6564437269744B65793103782B6170706C69636174696F6E2F766E642E636E63662E6E6F746172792E7061796C6F61642E76312B6A736F6E6A7369676E65644B6579316C7369676E656456616C7565316E7369676E6564437269744B657931707369676E65644372697456616C75653175696F2E636E63662E6E6F746172792E6578706972791A63071444781A696F2E636E63662E6E6F746172792E7369676E696E6754696D651A6305C2C4781C696F2E636E63662E6E6F746172792E7369676E696E67536368656D656B6E6F746172792E78353039', {\"io.cncf.notary.signingAgent\":\"NotationConformanceTest/1.0.0\"}, h'68656C6C6F20434F5345', h'31b6cb0cd9c974b39d603465811c2aa3d96a5dff89f80b33cb4e321dc6e68a29b4ba65c00f0f9f22ee4376abfaec2cba6fd21c6881ecaab25775e3fb9226a88cf41660b2d6fd14184540d07ded3744e19ff9dbdd081e15c8f77bb6ca3072ef57141594fad4ea57d206c6b8dd3a6e0a0a7ed764ff08dbcc439bd722e1b3d282921a579a3d860cceea37d633184f9316cb6b4fa4ea550da5ad9e5bf3c2d768a787da76e594290cb10b5b1ead8b7e75967de28e9ff429fe9db814380608a15674f9741563902a620f312213d9dce5c264017cbcb3bb4f8cebee0d5ef32b364f68c11cba5630fac8e3165d06fdebaca095267223c552fe605b4529f25b65f8fa47b010b9096cec275307e82b1062f660a73e07d0b85b978b4a59b5cde51fc9a031b488a3deb38fc312a64ef2ec1250238ae16cfefc00d9aa1ceb938fe6de51f265eebe975c29f4cff8ab0afb40c45e8c985d17347bf20f455851c1a46ab655f51a159cf8910a424c5a8bbdd239e49e43a73c7b5174de29e835063e5e64b459558de5'])" + "cborHex": "D284590117A80138250283781C696F2E636E63662E6E6F746172792E7369676E696E67536368656D6575696F2E636E63662E6E6F746172792E6578706972796E7369676E6564437269744B65793103782B6170706C69636174696F6E2F766E642E636E63662E6E6F746172792E7061796C6F61642E76312B6A736F6E6A7369676E65644B6579316C7369676E656456616C7565316E7369676E6564437269744B657931707369676E65644372697456616C75653175696F2E636E63662E6E6F746172792E657870697279C11A63071444781A696F2E636E63662E6E6F746172792E7369676E696E6754696D65C11A6305C2C4781C696F2E636E63662E6E6F746172792E7369676E696E67536368656D656B6E6F746172792E78353039A1781B696F2E636E63662E6E6F746172792E7369676E696E674167656E74781D4E6F746174696F6E436F6E666F726D616E6365546573742F312E302E304A68656C6C6F20434F53455901805BFEC0A345098B9B9B6FB7358FACE7AB76D191B648CCD19E36FB03C2085EA072EC050D9C6E4FA4845478386D0831A2360D343A1FF027BDD56D496F996B90AC2DB9DA2460BAFFEC21DB7C0CA759BA83AB35CDF521C0926138681BDE05277E2976CEDBEB4040C930908EF2B113D935378BD3C5E7740119B2B81C59E9C6C24411ABDF699547864F68F2E0F6346EEFF627BF0D971ABDF94E67E12A10134CCBBADFA0AB4031B18705696A9567A0F1F061247FDD00D343EA3A45F63DA7F80771612B38FC9877375BCBCE28AEF1F3EE2B25869722C24737C49D8C6711376DD62B3D32B24D489746E2BA5D25FA76FEBCC6ABF9D2BAEE67221C85A7A8F8763DADC5E20BB8C5C03A75C68211557813D2D6ADEA56EC5526F78C18460B1944C8307A4B0ED64A6D6B4ABED5067DE5A5AD38948A2EA140B01A7762C15B3E63D7D7BDC8962E6C4BFF18B34D2A19FC627F02EBF88DAF7FB25C55CE1B9CA06ADE02F9D60AD16CB306F433F692E598132D67B5D0A02193191D5C9CD52AD81F4E31917E5B5D40EF5CE7", + "cborDiag": "18([h'A80138250283781C696F2E636E63662E6E6F746172792E7369676E696E67536368656D6575696F2E636E63662E6E6F746172792E6578706972796E7369676E6564437269744B65793103782B6170706C69636174696F6E2F766E642E636E63662E6E6F746172792E7061796C6F61642E76312B6A736F6E6A7369676E65644B6579316C7369676E656456616C7565316E7369676E6564437269744B657931707369676E65644372697456616C75653175696F2E636E63662E6E6F746172792E657870697279C11A63071444781A696F2E636E63662E6E6F746172792E7369676E696E6754696D65C11A6305C2C4781C696F2E636E63662E6E6F746172792E7369676E696E67536368656D656B6E6F746172792E78353039', {\"io.cncf.notary.signingAgent\":\"NotationConformanceTest/1.0.0\"}, h'68656C6C6F20434F5345', h'5bfec0a345098b9b9b6fb7358face7ab76d191b648ccd19e36fb03c2085ea072ec050d9c6e4fa4845478386d0831a2360d343a1ff027bdd56d496f996b90ac2db9da2460baffec21db7c0ca759ba83ab35cdf521c0926138681bde05277e2976cedbeb4040c930908ef2b113d935378bd3c5e7740119b2b81c59e9c6c24411abdf699547864f68f2e0f6346eeff627bf0d971abdf94e67e12a10134ccbbadfa0ab4031b18705696a9567a0f1f061247fdd00d343ea3a45f63da7f80771612b38fc9877375bcbce28aef1f3ee2b25869722c24737c49d8c6711376dd62b3d32b24d489746e2ba5d25fa76febcc6abf9d2baee67221c85a7a8f8763dadc5e20bb8c5c03a75c68211557813d2d6adea56ec5526f78c18460b1944c8307a4b0ed64a6d6b4abed5067de5a5ad38948a2ea140b01a7762c15b3e63d7d7bdc8962e6c4bff18b34d2a19fc627f02ebf88daf7fb25c55ce1b9ca06ade02f9d60ad16cb306f433f692e598132d67b5d0a02193191d5c9cd52ad81f4e31917e5b5d40ef5ce7'])" } } diff --git a/signature/internal/base/envelope.go b/signature/internal/base/envelope.go index ca5c9e21..544c6bd1 100644 --- a/signature/internal/base/envelope.go +++ b/signature/internal/base/envelope.go @@ -114,7 +114,7 @@ func validateSignRequest(req *signature.SignRequest) error { if _, err := req.Signer.KeySpec(); err != nil { return err } - + return validateSigningSchema(req.SigningScheme) }