Adding TLS authentication
[icn.git] / cmd / bpa-restapi-agent / internal / auth / auth.go
1 /*
2  * Copyright 2018 Intel Corporation, Inc
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16
17 package auth
18
19 import (
20         "crypto/tls"
21         "crypto/x509"
22         "encoding/base64"
23         "encoding/pem"
24         "io/ioutil"
25         "log"
26
27         pkgerrors "github.com/pkg/errors"
28 )
29
30 // GetTLSConfig initializes a tlsConfig using the CA's certificate
31 // This config is then used to enable the server for mutual TLS
32 func GetTLSConfig(caCertFile string, certFile string, keyFile string) (*tls.Config, error) {
33
34         // Initialize tlsConfig once
35         caCert, err := ioutil.ReadFile(caCertFile)
36
37         if err != nil {
38                 return nil, pkgerrors.Wrap(err, "Read CA Cert file")
39         }
40
41         caCertPool := x509.NewCertPool()
42         caCertPool.AppendCertsFromPEM(caCert)
43
44         tlsConfig := &tls.Config{
45                 // Change to RequireAndVerify once we have mandatory certs
46                 ClientAuth: tls.VerifyClientCertIfGiven,
47                 ClientCAs:  caCertPool,
48                 MinVersion: tls.VersionTLS12,
49         }
50
51         certPEMBlk, err := readPEMBlock(certFile)
52         if err != nil {
53                 return nil, pkgerrors.Wrap(err, "Read Cert File")
54         }
55
56         keyPEMBlk, err := readPEMBlock(keyFile)
57         if err != nil {
58                 return nil, pkgerrors.Wrap(err, "Read Key File")
59         }
60
61         tlsConfig.Certificates = make([]tls.Certificate, 1)
62         tlsConfig.Certificates[0], err = tls.X509KeyPair(certPEMBlk, keyPEMBlk)
63         if err != nil {
64                 return nil, pkgerrors.Wrap(err, "Load x509 cert and key")
65         }
66
67         tlsConfig.BuildNameToCertificate()
68         return tlsConfig, nil
69 }
70
71 func readPEMBlock(filename string) ([]byte, error) {
72
73         pemData, err := ioutil.ReadFile(filename)
74         if err != nil {
75                 return nil, pkgerrors.Wrap(err, "Read PEM File")
76         }
77
78         pemBlock, rest := pem.Decode(pemData)
79         if len(rest) > 0 {
80                 log.Println("Pemfile has extra data")
81         }
82
83         if x509.IsEncryptedPEMBlock(pemBlock) {
84                 password, err := ioutil.ReadFile(filename + ".pass")
85                 if err != nil {
86                         return nil, pkgerrors.Wrap(err, "Read Password File")
87                 }
88
89                 pByte, err := base64.StdEncoding.DecodeString(string(password))
90                 if err != nil {
91                         return nil, pkgerrors.Wrap(err, "Decode PEM Password")
92                 }
93
94                 pemData, err = x509.DecryptPEMBlock(pemBlock, pByte)
95                 if err != nil {
96                         return nil, pkgerrors.Wrap(err, "Decrypt PEM Data")
97                 }
98                 var newPEMBlock pem.Block
99                 newPEMBlock.Type = pemBlock.Type
100                 newPEMBlock.Bytes = pemData
101                 // Converting back to PEM from DER data you get from
102                 // DecryptPEMBlock
103                 pemData = pem.EncodeToMemory(&newPEMBlock)
104         }
105
106         return pemData, nil
107 }