Skip to content
This repository has been archived by the owner on Apr 11, 2024. It is now read-only.

Debug xml dsig #4

Merged
merged 21 commits into from
Feb 13, 2019
Merged

Debug xml dsig #4

merged 21 commits into from
Feb 13, 2019

Conversation

fisx
Copy link
Collaborator

@fisx fisx commented Feb 12, 2019

These changes make XML signature validation more robust, and also more correct.

Tasks:

  • capture stdout, stderr noise from libxml2 and feed it into an error that is returned;
  • make sure that the signed subtrees are self-contained by applying an extra round of canonicalization;
  • fix test suite (currently: "failed to canonicalize input: xmlReadMemory: illegal operation (Inappropriate ioctl for device)")

doc' <- case mdoc' of
Right x
-> pure x
Left (err :: SomeException)
Copy link

@ChrisPenner ChrisPenner Feb 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It'd be nice to move the SomeException type annotation up into try @SomeException so the exception type stays close to the try and makes it clear that we plan to catch ALL exceptions 😄

Left err -> throwError . SignatureParseError $ show err
Right v -> pure v

signedInfoElem :: BS.ByteString
Copy link

@ChrisPenner ChrisPenner Feb 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Some docstring or comments explaining the magic xPaths would be nice 😄

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Agreed, but i would have to figure out what that code does first... (It's not mine)

$ mapM (`verifyReference` signedSubtree) (signedInfoReference signedInfoTyped)

unless (all isRight referenceChecks) $
throwError . SignatureVerifyBadReferences $ show (signedInfoReference signedInfoTyped, referenceChecks)

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If there's a left in the referenceChecks should we possibly sequence it to collect the error out? Or is it more descriptive to print everything out like this?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It's a list of Eithers, and I want to keep track of how many errors there are, and which precisely.

I agree it looks weird, but I can't think of a better way to do it. Wanna try something and add a commit?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In that case; how about show (signedInfoReference signedInfoTyped, lefts referenceChecks) instead? lefts will just grab all the errors from the list of Eithers

capture' :: String -> IO a -> IO a
capture' actionName action = hCapture [stdout, stderr] action >>= \case
("", !out) -> pure out
(noise, _) -> throwIO . ErrorCall $ actionName <> ": " <> noise

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If any noise on stdout indicates an error; it's probably helpful to have the output of stderr appended here too.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

i think that's what this does, no?

(thanks for the other comments, more changes coming up!)

Copy link

@ChrisPenner ChrisPenner Feb 12, 2019

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ahh; I see! I misunderstood; It looked at a glance that the tuple matched up with [stdout, stderr]; but in hindsight that does't make sense 👍

@ChrisPenner
Copy link

It's all greek to me 🤷‍♂️

Did this not change any behaviour in any of the tests? If that's the case we should almost certainly add some new tests to capture whatever was wrong before this change.

@fisx
Copy link
Collaborator Author

fisx commented Feb 12, 2019

It's all greek to me

Did this not change any behaviour in any of the tests? If that's the case we should almost certainly add some new tests to capture whatever was wrong before this change.

It does make one test fail. See PR description. :-)

To reproduce, run stack test --fast and follow the error.

@fisx
Copy link
Collaborator Author

fisx commented Feb 12, 2019

oh, and:

It's all greek to me

i've stared at this for over a day now, and not for the first time, and i feel the same way. :-). i don't think there is a way to implement xml:dsig though that would make the reader of the code feel any better about the world. that's just how xml standards are.

@fisx
Copy link
Collaborator Author

fisx commented Feb 12, 2019

xmlReadMemory: illegal operation (Inappropriate ioctl for device)

i think i know what's going on here.

Since libxml2 doesn't return errors, but spills them on stdout, stderr, I use hCapture that reads those into a string and returns it with together with the value.

hCapture seems to change the type of the file handle (from what to what?). libxml2 not only spills stuff on stderr, but also performs a ioctl operation on stderr (or stdout) that is supported before hCapture, but not after. hence, ENOTTY.

The first solution I can think of is to trap and ignore this error c14n.

I think this test had some issue with whitespace being changed
after signing, and canonicalization does not touch whitespace
that much.  I am removing it because it is very likely that this
is the issue, and very hard to robustly confirm it.
@fisx fisx changed the title [WIP] debug xml dsig Debug xml dsig Feb 13, 2019
@fisx
Copy link
Collaborator Author

fisx commented Feb 13, 2019

ready for review!

--
-- TODO: change this function to return 'HXT.XmlTrees' and replace 'samlToDoc' with it.
samlToDoc' :: XP.XmlPickler a => a -> HXT.XmlTree
samlToDoc' = head . getChildren . head

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

samlToDoc' = head . getChildren . samlToDoc ?

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Or do you want it to remain like it is so that it would be easier to get rid of samlToDoc in the future?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

yes and yes.

