Skip to content

Commit

Permalink
Merge pull request #7 from tianxiaoliang/master
Browse files Browse the repository at this point in the history
improvement: RFC 1423 is insecure, support load tls cert without password
  • Loading branch information
tianxiaoliang authored Mar 1, 2021
2 parents 958cbfa + e00e40e commit 538233c
Show file tree
Hide file tree
Showing 6 changed files with 122 additions and 39 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/golangci-lint.yml
Original file line number Diff line number Diff line change
Expand Up @@ -16,4 +16,4 @@ jobs:
uses: golangci/golangci-lint-action@v2
with:
version: v1.29
args: --skip-dirs=examples --out-format=colored-line-number --skip-files=.*_test.go$
args: --skip-dirs=examples,tls --out-format=colored-line-number --skip-files=.*_test.go$
4 changes: 2 additions & 2 deletions .github/workflows/static_check.yml
Original file line number Diff line number Diff line change
Expand Up @@ -5,10 +5,10 @@ jobs:
name: Merge check
runs-on: ubuntu-latest
steps:
- name: Set up Go 1.13
- name: Set up Go
uses: actions/setup-go@v1
with:
go-version: 1.13
go-version: 1.16
id: go
- name: UT
uses: actions/checkout@v1
Expand Down
5 changes: 4 additions & 1 deletion security/cipher.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,13 @@
* limitations under the License.
*/

// Package security is deprecated plz use github.com/go-chassis/cari/security
// Package security is deprecated
// Deprecated: use github.com/go-chassis/cari/security
package security

