package x509
import (
"bytes"
"crypto"
"crypto/dsa"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
"crypto/sha1"
"crypto/x509/pkix"
"encoding/asn1"
"encoding/pem"
"errors"
"fmt"
"io"
"math/big"
"net"
"net/url"
"strconv"
"strings"
"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 interface {}, 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" )
}
algo := getPublicKeyAlgorithmFromOID (pki .Algorithm .Algorithm )
if algo == UnknownPublicKeyAlgorithm {
return nil , errors .New ("x509: unknown public key algorithm" )
}
return parsePublicKey (algo , &pki )
}
func marshalPublicKey (pub interface {}) (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 :
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" )
}
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
default :
return nil , pkix .AlgorithmIdentifier {}, fmt .Errorf ("x509: unsupported public key type: %T" , pub )
}
return publicKeyBytes , publicKeyAlgorithm , nil
}
func MarshalPKIXPublicKey (pub interface {}) ([]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 {
Raw asn1 .RawContent
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:"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 }
oidPublicKeyEd25519 = oidSignatureEd25519
)
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
}
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 interface {}
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 {
return fmt .Sprintf ("x509: cannot verify signature: insecure algorithm %v" , SignatureAlgorithm (e ))
}
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 parent .CheckSignature (c .SignatureAlgorithm , c .RawTBSCertificate , c .Signature )
}
func (c *Certificate ) CheckSignature (algo SignatureAlgorithm , signed , signature []byte ) error {
return checkSignature (algo , signed , signature , c .PublicKey )
}
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 interface {}) error {
return fmt .Errorf ("x509: signature algorithm specifies an %s public key, but have public key of type %T" , expectedPubKeyAlgo .String (), pubKey )
}
func checkSignature (algo SignatureAlgorithm , signed , signature []byte , publicKey crypto .PublicKey ) (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 )
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 parsePublicKey (algo PublicKeyAlgorithm , keyData *publicKeyInfo ) (interface {}, error ) {
asn1Data := keyData .PublicKey .RightAlign ()
switch algo {
case RSA :
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 :
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 {
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
}
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 ) {
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 {
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 ] == '.' {
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 strings .Contains (constraint , "@" ) {
if _ , ok := parseRFC2821Mailbox (constraint ); !ok {
return nil , nil , nil , nil , fmt .Errorf ("x509: failed to parse rfc822Name constraint %q" , constraint )
}
} else {
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 ] == '.' {
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 {
unhandled = true
}
case 30 :
unhandled , err = parseNameConstraintsExtension (out , e )
if err != nil {
return nil , err
}
case 31 :
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 {
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 :
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 :
unhandled = true
}
} else if e .Id .Equal (oidExtensionAuthorityInfoAccess ) {
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 {
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 {
unhandled = true
}
if e .Critical && unhandled {
out .UnhandledCriticalExtensions = append (out .UnhandledCriticalExtensions , e .Id )
}
}
return out , nil
}
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
}
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" )
}
return constraints .IsCA , constraints .MaxPathLen , nil
}
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
}
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
}
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 )
}
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
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 }
)
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 )})
if err != nil {
return ext , err
}
return ext , nil
}
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 )
if err != nil {
return ext , err
}
return ext , nil
}
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 })
if err != nil {
return ext , nil
}
return ext , nil
}
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 )
if err != nil {
return ext , err
}
return ext , nil
}
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 interface {}, 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 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 interface {}) (cert []byte , err 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 .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
}
asn1Issuer , err := subjectBytes (parent )
if err != nil {
return
}
asn1Subject , err := subjectBytes (template )
if err != nil {
return
}
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 [:]
}
extensions , err := buildCertExtensions (template , bytes .Equal (asn1Subject , emptyASN1Subject ), authorityKeyId , subjectKeyId )
if err != nil {
return
}
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
}
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
}
signedCert , err := asn1 .Marshal (certificate {
nil ,
c ,
signatureAlgorithm ,
asn1 .BitString {Bytes : signature , BitLength : len (signature ) * 8 },
})
if err != nil {
return nil , err
}
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 )
}
}
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 interface {}, 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 interface {}
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
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
}
ret = append (ret , extensions ...)
}
return ret , nil
}
func CreateCertificateRequest (rand io .Reader , template *CertificateRequest , priv interface {}) (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
out .PublicKey , err = parsePublicKey (out .PublicKeyAlgorithm , &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 )
}
type RevocationList struct {
SignatureAlgorithm SignatureAlgorithm
RevokedCertificates []pkix .RevokedCertificate
Number *big .Int
ThisUpdate time .Time
NextUpdate time .Time
ExtraExtensions []pkix .Extension
}
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
}
revokedCertsUTC := make ([]pkix .RevokedCertificate , len (template .RevokedCertificates ))
for i , rc := range template .RevokedCertificates {
rc .RevocationTime = rc .RevocationTime .UTC ()
revokedCertsUTC [i ] = rc
}
aki , err := asn1 .Marshal (authKeyId {Id : issuer .SubjectKeyId })
if err != nil {
return nil , err
}
crlNum , err := asn1 .Marshal (template .Number )
if err != nil {
return nil , err
}
tbsCertList := pkix .TBSCertificateList {
Version : 1 ,
Signature : signatureAlgorithm ,
Issuer : issuer .Subject .ToRDNSequence (),
ThisUpdate : template .ThisUpdate .UTC (),
NextUpdate : template .NextUpdate .UTC (),
Extensions : []pkix .Extension {
{
Id : oidExtensionAuthorityKeyId ,
Value : aki ,
},
{
Id : oidExtensionCRLNumber ,
Value : crlNum ,
},
},
}
if len (revokedCertsUTC ) > 0 {
tbsCertList .RevokedCertificates = revokedCertsUTC
}
if len (template .ExtraExtensions ) > 0 {
tbsCertList .Extensions = append (tbsCertList .Extensions , template .ExtraExtensions ...)
}
tbsCertListContents , err := asn1 .Marshal (tbsCertList )
if err != nil {
return nil , err
}
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 (pkix .CertificateList {
TBSCertList : tbsCertList ,
SignatureAlgorithm : signatureAlgorithm ,
SignatureValue : asn1 .BitString {Bytes : signature , BitLength : len (signature ) * 8 },
})
}