blob: 52196ced1cd87db56e1f63abbb11275efeacff86 [file] [log] [blame]
Lorenz Brunaa6b7342019-12-12 02:55:02 +01001// Copyright 2020 The Monogon Project Authors.
2//
3// SPDX-License-Identifier: Apache-2.0
4//
5// Licensed under the Apache License, Version 2.0 (the "License");
6// you may not use this file except in compliance with the License.
7// You may obtain a copy of the License at
8//
9// http://www.apache.org/licenses/LICENSE-2.0
10//
11// Unless required by applicable law or agreed to in writing, software
12// distributed under the License is distributed on an "AS IS" BASIS,
13// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14// See the License for the specific language governing permissions and
15// limitations under the License.
16
17package integrity
18
19import (
20 "bytes"
21 "crypto/tls"
22 "crypto/x509"
23 "errors"
24 "fmt"
25 "net"
26 "strings"
27
Lorenz Brunaa6b7342019-12-12 02:55:02 +010028 "google.golang.org/grpc"
29 "google.golang.org/grpc/credentials"
Hendrik Hofstadt8efe51e2020-02-28 12:53:41 +010030
31 "git.monogon.dev/source/nexantic.git/core/generated/api"
32 "git.monogon.dev/source/nexantic.git/core/internal/common"
Lorenz Brunaa6b7342019-12-12 02:55:02 +010033)
34
35// Agent specifices the interface which every integrity agent needs to fulfill
Leopold Schabel8fba0f82020-01-22 18:46:25 +010036// TODO: This interface is not yet used, we call the TPM2 agent directly.
Lorenz Brunaa6b7342019-12-12 02:55:02 +010037type Agent interface {
38 // Initialize needs to be called once and initializes the systems required to maintain integrity
39 // on the given platform.
40 // nodeCert is a X.509 DER certificate which identifies the node once it's unlocked. This is
41 // required to bind the node certificate (which is only available when the node is unlocked) to
42 // the integrity subsystem used to attest said node.
43 // Initialize returns the cryptographic identity that it's bound to.
44 Initialize(newNode api.NewNodeInfo, enrolment api.EnrolmentConfig) (string, error)
45
Leopold Schabel8fba0f82020-01-22 18:46:25 +010046 // Unlock performs all required actions to assure the integrity of the platform and securely retrieves
47 // the unlock key.
Lorenz Brunaa6b7342019-12-12 02:55:02 +010048 Unlock(enrolment api.EnrolmentConfig) ([]byte, error)
49}
50
51// DialNMS creates a secure GRPC connection to the NodeManagementService
52func DialNMS(enrolment api.EnrolmentConfig) (*grpc.ClientConn, error) {
53 var targets []string
54 for _, target := range enrolment.MasterIps {
55 targets = append(targets, fmt.Sprintf("%v:%v", net.IP(target), common.MasterServicePort))
56 }
57 cert, err := x509.ParseCertificate(enrolment.MastersCert)
58 if err != nil {
59 return nil, err
60 }
61 mastersPool := x509.NewCertPool()
62 mastersPool.AddCert(cert)
63
64 secureTransport := &tls.Config{
65 InsecureSkipVerify: true,
66 // Critical function, please review any changes with care
67 // TODO(lorenz): Actively check that this actually provides the security guarantees that we need
68 VerifyPeerCertificate: func(rawCerts [][]byte, verifiedChains [][]*x509.Certificate) error {
69 for _, cert := range rawCerts {
70 // X.509 certificates in DER can be compared like this since DER has a unique representation
71 // for each certificate.
72 if bytes.Equal(cert, enrolment.MastersCert) {
73 return nil
74 }
75 }
76 return errors.New("failed to find authorized NMS certificate")
77 },
78 MinVersion: tls.VersionTLS13,
79 }
80 secureTransportCreds := credentials.NewTLS(secureTransport)
81
82 return grpc.Dial(strings.Join(targets, ","), grpc.WithTransportCredentials(secureTransportCreds))
83}