package x509
import (
"bytes"
"crypto"
"crypto/ecdh"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
"crypto/sha1"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"errors"
"fmt"
"internal/godebug"
"io"
"math/big"
"net"
"net/url"
"strconv"
"time"
"unicode"
_ "crypto/sha1"
_ "crypto/sha256"
_ "crypto/sha512"
"golang.org/x/crypto/cryptobyte"
cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
)
type pkixPublicKey struct {
Algo pkix .AlgorithmIdentifier
BitString asn1 .BitString
}
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 {
return nil , errors .New ("x509: failed to parse public key (use ParsePKCS1PublicKey instead for this key format)" )
}
return nil , err
} else if len (rest ) != 0 {
return nil , errors .New ("x509: trailing data after ASN.1 of public-key" )
}
return parsePublicKey (&pki )
}
func marshalPublicKey (pub any ) (publicKeyBytes []byte , publicKeyAlgorithm pkix .AlgorithmIdentifier , err error ) {
switch pub := pub .(type ) {
case *rsa .PublicKey :
publicKeyBytes , err = asn1 .Marshal (pkcs1PublicKey {
N : pub .N ,
E : pub .E ,
})
if err != nil {
return nil , pkix .AlgorithmIdentifier {}, err
}
publicKeyAlgorithm .Algorithm = oidPublicKeyRSA
publicKeyAlgorithm .Parameters = asn1 .NullRawValue
case *ecdsa .PublicKey :
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 )
if err != nil {
return
}
publicKeyAlgorithm .Parameters .FullBytes = paramBytes
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
}
default :
return nil , pkix .AlgorithmIdentifier {}, fmt .Errorf ("x509: unsupported public key type: %T" , pub )
}
return publicKeyBytes , publicKeyAlgorithm , nil
}
func MarshalPKIXPublicKey (pub any ) ([]byte , error ) {
var publicKeyBytes []byte
var publicKeyAlgorithm pkix .AlgorithmIdentifier
var err error
if publicKeyBytes , publicKeyAlgorithm , err = marshalPublicKey (pub ); err != nil {
return nil , err
}
pkix := pkixPublicKey {
Algo : publicKeyAlgorithm ,
BitString : asn1 .BitString {
Bytes : publicKeyBytes ,
BitLength : 8 * len (publicKeyBytes ),
},
}
ret , _ := asn1 .Marshal (pkix )
return ret , nil
}
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
}
type authKeyId struct {
Id []byte `asn1:"optional,tag:0"`
}
type SignatureAlgorithm int
const (
UnknownSignatureAlgorithm SignatureAlgorithm = iota
MD2WithRSA
MD5WithRSA
SHA1WithRSA
SHA256WithRSA
SHA384WithRSA
SHA512WithRSA
DSAWithSHA1
DSAWithSHA256
ECDSAWithSHA1
ECDSAWithSHA256
ECDSAWithSHA384
ECDSAWithSHA512
SHA256WithRSAPSS
SHA384WithRSAPSS
SHA512WithRSAPSS
PureEd25519
)
func (algo SignatureAlgorithm ) isRSAPSS () bool {
switch algo {
case SHA256WithRSAPSS , SHA384WithRSAPSS , SHA512WithRSAPSS :
return true
default :
return false
}
}
func (algo SignatureAlgorithm ) String () string {
for _ , details := range signatureAlgorithmDetails {
if details .algo == algo {
return details .name
}
}
return strconv .Itoa (int (algo ))
}
type PublicKeyAlgorithm int
const (
UnknownPublicKeyAlgorithm PublicKeyAlgorithm = iota
RSA
DSA
ECDSA
Ed25519
)
var publicKeyAlgoName = [...]string {
RSA : "RSA" ,
DSA : "DSA" ,
ECDSA : "ECDSA" ,
Ed25519 : "Ed25519" ,
}
func (algo PublicKeyAlgorithm ) String () string {
if 0 < algo && int (algo ) < len (publicKeyAlgoName ) {
return publicKeyAlgoName [algo ]
}
return strconv .Itoa (int (algo ))
}
var (
oidSignatureMD2WithRSA = asn1 .ObjectIdentifier {1 , 2 , 840 , 113549 , 1 , 1 , 2 }
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 = asn1 .ObjectIdentifier {1 , 3 , 14 , 3 , 2 , 29 }
)
var signatureAlgorithmDetails = []struct {
algo SignatureAlgorithm
name string
oid asn1 .ObjectIdentifier
pubKeyAlgo PublicKeyAlgorithm
hash crypto .Hash
}{
{MD2WithRSA , "MD2-RSA" , oidSignatureMD2WithRSA , RSA , crypto .Hash (0 ) },
{MD5WithRSA , "MD5-RSA" , oidSignatureMD5WithRSA , RSA , crypto .MD5 },
{SHA1WithRSA , "SHA1-RSA" , oidSignatureSHA1WithRSA , RSA , crypto .SHA1 },
{SHA1WithRSA , "SHA1-RSA" , oidISOSignatureSHA1WithRSA , RSA , crypto .SHA1 },
{SHA256WithRSA , "SHA256-RSA" , oidSignatureSHA256WithRSA , RSA , crypto .SHA256 },
{SHA384WithRSA , "SHA384-RSA" , oidSignatureSHA384WithRSA , RSA , crypto .SHA384 },
{SHA512WithRSA , "SHA512-RSA" , oidSignatureSHA512WithRSA , RSA , crypto .SHA512 },
{SHA256WithRSAPSS , "SHA256-RSAPSS" , oidSignatureRSAPSS , RSA , crypto .SHA256 },
{SHA384WithRSAPSS , "SHA384-RSAPSS" , oidSignatureRSAPSS , RSA , crypto .SHA384 },
{SHA512WithRSAPSS , "SHA512-RSAPSS" , oidSignatureRSAPSS , RSA , crypto .SHA512 },
{DSAWithSHA1 , "DSA-SHA1" , oidSignatureDSAWithSHA1 , DSA , crypto .SHA1 },
{DSAWithSHA256 , "DSA-SHA256" , oidSignatureDSAWithSHA256 , DSA , crypto .SHA256 },
{ECDSAWithSHA1 , "ECDSA-SHA1" , oidSignatureECDSAWithSHA1 , ECDSA , crypto .SHA1 },
{ECDSAWithSHA256 , "ECDSA-SHA256" , oidSignatureECDSAWithSHA256 , ECDSA , crypto .SHA256 },
{ECDSAWithSHA384 , "ECDSA-SHA384" , oidSignatureECDSAWithSHA384 , ECDSA , crypto .SHA384 },
{ECDSAWithSHA512 , "ECDSA-SHA512" , oidSignatureECDSAWithSHA512 , ECDSA , crypto .SHA512 },
{PureEd25519 , "Ed25519" , oidSignatureEd25519 , Ed25519 , crypto .Hash (0 ) },
}
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 }},
crypto .SHA512 : 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 }},
}
type pssParameters struct {
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 (ai pkix .AlgorithmIdentifier ) SignatureAlgorithm {
if ai .Algorithm .Equal (oidSignatureEd25519 ) {
if len (ai .Parameters .FullBytes ) != 0 {
return UnknownSignatureAlgorithm
}
}
if !ai .Algorithm .Equal (oidSignatureRSAPSS ) {
for _ , details := range signatureAlgorithmDetails {
if ai .Algorithm .Equal (details .oid ) {
return details .algo
}
}
return UnknownSignatureAlgorithm
}
var params pssParameters
if _ , err := asn1 .Unmarshal (ai .Parameters .FullBytes , ¶ms ); err != nil {
return UnknownSignatureAlgorithm
}
var mgf1HashFunc pkix .AlgorithmIdentifier
if _ , err := asn1 .Unmarshal (params .MGF .Parameters .FullBytes , &mgf1HashFunc ); err != nil {
return UnknownSignatureAlgorithm
}
if (len (params .Hash .Parameters .FullBytes ) != 0 && !bytes .Equal (params .Hash .Parameters .FullBytes , asn1 .NullBytes )) ||
!params .MGF .Algorithm .Equal (oidMGF1 ) ||
!mgf1HashFunc .Algorithm .Equal (params .Hash .Algorithm ) ||
(len (mgf1HashFunc .Parameters .FullBytes ) != 0 && !bytes .Equal (mgf1HashFunc .Parameters .FullBytes , asn1 .NullBytes )) ||
params .TrailerField != 1 {
return UnknownSignatureAlgorithm
}
switch {
case params .Hash .Algorithm .Equal (oidSHA256 ) && params .SaltLength == 32 :
return SHA256WithRSAPSS
case params .Hash .Algorithm .Equal (oidSHA384 ) && params .SaltLength == 48 :
return SHA384WithRSAPSS
case params .Hash .Algorithm .Equal (oidSHA512 ) && params .SaltLength == 64 :
return SHA512WithRSAPSS
}
return UnknownSignatureAlgorithm
}
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 }
oidPublicKeyX25519 = asn1 .ObjectIdentifier {1 , 3 , 101 , 110 }
oidPublicKeyEd25519 = asn1 .ObjectIdentifier {1 , 3 , 101 , 112 }
)
func getPublicKeyAlgorithmFromOID (oid asn1 .ObjectIdentifier ) PublicKeyAlgorithm {
switch {
case oid .Equal (oidPublicKeyRSA ):
return RSA
case oid .Equal (oidPublicKeyDSA ):
return DSA
case oid .Equal (oidPublicKeyECDSA ):
return ECDSA
case oid .Equal (oidPublicKeyEd25519 ):
return Ed25519
}
return UnknownPublicKeyAlgorithm
}
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 (oid asn1 .ObjectIdentifier ) elliptic .Curve {
switch {
case oid .Equal (oidNamedCurveP224 ):
return elliptic .P224 ()
case oid .Equal (oidNamedCurveP256 ):
return elliptic .P256 ()
case oid .Equal (oidNamedCurveP384 ):
return elliptic .P384 ()
case oid .Equal (oidNamedCurveP521 ):
return elliptic .P521 ()
}
return nil
}
func oidFromNamedCurve (curve elliptic .Curve ) (asn1 .ObjectIdentifier , bool ) {
switch curve {
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 (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
}
type KeyUsage int
const (
KeyUsageDigitalSignature KeyUsage = 1 << iota
KeyUsageContentCommitment
KeyUsageKeyEncipherment
KeyUsageDataEncipherment
KeyUsageKeyAgreement
KeyUsageCertSign
KeyUsageCRLSign
KeyUsageEncipherOnly
KeyUsageDecipherOnly
)
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 }
)
type ExtKeyUsage int
const (
ExtKeyUsageAny ExtKeyUsage = iota
ExtKeyUsageServerAuth
ExtKeyUsageClientAuth
ExtKeyUsageCodeSigning
ExtKeyUsageEmailProtection
ExtKeyUsageIPSECEndSystem
ExtKeyUsageIPSECTunnel
ExtKeyUsageIPSECUser
ExtKeyUsageTimeStamping
ExtKeyUsageOCSPSigning
ExtKeyUsageMicrosoftServerGatedCrypto
ExtKeyUsageNetscapeServerGatedCrypto
ExtKeyUsageMicrosoftCommercialCodeSigning
ExtKeyUsageMicrosoftKernelCodeSigning
)
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 (oid asn1 .ObjectIdentifier ) (eku ExtKeyUsage , ok bool ) {
for _ , pair := range extKeyUsageOIDs {
if oid .Equal (pair .oid ) {
return pair .extKeyUsage , true
}
}
return
}
func oidFromExtKeyUsage (eku ExtKeyUsage ) (oid asn1 .ObjectIdentifier , ok bool ) {
for _ , pair := range extKeyUsageOIDs {
if eku == pair .extKeyUsage {
return pair .oid , true
}
}
return
}
type Certificate struct {
Raw []byte
RawTBSCertificate []byte
RawSubjectPublicKeyInfo []byte
RawSubject []byte
RawIssuer []byte
Signature []byte
SignatureAlgorithm SignatureAlgorithm
PublicKeyAlgorithm PublicKeyAlgorithm
PublicKey any
Version int
SerialNumber *big .Int
Issuer pkix .Name
Subject pkix .Name
NotBefore , NotAfter time .Time
KeyUsage KeyUsage
Extensions []pkix .Extension
ExtraExtensions []pkix .Extension
UnhandledCriticalExtensions []asn1 .ObjectIdentifier
ExtKeyUsage []ExtKeyUsage
UnknownExtKeyUsage []asn1 .ObjectIdentifier
BasicConstraintsValid bool
IsCA bool
MaxPathLen int
MaxPathLenZero bool
SubjectKeyId []byte
AuthorityKeyId []byte
OCSPServer []string
IssuingCertificateURL []string
DNSNames []string
EmailAddresses []string
IPAddresses []net .IP
URIs []*url .URL
PermittedDNSDomainsCritical bool
PermittedDNSDomains []string
ExcludedDNSDomains []string
PermittedIPRanges []*net .IPNet
ExcludedIPRanges []*net .IPNet
PermittedEmailAddresses []string
ExcludedEmailAddresses []string
PermittedURIDomains []string
ExcludedURIDomains []string
CRLDistributionPoints []string
PolicyIdentifiers []asn1 .ObjectIdentifier
}
var ErrUnsupportedAlgorithm = errors .New ("x509: cannot verify signature: algorithm unimplemented" )
type InsecureAlgorithmError SignatureAlgorithm
func (e InsecureAlgorithmError ) Error () string {
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
}
type ConstraintViolationError struct {}
func (ConstraintViolationError ) Error () string {
return "x509: invalid signature: parent certificate cannot sign this kind of certificate"
}
func (c *Certificate ) Equal (other *Certificate ) bool {
if c == nil || other == nil {
return c == other
}
return bytes .Equal (c .Raw , other .Raw )
}
func (c *Certificate ) hasSANExtension () bool {
return oidInExtensions (oidExtensionSubjectAltName , c .Extensions )
}
func (c *Certificate ) CheckSignatureFrom (parent *Certificate ) error {
if parent .Version == 3 && !parent .BasicConstraintsValid ||
parent .BasicConstraintsValid && !parent .IsCA {
return ConstraintViolationError {}
}
if parent .KeyUsage != 0 && parent .KeyUsage &KeyUsageCertSign == 0 {
return ConstraintViolationError {}
}
if parent .PublicKeyAlgorithm == UnknownPublicKeyAlgorithm {
return ErrUnsupportedAlgorithm
}
return checkSignature (c .SignatureAlgorithm , c .RawTBSCertificate , c .Signature , parent .PublicKey , false )
}
func (c *Certificate ) CheckSignature (algo SignatureAlgorithm , signed , signature []byte ) error {
return checkSignature (algo , signed , signature , c .PublicKey , true )
}
func (c *Certificate ) hasNameConstraints () bool {
return oidInExtensions (oidExtensionNameConstraints , c .Extensions )
}
func (c *Certificate ) getSANExtension () []byte {
for _ , e := range c .Extensions {
if e .Id .Equal (oidExtensionSubjectAltName ) {
return e .Value
}
}
return nil
}
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 )
}
var x509sha1 = godebug .New ("x509sha1" )
func checkSignature (algo SignatureAlgorithm , signed , signature []byte , publicKey crypto .PublicKey , allowSHA1 bool ) (err error ) {
var hashType crypto .Hash
var pubKeyAlgo PublicKeyAlgorithm
for _ , details := range signatureAlgorithmDetails {
if details .algo == algo {
hashType = details .hash
pubKeyAlgo = details .pubKeyAlgo
}
}
switch hashType {
case crypto .Hash (0 ):
if pubKeyAlgo != Ed25519 {
return ErrUnsupportedAlgorithm
}
case crypto .MD5 :
return InsecureAlgorithmError (algo )
case crypto .SHA1 :
if !allowSHA1 {
if x509sha1 .Value () != "1" {
return InsecureAlgorithmError (algo )
}
x509sha1 .IncNonDefault ()
}
fallthrough
default :
if !hashType .Available () {
return ErrUnsupportedAlgorithm
}
h := hashType .New ()
h .Write (signed )
signed = h .Sum (nil )
}
switch pub := publicKey .(type ) {
case *rsa .PublicKey :
if pubKeyAlgo != RSA {
return signaturePublicKeyAlgoMismatchError (pubKeyAlgo , pub )
}
if algo .isRSAPSS () {
return rsa .VerifyPSS (pub , hashType , signed , signature , &rsa .PSSOptions {SaltLength : rsa .PSSSaltLengthEqualsHash })
} else {
return rsa .VerifyPKCS1v15 (pub , hashType , signed , signature )
}
case *ecdsa .PublicKey :
if pubKeyAlgo != ECDSA {
return signaturePublicKeyAlgoMismatchError (pubKeyAlgo , pub )
}
if !ecdsa .VerifyASN1 (pub , signed , signature ) {
return errors .New ("x509: ECDSA verification failure" )
}
return
case ed25519 .PublicKey :
if pubKeyAlgo != Ed25519 {
return signaturePublicKeyAlgoMismatchError (pubKeyAlgo , pub )
}
if !ed25519 .Verify (pub , signed , signature ) {
return errors .New ("x509: Ed25519 verification failure" )
}
return
}
return ErrUnsupportedAlgorithm
}
func (c *Certificate ) CheckCRLSignature (crl *pkix .CertificateList ) error {
algo := getSignatureAlgorithmFromAI (crl .SignatureAlgorithm )
return c .CheckSignature (algo , crl .TBSCertList .Raw , crl .SignatureValue .RightAlign ())
}
type UnhandledCriticalExtension struct {}
func (h UnhandledCriticalExtension ) Error () string {
return "x509: unhandled critical extension"
}
type basicConstraints struct {
IsCA bool `asn1:"optional"`
MaxPathLen int `asn1:"optional,default:-1"`
}
type policyInformation struct {
Policy asn1 .ObjectIdentifier
}
const (
nameTypeEmail = 1
nameTypeDNS = 2
nameTypeURI = 6
nameTypeIP = 7
)
type authorityInfoAccess struct {
Method asn1 .ObjectIdentifier
Location asn1 .RawValue
}
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 (in byte ) byte {
b1 := in >>4 | in <<4
b2 := b1 >>2 &0x33 | b1 <<2 &0xcc
b3 := b2 >>1 &0x55 | b2 <<1 &0xaa
return b3
}
func asn1BitLength (bitString []byte ) int {
bitLen := len (bitString ) * 8
for i := range bitString {
b := bitString [len (bitString )-i -1 ]
for bit := uint (0 ); bit < 8 ; bit ++ {
if (b >>bit )&1 == 1 {
return bitLen
}
bitLen --
}
}
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 }
)
func oidInExtensions (oid asn1 .ObjectIdentifier , extensions []pkix .Extension ) bool {
for _ , e := range extensions {
if e .Id .Equal (oid ) {
return true
}
}
return false
}
func marshalSANs (dnsNames , emailAddresses []string , ipAddresses []net .IP , uris []*url .URL ) (derBytes []byte , err error ) {
var rawValues []asn1 .RawValue
for _ , name := range dnsNames {
if err := isIA5String (name ); err != nil {
return nil , err
}
rawValues = append (rawValues , asn1 .RawValue {Tag : nameTypeDNS , Class : 2 , Bytes : []byte (name )})
}
for _ , email := range emailAddresses {
if err := isIA5String (email ); err != nil {
return nil , err
}
rawValues = append (rawValues , asn1 .RawValue {Tag : nameTypeEmail , Class : 2 , Bytes : []byte (email )})
}
for _ , rawIP := range ipAddresses {
ip := rawIP .To4 ()
if ip == nil {
ip = rawIP
}
rawValues = append (rawValues , asn1 .RawValue {Tag : nameTypeIP , Class : 2 , Bytes : ip })
}
for _ , uri := range uris {
uriStr := uri .String ()
if err := isIA5String (uriStr ); err != nil {
return nil , err
}
rawValues = append (rawValues , asn1 .RawValue {Tag : nameTypeURI , Class : 2 , Bytes : []byte (uriStr )})
}
return asn1 .Marshal (rawValues )
}
func isIA5String (s string ) error {
for _ , r := range s {
if r > unicode .MaxASCII {
return fmt .Errorf ("x509: %q cannot be encoded as an IA5String" , s )
}
}
return nil
}
func buildCertExtensions (template *Certificate , subjectIsEmpty bool , authorityKeyId []byte , subjectKeyId []byte ) (ret []pkix .Extension , err error ) {
ret = make ([]pkix .Extension , 10 )
n := 0
if template .KeyUsage != 0 &&
!oidInExtensions (oidExtensionKeyUsage , template .ExtraExtensions ) {
ret [n ], err = marshalKeyUsage (template .KeyUsage )
if err != nil {
return nil , err
}
n ++
}
if (len (template .ExtKeyUsage ) > 0 || len (template .UnknownExtKeyUsage ) > 0 ) &&
!oidInExtensions (oidExtensionExtendedKeyUsage , template .ExtraExtensions ) {
ret [n ], err = marshalExtKeyUsage (template .ExtKeyUsage , template .UnknownExtKeyUsage )
if err != nil {
return nil , err
}
n ++
}
if template .BasicConstraintsValid && !oidInExtensions (oidExtensionBasicConstraints , template .ExtraExtensions ) {
ret [n ], err = marshalBasicConstraints (template .IsCA , template .MaxPathLen , template .MaxPathLenZero )
if err != nil {
return nil , err
}
n ++
}
if len (subjectKeyId ) > 0 && !oidInExtensions (oidExtensionSubjectKeyId , template .ExtraExtensions ) {
ret [n ].Id = oidExtensionSubjectKeyId
ret [n ].Value , err = asn1 .Marshal (subjectKeyId )
if err != nil {
return
}
n ++
}
if len (authorityKeyId ) > 0 && !oidInExtensions (oidExtensionAuthorityKeyId , template .ExtraExtensions ) {
ret [n ].Id = oidExtensionAuthorityKeyId
ret [n ].Value , err = asn1 .Marshal (authKeyId {authorityKeyId })
if err != nil {
return
}
n ++
}
if (len (template .OCSPServer ) > 0 || len (template .IssuingCertificateURL ) > 0 ) &&
!oidInExtensions (oidExtensionAuthorityInfoAccess , template .ExtraExtensions ) {
ret [n ].Id = oidExtensionAuthorityInfoAccess
var aiaValues []authorityInfoAccess
for _ , name := range template .OCSPServer {
aiaValues = append (aiaValues , authorityInfoAccess {
Method : oidAuthorityInfoAccessOcsp ,
Location : asn1 .RawValue {Tag : 6 , Class : 2 , Bytes : []byte (name )},
})
}
for _ , name := range template .IssuingCertificateURL {
aiaValues = append (aiaValues , authorityInfoAccess {
Method : oidAuthorityInfoAccessIssuers ,
Location : asn1 .RawValue {Tag : 6 , Class : 2 , Bytes : []byte (name )},
})
}
ret [n ].Value , err = asn1 .Marshal (aiaValues )
if err != nil {
return
}
n ++
}
if (len (template .DNSNames ) > 0 || len (template .EmailAddresses ) > 0 || len (template .IPAddresses ) > 0 || len (template .URIs ) > 0 ) &&
!oidInExtensions (oidExtensionSubjectAltName , template .ExtraExtensions ) {
ret [n ].Id = oidExtensionSubjectAltName
ret [n ].Critical = subjectIsEmpty
ret [n ].Value , err = marshalSANs (template .DNSNames , template .EmailAddresses , template .IPAddresses , template .URIs )
if err != nil {
return
}
n ++
}
if len (template .PolicyIdentifiers ) > 0 &&
!oidInExtensions (oidExtensionCertificatePolicies , template .ExtraExtensions ) {
ret [n ], err = marshalCertificatePolicies (template .PolicyIdentifiers )
if err != nil {
return nil , err
}
n ++
}
if (len (template .PermittedDNSDomains ) > 0 || len (template .ExcludedDNSDomains ) > 0 ||
len (template .PermittedIPRanges ) > 0 || len (template .ExcludedIPRanges ) > 0 ||
len (template .PermittedEmailAddresses ) > 0 || len (template .ExcludedEmailAddresses ) > 0 ||
len (template .PermittedURIDomains ) > 0 || len (template .ExcludedURIDomains ) > 0 ) &&
!oidInExtensions (oidExtensionNameConstraints , template .ExtraExtensions ) {
ret [n ].Id = oidExtensionNameConstraints
ret [n ].Critical = template .PermittedDNSDomainsCritical
ipAndMask := func (ipNet *net .IPNet ) []byte {
maskedIP := ipNet .IP .Mask (ipNet .Mask )
ipAndMask := make ([]byte , 0 , len (maskedIP )+len (ipNet .Mask ))
ipAndMask = append (ipAndMask , maskedIP ...)
ipAndMask = append (ipAndMask , ipNet .Mask ...)
return ipAndMask
}
serialiseConstraints := func (dns []string , ips []*net .IPNet , emails []string , uriDomains []string ) (der []byte , err error ) {
var b cryptobyte .Builder
for _ , name := range dns {
if err = isIA5String (name ); err != nil {
return nil , err
}
b .AddASN1 (cryptobyte_asn1 .SEQUENCE , func (b *cryptobyte .Builder ) {
b .AddASN1 (cryptobyte_asn1 .Tag (2 ).ContextSpecific (), func (b *cryptobyte .Builder ) {
b .AddBytes ([]byte (name ))
})
})
}
for _ , ipNet := range ips {
b .AddASN1 (cryptobyte_asn1 .SEQUENCE , func (b *cryptobyte .Builder ) {
b .AddASN1 (cryptobyte_asn1 .Tag (7 ).ContextSpecific (), func (b *cryptobyte .Builder ) {
b .AddBytes (ipAndMask (ipNet ))
})
})
}
for _ , email := range emails {
if err = isIA5String (email ); err != nil {
return nil , err
}
b .AddASN1 (cryptobyte_asn1 .SEQUENCE , func (b *cryptobyte .Builder ) {
b .AddASN1 (cryptobyte_asn1 .Tag (1 ).ContextSpecific (), func (b *cryptobyte .Builder ) {
b .AddBytes ([]byte (email ))
})
})
}
for _ , uriDomain := range uriDomains {
if err = isIA5String (uriDomain ); err != nil {
return nil , err
}
b .AddASN1 (cryptobyte_asn1 .SEQUENCE , func (b *cryptobyte .Builder ) {
b .AddASN1 (cryptobyte_asn1 .Tag (6 ).ContextSpecific (), func (b *cryptobyte .Builder ) {
b .AddBytes ([]byte (uriDomain ))
})
})
}
return b .Bytes ()
}
permitted , err := serialiseConstraints (template .PermittedDNSDomains , template .PermittedIPRanges , template .PermittedEmailAddresses , template .PermittedURIDomains )
if err != nil {
return nil , err
}
excluded , err := serialiseConstraints (template .ExcludedDNSDomains , template .ExcludedIPRanges , template .ExcludedEmailAddresses , template .ExcludedURIDomains )
if err != nil {
return nil , err
}
var b cryptobyte .Builder
b .AddASN1 (cryptobyte_asn1 .SEQUENCE , func (b *cryptobyte .Builder ) {
if len (permitted ) > 0 {
b .AddASN1 (cryptobyte_asn1 .Tag (0 ).ContextSpecific ().Constructed (), func (b *cryptobyte .Builder ) {
b .AddBytes (permitted )
})
}
if len (excluded ) > 0 {
b .AddASN1 (cryptobyte_asn1 .Tag (1 ).ContextSpecific ().Constructed (), func (b *cryptobyte .Builder ) {
b .AddBytes (excluded )
})
}
})
ret [n ].Value , err = b .Bytes ()
if err != nil {
return nil , err
}
n ++
}
if len (template .CRLDistributionPoints ) > 0 &&
!oidInExtensions (oidExtensionCRLDistributionPoints , template .ExtraExtensions ) {
ret [n ].Id = oidExtensionCRLDistributionPoints
var crlDp []distributionPoint
for _ , name := range template .CRLDistributionPoints {
dp := distributionPoint {
DistributionPoint : distributionPointName {
FullName : []asn1 .RawValue {
{Tag : 6 , Class : 2 , Bytes : []byte (name )},
},
},
}
crlDp = append (crlDp , dp )
}
ret [n ].Value , err = asn1 .Marshal (crlDp )
if err != nil {
return
}
n ++
}
return append (ret [:n ], template .ExtraExtensions ...), nil
}
func marshalKeyUsage (ku KeyUsage ) (pkix .Extension , error ) {
ext := pkix .Extension {Id : oidExtensionKeyUsage , Critical : true }
var a [2 ]byte
a [0 ] = reverseBitsInAByte (byte (ku ))
a [1 ] = reverseBitsInAByte (byte (ku >> 8 ))
l := 1
if a [1 ] != 0 {
l = 2
}
bitString := a [:l ]
var err error
ext .Value , err = asn1 .Marshal (asn1 .BitString {Bytes : bitString , BitLength : asn1BitLength (bitString )})
return ext , err
}
func marshalExtKeyUsage (extUsages []ExtKeyUsage , unknownUsages []asn1 .ObjectIdentifier ) (pkix .Extension , error ) {
ext := pkix .Extension {Id : oidExtensionExtendedKeyUsage }
oids := make ([]asn1 .ObjectIdentifier , len (extUsages )+len (unknownUsages ))
for i , u := range extUsages {
if oid , ok := oidFromExtKeyUsage (u ); ok {
oids [i ] = oid
} else {
return ext , errors .New ("x509: unknown extended key usage" )
}
}
copy (oids [len (extUsages ):], unknownUsages )
var err error
ext .Value , err = asn1 .Marshal (oids )
return ext , err
}
func marshalBasicConstraints (isCA bool , maxPathLen int , maxPathLenZero bool ) (pkix .Extension , error ) {
ext := pkix .Extension {Id : oidExtensionBasicConstraints , Critical : true }
if maxPathLen == 0 && !maxPathLenZero {
maxPathLen = -1
}
var err error
ext .Value , err = asn1 .Marshal (basicConstraints {isCA , maxPathLen })
return ext , err
}
func marshalCertificatePolicies (policyIdentifiers []asn1 .ObjectIdentifier ) (pkix .Extension , error ) {
ext := pkix .Extension {Id : oidExtensionCertificatePolicies }
policies := make ([]policyInformation , len (policyIdentifiers ))
for i , policy := range policyIdentifiers {
policies [i ].Policy = policy
}
var err error
ext .Value , err = asn1 .Marshal (policies )
return ext , err
}
func buildCSRExtensions (template *CertificateRequest ) ([]pkix .Extension , error ) {
var ret []pkix .Extension
if (len (template .DNSNames ) > 0 || len (template .EmailAddresses ) > 0 || len (template .IPAddresses ) > 0 || len (template .URIs ) > 0 ) &&
!oidInExtensions (oidExtensionSubjectAltName , template .ExtraExtensions ) {
sanBytes , err := marshalSANs (template .DNSNames , template .EmailAddresses , template .IPAddresses , template .URIs )
if err != nil {
return nil , err
}
ret = append (ret , pkix .Extension {
Id : oidExtensionSubjectAltName ,
Value : sanBytes ,
})
}
return append (ret , template .ExtraExtensions ...), nil
}
func subjectBytes (cert *Certificate ) ([]byte , error ) {
if len (cert .RawSubject ) > 0 {
return cert .RawSubject , nil
}
return asn1 .Marshal (cert .Subject .ToRDNSequence ())
}
func signingParamsForPublicKey (pub any , requestedSigAlgo SignatureAlgorithm ) (hashFunc crypto .Hash , sigAlgo pkix .AlgorithmIdentifier , err error ) {
var pubType PublicKeyAlgorithm
switch pub := pub .(type ) {
case *rsa .PublicKey :
pubType = RSA
hashFunc = crypto .SHA256
sigAlgo .Algorithm = oidSignatureSHA256WithRSA
sigAlgo .Parameters = asn1 .NullRawValue
case *ecdsa .PublicKey :
pubType = ECDSA
switch pub .Curve {
case elliptic .P224 (), elliptic .P256 ():
hashFunc = crypto .SHA256
sigAlgo .Algorithm = oidSignatureECDSAWithSHA256
case elliptic .P384 ():
hashFunc = crypto .SHA384
sigAlgo .Algorithm = oidSignatureECDSAWithSHA384
case elliptic .P521 ():
hashFunc = crypto .SHA512
sigAlgo .Algorithm = oidSignatureECDSAWithSHA512
default :
err = errors .New ("x509: unknown elliptic curve" )
}
case ed25519 .PublicKey :
pubType = Ed25519
sigAlgo .Algorithm = oidSignatureEd25519
default :
err = errors .New ("x509: only RSA, ECDSA and Ed25519 keys supported" )
}
if err != nil {
return
}
if requestedSigAlgo == 0 {
return
}
found := false
for _ , details := range signatureAlgorithmDetails {
if details .algo == requestedSigAlgo {
if details .pubKeyAlgo != pubType {
err = errors .New ("x509: requested SignatureAlgorithm does not match private key type" )
return
}
sigAlgo .Algorithm , hashFunc = details .oid , details .hash
if hashFunc == 0 && pubType != Ed25519 {
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 ]
}
found = true
break
}
}
if !found {
err = errors .New ("x509: unknown SignatureAlgorithm" )
}
return
}
var emptyASN1Subject = []byte {0x30 , 0 }
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" )
}
if template .SerialNumber == nil {
return nil , errors .New ("x509: no SerialNumber given" )
}
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" )
}
hashFunc , signatureAlgorithm , err := signingParamsForPublicKey (key .Public (), template .SignatureAlgorithm )
if err != nil {
return nil , err
}
publicKeyBytes , publicKeyAlgorithm , err := marshalPublicKey (pub )
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 nil , err
}
asn1Subject , err := subjectBytes (template )
if err != nil {
return nil , err
}
authorityKeyId := template .AuthorityKeyId
if !bytes .Equal (asn1Issuer , asn1Subject ) && len (parent .SubjectKeyId ) > 0 {
authorityKeyId = parent .SubjectKeyId
}
subjectKeyId := template .SubjectKeyId
if len (subjectKeyId ) == 0 && template .IsCA {
h := sha1 .Sum (publicKeyBytes )
subjectKeyId = h [:]
}
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 nil , err
}
encodedPublicKey := asn1 .BitString {BitLength : len (publicKeyBytes ) * 8 , Bytes : publicKeyBytes }
c := tbsCertificate {
Version : 2 ,
SerialNumber : template .SerialNumber ,
SignatureAlgorithm : signatureAlgorithm ,
Issuer : asn1 .RawValue {FullBytes : asn1Issuer },
Validity : validity {template .NotBefore .UTC (), template .NotAfter .UTC ()},
Subject : asn1 .RawValue {FullBytes : asn1Subject },
PublicKey : publicKeyInfo {nil , publicKeyAlgorithm , encodedPublicKey },
Extensions : extensions ,
}
tbsCertContents , err := asn1 .Marshal (c )
if err != nil {
return nil , err
}
c .Raw = tbsCertContents
signed := tbsCertContents
if hashFunc != 0 {
h := hashFunc .New ()
h .Write (signed )
signed = h .Sum (nil )
}
var signerOpts crypto .SignerOpts = hashFunc
if template .SignatureAlgorithm != 0 && template .SignatureAlgorithm .isRSAPSS () {
signerOpts = &rsa .PSSOptions {
SaltLength : rsa .PSSSaltLengthEqualsHash ,
Hash : hashFunc ,
}
}
var signature []byte
signature , err = key .Sign (rand , signed , signerOpts )
if err != nil {
return nil , err
}
signedCert , err := asn1 .Marshal (certificate {
c ,
signatureAlgorithm ,
asn1 .BitString {Bytes : signature , BitLength : len (signature ) * 8 },
})
if err != nil {
return nil , 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 pemCRLPrefix = []byte ("-----BEGIN X509 CRL" )
var pemType = "X509 CRL"
func ParseCRL (crlBytes []byte ) (*pkix .CertificateList , error ) {
if bytes .HasPrefix (crlBytes , pemCRLPrefix ) {
block , _ := pem .Decode (crlBytes )
if block != nil && block .Type == pemType {
crlBytes = block .Bytes
}
}
return ParseDERCRL (crlBytes )
}
func ParseDERCRL (derBytes []byte ) (*pkix .CertificateList , error ) {
certList := new (pkix .CertificateList )
if rest , err := asn1 .Unmarshal (derBytes , certList ); err != nil {
return nil , err
} else if len (rest ) != 0 {
return nil , errors .New ("x509: trailing data after CRL" )
}
return certList , nil
}
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" )
}
hashFunc , signatureAlgorithm , err := signingParamsForPublicKey (key .Public (), 0 )
if err != nil {
return nil , err
}
revokedCertsUTC := make ([]pkix .RevokedCertificate , len (revokedCerts ))
for i , rc := range revokedCerts {
rc .RevocationTime = rc .RevocationTime .UTC ()
revokedCertsUTC [i ] = rc
}
tbsCertList := pkix .TBSCertificateList {
Version : 1 ,
Signature : signatureAlgorithm ,
Issuer : c .Subject .ToRDNSequence (),
ThisUpdate : now .UTC (),
NextUpdate : expiry .UTC (),
RevokedCertificates : revokedCertsUTC ,
}
if len (c .SubjectKeyId ) > 0 {
var aki pkix .Extension
aki .Id = oidExtensionAuthorityKeyId
aki .Value , err = asn1 .Marshal (authKeyId {Id : c .SubjectKeyId })
if err != nil {
return
}
tbsCertList .Extensions = append (tbsCertList .Extensions , aki )
}
tbsCertListContents , err := asn1 .Marshal (tbsCertList )
if err != nil {
return
}
signed := tbsCertListContents
if hashFunc != 0 {
h := hashFunc .New ()
h .Write (signed )
signed = h .Sum (nil )
}
var signature []byte
signature , err = key .Sign (rand , signed , hashFunc )
if err != nil {
return
}
return asn1 .Marshal (pkix .CertificateList {
TBSCertList : tbsCertList ,
SignatureAlgorithm : signatureAlgorithm ,
SignatureValue : asn1 .BitString {Bytes : signature , BitLength : len (signature ) * 8 },
})
}
type CertificateRequest struct {
Raw []byte
RawTBSCertificateRequest []byte
RawSubjectPublicKeyInfo []byte
RawSubject []byte
Version int
Signature []byte
SignatureAlgorithm SignatureAlgorithm
PublicKeyAlgorithm PublicKeyAlgorithm
PublicKey any
Subject pkix .Name
Attributes []pkix .AttributeTypeAndValueSET
Extensions []pkix .Extension
ExtraExtensions []pkix .Extension
DNSNames []string
EmailAddresses []string
IPAddresses []net .IP
URIs []*url .URL
}
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
}
var oidExtensionRequest = asn1 .ObjectIdentifier {1 , 2 , 840 , 113549 , 1 , 9 , 14 }
func newRawAttributes (attributes []pkix .AttributeTypeAndValueSET ) ([]asn1 .RawValue , error ) {
var rawAttributes []asn1 .RawValue
b , err := asn1 .Marshal (attributes )
if err != nil {
return nil , err
}
rest , err := asn1 .Unmarshal (b , &rawAttributes )
if err != nil {
return nil , err
}
if len (rest ) != 0 {
return nil , errors .New ("x509: failed to unmarshal raw CSR Attributes" )
}
return rawAttributes , nil
}
func parseRawAttributes (rawAttributes []asn1 .RawValue ) []pkix .AttributeTypeAndValueSET {
var attributes []pkix .AttributeTypeAndValueSET
for _ , rawAttr := range rawAttributes {
var attr pkix .AttributeTypeAndValueSET
rest , err := asn1 .Unmarshal (rawAttr .FullBytes , &attr )
if err == nil && len (rest ) == 0 {
attributes = append (attributes , attr )
}
}
return attributes
}
func parseCSRExtensions (rawAttributes []asn1 .RawValue ) ([]pkix .Extension , error ) {
type pkcs10Attribute struct {
Id asn1 .ObjectIdentifier
Values []asn1 .RawValue `asn1:"set"`
}
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 {
continue
}
if !attr .Id .Equal (oidExtensionRequest ) {
continue
}
var extensions []pkix .Extension
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 ...)
}
return ret , nil
}
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 hashFunc crypto .Hash
var sigAlgo pkix .AlgorithmIdentifier
hashFunc , sigAlgo , err = signingParamsForPublicKey (key .Public (), template .SignatureAlgorithm )
if err != nil {
return nil , err
}
var publicKeyBytes []byte
var publicKeyAlgorithm pkix .AlgorithmIdentifier
publicKeyBytes , publicKeyAlgorithm , err = marshalPublicKey (key .Public ())
if err != nil {
return nil , err
}
extensions , err := buildCSRExtensions (template )
if err != nil {
return nil , err
}
attributes := make ([]pkix .AttributeTypeAndValueSET , 0 , len (template .Attributes ))
for _ , attr := range template .Attributes {
values := make ([][]pkix .AttributeTypeAndValue , len (attr .Value ))
copy (values , attr .Value )
attributes = append (attributes , pkix .AttributeTypeAndValueSET {
Type : attr .Type ,
Value : values ,
})
}
extensionsAppended := false
if len (extensions ) > 0 {
for _ , atvSet := range attributes {
if !atvSet .Type .Equal (oidExtensionRequest ) || len (atvSet .Value ) == 0 {
continue
}
specifiedExtensions := make (map [string ]bool )
for _ , atvs := range atvSet .Value {
for _ , atv := range atvs {
specifiedExtensions [atv .Type .String ()] = true
}
}
newValue := make ([]pkix .AttributeTypeAndValue , 0 , len (atvSet .Value [0 ])+len (extensions ))
newValue = append (newValue , atvSet .Value [0 ]...)
for _ , e := range extensions {
if specifiedExtensions [e .Id .String ()] {
continue
}
newValue = append (newValue , pkix .AttributeTypeAndValue {
Type : e .Id ,
Value : e .Value ,
})
}
atvSet .Value [0 ] = newValue
extensionsAppended = true
break
}
}
rawAttributes , err := newRawAttributes (attributes )
if err != nil {
return
}
if len (extensions ) > 0 && !extensionsAppended {
attr := struct {
Type asn1 .ObjectIdentifier
Value [][]pkix .Extension `asn1:"set"`
}{
Type : oidExtensionRequest ,
Value : [][]pkix .Extension {extensions },
}
b , err := asn1 .Marshal (attr )
if err != nil {
return nil , errors .New ("x509: failed to serialise extensions attribute: " + err .Error())
}
var rawValue asn1 .RawValue
if _ , err := asn1 .Unmarshal (b , &rawValue ); err != nil {
return nil , err
}
rawAttributes = append (rawAttributes , rawValue )
}
asn1Subject := template .RawSubject
if len (asn1Subject ) == 0 {
asn1Subject , err = asn1 .Marshal (template .Subject .ToRDNSequence ())
if err != nil {
return nil , err
}
}
tbsCSR := tbsCertificateRequest {
Version : 0 ,
Subject : asn1 .RawValue {FullBytes : asn1Subject },
PublicKey : publicKeyInfo {
Algorithm : publicKeyAlgorithm ,
PublicKey : asn1 .BitString {
Bytes : publicKeyBytes ,
BitLength : len (publicKeyBytes ) * 8 ,
},
},
RawAttributes : rawAttributes ,
}
tbsCSRContents , err := asn1 .Marshal (tbsCSR )
if err != nil {
return
}
tbsCSR .Raw = tbsCSRContents
signed := tbsCSRContents
if hashFunc != 0 {
h := hashFunc .New ()
h .Write (signed )
signed = h .Sum (nil )
}
var signature []byte
signature , err = key .Sign (rand , signed , hashFunc )
if err != nil {
return
}
return asn1 .Marshal (certificateRequest {
TBSCSR : tbsCSR ,
SignatureAlgorithm : sigAlgo ,
SignatureValue : asn1 .BitString {
Bytes : signature ,
BitLength : len (signature ) * 8 ,
},
})
}
func ParseCertificateRequest (asn1Data []byte ) (*CertificateRequest , error ) {
var csr certificateRequest
rest , err := asn1 .Unmarshal (asn1Data , &csr )
if err != nil {
return nil , err
} else if len (rest ) != 0 {
return nil , asn1 .SyntaxError {Msg : "trailing data" }
}
return parseCertificateRequest (&csr )
}
func parseCertificateRequest (in *certificateRequest ) (*CertificateRequest , error ) {
out := &CertificateRequest {
Raw : in .Raw ,
RawTBSCertificateRequest : in .TBSCSR .Raw ,
RawSubjectPublicKeyInfo : in .TBSCSR .PublicKey .Raw ,
RawSubject : in .TBSCSR .Subject .FullBytes ,
Signature : in .SignatureValue .RightAlign (),
SignatureAlgorithm : getSignatureAlgorithmFromAI (in .SignatureAlgorithm ),
PublicKeyAlgorithm : getPublicKeyAlgorithmFromOID (in .TBSCSR .PublicKey .Algorithm .Algorithm ),
Version : in .TBSCSR .Version ,
Attributes : parseRawAttributes (in .TBSCSR .RawAttributes ),
}
var err error
if out .PublicKeyAlgorithm != UnknownPublicKeyAlgorithm {
out .PublicKey , err = parsePublicKey (&in .TBSCSR .PublicKey )
if err != nil {
return nil , err
}
}
var subject pkix .RDNSequence
if rest , err := asn1 .Unmarshal (in .TBSCSR .Subject .FullBytes , &subject ); err != nil {
return nil , err
} else if len (rest ) != 0 {
return nil , errors .New ("x509: trailing data after X.509 Subject" )
}
out .Subject .FillFromRDNSequence (&subject )
if out .Extensions , err = parseCSRExtensions (in .TBSCSR .RawAttributes ); err != nil {
return nil , err
}
for _ , extension := range out .Extensions {
switch {
case extension .Id .Equal (oidExtensionSubjectAltName ):
out .DNSNames , out .EmailAddresses , out .IPAddresses , out .URIs , err = parseSANExtension (extension .Value )
if err != nil {
return nil , err
}
}
}
return out , nil
}
func (c *CertificateRequest ) CheckSignature () error {
return checkSignature (c .SignatureAlgorithm , c .RawTBSCertificateRequest , c .Signature , c .PublicKey , true )
}
type RevocationListEntry struct {
Raw []byte
SerialNumber *big .Int
RevocationTime time .Time
ReasonCode int
Extensions []pkix .Extension
ExtraExtensions []pkix .Extension
}
type RevocationList struct {
Raw []byte
RawTBSRevocationList []byte
RawIssuer []byte
Issuer pkix .Name
AuthorityKeyId []byte
Signature []byte
SignatureAlgorithm SignatureAlgorithm
RevokedCertificateEntries []RevocationListEntry
RevokedCertificates []pkix .RevokedCertificate
Number *big .Int
ThisUpdate time .Time
NextUpdate time .Time
Extensions []pkix .Extension
ExtraExtensions []pkix .Extension
}
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"`
}
func CreateRevocationList (rand io .Reader , template *RevocationList , issuer *Certificate , priv crypto .Signer ) ([]byte , error ) {
if template == nil {
return nil , errors .New ("x509: template can not be nil" )
}
if issuer == nil {
return nil , errors .New ("x509: issuer can not be nil" )
}
if (issuer .KeyUsage & KeyUsageCRLSign ) == 0 {
return nil , errors .New ("x509: issuer must have the crlSign key usage bit set" )
}
if len (issuer .SubjectKeyId ) == 0 {
return nil , errors .New ("x509: issuer certificate doesn't contain a subject key identifier" )
}
if template .NextUpdate .Before (template .ThisUpdate ) {
return nil , errors .New ("x509: template.ThisUpdate is after template.NextUpdate" )
}
if template .Number == nil {
return nil , errors .New ("x509: template contains nil Number field" )
}
hashFunc , signatureAlgorithm , err := signingParamsForPublicKey (priv .Public (), template .SignatureAlgorithm )
if err != nil {
return nil , err
}
var revokedCerts []pkix .RevokedCertificate
if len (template .RevokedCertificates ) > 0 && len (template .RevokedCertificateEntries ) == 0 {
revokedCerts = make ([]pkix .RevokedCertificate , len (template .RevokedCertificates ))
for i , rc := range template .RevokedCertificates {
rc .RevocationTime = rc .RevocationTime .UTC ()
revokedCerts [i ] = rc
}
} else {
revokedCerts = make ([]pkix .RevokedCertificate , len (template .RevokedCertificateEntries ))
for i , rce := range template .RevokedCertificateEntries {
if rce .SerialNumber == nil {
return nil , errors .New ("x509: template contains entry with nil SerialNumber field" )
}
if rce .RevocationTime .IsZero () {
return nil , errors .New ("x509: template contains entry with zero RevocationTime field" )
}
rc := pkix .RevokedCertificate {
SerialNumber : rce .SerialNumber ,
RevocationTime : rce .RevocationTime .UTC (),
}
exts := make ([]pkix .Extension , 0 , len (rce .ExtraExtensions ))
for _ , ext := range rce .ExtraExtensions {
if ext .Id .Equal (oidExtensionReasonCode ) {
return nil , errors .New ("x509: template contains entry with ReasonCode ExtraExtension; use ReasonCode field instead" )
}
exts = append (exts , ext )
}
if rce .ReasonCode != 0 {
reasonBytes , err := asn1 .Marshal (asn1 .Enumerated (rce .ReasonCode ))
if err != nil {
return nil , err
}
exts = append (exts , pkix .Extension {
Id : oidExtensionReasonCode ,
Value : reasonBytes ,
})
}
if len (exts ) > 0 {
rc .Extensions = exts
}
revokedCerts [i ] = rc
}
}
aki , err := asn1 .Marshal (authKeyId {Id : issuer .SubjectKeyId })
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
}
issuerSubject , err := subjectBytes (issuer )
if err != nil {
return nil , err
}
tbsCertList := tbsCertificateList {
Version : 1 ,
Signature : signatureAlgorithm ,
Issuer : asn1 .RawValue {FullBytes : issuerSubject },
ThisUpdate : template .ThisUpdate .UTC (),
NextUpdate : template .NextUpdate .UTC (),
Extensions : []pkix .Extension {
{
Id : oidExtensionAuthorityKeyId ,
Value : aki ,
},
{
Id : oidExtensionCRLNumber ,
Value : crlNum ,
},
},
}
if len (revokedCerts ) > 0 {
tbsCertList .RevokedCertificates = revokedCerts
}
if len (template .ExtraExtensions ) > 0 {
tbsCertList .Extensions = append (tbsCertList .Extensions , template .ExtraExtensions ...)
}
tbsCertListContents , err := asn1 .Marshal (tbsCertList )
if err != nil {
return nil , err
}
tbsCertList .Raw = tbsCertListContents
input := tbsCertListContents
if hashFunc != 0 {
h := hashFunc .New ()
h .Write (tbsCertListContents )
input = h .Sum (nil )
}
var signerOpts crypto .SignerOpts = hashFunc
if template .SignatureAlgorithm .isRSAPSS () {
signerOpts = &rsa .PSSOptions {
SaltLength : rsa .PSSSaltLengthEqualsHash ,
Hash : hashFunc ,
}
}
signature , err := priv .Sign (rand , input , signerOpts )
if err != nil {
return nil , err
}
return asn1 .Marshal (certificateList {
TBSCertList : tbsCertList ,
SignatureAlgorithm : signatureAlgorithm ,
SignatureValue : asn1 .BitString {Bytes : signature , BitLength : len (signature ) * 8 },
})
}
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 )
}
The pages are generated with Golds v0.6.7 . (GOOS=linux GOARCH=amd64)
Golds is a Go 101 project developed by Tapir Liu .
PR and bug reports are welcome and can be submitted to the issue list .
Please follow @Go100and1 (reachable from the left QR code) to get the latest news of Golds .