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 }