Skip to content

Commit

Permalink
Initial commit
Browse files Browse the repository at this point in the history
  • Loading branch information
djkottmann committed Feb 2, 2017
1 parent f4056e8 commit 04e24f2
Show file tree
Hide file tree
Showing 11 changed files with 1,534 additions and 0 deletions.
112 changes: 112 additions & 0 deletions gss/gss.go
@@ -0,0 +1,112 @@
package gss

import (
"encoding/asn1"
"log"

"github.com/stacktitan/smb/smb/encoder"
)

const SpnegoOid = "1.3.6.1.5.5.2"
const NtLmSSPMechTypeOid = "1.3.6.1.4.1.311.2.2.10"

const GssStateAcceptCompleted = 0
const GssStateAcceptIncomplete = 1
const GssStateReject = 2
const GssStateRequestMic = 3

type NegTokenInitData struct {
MechTypes []asn1.ObjectIdentifier `asn1:"explicit,tag:0"`
ReqFlags asn1.BitString `asn1:"explicit,optional,omitempty,tag:1"`
MechToken []byte `asn1:"explicit,optional,omitempty,tag:2"`
MechTokenMIC []byte `asn1:"explicit,optional,omitempty,tag:3"`
}

type NegTokenInit struct {
OID asn1.ObjectIdentifier
Data NegTokenInitData `asn1:"explicit"`
}

type NegTokenResp struct {
State asn1.Enumerated `asn1:"explicit,optional,omitempty,tag:0"`
SupportedMech asn1.ObjectIdentifier `asn1:"explicit,optional,omitempty,tag:1"`
ResponseToken []byte `asn1:"explicit,optional,omitempty,tag:2"`
MechListMIC []byte `asn1:"explicit,optional,omitempty,tag:3"`
}

// gsswrapped used to force ASN1 encoding to include explicit sequence tags
// Type does not fulfill the BinaryMarshallable interfce and is used only as a
// helper to marshal a NegTokenResp
type gsswrapped struct{ G interface{} }

func NewNegTokenInit() (NegTokenInit, error) {
oid, err := ObjectIDStrToInt(SpnegoOid)
if err != nil {
return NegTokenInit{}, err
}
ntlmoid, err := ObjectIDStrToInt(NtLmSSPMechTypeOid)
if err != nil {
return NegTokenInit{}, err
}
return NegTokenInit{
OID: oid,
Data: NegTokenInitData{
MechTypes: []asn1.ObjectIdentifier{ntlmoid},
ReqFlags: asn1.BitString{},
MechToken: []byte{},
MechTokenMIC: []byte{},
},
}, nil
}

func NewNegTokenResp() (NegTokenResp, error) {
return NegTokenResp{}, nil
}

func (n *NegTokenInit) MarshalBinary(meta *encoder.Metadata) ([]byte, error) {
buf, err := asn1.Marshal(*n)
if err != nil {
log.Panicln(err)
return nil, err
}

// When marshalling struct, asn1 uses 30 (sequence) tag by default.
// Override to set 60 (application) to remain consistent with GSS/SMB
buf[0] = 0x60
return buf, nil
}

func (n *NegTokenInit) UnmarshalBinary(buf []byte, meta *encoder.Metadata) error {
data := NegTokenInit{}
if _, err := asn1.UnmarshalWithParams(buf, &data, "application"); err != nil {
return err
}
*n = data
return nil
}

func (r *NegTokenResp) MarshalBinary(meta *encoder.Metadata) ([]byte, error) {
// Oddities in Go's ASN1 package vs SMB encoding mean we have to wrap our
// struct in another struct to ensure proper tags and lengths are added
// to encoded data
wrapped := &gsswrapped{*r}
return wrapped.MarshalBinary(meta)
}

func (r *NegTokenResp) UnmarshalBinary(buf []byte, meta *encoder.Metadata) error {
data := NegTokenResp{}
if _, err := asn1.UnmarshalWithParams(buf, &data, "explicit,tag:1"); err != nil {
return err
}
*r = data
return nil
}

func (g *gsswrapped) MarshalBinary(meta *encoder.Metadata) ([]byte, error) {
buf, err := asn1.Marshal(*g)
if err != nil {
return nil, err
}
buf[0] = 0xa1
return buf, nil
}
19 changes: 19 additions & 0 deletions gss/oid.go
@@ -0,0 +1,19 @@
package gss

import (
"strconv"
"strings"
)

func ObjectIDStrToInt(oid string) ([]int, error) {
ret := []int{}
tokens := strings.Split(oid, ".")
for _, token := range tokens {
i, err := strconv.Atoi(token)
if err != nil {
return nil, err
}
ret = append(ret, i)
}
return ret, nil
}
41 changes: 41 additions & 0 deletions ntlmssp/crypto.go
@@ -0,0 +1,41 @@
package ntlmssp

import (
"crypto/hmac"
"crypto/md5"
"strings"

"golang.org/x/crypto/md4"
)

func ntowfv1(pass string) []byte {
hash := md4.New()
hash.Write(ToUnicode(pass))
return hash.Sum(nil)
}

func ntowfv2(pass, user, domain string) []byte {
h := hmac.New(md5.New, ntowfv1(pass))
h.Write(ToUnicode(strings.ToUpper(user) + domain))
return h.Sum(nil)
}

func lmowfv2(pass, user, domain string) []byte {
return ntowfv2(pass, user, domain)
}

func ComputeResponseNTLMv2(nthash, lmhash, clientChallenge, serverChallenge, timestamp, serverName []byte) []byte {

temp := []byte{1, 1}
temp = append(temp, 0, 0, 0, 0, 0, 0)
temp = append(temp, timestamp...)
temp = append(temp, clientChallenge...)
temp = append(temp, 0, 0, 0, 0)
temp = append(temp, serverName...)
temp = append(temp, 0, 0, 0, 0)

h := hmac.New(md5.New, nthash)
h.Write(append(serverChallenge, temp...))
ntproof := h.Sum(nil)
return append(ntproof, temp...)
}
2 changes: 2 additions & 0 deletions ntlmssp/crypto_test.go
@@ -0,0 +1,2 @@
package ntlmssp

0 comments on commit 04e24f2

Please sign in to comment.