// Copyright 2009 The Go Authors. All rights reserved.
// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.

// Package x509 implements a subset of the X.509 standard. // // It allows parsing and generating certificates, certificate signing // requests, certificate revocation lists, and encoded public and private keys. // It provides a certificate verifier, complete with a chain builder. // // The package targets the X.509 technical profile defined by the IETF (RFC // 2459/3280/5280), and as further restricted by the CA/Browser Forum Baseline // Requirements. There is minimal support for features outside of these // profiles, as the primary goal of the package is to provide compatibility // with the publicly trusted TLS certificate ecosystem and its policies and // constraints. // // On macOS and Windows, certificate verification is handled by system APIs, but // the package aims to apply consistent validation rules across operating // systems.
package x509 import ( // Explicitly import these for their crypto.RegisterHash init side-effects. // Keep these as blank imports, even if they're imported above. _ _ _ cryptobyte_asn1 ) // pkixPublicKey reflects a PKIX public key structure. See SubjectPublicKeyInfo // in RFC 3280. type pkixPublicKey struct { Algo pkix.AlgorithmIdentifier BitString asn1.BitString } // ParsePKIXPublicKey parses a public key in PKIX, ASN.1 DER form. The encoded // public key is a SubjectPublicKeyInfo structure (see RFC 5280, Section 4.1). // // It returns a *[rsa.PublicKey], *[dsa.PublicKey], *[ecdsa.PublicKey], // [ed25519.PublicKey] (not a pointer), or *[ecdh.PublicKey] (for X25519). // More types might be supported in the future. // // This kind of key is commonly encoded in PEM blocks of type "PUBLIC KEY". func ( []byte) ( any, error) { var publicKeyInfo if , := asn1.Unmarshal(, &); != nil { if , := asn1.Unmarshal(, &pkcs1PublicKey{}); == nil { return nil, errors.New("x509: failed to parse public key (use ParsePKCS1PublicKey instead for this key format)") } return nil, } else if len() != 0 { return nil, errors.New("x509: trailing data after ASN.1 of public-key") } return parsePublicKey(&) } func marshalPublicKey( any) ( []byte, pkix.AlgorithmIdentifier, error) { switch pub := .(type) { case *rsa.PublicKey: , = asn1.Marshal(pkcs1PublicKey{ N: .N, E: .E, }) if != nil { return nil, pkix.AlgorithmIdentifier{}, } .Algorithm = oidPublicKeyRSA // This is a NULL parameters value which is required by // RFC 3279, Section 2.3.1. .Parameters = asn1.NullRawValue case *ecdsa.PublicKey: , := oidFromNamedCurve(.Curve) if ! { return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve") } if !.Curve.IsOnCurve(.X, .Y) { return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: invalid elliptic curve public key") } = elliptic.Marshal(.Curve, .X, .Y) .Algorithm = oidPublicKeyECDSA var []byte , = asn1.Marshal() if != nil { return } .Parameters.FullBytes = case ed25519.PublicKey: = .Algorithm = oidPublicKeyEd25519 case *ecdh.PublicKey: = .Bytes() if .Curve() == ecdh.X25519() { .Algorithm = oidPublicKeyX25519 } else { , := oidFromECDHCurve(.Curve()) if ! { return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve") } .Algorithm = oidPublicKeyECDSA var []byte , = asn1.Marshal() if != nil { return } .Parameters.FullBytes = } default: return nil, pkix.AlgorithmIdentifier{}, fmt.Errorf("x509: unsupported public key type: %T", ) } return , , nil } // MarshalPKIXPublicKey converts a public key to PKIX, ASN.1 DER form. // The encoded public key is a SubjectPublicKeyInfo structure // (see RFC 5280, Section 4.1). // // The following key types are currently supported: *[rsa.PublicKey], // *[ecdsa.PublicKey], [ed25519.PublicKey] (not a pointer), and *[ecdh.PublicKey]. // Unsupported key types result in an error. // // This kind of key is commonly encoded in PEM blocks of type "PUBLIC KEY". func ( any) ([]byte, error) { var []byte var pkix.AlgorithmIdentifier var error if , , = marshalPublicKey(); != nil { return nil, } := pkixPublicKey{ Algo: , BitString: asn1.BitString{ Bytes: , BitLength: 8 * len(), }, } , := asn1.Marshal() return , nil } // These structures reflect the ASN.1 structure of X.509 certificates.: type certificate struct { TBSCertificate tbsCertificate SignatureAlgorithm pkix.AlgorithmIdentifier SignatureValue asn1.BitString } type tbsCertificate struct { Raw asn1.RawContent Version int `asn1:"optional,explicit,default:0,tag:0"` SerialNumber *big.Int SignatureAlgorithm pkix.AlgorithmIdentifier Issuer asn1.RawValue Validity validity Subject asn1.RawValue PublicKey publicKeyInfo UniqueId asn1.BitString `asn1:"optional,tag:1"` SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"` Extensions []pkix.Extension `asn1:"omitempty,optional,explicit,tag:3"` } type dsaAlgorithmParameters struct { P, Q, G *big.Int } type validity struct { NotBefore, NotAfter time.Time } type publicKeyInfo struct { Raw asn1.RawContent Algorithm pkix.AlgorithmIdentifier PublicKey asn1.BitString } // RFC 5280, 4.2.1.1 type authKeyId struct { Id []byte `asn1:"optional,tag:0"` } type SignatureAlgorithm int const ( UnknownSignatureAlgorithm SignatureAlgorithm = iota MD2WithRSA // Unsupported. MD5WithRSA // Only supported for signing, not verification. SHA1WithRSA // Only supported for signing, and verification of CRLs, CSRs, and OCSP responses. SHA256WithRSA SHA384WithRSA SHA512WithRSA DSAWithSHA1 // Unsupported. DSAWithSHA256 // Unsupported. ECDSAWithSHA1 // Only supported for signing, and verification of CRLs, CSRs, and OCSP responses. ECDSAWithSHA256 ECDSAWithSHA384 ECDSAWithSHA512 SHA256WithRSAPSS SHA384WithRSAPSS SHA512WithRSAPSS PureEd25519 ) func ( SignatureAlgorithm) () bool { for , := range signatureAlgorithmDetails { if .algo == { return .isRSAPSS } } return false } func ( SignatureAlgorithm) () crypto.Hash { for , := range signatureAlgorithmDetails { if .algo == { return .hash } } return crypto.Hash(0) } func ( SignatureAlgorithm) () string { for , := range signatureAlgorithmDetails { if .algo == { return .name } } return strconv.Itoa(int()) } type PublicKeyAlgorithm int const ( UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota RSA DSA // Only supported for parsing. ECDSA Ed25519 ) var publicKeyAlgoName = [...]string{ RSA: "RSA", DSA: "DSA", ECDSA: "ECDSA", Ed25519: "Ed25519", } func ( PublicKeyAlgorithm) () string { if 0 < && int() < len(publicKeyAlgoName) { return publicKeyAlgoName[] } return strconv.Itoa(int()) } // OIDs for signature algorithms // // pkcs-1 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 } // // RFC 3279 2.2.1 RSA Signature Algorithms // // md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 } // // sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 } // // dsaWithSha1 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 } // // RFC 3279 2.2.3 ECDSA Signature Algorithm // // ecdsa-with-SHA1 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) ansi-x962(10045) // signatures(4) ecdsa-with-SHA1(1)} // // RFC 4055 5 PKCS #1 Version 1.5 // // sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 } // // sha384WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 12 } // // sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 } // // RFC 5758 3.1 DSA Signature Algorithms // // dsaWithSha256 OBJECT IDENTIFIER ::= { // joint-iso-ccitt(2) country(16) us(840) organization(1) gov(101) // csor(3) algorithms(4) id-dsa-with-sha2(3) 2} // // RFC 5758 3.2 ECDSA Signature Algorithm // // ecdsa-with-SHA256 OBJECT IDENTIFIER ::= { iso(1) member-body(2) // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 2 } // // ecdsa-with-SHA384 OBJECT IDENTIFIER ::= { iso(1) member-body(2) // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 3 } // // ecdsa-with-SHA512 OBJECT IDENTIFIER ::= { iso(1) member-body(2) // us(840) ansi-X9-62(10045) signatures(4) ecdsa-with-SHA2(3) 4 } // // RFC 8410 3 Curve25519 and Curve448 Algorithm Identifiers // // id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 } var ( oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4} oidSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 5} oidSignatureSHA256WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 11} oidSignatureSHA384WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 12} oidSignatureSHA512WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 13} oidSignatureRSAPSS = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 10} oidSignatureDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 3} oidSignatureDSAWithSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 3, 2} oidSignatureECDSAWithSHA1 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 1} oidSignatureECDSAWithSHA256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 2} oidSignatureECDSAWithSHA384 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 3} oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4} oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112} oidSHA256 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 1} oidSHA384 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 2} oidSHA512 = asn1.ObjectIdentifier{2, 16, 840, 1, 101, 3, 4, 2, 3} oidMGF1 = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 8} // oidISOSignatureSHA1WithRSA means the same as oidSignatureSHA1WithRSA // but it's specified by ISO. Microsoft's makecert.exe has been known // to produce certificates with this OID. oidISOSignatureSHA1WithRSA = asn1.ObjectIdentifier{1, 3, 14, 3, 2, 29} ) var signatureAlgorithmDetails = []struct { algo SignatureAlgorithm name string oid asn1.ObjectIdentifier params asn1.RawValue pubKeyAlgo PublicKeyAlgorithm hash crypto.Hash isRSAPSS bool }{ {MD5WithRSA, "MD5-RSA", oidSignatureMD5WithRSA, asn1.NullRawValue, RSA, crypto.MD5, false}, {SHA1WithRSA, "SHA1-RSA", oidSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false}, {SHA1WithRSA, "SHA1-RSA", oidISOSignatureSHA1WithRSA, asn1.NullRawValue, RSA, crypto.SHA1, false}, {SHA256WithRSA, "SHA256-RSA", oidSignatureSHA256WithRSA, asn1.NullRawValue, RSA, crypto.SHA256, false}, {SHA384WithRSA, "SHA384-RSA", oidSignatureSHA384WithRSA, asn1.NullRawValue, RSA, crypto.SHA384, false}, {SHA512WithRSA, "SHA512-RSA", oidSignatureSHA512WithRSA, asn1.NullRawValue, RSA, crypto.SHA512, false}, {SHA256WithRSAPSS, "SHA256-RSAPSS", oidSignatureRSAPSS, pssParametersSHA256, RSA, crypto.SHA256, true}, {SHA384WithRSAPSS, "SHA384-RSAPSS", oidSignatureRSAPSS, pssParametersSHA384, RSA, crypto.SHA384, true}, {SHA512WithRSAPSS, "SHA512-RSAPSS", oidSignatureRSAPSS, pssParametersSHA512, RSA, crypto.SHA512, true}, {DSAWithSHA1, "DSA-SHA1", oidSignatureDSAWithSHA1, emptyRawValue, DSA, crypto.SHA1, false}, {DSAWithSHA256, "DSA-SHA256", oidSignatureDSAWithSHA256, emptyRawValue, DSA, crypto.SHA256, false}, {ECDSAWithSHA1, "ECDSA-SHA1", oidSignatureECDSAWithSHA1, emptyRawValue, ECDSA, crypto.SHA1, false}, {ECDSAWithSHA256, "ECDSA-SHA256", oidSignatureECDSAWithSHA256, emptyRawValue, ECDSA, crypto.SHA256, false}, {ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, emptyRawValue, ECDSA, crypto.SHA384, false}, {ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, emptyRawValue, ECDSA, crypto.SHA512, false}, {PureEd25519, "Ed25519", oidSignatureEd25519, emptyRawValue, Ed25519, crypto.Hash(0) /* no pre-hashing */, false}, } var emptyRawValue = asn1.RawValue{} // DER encoded RSA PSS parameters for the // SHA256, SHA384, and SHA512 hashes as defined in RFC 3447, Appendix A.2.3. // The parameters contain the following values: // - hashAlgorithm contains the associated hash identifier with NULL parameters // - maskGenAlgorithm always contains the default mgf1SHA1 identifier // - saltLength contains the length of the associated hash // - trailerField always contains the default trailerFieldBC value var ( pssParametersSHA256 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 1, 5, 0, 162, 3, 2, 1, 32}} pssParametersSHA384 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 2, 5, 0, 162, 3, 2, 1, 48}} pssParametersSHA512 = asn1.RawValue{FullBytes: []byte{48, 52, 160, 15, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 161, 28, 48, 26, 6, 9, 42, 134, 72, 134, 247, 13, 1, 1, 8, 48, 13, 6, 9, 96, 134, 72, 1, 101, 3, 4, 2, 3, 5, 0, 162, 3, 2, 1, 64}} ) // pssParameters reflects the parameters in an AlgorithmIdentifier that // specifies RSA PSS. See RFC 3447, Appendix A.2.3. type pssParameters struct { // The following three fields are not marked as // optional because the default values specify SHA-1, // which is no longer suitable for use in signatures. Hash pkix.AlgorithmIdentifier `asn1:"explicit,tag:0"` MGF pkix.AlgorithmIdentifier `asn1:"explicit,tag:1"` SaltLength int `asn1:"explicit,tag:2"` TrailerField int `asn1:"optional,explicit,tag:3,default:1"` } func getSignatureAlgorithmFromAI( pkix.AlgorithmIdentifier) SignatureAlgorithm { if .Algorithm.Equal(oidSignatureEd25519) { // RFC 8410, Section 3 // > For all of the OIDs, the parameters MUST be absent. if len(.Parameters.FullBytes) != 0 { return UnknownSignatureAlgorithm } } if !.Algorithm.Equal(oidSignatureRSAPSS) { for , := range signatureAlgorithmDetails { if .Algorithm.Equal(.oid) { return .algo } } return UnknownSignatureAlgorithm } // RSA PSS is special because it encodes important parameters // in the Parameters. var pssParameters if , := asn1.Unmarshal(.Parameters.FullBytes, &); != nil { return UnknownSignatureAlgorithm } var pkix.AlgorithmIdentifier if , := asn1.Unmarshal(.MGF.Parameters.FullBytes, &); != nil { return UnknownSignatureAlgorithm } // PSS is greatly overburdened with options. This code forces them into // three buckets by requiring that the MGF1 hash function always match the // message hash function (as recommended in RFC 3447, Section 8.1), that the // salt length matches the hash length, and that the trailer field has the // default value. if (len(.Hash.Parameters.FullBytes) != 0 && !bytes.Equal(.Hash.Parameters.FullBytes, asn1.NullBytes)) || !.MGF.Algorithm.Equal(oidMGF1) || !.Algorithm.Equal(.Hash.Algorithm) || (len(.Parameters.FullBytes) != 0 && !bytes.Equal(.Parameters.FullBytes, asn1.NullBytes)) || .TrailerField != 1 { return UnknownSignatureAlgorithm } switch { case .Hash.Algorithm.Equal(oidSHA256) && .SaltLength == 32: return SHA256WithRSAPSS case .Hash.Algorithm.Equal(oidSHA384) && .SaltLength == 48: return SHA384WithRSAPSS case .Hash.Algorithm.Equal(oidSHA512) && .SaltLength == 64: return SHA512WithRSAPSS } return UnknownSignatureAlgorithm } var ( // RFC 3279, 2.3 Public Key Algorithms // // pkcs-1 OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840) // rsadsi(113549) pkcs(1) 1 } // // rsaEncryption OBJECT IDENTIFIER ::== { pkcs1-1 1 } // // id-dsa OBJECT IDENTIFIER ::== { iso(1) member-body(2) us(840) // x9-57(10040) x9cm(4) 1 } oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1} oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1} // RFC 5480, 2.1.1 Unrestricted Algorithm Identifier and Parameters // // id-ecPublicKey OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) ansi-X9-62(10045) keyType(2) 1 } oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1} // RFC 8410, Section 3 // // id-X25519 OBJECT IDENTIFIER ::= { 1 3 101 110 } // id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 } oidPublicKeyX25519 = asn1.ObjectIdentifier{1, 3, 101, 110} oidPublicKeyEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112} ) // getPublicKeyAlgorithmFromOID returns the exposed PublicKeyAlgorithm // identifier for public key types supported in certificates and CSRs. Marshal // and Parse functions may support a different set of public key types. func getPublicKeyAlgorithmFromOID( asn1.ObjectIdentifier) PublicKeyAlgorithm { switch { case .Equal(oidPublicKeyRSA): return RSA case .Equal(oidPublicKeyDSA): return DSA case .Equal(oidPublicKeyECDSA): return ECDSA case .Equal(oidPublicKeyEd25519): return Ed25519 } return UnknownPublicKeyAlgorithm } // RFC 5480, 2.1.1.1. Named Curve // // secp224r1 OBJECT IDENTIFIER ::= { // iso(1) identified-organization(3) certicom(132) curve(0) 33 } // // secp256r1 OBJECT IDENTIFIER ::= { // iso(1) member-body(2) us(840) ansi-X9-62(10045) curves(3) // prime(1) 7 } // // secp384r1 OBJECT IDENTIFIER ::= { // iso(1) identified-organization(3) certicom(132) curve(0) 34 } // // secp521r1 OBJECT IDENTIFIER ::= { // iso(1) identified-organization(3) certicom(132) curve(0) 35 } // // NB: secp256r1 is equivalent to prime256v1 var ( oidNamedCurveP224 = asn1.ObjectIdentifier{1, 3, 132, 0, 33} oidNamedCurveP256 = asn1.ObjectIdentifier{1, 2, 840, 10045, 3, 1, 7} oidNamedCurveP384 = asn1.ObjectIdentifier{1, 3, 132, 0, 34} oidNamedCurveP521 = asn1.ObjectIdentifier{1, 3, 132, 0, 35} ) func namedCurveFromOID( asn1.ObjectIdentifier) elliptic.Curve { switch { case .Equal(oidNamedCurveP224): return elliptic.P224() case .Equal(oidNamedCurveP256): return elliptic.P256() case .Equal(oidNamedCurveP384): return elliptic.P384() case .Equal(oidNamedCurveP521): return elliptic.P521() } return nil } func oidFromNamedCurve( elliptic.Curve) (asn1.ObjectIdentifier, bool) { switch { case elliptic.P224(): return oidNamedCurveP224, true case elliptic.P256(): return oidNamedCurveP256, true case elliptic.P384(): return oidNamedCurveP384, true case elliptic.P521(): return oidNamedCurveP521, true } return nil, false } func oidFromECDHCurve( ecdh.Curve) (asn1.ObjectIdentifier, bool) { switch { case ecdh.X25519(): return oidPublicKeyX25519, true case ecdh.P256(): return oidNamedCurveP256, true case ecdh.P384(): return oidNamedCurveP384, true case ecdh.P521(): return oidNamedCurveP521, true } return nil, false } // KeyUsage represents the set of actions that are valid for a given key. It's // a bitmap of the KeyUsage* constants. type KeyUsage int const ( KeyUsageDigitalSignature KeyUsage = 1 << iota KeyUsageContentCommitment KeyUsageKeyEncipherment KeyUsageDataEncipherment KeyUsageKeyAgreement KeyUsageCertSign KeyUsageCRLSign KeyUsageEncipherOnly KeyUsageDecipherOnly ) // RFC 5280, 4.2.1.12 Extended Key Usage // // anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 } // // id-kp OBJECT IDENTIFIER ::= { id-pkix 3 } // // id-kp-serverAuth OBJECT IDENTIFIER ::= { id-kp 1 } // id-kp-clientAuth OBJECT IDENTIFIER ::= { id-kp 2 } // id-kp-codeSigning OBJECT IDENTIFIER ::= { id-kp 3 } // id-kp-emailProtection OBJECT IDENTIFIER ::= { id-kp 4 } // id-kp-timeStamping OBJECT IDENTIFIER ::= { id-kp 8 } // id-kp-OCSPSigning OBJECT IDENTIFIER ::= { id-kp 9 } var ( oidExtKeyUsageAny = asn1.ObjectIdentifier{2, 5, 29, 37, 0} oidExtKeyUsageServerAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 1} oidExtKeyUsageClientAuth = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 2} oidExtKeyUsageCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 3} oidExtKeyUsageEmailProtection = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 4} oidExtKeyUsageIPSECEndSystem = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 5} oidExtKeyUsageIPSECTunnel = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 6} oidExtKeyUsageIPSECUser = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 7} oidExtKeyUsageTimeStamping = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 8} oidExtKeyUsageOCSPSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 3, 9} oidExtKeyUsageMicrosoftServerGatedCrypto = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 10, 3, 3} oidExtKeyUsageNetscapeServerGatedCrypto = asn1.ObjectIdentifier{2, 16, 840, 1, 113730, 4, 1} oidExtKeyUsageMicrosoftCommercialCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 2, 1, 22} oidExtKeyUsageMicrosoftKernelCodeSigning = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 311, 61, 1, 1} ) // ExtKeyUsage represents an extended set of actions that are valid for a given key. // Each of the ExtKeyUsage* constants define a unique action. type ExtKeyUsage int const ( ExtKeyUsageAny ExtKeyUsage = iota ExtKeyUsageServerAuth ExtKeyUsageClientAuth ExtKeyUsageCodeSigning ExtKeyUsageEmailProtection ExtKeyUsageIPSECEndSystem ExtKeyUsageIPSECTunnel ExtKeyUsageIPSECUser ExtKeyUsageTimeStamping ExtKeyUsageOCSPSigning ExtKeyUsageMicrosoftServerGatedCrypto ExtKeyUsageNetscapeServerGatedCrypto ExtKeyUsageMicrosoftCommercialCodeSigning ExtKeyUsageMicrosoftKernelCodeSigning ) // extKeyUsageOIDs contains the mapping between an ExtKeyUsage and its OID. var extKeyUsageOIDs = []struct { extKeyUsage ExtKeyUsage oid asn1.ObjectIdentifier }{ {ExtKeyUsageAny, oidExtKeyUsageAny}, {ExtKeyUsageServerAuth, oidExtKeyUsageServerAuth}, {ExtKeyUsageClientAuth, oidExtKeyUsageClientAuth}, {ExtKeyUsageCodeSigning, oidExtKeyUsageCodeSigning}, {ExtKeyUsageEmailProtection, oidExtKeyUsageEmailProtection}, {ExtKeyUsageIPSECEndSystem, oidExtKeyUsageIPSECEndSystem}, {ExtKeyUsageIPSECTunnel, oidExtKeyUsageIPSECTunnel}, {ExtKeyUsageIPSECUser, oidExtKeyUsageIPSECUser}, {ExtKeyUsageTimeStamping, oidExtKeyUsageTimeStamping}, {ExtKeyUsageOCSPSigning, oidExtKeyUsageOCSPSigning}, {ExtKeyUsageMicrosoftServerGatedCrypto, oidExtKeyUsageMicrosoftServerGatedCrypto}, {ExtKeyUsageNetscapeServerGatedCrypto, oidExtKeyUsageNetscapeServerGatedCrypto}, {ExtKeyUsageMicrosoftCommercialCodeSigning, oidExtKeyUsageMicrosoftCommercialCodeSigning}, {ExtKeyUsageMicrosoftKernelCodeSigning, oidExtKeyUsageMicrosoftKernelCodeSigning}, } func extKeyUsageFromOID( asn1.ObjectIdentifier) ( ExtKeyUsage, bool) { for , := range extKeyUsageOIDs { if .Equal(.oid) { return .extKeyUsage, true } } return } func oidFromExtKeyUsage( ExtKeyUsage) ( asn1.ObjectIdentifier, bool) { for , := range extKeyUsageOIDs { if == .extKeyUsage { return .oid, true } } return } // A Certificate represents an X.509 certificate. type Certificate struct { Raw []byte // Complete ASN.1 DER content (certificate, signature algorithm and signature). RawTBSCertificate []byte // Certificate part of raw ASN.1 DER content. RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo. RawSubject []byte // DER encoded Subject RawIssuer []byte // DER encoded Issuer Signature []byte SignatureAlgorithm SignatureAlgorithm PublicKeyAlgorithm PublicKeyAlgorithm PublicKey any Version int SerialNumber *big.Int Issuer pkix.Name Subject pkix.Name NotBefore, NotAfter time.Time // Validity bounds. KeyUsage KeyUsage // Extensions contains raw X.509 extensions. When parsing certificates, // this can be used to extract non-critical extensions that are not // parsed by this package. When marshaling certificates, the Extensions // field is ignored, see ExtraExtensions. Extensions []pkix.Extension // ExtraExtensions contains extensions to be copied, raw, into any // marshaled certificates. Values override any extensions that would // otherwise be produced based on the other fields. The ExtraExtensions // field is not populated when parsing certificates, see Extensions. ExtraExtensions []pkix.Extension // UnhandledCriticalExtensions contains a list of extension IDs that // were not (fully) processed when parsing. Verify will fail if this // slice is non-empty, unless verification is delegated to an OS // library which understands all the critical extensions. // // Users can access these extensions using Extensions and can remove // elements from this slice if they believe that they have been // handled. UnhandledCriticalExtensions []asn1.ObjectIdentifier ExtKeyUsage []ExtKeyUsage // Sequence of extended key usages. UnknownExtKeyUsage []asn1.ObjectIdentifier // Encountered extended key usages unknown to this package. // BasicConstraintsValid indicates whether IsCA, MaxPathLen, // and MaxPathLenZero are valid. BasicConstraintsValid bool IsCA bool // 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 AuthorityKeyId []byte // RFC 5280, 4.2.2.1 (Authority Information Access) OCSPServer []string IssuingCertificateURL []string // Subject Alternate Name values. (Note that these values may not be valid // if invalid values were contained within a parsed certificate. For // example, an element of DNSNames may not be a valid DNS domain name.) DNSNames []string EmailAddresses []string IPAddresses []net.IP URIs []*url.URL // Name constraints PermittedDNSDomainsCritical bool // if true then the name constraints are marked critical. PermittedDNSDomains []string ExcludedDNSDomains []string PermittedIPRanges []*net.IPNet ExcludedIPRanges []*net.IPNet PermittedEmailAddresses []string ExcludedEmailAddresses []string PermittedURIDomains []string ExcludedURIDomains []string // CRL Distribution Points CRLDistributionPoints []string // PolicyIdentifiers contains asn1.ObjectIdentifiers, the components // of which are limited to int32. If a certificate contains a policy which // cannot be represented by asn1.ObjectIdentifier, it will not be included in // PolicyIdentifiers, but will be present in Policies, which contains all parsed // policy OIDs. PolicyIdentifiers []asn1.ObjectIdentifier // Policies contains all policy identifiers included in the certificate. // In Go 1.22, encoding/gob cannot handle and ignores this field. Policies []OID } // ErrUnsupportedAlgorithm results from attempting to perform an operation that // involves algorithms that are not currently implemented. var ErrUnsupportedAlgorithm = errors.New("x509: cannot verify signature: algorithm unimplemented") // An InsecureAlgorithmError indicates that the [SignatureAlgorithm] used to // generate the signature is not secure, and the signature has been rejected. // // To temporarily restore support for SHA-1 signatures, include the value // "x509sha1=1" in the GODEBUG environment variable. Note that this option will // be removed in a future release. type InsecureAlgorithmError SignatureAlgorithm func ( InsecureAlgorithmError) () string { var string if SignatureAlgorithm() == SHA1WithRSA || SignatureAlgorithm() == ECDSAWithSHA1 { = " (temporarily override with GODEBUG=x509sha1=1)" } return fmt.Sprintf("x509: cannot verify signature: insecure algorithm %v", SignatureAlgorithm()) + } // ConstraintViolationError results when a requested usage is not permitted by // a certificate. For example: checking a signature when the public key isn't a // certificate signing key. type ConstraintViolationError struct{} func (ConstraintViolationError) () string { return "x509: invalid signature: parent certificate cannot sign this kind of certificate" } func ( *Certificate) ( *Certificate) bool { if == nil || == nil { return == } return bytes.Equal(.Raw, .Raw) } func ( *Certificate) () bool { return oidInExtensions(oidExtensionSubjectAltName, .Extensions) } // CheckSignatureFrom verifies that the signature on c is a valid signature from parent. // // This is a low-level API that performs very limited checks, and not a full // path verifier. Most users should use [Certificate.Verify] instead. func ( *Certificate) ( *Certificate) error { // RFC 5280, 4.2.1.9: // "If the basic constraints extension is not present in a version 3 // certificate, or the extension is present but the cA boolean is not // asserted, then the certified public key MUST NOT be used to verify // certificate signatures." if .Version == 3 && !.BasicConstraintsValid || .BasicConstraintsValid && !.IsCA { return ConstraintViolationError{} } if .KeyUsage != 0 && .KeyUsage&KeyUsageCertSign == 0 { return ConstraintViolationError{} } if .PublicKeyAlgorithm == UnknownPublicKeyAlgorithm { return ErrUnsupportedAlgorithm } return checkSignature(.SignatureAlgorithm, .RawTBSCertificate, .Signature, .PublicKey, false) } // CheckSignature verifies that signature is a valid signature over signed from // c's public key. // // This is a low-level API that performs no validity checks on the certificate. // // [MD5WithRSA] signatures are rejected, while [SHA1WithRSA] and [ECDSAWithSHA1] // signatures are currently accepted. func ( *Certificate) ( SignatureAlgorithm, , []byte) error { return checkSignature(, , , .PublicKey, true) } func ( *Certificate) () bool { return oidInExtensions(oidExtensionNameConstraints, .Extensions) } func ( *Certificate) () []byte { for , := range .Extensions { if .Id.Equal(oidExtensionSubjectAltName) { return .Value } } return nil } func signaturePublicKeyAlgoMismatchError( PublicKeyAlgorithm, any) error { return fmt.Errorf("x509: signature algorithm specifies an %s public key, but have public key of type %T", .String(), ) } var x509sha1 = godebug.New("x509sha1") // checkSignature verifies that signature is a valid signature over signed from // a crypto.PublicKey. func checkSignature( SignatureAlgorithm, , []byte, crypto.PublicKey, bool) ( error) { var crypto.Hash var PublicKeyAlgorithm for , := range signatureAlgorithmDetails { if .algo == { = .hash = .pubKeyAlgo break } } switch { case crypto.Hash(0): if != Ed25519 { return ErrUnsupportedAlgorithm } case crypto.MD5: return InsecureAlgorithmError() case crypto.SHA1: // SHA-1 signatures are mostly disabled. See go.dev/issue/41682. if ! { if x509sha1.Value() != "1" { return InsecureAlgorithmError() } x509sha1.IncNonDefault() } fallthrough default: if !.Available() { return ErrUnsupportedAlgorithm } := .New() .Write() = .Sum(nil) } switch pub := .(type) { case *rsa.PublicKey: if != RSA { return signaturePublicKeyAlgoMismatchError(, ) } if .isRSAPSS() { return rsa.VerifyPSS(, , , , &rsa.PSSOptions{SaltLength: rsa.PSSSaltLengthEqualsHash}) } else { return rsa.VerifyPKCS1v15(, , , ) } case *ecdsa.PublicKey: if != ECDSA { return signaturePublicKeyAlgoMismatchError(, ) } if !ecdsa.VerifyASN1(, , ) { return errors.New("x509: ECDSA verification failure") } return case ed25519.PublicKey: if != Ed25519 { return signaturePublicKeyAlgoMismatchError(, ) } if !ed25519.Verify(, , ) { return errors.New("x509: Ed25519 verification failure") } return } return ErrUnsupportedAlgorithm } // CheckCRLSignature checks that the signature in crl is from c. // // Deprecated: Use [RevocationList.CheckSignatureFrom] instead. func ( *Certificate) ( *pkix.CertificateList) error { := getSignatureAlgorithmFromAI(.SignatureAlgorithm) return .CheckSignature(, .TBSCertList.Raw, .SignatureValue.RightAlign()) } type UnhandledCriticalExtension struct{} func ( UnhandledCriticalExtension) () string { return "x509: unhandled critical extension" } type basicConstraints struct { IsCA bool `asn1:"optional"` MaxPathLen int `asn1:"optional,default:-1"` } // RFC 5280 4.2.1.4 type policyInformation struct { Policy asn1.ObjectIdentifier // policyQualifiers omitted } const ( nameTypeEmail = 1 nameTypeDNS = 2 nameTypeURI = 6 nameTypeIP = 7 ) // RFC 5280, 4.2.2.1 type authorityInfoAccess struct { Method asn1.ObjectIdentifier Location asn1.RawValue } // RFC 5280, 4.2.1.14 type distributionPoint struct { DistributionPoint distributionPointName `asn1:"optional,tag:0"` Reason asn1.BitString `asn1:"optional,tag:1"` CRLIssuer asn1.RawValue `asn1:"optional,tag:2"` } type distributionPointName struct { FullName []asn1.RawValue `asn1:"optional,tag:0"` RelativeName pkix.RDNSequence `asn1:"optional,tag:1"` } func reverseBitsInAByte( byte) byte { := >>4 | <<4 := >>2&0x33 | <<2&0xcc := >>1&0x55 | <<1&0xaa return } // asn1BitLength returns the bit-length of bitString by considering the // most-significant bit in a byte to be the "first" bit. This convention // matches ASN.1, but differs from almost everything else. func asn1BitLength( []byte) int { := len() * 8 for := range { := [len()--1] for := uint(0); < 8; ++ { if (>>)&1 == 1 { return } -- } } return 0 } var ( oidExtensionSubjectKeyId = []int{2, 5, 29, 14} oidExtensionKeyUsage = []int{2, 5, 29, 15} oidExtensionExtendedKeyUsage = []int{2, 5, 29, 37} oidExtensionAuthorityKeyId = []int{2, 5, 29, 35} oidExtensionBasicConstraints = []int{2, 5, 29, 19} oidExtensionSubjectAltName = []int{2, 5, 29, 17} oidExtensionCertificatePolicies = []int{2, 5, 29, 32} oidExtensionNameConstraints = []int{2, 5, 29, 30} oidExtensionCRLDistributionPoints = []int{2, 5, 29, 31} oidExtensionAuthorityInfoAccess = []int{1, 3, 6, 1, 5, 5, 7, 1, 1} oidExtensionCRLNumber = []int{2, 5, 29, 20} oidExtensionReasonCode = []int{2, 5, 29, 21} ) var ( oidAuthorityInfoAccessOcsp = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 1} oidAuthorityInfoAccessIssuers = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 2} ) // oidInExtensions reports whether an extension with the given oid exists in // extensions. func oidInExtensions( asn1.ObjectIdentifier, []pkix.Extension) bool { for , := range { if .Id.Equal() { return true } } return false } // marshalSANs marshals a list of addresses into a the contents of an X.509 // SubjectAlternativeName extension. func marshalSANs(, []string, []net.IP, []*url.URL) ( []byte, error) { var []asn1.RawValue for , := range { if := isIA5String(); != nil { return nil, } = append(, asn1.RawValue{Tag: nameTypeDNS, Class: 2, Bytes: []byte()}) } for , := range { if := isIA5String(); != nil { return nil, } = append(, asn1.RawValue{Tag: nameTypeEmail, Class: 2, Bytes: []byte()}) } for , := range { // If possible, we always want to encode IPv4 addresses in 4 bytes. := .To4() if == nil { = } = append(, asn1.RawValue{Tag: nameTypeIP, Class: 2, Bytes: }) } for , := range { := .String() if := isIA5String(); != nil { return nil, } = append(, asn1.RawValue{Tag: nameTypeURI, Class: 2, Bytes: []byte()}) } return asn1.Marshal() } func isIA5String( string) error { for , := range { // Per RFC5280 "IA5String is limited to the set of ASCII characters" if > unicode.MaxASCII { return fmt.Errorf("x509: %q cannot be encoded as an IA5String", ) } } return nil } var x509usepolicies = godebug.New("x509usepolicies") func buildCertExtensions( *Certificate, bool, []byte, []byte) ( []pkix.Extension, error) { = make([]pkix.Extension, 10 /* maximum number of elements. */) := 0 if .KeyUsage != 0 && !oidInExtensions(oidExtensionKeyUsage, .ExtraExtensions) { [], = marshalKeyUsage(.KeyUsage) if != nil { return nil, } ++ } if (len(.ExtKeyUsage) > 0 || len(.UnknownExtKeyUsage) > 0) && !oidInExtensions(oidExtensionExtendedKeyUsage, .ExtraExtensions) { [], = marshalExtKeyUsage(.ExtKeyUsage, .UnknownExtKeyUsage) if != nil { return nil, } ++ } if .BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, .ExtraExtensions) { [], = marshalBasicConstraints(.IsCA, .MaxPathLen, .MaxPathLenZero) if != nil { return nil, } ++ } if len() > 0 && !oidInExtensions(oidExtensionSubjectKeyId, .ExtraExtensions) { [].Id = oidExtensionSubjectKeyId [].Value, = asn1.Marshal() if != nil { return } ++ } if len() > 0 && !oidInExtensions(oidExtensionAuthorityKeyId, .ExtraExtensions) { [].Id = oidExtensionAuthorityKeyId [].Value, = asn1.Marshal(authKeyId{}) if != nil { return } ++ } if (len(.OCSPServer) > 0 || len(.IssuingCertificateURL) > 0) && !oidInExtensions(oidExtensionAuthorityInfoAccess, .ExtraExtensions) { [].Id = oidExtensionAuthorityInfoAccess var []authorityInfoAccess for , := range .OCSPServer { = append(, authorityInfoAccess{ Method: oidAuthorityInfoAccessOcsp, Location: asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte()}, }) } for , := range .IssuingCertificateURL { = append(, authorityInfoAccess{ Method: oidAuthorityInfoAccessIssuers, Location: asn1.RawValue{Tag: 6, Class: 2, Bytes: []byte()}, }) } [].Value, = asn1.Marshal() if != nil { return } ++ } if (len(.DNSNames) > 0 || len(.EmailAddresses) > 0 || len(.IPAddresses) > 0 || len(.URIs) > 0) && !oidInExtensions(oidExtensionSubjectAltName, .ExtraExtensions) { [].Id = oidExtensionSubjectAltName // From RFC 5280, Section 4.2.1.6: // “If the subject field contains an empty sequence ... then // subjectAltName extension ... is marked as critical” [].Critical = [].Value, = marshalSANs(.DNSNames, .EmailAddresses, .IPAddresses, .URIs) if != nil { return } ++ } := x509usepolicies.Value() == "1" if ((! && len(.PolicyIdentifiers) > 0) || ( && len(.Policies) > 0)) && !oidInExtensions(oidExtensionCertificatePolicies, .ExtraExtensions) { [], = marshalCertificatePolicies(.Policies, .PolicyIdentifiers) if != nil { return nil, } ++ } if (len(.PermittedDNSDomains) > 0 || len(.ExcludedDNSDomains) > 0 || len(.PermittedIPRanges) > 0 || len(.ExcludedIPRanges) > 0 || len(.PermittedEmailAddresses) > 0 || len(.ExcludedEmailAddresses) > 0 || len(.PermittedURIDomains) > 0 || len(.ExcludedURIDomains) > 0) && !oidInExtensions(oidExtensionNameConstraints, .ExtraExtensions) { [].Id = oidExtensionNameConstraints [].Critical = .PermittedDNSDomainsCritical := func( *net.IPNet) []byte { := .IP.Mask(.Mask) := make([]byte, 0, len()+len(.Mask)) = append(, ...) = append(, .Mask...) return } := func( []string, []*net.IPNet, []string, []string) ( []byte, error) { var cryptobyte.Builder for , := range { if = isIA5String(); != nil { return nil, } .AddASN1(cryptobyte_asn1.SEQUENCE, func( *cryptobyte.Builder) { .AddASN1(cryptobyte_asn1.Tag(2).ContextSpecific(), func( *cryptobyte.Builder) { .AddBytes([]byte()) }) }) } for , := range { .AddASN1(cryptobyte_asn1.SEQUENCE, func( *cryptobyte.Builder) { .AddASN1(cryptobyte_asn1.Tag(7).ContextSpecific(), func( *cryptobyte.Builder) { .AddBytes(()) }) }) } for , := range { if = isIA5String(); != nil { return nil, } .AddASN1(cryptobyte_asn1.SEQUENCE, func( *cryptobyte.Builder) { .AddASN1(cryptobyte_asn1.Tag(1).ContextSpecific(), func( *cryptobyte.Builder) { .AddBytes([]byte()) }) }) } for , := range { if = isIA5String(); != nil { return nil, } .AddASN1(cryptobyte_asn1.SEQUENCE, func( *cryptobyte.Builder) { .AddASN1(cryptobyte_asn1.Tag(6).ContextSpecific(), func( *cryptobyte.Builder) { .AddBytes([]byte()) }) }) } return .Bytes() } , := (.PermittedDNSDomains, .PermittedIPRanges, .PermittedEmailAddresses, .PermittedURIDomains) if != nil { return nil, } , := (.ExcludedDNSDomains, .ExcludedIPRanges, .ExcludedEmailAddresses, .ExcludedURIDomains) if != nil { return nil, } var cryptobyte.Builder .AddASN1(cryptobyte_asn1.SEQUENCE, func( *cryptobyte.Builder) { if len() > 0 { .AddASN1(cryptobyte_asn1.Tag(0).ContextSpecific().Constructed(), func( *cryptobyte.Builder) { .AddBytes() }) } if len() > 0 { .AddASN1(cryptobyte_asn1.Tag(1).ContextSpecific().Constructed(), func( *cryptobyte.Builder) { .AddBytes() }) } }) [].Value, = .Bytes() if != nil { return nil, } ++ } if len(.CRLDistributionPoints) > 0 && !oidInExtensions(oidExtensionCRLDistributionPoints, .ExtraExtensions) { [].Id = oidExtensionCRLDistributionPoints var []distributionPoint for , := range .CRLDistributionPoints { := distributionPoint{ DistributionPoint: distributionPointName{ FullName: []asn1.RawValue{ {Tag: 6, Class: 2, Bytes: []byte()}, }, }, } = append(, ) } [].Value, = asn1.Marshal() if != nil { return } ++ } // Adding another extension here? Remember to update the maximum number // of elements in the make() at the top of the function and the list of // template fields used in CreateCertificate documentation. return append([:], .ExtraExtensions...), nil } func marshalKeyUsage( KeyUsage) (pkix.Extension, error) { := pkix.Extension{Id: oidExtensionKeyUsage, Critical: true} var [2]byte [0] = reverseBitsInAByte(byte()) [1] = reverseBitsInAByte(byte( >> 8)) := 1 if [1] != 0 { = 2 } := [:] var error .Value, = asn1.Marshal(asn1.BitString{Bytes: , BitLength: asn1BitLength()}) return , } func marshalExtKeyUsage( []ExtKeyUsage, []asn1.ObjectIdentifier) (pkix.Extension, error) { := pkix.Extension{Id: oidExtensionExtendedKeyUsage} := make([]asn1.ObjectIdentifier, len()+len()) for , := range { if , := oidFromExtKeyUsage(); { [] = } else { return , errors.New("x509: unknown extended key usage") } } copy([len():], ) var error .Value, = asn1.Marshal() return , } func marshalBasicConstraints( bool, int, bool) (pkix.Extension, error) { := pkix.Extension{Id: oidExtensionBasicConstraints, Critical: true} // Leaving MaxPathLen as zero indicates that no maximum path // length is desired, unless MaxPathLenZero is set. A value of // -1 causes encoding/asn1 to omit the value as desired. if == 0 && ! { = -1 } var error .Value, = asn1.Marshal(basicConstraints{, }) return , } func marshalCertificatePolicies( []OID, []asn1.ObjectIdentifier) (pkix.Extension, error) { := pkix.Extension{Id: oidExtensionCertificatePolicies} := cryptobyte.NewBuilder(make([]byte, 0, 128)) .AddASN1(cryptobyte_asn1.SEQUENCE, func( *cryptobyte.Builder) { if x509usepolicies.Value() == "1" { x509usepolicies.IncNonDefault() for , := range { .AddASN1(cryptobyte_asn1.SEQUENCE, func( *cryptobyte.Builder) { .AddASN1(cryptobyte_asn1.OBJECT_IDENTIFIER, func( *cryptobyte.Builder) { if len(.der) == 0 { .SetError(errors.New("invalid policy object identifier")) return } .AddBytes(.der) }) }) } } else { for , := range { .AddASN1(cryptobyte_asn1.SEQUENCE, func( *cryptobyte.Builder) { .AddASN1ObjectIdentifier() }) } } }) var error .Value, = .Bytes() return , } func buildCSRExtensions( *CertificateRequest) ([]pkix.Extension, error) { var []pkix.Extension if (len(.DNSNames) > 0 || len(.EmailAddresses) > 0 || len(.IPAddresses) > 0 || len(.URIs) > 0) && !oidInExtensions(oidExtensionSubjectAltName, .ExtraExtensions) { , := marshalSANs(.DNSNames, .EmailAddresses, .IPAddresses, .URIs) if != nil { return nil, } = append(, pkix.Extension{ Id: oidExtensionSubjectAltName, Value: , }) } return append(, .ExtraExtensions...), nil } func subjectBytes( *Certificate) ([]byte, error) { if len(.RawSubject) > 0 { return .RawSubject, nil } return asn1.Marshal(.Subject.ToRDNSequence()) } // signingParamsForKey returns the signature algorithm and its Algorithm // Identifier to use for signing, based on the key type. If sigAlgo is not zero // then it overrides the default. func signingParamsForKey( crypto.Signer, SignatureAlgorithm) (SignatureAlgorithm, pkix.AlgorithmIdentifier, error) { var pkix.AlgorithmIdentifier var PublicKeyAlgorithm var SignatureAlgorithm switch pub := .Public().(type) { case *rsa.PublicKey: = RSA = SHA256WithRSA case *ecdsa.PublicKey: = ECDSA switch .Curve { case elliptic.P224(), elliptic.P256(): = ECDSAWithSHA256 case elliptic.P384(): = ECDSAWithSHA384 case elliptic.P521(): = ECDSAWithSHA512 default: return 0, , errors.New("x509: unsupported elliptic curve") } case ed25519.PublicKey: = Ed25519 = PureEd25519 default: return 0, , errors.New("x509: only RSA, ECDSA and Ed25519 keys supported") } if == 0 { = } for , := range signatureAlgorithmDetails { if .algo == { if .pubKeyAlgo != { return 0, , errors.New("x509: requested SignatureAlgorithm does not match private key type") } if .hash == crypto.MD5 { return 0, , errors.New("x509: signing with MD5 is not supported") } return , pkix.AlgorithmIdentifier{ Algorithm: .oid, Parameters: .params, }, nil } } return 0, , errors.New("x509: unknown SignatureAlgorithm") } func signTBS( []byte, crypto.Signer, SignatureAlgorithm, io.Reader) ([]byte, error) { := := .hashFunc() if != 0 { := .New() .Write() = .Sum(nil) } var crypto.SignerOpts = if .isRSAPSS() { = &rsa.PSSOptions{ SaltLength: rsa.PSSSaltLengthEqualsHash, Hash: , } } , := .Sign(, , ) if != nil { return nil, } // Check the signature to ensure the crypto.Signer behaved correctly. if := checkSignature(, , , .Public(), true); != nil { return nil, fmt.Errorf("x509: signature returned by signer is invalid: %w", ) } return , nil } // emptyASN1Subject is the ASN.1 DER encoding of an empty Subject, which is // just an empty SEQUENCE. var emptyASN1Subject = []byte{0x30, 0} // CreateCertificate creates a new X.509 v3 certificate based on a template. // The following members of template are currently used: // // - AuthorityKeyId // - BasicConstraintsValid // - CRLDistributionPoints // - DNSNames // - EmailAddresses // - ExcludedDNSDomains // - ExcludedEmailAddresses // - ExcludedIPRanges // - ExcludedURIDomains // - ExtKeyUsage // - ExtraExtensions // - IPAddresses // - IsCA // - IssuingCertificateURL // - KeyUsage // - MaxPathLen // - MaxPathLenZero // - NotAfter // - NotBefore // - OCSPServer // - PermittedDNSDomains // - PermittedDNSDomainsCritical // - PermittedEmailAddresses // - PermittedIPRanges // - PermittedURIDomains // - PolicyIdentifiers (see note below) // - Policies (see note below) // - SerialNumber // - SignatureAlgorithm // - Subject // - SubjectKeyId // - URIs // - 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 // certificate to be generated and priv is the private key of the signer. // // The returned slice is the certificate in DER encoding. // // The currently supported key types are *rsa.PublicKey, *ecdsa.PublicKey and // ed25519.PublicKey. pub must be a supported key type, and priv must be a // crypto.Signer with a supported public key. // // 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. // // If SubjectKeyId from template is empty and the template is a CA, SubjectKeyId // will be generated from the hash of the public key. // // The PolicyIdentifier and Policies fields are both used to marshal certificate // policy OIDs. By default, only the PolicyIdentifier is marshaled, but if the // GODEBUG setting "x509usepolicies" has the value "1", the Policies field will // be marshaled instead of the PolicyIdentifier field. The Policies field can // be used to marshal policy OIDs which have components that are larger than 31 // bits. func ( io.Reader, , *Certificate, , any) ([]byte, error) { , := .(crypto.Signer) if ! { return nil, errors.New("x509: certificate private key does not implement crypto.Signer") } if .SerialNumber == nil { return nil, errors.New("x509: no SerialNumber given") } // RFC 5280 Section 4.1.2.2: serial number must positive // // We _should_ also restrict serials to <= 20 octets, but it turns out a lot of people // get this wrong, in part because the encoding can itself alter the length of the // serial. For now we accept these non-conformant serials. if .SerialNumber.Sign() == -1 { return nil, errors.New("x509: serial number must be positive") } if .BasicConstraintsValid && !.IsCA && .MaxPathLen != -1 && (.MaxPathLen != 0 || .MaxPathLenZero) { return nil, errors.New("x509: only CAs are allowed to specify MaxPathLen") } , , := signingParamsForKey(, .SignatureAlgorithm) if != nil { return nil, } , , := marshalPublicKey() if != nil { return nil, } if getPublicKeyAlgorithmFromOID(.Algorithm) == UnknownPublicKeyAlgorithm { return nil, fmt.Errorf("x509: unsupported public key type: %T", ) } , := subjectBytes() if != nil { return nil, } , := subjectBytes() if != nil { return nil, } := .AuthorityKeyId if !bytes.Equal(, ) && len(.SubjectKeyId) > 0 { = .SubjectKeyId } := .SubjectKeyId if len() == 0 && .IsCA { // SubjectKeyId generated using method 1 in RFC 5280, Section 4.2.1.2: // (1) The keyIdentifier is composed of the 160-bit SHA-1 hash of the // value of the BIT STRING subjectPublicKey (excluding the tag, // length, and number of unused bits). := sha1.Sum() = [:] } // Check that the signer's public key matches the private key, if available. type interface { (crypto.PublicKey) bool } if , := .Public().(); ! { return nil, errors.New("x509: internal error: supported public key does not implement Equal") } else if .PublicKey != nil && !.(.PublicKey) { return nil, errors.New("x509: provided PrivateKey doesn't match parent's PublicKey") } , := buildCertExtensions(, bytes.Equal(, emptyASN1Subject), , ) if != nil { return nil, } := asn1.BitString{BitLength: len() * 8, Bytes: } := tbsCertificate{ Version: 2, SerialNumber: .SerialNumber, SignatureAlgorithm: , Issuer: asn1.RawValue{FullBytes: }, Validity: validity{.NotBefore.UTC(), .NotAfter.UTC()}, Subject: asn1.RawValue{FullBytes: }, PublicKey: publicKeyInfo{nil, , }, Extensions: , } , := asn1.Marshal() if != nil { return nil, } .Raw = , := signTBS(, , , ) if != nil { return nil, } return asn1.Marshal(certificate{ TBSCertificate: , SignatureAlgorithm: , SignatureValue: asn1.BitString{Bytes: , BitLength: len() * 8}, }) } // pemCRLPrefix is the magic string that indicates that we have a PEM encoded // CRL. var pemCRLPrefix = []byte("-----BEGIN X509 CRL") // pemType is the type of a PEM encoded CRL. var pemType = "X509 CRL" // ParseCRL parses a CRL from the given bytes. It's often the case that PEM // encoded CRLs will appear where they should be DER encoded, so this function // will transparently handle PEM encoding as long as there isn't any leading // garbage. // // Deprecated: Use [ParseRevocationList] instead. func ( []byte) (*pkix.CertificateList, error) { if bytes.HasPrefix(, pemCRLPrefix) { , := pem.Decode() if != nil && .Type == pemType { = .Bytes } } return ParseDERCRL() } // ParseDERCRL parses a DER encoded CRL from the given bytes. // // Deprecated: Use [ParseRevocationList] instead. func ( []byte) (*pkix.CertificateList, error) { := new(pkix.CertificateList) if , := asn1.Unmarshal(, ); != nil { return nil, } else if len() != 0 { return nil, errors.New("x509: trailing data after CRL") } return , nil } // CreateCRL returns a DER encoded CRL, signed by this Certificate, that // contains the given list of revoked certificates. // // Deprecated: this method does not generate an RFC 5280 conformant X.509 v2 CRL. // To generate a standards compliant CRL, use [CreateRevocationList] instead. func ( *Certificate) ( io.Reader, any, []pkix.RevokedCertificate, , time.Time) ( []byte, error) { , := .(crypto.Signer) if ! { return nil, errors.New("x509: certificate private key does not implement crypto.Signer") } , , := signingParamsForKey(, 0) if != nil { return nil, } // Force revocation times to UTC per RFC 5280. := make([]pkix.RevokedCertificate, len()) for , := range { .RevocationTime = .RevocationTime.UTC() [] = } := pkix.TBSCertificateList{ Version: 1, Signature: , Issuer: .Subject.ToRDNSequence(), ThisUpdate: .UTC(), NextUpdate: .UTC(), RevokedCertificates: , } // Authority Key Id if len(.SubjectKeyId) > 0 { var pkix.Extension .Id = oidExtensionAuthorityKeyId .Value, = asn1.Marshal(authKeyId{Id: .SubjectKeyId}) if != nil { return nil, } .Extensions = append(.Extensions, ) } , := asn1.Marshal() if != nil { return nil, } .Raw = , := signTBS(, , , ) if != nil { return nil, } return asn1.Marshal(pkix.CertificateList{ TBSCertList: , SignatureAlgorithm: , SignatureValue: asn1.BitString{Bytes: , BitLength: len() * 8}, }) } // CertificateRequest represents a PKCS #10, certificate signature request. type CertificateRequest struct { Raw []byte // Complete ASN.1 DER content (CSR, signature algorithm and signature). RawTBSCertificateRequest []byte // Certificate request info part of raw ASN.1 DER content. RawSubjectPublicKeyInfo []byte // DER encoded SubjectPublicKeyInfo. RawSubject []byte // DER encoded Subject. Version int Signature []byte SignatureAlgorithm SignatureAlgorithm PublicKeyAlgorithm PublicKeyAlgorithm PublicKey any Subject pkix.Name // Attributes contains the CSR attributes that can parse as // pkix.AttributeTypeAndValueSET. // // Deprecated: Use Extensions and ExtraExtensions instead for parsing and // generating the requestedExtensions attribute. Attributes []pkix.AttributeTypeAndValueSET // Extensions contains all requested extensions, in raw form. When parsing // CSRs, this can be used to extract extensions that are not parsed by this // package. Extensions []pkix.Extension // ExtraExtensions contains extensions to be copied, raw, into any CSR // marshaled by CreateCertificateRequest. Values override any extensions // that would otherwise be produced based on the other fields but are // overridden by any extensions specified in Attributes. // // The ExtraExtensions field is not populated by ParseCertificateRequest, // see Extensions instead. ExtraExtensions []pkix.Extension // Subject Alternate Name values. DNSNames []string EmailAddresses []string IPAddresses []net.IP URIs []*url.URL } // These structures reflect the ASN.1 structure of X.509 certificate // signature requests (see RFC 2986): type tbsCertificateRequest struct { Raw asn1.RawContent Version int Subject asn1.RawValue PublicKey publicKeyInfo RawAttributes []asn1.RawValue `asn1:"tag:0"` } type certificateRequest struct { Raw asn1.RawContent TBSCSR tbsCertificateRequest SignatureAlgorithm pkix.AlgorithmIdentifier SignatureValue asn1.BitString } // oidExtensionRequest is a PKCS #9 OBJECT IDENTIFIER that indicates requested // extensions in a CSR. var oidExtensionRequest = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 9, 14} // newRawAttributes converts AttributeTypeAndValueSETs from a template // CertificateRequest's Attributes into tbsCertificateRequest RawAttributes. func newRawAttributes( []pkix.AttributeTypeAndValueSET) ([]asn1.RawValue, error) { var []asn1.RawValue , := asn1.Marshal() if != nil { return nil, } , := asn1.Unmarshal(, &) if != nil { return nil, } if len() != 0 { return nil, errors.New("x509: failed to unmarshal raw CSR Attributes") } return , nil } // parseRawAttributes Unmarshals RawAttributes into AttributeTypeAndValueSETs. func parseRawAttributes( []asn1.RawValue) []pkix.AttributeTypeAndValueSET { var []pkix.AttributeTypeAndValueSET for , := range { var pkix.AttributeTypeAndValueSET , := asn1.Unmarshal(.FullBytes, &) // Ignore attributes that don't parse into pkix.AttributeTypeAndValueSET // (i.e.: challengePassword or unstructuredName). if == nil && len() == 0 { = append(, ) } } return } // parseCSRExtensions parses the attributes from a CSR and extracts any // requested extensions. func parseCSRExtensions( []asn1.RawValue) ([]pkix.Extension, error) { // pkcs10Attribute reflects the Attribute structure from RFC 2986, Section 4.1. type struct { asn1.ObjectIdentifier []asn1.RawValue `asn1:"set"` } var []pkix.Extension := make(map[string]bool) for , := range { var if , := asn1.Unmarshal(.FullBytes, &); != nil || len() != 0 || len(.) == 0 { // Ignore attributes that don't parse. continue } if !..Equal(oidExtensionRequest) { continue } var []pkix.Extension if , := asn1.Unmarshal(.[0].FullBytes, &); != nil { return nil, } for , := range { := .Id.String() if [] { return nil, errors.New("x509: certificate request contains duplicate requested extensions") } [] = true } = append(, ...) } return , nil } // CreateCertificateRequest creates a new certificate request based on a // template. The following members of template are used: // // - SignatureAlgorithm // - Subject // - DNSNames // - EmailAddresses // - IPAddresses // - URIs // - ExtraExtensions // - Attributes (deprecated) // // priv is the private key to sign the CSR with, and the corresponding public // key will be included in the CSR. It must implement crypto.Signer and its // Public() method must return a *rsa.PublicKey or a *ecdsa.PublicKey or a // ed25519.PublicKey. (A *rsa.PrivateKey, *ecdsa.PrivateKey or // ed25519.PrivateKey satisfies this.) // // The returned slice is the certificate request in DER encoding. func ( io.Reader, *CertificateRequest, any) ( []byte, error) { , := .(crypto.Signer) if ! { return nil, errors.New("x509: certificate private key does not implement crypto.Signer") } , , := signingParamsForKey(, .SignatureAlgorithm) if != nil { return nil, } var []byte var pkix.AlgorithmIdentifier , , = marshalPublicKey(.Public()) if != nil { return nil, } , := buildCSRExtensions() if != nil { return nil, } // Make a copy of template.Attributes because we may alter it below. := make([]pkix.AttributeTypeAndValueSET, 0, len(.Attributes)) for , := range .Attributes { := make([][]pkix.AttributeTypeAndValue, len(.Value)) copy(, .Value) = append(, pkix.AttributeTypeAndValueSET{ Type: .Type, Value: , }) } := false if len() > 0 { // Append the extensions to an existing attribute if possible. for , := range { if !.Type.Equal(oidExtensionRequest) || len(.Value) == 0 { continue } // specifiedExtensions contains all the extensions that we // found specified via template.Attributes. := make(map[string]bool) for , := range .Value { for , := range { [.Type.String()] = true } } := make([]pkix.AttributeTypeAndValue, 0, len(.Value[0])+len()) = append(, .Value[0]...) for , := range { if [.Id.String()] { // Attributes already contained a value for // this extension and it takes priority. continue } = append(, pkix.AttributeTypeAndValue{ // There is no place for the critical // flag in an AttributeTypeAndValue. Type: .Id, Value: .Value, }) } .Value[0] = = true break } } , := newRawAttributes() if != nil { return nil, } // If not included in attributes, add a new attribute for the // extensions. if len() > 0 && ! { := struct { asn1.ObjectIdentifier [][]pkix.Extension `asn1:"set"` }{ : oidExtensionRequest, : [][]pkix.Extension{}, } , := asn1.Marshal() if != nil { return nil, errors.New("x509: failed to serialise extensions attribute: " + .Error()) } var asn1.RawValue if , := asn1.Unmarshal(, &); != nil { return nil, } = append(, ) } := .RawSubject if len() == 0 { , = asn1.Marshal(.Subject.ToRDNSequence()) if != nil { return nil, } } := tbsCertificateRequest{ Version: 0, // PKCS #10, RFC 2986 Subject: asn1.RawValue{FullBytes: }, PublicKey: publicKeyInfo{ Algorithm: , PublicKey: asn1.BitString{ Bytes: , BitLength: len() * 8, }, }, RawAttributes: , } , := asn1.Marshal() if != nil { return nil, } .Raw = , := signTBS(, , , ) if != nil { return nil, } return asn1.Marshal(certificateRequest{ TBSCSR: , SignatureAlgorithm: , SignatureValue: asn1.BitString{Bytes: , BitLength: len() * 8}, }) } // ParseCertificateRequest parses a single certificate request from the // given ASN.1 DER data. func ( []byte) (*CertificateRequest, error) { var certificateRequest , := asn1.Unmarshal(, &) if != nil { return nil, } else if len() != 0 { return nil, asn1.SyntaxError{Msg: "trailing data"} } return parseCertificateRequest(&) } func parseCertificateRequest( *certificateRequest) (*CertificateRequest, error) { := &CertificateRequest{ Raw: .Raw, RawTBSCertificateRequest: .TBSCSR.Raw, RawSubjectPublicKeyInfo: .TBSCSR.PublicKey.Raw, RawSubject: .TBSCSR.Subject.FullBytes, Signature: .SignatureValue.RightAlign(), SignatureAlgorithm: getSignatureAlgorithmFromAI(.SignatureAlgorithm), PublicKeyAlgorithm: getPublicKeyAlgorithmFromOID(.TBSCSR.PublicKey.Algorithm.Algorithm), Version: .TBSCSR.Version, Attributes: parseRawAttributes(.TBSCSR.RawAttributes), } var error if .PublicKeyAlgorithm != UnknownPublicKeyAlgorithm { .PublicKey, = parsePublicKey(&.TBSCSR.PublicKey) if != nil { return nil, } } var pkix.RDNSequence if , := asn1.Unmarshal(.TBSCSR.Subject.FullBytes, &); != nil { return nil, } else if len() != 0 { return nil, errors.New("x509: trailing data after X.509 Subject") } .Subject.FillFromRDNSequence(&) if .Extensions, = parseCSRExtensions(.TBSCSR.RawAttributes); != nil { return nil, } for , := range .Extensions { switch { case .Id.Equal(oidExtensionSubjectAltName): .DNSNames, .EmailAddresses, .IPAddresses, .URIs, = parseSANExtension(.Value) if != nil { return nil, } } } return , nil } // CheckSignature reports whether the signature on c is valid. func ( *CertificateRequest) () error { return checkSignature(.SignatureAlgorithm, .RawTBSCertificateRequest, .Signature, .PublicKey, true) } // RevocationListEntry represents an entry in the revokedCertificates // sequence of a CRL. type RevocationListEntry struct { // Raw contains the raw bytes of the revokedCertificates entry. It is set when // parsing a CRL; it is ignored when generating a CRL. Raw []byte // SerialNumber represents the serial number of a revoked certificate. It is // both used when creating a CRL and populated when parsing a CRL. It must not // be nil. SerialNumber *big.Int // RevocationTime represents the time at which the certificate was revoked. It // is both used when creating a CRL and populated when parsing a CRL. It must // not be the zero time. RevocationTime time.Time // ReasonCode represents the reason for revocation, using the integer enum // values specified in RFC 5280 Section 5.3.1. When creating a CRL, the zero // value will result in the reasonCode extension being omitted. When parsing a // CRL, the zero value may represent either the reasonCode extension being // absent (which implies the default revocation reason of 0/Unspecified), or // it may represent the reasonCode extension being present and explicitly // containing a value of 0/Unspecified (which should not happen according to // the DER encoding rules, but can and does happen anyway). ReasonCode int // Extensions contains raw X.509 extensions. When parsing CRL entries, // this can be used to extract non-critical extensions that are not // parsed by this package. When marshaling CRL entries, the Extensions // field is ignored, see ExtraExtensions. Extensions []pkix.Extension // ExtraExtensions contains extensions to be copied, raw, into any // marshaled CRL entries. Values override any extensions that would // otherwise be produced based on the other fields. The ExtraExtensions // field is not populated when parsing CRL entries, see Extensions. ExtraExtensions []pkix.Extension } // RevocationList represents a [Certificate] Revocation List (CRL) as specified // by RFC 5280. type RevocationList struct { // Raw contains the complete ASN.1 DER content of the CRL (tbsCertList, // signatureAlgorithm, and signatureValue.) Raw []byte // RawTBSRevocationList contains just the tbsCertList portion of the ASN.1 // DER. RawTBSRevocationList []byte // RawIssuer contains the DER encoded Issuer. RawIssuer []byte // Issuer contains the DN of the issuing certificate. Issuer pkix.Name // AuthorityKeyId is used to identify the public key associated with the // issuing certificate. It is populated from the authorityKeyIdentifier // extension when parsing a CRL. It is ignored when creating a CRL; the // extension is populated from the issuing certificate itself. AuthorityKeyId []byte Signature []byte // SignatureAlgorithm is used to determine the signature algorithm to be // used when signing the CRL. If 0 the default algorithm for the signing // key will be used. SignatureAlgorithm SignatureAlgorithm // RevokedCertificateEntries represents the revokedCertificates sequence in // the CRL. It is used when creating a CRL and also populated when parsing a // CRL. When creating a CRL, it may be empty or nil, in which case the // revokedCertificates ASN.1 sequence will be omitted from the CRL entirely. RevokedCertificateEntries []RevocationListEntry // RevokedCertificates is used to populate the revokedCertificates // sequence in the CRL if RevokedCertificateEntries is empty. It may be empty // or nil, in which case an empty CRL will be created. // // Deprecated: Use RevokedCertificateEntries instead. RevokedCertificates []pkix.RevokedCertificate // Number is used to populate the X.509 v2 cRLNumber extension in the CRL, // which should be a monotonically increasing sequence number for a given // CRL scope and CRL issuer. It is also populated from the cRLNumber // extension when parsing a CRL. Number *big.Int // ThisUpdate is used to populate the thisUpdate field in the CRL, which // indicates the issuance date of the CRL. ThisUpdate time.Time // NextUpdate is used to populate the nextUpdate field in the CRL, which // indicates the date by which the next CRL will be issued. NextUpdate // must be greater than ThisUpdate. NextUpdate time.Time // Extensions contains raw X.509 extensions. When creating a CRL, // the Extensions field is ignored, see ExtraExtensions. Extensions []pkix.Extension // ExtraExtensions contains any additional extensions to add directly to // the CRL. ExtraExtensions []pkix.Extension } // These structures reflect the ASN.1 structure of X.509 CRLs better than // the existing crypto/x509/pkix variants do. These mirror the existing // certificate structs in this file. // // Notably, we include issuer as an asn1.RawValue, mirroring the behavior of // tbsCertificate and allowing raw (unparsed) subjects to be passed cleanly. type certificateList struct { TBSCertList tbsCertificateList SignatureAlgorithm pkix.AlgorithmIdentifier SignatureValue asn1.BitString } type tbsCertificateList struct { Raw asn1.RawContent Version int `asn1:"optional,default:0"` Signature pkix.AlgorithmIdentifier Issuer asn1.RawValue ThisUpdate time.Time NextUpdate time.Time `asn1:"optional"` RevokedCertificates []pkix.RevokedCertificate `asn1:"optional"` Extensions []pkix.Extension `asn1:"tag:0,optional,explicit"` } // CreateRevocationList creates a new X.509 v2 [Certificate] Revocation List, // according to RFC 5280, based on template. // // The CRL is signed by priv which should be the private key associated with // the public key in the issuer certificate. // // The issuer may not be nil, and the crlSign bit must be set in [KeyUsage] in // order to use it as a CRL issuer. // // The issuer distinguished name CRL field and authority key identifier // extension are populated using the issuer certificate. issuer must have // SubjectKeyId set. func ( io.Reader, *RevocationList, *Certificate, crypto.Signer) ([]byte, error) { if == nil { return nil, errors.New("x509: template can not be nil") } if == nil { return nil, errors.New("x509: issuer can not be nil") } if (.KeyUsage & KeyUsageCRLSign) == 0 { return nil, errors.New("x509: issuer must have the crlSign key usage bit set") } if len(.SubjectKeyId) == 0 { return nil, errors.New("x509: issuer certificate doesn't contain a subject key identifier") } if .NextUpdate.Before(.ThisUpdate) { return nil, errors.New("x509: template.ThisUpdate is after template.NextUpdate") } if .Number == nil { return nil, errors.New("x509: template contains nil Number field") } , , := signingParamsForKey(, .SignatureAlgorithm) if != nil { return nil, } var []pkix.RevokedCertificate // Only process the deprecated RevokedCertificates field if it is populated // and the new RevokedCertificateEntries field is not populated. if len(.RevokedCertificates) > 0 && len(.RevokedCertificateEntries) == 0 { // Force revocation times to UTC per RFC 5280. = make([]pkix.RevokedCertificate, len(.RevokedCertificates)) for , := range .RevokedCertificates { .RevocationTime = .RevocationTime.UTC() [] = } } else { // Convert the ReasonCode field to a proper extension, and force revocation // times to UTC per RFC 5280. = make([]pkix.RevokedCertificate, len(.RevokedCertificateEntries)) for , := range .RevokedCertificateEntries { if .SerialNumber == nil { return nil, errors.New("x509: template contains entry with nil SerialNumber field") } if .RevocationTime.IsZero() { return nil, errors.New("x509: template contains entry with zero RevocationTime field") } := pkix.RevokedCertificate{ SerialNumber: .SerialNumber, RevocationTime: .RevocationTime.UTC(), } // Copy over any extra extensions, except for a Reason Code extension, // because we'll synthesize that ourselves to ensure it is correct. := make([]pkix.Extension, 0, len(.ExtraExtensions)) for , := range .ExtraExtensions { if .Id.Equal(oidExtensionReasonCode) { return nil, errors.New("x509: template contains entry with ReasonCode ExtraExtension; use ReasonCode field instead") } = append(, ) } // Only add a reasonCode extension if the reason is non-zero, as per // RFC 5280 Section 5.3.1. if .ReasonCode != 0 { , := asn1.Marshal(asn1.Enumerated(.ReasonCode)) if != nil { return nil, } = append(, pkix.Extension{ Id: oidExtensionReasonCode, Value: , }) } if len() > 0 { .Extensions = } [] = } } , := asn1.Marshal(authKeyId{Id: .SubjectKeyId}) if != nil { return nil, } if := .Number.Bytes(); len() > 20 || (len() == 20 && [0]&0x80 != 0) { return nil, errors.New("x509: CRL number exceeds 20 octets") } , := asn1.Marshal(.Number) if != nil { return nil, } // Correctly use the issuer's subject sequence if one is specified. , := subjectBytes() if != nil { return nil, } := tbsCertificateList{ Version: 1, // v2 Signature: , Issuer: asn1.RawValue{FullBytes: }, ThisUpdate: .ThisUpdate.UTC(), NextUpdate: .NextUpdate.UTC(), Extensions: []pkix.Extension{ { Id: oidExtensionAuthorityKeyId, Value: , }, { Id: oidExtensionCRLNumber, Value: , }, }, } if len() > 0 { .RevokedCertificates = } if len(.ExtraExtensions) > 0 { .Extensions = append(.Extensions, .ExtraExtensions...) } , := asn1.Marshal() if != nil { return nil, } // Optimization to only marshal this struct once, when signing and // then embedding in certificateList below. .Raw = , := signTBS(, , , ) if != nil { return nil, } return asn1.Marshal(certificateList{ TBSCertList: , SignatureAlgorithm: , SignatureValue: asn1.BitString{Bytes: , BitLength: len() * 8}, }) } // CheckSignatureFrom verifies that the signature on rl is a valid signature // from issuer. func ( *RevocationList) ( *Certificate) error { if .Version == 3 && !.BasicConstraintsValid || .BasicConstraintsValid && !.IsCA { return ConstraintViolationError{} } if .KeyUsage != 0 && .KeyUsage&KeyUsageCRLSign == 0 { return ConstraintViolationError{} } if .PublicKeyAlgorithm == UnknownPublicKeyAlgorithm { return ErrUnsupportedAlgorithm } return .CheckSignature(.SignatureAlgorithm, .RawTBSRevocationList, .Signature) }