-
Notifications
You must be signed in to change notification settings - Fork 18
/
certificate_helpers.go
102 lines (94 loc) · 2.46 KB
/
certificate_helpers.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
94
95
96
97
98
99
100
101
102
// Copyright 2021 Converter Systems LLC. All rights reserved.
package server
import (
"bytes"
"crypto/x509"
"encoding/pem"
"io/ioutil"
"github.com/awcullen/opcua/ua"
)
// validateClientCertificate validates the certificate of the client.
func validateClientCertificate(certificate *x509.Certificate, trustedCertsFile string,
suppressCertificateTimeInvalid, suppressCertificateChainIncomplete bool) (bool, error) {
if certificate == nil {
return false, ua.BadCertificateInvalid
}
var intermediates, roots *x509.CertPool
if buf, err := ioutil.ReadFile(trustedCertsFile); err == nil {
for len(buf) > 0 {
var block *pem.Block
block, buf = pem.Decode(buf)
if block == nil {
// maybe its der
cert, err := x509.ParseCertificate(buf)
if err == nil {
// is self-signed?
if bytes.Equal(cert.RawIssuer, cert.RawSubject) {
if roots == nil {
roots = x509.NewCertPool()
}
roots.AddCert(cert)
} else {
if intermediates == nil {
intermediates = x509.NewCertPool()
}
intermediates.AddCert(cert)
}
}
break
}
if block.Type != "CERTIFICATE" || len(block.Headers) != 0 {
continue
}
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
continue
}
// is self-signed?
if bytes.Equal(cert.RawIssuer, cert.RawSubject) {
if roots == nil {
roots = x509.NewCertPool()
}
roots.AddCert(cert)
} else {
if intermediates == nil {
intermediates = x509.NewCertPool()
}
intermediates.AddCert(cert)
}
}
}
opts := x509.VerifyOptions{
Intermediates: intermediates,
Roots: roots,
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageClientAuth},
}
if suppressCertificateTimeInvalid {
opts.CurrentTime = certificate.NotAfter // causes test to pass
}
if suppressCertificateChainIncomplete {
if opts.Roots == nil {
opts.Roots = x509.NewCertPool()
}
opts.Roots.AddCert(certificate)
}
// build chain and verify
if _, err := certificate.Verify(opts); err != nil {
switch se := err.(type) {
case x509.CertificateInvalidError:
switch se.Reason {
case x509.Expired:
return false, ua.BadCertificateTimeInvalid
case x509.IncompatibleUsage:
return false, ua.BadCertificateUseNotAllowed
default:
return false, ua.BadSecurityChecksFailed
}
case x509.UnknownAuthorityError:
return false, ua.BadSecurityChecksFailed
default:
return false, ua.BadSecurityChecksFailed
}
}
return true, nil
}