@@ -302,11 +306,6 @@ examples = zipWith ($) xs [1..]
where xs :: [Int -> VerifyExample]
xs =
[ VerifyExample
"<ds:KeyInfo xmlns:ds=\"http://www.w3.org/2000/09/xmldsig#\"><ds:X509Data><ds:X509Certificate>MIIDpDCCAoygAwIBAgIGAWOMMryDMA0GCSqGSIb3DQEBCwUAMIGSMQswCQYDVQQGEwJVUzETMBEGA1UECAwKQ2FsaWZvcm5pYTEWMBQGA1UEBwwNU2FuIEZyYW5jaXNjbzENMAsGA1UECgwET2t0YTEUMBIGA1UECwwLU1NPUHJvdmlkZXIxEzARBgNVBAMMCmRldi02MDc2NDgxHDAaBgkqhkiG9w0BCQEWDWluZm9Ab2t0YS5jb20wHhcNMTgwNTIzMDg1MTA1WhcNMjgwNTIzMDg1MjA1WjCBkjELMAkGA1UEBhMCVVMxEzARBgNVBAgMCkNhbGlmb3JuaWExFjAUBgNVBAcMDVNhbiBGcmFuY2lzY28xDTALBgNVBAoMBE9rdGExFDASBgNVBAsMC1NTT1Byb3ZpZGVyMRMwEQYDVQQDDApkZXYtNjA3NjQ4MRwwGgYJKoZIhvcNAQkBFg1pbmZvQG9rdGEuY29tMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEA2HkpOuMhVFUCptrVB/Zm36cuFM+YMQjKdtqEoBJDLbtSbb7uFuvm5rMJ+1VSK5GKAM/Bec5WXTE2WMkifK5JaGOLS7q8+pgiWmqKE3KHMUmLAioe/1jzHkCobxis0FIVhyarRY97w0VMbDGzhPiU7pEopYpicJBzRL2UrzR+PebGgllvnaPzlg8ePtr9/xMv0QTJlYEyCctO4vT5Qa5Xlfek3Ox5yMJM1JPXzn7yuJN5R/Nf8jFprsdBSxNMzkcTRFGy8as2GCt/Xh9H+ef4CxSgRK5UXcUCrb5YMnBehEp2YiuWtw8QsGRR8elgnF3Uw9J2xEDkZIhurPy8OYmGNQIDAQABMA0GCSqGSIb3DQEBCwUAA4IBAQA7kxxg2aVjo7Oml83bUWk4UtaQKYMEY74mygG/JV09g1DVMAPAyjaaMFamDSjortKarMQ3ET5tj2DggQBsWQNzsr3iZkmijab8JLwzA2+I1q63S68OaW5uaR5iMR8zZCTh/fWWYqa1AP64XeGHp+RLGfbp/eToNfkQWu7fH2QtDMOeLe5VmIV9pOFHnySszoR/epMd3sdDLVgmz4qbrMTBWD+5rxWdYS2glmRXl7IIQHrdBTRMll7S6ks5prqKFTwfPvZVrTnzD83a39wl2jBJhOQLjmSfSwP9H0YFNb/NRaDbSDS7BPuAlotZsaPZIN95tu+t9wmFwdxcVG/9q/Vu</ds:X509Certificate></ds:X509Data></ds:KeyInfo>"

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why was this removed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

see commit message.

xmlReadMemory p (fromIntegral l) nullPtr nullPtr (#{const XML_PARSE_NOENT} .|. #{const XML_PARSE_DTDLOAD} .|. #{const XML_PARSE_DTDATTR} .|. #{const XML_PARSE_NONET} .|. #{const XML_PARSE_COMPACT})
newDoc d
resetErrno
let config :: CInt

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Would be nice to have comments for those flags, because it's not obvious from the names what they do.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

it's not my code, and i only touched these to make it slightly easier to read. also, i would argue this information belongs into the libxml2 manual.

SAML2/XML/Signature.hs Outdated Show resolved Hide resolved
@neongreen
Copy link

I can't really vouch for the logic here. Having more tests for happy and unhappy paths would be nice: good signature, good signature but non-canonical encoding, bad signature, missing signature.

Co-Authored-By: fisx <[email protected]>
@fisx
Copy link
Collaborator Author

fisx commented Feb 13, 2019

I can't really vouch for the logic here. Having more tests for happy and unhappy paths would be nice: good signature, good signature but non-canonical encoding, bad signature, missing signature.

i agree, but i won't do it in this PR. note that some of the tests you suggest are in saml2-web-sso (or even in wire-server, i would have to read up on the details).

i will merge this now, if any of the answers i give are not enough please yell and i'll handle that in separate PRs.

@fisx fisx merged commit 6789978 into master Feb 13, 2019
@neongreen
Copy link

neongreen commented Feb 13, 2019 via email

@fisx fisx deleted the fisx-debug-xml-dsig branch February 13, 2019 20:07
fisx added a commit to wireapp/wire-server that referenced this pull request Feb 13, 2019
fisx added a commit to wireapp/wire-server that referenced this pull request Feb 14, 2019
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants