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.
16 type InvalidReason
int
19 // NotAuthorizedToSign results when a certificate is signed by another
20 // which isn't marked as a CA certificate.
21 NotAuthorizedToSign InvalidReason
= iota
22 // Expired results when a certificate has expired, based on the time
23 // given in the VerifyOptions.
25 // CANotAuthorizedForThisName results when an intermediate or root
26 // certificate has a name constraint which doesn't include the name
28 CANotAuthorizedForThisName
29 // TooManyIntermediates results when a path length constraint is
32 // IncompatibleUsage results when the certificate's key usage indicates
33 // that it may only be used for a different purpose.
37 // CertificateInvalidError results when an odd error occurs. Users of this
38 // library probably want to handle all these errors uniformly.
39 type CertificateInvalidError
struct {
44 func (e CertificateInvalidError
) Error() string {
46 case NotAuthorizedToSign
:
47 return "x509: certificate is not authorized to sign other certificates"
49 return "x509: certificate has expired or is not yet valid"
50 case CANotAuthorizedForThisName
:
51 return "x509: a root or intermediate certificate is not authorized to sign in this domain"
52 case TooManyIntermediates
:
53 return "x509: too many intermediates for path length constraint"
54 case IncompatibleUsage
:
55 return "x509: certificate specifies an incompatible key usage"
57 return "x509: unknown error"
60 // HostnameError results when the set of authorized names doesn't match the
62 type HostnameError
struct {
63 Certificate
*Certificate
67 func (h HostnameError
) Error() string {
71 if ip
:= net
.ParseIP(h
.Host
); ip
!= nil {
72 // Trying to validate an IP
73 if len(c
.IPAddresses
) == 0 {
74 return "x509: cannot validate certificate for " + h
.Host
+ " because it doesn't contain any IP SANs"
76 for _
, san
:= range c
.IPAddresses
{
83 if len(c
.DNSNames
) > 0 {
84 valid
= strings
.Join(c
.DNSNames
, ", ")
86 valid
= c
.Subject
.CommonName
89 return "x509: certificate is valid for " + valid
+ ", not " + h
.Host
92 // UnknownAuthorityError results when the certificate issuer is unknown
93 type UnknownAuthorityError
struct {
95 // hintErr contains an error that may be helpful in determining why an
96 // authority wasn't found.
98 // hintCert contains a possible authority certificate that was rejected
99 // because of the error in hintErr.
100 hintCert
*Certificate
103 func (e UnknownAuthorityError
) Error() string {
104 s
:= "x509: certificate signed by unknown authority"
105 if e
.hintErr
!= nil {
106 certName
:= e
.hintCert
.Subject
.CommonName
107 if len(certName
) == 0 {
108 if len(e
.hintCert
.Subject
.Organization
) > 0 {
109 certName
= e
.hintCert
.Subject
.Organization
[0]
111 certName
= "serial:" + e
.hintCert
.SerialNumber
.String()
113 s
+= fmt
.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e
.hintErr
, certName
)
118 // SystemRootsError results when we fail to load the system root certificates.
119 type SystemRootsError
struct {
122 func (e SystemRootsError
) Error() string {
123 return "x509: failed to load system roots and no roots provided"
126 // VerifyOptions contains parameters for Certificate.Verify. It's a structure
127 // because other PKIX verification APIs have ended up needing many options.
128 type VerifyOptions
struct {
130 Intermediates
*CertPool
131 Roots
*CertPool
// if nil, the system roots are used
132 CurrentTime time
.Time
// if zero, the current time is used
133 // KeyUsage specifies which Extended Key Usage values are acceptable.
134 // An empty list means ExtKeyUsageServerAuth. Key usage is considered a
135 // constraint down the chain which mirrors Windows CryptoAPI behaviour,
136 // but not the spec. To accept any key usage, include ExtKeyUsageAny.
137 KeyUsages
[]ExtKeyUsage
141 leafCertificate
= iota
142 intermediateCertificate
146 // isValid performs validity checks on the c.
147 func (c
*Certificate
) isValid(certType
int, currentChain
[]*Certificate
, opts
*VerifyOptions
) error
{
148 now
:= opts
.CurrentTime
152 if now
.Before(c
.NotBefore
) || now
.After(c
.NotAfter
) {
153 return CertificateInvalidError
{c
, Expired
}
156 if len(c
.PermittedDNSDomains
) > 0 {
158 for _
, domain
:= range c
.PermittedDNSDomains
{
159 if opts
.DNSName
== domain ||
160 (strings
.HasSuffix(opts
.DNSName
, domain
) &&
161 len(opts
.DNSName
) >= 1+len(domain
) &&
162 opts
.DNSName
[len(opts
.DNSName
)-len(domain
)-1] == '.') {
169 return CertificateInvalidError
{c
, CANotAuthorizedForThisName
}
173 // KeyUsage status flags are ignored. From Engineering Security, Peter
174 // Gutmann: A European government CA marked its signing certificates as
175 // being valid for encryption only, but no-one noticed. Another
176 // European CA marked its signature keys as not being valid for
177 // signatures. A different CA marked its own trusted root certificate
178 // as being invalid for certificate signing. Another national CA
179 // distributed a certificate to be used to encrypt data for the
180 // country’s tax authority that was marked as only being usable for
181 // digital signatures but not for encryption. Yet another CA reversed
182 // the order of the bit flags in the keyUsage due to confusion over
183 // encoding endianness, essentially setting a random keyUsage in
184 // certificates that it issued. Another CA created a self-invalidating
185 // certificate by adding a certificate policy statement stipulating
186 // that the certificate had to be used strictly as specified in the
187 // keyUsage, and a keyUsage containing a flag indicating that the RSA
188 // encryption key could only be used for Diffie-Hellman key agreement.
190 if certType
== intermediateCertificate
&& (!c
.BasicConstraintsValid ||
!c
.IsCA
) {
191 return CertificateInvalidError
{c
, NotAuthorizedToSign
}
194 if c
.BasicConstraintsValid
&& c
.MaxPathLen
>= 0 {
195 numIntermediates
:= len(currentChain
) - 1
196 if numIntermediates
> c
.MaxPathLen
{
197 return CertificateInvalidError
{c
, TooManyIntermediates
}
204 // Verify attempts to verify c by building one or more chains from c to a
205 // certificate in opts.Roots, using certificates in opts.Intermediates if
206 // needed. If successful, it returns one or more chains where the first
207 // element of the chain is c and the last element is from opts.Roots.
209 // WARNING: this doesn't do any revocation checking.
210 func (c
*Certificate
) Verify(opts VerifyOptions
) (chains
[][]*Certificate
, err error
) {
211 // Use Windows's own verification and chain building.
212 if opts
.Roots
== nil && runtime
.GOOS
== "windows" {
213 return c
.systemVerify(&opts
)
216 if opts
.Roots
== nil {
217 opts
.Roots
= systemRootsPool()
218 if opts
.Roots
== nil {
219 return nil, SystemRootsError
{}
223 err
= c
.isValid(leafCertificate
, nil, &opts
)
228 if len(opts
.DNSName
) > 0 {
229 err
= c
.VerifyHostname(opts
.DNSName
)
235 candidateChains
, err
:= c
.buildChains(make(map[int][][]*Certificate
), []*Certificate
{c
}, &opts
)
240 keyUsages
:= opts
.KeyUsages
241 if len(keyUsages
) == 0 {
242 keyUsages
= []ExtKeyUsage
{ExtKeyUsageServerAuth
}
245 // If any key usage is acceptable then we're done.
246 for _
, usage
:= range keyUsages
{
247 if usage
== ExtKeyUsageAny
{
248 chains
= candidateChains
253 for _
, candidate
:= range candidateChains
{
254 if checkChainForKeyUsage(candidate
, keyUsages
) {
255 chains
= append(chains
, candidate
)
259 if len(chains
) == 0 {
260 err
= CertificateInvalidError
{c
, IncompatibleUsage
}
266 func appendToFreshChain(chain
[]*Certificate
, cert
*Certificate
) []*Certificate
{
267 n
:= make([]*Certificate
, len(chain
)+1)
273 func (c
*Certificate
) buildChains(cache
map[int][][]*Certificate
, currentChain
[]*Certificate
, opts
*VerifyOptions
) (chains
[][]*Certificate
, err error
) {
274 possibleRoots
, failedRoot
, rootErr
:= opts
.Roots
.findVerifiedParents(c
)
275 for _
, rootNum
:= range possibleRoots
{
276 root
:= opts
.Roots
.certs
[rootNum
]
277 err
= root
.isValid(rootCertificate
, currentChain
, opts
)
281 chains
= append(chains
, appendToFreshChain(currentChain
, root
))
284 possibleIntermediates
, failedIntermediate
, intermediateErr
:= opts
.Intermediates
.findVerifiedParents(c
)
286 for _
, intermediateNum
:= range possibleIntermediates
{
287 intermediate
:= opts
.Intermediates
.certs
[intermediateNum
]
288 for _
, cert
:= range currentChain
{
289 if cert
== intermediate
{
290 continue nextIntermediate
293 err
= intermediate
.isValid(intermediateCertificate
, currentChain
, opts
)
297 var childChains
[][]*Certificate
298 childChains
, ok
:= cache
[intermediateNum
]
300 childChains
, err
= intermediate
.buildChains(cache
, appendToFreshChain(currentChain
, intermediate
), opts
)
301 cache
[intermediateNum
] = childChains
303 chains
= append(chains
, childChains
...)
310 if len(chains
) == 0 && err
== nil {
312 hintCert
:= failedRoot
314 hintErr
= intermediateErr
315 hintCert
= failedIntermediate
317 err
= UnknownAuthorityError
{c
, hintErr
, hintCert
}
323 func matchHostnames(pattern
, host
string) bool {
324 if len(pattern
) == 0 ||
len(host
) == 0 {
328 patternParts
:= strings
.Split(pattern
, ".")
329 hostParts
:= strings
.Split(host
, ".")
331 if len(patternParts
) != len(hostParts
) {
335 for i
, patternPart
:= range patternParts
{
336 if patternPart
== "*" {
339 if patternPart
!= hostParts
[i
] {
347 // toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use
348 // an explicitly ASCII function to avoid any sharp corners resulting from
349 // performing Unicode operations on DNS labels.
350 func toLowerCaseASCII(in
string) string {
351 // If the string is already lower-case then there's nothing to do.
352 isAlreadyLowerCase
:= true
353 for _
, c
:= range in
{
354 if c
== utf8
.RuneError
{
355 // If we get a UTF-8 error then there might be
356 // upper-case ASCII bytes in the invalid sequence.
357 isAlreadyLowerCase
= false
360 if 'A' <= c
&& c
<= 'Z' {
361 isAlreadyLowerCase
= false
366 if isAlreadyLowerCase
{
371 for i
, c
:= range out
{
372 if 'A' <= c
&& c
<= 'Z' {
379 // VerifyHostname returns nil if c is a valid certificate for the named host.
380 // Otherwise it returns an error describing the mismatch.
381 func (c
*Certificate
) VerifyHostname(h
string) error
{
382 // IP addresses may be written in [ ].
384 if len(h
) >= 3 && h
[0] == '[' && h
[len(h
)-1] == ']' {
385 candidateIP
= h
[1 : len(h
)-1]
387 if ip
:= net
.ParseIP(candidateIP
); ip
!= nil {
388 // We only match IP addresses against IP SANs.
389 // https://tools.ietf.org/html/rfc6125#appendix-B.2
390 for _
, candidate
:= range c
.IPAddresses
{
391 if ip
.Equal(candidate
) {
395 return HostnameError
{c
, candidateIP
}
398 lowered
:= toLowerCaseASCII(h
)
400 if len(c
.DNSNames
) > 0 {
401 for _
, match
:= range c
.DNSNames
{
402 if matchHostnames(toLowerCaseASCII(match
), lowered
) {
406 // If Subject Alt Name is given, we ignore the common name.
407 } else if matchHostnames(toLowerCaseASCII(c
.Subject
.CommonName
), lowered
) {
411 return HostnameError
{c
, h
}
414 func checkChainForKeyUsage(chain
[]*Certificate
, keyUsages
[]ExtKeyUsage
) bool {
415 usages
:= make([]ExtKeyUsage
, len(keyUsages
))
416 copy(usages
, keyUsages
)
422 usagesRemaining
:= len(usages
)
424 // We walk down the list and cross out any usages that aren't supported
425 // by each certificate. If we cross out all the usages, then the chain
429 for i
:= len(chain
) - 1; i
>= 0; i
-- {
431 if len(cert
.ExtKeyUsage
) == 0 && len(cert
.UnknownExtKeyUsage
) == 0 {
432 // The certificate doesn't have any extended key usage specified.
436 for _
, usage
:= range cert
.ExtKeyUsage
{
437 if usage
== ExtKeyUsageAny
{
438 // The certificate is explicitly good for any usage.
443 const invalidUsage ExtKeyUsage
= -1
446 for i
, requestedUsage
:= range usages
{
447 if requestedUsage
== invalidUsage
{
451 for _
, usage
:= range cert
.ExtKeyUsage
{
452 if requestedUsage
== usage
{
453 continue NextRequestedUsage
454 } else if requestedUsage
== ExtKeyUsageServerAuth
&&
455 (usage
== ExtKeyUsageNetscapeServerGatedCrypto ||
456 usage
== ExtKeyUsageMicrosoftServerGatedCrypto
) {
457 // In order to support COMODO
458 // certificate chains, we have to
459 // accept Netscape or Microsoft SGC
460 // usages as equal to ServerAuth.
461 continue NextRequestedUsage
465 usages
[i
] = invalidUsage
467 if usagesRemaining
== 0 {