Move subject, issuer and serial number.

This commit is contained in:
Mariano Cano 2020-07-17 12:46:10 -07:00
parent 8069d1246b
commit abaaec04f1
3 changed files with 151 additions and 143 deletions

View File

@ -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
}

View File

@ -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
}

104
x509util/pkix.go Normal file
View File

@ -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,
}
}