From 4e2842898af6383fcf782900f6dbc8e2082ecd42 Mon Sep 17 00:00:00 2001 From: Weiwu Zhang Date: Mon, 29 Jun 2020 15:16:36 +1000 Subject: [PATCH 1/4] adding xmldsigvierification sample golang code - not yet turned into commandline utilities --- xmldsig/README.md | 12 +++++++ xmldsig/golang/xmldsignverify.go | 60 ++++++++++++++++++++++++++++++++ 2 files changed, 72 insertions(+) create mode 100644 xmldsig/golang/xmldsignverify.go diff --git a/xmldsig/README.md b/xmldsig/README.md index 65e43275..d4299164 100644 --- a/xmldsig/README.md +++ b/xmldsig/README.md @@ -6,6 +6,18 @@ This repository serves to show how to verify XMLDSig signature in every programm In all following examples, assume you have cloned [TokenScript-Repo](https://github.com/AlphaWallet/TokenScript-Repo) - a nop-exhaustive TokenScript collection - into your home directory (`~/TokenScript-Repo`) for testing purpose. +### Go + +First, install the dependency. You can use `go get` + + $ go get github.com/russellhaering/goxmldsig + $ go run golang/xmldsignverify.go + +Or, on Ubuntu, `apt-get` + + $ sudo apt-get install golang-go golang-github-russellhaering-goxmldsig-dev + $ GOPATH=/usr/share/gocode/ go run golang/xmldsignverify.go + ### JavaScript *(not working for many files due to a bug in a JavaScript library)* diff --git a/xmldsig/golang/xmldsignverify.go b/xmldsig/golang/xmldsignverify.go new file mode 100644 index 00000000..b2d7df4d --- /dev/null +++ b/xmldsig/golang/xmldsignverify.go @@ -0,0 +1,60 @@ +package main + +import ( + "crypto/x509" + "github.com/beevik/etree" + "github.com/russellhaering/goxmldsig" +) + + +func main() { + // Generate a key and self-signed certificate for signing + randomKeyStore := dsig.RandomKeyStoreForTest() + ctx := dsig.NewDefaultSigningContext(randomKeyStore) + elementToSign := &etree.Element{ + Tag: "ExampleElement", + } + elementToSign.CreateAttr("ID", "id1234") + + // Sign the element + signedElement, err := ctx.SignEnveloped(elementToSign) + if err != nil { + panic(err) + } + + // Serialize the signed element. It is important not to modify the element + // after it has been signed - even pretty-printing the XML will invalidate + // the signature. + doc := etree.NewDocument() + doc.SetRoot(signedElement) + str, err := doc.WriteToString() + if err != nil { + panic(err) + } + + println(str) +} + +// Validate an element against a root certificate +func validate(root *x509.Certificate, el *etree.Element) { + // Construct a signing context with one or more roots of trust. + ctx := dsig.NewDefaultValidationContext(&dsig.MemoryX509CertificateStore{ + Roots: []*x509.Certificate{root}, + }) + + // It is important to only use the returned validated element. + // See: https://www.w3.org/TR/xmldsig-bestpractices/#check-what-is-signed + validated, err := ctx.Validate(el) + if err != nil { + panic(err) + } + + doc := etree.NewDocument() + doc.SetRoot(validated) + str, err := doc.WriteToString() + if err != nil { + panic(err) + } + + println(str) +} From 0a3fd049dd075e58cdd5eb460136ddfeb19e6abe Mon Sep 17 00:00:00 2001 From: Samuel Date: Fri, 9 Apr 2021 12:46:47 +1000 Subject: [PATCH 2/4] Add self-validation example code (#419) --- xmldsig/golang/ExampleElement.crt | 3 + xmldsig/golang/ExampleElement.xml | 1 + xmldsig/golang/go.mod | 8 ++ xmldsig/golang/xmldsignverify.go | 127 ++++++++++++++++++------------ 4 files changed, 90 insertions(+), 49 deletions(-) create mode 100644 xmldsig/golang/ExampleElement.crt create mode 100644 xmldsig/golang/ExampleElement.xml create mode 100644 xmldsig/golang/go.mod diff --git a/xmldsig/golang/ExampleElement.crt b/xmldsig/golang/ExampleElement.crt new file mode 100644 index 00000000..1ac51c99 --- /dev/null +++ b/xmldsig/golang/ExampleElement.crt @@ -0,0 +1,3 @@ +-----BEGIN CERTIFICATE----- +MIIBlTCB/6ADAgECAgEAMA0GCSqGSIb3DQEBCwUAMAAwHhcNMjEwNDA4MDMyNDA0WhcNMjIwNDA4MDMyOTA0WjAAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCx+Fzc+wzEMSt1+/f1BkIwLR6MUPlTM7kAoAjwvS3nIcHKZ/hM/5s9VDbYUQTThZxXHiGYSTHh4ahg5iSdV4L0Tjxv0aDmryLIpjrXU2b2VDTBNV07TA7ZaX37qa2S9biSe9Q6oI1tlS/ze6YTNeF8kaKWPrUlWePKNAfLD0E1/QIDAQABoyAwHjAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOBgQBSZwrrQuzihJFUVZ4tx/8XUN79xk/Nq3EjpJNpt5do9rOLlOgNNhbU0aH3ErmO4TGAhHn/40C3IbFxdWOSKoZLOs7/PNWoOuUmtJ/zbplCA/avniY3nq1zdUUK+cc7G+TwfJ1pYZgFFTYz1tWi9lmLES0O3J2SDuZL4wrk9Y8+HQ== +-----END CERTIFICATE----- diff --git a/xmldsig/golang/ExampleElement.xml b/xmldsig/golang/ExampleElement.xml new file mode 100644 index 00000000..c37260df --- /dev/null +++ b/xmldsig/golang/ExampleElement.xml @@ -0,0 +1 @@ +iMfmOOPBujUYLEbhg97cVxdcyx3WNgw5OrLsVf1+I6E=U0py5MnWOTSicSGPPY2LOA44fIy8A9E6GznXcljRWzjFGljqcrWd4L84mm45TUIi1r+X+6p9/iZRpESTIJ495LokX4abaoam7CuxYirDPKfpz18mBnejAZhpgOGTNLIPCn2PNLMQZc+WABJC6aszPJKrNol760rk0MwdQESQOYM=MIIBlTCB/6ADAgECAgEAMA0GCSqGSIb3DQEBCwUAMAAwHhcNMjEwNDA4MDMyNDA0WhcNMjIwNDA4MDMyOTA0WjAAMIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCx+Fzc+wzEMSt1+/f1BkIwLR6MUPlTM7kAoAjwvS3nIcHKZ/hM/5s9VDbYUQTThZxXHiGYSTHh4ahg5iSdV4L0Tjxv0aDmryLIpjrXU2b2VDTBNV07TA7ZaX37qa2S9biSe9Q6oI1tlS/ze6YTNeF8kaKWPrUlWePKNAfLD0E1/QIDAQABoyAwHjAOBgNVHQ8BAf8EBAMCB4AwDAYDVR0TAQH/BAIwADANBgkqhkiG9w0BAQsFAAOBgQBSZwrrQuzihJFUVZ4tx/8XUN79xk/Nq3EjpJNpt5do9rOLlOgNNhbU0aH3ErmO4TGAhHn/40C3IbFxdWOSKoZLOs7/PNWoOuUmtJ/zbplCA/avniY3nq1zdUUK+cc7G+TwfJ1pYZgFFTYz1tWi9lmLES0O3J2SDuZL4wrk9Y8+HQ== diff --git a/xmldsig/golang/go.mod b/xmldsig/golang/go.mod new file mode 100644 index 00000000..9a840a54 --- /dev/null +++ b/xmldsig/golang/go.mod @@ -0,0 +1,8 @@ +module github.com/alphawallet/xmldsig + +go 1.15 + +require ( + github.com/beevik/etree v1.1.0 // indirect + github.com/russellhaering/goxmldsig v1.1.0 // indirect +) diff --git a/xmldsig/golang/xmldsignverify.go b/xmldsig/golang/xmldsignverify.go index b2d7df4d..4a3a5df3 100644 --- a/xmldsig/golang/xmldsignverify.go +++ b/xmldsig/golang/xmldsignverify.go @@ -1,60 +1,89 @@ package main import ( - "crypto/x509" - "github.com/beevik/etree" - "github.com/russellhaering/goxmldsig" -) + "crypto/x509" + "encoding/pem" + "fmt" + "io/ioutil" + "os" + "github.com/beevik/etree" + dsig "github.com/russellhaering/goxmldsig" +) func main() { - // Generate a key and self-signed certificate for signing - randomKeyStore := dsig.RandomKeyStoreForTest() - ctx := dsig.NewDefaultSigningContext(randomKeyStore) - elementToSign := &etree.Element{ - Tag: "ExampleElement", - } - elementToSign.CreateAttr("ID", "id1234") - - // Sign the element - signedElement, err := ctx.SignEnveloped(elementToSign) - if err != nil { - panic(err) - } - - // Serialize the signed element. It is important not to modify the element - // after it has been signed - even pretty-printing the XML will invalidate - // the signature. - doc := etree.NewDocument() - doc.SetRoot(signedElement) - str, err := doc.WriteToString() - if err != nil { - panic(err) - } - - println(str) + // Generate a key and self-signed certificate for signing + randomKeyStore := dsig.RandomKeyStoreForTest() + ctx := dsig.NewDefaultSigningContext(randomKeyStore) + elementToSign := &etree.Element{ + Tag: "ExampleElement", + } + elementToSign.CreateAttr("ID", "id1234") + + // Sign the element + signedElement, err := ctx.SignEnveloped(elementToSign) + if err != nil { + panic(err) + } + + // Serialize the signed element. It is important not to modify the element + // after it has been signed - even pretty-printing the XML will invalidate + // the signature. + doc := etree.NewDocument() + doc.SetRoot(signedElement) + str, err := doc.WriteToString() + if err != nil { + panic(err) + } + + println(str) + + cf, e := ioutil.ReadFile("ExampleElement.crt") + if e != nil { + fmt.Println("cfload:", e.Error()) + os.Exit(1) + } + //fmt.Println(string(cf)) + cpb, cr := pem.Decode(cf) + fmt.Println(string(cr)) + fmt.Println(string(cpb.Type)) + cert, err := x509.ParseCertificate(cpb.Bytes) + if err != nil { + fmt.Println("x509.ParseCertificate:", e.Error()) + os.Exit(1) + } + fmt.Println(cert.PublicKeyAlgorithm) + + doc2 := etree.NewDocument() + errdoc := doc2.ReadFromFile("ExampleElement.xml") + if errdoc != nil { + panic(errdoc) + } + root := doc2.SelectElements("ExampleElement") + fmt.Println(root[0].Tag) + validate(cert, root[0]) } // Validate an element against a root certificate func validate(root *x509.Certificate, el *etree.Element) { - // Construct a signing context with one or more roots of trust. - ctx := dsig.NewDefaultValidationContext(&dsig.MemoryX509CertificateStore{ - Roots: []*x509.Certificate{root}, - }) - - // It is important to only use the returned validated element. - // See: https://www.w3.org/TR/xmldsig-bestpractices/#check-what-is-signed - validated, err := ctx.Validate(el) - if err != nil { - panic(err) - } - - doc := etree.NewDocument() - doc.SetRoot(validated) - str, err := doc.WriteToString() - if err != nil { - panic(err) - } - - println(str) + // Construct a signing context with one or more roots of trust. + ctx := dsig.NewDefaultValidationContext(&dsig.MemoryX509CertificateStore{ + Roots: []*x509.Certificate{root}, + }) + + // It is important to only use the returned validated element. + // See: https://www.w3.org/TR/xmldsig-bestpractices/#check-what-is-signed + validated, err := ctx.Validate(el) + if err != nil { + panic(err) + } + + doc := etree.NewDocument() + doc.SetRoot(validated) + str, err := doc.WriteToString() + if err != nil { + panic(err) + } + + println(str) } From bbc28813bceb507d215e0a6160e6d799a24ac041 Mon Sep 17 00:00:00 2001 From: Weiwu Zhang Date: Fri, 9 Apr 2021 12:49:50 +1000 Subject: [PATCH 3/4] moving readme to sub-directories --- xmldsig/README.md | 12 ------------ xmldsig/golang/README.md | 13 +++++++++++++ 2 files changed, 13 insertions(+), 12 deletions(-) create mode 100644 xmldsig/golang/README.md diff --git a/xmldsig/README.md b/xmldsig/README.md index d4299164..65e43275 100644 --- a/xmldsig/README.md +++ b/xmldsig/README.md @@ -6,18 +6,6 @@ This repository serves to show how to verify XMLDSig signature in every programm In all following examples, assume you have cloned [TokenScript-Repo](https://github.com/AlphaWallet/TokenScript-Repo) - a nop-exhaustive TokenScript collection - into your home directory (`~/TokenScript-Repo`) for testing purpose. -### Go - -First, install the dependency. You can use `go get` - - $ go get github.com/russellhaering/goxmldsig - $ go run golang/xmldsignverify.go - -Or, on Ubuntu, `apt-get` - - $ sudo apt-get install golang-go golang-github-russellhaering-goxmldsig-dev - $ GOPATH=/usr/share/gocode/ go run golang/xmldsignverify.go - ### JavaScript *(not working for many files due to a bug in a JavaScript library)* diff --git a/xmldsig/golang/README.md b/xmldsig/golang/README.md new file mode 100644 index 00000000..db7a91c2 --- /dev/null +++ b/xmldsig/golang/README.md @@ -0,0 +1,13 @@ + +# Go + +First, install the dependency. You can use `go get` + + $ go get github.com/russellhaering/goxmldsig + $ go run golang/xmldsignverify.go + +Or, on Ubuntu, `apt-get` + + $ sudo apt-get install golang-go golang-github-russellhaering-goxmldsig-dev + $ GOPATH=/usr/share/gocode/ go run golang/xmldsignverify.go + From 56cbae92e9a978ceb6840662312cc26edd477389 Mon Sep 17 00:00:00 2001 From: Samuel Huang Date: Fri, 9 Apr 2021 22:04:00 +1000 Subject: [PATCH 4/4] Read signed XML file list from argv --- xmldsig/golang/go.mod | 2 +- xmldsig/golang/xmldsignverify.go | 25 ++++++++++++++++++------- 2 files changed, 19 insertions(+), 8 deletions(-) diff --git a/xmldsig/golang/go.mod b/xmldsig/golang/go.mod index 9a840a54..f264d71e 100644 --- a/xmldsig/golang/go.mod +++ b/xmldsig/golang/go.mod @@ -4,5 +4,5 @@ go 1.15 require ( github.com/beevik/etree v1.1.0 // indirect - github.com/russellhaering/goxmldsig v1.1.0 // indirect + github.com/russellhaering/goxmldsig v1.1.1-0.20201210191726-3541f5e554ee ) diff --git a/xmldsig/golang/xmldsignverify.go b/xmldsig/golang/xmldsignverify.go index 4a3a5df3..c96f04a5 100644 --- a/xmldsig/golang/xmldsignverify.go +++ b/xmldsig/golang/xmldsignverify.go @@ -38,6 +38,7 @@ func main() { println(str) + // Replace ExampleElement.crt with the X509Certificate in your tsml accordingly. cf, e := ioutil.ReadFile("ExampleElement.crt") if e != nil { fmt.Println("cfload:", e.Error()) @@ -54,14 +55,21 @@ func main() { } fmt.Println(cert.PublicKeyAlgorithm) - doc2 := etree.NewDocument() - errdoc := doc2.ReadFromFile("ExampleElement.xml") - if errdoc != nil { - panic(errdoc) + for i := 1; i < len(os.Args); i++ { + doc2 := etree.NewDocument() + errdoc := doc2.ReadFromFile(os.Args[i]) + if errdoc != nil { + panic(errdoc) + } + root := doc2.SelectElements("ts:token") + fmt.Println(root[0].Tag) + defer func() { + if p := recover(); p != nil { + fmt.Printf("panic: %s\n", p) + } + }() + validate(cert, root[0]) } - root := doc2.SelectElements("ExampleElement") - fmt.Println(root[0].Tag) - validate(cert, root[0]) } // Validate an element against a root certificate @@ -78,6 +86,9 @@ func validate(root *x509.Certificate, el *etree.Element) { panic(err) } + if validated == nil { + return + } doc := etree.NewDocument() doc.SetRoot(validated) str, err := doc.WriteToString()