diff --git a/x509util/certificate.go b/x509util/certificate.go index 2668c256..37ceb0cf 100644 --- a/x509util/certificate.go +++ b/x509util/certificate.go @@ -4,9 +4,7 @@ import ( "crypto" "crypto/rand" "crypto/x509" - "crypto/x509/pkix" "encoding/json" - "math/big" "github.com/pkg/errors" ) @@ -139,144 +137,3 @@ func CreateCertificate(template, parent *x509.Certificate, pub crypto.PublicKey, } return cert, nil } - -// Name is the JSON representation of X.501 type Name, used in the X.509 subject -// and issuer fields. -type Name struct { - Country MultiString `json:"country"` - Organization MultiString `json:"organization"` - OrganizationalUnit MultiString `json:"organizationUnit"` - Locality MultiString `json:"locality"` - Province MultiString `json:"province"` - StreetAddress MultiString `json:"streetAddress"` - PostalCode MultiString `json:"postalCode"` - SerialNumber string `json:"serialNumber"` - CommonName string `json:"commonName"` -} - -// UnmarshalJSON implements the json.Unmarshal interface and unmarshals a JSON -// object in the Subject struct or a string as just the subject common name. -func (n *Name) UnmarshalJSON(data []byte) error { - if cn, ok := maybeString(data); ok { - n.CommonName = cn - return nil - } - - type nameAlias Name - var nn nameAlias - if err := json.Unmarshal(data, &nn); err != nil { - return errors.Wrap(err, "error unmarshaling json") - } - *n = Name(nn) - return nil -} - -// Subject is the JSON representation of the X.509 subject field. -type Subject Name - -func newSubject(n pkix.Name) Subject { - return Subject{ - Country: n.Country, - Organization: n.Organization, - OrganizationalUnit: n.OrganizationalUnit, - Locality: n.Locality, - Province: n.Province, - StreetAddress: n.StreetAddress, - PostalCode: n.PostalCode, - SerialNumber: n.SerialNumber, - CommonName: n.CommonName, - } -} - -// Set sets the subject in the given certificate. -func (s Subject) Set(c *x509.Certificate) { - c.Subject = pkix.Name{ - Country: s.Country, - Organization: s.Organization, - OrganizationalUnit: s.OrganizationalUnit, - Locality: s.Locality, - Province: s.Province, - StreetAddress: s.StreetAddress, - PostalCode: s.PostalCode, - SerialNumber: s.SerialNumber, - CommonName: s.CommonName, - } -} - -// Issuer is the JSON representation of the X.509 issuer field. -type Issuer Name - -func newIssuer(n pkix.Name) Issuer { - return Issuer{ - Country: n.Country, - Organization: n.Organization, - OrganizationalUnit: n.OrganizationalUnit, - Locality: n.Locality, - Province: n.Province, - StreetAddress: n.StreetAddress, - PostalCode: n.PostalCode, - SerialNumber: n.SerialNumber, - CommonName: n.CommonName, - } -} - -// Set sets the issuer in the given certificate. -func (i Issuer) Set(c *x509.Certificate) { - c.Issuer = pkix.Name{ - Country: i.Country, - Organization: i.Organization, - OrganizationalUnit: i.OrganizationalUnit, - Locality: i.Locality, - Province: i.Province, - StreetAddress: i.StreetAddress, - PostalCode: i.PostalCode, - SerialNumber: i.SerialNumber, - CommonName: i.CommonName, - } -} - -// SerialNumber is the JSON representation of the X509 serial number. -type SerialNumber struct { - *big.Int -} - -// Set sets the serial number in the given certificate. -func (s SerialNumber) Set(c *x509.Certificate) { - c.SerialNumber = s.Int -} - -func (s *SerialNumber) MarshalJSON() ([]byte, error) { - if s == nil || s.Int == nil { - return []byte(`null`), nil - } - return s.Int.MarshalJSON() -} - -// UnmarshalJSON implements the json.Unmarshal interface and unmarshals an -// integer or a string into a serial number. If a string is used, a prefix of -// “0b” or “0B” selects base 2, “0”, “0o” or “0O” selects base 8, and “0x” or -// “0X” selects base 16. Otherwise, the selected base is 10 and no prefix is -// accepted. -func (s *SerialNumber) UnmarshalJSON(data []byte) error { - if sn, ok := maybeString(data); ok { - // Using base 0 to accept prefixes 0b, 0o, 0x but defaults as base 10. - b, ok := new(big.Int).SetString(sn, 0) - if !ok { - return errors.Errorf("error unmarshaling json: serialNumber %s is not valid", sn) - } - *s = SerialNumber{ - Int: b, - } - return nil - } - - // Assume a number. - var i int64 - if err := json.Unmarshal(data, &i); err != nil { - return errors.Wrap(err, "error unmarshaling json") - } - *s = SerialNumber{ - Int: new(big.Int).SetInt64(i), - } - return nil -} diff --git a/x509util/extensions.go b/x509util/extensions.go index ab6ee86b..3f733a0b 100644 --- a/x509util/extensions.go +++ b/x509util/extensions.go @@ -6,6 +6,7 @@ import ( "encoding/asn1" "encoding/json" "fmt" + "math/big" "net" "net/url" "strings" @@ -373,3 +374,49 @@ func (n NameConstraints) Set(c *x509.Certificate) { c.PermittedURIDomains = n.PermittedURIDomains c.ExcludedURIDomains = n.ExcludedURIDomains } + +// SerialNumber is the JSON representation of the X509 serial number. +type SerialNumber struct { + *big.Int +} + +// Set sets the serial number in the given certificate. +func (s SerialNumber) Set(c *x509.Certificate) { + c.SerialNumber = s.Int +} + +func (s *SerialNumber) MarshalJSON() ([]byte, error) { + if s == nil || s.Int == nil { + return []byte(`null`), nil + } + return s.Int.MarshalJSON() +} + +// UnmarshalJSON implements the json.Unmarshal interface and unmarshals an +// integer or a string into a serial number. If a string is used, a prefix of +// “0b” or “0B” selects base 2, “0”, “0o” or “0O” selects base 8, and “0x” or +// “0X” selects base 16. Otherwise, the selected base is 10 and no prefix is +// accepted. +func (s *SerialNumber) UnmarshalJSON(data []byte) error { + if sn, ok := maybeString(data); ok { + // Using base 0 to accept prefixes 0b, 0o, 0x but defaults as base 10. + b, ok := new(big.Int).SetString(sn, 0) + if !ok { + return errors.Errorf("error unmarshaling json: serialNumber %s is not valid", sn) + } + *s = SerialNumber{ + Int: b, + } + return nil + } + + // Assume a number. + var i int64 + if err := json.Unmarshal(data, &i); err != nil { + return errors.Wrap(err, "error unmarshaling json") + } + *s = SerialNumber{ + Int: new(big.Int).SetInt64(i), + } + return nil +} diff --git a/x509util/pkix.go b/x509util/pkix.go new file mode 100644 index 00000000..2c6e3dfc --- /dev/null +++ b/x509util/pkix.go @@ -0,0 +1,104 @@ +package x509util + +import ( + "crypto/x509" + "crypto/x509/pkix" + "encoding/json" + + "github.com/pkg/errors" +) + +// Name is the JSON representation of X.501 type Name, used in the X.509 subject +// and issuer fields. +type Name struct { + Country MultiString `json:"country"` + Organization MultiString `json:"organization"` + OrganizationalUnit MultiString `json:"organizationUnit"` + Locality MultiString `json:"locality"` + Province MultiString `json:"province"` + StreetAddress MultiString `json:"streetAddress"` + PostalCode MultiString `json:"postalCode"` + SerialNumber string `json:"serialNumber"` + CommonName string `json:"commonName"` +} + +// UnmarshalJSON implements the json.Unmarshal interface and unmarshals a JSON +// object in the Subject struct or a string as just the subject common name. +func (n *Name) UnmarshalJSON(data []byte) error { + if cn, ok := maybeString(data); ok { + n.CommonName = cn + return nil + } + + type nameAlias Name + var nn nameAlias + if err := json.Unmarshal(data, &nn); err != nil { + return errors.Wrap(err, "error unmarshaling json") + } + *n = Name(nn) + return nil +} + +// Subject is the JSON representation of the X.509 subject field. +type Subject Name + +func newSubject(n pkix.Name) Subject { + return Subject{ + Country: n.Country, + Organization: n.Organization, + OrganizationalUnit: n.OrganizationalUnit, + Locality: n.Locality, + Province: n.Province, + StreetAddress: n.StreetAddress, + PostalCode: n.PostalCode, + SerialNumber: n.SerialNumber, + CommonName: n.CommonName, + } +} + +// Set sets the subject in the given certificate. +func (s Subject) Set(c *x509.Certificate) { + c.Subject = pkix.Name{ + Country: s.Country, + Organization: s.Organization, + OrganizationalUnit: s.OrganizationalUnit, + Locality: s.Locality, + Province: s.Province, + StreetAddress: s.StreetAddress, + PostalCode: s.PostalCode, + SerialNumber: s.SerialNumber, + CommonName: s.CommonName, + } +} + +// Issuer is the JSON representation of the X.509 issuer field. +type Issuer Name + +func newIssuer(n pkix.Name) Issuer { + return Issuer{ + Country: n.Country, + Organization: n.Organization, + OrganizationalUnit: n.OrganizationalUnit, + Locality: n.Locality, + Province: n.Province, + StreetAddress: n.StreetAddress, + PostalCode: n.PostalCode, + SerialNumber: n.SerialNumber, + CommonName: n.CommonName, + } +} + +// Set sets the issuer in the given certificate. +func (i Issuer) Set(c *x509.Certificate) { + c.Issuer = pkix.Name{ + Country: i.Country, + Organization: i.Organization, + OrganizationalUnit: i.OrganizationalUnit, + Locality: i.Locality, + Province: i.Province, + StreetAddress: i.StreetAddress, + PostalCode: i.PostalCode, + SerialNumber: i.SerialNumber, + CommonName: i.CommonName, + } +}