@@ -25,13 +25,9 @@ import (
2525
2626 "github.com/transparency-dev/tessera/ctonly"
2727 "github.com/transparency-dev/tesseract/internal/types/rfc6962"
28- )
2928
30- var (
31- oidExtensionAuthorityKeyId = asn1.ObjectIdentifier {2 , 5 , 29 , 35 }
32- // These extensions are defined in RFC 6962 s3.1.
33- oidExtensionCTPoison = asn1.ObjectIdentifier {1 , 3 , 6 , 1 , 4 , 1 , 11129 , 2 , 4 , 3 }
34- oidExtensionKeyUsageCertificateTransparency = asn1.ObjectIdentifier {1 , 3 , 6 , 1 , 4 , 1 , 11129 , 2 , 4 , 4 }
29+ "golang.org/x/crypto/cryptobyte"
30+ cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
3531)
3632
3733type tbsCertificate struct {
@@ -110,7 +106,7 @@ func removeExtension(tbsData []byte, oid asn1.ObjectIdentifier) ([]byte, error)
110106// - The precert's AuthorityKeyId is changed to the AuthorityKeyId of the
111107// intermediate.
112108func BuildPrecertTBS (tbsData []byte , preIssuer * x509.Certificate ) ([]byte , error ) {
113- data , err := removeExtension (tbsData , oidExtensionCTPoison )
109+ data , err := removeExtension (tbsData , rfc6962 . OIDExtensionCTPoison )
114110 if err != nil {
115111 return nil , err
116112 }
@@ -133,28 +129,20 @@ func BuildPrecertTBS(tbsData []byte, preIssuer *x509.Certificate) ([]byte, error
133129 // to that of the preIssuer.
134130 var issuerKeyID []byte
135131 for _ , ext := range preIssuer .Extensions {
136- if ext .Id .Equal (oidExtensionAuthorityKeyId ) {
132+ if ext .Id .Equal (rfc6962 . OIDExtAuthorityKeyId ) {
137133 issuerKeyID = ext .Value
138134 break
139135 }
140136 }
141137
142- // The x509 package does not parse CT EKU, so look for it in
143- // extensions directly.
144- seenCTEKU := false
145- for _ , ext := range preIssuer .Extensions {
146- if ext .Id .Equal (oidExtensionKeyUsageCertificateTransparency ) {
147- seenCTEKU = true
148- break
149- }
150- }
151- if ! seenCTEKU {
138+ // TODO(phbnf): is this check really necessary?
139+ if ! isPreIssuer (preIssuer ) {
152140 return nil , fmt .Errorf ("issuer does not have CertificateTransparency extended key usage" )
153141 }
154142
155143 keyAt := - 1
156144 for i , ext := range tbs .Extensions {
157- if ext .Id .Equal (oidExtensionAuthorityKeyId ) {
145+ if ext .Id .Equal (rfc6962 . OIDExtAuthorityKeyId ) {
158146 keyAt = i
159147 break
160148 }
@@ -169,7 +157,7 @@ func BuildPrecertTBS(tbsData []byte, preIssuer *x509.Certificate) ([]byte, error
169157 } else if issuerKeyID != nil {
170158 // PreCert did not have an auth-key-id, but the preIssuer does, so add it at the end.
171159 authKeyIDExt := pkix.Extension {
172- Id : oidExtensionAuthorityKeyId ,
160+ Id : rfc6962 . OIDExtAuthorityKeyId ,
173161 Critical : false ,
174162 Value : issuerKeyID ,
175163 }
@@ -198,7 +186,6 @@ func RemoveCTPoison(tbsData []byte) ([]byte, error) {
198186
199187// EntryFromChain generates an Entry from a chain and timestamp.
200188// copied from certificate-transparency-go/serialization.go
201- // TODO(phboneff): add tests
202189func EntryFromChain (chain []* x509.Certificate , isPrecert bool , timestamp uint64 ) (* ctonly.Entry , error ) {
203190 leaf := ctonly.Entry {
204191 IsPrecert : isPrecert ,
@@ -256,14 +243,35 @@ func EntryFromChain(chain []*x509.Certificate, isPrecert bool, timestamp uint64)
256243 return & leaf , nil
257244}
258245
259- // isPreIssuer indicates whether a certificate is a pre-cert issuer with the specific
260- // certificate transparency extended key usage.
246+ // isPreIssuer indicates if a certificate is a precertificate signing cert.
247+ //
248+ // From RFC6962 s3.1, these certs should contain:
249+ // (CA:true, Extended Key Usage: Certificate Transparency, OID 1.3.6.1.4.1.11129.2.4.4)
261250func isPreIssuer (cert * x509.Certificate ) bool {
262- // Look for the extension in the Extensions field and not ExtKeyUsage
263- // since crypto/x509 does not recognize this extension as an ExtKeyUsage.
251+ if ! cert .IsCA {
252+ return false
253+ }
254+ // Look for the extension in the Extensions field and not in ExtKeyUsage
255+ // since crypto/x509 does not recognize this extension as such.
256+ // We cannot reliably check in UnknownExtKeyUsage either, since it might
257+ // one day disappear from UnknownExtKeyUsage and make it to ExtKeyUsage.
258+ // Given that ExtKeyUsage does not contain OIDs, we would not be able to
259+ // detect such a move.
264260 for _ , ext := range cert .Extensions {
265- if rfc6962 .OIDExtKeyUsageCertificateTransparency .Equal (ext .Id ) {
266- return true
261+ if rfc6962 .OIDExtKeyUsage .Equal (ext .Id ) {
262+ der := cryptobyte .String (ext .Value )
263+ if ! der .ReadASN1 (& der , cryptobyte_asn1 .SEQUENCE ) {
264+ continue
265+ }
266+ for ! der .Empty () {
267+ var eku asn1.ObjectIdentifier
268+ if ! der .ReadASN1ObjectIdentifier (& eku ) {
269+ continue
270+ }
271+ if rfc6962 .OIDExtKeyUsageCertificateTransparency .Equal (eku ) {
272+ return true
273+ }
274+ }
267275 }
268276 }
269277 return false
0 commit comments