github.com/zmap/zcrypto@v0.0.0-20240512203510-0fef58d9a9db/x509/extensions.go (about)

     1  // Copyright 2015 The Go Authors. All rights reserved.
     2  // Use of this source code is governed by a BSD-style
     3  // license that can be found in the LICENSE file.
     4  
     5  package x509
     6  
     7  import (
     8  	"encoding/hex"
     9  	"encoding/json"
    10  	"net"
    11  	"strconv"
    12  	"strings"
    13  
    14  	"github.com/zmap/zcrypto/encoding/asn1"
    15  	"github.com/zmap/zcrypto/x509/ct"
    16  	"github.com/zmap/zcrypto/x509/pkix"
    17  )
    18  
    19  var (
    20  	oidExtKeyUsage           = asn1.ObjectIdentifier{2, 5, 29, 15}
    21  	oidExtBasicConstraints   = asn1.ObjectIdentifier{2, 5, 29, 19}
    22  	oidExtSubjectAltName     = asn1.ObjectIdentifier{2, 5, 29, 17}
    23  	oidExtIssuerAltName      = asn1.ObjectIdentifier{2, 5, 29, 18}
    24  	oidExtNameConstraints    = asn1.ObjectIdentifier{2, 5, 29, 30}
    25  	oidCRLDistributionPoints = asn1.ObjectIdentifier{2, 5, 29, 31}
    26  	oidExtAuthKeyId          = asn1.ObjectIdentifier{2, 5, 29, 35}
    27  	oidExtSubjectKeyId       = asn1.ObjectIdentifier{2, 5, 29, 14}
    28  	oidExtExtendedKeyUsage   = asn1.ObjectIdentifier{2, 5, 29, 37}
    29  	oidExtCertificatePolicy  = asn1.ObjectIdentifier{2, 5, 29, 32}
    30  	oidExtensionCRLNumber    = asn1.ObjectIdentifier{2, 5, 29, 20}
    31  	oidExtensionReasonCode   = asn1.ObjectIdentifier{2, 5, 29, 21}
    32  
    33  	oidExtAuthorityInfoAccess            = oidExtensionAuthorityInfoAccess
    34  	oidExtensionCTPrecertificatePoison   = asn1.ObjectIdentifier{1, 3, 6, 1, 4, 1, 11129, 2, 4, 3}
    35  	oidExtSignedCertificateTimestampList = oidExtensionSignedCertificateTimestampList
    36  
    37  	oidExtCABFOrganizationID = asn1.ObjectIdentifier{2, 23, 140, 3, 1}
    38  	oidExtQCStatements       = asn1.ObjectIdentifier{1, 3, 6, 1, 5, 5, 7, 1, 3}
    39  )
    40  
    41  type CertificateExtensions struct {
    42  	KeyUsage                       KeyUsage                         `json:"key_usage,omitempty"`
    43  	BasicConstraints               *BasicConstraints                `json:"basic_constraints,omitempty"`
    44  	SubjectAltName                 *GeneralNames                    `json:"subject_alt_name,omitempty"`
    45  	IssuerAltName                  *GeneralNames                    `json:"issuer_alt_name,omitempty"`
    46  	NameConstraints                *NameConstraints                 `json:"name_constraints,omitempty"`
    47  	CRLDistributionPoints          CRLDistributionPoints            `json:"crl_distribution_points,omitempty"`
    48  	AuthKeyID                      SubjAuthKeyId                    `json:"authority_key_id,omitempty"`
    49  	SubjectKeyID                   SubjAuthKeyId                    `json:"subject_key_id,omitempty"`
    50  	ExtendedKeyUsage               *ExtendedKeyUsageExtension       `json:"extended_key_usage,omitempty"`
    51  	CertificatePolicies            *CertificatePoliciesData         `json:"certificate_policies,omitempty"`
    52  	AuthorityInfoAccess            *AuthorityInfoAccess             `json:"authority_info_access,omitempty"`
    53  	IsPrecert                      IsPrecert                        `json:"ct_poison,omitempty"`
    54  	SignedCertificateTimestampList []*ct.SignedCertificateTimestamp `json:"signed_certificate_timestamps,omitempty"`
    55  	TorServiceDescriptors          []*TorServiceDescriptorHash      `json:"tor_service_descriptors,omitempty"`
    56  	CABFOrganizationIdentifier     *CABFOrganizationIdentifier      `json:"cabf_organization_id,omitempty"`
    57  	QCStatements                   *QCStatements                    `json:"qc_statements,omitempty"`
    58  }
    59  
    60  type UnknownCertificateExtensions []pkix.Extension
    61  
    62  type IsPrecert bool
    63  
    64  type BasicConstraints struct {
    65  	IsCA       bool `json:"is_ca"`
    66  	MaxPathLen *int `json:"max_path_len,omitempty"`
    67  }
    68  
    69  type NoticeReference struct {
    70  	Organization  string       `json:"organization,omitempty"`
    71  	NoticeNumbers NoticeNumber `json:"notice_numbers,omitempty"`
    72  }
    73  
    74  type UserNoticeData struct {
    75  	ExplicitText    string            `json:"explicit_text,omitempty"`
    76  	NoticeReference []NoticeReference `json:"notice_reference,omitempty"`
    77  }
    78  
    79  type CertificatePoliciesJSON struct {
    80  	PolicyIdentifier string           `json:"id,omitempty"`
    81  	CPSUri           []string         `json:"cps,omitempty"`
    82  	UserNotice       []UserNoticeData `json:"user_notice,omitempty"`
    83  }
    84  
    85  type CertificatePolicies []CertificatePoliciesJSON
    86  
    87  type CertificatePoliciesData struct {
    88  	PolicyIdentifiers     []asn1.ObjectIdentifier
    89  	QualifierId           [][]asn1.ObjectIdentifier
    90  	CPSUri                [][]string
    91  	ExplicitTexts         [][]string
    92  	NoticeRefOrganization [][]string
    93  	NoticeRefNumbers      [][]NoticeNumber
    94  }
    95  
    96  func (cp *CertificatePoliciesData) MarshalJSON() ([]byte, error) {
    97  	policies := CertificatePolicies{}
    98  	for idx, oid := range cp.PolicyIdentifiers {
    99  		cpsJSON := CertificatePoliciesJSON{}
   100  		cpsJSON.PolicyIdentifier = oid.String()
   101  		for _, uri := range cp.CPSUri[idx] {
   102  			cpsJSON.CPSUri = append(cpsJSON.CPSUri, uri)
   103  		}
   104  
   105  		for idx2, explicit_text := range cp.ExplicitTexts[idx] {
   106  			uNoticeData := UserNoticeData{}
   107  			uNoticeData.ExplicitText = explicit_text
   108  			noticeRef := NoticeReference{}
   109  			if len(cp.NoticeRefOrganization[idx]) > 0 {
   110  				organization := cp.NoticeRefOrganization[idx][idx2]
   111  				noticeRef.Organization = organization
   112  				noticeRef.NoticeNumbers = cp.NoticeRefNumbers[idx][idx2]
   113  				uNoticeData.NoticeReference = append(uNoticeData.NoticeReference, noticeRef)
   114  			}
   115  			cpsJSON.UserNotice = append(cpsJSON.UserNotice, uNoticeData)
   116  		}
   117  
   118  		policies = append(policies, cpsJSON)
   119  	}
   120  	return json.Marshal(policies)
   121  }
   122  
   123  // GeneralNames corresponds an X.509 GeneralName defined in
   124  // Section 4.2.1.6 of RFC 5280.
   125  //
   126  //	GeneralName ::= CHOICE {
   127  //	     otherName                 [0]  AnotherName,
   128  //	     rfc822Name                [1]  IA5String,
   129  //	     dNSName                   [2]  IA5String,
   130  //	     x400Address               [3]  ORAddress,
   131  //	     directoryName             [4]  Name,
   132  //	     ediPartyName              [5]  EDIPartyName,
   133  //	     uniformResourceIdentifier [6]  IA5String,
   134  //	     iPAddress                 [7]  OCTET STRING,
   135  //	     registeredID              [8]  OBJECT IDENTIFIER }
   136  type GeneralNames struct {
   137  	DirectoryNames []pkix.Name
   138  	DNSNames       []string
   139  	EDIPartyNames  []pkix.EDIPartyName
   140  	EmailAddresses []string
   141  	IPAddresses    []net.IP
   142  	OtherNames     []pkix.OtherName
   143  	RegisteredIDs  []asn1.ObjectIdentifier
   144  	URIs           []string
   145  }
   146  
   147  type jsonGeneralNames struct {
   148  	DirectoryNames []pkix.Name         `json:"directory_names,omitempty"`
   149  	DNSNames       []string            `json:"dns_names,omitempty"`
   150  	EDIPartyNames  []pkix.EDIPartyName `json:"edi_party_names,omitempty"`
   151  	EmailAddresses []string            `json:"email_addresses,omitempty"`
   152  	IPAddresses    []net.IP            `json:"ip_addresses,omitempty"`
   153  	OtherNames     []pkix.OtherName    `json:"other_names,omitempty"`
   154  	RegisteredIDs  []string            `json:"registered_ids,omitempty"`
   155  	URIs           []string            `json:"uniform_resource_identifiers,omitempty"`
   156  }
   157  
   158  func (gn *GeneralNames) MarshalJSON() ([]byte, error) {
   159  	jsan := jsonGeneralNames{
   160  		DirectoryNames: gn.DirectoryNames,
   161  		DNSNames:       gn.DNSNames,
   162  		EDIPartyNames:  gn.EDIPartyNames,
   163  		EmailAddresses: gn.EmailAddresses,
   164  		IPAddresses:    gn.IPAddresses,
   165  		OtherNames:     gn.OtherNames,
   166  		RegisteredIDs:  make([]string, 0, len(gn.RegisteredIDs)),
   167  		URIs:           gn.URIs,
   168  	}
   169  	for _, id := range gn.RegisteredIDs {
   170  		jsan.RegisteredIDs = append(jsan.RegisteredIDs, id.String())
   171  	}
   172  	return json.Marshal(jsan)
   173  }
   174  
   175  func (gn *GeneralNames) UnmarshalJSON(b []byte) error {
   176  	var jsan jsonGeneralNames
   177  	err := json.Unmarshal(b, &jsan)
   178  	if err != nil {
   179  		return err
   180  	}
   181  
   182  	gn.DirectoryNames = jsan.DirectoryNames
   183  	gn.DNSNames = jsan.DNSNames
   184  	gn.EDIPartyNames = jsan.EDIPartyNames
   185  	gn.EmailAddresses = jsan.EmailAddresses
   186  	gn.IPAddresses = jsan.IPAddresses
   187  	gn.OtherNames = jsan.OtherNames
   188  	gn.RegisteredIDs = make([]asn1.ObjectIdentifier, len(jsan.RegisteredIDs))
   189  	gn.URIs = jsan.URIs
   190  
   191  	for i, rID := range jsan.RegisteredIDs {
   192  		arcs := strings.Split(rID, ".")
   193  		oid := make(asn1.ObjectIdentifier, len(arcs))
   194  
   195  		for j, s := range arcs {
   196  			tmp, err := strconv.ParseInt(s, 10, 32)
   197  			if err != nil {
   198  				return err
   199  			}
   200  			oid[j] = int(tmp)
   201  		}
   202  		gn.RegisteredIDs[i] = oid
   203  	}
   204  	return nil
   205  }
   206  
   207  // TODO: Handle excluded names
   208  
   209  type NameConstraints struct {
   210  	Critical bool `json:"critical"`
   211  
   212  	PermittedDNSNames       []GeneralSubtreeString
   213  	PermittedEmailAddresses []GeneralSubtreeString
   214  	PermittedURIs           []GeneralSubtreeString
   215  	PermittedIPAddresses    []GeneralSubtreeIP
   216  	PermittedDirectoryNames []GeneralSubtreeName
   217  	PermittedEdiPartyNames  []GeneralSubtreeEdi
   218  	PermittedRegisteredIDs  []GeneralSubtreeOid
   219  
   220  	ExcludedEmailAddresses []GeneralSubtreeString
   221  	ExcludedDNSNames       []GeneralSubtreeString
   222  	ExcludedURIs           []GeneralSubtreeString
   223  	ExcludedIPAddresses    []GeneralSubtreeIP
   224  	ExcludedDirectoryNames []GeneralSubtreeName
   225  	ExcludedEdiPartyNames  []GeneralSubtreeEdi
   226  	ExcludedRegisteredIDs  []GeneralSubtreeOid
   227  }
   228  
   229  type NameConstraintsJSON struct {
   230  	Critical bool `json:"critical"`
   231  
   232  	PermittedDNSNames       []string            `json:"permitted_names,omitempty"`
   233  	PermittedEmailAddresses []string            `json:"permitted_email_addresses,omitempty"`
   234  	PermittedURIs           []string            `json:"permitted_uris,omitempty"`
   235  	PermittedIPAddresses    []GeneralSubtreeIP  `json:"permitted_ip_addresses,omitempty"`
   236  	PermittedDirectoryNames []pkix.Name         `json:"permitted_directory_names,omitempty"`
   237  	PermittedEdiPartyNames  []pkix.EDIPartyName `json:"permitted_edi_party_names,omitempty"`
   238  	PermittedRegisteredIDs  []string            `json:"permitted_registred_id,omitempty"`
   239  
   240  	ExcludedDNSNames       []string            `json:"excluded_names,omitempty"`
   241  	ExcludedEmailAddresses []string            `json:"excluded_email_addresses,omitempty"`
   242  	ExcludedURIs           []string            `json:"excluded_uris,omitempty"`
   243  	ExcludedIPAddresses    []GeneralSubtreeIP  `json:"excluded_ip_addresses,omitempty"`
   244  	ExcludedDirectoryNames []pkix.Name         `json:"excluded_directory_names,omitempty"`
   245  	ExcludedEdiPartyNames  []pkix.EDIPartyName `json:"excluded_edi_party_names,omitempty"`
   246  	ExcludedRegisteredIDs  []string            `json:"excluded_registred_id,omitempty"`
   247  }
   248  
   249  func (nc *NameConstraints) UnmarshalJSON(b []byte) error {
   250  	var ncJson NameConstraintsJSON
   251  	err := json.Unmarshal(b, &ncJson)
   252  	if err != nil {
   253  		return err
   254  	}
   255  	for _, dns := range ncJson.PermittedDNSNames {
   256  		nc.PermittedDNSNames = append(nc.PermittedDNSNames, GeneralSubtreeString{Data: dns})
   257  	}
   258  	for _, email := range ncJson.PermittedEmailAddresses {
   259  		nc.PermittedEmailAddresses = append(nc.PermittedEmailAddresses, GeneralSubtreeString{Data: email})
   260  	}
   261  	for _, uri := range ncJson.PermittedURIs {
   262  		nc.PermittedURIs = append(nc.PermittedURIs, GeneralSubtreeString{Data: uri})
   263  	}
   264  	for _, constraint := range ncJson.PermittedIPAddresses {
   265  		nc.PermittedIPAddresses = append(nc.PermittedIPAddresses, constraint)
   266  	}
   267  	for _, directory := range ncJson.PermittedDirectoryNames {
   268  		nc.PermittedDirectoryNames = append(nc.PermittedDirectoryNames, GeneralSubtreeName{Data: directory})
   269  	}
   270  	for _, edi := range ncJson.PermittedEdiPartyNames {
   271  		nc.PermittedEdiPartyNames = append(nc.PermittedEdiPartyNames, GeneralSubtreeEdi{Data: edi})
   272  	}
   273  	for _, id := range ncJson.PermittedRegisteredIDs {
   274  		arcs := strings.Split(id, ".")
   275  		oid := make(asn1.ObjectIdentifier, len(arcs))
   276  
   277  		for j, s := range arcs {
   278  			tmp, err := strconv.ParseInt(s, 10, 32)
   279  			if err != nil {
   280  				return err
   281  			}
   282  			oid[j] = int(tmp)
   283  		}
   284  		nc.PermittedRegisteredIDs = append(nc.PermittedRegisteredIDs, GeneralSubtreeOid{Data: oid})
   285  	}
   286  
   287  	for _, dns := range ncJson.ExcludedDNSNames {
   288  		nc.ExcludedDNSNames = append(nc.ExcludedDNSNames, GeneralSubtreeString{Data: dns})
   289  	}
   290  	for _, email := range ncJson.ExcludedEmailAddresses {
   291  		nc.ExcludedEmailAddresses = append(nc.ExcludedEmailAddresses, GeneralSubtreeString{Data: email})
   292  	}
   293  	for _, uri := range ncJson.ExcludedURIs {
   294  		nc.ExcludedURIs = append(nc.ExcludedURIs, GeneralSubtreeString{Data: uri})
   295  	}
   296  	for _, constraint := range ncJson.ExcludedIPAddresses {
   297  		nc.ExcludedIPAddresses = append(nc.ExcludedIPAddresses, constraint)
   298  	}
   299  	for _, directory := range ncJson.ExcludedDirectoryNames {
   300  		nc.ExcludedDirectoryNames = append(nc.ExcludedDirectoryNames, GeneralSubtreeName{Data: directory})
   301  	}
   302  	for _, edi := range ncJson.ExcludedEdiPartyNames {
   303  		nc.ExcludedEdiPartyNames = append(nc.ExcludedEdiPartyNames, GeneralSubtreeEdi{Data: edi})
   304  	}
   305  	for _, id := range ncJson.ExcludedRegisteredIDs {
   306  		arcs := strings.Split(id, ".")
   307  		oid := make(asn1.ObjectIdentifier, len(arcs))
   308  
   309  		for j, s := range arcs {
   310  			tmp, err := strconv.ParseInt(s, 10, 32)
   311  			if err != nil {
   312  				return err
   313  			}
   314  			oid[j] = int(tmp)
   315  		}
   316  		nc.ExcludedRegisteredIDs = append(nc.ExcludedRegisteredIDs, GeneralSubtreeOid{Data: oid})
   317  	}
   318  	return nil
   319  }
   320  
   321  func (nc NameConstraints) MarshalJSON() ([]byte, error) {
   322  	var out NameConstraintsJSON
   323  	for _, dns := range nc.PermittedDNSNames {
   324  		out.PermittedDNSNames = append(out.PermittedDNSNames, dns.Data)
   325  	}
   326  	for _, email := range nc.PermittedEmailAddresses {
   327  		out.PermittedEmailAddresses = append(out.PermittedEmailAddresses, email.Data)
   328  	}
   329  	for _, uri := range nc.PermittedURIs {
   330  		out.PermittedURIs = append(out.PermittedURIs, uri.Data)
   331  	}
   332  	out.PermittedIPAddresses = nc.PermittedIPAddresses
   333  	for _, directory := range nc.PermittedDirectoryNames {
   334  		out.PermittedDirectoryNames = append(out.PermittedDirectoryNames, directory.Data)
   335  	}
   336  	for _, edi := range nc.PermittedEdiPartyNames {
   337  		out.PermittedEdiPartyNames = append(out.PermittedEdiPartyNames, edi.Data)
   338  	}
   339  	for _, id := range nc.PermittedRegisteredIDs {
   340  		out.PermittedRegisteredIDs = append(out.PermittedRegisteredIDs, id.Data.String())
   341  	}
   342  
   343  	for _, dns := range nc.ExcludedDNSNames {
   344  		out.ExcludedDNSNames = append(out.ExcludedDNSNames, dns.Data)
   345  	}
   346  	for _, email := range nc.ExcludedEmailAddresses {
   347  		out.ExcludedEmailAddresses = append(out.ExcludedEmailAddresses, email.Data)
   348  	}
   349  	for _, uri := range nc.ExcludedURIs {
   350  		out.ExcludedURIs = append(out.ExcludedURIs, uri.Data)
   351  	}
   352  	for _, ip := range nc.ExcludedIPAddresses {
   353  		out.ExcludedIPAddresses = append(out.ExcludedIPAddresses, ip)
   354  	}
   355  	for _, directory := range nc.ExcludedDirectoryNames {
   356  		out.ExcludedDirectoryNames = append(out.ExcludedDirectoryNames, directory.Data)
   357  	}
   358  	for _, edi := range nc.ExcludedEdiPartyNames {
   359  		out.ExcludedEdiPartyNames = append(out.ExcludedEdiPartyNames, edi.Data)
   360  	}
   361  	for _, id := range nc.ExcludedRegisteredIDs {
   362  		out.ExcludedRegisteredIDs = append(out.ExcludedRegisteredIDs, id.Data.String())
   363  	}
   364  	return json.Marshal(out)
   365  }
   366  
   367  type CRLDistributionPoints []string
   368  
   369  type SubjAuthKeyId []byte
   370  
   371  func (kid SubjAuthKeyId) MarshalJSON() ([]byte, error) {
   372  	enc := hex.EncodeToString(kid)
   373  	return json.Marshal(enc)
   374  }
   375  
   376  type ExtendedKeyUsage []ExtKeyUsage
   377  
   378  type ExtendedKeyUsageExtension struct {
   379  	Known   ExtendedKeyUsage
   380  	Unknown []asn1.ObjectIdentifier
   381  }
   382  
   383  // MarshalJSON implements the json.Marshal interface. The output is a struct of
   384  // bools, with an additional `Value` field containing the actual OIDs.
   385  func (e *ExtendedKeyUsageExtension) MarshalJSON() ([]byte, error) {
   386  	aux := new(auxExtendedKeyUsage)
   387  	for _, e := range e.Known {
   388  		aux.populateFromExtKeyUsage(e)
   389  	}
   390  	for _, oid := range e.Unknown {
   391  		aux.Unknown = append(aux.Unknown, oid.String())
   392  	}
   393  	return json.Marshal(aux)
   394  }
   395  
   396  func (e *ExtendedKeyUsageExtension) UnmarshalJSON(b []byte) error {
   397  	aux := new(auxExtendedKeyUsage)
   398  	if err := json.Unmarshal(b, aux); err != nil {
   399  		return err
   400  	}
   401  	// TODO: Generate the reverse functions.
   402  	return nil
   403  }
   404  
   405  //go:generate go run extended_key_usage_gen.go
   406  
   407  // The string functions for CertValidationLevel are auto-generated via
   408  // `go generate <full_path_to_x509_package>` or running `go generate` in the package directory
   409  //
   410  //go:generate stringer -type=CertValidationLevel -output=generated_certvalidationlevel_string.go
   411  type CertValidationLevel int
   412  
   413  const (
   414  	UnknownValidationLevel CertValidationLevel = 0
   415  	DV                     CertValidationLevel = 1
   416  	OV                     CertValidationLevel = 2
   417  	EV                     CertValidationLevel = 3
   418  )
   419  
   420  func (c *CertValidationLevel) MarshalJSON() ([]byte, error) {
   421  	if *c == UnknownValidationLevel || *c < 0 || *c > EV {
   422  		return json.Marshal("unknown")
   423  	}
   424  	return json.Marshal(c.String())
   425  }
   426  
   427  // TODO: All of validation-level maps should be auto-generated from
   428  // https://github.com/zmap/constants.
   429  
   430  // ExtendedValidationOIDs contains the UNION of Chromium
   431  // (https://chromium.googlesource.com/chromium/src/net/+/master/cert/ev_root_ca_metadata.cc)
   432  // and Firefox
   433  // (http://hg.mozilla.org/mozilla-central/file/tip/security/certverifier/ExtendedValidation.cpp)
   434  // EV OID lists
   435  var ExtendedValidationOIDs = map[string]interface{}{
   436  	// CA/Browser Forum EV OID standard
   437  	// https://cabforum.org/object-registry/
   438  	"2.23.140.1.1": nil,
   439  	// CA/Browser Forum EV Code Signing
   440  	"2.23.140.1.3": nil,
   441  	// CA/Browser Forum .onion EV Certs
   442  	"2.23.140.1.31": nil,
   443  	// AC Camerfirma S.A. Chambers of Commerce Root - 2008
   444  	// https://www.camerfirma.com
   445  	// AC Camerfirma uses the last two arcs to track how the private key
   446  	// is managed - the effective verification policy is the same.
   447  	"1.3.6.1.4.1.17326.10.14.2.1.2": nil,
   448  	"1.3.6.1.4.1.17326.10.14.2.2.2": nil,
   449  	// AC Camerfirma S.A. Global Chambersign Root - 2008
   450  	// https://server2.camerfirma.com:8082
   451  	// AC Camerfirma uses the last two arcs to track how the private key
   452  	// is managed - the effective verification policy is the same.
   453  	"1.3.6.1.4.1.17326.10.8.12.1.2": nil,
   454  	"1.3.6.1.4.1.17326.10.8.12.2.2": nil,
   455  	// Actalis Authentication Root CA
   456  	// https://ssltest-a.actalis.it:8443
   457  	"1.3.159.1.17.1": nil,
   458  	// AffirmTrust Commercial
   459  	// https://commercial.affirmtrust.com/
   460  	"1.3.6.1.4.1.34697.2.1": nil,
   461  	// AffirmTrust Networking
   462  	// https://networking.affirmtrust.com:4431
   463  	"1.3.6.1.4.1.34697.2.2": nil,
   464  	// AffirmTrust Premium
   465  	// https://premium.affirmtrust.com:4432/
   466  	"1.3.6.1.4.1.34697.2.3": nil,
   467  	// AffirmTrust Premium ECC
   468  	// https://premiumecc.affirmtrust.com:4433/
   469  	"1.3.6.1.4.1.34697.2.4": nil,
   470  	// Autoridad de Certificacion Firmaprofesional CIF A62634068
   471  	// https://publifirma.firmaprofesional.com/
   472  	"1.3.6.1.4.1.13177.10.1.3.10": nil,
   473  	// Buypass Class 3 CA 1
   474  	// https://valid.evident.ca13.ssl.buypass.no/
   475  	"2.16.578.1.26.1.3.3": nil,
   476  	// Certification Authority of WoSign
   477  	// CA 沃通根证书
   478  	// https://root2evtest.wosign.com/
   479  	"1.3.6.1.4.1.36305.2": nil,
   480  	// CertPlus Class 2 Primary CA (KEYNECTIS)
   481  	// https://www.keynectis.com/
   482  	"1.3.6.1.4.1.22234.2.5.2.3.1": nil,
   483  	// Certum Trusted Network CA
   484  	// https://juice.certum.pl/
   485  	"1.2.616.1.113527.2.5.1.1": nil,
   486  	// China Internet Network Information Center EV Certificates Root
   487  	// https://evdemo.cnnic.cn/
   488  	"1.3.6.1.4.1.29836.1.10": nil,
   489  	// COMODO Certification Authority & USERTrust RSA Certification Authority & UTN-USERFirst-Hardware & AddTrust External CA Root
   490  	// https://secure.comodo.com/
   491  	// https://usertrustrsacertificationauthority-ev.comodoca.com/
   492  	// https://addtrustexternalcaroot-ev.comodoca.com
   493  	"1.3.6.1.4.1.6449.1.2.1.5.1": nil,
   494  	// Cybertrust Global Root & GTE CyberTrust Global Root & Baltimore CyberTrust Root
   495  	// https://evup.cybertrust.ne.jp/ctj-ev-upgrader/evseal.gif
   496  	// https://www.cybertrust.ne.jp/
   497  	// https://secure.omniroot.com/repository/
   498  	"1.3.6.1.4.1.6334.1.100.1": nil,
   499  	// DigiCert High Assurance EV Root CA
   500  	// https://www.digicert.com
   501  	"2.16.840.1.114412.2.1": nil,
   502  	// D-TRUST Root Class 3 CA 2 EV 2009
   503  	// https://certdemo-ev-valid.ssl.d-trust.net/
   504  	"1.3.6.1.4.1.4788.2.202.1": nil,
   505  	// Entrust.net Secure Server Certification Authority
   506  	// https://www.entrust.net/
   507  	"2.16.840.1.114028.10.1.2": nil,
   508  	// E-Tugra Certification Authority
   509  	// https://sslev.e-tugra.com.tr
   510  	"2.16.792.3.0.4.1.1.4": nil,
   511  	// GeoTrust Primary Certification Authority
   512  	// https://www.geotrust.com/
   513  	"1.3.6.1.4.1.14370.1.6": nil,
   514  	// GlobalSign Root CA - R2
   515  	// https://www.globalsign.com/
   516  	"1.3.6.1.4.1.4146.1.1": nil,
   517  	// Go Daddy Class 2 Certification Authority & Go Daddy Root Certificate Authority - G2
   518  	// https://www.godaddy.com/
   519  	// https://valid.gdig2.catest.godaddy.com/
   520  	"2.16.840.1.114413.1.7.23.3": nil,
   521  	// Izenpe.com - SHA256 root
   522  	// The first OID is for businesses and the second for government entities.
   523  	// These are the test sites, respectively:
   524  	// https://servicios.izenpe.com
   525  	// https://servicios1.izenpe.com
   526  	// Windows XP finds this, SHA1, root instead. The policy OIDs are the same
   527  	// as for the SHA256 root, above.
   528  	"1.3.6.1.4.1.14777.6.1.1": nil,
   529  	"1.3.6.1.4.1.14777.6.1.2": nil,
   530  	// Network Solutions Certificate Authority
   531  	// https://www.networksolutions.com/website-packages/index.jsp
   532  	"1.3.6.1.4.1.782.1.2.1.8.1": nil,
   533  	// QuoVadis Root CA 2
   534  	// https://www.quovadis.bm/
   535  	"1.3.6.1.4.1.8024.0.2.100.1.2": nil,
   536  	// SecureTrust CA, SecureTrust Corporation
   537  	// https://www.securetrust.com
   538  	// https://www.trustwave.com/
   539  	"2.16.840.1.114404.1.1.2.4.1": nil,
   540  	// Security Communication RootCA1
   541  	// https://www.secomtrust.net/contact/form.html
   542  	"1.2.392.200091.100.721.1": nil,
   543  	// Staat der Nederlanden EV Root CA
   544  	// https://pkioevssl-v.quovadisglobal.com/
   545  	"2.16.528.1.1003.1.2.7": nil,
   546  	// StartCom Certification Authority
   547  	// https://www.startssl.com/
   548  	"1.3.6.1.4.1.23223.1.1.1": nil,
   549  	// Starfield Class 2 Certification Authority
   550  	// https://www.starfieldtech.com/
   551  	"2.16.840.1.114414.1.7.23.3": nil,
   552  	// Starfield Services Root Certificate Authority - G2
   553  	// https://valid.sfsg2.catest.starfieldtech.com/
   554  	"2.16.840.1.114414.1.7.24.3": nil,
   555  	// SwissSign Gold CA - G2
   556  	// https://testevg2.swisssign.net/
   557  	"2.16.756.1.89.1.2.1.1": nil,
   558  	// Swisscom Root EV CA 2
   559  	// https://test-quarz-ev-ca-2.pre.swissdigicert.ch
   560  	"2.16.756.1.83.21.0": nil,
   561  	// thawte Primary Root CA
   562  	// https://www.thawte.com/
   563  	"2.16.840.1.113733.1.7.48.1": nil,
   564  	// TWCA Global Root CA
   565  	// https://evssldemo3.twca.com.tw/index.html
   566  	"1.3.6.1.4.1.40869.1.1.22.3": nil,
   567  	// T-TeleSec GlobalRoot Class 3
   568  	// http://www.telesec.de/ / https://root-class3.test.telesec.de/
   569  	"1.3.6.1.4.1.7879.13.24.1": nil,
   570  	// VeriSign Class 3 Public Primary Certification Authority - G5
   571  	// https://www.verisign.com/
   572  	"2.16.840.1.113733.1.7.23.6": nil,
   573  	// Wells Fargo WellsSecure Public Root Certificate Authority
   574  	// https://nerys.wellsfargo.com/test.html
   575  	"2.16.840.1.114171.500.9": nil,
   576  	// CN=CFCA EV ROOT,O=China Financial Certification Authority,C=CN
   577  	// https://www.cfca.com.cn/
   578  	"2.16.156.112554.3": nil,
   579  	// CN=OISTE WISeKey Global Root GB CA,OU=OISTE Foundation Endorsed,O=WISeKey,C=CH
   580  	// https://www.wisekey.com/repository/cacertificates/
   581  	"2.16.756.5.14.7.4.8": nil,
   582  	// CN=TÜRKTRUST Elektronik Sertifika Hizmet Sağlayıcısı H6,O=TÜRKTRUST Bilgi İletişim ve Bilişim Güvenliği Hizmetleri A...,L=Ankara,C=TR
   583  	// https://www.turktrust.com.tr/
   584  	"2.16.792.3.0.3.1.1.5": nil,
   585  }
   586  
   587  // OrganizationValidationOIDs contains CA specific OV OIDs from
   588  // https://cabforum.org/object-registry/
   589  var OrganizationValidationOIDs = map[string]interface{}{
   590  	// CA/Browser Forum OV OID standard
   591  	// https://cabforum.org/object-registry/
   592  	"2.23.140.1.2.2": nil,
   593  	// CA/Browser Forum individually validated
   594  	"2.23.140.1.2.3": nil,
   595  	// Digicert
   596  	"2.16.840.1.114412.1.1": nil,
   597  	// D-Trust
   598  	"1.3.6.1.4.1.4788.2.200.1": nil,
   599  	// GoDaddy
   600  	"2.16.840.1.114413.1.7.23.2": nil,
   601  	// Logius
   602  	"2.16.528.1.1003.1.2.5.6": nil,
   603  	// QuoVadis
   604  	"1.3.6.1.4.1.8024.0.2.100.1.1": nil,
   605  	// Starfield
   606  	"2.16.840.1.114414.1.7.23.2": nil,
   607  	// TurkTrust
   608  	"2.16.792.3.0.3.1.1.2": nil,
   609  }
   610  
   611  // DomainValidationOIDs contain OIDs that identify DV certs.
   612  var DomainValidationOIDs = map[string]interface{}{
   613  	// Globalsign
   614  	"1.3.6.1.4.1.4146.1.10.10": nil,
   615  	// Let's Encrypt
   616  	"1.3.6.1.4.1.44947.1.1.1": nil,
   617  	// Comodo (eNom)
   618  	"1.3.6.1.4.1.6449.1.2.2.10": nil,
   619  	// Comodo (WoTrust)
   620  	"1.3.6.1.4.1.6449.1.2.2.15": nil,
   621  	// Comodo (RBC SOFT)
   622  	"1.3.6.1.4.1.6449.1.2.2.16": nil,
   623  	// Comodo (RegisterFly)
   624  	"1.3.6.1.4.1.6449.1.2.2.17": nil,
   625  	// Comodo (Central Security Patrols)
   626  	"1.3.6.1.4.1.6449.1.2.2.18": nil,
   627  	// Comodo (eBiz Networks)
   628  	"1.3.6.1.4.1.6449.1.2.2.19": nil,
   629  	// Comodo (OptimumSSL)
   630  	"1.3.6.1.4.1.6449.1.2.2.21": nil,
   631  	// Comodo (WoSign)
   632  	"1.3.6.1.4.1.6449.1.2.2.22": nil,
   633  	// Comodo (Register.com)
   634  	"1.3.6.1.4.1.6449.1.2.2.24": nil,
   635  	// Comodo (The Code Project)
   636  	"1.3.6.1.4.1.6449.1.2.2.25": nil,
   637  	// Comodo (Gandi)
   638  	"1.3.6.1.4.1.6449.1.2.2.26": nil,
   639  	// Comodo (GlobeSSL)
   640  	"1.3.6.1.4.1.6449.1.2.2.27": nil,
   641  	// Comodo (DreamHost)
   642  	"1.3.6.1.4.1.6449.1.2.2.28": nil,
   643  	// Comodo (TERENA)
   644  	"1.3.6.1.4.1.6449.1.2.2.29": nil,
   645  	// Comodo (GlobalSSL)
   646  	"1.3.6.1.4.1.6449.1.2.2.31": nil,
   647  	// Comodo (IceWarp)
   648  	"1.3.6.1.4.1.6449.1.2.2.35": nil,
   649  	// Comodo (Dotname Korea)
   650  	"1.3.6.1.4.1.6449.1.2.2.37": nil,
   651  	// Comodo (TrustSign)
   652  	"1.3.6.1.4.1.6449.1.2.2.38": nil,
   653  	// Comodo (Formidable)
   654  	"1.3.6.1.4.1.6449.1.2.2.39": nil,
   655  	// Comodo (SSL Blindado)
   656  	"1.3.6.1.4.1.6449.1.2.2.40": nil,
   657  	// Comodo (Dreamscape Networks)
   658  	"1.3.6.1.4.1.6449.1.2.2.41": nil,
   659  	// Comodo (K Software)
   660  	"1.3.6.1.4.1.6449.1.2.2.42": nil,
   661  	// Comodo (FBS)
   662  	"1.3.6.1.4.1.6449.1.2.2.44": nil,
   663  	// Comodo (ReliaSite)
   664  	"1.3.6.1.4.1.6449.1.2.2.45": nil,
   665  	// Comodo (CertAssure)
   666  	"1.3.6.1.4.1.6449.1.2.2.47": nil,
   667  	// Comodo (TrustAsia)
   668  	"1.3.6.1.4.1.6449.1.2.2.49": nil,
   669  	// Comodo (SecureCore)
   670  	"1.3.6.1.4.1.6449.1.2.2.50": nil,
   671  	// Comodo (Western Digital)
   672  	"1.3.6.1.4.1.6449.1.2.2.51": nil,
   673  	// Comodo (cPanel)
   674  	"1.3.6.1.4.1.6449.1.2.2.52": nil,
   675  	// Comodo (BlackCert)
   676  	"1.3.6.1.4.1.6449.1.2.2.53": nil,
   677  	// Comodo (KeyNet Systems)
   678  	"1.3.6.1.4.1.6449.1.2.2.54": nil,
   679  	// Comodo
   680  	"1.3.6.1.4.1.6449.1.2.2.7": nil,
   681  	// Comodo (CSC)
   682  	"1.3.6.1.4.1.6449.1.2.2.8": nil,
   683  	// Digicert
   684  	"2.16.840.1.114412.1.2": nil,
   685  	// GoDaddy
   686  	"2.16.840.1.114413.1.7.23.1": nil,
   687  	// Starfield
   688  	"2.16.840.1.114414.1.7.23.1": nil,
   689  	// CA/B Forum
   690  	"2.23.140.1.2.1": nil,
   691  }
   692  
   693  // TODO pull out other types
   694  type AuthorityInfoAccess struct {
   695  	OCSPServer            []string `json:"ocsp_urls,omitempty"`
   696  	IssuingCertificateURL []string `json:"issuer_urls,omitempty"`
   697  }
   698  
   699  /*
   700  	    id-CABFOrganizationIdentifier OBJECT IDENTIFIER ::= { joint-iso-itu-t(2) international-organizations(23) ca-browser-forum(140) certificate-extensions(3) cabf-organization-identifier(1) }
   701  
   702  	    ext-CABFOrganizationIdentifier EXTENSION ::= { SYNTAX CABFOrganizationIdentifier IDENTIFIED BY id-CABFOrganizationIdentifier }
   703  
   704  	    CABFOrganizationIdentifier ::= SEQUENCE {
   705  
   706  	        registrationSchemeIdentifier   PrintableString (SIZE(3)),
   707  
   708  	        registrationCountry            PrintableString (SIZE(2)),
   709  
   710  	        registrationStateOrProvince    [0] IMPLICIT PrintableString OPTIONAL (SIZE(0..128)),
   711  
   712  	        registrationReference          UTF8String
   713  
   714  		}
   715  */
   716  type CABFOrganizationIDASN struct {
   717  	RegistrationSchemeIdentifier string `asn1:"printable"`
   718  	RegistrationCountry          string `asn1:"printable"`
   719  	RegistrationStateOrProvince  string `asn1:"printable,optional,tag:0"`
   720  	RegistrationReference        string `asn1:"utf8"`
   721  }
   722  
   723  type CABFOrganizationIdentifier struct {
   724  	Scheme    string `json:"scheme,omitempty"`
   725  	Country   string `json:"country,omitempty"`
   726  	State     string `json:"state,omitempty"`
   727  	Reference string `json:"reference,omitempty"`
   728  }
   729  
   730  func (c *Certificate) jsonifyExtensions() (*CertificateExtensions, UnknownCertificateExtensions) {
   731  	exts := new(CertificateExtensions)
   732  	unk := make([]pkix.Extension, 0, 2)
   733  	for _, e := range c.Extensions {
   734  		if e.Id.Equal(oidExtKeyUsage) {
   735  			exts.KeyUsage = c.KeyUsage
   736  		} else if e.Id.Equal(oidExtBasicConstraints) {
   737  			exts.BasicConstraints = new(BasicConstraints)
   738  			exts.BasicConstraints.IsCA = c.IsCA
   739  			if c.MaxPathLen > 0 || c.MaxPathLenZero {
   740  				exts.BasicConstraints.MaxPathLen = new(int)
   741  				*exts.BasicConstraints.MaxPathLen = c.MaxPathLen
   742  			}
   743  		} else if e.Id.Equal(oidExtSubjectAltName) {
   744  			exts.SubjectAltName = new(GeneralNames)
   745  			exts.SubjectAltName.DirectoryNames = c.DirectoryNames
   746  			exts.SubjectAltName.DNSNames = c.DNSNames
   747  			exts.SubjectAltName.EDIPartyNames = c.EDIPartyNames
   748  			exts.SubjectAltName.EmailAddresses = c.EmailAddresses
   749  			exts.SubjectAltName.IPAddresses = c.IPAddresses
   750  			exts.SubjectAltName.OtherNames = c.OtherNames
   751  			exts.SubjectAltName.RegisteredIDs = c.RegisteredIDs
   752  			exts.SubjectAltName.URIs = c.URIs
   753  		} else if e.Id.Equal(oidExtIssuerAltName) {
   754  			exts.IssuerAltName = new(GeneralNames)
   755  			exts.IssuerAltName.DirectoryNames = c.IANDirectoryNames
   756  			exts.IssuerAltName.DNSNames = c.IANDNSNames
   757  			exts.IssuerAltName.EDIPartyNames = c.IANEDIPartyNames
   758  			exts.IssuerAltName.EmailAddresses = c.IANEmailAddresses
   759  			exts.IssuerAltName.IPAddresses = c.IANIPAddresses
   760  			exts.IssuerAltName.OtherNames = c.IANOtherNames
   761  			exts.IssuerAltName.RegisteredIDs = c.IANRegisteredIDs
   762  			exts.IssuerAltName.URIs = c.IANURIs
   763  		} else if e.Id.Equal(oidExtNameConstraints) {
   764  			exts.NameConstraints = new(NameConstraints)
   765  			exts.NameConstraints.Critical = c.NameConstraintsCritical
   766  
   767  			exts.NameConstraints.PermittedDNSNames = c.PermittedDNSNames
   768  			exts.NameConstraints.PermittedEmailAddresses = c.PermittedEmailAddresses
   769  			exts.NameConstraints.PermittedURIs = c.PermittedURIs
   770  			exts.NameConstraints.PermittedIPAddresses = c.PermittedIPAddresses
   771  			exts.NameConstraints.PermittedDirectoryNames = c.PermittedDirectoryNames
   772  			exts.NameConstraints.PermittedEdiPartyNames = c.PermittedEdiPartyNames
   773  			exts.NameConstraints.PermittedRegisteredIDs = c.PermittedRegisteredIDs
   774  
   775  			exts.NameConstraints.ExcludedEmailAddresses = c.ExcludedEmailAddresses
   776  			exts.NameConstraints.ExcludedDNSNames = c.ExcludedDNSNames
   777  			exts.NameConstraints.ExcludedURIs = c.ExcludedURIs
   778  			exts.NameConstraints.ExcludedIPAddresses = c.ExcludedIPAddresses
   779  			exts.NameConstraints.ExcludedDirectoryNames = c.ExcludedDirectoryNames
   780  			exts.NameConstraints.ExcludedEdiPartyNames = c.ExcludedEdiPartyNames
   781  			exts.NameConstraints.ExcludedRegisteredIDs = c.ExcludedRegisteredIDs
   782  		} else if e.Id.Equal(oidCRLDistributionPoints) {
   783  			exts.CRLDistributionPoints = c.CRLDistributionPoints
   784  		} else if e.Id.Equal(oidExtAuthKeyId) {
   785  			exts.AuthKeyID = c.AuthorityKeyId
   786  		} else if e.Id.Equal(oidExtExtendedKeyUsage) {
   787  			exts.ExtendedKeyUsage = new(ExtendedKeyUsageExtension)
   788  			exts.ExtendedKeyUsage.Known = c.ExtKeyUsage
   789  			exts.ExtendedKeyUsage.Unknown = c.UnknownExtKeyUsage
   790  		} else if e.Id.Equal(oidExtCertificatePolicy) {
   791  			exts.CertificatePolicies = new(CertificatePoliciesData)
   792  			exts.CertificatePolicies.PolicyIdentifiers = c.PolicyIdentifiers
   793  			exts.CertificatePolicies.NoticeRefNumbers = c.NoticeRefNumbers
   794  			exts.CertificatePolicies.NoticeRefOrganization = c.ParsedNoticeRefOrganization
   795  			exts.CertificatePolicies.ExplicitTexts = c.ParsedExplicitTexts
   796  			exts.CertificatePolicies.QualifierId = c.QualifierId
   797  			exts.CertificatePolicies.CPSUri = c.CPSuri
   798  
   799  		} else if e.Id.Equal(oidExtAuthorityInfoAccess) {
   800  			exts.AuthorityInfoAccess = new(AuthorityInfoAccess)
   801  			exts.AuthorityInfoAccess.OCSPServer = c.OCSPServer
   802  			exts.AuthorityInfoAccess.IssuingCertificateURL = c.IssuingCertificateURL
   803  		} else if e.Id.Equal(oidExtSubjectKeyId) {
   804  			exts.SubjectKeyID = c.SubjectKeyId
   805  		} else if e.Id.Equal(oidExtSignedCertificateTimestampList) {
   806  			exts.SignedCertificateTimestampList = c.SignedCertificateTimestampList
   807  		} else if e.Id.Equal(oidExtensionCTPrecertificatePoison) {
   808  			exts.IsPrecert = true
   809  		} else if e.Id.Equal(oidBRTorServiceDescriptor) {
   810  			exts.TorServiceDescriptors = c.TorServiceDescriptors
   811  		} else if e.Id.Equal(oidExtCABFOrganizationID) {
   812  			exts.CABFOrganizationIdentifier = c.CABFOrganizationIdentifier
   813  		} else if e.Id.Equal(oidExtQCStatements) {
   814  			exts.QCStatements = c.QCStatements
   815  		} else {
   816  			// Unknown extension
   817  			unk = append(unk, e)
   818  		}
   819  	}
   820  	return exts, unk
   821  }