diff --git a/x509util/extensions.go b/x509util/extensions.go index ede5ab64..af4e4c42 100644 --- a/x509util/extensions.go +++ b/x509util/extensions.go @@ -287,6 +287,16 @@ func (id AuthorityKeyID) Set(c *x509.Certificate) { // authority information access extension. type OCSPServer MultiString +// UnmarshalJSON implements the json.Unmarshaler interface in OCSPServer. +func (o *OCSPServer) UnmarshalJSON(data []byte) error { + ms, err := unmarshalMultiString(data) + if err != nil { + return err + } + *o = ms + return nil +} + // Set sets the list of OSCP servers to the given certificate. func (o OCSPServer) Set(c *x509.Certificate) { c.OCSPServer = o @@ -296,6 +306,16 @@ func (o OCSPServer) Set(c *x509.Certificate) { // will be encoded in the authority information access extension. type IssuingCertificateURL MultiString +// UnmarshalJSON implements the json.Unmarshaler interface in IssuingCertificateURL. +func (u *IssuingCertificateURL) UnmarshalJSON(data []byte) error { + ms, err := unmarshalMultiString(data) + if err != nil { + return err + } + *u = ms + return nil +} + // Set sets the list of issuing certificate urls to the given certificate. func (u IssuingCertificateURL) Set(c *x509.Certificate) { c.IssuingCertificateURL = u @@ -305,6 +325,16 @@ func (u IssuingCertificateURL) Set(c *x509.Certificate) { // be encoded in the CRL distribution points extension. type CRLDistributionPoints MultiString +// UnmarshalJSON implements the json.Unmarshaler interface in CRLDistributionPoints. +func (u *CRLDistributionPoints) UnmarshalJSON(data []byte) error { + ms, err := unmarshalMultiString(data) + if err != nil { + return err + } + *u = ms + return nil +} + // Set sets the CRL distribution points to the given certificate. func (u CRLDistributionPoints) Set(c *x509.Certificate) { c.CRLDistributionPoints = u @@ -314,6 +344,21 @@ func (u CRLDistributionPoints) Set(c *x509.Certificate) { // policies extension. type PolicyIdentifiers MultiObjectIdentifier +// MarshalJSON implements the json.Marshaler interface in PolicyIdentifiers. +func (p PolicyIdentifiers) MarshalJSON() ([]byte, error) { + return MultiObjectIdentifier(p).MarshalJSON() +} + +// UnmarshalJSON implements the json.Unmarshaler interface in PolicyIdentifiers. +func (p *PolicyIdentifiers) UnmarshalJSON(data []byte) error { + var v MultiObjectIdentifier + if err := json.Unmarshal(data, &v); err != nil { + return errors.Wrap(err, "error unmarshaling json") + } + *p = PolicyIdentifiers(v) + return nil +} + // Sets sets the policy identifiers to the given certificate. func (p PolicyIdentifiers) Set(c *x509.Certificate) { c.PolicyIdentifiers = p diff --git a/x509util/extensions_test.go b/x509util/extensions_test.go index 2938e0eb..fb8f23f0 100644 --- a/x509util/extensions_test.go +++ b/x509util/extensions_test.go @@ -4,6 +4,7 @@ import ( "crypto/x509" "crypto/x509/pkix" "encoding/asn1" + "encoding/json" "math/big" "net" "net/url" @@ -451,6 +452,35 @@ func TestAuthorityKeyID_Set(t *testing.T) { } } +func TestOCSPServer_UnmarshalJSON(t *testing.T) { + type args struct { + data []byte + } + tests := []struct { + name string + args args + want OCSPServer + wantErr bool + }{ + {"string", args{[]byte(`"foo"`)}, []string{"foo"}, false}, + {"array", args{[]byte(`["foo", "bar", "zar"]`)}, []string{"foo", "bar", "zar"}, false}, + {"empty", args{[]byte(`[]`)}, []string{}, false}, + {"null", args{[]byte(`null`)}, nil, false}, + {"fail", args{[]byte(`["foo"`)}, nil, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var got OCSPServer + if err := got.UnmarshalJSON(tt.args.data); (err != nil) != tt.wantErr { + t.Errorf("OCSPServer.UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("OCSPServer.UnmarshalJSON() = %v, want %v", got, tt.want) + } + }) + } +} + func TestOCSPServer_Set(t *testing.T) { type args struct { c *x509.Certificate @@ -474,6 +504,35 @@ func TestOCSPServer_Set(t *testing.T) { } } +func TestIssuingCertificateURL_UnmarshalJSON(t *testing.T) { + type args struct { + data []byte + } + tests := []struct { + name string + args args + want IssuingCertificateURL + wantErr bool + }{ + {"string", args{[]byte(`"foo"`)}, []string{"foo"}, false}, + {"array", args{[]byte(`["foo", "bar", "zar"]`)}, []string{"foo", "bar", "zar"}, false}, + {"empty", args{[]byte(`[]`)}, []string{}, false}, + {"null", args{[]byte(`null`)}, nil, false}, + {"fail", args{[]byte(`["foo"`)}, nil, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var got IssuingCertificateURL + if err := got.UnmarshalJSON(tt.args.data); (err != nil) != tt.wantErr { + t.Errorf("IssuingCertificateURL.UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("IssuingCertificateURL.UnmarshalJSON() = %v, want %v", got, tt.want) + } + }) + } +} + func TestIssuingCertificateURL_Set(t *testing.T) { type args struct { c *x509.Certificate @@ -497,6 +556,35 @@ func TestIssuingCertificateURL_Set(t *testing.T) { } } +func TestCRLDistributionPoints_UnmarshalJSON(t *testing.T) { + type args struct { + data []byte + } + tests := []struct { + name string + args args + want CRLDistributionPoints + wantErr bool + }{ + {"string", args{[]byte(`"foo"`)}, []string{"foo"}, false}, + {"array", args{[]byte(`["foo", "bar", "zar"]`)}, []string{"foo", "bar", "zar"}, false}, + {"empty", args{[]byte(`[]`)}, []string{}, false}, + {"null", args{[]byte(`null`)}, nil, false}, + {"fail", args{[]byte(`["foo"`)}, nil, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var got CRLDistributionPoints + if err := got.UnmarshalJSON(tt.args.data); (err != nil) != tt.wantErr { + t.Errorf("CRLDistributionPoints.UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("CRLDistributionPoints.UnmarshalJSON() = %v, want %v", got, tt.want) + } + }) + } +} + func TestCRLDistributionPoints_Set(t *testing.T) { type args struct { c *x509.Certificate @@ -520,6 +608,61 @@ func TestCRLDistributionPoints_Set(t *testing.T) { } } +func TestPolicyIdentifiers_MarshalJSON(t *testing.T) { + tests := []struct { + name string + m PolicyIdentifiers + want []byte + wantErr bool + }{ + {"ok", []asn1.ObjectIdentifier{[]int{1, 2, 3, 4}, []int{5, 6, 7, 8, 9, 0}}, []byte(`["1.2.3.4","5.6.7.8.9.0"]`), false}, + {"empty", []asn1.ObjectIdentifier{}, []byte(`[]`), false}, + {"nil", nil, []byte(`null`), false}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + got, err := json.Marshal(tt.m) + if (err != nil) != tt.wantErr { + t.Errorf("PolicyIdentifiers.MarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + return + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("PolicyIdentifiers.MarshalJSON() = %v, want %v", got, tt.want) + } + }) + } +} + +func TestPolicyIdentifiers_UnmarshalJSON(t *testing.T) { + type args struct { + data []byte + } + tests := []struct { + name string + args args + want PolicyIdentifiers + wantErr bool + }{ + {"string", args{[]byte(`"1.2.3.4"`)}, []asn1.ObjectIdentifier{[]int{1, 2, 3, 4}}, false}, + {"array", args{[]byte(`["1.2.3.4", "5.6.7.8.9.0"]`)}, []asn1.ObjectIdentifier{[]int{1, 2, 3, 4}, []int{5, 6, 7, 8, 9, 0}}, false}, + {"empty", args{[]byte(`[]`)}, []asn1.ObjectIdentifier{}, false}, + {"null", args{[]byte(`null`)}, nil, false}, + {"fail", args{[]byte(`":foo:bar"`)}, nil, true}, + {"failJSON", args{[]byte(`["https://iss#sub"`)}, nil, true}, + } + for _, tt := range tests { + t.Run(tt.name, func(t *testing.T) { + var got PolicyIdentifiers + if err := got.UnmarshalJSON(tt.args.data); (err != nil) != tt.wantErr { + t.Errorf("PolicyIdentifiers.UnmarshalJSON() error = %v, wantErr %v", err, tt.wantErr) + } + if !reflect.DeepEqual(got, tt.want) { + t.Errorf("PolicyIdentifiers.UnmarshalJSON() = %v, want %v", got, tt.want) + } + }) + } +} + func TestPolicyIdentifiers_Set(t *testing.T) { type args struct { c *x509.Certificate