package x509
import (
"bytes"
"crypto/dsa"
"crypto/ecdh"
"crypto/ecdsa"
"crypto/ed25519"
"crypto/elliptic"
"crypto/rsa"
"crypto/x509/pkix"
"encoding/asn1"
"errors"
"fmt"
"internal/godebug"
"math/big"
"net"
"net/url"
"strconv"
"strings"
"time"
"unicode/utf16"
"unicode/utf8"
"golang.org/x/crypto/cryptobyte"
cryptobyte_asn1 "golang.org/x/crypto/cryptobyte/asn1"
)
func isPrintable(b byte ) bool {
return 'a' <= b && b <= 'z' ||
'A' <= b && b <= 'Z' ||
'0' <= b && b <= '9' ||
'\'' <= b && b <= ')' ||
'+' <= b && b <= '/' ||
b == ' ' ||
b == ':' ||
b == '=' ||
b == '?' ||
b == '*' ||
b == '&'
}
func parseASN1String(tag cryptobyte_asn1 .Tag , value []byte ) (string , error ) {
switch tag {
case cryptobyte_asn1 .T61String :
return string (value ), nil
case cryptobyte_asn1 .PrintableString :
for _ , b := range value {
if !isPrintable (b ) {
return "" , errors .New ("invalid PrintableString" )
}
}
return string (value ), nil
case cryptobyte_asn1 .UTF8String :
if !utf8 .Valid (value ) {
return "" , errors .New ("invalid UTF-8 string" )
}
return string (value ), nil
case cryptobyte_asn1 .Tag (asn1 .TagBMPString ):
if len (value )%2 != 0 {
return "" , errors .New ("invalid BMPString" )
}
if l := len (value ); l >= 2 && value [l -1 ] == 0 && value [l -2 ] == 0 {
value = value [:l -2 ]
}
s := make ([]uint16 , 0 , len (value )/2 )
for len (value ) > 0 {
s = append (s , uint16 (value [0 ])<<8 +uint16 (value [1 ]))
value = value [2 :]
}
return string (utf16 .Decode (s )), nil
case cryptobyte_asn1 .IA5String :
s := string (value )
if isIA5String (s ) != nil {
return "" , errors .New ("invalid IA5String" )
}
return s , nil
case cryptobyte_asn1 .Tag (asn1 .TagNumericString ):
for _ , b := range value {
if !('0' <= b && b <= '9' || b == ' ' ) {
return "" , errors .New ("invalid NumericString" )
}
}
return string (value ), nil
}
return "" , fmt .Errorf ("unsupported string type: %v" , tag )
}
func parseName(raw cryptobyte .String ) (*pkix .RDNSequence , error ) {
if !raw .ReadASN1 (&raw , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: invalid RDNSequence" )
}
var rdnSeq pkix .RDNSequence
for !raw .Empty () {
var rdnSet pkix .RelativeDistinguishedNameSET
var set cryptobyte .String
if !raw .ReadASN1 (&set , cryptobyte_asn1 .SET ) {
return nil , errors .New ("x509: invalid RDNSequence" )
}
for !set .Empty () {
var atav cryptobyte .String
if !set .ReadASN1 (&atav , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: invalid RDNSequence: invalid attribute" )
}
var attr pkix .AttributeTypeAndValue
if !atav .ReadASN1ObjectIdentifier (&attr .Type ) {
return nil , errors .New ("x509: invalid RDNSequence: invalid attribute type" )
}
var rawValue cryptobyte .String
var valueTag cryptobyte_asn1 .Tag
if !atav .ReadAnyASN1 (&rawValue , &valueTag ) {
return nil , errors .New ("x509: invalid RDNSequence: invalid attribute value" )
}
var err error
attr .Value , err = parseASN1String (valueTag , rawValue )
if err != nil {
return nil , fmt .Errorf ("x509: invalid RDNSequence: invalid attribute value: %s" , err )
}
rdnSet = append (rdnSet , attr )
}
rdnSeq = append (rdnSeq , rdnSet )
}
return &rdnSeq , nil
}
func parseAI(der cryptobyte .String ) (pkix .AlgorithmIdentifier , error ) {
ai := pkix .AlgorithmIdentifier {}
if !der .ReadASN1ObjectIdentifier (&ai .Algorithm ) {
return ai , errors .New ("x509: malformed OID" )
}
if der .Empty () {
return ai , nil
}
var params cryptobyte .String
var tag cryptobyte_asn1 .Tag
if !der .ReadAnyASN1Element (¶ms , &tag ) {
return ai , errors .New ("x509: malformed parameters" )
}
ai .Parameters .Tag = int (tag )
ai .Parameters .FullBytes = params
return ai , nil
}
func parseTime(der *cryptobyte .String ) (time .Time , error ) {
var t time .Time
switch {
case der .PeekASN1Tag (cryptobyte_asn1 .UTCTime ):
if !der .ReadASN1UTCTime (&t ) {
return t , errors .New ("x509: malformed UTCTime" )
}
case der .PeekASN1Tag (cryptobyte_asn1 .GeneralizedTime ):
if !der .ReadASN1GeneralizedTime (&t ) {
return t , errors .New ("x509: malformed GeneralizedTime" )
}
default :
return t , errors .New ("x509: unsupported time format" )
}
return t , nil
}
func parseValidity(der cryptobyte .String ) (time .Time , time .Time , error ) {
notBefore , err := parseTime (&der )
if err != nil {
return time .Time {}, time .Time {}, err
}
notAfter , err := parseTime (&der )
if err != nil {
return time .Time {}, time .Time {}, err
}
return notBefore , notAfter , nil
}
func parseExtension(der cryptobyte .String ) (pkix .Extension , error ) {
var ext pkix .Extension
if !der .ReadASN1ObjectIdentifier (&ext .Id ) {
return ext , errors .New ("x509: malformed extension OID field" )
}
if der .PeekASN1Tag (cryptobyte_asn1 .BOOLEAN ) {
if !der .ReadASN1Boolean (&ext .Critical ) {
return ext , errors .New ("x509: malformed extension critical field" )
}
}
var val cryptobyte .String
if !der .ReadASN1 (&val , cryptobyte_asn1 .OCTET_STRING ) {
return ext , errors .New ("x509: malformed extension value field" )
}
ext .Value = val
return ext , nil
}
func parsePublicKey(keyData *publicKeyInfo ) (any , error ) {
oid := keyData .Algorithm .Algorithm
params := keyData .Algorithm .Parameters
der := cryptobyte .String (keyData .PublicKey .RightAlign ())
switch {
case oid .Equal (oidPublicKeyRSA ):
if !bytes .Equal (params .FullBytes , asn1 .NullBytes ) {
return nil , errors .New ("x509: RSA key missing NULL parameters" )
}
p := &pkcs1PublicKey {N : new (big .Int )}
if !der .ReadASN1 (&der , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: invalid RSA public key" )
}
if !der .ReadASN1Integer (p .N ) {
return nil , errors .New ("x509: invalid RSA modulus" )
}
if !der .ReadASN1Integer (&p .E ) {
return nil , errors .New ("x509: invalid RSA public exponent" )
}
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 oid .Equal (oidPublicKeyECDSA ):
paramsDer := cryptobyte .String (params .FullBytes )
namedCurveOID := new (asn1 .ObjectIdentifier )
if !paramsDer .ReadASN1ObjectIdentifier (namedCurveOID ) {
return nil , errors .New ("x509: invalid ECDSA parameters" )
}
namedCurve := namedCurveFromOID (*namedCurveOID )
if namedCurve == nil {
return nil , errors .New ("x509: unsupported elliptic curve" )
}
x , y := elliptic .Unmarshal (namedCurve , der )
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 oid .Equal (oidPublicKeyEd25519 ):
if len (params .FullBytes ) != 0 {
return nil , errors .New ("x509: Ed25519 key encoded with illegal parameters" )
}
if len (der ) != ed25519 .PublicKeySize {
return nil , errors .New ("x509: wrong Ed25519 public key size" )
}
return ed25519 .PublicKey (der ), nil
case oid .Equal (oidPublicKeyX25519 ):
if len (params .FullBytes ) != 0 {
return nil , errors .New ("x509: X25519 key encoded with illegal parameters" )
}
return ecdh .X25519 ().NewPublicKey (der )
case oid .Equal (oidPublicKeyDSA ):
y := new (big .Int )
if !der .ReadASN1Integer (y ) {
return nil , errors .New ("x509: invalid DSA public key" )
}
pub := &dsa .PublicKey {
Y : y ,
Parameters : dsa .Parameters {
P : new (big .Int ),
Q : new (big .Int ),
G : new (big .Int ),
},
}
paramsDer := cryptobyte .String (params .FullBytes )
if !paramsDer .ReadASN1 (¶msDer , cryptobyte_asn1 .SEQUENCE ) ||
!paramsDer .ReadASN1Integer (pub .Parameters .P ) ||
!paramsDer .ReadASN1Integer (pub .Parameters .Q ) ||
!paramsDer .ReadASN1Integer (pub .Parameters .G ) {
return nil , errors .New ("x509: invalid DSA parameters" )
}
if pub .Y .Sign () <= 0 || pub .Parameters .P .Sign () <= 0 ||
pub .Parameters .Q .Sign () <= 0 || pub .Parameters .G .Sign () <= 0 {
return nil , errors .New ("x509: zero or negative DSA parameter" )
}
return pub , nil
default :
return nil , errors .New ("x509: unknown public key algorithm" )
}
}
func parseKeyUsageExtension(der cryptobyte .String ) (KeyUsage , error ) {
var usageBits asn1 .BitString
if !der .ReadASN1BitString (&usageBits ) {
return 0 , errors .New ("x509: invalid key usage" )
}
var usage int
for i := 0 ; i < 9 ; i ++ {
if usageBits .At (i ) != 0 {
usage |= 1 << uint (i )
}
}
return KeyUsage (usage ), nil
}
func parseBasicConstraintsExtension(der cryptobyte .String ) (bool , int , error ) {
var isCA bool
if !der .ReadASN1 (&der , cryptobyte_asn1 .SEQUENCE ) {
return false , 0 , errors .New ("x509: invalid basic constraints" )
}
if der .PeekASN1Tag (cryptobyte_asn1 .BOOLEAN ) {
if !der .ReadASN1Boolean (&isCA ) {
return false , 0 , errors .New ("x509: invalid basic constraints" )
}
}
maxPathLen := -1
if der .PeekASN1Tag (cryptobyte_asn1 .INTEGER ) {
if !der .ReadASN1Integer (&maxPathLen ) {
return false , 0 , errors .New ("x509: invalid basic constraints" )
}
}
return isCA , maxPathLen , nil
}
func forEachSAN(der cryptobyte .String , callback func (tag int , data []byte ) error ) error {
if !der .ReadASN1 (&der , cryptobyte_asn1 .SEQUENCE ) {
return errors .New ("x509: invalid subject alternative names" )
}
for !der .Empty () {
var san cryptobyte .String
var tag cryptobyte_asn1 .Tag
if !der .ReadAnyASN1 (&san , &tag ) {
return errors .New ("x509: invalid subject alternative name" )
}
if err := callback (int (tag ^0x80 ), san ); err != nil {
return err
}
}
return nil
}
func parseSANExtension(der cryptobyte .String ) (dnsNames , emailAddresses []string , ipAddresses []net .IP , uris []*url .URL , err error ) {
err = forEachSAN (der , 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 parseAuthorityKeyIdentifier(e pkix .Extension ) ([]byte , error ) {
if e .Critical {
return nil , errors .New ("x509: authority key identifier incorrectly marked critical" )
}
val := cryptobyte .String (e .Value )
var akid cryptobyte .String
if !val .ReadASN1 (&akid , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: invalid authority key identifier" )
}
if akid .PeekASN1Tag (cryptobyte_asn1 .Tag (0 ).ContextSpecific ()) {
if !akid .ReadASN1 (&akid , cryptobyte_asn1 .Tag (0 ).ContextSpecific ()) {
return nil , errors .New ("x509: invalid authority key identifier" )
}
return akid , nil
}
return nil , nil
}
func parseExtKeyUsageExtension(der cryptobyte .String ) ([]ExtKeyUsage , []asn1 .ObjectIdentifier , error ) {
var extKeyUsages []ExtKeyUsage
var unknownUsages []asn1 .ObjectIdentifier
if !der .ReadASN1 (&der , cryptobyte_asn1 .SEQUENCE ) {
return nil , nil , errors .New ("x509: invalid extended key usages" )
}
for !der .Empty () {
var eku asn1 .ObjectIdentifier
if !der .ReadASN1ObjectIdentifier (&eku ) {
return nil , nil , errors .New ("x509: invalid extended key usages" )
}
if extKeyUsage , ok := extKeyUsageFromOID (eku ); ok {
extKeyUsages = append (extKeyUsages , extKeyUsage )
} else {
unknownUsages = append (unknownUsages , eku )
}
}
return extKeyUsages , unknownUsages , nil
}
func parseCertificatePoliciesExtension(der cryptobyte .String ) ([]OID , error ) {
var oids []OID
if !der .ReadASN1 (&der , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: invalid certificate policies" )
}
for !der .Empty () {
var cp cryptobyte .String
var OIDBytes cryptobyte .String
if !der .ReadASN1 (&cp , cryptobyte_asn1 .SEQUENCE ) || !cp .ReadASN1 (&OIDBytes , cryptobyte_asn1 .OBJECT_IDENTIFIER ) {
return nil , errors .New ("x509: invalid certificate policies" )
}
oid , ok := newOIDFromDER (OIDBytes )
if !ok {
return nil , errors .New ("x509: invalid certificate policies" )
}
oids = append (oids , oid )
}
return oids , nil
}
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 processExtensions(out *Certificate ) error {
var err error
for _ , e := range out .Extensions {
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 err
}
case 19 :
out .IsCA , out .MaxPathLen , err = parseBasicConstraintsExtension (e .Value )
if err != nil {
return 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 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 err
}
case 31 :
val := cryptobyte .String (e .Value )
if !val .ReadASN1 (&val , cryptobyte_asn1 .SEQUENCE ) {
return errors .New ("x509: invalid CRL distribution points" )
}
for !val .Empty () {
var dpDER cryptobyte .String
if !val .ReadASN1 (&dpDER , cryptobyte_asn1 .SEQUENCE ) {
return errors .New ("x509: invalid CRL distribution point" )
}
var dpNameDER cryptobyte .String
var dpNamePresent bool
if !dpDER .ReadOptionalASN1 (&dpNameDER , &dpNamePresent , cryptobyte_asn1 .Tag (0 ).Constructed ().ContextSpecific ()) {
return errors .New ("x509: invalid CRL distribution point" )
}
if !dpNamePresent {
continue
}
if !dpNameDER .ReadASN1 (&dpNameDER , cryptobyte_asn1 .Tag (0 ).Constructed ().ContextSpecific ()) {
return errors .New ("x509: invalid CRL distribution point" )
}
for !dpNameDER .Empty () {
if !dpNameDER .PeekASN1Tag (cryptobyte_asn1 .Tag (6 ).ContextSpecific ()) {
break
}
var uri cryptobyte .String
if !dpNameDER .ReadASN1 (&uri , cryptobyte_asn1 .Tag (6 ).ContextSpecific ()) {
return errors .New ("x509: invalid CRL distribution point" )
}
out .CRLDistributionPoints = append (out .CRLDistributionPoints , string (uri ))
}
}
case 35 :
out .AuthorityKeyId , err = parseAuthorityKeyIdentifier (e )
if err != nil {
return err
}
case 37 :
out .ExtKeyUsage , out .UnknownExtKeyUsage , err = parseExtKeyUsageExtension (e .Value )
if err != nil {
return err
}
case 14 :
if e .Critical {
return errors .New ("x509: subject key identifier incorrectly marked critical" )
}
val := cryptobyte .String (e .Value )
var skid cryptobyte .String
if !val .ReadASN1 (&skid , cryptobyte_asn1 .OCTET_STRING ) {
return errors .New ("x509: invalid subject key identifier" )
}
out .SubjectKeyId = skid
case 32 :
out .Policies , err = parseCertificatePoliciesExtension (e .Value )
if err != nil {
return err
}
out .PolicyIdentifiers = make ([]asn1 .ObjectIdentifier , 0 , len (out .Policies ))
for _ , oid := range out .Policies {
if oid , ok := oid .toASN1OID (); ok {
out .PolicyIdentifiers = append (out .PolicyIdentifiers , oid )
}
}
default :
unhandled = true
}
} else if e .Id .Equal (oidExtensionAuthorityInfoAccess ) {
if e .Critical {
return errors .New ("x509: authority info access incorrectly marked critical" )
}
val := cryptobyte .String (e .Value )
if !val .ReadASN1 (&val , cryptobyte_asn1 .SEQUENCE ) {
return errors .New ("x509: invalid authority info access" )
}
for !val .Empty () {
var aiaDER cryptobyte .String
if !val .ReadASN1 (&aiaDER , cryptobyte_asn1 .SEQUENCE ) {
return errors .New ("x509: invalid authority info access" )
}
var method asn1 .ObjectIdentifier
if !aiaDER .ReadASN1ObjectIdentifier (&method ) {
return errors .New ("x509: invalid authority info access" )
}
if !aiaDER .PeekASN1Tag (cryptobyte_asn1 .Tag (6 ).ContextSpecific ()) {
continue
}
if !aiaDER .ReadASN1 (&aiaDER , cryptobyte_asn1 .Tag (6 ).ContextSpecific ()) {
return errors .New ("x509: invalid authority info access" )
}
switch {
case method .Equal (oidAuthorityInfoAccessOcsp ):
out .OCSPServer = append (out .OCSPServer , string (aiaDER ))
case method .Equal (oidAuthorityInfoAccessIssuers ):
out .IssuingCertificateURL = append (out .IssuingCertificateURL , string (aiaDER ))
}
}
} else {
unhandled = true
}
if e .Critical && unhandled {
out .UnhandledCriticalExtensions = append (out .UnhandledCriticalExtensions , e .Id )
}
}
return nil
}
var x509negativeserial = godebug .New ("x509negativeserial" )
func parseCertificate(der []byte ) (*Certificate , error ) {
cert := &Certificate {}
input := cryptobyte .String (der )
if !input .ReadASN1Element (&input , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed certificate" )
}
cert .Raw = input
if !input .ReadASN1 (&input , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed certificate" )
}
var tbs cryptobyte .String
if !input .ReadASN1Element (&tbs , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed tbs certificate" )
}
cert .RawTBSCertificate = tbs
if !tbs .ReadASN1 (&tbs , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed tbs certificate" )
}
if !tbs .ReadOptionalASN1Integer (&cert .Version , cryptobyte_asn1 .Tag (0 ).Constructed ().ContextSpecific (), 0 ) {
return nil , errors .New ("x509: malformed version" )
}
if cert .Version < 0 {
return nil , errors .New ("x509: malformed version" )
}
cert .Version ++
if cert .Version > 3 {
return nil , errors .New ("x509: invalid version" )
}
serial := new (big .Int )
if !tbs .ReadASN1Integer (serial ) {
return nil , errors .New ("x509: malformed serial number" )
}
if serial .Sign () == -1 {
if x509negativeserial .Value () != "1" {
return nil , errors .New ("x509: negative serial number" )
} else {
x509negativeserial .IncNonDefault ()
}
}
cert .SerialNumber = serial
var sigAISeq cryptobyte .String
if !tbs .ReadASN1 (&sigAISeq , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed signature algorithm identifier" )
}
var outerSigAISeq cryptobyte .String
if !input .ReadASN1 (&outerSigAISeq , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed algorithm identifier" )
}
if !bytes .Equal (outerSigAISeq , sigAISeq ) {
return nil , errors .New ("x509: inner and outer signature algorithm identifiers don't match" )
}
sigAI , err := parseAI (sigAISeq )
if err != nil {
return nil , err
}
cert .SignatureAlgorithm = getSignatureAlgorithmFromAI (sigAI )
var issuerSeq cryptobyte .String
if !tbs .ReadASN1Element (&issuerSeq , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed issuer" )
}
cert .RawIssuer = issuerSeq
issuerRDNs , err := parseName (issuerSeq )
if err != nil {
return nil , err
}
cert .Issuer .FillFromRDNSequence (issuerRDNs )
var validity cryptobyte .String
if !tbs .ReadASN1 (&validity , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed validity" )
}
cert .NotBefore , cert .NotAfter , err = parseValidity (validity )
if err != nil {
return nil , err
}
var subjectSeq cryptobyte .String
if !tbs .ReadASN1Element (&subjectSeq , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed issuer" )
}
cert .RawSubject = subjectSeq
subjectRDNs , err := parseName (subjectSeq )
if err != nil {
return nil , err
}
cert .Subject .FillFromRDNSequence (subjectRDNs )
var spki cryptobyte .String
if !tbs .ReadASN1Element (&spki , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed spki" )
}
cert .RawSubjectPublicKeyInfo = spki
if !spki .ReadASN1 (&spki , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed spki" )
}
var pkAISeq cryptobyte .String
if !spki .ReadASN1 (&pkAISeq , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed public key algorithm identifier" )
}
pkAI , err := parseAI (pkAISeq )
if err != nil {
return nil , err
}
cert .PublicKeyAlgorithm = getPublicKeyAlgorithmFromOID (pkAI .Algorithm )
var spk asn1 .BitString
if !spki .ReadASN1BitString (&spk ) {
return nil , errors .New ("x509: malformed subjectPublicKey" )
}
if cert .PublicKeyAlgorithm != UnknownPublicKeyAlgorithm {
cert .PublicKey , err = parsePublicKey (&publicKeyInfo {
Algorithm : pkAI ,
PublicKey : spk ,
})
if err != nil {
return nil , err
}
}
if cert .Version > 1 {
if !tbs .SkipOptionalASN1 (cryptobyte_asn1 .Tag (1 ).ContextSpecific ()) {
return nil , errors .New ("x509: malformed issuerUniqueID" )
}
if !tbs .SkipOptionalASN1 (cryptobyte_asn1 .Tag (2 ).ContextSpecific ()) {
return nil , errors .New ("x509: malformed subjectUniqueID" )
}
if cert .Version == 3 {
var extensions cryptobyte .String
var present bool
if !tbs .ReadOptionalASN1 (&extensions , &present , cryptobyte_asn1 .Tag (3 ).Constructed ().ContextSpecific ()) {
return nil , errors .New ("x509: malformed extensions" )
}
if present {
seenExts := make (map [string ]bool )
if !extensions .ReadASN1 (&extensions , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed extensions" )
}
for !extensions .Empty () {
var extension cryptobyte .String
if !extensions .ReadASN1 (&extension , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed extension" )
}
ext , err := parseExtension (extension )
if err != nil {
return nil , err
}
oidStr := ext .Id .String ()
if seenExts [oidStr ] {
return nil , fmt .Errorf ("x509: certificate contains duplicate extension with OID %q" , oidStr )
}
seenExts [oidStr ] = true
cert .Extensions = append (cert .Extensions , ext )
}
err = processExtensions (cert )
if err != nil {
return nil , err
}
}
}
}
var signature asn1 .BitString
if !input .ReadASN1BitString (&signature ) {
return nil , errors .New ("x509: malformed signature" )
}
cert .Signature = signature .RightAlign ()
return cert , nil
}
func ParseCertificate (der []byte ) (*Certificate , error ) {
cert , err := parseCertificate (der )
if err != nil {
return nil , err
}
if len (der ) != len (cert .Raw ) {
return nil , errors .New ("x509: trailing data" )
}
return cert , err
}
func ParseCertificates (der []byte ) ([]*Certificate , error ) {
var certs []*Certificate
for len (der ) > 0 {
cert , err := parseCertificate (der )
if err != nil {
return nil , err
}
certs = append (certs , cert )
der = der [len (cert .Raw ):]
}
return certs , nil
}
const x509v2Version = 1
func ParseRevocationList (der []byte ) (*RevocationList , error ) {
rl := &RevocationList {}
input := cryptobyte .String (der )
if !input .ReadASN1Element (&input , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed crl" )
}
rl .Raw = input
if !input .ReadASN1 (&input , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed crl" )
}
var tbs cryptobyte .String
if !input .ReadASN1Element (&tbs , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed tbs crl" )
}
rl .RawTBSRevocationList = tbs
if !tbs .ReadASN1 (&tbs , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed tbs crl" )
}
var version int
if !tbs .PeekASN1Tag (cryptobyte_asn1 .INTEGER ) {
return nil , errors .New ("x509: unsupported crl version" )
}
if !tbs .ReadASN1Integer (&version ) {
return nil , errors .New ("x509: malformed crl" )
}
if version != x509v2Version {
return nil , fmt .Errorf ("x509: unsupported crl version: %d" , version )
}
var sigAISeq cryptobyte .String
if !tbs .ReadASN1 (&sigAISeq , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed signature algorithm identifier" )
}
var outerSigAISeq cryptobyte .String
if !input .ReadASN1 (&outerSigAISeq , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed algorithm identifier" )
}
if !bytes .Equal (outerSigAISeq , sigAISeq ) {
return nil , errors .New ("x509: inner and outer signature algorithm identifiers don't match" )
}
sigAI , err := parseAI (sigAISeq )
if err != nil {
return nil , err
}
rl .SignatureAlgorithm = getSignatureAlgorithmFromAI (sigAI )
var signature asn1 .BitString
if !input .ReadASN1BitString (&signature ) {
return nil , errors .New ("x509: malformed signature" )
}
rl .Signature = signature .RightAlign ()
var issuerSeq cryptobyte .String
if !tbs .ReadASN1Element (&issuerSeq , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed issuer" )
}
rl .RawIssuer = issuerSeq
issuerRDNs , err := parseName (issuerSeq )
if err != nil {
return nil , err
}
rl .Issuer .FillFromRDNSequence (issuerRDNs )
rl .ThisUpdate , err = parseTime (&tbs )
if err != nil {
return nil , err
}
if tbs .PeekASN1Tag (cryptobyte_asn1 .GeneralizedTime ) || tbs .PeekASN1Tag (cryptobyte_asn1 .UTCTime ) {
rl .NextUpdate , err = parseTime (&tbs )
if err != nil {
return nil , err
}
}
if tbs .PeekASN1Tag (cryptobyte_asn1 .SEQUENCE ) {
var revokedSeq cryptobyte .String
if !tbs .ReadASN1 (&revokedSeq , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed crl" )
}
for !revokedSeq .Empty () {
rce := RevocationListEntry {}
var certSeq cryptobyte .String
if !revokedSeq .ReadASN1Element (&certSeq , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed crl" )
}
rce .Raw = certSeq
if !certSeq .ReadASN1 (&certSeq , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed crl" )
}
rce .SerialNumber = new (big .Int )
if !certSeq .ReadASN1Integer (rce .SerialNumber ) {
return nil , errors .New ("x509: malformed serial number" )
}
rce .RevocationTime , err = parseTime (&certSeq )
if err != nil {
return nil , err
}
var extensions cryptobyte .String
var present bool
if !certSeq .ReadOptionalASN1 (&extensions , &present , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed extensions" )
}
if present {
for !extensions .Empty () {
var extension cryptobyte .String
if !extensions .ReadASN1 (&extension , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed extension" )
}
ext , err := parseExtension (extension )
if err != nil {
return nil , err
}
if ext .Id .Equal (oidExtensionReasonCode ) {
val := cryptobyte .String (ext .Value )
if !val .ReadASN1Enum (&rce .ReasonCode ) {
return nil , fmt .Errorf ("x509: malformed reasonCode extension" )
}
}
rce .Extensions = append (rce .Extensions , ext )
}
}
rl .RevokedCertificateEntries = append (rl .RevokedCertificateEntries , rce )
rcDeprecated := pkix .RevokedCertificate {
SerialNumber : rce .SerialNumber ,
RevocationTime : rce .RevocationTime ,
Extensions : rce .Extensions ,
}
rl .RevokedCertificates = append (rl .RevokedCertificates , rcDeprecated )
}
}
var extensions cryptobyte .String
var present bool
if !tbs .ReadOptionalASN1 (&extensions , &present , cryptobyte_asn1 .Tag (0 ).Constructed ().ContextSpecific ()) {
return nil , errors .New ("x509: malformed extensions" )
}
if present {
if !extensions .ReadASN1 (&extensions , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed extensions" )
}
for !extensions .Empty () {
var extension cryptobyte .String
if !extensions .ReadASN1 (&extension , cryptobyte_asn1 .SEQUENCE ) {
return nil , errors .New ("x509: malformed extension" )
}
ext , err := parseExtension (extension )
if err != nil {
return nil , err
}
if ext .Id .Equal (oidExtensionAuthorityKeyId ) {
rl .AuthorityKeyId , err = parseAuthorityKeyIdentifier (ext )
if err != nil {
return nil , err
}
} else if ext .Id .Equal (oidExtensionCRLNumber ) {
value := cryptobyte .String (ext .Value )
rl .Number = new (big .Int )
if !value .ReadASN1Integer (rl .Number ) {
return nil , errors .New ("x509: malformed crl number" )
}
}
rl .Extensions = append (rl .Extensions , ext )
}
}
return rl , nil
}
The pages are generated with Golds v0.7.0-preview . (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 @zigo_101 (reachable from the left QR code) to get the latest news of Golds .