From b390a3e30add3c06a0cf22b1a3f4cf0f013d9af9 Mon Sep 17 00:00:00 2001 From: Ross Kinder Date: Wed, 23 Dec 2015 11:31:54 -0500 Subject: [PATCH] progress: enable xmldsig and do other cleanups --- decrypt.go | 2 +- decrypt_test.go | 2 - encrypt.go | 113 +------- xmlenc_test.go => encrypt_realworld_test.go | 103 ++++--- error_thunk.go | 5 + examples/xmldsig.go | 8 +- xmldsig.go | 157 +++++++++++ xmldsig_test.go | 280 ++++++++++++++++++++ xmlenc.go | 215 --------------- xmlsec.go | 151 +++++++++++ 10 files changed, 655 insertions(+), 381 deletions(-) rename xmlenc_test.go => encrypt_realworld_test.go (75%) create mode 100644 xmldsig.go create mode 100644 xmldsig_test.go delete mode 100644 xmlenc.go create mode 100644 xmlsec.go diff --git a/decrypt.go b/decrypt.go index 05104a4..2a3d8c3 100644 --- a/decrypt.go +++ b/decrypt.go @@ -48,7 +48,7 @@ func DecryptXML(privateKey []byte, doc []byte) ([]byte, error) { parsedDoc, err := newDoc(doc) if err != nil { - return nil, fmt.Errorf("malformed XML") + return nil, err } defer closeDoc(parsedDoc) diff --git a/decrypt_test.go b/decrypt_test.go index d4b0a51..71a97e3 100644 --- a/decrypt_test.go +++ b/decrypt_test.go @@ -106,7 +106,6 @@ Geka8nz8JjwxpUjAiSWYKLtJhGEaTqCYxCCX2Dw+dOTqUzHOZ7WKv4JXPK5G/Uhr c.Assert(Cert, Not(IsNil)) - /* XXX err = Verify(Cert, actualPlaintextString, DsigOptions{ XMLID: []XMLIDOption{{ ElementName: "Assertion", @@ -114,7 +113,6 @@ Geka8nz8JjwxpUjAiSWYKLtJhGEaTqCYxCCX2Dw+dOTqUzHOZ7WKv4JXPK5G/Uhr AttributeName: "ID", }}}) c.Assert(err, IsNil) - */ } func (testSuite *DecryptTest) TestDecryptWithPadding(c *C) { diff --git a/encrypt.go b/encrypt.go index ba9af5f..97c5962 100644 --- a/encrypt.go +++ b/encrypt.go @@ -1,123 +1,30 @@ package xmlsec -// Note: on mac you need: brew install libxmlsec1 libxml2 - // #cgo pkg-config: xmlsec1 // #include // #include // #include -// #include // #include // #include // -// static inline xmlSecKeyDataId MY_xmlSecKeyDataAesId(void) { -// return xmlSecKeyDataAesId; -// } +// // Note: the xmlSecKeyData*Id itentifiers are macros, so we need to wrap them +// // here to make them callable from go. +// static inline xmlSecKeyDataId MY_xmlSecKeyDataAesId(void) { return xmlSecKeyDataAesId; } +// static inline xmlSecKeyDataId MY_xmlSecKeyDataDesId(void) { return xmlSecKeyDataDesId; } +// static inline xmlSecTransformId MY_xmlSecTransformAes128CbcId(void) { return xmlSecTransformAes128CbcId; } +// static inline xmlSecTransformId MY_xmlSecTransformAes192CbcId(void) { return xmlSecTransformAes192CbcId; } +// static inline xmlSecTransformId MY_xmlSecTransformAes256CbcId(void) { return xmlSecTransformAes256CbcId; } +// static inline xmlSecTransformId MY_xmlSecTransformDes3CbcId(void) { return xmlSecTransformDes3CbcId; } +// static inline xmlSecTransformId MY_xmlSecTransformRsaOaepId(void) { return xmlSecTransformRsaOaepId; } +// static inline xmlSecTransformId MY_xmlSecTransformRsaPkcs1Id(void) { return xmlSecTransformRsaPkcs1Id; } // -// static inline xmlSecTransformId MY_xmlSecTransformAes128CbcId(void) { -// return xmlSecTransformAes128CbcId; -// } -// -// static inline xmlSecTransformId MY_xmlSecTransformRsaOaepId(void) { -// return xmlSecTransformRsaOaepId; -// } -// -// static inline xmlSecKeyDataId MY_xmlSecKeyDataDesId(void) { -// return xmlSecKeyDataDesId; -// } -// static inline xmlSecTransformId MY_xmlSecTransformAes192CbcId(void) { -// return xmlSecTransformAes192CbcId; -// } -// static inline xmlSecTransformId MY_xmlSecTransformAes256CbcId(void) { -// return xmlSecTransformAes256CbcId; -// } -// static inline xmlSecTransformId MY_xmlSecTransformDes3CbcId(void) { -// return xmlSecTransformDes3CbcId; -// } -// static inline xmlSecTransformId MY_xmlSecTransformRsaPkcs1Id(void) { -// return xmlSecTransformRsaPkcs1Id; -// } -// -import "C" - -// #cgo pkg-config: libxml-2.0 -// #include -// #include -// #include -// // Macro wrapper function -// static inline void MY_xmlFree(void *p) { -// xmlFree(p); -// } import "C" import ( - "errors" "fmt" "unsafe" ) -// void onError_cgo(char *file, int line, char *funcName, char *errorObject, char *errorSubject, int reason, char *msg); -import "C" - -func init() { - C.xmlInitParser() - - if rv := C.xmlSecInit(); rv < 0 { - panic("xmlsec failed to initialize") - } - if rv := C.xmlSecCryptoAppInit(nil); rv < 0 { - panic("xmlsec crypto initialization failed.") - } - if rv := C.xmlSecCryptoInit(); rv < 0 { - panic("xmlsec crypto initialization failed.") - } - - C.xmlSecErrorsSetCallback((C.xmlSecErrorsCallback)(unsafe.Pointer(C.onError_cgo))) -} - -func newDoc(buf []byte) (*C.xmlDoc, error) { - ctx := C.xmlCreateMemoryParserCtxt((*C.char)(unsafe.Pointer(&buf[0])), - C.int(len(buf))) - if ctx == nil { - return nil, errors.New("error creating parser") - } - defer C.xmlFreeParserCtxt(ctx) - - //C.xmlCtxtUseOptions(ctx, C.int(p.Options)) - C.xmlParseDocument(ctx) - - if ctx.wellFormed == C.int(0) { - return nil, errors.New("malformed XML") - } - - doc := ctx.myDoc - if doc == nil { - return nil, errors.New("parse failed") - } - - return doc, nil -} - -func closeDoc(doc *C.xmlDoc) { - C.xmlFreeDoc(doc) -} - -func dumpDoc(doc *C.xmlDoc) []byte { - var buffer *C.xmlChar - var bufferSize C.int - C.xmlDocDumpMemory(doc, &buffer, &bufferSize) - rv := C.GoStringN((*C.char)(unsafe.Pointer(buffer)), bufferSize) - C.MY_xmlFree(unsafe.Pointer(buffer)) - - // TODO(ross): this is totally nasty un-idiomatic, but I'm - // tired of googling how to copy a []byte from a char* - return []byte(rv) -} - -func constXmlChar(s string) *C.xmlChar { - return (*C.xmlChar)(unsafe.Pointer(C.CString(s))) -} - const ( DefaultAlgorithm = iota Aes128Cbc diff --git a/xmlenc_test.go b/encrypt_realworld_test.go similarity index 75% rename from xmlenc_test.go rename to encrypt_realworld_test.go index d521efb..69a7e8b 100644 --- a/xmlenc_test.go +++ b/encrypt_realworld_test.go @@ -1,21 +1,22 @@ package xmlsec -/* import ( "strings" . "gopkg.in/check.v1" ) -type XmlencTest struct { +// XmlencRealWorldTest is a test suite that verifies that xmlenc works in +// a real-world scenario where we decrypt real SAML assertions. +type XmlencRealWorldTest struct { Key []byte DocStr []byte ExpectedPlaintext []byte } -var _ = Suite(&XmlencTest{}) +var _ = Suite(&XmlencRealWorldTest{}) -func (testSuite *XmlencTest) SetUpTest(c *C) { +func (testSuite *XmlencRealWorldTest) SetUpTest(c *C) { testSuite.Key = []byte(`-----BEGIN RSA PRIVATE KEY----- MIICXgIBAAKBgQDU8wdiaFmPfTyRYuFlVPi866WrH/2JubkHzp89bBQopDaLXYxi 3PTu3O6Q/KaKxMOFBqrInwqpv/omOGZ4ycQ51O9I+Yc7ybVlW94lTo2gpGf+Y/8E @@ -44,17 +45,36 @@ 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 `) - testSuite.ExpectedPlaintext = []byte("https://idp.testshib.org/idp/shibbolethVwEKsGObmOM6y22Nstadwz1fq6dnQ2aDmERPMuEteds=gcROTzJ7HgTu/LQprki8v9J5y4et2np48hYspgmygZRvRawzxfQDgB0MBvDIBG78J5XSd401g7E999JUEh4JtSMAig1THbeWhyITGHU1Vpl2xAR5Ma0vCMLjVIleeuFHhStFBNqKirNfulfhEa7Q5THVGKrVsNuIaP/yc10Gf8AyHfCIOf/ZQGiU3Srp/pKZLXPkSKTEZIq5tAOl+pA0maFBvb4+EkMPB6E66HiXknHL9KdNh8bPcq+EkqjhtHWOy341F8W9iy6MJYGuO9ksxdiY6FK5SqmPHlgoJqXx7Et2vYME6opIgFYB6m1KW6kWgVcF0VyIzJbkXq3yTi0b5g==MIIEDjCCAvagAwIBAgIBADANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJVUzEVMBMGA1UECBMM\nUGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1cmdoMREwDwYDVQQKEwhUZXN0U2hpYjEZMBcG\nA1UEAxMQaWRwLnRlc3RzaGliLm9yZzAeFw0wNjA4MzAyMTEyMjVaFw0xNjA4MjcyMTEyMjVaMGcx\nCzAJBgNVBAYTAlVTMRUwEwYDVQQIEwxQZW5uc3lsdmFuaWExEzARBgNVBAcTClBpdHRzYnVyZ2gx\nETAPBgNVBAoTCFRlc3RTaGliMRkwFwYDVQQDExBpZHAudGVzdHNoaWIub3JnMIIBIjANBgkqhkiG\n9w0BAQEFAAOCAQ8AMIIBCgKCAQEArYkCGuTmJp9eAOSGHwRJo1SNatB5ZOKqDM9ysg7CyVTDClcp\nu93gSP10nH4gkCZOlnESNgttg0r+MqL8tfJC6ybddEFB3YBo8PZajKSe3OQ01Ow3yT4I+Wdg1tsT\npSge9gEz7SrC07EkYmHuPtd71CHiUaCWDv+xVfUQX0aTNPFmDixzUjoYzbGDrtAyCqA8f9CN2txI\nfJnpHE6q6CmKcoLADS4UrNPlhHSzd614kR/JYiks0K4kbRqCQF0Dv0P5Di+rEfefC6glV8ysC8dB\n5/9nb0yh/ojRuJGmgMWHgWk6h0ihjihqiu4jACovUZ7vVOCgSE5Ipn7OIwqd93zp2wIDAQABo4HE\nMIHBMB0GA1UdDgQWBBSsBQ869nh83KqZr5jArr4/7b+QazCBkQYDVR0jBIGJMIGGgBSsBQ869nh8\n3KqZr5jArr4/7b+Qa6FrpGkwZzELMAkGA1UEBhMCVVMxFTATBgNVBAgTDFBlbm5zeWx2YW5pYTET\nMBEGA1UEBxMKUGl0dHNidXJnaDERMA8GA1UEChMIVGVzdFNoaWIxGTAXBgNVBAMTEGlkcC50ZXN0\nc2hpYi5vcmeCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAjR29PhrCbk8qLN5M\nFfSVk98t3CT9jHZoYxd8QMRLI4j7iYQxXiGJTT1FXs1nd4Rha9un+LqTfeMMYqISdDDI6tv8iNpk\nOAvZZUosVkUo93pv1T0RPz35hcHHYq2yee59HJOco2bFlcsH8JBXRSRrJ3Q7Eut+z9uo80JdGNJ4\n/SJy5UorZ8KazGj16lfJhOBXldgrhppQBb0Nq6HKHguqmwRfJ+WkxemZXzhediAjGeka8nz8Jjwx\npUjAiSWYKLtJhGEaTqCYxCCX2Dw+dOTqUzHOZ7WKv4JXPK5G/Uhr8K/qhmFT2nIQi538n6rVYLeW\nj8Bbnl+ev0peYzxFyF5sQA==_5c425656721b41a6cfa4a9c96225e082https://15661444.ngrok.io/saml2/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransportmyselfMemberStaffmyself@testshib.orgAnd IMember@testshib.orgStaff@testshib.orgMe Myselfurn:mace:dir:entitlement:common-lib-termsMe Myself And I8F+M9ovyaYNwCId0pVkVsnZYRDo=555-5555") - + testSuite.ExpectedPlaintext = []byte("" + + "\n" + + "https://idp.testshib.org/idp/shibbolethhttps://idp.testshib.org/idp/shibbolethVwEKsGObmOM6y22Nstadwz1fq6dnQ2aDmERPMuEteds=gcROTzJ7HgTu/LQprki8v9J5y4et2np48hYspgmygZRvRawzxfQDgB0MBvDIBG78J5XSd401g7E999JUEh4JtSMAig1THbeWhyITGHU1Vpl2xAR5Ma0vCMLjVIleeuFHhStFBNqKirNfulfhEa7Q5THVGKrVsNuIaP/yc10Gf8AyHfCIOf/ZQGiU3Srp/pKZLXPkSKTEZIq5tAOl+pA0maFBvb4+EkMPB6E66HiXknHL9KdNh8bPcq+EkqjhtHWOy341F8W9iy6MJYGuO9ksxdiY6FK5SqmPHlgoJqXx7Et2vYME6opIgFYB6m1KW6kWgVcF0VyIzJbkXq3yTi0b5g==MIIEDjCCAvagAwIBAgIBADANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJVUzEVMBMGA1UECBMM\n" + + "UGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1cmdoMREwDwYDVQQKEwhUZXN0U2hpYjEZMBcG\n" + + "A1UEAxMQaWRwLnRlc3RzaGliLm9yZzAeFw0wNjA4MzAyMTEyMjVaFw0xNjA4MjcyMTEyMjVaMGcx\n" + + "CzAJBgNVBAYTAlVTMRUwEwYDVQQIEwxQZW5uc3lsdmFuaWExEzARBgNVBAcTClBpdHRzYnVyZ2gx\n" + + "ETAPBgNVBAoTCFRlc3RTaGliMRkwFwYDVQQDExBpZHAudGVzdHNoaWIub3JnMIIBIjANBgkqhkiG\n" + + "9w0BAQEFAAOCAQ8AMIIBCgKCAQEArYkCGuTmJp9eAOSGHwRJo1SNatB5ZOKqDM9ysg7CyVTDClcp\n" + + "u93gSP10nH4gkCZOlnESNgttg0r+MqL8tfJC6ybddEFB3YBo8PZajKSe3OQ01Ow3yT4I+Wdg1tsT\n" + + "pSge9gEz7SrC07EkYmHuPtd71CHiUaCWDv+xVfUQX0aTNPFmDixzUjoYzbGDrtAyCqA8f9CN2txI\n" + + "fJnpHE6q6CmKcoLADS4UrNPlhHSzd614kR/JYiks0K4kbRqCQF0Dv0P5Di+rEfefC6glV8ysC8dB\n" + + "5/9nb0yh/ojRuJGmgMWHgWk6h0ihjihqiu4jACovUZ7vVOCgSE5Ipn7OIwqd93zp2wIDAQABo4HE\n" + + "MIHBMB0GA1UdDgQWBBSsBQ869nh83KqZr5jArr4/7b+QazCBkQYDVR0jBIGJMIGGgBSsBQ869nh8\n" + + "3KqZr5jArr4/7b+Qa6FrpGkwZzELMAkGA1UEBhMCVVMxFTATBgNVBAgTDFBlbm5zeWx2YW5pYTET\n" + + "MBEGA1UEBxMKUGl0dHNidXJnaDERMA8GA1UEChMIVGVzdFNoaWIxGTAXBgNVBAMTEGlkcC50ZXN0\n" + + "c2hpYi5vcmeCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAjR29PhrCbk8qLN5M\n" + + "FfSVk98t3CT9jHZoYxd8QMRLI4j7iYQxXiGJTT1FXs1nd4Rha9un+LqTfeMMYqISdDDI6tv8iNpk\n" + + "OAvZZUosVkUo93pv1T0RPz35hcHHYq2yee59HJOco2bFlcsH8JBXRSRrJ3Q7Eut+z9uo80JdGNJ4\n" + + "/SJy5UorZ8KazGj16lfJhOBXldgrhppQBb0Nq6HKHguqmwRfJ+WkxemZXzhediAjGeka8nz8Jjwx\n" + + "pUjAiSWYKLtJhGEaTqCYxCCX2Dw+dOTqUzHOZ7WKv4JXPK5G/Uhr8K/qhmFT2nIQi538n6rVYLeW\n" + + "j8Bbnl+ev0peYzxFyF5sQA==_5c425656721b41a6cfa4a9c96225e082https://15661444.ngrok.io/saml2/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransportmyselfMemberStaffmyself@testshib.orgAnd IMember@testshib.orgStaff@testshib.orgMe Myselfurn:mace:dir:entitlement:common-lib-termsMe Myself And I8F+M9ovyaYNwCId0pVkVsnZYRDo=555-5555\n") } -func (testSuite *XmlencTest) TestDecrypt(c *C) { - actualPlaintextString, err := Decrypt(testSuite.Key, testSuite.DocStr) +func (testSuite *XmlencRealWorldTest) TestDecrypt(c *C) { + actualPlaintextString, err := DecryptXML(testSuite.Key, testSuite.DocStr) c.Assert(err, IsNil) c.Assert(string(actualPlaintextString), Equals, string(testSuite.ExpectedPlaintext)) } -func (testSuite *XmlencTest) TestDecryptWithPadding(c *C) { +func (testSuite *XmlencRealWorldTest) TestDecryptWithPadding(c *C) { // This docStr has two bytes of padding, make sure they are removed off docStr := []byte(`https://idp.testshib.org/idp/shibbolethMIIB7zCCAVgCCQDFzbKIp7b3MTANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGEwJVUzELMAkGA1UE CAwCR0ExDDAKBgNVBAoMA2ZvbzESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTEzMTAwMjAwMDg1MVoX @@ -65,27 +85,27 @@ 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`) - actualPlaintextString, err := Decrypt(testSuite.Key, docStr) + actualPlaintextString, err := DecryptXML(testSuite.Key, docStr) c.Assert(err, IsNil) - c.Assert(strings.HasSuffix(string(actualPlaintextString), ""), Equals, true) + c.Assert(strings.HasSuffix(string(actualPlaintextString), "\n"), Equals, true) } -func (testSuite *XmlencTest) TestInvalid(c *C) { - _, err := Decrypt(testSuite.Key, testSuite.DocStr) +func (testSuite *XmlencRealWorldTest) TestInvalid(c *C) { + _, err := DecryptXML(testSuite.Key, testSuite.DocStr) c.Assert(err, IsNil) - _, err = Decrypt(testSuite.Key, []byte("")) - c.Assert(err, ErrorMatches, "no EncryptedData elements found") + _, err = DecryptXML(testSuite.Key, []byte("")) + c.Assert(err, ErrorMatches, "xmlSecFindNode cannot find EncryptedData node") - _, err = Decrypt([]byte("XXX"), testSuite.DocStr) - c.Assert(err, ErrorMatches, "Cannot parse key as PEM encoded RSA private key") + _, err = DecryptXML([]byte("XXX"), testSuite.DocStr) + c.Assert(err, ErrorMatches, "func=xmlSecOpenSSLAppKeyLoadBIO:.*") docStr := []byte(`https://idp.testshib.org/idp/shibbolethinvalid<`) - _, err = Decrypt(testSuite.Key, docStr) - c.Assert(err, ErrorMatches, "XML syntax error on line 1: unexpected EOF") + _, err = DecryptXML(testSuite.Key, docStr) + c.Assert(err, ErrorMatches, "malformed XML") docStr = []byte(` @@ -98,7 +118,7 @@ func (testSuite *XmlencTest) TestInvalid(c *C) { - ??MIIB7zCCAVgCCQDFzbKIp7b3MTANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGEwJVUzELMAkGA1UECAwCR0ExDDAKBgNVBAoMA2ZvbzESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTEzMTAwMjAwMDg1MVoXDTE0MTAwMjAwMDg1MVowPDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkdBMQwwCgYDVQQKDANmb28xEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1PMHYmhZj308kWLhZVT4vOulqx/9ibm5B86fPWwUKKQ2i12MYtz07tzukPymisTDhQaqyJ8Kqb/6JjhmeMnEOdTvSPmHO8m1ZVveJU6NoKRn/mP/BD7FW52WhbrUXLSeHVSKfWkNk6S4hk9MV9TswTvyRIKvRsw0X/gfnqkroJcCAwEAATANBgkqhkiG9w0BAQUFAAOBgQCMMlIO+GNcGekevKgkakpMdAqJfs24maGb90DvTLbRZRD7Xvn1MnVBBS9hzlXiFLYOInXACMW5gcoRFfeTQLSouMM8o57h0uKjfTmuoWHLQLi6hnF+cvCsEFiJZ4AbF+DgmO6TarJ8O05t8zvnOwJlNCASPZRH/JmF8tX0hoHuAQ== + MIIB7zCCAVgCCQDFzbKIp7b3MTANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGEwJVUzELMAkGA1UECAwCR0ExDDAKBgNVBAoMA2ZvbzESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTEzMTAwMjAwMDg1MVoXDTE0MTAwMjAwMDg1MVowPDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkdBMQwwCgYDVQQKDANmb28xEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1PMHYmhZj308kWLhZVT4vOulqx/9ibm5B86fPWwUKKQ2i12MYtz07tzukPymisTDhQaqyJ8Kqb/6JjhmeMnEOdTvSPmHO8m1ZVveJU6NoKRn/mP/BD7FW52WhbrUXLSeHVSKfWkNk6S4hk9MV9TswTvyRIKvRsw0X/gfnqkroJcCAwEAATANBgkqhkiG9w0BAQUFAAOBgQCMMlIO+GNcGekevKgkakpMdAqJfs24maGb90DvTLbRZRD7Xvn1MnVBBS9hzlXiFLYOInXACMW5gcoRFfeTQLSouMM8o57h0uKjfTmuoWHLQLi6hnF+cvCsEFiJZ4AbF+DgmO6TarJ8O05t8zvnOwJlNCASPZRH/JmF8tX0hoHuAQ== @@ -112,7 +132,7 @@ func (testSuite *XmlencTest) TestInvalid(c *C) { `) - _, err = Decrypt(testSuite.Key, docStr) + _, err = DecryptXML(testSuite.Key, docStr) c.Assert(err, IsNil) docStr = []byte(` @@ -140,36 +160,8 @@ func (testSuite *XmlencTest) TestInvalid(c *C) { `) - _, err = Decrypt(testSuite.Key, docStr) - c.Assert(err, ErrorMatches, "illegal base64 data at input byte 2") - - docStr = []byte(` - - - - - - - - - - - MIIB7zCCAVgCCQDFzbKIp7b3MTANBgkqhkiG9w0BAQUFADA8MQswCQYDVQQGEwJVUzELMAkGA1UECAwCR0ExDDAKBgNVBAoMA2ZvbzESMBAGA1UEAwwJbG9jYWxob3N0MB4XDTEzMTAwMjAwMDg1MVoXDTE0MTAwMjAwMDg1MVowPDELMAkGA1UEBhMCVVMxCzAJBgNVBAgMAkdBMQwwCgYDVQQKDANmb28xEjAQBgNVBAMMCWxvY2FsaG9zdDCBnzANBgkqhkiG9w0BAQEFAAOBjQAwgYkCgYEA1PMHYmhZj308kWLhZVT4vOulqx/9ibm5B86fPWwUKKQ2i12MYtz07tzukPymisTDhQaqyJ8Kqb/6JjhmeMnEOdTvSPmHO8m1ZVveJU6NoKRn/mP/BD7FW52WhbrUXLSeHVSKfWkNk6S4hk9MV9TswTvyRIKvRsw0X/gfnqkroJcCAwEAATANBgkqhkiG9w0BAQUFAAOBgQCMMlIO+GNcGekevKgkakpMdAqJfs24maGb90DvTLbRZRD7Xvn1MnVBBS9hzlXiFLYOInXACMW5gcoRFfeTQLSouMM8o57h0uKjfTmuoWHLQLi6hnF+cvCsEFiJZ4AbF+DgmO6TarJ8O05t8zvnOwJlNCASPZRH/JmF8tX0hoHuAQ== - - - - 0grSplyWOao1tEshQRtSsQqcl8lKTOqg/AR+U2Dh/1ACl0nZcv18De8U0iySrKSHQNaWcm2YpvBGUMddf4yKn40eVvmNoqElJVgOIhc5rPykua2AEyt2ShXOpFaCtXindqyax1IxxyJi+6o62swx+Q5pIy3YDaFN6/lNCgSdLak= - - - - - NzvG??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 - - - -`) - _, err = Decrypt(testSuite.Key, docStr) - c.Assert(err, ErrorMatches, "illegal base64 data at input byte 4") + _, err = DecryptXML(testSuite.Key, docStr) + c.Assert(err, ErrorMatches, "func=xmlSecBase64CtxDecodeByte.*") docStr = []byte(` @@ -196,7 +188,6 @@ func (testSuite *XmlencTest) TestInvalid(c *C) { `) - _, err = Decrypt(testSuite.Key, docStr) - c.Assert(err, ErrorMatches, "unsupported encryption method: http://www.w3.org/2001/04/xmlenc#aes999-cbc") + _, err = DecryptXML(testSuite.Key, docStr) + c.Assert(err, ErrorMatches, ".*name=EncryptionMethod.*") } -*/ diff --git a/error_thunk.go b/error_thunk.go index e778ad0..dec27a6 100644 --- a/error_thunk.go +++ b/error_thunk.go @@ -1,5 +1,10 @@ package xmlsec +// onError_cgo is a C function that can be passed to xmlSecErrorsSetCallback which +// in turn invokes the go function onError which captures the error. +// For reasons I do not completely understand, it must be defined in a different +// file from onError + // void onError_cgo(char *file, int line, char *funcName, char *errorObject, char *errorSubject, int reason, char *msg) { // onError(file, line, funcName, errorObject, errorSubject, reason, msg); // } diff --git a/examples/xmldsig.go b/examples/xmldsig.go index 1e936d2..4fcaee1 100644 --- a/examples/xmldsig.go +++ b/examples/xmldsig.go @@ -6,7 +6,7 @@ import ( "io/ioutil" "os" - "github.com/crewjam/go-xmlsec/xmldsig" + "github.com/crewjam/go-xmlsec" ) func main() { @@ -33,7 +33,7 @@ func main() { buf, err := ioutil.ReadAll(os.Stdin) if *doSign { - signedBuf, err := xmldsig.Sign(key, buf, xmldsig.Options{}) + signedBuf, err := xmlsec.Sign(key, buf, xmlsec.DsigOptions{}) if err != nil { fmt.Printf("%s\n", err) os.Exit(1) @@ -42,8 +42,8 @@ func main() { } if *doVerify { - err := xmldsig.Verify(key, buf, xmldsig.Options{}) - if err == xmldsig.ErrVerificationFailed { + err := xmlsec.Verify(key, buf, xmlsec.DsigOptions{}) + if err == xmlsec.ErrVerificationFailed { fmt.Println("signature is not correct") os.Exit(1) } diff --git a/xmldsig.go b/xmldsig.go new file mode 100644 index 0000000..fe30edf --- /dev/null +++ b/xmldsig.go @@ -0,0 +1,157 @@ +package xmlsec + +import ( + "errors" + "fmt" + "unsafe" +) + +// #cgo pkg-config: xmlsec1 +// #include +// #include +// #include +// #include +// #include +// #include +import "C" + +// DsigOptions represents additional, less commonly used, options for Sign and +// Verify +type DsigOptions struct { + // Specify the name of ID attributes for specific elements. This + // may be required if the signed document contains Reference elements + // that define which parts of the document are to be signed. + // + // https://www.aleksey.com/xmlsec/faq.html#section_3_2 + // http://www.w3.org/TR/xml-id/ + // http://xmlsoft.org/html/libxml-valid.html#xmlAddID + XMLID []XMLIDOption +} + +type XMLIDOption struct { + ElementName string + ElementNamespace string + AttributeName string +} + +// Sign returns a version of docStr signed with key according to +// the XML-DSIG standard. docStr is a template document meaning +// that it contains a `Signature` element in the +// http://www.w3.org/2000/09/xmldsig# namespace. +func Sign(key []byte, doc []byte, opts DsigOptions) ([]byte, error) { + + startProcessingXML() + defer stopProcessingXML() + + ctx := C.xmlSecDSigCtxCreate(nil) + if ctx == nil { + return nil, errors.New("failed to create signature context") + } + defer C.xmlSecDSigCtxDestroy(ctx) + + ctx.signKey = C.xmlSecCryptoAppKeyLoadMemory( + (*C.xmlSecByte)(unsafe.Pointer(&key[0])), + C.xmlSecSize(len(key)), + C.xmlSecKeyDataFormatPem, + nil, nil, nil) + if ctx.signKey == nil { + return nil, errors.New("failed to load pem key") + } + + parsedDoc, err := newDoc2(doc, opts) + if err != nil { + return nil, err + } + defer closeDoc(parsedDoc) + + node := C.xmlSecFindNode(C.xmlDocGetRootElement(parsedDoc), + (*C.xmlChar)(unsafe.Pointer(&C.xmlSecNodeSignature)), + (*C.xmlChar)(unsafe.Pointer(&C.xmlSecDSigNs))) + if node == nil { + return nil, errors.New("cannot find start node") + } + + if rv := C.xmlSecDSigCtxSign(ctx, node); rv < 0 { + return nil, errors.New("failed to sign") + } + + return dumpDoc(parsedDoc), nil + +} + +// ErrVerificationFailed is returned from Verify when the signature is incorrect +var ErrVerificationFailed = errors.New("signature verification failed") + +const ( + xmlSecDSigStatusUnknown = 0 + xmlSecDSigStatusSucceeded = 1 + xmlSecDSigStatusInvalid = 2 +) + +// Verify checks that the signature in docStr is valid according +// to the XML-DSIG specification. publicKey is the public part of +// the key used to sign docStr. If the signature is not correct, +// this function returns ErrVerificationFailed. +func Verify(publicKey []byte, doc []byte, opts DsigOptions) error { + startProcessingXML() + defer stopProcessingXML() + + keysMngr := C.xmlSecKeysMngrCreate() + if keysMngr == nil { + return fmt.Errorf("xmlSecKeysMngrCreate failed") + } + defer C.xmlSecKeysMngrDestroy(keysMngr) + + if rv := C.xmlSecCryptoAppDefaultKeysMngrInit(keysMngr); rv < 0 { + return fmt.Errorf("xmlSecCryptoAppDefaultKeysMngrInit failed") + } + + key := C.xmlSecCryptoAppKeyLoadMemory( + (*C.xmlSecByte)(unsafe.Pointer(&publicKey[0])), + C.xmlSecSize(len(publicKey)), + C.xmlSecKeyDataFormatCertPem, + nil, nil, nil) + if key == nil { + return fmt.Errorf("xmlSecCryptoAppKeyLoadMemory failed") + } + + if rv := C.xmlSecCryptoAppKeyCertLoadMemory(key, + (*C.xmlSecByte)(unsafe.Pointer(&publicKey[0])), + C.xmlSecSize(len(publicKey)), + C.xmlSecKeyDataFormatCertPem); rv < 0 { + C.xmlSecKeyDestroy(key) + return fmt.Errorf("xmlSecCryptoAppKeyCertLoad failed") + } + + if rv := C.xmlSecCryptoAppDefaultKeysMngrAdoptKey(keysMngr, key); rv < 0 { + return fmt.Errorf("xmlSecCryptoAppDefaultKeysMngrAdoptKey failed") + } + + dsigCtx := C.xmlSecDSigCtxCreate(keysMngr) + if dsigCtx == nil { + return fmt.Errorf("xmlSecDSigCtxCreate failed") + } + defer C.xmlSecDSigCtxDestroy(dsigCtx) + + parsedDoc, err := newDoc2(doc, opts) + if err != nil { + return err + } + defer closeDoc(parsedDoc) + + node := C.xmlSecFindNode(C.xmlDocGetRootElement(parsedDoc), + (*C.xmlChar)(unsafe.Pointer(&C.xmlSecNodeSignature)), + (*C.xmlChar)(unsafe.Pointer(&C.xmlSecDSigNs))) + if node == nil { + return errors.New("cannot find start node") + } + + if rv := C.xmlSecDSigCtxVerify(dsigCtx, node); rv < 0 { + return ErrVerificationFailed + } + + if dsigCtx.status != xmlSecDSigStatusSucceeded { + return ErrVerificationFailed + } + return nil +} diff --git a/xmldsig_test.go b/xmldsig_test.go new file mode 100644 index 0000000..76dd5f5 --- /dev/null +++ b/xmldsig_test.go @@ -0,0 +1,280 @@ +package xmlsec + +import ( + "encoding/xml" + "strings" + + . "gopkg.in/check.v1" +) + +type Envelope struct { + Data string + Signature Signature `xml:"http://www.w3.org/2000/09/xmldsig# Signature"` +} + +type XmlDSigTest struct { + Key []byte + Cert []byte + DocStr []byte +} + +var _ = Suite(&XmlDSigTest{}) + +func (testSuite *XmlDSigTest) SetUpTest(c *C) { + testSuite.Key = []byte(`-----BEGIN RSA PRIVATE KEY----- +MIIBPAIBAAJBANPQbQ92nlbeg1Q5JNHSO1Yey46nZ7GJltLWw1ccSvp7pnvmfUm+ +M521CpFpfr4EAE3UVBMoU9j/hqq3dFAc2H0CAwEAAQJBALFVCjmsAZyQ5jqZLO5N +qEfNuHZSSUol+xPBogFIOq3BWa269eNNcAK5or5g0XWWon7EPdyGT4qyDVH9KzXK +RLECIQDzm/Nj0epUGN51/rKJgRXWkXW/nfSCMO9fvQR6Ujoq3wIhAN6WeHK9vgWg +wBWqMdq5sR211+LlDH7rOUQ6rBpbsoQjAiEA7jzpfglgPPZFOOfo+oh/LuP6X3a+ +FER/FQXpRyb7M8kCIETUrwZ8WkiPPxbz/Fqw1W5kjw/g2I5e2uSYaCP2eyuVAiEA +mOI6RhRyMqgxQyy0plJVjG1s4fdu92AWYy9AwYeyd/8= +-----END RSA PRIVATE KEY----- +`) + testSuite.Cert = []byte(`-----BEGIN CERTIFICATE----- +MIIDpzCCA1GgAwIBAgIJAK+ii7kzrdqvMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3Vy +aXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEWMBQG +A1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtz +ZXkuY29tMCAXDTE0MDUyMzE3NTUzNFoYDzIxMTQwNDI5MTc1NTM0WjCBxzELMAkG +A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExPTA7BgNVBAoTNFhNTCBTZWN1 +cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtzZXkuY29tL3htbHNlYykxKTAn +BgNVBAsTIFRlc3QgVGhpcmQgTGV2ZWwgUlNBIENlcnRpZmljYXRlMRYwFAYDVQQD +Ew1BbGVrc2V5IFNhbmluMSEwHwYJKoZIhvcNAQkBFhJ4bWxzZWNAYWxla3NleS5j +b20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA09BtD3aeVt6DVDkk0dI7Vh7Ljqdn +sYmW0tbDVxxK+nume+Z9Sb4znbUKkWl+vgQATdRUEyhT2P+Gqrd0UBzYfQIDAQAB +o4IBRTCCAUEwDAYDVR0TBAUwAwEB/zAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBH +ZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFNf0xkZ3zjcEI60pVPuwDqTM +QygZMIHjBgNVHSMEgdswgdiAFP7k7FMk8JWVxxC14US1XTllWuN+oYG0pIGxMIGu +MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1M +IFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2Vj +KTEQMA4GA1UECxMHUm9vdCBDQTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8G +CSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggkAr6KLuTOt2q0wDQYJKoZI +hvcNAQEFBQADQQAOXBj0yICp1RmHXqnUlsppryLCW3pKBD1dkb4HWarO7RjA1yJJ +fBjXssrERn05kpBcrRfzou4r3DCgQFPhjxga +-----END CERTIFICATE----- +`) + testSuite.DocStr = []byte(` + + + + Hello, World! + + + + + + + + + + + 9H/rQr2Axe9hYTV2n/tCp+3UIQQ= + + + + + + MIIDpzCCA1GgAwIBAgIJAK+ii7kzrdqvMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3Vy +aXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEWMBQG +A1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtz +ZXkuY29tMCAXDTE0MDUyMzE3NTUzNFoYDzIxMTQwNDI5MTc1NTM0WjCBxzELMAkG +A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExPTA7BgNVBAoTNFhNTCBTZWN1 +cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtzZXkuY29tL3htbHNlYykxKTAn +BgNVBAsTIFRlc3QgVGhpcmQgTGV2ZWwgUlNBIENlcnRpZmljYXRlMRYwFAYDVQQD +Ew1BbGVrc2V5IFNhbmluMSEwHwYJKoZIhvcNAQkBFhJ4bWxzZWNAYWxla3NleS5j +b20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA09BtD3aeVt6DVDkk0dI7Vh7Ljqdn +sYmW0tbDVxxK+nume+Z9Sb4znbUKkWl+vgQATdRUEyhT2P+Gqrd0UBzYfQIDAQAB +o4IBRTCCAUEwDAYDVR0TBAUwAwEB/zAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBH +ZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFNf0xkZ3zjcEI60pVPuwDqTM +QygZMIHjBgNVHSMEgdswgdiAFP7k7FMk8JWVxxC14US1XTllWuN+oYG0pIGxMIGu +MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1M +IFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2Vj +KTEQMA4GA1UECxMHUm9vdCBDQTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8G +CSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggkAr6KLuTOt2q0wDQYJKoZI +hvcNAQEFBQADQQAOXBj0yICp1RmHXqnUlsppryLCW3pKBD1dkb4HWarO7RjA1yJJ +fBjXssrERn05kpBcrRfzou4r3DCgQFPhjxga + + + + +`) + +} + +func (testSuite *XmlDSigTest) TestSignAndVerify(c *C) { + expectedSignedString := ` + + + + Hello, World! + + + + + + + + + + + 9H/rQr2Axe9hYTV2n/tCp+3UIQQ= + + + fDKK0so/zFcmmq2X+BaVFmS0t8KB7tyW53YN6n221OArzGCs4OyWsAjj/BUR+wNF +elOnt4fo2gPK1a3IVEhMGg== + + + MIIDpzCCA1GgAwIBAgIJAK+ii7kzrdqvMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYD +VQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3Vy +aXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEWMBQG +A1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtz +ZXkuY29tMCAXDTE0MDUyMzE3NTUzNFoYDzIxMTQwNDI5MTc1NTM0WjCBxzELMAkG +A1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExPTA7BgNVBAoTNFhNTCBTZWN1 +cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtzZXkuY29tL3htbHNlYykxKTAn +BgNVBAsTIFRlc3QgVGhpcmQgTGV2ZWwgUlNBIENlcnRpZmljYXRlMRYwFAYDVQQD +Ew1BbGVrc2V5IFNhbmluMSEwHwYJKoZIhvcNAQkBFhJ4bWxzZWNAYWxla3NleS5j +b20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA09BtD3aeVt6DVDkk0dI7Vh7Ljqdn +sYmW0tbDVxxK+nume+Z9Sb4znbUKkWl+vgQATdRUEyhT2P+Gqrd0UBzYfQIDAQAB +o4IBRTCCAUEwDAYDVR0TBAUwAwEB/zAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBH +ZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFNf0xkZ3zjcEI60pVPuwDqTM +QygZMIHjBgNVHSMEgdswgdiAFP7k7FMk8JWVxxC14US1XTllWuN+oYG0pIGxMIGu +MQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1M +IFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2Vj +KTEQMA4GA1UECxMHUm9vdCBDQTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8G +CSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggkAr6KLuTOt2q0wDQYJKoZI +hvcNAQEFBQADQQAOXBj0yICp1RmHXqnUlsppryLCW3pKBD1dkb4HWarO7RjA1yJJ +fBjXssrERn05kpBcrRfzou4r3DCgQFPhjxga + + + + +` + actualSignedString, err := Sign(testSuite.Key, testSuite.DocStr, DsigOptions{}) + c.Assert(err, IsNil) + c.Assert(string(actualSignedString), Equals, expectedSignedString) + + err = Verify(testSuite.Cert, actualSignedString, DsigOptions{}) + c.Assert(err, IsNil) +} + +func (testSuite *XmlDSigTest) TestConstructFromSignature(c *C) { + // Try again but this time construct the message from a struct having a Signature member + doc := Envelope{Data: "Hello, World!"} + doc.Signature = DefaultSignature(testSuite.Cert) + docStr, err := xml.MarshalIndent(doc, "", " ") + c.Assert(err, IsNil) + actualSignedString, err := Sign(testSuite.Key, docStr, DsigOptions{}) + c.Assert(err, IsNil) + + expectedSignedString := ` + + Hello, World! + + + + + + + + + + sEenIPkW9ssFSB9t4UU6VUrytqc= + + + chSWfpQBIQraySsUHzs5N51+ruelu2HMHh5Mnd3EjcLqFBVD0f23kmXUp7zVhCVD +vCfqu9yXDYKVOBI57F0Efg== + + + MIIDpzCCA1GgAwIBAgIJAK+ii7kzrdqvMA0GCSqGSIb3DQEBBQUAMIGcMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tMCAXDTE0MDUyMzE3NTUzNFoYDzIxMTQwNDI5MTc1NTM0WjCBxzELMAkGA1UEBhMCVVMxEzARBgNVBAgTCkNhbGlmb3JuaWExPTA7BgNVBAoTNFhNTCBTZWN1cml0eSBMaWJyYXJ5IChodHRwOi8vd3d3LmFsZWtzZXkuY29tL3htbHNlYykxKTAnBgNVBAsTIFRlc3QgVGhpcmQgTGV2ZWwgUlNBIENlcnRpZmljYXRlMRYwFAYDVQQDEw1BbGVrc2V5IFNhbmluMSEwHwYJKoZIhvcNAQkBFhJ4bWxzZWNAYWxla3NleS5jb20wXDANBgkqhkiG9w0BAQEFAANLADBIAkEA09BtD3aeVt6DVDkk0dI7Vh7LjqdnsYmW0tbDVxxK+nume+Z9Sb4znbUKkWl+vgQATdRUEyhT2P+Gqrd0UBzYfQIDAQABo4IBRTCCAUEwDAYDVR0TBAUwAwEB/zAsBglghkgBhvhCAQ0EHxYdT3BlblNTTCBHZW5lcmF0ZWQgQ2VydGlmaWNhdGUwHQYDVR0OBBYEFNf0xkZ3zjcEI60pVPuwDqTMQygZMIHjBgNVHSMEgdswgdiAFP7k7FMk8JWVxxC14US1XTllWuN+oYG0pIGxMIGuMQswCQYDVQQGEwJVUzETMBEGA1UECBMKQ2FsaWZvcm5pYTE9MDsGA1UEChM0WE1MIFNlY3VyaXR5IExpYnJhcnkgKGh0dHA6Ly93d3cuYWxla3NleS5jb20veG1sc2VjKTEQMA4GA1UECxMHUm9vdCBDQTEWMBQGA1UEAxMNQWxla3NleSBTYW5pbjEhMB8GCSqGSIb3DQEJARYSeG1sc2VjQGFsZWtzZXkuY29tggkAr6KLuTOt2q0wDQYJKoZIhvcNAQEFBQADQQAOXBj0yICp1RmHXqnUlsppryLCW3pKBD1dkb4HWarO7RjA1yJJfBjXssrERn05kpBcrRfzou4r3DCgQFPhjxga + + + + +` + c.Assert(string(actualSignedString), Equals, expectedSignedString) + + err = Verify(testSuite.Cert, actualSignedString, DsigOptions{}) + c.Assert(err, IsNil) +} + +func (testSuite *XmlDSigTest) TestVerifyFailsWhenMessageModified(c *C) { + // break the document and notice that the signature is invalid + signedStr, err := Sign(testSuite.Key, testSuite.DocStr, DsigOptions{}) + c.Assert(err, IsNil) + + err = Verify(testSuite.Cert, signedStr, DsigOptions{}) + c.Assert(err, IsNil) + + signedStr = []byte(strings.Replace(string(signedStr), "Hello", "Goodbye", 1)) + err = Verify(testSuite.Cert, []byte(signedStr), DsigOptions{}) + c.Assert(err, Equals, ErrVerificationFailed) +} + +func (testSuite *XmlDSigTest) TestInvalidXML(c *C) { + _, err := Sign(testSuite.Key, []byte(""), DsigOptions{}) + c.Assert(err, ErrorMatches, "cannot find start node") + + _, err = Sign([]byte("XXX"), testSuite.DocStr, DsigOptions{}) + c.Assert(err, ErrorMatches, "failed to load pem key") + + err = Verify(testSuite.Cert, []byte(""), DsigOptions{}) + c.Assert(err, ErrorMatches, "cannot find start node") + + err = Verify([]byte("XXX"), testSuite.DocStr, DsigOptions{}) + c.Assert(err, ErrorMatches, "xmlSecCryptoAppKeyLoadMemory failed") + + err = Verify(testSuite.Key, testSuite.DocStr, DsigOptions{}) + c.Assert(err, ErrorMatches, "xmlSecCryptoAppKeyLoadMemory failed") + + err = Verify(testSuite.Cert, testSuite.DocStr, DsigOptions{}) + c.Assert(err, ErrorMatches, "signature verification failed") + +} +func (testSuite *XmlDSigTest) TestVerifySAMLSignature(c *C) { + cert := []byte(`-----BEGIN CERTIFICATE----- +MIIEDjCCAvagAwIBAgIBADANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJVUzEV +MBMGA1UECBMMUGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1cmdoMREwDwYD +VQQKEwhUZXN0U2hpYjEZMBcGA1UEAxMQaWRwLnRlc3RzaGliLm9yZzAeFw0wNjA4 +MzAyMTEyMjVaFw0xNjA4MjcyMTEyMjVaMGcxCzAJBgNVBAYTAlVTMRUwEwYDVQQI +EwxQZW5uc3lsdmFuaWExEzARBgNVBAcTClBpdHRzYnVyZ2gxETAPBgNVBAoTCFRl +c3RTaGliMRkwFwYDVQQDExBpZHAudGVzdHNoaWIub3JnMIIBIjANBgkqhkiG9w0B +AQEFAAOCAQ8AMIIBCgKCAQEArYkCGuTmJp9eAOSGHwRJo1SNatB5ZOKqDM9ysg7C +yVTDClcpu93gSP10nH4gkCZOlnESNgttg0r+MqL8tfJC6ybddEFB3YBo8PZajKSe +3OQ01Ow3yT4I+Wdg1tsTpSge9gEz7SrC07EkYmHuPtd71CHiUaCWDv+xVfUQX0aT +NPFmDixzUjoYzbGDrtAyCqA8f9CN2txIfJnpHE6q6CmKcoLADS4UrNPlhHSzd614 +kR/JYiks0K4kbRqCQF0Dv0P5Di+rEfefC6glV8ysC8dB5/9nb0yh/ojRuJGmgMWH +gWk6h0ihjihqiu4jACovUZ7vVOCgSE5Ipn7OIwqd93zp2wIDAQABo4HEMIHBMB0G +A1UdDgQWBBSsBQ869nh83KqZr5jArr4/7b+QazCBkQYDVR0jBIGJMIGGgBSsBQ86 +9nh83KqZr5jArr4/7b+Qa6FrpGkwZzELMAkGA1UEBhMCVVMxFTATBgNVBAgTDFBl +bm5zeWx2YW5pYTETMBEGA1UEBxMKUGl0dHNidXJnaDERMA8GA1UEChMIVGVzdFNo +aWIxGTAXBgNVBAMTEGlkcC50ZXN0c2hpYi5vcmeCAQAwDAYDVR0TBAUwAwEB/zAN +BgkqhkiG9w0BAQUFAAOCAQEAjR29PhrCbk8qLN5MFfSVk98t3CT9jHZoYxd8QMRL +I4j7iYQxXiGJTT1FXs1nd4Rha9un+LqTfeMMYqISdDDI6tv8iNpkOAvZZUosVkUo +93pv1T0RPz35hcHHYq2yee59HJOco2bFlcsH8JBXRSRrJ3Q7Eut+z9uo80JdGNJ4 +/SJy5UorZ8KazGj16lfJhOBXldgrhppQBb0Nq6HKHguqmwRfJ+WkxemZXzhediAj +Geka8nz8JjwxpUjAiSWYKLtJhGEaTqCYxCCX2Dw+dOTqUzHOZ7WKv4JXPK5G/Uhr +8K/qhmFT2nIQi538n6rVYLeWj8Bbnl+ev0peYzxFyF5sQA== +-----END CERTIFICATE-----`) + doc := []byte("https://idp.testshib.org/idp/shibbolethVwEKsGObmOM6y22Nstadwz1fq6dnQ2aDmERPMuEteds=gcROTzJ7HgTu/LQprki8v9J5y4et2np48hYspgmygZRvRawzxfQDgB0MBvDIBG78J5XSd401g7E999JUEh4JtSMAig1THbeWhyITGHU1Vpl2xAR5Ma0vCMLjVIleeuFHhStFBNqKirNfulfhEa7Q5THVGKrVsNuIaP/yc10Gf8AyHfCIOf/ZQGiU3Srp/pKZLXPkSKTEZIq5tAOl+pA0maFBvb4+EkMPB6E66HiXknHL9KdNh8bPcq+EkqjhtHWOy341F8W9iy6MJYGuO9ksxdiY6FK5SqmPHlgoJqXx7Et2vYME6opIgFYB6m1KW6kWgVcF0VyIzJbkXq3yTi0b5g==MIIEDjCCAvagAwIBAgIBADANBgkqhkiG9w0BAQUFADBnMQswCQYDVQQGEwJVUzEVMBMGA1UECBMM\nUGVubnN5bHZhbmlhMRMwEQYDVQQHEwpQaXR0c2J1cmdoMREwDwYDVQQKEwhUZXN0U2hpYjEZMBcG\nA1UEAxMQaWRwLnRlc3RzaGliLm9yZzAeFw0wNjA4MzAyMTEyMjVaFw0xNjA4MjcyMTEyMjVaMGcx\nCzAJBgNVBAYTAlVTMRUwEwYDVQQIEwxQZW5uc3lsdmFuaWExEzARBgNVBAcTClBpdHRzYnVyZ2gx\nETAPBgNVBAoTCFRlc3RTaGliMRkwFwYDVQQDExBpZHAudGVzdHNoaWIub3JnMIIBIjANBgkqhkiG\n9w0BAQEFAAOCAQ8AMIIBCgKCAQEArYkCGuTmJp9eAOSGHwRJo1SNatB5ZOKqDM9ysg7CyVTDClcp\nu93gSP10nH4gkCZOlnESNgttg0r+MqL8tfJC6ybddEFB3YBo8PZajKSe3OQ01Ow3yT4I+Wdg1tsT\npSge9gEz7SrC07EkYmHuPtd71CHiUaCWDv+xVfUQX0aTNPFmDixzUjoYzbGDrtAyCqA8f9CN2txI\nfJnpHE6q6CmKcoLADS4UrNPlhHSzd614kR/JYiks0K4kbRqCQF0Dv0P5Di+rEfefC6glV8ysC8dB\n5/9nb0yh/ojRuJGmgMWHgWk6h0ihjihqiu4jACovUZ7vVOCgSE5Ipn7OIwqd93zp2wIDAQABo4HE\nMIHBMB0GA1UdDgQWBBSsBQ869nh83KqZr5jArr4/7b+QazCBkQYDVR0jBIGJMIGGgBSsBQ869nh8\n3KqZr5jArr4/7b+Qa6FrpGkwZzELMAkGA1UEBhMCVVMxFTATBgNVBAgTDFBlbm5zeWx2YW5pYTET\nMBEGA1UEBxMKUGl0dHNidXJnaDERMA8GA1UEChMIVGVzdFNoaWIxGTAXBgNVBAMTEGlkcC50ZXN0\nc2hpYi5vcmeCAQAwDAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQUFAAOCAQEAjR29PhrCbk8qLN5M\nFfSVk98t3CT9jHZoYxd8QMRLI4j7iYQxXiGJTT1FXs1nd4Rha9un+LqTfeMMYqISdDDI6tv8iNpk\nOAvZZUosVkUo93pv1T0RPz35hcHHYq2yee59HJOco2bFlcsH8JBXRSRrJ3Q7Eut+z9uo80JdGNJ4\n/SJy5UorZ8KazGj16lfJhOBXldgrhppQBb0Nq6HKHguqmwRfJ+WkxemZXzhediAjGeka8nz8Jjwx\npUjAiSWYKLtJhGEaTqCYxCCX2Dw+dOTqUzHOZ7WKv4JXPK5G/Uhr8K/qhmFT2nIQi538n6rVYLeW\nj8Bbnl+ev0peYzxFyF5sQA==_5c425656721b41a6cfa4a9c96225e082https://15661444.ngrok.io/saml2/metadataurn:oasis:names:tc:SAML:2.0:ac:classes:PasswordProtectedTransportmyselfMemberStaffmyself@testshib.orgAnd IMember@testshib.orgStaff@testshib.orgMe Myselfurn:mace:dir:entitlement:common-lib-termsMe Myself And I8F+M9ovyaYNwCId0pVkVsnZYRDo=555-5555") + + err := Verify(cert, doc, DsigOptions{ + XMLID: []XMLIDOption{{ + ElementName: "Assertion", + ElementNamespace: "urn:oasis:names:tc:SAML:2.0:assertion", + AttributeName: "ID", + }}, + }) + c.Assert(err, IsNil) +} diff --git a/xmlenc.go b/xmlenc.go deleted file mode 100644 index 9a0e945..0000000 --- a/xmlenc.go +++ /dev/null @@ -1,215 +0,0 @@ -package xmlsec - -/* -import ( - "bytes" - "crypto/aes" - "crypto/cipher" - "crypto/des" - "crypto/rand" - "crypto/rsa" - "crypto/sha1" - "crypto/x509" - "encoding/base64" - "encoding/pem" - "encoding/xml" - "errors" - "fmt" - "hash" - "io" -) - -type method struct { - Algorithm string `xml:",attr"` -} - -type encryptedData struct { - XMLName string `xml:"http://www.w3.org/2001/04/xmlenc# EncryptedData"` - ID string `xml:"Id,attr"` - Type string `xml:",attr"` - EncryptionMethod method `xml:"EncryptionMethod"` - KeyInfo keyInfo `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo"` - CipherData *cipherData -} - -type keyInfo struct { - XMLName string `xml:"http://www.w3.org/2000/09/xmldsig# KeyInfo"` - EncryptedKey *encryptedKey `xml:"http://www.w3.org/2001/04/xmlenc# EncryptedKey"` - X509Data x509Data `xml:"http://www.w3.org/2000/09/xmldsig# X509Data"` -} - -type encryptedKey struct { - XMLName string `xml:"http://www.w3.org/2001/04/xmlenc# EncryptedKey"` - EncryptionMethod *encryptionMethod - KeyInfo *keyInfo - CipherData *cipherData `xml:"http://www.w3.org/2001/04/xmlenc# CipherData"` -} - -type encryptionMethod struct { - Algorithm string `xml:",attr"` - DigestMethod method `xml:"http://www.w3.org/2000/09/xmldsig# DigestMethod"` -} - -type x509Data struct { - XMLName string `xml:"http://www.w3.org/2000/09/xmldsig# X509Data"` - X509Certificate string -} - -type cipherData struct { - XMLName string `xml:"http://www.w3.org/2001/04/xmlenc# CipherData"` - CipherValue string `xml:"CipherValue"` -} - -var ErrNoEncryptedDataFound = errors.New("no EncryptedData elements found") - -// Decrypt searches the serialized XML document `doc` looking for -// an EncryptedData element. When found, it decrypts the element -// and returns the plaintext of the encrypted section. -// -// Key is a PEM-encoded RSA private key, or a binary TDES key or a -// binary AES key, depending on the encryption type in use. -func Decrypt(key []byte, doc []byte) ([]byte, error) { - decoder := xml.NewDecoder(bytes.NewReader(doc)) - for { - t, err := decoder.Token() - if err == io.EOF { - break - } else if err != nil { - return nil, err - } - - if startElement, ok := t.(xml.StartElement); ok { - if startElement.Name.Space == "http://www.w3.org/2001/04/xmlenc#" && startElement.Name.Local == "EncryptedData" { - d := encryptedData{} - if err := decoder.DecodeElement(&d, &startElement); err != nil { - return nil, err - } - - plaintext, err := decryptEncryptedData(key, &d) - if err != nil { - return nil, err - } - - return plaintext, nil - } - } - } - return nil, ErrNoEncryptedDataFound -} - -// decryptEncryptedData decrypts the EncryptedData element and returns the -// plaintext. -func decryptEncryptedData(key []byte, d *encryptedData) ([]byte, error) { - if d.KeyInfo.EncryptedKey != nil { - var err error - key, err = decryptEncryptedKey(key, d.KeyInfo.EncryptedKey) - if err != nil { - return nil, err - } - } - - iv := []byte{} - ciphertext, err := base64.StdEncoding.DecodeString(d.CipherData.CipherValue) - if err != nil { - return nil, err - } - - var blockCipher cipher.Block - switch d.EncryptionMethod.Algorithm { - case "http://www.w3.org/2001/04/xmlenc#tripledes-cbc": - blockCipher, err = des.NewTripleDESCipher(key) - if err != nil { - return nil, err - } - iv = ciphertext[:des.BlockSize] - ciphertext = ciphertext[des.BlockSize:] - - case "http://www.w3.org/2001/04/xmlenc#aes128-cbc", - "http://www.w3.org/2001/04/xmlenc#aes192-cbc", - "http://www.w3.org/2001/04/xmlenc#aes256-cbc": - blockCipher, err = aes.NewCipher(key) - if err != nil { - return nil, err - } - iv = ciphertext[:aes.BlockSize] - ciphertext = ciphertext[aes.BlockSize:] - - default: - return nil, fmt.Errorf("unsupported encryption method: %s", d.EncryptionMethod.Algorithm) - } - - mode := cipher.NewCBCDecrypter(blockCipher, iv) - - plaintext := make([]byte, len(ciphertext)) - mode.CryptBlocks(plaintext, ciphertext) - - // Remove any padding from the end of the message. - // - // Per http://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html - // On decryption, just take the last byte and, after sanity checking - // it, strip that many bytes from the end of the decrypted cipher text. - paddingByteCount := int(plaintext[len(plaintext)-1]) - if paddingByteCount < 1 || paddingByteCount > len(plaintext) || paddingByteCount > blockCipher.BlockSize() { - return nil, fmt.Errorf("invalid padding") - } - plaintext = plaintext[:len(plaintext)-paddingByteCount] - - return plaintext, nil -} - -// decryptEncryptedKey returns the plaintext version of the EncryptedKey which is -// encrypted using RSA-PKCS1v15 or RSA-OAEP-MGF1P and assuming the `key` is -// a PEM-encoded RSA private key. -func decryptEncryptedKey(key []byte, encryptedKey *encryptedKey) ([]byte, error) { - // All the supported encryption schemes are based on RSA, so `key` must be an - // RSA key. (c.f. http://www.w3.org/TR/2002/REC-xmlenc-core-20021210/Overview.html - // in the "Key Transport" section) - pemBlock, _ := pem.Decode(key) - if pemBlock == nil { - return nil, fmt.Errorf("Cannot parse key as PEM encoded RSA private key") - } - rsaPriv, err := x509.ParsePKCS1PrivateKey(pemBlock.Bytes) - if err != nil { - return nil, err - } - - // The only supported/required algorithm is SHA1 - // (c.f. http://www.w3.org/TR/2001/PR-xmldsig-core-20010820/ section "Algorithms") - // - // TODO(ross): if RSA-PKCS1v15 is used, do we need to specify the digest algorithm? - var hashFunc hash.Hash - switch encryptedKey.EncryptionMethod.DigestMethod.Algorithm { - case "http://www.w3.org/2000/09/xmldsig#sha1": - hashFunc = sha1.New() - default: - return nil, fmt.Errorf("unsupported digest method: %s", - encryptedKey.EncryptionMethod.DigestMethod.Algorithm) - } - - sessionKeyCiphertext, err := base64.StdEncoding.DecodeString(encryptedKey.CipherData.CipherValue) - if err != nil { - return nil, err - } - - var sessionKeyPlaintext []byte - switch encryptedKey.EncryptionMethod.Algorithm { - case "http://www.w3.org/2001/04/xmlenc#rsa-1_5": - sessionKeyPlaintext, err = rsa.DecryptPKCS1v15(rand.Reader, rsaPriv, - sessionKeyCiphertext) - if err != nil { - return nil, err - } - case "http://www.w3.org/2001/04/xmlenc#rsa-oaep-mgf1p": - sessionKeyPlaintext, err = rsa.DecryptOAEP(hashFunc, rand.Reader, - rsaPriv, sessionKeyCiphertext, nil) - if err != nil { - return nil, err - } - default: - return nil, fmt.Errorf("unsupported encryption method: %s", - encryptedKey.EncryptionMethod.Algorithm) - } - - return sessionKeyPlaintext, nil -} -*/ diff --git a/xmlsec.go b/xmlsec.go new file mode 100644 index 0000000..426a67c --- /dev/null +++ b/xmlsec.go @@ -0,0 +1,151 @@ +package xmlsec + +import ( + "errors" + "unsafe" +) + +// Note: on mac you need: +// brew install libxmlsec1 libxml2 +// brew link libxml2 --force + +// #cgo pkg-config: xmlsec1 +// #include +// #include +// #include +// #include +// #include +// #include +import "C" + +// #cgo pkg-config: libxml-2.0 +// #include +// #include +// #include +// +// // xmlFree is a macro, so we need to wrap it in order to be able to call +// // it from go code. +// static inline void MY_xmlFree(void *p) { +// xmlFree(p); +// } +import "C" + +// void onError_cgo(char *file, int line, char *funcName, char *errorObject, char *errorSubject, int reason, char *msg); +import "C" + +func init() { + C.xmlInitParser() + + if rv := C.xmlSecInit(); rv < 0 { + panic("xmlsec failed to initialize") + } + if rv := C.xmlSecCryptoAppInit(nil); rv < 0 { + panic("xmlsec crypto initialization failed.") + } + if rv := C.xmlSecCryptoInit(); rv < 0 { + panic("xmlsec crypto initialization failed.") + } + + C.xmlSecErrorsSetCallback((C.xmlSecErrorsCallback)(unsafe.Pointer(C.onError_cgo))) +} + +func newDoc(buf []byte) (*C.xmlDoc, error) { + ctx := C.xmlCreateMemoryParserCtxt((*C.char)(unsafe.Pointer(&buf[0])), + C.int(len(buf))) + if ctx == nil { + return nil, errors.New("error creating parser") + } + defer C.xmlFreeParserCtxt(ctx) + + //C.xmlCtxtUseOptions(ctx, C.int(p.Options)) + C.xmlParseDocument(ctx) + + if ctx.wellFormed == C.int(0) { + return nil, errors.New("malformed XML") + } + + doc := ctx.myDoc + if doc == nil { + return nil, errors.New("parse failed") + } + + return doc, nil +} + +func newDoc2(buf []byte, opts DsigOptions) (*C.xmlDoc, error) { + ctx := C.xmlCreateMemoryParserCtxt((*C.char)(unsafe.Pointer(&buf[0])), + C.int(len(buf))) + if ctx == nil { + return nil, errors.New("error creating parser") + } + defer C.xmlFreeParserCtxt(ctx) + + //C.xmlCtxtUseDsigOptions(ctx, C.int(p.DsigOptions)) + C.xmlParseDocument(ctx) + + if ctx.wellFormed == C.int(0) { + return nil, errors.New("malformed XML") + } + + doc := ctx.myDoc + if doc == nil { + return nil, errors.New("parse failed") + } + + for _, idattr := range opts.XMLID { + addIDAttr(C.xmlDocGetRootElement(doc), + idattr.AttributeName, idattr.ElementName, idattr.ElementNamespace) + } + return doc, nil +} + +func addIDAttr(node *C.xmlNode, attrName, nodeName, nsHref string) { + // process children first because it does not matter much but does simplify code + cur := C.xmlSecGetNextElementNode(node.children) + for { + if cur == nil { + break + } + addIDAttr(cur, attrName, nodeName, nsHref) + cur = C.xmlSecGetNextElementNode(cur.next) + } + + if C.GoString((*C.char)(unsafe.Pointer(node.name))) != nodeName { + return + } + if nsHref != "" && node.ns != nil && C.GoString((*C.char)(unsafe.Pointer(node.ns.href))) != nsHref { + return + } + + // the attribute with name equal to attrName should exist + for attr := node.properties; attr != nil; attr = attr.next { + if C.GoString((*C.char)(unsafe.Pointer(attr.name))) == attrName { + id := C.xmlNodeListGetString(node.doc, attr.children, 1) + if id == nil { + continue + } + C.xmlAddID(nil, node.doc, id, attr) + } + } + + return +} +func closeDoc(doc *C.xmlDoc) { + C.xmlFreeDoc(doc) +} + +func dumpDoc(doc *C.xmlDoc) []byte { + var buffer *C.xmlChar + var bufferSize C.int + C.xmlDocDumpMemory(doc, &buffer, &bufferSize) + rv := C.GoStringN((*C.char)(unsafe.Pointer(buffer)), bufferSize) + C.MY_xmlFree(unsafe.Pointer(buffer)) + + // TODO(ross): this is totally nasty un-idiomatic, but I'm + // tired of googling how to copy a []byte from a char* + return []byte(rv) +} + +func constXmlChar(s string) *C.xmlChar { + return (*C.xmlChar)(unsafe.Pointer(C.CString(s))) +}