// 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/ecdh"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
_ "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 any, err error) {
} 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 any) (publicKeyBytes []byte, publicKeyAlgorithm pkix.AlgorithmIdentifier, err error) {
// 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 any) ([]byte, 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 {
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 {
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
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
}
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
// involves algorithms that are not currently implemented.
var ErrUnsupportedAlgorithm = errors.New("x509: cannot verify signature: algorithm unimplemented")
-// debugAllowSHA1 allows SHA-1 signatures. See issue 41682.
-var debugAllowSHA1 = godebug.Get("x509sha1") == "1"
-
// 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 Go 1.19.
+// be removed in a future release.
type InsecureAlgorithmError SignatureAlgorithm
func (e InsecureAlgorithmError) Error() string {
return oidInExtensions(oidExtensionSubjectAltName, c.Extensions)
}
-// CheckSignatureFrom verifies that the signature on c is a valid signature
-// from parent. SHA1WithRSA and ECDSAWithSHA1 signatures are not supported.
+// 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 checkSignature(c.SignatureAlgorithm, c.RawTBSCertificate, c.Signature, parent.PublicKey, debugAllowSHA1)
+ 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, true)
}
return fmt.Errorf("x509: signature algorithm specifies an %s public key, but have public key of type %T", expectedPubKeyAlgo.String(), pubKey)
}
+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, allowSHA1 bool) (err error) {
case crypto.MD5:
return InsecureAlgorithmError(algo)
case crypto.SHA1:
- if !allowSHA1 {
+ // SHA-1 signatures are mostly disabled. See go.dev/issue/41682.
+ if !allowSHA1 && x509sha1.Value() != "1" {
return InsecureAlgorithmError(algo)
}
fallthrough
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
}
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 {
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]
}
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 {
}
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.
- sigAlg := getSignatureAlgorithmFromAI(signatureAlgorithm)
- switch sigAlg {
- case MD5WithRSA:
- // We skip the check if the signature algorithm is only supported for
- // signing, not verification.
- default:
- if err := checkSignature(sigAlg, c.Raw, signature, key.Public(), true); 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
}
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...)
}
}
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
// RevocationList contains the fields used to create an X.509 v2 Certificate
// Revocation list with CreateRevocationList.
type RevocationList struct {
- Raw []byte
+ // 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 []byte
-
- Issuer pkix.Name
+ // 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
// 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
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},