diff options
Diffstat (limited to 'libgo/go/crypto/x509/x509.go')
-rw-r--r-- | libgo/go/crypto/x509/x509.go | 142 |
1 files changed, 87 insertions, 55 deletions
diff --git a/libgo/go/crypto/x509/x509.go b/libgo/go/crypto/x509/x509.go index 949ce018561..fdc7c5307bd 100644 --- a/libgo/go/crypto/x509/x509.go +++ b/libgo/go/crypto/x509/x509.go @@ -3,6 +3,10 @@ // license that can be found in the LICENSE file. // Package x509 parses X.509-encoded keys and certificates. +// +// On UNIX systems the environment variables SSL_CERT_FILE and SSL_CERT_DIR +// can be used to override the system default locations for the SSL certificate +// file and SSL certificate files directory, respectively. package x509 import ( @@ -59,7 +63,7 @@ func ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) { func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorithm pkix.AlgorithmIdentifier, err error) { switch pub := pub.(type) { case *rsa.PublicKey: - publicKeyBytes, err = asn1.Marshal(rsaPublicKey{ + publicKeyBytes, err = asn1.Marshal(pkcs1PublicKey{ N: pub.N, E: pub.E, }) @@ -69,9 +73,7 @@ func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorith publicKeyAlgorithm.Algorithm = oidPublicKeyRSA // This is a NULL parameters value which is required by // https://tools.ietf.org/html/rfc3279#section-2.3.1. - publicKeyAlgorithm.Parameters = asn1.RawValue{ - Tag: 5, - } + publicKeyAlgorithm.Parameters = asn1.NullRawValue case *ecdsa.PublicKey: publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y) oid, ok := oidFromNamedCurve(pub.Curve) @@ -355,10 +357,8 @@ func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue { params := pssParameters{ Hash: pkix.AlgorithmIdentifier{ - Algorithm: hashOID, - Parameters: asn1.RawValue{ - Tag: 5, /* ASN.1 NULL */ - }, + Algorithm: hashOID, + Parameters: asn1.NullRawValue, }, MGF: pkix.AlgorithmIdentifier{ Algorithm: oidMGF1, @@ -368,10 +368,8 @@ func rsaPSSParameters(hashFunc crypto.Hash) asn1.RawValue { } mgf1Params := pkix.AlgorithmIdentifier{ - Algorithm: hashOID, - Parameters: asn1.RawValue{ - Tag: 5, /* ASN.1 NULL */ - }, + Algorithm: hashOID, + Parameters: asn1.NullRawValue, } var err error @@ -418,11 +416,10 @@ func getSignatureAlgorithmFromAI(ai pkix.AlgorithmIdentifier) SignatureAlgorithm // https://tools.ietf.org/html/rfc3447#section-8.1), that the // salt length matches the hash length, and that the trailer // field has the default value. - asn1NULL := []byte{0x05, 0x00} - if !bytes.Equal(params.Hash.Parameters.FullBytes, asn1NULL) || + if !bytes.Equal(params.Hash.Parameters.FullBytes, asn1.NullBytes) || !params.MGF.Algorithm.Equal(oidMGF1) || !mgf1HashFunc.Algorithm.Equal(params.Hash.Algorithm) || - !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1NULL) || + !bytes.Equal(mgf1HashFunc.Parameters.FullBytes, asn1.NullBytes) || params.TrailerField != 1 { return UnknownSignatureAlgorithm } @@ -668,13 +665,28 @@ type Certificate struct { ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages. UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package. - BasicConstraintsValid bool // if true then the next two fields are valid. + // BasicConstraintsValid indicates whether IsCA, MaxPathLen, + // and MaxPathLenZero are valid. + BasicConstraintsValid bool IsCA bool - MaxPathLen int - // MaxPathLenZero indicates that BasicConstraintsValid==true and - // MaxPathLen==0 should be interpreted as an actual maximum path length - // of zero. Otherwise, that combination is interpreted as MaxPathLen - // not being set. + + // MaxPathLen and MaxPathLenZero indicate the presence and + // value of the BasicConstraints' "pathLenConstraint". + // + // When parsing a certificate, a positive non-zero MaxPathLen + // means that the field was specified, -1 means it was unset, + // and MaxPathLenZero being true mean that the field was + // explicitly set to zero. The case of MaxPathLen==0 with MaxPathLenZero==false + // should be treated equivalent to -1 (unset). + // + // When generating a certificate, an unset pathLenConstraint + // can be requested with either MaxPathLen == -1 or using the + // zero value for both MaxPathLen and MaxPathLenZero. + MaxPathLen int + // MaxPathLenZero indicates that BasicConstraintsValid==true + // and MaxPathLen==0 should be interpreted as an actual + // maximum path length of zero. Otherwise, that combination is + // interpreted as MaxPathLen not being set. MaxPathLenZero bool SubjectKeyId []byte @@ -692,6 +704,7 @@ type Certificate struct { // Name constraints PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical. PermittedDNSDomains []string + ExcludedDNSDomains []string // CRL Distribution Points CRLDistributionPoints []string @@ -723,6 +736,10 @@ func (c *Certificate) Equal(other *Certificate) bool { return bytes.Equal(c.Raw, other.Raw) } +func (c *Certificate) hasSANExtension() bool { + return oidInExtensions(oidExtensionSubjectAltName, c.Extensions) +} + // Entrust have a broken root certificate (CN=Entrust.net Certification // Authority (2048)) which isn't marked as a CA certificate and is thus invalid // according to PKIX. @@ -924,20 +941,17 @@ type distributionPointName struct { RelativeName pkix.RDNSequence `asn1:"optional,tag:1"` } -// asn1Null is the ASN.1 encoding of a NULL value. -var asn1Null = []byte{5, 0} - func parsePublicKey(algo PublicKeyAlgorithm, keyData *publicKeyInfo) (interface{}, error) { asn1Data := keyData.PublicKey.RightAlign() switch algo { case RSA: // RSA public keys must have a NULL in the parameters // (https://tools.ietf.org/html/rfc3279#section-2.3.1). - if !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1Null) { + if !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1.NullBytes) { return nil, errors.New("x509: RSA key missing NULL parameters") } - p := new(rsaPublicKey) + p := new(pkcs1PublicKey) rest, err := asn1.Unmarshal(asn1Data, p) if err != nil { return nil, err @@ -1150,7 +1164,7 @@ func parseCertificate(in *certificate) (*Certificate, error) { out.IsCA = constraints.IsCA out.MaxPathLen = constraints.MaxPathLen out.MaxPathLenZero = out.MaxPathLen == 0 - + // TODO: map out.MaxPathLen to 0 if it has the -1 default value? (Issue 19285) case 17: out.DNSNames, out.EmailAddresses, out.IPAddresses, err = parseSANExtension(e.Value) if err != nil { @@ -1185,19 +1199,27 @@ func parseCertificate(in *certificate) (*Certificate, error) { return nil, errors.New("x509: trailing data after X.509 NameConstraints") } - if len(constraints.Excluded) > 0 && e.Critical { - return out, UnhandledCriticalExtension{} - } - - for _, subtree := range constraints.Permitted { - if len(subtree.Name) == 0 { - if e.Critical { - return out, UnhandledCriticalExtension{} + getDNSNames := func(subtrees []generalSubtree, isCritical bool) (dnsNames []string, err error) { + for _, subtree := range subtrees { + if len(subtree.Name) == 0 { + if isCritical { + return nil, UnhandledCriticalExtension{} + } + continue } - continue + dnsNames = append(dnsNames, subtree.Name) } - out.PermittedDNSDomains = append(out.PermittedDNSDomains, subtree.Name) + + return dnsNames, nil + } + + if out.PermittedDNSDomains, err = getDNSNames(constraints.Permitted, e.Critical); err != nil { + return out, err + } + if out.ExcludedDNSDomains, err = getDNSNames(constraints.Excluded, e.Critical); err != nil { + return out, err } + out.PermittedDNSDomainsCritical = e.Critical case 31: // RFC 5280, 4.2.1.13 @@ -1451,7 +1473,7 @@ func marshalSANs(dnsNames, emailAddresses []string, ipAddresses []net.IP) (derBy return asn1.Marshal(rawValues) } -func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) { +func buildExtensions(template *Certificate, authorityKeyId []byte) (ret []pkix.Extension, err error) { ret = make([]pkix.Extension, 10 /* maximum number of elements. */) n := 0 @@ -1525,9 +1547,9 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) { n++ } - if len(template.AuthorityKeyId) > 0 && !oidInExtensions(oidExtensionAuthorityKeyId, template.ExtraExtensions) { + if len(authorityKeyId) > 0 && !oidInExtensions(oidExtensionAuthorityKeyId, template.ExtraExtensions) { ret[n].Id = oidExtensionAuthorityKeyId - ret[n].Value, err = asn1.Marshal(authKeyId{template.AuthorityKeyId}) + ret[n].Value, err = asn1.Marshal(authKeyId{authorityKeyId}) if err != nil { return } @@ -1581,16 +1603,22 @@ func buildExtensions(template *Certificate) (ret []pkix.Extension, err error) { n++ } - if len(template.PermittedDNSDomains) > 0 && + if (len(template.PermittedDNSDomains) > 0 || len(template.ExcludedDNSDomains) > 0) && !oidInExtensions(oidExtensionNameConstraints, template.ExtraExtensions) { ret[n].Id = oidExtensionNameConstraints ret[n].Critical = template.PermittedDNSDomainsCritical var out nameConstraints + out.Permitted = make([]generalSubtree, len(template.PermittedDNSDomains)) for i, permitted := range template.PermittedDNSDomains { out.Permitted[i] = generalSubtree{Name: permitted} } + out.Excluded = make([]generalSubtree, len(template.ExcludedDNSDomains)) + for i, excluded := range template.ExcludedDNSDomains { + out.Excluded[i] = generalSubtree{Name: excluded} + } + ret[n].Value, err = asn1.Marshal(out) if err != nil { return @@ -1646,9 +1674,7 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori pubType = RSA hashFunc = crypto.SHA256 sigAlgo.Algorithm = oidSignatureSHA256WithRSA - sigAlgo.Parameters = asn1.RawValue{ - Tag: 5, - } + sigAlgo.Parameters = asn1.NullRawValue case *ecdsa.PublicKey: pubType = ECDSA @@ -1706,11 +1732,12 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori return } -// CreateCertificate creates a new certificate based on a template. The -// following members of template are used: SerialNumber, Subject, NotBefore, -// NotAfter, KeyUsage, ExtKeyUsage, UnknownExtKeyUsage, BasicConstraintsValid, -// IsCA, MaxPathLen, SubjectKeyId, DNSNames, PermittedDNSDomainsCritical, -// PermittedDNSDomains, SignatureAlgorithm. +// CreateCertificate creates a new certificate based on a template. +// The following members of template are used: AuthorityKeyId, +// BasicConstraintsValid, DNSNames, ExcludedDNSDomains, ExtKeyUsage, +// IsCA, KeyUsage, MaxPathLen, MaxPathLenZero, NotAfter, NotBefore, +// PermittedDNSDomains, PermittedDNSDomainsCritical, SerialNumber, +// SignatureAlgorithm, Subject, SubjectKeyId, and UnknownExtKeyUsage. // // The certificate is signed by parent. If parent is equal to template then the // certificate is self-signed. The parameter pub is the public key of the @@ -1720,6 +1747,10 @@ func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgori // // All keys types that are implemented via crypto.Signer are supported (This // includes *rsa.PublicKey and *ecdsa.PublicKey.) +// +// The AuthorityKeyId will be taken from the SubjectKeyId of parent, if any, +// unless the resulting certificate is self-signed. Otherwise the value from +// template will be used. func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) { key, ok := priv.(crypto.Signer) if !ok { @@ -1750,11 +1781,12 @@ func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv return } + authorityKeyId := template.AuthorityKeyId if !bytes.Equal(asn1Issuer, asn1Subject) && len(parent.SubjectKeyId) > 0 { - template.AuthorityKeyId = parent.SubjectKeyId + authorityKeyId = parent.SubjectKeyId } - extensions, err := buildExtensions(template) + extensions, err := buildExtensions(template, authorityKeyId) if err != nil { return } @@ -2025,10 +2057,10 @@ func parseCSRExtensions(rawAttributes []asn1.RawValue) ([]pkix.Extension, error) return ret, nil } -// CreateCertificateRequest creates a new certificate request based on a template. -// The following members of template are used: Subject, Attributes, -// SignatureAlgorithm, Extensions, DNSNames, EmailAddresses, and IPAddresses. -// The private key is the private key of the signer. +// CreateCertificateRequest creates a new certificate request based on a +// template. The following members of template are used: Attributes, DNSNames, +// EmailAddresses, ExtraExtensions, IPAddresses, SignatureAlgorithm, and +// Subject. The private key is the private key of the signer. // // The returned slice is the certificate request in DER encoding. // |