//Cipher interface declares two function for encryption and decryption
//
// Deprecated: use github.com/go-chassis/cari/security
type Cipher interface {
Encrypt(src string) (string, error)

Expand Down
8 changes: 8 additions & 0 deletions string/string.go
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import (
)

// Deprecated StringInSlice convert string to bool
// Deprecated: use github.com/go-chassis/foundation/stringutil
func StringInSlice(a string, list []string) bool {
for _, b := range list {
if b == a {
Expand All @@ -17,18 +18,21 @@ func StringInSlice(a string, list []string) bool {
}

// Deprecated Str2bytes convert string to array of byte
// Deprecated: use github.com/go-chassis/foundation/stringutil
func Str2bytes(s string) []byte {
x := (*[2]uintptr)(unsafe.Pointer(&s))
h := [3]uintptr{x[0], x[1], x[1]}
return *(*[]byte)(unsafe.Pointer(&h))
}

// Deprecated Bytes2str convert array of byte to string
// Deprecated: use github.com/go-chassis/foundation/stringutil
func Bytes2str(b []byte) string {
return *(*string)(unsafe.Pointer(&b))
}

// Deprecated SplitToTwo split the string
// Deprecated: use github.com/go-chassis/foundation/stringutil
func SplitToTwo(s, sep string) (string, string) {
index := strings.Index(s, sep)
if index < 0 {
Expand All @@ -38,6 +42,7 @@ func SplitToTwo(s, sep string) (string, string) {
}

// Deprecated SplitFirstSep split the string
// Deprecated: use github.com/go-chassis/foundation/stringutil
func SplitFirstSep(s, sep string) string {
index := strings.Index(s, sep)
if index < 0 {
Expand All @@ -47,6 +52,7 @@ func SplitFirstSep(s, sep string) string {
}

// Deprecated MinInt check the minimum value of two integers
// Deprecated: use github.com/go-chassis/foundation/stringutil
func MinInt(x, y int) int {
if x <= y {
return x
Expand All @@ -57,6 +63,7 @@ func MinInt(x, y int) int {

// Deprecated ClearStringMemory clear string memory, for very sensitive security related data
//you should clear it in memory after use
// Deprecated: use github.com/go-chassis/foundation/stringutil
func ClearStringMemory(src *string) {
p := (*struct {
ptr uintptr
Expand All @@ -74,6 +81,7 @@ func ClearStringMemory(src *string) {

// Deprecated ClearByteMemory clear byte memory, for very sensitive security related data
//you should clear it in memory after use
// Deprecated: use github.com/go-chassis/foundation/stringutil
func ClearByteMemory(src []byte) {
len := MinInt(len(src), 32)
for idx := 0; idx < len; idx = idx + 1 {
Expand Down
53 changes: 25 additions & 28 deletions tlsutil/tls.go
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
)
Expand All @@ -24,50 +23,48 @@ func GetX509CACertPool(caCertFile string) (*x509.CertPool, error) {
}

//LoadTLSCertificate is a function used to load a certificate
func LoadTLSCertificate(certFile, keyFile, passphase string, decrypt Decrypt) ([]tls.Certificate, error) {
// RFC 1423 is insecure, password and decrypt is not required
func LoadTLSCertificate(certFile, keyFile, password string, decrypt Decrypt) ([]tls.Certificate, error) {
certContent, err := ioutil.ReadFile(certFile)
if err != nil {
errorMsg := "read cert file" + certFile + "failed."
return nil, errors.New(errorMsg)
return nil, err
}

keyContent, err := ioutil.ReadFile(keyFile)
if err != nil {
errorMsg := "read key file" + keyFile + "failed."
return nil, errors.New(errorMsg)
return nil, err
}

keyBlock, _ := pem.Decode(keyContent)
if keyBlock == nil {
errorMsg := "decode key file " + keyFile + " failed"
return nil, errors.New(errorMsg)
}

plainpass, err := decrypt(passphase)
if err != nil {
return nil, err
return nil, fmt.Errorf("decrypt key file "+keyFile+" failed: %w", err)
}

if x509.IsEncryptedPEMBlock(keyBlock) {
keyData, err := x509.DecryptPEMBlock(keyBlock, []byte(plainpass))
if err != nil {
errorMsg := "decrypt key file " + keyFile + " failed."
return nil, errors.New(errorMsg)
if password != "" {
var plainpass string
if decrypt != nil {
plainpass, err = decrypt(password)
if err != nil {
return nil, err
}
}
if x509.IsEncryptedPEMBlock(keyBlock) {
keyData, err := x509.DecryptPEMBlock(keyBlock, []byte(plainpass))
if err != nil {
return nil, fmt.Errorf("decrypt key file "+keyFile+" failed. err: %w", err)
}

// 解密成功,重新编码为无加密的PEM格式文件
plainKeyBlock := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: keyData,
}
// 解密成功,重新编码为无加密的PEM格式文件
keyBlock = &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: keyData,
}

keyContent = pem.EncodeToMemory(plainKeyBlock)
}
}

keyContent = pem.EncodeToMemory(keyBlock)
cert, err := tls.X509KeyPair(certContent, keyContent)
if err != nil {
errorMsg := "load X509 key pair from cert file " + certFile + " with key file " + keyFile + " failed."
return nil, errors.New(errorMsg)
return nil, fmt.Errorf("load cert failed:%w", err)
}

var certs []tls.Certificate
Expand Down
89 changes: 82 additions & 7 deletions tlsutil/tls_test.go
Original file line number Diff line number Diff line change
@@ -1,16 +1,91 @@
package tlsutil_test

import (
"testing"

"github.com/go-chassis/foundation/tlsutil"
"github.com/stretchr/testify/assert"
"io"
"os"
"path/filepath"
"testing"
)

func TestLoadTLSCertificateFileNotExist(t *testing.T) {
tlsCert, err := tlsutil.LoadTLSCertificate("abc.txt", "abc.txt", "fakepassphase", func(src string) (s string, err error) {
return "fakepassphase", nil
var rsaCertPEM = `-----BEGIN CERTIFICATE-----
MIIDXTCCAkWgAwIBAgIJANq58YD5coE2MA0GCSqGSIb3DQEBCwUAMEUxCzAJBgNV
BAYTAkFVMRMwEQYDVQQIDApTb21lLVN0YXRlMSEwHwYDVQQKDBhJbnRlcm5ldCBX
aWRnaXRzIFB0eSBMdGQwHhcNMjEwMzAxMDQzMDAzWhcNMjEwMzMxMDQzMDAzWjBF
MQswCQYDVQQGEwJBVTETMBEGA1UECAwKU29tZS1TdGF0ZTEhMB8GA1UECgwYSW50
ZXJuZXQgV2lkZ2l0cyBQdHkgTHRkMIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIB
CgKCAQEAySqpnHOj42/LcGguAIj/ZYDb96ccdAjhuSgScWnOiF2obMVuBxAkaYRa
IcBvphv2N6dCs/AiOzwhyi7d4X82NQ5ftMBjzEHZaRCXQtS2JLHmNi4iuA5GHN0Z
EjinwXeT8ZsJP1wIHtnqF7D8PZdhS8V/SYimx4ejYG3J/+AIDU4YYyb14/3jjVzy
X4UnMy1igPbPtx6CbjNxUaVCmy4RUbrLwYdY1k+QbGguhfk4YERiV0P5W2pZzVqn
9rjvrEdFn0lgyRjNqvsRVneEcd7Y+OqgXvB69wiFrEeoEq/qbsDYQNFEm30Bx0wi
cbqMMYsuZTDRcXPz8gveyjNw0E2zDQIDAQABo1AwTjAdBgNVHQ4EFgQUGL3vXIio
1B7uvqGmzTXNaDZ/u7YwHwYDVR0jBBgwFoAUGL3vXIio1B7uvqGmzTXNaDZ/u7Yw
DAYDVR0TBAUwAwEB/zANBgkqhkiG9w0BAQsFAAOCAQEAAjBY2o/Jyh6MLo4DletW
PyS/8f46HMWo8kPTeZ77oh7iJNnpzbI4pgJ5yVTR4RqAj25ibSE0UuOrRRAgEWzT
5Y4C0r+XZghxyt9XET2RSC+BJxm4rC+bvsIIE0fNgX21o5hhSfSBpIl5NZOdVIbw
3VkvFi2hOtViVRxkk28SdvymDgDYU6djixf3qGYlvE+YSMUfDNFflxLWNCRXOyK0
9YLSOLZyaX8VkENVSZb3OmSDQoCTpnmrVEKHp4OcjbqfKB2o1bvREJ4CRBHmGMgd
pkM+Xeu/qofei+ekZsGLIaceM+cSV4w42vaHdwC5HkTpV4fIaGHEwsI8FD7aWKrU
eA==
-----END CERTIFICATE-----
`

var rsaKeyPEM = []byte(`-----BEGIN RSA PRIVATE KEY-----
MIIEpgIBAAKCAQEAySqpnHOj42/LcGguAIj/ZYDb96ccdAjhuSgScWnOiF2obMVu
BxAkaYRaIcBvphv2N6dCs/AiOzwhyi7d4X82NQ5ftMBjzEHZaRCXQtS2JLHmNi4i
uA5GHN0ZEjinwXeT8ZsJP1wIHtnqF7D8PZdhS8V/SYimx4ejYG3J/+AIDU4YYyb1
4/3jjVzyX4UnMy1igPbPtx6CbjNxUaVCmy4RUbrLwYdY1k+QbGguhfk4YERiV0P5
W2pZzVqn9rjvrEdFn0lgyRjNqvsRVneEcd7Y+OqgXvB69wiFrEeoEq/qbsDYQNFE
m30Bx0wicbqMMYsuZTDRcXPz8gveyjNw0E2zDQIDAQABAoIBAQC3Yoz8cu8UhvWO
o2pMUpeAkNf2DAGERhSAFme5vBrrdXX0soZ7KdwH1P/VhPhDFXp/gZrtLhwGo+qp
xc+/oZhpBZF51Wkk62KmxNkfs4nYKdUTzzsXTuvbpDMWyU8krz3PIuZrPBqrBTzC
HDXWcAniaUiAYHKpspzdaziaakDs3obT5grtg6UNB/s/mPBrvHH9ftmolOBOxLhH
rvNxoCyP/tAB8AW1AJ6g3TSK1SANPgqzROe0X0ZHzW1T6/bZAC3OPA2PdhhnkdjN
zH2OLu3cU1Ybgtku/Ce7/AO1yKX2qdTn3v9iO0xO8swqAetepAqk8RKhfx0w61yc
Nugyya6BAoGBAOW5IzpB9USbTTzDuvVBBTS1e4OJRmkkR9KtZTfLNjVY7aY1mhrl
/Fi3JX+qPT9OsLyiRq9/UKuNcVeBYiVamBV4eBtmYqivOnnMe6P8V20RCWmhgZqw
2nyQfgIVFgSnTOlVdg5YD+GXptnfl/pqO2f2Pl4vQdM/nemyIk/HodgPAoGBAOAt
UZ8HTTzVnzyjPq1VGe2mQBmwC1fMkpmD2/d56TIDT4vVbAsu9ge106mdB52ZvlNc
nkl6KvsBcCXyJT6S/bpOINFViFAvigRpmez1rmFMqBf2OvTnELtlZ3kTn8/X1uIX
bFIX2G1XAKAQ6MBCYLzvCLMTf+EkebENA4kQr0cjAoGBAJrdfY8nqgYvQBmHxgDS
bYUEF5ksMQhuifDQLh035HqAUe2r0xDxHHZeOWxgQtvr25+/MjHbfXG5b8BTG+wc
r8xBo46tLjOTtbMok+2QDwwa4SKR24KCWTiCXEBhIK/QbTwb/fNbkJE/oB7e6mDJ
vvSt/4uVBiY4i+dgzFrGNSgnAoGBAJ/RbzkSuYu/N/DA6LQl0YBNX7FwggWsAG+V
Q8JglVFkbtdf5dDrP9crV6S6IG3I55kClI4JnI6p7cv/n3HG1UB25oqWkcGowpp2
tpfqZtFTFxtOHaXu/Uy79FKrHOnOFJHG5SB5g4Af4IA8zdITAGhxeSBBrI9Ts7X3
cyfKT0tFAoGBAJvS+AZK93SLYvsRdyytevKuYMAqIO+YRBOfZ+NN9+vosGlzbmuj
8zHkQQ8yeMJASbTpEAakz2ybJeN5zNELMKGUrsGVefiW0Z/5skO2toeF1PWtF0G8
FF2uvhCC6xWFT/PzYycBYMzq6gUus3aJQ+wjFnEflZYj7wGzf4tGzA5I
-----END RSA PRIVATE KEY-----
`)

func TestLoadTLSCertificate(t *testing.T) {
td := t.TempDir()
f1, err := os.Create(filepath.Join(td, "key.pem"))
assert.NoError(t, err)
defer f1.Close()
_, err = io.WriteString(f1, string(rsaKeyPEM))
assert.NoError(t, err)

f2, err := os.Create(filepath.Join(td, "cert.pem"))
assert.NoError(t, err)
defer f1.Close()
_, err = io.WriteString(f2, rsaCertPEM)
assert.NoError(t, err)

t.Run("given no file,should failed", func(t *testing.T) {
tlsCert, err := tlsutil.LoadTLSCertificate("abc.txt", "abc.txt", "fakepassphase", func(src string) (s string, err error) {
return "fakepassphase", nil
})
assert.Nil(t, tlsCert)
assert.Error(t, err)
})
t.Run("given rsa key pair,should success", func(t *testing.T) {
tlsCert, err := tlsutil.LoadTLSCertificate(f2.Name(), f1.Name(), "", nil)
assert.NotNil(t, tlsCert)
assert.NoError(t, err)
})
assert.Nil(t, tlsCert)
assert.Error(t, err)
}

0 comments on commit 538233c

Please sign in to comment.