diff --git a/xmldsig/signature.go b/xmldsig/signature.go new file mode 100644 index 0000000..f98b8d7 --- /dev/null +++ b/xmldsig/signature.go @@ -0,0 +1,51 @@ +package xmldsig + +import "encoding/xml" + +// Method is part of Signature. +type Method struct { + Algorithm string `xml:",attr"` +} + +// Signature is a model for the Signature object specified by XMLDSIG. This is +// convenience object when constructing XML that you'd like to sign. For example: +// +// type Foo struct { +// Stuff string +// Signature Signature +// } +// +// f := Foo{Suff: "hello"} +// f.Signature = DefaultSignature() +// buf, _ := xml.Marshal(f) +// buf, _ = Sign(key, buf) +// +type Signature struct { + XMLName xml.Name `xml:"http://www.w3.org/2000/09/xmldsig# Signature"` + + CanonicalizationMethod Method `xml:"SignedInfo>CanonicalizationMethod"` + SignatureMethod Method `xml:"SignedInfo>SignatureMethod"` + ReferenceTransforms []Method `xml:"SignedInfo>Reference>Transforms>Transform"` + DigestMethod Method `xml:"SignedInfo>Reference>DigestMethod"` + DigestValue string `xml:"SignedInfo>Reference>DigestValue"` + SignatureValue string `xml:"SignatureValue"` + KeyName string `xml:"KeyInfo>KeyName"` +} + +// DefaultSignature populates a default Signature that uses c14n and SHA1. +func DefaultSignature() Signature { + return Signature{ + CanonicalizationMethod: Method{ + Algorithm: "http://www.w3.org/TR/2001/REC-xml-c14n-20010315", + }, + SignatureMethod: Method{ + Algorithm: "http://www.w3.org/2000/09/xmldsig#rsa-sha1", + }, + ReferenceTransforms: []Method{ + Method{Algorithm: "http://www.w3.org/2000/09/xmldsig#enveloped-signature"}, + }, + DigestMethod: Method{ + Algorithm: "http://www.w3.org/2000/09/xmldsig#sha1", + }, + } +} diff --git a/xmldsig/xmldsig_test.go b/xmldsig/xmldsig_test.go index bcb4862..71805e0 100644 --- a/xmldsig/xmldsig_test.go +++ b/xmldsig/xmldsig_test.go @@ -1,10 +1,16 @@ package xmldsig import ( + "encoding/xml" "strings" "testing" ) +type Envelope struct { + Data string + Signature Signature `xml:"http://www.w3.org/2000/09/xmldsig# Signature"` +} + func TestSign(t *testing.T) { key := []byte(`-----BEGIN PRIVATE KEY----- MIICeAIBADANBgkqhkiG9w0BAQEFAASCAmIwggJeAgEAAoGBAOK9uFHs/nXrH9Lc @@ -48,7 +54,7 @@ XML Security Library example: Simple signature template file for sign1 example. -` +`) expectedSignedString := "\n\n\n \n\tHello, World!\n \n \n \n \n \n \n \n \n \n \n 9H/rQr2Axe9hYTV2n/tCp+3UIQQ=\n \n \n 2rM7C8ZzCjxEY4kueUaSevvEZjORQ7hBTWGxUJXStyQScLtX1drFx9dRmUdk/uRr\n0O37B3gsbKzlpQNfdVYPIfWgswjEVLBH7Ncl1dJ6dTofkQrogIF5CQE+PIAG3MPh\nnWsIcBahRQ+rNaRB/TDscuEV3+V3Je4K7E0OEKEuP1I=\n \n\t\n \n \n\n" @@ -62,6 +68,22 @@ XML Security Library example: Simple signature template file for sign1 example. t.Errorf("signed: expected %q, got `%q`", expectedSignedString, string(actualSignedString)) return } + + // Try again but this time construct the message from a struct having a Signature member + doc := Envelope{Data: "Hello, World!"} + doc.Signature = DefaultSignature() + docStr, err = xml.Marshal(doc) + if err != nil { + t.Errorf("marshal: %s", err) + } + actualSignedString, err = Sign(key, docStr) + if err != nil { + t.Errorf("sign: %s", err) + return + } + expectedSignedString = "\nHello, World!09XOMG8zghPZhJYD8kM2uJsr1cc=fqL9oHtcNiFFaTy7AJoQ1hs5Wz0fTqjq0xANLz/mSLBLiFv2OEicuwyo4InyBnyf\njSjmCBaz8QPX9rTW49a2wv1RMkls0WnqP65DUY2ofM4wKHWcjnGt1p1rlYdDv5Sl\njk5Wqwy2EmoqGSXQovRZmn4jidThmoqgum4LNKC2lFI=\n" + if string(actualSignedString) != expectedSignedString { + t.Errorf("signed: expected %q, got `%q`", expectedSignedString, string(actualSignedString)) return }