1 // Copyright 2011 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
15 type InvalidReason
int
18 // NotAuthorizedToSign results when a certificate is signed by another
19 // which isn't marked as a CA certificate.
20 NotAuthorizedToSign InvalidReason
= iota
21 // Expired results when a certificate has expired, based on the time
22 // given in the VerifyOptions.
24 // CANotAuthorizedForThisName results when an intermediate or root
25 // certificate has a name constraint which doesn't include the name
27 CANotAuthorizedForThisName
28 // TooManyIntermediates results when a path length constraint is
31 // IncompatibleUsage results when the certificate's key usage indicates
32 // that it may only be used for a different purpose.
36 // CertificateInvalidError results when an odd error occurs. Users of this
37 // library probably want to handle all these errors uniformly.
38 type CertificateInvalidError
struct {
43 func (e CertificateInvalidError
) Error() string {
45 case NotAuthorizedToSign
:
46 return "x509: certificate is not authorized to sign other certificates"
48 return "x509: certificate has expired or is not yet valid"
49 case CANotAuthorizedForThisName
:
50 return "x509: a root or intermediate certificate is not authorized to sign in this domain"
51 case TooManyIntermediates
:
52 return "x509: too many intermediates for path length constraint"
53 case IncompatibleUsage
:
54 return "x509: certificate specifies an incompatible key usage"
56 return "x509: unknown error"
59 // HostnameError results when the set of authorized names doesn't match the
61 type HostnameError
struct {
62 Certificate
*Certificate
66 func (h HostnameError
) Error() string {
70 if ip
:= net
.ParseIP(h
.Host
); ip
!= nil {
71 // Trying to validate an IP
72 if len(c
.IPAddresses
) == 0 {
73 return "x509: cannot validate certificate for " + h
.Host
+ " because it doesn't contain any IP SANs"
75 for _
, san
:= range c
.IPAddresses
{
82 if len(c
.DNSNames
) > 0 {
83 valid
= strings
.Join(c
.DNSNames
, ", ")
85 valid
= c
.Subject
.CommonName
88 return "x509: certificate is valid for " + valid
+ ", not " + h
.Host
91 // UnknownAuthorityError results when the certificate issuer is unknown
92 type UnknownAuthorityError
struct {
96 func (e UnknownAuthorityError
) Error() string {
97 return "x509: certificate signed by unknown authority"
100 // SystemRootsError results when we fail to load the system root certificates.
101 type SystemRootsError
struct {
104 func (e SystemRootsError
) Error() string {
105 return "x509: failed to load system roots and no roots provided"
108 // VerifyOptions contains parameters for Certificate.Verify. It's a structure
109 // because other PKIX verification APIs have ended up needing many options.
110 type VerifyOptions
struct {
112 Intermediates
*CertPool
113 Roots
*CertPool
// if nil, the system roots are used
114 CurrentTime time
.Time
// if zero, the current time is used
115 // KeyUsage specifies which Extended Key Usage values are acceptable.
116 // An empty list means ExtKeyUsageServerAuth. Key usage is considered a
117 // constraint down the chain which mirrors Windows CryptoAPI behaviour,
118 // but not the spec. To accept any key usage, include ExtKeyUsageAny.
119 KeyUsages
[]ExtKeyUsage
123 leafCertificate
= iota
124 intermediateCertificate
128 // isValid performs validity checks on the c.
129 func (c
*Certificate
) isValid(certType
int, currentChain
[]*Certificate
, opts
*VerifyOptions
) error
{
130 now
:= opts
.CurrentTime
134 if now
.Before(c
.NotBefore
) || now
.After(c
.NotAfter
) {
135 return CertificateInvalidError
{c
, Expired
}
138 if len(c
.PermittedDNSDomains
) > 0 {
139 for _
, domain
:= range c
.PermittedDNSDomains
{
140 if opts
.DNSName
== domain ||
141 (strings
.HasSuffix(opts
.DNSName
, domain
) &&
142 len(opts
.DNSName
) >= 1+len(domain
) &&
143 opts
.DNSName
[len(opts
.DNSName
)-len(domain
)-1] == '.') {
147 return CertificateInvalidError
{c
, CANotAuthorizedForThisName
}
151 // KeyUsage status flags are ignored. From Engineering Security, Peter
152 // Gutmann: A European government CA marked its signing certificates as
153 // being valid for encryption only, but no-one noticed. Another
154 // European CA marked its signature keys as not being valid for
155 // signatures. A different CA marked its own trusted root certificate
156 // as being invalid for certificate signing. Another national CA
157 // distributed a certificate to be used to encrypt data for the
158 // country’s tax authority that was marked as only being usable for
159 // digital signatures but not for encryption. Yet another CA reversed
160 // the order of the bit flags in the keyUsage due to confusion over
161 // encoding endianness, essentially setting a random keyUsage in
162 // certificates that it issued. Another CA created a self-invalidating
163 // certificate by adding a certificate policy statement stipulating
164 // that the certificate had to be used strictly as specified in the
165 // keyUsage, and a keyUsage containing a flag indicating that the RSA
166 // encryption key could only be used for Diffie-Hellman key agreement.
168 if certType
== intermediateCertificate
&& (!c
.BasicConstraintsValid ||
!c
.IsCA
) {
169 return CertificateInvalidError
{c
, NotAuthorizedToSign
}
172 if c
.BasicConstraintsValid
&& c
.MaxPathLen
>= 0 {
173 numIntermediates
:= len(currentChain
) - 1
174 if numIntermediates
> c
.MaxPathLen
{
175 return CertificateInvalidError
{c
, TooManyIntermediates
}
182 // Verify attempts to verify c by building one or more chains from c to a
183 // certificate in opts.Roots, using certificates in opts.Intermediates if
184 // needed. If successful, it returns one or more chains where the first
185 // element of the chain is c and the last element is from opts.Roots.
187 // WARNING: this doesn't do any revocation checking.
188 func (c
*Certificate
) Verify(opts VerifyOptions
) (chains
[][]*Certificate
, err error
) {
189 // Use Windows's own verification and chain building.
190 if opts
.Roots
== nil && runtime
.GOOS
== "windows" {
191 return c
.systemVerify(&opts
)
194 if opts
.Roots
== nil {
195 opts
.Roots
= systemRootsPool()
196 if opts
.Roots
== nil {
197 return nil, SystemRootsError
{}
201 err
= c
.isValid(leafCertificate
, nil, &opts
)
206 if len(opts
.DNSName
) > 0 {
207 err
= c
.VerifyHostname(opts
.DNSName
)
213 candidateChains
, err
:= c
.buildChains(make(map[int][][]*Certificate
), []*Certificate
{c
}, &opts
)
218 keyUsages
:= opts
.KeyUsages
219 if len(keyUsages
) == 0 {
220 keyUsages
= []ExtKeyUsage
{ExtKeyUsageServerAuth
}
223 // If any key usage is acceptable then we're done.
224 for _
, usage
:= range keyUsages
{
225 if usage
== ExtKeyUsageAny
{
226 chains
= candidateChains
231 for _
, candidate
:= range candidateChains
{
232 if checkChainForKeyUsage(candidate
, keyUsages
) {
233 chains
= append(chains
, candidate
)
237 if len(chains
) == 0 {
238 err
= CertificateInvalidError
{c
, IncompatibleUsage
}
244 func appendToFreshChain(chain
[]*Certificate
, cert
*Certificate
) []*Certificate
{
245 n
:= make([]*Certificate
, len(chain
)+1)
251 func (c
*Certificate
) buildChains(cache
map[int][][]*Certificate
, currentChain
[]*Certificate
, opts
*VerifyOptions
) (chains
[][]*Certificate
, err error
) {
252 for _
, rootNum
:= range opts
.Roots
.findVerifiedParents(c
) {
253 root
:= opts
.Roots
.certs
[rootNum
]
254 err
= root
.isValid(rootCertificate
, currentChain
, opts
)
258 chains
= append(chains
, appendToFreshChain(currentChain
, root
))
262 for _
, intermediateNum
:= range opts
.Intermediates
.findVerifiedParents(c
) {
263 intermediate
:= opts
.Intermediates
.certs
[intermediateNum
]
264 for _
, cert
:= range currentChain
{
265 if cert
== intermediate
{
266 continue nextIntermediate
269 err
= intermediate
.isValid(intermediateCertificate
, currentChain
, opts
)
273 var childChains
[][]*Certificate
274 childChains
, ok
:= cache
[intermediateNum
]
276 childChains
, err
= intermediate
.buildChains(cache
, appendToFreshChain(currentChain
, intermediate
), opts
)
277 cache
[intermediateNum
] = childChains
279 chains
= append(chains
, childChains
...)
286 if len(chains
) == 0 && err
== nil {
287 err
= UnknownAuthorityError
{c
}
293 func matchHostnames(pattern
, host
string) bool {
294 if len(pattern
) == 0 ||
len(host
) == 0 {
298 patternParts
:= strings
.Split(pattern
, ".")
299 hostParts
:= strings
.Split(host
, ".")
301 if len(patternParts
) != len(hostParts
) {
305 for i
, patternPart
:= range patternParts
{
306 if patternPart
== "*" {
309 if patternPart
!= hostParts
[i
] {
317 // toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use
318 // an explicitly ASCII function to avoid any sharp corners resulting from
319 // performing Unicode operations on DNS labels.
320 func toLowerCaseASCII(in
string) string {
321 // If the string is already lower-case then there's nothing to do.
322 isAlreadyLowerCase
:= true
323 for _
, c
:= range in
{
324 if c
== utf8
.RuneError
{
325 // If we get a UTF-8 error then there might be
326 // upper-case ASCII bytes in the invalid sequence.
327 isAlreadyLowerCase
= false
330 if 'A' <= c
&& c
<= 'Z' {
331 isAlreadyLowerCase
= false
336 if isAlreadyLowerCase
{
341 for i
, c
:= range out
{
342 if 'A' <= c
&& c
<= 'Z' {
349 // VerifyHostname returns nil if c is a valid certificate for the named host.
350 // Otherwise it returns an error describing the mismatch.
351 func (c
*Certificate
) VerifyHostname(h
string) error
{
352 // IP addresses may be written in [ ].
354 if len(h
) >= 3 && h
[0] == '[' && h
[len(h
)-1] == ']' {
355 candidateIP
= h
[1 : len(h
)-1]
357 if ip
:= net
.ParseIP(candidateIP
); ip
!= nil {
358 // We only match IP addresses against IP SANs.
359 // https://tools.ietf.org/html/rfc6125#appendix-B.2
360 for _
, candidate
:= range c
.IPAddresses
{
361 if ip
.Equal(candidate
) {
365 return HostnameError
{c
, candidateIP
}
368 lowered
:= toLowerCaseASCII(h
)
370 if len(c
.DNSNames
) > 0 {
371 for _
, match
:= range c
.DNSNames
{
372 if matchHostnames(toLowerCaseASCII(match
), lowered
) {
376 // If Subject Alt Name is given, we ignore the common name.
377 } else if matchHostnames(toLowerCaseASCII(c
.Subject
.CommonName
), lowered
) {
381 return HostnameError
{c
, h
}
384 func checkChainForKeyUsage(chain
[]*Certificate
, keyUsages
[]ExtKeyUsage
) bool {
385 usages
:= make([]ExtKeyUsage
, len(keyUsages
))
386 copy(usages
, keyUsages
)
392 usagesRemaining
:= len(usages
)
394 // We walk down the list and cross out any usages that aren't supported
395 // by each certificate. If we cross out all the usages, then the chain
398 for i
:= len(chain
) - 1; i
>= 0; i
-- {
400 if len(cert
.ExtKeyUsage
) == 0 && len(cert
.UnknownExtKeyUsage
) == 0 {
401 // The certificate doesn't have any extended key usage specified.
405 for _
, usage
:= range cert
.ExtKeyUsage
{
406 if usage
== ExtKeyUsageAny
{
407 // The certificate is explicitly good for any usage.
412 const invalidUsage ExtKeyUsage
= -1
415 for i
, requestedUsage
:= range usages
{
416 if requestedUsage
== invalidUsage
{
420 for _
, usage
:= range cert
.ExtKeyUsage
{
421 if requestedUsage
== usage
{
422 continue NextRequestedUsage
423 } else if requestedUsage
== ExtKeyUsageServerAuth
&&
424 (usage
== ExtKeyUsageNetscapeServerGatedCrypto ||
425 usage
== ExtKeyUsageMicrosoftServerGatedCrypto
) {
426 // In order to support COMODO
427 // certificate chains, we have to
428 // accept Netscape or Microsoft SGC
429 // usages as equal to ServerAuth.
430 continue NextRequestedUsage
434 usages
[i
] = invalidUsage
436 if usagesRemaining
== 0 {