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

     1  // Copyright 2014 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 pkix
     6  
     7  import (
     8  	"encoding/json"
     9  	"errors"
    10  	"strconv"
    11  	"strings"
    12  
    13  	"github.com/zmap/zcrypto/encoding/asn1"
    14  )
    15  
    16  type auxAttributeTypeAndValue struct {
    17  	Type  string `json:"type,omitempty"`
    18  	Value string `json:"value,omitempty"`
    19  }
    20  
    21  // MarshalJSON implements the json.Marshaler interface.
    22  func (a *AttributeTypeAndValue) MarshalJSON() ([]byte, error) {
    23  	aux := auxAttributeTypeAndValue{}
    24  	aux.Type = a.Type.String()
    25  	if s, ok := a.Value.(string); ok {
    26  		aux.Value = s
    27  	}
    28  	return json.Marshal(&aux)
    29  }
    30  
    31  // UnmarshalJSON implements the json.Unmarshaler interface.
    32  func (a *AttributeTypeAndValue) UnmarshalJSON(b []byte) error {
    33  	aux := auxAttributeTypeAndValue{}
    34  	if err := json.Unmarshal(b, &aux); err != nil {
    35  		return err
    36  	}
    37  	a.Type = nil
    38  	if len(aux.Type) > 0 {
    39  		parts := strings.Split(aux.Type, ".")
    40  		for _, part := range parts {
    41  			i, err := strconv.Atoi(part)
    42  			if err != nil {
    43  				return err
    44  			}
    45  			a.Type = append(a.Type, i)
    46  		}
    47  	}
    48  	a.Value = aux.Value
    49  	return nil
    50  }
    51  
    52  type auxOtherName struct {
    53  	ID    string `json:"id,omitempty"`
    54  	Value []byte `json:"value,omitempty"`
    55  }
    56  
    57  // MarshalJSON implements the json.Marshaler interface.
    58  func (o *OtherName) MarshalJSON() ([]byte, error) {
    59  	aux := auxOtherName{
    60  		ID:    o.TypeID.String(),
    61  		Value: o.Value.Bytes,
    62  	}
    63  	return json.Marshal(&aux)
    64  }
    65  
    66  // UnmarshalJSON implements the json.Unmarshaler interface.
    67  func (o *OtherName) UnmarshalJSON(b []byte) (err error) {
    68  	aux := auxOtherName{}
    69  	if err = json.Unmarshal(b, &aux); err != nil {
    70  		return
    71  	}
    72  
    73  	// Turn dot-notation back into an OID
    74  	if len(aux.ID) == 0 {
    75  		return errors.New("empty type ID")
    76  	}
    77  	parts := strings.Split(aux.ID, ".")
    78  	o.TypeID = nil
    79  	for _, part := range parts {
    80  		i, err := strconv.Atoi(part)
    81  		if err != nil {
    82  			return err
    83  		}
    84  		o.TypeID = append(o.TypeID, i)
    85  	}
    86  
    87  	// Build the ASN.1 value
    88  	o.Value = asn1.RawValue{
    89  		Tag:        0,
    90  		Class:      asn1.ClassContextSpecific,
    91  		IsCompound: true,
    92  		Bytes:      aux.Value,
    93  	}
    94  	o.Value.FullBytes, err = asn1.Marshal(o.Value)
    95  	return
    96  }
    97  
    98  type auxExtension struct {
    99  	ID       string `json:"id,omitempty"`
   100  	Critical bool   `json:"critical"`
   101  	Value    []byte `json:"value,omitempty"`
   102  }
   103  
   104  // MarshalJSON implements the json.Marshaler interface.
   105  func (ext *Extension) MarshalJSON() ([]byte, error) {
   106  	aux := auxExtension{
   107  		ID:       ext.Id.String(),
   108  		Critical: ext.Critical,
   109  		Value:    ext.Value,
   110  	}
   111  	return json.Marshal(&aux)
   112  }
   113  
   114  // UnmarshalJSON implements the json.Unmarshaler interface.
   115  func (ext *Extension) UnmarshalJSON(b []byte) (err error) {
   116  	aux := auxExtension{}
   117  	if err = json.Unmarshal(b, &aux); err != nil {
   118  		return
   119  	}
   120  
   121  	parts := strings.Split(aux.ID, ".")
   122  	for _, part := range parts {
   123  		i, err := strconv.Atoi(part)
   124  		if err != nil {
   125  			return err
   126  		}
   127  		ext.Id = append(ext.Id, i)
   128  	}
   129  	ext.Critical = aux.Critical
   130  	ext.Value = aux.Value
   131  	return
   132  }
   133  
   134  type auxName struct {
   135  	CommonName         []string `json:"common_name,omitempty"`
   136  	SerialNumber       []string `json:"serial_number,omitempty"`
   137  	Country            []string `json:"country,omitempty"`
   138  	Locality           []string `json:"locality,omitempty"`
   139  	Province           []string `json:"province,omitempty"`
   140  	StreetAddress      []string `json:"street_address,omitempty"`
   141  	Organization       []string `json:"organization,omitempty"`
   142  	OrganizationalUnit []string `json:"organizational_unit,omitempty"`
   143  	PostalCode         []string `json:"postal_code,omitempty"`
   144  	DomainComponent    []string `json:"domain_component,omitempty"`
   145  	EmailAddress       []string `json:"email_address,omitempty"`
   146  	GivenName          []string `json:"given_name,omitempty"`
   147  	Surname            []string `json:"surname,omitempty"`
   148  	// EV
   149  	JurisdictionCountry  []string `json:"jurisdiction_country,omitempty"`
   150  	JurisdictionLocality []string `json:"jurisdiction_locality,omitempty"`
   151  	JurisdictionProvince []string `json:"jurisdiction_province,omitempty"`
   152  
   153  	// QWACS
   154  	OrganizationID []string `json:"organization_id,omitempty"`
   155  
   156  	UnknownAttributes []AttributeTypeAndValue `json:"-"`
   157  }
   158  
   159  // MarshalJSON implements the json.Marshaler interface.
   160  func (n *Name) MarshalJSON() ([]byte, error) {
   161  	aux := auxName{}
   162  	attrs := n.ToRDNSequence()
   163  	for _, attrSet := range attrs {
   164  		for _, a := range attrSet {
   165  			s, ok := a.Value.(string)
   166  			if !ok {
   167  				continue
   168  			}
   169  			if a.Type.Equal(oidCommonName) {
   170  				aux.CommonName = append(aux.CommonName, s)
   171  			} else if a.Type.Equal(oidSurname) {
   172  				aux.Surname = append(aux.Surname, s)
   173  			} else if a.Type.Equal(oidSerialNumber) {
   174  				aux.SerialNumber = append(aux.SerialNumber, s)
   175  			} else if a.Type.Equal(oidCountry) {
   176  				aux.Country = append(aux.Country, s)
   177  			} else if a.Type.Equal(oidLocality) {
   178  				aux.Locality = append(aux.Locality, s)
   179  			} else if a.Type.Equal(oidProvince) {
   180  				aux.Province = append(aux.Province, s)
   181  			} else if a.Type.Equal(oidStreetAddress) {
   182  				aux.StreetAddress = append(aux.StreetAddress, s)
   183  			} else if a.Type.Equal(oidOrganization) {
   184  				aux.Organization = append(aux.Organization, s)
   185  			} else if a.Type.Equal(oidGivenName) {
   186  				aux.GivenName = append(aux.GivenName, s)
   187  			} else if a.Type.Equal(oidOrganizationalUnit) {
   188  				aux.OrganizationalUnit = append(aux.OrganizationalUnit, s)
   189  			} else if a.Type.Equal(oidPostalCode) {
   190  				aux.PostalCode = append(aux.PostalCode, s)
   191  			} else if a.Type.Equal(oidDomainComponent) {
   192  				aux.DomainComponent = append(aux.DomainComponent, s)
   193  			} else if a.Type.Equal(oidDNEmailAddress) {
   194  				aux.EmailAddress = append(aux.EmailAddress, s)
   195  				// EV
   196  			} else if a.Type.Equal(oidJurisdictionCountry) {
   197  				aux.JurisdictionCountry = append(aux.JurisdictionCountry, s)
   198  			} else if a.Type.Equal(oidJurisdictionLocality) {
   199  				aux.JurisdictionLocality = append(aux.JurisdictionLocality, s)
   200  			} else if a.Type.Equal(oidJurisdictionProvince) {
   201  				aux.JurisdictionProvince = append(aux.JurisdictionProvince, s)
   202  			} else if a.Type.Equal(oidOrganizationID) {
   203  				aux.OrganizationID = append(aux.OrganizationID, s)
   204  			} else {
   205  				aux.UnknownAttributes = append(aux.UnknownAttributes, a)
   206  			}
   207  		}
   208  	}
   209  	return json.Marshal(&aux)
   210  }
   211  
   212  func appendATV(names []AttributeTypeAndValue, fieldVals []string, asn1Id asn1.ObjectIdentifier) []AttributeTypeAndValue {
   213  	if len(fieldVals) == 0 {
   214  		return names
   215  	}
   216  
   217  	for _, val := range fieldVals {
   218  		names = append(names, AttributeTypeAndValue{Type: asn1Id, Value: val})
   219  	}
   220  
   221  	return names
   222  }
   223  
   224  // UnmarshalJSON implements the json.Unmarshaler interface.
   225  func (n *Name) UnmarshalJSON(b []byte) error {
   226  	aux := auxName{}
   227  	if err := json.Unmarshal(b, &aux); err != nil {
   228  		return err
   229  	}
   230  
   231  	// Populate Names as []AttributeTypeAndValue
   232  	n.Names = appendATV(n.Names, aux.Country, oidCountry)
   233  	n.Names = appendATV(n.Names, aux.Organization, oidOrganization)
   234  	n.Names = appendATV(n.Names, aux.OrganizationalUnit, oidOrganizationalUnit)
   235  	n.Names = appendATV(n.Names, aux.Locality, oidLocality)
   236  	n.Names = appendATV(n.Names, aux.Province, oidProvince)
   237  	n.Names = appendATV(n.Names, aux.StreetAddress, oidStreetAddress)
   238  	n.Names = appendATV(n.Names, aux.PostalCode, oidPostalCode)
   239  	n.Names = appendATV(n.Names, aux.DomainComponent, oidDomainComponent)
   240  	n.Names = appendATV(n.Names, aux.EmailAddress, oidDNEmailAddress)
   241  	// EV
   242  	n.Names = appendATV(n.Names, aux.JurisdictionCountry, oidJurisdictionCountry)
   243  	n.Names = appendATV(n.Names, aux.JurisdictionLocality, oidJurisdictionLocality)
   244  	n.Names = appendATV(n.Names, aux.JurisdictionProvince, oidJurisdictionProvince)
   245  
   246  	n.Names = appendATV(n.Names, aux.CommonName, oidCommonName)
   247  	n.Names = appendATV(n.Names, aux.SerialNumber, oidSerialNumber)
   248  
   249  	// Populate specific fields as []string
   250  	n.Country = aux.Country
   251  	n.Organization = aux.Organization
   252  	n.OrganizationalUnit = aux.OrganizationalUnit
   253  	n.Locality = aux.Locality
   254  	n.Province = aux.Province
   255  	n.StreetAddress = aux.StreetAddress
   256  	n.PostalCode = aux.PostalCode
   257  	n.DomainComponent = aux.DomainComponent
   258  	// EV
   259  	n.JurisdictionCountry = aux.JurisdictionCountry
   260  	n.JurisdictionLocality = aux.JurisdictionLocality
   261  	n.JurisdictionProvince = aux.JurisdictionProvince
   262  
   263  	// CommonName and SerialNumber are not arrays.
   264  	if len(aux.CommonName) > 0 {
   265  		n.CommonName = aux.CommonName[0]
   266  	}
   267  	if len(aux.SerialNumber) > 0 {
   268  		n.SerialNumber = aux.SerialNumber[0]
   269  	}
   270  
   271  	// Add "extra" commonNames and serialNumbers to ExtraNames.
   272  	if len(aux.CommonName) > 1 {
   273  		n.ExtraNames = appendATV(n.ExtraNames, aux.CommonName[1:], oidCommonName)
   274  	}
   275  	if len(aux.SerialNumber) > 1 {
   276  		n.ExtraNames = appendATV(n.ExtraNames, aux.SerialNumber[1:], oidSerialNumber)
   277  	}
   278  
   279  	return nil
   280  }