|
|
@ -13,58 +13,10 @@ import (
|
|
|
|
"strings"
|
|
|
|
"strings"
|
|
|
|
"sync"
|
|
|
|
"sync"
|
|
|
|
"time"
|
|
|
|
"time"
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var OidCRLReason = asn1.ObjectIdentifier{2, 5, 29, 21}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
type CRLReason int
|
|
|
|
"git.cacert.org/cacert-gosigner/x509/revoking"
|
|
|
|
|
|
|
|
|
|
|
|
// CRL reason codes as defined in RFC 5280 section 5.3.1
|
|
|
|
|
|
|
|
const (
|
|
|
|
|
|
|
|
CRLReasonUnspecified CRLReason = 0
|
|
|
|
|
|
|
|
CRLReasonKeyCompromise CRLReason = 1
|
|
|
|
|
|
|
|
CRLReasonCACompromise CRLReason = 2
|
|
|
|
|
|
|
|
CRLReasonAffiliationChanged CRLReason = 3
|
|
|
|
|
|
|
|
CRLReasonSuperseded CRLReason = 4
|
|
|
|
|
|
|
|
CRLReasonCessationOfOperation CRLReason = 5
|
|
|
|
|
|
|
|
CRLReasonCertificateHold CRLReason = 6
|
|
|
|
|
|
|
|
CRLReasonRemoveFromCRL CRLReason = 8
|
|
|
|
|
|
|
|
CRLReasonPrivilegeWithdrawn CRLReason = 9
|
|
|
|
|
|
|
|
CRLReasonAACompromise CRLReason = 10
|
|
|
|
|
|
|
|
)
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
var crlReasonNames = map[CRLReason]string{
|
|
|
|
|
|
|
|
CRLReasonUnspecified: "unspecified",
|
|
|
|
|
|
|
|
CRLReasonKeyCompromise: "keyCompromise",
|
|
|
|
|
|
|
|
CRLReasonCACompromise: "CACompromise",
|
|
|
|
|
|
|
|
CRLReasonAffiliationChanged: "affiliationChanged",
|
|
|
|
|
|
|
|
CRLReasonSuperseded: "superseded",
|
|
|
|
|
|
|
|
CRLReasonCessationOfOperation: "cessationOfOperation",
|
|
|
|
|
|
|
|
CRLReasonCertificateHold: "certificateHold",
|
|
|
|
|
|
|
|
CRLReasonRemoveFromCRL: "removeFromCRL",
|
|
|
|
|
|
|
|
CRLReasonPrivilegeWithdrawn: "privilegeWithdrawn",
|
|
|
|
|
|
|
|
CRLReasonAACompromise: "AACompromise",
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (r CRLReason) String() string {
|
|
|
|
|
|
|
|
if reason, ok := crlReasonNames[r]; ok {
|
|
|
|
|
|
|
|
return reason
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return crlReasonNames[CRLReasonUnspecified]
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// ParseReason takes a reason string and performs a case-insensitive match to a reason code
|
|
|
|
|
|
|
|
func ParseReason(rs string) CRLReason {
|
|
|
|
|
|
|
|
for key, name := range crlReasonNames {
|
|
|
|
|
|
|
|
if strings.EqualFold(name, rs) {
|
|
|
|
|
|
|
|
return key
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return CRLReasonUnspecified
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const TimeSpec = "060102030405Z"
|
|
|
|
const TimeSpec = "060102030405Z"
|
|
|
|
|
|
|
|
|
|
|
|
type indexStatus string
|
|
|
|
type indexStatus string
|
|
|
@ -81,7 +33,7 @@ type indexEntry struct {
|
|
|
|
statusFlag indexStatus
|
|
|
|
statusFlag indexStatus
|
|
|
|
expiresAt time.Time
|
|
|
|
expiresAt time.Time
|
|
|
|
revokedAt *time.Time
|
|
|
|
revokedAt *time.Time
|
|
|
|
revocationReason CRLReason
|
|
|
|
revocationReason revoking.CRLReason
|
|
|
|
serialNumber *big.Int
|
|
|
|
serialNumber *big.Int
|
|
|
|
fileName string
|
|
|
|
fileName string
|
|
|
|
certificateSubjectDN string
|
|
|
|
certificateSubjectDN string
|
|
|
@ -119,7 +71,7 @@ type Repository struct {
|
|
|
|
entries []indexEntry
|
|
|
|
entries []indexEntry
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (ie *indexEntry) markRevoked(revocationTime time.Time, reason CRLReason) {
|
|
|
|
func (ie *indexEntry) markRevoked(revocationTime time.Time, reason revoking.CRLReason) {
|
|
|
|
if ie.statusFlag == certificateValid {
|
|
|
|
if ie.statusFlag == certificateValid {
|
|
|
|
ie.statusFlag = certificateRevoked
|
|
|
|
ie.statusFlag = certificateRevoked
|
|
|
|
ie.revokedAt = &revocationTime
|
|
|
|
ie.revokedAt = &revocationTime
|
|
|
@ -168,10 +120,10 @@ func (r *Repository) StoreRevocation(revoked *pkix.RevokedCertificate) error {
|
|
|
|
return CannotRevokeUnknown{Serial: revoked.SerialNumber}
|
|
|
|
return CannotRevokeUnknown{Serial: revoked.SerialNumber}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
reason := CRLReasonUnspecified
|
|
|
|
reason := revoking.CRLReasonUnspecified
|
|
|
|
|
|
|
|
|
|
|
|
for _, ext := range revoked.Extensions {
|
|
|
|
for _, ext := range revoked.Extensions {
|
|
|
|
if ext.Id.Equal(OidCRLReason) {
|
|
|
|
if ext.Id.Equal(revoking.OidCRLReason) {
|
|
|
|
_, err := asn1.Unmarshal(ext.Value, &reason)
|
|
|
|
_, err := asn1.Unmarshal(ext.Value, &reason)
|
|
|
|
if err != nil {
|
|
|
|
if err != nil {
|
|
|
|
return fmt.Errorf("could not unmarshal ")
|
|
|
|
return fmt.Errorf("could not unmarshal ")
|
|
|
@ -225,6 +177,31 @@ func (r *Repository) StoreCertificate(signed *x509.Certificate) error {
|
|
|
|
return nil
|
|
|
|
return nil
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
func (r *Repository) RevokedCertificates() ([]pkix.RevokedCertificate, error) {
|
|
|
|
|
|
|
|
var err error
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
r.lock.Lock()
|
|
|
|
|
|
|
|
defer r.lock.Unlock()
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
err = r.loadIndex()
|
|
|
|
|
|
|
|
if err != nil {
|
|
|
|
|
|
|
|
return nil, err
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
result := make([]pkix.RevokedCertificate, 0)
|
|
|
|
|
|
|
|
for _, entry := range r.entries {
|
|
|
|
|
|
|
|
if entry.revokedAt != nil {
|
|
|
|
|
|
|
|
result = append(result, pkix.RevokedCertificate{
|
|
|
|
|
|
|
|
SerialNumber: entry.serialNumber,
|
|
|
|
|
|
|
|
RevocationTime: *entry.revokedAt,
|
|
|
|
|
|
|
|
Extensions: []pkix.Extension{entry.revocationReason.BuildExtension()},
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return result, nil
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
func (r *Repository) loadIndex() error {
|
|
|
|
func (r *Repository) loadIndex() error {
|
|
|
|
entries := make([]indexEntry, 0, 100)
|
|
|
|
entries := make([]indexEntry, 0, 100)
|
|
|
|
|
|
|
|
|
|
|
@ -320,14 +297,14 @@ func (r *Repository) newIndexEntryFromLine(text string) (*indexEntry, error) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
var revocationTimeParsed time.Time
|
|
|
|
var revocationTimeParsed time.Time
|
|
|
|
var revocationReason CRLReason
|
|
|
|
var revocationReason revoking.CRLReason
|
|
|
|
|
|
|
|
|
|
|
|
if fields[2] != "" {
|
|
|
|
if fields[2] != "" {
|
|
|
|
var timeString string
|
|
|
|
var timeString string
|
|
|
|
if strings.Contains(fields[2], ",") {
|
|
|
|
if strings.Contains(fields[2], ",") {
|
|
|
|
parts := strings.SplitN(fields[2], ",", 2)
|
|
|
|
parts := strings.SplitN(fields[2], ",", 2)
|
|
|
|
timeString = parts[0]
|
|
|
|
timeString = parts[0]
|
|
|
|
revocationReason = ParseReason(parts[1])
|
|
|
|
revocationReason = revoking.ParseReason(parts[1])
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
timeString = fields[2]
|
|
|
|
timeString = fields[2]
|
|
|
|
}
|
|
|
|
}
|
|
|
|