-
Notifications
You must be signed in to change notification settings - Fork 13
/
cert_chain.go
93 lines (77 loc) · 2.71 KB
/
cert_chain.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
// Copyright 2022 Dimitrij Drus <dadrus@gmx.de>
//
// 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.
//
// SPDX-License-Identifier: Apache-2.0
package keystore
import (
"bytes"
"crypto"
"crypto/x509"
"github.com/dadrus/heimdall/internal/heimdall"
"github.com/dadrus/heimdall/internal/x/errorchain"
"github.com/dadrus/heimdall/internal/x/pkix"
)
func FindChain(key crypto.PublicKey, pool []*x509.Certificate) []*x509.Certificate {
pubKey, ok := key.(interface {
Equal(x crypto.PublicKey) bool
})
if !ok {
return nil
}
for _, cert := range pool {
if pubKey.Equal(cert.PublicKey) {
return buildChain([]*x509.Certificate{cert}, pool)
}
}
return nil
}
func buildChain(chain []*x509.Certificate, issuerCandidates []*x509.Certificate) []*x509.Certificate {
child := chain[len(chain)-1]
for _, candidate := range issuerCandidates {
if child.Equal(candidate) {
continue
} else if isIssuerOf(child, candidate) {
return buildChain(append(chain, candidate), issuerCandidates)
}
}
return chain
}
func isIssuerOf(child, potentialIssuer *x509.Certificate) bool {
if len(child.AuthorityKeyId) != 0 && len(potentialIssuer.SubjectKeyId) != 0 {
return bytes.Equal(child.AuthorityKeyId, potentialIssuer.SubjectKeyId)
}
return bytes.Equal(child.RawIssuer, potentialIssuer.RawSubject)
}
func ValidateChain(chain []*x509.Certificate) error {
// the validation of the chain happens without the usage of the system
// trust store. Given the way how the buildChain function works, the last
// certificate in the chain is considered to be the root of trust, the first
// is the actual end entity certificate and all others are intermediaries.
// That also means, that if the chain consists of just one certificate, it is
// trusted explicitly.
const certificateCount = 2
var intermediatePool []*x509.Certificate
if len(chain) > certificateCount {
for i := 1; i < len(chain)-1; i++ {
intermediatePool = append(intermediatePool, chain[i])
}
}
if err := pkix.ValidateCertificate(chain[0],
pkix.WithRootCACertificates([]*x509.Certificate{chain[len(chain)-1]}),
pkix.WithIntermediateCACertificates(intermediatePool),
); err != nil {
return errorchain.New(heimdall.ErrConfiguration).CausedBy(err)
}
return nil
}