// Use of this source code is governed by a BSD-style
// license that can be found in the LICENSE file.
-// Package x509 parses X.509-encoded keys and certificates.
+// 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 (
"bytes"
"crypto"
- "crypto/dsa"
+ "crypto/ecdh"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"encoding/pem"
"errors"
"fmt"
+ "internal/godebug"
"io"
"math/big"
"net"
"net/url"
"strconv"
- "strings"
"time"
"unicode"
_ "crypto/sha256"
_ "crypto/sha512"
+ "crypto/go.cypherpunks.ru/gogost/v5/gost3410"
"golang.org/x/crypto/cryptobyte"
cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
)
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).
+// 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, or
-// ed25519.PublicKey. More types might be supported in the future.
+// 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 ParsePKIXPublicKey(derBytes []byte) (pub interface{}, err error) {
+func ParsePKIXPublicKey(derBytes []byte) (pub any, err error) {
var pki publicKeyInfo
if rest, err := asn1.Unmarshal(derBytes, &pki); err != nil {
if _, err := asn1.Unmarshal(derBytes, &pkcs1PublicKey{}); err == nil {
} else if len(rest) != 0 {
return nil, errors.New("x509: trailing data after ASN.1 of public-key")
}
- algo := getPublicKeyAlgorithmFromOID(pki.Algorithm.Algorithm)
- if algo == UnknownPublicKeyAlgorithm {
- return nil, errors.New("x509: unknown public key algorithm")
- }
- return parsePublicKey(algo, &pki)
+ return parsePublicKey(&pki)
}
-func marshalPublicKey(pub interface{}) (publicKeyBytes []byte, publicKeyAlgorithm pkix.AlgorithmIdentifier, err error) {
+func marshalPublicKey(pub any) (publicKeyBytes []byte, publicKeyAlgorithm pkix.AlgorithmIdentifier, err error) {
switch pub := pub.(type) {
case *rsa.PublicKey:
publicKeyBytes, err = asn1.Marshal(pkcs1PublicKey{
// RFC 3279, Section 2.3.1.
publicKeyAlgorithm.Parameters = asn1.NullRawValue
case *ecdsa.PublicKey:
- publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y)
oid, ok := oidFromNamedCurve(pub.Curve)
if !ok {
return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve")
}
+ if !pub.Curve.IsOnCurve(pub.X, pub.Y) {
+ return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: invalid elliptic curve public key")
+ }
+ publicKeyBytes = elliptic.Marshal(pub.Curve, pub.X, pub.Y)
publicKeyAlgorithm.Algorithm = oidPublicKeyECDSA
var paramBytes []byte
paramBytes, err = asn1.Marshal(oid)
case ed25519.PublicKey:
publicKeyBytes = pub
publicKeyAlgorithm.Algorithm = oidPublicKeyEd25519
+ case *ecdh.PublicKey:
+ publicKeyBytes = pub.Bytes()
+ if pub.Curve() == ecdh.X25519() {
+ publicKeyAlgorithm.Algorithm = oidPublicKeyX25519
+ } else {
+ oid, ok := oidFromECDHCurve(pub.Curve())
+ if !ok {
+ return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported elliptic curve")
+ }
+ publicKeyAlgorithm.Algorithm = oidPublicKeyECDSA
+ var paramBytes []byte
+ paramBytes, err = asn1.Marshal(oid)
+ if err != nil {
+ return
+ }
+ publicKeyAlgorithm.Parameters.FullBytes = paramBytes
+ }
+ case *gost3410.PublicKey:
+ builder := cryptobyte.NewBuilder(nil)
+ builder.AddASN1OctetString(pub.Raw())
+ publicKeyBytes, err = builder.Bytes()
+ if err != nil {
+ return
+ }
+ params := GostR341012PublicKeyParameters{}
+ switch pub.C.Name {
+ case "id-GostR3410-2001-CryptoPro-A-ParamSet":
+ publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+ params.PublicKeyParamSet = oidGostR34102001CryptoProAParamSet
+ params.DigestParamSet = oidTc26Gost34112012256
+ case "id-GostR3410-2001-CryptoPro-B-ParamSet":
+ publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+ params.PublicKeyParamSet = oidGostR34102001CryptoProBParamSet
+ params.DigestParamSet = oidTc26Gost34112012256
+ case "id-GostR3410-2001-CryptoPro-C-ParamSet":
+ publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+ params.PublicKeyParamSet = oidGostR34102001CryptoProCParamSet
+ params.DigestParamSet = oidTc26Gost34112012256
+ case "id-GostR3410-2001-CryptoPro-XchA-ParamSet":
+ publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+ params.PublicKeyParamSet = oidGostR34102001CryptoProXchAParamSet
+ params.DigestParamSet = oidTc26Gost34112012256
+ case "id-GostR3410-2001-CryptoPro-XchB-ParamSet":
+ publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+ params.PublicKeyParamSet = oidGostR34102001CryptoProXchBParamSet
+ params.DigestParamSet = oidTc26Gost34112012256
+ case "id-tc26-gost-3410-12-256-paramSetA":
+ publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+ params.PublicKeyParamSet = oidTc26Gost341012256ParamSetA
+ case "id-tc26-gost-3410-12-256-paramSetB":
+ publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+ params.PublicKeyParamSet = oidTc26Gost341012256ParamSetB
+ case "id-tc26-gost-3410-12-256-paramSetC":
+ publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+ params.PublicKeyParamSet = oidTc26Gost341012256ParamSetC
+ case "id-tc26-gost-3410-12-256-paramSetD":
+ publicKeyAlgorithm.Algorithm = oidTc26Gost341012256
+ params.PublicKeyParamSet = oidTc26Gost341012256ParamSetD
+ case "id-tc26-gost-3410-12-512-paramSetA":
+ publicKeyAlgorithm.Algorithm = oidTc26Gost341012512
+ params.PublicKeyParamSet = oidTc26Gost341012512ParamSetA
+ case "id-tc26-gost-3410-12-512-paramSetB":
+ publicKeyAlgorithm.Algorithm = oidTc26Gost341012512
+ params.PublicKeyParamSet = oidTc26Gost341012512ParamSetB
+ case "id-tc26-gost-3410-12-512-paramSetC":
+ publicKeyAlgorithm.Algorithm = oidTc26Gost341012512
+ params.PublicKeyParamSet = oidTc26Gost341012512ParamSetC
+ default:
+ return nil, pkix.AlgorithmIdentifier{}, errors.New("x509: unsupported GOST elliptic curve")
+ }
+ publicKeyAlgorithm.Parameters.FullBytes, err = asn1.Marshal(params)
+ if err != nil {
+ panic(err)
+ }
default:
return nil, pkix.AlgorithmIdentifier{}, fmt.Errorf("x509: unsupported public key type: %T", pub)
}
// 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
-// and ed25519.PublicKey. Unsupported key types result in an error.
+// 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 MarshalPKIXPublicKey(pub interface{}) ([]byte, error) {
+func MarshalPKIXPublicKey(pub any) ([]byte, error) {
var publicKeyBytes []byte
var publicKeyAlgorithm pkix.AlgorithmIdentifier
var err error
// These structures reflect the ASN.1 structure of X.509 certificates.:
type certificate struct {
- Raw asn1.RawContent
TBSCertificate tbsCertificate
SignatureAlgorithm pkix.AlgorithmIdentifier
SignatureValue asn1.BitString
PublicKey publicKeyInfo
UniqueId asn1.BitString `asn1:"optional,tag:1"`
SubjectUniqueId asn1.BitString `asn1:"optional,tag:2"`
- Extensions []pkix.Extension `asn1:"optional,explicit,tag:3"`
+ Extensions []pkix.Extension `asn1:"omitempty,optional,explicit,tag:3"`
}
type dsaAlgorithmParameters struct {
const (
UnknownSignatureAlgorithm SignatureAlgorithm = iota
- MD2WithRSA // Unsupported.
- MD5WithRSA // Only supported for signing, not verification.
- SHA1WithRSA
+ 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
+ ECDSAWithSHA1 // Only supported for signing, and verification of CRLs, CSRs, and OCSP responses.
ECDSAWithSHA256
ECDSAWithSHA384
ECDSAWithSHA512
SHA384WithRSAPSS
SHA512WithRSAPSS
PureEd25519
+ GOST256
+ GOST512
)
func (algo SignatureAlgorithm) isRSAPSS() bool {
const (
UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota
RSA
- DSA // Unsupported.
+ DSA // Only supported for parsing.
ECDSA
Ed25519
+ GOST
)
var publicKeyAlgoName = [...]string{
DSA: "DSA",
ECDSA: "ECDSA",
Ed25519: "Ed25519",
+ GOST: "GOST",
}
func (algo PublicKeyAlgorithm) String() string {
// OIDs for signature algorithms
//
-// pkcs-1 OBJECT IDENTIFIER ::= {
-// iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
-//
+// pkcs-1 OBJECT IDENTIFIER ::= {
+// iso(1) member-body(2) us(840) rsadsi(113549) pkcs(1) 1 }
//
// RFC 3279 2.2.1 RSA Signature Algorithms
//
-// md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
+// md2WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 2 }
//
-// md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
+// md5WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 4 }
//
-// sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
+// sha-1WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 5 }
//
-// dsaWithSha1 OBJECT IDENTIFIER ::= {
-// iso(1) member-body(2) us(840) x9-57(10040) x9cm(4) 3 }
+// 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)}
-//
+// 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 }
+// sha256WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 11 }
//
-// sha512WithRSAEncryption OBJECT IDENTIFIER ::= { pkcs-1 13 }
+// 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}
+// 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-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 }
+// 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 }
-
+// id-Ed25519 OBJECT IDENTIFIER ::= { 1 3 101 112 }
var (
oidSignatureMD2WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 2}
oidSignatureMD5WithRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 4}
oidSignatureECDSAWithSHA512 = asn1.ObjectIdentifier{1, 2, 840, 10045, 4, 3, 4}
oidSignatureEd25519 = asn1.ObjectIdentifier{1, 3, 101, 112}
+ oidTc26Gost341012256 = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 1, 1, 1}
+ oidTc26Gost341012512 = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 1, 1, 2}
+ oidTc26Gost34112012256 = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 1, 2, 2}
+ oidTc26Gost34112012512 = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 1, 2, 3}
+ oidTc26Gost341012256Signature = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 1, 3, 2}
+ oidTc26Gost341012512Signature = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 1, 3, 3}
+ oidGostR34102001CryptoProAParamSet = asn1.ObjectIdentifier{1, 2, 643, 2, 2, 35, 1}
+ oidGostR34102001CryptoProBParamSet = asn1.ObjectIdentifier{1, 2, 643, 2, 2, 35, 2}
+ oidGostR34102001CryptoProCParamSet = asn1.ObjectIdentifier{1, 2, 643, 2, 2, 35, 3}
+ oidGostR34102001CryptoProXchAParamSet = asn1.ObjectIdentifier{1, 2, 643, 2, 2, 36, 0}
+ oidGostR34102001CryptoProXchBParamSet = asn1.ObjectIdentifier{1, 2, 643, 2, 2, 36, 1}
+ oidTc26Gost341012256ParamSetA = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 2, 1, 1, 1}
+ oidTc26Gost341012256ParamSetB = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 2, 1, 1, 2}
+ oidTc26Gost341012256ParamSetC = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 2, 1, 1, 3}
+ oidTc26Gost341012256ParamSetD = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 2, 1, 1, 4}
+ oidTc26Gost341012512ParamSetA = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 2, 1, 2, 1}
+ oidTc26Gost341012512ParamSetB = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 2, 1, 2, 2}
+ oidTc26Gost341012512ParamSetC = asn1.ObjectIdentifier{1, 2, 643, 7, 1, 2, 1, 2, 3}
+
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}
{ECDSAWithSHA384, "ECDSA-SHA384", oidSignatureECDSAWithSHA384, ECDSA, crypto.SHA384},
{ECDSAWithSHA512, "ECDSA-SHA512", oidSignatureECDSAWithSHA512, ECDSA, crypto.SHA512},
{PureEd25519, "Ed25519", oidSignatureEd25519, Ed25519, crypto.Hash(0) /* no pre-hashing */},
+ {GOST256, "GOST256", oidTc26Gost341012256Signature, GOST, crypto.GOSTR34112012256},
+ {GOST512, "GOST512", oidTc26Gost341012512Signature, GOST, crypto.GOSTR34112012512},
}
// hashToPSSParameters contains the 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
+// - 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 hashToPSSParameters = map[crypto.Hash]asn1.RawValue{
crypto.SHA256: 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}},
crypto.SHA384: 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}},
return UnknownSignatureAlgorithm
}
-// 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 }
-//
-// 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 }
var (
- oidPublicKeyRSA = asn1.ObjectIdentifier{1, 2, 840, 113549, 1, 1, 1}
- oidPublicKeyDSA = asn1.ObjectIdentifier{1, 2, 840, 10040, 4, 1}
- oidPublicKeyECDSA = asn1.ObjectIdentifier{1, 2, 840, 10045, 2, 1}
- oidPublicKeyEd25519 = oidSignatureEd25519
+ // 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}
+
+ oidPublicKeyGOST256 = oidTc26Gost341012256
+ oidPublicKeyGOST512 = oidTc26Gost341012512
)
+// 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(oid asn1.ObjectIdentifier) PublicKeyAlgorithm {
switch {
case oid.Equal(oidPublicKeyRSA):
return ECDSA
case oid.Equal(oidPublicKeyEd25519):
return Ed25519
+ case oid.Equal(oidPublicKeyGOST256):
+ return GOST
+ case oid.Equal(oidPublicKeyGOST512):
+ return GOST
}
return UnknownPublicKeyAlgorithm
}
// RFC 5480, 2.1.1.1. Named Curve
//
-// secp224r1 OBJECT IDENTIFIER ::= {
-// iso(1) identified-organization(3) certicom(132) curve(0) 33 }
+// 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 }
+// 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 }
+// 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 }
+// secp521r1 OBJECT IDENTIFIER ::= {
+// iso(1) identified-organization(3) certicom(132) curve(0) 35 }
//
// NB: secp256r1 is equivalent to prime256v1
var (
return nil, false
}
+func oidFromECDHCurve(curve ecdh.Curve) (asn1.ObjectIdentifier, bool) {
+ switch curve {
+ 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
// RFC 5280, 4.2.1.12 Extended Key Usage
//
-// anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 }
+// anyExtendedKeyUsage OBJECT IDENTIFIER ::= { id-ce-extKeyUsage 0 }
//
-// id-kp OBJECT IDENTIFIER ::= { id-pkix 3 }
+// 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 }
+// 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}
SignatureAlgorithm SignatureAlgorithm
PublicKeyAlgorithm PublicKeyAlgorithm
- PublicKey interface{}
+ PublicKey any
Version int
SerialNumber *big.Int
// involves algorithms that are not currently implemented.
var ErrUnsupportedAlgorithm = errors.New("x509: cannot verify signature: algorithm unimplemented")
-// An InsecureAlgorithmError
+// 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 (e InsecureAlgorithmError) Error() string {
- return fmt.Sprintf("x509: cannot verify signature: insecure algorithm %v", SignatureAlgorithm(e))
+ var override string
+ if SignatureAlgorithm(e) == SHA1WithRSA || SignatureAlgorithm(e) == ECDSAWithSHA1 {
+ override = " (temporarily override with GODEBUG=x509sha1=1)"
+ }
+ return fmt.Sprintf("x509: cannot verify signature: insecure algorithm %v", SignatureAlgorithm(e)) + override
}
// ConstraintViolationError results when a requested usage is not permitted by
return oidInExtensions(oidExtensionSubjectAltName, c.Extensions)
}
-// CheckSignatureFrom verifies that the signature on c is a valid signature
-// from parent.
+// 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 (c *Certificate) CheckSignatureFrom(parent *Certificate) error {
// RFC 5280, 4.2.1.9:
// "If the basic constraints extension is not present in a version 3
return ErrUnsupportedAlgorithm
}
- // TODO(agl): don't ignore the path length constraint.
-
- return parent.CheckSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature)
+ return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature, parent.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 (c *Certificate) CheckSignature(algo SignatureAlgorithm, signed, signature []byte) error {
- return checkSignature(algo, signed, signature, c.PublicKey)
+ return checkSignature(algo, signed, signature, c.PublicKey, true)
}
func (c *Certificate) hasNameConstraints() bool {
return nil
}
-func signaturePublicKeyAlgoMismatchError(expectedPubKeyAlgo PublicKeyAlgorithm, pubKey interface{}) error {
+func signaturePublicKeyAlgoMismatchError(expectedPubKeyAlgo PublicKeyAlgorithm, pubKey any) error {
return fmt.Errorf("x509: signature algorithm specifies an %s public key, but have public key of type %T", expectedPubKeyAlgo.String(), pubKey)
}
-// CheckSignature verifies that signature is a valid signature over signed from
+var x509sha1 = godebug.New("x509sha1")
+
+// checkSignature verifies that signature is a valid signature over signed from
// a crypto.PublicKey.
-func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey) (err error) {
+func checkSignature(algo SignatureAlgorithm, signed, signature []byte, publicKey crypto.PublicKey, allowSHA1 bool) (err error) {
var hashType crypto.Hash
var pubKeyAlgo PublicKeyAlgorithm
}
case crypto.MD5:
return InsecureAlgorithmError(algo)
+ case crypto.SHA1:
+ // SHA-1 signatures are mostly disabled. See go.dev/issue/41682.
+ if !allowSHA1 && x509sha1.Value() != "1" {
+ return InsecureAlgorithmError(algo)
+ }
+ fallthrough
default:
if !hashType.Available() {
return ErrUnsupportedAlgorithm
return errors.New("x509: Ed25519 verification failure")
}
return
+ case *gost3410.PublicKey:
+ if pubKeyAlgo != GOST {
+ return signaturePublicKeyAlgoMismatchError(pubKeyAlgo, pub)
+ }
+ ok, err := gost3410.PublicKeyReverseDigest{Pub: pub}.VerifyDigest(signed, signature)
+ if err != nil {
+ return err
+ }
+ if !ok {
+ return errors.New("x509: GOST verification failure")
+ }
+ return err
}
return ErrUnsupportedAlgorithm
}
// CheckCRLSignature checks that the signature in crl is from c.
+//
+// Deprecated: Use RevocationList.CheckSignatureFrom instead.
func (c *Certificate) CheckCRLSignature(crl *pkix.CertificateList) error {
algo := getSignatureAlgorithmFromAI(crl.SignatureAlgorithm)
return c.CheckSignature(algo, crl.TBSCertList.Raw, crl.SignatureValue.RightAlign())
RelativeName pkix.RDNSequence `asn1:"optional,tag:1"`
}
-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.
- // See RFC 3279, Section 2.3.1.
- if !bytes.Equal(keyData.Algorithm.Parameters.FullBytes, asn1.NullBytes) {
- return nil, errors.New("x509: RSA key missing NULL parameters")
- }
-
- p := new(pkcs1PublicKey)
- rest, err := asn1.Unmarshal(asn1Data, p)
- if err != nil {
- return nil, err
- }
- if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after RSA public key")
- }
-
- if p.N.Sign() <= 0 {
- return nil, errors.New("x509: RSA modulus is not a positive number")
- }
- if p.E <= 0 {
- return nil, errors.New("x509: RSA public exponent is not a positive number")
- }
-
- pub := &rsa.PublicKey{
- E: p.E,
- N: p.N,
- }
- return pub, nil
- case DSA:
- var p *big.Int
- rest, err := asn1.Unmarshal(asn1Data, &p)
- if err != nil {
- return nil, err
- }
- if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after DSA public key")
- }
- paramsData := keyData.Algorithm.Parameters.FullBytes
- params := new(dsaAlgorithmParameters)
- rest, err = asn1.Unmarshal(paramsData, params)
- if err != nil {
- return nil, err
- }
- if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after DSA parameters")
- }
- if p.Sign() <= 0 || params.P.Sign() <= 0 || params.Q.Sign() <= 0 || params.G.Sign() <= 0 {
- return nil, errors.New("x509: zero or negative DSA parameter")
- }
- pub := &dsa.PublicKey{
- Parameters: dsa.Parameters{
- P: params.P,
- Q: params.Q,
- G: params.G,
- },
- Y: p,
- }
- return pub, nil
- case ECDSA:
- paramsData := keyData.Algorithm.Parameters.FullBytes
- namedCurveOID := new(asn1.ObjectIdentifier)
- rest, err := asn1.Unmarshal(paramsData, namedCurveOID)
- if err != nil {
- return nil, errors.New("x509: failed to parse ECDSA parameters as named curve")
- }
- if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after ECDSA parameters")
- }
- namedCurve := namedCurveFromOID(*namedCurveOID)
- if namedCurve == nil {
- return nil, errors.New("x509: unsupported elliptic curve")
- }
- x, y := elliptic.Unmarshal(namedCurve, asn1Data)
- if x == nil {
- return nil, errors.New("x509: failed to unmarshal elliptic curve point")
- }
- pub := &ecdsa.PublicKey{
- Curve: namedCurve,
- X: x,
- Y: y,
- }
- return pub, nil
- case Ed25519:
- // RFC 8410, Section 3
- // > For all of the OIDs, the parameters MUST be absent.
- if len(keyData.Algorithm.Parameters.FullBytes) != 0 {
- return nil, errors.New("x509: Ed25519 key encoded with illegal parameters")
- }
- if len(asn1Data) != ed25519.PublicKeySize {
- return nil, errors.New("x509: wrong Ed25519 public key size")
- }
- pub := make([]byte, ed25519.PublicKeySize)
- copy(pub, asn1Data)
- return ed25519.PublicKey(pub), nil
- default:
- return nil, nil
- }
-}
-
-func forEachSAN(extension []byte, callback func(tag int, data []byte) error) error {
- // RFC 5280, 4.2.1.6
-
- // SubjectAltName ::= GeneralNames
- //
- // GeneralNames ::= SEQUENCE SIZE (1..MAX) OF GeneralName
- //
- // GeneralName ::= CHOICE {
- // otherName [0] OtherName,
- // rfc822Name [1] IA5String,
- // dNSName [2] IA5String,
- // x400Address [3] ORAddress,
- // directoryName [4] Name,
- // ediPartyName [5] EDIPartyName,
- // uniformResourceIdentifier [6] IA5String,
- // iPAddress [7] OCTET STRING,
- // registeredID [8] OBJECT IDENTIFIER }
- var seq asn1.RawValue
- rest, err := asn1.Unmarshal(extension, &seq)
- if err != nil {
- return err
- } else if len(rest) != 0 {
- return errors.New("x509: trailing data after X.509 extension")
- }
- if !seq.IsCompound || seq.Tag != 16 || seq.Class != 0 {
- return asn1.StructuralError{Msg: "bad SAN sequence"}
- }
-
- rest = seq.Bytes
- for len(rest) > 0 {
- var v asn1.RawValue
- rest, err = asn1.Unmarshal(rest, &v)
- if err != nil {
- return err
- }
-
- if err := callback(v.Tag, v.Bytes); err != nil {
- return err
- }
- }
-
- return nil
-}
-
-func parseSANExtension(value []byte) (dnsNames, emailAddresses []string, ipAddresses []net.IP, uris []*url.URL, err error) {
- err = forEachSAN(value, func(tag int, data []byte) error {
- switch tag {
- case nameTypeEmail:
- email := string(data)
- if err := isIA5String(email); err != nil {
- return errors.New("x509: SAN rfc822Name is malformed")
- }
- emailAddresses = append(emailAddresses, email)
- case nameTypeDNS:
- name := string(data)
- if err := isIA5String(name); err != nil {
- return errors.New("x509: SAN dNSName is malformed")
- }
- dnsNames = append(dnsNames, string(name))
- case nameTypeURI:
- uriStr := string(data)
- if err := isIA5String(uriStr); err != nil {
- return errors.New("x509: SAN uniformResourceIdentifier is malformed")
- }
- uri, err := url.Parse(uriStr)
- if err != nil {
- return fmt.Errorf("x509: cannot parse URI %q: %s", uriStr, err)
- }
- if len(uri.Host) > 0 {
- if _, ok := domainToReverseLabels(uri.Host); !ok {
- return fmt.Errorf("x509: cannot parse URI %q: invalid domain", uriStr)
- }
- }
- uris = append(uris, uri)
- case nameTypeIP:
- switch len(data) {
- case net.IPv4len, net.IPv6len:
- ipAddresses = append(ipAddresses, data)
- default:
- return errors.New("x509: cannot parse IP address of length " + strconv.Itoa(len(data)))
- }
- }
-
- return nil
- })
-
- return
-}
-
-// isValidIPMask reports whether mask consists of zero or more 1 bits, followed by zero bits.
-func isValidIPMask(mask []byte) bool {
- seenZero := false
-
- for _, b := range mask {
- if seenZero {
- if b != 0 {
- return false
- }
-
- continue
- }
-
- switch b {
- case 0x00, 0x80, 0xc0, 0xe0, 0xf0, 0xf8, 0xfc, 0xfe:
- seenZero = true
- case 0xff:
- default:
- return false
- }
- }
-
- return true
-}
-
-func parseNameConstraintsExtension(out *Certificate, e pkix.Extension) (unhandled bool, err error) {
- // RFC 5280, 4.2.1.10
-
- // NameConstraints ::= SEQUENCE {
- // permittedSubtrees [0] GeneralSubtrees OPTIONAL,
- // excludedSubtrees [1] GeneralSubtrees OPTIONAL }
- //
- // GeneralSubtrees ::= SEQUENCE SIZE (1..MAX) OF GeneralSubtree
- //
- // GeneralSubtree ::= SEQUENCE {
- // base GeneralName,
- // minimum [0] BaseDistance DEFAULT 0,
- // maximum [1] BaseDistance OPTIONAL }
- //
- // BaseDistance ::= INTEGER (0..MAX)
-
- outer := cryptobyte.String(e.Value)
- var toplevel, permitted, excluded cryptobyte.String
- var havePermitted, haveExcluded bool
- if !outer.ReadASN1(&toplevel, cryptobyte_asn1.SEQUENCE) ||
- !outer.Empty() ||
- !toplevel.ReadOptionalASN1(&permitted, &havePermitted, cryptobyte_asn1.Tag(0).ContextSpecific().Constructed()) ||
- !toplevel.ReadOptionalASN1(&excluded, &haveExcluded, cryptobyte_asn1.Tag(1).ContextSpecific().Constructed()) ||
- !toplevel.Empty() {
- return false, errors.New("x509: invalid NameConstraints extension")
- }
-
- if !havePermitted && !haveExcluded || len(permitted) == 0 && len(excluded) == 0 {
- // From RFC 5280, Section 4.2.1.10:
- // “either the permittedSubtrees field
- // or the excludedSubtrees MUST be
- // present”
- return false, errors.New("x509: empty name constraints extension")
- }
-
- getValues := func(subtrees cryptobyte.String) (dnsNames []string, ips []*net.IPNet, emails, uriDomains []string, err error) {
- for !subtrees.Empty() {
- var seq, value cryptobyte.String
- var tag cryptobyte_asn1.Tag
- if !subtrees.ReadASN1(&seq, cryptobyte_asn1.SEQUENCE) ||
- !seq.ReadAnyASN1(&value, &tag) {
- return nil, nil, nil, nil, fmt.Errorf("x509: invalid NameConstraints extension")
- }
-
- var (
- dnsTag = cryptobyte_asn1.Tag(2).ContextSpecific()
- emailTag = cryptobyte_asn1.Tag(1).ContextSpecific()
- ipTag = cryptobyte_asn1.Tag(7).ContextSpecific()
- uriTag = cryptobyte_asn1.Tag(6).ContextSpecific()
- )
-
- switch tag {
- case dnsTag:
- domain := string(value)
- if err := isIA5String(domain); err != nil {
- return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
- }
-
- trimmedDomain := domain
- if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' {
- // constraints can have a leading
- // period to exclude the domain
- // itself, but that's not valid in a
- // normal domain name.
- trimmedDomain = trimmedDomain[1:]
- }
- if _, ok := domainToReverseLabels(trimmedDomain); !ok {
- return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse dnsName constraint %q", domain)
- }
- dnsNames = append(dnsNames, domain)
-
- case ipTag:
- l := len(value)
- var ip, mask []byte
-
- switch l {
- case 8:
- ip = value[:4]
- mask = value[4:]
-
- case 32:
- ip = value[:16]
- mask = value[16:]
-
- default:
- return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained value of length %d", l)
- }
-
- if !isValidIPMask(mask) {
- return nil, nil, nil, nil, fmt.Errorf("x509: IP constraint contained invalid mask %x", mask)
- }
-
- ips = append(ips, &net.IPNet{IP: net.IP(ip), Mask: net.IPMask(mask)})
-
- case emailTag:
- constraint := string(value)
- if err := isIA5String(constraint); err != nil {
- return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
- }
-
- // If the constraint contains an @ then
- // it specifies an exact mailbox name.
- if strings.Contains(constraint, "@") {
- if _, ok := parseRFC2821Mailbox(constraint); !ok {
- return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
- }
- } else {
- // Otherwise it's a domain name.
- domain := constraint
- if len(domain) > 0 && domain[0] == '.' {
- domain = domain[1:]
- }
- if _, ok := domainToReverseLabels(domain); !ok {
- return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse rfc822Name constraint %q", constraint)
- }
- }
- emails = append(emails, constraint)
-
- case uriTag:
- domain := string(value)
- if err := isIA5String(domain); err != nil {
- return nil, nil, nil, nil, errors.New("x509: invalid constraint value: " + err.Error())
- }
-
- if net.ParseIP(domain) != nil {
- return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q: cannot be IP address", domain)
- }
-
- trimmedDomain := domain
- if len(trimmedDomain) > 0 && trimmedDomain[0] == '.' {
- // constraints can have a leading
- // period to exclude the domain itself,
- // but that's not valid in a normal
- // domain name.
- trimmedDomain = trimmedDomain[1:]
- }
- if _, ok := domainToReverseLabels(trimmedDomain); !ok {
- return nil, nil, nil, nil, fmt.Errorf("x509: failed to parse URI constraint %q", domain)
- }
- uriDomains = append(uriDomains, domain)
-
- default:
- unhandled = true
- }
- }
-
- return dnsNames, ips, emails, uriDomains, nil
- }
-
- if out.PermittedDNSDomains, out.PermittedIPRanges, out.PermittedEmailAddresses, out.PermittedURIDomains, err = getValues(permitted); err != nil {
- return false, err
- }
- if out.ExcludedDNSDomains, out.ExcludedIPRanges, out.ExcludedEmailAddresses, out.ExcludedURIDomains, err = getValues(excluded); err != nil {
- return false, err
- }
- out.PermittedDNSDomainsCritical = e.Critical
-
- return unhandled, nil
-}
-
-func parseCertificate(in *certificate) (*Certificate, error) {
- out := new(Certificate)
- out.Raw = in.Raw
- out.RawTBSCertificate = in.TBSCertificate.Raw
- out.RawSubjectPublicKeyInfo = in.TBSCertificate.PublicKey.Raw
- out.RawSubject = in.TBSCertificate.Subject.FullBytes
- out.RawIssuer = in.TBSCertificate.Issuer.FullBytes
-
- out.Signature = in.SignatureValue.RightAlign()
- out.SignatureAlgorithm =
- getSignatureAlgorithmFromAI(in.TBSCertificate.SignatureAlgorithm)
-
- out.PublicKeyAlgorithm =
- getPublicKeyAlgorithmFromOID(in.TBSCertificate.PublicKey.Algorithm.Algorithm)
- var err error
- out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCertificate.PublicKey)
- if err != nil {
- return nil, err
- }
-
- out.Version = in.TBSCertificate.Version + 1
- out.SerialNumber = in.TBSCertificate.SerialNumber
-
- var issuer, subject pkix.RDNSequence
- if rest, err := asn1.Unmarshal(in.TBSCertificate.Subject.FullBytes, &subject); err != nil {
- return nil, err
- } else if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after X.509 subject")
- }
- if rest, err := asn1.Unmarshal(in.TBSCertificate.Issuer.FullBytes, &issuer); err != nil {
- return nil, err
- } else if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after X.509 issuer")
- }
-
- out.Issuer.FillFromRDNSequence(&issuer)
- out.Subject.FillFromRDNSequence(&subject)
-
- out.NotBefore = in.TBSCertificate.Validity.NotBefore
- out.NotAfter = in.TBSCertificate.Validity.NotAfter
-
- for _, e := range in.TBSCertificate.Extensions {
- out.Extensions = append(out.Extensions, e)
- unhandled := false
-
- if len(e.Id) == 4 && e.Id[0] == 2 && e.Id[1] == 5 && e.Id[2] == 29 {
- switch e.Id[3] {
- case 15:
- out.KeyUsage, err = parseKeyUsageExtension(e.Value)
- if err != nil {
- return nil, err
- }
- case 19:
- out.IsCA, out.MaxPathLen, err = parseBasicConstraintsExtension(e.Value)
- if err != nil {
- return nil, err
- }
- out.BasicConstraintsValid = true
- out.MaxPathLenZero = out.MaxPathLen == 0
- case 17:
- out.DNSNames, out.EmailAddresses, out.IPAddresses, out.URIs, err = parseSANExtension(e.Value)
- if err != nil {
- return nil, err
- }
-
- if len(out.DNSNames) == 0 && len(out.EmailAddresses) == 0 && len(out.IPAddresses) == 0 && len(out.URIs) == 0 {
- // If we didn't parse anything then we do the critical check, below.
- unhandled = true
- }
-
- case 30:
- unhandled, err = parseNameConstraintsExtension(out, e)
- if err != nil {
- return nil, err
- }
-
- case 31:
- // RFC 5280, 4.2.1.13
-
- // CRLDistributionPoints ::= SEQUENCE SIZE (1..MAX) OF DistributionPoint
- //
- // DistributionPoint ::= SEQUENCE {
- // distributionPoint [0] DistributionPointName OPTIONAL,
- // reasons [1] ReasonFlags OPTIONAL,
- // cRLIssuer [2] GeneralNames OPTIONAL }
- //
- // DistributionPointName ::= CHOICE {
- // fullName [0] GeneralNames,
- // nameRelativeToCRLIssuer [1] RelativeDistinguishedName }
-
- var cdp []distributionPoint
- if rest, err := asn1.Unmarshal(e.Value, &cdp); err != nil {
- return nil, err
- } else if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after X.509 CRL distribution point")
- }
-
- for _, dp := range cdp {
- // Per RFC 5280, 4.2.1.13, one of distributionPoint or cRLIssuer may be empty.
- if len(dp.DistributionPoint.FullName) == 0 {
- continue
- }
-
- for _, fullName := range dp.DistributionPoint.FullName {
- if fullName.Tag == 6 {
- out.CRLDistributionPoints = append(out.CRLDistributionPoints, string(fullName.Bytes))
- }
- }
- }
-
- case 35:
- // RFC 5280, 4.2.1.1
- var a authKeyId
- if rest, err := asn1.Unmarshal(e.Value, &a); err != nil {
- return nil, err
- } else if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after X.509 authority key-id")
- }
- out.AuthorityKeyId = a.Id
-
- case 37:
- out.ExtKeyUsage, out.UnknownExtKeyUsage, err = parseExtKeyUsageExtension(e.Value)
- if err != nil {
- return nil, err
- }
- case 14:
- out.SubjectKeyId, err = parseSubjectKeyIdExtension(e.Value)
- if err != nil {
- return nil, err
- }
- case 32:
- out.PolicyIdentifiers, err = parseCertificatePoliciesExtension(e.Value)
- if err != nil {
- return nil, err
- }
- default:
- // Unknown extensions are recorded if critical.
- unhandled = true
- }
- } else if e.Id.Equal(oidExtensionAuthorityInfoAccess) {
- // RFC 5280 4.2.2.1: Authority Information Access
- var aia []authorityInfoAccess
- if rest, err := asn1.Unmarshal(e.Value, &aia); err != nil {
- return nil, err
- } else if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after X.509 authority information")
- }
-
- for _, v := range aia {
- // GeneralName: uniformResourceIdentifier [6] IA5String
- if v.Location.Tag != 6 {
- continue
- }
- if v.Method.Equal(oidAuthorityInfoAccessOcsp) {
- out.OCSPServer = append(out.OCSPServer, string(v.Location.Bytes))
- } else if v.Method.Equal(oidAuthorityInfoAccessIssuers) {
- out.IssuingCertificateURL = append(out.IssuingCertificateURL, string(v.Location.Bytes))
- }
- }
- } else {
- // Unknown extensions are recorded if critical.
- unhandled = true
- }
-
- if e.Critical && unhandled {
- out.UnhandledCriticalExtensions = append(out.UnhandledCriticalExtensions, e.Id)
- }
- }
-
- return out, nil
-}
-
-// parseKeyUsageExtension parses id-ce-keyUsage (2.5.29.15) from RFC 5280
-// Section 4.2.1.3
-func parseKeyUsageExtension(ext []byte) (KeyUsage, error) {
- var usageBits asn1.BitString
- if rest, err := asn1.Unmarshal(ext, &usageBits); err != nil {
- return 0, err
- } else if len(rest) != 0 {
- return 0, errors.New("x509: trailing data after X.509 KeyUsage")
- }
-
- var usage int
- for i := 0; i < 9; i++ {
- if usageBits.At(i) != 0 {
- usage |= 1 << uint(i)
- }
- }
- return KeyUsage(usage), nil
-}
-
-// parseBasicConstraintsExtension parses id-ce-basicConstraints (2.5.29.19)
-// from RFC 5280 Section 4.2.1.9
-func parseBasicConstraintsExtension(ext []byte) (isCA bool, maxPathLen int, err error) {
- var constraints basicConstraints
- if rest, err := asn1.Unmarshal(ext, &constraints); err != nil {
- return false, 0, err
- } else if len(rest) != 0 {
- return false, 0, errors.New("x509: trailing data after X.509 BasicConstraints")
- }
-
- // TODO: map out.MaxPathLen to 0 if it has the -1 default value? (Issue 19285)
- return constraints.IsCA, constraints.MaxPathLen, nil
-}
-
-// parseExtKeyUsageExtension parses id-ce-extKeyUsage (2.5.29.37) from
-// RFC 5280 Section 4.2.1.12
-func parseExtKeyUsageExtension(ext []byte) ([]ExtKeyUsage, []asn1.ObjectIdentifier, error) {
- var keyUsage []asn1.ObjectIdentifier
- if rest, err := asn1.Unmarshal(ext, &keyUsage); err != nil {
- return nil, nil, err
- } else if len(rest) != 0 {
- return nil, nil, errors.New("x509: trailing data after X.509 ExtendedKeyUsage")
- }
-
- var extKeyUsages []ExtKeyUsage
- var unknownUsages []asn1.ObjectIdentifier
- for _, u := range keyUsage {
- if extKeyUsage, ok := extKeyUsageFromOID(u); ok {
- extKeyUsages = append(extKeyUsages, extKeyUsage)
- } else {
- unknownUsages = append(unknownUsages, u)
- }
- }
- return extKeyUsages, unknownUsages, nil
-}
-
-// parseSubjectKeyIdExtension parses id-ce-subjectKeyIdentifier (2.5.29.14)
-// from RFC 5280 Section 4.2.1.2
-func parseSubjectKeyIdExtension(ext []byte) ([]byte, error) {
- var keyid []byte
- if rest, err := asn1.Unmarshal(ext, &keyid); err != nil {
- return nil, err
- } else if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after X.509 key-id")
- }
- return keyid, nil
-}
-
-func parseCertificatePoliciesExtension(ext []byte) ([]asn1.ObjectIdentifier, error) {
- var policies []policyInformation
- if rest, err := asn1.Unmarshal(ext, &policies); err != nil {
- return nil, err
- } else if len(rest) != 0 {
- return nil, errors.New("x509: trailing data after X.509 certificate policies")
- }
- oids := make([]asn1.ObjectIdentifier, len(policies))
- for i, policy := range policies {
- oids[i] = policy.Policy
- }
- return oids, nil
-}
-
-// ParseCertificate parses a single certificate from the given ASN.1 DER data.
-func ParseCertificate(asn1Data []byte) (*Certificate, error) {
- var cert certificate
- rest, err := asn1.Unmarshal(asn1Data, &cert)
- if err != nil {
- return nil, err
- }
- if len(rest) > 0 {
- return nil, asn1.SyntaxError{Msg: "trailing data"}
- }
-
- return parseCertificate(&cert)
-}
-
-// ParseCertificates parses one or more certificates from the given ASN.1 DER
-// data. The certificates must be concatenated with no intermediate padding.
-func ParseCertificates(asn1Data []byte) ([]*Certificate, error) {
- var v []*certificate
-
- for len(asn1Data) > 0 {
- cert := new(certificate)
- var err error
- asn1Data, err = asn1.Unmarshal(asn1Data, cert)
- if err != nil {
- return nil, err
- }
- v = append(v, cert)
- }
-
- ret := make([]*Certificate, len(v))
- for i, ci := range v {
- cert, err := parseCertificate(ci)
- if err != nil {
- return nil, err
- }
- ret[i] = cert
- }
-
- return ret, nil
-}
-
func reverseBitsInAByte(in byte) byte {
b1 := in>>4 | in<<4
b2 := b1>>2&0x33 | b1<<2&0xcc
oidAuthorityInfoAccessIssuers = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 48, 2}
)
-// oidNotInExtensions reports whether an extension with the given oid exists in
+// oidInExtensions reports whether an extension with the given oid exists in
// extensions.
func oidInExtensions(oid asn1.ObjectIdentifier, extensions []pkix.Extension) bool {
for _, e := range extensions {
bitString := a[:l]
var err error
ext.Value, err = asn1.Marshal(asn1.BitString{Bytes: bitString, BitLength: asn1BitLength(bitString)})
- if err != nil {
- return ext, err
- }
- return ext, nil
+ return ext, err
}
func marshalExtKeyUsage(extUsages []ExtKeyUsage, unknownUsages []asn1.ObjectIdentifier) (pkix.Extension, error) {
var err error
ext.Value, err = asn1.Marshal(oids)
- if err != nil {
- return ext, err
- }
- return ext, nil
+ return ext, err
}
func marshalBasicConstraints(isCA bool, maxPathLen int, maxPathLenZero bool) (pkix.Extension, error) {
}
var err error
ext.Value, err = asn1.Marshal(basicConstraints{isCA, maxPathLen})
- if err != nil {
- return ext, nil
- }
- return ext, nil
+ return ext, err
}
func marshalCertificatePolicies(policyIdentifiers []asn1.ObjectIdentifier) (pkix.Extension, error) {
}
var err error
ext.Value, err = asn1.Marshal(policies)
- if err != nil {
- return ext, err
- }
- return ext, nil
+ return ext, err
}
func buildCSRExtensions(template *CertificateRequest) ([]pkix.Extension, error) {
})
}
- if template.KeyUsage != 0 &&
- !oidInExtensions(oidExtensionKeyUsage, template.ExtraExtensions) {
- ext, err := marshalKeyUsage(template.KeyUsage)
- if err != nil {
- return nil, err
- }
- ret = append(ret, ext)
- }
-
- if (len(template.ExtKeyUsage) > 0 || len(template.UnknownExtKeyUsage) > 0) &&
- !oidInExtensions(oidExtensionExtendedKeyUsage, template.ExtraExtensions) {
- ext, err := marshalExtKeyUsage(template.ExtKeyUsage, template.UnknownExtKeyUsage)
- if err != nil {
- return nil, err
- }
- ret = append(ret, ext)
- }
-
- if template.BasicConstraintsValid && !oidInExtensions(oidExtensionBasicConstraints, template.ExtraExtensions) {
- ext, err := marshalBasicConstraints(template.IsCA, template.MaxPathLen, template.MaxPathLenZero)
- if err != nil {
- return nil, err
- }
- ret = append(ret, ext)
- }
-
- if len(template.SubjectKeyId) > 0 && !oidInExtensions(oidExtensionSubjectKeyId, template.ExtraExtensions) {
- skidBytes, err := asn1.Marshal(template.SubjectKeyId)
- if err != nil {
- return nil, err
- }
- ret = append(ret, pkix.Extension{Id: oidExtensionSubjectKeyId, Value: skidBytes})
- }
-
- if len(template.PolicyIdentifiers) > 0 &&
- !oidInExtensions(oidExtensionCertificatePolicies, template.ExtraExtensions) {
- ext, err := marshalCertificatePolicies(template.PolicyIdentifiers)
- if err != nil {
- return nil, err
- }
- ret = append(ret, ext)
- }
-
return append(ret, template.ExtraExtensions...), nil
}
// signingParamsForPublicKey returns the parameters to use for signing with
// priv. If requestedSigAlgo is not zero then it overrides the default
// signature algorithm.
-func signingParamsForPublicKey(pub interface{}, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
+func signingParamsForPublicKey(pub any, requestedSigAlgo SignatureAlgorithm) (hashFunc crypto.Hash, sigAlgo pkix.AlgorithmIdentifier, err error) {
var pubType PublicKeyAlgorithm
switch pub := pub.(type) {
pubType = Ed25519
sigAlgo.Algorithm = oidSignatureEd25519
+ case *gost3410.PublicKey:
+ pubType = GOST
+ switch pub.C.PointSize() {
+ case 256 / 8:
+ hashFunc = crypto.GOSTR34112012256
+ sigAlgo.Algorithm = oidTc26Gost341012256Signature
+ case 512 / 8:
+ hashFunc = crypto.GOSTR34112012512
+ sigAlgo.Algorithm = oidTc26Gost341012512Signature
+ }
+
default:
- err = errors.New("x509: only RSA, ECDSA and Ed25519 keys supported")
+ err = errors.New("x509: only RSA, ECDSA, Ed25519 and GOST keys supported")
}
if err != nil {
err = errors.New("x509: cannot sign with hash function requested")
return
}
+ if hashFunc == crypto.MD5 {
+ err = errors.New("x509: signing with MD5 is not supported")
+ return
+ }
if requestedSigAlgo.isRSAPSS() {
sigAlgo.Parameters = hashToPSSParameters[hashFunc]
}
// just an empty SEQUENCE.
var emptyASN1Subject = []byte{0x30, 0}
-// CreateCertificate creates a new X.509v3 certificate based on a template.
-// The following members of template are used:
+// 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
-// - SerialNumber
-// - SignatureAlgorithm
-// - Subject
-// - SubjectKeyId
-// - URIs
-// - UnknownExtKeyUsage
+// - 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
+// - 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
-// signee and priv is the private key of the signer.
+// certificate to be generated and priv is the private key of the signer.
//
// The returned slice is the certificate in DER encoding.
//
//
// If SubjectKeyId from template is empty and the template is a CA, SubjectKeyId
// will be generated from the hash of the public key.
-func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv interface{}) (cert []byte, err error) {
+func CreateCertificate(rand io.Reader, template, parent *Certificate, pub, priv any) ([]byte, error) {
key, ok := priv.(crypto.Signer)
if !ok {
return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
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 template.SerialNumber.Sign() == -1 {
+ return nil, errors.New("x509: serial number must be positive")
+ }
+
if template.BasicConstraintsValid && !template.IsCA && template.MaxPathLen != -1 && (template.MaxPathLen != 0 || template.MaxPathLenZero) {
return nil, errors.New("x509: only CAs are allowed to specify MaxPathLen")
}
if err != nil {
return nil, err
}
+ if getPublicKeyAlgorithmFromOID(publicKeyAlgorithm.Algorithm) == UnknownPublicKeyAlgorithm {
+ return nil, fmt.Errorf("x509: unsupported public key type: %T", pub)
+ }
asn1Issuer, err := subjectBytes(parent)
if err != nil {
- return
+ return nil, err
}
asn1Subject, err := subjectBytes(template)
if err != nil {
- return
+ return nil, err
}
authorityKeyId := template.AuthorityKeyId
subjectKeyId = h[:]
}
+ // Check that the signer's public key matches the private key, if available.
+ type privateKey interface {
+ Equal(crypto.PublicKey) bool
+ }
+ if privPub, ok := key.Public().(privateKey); !ok {
+ return nil, errors.New("x509: internal error: supported public key does not implement Equal")
+ } else if parent.PublicKey != nil && !privPub.Equal(parent.PublicKey) {
+ return nil, errors.New("x509: provided PrivateKey doesn't match parent's PublicKey")
+ }
+
extensions, err := buildCertExtensions(template, bytes.Equal(asn1Subject, emptyASN1Subject), authorityKeyId, subjectKeyId)
if err != nil {
- return
+ return nil, err
}
encodedPublicKey := asn1.BitString{BitLength: len(publicKeyBytes) * 8, Bytes: publicKeyBytes}
tbsCertContents, err := asn1.Marshal(c)
if err != nil {
- return
+ return nil, err
}
c.Raw = tbsCertContents
var signature []byte
signature, err = key.Sign(rand, signed, signerOpts)
if err != nil {
- return
+ return nil, err
}
signedCert, err := asn1.Marshal(certificate{
- nil,
c,
signatureAlgorithm,
asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
}
// Check the signature to ensure the crypto.Signer behaved correctly.
- // We skip this check if the signature algorithm is MD5WithRSA as we
- // only support this algorithm for signing, and not verification.
- if sigAlg := getSignatureAlgorithmFromAI(signatureAlgorithm); sigAlg != MD5WithRSA {
- if err := checkSignature(sigAlg, c.Raw, signature, key.Public()); err != nil {
- return nil, fmt.Errorf("x509: signature over certificate returned by signer is invalid: %w", err)
- }
+ if err := checkSignature(getSignatureAlgorithmFromAI(signatureAlgorithm), c.Raw, signature, key.Public(), true); err != nil {
+ return nil, fmt.Errorf("x509: signature over certificate returned by signer is invalid: %w", err)
}
return signedCert, nil
// 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 ParseCRL(crlBytes []byte) (*pkix.CertificateList, error) {
if bytes.HasPrefix(crlBytes, pemCRLPrefix) {
block, _ := pem.Decode(crlBytes)
}
// ParseDERCRL parses a DER encoded CRL from the given bytes.
+//
+// Deprecated: Use ParseRevocationList instead.
func ParseDERCRL(derBytes []byte) (*pkix.CertificateList, error) {
certList := new(pkix.CertificateList)
if rest, err := asn1.Unmarshal(derBytes, certList); err != nil {
// CreateCRL returns a DER encoded CRL, signed by this Certificate, that
// contains the given list of revoked certificates.
//
-// Note: this method does not generate an RFC 5280 conformant X.509 v2 CRL.
+// Deprecated: this method does not generate an RFC 5280 conformant X.509 v2 CRL.
// To generate a standards compliant CRL, use CreateRevocationList instead.
-func (c *Certificate) CreateCRL(rand io.Reader, priv interface{}, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) {
+func (c *Certificate) CreateCRL(rand io.Reader, priv any, revokedCerts []pkix.RevokedCertificate, now, expiry time.Time) (crlBytes []byte, err error) {
key, ok := priv.(crypto.Signer)
if !ok {
return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
Version int
Signature []byte
SignatureAlgorithm SignatureAlgorithm
- KeyUsage KeyUsage
PublicKeyAlgorithm PublicKeyAlgorithm
- PublicKey interface{}
+ PublicKey any
Subject pkix.Name
EmailAddresses []string
IPAddresses []net.IP
URIs []*url.URL
-
- 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
-
- PolicyIdentifiers []asn1.ObjectIdentifier
}
// These structures reflect the ASN.1 structure of X.509 certificate
}
var ret []pkix.Extension
+ requestedExts := make(map[string]bool)
for _, rawAttr := range rawAttributes {
var attr pkcs10Attribute
if rest, err := asn1.Unmarshal(rawAttr.FullBytes, &attr); err != nil || len(rest) != 0 || len(attr.Values) == 0 {
if _, err := asn1.Unmarshal(attr.Values[0].FullBytes, &extensions); err != nil {
return nil, err
}
+ for _, ext := range extensions {
+ oidStr := ext.Id.String()
+ if requestedExts[oidStr] {
+ return nil, errors.New("x509: certificate request contains duplicate requested extensions")
+ }
+ requestedExts[oidStr] = true
+ }
ret = append(ret, extensions...)
}
// CreateCertificateRequest creates a new certificate request based on a
// template. The following members of template are used:
//
-// - SignatureAlgorithm
-// - Subject
-// - DNSNames
-// - EmailAddresses
-// - IPAddresses
-// - URIs
-// - KeyUsage
-// - ExtKeyUsage
-// - UnknownExtKeyUsage
-// - BasicConstraintsValid
-// - IsCA
-// - MaxPathLen
-// - MaxPathLenZero
-// - SubjectKeyId
-// - PolicyIdentifiers
-// - ExtraExtensions
-// - Attributes (deprecated)
+// - 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
// ed25519.PrivateKey satisfies this.)
//
// The returned slice is the certificate request in DER encoding.
-func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv interface{}) (csr []byte, err error) {
+func CreateCertificateRequest(rand io.Reader, template *CertificateRequest, priv any) (csr []byte, err error) {
key, ok := priv.(crypto.Signer)
if !ok {
return nil, errors.New("x509: certificate private key does not implement crypto.Signer")
}
var err error
- out.PublicKey, err = parsePublicKey(out.PublicKeyAlgorithm, &in.TBSCSR.PublicKey)
- if err != nil {
- return nil, err
+ if out.PublicKeyAlgorithm != UnknownPublicKeyAlgorithm {
+ out.PublicKey, err = parsePublicKey(&in.TBSCSR.PublicKey)
+ if err != nil {
+ return nil, err
+ }
}
var subject pkix.RDNSequence
if err != nil {
return nil, err
}
- case extension.Id.Equal(oidExtensionKeyUsage):
- out.KeyUsage, err = parseKeyUsageExtension(extension.Value)
- case extension.Id.Equal(oidExtensionExtendedKeyUsage):
- out.ExtKeyUsage, out.UnknownExtKeyUsage, err = parseExtKeyUsageExtension(extension.Value)
- if err != nil {
- return nil, err
- }
- case extension.Id.Equal(oidExtensionBasicConstraints):
- out.IsCA, out.MaxPathLen, err = parseBasicConstraintsExtension(extension.Value)
- if err != nil {
- return nil, err
- }
- out.BasicConstraintsValid = true
- out.MaxPathLenZero = out.MaxPathLen == 0
- case extension.Id.Equal(oidExtensionSubjectKeyId):
- out.SubjectKeyId, err = parseSubjectKeyIdExtension(extension.Value)
- if err != nil {
- return nil, err
- }
- case extension.Id.Equal(oidExtensionCertificatePolicies):
- out.PolicyIdentifiers, err = parseCertificatePoliciesExtension(extension.Value)
- if err != nil {
- return nil, err
- }
}
}
// CheckSignature reports whether the signature on c is valid.
func (c *CertificateRequest) CheckSignature() error {
- return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey)
+ return checkSignature(c.SignatureAlgorithm, c.RawTBSCertificateRequest, c.Signature, c.PublicKey, true)
}
// RevocationList contains the fields used to create an X.509 v2 Certificate
// Revocation list with CreateRevocationList.
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.
// 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.
+ // 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
// 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.
//
if err != nil {
return nil, err
}
+
+ if numBytes := template.Number.Bytes(); len(numBytes) > 20 || (len(numBytes) == 20 && numBytes[0]&0x80 != 0) {
+ return nil, errors.New("x509: CRL number exceeds 20 octets")
+ }
crlNum, err := asn1.Marshal(template.Number)
if err != nil {
return nil, err
}
- tbsCertList := pkix.TBSCertificateList{
+ // Correctly use the issuer's subject sequence if one is specified.
+ issuerSubject, err := subjectBytes(issuer)
+ if err != nil {
+ return nil, err
+ }
+
+ tbsCertList := tbsCertificateList{
Version: 1, // v2
Signature: signatureAlgorithm,
- Issuer: issuer.Subject.ToRDNSequence(),
+ Issuer: asn1.RawValue{FullBytes: issuerSubject},
ThisUpdate: template.ThisUpdate.UTC(),
NextUpdate: template.NextUpdate.UTC(),
Extensions: []pkix.Extension{
return nil, err
}
+ // Optimization to only marshal this struct once, when signing and
+ // then embedding in certificateList below.
+ tbsCertList.Raw = tbsCertListContents
+
input := tbsCertListContents
if hashFunc != 0 {
h := hashFunc.New()
return nil, err
}
- return asn1.Marshal(pkix.CertificateList{
+ return asn1.Marshal(certificateList{
TBSCertList: tbsCertList,
SignatureAlgorithm: signatureAlgorithm,
SignatureValue: asn1.BitString{Bytes: signature, BitLength: len(signature) * 8},
})
}
+
+// CheckSignatureFrom verifies that the signature on rl is a valid signature
+// from issuer.
+func (rl *RevocationList) CheckSignatureFrom(parent *Certificate) error {
+ if parent.Version == 3 && !parent.BasicConstraintsValid ||
+ parent.BasicConstraintsValid && !parent.IsCA {
+ return ConstraintViolationError{}
+ }
+
+ if parent.KeyUsage != 0 && parent.KeyUsage&KeyUsageCRLSign == 0 {
+ return ConstraintViolationError{}
+ }
+
+ if parent.PublicKeyAlgorithm == UnknownPublicKeyAlgorithm {
+ return ErrUnsupportedAlgorithm
+ }
+
+ return parent.CheckSignature(rl.SignatureAlgorithm, rl.RawTBSRevocationList, rl.Signature)
+}