Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Protect GO_EVP_CIPHER_CTX_PTR with sync.Mutex #145

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
25 changes: 22 additions & 3 deletions cipher.go
Original file line number Diff line number Diff line change
Expand Up @@ -145,7 +145,9 @@ func loadCipher(k cipherKind, mode cipherMode) (cipher C.GO_EVP_CIPHER_PTR) {

type evpCipher struct {
key []byte
encLock sync.Mutex
enc_ctx C.GO_EVP_CIPHER_CTX_PTR
decLock sync.Mutex
dec_ctx C.GO_EVP_CIPHER_CTX_PTR
kind cipherKind
blockSize int
Expand Down Expand Up @@ -184,6 +186,8 @@ func (c *evpCipher) encrypt(dst, src []byte) error {
if inexactOverlap(dst[:c.blockSize], src[:c.blockSize]) {
return errors.New("invalid buffer overlap")
}
c.encLock.Lock()
defer c.encLock.Unlock()
if c.enc_ctx == nil {
var err error
c.enc_ctx, err = newCipherCtx(c.kind, cipherModeECB, cipherOpEncrypt, c.key, nil)
Expand Down Expand Up @@ -211,6 +215,8 @@ func (c *evpCipher) decrypt(dst, src []byte) error {
if inexactOverlap(dst[:c.blockSize], src[:c.blockSize]) {
return errors.New("invalid buffer overlap")
}
c.decLock.Lock()
defer c.decLock.Unlock()
if c.dec_ctx == nil {
var err error
c.dec_ctx, err = newCipherCtx(c.kind, cipherModeECB, cipherOpDecrypt, c.key, nil)
Expand All @@ -229,6 +235,7 @@ func (c *evpCipher) decrypt(dst, src []byte) error {

type cipherCBC struct {
ctx C.GO_EVP_CIPHER_CTX_PTR
ctxLock sync.Mutex
blockSize int
}

Expand All @@ -249,6 +256,8 @@ func (x *cipherCBC) CryptBlocks(dst, src []byte) {
panic("crypto/cipher: output smaller than input")
}
if len(src) > 0 {
x.ctxLock.Lock()
defer x.ctxLock.Unlock()
if C.go_openssl_EVP_CipherUpdate_wrapper(x.ctx, base(dst), base(src), C.int(len(src))) != 1 {
panic("crypto/cipher: CipherUpdate failed")
}
Expand All @@ -260,6 +269,8 @@ func (x *cipherCBC) SetIV(iv []byte) {
if len(iv) != x.blockSize {
panic("cipher: incorrect length IV")
}
x.ctxLock.Lock()
defer x.ctxLock.Unlock()
if C.go_openssl_EVP_CipherInit_ex(x.ctx, nil, nil, nil, base(iv), C.int(cipherOpNone)) != 1 {
panic("cipher: unable to initialize EVP cipher ctx")
}
Expand All @@ -279,7 +290,8 @@ func (c *evpCipher) newCBC(iv []byte, op cipherOp) cipher.BlockMode {
}

type cipherCTR struct {
ctx C.GO_EVP_CIPHER_CTX_PTR
ctx C.GO_EVP_CIPHER_CTX_PTR
ctxLock sync.Mutex
}

func (x *cipherCTR) XORKeyStream(dst, src []byte) {
Expand All @@ -292,6 +304,8 @@ func (x *cipherCTR) XORKeyStream(dst, src []byte) {
if len(src) == 0 {
return
}
x.ctxLock.Lock()
defer x.ctxLock.Unlock()
if C.go_openssl_EVP_EncryptUpdate_wrapper(x.ctx, base(dst), base(src), C.int(len(src))) != 1 {
panic("crypto/cipher: EncryptUpdate failed")
}
Expand Down Expand Up @@ -321,8 +335,9 @@ const (
)

type cipherGCM struct {
ctx C.GO_EVP_CIPHER_CTX_PTR
tls cipherGCMTLS
ctx C.GO_EVP_CIPHER_CTX_PTR
ctxLock sync.Mutex
tls cipherGCMTLS
// minNextNonce is the minimum value that the next nonce can be, enforced by
// all TLS modes.
minNextNonce uint64
Expand Down Expand Up @@ -471,6 +486,8 @@ func (g *cipherGCM) Seal(dst, nonce, plaintext, additionalData []byte) []byte {
// relying in the explicit nonce being securely set externally,
// and it also gives some interesting speed gains.
// Unfortunately we can't use it because Go expects AEAD.Seal to honor the provided nonce.
g.ctxLock.Lock()
defer g.ctxLock.Unlock()
if C.go_openssl_EVP_CIPHER_CTX_seal_wrapper(g.ctx, base(out), base(nonce),
base(plaintext), C.int(len(plaintext)),
base(additionalData), C.int(len(additionalData))) != 1 {
Expand Down Expand Up @@ -506,6 +523,8 @@ func (g *cipherGCM) Open(dst, nonce, ciphertext, additionalData []byte) ([]byte,
panic("cipher: invalid buffer overlap")
}

g.ctxLock.Lock()
defer g.ctxLock.Unlock()
ok := C.go_openssl_EVP_CIPHER_CTX_open_wrapper(
g.ctx, base(out), base(nonce),
base(ciphertext), C.int(len(ciphertext)),
Expand Down
14 changes: 11 additions & 3 deletions rc4.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,10 @@ package openssl

// #include "goopenssl.h"
import "C"
import "runtime"
import (
"runtime"
"sync"
)

// SupportsRC4 returns true if NewRC4Cipher is supported.
func SupportsRC4() bool {
Expand All @@ -15,7 +18,8 @@ func SupportsRC4() bool {

// A RC4Cipher is an instance of RC4 using a particular key.
type RC4Cipher struct {
ctx C.GO_EVP_CIPHER_CTX_PTR
ctx C.GO_EVP_CIPHER_CTX_PTR
ctxLock sync.Mutex
}

// NewRC4Cipher creates and returns a new Cipher.
Expand All @@ -24,7 +28,7 @@ func NewRC4Cipher(key []byte) (*RC4Cipher, error) {
if err != nil {
return nil, err
}
c := &RC4Cipher{ctx}
c := &RC4Cipher{ctx: ctx}
runtime.SetFinalizer(c, (*RC4Cipher).finalize)
return c, nil
}
Expand All @@ -37,6 +41,8 @@ func (c *RC4Cipher) finalize() {

// Reset zeros the key data and makes the Cipher unusable.
func (c *RC4Cipher) Reset() {
c.ctxLock.Lock()
defer c.ctxLock.Unlock()
if c.ctx != nil {
C.go_openssl_EVP_CIPHER_CTX_free(c.ctx)
c.ctx = nil
Expand All @@ -54,6 +60,8 @@ func (c *RC4Cipher) XORKeyStream(dst, src []byte) {
}
// panic if len(dst) < len(src) with a runtime out of bound error,
// which is what crypto/rc4 does.
c.ctxLock.Lock()
defer c.ctxLock.Unlock()
_ = dst[len(src)-1]
var outLen C.int
if C.go_openssl_EVP_EncryptUpdate(c.ctx, base(dst), &outLen, base(src), C.int(len(src))) != 1 {
Expand Down