-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathcrl.go
160 lines (133 loc) · 4.34 KB
/
crl.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
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
package main
import (
"bytes"
"crypto/x509"
"crypto/x509/pkix"
"encoding/pem"
"errors"
"fmt"
"io/ioutil"
"math/big"
"net/http"
"net/url"
"time"
)
/*
printCRLDetails verifies serial number of leaf certificate against CRL and prints the results.
*/
func printCRLDetails(crlDistributionPoint string, serialNumber *big.Int, issuerCertificate *x509.Certificate) {
fmt.Printf("\nCRL DETAILS ...\n")
fmt.Printf(leftValue+"%v\n", "DistributionPoint", crlDistributionPoint)
// parse CRLDistributionPoint to filter out unsupported URL schemes
urlDetails, err := url.Parse(crlDistributionPoint)
if err != nil {
fmt.Printf(leftValue+"No (invalid URL, parsing error <%v>)\n", "DownloadSupport", err)
return
}
if urlDetails.Scheme == "ldap" {
fmt.Printf(leftValue+"No (ldap not supported)\n", "DownloadSupport")
return
}
fmt.Printf(leftValue+"Yes\n", "DownloadSupport")
rawCRL, err := fetchCRLfromCDP(crlDistributionPoint)
if err != nil {
fmt.Printf(leftValue+"Error (%v)\n", "ReadingStatus", err)
return
}
crl, err := x509.ParseCRL(rawCRL)
if err != nil {
fmt.Printf(leftValue+"Error (%v)\n", "ReadingStatus", err)
return
}
fmt.Printf(leftValue+"Ok\n", "ReadingStatus")
// check CRL signature
err = issuerCertificate.CheckCRLSignature(crl)
if err != nil {
fmt.Printf(leftValue+"Not Valid (%v)\n", "Signature", err)
return
}
fmt.Printf(leftValue+"Valid\n", "Signature")
// print CRL details
fmt.Printf(leftValue+"%v\n", "Version", crl.TBSCertList.Version)
fmt.Printf(leftValue+"%v\n", "Issuer", crl.TBSCertList.Issuer)
diff := start.Sub(crl.TBSCertList.ThisUpdate)
fmt.Printf(leftValue+"%v (was provided %d hours ago)\n", "ThisUpdate", crl.TBSCertList.ThisUpdate, diff/(time.Hour))
diff = crl.TBSCertList.NextUpdate.Sub(start)
fmt.Printf(leftValue+"%v (will be provided in %d hours)\n", "NextUpdate", crl.TBSCertList.NextUpdate, diff/(time.Hour))
for _, extension := range crl.TBSCertList.Extensions {
fmt.Printf(leftValue+"Id=%v, Value=%v\n", "Extension", extension.Id, extension.Value)
}
// check serial number of leaf certificate against CRL
certificateStatus := "Good"
// test with arbitrary serial number (e.g. revoked certificate)
// serialNumber.SetString("0DBBB048C52F232547BEC91FCBE7598A", 16)
var revokationEntry pkix.RevokedCertificate
for _, revoked := range crl.TBSCertList.RevokedCertificates {
if serialNumber.Cmp(revoked.SerialNumber) == 0 {
// certificate revoked
certificateStatus = "Revoked"
revokationEntry = revoked
break
}
}
fmt.Printf(leftValue+"%v\n", "CertificateStatus", certificateStatus)
fmt.Printf(leftValue+"%v\n", "SerialNumber", serialNumber)
if certificateStatus == "Revoked" {
fmt.Printf(leftValue+"%v\n", "RevokedAT", revokationEntry.RevocationTime)
if len(revokationEntry.Extensions) > 0 {
for _, extension := range revokationEntry.Extensions {
fmt.Printf(leftValue+"Id=%v, Value=%v\n", "RevocationReason", extension.Id, extension.Value)
}
} else {
fmt.Printf(leftValue+"Unspecified\n", "RevocationReason")
}
}
if *verbose {
printCRLPEM(rawCRL)
}
}
/*
fetchCRLfromCDP fetches certificate revocation list (CRL) from CRL distribution point (CDP)
*/
func fetchCRLfromCDP(crlURL string) ([]byte, error) {
httpClient := &http.Client{
Timeout: time.Duration(*timeout) * time.Second,
}
httpResponse, err := httpClient.Get(crlURL)
if err != nil {
message := fmt.Sprintf("error: error <%v> at httpClient.Do()", err)
return nil, errors.New(message)
}
defer httpResponse.Body.Close()
if httpResponse.StatusCode >= 300 {
message := fmt.Sprintf("error: unexpected http status code <%v> at httpClient.Get()", httpResponse.StatusCode)
return nil, errors.New(message)
}
output, err := ioutil.ReadAll(httpResponse.Body)
if err != nil {
message := fmt.Sprintf("error: error <%v> at ioutil.ReadAll()", err)
return nil, errors.New(message)
}
return output, nil
}
/*
printCRLPEM prints CRL in PEM format
*/
func printCRLPEM(rawCRL []byte) {
pemCRLPrefix := []byte("-----BEGIN X509 CRL")
if bytes.HasPrefix(rawCRL, pemCRLPrefix) {
// CRL is already PEM-formatted
fmt.Printf("\n%s", string(rawCRL))
return
}
var pemBuffer bytes.Buffer
block := &pem.Block{
Type: "X509 CRL",
Bytes: rawCRL,
}
if err := pem.Encode(&pemBuffer, block); err != nil {
fmt.Printf("Error: unable to encode CRL, error = %v\n", err)
return
}
fmt.Printf("\n%s", pemBuffer.String())
}