-
Notifications
You must be signed in to change notification settings - Fork 1
/
cert.go
142 lines (120 loc) · 3.44 KB
/
cert.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
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
package smartid
import (
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"io/ioutil"
"time"
)
// Certificate levels. QUALIFIED is the more modern way to use it. Some
// accounts or services might support only non-qualified certificates,
// which are known as basic accounts (ADVANCED).
const (
// CertLevelQualified QUALIFIED level of certificate.
CertLevelQualified = "QUALIFIED" // recommended
// CertLevelAdvanced ADVANCED level of certificate.
CertLevelAdvanced = "ADVANCED"
)
const (
certBegin = "-----BEGIN CERTIFICATE-----\n"
certEnd = "\n-----END CERTIFICATE-----"
)
var (
// ErrCertNoCertGiven error when no certificates used in Verify()
// function.
ErrCertNoCertGiven = errors.New("No certs given")
)
// Cert represents certificate from session response.
type Cert struct {
// Value is the base64 encoded string of certificate.
Value string `json:"value"`
// CertificateLevel is the level of the certificate:
// QUALIFIED
// ADVANCED
CertificateLevel string `json:"certificateLevel"`
// x509Cert is the X509 certificate.
x509Cert *x509.Certificate
}
// IsExpired checks that certificate has expired.
func (c *Cert) IsExpired() bool {
return time.Now().Before(c.x509Cert.NotBefore)
}
// IsNotActive checks that certificate is not yet active.
func (c *Cert) IsNotActive() bool {
return time.Now().After(c.x509Cert.NotAfter)
}
// IsSameLevel checks that certificate is the same level as argument.
func (c *Cert) IsSameLevel(lvl string) bool {
return c.CertificateLevel == lvl
}
// Verify certificate by file system paths.
func (c *Cert) Verify(paths []string) (bool, error) {
if len(paths) == 0 {
return false, ErrCertNoCertGiven
}
roots := x509.NewCertPool()
for _, path := range paths {
cert, err := createCertFromPath(path)
if err != nil {
return false, err
}
roots.AddCert(cert)
}
opts := x509.VerifyOptions{
Roots: roots,
// NOTE SK generated cert have incompatible keys.
// NOTE Maybe need to change this behaviour.
KeyUsages: []x509.ExtKeyUsage{x509.ExtKeyUsageAny},
}
if _, err := c.x509Cert.Verify(opts); err != nil {
return false, err
}
return true, nil
}
// GetX509Cert returns X509 certificate from response.
func (c *Cert) GetX509Cert() *x509.Certificate {
return c.x509Cert
}
// GetSubject get subject from certificate in PKIX format.
func (c *Cert) GetSubject() *pkix.Name {
return &c.GetX509Cert().Subject
}
// GetIssuer get issuer from certificate in PKIX format.
func (c *Cert) GetIssuer() *pkix.Name {
return &c.GetX509Cert().Issuer
}
// createCertFromPath certificate from given file system path.
func createCertFromPath(path string) (*x509.Certificate, error) {
bs, err := ioutil.ReadFile(path)
if err != nil {
return nil, err
}
cert, err := createCertFromString(string(bs))
if err != nil {
return nil, err
}
return cert, nil
}
// createCertFromString creates certificate from string.
func createCertFromString(s string) (*x509.Certificate, error) {
block := decodePEMBlock([]byte(s))
cert, err := x509.ParseCertificate(block.Bytes)
if err != nil {
return nil, err
}
return cert, nil
}
// decodePEMBlock decodes PEM block.
func decodePEMBlock(pemData []byte) *pem.Block {
block, _ := pem.Decode(pemData)
return block
}
// createX509CertIfNeeded creates X509 certificate from response if not yet
// certificate exists.
func (c *Cert) createX509CertIfNeeded() {
if c.GetX509Cert() == nil {
cert, _ := createCertFromString(certBegin + c.Value + certEnd)
c.x509Cert = cert
}
}