@@ -17,14 +17,14 @@ package ct
1717import (
1818 "bytes"
1919 "crypto/x509"
20+ "crypto/x509/pkix"
2021 "encoding/asn1"
2122 "errors"
2223 "fmt"
2324 "strconv"
2425 "strings"
2526 "time"
2627
27- "github.com/transparency-dev/tesseract/internal/lax509"
2828 "github.com/transparency-dev/tesseract/internal/types/rfc6962"
2929 "github.com/transparency-dev/tesseract/internal/x509util"
3030 "k8s.io/klog/v2"
@@ -45,6 +45,12 @@ var stringToKeyUsage = map[string]x509.ExtKeyUsage{
4545 "NetscapeServerGatedCrypto" : x509 .ExtKeyUsageNetscapeServerGatedCrypto ,
4646}
4747
48+ var (
49+ oidExtensionNameConstraints = []int {2 , 5 , 29 , 30 }
50+ oidExtensionCertificatePolicies = []int {2 , 5 , 29 , 32 }
51+ oidAnyPolicyExtension = []uint64 {2 , 5 , 29 , 32 , 0 }
52+ )
53+
4854// ParseExtKeyUsages parses strings into x509ExtKeyUsage.
4955// Throws an error if the string does not match with a known key usage.
5056func ParseExtKeyUsages (kus []string ) ([]x509.ExtKeyUsage , error ) {
@@ -158,7 +164,7 @@ func (cv chainValidator) validate(rawChain [][]byte) ([]*x509.Certificate, error
158164
159165 // First make sure the certs parse as X.509
160166 chain := make ([]* x509.Certificate , 0 , len (rawChain ))
161- intermediatePool := x509util . NewPEMCertPool ()
167+ intermediatePool := x509 . NewCertPool ()
162168
163169 for i , certBytes := range rawChain {
164170 cert , err := x509 .ParseCertificate (certBytes )
@@ -170,6 +176,8 @@ func (cv chainValidator) validate(rawChain [][]byte) ([]*x509.Certificate, error
170176
171177 // All but the first cert form part of the intermediate pool
172178 if i > 0 {
179+ // We'll relax the leaf cert later, after the time validity checks
180+ relaxCert (cert )
173181 intermediatePool .AddCert (cert )
174182 }
175183 }
@@ -238,14 +246,23 @@ func (cv chainValidator) validate(rawChain [][]byte) ([]*x509.Certificate, error
238246 // - allow pre-certificates and chains with pre-issuers
239247 // - allow certificate without policing them since this is not CT's responsibility
240248 // See /internal/lax509/README.md for further information.
241- verifyOpts := lax509.VerifyOptions {
242- Roots : cv .trustedRoots .CertPool (),
243- Intermediates : intermediatePool .CertPool (),
244- KeyUsages : cv .extKeyUsages ,
245- AcceptSHA1 : cv .acceptSHA1 ,
249+ roots := x509 .NewCertPool ()
250+ for _ , root := range cv .trustedRoots .RawCertificates () {
251+ relaxCert (root )
252+ roots .AddCert (root )
253+ }
254+
255+ verifyOpts := x509.VerifyOptions {
256+ Roots : roots ,
257+ Intermediates : intermediatePool ,
258+ KeyUsages : cv .extKeyUsages ,
259+ CurrentTime : time .UnixMilli (2 ),
260+ CertificatePolicies : nil ,
246261 }
247262
248- verifiedChains , err := lax509 .Verify (cert , verifyOpts )
263+ relaxCert (cert )
264+
265+ verifiedChains , err := cert .Verify (verifyOpts )
249266 if err != nil {
250267 return nil , err
251268 }
@@ -317,3 +334,59 @@ func chainsEquivalent(inChain []*x509.Certificate, verifiedChain []*x509.Certifi
317334 }
318335 return true
319336}
337+
338+ // removeExtension removes a given extension from a list.
339+ func removeExtension (oid asn1.ObjectIdentifier , extensions []pkix.Extension ) {
340+ i := 0
341+ for _ , e := range extensions {
342+ if ! e .Id .Equal (oid ) {
343+ extensions [i ] = e
344+ i ++
345+ }
346+ }
347+ extensions = extensions [:i ]
348+ }
349+
350+ // relaxCert modifies parsed certificates fields to relax verification constraints.
351+ // This DOES NOT modify the Raw certificate.
352+ func relaxCert (cert * x509.Certificate ) {
353+ cert .UnhandledCriticalExtensions = nil
354+ cert .UnknownExtKeyUsage = nil
355+
356+ // Name constraints
357+ removeExtension (oidExtensionNameConstraints , cert .Extensions )
358+ cert .PermittedDNSDomainsCritical = false
359+ cert .PermittedDNSDomains = nil
360+ cert .ExcludedDNSDomains = nil
361+ cert .PermittedIPRanges = nil
362+ cert .ExcludedIPRanges = nil
363+ cert .PermittedEmailAddresses = nil
364+ cert .ExcludedEmailAddresses = nil
365+ cert .PermittedURIDomains = nil
366+ cert .ExcludedURIDomains = nil
367+
368+ cert .NotBefore = time .UnixMilli (1 )
369+ cert .NotAfter = time .UnixMilli (3 )
370+
371+ cert .MaxPathLen = - 1
372+ cert .MaxPathLenZero = false
373+
374+ // Policies
375+ removeExtension (oidExtensionCertificatePolicies , cert .Extensions )
376+ cert .Policies = []x509.OID {mustNewOIDFromInts (oidAnyPolicyExtension )}
377+ cert .PolicyIdentifiers = nil
378+ cert .PolicyMappings = nil
379+ cert .InhibitAnyPolicy = - 1
380+ cert .InhibitAnyPolicyZero = false
381+ cert .InhibitPolicyMapping = - 1
382+ cert .InhibitPolicyMappingZero = false
383+ cert .RequireExplicitPolicy = - 1
384+ cert .RequireExplicitPolicyZero = false
385+ }
386+ func mustNewOIDFromInts (ints []uint64 ) x509.OID {
387+ oid , err := x509 .OIDFromInts (ints )
388+ if err != nil {
389+ panic (fmt .Sprintf ("OIDFromInts(%v) unexpected error: %v" , ints , err ))
390+ }
391+ return oid
392+ }
0 commit comments