github.com/zmap/zcrypto@v0.0.0-20240512203510-0fef58d9a9db/x509/revocation/crl/crl.go (about) 1 package crl 2 3 import ( 4 "encoding/json" 5 "time" 6 7 "github.com/zmap/zcrypto/encoding/asn1" 8 "github.com/zmap/zcrypto/x509" 9 "github.com/zmap/zcrypto/x509/pkix" 10 ) 11 12 // RevocationReasonCode - status codes that explain revocation reason see RFC 5280, Section 5.3.1 13 type RevocationReasonCode int 14 15 var reasonCodeNames map[RevocationReasonCode]string 16 17 func init() { 18 reasonCodeNames = make(map[RevocationReasonCode]string) 19 reasonCodeNames[0] = "unspecified" 20 reasonCodeNames[1] = "keyCompromise" 21 reasonCodeNames[2] = "cACompromise" 22 reasonCodeNames[3] = "affiliationChanged" 23 reasonCodeNames[4] = "superseded" 24 reasonCodeNames[5] = "cessationOfOperation" 25 reasonCodeNames[6] = "certificateHold" 26 // STATUS CODE 7 IS NOT USED 27 reasonCodeNames[8] = "removeFromCRL" 28 reasonCodeNames[9] = "privilegeWithdrawn" 29 reasonCodeNames[10] = "aACompromise" 30 } 31 32 // MarshalJSON implements the json.Marshler interface 33 func (code *RevocationReasonCode) MarshalJSON() ([]byte, error) { 34 aux := struct { 35 Value int `json:"value"` 36 Name string `json:"name"` 37 }{ 38 Value: int(*code), 39 Name: code.String(), 40 } 41 return json.Marshal(&aux) 42 } 43 44 // UnmarshalJSON implements the json.Unmarshaler interface 45 func (code *RevocationReasonCode) UnmarshalJSON(b []byte) error { 46 aux := struct { 47 Value int `json:"value"` 48 Name string `json:"name"` 49 }{} 50 if err := json.Unmarshal(b, &aux); err != nil { 51 return err 52 } 53 *code = RevocationReasonCode(aux.Value) 54 return nil 55 } 56 57 func (code *RevocationReasonCode) String() string { 58 return reasonCodeNames[*code] 59 } 60 61 var ( 62 crlNumberExtensionOID = asn1.ObjectIdentifier{2, 5, 29, 20} 63 revocationReasonExtensionOID = asn1.ObjectIdentifier{2, 5, 29, 21} 64 invalidityDateExtensionOID = asn1.ObjectIdentifier{2, 5, 29, 24} 65 ) 66 67 type crlNumberExtension struct { 68 ID asn1.ObjectIdentifier 69 Critical bool `asn1:"optional"` 70 CRLNumber int 71 } 72 73 // TODO: handle additional CRL Extensions 74 // 2.5.29.21,cRLReason 75 // id-ce-cRLReasons OBJECT IDENTIFIER ::= { id-ce 21 } 76 // -- reasonCode ::= { CRLReasonCode } 77 78 //2.5.29.24,invalidityDate 79 // id-ce-invalidityDate OBJECT IDENTIFIER ::= { id-ce 24 } 80 // -- InvalidityDate ::= GeneralizedTime 81 82 // RevocationData - information on whether a certificate has been 83 // revoked by a specified CRL, and information on the CRL 84 type RevocationData struct { 85 CRLSignatureAlgorithm x509.SignatureAlgorithm 86 CRLSignatureValue []byte 87 Version int `asn1:"optional,default:0"` 88 Issuer pkix.Name 89 ThisUpdate time.Time 90 NextUpdate time.Time `asn1:"optional"` 91 CRLExtensions ListExtensionData 92 UnknownCRLExtensions []pkix.Extension `asn1:"tag:0,optional,explicit"` 93 UnknownCriticalCRLExtensions []pkix.Extension `asn1:"tag:0,optional,explicit"` 94 IsRevoked bool 95 RevocationTime time.Time 96 CertificateEntryExtensions RevokedCertExtensionData 97 RawCertificateEntryExtensions []pkix.Extension `asn1:"optional"` 98 } 99 100 // ListExtensionData - Data from optional, non-critical pkix.CertificateList extensions 101 type ListExtensionData struct { 102 CRLNumber int 103 AuthKeyID x509.SubjAuthKeyId `json:"authority_key_id,omitempty"` 104 } 105 106 // RevokedCertExtensionData - Data from optional, non-critical pkix.RevokedCertificate extensions 107 type RevokedCertExtensionData struct { 108 Reason *RevocationReasonCode 109 invalidityDate time.Time 110 } 111 112 func gatherListExtensionInfo(certList *pkix.CertificateList, ret *RevocationData) { 113 for _, extension := range certList.TBSCertList.Extensions { 114 if extension.Id.Equal(crlNumberExtensionOID) { 115 var ext crlNumberExtension 116 asn1.Unmarshal(extension.Value, &ext.CRLNumber) 117 ret.CRLExtensions.CRLNumber = ext.CRLNumber 118 } else if extension.Critical { 119 ret.UnknownCriticalCRLExtensions = append(ret.UnknownCriticalCRLExtensions, extension) 120 } else { 121 ret.UnknownCRLExtensions = append(ret.UnknownCRLExtensions, extension) 122 } 123 } 124 } 125 126 // CheckCRLForCert - parses through a given CRL and to see if a given certificate 127 // is present, and returns data on the revocation and CRL in general 128 func CheckCRLForCert(certList *pkix.CertificateList, cert *x509.Certificate, cache map[string]*pkix.RevokedCertificate) (*RevocationData, error) { 129 ret := &RevocationData{ 130 CRLSignatureAlgorithm: x509.GetSignatureAlgorithmFromAI(certList.SignatureAlgorithm), 131 CRLSignatureValue: certList.SignatureValue.Bytes, 132 Version: certList.TBSCertList.Version, 133 ThisUpdate: certList.TBSCertList.ThisUpdate, 134 NextUpdate: certList.TBSCertList.NextUpdate, 135 IsRevoked: false, 136 } 137 ret.Issuer.FillFromRDNSequence(&certList.TBSCertList.Issuer) 138 139 gatherListExtensionInfo(certList, ret) 140 141 if cache != nil { 142 if val, ok := cache[cert.SerialNumber.String()]; ok { 143 ret.IsRevoked = true 144 ret.RevocationTime = val.RevocationTime 145 } 146 return ret, nil 147 } 148 149 // else no cache was given, must linear search through 150 revokedCerts := certList.TBSCertList.RevokedCertificates 151 for i := range revokedCerts { 152 if revokedCerts[i].SerialNumber.Cmp(cert.SerialNumber) == 0 { 153 ret.IsRevoked = true 154 ret.RevocationTime = revokedCerts[i].RevocationTime 155 break 156 } 157 } 158 return ret, nil 159 }