first commit

master
fangdingjun 7 years ago
commit a72416672a

1
.gitignore vendored

@ -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")
}
}

103
doc.go

@ -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-----

271
tls.go

@ -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…
Cancel
Save