alexbrainman / sspi

Windows SSPI
BSD 3-Clause "New" or "Revised" License
84 stars 27 forks source link

Add MakeSignature and VerifySignature calls #3

Closed bodgit closed 6 years ago

bodgit commented 6 years ago

I'm in the process of making some existing GSSAPI code use your SSPI library on Windows. I've used your Negotiate library to establish a context successfully however I now need to use MakeSignature & VerifySignature and noticed they weren't present.

This PR is the result of me updating syscall.go and running go generate. I'm not quite sure how/where I'm going to use these either adding them somewhere to your Negotiate library or just calling them from my side with the established context but this should be a start.

bodgit commented 6 years ago

I've started trying to use these new calls and I've found I need to call sspi.QueryContextAttributes() with _SECPKG_ATTR_SIZES to work out how large a buffer I need to be able to store the signature I'm about make.

The schannel package has all of the various constants defined as well as functions in schannel/attribute.go to query some of the other _SECPKG_ATTR_* values but AFAIK these can't be called with my negotiate.ClientContext. Do some of these functions perhaps need shuffling about? I was thinking that it might make sense to move the main function to the sspi package and then add thin wrappers to each of the relevant SSP.

For example, define in sspi:

const (
        _SECPKG_ATTR_SIZES = 0
)

type _SecPkgContext_Sizes struct {
       MaxToken        uint32
       MaxSignature    uint32
       BlockSize       uint32
       SecurityTrailer uint32
}

func (c *Context) Sizes() (uint32, uint32, uint32, uint32, error) {
       var s _SecPkgContext_Sizes
       ret := QueryContextAttributes(c.Handle, _SECPKG_ATTR_SIZES, (*byte)(unsafe.Pointer(&s)))
       if ret != SEC_E_OK {
               return 0, 0, 0, 0, ret
       }
       return s.MaxToken, s.MaxSignature, s.BlockSize, s.SecurityTrailer, nil
}

And then in sspi.negotiate just have:

func (c *ClientContext) Sizes() (uint32, uint32, uint32, uint32, error) {
       return sspi.Sizes(c.sctxt)
}

func (c *ServerContext) Sizes() (uint32, uint32, uint32, uint32, error) {
       return sspi.Sizes(c.sctxt)
}

etc.

alexbrainman commented 6 years ago

For example, define in sspi:

const ( _SECPKG_ATTR_SIZES = 0 )

I don't think SECPKG_ATTR_SIZES is part of SSPI. I think it (and others) are part of schannel Microsoft package. Just copy bits that you need into your code. Will that work for you?

Alex

bodgit commented 6 years ago

I don't think SECPKG_ATTR_SIZES is part of SSPI. I think it (and others) are part of schannel Microsoft package.

If you compare the documentation for QueryContextAttributes between say the negotiate version and the schannel version you can see the list of attributes implemented by both. The schannel version for example implements the SECPKG_ATTR_STREAM_SIZES attribute but the negotiate version doesn't, however both implement the SECPKG_ATTR_SIZES attribute. So I think it would make sense to move these to the base SSPI package and then add the wrappers to each security package where that particular attribute is implemented, thankfully the docs should make this straightforward.

Just copy bits that you need into your code. Will that work for you?

Unfortunately golang prohibits me from accessing the negotiate.ClientContext.sctxt member so I can't do much from outside of your SSPI package.

Happy to extend this PR if you want.

bodgit commented 6 years ago

This last commit adds everything that I needed to get things working. I added an exported NewSecBufferDesc function based on the unexported version in the schannel package as that seemed useful to have and added MakeSignature and VerifySignature functions to the negotiate package, (according to the docs this isn't supported by the Schannel SSP so I've not added them there).

The library that I've written is here: https://github.com/bodgit/tsig which allows me to do GSS-TSIG signed dynamic DNS updates (primarily to Windows servers) from either Windows clients using SSPI, or from non-Windows clients using GSSAPI). The negotiate handshake itself is performed over DNS using TKEY records.

bodgit commented 6 years ago

Fixed. Incidentally, I noticed the testContextExpiry test always fails for me; the context expiry always seems to be around 5 minutes rather than longer than an hour.

alexbrainman commented 6 years ago

Incidentally, I noticed the testContextExpiry test always fails for me; the context expiry always seems to be around 5 minutes rather than longer than an hour.

I don't have much free time to spend investigating bugs in this packages, but changes are welcome.

Alex