first commit
commit
a72416672a
@ -0,0 +1 @@
|
|||||||
|
*~
|
@ -0,0 +1,166 @@
|
|||||||
|
GNU LESSER GENERAL PUBLIC LICENSE
|
||||||
|
Version 3, 29 June 2007
|
||||||
|
|
||||||
|
Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
|
||||||
|
Everyone is permitted to copy and distribute verbatim copies
|
||||||
|
of this license document, but changing it is not allowed.
|
||||||
|
|
||||||
|
|
||||||
|
This version of the GNU Lesser General Public License incorporates
|
||||||
|
the terms and conditions of version 3 of the GNU General Public
|
||||||
|
License, supplemented by the additional permissions listed below.
|
||||||
|
|
||||||
|
0. Additional Definitions.
|
||||||
|
|
||||||
|
As used herein, "this License" refers to version 3 of the GNU Lesser
|
||||||
|
General Public License, and the "GNU GPL" refers to version 3 of the GNU
|
||||||
|
General Public License.
|
||||||
|
|
||||||
|
"The Library" refers to a covered work governed by this License,
|
||||||
|
other than an Application or a Combined Work as defined below.
|
||||||
|
|
||||||
|
An "Application" is any work that makes use of an interface provided
|
||||||
|
by the Library, but which is not otherwise based on the Library.
|
||||||
|
Defining a subclass of a class defined by the Library is deemed a mode
|
||||||
|
of using an interface provided by the Library.
|
||||||
|
|
||||||
|
A "Combined Work" is a work produced by combining or linking an
|
||||||
|
Application with the Library. The particular version of the Library
|
||||||
|
with which the Combined Work was made is also called the "Linked
|
||||||
|
Version".
|
||||||
|
|
||||||
|
The "Minimal Corresponding Source" for a Combined Work means the
|
||||||
|
Corresponding Source for the Combined Work, excluding any source code
|
||||||
|
for portions of the Combined Work that, considered in isolation, are
|
||||||
|
based on the Application, and not on the Linked Version.
|
||||||
|
|
||||||
|
The "Corresponding Application Code" for a Combined Work means the
|
||||||
|
object code and/or source code for the Application, including any data
|
||||||
|
and utility programs needed for reproducing the Combined Work from the
|
||||||
|
Application, but excluding the System Libraries of the Combined Work.
|
||||||
|
|
||||||
|
1. Exception to Section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
You may convey a covered work under sections 3 and 4 of this License
|
||||||
|
without being bound by section 3 of the GNU GPL.
|
||||||
|
|
||||||
|
2. Conveying Modified Versions.
|
||||||
|
|
||||||
|
If you modify a copy of the Library, and, in your modifications, a
|
||||||
|
facility refers to a function or data to be supplied by an Application
|
||||||
|
that uses the facility (other than as an argument passed when the
|
||||||
|
facility is invoked), then you may convey a copy of the modified
|
||||||
|
version:
|
||||||
|
|
||||||
|
a) under this License, provided that you make a good faith effort to
|
||||||
|
ensure that, in the event an Application does not supply the
|
||||||
|
function or data, the facility still operates, and performs
|
||||||
|
whatever part of its purpose remains meaningful, or
|
||||||
|
|
||||||
|
b) under the GNU GPL, with none of the additional permissions of
|
||||||
|
this License applicable to that copy.
|
||||||
|
|
||||||
|
3. Object Code Incorporating Material from Library Header Files.
|
||||||
|
|
||||||
|
The object code form of an Application may incorporate material from
|
||||||
|
a header file that is part of the Library. You may convey such object
|
||||||
|
code under terms of your choice, provided that, if the incorporated
|
||||||
|
material is not limited to numerical parameters, data structure
|
||||||
|
layouts and accessors, or small macros, inline functions and templates
|
||||||
|
(ten or fewer lines in length), you do both of the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the object code that the
|
||||||
|
Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the object code with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
4. Combined Works.
|
||||||
|
|
||||||
|
You may convey a Combined Work under terms of your choice that,
|
||||||
|
taken together, effectively do not restrict modification of the
|
||||||
|
portions of the Library contained in the Combined Work and reverse
|
||||||
|
engineering for debugging such modifications, if you also do each of
|
||||||
|
the following:
|
||||||
|
|
||||||
|
a) Give prominent notice with each copy of the Combined Work that
|
||||||
|
the Library is used in it and that the Library and its use are
|
||||||
|
covered by this License.
|
||||||
|
|
||||||
|
b) Accompany the Combined Work with a copy of the GNU GPL and this license
|
||||||
|
document.
|
||||||
|
|
||||||
|
c) For a Combined Work that displays copyright notices during
|
||||||
|
execution, include the copyright notice for the Library among
|
||||||
|
these notices, as well as a reference directing the user to the
|
||||||
|
copies of the GNU GPL and this license document.
|
||||||
|
|
||||||
|
d) Do one of the following:
|
||||||
|
|
||||||
|
0) Convey the Minimal Corresponding Source under the terms of this
|
||||||
|
License, and the Corresponding Application Code in a form
|
||||||
|
suitable for, and under terms that permit, the user to
|
||||||
|
recombine or relink the Application with a modified version of
|
||||||
|
the Linked Version to produce a modified Combined Work, in the
|
||||||
|
manner specified by section 6 of the GNU GPL for conveying
|
||||||
|
Corresponding Source.
|
||||||
|
|
||||||
|
1) Use a suitable shared library mechanism for linking with the
|
||||||
|
Library. A suitable mechanism is one that (a) uses at run time
|
||||||
|
a copy of the Library already present on the user's computer
|
||||||
|
system, and (b) will operate properly with a modified version
|
||||||
|
of the Library that is interface-compatible with the Linked
|
||||||
|
Version.
|
||||||
|
|
||||||
|
e) Provide Installation Information, but only if you would otherwise
|
||||||
|
be required to provide such information under section 6 of the
|
||||||
|
GNU GPL, and only to the extent that such information is
|
||||||
|
necessary to install and execute a modified version of the
|
||||||
|
Combined Work produced by recombining or relinking the
|
||||||
|
Application with a modified version of the Linked Version. (If
|
||||||
|
you use option 4d0, the Installation Information must accompany
|
||||||
|
the Minimal Corresponding Source and Corresponding Application
|
||||||
|
Code. If you use option 4d1, you must provide the Installation
|
||||||
|
Information in the manner specified by section 6 of the GNU GPL
|
||||||
|
for conveying Corresponding Source.)
|
||||||
|
|
||||||
|
5. Combined Libraries.
|
||||||
|
|
||||||
|
You may place library facilities that are a work based on the
|
||||||
|
Library side by side in a single library together with other library
|
||||||
|
facilities that are not Applications and are not covered by this
|
||||||
|
License, and convey such a combined library under terms of your
|
||||||
|
choice, if you do both of the following:
|
||||||
|
|
||||||
|
a) Accompany the combined library with a copy of the same work based
|
||||||
|
on the Library, uncombined with any other library facilities,
|
||||||
|
conveyed under the terms of this License.
|
||||||
|
|
||||||
|
b) Give prominent notice with the combined library that part of it
|
||||||
|
is a work based on the Library, and explaining where to find the
|
||||||
|
accompanying uncombined form of the same work.
|
||||||
|
|
||||||
|
6. Revised Versions of the GNU Lesser General Public License.
|
||||||
|
|
||||||
|
The Free Software Foundation may publish revised and/or new versions
|
||||||
|
of the GNU Lesser General Public License from time to time. Such new
|
||||||
|
versions will be similar in spirit to the present version, but may
|
||||||
|
differ in detail to address new problems or concerns.
|
||||||
|
|
||||||
|
Each version is given a distinguishing version number. If the
|
||||||
|
Library as you received it specifies that a certain numbered version
|
||||||
|
of the GNU Lesser General Public License "or any later version"
|
||||||
|
applies to it, you have the option of following the terms and
|
||||||
|
conditions either of that published version or of any later version
|
||||||
|
published by the Free Software Foundation. If the Library as you
|
||||||
|
received it does not specify a version number of the GNU Lesser
|
||||||
|
General Public License, you may choose any version of the GNU Lesser
|
||||||
|
General Public License ever published by the Free Software Foundation.
|
||||||
|
|
||||||
|
If the Library as you received it specifies that a proxy can decide
|
||||||
|
whether future versions of the GNU Lesser General Public License shall
|
||||||
|
apply, that proxy's public statement of acceptance of any version is
|
||||||
|
permanent authorization for you to choose that version for the
|
||||||
|
Library.
|
||||||
|
|
@ -0,0 +1,7 @@
|
|||||||
|
gnutls
|
||||||
|
=====
|
||||||
|
|
||||||
|
This is a gnutls binding for golang.
|
||||||
|
|
||||||
|
This library is just work, a lot things need to be done.
|
||||||
|
|
@ -0,0 +1,47 @@
|
|||||||
|
#ifndef _GNUTLS_H
|
||||||
|
#define _GNUTLS_H
|
||||||
|
#include <gnutls/gnutls.h>
|
||||||
|
#include <gnutls/crypto.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdio.h>
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
struct session
|
||||||
|
{
|
||||||
|
gnutls_session_t session;
|
||||||
|
gnutls_certificate_credentials_t xcred;
|
||||||
|
int handshake;
|
||||||
|
void *data;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int DataRead(void *, char *, int);
|
||||||
|
extern int DataWrite(void *, char *, int);
|
||||||
|
extern int DataTimeoutPull(void *, int);
|
||||||
|
|
||||||
|
struct session *init_client_session();
|
||||||
|
struct session *init_server_session();
|
||||||
|
|
||||||
|
int pull_timeout_function(gnutls_transport_ptr_t ptr, unsigned int ms);
|
||||||
|
ssize_t pull_function(gnutls_transport_ptr_t ptr, void *data, size_t len);
|
||||||
|
ssize_t push_function(gnutls_transport_ptr_t ptr, const void *data, size_t len);
|
||||||
|
|
||||||
|
void set_data(struct session *sess, size_t data);
|
||||||
|
void set_servername(struct session *sess, char *servername, int namelen);
|
||||||
|
int handshake(struct session *sess);
|
||||||
|
int set_callback(struct session *sess);
|
||||||
|
int set_keyfile(struct session *, char *, char *);
|
||||||
|
|
||||||
|
int write_application_data(struct session *sess, char *data, int datalen);
|
||||||
|
int read_application_data(struct session *sess, char *data, int buflen);
|
||||||
|
|
||||||
|
void session_destroy(struct session *);
|
||||||
|
|
||||||
|
gnutls_cipher_hd_t new_cipher(int cipher_type, char *key, int keylen, char *iv, int ivlen);
|
||||||
|
|
||||||
|
gnutls_hash_hd_t new_hash(int t);
|
||||||
|
|
||||||
|
int get_hash_len(int);
|
||||||
|
int cipher_get_block_size(int);
|
||||||
|
int cipher_get_iv_size(int);
|
||||||
|
|
||||||
|
#endif
|
@ -0,0 +1,113 @@
|
|||||||
|
package gnutls
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include "_gnutls.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
GNUTLS_CIPHER_AES_128_CBC = 4
|
||||||
|
GNUTLS_CIPHER_AES_256_CBC = 5
|
||||||
|
GNUTLS_CIPHER_ARCFOUR_40 = 6
|
||||||
|
GNUTLS_CIPHER_CAMELLIA_128_CBC = 7
|
||||||
|
GNUTLS_CIPHER_CAMELLIA_256_CBC = 8
|
||||||
|
GNUTLS_CIPHER_AES_192_CBC = 9
|
||||||
|
GNUTLS_CIPHER_AES_128_GCM = 10
|
||||||
|
GNUTLS_CIPHER_AES_256_GCM = 11
|
||||||
|
GNUTLS_CIPHER_CAMELLIA_192_CBC = 12
|
||||||
|
GNUTLS_CIPHER_SALSA20_256 = 13
|
||||||
|
GNUTLS_CIPHER_ESTREAM_SALSA20_256 = 14
|
||||||
|
GNUTLS_CIPHER_CAMELLIA_128_GCM = 15
|
||||||
|
GNUTLS_CIPHER_CAMELLIA_256_GCM = 16
|
||||||
|
GNUTLS_CIPHER_RC2_40_CBC = 17
|
||||||
|
GNUTLS_CIPHER_DES_CBC = 18
|
||||||
|
GNUTLS_CIPHER_AES_128_CCM = 19
|
||||||
|
GNUTLS_CIPHER_AES_256_CCM = 20
|
||||||
|
GNUTLS_CIPHER_AES_128_CCM_8 = 21
|
||||||
|
GNUTLS_CIPHER_AES_256_CCM_8 = 22
|
||||||
|
GNUTLS_CIPHER_CHACHA20_POLY1305 = 23
|
||||||
|
)
|
||||||
|
|
||||||
|
// Cipher cipher
|
||||||
|
type Cipher struct {
|
||||||
|
cipher C.gnutls_cipher_hd_t
|
||||||
|
t int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewCipher create cipher
|
||||||
|
func NewCipher(t int, key []byte, iv []byte) (*Cipher, error) {
|
||||||
|
ivSize := C.cipher_get_block_size(C.int(t))
|
||||||
|
blockSize := C.cipher_get_iv_size(C.int(t))
|
||||||
|
if len(key) != int(blockSize) || len(iv) != int(ivSize) {
|
||||||
|
|
||||||
|
return nil, fmt.Errorf("wrong block/iv size")
|
||||||
|
}
|
||||||
|
|
||||||
|
ckey := C.CBytes(key)
|
||||||
|
civ := C.CBytes(iv)
|
||||||
|
|
||||||
|
defer C.free(ckey)
|
||||||
|
defer C.free(civ)
|
||||||
|
|
||||||
|
c := C.new_cipher(C.int(t), (*C.char)(ckey), C.int(len(key)), (*C.char)(civ), C.int(len(iv)))
|
||||||
|
if c == nil {
|
||||||
|
log.Println("new cipher return nil")
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
return &Cipher{c, t}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Encrypt encrypt
|
||||||
|
func (c *Cipher) Encrypt(buf []byte) ([]byte, error) {
|
||||||
|
blockSize := C.cipher_get_iv_size(C.int(c.t))
|
||||||
|
if len(buf)%int(blockSize) != 0 {
|
||||||
|
return nil, fmt.Errorf("wrong block size")
|
||||||
|
}
|
||||||
|
|
||||||
|
cbuf := C.CBytes(buf)
|
||||||
|
defer C.free(cbuf)
|
||||||
|
|
||||||
|
bufLen := C.size_t(len(buf))
|
||||||
|
dstBuf := C.malloc(bufLen)
|
||||||
|
|
||||||
|
defer C.free(dstBuf)
|
||||||
|
|
||||||
|
ret := C.gnutls_cipher_encrypt2(c.cipher, cbuf, bufLen, dstBuf, bufLen)
|
||||||
|
if int(ret) < 0 {
|
||||||
|
return nil, fmt.Errorf("encrypt error: %s", C.GoString(C.gnutls_strerror(ret)))
|
||||||
|
}
|
||||||
|
return C.GoBytes(dstBuf, C.int(bufLen)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Decrypt decrypt
|
||||||
|
func (c *Cipher) Decrypt(buf []byte) ([]byte, error) {
|
||||||
|
blockSize := C.cipher_get_iv_size(C.int(c.t))
|
||||||
|
if len(buf)%int(blockSize) != 0 {
|
||||||
|
return nil, fmt.Errorf("wrong block size")
|
||||||
|
}
|
||||||
|
|
||||||
|
cbuf := C.CBytes(buf)
|
||||||
|
defer C.free(cbuf)
|
||||||
|
|
||||||
|
bufLen := C.size_t(len(buf))
|
||||||
|
dstBuf := C.malloc(C.size_t(len(buf)))
|
||||||
|
|
||||||
|
defer C.free(dstBuf)
|
||||||
|
|
||||||
|
ret := C.gnutls_cipher_decrypt2(c.cipher, cbuf, bufLen, dstBuf, bufLen)
|
||||||
|
if int(ret) < 0 {
|
||||||
|
return nil, fmt.Errorf("decrypt error: %s", C.GoString(C.gnutls_strerror(ret)))
|
||||||
|
}
|
||||||
|
return C.GoBytes(dstBuf, C.int(bufLen)), nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close destroy the cipher
|
||||||
|
func (c *Cipher) Close() error {
|
||||||
|
C.gnutls_cipher_deinit(c.cipher)
|
||||||
|
return nil
|
||||||
|
}
|
@ -0,0 +1,47 @@
|
|||||||
|
package gnutls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/aes"
|
||||||
|
"crypto/cipher"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestEncryptDecrypt(t *testing.T) {
|
||||||
|
key := []byte("0123456789abcdef")
|
||||||
|
iv := []byte("abcdefg123456789")
|
||||||
|
c, err := NewCipher(GNUTLS_CIPHER_AES_128_CBC, key, iv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
c1, err := NewCipher(GNUTLS_CIPHER_AES_128_CBC, key, iv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer c1.Close()
|
||||||
|
|
||||||
|
data := []byte("1234012121212121")
|
||||||
|
if c == nil {
|
||||||
|
t.Fatal("new ciphoer failed")
|
||||||
|
}
|
||||||
|
cdata, err := c.Encrypt(data)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("encrypt failed", err)
|
||||||
|
}
|
||||||
|
data1, err := c1.Decrypt(cdata)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("decrypt failed", err)
|
||||||
|
}
|
||||||
|
if !bytes.Equal(data, data1) {
|
||||||
|
t.Fatal("encrypt/decrypt failed", string(data), string(data1))
|
||||||
|
}
|
||||||
|
block, _ := aes.NewCipher(key)
|
||||||
|
mode := cipher.NewCBCEncrypter(block, iv)
|
||||||
|
dst := make([]byte, len(data))
|
||||||
|
mode.CryptBlocks(dst, data)
|
||||||
|
if !bytes.Equal(dst, cdata) {
|
||||||
|
t.Fatal("cipher text not equal to cypto/aes")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,103 @@
|
|||||||
|
/*Package gnutls is a gnutls binding for golang
|
||||||
|
|
||||||
|
a limit set of api is supported.
|
||||||
|
|
||||||
|
TLS api is very similar to crypto/tls on standard library.
|
||||||
|
|
||||||
|
TLS client example:
|
||||||
|
|
||||||
|
addr := "127.0.0.1:9443"
|
||||||
|
c, err := gnutls.Dial("tcp", addr, &gnutls.Config{ServerName: "localhost"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("gnutls dial ", err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
data := "hello, world"
|
||||||
|
if _, err = c.Write([]byte(data)); err != nil {
|
||||||
|
t.Fatal("gnutls write ", err)
|
||||||
|
}
|
||||||
|
buf := make([]byte, 100)
|
||||||
|
n, err := c.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("gnutls read ", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
TLS Server example:
|
||||||
|
|
||||||
|
l, err := gnults.Listen("tcp", "127.0.0.1:9443", &gnutls.Config{
|
||||||
|
CrtFile: "testdata/server.crt", KeyFile: "testdata/server.key"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("gnutls listen ", err)
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
for {
|
||||||
|
c, err := l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("gnutls accept ", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Println("accept connection from ", c.RemoteAddr())
|
||||||
|
go func(c net.Conn) {
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
buf := make([]byte, 4096)
|
||||||
|
for {
|
||||||
|
n, err := c.Read(buf[0:])
|
||||||
|
if err != nil {
|
||||||
|
log.Println("gnutls read ", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if _, err := c.Write(buf[:n]); err != nil {
|
||||||
|
log.Println("gnutls write ", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(c)
|
||||||
|
}
|
||||||
|
|
||||||
|
AES encrypt/decrypt example:
|
||||||
|
|
||||||
|
key := []byte("0123456789abcdef")
|
||||||
|
iv := []byte("abcdefg123456789")
|
||||||
|
c, err := gnutls.NewCipher(gnutls.GNUTLS_CIPHER_AES_128_CBC, key, iv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
c1, err := gnutls.NewCipher(gnutls.GNUTLS_CIPHER_AES_128_CBC, key, iv)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
defer c1.Close()
|
||||||
|
|
||||||
|
data := []byte("1234012121212121")
|
||||||
|
if c == nil {
|
||||||
|
t.Fatal("new ciphoer failed")
|
||||||
|
}
|
||||||
|
|
||||||
|
// encrypt
|
||||||
|
cdata, err := c.Encrypt(data)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("encrypt failed", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
// decrypt
|
||||||
|
data1, err := c1.Decrypt(cdata)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("decrypt failed", err)
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
Hash example:
|
||||||
|
|
||||||
|
h := gnutls.NewHash(gnutls.GNUTLS_SHA512)
|
||||||
|
defer h.Close()
|
||||||
|
|
||||||
|
data := []byte("1234")
|
||||||
|
|
||||||
|
h1 := h.Sum(data)
|
||||||
|
|
||||||
|
*/
|
||||||
|
package gnutls
|
@ -0,0 +1,175 @@
|
|||||||
|
#include "_gnutls.h"
|
||||||
|
|
||||||
|
#define MAX_BUF 1024
|
||||||
|
char buffer[MAX_BUF + 1], *desc;
|
||||||
|
gnutls_datum_t out;
|
||||||
|
int status;
|
||||||
|
int type;
|
||||||
|
|
||||||
|
struct session *init_client_session()
|
||||||
|
{
|
||||||
|
struct session *sess = malloc(sizeof(struct session));
|
||||||
|
memset(sess, sizeof(struct session), 0);
|
||||||
|
gnutls_init(&sess->session, GNUTLS_CLIENT);
|
||||||
|
gnutls_certificate_allocate_credentials(&sess->xcred);
|
||||||
|
gnutls_certificate_set_x509_system_trust(sess->xcred);
|
||||||
|
gnutls_set_default_priority(sess->session);
|
||||||
|
gnutls_credentials_set(sess->session, GNUTLS_CRD_CERTIFICATE, sess->xcred);
|
||||||
|
return sess;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct session *init_server_session()
|
||||||
|
{
|
||||||
|
struct session *sess = malloc(sizeof(struct session));
|
||||||
|
memset(sess, sizeof(struct session), 0);
|
||||||
|
gnutls_init(&sess->session, GNUTLS_SERVER);
|
||||||
|
gnutls_certificate_allocate_credentials(&sess->xcred);
|
||||||
|
gnutls_certificate_set_x509_system_trust(sess->xcred);
|
||||||
|
gnutls_set_default_priority(sess->session);
|
||||||
|
gnutls_credentials_set(sess->session, GNUTLS_CRD_CERTIFICATE, sess->xcred);
|
||||||
|
gnutls_certificate_server_set_request(sess->session, GNUTLS_CERT_IGNORE);
|
||||||
|
return sess;
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_keyfile(struct session *sess, char *crtfile, char *keyfile)
|
||||||
|
{
|
||||||
|
return gnutls_certificate_set_x509_key_file(
|
||||||
|
sess->xcred, crtfile, keyfile, GNUTLS_X509_FMT_PEM);
|
||||||
|
}
|
||||||
|
|
||||||
|
void session_destroy(struct session *sess)
|
||||||
|
{
|
||||||
|
gnutls_bye(sess->session, GNUTLS_SHUT_WR);
|
||||||
|
gnutls_deinit(sess->session);
|
||||||
|
gnutls_certificate_free_credentials(sess->xcred);
|
||||||
|
free(sess);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t pull_function(gnutls_transport_ptr_t ptr, void *data, size_t len)
|
||||||
|
{
|
||||||
|
return DataRead(ptr, data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
int pull_timeout_function(gnutls_transport_ptr_t ptr, unsigned int ms)
|
||||||
|
{
|
||||||
|
return DataTimeoutPull(ptr, ms);
|
||||||
|
}
|
||||||
|
|
||||||
|
ssize_t push_function(gnutls_transport_ptr_t ptr, const void *data, size_t len)
|
||||||
|
{
|
||||||
|
return DataWrite(ptr, (char *)data, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_data(struct session *sess, size_t data)
|
||||||
|
{
|
||||||
|
sess->data = (void *)((int *)data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void set_servername(struct session *sess, char *servername, int namelen)
|
||||||
|
{
|
||||||
|
gnutls_server_name_set(sess->session, GNUTLS_NAME_DNS, servername, namelen);
|
||||||
|
gnutls_session_set_verify_cert(sess->session, NULL, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int handshake(struct session *sess)
|
||||||
|
{
|
||||||
|
if (sess->handshake > 0)
|
||||||
|
{
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int ret;
|
||||||
|
do
|
||||||
|
{
|
||||||
|
ret = gnutls_handshake(sess->session);
|
||||||
|
} while (ret < 0 && gnutls_error_is_fatal(ret) == 0);
|
||||||
|
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
if (ret == GNUTLS_E_CERTIFICATE_VERIFICATION_ERROR)
|
||||||
|
{
|
||||||
|
// check certificate verification status
|
||||||
|
type = gnutls_certificate_type_get(sess->session);
|
||||||
|
status = gnutls_session_get_verify_cert_status(sess->session);
|
||||||
|
gnutls_certificate_verification_status_print(status,
|
||||||
|
type, &out, 0);
|
||||||
|
printf("cert verify output: %s\n", out.data);
|
||||||
|
gnutls_free(out.data);
|
||||||
|
}
|
||||||
|
fprintf(stderr, "*** Handshake failed: %s\n", gnutls_strerror(ret));
|
||||||
|
} /*else{
|
||||||
|
desc = gnutls_session_get_desc(sess->session);
|
||||||
|
printf("- Session info: %s\n", desc);
|
||||||
|
gnutls_free(desc);
|
||||||
|
}*/
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int read_application_data(struct session *sess, char *data, int buflen)
|
||||||
|
{
|
||||||
|
int ret = gnutls_record_recv(sess->session, data, buflen);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int write_application_data(struct session *sess, char *data, int datalen)
|
||||||
|
{
|
||||||
|
int ret = gnutls_record_send(sess->session, data, datalen);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
int set_callback(struct session *sess)
|
||||||
|
{
|
||||||
|
if (sess->data == NULL)
|
||||||
|
{
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
gnutls_transport_set_ptr(sess->session, sess->data);
|
||||||
|
gnutls_transport_set_pull_function(sess->session, pull_function);
|
||||||
|
gnutls_transport_set_push_function(sess->session, push_function);
|
||||||
|
gnutls_transport_set_pull_timeout_function(sess->session, pull_timeout_function);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
gnutls_cipher_hd_t new_cipher(int cipher_type, char *key, int keylen, char *iv, int ivlen)
|
||||||
|
{
|
||||||
|
gnutls_cipher_hd_t handle;
|
||||||
|
gnutls_datum_t _key;
|
||||||
|
gnutls_datum_t _iv;
|
||||||
|
|
||||||
|
_key.data = key;
|
||||||
|
_key.size = keylen;
|
||||||
|
_iv.data = iv;
|
||||||
|
_iv.size = ivlen;
|
||||||
|
|
||||||
|
int ret = gnutls_cipher_init(&handle, cipher_type, &_key, &_iv);
|
||||||
|
if (ret < 0)
|
||||||
|
{
|
||||||
|
printf("new cipher: %s\n", gnutls_strerror(ret));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
//printf("new cipher done\n");
|
||||||
|
//cipher->handle = handle;
|
||||||
|
return handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
int cipher_get_block_size(int t)
|
||||||
|
{
|
||||||
|
return gnutls_cipher_get_block_size(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
int cipher_get_iv_size(int t)
|
||||||
|
{
|
||||||
|
return gnutls_cipher_get_iv_size(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
gnutls_hash_hd_t new_hash(int t)
|
||||||
|
{
|
||||||
|
gnutls_hash_hd_t hash;
|
||||||
|
gnutls_hash_init(&hash, t);
|
||||||
|
return hash;
|
||||||
|
}
|
||||||
|
|
||||||
|
int get_hash_len(int t)
|
||||||
|
{
|
||||||
|
return gnutls_hash_get_len(t);
|
||||||
|
}
|
@ -0,0 +1,70 @@
|
|||||||
|
package gnutls
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include "_gnutls.h"
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
)
|
||||||
|
|
||||||
|
const (
|
||||||
|
GNUTLS_MD5 = 2
|
||||||
|
GNUTLS_SHA1 = 3
|
||||||
|
GNUTLS_MD2 = 5
|
||||||
|
GNUTLS_SHA256 = 6
|
||||||
|
GNUTLS_SHA384 = 7
|
||||||
|
GNUTLS_SHA512 = 8
|
||||||
|
GNUTLS_SHA224 = 9
|
||||||
|
)
|
||||||
|
|
||||||
|
// Hash hash struct
|
||||||
|
type Hash struct {
|
||||||
|
hash C.gnutls_hash_hd_t
|
||||||
|
t int
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewHash new hash struct
|
||||||
|
func NewHash(t int) *Hash {
|
||||||
|
h := C.new_hash(C.int(t))
|
||||||
|
return &Hash{h, t}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write write data to hash context
|
||||||
|
func (h *Hash) Write(buf []byte) error {
|
||||||
|
dataLen := len(buf)
|
||||||
|
|
||||||
|
cbuf := C.CBytes(buf)
|
||||||
|
defer C.free(cbuf)
|
||||||
|
|
||||||
|
ret := C.gnutls_hash(h.hash, cbuf, C.size_t(dataLen))
|
||||||
|
if int(ret) < 0 {
|
||||||
|
return fmt.Errorf("hash failed: %s", C.GoString(C.gnutls_strerror(ret)))
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sum get hash result
|
||||||
|
func (h *Hash) Sum(buf []byte) []byte {
|
||||||
|
if buf != nil {
|
||||||
|
h.Write(buf)
|
||||||
|
}
|
||||||
|
|
||||||
|
hashOutLen := C.get_hash_len(C.int(h.t))
|
||||||
|
|
||||||
|
dstBuf := C.malloc(C.size_t(hashOutLen))
|
||||||
|
defer C.free(dstBuf)
|
||||||
|
|
||||||
|
C.gnutls_hash_output(h.hash, dstBuf)
|
||||||
|
|
||||||
|
gobuf := C.GoBytes(dstBuf, hashOutLen)
|
||||||
|
|
||||||
|
return gobuf
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close destroy hash context
|
||||||
|
func (h *Hash) Close() error {
|
||||||
|
C.gnutls_hash_deinit(h.hash, nil)
|
||||||
|
return nil
|
||||||
|
}
|
@ -0,0 +1,24 @@
|
|||||||
|
package gnutls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"bytes"
|
||||||
|
"crypto/sha512"
|
||||||
|
"encoding/hex"
|
||||||
|
"log"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestHashSHA(t *testing.T) {
|
||||||
|
h := NewHash(GNUTLS_SHA512)
|
||||||
|
defer h.Close()
|
||||||
|
|
||||||
|
data := []byte("1234")
|
||||||
|
|
||||||
|
h1 := h.Sum(data)
|
||||||
|
|
||||||
|
h3 := sha512.Sum512(data)
|
||||||
|
if !bytes.Equal(h3[:], h1) {
|
||||||
|
log.Printf("\n%s\n%s", hex.EncodeToString(h3[:]), hex.EncodeToString(h1))
|
||||||
|
t.Fatal("hash not equal")
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,21 @@
|
|||||||
|
-----BEGIN CERTIFICATE-----
|
||||||
|
MIIDYDCCAkigAwIBAgIJAJ92ThBK0H0ZMA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
|
||||||
|
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
|
||||||
|
aWRnaXRzIFB0eSBMdGQwHhcNMTgwNjI3MDMwMjUwWhcNMjgwNjI0MDMwMjUwWjBF
|
||||||
|
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
|
||||||
|
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
|
||||||
|
CgKCAQEAufMjhIyoWzqqRKbglkfCWqSbU1N6SPaSjBmVQCfFGzUZx3DHWvemJ8Ip
|
||||||
|
2Nb9Gx9fI/GiRHs1K6noWZjJzsFZNdsoAADg+vXhS4MEwsItcRnKFgbmBtjKPbQy
|
||||||
|
jHnndAy8Wwe73NXTy7oBSbd5CZogvblLjfndSUIhCXVv7+PFHjfG78LEL7Dp1i1A
|
||||||
|
96SV2YuVYHr6FIS6C5FA0FGtGpXUC265jUN+sI88ONXMc/7zQ+4VWggB+Kq3B7uR
|
||||||
|
4DjTtxAC0X58AdWJm3yH6nTJLcsfOVQs1u7Mg97aUpRo9osw7ZMcEEchOw85L0Rl
|
||||||
|
K4vlZDnB2xD+8S8RRQi+Y/4GKPAihwIDAQABo1MwUTAdBgNVHQ4EFgQUGY2IxTxn
|
||||||
|
3tKlRsUnko97fF4X8WYwHwYDVR0jBBgwFoAUGY2IxTxn3tKlRsUnko97fF4X8WYw
|
||||||
|
DwYDVR0TAQH/BAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAHpvWRFV+Cen2VQdX
|
||||||
|
OO1YYufqcGPmTxo0XmksOUQsd+vwR0HSjCK1oC0PlloviFvCXn9p4ZvwVK1NdK19
|
||||||
|
RUkiXPAIw5QmXeNQgCJRv7jhObIuqfKVGfZuH8PdPMcPzU+PxgaZ/gnaW62AAFJA
|
||||||
|
frZXwMhr/Ar+CvH4NSZfOxBF4LOWM0eVYfxUOFq+qvYptdSxXyK1kuBxFXOVNEIw
|
||||||
|
CWp75uzvZ1gNaUrdfCNoYMV2qeyuL8gNfRhExrDfjn4ouOZq0Lh8FHCnGdoZo15D
|
||||||
|
ZHkLUqdKnOXtHKdnLcxStF6orKF7I3f3fp5kyRM19uZzLV07zdawVJSDbaO2cJz1
|
||||||
|
Qff5gg==
|
||||||
|
-----END CERTIFICATE-----
|
@ -0,0 +1,27 @@
|
|||||||
|
-----BEGIN RSA PRIVATE KEY-----
|
||||||
|
MIIEowIBAAKCAQEAufMjhIyoWzqqRKbglkfCWqSbU1N6SPaSjBmVQCfFGzUZx3DH
|
||||||
|
WvemJ8Ip2Nb9Gx9fI/GiRHs1K6noWZjJzsFZNdsoAADg+vXhS4MEwsItcRnKFgbm
|
||||||
|
BtjKPbQyjHnndAy8Wwe73NXTy7oBSbd5CZogvblLjfndSUIhCXVv7+PFHjfG78LE
|
||||||
|
L7Dp1i1A96SV2YuVYHr6FIS6C5FA0FGtGpXUC265jUN+sI88ONXMc/7zQ+4VWggB
|
||||||
|
+Kq3B7uR4DjTtxAC0X58AdWJm3yH6nTJLcsfOVQs1u7Mg97aUpRo9osw7ZMcEEch
|
||||||
|
Ow85L0RlK4vlZDnB2xD+8S8RRQi+Y/4GKPAihwIDAQABAoIBAFUuooin/r+8Ah/s
|
||||||
|
6lktikUHvvfO9+fQvJVdate24D50dti8Ozba18zCz3S8F7qDBoxqttD0OAlGjl/s
|
||||||
|
9BW40Osw+AP4YxfT5182J8ooNbToAYFRq7JbQVo+4CEl/vdUljyFMHQbqChdjxV7
|
||||||
|
7QCPEIyZA5mIauySVJwGpj6YcsZCMemwEVjD3tFEeXF6qu0hD9R4SVDiJEosxta7
|
||||||
|
evzfENVUgfUMceJQzRUQ/3HfbgBJybPfNQ8fH2ORF2eOgjcmlmh+EwXGNcuCCpXd
|
||||||
|
EOndM30YYBRJBCAuvCdPrg9/2H2KL9jsIuLG1PyO9/IiLGMh5nTP/2TYjKOxNcYh
|
||||||
|
1g8S4+ECgYEA8lW1Q9msH1wWM+eZwHDg1rZ3BLMCguRHh2CN/q1KAOgdRsEBsP3A
|
||||||
|
u45MjwwBWzy56H6w69RC4AXQcMdGjZT20095RpYD8Rv1hmaB/1n9mL6i8V2p+X5D
|
||||||
|
pk1EgDDTWy8VbT3jn/Qt8hxINGvKYbZaRQgAtAXPx71mNGgxYLm3+18CgYEAxG93
|
||||||
|
+on9SmhTXZNke+BRrgX0FTpkGtdCwfNnGMGyX7qlNR3kUls17JYE7ejLED7NWxOT
|
||||||
|
uSBCib8Lhh7qhCl+N9rvxpZkeESoZazhoBIigv9osOLOxZtrct1sg7MHDTWgIzT+
|
||||||
|
+OvLzveHPuliVKZVJdM69dz2QUplC9buf0JtUdkCgYAHaA0xNK7pCnR3Q6XUVt7Y
|
||||||
|
UR1UHHCANZ/mCFJurTcszetPJUj68tZ4JQI8AP7tne6Ep5KaspMUq7jSKZUDcMEW
|
||||||
|
dkBbouwd61/Wqr1gY4y3pWPvgpBWWsCQjZ4BWPystcSu4Qxa8CiTVL/0MjMuR1d8
|
||||||
|
8qCq396Y2TYNdf3EWgjAewKBgHUNJyU3zKLl/6cnCR130bQtAAEWRkhoNPN1ot1x
|
||||||
|
rmS0x3UbVs5sY3mS+2T47ufDRIMc603JF10VZjyJd51BTGDkKTTgsQWpg97yYZAM
|
||||||
|
vlvo7e1ZeXTu49wSbXMc3vrUFZRlI/oYJ94wSXsHfvyKEPr1H5EaFfNZ7VRcwsk6
|
||||||
|
QAIhAoGBAOX5gnUHiQe9n8Vg5AZS6JoNf11+ZHemDNczQAZ4o7L0nHvorqeKBZvG
|
||||||
|
U7jo1XDTyrdbs8BPibVdArSpD23auLBL8WZ2wORvFLWXl5po/GSGqoOVS9KoBGMs
|
||||||
|
6E2UkiVR00zYSXTXwsiin3DrLuZcjG7InV45I+ws5DerYFGoNer/
|
||||||
|
-----END RSA PRIVATE KEY-----
|
@ -0,0 +1,271 @@
|
|||||||
|
package gnutls
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include "_gnutls.h"
|
||||||
|
#cgo pkg-config: gnutls
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"fmt"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"os"
|
||||||
|
"time"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Conn tls connection for client
|
||||||
|
type Conn struct {
|
||||||
|
c net.Conn
|
||||||
|
sess *C.struct_session
|
||||||
|
handshake bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// Config tls configure
|
||||||
|
type Config struct {
|
||||||
|
ServerName string
|
||||||
|
CrtFile string
|
||||||
|
KeyFile string
|
||||||
|
}
|
||||||
|
type listener struct {
|
||||||
|
l net.Listener
|
||||||
|
c *Config
|
||||||
|
}
|
||||||
|
|
||||||
|
// Accept
|
||||||
|
func (l *listener) Accept() (net.Conn, error) {
|
||||||
|
c, err := l.l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewServerConn(c, l.c)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close
|
||||||
|
func (l *listener) Close() error {
|
||||||
|
return l.l.Close()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Addr
|
||||||
|
func (l *listener) Addr() net.Addr {
|
||||||
|
return l.l.Addr()
|
||||||
|
}
|
||||||
|
|
||||||
|
// Dial create a new connection
|
||||||
|
func Dial(network, addr string, cfg *Config) (*Conn, error) {
|
||||||
|
c, err := net.Dial(network, addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return NewClientConn(c, cfg)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Listen create a listener
|
||||||
|
func Listen(network, addr string, cfg *Config) (net.Listener, error) {
|
||||||
|
if cfg == nil {
|
||||||
|
return nil, fmt.Errorf("config is need")
|
||||||
|
}
|
||||||
|
if cfg.CrtFile == "" || cfg.KeyFile == "" {
|
||||||
|
return nil, fmt.Errorf("keyfile is needed")
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(cfg.CrtFile); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if _, err := os.Stat(cfg.KeyFile); err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
l, err := net.Listen(network, addr)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
return &listener{l, cfg}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewServerConn create a server Conn
|
||||||
|
func NewServerConn(c net.Conn, cfg *Config) (*Conn, error) {
|
||||||
|
var sess = C.init_server_session()
|
||||||
|
conn := &Conn{c: c, sess: sess}
|
||||||
|
n := C.size_t(uintptr(unsafe.Pointer(conn)))
|
||||||
|
//log.Println("conn addr ", int(n))
|
||||||
|
C.set_data(sess, n)
|
||||||
|
C.set_callback(sess)
|
||||||
|
crtfile := C.CString(cfg.CrtFile)
|
||||||
|
keyfile := C.CString(cfg.KeyFile)
|
||||||
|
defer C.free(unsafe.Pointer(crtfile))
|
||||||
|
defer C.free(unsafe.Pointer(keyfile))
|
||||||
|
ret := C.set_keyfile(sess, crtfile, keyfile)
|
||||||
|
if int(ret) < 0 {
|
||||||
|
cerrstr := C.gnutls_strerror(ret)
|
||||||
|
return nil, fmt.Errorf("set keyfile failed: %s", C.GoString(cerrstr))
|
||||||
|
}
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// NewClientConn create a new gnutls connection
|
||||||
|
func NewClientConn(c net.Conn, cfg *Config) (*Conn, error) {
|
||||||
|
var sess = C.init_client_session()
|
||||||
|
conn := &Conn{c: c, sess: sess}
|
||||||
|
n := C.size_t(uintptr(unsafe.Pointer(conn)))
|
||||||
|
//log.Println("conn addr ", int(n))
|
||||||
|
C.set_data(sess, n)
|
||||||
|
C.set_callback(sess)
|
||||||
|
if cfg != nil {
|
||||||
|
if cfg.ServerName != "" {
|
||||||
|
srvname := C.CString(cfg.ServerName)
|
||||||
|
defer C.free(unsafe.Pointer(srvname))
|
||||||
|
C.set_servername(sess, srvname, C.int(len(cfg.ServerName)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if cfg.CrtFile != "" && cfg.KeyFile != "" {
|
||||||
|
crtfile := C.CString(cfg.CrtFile)
|
||||||
|
keyfile := C.CString(cfg.KeyFile)
|
||||||
|
defer C.free(unsafe.Pointer(crtfile))
|
||||||
|
defer C.free(unsafe.Pointer(keyfile))
|
||||||
|
ret := C.set_keyfile(sess, crtfile, keyfile)
|
||||||
|
if int(ret) < 0 {
|
||||||
|
return nil, fmt.Errorf("set keyfile failed: %s", C.GoString(C.gnutls_strerror(ret)))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return conn, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handshake handshake tls
|
||||||
|
func (c *Conn) Handshake() error {
|
||||||
|
if c.handshake {
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
ret := C.handshake(c.sess)
|
||||||
|
if int(ret) < 0 {
|
||||||
|
return fmt.Errorf("handshake error")
|
||||||
|
}
|
||||||
|
c.handshake = true
|
||||||
|
//log.Println("handshake done")
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Read
|
||||||
|
func (c *Conn) Read(buf []byte) (n int, err error) {
|
||||||
|
if !c.handshake {
|
||||||
|
err = c.Handshake()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.handshake = true
|
||||||
|
}
|
||||||
|
|
||||||
|
bufLen := len(buf)
|
||||||
|
cbuf := C.malloc(C.size_t(bufLen))
|
||||||
|
defer C.free(cbuf)
|
||||||
|
|
||||||
|
ret := C.read_application_data(c.sess, (*C.char)(cbuf), C.int(bufLen))
|
||||||
|
if int(ret) < 0 {
|
||||||
|
return 0, fmt.Errorf("read error: %s", C.GoString(C.gnutls_strerror(ret)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if int(ret) == 0 {
|
||||||
|
return 0, fmt.Errorf("connection closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
n = int(ret)
|
||||||
|
gobuf2 := C.GoBytes(cbuf, ret)
|
||||||
|
copy(buf, gobuf2)
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Write
|
||||||
|
func (c *Conn) Write(buf []byte) (n int, err error) {
|
||||||
|
if !c.handshake {
|
||||||
|
err = c.Handshake()
|
||||||
|
if err != nil {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
c.handshake = true
|
||||||
|
}
|
||||||
|
cbuf := C.CBytes(buf)
|
||||||
|
defer C.free(cbuf)
|
||||||
|
|
||||||
|
ret := C.write_application_data(c.sess, (*C.char)(cbuf), C.int(len(buf)))
|
||||||
|
n = int(ret)
|
||||||
|
|
||||||
|
if n < 0 {
|
||||||
|
return 0, fmt.Errorf("write error: %s", C.GoString(C.gnutls_strerror(ret)))
|
||||||
|
}
|
||||||
|
|
||||||
|
if int(ret) == 0 {
|
||||||
|
return 0, fmt.Errorf("connection closed")
|
||||||
|
}
|
||||||
|
|
||||||
|
return n, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// Close close the conn
|
||||||
|
func (c *Conn) Close() error {
|
||||||
|
C.session_destroy(c.sess)
|
||||||
|
c.c.Close()
|
||||||
|
return nil
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetWriteDeadline implements net.Conn
|
||||||
|
func (c *Conn) SetWriteDeadline(t time.Time) error {
|
||||||
|
return c.c.SetWriteDeadline(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetReadDeadline implements net.Conn
|
||||||
|
func (c *Conn) SetReadDeadline(t time.Time) error {
|
||||||
|
return c.c.SetReadDeadline(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// RemoteAddr implements net.Conn
|
||||||
|
func (c *Conn) RemoteAddr() net.Addr {
|
||||||
|
return c.c.RemoteAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
// LocalAddr implements net.Conn
|
||||||
|
func (c *Conn) LocalAddr() net.Addr {
|
||||||
|
return c.c.LocalAddr()
|
||||||
|
}
|
||||||
|
|
||||||
|
// SetDeadline implements net.Conn
|
||||||
|
func (c *Conn) SetDeadline(t time.Time) error {
|
||||||
|
return c.c.SetDeadline(t)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataRead c callback function for data read
|
||||||
|
//export DataRead
|
||||||
|
func DataRead(d unsafe.Pointer, cbuf *C.char, bufLen C.int) C.int {
|
||||||
|
//log.Println("read addr ", uintptr(d))
|
||||||
|
conn := (*Conn)(unsafe.Pointer((uintptr(d))))
|
||||||
|
buf := make([]byte, int(bufLen))
|
||||||
|
n, err := conn.c.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
cbuf2 := C.CBytes(buf[:n])
|
||||||
|
// d := C.CString(string(buf[:n]))
|
||||||
|
defer C.free(cbuf2)
|
||||||
|
C.memcpy(unsafe.Pointer(cbuf), unsafe.Pointer(cbuf2), C.size_t(n))
|
||||||
|
return C.int(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataWrite c callback function for data write
|
||||||
|
//export DataWrite
|
||||||
|
func DataWrite(d unsafe.Pointer, cbuf *C.char, bufLen C.int) C.int {
|
||||||
|
//log.Println("write addr ", uintptr(d), int(_l))
|
||||||
|
conn := (*Conn)(unsafe.Pointer((uintptr(d))))
|
||||||
|
gobuf := C.GoBytes(unsafe.Pointer(cbuf), bufLen)
|
||||||
|
n, err := conn.c.Write(gobuf)
|
||||||
|
if err != nil {
|
||||||
|
log.Println(err)
|
||||||
|
return -1
|
||||||
|
}
|
||||||
|
return C.int(n)
|
||||||
|
}
|
||||||
|
|
||||||
|
// DataTimeoutPull c callback function for timeout read
|
||||||
|
//export DataTimeoutPull
|
||||||
|
func DataTimeoutPull(d unsafe.Pointer, delay C.int) C.int {
|
||||||
|
log.Println("timeout pull function")
|
||||||
|
return 0
|
||||||
|
}
|
@ -0,0 +1,122 @@
|
|||||||
|
package gnutls
|
||||||
|
|
||||||
|
import (
|
||||||
|
"crypto/tls"
|
||||||
|
"log"
|
||||||
|
"net"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func TestTLSClient(t *testing.T) {
|
||||||
|
cert, err := tls.LoadX509KeyPair("testdata/server.crt", "testdata/server.key")
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("load certificate failed")
|
||||||
|
}
|
||||||
|
l, err := tls.Listen("tcp", "127.0.0.1:0", &tls.Config{
|
||||||
|
Certificates: []tls.Certificate{cert},
|
||||||
|
})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("listen failed")
|
||||||
|
}
|
||||||
|
defer l.Close()
|
||||||
|
addr := l.Addr().String()
|
||||||
|
log.Println("test server listen on ", addr)
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
c, err := l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Printf("accept connection from %s", c.RemoteAddr())
|
||||||
|
go func(c net.Conn) {
|
||||||
|
defer c.Close()
|
||||||
|
for {
|
||||||
|
buf := make([]byte, 4096)
|
||||||
|
n, err := c.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
log.Println("connection closed")
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if _, err = c.Write(buf[:n]); err != nil {
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(c)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
c, err := Dial("tcp", addr, &Config{})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("gnutls dial ", err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
data := "hello, world"
|
||||||
|
if _, err = c.Write([]byte(data)); err != nil {
|
||||||
|
t.Fatal("gnutls write ", err)
|
||||||
|
}
|
||||||
|
buf := make([]byte, 100)
|
||||||
|
n, err := c.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("gnutls read ", err)
|
||||||
|
}
|
||||||
|
if string(buf[:n]) != data {
|
||||||
|
t.Errorf("need: %s, got: %s", data, string(buf[:n]))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestTLSServer(t *testing.T) {
|
||||||
|
l, err := Listen("tcp", "127.0.0.1:0", &Config{
|
||||||
|
CrtFile: "testdata/server.crt", KeyFile: "testdata/server.key"})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("gnutls listen ", err)
|
||||||
|
}
|
||||||
|
addr := l.Addr().String()
|
||||||
|
log.Println("test server listen on ", addr)
|
||||||
|
defer l.Close()
|
||||||
|
go func() {
|
||||||
|
for {
|
||||||
|
c, err := l.Accept()
|
||||||
|
if err != nil {
|
||||||
|
log.Println("gnutls accept ", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
log.Println("accept connection from ", c.RemoteAddr())
|
||||||
|
go func(c net.Conn) {
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
buf := make([]byte, 4096)
|
||||||
|
for {
|
||||||
|
n, err := c.Read(buf[0:])
|
||||||
|
if err != nil {
|
||||||
|
log.Println("gnutls read ", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
if _, err := c.Write(buf[:n]); err != nil {
|
||||||
|
log.Println("gnutls write ", err)
|
||||||
|
break
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}(c)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
c, err := tls.Dial("tcp", addr, &tls.Config{InsecureSkipVerify: true})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("dial ", err)
|
||||||
|
}
|
||||||
|
defer c.Close()
|
||||||
|
|
||||||
|
data := "hello, world"
|
||||||
|
if _, err := c.Write([]byte(data)); err != nil {
|
||||||
|
t.Fatal("write ", err)
|
||||||
|
}
|
||||||
|
buf := make([]byte, 100)
|
||||||
|
n, err := c.Read(buf)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal("read ", err)
|
||||||
|
}
|
||||||
|
if string(buf[:n]) != data {
|
||||||
|
t.Errorf("need: %s, got: %s", data, string(buf[:n]))
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue