Skip to content

refactor: deprecate SignedXml.signingKey in favor of SignedXml.publicKey and SignedXml.privateKey #317

Description

@LoneRifle

Originally posted by @djaqua in #295 (comment)

So, I'm late to the party, but I think I have caught up with what's happening here. Bare with me -- read this slowly because this should clear up a lot of confusion. I know I can be a bit long-winded, but I promise this will shed some light on the madness.

Private Keys and Public Keys

@shunkica , @cjbarth , @LoneRifle I ended up having to learn a lot more about digital signatures than I ever really wanted to learn in order to make a PR a few months ago. According to the Wikipedia on Digital Signatures (and you can verify this on the command line with openssl):

Two main properties are required. First, the authenticity of a signature generated from a fixed message and fixed private key can be verified by using the corresponding public key. Secondly, it should be computationally infeasible to generate a valid signature for a party without knowing that party's private key.

So this means that either a private key or a public key (i.e. a certificate) can be used to generate the signature itself. The API specs that dragged me into this project in the first place even say that the service will generate a signature in the response based on the public key I use in my request (e.g. a BinarySecurityToken from the WS-Security standard)

Current xml-crypto Implementation

So, with that understanding of the digital signatures, lets look at the two ways that SignedXml uses signingKey

  1. generate a signature using a private key (e.g. line 897 in signed-xml.js)
  2. validate a signature using a public key/certificate (e.g. line 407 in signed-xml.js)

When generating a signature, one need only set SignedXml.signingKey to the Private Key. Optionally, an implementation of KeyInfoProvider that implements getKeyInfo by returning a valid formatting of the public key can be used in order to transmit the public key. In this case, if you use StringKeyInfo or FileKeyInfo, it doesn't matter what you construct it with since the default implementation of getKeyInfo does nothing with the key parameter

When validating a signature, SignedXml.keyInfoProvider must be an instance of KeyInfoProvider that implements getKey by returning the private key. This means that if you use FileKeyInfo or StrignKeyInfo, you must construct it with the private key.

The Reason for the Confusion

you cannot use the same instance of KeyInfoProvider (regardless of implementation) for both the generation and validation of a signature on the same instance of SignedXml because of line 380. This is because in one context, SignedXml.signingKey is being treated as the Private Key (for generating a signature) and in the other context, SignedXml.signingKey is being treated as the Public Key (for validating a signature).

The solution

  • deprecate SignedXml.signingKey altogether in favor of using SignedXml.publicKey and SignedXml.privateKey -- we may be able to deprecate KeyInfoProvider in favor of something like KeyInfoProviderV2
  • [out-of-scope, to be handled in future issue] implement the Facade that the other guy mentioned on that other thread. I have an idea of how to do this -- whose interested?

Conclusion

Again, sorry for the long explanation, but the situation needs to be understood holistically in order to put KeyInfoProvider issues to bed ... forever. Strange as it may sound, the purpose of KeyInfoProvider is pretty ingenious (@yaronn I actually love this thing even if it causes a lot of problems), but it needs some work.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions