blob: feabf2a1933203c4a96f57b448d7b3199f3a2204 [file] [log] [blame]
//Copyright 2017 Huawei Technologies Co., Ltd
//
//Licensed under the Apache License, Version 2.0 (the "License");
//you may not use this file except in compliance with the License.
//You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
//Unless required by applicable law or agreed to in writing, software
//distributed under the License is distributed on an "AS IS" BASIS,
//WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
//See the License for the specific language governing permissions and
//limitations under the License.
package rest
import (
"crypto/tls"
"crypto/x509"
"encoding/pem"
"github.com/ServiceComb/service-center/pkg/common"
"github.com/ServiceComb/service-center/pkg/security"
"github.com/ServiceComb/service-center/util"
"github.com/astaxie/beego"
"io/ioutil"
"time"
)
const (
DEFAULT_TLS_HANDSHAKE_TIMEOUT = 30 * time.Second
DEFAULT_HTTP_RESPONSE_TIMEOUT = 60 * time.Second
)
const HTTP_ERROR_STATUS_CODE = 600
const (
HTTP_METHOD_GET = "GET"
HTTP_METHOD_PUT = "PUT"
HTTP_METHOD_POST = "POST"
HTTP_METHOD_DELETE = "DELETE"
)
func isValidMethod(method string) bool {
switch method {
case HTTP_METHOD_GET, HTTP_METHOD_PUT, HTTP_METHOD_POST, HTTP_METHOD_DELETE:
return true
default:
return false
}
}
func getX509CACertPool() (caCertPool *x509.CertPool, err error) {
pool := x509.NewCertPool()
caCertFile := common.GetServerSSLConfig().CACertFile
caCert, err := ioutil.ReadFile(caCertFile)
if err != nil {
util.LOGGER.Errorf(err, "read ca cert file %s failed.", caCertFile)
return nil, err
}
pool.AppendCertsFromPEM(caCert)
return pool, nil
}
func loadTLSCertificate() (tlsCert []tls.Certificate, err error) {
certFile, keyFile := common.GetServerSSLConfig().CertFile, common.GetServerSSLConfig().KeyFile
passphase := common.GetServerSSLConfig().KeyPassphase
plainPassphase, err := security.CipherPlugins[beego.AppConfig.DefaultString("cipher_plugin", "default")]().Decrypt(passphase)
if err != nil {
util.LOGGER.Errorf(err, "decrypt ssl passphase(%d) failed.", len(passphase))
plainPassphase = ""
}
certContent, err := ioutil.ReadFile(certFile)
if err != nil {
util.LOGGER.Errorf(err, "read cert file %s failed.", certFile)
return nil, err
}
keyContent, err := ioutil.ReadFile(keyFile)
if err != nil {
util.LOGGER.Errorf(err, "read key file %s failed.", keyFile)
return nil, err
}
keyBlock, _ := pem.Decode(keyContent)
if keyBlock == nil {
util.LOGGER.Errorf(err, "decode key file %s failed.", keyFile)
return nil, err
}
if x509.IsEncryptedPEMBlock(keyBlock) {
plainPassphaseBytes := []byte(plainPassphase)
keyData, err := x509.DecryptPEMBlock(keyBlock, plainPassphaseBytes)
util.ClearStringMemory(&plainPassphase)
util.ClearByteMemory(plainPassphaseBytes)
if err != nil {
util.LOGGER.Errorf(err, "decrypt key file %s failed.", keyFile)
return nil, err
}
// 解密成功,重新编码为PEM格式的文件
plainKeyBlock := &pem.Block{
Type: "RSA PRIVATE KEY",
Bytes: keyData,
}
keyContent = pem.EncodeToMemory(plainKeyBlock)
}
cert, err := tls.X509KeyPair(certContent, keyContent)
if err != nil {
util.LOGGER.Errorf(err, "load X509 key pair from cert file %s with key file %s failed.", certFile, keyFile)
return nil, err
}
var certs []tls.Certificate
certs = append(certs, cert)
return certs, nil
}
/**
verifyPeer Whether verify client
supplyCert Whether send certificate
verifyCN Whether verify CommonName
*/
func GetClientTLSConfig(verifyPeer bool, supplyCert bool, verifyCN bool) (tlsConfig *tls.Config, err error) {
var pool *x509.CertPool = nil
var certs []tls.Certificate
if verifyPeer {
pool, err = getX509CACertPool()
if err != nil {
return nil, err
}
}
if supplyCert {
certs, err = loadTLSCertificate()
if err != nil {
return nil, err
}
}
tlsConfig = &tls.Config{
RootCAs: pool,
Certificates: certs,
CipherSuites: common.GetClientSSLConfig().CipherSuites,
InsecureSkipVerify: !verifyCN,
MinVersion: common.GetClientSSLConfig().MinVersion,
MaxVersion: common.GetClientSSLConfig().MaxVersion,
}
return tlsConfig, nil
}
func GetServerTLSConfig(verifyPeer bool) (tlsConfig *tls.Config, err error) {
clientAuthMode := tls.NoClientCert
var pool *x509.CertPool = nil
if verifyPeer {
pool, err = getX509CACertPool()
if err != nil {
return nil, err
}
clientAuthMode = tls.RequireAndVerifyClientCert
}
var certs []tls.Certificate
certs, err = loadTLSCertificate()
if err != nil {
return nil, err
}
tlsConfig = &tls.Config{
ClientCAs: pool,
Certificates: certs,
CipherSuites: common.GetServerSSLConfig().CipherSuites,
PreferServerCipherSuites: true,
ClientAuth: clientAuthMode,
MinVersion: common.GetServerSSLConfig().MinVersion,
MaxVersion: common.GetServerSSLConfig().MaxVersion,
}
return tlsConfig, nil
}
func GetClient(communiType string) (*HttpClient, error) {
verifyClient := false
var err error
var client *HttpClient
//client, err = rest.GetHttpsClient(verifyClient)
if communiType == "https" {
client, err = GetAnnoHttpsClient(verifyClient)
if err != nil {
util.LOGGER.Error("Create https rest.client failed.", err)
return nil, err
}
return client, nil
}
client, err = GetHttpClient(true)
if err != nil {
util.LOGGER.Error("Create http rest.client failed.", err)
return nil, err
}
return client, nil
}