diff --git a/go/gmssl/certificate.go b/go/gmssl/certificate.go new file mode 100644 index 00000000..9100d2cb --- /dev/null +++ b/go/gmssl/certificate.go @@ -0,0 +1,127 @@ +/* +build cgo */ +package gmssl + +/* +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +void _OPENSSL_free(void *p) { + OPENSSL_free(p); +} + +long _BIO_get_mem_data(BIO *b, char **pp) { + return BIO_get_mem_data(b, pp); +} + +*/ +import "C" + +import ( + "fmt" + "unsafe" + "runtime" +) + +type Certificate struct { + x509 *C.X509 +} + +func ReadCertificateFromPEM(pem string, pass string) (*Certificate, error) { + cpem := C.CString(pem) + defer C.free(unsafe.Pointer(cpem)) + cpass := C.CString(pass) + defer C.free(unsafe.Pointer(cpass)) + + bio := C.BIO_new_mem_buf(unsafe.Pointer(cpem), -1) + if bio == nil { + return nil, GetErrors() + } + defer C.BIO_free(bio) + + x509 := C.PEM_read_bio_X509(bio, nil, nil, unsafe.Pointer(cpass)) + if x509 == nil { + return nil, GetErrors() + } + ret := &Certificate{x509} + runtime.SetFinalizer(ret, func(ret *Certificate) { + C.X509_free(ret.x509) + }) + + return ret, nil +} + +func (cert *Certificate) GetSubject() (string, error) { + name := C.X509_get_subject_name(cert.x509) + if name == nil { + return "", GetErrors() + } + str := C.X509_NAME_oneline(name, nil, 0) + if str == nil { + return "", GetErrors() + } + defer C._OPENSSL_free(unsafe.Pointer(str)) + return C.GoString(str), nil +} + +func (cert *Certificate) GetIssuer() (string, error) { + name := C.X509_get_issuer_name(cert.x509) + if name == nil { + return "", GetErrors() + } + str := C.X509_NAME_oneline(name, nil, 0) + if str == nil { + return "", GetErrors() + } + defer C._OPENSSL_free(unsafe.Pointer(str)) + return C.GoString(str), nil +} + +func (cert *Certificate) GetSerialNumber() (string, error) { + serial := C.X509_get0_serialNumber(cert.x509) + if serial == nil { + return "", GetErrors() + } + bn := C.ASN1_INTEGER_to_BN(serial, nil) + if bn == nil { + return "", GetErrors() + } + defer C.BN_free(bn) + hex := C.BN_bn2hex(bn) + if hex == nil { + return "", GetErrors() + } + defer C._OPENSSL_free(unsafe.Pointer(hex)) + return C.GoString(hex), nil +} + +func (cert *Certificate) GetPublicKey() (*PublicKey, error) { + pkey := C.X509_get_pubkey(cert.x509) + if pkey == nil { + return nil, GetErrors() + } + ret := &PublicKey{pkey} + runtime.SetFinalizer(ret, func(ret *PublicKey) { + C.EVP_PKEY_free(ret.pkey) + }) + return ret, nil +} +func (cert *Certificate) CheckPrivateKey(skey *PrivateKey) error { + if 1 != C.X509_check_private_key(cert.x509, skey.pkey) { + err := GetErrors() + if err == nil { + return fmt.Errorf("failure") + } + return err + } + return nil +} + diff --git a/go/gmssl/cipher.go b/go/gmssl/cipher.go index 8a93fc1a..cebf9604 100644 --- a/go/gmssl/cipher.go +++ b/go/gmssl/cipher.go @@ -8,9 +8,8 @@ import "C" import ( "errors" - "fmt" - "runtime" "unsafe" + "runtime" ) /* generated by `gmssl list -cipher-algorithms | sort -f | uniq -i` */ @@ -171,7 +170,7 @@ func GetCipherKeyLength(name string) (int, error) { defer C.free(unsafe.Pointer(cname)) cipher := C.EVP_get_cipherbyname(cname) if cipher == nil { - return 0, errors.New("Invalid cipher name") + return 0, GetErrors() } return int(C.EVP_CIPHER_key_length(cipher)), nil } @@ -181,7 +180,7 @@ func GetCipherBlockLength(name string) (int, error) { defer C.free(unsafe.Pointer(cname)) cipher := C.EVP_get_cipherbyname(cname) if cipher == nil { - return 0, errors.New("Invalid cipher") + return 0, GetErrors() } return int(C.EVP_CIPHER_block_size(cipher)), nil } @@ -191,7 +190,7 @@ func GetCipherIVLength(name string) (int, error) { defer C.free(unsafe.Pointer(cname)) cipher := C.EVP_get_cipherbyname(cname) if cipher == nil { - return 0, errors.New("Invalid cipher") + return 0, GetErrors() } return int(C.EVP_CIPHER_iv_length(cipher)), nil } @@ -208,7 +207,7 @@ func NewCipherContext(name string, eng *Engine, key, iv []byte, encrypt bool) ( cipher := C.EVP_get_cipherbyname(cname) if cipher == nil { - return nil, fmt.Errorf("shit") + return nil, GetErrors() } if key == nil { @@ -229,7 +228,7 @@ func NewCipherContext(name string, eng *Engine, key, iv []byte, encrypt bool) ( ctx := C.EVP_CIPHER_CTX_new() if ctx == nil { - return nil, fmt.Errorf("shit") + return nil, GetErrors() } ret := &CipherContext{ctx} @@ -244,7 +243,7 @@ func NewCipherContext(name string, eng *Engine, key, iv []byte, encrypt bool) ( if 1 != C.EVP_CipherInit(ctx, cipher, (*C.uchar)(&key[0]), (*C.uchar)(&iv[0]), C.int(enc)) { - return nil, fmt.Errorf("shit") + return nil, GetErrors() } return ret, nil @@ -255,7 +254,7 @@ func (ctx *CipherContext) Update(in []byte) ([]byte, error) { outlen := C.int(len(outbuf)) if 1 != C.EVP_CipherUpdate(ctx.ctx, (*C.uchar)(&outbuf[0]), &outlen, (*C.uchar)(&in[0]), C.int(len(in))) { - return nil, fmt.Errorf("failed to decrypt") + return nil, GetErrors() } return outbuf[:outlen], nil } @@ -264,7 +263,7 @@ func (ctx *CipherContext) Final() ([]byte, error) { outbuf := make([]byte, int(C.EVP_CIPHER_CTX_block_size(ctx.ctx))) outlen := C.int(len(outbuf)) if 1 != C.EVP_CipherFinal(ctx.ctx, (*C.uchar)(&outbuf[0]), &outlen) { - return nil, fmt.Errorf("failed to decrypt") + return nil, GetErrors() } return outbuf[:outlen], nil } diff --git a/go/gmssl/digest.go b/go/gmssl/digest.go index 53bf4510..0cd7f852 100644 --- a/go/gmssl/digest.go +++ b/go/gmssl/digest.go @@ -8,10 +8,8 @@ package gmssl import "C" import ( - "errors" - "fmt" - "runtime" "unsafe" + "runtime" ) func GetDigestNames() []string { @@ -45,7 +43,7 @@ func GetDigestLength(name string) (int, error) { defer C.free(unsafe.Pointer(cname)) md := C.EVP_get_digestbyname(cname) if md == nil { - return 0, errors.New("Invalid digest name") + return 0, GetErrors() } return int(C.EVP_MD_size(md)), nil } @@ -59,12 +57,12 @@ func NewDigestContext(name string, eng *Engine) (*DigestContext, error) { defer C.free(unsafe.Pointer(cname)) md := C.EVP_get_digestbyname(cname) if md == nil { - return nil, fmt.Errorf("shit") + return nil, GetErrors() } ctx := C.EVP_MD_CTX_new() if ctx == nil { - return nil, fmt.Errorf("shit") + return nil, GetErrors() } ret := &DigestContext{ctx} @@ -73,7 +71,7 @@ func NewDigestContext(name string, eng *Engine) (*DigestContext, error) { }) if 1 != C.EVP_DigestInit(ctx, md) { - return nil, fmt.Errorf("shit") + return nil, GetErrors() } return ret, nil @@ -84,16 +82,19 @@ func (ctx *DigestContext) Update(data []byte) error { return nil } if 1 != C.EVP_DigestUpdate(ctx.ctx, unsafe.Pointer(&data[0]), C.size_t(len(data))) { - errors.New("hello") + return GetErrors() } return nil } + + + func (ctx *DigestContext) Final() ([]byte, error) { outbuf := make([]byte, 64) outlen := C.uint(len(outbuf)) if 1 != C.EVP_DigestFinal(ctx.ctx, (*C.uchar)(unsafe.Pointer(&outbuf[0])), &outlen) { - return nil, errors.New("error") + return nil, GetErrors() } return outbuf[:outlen], nil } diff --git a/go/gmssl/engine.go b/go/gmssl/engine.go index caadcff8..0f647c24 100644 --- a/go/gmssl/engine.go +++ b/go/gmssl/engine.go @@ -66,8 +66,7 @@ func GetEngineByName(name string) (*Engine, error) { defer C.free(unsafe.Pointer(cname)) eng := C.ENGINE_by_id(cname) if eng == nil { - cerrors := C.get_errors() - return nil, errors.New(C.GoString(cerrors)) + return nil, GetErrors() } ret := &Engine{eng} runtime.SetFinalizer(ret, func(ret *Engine) { @@ -75,8 +74,7 @@ func GetEngineByName(name string) (*Engine, error) { C.ENGINE_free(ret.engine) }) if 1 != C.ENGINE_init(eng) { - cerrors := C.get_errors() - return nil, errors.New(C.GoString(cerrors)) + return nil, GetErrors() } return ret, nil } @@ -87,8 +85,7 @@ func (e *Engine) RunCommand(name, arg string) error { carg := C.CString(arg) defer C.free(unsafe.Pointer(carg)) if 1 != C.ENGINE_ctrl_cmd_string(e.engine, cname, carg, 0) { - cerrors := C.get_errors() - return errors.New(C.GoString(cerrors)) + return GetErrors() } return nil } @@ -104,8 +101,7 @@ func (e *Engine) GetPrivateKey(id string, pass string) (*PrivateKey, error) { defer C.free(unsafe.Pointer(cpass)) sk := C.load_private_key(e.engine, cid, cpass) if sk == nil { - cerrors := C.get_errors() - return nil, errors.New(C.GoString(cerrors)) + return nil, GetErrors() } return &PrivateKey{sk}, nil } @@ -117,8 +113,7 @@ func (e *Engine) GetPublicKey(id string, pass string) (*PublicKey, error) { defer C.free(unsafe.Pointer(cpass)) pk := C.load_public_key(e.engine, cid, cpass) if pk == nil { - cerrors := C.get_errors() - return nil, errors.New(C.GoString(cerrors)) + return nil, GetErrors() } return &PublicKey{pk}, nil } diff --git a/go/gmssl/mac.go b/go/gmssl/mac.go index 151d0d8d..fd0336db 100644 --- a/go/gmssl/mac.go +++ b/go/gmssl/mac.go @@ -9,10 +9,8 @@ package gmssl import "C" import ( - "errors" - "fmt" - "runtime" "unsafe" + "runtime" ) func GetMacNames(aliases bool) []string { @@ -53,17 +51,19 @@ type MACContext struct { hctx *C.HMAC_CTX } -func NewMACContext(name string, eng *Engine, key []byte) (*MACContext, error) { +func NewMACContext(name string, eng *Engine, key []byte) ( + *MACContext, error) { + cname := C.CString(name) defer C.free(unsafe.Pointer(cname)) md := C.EVP_get_digestbyname(cname) if md == nil { - return nil, fmt.Errorf("shit") + return nil, GetErrors() } ctx := C.HMAC_CTX_new() if ctx == nil { - return nil, fmt.Errorf("shit") + return nil, GetErrors() } ret := &MACContext{ctx} @@ -71,8 +71,9 @@ func NewMACContext(name string, eng *Engine, key []byte) (*MACContext, error) { C.HMAC_CTX_free(ret.hctx) }) - if 1 != C.HMAC_Init_ex(ctx, unsafe.Pointer(&key[0]), C.int(len(key)), md, nil) { - return nil, fmt.Errorf("shit") + if 1 != C.HMAC_Init_ex(ctx, + unsafe.Pointer(&key[0]), C.int(len(key)), md, nil) { + return nil, GetErrors() } return ret, nil @@ -82,8 +83,9 @@ func (ctx *MACContext) Update(data []byte) error { if len(data) == 0 { return nil } - if 1 != C.HMAC_Update(ctx.hctx, (*C.uchar)(unsafe.Pointer(&data[0])), C.size_t(len(data))) { - return errors.New("hello") + if 1 != C.HMAC_Update(ctx.hctx, + (*C.uchar)(unsafe.Pointer(&data[0])), C.size_t(len(data))) { + return GetErrors() } return nil } @@ -91,8 +93,9 @@ func (ctx *MACContext) Update(data []byte) error { func (ctx *MACContext) Final() ([]byte, error) { outbuf := make([]byte, 64) outlen := C.uint(len(outbuf)) - if 1 != C.HMAC_Final(ctx.hctx, (*C.uchar)(unsafe.Pointer(&outbuf[0])), &outlen) { - return nil, errors.New("error") + if 1 != C.HMAC_Final(ctx.hctx, + (*C.uchar)(unsafe.Pointer(&outbuf[0])), &outlen) { + return nil, GetErrors() } return outbuf[:outlen], nil } diff --git a/go/gmssl/rand.go b/go/gmssl/rand.go index 8e6fe169..ede21259 100644 --- a/go/gmssl/rand.go +++ b/go/gmssl/rand.go @@ -7,7 +7,6 @@ package gmssl import "C" import ( - "errors" "unsafe" ) @@ -19,7 +18,7 @@ func SeedRandom(seed []byte) error { func GenerateRandom(length int) ([]byte, error) { outbuf := make([]byte, length) if C.RAND_bytes((*C.uchar)(&outbuf[0]), C.int(length)) <= 0 { - return nil, errors.New("GmSSL Failure") + return nil, GetErrors() } return outbuf[:length], nil diff --git a/go/gmssl/version.go b/go/gmssl/version.go index 22c94a54..88dc29cc 100644 --- a/go/gmssl/version.go +++ b/go/gmssl/version.go @@ -7,8 +7,8 @@ package gmssl import "C" func GetVersions() []string { - versions := []string{ - "GmSSL Go API 1.1 Mar 31 2018", + versions := []string { + "GmSSL Go API 1.2 July 15 2018", C.GoString(C.OpenSSL_version(C.OPENSSL_VERSION)), C.GoString(C.OpenSSL_version(C.OPENSSL_BUILT_ON)), C.GoString(C.OpenSSL_version(C.OPENSSL_CFLAGS)),