Adding TLS authentication
[icn.git] / cmd / bpa-restapi-agent / internal / auth / auth.go
diff --git a/cmd/bpa-restapi-agent/internal/auth/auth.go b/cmd/bpa-restapi-agent/internal/auth/auth.go
new file mode 100644 (file)
index 0000000..3da8f2a
--- /dev/null
@@ -0,0 +1,107 @@
+/*
+ * Copyright 2018 Intel Corporation, Inc
+ *
+ * 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 auth
+
+import (
+       "crypto/tls"
+       "crypto/x509"
+       "encoding/base64"
+       "encoding/pem"
+       "io/ioutil"
+       "log"
+
+       pkgerrors "github.com/pkg/errors"
+)
+
+// GetTLSConfig initializes a tlsConfig using the CA's certificate
+// This config is then used to enable the server for mutual TLS
+func GetTLSConfig(caCertFile string, certFile string, keyFile string) (*tls.Config, error) {
+
+       // Initialize tlsConfig once
+       caCert, err := ioutil.ReadFile(caCertFile)
+
+       if err != nil {
+               return nil, pkgerrors.Wrap(err, "Read CA Cert file")
+       }
+
+       caCertPool := x509.NewCertPool()
+       caCertPool.AppendCertsFromPEM(caCert)
+
+       tlsConfig := &tls.Config{
+               // Change to RequireAndVerify once we have mandatory certs
+               ClientAuth: tls.VerifyClientCertIfGiven,
+               ClientCAs:  caCertPool,
+               MinVersion: tls.VersionTLS12,
+       }
+
+       certPEMBlk, err := readPEMBlock(certFile)
+       if err != nil {
+               return nil, pkgerrors.Wrap(err, "Read Cert File")
+       }
+
+       keyPEMBlk, err := readPEMBlock(keyFile)
+       if err != nil {
+               return nil, pkgerrors.Wrap(err, "Read Key File")
+       }
+
+       tlsConfig.Certificates = make([]tls.Certificate, 1)
+       tlsConfig.Certificates[0], err = tls.X509KeyPair(certPEMBlk, keyPEMBlk)
+       if err != nil {
+               return nil, pkgerrors.Wrap(err, "Load x509 cert and key")
+       }
+
+       tlsConfig.BuildNameToCertificate()
+       return tlsConfig, nil
+}
+
+func readPEMBlock(filename string) ([]byte, error) {
+
+       pemData, err := ioutil.ReadFile(filename)
+       if err != nil {
+               return nil, pkgerrors.Wrap(err, "Read PEM File")
+       }
+
+       pemBlock, rest := pem.Decode(pemData)
+       if len(rest) > 0 {
+               log.Println("Pemfile has extra data")
+       }
+
+       if x509.IsEncryptedPEMBlock(pemBlock) {
+               password, err := ioutil.ReadFile(filename + ".pass")
+               if err != nil {
+                       return nil, pkgerrors.Wrap(err, "Read Password File")
+               }
+
+               pByte, err := base64.StdEncoding.DecodeString(string(password))
+               if err != nil {
+                       return nil, pkgerrors.Wrap(err, "Decode PEM Password")
+               }
+
+               pemData, err = x509.DecryptPEMBlock(pemBlock, pByte)
+               if err != nil {
+                       return nil, pkgerrors.Wrap(err, "Decrypt PEM Data")
+               }
+               var newPEMBlock pem.Block
+               newPEMBlock.Type = pemBlock.Type
+               newPEMBlock.Bytes = pemData
+               // Converting back to PEM from DER data you get from
+               // DecryptPEMBlock
+               pemData = pem.EncodeToMemory(&newPEMBlock)
+       }
+
+       return pemData, nil
+}