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.
22 type InvalidReason
int
25 // NotAuthorizedToSign results when a certificate is signed by another
26 // which isn't marked as a CA certificate.
27 NotAuthorizedToSign InvalidReason
= iota
28 // Expired results when a certificate has expired, based on the time
29 // given in the VerifyOptions.
31 // CANotAuthorizedForThisName results when an intermediate or root
32 // certificate has a name constraint which doesn't permit a DNS or
33 // other name (including IP address) in the leaf certificate.
34 CANotAuthorizedForThisName
35 // TooManyIntermediates results when a path length constraint is
38 // IncompatibleUsage results when the certificate's key usage indicates
39 // that it may only be used for a different purpose.
41 // NameMismatch results when the subject name of a parent certificate
42 // does not match the issuer name in the child.
44 // NameConstraintsWithoutSANs results when a leaf certificate doesn't
45 // contain a Subject Alternative Name extension, but a CA certificate
46 // contains name constraints.
47 NameConstraintsWithoutSANs
48 // UnconstrainedName results when a CA certificate contains permitted
49 // name constraints, but leaf certificate contains a name of an
50 // unsupported or unconstrained type.
52 // TooManyConstraints results when the number of comparision operations
53 // needed to check a certificate exceeds the limit set by
54 // VerifyOptions.MaxConstraintComparisions. This limit exists to
55 // prevent pathological certificates can consuming excessive amounts of
56 // CPU time to verify.
58 // CANotAuthorizedForExtKeyUsage results when an intermediate or root
59 // certificate does not permit an extended key usage that is claimed by
60 // the leaf certificate.
61 CANotAuthorizedForExtKeyUsage
64 // CertificateInvalidError results when an odd error occurs. Users of this
65 // library probably want to handle all these errors uniformly.
66 type CertificateInvalidError
struct {
72 func (e CertificateInvalidError
) Error() string {
74 case NotAuthorizedToSign
:
75 return "x509: certificate is not authorized to sign other certificates"
77 return "x509: certificate has expired or is not yet valid"
78 case CANotAuthorizedForThisName
:
79 return "x509: a root or intermediate certificate is not authorized to sign for this name: " + e
.Detail
80 case CANotAuthorizedForExtKeyUsage
:
81 return "x509: a root or intermediate certificate is not authorized for an extended key usage: " + e
.Detail
82 case TooManyIntermediates
:
83 return "x509: too many intermediates for path length constraint"
84 case IncompatibleUsage
:
85 return "x509: certificate specifies an incompatible key usage: " + e
.Detail
87 return "x509: issuer name does not match subject from issuing certificate"
88 case NameConstraintsWithoutSANs
:
89 return "x509: issuer has name constraints but leaf doesn't have a SAN extension"
90 case UnconstrainedName
:
91 return "x509: issuer has name constraints but leaf contains unknown or unconstrained name: " + e
.Detail
93 return "x509: unknown error"
96 // HostnameError results when the set of authorized names doesn't match the
98 type HostnameError
struct {
99 Certificate
*Certificate
103 func (h HostnameError
) Error() string {
107 if ip
:= net
.ParseIP(h
.Host
); ip
!= nil {
108 // Trying to validate an IP
109 if len(c
.IPAddresses
) == 0 {
110 return "x509: cannot validate certificate for " + h
.Host
+ " because it doesn't contain any IP SANs"
112 for _
, san
:= range c
.IPAddresses
{
116 valid
+= san
.String()
119 if c
.hasSANExtension() {
120 valid
= strings
.Join(c
.DNSNames
, ", ")
122 valid
= c
.Subject
.CommonName
127 return "x509: certificate is not valid for any names, but wanted to match " + h
.Host
129 return "x509: certificate is valid for " + valid
+ ", not " + h
.Host
132 // UnknownAuthorityError results when the certificate issuer is unknown
133 type UnknownAuthorityError
struct {
135 // hintErr contains an error that may be helpful in determining why an
136 // authority wasn't found.
138 // hintCert contains a possible authority certificate that was rejected
139 // because of the error in hintErr.
140 hintCert
*Certificate
143 func (e UnknownAuthorityError
) Error() string {
144 s
:= "x509: certificate signed by unknown authority"
145 if e
.hintErr
!= nil {
146 certName
:= e
.hintCert
.Subject
.CommonName
147 if len(certName
) == 0 {
148 if len(e
.hintCert
.Subject
.Organization
) > 0 {
149 certName
= e
.hintCert
.Subject
.Organization
[0]
151 certName
= "serial:" + e
.hintCert
.SerialNumber
.String()
154 s
+= fmt
.Sprintf(" (possibly because of %q while trying to verify candidate authority certificate %q)", e
.hintErr
, certName
)
159 // SystemRootsError results when we fail to load the system root certificates.
160 type SystemRootsError
struct {
164 func (se SystemRootsError
) Error() string {
165 msg
:= "x509: failed to load system roots and no roots provided"
167 return msg
+ "; " + se
.Err
.Error()
172 // errNotParsed is returned when a certificate without ASN.1 contents is
173 // verified. Platform-specific verification needs the ASN.1 contents.
174 var errNotParsed
= errors
.New("x509: missing ASN.1 contents; use ParseCertificate")
176 // VerifyOptions contains parameters for Certificate.Verify. It's a structure
177 // because other PKIX verification APIs have ended up needing many options.
178 type VerifyOptions
struct {
180 Intermediates
*CertPool
181 Roots
*CertPool
// if nil, the system roots are used
182 CurrentTime time
.Time
// if zero, the current time is used
183 // KeyUsage specifies which Extended Key Usage values are acceptable. A leaf
184 // certificate is accepted if it contains any of the listed values. An empty
185 // list means ExtKeyUsageServerAuth. To accept any key usage, include
188 // Certificate chains are required to nest extended key usage values,
189 // irrespective of this value. This matches the Windows CryptoAPI behavior,
191 KeyUsages
[]ExtKeyUsage
192 // MaxConstraintComparisions is the maximum number of comparisons to
193 // perform when checking a given certificate's name constraints. If
194 // zero, a sensible default is used. This limit prevents pathalogical
195 // certificates from consuming excessive amounts of CPU time when
197 MaxConstraintComparisions
int
201 leafCertificate
= iota
202 intermediateCertificate
206 // rfc2821Mailbox represents a “mailbox” (which is an email address to most
207 // people) by breaking it into the “local” (i.e. before the '@') and “domain”
209 type rfc2821Mailbox
struct {
213 // parseRFC2821Mailbox parses an email address into local and domain parts,
214 // based on the ABNF for a “Mailbox” from RFC 2821. According to
215 // https://tools.ietf.org/html/rfc5280#section-4.2.1.6 that's correct for an
216 // rfc822Name from a certificate: “The format of an rfc822Name is a "Mailbox"
217 // as defined in https://tools.ietf.org/html/rfc2821#section-4.1.2”.
218 func parseRFC2821Mailbox(in
string) (mailbox rfc2821Mailbox
, ok
bool) {
220 return mailbox
, false
223 localPartBytes
:= make([]byte, 0, len(in
)/2)
226 // Quoted-string = DQUOTE *qcontent DQUOTE
227 // non-whitespace-control = %d1-8 / %d11 / %d12 / %d14-31 / %d127
228 // qcontent = qtext / quoted-pair
229 // qtext = non-whitespace-control /
230 // %d33 / %d35-91 / %d93-126
231 // quoted-pair = ("\" text) / obs-qp
232 // text = %d1-9 / %d11 / %d12 / %d14-127 / obs-text
234 // (Names beginning with “obs-” are the obsolete syntax from
235 // https://tools.ietf.org/html/rfc2822#section-4. Since it has
236 // been 16 years, we no longer accept that.)
241 return mailbox
, false
253 return mailbox
, false
257 (1 <= in
[0] && in
[0] <= 9) ||
258 (14 <= in
[0] && in
[0] <= 127) {
259 localPartBytes
= append(localPartBytes
, in
[0])
262 return mailbox
, false
267 // Space (char 32) is not allowed based on the
268 // BNF, but RFC 3696 gives an example that
269 // assumes that it is. Several “verified”
270 // errata continue to argue about this point.
271 // We choose to accept it.
275 (1 <= c
&& c
<= 8) ||
276 (14 <= c
&& c
<= 31) ||
277 (35 <= c
&& c
<= 91) ||
278 (93 <= c
&& c
<= 126):
280 localPartBytes
= append(localPartBytes
, c
)
283 return mailbox
, false
290 // atext from https://tools.ietf.org/html/rfc2822#section-3.2.4
295 // Examples given in RFC 3696 suggest that
296 // escaped characters can appear outside of a
297 // quoted string. Several “verified” errata
298 // continue to argue the point. We choose to
302 return mailbox
, false
306 case ('0' <= c
&& c
<= '9') ||
307 ('a' <= c
&& c
<= 'z') ||
308 ('A' <= c
&& c
<= 'Z') ||
309 c
== '!' || c
== '#' || c
== '$' || c
== '%' ||
310 c
== '&' || c
== '\'' || c
== '*' || c
== '+' ||
311 c
== '-' || c
== '/' || c
== '=' || c
== '?' ||
312 c
== '^' || c
== '_' || c
== '`' || c
== '{' ||
313 c
== '|' || c
== '}' || c
== '~' || c
== '.':
314 localPartBytes
= append(localPartBytes
, in
[0])
322 if len(localPartBytes
) == 0 {
323 return mailbox
, false
326 // https://tools.ietf.org/html/rfc3696#section-3
327 // “period (".") may also appear, but may not be used to start
328 // or end the local part, nor may two or more consecutive
330 twoDots
:= []byte{'.', '.'}
331 if localPartBytes
[0] == '.' ||
332 localPartBytes
[len(localPartBytes
)-1] == '.' ||
333 bytes
.Contains(localPartBytes
, twoDots
) {
334 return mailbox
, false
338 if len(in
) == 0 || in
[0] != '@' {
339 return mailbox
, false
343 // The RFC species a format for domains, but that's known to be
344 // violated in practice so we accept that anything after an '@' is the
346 if _
, ok
:= domainToReverseLabels(in
); !ok
{
347 return mailbox
, false
350 mailbox
.local
= string(localPartBytes
)
355 // domainToReverseLabels converts a textual domain name like foo.example.com to
356 // the list of labels in reverse order, e.g. ["com", "example", "foo"].
357 func domainToReverseLabels(domain
string) (reverseLabels
[]string, ok
bool) {
358 for len(domain
) > 0 {
359 if i
:= strings
.LastIndexByte(domain
, '.'); i
== -1 {
360 reverseLabels
= append(reverseLabels
, domain
)
363 reverseLabels
= append(reverseLabels
, domain
[i
+1:len(domain
)])
368 if len(reverseLabels
) > 0 && len(reverseLabels
[0]) == 0 {
369 // An empty label at the end indicates an absolute value.
373 for _
, label
:= range reverseLabels
{
375 // Empty labels are otherwise invalid.
379 for _
, c
:= range label
{
380 if c
< 33 || c
> 126 {
381 // Invalid character.
387 return reverseLabels
, true
390 func matchEmailConstraint(mailbox rfc2821Mailbox
, constraint
string) (bool, error
) {
391 // If the constraint contains an @, then it specifies an exact mailbox
393 if strings
.Contains(constraint
, "@") {
394 constraintMailbox
, ok
:= parseRFC2821Mailbox(constraint
)
396 return false, fmt
.Errorf("x509: internal error: cannot parse constraint %q", constraint
)
398 return mailbox
.local
== constraintMailbox
.local
&& strings
.EqualFold(mailbox
.domain
, constraintMailbox
.domain
), nil
401 // Otherwise the constraint is like a DNS constraint of the domain part
403 return matchDomainConstraint(mailbox
.domain
, constraint
)
406 func matchURIConstraint(uri
*url
.URL
, constraint
string) (bool, error
) {
407 // https://tools.ietf.org/html/rfc5280#section-4.2.1.10
408 // “a uniformResourceIdentifier that does not include an authority
409 // component with a host name specified as a fully qualified domain
410 // name (e.g., if the URI either does not include an authority
411 // component or includes an authority component in which the host name
412 // is specified as an IP address), then the application MUST reject the
417 return false, fmt
.Errorf("URI with empty host (%q) cannot be matched against constraints", uri
.String())
420 if strings
.Contains(host
, ":") && !strings
.HasSuffix(host
, "]") {
422 host
, _
, err
= net
.SplitHostPort(uri
.Host
)
428 if strings
.HasPrefix(host
, "[") && strings
.HasSuffix(host
, "]") ||
429 net
.ParseIP(host
) != nil {
430 return false, fmt
.Errorf("URI with IP (%q) cannot be matched against constraints", uri
.String())
433 return matchDomainConstraint(host
, constraint
)
436 func matchIPConstraint(ip net
.IP
, constraint
*net
.IPNet
) (bool, error
) {
437 if len(ip
) != len(constraint
.IP
) {
442 if mask
:= constraint
.Mask
[i
]; ip
[i
]&mask
!= constraint
.IP
[i
]&mask
{
450 func matchDomainConstraint(domain
, constraint
string) (bool, error
) {
451 // The meaning of zero length constraints is not specified, but this
452 // code follows NSS and accepts them as matching everything.
453 if len(constraint
) == 0 {
457 domainLabels
, ok
:= domainToReverseLabels(domain
)
459 return false, fmt
.Errorf("x509: internal error: cannot parse domain %q", domain
)
462 // RFC 5280 says that a leading period in a domain name means that at
463 // least one label must be prepended, but only for URI and email
464 // constraints, not DNS constraints. The code also supports that
465 // behaviour for DNS constraints.
467 mustHaveSubdomains
:= false
468 if constraint
[0] == '.' {
469 mustHaveSubdomains
= true
470 constraint
= constraint
[1:]
473 constraintLabels
, ok
:= domainToReverseLabels(constraint
)
475 return false, fmt
.Errorf("x509: internal error: cannot parse domain %q", constraint
)
478 if len(domainLabels
) < len(constraintLabels
) ||
479 (mustHaveSubdomains
&& len(domainLabels
) == len(constraintLabels
)) {
483 for i
, constraintLabel
:= range constraintLabels
{
484 if !strings
.EqualFold(constraintLabel
, domainLabels
[i
]) {
492 // checkNameConstraints checks that c permits a child certificate to claim the
493 // given name, of type nameType. The argument parsedName contains the parsed
494 // form of name, suitable for passing to the match function. The total number
495 // of comparisons is tracked in the given count and should not exceed the given
497 func (c
*Certificate
) checkNameConstraints(count
*int,
498 maxConstraintComparisons
int,
501 parsedName
interface{},
502 match
func(parsedName
, constraint
interface{}) (match
bool, err error
),
503 permitted
, excluded
interface{}) error
{
505 excludedValue
:= reflect
.ValueOf(excluded
)
507 *count
+= excludedValue
.Len()
508 if *count
> maxConstraintComparisons
{
509 return CertificateInvalidError
{c
, TooManyConstraints
, ""}
512 for i
:= 0; i
< excludedValue
.Len(); i
++ {
513 constraint
:= excludedValue
.Index(i
).Interface()
514 match
, err
:= match(parsedName
, constraint
)
516 return CertificateInvalidError
{c
, CANotAuthorizedForThisName
, err
.Error()}
520 return CertificateInvalidError
{c
, CANotAuthorizedForThisName
, fmt
.Sprintf("%s %q is excluded by constraint %q", nameType
, name
, constraint
)}
524 permittedValue
:= reflect
.ValueOf(permitted
)
526 *count
+= permittedValue
.Len()
527 if *count
> maxConstraintComparisons
{
528 return CertificateInvalidError
{c
, TooManyConstraints
, ""}
532 for i
:= 0; i
< permittedValue
.Len(); i
++ {
533 constraint
:= permittedValue
.Index(i
).Interface()
536 if ok
, err
= match(parsedName
, constraint
); err
!= nil {
537 return CertificateInvalidError
{c
, CANotAuthorizedForThisName
, err
.Error()}
546 return CertificateInvalidError
{c
, CANotAuthorizedForThisName
, fmt
.Sprintf("%s %q is not permitted by any constraint", nameType
, name
)}
553 checkingAgainstIssuerCert
= iota
554 checkingAgainstLeafCert
557 // ekuPermittedBy returns true iff the given extended key usage is permitted by
558 // the given EKU from a certificate. Normally, this would be a simple
559 // comparison plus a special case for the “any” EKU. But, in order to support
560 // existing certificates, some exceptions are made.
561 func ekuPermittedBy(eku
, certEKU ExtKeyUsage
, context
int) bool {
562 if certEKU
== ExtKeyUsageAny || eku
== certEKU
{
566 // Some exceptions are made to support existing certificates. Firstly,
567 // the ServerAuth and SGC EKUs are treated as a group.
568 mapServerAuthEKUs
:= func(eku ExtKeyUsage
) ExtKeyUsage
{
569 if eku
== ExtKeyUsageNetscapeServerGatedCrypto || eku
== ExtKeyUsageMicrosoftServerGatedCrypto
{
570 return ExtKeyUsageServerAuth
575 eku
= mapServerAuthEKUs(eku
)
576 certEKU
= mapServerAuthEKUs(certEKU
)
582 // If checking a requested EKU against the list in a leaf certificate there
583 // are fewer exceptions.
584 if context
== checkingAgainstLeafCert
{
588 // ServerAuth in a CA permits ClientAuth in the leaf.
589 return (eku
== ExtKeyUsageClientAuth
&& certEKU
== ExtKeyUsageServerAuth
) ||
590 // Any CA may issue an OCSP responder certificate.
591 eku
== ExtKeyUsageOCSPSigning ||
592 // Code-signing CAs can use Microsoft's commercial and
594 (eku
== ExtKeyUsageMicrosoftCommercialCodeSigning || eku
== ExtKeyUsageMicrosoftKernelCodeSigning
) && certEKU
== ExtKeyUsageCodeSigning
597 // isValid performs validity checks on c given that it is a candidate to append
598 // to the chain in currentChain.
599 func (c
*Certificate
) isValid(certType
int, currentChain
[]*Certificate
, opts
*VerifyOptions
) error
{
600 if len(c
.UnhandledCriticalExtensions
) > 0 {
601 return UnhandledCriticalExtension
{}
604 if len(currentChain
) > 0 {
605 child
:= currentChain
[len(currentChain
)-1]
606 if !bytes
.Equal(child
.RawIssuer
, c
.RawSubject
) {
607 return CertificateInvalidError
{c
, NameMismatch
, ""}
611 now
:= opts
.CurrentTime
615 if now
.Before(c
.NotBefore
) || now
.After(c
.NotAfter
) {
616 return CertificateInvalidError
{c
, Expired
, ""}
619 maxConstraintComparisons
:= opts
.MaxConstraintComparisions
620 if maxConstraintComparisons
== 0 {
621 maxConstraintComparisons
= 250000
625 var leaf
*Certificate
626 if certType
== intermediateCertificate || certType
== rootCertificate
{
627 if len(currentChain
) == 0 {
628 return errors
.New("x509: internal error: empty chain when appending CA cert")
630 leaf
= currentChain
[0]
633 if (certType
== intermediateCertificate || certType
== rootCertificate
) && c
.hasNameConstraints() {
634 sanExtension
, ok
:= leaf
.getSANExtension()
636 // This is the deprecated, legacy case of depending on
637 // the CN as a hostname. Chains modern enough to be
638 // using name constraints should not be depending on
640 return CertificateInvalidError
{c
, NameConstraintsWithoutSANs
, ""}
643 err
:= forEachSAN(sanExtension
, func(tag
int, data
[]byte) error
{
647 mailbox
, ok
:= parseRFC2821Mailbox(name
)
649 return fmt
.Errorf("x509: cannot parse rfc822Name %q", mailbox
)
652 if err
:= c
.checkNameConstraints(&comparisonCount
, maxConstraintComparisons
, "email address", name
, mailbox
,
653 func(parsedName
, constraint
interface{}) (bool, error
) {
654 return matchEmailConstraint(parsedName
.(rfc2821Mailbox
), constraint
.(string))
655 }, c
.PermittedEmailAddresses
, c
.ExcludedEmailAddresses
); err
!= nil {
661 if _
, ok
:= domainToReverseLabels(name
); !ok
{
662 return fmt
.Errorf("x509: cannot parse dnsName %q", name
)
665 if err
:= c
.checkNameConstraints(&comparisonCount
, maxConstraintComparisons
, "DNS name", name
, name
,
666 func(parsedName
, constraint
interface{}) (bool, error
) {
667 return matchDomainConstraint(parsedName
.(string), constraint
.(string))
668 }, c
.PermittedDNSDomains
, c
.ExcludedDNSDomains
); err
!= nil {
674 uri
, err
:= url
.Parse(name
)
676 return fmt
.Errorf("x509: internal error: URI SAN %q failed to parse", name
)
679 if err
:= c
.checkNameConstraints(&comparisonCount
, maxConstraintComparisons
, "URI", name
, uri
,
680 func(parsedName
, constraint
interface{}) (bool, error
) {
681 return matchURIConstraint(parsedName
.(*url
.URL
), constraint
.(string))
682 }, c
.PermittedURIDomains
, c
.ExcludedURIDomains
); err
!= nil {
688 if l
:= len(ip
); l
!= net
.IPv4len
&& l
!= net
.IPv6len
{
689 return fmt
.Errorf("x509: internal error: IP SAN %x failed to parse", data
)
692 if err
:= c
.checkNameConstraints(&comparisonCount
, maxConstraintComparisons
, "IP address", ip
.String(), ip
,
693 func(parsedName
, constraint
interface{}) (bool, error
) {
694 return matchIPConstraint(parsedName
.(net
.IP
), constraint
.(*net
.IPNet
))
695 }, c
.PermittedIPRanges
, c
.ExcludedIPRanges
); err
!= nil {
700 // Unknown SAN types are ignored.
711 checkEKUs
:= certType
== intermediateCertificate
713 // If no extended key usages are specified, then all are acceptable.
714 if checkEKUs
&& (len(c
.ExtKeyUsage
) == 0 && len(c
.UnknownExtKeyUsage
) == 0) {
718 // If the “any” key usage is permitted, then no more checks are needed.
720 for _
, caEKU
:= range c
.ExtKeyUsage
{
722 if caEKU
== ExtKeyUsageAny
{
731 for _
, eku
:= range leaf
.ExtKeyUsage
{
732 if comparisonCount
> maxConstraintComparisons
{
733 return CertificateInvalidError
{c
, TooManyConstraints
, ""}
736 for _
, caEKU
:= range c
.ExtKeyUsage
{
738 if ekuPermittedBy(eku
, caEKU
, checkingAgainstIssuerCert
) {
743 oid
, _
:= oidFromExtKeyUsage(eku
)
744 return CertificateInvalidError
{c
, CANotAuthorizedForExtKeyUsage
, fmt
.Sprintf("EKU not permitted: %#v", oid
)}
748 for _
, eku
:= range leaf
.UnknownExtKeyUsage
{
749 if comparisonCount
> maxConstraintComparisons
{
750 return CertificateInvalidError
{c
, TooManyConstraints
, ""}
753 for _
, caEKU
:= range c
.UnknownExtKeyUsage
{
755 if caEKU
.Equal(eku
) {
756 continue NextUnknownEKU
760 return CertificateInvalidError
{c
, CANotAuthorizedForExtKeyUsage
, fmt
.Sprintf("EKU not permitted: %#v", eku
)}
764 // KeyUsage status flags are ignored. From Engineering Security, Peter
765 // Gutmann: A European government CA marked its signing certificates as
766 // being valid for encryption only, but no-one noticed. Another
767 // European CA marked its signature keys as not being valid for
768 // signatures. A different CA marked its own trusted root certificate
769 // as being invalid for certificate signing. Another national CA
770 // distributed a certificate to be used to encrypt data for the
771 // country’s tax authority that was marked as only being usable for
772 // digital signatures but not for encryption. Yet another CA reversed
773 // the order of the bit flags in the keyUsage due to confusion over
774 // encoding endianness, essentially setting a random keyUsage in
775 // certificates that it issued. Another CA created a self-invalidating
776 // certificate by adding a certificate policy statement stipulating
777 // that the certificate had to be used strictly as specified in the
778 // keyUsage, and a keyUsage containing a flag indicating that the RSA
779 // encryption key could only be used for Diffie-Hellman key agreement.
781 if certType
== intermediateCertificate
&& (!c
.BasicConstraintsValid ||
!c
.IsCA
) {
782 return CertificateInvalidError
{c
, NotAuthorizedToSign
, ""}
785 if c
.BasicConstraintsValid
&& c
.MaxPathLen
>= 0 {
786 numIntermediates
:= len(currentChain
) - 1
787 if numIntermediates
> c
.MaxPathLen
{
788 return CertificateInvalidError
{c
, TooManyIntermediates
, ""}
795 // formatOID formats an ASN.1 OBJECT IDENTIFER in the common, dotted style.
796 func formatOID(oid asn1
.ObjectIdentifier
) string {
798 for i
, v
:= range oid
{
802 ret
+= strconv
.Itoa(v
)
807 // Verify attempts to verify c by building one or more chains from c to a
808 // certificate in opts.Roots, using certificates in opts.Intermediates if
809 // needed. If successful, it returns one or more chains where the first
810 // element of the chain is c and the last element is from opts.Roots.
812 // If opts.Roots is nil and system roots are unavailable the returned error
813 // will be of type SystemRootsError.
815 // Name constraints in the intermediates will be applied to all names claimed
816 // in the chain, not just opts.DNSName. Thus it is invalid for a leaf to claim
817 // example.com if an intermediate doesn't permit it, even if example.com is not
818 // the name being validated. Note that DirectoryName constraints are not
821 // Extended Key Usage values are enforced down a chain, so an intermediate or
822 // root that enumerates EKUs prevents a leaf from asserting an EKU not in that
825 // WARNING: this function doesn't do any revocation checking.
826 func (c
*Certificate
) Verify(opts VerifyOptions
) (chains
[][]*Certificate
, err error
) {
827 // Platform-specific verification needs the ASN.1 contents so
828 // this makes the behavior consistent across platforms.
830 return nil, errNotParsed
832 if opts
.Intermediates
!= nil {
833 for _
, intermediate
:= range opts
.Intermediates
.certs
{
834 if len(intermediate
.Raw
) == 0 {
835 return nil, errNotParsed
840 // Use Windows's own verification and chain building.
841 if opts
.Roots
== nil && runtime
.GOOS
== "windows" {
842 return c
.systemVerify(&opts
)
845 if opts
.Roots
== nil {
846 opts
.Roots
= systemRootsPool()
847 if opts
.Roots
== nil {
848 return nil, SystemRootsError
{systemRootsErr
}
852 err
= c
.isValid(leafCertificate
, nil, &opts
)
857 if len(opts
.DNSName
) > 0 {
858 err
= c
.VerifyHostname(opts
.DNSName
)
864 requestedKeyUsages
:= make([]ExtKeyUsage
, len(opts
.KeyUsages
))
865 copy(requestedKeyUsages
, opts
.KeyUsages
)
866 if len(requestedKeyUsages
) == 0 {
867 requestedKeyUsages
= append(requestedKeyUsages
, ExtKeyUsageServerAuth
)
870 // If no key usages are specified, then any are acceptable.
871 checkEKU
:= len(c
.ExtKeyUsage
) > 0
873 for _
, eku
:= range requestedKeyUsages
{
874 if eku
== ExtKeyUsageAny
{
883 for _
, eku
:= range requestedKeyUsages
{
884 for _
, leafEKU
:= range c
.ExtKeyUsage
{
885 if ekuPermittedBy(eku
, leafEKU
, checkingAgainstLeafCert
) {
893 msg
:= "leaf contains the following, recognized EKUs: "
895 for i
, leafEKU
:= range c
.ExtKeyUsage
{
896 oid
, ok
:= oidFromExtKeyUsage(leafEKU
)
904 msg
+= formatOID(oid
)
907 return nil, CertificateInvalidError
{c
, IncompatibleUsage
, msg
}
911 var candidateChains
[][]*Certificate
912 if opts
.Roots
.contains(c
) {
913 candidateChains
= append(candidateChains
, []*Certificate
{c
})
915 if candidateChains
, err
= c
.buildChains(make(map[int][][]*Certificate
), []*Certificate
{c
}, &opts
); err
!= nil {
920 return candidateChains
, nil
923 func appendToFreshChain(chain
[]*Certificate
, cert
*Certificate
) []*Certificate
{
924 n
:= make([]*Certificate
, len(chain
)+1)
930 func (c
*Certificate
) buildChains(cache
map[int][][]*Certificate
, currentChain
[]*Certificate
, opts
*VerifyOptions
) (chains
[][]*Certificate
, err error
) {
931 possibleRoots
, failedRoot
, rootErr
:= opts
.Roots
.findVerifiedParents(c
)
933 for _
, rootNum
:= range possibleRoots
{
934 root
:= opts
.Roots
.certs
[rootNum
]
936 for _
, cert
:= range currentChain
{
937 if cert
.Equal(root
) {
942 err
= root
.isValid(rootCertificate
, currentChain
, opts
)
946 chains
= append(chains
, appendToFreshChain(currentChain
, root
))
949 possibleIntermediates
, failedIntermediate
, intermediateErr
:= opts
.Intermediates
.findVerifiedParents(c
)
951 for _
, intermediateNum
:= range possibleIntermediates
{
952 intermediate
:= opts
.Intermediates
.certs
[intermediateNum
]
953 for _
, cert
:= range currentChain
{
954 if cert
.Equal(intermediate
) {
955 continue nextIntermediate
958 err
= intermediate
.isValid(intermediateCertificate
, currentChain
, opts
)
962 var childChains
[][]*Certificate
963 childChains
, ok
:= cache
[intermediateNum
]
965 childChains
, err
= intermediate
.buildChains(cache
, appendToFreshChain(currentChain
, intermediate
), opts
)
966 cache
[intermediateNum
] = childChains
968 chains
= append(chains
, childChains
...)
975 if len(chains
) == 0 && err
== nil {
977 hintCert
:= failedRoot
979 hintErr
= intermediateErr
980 hintCert
= failedIntermediate
982 err
= UnknownAuthorityError
{c
, hintErr
, hintCert
}
988 func matchHostnames(pattern
, host
string) bool {
989 host
= strings
.TrimSuffix(host
, ".")
990 pattern
= strings
.TrimSuffix(pattern
, ".")
992 if len(pattern
) == 0 ||
len(host
) == 0 {
996 patternParts
:= strings
.Split(pattern
, ".")
997 hostParts
:= strings
.Split(host
, ".")
999 if len(patternParts
) != len(hostParts
) {
1003 for i
, patternPart
:= range patternParts
{
1004 if i
== 0 && patternPart
== "*" {
1007 if patternPart
!= hostParts
[i
] {
1015 // toLowerCaseASCII returns a lower-case version of in. See RFC 6125 6.4.1. We use
1016 // an explicitly ASCII function to avoid any sharp corners resulting from
1017 // performing Unicode operations on DNS labels.
1018 func toLowerCaseASCII(in
string) string {
1019 // If the string is already lower-case then there's nothing to do.
1020 isAlreadyLowerCase
:= true
1021 for _
, c
:= range in
{
1022 if c
== utf8
.RuneError
{
1023 // If we get a UTF-8 error then there might be
1024 // upper-case ASCII bytes in the invalid sequence.
1025 isAlreadyLowerCase
= false
1028 if 'A' <= c
&& c
<= 'Z' {
1029 isAlreadyLowerCase
= false
1034 if isAlreadyLowerCase
{
1039 for i
, c
:= range out
{
1040 if 'A' <= c
&& c
<= 'Z' {
1047 // VerifyHostname returns nil if c is a valid certificate for the named host.
1048 // Otherwise it returns an error describing the mismatch.
1049 func (c
*Certificate
) VerifyHostname(h
string) error
{
1050 // IP addresses may be written in [ ].
1052 if len(h
) >= 3 && h
[0] == '[' && h
[len(h
)-1] == ']' {
1053 candidateIP
= h
[1 : len(h
)-1]
1055 if ip
:= net
.ParseIP(candidateIP
); ip
!= nil {
1056 // We only match IP addresses against IP SANs.
1057 // https://tools.ietf.org/html/rfc6125#appendix-B.2
1058 for _
, candidate
:= range c
.IPAddresses
{
1059 if ip
.Equal(candidate
) {
1063 return HostnameError
{c
, candidateIP
}
1066 lowered
:= toLowerCaseASCII(h
)
1068 if c
.hasSANExtension() {
1069 for _
, match
:= range c
.DNSNames
{
1070 if matchHostnames(toLowerCaseASCII(match
), lowered
) {
1074 // If Subject Alt Name is given, we ignore the common name.
1075 } else if matchHostnames(toLowerCaseASCII(c
.Subject
.CommonName
), lowered
) {
1079 return HostnameError
{c
, h
}