oiweiwei / go-msrpc

The DCE/RPC / MS-RPC Codegen/Client for Go
MIT License
34 stars 1 forks source link

Documentation for gssapi.Mechanism #8

Open rtpt-erikgeiser opened 3 weeks ago

rtpt-erikgeiser commented 3 weeks ago

I'm trying to implement my own authentication mechanism, and I can't figure out whether to use the methods in gssapi.Mechanism or gssapi.MechanismEx and how to implement the wrapping and signing methods.

So far, I managed to get authentication to work by implementing Init using Windows build-in authentication API InitializeSecurityContext. However, I can't figure out how to make the signing and sealing work with MakeSignature/VerifySignature/EncryptMessage/DecryptMessage. I just don't understand what part of the input token has to be encrypted/signed and how the token payloads map to the SecBufferDesc of the Windows API. It would help a lot if there was documentation on how to implement a gssapi.Mechanism.

oiweiwei commented 3 weeks ago

Hello, @rtpt-erikgeiser! I was not anticipating the new authentication mechanism, so it was poorly documented. But, I can give a hint here:

gssapi.Mechanism and gssapi.MechanismEx differ only in a way of parameters they accept (which is Token and TokenEx). And here the only difference is Token contains single payload buffer and TokenEx contains a list of payloads.

From RPC perspective, MechanismEx is what you need to implement (gssapi.Mechansim is rather generic GSSAPI implementation which can be used for some other purpose), this is how the RPC constructs the TokenEx:

https://github.com/oiweiwei/go-msrpc/blob/main/dcerpc/security.go#L355-L375

I'm not familiar with SSPI winapi, but I've chanced to look at heimdal code for SSP, and it resembles the SecBufferDesc in some way. First of all, in TokenEx we have 3 buffers, in my implementation I use flags like gssapi.Integrity / gssapi.Confidentiality to guide the implemented SSPs what should be included into the signature (integrity is set) and what should be in-place encrypted (Confidentiality is set).

However, in reality these 3 buffers have dedicated meaning, that is Header, Data and Trailer. So in your case, when you implement MakeSignatureEx and retrieve the TokenEx with 3 payloads, you should map them into SecBufferDesc in following way:

i = 0
// add header if header signing is enabled 
if TokenEx.Payloads[0].Capabilities.IsSet(gssapi.Integrity)
    Buffer[i] = {BufferType: SECBUFFER_STREAM_HEADER | SECBUFFER_READONLY_WITH_CHECKSUM (?), Buffer: TokenEx.Payloads[0].Payload}
    i++

// add data.
Buffer[i] = {BufferType: SECBUFFER_DATA, Buffer: TokenEx.Payloads[1].Payload}
i++

// add security trailer if header-signing is enabled
if TokenEx.Payloads[2].Capabilities.IsSet(gssapi.Integrity)
    Buffer[i] = {BufferType: SECBUFFER_STREAM_TRAILER | SECBUFFER_READONLY_WITH_CHECKSUM (?), Buffer: TokenEx.Payload[2].Payload}

// UPD: i guess buffer must be allocated to return the Signature:
i++
Buffer[i] = {BufferType: SECBUFFER_TOKEN, Buffer: make([]byte, ???)}

For EncryptData I guess it will be the same. I'm not sure where tokEx.Signature should go for verify checksum and others (should it be in STREAM_TRAILER, or in the end of DATA buffer? Looking at the examples (https://learn.microsoft.com/en-us/windows/win32/secauthn/verifying-a-message), tokEx.Signature should be placed into dedicated buffer called SECBUFFER_TOKEN, like:

i++
Buffer[i] = {BufferType: SECBUFFER_TOKEN, Buffer: TokenEx.Signature}
rtpt-erikgeiser commented 1 week ago

Sorry for the late response and thank you for your detailed reply. I will be able to try your suggestions out soon, but I was wondering about sequence numbers that have to be passed to the SSPI APIs.

As far as I am aware, sequence numbers are normally specified in and tracked by the outer protocol (e.g. SMB). However, it seems like they are tracked inside the auth providers in this library, instead of being passed through a a part of the TokenEx structure. Is this something that could be changed or do you prefer it the way it is now or am not understanding the concepts correctly?

oiweiwei commented 1 week ago

@rtpt-erikgeiser you understand the concept correctly, but:

I've decided to implement it inside Authentifier objects. I guess it's pretty simple just to maintain SeqNo for sender and receiver inside the Authentifier.

you can try with simple model like for NTLM and see how it will work for you. (see examples here: https://github.com/oiweiwei/go-msrpc/blob/main/ssp/ntlm/authentifier.go#L376-L390)