},
expectedError: "cannot parse rfc822Name",
},
+
+ // #80: if several EKUs are requested, satisfying any of them is sufficient.
+ nameConstraintsTest{
+ roots: []constraintsSpec{
+ constraintsSpec{},
+ },
+ intermediates: [][]constraintsSpec{
+ []constraintsSpec{
+ constraintsSpec{},
+ },
+ },
+ leaf: leafSpec{
+ sans: []string{"dns:example.com"},
+ ekus: []string{"email"},
+ },
+ requestedEKUs: []ExtKeyUsage{ExtKeyUsageClientAuth, ExtKeyUsageEmailProtection},
+ },
}
func makeConstraintsCACert(constraints constraintsSpec, name string, key *ecdsa.PrivateKey, parent *Certificate, parentKey *ecdsa.PrivateKey) (*Certificate, error) {
import (
"bytes"
+ "encoding/asn1"
"errors"
"fmt"
"net"
"net/url"
"reflect"
"runtime"
+ "strconv"
"strings"
"time"
"unicode/utf8"
Intermediates *CertPool
Roots *CertPool // if nil, the system roots are used
CurrentTime time.Time // if zero, the current time is used
- // KeyUsage specifies which Extended Key Usage values are acceptable.
- // An empty list means ExtKeyUsageServerAuth. Key usage is considered a
- // constraint down the chain which mirrors Windows CryptoAPI behavior,
- // but not the spec. To accept any key usage, include ExtKeyUsageAny.
+ // KeyUsage specifies which Extended Key Usage values are acceptable. A leaf
+ // certificate is accepted if it contains any of the listed values. An empty
+ // list means ExtKeyUsageServerAuth. To accept any key usage, include
+ // ExtKeyUsageAny.
+ //
+ // Certificate chains are required to nest extended key usage values,
+ // irrespective of this value. This matches the Windows CryptoAPI behavior,
+ // but not the spec.
KeyUsages []ExtKeyUsage
// MaxConstraintComparisions is the maximum number of comparisons to
// perform when checking a given certificate's name constraints. If
return nil
}
+// formatOID formats an ASN.1 OBJECT IDENTIFER in the common, dotted style.
+func formatOID(oid asn1.ObjectIdentifier) string {
+ ret := ""
+ for i, v := range oid {
+ if i > 0 {
+ ret += "."
+ }
+ ret += strconv.Itoa(v)
+ }
+ return ret
+}
+
// Verify attempts to verify c by building one or more chains from c to a
// certificate in opts.Roots, using certificates in opts.Intermediates if
// needed. If successful, it returns one or more chains where the first
}
if checkEKU {
+ foundMatch := false
NextUsage:
for _, eku := range requestedKeyUsages {
for _, leafEKU := range c.ExtKeyUsage {
if ekuPermittedBy(eku, leafEKU, checkingAgainstLeafCert) {
- continue NextUsage
+ foundMatch = true
+ break NextUsage
}
}
+ }
- oid, _ := oidFromExtKeyUsage(eku)
- return nil, CertificateInvalidError{c, IncompatibleUsage, fmt.Sprintf("%#v", oid)}
+ if !foundMatch {
+ msg := "leaf contains the following, recognized EKUs: "
+
+ for i, leafEKU := range c.ExtKeyUsage {
+ oid, ok := oidFromExtKeyUsage(leafEKU)
+ if !ok {
+ continue
+ }
+
+ if i > 0 {
+ msg += ", "
+ }
+ msg += formatOID(oid)
+ }
+
+ return nil, CertificateInvalidError{c, IncompatibleUsage, msg}
}
}