Skip to content

Commit 8ff3619

Browse files
committed
init go-msspi
1 parent b1e1c8d commit 8ff3619

File tree

7 files changed

+302
-1
lines changed

7 files changed

+302
-1
lines changed

.gitmodules

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
[submodule "msspi"]
2+
path = msspi
3+
url = https://github.com/deemru/msspi.git

README.md

+24-1
Original file line numberDiff line numberDiff line change
@@ -1 +1,24 @@
1-
# go-msspi
1+
# go-msspi
2+
3+
[go-msspi](https://github.com/deemru/go-msspi) is an adoption of [msspi](https://github.com/deemru/msspi) to crypto/tls like interface.
4+
5+
## Notice
6+
7+
- This is a demo implementation
8+
- There are very few functions available
9+
10+
## Installation
11+
12+
```bash
13+
git clone https://github.com/deemru/go-msspi --recursive
14+
cd go-msspi/msspi/build_linux
15+
make
16+
cd ../..
17+
go test
18+
```
19+
20+
## Usage
21+
22+
- import "github.com/deemru/go-msspi"
23+
- before: `tls.Client(conn, &tls.Config{})`
24+
- after: `msspi.Client(conn, &tls.Config{})`

msspi

Submodule msspi added at 67d4853

msspi.go

+108
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,108 @@
1+
package msspi
2+
3+
/*
4+
#cgo LDFLAGS: -Lmsspi/build_linux -lmsspi -lstdc++ -lcrypt32
5+
#include "msspi/src/msspi.h"
6+
extern int cgo_msspi_read( void * goPointer, void * buf, int len );
7+
extern int cgo_msspi_write( void * goPointer, void * buf, int len );
8+
MSSPI_HANDLE cgo_msspi_open( void * goPointer ) {
9+
return msspi_open( goPointer, (msspi_read_cb)cgo_msspi_read, (msspi_write_cb)cgo_msspi_write );
10+
}
11+
*/
12+
import "C"
13+
14+
import (
15+
"crypto/tls"
16+
"io"
17+
"net"
18+
"runtime"
19+
"sync"
20+
"unsafe"
21+
22+
"github.com/mattn/go-pointer"
23+
)
24+
25+
// Conn with MSSPI
26+
type Conn struct {
27+
conn net.Conn
28+
tls *tls.Conn
29+
// MSSPI
30+
handle C.MSSPI_HANDLE
31+
rerr error
32+
werr error
33+
isClient bool
34+
goPointer unsafe.Pointer
35+
mu sync.Mutex
36+
}
37+
38+
func (c *Conn) error() (err error) {
39+
state := C.msspi_state(c.handle)
40+
if state&C.MSSPI_ERROR != 0 || state&(C.MSSPI_SENT_SHUTDOWN|C.MSSPI_RECEIVED_SHUTDOWN) != 0 {
41+
err = io.EOF
42+
}
43+
return nil
44+
}
45+
46+
func (c *Conn) Read(b []byte) (int, error) {
47+
n := (int)(C.msspi_read(c.handle, unsafe.Pointer(&b[0]), C.int(len(b))))
48+
if n > 0 {
49+
return n, nil
50+
}
51+
return 0, c.error()
52+
}
53+
54+
func (c *Conn) Write(b []byte) (int, error) {
55+
len := len(b)
56+
sent := 0
57+
for len > 0 {
58+
n := int(C.msspi_write(c.handle, unsafe.Pointer(&b[sent]), C.int(len)))
59+
if n > 0 {
60+
sent += n
61+
len -= n
62+
continue
63+
}
64+
65+
return sent, c.error()
66+
}
67+
return sent, nil
68+
}
69+
70+
// Close with MSSPI
71+
func (c *Conn) Close() (err error) {
72+
if c.handle != nil {
73+
C.msspi_shutdown(c.handle);
74+
pointer.Unref(c.goPointer);
75+
}
76+
return c.conn.Close();
77+
}
78+
79+
// Finalizer with MSSPI
80+
func (c *Conn) Finalizer() {
81+
if c.handle != nil {
82+
C.msspi_close(c.handle)
83+
}
84+
}
85+
86+
// Client with MSSPI
87+
func Client(conn net.Conn, config *tls.Config) *Conn {
88+
c := &Conn{conn: conn, isClient: true}
89+
c.tls = tls.Client(conn, config)
90+
91+
c.goPointer = pointer.Save(c)
92+
c.handle = C.cgo_msspi_open(c.goPointer)
93+
94+
if c.handle != nil {
95+
C.msspi_set_client(c.handle)
96+
runtime.SetFinalizer(c, (*Conn).Finalizer)
97+
} else {
98+
pointer.Unref(c.goPointer)
99+
}
100+
return c
101+
}
102+
103+
// Server with MSSPI (not implemented)
104+
func Server(conn net.Conn, config *tls.Config) *Conn {
105+
c := &Conn{conn: conn, isClient: false}
106+
c.tls = tls.Server(conn, config)
107+
return nil
108+
}

msspi_cgo.go

+77
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,77 @@
1+
package msspi
2+
3+
/*
4+
#include <memory.h> // memcpy
5+
int cgo_msspi_read( void * goPointer, void * buf, int len );
6+
int cgo_msspi_write( void * goPointer, void * buf, int len );
7+
*/
8+
import "C"
9+
10+
import (
11+
"io"
12+
"os"
13+
"unsafe"
14+
15+
"github.com/mattn/go-pointer"
16+
)
17+
18+
//export cgo_msspi_read
19+
func cgo_msspi_read(goPointer, buffer unsafe.Pointer, length C.int) C.int {
20+
c := pointer.Restore(goPointer).(*Conn)
21+
if c == nil {
22+
return 0
23+
}
24+
25+
b := make([]byte, length)
26+
n, err := c.conn.Read(b)
27+
28+
// Read can be made to time out and return a net.Error with Timeout() == true
29+
// after a fixed time limit; see SetDeadline and SetReadDeadline.
30+
31+
if n > 0 {
32+
c.rerr = nil
33+
C.memcpy(buffer, unsafe.Pointer(&b[0]), C.size_t(n))
34+
b = C.GoBytes(buffer, C.int(n))
35+
return C.int(n)
36+
}
37+
38+
// RFC 8446, Section 6.1 suggests that EOF without an alertCloseNotify
39+
// is an error, but popular web sites seem to do this, so we accept it
40+
// if and only if at the record boundary.
41+
if err == io.ErrUnexpectedEOF {
42+
err = io.EOF
43+
}
44+
c.rerr = err
45+
if os.IsTimeout(err) {
46+
return -1
47+
}
48+
return 0
49+
}
50+
51+
//export cgo_msspi_write
52+
func cgo_msspi_write(goPointer, buffer unsafe.Pointer, length C.int) C.int {
53+
c := pointer.Restore(goPointer).(*Conn)
54+
if c == nil {
55+
return 0
56+
}
57+
58+
b := C.GoBytes(buffer, length)
59+
n, err := c.conn.Write(b)
60+
61+
if n > 0 {
62+
c.werr = nil
63+
return C.int(n)
64+
}
65+
66+
// RFC 8446, Section 6.1 suggests that EOF without an alertCloseNotify
67+
// is an error, but popular web sites seem to do this, so we accept it
68+
// if and only if at the record boundary.
69+
if err == io.ErrUnexpectedEOF {
70+
err = io.EOF
71+
}
72+
c.werr = err
73+
if os.IsTimeout(err) {
74+
return -1
75+
}
76+
return 0
77+
}

msspi_conn.go

+36
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
package msspi
2+
3+
import (
4+
"net"
5+
"time"
6+
)
7+
8+
// LocalAddr returns the local network address.
9+
func (c *Conn) LocalAddr() net.Addr {
10+
return c.conn.LocalAddr()
11+
}
12+
13+
// RemoteAddr returns the remote network address.
14+
func (c *Conn) RemoteAddr() net.Addr {
15+
return c.conn.RemoteAddr()
16+
}
17+
18+
// SetDeadline sets the read and write deadlines associated with the connection.
19+
// A zero value for t means Read and Write will not time out.
20+
// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
21+
func (c *Conn) SetDeadline(t time.Time) error {
22+
return c.conn.SetDeadline(t)
23+
}
24+
25+
// SetReadDeadline sets the read deadline on the underlying connection.
26+
// A zero value for t means Read will not time out.
27+
func (c *Conn) SetReadDeadline(t time.Time) error {
28+
return c.conn.SetReadDeadline(t)
29+
}
30+
31+
// SetWriteDeadline sets the write deadline on the underlying connection.
32+
// A zero value for t means Write will not time out.
33+
// After a Write has timed out, the TLS state is corrupt and all future writes will return the same error.
34+
func (c *Conn) SetWriteDeadline(t time.Time) error {
35+
return c.conn.SetWriteDeadline(t)
36+
}

msspi_test.go

+53
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
package msspi
2+
3+
import (
4+
"crypto/tls"
5+
"fmt"
6+
"net"
7+
"strings"
8+
"testing"
9+
"time"
10+
)
11+
12+
func TestMsspiClient(t *testing.T) {
13+
for i := 0; i < 2; i++ {
14+
conn, err := net.DialTimeout("tcp", fmt.Sprintf("%s:%d", "tls.cryptopro.ru", 443), 2*time.Second)
15+
if err != nil {
16+
t.Fatalf("Unexpected error on dial: %v", err)
17+
}
18+
defer conn.Close()
19+
20+
var tlsConn net.Conn
21+
if i == 0 {
22+
// crypto/tls
23+
tlsConn = tls.Client(conn, &tls.Config{InsecureSkipVerify: true})
24+
} else {
25+
// github.com/deemru/go-msspi
26+
tlsConn = /*msspi.*/ Client(conn, &tls.Config{InsecureSkipVerify: true})
27+
}
28+
defer tlsConn.Close()
29+
30+
wbuf := []byte("GET / HTTP/1.1\r\nHost: tls.cryptopro.ru\r\n\r\n")
31+
if wlen, err := tlsConn.Write(wbuf); wlen != len(wbuf) || err != nil {
32+
t.Fatalf("Error sending: %v", err)
33+
}
34+
35+
rbuf := make([]byte, 16384)
36+
if rlen, err := tlsConn.Read(rbuf); rlen == 0 || err != nil {
37+
t.Fatalf("Error reading: %v", err)
38+
} else {
39+
s := string(rbuf[:rlen])
40+
ms := "ssl_cipher</td><td class=\"wr\"><b>"
41+
me := "</b>"
42+
c1 := strings.Index(s, ms)
43+
if c1 == -1 {
44+
t.Fatalf("Marker not found")
45+
}
46+
c2 := strings.Index(s[c1:], me)
47+
if c2 == -1 {
48+
t.Fatalf("Marker not found")
49+
}
50+
fmt.Printf("%v) Cipher: %v\n", i+1, string(rbuf[c1+len(ms):c1+c2]))
51+
}
52+
}
53+
}

0 commit comments

Comments
 (0)